Примеры использования ipaddress для администрирования сетей

Раздел: Администрирование -> Сетевое программирование

Работа с IP-адресами и сетями в Python: модуль ipaddress

Модуль ipaddress стандартной библиотеки Python предоставляет удобные инструменты для создания, проверки и манипуляции IP-адресами и подсетями. Он поддерживает обе версии протокола - IPv4 и IPv6. В статье рассматриваются основные классы, типовые задачи и примеры кода.

Основные классы и создание объектов

Модуль включает классы IPv4Address, IPv6Address, IPv4Network, IPv6Network, IPv4Interface, IPv6Interface. Для создания объекта достаточно передать строку с адресом или сетью:

import ipaddress

addr = ipaddress.IPv4Address('192.168.1.10')
net = ipaddress.IPv4Network('192.168.1.0/24', strict=False)
print(addr, net)
# 192.168.1.10 192.168.1.0/24

Python client py (клиент на python)

Если указать strict=True (по умолчанию), то сеть должна быть задана точным сетевым адресом (биты хоста равны нулю). При strict=False допускается любой адрес, ipaddress автоматически отбросит хостовую часть.

Как проверить, принадлежит ли IP-адрес сети?

Оператор in работает с объектами IPv4Network/IPv6Network:

net = ipaddress.IPv4Network('10.0.0.0/8')
addr = ipaddress.IPv4Address('10.1.2.3')
print(addr in net)  # True

Python socket (сокеты в python (socket))

Также доступны методы subnet_of и supernet_of для сравнения сетей:

net1 = ipaddress.IPv4Network('192.168.1.0/24')
net2 = ipaddress.IPv4Network('192.168.1.0/26')
print(net2.subnet_of(net1))  # True
print(net1.supernet_of(net2))  # True

Python ipaddress ip network (модуль ipaddress в python)

Типичная ошибка:

При использовании in с IPv6 и IPv4 может возникнуть TypeError из-за несовместимости протоколов. Всегда проверяйте версию адреса.

Как получить все IP-адреса из сети?

Метод hosts() возвращает генератор всех используемых адресов (исключая сетевой и широковещательный):

net = ipaddress.IPv4Network('192.168.0.0/29', strict=False)
for host in net.hosts():
    print(host)
# 192.168.0.1
# 192.168.0.2
# ...
# 192.168.0.6

Python сети (сетевые возможности python)

Чтобы включить все адреса, используйте iter(net) или list(net).

Как разбить сеть на подсети заданного префикса?

Метод subnets() возвращает генератор подсетей:

net = ipaddress.IPv4Network('10.0.0.0/24')
for subnet in net.subnets(new_prefix=26):
    print(subnet)
# 10.0.0.0/26
# 10.0.0.64/26
# 10.0.0.128/26
# 10.0.0.192/26

Python network programming (сетевое программирование на python)

Ошибка:

Если новый префикс меньше текущего (например, /30 на /24), возникнет ValueError. Допустимо только увеличение префикса (разбиение на более мелкие подсети).

Как получить сетевой и широковещательный адреса, маску?

У объекта сети есть атрибуты:

net = ipaddress.IPv4Network('192.168.1.128/25')
print(f"Network: {net.network_address}")   # 192.168.1.128
print(f"Broadcast: {net.broadcast_address}")  # 192.168.1.255
print(f"Netmask: {net.netmask}")            # 255.255.255.128
print(f"Prefixlen: {net.prefixlen}")      # 25

Ip network python (работа с ip-сетями в python)

Как работать с IPv6 адресами?

Классы для IPv6 работают аналогично:

v6net = ipaddress.IPv6Network('2001:db8::/32')
v6addr = ipaddress.IPv6Address('2001:db8::1')
print(v6addr in v6net)  # True
print(v6net.exploded)  # '2001:0db8:0000:0000:0000:0000:0000:0000'
print(v6net.compressed)  # '2001:db8::'

Как преобразовать объект обратно в строку или число?

Для адреса доступны атрибуты packed (бинарное представление) и exploded/compressed для IPv6:

addr = ipaddress.IPv4Address('10.0.0.1')
print(int(addr))       # 167772161
print(bytes(addr))     # b'\n\x00\x00\x01'

net = ipaddress.IPv4Network('10.0.0.0/24')
print(str(net))        # '10.0.0.0/24'

Частая проблема: при ручном вводе адресов может возникнуть ValueError: 'xxx' does not appear to be an IPv4 or IPv6 network. Решение - проверять формат. Также при использовании strict=False некоторые адреса с ненулевой хостовой частью будут приняты, но может потеряться информация.

