1 /* 2 * Copyright 2006 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 91 #include "irs_p.h" 92 #include "dns_p.h" 93 #include "lcl_p.h" 94 95 #ifdef SPRINTF_CHAR 96 # define SPRINTF(x) strlen(sprintf/**/x) 97 #else 98 # define SPRINTF(x) sprintf x 99 #endif 100 101 /* Definitions. */ 102 103 #define MAXALIASES 35 104 #define MAXADDRS 35 105 #define Max(a,b) ((a) > (b) ? (a) : (b)) 106 107 #if PACKETSZ > 1024 108 #define MAXPACKET PACKETSZ 109 #else 110 #define MAXPACKET 1024 111 #endif 112 113 struct pvt { 114 FILE * fp; 115 struct hostent host; 116 char * h_addr_ptrs[MAXADDRS + 1]; 117 char * host_aliases[MAXALIASES]; 118 char hostbuf[8*1024]; 119 u_char host_addr[16]; /* IPv4 or IPv6 */ 120 struct __res_state *res; 121 void (*free_res)(void *); 122 }; 123 124 typedef union { 125 int32_t al; 126 char ac; 127 } align; 128 129 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; 130 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; 131 132 /* Forward. */ 133 134 static void ho_close(struct irs_ho *this); 135 static struct hostent * ho_byname(struct irs_ho *this, const char *name); 136 static struct hostent * ho_byname2(struct irs_ho *this, const char *name, 137 int af); 138 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 139 int len, int af); 140 static struct hostent * ho_next(struct irs_ho *this); 141 static void ho_rewind(struct irs_ho *this); 142 static void ho_minimize(struct irs_ho *this); 143 static struct __res_state * ho_res_get(struct irs_ho *this); 144 static void ho_res_set(struct irs_ho *this, 145 struct __res_state *res, 146 void (*free_res)(void *)); 147 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, 148 const struct addrinfo *pai); 149 150 static size_t ns_namelen(const char *); 151 static int init(struct irs_ho *this); 152 153 /* Portability. */ 154 155 #ifndef SEEK_SET 156 # define SEEK_SET 0 157 #endif 158 159 /* Public. */ 160 161 struct irs_ho * 162 irs_lcl_ho(struct irs_acc *this) { 163 struct irs_ho *ho; 164 struct pvt *pvt; 165 166 UNUSED(this); 167 168 if (!(pvt = memget(sizeof *pvt))) { 169 errno = ENOMEM; 170 return (NULL); 171 } 172 memset(pvt, 0, sizeof *pvt); 173 if (!(ho = memget(sizeof *ho))) { 174 memput(pvt, sizeof *pvt); 175 errno = ENOMEM; 176 return (NULL); 177 } 178 memset(ho, 0x5e, sizeof *ho); 179 ho->private = pvt; 180 ho->close = ho_close; 181 ho->byname = ho_byname; 182 ho->byname2 = ho_byname2; 183 ho->byaddr = ho_byaddr; 184 ho->next = ho_next; 185 ho->rewind = ho_rewind; 186 ho->minimize = ho_minimize; 187 ho->res_get = ho_res_get; 188 ho->res_set = ho_res_set; 189 ho->addrinfo = ho_addrinfo; 190 return (ho); 191 } 192 193 /* Methods. */ 194 195 static void 196 ho_close(struct irs_ho *this) { 197 struct pvt *pvt = (struct pvt *)this->private; 198 199 ho_minimize(this); 200 if (pvt->fp) 201 (void) fclose(pvt->fp); 202 if (pvt->res && pvt->free_res) 203 (*pvt->free_res)(pvt->res); 204 memput(pvt, sizeof *pvt); 205 memput(this, sizeof *this); 206 } 207 208 static struct hostent * 209 ho_byname(struct irs_ho *this, const char *name) { 210 struct pvt *pvt = (struct pvt *)this->private; 211 struct hostent *hp; 212 213 if (init(this) == -1) 214 return (NULL); 215 216 if (pvt->res->options & RES_USE_INET6) { 217 hp = ho_byname2(this, name, AF_INET6); 218 if (hp) 219 return (hp); 220 } 221 return (ho_byname2(this, name, AF_INET)); 222 } 223 224 static struct hostent * 225 ho_byname2(struct irs_ho *this, const char *name, int af) { 226 struct pvt *pvt = (struct pvt *)this->private; 227 struct hostent *hp; 228 char **hap; 229 size_t n; 230 231 if (init(this) == -1) 232 return (NULL); 233 234 ho_rewind(this); 235 n = ns_namelen(name); 236 while ((hp = ho_next(this)) != NULL) { 237 size_t nn; 238 239 if (hp->h_addrtype != af) 240 continue; 241 nn = ns_namelen(hp->h_name); 242 if (strncasecmp(hp->h_name, name, Max(n, nn)) == 0) 243 goto found; 244 for (hap = hp->h_aliases; *hap; hap++) { 245 nn = ns_namelen(*hap); 246 if (strncasecmp(*hap, name, Max(n, nn)) == 0) 247 goto found; 248 } 249 } 250 found: 251 if (!hp) { 252 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 253 return (NULL); 254 } 255 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); 256 return (hp); 257 } 258 259 static struct hostent * 260 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { 261 struct pvt *pvt = (struct pvt *)this->private; 262 const u_char *uaddr = addr; 263 struct hostent *hp; 264 int size; 265 266 if (init(this) == -1) 267 return (NULL); 268 269 if (af == AF_INET6 && len == IN6ADDRSZ && 270 (!memcmp(uaddr, mapped, sizeof mapped) || 271 !memcmp(uaddr, tunnelled, sizeof tunnelled))) { 272 /* Unmap. */ 273 addr = (const u_char *)addr + sizeof mapped; 274 uaddr += sizeof mapped; 275 af = AF_INET; 276 len = INADDRSZ; 277 } 278 switch (af) { 279 case AF_INET: 280 size = INADDRSZ; 281 break; 282 case AF_INET6: 283 size = IN6ADDRSZ; 284 break; 285 default: 286 errno = EAFNOSUPPORT; 287 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 288 return (NULL); 289 } 290 if (size > len) { 291 errno = EINVAL; 292 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 293 return (NULL); 294 } 295 296 /* 297 * Do the search. 298 */ 299 ho_rewind(this); 300 while ((hp = ho_next(this)) != NULL) { 301 char **hap; 302 303 for (hap = hp->h_addr_list; *hap; hap++) { 304 const u_char *taddr = (const u_char *)*hap; 305 int taf = hp->h_addrtype; 306 int tlen = hp->h_length; 307 308 if (taf == AF_INET6 && tlen == IN6ADDRSZ && 309 (!memcmp(taddr, mapped, sizeof mapped) || 310 !memcmp(taddr, tunnelled, sizeof tunnelled))) { 311 /* Unmap. */ 312 taddr += sizeof mapped; 313 taf = AF_INET; 314 tlen = INADDRSZ; 315 } 316 if (taf == af && tlen == len && 317 !memcmp(taddr, uaddr, tlen)) 318 goto found; 319 } 320 } 321 found: 322 if (!hp) { 323 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 324 return (NULL); 325 } 326 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); 327 return (hp); 328 } 329 330 static struct hostent * 331 ho_next(struct irs_ho *this) { 332 struct pvt *pvt = (struct pvt *)this->private; 333 char *cp, **q, *p; 334 char *bufp, *ndbuf, *dbuf = NULL; 335 int c, af, len, bufsiz, offset; 336 337 if (init(this) == -1) 338 return (NULL); 339 340 if (!pvt->fp) 341 ho_rewind(this); 342 if (!pvt->fp) { 343 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 344 return (NULL); 345 } 346 bufp = pvt->hostbuf; 347 bufsiz = sizeof pvt->hostbuf; 348 offset = 0; 349 again: 350 if (!(p = fgets(bufp + offset, bufsiz - offset, pvt->fp))) { 351 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 352 if (dbuf) 353 free(dbuf); 354 return (NULL); 355 } 356 if (!strchr(p, '\n') && !feof(pvt->fp)) { 357 #define GROWBUF 1024 358 /* allocate space for longer line */ 359 if (dbuf == NULL) { 360 if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL) 361 strcpy(ndbuf, bufp); 362 } else 363 ndbuf = realloc(dbuf, bufsiz + GROWBUF); 364 if (ndbuf) { 365 dbuf = ndbuf; 366 bufp = dbuf; 367 bufsiz += GROWBUF; 368 offset = strlen(dbuf); 369 } else { 370 /* allocation failed; skip this long line */ 371 while ((c = getc(pvt->fp)) != EOF) 372 if (c == '\n') 373 break; 374 if (c != EOF) 375 ungetc(c, pvt->fp); 376 } 377 goto again; 378 } 379 380 p -= offset; 381 offset = 0; 382 383 if (*p == '#') 384 goto again; 385 if ((cp = strpbrk(p, "#\n")) != NULL) 386 *cp = '\0'; 387 if (!(cp = strpbrk(p, " \t"))) 388 goto again; 389 *cp++ = '\0'; 390 if (inet_pton(AF_INET6, p, pvt->host_addr) > 0) { 391 af = AF_INET6; 392 len = IN6ADDRSZ; 393 } else if (inet_aton(p, (struct in_addr *)pvt->host_addr) > 0) { 394 if (pvt->res->options & RES_USE_INET6) { 395 map_v4v6_address((char*)pvt->host_addr, 396 (char*)pvt->host_addr); 397 af = AF_INET6; 398 len = IN6ADDRSZ; 399 } else { 400 af = AF_INET; 401 len = INADDRSZ; 402 } 403 } else { 404 goto again; 405 } 406 pvt->h_addr_ptrs[0] = (char *)pvt->host_addr; 407 pvt->h_addr_ptrs[1] = NULL; 408 pvt->host.h_addr_list = pvt->h_addr_ptrs; 409 pvt->host.h_length = len; 410 pvt->host.h_addrtype = af; 411 while (*cp == ' ' || *cp == '\t') 412 cp++; 413 pvt->host.h_name = cp; 414 q = pvt->host.h_aliases = pvt->host_aliases; 415 if ((cp = strpbrk(cp, " \t")) != NULL) 416 *cp++ = '\0'; 417 while (cp && *cp) { 418 if (*cp == ' ' || *cp == '\t') { 419 cp++; 420 continue; 421 } 422 if (q < &pvt->host_aliases[MAXALIASES - 1]) 423 *q++ = cp; 424 if ((cp = strpbrk(cp, " \t")) != NULL) 425 *cp++ = '\0'; 426 } 427 *q = NULL; 428 if (dbuf) 429 free(dbuf); 430 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); 431 return (&pvt->host); 432 } 433 434 static void 435 ho_rewind(struct irs_ho *this) { 436 struct pvt *pvt = (struct pvt *)this->private; 437 438 if (pvt->fp) { 439 if (fseek(pvt->fp, 0L, SEEK_SET) == 0) 440 return; 441 (void)fclose(pvt->fp); 442 } 443 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 444 if (!(pvt->fp = fopen(_PATH_HOSTS, "rF"))) 445 #else 446 if (!(pvt->fp = fopen(_PATH_HOSTS, "r"))) 447 #endif 448 return; 449 if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { 450 (void)fclose(pvt->fp); 451 pvt->fp = NULL; 452 } 453 } 454 455 static void 456 ho_minimize(struct irs_ho *this) { 457 struct pvt *pvt = (struct pvt *)this->private; 458 459 if (pvt->fp != NULL) { 460 (void)fclose(pvt->fp); 461 pvt->fp = NULL; 462 } 463 if (pvt->res) 464 res_nclose(pvt->res); 465 } 466 467 static struct __res_state * 468 ho_res_get(struct irs_ho *this) { 469 struct pvt *pvt = (struct pvt *)this->private; 470 471 if (!pvt->res) { 472 struct __res_state *res; 473 res = (struct __res_state *)malloc(sizeof *res); 474 if (!res) { 475 errno = ENOMEM; 476 return (NULL); 477 } 478 memset(res, 0, sizeof *res); 479 ho_res_set(this, res, free); 480 } 481 482 return (pvt->res); 483 } 484 485 static void 486 ho_res_set(struct irs_ho *this, struct __res_state *res, 487 void (*free_res)(void *)) { 488 struct pvt *pvt = (struct pvt *)this->private; 489 490 if (pvt->res && pvt->free_res) { 491 res_nclose(pvt->res); 492 (*pvt->free_res)(pvt->res); 493 } 494 495 pvt->res = res; 496 pvt->free_res = free_res; 497 } 498 499 struct lcl_res_target { 500 struct lcl_res_target *next; 501 int family; 502 }; 503 504 /* XXX */ 505 extern struct addrinfo *hostent2addrinfo __P((struct hostent *, 506 const struct addrinfo *pai)); 507 508 static struct addrinfo * 509 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) 510 { 511 struct pvt *pvt = (struct pvt *)this->private; 512 struct hostent *hp; 513 struct lcl_res_target q, q2, *p; 514 struct addrinfo sentinel, *cur; 515 516 memset(&q, 0, sizeof(q2)); 517 memset(&q2, 0, sizeof(q2)); 518 memset(&sentinel, 0, sizeof(sentinel)); 519 cur = &sentinel; 520 521 switch(pai->ai_family) { 522 case AF_UNSPEC: /* INET6 then INET4 */ 523 q.family = AF_INET6; 524 q.next = &q2; 525 q2.family = AF_INET; 526 break; 527 case AF_INET6: 528 q.family = AF_INET6; 529 break; 530 case AF_INET: 531 q.family = AF_INET; 532 break; 533 default: 534 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* ??? */ 535 return(NULL); 536 } 537 538 for (p = &q; p; p = p->next) { 539 struct addrinfo *ai; 540 541 hp = (*this->byname2)(this, name, p->family); 542 if (hp == NULL) { 543 /* byname2 should've set an appropriate error */ 544 continue; 545 } 546 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || 547 (hp->h_addr_list[0] == NULL)) { 548 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 549 continue; 550 } 551 552 ai = hostent2addrinfo(hp, pai); 553 if (ai) { 554 cur->ai_next = ai; 555 while (cur && cur->ai_next) 556 cur = cur->ai_next; 557 } 558 } 559 560 if (sentinel.ai_next == NULL) 561 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 562 563 return(sentinel.ai_next); 564 } 565 566 /* Private. */ 567 568 static size_t 569 ns_namelen(const char *s) { 570 int i; 571 572 for (i = strlen(s); i > 0 && s[i-1] == '.'; i--) 573 (void)NULL; 574 return ((size_t) i); 575 } 576 577 static int 578 init(struct irs_ho *this) { 579 struct pvt *pvt = (struct pvt *)this->private; 580 581 if (!pvt->res && !ho_res_get(this)) 582 return (-1); 583 if (((pvt->res->options & RES_INIT) == 0) && 584 res_ninit(pvt->res) == -1) 585 return (-1); 586 return (0); 587 } 588