Skip logging for DNSSEC responses [BZ 14841]
[glibc.git] / resolv / nss_dns / dns-host.c
blobb16b0ddf110907a0086b86612e544d3dc75182b8
1 /* Copyright (C) 1996-2015 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>
81 #include <sys/syslog.h>
83 #include "nsswitch.h"
85 /* Get implementation for some internal functions. */
86 #include <resolv/mapv4v6addr.h>
87 #include <resolv/mapv4v6hostent.h>
89 #define RESOLVSORT
91 #if PACKETSZ > 65536
92 # define MAXPACKET PACKETSZ
93 #else
94 # define MAXPACKET 65536
95 #endif
96 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
97 #ifdef MAXHOSTNAMELEN
98 # undef MAXHOSTNAMELEN
99 #endif
100 #define MAXHOSTNAMELEN 256
102 static const char AskedForGot[] = "\
103 gethostby*.getanswer: asked for \"%s\", got \"%s\"";
106 /* We need this time later. */
107 typedef union querybuf
109 HEADER hdr;
110 u_char buf[MAXPACKET];
111 } querybuf;
113 /* These functions are defined in res_comp.c. */
114 #define NS_MAXCDNAME 255 /* maximum compressed domain name */
115 extern int __ns_name_ntop (const u_char *, char *, size_t);
116 extern int __ns_name_unpack (const u_char *, const u_char *,
117 const u_char *, u_char *, size_t);
120 static enum nss_status getanswer_r (const querybuf *answer, int anslen,
121 const char *qname, int qtype,
122 struct hostent *result, char *buffer,
123 size_t buflen, int *errnop, int *h_errnop,
124 int map, int32_t *ttlp, char **canonp);
126 static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
127 const querybuf *answer2, int anslen2,
128 const char *qname,
129 struct gaih_addrtuple **pat,
130 char *buffer, size_t buflen,
131 int *errnop, int *h_errnop,
132 int32_t *ttlp);
134 extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
135 struct hostent *result,
136 char *buffer, size_t buflen,
137 int *errnop, int *h_errnop,
138 int32_t *ttlp,
139 char **canonp);
140 hidden_proto (_nss_dns_gethostbyname3_r)
142 enum nss_status
143 _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
144 char *buffer, size_t buflen, int *errnop,
145 int *h_errnop, int32_t *ttlp, char **canonp)
147 union
149 querybuf *buf;
150 u_char *ptr;
151 } host_buffer;
152 querybuf *orig_host_buffer;
153 char tmp[NS_MAXDNAME];
154 int size, type, n;
155 const char *cp;
156 int map = 0;
157 int olderr = errno;
158 enum nss_status status;
160 if (__res_maybe_init (&_res, 0) == -1)
161 return NSS_STATUS_UNAVAIL;
163 switch (af) {
164 case AF_INET:
165 size = INADDRSZ;
166 type = T_A;
167 break;
168 case AF_INET6:
169 size = IN6ADDRSZ;
170 type = T_AAAA;
171 break;
172 default:
173 *h_errnop = NO_DATA;
174 *errnop = EAFNOSUPPORT;
175 return NSS_STATUS_UNAVAIL;
178 result->h_addrtype = af;
179 result->h_length = size;
182 * if there aren't any dots, it could be a user-level alias.
183 * this is also done in res_query() since we are not the only
184 * function that looks up host names.
186 if (strchr (name, '.') == NULL
187 && (cp = res_hostalias (&_res, name, tmp, sizeof (tmp))) != NULL)
188 name = cp;
190 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
192 n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
193 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
194 if (n < 0)
196 switch (errno)
198 case ESRCH:
199 status = NSS_STATUS_TRYAGAIN;
200 h_errno = TRY_AGAIN;
201 break;
202 /* System has run out of file descriptors. */
203 case EMFILE:
204 case ENFILE:
205 h_errno = NETDB_INTERNAL;
206 /* Fall through. */
207 case ECONNREFUSED:
208 case ETIMEDOUT:
209 status = NSS_STATUS_UNAVAIL;
210 break;
211 default:
212 status = NSS_STATUS_NOTFOUND;
213 break;
215 *h_errnop = h_errno;
216 if (h_errno == TRY_AGAIN)
217 *errnop = EAGAIN;
218 else
219 __set_errno (olderr);
221 /* If we are looking for an IPv6 address and mapping is enabled
222 by having the RES_USE_INET6 bit in _res.options set, we try
223 another lookup. */
224 if (af == AF_INET6 && (_res.options & RES_USE_INET6))
225 n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
226 host_buffer.buf != orig_host_buffer
227 ? MAXPACKET : 1024, &host_buffer.ptr,
228 NULL, NULL, NULL, NULL);
230 if (n < 0)
232 if (host_buffer.buf != orig_host_buffer)
233 free (host_buffer.buf);
234 return status;
237 map = 1;
239 result->h_addrtype = AF_INET;
240 result->h_length = INADDRSZ;
243 status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen,
244 errnop, h_errnop, map, ttlp, canonp);
245 if (host_buffer.buf != orig_host_buffer)
246 free (host_buffer.buf);
247 return status;
249 hidden_def (_nss_dns_gethostbyname3_r)
252 enum nss_status
253 _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
254 char *buffer, size_t buflen, int *errnop,
255 int *h_errnop)
257 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
258 h_errnop, NULL, NULL);
262 enum nss_status
263 _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
264 char *buffer, size_t buflen, int *errnop,
265 int *h_errnop)
267 enum nss_status status = NSS_STATUS_NOTFOUND;
269 if (_res.options & RES_USE_INET6)
270 status = _nss_dns_gethostbyname3_r (name, AF_INET6, result, buffer,
271 buflen, errnop, h_errnop, NULL, NULL);
272 if (status == NSS_STATUS_NOTFOUND)
273 status = _nss_dns_gethostbyname3_r (name, AF_INET, result, buffer,
274 buflen, errnop, h_errnop, NULL, NULL);
276 return status;
280 enum nss_status
281 _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
282 char *buffer, size_t buflen, int *errnop,
283 int *herrnop, int32_t *ttlp)
285 if (__res_maybe_init (&_res, 0) == -1)
286 return NSS_STATUS_UNAVAIL;
289 * if there aren't any dots, it could be a user-level alias.
290 * this is also done in res_query() since we are not the only
291 * function that looks up host names.
293 if (strchr (name, '.') == NULL)
295 char *tmp = alloca (NS_MAXDNAME);
296 const char *cp = res_hostalias (&_res, name, tmp, NS_MAXDNAME);
297 if (cp != NULL)
298 name = cp;
301 union
303 querybuf *buf;
304 u_char *ptr;
305 } host_buffer;
306 querybuf *orig_host_buffer;
307 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
308 u_char *ans2p = NULL;
309 int nans2p = 0;
310 int resplen2 = 0;
311 int ans2p_malloced = 0;
313 int olderr = errno;
314 enum nss_status status;
315 int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
316 host_buffer.buf->buf, 2048, &host_buffer.ptr,
317 &ans2p, &nans2p, &resplen2, &ans2p_malloced);
318 if (n >= 0)
320 status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
321 resplen2, name, pat, buffer, buflen,
322 errnop, herrnop, ttlp);
324 else
326 switch (errno)
328 case ESRCH:
329 status = NSS_STATUS_TRYAGAIN;
330 h_errno = TRY_AGAIN;
331 break;
332 /* System has run out of file descriptors. */
333 case EMFILE:
334 case ENFILE:
335 h_errno = NETDB_INTERNAL;
336 /* Fall through. */
337 case ECONNREFUSED:
338 case ETIMEDOUT:
339 status = NSS_STATUS_UNAVAIL;
340 break;
341 default:
342 status = NSS_STATUS_NOTFOUND;
343 break;
346 *herrnop = h_errno;
347 if (h_errno == TRY_AGAIN)
348 *errnop = EAGAIN;
349 else
350 __set_errno (olderr);
353 /* Check whether ans2p was separately allocated. */
354 if (ans2p_malloced)
355 free (ans2p);
357 if (host_buffer.buf != orig_host_buffer)
358 free (host_buffer.buf);
360 return status;
364 extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
365 socklen_t len, int af,
366 struct hostent *result,
367 char *buffer, size_t buflen,
368 int *errnop, int *h_errnop,
369 int32_t *ttlp);
370 hidden_proto (_nss_dns_gethostbyaddr2_r)
372 enum nss_status
373 _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
374 struct hostent *result, char *buffer, size_t buflen,
375 int *errnop, int *h_errnop, int32_t *ttlp)
377 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
378 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
379 static const u_char v6local[] = { 0,0, 0,1 };
380 const u_char *uaddr = (const u_char *)addr;
381 struct host_data
383 char *aliases[MAX_NR_ALIASES];
384 unsigned char host_addr[16]; /* IPv4 or IPv6 */
385 char *h_addr_ptrs[MAX_NR_ADDRS + 1];
386 char linebuffer[0];
387 } *host_data = (struct host_data *) buffer;
388 union
390 querybuf *buf;
391 u_char *ptr;
392 } host_buffer;
393 querybuf *orig_host_buffer;
394 char qbuf[MAXDNAME+1], *qp = NULL;
395 size_t size;
396 int n, status;
397 int olderr = errno;
399 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
400 buffer += pad;
401 buflen = buflen > pad ? buflen - pad : 0;
403 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
405 *errnop = ERANGE;
406 *h_errnop = NETDB_INTERNAL;
407 return NSS_STATUS_TRYAGAIN;
410 host_data = (struct host_data *) buffer;
412 if (__res_maybe_init (&_res, 0) == -1)
413 return NSS_STATUS_UNAVAIL;
415 if (af == AF_INET6 && len == IN6ADDRSZ
416 && (memcmp (uaddr, mapped, sizeof mapped) == 0
417 || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
418 && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
420 /* Unmap. */
421 addr += sizeof mapped;
422 uaddr += sizeof mapped;
423 af = AF_INET;
424 len = INADDRSZ;
427 switch (af)
429 case AF_INET:
430 size = INADDRSZ;
431 break;
432 case AF_INET6:
433 size = IN6ADDRSZ;
434 break;
435 default:
436 *errnop = EAFNOSUPPORT;
437 *h_errnop = NETDB_INTERNAL;
438 return NSS_STATUS_UNAVAIL;
440 if (size > len)
442 *errnop = EAFNOSUPPORT;
443 *h_errnop = NETDB_INTERNAL;
444 return NSS_STATUS_UNAVAIL;
447 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
449 switch (af)
451 case AF_INET:
452 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
453 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
454 break;
455 case AF_INET6:
456 /* Only lookup with the byte string format if the user wants it. */
457 if (__glibc_unlikely (_res.options & RES_USEBSTRING))
459 qp = stpcpy (qbuf, "\\[x");
460 for (n = 0; n < IN6ADDRSZ; ++n)
461 qp += sprintf (qp, "%02hhx", uaddr[n]);
462 strcpy (qp, "].ip6.arpa");
463 n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
464 host_buffer.buf->buf, 1024, &host_buffer.ptr,
465 NULL, NULL, NULL, NULL);
466 if (n >= 0)
467 goto got_it_already;
469 qp = qbuf;
470 for (n = IN6ADDRSZ - 1; n >= 0; n--)
472 static const char nibblechar[16] = "0123456789abcdef";
473 *qp++ = nibblechar[uaddr[n] & 0xf];
474 *qp++ = '.';
475 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
476 *qp++ = '.';
478 strcpy(qp, "ip6.arpa");
479 break;
480 default:
481 /* Cannot happen. */
482 break;
485 n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
486 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
487 if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
489 strcpy (qp, "ip6.int");
490 n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
491 host_buffer.buf != orig_host_buffer
492 ? MAXPACKET : 1024, &host_buffer.ptr,
493 NULL, NULL, NULL, NULL);
495 if (n < 0)
497 *h_errnop = h_errno;
498 __set_errno (olderr);
499 if (host_buffer.buf != orig_host_buffer)
500 free (host_buffer.buf);
501 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
504 got_it_already:
505 status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
506 errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
507 if (host_buffer.buf != orig_host_buffer)
508 free (host_buffer.buf);
509 if (status != NSS_STATUS_SUCCESS)
510 return status;
512 #ifdef SUNSECURITY
513 This is not implemented because it is not possible to use the current
514 source from bind in a multi-threaded program.
515 #endif
517 result->h_addrtype = af;
518 result->h_length = len;
519 memcpy (host_data->host_addr, addr, len);
520 host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
521 host_data->h_addr_ptrs[1] = NULL;
522 #if 0
523 /* XXX I think this is wrong. Why should an IPv4 address be
524 converted to IPv6 if the user explicitly asked for IPv4? */
525 if (af == AF_INET && (_res.options & RES_USE_INET6))
527 map_v4v6_address ((char *) host_data->host_addr,
528 (char *) host_data->host_addr);
529 result->h_addrtype = AF_INET6;
530 result->h_length = IN6ADDRSZ;
532 #endif
533 *h_errnop = NETDB_SUCCESS;
534 return NSS_STATUS_SUCCESS;
536 hidden_def (_nss_dns_gethostbyaddr2_r)
539 enum nss_status
540 _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
541 struct hostent *result, char *buffer, size_t buflen,
542 int *errnop, int *h_errnop)
544 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
545 errnop, h_errnop, NULL);
548 #ifdef RESOLVSORT
549 static void addrsort (char **ap, int num);
551 static void
552 addrsort (char **ap, int num)
554 int i, j;
555 char **p;
556 short aval[MAX_NR_ADDRS];
557 int needsort = 0;
559 p = ap;
560 if (num > MAX_NR_ADDRS)
561 num = MAX_NR_ADDRS;
562 for (i = 0; i < num; i++, p++)
564 for (j = 0 ; (unsigned)j < _res.nsort; j++)
565 if (_res.sort_list[j].addr.s_addr ==
566 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
567 break;
568 aval[i] = j;
569 if (needsort == 0 && i > 0 && j < aval[i-1])
570 needsort = i;
572 if (!needsort)
573 return;
575 while (needsort++ < num)
576 for (j = needsort - 2; j >= 0; j--)
577 if (aval[j] > aval[j+1])
579 char *hp;
581 i = aval[j];
582 aval[j] = aval[j+1];
583 aval[j+1] = i;
585 hp = ap[j];
586 ap[j] = ap[j+1];
587 ap[j+1] = hp;
589 else
590 break;
592 #endif
594 static enum nss_status
595 getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
596 struct hostent *result, char *buffer, size_t buflen,
597 int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
599 struct host_data
601 char *aliases[MAX_NR_ALIASES];
602 unsigned char host_addr[16]; /* IPv4 or IPv6 */
603 char *h_addr_ptrs[0];
604 } *host_data;
605 int linebuflen;
606 const HEADER *hp;
607 const u_char *end_of_message, *cp;
608 int n, ancount, qdcount;
609 int haveanswer, had_error;
610 char *bp, **ap, **hap;
611 char tbuf[MAXDNAME];
612 const char *tname;
613 int (*name_ok) (const char *);
614 u_char packtmp[NS_MAXCDNAME];
615 int have_to_map = 0;
616 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
617 buffer += pad;
618 if (__glibc_unlikely (buflen < sizeof (struct host_data) + pad))
620 /* The buffer is too small. */
621 too_small:
622 *errnop = ERANGE;
623 *h_errnop = NETDB_INTERNAL;
624 return NSS_STATUS_TRYAGAIN;
626 host_data = (struct host_data *) buffer;
627 linebuflen = buflen - sizeof (struct host_data);
628 if (buflen - sizeof (struct host_data) != linebuflen)
629 linebuflen = INT_MAX;
631 tname = qname;
632 result->h_name = NULL;
633 end_of_message = answer->buf + anslen;
634 switch (qtype)
636 case T_A:
637 case T_AAAA:
638 name_ok = res_hnok;
639 break;
640 case T_PTR:
641 name_ok = res_dnok;
642 break;
643 default:
644 *errnop = ENOENT;
645 return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
649 * find first satisfactory answer
651 hp = &answer->hdr;
652 ancount = ntohs (hp->ancount);
653 qdcount = ntohs (hp->qdcount);
654 cp = answer->buf + HFIXEDSZ;
655 if (__builtin_expect (qdcount, 1) != 1)
657 *h_errnop = NO_RECOVERY;
658 return NSS_STATUS_UNAVAIL;
660 if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
661 goto too_small;
662 bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
663 linebuflen -= (ancount + 1) * sizeof (char *);
665 n = __ns_name_unpack (answer->buf, end_of_message, cp,
666 packtmp, sizeof packtmp);
667 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
669 if (__builtin_expect (errno, 0) == EMSGSIZE)
670 goto too_small;
672 n = -1;
675 if (n > 0 && bp[0] == '.')
676 bp[0] = '\0';
678 if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
681 *errnop = errno;
682 *h_errnop = NO_RECOVERY;
683 return NSS_STATUS_UNAVAIL;
685 cp += n + QFIXEDSZ;
687 if (qtype == T_A || qtype == T_AAAA)
689 /* res_send() has already verified that the query name is the
690 * same as the one we sent; this just gets the expanded name
691 * (i.e., with the succeeding search-domain tacked on).
693 n = strlen (bp) + 1; /* for the \0 */
694 if (n >= MAXHOSTNAMELEN)
696 *h_errnop = NO_RECOVERY;
697 *errnop = ENOENT;
698 return NSS_STATUS_TRYAGAIN;
700 result->h_name = bp;
701 bp += n;
702 linebuflen -= n;
703 if (linebuflen < 0)
704 goto too_small;
705 /* The qname can be abbreviated, but h_name is now absolute. */
706 qname = result->h_name;
709 ap = host_data->aliases;
710 *ap = NULL;
711 result->h_aliases = host_data->aliases;
712 hap = host_data->h_addr_ptrs;
713 *hap = NULL;
714 result->h_addr_list = host_data->h_addr_ptrs;
715 haveanswer = 0;
716 had_error = 0;
718 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
720 int type, class;
722 n = __ns_name_unpack (answer->buf, end_of_message, cp,
723 packtmp, sizeof packtmp);
724 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
726 if (__builtin_expect (errno, 0) == EMSGSIZE)
727 goto too_small;
729 n = -1;
732 if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
734 ++had_error;
735 continue;
737 cp += n; /* name */
739 if (__glibc_unlikely (cp + 10 > end_of_message))
741 ++had_error;
742 continue;
745 type = __ns_get16 (cp);
746 cp += INT16SZ; /* type */
747 class = __ns_get16 (cp);
748 cp += INT16SZ; /* class */
749 int32_t ttl = __ns_get32 (cp);
750 cp += INT32SZ; /* TTL */
751 n = __ns_get16 (cp);
752 cp += INT16SZ; /* len */
753 if (__glibc_unlikely (class != C_IN))
755 /* XXX - debug? syslog? */
756 cp += n;
757 continue; /* XXX - had_error++ ? */
760 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
762 /* A CNAME could also have a TTL entry. */
763 if (ttlp != NULL && ttl < *ttlp)
764 *ttlp = ttl;
766 if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
767 continue;
768 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
769 if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
771 ++had_error;
772 continue;
774 cp += n;
775 /* Store alias. */
776 *ap++ = bp;
777 n = strlen (bp) + 1; /* For the \0. */
778 if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
780 ++had_error;
781 continue;
783 bp += n;
784 linebuflen -= n;
785 /* Get canonical name. */
786 n = strlen (tbuf) + 1; /* For the \0. */
787 if (__glibc_unlikely (n > linebuflen))
788 goto too_small;
789 if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
791 ++had_error;
792 continue;
794 result->h_name = bp;
795 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
796 linebuflen -= n;
797 continue;
800 if (qtype == T_PTR && type == T_CNAME)
802 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
803 if (__glibc_unlikely (n < 0 || res_dnok (tbuf) == 0))
805 ++had_error;
806 continue;
808 cp += n;
809 /* Get canonical name. */
810 n = strlen (tbuf) + 1; /* For the \0. */
811 if (__glibc_unlikely (n > linebuflen))
812 goto too_small;
813 if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
815 ++had_error;
816 continue;
818 tname = bp;
819 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
820 linebuflen -= n;
821 continue;
824 if (type == T_A && qtype == T_AAAA && map)
825 have_to_map = 1;
826 else if (__glibc_unlikely (type != qtype))
828 /* Log a low priority message if we get an unexpected record, but
829 skip it if we are using DNSSEC since it uses many different types
830 in responses that do not match QTYPE. */
831 if ((_res.options & RES_USE_DNSSEC) == 0)
832 syslog (LOG_NOTICE | LOG_AUTH,
833 "gethostby*.getanswer: asked for \"%s %s %s\", "
834 "got type \"%s\"",
835 qname, p_class (C_IN), p_type (qtype), p_type (type));
836 cp += n;
837 continue; /* XXX - had_error++ ? */
840 switch (type)
842 case T_PTR:
843 if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
845 syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
846 cp += n;
847 continue; /* XXX - had_error++ ? */
850 n = __ns_name_unpack (answer->buf, end_of_message, cp,
851 packtmp, sizeof packtmp);
852 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
854 if (__builtin_expect (errno, 0) == EMSGSIZE)
855 goto too_small;
857 n = -1;
860 if (__glibc_unlikely (n < 0 || res_hnok (bp) == 0))
862 ++had_error;
863 break;
865 /* bind would put multiple PTR records as aliases, but we don't do
866 that. */
867 result->h_name = bp;
868 if (have_to_map)
870 n = strlen (bp) + 1; /* for the \0 */
871 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
873 ++had_error;
874 break;
876 bp += n;
877 linebuflen -= n;
878 if (map_v4v6_hostent (result, &bp, &linebuflen))
879 goto too_small;
881 *h_errnop = NETDB_SUCCESS;
882 return NSS_STATUS_SUCCESS;
883 case T_A:
884 case T_AAAA:
885 if (__builtin_expect (strcasecmp (result->h_name, bp), 0) != 0)
887 syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp);
888 cp += n;
889 continue; /* XXX - had_error++ ? */
891 if (n != result->h_length)
893 cp += n;
894 continue;
896 if (!haveanswer)
898 int nn;
900 /* We compose a single hostent out of the entire chain of
901 entries, so the TTL of the hostent is essentially the lowest
902 TTL in the chain. */
903 if (ttlp != NULL && ttl < *ttlp)
904 *ttlp = ttl;
905 if (canonp != NULL)
906 *canonp = bp;
907 result->h_name = bp;
908 nn = strlen (bp) + 1; /* for the \0 */
909 bp += nn;
910 linebuflen -= nn;
913 linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
914 bp += sizeof (align) - ((u_long) bp % sizeof (align));
916 if (__glibc_unlikely (n > linebuflen))
917 goto too_small;
918 bp = __mempcpy (*hap++ = bp, cp, n);
919 cp += n;
920 linebuflen -= n;
921 break;
922 default:
923 abort ();
925 if (had_error == 0)
926 ++haveanswer;
929 if (haveanswer > 0)
931 *ap = NULL;
932 *hap = NULL;
933 #if defined RESOLVSORT
935 * Note: we sort even if host can take only one address
936 * in its return structures - should give it the "best"
937 * address in that case, not some random one
939 if (_res.nsort && haveanswer > 1 && qtype == T_A)
940 addrsort (host_data->h_addr_ptrs, haveanswer);
941 #endif /*RESOLVSORT*/
943 if (result->h_name == NULL)
945 n = strlen (qname) + 1; /* For the \0. */
946 if (n > linebuflen)
947 goto too_small;
948 if (n >= MAXHOSTNAMELEN)
949 goto no_recovery;
950 result->h_name = bp;
951 bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
952 linebuflen -= n;
955 if (have_to_map)
956 if (map_v4v6_hostent (result, &bp, &linebuflen))
957 goto too_small;
958 *h_errnop = NETDB_SUCCESS;
959 return NSS_STATUS_SUCCESS;
961 no_recovery:
962 *h_errnop = NO_RECOVERY;
963 *errnop = ENOENT;
964 /* Special case here: if the resolver sent a result but it only
965 contains a CNAME while we are looking for a T_A or T_AAAA record,
966 we fail with NOTFOUND instead of TRYAGAIN. */
967 return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
968 ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
972 static enum nss_status
973 gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
974 struct gaih_addrtuple ***patp,
975 char **bufferp, size_t *buflenp,
976 int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
978 char *buffer = *bufferp;
979 size_t buflen = *buflenp;
981 struct gaih_addrtuple **pat = *patp;
982 const HEADER *hp = &answer->hdr;
983 int ancount = ntohs (hp->ancount);
984 int qdcount = ntohs (hp->qdcount);
985 const u_char *cp = answer->buf + HFIXEDSZ;
986 const u_char *end_of_message = answer->buf + anslen;
987 if (__glibc_unlikely (qdcount != 1))
989 *h_errnop = NO_RECOVERY;
990 return NSS_STATUS_UNAVAIL;
993 u_char packtmp[NS_MAXCDNAME];
994 int n = __ns_name_unpack (answer->buf, end_of_message, cp,
995 packtmp, sizeof packtmp);
996 /* We unpack the name to check it for validity. But we do not need
997 it later. */
998 if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
1000 if (__builtin_expect (errno, 0) == EMSGSIZE)
1002 too_small:
1003 *errnop = ERANGE;
1004 *h_errnop = NETDB_INTERNAL;
1005 return NSS_STATUS_TRYAGAIN;
1008 n = -1;
1011 if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
1012 && (errno = EBADMSG)), 0))
1014 *errnop = errno;
1015 *h_errnop = NO_RECOVERY;
1016 return NSS_STATUS_UNAVAIL;
1018 cp += n + QFIXEDSZ;
1020 int haveanswer = 0;
1021 int had_error = 0;
1022 char *canon = NULL;
1023 char *h_name = NULL;
1024 int h_namelen = 0;
1026 if (ancount == 0)
1027 return NSS_STATUS_NOTFOUND;
1029 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1031 n = __ns_name_unpack (answer->buf, end_of_message, cp,
1032 packtmp, sizeof packtmp);
1033 if (n != -1 &&
1034 (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
1036 if (__builtin_expect (errno, 0) == EMSGSIZE)
1037 goto too_small;
1039 n = -1;
1041 if (__glibc_unlikely (n < 0 || res_hnok (buffer) == 0))
1043 ++had_error;
1044 continue;
1046 if (*firstp && canon == NULL)
1048 h_name = buffer;
1049 buffer += h_namelen;
1050 buflen -= h_namelen;
1053 cp += n; /* name */
1055 if (__glibc_unlikely (cp + 10 > end_of_message))
1057 ++had_error;
1058 continue;
1061 int type = __ns_get16 (cp);
1062 cp += INT16SZ; /* type */
1063 int class = __ns_get16 (cp);
1064 cp += INT16SZ; /* class */
1065 int32_t ttl = __ns_get32 (cp);
1066 cp += INT32SZ; /* TTL */
1067 n = __ns_get16 (cp);
1068 cp += INT16SZ; /* len */
1070 if (class != C_IN)
1072 cp += n;
1073 continue;
1076 if (type == T_CNAME)
1078 char tbuf[MAXDNAME];
1080 /* A CNAME could also have a TTL entry. */
1081 if (ttlp != NULL && ttl < *ttlp)
1082 *ttlp = ttl;
1084 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
1085 if (__glibc_unlikely (n < 0 || res_hnok (tbuf) == 0))
1087 ++had_error;
1088 continue;
1090 cp += n;
1092 if (*firstp)
1094 /* Reclaim buffer space. */
1095 if (h_name + h_namelen == buffer)
1097 buffer = h_name;
1098 buflen += h_namelen;
1101 n = strlen (tbuf) + 1;
1102 if (__glibc_unlikely (n > buflen))
1103 goto too_small;
1104 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1106 ++had_error;
1107 continue;
1110 canon = buffer;
1111 buffer = __mempcpy (buffer, tbuf, n);
1112 buflen -= n;
1113 h_namelen = 0;
1115 continue;
1117 #if 1
1118 // We should not see any types other than those explicitly listed
1119 // below. Some types sent by server seem missing, though. Just
1120 // collect the data for now.
1121 if (__glibc_unlikely (type != T_A && type != T_AAAA))
1122 #else
1123 if (__builtin_expect (type == T_SIG, 0)
1124 || __builtin_expect (type == T_KEY, 0)
1125 || __builtin_expect (type == T_NXT, 0)
1126 || __builtin_expect (type == T_PTR, 0)
1127 || __builtin_expect (type == T_DNAME, 0))
1128 #endif
1130 /* We don't support DNSSEC yet. For now, ignore the record
1131 and send a low priority message to syslog.
1133 We also don't expect T_PTR or T_DNAME messages. */
1134 syslog (LOG_DEBUG | LOG_AUTH,
1135 "getaddrinfo*.gaih_getanswer: got type \"%s\"",
1136 p_type (type));
1137 cp += n;
1138 continue;
1140 if (type != T_A && type != T_AAAA)
1141 abort ();
1143 if (*pat == NULL)
1145 uintptr_t pad = (-(uintptr_t) buffer
1146 % __alignof__ (struct gaih_addrtuple));
1147 buffer += pad;
1148 buflen = buflen > pad ? buflen - pad : 0;
1150 if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
1152 goto too_small;
1154 *pat = (struct gaih_addrtuple *) buffer;
1155 buffer += sizeof (struct gaih_addrtuple);
1156 buflen -= sizeof (struct gaih_addrtuple);
1159 (*pat)->name = NULL;
1160 (*pat)->next = NULL;
1162 if (*firstp)
1164 /* We compose a single hostent out of the entire chain of
1165 entries, so the TTL of the hostent is essentially the lowest
1166 TTL in the chain. */
1167 if (ttlp != NULL && ttl < *ttlp)
1168 *ttlp = ttl;
1170 (*pat)->name = canon ?: h_name;
1172 *firstp = 0;
1175 (*pat)->family = type == T_A ? AF_INET : AF_INET6;
1176 if (__builtin_expect ((type == T_A && n != INADDRSZ)
1177 || (type == T_AAAA && n != IN6ADDRSZ), 0))
1179 ++had_error;
1180 continue;
1182 memcpy ((*pat)->addr, cp, n);
1183 cp += n;
1184 (*pat)->scopeid = 0;
1186 pat = &((*pat)->next);
1188 haveanswer = 1;
1191 if (haveanswer)
1193 *patp = pat;
1194 *bufferp = buffer;
1195 *buflenp = buflen;
1197 *h_errnop = NETDB_SUCCESS;
1198 return NSS_STATUS_SUCCESS;
1201 /* Special case here: if the resolver sent a result but it only
1202 contains a CNAME while we are looking for a T_A or T_AAAA record,
1203 we fail with NOTFOUND instead of TRYAGAIN. */
1204 return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
1208 static enum nss_status
1209 gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
1210 int anslen2, const char *qname,
1211 struct gaih_addrtuple **pat, char *buffer, size_t buflen,
1212 int *errnop, int *h_errnop, int32_t *ttlp)
1214 int first = 1;
1216 enum nss_status status = NSS_STATUS_NOTFOUND;
1218 if (anslen1 > 0)
1219 status = gaih_getanswer_slice(answer1, anslen1, qname,
1220 &pat, &buffer, &buflen,
1221 errnop, h_errnop, ttlp,
1222 &first);
1223 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
1224 || (status == NSS_STATUS_TRYAGAIN
1225 /* We want to look at the second answer in case of an
1226 NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
1227 *h_errnop is NO_RECOVERY. If not, and if the failure was due to
1228 an insufficient buffer (ERANGE), then we need to drop the results
1229 and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
1230 repeat the query with a larger buffer. */
1231 && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
1232 && answer2 != NULL && anslen2 > 0)
1234 enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
1235 &pat, &buffer, &buflen,
1236 errnop, h_errnop, ttlp,
1237 &first);
1238 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
1239 status = status2;
1242 return status;