1 /* Copyright (C) 1996-2021 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.  */
107 typedef union querybuf
108 {
109   HEADER hdr;
110   u_char buf[MAXPACKET];
111 } querybuf;
112 
113 static 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 
120 static 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 
128 static 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).  */
138 static int
rrtype_to_rdata_length(int type)139 rrtype_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 
153 enum nss_status
_nss_dns_gethostbyname3_r(const char * name,int af,struct hostent * result,char * buffer,size_t buflen,int * errnop,int * h_errnop,int32_t * ttlp,char ** canonp)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 }
libc_hidden_def(_nss_dns_gethostbyname3_r)170 libc_hidden_def (_nss_dns_gethostbyname3_r)
171 
172 static enum nss_status
173 gethostbyname3_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.  */
282 static enum nss_status
check_name(const char * name,int * h_errnop)283 check_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 
291 enum nss_status
_nss_dns_gethostbyname2_r(const char * name,int af,struct hostent * result,char * buffer,size_t buflen,int * errnop,int * h_errnop)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 }
libc_hidden_def(_nss_dns_gethostbyname2_r)302 libc_hidden_def (_nss_dns_gethostbyname2_r)
303 
304 enum 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 }
libc_hidden_def(_nss_dns_gethostbyname_r)329 libc_hidden_def (_nss_dns_gethostbyname_r)
330 
331 enum 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 }
libc_hidden_def(_nss_dns_gethostbyname4_r)421 libc_hidden_def (_nss_dns_gethostbyname4_r)
422 
423 enum 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 }
libc_hidden_def(_nss_dns_gethostbyaddr2_r)562 libc_hidden_def (_nss_dns_gethostbyaddr2_r)
563 
564 
565 enum 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 }
libc_hidden_def(_nss_dns_gethostbyaddr_r)573 libc_hidden_def (_nss_dns_gethostbyaddr_r)
574 
575 static void
576 addrsort (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 
621 static enum nss_status
getanswer_r(struct resolv_context * ctx,const querybuf * answer,int anslen,const char * qname,int qtype,struct hostent * result,char * buffer,size_t buflen,int * errnop,int * h_errnop,int map,int32_t * ttlp,char ** canonp)622 getanswer_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 
1012 static enum nss_status
gaih_getanswer_slice(const querybuf * answer,int anslen,const char * qname,struct gaih_addrtuple *** patp,char ** bufferp,size_t * buflenp,int * errnop,int * h_errnop,int32_t * ttlp,int * firstp)1013 gaih_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 
1257 static enum nss_status
gaih_getanswer(const querybuf * answer1,int anslen1,const querybuf * answer2,int anslen2,const char * qname,struct gaih_addrtuple ** pat,char * buffer,size_t buflen,int * errnop,int * h_errnop,int32_t * ttlp)1258 gaih_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