Python'da bir ipin ağda olup olmadığını nasıl kontrol edebilirim?


100

Bir ip adresi verildiğinde (örneğin 192.168.0.1), Python'da bir ağda (örneğin 192.168.0.0/24) olup olmadığını nasıl kontrol edebilirim?

Python'da ip adresi manipülasyonu için genel araçlar var mı? Ana bilgisayar aramaları, int için ip adresi, int ağ maskesiyle ağ adresi vb. Gibi şeyler? Umarım 2.5 için standart Python kitaplığında.


Bu soru, çok eski 2.x yanıtları için uygun bir standart gibi görünüyor, ancak 3.x için kullanılmıyor Bkz . "Python / pandalar IP adresini / CIDR karşılaştırması"
smci

@smci Neden göremiyorum; phihag'ın stackoverflow.com/a/1004527/1709587 adresindeki cevabı Python 3 için mükemmel bir cevaptır ve 2014'ten beri buradadır. Bu cevabı geçersiz kılan düzenlemenizi geri aldım.
Mark Amery

@Staale - Cevabınızı burada kritik bir hata içermeyen bir şekilde güncellemelisiniz . Diğer yanıtlar, aynı şeyi 1/10 kadar kodda, herhangi bir hata olmadan gerçekleştirmek için yerleşik kitaplıkları kullanır.
Addison

Yanıtlar:


30

Bu makale , bunu socketve structmodülleri ile çok fazla çaba harcamadan yapabileceğinizi gösterir . Makaleye şu şekilde biraz ekledim:

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)

Bu çıktılar:

False
True

Dizeleri alan tek bir işlev istiyorsanız, aşağıdaki gibi görünür:

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
Ek olarak, struct.unpack ('L', socket.inet_aton (ip)) [0], sonsuzluktan bağımsız olarak, 'L'nin 4 bayttan farklı bir şeye paketlendiği mimarilerde başarısız olacaktır.
Rafał Dowgird

5
Rafal'ın yorumuna devam edersek, bunun 64-bit Python yorumlayıcısında çalışmasını sağlamak için söz konusu satırı şununla değiştirin:return struct.unpack('<L',socket.inet_aton(ip))[0]
nitwit

11
Çözümünüzün ciddi bir hatası olduğunu düşünüyorum: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(64bit işletim
sistemimde

20
DİKKAT: Bu çözümün ciddi bir hatası var:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir

6
Bu cevapta bir hata var . Cevabı görün: stackoverflow.com/questions/819355/…
Debanshu Kundu

156

Bunun için netaddr kullanmayı seviyorum :

from netaddr import CIDR, IP

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

Arno_v'nin yorumlarda belirttiği gibi, netaddr'in yeni sürümü şöyle:

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
Veya yeni sürümde: netaddr'den IPNetwork'ü içe aktarın, IPAddress IPAddress ("192.168.0.1") IPNetwork'te ("192.168.0.0/24")
arno_v

140

Kullanma ipaddress ( 3.3 yana stdlib içinde , 2.6 / 2.7 PyPi de ):

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

Bu şekilde çok sayıda IP adresini değerlendirmek istiyorsanız , muhtemelen ağ maskesini önceden hesaplamak isteyeceksiniz.

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

Ardından, her adres için ikili gösterimi aşağıdakilerden biri ile hesaplayın:

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

Son olarak, şunları kontrol edebilirsiniz:

in_network = (a & mask) == netw

2
Dikkat edin, python-ipaddr bizim için oldukça yavaş davrandı, bu nedenle sık sık karşılaştırmanın gerekli olduğu bazı durumlar için uygun olmayabilir . YMMV, bu yüzden kendinizi kıyaslayın.
drdaeman

Bazı sürümlerde, Python str türü yerine bir unicode dizesi sağlamanız gerekebilir, örneğin ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
Bu yöntemin ağdaki adres listesi üzerinde yinelediğinden endişeliydim, ancak ipaddress modülü __contains__, ağın ve yayın adreslerinin tam sayı gösterimlerini karşılaştırarak bunu verimli bir şekilde yapmak için yöntemi geçersiz kılar , bu yüzden endişeniz buysa emin olabilirsiniz .
avatarofhope2


10

Bu kod benim için Linux x86 üzerinde çalışıyor. Sonsuz sorunları gerçekten düşünmedim, ancak 8 farklı ağ dizgisine karşı test edilen 200.000'den fazla IP adresi kullanarak "ipaddr" modülüne karşı test ettim ve ipaddr sonuçları bu kodla aynı.

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)

