xref: /freebsd/lib/libc/net/name6.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
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 <sys/queue.h>
46 #include <netinet/in.h>
47 
48 #include <arpa/inet.h>
49 #include <arpa/nameser.h>
50 
51 #include <errno.h>
52 #include <netdb.h>
53 #include <resolv.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 #ifndef _PATH_HOSTS
60 #define	_PATH_HOSTS	"/etc/hosts"
61 #endif
62 
63 #ifndef MAXALIASES
64 #define	MAXALIASES	10
65 #endif
66 #ifndef	MAXADDRS
67 #define	MAXADDRS	20
68 #endif
69 #ifndef MAXDNAME
70 #define	MAXDNAME	1025
71 #endif
72 
73 #ifdef INET6
74 #define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
75 					    sizeof(struct in_addr))
76 #else
77 #define	ADDRLEN(af)	sizeof(struct in_addr)
78 #endif
79 
80 #define	MAPADDR(ab, ina) \
81 do {									\
82 	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
83 	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
84 	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
85 } while (0)
86 #define	MAPADDRENABLED(flags) \
87 	(((flags) & AI_V4MAPPED) || \
88 	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
89 
90 union inx_addr {
91 	struct in_addr	in_addr;
92 #ifdef INET6
93 	struct in6_addr	in6_addr;
94 #endif
95 	struct {
96 		u_char	mau_zero[10];
97 		u_char	mau_one[2];
98 		struct in_addr mau_inaddr;
99 	}		map_addr_un;
100 #define	map_zero	map_addr_un.mau_zero
101 #define	map_one		map_addr_un.mau_one
102 #define	map_inaddr	map_addr_un.mau_inaddr
103 };
104 
105 static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
106 static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
107 static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
108 #ifdef INET6
109 static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
110 #endif
111 static struct	 hostent *_hpsort(struct hostent *hp);
112 static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
113 static char	*_hgetword(char **pp);
114 static int	 _mapped_addr_enabled(void);
115 
116 static FILE	*_files_open(int *errp);
117 static struct	 hostent *_files_ghbyname(const char *name, int af, int *errp);
118 static struct	 hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
119 static void	 _files_shent(int stayopen);
120 static void	 _files_ehent(void);
121 static struct	 hostent *_nis_ghbyname(const char *name, int af, int *errp);
122 static struct	 hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
123 static struct	 hostent *_dns_ghbyname(const char *name, int af, int *errp);
124 static struct	 hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
125 static void	 _dns_shent(int stayopen);
126 static void	 _dns_ehent(void);
127 #ifdef ICMPNL
128 static struct	 hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
129 #endif /* ICMPNL */
130 
131 /*
132  * Select order host function.
133  */
134 #define	MAXHOSTCONF	4
135 
136 #ifndef HOSTCONF
137 #  define	HOSTCONF	"/etc/host.conf"
138 #endif /* !HOSTCONF */
139 
140 struct _hostconf {
141 	struct hostent *(*byname)(const char *name, int af, int *errp);
142 	struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
143 };
144 
145 /* default order */
146 static struct _hostconf _hostconf[MAXHOSTCONF] = {
147 	{ _dns_ghbyname,	_dns_ghbyaddr },
148 	{ _files_ghbyname,	_files_ghbyaddr },
149 #ifdef ICMPNL
150 	{ NULL,			_icmp_ghbyaddr },
151 #endif /* ICMPNL */
152 };
153 
154 static int	_hostconf_init_done;
155 static void	_hostconf_init(void);
156 
157 /*
158  * Initialize hostconf structure.
159  */
160 
161 static void
162 _hostconf_init(void)
163 {
164 	FILE *fp;
165 	int n;
166 	char *p, *line;
167 	char buf[BUFSIZ];
168 
169 	_hostconf_init_done = 1;
170 	n = 0;
171 	p = HOSTCONF;
172 	if ((fp = fopen(p, "r")) == NULL)
173 		return;
174 	while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
175 		line = buf;
176 		if ((p = _hgetword(&line)) == NULL)
177 			continue;
178 		do {
179 			if (strcmp(p, "hosts") == 0
180 			||  strcmp(p, "local") == 0
181 			||  strcmp(p, "file") == 0
182 			||  strcmp(p, "files") == 0) {
183 				_hostconf[n].byname = _files_ghbyname;
184 				_hostconf[n].byaddr = _files_ghbyaddr;
185 				n++;
186 			}
187 			else if (strcmp(p, "dns") == 0
188 			     ||  strcmp(p, "bind") == 0) {
189 				_hostconf[n].byname = _dns_ghbyname;
190 				_hostconf[n].byaddr = _dns_ghbyaddr;
191 				n++;
192 			}
193 			else if (strcmp(p, "nis") == 0) {
194 				_hostconf[n].byname = _nis_ghbyname;
195 				_hostconf[n].byaddr = _nis_ghbyaddr;
196 				n++;
197 			}
198 #ifdef ICMPNL
199 			else if (strcmp(p, "icmp") == 0) {
200 				_hostconf[n].byname = NULL;
201 				_hostconf[n].byaddr = _icmp_ghbyaddr;
202 				n++;
203 			}
204 #endif /* ICMPNL */
205 		} while ((p = _hgetword(&line)) != NULL);
206 	}
207 	fclose(fp);
208 	if (n < 0) {
209 		/* no keyword found. do not change default configuration */
210 		return;
211 	}
212 	for (; n < MAXHOSTCONF; n++) {
213 		_hostconf[n].byname = NULL;
214 		_hostconf[n].byaddr = NULL;
215 	}
216 }
217 
218 /*
219  * Check if kernel supports mapped address.
220  *	implementation dependent
221  */
222 #ifdef __KAME__
223 #include <sys/sysctl.h>
224 #endif /* __KAME__ */
225 
226 static int
227 _mapped_addr_enabled(void)
228 {
229 	/* implementation dependent check */
230 #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
231 	int mib[4];
232 	size_t len;
233 	int val;
234 
235 	mib[0] = CTL_NET;
236 	mib[1] = PF_INET6;
237 	mib[2] = IPPROTO_IPV6;
238 	mib[3] = IPV6CTL_MAPPED_ADDR;
239 	len = sizeof(val);
240 	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
241 		return 1;
242 #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
243 	return 0;
244 }
245 
246 /*
247  * Functions defined in RFC2553
248  *	getipnodebyname, getipnodebyadr, freehostent
249  */
250 
251 static struct hostent *
252 _ghbyname(const char *name, int af, int flags, int *errp)
253 {
254 	struct hostent *hp;
255 	int i;
256 
257 	if (flags & AI_ADDRCONFIG) {
258 		int s;
259 
260 		/*
261 		 * TODO:
262 		 * Note that implementation dependent test for address
263 		 * configuration should be done everytime called
264 		 * (or apropriate interval),
265 		 * because addresses will be dynamically assigned or deleted.
266 		 */
267 		if (af == AF_UNSPEC) {
268 			if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
269 				af = AF_INET;
270 			else {
271 				_close(s);
272 				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
273 					af = AF_INET6;
274 				else
275 				_close(s);
276 			}
277 
278 		}
279 		if (af != AF_UNSPEC) {
280 			if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
281 				return NULL;
282 			_close(s);
283 		}
284 	}
285 
286 	for (i = 0; i < MAXHOSTCONF; i++) {
287 		if (_hostconf[i].byname
288 		&&  (hp = (*_hostconf[i].byname)(name, af, errp))
289 		    != NULL)
290 			return hp;
291 	}
292 
293 	return NULL;
294 }
295 
296 /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
297 struct hostent *
298 _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
299 {
300 	struct hostent *hp;
301 	union inx_addr addrbuf;
302 
303 	/* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */
304 	if (af != AF_INET
305 #ifdef INET6
306 	    && af != AF_INET6
307 #endif
308 	    && af != PF_UNSPEC
309 		)
310 	{
311 		*errp = NO_RECOVERY;
312 		return NULL;
313 	}
314 
315 #ifdef INET6
316 	/* special case for literal address */
317 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
318 		if (af != AF_INET6) {
319 			*errp = HOST_NOT_FOUND;
320 			return NULL;
321 		}
322 		return _hpaddr(af, name, &addrbuf, errp);
323 	}
324 #endif
325 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
326 		if (af != AF_INET) {
327 			if (MAPADDRENABLED(flags)) {
328 				MAPADDR(&addrbuf, &addrbuf.in_addr);
329 			} else {
330 				*errp = HOST_NOT_FOUND;
331 				return NULL;
332 			}
333 		}
334 		return _hpaddr(af, name, &addrbuf, errp);
335 	}
336 
337 	if (!_hostconf_init_done)
338 		_hostconf_init();
339 
340 	*errp = HOST_NOT_FOUND;
341 	hp = _ghbyname(name, af, flags, errp);
342 
343 #ifdef INET6
344 	if (af == AF_INET6
345 	&&  ((flags & AI_ALL) || hp == NULL)
346 	&&  (MAPADDRENABLED(flags))) {
347 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
348 		if (hp == NULL)
349 			hp = _hpmapv6(hp2, errp);
350 		else {
351 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
352 				freehostent(hp2);
353 				hp2 = NULL;
354 			}
355 			hp = _hpmerge(hp, hp2, errp);
356 		}
357 	}
358 #endif
359 	return _hpsort(hp);
360 }
361 
362 struct hostent *
363 getipnodebyname(const char *name, int af, int flags, int *errp)
364 {
365 	if (af != AF_INET
366 #ifdef INET6
367 	    && af != AF_INET6
368 #endif
369 		)
370 	{
371 		*errp = NO_RECOVERY;
372 		return NULL;
373 	}
374 	return(_getipnodebyname_multi(name, af ,flags, errp));
375 }
376 
377 struct hostent *
378 getipnodebyaddr(const void *src, size_t len, int af, int *errp)
379 {
380 	struct hostent *hp;
381 	int i;
382 #ifdef INET6
383 	struct in6_addr addrbuf;
384 #else
385 	struct in_addr addrbuf;
386 #endif
387 
388 	*errp = HOST_NOT_FOUND;
389 
390 	switch (af) {
391 	case AF_INET:
392 		if (len != sizeof(struct in_addr)) {
393 			*errp = NO_RECOVERY;
394 			return NULL;
395 		}
396 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
397 			memcpy(&addrbuf, src, len);
398 			src = &addrbuf;
399 		}
400 		if (((struct in_addr *)src)->s_addr == 0)
401 			return NULL;
402 		break;
403 #ifdef INET6
404 	case AF_INET6:
405 		if (len != sizeof(struct in6_addr)) {
406 			*errp = NO_RECOVERY;
407 			return NULL;
408 		}
409 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
410 			memcpy(&addrbuf, src, len);
411 			src = &addrbuf;
412 		}
413 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
414 			return NULL;
415 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
416 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
417 			src = (char *)src +
418 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
419 			af = AF_INET;
420 			len = sizeof(struct in_addr);
421 		}
422 		break;
423 #endif
424 	default:
425 		*errp = NO_RECOVERY;
426 		return NULL;
427 	}
428 
429 	if (!_hostconf_init_done)
430 		_hostconf_init();
431 	for (i = 0; i < MAXHOSTCONF; i++) {
432 		if (_hostconf[i].byaddr
433 		&&  (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
434 			return hp;
435 	}
436 
437 	return NULL;
438 }
439 
440 void
441 freehostent(struct hostent *ptr)
442 {
443 	free(ptr);
444 }
445 
446 #if 0
447 
448 /* XXX: should be deprecated */
449 struct hostent *
450 getnodebyname(const char *name, int af, int flags)
451 {
452 	return getipnodebyname(name, af, flags, &h_errno);
453 }
454 
455 #ifdef __warn_references
456 __warn_references(getnodebyname,
457 	"warning: getnodebyname() deprecated, "
458 	"should use getaddrinfo() or getipnodebyname()");
459 #endif
460 
461 struct hostent *
462 getnodebyaddr(const void *src, size_t len, int af)
463 {
464 	return getipnodebyaddr(src, len, af, &h_errno);
465 }
466 
467 #ifdef __warn_references
468 __warn_references(getnodebyaddr,
469 	"warning: getnodebyaddr() deprecated, "
470 	"should use getnameinfo() or getipnodebyaddr()");
471 #endif
472 
473 #endif
474 
475 /*
476  * Private utility functions
477  */
478 
479 /*
480  * _hpcopy: allocate and copy hostent structure
481  */
482 static struct hostent *
483 _hpcopy(struct hostent *hp, int *errp)
484 {
485 	struct hostent *nhp;
486 	char *cp, **pp;
487 	int size, addrsize;
488 	int nalias = 0, naddr = 0;
489 	int al_off;
490 	int i;
491 
492 	if (hp == NULL)
493 		return hp;
494 
495 	/* count size to be allocated */
496 	size = sizeof(struct hostent);
497 	if (hp->h_name != NULL && *hp->h_name != '\0')
498 		size += strlen(hp->h_name) + 1;
499 	if ((pp = hp->h_aliases) != NULL) {
500 		for (i = 0; *pp != NULL; i++, pp++) {
501 			if (**pp != '\0') {
502 				size += strlen(*pp) + 1;
503 				nalias++;
504 			}
505 		}
506 	}
507 	/* adjust alignment */
508 	size = ALIGN(size);
509 	al_off = size;
510 	size += sizeof(char *) * (nalias + 1);
511 	addrsize = ALIGN(hp->h_length);
512 	if ((pp = hp->h_addr_list) != NULL) {
513 		while (*pp++ != NULL)
514 			naddr++;
515 	}
516 	size += addrsize * naddr;
517 	size += sizeof(char *) * (naddr + 1);
518 
519 	/* copy */
520 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
521 		*errp = TRY_AGAIN;
522 		return NULL;
523 	}
524 	cp = (char *)&nhp[1];
525 	if (hp->h_name != NULL && *hp->h_name != '\0') {
526 		nhp->h_name = cp;
527 		strcpy(cp, hp->h_name);
528 		cp += strlen(cp) + 1;
529 	} else
530 		nhp->h_name = NULL;
531 	nhp->h_aliases = (char **)((char *)nhp + al_off);
532 	if ((pp = hp->h_aliases) != NULL) {
533 		for (i = 0; *pp != NULL; pp++) {
534 			if (**pp != '\0') {
535 				nhp->h_aliases[i++] = cp;
536 				strcpy(cp, *pp);
537 				cp += strlen(cp) + 1;
538 			}
539 		}
540 	}
541 	nhp->h_aliases[nalias] = NULL;
542 	cp = (char *)&nhp->h_aliases[nalias + 1];
543 	nhp->h_addrtype = hp->h_addrtype;
544 	nhp->h_length = hp->h_length;
545 	nhp->h_addr_list = (char **)cp;
546 	if ((pp = hp->h_addr_list) != NULL) {
547 		cp = (char *)&nhp->h_addr_list[naddr + 1];
548 		for (i = 0; *pp != NULL; pp++) {
549 			nhp->h_addr_list[i++] = cp;
550 			memcpy(cp, *pp, hp->h_length);
551 			cp += addrsize;
552 		}
553 	}
554 	nhp->h_addr_list[naddr] = NULL;
555 	return nhp;
556 }
557 
558 /*
559  * _hpaddr: construct hostent structure with one address
560  */
561 static struct hostent *
562 _hpaddr(int af, const char *name, void *addr, int *errp)
563 {
564 	struct hostent *hp, hpbuf;
565 	char *addrs[2];
566 
567 	hp = &hpbuf;
568 	hp->h_name = (char *)name;
569 	hp->h_aliases = NULL;
570 	hp->h_addrtype = af;
571 	hp->h_length = ADDRLEN(af);
572 	hp->h_addr_list = addrs;
573 	addrs[0] = (char *)addr;
574 	addrs[1] = NULL;
575 	return _hpcopy(hp, errp);
576 }
577 
578 /*
579  * _hpmerge: merge 2 hostent structure, arguments will be freed
580  */
581 static struct hostent *
582 _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
583 {
584 	int i, j;
585 	int naddr, nalias;
586 	char **pp;
587 	struct hostent *hp, hpbuf;
588 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
589 	union inx_addr addrbuf[MAXADDRS];
590 
591 	if (hp1 == NULL)
592 		return hp2;
593 	if (hp2 == NULL)
594 		return hp1;
595 
596 #define	HP(i)	(i == 1 ? hp1 : hp2)
597 	hp = &hpbuf;
598 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
599 	hp->h_aliases = aliases;
600 	nalias = 0;
601 	for (i = 1; i <= 2; i++) {
602 		if ((pp = HP(i)->h_aliases) == NULL)
603 			continue;
604 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
605 			/* check duplicates */
606 			for (j = 0; j < nalias; j++)
607 				if (strcasecmp(*pp, aliases[j]) == 0)
608 					break;
609 			if (j == nalias)
610 				aliases[nalias++] = *pp;
611 		}
612 	}
613 	aliases[nalias] = NULL;
614 #ifdef INET6
615 	if (hp1->h_length != hp2->h_length) {
616 		hp->h_addrtype = AF_INET6;
617 		hp->h_length = sizeof(struct in6_addr);
618 	} else {
619 #endif
620 		hp->h_addrtype = hp1->h_addrtype;
621 		hp->h_length = hp1->h_length;
622 #ifdef INET6
623 	}
624 #endif
625 	hp->h_addr_list = addrs;
626 	naddr = 0;
627 	for (i = 1; i <= 2; i++) {
628 		if ((pp = HP(i)->h_addr_list) == NULL)
629 			continue;
630 		if (HP(i)->h_length == hp->h_length) {
631 			while (naddr < MAXADDRS && *pp != NULL)
632 				addrs[naddr++] = *pp++;
633 		} else {
634 			/* copy IPv4 addr as mapped IPv6 addr */
635 			while (naddr < MAXADDRS && *pp != NULL) {
636 				MAPADDR(&addrbuf[naddr], *pp++);
637 				addrs[naddr] = (char *)&addrbuf[naddr];
638 				naddr++;
639 			}
640 		}
641 	}
642 	addrs[naddr] = NULL;
643 	hp = _hpcopy(hp, errp);
644 	freehostent(hp1);
645 	freehostent(hp2);
646 	return hp;
647 }
648 
649 /*
650  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
651  */
652 #ifdef INET6
653 static struct hostent *
654 _hpmapv6(struct hostent *hp, int *errp)
655 {
656 	struct hostent *hp6;
657 
658 	if (hp == NULL)
659 		return NULL;
660 	if (hp->h_addrtype == AF_INET6)
661 		return hp;
662 
663 	/* make dummy hostent to convert IPv6 address */
664 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
665 		*errp = TRY_AGAIN;
666 		return NULL;
667 	}
668 	hp6->h_name = NULL;
669 	hp6->h_aliases = NULL;
670 	hp6->h_addrtype = AF_INET6;
671 	hp6->h_length = sizeof(struct in6_addr);
672 	hp6->h_addr_list = NULL;
673 	return _hpmerge(hp6, hp, errp);
674 }
675 #endif
676 
677 /*
678  * _hpsort: sort address by sortlist
679  */
680 static struct hostent *
681 _hpsort(struct hostent *hp)
682 {
683 	int i, j, n;
684 	u_char *ap, *sp, *mp, **pp;
685 	char t;
686 	char order[MAXADDRS];
687 	int nsort = _res.nsort;
688 
689 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
690 		return hp;
691 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
692 		for (j = 0; j < nsort; j++) {
693 #ifdef INET6
694 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
695 				continue;
696 			sp = (u_char *)&_res_ext.sort_list[j].addr;
697 			mp = (u_char *)&_res_ext.sort_list[j].mask;
698 #else
699 			sp = (u_char *)&_res.sort_list[j].addr;
700 			mp = (u_char *)&_res.sort_list[j].mask;
701 #endif
702 			for (n = 0; n < hp->h_length; n++) {
703 				if ((ap[n] & mp[n]) != sp[n])
704 					break;
705 			}
706 			if (n == hp->h_length)
707 				break;
708 		}
709 		order[i] = j;
710 	}
711 	n = i;
712 	pp = (u_char **)hp->h_addr_list;
713 	for (i = 0; i < n - 1; i++) {
714 		for (j = i + 1; j < n; j++) {
715 			if (order[i] > order[j]) {
716 				ap = pp[i];
717 				pp[i] = pp[j];
718 				pp[j] = ap;
719 				t = order[i];
720 				order[i] = order[j];
721 				order[j] = t;
722 			}
723 		}
724 	}
725 	return hp;
726 }
727 
728 static char *
729 _hgetword(char **pp)
730 {
731 	char c, *p, *ret;
732 	const char *sp;
733 	static const char sep[] = "# \t\n";
734 
735 	ret = NULL;
736 	for (p = *pp; (c = *p) != '\0'; p++) {
737 		for (sp = sep; *sp != '\0'; sp++) {
738 			if (c == *sp)
739 				break;
740 		}
741 		if (c == '#')
742 			p[1] = '\0';	/* ignore rest of line */
743 		if (ret == NULL) {
744 			if (*sp == '\0')
745 				ret = p;
746 		} else {
747 			if (*sp != '\0') {
748 				*p++ = '\0';
749 				break;
750 			}
751 		}
752 	}
753 	*pp = p;
754 	if (ret == NULL || *ret == '\0')
755 		return NULL;
756 	return ret;
757 }
758 
759 /*
760  * FILES (/etc/hosts)
761  */
762 
763 static FILE *
764 _files_open(int *errp)
765 {
766 	FILE *fp;
767 	fp = fopen(_PATH_HOSTS, "r");
768 	if (fp == NULL)
769 		*errp = NO_RECOVERY;
770 	return fp;
771 }
772 
773 static struct hostent *
774 _files_ghbyname(const char *name, int af, int *errp)
775 {
776 	int match, nalias;
777 	char *p, *line, *addrstr, *cname;
778 	FILE *fp;
779 	struct hostent *rethp, *hp, hpbuf;
780 	char *aliases[MAXALIASES + 1], *addrs[2];
781 	union inx_addr addrbuf;
782 	char buf[BUFSIZ];
783 	int af0 = af;
784 
785 	if ((fp = _files_open(errp)) == NULL)
786 		return NULL;
787 	rethp = hp = NULL;
788 
789 	while (fgets(buf, sizeof(buf), fp)) {
790 		line = buf;
791 		if ((addrstr = _hgetword(&line)) == NULL
792 		||  (cname = _hgetword(&line)) == NULL)
793 			continue;
794 		match = (strcasecmp(cname, name) == 0);
795 		nalias = 0;
796 		while ((p = _hgetword(&line)) != NULL) {
797 			if (!match)
798 				match = (strcasecmp(p, name) == 0);
799 			if (nalias < MAXALIASES)
800 				aliases[nalias++] = p;
801 		}
802 		if (!match)
803 			continue;
804 		switch (af0) {
805 		case AF_INET:
806 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
807 			    != 1) {
808 				*errp = NO_DATA;	/* name found */
809 				continue;
810 			}
811 			af = af0;
812 			break;
813 #ifdef INET6
814 		case AF_INET6:
815 			if (inet_pton(af, addrstr, &addrbuf) != 1) {
816 				*errp = NO_DATA;	/* name found */
817 				continue;
818 			}
819 			af = af0;
820 			break;
821 #endif
822 		case AF_UNSPEC:
823 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
824 			    == 1) {
825 				af = AF_INET;
826 				break;
827 			}
828 #ifdef INET6
829 			if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) {
830 				af = AF_INET6;
831 				break;
832 			}
833 #endif
834 			*errp = NO_DATA;	/* name found */
835 			continue;
836 			/* NOTREACHED */
837 		}
838 		hp = &hpbuf;
839 		hp->h_name = cname;
840 		hp->h_aliases = aliases;
841 		aliases[nalias] = NULL;
842 		hp->h_addrtype = af;
843 		hp->h_length = ADDRLEN(af);
844 		hp->h_addr_list = addrs;
845 		addrs[0] = (char *)&addrbuf;
846 		addrs[1] = NULL;
847 		hp = _hpcopy(hp, errp);
848 		rethp = _hpmerge(rethp, hp, errp);
849 	}
850 	fclose(fp);
851 	return rethp;
852 }
853 
854 static struct hostent *
855 _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
856 {
857 	int nalias;
858 	char *p, *line;
859 	FILE *fp;
860 	struct hostent *hp, hpbuf;
861 	char *aliases[MAXALIASES + 1], *addrs[2];
862 	union inx_addr addrbuf;
863 	char buf[BUFSIZ];
864 
865 	if ((fp = _files_open(errp)) == NULL)
866 		return NULL;
867 	hp = NULL;
868 	while (fgets(buf, sizeof(buf), fp)) {
869 		line = buf;
870 		if ((p = _hgetword(&line)) == NULL
871 		||  (af == AF_INET
872 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
873 		     : inet_pton(af, p, &addrbuf)) != 1
874 		||  memcmp(addr, &addrbuf, addrlen) != 0
875 		||  (p = _hgetword(&line)) == NULL)
876 			continue;
877 		hp = &hpbuf;
878 		hp->h_name = p;
879 		hp->h_aliases = aliases;
880 		nalias = 0;
881 		while ((p = _hgetword(&line)) != NULL) {
882 			if (nalias < MAXALIASES)
883 				aliases[nalias++] = p;
884 		}
885 		aliases[nalias] = NULL;
886 		hp->h_addrtype = af;
887 		hp->h_length = addrlen;
888 		hp->h_addr_list = addrs;
889 		addrs[0] = (char *)&addrbuf;
890 		addrs[1] = NULL;
891 		hp = _hpcopy(hp, errp);
892 		break;
893 	}
894 	fclose(fp);
895 	return hp;
896 }
897 
898 /*
899  * NIS
900  *
901  * XXX actually a hack, these are INET4 specific.
902  */
903 static struct hostent *
904 _nis_ghbyname(const char *name, int af, int *errp)
905 {
906 	struct hostent *hp = NULL;
907 
908 	if (af == AF_UNSPEC)
909 		af = AF_INET;
910 	if (af == AF_INET) {
911 		hp = _gethostbynisname(name, af);
912 		if (hp != NULL)
913 			hp = _hpcopy(hp, errp);
914 	}
915 	return (hp);
916 
917 }
918 
919 static struct hostent *
920 _nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
921 {
922 	struct hostent *hp = NULL;
923 
924 	if (af == AF_INET) {
925 		hp = _gethostbynisaddr(addr, addrlen, af);
926 		if (hp != NULL)
927 			hp = _hpcopy(hp, errp);
928 	}
929 	return (hp);
930 }
931 
932 #ifdef DEBUG
933 #define	DNS_ASSERT(X)	if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
934 #else
935 #define	DNS_ASSERT(X)	if (!(X)) { goto badanswer; }
936 #endif
937 
938 struct __res_type_list {
939         SLIST_ENTRY(__res_type_list) rtl_entry;
940         int     rtl_type;
941 };
942 
943 static struct hostent *
944 _gethpbyanswer(answer, anslen, qtype, errp)
945 	const u_char *answer;
946 	int anslen;
947 	int qtype;
948 	int *errp;
949 {
950 	int n;
951 	char tbuf[MAXDNAME+1];
952 	HEADER *hp;
953 	const u_char *cp, *eom;
954 	int type, class, ancount, qdcount;
955 	u_long ttl;
956 	char hostbuf[BUFSIZ];
957 	char *bp;
958 	char *alist[MAXALIASES];
959 	char *hlist[MAXADDRS];
960 	struct hostent hbuf;
961 	int buflen;
962 	int na, nh;
963 
964 	hbuf.h_aliases = alist;
965 	hbuf.h_addrtype =
966 #ifdef INET6
967 		(qtype == T_AAAA) ? AF_INET6 :
968 #endif
969 		AF_INET;
970 	hbuf.h_length = ADDRLEN(hbuf.h_addrtype);
971 	hbuf.h_addr_list = hlist;
972 	na = nh = 0;
973 	hp = (HEADER *)answer;
974 	eom = answer + anslen;
975 	ancount = ntohs(hp->ancount);
976 	qdcount = ntohs(hp->qdcount);
977 	DNS_ASSERT(qdcount == 1);
978 	cp = answer + sizeof(HEADER);
979 	bp = hostbuf;
980 	buflen = sizeof(hostbuf);
981 
982 	n = dn_expand(answer, eom, cp, bp, buflen);
983 	DNS_ASSERT(n >= 0);
984 	cp += n + QFIXEDSZ;
985 	hbuf.h_name = bp;
986 	n = strlen(bp) + 1;
987 	bp += n;
988 	buflen -= n;
989 	while (ancount-- > 0 && cp < eom) {
990 		n = dn_expand(answer, eom, cp, bp, buflen);
991 		DNS_ASSERT(n >= 0);
992 		cp += n;		/* name */
993 		type = _getshort(cp);
994 		cp += 2;		/* type */
995 		class = _getshort(cp);
996 		cp += 2;		/* class */
997 		ttl = _getlong(cp);
998 		cp += 4;		/* ttl */
999 		n = _getshort(cp);
1000 		cp += 2;		/* len */
1001 		DNS_ASSERT(class == C_IN);
1002 		switch (type) {
1003 		case T_CNAME:
1004 			if (na >= MAXALIASES-1) {
1005 				cp += n;
1006 				break;
1007 			}
1008 			n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
1009 			DNS_ASSERT(n >= 0);
1010 			cp += n;
1011 			/* alias */
1012 			alist[na++] = bp;
1013 			n = strlen(bp) + 1;
1014 			bp += n;
1015 			buflen -= n;
1016 			/* canon */
1017 			n = strlen(tbuf) + 1;
1018 			DNS_ASSERT(n < buflen);
1019 			strcpy(bp, tbuf);
1020 			hbuf.h_name = bp;
1021 			bp += n;
1022 			buflen -= n;
1023 			break;
1024 		case T_A:
1025 #ifdef INET6
1026 		case T_AAAA:
1027 #endif
1028 			DNS_ASSERT(type == qtype);
1029 			bp = (char *)ALIGN(bp);
1030 			DNS_ASSERT(n == hbuf.h_length);
1031 			DNS_ASSERT(n < buflen);
1032 			if (nh < MAXADDRS-1) {
1033 				hlist[nh++] = bp;
1034 				memcpy(bp, cp, n);
1035 				bp += n;
1036 				buflen -= n;
1037 			}
1038 			cp += n;
1039 			break;
1040 		default:
1041 			DNS_ASSERT(0);
1042 			cp += n;
1043 			break;
1044 		}
1045 	}
1046 	if (nh == 0) {
1047   badanswer:
1048 		*errp = NO_RECOVERY;
1049 		return NULL;
1050 	}
1051 	alist[na] = NULL;
1052 	hlist[nh] = NULL;
1053 	return _hpcopy(&hbuf, errp);
1054 }
1055 
1056 /* res_search() variant with multiple query support. */
1057 static struct hostent *
1058 _res_search_multi(name, rtl, errp)
1059 	const char *name;	/* domain name */
1060 	struct	__res_type_list *rtl; /* list of query types */
1061 	int *errp;
1062 {
1063 	u_char answer[BUFSIZ];	/* buffer to put answer */
1064 	const char *cp, * const *domain;
1065 	struct hostent *hp0 = NULL, *hp;
1066 	u_int dots;
1067 	int trailing_dot, ret, saved_herrno;
1068 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1069 	struct __res_type_list *rtl0 = rtl;
1070 
1071 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1072 		*errp = NETDB_INTERNAL;
1073 		return (NULL);
1074 	}
1075 	dots = 0;
1076 	for (cp = name; *cp; cp++)
1077 		dots += (*cp == '.');
1078 	trailing_dot = 0;
1079 	if (cp > name && *--cp == '.')
1080 		trailing_dot++;
1081 
1082 	/* If there aren't any dots, it could be a user-level alias */
1083 	if (!dots && (cp = hostalias(name)) != NULL) {
1084 		for(rtl = rtl0; rtl != NULL;
1085 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1086 			ret = res_query(cp, C_IN, rtl->rtl_type, answer,
1087 					     sizeof(answer));
1088 			if (ret > 0) {
1089 				hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
1090 						    errp);
1091 				hp0 = _hpmerge(hp0, hp, errp);
1092 			}
1093 		}
1094 		return (hp0);
1095 	}
1096 
1097 	/*
1098 	 * If there are dots in the name already, let's just give it a try
1099 	 * 'as is'.  The threshold can be set with the "ndots" option.
1100 	 */
1101 	saved_herrno = -1;
1102 	if (dots >= _res.ndots) {
1103 		for(rtl = rtl0; rtl != NULL;
1104 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1105 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1106 					      answer, sizeof(answer));
1107 			if (ret > 0) {
1108 				hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
1109 						    errp);
1110 				hp0 = _hpmerge(hp0, hp, errp);
1111 			}
1112 		}
1113 		if (hp0 != NULL)
1114 			return (hp0);
1115 		saved_herrno = *errp;
1116 		tried_as_is++;
1117 	}
1118 
1119 	/*
1120 	 * We do at least one level of search if
1121 	 *	- there is no dot and RES_DEFNAME is set, or
1122 	 *	- there is at least one dot, there is no trailing dot,
1123 	 *	  and RES_DNSRCH is set.
1124 	 */
1125 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1126 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1127 		int done = 0;
1128 
1129 		for (domain = (const char * const *)_res.dnsrch;
1130 		     *domain && !done;
1131 		     domain++) {
1132 
1133 			for(rtl = rtl0; rtl != NULL;
1134 			    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1135 				ret = res_querydomain(name, *domain, C_IN,
1136 						      rtl->rtl_type,
1137 						      answer, sizeof(answer));
1138 				if (ret > 0) {
1139 					hp = _gethpbyanswer(answer, ret,
1140 							      rtl->rtl_type,
1141 							      errp);
1142 					hp0 = _hpmerge(hp0, hp, errp);
1143 				}
1144 			}
1145 			if (hp0 != NULL)
1146 				return (hp0);
1147 
1148 			/*
1149 			 * If no server present, give up.
1150 			 * If name isn't found in this domain,
1151 			 * keep trying higher domains in the search list
1152 			 * (if that's enabled).
1153 			 * On a NO_DATA error, keep trying, otherwise
1154 			 * a wildcard entry of another type could keep us
1155 			 * from finding this entry higher in the domain.
1156 			 * If we get some other error (negative answer or
1157 			 * server failure), then stop searching up,
1158 			 * but try the input name below in case it's
1159 			 * fully-qualified.
1160 			 */
1161 			if (errno == ECONNREFUSED) {
1162 				*errp = TRY_AGAIN;
1163 				return (NULL);
1164 			}
1165 
1166 			switch (*errp) {
1167 			case NO_DATA:
1168 				got_nodata++;
1169 				/* FALLTHROUGH */
1170 			case HOST_NOT_FOUND:
1171 				/* keep trying */
1172 				break;
1173 			case TRY_AGAIN:
1174 				if (((HEADER *)answer)->rcode == SERVFAIL) {
1175 					/* try next search element, if any */
1176 					got_servfail++;
1177 					break;
1178 				}
1179 				/* FALLTHROUGH */
1180 			default:
1181 				/* anything else implies that we're done */
1182 				done++;
1183 			}
1184 
1185 			/* if we got here for some reason other than DNSRCH,
1186 			 * we only wanted one iteration of the loop, so stop.
1187 			 */
1188 			if (!(_res.options & RES_DNSRCH))
1189 				done++;
1190 		}
1191 	}
1192 
1193 	/*
1194 	 * If we have not already tried the name "as is", do that now.
1195 	 * note that we do this regardless of how many dots were in the
1196 	 * name or whether it ends with a dot unless NOTLDQUERY is set.
1197 	 */
1198 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
1199 		for(rtl = rtl0; rtl != NULL;
1200 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1201 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1202 					      answer, sizeof(answer));
1203 			if (ret > 0) {
1204 				hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
1205 						    errp);
1206 				hp0 = _hpmerge(hp0, hp, errp);
1207 			}
1208 		}
1209 		if (hp0 != NULL)
1210 			return (hp0);
1211 	}
1212 
1213 	/* if we got here, we didn't satisfy the search.
1214 	 * if we did an initial full query, return that query's h_errno
1215 	 * (note that we wouldn't be here if that query had succeeded).
1216 	 * else if we ever got a nodata, send that back as the reason.
1217 	 * else send back meaningless h_errno, that being the one from
1218 	 * the last DNSRCH we did.
1219 	 */
1220 	if (saved_herrno != -1)
1221 		*errp = saved_herrno;
1222 	else if (got_nodata)
1223 		*errp = NO_DATA;
1224 	else if (got_servfail)
1225 		*errp = TRY_AGAIN;
1226 	return (NULL);
1227 }
1228 
1229 static struct hostent *
1230 _dns_ghbyname(const char *name, int af, int *errp)
1231 {
1232 	struct __res_type_list *rtl, rtl4;
1233 #ifdef INET6
1234 	struct __res_type_list rtl6;
1235 #endif
1236 
1237 #ifdef INET6
1238 	switch (af) {
1239 	case AF_UNSPEC:
1240 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1241 		SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA;
1242 		rtl = &rtl6;
1243 		break;
1244 	case AF_INET6:
1245 		SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA;
1246 		rtl = &rtl6;
1247 		break;
1248 	case AF_INET:
1249 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1250 		rtl = &rtl4;
1251 		break;
1252 	}
1253 #else
1254 	SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1255 	rtl = &rtl4;
1256 #endif
1257 	return(_res_search_multi(name, rtl, errp));
1258 }
1259 
1260 static struct hostent *
1261 _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1262 {
1263 	int n;
1264 	u_char answer[BUFSIZ];
1265 	HEADER *hp;
1266 	u_char c, *cp, *eom;
1267 	int type, class, ancount, qdcount;
1268 	u_long ttl;
1269 	char hostbuf[BUFSIZ];
1270 	char *bp;
1271 	char *alist[MAXALIASES];
1272 	char *hlist[2];
1273 	struct hostent hbuf;
1274 	int buflen;
1275 	int na;
1276 #ifdef INET6
1277 	static const char hex[] = "0123456789abcdef";
1278 #endif
1279 
1280 #ifdef INET6
1281 	/* XXX */
1282 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
1283 		return NULL;
1284 #endif
1285 
1286 	if ((_res.options & RES_INIT) == 0) {
1287 		if (res_init() < 0) {
1288 			*errp = h_errno;
1289 			return NULL;
1290 		}
1291 	}
1292 	hbuf.h_name = NULL;
1293 	hbuf.h_aliases = alist;
1294 	hbuf.h_addrtype = af;
1295 	hbuf.h_length = addrlen;
1296 	hbuf.h_addr_list = hlist;
1297 	hlist[0] = (char *)addr;
1298 	hlist[1] = NULL;
1299 	na = 0;
1300 
1301 	n = 0;
1302 	bp = hostbuf;
1303 	cp = (u_char *)addr+addrlen-1;
1304 	switch (af) {
1305 #ifdef INET6
1306 	case AF_INET6:
1307 		for (; n < addrlen; n++, cp--) {
1308 			c = *cp;
1309 			*bp++ = hex[c & 0xf];
1310 			*bp++ = '.';
1311 			*bp++ = hex[c >> 4];
1312 			*bp++ = '.';
1313 		}
1314 		strcpy(bp, "ip6.int");
1315 		break;
1316 #endif
1317 	default:
1318 		for (; n < addrlen; n++, cp--) {
1319 			c = *cp;
1320 			if (c >= 100)
1321 				*bp++ = '0' + c / 100;
1322 			if (c >= 10)
1323 				*bp++ = '0' + (c % 100) / 10;
1324 			*bp++ = '0' + c % 10;
1325 			*bp++ = '.';
1326 		}
1327 		strcpy(bp, "in-addr.arpa");
1328 		break;
1329 	}
1330 
1331 	n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
1332 	if (n < 0) {
1333 		*errp = h_errno;
1334 		return NULL;
1335 	}
1336 	hp = (HEADER *)answer;
1337 	eom = answer + n;
1338 	ancount = ntohs(hp->ancount);
1339 	qdcount = ntohs(hp->qdcount);
1340 	DNS_ASSERT(qdcount == 1);
1341 	cp = answer + sizeof(HEADER);
1342 	bp = hostbuf;
1343 	buflen = sizeof(hostbuf);
1344 
1345 	n = dn_expand(answer, eom, cp, bp, buflen);
1346 	DNS_ASSERT(n >= 0);
1347 	cp += n + QFIXEDSZ;
1348 	while (ancount-- > 0 && cp < eom) {
1349 		n = dn_expand(answer, eom, cp, bp, buflen);
1350 		DNS_ASSERT(n >= 0);
1351 		cp += n;		/* name */
1352 		type = _getshort(cp);
1353 		cp += 2;		/* type */
1354 		class = _getshort(cp);
1355 		cp += 2;		/* class */
1356 		ttl = _getlong(cp);
1357 		cp += 4;		/* ttl */
1358 		n = _getshort(cp);
1359 		cp += 2;		/* len */
1360 		DNS_ASSERT(class == C_IN);
1361 		switch (type) {
1362 		case T_PTR:
1363 			n = dn_expand(answer, eom, cp, bp, buflen);
1364 			DNS_ASSERT(n >= 0);
1365 			cp += n;
1366 			if (na >= MAXALIASES-1)
1367 				break;
1368 			if (hbuf.h_name == NULL)
1369 				hbuf.h_name = bp;
1370 			else
1371 				alist[na++] = bp;
1372 			n = strlen(bp) + 1;
1373 			bp += n;
1374 			buflen -= n;
1375 			break;
1376 		case T_CNAME:
1377 			cp += n;
1378 			break;
1379 		default:
1380   badanswer:
1381 			*errp = NO_RECOVERY;
1382 			return NULL;
1383 		}
1384 	}
1385 	if (hbuf.h_name == NULL) {
1386 		*errp = h_errno;
1387 		return NULL;
1388 	}
1389 	alist[na] = NULL;
1390 	return _hpcopy(&hbuf, errp);
1391 }
1392 
1393 #ifdef ICMPNL
1394 
1395 /*
1396  * experimental:
1397  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
1398  *	ifindex is assumed to be encoded in addr.
1399  */
1400 #include <sys/uio.h>
1401 #include <netinet/ip6.h>
1402 #include <netinet/icmp6.h>
1403 
1404 struct _icmp_host_cache {
1405 	struct _icmp_host_cache *hc_next;
1406 	int hc_ifindex;
1407 	struct in6_addr hc_addr;
1408 	char *hc_name;
1409 };
1410 
1411 static char *
1412 _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1413 {
1414 	int s;
1415 	struct icmp6_filter filter;
1416 	struct msghdr msg;
1417 	struct cmsghdr *cmsg;
1418 	struct in6_pktinfo *pkt;
1419 	char cbuf[256];
1420 	char buf[1024];
1421 	int cc;
1422 	struct icmp6_fqdn_query *fq;
1423 	struct icmp6_fqdn_reply *fr;
1424 	struct _icmp_host_cache *hc;
1425 	struct sockaddr_in6 sin6;
1426 	struct iovec iov;
1427 	fd_set s_fds, fds;
1428 	struct timeval tout;
1429 	int len;
1430 	char *name;
1431 	static int pid;
1432 	static struct _icmp_host_cache *hc_head;
1433 
1434 	for (hc = hc_head; hc; hc = hc->hc_next) {
1435 		if (hc->hc_ifindex == ifindex
1436 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1437 			return hc->hc_name;
1438 	}
1439 
1440 	if (pid == 0)
1441 		pid = getpid();
1442 
1443 	ICMP6_FILTER_SETBLOCKALL(&filter);
1444 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1445 
1446 	FD_ZERO(&s_fds);
1447 	tout.tv_sec = 0;
1448 	tout.tv_usec = 200000;	/*XXX: 200ms*/
1449 
1450 	fq = (struct icmp6_fqdn_query *)buf;
1451 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1452 	fq->icmp6_fqdn_code = 0;
1453 	fq->icmp6_fqdn_cksum = 0;
1454 	fq->icmp6_fqdn_id = (u_short)pid;
1455 	fq->icmp6_fqdn_unused = 0;
1456 	fq->icmp6_fqdn_cookie[0] = 0;
1457 	fq->icmp6_fqdn_cookie[1] = 0;
1458 
1459 	memset(&sin6, 0, sizeof(sin6));
1460 	sin6.sin6_family = AF_INET6;
1461 	sin6.sin6_addr = *addr;
1462 
1463 	memset(&msg, 0, sizeof(msg));
1464 	msg.msg_name = (caddr_t)&sin6;
1465 	msg.msg_namelen = sizeof(sin6);
1466 	msg.msg_iov = &iov;
1467 	msg.msg_iovlen = 1;
1468 	msg.msg_control = NULL;
1469 	msg.msg_controllen = 0;
1470 	iov.iov_base = (caddr_t)buf;
1471 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
1472 
1473 	if (ifindex) {
1474 		msg.msg_control = cbuf;
1475 		msg.msg_controllen = sizeof(cbuf);
1476 		cmsg = CMSG_FIRSTHDR(&msg);
1477 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1478 		cmsg->cmsg_level = IPPROTO_IPV6;
1479 		cmsg->cmsg_type = IPV6_PKTINFO;
1480 		pkt = (struct in6_pktinfo *)&cmsg[1];
1481 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1482 		pkt->ipi6_ifindex = ifindex;
1483 		cmsg = CMSG_NXTHDR(&msg, cmsg);
1484 		msg.msg_controllen = (char *)cmsg - cbuf;
1485 	}
1486 
1487 	if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1488 		return NULL;
1489 	(void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1490 			 (char *)&filter, sizeof(filter));
1491 	cc = sendmsg(s, &msg, 0);
1492 	if (cc < 0) {
1493 		_close(s);
1494 		return NULL;
1495 	}
1496 	FD_SET(s, &s_fds);
1497 	for (;;) {
1498 		fds = s_fds;
1499 		if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1500 			_close(s);
1501 			return NULL;
1502 		}
1503 		len = sizeof(sin6);
1504 		cc = recvfrom(s, buf, sizeof(buf), 0,
1505 			      (struct sockaddr *)&sin6, &len);
1506 		if (cc <= 0) {
1507 			_close(s);
1508 			return NULL;
1509 		}
1510 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1511 			continue;
1512 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1513 			continue;
1514 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1515 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1516 			break;
1517 	}
1518 	_close(s);
1519 	if (fr->icmp6_fqdn_cookie[1] != 0) {
1520 		/* rfc1788 type */
1521 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1522 		len = (buf + cc) - name;
1523 	} else {
1524 		len = fr->icmp6_fqdn_namelen;
1525 		name = fr->icmp6_fqdn_name;
1526 	}
1527 	if (len <= 0)
1528 		return NULL;
1529 	name[len] = 0;
1530 
1531 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1532 		return NULL;
1533 	/* XXX: limit number of cached entries */
1534 	hc->hc_ifindex = ifindex;
1535 	hc->hc_addr = *addr;
1536 	hc->hc_name = strdup(name);
1537 	hc->hc_next = hc_head;
1538 	hc_head = hc;
1539 	return hc->hc_name;
1540 }
1541 
1542 static struct hostent *
1543 _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1544 {
1545 	char *hname;
1546 	int ifindex;
1547 	struct in6_addr addr6;
1548 
1549 	if (af != AF_INET6) {
1550 		/*
1551 		 * Note: rfc1788 defines Who Are You for IPv4,
1552 		 * but no one implements it.
1553 		 */
1554 		return NULL;
1555 	}
1556 
1557 	memcpy(&addr6, addr, addrlen);
1558 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1559 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1560 
1561 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1562 		return NULL;	/*XXX*/
1563 
1564 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1565 		return NULL;
1566 	return _hpaddr(af, hname, &addr6, errp);
1567 }
1568 #endif /* ICMPNL */
1569