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