xref: /freebsd/lib/libc/net/name6.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
3  * 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. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 /* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */
32 /*
33  *	Atsushi Onoe <onoe@sm.sony.co.jp>
34  */
35 
36 /*
37  * TODO for thread safe
38  *	use mutex for _hostconf, _hostconf_init.
39  *	rewrite resolvers to be thread safe
40  */
41 
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 #include <netinet/in.h>
46 
47 #include <arpa/inet.h>
48 #include <arpa/nameser.h>
49 
50 #include <netdb.h>
51 #include <resolv.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #ifndef _PATH_HOSTS
58 #define	_PATH_HOSTS	"/etc/hosts"
59 #endif
60 
61 #ifndef MAXALIASES
62 #define	MAXALIASES	10
63 #endif
64 #ifndef	MAXADDRS
65 #define	MAXADDRS	20
66 #endif
67 #ifndef MAXDNAME
68 #define	MAXDNAME	1025
69 #endif
70 
71 #ifdef INET6
72 #define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
73 					    sizeof(struct in_addr))
74 #else
75 #define	ADDRLEN(af)	sizeof(struct in_addr)
76 #endif
77 
78 #define	MAPADDR(ab, ina) \
79 do {									\
80 	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
81 	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
82 	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
83 } while (0)
84 #define	MAPADDRENABLED(flags) \
85 	(((flags) & AI_V4MAPPED) || \
86 	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
87 
88 union inx_addr {
89 	struct in_addr	in_addr;
90 #ifdef INET6
91 	struct in6_addr	in6_addr;
92 #endif
93 	struct {
94 		u_char	mau_zero[10];
95 		u_char	mau_one[2];
96 		struct in_addr mau_inaddr;
97 	}		map_addr_un;
98 #define	map_zero	map_addr_un.mau_zero
99 #define	map_one		map_addr_un.mau_one
100 #define	map_inaddr	map_addr_un.mau_inaddr
101 };
102 
103 static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
104 static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
105 static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
106 #ifdef INET6
107 static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
108 #endif
109 static struct	 hostent *_hpsort(struct hostent *hp);
110 static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
111 static char	*_hgetword(char **pp);
112 static int	 _mapped_addr_enabled(void);
113 
114 static FILE	*_files_open(int *errp);
115 static struct	 hostent *_files_ghbyname(const char *name, int af, int *errp);
116 static struct	 hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
117 static void	 _files_shent(int stayopen);
118 static void	 _files_ehent(void);
119 static struct	 hostent *_dns_ghbyname(const char *name, int af, int *errp);
120 static struct	 hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
121 static void	 _dns_shent(int stayopen);
122 static void	 _dns_ehent(void);
123 #ifdef ICMPNL
124 static struct	 hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
125 #endif /* ICMPNL */
126 
127 /*
128  * Select order host function.
129  */
130 #define	MAXHOSTCONF	4
131 
132 #ifndef HOSTCONF
133 #  define	HOSTCONF	"/etc/host.conf"
134 #endif /* !HOSTCONF */
135 
136 struct _hostconf {
137 	struct hostent *(*byname)(const char *name, int af, int *errp);
138 	struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
139 };
140 
141 /* default order */
142 static struct _hostconf _hostconf[MAXHOSTCONF] = {
143 	{ _dns_ghbyname,	_dns_ghbyaddr },
144 	{ _files_ghbyname,	_files_ghbyaddr },
145 #ifdef ICMPNL
146 	{ NULL,			_icmp_ghbyaddr },
147 #endif /* ICMPNL */
148 };
149 
150 static int	_hostconf_init_done;
151 static void	_hostconf_init(void);
152 
153 /*
154  * Initialize hostconf structure.
155  */
156 
157 static void
158 _hostconf_init(void)
159 {
160 	FILE *fp;
161 	int n;
162 	char *p, *line;
163 	char buf[BUFSIZ];
164 
165 	_hostconf_init_done = 1;
166 	n = 0;
167 	p = HOSTCONF;
168 	if ((fp = fopen(p, "r")) == NULL)
169 		return;
170 	while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
171 		line = buf;
172 		if ((p = _hgetword(&line)) == NULL)
173 			continue;
174 		do {
175 			if (strcmp(p, "hosts") == 0
176 			||  strcmp(p, "local") == 0
177 			||  strcmp(p, "file") == 0
178 			||  strcmp(p, "files") == 0) {
179 				_hostconf[n].byname = _files_ghbyname;
180 				_hostconf[n].byaddr = _files_ghbyaddr;
181 				n++;
182 			}
183 			else if (strcmp(p, "dns") == 0
184 			     ||  strcmp(p, "bind") == 0) {
185 				_hostconf[n].byname = _dns_ghbyname;
186 				_hostconf[n].byaddr = _dns_ghbyaddr;
187 				n++;
188 			}
189 #ifdef ICMPNL
190 			else if (strcmp(p, "icmp") == 0) {
191 				_hostconf[n].byname = NULL;
192 				_hostconf[n].byaddr = _icmp_ghbyaddr;
193 				n++;
194 			}
195 #endif /* ICMPNL */
196 		} while ((p = _hgetword(&line)) != NULL);
197 	}
198 	fclose(fp);
199 	if (n < 0) {
200 		/* no keyword found. do not change default configuration */
201 		return;
202 	}
203 	for (; n < MAXHOSTCONF; n++) {
204 		_hostconf[n].byname = NULL;
205 		_hostconf[n].byaddr = NULL;
206 	}
207 }
208 
209 /*
210  * Check if kernel supports mapped address.
211  *	implementation dependent
212  */
213 #ifdef __KAME__
214 #include <sys/sysctl.h>
215 #endif /* __KAME__ */
216 
217 static int
218 _mapped_addr_enabled(void)
219 {
220 	/* implementation dependent check */
221 #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
222 	int mib[4];
223 	size_t len;
224 	int val;
225 
226 	mib[0] = CTL_NET;
227 	mib[1] = PF_INET6;
228 	mib[2] = IPPROTO_IPV6;
229 	mib[3] = IPV6CTL_MAPPED_ADDR;
230 	len = sizeof(val);
231 	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
232 		return 1;
233 #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
234 	return 0;
235 }
236 
237 /*
238  * Functions defined in RFC2553
239  *	getipnodebyname, getipnodebyadr, freehostent
240  */
241 
242 static struct hostent *
243 _ghbyname(const char *name, int af, int flags, int *errp)
244 {
245 	struct hostent *hp;
246 	int i;
247 
248 	if (flags & AI_ADDRCONFIG) {
249 		int s;
250 
251 		if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
252 			return NULL;
253 		/*
254 		 * TODO:
255 		 * Note that implementation dependent test for address
256 		 * configuration should be done everytime called
257 		 * (or apropriate interval),
258 		 * because addresses will be dynamically assigned or deleted.
259 		 */
260 		_close(s);
261 	}
262 
263 	for (i = 0; i < MAXHOSTCONF; i++) {
264 		if (_hostconf[i].byname
265 		&&  (hp = (*_hostconf[i].byname)(name, af, errp))
266 		    != NULL)
267 			return hp;
268 	}
269 
270 	return NULL;
271 }
272 
273 struct hostent *
274 getipnodebyname(const char *name, int af, int flags, int *errp)
275 {
276 	struct hostent *hp;
277 	union inx_addr addrbuf;
278 
279 	if (af != AF_INET
280 #ifdef INET6
281 	    && af != AF_INET6
282 #endif
283 		)
284 	{
285 		*errp = NO_RECOVERY;
286 		return NULL;
287 	}
288 
289 #ifdef INET6
290 	/* special case for literal address */
291 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
292 		if (af != AF_INET6) {
293 			*errp = HOST_NOT_FOUND;
294 			return NULL;
295 		}
296 		return _hpaddr(af, name, &addrbuf, errp);
297 	}
298 #endif
299 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
300 		if (af != AF_INET) {
301 			if (MAPADDRENABLED(flags)) {
302 				MAPADDR(&addrbuf, &addrbuf.in_addr);
303 			} else {
304 				*errp = HOST_NOT_FOUND;
305 				return NULL;
306 			}
307 		}
308 		return _hpaddr(af, name, &addrbuf, errp);
309 	}
310 
311 	if (!_hostconf_init_done)
312 		_hostconf_init();
313 
314 	*errp = HOST_NOT_FOUND;
315 	hp = _ghbyname(name, af, flags, errp);
316 
317 #ifdef INET6
318 	if (af == AF_INET6
319 	&&  ((flags & AI_ALL) || hp == NULL)
320 	&&  (MAPADDRENABLED(flags))) {
321 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
322 		if (hp == NULL)
323 			hp = _hpmapv6(hp2, errp);
324 		else {
325 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
326 				freehostent(hp2);
327 				hp2 = NULL;
328 			}
329 			hp = _hpmerge(hp, hp2, errp);
330 		}
331 	}
332 #endif
333 	return _hpsort(hp);
334 }
335 
336 struct hostent *
337 getipnodebyaddr(const void *src, size_t len, int af, int *errp)
338 {
339 	struct hostent *hp;
340 	int i;
341 #ifdef INET6
342 	struct in6_addr addrbuf;
343 #else
344 	struct in_addr addrbuf;
345 #endif
346 
347 	*errp = HOST_NOT_FOUND;
348 
349 	switch (af) {
350 	case AF_INET:
351 		if (len != sizeof(struct in_addr)) {
352 			*errp = NO_RECOVERY;
353 			return NULL;
354 		}
355 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
356 			memcpy(&addrbuf, src, len);
357 			src = &addrbuf;
358 		}
359 		if (((struct in_addr *)src)->s_addr == 0)
360 			return NULL;
361 		break;
362 #ifdef INET6
363 	case AF_INET6:
364 		if (len != sizeof(struct in6_addr)) {
365 			*errp = NO_RECOVERY;
366 			return NULL;
367 		}
368 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
369 			memcpy(&addrbuf, src, len);
370 			src = &addrbuf;
371 		}
372 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
373 			return NULL;
374 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
375 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
376 			src = (char *)src +
377 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
378 			af = AF_INET;
379 			len = sizeof(struct in_addr);
380 		}
381 		break;
382 #endif
383 	default:
384 		*errp = NO_RECOVERY;
385 		return NULL;
386 	}
387 
388 	if (!_hostconf_init_done)
389 		_hostconf_init();
390 	for (i = 0; i < MAXHOSTCONF; i++) {
391 		if (_hostconf[i].byaddr
392 		&&  (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
393 			return hp;
394 	}
395 
396 	return NULL;
397 }
398 
399 void
400 freehostent(struct hostent *ptr)
401 {
402 	free(ptr);
403 }
404 
405 #if 0
406 
407 /* XXX: should be deprecated */
408 struct hostent *
409 getnodebyname(const char *name, int af, int flags)
410 {
411 	return getipnodebyname(name, af, flags, &h_errno);
412 }
413 
414 #ifdef __warn_references
415 __warn_references(getnodebyname,
416 	"warning: getnodebyname() deprecated, "
417 	"should use getaddrinfo() or getipnodebyname()");
418 #endif
419 
420 struct hostent *
421 getnodebyaddr(const void *src, size_t len, int af)
422 {
423 	return getipnodebyaddr(src, len, af, &h_errno);
424 }
425 
426 #ifdef __warn_references
427 __warn_references(getnodebyaddr,
428 	"warning: getnodebyaddr() deprecated, "
429 	"should use getnameinfo() or getipnodebyaddr()");
430 #endif
431 
432 #endif
433 
434 /*
435  * Private utility functions
436  */
437 
438 /*
439  * _hpcopy: allocate and copy hostent structure
440  */
441 static struct hostent *
442 _hpcopy(struct hostent *hp, int *errp)
443 {
444 	struct hostent *nhp;
445 	char *cp, **pp;
446 	int size, addrsize;
447 	int nalias = 0, naddr = 0;
448 	int al_off;
449 	int i;
450 
451 	if (hp == NULL)
452 		return hp;
453 
454 	/* count size to be allocated */
455 	size = sizeof(struct hostent);
456 	if (hp->h_name != NULL && *hp->h_name != '\0')
457 		size += strlen(hp->h_name) + 1;
458 	if ((pp = hp->h_aliases) != NULL) {
459 		for (i = 0; *pp != NULL; i++, pp++) {
460 			if (**pp != '\0') {
461 				size += strlen(*pp) + 1;
462 				nalias++;
463 			}
464 		}
465 	}
466 	/* adjust alignment */
467 	size = ALIGN(size);
468 	al_off = size;
469 	size += sizeof(char *) * (nalias + 1);
470 	addrsize = ALIGN(hp->h_length);
471 	if ((pp = hp->h_addr_list) != NULL) {
472 		while (*pp++ != NULL)
473 			naddr++;
474 	}
475 	size += addrsize * naddr;
476 	size += sizeof(char *) * (naddr + 1);
477 
478 	/* copy */
479 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
480 		*errp = TRY_AGAIN;
481 		return NULL;
482 	}
483 	cp = (char *)&nhp[1];
484 	if (hp->h_name != NULL && *hp->h_name != '\0') {
485 		nhp->h_name = cp;
486 		strcpy(cp, hp->h_name);
487 		cp += strlen(cp) + 1;
488 	} else
489 		nhp->h_name = NULL;
490 	nhp->h_aliases = (char **)((char *)nhp + al_off);
491 	if ((pp = hp->h_aliases) != NULL) {
492 		for (i = 0; *pp != NULL; pp++) {
493 			if (**pp != '\0') {
494 				nhp->h_aliases[i++] = cp;
495 				strcpy(cp, *pp);
496 				cp += strlen(cp) + 1;
497 			}
498 		}
499 	}
500 	nhp->h_aliases[nalias] = NULL;
501 	cp = (char *)&nhp->h_aliases[nalias + 1];
502 	nhp->h_addrtype = hp->h_addrtype;
503 	nhp->h_length = hp->h_length;
504 	nhp->h_addr_list = (char **)cp;
505 	if ((pp = hp->h_addr_list) != NULL) {
506 		cp = (char *)&nhp->h_addr_list[naddr + 1];
507 		for (i = 0; *pp != NULL; pp++) {
508 			nhp->h_addr_list[i++] = cp;
509 			memcpy(cp, *pp, hp->h_length);
510 			cp += addrsize;
511 		}
512 	}
513 	nhp->h_addr_list[naddr] = NULL;
514 	return nhp;
515 }
516 
517 /*
518  * _hpaddr: construct hostent structure with one address
519  */
520 static struct hostent *
521 _hpaddr(int af, const char *name, void *addr, int *errp)
522 {
523 	struct hostent *hp, hpbuf;
524 	char *addrs[2];
525 
526 	hp = &hpbuf;
527 	hp->h_name = (char *)name;
528 	hp->h_aliases = NULL;
529 	hp->h_addrtype = af;
530 	hp->h_length = ADDRLEN(af);
531 	hp->h_addr_list = addrs;
532 	addrs[0] = (char *)addr;
533 	addrs[1] = NULL;
534 	return _hpcopy(hp, errp);
535 }
536 
537 /*
538  * _hpmerge: merge 2 hostent structure, arguments will be freed
539  */
540 static struct hostent *
541 _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
542 {
543 	int i, j;
544 	int naddr, nalias;
545 	char **pp;
546 	struct hostent *hp, hpbuf;
547 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
548 	union inx_addr addrbuf[MAXADDRS];
549 
550 	if (hp1 == NULL)
551 		return hp2;
552 	if (hp2 == NULL)
553 		return hp1;
554 
555 #define	HP(i)	(i == 1 ? hp1 : hp2)
556 	hp = &hpbuf;
557 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
558 	hp->h_aliases = aliases;
559 	nalias = 0;
560 	for (i = 1; i <= 2; i++) {
561 		if ((pp = HP(i)->h_aliases) == NULL)
562 			continue;
563 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
564 			/* check duplicates */
565 			for (j = 0; j < nalias; j++)
566 				if (strcasecmp(*pp, aliases[j]) == 0)
567 					break;
568 			if (j == nalias)
569 				aliases[nalias++] = *pp;
570 		}
571 	}
572 	aliases[nalias] = NULL;
573 #ifdef INET6
574 	if (hp1->h_length != hp2->h_length) {
575 		hp->h_addrtype = AF_INET6;
576 		hp->h_length = sizeof(struct in6_addr);
577 	} else {
578 #endif
579 		hp->h_addrtype = hp1->h_addrtype;
580 		hp->h_length = hp1->h_length;
581 #ifdef INET6
582 	}
583 #endif
584 	hp->h_addr_list = addrs;
585 	naddr = 0;
586 	for (i = 1; i <= 2; i++) {
587 		if ((pp = HP(i)->h_addr_list) == NULL)
588 			continue;
589 		if (HP(i)->h_length == hp->h_length) {
590 			while (naddr < MAXADDRS && *pp != NULL)
591 				addrs[naddr++] = *pp++;
592 		} else {
593 			/* copy IPv4 addr as mapped IPv6 addr */
594 			while (naddr < MAXADDRS && *pp != NULL) {
595 				MAPADDR(&addrbuf[naddr], *pp++);
596 				addrs[naddr] = (char *)&addrbuf[naddr];
597 				naddr++;
598 			}
599 		}
600 	}
601 	addrs[naddr] = NULL;
602 	hp = _hpcopy(hp, errp);
603 	freehostent(hp1);
604 	freehostent(hp2);
605 	return hp;
606 }
607 
608 /*
609  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
610  */
611 #ifdef INET6
612 static struct hostent *
613 _hpmapv6(struct hostent *hp, int *errp)
614 {
615 	struct hostent *hp6;
616 
617 	if (hp == NULL)
618 		return NULL;
619 	if (hp->h_addrtype == AF_INET6)
620 		return hp;
621 
622 	/* make dummy hostent to convert IPv6 address */
623 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
624 		*errp = TRY_AGAIN;
625 		return NULL;
626 	}
627 	hp6->h_name = NULL;
628 	hp6->h_aliases = NULL;
629 	hp6->h_addrtype = AF_INET6;
630 	hp6->h_length = sizeof(struct in6_addr);
631 	hp6->h_addr_list = NULL;
632 	return _hpmerge(hp6, hp, errp);
633 }
634 #endif
635 
636 /*
637  * _hpsort: sort address by sortlist
638  */
639 static struct hostent *
640 _hpsort(struct hostent *hp)
641 {
642 	int i, j, n;
643 	u_char *ap, *sp, *mp, **pp;
644 	char t;
645 	char order[MAXADDRS];
646 	int nsort = _res.nsort;
647 
648 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
649 		return hp;
650 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
651 		for (j = 0; j < nsort; j++) {
652 #ifdef INET6
653 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
654 				continue;
655 			sp = (u_char *)&_res_ext.sort_list[j].addr;
656 			mp = (u_char *)&_res_ext.sort_list[j].mask;
657 #else
658 			sp = (u_char *)&_res.sort_list[j].addr;
659 			mp = (u_char *)&_res.sort_list[j].mask;
660 #endif
661 			for (n = 0; n < hp->h_length; n++) {
662 				if ((ap[n] & mp[n]) != sp[n])
663 					break;
664 			}
665 			if (n == hp->h_length)
666 				break;
667 		}
668 		order[i] = j;
669 	}
670 	n = i;
671 	pp = (u_char **)hp->h_addr_list;
672 	for (i = 0; i < n - 1; i++) {
673 		for (j = i + 1; j < n; j++) {
674 			if (order[i] > order[j]) {
675 				ap = pp[i];
676 				pp[i] = pp[j];
677 				pp[j] = ap;
678 				t = order[i];
679 				order[i] = order[j];
680 				order[j] = t;
681 			}
682 		}
683 	}
684 	return hp;
685 }
686 
687 static char *
688 _hgetword(char **pp)
689 {
690 	char c, *p, *ret;
691 	const char *sp;
692 	static const char sep[] = "# \t\n";
693 
694 	ret = NULL;
695 	for (p = *pp; (c = *p) != '\0'; p++) {
696 		for (sp = sep; *sp != '\0'; sp++) {
697 			if (c == *sp)
698 				break;
699 		}
700 		if (c == '#')
701 			p[1] = '\0';	/* ignore rest of line */
702 		if (ret == NULL) {
703 			if (*sp == '\0')
704 				ret = p;
705 		} else {
706 			if (*sp != '\0') {
707 				*p++ = '\0';
708 				break;
709 			}
710 		}
711 	}
712 	*pp = p;
713 	if (ret == NULL || *ret == '\0')
714 		return NULL;
715 	return ret;
716 }
717 
718 /*
719  * FILES (/etc/hosts)
720  */
721 
722 static FILE *
723 _files_open(int *errp)
724 {
725 	FILE *fp;
726 	fp = fopen(_PATH_HOSTS, "r");
727 	if (fp == NULL)
728 		*errp = NO_RECOVERY;
729 	return fp;
730 }
731 
732 static struct hostent *
733 _files_ghbyname(const char *name, int af, int *errp)
734 {
735 	int match, nalias;
736 	char *p, *line, *addrstr, *cname;
737 	FILE *fp;
738 	struct hostent *rethp, *hp, hpbuf;
739 	char *aliases[MAXALIASES + 1], *addrs[2];
740 	union inx_addr addrbuf;
741 	char buf[BUFSIZ];
742 
743 	if ((fp = _files_open(errp)) == NULL)
744 		return NULL;
745 	rethp = hp = NULL;
746 
747 	while (fgets(buf, sizeof(buf), fp)) {
748 		line = buf;
749 		if ((addrstr = _hgetword(&line)) == NULL
750 		||  (cname = _hgetword(&line)) == NULL)
751 			continue;
752 		match = (strcasecmp(cname, name) == 0);
753 		nalias = 0;
754 		while ((p = _hgetword(&line)) != NULL) {
755 			if (!match)
756 				match = (strcasecmp(p, name) == 0);
757 			if (nalias < MAXALIASES)
758 				aliases[nalias++] = p;
759 		}
760 		if (!match)
761 			continue;
762 		if ((af == AF_INET
763 		     ? inet_aton(addrstr, (struct in_addr *)&addrbuf)
764 		     : inet_pton(af, addrstr, &addrbuf)) != 1) {
765 			*errp = NO_DATA;	/* name found */
766 			continue;
767 		}
768 		hp = &hpbuf;
769 		hp->h_name = cname;
770 		hp->h_aliases = aliases;
771 		aliases[nalias] = NULL;
772 		hp->h_addrtype = af;
773 		hp->h_length = ADDRLEN(af);
774 		hp->h_addr_list = addrs;
775 		addrs[0] = (char *)&addrbuf;
776 		addrs[1] = NULL;
777 		hp = _hpcopy(hp, errp);
778 		rethp = _hpmerge(rethp, hp, errp);
779 	}
780 	fclose(fp);
781 	return rethp;
782 }
783 
784 static struct hostent *
785 _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
786 {
787 	int nalias;
788 	char *p, *line;
789 	FILE *fp;
790 	struct hostent *hp, hpbuf;
791 	char *aliases[MAXALIASES + 1], *addrs[2];
792 	union inx_addr addrbuf;
793 	char buf[BUFSIZ];
794 
795 	if ((fp = _files_open(errp)) == NULL)
796 		return NULL;
797 	hp = NULL;
798 	while (fgets(buf, sizeof(buf), fp)) {
799 		line = buf;
800 		if ((p = _hgetword(&line)) == NULL
801 		||  (af == AF_INET
802 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
803 		     : inet_pton(af, p, &addrbuf)) != 1
804 		||  memcmp(addr, &addrbuf, addrlen) != 0
805 		||  (p = _hgetword(&line)) == NULL)
806 			continue;
807 		hp = &hpbuf;
808 		hp->h_name = p;
809 		hp->h_aliases = aliases;
810 		nalias = 0;
811 		while ((p = _hgetword(&line)) != NULL) {
812 			if (nalias < MAXALIASES)
813 				aliases[nalias++] = p;
814 		}
815 		aliases[nalias] = NULL;
816 		hp->h_addrtype = af;
817 		hp->h_length = addrlen;
818 		hp->h_addr_list = addrs;
819 		addrs[0] = (char *)&addrbuf;
820 		addrs[1] = NULL;
821 		hp = _hpcopy(hp, errp);
822 		break;
823 	}
824 	fclose(fp);
825 	return hp;
826 }
827 
828 #ifdef DEBUG
829 #define	DNS_ASSERT(X)	if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
830 #else
831 #define	DNS_ASSERT(X)	if (!(X)) { goto badanswer; }
832 #endif
833 
834 static struct hostent *
835 _dns_ghbyname(const char *name, int af, int *errp)
836 {
837 	int n;
838 	u_char answer[BUFSIZ];
839 	char tbuf[MAXDNAME+1];
840 	HEADER *hp;
841 	u_char *cp, *eom;
842 	int qtype;
843 	int type, class, ancount, qdcount;
844 	u_long ttl;
845 	char hostbuf[BUFSIZ];
846 	char *bp;
847 	char *alist[MAXALIASES];
848 	char *hlist[MAXADDRS];
849 	struct hostent hbuf;
850 	int buflen;
851 	int na, nh;
852 
853 	if ((_res.options & RES_INIT) == 0) {
854 		if (res_init() < 0) {
855 			*errp = h_errno;
856 			return NULL;
857 		}
858 	}
859 	hbuf.h_aliases = alist;
860 	hbuf.h_addrtype = af;
861 	hbuf.h_length = ADDRLEN(af);
862 	hbuf.h_addr_list = hlist;
863 	na = nh = 0;
864 
865 #ifdef INET6
866 	qtype = (af == AF_INET6 ? T_AAAA : T_A);
867 #else
868 	qtype = T_A;
869 #endif
870 	n = res_search(name, C_IN, qtype, answer, sizeof(answer));
871 	if (n < 0) {
872 		*errp = h_errno;
873 		return NULL;
874 	}
875 	hp = (HEADER *)answer;
876 	eom = answer + n;
877 	ancount = ntohs(hp->ancount);
878 	qdcount = ntohs(hp->qdcount);
879 	DNS_ASSERT(qdcount == 1);
880 	cp = answer + sizeof(HEADER);
881 	bp = hostbuf;
882 	buflen = sizeof(hostbuf);
883 
884 	n = dn_expand(answer, eom, cp, bp, buflen);
885 	DNS_ASSERT(n >= 0);
886 	cp += n + QFIXEDSZ;
887 	hbuf.h_name = bp;
888 	n = strlen(bp) + 1;
889 	bp += n;
890 	buflen -= n;
891 	while (ancount-- > 0 && cp < eom) {
892 		n = dn_expand(answer, eom, cp, bp, buflen);
893 		DNS_ASSERT(n >= 0);
894 		cp += n;		/* name */
895 		type = _getshort(cp);
896 		cp += 2;		/* type */
897 		class = _getshort(cp);
898 		cp += 2;		/* class */
899 		ttl = _getlong(cp);
900 		cp += 4;		/* ttl */
901 		n = _getshort(cp);
902 		cp += 2;		/* len */
903 		DNS_ASSERT(class == C_IN);
904 		switch (type) {
905 		case T_CNAME:
906 			if (na >= MAXALIASES-1) {
907 				cp += n;
908 				break;
909 			}
910 			n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
911 			DNS_ASSERT(n >= 0);
912 			cp += n;
913 			/* alias */
914 			alist[na++] = bp;
915 			n = strlen(bp) + 1;
916 			bp += n;
917 			buflen -= n;
918 			/* canon */
919 			n = strlen(tbuf) + 1;
920 			DNS_ASSERT(n < buflen);
921 			strcpy(bp, tbuf);
922 			hbuf.h_name = bp;
923 			bp += n;
924 			buflen -= n;
925 			break;
926 		case T_A:
927 #ifdef INET6
928 		case T_AAAA:
929 #endif
930 			DNS_ASSERT(type == qtype);
931 			bp = (char *)ALIGN(bp);
932 			DNS_ASSERT(n == hbuf.h_length);
933 			DNS_ASSERT(n < buflen);
934 			if (nh < MAXADDRS-1) {
935 				hlist[nh++] = bp;
936 				memcpy(bp, cp, n);
937 				bp += n;
938 				buflen -= n;
939 			}
940 			cp += n;
941 			break;
942 		default:
943 			DNS_ASSERT(0);
944 			cp += n;
945 			break;
946 		}
947 	}
948 	if (nh == 0) {
949   badanswer:
950 		*errp = NO_RECOVERY;
951 		return NULL;
952 	}
953 	alist[na] = NULL;
954 	hlist[nh] = NULL;
955 	return _hpcopy(&hbuf, errp);
956 }
957 
958 static struct hostent *
959 _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
960 {
961 	int n;
962 	u_char answer[BUFSIZ];
963 	HEADER *hp;
964 	u_char c, *cp, *eom;
965 	int type, class, ancount, qdcount;
966 	u_long ttl;
967 	char hostbuf[BUFSIZ];
968 	char *bp;
969 	char *alist[MAXALIASES];
970 	char *hlist[2];
971 	struct hostent hbuf;
972 	int buflen;
973 	int na;
974 #ifdef INET6
975 	static const char hex[] = "0123456789abcdef";
976 #endif
977 
978 #ifdef INET6
979 	/* XXX */
980 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
981 		return NULL;
982 #endif
983 
984 	if ((_res.options & RES_INIT) == 0) {
985 		if (res_init() < 0) {
986 			*errp = h_errno;
987 			return NULL;
988 		}
989 	}
990 	hbuf.h_name = NULL;
991 	hbuf.h_aliases = alist;
992 	hbuf.h_addrtype = af;
993 	hbuf.h_length = addrlen;
994 	hbuf.h_addr_list = hlist;
995 	hlist[0] = (char *)addr;
996 	hlist[1] = NULL;
997 	na = 0;
998 
999 	n = 0;
1000 	bp = hostbuf;
1001 	cp = (u_char *)addr+addrlen-1;
1002 	switch (af) {
1003 #ifdef INET6
1004 	case AF_INET6:
1005 		for (; n < addrlen; n++, cp--) {
1006 			c = *cp;
1007 			*bp++ = hex[c & 0xf];
1008 			*bp++ = '.';
1009 			*bp++ = hex[c >> 4];
1010 			*bp++ = '.';
1011 		}
1012 		strcpy(bp, "ip6.int");
1013 		break;
1014 #endif
1015 	default:
1016 		for (; n < addrlen; n++, cp--) {
1017 			c = *cp;
1018 			if (c >= 100)
1019 				*bp++ = '0' + c / 100;
1020 			if (c >= 10)
1021 				*bp++ = '0' + (c % 100) / 10;
1022 			*bp++ = '0' + c % 10;
1023 			*bp++ = '.';
1024 		}
1025 		strcpy(bp, "in-addr.arpa");
1026 		break;
1027 	}
1028 
1029 	n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
1030 	if (n < 0) {
1031 		*errp = h_errno;
1032 		return NULL;
1033 	}
1034 	hp = (HEADER *)answer;
1035 	eom = answer + n;
1036 	ancount = ntohs(hp->ancount);
1037 	qdcount = ntohs(hp->qdcount);
1038 	DNS_ASSERT(qdcount == 1);
1039 	cp = answer + sizeof(HEADER);
1040 	bp = hostbuf;
1041 	buflen = sizeof(hostbuf);
1042 
1043 	n = dn_expand(answer, eom, cp, bp, buflen);
1044 	DNS_ASSERT(n >= 0);
1045 	cp += n + QFIXEDSZ;
1046 	while (ancount-- > 0 && cp < eom) {
1047 		n = dn_expand(answer, eom, cp, bp, buflen);
1048 		DNS_ASSERT(n >= 0);
1049 		cp += n;		/* name */
1050 		type = _getshort(cp);
1051 		cp += 2;		/* type */
1052 		class = _getshort(cp);
1053 		cp += 2;		/* class */
1054 		ttl = _getlong(cp);
1055 		cp += 4;		/* ttl */
1056 		n = _getshort(cp);
1057 		cp += 2;		/* len */
1058 		DNS_ASSERT(class == C_IN);
1059 		switch (type) {
1060 		case T_PTR:
1061 			n = dn_expand(answer, eom, cp, bp, buflen);
1062 			DNS_ASSERT(n >= 0);
1063 			cp += n;
1064 			if (na >= MAXALIASES-1)
1065 				break;
1066 			if (hbuf.h_name == NULL)
1067 				hbuf.h_name = bp;
1068 			else
1069 				alist[na++] = bp;
1070 			n = strlen(bp) + 1;
1071 			bp += n;
1072 			buflen -= n;
1073 			break;
1074 		case T_CNAME:
1075 			cp += n;
1076 			break;
1077 		default:
1078   badanswer:
1079 			*errp = NO_RECOVERY;
1080 			return NULL;
1081 		}
1082 	}
1083 	if (hbuf.h_name == NULL) {
1084 		*errp = h_errno;
1085 		return NULL;
1086 	}
1087 	alist[na] = NULL;
1088 	return _hpcopy(&hbuf, errp);
1089 }
1090 
1091 #ifdef ICMPNL
1092 
1093 /*
1094  * experimental:
1095  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
1096  *	ifindex is assumed to be encoded in addr.
1097  */
1098 #include <sys/uio.h>
1099 #include <netinet/ip6.h>
1100 #include <netinet/icmp6.h>
1101 
1102 struct _icmp_host_cache {
1103 	struct _icmp_host_cache *hc_next;
1104 	int hc_ifindex;
1105 	struct in6_addr hc_addr;
1106 	char *hc_name;
1107 };
1108 
1109 static char *
1110 _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1111 {
1112 	int s;
1113 	struct icmp6_filter filter;
1114 	struct msghdr msg;
1115 	struct cmsghdr *cmsg;
1116 	struct in6_pktinfo *pkt;
1117 	char cbuf[256];
1118 	char buf[1024];
1119 	int cc;
1120 	struct icmp6_fqdn_query *fq;
1121 	struct icmp6_fqdn_reply *fr;
1122 	struct _icmp_host_cache *hc;
1123 	struct sockaddr_in6 sin6;
1124 	struct iovec iov;
1125 	fd_set s_fds, fds;
1126 	struct timeval tout;
1127 	int len;
1128 	char *name;
1129 	static int pid;
1130 	static struct _icmp_host_cache *hc_head;
1131 
1132 	for (hc = hc_head; hc; hc = hc->hc_next) {
1133 		if (hc->hc_ifindex == ifindex
1134 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1135 			return hc->hc_name;
1136 	}
1137 
1138 	if (pid == 0)
1139 		pid = getpid();
1140 
1141 	ICMP6_FILTER_SETBLOCKALL(&filter);
1142 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1143 
1144 	FD_ZERO(&s_fds);
1145 	tout.tv_sec = 0;
1146 	tout.tv_usec = 200000;	/*XXX: 200ms*/
1147 
1148 	fq = (struct icmp6_fqdn_query *)buf;
1149 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1150 	fq->icmp6_fqdn_code = 0;
1151 	fq->icmp6_fqdn_cksum = 0;
1152 	fq->icmp6_fqdn_id = (u_short)pid;
1153 	fq->icmp6_fqdn_unused = 0;
1154 	fq->icmp6_fqdn_cookie[0] = 0;
1155 	fq->icmp6_fqdn_cookie[1] = 0;
1156 
1157 	memset(&sin6, 0, sizeof(sin6));
1158 	sin6.sin6_family = AF_INET6;
1159 	sin6.sin6_addr = *addr;
1160 
1161 	memset(&msg, 0, sizeof(msg));
1162 	msg.msg_name = (caddr_t)&sin6;
1163 	msg.msg_namelen = sizeof(sin6);
1164 	msg.msg_iov = &iov;
1165 	msg.msg_iovlen = 1;
1166 	msg.msg_control = NULL;
1167 	msg.msg_controllen = 0;
1168 	iov.iov_base = (caddr_t)buf;
1169 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
1170 
1171 	if (ifindex) {
1172 		msg.msg_control = cbuf;
1173 		msg.msg_controllen = sizeof(cbuf);
1174 		cmsg = CMSG_FIRSTHDR(&msg);
1175 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1176 		cmsg->cmsg_level = IPPROTO_IPV6;
1177 		cmsg->cmsg_type = IPV6_PKTINFO;
1178 		pkt = (struct in6_pktinfo *)&cmsg[1];
1179 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1180 		pkt->ipi6_ifindex = ifindex;
1181 		cmsg = CMSG_NXTHDR(&msg, cmsg);
1182 		msg.msg_controllen = (char *)cmsg - cbuf;
1183 	}
1184 
1185 	if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1186 		return NULL;
1187 	(void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1188 			 (char *)&filter, sizeof(filter));
1189 	cc = sendmsg(s, &msg, 0);
1190 	if (cc < 0) {
1191 		_close(s);
1192 		return NULL;
1193 	}
1194 	FD_SET(s, &s_fds);
1195 	for (;;) {
1196 		fds = s_fds;
1197 		if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1198 			_close(s);
1199 			return NULL;
1200 		}
1201 		len = sizeof(sin6);
1202 		cc = recvfrom(s, buf, sizeof(buf), 0,
1203 			      (struct sockaddr *)&sin6, &len);
1204 		if (cc <= 0) {
1205 			_close(s);
1206 			return NULL;
1207 		}
1208 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1209 			continue;
1210 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1211 			continue;
1212 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1213 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1214 			break;
1215 	}
1216 	_close(s);
1217 	if (fr->icmp6_fqdn_cookie[1] != 0) {
1218 		/* rfc1788 type */
1219 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1220 		len = (buf + cc) - name;
1221 	} else {
1222 		len = fr->icmp6_fqdn_namelen;
1223 		name = fr->icmp6_fqdn_name;
1224 	}
1225 	if (len <= 0)
1226 		return NULL;
1227 	name[len] = 0;
1228 
1229 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1230 		return NULL;
1231 	/* XXX: limit number of cached entries */
1232 	hc->hc_ifindex = ifindex;
1233 	hc->hc_addr = *addr;
1234 	hc->hc_name = strdup(name);
1235 	hc->hc_next = hc_head;
1236 	hc_head = hc;
1237 	return hc->hc_name;
1238 }
1239 
1240 static struct hostent *
1241 _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1242 {
1243 	char *hname;
1244 	int ifindex;
1245 	struct in6_addr addr6;
1246 
1247 	if (af != AF_INET6) {
1248 		/*
1249 		 * Note: rfc1788 defines Who Are You for IPv4,
1250 		 * but no one implements it.
1251 		 */
1252 		return NULL;
1253 	}
1254 
1255 	memcpy(&addr6, addr, addrlen);
1256 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1257 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1258 
1259 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1260 		return NULL;	/*XXX*/
1261 
1262 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1263 		return NULL;
1264 	return _hpaddr(af, hname, &addr6, errp);
1265 }
1266 #endif /* ICMPNL */
1267