Wie kann ich überprüfen, ob sich eine IP in einem Netzwerk in Python befindet?


100

Wie überprüfe ich bei einer gegebenen IP-Adresse (z. B. 192.168.0.1), ob sie sich in einem Netzwerk (z. B. 192.168.0.0/24) in Python befindet?

Gibt es in Python allgemeine Tools zur Manipulation von IP-Adressen? Sachen wie Host-Lookups, IP-Adresse zu int, Netzwerkadresse mit Netzmaske zu int und so weiter? Hoffentlich in der Standard-Python-Bibliothek für 2.5.


Diese Frage scheint für sehr alte 2.x-Antworten in Ordnung zu sein, ist jedoch für 3.x veraltet. Siehe Organisieren und Zuweisen von Canonicals für „Python / Pandas vergleichen IP-Adresse / CIDR“.
smci

@smci Ich verstehe nicht warum; Die Antwort von phihag unter stackoverflow.com/a/1004527/1709587 ist eine sehr gute Antwort für Python 3 und ist seit 2014 hier. Ich habe Ihre Bearbeitung zurückgesetzt, die diese Antwort ungültig gemacht hat.
Mark Amery

@Staale - Sie sollten Ihre Antwort hier auf eine aktualisieren, die keinen kritischen Fehler aufweist . Die anderen Antworten verwenden integrierte Bibliotheken, um dasselbe in 1/10 so viel Code ohne Fehler zu erreichen.
Addison

Antworten:


30

Dieser Artikel zeigt, dass Sie dies mit socketund structModulen ohne großen Aufwand tun können . Ich habe dem Artikel wie folgt ein wenig hinzugefügt:

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)

Dies gibt aus:

False
True

Wenn Sie nur eine einzelne Funktion benötigen, die Zeichenfolgen akzeptiert, sieht dies folgendermaßen aus:

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
Darüber hinaus schlägt struct.unpack ('L', socket.inet_aton (ip)) [0] auf Architekturen fehl, bei denen 'L' unabhängig von der Endianness auf etwas anderes als 4 Byte entpackt wird.
Rafał Dowgird

5
Um Rafals Kommentar auf einem 64-Bit-Python-Interpreter zum Laufen zu bringen, ersetzen Sie die fragliche Zeile durch:return struct.unpack('<L',socket.inet_aton(ip))[0]
nitwit

11
Ich denke, Ihre Lösung hat einen schwerwiegenden Fehler: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(Ich habe 'L' in meinem 64-Bit-Betriebssystem in '<L' konvertiert)
Taha Jahangir

20
VORSICHT: Diese Lösung hat einen schwerwiegenden Fehler:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir

6
Diese Antwort hat einen Fehler . Siehe Antwort: stackoverflow.com/questions/819355/…
Debanshu Kundu

156

Ich benutze dafür gerne netaddr :

from netaddr import CIDR, IP

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

Wie arno_v in den Kommentaren hervorhob, macht die neue Version von netaddr das so:

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
Oder in der neuen Version: aus netaddr IPNetwork importieren, IPAddress IPAddress ("192.168.0.1") in IPNetwork ("192.168.0.0/24")
arno_v

140

Verwenden der IP-Adresse ( in der stdlib seit 3.3 , bei PyPi für 2.6 / 2.7 ):

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

Wenn Sie viele IP-Adressen auf diese Weise auswerten möchten, möchten Sie wahrscheinlich die Netzmaske im Voraus berechnen, z

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

Berechnen Sie dann für jede Adresse die binäre Darstellung mit einer von

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

Schließlich können Sie einfach überprüfen:

in_network = (a & mask) == netw

2
Achtung, Python-ipaddr hat sich für uns ziemlich langsam verhalten, daher ist es möglicherweise in einigen Fällen ungeeignet, in denen häufig viele Vergleiche erforderlich sind. YMMV, also messen Sie sich selbst.
Drdaeman

