use std::{net::SocketAddr, sync::LazyLock};
use hickory_resolver::{
TokioResolver,
config::{self, LookupIpStrategy, ResolverConfig},
net::runtime::TokioRuntimeProvider,
};
use super::{Addrs, Name, Resolve, Resolving};
#[derive(Debug, Clone)]
pub struct HickoryDnsResolver {
resolver: &'static LazyLock<TokioResolver>,
}
impl HickoryDnsResolver {
pub fn new() -> HickoryDnsResolver {
static RESOLVER: LazyLock<TokioResolver> = LazyLock::new(|| {
let mut builder = match TokioResolver::builder_tokio() {
Ok(resolver) => {
debug!("using system DNS configuration");
resolver
}
Err(_err) => {
debug!("error reading DNS system conf: {}, using defaults", _err);
TokioResolver::builder_with_config(
ResolverConfig::udp_and_tcp(&config::GOOGLE),
TokioRuntimeProvider::default(),
)
}
};
builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
builder.build().expect("failed to create DNS resolver")
});
HickoryDnsResolver {
resolver: &RESOLVER,
}
}
}
impl Resolve for HickoryDnsResolver {
fn resolve(&self, name: Name) -> Resolving {
let resolver = self.clone();
Box::pin(async move {
let lookup = resolver.resolver.lookup_ip(name.as_str()).await?;
let addrs: Addrs = Box::new(
lookup
.iter()
.map(|ip_addr| SocketAddr::new(ip_addr, 0))
.collect::<Vec<_>>()
.into_iter(),
);
Ok(addrs)
})
}
}