use std::{net::IpAddr, time::Instant};
use clap::Parser;
use console::style;
use hickory_net::runtime::TokioRuntimeProvider;
use hickory_proto::{
ROOTS,
op::Query,
rr::{Name, RecordType},
};
use hickory_resolver::recursor::{Recursor, RecursorOptions};
#[derive(Debug, Parser)]
#[clap(name = "recurse")]
struct Opts {
domainname: Name,
#[clap(short = 't', long = "type", default_value = "A")]
ty: RecordType,
#[clap(short = 'n', long, use_value_delimiter = true, value_delimiter(','))]
nameservers: Vec<IpAddr>,
#[clap(flatten)]
log_config: hickory_util::LogConfig,
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut opts = Opts::parse();
hickory_util::logger(env!("CARGO_BIN_NAME"), opts.log_config.level());
let mut name = opts.domainname;
name.set_fqdn(true);
let ty = opts.ty;
if opts.nameservers.is_empty() {
opts.nameservers = ROOTS.to_vec();
}
let recursor = Recursor::with_options(
&opts.nameservers,
RecursorOptions::default(),
TokioRuntimeProvider::default(),
)?;
println!(
"Recursing for {name} {ty} from roots",
name = style(&name).yellow(),
ty = style(ty).yellow(),
);
let now = Instant::now();
let query = Query::query(name, ty);
let response = recursor.resolve(query, now, false).await?;
println!(
"{} for query {:#?}",
style("Success").green(),
style(&response).blue()
);
for r in response.all_sections().filter(|r| r.record_type() == ty) {
println!(
"\t{name} {ttl} {class} {ty} {rdata}",
name = style(&r.name).blue(),
ttl = style(r.ttl).blue(),
class = style(r.dns_class).blue(),
ty = style(r.record_type()).blue(),
rdata = r.data
);
}
Ok(())
}