1 /* Test basic nss_dns functionality and the resolver test harness itself.
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/>. */
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
} 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
;
64 support_record_failure ();
65 printf ("error: unexpected QNAME: %s\n", qname
);
68 TEST_VERIFY_EXIT (qclass
== C_IN
);
69 struct resolv_response_flags flags
= {.tc
= force_tcp
&& !ctx
->tcp
};
70 if (requested_qname
== nxdomain
)
71 flags
.rcode
= 3; /* NXDOMAIN */
72 resolv_response_init (b
, flags
);
73 resolv_response_add_question (b
, qname
, qclass
, qtype
);
74 if (requested_qname
== nxdomain
|| flags
.tc
)
77 resolv_response_section (b
, ns_s_an
);
78 switch (requested_qname
)
82 resolv_response_open_record (b
, qname
, qclass
, qtype
, 0);
85 resolv_response_open_record (b
, qname
, qclass
, T_CNAME
, 0);
86 resolv_response_add_name (b
, "www.example");
87 resolv_response_close_record (b
);
88 resolv_response_open_record (b
, "www.example", qclass
, qtype
, 0);
91 FAIL_EXIT1 ("unreachable");
97 char ipv4
[4] = {192, 0, 2, 17};
98 ipv4
[3] += requested_qname
+ 2 * ctx
->tcp
+ 4 * ctx
->server_index
;
99 resolv_response_add_data (b
, &ipv4
, sizeof (ipv4
));
105 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
106 ipv6
[15] += requested_qname
+ 2 * ctx
->tcp
+ 4 * ctx
->server_index
;
107 resolv_response_add_data (b
, &ipv6
, sizeof (ipv6
));
111 support_record_failure ();
112 printf ("error: unexpected QTYPE: %s/%u/%u\n",
113 qname
, qclass
, qtype
);
115 resolv_response_close_record (b
);
119 check_h (const char *name
, int family
, const char *expected
)
121 if (family
== AF_INET
)
123 char *query
= xasprintf ("gethostbyname (\"%s\")", name
);
124 check_hostent (query
, gethostbyname (name
), expected
);
128 char *query
= xasprintf ("gethostbyname2 (\"%s\", %d)", name
, family
);
129 check_hostent (query
, gethostbyname2 (name
, family
), expected
);
133 bool too_small
= true;
134 for (unsigned int offset
= 0; offset
< 8; ++offset
)
135 for (unsigned int size
= 1; too_small
; ++size
)
137 char *buf
= xmalloc (offset
+ size
);
140 struct hostent hostbuf
;
141 struct hostent
*result
;
143 if (family
== AF_INET
)
145 char *query
= xasprintf ("gethostbyname (\"%s\") %u/%u",
147 int ret
= gethostbyname_r
148 (name
, &hostbuf
, buf
+ offset
, size
, &result
, &herror
);
152 check_hostent (query
, result
, expected
);
154 else if (ret
== ERANGE
)
159 FAIL_EXIT1 ("gethostbyname_r: %m");
162 memset (buf
, 0, offset
+ size
);
164 char *query
= xasprintf ("gethostbyname2 (\"%s\", %d) %u/%u",
165 name
, family
, offset
, size
);
166 int ret
= gethostbyname2_r
167 (name
, family
, &hostbuf
, buf
+ offset
, size
, &result
, &herror
);
171 check_hostent (query
, result
, expected
);
173 else if (ret
== ERANGE
)
178 FAIL_EXIT1 ("gethostbyname_r: %m");
186 check_ai_hints (const char *name
, const char *service
,
187 struct addrinfo hints
, const char *expected
)
190 char *query
= xasprintf ("%s:%s [%d]/0x%x", name
, service
,
191 hints
.ai_family
, hints
.ai_flags
);
192 int ret
= getaddrinfo (name
, service
, &hints
, &ai
);
193 check_addrinfo (query
, ai
, ret
, expected
);
200 check_ai (const char *name
, const char *service
,
201 int family
, const char *expected
)
203 return check_ai_hints (name
, service
,
204 (struct addrinfo
) { .ai_family
= family
, },
208 /* Test for bug 21295: getaddrinfo used to discard address information
209 instead of merging it. */
211 test_bug_21295 (void)
213 /* The address order is unpredictable. There are two factors which
214 contribute to that: The stub resolver does not perform proper
215 response matching for A/AAAA queries (an A response could be
216 associated with an AAAA query and vice versa), and without
217 namespaces, system configuration could affect address
219 for (int do_tcp
= 0; do_tcp
< 2; ++do_tcp
)
221 const struct addrinfo hints
=
223 .ai_family
= AF_INET6
,
224 .ai_socktype
= SOCK_STREAM
,
225 .ai_flags
= AI_V4MAPPED
| AI_ALL
,
229 qname
= "t.www.example";
231 qname
= "www.example";
232 struct addrinfo
*ai
= NULL
;
233 int ret
= getaddrinfo (qname
, "80", &hints
, &ai
);
234 TEST_VERIFY_EXIT (ret
== 0);
236 const char *expected_a
;
237 const char *expected_b
;
240 expected_a
= "flags: AI_V4MAPPED AI_ALL\n"
241 "address: STREAM/TCP 2001:db8::3 80\n"
242 "address: STREAM/TCP ::ffff:192.0.2.19 80\n";
243 expected_b
= "flags: AI_V4MAPPED AI_ALL\n"
244 "address: STREAM/TCP ::ffff:192.0.2.19 80\n"
245 "address: STREAM/TCP 2001:db8::3 80\n";
249 expected_a
= "flags: AI_V4MAPPED AI_ALL\n"
250 "address: STREAM/TCP 2001:db8::1 80\n"
251 "address: STREAM/TCP ::ffff:192.0.2.17 80\n";
252 expected_b
= "flags: AI_V4MAPPED AI_ALL\n"
253 "address: STREAM/TCP ::ffff:192.0.2.17 80\n"
254 "address: STREAM/TCP 2001:db8::1 80\n";
257 char *actual
= support_format_addrinfo (ai
, ret
);
258 if (!(strcmp (actual
, expected_a
) == 0
259 || strcmp (actual
, expected_b
) == 0))
261 support_record_failure ();
262 printf ("error: %s: unexpected response (TCP: %d):\n%s\n",
263 __func__
, do_tcp
, actual
);
273 struct resolv_test
*aux
= resolv_test_start
274 ((struct resolv_redirect_config
)
276 .response_callback
= response
,
279 check_h ("www.example", AF_INET
,
280 "name: www.example\n"
281 "address: 192.0.2.17\n");
282 check_h ("alias.example", AF_INET
,
283 "name: www.example\n"
284 "alias: alias.example\n"
285 "address: 192.0.2.18\n");
286 check_h ("www.example", AF_INET6
,
287 "name: www.example\n"
288 "address: 2001:db8::1\n");
289 check_h ("alias.example", AF_INET6
,
290 "name: www.example\n"
291 "alias: alias.example\n"
292 "address: 2001:db8::2\n");
293 check_h (LONG_NAME
, AF_INET
,
294 "name: " LONG_NAME
"\n"
295 "address: 192.0.2.20\n");
297 check_ai ("www.example", "80", AF_UNSPEC
,
298 "address: STREAM/TCP 192.0.2.17 80\n"
299 "address: DGRAM/UDP 192.0.2.17 80\n"
300 "address: RAW/IP 192.0.2.17 80\n"
301 "address: STREAM/TCP 2001:db8::1 80\n"
302 "address: DGRAM/UDP 2001:db8::1 80\n"
303 "address: RAW/IP 2001:db8::1 80\n");
304 check_ai_hints ("www.example", "80",
305 (struct addrinfo
) { .ai_family
= AF_UNSPEC
,
306 .ai_flags
= AI_CANONNAME
, },
307 "flags: AI_CANONNAME\n"
308 "canonname: www.example\n"
309 "address: STREAM/TCP 192.0.2.17 80\n"
310 "address: DGRAM/UDP 192.0.2.17 80\n"
311 "address: RAW/IP 192.0.2.17 80\n"
312 "address: STREAM/TCP 2001:db8::1 80\n"
313 "address: DGRAM/UDP 2001:db8::1 80\n"
314 "address: RAW/IP 2001:db8::1 80\n");
315 check_ai ("alias.example", "80", AF_UNSPEC
,
316 "address: STREAM/TCP 192.0.2.18 80\n"
317 "address: DGRAM/UDP 192.0.2.18 80\n"
318 "address: RAW/IP 192.0.2.18 80\n"
319 "address: STREAM/TCP 2001:db8::2 80\n"
320 "address: DGRAM/UDP 2001:db8::2 80\n"
321 "address: RAW/IP 2001:db8::2 80\n");
322 check_ai_hints ("alias.example", "80",
323 (struct addrinfo
) { .ai_family
= AF_UNSPEC
,
324 .ai_flags
= AI_CANONNAME
, },
325 "flags: AI_CANONNAME\n"
326 "canonname: www.example\n"
327 "address: STREAM/TCP 192.0.2.18 80\n"
328 "address: DGRAM/UDP 192.0.2.18 80\n"
329 "address: RAW/IP 192.0.2.18 80\n"
330 "address: STREAM/TCP 2001:db8::2 80\n"
331 "address: DGRAM/UDP 2001:db8::2 80\n"
332 "address: RAW/IP 2001:db8::2 80\n");
333 check_ai (LONG_NAME
, "80", AF_UNSPEC
,
334 "address: STREAM/TCP 192.0.2.20 80\n"
335 "address: DGRAM/UDP 192.0.2.20 80\n"
336 "address: RAW/IP 192.0.2.20 80\n"
337 "address: STREAM/TCP 2001:db8::4 80\n"
338 "address: DGRAM/UDP 2001:db8::4 80\n"
339 "address: RAW/IP 2001:db8::4 80\n");
340 check_ai ("www.example", "80", AF_INET
,
341 "address: STREAM/TCP 192.0.2.17 80\n"
342 "address: DGRAM/UDP 192.0.2.17 80\n"
343 "address: RAW/IP 192.0.2.17 80\n");
344 check_ai_hints ("www.example", "80",
345 (struct addrinfo
) { .ai_family
= AF_INET
,
346 .ai_flags
= AI_CANONNAME
, },
347 "flags: AI_CANONNAME\n"
348 "canonname: www.example\n"
349 "address: STREAM/TCP 192.0.2.17 80\n"
350 "address: DGRAM/UDP 192.0.2.17 80\n"
351 "address: RAW/IP 192.0.2.17 80\n");
352 check_ai ("alias.example", "80", AF_INET
,
353 "address: STREAM/TCP 192.0.2.18 80\n"
354 "address: DGRAM/UDP 192.0.2.18 80\n"
355 "address: RAW/IP 192.0.2.18 80\n");
356 check_ai_hints ("alias.example", "80",
357 (struct addrinfo
) { .ai_family
= AF_INET
,
358 .ai_flags
= AI_CANONNAME
, },
359 "flags: AI_CANONNAME\n"
360 "canonname: www.example\n"
361 "address: STREAM/TCP 192.0.2.18 80\n"
362 "address: DGRAM/UDP 192.0.2.18 80\n"
363 "address: RAW/IP 192.0.2.18 80\n");
364 check_ai (LONG_NAME
, "80", AF_INET
,
365 "address: STREAM/TCP 192.0.2.20 80\n"
366 "address: DGRAM/UDP 192.0.2.20 80\n"
367 "address: RAW/IP 192.0.2.20 80\n");
368 check_ai ("www.example", "80", AF_INET6
,
369 "address: STREAM/TCP 2001:db8::1 80\n"
370 "address: DGRAM/UDP 2001:db8::1 80\n"
371 "address: RAW/IP 2001:db8::1 80\n");
372 check_ai_hints ("www.example", "80",
373 (struct addrinfo
) { .ai_family
= AF_INET6
,
374 .ai_flags
= AI_CANONNAME
, },
375 "flags: AI_CANONNAME\n"
376 "canonname: www.example\n"
377 "address: STREAM/TCP 2001:db8::1 80\n"
378 "address: DGRAM/UDP 2001:db8::1 80\n"
379 "address: RAW/IP 2001:db8::1 80\n");
380 check_ai ("alias.example", "80", AF_INET6
,
381 "address: STREAM/TCP 2001:db8::2 80\n"
382 "address: DGRAM/UDP 2001:db8::2 80\n"
383 "address: RAW/IP 2001:db8::2 80\n");
384 check_ai_hints ("alias.example", "80",
385 (struct addrinfo
) { .ai_family
= AF_INET6
,
386 .ai_flags
= AI_CANONNAME
, },
387 "flags: AI_CANONNAME\n"
388 "canonname: www.example\n"
389 "address: STREAM/TCP 2001:db8::2 80\n"
390 "address: DGRAM/UDP 2001:db8::2 80\n"
391 "address: RAW/IP 2001:db8::2 80\n");
392 check_ai (LONG_NAME
, "80", AF_INET6
,
393 "address: STREAM/TCP 2001:db8::4 80\n"
394 "address: DGRAM/UDP 2001:db8::4 80\n"
395 "address: RAW/IP 2001:db8::4 80\n");
397 check_h ("t.www.example", AF_INET
,
398 "name: t.www.example\n"
399 "address: 192.0.2.19\n");
400 check_h ("t.alias.example", AF_INET
,
401 "name: www.example\n"
402 "alias: t.alias.example\n"
403 "address: 192.0.2.20\n");
404 check_h ("t.www.example", AF_INET6
,
405 "name: t.www.example\n"
406 "address: 2001:db8::3\n");
407 check_h ("t.alias.example", AF_INET6
,
408 "name: www.example\n"
409 "alias: t.alias.example\n"
410 "address: 2001:db8::4\n");
411 check_ai ("t.www.example", "80", AF_UNSPEC
,
412 "address: STREAM/TCP 192.0.2.19 80\n"
413 "address: DGRAM/UDP 192.0.2.19 80\n"
414 "address: RAW/IP 192.0.2.19 80\n"
415 "address: STREAM/TCP 2001:db8::3 80\n"
416 "address: DGRAM/UDP 2001:db8::3 80\n"
417 "address: RAW/IP 2001:db8::3 80\n");
418 check_ai ("t.alias.example", "80", AF_UNSPEC
,
419 "address: STREAM/TCP 192.0.2.20 80\n"
420 "address: DGRAM/UDP 192.0.2.20 80\n"
421 "address: RAW/IP 192.0.2.20 80\n"
422 "address: STREAM/TCP 2001:db8::4 80\n"
423 "address: DGRAM/UDP 2001:db8::4 80\n"
424 "address: RAW/IP 2001:db8::4 80\n");
425 check_ai ("t.www.example", "80", AF_INET
,
426 "address: STREAM/TCP 192.0.2.19 80\n"
427 "address: DGRAM/UDP 192.0.2.19 80\n"
428 "address: RAW/IP 192.0.2.19 80\n");
429 check_ai ("t.alias.example", "80", AF_INET
,
430 "address: STREAM/TCP 192.0.2.20 80\n"
431 "address: DGRAM/UDP 192.0.2.20 80\n"
432 "address: RAW/IP 192.0.2.20 80\n");
433 check_ai ("t.www.example", "80", AF_INET6
,
434 "address: STREAM/TCP 2001:db8::3 80\n"
435 "address: DGRAM/UDP 2001:db8::3 80\n"
436 "address: RAW/IP 2001:db8::3 80\n");
437 check_ai ("t.alias.example", "80", AF_INET6
,
438 "address: STREAM/TCP 2001:db8::4 80\n"
439 "address: DGRAM/UDP 2001:db8::4 80\n"
440 "address: RAW/IP 2001:db8::4 80\n");
442 check_h ("nxdomain.example", AF_INET
,
443 "error: HOST_NOT_FOUND\n");
444 check_h ("nxdomain.example", AF_INET6
,
445 "error: HOST_NOT_FOUND\n");
446 check_ai ("nxdomain.example", "80", AF_UNSPEC
,
447 "error: Name or service not known\n");
448 check_ai ("nxdomain.example", "80", AF_INET
,
449 "error: Name or service not known\n");
450 check_ai ("nxdomain.example", "80", AF_INET6
,
451 "error: Name or service not known\n");
453 check_h ("t.nxdomain.example", AF_INET
,
454 "error: HOST_NOT_FOUND\n");
455 check_h ("t.nxdomain.example", AF_INET6
,
456 "error: HOST_NOT_FOUND\n");
457 check_ai ("t.nxdomain.example", "80", AF_UNSPEC
,
458 "error: Name or service not known\n");
459 check_ai ("t.nxdomain.example", "80", AF_INET
,
460 "error: Name or service not known\n");
461 check_ai ("t.nxdomain.example", "80", AF_INET6
,
462 "error: Name or service not known\n");
466 resolv_test_end (aux
);
471 #include <support/test-driver.c>