1 /* $NetBSD: gethnamaddr.c,v 1.63 2004/08/17 02:29:56 ginsbach 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.63 2004/08/17 02:29:56 ginsbach 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 #if defined(_LIBC) && defined(__weak_alias) 99 __weak_alias(gethostbyaddr,_gethostbyaddr) 100 __weak_alias(gethostbyname,_gethostbyname) 101 __weak_alias(gethostent,_gethostent) 102 #endif 103 104 #define MAXALIASES 35 105 #define MAXADDRS 35 106 107 static const char AskedForGot[] = 108 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 109 110 static char *h_addr_ptrs[MAXADDRS + 1]; 111 112 #ifdef YP 113 static char *__ypdomain; 114 #endif 115 116 static struct hostent host; 117 static char *host_aliases[MAXALIASES]; 118 static char hostbuf[8*1024]; 119 static u_int32_t host_addr[16 / sizeof(u_int32_t)]; /* IPv4 or IPv6 */ 120 static FILE *hostf = NULL; 121 static int stayopen = 0; 122 123 #define MAXPACKET (64*1024) 124 125 typedef union { 126 HEADER hdr; 127 u_char buf[MAXPACKET]; 128 } querybuf; 129 130 typedef union { 131 int32_t al; 132 char ac; 133 } align; 134 135 #ifdef DEBUG 136 static void dprintf(char *, res_state *, ...) 137 __attribute__((__format__(__printf__, 1, 3))); 138 #endif 139 static struct hostent *getanswer(const querybuf *, int, const char *, int, 140 res_state); 141 static void map_v4v6_address(const char *, char *); 142 static void map_v4v6_hostent(struct hostent *, char **, char *); 143 #ifdef RESOLVSORT 144 static void addrsort(char **, int, res_state *); 145 #endif 146 147 void _sethtent(int); 148 void _endhtent(void); 149 struct hostent *_gethtent(void); 150 void ht_sethostent(int); 151 void ht_endhostent(void); 152 struct hostent *ht_gethostbyname(char *); 153 struct hostent *ht_gethostbyaddr(const char *, int, int); 154 void dns_service(void); 155 #undef dn_skipname 156 int dn_skipname(const u_char *, const u_char *); 157 int _gethtbyaddr(void *, void *, va_list); 158 int _gethtbyname(void *, void *, va_list); 159 struct hostent *_gethtbyname2(const char *, int); 160 int _dns_gethtbyaddr(void *, void *, va_list); 161 int _dns_gethtbyname(void *, void *, va_list); 162 #ifdef YP 163 struct hostent *_yphostent(char *, int); 164 int _yp_gethtbyaddr(void *, void *, va_list); 165 int _yp_gethtbyname(void *, void *, va_list); 166 #endif 167 168 static struct hostent *gethostbyname_internal(const char *, int, res_state); 169 170 static const ns_src default_dns_files[] = { 171 { NSSRC_FILES, NS_SUCCESS }, 172 { NSSRC_DNS, NS_SUCCESS }, 173 { 0 } 174 }; 175 176 177 #ifdef DEBUG 178 static void 179 dprintf(char *msg, res_state res, ...) 180 { 181 _DIAGASSERT(msg != NULL); 182 183 if (res->options & RES_DEBUG) { 184 int save = errno; 185 va_list ap; 186 187 va_start (ap, msg); 188 vprintf(msg, ap); 189 va_end (ap); 190 191 errno = save; 192 } 193 } 194 #else 195 # define dprintf(msg, res, num) /*nada*/ 196 #endif 197 198 #define BOUNDED_INCR(x) \ 199 do { \ 200 cp += (x); \ 201 if (cp > eom) { \ 202 h_errno = NO_RECOVERY; \ 203 return NULL; \ 204 } \ 205 } while (/*CONSTCOND*/0) 206 207 #define BOUNDS_CHECK(ptr, count) \ 208 do { \ 209 if ((ptr) + (count) > eom) { \ 210 h_errno = NO_RECOVERY; \ 211 return NULL; \ 212 } \ 213 } while (/*CONSTCOND*/0) 214 215 static struct hostent * 216 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 217 res_state res) 218 { 219 const HEADER *hp; 220 const u_char *cp; 221 int n; 222 const u_char *eom, *erdata; 223 char *bp, **ap, **hap, *ep; 224 int type, class, ancount, qdcount; 225 int haveanswer, had_error; 226 int toobig = 0; 227 char tbuf[MAXDNAME]; 228 const char *tname; 229 int (*name_ok)(const char *); 230 231 _DIAGASSERT(answer != NULL); 232 _DIAGASSERT(qname != NULL); 233 234 tname = qname; 235 host.h_name = NULL; 236 eom = answer->buf + anslen; 237 switch (qtype) { 238 case T_A: 239 case T_AAAA: 240 name_ok = res_hnok; 241 break; 242 case T_PTR: 243 name_ok = res_dnok; 244 break; 245 default: 246 return NULL; /* XXX should be abort(); */ 247 } 248 /* 249 * find first satisfactory answer 250 */ 251 hp = &answer->hdr; 252 ancount = ntohs(hp->ancount); 253 qdcount = ntohs(hp->qdcount); 254 bp = hostbuf; 255 ep = hostbuf + sizeof hostbuf; 256 cp = answer->buf; 257 BOUNDED_INCR(HFIXEDSZ); 258 if (qdcount != 1) { 259 h_errno = NO_RECOVERY; 260 return NULL; 261 } 262 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 263 if ((n < 0) || !(*name_ok)(bp)) { 264 h_errno = NO_RECOVERY; 265 return NULL; 266 } 267 BOUNDED_INCR(n + QFIXEDSZ); 268 if (qtype == T_A || qtype == T_AAAA) { 269 /* res_send() has already verified that the query name is the 270 * same as the one we sent; this just gets the expanded name 271 * (i.e., with the succeeding search-domain tacked on). 272 */ 273 n = strlen(bp) + 1; /* for the \0 */ 274 if (n >= MAXHOSTNAMELEN) { 275 h_errno = NO_RECOVERY; 276 return NULL; 277 } 278 host.h_name = bp; 279 bp += n; 280 /* The qname can be abbreviated, but h_name is now absolute. */ 281 qname = host.h_name; 282 } 283 ap = host_aliases; 284 *ap = NULL; 285 host.h_aliases = host_aliases; 286 hap = h_addr_ptrs; 287 *hap = NULL; 288 host.h_addr_list = h_addr_ptrs; 289 haveanswer = 0; 290 had_error = 0; 291 while (ancount-- > 0 && cp < eom && !had_error) { 292 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 293 if ((n < 0) || !(*name_ok)(bp)) { 294 had_error++; 295 continue; 296 } 297 cp += n; /* name */ 298 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 299 type = _getshort(cp); 300 cp += INT16SZ; /* type */ 301 class = _getshort(cp); 302 cp += INT16SZ + INT32SZ; /* class, TTL */ 303 n = _getshort(cp); 304 cp += INT16SZ; /* len */ 305 BOUNDS_CHECK(cp, n); 306 erdata = cp + n; 307 if (class != C_IN) { 308 /* XXX - debug? syslog? */ 309 cp += n; 310 continue; /* XXX - had_error++ ? */ 311 } 312 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 313 if (ap >= &host_aliases[MAXALIASES-1]) 314 continue; 315 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 316 if ((n < 0) || !(*name_ok)(tbuf)) { 317 had_error++; 318 continue; 319 } 320 cp += n; 321 if (cp != erdata) { 322 h_errno = NO_RECOVERY; 323 return NULL; 324 } 325 /* Store alias. */ 326 *ap++ = bp; 327 n = strlen(bp) + 1; /* for the \0 */ 328 if (n >= MAXHOSTNAMELEN) { 329 had_error++; 330 continue; 331 } 332 bp += n; 333 /* Get canonical name. */ 334 n = 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 host.h_name = bp; 341 bp += n; 342 continue; 343 } 344 if (qtype == T_PTR && type == T_CNAME) { 345 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 346 if (n < 0 || !res_dnok(tbuf)) { 347 had_error++; 348 continue; 349 } 350 cp += n; 351 if (cp != erdata) { 352 h_errno = NO_RECOVERY; 353 return NULL; 354 } 355 /* Get canonical name. */ 356 n = strlen(tbuf) + 1; /* for the \0 */ 357 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 358 had_error++; 359 continue; 360 } 361 strlcpy(bp, tbuf, (size_t)(ep - bp)); 362 tname = bp; 363 bp += n; 364 continue; 365 } 366 if (type != qtype) { 367 if (type != T_KEY && type != T_SIG) 368 syslog(LOG_NOTICE|LOG_AUTH, 369 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 370 qname, p_class(C_IN), p_type(qtype), 371 p_type(type)); 372 cp += n; 373 continue; /* XXX - had_error++ ? */ 374 } 375 switch (type) { 376 case T_PTR: 377 if (strcasecmp(tname, bp) != 0) { 378 syslog(LOG_NOTICE|LOG_AUTH, 379 AskedForGot, qname, bp); 380 cp += n; 381 continue; /* XXX - had_error++ ? */ 382 } 383 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 384 if ((n < 0) || !res_hnok(bp)) { 385 had_error++; 386 break; 387 } 388 #if MULTI_PTRS_ARE_ALIASES 389 cp += n; 390 if (cp != erdata) { 391 h_errno = NO_RECOVERY; 392 return NULL; 393 } 394 if (!haveanswer) 395 host.h_name = bp; 396 else if (ap < &host_aliases[MAXALIASES-1]) 397 *ap++ = bp; 398 else 399 n = -1; 400 if (n != -1) { 401 n = strlen(bp) + 1; /* for the \0 */ 402 if (n >= MAXHOSTNAMELEN) { 403 had_error++; 404 break; 405 } 406 bp += n; 407 } 408 break; 409 #else 410 host.h_name = bp; 411 if (res->options & RES_USE_INET6) { 412 n = strlen(bp) + 1; /* for the \0 */ 413 if (n >= MAXHOSTNAMELEN) { 414 had_error++; 415 break; 416 } 417 bp += n; 418 map_v4v6_hostent(&host, &bp, ep); 419 } 420 h_errno = NETDB_SUCCESS; 421 return &host; 422 #endif 423 case T_A: 424 case T_AAAA: 425 if (strcasecmp(host.h_name, bp) != 0) { 426 syslog(LOG_NOTICE|LOG_AUTH, 427 AskedForGot, host.h_name, bp); 428 cp += n; 429 continue; /* XXX - had_error++ ? */ 430 } 431 if (n != host.h_length) { 432 cp += n; 433 continue; 434 } 435 if (type == T_AAAA) { 436 struct in6_addr in6; 437 memcpy(&in6, cp, IN6ADDRSZ); 438 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 439 cp += n; 440 continue; 441 } 442 } 443 if (!haveanswer) { 444 int nn; 445 446 host.h_name = bp; 447 nn = strlen(bp) + 1; /* for the \0 */ 448 bp += nn; 449 } 450 451 bp += sizeof(align) - 452 (size_t)((u_long)bp % sizeof(align)); 453 454 if (bp + n >= &hostbuf[sizeof hostbuf]) { 455 dprintf("size (%d) too big\n", res, n); 456 had_error++; 457 continue; 458 } 459 if (hap >= &h_addr_ptrs[MAXADDRS-1]) { 460 if (!toobig++) 461 dprintf("Too many addresses (%d)\n", 462 res, MAXADDRS); 463 cp += n; 464 continue; 465 } 466 (void)memcpy(*hap++ = bp, cp, (size_t)n); 467 bp += n; 468 cp += n; 469 if (cp != erdata) { 470 h_errno = NO_RECOVERY; 471 return NULL; 472 } 473 break; 474 default: 475 abort(); 476 } 477 if (!had_error) 478 haveanswer++; 479 } 480 if (haveanswer) { 481 *ap = NULL; 482 *hap = NULL; 483 # if defined(RESOLVSORT) 484 /* 485 * Note: we sort even if host can take only one address 486 * in its return structures - should give it the "best" 487 * address in that case, not some random one 488 */ 489 if (res->nsort && haveanswer > 1 && qtype == T_A) 490 addrsort(h_addr_ptrs, haveanswer, res); 491 # endif /*RESOLVSORT*/ 492 if (!host.h_name) { 493 n = strlen(qname) + 1; /* for the \0 */ 494 if (n > ep - bp || n >= MAXHOSTNAMELEN) 495 goto no_recovery; 496 strlcpy(bp, qname, (size_t)(ep - bp)); 497 host.h_name = bp; 498 bp += n; 499 } 500 if (res->options & RES_USE_INET6) 501 map_v4v6_hostent(&host, &bp, ep); 502 h_errno = NETDB_SUCCESS; 503 return &host; 504 } 505 no_recovery: 506 h_errno = NO_RECOVERY; 507 return NULL; 508 } 509 510 struct hostent * 511 gethostbyname(const char *name) 512 { 513 struct hostent *hp; 514 res_state res = __res_get_state(); 515 516 if (res == NULL) 517 return NULL; 518 519 _DIAGASSERT(name != NULL); 520 521 if (res->options & RES_USE_INET6) { 522 hp = gethostbyname_internal(name, AF_INET6, res); 523 if (hp) { 524 __res_put_state(res); 525 return hp; 526 } 527 } 528 hp = gethostbyname_internal(name, AF_INET, res); 529 __res_put_state(res); 530 return hp; 531 } 532 533 struct hostent * 534 gethostbyname2(const char *name, int af) 535 { 536 struct hostent *hp; 537 res_state res = __res_get_state(); 538 539 if (res == NULL) 540 return NULL; 541 hp = gethostbyname_internal(name, af, res); 542 __res_put_state(res); 543 return hp; 544 } 545 546 static struct hostent * 547 gethostbyname_internal(const char *name, int af, res_state res) 548 { 549 const char *cp; 550 char *bp, *ep; 551 int size; 552 struct hostent *hp; 553 static const ns_dtab dtab[] = { 554 NS_FILES_CB(_gethtbyname, NULL) 555 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ 556 NS_NIS_CB(_yp_gethtbyname, NULL) 557 { 0 } 558 }; 559 560 _DIAGASSERT(name != NULL); 561 562 switch (af) { 563 case AF_INET: 564 size = INADDRSZ; 565 break; 566 case AF_INET6: 567 size = IN6ADDRSZ; 568 break; 569 default: 570 h_errno = NETDB_INTERNAL; 571 errno = EAFNOSUPPORT; 572 return NULL; 573 } 574 575 host.h_addrtype = af; 576 host.h_length = 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 if (inet_pton(af, name, 601 (char *)(void *)host_addr) <= 0) { 602 h_errno = HOST_NOT_FOUND; 603 return NULL; 604 } 605 strncpy(hostbuf, name, MAXDNAME); 606 hostbuf[MAXDNAME] = '\0'; 607 bp = hostbuf + MAXDNAME; 608 ep = hostbuf + sizeof hostbuf; 609 host.h_name = hostbuf; 610 host.h_aliases = host_aliases; 611 host_aliases[0] = NULL; 612 h_addr_ptrs[0] = (char *)(void *)host_addr; 613 h_addr_ptrs[1] = NULL; 614 host.h_addr_list = h_addr_ptrs; 615 if (res->options & RES_USE_INET6) 616 map_v4v6_hostent(&host, &bp, ep); 617 h_errno = NETDB_SUCCESS; 618 return &host; 619 } 620 if (!isdigit((u_char) *cp) && *cp != '.') 621 break; 622 } 623 if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) || 624 name[0] == ':') 625 for (cp = name;; ++cp) { 626 if (!*cp) { 627 if (*--cp == '.') 628 break; 629 /* 630 * All-IPv6-legal, no dot at the end. 631 * Fake up a hostent as if we'd actually 632 * done a lookup. 633 */ 634 if (inet_pton(af, name, 635 (char *)(void *)host_addr) <= 0) { 636 h_errno = HOST_NOT_FOUND; 637 return NULL; 638 } 639 strncpy(hostbuf, name, MAXDNAME); 640 hostbuf[MAXDNAME] = '\0'; 641 bp = hostbuf + MAXDNAME; 642 ep = hostbuf + sizeof hostbuf; 643 host.h_name = hostbuf; 644 host.h_aliases = host_aliases; 645 host_aliases[0] = NULL; 646 h_addr_ptrs[0] = (char *)(void *)host_addr; 647 h_addr_ptrs[1] = NULL; 648 host.h_addr_list = h_addr_ptrs; 649 h_errno = NETDB_SUCCESS; 650 return &host; 651 } 652 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') 653 break; 654 } 655 656 hp = NULL; 657 h_errno = NETDB_INTERNAL; 658 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname", 659 default_dns_files, name, strlen(name), af) != NS_SUCCESS) 660 return NULL; 661 h_errno = NETDB_SUCCESS; 662 return hp; 663 } 664 665 struct hostent * 666 gethostbyaddr(const char *addr, /* XXX should have been def'd as u_char! */ 667 socklen_t len, int af) 668 { 669 const u_char *uaddr = (const u_char *)addr; 670 socklen_t size; 671 struct hostent *hp; 672 static const ns_dtab dtab[] = { 673 NS_FILES_CB(_gethtbyaddr, NULL) 674 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ 675 NS_NIS_CB(_yp_gethtbyaddr, NULL) 676 { 0 } 677 }; 678 679 _DIAGASSERT(addr != NULL); 680 681 if (af == AF_INET6 && len == IN6ADDRSZ && 682 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) || 683 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) { 684 h_errno = HOST_NOT_FOUND; 685 return NULL; 686 } 687 if (af == AF_INET6 && len == IN6ADDRSZ && 688 (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) || 689 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) { 690 /* Unmap. */ 691 addr += IN6ADDRSZ - INADDRSZ; 692 uaddr += IN6ADDRSZ - INADDRSZ; 693 af = AF_INET; 694 len = INADDRSZ; 695 } 696 switch (af) { 697 case AF_INET: 698 size = INADDRSZ; 699 break; 700 case AF_INET6: 701 size = IN6ADDRSZ; 702 break; 703 default: 704 errno = EAFNOSUPPORT; 705 h_errno = NETDB_INTERNAL; 706 return NULL; 707 } 708 if (size != len) { 709 errno = EINVAL; 710 h_errno = NETDB_INTERNAL; 711 return NULL; 712 } 713 hp = NULL; 714 h_errno = NETDB_INTERNAL; 715 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", 716 default_dns_files, uaddr, len, af) != NS_SUCCESS) 717 return NULL; 718 h_errno = NETDB_SUCCESS; 719 return hp; 720 } 721 722 void 723 _sethtent(int f) 724 { 725 if (!hostf) 726 hostf = fopen(_PATH_HOSTS, "r" ); 727 else 728 rewind(hostf); 729 stayopen = f; 730 } 731 732 void 733 _endhtent(void) 734 { 735 if (hostf && !stayopen) { 736 (void) fclose(hostf); 737 hostf = NULL; 738 } 739 } 740 741 struct hostent * 742 _gethtent(void) 743 { 744 char *p; 745 char *cp, **q; 746 int af, len; 747 748 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) { 749 h_errno = NETDB_INTERNAL; 750 return NULL; 751 } 752 again: 753 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) { 754 h_errno = HOST_NOT_FOUND; 755 return NULL; 756 } 757 if (*p == '#') 758 goto again; 759 if (!(cp = strpbrk(p, "#\n"))) 760 goto again; 761 *cp = '\0'; 762 if (!(cp = strpbrk(p, " \t"))) 763 goto again; 764 *cp++ = '\0'; 765 if (inet_pton(AF_INET6, p, (char *)(void *)host_addr) > 0) { 766 af = AF_INET6; 767 len = IN6ADDRSZ; 768 } else if (inet_pton(AF_INET, p, (char *)(void *)host_addr) > 0) { 769 res_state res = __res_get_state(); 770 if (res == NULL) 771 return NULL; 772 if (res->options & RES_USE_INET6) { 773 map_v4v6_address((char *)(void *)host_addr, 774 (char *)(void *)host_addr); 775 af = AF_INET6; 776 len = IN6ADDRSZ; 777 } else { 778 af = AF_INET; 779 len = INADDRSZ; 780 } 781 __res_put_state(res); 782 } else { 783 goto again; 784 } 785 /* if this is not something we're looking for, skip it. */ 786 if (host.h_addrtype != af) 787 goto again; 788 if (host.h_length != len) 789 goto again; 790 h_addr_ptrs[0] = (char *)(void *)host_addr; 791 h_addr_ptrs[1] = NULL; 792 host.h_addr_list = h_addr_ptrs; 793 host.h_length = len; 794 host.h_addrtype = af; 795 while (*cp == ' ' || *cp == '\t') 796 cp++; 797 host.h_name = cp; 798 q = host.h_aliases = host_aliases; 799 if ((cp = strpbrk(cp, " \t")) != NULL) 800 *cp++ = '\0'; 801 while (cp && *cp) { 802 if (*cp == ' ' || *cp == '\t') { 803 cp++; 804 continue; 805 } 806 if (q < &host_aliases[MAXALIASES - 1]) 807 *q++ = cp; 808 if ((cp = strpbrk(cp, " \t")) != NULL) 809 *cp++ = '\0'; 810 } 811 *q = NULL; 812 h_errno = NETDB_SUCCESS; 813 return &host; 814 } 815 816 /*ARGSUSED*/ 817 int 818 _gethtbyname(void *rv, void *cb_data, va_list ap) 819 { 820 struct hostent *hp; 821 const char *name; 822 int af; 823 824 _DIAGASSERT(rv != NULL); 825 826 name = va_arg(ap, char *); 827 /* NOSTRICT skip len */(void)va_arg(ap, int); 828 af = va_arg(ap, int); 829 830 hp = NULL; 831 #if 0 832 { 833 res_state res = __res_get_state(); 834 if (res == NULL) 835 return NS_NOTFOUND; 836 if (res->options & RES_USE_INET6) 837 hp = _gethtbyname2(name, AF_INET6); 838 if (hp==NULL) 839 hp = _gethtbyname2(name, AF_INET); 840 __res_put_state(res); 841 } 842 #else 843 hp = _gethtbyname2(name, af); 844 #endif 845 *((struct hostent **)rv) = hp; 846 if (hp == NULL) { 847 h_errno = HOST_NOT_FOUND; 848 return NS_NOTFOUND; 849 } 850 return NS_SUCCESS; 851 } 852 853 struct hostent * 854 _gethtbyname2(const char *name, int af) 855 { 856 struct hostent *p; 857 char *tmpbuf, *ptr, **cp; 858 int num; 859 size_t len; 860 861 _DIAGASSERT(name != NULL); 862 863 _sethtent(stayopen); 864 ptr = tmpbuf = NULL; 865 num = 0; 866 while ((p = _gethtent()) != NULL && num < MAXADDRS) { 867 if (p->h_addrtype != af) 868 continue; 869 if (strcasecmp(p->h_name, name) != 0) { 870 for (cp = p->h_aliases; *cp != NULL; cp++) 871 if (strcasecmp(*cp, name) == 0) 872 break; 873 if (*cp == NULL) continue; 874 } 875 876 if (num == 0) { 877 size_t bufsize; 878 char *src; 879 880 bufsize = strlen(p->h_name) + 2 + 881 MAXADDRS * p->h_length + 882 ALIGNBYTES; 883 for (cp = p->h_aliases; *cp != NULL; cp++) 884 bufsize += strlen(*cp) + 1; 885 886 if ((tmpbuf = malloc(bufsize)) == NULL) { 887 h_errno = NETDB_INTERNAL; 888 return NULL; 889 } 890 891 ptr = tmpbuf; 892 src = p->h_name; 893 while ((*ptr++ = *src++) != '\0'); 894 for (cp = p->h_aliases; *cp != NULL; cp++) { 895 src = *cp; 896 while ((*ptr++ = *src++) != '\0'); 897 } 898 *ptr++ = '\0'; 899 900 ptr = (char *)(void *)ALIGN(ptr); 901 } 902 903 (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length); 904 ptr += p->h_length; 905 num++; 906 } 907 _endhtent(); 908 if (num == 0) return NULL; 909 910 len = ptr - tmpbuf; 911 if (len > (sizeof(hostbuf) - ALIGNBYTES)) { 912 free(tmpbuf); 913 errno = ENOSPC; 914 h_errno = NETDB_INTERNAL; 915 return NULL; 916 } 917 ptr = memcpy((void *)ALIGN(hostbuf), tmpbuf, len); 918 free(tmpbuf); 919 920 host.h_name = ptr; 921 while (*ptr++); 922 923 cp = host_aliases; 924 while (*ptr) { 925 *cp++ = ptr; 926 while (*ptr++); 927 } 928 ptr++; 929 *cp = NULL; 930 931 ptr = (char *)(void *)ALIGN(ptr); 932 cp = h_addr_ptrs; 933 while (num--) { 934 *cp++ = ptr; 935 ptr += host.h_length; 936 } 937 *cp = NULL; 938 939 return &host; 940 } 941 942 /*ARGSUSED*/ 943 int 944 _gethtbyaddr(void *rv, void *cb_data, va_list ap) 945 { 946 struct hostent *p; 947 const unsigned char *addr; 948 int len, af; 949 950 _DIAGASSERT(rv != NULL); 951 952 addr = va_arg(ap, unsigned char *); 953 len = va_arg(ap, int); 954 af = va_arg(ap, int); 955 956 host.h_length = len; 957 host.h_addrtype = af; 958 959 _sethtent(stayopen); 960 while ((p = _gethtent()) != NULL) 961 if (p->h_addrtype == af && !memcmp(p->h_addr, addr, 962 (size_t)len)) 963 break; 964 _endhtent(); 965 *((struct hostent **)rv) = p; 966 if (p==NULL) { 967 h_errno = HOST_NOT_FOUND; 968 return NS_NOTFOUND; 969 } 970 return NS_SUCCESS; 971 } 972 973 static void 974 map_v4v6_address(const char *src, char *dst) 975 { 976 u_char *p = (u_char *)dst; 977 char tmp[INADDRSZ]; 978 int i; 979 980 _DIAGASSERT(src != NULL); 981 _DIAGASSERT(dst != NULL); 982 983 /* Stash a temporary copy so our caller can update in place. */ 984 (void)memcpy(tmp, src, INADDRSZ); 985 /* Mark this ipv6 addr as a mapped ipv4. */ 986 for (i = 0; i < 10; i++) 987 *p++ = 0x00; 988 *p++ = 0xff; 989 *p++ = 0xff; 990 /* Retrieve the saved copy and we're done. */ 991 (void)memcpy((void *)p, tmp, INADDRSZ); 992 } 993 994 static void 995 map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) 996 { 997 char **ap; 998 999 _DIAGASSERT(hp != NULL); 1000 _DIAGASSERT(bpp != NULL); 1001 _DIAGASSERT(ep != NULL); 1002 1003 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) 1004 return; 1005 hp->h_addrtype = AF_INET6; 1006 hp->h_length = IN6ADDRSZ; 1007 for (ap = hp->h_addr_list; *ap; ap++) { 1008 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align)); 1009 1010 if (ep - *bpp < (i + IN6ADDRSZ)) { 1011 /* Out of memory. Truncate address list here. XXX */ 1012 *ap = NULL; 1013 return; 1014 } 1015 *bpp += i; 1016 map_v4v6_address(*ap, *bpp); 1017 *ap = *bpp; 1018 *bpp += IN6ADDRSZ; 1019 } 1020 } 1021 1022 #ifdef RESOLVSORT 1023 static void 1024 addrsort(char **ap, int num, res_state res) 1025 { 1026 int i, j; 1027 char **p; 1028 short aval[MAXADDRS]; 1029 int needsort = 0; 1030 1031 _DIAGASSERT(ap != NULL); 1032 1033 p = ap; 1034 for (i = 0; i < num; i++, p++) { 1035 for (j = 0 ; (unsigned)j < res->nsort; j++) 1036 if (res->sort_list[j].addr.s_addr == 1037 (((struct in_addr *)(void *)(*p))->s_addr & 1038 res->sort_list[j].mask)) 1039 break; 1040 aval[i] = j; 1041 if (needsort == 0 && i > 0 && j < aval[i-1]) 1042 needsort = i; 1043 } 1044 if (!needsort) 1045 return; 1046 1047 while (needsort < num) { 1048 for (j = needsort - 1; j >= 0; j--) { 1049 if (aval[j] > aval[j+1]) { 1050 char *hp; 1051 1052 i = aval[j]; 1053 aval[j] = aval[j+1]; 1054 aval[j+1] = i; 1055 1056 hp = ap[j]; 1057 ap[j] = ap[j+1]; 1058 ap[j+1] = hp; 1059 } else 1060 break; 1061 } 1062 needsort++; 1063 } 1064 } 1065 #endif 1066 1067 struct hostent * 1068 gethostent(void) 1069 { 1070 return _gethtent(); 1071 } 1072 1073 /*ARGSUSED*/ 1074 int 1075 _dns_gethtbyname(void *rv, void *cb_data, va_list ap) 1076 { 1077 querybuf *buf; 1078 int n, type; 1079 struct hostent *hp; 1080 const char *name; 1081 int af; 1082 res_state res; 1083 1084 _DIAGASSERT(rv != NULL); 1085 1086 name = va_arg(ap, char *); 1087 /* NOSTRICT skip len */(void)va_arg(ap, int); 1088 af = va_arg(ap, int); 1089 1090 switch (af) { 1091 case AF_INET: 1092 type = T_A; 1093 break; 1094 case AF_INET6: 1095 type = T_AAAA; 1096 break; 1097 default: 1098 return NS_UNAVAIL; 1099 } 1100 buf = malloc(sizeof(*buf)); 1101 if (buf == NULL) { 1102 h_errno = NETDB_INTERNAL; 1103 return NS_NOTFOUND; 1104 } 1105 res = __res_get_state(); 1106 if (res == NULL) 1107 return NS_NOTFOUND; 1108 n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf)); 1109 if (n < 0) { 1110 free(buf); 1111 dprintf("res_nsearch failed (%d)\n", res, n); 1112 __res_put_state(res); 1113 return NS_NOTFOUND; 1114 } 1115 hp = getanswer(buf, n, name, type, res); 1116 free(buf); 1117 __res_put_state(res); 1118 if (hp == NULL) 1119 switch (h_errno) { 1120 case HOST_NOT_FOUND: 1121 return NS_NOTFOUND; 1122 case TRY_AGAIN: 1123 return NS_TRYAGAIN; 1124 default: 1125 return NS_UNAVAIL; 1126 } 1127 *((struct hostent **)rv) = hp; 1128 return NS_SUCCESS; 1129 } 1130 1131 /*ARGSUSED*/ 1132 int 1133 _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) 1134 { 1135 char qbuf[MAXDNAME + 1], *qp, *ep; 1136 int n; 1137 querybuf *buf; 1138 struct hostent *hp; 1139 const unsigned char *uaddr; 1140 int len, af, advance; 1141 res_state res; 1142 1143 _DIAGASSERT(rv != NULL); 1144 1145 uaddr = va_arg(ap, unsigned char *); 1146 len = va_arg(ap, int); 1147 af = va_arg(ap, int); 1148 1149 switch (af) { 1150 case AF_INET: 1151 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 1152 (uaddr[3] & 0xff), (uaddr[2] & 0xff), 1153 (uaddr[1] & 0xff), (uaddr[0] & 0xff)); 1154 break; 1155 1156 case AF_INET6: 1157 qp = qbuf; 1158 ep = qbuf + sizeof(qbuf) - 1; 1159 for (n = IN6ADDRSZ - 1; n >= 0; n--) { 1160 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", 1161 uaddr[n] & 0xf, 1162 ((unsigned int)uaddr[n] >> 4) & 0xf); 1163 if (advance > 0 && qp + advance < ep) 1164 qp += advance; 1165 else { 1166 h_errno = NETDB_INTERNAL; 1167 return NS_NOTFOUND; 1168 } 1169 } 1170 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { 1171 h_errno = NETDB_INTERNAL; 1172 return NS_NOTFOUND; 1173 } 1174 break; 1175 default: 1176 abort(); 1177 } 1178 1179 buf = malloc(sizeof(*buf)); 1180 if (buf == NULL) { 1181 h_errno = NETDB_INTERNAL; 1182 return NS_NOTFOUND; 1183 } 1184 res = __res_get_state(); 1185 if (res == NULL) 1186 return NS_NOTFOUND; 1187 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); 1188 if (n < 0) { 1189 free(buf); 1190 dprintf("res_nquery failed (%d)\n", res, n); 1191 __res_put_state(res); 1192 return NS_NOTFOUND; 1193 } 1194 hp = getanswer(buf, n, qbuf, T_PTR, res); 1195 free(buf); 1196 if (hp == NULL) { 1197 __res_put_state(res); 1198 switch (h_errno) { 1199 case HOST_NOT_FOUND: 1200 return NS_NOTFOUND; 1201 case TRY_AGAIN: 1202 return NS_TRYAGAIN; 1203 default: 1204 return NS_UNAVAIL; 1205 } 1206 } 1207 hp->h_addrtype = af; 1208 hp->h_length = len; 1209 (void)memcpy(host_addr, uaddr, (size_t)len); 1210 h_addr_ptrs[0] = (char *)(void *)host_addr; 1211 h_addr_ptrs[1] = NULL; 1212 if (af == AF_INET && (res->options & RES_USE_INET6)) { 1213 map_v4v6_address((char *)(void *)host_addr, 1214 (char *)(void *)host_addr); 1215 hp->h_addrtype = AF_INET6; 1216 hp->h_length = IN6ADDRSZ; 1217 } 1218 1219 __res_put_state(res); 1220 *((struct hostent **)rv) = hp; 1221 h_errno = NETDB_SUCCESS; 1222 return NS_SUCCESS; 1223 } 1224 1225 #ifdef YP 1226 /*ARGSUSED*/ 1227 struct hostent * 1228 _yphostent(char *line, int af) 1229 { 1230 static struct in_addr host_addrs[MAXADDRS]; 1231 static struct in6_addr host6_addrs[MAXADDRS]; 1232 char *p = line; 1233 char *cp, **q; 1234 char **hap; 1235 int addrok; 1236 int more; 1237 size_t naddrs; 1238 1239 _DIAGASSERT(line != NULL); 1240 1241 host.h_name = NULL; 1242 host.h_addr_list = h_addr_ptrs; 1243 host.h_addrtype = af; 1244 switch (af) { 1245 case AF_INET: 1246 host.h_length = INADDRSZ; 1247 break; 1248 case AF_INET6: 1249 host.h_length = IN6ADDRSZ; 1250 break; 1251 default: 1252 return NULL; 1253 } 1254 hap = h_addr_ptrs; 1255 q = host.h_aliases = host_aliases; 1256 naddrs = 0; 1257 1258 nextline: 1259 /* check for host_addrs overflow */ 1260 if (naddrs >= sizeof(host_addrs) / sizeof(host_addrs[0])) 1261 goto done; 1262 if (naddrs >= sizeof(host6_addrs) / sizeof(host6_addrs[0])) 1263 goto done; 1264 1265 more = 0; 1266 cp = strpbrk(p, " \t"); 1267 if (cp == NULL) 1268 goto done; 1269 *cp++ = '\0'; 1270 1271 /* p has should have an address */ 1272 switch (af) { 1273 case AF_INET: 1274 addrok = inet_aton(p, &host_addrs[naddrs]); 1275 break; 1276 case AF_INET6: 1277 addrok = inet_pton(af, p, &host6_addrs[naddrs]); 1278 break; 1279 } 1280 if (addrok != 1) { 1281 /* skip to the next line */ 1282 while (cp && *cp) { 1283 if (*cp == '\n') { 1284 cp++; 1285 goto nextline; 1286 } 1287 cp++; 1288 } 1289 1290 goto done; 1291 } 1292 1293 switch (af) { 1294 case AF_INET: 1295 *hap++ = (char *)(void *)&host_addrs[naddrs++]; 1296 break; 1297 case AF_INET6: 1298 *hap++ = (char *)(void *)&host6_addrs[naddrs++]; 1299 break; 1300 } 1301 1302 while (*cp == ' ' || *cp == '\t') 1303 cp++; 1304 p = cp; 1305 cp = strpbrk(p, " \t\n"); 1306 if (cp != NULL) { 1307 if (*cp == '\n') 1308 more = 1; 1309 *cp++ = '\0'; 1310 } 1311 if (!host.h_name) 1312 host.h_name = p; 1313 else if (strcmp(host.h_name, p)==0) 1314 ; 1315 else if (q < &host_aliases[MAXALIASES - 1]) 1316 *q++ = p; 1317 p = cp; 1318 if (more) 1319 goto nextline; 1320 1321 while (cp && *cp) { 1322 if (*cp == ' ' || *cp == '\t') { 1323 cp++; 1324 continue; 1325 } 1326 if (*cp == '\n') { 1327 cp++; 1328 goto nextline; 1329 } 1330 if (q < &host_aliases[MAXALIASES - 1]) 1331 *q++ = cp; 1332 cp = strpbrk(cp, " \t"); 1333 if (cp != NULL) 1334 *cp++ = '\0'; 1335 } 1336 1337 done: 1338 if (host.h_name == NULL) 1339 return NULL; 1340 *q = NULL; 1341 *hap = NULL; 1342 return &host; 1343 } 1344 1345 /*ARGSUSED*/ 1346 int 1347 _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) 1348 { 1349 struct hostent *hp = NULL; 1350 static char *__ypcurrent; 1351 int __ypcurrentlen, r; 1352 char name[INET6_ADDRSTRLEN]; /* XXX enough? */ 1353 const unsigned char *uaddr; 1354 int af; 1355 const char *map; 1356 1357 _DIAGASSERT(rv != NULL); 1358 1359 uaddr = va_arg(ap, unsigned char *); 1360 /* NOSTRICT skip len */(void)va_arg(ap, int); 1361 af = va_arg(ap, int); 1362 1363 if (!__ypdomain) { 1364 if (_yp_check(&__ypdomain) == 0) 1365 return NS_UNAVAIL; 1366 } 1367 /* 1368 * XXX unfortunately, we cannot support IPv6 extended scoped address 1369 * notation here. gethostbyaddr() is not scope-aware. too bad. 1370 */ 1371 if (inet_ntop(af, uaddr, name, sizeof(name)) == NULL) 1372 return NS_UNAVAIL; 1373 if (__ypcurrent) 1374 free(__ypcurrent); 1375 __ypcurrent = NULL; 1376 switch (af) { 1377 case AF_INET: 1378 map = "hosts.byaddr"; 1379 break; 1380 default: 1381 map = "ipnodes.byaddr"; 1382 break; 1383 } 1384 r = yp_match(__ypdomain, map, name, 1385 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1386 if (r == 0) 1387 hp = _yphostent(__ypcurrent, af); 1388 if (hp == NULL) { 1389 h_errno = HOST_NOT_FOUND; 1390 return NS_NOTFOUND; 1391 } 1392 *((struct hostent **)rv) = hp; 1393 return NS_SUCCESS; 1394 } 1395 1396 /*ARGSUSED*/ 1397 int 1398 _yp_gethtbyname(void *rv, void *cb_data, va_list ap) 1399 { 1400 struct hostent *hp = NULL; 1401 static char *__ypcurrent; 1402 int __ypcurrentlen, r; 1403 const char *name; 1404 int af; 1405 const char *map; 1406 1407 _DIAGASSERT(rv != NULL); 1408 1409 name = va_arg(ap, char *); 1410 /* NOSTRICT skip len */(void)va_arg(ap, int); 1411 af = va_arg(ap, int); 1412 1413 if (!__ypdomain) { 1414 if (_yp_check(&__ypdomain) == 0) 1415 return NS_UNAVAIL; 1416 } 1417 if (__ypcurrent) 1418 free(__ypcurrent); 1419 __ypcurrent = NULL; 1420 switch (af) { 1421 case AF_INET: 1422 map = "hosts.byname"; 1423 break; 1424 default: 1425 map = "ipnodes.byname"; 1426 break; 1427 } 1428 r = yp_match(__ypdomain, map, name, 1429 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1430 if (r == 0) 1431 hp = _yphostent(__ypcurrent, af); 1432 if (hp == NULL) { 1433 h_errno = HOST_NOT_FOUND; 1434 return NS_NOTFOUND; 1435 } 1436 *((struct hostent **)rv) = hp; 1437 return NS_SUCCESS; 1438 } 1439 #endif 1440