Python中的ipaddress模块

原文地址:https://dbader.org/blog/python-ipaddress-module

作者:Jon Crawfurd

副标题:本文介绍了Python 3.3以上版本中用于处理IPv4和IPv6地址的ipaddress模块。

译者:首席IT民工


在本文中,我们会看一看Python 3.3及更高版本中提供的ipaddress模块。 本教程旨在为想知道如何在Python中解析和使用IP地址的网络工程师们提供一个简要参考。


在这篇概述中,你将了解到:


  • IPv4和IPv6地址之间的区别是什么

  • 如何使用Python的ipaddress模块处理IPv4地址

  • 如何使用Python的ipaddress模块处理IPv6地址


IPv4与IPv6地址 - 入门知识

从大的方面来看,IPv4地址和IPv6地址具有相同的目的和功能。但是,由于每个协议的地址结构存在很大差异。本教程用了不同的部分,来分别讨论IPv4和IPv6。


当今的互联网中,IPv4协议承担了绝大部分的IP处理任务,在不久的将来也依旧如此。 IPv6所带来的规模和功能方面的增强对未来互联网不可或缺。尽管正在被逐步采用,但是到目前为止,采用率仍然很低。


一个IPv4地址由32位组成,分为四个八位字节,称为“八位组”。 “八位组”一词用于标识一个八位结构来代替更常见的术语“字节”,但它们的定义相同。四个八位组被称为octet1,octet2,octet3和octet4。这是一个“点分十进制”格式,其中每个八位组有对应一个从0到255的十进制值。

IPv4地址示例:192.168.100.10


IPv4地址示例(CIDR表示法):192.168.100.10/24


“/24”是CIDR表示法,表示32位的前24位用于标识地址的网络部分。 记住每个八位字节长度为8位,这意味着前三个字节(3×8 = 24)标识网络(192.168.100.x),地址的其余八位标识节点(x.x.x.10)。


CIDR表示法可以是从 /8位 到 /30位的任何值,偶尔有 /32位(/31无效),但通常使用/24。 例如,你的家庭网络,或你的学校或公司网络很可能用/24 CIDR来表示。


用于表示网络标识的更老的格式是子网掩码,其中CIDR表示为单独的点分十进制数。 例如,一个/24 CIDR相当于一个网络掩码255.255.255.0。

IPv6地址长度为128位,与IPv4地址中的32位相比,有显著的增加。 IPv4和IPv6之间有很多不同之处,但最大的区别在于寻址结构。 额外的长度提供了可支持的网络和主机数量的指数级增长。

IPv6地址示例:2001:db8:abcd:100::1/64


在IPv4地址使用点分十进制格式的情况下,IPv6协议使用十六进制表示法。 IPv6地址中的每个位置表示4个位,其值从0到f,按以下方式组织:


  • 128位被分成8组,每组16位,每组由冒号分隔。一个组被称为4个十六进制字符(4个十六进制字符乘以4位= 16位)的“四重组”或“十六位组”。在上面的例子中,第一个四重组是“2001”。

  • 任何四重组中的头部的0会被去除/压缩。在上面的例子中,第二个四元组是“db8”,实际上是“0db8”“,最开头的0被去掉了。最后一个四重奏是“1”,实际上是“0001”“,三个头部0被压缩了。

  • 如果一个四重组包含全零,它将被压缩为一个零。例如:具有“:0000:”的四重奏将被压缩为“:0:”。

  • 如果一个地址包含一个连续的全部为零的四重组,则连续的零被压缩并用双冒号表示。在上面的例子中,双冒号表示3个全部为零的四元组,或者“:0000:0000:0000:”浓缩为“::”。由于范例的地址有5个有值的四重奏,所以浓缩四重奏的数量肯定是3个(总数减8)。


所有的IPv6地址结构都使用CIDR表示法来确定有多少前导位用于网络标识,其余部分则用于主机/接口标识。考虑到是128位,选择有很多。

Python的ipaddress模块,和IPv4地址

ipaddress模块是按照CIDR表示法设计的,由于其简洁易用,受到人们的推荐。 ipaddress模块还包含了一些方法,用于在必要的情况下还原子网掩码。


IPv4地址的最初定义中包含一个“类”,这个“类”由第一个八位组中的地址范围所定义。 ipaddress模块不识别IPv4类,故在本教程中不会涉及。


ipaddress模块包含三个特定的IPv4地址对象类型:


  • 一个“主机”,或一个不包含CIDR表示法的独立的地址对象

  • 包含CIDR表示法的单个接口地址对象

  • 以及一个网络地址对象,指的是整个网络的IP地址范围。


“主机”和“接口”之间的主要区别在于主机或ip_address对象不包含CIDR表示法,而ip_interface对象包含CIDR表示法:


  • 处理不需要或不使用CIDR表示法的IP数据包时,ip_address对象最为有用。

  • 当使用节点和接口标识来连接到必须包含网络/子网标识的IP网络时,ip_interface对象最管用。

  • ip_network对象包含网络中的所有地址,并且对于网络标识非常有用。


用ipaddress创建IPv4主机地址对象

ipaddress.ip_address() 工厂函数用于创建ip_address对象。它会根据传入的值自动确定是创建IPv4还是IPv6地址(IPv6地址将在本教程的后面部分讨论)。 如上所述,这个对象表示一个数据包在穿越不需要CIDR的网络的过程中,所发现的IP地址。


在多数情况下,用于创建ip_address对象的值将是一个字符串,格式为IPv4点分十进制,如图所示:

image.png

