Làm cách nào để kiểm tra xem ip có trong mạng bằng Python không?


100

Với một địa chỉ ip (giả sử 192.168.0.1), làm cách nào để kiểm tra xem địa chỉ đó có nằm trong mạng (giả sử 192.168.0.0/24) bằng Python hay không?

Có các công cụ chung trong Python để thao tác địa chỉ ip không? Những thứ như tra cứu máy chủ lưu trữ, địa chỉ ip thành int, địa chỉ mạng với netmask thành int, v.v.? Hy vọng rằng trong thư viện Python tiêu chuẩn cho 2.5.


Câu hỏi này có vẻ giống như một quy tắc ổn đối với các câu trả lời 2.x rất cũ, nhưng đã lỗi thời đối với 3.x Xem Cách tổ chức và gán các quy tắc chuẩn cho “Python / pandas so sánh địa chỉ IP / CIDR”?
smci

@smci Tôi không hiểu tại sao; Câu trả lời của phihag tại stackoverflow.com/a/1004527/1709587 là một câu trả lời hoàn toàn tốt cho Python 3 và đã ở đây từ năm 2014. Tôi đã khôi phục bản chỉnh sửa của bạn đã làm mất hiệu lực câu trả lời đó.
Mark Amery

@Staale - Bạn nên cập nhật câu trả lời của mình tại đây cho câu trả lời không có lỗi nghiêm trọng . Các câu trả lời khác sử dụng thư viện nội trang để thực hiện điều tương tự trong 1/10 mã mà không có bất kỳ lỗi nào.
Addison

Câu trả lời:


30

Bài viết này cho thấy bạn có thể làm điều đó với socketstructcác mô-đun mà không cần quá nhiều nỗ lực. Tôi đã thêm một chút vào bài viết như sau:

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)

Kết quả này là:

False
True

Nếu bạn chỉ muốn một hàm duy nhất nhận chuỗi, nó sẽ giống như sau:

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
Ngoài ra, struct.unpack ('L', socket.inet_aton (ip)) [0] sẽ không thành công trên các kiến ​​trúc trong đó 'L' giải nén thành một thứ gì đó khác 4 byte, bất kể độ bền.
Rafał Dowgird

5
Tiếp tục vào bình luận Rafal, để có được điều này để làm việc trên một phiên bản 64-bit Python thông dịch viên, thay thế dòng trong câu hỏi với:return struct.unpack('<L',socket.inet_aton(ip))[0]
đần độn

11
Tôi nghĩ rằng giải pháp của bạn có một lỗi nghiêm trọng: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(Tôi đã chuyển đổi 'L' thành '<L' trong hệ điều hành 64bit của mình)
Taha Jahangir

20
LƯU Ý: Giải pháp này có một lỗi nghiêm trọng:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir

6
Câu trả lời này có một lỗi . Xem câu trả lời: stackoverflow.com/questions/819355/…
Debanshu Kundu

156

Tôi thích sử dụng netaddr cho việc đó:

from netaddr import CIDR, IP

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

Như arno_v đã chỉ ra trong các nhận xét, phiên bản mới của netaddr thực hiện nó như thế này:

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
Hoặc trong phiên bản mới: từ netaddr nhập IPNetwork, IPAddress IPAddress ("192.168.0.1") trong IPNetwork ("192.168.0.0/24")
arno_v

140

Sử dụng ipaddress ( trong stdlib kể từ 3.3 , tại PyPi cho 2.6 / 2.7 ):

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

Nếu bạn muốn đánh giá nhiều địa chỉ IP theo cách này, có thể bạn sẽ muốn tính toán trước mặt nạ mạng, như

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

Sau đó, đối với mỗi địa chỉ, hãy tính toán biểu diễn nhị phân với một trong các

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

Cuối cùng, bạn chỉ cần kiểm tra:

in_network = (a & mask) == netw

2
Hãy lưu ý, python-ipaddr hoạt động khá chậm đối với chúng tôi, vì vậy nó thể không phù hợp với một số trường hợp yêu cầu nhiều so sánh thường xuyên. YMMV, vì vậy hãy tự đánh giá điểm chuẩn.
drdaeman

Trong một số phiên bản, bạn có thể cần cung cấp chuỗi unicode thay vì kiểu str Python, chẳng hạn như ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
Tôi lo ngại rằng phương pháp này đang lặp lại danh sách địa chỉ trong mạng, nhưng mô-đun ipaddress sẽ ghi đè __contains__phương thức để thực hiện điều đó theo cách hiệu quả bằng cách so sánh các đại diện số nguyên của mạng và địa chỉ quảng bá, vì vậy hãy yên tâm nếu đó là nỗi lo của bạn .
avatarofhope2

24

Đối với 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')

Đầu ra:

False
True

1
Tiêu chuẩn lib sử dụng kiểm tra bitwise thông minh vì vậy đây là giải pháp tối ưu nhất ở đây. github.com/python/cpython/blob/3.8/Lib/ipaddress.py#L690
rocketspacer

10

Mã này đang làm việc cho tôi trên Linux x86. Tôi chưa thực sự suy nghĩ về các vấn đề nội dung, nhưng tôi đã thử nghiệm nó với mô-đun "ipaddr" bằng cách sử dụng hơn 200K địa chỉ IP được thử nghiệm với 8 chuỗi mạng khác nhau và kết quả của ipaddr giống với mã này.

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)

Thí dụ:

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

Đẹp và nhanh chóng. Không cần thư viện cho một vài thao tác logic đơn giản.
Chris Koston

7

Sử dụng ipaddress 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}")))

Giải trình

Bạn có thể coi Địa chỉ IPMạng có mặt nạ mạng lớn nhất có thể ( /32đối với IPv4, /128đối với IPv6)

Kiểm tra xem có tham gia hay không 192.168.0.1về 192.168.0.0/16cơ bản giống như kiểm tra xem có phải 192.168.0.1/32là mạng con của192.168.0.0/16


... không chắc tại sao câu trả lời này không nằm ở đầu (chưa).
Filippo Vitale

6

Tôi đã thử giải pháp của Dave Webb nhưng gặp một số vấn đề:

Về cơ bản nhất - kết quả khớp phải được kiểm tra bằng cách AND địa chỉ IP với mặt nạ, sau đó kiểm tra kết quả khớp chính xác với địa chỉ Mạng. Không ANDing địa chỉ IP với địa chỉ Mạng như đã được thực hiện.

Tôi cũng nhận thấy rằng việc bỏ qua hành vi Endian giả định rằng tính nhất quán sẽ giúp bạn tiết kiệm sẽ chỉ hoạt động đối với các mặt nạ trên ranh giới octet (/ 24, / 16). Để các mặt nạ khác (/ 23, / 21) hoạt động chính xác, tôi đã thêm "lớn hơn" vào lệnh struct và thay đổi mã tạo mặt nạ nhị phân để bắt đầu bằng tất cả "1" và dịch chuyển sang trái bằng (32-mask ).

Cuối cùng, tôi đã thêm một kiểm tra đơn giản rằng địa chỉ mạng có hợp lệ cho mặt nạ hay không và chỉ cần in cảnh báo nếu không.

Đây là kết quả:

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

Điều này dường như hoạt động đáng tin cậy trên 64-bit ('L' không thành công vì giá trị là 32-bit) và trả về các giá trị theo thứ tự hợp lý (ipaddr sẽ là 0xC0A80001 cho 192.168.0.1). Nó cũng phản ứng với "192.168.0.1/24" như một mặt nạ mạng cho "192.168.0.1" (không tiêu chuẩn, nhưng có thể dễ dàng và có thể sửa chữa)
IBBoard

Hoạt động hoàn hảo trên Python 2.4
xlash

6

Tôi không phải là người thích sử dụng các mô-đun khi chúng không cần thiết. Công việc này chỉ yêu cầu phép toán đơn giản, vì vậy đây là hàm đơn giản của tôi để thực hiện công việc:

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

Sau đó, để sử dụng nó:

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

Vậy là xong, điều này nhanh hơn nhiều so với các giải pháp ở trên với các mô-đun đi kèm.


{TypeError}'map' object is not subscriptable. Bạn cần một o = list(o)sauo = map(int, ip.split('.'))
gies0r

5

Không có trong thư viện Chuẩn cho 2.5, nhưng ipaddr làm cho việc này rất dễ dàng. Tôi tin rằng nó nằm trong 3.3 dưới tên 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)

Đây là lựa chọn yêu thích của tôi trong số vô số lựa chọn ở đây (tại thời điểm nhận xét, năm 2017). Cảm ơn!
rsaw

5

Câu trả lời được chấp nhận không có tác dụng ... điều đó khiến tôi tức giận. Mặt nạ ngược và không hoạt động với bất kỳ bit nào không phải là một khối 8 bit đơn giản (ví dụ / 24). Tôi đã điều chỉnh câu trả lời, và nó hoạt động rất tốt.

    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

đây là một hàm trả về một chuỗi nhị phân có dấu chấm để giúp trực quan hóa đầu ra mặt nạ .. loại tương tự ipcalc.

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

ví dụ:

ảnh chụp màn hình của trăn


4

Mã của Marc gần đúng. Một phiên bản hoàn chỉnh của mã là -

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

Rõ ràng là từ các nguồn tương tự như trên ...

Một lưu ý rất quan trọng là mã đầu tiên có một trục trặc nhỏ - Địa chỉ IP 255.255.255.255 cũng hiển thị là IP hợp lệ cho bất kỳ mạng con nào. Tôi đã có rất nhiều thời gian để mã này hoạt động và cảm ơn Marc vì câu trả lời chính xác.


Đã thử và thử nghiệm. Từ tất cả các ví dụ các ổ cắm / struct trên trang này này là người duy nhất đúng
Zabuzzman

4

Việc dựa vào mô-đun "struct" có thể gây ra vấn đề với kích thước kiểu và kích thước endian-ness và chỉ là không cần thiết. Socket.inet_aton () cũng vậy. Python hoạt động rất tốt với các địa chỉ IP bốn chấm:

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

Tôi cần thực hiện đối sánh IP trên mỗi lệnh gọi accept () socket, với toàn bộ tập hợp các mạng nguồn được phép, vì vậy tôi tính toán trước mặt nạ và mạng, dưới dạng số nguyên:

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

Sau đó, tôi có thể nhanh chóng xem liệu một IP nhất định có nằm trong một trong các mạng đó hay không:

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

Không cần nhập mô-đun và mã khớp rất nhanh.


Những gì được gọi là cache_masks này ??
ajin

2

từ netaddr nhập 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')]

Đây là cách sử dụng cho phương pháp này:

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

Về cơ bản, bạn cung cấp địa chỉ ip làm đối số đầu tiên và danh sách các cidrs làm đối số thứ hai. Một danh sách các lần truy cập được trả lại.


2
# Điều này hoạt động bình thường mà không cần xử lý từng byte kỳ lạ
def addressInNetwork (ip, net):
    '' 'Là một địa chỉ trong mạng' ''
    # Chuyển đổi địa chỉ thành thứ tự lưu trữ, do đó, sự thay đổi thực sự có ý nghĩa
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bit = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Phải dịch sang trái một giá trị tất cả, / 32 = dịch chuyển bằng 0, / 0 = 32 dịch chuyển sang trái
    netmask = (0xffffffff << (32-int (bits))) & 0xffffffff
    # Không cần che địa chỉ mạng, miễn là địa chỉ mạng phù hợp
    return (ip & netmask) == netaddr 

Mã không hoạt động chính xác trên hệ điều hành 64 bit do các netmaskgiá trị không chính xác . Tôi đã tự do sửa chữa điều đó.
drdaeman

2

giải pháp trước có lỗi trong ip & net == net. Tra cứu ip đúng là ip & netmask = net

mã sửa lỗi:

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

Câu trả lời chọn có một lỗi.

Sau đây là mã chính xác:

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

Lưu ý: ipaddr & netmask == netaddr & netmaskthay vì ipaddr & netmask == netmask.

Tôi cũng thay thế ((2L<<int(bits)-1) - 1)bằng ((1L << int(bits)) - 1), vì cái sau có vẻ dễ hiểu hơn.


Tôi nghĩ rằng việc chuyển đổi mặt nạ ((2L<<int(bits)-1) - 1)là chính xác. ví dụ: nếu mặt nạ là 16, nó phải là "255.255.0.0" hoặc 65535L, nhưng ((1L << int(bits)) - 1)sẽ nhận được 32767L, điều này không đúng.
Chris.Q

@ Chris.Q, ((1L << int(bits)) - 1)cung cấp 65535L trên hệ thống của tôi, với bitsđặt thành 16 !!
Debanshu Kundu

Ngoài ra, đối với bitsthiết lập là 0, ((2L<<int(bits)-1) - 1)đang tăng lỗi.
Debanshu Kundu

Có, thực tế không có giá trị nào khác ngoài / 0, / 8, / 16, / 32 đang hoạt động bình thường.
Debanshu Kundu

2

