Un article sur le travail avec Junos PyEZ - «Microframe Python qui vous permet de gérer et d'automatiser les appareils exécutant Junos OS» d'automatisation et de contrôle, tout ce que nous aimons. L'écriture du script décrit dans cet article poursuivait plusieurs objectifs: apprendre Python et automatiser les tâches de collecte d'informations ou de modification des configurations sur les équipements exécutant Junos OS. Le choix de cet ensemble Python + Junos PyEZ particulier a été fait en raison du seuil bas pour entrer dans le langage de programmation Python et de la facilité d'utilisation de la bibliothèque Junos PyEZ, qui ne nécessite pas l'expertise de Junos OS.
Défi
Audit des sous-réseaux gratuits IPv4 appartenant à l'entreprise. Le critère selon lequel le sous-réseau est libre est le manque d'entrées à ce sujet dans les routes du commutateur qui agit comme un routeur exécutant Junos OS.
Implémentation
Python + Junos PyEZ, bien qu'il y ait eu une tentation de le faire via paramiko et ssh.exec_command,
en conséquence, il sera nécessaire de configurer le protocole de gestion de réseau pour les appareils netconf sur l'équipement étudié. Netconf fonctionne avec l'équipement via un appel de procédure distante (RPC) et utilise XML, dans cet exemple, pour fournir les informations reçues.
L'installation de la version actuelle de Junos PyEZ à partir de PyPI s'effectue avec la commande suivante:
$ pip install junos-eznc
Vous pouvez également installer à partir de la branche principale du projet sur GitHub avec la commande suivante:
$ pip install git+https://github.com/Juniper/py-junos-eznc.git
Et une option de plus à travers
$ pip install -r requirements.txt
cette commande installera les bibliothèques nécessaires au travail manquant dans le système. Dans ma version de
requirements.txt il n'y en a que deux, les dernières versions sont indiquées au moment de l'écriture du script:
junos-eznc netaddr
Le script par défaut prend le nom de l'utilisateur actuel dans le système, vous pouvez vous connecter sous le nom d'un autre utilisateur à l'aide de la clé show_route.py -u <nom_utilisateur> getpass.getpass accepte le mot de passe de stdin afin que le mot de passe ne reste pas dans le système. Pour vous connecter à l'équipement, vous devrez également saisir son nom d'hôte ou son adresse IP sur demande. Toutes les données nécessaires à l'autorisation sur l'appareil ont été reçues.
Junos PyEZ prend en charge la connexion à un équipement exécutant Junos OS à l'aide de la console, de telnet ou de netconf via ssh. L'article considère la dernière option.
Pour se connecter à l'équipement, la classe Device du module jnpr.junos est utilisée
with jnpr.junos.Device(host=router, user=args.name, passwd=password) as dev:
Une demande est faite sur toutes les routes connues du routeur via un appel de procédure distante ou un appel vers des procédures distantes, vers qui cela est plus pratique.
data = dev.rpc.get_route_information()
Une commande similaire sur Junos OS
user@router> show route | display xml
En ajoutant la commande rpc à la fin de la commande, nous obtenons la balise de demande et pouvons la faire correspondre avec le nom de la méthode RPC, de cette façon, vous pouvez trouver d'autres noms intéressants. Il convient de noter que la syntaxe pour écrire une balise de demande est différente du nom de la méthode, à savoir remplacer les tirets par des traits de soulignement.
user@router> show route | display xml rpc <rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1R1/junos"> <rpc> <get-route-information> </get-route-information> </rpc> </rpc-reply>
J'ai reçu les données d'itinéraire au format xml, dont je n'ai sélectionné que celles qui m'intéressent par la balise
<rt-destination> xxx.xxx.xxx.xxx/yy </rt-destination> et les
ai écrites dans une variable sous forme de liste sous forme de chaîne, obtenant ainsi une liste sous-réseaux occupés.
route_list = data.xpath("//rt-destination/text()")
J'ai enveloppé le reste dans une boucle while afin de ne pas réexécuter la demande au routeur si j'ai besoin de vérifier un sous-réseau différent de ceux que le routeur connaît déjà. Il est à noter que le routeur sur lequel je demande ne connaît les routes que via OSPF, donc pour le routeur frontière, il vaut mieux changer un peu la demande pour réduire le temps du script
data = dev.rpc.get_ospf_route_information()
Voyons maintenant 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 du réseau du même sous-réseau, cela est nécessaire pour définir la plage de recherche. Je n'aime pas vraiment cette implémentation de la définition des critères et de la plage de recherche, mais jusqu'à présent je n'ai pas trouvé de meilleure solution. Ensuite, dans la liste obtenue des sous-réseaux route_list, en utilisant une variable ne contenant pas plus de trois octets, je sélectionne les sous-réseaux qui m'intéressent
tmp = re.search(r'^%s\S*' % subnet_search, route_list[i])
Grâce à IPNetwork, le module netaddr, j'obtiens des sous-réseaux comme une liste d'adresses ipv4
range_subnet = netaddr.IPNetwork(tmp.group(0))
En utilisant IPNetwork à partir du réseau entré par l'utilisateur avec le masque, j'obtiens une 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)
Je déduis la liste des adresses libres reçues sous forme de sous-réseaux
print(netaddr.IPSet(freeip))
Ci-dessous le script complet, testé sur les commutateurs utilisés comme routeur, modèles ex4550, ex4600