tst-resolv-res_init-skeleton.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. /* Test parsing of /etc/resolv.conf. Genric version.
  2. Copyright (C) 2017-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. /* Before including this file, TEST_THREAD has to be defined to 0 or
  16. 1, depending on whether the threading tests should be compiled
  17. in. */
  18. #include <arpa/inet.h>
  19. #include <errno.h>
  20. #include <gnu/lib-names.h>
  21. #include <netdb.h>
  22. #include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6. */
  23. #include <resolv/resolv_context.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <support/capture_subprocess.h>
  27. #include <support/check.h>
  28. #include <support/namespace.h>
  29. #include <support/run_diff.h>
  30. #include <support/support.h>
  31. #include <support/temp_file.h>
  32. #include <support/test-driver.h>
  33. #include <support/xsocket.h>
  34. #include <support/xstdio.h>
  35. #include <support/xunistd.h>
  36. #if TEST_THREAD
  37. # include <support/xthread.h>
  38. #endif
  39. /* This is the host name used to ensure predictable behavior of
  40. res_init. */
  41. static const char *const test_hostname = "www.example.com";
  42. struct support_chroot *chroot_env;
  43. static void
  44. prepare (int argc, char **argv)
  45. {
  46. chroot_env = support_chroot_create
  47. ((struct support_chroot_configuration)
  48. {
  49. .resolv_conf = "",
  50. });
  51. }
  52. /* Verify that the chroot environment has been set up. */
  53. static void
  54. check_chroot_working (void *closure)
  55. {
  56. xchroot (chroot_env->path_chroot);
  57. FILE *fp = xfopen (_PATH_RESCONF, "r");
  58. xfclose (fp);
  59. TEST_VERIFY_EXIT (res_init () == 0);
  60. TEST_VERIFY (_res.options & RES_INIT);
  61. char buf[100];
  62. if (gethostname (buf, sizeof (buf)) < 0)
  63. FAIL_EXIT1 ("gethostname: %m");
  64. if (strcmp (buf, test_hostname) != 0)
  65. FAIL_EXIT1 ("unexpected host name: %s", buf);
  66. }
  67. /* If FLAG is set in *OPTIONS, write NAME to FP, and clear it in
  68. *OPTIONS. */
  69. static void
  70. print_option_flag (FILE *fp, int *options, int flag, const char *name)
  71. {
  72. if (*options & flag)
  73. {
  74. fprintf (fp, " %s", name);
  75. *options &= ~flag;
  76. }
  77. }
  78. /* Write a decoded version of the resolver configuration *RESP to the
  79. stream FP. */
  80. static void
  81. print_resp (FILE *fp, res_state resp)
  82. {
  83. struct resolv_context *ctx = __resolv_context_get_override (resp);
  84. TEST_VERIFY_EXIT (ctx != NULL);
  85. if (ctx->conf == NULL)
  86. fprintf (fp, "; extended resolver state missing\n");
  87. /* The options directive. */
  88. {
  89. /* RES_INIT is used internally for tracking initialization. */
  90. TEST_VERIFY (resp->options & RES_INIT);
  91. /* Also mask out other default flags which cannot be set through
  92. the options directive. */
  93. int options
  94. = resp->options & ~(RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH);
  95. if (options != 0
  96. || resp->ndots != 1
  97. || resp->retrans != RES_TIMEOUT
  98. || resp->retry != RES_DFLRETRY)
  99. {
  100. fputs ("options", fp);
  101. if (resp->ndots != 1)
  102. fprintf (fp, " ndots:%d", resp->ndots);
  103. if (resp->retrans != RES_TIMEOUT)
  104. fprintf (fp, " timeout:%d", resp->retrans);
  105. if (resp->retry != RES_DFLRETRY)
  106. fprintf (fp, " attempts:%d", resp->retry);
  107. print_option_flag (fp, &options, RES_USEVC, "use-vc");
  108. print_option_flag (fp, &options, DEPRECATED_RES_USE_INET6, "inet6");
  109. print_option_flag (fp, &options, RES_ROTATE, "rotate");
  110. print_option_flag (fp, &options, RES_USE_EDNS0, "edns0");
  111. print_option_flag (fp, &options, RES_SNGLKUP,
  112. "single-request");
  113. print_option_flag (fp, &options, RES_SNGLKUPREOP,
  114. "single-request-reopen");
  115. print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query");
  116. print_option_flag (fp, &options, RES_NORELOAD, "no-reload");
  117. fputc ('\n', fp);
  118. if (options != 0)
  119. fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
  120. }
  121. }
  122. /* The search and domain directives. */
  123. if (resp->dnsrch[0] != NULL)
  124. {
  125. fputs ("search", fp);
  126. for (int i = 0; i < MAXDNSRCH && resp->dnsrch[i] != NULL; ++i)
  127. {
  128. fputc (' ', fp);
  129. fputs (resp->dnsrch[i], fp);
  130. }
  131. fputc ('\n', fp);
  132. }
  133. else if (resp->defdname[0] != '\0')
  134. fprintf (fp, "domain %s\n", resp->defdname);
  135. /* The extended search path. */
  136. {
  137. size_t i = 0;
  138. while (true)
  139. {
  140. const char *name = __resolv_context_search_list (ctx, i);
  141. if (name == NULL)
  142. break;
  143. fprintf (fp, "; search[%zu]: %s\n", i, name);
  144. ++i;
  145. }
  146. }
  147. /* The sortlist directive. */
  148. if (resp->nsort > 0)
  149. {
  150. fputs ("sortlist", fp);
  151. for (int i = 0; i < resp->nsort && i < MAXRESOLVSORT; ++i)
  152. {
  153. char net[20];
  154. if (inet_ntop (AF_INET, &resp->sort_list[i].addr,
  155. net, sizeof (net)) == NULL)
  156. FAIL_EXIT1 ("inet_ntop: %m\n");
  157. char mask[20];
  158. if (inet_ntop (AF_INET, &resp->sort_list[i].mask,
  159. mask, sizeof (mask)) == NULL)
  160. FAIL_EXIT1 ("inet_ntop: %m\n");
  161. fprintf (fp, " %s/%s", net, mask);
  162. }
  163. fputc ('\n', fp);
  164. }
  165. /* The nameserver directives. */
  166. for (size_t i = 0; i < resp->nscount; ++i)
  167. {
  168. char host[NI_MAXHOST];
  169. char service[NI_MAXSERV];
  170. /* See get_nsaddr in res_send.c. */
  171. void *addr;
  172. size_t addrlen;
  173. if (resp->nsaddr_list[i].sin_family == 0
  174. && resp->_u._ext.nsaddrs[i] != NULL)
  175. {
  176. addr = resp->_u._ext.nsaddrs[i];
  177. addrlen = sizeof (*resp->_u._ext.nsaddrs[i]);
  178. }
  179. else
  180. {
  181. addr = &resp->nsaddr_list[i];
  182. addrlen = sizeof (resp->nsaddr_list[i]);
  183. }
  184. int ret = getnameinfo (addr, addrlen,
  185. host, sizeof (host), service, sizeof (service),
  186. NI_NUMERICHOST | NI_NUMERICSERV);
  187. if (ret != 0)
  188. {
  189. if (ret == EAI_SYSTEM)
  190. fprintf (fp, "; error: getnameinfo: %m\n");
  191. else
  192. fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
  193. }
  194. else
  195. {
  196. fprintf (fp, "nameserver %s\n", host);
  197. if (strcmp (service, "53") != 0)
  198. fprintf (fp, "; unrepresentable port number %s\n\n", service);
  199. }
  200. }
  201. /* The extended name server list. */
  202. {
  203. size_t i = 0;
  204. while (true)
  205. {
  206. const struct sockaddr *addr = __resolv_context_nameserver (ctx, i);
  207. if (addr == NULL)
  208. break;
  209. size_t addrlen;
  210. switch (addr->sa_family)
  211. {
  212. case AF_INET:
  213. addrlen = sizeof (struct sockaddr_in);
  214. break;
  215. case AF_INET6:
  216. addrlen = sizeof (struct sockaddr_in6);
  217. break;
  218. default:
  219. FAIL_EXIT1 ("invalid address family %d", addr->sa_family);
  220. }
  221. char host[NI_MAXHOST];
  222. char service[NI_MAXSERV];
  223. int ret = getnameinfo (addr, addrlen,
  224. host, sizeof (host), service, sizeof (service),
  225. NI_NUMERICHOST | NI_NUMERICSERV);
  226. if (ret != 0)
  227. {
  228. if (ret == EAI_SYSTEM)
  229. fprintf (fp, "; error: getnameinfo: %m\n");
  230. else
  231. fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
  232. }
  233. else
  234. fprintf (fp, "; nameserver[%zu]: [%s]:%s\n", i, host, service);
  235. ++i;
  236. }
  237. }
  238. TEST_VERIFY (!ferror (fp));
  239. __resolv_context_put (ctx);
  240. }
  241. /* Parameters of one test case. */
  242. struct test_case
  243. {
  244. /* A short, descriptive name of the test. */
  245. const char *name;
  246. /* The contents of the /etc/resolv.conf file. */
  247. const char *conf;
  248. /* The expected output from print_resp. */
  249. const char *expected;
  250. /* Setting for the LOCALDOMAIN environment variable. NULL if the
  251. variable is not to be set. */
  252. const char *localdomain;
  253. /* Setting for the RES_OPTIONS environment variable. NULL if the
  254. variable is not to be set. */
  255. const char *res_options;
  256. /* Override the system host name. NULL means that no change is made
  257. and the default is used (test_hostname). */
  258. const char *hostname;
  259. };
  260. enum test_init
  261. {
  262. test_init,
  263. test_ninit,
  264. test_mkquery,
  265. test_gethostbyname,
  266. test_getaddrinfo,
  267. test_init_method_last = test_getaddrinfo
  268. };
  269. static const char *const test_init_names[] =
  270. {
  271. [test_init] = "res_init",
  272. [test_ninit] = "res_ninit",
  273. [test_mkquery] = "res_mkquery",
  274. [test_gethostbyname] = "gethostbyname",
  275. [test_getaddrinfo] = "getaddrinfo",
  276. };
  277. /* Closure argument for run_res_init. */
  278. struct test_context
  279. {
  280. enum test_init init;
  281. const struct test_case *t;
  282. };
  283. static void
  284. setup_nss_dns_and_chroot (void)
  285. {
  286. /* Load nss_dns outside of the chroot. */
  287. if (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) == NULL)
  288. FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
  289. xchroot (chroot_env->path_chroot);
  290. /* Force the use of nss_dns. */
  291. __nss_configure_lookup ("hosts", "dns");
  292. }
  293. /* Run res_ninit or res_init in a subprocess and dump the parsed
  294. resolver state to standard output. */
  295. static void
  296. run_res_init (void *closure)
  297. {
  298. struct test_context *ctx = closure;
  299. TEST_VERIFY (getenv ("LOCALDOMAIN") == NULL);
  300. TEST_VERIFY (getenv ("RES_OPTIONS") == NULL);
  301. if (ctx->t->localdomain != NULL)
  302. setenv ("LOCALDOMAIN", ctx->t->localdomain, 1);
  303. if (ctx->t->res_options != NULL)
  304. setenv ("RES_OPTIONS", ctx->t->res_options, 1);
  305. if (ctx->t->hostname != NULL)
  306. {
  307. #ifdef CLONE_NEWUTS
  308. /* This test needs its own namespace, to avoid changing the host
  309. name for the parent, too. */
  310. TEST_VERIFY_EXIT (unshare (CLONE_NEWUTS) == 0);
  311. if (sethostname (ctx->t->hostname, strlen (ctx->t->hostname)) != 0)
  312. FAIL_EXIT1 ("sethostname (\"%s\"): %m", ctx->t->hostname);
  313. #else
  314. FAIL_UNSUPPORTED ("clone (CLONE_NEWUTS) not supported");
  315. #endif
  316. }
  317. switch (ctx->init)
  318. {
  319. case test_init:
  320. xchroot (chroot_env->path_chroot);
  321. TEST_VERIFY (res_init () == 0);
  322. print_resp (stdout, &_res);
  323. return;
  324. case test_ninit:
  325. xchroot (chroot_env->path_chroot);
  326. res_state resp = xmalloc (sizeof (*resp));
  327. memset (resp, 0, sizeof (*resp));
  328. TEST_VERIFY (res_ninit (resp) == 0);
  329. print_resp (stdout, resp);
  330. res_nclose (resp);
  331. free (resp);
  332. return;
  333. case test_mkquery:
  334. xchroot (chroot_env->path_chroot);
  335. unsigned char buf[512];
  336. TEST_VERIFY (res_mkquery (QUERY, "www.example",
  337. C_IN, ns_t_a, NULL, 0,
  338. NULL, buf, sizeof (buf)) > 0);
  339. print_resp (stdout, &_res);
  340. return;
  341. case test_gethostbyname:
  342. setup_nss_dns_and_chroot ();
  343. /* Trigger implicit initialization of the _res structure. The
  344. actual lookup result is immaterial. */
  345. (void )gethostbyname ("www.example");
  346. print_resp (stdout, &_res);
  347. return;
  348. case test_getaddrinfo:
  349. setup_nss_dns_and_chroot ();
  350. /* Trigger implicit initialization of the _res structure. The
  351. actual lookup result is immaterial. */
  352. struct addrinfo *ai;
  353. (void) getaddrinfo ("www.example", NULL, NULL, &ai);
  354. print_resp (stdout, &_res);
  355. return;
  356. }
  357. FAIL_EXIT1 ("invalid init method %d", ctx->init);
  358. }
  359. #if TEST_THREAD
  360. /* Helper function which calls run_res_init from a thread. */
  361. static void *
  362. run_res_init_thread_func (void *closure)
  363. {
  364. run_res_init (closure);
  365. return NULL;
  366. }
  367. /* Variant of res_run_init which runs the function on a non-main
  368. thread. */
  369. static void
  370. run_res_init_on_thread (void *closure)
  371. {
  372. xpthread_join (xpthread_create (NULL, run_res_init_thread_func, closure));
  373. }
  374. #endif /* TEST_THREAD */
  375. struct test_case test_cases[] =
  376. {
  377. {.name = "empty file",
  378. .conf = "",
  379. .expected = "search example.com\n"
  380. "; search[0]: example.com\n"
  381. "nameserver 127.0.0.1\n"
  382. "; nameserver[0]: [127.0.0.1]:53\n"
  383. },
  384. {.name = "empty file, no-dot hostname",
  385. .conf = "",
  386. .expected = "nameserver 127.0.0.1\n"
  387. "; nameserver[0]: [127.0.0.1]:53\n",
  388. .hostname = "example",
  389. },
  390. {.name = "empty file with LOCALDOMAIN",
  391. .conf = "",
  392. .expected = "search example.net\n"
  393. "; search[0]: example.net\n"
  394. "nameserver 127.0.0.1\n"
  395. "; nameserver[0]: [127.0.0.1]:53\n",
  396. .localdomain = "example.net",
  397. },
  398. {.name = "empty file with RES_OPTIONS",
  399. .conf = "",
  400. .expected = "options attempts:5 edns0\n"
  401. "search example.com\n"
  402. "; search[0]: example.com\n"
  403. "nameserver 127.0.0.1\n"
  404. "; nameserver[0]: [127.0.0.1]:53\n",
  405. .res_options = "edns0 attempts:5",
  406. },
  407. {.name = "empty file with RES_OPTIONS and LOCALDOMAIN",
  408. .conf = "",
  409. .expected = "options attempts:5 edns0\n"
  410. "search example.org\n"
  411. "; search[0]: example.org\n"
  412. "nameserver 127.0.0.1\n"
  413. "; nameserver[0]: [127.0.0.1]:53\n",
  414. .localdomain = "example.org",
  415. .res_options = "edns0 attempts:5",
  416. },
  417. {.name = "basic",
  418. .conf = "search corp.example.com example.com\n"
  419. "nameserver 192.0.2.1\n",
  420. .expected = "search corp.example.com example.com\n"
  421. "; search[0]: corp.example.com\n"
  422. "; search[1]: example.com\n"
  423. "nameserver 192.0.2.1\n"
  424. "; nameserver[0]: [192.0.2.1]:53\n"
  425. },
  426. {.name = "basic with no-dot hostname",
  427. .conf = "search corp.example.com example.com\n"
  428. "nameserver 192.0.2.1\n",
  429. .expected = "search corp.example.com example.com\n"
  430. "; search[0]: corp.example.com\n"
  431. "; search[1]: example.com\n"
  432. "nameserver 192.0.2.1\n"
  433. "; nameserver[0]: [192.0.2.1]:53\n",
  434. .hostname = "example",
  435. },
  436. {.name = "basic no-reload",
  437. .conf = "options no-reload\n"
  438. "search corp.example.com example.com\n"
  439. "nameserver 192.0.2.1\n",
  440. .expected = "options no-reload\n"
  441. "search corp.example.com example.com\n"
  442. "; search[0]: corp.example.com\n"
  443. "; search[1]: example.com\n"
  444. "nameserver 192.0.2.1\n"
  445. "; nameserver[0]: [192.0.2.1]:53\n"
  446. },
  447. {.name = "basic no-reload via RES_OPTIONS",
  448. .conf = "search corp.example.com example.com\n"
  449. "nameserver 192.0.2.1\n",
  450. .expected = "options no-reload\n"
  451. "search corp.example.com example.com\n"
  452. "; search[0]: corp.example.com\n"
  453. "; search[1]: example.com\n"
  454. "nameserver 192.0.2.1\n"
  455. "; nameserver[0]: [192.0.2.1]:53\n",
  456. .res_options = "no-reload"
  457. },
  458. {.name = "whitespace",
  459. .conf = "# This test covers comment and whitespace processing "
  460. " (trailing whitespace,\n"
  461. "# missing newline at end of file).\n"
  462. "\n"
  463. ";search commented out\n"
  464. "search corp.example.com\texample.com \n"
  465. "#nameserver 192.0.2.3\n"
  466. "nameserver 192.0.2.1 \n"
  467. "nameserver 192.0.2.2", /* No \n at end of file. */
  468. .expected = "search corp.example.com example.com\n"
  469. "; search[0]: corp.example.com\n"
  470. "; search[1]: example.com\n"
  471. "nameserver 192.0.2.1\n"
  472. "nameserver 192.0.2.2\n"
  473. "; nameserver[0]: [192.0.2.1]:53\n"
  474. "; nameserver[1]: [192.0.2.2]:53\n"
  475. },
  476. {.name = "domain",
  477. .conf = "domain example.net\n"
  478. "nameserver 192.0.2.1\n",
  479. .expected = "search example.net\n"
  480. "; search[0]: example.net\n"
  481. "nameserver 192.0.2.1\n"
  482. "; nameserver[0]: [192.0.2.1]:53\n"
  483. },
  484. {.name = "domain space",
  485. .conf = "domain example.net \n"
  486. "nameserver 192.0.2.1\n",
  487. .expected = "search example.net\n"
  488. "; search[0]: example.net\n"
  489. "nameserver 192.0.2.1\n"
  490. "; nameserver[0]: [192.0.2.1]:53\n"
  491. },
  492. {.name = "domain tab",
  493. .conf = "domain example.net\t\n"
  494. "nameserver 192.0.2.1\n",
  495. .expected = "search example.net\n"
  496. "; search[0]: example.net\n"
  497. "nameserver 192.0.2.1\n"
  498. "; nameserver[0]: [192.0.2.1]:53\n"
  499. },
  500. {.name = "domain override",
  501. .conf = "search example.com example.org\n"
  502. "nameserver 192.0.2.1\n"
  503. "domain example.net", /* No \n at end of file. */
  504. .expected = "search example.net\n"
  505. "; search[0]: example.net\n"
  506. "nameserver 192.0.2.1\n"
  507. "; nameserver[0]: [192.0.2.1]:53\n"
  508. },
  509. {.name = "option values, multiple servers",
  510. .conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
  511. "domain example.net\n"
  512. ";domain comment\n"
  513. "search corp.example.com\texample.com\n"
  514. "nameserver 192.0.2.1\n"
  515. "nameserver ::1\n"
  516. "nameserver 192.0.2.2\n",
  517. .expected = "options ndots:3 timeout:19 attempts:5 inet6 edns0\n"
  518. "search corp.example.com example.com\n"
  519. "; search[0]: corp.example.com\n"
  520. "; search[1]: example.com\n"
  521. "nameserver 192.0.2.1\n"
  522. "nameserver ::1\n"
  523. "nameserver 192.0.2.2\n"
  524. "; nameserver[0]: [192.0.2.1]:53\n"
  525. "; nameserver[1]: [::1]:53\n"
  526. "; nameserver[2]: [192.0.2.2]:53\n"
  527. },
  528. {.name = "out-of-range option vales",
  529. .conf = "options use-vc timeout:999 attempts:999 ndots:99\n"
  530. "search example.com\n",
  531. .expected = "options ndots:15 timeout:30 attempts:5 use-vc\n"
  532. "search example.com\n"
  533. "; search[0]: example.com\n"
  534. "nameserver 127.0.0.1\n"
  535. "; nameserver[0]: [127.0.0.1]:53\n"
  536. },
  537. {.name = "repeated directives",
  538. .conf = "options ndots:3 use-vc\n"
  539. "options edns0 ndots:2\n"
  540. "domain corp.example\n"
  541. "search example.net corp.example.com example.com\n"
  542. "search example.org\n"
  543. "search\n",
  544. .expected = "options ndots:2 use-vc edns0\n"
  545. "search example.org\n"
  546. "; search[0]: example.org\n"
  547. "nameserver 127.0.0.1\n"
  548. "; nameserver[0]: [127.0.0.1]:53\n"
  549. },
  550. {.name = "many name servers, sortlist",
  551. .conf = "options single-request\n"
  552. "search example.org example.com example.net corp.example.com\n"
  553. "sortlist 192.0.2.0/255.255.255.0\n"
  554. "nameserver 192.0.2.1\n"
  555. "nameserver 192.0.2.2\n"
  556. "nameserver 192.0.2.3\n"
  557. "nameserver 192.0.2.4\n"
  558. "nameserver 192.0.2.5\n"
  559. "nameserver 192.0.2.6\n"
  560. "nameserver 192.0.2.7\n"
  561. "nameserver 192.0.2.8\n",
  562. .expected = "options single-request\n"
  563. "search example.org example.com example.net corp.example.com\n"
  564. "; search[0]: example.org\n"
  565. "; search[1]: example.com\n"
  566. "; search[2]: example.net\n"
  567. "; search[3]: corp.example.com\n"
  568. "sortlist 192.0.2.0/255.255.255.0\n"
  569. "nameserver 192.0.2.1\n"
  570. "nameserver 192.0.2.2\n"
  571. "nameserver 192.0.2.3\n"
  572. "; nameserver[0]: [192.0.2.1]:53\n"
  573. "; nameserver[1]: [192.0.2.2]:53\n"
  574. "; nameserver[2]: [192.0.2.3]:53\n"
  575. "; nameserver[3]: [192.0.2.4]:53\n"
  576. "; nameserver[4]: [192.0.2.5]:53\n"
  577. "; nameserver[5]: [192.0.2.6]:53\n"
  578. "; nameserver[6]: [192.0.2.7]:53\n"
  579. "; nameserver[7]: [192.0.2.8]:53\n"
  580. },
  581. {.name = "IPv4 and IPv6 nameservers",
  582. .conf = "options single-request\n"
  583. "search example.org example.com example.net corp.example.com"
  584. " legacy.example.com\n"
  585. "sortlist 192.0.2.0\n"
  586. "nameserver 192.0.2.1\n"
  587. "nameserver 2001:db8::2\n"
  588. "nameserver 192.0.2.3\n"
  589. "nameserver 2001:db8::4\n"
  590. "nameserver 192.0.2.5\n"
  591. "nameserver 2001:db8::6\n"
  592. "nameserver 192.0.2.7\n"
  593. "nameserver 2001:db8::8\n",
  594. .expected = "options single-request\n"
  595. "search example.org example.com example.net corp.example.com"
  596. " legacy.example.com\n"
  597. "; search[0]: example.org\n"
  598. "; search[1]: example.com\n"
  599. "; search[2]: example.net\n"
  600. "; search[3]: corp.example.com\n"
  601. "; search[4]: legacy.example.com\n"
  602. "sortlist 192.0.2.0/255.255.255.0\n"
  603. "nameserver 192.0.2.1\n"
  604. "nameserver 2001:db8::2\n"
  605. "nameserver 192.0.2.3\n"
  606. "; nameserver[0]: [192.0.2.1]:53\n"
  607. "; nameserver[1]: [2001:db8::2]:53\n"
  608. "; nameserver[2]: [192.0.2.3]:53\n"
  609. "; nameserver[3]: [2001:db8::4]:53\n"
  610. "; nameserver[4]: [192.0.2.5]:53\n"
  611. "; nameserver[5]: [2001:db8::6]:53\n"
  612. "; nameserver[6]: [192.0.2.7]:53\n"
  613. "; nameserver[7]: [2001:db8::8]:53\n",
  614. },
  615. {.name = "garbage after nameserver",
  616. .conf = "nameserver 192.0.2.1 garbage\n"
  617. "nameserver 192.0.2.2:5353\n"
  618. "nameserver 192.0.2.3 5353\n",
  619. .expected = "search example.com\n"
  620. "; search[0]: example.com\n"
  621. "nameserver 192.0.2.1\n"
  622. "nameserver 192.0.2.3\n"
  623. "; nameserver[0]: [192.0.2.1]:53\n"
  624. "; nameserver[1]: [192.0.2.3]:53\n"
  625. },
  626. {.name = "RES_OPTIONS is cummulative",
  627. .conf = "options timeout:7 ndots:2 use-vc\n"
  628. "nameserver 192.0.2.1\n",
  629. .expected = "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
  630. "search example.com\n"
  631. "; search[0]: example.com\n"
  632. "nameserver 192.0.2.1\n"
  633. "; nameserver[0]: [192.0.2.1]:53\n",
  634. .res_options = "attempts:5 ndots:3 edns0 ",
  635. },
  636. {.name = "many search list entries (bug 19569)",
  637. .conf = "nameserver 192.0.2.1\n"
  638. "search corp.example.com support.example.com"
  639. " community.example.org wan.example.net vpn.example.net"
  640. " example.com example.org example.net\n",
  641. .expected = "search corp.example.com support.example.com"
  642. " community.example.org wan.example.net vpn.example.net example.com\n"
  643. "; search[0]: corp.example.com\n"
  644. "; search[1]: support.example.com\n"
  645. "; search[2]: community.example.org\n"
  646. "; search[3]: wan.example.net\n"
  647. "; search[4]: vpn.example.net\n"
  648. "; search[5]: example.com\n"
  649. "; search[6]: example.org\n"
  650. "; search[7]: example.net\n"
  651. "nameserver 192.0.2.1\n"
  652. "; nameserver[0]: [192.0.2.1]:53\n"
  653. },
  654. {.name = "very long search list entries (bug 21475)",
  655. .conf = "nameserver 192.0.2.1\n"
  656. "search example.com "
  657. #define H63 "this-host-name-is-longer-than-yours-yes-I-really-really-mean-it"
  658. #define D63 "this-domain-name-is-as-long-as-the-previous-name--63-characters"
  659. " " H63 "." D63 ".example.org"
  660. " " H63 "." D63 ".example.net\n",
  661. .expected = "search example.com " H63 "." D63 ".example.org\n"
  662. "; search[0]: example.com\n"
  663. "; search[1]: " H63 "." D63 ".example.org\n"
  664. "; search[2]: " H63 "." D63 ".example.net\n"
  665. #undef H63
  666. #undef D63
  667. "nameserver 192.0.2.1\n"
  668. "; nameserver[0]: [192.0.2.1]:53\n"
  669. },
  670. { NULL }
  671. };
  672. /* Run the indicated test case. This function assumes that the chroot
  673. contents has already been set up. */
  674. static void
  675. test_file_contents (const struct test_case *t)
  676. {
  677. #if TEST_THREAD
  678. for (int do_thread = 0; do_thread < 2; ++do_thread)
  679. #endif
  680. for (int init_method = 0; init_method <= test_init_method_last;
  681. ++init_method)
  682. {
  683. if (test_verbose > 0)
  684. printf ("info: testing init method %s\n",
  685. test_init_names[init_method]);
  686. struct test_context ctx = { .init = init_method, .t = t };
  687. void (*func) (void *) = run_res_init;
  688. #if TEST_THREAD
  689. if (do_thread)
  690. func = run_res_init_on_thread;
  691. #endif
  692. struct support_capture_subprocess proc
  693. = support_capture_subprocess (func, &ctx);
  694. if (strcmp (proc.out.buffer, t->expected) != 0)
  695. {
  696. support_record_failure ();
  697. printf ("error: output mismatch for %s (init method %s)\n",
  698. t->name, test_init_names[init_method]);
  699. support_run_diff ("expected", t->expected,
  700. "actual", proc.out.buffer);
  701. }
  702. support_capture_subprocess_check (&proc, t->name, 0,
  703. sc_allow_stdout);
  704. support_capture_subprocess_free (&proc);
  705. }
  706. }
  707. /* Special tests which do not follow the general pattern. */
  708. enum { special_tests_count = 11 };
  709. /* Implementation of special tests. */
  710. static void
  711. special_test_callback (void *closure)
  712. {
  713. unsigned int *test_indexp = closure;
  714. unsigned test_index = *test_indexp;
  715. TEST_VERIFY (test_index < special_tests_count);
  716. if (test_verbose > 0)
  717. printf ("info: special test %u\n", test_index);
  718. xchroot (chroot_env->path_chroot);
  719. switch (test_index)
  720. {
  721. case 0:
  722. case 1:
  723. /* Second res_init with missing or empty file preserves
  724. flags. */
  725. if (test_index == 1)
  726. TEST_VERIFY (unlink (_PATH_RESCONF) == 0);
  727. _res.options = RES_USE_EDNS0;
  728. TEST_VERIFY (res_init () == 0);
  729. /* First res_init clears flag. */
  730. TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
  731. _res.options |= RES_USE_EDNS0;
  732. TEST_VERIFY (res_init () == 0);
  733. /* Second res_init preserves flag. */
  734. TEST_VERIFY (_res.options & RES_USE_EDNS0);
  735. if (test_index == 1)
  736. /* Restore empty file. */
  737. support_write_file_string (_PATH_RESCONF, "");
  738. break;
  739. case 2:
  740. /* Second res_init is cumulative. */
  741. support_write_file_string (_PATH_RESCONF,
  742. "options rotate\n"
  743. "nameserver 192.0.2.1\n");
  744. _res.options = RES_USE_EDNS0;
  745. TEST_VERIFY (res_init () == 0);
  746. /* First res_init clears flag. */
  747. TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
  748. /* And sets RES_ROTATE. */
  749. TEST_VERIFY (_res.options & RES_ROTATE);
  750. _res.options |= RES_USE_EDNS0;
  751. TEST_VERIFY (res_init () == 0);
  752. /* Second res_init preserves flag. */
  753. TEST_VERIFY (_res.options & RES_USE_EDNS0);
  754. TEST_VERIFY (_res.options & RES_ROTATE);
  755. /* Reloading the configuration does not clear the explicitly set
  756. flag. */
  757. support_write_file_string (_PATH_RESCONF,
  758. "nameserver 192.0.2.1\n"
  759. "nameserver 192.0.2.2\n");
  760. TEST_VERIFY (res_init () == 0);
  761. TEST_VERIFY (_res.nscount == 2);
  762. TEST_VERIFY (_res.options & RES_USE_EDNS0);
  763. /* Whether RES_ROTATE (originally in resolv.conf, now removed)
  764. should be preserved is subject to debate. See bug 21701. */
  765. /* TEST_VERIFY (!(_res.options & RES_ROTATE)); */
  766. break;
  767. case 3:
  768. case 4:
  769. case 5:
  770. case 6:
  771. support_write_file_string (_PATH_RESCONF,
  772. "options edns0\n"
  773. "nameserver 192.0.2.1\n");
  774. goto reload_tests;
  775. case 7: /* 7 and the following tests are with no-reload. */
  776. case 8:
  777. case 9:
  778. case 10:
  779. support_write_file_string (_PATH_RESCONF,
  780. "options edns0 no-reload\n"
  781. "nameserver 192.0.2.1\n");
  782. /* Fall through. */
  783. reload_tests:
  784. for (int iteration = 0; iteration < 2; ++iteration)
  785. {
  786. switch (test_index)
  787. {
  788. case 3:
  789. case 7:
  790. TEST_VERIFY (res_init () == 0);
  791. break;
  792. case 4:
  793. case 8:
  794. {
  795. unsigned char buf[512];
  796. TEST_VERIFY
  797. (res_mkquery (QUERY, test_hostname, C_IN, T_A,
  798. NULL, 0, NULL, buf, sizeof (buf)) > 0);
  799. }
  800. break;
  801. case 5:
  802. case 9:
  803. gethostbyname (test_hostname);
  804. break;
  805. case 6:
  806. case 10:
  807. {
  808. struct addrinfo *ai;
  809. (void) getaddrinfo (test_hostname, NULL, NULL, &ai);
  810. }
  811. break;
  812. }
  813. /* test_index == 7 is res_init and performs a reload even
  814. with no-reload. */
  815. if (iteration == 0 || test_index > 7)
  816. {
  817. TEST_VERIFY (_res.options & RES_USE_EDNS0);
  818. TEST_VERIFY (!(_res.options & RES_ROTATE));
  819. if (test_index < 7)
  820. TEST_VERIFY (!(_res.options & RES_NORELOAD));
  821. else
  822. TEST_VERIFY (_res.options & RES_NORELOAD);
  823. TEST_VERIFY (_res.nscount == 1);
  824. /* File change triggers automatic reloading. */
  825. support_write_file_string (_PATH_RESCONF,
  826. "options rotate\n"
  827. "nameserver 192.0.2.1\n"
  828. "nameserver 192.0.2.2\n");
  829. }
  830. else
  831. {
  832. if (test_index != 3 && test_index != 7)
  833. /* test_index 3, 7 are res_init; this function does
  834. not reset flags. See bug 21701. */
  835. TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
  836. TEST_VERIFY (_res.options & RES_ROTATE);
  837. TEST_VERIFY (_res.nscount == 2);
  838. }
  839. }
  840. break;
  841. }
  842. }
  843. #if TEST_THREAD
  844. /* Helper function which calls special_test_callback from a
  845. thread. */
  846. static void *
  847. special_test_thread_func (void *closure)
  848. {
  849. special_test_callback (closure);
  850. return NULL;
  851. }
  852. /* Variant of special_test_callback which runs the function on a
  853. non-main thread. */
  854. static void
  855. run_special_test_on_thread (void *closure)
  856. {
  857. xpthread_join (xpthread_create (NULL, special_test_thread_func, closure));
  858. }
  859. #endif /* TEST_THREAD */
  860. /* Perform the requested special test in a subprocess using
  861. special_test_callback. */
  862. static void
  863. special_test (unsigned int test_index)
  864. {
  865. #if TEST_THREAD
  866. for (int do_thread = 0; do_thread < 2; ++do_thread)
  867. #endif
  868. {
  869. void (*func) (void *) = special_test_callback;
  870. #if TEST_THREAD
  871. if (do_thread)
  872. func = run_special_test_on_thread;
  873. #endif
  874. struct support_capture_subprocess proc
  875. = support_capture_subprocess (func, &test_index);
  876. char *test_name = xasprintf ("special test %u", test_index);
  877. if (strcmp (proc.out.buffer, "") != 0)
  878. {
  879. support_record_failure ();
  880. printf ("error: output mismatch for %s\n", test_name);
  881. support_run_diff ("expected", "",
  882. "actual", proc.out.buffer);
  883. }
  884. support_capture_subprocess_check (&proc, test_name, 0, sc_allow_stdout);
  885. free (test_name);
  886. support_capture_subprocess_free (&proc);
  887. }
  888. }
  889. /* Dummy DNS server. It ensures that the probe queries sent by
  890. gethostbyname and getaddrinfo receive a reply even if the system
  891. applies a very strict rate limit to localhost. */
  892. static pid_t
  893. start_dummy_server (void)
  894. {
  895. int server_socket = xsocket (AF_INET, SOCK_DGRAM, 0);
  896. {
  897. struct sockaddr_in sin =
  898. {
  899. .sin_family = AF_INET,
  900. .sin_addr = { .s_addr = htonl (INADDR_LOOPBACK) },
  901. .sin_port = htons (53),
  902. };
  903. int ret = bind (server_socket, (struct sockaddr *) &sin, sizeof (sin));
  904. if (ret < 0)
  905. {
  906. if (errno == EACCES)
  907. /* The port is reserved, which means we cannot start the
  908. server. */
  909. return -1;
  910. FAIL_EXIT1 ("cannot bind socket to port 53: %m");
  911. }
  912. }
  913. pid_t pid = xfork ();
  914. if (pid == 0)
  915. {
  916. /* Child process. Echo back queries as SERVFAIL responses. */
  917. while (true)
  918. {
  919. union
  920. {
  921. HEADER header;
  922. unsigned char bytes[512];
  923. } packet;
  924. struct sockaddr_in sin;
  925. socklen_t sinlen = sizeof (sin);
  926. ssize_t ret = recvfrom
  927. (server_socket, &packet, sizeof (packet),
  928. MSG_NOSIGNAL, (struct sockaddr *) &sin, &sinlen);
  929. if (ret < 0)
  930. FAIL_EXIT1 ("recvfrom on fake server socket: %m");
  931. if (ret > sizeof (HEADER))
  932. {
  933. /* Turn the query into a SERVFAIL response. */
  934. packet.header.qr = 1;
  935. packet.header.rcode = ns_r_servfail;
  936. /* Send the response. */
  937. ret = sendto (server_socket, &packet, ret,
  938. MSG_NOSIGNAL, (struct sockaddr *) &sin, sinlen);
  939. if (ret < 0)
  940. /* The peer may have closed socket prematurely, so
  941. this is not an error. */
  942. printf ("warning: sending DNS server reply: %m\n");
  943. }
  944. }
  945. }
  946. /* In the parent, close the socket. */
  947. xclose (server_socket);
  948. return pid;
  949. }
  950. static int
  951. do_test (void)
  952. {
  953. support_become_root ();
  954. support_enter_network_namespace ();
  955. if (!support_in_uts_namespace () || !support_can_chroot ())
  956. return EXIT_UNSUPPORTED;
  957. /* We are in an UTS namespace, so we can set the host name without
  958. altering the state of the entire system. */
  959. if (sethostname (test_hostname, strlen (test_hostname)) != 0)
  960. FAIL_EXIT1 ("sethostname: %m");
  961. /* These environment variables affect resolv.conf parsing. */
  962. unsetenv ("LOCALDOMAIN");
  963. unsetenv ("RES_OPTIONS");
  964. /* Ensure that the chroot setup worked. */
  965. {
  966. struct support_capture_subprocess proc
  967. = support_capture_subprocess (check_chroot_working, NULL);
  968. support_capture_subprocess_check (&proc, "chroot", 0, sc_allow_none);
  969. support_capture_subprocess_free (&proc);
  970. }
  971. pid_t server = start_dummy_server ();
  972. for (size_t i = 0; test_cases[i].name != NULL; ++i)
  973. {
  974. if (test_verbose > 0)
  975. printf ("info: running test: %s\n", test_cases[i].name);
  976. TEST_VERIFY (test_cases[i].conf != NULL);
  977. TEST_VERIFY (test_cases[i].expected != NULL);
  978. support_write_file_string (chroot_env->path_resolv_conf,
  979. test_cases[i].conf);
  980. test_file_contents (&test_cases[i]);
  981. /* The expected output from the empty file test is used for
  982. further tests. */
  983. if (test_cases[i].conf[0] == '\0')
  984. {
  985. if (test_verbose > 0)
  986. printf ("info: special test: missing file\n");
  987. TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
  988. test_file_contents (&test_cases[i]);
  989. if (test_verbose > 0)
  990. printf ("info: special test: dangling symbolic link\n");
  991. TEST_VERIFY (symlink ("does-not-exist", chroot_env->path_resolv_conf) == 0);
  992. test_file_contents (&test_cases[i]);
  993. TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
  994. if (test_verbose > 0)
  995. printf ("info: special test: unreadable file\n");
  996. support_write_file_string (chroot_env->path_resolv_conf, "");
  997. TEST_VERIFY (chmod (chroot_env->path_resolv_conf, 0) == 0);
  998. test_file_contents (&test_cases[i]);
  999. /* Restore the empty file. */
  1000. TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
  1001. support_write_file_string (chroot_env->path_resolv_conf, "");
  1002. }
  1003. }
  1004. /* The tests which do not follow a regular pattern. */
  1005. for (unsigned int test_index = 0;
  1006. test_index < special_tests_count; ++test_index)
  1007. special_test (test_index);
  1008. if (server > 0)
  1009. {
  1010. if (kill (server, SIGTERM) < 0)
  1011. FAIL_EXIT1 ("could not terminate server process: %m");
  1012. xwaitpid (server, NULL, 0);
  1013. }
  1014. support_chroot_free (chroot_env);
  1015. return 0;
  1016. }
  1017. #define PREPARE prepare
  1018. #include <support/test-driver.c>