]>
Commit | Line | Data |
---|---|---|
5840c75c | 1 | /* Basic functionality tests for inet6 option processing. |
688903eb | 2 | Copyright (C) 2016-2018 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. */ | |
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 | ||
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 |
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 | { | |
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. */ | |
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; | |
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. */ | |
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 | ||
5e9c4d17 FW |
304 | /* Test that gethostbyname2 is mostly not influenced by |
305 | RES_USE_INET6. */ | |
5840c75c | 306 | static void |
5e9c4d17 | 307 | test_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. */ | |
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"); | |
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 | ||
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 | ||
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 | ||
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> |