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