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

pip install netaddr
核心概念
netaddr 主要处理三种核心对象:
- IP 地址 (
IPAddress): 代表一个单独的 IPv4 或 IPv6 地址,168.1.1。 - IP 网络 (
IPNetwork): 代表一个 IP 地址范围,通常由一个网络地址和子网掩码(或前缀长度)定义,168.1.0/24,这个网络包含了从168.1.1到168.1.254的所有可用主机地址。 - 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 是一个非常值得学习和掌握的工具。
