netaddr ipaddress address python networking ip-address python-2.x cidr

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.0

    Así 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)

Este es el enlace


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 &lt&lt (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