1use std::collections::{BTreeSet, HashMap};
25use std::convert::TryFrom;
26use std::io::ErrorKind;
27use std::net::{IpAddr, SocketAddr, TcpStream, ToSocketAddrs, UdpSocket};
28use std::vec;
29use std::sync::Arc;
30use std::time::Duration;
31use std::time::Instant;
32
33use crate::cfg_resolv_parser::{ConfigEntryTls, ResolveConfEntry, ResolveConfig, ResolveConfigFamily};
34use crate::{error::*, internal_error_map, write_error};
35use crate::query::{QDnsQuery, QDnsQueryResult, QuerySetup};
36use crate::sync::network::NetworkTap;
37use crate::internal_error;
38use crate::query_private::QDnsReq;
39use crate::common::*;
40
41use super::caches::CACHE;
42use super::network::SocketTap;
43
44#[cfg(feature = "use_sync_tls")]
45use super::network::with_tls::{TcpHttpsConnection, TcpTlsConnection};
46
47#[derive(Clone, Debug)]
51pub enum QDnsSockerAddr
52{
53 Ip(SocketAddr),
54 Host(String, u16)
55}
56
57impl ToSocketAddrs for QDnsSockerAddr
58{
59 type Iter = vec::IntoIter<SocketAddr>;
60
61 fn to_socket_addrs(&self) -> std::io::Result<Self::Iter>
62 {
63 match self
64 {
65 QDnsSockerAddr::Ip(socket_addr) =>
66 return Ok(vec![socket_addr.clone()].into_iter()),
67 QDnsSockerAddr::Host(host, port) =>
68 {
69 let qdns =
70 QDns::make_a_aaaa_request(None, host.as_str(), QuerySetup::default())
71 .map_err(|e|
72 std::io::Error::new(ErrorKind::NotFound, CDnsSuperError::from(e))
73 )?;
74
75 let res =
76 qdns
77 .query()
78 .collect_ok()
79 .into_iter()
80 .map(|resp|
81 resp
82 .get_responses()
83 .iter()
84 .map(|r|
85 r.get_rdata().get_ip().map(|f| SocketAddr::new(f, *port))
86 )
87 .collect::<Vec<Option<SocketAddr>>>()
88 )
89 .flatten()
90 .filter(|p| p.is_some())
91 .map(|v| v.unwrap())
92 .collect::<Vec<SocketAddr>>();
93
94 return Ok( res.into_iter() );
95 }
96 }
97 }
98}
99
100
101impl QDnsSockerAddr
102{
103 pub
112 fn resolve<D>(host: D) -> std::io::Result<Self>
113 where D: AsRef<str>
114 {
115 if let Ok(addr) = host.as_ref().parse::<SocketAddr>()
116 {
117 return Ok(Self::Ip(addr));
118 }
119 else
120 {
121 let ref_host = host.as_ref();
122
123 let (domain, port) =
124 match ref_host.split_once(":")
125 {
126 Some((h, portno)) =>
127 {
128 let port: u16 =
129 portno
130 .parse()
131 .map_err(|e|
132 std::io::Error::new(ErrorKind::InvalidData, format!("{}", e))
133 )?;
134
135 (h, port)
136 },
137 None =>
138 return Err(std::io::Error::new(ErrorKind::InvalidData, "missing prot number"))
139 };
140
141 return Ok(Self::Host(domain.to_string(), port));
142 }
143 }
144
145 pub
154 fn resolve_port<D>(host: D, port: u16) -> std::io::Result<Self>
155 where D: AsRef<str>
156 {
157 if let Ok(addr) = host.as_ref().parse::<IpAddr>()
158 {
159 return Ok(Self::Ip(SocketAddr::new(addr, port)));
160 }
161 else
162 {
163 return Ok(Self::Host(host.as_ref().to_string(), port));
164 }
165 }
166}
167
168#[derive(Clone, Debug)]
179pub struct QDns
180{
181 resolvers: Arc<ResolveConfig>,
183
184 ordered_req_list: Vec<QDnsReq>,
186
187 opts: QuerySetup,
189}
190
191impl QDns
192{
193 pub
213 fn make_empty(resolvers: Option<Arc<ResolveConfig>>, opts: QuerySetup) -> CDnsResult<Self>
214 {
215 return Ok(
216 Self
217 {
218 resolvers: resolvers.unwrap_or(CACHE.clone_resolve_list()?),
219 ordered_req_list: Vec::new(),
220 opts: opts,
221 }
222 );
223 }
224
225 pub
233 fn add_request(&mut self, qtype: QType, req_name: impl Into<QDnsName>)
234 {
235 let qr = QDnsReq::new_into(req_name, qtype);
236
237 self.ordered_req_list.push(qr);
238
239 return;
240 }
241
242 pub
266 fn make_a_aaaa_request(resolvers_opt: Option<Arc<ResolveConfig>>, req_name: impl Into<QDnsName>,
267 opts: QuerySetup) -> CDnsResult<Self>
268 {
269 let resolvers = resolvers_opt.unwrap_or(CACHE.clone_resolve_list()?);
270
271 let reqs: Vec<QDnsReq> =
273 match resolvers.family
274 {
275 ResolveConfigFamily::INET4_INET6 =>
276 {
277 let req_n: QDnsName = req_name.into();
278
279 vec![
280 QDnsReq::new(req_n.clone(), QType::A),
281 QDnsReq::new(req_n, QType::AAAA),
282 ]
283 },
284 ResolveConfigFamily::INET6_INET4 =>
285 {
286 let req_n: QDnsName = req_name.into();
287
288 vec![
289 QDnsReq::new(req_n.clone(), QType::AAAA),
290 QDnsReq::new(req_n, QType::A),
291 ]
292 },
293 ResolveConfigFamily::INET6 =>
294 {
295 vec![
296 QDnsReq::new(req_name.into(), QType::AAAA),
297 ]
298 },
299 ResolveConfigFamily::INET4 =>
300 {
301 vec![
302 QDnsReq::new(req_name.into(), QType::A),
303 ]
304 }
305 _ =>
306 {
307 let req_n: QDnsName = req_name.into();
309
310 vec![
311 QDnsReq::new(req_n.clone(), QType::A),
312 QDnsReq::new(req_n, QType::AAAA),
313 ]
314 }
315 };
316
317
318
319 return Ok(
320 Self
321 {
322 resolvers: resolvers,
323 ordered_req_list: reqs,
324 opts: opts,
325 }
326 );
327 }
328
329 pub
336 fn query(mut self) -> QDnsQueryResult
337 {
338 let now =
340 if self.opts.measure_time == true
341 {
342 Some(Instant::now())
343 }
344 else
345 {
346 None
347 };
348
349 if self.resolvers.lookup.is_file_first()
352 {
353 let mut query_res =
354 match self.lookup_file(now.as_ref())
355 {
356 Ok(file) =>
357 {
358 if file.is_empty() == false
359 {
360 self.ordered_req_list.retain(|req|
362 {
363 return !file.contains_dnsreq(req);
364 }
365 );
366 }
367
368 file
369 },
370 Err(e) =>
371 {
372 write_error!(e);
373
374 QDnsQueryResult::default()
375 }
376 };
377
378
379 if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_bind() == true
381 {
382 let res = self.process_request(now.as_ref());
383
384 query_res.extend(res);
385 }
386
387 return query_res;
388 }
389 else
390 {
391 let mut dns_res = self.process_request(now.as_ref());
392 if dns_res.is_empty() == false
393 {
394 self.ordered_req_list.retain(|req|
396 {
397 return !dns_res.contains_dnsreq(req);
398 }
399 );
400 }
401
402
403
404 if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_file() == true
405 {
406 match self.lookup_file(now.as_ref())
407 {
408 Ok(res) =>
409 {
410 dns_res.extend(res);
411 },
412 Err(e) =>
413 {
414 write_error!(e);
415 }
416 }
417 }
418
419 return dns_res;
420 }
421 }
422
423 fn get_timeout(&self) -> Duration
425 {
426 if let Some(timeout) = self.opts.timeout
427 {
428 return Duration::from_secs(timeout as u64);
429 }
430 else
431 {
432 return Duration::from_secs(self.resolvers.timeout as u64);
433 }
434 }
435
436 fn lookup_file(&mut self, now: Option<&Instant>) -> CDnsResult<QDnsQueryResult>
438 {
439 let mut dnsquries: QDnsQueryResult = QDnsQueryResult::default();
440
441 if self.opts.ign_hosts == false
443 {
444 let hlist = CACHE.clone_host_list()?;
445
446 for req in self.ordered_req_list.iter()
447 {
448 match *req.get_type()
449 {
450 QType::A | QType::AAAA =>
451 {
452 let req_name = String::from(req.get_req_name());
453
454 let Some(host_name_ent) = hlist.search_by_fqdn(req.get_type(), req_name.as_str())
455 else { continue };
456
457 let Some(drp) = DnsResponsePayload::new_local(*req.get_type(), host_name_ent)
458 else { continue };
459
460 dnsquries.push(req.clone(), Ok(QDnsQuery::from_local(drp, now)));
462 },
463 QType::PTR =>
464 {
465 let Ok(ip) = IpAddr::try_from(req.get_req_name())
466 else { continue };
467
468 let Some(host_name_ent) = hlist.search_by_ip(&ip)
469 else { continue };
470
471 let Some(drp) = DnsResponsePayload::new_local(*req.get_type(), host_name_ent)
472 else { continue };
473
474 dnsquries.push(req.clone(), Ok(QDnsQuery::from_local(drp, now)));
475 },
476 _ =>
477 continue,
478 }
479 }
480
481
482 }
483
484 return Ok(dnsquries);
485 }
486
487
488 #[inline]
491 fn create_socket(&self, force_tcp: bool, resolver: Arc<ResolveConfEntry>) -> Option<Box<dyn SocketTap>>
492 {
493 let is_tls = resolver.get_tls_type();
494
495 if is_tls == ConfigEntryTls::Tls
496 {
497 #[cfg(feature = "use_sync_tls")]
498 return Some(NetworkTap::<TcpTlsConnection>::new_tls(resolver, self.get_timeout()));
499 #[cfg(not(feature = "use_sync_tls"))]
500 return None;
501 }
502 else if is_tls == ConfigEntryTls::Https
503 {
504 #[cfg(feature = "use_sync_tls")]
505 return Some(NetworkTap::<TcpHttpsConnection>::new_https(resolver, self.get_timeout()));
506 #[cfg(not(feature = "use_sync_tls"))]
507 return None;
508 }
509 else if self.resolvers.option_flags.is_force_tcp() == true || force_tcp == true
510 {
511 return Some(NetworkTap::<TcpStream>::new_tcp(resolver, self.get_timeout()));
512 }
513 else
514 {
515 return Some(NetworkTap::<UdpSocket>::new_udp(resolver, self.get_timeout()));
516 }
517 }
518
519
520 fn process_request(&mut self, now: Option<&Instant>) -> QDnsQueryResult
522 {
523 let mut responses: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
524
525 if self.resolvers.option_flags.is_no_parallel() == true
526 {
527 for req in self.ordered_req_list.iter()
528 {
529 let mut last_resp: Option<CDnsResult<QDnsQuery>> = None;
530
531 for resolver in self.resolvers.get_resolvers_iter()
532 {
533 match self.query_exec_seq(now, resolver.clone(), req, None)
534 {
535 Ok(resp) =>
536 {
537 if resp.should_check_next_ns() == true
538 {
539 last_resp = Some(Ok(resp));
540
541 continue;
542 }
543 else
544 {
545 responses.push(req.clone(), Ok(resp));
546
547 let _ = last_resp.take();
548
549 break;
550 }
551 },
552 Err(e) =>
553 {
554 if last_resp.is_none() == true
555 {
556 last_resp = Some(Err(e));
557 }
558
559 continue;
560 }
561 }
562 } responses.push(req.clone(), last_resp.take().unwrap());
565 }}
567 else
568 {
569 for resolver in self.resolvers.get_resolvers_iter()
572 {
573 if self.ordered_req_list.is_empty() == true
574 {
575 break;
576 }
577
578 match self.query_exec_pipelined(now, resolver.clone(), None)
579 {
580 Ok(resp) =>
581 {
582 for (qdns_res, qdns_que) in resp
583 {
584 if let Ok(ref resp) = qdns_que
585 {
586 if resp.should_check_next_ns() == false
587 {
588 self
589 .ordered_req_list
590 .retain(
591 |req_item|
592 req_item != &qdns_res
593 );
594 }
595 }
596
597 responses.push(qdns_res, qdns_que);
598 }
599 },
600 Err(e) =>
601 {
602 write_error!(e);
603
604 continue;
605 }
606 }
607 }
608 }
609
610 return responses;
611 }
612
613 fn query_exec_pipelined(
616 &self,
617 now: Option<&Instant>,
618 resolver: Arc<ResolveConfEntry>,
619 requery: Option<HashMap<DnsRequestHeader, QDnsReq>>,
620 ) -> CDnsResult<QDnsQueryResult>
621 {
622 let force_tcp = self.resolvers.option_flags.is_force_tcp() || requery.is_some();
623
624 let mut query_headers: HashMap<DnsRequestHeader, QDnsReq> =
625 if let Some(requer) = requery
626 {
627 let pkts_ids = requer.iter().map(|q| q.0.get_id()).collect::<BTreeSet<u16>>();
628
629 requer
631 .into_iter()
632 .map(
633 |(mut qrr, qdr)|
634 {
635 loop
636 {
637 qrr.regenerate_id();
638
639 if pkts_ids.contains(&qrr.get_id()) == false
640 {
641 break;
642 }
643 }
644 (qrr, qdr)
645 })
646 .collect::<HashMap<DnsRequestHeader, QDnsReq>>()
647 }
648 else
649 {
650 let mut pkts_ids: BTreeSet<u16> = BTreeSet::new();
651
652 self
654 .ordered_req_list
655 .iter()
656 .map(
657 |query|
658 {
659
660 let mut drh_res = DnsRequestHeader::try_from(query);
661
662 loop
663 {
664 if let Ok(ref mut drh) = drh_res
665 {
666 if pkts_ids.contains(&drh.get_id()) == true
667 {
668 drh.regenerate_id();
669
670 continue;
671 }
672 else
673 {
674 pkts_ids.insert(drh.get_id());
675 break;
676 }
677 }
678 else
679 {
680 break;
681 }
682 }
683
684 drh_res.map(|dh| (dh, query.clone()))
685 }
686 )
687 .collect::<CDnsResult<HashMap<DnsRequestHeader, QDnsReq>>>()?
688 };
689
690 let mut tap =
692 self
693 .create_socket(force_tcp, resolver.clone())
694 .ok_or_else(||
695 internal_error_map!(CDnsErrorType::SocketNotSupported,
696 "socket not supported: '{}'", resolver.get_tls_type())
697 )?;
698
699
700
701 tap.connect(true, CDdnsGlobals::get_tcp_conn_timeout())?;
702
703 for qh in query_headers.iter()
705 {
706 let pkt = qh.0.to_bytes(tap.should_append_len())?;
707
708 tap.send(pkt.as_slice())?;
709 }
710
711 let mut resp: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
712 let mut requery: HashMap<DnsRequestHeader, QDnsReq> = HashMap::new();
713 loop
716 {
717 if query_headers.len() == 0
718 {
719 break;
720 }
721
722 if tap.poll_read()? == false
723 {
724 break;
726 }
727
728 let ans = tap.recv()?;let Some((query_header, qdnsreq)) = query_headers.remove_entry(&ans.req_header)
731 else
732 {
733 internal_error!(CDnsErrorType::IoError, "can not find response with request: {}", ans.req_header);
734 };
735
736 ans.verify(&query_header)?;
737
738 let qdns_resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now);
740
741 if let Ok(ref qdns) = qdns_resp
742 {
743 if qdns.get_status().should_try_tcp() == true && force_tcp == false
744 {
745 requery.insert(query_header, qdnsreq);
746 }
747 else
748 {
749 resp.push(qdnsreq, qdns_resp);
750 }
751 }
752 else
753 {
754 resp.push(qdnsreq, qdns_resp);
755 }
756 }
757
758 if requery.is_empty() == false
759 {
760 let res = self.query_exec_pipelined(now, resolver, Some(requery))?;
761
762 resp.extend(res);
763 }
764
765 return Ok(resp);
766 }
767
768 fn query_exec_seq(
770 &self,
771 now: Option<&Instant>,
772 resolver: Arc<ResolveConfEntry>,
773 query: &QDnsReq,
774 requery: Option<DnsRequestHeader>,
775 ) -> CDnsResult<QDnsQuery>
776 {
777 let force_tcp = self.resolvers.option_flags.is_force_tcp() || requery.is_some();
778
779 let mut tap =
781 self
782 .create_socket(force_tcp, resolver.clone())
783 .ok_or_else(||
784 internal_error_map!(CDnsErrorType::SocketNotSupported,
785 "socket not supported: '{}'", resolver.get_tls_type())
786 )?;
787
788 let query_header =
789 if let Some(mut requery) = requery
791 {
792 requery.regenerate_id();
793
794 requery
795 }
796 else
797 {
798 let drh_req = DnsRequestHeader::try_from(query)?;
799
800 drh_req
801 };
802
803 let res =
804 {
805 tap.connect(false, CDdnsGlobals::get_tcp_conn_timeout())?;
807
808 let pkt = query_header.to_bytes(tap.should_append_len())?;
810
811 tap.send(pkt.as_slice())?;
813
814 let ans = tap.recv()?; ans.verify(&query_header)?;
817
818 let resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now)?;
820
821 Ok(resp)
822 };
823
824 if (res.is_ok() == true && res.as_ref().unwrap().status.should_try_tcp() == false) ||
825 (res.is_err() == true && force_tcp == true)
826 {
827 return res;
828 }
829
830
831 return
832 self.query_exec_seq(now, resolver.clone(), query, Some(query_header));
833 }
834
835 }
894
895#[cfg(test)]
896
897mod tests
898{
899 use std::net::IpAddr;
900
901 use crate::{common::{byte2hexchar, ip2pkt, RecordPTR, RecordReader}, sync::{query::QDns}, QDnsQueryRec, QType, QuerySetup};
902
903 #[test]
904 fn test_ip2pkt()
905 {
906 use std::time::Instant;
907 use std::net::{IpAddr, Ipv4Addr};
908
909 let test = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
910
911 let now = Instant::now();
912
913 let res = ip2pkt(&test);
914
915 let elapsed = now.elapsed();
916 println!("Elapsed: {:.2?}", elapsed);
917
918 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
919
920 let res = res.unwrap();
921 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";
922
923 assert_eq!(res.as_slice(), ctrl);
924 }
925
926
927 #[test]
928 fn test_byte2hexchar()
929 {
930 assert_eq!(byte2hexchar(1), 0x31);
931 assert_eq!(byte2hexchar(9), 0x39);
932 assert_eq!(byte2hexchar(10), 'a' as u8);
933 assert_eq!(byte2hexchar(15), 'f' as u8);
934 }
935
936 #[test]
937 fn reverse_lookup_test()
938 {
939 use std::time::Instant;
940
941 let ipp: IpAddr = "8.8.8.8".parse().unwrap();
942 let mut query_setup = QuerySetup::default();
945 query_setup.set_measure_time(true);
946
947 let now = Instant::now();
948
949 let mut dns_req =
950 QDns::make_empty(None, query_setup).unwrap();
951
952 dns_req.add_request(QType::PTR, ipp);
953 let res = dns_req.query();
954
955 let elapsed = now.elapsed();
956 println!("Elapsed: {:.2?}", elapsed);
957
958 println!("{}", res);
959
960 assert_eq!(res.is_empty(), false);
961
962 let recs = res.collect_ok();
963 let rec = &recs[0];
964 assert_eq!(rec.status, QDnsQueryRec::Ok);
966
967 assert_eq!(rec.resp.len(), 1);
968 assert_eq!(rec.resp[0].rdata, RecordPTR::wrap(RecordPTR{ fqdn: "dns.google".to_string() }));
969 }
970
971 #[test]
972 fn reverse_lookup_hosts_test()
973 {
974 use std::time::Instant;
975
976 let ipp: IpAddr = "127.0.0.1".parse().unwrap();
977 let now = Instant::now();
980
981 let mut query_setup = QuerySetup::default();
982 query_setup.set_measure_time(true);
983
984 let mut dns_req =
985 QDns::make_empty(None, query_setup).unwrap();
986
987 dns_req.add_request(QType::PTR, ipp);
988
989 let res = dns_req.query();
990
991 let elapsed = now.elapsed();
992 println!("Elapsed: {:.2?}", elapsed);
993
994 println!("{}", res);
995
996 assert_eq!(res.is_empty(), false);
997
998 let recs = res.collect_ok();
999 let rec = &recs[0];
1000
1001 assert_eq!(rec.server.as_str(), "/etc/hosts");
1002 assert_eq!(rec.status, QDnsQueryRec::Ok);
1003
1004 assert_eq!(rec.resp.len(), 1);
1005 assert_eq!(rec.resp[0].rdata, RecordPTR::wrap(RecordPTR{ fqdn: "localhost".to_string() }));
1006 }
1007
1008
1009 #[test]
1010 fn reverse_lookup_a()
1011 {
1012 use std::time::Instant;
1013
1014 let mut query_setup = QuerySetup::default();
1017 query_setup.set_measure_time(true);
1018
1019
1020 let res =
1021 QDns::make_a_aaaa_request(None, "dns.google", query_setup).unwrap();
1022
1023
1024 let now = Instant::now();
1025 let res = res.query();
1026
1027
1028 let elapsed = now.elapsed();
1029 println!("Elapsed: {:.2?}", elapsed);
1030
1031 println!("{}", res);
1035 }
1036
1037
1038 #[test]
1039 fn truncation_test_1()
1040 {
1041 use std::time::Instant;
1042
1043 let mut query_setup = QuerySetup::default();
1046 query_setup.set_measure_time(true);
1047
1048
1049 let mut res =
1050 QDns::make_empty(None, query_setup).unwrap();
1051
1052 res.add_request(QType::TXT, "truncate-zyxw11.go.dnscheck.tools");
1053
1054
1055 let now = Instant::now();
1056 let res = res.query();
1057
1058
1059 let elapsed = now.elapsed();
1060 println!("Elapsed: {:.2?}", elapsed);
1061
1062 println!("{}", res);
1066 }
1067
1068 #[test]
1069 fn truncation_test_2()
1070 {
1071 use std::time::Instant;
1072
1073 let mut query_setup = QuerySetup::default();
1079 query_setup.set_measure_time(true);
1080
1081
1082 let mut res =
1083 QDns::make_empty(None, query_setup).unwrap();
1084
1085 res.add_request(QType::A, "dnscheck.tools");
1086 res.add_request(QType::A, "localhost");
1087 res.add_request(QType::A, "unknownnonexistentdomain.com");
1088 res.add_request(QType::TXT, "example.com");
1089
1090
1091 let now = Instant::now();
1092 let res = res.query();
1093
1094
1095 let elapsed = now.elapsed();
1096 println!("Elapsed: {:.2?}", elapsed);
1097
1098
1099 let (ans, errs) = res.collect_split();
1100
1101 println!("ANSWERS");
1102 for a in ans
1103 {
1104 println!("-----\n{} \n{}", a.0, a.1.unwrap());
1105 }
1106
1107 println!("ERRORS");
1108 for b in errs
1109 {
1110 println!("-----\n{} \n{}", b.0, b.1.err().unwrap());
1111 }
1112 }
1113}