python netaddr找到最接近的IP地址匹配

时间:2014-11-25 00:54:18

标签: python inetaddress

如何使用python netaddr找到最接近匹配的相同前缀?

>>> l = ['172.27.145.130/25', '172.27.145.129/25', '172.27.145.131/25']
>>> myip = '172.27.145.129'
>>> netaddr.IPAddress(myip) in netaddr.IPNetwork(l[0])
True
>>> netaddr.IPAddress(myip) in netaddr.IPNetwork(l[1])
True
>>> netaddr.IPAddress(myip) in netaddr.IPNetwork(l[2])
True
>>>

1 个答案:

答案 0 :(得分:1)

你似乎错过了一个关键点:你说"所有三个ip子网都是同一网络的一部分172.27.145.128/25"但这不是真的;所有这些 相同的网络,只是不同的非标准名称。这就是IP网络的工作方式:对于N比特网络,基地址的最后N位并不重要。因此,没有办法将它们相互对比,并挑出哪一个是最长的"或者"最近的"或任何其他类型的比赛,因为它们都将完全相同。

您可能认为这些是接口,而不是网络。接口在网络中具有地址 - 例如,网络172.27.145.130中的地址172.27.145.128/25。您可以使用速记127.27.145.130/25指定。是的,界面的简写形式与网络的速记形式相同,但它们不是一回事。

如果您仍然无法区分地址,网络和界面,那么3.3 + Python文档会有很棒的HOWTO

虽然netaddr对接口没有任何支持,但是对于Python 2.6-2.7,stdlib的ipaddress和第三方ipaddress反向支持。例如:

>>> l = ['172.27.145.130/25', '172.27.145.129/25', '172.27.145.131/25']
>>> interfaces = [ipaddress.ip_interface(x) for x in l]
>>> interfaces[0]
IPv4Interface('172.27.145.130/25')
>>> interfaces[0].ip, interfaces[0].network
(IPv4Address('172.27.145.130'), IPv4Network('172.27.145.128/25'))

那么,也许您要问的是哪个接口与给定地址共享的位数最多? (我仍然不确定这是不是你的意思"最接近的匹配"或者"最长的匹配",但这似乎是一个合理的猜测。)

这仍然是一个含糊不清的问题。您可能要么询问哪个接口的地址共享更多位周期,要么在哪个共享子网内共享更多位。但由于他们都在同一个子网中,这并不重要。

这意味着我们甚至可以将netaddr网络对象用作ersatz接口对象(尽管如此,您最好使用ipaddress或其他实际支持接口对象的库)

所以:

>>> l = ['172.27.145.130/25', '172.27.145.129/25', '172.27.145.131/25']
>>> interfaces = [netaddr.IPNetwork(interface) for interface in l]
>>> addresses = [interface.ip for interface in interfaces]
>>> bits = [address.bits() for address in addresses]
>>> bits
['10101100.00011011.10010001.10000010',
 '10101100.00011011.10010001.10000001',
 '10101100.00011011.10010001.10000011']
>>> myip = '172.27.145.129'
>>> myaddress = netaddr.IPAddress(myip)
>>> mybits = myaddress.bits()
'10101100.00011011.10010001.10000001'

(显然你可以将大部分步骤合并在一起,所以整个过程只有两三行。)

现在我们只是比较字符串。

但是netaddr.IPAddress也有一个&运算符,所以我们可以让它变得更简单:

>>> common_bits = [(address & myaddress).bits() for address in addresses]
>>> common_bits
['10101100.00011011.10010001.10000000',
 '10101100.00011011.10010001.10000001',
 '10101100.00011011.10010001.10000001']
>>> common_bit_counts = [bits.count('1') for bits in common_bits]
>>> common_bit_counts
[12, 13, 13]

还有其他方法可以解决这个问题。例如,每个value的{​​{1}}是一个32位的int,所以你可以和那些一起在数字上计算比特而不是字符串。但希望这能明确地显示出来。