tst-nss-files-hosts-multi.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /* Parse /etc/hosts in multi mode with many addresses/aliases.
  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. #include <dlfcn.h>
  16. #include <errno.h>
  17. #include <gnu/lib-names.h>
  18. #include <netdb.h>
  19. #include <nss.h>
  20. #include <stdbool.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <support/check.h>
  24. #include <support/check_nss.h>
  25. #include <support/namespace.h>
  26. #include <support/support.h>
  27. #include <support/test-driver.h>
  28. #include <support/test-driver.h>
  29. #include <support/xmemstream.h>
  30. #include <support/xstdio.h>
  31. #include <support/xunistd.h>
  32. #include <sys/resource.h>
  33. struct support_chroot *chroot_env;
  34. static void
  35. prepare (int argc, char **argv)
  36. {
  37. chroot_env = support_chroot_create
  38. ((struct support_chroot_configuration)
  39. {
  40. .resolv_conf = "",
  41. .hosts = "", /* See write_hosts below. */
  42. .host_conf = "multi on\n",
  43. });
  44. }
  45. /* Create the /etc/hosts file from outside the chroot. */
  46. static void
  47. write_hosts (int count)
  48. {
  49. TEST_VERIFY (count > 0 && count <= 65535);
  50. FILE *fp = xfopen (chroot_env->path_hosts, "w");
  51. fputs ("127.0.0.1 localhost localhost.localdomain\n"
  52. "::1 localhost localhost.localdomain\n",
  53. fp);
  54. for (int i = 0; i < count; ++i)
  55. {
  56. fprintf (fp, "10.4.%d.%d www4.example.com\n",
  57. (i / 256) & 0xff, i & 0xff);
  58. fprintf (fp, "10.46.%d.%d www.example.com\n",
  59. (i / 256) & 0xff, i & 0xff);
  60. fprintf (fp, "192.0.2.1 alias.example.com v4-%d.example.com\n", i);
  61. fprintf (fp, "2001:db8::6:%x www6.example.com\n", i);
  62. fprintf (fp, "2001:db8::46:%x www.example.com\n", i);
  63. fprintf (fp, "2001:db8::1 alias.example.com v6-%d.example.com\n", i);
  64. }
  65. xfclose (fp);
  66. }
  67. /* Parameters of a single test. */
  68. struct test_params
  69. {
  70. const char *name; /* Name to query. */
  71. const char *marker; /* Address marker for the name. */
  72. int count; /* Number of addresses/aliases. */
  73. int family; /* AF_INET, AF_INET_6 or AF_UNSPEC. */
  74. bool canonname; /* True if AI_CANONNAME should be enabled. */
  75. };
  76. /* Expected result of gethostbyname/gethostbyname2. */
  77. static char *
  78. expected_ghbn (const struct test_params *params)
  79. {
  80. TEST_VERIFY (params->family == AF_INET || params->family == AF_INET6);
  81. struct xmemstream expected;
  82. xopen_memstream (&expected);
  83. if (strcmp (params->name, "alias.example.com") == 0)
  84. {
  85. fprintf (expected.out, "name: %s\n", params->name);
  86. char af;
  87. if (params->family == AF_INET)
  88. af = '4';
  89. else
  90. af = '6';
  91. for (int i = 0; i < params->count; ++i)
  92. fprintf (expected.out, "alias: v%c-%d.example.com\n", af, i);
  93. for (int i = 0; i < params->count; ++i)
  94. if (params->family == AF_INET)
  95. fputs ("address: 192.0.2.1\n", expected.out);
  96. else
  97. fputs ("address: 2001:db8::1\n", expected.out);
  98. }
  99. else /* www/www4/www6 name. */
  100. {
  101. bool do_ipv4 = params->family == AF_INET
  102. && strncmp (params->name, "www6", 4) != 0;
  103. bool do_ipv6 = params->family == AF_INET6
  104. && strncmp (params->name, "www4", 4) != 0;
  105. if (do_ipv4 || do_ipv6)
  106. {
  107. fprintf (expected.out, "name: %s\n", params->name);
  108. if (do_ipv4)
  109. for (int i = 0; i < params->count; ++i)
  110. fprintf (expected.out, "address: 10.%s.%d.%d\n",
  111. params->marker, i / 256, i % 256);
  112. if (do_ipv6)
  113. for (int i = 0; i < params->count; ++i)
  114. fprintf (expected.out, "address: 2001:db8::%s:%x\n",
  115. params->marker, i);
  116. }
  117. else
  118. fputs ("error: HOST_NOT_FOUND\n", expected.out);
  119. }
  120. xfclose_memstream (&expected);
  121. return expected.buffer;
  122. }
  123. /* Expected result of getaddrinfo. */
  124. static char *
  125. expected_gai (const struct test_params *params)
  126. {
  127. bool do_ipv4 = false;
  128. bool do_ipv6 = false;
  129. if (params->family == AF_UNSPEC)
  130. do_ipv4 = do_ipv6 = true;
  131. else if (params->family == AF_INET)
  132. do_ipv4 = true;
  133. else if (params->family == AF_INET6)
  134. do_ipv6 = true;
  135. struct xmemstream expected;
  136. xopen_memstream (&expected);
  137. if (strcmp (params->name, "alias.example.com") == 0)
  138. {
  139. if (params->canonname)
  140. fprintf (expected.out,
  141. "flags: AI_CANONNAME\n"
  142. "canonname: %s\n",
  143. params->name);
  144. if (do_ipv4)
  145. for (int i = 0; i < params->count; ++i)
  146. fputs ("address: STREAM/TCP 192.0.2.1 80\n", expected.out);
  147. if (do_ipv6)
  148. for (int i = 0; i < params->count; ++i)
  149. fputs ("address: STREAM/TCP 2001:db8::1 80\n", expected.out);
  150. }
  151. else /* www/www4/www6 name. */
  152. {
  153. if (strncmp (params->name, "www4", 4) == 0)
  154. do_ipv6 = false;
  155. else if (strncmp (params->name, "www6", 4) == 0)
  156. do_ipv4 = false;
  157. /* Otherwise, we have www as the name, so we do both. */
  158. if (do_ipv4 || do_ipv6)
  159. {
  160. if (params->canonname)
  161. fprintf (expected.out,
  162. "flags: AI_CANONNAME\n"
  163. "canonname: %s\n",
  164. params->name);
  165. if (do_ipv4)
  166. for (int i = 0; i < params->count; ++i)
  167. fprintf (expected.out, "address: STREAM/TCP 10.%s.%d.%d 80\n",
  168. params->marker, i / 256, i % 256);
  169. if (do_ipv6)
  170. for (int i = 0; i < params->count; ++i)
  171. fprintf (expected.out,
  172. "address: STREAM/TCP 2001:db8::%s:%x 80\n",
  173. params->marker, i);
  174. }
  175. else
  176. fputs ("error: Name or service not known\n", expected.out);
  177. }
  178. xfclose_memstream (&expected);
  179. return expected.buffer;
  180. }
  181. static void
  182. run_gbhn_gai (struct test_params *params)
  183. {
  184. char *ctx = xasprintf ("name=%s marker=%s count=%d family=%d",
  185. params->name, params->marker, params->count,
  186. params->family);
  187. if (test_verbose > 0)
  188. printf ("info: %s\n", ctx);
  189. /* Check gethostbyname, gethostbyname2. */
  190. if (params->family == AF_INET)
  191. {
  192. char *expected = expected_ghbn (params);
  193. check_hostent (ctx, gethostbyname (params->name), expected);
  194. free (expected);
  195. }
  196. if (params->family != AF_UNSPEC)
  197. {
  198. char *expected = expected_ghbn (params);
  199. check_hostent (ctx, gethostbyname2 (params->name, params->family),
  200. expected);
  201. free (expected);
  202. }
  203. /* Check getaddrinfo. */
  204. for (int do_canonical = 0; do_canonical < 2; ++do_canonical)
  205. {
  206. params->canonname = do_canonical;
  207. char *expected = expected_gai (params);
  208. struct addrinfo hints =
  209. {
  210. .ai_family = params->family,
  211. .ai_socktype = SOCK_STREAM,
  212. .ai_protocol = IPPROTO_TCP,
  213. };
  214. if (do_canonical)
  215. hints.ai_flags |= AI_CANONNAME;
  216. struct addrinfo *ai;
  217. int ret = getaddrinfo (params->name, "80", &hints, &ai);
  218. check_addrinfo (ctx, ai, ret, expected);
  219. if (ret == 0)
  220. freeaddrinfo (ai);
  221. free (expected);
  222. }
  223. free (ctx);
  224. }
  225. /* Callback for the subprocess which runs the test in a chroot. */
  226. static void
  227. subprocess (void *closure)
  228. {
  229. struct test_params *params = closure;
  230. xchroot (chroot_env->path_chroot);
  231. static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC, -1 };
  232. static const char *const names[] =
  233. {
  234. "www.example.com", "www4.example.com", "www6.example.com",
  235. "alias.example.com",
  236. NULL
  237. };
  238. static const char *const names_marker[] = { "46", "4", "6", "" };
  239. for (int family_idx = 0; families[family_idx] >= 0; ++family_idx)
  240. {
  241. params->family = families[family_idx];
  242. for (int names_idx = 0; names[names_idx] != NULL; ++names_idx)
  243. {
  244. params->name = names[names_idx];
  245. params->marker = names_marker[names_idx];
  246. run_gbhn_gai (params);
  247. }
  248. }
  249. }
  250. /* Run the test for a specific number of addresses/aliases. */
  251. static void
  252. run_test (int count)
  253. {
  254. write_hosts (count);
  255. struct test_params params =
  256. {
  257. .count = count,
  258. };
  259. support_isolate_in_subprocess (subprocess, &params);
  260. }
  261. static int
  262. do_test (void)
  263. {
  264. support_become_root ();
  265. if (!support_can_chroot ())
  266. return EXIT_UNSUPPORTED;
  267. /* This test should not use gigabytes of memory. */
  268. {
  269. struct rlimit limit;
  270. if (getrlimit (RLIMIT_AS, &limit) != 0)
  271. {
  272. printf ("getrlimit (RLIMIT_AS) failed: %m\n");
  273. return 1;
  274. }
  275. long target = 200 * 1024 * 1024;
  276. if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
  277. {
  278. limit.rlim_cur = target;
  279. if (setrlimit (RLIMIT_AS, &limit) != 0)
  280. {
  281. printf ("setrlimit (RLIMIT_AS) failed: %m\n");
  282. return 1;
  283. }
  284. }
  285. }
  286. __nss_configure_lookup ("hosts", "files");
  287. if (dlopen (LIBNSS_FILES_SO, RTLD_LAZY) == NULL)
  288. FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
  289. /* Run the tests with a few different address/alias counts. */
  290. for (int count = 1; count <= 111; ++count)
  291. run_test (count);
  292. run_test (1111);
  293. run_test (22222);
  294. support_chroot_free (chroot_env);
  295. return 0;
  296. }
  297. #define TIMEOUT 40
  298. #define PREPARE prepare
  299. #include <support/test-driver.c>