ipaddress模塊介紹?

作者

Peter Moody

作者

Nick Coghlan

概述

本文檔旨在簡要介紹 ipaddress 模塊。 它主要針對那些不熟悉 IP 網絡術語的用戶,但也可能對想要速覽 ipaddress 如何代表IP網絡尋址概念的網絡工程師有用。

創建 Address/Network/Interface 對象?

因為 ipaddress 是一個用于檢查和操作 IP 地址的模塊,你要做的第一件事就是創建一些對象。 您可以使用 ipaddress 從字符串和整數創建對象。

關于IP版本的說明?

對于不太熟悉 IP 尋址的讀者,重要的是要知道 Internet 協議當前正在從協議的版本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.0/24 網絡上的主機 192.0.2.1 ”的簡寫。因此,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版本。

審查 Address/Network/Interface 對象?

你已經遇到了創建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地址。

Network 作為 Address 列表?

將網絡視為列表有時很有用。 這意味著它可以像這樣索引它們:

>>> 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

實例創建失敗時獲取更多詳細信息?

使用與版本無關的工廠函數創建 address/network/interface 對象時,任何錯誤都將報告為 ValueError ,帶有一般錯誤消息,只是說傳入的值未被識別為該類型的對象。 缺少特定錯誤是因為有必要知道該值是*假設*是IPv4還是IPv6,以便提供有關其被拒絕原因的更多詳細信息。

為了支持訪問這些額外細節的用例,各個類構造函數實際上引發了 ValueError 子類 ipaddress.AddressValueErroripaddress.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)