name6.c revision 62427
1/*	$FreeBSD: head/lib/libc/net/name6.c 62427 2000-07-03 02:33:02Z kris $	*/
2/*	$KAME: name6.c,v 1.22 2000/05/01 08:19:08 itojun Exp $	*/
3
4/*
5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32/*
33 * ++Copyright++ 1985, 1988, 1993
34 * -
35 * Copyright (c) 1985, 1988, 1993
36 *    The Regents of the University of California.  All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 *    must display the following acknowledgement:
48 * 	This product includes software developed by the University of
49 * 	California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 *    may be used to endorse or promote products derived from this software
52 *    without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 * -
66 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
67 *
68 * Permission to use, copy, modify, and distribute this software for any
69 * purpose with or without fee is hereby granted, provided that the above
70 * copyright notice and this permission notice appear in all copies, and that
71 * the name of Digital Equipment Corporation not be used in advertising or
72 * publicity pertaining to distribution of the document or software without
73 * specific, written prior permission.
74 *
75 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
76 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
77 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
78 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
79 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
80 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
81 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
82 * SOFTWARE.
83 * -
84 * --Copyright--
85 */
86
87/*
88 *	Atsushi Onoe <onoe@sm.sony.co.jp>
89 */
90
91/*
92 * TODO for thread safe
93 *	use mutex for _hostconf, _hostconf_init.
94 *	rewrite resolvers to be thread safe
95 */
96
97#include <sys/param.h>
98#include <sys/socket.h>
99#include <sys/time.h>
100#include <sys/queue.h>
101#include <netinet/in.h>
102
103#include <arpa/inet.h>
104#include <arpa/nameser.h>
105
106#include <errno.h>
107#include <netdb.h>
108#include <resolv.h>
109#include <stdio.h>
110#include <stdlib.h>
111#include <string.h>
112#include <unistd.h>
113
114#ifndef _PATH_HOSTS
115#define	_PATH_HOSTS	"/etc/hosts"
116#endif
117
118#ifndef MAXALIASES
119#define	MAXALIASES	10
120#endif
121#ifndef	MAXADDRS
122#define	MAXADDRS	20
123#endif
124#ifndef MAXDNAME
125#define	MAXDNAME	1025
126#endif
127
128#ifdef INET6
129#define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
130					    sizeof(struct in_addr))
131#else
132#define	ADDRLEN(af)	sizeof(struct in_addr)
133#endif
134
135#define	MAPADDR(ab, ina) \
136do {									\
137	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
138	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
139	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
140} while (0)
141#define	MAPADDRENABLED(flags) \
142	(((flags) & AI_V4MAPPED) || \
143	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
144
145union inx_addr {
146	struct in_addr	in_addr;
147#ifdef INET6
148	struct in6_addr	in6_addr;
149#endif
150	struct {
151		u_char	mau_zero[10];
152		u_char	mau_one[2];
153		struct in_addr mau_inaddr;
154	}		map_addr_un;
155#define	map_zero	map_addr_un.mau_zero
156#define	map_one		map_addr_un.mau_one
157#define	map_inaddr	map_addr_un.mau_inaddr
158};
159
160static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
161static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
162static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
163#ifdef INET6
164static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
165#endif
166static struct	 hostent *_hpsort(struct hostent *hp);
167static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
168static char	*_hgetword(char **pp);
169static int	 _mapped_addr_enabled(void);
170
171static FILE	*_files_open(int *errp);
172static struct	 hostent *_files_ghbyname(const char *name, int af, int *errp);
173static struct	 hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
174static void	 _files_shent(int stayopen);
175static void	 _files_ehent(void);
176#ifdef YP
177static struct	 hostent *_nis_ghbyname(const char *name, int af, int *errp);
178static struct	 hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
179#endif
180static struct	 hostent *_dns_ghbyname(const char *name, int af, int *errp);
181static struct	 hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
182static void	 _dns_shent(int stayopen);
183static void	 _dns_ehent(void);
184#ifdef ICMPNL
185static struct	 hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
186#endif /* ICMPNL */
187
188/*
189 * Select order host function.
190 */
191#define	MAXHOSTCONF	4
192
193#ifndef HOSTCONF
194#  define	HOSTCONF	"/etc/host.conf"
195#endif /* !HOSTCONF */
196
197struct _hostconf {
198	struct hostent *(*byname)(const char *name, int af, int *errp);
199	struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
200};
201
202/* default order */
203static struct _hostconf _hostconf[MAXHOSTCONF] = {
204	{ _dns_ghbyname,	_dns_ghbyaddr },
205	{ _files_ghbyname,	_files_ghbyaddr },
206#ifdef ICMPNL
207	{ NULL,			_icmp_ghbyaddr },
208#endif /* ICMPNL */
209};
210
211static int	_hostconf_init_done;
212static void	_hostconf_init(void);
213
214/*
215 * Initialize hostconf structure.
216 */
217
218static void
219_hostconf_init(void)
220{
221	FILE *fp;
222	int n;
223	char *p, *line;
224	char buf[BUFSIZ];
225
226	_hostconf_init_done = 1;
227	n = 0;
228	p = HOSTCONF;
229	if ((fp = fopen(p, "r")) == NULL)
230		return;
231	while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
232		line = buf;
233		if ((p = _hgetword(&line)) == NULL)
234			continue;
235		do {
236			if (strcmp(p, "hosts") == 0
237			||  strcmp(p, "local") == 0
238			||  strcmp(p, "file") == 0
239			||  strcmp(p, "files") == 0) {
240				_hostconf[n].byname = _files_ghbyname;
241				_hostconf[n].byaddr = _files_ghbyaddr;
242				n++;
243			}
244			else if (strcmp(p, "dns") == 0
245			     ||  strcmp(p, "bind") == 0) {
246				_hostconf[n].byname = _dns_ghbyname;
247				_hostconf[n].byaddr = _dns_ghbyaddr;
248				n++;
249			}
250#ifdef YP
251			else if (strcmp(p, "nis") == 0) {
252				_hostconf[n].byname = _nis_ghbyname;
253				_hostconf[n].byaddr = _nis_ghbyaddr;
254				n++;
255			}
256#endif
257#ifdef ICMPNL
258			else if (strcmp(p, "icmp") == 0) {
259				_hostconf[n].byname = NULL;
260				_hostconf[n].byaddr = _icmp_ghbyaddr;
261				n++;
262			}
263#endif /* ICMPNL */
264		} while ((p = _hgetword(&line)) != NULL);
265	}
266	fclose(fp);
267	if (n < 0) {
268		/* no keyword found. do not change default configuration */
269		return;
270	}
271	for (; n < MAXHOSTCONF; n++) {
272		_hostconf[n].byname = NULL;
273		_hostconf[n].byaddr = NULL;
274	}
275}
276
277/*
278 * Check if kernel supports mapped address.
279 *	implementation dependent
280 */
281#ifdef __KAME__
282#include <sys/sysctl.h>
283#endif /* __KAME__ */
284
285static int
286_mapped_addr_enabled(void)
287{
288	/* implementation dependent check */
289#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
290	int mib[4];
291	size_t len;
292	int val;
293
294	mib[0] = CTL_NET;
295	mib[1] = PF_INET6;
296	mib[2] = IPPROTO_IPV6;
297	mib[3] = IPV6CTL_MAPPED_ADDR;
298	len = sizeof(val);
299	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
300		return 1;
301#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
302	return 0;
303}
304
305/*
306 * Functions defined in RFC2553
307 *	getipnodebyname, getipnodebyaddr, freehostent
308 */
309
310static struct hostent *
311_ghbyname(const char *name, int af, int flags, int *errp)
312{
313	struct hostent *hp;
314	int i;
315
316	if (flags & AI_ADDRCONFIG) {
317		int s;
318
319		/*
320		 * TODO:
321		 * Note that implementation dependent test for address
322		 * configuration should be done everytime called
323		 * (or apropriate interval),
324		 * because addresses will be dynamically assigned or deleted.
325		 */
326		if (af == AF_UNSPEC) {
327			if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
328				af = AF_INET;
329			else {
330				_close(s);
331				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
332					af = AF_INET6;
333				else
334				_close(s);
335			}
336
337		}
338		if (af != AF_UNSPEC) {
339			if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
340				return NULL;
341			_close(s);
342		}
343	}
344
345	for (i = 0; i < MAXHOSTCONF; i++) {
346		if (_hostconf[i].byname
347		 && (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL)
348			return hp;
349	}
350
351	return NULL;
352}
353
354/* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
355struct hostent *
356_getipnodebyname_multi(const char *name, int af, int flags, int *errp)
357{
358	struct hostent *hp;
359	union inx_addr addrbuf;
360
361	/* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */
362	if (af != AF_INET
363#ifdef INET6
364	    && af != AF_INET6
365#endif
366	    && af != PF_UNSPEC
367		)
368	{
369		*errp = NO_RECOVERY;
370		return NULL;
371	}
372
373#ifdef INET6
374	/* special case for literal address */
375	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
376		if (af != AF_INET6) {
377			*errp = HOST_NOT_FOUND;
378			return NULL;
379		}
380		return _hpaddr(af, name, &addrbuf, errp);
381	}
382#endif
383	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
384		if (af != AF_INET) {
385			if (MAPADDRENABLED(flags)) {
386				MAPADDR(&addrbuf, &addrbuf.in_addr);
387			} else {
388				*errp = HOST_NOT_FOUND;
389				return NULL;
390			}
391		}
392		return _hpaddr(af, name, &addrbuf, errp);
393	}
394
395	if (!_hostconf_init_done)
396		_hostconf_init();
397
398	*errp = HOST_NOT_FOUND;
399	hp = _ghbyname(name, af, flags, errp);
400
401#ifdef INET6
402	if (af == AF_INET6
403	&&  ((flags & AI_ALL) || hp == NULL)
404	&&  (MAPADDRENABLED(flags))) {
405		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
406		if (hp == NULL)
407			hp = _hpmapv6(hp2, errp);
408		else {
409			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
410				freehostent(hp2);
411				hp2 = NULL;
412			}
413			hp = _hpmerge(hp, hp2, errp);
414		}
415	}
416#endif
417	return _hpsort(hp);
418}
419
420struct hostent *
421getipnodebyname(const char *name, int af, int flags, int *errp)
422{
423	if (af != AF_INET
424#ifdef INET6
425	    && af != AF_INET6
426#endif
427		)
428	{
429		*errp = NO_RECOVERY;
430		return NULL;
431	}
432	return(_getipnodebyname_multi(name, af ,flags, errp));
433}
434
435struct hostent *
436getipnodebyaddr(const void *src, size_t len, int af, int *errp)
437{
438	struct hostent *hp;
439	int i;
440#ifdef INET6
441	struct in6_addr addrbuf;
442#else
443	struct in_addr addrbuf;
444#endif
445
446	*errp = HOST_NOT_FOUND;
447
448	switch (af) {
449	case AF_INET:
450		if (len != sizeof(struct in_addr)) {
451			*errp = NO_RECOVERY;
452			return NULL;
453		}
454		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
455			memcpy(&addrbuf, src, len);
456			src = &addrbuf;
457		}
458		if (((struct in_addr *)src)->s_addr == 0)
459			return NULL;
460		break;
461#ifdef INET6
462	case AF_INET6:
463		if (len != sizeof(struct in6_addr)) {
464			*errp = NO_RECOVERY;
465			return NULL;
466		}
467		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
468			memcpy(&addrbuf, src, len);
469			src = &addrbuf;
470		}
471		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
472			return NULL;
473		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
474		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
475			src = (char *)src +
476			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
477			af = AF_INET;
478			len = sizeof(struct in_addr);
479		}
480		break;
481#endif
482	default:
483		*errp = NO_RECOVERY;
484		return NULL;
485	}
486
487	if (!_hostconf_init_done)
488		_hostconf_init();
489	for (i = 0; i < MAXHOSTCONF; i++) {
490		if (_hostconf[i].byaddr
491		&&  (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
492			return hp;
493	}
494
495	return NULL;
496}
497
498void
499freehostent(struct hostent *ptr)
500{
501	free(ptr);
502}
503
504#if 0
505
506/* XXX: should be deprecated */
507struct hostent *
508getnodebyname(const char *name, int af, int flags)
509{
510	return getipnodebyname(name, af, flags, &h_errno);
511}
512
513#ifdef __warn_references
514__warn_references(getnodebyname,
515	"warning: getnodebyname() deprecated, "
516	"should use getaddrinfo() or getipnodebyname()");
517#endif
518
519struct hostent *
520getnodebyaddr(const void *src, size_t len, int af)
521{
522	return getipnodebyaddr(src, len, af, &h_errno);
523}
524
525#ifdef __warn_references
526__warn_references(getnodebyaddr,
527	"warning: getnodebyaddr() deprecated, "
528	"should use getnameinfo() or getipnodebyaddr()");
529#endif
530
531#endif
532
533/*
534 * Private utility functions
535 */
536
537/*
538 * _hpcopy: allocate and copy hostent structure
539 */
540static struct hostent *
541_hpcopy(struct hostent *hp, int *errp)
542{
543	struct hostent *nhp;
544	char *cp, **pp;
545	int size, addrsize;
546	int nalias = 0, naddr = 0;
547	int al_off;
548	int i;
549
550	if (hp == NULL)
551		return hp;
552
553	/* count size to be allocated */
554	size = sizeof(struct hostent);
555	if (hp->h_name != NULL && *hp->h_name != '\0')
556		size += strlen(hp->h_name) + 1;
557	if ((pp = hp->h_aliases) != NULL) {
558		for (i = 0; *pp != NULL; i++, pp++) {
559			if (**pp != '\0') {
560				size += strlen(*pp) + 1;
561				nalias++;
562			}
563		}
564	}
565	/* adjust alignment */
566	size = ALIGN(size);
567	al_off = size;
568	size += sizeof(char *) * (nalias + 1);
569	addrsize = ALIGN(hp->h_length);
570	if ((pp = hp->h_addr_list) != NULL) {
571		while (*pp++ != NULL)
572			naddr++;
573	}
574	size += addrsize * naddr;
575	size += sizeof(char *) * (naddr + 1);
576
577	/* copy */
578	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
579		*errp = TRY_AGAIN;
580		return NULL;
581	}
582	cp = (char *)&nhp[1];
583	if (hp->h_name != NULL && *hp->h_name != '\0') {
584		nhp->h_name = cp;
585		strcpy(cp, hp->h_name);
586		cp += strlen(cp) + 1;
587	} else
588		nhp->h_name = NULL;
589	nhp->h_aliases = (char **)((char *)nhp + al_off);
590	if ((pp = hp->h_aliases) != NULL) {
591		for (i = 0; *pp != NULL; pp++) {
592			if (**pp != '\0') {
593				nhp->h_aliases[i++] = cp;
594				strcpy(cp, *pp);
595				cp += strlen(cp) + 1;
596			}
597		}
598	}
599	nhp->h_aliases[nalias] = NULL;
600	cp = (char *)&nhp->h_aliases[nalias + 1];
601	nhp->h_addrtype = hp->h_addrtype;
602	nhp->h_length = hp->h_length;
603	nhp->h_addr_list = (char **)cp;
604	if ((pp = hp->h_addr_list) != NULL) {
605		cp = (char *)&nhp->h_addr_list[naddr + 1];
606		for (i = 0; *pp != NULL; pp++) {
607			nhp->h_addr_list[i++] = cp;
608			memcpy(cp, *pp, hp->h_length);
609			cp += addrsize;
610		}
611	}
612	nhp->h_addr_list[naddr] = NULL;
613	return nhp;
614}
615
616/*
617 * _hpaddr: construct hostent structure with one address
618 */
619static struct hostent *
620_hpaddr(int af, const char *name, void *addr, int *errp)
621{
622	struct hostent *hp, hpbuf;
623	char *addrs[2];
624
625	hp = &hpbuf;
626	hp->h_name = (char *)name;
627	hp->h_aliases = NULL;
628	hp->h_addrtype = af;
629	hp->h_length = ADDRLEN(af);
630	hp->h_addr_list = addrs;
631	addrs[0] = (char *)addr;
632	addrs[1] = NULL;
633	return _hpcopy(hp, errp);
634}
635
636/*
637 * _hpmerge: merge 2 hostent structure, arguments will be freed
638 */
639static struct hostent *
640_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
641{
642	int i, j;
643	int naddr, nalias;
644	char **pp;
645	struct hostent *hp, hpbuf;
646	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
647	union inx_addr addrbuf[MAXADDRS];
648
649	if (hp1 == NULL)
650		return hp2;
651	if (hp2 == NULL)
652		return hp1;
653
654#define	HP(i)	(i == 1 ? hp1 : hp2)
655	hp = &hpbuf;
656	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
657	hp->h_aliases = aliases;
658	nalias = 0;
659	for (i = 1; i <= 2; i++) {
660		if ((pp = HP(i)->h_aliases) == NULL)
661			continue;
662		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
663			/* check duplicates */
664			for (j = 0; j < nalias; j++)
665				if (strcasecmp(*pp, aliases[j]) == 0)
666					break;
667			if (j == nalias)
668				aliases[nalias++] = *pp;
669		}
670	}
671	aliases[nalias] = NULL;
672#ifdef INET6
673	if (hp1->h_length != hp2->h_length) {
674		hp->h_addrtype = AF_INET6;
675		hp->h_length = sizeof(struct in6_addr);
676	} else {
677#endif
678		hp->h_addrtype = hp1->h_addrtype;
679		hp->h_length = hp1->h_length;
680#ifdef INET6
681	}
682#endif
683	hp->h_addr_list = addrs;
684	naddr = 0;
685	for (i = 1; i <= 2; i++) {
686		if ((pp = HP(i)->h_addr_list) == NULL)
687			continue;
688		if (HP(i)->h_length == hp->h_length) {
689			while (naddr < MAXADDRS && *pp != NULL)
690				addrs[naddr++] = *pp++;
691		} else {
692			/* copy IPv4 addr as mapped IPv6 addr */
693			while (naddr < MAXADDRS && *pp != NULL) {
694				MAPADDR(&addrbuf[naddr], *pp++);
695				addrs[naddr] = (char *)&addrbuf[naddr];
696				naddr++;
697			}
698		}
699	}
700	addrs[naddr] = NULL;
701	hp = _hpcopy(hp, errp);
702	freehostent(hp1);
703	freehostent(hp2);
704	return hp;
705}
706
707/*
708 * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
709 */
710#ifdef INET6
711static struct hostent *
712_hpmapv6(struct hostent *hp, int *errp)
713{
714	struct hostent *hp6;
715
716	if (hp == NULL)
717		return NULL;
718	if (hp->h_addrtype == AF_INET6)
719		return hp;
720
721	/* make dummy hostent to convert IPv6 address */
722	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
723		*errp = TRY_AGAIN;
724		return NULL;
725	}
726	hp6->h_name = NULL;
727	hp6->h_aliases = NULL;
728	hp6->h_addrtype = AF_INET6;
729	hp6->h_length = sizeof(struct in6_addr);
730	hp6->h_addr_list = NULL;
731	return _hpmerge(hp6, hp, errp);
732}
733#endif
734
735/*
736 * _hpsort: sort address by sortlist
737 */
738static struct hostent *
739_hpsort(struct hostent *hp)
740{
741	int i, j, n;
742	u_char *ap, *sp, *mp, **pp;
743	char t;
744	char order[MAXADDRS];
745	int nsort = _res.nsort;
746
747	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
748		return hp;
749	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
750		for (j = 0; j < nsort; j++) {
751#ifdef INET6
752			if (_res_ext.sort_list[j].af != hp->h_addrtype)
753				continue;
754			sp = (u_char *)&_res_ext.sort_list[j].addr;
755			mp = (u_char *)&_res_ext.sort_list[j].mask;
756#else
757			sp = (u_char *)&_res.sort_list[j].addr;
758			mp = (u_char *)&_res.sort_list[j].mask;
759#endif
760			for (n = 0; n < hp->h_length; n++) {
761				if ((ap[n] & mp[n]) != sp[n])
762					break;
763			}
764			if (n == hp->h_length)
765				break;
766		}
767		order[i] = j;
768	}
769	n = i;
770	pp = (u_char **)hp->h_addr_list;
771	for (i = 0; i < n - 1; i++) {
772		for (j = i + 1; j < n; j++) {
773			if (order[i] > order[j]) {
774				ap = pp[i];
775				pp[i] = pp[j];
776				pp[j] = ap;
777				t = order[i];
778				order[i] = order[j];
779				order[j] = t;
780			}
781		}
782	}
783	return hp;
784}
785
786static char *
787_hgetword(char **pp)
788{
789	char c, *p, *ret;
790	const char *sp;
791	static const char sep[] = "# \t\n";
792
793	ret = NULL;
794	for (p = *pp; (c = *p) != '\0'; p++) {
795		for (sp = sep; *sp != '\0'; sp++) {
796			if (c == *sp)
797				break;
798		}
799		if (c == '#')
800			p[1] = '\0';	/* ignore rest of line */
801		if (ret == NULL) {
802			if (*sp == '\0')
803				ret = p;
804		} else {
805			if (*sp != '\0') {
806				*p++ = '\0';
807				break;
808			}
809		}
810	}
811	*pp = p;
812	if (ret == NULL || *ret == '\0')
813		return NULL;
814	return ret;
815}
816
817/*
818 * FILES (/etc/hosts)
819 */
820
821static FILE *
822_files_open(int *errp)
823{
824	FILE *fp;
825	fp = fopen(_PATH_HOSTS, "r");
826	if (fp == NULL)
827		*errp = NO_RECOVERY;
828	return fp;
829}
830
831static struct hostent *
832_files_ghbyname(const char *name, int af, int *errp)
833{
834	int match, nalias;
835	char *p, *line, *addrstr, *cname;
836	FILE *fp;
837	struct hostent *rethp, *hp, hpbuf;
838	char *aliases[MAXALIASES + 1], *addrs[2];
839	union inx_addr addrbuf;
840	char buf[BUFSIZ];
841	int af0 = af;
842
843	if ((fp = _files_open(errp)) == NULL)
844		return NULL;
845	rethp = hp = NULL;
846
847	while (fgets(buf, sizeof(buf), fp)) {
848		line = buf;
849		if ((addrstr = _hgetword(&line)) == NULL
850		||  (cname = _hgetword(&line)) == NULL)
851			continue;
852		match = (strcasecmp(cname, name) == 0);
853		nalias = 0;
854		while ((p = _hgetword(&line)) != NULL) {
855			if (!match)
856				match = (strcasecmp(p, name) == 0);
857			if (nalias < MAXALIASES)
858				aliases[nalias++] = p;
859		}
860		if (!match)
861			continue;
862		switch (af0) {
863		case AF_INET:
864			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
865			    != 1) {
866				*errp = NO_DATA;	/* name found */
867				continue;
868			}
869			af = af0;
870			break;
871#ifdef INET6
872		case AF_INET6:
873			if (inet_pton(af, addrstr, &addrbuf) != 1) {
874				*errp = NO_DATA;	/* name found */
875				continue;
876			}
877			af = af0;
878			break;
879#endif
880		case AF_UNSPEC:
881			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
882			    == 1) {
883				af = AF_INET;
884				break;
885			}
886#ifdef INET6
887			if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) {
888				af = AF_INET6;
889				break;
890			}
891#endif
892			*errp = NO_DATA;	/* name found */
893			continue;
894			/* NOTREACHED */
895		}
896		hp = &hpbuf;
897		hp->h_name = cname;
898		hp->h_aliases = aliases;
899		aliases[nalias] = NULL;
900		hp->h_addrtype = af;
901		hp->h_length = ADDRLEN(af);
902		hp->h_addr_list = addrs;
903		addrs[0] = (char *)&addrbuf;
904		addrs[1] = NULL;
905		hp = _hpcopy(hp, errp);
906		rethp = _hpmerge(rethp, hp, errp);
907	}
908	fclose(fp);
909	return rethp;
910}
911
912static struct hostent *
913_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
914{
915	int nalias;
916	char *p, *line;
917	FILE *fp;
918	struct hostent *hp, hpbuf;
919	char *aliases[MAXALIASES + 1], *addrs[2];
920	union inx_addr addrbuf;
921	char buf[BUFSIZ];
922
923	if ((fp = _files_open(errp)) == NULL)
924		return NULL;
925	hp = NULL;
926	while (fgets(buf, sizeof(buf), fp)) {
927		line = buf;
928		if ((p = _hgetword(&line)) == NULL
929		||  (af == AF_INET
930		     ? inet_aton(p, (struct in_addr *)&addrbuf)
931		     : inet_pton(af, p, &addrbuf)) != 1
932		||  memcmp(addr, &addrbuf, addrlen) != 0
933		||  (p = _hgetword(&line)) == NULL)
934			continue;
935		hp = &hpbuf;
936		hp->h_name = p;
937		hp->h_aliases = aliases;
938		nalias = 0;
939		while ((p = _hgetword(&line)) != NULL) {
940			if (nalias < MAXALIASES)
941				aliases[nalias++] = p;
942		}
943		aliases[nalias] = NULL;
944		hp->h_addrtype = af;
945		hp->h_length = addrlen;
946		hp->h_addr_list = addrs;
947		addrs[0] = (char *)&addrbuf;
948		addrs[1] = NULL;
949		hp = _hpcopy(hp, errp);
950		break;
951	}
952	fclose(fp);
953	return hp;
954}
955
956#ifdef YP
957/*
958 * NIS
959 *
960 * XXX actually a hack, these are INET4 specific.
961 */
962static struct hostent *
963_nis_ghbyname(const char *name, int af, int *errp)
964{
965	struct hostent *hp = NULL;
966
967	if (af == AF_UNSPEC)
968		af = AF_INET;
969	if (af == AF_INET) {
970		hp = _gethostbynisname(name, af);
971		if (hp != NULL)
972			hp = _hpcopy(hp, errp);
973	}
974	return (hp);
975
976}
977
978static struct hostent *
979_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
980{
981	struct hostent *hp = NULL;
982
983	if (af == AF_INET) {
984		hp = _gethostbynisaddr(addr, addrlen, af);
985		if (hp != NULL)
986			hp = _hpcopy(hp, errp);
987	}
988	return (hp);
989}
990#endif
991
992struct __res_type_list {
993        SLIST_ENTRY(__res_type_list) rtl_entry;
994        int     rtl_type;
995};
996
997#if PACKETSZ > 1024
998#define	MAXPACKET	PACKETSZ
999#else
1000#define	MAXPACKET	1024
1001#endif
1002
1003typedef union {
1004	HEADER hdr;
1005	u_char buf[MAXPACKET];
1006} querybuf;
1007
1008static struct hostent *getanswer __P((const querybuf *, int, const char *,
1009	int, struct hostent *, int *));
1010
1011/*
1012 * we don't need to take care about sorting, nor IPv4 mapped address here.
1013 */
1014static struct hostent *
1015getanswer(answer, anslen, qname, qtype, template, errp)
1016	const querybuf *answer;
1017	int anslen;
1018	const char *qname;
1019	int qtype;
1020	struct hostent *template;
1021	int *errp;
1022{
1023	register const HEADER *hp;
1024	register const u_char *cp;
1025	register int n;
1026	const u_char *eom, *erdata;
1027	char *bp, **ap, **hap;
1028	int type, class, buflen, ancount, qdcount;
1029	int haveanswer, had_error;
1030	char tbuf[MAXDNAME];
1031	const char *tname;
1032	int (*name_ok) __P((const char *));
1033	static char *h_addr_ptrs[MAXADDRS + 1];
1034	static char *host_aliases[MAXALIASES];
1035	static char hostbuf[8*1024];
1036
1037#define BOUNDED_INCR(x) \
1038	do { \
1039		cp += x; \
1040		if (cp > eom) { \
1041			*errp = NO_RECOVERY; \
1042			return (NULL); \
1043		} \
1044	} while (0)
1045
1046#define BOUNDS_CHECK(ptr, count) \
1047	do { \
1048		if ((ptr) + (count) > eom) { \
1049			*errp = NO_RECOVERY; \
1050			return (NULL); \
1051		} \
1052	} while (0)
1053
1054#define DNS_ASSERT(x) \
1055	do {				\
1056		if (!(x)) {		\
1057			cp += n;	\
1058			continue;	\
1059		}			\
1060	} while (0)
1061
1062#define DNS_FATAL(x) \
1063	do {				\
1064		if (!(x)) {		\
1065			had_error++;	\
1066			continue;	\
1067		}			\
1068	} while (0)
1069
1070	tname = qname;
1071	template->h_name = NULL;
1072	eom = answer->buf + anslen;
1073	switch (qtype) {
1074	case T_A:
1075	case T_AAAA:
1076		name_ok = res_hnok;
1077		break;
1078	case T_PTR:
1079		name_ok = res_dnok;
1080		break;
1081	default:
1082		return (NULL);	/* XXX should be abort(); */
1083	}
1084	/*
1085	 * find first satisfactory answer
1086	 */
1087	hp = &answer->hdr;
1088	ancount = ntohs(hp->ancount);
1089	qdcount = ntohs(hp->qdcount);
1090	bp = hostbuf;
1091	buflen = sizeof hostbuf;
1092	cp = answer->buf;
1093	BOUNDED_INCR(HFIXEDSZ);
1094	if (qdcount != 1) {
1095		*errp = NO_RECOVERY;
1096		return (NULL);
1097	}
1098	n = dn_expand(answer->buf, eom, cp, bp, buflen);
1099	if ((n < 0) || !(*name_ok)(bp)) {
1100		*errp = NO_RECOVERY;
1101		return (NULL);
1102	}
1103	BOUNDED_INCR(n + QFIXEDSZ);
1104	if (qtype == T_A || qtype == T_AAAA) {
1105		/* res_send() has already verified that the query name is the
1106		 * same as the one we sent; this just gets the expanded name
1107		 * (i.e., with the succeeding search-domain tacked on).
1108		 */
1109		n = strlen(bp) + 1;		/* for the \0 */
1110		if (n >= MAXHOSTNAMELEN) {
1111			*errp = NO_RECOVERY;
1112			return (NULL);
1113		}
1114		template->h_name = bp;
1115		bp += n;
1116		buflen -= n;
1117		/* The qname can be abbreviated, but h_name is now absolute. */
1118		qname = template->h_name;
1119	}
1120	ap = host_aliases;
1121	*ap = NULL;
1122	template->h_aliases = host_aliases;
1123	hap = h_addr_ptrs;
1124	*hap = NULL;
1125	template->h_addr_list = h_addr_ptrs;
1126	haveanswer = 0;
1127	had_error = 0;
1128	while (ancount-- > 0 && cp < eom && !had_error) {
1129		n = dn_expand(answer->buf, eom, cp, bp, buflen);
1130		DNS_FATAL(n >= 0);
1131		DNS_FATAL((*name_ok)(bp));
1132		cp += n;			/* name */
1133		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
1134		type = _getshort(cp);
1135 		cp += INT16SZ;			/* type */
1136		class = _getshort(cp);
1137 		cp += INT16SZ + INT32SZ;	/* class, TTL */
1138		n = _getshort(cp);
1139		cp += INT16SZ;			/* len */
1140		BOUNDS_CHECK(cp, n);
1141		erdata = cp + n;
1142		DNS_ASSERT(class == C_IN);
1143		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
1144			if (ap >= &host_aliases[MAXALIASES-1])
1145				continue;
1146			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1147			DNS_FATAL(n >= 0);
1148			DNS_FATAL((*name_ok)(tbuf));
1149			cp += n;
1150			if (cp != erdata) {
1151				*errp = NO_RECOVERY;
1152				return (NULL);
1153			}
1154			/* Store alias. */
1155			*ap++ = bp;
1156			n = strlen(bp) + 1;	/* for the \0 */
1157			DNS_FATAL(n < MAXHOSTNAMELEN);
1158			bp += n;
1159			buflen -= n;
1160			/* Get canonical name. */
1161			n = strlen(tbuf) + 1;	/* for the \0 */
1162			DNS_FATAL(n <= buflen);
1163			DNS_FATAL(n < MAXHOSTNAMELEN);
1164			strcpy(bp, tbuf);
1165			template->h_name = bp;
1166			bp += n;
1167			buflen -= n;
1168			continue;
1169		}
1170		if (qtype == T_PTR && type == T_CNAME) {
1171			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1172			if (n < 0 || !res_dnok(tbuf)) {
1173				had_error++;
1174				continue;
1175			}
1176			cp += n;
1177			if (cp != erdata) {
1178				*errp = NO_RECOVERY;
1179				return (NULL);
1180			}
1181			/* Get canonical name. */
1182			n = strlen(tbuf) + 1;	/* for the \0 */
1183			if (n > buflen || n >= MAXHOSTNAMELEN) {
1184				had_error++;
1185				continue;
1186			}
1187			strcpy(bp, tbuf);
1188			template->h_name = bp;
1189			bp += n;
1190			buflen -= n;
1191			continue;
1192		}
1193		DNS_ASSERT(type == qtype);
1194		switch (type) {
1195		case T_PTR:
1196			DNS_ASSERT(strcasecmp(tname, bp) == 0);
1197			n = dn_expand(answer->buf, eom, cp, bp, buflen);
1198			DNS_FATAL(n >= 0);
1199			DNS_FATAL(res_hnok(bp));
1200#if MULTI_PTRS_ARE_ALIASES
1201			cp += n;
1202			if (cp != erdata) {
1203				*errp = NO_RECOVERY;
1204				return (NULL);
1205			}
1206			if (!haveanswer)
1207				template->h_name = bp;
1208			else if (ap < &host_aliases[MAXALIASES-1])
1209				*ap++ = bp;
1210			else
1211				n = -1;
1212			if (n != -1) {
1213				n = strlen(bp) + 1;	/* for the \0 */
1214				if (n >= MAXHOSTNAMELEN) {
1215					had_error++;
1216					break;
1217				}
1218				bp += n;
1219				buflen -= n;
1220			}
1221			break;
1222#else
1223			template->h_name = bp;
1224			*errp = NETDB_SUCCESS;
1225			return (template);
1226#endif
1227		case T_A:
1228		case T_AAAA:
1229			DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
1230			DNS_ASSERT(n == template->h_length);
1231			if (!haveanswer) {
1232				register int nn;
1233
1234				template->h_name = bp;
1235				nn = strlen(bp) + 1;	/* for the \0 */
1236				bp += nn;
1237				buflen -= nn;
1238			}
1239			bp = (char *)ALIGN(bp);
1240
1241			DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]);
1242			DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
1243#ifdef FILTER_V4MAPPED
1244			if (type == T_AAAA) {
1245				struct in6_addr in6;
1246				memcpy(&in6, cp, sizeof(in6));
1247				DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
1248			}
1249#endif
1250			bcopy(cp, *hap++ = bp, n);
1251			bp += n;
1252			buflen -= n;
1253			cp += n;
1254			if (cp != erdata) {
1255				*errp = NO_RECOVERY;
1256				return (NULL);
1257			}
1258			break;
1259		default:
1260			abort();
1261		}
1262		if (!had_error)
1263			haveanswer++;
1264	}
1265	if (haveanswer) {
1266		*ap = NULL;
1267		*hap = NULL;
1268		if (!template->h_name) {
1269			n = strlen(qname) + 1;	/* for the \0 */
1270			if (n > buflen || n >= MAXHOSTNAMELEN)
1271				goto no_recovery;
1272			strcpy(bp, qname);
1273			template->h_name = bp;
1274			bp += n;
1275			buflen -= n;
1276		}
1277		*errp = NETDB_SUCCESS;
1278		return (template);
1279	}
1280 no_recovery:
1281	*errp = NO_RECOVERY;
1282	return (NULL);
1283
1284#undef BOUNDED_INCR
1285#undef BOUNDS_CHECK
1286#undef DNS_ASSERT
1287#undef DNS_FATAL
1288}
1289
1290/* res_search() variant with multiple query support. */
1291static struct hostent *
1292_res_search_multi(name, rtl, errp)
1293	const char *name;	/* domain name */
1294	struct	__res_type_list *rtl; /* list of query types */
1295	int *errp;
1296{
1297	const char *cp, * const *domain;
1298	struct hostent *hp0 = NULL, *hp;
1299	struct hostent hpbuf;
1300	u_int dots;
1301	int trailing_dot, ret, saved_herrno;
1302	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1303	struct __res_type_list *rtl0 = rtl;
1304	querybuf buf;
1305
1306	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1307		*errp = NETDB_INTERNAL;
1308		return (NULL);
1309	}
1310	dots = 0;
1311	for (cp = name; *cp; cp++)
1312		dots += (*cp == '.');
1313	trailing_dot = 0;
1314	if (cp > name && *--cp == '.')
1315		trailing_dot++;
1316
1317	/* If there aren't any dots, it could be a user-level alias */
1318	if (!dots && (cp = hostalias(name)) != NULL) {
1319		for(rtl = rtl0; rtl != NULL;
1320		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1321			ret = res_query(cp, C_IN, rtl->rtl_type, buf.buf,
1322					     sizeof(buf.buf));
1323			if (ret > 0) {
1324				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1325				    ? AF_INET6 : AF_INET;
1326				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1327				hp = getanswer(&buf, ret, name, rtl->rtl_type,
1328						    &hpbuf, errp);
1329				hp = _hpcopy(&hpbuf, errp);
1330				hp0 = _hpmerge(hp0, hp, errp);
1331			}
1332		}
1333		return (hp0);
1334	}
1335
1336	/*
1337	 * If there are dots in the name already, let's just give it a try
1338	 * 'as is'.  The threshold can be set with the "ndots" option.
1339	 */
1340	saved_herrno = -1;
1341	if (dots >= _res.ndots) {
1342		for(rtl = rtl0; rtl != NULL;
1343		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1344			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1345					      buf.buf, sizeof(buf.buf));
1346			if (ret > 0) {
1347				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1348				    ? AF_INET6 : AF_INET;
1349				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1350				hp = getanswer(&buf, ret, name, rtl->rtl_type,
1351						    &hpbuf, errp);
1352				hp = _hpcopy(&hpbuf, errp);
1353				hp0 = _hpmerge(hp0, hp, errp);
1354			}
1355		}
1356		if (hp0 != NULL)
1357			return (hp0);
1358		saved_herrno = *errp;
1359		tried_as_is++;
1360	}
1361
1362	/*
1363	 * We do at least one level of search if
1364	 *	- there is no dot and RES_DEFNAME is set, or
1365	 *	- there is at least one dot, there is no trailing dot,
1366	 *	  and RES_DNSRCH is set.
1367	 */
1368	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1369	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1370		int done = 0;
1371
1372		for (domain = (const char * const *)_res.dnsrch;
1373		     *domain && !done;
1374		     domain++) {
1375
1376			for(rtl = rtl0; rtl != NULL;
1377			    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1378				ret = res_querydomain(name, *domain, C_IN,
1379						      rtl->rtl_type,
1380						      buf.buf, sizeof(buf.buf));
1381				if (ret > 0) {
1382					hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1383					    ? AF_INET6 : AF_INET;
1384					hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1385					hp = getanswer(&buf, ret, name,
1386					    rtl->rtl_type, &hpbuf, errp);
1387					hp = _hpcopy(&hpbuf, errp);
1388					hp0 = _hpmerge(hp0, hp, errp);
1389				}
1390			}
1391			if (hp0 != NULL)
1392				return (hp0);
1393
1394			/*
1395			 * If no server present, give up.
1396			 * If name isn't found in this domain,
1397			 * keep trying higher domains in the search list
1398			 * (if that's enabled).
1399			 * On a NO_DATA error, keep trying, otherwise
1400			 * a wildcard entry of another type could keep us
1401			 * from finding this entry higher in the domain.
1402			 * If we get some other error (negative answer or
1403			 * server failure), then stop searching up,
1404			 * but try the input name below in case it's
1405			 * fully-qualified.
1406			 */
1407			if (errno == ECONNREFUSED) {
1408				*errp = TRY_AGAIN;
1409				return (NULL);
1410			}
1411
1412			switch (*errp) {
1413			case NO_DATA:
1414				got_nodata++;
1415				/* FALLTHROUGH */
1416			case HOST_NOT_FOUND:
1417				/* keep trying */
1418				break;
1419			case TRY_AGAIN:
1420				if (buf.hdr.rcode == SERVFAIL) {
1421					/* try next search element, if any */
1422					got_servfail++;
1423					break;
1424				}
1425				/* FALLTHROUGH */
1426			default:
1427				/* anything else implies that we're done */
1428				done++;
1429			}
1430
1431			/* if we got here for some reason other than DNSRCH,
1432			 * we only wanted one iteration of the loop, so stop.
1433			 */
1434			if (!(_res.options & RES_DNSRCH))
1435				done++;
1436		}
1437	}
1438
1439	/*
1440	 * If we have not already tried the name "as is", do that now.
1441	 * note that we do this regardless of how many dots were in the
1442	 * name or whether it ends with a dot unless NOTLDQUERY is set.
1443	 */
1444	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
1445		for(rtl = rtl0; rtl != NULL;
1446		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1447			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1448					      buf.buf, sizeof(buf.buf));
1449			if (ret > 0) {
1450				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1451				    ? AF_INET6 : AF_INET;
1452				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1453				hp = getanswer(&buf, ret, name, rtl->rtl_type,
1454				    &hpbuf, errp);
1455				hp = _hpcopy(&hpbuf, errp);
1456				hp0 = _hpmerge(hp0, hp, errp);
1457			}
1458		}
1459		if (hp0 != NULL)
1460			return (hp0);
1461	}
1462
1463	/* if we got here, we didn't satisfy the search.
1464	 * if we did an initial full query, return that query's h_errno
1465	 * (note that we wouldn't be here if that query had succeeded).
1466	 * else if we ever got a nodata, send that back as the reason.
1467	 * else send back meaningless h_errno, that being the one from
1468	 * the last DNSRCH we did.
1469	 */
1470	if (saved_herrno != -1)
1471		*errp = saved_herrno;
1472	else if (got_nodata)
1473		*errp = NO_DATA;
1474	else if (got_servfail)
1475		*errp = TRY_AGAIN;
1476	return (NULL);
1477}
1478
1479static struct hostent *
1480_dns_ghbyname(const char *name, int af, int *errp)
1481{
1482	struct __res_type_list *rtl, rtl4;
1483#ifdef INET6
1484	struct __res_type_list rtl6;
1485#endif
1486
1487#ifdef INET6
1488	switch (af) {
1489	case AF_UNSPEC:
1490		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1491		SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA;
1492		rtl = &rtl6;
1493		break;
1494	case AF_INET6:
1495		SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA;
1496		rtl = &rtl6;
1497		break;
1498	case AF_INET:
1499		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1500		rtl = &rtl4;
1501		break;
1502	}
1503#else
1504	SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1505	rtl = &rtl4;
1506#endif
1507	return(_res_search_multi(name, rtl, errp));
1508}
1509
1510static struct hostent *
1511_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1512{
1513	int n;
1514	struct hostent *hp;
1515	u_char c, *cp;
1516	char *bp;
1517	struct hostent hbuf;
1518	int na;
1519#ifdef INET6
1520	static const char hex[] = "0123456789abcdef";
1521#endif
1522	querybuf buf;
1523	char qbuf[MAXDNAME+1];
1524	char *hlist[2];
1525
1526#ifdef INET6
1527	/* XXX */
1528	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
1529		return NULL;
1530#endif
1531
1532	if ((_res.options & RES_INIT) == 0) {
1533		if (res_init() < 0) {
1534			*errp = h_errno;
1535			return NULL;
1536		}
1537	}
1538	memset(&hbuf, 0, sizeof(hbuf));
1539	hbuf.h_name = NULL;
1540	hbuf.h_addrtype = af;
1541	hbuf.h_length = addrlen;
1542	na = 0;
1543
1544	/* XXX assumes that MAXDNAME is big enough */
1545	n = 0;
1546	bp = qbuf;
1547	cp = (u_char *)addr+addrlen-1;
1548	switch (af) {
1549#ifdef INET6
1550	case AF_INET6:
1551		for (; n < addrlen; n++, cp--) {
1552			c = *cp;
1553			*bp++ = hex[c & 0xf];
1554			*bp++ = '.';
1555			*bp++ = hex[c >> 4];
1556			*bp++ = '.';
1557		}
1558		strcpy(bp, "ip6.int");
1559		break;
1560#endif
1561	default:
1562		for (; n < addrlen; n++, cp--) {
1563			c = *cp;
1564			if (c >= 100)
1565				*bp++ = '0' + c / 100;
1566			if (c >= 10)
1567				*bp++ = '0' + (c % 100) / 10;
1568			*bp++ = '0' + c % 10;
1569			*bp++ = '.';
1570		}
1571		strcpy(bp, "in-addr.arpa");
1572		break;
1573	}
1574
1575	n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
1576	if (n < 0) {
1577		*errp = h_errno;
1578		return NULL;
1579	}
1580	hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp);
1581	hbuf.h_addrtype = af;
1582	hbuf.h_length = addrlen;
1583	hbuf.h_addr_list = hlist;
1584	hlist[0] = (char *)addr;
1585	hlist[1] = NULL;
1586	return _hpcopy(&hbuf, errp);
1587}
1588
1589static void
1590_dns_shent(int stayopen)
1591{
1592	if ((_res.options & RES_INIT) == 0) {
1593		if (res_init() < 0)
1594			return;
1595	}
1596	if (stayopen)
1597		_res.options |= RES_STAYOPEN | RES_USEVC;
1598}
1599
1600static void
1601_dns_ehent(void)
1602{
1603	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
1604	res_close();
1605}
1606
1607#ifdef ICMPNL
1608
1609/*
1610 * experimental:
1611 *	draft-ietf-ipngwg-icmp-namelookups-02.txt
1612 *	ifindex is assumed to be encoded in addr.
1613 */
1614#include <sys/uio.h>
1615#include <netinet/ip6.h>
1616#include <netinet/icmp6.h>
1617
1618struct _icmp_host_cache {
1619	struct _icmp_host_cache *hc_next;
1620	int hc_ifindex;
1621	struct in6_addr hc_addr;
1622	char *hc_name;
1623};
1624
1625static char *
1626_icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1627{
1628	int s;
1629	struct icmp6_filter filter;
1630	struct msghdr msg;
1631	struct cmsghdr *cmsg;
1632	struct in6_pktinfo *pkt;
1633	char cbuf[256];
1634	char buf[1024];
1635	int cc;
1636	struct icmp6_fqdn_query *fq;
1637	struct icmp6_fqdn_reply *fr;
1638	struct _icmp_host_cache *hc;
1639	struct sockaddr_in6 sin6;
1640	struct iovec iov;
1641	fd_set s_fds, fds;
1642	struct timeval tout;
1643	int len;
1644	char *name;
1645	static int pid;
1646	static struct _icmp_host_cache *hc_head;
1647
1648	for (hc = hc_head; hc; hc = hc->hc_next) {
1649		if (hc->hc_ifindex == ifindex
1650		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1651			return hc->hc_name;
1652	}
1653
1654	if (pid == 0)
1655		pid = getpid();
1656
1657	ICMP6_FILTER_SETBLOCKALL(&filter);
1658	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1659
1660	FD_ZERO(&s_fds);
1661	tout.tv_sec = 0;
1662	tout.tv_usec = 200000;	/*XXX: 200ms*/
1663
1664	fq = (struct icmp6_fqdn_query *)buf;
1665	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1666	fq->icmp6_fqdn_code = 0;
1667	fq->icmp6_fqdn_cksum = 0;
1668	fq->icmp6_fqdn_id = (u_short)pid;
1669	fq->icmp6_fqdn_unused = 0;
1670	fq->icmp6_fqdn_cookie[0] = 0;
1671	fq->icmp6_fqdn_cookie[1] = 0;
1672
1673	memset(&sin6, 0, sizeof(sin6));
1674	sin6.sin6_family = AF_INET6;
1675	sin6.sin6_addr = *addr;
1676
1677	memset(&msg, 0, sizeof(msg));
1678	msg.msg_name = (caddr_t)&sin6;
1679	msg.msg_namelen = sizeof(sin6);
1680	msg.msg_iov = &iov;
1681	msg.msg_iovlen = 1;
1682	msg.msg_control = NULL;
1683	msg.msg_controllen = 0;
1684	iov.iov_base = (caddr_t)buf;
1685	iov.iov_len = sizeof(struct icmp6_fqdn_query);
1686
1687	if (ifindex) {
1688		msg.msg_control = cbuf;
1689		msg.msg_controllen = sizeof(cbuf);
1690		cmsg = CMSG_FIRSTHDR(&msg);
1691		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1692		cmsg->cmsg_level = IPPROTO_IPV6;
1693		cmsg->cmsg_type = IPV6_PKTINFO;
1694		pkt = (struct in6_pktinfo *)&cmsg[1];
1695		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1696		pkt->ipi6_ifindex = ifindex;
1697		cmsg = CMSG_NXTHDR(&msg, cmsg);
1698		msg.msg_controllen = (char *)cmsg - cbuf;
1699	}
1700
1701	if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1702		return NULL;
1703	(void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1704			 (char *)&filter, sizeof(filter));
1705	cc = sendmsg(s, &msg, 0);
1706	if (cc < 0) {
1707		_close(s);
1708		return NULL;
1709	}
1710	FD_SET(s, &s_fds);
1711	for (;;) {
1712		fds = s_fds;
1713		if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1714			_close(s);
1715			return NULL;
1716		}
1717		len = sizeof(sin6);
1718		cc = recvfrom(s, buf, sizeof(buf), 0,
1719			      (struct sockaddr *)&sin6, &len);
1720		if (cc <= 0) {
1721			_close(s);
1722			return NULL;
1723		}
1724		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1725			continue;
1726		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1727			continue;
1728		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1729		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1730			break;
1731	}
1732	_close(s);
1733	if (fr->icmp6_fqdn_cookie[1] != 0) {
1734		/* rfc1788 type */
1735		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1736		len = (buf + cc) - name;
1737	} else {
1738		len = fr->icmp6_fqdn_namelen;
1739		name = fr->icmp6_fqdn_name;
1740	}
1741	if (len <= 0)
1742		return NULL;
1743	name[len] = 0;
1744
1745	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1746		return NULL;
1747	/* XXX: limit number of cached entries */
1748	hc->hc_ifindex = ifindex;
1749	hc->hc_addr = *addr;
1750	hc->hc_name = strdup(name);
1751	hc->hc_next = hc_head;
1752	hc_head = hc;
1753	return hc->hc_name;
1754}
1755
1756static struct hostent *
1757_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1758{
1759	char *hname;
1760	int ifindex;
1761	struct in6_addr addr6;
1762
1763	if (af != AF_INET6) {
1764		/*
1765		 * Note: rfc1788 defines Who Are You for IPv4,
1766		 * but no one implements it.
1767		 */
1768		return NULL;
1769	}
1770
1771	memcpy(&addr6, addr, addrlen);
1772	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1773	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1774
1775	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1776		return NULL;	/*XXX*/
1777
1778	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1779		return NULL;
1780	return _hpaddr(af, hname, &addr6, errp);
1781}
1782#endif /* ICMPNL */
1783