或者,IPv4地址可以以二进制形式输入,如完整32位二进制值的十进制值,或按照此例,以十六进制格式输入:

image.png

第一个例子使用完整的32位地址,第二个例子是32位地址的十进制值。 两者都很笨拙,容易出错且没什么太大的价值。 第三个示例使用十六进制值,这可能很有用,因为解析或嗅探中的大多数数据包,都以十六进制格式表示。

用ipaddress创建IPv4接口地址对象

ipaddress.ip_interface() 工厂函数用于创建ip_interface对象,该对象根据传入的值自动确定是创建IPv4还是IPv6地址(IPv6地址将在本教程的后面部分讨论)。


如前所述,ip_interface对象表示在正确处理数据包所需的CIDR(或掩码)所在的主机或网络接口上找到的IP地址。


image.png

在创建ip_interface选项时可以使用与ip_address选项(二进制,十进制值,十六进制)相同的选项。 但是,唯一通过CIDR表示法或掩码来有效创建ip_interface的办法,是使用点分十进制IPv4地址字符串。


用ipaddress创建IPv4网络地址对象

ipaddress.ip_network()工厂函数用于创建ip_network对象,该对象根据传入的值自动确定是创建IPv4还是IPv6地址(IPv6地址将在本教程的后面部分讨论)。


IP网络定义:包括了一个网络或子网的连续IP地址范围。 例如:


  • 192.168.100.0/24是192.168.100.0网络,其中/24指定前3个八位组组构成网络标识。

  • 第4个八位组用于分配给各个主机和路由器接口。

  • 地址范围是192.168.100.1到.254。

  • 192.168.100.0用于定义网络/子网,192.168.100.255是该网络的广播地址。 它们都不能用于分配给主机或路由器接口。


创建ip_network对象遵循与创建ip_interface对象相同的语法:


image.png


在上面的例子中,使用的网络地址必须是一个有效的网络地址,它是构成网络的IPv4地址范围中的第一个地址。 否则,Python将抛出一个异常:

image.png


在使用主机或路由器接口时,通常需要确定网络地址。 可以经由计算得出,但是需要几个步骤,可以使用strict = False选项(strict = True是默认值)在一个步骤中完成。


image.png

在上面的例子中,ip_interface地址是已知的(192.168.100.10),但不是接口所属的ip_network。 使用strict = False选项,计算ip_network地址(192.168.100.0/24)并将其填充到ip_network对象中。


Python的ipaddress模块,和IPv6地址

与IPv4一样,ipaddress模块使用与IPv4相同的三种基本工厂功能。 包括:


  1. 一个“主机”,或一个不包含CIDR表示法的单独地址对象,

  2. 包含CIDR表示法的接口地址对象

  3. 以及引用整个网络的IP地址范围的网络地址对象。


由于详细信息在IPv4部分中已经介绍,在此仅作简要描述。


用ipaddress创建IPv6主机地址对象

ipaddress.ip_address() 工厂函数用于创建ip_address对象。 它会根据传入的值自动确定使用IPv6地址格式。 请注意,CIDR表示法未与ip_address函数一起使用。


在大多数情况下,用于为IPv6创建ip_address对象的值将是根据此示例的IPv6四进制/六进制格式的字符串:


image.png

与IPv4一样,可以使用完整的二进制,十进制或十六进制值创建IPv6地址对象。 对于IPv4地址,32位难以处理,而对于128位IPv6地址来说更是尴尬。 实际上,预计八个四重组表示的字符串将是一般形式。


用ipaddress创建IPv6接口地址对象

ipaddress.ip_interface() 工厂函数用于创建ip_interface对象,该对象根据传入的值自动创建IPv6地址。 请注意,函数中必须包含CIDR表示法。

image.png


用ipaddress创建IPv6网络地址对象

ipaddress.ip_network() 工厂函数用于根据传入的值为IPv6创建一个ip_network对象。


与IPv4一样,IPv6网络被定义为可分配给特定主机或路由器接口的一系列连续IP地址。


使用我们以前的示例2001:db8:abcd:100:: /64,/64 CIDR指定四个四重组构成完整的网络标识。 请记住,前三个四重组是IPS分配的全局ID,第四个四重组识别内部子网编号。 64位的余额用于从“0000:0000:0000:0001”到“ffff:ffff:ffff:fffe”的范围内的主机标识。


与IPv4寻址一样,IPv6子网中的第一个和最后一个地址不能用于主机寻址。 给定一个/ 64 CIDR,这意味着有2到64个功率(减2)可能的主机地址,这意味着每个网络/子网有18,446,744,073,709,551,614个数学上可能的主机地址。


image.png


293/5000上述全局地址划分如下:


  • 全局标识符由ISP分配:2001:db8:abcd::/48

  • 子网标识:2001:db8:abcd:100:: / 64

  • 子网中的第一个可用地址:2001:db8:abcd:100:: 1/64

  • 子网中最后一个可用地址:2001:db8:abcd:100:ffff:ffff:ffff:fffeffff / 64

更多资源

这里是一些额外的资源,以便你进一步了解Python中的ipaddress模块:


本文的扩展PDF版本以及其他信息https://dbader.org/static/img/ipaddress-module-introduction.pdf 

ipaddress模块文档https://docs.python.org/3/library/ipaddress.html 

ipaddress模块介绍https://docs.python.org/3/howto/ipaddress.html 

维基百科 - IPv4https://en.wikipedia.org/wiki/IPv4 

维基百科 - IPv6https://en.wikipedia.org/wiki/IPv6 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值