]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/tst-res_use_inet6.c
iconv, localedef: avoid floating point rounding differences [BZ #24372]
[thirdparty/glibc.git] / resolv / tst-res_use_inet6.c
CommitLineData
5840c75c 1/* Basic functionality tests for inet6 option processing.
04277e02 2 Copyright (C) 2016-2019 Free Software Foundation, Inc.
5840c75c
FW
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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/>. */
18
c77eb969 19#include <ctype.h>
5840c75c
FW
20#include <netdb.h>
21#include <resolv.h>
c77eb969
FW
22#include <stdio.h>
23#include <stdlib.h>
5840c75c 24#include <string.h>
5e9c4d17 25#include <support/check.h>
5840c75c
FW
26#include <support/check_nss.h>
27#include <support/resolv_test.h>
c77eb969 28#include <support/support.h>
5840c75c
FW
29#include <support/xthread.h>
30
c77eb969
FW
31/* Handle IPv4 reverse lookup responses. Product a PTR record
32 A-B-C-D.v4.example. */
33static void
34response_ptr_v4 (const struct resolv_response_context *ctx,
35 struct resolv_response_builder *b,
36 const char *qname, uint16_t qclass, uint16_t qtype)
37{
38 int bytes[4];
39 int offset = -1;
40 TEST_VERIFY (sscanf (qname, "%d.%d.%d.%d.in-addr.arpa%n",
41 bytes + 0, bytes + 1, bytes + 2, bytes + 3,
42 &offset) == 4);
43 TEST_VERIFY (offset == strlen (qname));
44 resolv_response_init (b, (struct resolv_response_flags) {});
45 resolv_response_add_question (b, qname, qclass, qtype);
46 resolv_response_section (b, ns_s_an);
47 resolv_response_open_record (b, qname, qclass, T_PTR, 0);
48 char *name = xasprintf ("%d-%d-%d-%d.v4.example",
49 bytes[3], bytes[2], bytes[1], bytes[0]);
50 resolv_response_add_name (b, name);
51 free (name);
52 resolv_response_close_record (b);
53}
54
55/* Handle IPv6 reverse lookup responses. Produce a PTR record
56 <32 hex digits>.v6.example. */
57static void
58response_ptr_v6 (const struct resolv_response_context *ctx,
59 struct resolv_response_builder *b,
60 const char *qname, uint16_t qclass, uint16_t qtype)
61{
62
63 TEST_VERIFY_EXIT (strlen (qname) > 64);
64
65 char bytes[33];
66 for (int i = 0; i < 64; ++i)
67 if ((i % 2) == 0)
68 {
69 TEST_VERIFY (isxdigit ((unsigned char) qname[i]));
70 bytes[31 - i / 2] = qname[i];
71 }
72 else
73 TEST_VERIFY_EXIT (qname[i] == '.');
74 bytes[32] = '\0';
75
76 resolv_response_init (b, (struct resolv_response_flags) {});
77 resolv_response_add_question (b, qname, qclass, qtype);
78 resolv_response_section (b, ns_s_an);
79 resolv_response_open_record (b, qname, qclass, T_PTR, 0);
80 char *name = xasprintf ("%s.v6.example", bytes);
81 resolv_response_add_name (b, name);
82 free (name);
83 resolv_response_close_record (b);
84}
85
5e9c4d17
FW
86/* Produce a response based on QNAME: Certain characters in the first
87 label of QNAME trigger the inclusion of resource records:
88
89 'a' A record (IPv4 address)
90 'q' AAAA record (quad A record, IPv6 address)
c77eb969 91 'p' PTR record
5e9c4d17 92 'm' record type must match QTYPE (no additional records)
c77eb969
FW
93 '6' stop flag processing if QTYPE == AAAA
94
95 For 'a' and 'q', QTYPE is ignored for record type selection if 'm'
96 is not specified.
5e9c4d17 97
c77eb969
FW
98 in-addr.arpa and ip6.arpa queries are handled separately in
99 response_ptr_v4 and response_ptr_v6. */
5840c75c
FW
100static void
101response (const struct resolv_response_context *ctx,
102 struct resolv_response_builder *b,
103 const char *qname, uint16_t qclass, uint16_t qtype)
104{
c77eb969
FW
105 if (strstr (qname, ".in-addr.arpa") != NULL)
106 return response_ptr_v4 (ctx, b, qname, qclass, qtype);
107 else if (strstr (qname, ".ip6.arpa") != NULL)
108 return response_ptr_v6 (ctx, b, qname, qclass, qtype);
109
5e9c4d17
FW
110 bool include_a = false;
111 bool include_aaaa = false;
112 bool include_match = false;
c77eb969 113 bool include_ptr = false;
5e9c4d17
FW
114 for (const char *p = qname; *p != '.' && *p != '\0'; ++p)
115 {
116 if (*p == 'a')
117 include_a = true;
118 else if (*p == 'q')
119 include_aaaa = true;
120 else if (*p == 'm')
121 include_match = true;
c77eb969
FW
122 else if (*p == 'p')
123 include_ptr = true;
124 else if (*p == '6' && qtype == T_AAAA)
125 break;
5e9c4d17
FW
126 }
127 if (include_match)
128 {
129 if (qtype == T_A)
130 include_aaaa = false;
131 else if (qtype == T_AAAA)
132 include_a = false;
133 }
5840c75c
FW
134
135 resolv_response_init (b, (struct resolv_response_flags) {});
136 resolv_response_add_question (b, qname, qclass, qtype);
137 resolv_response_section (b, ns_s_an);
138 if (include_a)
139 {
140 char ipv4[4] = {192, 0, 2, 17};
141 resolv_response_open_record (b, qname, qclass, T_A, 0);
142 resolv_response_add_data (b, &ipv4, sizeof (ipv4));
143 resolv_response_close_record (b);
144 }
145 if (include_aaaa)
146 {
c77eb969
FW
147 char ipv6[16]
148 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
149 resolv_response_open_record (b, qname, qclass, T_AAAA, 0);
150 resolv_response_add_data (b, &ipv6, sizeof (ipv6));
151 resolv_response_close_record (b);
152 }
153 if (include_ptr)
154 {
155 resolv_response_open_record (b, qname, qclass, T_PTR, 0);
156 resolv_response_add_name (b, "ptr-target.example");
157 resolv_response_close_record (b);
5840c75c
FW
158 }
159}
160
161/* Test that getaddrinfo is not influenced by RES_USE_INET6. */
162static void
163test_gai (void)
164{
165 {
166 struct addrinfo hints =
167 {
168 .ai_family = AF_UNSPEC,
169 .ai_socktype = SOCK_STREAM,
170 .ai_protocol = IPPROTO_TCP,
171 };
172 struct addrinfo *ai;
5e9c4d17
FW
173 int ret = getaddrinfo ("qam.example", "80", &hints, &ai);
174 check_addrinfo ("getaddrinfo AF_UNSPEC qam.example", ai, ret,
5840c75c
FW
175 "address: STREAM/TCP 192.0.2.17 80\n"
176 "address: STREAM/TCP 2001:db8::1 80\n");
177 if (ret == 0)
178 freeaddrinfo (ai);
5e9c4d17
FW
179 ret = getaddrinfo ("am.example", "80", &hints, &ai);
180 check_addrinfo ("getaddrinfo AF_UNSPEC am.example", ai, ret,
181 "address: STREAM/TCP 192.0.2.17 80\n");
182 if (ret == 0)
183 freeaddrinfo (ai);
184 ret = getaddrinfo ("qa.example", "80", &hints, &ai);
5840c75c
FW
185 /* Combined A/AAAA responses currently result in address
186 duplication. */
5e9c4d17 187 check_addrinfo ("getaddrinfo AF_UNSPEC qa.example", ai, ret,
5840c75c
FW
188 "address: STREAM/TCP 192.0.2.17 80\n"
189 "address: STREAM/TCP 192.0.2.17 80\n"
190 "address: STREAM/TCP 2001:db8::1 80\n"
191 "address: STREAM/TCP 2001:db8::1 80\n");
192 if (ret == 0)
193 freeaddrinfo (ai);
194 }
195 {
196 struct addrinfo hints =
197 {
198 .ai_family = AF_INET,
199 .ai_socktype = SOCK_STREAM,
200 .ai_protocol = IPPROTO_TCP,
201 };
202 struct addrinfo *ai;
5e9c4d17
FW
203 int ret = getaddrinfo ("qam.example", "80", &hints, &ai);
204 check_addrinfo ("getaddrinfo AF_INET qam.example", ai, ret,
205 "address: STREAM/TCP 192.0.2.17 80\n");
206 if (ret == 0)
207 freeaddrinfo (ai);
208 ret = getaddrinfo ("am.example", "80", &hints, &ai);
209 check_addrinfo ("getaddrinfo AF_INET am.example", ai, ret,
5840c75c
FW
210 "address: STREAM/TCP 192.0.2.17 80\n");
211 if (ret == 0)
212 freeaddrinfo (ai);
5e9c4d17
FW
213 ret = getaddrinfo ("qa.example", "80", &hints, &ai);
214 check_addrinfo ("getaddrinfo AF_INET qa.example", ai, ret,
5840c75c
FW
215 "address: STREAM/TCP 192.0.2.17 80\n");
216 if (ret == 0)
217 freeaddrinfo (ai);
218 }
219 {
220 struct addrinfo hints =
221 {
222 .ai_family = AF_INET6,
223 .ai_socktype = SOCK_STREAM,
224 .ai_protocol = IPPROTO_TCP,
225 };
226 struct addrinfo *ai;
5e9c4d17 227 int ret = getaddrinfo ("qa.example", "80", &hints, &ai);
5840c75c
FW
228 check_addrinfo ("getaddrinfo (AF_INET6)", ai, ret,
229 "address: STREAM/TCP 2001:db8::1 80\n");
230 if (ret == 0)
231 freeaddrinfo (ai);
5e9c4d17
FW
232 ret = getaddrinfo ("am.example", "80", &hints, &ai);
233 check_addrinfo ("getaddrinfo AF_INET6 am.example", ai, ret,
234 "error: No address associated with hostname\n");
235 if (ret == 0)
236 freeaddrinfo (ai);
237 ret = getaddrinfo ("qam.example", "80", &hints, &ai);
238 check_addrinfo ("getaddrinfo AF_INET6 qam.example", ai, ret,
5840c75c
FW
239 "address: STREAM/TCP 2001:db8::1 80\n");
240 if (ret == 0)
241 freeaddrinfo (ai);
242 }
243}
244
c77eb969
FW
245/* Test gethostbyaddr and getnameinfo. The results are independent of
246 RES_USE_INET6. */
247static void
248test_reverse (void)
249{
250 {
251 char ipv4[4] = { 192, 0, 2, 17 };
252 check_hostent ("gethostbyaddr AF_INET",
253 gethostbyaddr (ipv4, sizeof (ipv4), AF_INET),
254 "name: 192-0-2-17.v4.example\n"
255 "address: 192.0.2.17\n");
256 }
257 {
258 char ipv6[16]
259 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
260 check_hostent ("gethostbyaddr AF_INET",
261 gethostbyaddr (ipv6, sizeof (ipv6), AF_INET6),
262 "name: 20010db8000000000000000000000001.v6.example\n"
263 "address: 2001:db8::1\n");
264 }
265
266 {
267 struct sockaddr_in addr =
268 {
269 .sin_family = AF_INET,
270 .sin_addr = { .s_addr = htonl (0xc0000211) },
271 .sin_port = htons (80)
272 };
273 char host[NI_MAXHOST];
274 char service[NI_MAXSERV];
275 int ret = getnameinfo ((struct sockaddr *) &addr, sizeof (addr),
276 host, sizeof (host), service, sizeof (service),
277 NI_NUMERICSERV);
278 TEST_VERIFY (ret == 0);
279 TEST_VERIFY (strcmp (host, "192-0-2-17.v4.example") == 0);
280 TEST_VERIFY (strcmp (service, "80") == 0);
281 }
282 {
283 char ipv6[16]
284 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
285 struct sockaddr_in6 addr =
286 {
287 .sin6_family = AF_INET6,
288 .sin6_port = htons (80),
289 };
290 TEST_VERIFY (sizeof (ipv6) == sizeof (addr.sin6_addr));
291 memcpy (&addr.sin6_addr, ipv6, sizeof (addr.sin6_addr));
292 char host[NI_MAXHOST];
293 char service[NI_MAXSERV];
294 int ret = getnameinfo ((struct sockaddr *) &addr, sizeof (addr),
295 host, sizeof (host), service, sizeof (service),
296 NI_NUMERICSERV);
297 TEST_VERIFY (ret == 0);
298 TEST_VERIFY
299 (strcmp (host, "20010db8000000000000000000000001.v6.example") == 0);
300 TEST_VERIFY (strcmp (service, "80") == 0);
301 }
302}
303
5e9c4d17
FW
304/* Test that gethostbyname2 is mostly not influenced by
305 RES_USE_INET6. */
5840c75c 306static void
5e9c4d17 307test_get2_any (void)
5840c75c 308{
5e9c4d17
FW
309 check_hostent ("gethostbyname2 AF_INET am.example",
310 gethostbyname2 ("am.example", AF_INET),
311 "name: am.example\n"
5840c75c 312 "address: 192.0.2.17\n");
5e9c4d17
FW
313 check_hostent ("gethostbyname2 AF_INET a.example",
314 gethostbyname2 ("a.example", AF_INET),
315 "name: a.example\n"
316 "address: 192.0.2.17\n");
317 check_hostent ("gethostbyname2 AF_INET qm.example",
318 gethostbyname2 ("qm.example", AF_INET),
319 "error: NO_ADDRESS\n");
320 check_hostent ("gethostbyname2 AF_INET q.example",
321 gethostbyname2 ("q.example", AF_INET),
322 "error: NO_RECOVERY\n");
323 check_hostent ("gethostbyname2 AF_INET qam.example",
324 gethostbyname2 ("qam.example", AF_INET),
325 "name: qam.example\n"
326 "address: 192.0.2.17\n");
327 check_hostent ("gethostbyname2 AF_INET qa.example",
328 gethostbyname2 ("qa.example", AF_INET),
329 "name: qa.example\n"
5840c75c
FW
330 "address: 192.0.2.17\n");
331
5e9c4d17
FW
332 check_hostent ("gethostbyname2 AF_INET6 qm.example",
333 gethostbyname2 ("qm.example", AF_INET6),
334 "name: qm.example\n"
335 "address: 2001:db8::1\n");
336 check_hostent ("gethostbyname2 AF_INET6 q.example",
337 gethostbyname2 ("q.example", AF_INET6),
338 "name: q.example\n"
5840c75c 339 "address: 2001:db8::1\n");
5e9c4d17
FW
340 check_hostent ("gethostbyname2 AF_INET6 qam.example",
341 gethostbyname2 ("qam.example", AF_INET6),
342 "name: qam.example\n"
5840c75c 343 "address: 2001:db8::1\n");
5e9c4d17
FW
344 check_hostent ("gethostbyname2 AF_INET6 qa.example",
345 gethostbyname2 ("qa.example", AF_INET6),
346 "name: qa.example\n"
347 "address: 2001:db8::1\n");
348 /* Additional AF_INET6 tests depend on RES_USE_INET6; see below. */
c77eb969
FW
349
350 test_reverse ();
5e9c4d17
FW
351}
352
353/* gethostbyname2 tests with RES_USE_INET6 disabled. */
354static void
355test_get2_no_inet6 (void)
356{
357 test_get2_any ();
358
359 check_hostent ("gethostbyname2 AF_INET6 am.example",
360 gethostbyname2 ("am.example", AF_INET6),
361 "error: NO_ADDRESS\n");
362 check_hostent ("gethostbyname2 AF_INET6 a.example",
363 gethostbyname2 ("a.example", AF_INET6),
364 "error: NO_RECOVERY\n");
365}
366
367/* gethostbyname2 tests with RES_USE_INET6 enabled. */
368static void
369test_get2_inet6 (void)
370{
371 test_get2_any ();
372
373 check_hostent ("gethostbyname2 AF_INET6 am.example",
374 gethostbyname2 ("am.example", AF_INET6),
375 "name: am.example\n"
376 "address: ::ffff:192.0.2.17\n");
377 check_hostent ("gethostbyname2 AF_INET6 a.example",
378 gethostbyname2 ("a.example", AF_INET6),
379 "error: NO_RECOVERY\n");
380}
381
382/* Collection of tests which assume no RES_USE_INET6 flag. */
383static void
384test_no_inet6 (void)
385{
386 check_hostent ("gethostbyname (\"a.example\")",
387 gethostbyname ("a.example"),
388 "name: a.example\n"
389 "address: 192.0.2.17\n");
390 check_hostent ("gethostbyname (\"qa.example\")",
391 gethostbyname ("qa.example"),
392 "name: qa.example\n"
393 "address: 192.0.2.17\n");
394 check_hostent ("gethostbyname (\"am.example\")",
395 gethostbyname ("am.example"),
396 "name: am.example\n"
397 "address: 192.0.2.17\n");
c77eb969
FW
398 check_hostent ("gethostbyname (\"amp.example\")",
399 gethostbyname ("amp.example"),
400 "name: amp.example\n"
401 "address: 192.0.2.17\n");
5e9c4d17
FW
402 check_hostent ("gethostbyname (\"qam.example\")",
403 gethostbyname ("qam.example"),
404 "name: qam.example\n"
405 "address: 192.0.2.17\n");
406 check_hostent ("gethostbyname (\"q.example\")",
407 gethostbyname ("q.example"),
408 "error: NO_RECOVERY\n");
409 check_hostent ("gethostbyname (\"qm.example\")",
410 gethostbyname ("qm.example"),
411 "error: NO_ADDRESS\n");
412 test_get2_no_inet6 ();
413 test_get2_no_inet6 ();
414 test_gai ();
415 test_get2_no_inet6 ();
416 test_get2_no_inet6 ();
5840c75c
FW
417}
418
419static void *
420threadfunc (void *ignored)
421{
422 struct resolv_test *obj = resolv_test_start
423 ((struct resolv_redirect_config)
424 {
425 .response_callback = response
426 });
427
5e9c4d17
FW
428 TEST_VERIFY ((_res.options & RES_USE_INET6) == 0);
429 test_no_inet6 ();
5840c75c
FW
430
431 _res.options |= RES_USE_INET6;
5e9c4d17
FW
432 check_hostent ("gethostbyname (\"a.inet6.example\")",
433 gethostbyname ("a.inet6.example"),
434 "error: NO_RECOVERY\n");
435 check_hostent ("gethostbyname (\"am.inet6.example\")",
436 gethostbyname ("am.inet6.example"),
437 "name: am.inet6.example\n"
438 "address: ::ffff:192.0.2.17\n");
439 check_hostent ("gethostbyname (\"qa.inet6.example\")",
440 gethostbyname ("qa.inet6.example"),
441 "name: qa.inet6.example\n"
442 "address: 2001:db8::1\n");
443 check_hostent ("gethostbyname (\"qam.inet6.example\")",
444 gethostbyname ("qam.inet6.example"),
445 "name: qam.inet6.example\n"
5840c75c 446 "address: 2001:db8::1\n");
5e9c4d17
FW
447 check_hostent ("gethostbyname (\"q.inet6.example\")",
448 gethostbyname ("q.inet6.example"),
449 "name: q.inet6.example\n"
5840c75c 450 "address: 2001:db8::1\n");
5e9c4d17
FW
451 check_hostent ("gethostbyname (\"qm.inet6.example\")",
452 gethostbyname ("qm.inet6.example"),
453 "name: qm.inet6.example\n"
454 "address: 2001:db8::1\n");
c77eb969
FW
455 check_hostent ("gethostbyname (\"amp.inet6.example\")",
456 gethostbyname ("amp.inet6.example"),
457 "error: NO_RECOVERY\n");
458 check_hostent ("gethostbyname (\"qmp.inet6.example\")",
459 gethostbyname ("qmp.inet6.example"),
460 "name: qmp.inet6.example\n"
461 "address: 2001:db8::1\n");
462 check_hostent ("gethostbyname (\"ap.inet6.example\")",
463 gethostbyname ("ap.inet6.example"),
464 "error: NO_RECOVERY\n");
465 check_hostent ("gethostbyname (\"6ap.inet6.example\")",
466 gethostbyname ("6ap.inet6.example"),
467 "name: 6ap.inet6.example\n"
468 "address: ::ffff:192.0.2.17\n");
469 check_hostent ("gethostbyname (\"am6p.inet6.example\")",
470 gethostbyname ("am6p.inet6.example"),
471 "name: am6p.inet6.example\n"
472 "address: ::ffff:192.0.2.17\n");
473 check_hostent ("gethostbyname (\"qp.inet6.example\")",
474 gethostbyname ("qp.inet6.example"),
475 "name: qp.inet6.example\n"
476 "address: 2001:db8::1\n");
5e9c4d17
FW
477 test_get2_inet6 ();
478 test_get2_inet6 ();
5840c75c 479 test_gai ();
5e9c4d17
FW
480 test_get2_inet6 ();
481 test_get2_inet6 ();
482
483 TEST_VERIFY (_res.options & RES_USE_INET6);
484 _res.options &= ~RES_USE_INET6;
485 test_no_inet6 ();
5840c75c
FW
486
487 resolv_test_end (obj);
488
489 return NULL;
490}
491
492static int
493do_test (void)
494{
495 resolv_test_init ();
496
497 /* Attempt to run on a non-main thread first. */
498 {
499 pthread_t thr = xpthread_create (NULL, threadfunc, NULL);
500 xpthread_join (thr);
501 }
502
503 /* Try the main thread next. */
504 threadfunc (NULL);
505
506 return 0;
507}
508
509#include <support/test-driver.c>