use hickory_resolver::{
config::{LookupIpStrategy, ResolverConfig},
net::runtime::TokioRuntimeProvider,
TokioResolver,
};
use once_cell::sync::OnceCell;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use super::{Addrs, Name, Resolve, Resolving};
#[derive(Debug, Default, Clone)]
pub(crate) struct HickoryDnsResolver {
state: Arc<OnceCell<TokioResolver>>,
}
pub(crate) struct SocketAddrs {
pub(crate) iter: std::vec::IntoIter<IpAddr>,
}
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 ips: Vec<IpAddr> = lookup.iter().collect();
let addrs: Addrs = Box::new(SocketAddrs {
iter: ips.into_iter(),
});
Ok(addrs)
})
}
}
impl Iterator for SocketAddrs {
type Item = SocketAddr;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|ip| SocketAddr::new(ip, 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(),
TokioRuntimeProvider::default(),
)
});
builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
builder.build().expect("failed to build hickory resolver")
}