Bagaimana cara memeriksa apakah ip ada dalam jaringan dengan Python?

100

Diberikan alamat ip (katakanlah 192.168.0.1), bagaimana cara memeriksa apakah itu dalam jaringan (katakanlah 192.168.0.0/24) dengan Python?

Apakah ada alat umum di Python untuk manipulasi alamat ip? Hal-hal seperti pencarian host, alamat ip ke int, alamat jaringan dengan netmask ke int dan sebagainya? Semoga di perpustakaan Python standar untuk 2.5.

Staale
sumber
Pertanyaan ini sepertinya kanonis yang oke untuk jawaban 2.x yang sangat lama, tetapi sudah usang untuk 3.x. Lihat Bagaimana mengatur dan menetapkan kanonikal untuk "Python / pandas membandingkan alamat IP / CIDR"?
smci
@ci Saya tidak mengerti mengapa; Jawaban phihag di stackoverflow.com/a/1004527/1709587 adalah jawaban yang sangat bagus untuk Python 3 dan telah ada di sini sejak 2014. Saya telah mengembalikan hasil edit Anda yang membatalkan jawaban itu.
Mark Amery
@Staale - Anda harus memperbarui jawaban Anda di sini ke jawaban yang tidak memiliki bug kritis . Jawaban lain menggunakan pustaka bawaan untuk mencapai hal yang sama dalam kode 1/10, tanpa bug.
Addison

Jawaban:

30

Artikel ini menunjukkan Anda dapat melakukannya dengan modul socketdan structtanpa terlalu banyak usaha ekstra. Saya menambahkan sedikit ke artikel sebagai berikut:

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)

Output ini:

False
True

Jika Anda hanya menginginkan satu fungsi yang mengambil string, maka akan terlihat seperti ini:

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
Dave Webb
sumber
8
Selain itu, struct.unpack ('L', socket.inet_aton (ip)) [0] akan gagal pada arsitektur di mana 'L' membongkar ke sesuatu yang berbeda dari 4 byte, terlepas dari endianness.
Rafał Dowgird
5
Melanjutkan komentar Rafal, agar ini berfungsi pada penerjemah Python 64-bit, ganti baris yang dimaksud dengan:return struct.unpack('<L',socket.inet_aton(ip))[0]
nitwit
11
Saya pikir solusi Anda memiliki bug yang serius: addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(Saya mengonversi 'L' ke '<L' di os 64bit saya)
Taha Jahangir
20
PERHATIAN: Solusi ini memiliki bug yang serius:addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
Taha Jahangir
6
Jawaban ini memiliki bug . Lihat jawabannya: stackoverflow.com/questions/819355/…
Debanshu Kundu
156

Saya suka menggunakan netaddr untuk itu:

from netaddr import CIDR, IP

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

Seperti yang ditunjukkan arno_v di komentar, versi baru netaddr melakukannya seperti ini:

from netaddr import IPNetwork, IPAddress
if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"):
    print "Yay!"
nosklo.dll
sumber
>>> 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
Atau di versi baru: dari netaddr import IPNetwork, IPAddress IPAddress ("192.168.0.1") di IPNetwork ("192.168.0.0/24")
arno_v
140

Menggunakan ipaddress ( di stdlib sejak 3.3 , di PyPi untuk 2.6 / 2.7 ):

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

Jika Anda ingin mengevaluasi banyak alamat IP dengan cara ini, Anda mungkin ingin menghitung netmask dimuka, seperti

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

Kemudian, untuk setiap alamat, hitung representasi biner dengan salah satu

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

Terakhir, Anda cukup memeriksa:

in_network = (a & mask) == netw
phihag
sumber
2
Berhati-hatilah, python-ipaddr berperilaku cukup lambat bagi kami, jadi mungkin tidak sesuai untuk beberapa kasus di mana banyak perbandingan sering diperlukan. YMMV, jadi tolok ukur diri Anda.
drdaeman
Di beberapa versi, Anda mungkin perlu menyediakan string unicode alih-alih jenis str Python, seperti ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy
1
Saya khawatir bahwa metode ini mengulangi daftar alamat di jaringan, tetapi modul ipaddress mengganti __contains__metode untuk melakukannya dengan cara yang efisien dengan membandingkan representasi integer dari jaringan dan alamat siaran, jadi yakinlah jika itu kekhawatiran Anda .
avatarofhope2
24

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

Keluaran:

False
True
petertc
sumber
1
Lib standar menggunakan pemeriksaan bitwise pintar jadi ini adalah solusi paling optimal di sini. github.com/python/cpython/blob/3.8/Lib/ipaddress.py#L690
rocketspacer
10

Kode ini berfungsi untuk saya di Linux x86. Saya belum benar-benar memikirkan masalah endianess, tetapi saya telah mengujinya terhadap modul "ipaddr" menggunakan lebih dari 200K alamat IP yang diuji terhadap 8 string jaringan yang berbeda, dan hasil ipaddr sama dengan kode ini.

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)

Contoh:

>>> print addressInNetwork('10.9.8.7', '10.9.1.0/16')
True
>>> print addressInNetwork('10.9.8.7', '10.9.1.0/24')
False
Sean Reifschneider
sumber
Bagus dan cepat. Tidak perlu perpustakaan untuk beberapa operasi logika sederhana.
Chris Koston
7

Menggunakan Python3 ipaddress :

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

Penjelasan

Anda dapat menganggap Alamat IP sebagai Jaringan dengan kemungkinan netmask terbesar ( /32untuk IPv4, /128untuk IPv6)

Memeriksa apakah 192.168.0.1masuk pada 192.168.0.0/16dasarnya sama dengan memeriksa apakah 192.168.0.1/32itu subnet dari192.168.0.0/16

rocketspacer
sumber
... tidak yakin mengapa jawaban ini belum ada di atas (belum).
Filippo Vitale
6

Saya mencoba solusi Dave Webb tetapi mengalami beberapa masalah:

Yang paling mendasar - kecocokan harus diperiksa dengan MENGANDALKAN alamat IP dengan mask, kemudian memeriksa hasilnya cocok dengan alamat Jaringan secara tepat. Bukan ANDing alamat IP dengan alamat Jaringan seperti yang telah dilakukan.

Saya juga memperhatikan bahwa mengabaikan perilaku Endian dengan asumsi bahwa konsistensi akan menyelamatkan Anda hanya akan berfungsi untuk topeng pada batas oktet (/ 24, / 16). Agar topeng lain (/ 23, / 21) bekerja dengan benar, saya menambahkan "lebih besar dari" ke perintah struct dan mengubah kode untuk membuat topeng biner untuk memulai dengan semua "1" dan menggeser ke kiri oleh (32-mask ).

Akhirnya, saya menambahkan pemeriksaan sederhana bahwa alamat jaringan valid untuk mask dan hanya mencetak peringatan jika tidak.

Inilah hasilnya:

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
Paul McDonnell
sumber
Ini tampaknya bekerja dengan andal pada 64-bit ('L' gagal karena nilainya 32-bit) dan mengembalikan nilai dalam urutan yang masuk akal (ipaddr akan menjadi 0xC0A80001 untuk 192.168.0.1). Ini juga mengatasi "192.168.0.1/24" sebagai netmask untuk "192.168.0.1" (bukan standar, tetapi mungkin dan mudah diperbaiki)
IBBoard
Bekerja dengan sempurna pada Python 2.4
xlash
6

Saya bukan penggemar menggunakan modul saat tidak diperlukan. Pekerjaan ini hanya membutuhkan matematika sederhana, jadi inilah fungsi sederhana saya untuk melakukan pekerjaan itu:

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

Kemudian untuk menggunakannya:

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

Itu saja, ini jauh lebih cepat daripada solusi di atas dengan modul yang disertakan.

Mendarat di
sumber
{TypeError}'map' object is not subscriptable. Anda membutuhkan o = list(o)setelaho = map(int, ip.split('.'))
gies0r
5

Tidak ada di perpustakaan Standar untuk 2.5, tetapi ipaddr membuat ini sangat mudah. Saya percaya itu ada di 3.3 dengan nama 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)
James Robinson
sumber
Sejauh ini, ini adalah favorit saya dari semua pilihan yang banyak di sini (saat komentar, 2017). Terima kasih!
rsaw
5

Jawaban yang diterima tidak berhasil ... yang membuatku marah. Mask mundur dan tidak bekerja dengan bit apa pun yang bukan blok 8 bit sederhana (mis. / 24). Saya menyesuaikan jawabannya, dan berhasil dengan baik.

    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

di sini adalah fungsi yang mengembalikan string biner bertitik untuk membantu memvisualisasikan masking .. jenis ipcalckeluaran serupa .

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

