1 /* Test basic nss_dns functionality with multiple threads.
2 Copyright (C) 2016-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/>. */
19 /* Unlike tst-resolv-basic, this test does not overwrite the _res
20 structure and relies on namespaces to achieve the redirection to
21 the test servers with a custom /etc/resolv.conf file. */
25 #include <gnu/lib-names.h>
27 #include <resolv/resolv-internal.h>
28 #include <resolv/resolv_context.h>
32 #include <support/check.h>
33 #include <support/namespace.h>
34 #include <support/resolv_test.h>
35 #include <support/support.h>
36 #include <support/temp_file.h>
37 #include <support/test-driver.h>
38 #include <support/xthread.h>
39 #include <support/xunistd.h>
41 /* Each client thread sends this many queries. */
42 enum { queries_per_thread
= 500 };
44 /* Return a small positive number identifying this thread. */
46 get_thread_number (void)
48 static int __thread local
;
51 static int global
= 1;
52 local
= __atomic_fetch_add (&global
, 1, __ATOMIC_RELAXED
);
57 response (const struct resolv_response_context
*ctx
,
58 struct resolv_response_builder
*b
,
59 const char *qname
, uint16_t qclass
, uint16_t qtype
)
61 TEST_VERIFY_EXIT (qname
!= NULL
);
66 TEST_VERIFY (sscanf (qname
, "counter%d.thread%d.example.com%n",
67 &counter
, &thread
, &dummy
) == 2);
68 TEST_VERIFY (dummy
> 0);
70 struct resolv_response_flags flags
= { 0 };
71 resolv_response_init (b
, flags
);
72 resolv_response_add_question (b
, qname
, qclass
, qtype
);
74 resolv_response_section (b
, ns_s_an
);
75 resolv_response_open_record (b
, qname
, qclass
, qtype
, 0);
80 char ipv4
[4] = {10, 0, counter
, thread
};
81 resolv_response_add_data (b
, &ipv4
, sizeof (ipv4
));
87 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0,
88 counter
, 0, thread
, 0, 0};
89 resolv_response_add_data (b
, &ipv6
, sizeof (ipv6
));
93 support_record_failure ();
94 printf ("error: unexpected QTYPE: %s/%u/%u\n",
95 qname
, qclass
, qtype
);
97 resolv_response_close_record (b
);
100 /* Check that the resolver configuration for this thread has an
101 extended resolver configuration. */
103 check_have_conf (void)
105 struct resolv_context
*ctx
= __resolv_context_get ();
106 TEST_VERIFY_EXIT (ctx
!= NULL
);
107 TEST_VERIFY (ctx
->conf
!= NULL
);
108 __resolv_context_put (ctx
);
111 /* Verify that E matches the expected response for FAMILY and
114 check_hostent (const char *caller
, const char *function
, const char *qname
,
115 int ret
, struct hostent
*e
, int family
, int counter
)
120 support_record_failure ();
121 printf ("error: %s: %s for %s failed: %m\n", caller
, function
, qname
);
125 TEST_VERIFY_EXIT (e
!= NULL
);
126 TEST_VERIFY (strcmp (qname
, e
->h_name
) == 0);
127 TEST_VERIFY (e
->h_addrtype
== family
);
128 TEST_VERIFY_EXIT (e
->h_addr_list
[0] != NULL
);
129 TEST_VERIFY (e
->h_addr_list
[1] == NULL
);
134 char addr
[4] = {10, 0, counter
, get_thread_number ()};
135 TEST_VERIFY (e
->h_length
== sizeof (addr
));
136 TEST_VERIFY (memcmp (e
->h_addr_list
[0], addr
, sizeof (addr
)) == 0);
142 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
143 0, counter
, 0, get_thread_number (), 0, 0};
144 TEST_VERIFY (e
->h_length
== sizeof (addr
));
145 TEST_VERIFY (memcmp (e
->h_addr_list
[0], addr
, sizeof (addr
)) == 0);
149 FAIL_EXIT1 ("%s: invalid address family %d", caller
, family
);
154 /* Check a getaddrinfo result. */
156 check_addrinfo (const char *caller
, const char *qname
,
157 int ret
, struct addrinfo
*ai
, int family
, int counter
)
161 support_record_failure ();
162 printf ("error: %s: getaddrinfo for %s failed: %s\n",
163 caller
, qname
, gai_strerror (ret
));
167 TEST_VERIFY_EXIT (ai
!= NULL
);
169 /* Check that available data matches the requirements. */
170 bool have_ipv4
= false;
171 bool have_ipv6
= false;
172 for (struct addrinfo
*p
= ai
; p
!= NULL
; p
= p
->ai_next
)
174 TEST_VERIFY (p
->ai_socktype
== SOCK_STREAM
);
175 TEST_VERIFY (p
->ai_protocol
== IPPROTO_TCP
);
176 TEST_VERIFY_EXIT (p
->ai_addr
!= NULL
);
177 TEST_VERIFY (p
->ai_addr
->sa_family
== p
->ai_family
);
179 switch (p
->ai_family
)
183 TEST_VERIFY (!have_ipv4
);
185 struct sockaddr_in
*sa
= (struct sockaddr_in
*) p
->ai_addr
;
186 TEST_VERIFY (p
->ai_addrlen
== sizeof (*sa
));
187 char addr
[4] = {10, 0, counter
, get_thread_number ()};
188 TEST_VERIFY (memcmp (&sa
->sin_addr
, addr
, sizeof (addr
)) == 0);
189 TEST_VERIFY (ntohs (sa
->sin_port
) == 80);
194 TEST_VERIFY (!have_ipv6
);
196 struct sockaddr_in6
*sa
= (struct sockaddr_in6
*) p
->ai_addr
;
197 TEST_VERIFY (p
->ai_addrlen
== sizeof (*sa
));
199 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
200 0, counter
, 0, get_thread_number (), 0, 0};
201 TEST_VERIFY (memcmp (&sa
->sin6_addr
, addr
, sizeof (addr
)) == 0);
202 TEST_VERIFY (ntohs (sa
->sin6_port
) == 80);
206 FAIL_EXIT1 ("%s: invalid address family %d", caller
, family
);
213 TEST_VERIFY (have_ipv4
);
214 TEST_VERIFY (!have_ipv6
);
217 TEST_VERIFY (!have_ipv4
);
218 TEST_VERIFY (have_ipv6
);
221 TEST_VERIFY (have_ipv4
);
222 TEST_VERIFY (have_ipv6
);
225 FAIL_EXIT1 ("%s: invalid address family %d", caller
, family
);
231 /* This barrier ensures that all test threads begin their work
233 static pthread_barrier_t barrier
;
235 /* Test gethostbyname2_r (if do_2 is false) or gethostbyname2_r with
236 AF_INET (if do_2 is true). */
240 int this_thread
= get_thread_number ();
241 xpthread_barrier_wait (&barrier
);
242 for (int i
= 0; i
< queries_per_thread
; ++i
)
245 snprintf (qname
, sizeof (qname
), "counter%d.thread%d.example.com",
247 struct hostent storage
;
249 struct hostent
*e
= NULL
;
253 ret
= gethostbyname_r (qname
, &storage
, buf
, sizeof (buf
),
256 ret
= gethostbyname2_r (qname
, AF_INET
, &storage
, buf
, sizeof (buf
),
258 check_hostent (__func__
, do_2
? "gethostbyname2_r" : "gethostbyname_r",
259 qname
, ret
, e
, AF_INET
, i
);
265 /* Test gethostbyname_r. */
267 thread_byname (void *closure
)
269 return byname (false);
272 /* Test gethostbyname2_r with AF_INET. */
274 thread_byname2 (void *closure
)
276 return byname (true);
279 /* Test gethostbyname2_r with AF_INET6. */
281 thread_byname2_af_inet6 (void *closure
)
283 int this_thread
= get_thread_number ();
284 xpthread_barrier_wait (&barrier
);
285 for (int i
= 0; i
< queries_per_thread
; ++i
)
288 snprintf (qname
, sizeof (qname
), "counter%d.thread%d.example.com",
290 struct hostent storage
;
292 struct hostent
*e
= NULL
;
294 int ret
= gethostbyname2_r (qname
, AF_INET6
, &storage
, buf
, sizeof (buf
),
296 check_hostent (__func__
, "gethostbyname2_r", qname
, ret
, e
, AF_INET6
, i
);
301 /* Run getaddrinfo tests for FAMILY. */
305 int this_thread
= get_thread_number ();
306 xpthread_barrier_wait (&barrier
);
307 for (int i
= 0; i
< queries_per_thread
; ++i
)
310 snprintf (qname
, sizeof (qname
), "counter%d.thread%d.example.com",
312 struct addrinfo hints
=
315 .ai_socktype
= SOCK_STREAM
,
316 .ai_protocol
= IPPROTO_TCP
,
319 int ret
= getaddrinfo (qname
, "80", &hints
, &ai
);
320 check_addrinfo (__func__
, qname
, ret
, ai
, family
, i
);
327 /* Test getaddrinfo with AF_INET. */
329 thread_gai_inet (void *closure
)
331 return gai (AF_INET
);
334 /* Test getaddrinfo with AF_INET6. */
336 thread_gai_inet6 (void *closure
)
338 return gai (AF_INET6
);
341 /* Test getaddrinfo with AF_UNSPEC. */
343 thread_gai_unspec (void *closure
)
345 return gai (AF_UNSPEC
);
348 /* Description of the chroot environment used to run the tests. */
349 static struct support_chroot
*chroot_env
;
351 /* Set up the chroot environment. */
353 prepare (int argc
, char **argv
)
355 chroot_env
= support_chroot_create
356 ((struct support_chroot_configuration
)
359 "search example.com\n"
360 "nameserver 127.0.0.1\n"
361 "nameserver 127.0.0.2\n"
362 "nameserver 127.0.0.3\n",
369 support_become_root ();
370 if (!support_enter_network_namespace ())
371 return EXIT_UNSUPPORTED
;
372 if (!support_can_chroot ())
373 return EXIT_UNSUPPORTED
;
375 /* Load the shared object outside of the chroot. */
376 TEST_VERIFY (dlopen (LIBNSS_DNS_SO
, RTLD_LAZY
) != NULL
);
378 xchroot (chroot_env
->path_chroot
);
379 TEST_VERIFY_EXIT (chdir ("/") == 0);
381 struct sockaddr_in server_address
=
383 .sin_family
= AF_INET
,
384 .sin_addr
= { .s_addr
= htonl (INADDR_LOOPBACK
) },
385 .sin_port
= htons (53)
387 const struct sockaddr
*server_addresses
[1] =
388 { (const struct sockaddr
*) &server_address
};
390 struct resolv_test
*aux
= resolv_test_start
391 ((struct resolv_redirect_config
)
393 .response_callback
= response
,
395 .disable_redirect
= true,
396 .server_address_overrides
= server_addresses
,
399 enum { thread_count
= 6 };
400 xpthread_barrier_init (&barrier
, NULL
, thread_count
+ 1);
401 pthread_t threads
[thread_count
];
402 typedef void *(*thread_func
) (void *);
403 thread_func thread_funcs
[thread_count
] =
407 thread_byname2_af_inet6
,
412 for (int i
= 0; i
< thread_count
; ++i
)
413 threads
[i
] = xpthread_create (NULL
, thread_funcs
[i
], NULL
);
414 xpthread_barrier_wait (&barrier
); /* Start the test threads. */
415 for (int i
= 0; i
< thread_count
; ++i
)
416 xpthread_join (threads
[i
]);
418 resolv_test_end (aux
);
419 support_chroot_free (chroot_env
);
424 #define PREPARE prepare
425 #include <support/test-driver.c>