1 /* $NetBSD: gethnamaddr.c,v 1.84 2013/08/27 09:56:12 christos Exp $ */ 2 3 /* 4 * ++Copyright++ 1985, 1988, 1993 5 * - 6 * Copyright (c) 1985, 1988, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * - 33 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 34 * 35 * Permission to use, copy, modify, and distribute this software for any 36 * purpose with or without fee is hereby granted, provided that the above 37 * copyright notice and this permission notice appear in all copies, and that 38 * the name of Digital Equipment Corporation not be used in advertising or 39 * publicity pertaining to distribution of the document or software without 40 * specific, written prior permission. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 43 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 44 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 45 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 46 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 47 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 48 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 49 * SOFTWARE. 50 * - 51 * --Copyright-- 52 */ 53 54 #include <sys/cdefs.h> 55 #if defined(LIBC_SCCS) && !defined(lint) 56 #if 0 57 static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; 58 static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp "; 59 #else 60 __RCSID("$NetBSD: gethnamaddr.c,v 1.84 2013/08/27 09:56:12 christos Exp $"); 61 #endif 62 #endif /* LIBC_SCCS and not lint */ 63 64 #if defined(_LIBC) 65 #include "namespace.h" 66 #endif 67 #include <sys/param.h> 68 #include <sys/socket.h> 69 #include <netinet/in.h> 70 #include <arpa/inet.h> 71 #include <arpa/nameser.h> 72 73 #include <assert.h> 74 #include <ctype.h> 75 #include <errno.h> 76 #include <netdb.h> 77 #include <resolv.h> 78 #include <stdarg.h> 79 #include <stdio.h> 80 #include <syslog.h> 81 82 #ifndef LOG_AUTH 83 # define LOG_AUTH 0 84 #endif 85 86 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ 87 88 #include <nsswitch.h> 89 #include <stdlib.h> 90 #include <string.h> 91 92 #ifdef YP 93 #include <rpc/rpc.h> 94 #include <rpcsvc/yp_prot.h> 95 #include <rpcsvc/ypclnt.h> 96 #endif 97 98 #include "hostent.h" 99 100 #if defined(_LIBC) && defined(__weak_alias) 101 __weak_alias(gethostbyaddr,_gethostbyaddr) 102 __weak_alias(gethostbyname,_gethostbyname) 103 __weak_alias(gethostent,_gethostent) 104 #endif 105 106 #define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \ 107 (ok)(nm) != 0) 108 #define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok) 109 #define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok) 110 111 112 static const char AskedForGot[] = 113 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 114 115 116 #ifdef YP 117 static char *__ypdomain; 118 #endif 119 120 #define MAXPACKET (64*1024) 121 122 typedef union { 123 HEADER hdr; 124 u_char buf[MAXPACKET]; 125 } querybuf; 126 127 typedef union { 128 int32_t al; 129 char ac; 130 } align; 131 132 #ifdef DEBUG 133 static void debugprintf(const char *, res_state, ...) 134 __attribute__((__format__(__printf__, 1, 3))); 135 #endif 136 static struct hostent *getanswer(const querybuf *, int, const char *, int, 137 res_state, struct hostent *, char *, size_t, int *); 138 static void map_v4v6_address(const char *, char *); 139 static void map_v4v6_hostent(struct hostent *, char **, char *); 140 static void addrsort(char **, int, res_state); 141 142 void dns_service(void); 143 #undef dn_skipname 144 int dn_skipname(const u_char *, const u_char *); 145 146 #ifdef YP 147 static struct hostent *_yp_hostent(char *, int, struct getnamaddr *); 148 #endif 149 150 static struct hostent *gethostbyname_internal(const char *, int, res_state, 151 struct hostent *, char *, size_t, int *); 152 153 static const ns_src default_dns_files[] = { 154 { NSSRC_FILES, NS_SUCCESS }, 155 { NSSRC_DNS, NS_SUCCESS }, 156 { 0, 0 } 157 }; 158 159 160 #ifdef DEBUG 161 static void 162 debugprintf(const char *msg, res_state res, ...) 163 { 164 _DIAGASSERT(msg != NULL); 165 166 if (res->options & RES_DEBUG) { 167 int save = errno; 168 va_list ap; 169 170 va_start (ap, res); 171 vprintf(msg, ap); 172 va_end (ap); 173 174 errno = save; 175 } 176 } 177 #else 178 # define debugprintf(msg, res, num) /*nada*/ 179 #endif 180 181 #define BOUNDED_INCR(x) \ 182 do { \ 183 cp += (x); \ 184 if (cp > eom) { \ 185 h_errno = NO_RECOVERY; \ 186 return NULL; \ 187 } \ 188 } while (/*CONSTCOND*/0) 189 190 #define BOUNDS_CHECK(ptr, count) \ 191 do { \ 192 if ((ptr) + (count) > eom) { \ 193 h_errno = NO_RECOVERY; \ 194 return NULL; \ 195 } \ 196 } while (/*CONSTCOND*/0) 197 198 static struct hostent * 199 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 200 res_state res, struct hostent *hent, char *buf, size_t buflen, int *he) 201 { 202 const HEADER *hp; 203 const u_char *cp; 204 int n; 205 size_t qlen; 206 const u_char *eom, *erdata; 207 char *bp, **ap, **hap, *ep; 208 int type, class, ancount, qdcount; 209 int haveanswer, had_error; 210 int toobig = 0; 211 char tbuf[MAXDNAME]; 212 char *aliases[MAXALIASES]; 213 char *addr_ptrs[MAXADDRS]; 214 const char *tname; 215 int (*name_ok)(const char *); 216 217 _DIAGASSERT(answer != NULL); 218 _DIAGASSERT(qname != NULL); 219 220 tname = qname; 221 hent->h_name = NULL; 222 eom = answer->buf + anslen; 223 switch (qtype) { 224 case T_A: 225 case T_AAAA: 226 name_ok = res_hnok; 227 break; 228 case T_PTR: 229 name_ok = res_dnok; 230 break; 231 default: 232 return NULL; /* XXX should be abort(); */ 233 } 234 /* 235 * find first satisfactory answer 236 */ 237 hp = &answer->hdr; 238 ancount = ntohs(hp->ancount); 239 qdcount = ntohs(hp->qdcount); 240 bp = buf; 241 ep = buf + buflen; 242 cp = answer->buf; 243 BOUNDED_INCR(HFIXEDSZ); 244 if (qdcount != 1) 245 goto no_recovery; 246 247 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); 248 if ((n < 0) || !maybe_ok(res, bp, name_ok)) 249 goto no_recovery; 250 251 BOUNDED_INCR(n + QFIXEDSZ); 252 if (qtype == T_A || qtype == T_AAAA) { 253 /* res_send() has already verified that the query name is the 254 * same as the one we sent; this just gets the expanded name 255 * (i.e., with the succeeding search-domain tacked on). 256 */ 257 n = (int)strlen(bp) + 1; /* for the \0 */ 258 if (n >= MAXHOSTNAMELEN) 259 goto no_recovery; 260 hent->h_name = bp; 261 bp += n; 262 /* The qname can be abbreviated, but h_name is now absolute. */ 263 qname = hent->h_name; 264 } 265 hent->h_aliases = ap = aliases; 266 hent->h_addr_list = hap = addr_ptrs; 267 *ap = NULL; 268 *hap = NULL; 269 haveanswer = 0; 270 had_error = 0; 271 while (ancount-- > 0 && cp < eom && !had_error) { 272 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); 273 if ((n < 0) || !maybe_ok(res, bp, name_ok)) { 274 had_error++; 275 continue; 276 } 277 cp += n; /* name */ 278 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 279 type = _getshort(cp); 280 cp += INT16SZ; /* type */ 281 class = _getshort(cp); 282 cp += INT16SZ + INT32SZ; /* class, TTL */ 283 n = _getshort(cp); 284 cp += INT16SZ; /* len */ 285 BOUNDS_CHECK(cp, n); 286 erdata = cp + n; 287 if (class != C_IN) { 288 /* XXX - debug? syslog? */ 289 cp += n; 290 continue; /* XXX - had_error++ ? */ 291 } 292 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 293 if (ap >= &aliases[MAXALIASES-1]) 294 continue; 295 n = dn_expand(answer->buf, eom, cp, tbuf, 296 (int)sizeof tbuf); 297 if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) { 298 had_error++; 299 continue; 300 } 301 cp += n; 302 if (cp != erdata) 303 goto no_recovery; 304 /* Store alias. */ 305 *ap++ = bp; 306 n = (int)strlen(bp) + 1; /* for the \0 */ 307 if (n >= MAXHOSTNAMELEN) { 308 had_error++; 309 continue; 310 } 311 bp += n; 312 /* Get canonical name. */ 313 n = (int)strlen(tbuf) + 1; /* for the \0 */ 314 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 315 had_error++; 316 continue; 317 } 318 strlcpy(bp, tbuf, (size_t)(ep - bp)); 319 hent->h_name = bp; 320 bp += n; 321 continue; 322 } 323 if (qtype == T_PTR && type == T_CNAME) { 324 n = dn_expand(answer->buf, eom, cp, tbuf, 325 (int)sizeof tbuf); 326 if (n < 0 || !maybe_dnok(res, tbuf)) { 327 had_error++; 328 continue; 329 } 330 cp += n; 331 if (cp != erdata) 332 goto no_recovery; 333 /* Get canonical name. */ 334 n = (int)strlen(tbuf) + 1; /* for the \0 */ 335 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 336 had_error++; 337 continue; 338 } 339 strlcpy(bp, tbuf, (size_t)(ep - bp)); 340 tname = bp; 341 bp += n; 342 continue; 343 } 344 if (type != qtype) { 345 if (type != T_KEY && type != T_SIG) 346 syslog(LOG_NOTICE|LOG_AUTH, 347 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 348 qname, p_class(C_IN), p_type(qtype), 349 p_type(type)); 350 cp += n; 351 continue; /* XXX - had_error++ ? */ 352 } 353 switch (type) { 354 case T_PTR: 355 if (strcasecmp(tname, bp) != 0) { 356 syslog(LOG_NOTICE|LOG_AUTH, 357 AskedForGot, qname, bp); 358 cp += n; 359 continue; /* XXX - had_error++ ? */ 360 } 361 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); 362 if ((n < 0) || !maybe_hnok(res, bp)) { 363 had_error++; 364 break; 365 } 366 #if MULTI_PTRS_ARE_ALIASES 367 cp += n; 368 if (cp != erdata) 369 goto no_recovery; 370 if (!haveanswer) 371 hent->h_name = bp; 372 else if (ap < &aliases[MAXALIASES-1]) 373 *ap++ = bp; 374 else 375 n = -1; 376 if (n != -1) { 377 n = (int)strlen(bp) + 1; /* for the \0 */ 378 if (n >= MAXHOSTNAMELEN) { 379 had_error++; 380 break; 381 } 382 bp += n; 383 } 384 break; 385 #else 386 hent->h_name = bp; 387 if (res->options & RES_USE_INET6) { 388 n = strlen(bp) + 1; /* for the \0 */ 389 if (n >= MAXHOSTNAMELEN) { 390 had_error++; 391 break; 392 } 393 bp += n; 394 map_v4v6_hostent(hent, &bp, ep); 395 } 396 goto success; 397 #endif 398 case T_A: 399 case T_AAAA: 400 if (strcasecmp(hent->h_name, bp) != 0) { 401 syslog(LOG_NOTICE|LOG_AUTH, 402 AskedForGot, hent->h_name, bp); 403 cp += n; 404 continue; /* XXX - had_error++ ? */ 405 } 406 if (n != hent->h_length) { 407 cp += n; 408 continue; 409 } 410 if (type == T_AAAA) { 411 struct in6_addr in6; 412 memcpy(&in6, cp, NS_IN6ADDRSZ); 413 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 414 cp += n; 415 continue; 416 } 417 } 418 if (!haveanswer) { 419 int nn; 420 421 hent->h_name = bp; 422 nn = (int)strlen(bp) + 1; /* for the \0 */ 423 bp += nn; 424 } 425 426 bp += sizeof(align) - 427 (size_t)((u_long)bp % sizeof(align)); 428 429 if (bp + n >= ep) { 430 debugprintf("size (%d) too big\n", res, n); 431 had_error++; 432 continue; 433 } 434 if (hap >= &addr_ptrs[MAXADDRS - 1]) { 435 if (!toobig++) { 436 debugprintf("Too many addresses (%d)\n", 437 res, MAXADDRS); 438 } 439 cp += n; 440 continue; 441 } 442 (void)memcpy(*hap++ = bp, cp, (size_t)n); 443 bp += n; 444 cp += n; 445 if (cp != erdata) 446 goto no_recovery; 447 break; 448 default: 449 abort(); 450 } 451 if (!had_error) 452 haveanswer++; 453 } 454 if (haveanswer) { 455 *ap = NULL; 456 *hap = NULL; 457 /* 458 * Note: we sort even if host can take only one address 459 * in its return structures - should give it the "best" 460 * address in that case, not some random one 461 */ 462 if (res->nsort && haveanswer > 1 && qtype == T_A) 463 addrsort(addr_ptrs, haveanswer, res); 464 if (!hent->h_name) { 465 n = (int)strlen(qname) + 1; /* for the \0 */ 466 if (n > ep - bp || n >= MAXHOSTNAMELEN) 467 goto no_recovery; 468 strlcpy(bp, qname, (size_t)(ep - bp)); 469 hent->h_name = bp; 470 bp += n; 471 } 472 if (res->options & RES_USE_INET6) 473 map_v4v6_hostent(hent, &bp, ep); 474 goto success; 475 } 476 no_recovery: 477 *he = NO_RECOVERY; 478 return NULL; 479 success: 480 bp = (char *)ALIGN(bp); 481 n = (int)(ap - aliases); 482 qlen = (n + 1) * sizeof(*hent->h_aliases); 483 if ((size_t)(ep - bp) < qlen) 484 goto nospc; 485 hent->h_aliases = (void *)bp; 486 memcpy(bp, aliases, qlen); 487 488 bp += qlen; 489 n = (int)(hap - addr_ptrs); 490 qlen = (n + 1) * sizeof(*hent->h_addr_list); 491 if ((size_t)(ep - bp) < qlen) 492 goto nospc; 493 hent->h_addr_list = (void *)bp; 494 memcpy(bp, addr_ptrs, qlen); 495 *he = NETDB_SUCCESS; 496 return hent; 497 nospc: 498 errno = ENOSPC; 499 *he = NETDB_INTERNAL; 500 return NULL; 501 } 502 503 struct hostent * 504 gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, 505 int *he) 506 { 507 res_state res = __res_get_state(); 508 509 if (res == NULL) { 510 *he = NETDB_INTERNAL; 511 return NULL; 512 } 513 514 _DIAGASSERT(name != NULL); 515 516 if (res->options & RES_USE_INET6) { 517 hp = gethostbyname_internal(name, AF_INET6, res, hp, buf, 518 buflen, he); 519 if (hp) { 520 __res_put_state(res); 521 return hp; 522 } 523 } 524 hp = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, he); 525 __res_put_state(res); 526 return hp; 527 } 528 529 struct hostent * 530 gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf, 531 size_t buflen, int *he) 532 { 533 res_state res = __res_get_state(); 534 535 if (res == NULL) { 536 *he = NETDB_INTERNAL; 537 return NULL; 538 } 539 hp = gethostbyname_internal(name, af, res, hp, buf, buflen, he); 540 __res_put_state(res); 541 return hp; 542 } 543 544 static struct hostent * 545 gethostbyname_internal(const char *name, int af, res_state res, 546 struct hostent *hp, char *buf, size_t buflen, int *he) 547 { 548 const char *cp; 549 struct getnamaddr info; 550 size_t size; 551 static const ns_dtab dtab[] = { 552 NS_FILES_CB(_hf_gethtbyname, NULL) 553 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ 554 NS_NIS_CB(_yp_gethtbyname, NULL) 555 NS_NULL_CB 556 }; 557 558 _DIAGASSERT(name != NULL); 559 560 switch (af) { 561 case AF_INET: 562 size = NS_INADDRSZ; 563 break; 564 case AF_INET6: 565 size = NS_IN6ADDRSZ; 566 break; 567 default: 568 *he = NETDB_INTERNAL; 569 errno = EAFNOSUPPORT; 570 return NULL; 571 } 572 if (buflen < size) 573 goto nospc; 574 575 hp->h_addrtype = af; 576 hp->h_length = (int)size; 577 578 /* 579 * if there aren't any dots, it could be a user-level alias. 580 * this is also done in res_nquery() since we are not the only 581 * function that looks up host names. 582 */ 583 if (!strchr(name, '.') && (cp = __hostalias(name))) 584 name = cp; 585 586 /* 587 * disallow names consisting only of digits/dots, unless 588 * they end in a dot. 589 */ 590 if (isdigit((u_char) name[0])) 591 for (cp = name;; ++cp) { 592 if (!*cp) { 593 if (*--cp == '.') 594 break; 595 /* 596 * All-numeric, no dot at the end. 597 * Fake up a hostent as if we'd actually 598 * done a lookup. 599 */ 600 goto fake; 601 } 602 if (!isdigit((u_char) *cp) && *cp != '.') 603 break; 604 } 605 if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) || 606 name[0] == ':') 607 for (cp = name;; ++cp) { 608 if (!*cp) { 609 if (*--cp == '.') 610 break; 611 /* 612 * All-IPv6-legal, no dot at the end. 613 * Fake up a hostent as if we'd actually 614 * done a lookup. 615 */ 616 goto fake; 617 } 618 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') 619 break; 620 } 621 622 *he = NETDB_INTERNAL; 623 info.hp = hp; 624 info.buf = buf; 625 info.buflen = buflen; 626 info.he = he; 627 if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname", 628 default_dns_files, name, strlen(name), af) != NS_SUCCESS) 629 return NULL; 630 *he = NETDB_SUCCESS; 631 return hp; 632 nospc: 633 *he = NETDB_INTERNAL; 634 errno = ENOSPC; 635 return NULL; 636 fake: 637 HENT_ARRAY(hp->h_addr_list, 1, buf, buflen); 638 HENT_ARRAY(hp->h_aliases, 0, buf, buflen); 639 640 hp->h_aliases[0] = NULL; 641 if (size > buflen) 642 goto nospc; 643 644 if (inet_pton(af, name, buf) <= 0) { 645 *he = HOST_NOT_FOUND; 646 return NULL; 647 } 648 hp->h_addr_list[0] = buf; 649 hp->h_addr_list[1] = NULL; 650 buf += size; 651 buflen -= size; 652 HENT_SCOPY(hp->h_name, name, buf, buflen); 653 if (res->options & RES_USE_INET6) 654 map_v4v6_hostent(hp, &buf, buf + buflen); 655 *he = NETDB_SUCCESS; 656 return hp; 657 } 658 659 struct hostent * 660 gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, 661 char *buf, size_t buflen, int *he) 662 { 663 const u_char *uaddr = (const u_char *)addr; 664 socklen_t size; 665 struct getnamaddr info; 666 static const ns_dtab dtab[] = { 667 NS_FILES_CB(_hf_gethtbyaddr, NULL) 668 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ 669 NS_NIS_CB(_yp_gethtbyaddr, NULL) 670 NS_NULL_CB 671 }; 672 673 _DIAGASSERT(addr != NULL); 674 675 if (af == AF_INET6 && len == NS_IN6ADDRSZ && 676 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) || 677 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) { 678 *he = HOST_NOT_FOUND; 679 return NULL; 680 } 681 if (af == AF_INET6 && len == NS_IN6ADDRSZ && 682 (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) || 683 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) { 684 /* Unmap. */ 685 uaddr += NS_IN6ADDRSZ - NS_INADDRSZ; 686 addr = uaddr; 687 af = AF_INET; 688 len = NS_INADDRSZ; 689 } 690 switch (af) { 691 case AF_INET: 692 size = NS_INADDRSZ; 693 break; 694 case AF_INET6: 695 size = NS_IN6ADDRSZ; 696 break; 697 default: 698 errno = EAFNOSUPPORT; 699 *he = NETDB_INTERNAL; 700 return NULL; 701 } 702 if (size != len) { 703 errno = EINVAL; 704 *he = NETDB_INTERNAL; 705 return NULL; 706 } 707 info.hp = hp; 708 info.buf = buf; 709 info.buflen = buflen; 710 info.he = he; 711 *he = NETDB_INTERNAL; 712 if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr", 713 default_dns_files, uaddr, len, af) != NS_SUCCESS) 714 return NULL; 715 *he = NETDB_SUCCESS; 716 return hp; 717 } 718 719 struct hostent * 720 gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he) 721 { 722 char *p, *name; 723 char *cp, **q; 724 int af, len; 725 size_t llen, anum; 726 char *aliases[MAXALIASES]; 727 struct in6_addr host_addr; 728 729 if (hf == NULL) { 730 *he = NETDB_INTERNAL; 731 errno = EINVAL; 732 return NULL; 733 } 734 again: 735 if ((p = fgetln(hf, &llen)) == NULL) { 736 *he = HOST_NOT_FOUND; 737 return NULL; 738 } 739 if (llen < 1) 740 goto again; 741 if (*p == '#') 742 goto again; 743 p[llen] = '\0'; 744 if (!(cp = strpbrk(p, "#\n"))) 745 goto again; 746 *cp = '\0'; 747 if (!(cp = strpbrk(p, " \t"))) 748 goto again; 749 *cp++ = '\0'; 750 if (inet_pton(AF_INET6, p, &host_addr) > 0) { 751 af = AF_INET6; 752 len = NS_IN6ADDRSZ; 753 } else if (inet_pton(AF_INET, p, &host_addr) > 0) { 754 res_state res = __res_get_state(); 755 if (res == NULL) 756 return NULL; 757 if (res->options & RES_USE_INET6) { 758 map_v4v6_address(buf, buf); 759 af = AF_INET6; 760 len = NS_IN6ADDRSZ; 761 } else { 762 af = AF_INET; 763 len = NS_INADDRSZ; 764 } 765 __res_put_state(res); 766 } else { 767 goto again; 768 } 769 /* if this is not something we're looking for, skip it. */ 770 if (hent->h_addrtype != 0 && hent->h_addrtype != af) 771 goto again; 772 if (hent->h_length != 0 && hent->h_length != len) 773 goto again; 774 775 while (*cp == ' ' || *cp == '\t') 776 cp++; 777 if ((cp = strpbrk(name = cp, " \t")) != NULL) 778 *cp++ = '\0'; 779 q = aliases; 780 while (cp && *cp) { 781 if (*cp == ' ' || *cp == '\t') { 782 cp++; 783 continue; 784 } 785 if (q >= &aliases[__arraycount(aliases)]) 786 goto nospc; 787 *q++ = cp; 788 if ((cp = strpbrk(cp, " \t")) != NULL) 789 *cp++ = '\0'; 790 } 791 hent->h_length = len; 792 hent->h_addrtype = af; 793 HENT_ARRAY(hent->h_addr_list, 1, buf, buflen); 794 anum = (size_t)(q - aliases); 795 HENT_ARRAY(hent->h_aliases, anum, buf, buflen); 796 HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf, 797 buflen); 798 hent->h_addr_list[1] = NULL; 799 800 HENT_SCOPY(hent->h_name, name, buf, buflen); 801 for (size_t i = 0; i < anum; i++) 802 HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen); 803 hent->h_aliases[anum] = NULL; 804 805 *he = NETDB_SUCCESS; 806 return hent; 807 nospc: 808 errno = ENOSPC; 809 *he = NETDB_INTERNAL; 810 return NULL; 811 } 812 813 static void 814 map_v4v6_address(const char *src, char *dst) 815 { 816 u_char *p = (u_char *)dst; 817 char tmp[NS_INADDRSZ]; 818 int i; 819 820 _DIAGASSERT(src != NULL); 821 _DIAGASSERT(dst != NULL); 822 823 /* Stash a temporary copy so our caller can update in place. */ 824 (void)memcpy(tmp, src, NS_INADDRSZ); 825 /* Mark this ipv6 addr as a mapped ipv4. */ 826 for (i = 0; i < 10; i++) 827 *p++ = 0x00; 828 *p++ = 0xff; 829 *p++ = 0xff; 830 /* Retrieve the saved copy and we're done. */ 831 (void)memcpy(p, tmp, NS_INADDRSZ); 832 } 833 834 static void 835 map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) 836 { 837 char **ap; 838 839 _DIAGASSERT(hp != NULL); 840 _DIAGASSERT(bpp != NULL); 841 _DIAGASSERT(ep != NULL); 842 843 if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ) 844 return; 845 hp->h_addrtype = AF_INET6; 846 hp->h_length = NS_IN6ADDRSZ; 847 for (ap = hp->h_addr_list; *ap; ap++) { 848 int i = (int)(sizeof(align) - 849 (size_t)((u_long)*bpp % sizeof(align))); 850 851 if (ep - *bpp < (i + NS_IN6ADDRSZ)) { 852 /* Out of memory. Truncate address list here. XXX */ 853 *ap = NULL; 854 return; 855 } 856 *bpp += i; 857 map_v4v6_address(*ap, *bpp); 858 *ap = *bpp; 859 *bpp += NS_IN6ADDRSZ; 860 } 861 } 862 863 static void 864 addrsort(char **ap, int num, res_state res) 865 { 866 int i, j; 867 char **p; 868 short aval[MAXADDRS]; 869 int needsort = 0; 870 871 _DIAGASSERT(ap != NULL); 872 873 p = ap; 874 for (i = 0; i < num; i++, p++) { 875 for (j = 0 ; (unsigned)j < res->nsort; j++) 876 if (res->sort_list[j].addr.s_addr == 877 (((struct in_addr *)(void *)(*p))->s_addr & 878 res->sort_list[j].mask)) 879 break; 880 aval[i] = j; 881 if (needsort == 0 && i > 0 && j < aval[i-1]) 882 needsort = i; 883 } 884 if (!needsort) 885 return; 886 887 while (needsort < num) { 888 for (j = needsort - 1; j >= 0; j--) { 889 if (aval[j] > aval[j+1]) { 890 char *hp; 891 892 i = aval[j]; 893 aval[j] = aval[j+1]; 894 aval[j+1] = i; 895 896 hp = ap[j]; 897 ap[j] = ap[j+1]; 898 ap[j+1] = hp; 899 } else 900 break; 901 } 902 needsort++; 903 } 904 } 905 906 907 /*ARGSUSED*/ 908 int 909 _dns_gethtbyname(void *rv, void *cb_data, va_list ap) 910 { 911 querybuf *buf; 912 int n, type; 913 struct hostent *hp; 914 const char *name; 915 res_state res; 916 struct getnamaddr *info = rv; 917 918 _DIAGASSERT(rv != NULL); 919 920 name = va_arg(ap, char *); 921 /* NOSTRICT skip string len */(void)va_arg(ap, int); 922 info->hp->h_addrtype = va_arg(ap, int); 923 924 switch (info->hp->h_addrtype) { 925 case AF_INET: 926 info->hp->h_length = NS_INADDRSZ; 927 type = T_A; 928 break; 929 case AF_INET6: 930 info->hp->h_length = NS_IN6ADDRSZ; 931 type = T_AAAA; 932 break; 933 default: 934 return NS_UNAVAIL; 935 } 936 buf = malloc(sizeof(*buf)); 937 if (buf == NULL) { 938 *info->he = NETDB_INTERNAL; 939 return NS_NOTFOUND; 940 } 941 res = __res_get_state(); 942 if (res == NULL) { 943 free(buf); 944 return NS_NOTFOUND; 945 } 946 n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf)); 947 if (n < 0) { 948 free(buf); 949 debugprintf("res_nsearch failed (%d)\n", res, n); 950 __res_put_state(res); 951 return NS_NOTFOUND; 952 } 953 hp = getanswer(buf, n, name, type, res, info->hp, info->buf, 954 info->buflen, info->he); 955 free(buf); 956 __res_put_state(res); 957 if (hp == NULL) 958 switch (h_errno) { 959 case HOST_NOT_FOUND: 960 return NS_NOTFOUND; 961 case TRY_AGAIN: 962 return NS_TRYAGAIN; 963 default: 964 return NS_UNAVAIL; 965 } 966 return NS_SUCCESS; 967 } 968 969 /*ARGSUSED*/ 970 int 971 _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) 972 { 973 char qbuf[MAXDNAME + 1], *qp, *ep; 974 int n; 975 querybuf *buf; 976 struct hostent *hp; 977 const unsigned char *uaddr; 978 int advance; 979 res_state res; 980 char *bf; 981 size_t blen; 982 struct getnamaddr *info = rv; 983 984 _DIAGASSERT(rv != NULL); 985 986 uaddr = va_arg(ap, unsigned char *); 987 info->hp->h_length = va_arg(ap, int); 988 info->hp->h_addrtype = va_arg(ap, int); 989 990 switch (info->hp->h_addrtype) { 991 case AF_INET: 992 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 993 (uaddr[3] & 0xff), (uaddr[2] & 0xff), 994 (uaddr[1] & 0xff), (uaddr[0] & 0xff)); 995 break; 996 997 case AF_INET6: 998 qp = qbuf; 999 ep = qbuf + sizeof(qbuf) - 1; 1000 for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) { 1001 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", 1002 uaddr[n] & 0xf, 1003 ((unsigned int)uaddr[n] >> 4) & 0xf); 1004 if (advance > 0 && qp + advance < ep) 1005 qp += advance; 1006 else { 1007 *info->he = NETDB_INTERNAL; 1008 return NS_NOTFOUND; 1009 } 1010 } 1011 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { 1012 *info->he = NETDB_INTERNAL; 1013 return NS_NOTFOUND; 1014 } 1015 break; 1016 default: 1017 return NS_UNAVAIL; 1018 } 1019 1020 buf = malloc(sizeof(*buf)); 1021 if (buf == NULL) { 1022 *info->he = NETDB_INTERNAL; 1023 return NS_NOTFOUND; 1024 } 1025 res = __res_get_state(); 1026 if (res == NULL) { 1027 free(buf); 1028 return NS_NOTFOUND; 1029 } 1030 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf)); 1031 if (n < 0) { 1032 free(buf); 1033 debugprintf("res_nquery failed (%d)\n", res, n); 1034 __res_put_state(res); 1035 return NS_NOTFOUND; 1036 } 1037 hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, 1038 info->buflen, info->he); 1039 free(buf); 1040 if (hp == NULL) { 1041 __res_put_state(res); 1042 switch (*info->he) { 1043 case HOST_NOT_FOUND: 1044 return NS_NOTFOUND; 1045 case TRY_AGAIN: 1046 return NS_TRYAGAIN; 1047 default: 1048 return NS_UNAVAIL; 1049 } 1050 } 1051 1052 bf = (void *)(hp->h_addr_list + 2); 1053 blen = (size_t)(bf - info->buf); 1054 if (blen + info->hp->h_length > info->buflen) 1055 goto nospc; 1056 hp->h_addr_list[0] = bf; 1057 hp->h_addr_list[1] = NULL; 1058 (void)memcpy(bf, uaddr, (size_t)info->hp->h_length); 1059 if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) { 1060 if (blen + NS_IN6ADDRSZ > info->buflen) 1061 goto nospc; 1062 map_v4v6_address(bf, bf); 1063 hp->h_addrtype = AF_INET6; 1064 hp->h_length = NS_IN6ADDRSZ; 1065 } 1066 1067 __res_put_state(res); 1068 *info->he = NETDB_SUCCESS; 1069 return NS_SUCCESS; 1070 nospc: 1071 *info->he = NETDB_INTERNAL; 1072 return NS_UNAVAIL; 1073 } 1074 1075 #ifdef YP 1076 /*ARGSUSED*/ 1077 static struct hostent * 1078 _yp_hostent(char *line, int af, struct getnamaddr *info) 1079 { 1080 struct in6_addr host_addrs[MAXADDRS]; 1081 char *aliases[MAXALIASES]; 1082 char *p = line; 1083 char *cp, **q, *ptr; 1084 size_t len, anum, i; 1085 int addrok; 1086 int more; 1087 size_t naddrs; 1088 struct hostent *hp = info->hp; 1089 1090 _DIAGASSERT(line != NULL); 1091 1092 hp->h_name = NULL; 1093 hp->h_addrtype = af; 1094 switch (af) { 1095 case AF_INET: 1096 hp->h_length = NS_INADDRSZ; 1097 break; 1098 case AF_INET6: 1099 hp->h_length = NS_IN6ADDRSZ; 1100 break; 1101 default: 1102 return NULL; 1103 } 1104 naddrs = 0; 1105 q = aliases; 1106 1107 nextline: 1108 /* check for host_addrs overflow */ 1109 if (naddrs >= __arraycount(host_addrs)) 1110 goto done; 1111 1112 more = 0; 1113 cp = strpbrk(p, " \t"); 1114 if (cp == NULL) 1115 goto done; 1116 *cp++ = '\0'; 1117 1118 /* p has should have an address */ 1119 addrok = inet_pton(af, p, &host_addrs[naddrs]); 1120 if (addrok != 1) { 1121 /* skip to the next line */ 1122 while (cp && *cp) { 1123 if (*cp == '\n') { 1124 cp++; 1125 goto nextline; 1126 } 1127 cp++; 1128 } 1129 goto done; 1130 } 1131 1132 while (*cp == ' ' || *cp == '\t') 1133 cp++; 1134 p = cp; 1135 cp = strpbrk(p, " \t\n"); 1136 if (cp != NULL) { 1137 if (*cp == '\n') 1138 more = 1; 1139 *cp++ = '\0'; 1140 } 1141 if (!hp->h_name) 1142 hp->h_name = p; 1143 else if (strcmp(hp->h_name, p) == 0) 1144 ; 1145 else if (q < &aliases[MAXALIASES - 1]) 1146 *q++ = p; 1147 p = cp; 1148 if (more) 1149 goto nextline; 1150 1151 while (cp && *cp) { 1152 if (*cp == ' ' || *cp == '\t') { 1153 cp++; 1154 continue; 1155 } 1156 if (*cp == '\n') { 1157 cp++; 1158 goto nextline; 1159 } 1160 if (q < &aliases[MAXALIASES - 1]) 1161 *q++ = cp; 1162 cp = strpbrk(cp, " \t"); 1163 if (cp != NULL) 1164 *cp++ = '\0'; 1165 } 1166 1167 done: 1168 if (hp->h_name == NULL) 1169 return NULL; 1170 1171 ptr = info->buf; 1172 len = info->buflen; 1173 1174 anum = (size_t)(q - aliases); 1175 HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len); 1176 HENT_ARRAY(hp->h_aliases, anum, ptr, len); 1177 1178 for (i = 0; i < naddrs; i++) 1179 HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length, 1180 ptr, len); 1181 hp->h_addr_list[naddrs] = NULL; 1182 1183 HENT_SCOPY(hp->h_name, hp->h_name, ptr, len); 1184 1185 for (i = 0; i < anum; i++) 1186 HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len); 1187 hp->h_aliases[anum] = NULL; 1188 1189 return hp; 1190 nospc: 1191 *info->he = NETDB_INTERNAL; 1192 errno = ENOSPC; 1193 return NULL; 1194 } 1195 1196 /*ARGSUSED*/ 1197 int 1198 _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) 1199 { 1200 struct hostent *hp = NULL; 1201 char *ypcurrent; 1202 int ypcurrentlen, r; 1203 char name[INET6_ADDRSTRLEN]; /* XXX enough? */ 1204 const unsigned char *uaddr; 1205 int af; 1206 const char *map; 1207 struct getnamaddr *info = rv; 1208 1209 _DIAGASSERT(rv != NULL); 1210 1211 uaddr = va_arg(ap, unsigned char *); 1212 /* NOSTRICT skip len */(void)va_arg(ap, int); 1213 af = va_arg(ap, int); 1214 1215 if (!__ypdomain) { 1216 if (_yp_check(&__ypdomain) == 0) 1217 return NS_UNAVAIL; 1218 } 1219 /* 1220 * XXX unfortunately, we cannot support IPv6 extended scoped address 1221 * notation here. gethostbyaddr() is not scope-aware. too bad. 1222 */ 1223 if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL) 1224 return NS_UNAVAIL; 1225 switch (af) { 1226 case AF_INET: 1227 map = "hosts.byaddr"; 1228 break; 1229 default: 1230 map = "ipnodes.byaddr"; 1231 break; 1232 } 1233 ypcurrent = NULL; 1234 r = yp_match(__ypdomain, map, name, 1235 (int)strlen(name), &ypcurrent, &ypcurrentlen); 1236 if (r == 0) 1237 hp = _yp_hostent(ypcurrent, af, info); 1238 else 1239 hp = NULL; 1240 free(ypcurrent); 1241 if (hp == NULL) { 1242 *info->he = HOST_NOT_FOUND; 1243 return NS_NOTFOUND; 1244 } 1245 return NS_SUCCESS; 1246 } 1247 1248 /*ARGSUSED*/ 1249 int 1250 _yp_gethtbyname(void *rv, void *cb_data, va_list ap) 1251 { 1252 struct hostent *hp; 1253 char *ypcurrent; 1254 int ypcurrentlen, r; 1255 const char *name; 1256 int af; 1257 const char *map; 1258 struct getnamaddr *info = rv; 1259 1260 _DIAGASSERT(rv != NULL); 1261 1262 name = va_arg(ap, char *); 1263 /* NOSTRICT skip string len */(void)va_arg(ap, int); 1264 af = va_arg(ap, int); 1265 1266 if (!__ypdomain) { 1267 if (_yp_check(&__ypdomain) == 0) 1268 return NS_UNAVAIL; 1269 } 1270 switch (af) { 1271 case AF_INET: 1272 map = "hosts.byname"; 1273 break; 1274 default: 1275 map = "ipnodes.byname"; 1276 break; 1277 } 1278 ypcurrent = NULL; 1279 r = yp_match(__ypdomain, map, name, 1280 (int)strlen(name), &ypcurrent, &ypcurrentlen); 1281 if (r == 0) 1282 hp = _yp_hostent(ypcurrent, af, info); 1283 else 1284 hp = NULL; 1285 free(ypcurrent); 1286 if (hp == NULL) { 1287 *info->he = HOST_NOT_FOUND; 1288 return NS_NOTFOUND; 1289 } 1290 return NS_SUCCESS; 1291 } 1292 #endif 1293 1294 /* 1295 * Non-reentrant versions. 1296 */ 1297 FILE *_h_file; 1298 static struct hostent h_ent; 1299 static char h_buf[16384]; 1300 1301 struct hostent * 1302 gethostbyaddr(const void *addr, socklen_t len, int af) { 1303 return gethostbyaddr_r(addr, len, af, &h_ent, h_buf, sizeof(h_buf), 1304 &h_errno); 1305 } 1306 1307 struct hostent * 1308 gethostbyname(const char *name) { 1309 return gethostbyname_r(name, &h_ent, h_buf, sizeof(h_buf), &h_errno); 1310 } 1311 1312 struct hostent * 1313 gethostbyname2(const char *name, int af) { 1314 return gethostbyname2_r(name, af, &h_ent, h_buf, sizeof(h_buf), 1315 &h_errno); 1316 } 1317 1318 struct hostent * 1319 gethostent(void) 1320 { 1321 if (_h_file == NULL) { 1322 sethostent_r(&_h_file); 1323 if (_h_file == NULL) { 1324 h_errno = NETDB_INTERNAL; 1325 return NULL; 1326 } 1327 } 1328 memset(&h_ent, 0, sizeof(h_ent)); 1329 return gethostent_r(_h_file, &h_ent, h_buf, sizeof(h_buf), &h_errno); 1330 } 1331 1332