1 /* Test parsing of /etc/resolv.conf. Genric version.
2 Copyright (C) 2017-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* Before including this file, TEST_THREAD has to be defined to 0 or
20 1, depending on whether the threading tests should be compiled
23 #include <arpa/inet.h>
25 #include <gnu/lib-names.h>
27 #include <resolv/resolv_context.h>
30 #include <support/capture_subprocess.h>
31 #include <support/check.h>
32 #include <support/namespace.h>
33 #include <support/run_diff.h>
34 #include <support/support.h>
35 #include <support/temp_file.h>
36 #include <support/test-driver.h>
37 #include <support/xsocket.h>
38 #include <support/xstdio.h>
39 #include <support/xunistd.h>
42 # include <support/xthread.h>
45 /* This is the host name used to ensure predictable behavior of
47 static const char *const test_hostname
= "www.example.com";
49 struct support_chroot
*chroot_env
;
52 prepare (int argc
, char **argv
)
54 chroot_env
= support_chroot_create
55 ((struct support_chroot_configuration
)
61 /* Verify that the chroot environment has been set up. */
63 check_chroot_working (void *closure
)
65 xchroot (chroot_env
->path_chroot
);
66 FILE *fp
= xfopen (_PATH_RESCONF
, "r");
69 TEST_VERIFY_EXIT (res_init () == 0);
70 TEST_VERIFY (_res
.options
& RES_INIT
);
73 if (gethostname (buf
, sizeof (buf
)) < 0)
74 FAIL_EXIT1 ("gethostname: %m");
75 if (strcmp (buf
, test_hostname
) != 0)
76 FAIL_EXIT1 ("unexpected host name: %s", buf
);
79 /* If FLAG is set in *OPTIONS, write NAME to FP, and clear it in
82 print_option_flag (FILE *fp
, int *options
, int flag
, const char *name
)
86 fprintf (fp
, " %s", name
);
91 /* Write a decoded version of the resolver configuration *RESP to the
94 print_resp (FILE *fp
, res_state resp
)
96 struct resolv_context
*ctx
= __resolv_context_get_override (resp
);
97 TEST_VERIFY_EXIT (ctx
!= NULL
);
98 if (ctx
->conf
== NULL
)
99 fprintf (fp
, "; extended resolver state missing\n");
101 /* The options directive. */
103 /* RES_INIT is used internally for tracking initialization. */
104 TEST_VERIFY (resp
->options
& RES_INIT
);
105 /* Also mask out other default flags which cannot be set through
106 the options directive. */
108 = resp
->options
& ~(RES_INIT
| RES_RECURSE
| RES_DEFNAMES
| RES_DNSRCH
);
111 || resp
->retrans
!= RES_TIMEOUT
112 || resp
->retry
!= RES_DFLRETRY
)
114 fputs ("options", fp
);
115 if (resp
->ndots
!= 1)
116 fprintf (fp
, " ndots:%d", resp
->ndots
);
117 if (resp
->retrans
!= RES_TIMEOUT
)
118 fprintf (fp
, " timeout:%d", resp
->retrans
);
119 if (resp
->retry
!= RES_DFLRETRY
)
120 fprintf (fp
, " attempts:%d", resp
->retry
);
121 print_option_flag (fp
, &options
, RES_USEVC
, "use-vc");
122 print_option_flag (fp
, &options
, RES_ROTATE
, "rotate");
123 print_option_flag (fp
, &options
, RES_USE_EDNS0
, "edns0");
124 print_option_flag (fp
, &options
, RES_SNGLKUP
,
126 print_option_flag (fp
, &options
, RES_SNGLKUPREOP
,
127 "single-request-reopen");
128 print_option_flag (fp
, &options
, RES_NOTLDQUERY
, "no-tld-query");
129 print_option_flag (fp
, &options
, RES_NORELOAD
, "no-reload");
130 print_option_flag (fp
, &options
, RES_TRUSTAD
, "trust-ad");
133 fprintf (fp
, "; error: unresolved option bits: 0x%x\n", options
);
137 /* The search and domain directives. */
138 if (resp
->dnsrch
[0] != NULL
)
140 fputs ("search", fp
);
141 for (int i
= 0; i
< MAXDNSRCH
&& resp
->dnsrch
[i
] != NULL
; ++i
)
144 fputs (resp
->dnsrch
[i
], fp
);
148 else if (resp
->defdname
[0] != '\0')
149 fprintf (fp
, "domain %s\n", resp
->defdname
);
151 /* The extended search path. */
156 const char *name
= __resolv_context_search_list (ctx
, i
);
159 fprintf (fp
, "; search[%zu]: %s\n", i
, name
);
164 /* The sortlist directive. */
167 fputs ("sortlist", fp
);
168 for (int i
= 0; i
< resp
->nsort
&& i
< MAXRESOLVSORT
; ++i
)
171 if (inet_ntop (AF_INET
, &resp
->sort_list
[i
].addr
,
172 net
, sizeof (net
)) == NULL
)
173 FAIL_EXIT1 ("inet_ntop: %m\n");
175 if (inet_ntop (AF_INET
, &resp
->sort_list
[i
].mask
,
176 mask
, sizeof (mask
)) == NULL
)
177 FAIL_EXIT1 ("inet_ntop: %m\n");
178 fprintf (fp
, " %s/%s", net
, mask
);
183 /* The nameserver directives. */
184 for (size_t i
= 0; i
< resp
->nscount
; ++i
)
186 char host
[NI_MAXHOST
];
187 char service
[NI_MAXSERV
];
189 /* See get_nsaddr in res_send.c. */
192 if (resp
->nsaddr_list
[i
].sin_family
== 0
193 && resp
->_u
._ext
.nsaddrs
[i
] != NULL
)
195 addr
= resp
->_u
._ext
.nsaddrs
[i
];
196 addrlen
= sizeof (*resp
->_u
._ext
.nsaddrs
[i
]);
200 addr
= &resp
->nsaddr_list
[i
];
201 addrlen
= sizeof (resp
->nsaddr_list
[i
]);
204 int ret
= getnameinfo (addr
, addrlen
,
205 host
, sizeof (host
), service
, sizeof (service
),
206 NI_NUMERICHOST
| NI_NUMERICSERV
);
209 if (ret
== EAI_SYSTEM
)
210 fprintf (fp
, "; error: getnameinfo: %m\n");
212 fprintf (fp
, "; error: getnameinfo: %s\n", gai_strerror (ret
));
216 fprintf (fp
, "nameserver %s\n", host
);
217 if (strcmp (service
, "53") != 0)
218 fprintf (fp
, "; unrepresentable port number %s\n\n", service
);
222 /* The extended name server list. */
227 const struct sockaddr
*addr
= __resolv_context_nameserver (ctx
, i
);
231 switch (addr
->sa_family
)
234 addrlen
= sizeof (struct sockaddr_in
);
237 addrlen
= sizeof (struct sockaddr_in6
);
240 FAIL_EXIT1 ("invalid address family %d", addr
->sa_family
);
243 char host
[NI_MAXHOST
];
244 char service
[NI_MAXSERV
];
245 int ret
= getnameinfo (addr
, addrlen
,
246 host
, sizeof (host
), service
, sizeof (service
),
247 NI_NUMERICHOST
| NI_NUMERICSERV
);
251 if (ret
== EAI_SYSTEM
)
252 fprintf (fp
, "; error: getnameinfo: %m\n");
254 fprintf (fp
, "; error: getnameinfo: %s\n", gai_strerror (ret
));
257 fprintf (fp
, "; nameserver[%zu]: [%s]:%s\n", i
, host
, service
);
262 TEST_VERIFY (!ferror (fp
));
264 __resolv_context_put (ctx
);
267 /* Parameters of one test case. */
270 /* A short, descriptive name of the test. */
273 /* The contents of the /etc/resolv.conf file. */
276 /* The expected output from print_resp. */
277 const char *expected
;
279 /* Setting for the LOCALDOMAIN environment variable. NULL if the
280 variable is not to be set. */
281 const char *localdomain
;
283 /* Setting for the RES_OPTIONS environment variable. NULL if the
284 variable is not to be set. */
285 const char *res_options
;
287 /* Override the system host name. NULL means that no change is made
288 and the default is used (test_hostname). */
289 const char *hostname
;
299 test_init_method_last
= test_getaddrinfo
302 static const char *const test_init_names
[] =
304 [test_init
] = "res_init",
305 [test_ninit
] = "res_ninit",
306 [test_mkquery
] = "res_mkquery",
307 [test_gethostbyname
] = "gethostbyname",
308 [test_getaddrinfo
] = "getaddrinfo",
311 /* Closure argument for run_res_init. */
315 const struct test_case
*t
;
319 setup_nss_dns_and_chroot (void)
321 /* Load nss_dns outside of the chroot. */
322 if (dlopen (LIBNSS_DNS_SO
, RTLD_LAZY
) == NULL
)
323 FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO
": %s", dlerror ());
324 xchroot (chroot_env
->path_chroot
);
325 /* Force the use of nss_dns. */
326 __nss_configure_lookup ("hosts", "dns");
329 /* Run res_ninit or res_init in a subprocess and dump the parsed
330 resolver state to standard output. */
332 run_res_init (void *closure
)
334 struct test_context
*ctx
= closure
;
335 TEST_VERIFY (getenv ("LOCALDOMAIN") == NULL
);
336 TEST_VERIFY (getenv ("RES_OPTIONS") == NULL
);
337 if (ctx
->t
->localdomain
!= NULL
)
338 setenv ("LOCALDOMAIN", ctx
->t
->localdomain
, 1);
339 if (ctx
->t
->res_options
!= NULL
)
340 setenv ("RES_OPTIONS", ctx
->t
->res_options
, 1);
341 if (ctx
->t
->hostname
!= NULL
)
344 /* This test needs its own namespace, to avoid changing the host
345 name for the parent, too. */
346 TEST_VERIFY_EXIT (unshare (CLONE_NEWUTS
) == 0);
347 if (sethostname (ctx
->t
->hostname
, strlen (ctx
->t
->hostname
)) != 0)
348 FAIL_EXIT1 ("sethostname (\"%s\"): %m", ctx
->t
->hostname
);
350 FAIL_UNSUPPORTED ("clone (CLONE_NEWUTS) not supported");
357 xchroot (chroot_env
->path_chroot
);
358 TEST_VERIFY (res_init () == 0);
359 print_resp (stdout
, &_res
);
363 xchroot (chroot_env
->path_chroot
);
364 res_state resp
= xmalloc (sizeof (*resp
));
365 memset (resp
, 0, sizeof (*resp
));
366 TEST_VERIFY (res_ninit (resp
) == 0);
367 print_resp (stdout
, resp
);
373 xchroot (chroot_env
->path_chroot
);
374 unsigned char buf
[512];
375 TEST_VERIFY (res_mkquery (QUERY
, "www.example",
376 C_IN
, ns_t_a
, NULL
, 0,
377 NULL
, buf
, sizeof (buf
)) > 0);
378 print_resp (stdout
, &_res
);
381 case test_gethostbyname
:
382 setup_nss_dns_and_chroot ();
383 /* Trigger implicit initialization of the _res structure. The
384 actual lookup result is immaterial. */
385 (void )gethostbyname ("www.example");
386 print_resp (stdout
, &_res
);
389 case test_getaddrinfo
:
390 setup_nss_dns_and_chroot ();
391 /* Trigger implicit initialization of the _res structure. The
392 actual lookup result is immaterial. */
394 (void) getaddrinfo ("www.example", NULL
, NULL
, &ai
);
395 print_resp (stdout
, &_res
);
399 FAIL_EXIT1 ("invalid init method %d", ctx
->init
);
403 /* Helper function which calls run_res_init from a thread. */
405 run_res_init_thread_func (void *closure
)
407 run_res_init (closure
);
411 /* Variant of res_run_init which runs the function on a non-main
414 run_res_init_on_thread (void *closure
)
416 xpthread_join (xpthread_create (NULL
, run_res_init_thread_func
, closure
));
418 #endif /* TEST_THREAD */
420 struct test_case test_cases
[] =
422 {.name
= "empty file",
424 .expected
= "search example.com\n"
425 "; search[0]: example.com\n"
426 "nameserver 127.0.0.1\n"
427 "; nameserver[0]: [127.0.0.1]:53\n"
429 {.name
= "empty file, no-dot hostname",
431 .expected
= "nameserver 127.0.0.1\n"
432 "; nameserver[0]: [127.0.0.1]:53\n",
433 .hostname
= "example",
435 {.name
= "empty file with LOCALDOMAIN",
437 .expected
= "search example.net\n"
438 "; search[0]: example.net\n"
439 "nameserver 127.0.0.1\n"
440 "; nameserver[0]: [127.0.0.1]:53\n",
441 .localdomain
= "example.net",
443 {.name
= "empty file with RES_OPTIONS",
445 .expected
= "options attempts:5 edns0\n"
446 "search example.com\n"
447 "; search[0]: example.com\n"
448 "nameserver 127.0.0.1\n"
449 "; nameserver[0]: [127.0.0.1]:53\n",
450 .res_options
= "edns0 attempts:5",
452 {.name
= "empty file with RES_OPTIONS and LOCALDOMAIN",
454 .expected
= "options attempts:5 edns0\n"
455 "search example.org\n"
456 "; search[0]: example.org\n"
457 "nameserver 127.0.0.1\n"
458 "; nameserver[0]: [127.0.0.1]:53\n",
459 .localdomain
= "example.org",
460 .res_options
= "edns0 attempts:5",
463 .conf
= "search corp.example.com example.com\n"
464 "nameserver 192.0.2.1\n",
465 .expected
= "search corp.example.com example.com\n"
466 "; search[0]: corp.example.com\n"
467 "; search[1]: example.com\n"
468 "nameserver 192.0.2.1\n"
469 "; nameserver[0]: [192.0.2.1]:53\n"
471 {.name
= "basic with no-dot hostname",
472 .conf
= "search corp.example.com example.com\n"
473 "nameserver 192.0.2.1\n",
474 .expected
= "search corp.example.com example.com\n"
475 "; search[0]: corp.example.com\n"
476 "; search[1]: example.com\n"
477 "nameserver 192.0.2.1\n"
478 "; nameserver[0]: [192.0.2.1]:53\n",
479 .hostname
= "example",
481 {.name
= "basic no-reload",
482 .conf
= "options no-reload\n"
483 "search corp.example.com example.com\n"
484 "nameserver 192.0.2.1\n",
485 .expected
= "options no-reload\n"
486 "search corp.example.com example.com\n"
487 "; search[0]: corp.example.com\n"
488 "; search[1]: example.com\n"
489 "nameserver 192.0.2.1\n"
490 "; nameserver[0]: [192.0.2.1]:53\n"
492 {.name
= "basic no-reload via RES_OPTIONS",
493 .conf
= "search corp.example.com example.com\n"
494 "nameserver 192.0.2.1\n",
495 .expected
= "options no-reload\n"
496 "search corp.example.com example.com\n"
497 "; search[0]: corp.example.com\n"
498 "; search[1]: example.com\n"
499 "nameserver 192.0.2.1\n"
500 "; nameserver[0]: [192.0.2.1]:53\n",
501 .res_options
= "no-reload"
503 {.name
= "whitespace",
504 .conf
= "# This test covers comment and whitespace processing "
505 " (trailing whitespace,\n"
506 "# missing newline at end of file).\n"
508 ";search commented out\n"
509 "search corp.example.com\texample.com \n"
510 "#nameserver 192.0.2.3\n"
511 "nameserver 192.0.2.1 \n"
512 "nameserver 192.0.2.2", /* No \n at end of file. */
513 .expected
= "search corp.example.com example.com\n"
514 "; search[0]: corp.example.com\n"
515 "; search[1]: example.com\n"
516 "nameserver 192.0.2.1\n"
517 "nameserver 192.0.2.2\n"
518 "; nameserver[0]: [192.0.2.1]:53\n"
519 "; nameserver[1]: [192.0.2.2]:53\n"
522 .conf
= "domain example.net\n"
523 "nameserver 192.0.2.1\n",
524 .expected
= "search example.net\n"
525 "; search[0]: example.net\n"
526 "nameserver 192.0.2.1\n"
527 "; nameserver[0]: [192.0.2.1]:53\n"
529 {.name
= "domain space",
530 .conf
= "domain example.net \n"
531 "nameserver 192.0.2.1\n",
532 .expected
= "search example.net\n"
533 "; search[0]: example.net\n"
534 "nameserver 192.0.2.1\n"
535 "; nameserver[0]: [192.0.2.1]:53\n"
537 {.name
= "domain tab",
538 .conf
= "domain example.net\t\n"
539 "nameserver 192.0.2.1\n",
540 .expected
= "search example.net\n"
541 "; search[0]: example.net\n"
542 "nameserver 192.0.2.1\n"
543 "; nameserver[0]: [192.0.2.1]:53\n"
545 {.name
= "domain override",
546 .conf
= "search example.com example.org\n"
547 "nameserver 192.0.2.1\n"
548 "domain example.net", /* No \n at end of file. */
549 .expected
= "search example.net\n"
550 "; search[0]: example.net\n"
551 "nameserver 192.0.2.1\n"
552 "; nameserver[0]: [192.0.2.1]:53\n"
554 {.name
= "option values, multiple servers",
555 .conf
= "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
556 "domain example.net\n"
558 "search corp.example.com\texample.com\n"
559 "nameserver 192.0.2.1\n"
561 "nameserver 192.0.2.2\n",
562 .expected
= "options ndots:3 timeout:19 attempts:5 edns0\n"
563 "search corp.example.com example.com\n"
564 "; search[0]: corp.example.com\n"
565 "; search[1]: example.com\n"
566 "nameserver 192.0.2.1\n"
568 "nameserver 192.0.2.2\n"
569 "; nameserver[0]: [192.0.2.1]:53\n"
570 "; nameserver[1]: [::1]:53\n"
571 "; nameserver[2]: [192.0.2.2]:53\n"
573 {.name
= "out-of-range option vales",
574 .conf
= "options use-vc timeout:999 attempts:999 ndots:99\n"
575 "search example.com\n",
576 .expected
= "options ndots:15 timeout:30 attempts:5 use-vc\n"
577 "search example.com\n"
578 "; search[0]: example.com\n"
579 "nameserver 127.0.0.1\n"
580 "; nameserver[0]: [127.0.0.1]:53\n"
582 {.name
= "repeated directives",
583 .conf
= "options ndots:3 use-vc\n"
584 "options edns0 ndots:2\n"
585 "domain corp.example\n"
586 "search example.net corp.example.com example.com\n"
587 "search example.org\n"
589 .expected
= "options ndots:2 use-vc edns0\n"
590 "search example.org\n"
591 "; search[0]: example.org\n"
592 "nameserver 127.0.0.1\n"
593 "; nameserver[0]: [127.0.0.1]:53\n"
595 {.name
= "many name servers, sortlist",
596 .conf
= "options single-request\n"
597 "search example.org example.com example.net corp.example.com\n"
598 "sortlist 192.0.2.0/255.255.255.0\n"
599 "nameserver 192.0.2.1\n"
600 "nameserver 192.0.2.2\n"
601 "nameserver 192.0.2.3\n"
602 "nameserver 192.0.2.4\n"
603 "nameserver 192.0.2.5\n"
604 "nameserver 192.0.2.6\n"
605 "nameserver 192.0.2.7\n"
606 "nameserver 192.0.2.8\n",
607 .expected
= "options single-request\n"
608 "search example.org example.com example.net corp.example.com\n"
609 "; search[0]: example.org\n"
610 "; search[1]: example.com\n"
611 "; search[2]: example.net\n"
612 "; search[3]: corp.example.com\n"
613 "sortlist 192.0.2.0/255.255.255.0\n"
614 "nameserver 192.0.2.1\n"
615 "nameserver 192.0.2.2\n"
616 "nameserver 192.0.2.3\n"
617 "; nameserver[0]: [192.0.2.1]:53\n"
618 "; nameserver[1]: [192.0.2.2]:53\n"
619 "; nameserver[2]: [192.0.2.3]:53\n"
620 "; nameserver[3]: [192.0.2.4]:53\n"
621 "; nameserver[4]: [192.0.2.5]:53\n"
622 "; nameserver[5]: [192.0.2.6]:53\n"
623 "; nameserver[6]: [192.0.2.7]:53\n"
624 "; nameserver[7]: [192.0.2.8]:53\n"
626 {.name
= "IPv4 and IPv6 nameservers",
627 .conf
= "options single-request\n"
628 "search example.org example.com example.net corp.example.com"
629 " legacy.example.com\n"
630 "sortlist 192.0.2.0\n"
631 "nameserver 192.0.2.1\n"
632 "nameserver 2001:db8::2\n"
633 "nameserver 192.0.2.3\n"
634 "nameserver 2001:db8::4\n"
635 "nameserver 192.0.2.5\n"
636 "nameserver 2001:db8::6\n"
637 "nameserver 192.0.2.7\n"
638 "nameserver 2001:db8::8\n",
639 .expected
= "options single-request\n"
640 "search example.org example.com example.net corp.example.com"
641 " legacy.example.com\n"
642 "; search[0]: example.org\n"
643 "; search[1]: example.com\n"
644 "; search[2]: example.net\n"
645 "; search[3]: corp.example.com\n"
646 "; search[4]: legacy.example.com\n"
647 "sortlist 192.0.2.0/255.255.255.0\n"
648 "nameserver 192.0.2.1\n"
649 "nameserver 2001:db8::2\n"
650 "nameserver 192.0.2.3\n"
651 "; nameserver[0]: [192.0.2.1]:53\n"
652 "; nameserver[1]: [2001:db8::2]:53\n"
653 "; nameserver[2]: [192.0.2.3]:53\n"
654 "; nameserver[3]: [2001:db8::4]:53\n"
655 "; nameserver[4]: [192.0.2.5]:53\n"
656 "; nameserver[5]: [2001:db8::6]:53\n"
657 "; nameserver[6]: [192.0.2.7]:53\n"
658 "; nameserver[7]: [2001:db8::8]:53\n",
660 {.name
= "garbage after nameserver",
661 .conf
= "nameserver 192.0.2.1 garbage\n"
662 "nameserver 192.0.2.2:5353\n"
663 "nameserver 192.0.2.3 5353\n",
664 .expected
= "search example.com\n"
665 "; search[0]: example.com\n"
666 "nameserver 192.0.2.1\n"
667 "nameserver 192.0.2.3\n"
668 "; nameserver[0]: [192.0.2.1]:53\n"
669 "; nameserver[1]: [192.0.2.3]:53\n"
671 {.name
= "RES_OPTIONS is cummulative",
672 .conf
= "options timeout:7 ndots:2 use-vc\n"
673 "nameserver 192.0.2.1\n",
674 .expected
= "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
675 "search example.com\n"
676 "; search[0]: example.com\n"
677 "nameserver 192.0.2.1\n"
678 "; nameserver[0]: [192.0.2.1]:53\n",
679 .res_options
= "attempts:5 ndots:3 edns0 ",
681 {.name
= "many search list entries (bug 19569)",
682 .conf
= "nameserver 192.0.2.1\n"
683 "search corp.example.com support.example.com"
684 " community.example.org wan.example.net vpn.example.net"
685 " example.com example.org example.net\n",
686 .expected
= "search corp.example.com support.example.com"
687 " community.example.org wan.example.net vpn.example.net example.com\n"
688 "; search[0]: corp.example.com\n"
689 "; search[1]: support.example.com\n"
690 "; search[2]: community.example.org\n"
691 "; search[3]: wan.example.net\n"
692 "; search[4]: vpn.example.net\n"
693 "; search[5]: example.com\n"
694 "; search[6]: example.org\n"
695 "; search[7]: example.net\n"
696 "nameserver 192.0.2.1\n"
697 "; nameserver[0]: [192.0.2.1]:53\n"
699 {.name
= "very long search list entries (bug 21475)",
700 .conf
= "nameserver 192.0.2.1\n"
701 "search example.com "
702 #define H63 "this-host-name-is-longer-than-yours-yes-I-really-really-mean-it"
703 #define D63 "this-domain-name-is-as-long-as-the-previous-name--63-characters"
704 " " H63
"." D63
".example.org"
705 " " H63
"." D63
".example.net\n",
706 .expected
= "search example.com " H63
"." D63
".example.org\n"
707 "; search[0]: example.com\n"
708 "; search[1]: " H63
"." D63
".example.org\n"
709 "; search[2]: " H63
"." D63
".example.net\n"
712 "nameserver 192.0.2.1\n"
713 "; nameserver[0]: [192.0.2.1]:53\n"
715 {.name
= "trust-ad flag",
716 .conf
= "options trust-ad\n"
717 "nameserver 192.0.2.1\n",
718 .expected
= "options trust-ad\n"
719 "search example.com\n"
720 "; search[0]: example.com\n"
721 "nameserver 192.0.2.1\n"
722 "; nameserver[0]: [192.0.2.1]:53\n"
727 /* Run the indicated test case. This function assumes that the chroot
728 contents has already been set up. */
730 test_file_contents (const struct test_case
*t
)
733 for (int do_thread
= 0; do_thread
< 2; ++do_thread
)
735 for (int init_method
= 0; init_method
<= test_init_method_last
;
738 if (test_verbose
> 0)
739 printf ("info: testing init method %s\n",
740 test_init_names
[init_method
]);
741 struct test_context ctx
= { .init
= init_method
, .t
= t
};
742 void (*func
) (void *) = run_res_init
;
745 func
= run_res_init_on_thread
;
747 struct support_capture_subprocess proc
748 = support_capture_subprocess (func
, &ctx
);
749 if (strcmp (proc
.out
.buffer
, t
->expected
) != 0)
751 support_record_failure ();
752 printf ("error: output mismatch for %s (init method %s)\n",
753 t
->name
, test_init_names
[init_method
]);
754 support_run_diff ("expected", t
->expected
,
755 "actual", proc
.out
.buffer
);
757 support_capture_subprocess_check (&proc
, t
->name
, 0,
759 support_capture_subprocess_free (&proc
);
763 /* Special tests which do not follow the general pattern. */
764 enum { special_tests_count
= 11 };
766 /* Implementation of special tests. */
768 special_test_callback (void *closure
)
770 unsigned int *test_indexp
= closure
;
771 unsigned test_index
= *test_indexp
;
772 TEST_VERIFY (test_index
< special_tests_count
);
773 if (test_verbose
> 0)
774 printf ("info: special test %u\n", test_index
);
775 xchroot (chroot_env
->path_chroot
);
781 /* Second res_init with missing or empty file preserves
784 TEST_VERIFY (unlink (_PATH_RESCONF
) == 0);
785 _res
.options
= RES_USE_EDNS0
;
786 TEST_VERIFY (res_init () == 0);
787 /* First res_init clears flag. */
788 TEST_VERIFY (!(_res
.options
& RES_USE_EDNS0
));
789 _res
.options
|= RES_USE_EDNS0
;
790 TEST_VERIFY (res_init () == 0);
791 /* Second res_init preserves flag. */
792 TEST_VERIFY (_res
.options
& RES_USE_EDNS0
);
794 /* Restore empty file. */
795 support_write_file_string (_PATH_RESCONF
, "");
799 /* Second res_init is cumulative. */
800 support_write_file_string (_PATH_RESCONF
,
802 "nameserver 192.0.2.1\n");
803 _res
.options
= RES_USE_EDNS0
;
804 TEST_VERIFY (res_init () == 0);
805 /* First res_init clears flag. */
806 TEST_VERIFY (!(_res
.options
& RES_USE_EDNS0
));
807 /* And sets RES_ROTATE. */
808 TEST_VERIFY (_res
.options
& RES_ROTATE
);
809 _res
.options
|= RES_USE_EDNS0
;
810 TEST_VERIFY (res_init () == 0);
811 /* Second res_init preserves flag. */
812 TEST_VERIFY (_res
.options
& RES_USE_EDNS0
);
813 TEST_VERIFY (_res
.options
& RES_ROTATE
);
814 /* Reloading the configuration does not clear the explicitly set
816 support_write_file_string (_PATH_RESCONF
,
817 "nameserver 192.0.2.1\n"
818 "nameserver 192.0.2.2\n");
819 TEST_VERIFY (res_init () == 0);
820 TEST_VERIFY (_res
.nscount
== 2);
821 TEST_VERIFY (_res
.options
& RES_USE_EDNS0
);
822 /* Whether RES_ROTATE (originally in resolv.conf, now removed)
823 should be preserved is subject to debate. See bug 21701. */
824 /* TEST_VERIFY (!(_res.options & RES_ROTATE)); */
831 support_write_file_string (_PATH_RESCONF
,
833 "nameserver 192.0.2.1\n");
835 case 7: /* 7 and the following tests are with no-reload. */
839 support_write_file_string (_PATH_RESCONF
,
840 "options edns0 no-reload\n"
841 "nameserver 192.0.2.1\n");
844 for (int iteration
= 0; iteration
< 2; ++iteration
)
850 TEST_VERIFY (res_init () == 0);
855 unsigned char buf
[512];
857 (res_mkquery (QUERY
, test_hostname
, C_IN
, T_A
,
858 NULL
, 0, NULL
, buf
, sizeof (buf
)) > 0);
863 gethostbyname (test_hostname
);
869 (void) getaddrinfo (test_hostname
, NULL
, NULL
, &ai
);
873 /* test_index == 7 is res_init and performs a reload even
875 if (iteration
== 0 || test_index
> 7)
877 TEST_VERIFY (_res
.options
& RES_USE_EDNS0
);
878 TEST_VERIFY (!(_res
.options
& RES_ROTATE
));
880 TEST_VERIFY (!(_res
.options
& RES_NORELOAD
));
882 TEST_VERIFY (_res
.options
& RES_NORELOAD
);
883 TEST_VERIFY (_res
.nscount
== 1);
884 /* File change triggers automatic reloading. */
885 support_write_file_string (_PATH_RESCONF
,
887 "nameserver 192.0.2.1\n"
888 "nameserver 192.0.2.2\n");
892 if (test_index
!= 3 && test_index
!= 7)
893 /* test_index 3, 7 are res_init; this function does
894 not reset flags. See bug 21701. */
895 TEST_VERIFY (!(_res
.options
& RES_USE_EDNS0
));
896 TEST_VERIFY (_res
.options
& RES_ROTATE
);
897 TEST_VERIFY (_res
.nscount
== 2);
905 /* Helper function which calls special_test_callback from a
908 special_test_thread_func (void *closure
)
910 special_test_callback (closure
);
914 /* Variant of special_test_callback which runs the function on a
917 run_special_test_on_thread (void *closure
)
919 xpthread_join (xpthread_create (NULL
, special_test_thread_func
, closure
));
921 #endif /* TEST_THREAD */
923 /* Perform the requested special test in a subprocess using
924 special_test_callback. */
926 special_test (unsigned int test_index
)
929 for (int do_thread
= 0; do_thread
< 2; ++do_thread
)
932 void (*func
) (void *) = special_test_callback
;
935 func
= run_special_test_on_thread
;
937 struct support_capture_subprocess proc
938 = support_capture_subprocess (func
, &test_index
);
939 char *test_name
= xasprintf ("special test %u", test_index
);
940 if (strcmp (proc
.out
.buffer
, "") != 0)
942 support_record_failure ();
943 printf ("error: output mismatch for %s\n", test_name
);
944 support_run_diff ("expected", "",
945 "actual", proc
.out
.buffer
);
947 support_capture_subprocess_check (&proc
, test_name
, 0, sc_allow_stdout
);
949 support_capture_subprocess_free (&proc
);
954 /* Dummy DNS server. It ensures that the probe queries sent by
955 gethostbyname and getaddrinfo receive a reply even if the system
956 applies a very strict rate limit to localhost. */
958 start_dummy_server (void)
960 int server_socket
= xsocket (AF_INET
, SOCK_DGRAM
, 0);
962 struct sockaddr_in sin
=
964 .sin_family
= AF_INET
,
965 .sin_addr
= { .s_addr
= htonl (INADDR_LOOPBACK
) },
966 .sin_port
= htons (53),
968 int ret
= bind (server_socket
, (struct sockaddr
*) &sin
, sizeof (sin
));
972 /* The port is reserved, which means we cannot start the
975 FAIL_EXIT1 ("cannot bind socket to port 53: %m");
979 pid_t pid
= xfork ();
982 /* Child process. Echo back queries as SERVFAIL responses. */
988 unsigned char bytes
[512];
990 struct sockaddr_in sin
;
991 socklen_t sinlen
= sizeof (sin
);
993 ssize_t ret
= recvfrom
994 (server_socket
, &packet
, sizeof (packet
),
995 MSG_NOSIGNAL
, (struct sockaddr
*) &sin
, &sinlen
);
997 FAIL_EXIT1 ("recvfrom on fake server socket: %m");
998 if (ret
> sizeof (HEADER
))
1000 /* Turn the query into a SERVFAIL response. */
1001 packet
.header
.qr
= 1;
1002 packet
.header
.rcode
= ns_r_servfail
;
1004 /* Send the response. */
1005 ret
= sendto (server_socket
, &packet
, ret
,
1006 MSG_NOSIGNAL
, (struct sockaddr
*) &sin
, sinlen
);
1008 /* The peer may have closed socket prematurely, so
1009 this is not an error. */
1010 printf ("warning: sending DNS server reply: %m\n");
1015 /* In the parent, close the socket. */
1016 xclose (server_socket
);
1024 support_become_root ();
1025 support_enter_network_namespace ();
1026 if (!support_in_uts_namespace () || !support_can_chroot ())
1027 return EXIT_UNSUPPORTED
;
1029 /* We are in an UTS namespace, so we can set the host name without
1030 altering the state of the entire system. */
1031 if (sethostname (test_hostname
, strlen (test_hostname
)) != 0)
1032 FAIL_EXIT1 ("sethostname: %m");
1034 /* These environment variables affect resolv.conf parsing. */
1035 unsetenv ("LOCALDOMAIN");
1036 unsetenv ("RES_OPTIONS");
1038 /* Ensure that the chroot setup worked. */
1040 struct support_capture_subprocess proc
1041 = support_capture_subprocess (check_chroot_working
, NULL
);
1042 support_capture_subprocess_check (&proc
, "chroot", 0, sc_allow_none
);
1043 support_capture_subprocess_free (&proc
);
1046 pid_t server
= start_dummy_server ();
1048 for (size_t i
= 0; test_cases
[i
].name
!= NULL
; ++i
)
1050 if (test_verbose
> 0)
1051 printf ("info: running test: %s\n", test_cases
[i
].name
);
1052 TEST_VERIFY (test_cases
[i
].conf
!= NULL
);
1053 TEST_VERIFY (test_cases
[i
].expected
!= NULL
);
1055 support_write_file_string (chroot_env
->path_resolv_conf
,
1056 test_cases
[i
].conf
);
1058 test_file_contents (&test_cases
[i
]);
1060 /* The expected output from the empty file test is used for
1062 if (test_cases
[i
].conf
[0] == '\0')
1064 if (test_verbose
> 0)
1065 printf ("info: special test: missing file\n");
1066 TEST_VERIFY (unlink (chroot_env
->path_resolv_conf
) == 0);
1067 test_file_contents (&test_cases
[i
]);
1069 if (test_verbose
> 0)
1070 printf ("info: special test: dangling symbolic link\n");
1071 TEST_VERIFY (symlink ("does-not-exist", chroot_env
->path_resolv_conf
) == 0);
1072 test_file_contents (&test_cases
[i
]);
1073 TEST_VERIFY (unlink (chroot_env
->path_resolv_conf
) == 0);
1075 if (test_verbose
> 0)
1076 printf ("info: special test: unreadable file\n");
1077 support_write_file_string (chroot_env
->path_resolv_conf
, "");
1078 TEST_VERIFY (chmod (chroot_env
->path_resolv_conf
, 0) == 0);
1079 test_file_contents (&test_cases
[i
]);
1081 /* Restore the empty file. */
1082 TEST_VERIFY (unlink (chroot_env
->path_resolv_conf
) == 0);
1083 support_write_file_string (chroot_env
->path_resolv_conf
, "");
1087 /* The tests which do not follow a regular pattern. */
1088 for (unsigned int test_index
= 0;
1089 test_index
< special_tests_count
; ++test_index
)
1090 special_test (test_index
);
1094 if (kill (server
, SIGTERM
) < 0)
1095 FAIL_EXIT1 ("could not terminate server process: %m");
1096 xwaitpid (server
, NULL
, 0);
1099 support_chroot_free (chroot_env
);
1103 #define PREPARE prepare
1104 #include <support/test-driver.c>