ipaddress 模組簡介¶
- 作者:
Peter Moody
- 作者:
Nick Coghlan
建立地址/網路/介面物件¶
由於 ipaddress
是一個用於檢查和操作 IP 地址的模組,您要做的第一件事是建立一些物件。您可以使用 ipaddress
從字串和整數建立物件。
關於 IP 版本的說明¶
對於不太熟悉 IP 定址的讀者來說,重要的是要知道 Internet 協議 (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.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 版本。
檢查地址/網路/介面物件¶
您已經費盡心思建立了一個 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)