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