In einigen Versionen müssen Sie möglicherweise eine Unicode-Zeichenfolge anstelle eines Python-Str-Typs angeben, z ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
Ich war besorgt, dass diese Methode die Liste der Adressen im Netzwerk durchläuft, aber das IP-Adressmodul überschreibt die __contains__Methode, um dies auf effiziente Weise zu tun, indem es die ganzzahligen Darstellungen des Netzwerks und die Broadcast-Adressen vergleicht. Seien Sie also versichert, wenn dies Ihre Sorge ist .
Avatarofhope2


10

Dieser Code funktioniert für mich unter Linux x86. Ich habe nicht wirklich über Endianess-Probleme nachgedacht, aber ich habe es mit dem "ipaddr" -Modul unter Verwendung von über 200 KB IP-Adressen getestet, die mit 8 verschiedenen Netzwerkzeichenfolgen getestet wurden. Die Ergebnisse von ipaddr stimmen mit denen dieses Codes überein.

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)

Beispiel:

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

Schön und schnell. Für einige einfache Logikoperationen ist keine Bibliothek erforderlich.
Chris Koston

7

Verwenden der Python3- IP-Adresse :

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

Erläuterung

Sie können sich eine IP-Adresse als ein Netzwerk mit der größtmöglichen Netzmaske vorstellen ( /32für IPv4, /128für IPv6).

Das Überprüfen, ob 192.168.0.1in 192.168.0.0/16ist, ist im Wesentlichen dasselbe wie das Überprüfen, ob 192.168.0.1/32es sich um ein Subnetz von handelt192.168.0.0/16


... nicht sicher, warum diese Antwort (noch) nicht ganz oben steht.
Filippo Vitale

6

Ich habe die Lösung von Dave Webb ausprobiert, bin aber auf einige Probleme gestoßen:

Grundsätzlich gilt: Eine Übereinstimmung sollte überprüft werden, indem die IP-Adresse mit der Maske UND-verknüpft wird und anschließend überprüft wird, ob das Ergebnis genau mit der Netzwerkadresse übereinstimmt. Die IP-Adresse wird nicht wie zuvor mit der Netzwerkadresse UND-verknüpft.

Mir ist auch aufgefallen, dass das Ignorieren des Endian-Verhaltens unter der Annahme, dass Konsistenz Sie spart, nur für Masken an Oktettgrenzen (/ 24, / 16) funktioniert. Damit andere Masken (/ 23, / 21) korrekt funktionieren, habe ich den struct-Befehlen ein "Größer als" hinzugefügt und den Code zum Erstellen der Binärmaske so geändert, dass er mit allen "1" beginnt und um (32-Maske) nach links verschoben wird ).

Schließlich habe ich eine einfache Überprüfung hinzugefügt, ob die Netzwerkadresse für die Maske gültig ist, und nur eine Warnung gedruckt, wenn dies nicht der Fall ist.

Hier ist das Ergebnis:

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

Dies scheint bei 64-Bit zuverlässig zu funktionieren ('L' schlägt fehl, da der Wert 32-Bit ist) und gibt die Werte in einer sinnvollen Reihenfolge zurück (ipaddr ist 0xC0A80001 für 192.168.0.1). Es kommt auch mit "192.168.0.1/24" als Netzmaske für "192.168.0.1" (nicht Standard, aber möglich und leicht zu korrigieren)
IBBoard

Funktioniert perfekt auf Python 2.4
xlash

6

Ich bin kein Fan von Modulen, wenn sie nicht benötigt werden. Dieser Job erfordert nur einfache Mathematik. Hier ist meine einfache Funktion, um den Job zu erledigen:

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

Dann, um es zu benutzen:

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

Das war's, das ist viel schneller als die oben genannten Lösungen mit den enthaltenen Modulen.


{TypeError}'map' object is not subscriptable. Sie benötigen einen o = list(o)nacho = map(int, ip.split('.'))
gies0r

5

Nicht in der Standardbibliothek für 2.5, aber ipaddr macht dies sehr einfach. Ich glaube es ist in 3.3 unter dem Namen 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)

Dies ist bei weitem mein Favorit unter all den unzähligen Möglichkeiten hier (zum Zeitpunkt des Kommentars, 2017). Vielen Dank!
rsaw

5