Расширенные примеры использования модуля ipaddress

1. Вычисление общей сети (supernet) для списка подсетей

Функция collapse_addresses находит минимальный набор подсетей, покрывающий все заданные:

Пример
import ipaddress

def find_supernet(subnets_str):
    networks = [ipaddress.IPv4Network(s, strict=False) for s in subnets_str]
    collapsed = list(ipaddress.collapse_addresses(networks))
    return collapsed

subs = ['10.0.0.0/25', '10.0.0.128/25']
result = find_supernet(subs)
print([str(n) for n in result])
# ['10.0.0.0/24']
['10.0.0.0/24']

2. Проверка пересечения (overlap) двух сетей

Метод overlaps возвращает True, если сети имеют общие адреса:

Пример
net1 = ipaddress.IPv4Network('192.168.1.0/24')
net2 = ipaddress.IPv4Network('192.168.1.128/25')
print(net1.overlaps(net2))  # True
net3 = ipaddress.IPv4Network('10.0.0.0/8')
print(net1.overlaps(net3))  # False
True
False

3. Использование интерфейсов (IPv4Interface)

Класс IPv4Interface объединяет адрес и сеть. Позволяет получить маску, broadcast и т.д.:

Пример
iface = ipaddress.IPv4Interface('192.168.1.10/24')
print(f"IP: {iface.ip}")          # 192.168.1.10
print(f"Net: {iface.network}")    # 192.168.1.0/24
print(f"Broadcast: {iface.network.broadcast_address}")
# 192.168.1.255

# Извлечение адреса и сети отдельно
addr = iface.ip
net = iface.network
print(addr in net)  # True
IP: 192.168.1.10
Net: 192.168.1.0/24
Broadcast: 192.168.1.255
True

4. Работа с частными (private) и публичными адресами

Методы is_private, is_global, is_loopback и др.:

Пример
addr_priv = ipaddress.IPv4Address('10.0.0.5')
addr_pub = ipaddress.IPv4Address('8.8.8.8')
print(f"Private: {addr_priv.is_private}, Global: {addr_priv.is_global}")
print(f"Private: {addr_pub.is_private}, Global: {addr_pub.is_global}")

# Для сетей
net_priv = ipaddress.IPv4Network('172.16.0.0/12')
print(net_priv.is_private)  # True
Private: True, Global: False
Private: False, Global: True
True

5. Создание диапазона адресов и связка с другими модулями

Использование summarize_address_range для получения списка подсетей, покрывающих диапазон:

Пример
start = ipaddress.IPv4Address('192.168.0.0')
end = ipaddress.IPv4Address('192.168.0.255')
networks = list(ipaddress.summarize_address_range(start, end))
print([str(n) for n in networks])
# ['192.168.0.0/24']
['192.168.0.0/24']

Модуль часто применяется с socket для разрешения имён хостов:

Пример
import socket
import ipaddress

def resolve_to_network(hostname):
    try:
        ip_str = socket.gethostbyname(hostname)
        ip = ipaddress.IPv4Address(ip_str)
        return ip
    except (socket.gaierror, ValueError):
        return None

print(resolve_to_network('google.com'))
# Примерный вывод: 142.250.185.78
142.250.185.78

6. Проверка корректности маски и префикса

Маска может быть задана как в десятичном виде, так и через длину префикса:

Пример
# Автоматическое определение по адресу и маске
net = ipaddress.IPv4Network('192.168.1.0/255.255.255.0')
print(net)  # 192.168.1.0/24

# Проверка маски - только степени двойки
mask_str = '255.255.255.0'
try:
    ipaddress.IPv4Network(f'0.0.0.0/{mask_str}')
    print('Valida mask')
except ValueError as e:
    print(f'Invalid mask: {e}')
192.168.1.0/24
Valida mask

7. Преобразование между IPv4 и IPv6 (если применимо)

IPv4-совместимые IPv6 адреса:

Пример
v4 = ipaddress.IPv4Address('192.0.2.1')
v6_mapped = v4.ipv4_mapped  # IPv4-mapped IPv6
print(v6_mapped)  # ::ffff:192.0.2.1

v6 = ipaddress.IPv6Address('::ffff:192.0.2.1')
print(v6.ipv4_mapped)  # 192.0.2.1
::ffff:192.0.2.1
192.0.2.1

Модуль ipaddress в Python - comments

En
Python ipaddress ip network (python)