125 lines
4.0 KiB
Rust
125 lines
4.0 KiB
Rust
use rpki::bundle::{decode_ccr_compare_views, write_vap_csv, write_vrp_csv};
|
|
use rpki::ccr::decode_content_info;
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq)]
|
|
struct Args {
|
|
ccr_path: Option<std::path::PathBuf>,
|
|
vrps_out_path: Option<std::path::PathBuf>,
|
|
vaps_out_path: Option<std::path::PathBuf>,
|
|
trust_anchor: String,
|
|
}
|
|
|
|
fn usage() -> &'static str {
|
|
"Usage: ccr_to_compare_views --ccr <path> --vrps-out <path> --vaps-out <path> [--trust-anchor <name>]"
|
|
}
|
|
|
|
fn parse_args(argv: &[String]) -> Result<Args, String> {
|
|
let mut args = Args {
|
|
trust_anchor: "unknown".to_string(),
|
|
..Args::default()
|
|
};
|
|
let mut i = 1usize;
|
|
while i < argv.len() {
|
|
match argv[i].as_str() {
|
|
"--ccr" => {
|
|
i += 1;
|
|
let v = argv.get(i).ok_or("--ccr requires a value")?;
|
|
args.ccr_path = Some(v.into());
|
|
}
|
|
"--vrps-out" => {
|
|
i += 1;
|
|
let v = argv.get(i).ok_or("--vrps-out requires a value")?;
|
|
args.vrps_out_path = Some(v.into());
|
|
}
|
|
"--vaps-out" => {
|
|
i += 1;
|
|
let v = argv.get(i).ok_or("--vaps-out requires a value")?;
|
|
args.vaps_out_path = Some(v.into());
|
|
}
|
|
"--trust-anchor" => {
|
|
i += 1;
|
|
let v = argv.get(i).ok_or("--trust-anchor requires a value")?;
|
|
args.trust_anchor = v.clone();
|
|
}
|
|
"-h" | "--help" => return Err(usage().to_string()),
|
|
other => return Err(format!("unknown argument: {other}\n{}", usage())),
|
|
}
|
|
i += 1;
|
|
}
|
|
if args.ccr_path.is_none() {
|
|
return Err(format!("--ccr is required\n{}", usage()));
|
|
}
|
|
if args.vrps_out_path.is_none() {
|
|
return Err(format!("--vrps-out is required\n{}", usage()));
|
|
}
|
|
if args.vaps_out_path.is_none() {
|
|
return Err(format!("--vaps-out is required\n{}", usage()));
|
|
}
|
|
Ok(args)
|
|
}
|
|
|
|
fn main() -> Result<(), String> {
|
|
let args = parse_args(&std::env::args().collect::<Vec<_>>())?;
|
|
let ccr_path = args.ccr_path.as_ref().unwrap();
|
|
let bytes = std::fs::read(ccr_path)
|
|
.map_err(|e| format!("read ccr failed: {}: {e}", ccr_path.display()))?;
|
|
let content_info = decode_content_info(&bytes).map_err(|e| e.to_string())?;
|
|
let (vrps, vaps) =
|
|
decode_ccr_compare_views(&content_info, &args.trust_anchor).map_err(|e| e.to_string())?;
|
|
write_vrp_csv(args.vrps_out_path.as_ref().unwrap(), &vrps)?;
|
|
write_vap_csv(args.vaps_out_path.as_ref().unwrap(), &vaps)?;
|
|
println!(
|
|
"{}\n{}",
|
|
args.vrps_out_path.as_ref().unwrap().display(),
|
|
args.vaps_out_path.as_ref().unwrap().display()
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn parse_args_accepts_required_flags() {
|
|
let argv = vec![
|
|
"ccr_to_compare_views".to_string(),
|
|
"--ccr".to_string(),
|
|
"a.ccr".to_string(),
|
|
"--vrps-out".to_string(),
|
|
"vrps.csv".to_string(),
|
|
"--vaps-out".to_string(),
|
|
"vaps.csv".to_string(),
|
|
"--trust-anchor".to_string(),
|
|
"apnic".to_string(),
|
|
];
|
|
let args = parse_args(&argv).expect("parse args");
|
|
assert_eq!(
|
|
args.ccr_path.as_deref(),
|
|
Some(std::path::Path::new("a.ccr"))
|
|
);
|
|
assert_eq!(
|
|
args.vrps_out_path.as_deref(),
|
|
Some(std::path::Path::new("vrps.csv"))
|
|
);
|
|
assert_eq!(
|
|
args.vaps_out_path.as_deref(),
|
|
Some(std::path::Path::new("vaps.csv"))
|
|
);
|
|
assert_eq!(args.trust_anchor, "apnic");
|
|
}
|
|
|
|
#[test]
|
|
fn parse_args_rejects_missing_required_flags() {
|
|
let argv = vec![
|
|
"ccr_to_compare_views".to_string(),
|
|
"--ccr".to_string(),
|
|
"a.ccr".to_string(),
|
|
"--vrps-out".to_string(),
|
|
"vrps.csv".to_string(),
|
|
];
|
|
let err = parse_args(&argv).unwrap_err();
|
|
assert!(err.contains("--vaps-out is required"), "{err}");
|
|
}
|
|
}
|