resolv: Introduce struct resolv_context [BZ #21668]
[glibc.git] / resolv / nss_dns / dns-host.c
blob9d7ceb1691987b275974bfb26aea5a5b2908a112
1 /* Copyright (C) 1996-2017 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.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 /* Parts of this file are plain copies of the file `gethtnamadr.c' from
20 the bind package and it has the following copyright. */
23 * ++Copyright++ 1985, 1988, 1993
24 * -
25 * Copyright (c) 1985, 1988, 1993
26 * The Regents of the University of California. All rights reserved.
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.
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.
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.
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--
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>
82 #include "nsswitch.h"
83 #include <arpa/nameser.h>
85 /* Get implementeation for some internal functions. */
86 #include <resolv/resolv-internal.h>
87 #include <resolv/resolv_context.h>
88 #include <resolv/mapv4v6addr.h>
89 #include <resolv/mapv4v6hostent.h>
91 #define RESOLVSORT
93 #if PACKETSZ > 65536
94 # define MAXPACKET PACKETSZ
95 #else
96 # define MAXPACKET 65536
97 #endif
98 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
99 #ifdef MAXHOSTNAMELEN
100 # undef MAXHOSTNAMELEN
101 #endif
102 #define MAXHOSTNAMELEN 256
104 /* We need this time later. */
105 typedef union querybuf
107 HEADER hdr;
108 u_char buf[MAXPACKET];
109 } querybuf;
111 static enum nss_status getanswer_r (const querybuf *answer, int anslen,
112 const char *qname, int qtype,
113 struct hostent *result, char *buffer,
114 size_t buflen, int *errnop, int *h_errnop,
115 int map, int32_t *ttlp, char **canonp);
117 static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
118 const querybuf *answer2, int anslen2,
119 const char *qname,
120 struct gaih_addrtuple **pat,
121 char *buffer, size_t buflen,
122 int *errnop, int *h_errnop,
123 int32_t *ttlp);
125 static enum nss_status gethostbyname3_context (struct resolv_context *ctx,
126 const char *name, int af,
127 struct hostent *result,
128 char *buffer, size_t buflen,
129 int *errnop, int *h_errnop,
130 int32_t *ttlp,
131 char **canonp);
133 /* Return the expected RDATA length for an address record type (A or
134 AAAA). */
135 static int
136 rrtype_to_rdata_length (int type)
138 switch (type)
140 case T_A:
141 return INADDRSZ;
142 case T_AAAA:
143 return IN6ADDRSZ;
144 default:
145 return -1;
150 enum nss_status
151 _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
152 char *buffer, size_t buflen, int *errnop,
153 int *h_errnop, int32_t *ttlp, char **canonp)
155 struct resolv_context *ctx = __resolv_context_get ();
156 if (ctx == NULL)
158 *errnop = errno;
159 *h_errnop = NETDB_INTERNAL;
160 return NSS_STATUS_UNAVAIL;
162 enum nss_status status = gethostbyname3_context
163 (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
164 __resolv_context_put (ctx);
165 return status;
168 static enum nss_status
169 gethostbyname3_context (struct resolv_context *ctx,
170 const char *name, int af, struct hostent *result,
171 char *buffer, size_t buflen, int *errnop,
172 int *h_errnop, int32_t *ttlp, char **canonp)
174 union
176 querybuf *buf;
177 u_char *ptr;
178 } host_buffer;
179 querybuf *orig_host_buffer;
180 char tmp[NS_MAXDNAME];
181 int size, type, n;
182 const char *cp;
183 int map = 0;
184 int olderr = errno;
185 enum nss_status status;
187 switch (af) {
188 case AF_INET:
189 size = INADDRSZ;
190 type = T_A;
191 break;
192 case AF_INET6:
193 size = IN6ADDRSZ;
194 type = T_AAAA;
195 break;
196 default:
197 *h_errnop = NO_DATA;
198 *errnop = EAFNOSUPPORT;
199 return NSS_STATUS_UNAVAIL;
202 result->h_addrtype = af;
203 result->h_length = size;
206 * if there aren't any dots, it could be a user-level alias.
207 * this is also done in res_query() since we are not the only
208 * function that looks up host names.
210 if (strchr (name, '.') == NULL
211 && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
212 name = cp;
214 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
216 n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
217 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
218 if (n < 0)
220 switch (errno)
222 case ESRCH:
223 status = NSS_STATUS_TRYAGAIN;
224 h_errno = TRY_AGAIN;
225 break;
226 /* System has run out of file descriptors. */
227 case EMFILE:
228 case ENFILE:
229 h_errno = NETDB_INTERNAL;
230 /* Fall through. */
231 case ECONNREFUSED:
232 case ETIMEDOUT:
233 status = NSS_STATUS_UNAVAIL;
234 break;
235 default:
236 status = NSS_STATUS_NOTFOUND;
237 break;
239 *h_errnop = h_errno;
240 if (h_errno == TRY_AGAIN)
241 *errnop = EAGAIN;
242 else
243 __set_errno (olderr);
245 /* If we are looking for an IPv6 address and mapping is enabled
246 by having the RES_USE_INET6 bit in _res.options set, we try
247 another lookup. */
248 if (af == AF_INET6 && res_use_inet6 ())
249 n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
250 host_buffer.buf != orig_host_buffer
251 ? MAXPACKET : 1024, &host_buffer.ptr,
252 NULL, NULL, NULL, NULL);
254 if (n < 0)
256 if (host_buffer.buf != orig_host_buffer)
257 free (host_buffer.buf);
258 return status;
261 map = 1;
263 result->h_addrtype = AF_INET;
264 result->h_length = INADDRSZ;
267 status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen,
268 errnop, h_errnop, map, ttlp, canonp);
269 if (host_buffer.buf != orig_host_buffer)
270 free (host_buffer.buf);
271 return status;
274 enum nss_status
275 _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
276 char *buffer, size_t buflen, int *errnop,
277 int *h_errnop)
279 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
280 h_errnop, NULL, NULL);
284 enum nss_status
285 _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
286 char *buffer, size_t buflen, int *errnop,
287 int *h_errnop)
289 struct resolv_context *ctx = __resolv_context_get ();
290 if (ctx == NULL)
292 *errnop = errno;
293 *h_errnop = NETDB_INTERNAL;
294 return NSS_STATUS_UNAVAIL;
296 enum nss_status status = NSS_STATUS_NOTFOUND;
297 if (res_use_inet6 ())
298 status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
299 buflen, errnop, h_errnop, NULL, NULL);
300 if (status == NSS_STATUS_NOTFOUND)
301 status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
302 buflen, errnop, h_errnop, NULL, NULL);
303 __resolv_context_put (ctx);
304 return status;
308 enum nss_status
309 _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
310 char *buffer, size_t buflen, int *errnop,
311 int *herrnop, int32_t *ttlp)
313 struct resolv_context *ctx = __resolv_context_get ();
314 if (ctx == NULL)
316 *errnop = errno;
317 *herrnop = NETDB_INTERNAL;
318 return NSS_STATUS_UNAVAIL;
322 * if there aren't any dots, it could be a user-level alias.
323 * this is also done in res_query() since we are not the only
324 * function that looks up host names.
326 if (strchr (name, '.') == NULL)
328 char *tmp = alloca (NS_MAXDNAME);
329 const char *cp = __res_context_hostalias (ctx, name, tmp, NS_MAXDNAME);
330 if (cp != NULL)
331 name = cp;
334 union
336 querybuf *buf;
337 u_char *ptr;
338 } host_buffer;
339 querybuf *orig_host_buffer;
340 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
341 u_char *ans2p = NULL;
342 int nans2p = 0;
343 int resplen2 = 0;
344 int ans2p_malloced = 0;
346 int olderr = errno;
347 enum nss_status status;
348 int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
349 host_buffer.buf->buf, 2048, &host_buffer.ptr,
350 &ans2p, &nans2p, &resplen2, &ans2p_malloced);
351 if (n >= 0)
353 status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
354 resplen2, name, pat, buffer, buflen,
355 errnop, herrnop, ttlp);
357 else
359 switch (errno)
361 case ESRCH:
362 status = NSS_STATUS_TRYAGAIN;
363 h_errno = TRY_AGAIN;
364 break;
365 /* System has run out of file descriptors. */
366 case EMFILE:
367 case ENFILE:
368 h_errno = NETDB_INTERNAL;
369 /* Fall through. */
370 case ECONNREFUSED:
371 case ETIMEDOUT:
372 status = NSS_STATUS_UNAVAIL;
373 break;
374 default:
375 status = NSS_STATUS_NOTFOUND;
376 break;
379 *herrnop = h_errno;
380 if (h_errno == TRY_AGAIN)
381 *errnop = EAGAIN;
382 else
383 __set_errno (olderr);
386 /* Check whether ans2p was separately allocated. */
387 if (ans2p_malloced)
388 free (ans2p);
390 if (host_buffer.buf != orig_host_buffer)
391 free (host_buffer.buf);
393 __resolv_context_put (ctx);
394 return status;
398 extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
399 socklen_t len, int af,
400 struct hostent *result,
401 char *buffer, size_t buflen,
402 int *errnop, int *h_errnop,
403 int32_t *ttlp);
404 hidden_proto (_nss_dns_gethostbyaddr2_r)
406 enum nss_status
407 _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
408 struct hostent *result, char *buffer, size_t buflen,
409 int *errnop, int *h_errnop, int32_t *ttlp)
411 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
412 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
413 static const u_char v6local[] = { 0,0, 0,1 };
414 const u_char *uaddr = (const u_char *)addr;
415 struct host_data
417 char *aliases[MAX_NR_ALIASES];
418 unsigned char host_addr[16]; /* IPv4 or IPv6 */
419 char *h_addr_ptrs[MAX_NR_ADDRS + 1];
420 char linebuffer[0];
421 } *host_data = (struct host_data *) buffer;
422 union
424 querybuf *buf;
425 u_char *ptr;
426 } host_buffer;
427 querybuf *orig_host_buffer;
428 char qbuf[MAXDNAME+1], *qp = NULL;
429 size_t size;
430 int n, status;
431 int olderr = errno;
433 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
434 buffer += pad;
435 buflen = buflen > pad ? buflen - pad : 0;
437 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
439 *errnop = ERANGE;
440 *h_errnop = NETDB_INTERNAL;
441 return NSS_STATUS_TRYAGAIN;
444 host_data = (struct host_data *) buffer;
446 struct resolv_context *ctx = __resolv_context_get ();
447 if (ctx == NULL)
449 *errnop = errno;
450 *h_errnop = NETDB_INTERNAL;
451 return NSS_STATUS_UNAVAIL;
454 if (af == AF_INET6 && len == IN6ADDRSZ
455 && (memcmp (uaddr, mapped, sizeof mapped) == 0
456 || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
457 && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
459 /* Unmap. */
460 addr += sizeof mapped;
461 uaddr += sizeof mapped;
462 af = AF_INET;
463 len = INADDRSZ;
466 switch (af)
468 case AF_INET:
469 size = INADDRSZ;
470 break;
471 case AF_INET6:
472 size = IN6ADDRSZ;
473 break;
474 default:
475 *errnop = EAFNOSUPPORT;
476 *h_errnop = NETDB_INTERNAL;
477 __resolv_context_put (ctx);
478 return NSS_STATUS_UNAVAIL;
480 if (size > len)
482 *errnop = EAFNOSUPPORT;
483 *h_errnop = NETDB_INTERNAL;
484 __resolv_context_put (ctx);
485 return NSS_STATUS_UNAVAIL;
488 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
490 switch (af)
492 case AF_INET:
493 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
494 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
495 break;
496 case AF_INET6:
497 qp = qbuf;
498 for (n = IN6ADDRSZ - 1; n >= 0; n--)
500 static const char nibblechar[16] = "0123456789abcdef";
501 *qp++ = nibblechar[uaddr[n] & 0xf];
502 *qp++ = '.';
503 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
504 *qp++ = '.';
506 strcpy(qp, "ip6.arpa");
507 break;
508 default:
509 /* Cannot happen. */
510 break;
513 n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
514 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
515 if (n < 0)
517 *h_errnop = h_errno;
518 __set_errno (olderr);
519 if (host_buffer.buf != orig_host_buffer)
520 free (host_buffer.buf);
521 __resolv_context_put (ctx);
522 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
525 status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
526 errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
527 if (host_buffer.buf != orig_host_buffer)
528 free (host_buffer.buf);
529 if (status != NSS_STATUS_SUCCESS)
531 __resolv_context_put (ctx);
532 return status;
535 result->h_addrtype = af;
536 result->h_length = len;
537 memcpy (host_data->host_addr, addr, len);
538 host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
539 host_data->h_addr_ptrs[1] = NULL;
540 *h_errnop = NETDB_SUCCESS;
541 __resolv_context_put (ctx);
542 return NSS_STATUS_SUCCESS;
544 hidden_def (_nss_dns_gethostbyaddr2_r)
547 enum nss_status
548 _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
549 struct hostent *result, char *buffer, size_t buflen,
550 int *errnop, int *h_errnop)
552 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
553 errnop, h_errnop, NULL);
556 static void addrsort (char **ap, int num);
558 static void
559 addrsort (char **ap, int num)
561 int i, j;
562 char **p;
563 short aval[MAX_NR_ADDRS];
564 int needsort = 0;
566 p = ap;
567 if (num > MAX_NR_ADDRS)
568 num = MAX_NR_ADDRS;
569 for (i = 0; i < num; i++, p++)
571 for (j = 0 ; (unsigned)j < _res.nsort; j++)
572 if (_res.sort_list[j].addr.s_addr ==
573 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
574 break;
575 aval[i] = j;
576 if (needsort == 0 && i > 0 && j < aval[i-1])
577 needsort = i;
579 if (!needsort)
580 return;
582 while (needsort++ < num)
583 for (j = needsort - 2; j >= 0; j--)
584 if (aval[j] > aval[j+1])
586 char *hp;
588 i = aval[j];
589 aval[j] = aval[j+1];
590 aval[j+1] = i;
592 hp = ap[j];
593 ap[j] = ap[j+1];
594 ap[j+1] = hp;
596 else
597 break;
600 static enum nss_status
601 getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
602 struct hostent *result, char *buffer, size_t buflen,
603 int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
605 struct host_data
607 char *aliases[MAX_NR_ALIASES];
608 unsigned char host_addr[16]; /* IPv4 or IPv6 */
609 char *h_addr_ptrs[0];
610 } *host_data;
611 int linebuflen;
612 const HEADER *hp;
613 const u_char *end_of_message, *cp;
614 int n, ancount, qdcount;
615 int haveanswer, had_error;
616 char *bp, **ap, **hap;
617 char tbuf[MAXDNAME];
618 const char *tname;
619 int (*name_ok) (const char *);
620 u_char packtmp[NS_MAXCDNAME];
621 int have_to_map = 0;
622 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
623 buffer += pad;
624 buflen = buflen > pad ? buflen - pad : 0;
625 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
627 /* The buffer is too small. */
628 too_small:
629 *errnop = ERANGE;
630 *h_errnop = NETDB_INTERNAL;
631 return NSS_STATUS_TRYAGAIN;
633 host_data = (struct host_data *) buffer;
634 linebuflen = buflen - sizeof (struct host_data);
635 if (buflen - sizeof (struct host_data) != linebuflen)
636 linebuflen = INT_MAX;
638 tname = qname;
639 result->h_name = NULL;
640 end_of_message = answer->buf + anslen;
641 switch (qtype)
643 case T_A:
644 case T_AAAA:
645 name_ok = res_hnok;
646 break;
647 case T_PTR:
648 name_ok = res_dnok;
649 break;
650 default:
651 *errnop = ENOENT;
652 return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
656 * find first satisfactory answer
658 hp = &answer->hdr;
659 ancount = ntohs (hp->ancount);
660 qdcount = ntohs (hp->qdcount);
661 cp = answer->buf + HFIXEDSZ;
662 if (__glibc_unlikely (qdcount != 1))
664 *h_errnop = NO_RECOVERY;
665 return NSS_STATUS_UNAVAIL;
667 if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
668 goto too_small;
669 bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
670 linebuflen -= (ancount + 1) * sizeof (char *);
672 n = __ns_name_unpack (answer->buf, end_of_message, cp,
673 packtmp, sizeof packtmp);
674 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
676 if (__glibc_unlikely (errno == EMSGSIZE))
677 goto too_small;
679 n = -1;
682 if (n > 0 && bp[0] == '.')
683 bp[0] = '\0';
685 if (__glibc_unlikely (n < 0))
687 *errnop = errno;
688 *h_errnop = NO_RECOVERY;
689 return NSS_STATUS_UNAVAIL;
691 if (__glibc_unlikely (name_ok (bp) == 0))
693 errno = EBADMSG;
694 *errnop = EBADMSG;
695 *h_errnop = NO_RECOVERY;
696 return NSS_STATUS_UNAVAIL;
698 cp += n + QFIXEDSZ;
700 if (qtype == T_A || qtype == T_AAAA)
702 /* res_send() has already verified that the query name is the
703 * same as the one we sent; this just gets the expanded name
704 * (i.e., with the succeeding search-domain tacked on).
706 n = strlen (bp) + 1; /* for the \0 */
707 if (n >= MAXHOSTNAMELEN)
709 *h_errnop = NO_RECOVERY;
710 *errnop = ENOENT;
711 return NSS_STATUS_TRYAGAIN;
713 result->h_name = bp;
714 bp += n;
715 linebuflen -= n;
716 if (linebuflen < 0)
717 goto too_small;
718 /* The qname can be abbreviated, but h_name is now absolute. */
719 qname = result->h_name;
722 ap = host_data->aliases;
723 *ap = NULL;
724 result->h_aliases = host_data->aliases;
725 hap = host_data->h_addr_ptrs;
726 *hap = NULL;
727 result->h_addr_list = host_data->h_addr_ptrs;
728 haveanswer = 0;
729 had_error = 0;
731 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
733 int type, class;
735 n = __ns_name_unpack (answer->buf, end_of_message, cp,
736 packtmp, sizeof packtmp);
737 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
739 if (__glibc_unlikely (errno == EMSGSIZE))
740 goto too_small;
742 n = -1;
745 if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
747 ++had_error;
748 continue;
750 cp += n; /* name */
752 if (__glibc_unlikely (cp + 10 > end_of_message))
754 ++had_error;
755 continue;
758 type = __ns_get16 (cp);
759 cp += INT16SZ; /* type */
760 class = __ns_get16 (cp);
761 cp += INT16SZ; /* class */
762 int32_t ttl = __ns_get32 (cp);
763 cp += INT32SZ; /* TTL */
764 n = __ns_get16 (cp);
765 cp += INT16SZ; /* len */
767 if (end_of_message - cp < n)
769 /* RDATA extends beyond the end of the packet. */
770 ++had_error;
771 continue;
774 if (__glibc_unlikely (class != C_IN))
776 /* XXX - debug? syslog? */
777 cp += n;
778 continue; /* XXX - had_error++ ? */
781 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
783 /* A CNAME could also have a TTL entry. */
784 if (ttlp != NULL && ttl < *ttlp)
785 *ttlp = ttl;
787 if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
788 continue;
789 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
790 if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
792 ++had_error;
793 continue;
795 cp += n;
796 /* Store alias. */
797 *ap++ = bp;
798 n = strlen (bp) + 1; /* For the \0. */
799 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
801 ++had_error;
802 continue;
804 bp += n;
805 linebuflen -= n;
806 /* Get canonical name. */
807 n = strlen (tbuf) + 1; /* For the \0. */
808 if (__glibc_unlikely (n > linebuflen))
809 goto too_small;
810 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
812 ++had_error;
813 continue;
815 result->h_name = bp;
816 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
817 linebuflen -= n;
818 continue;
821 if (qtype == T_PTR && type == T_CNAME)
823 /* A CNAME could also have a TTL entry. */
824 if (ttlp != NULL && ttl < *ttlp)
825 *ttlp = ttl;
827 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
828 if (__glibc_unlikely (n < 0 || res_dnok (tbuf) == 0))
830 ++had_error;
831 continue;
833 cp += n;
834 /* Get canonical name. */
835 n = strlen (tbuf) + 1; /* For the \0. */
836 if (__glibc_unlikely (n > linebuflen))
837 goto too_small;
838 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
840 ++had_error;
841 continue;
843 tname = bp;
844 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
845 linebuflen -= n;
846 continue;
849 if (type == T_A && qtype == T_AAAA && map)
850 have_to_map = 1;
851 else if (__glibc_unlikely (type != qtype))
853 cp += n;
854 continue; /* XXX - had_error++ ? */
857 switch (type)
859 case T_PTR:
860 if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
862 cp += n;
863 continue; /* XXX - had_error++ ? */
866 n = __ns_name_unpack (answer->buf, end_of_message, cp,
867 packtmp, sizeof packtmp);
868 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
870 if (__glibc_unlikely (errno == EMSGSIZE))
871 goto too_small;
873 n = -1;
876 if (__glibc_unlikely (n < 0 || res_hnok (bp) == 0))
878 ++had_error;
879 break;
881 if (ttlp != NULL && ttl < *ttlp)
882 *ttlp = ttl;
883 /* bind would put multiple PTR records as aliases, but we don't do
884 that. */
885 result->h_name = bp;
886 if (have_to_map)
888 n = strlen (bp) + 1; /* for the \0 */
889 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
891 ++had_error;
892 break;
894 bp += n;
895 linebuflen -= n;
896 if (map_v4v6_hostent (result, &bp, &linebuflen))
897 goto too_small;
899 *h_errnop = NETDB_SUCCESS;
900 return NSS_STATUS_SUCCESS;
901 case T_A:
902 case T_AAAA:
903 if (__glibc_unlikely (strcasecmp (result->h_name, bp) != 0))
905 cp += n;
906 continue; /* XXX - had_error++ ? */
909 /* Stop parsing at a record whose length is incorrect. */
910 if (n != rrtype_to_rdata_length (type))
912 ++had_error;
913 break;
916 /* Skip records of the wrong type. */
917 if (n != result->h_length)
919 cp += n;
920 continue;
922 if (!haveanswer)
924 int nn;
926 /* We compose a single hostent out of the entire chain of
927 entries, so the TTL of the hostent is essentially the lowest
928 TTL in the chain. */
929 if (ttlp != NULL && ttl < *ttlp)
930 *ttlp = ttl;
931 if (canonp != NULL)
932 *canonp = bp;
933 result->h_name = bp;
934 nn = strlen (bp) + 1; /* for the \0 */
935 bp += nn;
936 linebuflen -= nn;
939 linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
940 bp += sizeof (align) - ((u_long) bp % sizeof (align));
942 if (__glibc_unlikely (n > linebuflen))
943 goto too_small;
944 bp = __mempcpy (*hap++ = bp, cp, n);
945 cp += n;
946 linebuflen -= n;
947 break;
948 default:
949 abort ();
951 if (had_error == 0)
952 ++haveanswer;
955 if (haveanswer > 0)
957 *ap = NULL;
958 *hap = NULL;
960 * Note: we sort even if host can take only one address
961 * in its return structures - should give it the "best"
962 * address in that case, not some random one
964 if (_res.nsort && haveanswer > 1 && qtype == T_A)
965 addrsort (host_data->h_addr_ptrs, haveanswer);
967 if (result->h_name == NULL)
969 n = strlen (qname) + 1; /* For the \0. */
970 if (n > linebuflen)
971 goto too_small;
972 if (n >= MAXHOSTNAMELEN)
973 goto no_recovery;
974 result->h_name = bp;
975 bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
976 linebuflen -= n;
979 if (have_to_map)
980 if (map_v4v6_hostent (result, &bp, &linebuflen))
981 goto too_small;
982 *h_errnop = NETDB_SUCCESS;
983 return NSS_STATUS_SUCCESS;
985 no_recovery:
986 *h_errnop = NO_RECOVERY;
987 *errnop = ENOENT;
988 /* Special case here: if the resolver sent a result but it only
989 contains a CNAME while we are looking for a T_A or T_AAAA record,
990 we fail with NOTFOUND instead of TRYAGAIN. */
991 return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
992 ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
996 static enum nss_status
997 gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
998 struct gaih_addrtuple ***patp,
999 char **bufferp, size_t *buflenp,
1000 int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
1002 char *buffer = *bufferp;
1003 size_t buflen = *buflenp;
1005 struct gaih_addrtuple **pat = *patp;
1006 const HEADER *hp = &answer->hdr;
1007 int ancount = ntohs (hp->ancount);
1008 int qdcount = ntohs (hp->qdcount);
1009 const u_char *cp = answer->buf + HFIXEDSZ;
1010 const u_char *end_of_message = answer->buf + anslen;
1011 if (__glibc_unlikely (qdcount != 1))
1013 *h_errnop = NO_RECOVERY;
1014 return NSS_STATUS_UNAVAIL;
1017 u_char packtmp[NS_MAXCDNAME];
1018 int n = __ns_name_unpack (answer->buf, end_of_message, cp,
1019 packtmp, sizeof packtmp);
1020 /* We unpack the name to check it for validity. But we do not need
1021 it later. */
1022 if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
1024 if (__glibc_unlikely (errno == EMSGSIZE))
1026 too_small:
1027 *errnop = ERANGE;
1028 *h_errnop = NETDB_INTERNAL;
1029 return NSS_STATUS_TRYAGAIN;
1032 n = -1;
1035 if (__glibc_unlikely (n < 0))
1037 *errnop = errno;
1038 *h_errnop = NO_RECOVERY;
1039 return NSS_STATUS_UNAVAIL;
1041 if (__glibc_unlikely (res_hnok (buffer) == 0))
1043 errno = EBADMSG;
1044 *errnop = EBADMSG;
1045 *h_errnop = NO_RECOVERY;
1046 return NSS_STATUS_UNAVAIL;
1048 cp += n + QFIXEDSZ;
1050 int haveanswer = 0;
1051 int had_error = 0;
1052 char *canon = NULL;
1053 char *h_name = NULL;
1054 int h_namelen = 0;
1056 if (ancount == 0)
1058 *h_errnop = HOST_NOT_FOUND;
1059 return NSS_STATUS_NOTFOUND;
1062 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1064 n = __ns_name_unpack (answer->buf, end_of_message, cp,
1065 packtmp, sizeof packtmp);
1066 if (n != -1 &&
1067 (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
1069 if (__glibc_unlikely (errno == EMSGSIZE))
1070 goto too_small;
1072 n = -1;
1074 if (__glibc_unlikely (n < 0 || res_hnok (buffer) == 0))
1076 ++had_error;
1077 continue;
1079 if (*firstp && canon == NULL)
1081 h_name = buffer;
1082 buffer += h_namelen;
1083 buflen -= h_namelen;
1086 cp += n; /* name */
1088 if (__glibc_unlikely (cp + 10 > end_of_message))
1090 ++had_error;
1091 continue;
1094 int type = __ns_get16 (cp);
1095 cp += INT16SZ; /* type */
1096 int class = __ns_get16 (cp);
1097 cp += INT16SZ; /* class */
1098 int32_t ttl = __ns_get32 (cp);
1099 cp += INT32SZ; /* TTL */
1100 n = __ns_get16 (cp);
1101 cp += INT16SZ; /* len */
1103 if (end_of_message - cp < n)
1105 /* RDATA extends beyond the end of the packet. */
1106 ++had_error;
1107 continue;
1110 if (class != C_IN)
1112 cp += n;
1113 continue;
1116 if (type == T_CNAME)
1118 char tbuf[MAXDNAME];
1120 /* A CNAME could also have a TTL entry. */
1121 if (ttlp != NULL && ttl < *ttlp)
1122 *ttlp = ttl;
1124 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
1125 if (__glibc_unlikely (n < 0 || res_hnok (tbuf) == 0))
1127 ++had_error;
1128 continue;
1130 cp += n;
1132 if (*firstp)
1134 /* Reclaim buffer space. */
1135 if (h_name + h_namelen == buffer)
1137 buffer = h_name;
1138 buflen += h_namelen;
1141 n = strlen (tbuf) + 1;
1142 if (__glibc_unlikely (n > buflen))
1143 goto too_small;
1144 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1146 ++had_error;
1147 continue;
1150 canon = buffer;
1151 buffer = __mempcpy (buffer, tbuf, n);
1152 buflen -= n;
1153 h_namelen = 0;
1155 continue;
1158 /* Stop parsing if we encounter a record with incorrect RDATA
1159 length. */
1160 if (type == T_A || type == T_AAAA)
1162 if (n != rrtype_to_rdata_length (type))
1164 ++had_error;
1165 continue;
1168 else
1170 /* Skip unknown records. */
1171 cp += n;
1172 continue;
1175 assert (type == T_A || type == T_AAAA);
1176 if (*pat == NULL)
1178 uintptr_t pad = (-(uintptr_t) buffer
1179 % __alignof__ (struct gaih_addrtuple));
1180 buffer += pad;
1181 buflen = buflen > pad ? buflen - pad : 0;
1183 if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
1184 goto too_small;
1186 *pat = (struct gaih_addrtuple *) buffer;
1187 buffer += sizeof (struct gaih_addrtuple);
1188 buflen -= sizeof (struct gaih_addrtuple);
1191 (*pat)->name = NULL;
1192 (*pat)->next = NULL;
1194 if (*firstp)
1196 /* We compose a single hostent out of the entire chain of
1197 entries, so the TTL of the hostent is essentially the lowest
1198 TTL in the chain. */
1199 if (ttlp != NULL && ttl < *ttlp)
1200 *ttlp = ttl;
1202 (*pat)->name = canon ?: h_name;
1204 *firstp = 0;
1207 (*pat)->family = type == T_A ? AF_INET : AF_INET6;
1208 memcpy ((*pat)->addr, cp, n);
1209 cp += n;
1210 (*pat)->scopeid = 0;
1212 pat = &((*pat)->next);
1214 haveanswer = 1;
1217 if (haveanswer)
1219 *patp = pat;
1220 *bufferp = buffer;
1221 *buflenp = buflen;
1223 *h_errnop = NETDB_SUCCESS;
1224 return NSS_STATUS_SUCCESS;
1227 /* Special case here: if the resolver sent a result but it only
1228 contains a CNAME while we are looking for a T_A or T_AAAA record,
1229 we fail with NOTFOUND instead of TRYAGAIN. */
1230 if (canon != NULL)
1232 *h_errnop = HOST_NOT_FOUND;
1233 return NSS_STATUS_NOTFOUND;
1236 *h_errnop = NETDB_INTERNAL;
1237 return NSS_STATUS_TRYAGAIN;
1241 static enum nss_status
1242 gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
1243 int anslen2, const char *qname,
1244 struct gaih_addrtuple **pat, char *buffer, size_t buflen,
1245 int *errnop, int *h_errnop, int32_t *ttlp)
1247 int first = 1;
1249 enum nss_status status = NSS_STATUS_NOTFOUND;
1251 /* Combining the NSS status of two distinct queries requires some
1252 compromise and attention to symmetry (A or AAAA queries can be
1253 returned in any order). What follows is a breakdown of how this
1254 code is expected to work and why. We discuss only SUCCESS,
1255 TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
1256 that apply (though RETURN and MERGE exist). We make a distinction
1257 between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
1258 A recoverable TRYAGAIN is almost always due to buffer size issues
1259 and returns ERANGE in errno and the caller is expected to retry
1260 with a larger buffer.
1262 Lastly, you may be tempted to make significant changes to the
1263 conditions in this code to bring about symmetry between responses.
1264 Please don't change anything without due consideration for
1265 expected application behaviour. Some of the synthesized responses
1266 aren't very well thought out and sometimes appear to imply that
1267 IPv4 responses are always answer 1, and IPv6 responses are always
1268 answer 2, but that's not true (see the implementation of send_dg
1269 and send_vc to see response can arrive in any order, particularly
1270 for UDP). However, we expect it holds roughly enough of the time
1271 that this code works, but certainly needs to be fixed to make this
1272 a more robust implementation.
1274 ----------------------------------------------
1275 | Answer 1 Status / | Synthesized | Reason |
1276 | Answer 2 Status | Status | |
1277 |--------------------------------------------|
1278 | SUCCESS/SUCCESS | SUCCESS | [1] |
1279 | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
1280 | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
1281 | SUCCESS/NOTFOUND | SUCCESS | [1] |
1282 | SUCCESS/UNAVAIL | SUCCESS | [1] |
1283 | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
1284 | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
1285 | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
1286 | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
1287 | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
1288 | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
1289 | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
1290 | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
1291 | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
1292 | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
1293 | NOTFOUND/SUCCESS | SUCCESS | [3] |
1294 | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
1295 | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
1296 | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
1297 | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
1298 | UNAVAIL/SUCCESS | UNAVAIL | [4] |
1299 | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
1300 | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
1301 | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
1302 | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
1303 ----------------------------------------------
1305 [1] If the first response is a success we return success.
1306 This ignores the state of the second answer and in fact
1307 incorrectly sets errno and h_errno to that of the second
1308 answer. However because the response is a success we ignore
1309 *errnop and *h_errnop (though that means you touched errno on
1310 success). We are being conservative here and returning the
1311 likely IPv4 response in the first answer as a success.
1313 [2] If the first response is a recoverable TRYAGAIN we return
1314 that instead of looking at the second response. The
1315 expectation here is that we have failed to get an IPv4 response
1316 and should retry both queries.
1318 [3] If the first response was not a SUCCESS and the second
1319 response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
1320 or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
1321 result from the second response, otherwise the first responses
1322 status is used. Again we have some odd side-effects when the
1323 second response is NOTFOUND because we overwrite *errnop and
1324 *h_errnop that means that a first answer of NOTFOUND might see
1325 its *errnop and *h_errnop values altered. Whether it matters
1326 in practice that a first response NOTFOUND has the wrong
1327 *errnop and *h_errnop is undecided.
1329 [4] If the first response is UNAVAIL we return that instead of
1330 looking at the second response. The expectation here is that
1331 it will have failed similarly e.g. configuration failure.
1333 [5] Testing this code is complicated by the fact that truncated
1334 second response buffers might be returned as SUCCESS if the
1335 first answer is a SUCCESS. To fix this we add symmetry to
1336 TRYAGAIN with the second response. If the second response
1337 is a recoverable error we now return TRYAGIN even if the first
1338 response was SUCCESS. */
1340 if (anslen1 > 0)
1341 status = gaih_getanswer_slice(answer1, anslen1, qname,
1342 &pat, &buffer, &buflen,
1343 errnop, h_errnop, ttlp,
1344 &first);
1346 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
1347 || (status == NSS_STATUS_TRYAGAIN
1348 /* We want to look at the second answer in case of an
1349 NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
1350 *h_errnop is NO_RECOVERY. If not, and if the failure was due to
1351 an insufficient buffer (ERANGE), then we need to drop the results
1352 and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
1353 repeat the query with a larger buffer. */
1354 && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
1355 && answer2 != NULL && anslen2 > 0)
1357 enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
1358 &pat, &buffer, &buflen,
1359 errnop, h_errnop, ttlp,
1360 &first);
1361 /* Use the second response status in some cases. */
1362 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
1363 status = status2;
1364 /* Do not return a truncated second response (unless it was
1365 unavoidable e.g. unrecoverable TRYAGAIN). */
1366 if (status == NSS_STATUS_SUCCESS
1367 && (status2 == NSS_STATUS_TRYAGAIN
1368 && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
1369 status = NSS_STATUS_TRYAGAIN;
1372 return status;