use std::io;
use std::net::SocketAddr;
use hickory_resolver::TokioResolver;
use tokio::sync::OnceCell;
static DNS_RESOLVER: OnceCell<TokioResolver> = OnceCell::const_new();
pub(crate) async fn get_dns_resolver() -> &'static TokioResolver {
DNS_RESOLVER
.get_or_init(|| async {
TokioResolver::builder_tokio()
.expect("failed to create dns resolver from system config")
.build()
})
.await
}
pub(crate) async fn resolve_domain(domain: &[u8], port: u16) -> io::Result<SocketAddr> {
let domain_str = std::str::from_utf8(domain).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"domain name contains invalid utf-8 characters",
)
})?;
let resolver = get_dns_resolver().await;
let lookup_result = resolver.lookup_ip(domain_str).await.map_err(|e| {
io::Error::new(
io::ErrorKind::NotFound,
format!("dns resolution failed for {}: {}", domain_str, e),
)
})?;
lookup_result
.iter()
.next()
.map(|ip| SocketAddr::new(ip, port))
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
format!("no ip addresses found for {}", domain_str),
)
})
}