krisprice/ipnet
GitHub: krisprice/ipnet
这是一个用于 Rust 的 IP 网络地址处理库,扩展了标准库以支持 IPv4/IPv6 前缀、子网划分、地址遍历及路由聚合等高级操作。
Stars: 160 | Forks: 39
[](https://travis-ci.org/krisprice/ipnet)
本模块提供了用于处理 IPv4 和 IPv6 网络地址(通常称为 IP 前缀)的类型和实用方法。新增的 `IpNet`、`Ipv4Net` 和 `Ipv6Net` 类型建立在 Rust 标准库中已有的 `IpAddr`、`Ipv4Addr` 和 `Ipv6Addr` 类型之上,并与其设计保持一致以确保连贯性。
该模块还提供了 `IpSubnets`、`Ipv4Subnets` 和 `Ipv6Subnets` 类型,用于遍历 IP 地址范围内包含的子网;以及 `IpAddrRange`、`Ipv4AddrRange` 和 `Ipv6AddrRange` 类型,用于遍历范围内的 IP 地址。此外,它还提供了一些 trait,通过加法、减法、按位与和按位或操作扩展了 `Ipv4Addr` 和 `Ipv6Addr`,而这些操作在 Rust 标准库中是缺失的。
该模块仅使用稳定特性,因此保证可以使用 stable 工具链进行编译。测试旨在实现全面覆盖,可在测试模块和文档测试中找到。如果您有任何问题、请求或建议改进,请在 GitHub 上提交 [issue]。
阅读 [文档] 了解完整详情。并在 [Crates.io] 上查找它。
## 2.0 版本要求
2.0 版本要求 Rust 1.26 或更高版本。1.0 版本使用自定义模拟的 128 位整数类型(`Emu128`)来完全支持 IPv6 地址。这已被 Rust 内置的 128 位整数取代,该类型自 Rust 1.26 起已稳定。有报告称在某些目标平台(如 Emscripten)上使用 Rust 的 128 位整数存在问题。如果您在所选目标平台上遇到问题,在该问题解决之前,请继续使用 1.0 版本。
## 示例
### 创建一个网络地址并打印主机掩码和子网掩码
```
extern crate ipnet;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use ipnet::{IpNet, Ipv4Net, Ipv6Net};
fn main() {
// Create an Ipv4Net and Ipv6Net from their constructors.
let net4 = Ipv4Net::new(Ipv4Addr::new(10, 1, 1, 0), 24).unwrap();
let net6 = Ipv6Net::new(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24).unwrap();
// They can also be created by a constructor that panics when the prefix length is invalid,
let net4 = Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 1, 0), 24);
let net6 = Ipv6Net::new_assert(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24);
// or does not compile when called from a const context.
const NET4: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 1, 0), 24);
const NET6: Ipv6Net = Ipv6Net::new_assert(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24);
// They can also be created from string representations.
let net4 = Ipv4Net::from_str("10.1.1.0/24").unwrap();
let net6 = Ipv6Net::from_str("fd00::/24").unwrap();
// Or alternatively as follows.
let net4: Ipv4Net = "10.1.1.0/24".parse().unwrap();
let net6: Ipv6Net = "fd00::/24".parse().unwrap();
// IpNet can represent either an IPv4 or IPv6 network address.
let net = IpNet::from(net4);
// It can also be created from string representations.
let net = IpNet::from_str("10.1.1.0/24").unwrap();
let net: IpNet = "10.1.1.0/24".parse().unwrap();
// There are a number of methods that can be used. Read the
// documentation for the full details.
println!("{} hostmask = {}", net, net.hostmask());
println!("{} netmask = {}", net4, net4.netmask());
}
```
### 将现有 IP 网络划分为更小的子网
```
extern crate ipnet;
use ipnet::Ipv4Net;
fn main() {
let net: Ipv4Net = "192.168.0.0/23".parse().unwrap();
println!("\n/25 subnets in {}:", net);
// Note: `subnets()` returns a `Result`. If the given prefix length
// is less than the existing prefix length the `Result` will contain
// an error.
let subnets = net.subnets(25)
.expect("PrefixLenError: new prefix length cannot be shorter than existing");
// Output:
// subnet 0 = 192.168.0.0/25
// subnet 1 = 192.168.0.128/25
// subnet 2 = 192.168.1.0/25
// subnet 3 = 192.168.1.128/25
for (i, n) in subnets.enumerate() {
println!("\tsubnet {} = {}", i, n);
}
}
```
### 遍历两个 IPv4 地址之间的有效子网
```
extern crate ipnet;
use std::net::Ipv4Addr;
use ipnet::Ipv4Subnets;
fn main() {
let start = Ipv4Addr::new(10, 0, 0, 0);
let end = Ipv4Addr::new(10, 0, 0, 239);
println!("\n/0 or greater subnets between {} and {}:", start, end);
// Output all subnets starting with the largest that will fit. This
// will give us the smallest possible set of valid subnets.
//
// Output:
// subnet 0 = 10.0.0.0/25
// subnet 1 = 10.0.0.128/26
// subnet 2 = 10.0.0.192/27
// subnet 3 = 10.0.0.224/28
let subnets = Ipv4Subnets::new(start, end, 0);
for (i, n) in subnets.enumerate() {
println!("\tsubnet {} = {}", i, n);
}
println!("\n/26 or greater subnets between {} and {}:", start, end);
// Output all subnets with prefix lengths less than or equal to 26.
// This results in more subnets, but limits them to a maximum size.
//
// Output:
// subnet 0 = 10.0.0.0/26
// subnet 1 = 10.0.0.64/26
// subnet 2 = 10.0.0.128/26
// subnet 3 = 10.0.0.192/27
// subnet 4 = 10.0.0.224/28
let subnets = Ipv4Subnets::new(start, end, 26);
for (i, n) in subnets.enumerate() {
println!("\tsubnet {} = {}", i, n);
}
}
```
### 聚合 IP 前缀列表
```
extern crate ipnet;
use ipnet::IpNet;
fn main() {
// Example input list of overlapping and adjacent prefixes.
let strings = vec![
"10.0.0.0/24", "10.0.1.0/24", "10.0.1.1/24", "10.0.1.2/24",
"10.0.2.0/24",
"10.1.0.0/24", "10.1.1.0/24",
"192.168.0.0/24", "192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24",
"fd00::/32", "fd00:1::/32",
];
let nets: Vec = strings.iter().filter_map(|p| p.parse().ok()).collect();
println!("\nAggregated IP prefixes:");
// Output:
// 10.0.0.0/23
// 10.0.2.0/24
// 10.1.0.0/23
// 192.168.0.0/22
// fd00::/31
for n in IpNet::aggregate(&nets) {
println!("\t{}", n);
}
}
```
## 未来计划
* 为 `Ipv4Addr` 和 `Ipv6Addr` 实现 `std::ops::{Add, Sub, BitAnd, BitOr}` 将很有用,因为这些是 IP 地址的常见操作。如果实现,本模块提供的扩展 trait 将被移除,主版本号将会增加。实现这些功能需要更改标准库。我在 [Rust Internals](https://internals.rust-lang.org/t/pre-rfc-implementing-add-sub-bitand-bitor-for-ipaddr-ipv4addr-ipv6addr/) 讨论板上就此话题开启了一个主题。
* `hosts()` 以及可能的 `subnets()` 的结果应该表示为 `Range`,而不是本模块提供的自定义 `IpAddrRange` 和 `IpSubnets` 类型。这要求目标类型实现了 `Add` 和 `Step`。为 `IpAddr`、`Ipv4Addr` 和 `Ipv6Addr` 实现 `Add` 需要更改标准库(见上文)。此外 `Step` 仍然不稳定,因此探索该功能也将等到其稳定后再进行。
## 许可证
版权所有 (c) 2017,Juniper Networks, Inc. 保留所有权利。
本代码根据您选择的 MIT 许可证或 Apache License, Version 2.0(“许可证”)授权给您。除非遵守许可证,否则您不得使用此代码。本代码不是 Juniper 的官方产品。您可以在以下地址获取许可证副本:https://opensource.org/licenses/MIT 或 http://www.apache.org/licenses/LICENSE-2.0
标签:CIDR, Crates.io, IPv4, IPv6, IP地址, IP工具, PowerShell, Rust, 位运算, 内核驱动, 前缀, 可视化界面, 地址范围, 子网, 开发库, 标准库扩展, 系统编程, 网段, 网络协议, 网络安全, 网络流量审计, 网络编程, 网络计算, 迭代器, 通知系统, 隐私保护