Junos PyEZ à travers la tâche de recherche de sous-réseaux ipv4 disponibles

Un article sur le travail avec Junos PyEZ — « microframework Python qui vous permet de gérer et d'automatiser les appareils fonctionnant sous Junos OS » automatisation et gestion, tout ce que nous aimons. L'écriture du script décrit dans cet article avait plusieurs objectifs — apprendre Python et automatiser des tâches de collecte d'informations ou de modification de la configuration sur du matériel sous Junos OS. Le choix de cette combinaison Python + Junos PyEZ a été fait en raison du faible seuil d'entrée dans le langage de programmation Python et de la simplicité d'utilisation de la bibliothèque Junos PyEZ, qui ne nécessite pas de connaissances expertes en Junos OS.

La tâche

Audit des sous-réseaux ipv4 libres appartenant à l'entreprise. Le critère selon lequel le sous-réseau est libre est l'absence d'enregistrement à son sujet dans les routes sur le commutateur agissant comme routeur sous Junos OS.

Mise en œuvre

Python + Junos PyEZ, bien qu'il y ait eu la tentation de le faire via paramiko et ssh.exec_command, par conséquent, il faudra configurer le protocole de gestion de réseau des appareils netconf sur le matériel interrogé. Netconf fonctionne avec le matériel via des appels de procédure à distance (remote procedure call RPC) et utilise XML, dans l'exemple en question, pour fournir les informations obtenues.

L'installation de la version actuelle de Junos PyEZ depuis PyPI s'effectue avec la commande suivante :

$ pip install junos-eznc

Il est également possible de l'installer depuis la branche principale du projet sur GitHub avec la commande suivante :

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

Et une autre option via

$ pip install -r requirements.txt 

cette commande installera les bibliothèques manquantes sur le système nécessaires au fonctionnement. Dans ma version requirements.txt il n'y en a que deux, les versions sont les dernières au moment de l'écriture du script :

junos-eznc
netaddr

Le script prend par défaut le nom de l'utilisateur courant dans le système, pour se connecter sous le nom d'un autre utilisateur, il faut utiliser la clé show_route.py -u getpass.getpass prend le mot de passe depuis stdin donc le mot de passe ne restera pas dans le système. Pour se connecter à l'équipement, il faudra également entrer, si demandé, son hostname ou son adresse ip. Toutes les données nécessaires à l'autorisation sur l'appareil ont été obtenues.

Junos PyEZ prend en charge la connexion au matériel fonctionnant sous Junos OS via console, telnet ou netconf via ssh. Cet article traite de la dernière option.

Pour se connecter au matériel, la classe Device du module jnpr.junos est utilisée

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

Une requête est effectuée pour obtenir toutes les routes connues du routeur via un appel de procédure distante, ou appel de procédures distantes, selon ce qui est le plus pratique.

data = dev.rpc.get_route_information()

Commande équivalente sur Junos OS

user@router> show route | display xml

En ajoutant le tag rpc à la fin de la commande, nous obtenons le tag de requête et pouvons le faire correspondre avec le nom de la méthode RPC, ce qui permet de découvrir d'autres noms d'intérêt. Il convient de noter que la syntaxe de l'écriture du tag de requête diffère de celle du nom de la méthode, notamment en remplaçant les signaux de tirets par des traits de soulignement.

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

Le reste a été enveloppé dans une boucle while, pour ne pas effectuer une nouvelle requête au routeur, si je dois vérifier dans un autre sous-réseau que celui que le routeur connaît déjà. Il faut mentionner que le routeur auquel je m'adresse ne connaît que les routes via OSPF, donc pour le routeur frontière, il vaut mieux modifier un peu la requête pour réduire le temps d'exécution du script.

data = dev.rpc.get_ospf_route_information()

Maintenant, regardons le contenu de la boucle while.

Au début, l'utilisateur sera invité à entrer un sous-réseau avec un masque et pas plus de trois octets de ce même sous-réseau, nécessaire pour définir la plage de recherche. Je n'apprécie pas vraiment cette mise en œuvre pour définir le critère et la plage de recherche, mais pour l'instant, je n'ai pas trouvé de meilleure solution. Ensuite, à partir de la liste de sous-réseaux route_list, en utilisant une variable contenant pas plus de trois octets, je choisis les sous-réseaux qui m'intéressent.

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

Via IPNetwork, du module netaddr, j'obtiens les sous-réseaux sous forme de liste d'adresses ipv4.

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

En utilisant IPNetwork du réseau entré par l'utilisateur avec le masque, je reçois la plage d'adresses et forme une liste de toutes les adresses de cette plage pour comparaison avec la liste des adresses occupées.

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

La liste des adresses libres obtenue est affichée sous forme de sous-réseaux.

print(netaddr.IPSet(freeip))

Voici le script complet, testé sur des commutateurs utilisés en tant que routeur, modèles 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

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster