如何在 Python 中检查 IP 是否在网络中?

给定一个 ip 地址(比如192.168.0.1) ,如何用 Python 检查它是否在网络中(比如192.168.0.0/24) ?

Python 中是否有用于 IP 地址操作的通用工具?主机查找,IP 地址到整型,网络地址与网络掩码到整型等等?希望在2.5版本的标准 Python 库中。

187648 次浏览

我对标准库一无所知,但是 PySubnetTree是一个 Python 库,可以进行子网匹配。

本文 展示了使用 socketstruct模块可以做到这一点,而不需要太多额外的工作。我在文章中添加了一些内容如下:

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)

产出:

False
True

如果你只想要一个接受字符串的函数,它应该是这样的:

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

我喜欢使用 Netaddr:

from netaddr import CIDR, IP


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

正如 arno _ v 在评论中指出的,新版本的 netaddr 是这样的:

from netaddr import IPNetwork, IPAddress
if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"):
print "Yay!"

使用 地址(从3.3开始2.6/2.7版本) :

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

如果希望以这种方式计算 IP 地址的 很多,可能需要预先计算网络掩码,如

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

然后,对于每个地址,使用

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

最后,你可以简单地检查:

in_network = (a & mask) == netw

谢谢你的剧本!
我在这上面花了很长时间来让一切运转起来... 所以我在这里分享它

  • 使用 netaddr 类比使用二进制转换慢10倍,所以如果您想在大量的 IP 上使用它,您应该考虑不使用 netaddr 类
  • MakMask 函数不工作! 只能在/8,/16,/24 < br > Ex:

    Bits = “21”; socket.inet _ ntoa (struct.pack (’= L’,(2L < < int (bits)-1)-1))
    ’255.255.31.0’,而它应该是255.255.248.0

    因此,我使用了来自 http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/的另一个函数 calcDottedNetcover (掩码)
    例句:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • 另一个问题是 IP 是否属于网络的匹配过程!基本的操作应该是比较(ipaddr 和网络掩码)和(网络和网络掩码)。< br > Ex: 目前,函数是错误的

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

因此,我的新地址 InNetwork 函数看起来像:


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




现在,答案是正确的! !


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

我希望它能帮助其他人,为他们节省时间!

这段代码可以在 Linux x86上运行。我并没有真正考虑到 endiness 问题,但是我已经用超过200K 的 IP 地址在“ ipaddr”模块中对8个不同的网络字符串进行了测试,并且 ipaddr 的结果与这段代码相同。

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)

例如:

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

马克的代码几乎是正确的。一个完整的版本的代码是-

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

很明显,来自上面提到的同一个消息来源。

一个非常重要的注意事项是,第一个代码有一个小故障-IP 地址255.255.255.255也显示为任何子网的有效 IP。我花了很长时间才让这个代码工作起来,并且感谢 Marc 给出了正确的答案。

从 netaddr 导入 all _ match _ 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')]

这个方法的用法如下:

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

基本上,第一个参数提供 ip 地址,第二个参数提供 cidr 列表。返回命中列表。

#This works properly without the weird byte by byte handling
def addressInNetwork(ip,net):
'''Is an address in a network'''
# Convert addresses to host order, so shifts actually make sense
ip = struct.unpack('>L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netaddr = struct.unpack('>L',socket.inet_aton(netaddr))[0]
# Must shift left an all ones value, /32 = zero shift, /0 = 32 shift left
netmask = (0xffffffff << (32-int(bits))) & 0xffffffff
# There's no need to mask the network address, as long as its a proper network address
return (ip & netmask) == netaddr

我尝试了戴夫•韦伯(Dave Webb)的解决方案,但遇到了一些问题:

最基本的是-一个匹配应该通过 ANDing 的 IP 地址与掩码,然后检查结果与网络地址完全匹配。没有像以前那样使用网络地址对 IP 地址进行 AND。

我还注意到,只是忽略 Endian 行为假设一致性将节省您将只工作在八位边界的掩码(/24,/16)。为了让其他掩码(/23,/21)正常工作,我在 struct 命令中添加了一个“大于”,并修改了创建二进制掩码的代码,以全部“1”开始,并向左移动(32掩码)。

最后,我添加了一个简单的检查,检查网络地址是否对掩码有效,如果没有,只需打印一个警告。

结果是这样的:

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

关于以上所有内容,我认为 socket.inet _ aton ()按网络顺序返回字节,因此解压缩它们的正确方法可能是

struct.unpack('!L', ... )

下面是我为最长前缀匹配编写的一个类:

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

这是一个测试程序:

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

虽然在标准库中不支持2.5版本,但是 ipaddr 使这个过程变得非常简单。我相信是在3.3下的名称 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)

