如何在Python中检查IP地址(比如192.168.0.1)是否属于某个网络(比如192.168.0.0/24)?
在Python中是否有一些常规工具用于IP地址的操作,例如主机查找、将IP地址转换为整数、将带有子网掩码的网络地址转换成整数等等?希望这些工具能够在Python 2.5标准库中找到。
如何在Python中检查IP地址(比如192.168.0.1)是否属于某个网络(比如192.168.0.0/24)?
在Python中是否有一些常规工具用于IP地址的操作,例如主机查找、将IP地址转换为整数、将带有子网掩码的网络地址转换成整数等等?希望这些工具能够在Python 2.5标准库中找到。
使用 ipaddress (自Python 3.3起在标准库中可用, 在PyPi上可用于2.6/2.7版本):
>>> import ipaddress
>>> ipaddress.ip_address('192.168.0.1') in ipaddress.ip_network('192.168.0.0/24')
True
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
ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24')
。 - Moondoggy__contains__
方法,通过比较网络和广播地址的整数表示来以高效的方式执行此操作,因此请放心,如果这是您的担忧。 - avatarofhope2ipaddress
中的 overlaps
方法,例如:ipaddress.ip_network('192.168.0.16/28').overlaps(ipaddress.ip_network('192.168.0.0/24'))
。 - trebor我喜欢使用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!"
- user221014netaddr.all_matching_cidrs("192.168.0.1", ["192.168.0.0/24","212.11.64.0/19"] ) [IPNetwork('192.168.0.0/24')]
适用于Python 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 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}")))
你可以将IP地址看作是带有最大可能子网掩码的网络(对于IPv4为/32
,IPv6为/128
)
检查192.168.0.1
是否在192.168.0.0/16
中,本质上与检查192.168.0.1/32
是否为192.168.0.0/16
的子网相同。
if IPv4Address('192.0.2.6') in IPv4Network('192.0.2.0/28')
- benzkji这篇文章展示了如何使用socket
和struct
模块,不需要太多额外的努力即可实现。我在文章中添加了以下内容:
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
return struct.unpack('<L',socket.inet_aton(ip))[0]
。 - nitwitaddressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
(在我的64位操作系统中,我将'L'转换为'<L') - Taha Jahangir这段代码在我的Linux x86系统上运行良好。我没有考虑过字节顺序问题,但我已经使用超过200K个IP地址对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
在可能的情况下,我建议使用内置的ipaddress模块。虽然它只能在Python 3中使用,但它非常容易使用并支持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]
例如:
我不太喜欢在没有必要的情况下使用模块。这项工作只需要进行简单的数学计算,因此这里是我的简单函数来完成任务:
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)
{TypeError}'map' object is not subscriptable
. You need a o = list(o)
after o = map(int, ip.split('.'))
- gies0r在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)
我尝试了Dave Webb的解决方案,但遇到了一些问题:
最根本的是-应该通过将IP地址与掩码进行AND运算来检查匹配,然后检查结果是否与网络地址完全匹配。而不是像以前那样将IP地址与网络地址进行AND运算。
我还注意到,仅仅忽略字节序的行为,假设一致性会使你免受困扰,只适用于八位边界(/24,/16)的掩码。为了让其他掩码(/23,/21)正常工作,我在结构命令中添加了“大于”并更改了创建二进制掩码的代码,从所有“1”开始,并向左移动(32-mask)。
最后,我添加了一个简单的检查,确保网络地址对于掩码是有效的,如果无效就打印一个警告。
以下是结果:
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