Add MREMAP_DONTUNMAP from Linux 5.7
[glibc.git] / resolv / nss_dns / dns-host.c
blob91c0a3b0e488af36b7f23b7fd5d0431f1fbe7788
1 /* Copyright (C) 1996-2020 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 <https://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>
81 #include <libc-pointer-arith.h>
83 #include "nsswitch.h"
84 #include <arpa/nameser.h>
86 #include <resolv/resolv-internal.h>
87 #include <resolv/resolv_context.h>
89 /* Get implementations of some internal functions. */
90 #include <resolv/mapv4v6addr.h>
91 #include <resolv/mapv4v6hostent.h>
93 NSS_DECLARE_MODULE_FUNCTIONS (dns)
95 #define RESOLVSORT
97 #if PACKETSZ > 65536
98 # define MAXPACKET PACKETSZ
99 #else
100 # define MAXPACKET 65536
101 #endif
102 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
103 #ifdef MAXHOSTNAMELEN
104 # undef MAXHOSTNAMELEN
105 #endif
106 #define MAXHOSTNAMELEN 256
108 /* We need this time later. */
109 typedef union querybuf
111 HEADER hdr;
112 u_char buf[MAXPACKET];
113 } querybuf;
115 static enum nss_status getanswer_r (struct resolv_context *ctx,
116 const querybuf *answer, int anslen,
117 const char *qname, int qtype,
118 struct hostent *result, char *buffer,
119 size_t buflen, int *errnop, int *h_errnop,
120 int map, int32_t *ttlp, char **canonp);
122 static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
123 const querybuf *answer2, int anslen2,
124 const char *qname,
125 struct gaih_addrtuple **pat,
126 char *buffer, size_t buflen,
127 int *errnop, int *h_errnop,
128 int32_t *ttlp);
130 static enum nss_status gethostbyname3_context (struct resolv_context *ctx,
131 const char *name, int af,
132 struct hostent *result,
133 char *buffer, size_t buflen,
134 int *errnop, int *h_errnop,
135 int32_t *ttlp,
136 char **canonp);
138 /* Return the expected RDATA length for an address record type (A or
139 AAAA). */
140 static int
141 rrtype_to_rdata_length (int type)
143 switch (type)
145 case T_A:
146 return INADDRSZ;
147 case T_AAAA:
148 return IN6ADDRSZ;
149 default:
150 return -1;
155 enum nss_status
156 _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
157 char *buffer, size_t buflen, int *errnop,
158 int *h_errnop, int32_t *ttlp, char **canonp)
160 struct resolv_context *ctx = __resolv_context_get ();
161 if (ctx == NULL)
163 *errnop = errno;
164 *h_errnop = NETDB_INTERNAL;
165 return NSS_STATUS_UNAVAIL;
167 enum nss_status status = gethostbyname3_context
168 (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
169 __resolv_context_put (ctx);
170 return status;
173 static enum nss_status
174 gethostbyname3_context (struct resolv_context *ctx,
175 const char *name, int af, struct hostent *result,
176 char *buffer, size_t buflen, int *errnop,
177 int *h_errnop, int32_t *ttlp, char **canonp)
179 union
181 querybuf *buf;
182 u_char *ptr;
183 } host_buffer;
184 querybuf *orig_host_buffer;
185 char tmp[NS_MAXDNAME];
186 int size, type, n;
187 const char *cp;
188 int map = 0;
189 int olderr = errno;
190 enum nss_status status;
192 switch (af) {
193 case AF_INET:
194 size = INADDRSZ;
195 type = T_A;
196 break;
197 case AF_INET6:
198 size = IN6ADDRSZ;
199 type = T_AAAA;
200 break;
201 default:
202 *h_errnop = NO_DATA;
203 *errnop = EAFNOSUPPORT;
204 return NSS_STATUS_UNAVAIL;
207 result->h_addrtype = af;
208 result->h_length = size;
211 * if there aren't any dots, it could be a user-level alias.
212 * this is also done in res_query() since we are not the only
213 * function that looks up host names.
215 if (strchr (name, '.') == NULL
216 && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
217 name = cp;
219 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
221 n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
222 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
223 if (n < 0)
225 switch (errno)
227 case ESRCH:
228 status = NSS_STATUS_TRYAGAIN;
229 h_errno = TRY_AGAIN;
230 break;
231 /* System has run out of file descriptors. */
232 case EMFILE:
233 case ENFILE:
234 h_errno = NETDB_INTERNAL;
235 /* Fall through. */
236 case ECONNREFUSED:
237 case ETIMEDOUT:
238 status = NSS_STATUS_UNAVAIL;
239 break;
240 default:
241 status = NSS_STATUS_NOTFOUND;
242 break;
244 *h_errnop = h_errno;
245 if (h_errno == TRY_AGAIN)
246 *errnop = EAGAIN;
247 else
248 __set_errno (olderr);
250 /* If we are looking for an IPv6 address and mapping is enabled
251 by having the RES_USE_INET6 bit in _res.options set, we try
252 another lookup. */
253 if (af == AF_INET6 && res_use_inet6 ())
254 n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
255 host_buffer.buf != orig_host_buffer
256 ? MAXPACKET : 1024, &host_buffer.ptr,
257 NULL, NULL, NULL, NULL);
259 if (n < 0)
261 if (host_buffer.buf != orig_host_buffer)
262 free (host_buffer.buf);
263 return status;
266 map = 1;
268 result->h_addrtype = AF_INET;
269 result->h_length = INADDRSZ;
272 status = getanswer_r
273 (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
274 errnop, h_errnop, map, ttlp, canonp);
275 if (host_buffer.buf != orig_host_buffer)
276 free (host_buffer.buf);
277 return status;
280 /* Verify that the name looks like a host name. There is no point in
281 sending a query which will not produce a usable name in the
282 response. */
283 static enum nss_status
284 check_name (const char *name, int *h_errnop)
286 if (res_hnok (name))
287 return NSS_STATUS_SUCCESS;
288 *h_errnop = HOST_NOT_FOUND;
289 return NSS_STATUS_NOTFOUND;
292 enum nss_status
293 _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
294 char *buffer, size_t buflen, int *errnop,
295 int *h_errnop)
297 enum nss_status status = check_name (name, h_errnop);
298 if (status != NSS_STATUS_SUCCESS)
299 return status;
300 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
301 h_errnop, NULL, NULL);
305 enum nss_status
306 _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
307 char *buffer, size_t buflen, int *errnop,
308 int *h_errnop)
310 enum nss_status status = check_name (name, h_errnop);
311 if (status != NSS_STATUS_SUCCESS)
312 return status;
313 struct resolv_context *ctx = __resolv_context_get ();
314 if (ctx == NULL)
316 *errnop = errno;
317 *h_errnop = NETDB_INTERNAL;
318 return NSS_STATUS_UNAVAIL;
320 status = NSS_STATUS_NOTFOUND;
321 if (res_use_inet6 ())
322 status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
323 buflen, errnop, h_errnop, NULL, NULL);
324 if (status == NSS_STATUS_NOTFOUND)
325 status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
326 buflen, errnop, h_errnop, NULL, NULL);
327 __resolv_context_put (ctx);
328 return status;
332 enum nss_status
333 _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
334 char *buffer, size_t buflen, int *errnop,
335 int *herrnop, int32_t *ttlp)
337 enum nss_status status = check_name (name, herrnop);
338 if (status != NSS_STATUS_SUCCESS)
339 return status;
340 struct resolv_context *ctx = __resolv_context_get ();
341 if (ctx == NULL)
343 *errnop = errno;
344 *herrnop = NETDB_INTERNAL;
345 return NSS_STATUS_UNAVAIL;
349 * if there aren't any dots, it could be a user-level alias.
350 * this is also done in res_query() since we are not the only
351 * function that looks up host names.
353 if (strchr (name, '.') == NULL)
355 char *tmp = alloca (NS_MAXDNAME);
356 const char *cp = __res_context_hostalias (ctx, name, tmp, NS_MAXDNAME);
357 if (cp != NULL)
358 name = cp;
361 union
363 querybuf *buf;
364 u_char *ptr;
365 } host_buffer;
366 querybuf *orig_host_buffer;
367 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
368 u_char *ans2p = NULL;
369 int nans2p = 0;
370 int resplen2 = 0;
371 int ans2p_malloced = 0;
373 int olderr = errno;
374 int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
375 host_buffer.buf->buf, 2048, &host_buffer.ptr,
376 &ans2p, &nans2p, &resplen2, &ans2p_malloced);
377 if (n >= 0)
379 status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
380 resplen2, name, pat, buffer, buflen,
381 errnop, herrnop, ttlp);
383 else
385 switch (errno)
387 case ESRCH:
388 status = NSS_STATUS_TRYAGAIN;
389 h_errno = TRY_AGAIN;
390 break;
391 /* System has run out of file descriptors. */
392 case EMFILE:
393 case ENFILE:
394 h_errno = NETDB_INTERNAL;
395 /* Fall through. */
396 case ECONNREFUSED:
397 case ETIMEDOUT:
398 status = NSS_STATUS_UNAVAIL;
399 break;
400 default:
401 status = NSS_STATUS_NOTFOUND;
402 break;
405 *herrnop = h_errno;
406 if (h_errno == TRY_AGAIN)
407 *errnop = EAGAIN;
408 else
409 __set_errno (olderr);
412 /* Check whether ans2p was separately allocated. */
413 if (ans2p_malloced)
414 free (ans2p);
416 if (host_buffer.buf != orig_host_buffer)
417 free (host_buffer.buf);
419 __resolv_context_put (ctx);
420 return status;
424 extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
425 socklen_t len, int af,
426 struct hostent *result,
427 char *buffer, size_t buflen,
428 int *errnop, int *h_errnop,
429 int32_t *ttlp);
430 hidden_proto (_nss_dns_gethostbyaddr2_r)
432 enum nss_status
433 _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
434 struct hostent *result, char *buffer, size_t buflen,
435 int *errnop, int *h_errnop, int32_t *ttlp)
437 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
438 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
439 static const u_char v6local[] = { 0,0, 0,1 };
440 const u_char *uaddr = (const u_char *)addr;
441 struct host_data
443 char *aliases[MAX_NR_ALIASES];
444 unsigned char host_addr[16]; /* IPv4 or IPv6 */
445 char *h_addr_ptrs[MAX_NR_ADDRS + 1];
446 char linebuffer[0];
447 } *host_data = (struct host_data *) buffer;
448 union
450 querybuf *buf;
451 u_char *ptr;
452 } host_buffer;
453 querybuf *orig_host_buffer;
454 char qbuf[MAXDNAME+1], *qp = NULL;
455 size_t size;
456 int n, status;
457 int olderr = errno;
459 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
460 buffer += pad;
461 buflen = buflen > pad ? buflen - pad : 0;
463 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
465 *errnop = ERANGE;
466 *h_errnop = NETDB_INTERNAL;
467 return NSS_STATUS_TRYAGAIN;
470 host_data = (struct host_data *) buffer;
472 struct resolv_context *ctx = __resolv_context_get ();
473 if (ctx == NULL)
475 *errnop = errno;
476 *h_errnop = NETDB_INTERNAL;
477 return NSS_STATUS_UNAVAIL;
480 if (af == AF_INET6 && len == IN6ADDRSZ
481 && (memcmp (uaddr, mapped, sizeof mapped) == 0
482 || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
483 && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
485 /* Unmap. */
486 addr += sizeof mapped;
487 uaddr += sizeof mapped;
488 af = AF_INET;
489 len = INADDRSZ;
492 switch (af)
494 case AF_INET:
495 size = INADDRSZ;
496 break;
497 case AF_INET6:
498 size = IN6ADDRSZ;
499 break;
500 default:
501 *errnop = EAFNOSUPPORT;
502 *h_errnop = NETDB_INTERNAL;
503 __resolv_context_put (ctx);
504 return NSS_STATUS_UNAVAIL;
506 if (size > len)
508 *errnop = EAFNOSUPPORT;
509 *h_errnop = NETDB_INTERNAL;
510 __resolv_context_put (ctx);
511 return NSS_STATUS_UNAVAIL;
514 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
516 switch (af)
518 case AF_INET:
519 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
520 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
521 break;
522 case AF_INET6:
523 qp = qbuf;
524 for (n = IN6ADDRSZ - 1; n >= 0; n--)
526 static const char nibblechar[16] = "0123456789abcdef";
527 *qp++ = nibblechar[uaddr[n] & 0xf];
528 *qp++ = '.';
529 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
530 *qp++ = '.';
532 strcpy(qp, "ip6.arpa");
533 break;
534 default:
535 /* Cannot happen. */
536 break;
539 n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
540 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
541 if (n < 0)
543 *h_errnop = h_errno;
544 __set_errno (olderr);
545 if (host_buffer.buf != orig_host_buffer)
546 free (host_buffer.buf);
547 __resolv_context_put (ctx);
548 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
551 status = getanswer_r
552 (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
553 errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
554 if (host_buffer.buf != orig_host_buffer)
555 free (host_buffer.buf);
556 if (status != NSS_STATUS_SUCCESS)
558 __resolv_context_put (ctx);
559 return status;
562 result->h_addrtype = af;
563 result->h_length = len;
564 memcpy (host_data->host_addr, addr, len);
565 host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
566 host_data->h_addr_ptrs[1] = NULL;
567 *h_errnop = NETDB_SUCCESS;
568 __resolv_context_put (ctx);
569 return NSS_STATUS_SUCCESS;
571 hidden_def (_nss_dns_gethostbyaddr2_r)
574 enum nss_status
575 _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
576 struct hostent *result, char *buffer, size_t buflen,
577 int *errnop, int *h_errnop)
579 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
580 errnop, h_errnop, NULL);
583 static void
584 addrsort (struct resolv_context *ctx, char **ap, int num)
586 int i, j;
587 char **p;
588 short aval[MAX_NR_ADDRS];
589 int needsort = 0;
590 size_t nsort = __resolv_context_sort_count (ctx);
592 p = ap;
593 if (num > MAX_NR_ADDRS)
594 num = MAX_NR_ADDRS;
595 for (i = 0; i < num; i++, p++)
597 for (j = 0 ; (unsigned)j < nsort; j++)
599 struct resolv_sortlist_entry e
600 = __resolv_context_sort_entry (ctx, j);
601 if (e.addr.s_addr == (((struct in_addr *)(*p))->s_addr & e.mask))
602 break;
604 aval[i] = j;
605 if (needsort == 0 && i > 0 && j < aval[i-1])
606 needsort = i;
608 if (!needsort)
609 return;
611 while (needsort++ < num)
612 for (j = needsort - 2; j >= 0; j--)
613 if (aval[j] > aval[j+1])
615 char *hp;
617 i = aval[j];
618 aval[j] = aval[j+1];
619 aval[j+1] = i;
621 hp = ap[j];
622 ap[j] = ap[j+1];
623 ap[j+1] = hp;
625 else
626 break;
629 static enum nss_status
630 getanswer_r (struct resolv_context *ctx,
631 const querybuf *answer, int anslen, const char *qname, int qtype,
632 struct hostent *result, char *buffer, size_t buflen,
633 int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
635 struct host_data
637 char *aliases[MAX_NR_ALIASES];
638 unsigned char host_addr[16]; /* IPv4 or IPv6 */
639 char *h_addr_ptrs[0];
640 } *host_data;
641 int linebuflen;
642 const HEADER *hp;
643 const u_char *end_of_message, *cp;
644 int n, ancount, qdcount;
645 int haveanswer, had_error;
646 char *bp, **ap, **hap;
647 char tbuf[MAXDNAME];
648 const char *tname;
649 int (*name_ok) (const char *);
650 u_char packtmp[NS_MAXCDNAME];
651 int have_to_map = 0;
652 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
653 buffer += pad;
654 buflen = buflen > pad ? buflen - pad : 0;
655 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
657 /* The buffer is too small. */
658 too_small:
659 *errnop = ERANGE;
660 *h_errnop = NETDB_INTERNAL;
661 return NSS_STATUS_TRYAGAIN;
663 host_data = (struct host_data *) buffer;
664 linebuflen = buflen - sizeof (struct host_data);
665 if (buflen - sizeof (struct host_data) != linebuflen)
666 linebuflen = INT_MAX;
668 tname = qname;
669 result->h_name = NULL;
670 end_of_message = answer->buf + anslen;
671 switch (qtype)
673 case T_A:
674 case T_AAAA:
675 name_ok = res_hnok;
676 break;
677 case T_PTR:
678 name_ok = res_dnok;
679 break;
680 default:
681 *errnop = ENOENT;
682 return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
686 * find first satisfactory answer
688 hp = &answer->hdr;
689 ancount = ntohs (hp->ancount);
690 qdcount = ntohs (hp->qdcount);
691 cp = answer->buf + HFIXEDSZ;
692 if (__glibc_unlikely (qdcount != 1))
694 *h_errnop = NO_RECOVERY;
695 return NSS_STATUS_UNAVAIL;
697 if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
698 goto too_small;
699 bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
700 linebuflen -= (ancount + 1) * sizeof (char *);
702 n = __ns_name_unpack (answer->buf, end_of_message, cp,
703 packtmp, sizeof packtmp);
704 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
706 if (__glibc_unlikely (errno == EMSGSIZE))
707 goto too_small;
709 n = -1;
712 if (__glibc_unlikely (n < 0))
714 *errnop = errno;
715 *h_errnop = NO_RECOVERY;
716 return NSS_STATUS_UNAVAIL;
718 if (__glibc_unlikely (name_ok (bp) == 0))
720 errno = EBADMSG;
721 *errnop = EBADMSG;
722 *h_errnop = NO_RECOVERY;
723 return NSS_STATUS_UNAVAIL;
725 cp += n + QFIXEDSZ;
727 if (qtype == T_A || qtype == T_AAAA)
729 /* res_send() has already verified that the query name is the
730 * same as the one we sent; this just gets the expanded name
731 * (i.e., with the succeeding search-domain tacked on).
733 n = strlen (bp) + 1; /* for the \0 */
734 if (n >= MAXHOSTNAMELEN)
736 *h_errnop = NO_RECOVERY;
737 *errnop = ENOENT;
738 return NSS_STATUS_TRYAGAIN;
740 result->h_name = bp;
741 bp += n;
742 linebuflen -= n;
743 if (linebuflen < 0)
744 goto too_small;
745 /* The qname can be abbreviated, but h_name is now absolute. */
746 qname = result->h_name;
749 ap = host_data->aliases;
750 *ap = NULL;
751 result->h_aliases = host_data->aliases;
752 hap = host_data->h_addr_ptrs;
753 *hap = NULL;
754 result->h_addr_list = host_data->h_addr_ptrs;
755 haveanswer = 0;
756 had_error = 0;
758 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
760 int type, class;
762 n = __ns_name_unpack (answer->buf, end_of_message, cp,
763 packtmp, sizeof packtmp);
764 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
766 if (__glibc_unlikely (errno == EMSGSIZE))
767 goto too_small;
769 n = -1;
772 if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
774 ++had_error;
775 continue;
777 cp += n; /* name */
779 if (__glibc_unlikely (cp + 10 > end_of_message))
781 ++had_error;
782 continue;
785 type = __ns_get16 (cp);
786 cp += INT16SZ; /* type */
787 class = __ns_get16 (cp);
788 cp += INT16SZ; /* class */
789 int32_t ttl = __ns_get32 (cp);
790 cp += INT32SZ; /* TTL */
791 n = __ns_get16 (cp);
792 cp += INT16SZ; /* len */
794 if (end_of_message - cp < n)
796 /* RDATA extends beyond the end of the packet. */
797 ++had_error;
798 continue;
801 if (__glibc_unlikely (class != C_IN))
803 /* XXX - debug? syslog? */
804 cp += n;
805 continue; /* XXX - had_error++ ? */
808 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
810 /* A CNAME could also have a TTL entry. */
811 if (ttlp != NULL && ttl < *ttlp)
812 *ttlp = ttl;
814 if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
815 continue;
816 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
817 if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
819 ++had_error;
820 continue;
822 cp += n;
823 /* Store alias. */
824 *ap++ = bp;
825 n = strlen (bp) + 1; /* For the \0. */
826 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
828 ++had_error;
829 continue;
831 bp += n;
832 linebuflen -= n;
833 /* Get canonical name. */
834 n = strlen (tbuf) + 1; /* For the \0. */
835 if (__glibc_unlikely (n > linebuflen))
836 goto too_small;
837 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
839 ++had_error;
840 continue;
842 result->h_name = bp;
843 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
844 linebuflen -= n;
845 continue;
848 if (qtype == T_PTR && type == T_CNAME)
850 /* A CNAME could also have a TTL entry. */
851 if (ttlp != NULL && ttl < *ttlp)
852 *ttlp = ttl;
854 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
855 if (__glibc_unlikely (n < 0 || res_dnok (tbuf) == 0))
857 ++had_error;
858 continue;
860 cp += n;
861 /* Get canonical name. */
862 n = strlen (tbuf) + 1; /* For the \0. */
863 if (__glibc_unlikely (n > linebuflen))
864 goto too_small;
865 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
867 ++had_error;
868 continue;
870 tname = bp;
871 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
872 linebuflen -= n;
873 continue;
876 if (type == T_A && qtype == T_AAAA && map)
877 have_to_map = 1;
878 else if (__glibc_unlikely (type != qtype))
880 cp += n;
881 continue; /* XXX - had_error++ ? */
884 switch (type)
886 case T_PTR:
887 if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
889 cp += n;
890 continue; /* XXX - had_error++ ? */
893 n = __ns_name_unpack (answer->buf, end_of_message, cp,
894 packtmp, sizeof packtmp);
895 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
897 if (__glibc_unlikely (errno == EMSGSIZE))
898 goto too_small;
900 n = -1;
903 if (__glibc_unlikely (n < 0 || res_hnok (bp) == 0))
905 ++had_error;
906 break;
908 if (ttlp != NULL && ttl < *ttlp)
909 *ttlp = ttl;
910 /* bind would put multiple PTR records as aliases, but we don't do
911 that. */
912 result->h_name = bp;
913 *h_errnop = NETDB_SUCCESS;
914 return NSS_STATUS_SUCCESS;
915 case T_A:
916 case T_AAAA:
917 if (__glibc_unlikely (strcasecmp (result->h_name, bp) != 0))
919 cp += n;
920 continue; /* XXX - had_error++ ? */
923 /* Stop parsing at a record whose length is incorrect. */
924 if (n != rrtype_to_rdata_length (type))
926 ++had_error;
927 break;
930 /* Skip records of the wrong type. */
931 if (n != result->h_length)
933 cp += n;
934 continue;
936 if (!haveanswer)
938 int nn;
940 /* We compose a single hostent out of the entire chain of
941 entries, so the TTL of the hostent is essentially the lowest
942 TTL in the chain. */
943 if (ttlp != NULL && ttl < *ttlp)
944 *ttlp = ttl;
945 if (canonp != NULL)
946 *canonp = bp;
947 result->h_name = bp;
948 nn = strlen (bp) + 1; /* for the \0 */
949 bp += nn;
950 linebuflen -= nn;
953 /* Provide sufficient alignment for both address
954 families. */
955 enum { align = 4 };
956 _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
957 "struct in_addr alignment");
958 _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
959 "struct in6_addr alignment");
961 char *new_bp = PTR_ALIGN_UP (bp, align);
962 linebuflen -= new_bp - bp;
963 bp = new_bp;
966 if (__glibc_unlikely (n > linebuflen))
967 goto too_small;
968 bp = __mempcpy (*hap++ = bp, cp, n);
969 cp += n;
970 linebuflen -= n;
971 break;
972 default:
973 abort ();
975 if (had_error == 0)
976 ++haveanswer;
979 if (haveanswer > 0)
981 *ap = NULL;
982 *hap = NULL;
984 * Note: we sort even if host can take only one address
985 * in its return structures - should give it the "best"
986 * address in that case, not some random one
988 if (haveanswer > 1 && qtype == T_A
989 && __resolv_context_sort_count (ctx) > 0)
990 addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
992 if (result->h_name == NULL)
994 n = strlen (qname) + 1; /* For the \0. */
995 if (n > linebuflen)
996 goto too_small;
997 if (n >= MAXHOSTNAMELEN)
998 goto no_recovery;
999 result->h_name = bp;
1000 bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
1001 linebuflen -= n;
1004 if (have_to_map)
1005 if (map_v4v6_hostent (result, &bp, &linebuflen))
1006 goto too_small;
1007 *h_errnop = NETDB_SUCCESS;
1008 return NSS_STATUS_SUCCESS;
1010 no_recovery:
1011 *h_errnop = NO_RECOVERY;
1012 *errnop = ENOENT;
1013 /* Special case here: if the resolver sent a result but it only
1014 contains a CNAME while we are looking for a T_A or T_AAAA record,
1015 we fail with NOTFOUND instead of TRYAGAIN. */
1016 return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
1017 ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
1021 static enum nss_status
1022 gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
1023 struct gaih_addrtuple ***patp,
1024 char **bufferp, size_t *buflenp,
1025 int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
1027 char *buffer = *bufferp;
1028 size_t buflen = *buflenp;
1030 struct gaih_addrtuple **pat = *patp;
1031 const HEADER *hp = &answer->hdr;
1032 int ancount = ntohs (hp->ancount);
1033 int qdcount = ntohs (hp->qdcount);
1034 const u_char *cp = answer->buf + HFIXEDSZ;
1035 const u_char *end_of_message = answer->buf + anslen;
1036 if (__glibc_unlikely (qdcount != 1))
1038 *h_errnop = NO_RECOVERY;
1039 return NSS_STATUS_UNAVAIL;
1042 u_char packtmp[NS_MAXCDNAME];
1043 int n = __ns_name_unpack (answer->buf, end_of_message, cp,
1044 packtmp, sizeof packtmp);
1045 /* We unpack the name to check it for validity. But we do not need
1046 it later. */
1047 if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
1049 if (__glibc_unlikely (errno == EMSGSIZE))
1051 too_small:
1052 *errnop = ERANGE;
1053 *h_errnop = NETDB_INTERNAL;
1054 return NSS_STATUS_TRYAGAIN;
1057 n = -1;
1060 if (__glibc_unlikely (n < 0))
1062 *errnop = errno;
1063 *h_errnop = NO_RECOVERY;
1064 return NSS_STATUS_UNAVAIL;
1066 if (__glibc_unlikely (res_hnok (buffer) == 0))
1068 errno = EBADMSG;
1069 *errnop = EBADMSG;
1070 *h_errnop = NO_RECOVERY;
1071 return NSS_STATUS_UNAVAIL;
1073 cp += n + QFIXEDSZ;
1075 int haveanswer = 0;
1076 int had_error = 0;
1077 char *canon = NULL;
1078 char *h_name = NULL;
1079 int h_namelen = 0;
1081 if (ancount == 0)
1083 *h_errnop = HOST_NOT_FOUND;
1084 return NSS_STATUS_NOTFOUND;
1087 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1089 n = __ns_name_unpack (answer->buf, end_of_message, cp,
1090 packtmp, sizeof packtmp);
1091 if (n != -1 &&
1092 (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
1094 if (__glibc_unlikely (errno == EMSGSIZE))
1095 goto too_small;
1097 n = -1;
1099 if (__glibc_unlikely (n < 0 || res_hnok (buffer) == 0))
1101 ++had_error;
1102 continue;
1104 if (*firstp && canon == NULL)
1106 h_name = buffer;
1107 buffer += h_namelen;
1108 buflen -= h_namelen;
1111 cp += n; /* name */
1113 if (__glibc_unlikely (cp + 10 > end_of_message))
1115 ++had_error;
1116 continue;
1119 int type = __ns_get16 (cp);
1120 cp += INT16SZ; /* type */
1121 int class = __ns_get16 (cp);
1122 cp += INT16SZ; /* class */
1123 int32_t ttl = __ns_get32 (cp);
1124 cp += INT32SZ; /* TTL */
1125 n = __ns_get16 (cp);
1126 cp += INT16SZ; /* len */
1128 if (end_of_message - cp < n)
1130 /* RDATA extends beyond the end of the packet. */
1131 ++had_error;
1132 continue;
1135 if (class != C_IN)
1137 cp += n;
1138 continue;
1141 if (type == T_CNAME)
1143 char tbuf[MAXDNAME];
1145 /* A CNAME could also have a TTL entry. */
1146 if (ttlp != NULL && ttl < *ttlp)
1147 *ttlp = ttl;
1149 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
1150 if (__glibc_unlikely (n < 0 || res_hnok (tbuf) == 0))
1152 ++had_error;
1153 continue;
1155 cp += n;
1157 if (*firstp)
1159 /* Reclaim buffer space. */
1160 if (h_name + h_namelen == buffer)
1162 buffer = h_name;
1163 buflen += h_namelen;
1166 n = strlen (tbuf) + 1;
1167 if (__glibc_unlikely (n > buflen))
1168 goto too_small;
1169 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1171 ++had_error;
1172 continue;
1175 canon = buffer;
1176 buffer = __mempcpy (buffer, tbuf, n);
1177 buflen -= n;
1178 h_namelen = 0;
1180 continue;
1183 /* Stop parsing if we encounter a record with incorrect RDATA
1184 length. */
1185 if (type == T_A || type == T_AAAA)
1187 if (n != rrtype_to_rdata_length (type))
1189 ++had_error;
1190 continue;
1193 else
1195 /* Skip unknown records. */
1196 cp += n;
1197 continue;
1200 assert (type == T_A || type == T_AAAA);
1201 if (*pat == NULL)
1203 uintptr_t pad = (-(uintptr_t) buffer
1204 % __alignof__ (struct gaih_addrtuple));
1205 buffer += pad;
1206 buflen = buflen > pad ? buflen - pad : 0;
1208 if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
1209 goto too_small;
1211 *pat = (struct gaih_addrtuple *) buffer;
1212 buffer += sizeof (struct gaih_addrtuple);
1213 buflen -= sizeof (struct gaih_addrtuple);
1216 (*pat)->name = NULL;
1217 (*pat)->next = NULL;
1219 if (*firstp)
1221 /* We compose a single hostent out of the entire chain of
1222 entries, so the TTL of the hostent is essentially the lowest
1223 TTL in the chain. */
1224 if (ttlp != NULL && ttl < *ttlp)
1225 *ttlp = ttl;
1227 (*pat)->name = canon ?: h_name;
1229 *firstp = 0;
1232 (*pat)->family = type == T_A ? AF_INET : AF_INET6;
1233 memcpy ((*pat)->addr, cp, n);
1234 cp += n;
1235 (*pat)->scopeid = 0;
1237 pat = &((*pat)->next);
1239 haveanswer = 1;
1242 if (haveanswer)
1244 *patp = pat;
1245 *bufferp = buffer;
1246 *buflenp = buflen;
1248 *h_errnop = NETDB_SUCCESS;
1249 return NSS_STATUS_SUCCESS;
1252 /* Special case here: if the resolver sent a result but it only
1253 contains a CNAME while we are looking for a T_A or T_AAAA record,
1254 we fail with NOTFOUND instead of TRYAGAIN. */
1255 if (canon != NULL)
1257 *h_errnop = HOST_NOT_FOUND;
1258 return NSS_STATUS_NOTFOUND;
1261 *h_errnop = NETDB_INTERNAL;
1262 return NSS_STATUS_TRYAGAIN;
1266 static enum nss_status
1267 gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
1268 int anslen2, const char *qname,
1269 struct gaih_addrtuple **pat, char *buffer, size_t buflen,
1270 int *errnop, int *h_errnop, int32_t *ttlp)
1272 int first = 1;
1274 enum nss_status status = NSS_STATUS_NOTFOUND;
1276 /* Combining the NSS status of two distinct queries requires some
1277 compromise and attention to symmetry (A or AAAA queries can be
1278 returned in any order). What follows is a breakdown of how this
1279 code is expected to work and why. We discuss only SUCCESS,
1280 TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
1281 that apply (though RETURN and MERGE exist). We make a distinction
1282 between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
1283 A recoverable TRYAGAIN is almost always due to buffer size issues
1284 and returns ERANGE in errno and the caller is expected to retry
1285 with a larger buffer.
1287 Lastly, you may be tempted to make significant changes to the
1288 conditions in this code to bring about symmetry between responses.
1289 Please don't change anything without due consideration for
1290 expected application behaviour. Some of the synthesized responses
1291 aren't very well thought out and sometimes appear to imply that
1292 IPv4 responses are always answer 1, and IPv6 responses are always
1293 answer 2, but that's not true (see the implementation of send_dg
1294 and send_vc to see response can arrive in any order, particularly
1295 for UDP). However, we expect it holds roughly enough of the time
1296 that this code works, but certainly needs to be fixed to make this
1297 a more robust implementation.
1299 ----------------------------------------------
1300 | Answer 1 Status / | Synthesized | Reason |
1301 | Answer 2 Status | Status | |
1302 |--------------------------------------------|
1303 | SUCCESS/SUCCESS | SUCCESS | [1] |
1304 | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
1305 | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
1306 | SUCCESS/NOTFOUND | SUCCESS | [1] |
1307 | SUCCESS/UNAVAIL | SUCCESS | [1] |
1308 | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
1309 | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
1310 | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
1311 | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
1312 | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
1313 | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
1314 | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
1315 | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
1316 | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
1317 | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
1318 | NOTFOUND/SUCCESS | SUCCESS | [3] |
1319 | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
1320 | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
1321 | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
1322 | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
1323 | UNAVAIL/SUCCESS | UNAVAIL | [4] |
1324 | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
1325 | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
1326 | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
1327 | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
1328 ----------------------------------------------
1330 [1] If the first response is a success we return success.
1331 This ignores the state of the second answer and in fact
1332 incorrectly sets errno and h_errno to that of the second
1333 answer. However because the response is a success we ignore
1334 *errnop and *h_errnop (though that means you touched errno on
1335 success). We are being conservative here and returning the
1336 likely IPv4 response in the first answer as a success.
1338 [2] If the first response is a recoverable TRYAGAIN we return
1339 that instead of looking at the second response. The
1340 expectation here is that we have failed to get an IPv4 response
1341 and should retry both queries.
1343 [3] If the first response was not a SUCCESS and the second
1344 response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
1345 or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
1346 result from the second response, otherwise the first responses
1347 status is used. Again we have some odd side-effects when the
1348 second response is NOTFOUND because we overwrite *errnop and
1349 *h_errnop that means that a first answer of NOTFOUND might see
1350 its *errnop and *h_errnop values altered. Whether it matters
1351 in practice that a first response NOTFOUND has the wrong
1352 *errnop and *h_errnop is undecided.
1354 [4] If the first response is UNAVAIL we return that instead of
1355 looking at the second response. The expectation here is that
1356 it will have failed similarly e.g. configuration failure.
1358 [5] Testing this code is complicated by the fact that truncated
1359 second response buffers might be returned as SUCCESS if the
1360 first answer is a SUCCESS. To fix this we add symmetry to
1361 TRYAGAIN with the second response. If the second response
1362 is a recoverable error we now return TRYAGIN even if the first
1363 response was SUCCESS. */
1365 if (anslen1 > 0)
1366 status = gaih_getanswer_slice(answer1, anslen1, qname,
1367 &pat, &buffer, &buflen,
1368 errnop, h_errnop, ttlp,
1369 &first);
1371 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
1372 || (status == NSS_STATUS_TRYAGAIN
1373 /* We want to look at the second answer in case of an
1374 NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
1375 *h_errnop is NO_RECOVERY. If not, and if the failure was due to
1376 an insufficient buffer (ERANGE), then we need to drop the results
1377 and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
1378 repeat the query with a larger buffer. */
1379 && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
1380 && answer2 != NULL && anslen2 > 0)
1382 enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
1383 &pat, &buffer, &buflen,
1384 errnop, h_errnop, ttlp,
1385 &first);
1386 /* Use the second response status in some cases. */
1387 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
1388 status = status2;
1389 /* Do not return a truncated second response (unless it was
1390 unavoidable e.g. unrecoverable TRYAGAIN). */
1391 if (status == NSS_STATUS_SUCCESS
1392 && (status2 == NSS_STATUS_TRYAGAIN
1393 && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
1394 status = NSS_STATUS_TRYAGAIN;
1397 return status;