简体   繁体   English

在 Python 中,您如何确定 IP 地址是否是私有的?

[英]How do you determine if an IP address is private, in Python?

In Python, what is the best way to determine if an IP address (eg, '127.0.0.1' or '10.98.76.6' ) is on a private network ?在 Python 中,确定 IP 地址(例如'127.0.0.1''10.98.76.6' )是否在专用网络上的最佳方法是什么? The code does not sound difficult to write.代码听起来并不难写。 But there may be more edge cases than are immediately apparent, and there's IPv6 support to consider, etc. Is there an existing library that does it?但是可能存在比立即显而易见的更多边缘情况,并且需要考虑 IPv6 支持等。是否有现有的库可以做到这一点?

Since Python 3.3 there is an ipaddress module in the stdlib that you can use.从 Python 3.3 开始,您可以使用 stdlib 中的ipaddress 模块

>>> import ipaddress
>>> ipaddress.ip_address('192.168.0.1').is_private
True

If using Python 2.6 or higher I would strongly recommend to use a backport of this module .如果使用 Python 2.6 或更高版本,我强烈建议使用此模块的反向移植

Check out the IPy module.查看IPy模块。 If has a function iptype() that seems to do what you want:如果有一个函数iptype()似乎可以执行您想要的操作:

>>> from IPy import IP
>>> ip = IP('127.0.0.0/30')
>>> ip.iptype()
'PRIVATE'

You can check that yourself using http://tools.ietf.org/html/rfc1918 and http://tools.ietf.org/html/rfc3330 .您可以使用http://tools.ietf.org/html/rfc1918http://tools.ietf.org/html/rfc3330 自行检查。 If you have 127.0.0.1 you just need to & it with the mask (lets say 255.0.0.0 ) and see if the value matches any of the private network's network address .如果你有 127.0.0.1 你只需要&它与掩码(假设255.0.0.0 )并查看该值是否与任何专用网络的网络地址匹配。 So using inet_pton you can do: 127.0.0.1 & 255.0.0.0 = 127.0.0.0所以使用inet_pton你可以做到: 127.0.0.1 & 255.0.0.0 = 127.0.0.0

Here is the code that illustrates that:这是说明这一点的代码:

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   http://tools.ietf.org/html/rfc3330
        [ 3232235520, 4294901760 ], # 192.168.0.0, 255.255.0.0 http://tools.ietf.org/html/rfc1918
        [ 2886729728, 4293918720 ], # 172.16.0.0,  255.240.0.0 http://tools.ietf.org/html/rfc1918
        [ 167772160,  4278190080 ], # 10.0.0.0,    255.0.0.0   http://tools.ietf.org/html/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

another implementation is to compute the int values of all private blocks:另一种实现是计算所有私有块的 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"

This is the fixed version of the regex approach suggested by @Kurt including the fix recommended by @RobEvans这是@Kurt 建议的正则表达式方法的固定版本,包括@RobEvans 建议的修复

  • ^127.\\d{1,3}.\\d{1,3}.\\d{1,3}$ ^127.\\d{1,3}.\\d{1,3}.\\d{1,3}$

  • ^10.\\d{1,3}.\\d{1,3}.\\d{1,3}$ ^10.\\d{1,3}.\\d{1,3}.\\d{1,3}$

  • ^192.168.\\d{1,3}.\\d{1,3}$ ^192.168.\\d{1,3}.\\d{1,3}$

  • ^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,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\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$") priv_24 = re.compile("^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$") priv_20 = re.compile("^192\\.168\\.\\d{1,3}.\\d{1,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

This will not 100.xxx range which is used internally in kubernetes这不会是 kubernetes 内部使用的 100.xxx 范围

I find this in cuckoo .There is no need to install new modules.Just import two built-in modules: socket and struct.我在cuckoo 中找到了这个。不需要安装新模块。只需导入两个内置模块:socket 和 struct。 And use function below.并使用下面的功能。

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

A few days after asking this question, I found out about this Google project, ipaddr-py , which appears to have some of the same functionality with respect to determining if an address is private ( is_rfc1918 ).问这个问题几天后,我发现了这个谷歌项目ipaddr-py ,它似乎具有一些相同的功能,用于确定地址是否是私有的( is_rfc1918 )。 Apparently this will be standard in Python 3.1.显然,这将是 Python 3.1 的标准。

If you want to avoid importing a module you can just apply a simple regex:如果你想避免导入一个模块,你可以应用一个简单的正则表达式:

  • ^127.\\d{1,3}.\\d{1,3}.\\d{1,3}$ ^127.\\d{1,3}.\\d{1,3}.\\d{1,3}$
  • ^10.\\d{1,3}.\\d{1,3}.\\d{1,3}$ ^10.\\d{1,3}.\\d{1,3}.\\d{1,3}$
  • ^192.168.\\d{1,3}$ ^192.168.\\d{1,3}$
  • ^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$ ^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM