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