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