1 /* Test basic nss_dns functionality and the resolver test harness itself.
2 Copyright (C) 2016-2023 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 <https://www.gnu.org/licenses/>. */
23 #include <support/check.h>
24 #include <support/check_nss.h>
25 #include <support/format_nss.h>
26 #include <support/resolv_test.h>
27 #include <support/support.h>
30 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax." \
31 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay." \
32 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz." \
33 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaat"
36 response (const struct resolv_response_context
*ctx
,
37 struct resolv_response_builder
*b
,
38 const char *qname
, uint16_t qclass
, uint16_t qtype
)
40 TEST_VERIFY_EXIT (qname
!= NULL
);
42 /* The "t." prefix can be used to request TCP fallback. */
44 if (strncmp ("t.", qname
, 2) == 0)
48 const char *qname_compare
;
50 qname_compare
= qname
+ 2;
52 qname_compare
= qname
;
53 enum {www
, alias
, nxdomain
, long_name
, nodata
} requested_qname
;
54 if (strcmp (qname_compare
, "www.example") == 0)
55 requested_qname
= www
;
56 else if (strcmp (qname_compare
, "alias.example") == 0)
57 requested_qname
= alias
;
58 else if (strcmp (qname_compare
, "nxdomain.example") == 0)
59 requested_qname
= nxdomain
;
60 else if (strcmp (qname_compare
, LONG_NAME
) == 0)
61 requested_qname
= long_name
;
62 else if (strcmp (qname_compare
, "nodata.example") == 0)
63 requested_qname
= nodata
;
66 support_record_failure ();
67 printf ("error: unexpected QNAME: %s\n", qname
);
70 TEST_VERIFY_EXIT (qclass
== C_IN
);
71 struct resolv_response_flags flags
= {.tc
= force_tcp
&& !ctx
->tcp
};
72 if (requested_qname
== nxdomain
)
73 flags
.rcode
= 3; /* NXDOMAIN */
74 resolv_response_init (b
, flags
);
75 resolv_response_add_question (b
, qname
, qclass
, qtype
);
76 if (requested_qname
== nxdomain
|| flags
.tc
)
79 resolv_response_section (b
, ns_s_an
);
80 switch (requested_qname
)
84 resolv_response_open_record (b
, qname
, qclass
, qtype
, 0);
87 resolv_response_open_record (b
, qname
, qclass
, T_CNAME
, 0);
88 resolv_response_add_name (b
, "www.example");
89 resolv_response_close_record (b
);
90 resolv_response_open_record (b
, "www.example", qclass
, qtype
, 0);
95 FAIL_EXIT1 ("unreachable");
101 char ipv4
[4] = {192, 0, 2, 17};
102 ipv4
[3] += requested_qname
+ 2 * ctx
->tcp
+ 4 * ctx
->server_index
;
103 resolv_response_add_data (b
, &ipv4
, sizeof (ipv4
));
109 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
110 ipv6
[15] += requested_qname
+ 2 * ctx
->tcp
+ 4 * ctx
->server_index
;
111 resolv_response_add_data (b
, &ipv6
, sizeof (ipv6
));
115 support_record_failure ();
116 printf ("error: unexpected QTYPE: %s/%u/%u\n",
117 qname
, qclass
, qtype
);
119 resolv_response_close_record (b
);
123 check_h (const char *name
, int family
, const char *expected
)
125 if (family
== AF_INET
)
127 char *query
= xasprintf ("gethostbyname (\"%s\")", name
);
128 check_hostent (query
, gethostbyname (name
), expected
);
132 char *query
= xasprintf ("gethostbyname2 (\"%s\", %d)", name
, family
);
133 check_hostent (query
, gethostbyname2 (name
, family
), expected
);
137 bool too_small
= true;
138 for (unsigned int offset
= 0; offset
< 8; ++offset
)
139 for (unsigned int size
= 1; too_small
; ++size
)
141 char *buf
= xmalloc (offset
+ size
);
144 struct hostent hostbuf
;
145 struct hostent
*result
;
147 if (family
== AF_INET
)
149 char *query
= xasprintf ("gethostbyname (\"%s\") %u/%u",
151 int ret
= gethostbyname_r
152 (name
, &hostbuf
, buf
+ offset
, size
, &result
, &herror
);
156 check_hostent (query
, result
, expected
);
158 else if (ret
== ERANGE
)
163 FAIL_EXIT1 ("gethostbyname_r: %m");
166 memset (buf
, 0, offset
+ size
);
168 char *query
= xasprintf ("gethostbyname2 (\"%s\", %d) %u/%u",
169 name
, family
, offset
, size
);
170 int ret
= gethostbyname2_r
171 (name
, family
, &hostbuf
, buf
+ offset
, size
, &result
, &herror
);
175 check_hostent (query
, result
, expected
);
177 else if (ret
== ERANGE
)
182 FAIL_EXIT1 ("gethostbyname_r: %m");
190 check_ai_hints (const char *name
, const char *service
,
191 struct addrinfo hints
, const char *expected
)
194 char *query
= xasprintf ("%s:%s [%d]/0x%x", name
, service
,
195 hints
.ai_family
, hints
.ai_flags
);
196 int ret
= getaddrinfo (name
, service
, &hints
, &ai
);
197 check_addrinfo (query
, ai
, ret
, expected
);
204 check_ai (const char *name
, const char *service
,
205 int family
, const char *expected
)
207 return check_ai_hints (name
, service
,
208 (struct addrinfo
) { .ai_family
= family
, },
212 /* Test for bug 21295: getaddrinfo used to discard address information
213 instead of merging it. */
215 test_bug_21295 (void)
217 /* The address order is unpredictable. There are two factors which
218 contribute to that: The stub resolver does not perform proper
219 response matching for A/AAAA queries (an A response could be
220 associated with an AAAA query and vice versa), and without
221 namespaces, system configuration could affect address
223 for (int do_tcp
= 0; do_tcp
< 2; ++do_tcp
)
225 const struct addrinfo hints
=
227 .ai_family
= AF_INET6
,
228 .ai_socktype
= SOCK_STREAM
,
229 .ai_flags
= AI_V4MAPPED
| AI_ALL
,
233 qname
= "t.www.example";
235 qname
= "www.example";
236 struct addrinfo
*ai
= NULL
;
237 int ret
= getaddrinfo (qname
, "80", &hints
, &ai
);
238 TEST_VERIFY_EXIT (ret
== 0);
240 const char *expected_a
;
241 const char *expected_b
;
244 expected_a
= "flags: AI_V4MAPPED AI_ALL\n"
245 "address: STREAM/TCP 2001:db8::3 80\n"
246 "address: STREAM/TCP ::ffff:192.0.2.19 80\n";
247 expected_b
= "flags: AI_V4MAPPED AI_ALL\n"
248 "address: STREAM/TCP ::ffff:192.0.2.19 80\n"
249 "address: STREAM/TCP 2001:db8::3 80\n";
253 expected_a
= "flags: AI_V4MAPPED AI_ALL\n"
254 "address: STREAM/TCP 2001:db8::1 80\n"
255 "address: STREAM/TCP ::ffff:192.0.2.17 80\n";
256 expected_b
= "flags: AI_V4MAPPED AI_ALL\n"
257 "address: STREAM/TCP ::ffff:192.0.2.17 80\n"
258 "address: STREAM/TCP 2001:db8::1 80\n";
261 char *actual
= support_format_addrinfo (ai
, ret
);
262 if (!(strcmp (actual
, expected_a
) == 0
263 || strcmp (actual
, expected_b
) == 0))
265 support_record_failure ();
266 printf ("error: %s: unexpected response (TCP: %d):\n%s\n",
267 __func__
, do_tcp
, actual
);
274 /* Run tests which do not expect any data. */
276 test_nodata_nxdomain (void)
278 /* Iterate through different address families. */
279 int families
[] = { AF_UNSPEC
, AF_INET
, AF_INET6
, -1 };
280 for (int i
= 0; families
[i
] >= 0; ++i
)
281 /* If do_tcp, prepend "t." to the name to trigger TCP
283 for (int do_tcp
= 0; do_tcp
< 2; ++do_tcp
)
284 /* If do_nxdomain, trigger an NXDOMAIN error (DNS failure),
285 otherwise use a NODATA response (empty but successful
287 for (int do_nxdomain
= 0; do_nxdomain
< 2; ++do_nxdomain
)
289 int family
= families
[i
];
290 char *name
= xasprintf ("%s%s.example",
292 do_nxdomain
? "nxdomain" : "nodata");
294 if (family
!= AF_UNSPEC
)
297 check_h (name
, family
, "error: HOST_NOT_FOUND\n");
299 check_h (name
, family
, "error: NO_ADDRESS\n");
302 const char *expected
;
304 expected
= "error: Name or service not known\n";
306 expected
= "error: No address associated with hostname\n";
308 check_ai (name
, "80", family
, expected
);
310 struct addrinfo hints
=
313 .ai_flags
= AI_V4MAPPED
| AI_ALL
,
315 check_ai_hints (name
, "80", hints
, expected
);
316 hints
.ai_flags
|= AI_CANONNAME
;
317 check_ai_hints (name
, "80", hints
, expected
);
326 struct resolv_test
*aux
= resolv_test_start
327 ((struct resolv_redirect_config
)
329 .response_callback
= response
,
332 check_h ("www.example", AF_INET
,
333 "name: www.example\n"
334 "address: 192.0.2.17\n");
335 check_h ("alias.example", AF_INET
,
336 "name: www.example\n"
337 "alias: alias.example\n"
338 "address: 192.0.2.18\n");
339 check_h ("www.example", AF_INET6
,
340 "name: www.example\n"
341 "address: 2001:db8::1\n");
342 check_h ("alias.example", AF_INET6
,
343 "name: www.example\n"
344 "alias: alias.example\n"
345 "address: 2001:db8::2\n");
346 check_h (LONG_NAME
, AF_INET
,
347 "name: " LONG_NAME
"\n"
348 "address: 192.0.2.20\n");
350 check_ai ("www.example", "80", AF_UNSPEC
,
351 "address: STREAM/TCP 192.0.2.17 80\n"
352 "address: DGRAM/UDP 192.0.2.17 80\n"
353 "address: RAW/IP 192.0.2.17 80\n"
354 "address: STREAM/TCP 2001:db8::1 80\n"
355 "address: DGRAM/UDP 2001:db8::1 80\n"
356 "address: RAW/IP 2001:db8::1 80\n");
357 check_ai_hints ("www.example", "80",
358 (struct addrinfo
) { .ai_family
= AF_UNSPEC
,
359 .ai_flags
= AI_CANONNAME
, },
360 "flags: AI_CANONNAME\n"
361 "canonname: www.example\n"
362 "address: STREAM/TCP 192.0.2.17 80\n"
363 "address: DGRAM/UDP 192.0.2.17 80\n"
364 "address: RAW/IP 192.0.2.17 80\n"
365 "address: STREAM/TCP 2001:db8::1 80\n"
366 "address: DGRAM/UDP 2001:db8::1 80\n"
367 "address: RAW/IP 2001:db8::1 80\n");
368 check_ai ("alias.example", "80", AF_UNSPEC
,
369 "address: STREAM/TCP 192.0.2.18 80\n"
370 "address: DGRAM/UDP 192.0.2.18 80\n"
371 "address: RAW/IP 192.0.2.18 80\n"
372 "address: STREAM/TCP 2001:db8::2 80\n"
373 "address: DGRAM/UDP 2001:db8::2 80\n"
374 "address: RAW/IP 2001:db8::2 80\n");
375 check_ai_hints ("alias.example", "80",
376 (struct addrinfo
) { .ai_family
= AF_UNSPEC
,
377 .ai_flags
= AI_CANONNAME
, },
378 "flags: AI_CANONNAME\n"
379 "canonname: www.example\n"
380 "address: STREAM/TCP 192.0.2.18 80\n"
381 "address: DGRAM/UDP 192.0.2.18 80\n"
382 "address: RAW/IP 192.0.2.18 80\n"
383 "address: STREAM/TCP 2001:db8::2 80\n"
384 "address: DGRAM/UDP 2001:db8::2 80\n"
385 "address: RAW/IP 2001:db8::2 80\n");
386 check_ai (LONG_NAME
, "80", AF_UNSPEC
,
387 "address: STREAM/TCP 192.0.2.20 80\n"
388 "address: DGRAM/UDP 192.0.2.20 80\n"
389 "address: RAW/IP 192.0.2.20 80\n"
390 "address: STREAM/TCP 2001:db8::4 80\n"
391 "address: DGRAM/UDP 2001:db8::4 80\n"
392 "address: RAW/IP 2001:db8::4 80\n");
393 check_ai ("www.example", "80", AF_INET
,
394 "address: STREAM/TCP 192.0.2.17 80\n"
395 "address: DGRAM/UDP 192.0.2.17 80\n"
396 "address: RAW/IP 192.0.2.17 80\n");
397 check_ai_hints ("www.example", "80",
398 (struct addrinfo
) { .ai_family
= AF_INET
,
399 .ai_flags
= AI_CANONNAME
, },
400 "flags: AI_CANONNAME\n"
401 "canonname: www.example\n"
402 "address: STREAM/TCP 192.0.2.17 80\n"
403 "address: DGRAM/UDP 192.0.2.17 80\n"
404 "address: RAW/IP 192.0.2.17 80\n");
405 check_ai ("alias.example", "80", AF_INET
,
406 "address: STREAM/TCP 192.0.2.18 80\n"
407 "address: DGRAM/UDP 192.0.2.18 80\n"
408 "address: RAW/IP 192.0.2.18 80\n");
409 check_ai_hints ("alias.example", "80",
410 (struct addrinfo
) { .ai_family
= AF_INET
,
411 .ai_flags
= AI_CANONNAME
, },
412 "flags: AI_CANONNAME\n"
413 "canonname: www.example\n"
414 "address: STREAM/TCP 192.0.2.18 80\n"
415 "address: DGRAM/UDP 192.0.2.18 80\n"
416 "address: RAW/IP 192.0.2.18 80\n");
417 check_ai (LONG_NAME
, "80", AF_INET
,
418 "address: STREAM/TCP 192.0.2.20 80\n"
419 "address: DGRAM/UDP 192.0.2.20 80\n"
420 "address: RAW/IP 192.0.2.20 80\n");
421 check_ai ("www.example", "80", AF_INET6
,
422 "address: STREAM/TCP 2001:db8::1 80\n"
423 "address: DGRAM/UDP 2001:db8::1 80\n"
424 "address: RAW/IP 2001:db8::1 80\n");
425 check_ai_hints ("www.example", "80",
426 (struct addrinfo
) { .ai_family
= AF_INET6
,
427 .ai_flags
= AI_CANONNAME
, },
428 "flags: AI_CANONNAME\n"
429 "canonname: www.example\n"
430 "address: STREAM/TCP 2001:db8::1 80\n"
431 "address: DGRAM/UDP 2001:db8::1 80\n"
432 "address: RAW/IP 2001:db8::1 80\n");
433 check_ai ("alias.example", "80", AF_INET6
,
434 "address: STREAM/TCP 2001:db8::2 80\n"
435 "address: DGRAM/UDP 2001:db8::2 80\n"
436 "address: RAW/IP 2001:db8::2 80\n");
437 check_ai_hints ("alias.example", "80",
438 (struct addrinfo
) { .ai_family
= AF_INET6
,
439 .ai_flags
= AI_CANONNAME
, },
440 "flags: AI_CANONNAME\n"
441 "canonname: www.example\n"
442 "address: STREAM/TCP 2001:db8::2 80\n"
443 "address: DGRAM/UDP 2001:db8::2 80\n"
444 "address: RAW/IP 2001:db8::2 80\n");
445 check_ai (LONG_NAME
, "80", AF_INET6
,
446 "address: STREAM/TCP 2001:db8::4 80\n"
447 "address: DGRAM/UDP 2001:db8::4 80\n"
448 "address: RAW/IP 2001:db8::4 80\n");
450 check_h ("t.www.example", AF_INET
,
451 "name: t.www.example\n"
452 "address: 192.0.2.19\n");
453 check_h ("t.alias.example", AF_INET
,
454 "name: www.example\n"
455 "alias: t.alias.example\n"
456 "address: 192.0.2.20\n");
457 check_h ("t.www.example", AF_INET6
,
458 "name: t.www.example\n"
459 "address: 2001:db8::3\n");
460 check_h ("t.alias.example", AF_INET6
,
461 "name: www.example\n"
462 "alias: t.alias.example\n"
463 "address: 2001:db8::4\n");
464 check_ai ("t.www.example", "80", AF_UNSPEC
,
465 "address: STREAM/TCP 192.0.2.19 80\n"
466 "address: DGRAM/UDP 192.0.2.19 80\n"
467 "address: RAW/IP 192.0.2.19 80\n"
468 "address: STREAM/TCP 2001:db8::3 80\n"
469 "address: DGRAM/UDP 2001:db8::3 80\n"
470 "address: RAW/IP 2001:db8::3 80\n");
471 check_ai ("t.alias.example", "80", AF_UNSPEC
,
472 "address: STREAM/TCP 192.0.2.20 80\n"
473 "address: DGRAM/UDP 192.0.2.20 80\n"
474 "address: RAW/IP 192.0.2.20 80\n"
475 "address: STREAM/TCP 2001:db8::4 80\n"
476 "address: DGRAM/UDP 2001:db8::4 80\n"
477 "address: RAW/IP 2001:db8::4 80\n");
478 check_ai ("t.www.example", "80", AF_INET
,
479 "address: STREAM/TCP 192.0.2.19 80\n"
480 "address: DGRAM/UDP 192.0.2.19 80\n"
481 "address: RAW/IP 192.0.2.19 80\n");
482 check_ai ("t.alias.example", "80", AF_INET
,
483 "address: STREAM/TCP 192.0.2.20 80\n"
484 "address: DGRAM/UDP 192.0.2.20 80\n"
485 "address: RAW/IP 192.0.2.20 80\n");
486 check_ai ("t.www.example", "80", AF_INET6
,
487 "address: STREAM/TCP 2001:db8::3 80\n"
488 "address: DGRAM/UDP 2001:db8::3 80\n"
489 "address: RAW/IP 2001:db8::3 80\n");
490 check_ai ("t.alias.example", "80", AF_INET6
,
491 "address: STREAM/TCP 2001:db8::4 80\n"
492 "address: DGRAM/UDP 2001:db8::4 80\n"
493 "address: RAW/IP 2001:db8::4 80\n");
496 test_nodata_nxdomain ();
498 resolv_test_end (aux
);
503 #include <support/test-driver.c>