use hickory_resolver::{
config::LookupIpStrategy, error::ResolveError, lookup_ip::LookupIpIntoIter, system_conf,
TokioAsyncResolver,
};
use once_cell::sync::OnceCell;
use std::fmt;
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<TokioAsyncResolver>>,
}
struct SocketAddrs {
iter: LookupIpIntoIter,
}
#[derive(Debug)]
struct HickoryDnsSystemConfError(ResolveError);
impl Resolve for HickoryDnsResolver {
fn resolve(&self, name: Name) -> Resolving {
let resolver = self.clone();
Box::pin(async move {
let resolver = resolver.state.get_or_try_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() -> Result<TokioAsyncResolver, HickoryDnsSystemConfError> {
let (config, mut opts) = system_conf::read_system_conf().map_err(HickoryDnsSystemConfError)?;
opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
Ok(TokioAsyncResolver::tokio(config, opts))
}
impl fmt::Display for HickoryDnsSystemConfError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("error reading DNS system conf for hickory-dns")
}
}
impl std::error::Error for HickoryDnsSystemConfError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.0)
}
}