1 /* Parse /etc/hosts in multi mode with many addresses/aliases.
2 Copyright (C) 2017-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
21 #include <gnu/lib-names.h>
27 #include <support/check.h>
28 #include <support/check_nss.h>
29 #include <support/namespace.h>
30 #include <support/support.h>
31 #include <support/test-driver.h>
32 #include <support/test-driver.h>
33 #include <support/xmemstream.h>
34 #include <support/xstdio.h>
35 #include <support/xunistd.h>
36 #include <sys/resource.h>
38 struct support_chroot
*chroot_env
;
41 prepare (int argc
, char **argv
)
43 chroot_env
= support_chroot_create
44 ((struct support_chroot_configuration
)
47 .hosts
= "", /* See write_hosts below. */
48 .host_conf
= "multi on\n",
52 /* Create the /etc/hosts file from outside the chroot. */
54 write_hosts (int count
)
56 TEST_VERIFY (count
> 0 && count
<= 65535);
57 FILE *fp
= xfopen (chroot_env
->path_hosts
, "w");
58 fputs ("127.0.0.1 localhost localhost.localdomain\n"
59 "::1 localhost localhost.localdomain\n",
61 for (int i
= 0; i
< count
; ++i
)
63 fprintf (fp
, "10.4.%d.%d www4.example.com\n",
64 (i
/ 256) & 0xff, i
& 0xff);
65 fprintf (fp
, "10.46.%d.%d www.example.com\n",
66 (i
/ 256) & 0xff, i
& 0xff);
67 fprintf (fp
, "192.0.2.1 alias.example.com v4-%d.example.com\n", i
);
68 fprintf (fp
, "2001:db8::6:%x www6.example.com\n", i
);
69 fprintf (fp
, "2001:db8::46:%x www.example.com\n", i
);
70 fprintf (fp
, "2001:db8::1 alias.example.com v6-%d.example.com\n", i
);
75 /* Parameters of a single test. */
78 const char *name
; /* Name to query. */
79 const char *marker
; /* Address marker for the name. */
80 int count
; /* Number of addresses/aliases. */
81 int family
; /* AF_INET, AF_INET_6 or AF_UNSPEC. */
82 bool canonname
; /* True if AI_CANONNAME should be enabled. */
85 /* Expected result of gethostbyname/gethostbyname2. */
87 expected_ghbn (const struct test_params
*params
)
89 TEST_VERIFY (params
->family
== AF_INET
|| params
->family
== AF_INET6
);
91 struct xmemstream expected
;
92 xopen_memstream (&expected
);
93 if (strcmp (params
->name
, "alias.example.com") == 0)
95 fprintf (expected
.out
, "name: %s\n", params
->name
);
97 if (params
->family
== AF_INET
)
101 for (int i
= 0; i
< params
->count
; ++i
)
102 fprintf (expected
.out
, "alias: v%c-%d.example.com\n", af
, i
);
104 for (int i
= 0; i
< params
->count
; ++i
)
105 if (params
->family
== AF_INET
)
106 fputs ("address: 192.0.2.1\n", expected
.out
);
108 fputs ("address: 2001:db8::1\n", expected
.out
);
110 else /* www/www4/www6 name. */
112 bool do_ipv4
= params
->family
== AF_INET
113 && strncmp (params
->name
, "www6", 4) != 0;
114 bool do_ipv6
= params
->family
== AF_INET6
115 && strncmp (params
->name
, "www4", 4) != 0;
116 if (do_ipv4
|| do_ipv6
)
118 fprintf (expected
.out
, "name: %s\n", params
->name
);
120 for (int i
= 0; i
< params
->count
; ++i
)
121 fprintf (expected
.out
, "address: 10.%s.%d.%d\n",
122 params
->marker
, i
/ 256, i
% 256);
124 for (int i
= 0; i
< params
->count
; ++i
)
125 fprintf (expected
.out
, "address: 2001:db8::%s:%x\n",
129 fputs ("error: HOST_NOT_FOUND\n", expected
.out
);
131 xfclose_memstream (&expected
);
132 return expected
.buffer
;
135 /* Expected result of getaddrinfo. */
137 expected_gai (const struct test_params
*params
)
139 bool do_ipv4
= false;
140 bool do_ipv6
= false;
141 if (params
->family
== AF_UNSPEC
)
142 do_ipv4
= do_ipv6
= true;
143 else if (params
->family
== AF_INET
)
145 else if (params
->family
== AF_INET6
)
148 struct xmemstream expected
;
149 xopen_memstream (&expected
);
150 if (strcmp (params
->name
, "alias.example.com") == 0)
152 if (params
->canonname
)
153 fprintf (expected
.out
,
154 "flags: AI_CANONNAME\n"
159 for (int i
= 0; i
< params
->count
; ++i
)
160 fputs ("address: STREAM/TCP 192.0.2.1 80\n", expected
.out
);
162 for (int i
= 0; i
< params
->count
; ++i
)
163 fputs ("address: STREAM/TCP 2001:db8::1 80\n", expected
.out
);
165 else /* www/www4/www6 name. */
167 if (strncmp (params
->name
, "www4", 4) == 0)
169 else if (strncmp (params
->name
, "www6", 4) == 0)
171 /* Otherwise, we have www as the name, so we do both. */
173 if (do_ipv4
|| do_ipv6
)
175 if (params
->canonname
)
176 fprintf (expected
.out
,
177 "flags: AI_CANONNAME\n"
182 for (int i
= 0; i
< params
->count
; ++i
)
183 fprintf (expected
.out
, "address: STREAM/TCP 10.%s.%d.%d 80\n",
184 params
->marker
, i
/ 256, i
% 256);
186 for (int i
= 0; i
< params
->count
; ++i
)
187 fprintf (expected
.out
,
188 "address: STREAM/TCP 2001:db8::%s:%x 80\n",
192 fputs ("error: Name or service not known\n", expected
.out
);
194 xfclose_memstream (&expected
);
195 return expected
.buffer
;
199 run_gbhn_gai (struct test_params
*params
)
201 char *ctx
= xasprintf ("name=%s marker=%s count=%d family=%d",
202 params
->name
, params
->marker
, params
->count
,
204 if (test_verbose
> 0)
205 printf ("info: %s\n", ctx
);
207 /* Check gethostbyname, gethostbyname2. */
208 if (params
->family
== AF_INET
)
210 char *expected
= expected_ghbn (params
);
211 check_hostent (ctx
, gethostbyname (params
->name
), expected
);
214 if (params
->family
!= AF_UNSPEC
)
216 char *expected
= expected_ghbn (params
);
217 check_hostent (ctx
, gethostbyname2 (params
->name
, params
->family
),
222 /* Check getaddrinfo. */
223 for (int do_canonical
= 0; do_canonical
< 2; ++do_canonical
)
225 params
->canonname
= do_canonical
;
226 char *expected
= expected_gai (params
);
227 struct addrinfo hints
=
229 .ai_family
= params
->family
,
230 .ai_socktype
= SOCK_STREAM
,
231 .ai_protocol
= IPPROTO_TCP
,
234 hints
.ai_flags
|= AI_CANONNAME
;
236 int ret
= getaddrinfo (params
->name
, "80", &hints
, &ai
);
237 check_addrinfo (ctx
, ai
, ret
, expected
);
246 /* Callback for the subprocess which runs the test in a chroot. */
248 subprocess (void *closure
)
250 struct test_params
*params
= closure
;
252 xchroot (chroot_env
->path_chroot
);
254 static const int families
[] = { AF_INET
, AF_INET6
, AF_UNSPEC
, -1 };
255 static const char *const names
[] =
257 "www.example.com", "www4.example.com", "www6.example.com",
261 static const char *const names_marker
[] = { "46", "4", "6", "" };
263 for (int family_idx
= 0; families
[family_idx
] >= 0; ++family_idx
)
265 params
->family
= families
[family_idx
];
266 for (int names_idx
= 0; names
[names_idx
] != NULL
; ++names_idx
)
268 params
->name
= names
[names_idx
];
269 params
->marker
= names_marker
[names_idx
];
270 run_gbhn_gai (params
);
275 /* Run the test for a specific number of addresses/aliases. */
281 struct test_params params
=
286 support_isolate_in_subprocess (subprocess
, ¶ms
);
292 support_become_root ();
293 if (!support_can_chroot ())
294 return EXIT_UNSUPPORTED
;
296 /* This test should not use gigabytes of memory. */
299 if (getrlimit (RLIMIT_AS
, &limit
) != 0)
301 printf ("getrlimit (RLIMIT_AS) failed: %m\n");
304 long target
= 200 * 1024 * 1024;
305 if (limit
.rlim_cur
== RLIM_INFINITY
|| limit
.rlim_cur
> target
)
307 limit
.rlim_cur
= target
;
308 if (setrlimit (RLIMIT_AS
, &limit
) != 0)
310 printf ("setrlimit (RLIMIT_AS) failed: %m\n");
316 __nss_configure_lookup ("hosts", "files");
317 if (dlopen (LIBNSS_FILES_SO
, RTLD_LAZY
) == NULL
)
318 FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO
": %s", dlerror ());
320 /* Run the tests with a few different address/alias counts. */
321 for (int count
= 1; count
<= 111; ++count
)
326 support_chroot_free (chroot_env
);
331 #define PREPARE prepare
332 #include <support/test-driver.c>