ipaddress模塊介紹?

作者

Peter Moody

作者

Nick Coghlan

概述

本文檔旨在簡(jiǎn)要介紹 ipaddress 模塊。 它主要針對(duì)那些不熟悉 IP 網(wǎng)絡(luò)術(shù)語(yǔ)的用戶,但也可能對(duì)想要速覽 ipaddress 如何代表IP網(wǎng)絡(luò)尋址概念的網(wǎng)絡(luò)工程師有用。

創(chuàng)建 Address/Network/Interface 對(duì)象?

因?yàn)?ipaddress 是一個(gè)用于檢查和操作 IP 地址的模塊,你要做的第一件事就是創(chuàng)建一些對(duì)象。 您可以使用 ipaddress 從字符串和整數(shù)創(chuàng)建對(duì)象。

關(guān)于IP版本的說(shuō)明?

對(duì)于不太熟悉 IP 尋址的讀者來(lái)說(shuō),重要的一點(diǎn)是知道互聯(lián)網(wǎng)協(xié)議 (IP) 目前正在從第 4 版協(xié)議遷移到第 6 版。 進(jìn)行這樣的遷移主要是因?yàn)榈?4 版協(xié)議無(wú)法提供足夠的地址來(lái)滿足全世界的需求,特別是考慮到有越來(lái)越多的設(shè)備連接到了互聯(lián)網(wǎng)中。

解釋協(xié)議的兩個(gè)版本之間的差異的細(xì)節(jié)超出了本介紹的范圍,但讀者需要至少知道存在這兩個(gè)版本,并且有時(shí)需要強(qiáng)制使用一個(gè)版本或其他版本。

IP主機(jī)地址?

通常稱為“主機(jī)地址”的地址是使用IP尋址時(shí)最基本的單元。 創(chuàng)建地址的最簡(jiǎn)單方法是使用 ipaddress.ip_address() 工廠函數(shù),該函數(shù)根據(jù)傳入的值自動(dòng)確定是創(chuàng)建 IPv4 還是 IPv6 地址:

>>>
>>> ipaddress.ip_address('192.0.2.1')
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address('2001:DB8::1')
IPv6Address('2001:db8::1')

地址也可以直接從整數(shù)創(chuàng)建,適配32位的值并假定為IPv4地址:

>>>
>>> ipaddress.ip_address(3221225985)
IPv4Address('192.0.2.1')
>>> ipaddress.ip_address(42540766411282592856903984951653826561)
IPv6Address('2001:db8::1')

要強(qiáng)制使用IPv4或IPv6地址,可以直接調(diào)用相關(guān)的類。 這對(duì)于強(qiáng)制為小整數(shù)創(chuàng)建IPv6地址特別有用:

>>>
>>> ipaddress.ip_address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv4Address(1)
IPv4Address('0.0.0.1')
>>> ipaddress.IPv6Address(1)
IPv6Address('::1')

定義網(wǎng)絡(luò)?

主機(jī)地址通常組合在一起形成IP網(wǎng)絡(luò),因此 ipaddress 提供了一種創(chuàng)建、檢查和操作網(wǎng)絡(luò)定義的方法。 IP網(wǎng)絡(luò)對(duì)象由字符串構(gòu)成,這些字符串定義作為該網(wǎng)絡(luò)一部分的主機(jī)地址范圍。 該信息的最簡(jiǎn)單形式是“網(wǎng)絡(luò)地址/網(wǎng)絡(luò)前綴”對(duì),其中前綴定義了比較的前導(dǎo)比特?cái)?shù),以確定地址是否是網(wǎng)絡(luò)的一部分,并且網(wǎng)絡(luò)地址定義了那些位的預(yù)期值。

對(duì)于地址,提供了一個(gè)自動(dòng)確定正確IP版本的工廠函數(shù):

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

網(wǎng)絡(luò)對(duì)象不能設(shè)置任何主機(jī)位。 這樣做的實(shí)際效果是``192.0.2.1/24``沒(méi)有描述網(wǎng)絡(luò)。 這種定義被稱為接口對(duì)象,因?yàn)榫W(wǎng)絡(luò)上IP表示法通常用于描述給定網(wǎng)絡(luò)上的計(jì)算機(jī)的網(wǎng)絡(luò)接口,并在下一節(jié)中進(jìn)一步描述。

默認(rèn)情況下,嘗試創(chuàng)建一個(gè)設(shè)置了主機(jī)位的網(wǎng)絡(luò)對(duì)象將導(dǎo)致 ValueError 被引發(fā)。 要請(qǐng)求將附加位強(qiáng)制為零,可以將標(biāo)志``strict=False`` 傳遞給構(gòu)造函數(shù):

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

雖然字符串形式提供了更大的靈活性,但網(wǎng)絡(luò)也可以用整數(shù)定義,就像主機(jī)地址一樣。 在這種情況下,網(wǎng)絡(luò)被認(rèn)為只包含由整數(shù)標(biāo)識(shí)的單個(gè)地址,因此網(wǎng)絡(luò)前綴包括整個(gè)網(wǎng)絡(luò)地址:

>>>
>>> ipaddress.ip_network(3221225984)
IPv4Network('192.0.2.0/32')
>>> ipaddress.ip_network(42540766411282592856903984951653826560)
IPv6Network('2001:db8::/128')

