name6.c revision 59411
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: head/lib/libc/net/name6.c 59411 2000-04-20 03:31:40Z shin $
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) \
81do {									\
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
90union 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
105static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
106static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
107static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
108#ifdef INET6
109static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
110#endif
111static struct	 hostent *_hpsort(struct hostent *hp);
112static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
113static char	*_hgetword(char **pp);
114static int	 _mapped_addr_enabled(void);
115
116static FILE	*_files_open(int *errp);
117static struct	 hostent *_files_ghbyname(const char *name, int af, int *errp);
118static struct	 hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
119static void	 _files_shent(int stayopen);
120static void	 _files_ehent(void);
121static struct	 hostent *_nis_ghbyname(const char *name, int af, int *errp);
122static struct	 hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
123static struct	 hostent *_dns_ghbyname(const char *name, int af, int *errp);
124static struct	 hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
125static void	 _dns_shent(int stayopen);
126static void	 _dns_ehent(void);
127#ifdef ICMPNL
128static 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
140struct _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 */
146static 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
154static int	_hostconf_init_done;
155static void	_hostconf_init(void);
156
157/*
158 * Initialize hostconf structure.
159 */
160
161static 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
226static 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
251static 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. */
297struct 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
362struct hostent *
363getipnodebyname(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
377struct hostent *
378getipnodebyaddr(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
440void
441freehostent(struct hostent *ptr)
442{
443	free(ptr);
444}
445
446#if 0
447
448/* XXX: should be deprecated */
449struct hostent *
450getnodebyname(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
461struct hostent *
462getnodebyaddr(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 */
482static 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 */
561static 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 */
581static 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
653static 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 */
680static 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
728static 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
763static 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
773static 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
854static 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 */
903static 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
919static 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
938struct __res_type_list {
939        SLIST_ENTRY(__res_type_list) rtl_entry;
940        int     rtl_type;
941};
942
943static 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. */
1057static 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
1229static 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
1260static 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
1404struct _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
1411static 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
1542static 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