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#[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 pub fn empty() -> Resolver {
155 Resolver {
156 ns: vec![],
157 tcp: false,
158 timeout: None,
159 }
160 }
161
162 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 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 pub fn from_system() -> Result<Resolver> {
182 let ns = system_conf::read_system_conf()?;
183 Ok(Resolver::new(ns))
184 }
185
186 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 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#[must_use = "futures do nothing unless polled"]
315pub struct Resolving(Box<dyn Future<Item = DnsReply, Error = Error> + Send>);
316
317impl Resolving {
318 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 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}