1 use std::future::Future;
2 use std::io;
3 use std::net::SocketAddr;
4 use std::pin::Pin;
5 use std::sync::Arc;
6 use std::task::{self, Poll};
7 
8 use hyper::client::connect::dns as hyper_dns;
9 use hyper::service::Service;
10 use tokio::sync::Mutex;
11 use trust_dns_resolver::{
12     config::{ResolverConfig, ResolverOpts},
13     lookup_ip::LookupIpIntoIter,
14     system_conf, AsyncResolver, TokioConnection, TokioConnectionProvider, TokioHandle,
15 };
16 
17 use crate::error::BoxError;
18 
19 type SharedResolver = Arc<AsyncResolver<TokioConnection, TokioConnectionProvider>>;
20 
21 lazy_static! {
22     static ref SYSTEM_CONF: io::Result<(ResolverConfig, ResolverOpts)> =
23         system_conf::read_system_conf().map_err(io::Error::from);
24 }
25 
26 #[derive(Clone)]
27 pub(crate) struct TrustDnsResolver {
28     state: Arc<Mutex<State>>,
29 }
30 
31 pub(crate) struct SocketAddrs {
32     iter: LookupIpIntoIter,
33 }
34 
35 enum State {
36     Init,
37     Ready(SharedResolver),
38 }
39 
40 impl TrustDnsResolver {
new() -> io::Result<Self>41     pub(crate) fn new() -> io::Result<Self> {
42         SYSTEM_CONF.as_ref().map_err(|e| {
43             io::Error::new(e.kind(), format!("error reading DNS system conf: {}", e))
44         })?;
45 
46         // At this stage, we might not have been called in the context of a
47         // Tokio Runtime, so we must delay the actual construction of the
48         // resolver.
49         Ok(TrustDnsResolver {
50             state: Arc::new(Mutex::new(State::Init)),
51         })
52     }
53 }
54 
55 impl Service<hyper_dns::Name> for TrustDnsResolver {
56     type Response = SocketAddrs;
57     type Error = BoxError;
58     type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
59 
poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>60     fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
61         Poll::Ready(Ok(()))
62     }
63 
call(&mut self, name: hyper_dns::Name) -> Self::Future64     fn call(&mut self, name: hyper_dns::Name) -> Self::Future {
65         let resolver = self.clone();
66         Box::pin(async move {
67             let mut lock = resolver.state.lock().await;
68 
69             let resolver = match &*lock {
70                 State::Init => {
71                     let resolver = new_resolver().await?;
72                     *lock = State::Ready(resolver.clone());
73                     resolver
74                 }
75                 State::Ready(resolver) => resolver.clone(),
76             };
77 
78             // Don't keep lock once the resolver is constructed, otherwise
79             // only one lookup could be done at a time.
80             drop(lock);
81 
82             let lookup = resolver.lookup_ip(name.as_str()).await?;
83             Ok(SocketAddrs {
84                 iter: lookup.into_iter(),
85             })
86         })
87     }
88 }
89 
90 impl Iterator for SocketAddrs {
91     type Item = SocketAddr;
92 
next(&mut self) -> Option<Self::Item>93     fn next(&mut self) -> Option<Self::Item> {
94         self.iter.next().map(|ip_addr| SocketAddr::new(ip_addr, 0))
95     }
96 }
97 
new_resolver() -> Result<SharedResolver, BoxError>98 async fn new_resolver() -> Result<SharedResolver, BoxError> {
99     let (config, opts) = SYSTEM_CONF
100         .as_ref()
101         .expect("can't construct TrustDnsResolver if SYSTEM_CONF is error")
102         .clone();
103     let resolver = AsyncResolver::new(config, opts, TokioHandle)?;
104     Ok(Arc::new(resolver))
105 }
106