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