Junos PyEZ az ingyenes ipv4 alhálózatok keresési feladatának példájával

Egy cikk a Junos PyEZ-szel való együttműködésről – „Python mikrokeret, amely lehetővé teszi a Junos OS-t futtató eszközök kezelését és automatizálását” – minden, amit szeretünk. Az ebben a cikkben ismertetett szkript megírásának több célja is volt – a Python megtanulása, valamint a Junos operációs rendszert futtató berendezések információgyűjtési vagy konfigurációs módosítási feladatainak automatizálása. A Python + Junos PyEZ ezen speciális kombinációját a Python programozási nyelvbe való belépés alacsony korlátai és a Junos PyEZ könyvtár egyszerű használata miatt választották, amihez nem szükséges a Junos OS szakértői ismerete.

Feladat

A céghez tartozó ingyenes ipv4 alhálózatok auditálása. Az alhálózat ingyenességének feltétele, hogy a Junos OS-t futtató routerként működő switch útvonalaiban nincs róla bejegyzés.

Реализация

Python + Junos PyEZ, bár volt kísértés a paramiko és az ssh.exec_command segítségével, Ennek eredményeként konfigurálnia kell a netconf eszköz hálózatkezelési protokollját a lekérdezett berendezésen. A Netconf a hardverrel az RPC távoli eljáráshíváson keresztül működik, és ebben a példában XML-t használ a kapott információk biztosítására.

A Junos PyEZ jelenlegi verziójának telepítése a PyPI-ből a következő paranccsal történik:

$ pip install junos-eznc

Telepítheti a projekt fő ágából is a GitHubon a következő paranccsal:

$ pip install git+https://github.com/Juniper/py-junos-eznc.git

És még egy lehetőség via

$ pip install -r requirements.txt 

Ez a parancs a rendszerből hiányzó és a működéshez szükséges könyvtárakat telepíti. Az én verziómban követelmények.txt Csak kettő van belőlük, a legújabb verziók a forgatókönyv írásakor vannak feltüntetve:

junos-eznc
netaddr

Alapértelmezés szerint a szkript az aktuális felhasználó nevét veszi fel a rendszerben; bejelentkezhet egy másik felhasználó neve alatt a show_route.py -u billentyűvel A getpass.getpass átveszi a jelszót az stdin-től, így a jelszó nem marad meg a rendszerben. A berendezéshez való csatlakozáshoz meg kell adnia annak gazdagépnevét vagy IP-címét is, amikor a rendszer kéri. Az eszközön való engedélyezéshez szükséges összes adat megérkezett.

A Junos PyEZ támogatja a Junos OS-t futtató berendezésekhez való csatlakozást konzol, telnet vagy netconf használatával ssh-n keresztül. A cikk az utóbbi lehetőséget tárgyalja.

A berendezésekhez való csatlakozáshoz használja a jnpr.junos modul Eszköz osztályát

with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:

A kérés az útválasztó által ismert összes útvonalra vonatkozóan távoli eljáráshíváson vagy távoli eljáráshíváson keresztül történik, amelyik kényelmesebb.

data = dev.rpc.get_route_information()

Hasonló parancs a Junos OS-en

user@router> show route | display xml

Ha a parancs végére rpc-t adunk, akkor egy kérés címkét kapunk, amelyet az RPC metódus nevével párosíthatunk, így más érdekes neveket is megtudhatunk. Érdemes megjegyezni, hogy a kéréscímke írásának szintaxisa eltér a metódus nevétől, vagyis a kötőjeleket aláhúzásjelekkel kell helyettesíteni.

user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")

A többi rész egy while hurokba volt burkolva, hogy ne ismételje meg a kérést az útválasztóhoz, ha egy másik alhálózatba kell bejelentkeznie azokból, amelyekről a router már tud. Érdemes megemlíteni, hogy az útválasztó, amelyen a kérést benyújtom, csak az OSPF-en keresztül ismeri az útvonalakat, így szélső router esetén jobb, ha kicsit módosítjuk a kérést, hogy csökkentsük a szkript futási idejét

data = dev.rpc.get_ospf_route_information()

Most nézzük meg a while ciklus tartalmát

Kezdetben a felhasználót arra kérik, hogy adjon meg egy alhálózatot egy maszkkal és legfeljebb három oktetttel az azonos alhálózat hálózatából, ez szükséges a keresési tartomány beállításához. Nem igazán szeretem ezt a kritériumok és keresési tartomány megadásának megvalósítását, de eddig nem találtam jobb megoldást. Ezután az eredményül kapott alhálózati listából egy legfeljebb három oktettet tartalmazó változó segítségével kiválasztom az engem érdeklő alhálózatokat.

tmp = re.search(r'^%sS*' % subnet_search, route_list[i])

Az IPNetwork-en, a netaddr modulon keresztül alhálózatokat kapok ipv4-címlista formájában

range_subnet = netaddr.IPNetwork(tmp.group(0))

Az IPNetwork használatával a felhasználó által megadott hálózatból címtartományt kapok maszkkal, és létrehozok egy listát az ebből a tartományból származó összes címről, hogy összehasonlítsam a foglalt címek listájával.

for i in set(net_list).difference(set(busyip)):
        freeip.append(i)

Az eredményül kapott szabad címlistát alhálózatok formájában jelenítem meg

print(netaddr.IPSet(freeip))

Alább látható a teljes szkript, amelyet útválasztóként használt kapcsolókon teszteltek, ex4550, ex4600 modellek


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import getpass
import netaddr
import re
import sys

import jnpr.junos

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user',
                    action='store',
                    dest='name',
                    help='Enter login from tacacs if it differs from the '
                         'username in the system.')
args = parser.parse_args()

if not args.name:
    args.name = getpass.getuser()    # Return the “login name” of the user.
router = input("Full routers name: ")
password = getpass.getpass("Password: ")

try:
    # Authenticates to a device running Junos, for get information about routs
    # into xml format and selects by tag.
    route_list = []
    with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:
        data = dev.rpc.get_route_information()
    route_list = data.xpath("//rt-destination/text()")
except (jnpr.junos.exception.ConnectRefusedError,
        jnpr.junos.exception.ConnectUnknownHostError) as err:
    print("Equipment name or password wrong.")
    sys.exit(1)

while True:
    subnet = input("Net with mask: ")
    subnet_search = input("Input no more three octet: ")
    # Gets a list of busy IP addresses from the received subnets.
    busyip = []
    for i in range(len(route_list)):
        tmp = re.search(r'^%sS*' % subnet_search, route_list[i])
        if tmp:
            range_subnet = netaddr.IPNetwork(tmp.group(0))
            for ip in range_subnet:
                busyip.append("%s" % ip)
    range_subnet = netaddr.IPNetwork(subnet)
    # Gets list ip adresses from subnetworks lists.
    net_list = []
    for ip in range_subnet:
        net_list.append("%s" % ip)
    # Сomparing lists.
    freeip = []
    for i in set(net_list).difference(set(busyip)):
        freeip.append(i)
    print(netaddr.IPSet(freeip))

    request = input("To run request again enter yes or y, "
                    "press 'enter', complete request: ")
    if request in ("yes", "y"):
        continue
    else:
        print('Bye')
        break

Forrás: will.com

Hozzászólás