1 /* Test basic nss_dns functionality with multiple threads.
2 Copyright (C) 2016-2017 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 <http://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 /* Call gethostbyname_r with RES_USE_INET6 (if do_2 is false), or
280 gethostbyname_r with AF_INET6 (if do_2 is true). */
282 byname_inet6 (bool do_2
)
284 int this_thread
= get_thread_number ();
285 xpthread_barrier_wait (&barrier
);
289 _res
.options
|= DEPRECATED_RES_USE_INET6
;
290 TEST_VERIFY (strcmp (_res
.defdname
, "example.com") == 0);
292 for (int i
= 0; i
< queries_per_thread
; ++i
)
295 snprintf (qname
, sizeof (qname
), "counter%d.thread%d.example.com",
297 struct hostent storage
;
299 struct hostent
*e
= NULL
;
303 ret
= gethostbyname2_r (qname
, AF_INET6
, &storage
, buf
, sizeof (buf
),
306 ret
= gethostbyname_r (qname
, &storage
, buf
, sizeof (buf
),
308 check_hostent (__func__
,
309 do_2
? "gethostbyname2_r" : "gethostbyname_r",
310 qname
, ret
, e
, AF_INET6
, i
);
315 /* Test gethostbyname_r with AF_INET6. */
317 thread_byname_inet6 (void *closure
)
319 return byname_inet6 (false);
322 /* Test gethostbyname2_r with AF_INET6. */
324 thread_byname2_af_inet6 (void *closure
)
326 return byname_inet6 (true);
329 /* Run getaddrinfo tests for FAMILY. */
331 gai (int family
, bool do_inet6
)
333 int this_thread
= get_thread_number ();
334 xpthread_barrier_wait (&barrier
);
338 _res
.options
|= DEPRECATED_RES_USE_INET6
;
341 for (int i
= 0; i
< queries_per_thread
; ++i
)
344 snprintf (qname
, sizeof (qname
), "counter%d.thread%d.example.com",
346 struct addrinfo hints
=
349 .ai_socktype
= SOCK_STREAM
,
350 .ai_protocol
= IPPROTO_TCP
,
353 int ret
= getaddrinfo (qname
, "80", &hints
, &ai
);
354 check_addrinfo (__func__
, qname
, ret
, ai
, family
, i
);
361 /* Test getaddrinfo with AF_INET. */
363 thread_gai_inet (void *closure
)
365 return gai (AF_INET
, false);
368 /* Test getaddrinfo with AF_INET6. */
370 thread_gai_inet6 (void *closure
)
372 return gai (AF_INET6
, false);
375 /* Test getaddrinfo with AF_UNSPEC. */
377 thread_gai_unspec (void *closure
)
379 return gai (AF_UNSPEC
, false);
382 /* Test getaddrinfo with AF_INET. */
384 thread_gai_inet_inet6 (void *closure
)
386 return gai (AF_INET
, true);
389 /* Test getaddrinfo with AF_INET6. */
391 thread_gai_inet6_inet6 (void *closure
)
393 return gai (AF_INET6
, true);
396 /* Test getaddrinfo with AF_UNSPEC. */
398 thread_gai_unspec_inet6 (void *closure
)
400 return gai (AF_UNSPEC
, true);
403 /* Description of the chroot environment used to run the tests. */
404 static struct support_chroot
*chroot_env
;
406 /* Set up the chroot environment. */
408 prepare (int argc
, char **argv
)
410 chroot_env
= support_chroot_create
411 ((struct support_chroot_configuration
)
414 "search example.com\n"
415 "nameserver 127.0.0.1\n"
416 "nameserver 127.0.0.2\n"
417 "nameserver 127.0.0.3\n",
424 support_become_root ();
425 if (!support_enter_network_namespace ())
426 return EXIT_UNSUPPORTED
;
427 if (!support_can_chroot ())
428 return EXIT_UNSUPPORTED
;
430 /* Load the shared object outside of the chroot. */
431 TEST_VERIFY (dlopen (LIBNSS_DNS_SO
, RTLD_LAZY
) != NULL
);
433 xchroot (chroot_env
->path_chroot
);
434 TEST_VERIFY_EXIT (chdir ("/") == 0);
436 struct sockaddr_in server_address
=
438 .sin_family
= AF_INET
,
439 .sin_addr
= { .s_addr
= htonl (INADDR_LOOPBACK
) },
440 .sin_port
= htons (53)
442 const struct sockaddr
*server_addresses
[1] =
443 { (const struct sockaddr
*) &server_address
};
445 struct resolv_test
*aux
= resolv_test_start
446 ((struct resolv_redirect_config
)
448 .response_callback
= response
,
450 .disable_redirect
= true,
451 .server_address_overrides
= server_addresses
,
454 enum { thread_count
= 10 };
455 xpthread_barrier_init (&barrier
, NULL
, thread_count
+ 1);
456 pthread_t threads
[thread_count
];
457 typedef void *(*thread_func
) (void *);
458 thread_func thread_funcs
[thread_count
] =
463 thread_byname2_af_inet6
,
467 thread_gai_inet_inet6
,
468 thread_gai_inet6_inet6
,
469 thread_gai_unspec_inet6
,
471 for (int i
= 0; i
< thread_count
; ++i
)
472 threads
[i
] = xpthread_create (NULL
, thread_funcs
[i
], NULL
);
473 xpthread_barrier_wait (&barrier
); /* Start the test threads. */
474 for (int i
= 0; i
< thread_count
; ++i
)
475 xpthread_join (threads
[i
]);
477 resolv_test_end (aux
);
478 support_chroot_free (chroot_env
);
483 #define PREPARE prepare
484 #include <support/test-driver.c>