1 /* $NetBSD: gethnamaddr.c,v 1.64 2004/11/23 03:42:13 lukem 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.64 2004/11/23 03:42:13 lukem 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 != 0 && host.h_addrtype != af) 787 goto again; 788 if (host.h_length != 0 && 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 host.h_addrtype = 0; 1071 host.h_length = 0; 1072 return _gethtent(); 1073 } 1074 1075 /*ARGSUSED*/ 1076 int 1077 _dns_gethtbyname(void *rv, void *cb_data, va_list ap) 1078 { 1079 querybuf *buf; 1080 int n, type; 1081 struct hostent *hp; 1082 const char *name; 1083 int af; 1084 res_state res; 1085 1086 _DIAGASSERT(rv != NULL); 1087 1088 name = va_arg(ap, char *); 1089 /* NOSTRICT skip len */(void)va_arg(ap, int); 1090 af = va_arg(ap, int); 1091 1092 switch (af) { 1093 case AF_INET: 1094 type = T_A; 1095 break; 1096 case AF_INET6: 1097 type = T_AAAA; 1098 break; 1099 default: 1100 return NS_UNAVAIL; 1101 } 1102 buf = malloc(sizeof(*buf)); 1103 if (buf == NULL) { 1104 h_errno = NETDB_INTERNAL; 1105 return NS_NOTFOUND; 1106 } 1107 res = __res_get_state(); 1108 if (res == NULL) 1109 return NS_NOTFOUND; 1110 n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf)); 1111 if (n < 0) { 1112 free(buf); 1113 dprintf("res_nsearch failed (%d)\n", res, n); 1114 __res_put_state(res); 1115 return NS_NOTFOUND; 1116 } 1117 hp = getanswer(buf, n, name, type, res); 1118 free(buf); 1119 __res_put_state(res); 1120 if (hp == NULL) 1121 switch (h_errno) { 1122 case HOST_NOT_FOUND: 1123 return NS_NOTFOUND; 1124 case TRY_AGAIN: 1125 return NS_TRYAGAIN; 1126 default: 1127 return NS_UNAVAIL; 1128 } 1129 *((struct hostent **)rv) = hp; 1130 return NS_SUCCESS; 1131 } 1132 1133 /*ARGSUSED*/ 1134 int 1135 _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) 1136 { 1137 char qbuf[MAXDNAME + 1], *qp, *ep; 1138 int n; 1139 querybuf *buf; 1140 struct hostent *hp; 1141 const unsigned char *uaddr; 1142 int len, af, advance; 1143 res_state res; 1144 1145 _DIAGASSERT(rv != NULL); 1146 1147 uaddr = va_arg(ap, unsigned char *); 1148 len = va_arg(ap, int); 1149 af = va_arg(ap, int); 1150 1151 switch (af) { 1152 case AF_INET: 1153 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 1154 (uaddr[3] & 0xff), (uaddr[2] & 0xff), 1155 (uaddr[1] & 0xff), (uaddr[0] & 0xff)); 1156 break; 1157 1158 case AF_INET6: 1159 qp = qbuf; 1160 ep = qbuf + sizeof(qbuf) - 1; 1161 for (n = IN6ADDRSZ - 1; n >= 0; n--) { 1162 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", 1163 uaddr[n] & 0xf, 1164 ((unsigned int)uaddr[n] >> 4) & 0xf); 1165 if (advance > 0 && qp + advance < ep) 1166 qp += advance; 1167 else { 1168 h_errno = NETDB_INTERNAL; 1169 return NS_NOTFOUND; 1170 } 1171 } 1172 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { 1173 h_errno = NETDB_INTERNAL; 1174 return NS_NOTFOUND; 1175 } 1176 break; 1177 default: 1178 abort(); 1179 } 1180 1181 buf = malloc(sizeof(*buf)); 1182 if (buf == NULL) { 1183 h_errno = NETDB_INTERNAL; 1184 return NS_NOTFOUND; 1185 } 1186 res = __res_get_state(); 1187 if (res == NULL) 1188 return NS_NOTFOUND; 1189 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); 1190 if (n < 0) { 1191 free(buf); 1192 dprintf("res_nquery failed (%d)\n", res, n); 1193 __res_put_state(res); 1194 return NS_NOTFOUND; 1195 } 1196 hp = getanswer(buf, n, qbuf, T_PTR, res); 1197 free(buf); 1198 if (hp == NULL) { 1199 __res_put_state(res); 1200 switch (h_errno) { 1201 case HOST_NOT_FOUND: 1202 return NS_NOTFOUND; 1203 case TRY_AGAIN: 1204 return NS_TRYAGAIN; 1205 default: 1206 return NS_UNAVAIL; 1207 } 1208 } 1209 hp->h_addrtype = af; 1210 hp->h_length = len; 1211 (void)memcpy(host_addr, uaddr, (size_t)len); 1212 h_addr_ptrs[0] = (char *)(void *)host_addr; 1213 h_addr_ptrs[1] = NULL; 1214 if (af == AF_INET && (res->options & RES_USE_INET6)) { 1215 map_v4v6_address((char *)(void *)host_addr, 1216 (char *)(void *)host_addr); 1217 hp->h_addrtype = AF_INET6; 1218 hp->h_length = IN6ADDRSZ; 1219 } 1220 1221 __res_put_state(res); 1222 *((struct hostent **)rv) = hp; 1223 h_errno = NETDB_SUCCESS; 1224 return NS_SUCCESS; 1225 } 1226 1227 #ifdef YP 1228 /*ARGSUSED*/ 1229 struct hostent * 1230 _yphostent(char *line, int af) 1231 { 1232 static struct in_addr host_addrs[MAXADDRS]; 1233 static struct in6_addr host6_addrs[MAXADDRS]; 1234 char *p = line; 1235 char *cp, **q; 1236 char **hap; 1237 int addrok; 1238 int more; 1239 size_t naddrs; 1240 1241 _DIAGASSERT(line != NULL); 1242 1243 host.h_name = NULL; 1244 host.h_addr_list = h_addr_ptrs; 1245 host.h_addrtype = af; 1246 switch (af) { 1247 case AF_INET: 1248 host.h_length = INADDRSZ; 1249 break; 1250 case AF_INET6: 1251 host.h_length = IN6ADDRSZ; 1252 break; 1253 default: 1254 return NULL; 1255 } 1256 hap = h_addr_ptrs; 1257 q = host.h_aliases = host_aliases; 1258 naddrs = 0; 1259 1260 nextline: 1261 /* check for host_addrs overflow */ 1262 if (naddrs >= sizeof(host_addrs) / sizeof(host_addrs[0])) 1263 goto done; 1264 if (naddrs >= sizeof(host6_addrs) / sizeof(host6_addrs[0])) 1265 goto done; 1266 1267 more = 0; 1268 cp = strpbrk(p, " \t"); 1269 if (cp == NULL) 1270 goto done; 1271 *cp++ = '\0'; 1272 1273 /* p has should have an address */ 1274 switch (af) { 1275 case AF_INET: 1276 addrok = inet_aton(p, &host_addrs[naddrs]); 1277 break; 1278 case AF_INET6: 1279 addrok = inet_pton(af, p, &host6_addrs[naddrs]); 1280 break; 1281 } 1282 if (addrok != 1) { 1283 /* skip to the next line */ 1284 while (cp && *cp) { 1285 if (*cp == '\n') { 1286 cp++; 1287 goto nextline; 1288 } 1289 cp++; 1290 } 1291 1292 goto done; 1293 } 1294 1295 switch (af) { 1296 case AF_INET: 1297 *hap++ = (char *)(void *)&host_addrs[naddrs++]; 1298 break; 1299 case AF_INET6: 1300 *hap++ = (char *)(void *)&host6_addrs[naddrs++]; 1301 break; 1302 } 1303 1304 while (*cp == ' ' || *cp == '\t') 1305 cp++; 1306 p = cp; 1307 cp = strpbrk(p, " \t\n"); 1308 if (cp != NULL) { 1309 if (*cp == '\n') 1310 more = 1; 1311 *cp++ = '\0'; 1312 } 1313 if (!host.h_name) 1314 host.h_name = p; 1315 else if (strcmp(host.h_name, p)==0) 1316 ; 1317 else if (q < &host_aliases[MAXALIASES - 1]) 1318 *q++ = p; 1319 p = cp; 1320 if (more) 1321 goto nextline; 1322 1323 while (cp && *cp) { 1324 if (*cp == ' ' || *cp == '\t') { 1325 cp++; 1326 continue; 1327 } 1328 if (*cp == '\n') { 1329 cp++; 1330 goto nextline; 1331 } 1332 if (q < &host_aliases[MAXALIASES - 1]) 1333 *q++ = cp; 1334 cp = strpbrk(cp, " \t"); 1335 if (cp != NULL) 1336 *cp++ = '\0'; 1337 } 1338 1339 done: 1340 if (host.h_name == NULL) 1341 return NULL; 1342 *q = NULL; 1343 *hap = NULL; 1344 return &host; 1345 } 1346 1347 /*ARGSUSED*/ 1348 int 1349 _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) 1350 { 1351 struct hostent *hp = NULL; 1352 static char *__ypcurrent; 1353 int __ypcurrentlen, r; 1354 char name[INET6_ADDRSTRLEN]; /* XXX enough? */ 1355 const unsigned char *uaddr; 1356 int af; 1357 const char *map; 1358 1359 _DIAGASSERT(rv != NULL); 1360 1361 uaddr = va_arg(ap, unsigned char *); 1362 /* NOSTRICT skip len */(void)va_arg(ap, int); 1363 af = va_arg(ap, int); 1364 1365 if (!__ypdomain) { 1366 if (_yp_check(&__ypdomain) == 0) 1367 return NS_UNAVAIL; 1368 } 1369 /* 1370 * XXX unfortunately, we cannot support IPv6 extended scoped address 1371 * notation here. gethostbyaddr() is not scope-aware. too bad. 1372 */ 1373 if (inet_ntop(af, uaddr, name, sizeof(name)) == NULL) 1374 return NS_UNAVAIL; 1375 if (__ypcurrent) 1376 free(__ypcurrent); 1377 __ypcurrent = NULL; 1378 switch (af) { 1379 case AF_INET: 1380 map = "hosts.byaddr"; 1381 break; 1382 default: 1383 map = "ipnodes.byaddr"; 1384 break; 1385 } 1386 r = yp_match(__ypdomain, map, name, 1387 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1388 if (r == 0) 1389 hp = _yphostent(__ypcurrent, af); 1390 if (hp == NULL) { 1391 h_errno = HOST_NOT_FOUND; 1392 return NS_NOTFOUND; 1393 } 1394 *((struct hostent **)rv) = hp; 1395 return NS_SUCCESS; 1396 } 1397 1398 /*ARGSUSED*/ 1399 int 1400 _yp_gethtbyname(void *rv, void *cb_data, va_list ap) 1401 { 1402 struct hostent *hp = NULL; 1403 static char *__ypcurrent; 1404 int __ypcurrentlen, r; 1405 const char *name; 1406 int af; 1407 const char *map; 1408 1409 _DIAGASSERT(rv != NULL); 1410 1411 name = va_arg(ap, char *); 1412 /* NOSTRICT skip len */(void)va_arg(ap, int); 1413 af = va_arg(ap, int); 1414 1415 if (!__ypdomain) { 1416 if (_yp_check(&__ypdomain) == 0) 1417 return NS_UNAVAIL; 1418 } 1419 if (__ypcurrent) 1420 free(__ypcurrent); 1421 __ypcurrent = NULL; 1422 switch (af) { 1423 case AF_INET: 1424 map = "hosts.byname"; 1425 break; 1426 default: 1427 map = "ipnodes.byname"; 1428 break; 1429 } 1430 r = yp_match(__ypdomain, map, name, 1431 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1432 if (r == 0) 1433 hp = _yphostent(__ypcurrent, af); 1434 if (hp == NULL) { 1435 h_errno = HOST_NOT_FOUND; 1436 return NS_NOTFOUND; 1437 } 1438 *((struct hostent **)rv) = hp; 1439 return NS_SUCCESS; 1440 } 1441 #endif 1442