x86_64 hurd: ensure we have a large enough buffer to receive exception_raise requests.
[glibc.git] / resolv / tst-resolv-res_init-skeleton.c
blobe41bcebd9d9a80249d3fd0181f57e7a59f70a567
1 /* Test parsing of /etc/resolv.conf. Generic version.
2 Copyright (C) 2017-2024 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
21 in. */
23 #include <arpa/inet.h>
24 #include <errno.h>
25 #include <gnu/lib-names.h>
26 #include <netdb.h>
27 #include <resolv/resolv_context.h>
28 #include <stdio.h>
29 #include <stdlib.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>
41 #if TEST_THREAD
42 # include <support/xthread.h>
43 #endif
45 /* This is the host name used to ensure predictable behavior of
46 res_init. */
47 static const char *const test_hostname = "www.example.com";
49 struct support_chroot *chroot_env;
51 static void
52 prepare (int argc, char **argv)
54 chroot_env = support_chroot_create
55 ((struct support_chroot_configuration)
57 .resolv_conf = "",
58 });
61 /* Verify that the chroot environment has been set up. */
62 static void
63 check_chroot_working (void *closure)
65 xchroot (chroot_env->path_chroot);
66 FILE *fp = xfopen (_PATH_RESCONF, "r");
67 xfclose (fp);
69 TEST_VERIFY_EXIT (res_init () == 0);
70 TEST_VERIFY (_res.options & RES_INIT);
72 char buf[100];
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
80 *OPTIONS. */
81 static void
82 print_option_flag (FILE *fp, int *options, int flag, const char *name)
84 if (*options & flag)
86 fprintf (fp, " %s", name);
87 *options &= ~flag;
91 /* Write a decoded version of the resolver configuration *RESP to the
92 stream FP. */
93 static void
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. */
107 int options
108 = resp->options & ~(RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH);
109 if (options != 0
110 || resp->ndots != 1
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,
125 "single-request");
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");
131 print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa");
132 print_option_flag (fp, &options, RES_STRICTERR, "strict-error");
133 fputc ('\n', fp);
134 if (options != 0)
135 fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
139 /* The search and domain directives. */
140 if (resp->dnsrch[0] != NULL)
142 fputs ("search", fp);
143 for (int i = 0; i < MAXDNSRCH && resp->dnsrch[i] != NULL; ++i)
145 fputc (' ', fp);
146 fputs (resp->dnsrch[i], fp);
148 fputc ('\n', fp);
150 else if (resp->defdname[0] != '\0')
151 fprintf (fp, "domain %s\n", resp->defdname);
153 /* The extended search path. */
155 size_t i = 0;
156 while (true)
158 const char *name = __resolv_context_search_list (ctx, i);
159 if (name == NULL)
160 break;
161 fprintf (fp, "; search[%zu]: %s\n", i, name);
162 ++i;
166 /* The sortlist directive. */
167 if (resp->nsort > 0)
169 fputs ("sortlist", fp);
170 for (int i = 0; i < resp->nsort && i < MAXRESOLVSORT; ++i)
172 char net[20];
173 if (inet_ntop (AF_INET, &resp->sort_list[i].addr,
174 net, sizeof (net)) == NULL)
175 FAIL_EXIT1 ("inet_ntop: %m\n");
176 char mask[20];
177 if (inet_ntop (AF_INET, &resp->sort_list[i].mask,
178 mask, sizeof (mask)) == NULL)
179 FAIL_EXIT1 ("inet_ntop: %m\n");
180 fprintf (fp, " %s/%s", net, mask);
182 fputc ('\n', fp);
185 /* The nameserver directives. */
186 for (size_t i = 0; i < resp->nscount; ++i)
188 char host[NI_MAXHOST];
189 char service[NI_MAXSERV];
191 /* See get_nsaddr in res_send.c. */
192 void *addr;
193 size_t addrlen;
194 if (resp->nsaddr_list[i].sin_family == 0
195 && resp->_u._ext.nsaddrs[i] != NULL)
197 addr = resp->_u._ext.nsaddrs[i];
198 addrlen = sizeof (*resp->_u._ext.nsaddrs[i]);
200 else
202 addr = &resp->nsaddr_list[i];
203 addrlen = sizeof (resp->nsaddr_list[i]);
206 int ret = getnameinfo (addr, addrlen,
207 host, sizeof (host), service, sizeof (service),
208 NI_NUMERICHOST | NI_NUMERICSERV);
209 if (ret != 0)
211 if (ret == EAI_SYSTEM)
212 fprintf (fp, "; error: getnameinfo: %m\n");
213 else
214 fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
216 else
218 fprintf (fp, "nameserver %s\n", host);
219 if (strcmp (service, "53") != 0)
220 fprintf (fp, "; unrepresentable port number %s\n\n", service);
224 /* The extended name server list. */
226 size_t i = 0;
227 while (true)
229 const struct sockaddr *addr = __resolv_context_nameserver (ctx, i);
230 if (addr == NULL)
231 break;
232 size_t addrlen;
233 switch (addr->sa_family)
235 case AF_INET:
236 addrlen = sizeof (struct sockaddr_in);
237 break;
238 case AF_INET6:
239 addrlen = sizeof (struct sockaddr_in6);
240 break;
241 default:
242 FAIL_EXIT1 ("invalid address family %d", addr->sa_family);
245 char host[NI_MAXHOST];
246 char service[NI_MAXSERV];
247 int ret = getnameinfo (addr, addrlen,
248 host, sizeof (host), service, sizeof (service),
249 NI_NUMERICHOST | NI_NUMERICSERV);
251 if (ret != 0)
253 if (ret == EAI_SYSTEM)
254 fprintf (fp, "; error: getnameinfo: %m\n");
255 else
256 fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
258 else
259 fprintf (fp, "; nameserver[%zu]: [%s]:%s\n", i, host, service);
260 ++i;
264 TEST_VERIFY (!ferror (fp));
266 __resolv_context_put (ctx);
269 /* Parameters of one test case. */
270 struct test_case
272 /* A short, descriptive name of the test. */
273 const char *name;
275 /* The contents of the /etc/resolv.conf file. */
276 const char *conf;
278 /* The expected output from print_resp. */
279 const char *expected;
281 /* Setting for the LOCALDOMAIN environment variable. NULL if the
282 variable is not to be set. */
283 const char *localdomain;
285 /* Setting for the RES_OPTIONS environment variable. NULL if the
286 variable is not to be set. */
287 const char *res_options;
289 /* Override the system host name. NULL means that no change is made
290 and the default is used (test_hostname). */
291 const char *hostname;
294 enum test_init
296 test_init,
297 test_ninit,
298 test_mkquery,
299 test_gethostbyname,
300 test_getaddrinfo,
301 test_init_method_last = test_getaddrinfo
304 static const char *const test_init_names[] =
306 [test_init] = "res_init",
307 [test_ninit] = "res_ninit",
308 [test_mkquery] = "res_mkquery",
309 [test_gethostbyname] = "gethostbyname",
310 [test_getaddrinfo] = "getaddrinfo",
313 /* Closure argument for run_res_init. */
314 struct test_context
316 enum test_init init;
317 const struct test_case *t;
320 static void
321 setup_nss_dns_and_chroot (void)
323 /* Load nss_dns outside of the chroot. */
324 if (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) == NULL)
325 FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
326 xchroot (chroot_env->path_chroot);
327 /* Force the use of nss_dns. */
328 __nss_configure_lookup ("hosts", "dns");
331 /* Run res_ninit or res_init in a subprocess and dump the parsed
332 resolver state to standard output. */
333 static void
334 run_res_init (void *closure)
336 struct test_context *ctx = closure;
337 TEST_VERIFY (getenv ("LOCALDOMAIN") == NULL);
338 TEST_VERIFY (getenv ("RES_OPTIONS") == NULL);
339 if (ctx->t->localdomain != NULL)
340 setenv ("LOCALDOMAIN", ctx->t->localdomain, 1);
341 if (ctx->t->res_options != NULL)
342 setenv ("RES_OPTIONS", ctx->t->res_options, 1);
343 if (ctx->t->hostname != NULL)
345 #ifdef CLONE_NEWUTS
346 /* This test needs its own namespace, to avoid changing the host
347 name for the parent, too. */
348 TEST_VERIFY_EXIT (unshare (CLONE_NEWUTS) == 0);
349 if (sethostname (ctx->t->hostname, strlen (ctx->t->hostname)) != 0)
350 FAIL_EXIT1 ("sethostname (\"%s\"): %m", ctx->t->hostname);
351 #else
352 FAIL_UNSUPPORTED ("clone (CLONE_NEWUTS) not supported");
353 #endif
356 switch (ctx->init)
358 case test_init:
359 xchroot (chroot_env->path_chroot);
360 TEST_VERIFY (res_init () == 0);
361 print_resp (stdout, &_res);
362 return;
364 case test_ninit:
365 xchroot (chroot_env->path_chroot);
366 res_state resp = xmalloc (sizeof (*resp));
367 memset (resp, 0, sizeof (*resp));
368 TEST_VERIFY (res_ninit (resp) == 0);
369 print_resp (stdout, resp);
370 res_nclose (resp);
371 free (resp);
372 return;
374 case test_mkquery:
375 xchroot (chroot_env->path_chroot);
376 unsigned char buf[512];
377 TEST_VERIFY (res_mkquery (QUERY, "www.example",
378 C_IN, ns_t_a, NULL, 0,
379 NULL, buf, sizeof (buf)) > 0);
380 print_resp (stdout, &_res);
381 return;
383 case test_gethostbyname:
384 setup_nss_dns_and_chroot ();
385 /* Trigger implicit initialization of the _res structure. The
386 actual lookup result is immaterial. */
387 (void )gethostbyname ("www.example");
388 print_resp (stdout, &_res);
389 return;
391 case test_getaddrinfo:
392 setup_nss_dns_and_chroot ();
393 /* Trigger implicit initialization of the _res structure. The
394 actual lookup result is immaterial. */
395 struct addrinfo *ai;
396 (void) getaddrinfo ("www.example", NULL, NULL, &ai);
397 print_resp (stdout, &_res);
398 return;
401 FAIL_EXIT1 ("invalid init method %d", ctx->init);
404 #if TEST_THREAD
405 /* Helper function which calls run_res_init from a thread. */
406 static void *
407 run_res_init_thread_func (void *closure)
409 run_res_init (closure);
410 return NULL;
413 /* Variant of res_run_init which runs the function on a non-main
414 thread. */
415 static void
416 run_res_init_on_thread (void *closure)
418 xpthread_join (xpthread_create (NULL, run_res_init_thread_func, closure));
420 #endif /* TEST_THREAD */
422 struct test_case test_cases[] =
424 {.name = "empty file",
425 .conf = "",
426 .expected = "search example.com\n"
427 "; search[0]: example.com\n"
428 "nameserver 127.0.0.1\n"
429 "; nameserver[0]: [127.0.0.1]:53\n"
431 {.name = "empty file, no-dot hostname",
432 .conf = "",
433 .expected = "nameserver 127.0.0.1\n"
434 "; nameserver[0]: [127.0.0.1]:53\n",
435 .hostname = "example",
437 {.name = "empty file with LOCALDOMAIN",
438 .conf = "",
439 .expected = "search example.net\n"
440 "; search[0]: example.net\n"
441 "nameserver 127.0.0.1\n"
442 "; nameserver[0]: [127.0.0.1]:53\n",
443 .localdomain = "example.net",
445 {.name = "empty file with RES_OPTIONS",
446 .conf = "",
447 .expected = "options attempts:5 edns0\n"
448 "search example.com\n"
449 "; search[0]: example.com\n"
450 "nameserver 127.0.0.1\n"
451 "; nameserver[0]: [127.0.0.1]:53\n",
452 .res_options = "edns0 attempts:5",
454 {.name = "empty file with RES_OPTIONS and LOCALDOMAIN",
455 .conf = "",
456 .expected = "options attempts:5 edns0\n"
457 "search example.org\n"
458 "; search[0]: example.org\n"
459 "nameserver 127.0.0.1\n"
460 "; nameserver[0]: [127.0.0.1]:53\n",
461 .localdomain = "example.org",
462 .res_options = "edns0 attempts:5",
464 {.name = "basic",
465 .conf = "search corp.example.com example.com\n"
466 "nameserver 192.0.2.1\n",
467 .expected = "search corp.example.com example.com\n"
468 "; search[0]: corp.example.com\n"
469 "; search[1]: example.com\n"
470 "nameserver 192.0.2.1\n"
471 "; nameserver[0]: [192.0.2.1]:53\n"
473 {.name = "basic with no-dot hostname",
474 .conf = "search corp.example.com example.com\n"
475 "nameserver 192.0.2.1\n",
476 .expected = "search corp.example.com example.com\n"
477 "; search[0]: corp.example.com\n"
478 "; search[1]: example.com\n"
479 "nameserver 192.0.2.1\n"
480 "; nameserver[0]: [192.0.2.1]:53\n",
481 .hostname = "example",
483 {.name = "basic no-reload",
484 .conf = "options no-reload\n"
485 "search corp.example.com example.com\n"
486 "nameserver 192.0.2.1\n",
487 .expected = "options no-reload\n"
488 "search corp.example.com example.com\n"
489 "; search[0]: corp.example.com\n"
490 "; search[1]: example.com\n"
491 "nameserver 192.0.2.1\n"
492 "; nameserver[0]: [192.0.2.1]:53\n"
494 {.name = "basic no-reload via RES_OPTIONS",
495 .conf = "search corp.example.com example.com\n"
496 "nameserver 192.0.2.1\n",
497 .expected = "options no-reload\n"
498 "search corp.example.com example.com\n"
499 "; search[0]: corp.example.com\n"
500 "; search[1]: example.com\n"
501 "nameserver 192.0.2.1\n"
502 "; nameserver[0]: [192.0.2.1]:53\n",
503 .res_options = "no-reload"
505 {.name = "whitespace",
506 .conf = "# This test covers comment and whitespace processing "
507 " (trailing whitespace,\n"
508 "# missing newline at end of file).\n"
509 "\n"
510 ";search commented out\n"
511 "search corp.example.com\texample.com \n"
512 "#nameserver 192.0.2.3\n"
513 "nameserver 192.0.2.1 \n"
514 "nameserver 192.0.2.2", /* No \n at end of file. */
515 .expected = "search corp.example.com example.com\n"
516 "; search[0]: corp.example.com\n"
517 "; search[1]: example.com\n"
518 "nameserver 192.0.2.1\n"
519 "nameserver 192.0.2.2\n"
520 "; nameserver[0]: [192.0.2.1]:53\n"
521 "; nameserver[1]: [192.0.2.2]:53\n"
523 {.name = "domain",
524 .conf = "domain example.net\n"
525 "nameserver 192.0.2.1\n",
526 .expected = "search example.net\n"
527 "; search[0]: example.net\n"
528 "nameserver 192.0.2.1\n"
529 "; nameserver[0]: [192.0.2.1]:53\n"
531 {.name = "domain space",
532 .conf = "domain example.net \n"
533 "nameserver 192.0.2.1\n",
534 .expected = "search example.net\n"
535 "; search[0]: example.net\n"
536 "nameserver 192.0.2.1\n"
537 "; nameserver[0]: [192.0.2.1]:53\n"
539 {.name = "domain tab",
540 .conf = "domain example.net\t\n"
541 "nameserver 192.0.2.1\n",
542 .expected = "search example.net\n"
543 "; search[0]: example.net\n"
544 "nameserver 192.0.2.1\n"
545 "; nameserver[0]: [192.0.2.1]:53\n"
547 {.name = "domain override",
548 .conf = "search example.com example.org\n"
549 "nameserver 192.0.2.1\n"
550 "domain example.net", /* No \n at end of file. */
551 .expected = "search example.net\n"
552 "; search[0]: example.net\n"
553 "nameserver 192.0.2.1\n"
554 "; nameserver[0]: [192.0.2.1]:53\n"
556 {.name = "option values, multiple servers",
557 .conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
558 "domain example.net\n"
559 ";domain comment\n"
560 "search corp.example.com\texample.com\n"
561 "nameserver 192.0.2.1\n"
562 "nameserver ::1\n"
563 "nameserver 192.0.2.2\n",
564 .expected = "options ndots:3 timeout:19 attempts:5 edns0\n"
565 "search corp.example.com example.com\n"
566 "; search[0]: corp.example.com\n"
567 "; search[1]: example.com\n"
568 "nameserver 192.0.2.1\n"
569 "nameserver ::1\n"
570 "nameserver 192.0.2.2\n"
571 "; nameserver[0]: [192.0.2.1]:53\n"
572 "; nameserver[1]: [::1]:53\n"
573 "; nameserver[2]: [192.0.2.2]:53\n"
575 {.name = "out-of-range option vales",
576 .conf = "options use-vc timeout:999 attempts:999 ndots:99\n"
577 "search example.com\n",
578 .expected = "options ndots:15 timeout:30 attempts:5 use-vc\n"
579 "search example.com\n"
580 "; search[0]: example.com\n"
581 "nameserver 127.0.0.1\n"
582 "; nameserver[0]: [127.0.0.1]:53\n"
584 {.name = "repeated directives",
585 .conf = "options ndots:3 use-vc\n"
586 "options edns0 ndots:2\n"
587 "domain corp.example\n"
588 "search example.net corp.example.com example.com\n"
589 "search example.org\n"
590 "search\n",
591 .expected = "options ndots:2 use-vc edns0\n"
592 "search example.org\n"
593 "; search[0]: example.org\n"
594 "nameserver 127.0.0.1\n"
595 "; nameserver[0]: [127.0.0.1]:53\n"
597 {.name = "many name servers, sortlist",
598 .conf = "options single-request\n"
599 "search example.org example.com example.net corp.example.com\n"
600 "sortlist 192.0.2.0/255.255.255.0\n"
601 "nameserver 192.0.2.1\n"
602 "nameserver 192.0.2.2\n"
603 "nameserver 192.0.2.3\n"
604 "nameserver 192.0.2.4\n"
605 "nameserver 192.0.2.5\n"
606 "nameserver 192.0.2.6\n"
607 "nameserver 192.0.2.7\n"
608 "nameserver 192.0.2.8\n",
609 .expected = "options single-request\n"
610 "search example.org example.com example.net corp.example.com\n"
611 "; search[0]: example.org\n"
612 "; search[1]: example.com\n"
613 "; search[2]: example.net\n"
614 "; search[3]: corp.example.com\n"
615 "sortlist 192.0.2.0/255.255.255.0\n"
616 "nameserver 192.0.2.1\n"
617 "nameserver 192.0.2.2\n"
618 "nameserver 192.0.2.3\n"
619 "; nameserver[0]: [192.0.2.1]:53\n"
620 "; nameserver[1]: [192.0.2.2]:53\n"
621 "; nameserver[2]: [192.0.2.3]:53\n"
622 "; nameserver[3]: [192.0.2.4]:53\n"
623 "; nameserver[4]: [192.0.2.5]:53\n"
624 "; nameserver[5]: [192.0.2.6]:53\n"
625 "; nameserver[6]: [192.0.2.7]:53\n"
626 "; nameserver[7]: [192.0.2.8]:53\n"
628 {.name = "IPv4 and IPv6 nameservers",
629 .conf = "options single-request\n"
630 "search example.org example.com example.net corp.example.com"
631 " legacy.example.com\n"
632 "sortlist 192.0.2.0\n"
633 "nameserver 192.0.2.1\n"
634 "nameserver 2001:db8::2\n"
635 "nameserver 192.0.2.3\n"
636 "nameserver 2001:db8::4\n"
637 "nameserver 192.0.2.5\n"
638 "nameserver 2001:db8::6\n"
639 "nameserver 192.0.2.7\n"
640 "nameserver 2001:db8::8\n",
641 .expected = "options single-request\n"
642 "search example.org example.com example.net corp.example.com"
643 " legacy.example.com\n"
644 "; search[0]: example.org\n"
645 "; search[1]: example.com\n"
646 "; search[2]: example.net\n"
647 "; search[3]: corp.example.com\n"
648 "; search[4]: legacy.example.com\n"
649 "sortlist 192.0.2.0/255.255.255.0\n"
650 "nameserver 192.0.2.1\n"
651 "nameserver 2001:db8::2\n"
652 "nameserver 192.0.2.3\n"
653 "; nameserver[0]: [192.0.2.1]:53\n"
654 "; nameserver[1]: [2001:db8::2]:53\n"
655 "; nameserver[2]: [192.0.2.3]:53\n"
656 "; nameserver[3]: [2001:db8::4]:53\n"
657 "; nameserver[4]: [192.0.2.5]:53\n"
658 "; nameserver[5]: [2001:db8::6]:53\n"
659 "; nameserver[6]: [192.0.2.7]:53\n"
660 "; nameserver[7]: [2001:db8::8]:53\n",
662 {.name = "garbage after nameserver",
663 .conf = "nameserver 192.0.2.1 garbage\n"
664 "nameserver 192.0.2.2:5353\n"
665 "nameserver 192.0.2.3 5353\n",
666 .expected = "search example.com\n"
667 "; search[0]: example.com\n"
668 "nameserver 192.0.2.1\n"
669 "nameserver 192.0.2.3\n"
670 "; nameserver[0]: [192.0.2.1]:53\n"
671 "; nameserver[1]: [192.0.2.3]:53\n"
673 {.name = "RES_OPTIONS is cumulative",
674 .conf = "options timeout:7 ndots:2 use-vc\n"
675 "nameserver 192.0.2.1\n",
676 .expected = "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
677 "search example.com\n"
678 "; search[0]: example.com\n"
679 "nameserver 192.0.2.1\n"
680 "; nameserver[0]: [192.0.2.1]:53\n",
681 .res_options = "attempts:5 ndots:3 edns0 ",
683 {.name = "RES_OPTIONS can clear flags",
684 .conf = "options ndots:2 use-vc no-aaaa edns0\n"
685 "nameserver 192.0.2.1\n",
686 .expected = "options ndots:3 use-vc\n"
687 "search example.com\n"
688 "; search[0]: example.com\n"
689 "nameserver 192.0.2.1\n"
690 "; nameserver[0]: [192.0.2.1]:53\n",
691 .res_options = "ndots:3 -edns0 -no-aaaa",
693 {.name = "many search list entries (bug 19569)",
694 .conf = "nameserver 192.0.2.1\n"
695 "search corp.example.com support.example.com"
696 " community.example.org wan.example.net vpn.example.net"
697 " example.com example.org example.net\n",
698 .expected = "search corp.example.com support.example.com"
699 " community.example.org wan.example.net vpn.example.net example.com\n"
700 "; search[0]: corp.example.com\n"
701 "; search[1]: support.example.com\n"
702 "; search[2]: community.example.org\n"
703 "; search[3]: wan.example.net\n"
704 "; search[4]: vpn.example.net\n"
705 "; search[5]: example.com\n"
706 "; search[6]: example.org\n"
707 "; search[7]: example.net\n"
708 "nameserver 192.0.2.1\n"
709 "; nameserver[0]: [192.0.2.1]:53\n"
711 {.name = "very long search list entries (bug 21475)",
712 .conf = "nameserver 192.0.2.1\n"
713 "search example.com "
714 #define H63 "this-host-name-is-longer-than-yours-yes-I-really-really-mean-it"
715 #define D63 "this-domain-name-is-as-long-as-the-previous-name--63-characters"
716 " " H63 "." D63 ".example.org"
717 " " H63 "." D63 ".example.net\n",
718 .expected = "search example.com " H63 "." D63 ".example.org\n"
719 "; search[0]: example.com\n"
720 "; search[1]: " H63 "." D63 ".example.org\n"
721 "; search[2]: " H63 "." D63 ".example.net\n"
722 #undef H63
723 #undef D63
724 "nameserver 192.0.2.1\n"
725 "; nameserver[0]: [192.0.2.1]:53\n"
727 {.name = "trust-ad flag",
728 .conf = "options trust-ad\n"
729 "nameserver 192.0.2.1\n",
730 .expected = "options trust-ad\n"
731 "search example.com\n"
732 "; search[0]: example.com\n"
733 "nameserver 192.0.2.1\n"
734 "; nameserver[0]: [192.0.2.1]:53\n"
736 {.name = "no-aaaa flag",
737 .conf = "options no-aaaa\n"
738 "nameserver 192.0.2.1\n",
739 .expected = "options no-aaaa\n"
740 "search example.com\n"
741 "; search[0]: example.com\n"
742 "nameserver 192.0.2.1\n"
743 "; nameserver[0]: [192.0.2.1]:53\n"
745 {.name = "strict-error flag",
746 .conf = "options strict-error\n"
747 "nameserver 192.0.2.1\n",
748 .expected = "options strict-error\n"
749 "search example.com\n"
750 "; search[0]: example.com\n"
751 "nameserver 192.0.2.1\n"
752 "; nameserver[0]: [192.0.2.1]:53\n"
754 { NULL }
757 /* Run the indicated test case. This function assumes that the chroot
758 contents has already been set up. */
759 static void
760 test_file_contents (const struct test_case *t)
762 #if TEST_THREAD
763 for (int do_thread = 0; do_thread < 2; ++do_thread)
764 #endif
765 for (int init_method = 0; init_method <= test_init_method_last;
766 ++init_method)
768 if (test_verbose > 0)
769 printf ("info: testing init method %s\n",
770 test_init_names[init_method]);
771 struct test_context ctx = { .init = init_method, .t = t };
772 void (*func) (void *) = run_res_init;
773 #if TEST_THREAD
774 if (do_thread)
775 func = run_res_init_on_thread;
776 #endif
777 struct support_capture_subprocess proc
778 = support_capture_subprocess (func, &ctx);
779 if (strcmp (proc.out.buffer, t->expected) != 0)
781 support_record_failure ();
782 printf ("error: output mismatch for %s (init method %s)\n",
783 t->name, test_init_names[init_method]);
784 support_run_diff ("expected", t->expected,
785 "actual", proc.out.buffer);
787 support_capture_subprocess_check (&proc, t->name, 0,
788 sc_allow_stdout);
789 support_capture_subprocess_free (&proc);
793 /* Special tests which do not follow the general pattern. */
794 enum { special_tests_count = 11 };
796 /* Implementation of special tests. */
797 static void
798 special_test_callback (void *closure)
800 unsigned int *test_indexp = closure;
801 unsigned test_index = *test_indexp;
802 TEST_VERIFY (test_index < special_tests_count);
803 if (test_verbose > 0)
804 printf ("info: special test %u\n", test_index);
805 xchroot (chroot_env->path_chroot);
807 switch (test_index)
809 case 0:
810 case 1:
811 /* Second res_init with missing or empty file preserves
812 flags. */
813 if (test_index == 1)
814 TEST_VERIFY (unlink (_PATH_RESCONF) == 0);
815 _res.options = RES_USE_EDNS0;
816 TEST_VERIFY (res_init () == 0);
817 /* First res_init clears flag. */
818 TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
819 _res.options |= RES_USE_EDNS0;
820 TEST_VERIFY (res_init () == 0);
821 /* Second res_init preserves flag. */
822 TEST_VERIFY (_res.options & RES_USE_EDNS0);
823 if (test_index == 1)
824 /* Restore empty file. */
825 support_write_file_string (_PATH_RESCONF, "");
826 break;
828 case 2:
829 /* Second res_init is cumulative. */
830 support_write_file_string (_PATH_RESCONF,
831 "options rotate\n"
832 "nameserver 192.0.2.1\n");
833 _res.options = RES_USE_EDNS0;
834 TEST_VERIFY (res_init () == 0);
835 /* First res_init clears flag. */
836 TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
837 /* And sets RES_ROTATE. */
838 TEST_VERIFY (_res.options & RES_ROTATE);
839 _res.options |= RES_USE_EDNS0;
840 TEST_VERIFY (res_init () == 0);
841 /* Second res_init preserves flag. */
842 TEST_VERIFY (_res.options & RES_USE_EDNS0);
843 TEST_VERIFY (_res.options & RES_ROTATE);
844 /* Reloading the configuration does not clear the explicitly set
845 flag. */
846 support_write_file_string (_PATH_RESCONF,
847 "nameserver 192.0.2.1\n"
848 "nameserver 192.0.2.2\n");
849 TEST_VERIFY (res_init () == 0);
850 TEST_VERIFY (_res.nscount == 2);
851 TEST_VERIFY (_res.options & RES_USE_EDNS0);
852 /* Whether RES_ROTATE (originally in resolv.conf, now removed)
853 should be preserved is subject to debate. See bug 21701. */
854 /* TEST_VERIFY (!(_res.options & RES_ROTATE)); */
855 break;
857 case 3:
858 case 4:
859 case 5:
860 case 6:
861 support_write_file_string (_PATH_RESCONF,
862 "options edns0\n"
863 "nameserver 192.0.2.1\n");
864 goto reload_tests;
865 case 7: /* 7 and the following tests are with no-reload. */
866 case 8:
867 case 9:
868 case 10:
869 support_write_file_string (_PATH_RESCONF,
870 "options edns0 no-reload\n"
871 "nameserver 192.0.2.1\n");
872 /* Fall through. */
873 reload_tests:
874 for (int iteration = 0; iteration < 2; ++iteration)
876 switch (test_index)
878 case 3:
879 case 7:
880 TEST_VERIFY (res_init () == 0);
881 break;
882 case 4:
883 case 8:
885 unsigned char buf[512];
886 TEST_VERIFY
887 (res_mkquery (QUERY, test_hostname, C_IN, T_A,
888 NULL, 0, NULL, buf, sizeof (buf)) > 0);
890 break;
891 case 5:
892 case 9:
893 gethostbyname (test_hostname);
894 break;
895 case 6:
896 case 10:
898 struct addrinfo *ai;
899 (void) getaddrinfo (test_hostname, NULL, NULL, &ai);
901 break;
903 /* test_index == 7 is res_init and performs a reload even
904 with no-reload. */
905 if (iteration == 0 || test_index > 7)
907 TEST_VERIFY (_res.options & RES_USE_EDNS0);
908 TEST_VERIFY (!(_res.options & RES_ROTATE));
909 if (test_index < 7)
910 TEST_VERIFY (!(_res.options & RES_NORELOAD));
911 else
912 TEST_VERIFY (_res.options & RES_NORELOAD);
913 TEST_VERIFY (_res.nscount == 1);
914 /* File change triggers automatic reloading. */
915 support_write_file_string (_PATH_RESCONF,
916 "options rotate\n"
917 "nameserver 192.0.2.1\n"
918 "nameserver 192.0.2.2\n");
920 else
922 if (test_index != 3 && test_index != 7)
923 /* test_index 3, 7 are res_init; this function does
924 not reset flags. See bug 21701. */
925 TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
926 TEST_VERIFY (_res.options & RES_ROTATE);
927 TEST_VERIFY (_res.nscount == 2);
930 break;
934 #if TEST_THREAD
935 /* Helper function which calls special_test_callback from a
936 thread. */
937 static void *
938 special_test_thread_func (void *closure)
940 special_test_callback (closure);
941 return NULL;
944 /* Variant of special_test_callback which runs the function on a
945 non-main thread. */
946 static void
947 run_special_test_on_thread (void *closure)
949 xpthread_join (xpthread_create (NULL, special_test_thread_func, closure));
951 #endif /* TEST_THREAD */
953 /* Perform the requested special test in a subprocess using
954 special_test_callback. */
955 static void
956 special_test (unsigned int test_index)
958 #if TEST_THREAD
959 for (int do_thread = 0; do_thread < 2; ++do_thread)
960 #endif
962 void (*func) (void *) = special_test_callback;
963 #if TEST_THREAD
964 if (do_thread)
965 func = run_special_test_on_thread;
966 #endif
967 struct support_capture_subprocess proc
968 = support_capture_subprocess (func, &test_index);
969 char *test_name = xasprintf ("special test %u", test_index);
970 if (strcmp (proc.out.buffer, "") != 0)
972 support_record_failure ();
973 printf ("error: output mismatch for %s\n", test_name);
974 support_run_diff ("expected", "",
975 "actual", proc.out.buffer);
977 support_capture_subprocess_check (&proc, test_name, 0, sc_allow_stdout);
978 free (test_name);
979 support_capture_subprocess_free (&proc);
984 /* Dummy DNS server. It ensures that the probe queries sent by
985 gethostbyname and getaddrinfo receive a reply even if the system
986 applies a very strict rate limit to localhost. */
987 static pid_t
988 start_dummy_server (void)
990 int server_socket = xsocket (AF_INET, SOCK_DGRAM, 0);
992 struct sockaddr_in sin =
994 .sin_family = AF_INET,
995 .sin_addr = { .s_addr = htonl (INADDR_LOOPBACK) },
996 .sin_port = htons (53),
998 int ret = bind (server_socket, (struct sockaddr *) &sin, sizeof (sin));
999 if (ret < 0)
1001 if (errno == EACCES)
1002 /* The port is reserved, which means we cannot start the
1003 server. */
1004 return -1;
1005 FAIL_EXIT1 ("cannot bind socket to port 53: %m");
1009 pid_t pid = xfork ();
1010 if (pid == 0)
1012 /* Child process. Echo back queries as SERVFAIL responses. */
1013 while (true)
1015 union
1017 HEADER header;
1018 unsigned char bytes[512];
1019 } packet;
1020 struct sockaddr_in sin;
1021 socklen_t sinlen = sizeof (sin);
1023 ssize_t ret = recvfrom
1024 (server_socket, &packet, sizeof (packet),
1025 MSG_NOSIGNAL, (struct sockaddr *) &sin, &sinlen);
1026 if (ret < 0)
1027 FAIL_EXIT1 ("recvfrom on fake server socket: %m");
1028 if (ret > sizeof (HEADER))
1030 /* Turn the query into a SERVFAIL response. */
1031 packet.header.qr = 1;
1032 packet.header.rcode = ns_r_servfail;
1034 /* Send the response. */
1035 ret = sendto (server_socket, &packet, ret,
1036 MSG_NOSIGNAL, (struct sockaddr *) &sin, sinlen);
1037 if (ret < 0)
1038 /* The peer may have closed socket prematurely, so
1039 this is not an error. */
1040 printf ("warning: sending DNS server reply: %m\n");
1045 /* In the parent, close the socket. */
1046 xclose (server_socket);
1048 return pid;
1051 static int
1052 do_test (void)
1054 support_become_root ();
1055 support_enter_network_namespace ();
1056 if (!support_in_uts_namespace () || !support_can_chroot ())
1057 return EXIT_UNSUPPORTED;
1059 /* We are in an UTS namespace, so we can set the host name without
1060 altering the state of the entire system. */
1061 if (sethostname (test_hostname, strlen (test_hostname)) != 0)
1062 FAIL_EXIT1 ("sethostname: %m");
1064 /* These environment variables affect resolv.conf parsing. */
1065 unsetenv ("LOCALDOMAIN");
1066 unsetenv ("RES_OPTIONS");
1068 /* Ensure that the chroot setup worked. */
1070 struct support_capture_subprocess proc
1071 = support_capture_subprocess (check_chroot_working, NULL);
1072 support_capture_subprocess_check (&proc, "chroot", 0, sc_allow_none);
1073 support_capture_subprocess_free (&proc);
1076 pid_t server = start_dummy_server ();
1078 for (size_t i = 0; test_cases[i].name != NULL; ++i)
1080 if (test_verbose > 0)
1081 printf ("info: running test: %s\n", test_cases[i].name);
1082 TEST_VERIFY (test_cases[i].conf != NULL);
1083 TEST_VERIFY (test_cases[i].expected != NULL);
1085 support_write_file_string (chroot_env->path_resolv_conf,
1086 test_cases[i].conf);
1088 test_file_contents (&test_cases[i]);
1090 /* The expected output from the empty file test is used for
1091 further tests. */
1092 if (test_cases[i].conf[0] == '\0')
1094 if (test_verbose > 0)
1095 printf ("info: special test: missing file\n");
1096 TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
1097 test_file_contents (&test_cases[i]);
1099 if (test_verbose > 0)
1100 printf ("info: special test: dangling symbolic link\n");
1101 TEST_VERIFY (symlink ("does-not-exist", chroot_env->path_resolv_conf) == 0);
1102 test_file_contents (&test_cases[i]);
1103 TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
1105 if (test_verbose > 0)
1106 printf ("info: special test: unreadable file\n");
1107 support_write_file_string (chroot_env->path_resolv_conf, "");
1108 TEST_VERIFY (chmod (chroot_env->path_resolv_conf, 0) == 0);
1109 test_file_contents (&test_cases[i]);
1111 /* Restore the empty file. */
1112 TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
1113 support_write_file_string (chroot_env->path_resolv_conf, "");
1117 /* The tests which do not follow a regular pattern. */
1118 for (unsigned int test_index = 0;
1119 test_index < special_tests_count; ++test_index)
1120 special_test (test_index);
1122 if (server > 0)
1124 if (kill (server, SIGTERM) < 0)
1125 FAIL_EXIT1 ("could not terminate server process: %m");
1126 xwaitpid (server, NULL, 0);
1129 support_chroot_free (chroot_env);
1130 return 0;
1133 #define PREPARE prepare
1134 #include <support/test-driver.c>