use async_trait::async_trait;
use std::{
error::Error,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
time::Duration,
};
use tokio::time::{self, Instant};
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
system_conf, TokioAsyncResolver,
};
use viaspf::lookup::{Lookup, LookupError, LookupResult, Name};
pub struct Resolver {
pub inner: TokioAsyncResolver,
pub deadline: Instant,
}
impl Resolver {
pub fn new(timeout: Duration) -> Self {
let (config, opts) = Default::default();
Self::new_internal(timeout, config, opts)
}
pub fn new_with_system_config(timeout: Duration) -> Result<Self, Box<dyn Error>> {
let (config, opts) = system_conf::read_system_conf()?;
Ok(Self::new_internal(timeout, config, opts))
}
fn new_internal(timeout: Duration, config: ResolverConfig, mut opts: ResolverOpts) -> Self {
opts.timeout = timeout;
let inner = TokioAsyncResolver::tokio(config, opts);
let deadline = Instant::now() + timeout;
Self { inner, deadline }
}
}
#[async_trait]
impl Lookup for Resolver {
async fn lookup_a(&self, name: &Name) -> LookupResult<Vec<Ipv4Addr>> {
time::timeout_at(self.deadline, self.inner.lookup_a(name))
.await
.map_err(|_| LookupError::Timeout)?
}
async fn lookup_aaaa(&self, name: &Name) -> LookupResult<Vec<Ipv6Addr>> {
time::timeout_at(self.deadline, self.inner.lookup_aaaa(name))
.await
.map_err(|_| LookupError::Timeout)?
}
async fn lookup_mx(&self, name: &Name) -> LookupResult<Vec<Name>> {
time::timeout_at(self.deadline, self.inner.lookup_mx(name))
.await
.map_err(|_| LookupError::Timeout)?
}
async fn lookup_txt(&self, name: &Name) -> LookupResult<Vec<String>> {
time::timeout_at(self.deadline, self.inner.lookup_txt(name))
.await
.map_err(|_| LookupError::Timeout)?
}
async fn lookup_ptr(&self, ip: IpAddr) -> LookupResult<Vec<Name>> {
time::timeout_at(self.deadline, self.inner.lookup_ptr(ip))
.await
.map_err(|_| LookupError::Timeout)?
}
}