ipaddress - ¿Cómo puedo verificar si una ip está en una red en Python 2.x?
python get ip address (23)
de netaddr import all_matching_cidrs
>>> from netaddr import all_matching_cidrs
>>> all_matching_cidrs("212.11.70.34", ["192.168.0.0/24","212.11.64.0/19"] )
[IPNetwork(''212.11.64.0/19'')]
Aquí está el uso de este método:
>>> help(all_matching_cidrs)
Help on function all_matching_cidrs in module netaddr.ip:
all_matching_cidrs(ip, cidrs)
Matches an IP address or subnet against a given sequence of IP addresses and subnets.
@param ip: a single IP address or subnet.
@param cidrs: a sequence of IP addresses and/or subnets.
@return: all matching IPAddress and/or IPNetwork objects from the provided
sequence, an empty list if there was no match.
Básicamente, usted proporciona una dirección IP como primer argumento y una lista de cidrs como segundo argumento. Se devuelve una lista de visitas.
Dada una dirección IP (digamos 192.168.0.1), ¿cómo puedo verificar si está en una red (digamos 192.168.0.0/24) en Python?
¿Hay herramientas generales en Python para la manipulación de direcciones IP? ¿Cosas como búsquedas de host, direcciones IP en int, direcciones de red con netmask en int, etc.? Esperemos que en la biblioteca estándar de Python para 2.5.
¡Gracias por tu guion!
He trabajado bastante para que todo funcione ... Así que lo estoy compartiendo aquí
- El uso de netaddr Class es 10 veces más lento que el uso de la conversión binaria, por lo que si desea usarlo en una gran lista de IP, debería considerar no usar la clase netaddr.
la función makeMask no funciona! Solo trabajando para / 8, / 16, / 24
Ex:bits = "21"; socket.inet_ntoa (struct.pack (''= L'', (2L << int (bits) -1) - 1))
''255.255.31.0'' mientras que debería ser 255.255.248.0Así que he usado otra función calcDottedNetmask (máscara) de http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
Ex:
#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> ''255.255.248.0''
- Otro problema es el proceso de emparejar si una IP pertenece a una red. La operación básica debe ser comparar (ipaddr y netmask) y (red y máscara de red).
Ej .: por el momento, la función es incorrecta
#!/usr/bin/python
>>> addressInNetwork(''188.104.8.64'',''172.16.0.0/12'')
>>>True which is completely WRONG!!
Así que mi nueva función addressInNetwork se parece a:
#!/usr/bin/python
import socket,struct
def addressInNetwork(ip,net):
''''''This function allows you to check if on IP belogs to a Network''''''
ipaddr = struct.unpack(''=L'',socket.inet_aton(ip))[0]
netaddr,bits = net.split(''/'')
netmask = struct.unpack(''=L'',socket.inet_aton(calcDottedNetmask(bits)))[0]
network = struct.unpack(''=L'',socket.inet_aton(netaddr))[0] & netmask
return (ipaddr & netmask) == (network & netmask)
def calcDottedNetmask(mask):
bits = 0
for i in xrange(32-int(mask),32):
bits |= (1 > 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8 , (bits & 0xff))
Y ahora, ¡la respuesta es correcta!
#!/usr/bin/python
>>> addressInNetwork(''188.104.8.64'',''172.16.0.0/12'')
False
¡Espero que ayude a otras personas, ahorrando tiempo para ellos!
Aquí está mi código
# -*- coding: utf-8 -*-
import socket
class SubnetTest(object):
def __init__(self, network):
self.network, self.netmask = network.split(''/'')
self._network_int = int(socket.inet_aton(self.network).encode(''hex''), 16)
self._mask = ((1L << int(self.netmask)) - 1) << (32 - int(self.netmask))
self._net_prefix = self._network_int & self._mask
def match(self, ip):
''''''
判断传入的 IP 是不是本 Network 内的 IP
''''''
ip_int = int(socket.inet_aton(ip).encode(''hex''), 16)
return (ip_int & self._mask) == self._net_prefix
st = SubnetTest(''100.98.21.0/24'')
print st.match(''100.98.23.32'')
Aquí hay una clase que escribí para la coincidencia de prefijo más larga:
#!/usr/bin/env python
class Node:
def __init__(self):
self.left_child = None
self.right_child = None
self.data = "-"
def setData(self, data): self.data = data
def setLeft(self, pointer): self.left_child = pointer
def setRight(self, pointer): self.right_child = pointer
def getData(self): return self.data
def getLeft(self): return self.left_child
def getRight(self): return self.right_child
def __str__(self):
return "LC: %s RC: %s data: %s" % (self.left_child, self.right_child, self.data)
class LPMTrie:
def __init__(self):
self.nodes = [Node()]
self.curr_node_ind = 0
def addPrefix(self, prefix):
self.curr_node_ind = 0
prefix_bits = ''''.join([bin(int(x)+256)[3:] for x in prefix.split(''/'')[0].split(''.'')])
prefix_length = int(prefix.split(''/'')[1])
for i in xrange(0, prefix_length):
if (prefix_bits[i] == ''1''):
if (self.nodes[self.curr_node_ind].getRight()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getRight()
else:
tmp = Node()
self.nodes[self.curr_node_ind].setRight(len(self.nodes))
tmp.setData(self.nodes[self.curr_node_ind].getData());
self.curr_node_ind = len(self.nodes)
self.nodes.append(tmp)
else:
if (self.nodes[self.curr_node_ind].getLeft()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getLeft()
else:
tmp = Node()
self.nodes[self.curr_node_ind].setLeft(len(self.nodes))
tmp.setData(self.nodes[self.curr_node_ind].getData());
self.curr_node_ind = len(self.nodes)
self.nodes.append(tmp)
if i == prefix_length - 1 :
self.nodes[self.curr_node_ind].setData(prefix)
def searchPrefix(self, ip):
self.curr_node_ind = 0
ip_bits = ''''.join([bin(int(x)+256)[3:] for x in ip.split(''.'')])
for i in xrange(0, 32):
if (ip_bits[i] == ''1''):
if (self.nodes[self.curr_node_ind].getRight()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getRight()
else:
return self.nodes[self.curr_node_ind].getData()
else:
if (self.nodes[self.curr_node_ind].getLeft()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getLeft()
else:
return self.nodes[self.curr_node_ind].getData()
return None
def triePrint(self):
n = 1
for i in self.nodes:
print n, '':''
print i
n += 1
Y aquí hay un programa de prueba:
n=LPMTrie()
n.addPrefix(''10.25.63.0/24'')
n.addPrefix(''10.25.63.0/16'')
n.addPrefix(''100.25.63.2/8'')
n.addPrefix(''100.25.0.3/16'')
print n.searchPrefix(''10.25.63.152'')
print n.searchPrefix(''100.25.63.200'')
#10.25.63.0/24
#100.25.0.3/16
Confiar en el módulo "struct" puede causar problemas con endian-ness y tamaños de letra, y simplemente no es necesario. Tampoco es socket.inet_aton (). Python funciona muy bien con direcciones IP de cuatro puntos:
def ip_to_u32(ip):
return int(''''.join(''%02x'' % int(d) for d in ip.split(''.'')), 16)
Necesito hacer una coincidencia de IP en cada llamada de socket accept (), frente a un conjunto completo de redes de origen permitidas, así que precomputo máscaras y redes, como enteros:
SNS_SOURCES = [
# US-EAST-1
''207.171.167.101'',
''207.171.167.25'',
''207.171.167.26'',
''207.171.172.6'',
''54.239.98.0/24'',
''54.240.217.16/29'',
''54.240.217.8/29'',
''54.240.217.64/28'',
''54.240.217.80/29'',
''72.21.196.64/29'',
''72.21.198.64/29'',
''72.21.198.72'',
''72.21.217.0/24'',
]
def build_masks():
masks = [ ]
for cidr in SNS_SOURCES:
if ''/'' in cidr:
netstr, bits = cidr.split(''/'')
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
net = ip_to_u32(netstr) & mask
else:
mask = 0xffffffff
net = ip_to_u32(cidr)
masks.append((mask, net))
return masks
Luego puedo ver rápidamente si una IP dada se encuentra dentro de una de esas redes:
ip = ip_to_u32(ipstr)
for mask, net in cached_masks:
if ip & mask == net:
# matched!
break
else:
raise BadClientIP(ipstr)
No se necesitan importaciones de módulos, y el código es muy rápido en la coincidencia.
De varias fuentes anteriores, y de mi propia investigación, así es como funcionó el cálculo de subredes y direcciones. Estas piezas son suficientes para resolver la pregunta y otras preguntas relacionadas.
class iptools:
@staticmethod
def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack(''>L'', socket.inet_aton(ip))[0]
@staticmethod
def numToDottedQuad(n):
"convert long int to dotted quad string"
return socket.inet_ntoa(struct.pack(''>L'', n))
@staticmethod
def makeNetmask(mask):
bits = 0
for i in xrange(32-int(mask), 32):
bits |= (1 << i)
return bits
@staticmethod
def ipToNetAndHost(ip, maskbits):
"returns tuple (network, host) dotted-quad addresses given"
" IP and mask size"
# (by Greg Jorgensen)
n = iptools.dottedQuadToNum(ip)
m = iptools.makeMask(maskbits)
net = n & m
host = n - mask
return iptools.numToDottedQuad(net), iptools.numToDottedQuad(host)
El código de Marc es casi correcto. Una versión completa del código es -
def addressInNetwork3(ip,net):
''''''This function allows you to check if on IP belogs to a Network''''''
ipaddr = struct.unpack(''=L'',socket.inet_aton(ip))[0]
netaddr,bits = net.split(''/'')
netmask = struct.unpack(''=L'',socket.inet_aton(calcDottedNetmask(int(bits))))[0]
network = struct.unpack(''=L'',socket.inet_aton(netaddr))[0] & netmask
return (ipaddr & netmask) == (network & netmask)
def calcDottedNetmask(mask):
bits = 0
for i in xrange(32-mask,32):
bits |= (1 << i)
return "%d.%d.%d.%d" % ((bits & 0xff000000) >> 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8 , (bits & 0xff))
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 muchísimo tiempo para que este código funcionara y gracias a Marc por la respuesta correcta.
En relación con todo lo anterior, creo que socket.inet_aton () devuelve bytes en orden de red, por lo que es probable que la forma correcta de descomprimirlos sea
struct.unpack(''!L'', ... )
Este código me funciona en Linux x86. Realmente no he pensado en 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 este código.
def addressInNetwork(ip, net):
import socket,struct
ipaddr = int(''''.join([ ''%02x'' % int(x) for x in ip.split(''.'') ]), 16)
netstr, bits = net.split(''/'')
netaddr = int(''''.join([ ''%02x'' % int(x) for x in netstr.split(''.'') ]), 16)
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
return (ipaddr & mask) == (netaddr & mask)
Ejemplo:
>>> print addressInNetwork(''10.9.8.7'', ''10.9.1.0/16'')
True
>>> print addressInNetwork(''10.9.8.7'', ''10.9.1.0/24'')
False
Hay una API llamada SubnetTree disponible en python que hace este trabajo muy bien. Este es un ejemplo simple :
import SubnetTree
t = SubnetTree.SubnetTree()
t.insert("10.0.1.3/32")
print("10.0.1.3" in t)
Intenté la solución de Dave Webb pero tuve algunos problemas:
Lo más fundamental es que se verifique una coincidencia mediante ANDing la dirección IP con la máscara, y luego verificando el resultado que coincide exactamente con la dirección de red. No ANDing la dirección IP con la dirección de red como se hizo.
También me di cuenta de que ignorar el comportamiento de Endian suponiendo que la coherencia te salvará solo funcionará para las máscaras en los límites de los octetos (/ 24, / 16). Para obtener otras máscaras (/ 23, / 21) funcionando correctamente, agregué un "mayor que" a los comandos struct y cambié el código para crear la máscara binaria para comenzar con todo "1" y cambiar a la izquierda por (32-máscara )
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 es así.
Este es el resultado:
def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack(''>L'',socket.inet_aton(ip))[0]
netaddr,bits = net.split(''/'')
netmask = struct.unpack(''>L'',socket.inet_aton(netaddr))[0]
ipaddr_masked = ipaddr & (4294967295<<(32-int(bits))) # Logical AND of IP address and mask will equal the network address if it matches
if netmask == netmask & (4294967295<<(32-int(bits))): # Validate network address is valid for mask
return ipaddr_masked == netmask
else:
print "***WARNING*** Network",netaddr,"not valid with mask /"+bits
return ipaddr_masked == netmask
La respuesta aceptada no funciona ... lo que me enoja. La máscara está hacia atrás y no funciona con ningún bit que no sea un simple bloque de 8 bits (p. Ej., / 24). Adapte la respuesta, y funciona muy bien.
import socket,struct
def addressInNetwork(ip, net_n_bits):
ipaddr = struct.unpack(''!L'', socket.inet_aton(ip))[0]
net, bits = net_n_bits.split(''/'')
netaddr = struct.unpack(''!L'', socket.inet_aton(net))[0]
netmask = (0xFFFFFFFF >> int(bits)) ^ 0xFFFFFFFF
return ipaddr & netmask == netaddr
aquí hay una función que devuelve una cadena binaria punteada para ayudar a visualizar el enmascaramiento ... tipo de salida ipcalc
.
def bb(i):
def s = ''{:032b}''.format(i)
def return s[0:8]+"."+s[8:16]+"."+s[16:24]+"."+s[24:32]
p.ej:
La respuesta elegida tiene un error.
A continuación está el código correcto:
def addressInNetwork(ip, net_n_bits):
ipaddr = struct.unpack(''<L'', socket.inet_aton(ip))[0]
net, bits = net_n_bits.split(''/'')
netaddr = struct.unpack(''<L'', socket.inet_aton(net))[0]
netmask = ((1L << int(bits)) - 1)
return ipaddr & netmask == netaddr & netmask
Nota: ipaddr & netmask == netaddr & netmask
lugar de ipaddr & netmask == netmask
.
También reemplazo ((2L<<int(bits)-1) - 1)
con ((1L << int(bits)) - 1)
, ya que este último parece más comprensible.
Me gusta usar netaddr para eso:
from netaddr import CIDR, IP
if IP("192.168.0.1") in CIDR("192.168.0.0/24"):
print "Yay!"
Como arno_v señaló en los comentarios, la nueva versión de netaddr lo hace así:
from netaddr import IPNetwork, IPAddress
if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"):
print "Yay!"
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.
import ipaddr
a = ipaddr.IPAddress(''192.168.0.1'')
n = ipaddr.IPNetwork(''192.168.0.0/24'')
#This will return True
n.Contains(a)
No sé nada de la biblioteca estándar, pero PySubnetTree es una biblioteca de Python que hará la coincidencia de subredes.
No soy partidario de usar módulos cuando no son necesarios. Este trabajo solo requiere matemática simple, así que aquí está mi sencilla función para hacer el trabajo:
def ipToInt(ip):
o = map(int, ip.split(''.''))
res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
return res
def isIpInSubnet(ip, ipNetwork, maskLength):
ipInt = ipToInt(ip)#my test ip, in int form
maskLengthFromRight = 32 - maskLength
ipNetworkInt = ipToInt(ipNetwork) #convert the ip network into integer form
binString = "{0:b}".format(ipNetworkInt) #convert that into into binary (string format)
chopAmount = 0 #find out how much of that int I need to cut off
for i in range(maskLengthFromRight):
if i < len(binString):
chopAmount += int(binString[len(binString)-1-i]) * 2**i
minVal = ipNetworkInt-chopAmount
maxVal = minVal+2**maskLengthFromRight -1
return minVal <= ipInt and ipInt <= maxVal
Entonces para usarlo:
>>> print isIpInSubnet(''66.151.97.0'', ''66.151.97.192'',24)
True
>>> print isIpInSubnet(''66.151.97.193'', ''66.151.97.192'',29)
True
>>> print isIpInSubnet(''66.151.96.0'', ''66.151.97.192'',24)
False
>>> print isIpInSubnet(''66.151.97.0'', ''66.151.97.192'',29)
Eso es todo, esto es mucho más rápido que las soluciones anteriores con los módulos incluidos.
Si no desea importar otros módulos, puede ir con:
def ip_matches_network(self, network, ip):
"""
''{:08b}''.format(254): Converts 254 in a string of its binary representation
ip_bits[:net_mask] == net_ip_bits[:net_mask]: compare the ip bit streams
:param network: string like ''192.168.33.0/24''
:param ip: string like ''192.168.33.1''
:return: if ip matches network
"""
net_ip, net_mask = network.split(''/'')
net_mask = int(net_mask)
ip_bits = ''''.join(''{:08b}''.format(int(x)) for x in ip.split(''.''))
net_ip_bits = ''''.join(''{:08b}''.format(int(x)) for x in net_ip.split(''.''))
# example: net_mask=24 -> compare strings at position 0 to 23
return ip_bits[:net_mask] == net_ip_bits[:net_mask]
Usando ipaddress ( en stdlib desde 3.3 , en PyPi para 2.6 / 2.7 ):
>>> import ipaddress
>>> ipaddress.ip_address(''192.168.0.1'') in ipaddress.ip_network(''192.168.0.0/24'')
True
Si desea evaluar una gran cantidad de direcciones IP de esta manera, es probable que desee calcular la máscara de red por adelantado, como
n = ipaddress.ip_network(''192.0.0.0/16'')
netw = int(n.network_address)
mask = int(n.netmask)
Luego, para cada dirección, calcule la representación binaria con una de
a = int(ipaddress.ip_address(''192.0.43.10''))
a = struct.unpack(''!I'', socket.inet_pton(socket.AF_INET, ''192.0.43.10''))[0]
a = struct.unpack(''!I'', socket.inet_aton(''192.0.43.10''))[0] # IPv4 only
Finalmente, simplemente puede verificar:
in_network = (a & mask) == netw
Este artículo muestra que puedes hacerlo con módulos socket
y struct
sin demasiado esfuerzo extra. Agregué un poco al artículo de la siguiente manera:
import socket,struct
def makeMask(n):
"return a mask of n bits as a long integer"
return (2L<<n-1) - 1
def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack(''L'',socket.inet_aton(ip))[0]
def networkMask(ip,bits):
"Convert a network address to a long integer"
return dottedQuadToNum(ip) & makeMask(bits)
def addressInNetwork(ip,net):
"Is an address in a network"
return ip & net == net
address = dottedQuadToNum("192.168.1.1")
networka = networkMask("10.0.0.0",24)
networkb = networkMask("192.168.0.0",24)
print (address,networka,networkb)
print addressInNetwork(address,networka)
print addressInNetwork(address,networkb)
Esto produce:
False
True
Si solo quieres una sola función que tenga cadenas, se vería así:
import socket,struct
def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack(''L'',socket.inet_aton(ip))[0]
netaddr,bits = net.split(''/'')
netmask = struct.unpack(''L'',socket.inet_aton(netaddr))[0] & ((2L<<int(bits)-1) - 1)
return ipaddr & netmask == netmask
la solución anterior tiene un error en ip & net == net. Corregir la búsqueda de IP es ip & netmask = net
código corregido
import socket
import struct
def makeMask(n):
"return a mask of n bits as a long integer"
return (2L<<n-1) - 1
def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack(''L'',socket.inet_aton(ip))[0]
def addressInNetwork(ip,net,netmask):
"Is an address in a network"
print "IP "+str(ip) + " NET "+str(net) + " MASK "+str(netmask)+" AND "+str(ip & netmask)
return ip & netmask == net
def humannetcheck(ip,net):
address=dottedQuadToNum(ip)
netaddr=dottedQuadToNum(net.split("/")[0])
netmask=makeMask(long(net.split("/")[1]))
return addressInNetwork(address,netaddr,netmask)
print humannetcheck("192.168.0.1","192.168.0.0/24");
print humannetcheck("192.169.0.1","192.168.0.0/24");
#This works properly without the weird byte by byte handling def addressInNetwork(ip,net): ''''''Is an address in a network'''''' # Convert addresses to host order, so shifts actually make sense ip = struct.unpack(''>L'',socket.inet_aton(ip))[0] netaddr,bits = net.split(''/'') netaddr = struct.unpack(''>L'',socket.inet_aton(netaddr))[0] # Must shift left an all ones value, /32 = zero shift, /0 = 32 shift left netmask = (0xffffffff << (32-int(bits))) & 0xffffffff # There''s no need to mask the network address, as long as its a proper network address return (ip & netmask) == netaddr
import socket,struct
def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack(''!L'',socket.inet_aton(ip))[0]
netaddr,bits = net.split(''/'')
netaddr = struct.unpack(''!L'',socket.inet_aton(netaddr))[0]
netmask = ((1<<(32-int(bits))) - 1)^0xffffffff
return ipaddr & netmask == netaddr & netmask
print addressInNetwork(''10.10.10.110'',''10.10.10.128/25'')
print addressInNetwork(''10.10.10.110'',''10.10.10.0/25'')
print addressInNetwork(''10.10.10.110'',''10.20.10.128/25'')
$ python check-subnet.py
Falso
Cierto
Falso