Sta*_*ale 88 python networking ip-address cidr
给定一个IP地址(比如192.168.0.1),如何在Python中检查它是否在网络中(比如192.168.0.0/24)?
Python中是否有用于ip地址操作的通用工具?像主机查找,ip adddress到int,网络地址与netmask到int等等?希望在2.5的标准Python库中.
nos*_*klo 146
我喜欢使用netaddr:
from netaddr import CIDR, IP
if IP("192.168.0.1") in CIDR("192.168.0.0/24"):
print "Yay!"
Run Code Online (Sandbox Code Playgroud)
正如arno_v在评论中指出的那样,netaddr的新版本是这样的:
from netaddr import IPNetwork, IPAddress
if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"):
print "Yay!"
Run Code Online (Sandbox Code Playgroud)
phi*_*hag 114
使用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
Run Code Online (Sandbox Code Playgroud)
如果你想以这种方式评估很多 IP地址,你可能想要预先计算网络掩码,比如
n = ipaddress.ip_network('192.0.0.0/16')
netw = int(n.network_address)
mask = int(n.netmask)
Run Code Online (Sandbox Code Playgroud)
然后,对于每个地址,用其中一个计算二进制表示
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
Run Code Online (Sandbox Code Playgroud)
最后,您只需检查:
in_network = (a & mask) == netw
Run Code Online (Sandbox Code Playgroud)
Dav*_*ebb 34
本文展示了您可以使用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)
Run Code Online (Sandbox Code Playgroud)
这输出:
False
True
Run Code Online (Sandbox Code Playgroud)
如果你只想要一个带字符串的函数,它将如下所示:
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
Run Code Online (Sandbox Code Playgroud)
roc*_*cer 15
使用 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}")))
Run Code Online (Sandbox Code Playgroud)
你可以把的IP地址作为网络具有最大可能子网掩码(/32对于IPv4,/128IPv6的)
检查是否192.168.0.1在192.168.0.0/16本质上与检查是否192.168.0.1/32是192.168.0.0/16
okw*_*wap 10
对于python3
In [64]: ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/24')
Out[64]: False
Run Code Online (Sandbox Code Playgroud)
这段代码在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)
Run Code Online (Sandbox Code Playgroud)
例:
>>> print addressInNetwork('10.9.8.7', '10.9.1.0/16')
True
>>> print addressInNetwork('10.9.8.7', '10.9.1.0/24')
False
Run Code Online (Sandbox Code Playgroud)
小智 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
Run Code Online (Sandbox Code Playgroud)
不在 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)
Run Code Online (Sandbox Code Playgroud)
我不喜欢在不需要时使用模块.这项工作只需要简单的数学,所以这是我完成这项工作的简单功能:
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
Run Code Online (Sandbox Code Playgroud)
然后使用它:
>>> 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)
Run Code Online (Sandbox Code Playgroud)
就是这样,这比包含模块的上述解决方案快得多.
小智 5
接受的答案不起作用......这让我很生气.掩码是向后的,不适用于任何不是简单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
Run Code Online (Sandbox Code Playgroud)
这是一个返回虚线二进制字符串的函数,以帮助可视化屏蔽......有点像ipcalc输出.
def bb(i):
def s = '{:032b}'.format(i)
def return s[0:8]+"."+s[8:16]+"."+s[16:24]+"."+s[24:32]
Run Code Online (Sandbox Code Playgroud)
例如:

从 Python 3.7 开始,您可以使用subnet_of和supernet_of辅助方法,它们是标准库的一部分:
要仅针对单个 IP 进行测试,您可以仅使用子网掩码/32(这意味着“仅此 IP 地址”)作为子网,或者您可以将 IP 地址传递给IPv4Nework或IPv6Nework构造函数,它们将为您返回子网值。
所以对于你的例子:
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
Run Code Online (Sandbox Code Playgroud)
Python 中有用于 ip 地址操作的通用工具吗?像主机查找、IP 地址转为 int、网络地址和网络掩码转为 int 之类的东西?希望在 2.5 的标准 Python 库中。
在 Python 3 中,有一个ipaddress模块包含用于 IPv4 和 IPv6 操作的工具。您可以通过强制转换将它们转换为 int,即int(IPv4Address('192.168.0.1'))。ipaddress主机模块中还有许多其他有用的功能等。