Comment puis-je vérifier si une adresse IP est dans un réseau en Python?


100

Étant donné une adresse IP (par exemple 192.168.0.1), comment puis-je vérifier si elle se trouve dans un réseau (par exemple 192.168.0.0/24) en Python?

Existe-t-il des outils généraux en Python pour la manipulation d'adresses IP? Des trucs comme des recherches d'hôte, une adresse IP à int, une adresse réseau avec un masque de réseau à int et ainsi de suite? Espérons que dans la bibliothèque Python standard pour 2.5.


Cette question semble être un canonique correct pour les très anciennes réponses 2.x, mais est obsolète pour 3.x Voir Comment organiser et attribuer des canoniques pour «Python / pandas compare IP address / CIDR»?
smci

@smci je ne vois pas pourquoi; La réponse de phihag à stackoverflow.com/a/1004527/1709587 est une parfaitement bonne réponse pour Python 3 et est ici depuis 2014. J'ai annulé votre modification qui a invalidé cette réponse.
Mark Amery

@Staale - Vous devriez mettre à jour votre réponse ici pour une réponse qui n'a pas de bug critique . Les autres réponses utilisent des bibliothèques intégrées pour accomplir la même chose en 1/10 de code, sans aucun bogue.
Addison

Réponses:


30

Cet article montre que vous pouvez le faire avec socketet des structmodules sans trop d'effort supplémentaire. J'ai ajouté un peu à l'article comme suit:

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)

Cela produit:

False
True

Si vous voulez juste une seule fonction qui prend des chaînes, cela ressemblerait à ceci:

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
De plus, struct.unpack ('L', socket.inet_aton (ip)) [0] échouera sur les architectures où 'L' se décompresse en quelque chose de différent de 4 octets, indépendamment de l'endianité.
Rafał Dowgird

5
En continuant sur le commentaire de Rafal, pour que cela fonctionne sur un interpréteur Python 64 bits, remplacez la ligne en question par:return struct.unpack('<L',socket.inet_aton(ip))[0]
nitwit

11
Je pense que votre solution a un bogue sérieux: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(j'ai converti 'L' en '<L' dans mon système d'exploitation 64 bits)
Taha Jahangir

20
ATTENTION: Cette solution a un bug sérieux:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir

6
Cette réponse a un bug . Voir la réponse: stackoverflow.com/questions/819355/…
Debanshu Kundu

156

J'aime utiliser netaddr pour cela:

from netaddr import CIDR, IP

if IP("192.168.0.1") in CIDR("192.168.0.0/24"):
    print "Yay!"

Comme arno_v l'a souligné dans les commentaires, la nouvelle version de netaddr le fait comme ceci:

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
Ou dans la nouvelle version: depuis netaddr import IPNetwork, IPAddress IPAddress ("192.168.0.1") dans IPNetwork ("192.168.0.0/24")
arno_v

140

En utilisant ipaddress ( dans le stdlib depuis 3.3 , chez PyPi pour 2.6 / 2.7 ):

>>> import ipaddress
>>> ipaddress.ip_address('192.168.0.1') in ipaddress.ip_network('192.168.0.0/24')
True

Si vous souhaitez évaluer un grand nombre d'adresses IP de cette façon, vous voudrez probablement calculer le masque de réseau à l'avance, comme

n = ipaddress.ip_network('192.0.0.0/16')
netw = int(n.network_address)
mask = int(n.netmask)

Ensuite, pour chaque adresse, calculez la représentation binaire avec l'un des

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

Enfin, vous pouvez simplement vérifier:

in_network = (a & mask) == netw

2
Attention, python-ipaddr s'est comporté assez lentement pour nous, il peut donc ne pas convenir dans certains cas où de nombreuses comparaisons sont fréquemment nécessaires. YMMV, alors comparez-vous.
drdaeman

