1use std::fmt;
25use std::hash::Hash;
29use std::net::{IpAddr, SocketAddr};
30use std::str::FromStr;
31use std::sync::atomic::{AtomicUsize, Ordering};
32use std::sync::Arc;
33
34use bitflags::bitflags;
35
36use crate::common::{bind_all, DEF_HTTPS_PORT, DEF_TLS_PORT};
37use crate::{error::*, internal_error, internal_error_map, write_error};
38use crate::portable::*;
39use crate::tokenizer::*;
40
41static ROUND_ROBIN_CNT: AtomicUsize = AtomicUsize::new(0);
44
45
46
47pub struct RoundRobinIterator<'iterator, I>
50{
51 end_index: usize,
52 current_index: usize,
53 slice: &'iterator [I]
54}
55
56impl<'iterator, I> RoundRobinIterator<'iterator, I>
57{
58 pub
59 fn new(start_index: usize, slice: &'iterator [I]) -> RoundRobinIterator<'iterator, I>
60 {
61 return
62 RoundRobinIterator
63 {
64 end_index: start_index + slice.len(),
65 current_index: start_index,
66 slice: slice
67 };
68 }
69
70 pub
71 fn len(&self) -> usize
72 {
73 return self.slice.len();
74 }
75}
76
77impl<'iterator, I> Iterator for RoundRobinIterator<'iterator, I>
78{
79 type Item = &'iterator I;
80
81 fn next(&mut self) -> Option<Self::Item>
82 {
83 let temp_index = self.current_index;
84
85 self.current_index += 1;
86
87 if temp_index == self.end_index
88 {
89 return None;
90 }
91
92 let real_index = temp_index % self.slice.len();
94
95 return self.slice.get(real_index);
96 }
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
100pub enum ConfigEntryTls
101{
102 None, Tls, Https
103}
104
105impl fmt::Display for ConfigEntryTls
106{
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
108 {
109 match self
110 {
111 Self::None => write!(f, "unencrypted"),
112 Self::Tls => write!(f, "TLS"),
113 Self::Https => write!(f, "HTTPS"),
114 }
115 }
116}
117
118#[derive(Clone, Debug, PartialEq, Eq)]
120pub struct ResolveConfEntry
121{
122 ip: SocketAddr,
123 tls_domain: Option<String>,
124 https_req_path: Option<String>,
125 adapter_ip: SocketAddr,
126 tls_type: ConfigEntryTls,
127}
128
129impl ResolveConfEntry
130{
131 pub
132 fn new(ip: SocketAddr, tls_url: Option<String>, adapter_ip: SocketAddr) -> CDnsResult<Self>
133 {
134 let (tls_type, https_domain, https_req_path) =
135 if let Some(tlsd) = tls_url.as_ref()
136 {
137 if let Some(domain_path_https) = tlsd.strip_prefix("https://")
138 {
139 let Some ((domain, path)) = domain_path_https.split_once("/")
140 else
141 {
142 internal_error!(CDnsErrorType::ConfigError,
143 "in /etc/resolv.conf - invalid TLS/HTTPS URL '{}'",
144 domain_path_https
145 )
146 };
147
148 (ConfigEntryTls::Https, Some(domain.to_string()), Some(path.to_string()))
149 }
150 else
151 {
152 let domain =
154 tlsd
155 .split_once("://")
156 .map_or(tlsd.as_str(), |(_, d)| d);
157
158
159 let domain =
160 domain
161 .split_once("/")
162 .map_or(domain, |(d, _)| d);
163
164
165 (ConfigEntryTls::Tls, Some(domain.to_string()), None)
166 }
167 }
168 else
169 {
170 if ip.port() == DEF_HTTPS_PORT
171 {
172 (ConfigEntryTls::Https, None, None)
173 }
174 else if ip.port() == DEF_TLS_PORT
175 {
176 (ConfigEntryTls::Tls, None, None)
177 }
178 else
179 {
180 (ConfigEntryTls::None, None, None)
181 }
182 };
183
184 return Ok(Self {ip, tls_domain: https_domain, https_req_path: https_req_path, adapter_ip, tls_type});
185 }
186
187 pub
188 fn get_resolver_ip(&self) -> IpAddr
189 {
190 return self.ip.ip();
191 }
192
193 pub
194 fn get_resolver_sa(&self) -> &SocketAddr
195 {
196 return &self.ip;
197 }
198
199 pub
200 fn get_tls_domain(&self) -> Option<&String>
201 {
202 return self.tls_domain.as_ref();
203 }
204
205 pub
206 fn get_adapter_ip(&self) -> &SocketAddr
207 {
208 return &self.adapter_ip;
209 }
210
211 pub
212 fn get_tls_type(&self) -> ConfigEntryTls
213 {
214 return self.tls_type;
215 }
216
217 pub
218 fn get_tls_path(&self) -> Option<&String>
219 {
220 return self.https_req_path.as_ref();
221 }
222}
223
224bitflags! {
232 #[derive(Clone, Debug, PartialEq, Eq, Copy)]
234 pub struct ResolveConfigLookup: u32
235 {
236 const FILE_BIND = 0x10;
238 const BIND_FILE = 0x20;
240 const FILE = 0x01;
242 const BIND = 0x02;
244 }
245}
246
247
248impl ResolveConfigLookup
249{
250 pub
251 fn is_file(&self) -> bool
252 {
253 return self.contains(Self::FILE);
254 }
255
256 pub
257 fn is_bind(&self) -> bool
258 {
259 return self.contains(Self::BIND);
260 }
261
262 pub
263 fn is_file_first(&self) -> bool
264 {
265 return self.contains(Self::FILE_BIND);
266 }
267}
268
269impl Default for ResolveConfigLookup
270{
271 fn default() -> Self
272 {
273 return Self::FILE_BIND | Self::FILE | Self::BIND;
274 }
275}
276
277const LOOKUP_FILE: &'static str = "file";
278const LOOKUP_BIND: &'static str = "bind";
279
280impl TryFrom<&[String]> for ResolveConfigLookup
281{
282 type Error = CDnsError;
283
284 fn try_from(value: &[String]) -> Result<Self, Self::Error>
285 {
286 if value.is_empty() == true
287 {
288 internal_error!(CDnsErrorType::ConfigError, "'lookup' is empty");
289 }
290 else if value.len() > 2
291 {
292 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with too many paramenters: '{:?}'", value);
293 }
294
295 let first =
298 if value[0] == LOOKUP_FILE
299 {
300 Self::FILE
301 }
302 else if value[0] == LOOKUP_BIND
303 {
304 Self::BIND
305 }
306 else
307 {
308 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with unknown parameter: '{}'", value[0]);
309 };
310
311 let second: Self =
312 if value.len() == 2
313 {
314 if value[1] == LOOKUP_FILE
315 {
316 if first.contains(Self::FILE) == true
317 {
318 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with duplicate parameter: '{}'", value[1]);
319 }
320
321 Self::BIND_FILE | Self::FILE
322 }
323 else if value[1] == LOOKUP_BIND
324 {
325 if first.contains(Self::BIND) == true
326 {
327 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with duplicate parameter: '{}'", value[1]);
328 }
329
330 Self::FILE_BIND | Self::BIND
331 }
332 else
333 {
334 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with unknown parameter: '{}'", value[0]);
335 }
336 }
337 else
338 {
339 Self::empty()
340 };
341
342 return Ok(Self::from(first | second));
343
344 }
345}
346
347bitflags! {
348 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
350 pub struct ResolveConfigFamily: u32
351 {
352 const INET4_INET6 = 0x10;
354 const INET6_INET4 = 0x20;
356 const INET4 = 0x01;
358 const INET6 = 0x02;
360 }
361}
362
363impl ResolveConfigFamily
364{
365 pub
366 fn is_inet4(&self) -> bool
367 {
368 return self.contains(Self::INET4);
369 }
370
371 pub
372 fn is_inet6(&self) -> bool
373 {
374 return self.contains(Self::INET6);
375 }
376
377 pub
378 fn is_inet4_first(&self) -> bool
379 {
380 return self.contains(Self::INET4_INET6);
381 }
382
383 fn inverted_default() -> Self
384 {
385 return Self::INET6_INET4 | Self::INET4 | Self::INET6;
386 }
387}
388
389impl Default for ResolveConfigFamily
390{
391 fn default() -> Self
392 {
393 return Self::INET4_INET6 | Self::INET4 | Self::INET6;
394 }
395}
396
397const FAMILY_INET4: &'static str = "inet4";
398const FAMILY_INET6: &'static str = "inet6";
399
400impl TryFrom<&[String]> for ResolveConfigFamily
401{
402 type Error = CDnsError;
403
404 fn try_from(value: &[String]) -> Result<Self, Self::Error>
405 {
406 if value.is_empty() == true
407 {
408 internal_error!(CDnsErrorType::ConfigError, "'family' is empty");
409 }
410 else if value.len() > 2
411 {
412 internal_error!(CDnsErrorType::ConfigError, "'family' is set with too many paramenters: '{:?}'", value);
413 }
414
415 let mut family =
416 if value[0] == FAMILY_INET4
417 {
418 Self::INET4_INET6 | Self::INET4
420 }
421 else if value[0] == FAMILY_INET6
422 {
423 Self::INET6_INET4 | Self::INET6
425 }
426 else
427 {
428 internal_error!(CDnsErrorType::ConfigError, "'family' is set with unknown parameter: '{}'", value[0]);
429 };
430
431 if value.len() == 2
432 {
433 if value[1] == FAMILY_INET4
434 {
435 if family.contains(Self::INET4) == true
436 {
437 internal_error!(CDnsErrorType::ConfigError, "'family' is set with duplicate parameter: '{}'", value[1]);
438 }
439
440 family |= Self::INET4
442 }
443 else if value[1] == FAMILY_INET6
444 {
445 if family.contains(Self::INET6) == true
446 {
447 internal_error!(CDnsErrorType::ConfigError, "'family' is set with duplicate parameter: '{}'", value[1]);
448 }
449
450 family |= Self::INET6
452 }
453 else
454 {
455 internal_error!(CDnsErrorType::ConfigError, "'family' is set with unknown parameter: '{}'", value[0]);
456 }
457 }
458
459 return Ok(family);
460 }
461}
462
463
464bitflags! {
465 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
467 pub struct OptionFlags: u16
468 {
469 const OPT_DEBUG = 0x0001;
471
472 const OPT_ROTATE = 0x0002;
474
475 const OPT_NO_CHECK_NAMES = 0x0004;
479
480 const OPT_INET6 = 0x0008;
482
483 const OPT_SINGLE_REQUEST = 0x0010;
486
487 const OPT_SINGLE_REQUEST_REOPEN = 0x0020;
490
491 const OPT_NO_RELOAD = 0x0040;
493
494 const OPT_TRUST_AD = 0x0080;
496
497 const OPT_USE_VC = 0x0100;
499 }
500}
501
502impl Default for OptionFlags
503{
504 fn default() -> Self
505 {
506 return Self::empty();
507 }
508}
509
510impl OptionFlags
511{
512 pub
513 fn is_debug(&self) -> bool
514 {
515 return self.contains(Self::OPT_DEBUG);
516 }
517
518 pub
519 fn is_rotate(&self) -> bool
520 {
521 return self.contains(Self::OPT_ROTATE);
522 }
523
524 pub
525 fn is_no_check_names(&self) -> bool
526 {
527 return self.contains(Self::OPT_NO_CHECK_NAMES);
528 }
529
530 pub
531 fn is_no_parallel(&self) -> bool
532 {
533 return self.contains(Self::OPT_SINGLE_REQUEST);
534 }
535
536 pub
537 fn is_reopen_socket(&self) -> bool
538 {
539 return self.contains(Self::OPT_SINGLE_REQUEST_REOPEN);
540 }
541
542 pub
543 fn is_force_tcp(&self) -> bool
544 {
545 return self.contains(Self::OPT_USE_VC);
546 }
547}
548
549
550#[derive(Clone, Debug, PartialEq, Eq)]
551pub struct ResolveConfig
552{
553 pub nameservers: Vec<Arc<ResolveConfEntry>>,
554 pub lookup: ResolveConfigLookup,
555 pub family: ResolveConfigFamily,
556 pub search_list: Vec<String>,
557 pub domain: Option<String>,
558 pub option_flags: OptionFlags,
559 pub ndots: usize,
560 pub timeout: u16,
561 pub attempts: usize,
562}
563
564impl Default for ResolveConfig
565{
566 fn default() -> Self
567 {
568 return
569 ResolveConfig
570 {
571 nameservers: vec![],
572 lookup: ResolveConfigLookup::default(),
573 family: ResolveConfigFamily::default(),
574 search_list: vec![],
575 domain: None,
576 option_flags: OptionFlags::default(),
577 ndots: 1,
578 timeout: 5,
579 attempts: 2,
580 };
581 }
582}
583
584impl ResolveConfig
585{
586 pub
595 fn get_resolvers_iter(&self) -> RoundRobinIterator<Arc<ResolveConfEntry>>
596 {
597 if self.option_flags.is_rotate() == true
598 {
599 let start_index = ROUND_ROBIN_CNT.fetch_add(1, Ordering::SeqCst);
600
601 return RoundRobinIterator::new(start_index, self.nameservers.as_slice());
602 }
603 else
604 {
605 return RoundRobinIterator::new(0, self.nameservers.as_slice());
606 };
607 }
608
609 fn split_ext(field_data: &str) -> CDnsResult<(&str, u16, Option<String>)>
612 {
613 let splited = field_data.split("#").collect::<Vec<&str>>();
614 let mut port: u16 = 53;
615 let mut domain: Option<String> = None;
616
617 if splited.is_empty() == true
618 {
619 return Ok((field_data, port, domain));
620 }
621
622 let mut splt_iter = splited.into_iter();
623 let without_ext = splt_iter.nth(0).unwrap();
624
625
626 for ext in splt_iter
627 {
628 if ext.starts_with("@") == true
629 {
630 port =
632 u16::from_str_radix(&ext[1..], 10).map_err(|e|
633 internal_error_map!(CDnsErrorType::InternalError, "can not parse port number, {}", e)
634 )?;
635 }
636 else
637 {
638 domain = Some(ext.to_string());
640 }
641 }
642
643 return Ok((without_ext, port, domain));
644 }
645
646 fn split_dns_ifr(field_data: &str, ifr: &IfInfo) -> CDnsResult<(IpAddr, SocketAddr)>
647 {
648 if let Some((ip, intf)) = field_data.split_once("%")
649 {
650 let ip_addr: IpAddr =
651 ip.parse().map_err(|e|
652 internal_error_map!(CDnsErrorType::InternalError, "parse IP: '{}' failed: '{}'", ip, e)
653 )?;
654
655
656 match unsafe { ifr.get_ifr_ip(intf, &ip_addr)? }
657 {
658 Some(ip_ifr) =>
659 return Ok( (ip_addr, SocketAddr::from((ip_ifr, 0))) ),
660 None =>
661 internal_error!(CDnsErrorType::InternalError, "interface: '{}' does not exist", intf),
662 }
663 }
664 else
665 {
666 let ip_addr: IpAddr =
667 field_data.parse().map_err(|e|
668 internal_error_map!(CDnsErrorType::InternalError, "parse IP: '{}' failed: '{}'", field_data, e)
669 )?;
670
671 let ip_ifr = bind_all(ip_addr);
672 return Ok((ip_addr, ip_ifr))
681 }
682 }
683
684 #[inline]
685 fn set_option(
686 optname: &'static str,
687 right: Option<&str>,
688 option_flags: &mut OptionFlags,
689 opt_flag: OptionFlags
690 ) -> CDnsResult<()>
691 {
692 if right.is_some() == true
693 {
694 internal_error!(CDnsErrorType::ConfigError,
695 "in /etc/resolv.conf - 'option' '{}' is defined \
696 with parameter: '{}', but it does not have parameters", optname, right.unwrap());
697 }
698
699 option_flags.set(opt_flag, true);
700
701 return Ok(());
702 }
703
704 #[inline]
705 fn read_parameter<P: FromStr>(optname: &'static str, right: Option<&str>) -> CDnsResult<P>
706 {
707 if right.is_none() == true
708 {
709 internal_error!(CDnsErrorType::ConfigError,
710 "in /etc/resolv.conf - 'option' '{}' is defined without parameter", optname);
711 }
712 else
713 {
714 return
715 right.unwrap()
716 .parse::<P>()
717 .map_err(|_|
718 internal_error_map!(
719 CDnsErrorType::ConfigError,
720 "in /etc/resolv.conf - 'option' '{}' is defined with invalid \
721 parameter: '{}'", optname, right.unwrap()
722 )
723 );
724 }
725 }
726
727 pub(crate)
733 fn parser_resolv_internal(file_content: &str) -> CDnsResult<Self>
734 {
735 let mut tk = ConfTokenizer::from_str(&file_content)?;
736
737 let mut dns_list: Vec<Arc<ResolveConfEntry>> = Vec::new();
738 let mut lookup_list: ResolveConfigLookup = ResolveConfigLookup::default();
739 let mut family_list: ResolveConfigFamily = ResolveConfigFamily::default();
740
741 let mut search_list: Vec<String> = Vec::new();
743
744 let mut domain: Option<String> = None;
745 let mut option_flags: OptionFlags = OptionFlags::empty();
746 let mut ndots: usize = 1;
747 let mut timeout: u16 = 5;
748 let mut attempts: usize = 2;
749
750 let if_info: IfInfo = unsafe { IfInfo::get_interfaces_info()? };
751
752 loop
753 {
754 let field_name = tk.read_next()?;
755
756 if field_name.is_none() == true
757 {
758 break;
760 }
761
762 let field_name = field_name.unwrap();
763
764 if field_name == "nameserver"
765 {
766 let Some(field_data) = tk.read_next()?
768 else
769 {
770 internal_error!(CDnsErrorType::ConfigError, "unexpected EOF near nameserver");
772 };
773
774 let ext_split_res = Self::split_ext(field_data);
776
777 let Ok((without_ext, port, domain)) = ext_split_res
778 else
779 {
780 internal_error!(CDnsErrorType::ConfigError, "{}", ext_split_res.err().unwrap());
781 };
782
783 let split = Self::split_dns_ifr(without_ext, &if_info);
784
785 let Ok((dns_ip, ifr_ip)) = split
786 else
787 {
788 internal_error!(CDnsErrorType::ConfigError, "{}", split.err().unwrap());
789 };
790
791
792 dns_list.push(
793 Arc::new(ResolveConfEntry::new(SocketAddr::new(dns_ip, port), domain, ifr_ip)?)
794 );
795
796
797 }
798 else if field_name == "lookup" {
800 let lookups = tk.read_upto_eol()?;
802
803 if lookups.len() == 0
804 {
805 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'lookup' is set but no args provided, setting defaults file, bind"));
806
807 continue;
808 }
809
810 lookup_list =
811 match ResolveConfigLookup::try_from(lookups.as_slice())
812 {
813 Ok(r) => r,
814 Err(e) =>
815 {
816 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - {}", e));
817
818 continue;
819 }
820 };
821 }
822 else if field_name == "family" {
824 let families = tk.read_upto_eol()?;
826
827 if families.len() == 0
828 {
829 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'family' is set but no args provided, setting defaults inet4, inet6"));
830
831 continue;
832 }
833
834 family_list =
835 match ResolveConfigFamily::try_from(families.as_slice())
836 {
837 Ok(r) => r,
838 Err(e) =>
839 {
840 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - {}", e));
841 continue;
842 }
843 };
844 }
845 else if field_name == "search"
846 {
847 let searches = tk.read_upto_eol()?;
849
850 if searches.len() == 0
851 {
852 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'search' is defined but empty"));
853 }
854 else
855 {
856 search_list.extend(searches);
857 }
858 }
859 else if field_name == "domain"
860 {
861 let mut domains = tk.read_upto_eol()?;
862
863 if domain.is_some() == true
864 {
865 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'domain' is defined more than once: {:?} {:?}", domain, domains));
866 }
867
868 if domains.len() > 1
869 {
870 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'domain' is defined with more than 1 address: {:?}", domains));
871 }
872 else if domains.len() == 0
873 {
874 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'domain' is defined but empty"));
875 }
876 else
877 {
878 domain = Some(domains.pop().unwrap());
879 }
880 }
881 else if field_name == "options"
882 {
883
884 let options_vec = tk.read_upto_eol()?;
885
886 if options_vec.is_empty() == true
887 {
888 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'option' is empty!"));
889
890 continue;
892 }
893
894 for option in options_vec
895 {
896 let (left, right) =
897 match option.split_once(":")
898 {
899 Some((l, r)) => (l, Some(r)),
900 None => (option.as_str(), None),
901 };
902
903 match left
904 {
905 "use-vc" | "usevc" | "tcp" => {
908 match Self::set_option("usevc", right, &mut option_flags, OptionFlags::OPT_USE_VC)
909 {
910 Err(e) =>
911 write_error!(e),
912 Ok(_) => {}
913 }
914 },
915 "debug" =>
916 {
917 match Self::set_option("debug", right, &mut option_flags, OptionFlags::OPT_DEBUG)
918 {
919 Err(e) =>
920 write_error!(e),
921 Ok(_) => {}
922 }
923 },
924 "ndots" =>
925 {
926 match Self::read_parameter("ndots", right)
927 {
928 Ok(val) =>
929 {
930 ndots = if val > 15 { 15 } else { val };
931 },
932 Err(e) =>
933 {
934 write_error!(e);
935 }
936 }
937 },
938 "timeout" =>
939 {
940 match Self::read_parameter::<u16>("timeout", right)
941 {
942 Ok(val) =>
943 {
944 timeout = if val > 30 { 30 } else { val };
945 },
946 Err(e) =>
947 {
948 write_error!(e);
949 }
950 }
951 },
952 "attempts" =>
953 {
954 match Self::read_parameter("attempts", right)
955 {
956 Ok(val) =>
957 {
958 attempts = if val > 5 { 5 } else { val };
959 },
960 Err(e) =>
961 {
962 write_error!(e);
963 }
964 }
965 },
966 "rotate" =>
967 {
968 match Self::set_option("rotate", right, &mut option_flags, OptionFlags::OPT_ROTATE)
969 {
970 Err(e) =>
971 write_error!(e),
972 Ok(_) => {}
973 }
974 },
975 "no-check-names" =>
976 {
977 match Self::set_option("no-check-names", right, &mut option_flags, OptionFlags::OPT_NO_CHECK_NAMES)
978 {
979 Err(e) =>
980 write_error!(e),
981 Ok(_) => {}
982 }
983 },
984 "no-reload" =>
985 {
986 match Self::set_option("no-reload", right, &mut option_flags, OptionFlags::OPT_NO_RELOAD)
987 {
988 Err(e) =>
989 write_error!(e),
990 Ok(_) => {}
991 }
992 },
993 "inet6" =>
994 {
995 match Self::set_option("inet6", right, &mut option_flags, OptionFlags::OPT_INET6)
997 {
998 Err(e) =>
999 write_error!(e),
1000 Ok(_) => {}
1001 }
1002 },
1003 "edns0" =>
1004 {
1005 },
1007 "single-request" =>
1008 {
1009 match Self::set_option("single-request", right, &mut option_flags, OptionFlags::OPT_SINGLE_REQUEST)
1010 {
1011 Err(e) =>
1012 write_error!(e),
1013 Ok(_) => {}
1014 }
1015 },
1016 "single-request-reopen" =>
1017 {
1018 match Self::set_option("single-request-reopen", right, &mut option_flags, OptionFlags::OPT_SINGLE_REQUEST_REOPEN)
1019 {
1020 Err(e) =>
1021 write_error!(e),
1022 Ok(_) => {}
1023 }
1024 },
1025 "trust-ad" =>
1026 {
1027 match Self::set_option("trust-ad", right, &mut option_flags, OptionFlags::OPT_TRUST_AD)
1028 {
1029 Err(e) =>
1030 write_error!(e),
1031 Ok(_) => {}
1032 }
1033 },
1034 _ =>
1035 {
1036 write_error!(internal_error_map!(CDnsErrorType::ConfigError, "in /etc/resolv.conf - 'option' '{}' is unknown \
1037 with parameter: '{:?}'", left, right));
1038 },
1039 }
1040
1041
1042 }
1043 }
1044 else
1045 {
1046 tk.skip_upto_eol();
1048 }
1049 }
1050
1051 if option_flags.contains(OptionFlags::OPT_INET6) == true
1052 {
1053 family_list = ResolveConfigFamily::inverted_default();
1054 }
1055
1056
1057 return Ok(
1058 Self
1059 {
1060 nameservers: dns_list,
1061 lookup: lookup_list,
1062 family: family_list,
1063 search_list: search_list,
1064 domain: domain,
1065 option_flags: option_flags,
1066 ndots: ndots,
1067 timeout: timeout,
1068 attempts: attempts,
1069 }
1070 );
1071 }
1072}
1073
1074#[cfg(feature = "use_sync")]
1075#[cfg(test)]
1076mod tests
1077{
1078 use std::{net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, str::FromStr};
1079
1080 use crate::{cfg_resolv_parser::{OptionFlags, ResolveConfigFamily, ResolveConfigLookup}, sync::ResolveConfig};
1081
1082 #[test]
1083 fn test_parser_resolv_tls_0()
1084 {
1085 let ip1 = SocketAddr::new("1.1.1.1".parse::<IpAddr>().unwrap(), 853);
1086 let tls_domain1 = Some(String::from("cloudflare-dns.com"));
1087 let ip2 = SocketAddr::new("2606:4700:4700::1001".parse::<IpAddr>().unwrap(), 853);
1088 let tls_domain2 = Some(String::from("cloudflare-dns.com"));
1089 let ip3 = SocketAddr::new("127.0.0.1".parse().unwrap(), 853);
1090 let tls_domain3 = Some(String::from("localdomain"));
1091 let ip3_if: SocketAddr = SocketAddr::from((Ipv4Addr::from_str("127.0.0.1").unwrap(), 0));
1092 let ip4 = SocketAddr::new("8.8.8.8".parse().unwrap(), 55);
1093 let ip5 = SocketAddr::new("1.0.0.2".parse().unwrap(), 53);
1094 let ip6 = SocketAddr::new("1.1.1.1".parse::<IpAddr>().unwrap(), 443);
1095
1096 let test =
1097 "nameserver 1.1.1.1#@853#cloudflare-dns.com\n\
1098 nameserver 2606:4700:4700::1001#@853#cloudflare-dns.com\n\
1099 nameserver 127.0.0.1%lo#@853#localdomain\n\
1100 nameserver 8.8.8.8#@55\n\
1101 nameserver 1.0.0.2 #@853\n\
1102 nameserver 1.1.1.1#@443#https://cloudflare-dns.com/dns-query\n";
1103
1104 let res = ResolveConfig::parser_resolv_internal(test);
1105
1106 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1107 let res = res.unwrap();
1108
1109 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET6 | ResolveConfigFamily::INET4);
1110
1111 assert_eq!(res.nameservers[0].ip, ip1);
1112 assert_eq!(res.nameservers[0].tls_domain.as_ref(), tls_domain1.as_ref());
1113 assert_eq!(res.nameservers[0].https_req_path, None);
1114 assert_eq!(res.nameservers[1].ip, ip2);
1115 assert_eq!(res.nameservers[1].tls_domain.as_ref(), tls_domain2.as_ref());
1116 assert_eq!(res.nameservers[2].ip, ip3);
1117 assert_eq!(res.nameservers[2].tls_domain.as_ref(), tls_domain3.as_ref());
1118 assert_eq!(res.nameservers[2].adapter_ip, ip3_if);
1119 assert_eq!(res.nameservers[3].ip, ip4);
1120 assert_eq!(res.nameservers[4].ip, ip5);
1121 assert_eq!(res.nameservers[5].ip, ip6);
1122 assert_eq!(res.nameservers[5].tls_domain, Some("cloudflare-dns.com".to_string()));
1123 assert_eq!(res.nameservers[5].https_req_path, Some("dns-query".to_string()));
1124 }
1125
1126 #[test]
1127 fn test_parser_resolv_internal_0()
1128 {
1129 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1130 let ip2 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1131 let ip3 = SocketAddr::new("8.8.8.8".parse().unwrap(), 53);
1132 let ip4 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1133 let ip4_if: SocketAddr = SocketAddr::from((Ipv4Addr::from_str("127.0.0.1").unwrap(), 0));
1134 let ip5 = SocketAddr::new("fe80::1".parse().unwrap(), 53);
1135 let ip5_if: SocketAddr = SocketAddr::from((Ipv6Addr::from_str("::1").unwrap(), 0));
1136
1137 let test =
1138 "nameserver 192.168.2.1\n\
1139 nameserver 127.0.0.1\n\
1140 lookup bind\n\
1141 nameserver 8.8.8.8\n
1142 nameserver 127.0.0.1%lo\n
1143 nameserver fe80::1%lo\n";
1144
1145
1146 let res = ResolveConfig::parser_resolv_internal(test);
1147
1148 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1149 let res = res.unwrap();
1150
1151 assert_eq!(res.lookup, ResolveConfigLookup::BIND);
1152
1153 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET6 | ResolveConfigFamily::INET4);
1154
1155 assert_eq!(res.nameservers[0].ip, ip1);
1156 assert_eq!(res.nameservers[1].ip, ip2);
1157 assert_eq!(res.nameservers[2].ip, ip3);
1158 assert_eq!(res.nameservers[3].ip, ip4);
1159 assert_eq!(res.nameservers[3].adapter_ip, ip4_if);
1160 assert_eq!(res.nameservers[4].ip, ip5);
1161 assert_eq!(res.nameservers[4].adapter_ip, ip5_if);
1162 }
1163
1164 #[test]
1165 fn test_parser_resolv_internal()
1166 {
1167 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1168 let ip2 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1169 let ip3 = SocketAddr::new("8.8.8.8".parse().unwrap(), 53);
1170
1171 let test =
1172 "nameserver 192.168.2.1\n\
1173 nameserver 127.0.0.1\n\
1174 lookup bind file\n\
1175 nameserver 8.8.8.8";
1176
1177 let res = ResolveConfig::parser_resolv_internal(test);
1178 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1179 let res = res.unwrap();
1180
1181 assert_eq!(res.lookup, ResolveConfigLookup::BIND | ResolveConfigLookup::FILE | ResolveConfigLookup::BIND_FILE);
1182
1183 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET6 | ResolveConfigFamily::INET4);
1184
1185 assert_eq!(res.nameservers[0].ip, ip1);
1186 assert_eq!(res.nameservers[1].ip, ip2);
1187 assert_eq!(res.nameservers[2].ip, ip3);
1188 }
1189
1190 #[test]
1191 fn test_parser_resolv_internal2()
1192 {
1193 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1194 let ip2 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1195 let ip3 = SocketAddr::new("8.8.8.8".parse().unwrap(), 53);
1196
1197 let test =
1198 "# test 12345\n\
1199 # nameserver 192.168.3.1
1200 nameserver 192.168.2.1 \n\
1201 nameserver 127.0.0.1 \n\
1202 lookup file\n\
1203 family inet4\n\
1204 nameserver 8.8.8.8\n";
1205
1206 let res = ResolveConfig::parser_resolv_internal(test);
1207 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1208 let res = res.unwrap();
1209
1210 assert_eq!(res.lookup, ResolveConfigLookup::FILE);
1211
1212 assert_eq!(res.family, ResolveConfigFamily::INET4 | ResolveConfigFamily::INET4_INET6);
1213
1214 assert_eq!(res.nameservers.len(), 3);
1215 assert_eq!(res.nameservers[0].ip, ip1);
1216 assert_eq!(res.nameservers[1].ip, ip2);
1217 assert_eq!(res.nameservers[2].ip, ip3);
1218 }
1219
1220 #[test]
1221 fn test_parser_resolv_internal3()
1222 {
1223 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1224 let ip2 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1225 let ip3 = SocketAddr::new("8.8.8.8".parse().unwrap(), 53);
1226
1227 let test =
1228 "# test 12345\n\
1229 # nameserver 192.168.3.1
1230 nameserver 192.168.2.1 \n\
1231 nameserver 127.0.0.1 \n\
1232 lookup file\n\
1233 family inet4\n\
1234 nameserver 8.8.8.8\n
1235 options attempts:1 timeout:3 debug use-vc single-request-reopen\n
1236 search localdomain";
1237
1238 let res = ResolveConfig::parser_resolv_internal(test);
1239 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1240 let res = res.unwrap();
1241
1242 assert_eq!(res.lookup, ResolveConfigLookup::FILE);
1243
1244 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET4);
1245
1246 assert_eq!(res.nameservers.len(), 3);
1247 assert_eq!(res.nameservers[0].ip, ip1);
1248 assert_eq!(res.nameservers[1].ip, ip2);
1249 assert_eq!(res.nameservers[2].ip, ip3);
1250
1251 assert_eq!(res.search_list[0], "localdomain");
1252
1253 assert_eq!(res.timeout, 3);
1254 assert_eq!(res.attempts, 1);
1255
1256 assert_eq!(res.option_flags.contains(OptionFlags::OPT_DEBUG), true);
1257 assert_eq!(res.option_flags.contains(OptionFlags::OPT_USE_VC), true);
1258 assert_eq!(res.option_flags.contains(OptionFlags::OPT_SINGLE_REQUEST_REOPEN), true);
1259 }
1260
1261 #[test]
1262 fn test_parser_resolv_internal4()
1263 {
1264 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1265 let ip2 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1266 let ip3 = SocketAddr::new("8.8.8.8".parse().unwrap(), 53);
1267
1268 let test =
1269 "\
1270 # test 12345\n\
1271 # nameserver 192.168.3.1\n\
1272 nameserver 192.168.2.1 \n\
1273 nameserver 127.0.0.1 \n\
1274 lookup file\n\
1275 family inet4 \n\
1276 nameserver 8.8.8.8\n\
1277 options attempts:1 timeout:3 debug use-vc single-request-reopen\n\
1278 search localdomain\n\
1279 ";
1280
1281
1282 let res = ResolveConfig::parser_resolv_internal(test);
1283 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1284 let res = res.unwrap();
1285
1286 assert_eq!(res.lookup, ResolveConfigLookup::FILE);
1287
1288 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET4);
1289
1290 assert_eq!(res.nameservers.len(), 3);
1291 assert_eq!(res.nameservers[0].ip, ip1);
1292 assert_eq!(res.nameservers[1].ip, ip2);
1293 assert_eq!(res.nameservers[2].ip, ip3);
1294
1295 assert_eq!(res.search_list[0], "localdomain");
1296
1297 assert_eq!(res.timeout, 3);
1298 assert_eq!(res.attempts, 1);
1299
1300 assert_eq!(res.option_flags.contains(OptionFlags::OPT_DEBUG), true);
1301 assert_eq!(res.option_flags.contains(OptionFlags::OPT_USE_VC), true);
1302 assert_eq!(res.option_flags.contains(OptionFlags::OPT_SINGLE_REQUEST_REOPEN), true);
1303 }
1304
1305 #[test]
1306 fn test_roundrobin_iter_1()
1307 {
1308 use std::time::Instant;
1309
1310 fn check_order(res: &ResolveConfig, ipl: &[SocketAddr], indx: usize)
1311 {
1312 let mut i = indx;
1313 let assert_i = (indx + ipl.len()) % ipl.len();
1314 let now = Instant::now();
1315
1316 let itr = res.get_resolvers_iter();
1317
1318 assert_eq!(itr.len(), ipl.len());
1319
1320 for n in itr
1321 {
1322 assert_eq!(n.ip, ipl[i]);
1324
1325 i += 1;
1326
1327 i %= ipl.len();
1328
1329 }
1330
1331 assert_eq!(i, assert_i);
1332
1333 let elapsed = now.elapsed();
1334 println!("Iter Elapsed: {:.2?}", elapsed);
1335 }
1336
1337 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1338
1339 let ip_list: Vec<SocketAddr> = vec![ip1];
1340
1341 let test =
1342 "\
1343 # test 12345\n\
1344 # nameserver 192.168.3.1\n\
1345 nameserver 192.168.2.1 \n\
1346 #nameserver 127.0.0.1 \n\
1347 lookup file\n\
1348 family inet4 \n\
1349 #nameserver 8.8.8.8\n\
1350 options attempts:1 rotate timeout:3 debug use-vc single-request-reopen\n\
1351 search localdomain\n\
1352 ";
1353
1354 let now = Instant::now();
1355
1356
1357 let res = ResolveConfig::parser_resolv_internal(test);
1358
1359 let elapsed = now.elapsed();
1360 println!("parser_resolv_internal elapsed: {:.2?}", elapsed);
1361
1362 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1363 let res = res.unwrap();
1364
1365 check_order(&res, &ip_list, 0);
1366 check_order(&res, &ip_list, 0);
1367 check_order(&res, &ip_list, 0);
1368 check_order(&res, &ip_list, 0);
1369 check_order(&res, &ip_list, 0);
1370 check_order(&res, &ip_list, 0);
1371 check_order(&res, &ip_list, 0);
1372 check_order(&res, &ip_list, 0);
1373 check_order(&res, &ip_list, 0);
1374 }
1375
1376 #[test]
1377 fn test_roundrobin_iter()
1378 {
1379 use std::time::Instant;
1380
1381 fn check_order(res: &ResolveConfig, ipl: &[SocketAddr], indx: usize)
1382 {
1383 let mut i = indx;
1384 let assert_i = (indx + ipl.len()) % ipl.len();
1385 let now = Instant::now();
1386
1387 let itr = res.get_resolvers_iter();
1388
1389 assert_eq!(itr.len(), ipl.len());
1390
1391 for n in itr
1392 {
1393 assert_eq!(n.ip, ipl[i]);
1395
1396 i += 1;
1397
1398 i %= ipl.len();
1399
1400 }
1401
1402 assert_eq!(i, assert_i);
1403
1404 let elapsed = now.elapsed();
1405 println!("Iter Elapsed: {:.2?}", elapsed);
1406 }
1407
1408 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1409 let ip2 = SocketAddr::new("127.0.0.1".parse().unwrap(), 53);
1410 let ip3 = SocketAddr::new("8.8.8.8".parse().unwrap(), 53);
1411
1412 let ip_list: Vec<SocketAddr> = vec![ip1, ip2, ip3];
1413
1414 let test =
1415 "\
1416 # test 12345\n\
1417 # nameserver 192.168.3.1\n\
1418 nameserver 192.168.2.1 \n\
1419 nameserver 127.0.0.1 \n\
1420 lookup file\n\
1421 family inet4 \n\
1422 nameserver 8.8.8.8\n\
1423 options attempts:1 rotate timeout:3 debug use-vc single-request-reopen\n\
1424 search localdomain\n\
1425 ";
1426
1427 let now = Instant::now();
1428
1429 let res = ResolveConfig::parser_resolv_internal(test);
1430
1431 let elapsed = now.elapsed();
1432 println!("parser_resolv_internal elapsed: {:.2?}", elapsed);
1433
1434 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1435 let res = res.unwrap();
1436
1437 check_order(&res, &ip_list, 0);
1438 check_order(&res, &ip_list, 1);
1439 check_order(&res, &ip_list, 2);
1440 check_order(&res, &ip_list, 0);
1441 check_order(&res, &ip_list, 1);
1442 check_order(&res, &ip_list, 2);
1443 check_order(&res, &ip_list, 0);
1444 check_order(&res, &ip_list, 1);
1445 check_order(&res, &ip_list, 2);
1446 }
1447
1448 #[test]
1449 fn test_direct_iter()
1450 {
1451 use std::time::Instant;
1452
1453 let ip1 = SocketAddr::new("192.168.2.1".parse().unwrap(), 53);
1454 let ip2 = SocketAddr::new("192.168.2.2".parse().unwrap(), 53);
1455
1456 let test =
1457 "\
1458 # test 12345\n\
1459 # nameserver 192.168.3.1\n\
1460 nameserver 192.168.2.1 \n\
1461 nameserver 192.168.2.2 \n\
1462 lookup file\n\
1463 family inet4 \n\
1464 options attempts:1 timeout:3 debug use-vc single-request-reopen\n\
1465 search localdomain\n\
1466 ";
1467
1468 let now = Instant::now();
1469
1470
1471 let res = ResolveConfig::parser_resolv_internal(test);
1472
1473 let elapsed = now.elapsed();
1474 println!("Elapsed: {:.2?}", elapsed);
1475
1476 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1477 let res = res.unwrap();
1478
1479 let mut i: usize = 0;
1480
1481 let now = Instant::now();
1482
1483 for n in res.get_resolvers_iter()
1484 {
1485 match i
1486 {
1487 0 => { assert_eq!(n.ip, ip1); i += 1; },
1488 1 => { assert_eq!(n.ip, ip2); i += 1; },
1489 _ => panic!("!")
1490 }
1491 }
1492
1493 let elapsed = now.elapsed();
1494 println!("Iter Elapsed: {:.2?}", elapsed);
1495
1496 assert_eq!(i, 2);
1497
1498 i = 0;
1499 for n in res.get_resolvers_iter()
1500 {
1501 match i
1502 {
1503 0 => { assert_eq!(n.ip, ip1); i += 1; },
1504 1 => { assert_eq!(n.ip, ip2); i += 1; },
1505 _ => panic!("!")
1506 }
1507 }
1508
1509 assert_eq!(i, 2);
1510 }
1511
1512}