tst-resolv-threads.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /* Test basic nss_dns functionality with multiple threads.
  2. Copyright (C) 2016-2026 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. <https://www.gnu.org/licenses/>. */
  15. /* Unlike tst-resolv-basic, this test does not overwrite the _res
  16. structure and relies on namespaces to achieve the redirection to
  17. the test servers with a custom /etc/resolv.conf file. */
  18. #include <dlfcn.h>
  19. #include <errno.h>
  20. #include <gnu/lib-names.h>
  21. #include <netdb.h>
  22. #include <resolv/resolv-internal.h>
  23. #include <resolv/resolv_context.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <support/check.h>
  28. #include <support/namespace.h>
  29. #include <support/resolv_test.h>
  30. #include <support/support.h>
  31. #include <support/temp_file.h>
  32. #include <support/test-driver.h>
  33. #include <support/xthread.h>
  34. #include <support/xunistd.h>
  35. /* Each client thread sends this many queries. */
  36. enum { queries_per_thread = 500 };
  37. /* Return a small positive number identifying this thread. */
  38. static int
  39. get_thread_number (void)
  40. {
  41. static int __thread local;
  42. if (local != 0)
  43. return local;
  44. static int global = 1;
  45. local = __atomic_fetch_add (&global, 1, __ATOMIC_RELAXED);
  46. return local;
  47. }
  48. static void
  49. response (const struct resolv_response_context *ctx,
  50. struct resolv_response_builder *b,
  51. const char *qname, uint16_t qclass, uint16_t qtype)
  52. {
  53. TEST_VERIFY_EXIT (qname != NULL);
  54. int counter = 0;
  55. int thread = 0;
  56. int dummy = 0;
  57. TEST_VERIFY (sscanf (qname, "counter%d.thread%d.example.com%n",
  58. &counter, &thread, &dummy) == 2);
  59. TEST_VERIFY (dummy > 0);
  60. struct resolv_response_flags flags = { 0 };
  61. resolv_response_init (b, flags);
  62. resolv_response_add_question (b, qname, qclass, qtype);
  63. resolv_response_section (b, ns_s_an);
  64. resolv_response_open_record (b, qname, qclass, qtype, 0);
  65. switch (qtype)
  66. {
  67. case T_A:
  68. {
  69. char ipv4[4] = {10, 0, counter, thread};
  70. resolv_response_add_data (b, &ipv4, sizeof (ipv4));
  71. }
  72. break;
  73. case T_AAAA:
  74. {
  75. char ipv6[16]
  76. = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0,
  77. counter, 0, thread, 0, 0};
  78. resolv_response_add_data (b, &ipv6, sizeof (ipv6));
  79. }
  80. break;
  81. default:
  82. support_record_failure ();
  83. printf ("error: unexpected QTYPE: %s/%u/%u\n",
  84. qname, qclass, qtype);
  85. }
  86. resolv_response_close_record (b);
  87. }
  88. /* Check that the resolver configuration for this thread has an
  89. extended resolver configuration. */
  90. static void
  91. check_have_conf (void)
  92. {
  93. struct resolv_context *ctx = __resolv_context_get ();
  94. TEST_VERIFY_EXIT (ctx != NULL);
  95. TEST_VERIFY (ctx->conf != NULL);
  96. __resolv_context_put (ctx);
  97. }
  98. /* Verify that E matches the expected response for FAMILY and
  99. COUNTER. */
  100. static void
  101. check_hostent (const char *caller, const char *function, const char *qname,
  102. int ret, struct hostent *e, int family, int counter)
  103. {
  104. if (ret != 0)
  105. {
  106. errno = ret;
  107. support_record_failure ();
  108. printf ("error: %s: %s for %s failed: %m\n", caller, function, qname);
  109. return;
  110. }
  111. TEST_VERIFY_EXIT (e != NULL);
  112. TEST_VERIFY (strcmp (qname, e->h_name) == 0);
  113. TEST_VERIFY (e->h_addrtype == family);
  114. TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL);
  115. TEST_VERIFY (e->h_addr_list[1] == NULL);
  116. switch (family)
  117. {
  118. case AF_INET:
  119. {
  120. char addr[4] = {10, 0, counter, get_thread_number ()};
  121. TEST_VERIFY (e->h_length == sizeof (addr));
  122. TEST_VERIFY (memcmp (e->h_addr_list[0], addr, sizeof (addr)) == 0);
  123. }
  124. break;
  125. case AF_INET6:
  126. {
  127. char addr[16]
  128. = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
  129. 0, counter, 0, get_thread_number (), 0, 0};
  130. TEST_VERIFY (e->h_length == sizeof (addr));
  131. TEST_VERIFY (memcmp (e->h_addr_list[0], addr, sizeof (addr)) == 0);
  132. }
  133. break;
  134. default:
  135. FAIL_EXIT1 ("%s: invalid address family %d", caller, family);
  136. }
  137. check_have_conf ();
  138. }
  139. /* Check a getaddrinfo result. */
  140. static void
  141. check_addrinfo (const char *caller, const char *qname,
  142. int ret, struct addrinfo *ai, int family, int counter)
  143. {
  144. if (ret != 0)
  145. {
  146. support_record_failure ();
  147. printf ("error: %s: getaddrinfo for %s failed: %s\n",
  148. caller, qname, gai_strerror (ret));
  149. return;
  150. }
  151. TEST_VERIFY_EXIT (ai != NULL);
  152. /* Check that available data matches the requirements. */
  153. bool have_ipv4 = false;
  154. bool have_ipv6 = false;
  155. for (struct addrinfo *p = ai; p != NULL; p = p->ai_next)
  156. {
  157. TEST_VERIFY (p->ai_socktype == SOCK_STREAM);
  158. TEST_VERIFY (p->ai_protocol == IPPROTO_TCP);
  159. TEST_VERIFY_EXIT (p->ai_addr != NULL);
  160. TEST_VERIFY (p->ai_addr->sa_family == p->ai_family);
  161. switch (p->ai_family)
  162. {
  163. case AF_INET:
  164. {
  165. TEST_VERIFY (!have_ipv4);
  166. have_ipv4 = true;
  167. struct sockaddr_in *sa = (struct sockaddr_in *) p->ai_addr;
  168. TEST_VERIFY (p->ai_addrlen == sizeof (*sa));
  169. char addr[4] = {10, 0, counter, get_thread_number ()};
  170. TEST_VERIFY (memcmp (&sa->sin_addr, addr, sizeof (addr)) == 0);
  171. TEST_VERIFY (ntohs (sa->sin_port) == 80);
  172. }
  173. break;
  174. case AF_INET6:
  175. {
  176. TEST_VERIFY (!have_ipv6);
  177. have_ipv6 = true;
  178. struct sockaddr_in6 *sa = (struct sockaddr_in6 *) p->ai_addr;
  179. TEST_VERIFY (p->ai_addrlen == sizeof (*sa));
  180. char addr[16]
  181. = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
  182. 0, counter, 0, get_thread_number (), 0, 0};
  183. TEST_VERIFY (memcmp (&sa->sin6_addr, addr, sizeof (addr)) == 0);
  184. TEST_VERIFY (ntohs (sa->sin6_port) == 80);
  185. }
  186. break;
  187. default:
  188. FAIL_EXIT1 ("%s: invalid address family %d", caller, family);
  189. }
  190. }
  191. switch (family)
  192. {
  193. case AF_INET:
  194. TEST_VERIFY (have_ipv4);
  195. TEST_VERIFY (!have_ipv6);
  196. break;
  197. case AF_INET6:
  198. TEST_VERIFY (!have_ipv4);
  199. TEST_VERIFY (have_ipv6);
  200. break;
  201. case AF_UNSPEC:
  202. TEST_VERIFY (have_ipv4);
  203. TEST_VERIFY (have_ipv6);
  204. break;
  205. default:
  206. FAIL_EXIT1 ("%s: invalid address family %d", caller, family);
  207. }
  208. check_have_conf ();
  209. }
  210. /* This barrier ensures that all test threads begin their work
  211. simultaneously. */
  212. static pthread_barrier_t barrier;
  213. /* Test gethostbyname2_r (if do_2 is false) or gethostbyname2_r with
  214. AF_INET (if do_2 is true). */
  215. static void *
  216. byname (bool do_2)
  217. {
  218. int this_thread = get_thread_number ();
  219. xpthread_barrier_wait (&barrier);
  220. for (int i = 0; i < queries_per_thread; ++i)
  221. {
  222. char qname[100];
  223. snprintf (qname, sizeof (qname), "counter%d.thread%d.example.com",
  224. i, this_thread);
  225. struct hostent storage;
  226. char buf[1000];
  227. struct hostent *e = NULL;
  228. int herrno;
  229. int ret;
  230. if (do_2)
  231. ret = gethostbyname_r (qname, &storage, buf, sizeof (buf),
  232. &e, &herrno);
  233. else
  234. ret = gethostbyname2_r (qname, AF_INET, &storage, buf, sizeof (buf),
  235. &e, &herrno);
  236. check_hostent (__func__, do_2 ? "gethostbyname2_r" : "gethostbyname_r",
  237. qname, ret, e, AF_INET, i);
  238. }
  239. check_have_conf ();
  240. return NULL;
  241. }
  242. /* Test gethostbyname_r. */
  243. static void *
  244. thread_byname (void *closure)
  245. {
  246. return byname (false);
  247. }
  248. /* Test gethostbyname2_r with AF_INET. */
  249. static void *
  250. thread_byname2 (void *closure)
  251. {
  252. return byname (true);
  253. }
  254. /* Test gethostbyname2_r with AF_INET6. */
  255. static void *
  256. thread_byname2_af_inet6 (void *closure)
  257. {
  258. int this_thread = get_thread_number ();
  259. xpthread_barrier_wait (&barrier);
  260. for (int i = 0; i < queries_per_thread; ++i)
  261. {
  262. char qname[100];
  263. snprintf (qname, sizeof (qname), "counter%d.thread%d.example.com",
  264. i, this_thread);
  265. struct hostent storage;
  266. char buf[1000];
  267. struct hostent *e = NULL;
  268. int herrno;
  269. int ret = gethostbyname2_r (qname, AF_INET6, &storage, buf, sizeof (buf),
  270. &e, &herrno);
  271. check_hostent (__func__, "gethostbyname2_r", qname, ret, e, AF_INET6, i);
  272. }
  273. return NULL;
  274. }
  275. /* Run getaddrinfo tests for FAMILY. */
  276. static void *
  277. gai (int family)
  278. {
  279. int this_thread = get_thread_number ();
  280. xpthread_barrier_wait (&barrier);
  281. for (int i = 0; i < queries_per_thread; ++i)
  282. {
  283. char qname[100];
  284. snprintf (qname, sizeof (qname), "counter%d.thread%d.example.com",
  285. i, this_thread);
  286. struct addrinfo hints =
  287. {
  288. .ai_family = family,
  289. .ai_socktype = SOCK_STREAM,
  290. .ai_protocol = IPPROTO_TCP,
  291. };
  292. struct addrinfo *ai;
  293. int ret = getaddrinfo (qname, "80", &hints, &ai);
  294. check_addrinfo (__func__, qname, ret, ai, family, i);
  295. if (ret == 0)
  296. freeaddrinfo (ai);
  297. }
  298. return NULL;
  299. }
  300. /* Test getaddrinfo with AF_INET. */
  301. static void *
  302. thread_gai_inet (void *closure)
  303. {
  304. return gai (AF_INET);
  305. }
  306. /* Test getaddrinfo with AF_INET6. */
  307. static void *
  308. thread_gai_inet6 (void *closure)
  309. {
  310. return gai (AF_INET6);
  311. }
  312. /* Test getaddrinfo with AF_UNSPEC. */
  313. static void *
  314. thread_gai_unspec (void *closure)
  315. {
  316. return gai (AF_UNSPEC);
  317. }
  318. /* Description of the chroot environment used to run the tests. */
  319. static struct support_chroot *chroot_env;
  320. /* Set up the chroot environment. */
  321. static void
  322. prepare (int argc, char **argv)
  323. {
  324. chroot_env = support_chroot_create
  325. ((struct support_chroot_configuration)
  326. {
  327. .resolv_conf =
  328. "search example.com\n"
  329. "nameserver 127.0.0.1\n"
  330. "nameserver 127.0.0.2\n"
  331. "nameserver 127.0.0.3\n",
  332. });
  333. }
  334. static int
  335. do_test (void)
  336. {
  337. support_become_root ();
  338. if (!support_enter_network_namespace ())
  339. return EXIT_UNSUPPORTED;
  340. if (!support_can_chroot ())
  341. return EXIT_UNSUPPORTED;
  342. /* Load the shared object outside of the chroot. */
  343. TEST_VERIFY (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) != NULL);
  344. xchroot (chroot_env->path_chroot);
  345. TEST_VERIFY_EXIT (chdir ("/") == 0);
  346. struct sockaddr_in server_address =
  347. {
  348. .sin_family = AF_INET,
  349. .sin_addr = { .s_addr = htonl (INADDR_LOOPBACK) },
  350. .sin_port = htons (53)
  351. };
  352. const struct sockaddr *server_addresses[1] =
  353. { (const struct sockaddr *) &server_address };
  354. struct resolv_test *aux = resolv_test_start
  355. ((struct resolv_redirect_config)
  356. {
  357. .response_callback = response,
  358. .nscount = 1,
  359. .disable_redirect = true,
  360. .server_address_overrides = server_addresses,
  361. });
  362. enum { thread_count = 6 };
  363. xpthread_barrier_init (&barrier, NULL, thread_count + 1);
  364. pthread_t threads[thread_count];
  365. typedef void *(*thread_func) (void *);
  366. thread_func thread_funcs[thread_count] =
  367. {
  368. thread_byname,
  369. thread_byname2,
  370. thread_byname2_af_inet6,
  371. thread_gai_inet,
  372. thread_gai_inet6,
  373. thread_gai_unspec,
  374. };
  375. for (int i = 0; i < thread_count; ++i)
  376. threads[i] = xpthread_create (NULL, thread_funcs[i], NULL);
  377. xpthread_barrier_wait (&barrier); /* Start the test threads. */
  378. for (int i = 0; i < thread_count; ++i)
  379. xpthread_join (threads[i]);
  380. resolv_test_end (aux);
  381. support_chroot_free (chroot_env);
  382. return 0;
  383. }
  384. #define PREPARE prepare
  385. #include <support/test-driver.c>