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