Введение в модуль ipaddress
- автор:
-
Peter Moody
- автор:
-
Nick Coghlan
Создание объектов адресов, сетей и интерфейсов
Поскольку ipaddress — это модуль для просмотра и обработки IP-адресов, прежде всего вам потребуется создать несколько объектов. С помощью ipaddress можно создавать объекты из строк и целых чисел.
Примечание о версиях IP
Читателям, не знакомым с IP-адресацией, важно знать, что сейчас происходит переход с версии 4 Интернет-протокола (IP) на версию 6. Этот переход вызван главным образом тем, что версия 4 протокола не предоставляет достаточно адресов для нужд всего мира, особенно с учётом растущего числа устройств с прямым подключением к интернету.
Подробное объяснение различий между двумя версиями протокола выходит за рамки этого введения, однако читателям следует знать хотя бы о существовании обеих версий. Иногда потребуется явно указать, какую из них использовать.
IP-адреса узлов
Адреса, которые часто называют «адресами узлов», — это базовая единица при работе с IP-адресацией. Проще всего создавать адреса с помощью фабричной функции ipaddress.ip_address(), которая автоматически определяет, следует ли создать адрес IPv4 или IPv6, исходя из переданного значения:
>>> ipaddress.ip_address('192.0.2.1')
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address('2001:DB8::1')
IPv6Address('2001:db8::1')
Адреса также можно создавать непосредственно из целых чисел. Значения, помещающиеся в 32 бита, считаются адресами IPv4:
>>> ipaddress.ip_address(3221225985)
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address(42540766411282592856903984951653826561)
IPv6Address('2001:db8::1')
Чтобы принудительно использовать адреса IPv4 или IPv6, можно напрямую вызвать соответствующие классы. Это особенно полезно, когда требуется создать адрес IPv6 из небольшого целого числа:
>>> ipaddress.ip_address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv4Address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv6Address(1)
IPv6Address('::1')
Определение сетей
Адреса узлов обычно объединяют в IP-сети, поэтому ipaddress позволяет создавать, просматривать и обрабатывать определения сетей. Объекты IP-сетей создаются из строк, задающих диапазон адресов узлов, входящих в сеть. Простейший формат таких данных — пара «сетевой адрес/префикс сети», где префикс задаёт количество начальных битов, по которым определяется принадлежность адреса к сети, а сетевой адрес — ожидаемое значение этих битов.
Как и для адресов, предусмотрена фабричная функция, автоматически определяющая нужную версию IP:
>>> ipaddress.ip_network('192.0.2.0/24')
IPv4Network('192.0.2.0/24')
>>> ipaddress.ip_network('2001:db8::0/96')
IPv6Network('2001:db8::/96')
Объекты сетей не могут содержать установленные биты узла. На практике это означает, что 192.0.2.1/24 не описывает сеть. Такие определения называются объектами интерфейсов, поскольку запись «IP-адрес в сети» обычно используется для описания сетевых интерфейсов компьютера в конкретной сети. Подробнее они рассматриваются в следующем разделе.
По умолчанию попытка создать объект сети с установленными битами узла приводит к возникновению исключения ValueError. Чтобы вместо этого дополнительные биты обнулялись, конструктору можно передать флаг strict=False:
>>> ipaddress.ip_network('192.0.2.1/24')
Traceback (most recent call last):
...
ValueError: 192.0.2.1/24 has host bits set
>>> ipaddress.ip_network('192.0.2.1/24', strict=False)
IPv4Network('192.0.2.0/24')
Хотя строковый формат предоставляет значительно больше возможностей, сети можно определять и с помощью целых чисел, как и адреса узлов. В этом случае считается, что сеть содержит только один адрес, заданный целым числом, поэтому префикс сети включает весь сетевой адрес:
>>> ipaddress.ip_network(3221225984)
IPv4Network('192.0.2.0/32')
>>> ipaddress.ip_network(42540766411282592856903984951653826560)
IPv6Network('2001:db8::/128')
Как и в случае с адресами, чтобы принудительно создать сеть определённого типа, можно напрямую вызвать конструктор класса, а не использовать фабричную функцию.
Интерфейсы узлов
Как упоминалось выше, если нужно описать адрес в конкретной сети, одного класса адресов или сетей недостаточно. Запись вроде 192.0.2.1/24 сетевые инженеры и разработчики инструментов для межсетевых экранов и маршрутизаторов часто используют как сокращение выражения «узел 192.0.2.1 в сети 192.0.2.0/24». Поэтому ipaddress предоставляет набор гибридных классов, связывающих адрес с конкретной сетью. Интерфейс создания таких объектов совпадает с интерфейсом определения сетей, за исключением того, что адресная часть не ограничивается сетевым адресом.
>>> ipaddress.ip_interface('192.0.2.1/24')
IPv4Interface('192.0.2.1/24')
>>> ipaddress.ip_interface('2001:db8::1/96')
IPv6Interface('2001:db8::1/96')
Как и для сетей, допускаются целочисленные значения, а нужную версию IP можно принудительно задать прямым вызовом соответствующего конструктора.
Просмотр объектов адресов, сетей и интерфейсов
Вы потратили усилия на создание объекта IPv(4|6)(Address|Network|Interface), так что, вероятно, захотите получить о нём информацию. ipaddress старается сделать это простым и понятным.
Получение версии IP:
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> addr6 = ipaddress.ip_address('2001:db8::1')
>>> addr6.version
6
>>> addr4.version
4
Получение сети по интерфейсу:
>>> host4 = ipaddress.ip_interface('192.0.2.1/24')
>>> host4.network
IPv4Network('192.0.2.0/24')
>>> host6 = ipaddress.ip_interface('2001:db8::1/96')
>>> host6.network
IPv6Network('2001:db8::/96')
Определение числа отдельных адресов в сети:
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> net4.num_addresses
256
>>> net6 = ipaddress.ip_network('2001:db8::0/96')
>>> net6.num_addresses
4294967296
Перебор «доступных» адресов в сети:
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> for x in net4.hosts():
... print(x)
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
...
192.0.2.252
192.0.2.253
192.0.2.254
Получение маски сети (то есть битов, установленных в соответствии с префиксом сети) или маски узла (любых битов, не входящих в маску сети):
>>> net4 = ipaddress.ip_network('192.0.2.0/24')
>>> net4.netmask
IPv4Address('255.255.255.0')
>>> net4.hostmask
IPv4Address('0.0.0.255')
>>> net6 = ipaddress.ip_network('2001:db8::0/96')
>>> net6.netmask
IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::')
>>> net6.hostmask
IPv6Address('::ffff:ffff')
Развёрнутая или сокращённая запись адреса:
>>> addr6.exploded '2001:0db8:0000:0000:0000:0000:0000:0001' >>> addr6.compressed '2001:db8::1' >>> net6.exploded '2001:0db8:0000:0000:0000:0000:0000:0000/96' >>> net6.compressed '2001:db8::/96'
Хотя IPv4 не поддерживает развёрнутую и сокращённую запись, соответствующие объекты всё равно предоставляют нужные свойства. Это позволяет коду, не зависящему от версии IP, легко выбирать наиболее краткую или наиболее полную запись для адресов IPv6, корректно обрабатывая при этом адреса IPv4.
Сети как списки адресов
Иногда удобно рассматривать сети как списки. Это позволяет обращаться к ним по индексу:
>>> net4[1]
IPv4Address('192.0.2.1')
>>> net4[-1]
IPv4Address('192.0.2.255')
>>> net6[1]
IPv6Address('2001:db8::1')
>>> net6[-1]
IPv6Address('2001:db8::ffff:ffff')
Кроме того, объекты сетей можно использовать с синтаксисом проверки вхождения элемента в список:
if address in network:
# do something
Проверка принадлежности выполняется эффективно на основе префикса сети:
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> addr4 in ipaddress.ip_network('192.0.2.0/24')
True
>>> addr4 in ipaddress.ip_network('192.0.3.0/24')
False
Сравнения
ipaddress предоставляет несколько простых и, будем надеяться, интуитивно понятных способов сравнения объектов, когда это имеет смысл:
>>> ipaddress.ip_address('192.0.2.1') < ipaddress.ip_address('192.0.2.2')
True
При попытке сравнить объекты разных версий или разных типов возникает исключение TypeError.
Использование IP-адресов с другими модулями
Другие модули, работающие с IP-адресами (например, socket), обычно не принимают напрямую объекты этого модуля. Вместо этого их нужно преобразовать в целое число или строку, которые сможет принять другой модуль:
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> str(addr4)
'192.0.2.1'
>>> int(addr4)
3221225985
Дополнительные сведения об ошибках при создании экземпляра
При создании объектов адресов, сетей и интерфейсов с помощью фабричных функций, не зависящих от версии, любые ошибки сообщаются как ValueError с общим сообщением о том, что переданное значение не распознано как объект данного типа. Конкретная ошибка не указывается, поскольку для подробного объяснения причины отказа необходимо знать, должен ли адрес быть IPv4- или IPv6-адресом.
Чтобы поддержать сценарии, в которых нужны эти дополнительные сведения, конструкторы отдельных классов вызывают подклассы ValueError — ipaddress.AddressValueError и ipaddress.NetmaskValueError. Они точно указывают, какая часть определения не была корректно разобрана.
При прямом вызове конструкторов классов сообщения об ошибках значительно подробнее. Например:
>>> ipaddress.ip_address("192.168.0.256")
Traceback (most recent call last):
...
ValueError: '192.168.0.256' does not appear to be an IPv4 or IPv6 address
>>> ipaddress.IPv4Address("192.168.0.256")
Traceback (most recent call last):
...
ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.0.256'
>>> ipaddress.ip_network("192.168.0.1/64")
Traceback (most recent call last):
...
ValueError: '192.168.0.1/64' does not appear to be an IPv4 or IPv6 network
>>> ipaddress.IPv4Network("192.168.0.1/64")
Traceback (most recent call last):
...
ipaddress.NetmaskValueError: '64' is not a valid netmask
Однако оба исключения, специфичных для модуля, являются подклассами ValueError. Поэтому, если конкретный тип ошибки не имеет значения, можно по-прежнему написать такой код:
try:
network = ipaddress.IPv4Network(address)
except ValueError:
print('address/netmask is invalid for IPv4:', address)
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/howto/ipaddress.html