與地址一樣,可以通過(guò)直接調(diào)用類構(gòu)造函數(shù)而不是使用工廠函數(shù)來(lái)強(qiáng)制創(chuàng)建特定類型的網(wǎng)絡(luò)。

主機(jī)接口?

如上所述,如果您需要描述特定網(wǎng)絡(luò)上的地址,則地址和網(wǎng)絡(luò)類都不夠。 像 192.0.2.1/24 這樣的表示法通常被網(wǎng)絡(luò)工程師和為防火墻和路由器編寫(xiě)工具的人用作“ 192.0.2.0/24 網(wǎng)絡(luò)上的主機(jī) 192.0.2.1 ”的簡(jiǎn)寫(xiě)。因此,ipaddress 提供了一組將地址與特定網(wǎng)絡(luò)相關(guān)聯(lián)的混合類。用于創(chuàng)建的接口與用于定義網(wǎng)絡(luò)對(duì)象的接口相同,除了地址部分不限于是網(wǎng)絡(luò)地址。

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

接受整數(shù)輸入(與網(wǎng)絡(luò)一樣),并且可以通過(guò)直接調(diào)用相關(guān)構(gòu)造函數(shù)來(lái)強(qiáng)制使用特定IP版本。

審查 Address/Network/Interface 對(duì)象?

你已經(jīng)遇到了創(chuàng)建IPv(4|6)(Address|Network|Interface) 對(duì)象的麻煩,因此你可能希望獲得有關(guān)它的信息。 ipaddress 試圖讓這個(gè)過(guò)程變得簡(jiǎn)單直觀。

提取 IP 版本:

>>>
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> addr6 = ipaddress.ip_address('2001:db8::1')
>>> addr6.version
6
>>> addr4.version
4

從接口獲取網(wǎng)絡(luò):

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

找出網(wǎng)絡(luò)中有多少獨(dú)立地址:

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

迭代網(wǎng)絡(luò)上的“可用”地址:

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

獲取網(wǎng)絡(luò)掩碼(即對(duì)應(yīng)于網(wǎng)絡(luò)前綴的設(shè)置位)或主機(jī)掩碼(不屬于網(wǎng)絡(luò)掩碼的任何位):

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

展開(kāi)或壓縮地址:

>>>
>>> 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不支持展開(kāi)或壓縮,但關(guān)聯(lián)對(duì)象仍提供相關(guān)屬性,因此版本中性代碼可以輕松確保最簡(jiǎn)潔或最詳細(xì)的形式用于IPv6地址,同時(shí)仍能正確處理IPv4地址。

Network 作為 Address 列表?

將網(wǎng)絡(luò)視為列表有時(shí)很有用。 這意味著它可以像這樣索引它們:

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

它還意味著網(wǎng)絡(luò)對(duì)象可以使用像這樣的列表成員測(cè)試語(yǔ)法:

if address in network:
    # do something

根據(jù)網(wǎng)絡(luò)前綴有效地完成包含性測(cè)試:

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

比較運(yùn)算?

ipaddress 有意義地提供了一些簡(jiǎn)單、希望直觀的比較對(duì)象的方法:

>>>
>>> ipaddress.ip_address('192.0.2.1') < ipaddress.ip_address('192.0.2.2')
True

如果你嘗試比較不同版本或不同類型的對(duì)象,則會(huì)引發(fā) TypeError 異常。

將IP地址與其他模塊一起使用?

其他使用IP地址的模塊(例如 socket )通常不會(huì)直接接受來(lái)自該模塊的對(duì)象。 相反,它們必須被強(qiáng)制轉(zhuǎn)換為另一個(gè)模塊可接受的整數(shù)或字符串:

>>>
>>> addr4 = ipaddress.ip_address('192.0.2.1')
>>> str(addr4)
'192.0.2.1'
>>> int(addr4)
3221225985

實(shí)例創(chuàng)建失敗時(shí)獲取更多詳細(xì)信息?

使用與版本無(wú)關(guān)的工廠函數(shù)創(chuàng)建 address/network/interface 對(duì)象時(shí),任何錯(cuò)誤都將報(bào)告為 ValueError ,帶有一般錯(cuò)誤消息,只是說(shuō)傳入的值未被識(shí)別為該類型的對(duì)象。 缺少特定錯(cuò)誤是因?yàn)橛斜匾涝撝凳?假設(shè)*是IPv4還是IPv6,以便提供有關(guān)其被拒絕原因的更多詳細(xì)信息。

為了支持訪問(wèn)這些額外細(xì)節(jié)的用例,各個(gè)類構(gòu)造函數(shù)實(shí)際上引發(fā)了 ValueError 子類 ipaddress.AddressValueErroripaddress.NetmaskValueError 以準(zhǔn)確指示定義的哪一部分無(wú)法正確解析。

直接使用類構(gòu)造函數(shù)時(shí),錯(cuò)誤消息更加詳細(xì)。 例如:

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

但是,兩個(gè)模塊特定的異常都有 ValueError 作為它們的父類,所以如果你不關(guān)心特定類型的錯(cuò)誤,你仍然可以編寫(xiě)如下代碼:

try:
    network = ipaddress.IPv4Network(address)
except ValueError:
    print('address/netmask is invalid for IPv4:', address)