1 /* Enumerate /etc/hosts with a long line (bug 18991).
2 Copyright (C) 2018-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/>. */
22 #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/xmemstream.h>
33 #include <support/xstdio.h>
34 #include <support/xunistd.h>
36 struct support_chroot
*chroot_env
;
38 /* Number of alias names in the long line. This is varied to catch
39 different cases where the ERANGE handling can go wrong (line buffer
40 length, alias buffer). */
41 static int name_count
;
43 /* Write /etc/hosts, from outside of the chroot. */
47 FILE *fp
= xfopen (chroot_env
->path_hosts
, "w");
48 fputs ("127.0.0.1 localhost localhost.localdomain\n", fp
);
49 fputs ("192.0.2.2 host2.example.com\n", fp
);
50 fputs ("192.0.2.1", fp
);
51 for (int i
= 0; i
< name_count
; ++i
)
52 fprintf (fp
, " host%d.example.com", i
);
53 fputs ("\n192.0.2.80 www.example.com\n"
54 "192.0.2.5 host5.example.com\n"
55 "192.0.2.81 www1.example.com\n", fp
);
59 const char *host1_expected
=
61 "alias: localhost.localdomain\n"
62 "address: 127.0.0.1\n";
63 const char *host2_expected
=
64 "name: host2.example.com\n"
65 "address: 192.0.2.2\n";
66 const char *host4_expected
=
67 "name: www.example.com\n"
68 "address: 192.0.2.80\n";
69 const char *host5_expected
=
70 "name: host5.example.com\n"
71 "address: 192.0.2.5\n";
72 const char *host6_expected
=
73 "name: www1.example.com\n"
74 "address: 192.0.2.81\n";
77 prepare (int argc
, char **argv
)
79 chroot_env
= support_chroot_create
80 ((struct support_chroot_configuration
)
83 .hosts
= "", /* Filled in by write_hosts. */
84 .host_conf
= "multi on\n",
88 /* If -1, no sethostent call. Otherwise, pass do_stayopen as the
89 sethostent argument. */
90 static int do_stayopen
;
92 /* If non-zero, perform an endostent call. */
96 subprocess_getent (void *closure
)
98 xchroot (chroot_env
->path_chroot
);
101 if (do_stayopen
>= 0)
102 sethostent (do_stayopen
);
103 TEST_VERIFY (errno
== 0);
108 struct xmemstream expected
;
109 xopen_memstream (&expected
);
113 fputs (host1_expected
, expected
.out
);
116 fputs (host2_expected
, expected
.out
);
119 fputs ("name: host0.example.com\n", expected
.out
);
120 for (int j
= 1; j
< name_count
; ++j
)
121 fprintf (expected
.out
, "alias: host%d.example.com\n", j
);
122 fputs ("address: 192.0.2.1\n", expected
.out
);
125 fputs (host4_expected
, expected
.out
);
128 fputs (host5_expected
, expected
.out
);
131 fputs (host6_expected
, expected
.out
);
134 fprintf (expected
.out
, "*** unexpected host %d ***\n", i
);
137 xfclose_memstream (&expected
);
138 char *context
= xasprintf ("do_stayopen=%d host=%d", do_stayopen
, i
);
141 struct hostent
*e
= gethostent ();
144 TEST_VERIFY (errno
== 0);
147 check_hostent (context
, e
, expected
.buffer
);
149 free (expected
.buffer
);
155 TEST_VERIFY (errno
== 0);
157 /* Exercise process termination. */
161 /* getaddrinfo test. To be run from a subprocess. */
163 test_gai (int family
)
165 struct addrinfo hints
=
168 .ai_protocol
= IPPROTO_TCP
,
169 .ai_socktype
= SOCK_STREAM
,
173 int ret
= getaddrinfo ("host2.example.com", "80", &hints
, &ai
);
174 check_addrinfo ("host2.example.com", ai
, ret
,
175 "address: STREAM/TCP 192.0.2.2 80\n"
176 "address: STREAM/TCP 192.0.2.1 80\n");
178 ret
= getaddrinfo ("host5.example.com", "80", &hints
, &ai
);
179 check_addrinfo ("host5.example.com", ai
, ret
,
180 "address: STREAM/TCP 192.0.2.1 80\n"
181 "address: STREAM/TCP 192.0.2.5 80\n");
183 ret
= getaddrinfo ("www.example.com", "80", &hints
, &ai
);
184 check_addrinfo ("www.example.com", ai
, ret
,
185 "address: STREAM/TCP 192.0.2.80 80\n");
187 ret
= getaddrinfo ("www1.example.com", "80", &hints
, &ai
);
188 check_addrinfo ("www1.example.com", ai
, ret
,
189 "address: STREAM/TCP 192.0.2.81 80\n");
192 /* Subprocess routine for gethostbyname/getaddrinfo testing. */
194 subprocess_gethost (void *closure
)
196 xchroot (chroot_env
->path_chroot
);
198 /* This tests enlarging the read buffer in the multi case. */
199 struct xmemstream expected
;
200 xopen_memstream (&expected
);
201 fputs ("name: host2.example.com\n", expected
.out
);
202 for (int j
= 1; j
< name_count
; ++j
)
203 /* NB: host2 is duplicated in the alias list. */
204 fprintf (expected
.out
, "alias: host%d.example.com\n", j
);
205 fputs ("alias: host0.example.com\n"
206 "address: 192.0.2.2\n"
207 "address: 192.0.2.1\n",
209 xfclose_memstream (&expected
);
210 check_hostent ("host2.example.com",
211 gethostbyname ("host2.example.com"),
213 free (expected
.buffer
);
215 /* Similarly, but with a different order in the /etc/hosts file. */
216 xopen_memstream (&expected
);
217 fputs ("name: host0.example.com\n", expected
.out
);
218 for (int j
= 1; j
< name_count
; ++j
)
219 fprintf (expected
.out
, "alias: host%d.example.com\n", j
);
220 /* NB: host5 is duplicated in the alias list. */
221 fputs ("alias: host5.example.com\n"
222 "address: 192.0.2.1\n"
223 "address: 192.0.2.5\n",
225 xfclose_memstream (&expected
);
226 check_hostent ("host5.example.com",
227 gethostbyname ("host5.example.com"),
229 free (expected
.buffer
);
231 check_hostent ("www.example.com",
232 gethostbyname ("www.example.com"),
234 check_hostent ("www1.example.com",
235 gethostbyname ("www1.example.com"),
239 test_gai (AF_UNSPEC
);
245 support_become_root ();
246 if (!support_can_chroot ())
247 return EXIT_UNSUPPORTED
;
249 __nss_configure_lookup ("hosts", "files");
250 if (dlopen (LIBNSS_FILES_SO
, RTLD_LAZY
) == NULL
)
251 FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO
": %s", dlerror ());
253 /* Each name takes about 20 bytes, so this covers a wide range of
254 buffer sizes, from less than 1000 bytes to about 18000 bytes. */
255 for (name_count
= 40; name_count
<= 850; ++name_count
)
259 for (do_stayopen
= -1; do_stayopen
< 2; ++do_stayopen
)
260 for (do_endent
= 0; do_endent
< 2; ++do_endent
)
262 if (test_verbose
> 0)
263 printf ("info: name_count=%d do_stayopen=%d do_endent=%d\n",
264 name_count
, do_stayopen
, do_endent
);
265 support_isolate_in_subprocess (subprocess_getent
, NULL
);
268 support_isolate_in_subprocess (subprocess_gethost
, NULL
);
271 support_chroot_free (chroot_env
);
275 #define PREPARE prepare
276 #include <support/test-driver.c>