krisprice/ipnet

GitHub: krisprice/ipnet

这是一个用于 Rust 的 IP 网络地址处理库,扩展了标准库以支持 IPv4/IPv6 前缀、子网划分、地址遍历及路由聚合等高级操作。

Stars: 160 | Forks: 39

[![构建状态](https://travis-ci.org/krisprice/ipnet.svg?branch=master)](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, 位运算, 内核驱动, 前缀, 可视化界面, 地址范围, 子网, 开发库, 标准库扩展, 系统编程, 网段, 网络协议, 网络安全, 网络流量审计, 网络编程, 网络计算, 迭代器, 通知系统, 隐私保护