ipnet这个第三方crate提供了处理 IPv4/IPv6 相关的有用方法
使用ipnet ="2.9.0"版本
创建网络地址并打印主机掩码和网络掩码
1 | use ipnet::{IpNet, Ipv4Net, Ipv6Net}; |
一个ipv4地址是10.1.1.0/24,其hostmask和netmask各为多少?
对一个ipv4地址10.1.1.0/24进行解析:
/24表示子网掩码长度为24个1,即以二进制表示子网掩码是:11111111.11111111.11111111.00000000
即对应的子网掩码(netmask)为:255.255.255.0
而主机掩码计算方法是: 取反后的子网掩码
即:00000000.00000000.00000000.11111111
即 对应的主机掩码(hostmask)为: 0.0.0.255
将现有 IP 网络细分为更小的子网
下面的例子 是把一个 /23 的网段,划分成多个 /25 的小网段
需要先理解为什么要做这样的操作:
将一个 /23 网段划分成多个 /25 网段意味着 要把一个较大的网络地址范围划分成几个较小的子网。每个子网有更少的可用IP地址,但能支持更多的独立网络。
/23 网段:表示子网掩码有23个连续的1,剩下的9位用于主机地址。这意味着这个网段有 (2^{9} = 512) 个可用IP地址。
/25 网段:表示子网掩码有25个连续的1,剩下的7位用于主机地址。这意味着这个网段有 (2^{7} = 128) 个可用IP地址。
举例:
假设有一个 /23 网段 192.168.0.0/23。这个网段的IP地址范围是从 192.168.0.0`` 到 192.168.1.255`,总共512个地址。
现在想把这个网段划分成几个 /25 网段。每个 /25 网段有128个地址,所以可以从192.168.0.0/23 网段中划分出4个 /25 网段,它们的地址范围如下:
- 第一个 /25 网段:
192.168.0.0/25,范围是192.168.0.0 - 192.168.0.127 - 第二个 /25 网段:
192.168.0.128/25,范围是192.168.0.128 - 192.168.0.255 - 第三个 /25 网段:
192.168.1.0/25,范围是192.168.1.0 - 192.168.1.127 - 第四个 /25 网段:
192.168.1.128/25,范围是192.168.1.128 - 192.168.1.255
每个这样的子网可以用于不同的网络,允许更细致的网络控制和管理。
1 | use ipnet::Ipv4Net; |
迭代两个 IPv4 地址之间的有效子网
下面的例子,是 获取两个ipv4地址10.0.0.0和10.0.0.239之间的有效子网
1 | use ipnet::Ipv4Subnets; |
上面这段 Rust 程序的目的是找出从 10.0.0.0 到 10.0.0.239 的所有有效子网。这里的关键在于理解“有效子网”的含义,以及为什么程序从 /25 开始。
有效子网:有效子网是指能够包含起始和结束IP地址(这里是
10.0.0.0到10.0.0.239)的最小子网。换句话说,子网不应超过结束地址10.0.0.239。从
/25开始:10.0.0.0/25覆盖从10.0.0.0到10.0.0.127的地址。没有超出,而如果是10.0.0.0/24则从10.0.0.0到10.0.0.255,超过了10.0.0.239
该程序通过列出不同大小的子网来实现这一点,从 /25 开始,因为 /24 或更大的子网(比如 /23、/22 等)将包括比 10.0.0.239 更高的地址。
程序的输出显示了从 10.0.0.0/25 开始到能够覆盖 10.0.0.239 为止的所有子网。这包括 /25, /26, /27, /28 的子网,因为每一个都是在尝试找到一个更小的子网来覆盖这个范围。
10.0.0.128/26的范围是从哪到哪?
10.0.0.128/26对应的子网地址范围如下:
子网掩码(netmask): 255.255.255.192
或者子网掩码长度: 26
网络地址: 10.0.0.128
首个主机地址: 10.0.0.129
最后一个主机地址: 10.0.0.190
广播地址: 10.0.0.191
所以:
10.0.0.128/26的ip地址范围是:
从10.0.0.129到10.0.0.190
计算方法:
- 网络地址 = 地址与子网掩码与运算结果
- 首个主机地址 = 网络地址 + 1
- 最后一个主机地址 = 网络地址 | 不与子网掩码匹配的位数全部为1
- 广播地址 = 最后一个主机地址 + 1
所以对于10.0.0.128/26来说,它划分出的地址范围就是10.0.0.129到10.0.0.190这63个可用的主机地址。
10.0.0.192/27的范围是从哪到哪?
10.0.0.192/27对应的子网范围如下:
子网掩码(netmask): 255.255.255.224
或者子网掩码长度: 27
网络地址: 10.0.0.192
首个主机地址: 10.0.0.193
最后一个主机地址: 10.0.0.198
广播地址: 10.0.0.199
所以:
10.0.0.192/27的IP地址范围是:
从10.0.0.193到10.0.0.198
计算方法同10.0.0.128/26一致:
- 网络地址 = 地址与子网掩码与运算结果
- 首个主机地址 = 网络地址 + 1
- 最后一个主机地址 = 网络地址 | 不与子网掩码匹配的位数全部为1
- 广播地址 = 最后一个主机地址 + 1
因此,10.0.0.192/27对应的地址范围就是从10.0.0.193开始,到10.0.0.198结束,共计6个可用主机IP地址。
10.0.0.224/28的范围是从哪到哪?
10.0.0.224/28对应的子网范围是:
子网掩码(netmask): 255.255.255.240
或者子网掩码长度: 28
网络地址: 10.0.0.224
首个主机地址: 10.0.0.225
最后一个主机地址: 10.0.0.230
广播地址: 10.0.0.231
所以,10.0.0.224/28的IP地址范围是:
从10.0.0.225到10.0.0.230
计算方法同前两例:
- 网络地址 = 地址与子网掩码与运算结果
- 首个主机地址 = 网络地址 + 1
- 最后一个主机地址 = 网络地址 | 不与子网掩码匹配的位数全部为1
- 广播地址 = 最后一个主机地址 + 1
因此,10.0.0.224/28对应的子网范围就是从10.0.0.225开始,到10.0.0.230结束,共计6个主机IP地址。
总结来说,给出一个子网地址和掩码长度,就可以通过简单计算得出其对应的有效IP地址范围。
聚合(汇总) (包含重叠和相邻前缀的)IP 前缀列表
1 | use ipnet::IpNet; |
以上 Rust 代码演示了如何对一组 IPv4 和 IPv6 地址前缀进行聚合。聚合的目的是简化和优化 IP 地址的表示,通过将重叠和相邻的网络前缀合并成更大的单个网络前缀来减少总数。这对于路由表的优化特别有用。
其中,
输入字符串列表:
let strings = vec![...]: 定义一个包含多个 CIDR 表示法的 IP 网络前缀的字符串向量。这些前缀可能重叠或相邻。
字符串解析为
IpNet对象:let nets: Vec<IpNet> = strings.iter().filter_map(|p| p.parse().ok()).collect();: 这行代码遍历字符串向量,尝试将每个字符串解析为IpNet对象。filter_map结合parse().ok()用于过滤出有效的解析结果并收集它们到一个新的IpNet对象向量中。
聚合 IP 前缀:
IpNet::aggregate(&nets): 这个方法调用将输入的IpNet对象向量进行聚合。聚合的结果是一个新的IpNet向量,其中包含了优化后的、更少数量的网络前缀。
打印聚合后的结果:
for n in IpNet::aggregate(&nets) { println!("\t{}", n); }: 这段代码遍历聚合后的IpNet对象并打印它们。这些打印出来的网络前缀是原始输入的优化版本,包含了最少量的不重叠且不相邻的网络前缀。
对于输出的结果:
输出显示了聚合过程的结果,其中合并了重叠和相邻的前缀。例如,
10.0.0.0/24和10.0.1.0/24被聚合成10.0.0.0/23,因为它们是相邻的前缀,可以用一个更大的前缀来表示。对于 IPv6 地址,
fd00::/32和fd00:1::/32被聚合成fd00::/31。
通过这种方式,代码有效地减少了所需处理的网络前缀的数量,这在管理大型网络时尤其有用。
原文链接: https://dashen.tech/2017/01/08/Rust-ipnet库的使用/
版权声明: 转载请注明出处.