Files
simple-rust-tests/__network/dingo/src/cli.rs
2022-04-15 23:49:53 +08:00

84 lines
2.3 KiB
Rust

use std::{
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
process::exit,
};
use ascii::AsciiString;
use crate::dns_types::RecordType;
const HELP: &str = "\
dingo -- domain information gatherer, obviously
USAGE:
dingo [OPTIONS] --record-type TYPE NAME
FLAGS:
-h, --help Prints help information
OPTIONS:
-t, --record-type TYPE Choose the DNS record type (currently only supports A, CNAME, SOA and AAAA)
-r, --resolver IP Which DNS resolver to query (default is 1.1.1.1:53)
ARGS:
NAME A domain name to look up. Remember, these must be ASCII.
";
/// Values derived from the CLI arguments.
#[derive(Debug)]
pub struct AppArgs {
pub record_type: RecordType,
pub name: String,
pub resolver: SocketAddr,
}
impl AppArgs {
pub fn parse() -> Result<Self, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
// Help has a higher priority and should be handled separately.
if pargs.contains(["-h", "--help"]) {
print!("{}", HELP);
std::process::exit(0);
}
let record_type = match pargs
.opt_value_from_str("--record-type")?
.xor(pargs.opt_value_from_str("-t")?)
{
Some(rt) => rt,
None => {
eprintln!("You must supply exactly one of either -t or --record-type");
print!("{}", HELP);
std::process::exit(1);
}
};
// I asked some coworkers and they suggested this DNS resolver
let default_resolver = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53));
let resolver = pargs
.opt_value_from_str("--resolver")?
.or(pargs.opt_value_from_str("-r")?)
.unwrap_or(default_resolver);
let mut name: String = pargs.free_from_str()?;
use std::str::FromStr;
if AsciiString::from_str(&name).is_err() {
eprintln!("DNS names must be ASCII, and {name} is not.");
exit(1);
}
if !name.ends_with('.') {
name.push('.');
}
let args = AppArgs {
record_type,
name,
resolver,
};
let remaining = pargs.finish();
if !remaining.is_empty() {
eprintln!("Warning: unused arguments left: {:?}.", remaining);
}
Ok(args)
}
}