Dans certaines versions, vous devrez peut-être fournir une chaîne Unicode au lieu d'un type Python str, comme ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
Je craignais que cette méthode itère sur la liste d'adresses du réseau, mais le module ipaddress remplace la __contains__méthode pour le faire de manière efficace en comparant les représentations entières du réseau et des adresses de diffusion, alors soyez assuré si c'était votre souci .
avatarofhope2

24

Pour 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')

Production :

False
True

1
La bibliothèque standard utilise une vérification intelligente au niveau du bit, c'est donc la solution la plus optimale ici. github.com/python/cpython/blob/3.8/Lib/ipaddress.py#L690
rocketspacer

10

Ce code fonctionne pour moi sous Linux x86. Je n'ai pas vraiment réfléchi aux problèmes d'endianess, mais je l'ai testé contre le module "ipaddr" en utilisant plus de 200K adresses IP testées sur 8 chaînes réseau différentes, et les résultats d'ipaddr sont les mêmes que ce code.

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)

Exemple:

>>> print addressInNetwork('10.9.8.7', '10.9.1.0/16')
True
>>> print addressInNetwork('10.9.8.7', '10.9.1.0/24')
False

Sympa et rapide. Pas besoin de bibliothèque pour quelques opérations logiques simples.
Chris Koston

7

Utilisation de l'adresse IP Python3 :

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}")))

Explication

Vous pouvez considérer une adresse IP comme un réseau avec le plus grand masque de réseau possible ( /32pour IPv4, /128pour IPv6)

Vérifier si 192.168.0.1est dans 192.168.0.0/16est essentiellement la même que vérifier s'il 192.168.0.1/32s'agit d'un sous-réseau de192.168.0.0/16


... je ne sais pas pourquoi cette réponse n'est pas (encore) au sommet.
Filippo Vitale

6

J'ai essayé la solution de Dave Webb mais j'ai rencontré des problèmes:

Plus fondamentalement, une correspondance doit être vérifiée en associant l'adresse IP avec le masque, puis en vérifiant que le résultat correspond exactement à l'adresse réseau. Ne pas ANDing l'adresse IP avec l'adresse réseau comme cela a été fait.

J'ai également remarqué que le simple fait d'ignorer le comportement Endian en supposant que la cohérence vous sauvera ne fonctionnera que pour les masques sur les limites d'octets (/ 24, / 16). Afin de faire fonctionner correctement les autres masques (/ 23, / 21), j'ai ajouté un "supérieur à" aux commandes struct et j'ai changé le code de création du masque binaire pour qu'il commence par tout "1" et décale à gauche de (32-mask ).

Enfin, j'ai ajouté une simple vérification que l'adresse réseau est valide pour le masque et j'ai simplement imprimé un avertissement si ce n'est pas le cas.

Voici le résultat:

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

Cela semble fonctionner de manière fiable sur 64 bits («L» échoue car la valeur est 32 bits) et renvoie les valeurs dans un ordre raisonnable (ipaddr sera 0xC0A80001 pour 192.168.0.1). Il gère également "192.168.0.1/24" comme masque de réseau pour "192.168.0.1" (pas standard, mais possible et facilement corrigible)
IBBoard

Fonctionne parfaitement sur Python 2.4
xlash

6

Je ne suis pas fan de l'utilisation de modules lorsqu'ils ne sont pas nécessaires. Ce travail ne nécessite que de simples calculs, voici donc ma fonction simple pour faire le travail:

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

Alors pour l'utiliser:

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

Voilà, c'est beaucoup plus rapide que les solutions ci-dessus avec les modules inclus.


{TypeError}'map' object is not subscriptable. Vous avez besoin d'un o = list(o)aprèso = map(int, ip.split('.'))
gies0r

5

Pas dans la bibliothèque Standard pour 2.5, mais ipaddr rend cela très facile. Je crois que c'est en 3.3 sous le nom 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)

