1use std::hash::Hash;
28use std::net::{IpAddr, SocketAddr};
29use std::str::FromStr;
30use std::sync::atomic::{AtomicUsize, Ordering};
31
32use bitflags::bitflags;
33
34use crate::{internal_error, internal_error_map, error::*, writer_error};
35use crate::portable::*;
36use crate::tokenizer::*;
37
38use super::common::{IPV4_BIND_ALL, IPV6_BIND_ALL};
39
40static ROUND_ROBIN_CNT: AtomicUsize = AtomicUsize::new(0);
43
44
45
46pub struct RoundRobinIterator<'iterator>
49{
50 end_index: usize,
51 current_index: usize,
52 slice: &'iterator [ResolveConfEntry]
53}
54
55impl<'iterator> RoundRobinIterator<'iterator>
56{
57 pub
58 fn new(start_index: usize, slice: &'iterator [ResolveConfEntry]) -> RoundRobinIterator<'iterator>
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> Iterator for RoundRobinIterator<'iterator>
77{
78 type Item = &'iterator ResolveConfEntry;
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, Debug)]
100pub struct ResolveConfEntry
101{
102 ip: IpAddr,
103 adapter_ip: SocketAddr,
104}
105
106impl ResolveConfEntry
107{
108 pub
109 fn get_resolver_ip(&self) -> &IpAddr
110 {
111 return &self.ip;
112 }
113
114 pub
115 fn get_adapter_ip(&self) -> &SocketAddr
116 {
117 return &self.adapter_ip;
118 }
119}
120
121bitflags! {
129 #[derive(Clone, Debug, PartialEq, Eq, Copy)]
131 pub struct ResolveConfigLookup: u32
132 {
133 const FILE_BIND = 0x10;
135 const BIND_FILE = 0x20;
137 const FILE = 0x01;
139 const BIND = 0x02;
141 }
142}
143
144
145impl ResolveConfigLookup
146{
147 pub
148 fn is_file(&self) -> bool
149 {
150 return self.contains(Self::FILE);
151 }
152
153 pub
154 fn is_bind(&self) -> bool
155 {
156 return self.contains(Self::BIND);
157 }
158
159 pub
160 fn is_file_first(&self) -> bool
161 {
162 return self.contains(Self::FILE_BIND);
163 }
164}
165
166impl Default for ResolveConfigLookup
167{
168 fn default() -> Self
169 {
170 return Self::FILE_BIND | Self::FILE | Self::BIND;
171 }
172}
173
174const LOOKUP_FILE: &'static str = "file";
175const LOOKUP_BIND: &'static str = "bind";
176
177impl TryFrom<&[String]> for ResolveConfigLookup
178{
179 type Error = CDnsError;
180
181 fn try_from(value: &[String]) -> Result<Self, Self::Error>
182 {
183 if value.is_empty() == true
184 {
185 internal_error!(CDnsErrorType::ConfigError, "'lookup' is empty");
186 }
187 else if value.len() > 2
188 {
189 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with too many paramenters: '{:?}'", value);
190 }
191
192 let first =
195 if value[0] == LOOKUP_FILE
196 {
197 Self::FILE
198 }
199 else if value[0] == LOOKUP_BIND
200 {
201 Self::BIND
202 }
203 else
204 {
205 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with unknown parameter: '{}'", value[0]);
206 };
207
208 let second: Self =
209 if value.len() == 2
210 {
211 if value[1] == LOOKUP_FILE
212 {
213 if first.contains(Self::FILE) == true
214 {
215 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with duplicate parameter: '{}'", value[1]);
216 }
217
218 Self::BIND_FILE | Self::FILE
219 }
220 else if value[1] == LOOKUP_BIND
221 {
222 if first.contains(Self::BIND) == true
223 {
224 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with duplicate parameter: '{}'", value[1]);
225 }
226
227 Self::FILE_BIND | Self::BIND
228 }
229 else
230 {
231 internal_error!(CDnsErrorType::ConfigError, "'lookup' is set with unknown parameter: '{}'", value[0]);
232 }
233 }
234 else
235 {
236 Self::empty()
237 };
238
239 return Ok(Self::from(first | second));
240
241 }
242}
243
244bitflags! {
245 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
247 pub struct ResolveConfigFamily: u32
248 {
249 const INET4_INET6 = 0x10;
251 const INET6_INET4 = 0x20;
253 const INET4 = 0x01;
255 const INET6 = 0x02;
257 }
258}
259
260impl ResolveConfigFamily
261{
262 pub
263 fn is_inet4(&self) -> bool
264 {
265 return self.contains(Self::INET4);
266 }
267
268 pub
269 fn is_inet6(&self) -> bool
270 {
271 return self.contains(Self::INET6);
272 }
273
274 pub
275 fn is_inet4_first(&self) -> bool
276 {
277 return self.contains(Self::INET4_INET6);
278 }
279
280 fn inverted_default() -> Self
281 {
282 return Self::INET6_INET4 | Self::INET4 | Self::INET6;
283 }
284}
285
286impl Default for ResolveConfigFamily
287{
288 fn default() -> Self
289 {
290 return Self::INET4_INET6 | Self::INET4 | Self::INET6;
291 }
292}
293
294const FAMILY_INET4: &'static str = "inet4";
295const FAMILY_INET6: &'static str = "inet6";
296
297impl TryFrom<&[String]> for ResolveConfigFamily
298{
299 type Error = CDnsError;
300
301 fn try_from(value: &[String]) -> Result<Self, Self::Error>
302 {
303 if value.is_empty() == true
304 {
305 internal_error!(CDnsErrorType::ConfigError, "'family' is empty");
306 }
307 else if value.len() > 2
308 {
309 internal_error!(CDnsErrorType::ConfigError, "'family' is set with too many paramenters: '{:?}'", value);
310 }
311
312 let mut family =
313 if value[0] == FAMILY_INET4
314 {
315 Self::INET4_INET6 | Self::INET4
317 }
318 else if value[0] == FAMILY_INET6
319 {
320 Self::INET6_INET4 | Self::INET6
322 }
323 else
324 {
325 internal_error!(CDnsErrorType::ConfigError, "'family' is set with unknown parameter: '{}'", value[0]);
326 };
327
328 if value.len() == 2
329 {
330 if value[1] == FAMILY_INET4
331 {
332 if family.contains(Self::INET4) == true
333 {
334 internal_error!(CDnsErrorType::ConfigError, "'family' is set with duplicate parameter: '{}'", value[1]);
335 }
336
337 family |= Self::INET4
339 }
340 else if value[1] == FAMILY_INET6
341 {
342 if family.contains(Self::INET6) == true
343 {
344 internal_error!(CDnsErrorType::ConfigError, "'family' is set with duplicate parameter: '{}'", value[1]);
345 }
346
347 family |= Self::INET6
349 }
350 else
351 {
352 internal_error!(CDnsErrorType::ConfigError, "'family' is set with unknown parameter: '{}'", value[0]);
353 }
354 }
355
356 return Ok(family);
357 }
358}
359
360
361bitflags! {
362 #[derive(Debug, Copy, Clone)]
364 pub struct OptionFlags: u16
365 {
366 const OPT_DEBUG = 0x0001;
368
369 const OPT_ROTATE = 0x0002;
371
372 const OPT_NO_CHECK_NAMES = 0x0004;
376
377 const OPT_INET6 = 0x0008;
379
380 const OPT_SINGLE_REQUEST = 0x0010;
383
384 const OPT_SINGLE_REQUEST_REOPEN = 0x0020;
387
388 const OPT_NO_RELOAD = 0x0040;
390
391 const OPT_TRUST_AD = 0x0080;
393
394 const OPT_USE_VC = 0x0100;
396 }
397}
398
399impl Default for OptionFlags
400{
401 fn default() -> Self
402 {
403 return Self::empty();
404 }
405}
406
407impl OptionFlags
408{
409 pub
410 fn is_debug(&self) -> bool
411 {
412 return self.contains(Self::OPT_DEBUG);
413 }
414
415 pub
416 fn is_rotate(&self) -> bool
417 {
418 return self.contains(Self::OPT_ROTATE);
419 }
420
421 pub
422 fn is_no_check_names(&self) -> bool
423 {
424 return self.contains(Self::OPT_NO_CHECK_NAMES);
425 }
426
427 pub
428 fn is_no_parallel(&self) -> bool
429 {
430 return self.contains(Self::OPT_SINGLE_REQUEST);
431 }
432
433 pub
434 fn is_reopen_socket(&self) -> bool
435 {
436 return self.contains(Self::OPT_SINGLE_REQUEST_REOPEN);
437 }
438
439 pub
440 fn is_force_tcp(&self) -> bool
441 {
442 return self.contains(Self::OPT_USE_VC);
443 }
444}
445
446
447#[derive(Clone, Debug, Default)]
448pub struct ResolveConfig
449{
450 pub nameservers: Vec<ResolveConfEntry>,
451 pub lookup: ResolveConfigLookup,
452 pub family: ResolveConfigFamily,
453 pub search_list: Vec<String>,
454 pub domain: Option<String>,
455 pub option_flags: OptionFlags,
456 pub ndots: usize,
457 pub timeout: u32,
458 pub attempts: usize,
459}
460
461
462impl ResolveConfig
463{
464 pub
473 fn get_resolvers_iter(&self) -> RoundRobinIterator
474 {
475 if self.option_flags.is_rotate() == true
476 {
477 let start_index = ROUND_ROBIN_CNT.fetch_add(1, Ordering::SeqCst);
478
479 return RoundRobinIterator::new(start_index, self.nameservers.as_slice());
480 }
481 else
482 {
483 return RoundRobinIterator::new(0, self.nameservers.as_slice());
484 };
485 }
486
487 unsafe
488 fn split_dns_ifr(field_data: &str, ifr: Option<&IfInfo>) -> CDnsResult<(IpAddr, SocketAddr)>
489 {
490 if let Some((ip, intf)) = field_data.split_once("%")
491 {
492 let ip_addr: IpAddr =
493 ip.parse().map_err(|e|
494 internal_error_map!(CDnsErrorType::InternalError, "parse IP: '{}' failed: '{}'", ip, e)
495 )?;
496
497 if ifr.is_none() == true
498 {
499 internal_error!(
500 CDnsErrorType::InternalError,
501 "can not add: '{}' to list because interface data is not available!",
502 field_data
503 );
504 }
505
506 let ifrr = ifr.unwrap();
507
508 match ifrr.get_ifr_ip(intf, &ip_addr)?
509 {
510 Some(ip_ifr) => return Ok( (ip_addr, SocketAddr::from((ip_ifr, 0))) ),
511 None => internal_error!(CDnsErrorType::InternalError, "interface: '{}' does not exist", intf),
512 }
513 }
514 else
515 {
516 let ip_addr: IpAddr =
517 match field_data.parse()
518 {
519 Ok(r) => r,
520 Err(e) =>
521 internal_error!(CDnsErrorType::InternalError, "parse IP: '{}' failed: '{}'", field_data, e)
522 };
523
524 let ip_ifr =
525 match ip_addr
526 {
527 IpAddr::V4(_) =>
528 SocketAddr::from((IPV4_BIND_ALL, 0)),
529 IpAddr::V6(_) =>
530 SocketAddr::from((IPV6_BIND_ALL, 0)),
531 };
532
533 return Ok((ip_addr, ip_ifr))
534 }
535 }
536
537 #[inline]
538 fn set_option(
539 optname: &'static str,
540 right: Option<&str>,
541 option_flags: &mut OptionFlags,
542 opt_flag: OptionFlags
543 ) -> CDnsResult<()>
544 {
545 if right.is_some() == true
546 {
547 internal_error!(CDnsErrorType::ConfigError,
548 "in /etc/resolv.conf - 'option' '{}' is defined \
549 with parameter: '{}', but it does not have parameters", optname, right.unwrap());
550 }
551
552 option_flags.set(opt_flag, true);
553
554 return Ok(());
555 }
556
557 #[inline]
558 fn read_parameter<P: FromStr>(optname: &'static str, right: Option<&str>) -> CDnsResult<P>
559 {
560 if right.is_none() == true
561 {
562 internal_error!(CDnsErrorType::ConfigError,
563 "in /etc/resolv.conf - 'option' '{}' is defined without parameter", optname);
564 }
565 else
566 {
567 return
568 right.unwrap()
569 .parse::<P>()
570 .map_err(|_|
571 internal_error_map!(
572 CDnsErrorType::ConfigError,
573 "in /etc/resolv.conf - 'option' '{}' is defined with invalid \
574 parameter: '{}'", optname, right.unwrap()
575 )
576 );
577 }
578 }
579
580 pub(crate)
586 fn parser_resolv_internal(file_content: &str, f: &mut Writer) -> CDnsResult<Self>
587 {
588 let mut tk = ConfTokenizer::from_str(&file_content)?;
589
590 let mut dns_list: Vec<ResolveConfEntry> = Vec::new();
591 let mut lookup_list: ResolveConfigLookup = ResolveConfigLookup::default();
592 let mut family_list: ResolveConfigFamily = ResolveConfigFamily::default();
593
594 let mut search_list: Vec<String> = Vec::new();
596
597 let mut domain: Option<String> = None;
598 let mut option_flags: OptionFlags = OptionFlags::empty();
599 let mut ndots: usize = 1;
600 let mut timeout: u32 = 5;
601 let mut attempts: usize = 2;
602
603 let if_info: Option<IfInfo> =
604 unsafe
605 {
606 match IfInfo::get_interfaces_info()
607 {
608 Ok(r) => Some(r),
609 Err(e) =>
610 {
611 writer_error!(f, "{}", e);
612 None
613 }
614 }
615 };
616
617 loop
618 {
619 let field_name = tk.read_next()?;
620
621 if field_name.is_none() == true
622 {
623 break;
625 }
626
627 let field_name = field_name.unwrap();
628
629 if field_name == "nameserver"
630 {
631 let field_data = tk.read_next()?;
633
634 if field_data.is_none() == true
635 {
636 writer_error!(f, "unexpected EOF near nameserver");
638 break;
639 }
640
641 let field_data = field_data.unwrap();
642
643 let (dns_ip, ifr_ip) =
645 unsafe
646 {
647 match Self::split_dns_ifr(field_data, if_info.as_ref())
648 {
649 Ok((d_ip, i_ip)) => (d_ip, i_ip),
650 Err(e) =>
651 {
652 writer_error!(f, "{}", e);
653 continue;
654 }
655 }
656 };
657
658
659 dns_list.push(
660 ResolveConfEntry
661 {
662 ip: dns_ip,
663 adapter_ip: ifr_ip,
664 }
665 );
666
667
668 }
669 else if field_name == "lookup" {
671 let lookups = tk.read_upto_eol()?;
673
674 if lookups.len() == 0
675 {
676 writer_error!(f, "in /etc/resolv.conf - 'lookup' is set but no args provided, setting defaults file, bind");
677
678 lookup_list = ResolveConfigLookup::default();
679
680 continue;
681 }
682
683 lookup_list =
684 match ResolveConfigLookup::try_from(lookups.as_slice())
685 {
686 Ok(r) => r,
687 Err(e) =>
688 {
689 writer_error!(f, "in /etc/resolv.conf - {}", e);
690
691 continue;
692 }
693 };
694 }
695 else if field_name == "family" {
697 let families = tk.read_upto_eol()?;
699
700 if families.len() == 0
701 {
702 writer_error!(f, "in /etc/resolv.conf - 'family' is set but no args provided, setting defaults inet4, inet6");
703
704 family_list = ResolveConfigFamily::default();
705
706 continue;
707 }
708
709 family_list =
710 match ResolveConfigFamily::try_from(families.as_slice())
711 {
712 Ok(r) => r,
713 Err(e) =>
714 {
715 writer_error!(f, "in /etc/resolv.conf - {}", e);
716 continue;
717 }
718 };
719 }
720 else if field_name == "search"
721 {
722 let searches = tk.read_upto_eol()?;
724
725 if searches.len() == 0
726 {
727 writer_error!(f, "in /etc/resolv.conf - 'search' is defined but empty");
728 }
729 else
730 {
731 search_list.extend(searches);
732 }
733 }
734 else if field_name == "domain"
735 {
736 let mut domains = tk.read_upto_eol()?;
737
738 if domain.is_some() == true
739 {
740 writer_error!(f, "in /etc/resolv.conf - 'domain' is defined more than once: {:?} {:?}", domain, domains);
741 }
742
743 if domains.len() > 1
744 {
745 writer_error!(f, "in /etc/resolv.conf - 'domain' is defined with more than 1 address: {:?}", domains);
746 }
747 else if domains.len() == 0
748 {
749 writer_error!(f, "in /etc/resolv.conf - 'domain' is defined but empty");
750 }
751 else
752 {
753 domain = Some(domains.pop().unwrap());
754 }
755 }
756 else if field_name == "options"
757 {
758
759 let options_vec = tk.read_upto_eol()?;
760
761 if options_vec.is_empty() == true
762 {
763 writer_error!(f, "in /etc/resolv.conf - 'option' is empty!");
764
765 continue;
767 }
768
769 for option in options_vec
770 {
771 let (left, right) =
772 match option.split_once(":")
773 {
774 Some((l, r)) => (l, Some(r)),
775 None => (option.as_str(), None),
776 };
777
778 match left
779 {
780 "use-vc" | "usevc" | "tcp" => {
783 match Self::set_option("usevc", right, &mut option_flags, OptionFlags::OPT_USE_VC)
784 {
785 Err(e) => { writer_error!(f, "{}", e); },
786 Ok(_) => {}
787 }
788 },
789 "debug" =>
790 {
791 match Self::set_option("debug", right, &mut option_flags, OptionFlags::OPT_DEBUG)
792 {
793 Err(e) => { writer_error!(f, "{}", e); },
794 Ok(_) => {}
795 }
796 },
797 "ndots" =>
798 {
799 match Self::read_parameter("ndots", right)
800 {
801 Ok(val) =>
802 {
803 ndots = if val > 15 { 15 } else { val };
804 },
805 Err(e) =>
806 {
807 writer_error!(f, "{}", e);
808 }
809 }
810 },
811 "timeout" =>
812 {
813 match Self::read_parameter::<u32>("timeout", right)
814 {
815 Ok(val) =>
816 {
817 timeout = if val > 30 { 30 } else { val };
818 },
819 Err(e) =>
820 {
821 writer_error!(f, "{}", e);
822 }
823 }
824 },
825 "attempts" =>
826 {
827 match Self::read_parameter("attempts", right)
828 {
829 Ok(val) =>
830 {
831 attempts = if val > 5 { 5 } else { val };
832 },
833 Err(e) =>
834 {
835 writer_error!(f, "{}", e);
836 }
837 }
838 },
839 "rotate" =>
840 {
841 match Self::set_option("rotate", right, &mut option_flags, OptionFlags::OPT_ROTATE)
842 {
843 Err(e) => { writer_error!(f, "{}", e); },
844 Ok(_) => {}
845 }
846 },
847 "no-check-names" =>
848 {
849 match Self::set_option("no-check-names", right, &mut option_flags, OptionFlags::OPT_NO_CHECK_NAMES)
850 {
851 Err(e) => { writer_error!(f, "{}", e); },
852 Ok(_) => {}
853 }
854 },
855 "no-reload" =>
856 {
857 match Self::set_option("no-reload", right, &mut option_flags, OptionFlags::OPT_NO_RELOAD)
858 {
859 Err(e) => { writer_error!(f, "{}", e); },
860 Ok(_) => {}
861 }
862 },
863 "inet6" =>
864 {
865 match Self::set_option("inet6", right, &mut option_flags, OptionFlags::OPT_INET6)
867 {
868 Err(e) => { writer_error!(f, "{}", e); },
869 Ok(_) => {}
870 }
871 },
872 "edns0" =>
873 {
874 },
876 "single-request" =>
877 {
878 match Self::set_option("single-request", right, &mut option_flags, OptionFlags::OPT_SINGLE_REQUEST)
879 {
880 Err(e) => { writer_error!(f, "{}", e); },
881 Ok(_) => {}
882 }
883 },
884 "single-request-reopen" =>
885 {
886 match Self::set_option("single-request-reopen", right, &mut option_flags, OptionFlags::OPT_SINGLE_REQUEST_REOPEN)
887 {
888 Err(e) => { writer_error!(f, "{}", e); },
889 Ok(_) => {}
890 }
891 },
892 "trust-ad" =>
893 {
894 match Self::set_option("trust-ad", right, &mut option_flags, OptionFlags::OPT_TRUST_AD)
895 {
896 Err(e) => { writer_error!(f, "{}", e); },
897 Ok(_) => {}
898 }
899 },
900 _ =>
901 {
902 writer_error!(f, "in /etc/resolv.conf - 'option' '{}' is unknown \
903 with parameter: '{:?}'", left, right);
904 },
905 }
906
907
908 }
909 }
910 else
911 {
912 tk.skip_upto_eol();
914 }
915 }
916
917 if option_flags.contains(OptionFlags::OPT_INET6) == true
918 {
919 family_list = ResolveConfigFamily::inverted_default();
920 }
921
922
923 return Ok(
924 Self
925 {
926 nameservers: dns_list,
927 lookup: lookup_list,
928 family: family_list,
929 search_list: search_list,
930 domain: domain,
931 option_flags: option_flags,
932 ndots: ndots,
933 timeout: timeout,
934 attempts: attempts,
935 }
936 );
937 }
938}
939
940
941
942#[test]
943fn test_parser_resolv_internal_0()
944{
945 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
946 use std::str::FromStr;
947
948 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
949 let ip2: IpAddr = "127.0.0.1".parse().unwrap();
950 let ip3: IpAddr = "8.8.8.8".parse().unwrap();
951 let ip4: IpAddr = "127.0.0.1".parse().unwrap();
952 let ip4_if: SocketAddr = SocketAddr::from((Ipv4Addr::from_str("127.0.0.1").unwrap(), 0));
953 let ip5: IpAddr = "fe80::1".parse().unwrap();
954 let ip5_if: SocketAddr = SocketAddr::from((Ipv6Addr::from_str("::1").unwrap(), 0));
955
956 let test =
957 "nameserver 192.168.2.1\n\
958 nameserver 127.0.0.1\n\
959 lookup bind\n\
960 nameserver 8.8.8.8\n
961 nameserver 127.0.0.1%lo\n
962 nameserver fe80::1%lo\n";
963
964 let mut writer = Writer::new();
965
966 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
967
968 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
969 let res = res.unwrap();
970
971 assert_eq!(res.lookup, ResolveConfigLookup::BIND);
972
973 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET6 | ResolveConfigFamily::INET4);
974
975 assert_eq!(res.nameservers[0].ip, ip1);
976 assert_eq!(res.nameservers[1].ip, ip2);
977 assert_eq!(res.nameservers[2].ip, ip3);
978 assert_eq!(res.nameservers[3].ip, ip4);
979 assert_eq!(res.nameservers[3].adapter_ip, ip4_if);
980 assert_eq!(res.nameservers[4].ip, ip5);
981 assert_eq!(res.nameservers[4].adapter_ip, ip5_if);
982}
983
984#[test]
985fn test_parser_resolv_internal()
986{
987 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
988 let ip2: IpAddr = "127.0.0.1".parse().unwrap();
989 let ip3: IpAddr = "8.8.8.8".parse().unwrap();
990
991 let test =
992 "nameserver 192.168.2.1\n\
993 nameserver 127.0.0.1\n\
994 lookup bind file\n\
995 nameserver 8.8.8.8";
996
997 let mut writer = Writer::new();
998
999 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1000 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1001 let res = res.unwrap();
1002
1003 assert_eq!(res.lookup, ResolveConfigLookup::BIND | ResolveConfigLookup::FILE | ResolveConfigLookup::BIND_FILE);
1004
1005 assert_eq!(res.family, ResolveConfigFamily::INET4_INET6 | ResolveConfigFamily::INET6 | ResolveConfigFamily::INET4);
1006
1007 assert_eq!(res.nameservers[0].ip, ip1);
1008 assert_eq!(res.nameservers[1].ip, ip2);
1009 assert_eq!(res.nameservers[2].ip, ip3);
1010}
1011
1012#[test]
1013fn test_parser_resolv_internal2()
1014{
1015 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
1016 let ip2: IpAddr = "127.0.0.1".parse().unwrap();
1017 let ip3: IpAddr = "8.8.8.8".parse().unwrap();
1018
1019 let test =
1020 "# test 12345\n\
1021 # nameserver 192.168.3.1
1022 nameserver 192.168.2.1 \n\
1023 nameserver 127.0.0.1 \n\
1024 lookup file\n\
1025 family inet4\n\
1026 nameserver 8.8.8.8\n";
1027
1028 let mut writer = Writer::new();
1029
1030 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1031 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1032 let res = res.unwrap();
1033
1034 assert_eq!(res.lookup, ResolveConfigLookup::FILE);
1035
1036 assert_eq!(res.family, ResolveConfigFamily::INET4);
1037
1038 assert_eq!(res.nameservers.len(), 3);
1039 assert_eq!(res.nameservers[0].ip, ip1);
1040 assert_eq!(res.nameservers[1].ip, ip2);
1041 assert_eq!(res.nameservers[2].ip, ip3);
1042}
1043
1044#[test]
1045fn test_parser_resolv_internal3()
1046{
1047 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
1048 let ip2: IpAddr = "127.0.0.1".parse().unwrap();
1049 let ip3: IpAddr = "8.8.8.8".parse().unwrap();
1050
1051 let test =
1052 "# test 12345\n\
1053 # nameserver 192.168.3.1
1054 nameserver 192.168.2.1 \n\
1055 nameserver 127.0.0.1 \n\
1056 lookup file\n\
1057 family inet4\n\
1058 nameserver 8.8.8.8\n
1059 options attempts:1 timeout:3 debug use-vc single-request-reopen\n
1060 search localdomain";
1061
1062 let mut writer = Writer::new();
1063
1064 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1065 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1066 let res = res.unwrap();
1067
1068 assert_eq!(res.lookup, ResolveConfigLookup::FILE);
1069
1070 assert_eq!(res.family, ResolveConfigFamily::INET4);
1071
1072 assert_eq!(res.nameservers.len(), 3);
1073 assert_eq!(res.nameservers[0].ip, ip1);
1074 assert_eq!(res.nameservers[1].ip, ip2);
1075 assert_eq!(res.nameservers[2].ip, ip3);
1076
1077 assert_eq!(res.search_list[0], "localdomain");
1078
1079 assert_eq!(res.timeout, 3);
1080 assert_eq!(res.attempts, 1);
1081
1082 assert_eq!(res.option_flags.contains(OptionFlags::OPT_DEBUG), true);
1083 assert_eq!(res.option_flags.contains(OptionFlags::OPT_USE_VC), true);
1084 assert_eq!(res.option_flags.contains(OptionFlags::OPT_SINGLE_REQUEST_REOPEN), true);
1085}
1086
1087#[test]
1088fn test_parser_resolv_internal4()
1089{
1090 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
1091 let ip2: IpAddr = "127.0.0.1".parse().unwrap();
1092 let ip3: IpAddr = "8.8.8.8".parse().unwrap();
1093
1094 let test =
1095"\
1096# test 12345\n\
1097 # nameserver 192.168.3.1\n\
1098nameserver 192.168.2.1 \n\
1099nameserver 127.0.0.1 \n\
1100lookup file\n\
1101family inet4 \n\
1102nameserver 8.8.8.8\n\
1103options attempts:1 timeout:3 debug use-vc single-request-reopen\n\
1104search localdomain\n\
1105";
1106
1107 let mut writer = Writer::new();
1108
1109 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1110 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1111 let res = res.unwrap();
1112
1113 assert_eq!(res.lookup, ResolveConfigLookup::FILE);
1114
1115 assert_eq!(res.family, ResolveConfigFamily::INET4);
1116
1117 assert_eq!(res.nameservers.len(), 3);
1118 assert_eq!(res.nameservers[0].ip, ip1);
1119 assert_eq!(res.nameservers[1].ip, ip2);
1120 assert_eq!(res.nameservers[2].ip, ip3);
1121
1122 assert_eq!(res.search_list[0], "localdomain");
1123
1124 assert_eq!(res.timeout, 3);
1125 assert_eq!(res.attempts, 1);
1126
1127 assert_eq!(res.option_flags.contains(OptionFlags::OPT_DEBUG), true);
1128 assert_eq!(res.option_flags.contains(OptionFlags::OPT_USE_VC), true);
1129 assert_eq!(res.option_flags.contains(OptionFlags::OPT_SINGLE_REQUEST_REOPEN), true);
1130}
1131
1132#[test]
1133fn test_roundrobin_iter_1()
1134{
1135 use std::time::Instant;
1136
1137 fn check_order(res: &ResolveConfig, ipl: &[IpAddr], indx: usize)
1138 {
1139 let mut i = indx;
1140 let assert_i = (indx + ipl.len()) % ipl.len();
1141 let now = Instant::now();
1142
1143 let itr = res.get_resolvers_iter();
1144
1145 assert_eq!(itr.len(), ipl.len());
1146
1147 for n in itr
1148 {
1149 assert_eq!(n.ip, ipl[i]);
1151
1152 i += 1;
1153
1154 i %= ipl.len();
1155
1156 }
1157
1158 assert_eq!(i, assert_i);
1159
1160 let elapsed = now.elapsed();
1161 println!("Iter Elapsed: {:.2?}", elapsed);
1162 }
1163
1164 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
1165
1166 let ip_list: Vec<IpAddr> = vec![ip1];
1167
1168 let test =
1169"\
1170# test 12345\n\
1171 # nameserver 192.168.3.1\n\
1172nameserver 192.168.2.1 \n\
1173#nameserver 127.0.0.1 \n\
1174lookup file\n\
1175family inet4 \n\
1176#nameserver 8.8.8.8\n\
1177options attempts:1 rotate timeout:3 debug use-vc single-request-reopen\n\
1178search localdomain\n\
1179";
1180
1181let now = Instant::now();
1182
1183 let mut writer = Writer::new();
1184
1185 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1186
1187let elapsed = now.elapsed();
1188println!("parser_resolv_internal elapsed: {:.2?}", elapsed);
1189
1190 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1191 let res = res.unwrap();
1192
1193 check_order(&res, &ip_list, 0);
1194 check_order(&res, &ip_list, 0);
1195 check_order(&res, &ip_list, 0);
1196 check_order(&res, &ip_list, 0);
1197 check_order(&res, &ip_list, 0);
1198 check_order(&res, &ip_list, 0);
1199 check_order(&res, &ip_list, 0);
1200 check_order(&res, &ip_list, 0);
1201 check_order(&res, &ip_list, 0);
1202}
1203
1204#[test]
1205fn test_roundrobin_iter()
1206{
1207 use std::time::Instant;
1208
1209 fn check_order(res: &ResolveConfig, ipl: &[IpAddr], indx: usize)
1210 {
1211 let mut i = indx;
1212 let assert_i = (indx + ipl.len()) % ipl.len();
1213 let now = Instant::now();
1214
1215 let itr = res.get_resolvers_iter();
1216
1217 assert_eq!(itr.len(), ipl.len());
1218
1219 for n in itr
1220 {
1221 assert_eq!(n.ip, ipl[i]);
1223
1224 i += 1;
1225
1226 i %= ipl.len();
1227
1228 }
1229
1230 assert_eq!(i, assert_i);
1231
1232 let elapsed = now.elapsed();
1233 println!("Iter Elapsed: {:.2?}", elapsed);
1234 }
1235
1236 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
1237 let ip2: IpAddr = "127.0.0.1".parse().unwrap();
1238 let ip3: IpAddr = "8.8.8.8".parse().unwrap();
1239
1240 let ip_list: Vec<IpAddr> = vec![ip1, ip2, ip3];
1241
1242 let test =
1243"\
1244# test 12345\n\
1245 # nameserver 192.168.3.1\n\
1246nameserver 192.168.2.1 \n\
1247nameserver 127.0.0.1 \n\
1248lookup file\n\
1249family inet4 \n\
1250nameserver 8.8.8.8\n\
1251options attempts:1 rotate timeout:3 debug use-vc single-request-reopen\n\
1252search localdomain\n\
1253";
1254
1255let now = Instant::now();
1256
1257 let mut writer = Writer::new();
1258
1259 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1260
1261let elapsed = now.elapsed();
1262println!("parser_resolv_internal elapsed: {:.2?}", elapsed);
1263
1264 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1265 let res = res.unwrap();
1266
1267 check_order(&res, &ip_list, 0);
1268 check_order(&res, &ip_list, 1);
1269 check_order(&res, &ip_list, 2);
1270 check_order(&res, &ip_list, 0);
1271 check_order(&res, &ip_list, 1);
1272 check_order(&res, &ip_list, 2);
1273 check_order(&res, &ip_list, 0);
1274 check_order(&res, &ip_list, 1);
1275 check_order(&res, &ip_list, 2);
1276}
1277
1278#[test]
1279fn test_direct_iter()
1280{
1281 use std::time::Instant;
1282
1283 let ip1: IpAddr = "192.168.2.1".parse().unwrap();
1284 let ip2: IpAddr = "192.168.2.2".parse().unwrap();
1285
1286 let test =
1287"\
1288# test 12345\n\
1289 # nameserver 192.168.3.1\n\
1290nameserver 192.168.2.1 \n\
1291nameserver 192.168.2.2 \n\
1292lookup file\n\
1293family inet4 \n\
1294options attempts:1 timeout:3 debug use-vc single-request-reopen\n\
1295search localdomain\n\
1296";
1297
1298let now = Instant::now();
1299
1300 let mut writer = Writer::new();
1301
1302 let res = ResolveConfig::parser_resolv_internal(test, &mut writer);
1303
1304let elapsed = now.elapsed();
1305println!("Elapsed: {:.2?}", elapsed);
1306
1307 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1308 let res = res.unwrap();
1309
1310 let mut i: usize = 0;
1311
1312 let now = Instant::now();
1313
1314 for n in res.get_resolvers_iter()
1315 {
1316 match i
1317 {
1318 0 => { assert_eq!(n.ip, ip1); i += 1; },
1319 1 => { assert_eq!(n.ip, ip2); i += 1; },
1320 _ => panic!("!")
1321 }
1322 }
1323
1324 let elapsed = now.elapsed();
1325 println!("Iter Elapsed: {:.2?}", elapsed);
1326
1327 assert_eq!(i, 2);
1328
1329 i = 0;
1330 for n in res.get_resolvers_iter()
1331 {
1332 match i
1333 {
1334 0 => { assert_eq!(n.ip, ip1); i += 1; },
1335 1 => { assert_eq!(n.ip, ip2); i += 1; },
1336 _ => panic!("!")
1337 }
1338 }
1339
1340 assert_eq!(i, 2);
1341}
1342
1343