在 Python 中,如何确定 IP 地址是不是是私有的?
Posted
技术标签:
【中文标题】在 Python 中,如何确定 IP 地址是不是是私有的?【英文标题】:How do you determine if an IP address is private, in Python?在 Python 中,如何确定 IP 地址是否是私有的? 【发布时间】:2010-10-16 00:25:37 【问题描述】:在 Python 中,确定 IP 地址(例如,'127.0.0.1'
或 '10.98.76.6'
)是否在 private network 上的最佳方法是什么?代码听起来并不难写。但是可能存在比立即明显更多的边缘情况,并且需要考虑 IPv6 支持等。是否有现有的库可以做到这一点?
【问题讨论】:
【参考方案1】:从 Python 3.3 开始,您可以使用标准库中的 ipaddress module。
>>> import ipaddress
>>> ipaddress.ip_address('192.168.0.1').is_private
True
如果使用 Python 2.6 或更高版本,我强烈建议使用a backport of this module。
【讨论】:
【参考方案2】:查看IPy 模块。如果有一个函数iptype()
似乎可以做你想做的事:
>>> from IPy import IP
>>> ip = IP('127.0.0.0/30')
>>> ip.iptype()
'PRIVATE'
【讨论】:
正如对公共 IP 的预期,字符串是“PUBLIC”。有一些意想不到的结果:print(IP('127.0.0.1').iptype())
产生PRIVATE
。 print(IP('::1').iptype())
产生 LOOPBACK
。 print(IP('2001:0658:022a:cafe:0200::1').iptype())
产生 ALLOCATED RIPE NCC
确实有一些意想不到的结果:print(IP('0.0.0.0/0').iptype())
产生“PRIVATE”,而我希望“整个 IPv4 互联网”是 PUBLIC...
我应该用它来预防s-s-rF吗?
你打算如何使用它来防止 s-s-rF ?【参考方案3】:
您可以使用
https://www.rfc-editor.org/rfc/rfc1918 和 https://www.rfc-editor.org/rfc/rfc3330。如果你有 127.0.0.1,你只需要用掩码 &
它(比如说255.0.0.0
),看看该值是否与任何专用网络的network address 匹配。所以使用inet_pton 你可以这样做:127.0.0.1 & 255.0.0.0 = 127.0.0.0
下面的代码说明了这一点:
from struct import unpack
from socket import AF_INET, inet_pton
def lookup(ip):
f = unpack('!I',inet_pton(AF_INET,ip))[0]
private = (
[ 2130706432, 4278190080 ], # 127.0.0.0, 255.0.0.0 https://www.rfc-editor.org/rfc/rfc3330
[ 3232235520, 4294901760 ], # 192.168.0.0, 255.255.0.0 https://www.rfc-editor.org/rfc/rfc1918
[ 2886729728, 4293918720 ], # 172.16.0.0, 255.240.0.0 https://www.rfc-editor.org/rfc/rfc1918
[ 167772160, 4278190080 ], # 10.0.0.0, 255.0.0.0 https://www.rfc-editor.org/rfc/rfc1918
)
for net in private:
if (f & net[1]) == net[0]:
return True
return False
# example
print(lookup("127.0.0.1"))
print(lookup("192.168.10.1"))
print(lookup("10.10.10.10"))
print(lookup("172.17.255.255"))
# outputs True True True True
另一种实现是计算所有私有块的 int 值:
from struct import unpack
from socket import AF_INET, inet_pton
lookup = "127.0.0.1"
f = unpack('!I',inet_pton(AF_INET,lookup))[0]
private = (["127.0.0.0","255.0.0.0"],["192.168.0.0","255.255.0.0"],["172.16.0.0","255.240.0.0"],["10.0.0.0","255.0.0.0"])
for net in private:
mask = unpack('!I',inet_aton(net[1]))[0]
p = unpack('!I',inet_aton(net[0]))[0]
if (f & mask) == p:
print lookup + " is private"
【讨论】:
【参考方案4】:这是@Kurt 建议的正则表达式方法的固定版本,包括@RobEvans 推荐的修复方法
^127.\d1,3.\d1,3.\d1,3$
^10.\d1,3.\d1,3.\d1,3$
^192.168.\d1,3.\d1,3$
^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]1,3.[0-9]1,3 $
def is_ip_private(ip):
# https://en.wikipedia.org/wiki/Private_network
priv_lo = re.compile("^127\.\d1,3\.\d1,3\.\d1,3$")
priv_24 = re.compile("^10\.\d1,3\.\d1,3\.\d1,3$")
priv_20 = re.compile("^192\.168\.\d1,3.\d1,3$")
priv_16 = re.compile("^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]1,3.[0-9]1,3$")
res = priv_lo.match(ip) or priv_24.match(ip) or priv_20.match(ip) or priv_16.match(ip)
return res is not None
这不会是 kubernetes 内部使用的 100.x.x.x 范围
【讨论】:
+1,我建议返回一个布尔“包装器”,以更好地反映函数名称:return (priv_lo.match(ip) or priv_24.match(ip) or priv_20.match(ip ) 或 priv_16.match(ip)) 不是无【参考方案5】:在问了这个问题几天后,我发现了这个 Google 项目 ipaddr-py,它在确定地址是否为私有 (is_rfc1918
) 方面似乎具有一些相同的功能。显然这将成为 Python 3.1 中的标准。
【讨论】:
现在在 3.3 中是临时的,参见 [ipaddress][1] 模块。 [1]:docs.python.org/3.3/library/ipaddress.html 查看“is_private”属性。【参考方案6】:我在cuckoo找到这个。不需要安装新模块。只需导入两个内置模块:socket和struct。并使用下面的函数。
def _is_private_ip(self, ip):
"""Check if the IP belongs to private network blocks.
@param ip: IP address to verify.
@return: boolean representing whether the IP belongs or not to
a private network block.
"""
networks = [
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.88.99.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"240.0.0.0/4",
"255.255.255.255/32",
"224.0.0.0/4",
]
for network in networks:
try:
ipaddr = struct.unpack(">I", socket.inet_aton(ip))[0]
netaddr, bits = network.split("/")
network_low = struct.unpack(">I", socket.inet_aton(netaddr))[0]
network_high = network_low | 1 << (32 - int(bits)) - 1
if ipaddr <= network_high and ipaddr >= network_low:
return True
except Exception,err:
continue
return False
【讨论】:
此检查失败示例如果 ip : 172.29.0.1【参考方案7】:如果你想避免导入一个模块,你可以应用一个简单的正则表达式:
^127.\d1,3.\d1,3.\d1,3$ ^10.\d1,3.\d1,3.\d1,3$ ^192.168.\d1,3$ ^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]1,3.[0-9]1,3 $【讨论】:
不应该是那些。字符通过 \ 转义。 ?我猜这个模式仍然可以工作。 那个正则表达式对我不起作用,但如果你用 1,3 替换 123 就可以了。 我不同意 - 它可能有效,但并不简单。如果我查看所有这些特殊字符等,据我所知,“简单”一词不适用于该正则表达式……您能否阅读,快速记住它并在不看它的情况下再次写下来(并且不重构根据您应用的规则)?如果有什么问题/改变了,你能一眼看出吗?所以,恕我直言,是的,如果您有原因或限制使添加外部代码成为不可能/不需要的,它可以工作,但它是一个复杂且难以调试/理解/记忆/验证的表达式。以上是关于在 Python 中,如何确定 IP 地址是不是是私有的?的主要内容,如果未能解决你的问题,请参考以下文章