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