在 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()) 产生PRIVATEprint(IP('::1').iptype()) 产生 LOOPBACKprint(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 地址是不是是私有的?的主要内容,如果未能解决你的问题,请参考以下文章

C# - 确定 IP 地址范围是不是包含特定地址

当我有多个 NIC 时,如何确定我的所有 IP 地址?

如何在节点中确定用户的IP地址

如何在节点中确定用户的IP地址

如何把IP转换成经纬度

python如何使用字符串比较来判断ip地址是不是为多播? [复制]