use std::{collections::HashMap, env::args, error::Error, io::stderr}; use ip::{traits::PrefixSet as _, Any, Ipv4, Ipv6, Prefix, PrefixSet}; use irrc::{IrrClient, Query}; use rpsl::names::AutNum; fn main() -> Result<(), Box> { tracing_subscriber::fmt() .with_max_level(tracing::Level::WARN) .with_writer(stderr) .try_init()?; let args: Vec = args().collect(); let host = format!("{}:43", args[1]); let object = args[2].parse().unwrap(); let mut irr = IrrClient::new(host).connect()?; let mut pipeline = irr.pipeline(); pipeline.push(Query::AsSetMembersRecursive(object))?; let mut autnums: HashMap = pipeline .pop() .unwrap()? .filter_map(|item| { item.map_err(|err| { tracing::warn!(%err); err }) .map(|item| { ( item.into_content(), (PrefixSet::::default(), PrefixSet::::default()), ) }) .ok() }) .collect(); pipeline.extend( autnums .keys() .flat_map(|k| [Query::Ipv4Routes(*k), Query::Ipv6Routes(*k)]), ); while let Some(response_result) = pipeline.pop::>() { match response_result { Ok(response) => match response.query() { Query::Ipv4Routes(autnum) => { autnums.entry(*autnum).and_modify(|(set, _)| { set.extend(response.filter_map::, _>(|item_result| { item_result .map(|item| item.into_content().try_into().unwrap()) .map_err(|err| tracing::warn!(%err)) .ok() })) }); } Query::Ipv6Routes(autnum) => { autnums.entry(*autnum).and_modify(|(_, set)| { set.extend(response.filter_map::, _>(|item_result| { item_result .map(|item| item.into_content().try_into().unwrap()) .map_err(|err| tracing::warn!(%err)) .ok() })) }); } _ => unreachable!(), }, Err(err) => { tracing::warn!("query failed: {}", err); } } } autnums .into_iter() .for_each(|(autnum, (ipv4_set, ipv6_set))| { println!("{}:", autnum); println!(" ipv4 prefixes: {}", ipv4_set.prefixes().count()); println!(" ipv6 prefixes: {}", ipv6_set.prefixes().count()); }); Ok(()) }