Die akzeptierte Antwort funktioniert nicht ... was mich wütend macht. Die Maske ist rückwärts und funktioniert nicht mit Bits, die kein einfacher 8-Bit-Block sind (z. B. / 24). Ich habe die Antwort angepasst und es funktioniert gut.

    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

Hier ist eine Funktion, die eine gepunktete Binärzeichenfolge zurückgibt, um die Maskierung zu veranschaulichen ipcalc.

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

z.B:

Screenshot von Python


4

Marc's Code ist fast korrekt. Eine vollständige Version des Codes ist -

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

Offensichtlich aus den gleichen Quellen wie oben ...

Ein sehr wichtiger Hinweis ist, dass der erste Code einen kleinen Fehler aufweist. Die IP-Adresse 255.255.255.255 wird auch als gültige IP für jedes Subnetz angezeigt. Ich hatte verdammt viel Zeit, um diesen Code zum Laufen zu bringen, und danke Marc für die richtige Antwort.


Ausprobiert und getestet. Von allen Socket / Struct-Beispielen auf dieser Seite ist dies das einzig richtige
Zabuzzman

4

Das Verlassen auf das "struct" -Modul kann Probleme mit der Endianität und den Typgrößen verursachen und wird einfach nicht benötigt. Socket.inet_aton () ist auch nicht. Python funktioniert sehr gut mit gepunkteten Quad-IP-Adressen:

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

Ich muss bei jedem Aufruf des Sockets accept () einen IP-Abgleich für eine ganze Reihe zulässiger Quellnetzwerke durchführen, daher berechne ich Masken und Netzwerke als Ganzzahlen vor:

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

Dann kann ich schnell sehen, ob sich eine bestimmte IP in einem dieser Netzwerke befindet:

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

Es sind keine Modulimporte erforderlich, und der Code ist beim Abgleichen sehr schnell.


Worauf bezieht sich diese cached_masks?
Ajin

2

aus netaddr importiere 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')]

Hier ist die Verwendung für diese Methode:

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

Grundsätzlich geben Sie als erstes Argument eine IP-Adresse und als zweites Argument eine Liste von cidrs an. Eine Liste der Treffer wird zurückgegeben.


2
#Dies funktioniert ordnungsgemäß ohne die seltsame Behandlung von Byte für Byte
def addressInNetwork (ip, net):
    '' 'Ist eine Adresse in einem Netzwerk' ''
    # Konvertieren Sie Adressen in Host-Reihenfolge, sodass Verschiebungen tatsächlich Sinn machen
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bits = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Muss um einen Einsenwert nach links verschoben werden, / 32 = Nullverschiebung, / 0 = 32 nach links verschieben
    Netzmaske = (0xffffffff << (32-int (Bits))) & 0xffffffff
    # Die Netzwerkadresse muss nicht maskiert werden, solange es sich um eine ordnungsgemäße Netzwerkadresse handelt
    return (ip & netmask) == netaddr 

Der Code funktionierte unter 64-Bit-Betriebssystemen aufgrund falscher netmaskWerte nicht richtig . Ich habe mir erlaubt, das zu beheben.
Drdaeman

2

vorherige Lösung haben einen Fehler in ip & net == net. Die korrekte IP-Suche lautet ip & netmask = net

Bugfixed Code:

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

Die gewählte Antwort hat einen Fehler.

Es folgt der richtige Code:

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

Hinweis: ipaddr & netmask == netaddr & netmaskanstelle von ipaddr & netmask == netmask.

Ich ersetze auch ((2L<<int(bits)-1) - 1)mit ((1L << int(bits)) - 1), da diese besser verständlich zu sein scheint.


Ich denke, die Maskenkonvertierung ((2L<<int(bits)-1) - 1)ist korrekt. Wenn die Maske beispielsweise 16 ist, sollte sie "255.255.0.0" oder 65535L sein, ((1L << int(bits)) - 1)erhält aber 32767L, was nicht richtig ist.
Chris.Q

@ Chris.Q, ((1L << int(bits)) - 1)gibt 65535L auf meinem System, mit bitsauf 16 gesetzt !!
Debanshu Kundu

Auch für bitsSatz zu 0, ((2L<<int(bits)-1) - 1)hebt Fehler.
Debanshu Kundu

