use super::{Addrs, Name, Resolve, Resolving};
pub use hickory_resolver::config::LookupIpStrategy;
use hickory_resolver::config::ResolverConfig;
use hickory_resolver::name_server::TokioConnectionProvider;
use hickory_resolver::{TokioResolver, lookup_ip::LookupIpIntoIter};
use std::net::SocketAddr;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct HickoryDnsResolver {
state: Arc<TokioResolver>,
}
impl HickoryDnsResolver {
pub fn new<S>(strategy: S) -> crate::Result<Self>
where
S: Into<Option<LookupIpStrategy>>,
{
let mut resolver = match TokioResolver::builder_tokio() {
Ok(resolver) => resolver,
Err(err) => {
log::debug!("error reading DNS system conf: {}", err);
TokioResolver::builder_with_config(
ResolverConfig::default(),
TokioConnectionProvider::default(),
)
}
};
resolver.options_mut().ip_strategy =
strategy.into().unwrap_or(LookupIpStrategy::Ipv4AndIpv6);
Ok(Self {
state: Arc::new(resolver.build()),
})
}
}
struct SocketAddrs {
iter: LookupIpIntoIter,
}
impl Resolve for HickoryDnsResolver {
fn resolve(&self, name: Name) -> Resolving {
let resolver = self.clone();
Box::pin(async move {
let lookup = resolver.state.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))
}
}