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