Работа с IP-адресами в Python с помощью ipaddress
Введение в библиотеку ipaddress
Модуль ipaddress в Python предоставляет классы для создания, манипуляции и проверки IP-адресов и сетей. Он поддерживает как IPv4, так и IPv6, и позволяет выполнять операции, такие как проверка принадлежности адреса сети, разделение сети на подсети, объединение сетей и многое другое.
Основное решение: создание и проверка IP-адресов и сетей
Наиболее эффективный способ работы с IP-адресами - использование классов ipaddress.IPv4Address, ipaddress.IPv6Address, ipaddress.IPv4Network и ipaddress.IPv6Network. Они автоматически проверяют корректность входных данных и предоставляют удобные методы.
import ipaddress
# Создание IPv4 адреса
addr = ipaddress.IPv4Address('192.168.1.1')
print(addr) # 192.168.1.1
print(addr.version) # 4
print(addr.is_private) # True
# Создание сети
net = ipaddress.IPv4Network('192.168.1.0/24')
print(net) # 192.168.1.0/24
print(net.netmask) # 255.255.255.0
print(net.num_addresses) # 256
# Проверка вхождения адреса в сеть
print(addr in net) # Trueбиблиотека ipaddress python (библиотека ipaddress в python)
192.168.1.1 4 True 192.168.1.0/24 255.255.255.0 256 True
Этот подход позволяет избежать ручного парсинга строк, обработки ошибок и работы с двоичными представлениями.
Типичные ошибки и их решение
- ValueError: '192.168.1.256' does not appear to be an IPv4 or IPv6 address - адрес содержит число больше 255. Используйте только валидные октеты.
- ValueError: '192.168.1.0/33' has invalid prefix length - префикс больше 32 для IPv4. Для IPv6 префикс от 0 до 128.
- TypeError при попытке сравнить IPv4Address с IPv6Address - нельзя сравнивать напрямую. Преобразуйте к строке или используйте .exploded.
- Нестрогие сети: по умолчанию strict=True в конструкторе IPv4Network - адрес сети должен быть базовым. Если передать '192.168.1.1/24', будет ошибка. Для разрешения используйте strict=False, тогда сеть будет округлена до '192.168.1.0/24'.
Как создать IPv6 адрес и сеть?
import ipaddress
ipv6_addr = ipaddress.IPv6Address('2001:db8::1')
print(ipv6_addr) # 2001:db8::1
print(ipv6_addr.version) # 6
ipv6_net = ipaddress.IPv6Network('2001:db8::/32')
print(ipv6_net) # 2001:db8::/32
print(ipv6_net.num_addresses) # 2**96
# Проверка вхождения
print(ipv6_addr in ipv6_net) # True2001:db8::1 6 2001:db8::/32 79228162514264337593543950336 True
Как разбить сеть на подсети одинакового размера?
import ipaddress
net = ipaddress.IPv4Network('10.0.0.0/24')
subnets = list(net.subnets(new_prefix=26)) # подсети по 64 адреса
for sub in subnets:
print(sub)
# 10.0.0.0/26
# 10.0.0.64/26
# 10.0.0.128/26
# 10.0.0.192/2610.0.0.0/26 10.0.0.64/26 10.0.0.128/26 10.0.0.192/26
Как объединить несколько сетей в одну суперсеть (supernet)?
import ipaddress
nets = [ipaddress.IPv4Network('192.168.1.0/25'),
ipaddress.IPv4Network('192.168.1.128/25')]
supernet = nets[0].supernet(new_prefix=24)
print(supernet) # 192.168.1.0/24192.168.1.0/24
Как получить список всех адресов (хостов) в сети?
import ipaddress
net = ipaddress.IPv4Network('192.168.0.0/29')
for host in net.hosts():
print(host)
# 192.168.0.1
# 192.168.0.2
# 192.168.0.3
# 192.168.0.4
# 192.168.0.5
# 192.168.0.6192.168.0.1 192.168.0.2 192.168.0.3 192.168.0.4 192.168.0.5 192.168.0.6
Как проверить, является ли адрес частным или публичным?
import ipaddress
addr1 = ipaddress.IPv4Address('10.0.0.1')
addr2 = ipaddress.IPv4Address('8.8.8.8')
print(addr1.is_private) # True
print(addr2.is_private) # False
print(addr1.is_global) # False
print(addr2.is_global) # True
# Также is_multicast, is_loopback, is_link_local и др.True False False True
Проблема: сравнение сетей с разными масками
Например, сети '192.168.1.0/24' и '192.168.1.0/25' разные, и subnet_of() и supernet_of() помогут определить иерархию. Если передать строку без маски, будет ошибка.
Расширенные примеры работы с ipaddress
1. Работа с IPv6 и сравнение адресов
import ipaddress
a = ipaddress.IPv6Address('2001:0db8:85a3:0000:0000:8a2e:0370:7334')
b = ipaddress.IPv6Address('2001:db8:85a3::8a2e:370:7334')
print(a == b) # True - одинаковые после нормализации
print(a.exploded) # 2001:0db8:85a3:0000:0000:8a2e:0370:7334
print(b.compressed) # 2001:db8:85a3::8a2e:370:7334
# Сложение и вычитание (только для IPv4Address)
c = ipaddress.IPv4Address('192.168.1.10')
d = int(c) + 5
print(ipaddress.IPv4Address(d)) # 192.168.1.15True 2001:0db8:85a3:0000:0000:8a2e:0370:7334 2001:db8:85a3::8a2e:370:7334 192.168.1.15
2. Преобразование между адресами и целыми числами
import ipaddress
addr = ipaddress.IPv4Address('10.0.0.1')
print(int(addr)) # 167772161
print(ipaddress.IPv4Address(167772161)) # 10.0.0.1
# Для IPv6
addr6 = ipaddress.IPv6Address('::1')
print(int(addr6)) # 1
print(ipaddress.IPv6Address(1)) # ::1167772161 10.0.0.1 1 ::1
3. Создание объекта сети из адреса и маски в разных форматах
import ipaddress
# Из строки со слешем
net1 = ipaddress.IPv4Network('10.0.0.0/255.255.255.0')
print(net1) # 10.0.0.0/24
# Из пары (адрес, маска)
addr = ipaddress.IPv4Address('10.0.0.0')
mask = ipaddress.IPv4Address('255.255.255.0')
net2 = ipaddress.IPv4Network(addr, mask=mask)
print(net2) # 10.0.0.0/24
# Использование strict=False для небазового адреса
net3 = ipaddress.IPv4Network('10.0.0.5/24', strict=False)
print(net3) # 10.0.0.0/2410.0.0.0/24 10.0.0.0/24 10.0.0.0/24
4. Проверка перекрытия сетей и подчиненности
import ipaddress
net_a = ipaddress.IPv4Network('192.168.0.0/23')
net_b = ipaddress.IPv4Network('192.168.1.0/24')
net_c = ipaddress.IPv4Network('10.0.0.0/8')
print(net_a.overlaps(net_b)) # True (net_b полностью внутри net_a)
print(net_b.subnet_of(net_a)) # True
print(net_a.supernet_of(net_b)) # True
print(net_c.overlaps(net_a)) # FalseTrue True True False
5. Итерация по всем адресам сети с исключением сетевого и широковещательного
import ipaddress
net = ipaddress.IPv4Network('10.0.0.0/28')
hosts = list(net.hosts())
print('Количество хостов:', len(hosts)) # 14
print('Первый хост:', hosts[0]) # 10.0.0.1
print('Последний:', hosts[-1]) # 10.0.0.14
# Включая все адреса (с сетью и broadcast)
all_addresses = list(net)
print(len(all_addresses)) # 16
print(all_addresses[0]) # 10.0.0.0 (сетевой)
print(all_addresses[-1]) # 10.0.0.15 (broadcast)Количество хостов: 14 Первый хост: 10.0.0.1 Последний: 10.0.0.14 16 10.0.0.0 10.0.0.15
6. Создание произвольного набора адресов с использованием ipaddress.ip_interface
import ipaddress
# Интерфейс - адрес с маской сети
iface = ipaddress.IPv4Interface('192.168.1.10/24')
print(iface.ip) # 192.168.1.10
print(iface.network) # 192.168.1.0/24
print(iface.netmask) # 255.255.255.0
# Также работает для IPv6
iface6 = ipaddress.IPv6Interface('2001:db8::1/64')
print(iface6.ip) # 2001:db8::1
print(iface6.network) # 2001:db8::/64192.168.1.10 192.168.1.0/24 255.255.255.0 2001:db8::1 2001:db8::/64
7. Работа с произвольными масками и CIDR нотацией
import ipaddress
# Определение маски по длине префикса
mask = ipaddress.IPv4Network('0.0.0.0/26').netmask
print(mask) # 255.255.255.192
# Обратно: получить префикс из маски
from ipaddress import IPv4Network
net = IPv4Network('10.0.0.0/255.255.255.192')
print(net.prefixlen) # 26255.255.255.192 26
8. Валидация IP-адресов и сетей из пользовательского ввода
import ipaddress
def validate_ip(ip_str):
try:
ipaddress.ip_address(ip_str)
return True
except ValueError:
return False
def validate_network(net_str):
try:
ipaddress.ip_network(net_str, strict=False)
return True
except ValueError:
return False
print(validate_ip('256.1.2.3')) # False
print(validate_ip('10.0.0.1')) # True
print(validate_network('10.0.0.0/8')) # True
print(validate_network('10.0.0.0/33')) # FalseFalse True True False
9. Сравнение адресов и сетей с помощью стандартных операторов
import ipaddress
a = ipaddress.IPv4Address('10.0.0.5')
b = ipaddress.IPv4Address('10.0.0.10')
print(a < b) # True
print(a >= b) # False
net1 = ipaddress.IPv4Network('10.0.0.0/24')
net2 = ipaddress.IPv4Network('10.0.0.0/25')
print(net1 > net2) # False (большая сеть не считается "больше")
# Для иерархии используйте subnet_of, supernet_ofTrue False False
10. Получение broadcast-адреса и сетевого адреса
import ipaddress
net = ipaddress.IPv4Network('10.0.0.128/25')
print(net.network_address) # 10.0.0.128
print(net.broadcast_address) # 10.0.0.25510.0.0.128 10.0.0.255
11. Обработка ошибок при работе с невалидными данными
import ipaddress
# Пример ошибки: неверный формат
addr_str = 'hello'
try:
ipaddress.IPv4Address(addr_str)
except ValueError as e:
print(f"Ошибка: {e}") # Ошибка: 'hello' does not appear to be an IPv4 or IPv6 address
# Пример: сеть с широковещательным адресом
net_str = '192.168.1.255/24'
try:
ipaddress.IPv4Network(net_str) # strict=True по умолчанию
except ValueError as e:
print(f"Ошибка: {e}") # 192.168.1.255/24 has host bits set
# Решение: strict=False
net = ipaddress.IPv4Network(net_str, strict=False)
print(net) # 192.168.1.0/24Ошибка: 'hello' does not appear to be an IPv4 or IPv6 address Ошибка: 192.168.1.255/24 has host bits set 192.168.1.0/24
12. Комбинирование с модулем socket для работы с сетевыми соединениями
import ipaddress
import socket
# Преобразование IP-адреса из строки в двоичный формат для socket
ip_str = '192.168.1.1'
addr = ipaddress.IPv4Address(ip_str)
packed = addr.packed # 4 байта
print(packed) # b'\xc0\xa8\x01\x01'
# Обратно: из packed в объект
addr_back = ipaddress.IPv4Address(packed)
print(addr_back) # 192.168.1.1
# Получение адреса по имени хоста (если доступно)
try:
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
addr = ipaddress.IPv4Address(ip)
print(f"Адрес этого компьютера: {addr}")
except Exception as e:
print(f"Ошибка получения адреса: {e}")b'\xc0\xa8\x01\x01' 192.168.1.1 Адрес этого компьютера: 192.168.1.100
13. Генерация всех подсетей заданного размера из диапазона адресов
import ipaddress
# Создаем сеть и разбиваем на подсети /28
net = ipaddress.IPv4Network('10.0.0.0/24')
subnets = list(net.subnets(new_prefix=28))
print(f"Количество подсетей: {len(subnets)}") # 16
for s in subnets[:3]:
print(s)
# 10.0.0.0/28
# 10.0.0.16/28
# 10.0.0.32/28Количество подсетей: 16 10.0.0.0/28 10.0.0.16/28 10.0.0.32/28