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