Misal:

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

Güzel ve hızlı. Birkaç basit mantık işlemi için kitaplığa gerek yok.
Chris Koston

7

Python3 ipadresini kullanma :

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

Açıklama

Bir IP Adresini olası en büyük ağ maskesine sahip bir olarak düşünebilirsiniz ( /32IPv4 /128için, IPv6 için)

İçinde olup olmadığını kontrol etmek 192.168.0.1, 192.168.0.0/16esasen 192.168.0.1/32bir alt ağ olup olmadığını kontrol etmekle192.168.0.0/16


... bu cevabın neden en üstte olmadığından emin değilim (henüz).
Filippo Vitale

6

Dave Webb'in çözümünü denedim ama bazı problemleri çözdüm:

En temelde - bir eşleşme, IP adresini maskeyle VE yazarak, ardından sonucun Ağ adresiyle tam olarak eşleştiğini kontrol ederek kontrol edilmelidir. Yapıldığı gibi IP adresini Ağ adresiyle AND yapmamak.

Ayrıca tutarlılığın sizi kurtaracağını varsayarak Endian davranışını görmezden gelmenin yalnızca sekizli sınırlardaki maskeler için çalışacağını fark ettim (/ 24, / 16). Diğer maskelerin (/ 23, / 21) düzgün çalışmasını sağlamak için struct komutlarına bir "daha büyük" ekledim ve ikili maskeyi oluşturma kodunu tüm "1" ile başlayacak ve (32-mask ).

Son olarak, ağ adresinin maske için geçerli olduğuna dair basit bir kontrol ekledim ve değilse sadece bir uyarı yazdırdım.

İşte sonuç:

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

Bu, 64 bit üzerinde güvenilir bir şekilde çalışıyor gibi görünüyor (değer 32 bit olduğundan 'L' başarısız olur) ve değerleri mantıklı bir sırayla döndürür (ipaddr, 192.168.0.1 için 0xC0A80001 olacaktır). Ayrıca "192.168.0.1" için bir ağ maskesi olarak "192.168.0.1/24" ile de başa çıkmaktadır (standart değil, ancak mümkün ve kolayca düzeltilebilir)
IBBoard

Python 2.4'te mükemmel çalışıyor
xlash

6

Gerekli olmadıklarında modülleri kullanma hayranı değilim. Bu iş yalnızca basit matematik gerektirir, bu yüzden işte benim basit işlevim:

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

Sonra kullanmak için:

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

İşte bu, bu, dahil edilen modüllerle yukarıdaki çözümlerden çok daha hızlı.


{TypeError}'map' object is not subscriptable. Bir o = list(o)sonrasına ihtiyacın varo = map(int, ip.split('.'))
gies0r

5

2.5 için Standart kitaplıkta değil, ancak ipaddr bunu çok kolaylaştırıyor. 3.3'te ipaddress adı altında olduğuna inanıyorum.

import ipaddr

a = ipaddr.IPAddress('192.168.0.1')
n = ipaddr.IPNetwork('192.168.0.0/24')

#This will return True
n.Contains(a)

Bu, buradaki sayısız seçenek arasından en sevdiğim şey (yorum sırasında, 2017). Teşekkürler!
rsaw

5

