use hickory_resolver::{
config::{LookupIpStrategy, ResolverConfig},
lookup_ip::LookupIpIntoIter,
name_server::TokioConnectionProvider,
TokioResolver,
};
use once_cell::sync::OnceCell;
use std::net::SocketAddr;
use std::sync::Arc;
use super::{Addrs, Name, Resolve, Resolving};
#[derive(Debug, Default, Clone)]
pub(crate) struct HickoryDnsResolver {
state: Arc<OnceCell<TokioResolver>>,
}
struct SocketAddrs {
iter: LookupIpIntoIter,
}
impl Resolve for HickoryDnsResolver {
fn resolve(&self, name: Name) -> Resolving {
let resolver = self.clone();
Box::pin(async move {
let resolver = resolver.state.get_or_init(new_resolver);
let lookup = resolver.lookup_ip(name.as_str()).await?;
let addrs: Addrs = Box::new(SocketAddrs {
iter: lookup.into_iter(),
});
Ok(addrs)
})
}
}
impl Iterator for SocketAddrs {
type Item = SocketAddr;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|ip_addr| SocketAddr::new(ip_addr, 0))
}
}
fn new_resolver() -> TokioResolver {
let mut builder = TokioResolver::builder_tokio().unwrap_or_else(|err| {
log::debug!(
"hickory-dns: failed to load system DNS configuration; falling back to hickory_resolver defaults: {:?}",
err
);
TokioResolver::builder_with_config(
ResolverConfig::default(),
TokioConnectionProvider::default(),
)
});
builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
builder.build()
}