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