杰瑞科技汇

Python netaddr如何高效使用?

安装 netaddr

你需要安装这个库,使用 pip 非常简单:

Python netaddr如何高效使用?-图1
(图片来源网络,侵删)
pip install netaddr

核心概念

netaddr 主要处理三种核心对象:

  1. IP 地址 (IPAddress): 代表一个单独的 IPv4 或 IPv6 地址,168.1.1
  2. IP 网络 (IPNetwork): 代表一个 IP 地址范围,通常由一个网络地址和子网掩码(或前缀长度)定义,168.1.0/24,这个网络包含了从 168.1.1168.1.254 的所有可用主机地址。
  3. MAC 地址 (EUI): 代表一个物理硬件地址,00:11:22:AA:BB:CC

IPAddress (IP 地址) 使用

1 创建和基本属性

from netaddr import IPAddress, IPNetwork
# 创建一个 IPv4 地址
ip_v4 = IPAddress('192.168.1.1')
print(f"IP 地址: {ip_v4}")
print(f"版本: {ip_v4.version}")  # 4 代表 IPv4
print(f"是否是私有地址: {ip_v4.is_private()}")
print(f"是否是公网地址: {ip_v4.is_public()}")
print(f"十六进制格式: {ip_v4.hex}")
print(f"十进制格式: {int(ip_v4)}")
# 创建一个 IPv6 地址
ip_v6 = IPAddress('2001:db8::1')
print(f"\nIP 地址: {ip_v6}")
print(f"版本: {ip_v6.version}")  # 6 代表 IPv6

2 地址比较

IPAddress 对象支持标准的比较运算符(<, >, , , <=, >=),比较的是地址的数值大小。

ip1 = IPAddress('10.0.0.1')
ip2 = IPAddress('10.0.0.2')
print(f"\n地址比较:")
print(f"ip1 < ip2: {ip1 < ip2}")  # True
print(f"ip1 > ip2: {ip1 > ip2}")  # False
print(f"ip1 == IPAddress('10.0.0.1'): {ip1 == IPAddress('10.0.0.1')}") # True

3 地址操作

可以方便地对地址进行加减操作,这会改变其数值。

print(f"\n地址操作:")
ip = IPAddress('192.168.1.10')
print(f"原始地址: {ip}")
# 加 1
next_ip = ip + 1
print(f"下一个地址: {next_ip}") # 192.168.1.11
# 减 1
prev_ip = ip - 1
print(f"上一个地址: {prev_ip}") # 192.168.1.9

IPNetwork (IP 网络) 使用

这是 netaddr 最强大的部分之一。

1 创建和基本属性

# 创建一个网络
network = IPNetwork('192.168.1.0/24')
print(f"\n网络信息:")
print(f"网络: {network}")
print(f"网络地址: {network.network}")  # 192.168.1.0
print(f"广播地址: {network.broadcast}") # 192.168.1.255
print(f"子网掩码: {network.netmask}")   # 255.255.255.0
print(f"反掩码: {network.hostmask}")   # 0.0.0.255
print(f"前缀长度: {network.prefixlen}") # 24
print(f"网络中的 IP 数量: {network.size}") # 256

2 获取网络中的主机地址

.hosts() 是一个非常实用的生成器,它会返回网络中所有可用的主机地址(排除了网络地址和广播地址)。

print(f"\n网络中的主机地址:")
for i, host in enumerate(network.hosts()):
    if i < 5:  # 只打印前5个
        print(host)
    else:
        break
print("...")
# 也可以直接转换为列表
# all_hosts = list(network.hosts())

3 网络划分

这是 netaddr 的王牌功能,你可以轻松地将一个大网络划分为多个小网络。

print(f"\n网络划分:")
# 将 /24 网络划分为 4 个 /26 子网
supernet = IPNetwork('192.168.1.0/24')
subnets = supernet.subnet(new_prefix=26)
print(f"将 {supernet} 划分为 /26 子网:")
for subnet in subnets:
    print(subnet)

4 网络聚合

与划分相反,你可以将多个小的网络合并(聚合)成一个大的网络,这在处理路由表时非常有用。

print(f"\n网络聚合:")
nets_to_aggregate = [
    IPNetwork('192.168.1.0/25'),
    IPNetwork('192.168.1.128/25')
]
# 使用 cidr_sum() 进行聚合
aggregated_net = IPNetwork.summarize_address_range(nets_to_aggregate[0].network, nets_to_aggregate[1].broadcast)
print(f"聚合 {nets_to_aggregate} 的结果:")
for net in aggregated_net:
    print(net)

更常见的聚合方式是使用 cidr_merge

