Muitos administradores de redes e sysadmins encontram problemas de conectividade nos ambientes que administram e por muitas vezes o problema é um simples IP duplicado causando todo mal estar. Agora veremos como usar o scapy e defaultdict da lib collections para monitorar esses IPs.
Scapy
O Scapy é uma poderosa biblioteca de manipulação de pacotes interativa, com abrangencia a uma enorme quantidade de protocolos provenientes da suite TCP/IP. Mais informações sobre o scpay pode ser encontrada na documentação oficial. Nesse caso em especifico iremos utilizar do scapy a metaclasse ARP e a função sniff.
from scapy.all import ARP, sniff
sniff
Vamos usar a função sniff para monitorar os pacotes que trafegam na rede usando o protocolo ARP. Pra isso vamos utilizar dela quatro parametros basicos:
sniff(prn=pacotes, filter="arp", iface=interface, timeout=10)
-
prn, chama uma função para ser aplicada a cada pacote capturado pelo sniff.
-
filter, irá filtrar todos os pacotes que contiverem o protocolo ARP.
-
iface, determina a interface de rede que será monitorada.
-
timeout, irá determinar que nosso monitoramento da rede se dara por 60 segundos.
ARP
ARP é uma metaclasse de pacotes com dados sobre o protocolo arp pertencente a camada de enlace de dados. Iremos utilizar essa metaclasse para filtrar os pacotes com informações de pacotes com respostas a requisições arp. (opcode == 2 [is at]) As informações sobre o protocolo ARP podem serm encontradas na rfc826 no site do IETF.
collections.defaultdict
defaultdict é uma subclasse de dict que prove uma instancia de variavel para a chamada de uma chave inexistente.
from collections import defaultdict
list_ips = defaultdict(set)
Basicamente nossa função irá monitorar por um certo tempo o trafego de pacotes pela rede adicionar a nossa variavel list_ips o endereço ou endereços MAC encontrados.
Definindo a função que será passada como parametro para o sniff.
Para cada pacote capturado pela função sniff, será checado se o opcode corresponde a um response do protocolo arp. Caso seja, sera adicionado a nossa defaultdict.
def pacotes(pacote):
"""Checa se o valor do opcode dentro do protocolo arp é igual a 2."""
if pacote[ARP].op == 2:
# Se for adiciona o ip de origem e seu mac à dict list_ips
list_ips[pacote[ARP].psrc].add(pacote[ARP].hwsrc)
Limpando a tabela arp
Para que seja feita novas requisições arp, iremos limpar nossa tabela arp e iniciar o monitoramento da rede. Pra isso iremos usar o comando arp, dentro do shell do sistema. (Como uso FreeBSD vou definir uma função chamando um comando pelo csh)
import os
os.system('which arp')
/usr/sbin/arp
Com posse do caminho do comando arp, irei definir uma função que limpe a tabela e inicie o monitore a rede por 60 segundos.
def monitorar(interface):
"""
O comando arp no FreeBSD usa os parametros:
-d para deletar as entradas
-i para declarar a interface
-a para representar todas entradas a serem deletas.
"""
cmd = "/usr/sbin/arp -d -i {} -a".format(interface)
os.system(cmd)
sniff(prn=pacotes, filter="arp", iface=interface, timeout=10)
E por ultimo chamar a função de monitoramento. No meu caso eu vou monitorar a interface em0.
monitorar("em0")
Agora só conferir as entradas em nossa dict.
for ip in list_ips:
print "IP: {} -> MACs: {}".format(ip, ", ".join(list(list_ips[ip])))
IP: 192.168.213.1 -> MACs: 00:90:0b:49:3d:0a
IP: 192.168.213.10 -> MACs: 08:00:27:bf:52:6d, a0:f3:c1:03:74:6a
Eu uso um script rodando nos switchs e gateway da rede que me enviam mensagens assim que ips duplicados são encontrados na rede. Também da pra usar o arping do scpay para fazer as requisições arp e coletar os responses.
Abraços.
"Monitorando Ips Duplicados na Rede" de "Silvio Ap Silva" está licenciado com uma Licença Creative Commons - Atribuição-NãoComercial-SemDerivações 4.0 Internacional.