Kabul edilen cevap işe yaramıyor ... bu da beni kızdırıyor. Maske geriye doğrudur ve basit bir 8 bitlik blok (örneğin / 24) olmayan bitlerle çalışmaz. Cevabı uyarladım ve güzel çalışıyor.

    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

Burada, maskelemeyi görselleştirmeye yardımcı olmak için noktalı bir ikili dize döndüren bir işlev .. benzer bir ipcalcçıktı.

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

Örneğin:

python ekran görüntüsü


4

Marc'ın kodu neredeyse doğru. Kodun tam sürümü -

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

Açıkçası yukarıdaki ile aynı kaynaklardan ...

Çok önemli bir not, ilk kodda küçük bir aksaklık olmasıdır - 255.255.255.255 IP adresi de herhangi bir alt ağ için Geçerli IP olarak görünür. Bu kodu çalıştırmak için çok zamanım oldu ve doğru cevap için Marc'a teşekkürler.


Denendi ve test edildi. Bu sayfadaki tüm soket / yapı örneklerinden bu tek doğru olanıdır
Zabuzzman

4

"Struct" modülüne güvenmek, bitim ve tür boyutlarında sorunlara neden olabilir ve buna gerek yoktur. Socket.inet_aton () da değildir. Python, noktalı dörtlü IP adresleriyle çok iyi çalışır:

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

Kabul edilebilir kaynak ağlarının tamamına karşı her soket için IP eşleştirme yapmam gerekiyor, böylece maskeleri ve ağları tamsayı olarak önceden hesaplıyorum:

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

Ardından, belirli bir IP'nin bu ağlardan biri içinde olup olmadığını hızlıca görebilirim:

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

Modül aktarımına gerek yoktur ve kod eşleştirmede çok hızlıdır.


Bu cached_masks neye atıfta bulunuyor?
ajin

2

netaddr'den all_matching_cidrs'i içe aktar

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

İşte bu yöntemin kullanımı:

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

Temel olarak ilk argüman olarak bir ip adresi ve ikinci argüman olarak bir cidrs listesi sağlarsınız. Bir isabet listesi döndürülür.


2
# Bu, garip bayt bayt işleme olmadan düzgün çalışır
def addressInNetwork (ip, net):
    '' 'Ağdaki bir adres' ''
    # Adresleri ana bilgisayar siparişine dönüştürün, böylece vardiyalar gerçekten mantıklıdır
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bit = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Hepsi birler değerini sola kaydırmalı, / 32 = sıfır kaydırma, / 0 = 32 sola kaydırma
    netmask = (0xffffffff << (32-int (bit))) & 0xffffffff
    # Uygun bir ağ adresi olduğu sürece ağ adresini maskelemeye gerek yoktur
    return (ip & netmask) == netaddr 

Hatalı netmaskdeğerler nedeniyle kod 64 bit işletim sisteminde düzgün çalışmadı . Bunu düzeltmek için özgürdüm.
drdaeman

2

önceki çözümde ip & net == net'te bir hata var. Doğru ip araması ip & netmask = net şeklindedir

düzeltilmiş kod:

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

Seçilen cevapta bir hata var.

Doğru kod aşağıdadır:

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

Not: ipaddr & netmask == netaddr & netmaskyerine ipaddr & netmask == netmask.

Ben de değiştirmek ((2L<<int(bits)-1) - 1)ile ((1L << int(bits)) - 1)ikincisi daha anlaşılır göründüğü gibi.


Maske dönüşümünün ((2L<<int(bits)-1) - 1)doğru olduğunu düşünüyorum . örneğin, maske 16 ise "255.255.0.0" veya 65535L olmalıdır, ancak ((1L << int(bits)) - 1)32767L alacaktır, bu doğru değildir.
Chris.Q

@ Chris.Q, ((1L << int(bits)) - 1)sistemimde 65535L veriyor, 16'ya bitsayarlı !!
Debanshu Kundu

Ayrıca, için bitssete 0, ((2L<<int(bits)-1) - 1)hatayı yükseltiyor.
Debanshu Kundu

