Consolidate non cancellable read call
[glibc.git] / resolv / tst-resolv-basic.c
blob64eedbbd81d58d959897601fab6ccad7b396bcd6
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/>. */
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
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>
29 #define LONG_NAME \
30 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax." \
31 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay." \
32 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz." \
33 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaat"
35 static void
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. */
43 bool force_tcp;
44 if (strncmp ("t.", qname, 2) == 0)
45 force_tcp = true;
46 else
47 force_tcp = false;
48 const char *qname_compare;
49 if (force_tcp)
50 qname_compare = qname + 2;
51 else
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;
62 else
64 support_record_failure ();
65 printf ("error: unexpected QNAME: %s\n", qname);
66 return;
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)
75 return;
77 resolv_response_section (b, ns_s_an);
78 switch (requested_qname)
80 case www:
81 case long_name:
82 resolv_response_open_record (b, qname, qclass, qtype, 0);
83 break;
84 case alias:
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);
89 break;
90 case nxdomain:
91 FAIL_EXIT1 ("unreachable");
93 switch (qtype)
95 case T_A:
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));
101 break;
102 case T_AAAA:
104 char ipv6[16]
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));
109 break;
110 default:
111 support_record_failure ();
112 printf ("error: unexpected QTYPE: %s/%u/%u\n",
113 qname, qclass, qtype);
115 resolv_response_close_record (b);
118 static void
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);
125 free (query);
128 char *query = xasprintf ("gethostbyname2 (\"%s\", %d)", name, family);
129 check_hostent (query, gethostbyname2 (name, family), expected);
130 free (query);
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);
138 too_small = false;
140 struct hostent hostbuf;
141 struct hostent *result;
142 int herror;
143 if (family == AF_INET)
145 char *query = xasprintf ("gethostbyname (\"%s\") %u/%u",
146 name, offset, size);
147 int ret = gethostbyname_r
148 (name, &hostbuf, buf + offset, size, &result, &herror);
149 if (ret == 0)
151 h_errno = herror;
152 check_hostent (query, result, expected);
154 else if (ret == ERANGE)
155 too_small = true;
156 else
158 errno = ret;
159 FAIL_EXIT1 ("gethostbyname_r: %m");
161 free (query);
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);
168 if (ret == 0)
170 h_errno = herror;
171 check_hostent (query, result, expected);
173 else if (ret == ERANGE)
174 too_small = true;
175 else
177 errno = ret;
178 FAIL_EXIT1 ("gethostbyname_r: %m");
180 free (buf);
181 free (query);
185 static void
186 check_ai_hints (const char *name, const char *service,
187 struct addrinfo hints, const char *expected)
189 struct addrinfo *ai;
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);
194 if (ret == 0)
195 freeaddrinfo (ai);
196 free (query);
199 static void
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, },
205 expected);
208 /* Test for bug 21295: getaddrinfo used to discard address information
209 instead of merging it. */
210 static void
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
218 ordering. */
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,
227 const char *qname;
228 if (do_tcp)
229 qname = "t.www.example";
230 else
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;
238 if (do_tcp)
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";
247 else
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);
265 free (actual);
266 freeaddrinfo (ai);
270 static int
271 do_test (void)
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");
464 test_bug_21295 ();
466 resolv_test_end (aux);
468 return 0;
471 #include <support/test-driver.c>