1use std::collections::{BTreeSet, HashMap};
26use std::convert::TryFrom;
27use std::net::IpAddr;
28use std::sync::Arc;
29use std::time::Duration;
30use std::time::Instant;
31
32use async_recursion::async_recursion;
33use tokio::net::{TcpStream, UdpSocket};
34
35use crate::cfg_resolv_parser::{ConfigEntryTls, ResolveConfEntry, ResolveConfigFamily};
36use crate::common::{CDdnsGlobals, DnsRequestAnswer, DnsRequestHeader};
37use crate::{error::*, DnsResponsePayload, QDnsQueryResult};
38use crate::query::QDnsQuery;
39use crate::{write_error, internal_error};
40use crate::query_private::QDnsReq;
41
42use super::caches::CACHE;
43use super::network::{NetworkTap, NetworkTapType, SocketTap, TcpTlsConnection};
44use super::{QDnsName, QType, QuerySetup, ResolveConfig};
45
46#[derive(Clone, Debug)]
48pub struct QDns
49{
50 resolvers: Arc<ResolveConfig>,
52
53 ordered_req_list: Vec<QDnsReq>,
55
56 opts: QuerySetup,
58}
59
60
61impl QDns
62{
63 pub async
81 fn make_empty(resolvers: Option<Arc<ResolveConfig>>, opts: QuerySetup) -> CDnsResult<Self>
82 {
83 return Ok(
84 Self
85 {
86 resolvers: resolvers.unwrap_or(CACHE.clone_resolve_list().await?),
87 ordered_req_list: Vec::new(),
88 opts: opts,
89 }
90 );
91 }
92
93 pub
107 fn add_request(&mut self, qtype: QType, req_name: impl Into<QDnsName>)
108 {
109 let qr = QDnsReq::new_into(req_name, qtype);
110
111 self.ordered_req_list.push(qr);
112
113 return;
114 }
115
116 pub async
139 fn make_a_aaaa_request(resolvers_opt: Option<Arc<ResolveConfig>>, req_name: impl Into<QDnsName>,
140 opts: QuerySetup) -> CDnsResult<Self>
141 {
142 let resolvers = resolvers_opt.unwrap_or(CACHE.clone_resolve_list().await?);
143
144 let reqs: Vec<QDnsReq> =
146 match resolvers.family
147 {
148 ResolveConfigFamily::INET4_INET6 =>
149 {
150 let req_n: QDnsName = req_name.into();
151
152 vec![
153 QDnsReq::new(req_n.clone(), QType::A),
154 QDnsReq::new(req_n, QType::AAAA),
155 ]
156 },
157 ResolveConfigFamily::INET6_INET4 =>
158 {
159 let req_n: QDnsName = req_name.into();
160
161 vec![
162 QDnsReq::new(req_n.clone(), QType::AAAA),
163 QDnsReq::new(req_n, QType::A),
164 ]
165 },
166 ResolveConfigFamily::INET6 =>
167 {
168 vec![
169 QDnsReq::new(req_name.into(), QType::AAAA),
170 ]
171 },
172 ResolveConfigFamily::INET4 =>
173 {
174 vec![
175 QDnsReq::new(req_name.into(), QType::A),
176 ]
177 }
178 _ =>
179 {
180 let req_n: QDnsName = req_name.into();
182
183 vec![
184 QDnsReq::new(req_n.clone(), QType::A),
185 QDnsReq::new(req_n, QType::AAAA),
186 ]
187 }
188 };
189
190
191
192 return Ok(
193 Self
194 {
195 resolvers: resolvers,
196 ordered_req_list: reqs,
197 opts: opts,
198 }
199 );
200 }
201
202 pub async
212 fn query(mut self) -> QDnsQueryResult
213 {
214 let now =
216 if self.opts.measure_time == true
217 {
218 Some(Instant::now())
219 }
220 else
221 {
222 None
223 };
224
225 if self.resolvers.lookup.is_file_first()
228 {
229 let mut query_res =
230 match self.lookup_file(now.as_ref()).await
231 {
232 Ok(file) =>
233 {
234 if file.is_empty() == false
235 {
236 self.ordered_req_list.retain(|req|
238 {
239 return !file.contains_dnsreq(req);
240 }
241 );
242 }
243
244 file
245 },
246 Err(e) =>
247 {
248 write_error!(e);
249
250 QDnsQueryResult::default()
251 }
252 };
253
254
255 if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_bind() == true
257 {
258 let res = self.process_request(now.as_ref()).await;
259
260 query_res.extend(res);
261 }
262
263 return query_res;
264 }
265 else
266 {
267 let mut dns_res = self.process_request(now.as_ref()).await;
268 if dns_res.is_empty() == false
269 {
270 self.ordered_req_list.retain(|req|
272 {
273 return !dns_res.contains_dnsreq(req);
274 }
275 );
276 }
277
278
279
280 if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_file() == true
281 {
282 match self.lookup_file(now.as_ref()).await
283 {
284 Ok(res) =>
285 {
286 dns_res.extend(res);
287 },
288 Err(e) =>
289 {
290 write_error!(e);
291 }
292 }
293 }
294
295 return dns_res;
296 }
297 }
298
299 fn get_timeout(&self) -> Duration
301 {
302 if let Some(timeout) = self.opts.timeout
303 {
304 return Duration::from_secs(timeout as u64);
305 }
306 else
307 {
308 return Duration::from_secs(self.resolvers.timeout as u64);
309 }
310 }
311
312 async
314 fn lookup_file(&mut self, now: Option<&Instant>) -> CDnsResult<QDnsQueryResult>
315 {
316 let mut dnsquries: QDnsQueryResult = QDnsQueryResult::default();
317
318 if self.opts.ign_hosts == false
320 {
321 let hlist = CACHE.clone_host_list().await?;
322
323 for req in self.ordered_req_list.iter()
324 {
325 match *req.get_type()
326 {
327 QType::A | QType::AAAA =>
328 {
329 let req_name = String::from(req.get_req_name());
330
331 let Some(host_name_ent) = hlist.search_by_fqdn(req.get_type(), req_name.as_str())
332 else { continue };
333
334 let Some(drp) = DnsResponsePayload::new_local(*req.get_type(), host_name_ent)
335 else { continue };
336
337 dnsquries.push(req.clone(), Ok(QDnsQuery::from_local(drp, now)));
339 },
340 QType::PTR =>
341 {
342 let Ok(ip) = IpAddr::try_from(req.get_req_name())
343 else { continue };
344
345 let Some(host_name_ent) = hlist.search_by_ip(&ip)
346 else { continue };
347
348 let Some(drp) = DnsResponsePayload::new_local(*req.get_type(), host_name_ent)
349 else { continue };
350
351 dnsquries.push(req.clone(), Ok(QDnsQuery::from_local(drp, now)));
352 },
353 _ =>
354 continue,
355 }
356 }
357
358 }
359
360 return Ok(dnsquries);
361 }
362
363#[inline]
366 fn create_socket(&self, force_tcp: bool, resolver: Arc<ResolveConfEntry>) -> CDnsResult<Box<NetworkTapType>>
367 {
368if resolver.get_tls_type() != ConfigEntryTls::None
370 {
371 return NetworkTap::<TcpTlsConnection>::new(resolver, self.get_timeout());
372 }
373 else if self.resolvers.option_flags.is_force_tcp() == true || force_tcp == true
374 {
375 return NetworkTap::<TcpStream>::new(resolver, self.get_timeout());
376 }
377 else
378 {
379 return NetworkTap::<UdpSocket>::new(resolver, self.get_timeout());
380 }
381 }
382
383 async
385 fn process_request(&mut self, now: Option<&Instant>) -> QDnsQueryResult
386 {
387 let mut responses: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
388
389 if self.resolvers.option_flags.is_no_parallel() == true
390 {
391 for req in self.ordered_req_list.iter()
392 {
393 let mut last_resp: Option<CDnsResult<QDnsQuery>> = None;
394
395 for resolver in self.resolvers.get_resolvers_iter()
396 {
397 match self.query_exec_seq(now, resolver.clone(), req, None).await
398 {
399 Ok(resp) =>
400 {
401 if resp.should_check_next_ns() == true
402 {
403 last_resp = Some(Ok(resp));
404
405 continue;
406 }
407 else
408 {
409 responses.push(req.clone(), Ok(resp));
410
411 let _ = last_resp.take();
412
413 break;
414 }
415 },
416 Err(e) =>
417 {
418 if last_resp.is_none() == true
419 {
420 last_resp = Some(Err(e));
421 }
422
423 continue;
424 }
425 }
426 } responses.push(req.clone(), last_resp.take().unwrap());
429 }}
431 else
432 {
433 for resolver in self.resolvers.get_resolvers_iter()
436 {
437 if self.ordered_req_list.is_empty() == true
438 {
439 break;
440 }
441
442 match self.query_exec_pipelined(now, resolver.clone(), None).await
443 {
444 Ok(resp) =>
445 {
446 for (qdns_res, qdns_que) in resp
447 {
448 if let Ok(ref resp) = qdns_que
449 {
450 if resp.should_check_next_ns() == false
451 {
452 self
453 .ordered_req_list
454 .retain(
455 |req_item|
456 req_item != &qdns_res
457 );
458 }
459 }
460
461 responses.push(qdns_res, qdns_que);
462 }
463 },
464 Err(e) =>
465 {
466 write_error!(e);
467
468 continue;
469 }
470 }
471 }
472 }
473
474 return responses;
475 }
476
477 #[async_recursion]
478 async
479 fn query_exec_pipelined(
480 &self,
481 now: Option<&Instant>,
482 resolver: Arc<ResolveConfEntry>,
483 requery: Option<HashMap<DnsRequestHeader, QDnsReq>>,
484 ) -> CDnsResult<QDnsQueryResult>
485 {
486 let force_tcp = self.resolvers.option_flags.is_force_tcp() || requery.is_some();
487
488 let mut query_headers: HashMap<DnsRequestHeader, QDnsReq> =
489 if let Some(requer) = requery
490 {
491 let pkts_ids = requer.iter().map(|q| q.0.get_id()).collect::<BTreeSet<u16>>();
492
493 requer
495 .into_iter()
496 .map(
497 |(mut qrr, qdr)|
498 {
499 loop
500 {
501 qrr.regenerate_id();
502
503 if pkts_ids.contains(&qrr.get_id()) == false
504 {
505 break;
506 }
507 }
508 (qrr, qdr)
509 })
510 .collect::<HashMap<DnsRequestHeader, QDnsReq>>()
511 }
512 else
513 {
514 let mut pkts_ids: BTreeSet<u16> = BTreeSet::new();
515
516 self
518 .ordered_req_list
519 .iter()
520 .map(
521 |query|
522 {
523
524 let mut drh_res = DnsRequestHeader::try_from(query);
525
526 loop
527 {
528 if let Ok(ref mut drh) = drh_res
529 {
530 if pkts_ids.contains(&drh.get_id()) == true
531 {
532 drh.regenerate_id();
533
534 continue;
535 }
536 else
537 {
538 pkts_ids.insert(drh.get_id());
539 break;
540 }
541 }
542 else
543 {
544 break;
545 }
546 }
547
548 drh_res.map(|dh| (dh, query.clone()))
549 }
550 )
551 .collect::<CDnsResult<HashMap<DnsRequestHeader, QDnsReq>>>()?
552 };
553
554 let mut tap = self.create_socket(force_tcp, resolver.clone())?;
556
557 tap.connect(CDdnsGlobals::get_tcp_conn_timeout()).await?;
558
559 for qh in query_headers.iter()
561 {
562 let pkt = qh.0.to_bytes(tap.should_append_len())?;
563
564 tap.send(pkt.as_slice()).await?;
565 }
566
567 let mut resp: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
568 let mut requery: HashMap<DnsRequestHeader, QDnsReq> = HashMap::new();
569 loop
572 {
573 if query_headers.len() == 0
574 {
575 break;
576 }
577
578 tap.poll_read().await?;
579
580 let ans = self.read_response(tap.as_mut()).await?;
581
582 let Some((query_header, qdnsreq)) = query_headers.remove_entry(&ans.req_header)
583 else
584 {
585 internal_error!(CDnsErrorType::IoError, "can not find response with request: {}", ans.req_header);
586 };
587
588 ans.verify(&query_header)?;
589
590 let qdns_resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now);
592
593 if let Ok(ref qdns) = qdns_resp
594 {
595 if qdns.get_status().should_try_tcp() == true && force_tcp == false
596 {
597 requery.insert(query_header, qdnsreq);
598 }
599 else
600 {
601 resp.push(qdnsreq, qdns_resp);
602 }
603 }
604 else
605 {
606 resp.push(qdnsreq, qdns_resp);
607 }
608 }
609
610 if requery.is_empty() == false
611 {
612 let res = self.query_exec_pipelined(now, resolver, Some(requery)).await?;
613
614 resp.extend(res);
615 }
616
617 return Ok(resp);
618 }
619
620 #[async_recursion]
622 async
623 fn query_exec_seq(
624 &self,
625 now: Option<&Instant>,
626 resolver: Arc<ResolveConfEntry>,
627 query: &QDnsReq,
628 requery: Option<DnsRequestHeader>,
629 ) -> CDnsResult<QDnsQuery>
630 {
631 let force_tcp = self.resolvers.option_flags.is_force_tcp() || requery.is_some();
632
633 let mut tap = self.create_socket(force_tcp, resolver.clone())?;
635
636 let query_header =
637 if let Some(mut requery) = requery
639 {
640 requery.regenerate_id();
641
642 requery
643 }
644 else
645 {
646 let drh_req = DnsRequestHeader::try_from(query)?;
647
648 drh_req
649 };
650
651 let res =
652 {
653 tap.connect(CDdnsGlobals::get_tcp_conn_timeout()).await?;
655
656 let pkt = query_header.to_bytes(tap.should_append_len())?;
658
659 tap.send(pkt.as_slice()).await?;
661
662 let ans = self.read_response(tap.as_mut()).await?;
663
664 ans.verify(&query_header)?;
665
666 let resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now)?;
668
669 Ok(resp)
670 };
671
672 if (res.is_ok() == true && res.as_ref().unwrap().status.should_try_tcp() == false) ||
673 (res.is_err() == true && force_tcp == true)
674 {
675 return res;
676 }
677
678
679 return
680 self.query_exec_seq(now, resolver.clone(), query, Some(query_header)).await;
681 }
682
683 async
685 fn read_response(&self, socktap: &mut (dyn SocketTap)) -> CDnsResult<DnsRequestAnswer>
686 {
687 if socktap.is_tcp() == false
688 {
689 let mut rcvbuf = vec![0_u8; 1457];
690
691 let n = socktap.recv(rcvbuf.as_mut_slice()).await?;
693
694 return DnsRequestAnswer::parse(&rcvbuf); }
697 else
698 {
699 let mut pkg_pen: [u8; 2] = [0, 0];
700 let n = socktap.recv(&mut pkg_pen).await?;
701
702 if n == 0
703 {
704 internal_error!(CDnsErrorType::IoError, "tcp received zero len message!");
705 }
706 else if n != 2
707 {
708 internal_error!(CDnsErrorType::IoError, "tcp expected 2 bytes to be read!");
709 }
710
711 let ln = u16::from_be_bytes(pkg_pen);
712
713 let mut rcvbuf = vec![0_u8; ln as usize];
714
715 let mut n = socktap.recv(rcvbuf.as_mut_slice()).await?;
717
718 if n == 0
719 {
720 internal_error!(CDnsErrorType::IoError, "tcp received zero len message!");
721 }
722 else if n == 1
723 {
724 n = socktap.recv(&mut rcvbuf[1..]).await?;
725
726 if n == 0
727 {
728 internal_error!(CDnsErrorType::IoError, "tcp received zero len message again!");
729 }
730
731 n += 1;
732 }
733
734 return DnsRequestAnswer::parse(&rcvbuf);
735 }
736 }
737}
738
739#[cfg(test)]
740mod tests
741{
742 use std::net::IpAddr;
743
744 use crate::{a_sync::query::QDns, common::{byte2hexchar, ip2pkt, RecordPTR, RecordReader}, QDnsQueryRec, QType, QuerySetup};
745
746 #[tokio::test]
747 async fn test_ip2pkt()
748 {
749 use tokio::time::Instant;
750 use std::net::{IpAddr, Ipv4Addr};
751
752 let test = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
753
754 let now = Instant::now();
755
756 let res = ip2pkt(&test);
757
758 let elapsed = now.elapsed();
759 println!("Elapsed: {:.2?}", elapsed);
760
761 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
762
763 let res = res.unwrap();
764 let ctrl = b"\x01\x38\x01\x38\x01\x38\x01\x38\x07\x69\x6e\x2d\x61\x64\x64\x72\x04\x61\x72\x70\x61\x00";
765
766 assert_eq!(res.as_slice(), ctrl);
767 }
768
769
770 #[tokio::test]
771 async fn test_byte2hexchar()
772 {
773 assert_eq!(byte2hexchar(1), 0x31);
774 assert_eq!(byte2hexchar(9), 0x39);
775 assert_eq!(byte2hexchar(10), 'a' as u8);
776 assert_eq!(byte2hexchar(15), 'f' as u8);
777 }
778
779
780 #[tokio::test]
781 async fn reverse_lookup_test()
782 {
783 use tokio::time::Instant;
784
785 let ipp: IpAddr = "8.8.8.8".parse().unwrap();
786 let mut query_setup = QuerySetup::default();
789 query_setup.set_measure_time(true);
790
791 let now = Instant::now();
792
793 let mut dns_req =
794 QDns::make_empty(None, query_setup).await.unwrap();
795
796 dns_req.add_request(QType::PTR, ipp);
797
798 let res = dns_req.query().await;
799
800 let elapsed = now.elapsed();
801 println!("Elapsed: {:.2?}", elapsed);
802
803 println!("{}", res);
804
805 assert_eq!(res.is_empty(), false);
806
807 let recs = res.collect_ok();
808 let rec = &recs[0];
809 assert_eq!(rec.status, QDnsQueryRec::Ok);
811
812 assert_eq!(rec.resp.len(), 1);
813 assert_eq!(rec.resp[0].rdata, RecordPTR::wrap(RecordPTR{ fqdn: "dns.google".to_string() }));
814 }
815
816 #[tokio::test]
817 async fn reverse_lookup_hosts_test()
818 {
819 use tokio::time::Instant;
820
821 let ipp: IpAddr = "127.0.0.1".parse().unwrap();
822 let now = Instant::now();
825
826 let mut query_setup = QuerySetup::default();
827 query_setup.set_measure_time(true);
828
829 let mut dns_req =
830 QDns::make_empty(None, query_setup).await.unwrap();
831
832 dns_req.add_request(QType::PTR, ipp);
833
834 let res = dns_req.query().await;
835
836 let elapsed = now.elapsed();
837 println!("Elapsed: {:.2?}", elapsed);
838
839 println!("{}", res);
840
841 assert_eq!(res.is_empty(), false);
842
843 let recs = res.collect_ok();
844 let rec = &recs[0];
845
846 assert_eq!(rec.server.as_str(), "/etc/hosts");
847 assert_eq!(rec.status, QDnsQueryRec::Ok);
848
849 assert_eq!(rec.resp.len(), 1);
850 assert_eq!(rec.resp[0].rdata, RecordPTR::wrap(RecordPTR{ fqdn: "localhost".to_string() }));
851 }
852
853
854 #[tokio::test]
855 async fn reverse_lookup_a()
856 {
857 use tokio::time::Instant;
858
859 let mut query_setup = QuerySetup::default();
862 query_setup.set_measure_time(true);
863
864
865 let res = QDns::make_a_aaaa_request(None, "dns.google", query_setup).await.unwrap();
866
867
868 let now = Instant::now();
869 let res = res.query().await;
870
871
872 let elapsed = now.elapsed();
873 println!("Elapsed: {:.2?}", elapsed);
874
875 println!("{}", res);
876 }
877}