ipaddress模块介绍

    Peter Moody

    作者

    Nick Coghlan

    概述

    本文档旨在简要介绍 ipaddress 模块。 它主要针对那些不熟悉 IP 网络术语的用户,但也可能对想要速览 如何代表IP网络寻址概念的网络工程师有用。

    因为 ipaddress 是一个用于检查和操作 IP 地址的模块,你要做的第一件事就是创建一些对象。 您可以使用 从字符串和整数创建对象。

    对于不太熟悉 IP 寻址的读者,重要的是要知道 Internet 协议当前正在从协议的版本4转移到版本6。转换很大程度上是因为协议的版本4没有提供足够的地址来满足整个世界的需求,特别是考虑到越来越多的设备直接连接到互联网。

    解释协议的两个版本之间的差异的细节超出了本介绍的范围,但读者需要至少知道存在这两个版本,并且有时需要强制使用一个版本或其他版本。

    通常称为“主机地址”的地址是使用IP寻址时最基本的单元。 创建地址的最简单方法是使用 ipaddress.ip_address() 工厂函数,该函数根据传入的值自动确定是创建 IPv4 还是 IPv6 地址:

    地址也可以直接从整数创建,适配32位的值并假定为IPv4地址:

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

    要强制使用IPv4或IPv6地址,可以直接调用相关的类。 这对于强制为小整数创建IPv6地址特别有用:

    1. >>> ipaddress.ip_address(1)
    2. IPv4Address('0.0.0.1')
    3. >>> ipaddress.IPv4Address(1)
    4. IPv4Address('0.0.0.1')
    5. >>> ipaddress.IPv6Address(1)
    6. IPv6Address('::1')

    对于地址,提供了一个自动确定正确IP版本的工厂函数:

    1. >>> ipaddress.ip_network('192.0.2.0/24')
    2. IPv4Network('192.0.2.0/24')
    3. >>> ipaddress.ip_network('2001:db8::0/96')
    4. IPv6Network('2001:db8::/96')

    网络对象不能设置任何主机位。 这样做的实际效果是``192.0.2.1/24``没有描述网络。 这种定义被称为接口对象,因为网络上IP表示法通常用于描述给定网络上的计算机的网络接口,并在下一节中进一步描述。

    默认情况下,尝试创建一个设置了主机位的网络对象将导致 被引发。 要请求将附加位强制为零,可以将标志``strict=False`` 传递给构造函数:

    1. >>> ipaddress.ip_network('192.0.2.1/24')
    2. Traceback (most recent call last):
    3. ...
    4. ValueError: 192.0.2.1/24 has host bits set
    5. >>> ipaddress.ip_network('192.0.2.1/24', strict=False)
    6. IPv4Network('192.0.2.0/24')

    虽然字符串形式提供了更大的灵活性,但网络也可以用整数定义,就像主机地址一样。 在这种情况下,网络被认为只包含由整数标识的单个地址,因此网络前缀包括整个网络地址:

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

    与地址一样,可以通过直接调用类构造函数而不是使用工厂函数来强制创建特定类型的网络。

    如上所述,如果您需要描述特定网络上的地址,则地址和网络类都不够。 像 192.0.2.1/24 这样的表示法通常被网络工程师和为防火墙和路由器编写工具的人用作“ 192.0.2.0/24 网络上的主机 192.0.2.1 ”的简写。因此,ipaddress 提供了一组将地址与特定网络相关联的混合类。用于创建的接口与用于定义网络对象的接口相同,除了地址部分不限于是网络地址。

    接受整数输入(与网络一样),并且可以通过直接调用相关构造函数来强制使用特定IP版本。

    审查 Address/Network/Interface 对象

    你已经遇到了创建IPv(4|6)(Address|Network|Interface) 对象的麻烦,因此你可能希望获得有关它的信息。 ipaddress 试图让这个过程变得简单直观。

    提取 IP 版本:

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

    从接口获取网络:

    1. >>> host4 = ipaddress.ip_interface('192.0.2.1/24')
    2. >>> host4.network
    3. IPv4Network('192.0.2.0/24')
    4. >>> host6 = ipaddress.ip_interface('2001:db8::1/96')
    5. >>> host6.network
    6. IPv6Network('2001:db8::/96')

    找出网络中有多少独立地址:

    1. >>> net4 = ipaddress.ip_network('192.0.2.0/24')
    2. >>> net4.num_addresses
    3. 256
    4. >>> net6 = ipaddress.ip_network('2001:db8::0/96')
    5. >>> net6.num_addresses
    6. 4294967296
    1. >>> net4 = ipaddress.ip_network('192.0.2.0/24')
    2. >>> for x in net4.hosts():
    3. ... print(x)
    4. 192.0.2.1
    5. 192.0.2.2
    6. 192.0.2.3
    7. 192.0.2.4
    8. ...
    9. 192.0.2.252
    10. 192.0.2.253
    11. 192.0.2.254

    获取网络掩码(即对应于网络前缀的设置位)或主机掩码(不属于网络掩码的任何位):

    1. >>> net4 = ipaddress.ip_network('192.0.2.0/24')
    2. >>> net4.netmask
    3. >>> net4.hostmask
    4. >>> net6 = ipaddress.ip_network('2001:db8::0/96')
    5. >>> net6.netmask
    6. IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::')
    7. >>> net6.hostmask
    8. IPv6Address('::ffff:ffff')

    展开或压缩地址:

    虽然IPv4不支持展开或压缩,但关联对象仍提供相关属性,因此版本中性代码可以轻松确保最简洁或最详细的形式用于IPv6地址,同时仍能正确处理IPv4地址。

    将网络视为列表有时很有用。 这意味着它可以像这样索引它们:

    1. >>> net4[1]
    2. IPv4Address('192.0.2.1')
    3. >>> net4[-1]
    4. IPv4Address('192.0.2.255')
    5. >>> net6[1]
    6. IPv6Address('2001:db8::1')
    7. >>> net6[-1]
    8. IPv6Address('2001:db8::ffff:ffff')

    它还意味着网络对象可以使用像这样的列表成员测试语法:

    1. if address in network:
    2. # do something

    根据网络前缀有效地完成包含性测试:

    1. >>> addr4 = ipaddress.ip_address('192.0.2.1')
    2. >>> addr4 in ipaddress.ip_network('192.0.2.0/24')
    3. True
    4. >>> addr4 in ipaddress.ip_network('192.0.3.0/24')
    5. False

    比较运算

    ipaddress 有意义地提供了一些简单、希望直观的比较对象的方法:

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

    如果你尝试比较不同版本或不同类型的对象,则会引发 异常。

    其他使用IP地址的模块(例如 socket )通常不会直接接受来自该模块的对象。 相反,它们必须被强制转换为另一个模块可接受的整数或字符串:

    1. >>> addr4 = ipaddress.ip_address('192.0.2.1')
    2. >>> str(addr4)
    3. '192.0.2.1'
    4. >>> int(addr4)
    5. 3221225985

    实例创建失败时获取更多详细信息

    使用与版本无关的工厂函数创建 address/network/interface 对象时,任何错误都将报告为 ValueError ,带有一般错误消息,只是说传入的值未被识别为该类型的对象。 缺少特定错误是因为有必要知道该值是假设是IPv4还是IPv6,以便提供有关其被拒绝原因的更多详细信息。

    为了支持访问这些额外细节的用例,各个类构造函数实际上引发了 子类 ipaddress.AddressValueError 和 以准确指示定义的哪一部分无法正确解析。

    但是,两个模块特定的异常都有 ValueError 作为它们的父类,所以如果你不关心特定类型的错误,你仍然可以编写如下代码:

    1. try:
    2. network = ipaddress.IPv4Network(address)