]> git.ipfire.org Git - thirdparty/glibc.git/blob - resolv/tst-res_use_inet6.c
65145b7b1f53fa59c5677794fa404aaf81e90fd6
[thirdparty/glibc.git] / resolv / tst-res_use_inet6.c
1 /* Basic functionality tests for inet6 option processing.
2 Copyright (C) 2016-2019 Free Software Foundation, Inc.
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
19 #include <ctype.h>
20 #include <netdb.h>
21 #include <resolv.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <support/check.h>
26 #include <support/check_nss.h>
27 #include <support/resolv_test.h>
28 #include <support/support.h>
29 #include <support/xthread.h>
30
31 /* Handle IPv4 reverse lookup responses. Product a PTR record
32 A-B-C-D.v4.example. */
33 static void
34 response_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. */
57 static void
58 response_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
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)
91 'p' PTR record
92 'm' record type must match QTYPE (no additional records)
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.
97
98 in-addr.arpa and ip6.arpa queries are handled separately in
99 response_ptr_v4 and response_ptr_v6. */
100 static void
101 response (const struct resolv_response_context *ctx,
102 struct resolv_response_builder *b,
103 const char *qname, uint16_t qclass, uint16_t qtype)
104 {
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
110 bool include_a = false;
111 bool include_aaaa = false;
112 bool include_match = false;
113 bool include_ptr = false;
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;
122 else if (*p == 'p')
123 include_ptr = true;
124 else if (*p == '6' && qtype == T_AAAA)
125 break;
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 }
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 {
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);
158 }
159 }
160
161 /* Test that getaddrinfo is not influenced by RES_USE_INET6. */
162 static void
163 test_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;
173 int ret = getaddrinfo ("qam.example", "80", &hints, &ai);
174 check_addrinfo ("getaddrinfo AF_UNSPEC qam.example", ai, ret,
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);
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);
185 /* Combined A/AAAA responses currently result in address
186 duplication. */
187 check_addrinfo ("getaddrinfo AF_UNSPEC qa.example", ai, ret,
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;
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,
210 "address: STREAM/TCP 192.0.2.17 80\n");
211 if (ret == 0)
212 freeaddrinfo (ai);
213 ret = getaddrinfo ("qa.example", "80", &hints, &ai);
214 check_addrinfo ("getaddrinfo AF_INET qa.example", ai, ret,
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;
227 int ret = getaddrinfo ("qa.example", "80", &hints, &ai);
228 check_addrinfo ("getaddrinfo (AF_INET6)", ai, ret,
229 "address: STREAM/TCP 2001:db8::1 80\n");
230 if (ret == 0)
231 freeaddrinfo (ai);
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,
239 "address: STREAM/TCP 2001:db8::1 80\n");
240 if (ret == 0)
241 freeaddrinfo (ai);
242 }
243 }
244
245 /* Test gethostbyaddr and getnameinfo. The results are independent of
246 RES_USE_INET6. */
247 static void
248 test_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
304 /* Test that gethostbyname2 is mostly not influenced by
305 RES_USE_INET6. */
306 static void
307 test_get2_any (void)
308 {
309 check_hostent ("gethostbyname2 AF_INET am.example",
310 gethostbyname2 ("am.example", AF_INET),
311 "name: am.example\n"
312 "address: 192.0.2.17\n");
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"
330 "address: 192.0.2.17\n");
331
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"
339 "address: 2001:db8::1\n");
340 check_hostent ("gethostbyname2 AF_INET6 qam.example",
341 gethostbyname2 ("qam.example", AF_INET6),
342 "name: qam.example\n"
343 "address: 2001:db8::1\n");
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. */
349
350 test_reverse ();
351 }
352
353 /* gethostbyname2 tests with RES_USE_INET6 disabled. */
354 static void
355 test_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. */
368 static void
369 test_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. */
383 static void
384 test_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");
398 check_hostent ("gethostbyname (\"amp.example\")",
399 gethostbyname ("amp.example"),
400 "name: amp.example\n"
401 "address: 192.0.2.17\n");
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 ();
417 }
418
419 static void *
420 threadfunc (void *ignored)
421 {
422 struct resolv_test *obj = resolv_test_start
423 ((struct resolv_redirect_config)
424 {
425 .response_callback = response
426 });
427
428 TEST_VERIFY ((_res.options & RES_USE_INET6) == 0);
429 test_no_inet6 ();
430
431 _res.options |= RES_USE_INET6;
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"
446 "address: 2001:db8::1\n");
447 check_hostent ("gethostbyname (\"q.inet6.example\")",
448 gethostbyname ("q.inet6.example"),
449 "name: q.inet6.example\n"
450 "address: 2001:db8::1\n");
451 check_hostent ("gethostbyname (\"qm.inet6.example\")",
452 gethostbyname ("qm.inet6.example"),
453 "name: qm.inet6.example\n"
454 "address: 2001:db8::1\n");
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");
477 test_get2_inet6 ();
478 test_get2_inet6 ();
479 test_gai ();
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 ();
486
487 resolv_test_end (obj);
488
489 return NULL;
490 }
491
492 static int
493 do_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>