chrootable_https/dns/
mod.rs

1use crate::errors::*;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
3use std::result;
4use std::str::{self, FromStr};
5use std::time::Duration;
6
7use futures::Poll;
8use futures::{future, Future};
9use tokio::prelude::FutureExt;
10use tokio::runtime::Runtime;
11use trust_dns::client::ClientHandle;
12use trust_dns::client::{Client, ClientConnection, SyncClient};
13use trust_dns::op::ResponseCode;
14use trust_dns::rr::rdata;
15use trust_dns::rr::record_data;
16pub use trust_dns::rr::record_type::RecordType;
17use trust_dns::rr::{DNSClass, Name};
18use trust_dns::tcp::TcpClientConnection;
19use trust_dns::udp::UdpClientConnection;
20
21pub mod system_conf;
22
23#[derive(Debug, PartialEq, Serialize, Deserialize)]
24pub enum DnsError {
25    FormErr,
26    ServFail,
27    NXDomain,
28    Other,
29    Refused,
30    NotAuth,
31    NotZone,
32    DnsSec,
33}
34
35impl DnsError {
36    fn from_response_code(code: ResponseCode) -> Option<DnsError> {
37        use trust_dns::op::ResponseCode::*;
38        match code {
39            NoError => None,
40            FormErr => Some(DnsError::FormErr),
41            ServFail => Some(DnsError::ServFail),
42            NXDomain => Some(DnsError::NXDomain),
43            NotImp => Some(DnsError::Other),
44            Refused => Some(DnsError::Refused),
45            YXDomain => Some(DnsError::Other),
46            YXRRSet => Some(DnsError::Other),
47            NXRRSet => Some(DnsError::Other),
48            NotAuth => Some(DnsError::NotAuth),
49            NotZone => Some(DnsError::NotZone),
50            BADVERS => Some(DnsError::DnsSec),
51            BADSIG => Some(DnsError::DnsSec),
52            BADKEY => Some(DnsError::DnsSec),
53            BADTIME => Some(DnsError::DnsSec),
54            BADMODE => Some(DnsError::DnsSec),
55            BADNAME => Some(DnsError::DnsSec),
56            BADALG => Some(DnsError::DnsSec),
57            BADTRUNC => Some(DnsError::DnsSec),
58            BADCOOKIE => Some(DnsError::DnsSec),
59        }
60    }
61}
62
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64pub enum RData {
65    A(Ipv4Addr),
66    AAAA(Ipv6Addr),
67    CNAME(String),
68    MX((u16, String)),
69    NS(String),
70    PTR(String),
71    SOA(SOA),
72    SRV((String, u16)),
73    TXT(Vec<u8>),
74    Other(String),
75}
76
77impl<'a> From<&'a record_data::RData> for RData {
78    fn from(rdata: &'a record_data::RData) -> RData {
79        use trust_dns::rr::record_data::RData::*;
80        match rdata {
81            A(ip) => RData::A(*ip),
82            AAAA(ip) => RData::AAAA(*ip),
83            CNAME(name) => RData::CNAME(name.to_string()),
84            MX(mx) => RData::MX((mx.preference(), mx.exchange().to_string())),
85            NS(ns) => RData::NS(ns.to_string()),
86            PTR(ptr) => RData::PTR(ptr.to_string()),
87            SOA(soa) => RData::SOA(soa.into()),
88            SRV(srv) => RData::SRV((srv.target().to_string(), srv.port())),
89            TXT(txt) => RData::TXT(txt.iter().fold(Vec::new(), |mut a, b| {
90                a.extend(b.iter());
91                a
92            })),
93            _ => RData::Other("unknown".to_string()),
94        }
95    }
96}
97
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99pub struct SOA {
100    mname: String,
101    rname: String,
102    serial: u32,
103    refresh: i32,
104    retry: i32,
105    expire: i32,
106    minimum: u32,
107}
108
109impl<'a> From<&'a rdata::soa::SOA> for SOA {
110    fn from(soa: &'a rdata::soa::SOA) -> SOA {
111        SOA {
112            mname: soa.mname().to_string(),
113            rname: soa.rname().to_string(),
114            serial: soa.serial(),
115            refresh: soa.refresh(),
116            retry: soa.retry(),
117            expire: soa.expire(),
118            minimum: soa.minimum(),
119        }
120    }
121}
122
123pub fn dns_name_to_string(name: &Name) -> Result<String> {
124    let labels = name
125        .iter()
126        .map(str::from_utf8)
127        .collect::<result::Result<Vec<_>, _>>()?;
128    Ok(labels.join("."))
129}
130
131pub trait DnsResolver: Send + Sync {
132    fn resolve(&self, name: &str, query_type: RecordType) -> Resolving;
133}
134
135/// An asynchronous DNS resolver.
136#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
137pub struct Resolver {
138    pub ns: Vec<SocketAddr>,
139    #[serde(default)]
140    pub tcp: bool,
141    pub timeout: Option<Duration>,
142}
143
144impl Resolver {
145    pub fn new(ns: Vec<SocketAddr>) -> Resolver {
146        Resolver {
147            ns,
148            tcp: false,
149            timeout: Some(Duration::from_secs(3)),
150        }
151    }
152
153    /// Build a resolver with no nameservers
154    pub fn empty() -> Resolver {
155        Resolver {
156            ns: vec![],
157            tcp: false,
158            timeout: None,
159        }
160    }
161
162    /// Creates a new resolver using the [CloudFlare Authoritative DNS][cf] service.
163    ///
164    /// [cf]: https://www.cloudflare.com/learning/dns/what-is-1.1.1.1/
165    pub fn cloudflare() -> Resolver {
166        Resolver::new(
167            vec!["1.1.1.1:53".parse().unwrap(), "1.0.0.1:53".parse().unwrap()],
168        )
169    }
170    
171    /// Creates a new resolver using the [Google Public DNS][ggl] service.
172    ///
173    /// [ggl]: https://developers.google.com/speed/public-dns/
174    pub fn google() -> Resolver {
175        Resolver::new(
176            vec!["8.8.8.8:53".parse().unwrap(), "8.8.4.4:53".parse().unwrap()],
177        )
178    }
179
180    /// Creates a new resolver from `/etc/resolv.conf`.
181    pub fn from_system() -> Result<Resolver> {
182        let ns = system_conf::read_system_conf()?;
183        Ok(Resolver::new(ns))
184    }
185
186    /// Creates a new resolver from `/etc/resolv.conf`.
187    pub fn from_system_v4() -> Result<Resolver> {
188        let ns = system_conf::read_system_conf()?
189            .into_iter()
190            .filter(|ns| ns.is_ipv4())
191            .collect();
192        Ok(Resolver::new(ns))
193    }
194
195    /// Sets a timeout within which each DNS query must complete.
196    ///
197    /// Default setting is no timeout.
198    pub fn timeout(&mut self, timeout: Option<Duration>) {
199        self.timeout = timeout;
200    }
201}
202
203impl Resolver {
204    fn resolve_with<T>(&self, conn: T, name: Name, query_type: RecordType) -> Resolving
205    where
206        T: ClientConnection,
207    {
208        let client = SyncClient::new(conn);
209        let (bg, mut client) = client.new_future();
210
211        let query = future::lazy(move || {
212            tokio::executor::spawn(bg);
213            client
214                .query(name, DNSClass::IN, query_type)
215                .map_err(Error::from)
216        });
217
218        let response: Box<dyn Future<Item = _, Error = _> + Send> = match self.timeout {
219            Some(ref timeout) => Box::new(query.timeout(*timeout).map_err(|e| {
220                e.into_inner()
221                    .unwrap_or_else(|| format_err!("DNS query timed out"))
222            })),
223            None => Box::new(query),
224        };
225
226        let reply = response.and_then(|response| {
227            let error = DnsError::from_response_code(response.response_code());
228
229            let answers = response
230                .answers()
231                .iter()
232                .map(|x| {
233                    let name = dns_name_to_string(x.name())?;
234                    let rdata = x.rdata().into();
235                    let ttl = x.ttl();
236                    Ok((name, rdata, ttl))
237                }).collect::<Result<Vec<_>>>()?;
238
239            Ok(DnsReply { answers, error })
240        });
241
242        Resolving::new(reply)
243    }
244}
245
246impl DnsResolver for Resolver {
247    fn resolve(&self, name: &str, query_type: RecordType) -> Resolving {
248        let name = match Name::from_str(name) {
249            Ok(name) => name,
250            Err(e) => return Resolving::new(future::err(e.into())),
251        };
252
253        let address = match self.ns.first() {
254            Some(ref address) => *address,
255            None => return Resolving::new(future::err(format_err!("No nameserver configured"))),
256        };
257
258        if self.tcp {
259            match TcpClientConnection::new(*address) {
260                Ok(conn) => self.resolve_with(conn, name, query_type),
261                Err(e) => Resolving::new(future::err(e.into())),
262            }
263        } else {
264            match UdpClientConnection::new(*address) {
265                Ok(conn) => self.resolve_with(conn, name, query_type),
266                Err(e) => Resolving::new(future::err(e.into())),
267            }
268        }
269    }
270}
271
272#[derive(Debug, PartialEq, Serialize, Deserialize)]
273pub struct DnsReply {
274    pub answers: Vec<(String, RData, u32)>,
275    pub error: Option<DnsError>,
276}
277
278impl DnsReply {
279    pub fn success(&self) -> Result<Vec<IpAddr>> {
280        if let Some(ref error) = self.error {
281            bail!("dns server returned error: {:?}", error)
282        }
283
284        let ips = self
285            .answers
286            .iter()
287            .flat_map(|x| match x.1 {
288                RData::A(ip) => Some(IpAddr::V4(ip)),
289                RData::AAAA(ip) => Some(IpAddr::V6(ip)),
290                _ => None,
291            }).collect();
292
293        Ok(ips)
294    }
295
296    pub fn ttl(&self) -> Duration {
297        let ttl = if self.error.is_none() {
298            self.answers.iter()
299                .map(|(_, _, ttl)| *ttl)
300                .min()
301        } else {
302            self.answers.iter()
303                .filter_map(|x| match x {
304                    (_, RData::SOA(soa), _) => Some(soa.minimum),
305                    _ => None,
306                })
307                .next()
308        };
309        Duration::from_secs(u64::from(ttl.unwrap_or(0)))
310    }
311}
312
313/// A `Future` that represents a resolving DNS query.
314#[must_use = "futures do nothing unless polled"]
315pub struct Resolving(Box<dyn Future<Item = DnsReply, Error = Error> + Send>);
316
317impl Resolving {
318    /// Creates a new `Resolving` future.
319    pub(crate) fn new<F>(inner: F) -> Self
320    where
321        F: Future<Item = DnsReply, Error = Error> + Send + 'static,
322    {
323        Resolving(Box::new(inner))
324    }
325
326    /// Drives this future to completion, eventually returning a DNS reply.
327    pub fn wait_for_response(self) -> Result<DnsReply> {
328        let mut rt = Runtime::new()?;
329        rt.block_on(self)
330    }
331}
332
333impl Future for Resolving {
334    type Item = DnsReply;
335    type Error = Error;
336
337    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
338        self.0.poll()
339    }
340}
341
342#[cfg(test)]
343mod tests {
344    use super::*;
345    use serde_json;
346    use tokio::runtime::current_thread::Runtime;
347
348    #[test]
349    fn verify_dns_config() {
350        let mut runtime = Runtime::new().unwrap();
351
352        let config = Resolver::from_system().expect("DnsConfig::from_system");
353        let json = serde_json::to_string(&config).expect("to json");
354        println!("{:?}", json);
355        let resolver = serde_json::from_str::<Resolver>(&json).expect("to json");
356
357        let fut = resolver.resolve("example.com", RecordType::A);
358        runtime.block_on(fut).expect("resolve failed");
359    }
360
361    #[test]
362    fn verify_dns_config_from_json() {
363        let json = r#"{"ns":["1.1.1.1:53","1.0.0.1:53"]}"#;
364        let _resolver = serde_json::from_str::<Resolver>(&json).expect("to json");
365    }
366
367    #[test]
368    fn verify_dns_query() {
369        let mut runtime = Runtime::new().unwrap();
370        let resolver = Resolver::from_system().expect("DnsConfig::from_system");
371        let fut = resolver.resolve("example.com", RecordType::A);
372        let x = runtime.block_on(fut).expect("resolve failed");
373        println!("{:?}", x);
374        assert!(x.error.is_none());
375    }
376
377    #[test]
378    fn verify_dns_query_timeout() {
379        let mut runtime = Runtime::new().unwrap();
380        let resolver = Resolver {
381            ns: vec!["1.2.3.4:53".parse().unwrap()],
382            tcp: false,
383            timeout: Some(Duration::from_millis(100)),
384        };
385        let fut = resolver.resolve("example.com", RecordType::A);
386        let x = runtime.block_on(fut);
387        assert!(x.is_err());
388    }
389
390    #[test]
391    fn verify_dns_query_nx() {
392        let mut runtime = Runtime::new().unwrap();
393        let resolver = Resolver::from_system().expect("DnsConfig::from_system");
394        let fut = resolver.resolve("nonexistant.example.com", RecordType::A);
395        let x = runtime.block_on(fut).expect("resolve failed");
396        println!("{:?}", x);
397        assert_eq!(
398            x,
399            DnsReply {
400                answers: Vec::new(),
401                error: Some(DnsError::NXDomain),
402            }
403        );
404    }
405
406    #[test]
407    fn verify_dns_query_empty_cname() {
408        let mut runtime = Runtime::new().unwrap();
409        let resolver = Resolver::from_system().expect("DnsConfig::from_system");
410        let fut = resolver.resolve("example.com", RecordType::CNAME);
411        let x = runtime.block_on(fut).expect("resolve failed");
412        println!("{:?}", x);
413        assert_eq!(
414            x,
415            DnsReply {
416                answers: Vec::new(),
417                error: None,
418            }
419        );
420    }
421}