Đây là một lớp tôi đã viết để so khớp tiền tố dài nhất:

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

Và đây là một chương trình thử nghiệm:

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

Cảm ơn vì kịch bản của bạn!
Tôi đã làm việc khá lâu về nó để làm cho mọi thứ hoạt động ... Vì vậy, tôi đang chia sẻ nó ở đây

  • Sử dụng netaddr Class chậm hơn 10 lần so với sử dụng chuyển đổi nhị phân, vì vậy nếu bạn muốn sử dụng nó trên một danh sách IP lớn, bạn nên cân nhắc không sử dụng netaddr class
  • chức năng makeMask không hoạt động! Chỉ hoạt động cho / 8, / 16, / 24
    Ví dụ:

    bit = "21"; socket.inet_ntoa (struct.pack ('= L', (2L << int (bits) -1) - 1))
    '255.255.31.0' trong khi nó phải là 255.255.248.0

    Vì vậy, tôi đã sử dụng một hàm khác calcDottedNetmask (mặt nạ) từ http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
    Ví dụ:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Một vấn đề khác là quá trình đối sánh nếu một IP thuộc về một mạng! Thao tác cơ bản phải là để so sánh (ipaddr & netmask) và (mạng & netmask).
    Vd: tạm thời chức năng bị sai

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

Vì vậy, hàm addressInNetwork mới của tôi trông giống như sau:


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

Và bây giờ, câu trả lời là đúng !!


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

Tôi hy vọng rằng nó sẽ giúp ích cho người khác, tiết kiệm thời gian cho họ!


1
phiên bản hiện tại của đoạn mã trên cung cấp một dấu vết ở dòng cuối cùng, mà bạn có thể "| =" một int và một tuple.
Sean Reifschneider

1

Liên quan đến tất cả những điều trên, tôi nghĩ rằng socket.inet_aton () trả về các byte theo thứ tự mạng, vì vậy cách chính xác để giải nén chúng có lẽ là

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
Sai
Đúng
Sai


Bạn có thể giải thích những gì bạn đang thêm vào các câu trả lời đã được đưa ra?
David Guyon

Các câu trả lời đã cho có một số vấn đề, không thể xử lý CIDR. Tôi vừa thay đổi thứ tự byte của địa chỉ IP. Giống như thế này:>>> 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
Cảm ơn vì câu trả lời. Tôi đoán đó là điều bạn nên thêm vào câu trả lời của mình để làm rõ. Theo tinh thần của StackOverflow là giải thích "cái gì" "tại sao" và cuối cùng là "làm thế nào". Câu trả lời của bạn chỉ chứa "cách" :(. Tôi cho phép bạn hoàn thành câu trả lời của mình bằng cách chỉnh sửa nó;).
David Guyon

1

Tôi không biết bất kỳ thứ gì trong thư viện tiêu chuẩn, nhưng PySubnetTree là một thư viện Python sẽ thực hiện khớp mạng con.


Liên kết đã được thay đổi. Bạn có thể tìm thấy PySubnetTree tại GitHub
Mayank Agarwal,

0

Từ các nguồn khác nhau ở trên, và từ nghiên cứu của riêng tôi, đây là cách tôi làm việc tính toán mạng con và địa chỉ. Những phần này đủ để giải quyết câu hỏi và các câu hỏi liên quan khác.

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ó một API được gọi là SubnetTree có sẵn trong python thực hiện công việc này rất tốt. Đây là một ví dụ đơn giản:

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

Đây là liên kết


0

Đây là mã của tôi

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

Nếu bạn không muốn nhập các mô-đun khác, bạn có thể sử dụng:

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

Tôi đã thử một tập hợp con các giải pháp được đề xuất trong các câu trả lời này .. không thành công, cuối cùng tôi đã điều chỉnh và sửa mã đề xuất và viết hàm cố định của mình.

Tôi đã thử nghiệm nó và hoạt động ít nhất trên các kiến ​​trúc endian nhỏ - vdx86-- nếu có ai thích thử một kiến ​​trúc endian lớn, vui lòng cho tôi phản hồi.

IP2Intmã đến từ bài đăng này , phương pháp khác là một bản sửa lỗi hoạt động đầy đủ (cho các trường hợp thử nghiệm của tôi) đối với các đề xuất trước đó trong câu hỏi này.

Mật mã:

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

Hy vọng hữu ích,


0

Đây là giải pháp sử dụng gói 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.