use hickory_resolver::Resolver;
use hickory_resolver::TokioResolver;
use hickory_resolver::net::runtime::TokioRuntimeProvider;
use rand::SeedableRng;
use rand::rngs::SmallRng;
use rand::rngs::SysRng;
use rand::seq::SliceRandom;
use reqwest::dns::Addrs;
use reqwest::dns::Name;
use reqwest::dns::Resolve;
use reqwest::dns::Resolving;
use std::net::SocketAddr;
use std::sync::Arc;
pub use hickory_resolver::config;
pub use hickory_resolver::config::ResolverConfig;
pub use hickory_resolver::config::ResolverOpts;
#[derive(Debug, Default, Clone)]
pub struct HickoryResolverBuilder {
conf: Option<ResolverConfig>,
opts: Option<ResolverOpts>,
shuffle: bool,
}
impl HickoryResolverBuilder {
pub fn with_options(mut self, options: ResolverOpts) -> Self {
self.opts = Some(options);
self
}
pub fn with_config(mut self, config: ResolverConfig) -> Self {
self.conf = Some(config);
self
}
pub fn with_shuffle(mut self, shuffle: bool) -> Self {
self.shuffle = shuffle;
self
}
pub fn build(self) -> Result<HickoryResolver, Box<dyn std::error::Error + Send + Sync>> {
let shuffler = if self.shuffle {
Some(SmallRng::try_from_rng(&mut SysRng)?)
} else {
None
};
let builder = if let Ok(builder) = Resolver::builder(TokioRuntimeProvider::default()) {
builder
} else if let Some(conf) = self.conf {
Resolver::builder_with_config(conf, TokioRuntimeProvider::default())
} else {
Resolver::builder_with_config(
ResolverConfig::default(),
TokioRuntimeProvider::default(),
)
};
let resolver = if let Some(opts) = self.opts {
builder.with_options(opts).build()?
} else {
builder.build()?
};
let resolver = Arc::new(resolver);
Ok(HickoryResolver { resolver, shuffler })
}
}
#[derive(Debug, Clone)]
pub struct HickoryResolver {
resolver: Arc<TokioResolver>,
shuffler: Option<SmallRng>,
}
impl Resolve for HickoryResolver {
fn resolve(&self, name: Name) -> Resolving {
let HickoryResolver {
resolver,
mut shuffler,
} = self.clone();
Box::pin(async move {
let lookup = resolver.lookup_ip(name.as_str()).await?;
let mut ips = lookup.iter().collect::<Vec<_>>();
if let Some(shuffler) = shuffler.as_mut() {
ips.shuffle(shuffler);
}
Ok(Box::new(ips.into_iter().map(|addr| SocketAddr::new(addr, 0))) as Addrs)
})
}
}