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

Question:

In Python, what is the best way to determine if an IP address (e.g., '127.0.0.1' or '10.98.76.6') is on a private network? 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?

Asked By: Jacob Gabrielson

||

Answers:

Check out the IPy module. If has a function iptype() that seems to do what you want:

>>> from IPy import IP
>>> ip = IP('127.0.0.0/30')
>>> ip.iptype()
'PRIVATE'
Answered By: Paolo Bergantino

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}$
  • ^10.d{1,3}.d{1,3}.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}$
Answered By: Kurt

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). Apparently this will be standard in Python 3.1.

Answered By: Jacob Gabrielson

You can check that yourself using
https://www.rfc-editor.org/rfc/rfc1918 and https://www.rfc-editor.org/rfc/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. So using inet_pton you can do: 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   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

another implementation is to compute the int values of all private blocks:

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"
Answered By: jackdoe

This is the fixed version of the regex approach suggested by @Kurt including the fix recommended by @RobEvans

  • ^127.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}$

  • ^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.x.x.x range which is used internally in kubernetes

Answered By: Tk421

Since Python 3.3 there is an ipaddress module in the stdlib that you can use.

>>> 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.

Answered By: Nik Haldimann

I find this in cuckoo.There is no need to install new modules.Just import two built-in modules: socket and 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
Answered By: jojo1776568