Dado um endereço IP (digamos 192.168.0.1), como faço para verificar se ele está em uma rede (digamos 192.168.0.0/24) no Python?
Existem ferramentas gerais em Python para manipulação de endereços IP? Coisas como pesquisas de host, endereço de IP para int, endereço de rede com máscara de rede para int e assim por diante? Esperançosamente na biblioteca Python padrão para 2.5.
python
networking
ip-address
cidr
Staale
fonte
fonte
Respostas:
Este artigo mostra que você pode fazê-lo com
socket
estruct
módulos sem muito esforço extra. Eu adicionei um pouco ao artigo da seguinte maneira:Isso resulta em:
Se você quiser apenas uma única função que receba strings, ela ficaria assim:
fonte
return struct.unpack('<L',socket.inet_aton(ip))[0]
addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
(converti 'L' em '<L' em meu sistema operacional de 64 bits)addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Eu gosto de usar o netaddr para isso:
Como arno_v apontou nos comentários, a nova versão do netaddr faz assim:
fonte
Usando ipaddress ( no stdlib desde 3.3 , no PyPi para 2.6 / 2.7 ):
Se você quiser avaliar muitos endereços IP dessa maneira, provavelmente desejará calcular a máscara de rede antecipadamente, como
Então, para cada endereço, calcule a representação binária com um de
Finalmente, você pode simplesmente verificar:
fonte
ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24')
.__contains__
método para fazê-lo de forma eficiente, comparando as representações inteiras da rede e dos endereços de broadcast, então fique tranquilo se essa foi a sua preocupação .Para python3
Resultado :
fonte
Este código está funcionando para mim no Linux x86. Eu realmente não pensei em problemas de endianess, mas eu o testei no módulo "ipaddr" usando mais de 200 mil endereços IP testados em 8 strings de rede diferentes, e os resultados de ipaddr são iguais a este código.
Exemplo:
fonte
Usando ipaddress Python3 :
Explicação
Você pode pensar em um endereço IP como uma rede com a maior máscara de rede possível (
/32
para IPv4,/128
para IPv6)Verificar se
192.168.0.1
está dentro192.168.0.0/16
é essencialmente o mesmo que verificar se192.168.0.1/32
é uma sub-rede de192.168.0.0/16
fonte
Tentei a solução de Dave Webb, mas encontrei alguns problemas:
Mais fundamentalmente - uma correspondência deve ser verificada colocando o endereço IP em AND com a máscara e, em seguida, verificando se o resultado corresponde ao endereço de rede exatamente. Não fazer AND do endereço IP com o endereço de rede como foi feito.
Eu também percebi que simplesmente ignorar o comportamento de Endian, assumindo que a consistência o salvará, funcionará apenas para máscaras nos limites do octeto (/ 24, / 16). Para que outras máscaras (/ 23, / 21) funcionem corretamente, adicionei um "maior que" aos comandos de estrutura e alterei o código para a criação da máscara binária para começar com "1" e deslocar para a esquerda em (32-máscara )
Por fim, adicionei uma verificação simples de que o endereço de rede é válido para a máscara e apenas imprimo um aviso se não for.
Aqui está o resultado:
fonte
Não sou fã de usar módulos quando eles não são necessários. Este trabalho requer apenas matemática simples, então aqui está minha função simples para fazer o trabalho:
Então, para usá-lo:
É isso, é muito mais rápido do que as soluções acima com os módulos incluídos.
fonte
{TypeError}'map' object is not subscriptable
. Você precisa de umo = list(o)
aftero = map(int, ip.split('.'))
Não na biblioteca padrão para 2.5, mas ipaddr torna isso muito fácil. Acredito que esteja no 3.3 com o nome ipaddress.
fonte
A resposta aceita não funciona ... o que está me deixando com raiva. A máscara está invertida e não funciona com nenhum bit que não seja um bloco de 8 bits simples (por exemplo, / 24). Adaptei a resposta e funciona bem.
aqui está uma função que retorna uma string binária pontilhada para ajudar a visualizar o mascaramento .. tipo de
ipcalc
saída semelhante .por exemplo:
fonte
O código de Marc está quase correto. Uma versão completa do código é -
Obviamente, das mesmas fontes acima ...
Uma observação muito importante é que o primeiro código tem uma pequena falha - O endereço IP 255.255.255.255 também aparece como um IP válido para qualquer sub-rede. Tive muito tempo para fazer esse código funcionar e agradeço ao Marc pela resposta correta.
fonte
Depender do módulo "struct" pode causar problemas com endian-ness e tamanhos de tipo, e simplesmente não é necessário. Nem socket.inet_aton (). Python funciona muito bem com endereços IP quádruplos com pontos:
Preciso fazer a correspondência de IP em cada chamada accept () de soquete, em relação a todo um conjunto de redes de origem permitidas, então eu pré-calculo máscaras e redes, como números inteiros:
Então posso ver rapidamente se um determinado IP está dentro de uma dessas redes:
Nenhuma importação de módulo necessária e o código é muito rápido na correspondência.
fonte
from netaddr import all_matching_cidrs
Aqui está o uso para este método:
Basicamente, você fornece um endereço IP como o primeiro argumento e uma lista de cidrs como o segundo argumento. Uma lista de resultados é retornada.
fonte
fonte
netmask
valores incorretos . Tomei a liberdade de consertar isso.solução anterior tem um bug em ip & net == net. A pesquisa de ip correta é ip & netmask = net
código corrigido para bugs:
fonte
A resposta escolhida tem um bug.
A seguir está o código correto:
Nota: em
ipaddr & netmask == netaddr & netmask
vez deipaddr & netmask == netmask
.Eu também substituo
((2L<<int(bits)-1) - 1)
por((1L << int(bits)) - 1)
, pois este último parece mais compreensível.fonte
((2L<<int(bits)-1) - 1)
está correta. por exemplo, se a máscara for 16, deve ser "255.255.0.0" ou 65535L, mas((1L << int(bits)) - 1)
obterá 32767L, o que não está certo.((1L << int(bits)) - 1)
dá 65535L no meu sistema, combits
definido para 16 !!bits
definido como0
,((2L<<int(bits)-1) - 1)
está gerando erro.Aqui está uma classe que escrevi para correspondência de prefixo mais longa:
E aqui está um programa de teste:
fonte
Obrigado pelo seu roteiro!
Tenho trabalhado bastante nisso para fazer tudo funcionar ... Então, estou compartilhando isso aqui
A função makeMask não está funcionando! Funcionando apenas para / 8, / 16, / 24
Ex:
Então, usei outra função calcDottedNetmask (máscara) de http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
Ex:
Ex: por enquanto, a função está errada
Portanto, minha nova função addressInNetwork se parece com:
E agora, a resposta é certa !!
Espero que ajude outras pessoas, economizando tempo para elas!
fonte
Com relação a todos os itens acima, acho que socket.inet_aton () retorna bytes na ordem da rede, então a maneira correta de descompactá-los é provavelmente
fonte
$ python check-subnet.py
False
True
False
fonte
>>> struct.unpack('!L',socket.inet_aton('10.10.10.110'))[0] 168430190 >>> socket.inet_ntoa(struct.pack('!L', 168430190)) '10.10.10.110'
Não sei de nada na biblioteca padrão, mas PySubnetTree é uma biblioteca Python que fará correspondência de sub-rede.
fonte
De várias fontes acima e de minha própria pesquisa, foi assim que fiz o cálculo de sub-rede e endereço funcionar. Essas peças são suficientes para resolver a questão e outras questões relacionadas.
fonte
Existe uma API chamada SubnetTree disponível em python que faz esse trabalho muito bem. Este é um exemplo simples:
Este é o link
fonte
Aqui está meu código
fonte
Se você não quiser importar outros módulos, você pode ir com:
fonte
Eu tentei um subconjunto de soluções propostas nessas respostas ... sem sucesso, finalmente adaptei e fixei o código proposto e escrevi minha função fixa.
Eu testei e funciona pelo menos em arquiteturas little endian - egx86 - se alguém gosta de experimentar uma arquitetura big endian, por favor me dê um feedback.
IP2Int
código vem desta postagem , o outro método é totalmente (para meus casos de teste) uma correção de trabalho de propostas anteriores nesta questão.O código:
Espero que seja útil,
fonte
Aqui está a solução usando o pacote netaddr
fonte