1 /* Basic functionality tests for inet6 option processing.
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/>. */
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>
31 /* Handle IPv4 reverse lookup responses. Product a PTR record
32 A-B-C-D.v4.example. */
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
)
40 TEST_VERIFY (sscanf (qname
, "%d.%d.%d.%d.in-addr.arpa%n",
41 bytes
+ 0, bytes
+ 1, bytes
+ 2, bytes
+ 3,
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
);
52 resolv_response_close_record (b
);
55 /* Handle IPv6 reverse lookup responses. Produce a PTR record
56 <32 hex digits>.v6.example. */
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
)
63 TEST_VERIFY_EXIT (strlen (qname
) > 64);
66 for (int i
= 0; i
< 64; ++i
)
69 TEST_VERIFY (isxdigit ((unsigned char) qname
[i
]));
70 bytes
[31 - i
/ 2] = qname
[i
];
73 TEST_VERIFY_EXIT (qname
[i
] == '.');
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
);
83 resolv_response_close_record (b
);
86 /* Produce a response based on QNAME: Certain characters in the first
87 label of QNAME trigger the inclusion of resource records:
89 'a' A record (IPv4 address)
90 'q' AAAA record (quad A record, IPv6 address)
92 'm' record type must match QTYPE (no additional records)
93 '6' stop flag processing if QTYPE == AAAA
95 For 'a' and 'q', QTYPE is ignored for record type selection if 'm'
98 in-addr.arpa and ip6.arpa queries are handled separately in
99 response_ptr_v4 and response_ptr_v6. */
101 response (const struct resolv_response_context
*ctx
,
102 struct resolv_response_builder
*b
,
103 const char *qname
, uint16_t qclass
, uint16_t qtype
)
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
);
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
)
121 include_match
= true;
124 else if (*p
== '6' && qtype
== T_AAAA
)
130 include_aaaa
= false;
131 else if (qtype
== T_AAAA
)
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
);
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
);
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
);
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
);
161 /* Test that getaddrinfo is not influenced by RES_USE_INET6. */
166 struct addrinfo hints
=
168 .ai_family
= AF_UNSPEC
,
169 .ai_socktype
= SOCK_STREAM
,
170 .ai_protocol
= IPPROTO_TCP
,
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");
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");
184 ret
= getaddrinfo ("qa.example", "80", &hints
, &ai
);
185 /* Combined A/AAAA responses currently result in address
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");
196 struct addrinfo hints
=
198 .ai_family
= AF_INET
,
199 .ai_socktype
= SOCK_STREAM
,
200 .ai_protocol
= IPPROTO_TCP
,
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");
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");
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");
220 struct addrinfo hints
=
222 .ai_family
= AF_INET6
,
223 .ai_socktype
= SOCK_STREAM
,
224 .ai_protocol
= IPPROTO_TCP
,
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");
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");
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");
245 /* Test gethostbyaddr and getnameinfo. The results are independent of
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");
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");
267 struct sockaddr_in addr
=
269 .sin_family
= AF_INET
,
270 .sin_addr
= { .s_addr
= htonl (0xc0000211) },
271 .sin_port
= htons (80)
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
),
278 TEST_VERIFY (ret
== 0);
279 TEST_VERIFY (strcmp (host
, "192-0-2-17.v4.example") == 0);
280 TEST_VERIFY (strcmp (service
, "80") == 0);
284 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
285 struct sockaddr_in6 addr
=
287 .sin6_family
= AF_INET6
,
288 .sin6_port
= htons (80),
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
),
297 TEST_VERIFY (ret
== 0);
299 (strcmp (host
, "20010db8000000000000000000000001.v6.example") == 0);
300 TEST_VERIFY (strcmp (service
, "80") == 0);
304 /* Test that gethostbyname2 is mostly not influenced by
309 check_hostent ("gethostbyname2 AF_INET am.example",
310 gethostbyname2 ("am.example", AF_INET
),
312 "address: 192.0.2.17\n");
313 check_hostent ("gethostbyname2 AF_INET a.example",
314 gethostbyname2 ("a.example", AF_INET
),
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
),
330 "address: 192.0.2.17\n");
332 check_hostent ("gethostbyname2 AF_INET6 qm.example",
333 gethostbyname2 ("qm.example", AF_INET6
),
335 "address: 2001:db8::1\n");
336 check_hostent ("gethostbyname2 AF_INET6 q.example",
337 gethostbyname2 ("q.example", AF_INET6
),
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
),
347 "address: 2001:db8::1\n");
348 /* Additional AF_INET6 tests depend on RES_USE_INET6; see below. */
353 /* gethostbyname2 tests with RES_USE_INET6 disabled. */
355 test_get2_no_inet6 (void)
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");
367 /* gethostbyname2 tests with RES_USE_INET6 enabled. */
369 test_get2_inet6 (void)
373 check_hostent ("gethostbyname2 AF_INET6 am.example",
374 gethostbyname2 ("am.example", AF_INET6
),
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");
382 /* Collection of tests which assume no RES_USE_INET6 flag. */
386 check_hostent ("gethostbyname (\"a.example\")",
387 gethostbyname ("a.example"),
389 "address: 192.0.2.17\n");
390 check_hostent ("gethostbyname (\"qa.example\")",
391 gethostbyname ("qa.example"),
393 "address: 192.0.2.17\n");
394 check_hostent ("gethostbyname (\"am.example\")",
395 gethostbyname ("am.example"),
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 ();
415 test_get2_no_inet6 ();
416 test_get2_no_inet6 ();
420 threadfunc (void *ignored
)
422 struct resolv_test
*obj
= resolv_test_start
423 ((struct resolv_redirect_config
)
425 .response_callback
= response
428 TEST_VERIFY ((_res
.options
& RES_USE_INET6
) == 0);
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");
483 TEST_VERIFY (_res
.options
& RES_USE_INET6
);
484 _res
.options
&= ~RES_USE_INET6
;
487 resolv_test_end (obj
);
497 /* Attempt to run on a non-main thread first. */
499 pthread_t thr
= xpthread_create (NULL
, threadfunc
, NULL
);
503 /* Try the main thread next. */
509 #include <support/test-driver.c>