C'est de loin mon préféré parmi la myriade de choix ici (au moment du commentaire, 2017). Merci!
rsaw

5

La réponse acceptée ne fonctionne pas ... ce qui me met en colère. Le masque est à l'envers et ne fonctionne pas avec des bits qui ne sont pas un simple bloc de 8 bits (par exemple / 24). J'ai adapté la réponse et cela fonctionne 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

voici une fonction qui renvoie une chaîne binaire en pointillé pour aider à visualiser le masquage .. un peu comme une ipcalcsortie.

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

par exemple:

capture d'écran de python


4

Le code de Marc est presque correct. Une version complète du code est -

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

Evidemment des mêmes sources que ci-dessus ...

Une note très importante est que le premier code a un petit problème - L'adresse IP 255.255.255.255 apparaît également comme une adresse IP valide pour n'importe quel sous-réseau. J'ai eu beaucoup de temps à faire fonctionner ce code et merci à Marc pour la bonne réponse.


Essayé et testé. De tous les exemples de socket / struct sur cette page, c'est le seul correct
Zabuzzman

4

Se fier au module "struct" peut causer des problèmes avec les tailles d'endian-ness et de type, et n'est tout simplement pas nécessaire. Socket.inet_aton () non plus. Python fonctionne très bien avec les adresses IP à quatre points:

def ip_to_u32(ip):
  return int(''.join('%02x' % int(d) for d in ip.split('.')), 16)

Je dois faire une correspondance IP sur chaque appel de socket accept (), contre un ensemble complet de réseaux source autorisés, donc je précalcule les masques et les réseaux, sous forme d'entiers:

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

Ensuite, je peux voir rapidement si une adresse IP donnée se trouve dans l'un de ces réseaux:

ip = ip_to_u32(ipstr)
for mask, net in cached_masks:
  if ip & mask == net:
    # matched!
    break
else:
  raise BadClientIP(ipstr)

Aucune importation de module n'est nécessaire et le code est très rapide à faire correspondre.


À quoi fait référence ce cached_masks ??
ajin

2

depuis 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')]

Voici l'utilisation de cette méthode:

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

En gros, vous fournissez une adresse IP comme premier argument et une liste de cidrs comme deuxième argument. Une liste de résultats est renvoyée.


2
# Cela fonctionne correctement sans la gestion bizarre d'octet par octet
def addressInNetwork (ip, net):
    '' 'Est une adresse dans un réseau' ''
    # Convertissez les adresses en ordre d'hôte, les changements ont donc un sens
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bits = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Doit décaler vers la gauche une valeur de tous les uns, / 32 = décalage zéro, / 0 = 32 décalage vers la gauche
    masque de réseau = (0xffffffff << (32-int (bits))) & 0xffffffff
    # Il n'est pas nécessaire de masquer l'adresse réseau, tant que c'est une adresse réseau correcte
    return (ip & netmask) == netaddr 

Le code ne fonctionnait pas correctement sur le système d'exploitation 64 bits en raison de netmaskvaleurs incorrectes . J'ai pris la liberté de résoudre ce problème.
drdaeman

2

la solution précédente a un bogue dans ip & net == net. La recherche d'IP correcte est ip & netmask = net

code corrigé:

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 réponse choisie a un bug.

Voici le code correct:

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

Remarque: ipaddr & netmask == netaddr & netmaskau lieu de ipaddr & netmask == netmask.

Je remplace également ((2L<<int(bits)-1) - 1)par ((1L << int(bits)) - 1), car ce dernier semble plus compréhensible.


Je pense que la conversion du masque ((2L<<int(bits)-1) - 1)est correcte. par exemple, si le masque est 16, il devrait être "255.255.0.0" ou 65535L, mais ((1L << int(bits)) - 1)obtiendra 32767L, ce qui n'est pas correct.
Chris.Q

@ Chris.Q, ((1L << int(bits)) - 1)donne 65535L sur mon système, avec une valeur bitsde 16 !!
Debanshu Kundu