以前的解决方案在 ip & net = net 中有一个 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");

所选择的答案有一个错误。

下面是正确的代码:

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

注: ipaddr & netmask == netaddr & netmask代替 ipaddr & netmask == netmask

我也用 ((1L << int(bits)) - 1)代替 ((2L<<int(bits)-1) - 1),因为后者似乎更容易理解。

我不喜欢在不需要的时候使用模块。这项工作只需要简单的数学,所以这里是我的简单函数来做这项工作:

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

然后使用它:

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

就是这样,这比上面包含模块的解决方案要快得多。

只要有可能,我会推荐内置的 地址模块。虽然它只能在 Python3中使用,但是它非常容易使用,并且支持 IPv6。你为什么还不用 Python 3呢,


接受的答案不起作用... 这让我很生气。掩码是向后的,不能与任何不是简单的8位块(例如/24)的位一起工作。我改编了答案,效果很好。

    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

这里有一个函数,它返回一个虚线二进制字符串来帮助可视化屏蔽. . 类似于 ipcalc输出。

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

例如:

screen shot of python

从上面的各种来源,以及从我自己的研究,这就是我如何得到子网和地址计算工作。这些片段足以解决问题和其他相关问题。

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)

在 python 中有一个名为 SubnetTree 的 API,可以很好地完成这项工作。 这是一个简单的例子:

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

这就是链接

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
假的
没错
假的

这是我的密码

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

如果您不想导入其他模块,可以使用:

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]

依赖“ struct”模块可能会导致 Endian-ness 和类型大小方面的问题,而且根本不需要这样做。Socket.inet _ aton ()也不是。Python 可以很好地处理点四 IP 地址:

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

我需要在每个套接字接受()调用上对一整套允许的源网络进行 IP 匹配,因此我将掩码和网络作为整数进行预计算:

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

然后我就可以快速查看给定的 IP 是否在其中一个网络中:

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

不需要模块导入,并且代码是 非常快速匹配。

在这些答案中,我尝试了一些建议的解决方案。.没有成功,我最终改编和修正了提出的代码,并写了我的固定功能。

我测试了它,并且至少在 little endian 架构上工作——例如 x86——如果有人喜欢尝试 big endian 架构,请给我反馈。

IP2Int代码来自 这篇文章,另一种方法是一个完整的(对于我的测试用例)工作修复以前的建议在这个问题。

密码:

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

希望有用,

巨蟒3

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

产出:

False
True

使用 Python > = 3.7 地址:

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

解释

您可以将 IP 地址视为具有最大可能网络掩码的 网络(对于 IPv4来说是 /32,对于 IPv6来说是 /128)

检查 192.168.0.1是否在 192.168.0.0/16中基本上与检查 192.168.0.1/32是否是 192.168.0.0/16的子网相同

下面是使用 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)

对于 Python 3.7 ,您可以使用 subnet_ofsupernet_of助手方法,它们是标准库的一部分:

为了只测试一个 IP,你可以使用子网掩码 /32,意思是“只有这个 IP 地址”作为子网,或者你可以将 IP 地址传递给 IPv4NeworkIPv6Nework构造函数,他们会为你返回一个子网值。

举个例子:

from ipaddress import IPv4Network, IPv4Address


# Store IP Address as variable
>>> myip = IPv4Address('192.168.0.1')
>>> myip
IPv4Address('192.168.0.1')


