Come posso verificare se un IP è in una rete in Python?


100

Dato un indirizzo IP (ad esempio 192.168.0.1), come posso verificare se è in una rete (ad esempio 192.168.0.0/24) in Python?

Esistono strumenti generali in Python per la manipolazione dell'indirizzo IP? Cose come ricerche host, indirizzo IP a int, indirizzo di rete con maschera di rete a int e così via? Si spera nella libreria Python standard per 2.5.


Questa domanda sembra una canonica accettabile per le risposte 2.x molto vecchie, ma è obsoleta per 3.x Vedi Come organizzare e assegnare canoniche per "Python / panda confronta indirizzo IP / CIDR"?
smci

@smci non vedo perché; La risposta di phihag a stackoverflow.com/a/1004527/1709587 è una perfetta buona risposta per Python 3 ed è stato qui dal 2014. Ho rollback la modifica che invalidata quella risposta.
Mark Amery

@Staale - Dovresti aggiornare la tua risposta qui a una che non ha un bug critico . Le altre risposte usano le librerie incorporate per ottenere la stessa cosa in 1/10 del codice, senza bug.
Addison

Risposte:


30

Questo articolo mostra che puoi farlo con i moduli sockete structsenza troppi sforzi extra. Ho aggiunto un po 'all'articolo come segue:

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)

Questo produce:

False
True

Se vuoi solo una singola funzione che accetta le stringhe sarebbe simile a questa:

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
Inoltre, struct.unpack ('L', socket.inet_aton (ip)) [0] fallirà su architetture in cui 'L' decomprime in qualcosa di diverso da 4 byte, indipendentemente dall'endianness.
Rafał Dowgird

5
Continuando sul commento di Rafal, per farlo funzionare su un interprete Python a 64 bit, sostituire la riga in questione con:return struct.unpack('<L',socket.inet_aton(ip))[0]
nitwit

11
Penso che la tua soluzione abbia un bug serio: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(ho convertito 'L' in '<L' nel mio sistema operativo a 64 bit)
Taha Jahangir

20
ATTENZIONE: questa soluzione presenta un bug grave:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir

6
Questa risposta ha un bug . Si veda la risposta: stackoverflow.com/questions/819355/...
Debanshu Kundu

156

Mi piace usare netaddr per questo:

from netaddr import CIDR, IP

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

Come ha sottolineato arno_v nei commenti, la nuova versione di netaddr funziona in questo modo:

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
Oppure nella nuova versione: da netaddr importa IPNetwork, IPAddress IPAddress ("192.168.0.1") in IPNetwork ("192.168.0.0/24")
arno_v

140

Usando ipaddress ( nello stdlib dalla 3.3 , a PyPi per 2.6 / 2.7 ):

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

Se vuoi valutare molti indirizzi IP in questo modo, probabilmente vorrai calcolare la maschera di rete in anticipo, come

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

Quindi, per ogni indirizzo, calcola la rappresentazione binaria con uno di

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

Infine, puoi semplicemente controllare:

in_network = (a & mask) == netw

2
Attenzione, python-ipaddr si è comportato abbastanza lentamente per noi, quindi potrebbe non essere adatto per alcuni casi in cui sono richiesti molti confronti frequentemente. YMMV, quindi confronta te stesso.
drdaeman

In alcune versioni, potrebbe essere necessario fornire una stringa Unicode invece di un tipo str Python, come ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
Ero preoccupato che questo metodo stesse iterando sull'elenco degli indirizzi nella rete, ma il modulo indirizzoip sovrascrive il __contains__metodo per farlo in modo efficiente confrontando le rappresentazioni intere della rete e degli indirizzi di trasmissione, quindi stai tranquillo se questa era la tua preoccupazione .
avatarofhope2

24

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

Produzione :

False
True

1
La libreria standard utilizza un controllo bit per bit intelligente, quindi questa è la soluzione ottimale qui. github.com/python/cpython/blob/3.8/Lib/ipaddress.py#L690
rocketspacer

10

Questo codice funziona per me su Linux x86. Non ho davvero pensato a problemi di endianess, ma l'ho testato contro il modulo "ipaddr" usando oltre 200K indirizzi IP testati su 8 diverse stringhe di rete, ei risultati di ipaddr sono gli stessi di questo codice.

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)

Esempio:

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

Bello e veloce. Non c'è bisogno di una libreria per poche semplici operazioni logiche.
Chris Koston

7

Utilizzando l' indirizzo IP di 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}")))

Spiegazione

Puoi pensare a un indirizzo IP come a una rete con la maschera di rete più ampia possibile ( /32per IPv4, /128per IPv6)

