Введение в модуль ipaddress¶
Автор: | Peter Moody |
---|---|
Автор: | Nick Coghlan |
Обзор
Этот документ предназначен для того, чтобы обеспечить мягкое введение в модуль
ipaddress
. Она ориентирована в первую очередь на пользователей, которые еще не
знакомы с терминологией IP сетей, но также может быть полезна инженерам сети,
желающим получить обзор того, как ipaddress
представляет концепции IP-сетевых
адресаций.
Создание объектов Адрес/Сеть/Интерфейс¶
Поскольку ipaddress
является модулем для проверки и манипулирования IP-
адресами, первое, что вы хотите сделать, это создать некоторые объекты. Можно
использовать ipaddress
для создания объектов из строки и целых чисел.
Примечание о версиях 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)(Интерфейс|Адрес|Сеть)
поэтому, вероятно, вам нужно получить информацию о нем. 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
с универсальным
сообщением об ошибке, в котором просто говорится, что переданный в стоимости не
был признан объектом того типа. Отсутствие определенной ошибки - то, потому что
необходимо знать, является ли стоимость supposed, чтобы быть 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)