1/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18/* Parts of this file are plain copies of the file `gethtnamadr.c' from
19 the bind package and it has the following copyright. */
20
21/*
22 * ++Copyright++ 1985, 1988, 1993
23 * -
24 * Copyright (c) 1985, 1988, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 4. Neither the name of the University nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 * -
51 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
52 *
53 * Permission to use, copy, modify, and distribute this software for any
54 * purpose with or without fee is hereby granted, provided that the above
55 * copyright notice and this permission notice appear in all copies, and that
56 * the name of Digital Equipment Corporation not be used in advertising or
57 * publicity pertaining to distribution of the document or software without
58 * specific, written prior permission.
59 *
60 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
61 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
62 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
63 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
64 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
65 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
66 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
67 * SOFTWARE.
68 * -
69 * --Copyright--
70 */
71
72#include <assert.h>
73#include <ctype.h>
74#include <errno.h>
75#include <netdb.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <stddef.h>
79#include <string.h>
80#include <libc-pointer-arith.h>
81
82#include "nsswitch.h"
83#include <arpa/nameser.h>
84#include <nss_dns.h>
85
86#include <resolv/resolv-internal.h>
87#include <resolv/resolv_context.h>
88
89/* Get implementations of some internal functions. */
90#include <resolv/mapv4v6addr.h>
91#include <resolv/mapv4v6hostent.h>
92
93#define RESOLVSORT
94
95#if PACKETSZ > 65536
96# define MAXPACKET PACKETSZ
97#else
98# define MAXPACKET 65536
99#endif
100/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
101#ifdef MAXHOSTNAMELEN
102# undef MAXHOSTNAMELEN
103#endif
104#define MAXHOSTNAMELEN 256
105
106/* We need this time later. */
107typedef union querybuf
108{
109 HEADER hdr;
110 u_char buf[MAXPACKET];
111} querybuf;
112
113static enum nss_status getanswer_r (struct resolv_context *ctx,
114 const querybuf *answer, int anslen,
115 const char *qname, int qtype,
116 struct hostent *result, char *buffer,
117 size_t buflen, int *errnop, int *h_errnop,
118 int map, int32_t *ttlp, char **canonp);
119
120static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
121 const querybuf *answer2, int anslen2,
122 const char *qname,
123 struct gaih_addrtuple **pat,
124 char *buffer, size_t buflen,
125 int *errnop, int *h_errnop,
126 int32_t *ttlp);
127
128static enum nss_status gethostbyname3_context (struct resolv_context *ctx,
129 const char *name, int af,
130 struct hostent *result,
131 char *buffer, size_t buflen,
132 int *errnop, int *h_errnop,
133 int32_t *ttlp,
134 char **canonp);
135
136/* Return the expected RDATA length for an address record type (A or
137 AAAA). */
138static int
139rrtype_to_rdata_length (int type)
140{
141 switch (type)
142 {
143 case T_A:
144 return INADDRSZ;
145 case T_AAAA:
146 return IN6ADDRSZ;
147 default:
148 return -1;
149 }
150}
151
152
153enum nss_status
154_nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
155 char *buffer, size_t buflen, int *errnop,
156 int *h_errnop, int32_t *ttlp, char **canonp)
157{
158 struct resolv_context *ctx = __resolv_context_get ();
159 if (ctx == NULL)
160 {
161 *errnop = errno;
162 *h_errnop = NETDB_INTERNAL;
163 return NSS_STATUS_UNAVAIL;
164 }
165 enum nss_status status = gethostbyname3_context
166 (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
167 __resolv_context_put (ctx);
168 return status;
169}
170libc_hidden_def (_nss_dns_gethostbyname3_r)
171
172static enum nss_status
173gethostbyname3_context (struct resolv_context *ctx,
174 const char *name, int af, struct hostent *result,
175 char *buffer, size_t buflen, int *errnop,
176 int *h_errnop, int32_t *ttlp, char **canonp)
177{
178 union
179 {
180 querybuf *buf;
181 u_char *ptr;
182 } host_buffer;
183 querybuf *orig_host_buffer;
184 char tmp[NS_MAXDNAME];
185 int size, type, n;
186 const char *cp;
187 int map = 0;
188 int olderr = errno;
189 enum nss_status status;
190
191 switch (af) {
192 case AF_INET:
193 size = INADDRSZ;
194 type = T_A;
195 break;
196 case AF_INET6:
197 size = IN6ADDRSZ;
198 type = T_AAAA;
199 break;
200 default:
201 *h_errnop = NO_DATA;
202 *errnop = EAFNOSUPPORT;
203 return NSS_STATUS_UNAVAIL;
204 }
205
206 result->h_addrtype = af;
207 result->h_length = size;
208
209 /*
210 * if there aren't any dots, it could be a user-level alias.
211 * this is also done in res_query() since we are not the only
212 * function that looks up host names.
213 */
214 if (strchr (name, '.') == NULL
215 && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
216 name = cp;
217
218 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
219
220 n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
221 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
222 if (n < 0)
223 {
224 switch (errno)
225 {
226 case ESRCH:
227 status = NSS_STATUS_TRYAGAIN;
228 h_errno = TRY_AGAIN;
229 break;
230 /* System has run out of file descriptors. */
231 case EMFILE:
232 case ENFILE:
233 h_errno = NETDB_INTERNAL;
234 /* Fall through. */
235 case ECONNREFUSED:
236 case ETIMEDOUT:
237 status = NSS_STATUS_UNAVAIL;
238 break;
239 default:
240 status = NSS_STATUS_NOTFOUND;
241 break;
242 }
243 *h_errnop = h_errno;
244 if (h_errno == TRY_AGAIN)
245 *errnop = EAGAIN;
246 else
247 __set_errno (olderr);
248
249 /* If we are looking for an IPv6 address and mapping is enabled
250 by having the RES_USE_INET6 bit in _res.options set, we try
251 another lookup. */
252 if (af == AF_INET6 && res_use_inet6 ())
253 n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
254 host_buffer.buf != orig_host_buffer
255 ? MAXPACKET : 1024, &host_buffer.ptr,
256 NULL, NULL, NULL, NULL);
257
258 if (n < 0)
259 {
260 if (host_buffer.buf != orig_host_buffer)
261 free (host_buffer.buf);
262 return status;
263 }
264
265 map = 1;
266
267 result->h_addrtype = AF_INET;
268 result->h_length = INADDRSZ;
269 }
270
271 status = getanswer_r
272 (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
273 errnop, h_errnop, map, ttlp, canonp);
274 if (host_buffer.buf != orig_host_buffer)
275 free (host_buffer.buf);
276 return status;
277}
278
279/* Verify that the name looks like a host name. There is no point in
280 sending a query which will not produce a usable name in the
281 response. */
282static enum nss_status
283check_name (const char *name, int *h_errnop)
284{
285 if (__libc_res_hnok (name))
286 return NSS_STATUS_SUCCESS;
287 *h_errnop = HOST_NOT_FOUND;
288 return NSS_STATUS_NOTFOUND;
289}
290
291enum nss_status
292_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
293 char *buffer, size_t buflen, int *errnop,
294 int *h_errnop)
295{
296 enum nss_status status = check_name (name, h_errnop);
297 if (status != NSS_STATUS_SUCCESS)
298 return status;
299 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
300 h_errnop, NULL, NULL);
301}
302libc_hidden_def (_nss_dns_gethostbyname2_r)
303
304enum nss_status
305_nss_dns_gethostbyname_r (const char *name, struct hostent *result,
306 char *buffer, size_t buflen, int *errnop,
307 int *h_errnop)
308{
309 enum nss_status status = check_name (name, h_errnop);
310 if (status != NSS_STATUS_SUCCESS)
311 return status;
312 struct resolv_context *ctx = __resolv_context_get ();
313 if (ctx == NULL)
314 {
315 *errnop = errno;
316 *h_errnop = NETDB_INTERNAL;
317 return NSS_STATUS_UNAVAIL;
318 }
319 status = NSS_STATUS_NOTFOUND;
320 if (res_use_inet6 ())
321 status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
322 buflen, errnop, h_errnop, NULL, NULL);
323 if (status == NSS_STATUS_NOTFOUND)
324 status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
325 buflen, errnop, h_errnop, NULL, NULL);
326 __resolv_context_put (ctx);
327 return status;
328}
329libc_hidden_def (_nss_dns_gethostbyname_r)
330
331enum nss_status
332_nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
333 char *buffer, size_t buflen, int *errnop,
334 int *herrnop, int32_t *ttlp)
335{
336 enum nss_status status = check_name (name, herrnop);
337 if (status != NSS_STATUS_SUCCESS)
338 return status;
339 struct resolv_context *ctx = __resolv_context_get ();
340 if (ctx == NULL)
341 {
342 *errnop = errno;
343 *herrnop = NETDB_INTERNAL;
344 return NSS_STATUS_UNAVAIL;
345 }
346
347 /*
348 * if there aren't any dots, it could be a user-level alias.
349 * this is also done in res_query() since we are not the only
350 * function that looks up host names.
351 */
352 if (strchr (name, '.') == NULL)
353 {
354 char *tmp = alloca (NS_MAXDNAME);
355 const char *cp = __res_context_hostalias (ctx, name, tmp, NS_MAXDNAME);
356 if (cp != NULL)
357 name = cp;
358 }
359
360 union
361 {
362 querybuf *buf;
363 u_char *ptr;
364 } host_buffer;
365 querybuf *orig_host_buffer;
366 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
367 u_char *ans2p = NULL;
368 int nans2p = 0;
369 int resplen2 = 0;
370 int ans2p_malloced = 0;
371
372 int olderr = errno;
373 int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
374 host_buffer.buf->buf, 2048, &host_buffer.ptr,
375 &ans2p, &nans2p, &resplen2, &ans2p_malloced);
376 if (n >= 0)
377 {
378 status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
379 resplen2, name, pat, buffer, buflen,
380 errnop, herrnop, ttlp);
381 }
382 else
383 {
384 switch (errno)
385 {
386 case ESRCH:
387 status = NSS_STATUS_TRYAGAIN;
388 h_errno = TRY_AGAIN;
389 break;
390 /* System has run out of file descriptors. */
391 case EMFILE:
392 case ENFILE:
393 h_errno = NETDB_INTERNAL;
394 /* Fall through. */
395 case ECONNREFUSED:
396 case ETIMEDOUT:
397 status = NSS_STATUS_UNAVAIL;
398 break;
399 default:
400 status = NSS_STATUS_NOTFOUND;
401 break;
402 }
403
404 *herrnop = h_errno;
405 if (h_errno == TRY_AGAIN)
406 *errnop = EAGAIN;
407 else
408 __set_errno (olderr);
409 }
410
411 /* Check whether ans2p was separately allocated. */
412 if (ans2p_malloced)
413 free (ans2p);
414
415 if (host_buffer.buf != orig_host_buffer)
416 free (host_buffer.buf);
417
418 __resolv_context_put (ctx);
419 return status;
420}
421libc_hidden_def (_nss_dns_gethostbyname4_r)
422
423enum nss_status
424_nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
425 struct hostent *result, char *buffer, size_t buflen,
426 int *errnop, int *h_errnop, int32_t *ttlp)
427{
428 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
429 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
430 static const u_char v6local[] = { 0,0, 0,1 };
431 const u_char *uaddr = (const u_char *)addr;
432 struct host_data
433 {
434 char *aliases[MAX_NR_ALIASES];
435 unsigned char host_addr[16]; /* IPv4 or IPv6 */
436 char *h_addr_ptrs[MAX_NR_ADDRS + 1];
437 char linebuffer[0];
438 } *host_data = (struct host_data *) buffer;
439 union
440 {
441 querybuf *buf;
442 u_char *ptr;
443 } host_buffer;
444 querybuf *orig_host_buffer;
445 char qbuf[MAXDNAME+1], *qp = NULL;
446 size_t size;
447 int n, status;
448 int olderr = errno;
449
450 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
451 buffer += pad;
452 buflen = buflen > pad ? buflen - pad : 0;
453
454 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
455 {
456 *errnop = ERANGE;
457 *h_errnop = NETDB_INTERNAL;
458 return NSS_STATUS_TRYAGAIN;
459 }
460
461 host_data = (struct host_data *) buffer;
462
463 struct resolv_context *ctx = __resolv_context_get ();
464 if (ctx == NULL)
465 {
466 *errnop = errno;
467 *h_errnop = NETDB_INTERNAL;
468 return NSS_STATUS_UNAVAIL;
469 }
470
471 if (af == AF_INET6 && len == IN6ADDRSZ
472 && (memcmp (uaddr, mapped, sizeof mapped) == 0
473 || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
474 && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
475 {
476 /* Unmap. */
477 addr += sizeof mapped;
478 uaddr += sizeof mapped;
479 af = AF_INET;
480 len = INADDRSZ;
481 }
482
483 switch (af)
484 {
485 case AF_INET:
486 size = INADDRSZ;
487 break;
488 case AF_INET6:
489 size = IN6ADDRSZ;
490 break;
491 default:
492 *errnop = EAFNOSUPPORT;
493 *h_errnop = NETDB_INTERNAL;
494 __resolv_context_put (ctx);
495 return NSS_STATUS_UNAVAIL;
496 }
497 if (size > len)
498 {
499 *errnop = EAFNOSUPPORT;
500 *h_errnop = NETDB_INTERNAL;
501 __resolv_context_put (ctx);
502 return NSS_STATUS_UNAVAIL;
503 }
504
505 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
506
507 switch (af)
508 {
509 case AF_INET:
510 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
511 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
512 break;
513 case AF_INET6:
514 qp = qbuf;
515 for (n = IN6ADDRSZ - 1; n >= 0; n--)
516 {
517 static const char nibblechar[16] = "0123456789abcdef";
518 *qp++ = nibblechar[uaddr[n] & 0xf];
519 *qp++ = '.';
520 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
521 *qp++ = '.';
522 }
523 strcpy(qp, "ip6.arpa");
524 break;
525 default:
526 /* Cannot happen. */
527 break;
528 }
529
530 n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
531 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
532 if (n < 0)
533 {
534 *h_errnop = h_errno;
535 __set_errno (olderr);
536 if (host_buffer.buf != orig_host_buffer)
537 free (host_buffer.buf);
538 __resolv_context_put (ctx);
539 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
540 }
541
542 status = getanswer_r
543 (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
544 errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
545 if (host_buffer.buf != orig_host_buffer)
546 free (host_buffer.buf);
547 if (status != NSS_STATUS_SUCCESS)
548 {
549 __resolv_context_put (ctx);
550 return status;
551 }
552
553 result->h_addrtype = af;
554 result->h_length = len;
555 memcpy (host_data->host_addr, addr, len);
556 host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
557 host_data->h_addr_ptrs[1] = NULL;
558 *h_errnop = NETDB_SUCCESS;
559 __resolv_context_put (ctx);
560 return NSS_STATUS_SUCCESS;
561}
562libc_hidden_def (_nss_dns_gethostbyaddr2_r)
563
564
565enum nss_status
566_nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
567 struct hostent *result, char *buffer, size_t buflen,
568 int *errnop, int *h_errnop)
569{
570 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
571 errnop, h_errnop, NULL);
572}
573libc_hidden_def (_nss_dns_gethostbyaddr_r)
574
575static void
576addrsort (struct resolv_context *ctx, char **ap, int num)
577{
578 int i, j;
579 char **p;
580 short aval[MAX_NR_ADDRS];
581 int needsort = 0;
582 size_t nsort = __resolv_context_sort_count (ctx);
583
584 p = ap;
585 if (num > MAX_NR_ADDRS)
586 num = MAX_NR_ADDRS;
587 for (i = 0; i < num; i++, p++)
588 {
589 for (j = 0 ; (unsigned)j < nsort; j++)
590 {
591 struct resolv_sortlist_entry e
592 = __resolv_context_sort_entry (ctx, j);
593 if (e.addr.s_addr == (((struct in_addr *)(*p))->s_addr & e.mask))
594 break;
595 }
596 aval[i] = j;
597 if (needsort == 0 && i > 0 && j < aval[i-1])
598 needsort = i;
599 }
600 if (!needsort)
601 return;
602
603 while (needsort++ < num)
604 for (j = needsort - 2; j >= 0; j--)
605 if (aval[j] > aval[j+1])
606 {
607 char *hp;
608
609 i = aval[j];
610 aval[j] = aval[j+1];
611 aval[j+1] = i;
612
613 hp = ap[j];
614 ap[j] = ap[j+1];
615 ap[j+1] = hp;
616 }
617 else
618 break;
619}
620
621static enum nss_status
622getanswer_r (struct resolv_context *ctx,
623 const querybuf *answer, int anslen, const char *qname, int qtype,
624 struct hostent *result, char *buffer, size_t buflen,
625 int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
626{
627 struct host_data
628 {
629 char *aliases[MAX_NR_ALIASES];
630 unsigned char host_addr[16]; /* IPv4 or IPv6 */
631 char *h_addr_ptrs[0];
632 } *host_data;
633 int linebuflen;
634 const HEADER *hp;
635 const u_char *end_of_message, *cp;
636 int n, ancount, qdcount;
637 int haveanswer, had_error;
638 char *bp, **ap, **hap;
639 char tbuf[MAXDNAME];
640 const char *tname;
641 int (*name_ok) (const char *);
642 u_char packtmp[NS_MAXCDNAME];
643 int have_to_map = 0;
644 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
645 buffer += pad;
646 buflen = buflen > pad ? buflen - pad : 0;
647 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
648 {
649 /* The buffer is too small. */
650 too_small:
651 *errnop = ERANGE;
652 *h_errnop = NETDB_INTERNAL;
653 return NSS_STATUS_TRYAGAIN;
654 }
655 host_data = (struct host_data *) buffer;
656 linebuflen = buflen - sizeof (struct host_data);
657 if (buflen - sizeof (struct host_data) != linebuflen)
658 linebuflen = INT_MAX;
659
660 tname = qname;
661 result->h_name = NULL;
662 end_of_message = answer->buf + anslen;
663 switch (qtype)
664 {
665 case T_A:
666 case T_AAAA:
667 name_ok = __libc_res_hnok;
668 break;
669 case T_PTR:
670 name_ok = __libc_res_dnok;
671 break;
672 default:
673 *errnop = ENOENT;
674 return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
675 }
676
677 /*
678 * find first satisfactory answer
679 */
680 hp = &answer->hdr;
681 ancount = ntohs (hp->ancount);
682 qdcount = ntohs (hp->qdcount);
683 cp = answer->buf + HFIXEDSZ;
684 if (__glibc_unlikely (qdcount != 1))
685 {
686 *h_errnop = NO_RECOVERY;
687 return NSS_STATUS_UNAVAIL;
688 }
689 if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
690 goto too_small;
691 bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
692 linebuflen -= (ancount + 1) * sizeof (char *);
693
694 n = __ns_name_unpack (answer->buf, end_of_message, cp,
695 packtmp, sizeof packtmp);
696 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
697 {
698 if (__glibc_unlikely (errno == EMSGSIZE))
699 goto too_small;
700
701 n = -1;
702 }
703
704 if (__glibc_unlikely (n < 0))
705 {
706 *errnop = errno;
707 *h_errnop = NO_RECOVERY;
708 return NSS_STATUS_UNAVAIL;
709 }
710 if (__glibc_unlikely (name_ok (bp) == 0))
711 {
712 errno = EBADMSG;
713 *errnop = EBADMSG;
714 *h_errnop = NO_RECOVERY;
715 return NSS_STATUS_UNAVAIL;
716 }
717 cp += n + QFIXEDSZ;
718
719 if (qtype == T_A || qtype == T_AAAA)
720 {
721 /* res_send() has already verified that the query name is the
722 * same as the one we sent; this just gets the expanded name
723 * (i.e., with the succeeding search-domain tacked on).
724 */
725 n = strlen (bp) + 1; /* for the \0 */
726 if (n >= MAXHOSTNAMELEN)
727 {
728 *h_errnop = NO_RECOVERY;
729 *errnop = ENOENT;
730 return NSS_STATUS_TRYAGAIN;
731 }
732 result->h_name = bp;
733 bp += n;
734 linebuflen -= n;
735 if (linebuflen < 0)
736 goto too_small;
737 /* The qname can be abbreviated, but h_name is now absolute. */
738 qname = result->h_name;
739 }
740
741 ap = host_data->aliases;
742 *ap = NULL;
743 result->h_aliases = host_data->aliases;
744 hap = host_data->h_addr_ptrs;
745 *hap = NULL;
746 result->h_addr_list = host_data->h_addr_ptrs;
747 haveanswer = 0;
748 had_error = 0;
749
750 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
751 {
752 int type, class;
753
754 n = __ns_name_unpack (answer->buf, end_of_message, cp,
755 packtmp, sizeof packtmp);
756 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
757 {
758 if (__glibc_unlikely (errno == EMSGSIZE))
759 goto too_small;
760
761 n = -1;
762 }
763
764 if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
765 {
766 ++had_error;
767 continue;
768 }
769 cp += n; /* name */
770
771 if (__glibc_unlikely (cp + 10 > end_of_message))
772 {
773 ++had_error;
774 continue;
775 }
776
777 NS_GET16 (type, cp);
778 NS_GET16 (class, cp);
779 int32_t ttl;
780 NS_GET32 (ttl, cp);
781 NS_GET16 (n, cp); /* RDATA length. */
782
783 if (end_of_message - cp < n)
784 {
785 /* RDATA extends beyond the end of the packet. */
786 ++had_error;
787 continue;
788 }
789
790 if (__glibc_unlikely (class != C_IN))
791 {
792 /* XXX - debug? syslog? */
793 cp += n;
794 continue; /* XXX - had_error++ ? */
795 }
796
797 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
798 {
799 /* A CNAME could also have a TTL entry. */
800 if (ttlp != NULL && ttl < *ttlp)
801 *ttlp = ttl;
802
803 if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
804 continue;
805 n = __libc_dn_expand (answer->buf, end_of_message, cp,
806 tbuf, sizeof tbuf);
807 if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
808 {
809 ++had_error;
810 continue;
811 }
812 cp += n;
813 /* Store alias. */
814 *ap++ = bp;
815 n = strlen (bp) + 1; /* For the \0. */
816 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
817 {
818 ++had_error;
819 continue;
820 }
821 bp += n;
822 linebuflen -= n;
823 /* Get canonical name. */
824 n = strlen (tbuf) + 1; /* For the \0. */
825 if (__glibc_unlikely (n > linebuflen))
826 goto too_small;
827 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
828 {
829 ++had_error;
830 continue;
831 }
832 result->h_name = bp;
833 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
834 linebuflen -= n;
835 continue;
836 }
837
838 if (qtype == T_PTR && type == T_CNAME)
839 {
840 /* A CNAME could also have a TTL entry. */
841 if (ttlp != NULL && ttl < *ttlp)
842 *ttlp = ttl;
843
844 n = __libc_dn_expand (answer->buf, end_of_message, cp,
845 tbuf, sizeof tbuf);
846 if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
847 {
848 ++had_error;
849 continue;
850 }
851 cp += n;
852 /* Get canonical name. */
853 n = strlen (tbuf) + 1; /* For the \0. */
854 if (__glibc_unlikely (n > linebuflen))
855 goto too_small;
856 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
857 {
858 ++had_error;
859 continue;
860 }
861 tname = bp;
862 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
863 linebuflen -= n;
864 continue;
865 }
866
867 if (type == T_A && qtype == T_AAAA && map)
868 have_to_map = 1;
869 else if (__glibc_unlikely (type != qtype))
870 {
871 cp += n;
872 continue; /* XXX - had_error++ ? */
873 }
874
875 switch (type)
876 {
877 case T_PTR:
878 if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
879 {
880 cp += n;
881 continue; /* XXX - had_error++ ? */
882 }
883
884 n = __ns_name_unpack (answer->buf, end_of_message, cp,
885 packtmp, sizeof packtmp);
886 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
887 {
888 if (__glibc_unlikely (errno == EMSGSIZE))
889 goto too_small;
890
891 n = -1;
892 }
893
894 if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
895 {
896 ++had_error;
897 break;
898 }
899 if (ttlp != NULL && ttl < *ttlp)
900 *ttlp = ttl;
901 /* bind would put multiple PTR records as aliases, but we don't do
902 that. */
903 result->h_name = bp;
904 *h_errnop = NETDB_SUCCESS;
905 return NSS_STATUS_SUCCESS;
906 case T_A:
907 case T_AAAA:
908 if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
909 {
910 cp += n;
911 continue; /* XXX - had_error++ ? */
912 }
913
914 /* Stop parsing at a record whose length is incorrect. */
915 if (n != rrtype_to_rdata_length (type))
916 {
917 ++had_error;
918 break;
919 }
920
921 /* Skip records of the wrong type. */
922 if (n != result->h_length)
923 {
924 cp += n;
925 continue;
926 }
927 if (!haveanswer)
928 {
929 int nn;
930
931 /* We compose a single hostent out of the entire chain of
932 entries, so the TTL of the hostent is essentially the lowest
933 TTL in the chain. */
934 if (ttlp != NULL && ttl < *ttlp)
935 *ttlp = ttl;
936 if (canonp != NULL)
937 *canonp = bp;
938 result->h_name = bp;
939 nn = strlen (bp) + 1; /* for the \0 */
940 bp += nn;
941 linebuflen -= nn;
942 }
943
944 /* Provide sufficient alignment for both address
945 families. */
946 enum { align = 4 };
947 _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
948 "struct in_addr alignment");
949 _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
950 "struct in6_addr alignment");
951 {
952 char *new_bp = PTR_ALIGN_UP (bp, align);
953 linebuflen -= new_bp - bp;
954 bp = new_bp;
955 }
956
957 if (__glibc_unlikely (n > linebuflen))
958 goto too_small;
959 bp = __mempcpy (*hap++ = bp, cp, n);
960 cp += n;
961 linebuflen -= n;
962 break;
963 default:
964 abort ();
965 }
966 if (had_error == 0)
967 ++haveanswer;
968 }
969
970 if (haveanswer > 0)
971 {
972 *ap = NULL;
973 *hap = NULL;
974 /*
975 * Note: we sort even if host can take only one address
976 * in its return structures - should give it the "best"
977 * address in that case, not some random one
978 */
979 if (haveanswer > 1 && qtype == T_A
980 && __resolv_context_sort_count (ctx) > 0)
981 addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
982
983 if (result->h_name == NULL)
984 {
985 n = strlen (qname) + 1; /* For the \0. */
986 if (n > linebuflen)
987 goto too_small;
988 if (n >= MAXHOSTNAMELEN)
989 goto no_recovery;
990 result->h_name = bp;
991 bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
992 linebuflen -= n;
993 }
994
995 if (have_to_map)
996 if (map_v4v6_hostent (result, &bp, &linebuflen))
997 goto too_small;
998 *h_errnop = NETDB_SUCCESS;
999 return NSS_STATUS_SUCCESS;
1000 }
1001 no_recovery:
1002 *h_errnop = NO_RECOVERY;
1003 *errnop = ENOENT;
1004 /* Special case here: if the resolver sent a result but it only
1005 contains a CNAME while we are looking for a T_A or T_AAAA record,
1006 we fail with NOTFOUND instead of TRYAGAIN. */
1007 return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
1008 ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
1009}
1010
1011
1012static enum nss_status
1013gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
1014 struct gaih_addrtuple ***patp,
1015 char **bufferp, size_t *buflenp,
1016 int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
1017{
1018 char *buffer = *bufferp;
1019 size_t buflen = *buflenp;
1020
1021 struct gaih_addrtuple **pat = *patp;
1022 const HEADER *hp = &answer->hdr;
1023 int ancount = ntohs (hp->ancount);
1024 int qdcount = ntohs (hp->qdcount);
1025 const u_char *cp = answer->buf + HFIXEDSZ;
1026 const u_char *end_of_message = answer->buf + anslen;
1027 if (__glibc_unlikely (qdcount != 1))
1028 {
1029 *h_errnop = NO_RECOVERY;
1030 return NSS_STATUS_UNAVAIL;
1031 }
1032
1033 u_char packtmp[NS_MAXCDNAME];
1034 int n = __ns_name_unpack (answer->buf, end_of_message, cp,
1035 packtmp, sizeof packtmp);
1036 /* We unpack the name to check it for validity. But we do not need
1037 it later. */
1038 if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
1039 {
1040 if (__glibc_unlikely (errno == EMSGSIZE))
1041 {
1042 too_small:
1043 *errnop = ERANGE;
1044 *h_errnop = NETDB_INTERNAL;
1045 return NSS_STATUS_TRYAGAIN;
1046 }
1047
1048 n = -1;
1049 }
1050
1051 if (__glibc_unlikely (n < 0))
1052 {
1053 *errnop = errno;
1054 *h_errnop = NO_RECOVERY;
1055 return NSS_STATUS_UNAVAIL;
1056 }
1057 if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
1058 {
1059 errno = EBADMSG;
1060 *errnop = EBADMSG;
1061 *h_errnop = NO_RECOVERY;
1062 return NSS_STATUS_UNAVAIL;
1063 }
1064 cp += n + QFIXEDSZ;
1065
1066 int haveanswer = 0;
1067 int had_error = 0;
1068 char *canon = NULL;
1069 char *h_name = NULL;
1070 int h_namelen = 0;
1071
1072 if (ancount == 0)
1073 {
1074 *h_errnop = HOST_NOT_FOUND;
1075 return NSS_STATUS_NOTFOUND;
1076 }
1077
1078 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1079 {
1080 n = __ns_name_unpack (answer->buf, end_of_message, cp,
1081 packtmp, sizeof packtmp);
1082 if (n != -1 &&
1083 (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
1084 {
1085 if (__glibc_unlikely (errno == EMSGSIZE))
1086 goto too_small;
1087
1088 n = -1;
1089 }
1090 if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0))
1091 {
1092 ++had_error;
1093 continue;
1094 }
1095 if (*firstp && canon == NULL)
1096 {
1097 h_name = buffer;
1098 buffer += h_namelen;
1099 buflen -= h_namelen;
1100 }
1101
1102 cp += n; /* name */
1103
1104 if (__glibc_unlikely (cp + 10 > end_of_message))
1105 {
1106 ++had_error;
1107 continue;
1108 }
1109
1110 uint16_t type;
1111 NS_GET16 (type, cp);
1112 uint16_t class;
1113 NS_GET16 (class, cp);
1114 int32_t ttl;
1115 NS_GET32 (ttl, cp);
1116 NS_GET16 (n, cp); /* RDATA length. */
1117
1118 if (end_of_message - cp < n)
1119 {
1120 /* RDATA extends beyond the end of the packet. */
1121 ++had_error;
1122 continue;
1123 }
1124
1125 if (class != C_IN)
1126 {
1127 cp += n;
1128 continue;
1129 }
1130
1131 if (type == T_CNAME)
1132 {
1133 char tbuf[MAXDNAME];
1134
1135 /* A CNAME could also have a TTL entry. */
1136 if (ttlp != NULL && ttl < *ttlp)
1137 *ttlp = ttl;
1138
1139 n = __libc_dn_expand (answer->buf, end_of_message, cp,
1140 tbuf, sizeof tbuf);
1141 if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0))
1142 {
1143 ++had_error;
1144 continue;
1145 }
1146 cp += n;
1147
1148 if (*firstp)
1149 {
1150 /* Reclaim buffer space. */
1151 if (h_name + h_namelen == buffer)
1152 {
1153 buffer = h_name;
1154 buflen += h_namelen;
1155 }
1156
1157 n = strlen (tbuf) + 1;
1158 if (__glibc_unlikely (n > buflen))
1159 goto too_small;
1160 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1161 {
1162 ++had_error;
1163 continue;
1164 }
1165
1166 canon = buffer;
1167 buffer = __mempcpy (buffer, tbuf, n);
1168 buflen -= n;
1169 h_namelen = 0;
1170 }
1171 continue;
1172 }
1173
1174 /* Stop parsing if we encounter a record with incorrect RDATA
1175 length. */
1176 if (type == T_A || type == T_AAAA)
1177 {
1178 if (n != rrtype_to_rdata_length (type))
1179 {
1180 ++had_error;
1181 continue;
1182 }
1183 }
1184 else
1185 {
1186 /* Skip unknown records. */
1187 cp += n;
1188 continue;
1189 }
1190
1191 assert (type == T_A || type == T_AAAA);
1192 if (*pat == NULL)
1193 {
1194 uintptr_t pad = (-(uintptr_t) buffer
1195 % __alignof__ (struct gaih_addrtuple));
1196 buffer += pad;
1197 buflen = buflen > pad ? buflen - pad : 0;
1198
1199 if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
1200 goto too_small;
1201
1202 *pat = (struct gaih_addrtuple *) buffer;
1203 buffer += sizeof (struct gaih_addrtuple);
1204 buflen -= sizeof (struct gaih_addrtuple);
1205 }
1206
1207 (*pat)->name = NULL;
1208 (*pat)->next = NULL;
1209
1210 if (*firstp)
1211 {
1212 /* We compose a single hostent out of the entire chain of
1213 entries, so the TTL of the hostent is essentially the lowest
1214 TTL in the chain. */
1215 if (ttlp != NULL && ttl < *ttlp)
1216 *ttlp = ttl;
1217
1218 (*pat)->name = canon ?: h_name;
1219
1220 *firstp = 0;
1221 }
1222
1223 (*pat)->family = type == T_A ? AF_INET : AF_INET6;
1224 memcpy ((*pat)->addr, cp, n);
1225 cp += n;
1226 (*pat)->scopeid = 0;
1227
1228 pat = &((*pat)->next);
1229
1230 haveanswer = 1;
1231 }
1232
1233 if (haveanswer)
1234 {
1235 *patp = pat;
1236 *bufferp = buffer;
1237 *buflenp = buflen;
1238
1239 *h_errnop = NETDB_SUCCESS;
1240 return NSS_STATUS_SUCCESS;
1241 }
1242
1243 /* Special case here: if the resolver sent a result but it only
1244 contains a CNAME while we are looking for a T_A or T_AAAA record,
1245 we fail with NOTFOUND instead of TRYAGAIN. */
1246 if (canon != NULL)
1247 {
1248 *h_errnop = HOST_NOT_FOUND;
1249 return NSS_STATUS_NOTFOUND;
1250 }
1251
1252 *h_errnop = NETDB_INTERNAL;
1253 return NSS_STATUS_TRYAGAIN;
1254}
1255
1256
1257static enum nss_status
1258gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
1259 int anslen2, const char *qname,
1260 struct gaih_addrtuple **pat, char *buffer, size_t buflen,
1261 int *errnop, int *h_errnop, int32_t *ttlp)
1262{
1263 int first = 1;
1264
1265 enum nss_status status = NSS_STATUS_NOTFOUND;
1266
1267 /* Combining the NSS status of two distinct queries requires some
1268 compromise and attention to symmetry (A or AAAA queries can be
1269 returned in any order). What follows is a breakdown of how this
1270 code is expected to work and why. We discuss only SUCCESS,
1271 TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
1272 that apply (though RETURN and MERGE exist). We make a distinction
1273 between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
1274 A recoverable TRYAGAIN is almost always due to buffer size issues
1275 and returns ERANGE in errno and the caller is expected to retry
1276 with a larger buffer.
1277
1278 Lastly, you may be tempted to make significant changes to the
1279 conditions in this code to bring about symmetry between responses.
1280 Please don't change anything without due consideration for
1281 expected application behaviour. Some of the synthesized responses
1282 aren't very well thought out and sometimes appear to imply that
1283 IPv4 responses are always answer 1, and IPv6 responses are always
1284 answer 2, but that's not true (see the implementation of send_dg
1285 and send_vc to see response can arrive in any order, particularly
1286 for UDP). However, we expect it holds roughly enough of the time
1287 that this code works, but certainly needs to be fixed to make this
1288 a more robust implementation.
1289
1290 ----------------------------------------------
1291 | Answer 1 Status / | Synthesized | Reason |
1292 | Answer 2 Status | Status | |
1293 |--------------------------------------------|
1294 | SUCCESS/SUCCESS | SUCCESS | [1] |
1295 | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
1296 | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
1297 | SUCCESS/NOTFOUND | SUCCESS | [1] |
1298 | SUCCESS/UNAVAIL | SUCCESS | [1] |
1299 | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
1300 | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
1301 | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
1302 | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
1303 | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
1304 | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
1305 | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
1306 | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
1307 | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
1308 | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
1309 | NOTFOUND/SUCCESS | SUCCESS | [3] |
1310 | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
1311 | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
1312 | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
1313 | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
1314 | UNAVAIL/SUCCESS | UNAVAIL | [4] |
1315 | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
1316 | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
1317 | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
1318 | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
1319 ----------------------------------------------
1320
1321 [1] If the first response is a success we return success.
1322 This ignores the state of the second answer and in fact
1323 incorrectly sets errno and h_errno to that of the second
1324 answer. However because the response is a success we ignore
1325 *errnop and *h_errnop (though that means you touched errno on
1326 success). We are being conservative here and returning the
1327 likely IPv4 response in the first answer as a success.
1328
1329 [2] If the first response is a recoverable TRYAGAIN we return
1330 that instead of looking at the second response. The
1331 expectation here is that we have failed to get an IPv4 response
1332 and should retry both queries.
1333
1334 [3] If the first response was not a SUCCESS and the second
1335 response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
1336 or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
1337 result from the second response, otherwise the first responses
1338 status is used. Again we have some odd side-effects when the
1339 second response is NOTFOUND because we overwrite *errnop and
1340 *h_errnop that means that a first answer of NOTFOUND might see
1341 its *errnop and *h_errnop values altered. Whether it matters
1342 in practice that a first response NOTFOUND has the wrong
1343 *errnop and *h_errnop is undecided.
1344
1345 [4] If the first response is UNAVAIL we return that instead of
1346 looking at the second response. The expectation here is that
1347 it will have failed similarly e.g. configuration failure.
1348
1349 [5] Testing this code is complicated by the fact that truncated
1350 second response buffers might be returned as SUCCESS if the
1351 first answer is a SUCCESS. To fix this we add symmetry to
1352 TRYAGAIN with the second response. If the second response
1353 is a recoverable error we now return TRYAGIN even if the first
1354 response was SUCCESS. */
1355
1356 if (anslen1 > 0)
1357 status = gaih_getanswer_slice(answer1, anslen1, qname,
1358 &pat, &buffer, &buflen,
1359 errnop, h_errnop, ttlp,
1360 &first);
1361
1362 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
1363 || (status == NSS_STATUS_TRYAGAIN
1364 /* We want to look at the second answer in case of an
1365 NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
1366 *h_errnop is NO_RECOVERY. If not, and if the failure was due to
1367 an insufficient buffer (ERANGE), then we need to drop the results
1368 and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
1369 repeat the query with a larger buffer. */
1370 && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
1371 && answer2 != NULL && anslen2 > 0)
1372 {
1373 enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
1374 &pat, &buffer, &buflen,
1375 errnop, h_errnop, ttlp,
1376 &first);
1377 /* Use the second response status in some cases. */
1378 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
1379 status = status2;
1380 /* Do not return a truncated second response (unless it was
1381 unavoidable e.g. unrecoverable TRYAGAIN). */
1382 if (status == NSS_STATUS_SUCCESS
1383 && (status2 == NSS_STATUS_TRYAGAIN
1384 && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
1385 status = NSS_STATUS_TRYAGAIN;
1386 }
1387
1388 return status;
1389}
1390

source code of glibc/resolv/nss_dns/dns-host.c