]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/nss_dns/dns-host.c
Skip logging for DNSSEC responses [BZ 14841]
[thirdparty/glibc.git] / resolv / nss_dns / dns-host.c
CommitLineData
b168057a 1/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
84384f5b
UD
2 This file is part of the GNU C Library.
3 Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
5f0e6fc7 4
84384f5b 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
5f0e6fc7 9
84384f5b
UD
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
41bdb6e2 13 Lesser General Public License for more details.
5f0e6fc7 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
5f0e6fc7 18
df21c858 19/* Parts of this file are plain copies of the file `gethtnamadr.c' from
5f0e6fc7
RM
20 the bind package and it has the following copyright. */
21
5f0e6fc7 22/*
df21c858
UD
23 * ++Copyright++ 1985, 1988, 1993
24 * -
25 * Copyright (c) 1985, 1988, 1993
26 * The Regents of the University of California. All rights reserved.
5f0e6fc7
RM
27 *
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.
5f0e6fc7
RM
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.
39 *
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.
df21c858
UD
51 * -
52 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
53 *
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.
60 *
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--
5f0e6fc7
RM
71 */
72
1eb946b9 73#include <assert.h>
5f0e6fc7
RM
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>
82
5f0e6fc7
RM
83#include "nsswitch.h"
84
85/* Get implementation for some internal functions. */
da2d1bc5
UD
86#include <resolv/mapv4v6addr.h>
87#include <resolv/mapv4v6hostent.h>
5f0e6fc7 88
5db91571
UD
89#define RESOLVSORT
90
e2dced82 91#if PACKETSZ > 65536
5f0e6fc7
RM
92# define MAXPACKET PACKETSZ
93#else
e2dced82 94# define MAXPACKET 65536
5f0e6fc7 95#endif
1522c368
UD
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
5f0e6fc7
RM
101
102static const char AskedForGot[] = "\
103gethostby*.getanswer: asked for \"%s\", got \"%s\"";
104
105
106/* We need this time later. */
107typedef union querybuf
108{
109 HEADER hdr;
110 u_char buf[MAXPACKET];
111} querybuf;
112
8d8c6efa
UD
113/* These functions are defined in res_comp.c. */
114#define NS_MAXCDNAME 255 /* maximum compressed domain name */
b455972f
UD
115extern int __ns_name_ntop (const u_char *, char *, size_t);
116extern int __ns_name_unpack (const u_char *, const u_char *,
117 const u_char *, u_char *, size_t);
8d8c6efa 118
5f0e6fc7
RM
119
120static enum nss_status getanswer_r (const querybuf *answer, int anslen,
121 const char *qname, int qtype,
df4ef2ab 122 struct hostent *result, char *buffer,
b455972f 123 size_t buflen, int *errnop, int *h_errnop,
d1fe1f22 124 int map, int32_t *ttlp, char **canonp);
5f0e6fc7 125
1eb946b9
UD
126static 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);
133
78d8d211
UD
134extern 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);
140hidden_proto (_nss_dns_gethostbyname3_r)
141
5f0e6fc7 142enum nss_status
d1fe1f22 143_nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
67479a70 144 char *buffer, size_t buflen, int *errnop,
d1fe1f22 145 int *h_errnop, int32_t *ttlp, char **canonp)
5f0e6fc7 146{
16b66062
AJ
147 union
148 {
149 querybuf *buf;
150 u_char *ptr;
151 } host_buffer;
152 querybuf *orig_host_buffer;
f80f1a4a 153 char tmp[NS_MAXDNAME];
5f0e6fc7
RM
154 int size, type, n;
155 const char *cp;
0420d888 156 int map = 0;
34816665 157 int olderr = errno;
6166815d 158 enum nss_status status;
5f0e6fc7 159
87bb6b6c 160 if (__res_maybe_init (&_res, 0) == -1)
b43b13ac
UD
161 return NSS_STATUS_UNAVAIL;
162
5f0e6fc7
RM
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:
0cc70fcf 173 *h_errnop = NO_DATA;
67479a70 174 *errnop = EAFNOSUPPORT;
5f0e6fc7
RM
175 return NSS_STATUS_UNAVAIL;
176 }
177
178 result->h_addrtype = af;
179 result->h_length = size;
180
181 /*
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.
185 */
f80f1a4a
UD
186 if (strchr (name, '.') == NULL
187 && (cp = res_hostalias (&_res, name, tmp, sizeof (tmp))) != NULL)
5f0e6fc7
RM
188 name = cp;
189
16b66062 190 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
6166815d 191
16b66062 192 n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
ab09bf61 193 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
5f0e6fc7 194 if (n < 0)
dd7d45e8 195 {
4535680d 196 switch (errno)
da5ac135 197 {
4535680d 198 case ESRCH:
da5ac135
UD
199 status = NSS_STATUS_TRYAGAIN;
200 h_errno = TRY_AGAIN;
4535680d 201 break;
cfde9b46
SP
202 /* System has run out of file descriptors. */
203 case EMFILE:
204 case ENFILE:
205 h_errno = NETDB_INTERNAL;
206 /* Fall through. */
4535680d
UD
207 case ECONNREFUSED:
208 case ETIMEDOUT:
209 status = NSS_STATUS_UNAVAIL;
210 break;
211 default:
212 status = NSS_STATUS_NOTFOUND;
213 break;
da5ac135 214 }
dd7d45e8 215 *h_errnop = h_errno;
34816665
UD
216 if (h_errno == TRY_AGAIN)
217 *errnop = EAGAIN;
218 else
219 __set_errno (olderr);
b455972f 220
4535680d 221 /* If we are looking for an IPv6 address and mapping is enabled
b455972f
UD
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))
16b66062
AJ
225 n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
226 host_buffer.buf != orig_host_buffer
1eb946b9 227 ? MAXPACKET : 1024, &host_buffer.ptr,
ab09bf61 228 NULL, NULL, NULL, NULL);
b455972f
UD
229
230 if (n < 0)
6166815d 231 {
16b66062
AJ
232 if (host_buffer.buf != orig_host_buffer)
233 free (host_buffer.buf);
6166815d
UD
234 return status;
235 }
b455972f
UD
236
237 map = 1;
238
239 result->h_addrtype = AF_INET;
2884dad4 240 result->h_length = INADDRSZ;
dd7d45e8 241 }
5f0e6fc7 242
16b66062 243 status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen,
d1fe1f22 244 errnop, h_errnop, map, ttlp, canonp);
16b66062
AJ
245 if (host_buffer.buf != orig_host_buffer)
246 free (host_buffer.buf);
6166815d 247 return status;
5f0e6fc7 248}
78d8d211 249hidden_def (_nss_dns_gethostbyname3_r)
5f0e6fc7
RM
250
251
d1fe1f22
UD
252enum 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)
256{
257 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
258 h_errnop, NULL, NULL);
259}
260
261
5f0e6fc7
RM
262enum nss_status
263_nss_dns_gethostbyname_r (const char *name, struct hostent *result,
67479a70
UD
264 char *buffer, size_t buflen, int *errnop,
265 int *h_errnop)
5f0e6fc7
RM
266{
267 enum nss_status status = NSS_STATUS_NOTFOUND;
268
269 if (_res.options & RES_USE_INET6)
78d8d211
UD
270 status = _nss_dns_gethostbyname3_r (name, AF_INET6, result, buffer,
271 buflen, errnop, h_errnop, NULL, NULL);
5f0e6fc7 272 if (status == NSS_STATUS_NOTFOUND)
78d8d211
UD
273 status = _nss_dns_gethostbyname3_r (name, AF_INET, result, buffer,
274 buflen, errnop, h_errnop, NULL, NULL);
5f0e6fc7
RM
275
276 return status;
277}
278
279
1eb946b9
UD
280enum 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)
284{
285 if (__res_maybe_init (&_res, 0) == -1)
286 return NSS_STATUS_UNAVAIL;
287
1eb946b9
UD
288 /*
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.
292 */
293 if (strchr (name, '.') == NULL)
294 {
b7da31a1
UD
295 char *tmp = alloca (NS_MAXDNAME);
296 const char *cp = res_hostalias (&_res, name, tmp, NS_MAXDNAME);
1eb946b9
UD
297 if (cp != NULL)
298 name = cp;
299 }
300
301 union
302 {
303 querybuf *buf;
304 u_char *ptr;
305 } host_buffer;
306 querybuf *orig_host_buffer;
ab09bf61 307 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
1eb946b9
UD
308 u_char *ans2p = NULL;
309 int nans2p = 0;
b7da31a1 310 int resplen2 = 0;
ab09bf61 311 int ans2p_malloced = 0;
1eb946b9
UD
312
313 int olderr = errno;
314 enum nss_status status;
315 int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
ab09bf61
AS
316 host_buffer.buf->buf, 2048, &host_buffer.ptr,
317 &ans2p, &nans2p, &resplen2, &ans2p_malloced);
ab7ac0f2
OB
318 if (n >= 0)
319 {
320 status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
321 resplen2, name, pat, buffer, buflen,
322 errnop, herrnop, ttlp);
323 }
324 else
1eb946b9 325 {
cfde9b46 326 switch (errno)
da5ac135 327 {
cfde9b46 328 case ESRCH:
da5ac135
UD
329 status = NSS_STATUS_TRYAGAIN;
330 h_errno = TRY_AGAIN;
cfde9b46
SP
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;
da5ac135 344 }
cfde9b46 345
1eb946b9
UD
346 *herrnop = h_errno;
347 if (h_errno == TRY_AGAIN)
348 *errnop = EAGAIN;
349 else
350 __set_errno (olderr);
1eb946b9
UD
351 }
352
d6680619 353 /* Check whether ans2p was separately allocated. */
ab09bf61 354 if (ans2p_malloced)
d6680619
AS
355 free (ans2p);
356
1eb946b9
UD
357 if (host_buffer.buf != orig_host_buffer)
358 free (host_buffer.buf);
359
360 return status;
361}
362
363
31e2791c
UD
364extern 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);
370hidden_proto (_nss_dns_gethostbyaddr2_r)
371
5f0e6fc7 372enum nss_status
31e2791c
UD
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)
5f0e6fc7
RM
376{
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 };
20cc4c87 379 static const u_char v6local[] = { 0,0, 0,1 };
5f0e6fc7
RM
380 const u_char *uaddr = (const u_char *)addr;
381 struct host_data
382 {
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;
16b66062
AJ
388 union
389 {
390 querybuf *buf;
391 u_char *ptr;
392 } host_buffer;
393 querybuf *orig_host_buffer;
1f3f143e 394 char qbuf[MAXDNAME+1], *qp = NULL;
30f22ab1 395 size_t size;
0420d888 396 int n, status;
34816665 397 int olderr = errno;
5f0e6fc7 398
df9293cb
UD
399 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
400 buffer += pad;
401 buflen = buflen > pad ? buflen - pad : 0;
402
a1ffb40e 403 if (__glibc_unlikely (buflen < sizeof (struct host_data)))
df9293cb
UD
404 {
405 *errnop = ERANGE;
406 *h_errnop = NETDB_INTERNAL;
407 return NSS_STATUS_TRYAGAIN;
408 }
409
410 host_data = (struct host_data *) buffer;
411
87bb6b6c 412 if (__res_maybe_init (&_res, 0) == -1)
b43b13ac
UD
413 return NSS_STATUS_UNAVAIL;
414
20cc4c87
UD
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))))
5f0e6fc7
RM
419 {
420 /* Unmap. */
421 addr += sizeof mapped;
422 uaddr += sizeof mapped;
423 af = AF_INET;
424 len = INADDRSZ;
425 }
426
427 switch (af)
428 {
429 case AF_INET:
430 size = INADDRSZ;
431 break;
432 case AF_INET6:
433 size = IN6ADDRSZ;
434 break;
435 default:
67479a70 436 *errnop = EAFNOSUPPORT;
5f0e6fc7
RM
437 *h_errnop = NETDB_INTERNAL;
438 return NSS_STATUS_UNAVAIL;
439 }
20cc4c87 440 if (size > len)
5f0e6fc7 441 {
67479a70 442 *errnop = EAFNOSUPPORT;
5f0e6fc7
RM
443 *h_errnop = NETDB_INTERNAL;
444 return NSS_STATUS_UNAVAIL;
445 }
446
ee778b56
UD
447 host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
448
5f0e6fc7
RM
449 switch (af)
450 {
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:
ee778b56 456 /* Only lookup with the byte string format if the user wants it. */
a1ffb40e 457 if (__glibc_unlikely (_res.options & RES_USEBSTRING))
ee778b56
UD
458 {
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,
1eb946b9 464 host_buffer.buf->buf, 1024, &host_buffer.ptr,
ab09bf61 465 NULL, NULL, NULL, NULL);
ee778b56
UD
466 if (n >= 0)
467 goto got_it_already;
468 }
5f0e6fc7 469 qp = qbuf;
ee778b56
UD
470 for (n = IN6ADDRSZ - 1; n >= 0; n--)
471 {
472 static const char nibblechar[16] = "0123456789abcdef";
473 *qp++ = nibblechar[uaddr[n] & 0xf];
474 *qp++ = '.';
475 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
476 *qp++ = '.';
477 }
478 strcpy(qp, "ip6.arpa");
5f0e6fc7
RM
479 break;
480 default:
481 /* Cannot happen. */
9fea9ed6 482 break;
5f0e6fc7
RM
483 }
484
16b66062 485 n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
ab09bf61 486 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
340ef046 487 if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
62a08e44
UD
488 {
489 strcpy (qp, "ip6.int");
16b66062
AJ
490 n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
491 host_buffer.buf != orig_host_buffer
1eb946b9 492 ? MAXPACKET : 1024, &host_buffer.ptr,
ab09bf61 493 NULL, NULL, NULL, NULL);
62a08e44 494 }
5f0e6fc7 495 if (n < 0)
dd7d45e8
UD
496 {
497 *h_errnop = h_errno;
34816665 498 __set_errno (olderr);
16b66062
AJ
499 if (host_buffer.buf != orig_host_buffer)
500 free (host_buffer.buf);
dd7d45e8
UD
501 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
502 }
5f0e6fc7 503
ee778b56 504 got_it_already:
16b66062 505 status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
31e2791c 506 errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
16b66062
AJ
507 if (host_buffer.buf != orig_host_buffer)
508 free (host_buffer.buf);
5f0e6fc7 509 if (status != NSS_STATUS_SUCCESS)
65b4743a 510 return status;
5f0e6fc7
RM
511
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
516
517 result->h_addrtype = af;
518 result->h_length = len;
63551311 519 memcpy (host_data->host_addr, addr, len);
5f0e6fc7
RM
520 host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
521 host_data->h_addr_ptrs[1] = NULL;
b455972f
UD
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? */
5f0e6fc7
RM
525 if (af == AF_INET && (_res.options & RES_USE_INET6))
526 {
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;
531 }
b455972f 532#endif
5f0e6fc7
RM
533 *h_errnop = NETDB_SUCCESS;
534 return NSS_STATUS_SUCCESS;
535}
31e2791c
UD
536hidden_def (_nss_dns_gethostbyaddr2_r)
537
538
539enum 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)
543{
544 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
545 errnop, h_errnop, NULL);
546}
5f0e6fc7 547
5db91571
UD
548#ifdef RESOLVSORT
549static void addrsort (char **ap, int num);
550
551static void
552addrsort (char **ap, int num)
553{
554 int i, j;
555 char **p;
556 short aval[MAX_NR_ADDRS];
557 int needsort = 0;
558
559 p = ap;
560 if (num > MAX_NR_ADDRS)
561 num = MAX_NR_ADDRS;
562 for (i = 0; i < num; i++, p++)
563 {
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;
571 }
572 if (!needsort)
573 return;
574
575 while (needsort++ < num)
576 for (j = needsort - 2; j >= 0; j--)
577 if (aval[j] > aval[j+1])
578 {
579 char *hp;
580
581 i = aval[j];
582 aval[j] = aval[j+1];
583 aval[j+1] = i;
584
585 hp = ap[j];
586 ap[j] = ap[j+1];
587 ap[j+1] = hp;
588 }
589 else
590 break;
591}
592#endif
5f0e6fc7
RM
593
594static enum nss_status
595getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
df4ef2ab 596 struct hostent *result, char *buffer, size_t buflen,
d1fe1f22 597 int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
5f0e6fc7
RM
598{
599 struct host_data
600 {
601 char *aliases[MAX_NR_ALIASES];
602 unsigned char host_addr[16]; /* IPv4 or IPv6 */
88a96b81 603 char *h_addr_ptrs[0];
2f1687b9
UD
604 } *host_data;
605 int linebuflen;
2e09a79a 606 const HEADER *hp;
5f0e6fc7
RM
607 const u_char *end_of_message, *cp;
608 int n, ancount, qdcount;
609 int haveanswer, had_error;
610 char *bp, **ap, **hap;
845dcb57 611 char tbuf[MAXDNAME];
5f0e6fc7 612 const char *tname;
b455972f 613 int (*name_ok) (const char *);
8d8c6efa 614 u_char packtmp[NS_MAXCDNAME];
b455972f 615 int have_to_map = 0;
2f1687b9
UD
616 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
617 buffer += pad;
a1ffb40e 618 if (__glibc_unlikely (buflen < sizeof (struct host_data) + pad))
560d3b76
UD
619 {
620 /* The buffer is too small. */
621 too_small:
622 *errnop = ERANGE;
623 *h_errnop = NETDB_INTERNAL;
624 return NSS_STATUS_TRYAGAIN;
625 }
2f1687b9
UD
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;
560d3b76 630
5f0e6fc7
RM
631 tname = qname;
632 result->h_name = NULL;
633 end_of_message = answer->buf + anslen;
634 switch (qtype)
635 {
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:
a0bf6ac7 644 *errnop = ENOENT;
5f0e6fc7
RM
645 return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */
646 }
647
648 /*
649 * find first satisfactory answer
650 */
651 hp = &answer->hdr;
5f0e6fc7
RM
652 ancount = ntohs (hp->ancount);
653 qdcount = ntohs (hp->qdcount);
654 cp = answer->buf + HFIXEDSZ;
b455972f 655 if (__builtin_expect (qdcount, 1) != 1)
5f0e6fc7
RM
656 {
657 *h_errnop = NO_RECOVERY;
658 return NSS_STATUS_UNAVAIL;
659 }
88a96b81
UD
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 *);
5f0e6fc7 664
8d8c6efa
UD
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)
5f0e6fc7 668 {
b455972f 669 if (__builtin_expect (errno, 0) == EMSGSIZE)
560d3b76 670 goto too_small;
8d8c6efa
UD
671
672 n = -1;
673 }
674
675 if (n > 0 && bp[0] == '.')
676 bp[0] = '\0';
677
1eb946b9
UD
678 if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
679 0))
8d8c6efa
UD
680 {
681 *errnop = errno;
682 *h_errnop = NO_RECOVERY;
5f0e6fc7
RM
683 return NSS_STATUS_UNAVAIL;
684 }
685 cp += n + QFIXEDSZ;
686
687 if (qtype == T_A || qtype == T_AAAA)
688 {
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).
692 */
693 n = strlen (bp) + 1; /* for the \0 */
76b87c03
UD
694 if (n >= MAXHOSTNAMELEN)
695 {
67479a70 696 *h_errnop = NO_RECOVERY;
a0bf6ac7 697 *errnop = ENOENT;
76b87c03
UD
698 return NSS_STATUS_TRYAGAIN;
699 }
5f0e6fc7
RM
700 result->h_name = bp;
701 bp += n;
702 linebuflen -= n;
560d3b76
UD
703 if (linebuflen < 0)
704 goto too_small;
5f0e6fc7
RM
705 /* The qname can be abbreviated, but h_name is now absolute. */
706 qname = result->h_name;
707 }
708
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;
717
718 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
719 {
720 int type, class;
721
8d8c6efa
UD
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)
725 {
b455972f 726 if (__builtin_expect (errno, 0) == EMSGSIZE)
0cc70fcf 727 goto too_small;
8d8c6efa
UD
728
729 n = -1;
730 }
731
a1ffb40e 732 if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
5f0e6fc7
RM
733 {
734 ++had_error;
735 continue;
736 }
737 cp += n; /* name */
b7da31a1 738
a1ffb40e 739 if (__glibc_unlikely (cp + 10 > end_of_message))
b7da31a1
UD
740 {
741 ++had_error;
742 continue;
743 }
744
cd5743fd 745 type = __ns_get16 (cp);
5f0e6fc7 746 cp += INT16SZ; /* type */
cd5743fd 747 class = __ns_get16 (cp);
d1fe1f22 748 cp += INT16SZ; /* class */
a7690819 749 int32_t ttl = __ns_get32 (cp);
d1fe1f22 750 cp += INT32SZ; /* TTL */
cd5743fd 751 n = __ns_get16 (cp);
5f0e6fc7 752 cp += INT16SZ; /* len */
a1ffb40e 753 if (__glibc_unlikely (class != C_IN))
5f0e6fc7
RM
754 {
755 /* XXX - debug? syslog? */
756 cp += n;
757 continue; /* XXX - had_error++ ? */
758 }
759
1eb946b9 760 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
5f0e6fc7 761 {
48c41d04
SP
762 /* A CNAME could also have a TTL entry. */
763 if (ttlp != NULL && ttl < *ttlp)
764 *ttlp = ttl;
765
5f0e6fc7
RM
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);
a1ffb40e 769 if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
5f0e6fc7
RM
770 {
771 ++had_error;
772 continue;
773 }
774 cp += n;
775 /* Store alias. */
776 *ap++ = bp;
777 n = strlen (bp) + 1; /* For the \0. */
b455972f 778 if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
76b87c03
UD
779 {
780 ++had_error;
781 continue;
782 }
5f0e6fc7
RM
783 bp += n;
784 linebuflen -= n;
785 /* Get canonical name. */
786 n = strlen (tbuf) + 1; /* For the \0. */
a1ffb40e 787 if (__glibc_unlikely (n > linebuflen))
0cc70fcf 788 goto too_small;
b455972f 789 if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
5f0e6fc7
RM
790 {
791 ++had_error;
792 continue;
793 }
8d8c6efa
UD
794 result->h_name = bp;
795 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
5f0e6fc7
RM
796 linebuflen -= n;
797 continue;
798 }
799
800 if (qtype == T_PTR && type == T_CNAME)
801 {
802 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
a1ffb40e 803 if (__glibc_unlikely (n < 0 || res_dnok (tbuf) == 0))
5f0e6fc7
RM
804 {
805 ++had_error;
806 continue;
807 }
808 cp += n;
da2d1bc5 809 /* Get canonical name. */
5f0e6fc7 810 n = strlen (tbuf) + 1; /* For the \0. */
a1ffb40e 811 if (__glibc_unlikely (n > linebuflen))
0cc70fcf 812 goto too_small;
b455972f 813 if (__builtin_expect (n, 0) >= MAXHOSTNAMELEN)
5f0e6fc7
RM
814 {
815 ++had_error;
816 continue;
817 }
8d8c6efa
UD
818 tname = bp;
819 bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
5f0e6fc7
RM
820 linebuflen -= n;
821 continue;
822 }
b455972f
UD
823
824 if (type == T_A && qtype == T_AAAA && map)
825 have_to_map = 1;
a1ffb40e 826 else if (__glibc_unlikely (type != qtype))
5f0e6fc7 827 {
3e3002ff
SP
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));
5f0e6fc7
RM
836 cp += n;
837 continue; /* XXX - had_error++ ? */
838 }
839
840 switch (type)
841 {
842 case T_PTR:
a1ffb40e 843 if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
5f0e6fc7
RM
844 {
845 syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
846 cp += n;
847 continue; /* XXX - had_error++ ? */
848 }
8d8c6efa
UD
849
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)
853 {
b455972f 854 if (__builtin_expect (errno, 0) == EMSGSIZE)
0cc70fcf 855 goto too_small;
8d8c6efa
UD
856
857 n = -1;
858 }
859
a1ffb40e 860 if (__glibc_unlikely (n < 0 || res_hnok (bp) == 0))
5f0e6fc7
RM
861 {
862 ++had_error;
863 break;
864 }
76985d3e
SP
865 /* bind would put multiple PTR records as aliases, but we don't do
866 that. */
5f0e6fc7 867 result->h_name = bp;
b455972f 868 if (have_to_map)
5f0e6fc7
RM
869 {
870 n = strlen (bp) + 1; /* for the \0 */
a1ffb40e 871 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
76b87c03
UD
872 {
873 ++had_error;
874 break;
875 }
5f0e6fc7
RM
876 bp += n;
877 linebuflen -= n;
51e4196f
AS
878 if (map_v4v6_hostent (result, &bp, &linebuflen))
879 goto too_small;
5f0e6fc7
RM
880 }
881 *h_errnop = NETDB_SUCCESS;
882 return NSS_STATUS_SUCCESS;
5f0e6fc7
RM
883 case T_A:
884 case T_AAAA:
b455972f 885 if (__builtin_expect (strcasecmp (result->h_name, bp), 0) != 0)
5f0e6fc7
RM
886 {
887 syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp);
888 cp += n;
889 continue; /* XXX - had_error++ ? */
890 }
1f64ac13 891 if (n != result->h_length)
5f0e6fc7 892 {
1f64ac13
UD
893 cp += n;
894 continue;
5f0e6fc7 895 }
1f64ac13 896 if (!haveanswer)
5f0e6fc7 897 {
2e09a79a 898 int nn;
5f0e6fc7 899
48c41d04
SP
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)
d1fe1f22
UD
904 *ttlp = ttl;
905 if (canonp != NULL)
906 *canonp = bp;
5f0e6fc7
RM
907 result->h_name = bp;
908 nn = strlen (bp) + 1; /* for the \0 */
909 bp += nn;
910 linebuflen -= nn;
911 }
912
560d3b76 913 linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
5f0e6fc7
RM
914 bp += sizeof (align) - ((u_long) bp % sizeof (align));
915
a1ffb40e 916 if (__glibc_unlikely (n > linebuflen))
0cc70fcf 917 goto too_small;
8d8c6efa 918 bp = __mempcpy (*hap++ = bp, cp, n);
5f0e6fc7
RM
919 cp += n;
920 linebuflen -= n;
921 break;
922 default:
923 abort ();
924 }
925 if (had_error == 0)
926 ++haveanswer;
927 }
928
929 if (haveanswer > 0)
930 {
931 *ap = NULL;
932 *hap = NULL;
da2d1bc5 933#if defined RESOLVSORT
5f0e6fc7
RM
934 /*
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
938 */
939 if (_res.nsort && haveanswer > 1 && qtype == T_A)
940 addrsort (host_data->h_addr_ptrs, haveanswer);
941#endif /*RESOLVSORT*/
942
943 if (result->h_name == NULL)
944 {
945 n = strlen (qname) + 1; /* For the \0. */
8d8c6efa 946 if (n > linebuflen)
0cc70fcf 947 goto too_small;
8d8c6efa 948 if (n >= MAXHOSTNAMELEN)
76b87c03 949 goto no_recovery;
8d8c6efa
UD
950 result->h_name = bp;
951 bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
5f0e6fc7
RM
952 linebuflen -= n;
953 }
954
b455972f 955 if (have_to_map)
51e4196f
AS
956 if (map_v4v6_hostent (result, &bp, &linebuflen))
957 goto too_small;
5f0e6fc7
RM
958 *h_errnop = NETDB_SUCCESS;
959 return NSS_STATUS_SUCCESS;
960 }
76b87c03
UD
961 no_recovery:
962 *h_errnop = NO_RECOVERY;
a0bf6ac7 963 *errnop = ENOENT;
2884dad4
UD
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);
5f0e6fc7 969}
1eb946b9
UD
970
971
972static enum nss_status
973gaih_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)
977{
978 char *buffer = *bufferp;
979 size_t buflen = *buflenp;
980
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;
a1ffb40e 987 if (__glibc_unlikely (qdcount != 1))
1eb946b9
UD
988 {
989 *h_errnop = NO_RECOVERY;
990 return NSS_STATUS_UNAVAIL;
991 }
992
b7da31a1 993 u_char packtmp[NS_MAXCDNAME];
1eb946b9
UD
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)
999 {
1000 if (__builtin_expect (errno, 0) == EMSGSIZE)
1001 {
1002 too_small:
1003 *errnop = ERANGE;
1004 *h_errnop = NETDB_INTERNAL;
1005 return NSS_STATUS_TRYAGAIN;
1006 }
1007
1008 n = -1;
1009 }
1010
1011 if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
1012 && (errno = EBADMSG)), 0))
1013 {
1014 *errnop = errno;
1015 *h_errnop = NO_RECOVERY;
1016 return NSS_STATUS_UNAVAIL;
1017 }
1018 cp += n + QFIXEDSZ;
1019
1020 int haveanswer = 0;
1021 int had_error = 0;
1022 char *canon = NULL;
1023 char *h_name = NULL;
1024 int h_namelen = 0;
1025
343996c4
UD
1026 if (ancount == 0)
1027 return NSS_STATUS_NOTFOUND;
1028
1eb946b9
UD
1029 while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1030 {
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)
1035 {
1036 if (__builtin_expect (errno, 0) == EMSGSIZE)
1037 goto too_small;
1038
1039 n = -1;
1040 }
a1ffb40e 1041 if (__glibc_unlikely (n < 0 || res_hnok (buffer) == 0))
1eb946b9
UD
1042 {
1043 ++had_error;
1044 continue;
1045 }
ea42a20c 1046 if (*firstp && canon == NULL)
1eb946b9
UD
1047 {
1048 h_name = buffer;
1049 buffer += h_namelen;
1050 buflen -= h_namelen;
1051 }
1052
1053 cp += n; /* name */
b7da31a1 1054
a1ffb40e 1055 if (__glibc_unlikely (cp + 10 > end_of_message))
b7da31a1
UD
1056 {
1057 ++had_error;
1058 continue;
1059 }
1060
cd5743fd 1061 int type = __ns_get16 (cp);
1eb946b9 1062 cp += INT16SZ; /* type */
cd5743fd 1063 int class = __ns_get16 (cp);
1eb946b9 1064 cp += INT16SZ; /* class */
cd5743fd 1065 int32_t ttl = __ns_get32 (cp);
1eb946b9 1066 cp += INT32SZ; /* TTL */
cd5743fd 1067 n = __ns_get16 (cp);
1eb946b9
UD
1068 cp += INT16SZ; /* len */
1069
1070 if (class != C_IN)
1071 {
1072 cp += n;
1073 continue;
1074 }
1075
1076 if (type == T_CNAME)
1077 {
1078 char tbuf[MAXDNAME];
48c41d04
SP
1079
1080 /* A CNAME could also have a TTL entry. */
1081 if (ttlp != NULL && ttl < *ttlp)
1082 *ttlp = ttl;
1083
1eb946b9 1084 n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
a1ffb40e 1085 if (__glibc_unlikely (n < 0 || res_hnok (tbuf) == 0))
1eb946b9
UD
1086 {
1087 ++had_error;
1088 continue;
1089 }
1090 cp += n;
1091
1092 if (*firstp)
1093 {
1094 /* Reclaim buffer space. */
1095 if (h_name + h_namelen == buffer)
1096 {
1097 buffer = h_name;
1098 buflen += h_namelen;
1099 }
1100
1101 n = strlen (tbuf) + 1;
a1ffb40e 1102 if (__glibc_unlikely (n > buflen))
1eb946b9 1103 goto too_small;
a1ffb40e 1104 if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1eb946b9
UD
1105 {
1106 ++had_error;
1107 continue;
1108 }
1109
1110 canon = buffer;
1111 buffer = __mempcpy (buffer, tbuf, n);
1112 buflen -= n;
1113 h_namelen = 0;
1114 }
1115 continue;
1116 }
9ba27474
UD
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.
a1ffb40e 1121 if (__glibc_unlikely (type != T_A && type != T_AAAA))
9ba27474 1122#else
1eb946b9
UD
1123 if (__builtin_expect (type == T_SIG, 0)
1124 || __builtin_expect (type == T_KEY, 0)
1125 || __builtin_expect (type == T_NXT, 0)
c1283552
UD
1126 || __builtin_expect (type == T_PTR, 0)
1127 || __builtin_expect (type == T_DNAME, 0))
9ba27474 1128#endif
1eb946b9
UD
1129 {
1130 /* We don't support DNSSEC yet. For now, ignore the record
1131 and send a low priority message to syslog.
1132
c1283552 1133 We also don't expect T_PTR or T_DNAME messages. */
1eb946b9
UD
1134 syslog (LOG_DEBUG | LOG_AUTH,
1135 "getaddrinfo*.gaih_getanswer: got type \"%s\"",
1136 p_type (type));
1137 cp += n;
1138 continue;
1139 }
1140 if (type != T_A && type != T_AAAA)
1141 abort ();
1142
1143 if (*pat == NULL)
1144 {
1145 uintptr_t pad = (-(uintptr_t) buffer
1146 % __alignof__ (struct gaih_addrtuple));
1147 buffer += pad;
1148 buflen = buflen > pad ? buflen - pad : 0;
1149
1150 if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
1151 0))
f854efd7 1152 goto too_small;
1eb946b9
UD
1153
1154 *pat = (struct gaih_addrtuple *) buffer;
1155 buffer += sizeof (struct gaih_addrtuple);
1156 buflen -= sizeof (struct gaih_addrtuple);
1157 }
1158
1159 (*pat)->name = NULL;
1160 (*pat)->next = NULL;
1161
1162 if (*firstp)
1163 {
48c41d04
SP
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)
1eb946b9
UD
1168 *ttlp = ttl;
1169
ea42a20c 1170 (*pat)->name = canon ?: h_name;
1eb946b9
UD
1171
1172 *firstp = 0;
1173 }
1174
1175 (*pat)->family = type == T_A ? AF_INET : AF_INET6;
b7da31a1
UD
1176 if (__builtin_expect ((type == T_A && n != INADDRSZ)
1177 || (type == T_AAAA && n != IN6ADDRSZ), 0))
1178 {
1179 ++had_error;
1180 continue;
1181 }
1eb946b9
UD
1182 memcpy ((*pat)->addr, cp, n);
1183 cp += n;
1184 (*pat)->scopeid = 0;
1185
1186 pat = &((*pat)->next);
1187
1188 haveanswer = 1;
1189 }
1190
1191 if (haveanswer)
1192 {
1193 *patp = pat;
1194 *bufferp = buffer;
1195 *buflenp = buflen;
1196
1197 *h_errnop = NETDB_SUCCESS;
1198 return NSS_STATUS_SUCCESS;
1199 }
1200
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;
1205}
1206
1207
1208static enum nss_status
1209gaih_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)
1213{
1214 int first = 1;
1215
343996c4
UD
1216 enum nss_status status = NSS_STATUS_NOTFOUND;
1217
1218 if (anslen1 > 0)
1219 status = gaih_getanswer_slice(answer1, anslen1, qname,
1220 &pat, &buffer, &buflen,
1221 errnop, h_errnop, ttlp,
1222 &first);
f854efd7 1223 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
b7da31a1 1224 || (status == NSS_STATUS_TRYAGAIN
86ae07a8
JL
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)))
343996c4 1232 && answer2 != NULL && anslen2 > 0)
f854efd7
UD
1233 {
1234 enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
1235 &pat, &buffer, &buflen,
1236 errnop, h_errnop, ttlp,
1237 &first);
b7da31a1 1238 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
f854efd7
UD
1239 status = status2;
1240 }
1eb946b9
UD
1241
1242 return status;
1243}