1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use super::{Lookup, LookupError, LookupResult, Name};
use async_trait::async_trait;
use std::{
    error::Error,
    net::{IpAddr, Ipv4Addr, Ipv6Addr},
};
use trust_dns_resolver::{
    error::{ResolveError, ResolveErrorKind},
    Name as TrustDnsName, TokioAsyncResolver,
};

#[async_trait]
impl Lookup for TokioAsyncResolver {
    async fn lookup_a<'lookup, 'a>(&'lookup self, name: &'a Name) -> LookupResult<Vec<Ipv4Addr>> {
        Ok(self
            .ipv4_lookup(to_trust_dns_name(name)?)
            .await
            .map_err(to_lookup_error)?
            .into_iter()
            .collect())
    }

    async fn lookup_aaaa<'lookup, 'a>(&'lookup self, name: &'a Name) -> LookupResult<Vec<Ipv6Addr>> {
        Ok(self
            .ipv6_lookup(to_trust_dns_name(name)?)
            .await
            .map_err(to_lookup_error)?
            .into_iter()
            .collect())
    }

    async fn lookup_mx<'lookup, 'a>(&'lookup self, name: &'a Name) -> LookupResult<Vec<Name>> {
        let mut mxs = self
            .mx_lookup(to_trust_dns_name(name)?)
            .await
            .map_err(to_lookup_error)?
            .into_iter()
            .collect::<Vec<_>>();
        mxs.sort_by_key(|mx| mx.preference());
        mxs.into_iter()
            .map(|mx| Name::new(&mx.exchange().to_ascii()).map_err(wrap_error))
            .collect()
    }

    async fn lookup_txt<'lookup, 'a>(&'lookup self, name: &'a Name) -> LookupResult<Vec<String>> {
        Ok(self
            .txt_lookup(to_trust_dns_name(name)?)
            .await
            .map_err(to_lookup_error)?
            .into_iter()
            .map(|txt| {
                txt.iter()
                    .map(|data| String::from_utf8_lossy(data))
                    .collect()
            })
            .collect())
    }

    async fn lookup_ptr<'lookup>(&'lookup self, ip: IpAddr) -> LookupResult<Vec<Name>> {
        self.reverse_lookup(ip)
            .await
            .map_err(to_lookup_error)?
            .into_iter()
            .map(|name| Name::new(&name.to_ascii()).map_err(wrap_error))
            .collect()
    }
}

fn to_trust_dns_name(name: &Name) -> LookupResult<TrustDnsName> {
    TrustDnsName::from_ascii(name).map_err(wrap_error)
}

fn to_lookup_error(error: ResolveError) -> LookupError {
    match error.kind() {
        ResolveErrorKind::NoRecordsFound { .. } => LookupError::NoRecords,
        ResolveErrorKind::Timeout => LookupError::Timeout,
        _ => wrap_error(error),
    }
}

fn wrap_error(error: impl Error + Send + Sync + 'static) -> LookupError {
    LookupError::Dns(Some(error.into()))
}