Home | History | Annotate | Line # | Download | only in irs
lcl_ho.c revision 1.1.1.1.6.2
      1 /*	$NetBSD: lcl_ho.c,v 1.1.1.1.6.2 2011/01/09 20:42:55 riz 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