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