Junos PyEZ am Beispiel der Suche nach freien IPv4-Subnetzen

Ein Artikel ĂŒber die Arbeit mit Junos PyEZ – „Python-Mikroframework, das es ermöglicht, GerĂ€te mit Junos OS zu verwalten und zu automatisieren“. Automatisierung und Verwaltung, genau wie wir es lieben. Das Schreiben des in diesem Artikel beschriebenen Skripts verfolgte mehrere Ziele – das Erlernen von Python und die Automatisierung von Aufgaben zur Informationssammlung oder zur Änderung von Konfigurationen auf GerĂ€ten, die Junos OS verwenden. Die Wahl dieser Kombination aus Python + Junos PyEZ fiel aufgrund der niedrigen EinstiegshĂŒrde der Programmiersprache Python und der Benutzerfreundlichkeit der Bibliothek Junos PyEZ, die keine Expertenkenntnisse in Junos OS erfordert.

Aufgabe

Audit freier IPv4-Subnetze, die dem Unternehmen gehören. Das Kriterium dafĂŒr, dass ein Subnetz frei ist, besteht darin, dass es keinen Eintrag in den Routen auf dem Switch gibt, der als Router unter Junos OS fungiert.

Implementierung

Python + Junos PyEZ, obwohl es verlockend war, stattdessen paramiko und ssh.exec_command zu verwenden, wird es notwendig sein, den Protokoll fĂŒr die Netzwerkverwaltung Netconf auf dem zu befragenden GerĂ€t zu konfigurieren. Netconf arbeitet mit GerĂ€ten ĂŒber Remote Procedure Call (RPC) und verwendet XML, um die bereitgestellten Informationen im vorliegenden Beispiel zu ĂŒbermitteln.

Die Installation der aktuellen Version von Junos PyEZ aus PyPI erfolgt mit folgendem Befehl:

$ pip install junos-eznc

Es kann auch aus dem Hauptzweig des Projekts auf GitHub mit folgendem Befehl installiert werden:

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

Und eine weitere Option ĂŒber

$ pip install -r requirements.txt 

Dieser Befehl installiert die in der Systembibliothek fehlenden Bibliotheken, die zum Betrieb erforderlich sind. In meiner Version requirements.txt sind es insgesamt zwei, die zuletzt zum Zeitpunkt des Schreibens des Skripts angegebenen Versionen:

junos-eznc
netaddr

Das Skript verwendet standardmĂ€ĂŸig den Namen des aktuellen Benutzers im System. Um sich unter einem anderen Benutzernamen anzumelden, kann der SchlĂŒssel show_route.py -u verwendet werden, getpass.getpass nimmt das Passwort von stdin entgegen, sodass das Passwort nicht im System bleibt. FĂŒr die Verbindung zum GerĂ€t wird außerdem nach seinem Hostnamen oder seiner IP-Adresse gefragt. Alle fĂŒr die Authentifizierung erforderlichen Daten auf dem GerĂ€t wurden erhalten.

Junos PyEZ unterstĂŒtzt die Verbindung zu GerĂ€ten, die unter Junos OS betrieben werden, ĂŒber eine Konsole, Telnet oder Netconf ĂŒber SSH. In diesem Artikel wird die letzte Option behandelt.

FĂŒr die Verbindung zu GerĂ€ten wird die Klasse Device des Moduls jnpr.junos verwendet

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

Eine Anfrage nach allen dem Router bekannten Routen wird ĂŒber einen Remote Procedure Call oder per Aufruf von Remote Procedures ausgefĂŒhrt, je nach Wunsch.

data = dev.rpc.get_route_information()

Ein Àhnlicher Befehl in Junos OS

user@router> show route | display xml

Wenn wir den Befehl rpc am Ende hinzufĂŒgen, erhalten wir ein Anfrage-Tag, das wir mit dem Namen der RPC-Methode abgleichen können, auf diese Weise können wir auch andere interessante Namen erfahren. Es ist zu beachten, dass die Syntax des Anfrage-Tags von dem Namen der Methode abweicht, insbesondere sollten die Bindestriche durch Unterstriche ersetzt werden.

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

Den restlichen Teil habe ich in eine while-Schleife gewickelt, um nicht erneut eine Anfrage an den Router auszufĂŒhren, falls ich in einem anderen Subnetz prĂŒfen muss, das vom Router bereits bekannt ist. Es ist erwĂ€hnenswert, dass der Router, von dem ich anfrage, nur ĂŒber OSPF-Routen kennt, daher wĂ€re es besser, die Anfrage fĂŒr den Grenzrouter etwas zu Ă€ndern, um die AusfĂŒhrungszeit des Skripts zu verkĂŒrzen.

data = dev.rpc.get_ospf_route_information()

Jetzt wenden wir uns dem Inhalt der while-Schleife zu.

Zu Beginn wird der Benutzer aufgefordert, ein Subnetz mit einer Maske und nicht mehr als drei Oktetten aus dem Netzwerk dieses Subnetzes einzugeben, dies ist notwendig, um den Suchbereich festzulegen. Mir gefÀllt diese Implementierung der Festlegung der Kriterien und des Suchbereichs nicht besonders, aber ich habe bisher keine bessere Lösung gefunden. Danach wÀhle ich aus der erhaltenen Liste der Subnetze route_list die Subnetze aus, die mich interessieren, indem ich eine Variable verwende, die nicht mehr als drei Oktette enthÀlt.

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

Durch IPNetwork des Moduls netaddr erhalte ich Subnetze in Form einer Liste von ipv4-Adressen.

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

Mit IPNetwork des vom Benutzer eingegebenen Netzwerks mit Maske erhalte ich den Adressbereich und forme eine Liste aller Adressen aus diesem Bereich fĂŒr den Vergleich mit der Liste der belegten Adressen.

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

Die erhaltene Liste der freien Adressen gebe ich als Subnetze aus.

print(netaddr.IPSet(freeip))

Nachfolgend ist das vollstĂ€ndige Skript aufgefĂŒhrt, das auf Switches getestet wurde, die als Router verwendet werden, Modelle ex4550, ex4600.


#!/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

Quelle: habr.com

ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server đŸ”„ ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster