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