use std::{net::IpAddr, process::ExitCode};
use libc::{res_init, AF_INET, AF_INET6};
use nix::errno::Errno;
use syd::{
dns::{lookup_addr, resolve_host, resolve_rand},
path::XPathBuf,
};
#[cfg(all(
not(coverage),
not(feature = "prof"),
not(target_os = "android"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;
syd::main! {
use lexopt::prelude::*;
syd::set_sigpipe_dfl()?;
let mut opt_ipv4 = false;
let mut opt_ipv6 = false;
let mut opt_rand = false;
let mut opt_rdns = false;
let mut hostname = None;
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('h') => {
help();
return Ok(ExitCode::SUCCESS);
}
Short('r') => opt_rand = true,
Short('R') => opt_rdns = true,
Short('4') => opt_ipv4 = true,
Short('6') => opt_ipv6 = true,
Value(val) if hostname.is_none() => {
hostname = Some(val.string()?);
}
_ => return Err(arg.unexpected().into()),
}
}
if opt_rdns && (opt_ipv4 || opt_ipv6 || opt_rand) {
eprintln!("Options -4, -6 and -r must not be given with -R!");
return Err(Errno::EINVAL.into());
}
let family = if opt_rdns {
None
} else if opt_ipv4 && opt_ipv6 {
eprintln!("At most one of -4, -6 must be given!");
return Err(Errno::EINVAL.into());
} else if opt_ipv4 {
Some(AF_INET)
} else if opt_ipv6 {
Some(AF_INET6)
} else {
None
};
let hostname = if let Some(hostname) = hostname {
hostname
} else {
help();
return Err(Errno::ENOENT.into());
};
if opt_rdns {
if unsafe { res_init() } != 0 {
return Err(Errno::EFAULT.into());
}
let addr = match hostname.parse::<IpAddr>() {
Ok(addr) => addr,
Err(err) => {
eprintln!("Failed to parse IP address `{hostname}': {err}");
return Err(Errno::EINVAL.into());
}
};
let name: XPathBuf = lookup_addr(addr)?.into();
println!("{name}");
} else if opt_rand {
let addr = resolve_rand(&hostname, family)?;
println!("{addr}");
} else {
for addr in resolve_host(&hostname, family)? {
println!("{addr}");
}
}
Ok(ExitCode::SUCCESS)
}
fn help() {
println!("Usage: syd-dns [-hr46] hostname");
println!(" syd-dns [-R] IPv4/6 address");
println!("Resolve hostname into IPs using system DNS resolver.");
println!("Given -R, perform a reverse-DNS lookup using system DNS resolver.");
println!("If -4 is given, print only IPv4 addresses.");
println!("If -6 is given, print only IPv6 addresses.");
println!("If -r is given, print a random IP.");
}