1 extern crate resolv_conf;
2 
3 use resolv_conf::{Network, ScopedIp, Lookup, Family};
4 use std::path::Path;
5 use std::io::Read;
6 use std::fs::File;
7 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
8 
9 #[test]
test_comment()10 fn test_comment() {
11     resolv_conf::Config::parse("#").unwrap();
12     resolv_conf::Config::parse(";").unwrap();
13     resolv_conf::Config::parse("#junk").unwrap();
14     resolv_conf::Config::parse("# junk").unwrap();
15     resolv_conf::Config::parse(";junk").unwrap();
16     resolv_conf::Config::parse("; junk").unwrap();
17 }
18 
ip(s: &str) -> ScopedIp19 fn ip(s: &str) -> ScopedIp {
20     s.parse().unwrap()
21 }
22 
parse_str(s: &str) -> resolv_conf::Config23 fn parse_str(s: &str) -> resolv_conf::Config {
24     resolv_conf::Config::parse(s).unwrap()
25 }
26 
27 #[test]
test_basic_options()28 fn test_basic_options() {
29     assert_eq!(
30         parse_str("nameserver 127.0.0.1").nameservers,
31         vec![ip("127.0.0.1")]
32     );
33     assert_eq!(
34         parse_str("search localnet.*").get_search(),
35         Some(vec!["localnet.*".to_string()]).as_ref()
36     );
37     assert_eq!(
38         parse_str("domain example.com.").get_domain(),
39         Some(String::from("example.com.")).as_ref()
40     );
41 }
42 
43 #[test]
test_extra_whitespace()44 fn test_extra_whitespace() {
45     assert_eq!(
46         parse_str("domain       example.com.").get_domain(),
47         Some(String::from("example.com.")).as_ref()
48     );
49     assert_eq!(
50         parse_str("domain   example.com.   ").get_domain(),
51         Some(String::from("example.com.")).as_ref()
52     );
53     // hard tabs
54     assert_eq!(
55         parse_str("	domain		example.com.		").get_domain(),
56         Some(String::from("example.com.")).as_ref()
57     );
58     // hard tabs + spaces
59     assert_eq!(
60         parse_str(" 	domain  		example.com.	 	").get_domain(),
61         Some(String::from("example.com.")).as_ref()
62     );
63 }
64 
65 #[test]
test_invalid_lines()66 fn test_invalid_lines() {
67     assert!(resolv_conf::Config::parse("nameserver 10.0.0.1%1").is_err());
68     assert!(resolv_conf::Config::parse("nameserver 10.0.0.1.0").is_err());
69     assert!(resolv_conf::Config::parse("Nameserver 10.0.0.1").is_err());
70     assert!(resolv_conf::Config::parse("nameserver 10.0.0.1 domain foo.com").is_err());
71     assert!(resolv_conf::Config::parse("invalid foo.com").is_err());
72     assert!(resolv_conf::Config::parse("options ndots:1 foo:1").is_err());
73 }
74 
75 #[test]
test_empty_line()76 fn test_empty_line() {
77     assert_eq!(parse_str(""), resolv_conf::Config::new());
78 }
79 
80 #[test]
test_multiple_options_on_one_line()81 fn test_multiple_options_on_one_line() {
82     let config = parse_str("options ndots:8 attempts:8 rotate inet6 no-tld-query timeout:8");
83     assert_eq!(config.ndots, 8);
84     assert_eq!(config.timeout, 8);
85     assert_eq!(config.attempts, 8);
86     assert_eq!(config.rotate, true);
87     assert_eq!(config.inet6, true);
88     assert_eq!(config.no_tld_query, true);
89 }
90 
91 #[test]
test_ip()92 fn test_ip() {
93     let parsed = ip("FE80::C001:1DFF:FEE0:0%eth0");
94     let address = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xc001, 0x1dff, 0xfee0, 0);
95     let scope = "eth0".to_string();
96     assert_eq!(parsed, ScopedIp::V6(address, Some(scope)));
97 
98     let parsed = ip("FE80::C001:1DFF:FEE0:0%1");
99     let address = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xc001, 0x1dff, 0xfee0, 0);
100     let scope = "1".to_string();
101     assert_eq!(parsed, ScopedIp::V6(address, Some(scope)));
102 
103     let parsed = ip("FE80::C001:1DFF:FEE0:0");
104     let address = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xc001, 0x1dff, 0xfee0, 0);
105     assert_eq!(parsed, ScopedIp::V6(address, None));
106 
107     assert!("10.0.0.1%1".parse::<ScopedIp>().is_err());
108     assert!("10.0.0.1%eth0".parse::<ScopedIp>().is_err());
109     assert!("FE80::C001:1DFF:FEE0:0%".parse::<ScopedIp>().is_err());
110     assert!("FE80::C001:1DFF:FEE0:0% ".parse::<ScopedIp>().is_err());
111 
112     let parsed = ip("192.168.10.1");
113     let address = Ipv4Addr::new(192, 168, 10, 1);
114     assert_eq!(parsed, ScopedIp::V4(address));
115 }
116 
117 #[test]
test_nameserver()118 fn test_nameserver() {
119     assert_eq!(
120         parse_str("nameserver 127.0.0.1").nameservers[0],
121         ip("127.0.0.1")
122     );
123     assert_eq!(
124         parse_str("nameserver 127.0.0.1#comment").nameservers[0],
125         ip("127.0.0.1")
126     );
127     assert_eq!(
128         parse_str("nameserver 127.0.0.1;comment").nameservers[0],
129         ip("127.0.0.1")
130     );
131     assert_eq!(
132         parse_str("nameserver 127.0.0.1 # another comment").nameservers[0],
133         ip("127.0.0.1")
134     );
135     assert_eq!(
136         parse_str("nameserver 127.0.0.1  ; ").nameservers[0],
137         ip("127.0.0.1")
138     );
139     assert_eq!(parse_str("nameserver ::1").nameservers[0], ip("::1"));
140     assert_eq!(
141         parse_str("nameserver 2001:db8:85a3:8d3:1319:8a2e:370:7348").nameservers[0],
142         ip("2001:db8:85a3:8d3:1319:8a2e:370:7348")
143     );
144     assert_eq!(
145         parse_str("nameserver ::ffff:192.0.2.128").nameservers[0],
146         ip("::ffff:192.0.2.128")
147     );
148 }
149 
parse_file<P: AsRef<Path>>(path: P) -> resolv_conf::Config150 fn parse_file<P: AsRef<Path>>(path: P) -> resolv_conf::Config {
151     let mut data = String::new();
152     let mut file = File::open(path).unwrap();
153     file.read_to_string(&mut data).unwrap();
154     resolv_conf::Config::parse(&data).unwrap()
155 }
156 
157 #[test]
test_parse_simple_conf()158 fn test_parse_simple_conf() {
159     let mut config = resolv_conf::Config::new();
160     config
161         .nameservers
162         .push(ScopedIp::V4(Ipv4Addr::new(8, 8, 8, 8)));
163     config
164         .nameservers
165         .push(ScopedIp::V4(Ipv4Addr::new(8, 8, 4, 4)));
166     assert_eq!(config, parse_file("tests/resolv.conf-simple"));
167 }
168 
169 #[test]
test_parse_linux_conf()170 fn test_parse_linux_conf() {
171     let mut config = resolv_conf::Config::new();
172     config.set_domain(String::from("example.com"));
173     config.set_search(vec!["example.com".into(), "sub.example.com".into()]);
174     config.nameservers = vec![
175         ScopedIp::V6(
176             Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888),
177             None,
178         ),
179         ScopedIp::V6(
180             Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844),
181             None,
182         ),
183         ScopedIp::V4(Ipv4Addr::new(8, 8, 8, 8)),
184         ScopedIp::V4(Ipv4Addr::new(8, 8, 4, 4)),
185     ];
186     config.ndots = 8;
187     config.timeout = 8;
188     config.attempts = 8;
189     config.rotate = true;
190     config.inet6 = true;
191     config.no_tld_query = true;
192     config.sortlist = vec![
193         Network::V4(
194             Ipv4Addr::new(130, 155, 160, 0),
195             Ipv4Addr::new(255, 255, 240, 0),
196         ),
197         // This fails currently
198         Network::V4(Ipv4Addr::new(130, 155, 0, 0), Ipv4Addr::new(255, 255, 0, 0)),
199     ];
200     assert_eq!(config, parse_file("tests/resolv.conf-linux"));
201 }
202 
203 #[test]
test_parse_macos_conf()204 fn test_parse_macos_conf() {
205     let mut config = resolv_conf::Config::new();
206     config.set_domain(String::from("example.com."));
207     config.set_search(vec!["example.com.".into(), "sub.example.com.".into()]);
208     config.nameservers = vec![
209         ScopedIp::V6(
210             Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888),
211             None,
212         ),
213         ScopedIp::V6(
214             Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844),
215             None,
216         ),
217         ScopedIp::V4(Ipv4Addr::new(8, 8, 8, 8)),
218         ScopedIp::V4(Ipv4Addr::new(8, 8, 4, 4)),
219     ];
220     config.ndots = 8;
221     config.timeout = 8;
222     config.attempts = 8;
223     assert_eq!(config, parse_file("tests/resolv.conf-macos"));
224 }
225 
226 #[test]
test_openbsd_conf()227 fn test_openbsd_conf() {
228     let mut config = resolv_conf::Config::new();
229     config.nameservers = vec![
230         ScopedIp::V4(Ipv4Addr::new(8, 8, 8, 8)),
231         ScopedIp::V4(Ipv4Addr::new(8, 8, 4, 4)),
232     ];
233     config.lookup = vec![Lookup::File, Lookup::Bind];
234     assert_eq!(config, parse_file("tests/resolv.conf-openbsd"));
235 }
236 
237 #[test]
test_openbsd_grammar()238 fn test_openbsd_grammar() {
239     let mut config = resolv_conf::Config::new();
240     config.lookup = vec![Lookup::File, Lookup::Bind];
241     assert_eq!(resolv_conf::Config::parse("lookup file bind").unwrap(), config);
242 
243     let mut config = resolv_conf::Config::new();
244     config.lookup = vec![Lookup::Bind];
245     assert_eq!(resolv_conf::Config::parse("lookup bind").unwrap(), config);
246 
247     let mut config = resolv_conf::Config::new();
248     config.lookup = vec![Lookup::Extra(String::from("unexpected"))];
249     assert_eq!(resolv_conf::Config::parse("lookup unexpected").unwrap(), config);
250 
251     let mut config = resolv_conf::Config::new();
252     config.family = vec![Family::Inet4, Family::Inet6];
253     assert_eq!(resolv_conf::Config::parse("family inet4 inet6").unwrap(), config);
254 
255     let mut config = resolv_conf::Config::new();
256     config.family = vec![Family::Inet4];
257     assert_eq!(resolv_conf::Config::parse("family inet4").unwrap(), config);
258 
259     let mut config = resolv_conf::Config::new();
260     config.family = vec![Family::Inet6];
261     assert_eq!(resolv_conf::Config::parse("family inet6").unwrap(), config);
262 
263     assert!(resolv_conf::Config::parse("family invalid").is_err());
264 }
265 
266 #[test]
test_glibc_normalize()267 fn test_glibc_normalize() {
268     let mut config = resolv_conf::Config::new();
269     config.nameservers = vec![
270         ScopedIp::V6(
271             Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888),
272             None,
273         ),
274         ScopedIp::V6(
275             Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844),
276             None,
277         ),
278         ScopedIp::V4(Ipv4Addr::new(8, 8, 8, 8)),
279         ScopedIp::V4(Ipv4Addr::new(8, 8, 4, 4)),
280     ];
281 
282     config.set_search(vec![
283         "a.example.com".into(),
284         "b.example.com".into(),
285         "c.example.com".into(),
286         "d.example.com".into(),
287         "e.example.com".into(),
288         "f.example.com".into(),
289         "g.example.com".into(),
290         "h.example.com".into(),
291     ]);
292 
293     config.glibc_normalize();
294     assert_eq!(
295         vec![
296             ScopedIp::V6(
297                 Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888),
298                 None,
299             ),
300             ScopedIp::V6(
301                 Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844),
302                 None,
303             ),
304             ScopedIp::V4(Ipv4Addr::new(8, 8, 8, 8)),
305         ],
306         config.nameservers
307     );
308 
309     assert_eq!(
310         Some(&vec![
311             "a.example.com".into(),
312             "b.example.com".into(),
313             "c.example.com".into(),
314             "d.example.com".into(),
315             "e.example.com".into(),
316             "f.example.com".into()
317         ]),
318         config.get_search()
319     );
320 }
321 
322 #[test]
test_get_nameservers_or_local()323 fn test_get_nameservers_or_local() {
324     let config = resolv_conf::Config::new();
325     assert_eq!(
326         vec![
327             ScopedIp::from(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
328             ScopedIp::from(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))),
329         ],
330         config.get_nameservers_or_local()
331     );
332 }
333 
334 #[test]
335 #[cfg(feature = "system")]
336 #[ignore]
test_get_system_domain()337 fn test_get_system_domain() {
338     let config = resolv_conf::Config::new();
339     assert_eq!(Some("lan".into()), config.get_system_domain());
340 }
341 
342 #[test]
test_default_display()343 fn test_default_display() {
344     let original_config = resolv_conf::Config::new();
345     let output = original_config.to_string();
346     let restored_config = resolv_conf::Config::parse(&output).unwrap();
347 
348     assert_eq!(original_config, restored_config);
349 }
350 
351 #[test]
test_non_default_display()352 fn test_non_default_display() {
353     let mut original_config = resolv_conf::Config::new();
354 
355     original_config.nameservers = vec![
356         ip("192.168.0.94"),
357         ip("fe80::0123:4567:89ab:cdef"),
358         ip("fe80::0123:4567:89ab:cdef%zone"),
359     ];
360 
361     original_config.sortlist = vec![
362         Network::V4(
363             "192.168.1.94".parse().unwrap(),
364             "255.255.252.0".parse().unwrap(),
365         ),
366         Network::V6("fe80::0123".parse().unwrap(), "fe80::cdef".parse().unwrap()),
367     ];
368 
369     original_config.set_domain("my.domain".to_owned());
370 
371     original_config.set_search(
372         vec!["my.domain", "alt.domain"]
373             .into_iter()
374             .map(str::to_owned)
375             .collect(),
376     );
377 
378     original_config.debug = true;
379     original_config.ndots = 4;
380     original_config.timeout = 20;
381     original_config.attempts = 5;
382     original_config.rotate = true;
383     original_config.no_check_names = true;
384     original_config.inet6 = true;
385     original_config.ip6_bytestring = true;
386     original_config.ip6_dotint = true;
387     original_config.edns0 = true;
388     original_config.single_request = true;
389     original_config.single_request_reopen = true;
390     original_config.no_tld_query = true;
391     original_config.use_vc = true;
392 
393     let output = original_config.to_string();
394     println!("Output:\n\n{}", output);
395     let restored_config = resolv_conf::Config::parse(&output).unwrap();
396 
397     assert_eq!(original_config, restored_config);
398 }
399 
400 #[test]
test_display_preservers_last_search()401 fn test_display_preservers_last_search() {
402     let mut original_config = resolv_conf::Config::new();
403 
404     original_config.set_search(
405         vec!["my.domain", "alt.domain"]
406             .into_iter()
407             .map(str::to_owned)
408             .collect(),
409     );
410 
411     original_config.set_domain("my.domain".to_owned());
412 
413     let output = original_config.to_string();
414     println!("Output:\n\n{}", output);
415     let restored_config = resolv_conf::Config::parse(&output).unwrap();
416 
417     assert_eq!(original_config, restored_config);
418 }
419