Python's ipaddress module provides tools for working with IPv4 and IPv6 addresses and networks. It handles validation, comparison, and network calculations without regex or manual parsing.

IP Addresses

from ipaddress import ip_address
 
# Create from string
addr = ip_address('192.168.1.1')
print(addr)           # 192.168.1.1
print(addr.version)   # 4
 
# IPv6
addr6 = ip_address('2001:db8::1')
print(addr6.version)  # 6
 
# From integer
addr = ip_address(3232235777)  # 192.168.1.1

Address Properties

from ipaddress import ip_address
 
addr = ip_address('192.168.1.1')
 
print(addr.is_private)      # True
print(addr.is_global)       # False
print(addr.is_loopback)     # False
print(addr.is_multicast)    # False
print(addr.is_reserved)     # False
print(addr.is_link_local)   # False
 
# Loopback
loopback = ip_address('127.0.0.1')
print(loopback.is_loopback)  # True
 
# Public IP
public = ip_address('8.8.8.8')
print(public.is_global)  # True

IP Networks

from ipaddress import ip_network
 
# Create a network
net = ip_network('192.168.1.0/24')
 
print(net.network_address)   # 192.168.1.0
print(net.broadcast_address) # 192.168.1.255
print(net.netmask)          # 255.255.255.0
print(net.hostmask)         # 0.0.0.255
print(net.num_addresses)    # 256
print(net.prefixlen)        # 24

Iterating Over Hosts

from ipaddress import ip_network
 
net = ip_network('192.168.1.0/28')
 
# All addresses (including network and broadcast)
for addr in net:
    print(addr)
 
# Only usable host addresses
for host in net.hosts():
    print(host)
# 192.168.1.1 through 192.168.1.14

Network Membership

from ipaddress import ip_address, ip_network
 
net = ip_network('10.0.0.0/8')
 
print(ip_address('10.1.2.3') in net)   # True
print(ip_address('192.168.1.1') in net) # False

IP Interfaces

Combine address and network info:

from ipaddress import ip_interface
 
iface = ip_interface('192.168.1.5/24')
 
print(iface.ip)       # 192.168.1.5
print(iface.network)  # 192.168.1.0/24
print(iface.netmask)  # 255.255.255.0

Network Operations

from ipaddress import ip_network
 
net = ip_network('192.168.0.0/16')
 
# Subnetting
subnets = list(net.subnets(prefixlen_diff=8))
print(subnets)  # 256 /24 networks
 
# Supernetting
net1 = ip_network('192.168.0.0/24')
net2 = ip_network('192.168.1.0/24')
supernet = net1.supernet()
print(supernet)  # 192.168.0.0/23
 
# Overlaps
print(net1.overlaps(net2))  # False
print(net1.overlaps(ip_network('192.168.0.0/25')))  # True

Address Arithmetic

from ipaddress import ip_address
 
addr = ip_address('192.168.1.1')
 
# Increment/decrement
print(addr + 1)   # 192.168.1.2
print(addr + 10)  # 192.168.1.11
print(addr - 1)   # 192.168.1.0
 
# Comparison
print(ip_address('10.0.0.1') < ip_address('10.0.0.2'))  # True

IPv6

from ipaddress import ip_address, ip_network
 
# IPv6 addresses
addr = ip_address('2001:db8::1')
print(addr.exploded)    # 2001:0db8:0000:0000:0000:0000:0000:0001
print(addr.compressed)  # 2001:db8::1
 
# IPv6 network
net = ip_network('2001:db8::/32')
print(net.num_addresses)  # 79228162514264337593543950336
 
# IPv4-mapped IPv6
mapped = ip_address('::ffff:192.168.1.1')
print(mapped.ipv4_mapped)  # 192.168.1.1

Validation

from ipaddress import ip_address, ip_network
 
def is_valid_ip(s):
    try:
        ip_address(s)
        return True
    except ValueError:
        return False
 
print(is_valid_ip('192.168.1.1'))   # True
print(is_valid_ip('192.168.1.256')) # False
print(is_valid_ip('not an ip'))     # False
 
# Strict network validation
try:
    # This fails: host bits are set
    net = ip_network('192.168.1.5/24')
except ValueError as e:
    print(e)  # '192.168.1.5/24' has host bits set
 
# Allow host bits
net = ip_network('192.168.1.5/24', strict=False)
print(net)  # 192.168.1.0/24

Practical Examples

Firewall Rule Checker

from ipaddress import ip_address, ip_network
 
allowed_networks = [
    ip_network('10.0.0.0/8'),
    ip_network('192.168.0.0/16'),
]
 
def is_allowed(ip_str):
    try:
        addr = ip_address(ip_str)
        return any(addr in net for net in allowed_networks)
    except ValueError:
        return False
 
print(is_allowed('10.1.2.3'))     # True
print(is_allowed('8.8.8.8'))       # False

Subnet Calculator

from ipaddress import ip_network
 
def subnet_info(cidr):
    net = ip_network(cidr, strict=False)
    return {
        'network': str(net.network_address),
        'broadcast': str(net.broadcast_address),
        'netmask': str(net.netmask),
        'hosts': net.num_addresses - 2,
        'range': f"{net[1]} - {net[-2]}"
    }
 
print(subnet_info('192.168.1.0/24'))

IP Range Generator

from ipaddress import ip_address
 
def ip_range(start, end):
    start = ip_address(start)
    end = ip_address(end)
    while start <= end:
        yield start
        start += 1
 
for ip in ip_range('192.168.1.1', '192.168.1.5'):
    print(ip)

Summary

The ipaddress module handles IP addresses elegantly:

  • ip_address() for individual addresses
  • ip_network() for networks/subnets
  • ip_interface() for address + network
  • Built-in validation, comparison, and arithmetic
  • Full IPv4 and IPv6 support

No more regex for IP validation—use this.

React to this post: