1use std::collections::HashMap;
17use std::convert::{TryFrom, TryInto};
18use std::net::SocketAddr;
19use std::fmt;
20use std::ops::Index;
21use std::time::Duration;
22use std::time::Instant;
23
24
25use crate::error::*;
26use crate::internal_error;
27use crate::query_private::QDnsReq;
28
29use super::common::*;
30
31
32#[derive(Debug, Clone)]
34pub struct QuerySetup
35{
36 pub(crate) measure_time: bool,
38
39 pub(crate) ign_hosts: bool,
41
42 pub(crate) timeout: Option<u32>,
44}
45
46impl Default for QuerySetup
47{
48 fn default() -> Self
49 {
50 return Self { measure_time: false, ign_hosts: false, timeout: None };
51 }
52}
53
54impl QuerySetup
55{
56 pub
59 fn set_measure_time(&mut self, flag: bool) -> &mut Self
60 {
61 self.measure_time = flag;
62
63 return self;
64 }
65
66 pub
69 fn set_ign_hosts(&mut self, flag: bool) -> &mut Self
70 {
71 self.ign_hosts = flag;
72
73 return self;
74 }
75
76 pub
78 fn set_override_timeout(&mut self, timeout: u32) -> &mut Self
79 {
80 if timeout == 0
81 {
82 return self;
83 }
84
85 self.timeout = Some(timeout);
86
87 return self;
88 }
89
90 pub
92 fn reset_override_timeout(&mut self) -> &mut Self
93 {
94 self.timeout = None;
95
96 return self;
97 }
98
99}
100
101#[derive(Clone, Copy, Debug, PartialEq, Eq)]
103pub enum QDnsQueryRec
104{
105 Ok,
107 ServFail,
109 NxDomain,
111 Refused,
113 NotImpl,
115 Truncated,
117 FormError,
119}
120
121impl QDnsQueryRec
122{
123 pub(crate)
127 fn try_next_nameserver(&self, aa: bool) -> bool
128 {
129 match *self
130 {
131 Self::NxDomain =>
132 {
133 if aa == true
134 {
135 return false;
137 }
138
139 return true;
140 },
141 Self::Truncated =>
142 {
143 return true;
144 },
145 Self::Ok | Self::Refused | Self::ServFail | Self::NotImpl | Self::FormError =>
146 {
147 return true;
148 }
149 }
150 }
151
152 pub(crate)
153 fn should_try_tcp(&self) -> bool
154 {
155 return *self == Self::Truncated || *self == Self::ServFail || *self == Self::NxDomain;
156 }
157}
158
159impl TryFrom<StatusBits> for QDnsQueryRec
160{
161 type Error = CDnsError;
162
163 fn try_from(value: StatusBits) -> Result<Self, Self::Error>
164 {
165 if value.contains(StatusBits::TRUN_CATION) == true
166 {
167 return Ok(QDnsQueryRec::Truncated);
168 }
169 else if value.contains(StatusBits::RESP_NOERROR) == true
170 {
171 return Ok(QDnsQueryRec::Ok);
175 }
176 else if value.contains(StatusBits::RESP_FORMERR) == true
177 {
178 return Ok(QDnsQueryRec::FormError);
179 }
180 else if value.contains(StatusBits::RESP_NOT_IMPL) == true
181 {
182 return Ok(QDnsQueryRec::NotImpl);
183 }
184 else if value.contains(StatusBits::RESP_NXDOMAIN) == true
185 {
186 return Ok(QDnsQueryRec::NxDomain);
187 }
188 else if value.contains(StatusBits::RESP_REFUSED) == true
189 {
190 return Ok(QDnsQueryRec::Refused);
191 }
192 else if value.contains(StatusBits::RESP_SERVFAIL) == true
193 {
194 return Ok(QDnsQueryRec::ServFail);
195 }
196 else
197 {
198 internal_error!(CDnsErrorType::DnsResponse, "response status bits unknwon result: '{}'", value.bits());
199 };
200 }
201}
202
203
204impl fmt::Display for QDnsQueryRec
205{
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
207 {
208 match *self
209 {
210 Self::Ok =>
211 writeln!(f, "OK"),
212 Self::ServFail =>
213 writeln!(f, "SERVFAIL"),
214 Self::NxDomain =>
215 writeln!(f, "NXDOMAIN"),
216 Self::Refused =>
217 writeln!(f, "REFUSED"),
218 Self::NotImpl =>
219 writeln!(f, "NOT IMPLEMENTED"),
220 Self::Truncated =>
221 writeln!(f, "TRUNCATED"),
222 Self::FormError =>
223 writeln!(f, "FORMAT ERROR"),
224 }
225 }
226}
227
228#[derive(Debug, Default)]
230pub struct QDnsQueryResult
231{
232 queries: HashMap<QDnsReq, CDnsResult<QDnsQuery>>,
233}
234
235impl IntoIterator for QDnsQueryResult
236{
237 type Item = (QDnsReq, CDnsResult<QDnsQuery>);
238 type IntoIter = std::collections::hash_map::IntoIter<QDnsReq, CDnsResult<QDnsQuery>>;
239
240 #[inline]
241 fn into_iter(self) -> Self::IntoIter
242 {
243 return self.queries.into_iter();
244 }
245}
246
247
248impl Index<QDnsReq> for QDnsQueryResult
249{
250 type Output = CDnsResult<QDnsQuery>;
251
252 fn index(&self, index: QDnsReq) -> &Self::Output
253 {
254 return &self.queries.get(&index).unwrap();
255 }
256}
257
258impl QDnsQueryResult
259{
260 pub(crate)
261 fn with_capacity(cap: usize) -> Self
262 {
263 return Self{ queries: HashMap::with_capacity(cap) };
264 }
265
266 pub(crate)
267 fn push(&mut self, req: QDnsReq, resp: CDnsResult<QDnsQuery>)
268 {
269 self.queries.insert(req, resp);
270 }
271
272 pub
273 fn is_empty(&self) -> bool
274 {
275 return self.queries.is_empty();
276 }
277
278 pub
279 fn contains_dnsreq(&self, req: &QDnsReq) -> bool
280 {
281 return self.queries.contains_key(req);
282 }
283
284 pub
285 fn extend(&mut self, other: Self)
286 {
287 self.queries.extend(other.queries);
288 }
289
290 pub
291 fn list_results(&self) -> std::collections::hash_map::Iter<'_, QDnsReq, Result<QDnsQuery, CDnsError>>
292 {
293 return self.queries.iter();
294 }
295
296 pub
297 fn get_result(self) -> CDnsResult<Vec<QDnsQuery>>
298 {
299 let ok = self.collect_ok();
300
301 if ok.is_empty() == true
302 {
303 internal_error!(CDnsErrorType::DnsNotAvailable, "network error");
304 }
305
306 return Ok(ok);
307 }
308
309 pub
310 fn get_ok_or_error(self) ->CDnsResult<Vec<QDnsQuery>>
311 {
312 return
313 self
314 .queries
315 .into_iter()
316 .map(|e| e.1)
317 .collect::<CDnsResult<Vec<QDnsQuery>>>();
318 }
319
320 pub
321 fn collect_ok(self) -> Vec<QDnsQuery>
322 {
323 return
324 self
325 .queries
326 .into_iter()
327 .filter(
328 |(_k, v)|
329 v.is_ok()
330 )
331 .map(|(_, v)| v.unwrap())
332 .collect();
333 }
334
335 pub
336 fn collect_ok_with_answers(self) -> Vec<QDnsQuery>
337 {
338 return
339 self
340 .queries
341 .into_iter()
342 .filter(
343 |(_k, v)|
344 v.is_ok() && v.as_ref().unwrap().resp.is_empty() == false
345 )
346 .map(|(_, v)| v.unwrap())
347 .collect();
348 }
349
350 pub
352 fn collect_split(self) -> (Vec<(QDnsReq, Result<QDnsQuery, CDnsError>)>, Vec<(QDnsReq, Result<QDnsQuery, CDnsError>)>)
353
354 {
355 return
356 self
357 .queries
358 .into_iter()
359 .partition(|(_, v)|
360 v.is_ok()
361 );
362 }
363
364}
365
366impl fmt::Display for QDnsQueryResult
367{
368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
369 {
370 if self.is_empty() == false
371 {
372 for (req, qr) in self.list_results()
373 {
374 match qr
375 {
376 Ok(r) =>
377 write!(f, "{}", r)?,
378 Err(e) =>
379 write!(f, "request: {}, error: {}", req, e)?
380 }
381
382 }
383 }
384 else
385 {
386 write!(f, "No DNS server available")?;
387 }
388
389 return Ok(());
390 }
391}
392
393#[derive(Clone, Debug)]
396pub struct QDnsQuery
397{
398 pub elapsed: Option<Duration>,
400 pub server: String,
402 pub aa: bool,
404 pub authoratives: Vec<DnsResponsePayload>,
406 pub resp: Vec<DnsResponsePayload>,
408 pub status: QDnsQueryRec,
410}
411
412impl fmt::Display for QDnsQuery
413{
414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
415 {
416 write!(f, "Source: {} ", self.server)?;
417 if let Some(ref el) = self.elapsed
418 {
419 write!(f, "{:.2?} ", el)?;
420 }
421
422 if self.aa == true
423 {
424 writeln!(f, "Authoritative answer")?;
425 }
426 else
427 {
428 writeln!(f, "Non-Authoritative answer")?;
429 }
430
431
432 writeln!(f, "Authoritatives: {}", self.authoratives.len())?;
433
434 if self.authoratives.len() > 0
435 {
436 for a in self.authoratives.iter()
437 {
438 writeln!(f, "{}", a)?;
439 }
440
441 writeln!(f, "")?;
442 }
443
444 writeln!(f, "Status: {}", self.status)?;
445
446 writeln!(f, "Answers: {}", self.resp.len())?;
447
448 if self.resp.len() > 0
449 {
450 for r in self.resp.iter()
451 {
452 writeln!(f, "{}", r)?;
453 }
454
455 writeln!(f, "")?;
456 }
457
458 return Ok(());
459 }
460}
461
462impl IntoIterator for QDnsQuery
463{
464 type Item = DnsResponsePayload;
465 type IntoIter = std::vec::IntoIter<Self::Item>;
466
467 fn into_iter(self) -> Self::IntoIter
468 {
469 self.resp.into_iter()
470 }
471}
472
473impl QDnsQuery
474{
475 pub
477 fn is_ok(&self) -> bool
478 {
479 return self.status == QDnsQueryRec::Ok;
480 }
481
482 pub
483 fn is_authorative(&self) -> bool
484 {
485 return self.aa;
486 }
487
488 pub
489 fn get_elapsed_time(&self) -> Option<&Duration>
490 {
491 return self.elapsed.as_ref();
492 }
493
494 pub
495 fn get_server(&self) -> &String
496 {
497 return &self.server;
498 }
499
500 pub
502 fn get_authoratives(&self) -> &[DnsResponsePayload]
503 {
504 return self.authoratives.as_slice();
505 }
506
507 pub
509 fn get_responses(&self) -> &[DnsResponsePayload]
510 {
511 return self.resp.as_slice();
512 }
513
514 pub
516 fn move_responses(self) -> Vec<DnsResponsePayload>
517 {
518 return self.resp;
519 }
520
521 pub
522 fn get_status(&self) -> QDnsQueryRec
523 {
524 return self.status;
525 }
526
527 pub
528 fn should_check_next_ns(&self) -> bool
529 {
530 return self.status.try_next_nameserver(self.aa);
531 }
532}
533
534impl QDnsQuery
535{
536 pub
538 fn from_local(req_pl: Vec<DnsResponsePayload>, now: Option<&Instant>) -> QDnsQuery
539 {
540 let elapsed = now.map(|n| n.elapsed());
541
542 return
543 Self
544 {
545 elapsed: elapsed,
546 server: HOST_CFG_PATH.to_string(),
547 aa: true,
548 authoratives: Vec::new(),
549 status: QDnsQueryRec::Ok,
550 resp: req_pl
551 };
552 }
553
554 pub
556 fn from_response(server: &SocketAddr, ans: DnsRequestAnswer, now: Option<&Instant>) -> CDnsResult<Self>
557 {
558 return Ok(
559 Self
560 {
561 elapsed: now.map_or(None, |n| Some(n.elapsed())),
562 server: server.to_string(),
563 aa: ans.req_header.header.status.contains(StatusBits::AUTH_ANSWER),
564 authoratives: ans.authoratives,
565 status: ans.req_header.header.status.try_into()?,
566 resp: ans.response,
567 }
568 );
569 }
570}