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