# This treats the IP as a subnet
>>> myip_subnet = IPv4Network(myip)
>>> myip_subnet
IPv4Network('192.168.0.1/32')


# The other subnet to test membership against
>>> other_subnet = IPv4Network('192.168.0.0/24')
>>> other_subnet
IPv4Network('192.168.0.0/24')


# Now we can test
>>> myip_subnet.subnet_of(other_subnet)
True

Python 中是否有用于 IP 地址操作的通用工具 如主机查找,IP 地址到整型,网络地址与网络掩码到 希望在2.5版本的标准 Python 库中。

在 Python3中,有一个 ipaddress模块,它具有用于 IPv4和 IPv6操作的工具。您可以通过强制转换(即 int(IPv4Address('192.168.0.1')))将它们转换为 int。ipaddress模块中的许多其他有用的函数用于主机,等等。

为了避免内置模块或第三方模块随着时间的推移改变语法,我创建了自己的模块。我将它用作一个可导入的模块。我希望这对某些人有所帮助:


def subnet_lookup(subnet: str, netmask: str, ip_address: str):
"""
:param subnet: subnet to test against (as string)
:param netmask: mask of subnet
:param ip_address: ip to test against subnet and mask


:return True if a match; False if not a match


Steps:


1) convert entire subnet into one binary word
2) convert entire mask into one binary word
3) determine bcast from comparing subnet and mask
4) convert entire ip_address into one binary word
5) convert entire subnet into decimal
6) convert entire bcast into decimal
7) convert entire ip_address into decimal
8) determine if ip_address falls between subnet and bcast using range(); returns True if yes, False if no
"""


def convert_whole_to_bin(whole):
ip_dec_list = whole.split(".")
ip_bin_str = ""


for ip in ip_dec_list:
binary = dec_to_bin(int(ip))
ip_bin_str += binary


return ip_bin_str


def dec_to_bin(decimal_octet: int):
binary = bin(decimal_octet).replace("0b", "")


return binary.rjust(8, '0')


def split_binary_into_list(binary_octet: str):
bin_list = []
for s in binary_octet:
bin_list.append(s)


return bin_list


def determine_bcast(subnet, netmask):
subnet_split = split_binary_into_list(subnet)
netmask_split = split_binary_into_list(netmask)
bcast_list = []


for subnet, mask in zip(subnet_split, netmask_split):
if mask != '0':
bcast_list.append(subnet)


else:
bcast_list.append('1')


bcast_bin = "".join(bcast_list)


return bcast_bin


def bin_to_dec(binary_single_word: str):
decimal = int(binary_single_word, 2)


return decimal


def subnet_lookup(ip_address, subnet, bcast):


return ip_address in range(subnet, bcast + 1)


# 1) convert entire subnet into one binary word
subnet_single_bin = convert_whole_to_bin(whole=subnet)


# 2) convert entire mask into one binary word
mask_single_bin = convert_whole_to_bin(whole=netmask)


# 3) determine bcast from comparing subnet and mask
bcast_single_bin = determine_bcast(subnet=subnet_single_bin, netmask=mask_single_bin)


# 4) convert entire ip_address into one binary word
ip_address_single_bin = convert_whole_to_bin(whole=ip_address)


# 5) convert entire subnet into decimal
subnet_single_dec = bin_to_dec(binary_single_word=subnet_single_bin)


# 6) convert entire bcast into decimal
bcast_single_dec = bin_to_dec(binary_single_word=bcast_single_bin)


# 7) convert entire ip_address into decimal
ip_address_single_dec = bin_to_dec(binary_single_word=ip_address_single_bin)


# 8) determine if ip_address falls between subnet and bcast; returns True if yes, False if no
lookup_result = subnet_lookup(ip_address=ip_address_single_dec, subnet=subnet_single_dec, bcast=bcast_single_dec)


return lookup_result




# Testing:


subnet = "172.16.0.0"
netmask = "255.255.0.0"
ip_address = "172.16.255.255"


result = subnet_lookup(subnet=subnet, netmask=netmask, ip_address=ip_address)


print(result)