¿Cómo puedo verificar si una ip está en una red en Python?


100

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.


Esta pregunta parece una canónica aceptable para respuestas 2.x muy antiguas, pero es obsoleta para 3.x. Consulte ¿Cómo organizar y asignar canónicos para “Python / pandas compare IP address / CIDR”?
smci

@smci No veo por qué; La respuesta de phihag en stackoverflow.com/a/1004527/1709587 es una respuesta perfectamente buena para Python 3 y ha estado aquí desde 2014. He revertido su edición que invalidaba esa respuesta.
Mark Amery

@Staale: debe actualizar su respuesta aquí a una que no tenga un error crítico . Las otras respuestas usan bibliotecas integradas para lograr lo mismo en 1/10 de código, sin errores.
Addison

Respuestas:


30

Este artículo muestra que puede hacerlo con módulos sockety structsin demasiado esfuerzo adicional. 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 desea una función única que tome 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

8
Además, struct.unpack ('L', socket.inet_aton (ip)) [0] fallará en arquitecturas donde 'L' se descomprime en algo diferente a 4 bytes, independientemente del endianness.
Rafał Dowgird

5
Continuando con el comentario de Rafal, para que esto funcione en un intérprete de Python de 64 bits, reemplace la línea en cuestión con:return struct.unpack('<L',socket.inet_aton(ip))[0]
tonto

11
Creo que su solución tiene un error grave: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(convertí 'L' a '<L' en mi sistema operativo de 64 bits)
Taha Jahangir

20
PRECAUCIÓN: Esta solución tiene un error grave:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir

6
Esta respuesta tiene un error . Ver respuesta: stackoverflow.com/questions/819355/…
Debanshu Kundu

156

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 señaló arno_v 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!"

>>> netaddr.all_matching_cidrs ("192.168.0.1", ["192.168.0.0/24","212.11.64.0/19"]) [IPNetwork ('192.168.0.0/24')]

22
O en la nueva versión: desde netaddr import IPNetwork, IPAddress IPAddress ("192.168.0.1") en IPNetwork ("192.168.0.0/24")
arno_v

140

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 muchas direcciones IP de esta manera, probablemente 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 uno 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, puede simplemente verificar:

in_network = (a & mask) == netw

2
Tenga cuidado, python-ipaddr se comportó bastante lento para nosotros, por lo que puede no ser adecuado para algunos casos en los que se requieren muchas comparaciones con frecuencia. YMMV, así que evalúe usted mismo.
drdaeman

En algunas versiones, es posible que deba proporcionar una cadena Unicode en lugar de un tipo str de Python, como ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
Me preocupaba que este método estuviera iterando sobre la lista de direcciones en la red, pero el módulo ipaddress anula el __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. .
avatarofhope2

24

Para python3

import ipaddress
ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/24')
ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/16')

Salida:

False
True

1
La biblioteca estándar utiliza una comprobación inteligente a nivel de bits, por lo que esta es la solución más óptima aquí. github.com/python/cpython/blob/3.8/Lib/ipaddress.py#L690
rocketspacer

10

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.

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

Agradable y rapido. No se necesita una biblioteca para algunas operaciones lógicas simples.
Chris Koston

7

Usando python3 direcciónip :

import ipaddress

address = ipaddress.ip_address("192.168.0.1")
network = ipaddress.ip_network("192.168.0.0/16")

print(network.supernet_of(ipaddress.ip_network(f"{address}/{address.max_prefixlen}")))

Explicación

Puede pensar en una dirección IP como una red con la máscara de red más grande posible ( /32para IPv4, /128para IPv6)

Verificar si 192.168.0.1está en 192.168.0.0/16es esencialmente lo mismo que verificar si 192.168.0.1/32es una subred de192.168.0.0/16


... no estoy seguro de por qué esta respuesta no está en la parte superior (todavía).
Filippo Vitale

6

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:

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

Esto parece funcionar de manera confiable en 64 bits ('L' falla porque el valor es de 32 bits) y devuelve los valores en un orden sensato (ipaddr será 0xC0A80001 para 192.168.0.1). También hace frente a "192.168.0.1/24" como máscara de red para "192.168.0.1" (no estándar, pero posible y fácilmente corregible)
IBBoard

Funciona perfectamente en Python 2.4
xlash

6

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:

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.


{TypeError}'map' object is not subscriptable. Necesitas un o = list(o)despuéso = map(int, ip.split('.'))
gies0r

5

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)

Esta es, con mucho, mi favorita de todas las innumerables opciones aquí (en el momento del comentario, 2017). ¡Gracias!
rsaw

5

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.

    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 con puntos para ayudar a visualizar el enmascaramiento ... una especie de ipcalcsalida similar .

    def bb(i):
     def s = '{:032b}'.format(i)
     def return s[0:8]+"."+s[8:16]+"."+s[16:24]+"."+s[24:32]

