1/* Copyright (C) 1996-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18/* Parts of this file are plain copies of the file `gethtnamadr.c' from
19 the bind package and it has the following copyright. */
20
21/*
22 * ++Copyright++ 1985, 1988, 1993
23 * -
24 * Copyright (c) 1985, 1988, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 4. Neither the name of the University nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 * -
51 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
52 *
53 * Permission to use, copy, modify, and distribute this software for any
54 * purpose with or without fee is hereby granted, provided that the above
55 * copyright notice and this permission notice appear in all copies, and that
56 * the name of Digital Equipment Corporation not be used in advertising or
57 * publicity pertaining to distribution of the document or software without
58 * specific, written prior permission.
59 *
60 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
61 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
62 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
63 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
64 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
65 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
66 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
67 * SOFTWARE.
68 * -
69 * --Copyright--
70 */
71
72#include <alloc_buffer.h>
73#include <assert.h>
74#include <ctype.h>
75#include <errno.h>
76#include <netdb.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <stddef.h>
80#include <string.h>
81#include <libc-pointer-arith.h>
82
83#include "nsswitch.h"
84#include <arpa/nameser.h>
85#include <nss_dns.h>
86
87#include <resolv/resolv-internal.h>
88#include <resolv/resolv_context.h>
89
90#define RESOLVSORT
91
92#if PACKETSZ > 65536
93# define MAXPACKET PACKETSZ
94#else
95# define MAXPACKET 65536
96#endif
97/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
98#ifdef MAXHOSTNAMELEN
99# undef MAXHOSTNAMELEN
100#endif
101#define MAXHOSTNAMELEN 256
102
103/* For historic reasons, pointers to IP addresses are char *, so use a
104 single list type for addresses and host names. */
105#define DYNARRAY_STRUCT ptrlist
106#define DYNARRAY_ELEMENT char *
107#define DYNARRAY_PREFIX ptrlist_
108#include <malloc/dynarray-skeleton.c>
109
110static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen,
111 uint16_t qtype, struct alloc_buffer *abuf,
112 struct ptrlist *addresses,
113 struct ptrlist *aliases,
114 int *errnop, int *h_errnop, int32_t *ttlp);
115static void addrsort (struct resolv_context *ctx, char **ap, int num);
116static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
117 struct alloc_buffer *abuf,
118 char **hnamep, int *errnop,
119 int *h_errnop, int32_t *ttlp);
120
121static enum nss_status gaih_getanswer (unsigned char *packet1,
122 size_t packet1len,
123 unsigned char *packet2,
124 size_t packet2len,
125 struct alloc_buffer *abuf,
126 struct gaih_addrtuple **pat,
127 int *errnop, int *h_errnop,
128 int32_t *ttlp);
129static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
130 size_t packetlen,
131 struct alloc_buffer *abuf,
132 struct gaih_addrtuple **pat,
133 int *errnop, int *h_errnop,
134 int32_t *ttlp);
135
136
137static enum nss_status gethostbyname3_context (struct resolv_context *ctx,
138 const char *name, int af,
139 struct hostent *result,
140 char *buffer, size_t buflen,
141 int *errnop, int *h_errnop,
142 int32_t *ttlp,
143 char **canonp);
144
145/* Return the expected RDATA length for an address record type (A or
146 AAAA). */
147static int
148rrtype_to_rdata_length (int type)
149{
150 switch (type)
151 {
152 case T_A:
153 return INADDRSZ;
154 case T_AAAA:
155 return IN6ADDRSZ;
156 default:
157 return -1;
158 }
159}
160
161
162enum nss_status
163_nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
164 char *buffer, size_t buflen, int *errnop,
165 int *h_errnop, int32_t *ttlp, char **canonp)
166{
167 struct resolv_context *ctx = __resolv_context_get ();
168 if (ctx == NULL)
169 {
170 *errnop = errno;
171 *h_errnop = NETDB_INTERNAL;
172 return NSS_STATUS_UNAVAIL;
173 }
174 enum nss_status status = gethostbyname3_context
175 (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
176 __resolv_context_put (ctx);
177 return status;
178}
179libc_hidden_def (_nss_dns_gethostbyname3_r)
180
181static enum nss_status
182gethostbyname3_context (struct resolv_context *ctx,
183 const char *name, int af, struct hostent *result,
184 char *buffer, size_t buflen, int *errnop,
185 int *h_errnop, int32_t *ttlp, char **canonp)
186{
187 char tmp[NS_MAXDNAME];
188 int size, type, n;
189 const char *cp;
190 int olderr = errno;
191 enum nss_status status;
192
193 switch (af) {
194 case AF_INET:
195 size = INADDRSZ;
196 type = T_A;
197 break;
198 case AF_INET6:
199 size = IN6ADDRSZ;
200 type = T_AAAA;
201 break;
202 default:
203 *h_errnop = NO_DATA;
204 *errnop = EAFNOSUPPORT;
205 return NSS_STATUS_UNAVAIL;
206 }
207
208 result->h_addrtype = af;
209 result->h_length = size;
210
211 /*
212 * if there aren't any dots, it could be a user-level alias.
213 * this is also done in res_query() since we are not the only
214 * function that looks up host names.
215 */
216 if (strchr (name, '.') == NULL
217 && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
218 name = cp;
219
220 unsigned char dns_packet_buffer[1024];
221 unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
222
223 n = __res_context_search (ctx, name, C_IN, type,
224 dns_packet_buffer, sizeof (dns_packet_buffer),
225 &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
226 if (n < 0)
227 {
228 switch (errno)
229 {
230 case ESRCH:
231 status = NSS_STATUS_TRYAGAIN;
232 h_errno = TRY_AGAIN;
233 break;
234 /* System has run out of file descriptors. */
235 case EMFILE:
236 case ENFILE:
237 h_errno = NETDB_INTERNAL;
238 /* Fall through. */
239 case ECONNREFUSED:
240 case ETIMEDOUT:
241 status = NSS_STATUS_UNAVAIL;
242 break;
243 default:
244 status = NSS_STATUS_NOTFOUND;
245 break;
246 }
247 *h_errnop = h_errno;
248 if (h_errno == TRY_AGAIN)
249 *errnop = EAGAIN;
250 else
251 __set_errno (olderr);
252 }
253 else
254 {
255 struct alloc_buffer abuf = alloc_buffer_create (start: buffer, size: buflen);
256
257 struct ptrlist addresses;
258 ptrlist_init (list: &addresses);
259 struct ptrlist aliases;
260 ptrlist_init (list: &aliases);
261
262 status = getanswer_r (packet: alt_dns_packet_buffer, packetlen: n, qtype: type,
263 abuf: &abuf, addresses: &addresses, aliases: &aliases,
264 errnop, h_errnop, ttlp);
265 if (status == NSS_STATUS_SUCCESS)
266 {
267 if (ptrlist_has_failed (list: &addresses)
268 || ptrlist_has_failed (list: &aliases))
269 {
270 /* malloc failure. Do not retry using the ERANGE protocol. */
271 *errnop = ENOMEM;
272 *h_errnop = NETDB_INTERNAL;
273 status = NSS_STATUS_UNAVAIL;
274 }
275
276 /* Reserve the address and alias arrays in the result
277 buffer. Both are NULL-terminated, but the first element
278 of the alias array is stored in h_name, so no extra space
279 for the NULL terminator is needed there. */
280 result->h_addr_list
281 = alloc_buffer_alloc_array (&abuf, char *,
282 ptrlist_size (&addresses) + 1);
283 result->h_aliases
284 = alloc_buffer_alloc_array (&abuf, char *,
285 ptrlist_size (&aliases));
286 if (alloc_buffer_has_failed (buf: &abuf))
287 {
288 /* Retry using the ERANGE protocol. */
289 *errnop = ERANGE;
290 *h_errnop = NETDB_INTERNAL;
291 status = NSS_STATUS_TRYAGAIN;
292 }
293 else
294 {
295 /* Copy the address list and NULL-terminate it. */
296 memcpy (result->h_addr_list, ptrlist_begin (list: &addresses),
297 ptrlist_size (list: &addresses) * sizeof (char *));
298 result->h_addr_list[ptrlist_size (list: &addresses)] = NULL;
299
300 /* Sort the address list if requested. */
301 if (type == T_A && __resolv_context_sort_count (ctx) > 0)
302 addrsort (ctx, ap: result->h_addr_list, num: ptrlist_size (list: &addresses));
303
304 /* Copy the aliases, excluding the last one. */
305 memcpy (result->h_aliases, ptrlist_begin (list: &aliases),
306 (ptrlist_size (list: &aliases) - 1) * sizeof (char *));
307 result->h_aliases[ptrlist_size (list: &aliases) - 1] = NULL;
308
309 /* The last alias goes into h_name. */
310 assert (ptrlist_size (&aliases) >= 1);
311 result->h_name = ptrlist_end (list: &aliases)[-1];
312
313 /* This is also the canonical name. */
314 if (canonp != NULL)
315 *canonp = result->h_name;
316 }
317 }
318
319 ptrlist_free (list: &aliases);
320 ptrlist_free (list: &addresses);
321 }
322
323 if (alt_dns_packet_buffer != dns_packet_buffer)
324 free (ptr: alt_dns_packet_buffer);
325 return status;
326}
327
328/* Verify that the name looks like a host name. There is no point in
329 sending a query which will not produce a usable name in the
330 response. */
331static enum nss_status
332check_name (const char *name, int *h_errnop)
333{
334 if (__libc_res_hnok (name))
335 return NSS_STATUS_SUCCESS;
336 *h_errnop = HOST_NOT_FOUND;
337 return NSS_STATUS_NOTFOUND;
338}
339
340enum nss_status
341_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
342 char *buffer, size_t buflen, int *errnop,
343 int *h_errnop)
344{
345 enum nss_status status = check_name (name, h_errnop);
346 if (status != NSS_STATUS_SUCCESS)
347 return status;
348 return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
349 h_errnop, NULL, NULL);
350}
351libc_hidden_def (_nss_dns_gethostbyname2_r)
352
353enum nss_status
354_nss_dns_gethostbyname_r (const char *name, struct hostent *result,
355 char *buffer, size_t buflen, int *errnop,
356 int *h_errnop)
357{
358 enum nss_status status = check_name (name, h_errnop);
359 if (status != NSS_STATUS_SUCCESS)
360 return status;
361 struct resolv_context *ctx = __resolv_context_get ();
362 if (ctx == NULL)
363 {
364 *errnop = errno;
365 *h_errnop = NETDB_INTERNAL;
366 return NSS_STATUS_UNAVAIL;
367 }
368 status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
369 buflen, errnop, h_errnop, NULL, NULL);
370 __resolv_context_put (ctx);
371 return status;
372}
373libc_hidden_def (_nss_dns_gethostbyname_r)
374
375enum nss_status
376_nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
377 char *buffer, size_t buflen, int *errnop,
378 int *herrnop, int32_t *ttlp)
379{
380 enum nss_status status = check_name (name, h_errnop: herrnop);
381 char tmp[NS_MAXDNAME];
382 if (status != NSS_STATUS_SUCCESS)
383 return status;
384 struct resolv_context *ctx = __resolv_context_get ();
385 if (ctx == NULL)
386 {
387 *errnop = errno;
388 *herrnop = NETDB_INTERNAL;
389 return NSS_STATUS_UNAVAIL;
390 }
391
392 /*
393 * if there aren't any dots, it could be a user-level alias.
394 * this is also done in res_query() since we are not the only
395 * function that looks up host names.
396 */
397 if (strchr (name, '.') == NULL)
398 {
399 const char *cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp));
400 if (cp != NULL)
401 name = cp;
402 }
403
404 unsigned char dns_packet_buffer[2048];
405 unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
406 u_char *ans2p = NULL;
407 int nans2p = 0;
408 int resplen2 = 0;
409 int ans2p_malloced = 0;
410 struct alloc_buffer abuf = alloc_buffer_create (start: buffer, size: buflen);
411
412
413 int olderr = errno;
414 int n;
415
416 if ((ctx->resp->options & RES_NOAAAA) == 0)
417 {
418 n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
419 dns_packet_buffer, sizeof (dns_packet_buffer),
420 &alt_dns_packet_buffer, &ans2p, &nans2p,
421 &resplen2, &ans2p_malloced);
422 if (n >= 0)
423 status = gaih_getanswer (packet1: alt_dns_packet_buffer, packet1len: n, packet2: ans2p, packet2len: resplen2,
424 abuf: &abuf, pat, errnop, h_errnop: herrnop, ttlp);
425 }
426 else
427 {
428 n = __res_context_search (ctx, name, C_IN, T_A,
429 dns_packet_buffer, sizeof (dns_packet_buffer),
430 &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
431 if (n >= 0)
432 status = gaih_getanswer_noaaaa (packet: alt_dns_packet_buffer, packetlen: n,
433 abuf: &abuf, pat, errnop, h_errnop: herrnop, ttlp);
434 }
435 if (n < 0)
436 {
437 switch (errno)
438 {
439 case ESRCH:
440 status = NSS_STATUS_TRYAGAIN;
441 h_errno = TRY_AGAIN;
442 break;
443 /* System has run out of file descriptors. */
444 case EMFILE:
445 case ENFILE:
446 h_errno = NETDB_INTERNAL;
447 /* Fall through. */
448 case ECONNREFUSED:
449 case ETIMEDOUT:
450 status = NSS_STATUS_UNAVAIL;
451 break;
452 default:
453 status = NSS_STATUS_NOTFOUND;
454 break;
455 }
456
457 *herrnop = h_errno;
458 if (h_errno == TRY_AGAIN)
459 *errnop = EAGAIN;
460 else
461 __set_errno (olderr);
462 }
463
464 /* Implement the buffer resizing protocol. */
465 if (alloc_buffer_has_failed (buf: &abuf))
466 {
467 *errnop = ERANGE;
468 *herrnop = NETDB_INTERNAL;
469 status = NSS_STATUS_TRYAGAIN;
470 }
471
472 /* Check whether ans2p was separately allocated. */
473 if (ans2p_malloced)
474 free (ptr: ans2p);
475
476 if (alt_dns_packet_buffer != dns_packet_buffer)
477 free (ptr: alt_dns_packet_buffer);
478
479 __resolv_context_put (ctx);
480 return status;
481}
482libc_hidden_def (_nss_dns_gethostbyname4_r)
483
484enum nss_status
485_nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
486 struct hostent *result, char *buffer, size_t buflen,
487 int *errnop, int *h_errnop, int32_t *ttlp)
488{
489 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
490 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
491 static const u_char v6local[] = { 0,0, 0,1 };
492 const u_char *uaddr = (const u_char *)addr;
493 char qbuf[MAXDNAME+1], *qp = NULL;
494 size_t size;
495 int n, status;
496 int olderr = errno;
497
498 /* Prepare the allocation buffer. Store the pointer array first, to
499 benefit from buffer alignment. */
500 struct alloc_buffer abuf = alloc_buffer_create (start: buffer, size: buflen);
501 char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2);
502 if (address_array == NULL)
503 {
504 *errnop = ERANGE;
505 *h_errnop = NETDB_INTERNAL;
506 return NSS_STATUS_TRYAGAIN;
507 }
508
509 struct resolv_context *ctx = __resolv_context_get ();
510 if (ctx == NULL)
511 {
512 *errnop = errno;
513 *h_errnop = NETDB_INTERNAL;
514 return NSS_STATUS_UNAVAIL;
515 }
516
517 if (af == AF_INET6 && len == IN6ADDRSZ
518 && (memcmp (uaddr, mapped, sizeof mapped) == 0
519 || (memcmp (uaddr, tunnelled, sizeof tunnelled) == 0
520 && memcmp (&uaddr[sizeof tunnelled], v6local, sizeof v6local))))
521 {
522 /* Unmap. */
523 addr += sizeof mapped;
524 uaddr += sizeof mapped;
525 af = AF_INET;
526 len = INADDRSZ;
527 }
528
529 switch (af)
530 {
531 case AF_INET:
532 size = INADDRSZ;
533 break;
534 case AF_INET6:
535 size = IN6ADDRSZ;
536 break;
537 default:
538 *errnop = EAFNOSUPPORT;
539 *h_errnop = NETDB_INTERNAL;
540 __resolv_context_put (ctx);
541 return NSS_STATUS_UNAVAIL;
542 }
543 if (size > len)
544 {
545 *errnop = EAFNOSUPPORT;
546 *h_errnop = NETDB_INTERNAL;
547 __resolv_context_put (ctx);
548 return NSS_STATUS_UNAVAIL;
549 }
550
551 switch (af)
552 {
553 case AF_INET:
554 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
555 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
556 break;
557 case AF_INET6:
558 qp = qbuf;
559 for (n = IN6ADDRSZ - 1; n >= 0; n--)
560 {
561 static const char nibblechar[16] = "0123456789abcdef";
562 *qp++ = nibblechar[uaddr[n] & 0xf];
563 *qp++ = '.';
564 *qp++ = nibblechar[(uaddr[n] >> 4) & 0xf];
565 *qp++ = '.';
566 }
567 strcpy(qp, "ip6.arpa");
568 break;
569 default:
570 /* Cannot happen. */
571 break;
572 }
573
574 unsigned char dns_packet_buffer[1024];
575 unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
576 n = __res_context_query (ctx, qbuf, C_IN, T_PTR,
577 dns_packet_buffer, sizeof (dns_packet_buffer),
578 &alt_dns_packet_buffer,
579 NULL, NULL, NULL, NULL);
580 if (n < 0)
581 {
582 *h_errnop = h_errno;
583 __set_errno (olderr);
584 if (alt_dns_packet_buffer != dns_packet_buffer)
585 free (ptr: alt_dns_packet_buffer);
586 __resolv_context_put (ctx);
587 return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
588 }
589
590 status = getanswer_ptr (packet: alt_dns_packet_buffer, packetlen: n,
591 abuf: &abuf, hnamep: &result->h_name, errnop, h_errnop, ttlp);
592
593 if (alt_dns_packet_buffer != dns_packet_buffer)
594 free (ptr: alt_dns_packet_buffer);
595 __resolv_context_put (ctx);
596
597 if (status != NSS_STATUS_SUCCESS)
598 return status;
599
600 /* result->h_name has already been set by getanswer_ptr. */
601 result->h_addrtype = af;
602 result->h_length = len;
603 /* Increase the alignment to 4, in case there are applications out
604 there that expect at least this level of address alignment. */
605 address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t);
606 alloc_buffer_copy_bytes (buf: &abuf, src: uaddr, size: len);
607 address_array[1] = NULL;
608
609 /* This check also covers allocation failure in getanswer_ptr. */
610 if (alloc_buffer_has_failed (buf: &abuf))
611 {
612 *errnop = ERANGE;
613 *h_errnop = NETDB_INTERNAL;
614 return NSS_STATUS_TRYAGAIN;
615 }
616 result->h_addr_list = address_array;
617 result->h_aliases = &address_array[1]; /* Points to NULL. */
618
619 *h_errnop = NETDB_SUCCESS;
620 return NSS_STATUS_SUCCESS;
621}
622libc_hidden_def (_nss_dns_gethostbyaddr2_r)
623
624
625enum nss_status
626_nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
627 struct hostent *result, char *buffer, size_t buflen,
628 int *errnop, int *h_errnop)
629{
630 return _nss_dns_gethostbyaddr2_r (addr, len, af, result, buffer, buflen,
631 errnop, h_errnop, NULL);
632}
633libc_hidden_def (_nss_dns_gethostbyaddr_r)
634
635static void
636addrsort (struct resolv_context *ctx, char **ap, int num)
637{
638 int i, j;
639 char **p;
640 short aval[MAX_NR_ADDRS];
641 int needsort = 0;
642 size_t nsort = __resolv_context_sort_count (ctx);
643
644 p = ap;
645 if (num > MAX_NR_ADDRS)
646 num = MAX_NR_ADDRS;
647 for (i = 0; i < num; i++, p++)
648 {
649 for (j = 0 ; (unsigned)j < nsort; j++)
650 {
651 struct resolv_sortlist_entry e
652 = __resolv_context_sort_entry (ctx, index: j);
653 if (e.addr.s_addr == (((struct in_addr *)(*p))->s_addr & e.mask))
654 break;
655 }
656 aval[i] = j;
657 if (needsort == 0 && i > 0 && j < aval[i-1])
658 needsort = i;
659 }
660 if (!needsort)
661 return;
662
663 while (needsort++ < num)
664 for (j = needsort - 2; j >= 0; j--)
665 if (aval[j] > aval[j+1])
666 {
667 char *hp;
668
669 i = aval[j];
670 aval[j] = aval[j+1];
671 aval[j+1] = i;
672
673 hp = ap[j];
674 ap[j] = ap[j+1];
675 ap[j+1] = hp;
676 }
677 else
678 break;
679}
680
681/* Convert the uncompressed, binary domain name CDNAME into its
682 textual representation and add it to the end of ALIASES, allocating
683 space for a copy of the name from ABUF. Skip adding the name if it
684 is not a valid host name, and return false in that case, otherwise
685 true. */
686static bool
687getanswer_r_store_alias (const unsigned char *cdname,
688 struct alloc_buffer *abuf,
689 struct ptrlist *aliases)
690{
691 /* Filter out domain names that are not host names. */
692 if (!__res_binary_hnok (dn: cdname))
693 return false;
694
695 /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks
696 for length. */
697 char dname[MAXHOSTNAMELEN + 1];
698 if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0)
699 return false;
700 /* Do not report an error on allocation failure, instead store NULL
701 or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS
702 and detect the memory allocation failure or buffer space
703 exhaustion, and report it accordingly. */
704 ptrlist_add (list: aliases, item: alloc_buffer_copy_string (buf: abuf, src: dname));
705 return true;
706}
707
708static enum nss_status __attribute__ ((noinline))
709getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype,
710 struct alloc_buffer *abuf,
711 struct ptrlist *addresses, struct ptrlist *aliases,
712 int *errnop, int *h_errnop, int32_t *ttlp)
713{
714 struct ns_rr_cursor c;
715 if (!__ns_rr_cursor_init (c: &c, buf: packet, len: packetlen))
716 {
717 /* This should not happen because __res_context_query already
718 performs response validation. */
719 *h_errnop = NO_RECOVERY;
720 return NSS_STATUS_UNAVAIL;
721 }
722
723 /* Treat the QNAME just like an alias. Error out if it is not a
724 valid host name. */
725 if (ns_rr_cursor_rcode (c: &c) == NXDOMAIN
726 || !getanswer_r_store_alias (cdname: ns_rr_cursor_qname (c: &c), abuf, aliases))
727 {
728 if (ttlp != NULL)
729 /* No negative caching. */
730 *ttlp = 0;
731 *h_errnop = HOST_NOT_FOUND;
732 *errnop = ENOENT;
733 return NSS_STATUS_NOTFOUND;
734 }
735
736 int ancount = ns_rr_cursor_ancount (c: &c);
737 const unsigned char *expected_name = ns_rr_cursor_qname (c: &c);
738 /* expected_name may be updated to point into this buffer. */
739 unsigned char name_buffer[NS_MAXCDNAME];
740
741 for (; ancount > 0; --ancount)
742 {
743 struct ns_rr_wire rr;
744 if (!__ns_rr_cursor_next (c: &c, rr: &rr))
745 {
746 *h_errnop = NO_RECOVERY;
747 return NSS_STATUS_UNAVAIL;
748 }
749
750 /* Skip over records with the wrong class. */
751 if (rr.rclass != C_IN)
752 continue;
753
754 /* Update TTL for recognized record types. */
755 if ((rr.rtype == T_CNAME || rr.rtype == qtype)
756 && ttlp != NULL && *ttlp > rr.ttl)
757 *ttlp = rr.ttl;
758
759 if (rr.rtype == T_CNAME)
760 {
761 /* NB: No check for owner name match, based on historic
762 precedent. Record the CNAME target as the new expected
763 name. */
764 int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
765 name_buffer, sizeof (name_buffer));
766 if (n < 0)
767 {
768 *h_errnop = NO_RECOVERY;
769 return NSS_STATUS_UNAVAIL;
770 }
771 /* And store the new name as an alias. */
772 getanswer_r_store_alias (cdname: name_buffer, abuf, aliases);
773 expected_name = name_buffer;
774 }
775 else if (rr.rtype == qtype
776 && __ns_samebinaryname (rr.rname, expected_name)
777 && rr.rdlength == rrtype_to_rdata_length (type: qtype))
778 {
779 /* Make a copy of the address and store it. Increase the
780 alignment to 4, in case there are applications out there
781 that expect at least this level of address alignment. */
782 ptrlist_add (list: addresses, item: (char *) alloc_buffer_next (abuf, uint32_t));
783 alloc_buffer_copy_bytes (buf: abuf, src: rr.rdata, size: rr.rdlength);
784 }
785 }
786
787 if (ptrlist_size (list: addresses) == 0)
788 {
789 /* No address record found. */
790 if (ttlp != NULL)
791 /* No caching of negative responses. */
792 *ttlp = 0;
793
794 *h_errnop = NO_RECOVERY;
795 *errnop = ENOENT;
796 return NSS_STATUS_TRYAGAIN;
797 }
798 else
799 {
800 *h_errnop = NETDB_SUCCESS;
801 return NSS_STATUS_SUCCESS;
802 }
803}
804
805static enum nss_status
806getanswer_ptr (unsigned char *packet, size_t packetlen,
807 struct alloc_buffer *abuf, char **hnamep,
808 int *errnop, int *h_errnop, int32_t *ttlp)
809{
810 struct ns_rr_cursor c;
811 if (!__ns_rr_cursor_init (c: &c, buf: packet, len: packetlen))
812 {
813 /* This should not happen because __res_context_query already
814 performs response validation. */
815 *h_errnop = NO_RECOVERY;
816 return NSS_STATUS_UNAVAIL;
817 }
818 int ancount = ns_rr_cursor_ancount (c: &c);
819 const unsigned char *expected_name = ns_rr_cursor_qname (c: &c);
820 /* expected_name may be updated to point into this buffer. */
821 unsigned char name_buffer[NS_MAXCDNAME];
822
823 while (ancount > 0)
824 {
825 struct ns_rr_wire rr;
826 if (!__ns_rr_cursor_next (c: &c, rr: &rr))
827 {
828 *h_errnop = NO_RECOVERY;
829 return NSS_STATUS_UNAVAIL;
830 }
831
832 /* Skip over records with the wrong class. */
833 if (rr.rclass != C_IN)
834 continue;
835
836 /* Update TTL for known record types. */
837 if ((rr.rtype == T_CNAME || rr.rtype == T_PTR)
838 && ttlp != NULL && *ttlp > rr.ttl)
839 *ttlp = rr.ttl;
840
841 if (rr.rtype == T_CNAME)
842 {
843 /* NB: No check for owner name match, based on historic
844 precedent. Record the CNAME target as the new expected
845 name. */
846 int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
847 name_buffer, sizeof (name_buffer));
848 if (n < 0)
849 {
850 *h_errnop = NO_RECOVERY;
851 return NSS_STATUS_UNAVAIL;
852 }
853 expected_name = name_buffer;
854 }
855 else if (rr.rtype == T_PTR
856 && __ns_samebinaryname (rr.rname, expected_name))
857 {
858 /* Decompress the target of the PTR record. This is the
859 host name we are looking for. We can only use it if it
860 is syntactically valid. Historically, only one host name
861 is returned here. If the recursive resolver performs DNS
862 record rotation, the returned host name is essentially
863 random, which is why multiple PTR records are rarely
864 used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for
865 additional length checking. */
866 char hname[MAXHOSTNAMELEN + 1];
867 if (__ns_name_unpack (c.begin, c.end, rr.rdata,
868 name_buffer, sizeof (name_buffer)) < 0
869 || !__res_binary_hnok (dn: expected_name)
870 || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
871 {
872 *h_errnop = NO_RECOVERY;
873 return NSS_STATUS_UNAVAIL;
874 }
875 /* Successful allocation is checked by the caller. */
876 *hnamep = alloc_buffer_copy_string (buf: abuf, src: hname);
877 return NSS_STATUS_SUCCESS;
878 }
879 }
880
881 /* No PTR record found. */
882 if (ttlp != NULL)
883 /* No caching of negative responses. */
884 *ttlp = 0;
885
886 *h_errnop = NO_RECOVERY;
887 *errnop = ENOENT;
888 return NSS_STATUS_TRYAGAIN;
889}
890
891/* Parses DNS data found in PACKETLEN bytes at PACKET in struct
892 gaih_addrtuple address tuples. The new address tuples are linked
893 from **TAILP, with backing store allocated from ABUF, and *TAILP is
894 updated to point where the next tuple pointer should be stored. If
895 TTLP is not null, *TTLP is updated to reflect the minimum TTL. If
896 STORE_CANON is true, the canonical name is stored as part of the
897 first address tuple being written. */
898static enum nss_status
899gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
900 struct alloc_buffer *abuf,
901 struct gaih_addrtuple ***tailp,
902 int *errnop, int *h_errnop, int32_t *ttlp,
903 bool store_canon)
904{
905 struct ns_rr_cursor c;
906 if (!__ns_rr_cursor_init (c: &c, buf: packet, len: packetlen))
907 {
908 /* This should not happen because __res_context_query already
909 performs response validation. */
910 *h_errnop = NO_RECOVERY;
911 return NSS_STATUS_UNAVAIL;
912 }
913 bool haveanswer = false; /* Set to true if at least one address. */
914 uint16_t qtype = ns_rr_cursor_qtype (c: &c);
915 int ancount = ns_rr_cursor_ancount (c: &c);
916 const unsigned char *expected_name = ns_rr_cursor_qname (c: &c);
917 /* expected_name may be updated to point into this buffer. */
918 unsigned char name_buffer[NS_MAXCDNAME];
919
920 /* This is a pointer to a possibly-compressed name in the packet.
921 Eventually it is equivalent to the canonical name. If needed, it
922 is uncompressed and translated to text form when the first
923 address tuple is encountered. */
924 const unsigned char *compressed_alias_name = expected_name;
925
926 if (ancount == 0 || !__res_binary_hnok (dn: compressed_alias_name))
927 {
928 *h_errnop = HOST_NOT_FOUND;
929 return NSS_STATUS_NOTFOUND;
930 }
931
932 for (; ancount > -0; --ancount)
933 {
934 struct ns_rr_wire rr;
935 if (!__ns_rr_cursor_next (c: &c, rr: &rr))
936 {
937 *h_errnop = NO_RECOVERY;
938 return NSS_STATUS_UNAVAIL;
939 }
940
941 /* Update TTL for known record types. */
942 if ((rr.rtype == T_CNAME || rr.rtype == qtype)
943 && ttlp != NULL && *ttlp > rr.ttl)
944 *ttlp = rr.ttl;
945
946 if (rr.rtype == T_CNAME)
947 {
948 /* NB: No check for owner name match, based on historic
949 precedent. Record the CNAME target as the new expected
950 name. */
951 int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
952 name_buffer, sizeof (name_buffer));
953 if (n < 0)
954 {
955 *h_errnop = NO_RECOVERY;
956 return NSS_STATUS_UNAVAIL;
957 }
958 expected_name = name_buffer;
959 if (store_canon && __res_binary_hnok (dn: name_buffer))
960 /* This name can be used as a canonical name. Do not
961 translate to text form here to conserve buffer space.
962 Point to the compressed name because name_buffer can be
963 overwritten with an unusable name later. */
964 compressed_alias_name = rr.rdata;
965 }
966 else if (rr.rtype == qtype
967 && __ns_samebinaryname (rr.rname, expected_name)
968 && rr.rdlength == rrtype_to_rdata_length (type: qtype))
969 {
970 struct gaih_addrtuple *ntup
971 = alloc_buffer_alloc (abuf, struct gaih_addrtuple);
972 /* Delay error reporting to the callers (they implement the
973 ERANGE buffer resizing handshake). */
974 if (ntup != NULL)
975 {
976 ntup->next = NULL;
977 if (store_canon && compressed_alias_name != NULL)
978 {
979 /* This assumes that all the CNAME records come
980 first. Use MAXHOSTNAMELEN instead of
981 NS_MAXCDNAME for additional length checking.
982 However, these checks are not expected to fail
983 because all size NS_MAXCDNAME names should into
984 the hname buffer because no escaping is
985 needed. */
986 char unsigned nbuf[NS_MAXCDNAME];
987 char hname[MAXHOSTNAMELEN + 1];
988 if (__ns_name_unpack (c.begin, c.end,
989 compressed_alias_name,
990 nbuf, sizeof (nbuf)) >= 0
991 && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0)
992 /* Space checking is performed by the callers. */
993 ntup->name = alloc_buffer_copy_string (buf: abuf, src: hname);
994 store_canon = false;
995 }
996 else
997 ntup->name = NULL;
998 if (rr.rdlength == 4)
999 ntup->family = AF_INET;
1000 else
1001 ntup->family = AF_INET6;
1002 memcpy (ntup->addr, rr.rdata, rr.rdlength);
1003 ntup->scopeid = 0;
1004
1005 /* Link in the new tuple, and update the tail pointer to
1006 point to its next field. */
1007 **tailp = ntup;
1008 *tailp = &ntup->next;
1009
1010 haveanswer = true;
1011 }
1012 }
1013 }
1014
1015 if (haveanswer)
1016 {
1017 *h_errnop = NETDB_SUCCESS;
1018 return NSS_STATUS_SUCCESS;
1019 }
1020 else
1021 {
1022 /* Special case here: if the resolver sent a result but it only
1023 contains a CNAME while we are looking for a T_A or T_AAAA
1024 record, we fail with NOTFOUND. */
1025 *h_errnop = HOST_NOT_FOUND;
1026 return NSS_STATUS_NOTFOUND;
1027 }
1028}
1029
1030
1031static enum nss_status
1032gaih_getanswer (unsigned char *packet1, size_t packet1len,
1033 unsigned char *packet2, size_t packet2len,
1034 struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
1035 int *errnop, int *h_errnop, int32_t *ttlp)
1036{
1037 enum nss_status status = NSS_STATUS_NOTFOUND;
1038
1039 /* Combining the NSS status of two distinct queries requires some
1040 compromise and attention to symmetry (A or AAAA queries can be
1041 returned in any order). What follows is a breakdown of how this
1042 code is expected to work and why. We discuss only SUCCESS,
1043 TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
1044 that apply (though RETURN and MERGE exist). We make a distinction
1045 between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
1046 A recoverable TRYAGAIN is almost always due to buffer size issues
1047 and returns ERANGE in errno and the caller is expected to retry
1048 with a larger buffer. (The caller, _nss_dns_gethostbyname4_r,
1049 ignores the return status if it detects that the result buffer
1050 has been exhausted and generates a TRYAGAIN failure with an
1051 ERANGE code.)
1052
1053 Lastly, you may be tempted to make significant changes to the
1054 conditions in this code to bring about symmetry between responses.
1055 Please don't change anything without due consideration for
1056 expected application behaviour. Some of the synthesized responses
1057 aren't very well thought out and sometimes appear to imply that
1058 IPv4 responses are always answer 1, and IPv6 responses are always
1059 answer 2, but that's not true (see the implementation of send_dg
1060 and send_vc to see response can arrive in any order, particularly
1061 for UDP). However, we expect it holds roughly enough of the time
1062 that this code works, but certainly needs to be fixed to make this
1063 a more robust implementation.
1064
1065 ----------------------------------------------
1066 | Answer 1 Status / | Synthesized | Reason |
1067 | Answer 2 Status | Status | |
1068 |--------------------------------------------|
1069 | SUCCESS/SUCCESS | SUCCESS | [1] |
1070 | SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
1071 | SUCCESS/TRYAGAIN' | SUCCESS | [1] |
1072 | SUCCESS/NOTFOUND | SUCCESS | [1] |
1073 | SUCCESS/UNAVAIL | SUCCESS | [1] |
1074 | TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
1075 | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
1076 | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
1077 | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
1078 | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
1079 | TRYAGAIN'/SUCCESS | SUCCESS | [3] |
1080 | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
1081 | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
1082 | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
1083 | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
1084 | NOTFOUND/SUCCESS | SUCCESS | [3] |
1085 | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
1086 | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
1087 | NOTFOUND/NOTFOUND | NOTFOUND | [3] |
1088 | NOTFOUND/UNAVAIL | UNAVAIL | [3] |
1089 | UNAVAIL/SUCCESS | UNAVAIL | [4] |
1090 | UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
1091 | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
1092 | UNAVAIL/NOTFOUND | UNAVAIL | [4] |
1093 | UNAVAIL/UNAVAIL | UNAVAIL | [4] |
1094 ----------------------------------------------
1095
1096 [1] If the first response is a success we return success.
1097 This ignores the state of the second answer and in fact
1098 incorrectly sets errno and h_errno to that of the second
1099 answer. However because the response is a success we ignore
1100 *errnop and *h_errnop (though that means you touched errno on
1101 success). We are being conservative here and returning the
1102 likely IPv4 response in the first answer as a success.
1103
1104 [2] If the first response is a recoverable TRYAGAIN we return
1105 that instead of looking at the second response. The
1106 expectation here is that we have failed to get an IPv4 response
1107 and should retry both queries.
1108
1109 [3] If the first response was not a SUCCESS and the second
1110 response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
1111 or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
1112 result from the second response, otherwise the first responses
1113 status is used. Again we have some odd side-effects when the
1114 second response is NOTFOUND because we overwrite *errnop and
1115 *h_errnop that means that a first answer of NOTFOUND might see
1116 its *errnop and *h_errnop values altered. Whether it matters
1117 in practice that a first response NOTFOUND has the wrong
1118 *errnop and *h_errnop is undecided.
1119
1120 [4] If the first response is UNAVAIL we return that instead of
1121 looking at the second response. The expectation here is that
1122 it will have failed similarly e.g. configuration failure.
1123
1124 [5] Testing this code is complicated by the fact that truncated
1125 second response buffers might be returned as SUCCESS if the
1126 first answer is a SUCCESS. To fix this we add symmetry to
1127 TRYAGAIN with the second response. If the second response
1128 is a recoverable error we now return TRYAGIN even if the first
1129 response was SUCCESS. */
1130
1131 if (packet1len > 0)
1132 {
1133 status = gaih_getanswer_slice (packet: packet1, packetlen: packet1len,
1134 abuf, tailp: &pat, errnop, h_errnop, ttlp, true);
1135 if (alloc_buffer_has_failed (buf: abuf))
1136 /* Do not try parsing the second packet if a larger result
1137 buffer is needed. The caller implements the resizing
1138 protocol because *abuf has been exhausted. */
1139 return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */
1140 }
1141
1142 if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
1143 && packet2 != NULL && packet2len > 0)
1144 {
1145 enum nss_status status2
1146 = gaih_getanswer_slice (packet: packet2, packetlen: packet2len,
1147 abuf, tailp: &pat, errnop, h_errnop, ttlp,
1148 /* Success means that data with a
1149 canonical name has already been
1150 stored. Do not store the name again. */
1151 store_canon: status != NSS_STATUS_SUCCESS);
1152 /* Use the second response status in some cases. */
1153 if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
1154 status = status2;
1155 }
1156
1157 return status;
1158}
1159
1160/* Variant of gaih_getanswer without a second (AAAA) response. */
1161static enum nss_status
1162gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
1163 struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
1164 int *errnop, int *h_errnop, int32_t *ttlp)
1165{
1166 enum nss_status status = NSS_STATUS_NOTFOUND;
1167 if (packetlen > 0)
1168 status = gaih_getanswer_slice (packet, packetlen,
1169 abuf, tailp: &pat, errnop, h_errnop, ttlp, true);
1170 return status;
1171}
1172

source code of glibc/resolv/nss_dns/dns-host.c