Spec-Zone.ru › Python 3.13

Введение в модуль ipaddress

автор:

Питер Муди

автор:

Ник Коглан

Обзор

Этот документ призван предоставить краткое введение в модуль ipaddress. Он предназначен в первую очередь для пользователей, не знакомых с терминологией IP-сетей, но может быть полезен и сетевым инженерам, желающим получить общее представление о том, как ipaddress представляет концепции адресации IP-сетей.

Создание объектов адреса/сети/интерфейса

Поскольку ipaddress — это модуль для проверки и обработки IP-адресов, первое, что вам нужно сделать, — создать некоторые объекты. Вы можете использовать ipaddress для создания объектов из строк и целых чисел.

Примечание по версиям IP

Для читателей, которые не очень знакомы с адресацией IP, важно знать, что протокол Интернет (IP) в настоящее время переходит от версии 4 к версии 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 не поддерживает расширение или сжатие, связанные объекты по-прежнему предоставляют соответствующие свойства, так что код, нейтральный по отношению к версии, может легко обеспечить использование наиболее компактной или наиболее подробной формы для 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/howto/ipaddress.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API