p.ej:

captura de pantalla de pitón


4

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 mucho tiempo para que este código funcionara y gracias a Marc por la respuesta correcta.


Tratado y probado. De todos los ejemplos de socket / struct en esta página, este es el único correcto
Zabuzzman

4

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:

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 (), contra un conjunto completo de redes de origen permitidas, por lo que precalculo máscaras y redes, como números 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

Entonces puedo ver rápidamente si una IP determinada está 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 se empareja muy rápido.


¿A qué se refiere esto cached_masks?
ajin

2

desde netaddr importar 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, proporcionas una dirección IP como primer argumento y una lista de sidras como segundo argumento. Se devuelve una lista de resultados.


2
# Esto funciona correctamente sin el extraño manejo byte por byte
def addressInNetwork (ip, net):
    '' 'Es una dirección en una red' ''
    # Convierta direcciones en orden de host, por lo que los turnos realmente tienen sentido
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bits = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Debe desplazarse a la izquierda y el valor de todos unos, / 32 = desplazamiento a cero, / 0 = 32 desplazamiento a la izquierda
    máscara de red = (0xffffffff << (32-int (bits))) & 0xffffffff
    # No es necesario enmascarar la dirección de red, siempre que sea una dirección de red adecuada
    return (ip y máscara de red) == netaddr 

El código no funcionó correctamente en sistemas operativos de 64 bits debido a netmaskvalores incorrectos . Me he tomado la libertad de arreglar eso.
drdaeman

2

La solución anterior tiene un error en ip & net == net. La búsqueda de IP correcta 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");

2

La respuesta elegida tiene un error.

A continuación se muestra 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: en ipaddr & netmask == netaddr & netmasklugar 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.


Creo que la conversión de la máscara ((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.
Chris.Q

@ Chris.Q, ((1L << int(bits)) - 1)da 65535L en mi sistema, con el bitsvalor 16 !!
Debanshu Kundu

Además, para bitsestablecer en 0, ((2L<<int(bits)-1) - 1)genera un error.
Debanshu Kundu

Sí, en realidad ningún valor que no sea / 0, / 8, / 16, / 32 funciona correctamente.
Debanshu Kundu

2

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

1

¡Gracias por tu guión!
He trabajado bastante para que todo funcione ... Así que lo comparto aquí

  • Usar la clase netaddr es 10 veces más lento que usar la conversión binaria, por lo que si desea usarlo en una gran lista de IP, debe 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/
    Ej:


#!/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 netmask).
    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!!

Entonces 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, ahorrándoles tiempo!


1
la versión actual del código anterior da un seguimiento en la última línea, que puede "| =" un int y una tupla.
Sean Reifschneider

1

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

struct.unpack('!L', ... )

1
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
Verdadero
Falso


¿Puede explicar qué está agregando a las respuestas ya dadas?
David Guyon

Las respuestas dadas tienen algún problema, que no pudo manejar CIDR. Acabo de cambiar el orden de bytes de la dirección IP. Justo así:>>> struct.unpack('!L',socket.inet_aton('10.10.10.110'))[0] 168430190 >>> socket.inet_ntoa(struct.pack('!L', 168430190)) '10.10.10.110'
Johnson

1
Gracias por la respuesta. Supongo que es algo que debería agregar a su respuesta para aclarar. Está en el espíritu de StackOverflow explicar el "qué", "por qué" y finalmente "cómo". Tu respuesta solo contiene el "cómo" :(. Te dejo completar tu respuesta editándola;).
David Guyon


0

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.

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)

0

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


0

Aqui esta mi codigo

# -*- 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')

0

Si no desea importar otros módulos, puede optar por:

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]

0

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.

IP2IntEl 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:

def IP2Int(ip):
    o = map(int, ip.split('.'))
    res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
    return res


def addressInNetwork(ip, net_n_bits):
    ipaddr = IP2Int(ip)
    net, bits = net_n_bits.split('/')
    netaddr = IP2Int(net)
    bits_num = int(bits)
    netmask = ((1L << bits_num) - 1) << (32 - bits_num)
    return ipaddr & netmask == netaddr & netmask

Espero útil,


0

Aquí está la solución usando el paquete netaddr

from netaddr import IPNetwork, IPAddress


def network_has_ip(network, ip):

    if not isinstance(network, IPNetwork):
        raise Exception("network parameter must be {0} instance".format(IPNetwork.__name__))

    if not isinstance(ip, IPAddress):
        raise Exception("ip parameter must be {0} instance".format(IPAddress.__name__))

    return (network.cidr.ip.value & network.netmask.value) == (ip.value & network.netmask.value)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.