Подтвердить что ты не робот

Как определить, является ли IP-адрес приватным, в Python?

В Python лучший способ определить, находится ли IP-адрес (например, '127.0.0.1' или '10.98.76.6') в частной сети ? Код не кажется сложным для записи. Но может быть больше случаев с краями, чем сразу видно, и поддержка IPv6 для рассмотрения и т.д. Есть ли существующая библиотека, которая это делает?

4b9b3361

Ответ 1

Проверьте модуль IPy. Если имеет функцию iptype(), которая, похоже, делает то, что вы хотите:

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

Ответ 2

Так как Python 3.3 содержит модуль ipaddress в stdlib, который вы можете использовать.

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

Если вы используете Python 2.6 или выше, я настоятельно рекомендую использовать backport этого модуля.

Ответ 3

Вы можете проверить, что вы используете http://tools.ietf.org/html/rfc1918 и http://tools.ietf.org/html/rfc3330. Если у вас есть 127.0.0.1, вам просто нужно & с помощью маски (скажем, 255.0.0.0) и посмотреть, соответствует ли значение какой-либо частной сети сетевой адрес. Поэтому, используя 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   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

Другая реализация заключается в вычислении значений 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.\d {1,3}.\d {1,3}.\d {1,3} $
  • ^ 10.\Д {1,3}.\Д {1,3}.\Д {1,3} $
  • ^ 192.168.\Д {1,3}.\Д {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
    

Ответ 5

Через несколько дней после запроса этого вопроса я узнал об этом проекте Google, ipaddr-py, который, как представляется, имеет некоторые из одинаковая функциональность в отношении определения того, является ли адрес приватным (is_rfc1918). По-видимому, это будет стандартным для Python 3.1.

Ответ 6

Если вы хотите избежать импорта модуля, вы можете просто применить простое регулярное выражение:

  • ^ 127.\Д {1,3}.\Д {1,3}.\Д {1,3} $
  • ^ 10.\Д {1,3}.\Д {1,3}.\Д {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} $

Ответ 7

Я нахожу это в 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