Junos PyEZ mintázat az ipv4 szabad alhálózatok keresésére

Cikk a Junos PyEZ használatáról – „Python mikrokeretrendszer, amely lehetővé teszi a Junos OS-t futtató eszközök kezelését és automatizálását” automatizálás és kezelés, mindaz, amit szeretünk. A cikkben leírt szkript megírásának több célja volt – a Python tanulmányozása és az információgyűjtési vagy konfigurációs változtatási feladatok automatizálása Junos OS vezérlésű hardveren. A Python + Junos PyEZ páros választását a Python programozási nyelv alacsony belépési küszöbe és a Junos PyEZ könyvtár egyszerű használata indokolta, amely nem igényel szakértői tudást a Junos OS-ról.

Feladat

Az IPv4 szabad alhálózatok auditálása a cég tulajdonában. A szabad alhálózat kritériuma az, hogy nincs róla nyilvántartás a Junos OS-t futtató router szerepét betöltő switch útvonalán.

Megvalósítás

A Python + Junos PyEZ, noha volt kísértés a paramiko és ssh.exec_command használatára, ennek következményeként szükség lesz a lekérdezett hardveren a netconf eszközmenedzsment protokoll beállítására. A Netconf távoli eljárás meghívás (RPC) segítségével működik a hardverrel, és XML-t használ, a vizsgált példában, az nyújtott információk biztosítására.

A jelenlegi Junos PyEZ verzió telepítése a PyPI-ból a következő parancs kiadásával történik:

$ pip install junos-eznc

A GitHub projekt fő ágából is telepíthető a következő parancs kiadásával:

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

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

$ pip install -r requirements.txt 

ez a parancs telepíti a hiányzó könyvtárakat, amelyek szükségesek a működéshez. Az én verziómban requirements.txt összesen kettő van, a verziók a szkript megírásának időpontjában a legutolsóak:

junos-eznc
netaddr

A szkript alapértelmezetten a rendszer aktuális felhasználónevét veszi, más felhasználónévvel való bejelentkezéshez használja a show_route.py -u kulcsot, a getpass.getpass pedig az stdin-ből kéri a jelszót, így a jelszó nem marad a rendszerben. Az eszközökhöz való csatlakozáshoz emellett be kell írni a gépjármű nevét vagy IP-címét is. Minden szükséges adat az eszközre való hitelesítéshez megvan.

A Junos PyEZ támogatja a Junos OS-t futtató eszközökhöz való csatlakozást konzolon, telneten vagy ssh-n keresztüli netconf-on. A cikkben az utolsó lehetőség került bemutatásra.

Az eszközhöz való csatlakozáshoz a jnpr.junos modul Device osztályát használjuk.

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

A kérés a router által ismert összes útvonalról kerül végrehajtásra távoli eljárás meghívásán keresztül, vagy távoli eljárások hívásán, ahogy kényelmesebb a felhasználónak.

data = dev.rpc.get_route_information()

Hasonló parancs a Junos OS-en

user@router> show route | display xml

Ha a rpc végére adjuk a parancsot, megkapjuk a kérés címkéjét, és párosíthatjuk azt az RPC metódus nevével, ezzel a módszerrel más érdekes neveket is megtudhatunk. Érdemes megjegyezni, hogy a kérés címke írásának szintaxisa különbözik a metódus nevétől, mégpedig a kötőjelek alsó vonalakra cserélésével.

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

A maradék részt while ciklusba burkoltam, hogy ne kelljen újra végrehajtani a kérést a routeren, ha más alhálózaton kell ellenőriznünk, amelyeket a router már ismer. Érdemes megemlíteni, hogy a router, amelyen a kérést végzem, csak OSPF-en keresztül ismeri az útvonalakat, ezért a határrouter számára érdemes kissé módosítani a kérést, hogy csökkentsem a szkript futási idejét.

data = dev.rpc.get_ospf_route_information()

Most térjünk rá a while ciklus tartalmára.

Kezdetben a felhasználónak javasolják, hogy adjon meg egy alhálózatot maszkkal, és legfeljebb három oktet az alhálózatból, ez szükséges a keresési tartomány meghatározásához. Nem igazán tetszik ez a megvalósítás a kritériumok és a keresési tartomány megadására, de egyelőre nem találtam jobb megoldást. A későbbiekben a route_list-ból, figyelembe véve a legfeljebb három oktetből álló változót, kiválasztom az érdekes alhálózatokat.

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

Az IPNetwork modul segítségével, a netaddr-ból, listaként kapom meg az alhálózatokat ipv4 címek formájában.

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

A felhasználó által megadott hálózat IPNetwork-jével és maszkkal megkapom a címtartományt, és összeállítom az összes címet ebből a tartományból az elfoglalt címek listájával való összehasonlításhoz.

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

A kapott szabad címek listáját alhálózat formájában mutatom be.

print(netaddr.IPSet(freeip))

Az alábbiakban a teljes szkript látható, amelyet olyan kapcsolóknál teszteltem, amelyek routerként működnek, az ex4550 és ex4600 modelleken.


#!/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: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster