1 /* 2 * Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1985, 1988, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 /* 40 * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 41 * 42 * Permission to use, copy, modify, and distribute this software for any 43 * purpose with or without fee is hereby granted, provided that the above 44 * copyright notice and this permission notice appear in all copies. 45 * 46 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 47 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 49 * CONSORTIUM 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 56 #pragma ident "%Z%%M% %I% %E% SMI" 57 58 /* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */ 59 /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */ 60 61 #if defined(LIBC_SCCS) && !defined(lint) 62 static const char rcsid[] = "$Id: lcl_ho.c,v 1.26 2001/05/29 05:49:04 marka Exp $"; 63 #endif /* LIBC_SCCS and not lint */ 64 65 /* Imports. */ 66 67 #include "port_before.h" 68 69 #include <sys/types.h> 70 #include <sys/param.h> 71 #include <sys/socket.h> 72 73 #include <netinet/in.h> 74 #include <arpa/inet.h> 75 #include <arpa/nameser.h> 76 77 #include <ctype.h> 78 #include <errno.h> 79 #include <fcntl.h> 80 #include <netdb.h> 81 #include <resolv.h> 82 #include <stdio.h> 83 #include <stdlib.h> 84 #include <string.h> 85 86 #include <irs.h> 87 #include <isc/memcluster.h> 88 89 #include "port_after.h" 90 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 91 #include "../../../libnsl/include/nsl_stdio_prv.h" 92 #endif 93 94 #include "irs_p.h" 95 #include "dns_p.h" 96 #include "lcl_p.h" 97 98 #ifdef SPRINTF_CHAR 99 # define SPRINTF(x) strlen(sprintf/**/x) 100 #else 101 # define SPRINTF(x) sprintf x 102 #endif 103 104 /* Definitions. */ 105 106 #define MAXALIASES 35 107 #define MAXADDRS 35 108 #define Max(a,b) ((a) > (b) ? (a) : (b)) 109 110 #if PACKETSZ > 1024 111 #define MAXPACKET PACKETSZ 112 #else 113 #define MAXPACKET 1024 114 #endif 115 116 struct pvt { 117 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 118 __NSL_FILE * fp; 119 #else 120 FILE * fp; 121 #endif 122 struct hostent host; 123 char * h_addr_ptrs[MAXADDRS + 1]; 124 char * host_aliases[MAXALIASES]; 125 char hostbuf[8*1024]; 126 u_char host_addr[16]; /* IPv4 or IPv6 */ 127 struct __res_state *res; 128 void (*free_res)(void *); 129 }; 130 131 typedef union { 132 int32_t al; 133 char ac; 134 } align; 135 136 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; 137 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; 138 139 /* Forward. */ 140 141 static void ho_close(struct irs_ho *this); 142 static struct hostent * ho_byname(struct irs_ho *this, const char *name); 143 static struct hostent * ho_byname2(struct irs_ho *this, const char *name, 144 int af); 145 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 146 int len, int af); 147 static struct hostent * ho_next(struct irs_ho *this); 148 static void ho_rewind(struct irs_ho *this); 149 static void ho_minimize(struct irs_ho *this); 150 static struct __res_state * ho_res_get(struct irs_ho *this); 151 static void ho_res_set(struct irs_ho *this, 152 struct __res_state *res, 153 void (*free_res)(void *)); 154 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, 155 const struct addrinfo *pai); 156 157 static size_t ns_namelen(const char *); 158 static int init(struct irs_ho *this); 159 160 /* Portability. */ 161 162 #ifndef SEEK_SET 163 # define SEEK_SET 0 164 #endif 165 166 /* Public. */ 167 168 struct irs_ho * 169 irs_lcl_ho(struct irs_acc *this) { 170 struct irs_ho *ho; 171 struct pvt *pvt; 172 173 UNUSED(this); 174 175 if (!(pvt = memget(sizeof *pvt))) { 176 errno = ENOMEM; 177 return (NULL); 178 } 179 memset(pvt, 0, sizeof *pvt); 180 if (!(ho = memget(sizeof *ho))) { 181 memput(pvt, sizeof *pvt); 182 errno = ENOMEM; 183 return (NULL); 184 } 185 memset(ho, 0x5e, sizeof *ho); 186 ho->private = pvt; 187 ho->close = ho_close; 188 ho->byname = ho_byname; 189 ho->byname2 = ho_byname2; 190 ho->byaddr = ho_byaddr; 191 ho->next = ho_next; 192 ho->rewind = ho_rewind; 193 ho->minimize = ho_minimize; 194 ho->res_get = ho_res_get; 195 ho->res_set = ho_res_set; 196 ho->addrinfo = ho_addrinfo; 197 return (ho); 198 } 199 200 /* Methods. */ 201 202 static void 203 ho_close(struct irs_ho *this) { 204 struct pvt *pvt = (struct pvt *)this->private; 205 206 ho_minimize(this); 207 if (pvt->fp) 208 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 209 (void) __nsl_fclose(pvt->fp); 210 #else 211 (void) fclose(pvt->fp); 212 #endif 213 if (pvt->res && pvt->free_res) 214 (*pvt->free_res)(pvt->res); 215 memput(pvt, sizeof *pvt); 216 memput(this, sizeof *this); 217 } 218 219 static struct hostent * 220 ho_byname(struct irs_ho *this, const char *name) { 221 struct pvt *pvt = (struct pvt *)this->private; 222 struct hostent *hp; 223 224 if (init(this) == -1) 225 return (NULL); 226 227 if (pvt->res->options & RES_USE_INET6) { 228 hp = ho_byname2(this, name, AF_INET6); 229 if (hp) 230 return (hp); 231 } 232 return (ho_byname2(this, name, AF_INET)); 233 } 234 235 static struct hostent * 236 ho_byname2(struct irs_ho *this, const char *name, int af) { 237 struct pvt *pvt = (struct pvt *)this->private; 238 struct hostent *hp; 239 char **hap; 240 size_t n; 241 242 if (init(this) == -1) 243 return (NULL); 244 245 ho_rewind(this); 246 n = ns_namelen(name); 247 while ((hp = ho_next(this)) != NULL) { 248 size_t nn; 249 250 if (hp->h_addrtype != af) 251 continue; 252 nn = ns_namelen(hp->h_name); 253 if (strncasecmp(hp->h_name, name, Max(n, nn)) == 0) 254 goto found; 255 for (hap = hp->h_aliases; *hap; hap++) { 256 nn = ns_namelen(*hap); 257 if (strncasecmp(*hap, name, Max(n, nn)) == 0) 258 goto found; 259 } 260 } 261 found: 262 if (!hp) { 263 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 264 return (NULL); 265 } 266 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); 267 return (hp); 268 } 269 270 static struct hostent * 271 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { 272 struct pvt *pvt = (struct pvt *)this->private; 273 const u_char *uaddr = addr; 274 struct hostent *hp; 275 int size; 276 277 if (init(this) == -1) 278 return (NULL); 279 280 if (af == AF_INET6 && len == IN6ADDRSZ && 281 (!memcmp(uaddr, mapped, sizeof mapped) || 282 !memcmp(uaddr, tunnelled, sizeof tunnelled))) { 283 /* Unmap. */ 284 addr = (const u_char *)addr + sizeof mapped; 285 uaddr += sizeof mapped; 286 af = AF_INET; 287 len = INADDRSZ; 288 } 289 switch (af) { 290 case AF_INET: 291 size = INADDRSZ; 292 break; 293 case AF_INET6: 294 size = IN6ADDRSZ; 295 break; 296 default: 297 errno = EAFNOSUPPORT; 298 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 299 return (NULL); 300 } 301 if (size > len) { 302 errno = EINVAL; 303 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 304 return (NULL); 305 } 306 307 /* 308 * Do the search. 309 */ 310 ho_rewind(this); 311 while ((hp = ho_next(this)) != NULL) { 312 char **hap; 313 314 for (hap = hp->h_addr_list; *hap; hap++) { 315 const u_char *taddr = (const u_char *)*hap; 316 int taf = hp->h_addrtype; 317 int tlen = hp->h_length; 318 319 if (taf == AF_INET6 && tlen == IN6ADDRSZ && 320 (!memcmp(taddr, mapped, sizeof mapped) || 321 !memcmp(taddr, tunnelled, sizeof tunnelled))) { 322 /* Unmap. */ 323 taddr += sizeof mapped; 324 taf = AF_INET; 325 tlen = INADDRSZ; 326 } 327 if (taf == af && tlen == len && 328 !memcmp(taddr, uaddr, tlen)) 329 goto found; 330 } 331 } 332 found: 333 if (!hp) { 334 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 335 return (NULL); 336 } 337 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); 338 return (hp); 339 } 340 341 static struct hostent * 342 ho_next(struct irs_ho *this) { 343 struct pvt *pvt = (struct pvt *)this->private; 344 char *cp, **q, *p; 345 char *bufp, *ndbuf, *dbuf = NULL; 346 int c, af, len, bufsiz, offset; 347 348 if (init(this) == -1) 349 return (NULL); 350 351 if (!pvt->fp) 352 ho_rewind(this); 353 if (!pvt->fp) { 354 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 355 return (NULL); 356 } 357 bufp = pvt->hostbuf; 358 bufsiz = sizeof pvt->hostbuf; 359 offset = 0; 360 again: 361 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 362 if (!(p = __nsl_fgets(bufp + offset, bufsiz - offset, pvt->fp))) { 363 #else 364 if (!(p = fgets(bufp + offset, bufsiz - offset, pvt->fp))) { 365 #endif 366 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 367 if (dbuf) 368 free(dbuf); 369 return (NULL); 370 } 371 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 372 if (!strchr(p, '\n') && !__nsl_feof(pvt->fp)) { 373 #else 374 if (!strchr(p, '\n') && !feof(pvt->fp)) { 375 #endif 376 #define GROWBUF 1024 377 /* allocate space for longer line */ 378 if (dbuf == NULL) { 379 if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL) 380 strcpy(ndbuf, bufp); 381 } else 382 ndbuf = realloc(dbuf, bufsiz + GROWBUF); 383 if (ndbuf) { 384 dbuf = ndbuf; 385 bufp = dbuf; 386 bufsiz += GROWBUF; 387 offset = strlen(dbuf); 388 } else { 389 /* allocation failed; skip this long line */ 390 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 391 while ((c = __nsl_getc(pvt->fp)) != EOF) 392 #else 393 while ((c = getc(pvt->fp)) != EOF) 394 #endif 395 if (c == '\n') 396 break; 397 if (c != EOF) 398 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 399 __nsl_ungetc(c, pvt->fp); 400 #else 401 ungetc(c, pvt->fp); 402 #endif 403 } 404 goto again; 405 } 406 407 p -= offset; 408 offset = 0; 409 410 if (*p == '#') 411 goto again; 412 if ((cp = strpbrk(p, "#\n")) != NULL) 413 *cp = '\0'; 414 if (!(cp = strpbrk(p, " \t"))) 415 goto again; 416 *cp++ = '\0'; 417 if (inet_pton(AF_INET6, p, pvt->host_addr) > 0) { 418 af = AF_INET6; 419 len = IN6ADDRSZ; 420 } else if (inet_aton(p, (struct in_addr *)pvt->host_addr) > 0) { 421 if (pvt->res->options & RES_USE_INET6) { 422 map_v4v6_address((char*)pvt->host_addr, 423 (char*)pvt->host_addr); 424 af = AF_INET6; 425 len = IN6ADDRSZ; 426 } else { 427 af = AF_INET; 428 len = INADDRSZ; 429 } 430 } else { 431 goto again; 432 } 433 pvt->h_addr_ptrs[0] = (char *)pvt->host_addr; 434 pvt->h_addr_ptrs[1] = NULL; 435 pvt->host.h_addr_list = pvt->h_addr_ptrs; 436 pvt->host.h_length = len; 437 pvt->host.h_addrtype = af; 438 while (*cp == ' ' || *cp == '\t') 439 cp++; 440 pvt->host.h_name = cp; 441 q = pvt->host.h_aliases = pvt->host_aliases; 442 if ((cp = strpbrk(cp, " \t")) != NULL) 443 *cp++ = '\0'; 444 while (cp && *cp) { 445 if (*cp == ' ' || *cp == '\t') { 446 cp++; 447 continue; 448 } 449 if (q < &pvt->host_aliases[MAXALIASES - 1]) 450 *q++ = cp; 451 if ((cp = strpbrk(cp, " \t")) != NULL) 452 *cp++ = '\0'; 453 } 454 *q = NULL; 455 if (dbuf) 456 free(dbuf); 457 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); 458 return (&pvt->host); 459 } 460 461 static void 462 ho_rewind(struct irs_ho *this) { 463 struct pvt *pvt = (struct pvt *)this->private; 464 465 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 466 if (pvt->fp) { 467 if (__nsl_fseek(pvt->fp, 0L, SEEK_SET) == 0) 468 return; 469 (void)__nsl_fclose(pvt->fp); 470 } 471 if (!(pvt->fp = __nsl_fopen(_PATH_HOSTS, "r"))) 472 return; 473 if (fcntl(__nsl_fileno(pvt->fp), F_SETFD, 1) < 0) { 474 (void)__nsl_fclose(pvt->fp); 475 pvt->fp = NULL; 476 } 477 #else 478 if (pvt->fp) { 479 if (fseek(pvt->fp, 0L, SEEK_SET) == 0) 480 return; 481 (void)fclose(pvt->fp); 482 } 483 if (!(pvt->fp = fopen(_PATH_HOSTS, "r"))) 484 return; 485 if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { 486 (void)fclose(pvt->fp); 487 pvt->fp = NULL; 488 } 489 #endif 490 491 } 492 493 static void 494 ho_minimize(struct irs_ho *this) { 495 struct pvt *pvt = (struct pvt *)this->private; 496 497 if (pvt->fp != NULL) { 498 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 499 (void)__nsl_fclose(pvt->fp); 500 #else 501 (void)fclose(pvt->fp); 502 #endif 503 pvt->fp = NULL; 504 } 505 if (pvt->res) 506 res_nclose(pvt->res); 507 } 508 509 static struct __res_state * 510 ho_res_get(struct irs_ho *this) { 511 struct pvt *pvt = (struct pvt *)this->private; 512 513 if (!pvt->res) { 514 struct __res_state *res; 515 res = (struct __res_state *)malloc(sizeof *res); 516 if (!res) { 517 errno = ENOMEM; 518 return (NULL); 519 } 520 memset(res, 0, sizeof *res); 521 ho_res_set(this, res, free); 522 } 523 524 return (pvt->res); 525 } 526 527 static void 528 ho_res_set(struct irs_ho *this, struct __res_state *res, 529 void (*free_res)(void *)) { 530 struct pvt *pvt = (struct pvt *)this->private; 531 532 if (pvt->res && pvt->free_res) { 533 res_nclose(pvt->res); 534 (*pvt->free_res)(pvt->res); 535 } 536 537 pvt->res = res; 538 pvt->free_res = free_res; 539 } 540 541 struct lcl_res_target { 542 struct lcl_res_target *next; 543 int family; 544 }; 545 546 /* XXX */ 547 extern struct addrinfo *hostent2addrinfo __P((struct hostent *, 548 const struct addrinfo *pai)); 549 550 static struct addrinfo * 551 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) 552 { 553 struct pvt *pvt = (struct pvt *)this->private; 554 struct hostent *hp; 555 struct lcl_res_target q, q2, *p; 556 struct addrinfo sentinel, *cur; 557 558 memset(&q, 0, sizeof(q2)); 559 memset(&q2, 0, sizeof(q2)); 560 memset(&sentinel, 0, sizeof(sentinel)); 561 cur = &sentinel; 562 563 switch(pai->ai_family) { 564 case AF_UNSPEC: /* INET6 then INET4 */ 565 q.family = AF_INET6; 566 q.next = &q2; 567 q2.family = AF_INET; 568 break; 569 case AF_INET6: 570 q.family = AF_INET6; 571 break; 572 case AF_INET: 573 q.family = AF_INET; 574 break; 575 default: 576 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* ??? */ 577 return(NULL); 578 } 579 580 for (p = &q; p; p = p->next) { 581 struct addrinfo *ai; 582 583 hp = (*this->byname2)(this, name, p->family); 584 if (hp == NULL) { 585 /* byname2 should've set an appropriate error */ 586 continue; 587 } 588 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || 589 (hp->h_addr_list[0] == NULL)) { 590 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 591 continue; 592 } 593 594 ai = hostent2addrinfo(hp, pai); 595 if (ai) { 596 cur->ai_next = ai; 597 while (cur && cur->ai_next) 598 cur = cur->ai_next; 599 } 600 } 601 602 if (sentinel.ai_next == NULL) 603 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 604 605 return(sentinel.ai_next); 606 } 607 608 /* Private. */ 609 610 static size_t 611 ns_namelen(const char *s) { 612 int i; 613 614 for (i = strlen(s); i > 0 && s[i-1] == '.'; i--) 615 (void)NULL; 616 return ((size_t) i); 617 } 618 619 static int 620 init(struct irs_ho *this) { 621 struct pvt *pvt = (struct pvt *)this->private; 622 623 if (!pvt->res && !ho_res_get(this)) 624 return (-1); 625 if (((pvt->res->options & RES_INIT) == 0) && 626 res_ninit(pvt->res) == -1) 627 return (-1); 628 return (0); 629 } 630