misalnya:

tangkapan layar python

jorb
sumber
4

Kode Marc hampir benar. Versi lengkap dari kode ini adalah -

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

Jelas dari sumber yang sama seperti di atas ...

Catatan yang sangat penting adalah bahwa kode pertama memiliki kesalahan kecil - Alamat IP 255.255.255.255 juga muncul sebagai IP yang Valid untuk subnet apa pun. Saya memiliki banyak waktu untuk membuat kode ini berfungsi dan terima kasih kepada Marc untuk jawaban yang benar.

Nitin Khanna
sumber
Dicoba dan diuji. Dari semua contoh socket / struct di halaman ini adalah satu-satunya yang benar
Zabuzzman
4

Mengandalkan modul "struct" dapat menyebabkan masalah dengan endian-ness dan ukuran tipe, dan tidak diperlukan. Juga bukan socket.inet_aton (). Python bekerja sangat baik dengan alamat IP dotted-quad:

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

Saya perlu melakukan pencocokan IP pada setiap panggilan socket accept (), terhadap seluruh rangkaian jaringan sumber yang diizinkan, jadi saya menghitung sebelumnya topeng dan jaringan, sebagai bilangan bulat:

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

Kemudian saya dapat dengan cepat melihat apakah IP yang diberikan ada dalam salah satu jaringan tersebut:

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

Tidak perlu impor modul, dan kodenya sangat cepat dalam mencocokkan.

gstein.dll
sumber
Apa yang dimaksud cached_masks ini ??
ajin
2

dari netaddr import all_matching_cidrs

>>> from netaddr import all_matching_cidrs
>>> all_matching_cidrs("212.11.70.34", ["192.168.0.0/24","212.11.64.0/19"] )
[IPNetwork('212.11.64.0/19')]

Berikut adalah penggunaan metode ini:

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

Pada dasarnya Anda memberikan alamat ip sebagai argumen pertama dan daftar cidrs sebagai argumen kedua. Daftar klik dikembalikan.


sumber
2
#Ini berfungsi dengan baik tanpa byte aneh dengan penanganan byte
def addressInNetwork (ip, net):
    '' 'Apakah alamat dalam jaringan' ''
    # Konversikan alamat menjadi urutan host, jadi pergeseran sebenarnya masuk akal
    ip = struct.unpack ('> L', socket.inet_aton (ip)) [0]
    netaddr, bits = net.split ('/')
    netaddr = struct.unpack ('> L', socket.inet_aton (netaddr)) [0]
    # Harus bergeser ke kiri nilai semua, / 32 = nol shift, / 0 = 32 shift kiri
    netmask = (0xffffffff << (32-int (bits))) & 0xffffffff
    # Tidak perlu menutupi alamat jaringan, selama itu alamat jaringan yang benar
    return (ip & netmask) == netaddr 
Marcelo Pacheco
sumber
Kode tidak berfungsi dengan benar pada OS 64-bit, karena netmasknilai yang salah . Saya telah mengambil kebebasan untuk memperbaikinya.
drdaeman
2

solusi sebelumnya memiliki bug di ip & net == net. Pencarian ip yang benar adalah ip & netmask = net

kode perbaikan bug:

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");
pengguna3265849
sumber
2

Jawaban yang dipilih memiliki bug.

Berikut adalah kode yang benar:

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

Catatan: ipaddr & netmask == netaddr & netmaskalih-alih ipaddr & netmask == netmask.

Saya juga mengganti ((2L<<int(bits)-1) - 1)dengan ((1L << int(bits)) - 1), karena yang terakhir tampaknya lebih bisa dimengerti.

Debanshu Kundu
sumber
Saya pikir konversi topeng ((2L<<int(bits)-1) - 1)sudah benar. misal, jika topengnya 16, seharusnya "255.255.0.0" atau 65535L, tetapi ((1L << int(bits)) - 1)akan mendapatkan 32767L, yang mana tidak benar.
Chris.Q
@ Chris.Q, ((1L << int(bits)) - 1)memberikan 65535L pada sistem saya, dengan bitsset ke 16 !!
Debanshu Kundu
Juga, untuk bitsset ke 0, ((2L<<int(bits)-1) - 1)meningkatkan kesalahan.
Debanshu Kundu
Ya, sebenarnya tidak ada nilai selain / 0, / 8, / 16, / 32 yang berfungsi dengan baik.
Debanshu Kundu
2