Controllare se 192.168.0.1è in 192.168.0.0/16è essenzialmente lo stesso che controllare se 192.168.0.1/32è una sottorete di192.168.0.0/16


... non sono sicuro del motivo per cui questa risposta non è in cima (ancora).
Filippo Vitale

6

Ho provato la soluzione di Dave Webb ma ho riscontrato alcuni problemi:

Fondamentalmente: una corrispondenza dovrebbe essere verificata mediante AND all'indirizzo IP con la maschera, quindi controllando che il risultato corrisponda esattamente all'indirizzo di rete. Non ANDing l'indirizzo IP con l'indirizzo di rete come è stato fatto.

Ho anche notato che ignorando il comportamento di Endian assumendo che la coerenza salverà funzionerai solo per le maschere sui limiti degli ottetti (/ 24, / 16). Per fare in modo che le altre maschere (/ 23, / 21) funzionino correttamente, ho aggiunto un "maggiore di" ai comandi della struttura e ho cambiato il codice per creare la maschera binaria in modo che inizi con tutto "1" e sposta a sinistra di (32-maschera ).

Infine, ho aggiunto un semplice controllo che l'indirizzo di rete sia valido per la maschera e stampa solo un avviso se non lo è.

Ecco il risultato:

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

Questo sembra funzionare in modo affidabile su 64 bit ("L" non riesce poiché il valore è a 32 bit) e restituisce i valori in un ordine ragionevole (ipaddr sarà 0xC0A80001 per 192.168.0.1). Gestisce anche "192.168.0.1/24" come maschera di rete per "192.168.0.1" (non standard, ma possibile e facilmente correggibile)
IBBoard

Funziona perfettamente su Python 2.4
xlash

6

Non sono un fan dell'utilizzo dei moduli quando non sono necessari. Questo lavoro richiede solo matematica semplice, quindi ecco la mia semplice funzione per fare il lavoro:

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

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

Ecco, è molto più veloce delle soluzioni sopra con i moduli inclusi.


{TypeError}'map' object is not subscriptable. Hai bisogno di un o = list(o)dopoo = map(int, ip.split('.'))
gies0r

5

Non nella libreria Standard per 2.5, ma ipaddr lo rende molto semplice. Credo che sia in 3.3 sotto il nome 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)

Questo è di gran lunga il mio preferito tra tutte le miriadi di scelte qui (al momento del commento, 2017). Grazie!
rsaw

5

La risposta accettata non funziona ... il che mi fa arrabbiare. La maschera è al contrario e non funziona con bit che non siano un semplice blocco a 8 bit (ad esempio / 24). Ho adattato la risposta e funziona bene.

    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

ecco una funzione che restituisce una stringa binaria punteggiata per aiutare a visualizzare il mascheramento .. tipo di ipcalcoutput simile .

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

per esempio:

schermata di python


4

Il codice di Marc è quasi corretto. Una versione completa del codice è:

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

Ovviamente dalle stesse fonti di cui sopra ...

Una nota molto importante è che il primo codice ha un piccolo problema tecnico: l'indirizzo IP 255.255.255.255 viene visualizzato anche come IP valido per qualsiasi sottorete. Ho avuto un sacco di tempo per far funzionare questo codice e grazie a Marc per la risposta corretta.


Provato e testato. Da tutti gli esempi di socket / struct in questa pagina questo è l'unico corretto
Zabuzzman

4

Affidarsi al modulo "struct" può causare problemi con endianness e dimensioni dei tipi, e semplicemente non è necessario. Nemmeno socket.inet_aton (). Python funziona molto bene con indirizzi IP a quattro punte:

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

Devo eseguire la corrispondenza IP su ciascuna chiamata accept () socket, su un intero set di reti sorgente consentite, quindi precomputo maschere e reti, come numeri interi:

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

Quindi posso vedere rapidamente se un dato IP si trova all'interno di una di quelle reti:

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

Non sono necessarie importazioni di moduli e il codice è molto veloce nella corrispondenza.


A cosa si riferisce questo cached_masks ??
ajin

2

da netaddr importa 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')]

Ecco l'utilizzo di questo metodo:

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

Fondamentalmente fornisci un indirizzo IP come primo argomento e un elenco di cidr come secondo argomento. Viene restituito un elenco di risultati.


2
#Questo funziona correttamente senza lo strano byte per la gestione dei byte
def addressInNetwork (ip, net):
    '' 'È un indirizzo in una rete' ''
    # Converti gli indirizzi nell'ordine host, quindi i cambiamenti hanno davvero senso
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bits = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Deve spostare a sinistra un valore di tutti gli uno, / 32 = spostamento zero, / 0 = 32 spostamento a sinistra
    netmask = (0xffffffff << (32-int (bit))) & 0xffffffff
    # Non è necessario mascherare l'indirizzo di rete, purché sia ​​un indirizzo di rete corretto
    return (ip & netmask) == netaddr 

Il codice non funzionava correttamente su SO a 64 bit, a causa di netmaskvalori errati . Mi sono preso la libertà di rimediare.
drdaeman

2

la soluzione precedente ha un bug in ip & net == net. La corretta ricerca dell'ip è ip & netmask = net

codice corretto:

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 risposta scelta ha un bug.

Di seguito è riportato il codice corretto:

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 & netmaskinvece di ipaddr & netmask == netmask.

Sostituisco anche ((2L<<int(bits)-1) - 1)con ((1L << int(bits)) - 1), poiché quest'ultimo sembra più comprensibile.


Penso che la conversione della maschera ((2L<<int(bits)-1) - 1)sia corretta. ad esempio, se la maschera è 16, dovrebbe essere "255.255.0.0" o 65535L, ma ((1L << int(bits)) - 1)otterrà 32767L, che non è corretto.
Chris.Q

@ Chris.Q, ((1L << int(bits)) - 1)dà 65535L sul mio sistema, con bitsimpostato su 16 !!
Debanshu Kundu

Inoltre, per bitsimpostato su 0, ((2L<<int(bits)-1) - 1)viene generato un errore.
Debanshu Kundu

Sì, in realtà nessun valore diverso da / 0, / 8, / 16, / 32 funziona correttamente.
Debanshu Kundu

2

Ecco una classe che ho scritto per la corrispondenza del prefisso più lunga:

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

Ed ecco un programma di 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

Grazie per il tuo copione!
Ci ho lavorato parecchio per far funzionare tutto ... Quindi lo condivido qui

  • L'uso della classe netaddr è 10 volte più lento rispetto alla conversione binaria, quindi se desideri utilizzarlo su un grande elenco di IP, dovresti considerare di non utilizzare la classe netaddr
  • La funzione makeMask non funziona! Funziona solo per / 8, / 16, / 24
    Ex:

    bit = "21"; socket.inet_ntoa (struct.pack ('= L', (2L << int (bits) -1) - 1))
    '255.255.31.0' mentre dovrebbe essere 255.255.248.0

    Quindi ho usato un'altra funzione calcDottedNetmask (maschera) da http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
    Es:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Un altro problema è il processo di corrispondenza se un IP appartiene a una rete! L'operazione di base dovrebbe essere quella di confrontare (ipaddr e netmask) e (rete e netmask).
    Es: per il momento la funzione è sbagliata

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

Quindi la mia nuova funzione addressInNetwork assomiglia 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))

E ora, la risposta è giusta !!


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

Spero che possa aiutare altre persone, facendo risparmiare loro tempo!


1
la versione corrente del codice precedente fornisce un traceback nell'ultima riga, che puoi "| =" un int e una tupla.
Sean Reifschneider

1

Relativamente a tutto quanto sopra, penso che socket.inet_aton () restituisca i byte in ordine di rete, quindi il modo corretto per decomprimerli è probabilmente

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
False
True
False


Puoi spiegare cosa stai aggiungendo alle risposte già fornite?
David Guyon

Le risposte fornite hanno qualche problema, che non poteva gestire CIDR. Ho appena cambiato l'ordine dei byte dell'indirizzo IP. Proprio così:>>> 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
Grazie per la risposta. Immagino sia qualcosa che dovresti aggiungere alla tua risposta per chiarire. È nello spirito di StackOverflow spiegare "cosa", "perché" e infine "come". La tua risposta contiene solo il "come" :(. Ti lascio completare la tua risposta modificandola;).
David Guyon


0

Da varie fonti sopra e dalla mia ricerca, è così che ho funzionato il calcolo della sottorete e dell'indirizzo. Questi pezzi sono sufficienti per risolvere la domanda e altre domande correlate.

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

C'è un'API chiamata SubnetTree disponibile in Python che fa questo lavoro molto bene. Questo è un semplice esempio:

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

Questo è il collegamento


0

Ecco il mio codice

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

Se non vuoi importare altri moduli potresti andare 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]

0

Ho provato un sottoinsieme di soluzioni proposte in queste risposte .. senza successo, ho finalmente adattato e corretto il codice proposto e ho scritto la mia funzione fissa.

L'ho testato e funziona almeno su architetture little endian - egx86 - se a qualcuno piace provare un'architettura big endian, per favore mi dia un feedback.

IP2Intil codice proviene da questo post , l'altro metodo è una correzione completamente (per i miei casi di test) funzionante delle proposte precedenti in questa domanda.

Il codice:

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

Spero utile,


0

Ecco la soluzione utilizzando il pacchetto 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.