1use std::collections::{LinkedList, BTreeSet, HashSet};
25use std::convert::TryFrom;
26use std::net::IpAddr;
27use std::os::fd::{AsFd, AsRawFd, RawFd};
28use std::sync::Arc;
29use std::time::Duration;
30use std::time::Instant;
31
32use nix::poll::{PollFd, PollFlags, PollTimeout};
33
34use crate::cfg_resolv_parser::{ResolveConfig, ResolveConfigFamily, ResolveConfEntry};
35use crate::error::*;
36use crate::query::{QuerySetup, QDnsQueriesRes, QDnsQuery, QDnsQueryRec};
37use crate::{write_error, internal_error, internal_error_map};
38use crate::query_private::QDnsReq;
39
40use super::common::*;
41use super::caches::CACHE;
42use super::network::{new_udp, new_tcp, SocketTap};
43use super::query_polltaps::{PollTaps, Tap};
44
45pub struct QDns
47{
48 resolvers: Arc<ResolveConfig>,
50 ordered_req_list: Vec<QDnsReq>,
52 opts: QuerySetup,
54}
55
56impl QDns
57{
58 pub
76 fn make_empty(resolvers: Arc<ResolveConfig>, planned_reqs_len: usize, opts: QuerySetup) -> Self
77 {
78 return
79 Self
80 {
81 resolvers: resolvers,
82 ordered_req_list: Vec::with_capacity(planned_reqs_len),
83 opts: opts,
84 };
85 }
86
87 pub
101 fn add_request<R>(&mut self, qtype: QType, req_name: R)
102 where R: Into<QDnsName>
103 {
104 let qr = QDnsReq::new(req_name.into(), qtype);
105
106 self.ordered_req_list.push(qr);
107
108 return;
109 }
110
111 pub
131 fn make_a_aaaa_request<R>(resolvers: Arc<ResolveConfig>, req_name: R, opts: QuerySetup) -> CDnsResult<Self>
132 where R: Into<QDnsName>
133 {
134 let reqs: Vec<QDnsReq> =
136 match resolvers.family
137 {
138 ResolveConfigFamily::INET4_INET6 =>
139 {
140 let req_n: QDnsName = req_name.into();
141
142 vec![
143 QDnsReq::new(req_n.clone(), QType::A),
144 QDnsReq::new(req_n, QType::AAAA),
145 ]
146 },
147 ResolveConfigFamily::INET6_INET4 =>
148 {
149 let req_n: QDnsName = req_name.into();
150
151 vec![
152 QDnsReq::new(req_n.clone(), QType::AAAA),
153 QDnsReq::new(req_n, QType::A),
154 ]
155 },
156 ResolveConfigFamily::INET6 =>
157 {
158 vec![
159 QDnsReq::new(req_name.into(), QType::AAAA),
160 ]
161 },
162 ResolveConfigFamily::INET4 =>
163 {
164 vec![
165 QDnsReq::new(req_name.into(), QType::A),
166 ]
167 }
168 _ =>
169 {
170 let req_n: QDnsName = req_name.into();
172
173 vec![
174 QDnsReq::new(req_n.clone(), QType::A),
175 QDnsReq::new(req_n, QType::AAAA),
176 ]
177 }
178 };
179
180
181
182 return Ok(
183 Self
184 {
185 resolvers: resolvers,
186 ordered_req_list: reqs,
187 opts: opts,
188 }
189 );
190 }
191
192 pub
202 fn query(mut self) -> QDnsQueriesRes
203 {
204 let now =
206 if self.opts.measure_time == true
207 {
208 Some(Instant::now())
209 }
210 else
211 {
212 None
213 };
214
215 let mut qres: QDnsQueriesRes = QDnsQueriesRes::DnsNotAvailable;
216
217 if self.resolvers.lookup.is_file_first()
220 {
221 match self.lookup_file(now.as_ref())
222 {
223 Ok(r) =>
224 qres.extend(r),
225 Err(e) =>
226 write_error!("{}", e),
227 }
228
229 if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_bind() == true
231 {
232 match self.process_request(now.as_ref())
233 {
234 Ok(r) =>
235 qres.extend(r),
236 Err(e) =>
237 write_error!("{}", e),
238 }
239 }
240 }
241 else
242 {
243 match self.process_request(now.as_ref())
244 {
245 Ok(r) =>
246 qres.extend(r),
247 Err(e) =>
248 write_error!("{}", e),
249 }
250
251
252 if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_file() == true
253 {
254 match self.lookup_file(now.as_ref())
255 {
256 Ok(r) =>
257 qres.extend(r),
258 Err(e) =>
259 write_error!("{}", e),
260 }
261 }
262 }
263
264 return qres;
265 }
266
267 fn get_timeout(&self) -> Duration
269 {
270 if let Some(timeout) = self.opts.timeout
271 {
272 return Duration::from_secs(timeout as u64);
273 }
274 else
275 {
276 return Duration::from_secs(self.resolvers.timeout as u64);
277 }
278 }
279
280 fn lookup_file(&mut self, now: Option<&Instant>) -> CDnsResult<QDnsQueriesRes>
282 {
283 if self.opts.ign_hosts == false
285 {
286 let hlist = CACHE.clone_host_list()?;
287
288 let mut dnsquries: LinkedList<QDnsQuery> = LinkedList::new();
289
290 self.ordered_req_list.retain(|req|
291 {
292 match *req.get_type()
293 {
294 QType::A | QType::AAAA =>
295 {
296 let req_name = String::from(req.get_req_name());
297
298 if let Some(res) = hlist.search_by_fqdn(req.get_type(), req_name.as_str())
299 {
300 let drp =
302 match DnsResponsePayload::new_local(*req.get_type(), res)
303 {
304 Ok(r) => r,
305 Err(e) =>
306 {
307 write_error!("{}", e);
308
309 return true;
310 }
311 };
312
313 dnsquries.push_back(
315 QDnsQuery::from_local(drp, now)
316 );
317
318 return false;
319 }
320 else
321 {
322 return true;
323 }
324 },
325 QType::PTR =>
326 {
327 let ip: IpAddr =
328 match IpAddr::try_from(req.get_req_name())
329 {
330 Ok(r) => r,
331 Err(e) =>
332 {
333 write_error!("{}", e);
335
336 return true;
337 }
338 };
339
340 if let Some(r) = hlist.search_by_ip(&ip)
341 {
342 let drp =
344 match DnsResponsePayload::new_local(QType::PTR, r)
345 {
346 Ok(r) => r,
347 Err(e) =>
348 {
349 write_error!("{}", e);
350
351 return true;
352 }
353 };
354
355 dnsquries.push_back(
357 QDnsQuery::from_local(drp, now)
358 );
359
360 return false;
361 }
362 else
363 {
364 return true;
365 }
366 },
367 _ =>
368 {
369 return true;
371 }
372 }
373 }
374 );
375
376 return Ok( QDnsQueriesRes::from(dnsquries) );
381 }
382 else
383 {
384 return Ok(QDnsQueriesRes::DnsNotAvailable);
385 }
386 }
387
388 fn create_socket(&self, force_tcp: bool, resolver: &ResolveConfEntry) -> CDnsResult<Box<dyn SocketTap>>
391 {
392 if self.resolvers.option_flags.is_force_tcp() == true || force_tcp == true
394 {
395 return new_tcp(resolver.get_resolver_ip(), 53, resolver.get_adapter_ip());
396 }
397 else
398 {
399 return new_udp(resolver.get_resolver_ip(), 53, resolver.get_adapter_ip());
400 };
401 }
402
403 fn create_sockets(
405 &self,
406 resolver: &ResolveConfEntry,
407 requery_list: Option<LinkedList<DnsRequestHeader>>,
408 force_tcp: bool,
409 ) -> CDnsResult<PollTaps>
410 {
411 let mut taps: PollTaps = PollTaps::new_with_capacity(self.ordered_req_list.len());
412
413
414 let force_tcp: bool =
415 force_tcp == true || self.resolvers.option_flags.is_force_tcp() == true;
416
417 if let Some(requery) = requery_list
418 {
419 let mut ids: HashSet<u16> = HashSet::with_capacity(requery.len());
420
421
422
423 for mut req in requery
424 {
425 if self.resolvers.option_flags.is_reopen_socket() == true || taps.len() == 0
426 {
427 let tap =
429 self.create_socket(force_tcp, resolver)?;
430
431 loop
433 {
434 req.regenerate_id();
435
436 if ids.insert(req.get_id()) == true
437 {
438 break;
439 }
440 }
441
442 taps.push(Tap::new(tap, req));
443 }
444 else
445 {
446 taps.push_to_last(req);
447 }
448 }
449
450
451 }
452 else
453 {
454 let mut ids: HashSet<u16> = HashSet::with_capacity(self.ordered_req_list.len());
455
456 for req in self.ordered_req_list.iter()
458 {
459 let mut drh_req = DnsRequestHeader::from_qdns_req(req, self.resolvers.as_ref())?;
460
461 loop
463 {
464 if ids.insert(drh_req.get_id()) == true
465 {
466 break;
467 }
468
469 drh_req.regenerate_id();
470 }
471
472 if self.resolvers.option_flags.is_reopen_socket() == true || taps.len() == 0
473 {
474 let tap =
476 self.create_socket(force_tcp, resolver)?;
477
478 taps.push(Tap::new(tap, drh_req));
479 }
480 else
481 {
482 taps.push_to_last(drh_req);
483 }
484 } }
488
489 return Ok(taps);
490 }
491
492 fn get_result(responses: &LinkedList<QDnsQuery>) -> QDnsQueryRec
494 {
495 let mut resp = QDnsQueryRec::Ok;
496
497 for r in responses.iter()
498 {
499 if r.is_ok() == false
500 {
501 resp = r.status;
502
503 return resp;
504 }
505 }
506
507 return resp;
508 }
509
510 fn get_authorative(responses: &LinkedList<QDnsQuery>) -> bool
512 {
513 return responses.front().map_or(false, |r| r.aa);
514 }
515
516 fn process_request(&mut self, now: Option<&Instant>) -> CDnsResult<QDnsQueriesRes>
518 {
519 let mut qresponses: LinkedList<QDnsQuery> = LinkedList::new();
520
521 for resolver in self.resolvers.get_resolvers_iter()
524 {
525 let qresp =
526 if self.resolvers.option_flags.is_no_parallel() == true
527 {
528 match self.no_parallel(now, resolver, None, false)
529 {
530 Ok(qresp) => qresp,
531 Err(e) =>
532 {
533 write_error!("{}", e);
534 continue;
535 }
536 }
537 }
538 else
539 {
540 match self.parallel(now, resolver, None, false)
541 {
542 Ok(qresp) => qresp,
543 Err(e) =>
544 {
545 write_error!("{}", e);
546 continue;
547 }
548 }
549 };
550
551 let dnsres = Self::get_result(&qresp);
553 let aa = Self::get_authorative(&qresp);
554
555 qresponses.extend(qresp);
556
557 if dnsres.try_next_nameserver(aa) == false
558 {
559 break;
560 }
561
562 }
563
564 return Ok(QDnsQueriesRes::from(qresponses));
565 }
566
567 fn no_parallel(
569 &self,
570 now: Option<&Instant>,
571 resolver: &ResolveConfEntry,
572 requery: Option<LinkedList<DnsRequestHeader>>,
573 force_tcp: bool
574 ) -> CDnsResult<LinkedList<QDnsQuery>>
575 {
576 let mut responses: LinkedList<QDnsQuery> = LinkedList::new();
579
580 let mut truncated_list: LinkedList<DnsRequestHeader> = LinkedList::new();
582
583 let taps_list =
585 self.create_sockets(resolver, requery, force_tcp)?;
586
587 for ptap in taps_list.into_iter()
588 {
589 let (mut tap, qdnsr) = ptap.unwrap_inner();
590
591 tap.connect(Some(self.get_timeout()))?;
593
594 for req in qdnsr
595 {
596 let pkt = req.to_bytes()?;
598
599 tap.send(pkt.as_slice())?;
601
602 let ans = self.read_response(tap.as_mut())?;
604
605 match ans.verify(&req)
607 {
608 Ok(_) => {},
609 Err(ref e)
610 if e.err_code == CDnsErrorType::MessageTruncated =>
611 {
612 write_error!("{}", e);
615
616 truncated_list.push_back(req);
617 },
618 Err(e) =>
619 return Err(e),
620 };
621
622 let resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now)?;
624
625 responses.push_back(resp);
626 } } if truncated_list.is_empty() == false
631 {
632 if force_tcp == true || self.resolvers.option_flags.is_force_tcp() == true
634 {
635 internal_error!(CDnsErrorType::MessageTruncated, "Message is truncated even using TCP. Give up.");
637 }
638
639 let res =
640 self.no_parallel(now, resolver, Some(truncated_list), true)?;
641
642 responses.extend(res);
643 }
644
645 return Ok(responses);
646 }
647
648 fn parallel(
650 &self,
651 now: Option<&Instant>,
652 resolver: &ResolveConfEntry,
653 requery: Option<LinkedList<DnsRequestHeader>>,
654 force_tcp: bool
655 ) -> CDnsResult<LinkedList<QDnsQuery>>
656 {
657 let mut responses: LinkedList<QDnsQuery> = LinkedList::new();
660
661 let mut taps_list = self.create_sockets(resolver, requery, force_tcp)?;
663
664 for ptap in taps_list.get_mut_iter()
670 {
671 ptap.get_tap_mut().connect(None)?;
673
674 let pkts = ptap.generate_packets()?;
675
676 for pkt in pkts
678 {
679 ptap.get_tap_mut().send(pkt.as_slice())?;
680 }
681 } let mut truncated_list: LinkedList<DnsRequestHeader> = LinkedList::new();
685
686 let poll_data =
688 self.run_poll(taps_list, &mut truncated_list, now)?;
689
690 responses.extend(poll_data);
692
693 if truncated_list.is_empty() == false
694 {
695 if force_tcp == true || self.resolvers.option_flags.is_force_tcp() == true
697 {
698 internal_error!(CDnsErrorType::MessageTruncated, "Message is truncated even using TCP. Give up.");
700 }
701
702 let res =
703 self.parallel(now, resolver, Some(truncated_list), true)?;
704
705 responses.extend(res);
706 }
707
708 return Ok(responses);
709 }
710
711 fn read_response(&self, socktap: &mut (dyn SocketTap)) -> CDnsResult<DnsRequestAnswer>
713 {
714 let mut rcvbuf = vec![0_u8; 1024];
715
716 socktap.recv(rcvbuf.as_mut_slice())?;
718
719 let ans = DnsRequestAnswer::try_from(rcvbuf.as_slice())?;
721
722 return Ok(ans);
723 }
724
725 fn run_poll(
727 &self,
728 mut taps_list: PollTaps,
729 trunc_list: &mut LinkedList<DnsRequestHeader>,
730 now: Option<&Instant>
731 ) ->CDnsResult<LinkedList<QDnsQuery>>
732 {
733 let mut responses: LinkedList<QDnsQuery> = LinkedList::new();
735
736 let mut timeout: nix::libc::c_int = (self.resolvers.timeout * 1000) as i32;
738
739 if timeout <= 0
741 {
742 write_error!("Somehow the timeout is 0, setting to 5000ms");
743 timeout = 5000;
744 }
745
746 let pt = PollTimeout::try_from(timeout).unwrap();
747
748 let mut reqs_await_list: BTreeSet<u16> = taps_list.get_reqs_list();
749
750 loop
757 {
758 if reqs_await_list.is_empty() == true
760 {
761 break;
763 }
764
765
766
767 let mut poll_list: Vec<PollFd> = taps_list.get_pollfd_list();
768 let poll_res =
770 nix::poll::poll(poll_list.as_mut_slice(), pt)
771 .map_err(|e| internal_error_map!(CDnsErrorType::IoError, "{}", e))?;
772
773 if poll_res == 0
774 {
775 internal_error!(CDnsErrorType::RequestTimeout, "timeout poll");
777 }
778
779 let mut events: Vec<RawFd> = Vec::with_capacity(poll_list.len());
780
781 for pfd in poll_list
782 {
783 let revents = pfd.revents();
784
785 if revents.is_none() == true
786 {
787 panic!("Crate NIX returned None due to unknown data returned by kernel!\
788 Try update nix crate! Probably it is outdated!");
789 }
790
791 let revents = revents.unwrap();
792
793 if revents.contains(PollFlags::POLLIN) == true
795 {
796 events.push(pfd.as_fd().as_raw_fd());
797 }
798 }
799
800 for rawfd in events
801 {
802
803 let ptap = taps_list.find_tap_by_tap_fd(rawfd);
805
806 let ans = self.read_response(ptap.get_tap_mut())?;
808
809 let ans_id = ans.header.id;
810
811 let req =
814 ptap.find_request(ans_id)
815 .ok_or_else(||
816 internal_error_map!(CDnsErrorType::RespIdMismatch, "id: '{}' not found", ans_id)
817 )?;
818
819 match ans.verify(&req)
821 {
822 Ok(_) =>
823 {
824 let resp =
826 QDnsQuery::from_response(ptap.get_tap_mut().get_remote_addr(), ans, now)?;
827
828 responses.push_back(resp);
829 },
830 Err(ref e)
831 if e.err_code == CDnsErrorType::MessageTruncated =>
832 {
833 write_error!("{}", e);
836
837 trunc_list.push_back(req.clone());
838 },
839 Err(e) =>
840 return Err(e),
841 }
842
843 if reqs_await_list.remove(&ans_id) == false
845 {
846 internal_error!(
847 CDnsErrorType::InternalError,
848 "request ID: '{}' for some reason can not be removed",
849 ans_id
850 );
851 }
852 } } return Ok(responses);
857 }
858}
859
860#[cfg(test)]
861
862mod tests
863{
864 use std::net::IpAddr;
865
866 use crate::{a_sync::{common::{byte2hexchar, ip2pkt}, QDnsName}, sync::{caches::CACHE, QDns}, DnsRdata, QDnsQueriesRes, QDnsQueryRec, QType, QuerySetup};
867
868 #[test]
869 fn test_ip2pkt()
870 {
871 use std::time::Instant;
872 use std::net::{IpAddr, Ipv4Addr};
873
874 let test = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
875
876 let now = Instant::now();
877
878 let res = ip2pkt(&test);
879
880 let elapsed = now.elapsed();
881 println!("Elapsed: {:.2?}", elapsed);
882
883 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
884
885 let res = res.unwrap();
886 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";
887
888 assert_eq!(res.as_slice(), ctrl);
889 }
890
891
892 #[test]
893 fn test_byte2hexchar()
894 {
895 assert_eq!(byte2hexchar(1), 0x31);
896 assert_eq!(byte2hexchar(9), 0x39);
897 assert_eq!(byte2hexchar(10), 'a' as u8);
898 assert_eq!(byte2hexchar(15), 'f' as u8);
899 }
900
901
902 #[test]
903 fn reverse_lookup_test()
904 {
905 use std::time::Instant;
906
907 let ipp: IpAddr = "8.8.8.8".parse().unwrap();
908 let test = QDnsName::from(&ipp);
909
910 let resolvers = CACHE.clone_resolve_list().unwrap();
911 let mut query_setup = QuerySetup::default();
912 query_setup.set_measure_time(true);
913
914 let now = Instant::now();
915
916 let mut dns_req =
917 QDns::make_empty(resolvers, 1, query_setup);
918
919 dns_req.add_request(QType::PTR, test);
920 let res = dns_req.query();
921
922 let elapsed = now.elapsed();
923 println!("Elapsed: {:.2?}", elapsed);
924
925 assert_eq!(res.is_results(), true, "{}", res);
926
927 println!("{}", res);
928
929 match res
930 {
931 QDnsQueriesRes::DnsOk{ res } =>
932 {
933 let rec = &res[0];
934
935 assert_eq!(rec.status, QDnsQueryRec::Ok);
937
938 assert_eq!(rec.resp.len(), 1);
939 assert_eq!(rec.resp[0].rdata, DnsRdata::PTR{ fqdn: "dns.google".to_string() });
940
941 },
942 _ => assert_eq!(true, false, "expected DnsResultSingle"),
943 }
944 }
945
946 #[test]
947 fn reverse_lookup_hosts_test()
948 {
949 use std::time::Instant;
950
951 let ipp: IpAddr = "127.0.0.1".parse().unwrap();
952 let test = QDnsName::from(&ipp);
953
954 let now = Instant::now();
955
956 let mut query_setup = QuerySetup::default();
957 query_setup.set_measure_time(true);
958
959 let resolvers = CACHE.clone_resolve_list().unwrap();
960
961 let mut dns_req =
962 QDns::make_empty(resolvers, 1, query_setup);
963
964 dns_req.add_request(QType::PTR, test);
965
966 let res = dns_req.query();
967
968 let elapsed = now.elapsed();
969 println!("Elapsed: {:.2?}", elapsed);
970
971 assert_eq!(res.is_results(), true);
972
973 println!("{}", res);
974
975 match res
976 {
977 QDnsQueriesRes::DnsOk{ res } =>
978 {
979 let rec = &res[0];
980
981 assert_eq!(rec.server.as_str(), "/etc/hosts");
982 assert_eq!(rec.status, QDnsQueryRec::Ok);
983
984 assert_eq!(rec.resp.len(), 1);
985 assert_eq!(rec.resp[0].rdata, DnsRdata::PTR{ fqdn: "localhost".to_string() });
986
987 },
988 _ => assert_eq!(true, false, "expected DnsResultSingle"),
989 }
990 }
991
992
993 #[test]
994 fn reverse_lookup_a()
995 {
996 use std::time::Instant;
997
998 let test = QDnsName::from("dns.google");
999
1000 let mut query_setup = QuerySetup::default();
1001 query_setup.set_measure_time(true);
1002
1003
1004 let resolvers = CACHE.clone_resolve_list().unwrap();
1005 let res =
1006 QDns::make_a_aaaa_request(resolvers, test, query_setup).unwrap();
1007
1008
1009 let now = Instant::now();
1010 let res = res.query();
1011
1012
1013 let elapsed = now.elapsed();
1014 println!("Elapsed: {:.2?}", elapsed);
1015
1016 println!("{}", res);
1020 }
1021
1022
1023 #[test]
1024 fn truncation_test_1()
1025 {
1026 use std::time::Instant;
1027
1028 let test = QDnsName::from("truncate-zyxw11.go.dnscheck.tools");
1029
1030 let mut query_setup = QuerySetup::default();
1031 query_setup.set_measure_time(true);
1032
1033
1034 let resolvers = CACHE.clone_resolve_list().unwrap();
1035 let mut res =
1036 QDns::make_empty(resolvers, 1, query_setup);
1037
1038 res.add_request(QType::TXT, test);
1039
1040
1041 let now = Instant::now();
1042 let res = res.query();
1043
1044
1045 let elapsed = now.elapsed();
1046 println!("Elapsed: {:.2?}", elapsed);
1047
1048 println!("{}", res);
1052 }
1053
1054}