mirror of
https://github.com/ktims/rs-aggregate.git
synced 2025-07-03 19:42:30 -07:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
16284f4d95
|
|||
7c74cd6f7a
|
|||
675cda945f
|
|||
4897aad492
|
|||
498c509e70
|
|||
5190e83bb3
|
|||
59bad102c7
|
|||
f4aa49abee
|
|||
be7bab4fa9
|
|||
9588b7f0df
|
|||
d625a6ec07
|
6
.github/workflows/commit.yml
vendored
6
.github/workflows/commit.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Build
|
- name: Build tests
|
||||||
run: cargo build --verbose
|
run: cargo test --no-run --verbose
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose
|
run: cargo test
|
||||||
|
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@ -2,6 +2,9 @@ on:
|
|||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: release ${{ matrix.target }}
|
name: release ${{ matrix.target }}
|
||||||
@ -24,4 +27,11 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
RUSTTARGET: ${{ matrix.target }}
|
RUSTTARGET: ${{ matrix.target }}
|
||||||
ARCHIVE_TYPES: ${{ matrix.archive }}
|
ARCHIVE_TYPES: ${{ matrix.archive }}
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Binary
|
||||||
|
path: |
|
||||||
|
${{ steps.compile.outputs.BUILT_ARCHIVE }}
|
||||||
|
${{ steps.compile.outputs.BUILT_CHECKSUM }}
|
92
Cargo.lock
generated
92
Cargo.lock
generated
@ -61,9 +61,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d5dd14596c0e5b954530d0e6f1fd99b89c03e313aa2086e8da4303701a09e1cf"
|
checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
@ -91,11 +91,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.1.11"
|
version = "4.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098"
|
checksum = "76e21918af71fb4bcd813230cf549e33d14f73d0326b932b630ce2930332b131"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.0.1",
|
"bitflags 2.0.2",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"is-terminal",
|
"is-terminal",
|
||||||
@ -106,15 +106,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.1.9"
|
version = "4.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644"
|
checksum = "9a932373bab67b984c790ddf2c9ca295d8e3af3b7ef92de5a5bacdccdee4b09b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -256,7 +255,7 @@ checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -365,9 +364,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.8"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dd6da19f25979c7270e70fa95ab371ec3b701cd0eefc47667a09785b3c59155"
|
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
@ -466,9 +465,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.4.1"
|
version = "6.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
@ -513,35 +512,11 @@ dependencies = [
|
|||||||
"termtree",
|
"termtree",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.52"
|
version = "1.0.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
|
checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@ -566,9 +541,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.7.1"
|
version = "1.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -583,13 +558,13 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.28"
|
version = "0.6.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rs-aggregate"
|
name = "rs-aggregate"
|
||||||
version = "0.2.0"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"assert_fs",
|
"assert_fs",
|
||||||
@ -624,7 +599,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn",
|
"syn 1.0.109",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -639,9 +614,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.36.10"
|
version = "0.36.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2fe885c3a125aa45213b68cc1472a49880cb5923dc23f522ad2791b882228778"
|
checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"errno",
|
"errno",
|
||||||
@ -668,9 +643,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.157"
|
version = "1.0.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca"
|
checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
@ -698,6 +673,17 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
@ -742,12 +728,6 @@ version = "1.0.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wait-timeout"
|
name = "wait-timeout"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rs-aggregate"
|
name = "rs-aggregate"
|
||||||
version = "0.2.0"
|
version = "0.2.2"
|
||||||
authors = ["Keenan Tims <ktims@gotroot.ca>"]
|
authors = ["Keenan Tims <ktims@gotroot.ca>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Aggregate a list of IP prefixes into their minimum equivalent representation"
|
description = "Aggregate a list of IP prefixes into their minimum equivalent representation"
|
||||||
@ -8,6 +8,11 @@ readme = "README.md"
|
|||||||
repository = "https://github.com/ktims/rs-aggregate"
|
repository = "https://github.com/ktims/rs-aggregate"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
categories = ["network-programming"]
|
categories = ["network-programming"]
|
||||||
|
exclude = [
|
||||||
|
".github/*",
|
||||||
|
"doc/*",
|
||||||
|
"test-data/*",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.1.8", features = ["derive"] }
|
clap = { version = "4.1.8", features = ["derive"] }
|
||||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Keenan Tims
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -18,7 +18,7 @@ Takes a list of whitespace-separated IPs or IP networks and aggregates them to t
|
|||||||
Performance comparison of `rs-aggregate` vs `aggregate6`. A speedup of >100x is achieved on DFZ data.
|
Performance comparison of `rs-aggregate` vs `aggregate6`. A speedup of >100x is achieved on DFZ data.
|
||||||
|
|
||||||
Full DFZ (1154968 total, 202729 aggregates):
|
Full DFZ (1154968 total, 202729 aggregates):
|
||||||

|

|
||||||
|
|
||||||
IPv4 DFZ (968520 total, 154061 aggregates):
|
IPv4 DFZ (968520 total, 154061 aggregates):
|
||||||

|

|
BIN
doc/perfcomp_all.png
Normal file
BIN
doc/perfcomp_all.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
doc/perfcomp_v4.png
Normal file
BIN
doc/perfcomp_v4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
109
src/iputils.rs
109
src/iputils.rs
@ -19,7 +19,7 @@ impl IpBothRange {
|
|||||||
IpBothRange::default()
|
IpBothRange::default()
|
||||||
}
|
}
|
||||||
pub fn add(&mut self, net: IpOrNet) {
|
pub fn add(&mut self, net: IpOrNet) {
|
||||||
match net.net {
|
match net.0 {
|
||||||
IpNet::V4(v4_net) => drop(self.v4.add(v4_net)),
|
IpNet::V4(v4_net) => drop(self.v4.add(v4_net)),
|
||||||
IpNet::V6(v6_net) => drop(self.v6.add(v6_net)),
|
IpNet::V6(v6_net) => drop(self.v6.add(v6_net)),
|
||||||
}
|
}
|
||||||
@ -38,6 +38,17 @@ impl IpBothRange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for IpBothRange {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for ip in self {
|
||||||
|
ip.fmt(f)?;
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct IpBothRangeIter<'a> {
|
pub struct IpBothRangeIter<'a> {
|
||||||
v4_iter: IpRangeIter<'a, Ipv4Net>,
|
v4_iter: IpRangeIter<'a, Ipv4Net>,
|
||||||
v6_iter: IpRangeIter<'a, Ipv6Net>,
|
v6_iter: IpRangeIter<'a, Ipv6Net>,
|
||||||
@ -79,9 +90,7 @@ impl<'a> IntoIterator for &'a IpBothRange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct IpOrNet {
|
pub struct IpOrNet(IpNet);
|
||||||
pub net: IpNet,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NetParseError {
|
pub struct NetParseError {
|
||||||
@ -102,33 +111,29 @@ impl IpOrNet {
|
|||||||
// netmask - 1.1.1.0/255.255.255.0
|
// netmask - 1.1.1.0/255.255.255.0
|
||||||
// wildcard mask - 1.1.1.0/0.0.0.255
|
// wildcard mask - 1.1.1.0/0.0.0.255
|
||||||
fn parse_mask(p: &str) -> Result<u8, Box<dyn Error>> {
|
fn parse_mask(p: &str) -> Result<u8, Box<dyn Error>> {
|
||||||
let mask = p.parse::<Ipv4Addr>();
|
let mask = p.parse::<Ipv4Addr>()?;
|
||||||
match mask {
|
let intrep: u32 = mask.into();
|
||||||
Ok(mask) => {
|
let lead_ones = intrep.leading_ones();
|
||||||
let intrep: u32 = mask.into();
|
if lead_ones > 0 {
|
||||||
let lead_ones = intrep.leading_ones();
|
if lead_ones + intrep.trailing_zeros() == 32 {
|
||||||
if lead_ones > 0 {
|
Ok(lead_ones.try_into()?)
|
||||||
if lead_ones + intrep.trailing_zeros() == 32 {
|
} else {
|
||||||
Ok(lead_ones.try_into()?)
|
Err(Box::new(NetParseError {
|
||||||
} else {
|
msg: "Invalid subnet mask".to_owned(),
|
||||||
Err(Box::new(NetParseError {
|
}))
|
||||||
msg: "Invalid subnet mask".to_owned(),
|
}
|
||||||
}))
|
} else {
|
||||||
}
|
let lead_zeros = intrep.leading_zeros();
|
||||||
} else {
|
if lead_zeros + intrep.trailing_ones() == 32 {
|
||||||
let lead_zeros = intrep.leading_zeros();
|
Ok(lead_zeros.try_into()?)
|
||||||
if lead_zeros + intrep.trailing_ones() == 32 {
|
} else {
|
||||||
Ok(lead_zeros.try_into()?)
|
Err(Box::new(NetParseError {
|
||||||
} else {
|
msg: "Invalid wildcard mask".to_owned(),
|
||||||
Err(Box::new(NetParseError {
|
}))
|
||||||
msg: "Invalid wildcard mask".to_owned(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => Err(Box::new(e)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_parts(ip: &str, pfxlen: &str) -> Result<Self, Box<dyn Error>> {
|
fn from_parts(ip: &str, pfxlen: &str) -> Result<Self, Box<dyn Error>> {
|
||||||
let ip = ip.parse::<IpAddr>()?;
|
let ip = ip.parse::<IpAddr>()?;
|
||||||
let pfxlenp = pfxlen.parse::<u8>();
|
let pfxlenp = pfxlen.parse::<u8>();
|
||||||
@ -147,13 +152,25 @@ impl IpOrNet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn prefix_len(&self) -> u8 {
|
pub fn prefix_len(&self) -> u8 {
|
||||||
self.net.prefix_len()
|
self.0.prefix_len()
|
||||||
}
|
}
|
||||||
pub fn is_ipv4(&self) -> bool {
|
pub fn is_ipv4(&self) -> bool {
|
||||||
self.net.network().is_ipv4()
|
match self.0 {
|
||||||
|
IpNet::V4(_) => true,
|
||||||
|
IpNet::V6(_) => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn is_ipv6(&self) -> bool {
|
pub fn is_ipv6(&self) -> bool {
|
||||||
self.net.network().is_ipv6()
|
match self.0 {
|
||||||
|
IpNet::V4(_) => false,
|
||||||
|
IpNet::V6(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn addr(&self) -> IpAddr {
|
||||||
|
self.0.addr()
|
||||||
|
}
|
||||||
|
pub fn network(&self) -> IpAddr {
|
||||||
|
self.0.network()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,47 +187,43 @@ impl FromStr for IpOrNet {
|
|||||||
|
|
||||||
impl Display for IpOrNet {
|
impl Display for IpOrNet {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.net.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IpNet> for IpOrNet {
|
impl From<IpNet> for IpOrNet {
|
||||||
fn from(net: IpNet) -> Self {
|
fn from(net: IpNet) -> Self {
|
||||||
IpOrNet { net }
|
IpOrNet(net)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IpAddr> for IpOrNet {
|
impl From<IpAddr> for IpOrNet {
|
||||||
fn from(addr: IpAddr) -> Self {
|
fn from(addr: IpAddr) -> Self {
|
||||||
IpOrNet { net: addr.into() }
|
IpOrNet(addr.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ipv4Net> for IpOrNet {
|
impl From<Ipv4Net> for IpOrNet {
|
||||||
fn from(net: Ipv4Net) -> Self {
|
fn from(net: Ipv4Net) -> Self {
|
||||||
IpOrNet { net: net.into() }
|
IpOrNet(net.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ipv6Net> for IpOrNet {
|
impl From<Ipv6Net> for IpOrNet {
|
||||||
fn from(net: Ipv6Net) -> Self {
|
fn from(net: Ipv6Net) -> Self {
|
||||||
IpOrNet { net: net.into() }
|
IpOrNet(net.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ipv4Addr> for IpOrNet {
|
impl From<Ipv4Addr> for IpOrNet {
|
||||||
fn from(addr: Ipv4Addr) -> Self {
|
fn from(addr: Ipv4Addr) -> Self {
|
||||||
IpOrNet {
|
IpOrNet(IpAddr::from(addr).into())
|
||||||
net: IpAddr::from(addr).into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ipv6Addr> for IpOrNet {
|
impl From<Ipv6Addr> for IpOrNet {
|
||||||
fn from(addr: Ipv6Addr) -> Self {
|
fn from(addr: Ipv6Addr) -> Self {
|
||||||
IpOrNet {
|
IpOrNet(IpAddr::from(addr).into())
|
||||||
net: IpAddr::from(addr).into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +247,7 @@ impl Display for PrefixlenPair {
|
|||||||
|
|
||||||
impl PartialEq<IpOrNet> for PrefixlenPair {
|
impl PartialEq<IpOrNet> for PrefixlenPair {
|
||||||
fn eq(&self, other: &IpOrNet) -> bool {
|
fn eq(&self, other: &IpOrNet) -> bool {
|
||||||
match other.net {
|
match other.0 {
|
||||||
IpNet::V4(net) => self.v4 == net.prefix_len(),
|
IpNet::V4(net) => self.v4 == net.prefix_len(),
|
||||||
IpNet::V6(net) => self.v6 == net.prefix_len(),
|
IpNet::V6(net) => self.v6 == net.prefix_len(),
|
||||||
}
|
}
|
||||||
@ -249,31 +262,31 @@ impl PartialEq<PrefixlenPair> for PrefixlenPair {
|
|||||||
|
|
||||||
impl PartialOrd<IpOrNet> for PrefixlenPair {
|
impl PartialOrd<IpOrNet> for PrefixlenPair {
|
||||||
fn ge(&self, other: &IpOrNet) -> bool {
|
fn ge(&self, other: &IpOrNet) -> bool {
|
||||||
match other.net {
|
match other.0 {
|
||||||
IpNet::V4(net) => self.v4 >= net.prefix_len(),
|
IpNet::V4(net) => self.v4 >= net.prefix_len(),
|
||||||
IpNet::V6(net) => self.v6 >= net.prefix_len(),
|
IpNet::V6(net) => self.v6 >= net.prefix_len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn gt(&self, other: &IpOrNet) -> bool {
|
fn gt(&self, other: &IpOrNet) -> bool {
|
||||||
match other.net {
|
match other.0 {
|
||||||
IpNet::V4(net) => self.v4 > net.prefix_len(),
|
IpNet::V4(net) => self.v4 > net.prefix_len(),
|
||||||
IpNet::V6(net) => self.v6 > net.prefix_len(),
|
IpNet::V6(net) => self.v6 > net.prefix_len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn le(&self, other: &IpOrNet) -> bool {
|
fn le(&self, other: &IpOrNet) -> bool {
|
||||||
match other.net {
|
match other.0 {
|
||||||
IpNet::V4(net) => self.v4 <= net.prefix_len(),
|
IpNet::V4(net) => self.v4 <= net.prefix_len(),
|
||||||
IpNet::V6(net) => self.v6 <= net.prefix_len(),
|
IpNet::V6(net) => self.v6 <= net.prefix_len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn lt(&self, other: &IpOrNet) -> bool {
|
fn lt(&self, other: &IpOrNet) -> bool {
|
||||||
match other.net {
|
match other.0 {
|
||||||
IpNet::V4(net) => self.v4 < net.prefix_len(),
|
IpNet::V4(net) => self.v4 < net.prefix_len(),
|
||||||
IpNet::V6(net) => self.v6 < net.prefix_len(),
|
IpNet::V6(net) => self.v6 < net.prefix_len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn partial_cmp(&self, other: &IpOrNet) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &IpOrNet) -> Option<std::cmp::Ordering> {
|
||||||
match other.net {
|
match other.0 {
|
||||||
IpNet::V4(net) => self.v4.partial_cmp(&net.prefix_len()),
|
IpNet::V4(net) => self.v4.partial_cmp(&net.prefix_len()),
|
||||||
IpNet::V6(net) => self.v6.partial_cmp(&net.prefix_len()),
|
IpNet::V6(net) => self.v6.partial_cmp(&net.prefix_len()),
|
||||||
}
|
}
|
||||||
|
40
src/main.rs
40
src/main.rs
@ -1,14 +1,18 @@
|
|||||||
extern crate ipnet;
|
extern crate ipnet;
|
||||||
extern crate iprange;
|
extern crate iprange;
|
||||||
|
|
||||||
|
use std::{process::exit, io};
|
||||||
|
|
||||||
mod iputils;
|
mod iputils;
|
||||||
use iputils::{IpBothRange, IpOrNet, PrefixlenPair};
|
use iputils::{IpBothRange, IpOrNet, PrefixlenPair};
|
||||||
|
|
||||||
use clio::*;
|
use clio::*;
|
||||||
use std::io::BufRead;
|
use std::io::{Write, BufRead};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
|
const WRITER_BUFSIZE: usize = 32 * 1024;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about=None)]
|
#[command(author, version, about, long_about=None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
@ -72,7 +76,7 @@ impl App {
|
|||||||
// Parser accepts host bits set, so detect that case and error if not truncate mode
|
// Parser accepts host bits set, so detect that case and error if not truncate mode
|
||||||
// Note: aggregate6 errors in this case regardless of -4, -6 so do the same
|
// Note: aggregate6 errors in this case regardless of -4, -6 so do the same
|
||||||
if !self.args.truncate {
|
if !self.args.truncate {
|
||||||
if pfx.net.addr() != pfx.net.network() {
|
if pfx.addr() != pfx.network() {
|
||||||
eprintln!("ERROR: '{}' is not a valid IP network, ignoring.", pfx);
|
eprintln!("ERROR: '{}' is not a valid IP network, ignoring.", pfx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -89,18 +93,22 @@ impl App {
|
|||||||
}
|
}
|
||||||
fn consume_input(&mut self, input: &mut Input) {
|
fn consume_input(&mut self, input: &mut Input) {
|
||||||
for line in input.lock().lines() {
|
for line in input.lock().lines() {
|
||||||
for net in line.unwrap().split_whitespace().to_owned() {
|
match line {
|
||||||
let pnet = net.parse::<IpOrNet>();
|
Ok(line) => {
|
||||||
match pnet {
|
for net in line.split_whitespace() {
|
||||||
Ok(pnet) => self.add_prefix(pnet),
|
let pnet = net.parse::<IpOrNet>();
|
||||||
Err(_e) => {
|
match pnet {
|
||||||
// self.errors.push(IpParseError {
|
Ok(pnet) => self.add_prefix(pnet),
|
||||||
// ip: net.to_string(),
|
Err(_e) => {
|
||||||
// problem: e.to_string(),
|
eprintln!("ERROR: '{}' is not a valid IP network, ignoring.", net);
|
||||||
// });
|
}
|
||||||
eprintln!("ERROR: '{}' is not a valid IP network, ignoring.", net);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("I/O error! {}", e);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,9 +125,11 @@ impl App {
|
|||||||
|
|
||||||
self.simplify_inputs();
|
self.simplify_inputs();
|
||||||
|
|
||||||
for net in &self.prefixes {
|
let stdout = io::stdout().lock();
|
||||||
println!("{}", net);
|
let mut w = io::BufWriter::with_capacity(WRITER_BUFSIZE, stdout);
|
||||||
}
|
|
||||||
|
write!(&mut w, "{}", self.prefixes).unwrap();
|
||||||
|
w.flush().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user