Junos PyEZ no exemplo da tarefa de encontrar sub-redes ipv4 gratuitas

Um artigo sobre como trabalhar com o Junos PyEZ - “Microestrutura de Python que permite gerenciar e automatizar dispositivos executando o sistema e automação do Junos OS”, tudo o que amamos. A escrita do script descrito neste artigo alcançou vários objetivos - aprender Python e automatizar as tarefas de coleta de informações ou alteração de configurações em equipamentos executando o Junos OS. A escolha desse pacote específico Python + Junos PyEZ foi feita devido ao baixo limite de entrada na linguagem de programação Python e à facilidade de uso da biblioteca Junos PyEZ, que não requer conhecimento do Junos OS.

Desafio


Auditoria de sub-redes livres de ipv4 de propriedade da empresa. O critério de que a sub-rede é livre é a falta de entradas sobre ela nas rotas no switch que atua como um roteador executando o Junos OS.

Implementação


Python + Junos PyEZ, embora tenha havido uma tentação de fazer isso através de paramiko e ssh.exec_command, como resultado, será necessário configurar o protocolo de gerenciamento de rede para dispositivos netconf no equipamento que está sendo pesquisado. O Netconf trabalha com o equipamento por meio de uma chamada de procedimento remoto (RPC) e usa XML, neste exemplo, para fornecer as informações recebidas.

A instalação da versão atual do Junos PyEZ a partir do PyPI é realizada com o seguinte comando:

$ pip install junos-eznc 

Você também pode instalar a partir da ramificação principal do projeto no GitHub com o seguinte comando:

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

E mais uma opção através

 $ pip install -r requirements.txt 

este comando instalará as bibliotecas necessárias para o trabalho ausente no sistema. Na minha versão do requirements.txt, existem apenas dois deles, as últimas versões são indicadas no momento da escrita do script:

 junos-eznc netaddr 

O script padrão leva o nome do usuário atual no sistema. Você pode efetuar login com o nome de outro usuário usando a chave show_route.py -u <nome_do_usuário> getpass.getpass aceita a senha do stdin para que a senha não permaneça no sistema. Para conectar-se ao equipamento, você também precisará inserir o nome do host ou o endereço IP, mediante solicitação. Todos os dados necessários para a autorização no dispositivo foram recebidos.

O Junos PyEZ suporta a conexão a equipamentos que executam o Junos OS usando o console, telnet ou netconf via ssh. O artigo considera a última opção.

Para conectar ao equipamento, é usada a classe Device do módulo jnpr.junos.

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

É feita uma solicitação sobre todas as rotas conhecidas pelo roteador por meio de uma chamada de procedimento remoto ou de procedimentos remotos, para quem é mais conveniente.

 data = dev.rpc.get_route_information() 

Um comando semelhante no Junos OS

 user@router> show route | display xml 

Adicionando o comando rpc ao final do comando, obtemos a tag de solicitação e podemos combiná-la com o nome do método RPC, desta forma, você pode descobrir outros nomes de interesse. Vale ressaltar que a sintaxe para escrever uma tag de solicitação é diferente do nome do método, ou seja, substitua hífens por sublinhados.

 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> 

Recebi os dados da rota no formato xml, dos quais selecionei apenas os que me interessam pela tag <rt-destination> xxx.xxx.xxx.xxx/yy </rt-destination> e os escrevi em uma variável como uma lista no formato de string, obtendo assim uma lista sub-redes ocupadas.

 route_list = data.xpath("//rt-destination/text()") 

Embrulhei o restante em um loop while para não executar novamente a solicitação ao roteador se eu precisar verificar uma sub-rede diferente daquela que o roteador já conhece. Vale ressaltar que o roteador no qual solicito conhece as rotas apenas através do OSPF, portanto, para o roteador de borda, é melhor alterar um pouco a solicitação para reduzir o tempo do script

 data = dev.rpc.get_ospf_route_information() 

Agora, vamos ver o conteúdo do loop while


No início, o usuário será solicitado a inserir uma sub-rede com uma máscara e, no máximo, três octetos da rede da mesma sub-rede, isso é necessário para definir o intervalo de pesquisa. Eu realmente não gosto dessa implementação de definir os critérios e o intervalo de pesquisa, mas até agora não encontrei uma solução melhor. Em seguida, na lista obtida de sub-redes route_list, usando uma variável que contém no máximo três octetos, seleciono as sub-redes de interesse para mim

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

Através da IPNetwork, o módulo netaddr, recebo sub-redes como uma lista de endereços IPv4

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

Usando o IPNetwork da rede inserida pelo usuário com a máscara, obtenho um intervalo de endereços e formo uma lista de todos os endereços desse intervalo para comparação com a lista de endereços ocupados.

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

Dedico a lista recebida de endereços gratuitos na forma de sub-redes

 print(netaddr.IPSet(freeip)) 

Abaixo está o script completo, testado em switches usados ​​como modelos roteador, 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'^%s\S*' % 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: https://habr.com/ru/post/pt481648/


All Articles