Ja, tatsächlich funktioniert kein anderer Wert als / 0, / 8, / 16, / 32 ordnungsgemäß.
Debanshu Kundu

2

Hier ist eine Klasse, die ich für die längste Präfixübereinstimmung geschrieben habe:

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

Und hier ist ein Testprogramm:

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

Vielen Dank für Ihr Skript!
Ich habe ziemlich lange daran gearbeitet, damit alles funktioniert ... Also teile ich es hier

  • Die Verwendung der netaddr-Klasse ist zehnmal langsamer als die Verwendung der binären Konvertierung. Wenn Sie sie also für eine große IP-Liste verwenden möchten, sollten Sie in Betracht ziehen, die netaddr-Klasse nicht zu verwenden
  • Die Funktion makeMask funktioniert nicht! Arbeitet nur für / 8, / 16, / 24 Beispiel
    :

    Bits = "21"; socket.inet_ntoa (struct.pack ('= L', (2L << int (Bits) -1) - 1))
    '255.255.31.0', während es 255.255.248.0 sein sollte

    Also habe ich eine andere Funktion calcDottedNetmask (Maske) von http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/ verwendet. Beispiel
    :


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Ein weiteres Problem ist der Prozess des Abgleichs, wenn eine IP zu einem Netzwerk gehört! Die Grundbedienung sollte darin bestehen, (ipaddr & netmask) und (network & netmask) zu vergleichen.
    Bsp.: Derzeit ist die Funktion falsch

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

Meine neue addressInNetwork-Funktion sieht also folgendermaßen aus:


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

Und jetzt ist die Antwort richtig !!


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

Ich hoffe, dass es anderen Menschen hilft und ihnen Zeit spart!


1
Die aktuelle Version des obigen Codes gibt in der letzten Zeile einen Traceback, mit dem Sie ein int und ein Tupel "| =" können.
Sean Reifschneider

1

In Bezug auf all das oben Genannte denke ich, dass socket.inet_aton () Bytes in der Netzwerkreihenfolge zurückgibt, daher ist der richtige Weg, sie zu entpacken, wahrscheinlich

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


Können Sie erklären, was Sie zu den bereits gegebenen Antworten hinzufügen?
David Guyon

Die gegebenen Antworten haben ein Problem, das mit CIDR nicht umgehen konnte. Ich habe gerade die Bytereihenfolge der IP-Adresse geändert. Einfach so:>>> 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
Danke für die Antwort. Ich denke, es ist etwas, das Sie Ihrer Antwort hinzufügen sollten, um es zu klären. Es liegt im Sinne von StackOverflow, das "Was", "Warum" und schließlich "Wie" zu erklären. Ihre Antwort enthält nur das "Wie" :(. Ich lasse Sie Ihre Antwort vervollständigen, indem Sie sie bearbeiten;).
David Guyon


0

Aus verschiedenen Quellen oben und aus meiner eigenen Forschung habe ich auf diese Weise die Subnetz- und Adressberechnung zum Laufen gebracht. Diese Stücke reichen aus, um die Frage und andere verwandte Fragen zu lösen.

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

In Python gibt es eine API namens SubnetTree, die diese Aufgabe sehr gut erfüllt. Dies ist ein einfaches Beispiel:

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

Das ist die Verbindung


0

Hier ist mein 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

Wenn Sie keine anderen Module importieren möchten, können Sie Folgendes tun:

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

Ich habe eine Teilmenge der vorgeschlagenen Lösungen in diesen Antworten ausprobiert. Ohne Erfolg habe ich schließlich den vorgeschlagenen Code angepasst und korrigiert und meine feste Funktion geschrieben.

Ich habe es getestet und arbeite zumindest mit Little-Endian-Architekturen - egx86 -. Wenn jemand eine Big-Endian-Architektur ausprobieren möchte, gib mir bitte Feedback.

IP2IntCode kommt aus diesem Beitrag , die andere Methode ist eine vollständig (für meine Testfälle) funktionierende Korrektur früherer Vorschläge in dieser Frage.

Der 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

Hoffe nützlich,


0

Hier ist die Lösung mit dem netaddr-Paket

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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.