Evet, aslında / 0, / 8, / 16, / 32 dışında hiçbir değer düzgün çalışmıyor.
Debanshu Kundu

2

İşte en uzun önek eşleşmesi için yazdığım bir sınıf:

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

Ve işte bir test programı:

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

Senaryonuz için teşekkürler!
Her şeyin çalışmasını sağlamak için üzerinde epeyce çalışıyorum ... O yüzden burada paylaşıyorum

  • Netaddr Sınıfını kullanmak, ikili dönüştürmeyi kullanmaktan 10 kat daha yavaştır, bu nedenle onu büyük bir IP listesinde kullanmak istiyorsanız, netaddr sınıfını kullanmamayı düşünmelisiniz.
  • makeMask işlevi çalışmıyor! Yalnızca / 8, / 16, / 24
    Örn. İçin çalışıyor:

    bit = "21"; socket.inet_ntoa (struct.pack ('= L', (2L << int (bit) -1) - 1))
    '255.255.31.0' halbuki 255.255.248.0 olmalıdır

    Bu yüzden, http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/ Örnekten başka bir calcDottedNetmask (mask) işlevi kullandım
    :


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Diğer bir sorun, bir IP ağa aitse eşleştirme işlemidir! Temel İşlem (ipaddr & netmask) ve (network & netmask) ile karşılaştırılmalıdır.
    Ör: şimdilik işlev yanlış

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

Yeni adresimInNetwork işlevi şuna benzer:


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

Ve şimdi, cevap doğru!


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

Umarım diğer insanlara yardımcı olur ve onlara zaman kazandırır!


1
Yukarıdaki kodun geçerli sürümü, son satırda bir int ve bir tuple "| =" yapabileceğiniz bir geri bildirim verir.
Sean Reifschneider

1

Yukarıdakilerin tümü ile ilgili olarak, socket.inet_aton () 'ın baytları ağ sırasına göre döndürdüğünü düşünüyorum, bu nedenle bunları açmanın doğru yolu muhtemelen

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
Yanlış
Doğru
Yanlış


Önceden verilen cevaplara ne kattığınızı açıklayabilir misiniz?
David Guyon

Verilen cevaplarda CIDR ile başa çıkamayan bazı sorunlar var. IP adresinin bayt sırasını değiştirdim. Aynen böyle:>>> 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
Cevap için teşekkürler. Sanırım bu, netleştirmek için cevabınıza eklemeniz gereken bir şey. "Ne" "neden" ve son olarak "nasıl" ı açıklamak StackOverflow'un ruhunda. Cevabınız yalnızca "nasıl" ı içerir :(. Cevabınızı düzenleyerek tamamlamanıza izin veriyorum;).
David Guyon


0

Yukarıdaki çeşitli kaynaklardan ve kendi araştırmamdan, alt ağ ve adres hesaplamasını böyle çalıştırdım. Bu parçalar soruyu ve diğer ilgili soruları çözmek için yeterlidir.

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

Python'da bu işi çok iyi yapan SubnetTree adlı bir API vardır. Bu basit bir örnek:

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

Bu bağlantı


0

İşte kodum

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

Diğer modülleri içe aktarmak istemiyorsanız, gidebilirsiniz:

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

Bu cevaplarda önerilen çözümlerin bir alt kümesini denedim .. başarılı olamadım, sonunda önerilen kodu uyarlayıp düzelttim ve sabit fonksiyonumu yazdım.

Test ettim ve en azından küçük endian mimarilerinde (egx86) çalıştım, eğer biri büyük bir endian mimarisini denemeyi seviyorsa, lütfen bana geri bildirimde bulunun.

IP2Intkod bu gönderiden gelir , diğer yöntem ise bu sorudaki önceki tekliflerin tamamen (benim test durumlarım için) çalışan bir düzeltmesidir.

Kod:

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

Umarım faydalı olur,


0

İşte netaddr paketini kullanan çözüm

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.