En outre, pour bitsdéfinir sur 0, ((2L<<int(bits)-1) - 1)génère une erreur.
Debanshu Kundu

Oui, aucune valeur autre que / 0, / 8, / 16, / 32 ne fonctionne correctement.
Debanshu Kundu

2

Voici une classe que j'ai écrite pour la correspondance de préfixe la plus longue:

#!/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

Et voici un programme de test:

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

Merci pour votre script!
J'ai beaucoup de travail dessus pour que tout fonctionne ... Donc je le partage ici

  • L'utilisation de la classe netaddr est 10 fois plus lente que celle de la conversion binaire, donc si vous souhaitez l'utiliser sur une grande liste d'adresses IP, vous devriez envisager de ne pas utiliser la classe netaddr
  • La fonction makeMask ne fonctionne pas! Fonctionne uniquement pour / 8, / 16, / 24
    Ex:

    bits = "21"; socket.inet_ntoa (struct.pack ('= L', (2L << int (bits) -1) - 1))
    '255.255.31.0' alors qu'il devrait être 255.255.248.0

    J'ai donc utilisé une autre fonction calcDottedNetmask (mask) de http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
    Ex:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Un autre problème est le processus de correspondance si une adresse IP appartient à un réseau! L'opération de base devrait être de comparer (ipaddr & netmask) et (network & netmask).
    Ex: pour le moment, la fonction est fausse

#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
>>>True which is completely WRONG!!

Donc, ma nouvelle fonction addressInNetwork ressemble à:


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

Et maintenant, la réponse est juste !!


#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
False

J'espère que cela aidera d'autres personnes, leur faisant gagner du temps!


1
la version actuelle du code ci-dessus donne un traceback dans la dernière ligne, que vous pouvez "| =" un int et un tuple.
Sean Reifschneider

1

En ce qui concerne tout ce qui précède, je pense que socket.inet_aton () renvoie les octets dans l'ordre du réseau, donc la bonne façon de les décompresser est probablement

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
Faux
Vrai
Faux


Pouvez-vous expliquer ce que vous ajoutez aux réponses déjà données?
David Guyon

Les réponses données ont un problème, qui ne pouvait pas gérer CIDR. Je viens de changer l'ordre des octets de l'adresse IP. Juste comme ça:>>> 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
Merci d'avoir répondu. Je suppose que c'est quelque chose que vous devriez ajouter à votre réponse pour clarifier. C'est dans l'esprit de StackOverflow d'expliquer le «quoi» «pourquoi» et enfin «comment». Votre réponse ne contient que le "comment": (. Je vous laisse compléter votre réponse en la modifiant;).
David Guyon


0

À partir de diverses sources ci-dessus et de mes propres recherches, c'est ainsi que j'ai fait fonctionner le calcul de sous-réseau et d'adresse. Ces pièces suffisent à résoudre la question et d'autres questions connexes.

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

Il existe une API appelée SubnetTree disponible en python qui fait très bien ce travail. Voici un exemple simple:

import SubnetTree
t = SubnetTree.SubnetTree()
t.insert("10.0.1.3/32")
print("10.0.1.3" in t)

Voici le lien


0

Voici mon code

# -*- 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 vous ne souhaitez pas importer d'autres modules, vous pouvez utiliser:

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

J'ai essayé un sous-ensemble de solutions proposées dans ces réponses .. sans succès, j'ai finalement adapté et corrigé le code proposé et écrit ma fonction fixe.

Je l'ai testé et fonctionne au moins sur des architectures little endian - egx86 - si quelqu'un aime essayer une architecture big endian, merci de me faire part de vos commentaires.

IP2Intle code vient de cet article , l'autre méthode est un correctif de travail complet (pour mes cas de test) des propositions précédentes dans cette question.

Le code:

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

J'espère utile,


0

Voici la solution utilisant le package 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)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.