from netaddr import cidr_merge
nets = [IPNetwork('192.168.1.0/25'), IPNetwork('192.168.1.128/25')]
merged = cidr_merge(nets)
print(f"使用 cidr_merge 合并结果: {list(merged)}")

5 判断地址是否属于网络

print(f"\n地址归属判断:")
ip_in_network = IPAddress('192.168.1.50')
ip_not_in_network = IPAddress('10.0.0.1')
print(f"地址 {ip_in_network} 是否属于网络 {network}: {ip_in_network in network}")
print(f"地址 {ip_not_in_network} 是否属于网络 {network}: {ip_not_in_network in network}")

EUI (MAC 地址) 使用

from netaddr import EUI
# 创建一个 MAC 地址
mac = EUI('00-11-22-AA-BB-CC')
print(f"\nMAC 地址信息:")
print(f"MAC: {mac}")
print(f"不带分隔符的格式: {mac.eui}") # 001122AABBCC
print(f"带有冒号的格式: {mac.mac}")   # 00:11:22:AA:BB:CC
# OUI (Organizationally Unique Identifier) 是 MAC 地址的前 24 位
print(f"OUI: {mac.oui}")
print(f"OUI 的十六进制: {mac.oui.hex}")
print(f"OUI 的厂商: {mac.oui.registration().org}") # 需要联网查询

实用技巧和高级功能

1 IP 地址范围

IPRange 可以表示一个连续的 IP 地址范围,并且可以方便地转换为网络列表。

from netaddr import IPRange, cidr_merge
# 创建一个 IP 范围
ip_range = IPRange('192.168.1.10', '192.168.1.20')
print(f"\nIP 范围: {ip_range}")
print(f"范围大小: {len(ip_range)}")
# 将范围转换为 CIDR 列表
cidrs_from_range = list(ip_range.cidrs())
print(f"范围对应的 CIDR: {cidrs_from_range}") # 通常是 /32 的列表
# 一个更复杂的范围
complex_range = IPRange('192.168.1.0', '192.168.1.255')
complex_cidrs = cidr_merge(complex_range.cidrs())
print(f"复杂范围合并后的 CIDR: {list(complex_cidrs)}") # [192.168.1.0/24]

2 IPSet

IPSet 是一个高性能的集合类,专门用于存储和操作大量的 IP 地址和网络,它内部使用 CIDR 优化存储,非常适合防火墙规则、IP 黑白名单等场景。

from netaddr import IPSet, IPNetwork, IPAddress
# 创建一个 IPSet
ipset = IPSet()
ipset.add(IPNetwork('192.168.1.0/24'))
ipset.add(IPAddress('10.0.0.1'))
ipset.add(IPNetwork('172.16.0.0/16'))
print(f"\nIPSet 内容: {ipset}")
# 检查地址是否在集合中
print(f"'192.168.1.5' 在 IPSet 中吗? {'192.168.1.5' in ipset}")
print(f"'8.8.8.8' 在 IPSet 中吗? {'8.8.8.8' in ipset}")
# 从集合中移除
ipset.remove(IPNetwork('172.16.0.0/16'))
print(f"移除后 IPSet 内容: {ipset}")
# 集合运算
set1 = IPSet([IPNetwork('192.168.1.0/25')])
set2 = IPSet([IPNetwork('192.168.1.128/25')])
union_set = set1 | set2  # 并集
print(f"并集结果: {union_set}")
intersection_set = set1 & set2 # 交集
print(f"交集结果: {intersection_set}")

netaddr vs. Python ipaddress 模块

特性 netaddr Python ipaddress (标准库)
安装 pip install netaddr 内置于 Python 3.3+
API 风格 面向对象,功能丰富,API 直观 面向对象,更“Pythonic”
网络划分 network.subnet() 非常简单直接 需要使用 ipaddress.summarize_address_range 或手动计算,稍显复杂
网络聚合 cidr_merge() 功能强大 ipaddress.collapse_addresses() 功能相似
IPSet 有专门的 IPSet 类,性能高 无专门的集合类,用 set 存储对象
MAC 地址 有强大的 EUI
IP 范围 IPRange 无直接对应,需要自己处理
社区 活跃,但非官方 官方维护,稳定
  • 如果你需要快速、强大的网络操作,特别是子网划分和聚合,并且不介意安装第三方库,netaddr 是绝佳选择。
  • 如果你追求轻量级,不想安装任何依赖,并且项目使用的是 Python 3.3+,那么标准的 ipaddress 模块已经足够应对大多数基本需求。

对于网络管理员、运维工程师和网络安全开发者来说,netaddr 是一个非常值得学习和掌握的工具。

分享:
扫描分享到社交APP
上一篇
下一篇