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