Berikut adalah kelas yang saya tulis untuk pencocokan awalan terpanjang:

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

Dan ini program tesnya:

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
Amir
sumber
1

Terima kasih atas naskah Anda!
Saya memiliki pekerjaan yang cukup lama untuk membuat semuanya bekerja ... Jadi saya membagikannya di sini

  • Menggunakan Kelas netaddr 10 kali lebih lambat daripada menggunakan konversi biner, jadi jika Anda ingin menggunakannya pada daftar besar IP, Anda harus mempertimbangkan untuk tidak menggunakan kelas netaddr
  • Fungsi makeMask tidak berfungsi! Hanya bekerja untuk / 8, / 16, / 24
    Ex:

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

    Jadi saya telah menggunakan fungsi lain calcDottedNetmask (mask) dari http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
    Ex:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • Masalah lainnya adalah proses pencocokan jika IP milik jaringan! Operasi Dasar harus membandingkan (ipaddr & netmask) dan (network & netmask).
    Misal: untuk saat ini fungsinya salah

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

Jadi fungsi addressInNetwork baru saya terlihat seperti:


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

Dan sekarang, jawabannya benar !!


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

Saya berharap ini akan membantu orang lain, menghemat waktu untuk mereka!

Marc Leurent
sumber
1
versi saat ini dari kode di atas memberikan penelusuran kembali di baris terakhir, bahwa Anda dapat "| =" an int dan tuple.
Sean Reifschneider
1

Berkaitan dengan semua hal di atas, saya pikir socket.inet_aton () mengembalikan byte dalam urutan jaringan, jadi cara yang benar untuk membukanya mungkin adalah

struct.unpack('!L', ... )
Quentin Stafford-Fraser
sumber
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

Johnson
sumber
Bisakah Anda menjelaskan apa yang Anda tambahkan ke jawaban yang sudah diberikan?
David Guyon
Jawaban yang diberikan memiliki beberapa masalah, yang tidak dapat menangani CIDR. Saya baru saja mengubah urutan byte dari alamat IP. Persis seperti ini:>>> 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
Terima kasih atas jawabannya. Saya rasa itu adalah sesuatu yang harus Anda tambahkan pada jawaban Anda untuk memperjelas. Ada dalam semangat StackOverflow untuk menjelaskan "apa" "mengapa" dan terakhir "bagaimana". Jawaban Anda hanya berisi "bagaimana" :(. Saya mengizinkan Anda melengkapi jawaban Anda dengan mengeditnya;).
David Guyon
1

Saya tidak tahu apa-apa di perpustakaan standar, tetapi PySubnetTree adalah perpustakaan Python yang akan melakukan pencocokan subnet.

RichieHindle
sumber
Tautan telah diubah. PySubnetTree dapat ditemukan di GitHub
Mayank Agarwal
0

Dari berbagai sumber di atas, dan dari penelitian saya sendiri, inilah cara saya mendapatkan subnet dan penghitungan alamat. Potongan-potongan ini cukup untuk menjawab pertanyaan dan pertanyaan terkait lainnya.

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)
Nathan Garabedian
sumber
0

Ada API yang disebut SubnetTree tersedia dalam python yang melakukan pekerjaan ini dengan sangat baik. Ini adalah contoh sederhana:

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

Ini tautannya

salaheddine
sumber
0

Ini kode saya

# -*- 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')
ruohanc
sumber
0

Jika Anda tidak ingin mengimpor modul lain, Anda dapat menggunakan:

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]
Benny93
sumber
0

Saya mencoba satu subset dari solusi yang diusulkan dalam jawaban ini .. tanpa hasil, saya akhirnya menyesuaikan dan memperbaiki kode yang diusulkan dan menulis fungsi tetap saya.

Saya mengujinya dan bekerja setidaknya pada arsitektur little endian - egx86 - jika ada yang suka mencoba arsitektur big endian, tolong beri saya umpan balik.

IP2Intkode berasal dari posting ini , metode lainnya adalah sepenuhnya (untuk kasus uji saya) perbaikan yang berfungsi dari proposal sebelumnya dalam pertanyaan ini.

Kode:

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

Semoga bermanfaat,

Fabiano Tarlao
sumber
0

Berikut adalah solusi menggunakan paket 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)
chasank
sumber