给定一个IP地址(比如192.168.0.1),如何在Python中检查它是否在网络中(比如192.168.0.0/24)?
Python中是否有用于ip地址操作的通用工具?像主机查找,ip adddress到int,网络地址与netmask到int等等?希望在2.5的标准Python库中.
我喜欢使用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!"
使用ipaddress(在3.3以后的stdlib中,在PyPi中为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
本文展示了您可以使用socket
和struct
模块完成它而无需太多额外的工作.我在文章中加了一点如下:
import socket,struct def makeMask(n): "return a mask of n bits as a long integer" return (2L<这输出:
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<
注意:这个解决方案有一个严重的错误:`addressInNetwork('172.7.1.1','172.3.0.0/16') - > True`
我认为你的解决方案有一个严重的错误:`addressInNetwork('172.7.1.1','172.3.0.0/16') - > True`(我在我的64位操作系统中将'L'转换为'此外,struct.unpack('L',socket.inet_aton(ip))[0]将在体系结构上失败,其中'L'解包为不同于4字节的内容,而不管字节顺序如何.
继续Rafal的评论,为了让它在64位Python解释器上工作,用以下命令替换该行:`return struct.unpack('我想这里可能存在大的和小的端点问题,但由于网络和IP地址解析都发生在同一台计算机上,因此这两个数字应该具有相同的错误,并且至少在相同的字节顺序中.
请注意,这不适用于IPv6地址.
这个答案有一个*bug*.见答案:http://stackoverflow.com/questions/819355/how-can-i-check-if-an-ip-is-in-a-network-in-python/23230273#23230273
AFAIK inet_aton默认为网络字节顺序,这是大端.事实上,你的代码依赖于inet_aton,它具有与系统1相反的字节序*,因此ip地址的第一个字节(例如"10.0.0.0"中的10)与掩码的最低有效字节对齐(例如0x000000ff中的0xff) .
4> okwap..:对于python3
In [64]: ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/24') Out[64]: False
5> Sean Reifsch..:这段代码在Linux x86上适用于我.我没有真正考虑过endianess问题,但我已经针对"ipaddr"模块测试了它,使用针对8个不同网络字符串测试的超过200K IP地址,并且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
6> 小智..:我尝试过Dave Webb的解决方案,但遇到了一些问题:
最根本的是 - 应通过使用掩码对IP地址进行AND运算来检查匹配,然后检查结果与网络地址完全匹配.没有使用网络地址与IP地址进行AND运算.
我还注意到,只是忽略Endian行为,假设一致性将保存您将只适用于八位字节边界(/ 24,/ 16)上的掩码.为了使其他掩码(/ 23,/ 21)正常工作,我在struct命令中添加了"大于",并将创建二进制掩码的代码更改为以"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
7> Landon..:我不喜欢在不需要时使用模块.这项工作只需要简单的数学,所以这是我完成这项工作的简单功能:
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)就是这样,这比包含模块的上述解决方案快得多.
8> 小智..:接受的答案不起作用......这让我很生气.掩码是向后的,不适用于任何不是简单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]例如: