Dada una dirección IP (digamos 192.168.0.1), ¿cómo verifico si está en una red (digamos 192.168.0.0/24) en Python?
¿Existen herramientas generales en Python para la manipulación de direcciones IP? ¿Cosas como búsquedas de host, dirección IP a int, dirección de red con máscara de red a int y así sucesivamente? Con suerte, en la biblioteca estándar de Python para 2.5.
python
networking
ip-address
cidr
Staale
fuente
fuente
Respuestas:
Este artículo muestra que puede hacerlo con módulos
socket
ystruct
sin demasiado esfuerzo adicional. Agregué un poco al artículo de la siguiente manera:Esto produce:
Si solo desea una función única que tome cadenas, se vería así:
fuente
return struct.unpack('<L',socket.inet_aton(ip))[0]
addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
(convertí 'L' a '<L' en mi sistema operativo de 64 bits)addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Me gusta usar netaddr para eso:
Como señaló arno_v en los comentarios, la nueva versión de netaddr lo hace así:
fuente
Usando ipaddress ( en stdlib desde 3.3 , en PyPi para 2.6 / 2.7 ):
Si desea evaluar muchas direcciones IP de esta manera, probablemente desee calcular la máscara de red por adelantado, como
Luego, para cada dirección, calcule la representación binaria con uno de
Finalmente, puede simplemente verificar:
fuente
ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24')
.__contains__
método para hacerlo de una manera eficiente al comparar las representaciones enteras de la red y las direcciones de transmisión, así que tenga la seguridad de que esa fue su preocupación. .Para python3
Salida:
fuente
Este código me funciona en Linux x86. Realmente no he pensado en los problemas de endianess, pero lo he probado contra el módulo "ipaddr" usando más de 200K direcciones IP probadas contra 8 cadenas de red diferentes, y los resultados de ipaddr son los mismos que en este código.
Ejemplo:
fuente
Usando python3 direcciónip :
Explicación
Puede pensar en una dirección IP como una red con la máscara de red más grande posible (
/32
para IPv4,/128
para IPv6)Verificar si
192.168.0.1
está en192.168.0.0/16
es esencialmente lo mismo que verificar si192.168.0.1/32
es una subred de192.168.0.0/16
fuente
Probé la solución de Dave Webb pero encontré algunos problemas:
Lo más fundamental: una coincidencia debe comprobarse haciendo una operación AND de la dirección IP con la máscara, y luego verificando que el resultado coincida exactamente con la dirección de red. No anotar la dirección IP con la dirección de red como se hizo.
También noté que simplemente ignorar el comportamiento de Endian, asumiendo que la consistencia lo salvará, solo funcionará para máscaras en los límites de octetos (/ 24, / 16). Para que otras máscaras (/ 23, / 21) funcionen correctamente, agregué un "mayor que" a los comandos de estructura y cambié el código para crear la máscara binaria para comenzar con todo "1" y desplazar hacia la izquierda (32-mask ).
Finalmente, agregué una simple verificación de que la dirección de red es válida para la máscara y solo imprimo una advertencia si no lo es.
Aquí está el resultado:
fuente
No soy fanático de usar módulos cuando no son necesarios. Este trabajo solo requiere matemáticas simples, así que aquí está mi función simple para hacer el trabajo:
Entonces para usarlo:
Eso es todo, esto es mucho más rápido que las soluciones anteriores con los módulos incluidos.
fuente
{TypeError}'map' object is not subscriptable
. Necesitas uno = list(o)
despuéso = map(int, ip.split('.'))
No en la biblioteca estándar para 2.5, pero ipaddr lo hace muy fácil. Creo que está en 3.3 bajo el nombre ipaddress.
fuente
La respuesta aceptada no funciona ... lo que me enoja. La máscara está al revés y no funciona con ningún bit que no sea un bloque simple de 8 bits (por ejemplo, / 24). Adapté la respuesta y funciona muy bien.
aquí hay una función que devuelve una cadena binaria con puntos para ayudar a visualizar el enmascaramiento ... una especie de
ipcalc
salida similar .p.ej:
fuente
El código de Marc es casi correcto. Una versión completa del código es:
Obviamente de las mismas fuentes que arriba ...
Una nota muy importante es que el primer código tiene un pequeño error: la dirección IP 255.255.255.255 también aparece como una IP válida para cualquier subred. Tuve mucho tiempo para que este código funcionara y gracias a Marc por la respuesta correcta.
fuente
Depender del módulo "struct" puede causar problemas con la endianidad y los tamaños de letra, y simplemente no es necesario. Tampoco socket.inet_aton (). Python funciona muy bien con direcciones IP de cuatro puntos:
Necesito hacer una coincidencia de IP en cada llamada de socket accept (), contra un conjunto completo de redes de origen permitidas, por lo que precalculo máscaras y redes, como números enteros:
Entonces puedo ver rápidamente si una IP determinada está dentro de una de esas redes:
No se necesitan importaciones de módulos y el código se empareja muy rápido.
fuente
desde netaddr importar all_matching_cidrs
Aquí está el uso de este método:
Básicamente, proporcionas una dirección IP como primer argumento y una lista de sidras como segundo argumento. Se devuelve una lista de resultados.
fuente
fuente
netmask
valores incorrectos . Me he tomado la libertad de arreglar eso.La solución anterior tiene un error en ip & net == net. La búsqueda de IP correcta es ip & netmask = net
código corregido:
fuente
La respuesta elegida tiene un error.
A continuación se muestra el código correcto:
Nota: en
ipaddr & netmask == netaddr & netmask
lugar deipaddr & netmask == netmask
.También reemplazo
((2L<<int(bits)-1) - 1)
con((1L << int(bits)) - 1)
, ya que este último parece más comprensible.fuente
((2L<<int(bits)-1) - 1)
es correcta. por ejemplo, si la máscara es 16, debería ser "255.255.0.0" o 65535L, pero((1L << int(bits)) - 1)
obtendrá 32767L, lo cual no es correcto.((1L << int(bits)) - 1)
da 65535L en mi sistema, con elbits
valor 16 !!bits
establecer en0
,((2L<<int(bits)-1) - 1)
genera un error.Aquí hay una clase que escribí para la coincidencia de prefijo más larga:
Y aquí hay un programa de prueba:
fuente
¡Gracias por tu guión!
He trabajado bastante para que todo funcione ... Así que lo comparto aquí
¡La función makeMask no funciona! Solo trabajando para / 8, / 16, / 24
Ex:
Así que he usado otra función calcDottedNetmask (máscara) de http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
Ej:
Ej: por el momento, la función es incorrecta
Entonces mi nueva función addressInNetwork se parece a:
¡¡Y ahora la respuesta es correcta !!
¡Espero que ayude a otras personas, ahorrándoles tiempo!
fuente
En relación con todo lo anterior, creo que socket.inet_aton () devuelve bytes en orden de red, por lo que la forma correcta de descomprimirlos es probablemente
fuente
$ python check-subnet.py
Falso
Verdadero
Falso
fuente
>>> struct.unpack('!L',socket.inet_aton('10.10.10.110'))[0] 168430190 >>> socket.inet_ntoa(struct.pack('!L', 168430190)) '10.10.10.110'
No conozco nada en la biblioteca estándar, pero PySubnetTree es una biblioteca de Python que hará coincidencias de subredes.
fuente
De varias fuentes anteriores, y de mi propia investigación, así es como hice que funcionara el cálculo de subred y direcciones. Estas piezas son suficientes para resolver la pregunta y otras cuestiones relacionadas.
fuente
Hay una API llamada SubnetTree disponible en Python que hace este trabajo muy bien. Este es un ejemplo simple :
Este es el enlace
fuente
Aqui esta mi codigo
fuente
Si no desea importar otros módulos, puede optar por:
fuente
Probé un subconjunto de soluciones propuestas en estas respuestas ... sin éxito, finalmente adapté y arreglé el código propuesto y escribí mi función fija.
Lo probé y funciona al menos en arquitecturas little endian, egx86, si a alguien le gusta probar una arquitectura big endian, por favor envíenme sus comentarios.
IP2Int
El código proviene de esta publicación , el otro método es una solución completamente funcional (para mis casos de prueba) de las propuestas anteriores en esta pregunta.El código:
Espero útil,
fuente
Aquí está la solución usando el paquete netaddr
fuente