getaddrinfo.c revision 105940
1/*	$KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
34 *
35 * Issues to be discussed:
36 * - Thread safe-ness must be checked.
37 * - Return values.  There are nonstandard return values defined and used
38 *   in the source code.  This is because RFC2553 is silent about which error
39 *   code must be returned for which situation.
40 * - freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
41 *   invalid.  current code - SEGV on freeaddrinfo(NULL)
42 *
43 * Note:
44 * - The code filters out AFs that are not supported by the kernel,
45 *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
46 *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
47 *   in ai_flags?
48 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
49 *   (1) what should we do against numeric hostname (2) what should we do
50 *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
51 *   non-loopback address configured?  global address configured?
52 *
53 * OS specific notes for netbsd/openbsd/freebsd4/bsdi4:
54 * - To avoid search order issue, we have a big amount of code duplicate
55 *   from gethnamaddr.c and some other places.  The issues that there's no
56 *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
57 *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
58 *   presented above.
59 *
60 * OS specific notes for freebsd4:
61 * - FreeBSD supported $GAI.  The code does not.
62 * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not.
63 */
64
65#include <sys/cdefs.h>
66__FBSDID("$FreeBSD: head/lib/libc/net/getaddrinfo.c 105940 2002-10-25 16:24:28Z ume $");
67
68#include "namespace.h"
69#include <sys/types.h>
70#include <sys/param.h>
71#include <sys/socket.h>
72#include <net/if.h>
73#include <netinet/in.h>
74#include <arpa/inet.h>
75#include <arpa/nameser.h>
76#include <rpc/rpc.h>
77#include <rpcsvc/yp_prot.h>
78#include <rpcsvc/ypclnt.h>
79#include <netdb.h>
80#include <resolv.h>
81#include <string.h>
82#include <stdlib.h>
83#include <stddef.h>
84#include <ctype.h>
85#include <unistd.h>
86#include <stdio.h>
87#include <errno.h>
88
89#include "res_config.h"
90
91#ifdef DEBUG
92#include <syslog.h>
93#endif
94
95#include <stdarg.h>
96#include <nsswitch.h>
97#include "un-namespace.h"
98
99#if defined(__KAME__) && defined(INET6)
100# define FAITH
101#endif
102
103#define SUCCESS 0
104#define ANY 0
105#define YES 1
106#define NO  0
107
108static const char in_addrany[] = { 0, 0, 0, 0 };
109static const char in_loopback[] = { 127, 0, 0, 1 };
110#ifdef INET6
111static const char in6_addrany[] = {
112	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
113};
114static const char in6_loopback[] = {
115	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
116};
117#endif
118
119static const struct afd {
120	int a_af;
121	int a_addrlen;
122	int a_socklen;
123	int a_off;
124	const char *a_addrany;
125	const char *a_loopback;
126	int a_scoped;
127} afdl [] = {
128#ifdef INET6
129#define	N_INET6 0
130	{PF_INET6, sizeof(struct in6_addr),
131	 sizeof(struct sockaddr_in6),
132	 offsetof(struct sockaddr_in6, sin6_addr),
133	 in6_addrany, in6_loopback, 1},
134#define	N_INET 1
135#else
136#define	N_INET 0
137#endif
138	{PF_INET, sizeof(struct in_addr),
139	 sizeof(struct sockaddr_in),
140	 offsetof(struct sockaddr_in, sin_addr),
141	 in_addrany, in_loopback, 0},
142	{0, 0, 0, 0, NULL, NULL, 0},
143};
144
145struct explore {
146	int e_af;
147	int e_socktype;
148	int e_protocol;
149	const char *e_protostr;
150	int e_wild;
151#define WILD_AF(ex)		((ex)->e_wild & 0x01)
152#define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
153#define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
154};
155
156static const struct explore explore[] = {
157#if 0
158	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
159#endif
160#ifdef INET6
161	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
162	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
163	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
164#endif
165	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
166	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
167	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
168	{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
169	{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
170	{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
171	{ -1, 0, 0, NULL, 0 },
172};
173
174#ifdef INET6
175#define PTON_MAX	16
176#else
177#define PTON_MAX	4
178#endif
179
180static const ns_src default_dns_files[] = {
181	{ NSSRC_FILES, 	NS_SUCCESS },
182	{ NSSRC_DNS, 	NS_SUCCESS },
183	{ 0 }
184};
185
186#define MAXPACKET	(64*1024)
187
188typedef union {
189	HEADER hdr;
190	u_char buf[MAXPACKET];
191} querybuf;
192
193struct res_target {
194	struct res_target *next;
195	const char *name;	/* domain name */
196	int qclass, qtype;	/* class and type of query */
197	u_char *answer;		/* buffer to put answer */
198	int anslen;		/* size of answer buffer */
199	int n;			/* result length */
200};
201
202static int str_isnumber(const char *);
203static int explore_fqdn(const struct addrinfo *, const char *,
204	const char *, struct addrinfo **);
205static int explore_null(const struct addrinfo *,
206	const char *, struct addrinfo **);
207static int explore_numeric(const struct addrinfo *, const char *,
208	const char *, struct addrinfo **);
209static int explore_numeric_scope(const struct addrinfo *, const char *,
210	const char *, struct addrinfo **);
211static int get_canonname(const struct addrinfo *,
212	struct addrinfo *, const char *);
213static struct addrinfo *get_ai(const struct addrinfo *,
214	const struct afd *, const char *);
215static int get_portmatch(const struct addrinfo *, const char *);
216static int get_port(struct addrinfo *, const char *, int);
217static const struct afd *find_afd(int);
218static int addrconfig(struct addrinfo *);
219#ifdef INET6
220static int ip6_str2scopeid(char *, struct sockaddr_in6 *);
221#endif
222
223static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
224	const struct addrinfo *);
225static void _sethtent(void);
226static void _endhtent(void);
227static int _dns_getaddrinfo(void *, void *, va_list);
228static struct addrinfo *_gethtent(const char *, const struct addrinfo *);
229static int _files_getaddrinfo(void *, void *, va_list);
230#ifdef YP
231static struct addrinfo *_yphostent(char *, const struct addrinfo *);
232static int _yp_getaddrinfo(void *, void *, va_list);
233extern int _yp_check(char **);
234#endif
235
236static int res_queryN(const char *, struct res_target *);
237static int res_searchN(const char *, struct res_target *);
238static int res_querydomainN(const char *, const char *,
239	struct res_target *);
240
241static char *ai_errlist[] = {
242	"Success",
243	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
244	"Temporary failure in name resolution",		/* EAI_AGAIN      */
245	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
246	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
247	"ai_family not supported",			/* EAI_FAMILY     */
248	"Memory allocation failure", 			/* EAI_MEMORY     */
249	"No address associated with hostname", 		/* EAI_NODATA     */
250	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
251	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
252	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
253	"System error returned in errno", 		/* EAI_SYSTEM     */
254	"Invalid value for hints",			/* EAI_BADHINTS	  */
255	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
256	"Unknown error", 				/* EAI_MAX        */
257};
258
259/* Make getaddrinfo() thread-safe in libc for use with kernel threads. */
260#include "libc_private.h"
261#include "spinlock.h"
262/*
263 * XXX: Our res_*() is not thread-safe.  So, we share lock between
264 * getaddrinfo() and getipnodeby*().  Still, we cannot use
265 * getaddrinfo() and getipnodeby*() in conjunction with other
266 * functions which call res_*().
267 */
268spinlock_t __getaddrinfo_thread_lock = _SPINLOCK_INITIALIZER;
269#define THREAD_LOCK() \
270	if (__isthreaded) _SPINLOCK(&__getaddrinfo_thread_lock);
271#define THREAD_UNLOCK() \
272	if (__isthreaded) _SPINUNLOCK(&__getaddrinfo_thread_lock);
273
274/* XXX macros that make external reference is BAD. */
275
276#define GET_AI(ai, afd, addr) \
277do { \
278	/* external reference: pai, error, and label free */ \
279	(ai) = get_ai(pai, (afd), (addr)); \
280	if ((ai) == NULL) { \
281		error = EAI_MEMORY; \
282		goto free; \
283	} \
284} while (/*CONSTCOND*/0)
285
286#define GET_PORT(ai, serv) \
287do { \
288	/* external reference: error and label free */ \
289	error = get_port((ai), (serv), 0); \
290	if (error != 0) \
291		goto free; \
292} while (/*CONSTCOND*/0)
293
294#define GET_CANONNAME(ai, str) \
295do { \
296	/* external reference: pai, error and label free */ \
297	error = get_canonname(pai, (ai), (str)); \
298	if (error != 0) \
299		goto free; \
300} while (/*CONSTCOND*/0)
301
302#define ERR(err) \
303do { \
304	/* external reference: error, and label bad */ \
305	error = (err); \
306	goto bad; \
307	/*NOTREACHED*/ \
308} while (/*CONSTCOND*/0)
309
310#define MATCH_FAMILY(x, y, w) \
311	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
312#define MATCH(x, y, w) \
313	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
314
315char *
316gai_strerror(ecode)
317	int ecode;
318{
319	if (ecode < 0 || ecode > EAI_MAX)
320		ecode = EAI_MAX;
321	return ai_errlist[ecode];
322}
323
324void
325freeaddrinfo(ai)
326	struct addrinfo *ai;
327{
328	struct addrinfo *next;
329
330	do {
331		next = ai->ai_next;
332		if (ai->ai_canonname)
333			free(ai->ai_canonname);
334		/* no need to free(ai->ai_addr) */
335		free(ai);
336		ai = next;
337	} while (ai);
338}
339
340static int
341str_isnumber(p)
342	const char *p;
343{
344	char *ep;
345
346	if (*p == '\0')
347		return NO;
348	ep = NULL;
349	(void)strtoul(p, &ep, 10);
350	if (ep && *ep == '\0')
351		return YES;
352	else
353		return NO;
354}
355
356int
357getaddrinfo(hostname, servname, hints, res)
358	const char *hostname, *servname;
359	const struct addrinfo *hints;
360	struct addrinfo **res;
361{
362	struct addrinfo sentinel;
363	struct addrinfo *cur;
364	int error = 0;
365	struct addrinfo ai;
366	struct addrinfo ai0;
367	struct addrinfo *pai;
368	const struct explore *ex;
369
370	memset(&sentinel, 0, sizeof(sentinel));
371	cur = &sentinel;
372	pai = &ai;
373	pai->ai_flags = 0;
374	pai->ai_family = PF_UNSPEC;
375	pai->ai_socktype = ANY;
376	pai->ai_protocol = ANY;
377	pai->ai_addrlen = 0;
378	pai->ai_canonname = NULL;
379	pai->ai_addr = NULL;
380	pai->ai_next = NULL;
381
382	if (hostname == NULL && servname == NULL)
383		return EAI_NONAME;
384	if (hints) {
385		/* error check for hints */
386		if (hints->ai_addrlen || hints->ai_canonname ||
387		    hints->ai_addr || hints->ai_next)
388			ERR(EAI_BADHINTS); /* xxx */
389		if (hints->ai_flags & ~AI_MASK)
390			ERR(EAI_BADFLAGS);
391		switch (hints->ai_family) {
392		case PF_UNSPEC:
393		case PF_INET:
394#ifdef INET6
395		case PF_INET6:
396#endif
397			break;
398		default:
399			ERR(EAI_FAMILY);
400		}
401		memcpy(pai, hints, sizeof(*pai));
402
403		/*
404		 * if both socktype/protocol are specified, check if they
405		 * are meaningful combination.
406		 */
407		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
408			for (ex = explore; ex->e_af >= 0; ex++) {
409				if (pai->ai_family != ex->e_af)
410					continue;
411				if (ex->e_socktype == ANY)
412					continue;
413				if (ex->e_protocol == ANY)
414					continue;
415				if (pai->ai_socktype == ex->e_socktype &&
416				    pai->ai_protocol != ex->e_protocol) {
417					ERR(EAI_BADHINTS);
418				}
419			}
420		}
421	}
422
423	/*
424	 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
425	 * AF_INET6 query.  They need to be ignored if specified in other
426	 * occassions.
427	 */
428	switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
429	case AI_V4MAPPED:
430	case AI_ALL | AI_V4MAPPED:
431		if (pai->ai_family != AF_INET6)
432			pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
433		break;
434	case AI_ALL:
435#if 1
436		/* illegal */
437		ERR(EAI_BADFLAGS);
438#else
439		pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
440#endif
441		break;
442	}
443
444	/*
445	 * check for special cases.  (1) numeric servname is disallowed if
446	 * socktype/protocol are left unspecified. (2) servname is disallowed
447	 * for raw and other inet{,6} sockets.
448	 */
449	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
450#ifdef PF_INET6
451	    || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
452#endif
453	    ) {
454		ai0 = *pai;	/* backup *pai */
455
456		if (pai->ai_family == PF_UNSPEC) {
457#ifdef PF_INET6
458			pai->ai_family = PF_INET6;
459#else
460			pai->ai_family = PF_INET;
461#endif
462		}
463		error = get_portmatch(pai, servname);
464		if (error)
465			ERR(error);
466
467		*pai = ai0;
468	}
469
470	ai0 = *pai;
471
472	/* NULL hostname, or numeric hostname */
473	for (ex = explore; ex->e_af >= 0; ex++) {
474		*pai = ai0;
475
476		/* PF_UNSPEC entries are prepared for DNS queries only */
477		if (ex->e_af == PF_UNSPEC)
478			continue;
479
480		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
481			continue;
482		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
483			continue;
484		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
485			continue;
486
487		if (pai->ai_family == PF_UNSPEC)
488			pai->ai_family = ex->e_af;
489		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
490			pai->ai_socktype = ex->e_socktype;
491		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
492			pai->ai_protocol = ex->e_protocol;
493
494		if (hostname == NULL)
495			error = explore_null(pai, servname, &cur->ai_next);
496		else
497			error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
498
499		if (error)
500			goto free;
501
502		while (cur && cur->ai_next)
503			cur = cur->ai_next;
504	}
505
506	/*
507	 * XXX
508	 * If numreic representation of AF1 can be interpreted as FQDN
509	 * representation of AF2, we need to think again about the code below.
510	 */
511	if (sentinel.ai_next)
512		goto good;
513
514	if (pai->ai_flags & AI_NUMERICHOST)
515		ERR(EAI_NONAME);
516	if (hostname == NULL)
517		ERR(EAI_NODATA);
518
519	if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
520		ERR(EAI_FAIL);
521
522	/*
523	 * hostname as alphabetical name.
524	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
525	 * outer loop by AFs.
526	 */
527	for (ex = explore; ex->e_af >= 0; ex++) {
528		*pai = ai0;
529
530		/* require exact match for family field */
531		if (pai->ai_family != ex->e_af)
532			continue;
533
534		if (!MATCH(pai->ai_socktype, ex->e_socktype,
535				WILD_SOCKTYPE(ex))) {
536			continue;
537		}
538		if (!MATCH(pai->ai_protocol, ex->e_protocol,
539				WILD_PROTOCOL(ex))) {
540			continue;
541		}
542
543		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
544			pai->ai_socktype = ex->e_socktype;
545		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
546			pai->ai_protocol = ex->e_protocol;
547
548		error = explore_fqdn(pai, hostname, servname,
549			&cur->ai_next);
550
551		while (cur && cur->ai_next)
552			cur = cur->ai_next;
553	}
554
555	/* XXX */
556	if (sentinel.ai_next)
557		error = 0;
558
559	if (error)
560		goto free;
561	if (error == 0) {
562		if (sentinel.ai_next) {
563 good:
564			*res = sentinel.ai_next;
565			return SUCCESS;
566		} else
567			error = EAI_FAIL;
568	}
569 free:
570 bad:
571	if (sentinel.ai_next)
572		freeaddrinfo(sentinel.ai_next);
573	*res = NULL;
574	return error;
575}
576
577/*
578 * FQDN hostname, DNS lookup
579 */
580static int
581explore_fqdn(pai, hostname, servname, res)
582	const struct addrinfo *pai;
583	const char *hostname;
584	const char *servname;
585	struct addrinfo **res;
586{
587	struct addrinfo *result;
588	struct addrinfo *cur;
589	int error = 0;
590	static const ns_dtab dtab[] = {
591		NS_FILES_CB(_files_getaddrinfo, NULL)
592		{ NSSRC_DNS, _dns_getaddrinfo, NULL },	/* force -DHESIOD */
593		NS_NIS_CB(_yp_getaddrinfo, NULL)
594		{ 0 }
595	};
596
597	result = NULL;
598
599	THREAD_LOCK();
600
601	/*
602	 * if the servname does not match socktype/protocol, ignore it.
603	 */
604	if (get_portmatch(pai, servname) != 0) {
605		THREAD_UNLOCK();
606		return 0;
607	}
608
609	switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
610			default_dns_files, hostname, pai)) {
611	case NS_TRYAGAIN:
612		error = EAI_AGAIN;
613		goto free;
614	case NS_UNAVAIL:
615		error = EAI_FAIL;
616		goto free;
617	case NS_NOTFOUND:
618		error = EAI_NODATA;
619		goto free;
620	case NS_SUCCESS:
621		error = 0;
622		for (cur = result; cur; cur = cur->ai_next) {
623			GET_PORT(cur, servname);
624			/* canonname should be filled already */
625		}
626		break;
627	}
628	THREAD_UNLOCK();
629
630	*res = result;
631
632	return 0;
633
634free:
635	THREAD_UNLOCK();
636	if (result)
637		freeaddrinfo(result);
638	return error;
639}
640
641/*
642 * hostname == NULL.
643 * passive socket -> anyaddr (0.0.0.0 or ::)
644 * non-passive socket -> localhost (127.0.0.1 or ::1)
645 */
646static int
647explore_null(pai, servname, res)
648	const struct addrinfo *pai;
649	const char *servname;
650	struct addrinfo **res;
651{
652	int s;
653	const struct afd *afd;
654	struct addrinfo *cur;
655	struct addrinfo sentinel;
656	int error;
657
658	*res = NULL;
659	sentinel.ai_next = NULL;
660	cur = &sentinel;
661
662	/*
663	 * filter out AFs that are not supported by the kernel
664	 * XXX errno?
665	 */
666	s = _socket(pai->ai_family, SOCK_DGRAM, 0);
667	if (s < 0) {
668		if (errno != EMFILE)
669			return 0;
670	} else
671		_close(s);
672
673	/*
674	 * if the servname does not match socktype/protocol, ignore it.
675	 */
676	if (get_portmatch(pai, servname) != 0)
677		return 0;
678
679	afd = find_afd(pai->ai_family);
680	if (afd == NULL)
681		return 0;
682
683	if (pai->ai_flags & AI_PASSIVE) {
684		GET_AI(cur->ai_next, afd, afd->a_addrany);
685		/* xxx meaningless?
686		 * GET_CANONNAME(cur->ai_next, "anyaddr");
687		 */
688		GET_PORT(cur->ai_next, servname);
689	} else {
690		GET_AI(cur->ai_next, afd, afd->a_loopback);
691		/* xxx meaningless?
692		 * GET_CANONNAME(cur->ai_next, "localhost");
693		 */
694		GET_PORT(cur->ai_next, servname);
695	}
696	cur = cur->ai_next;
697
698	*res = sentinel.ai_next;
699	return 0;
700
701free:
702	if (sentinel.ai_next)
703		freeaddrinfo(sentinel.ai_next);
704	return error;
705}
706
707/*
708 * numeric hostname
709 */
710static int
711explore_numeric(pai, hostname, servname, res)
712	const struct addrinfo *pai;
713	const char *hostname;
714	const char *servname;
715	struct addrinfo **res;
716{
717	const struct afd *afd;
718	struct addrinfo *cur;
719	struct addrinfo sentinel;
720	int error;
721	char pton[PTON_MAX];
722
723	*res = NULL;
724	sentinel.ai_next = NULL;
725	cur = &sentinel;
726
727	/*
728	 * if the servname does not match socktype/protocol, ignore it.
729	 */
730	if (get_portmatch(pai, servname) != 0)
731		return 0;
732
733	afd = find_afd(pai->ai_family);
734	if (afd == NULL)
735		return 0;
736
737	switch (afd->a_af) {
738#if 1 /*X/Open spec*/
739	case AF_INET:
740		if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
741			if (pai->ai_family == afd->a_af ||
742			    pai->ai_family == PF_UNSPEC /*?*/) {
743				GET_AI(cur->ai_next, afd, pton);
744				GET_PORT(cur->ai_next, servname);
745				while (cur && cur->ai_next)
746					cur = cur->ai_next;
747			} else
748				ERR(EAI_FAMILY);	/*xxx*/
749		}
750		break;
751#endif
752	default:
753		if (inet_pton(afd->a_af, hostname, pton) == 1) {
754			if (pai->ai_family == afd->a_af ||
755			    pai->ai_family == PF_UNSPEC /*?*/) {
756				GET_AI(cur->ai_next, afd, pton);
757				GET_PORT(cur->ai_next, servname);
758				while (cur && cur->ai_next)
759					cur = cur->ai_next;
760			} else
761				ERR(EAI_FAMILY);	/* XXX */
762		}
763		break;
764	}
765
766	*res = sentinel.ai_next;
767	return 0;
768
769free:
770bad:
771	if (sentinel.ai_next)
772		freeaddrinfo(sentinel.ai_next);
773	return error;
774}
775
776/*
777 * numeric hostname with scope
778 */
779static int
780explore_numeric_scope(pai, hostname, servname, res)
781	const struct addrinfo *pai;
782	const char *hostname;
783	const char *servname;
784	struct addrinfo **res;
785{
786#if !defined(SCOPE_DELIMITER) || !defined(INET6)
787	return explore_numeric(pai, hostname, servname, res);
788#else
789	const struct afd *afd;
790	struct addrinfo *cur;
791	int error;
792	char *cp, *hostname2 = NULL, *scope, *addr;
793	struct sockaddr_in6 *sin6;
794
795	/*
796	 * if the servname does not match socktype/protocol, ignore it.
797	 */
798	if (get_portmatch(pai, servname) != 0)
799		return 0;
800
801	afd = find_afd(pai->ai_family);
802	if (afd == NULL)
803		return 0;
804
805	if (!afd->a_scoped)
806		return explore_numeric(pai, hostname, servname, res);
807
808	cp = strchr(hostname, SCOPE_DELIMITER);
809	if (cp == NULL)
810		return explore_numeric(pai, hostname, servname, res);
811
812	/*
813	 * Handle special case of <scoped_address><delimiter><scope id>
814	 */
815	hostname2 = strdup(hostname);
816	if (hostname2 == NULL)
817		return EAI_MEMORY;
818	/* terminate at the delimiter */
819	hostname2[cp - hostname] = '\0';
820	addr = hostname2;
821	scope = cp + 1;
822
823	error = explore_numeric(pai, addr, servname, res);
824	if (error == 0) {
825		int scopeid;
826
827		for (cur = *res; cur; cur = cur->ai_next) {
828			if (cur->ai_family != AF_INET6)
829				continue;
830			sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
831			if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) {
832				free(hostname2);
833				return(EAI_NODATA); /* XXX: is return OK? */
834			}
835			sin6->sin6_scope_id = scopeid;
836		}
837	}
838
839	free(hostname2);
840
841	return error;
842#endif
843}
844
845static int
846get_canonname(pai, ai, str)
847	const struct addrinfo *pai;
848	struct addrinfo *ai;
849	const char *str;
850{
851	if ((pai->ai_flags & AI_CANONNAME) != 0) {
852		ai->ai_canonname = (char *)malloc(strlen(str) + 1);
853		if (ai->ai_canonname == NULL)
854			return EAI_MEMORY;
855		strlcpy(ai->ai_canonname, str, strlen(str) + 1);
856	}
857	return 0;
858}
859
860static struct addrinfo *
861get_ai(pai, afd, addr)
862	const struct addrinfo *pai;
863	const struct afd *afd;
864	const char *addr;
865{
866	char *p;
867	struct addrinfo *ai;
868#ifdef FAITH
869	struct in6_addr faith_prefix;
870	char *fp_str;
871	int translate = 0;
872#endif
873
874#ifdef FAITH
875	/*
876	 * Transfrom an IPv4 addr into a special IPv6 addr format for
877	 * IPv6->IPv4 translation gateway. (only TCP is supported now)
878	 *
879	 * +-----------------------------------+------------+
880	 * | faith prefix part (12 bytes)      | embedded   |
881	 * |                                   | IPv4 addr part (4 bytes)
882	 * +-----------------------------------+------------+
883	 *
884	 * faith prefix part is specified as ascii IPv6 addr format
885	 * in environmental variable GAI.
886	 * For FAITH to work correctly, routing to faith prefix must be
887	 * setup toward a machine where a FAITH daemon operates.
888	 * Also, the machine must enable some mechanizm
889	 * (e.g. faith interface hack) to divert those packet with
890	 * faith prefixed destination addr to user-land FAITH daemon.
891	 */
892	fp_str = getenv("GAI");
893	if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 &&
894	    afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) {
895		u_int32_t v4a;
896		u_int8_t v4a_top;
897
898		memcpy(&v4a, addr, sizeof v4a);
899		v4a_top = v4a >> IN_CLASSA_NSHIFT;
900		if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) &&
901		    v4a_top != 0 && v4a != IN_LOOPBACKNET) {
902			afd = &afdl[N_INET6];
903			memcpy(&faith_prefix.s6_addr[12], addr,
904			       sizeof(struct in_addr));
905			translate = 1;
906		}
907	}
908#endif
909
910	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
911		+ (afd->a_socklen));
912	if (ai == NULL)
913		return NULL;
914
915	memcpy(ai, pai, sizeof(struct addrinfo));
916	ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
917	memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
918	ai->ai_addr->sa_len = afd->a_socklen;
919	ai->ai_addrlen = afd->a_socklen;
920	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
921	p = (char *)(void *)(ai->ai_addr);
922#ifdef FAITH
923	if (translate == 1)
924		memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
925	else
926#endif
927	memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
928	return ai;
929}
930
931static int
932get_portmatch(ai, servname)
933	const struct addrinfo *ai;
934	const char *servname;
935{
936
937	/* get_port does not touch first argument. when matchonly == 1. */
938	/* LINTED const cast */
939	return get_port((struct addrinfo *)ai, servname, 1);
940}
941
942static int
943get_port(ai, servname, matchonly)
944	struct addrinfo *ai;
945	const char *servname;
946	int matchonly;
947{
948	const char *proto;
949	struct servent *sp;
950	int port;
951	int allownumeric;
952
953	if (servname == NULL)
954		return 0;
955	switch (ai->ai_family) {
956	case AF_INET:
957#ifdef AF_INET6
958	case AF_INET6:
959#endif
960		break;
961	default:
962		return 0;
963	}
964
965	switch (ai->ai_socktype) {
966	case SOCK_RAW:
967		return EAI_SERVICE;
968	case SOCK_DGRAM:
969	case SOCK_STREAM:
970		allownumeric = 1;
971		break;
972	case ANY:
973		allownumeric = 0;
974		break;
975	default:
976		return EAI_SOCKTYPE;
977	}
978
979	if (str_isnumber(servname)) {
980		if (!allownumeric)
981			return EAI_SERVICE;
982		port = atoi(servname);
983		if (port < 0 || port > 65535)
984			return EAI_SERVICE;
985		port = htons(port);
986	} else {
987		switch (ai->ai_socktype) {
988		case SOCK_DGRAM:
989			proto = "udp";
990			break;
991		case SOCK_STREAM:
992			proto = "tcp";
993			break;
994		default:
995			proto = NULL;
996			break;
997		}
998
999		if ((sp = getservbyname(servname, proto)) == NULL)
1000			return EAI_SERVICE;
1001		port = sp->s_port;
1002	}
1003
1004	if (!matchonly) {
1005		switch (ai->ai_family) {
1006		case AF_INET:
1007			((struct sockaddr_in *)(void *)
1008			    ai->ai_addr)->sin_port = port;
1009			break;
1010#ifdef INET6
1011		case AF_INET6:
1012			((struct sockaddr_in6 *)(void *)
1013			    ai->ai_addr)->sin6_port = port;
1014			break;
1015#endif
1016		}
1017	}
1018
1019	return 0;
1020}
1021
1022static const struct afd *
1023find_afd(af)
1024	int af;
1025{
1026	const struct afd *afd;
1027
1028	if (af == PF_UNSPEC)
1029		return NULL;
1030	for (afd = afdl; afd->a_af; afd++) {
1031		if (afd->a_af == af)
1032			return afd;
1033	}
1034	return NULL;
1035}
1036
1037/*
1038 * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
1039 * will take care of it.
1040 * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
1041 * if the code is right or not.
1042 *
1043 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
1044 * _dns_getaddrinfo.
1045 */
1046static int
1047addrconfig(pai)
1048	struct addrinfo *pai;
1049{
1050	int s, af;
1051
1052	/*
1053	 * TODO:
1054	 * Note that implementation dependent test for address
1055	 * configuration should be done everytime called
1056	 * (or apropriate interval),
1057	 * because addresses will be dynamically assigned or deleted.
1058	 */
1059	af = pai->ai_family;
1060	if (af == AF_UNSPEC) {
1061		if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1062			af = AF_INET;
1063		else {
1064			_close(s);
1065			if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1066				af = AF_INET6;
1067			else
1068				_close(s);
1069		}
1070	}
1071	if (af != AF_UNSPEC) {
1072		if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
1073			return 0;
1074		_close(s);
1075	}
1076	pai->ai_family = af;
1077	return 1;
1078}
1079
1080#ifdef INET6
1081/* convert a string to a scope identifier. XXX: IPv6 specific */
1082static int
1083ip6_str2scopeid(scope, sin6)
1084	char *scope;
1085	struct sockaddr_in6 *sin6;
1086{
1087	int scopeid;
1088	struct in6_addr *a6 = &sin6->sin6_addr;
1089	char *ep;
1090
1091	/* empty scopeid portion is invalid */
1092	if (*scope == '\0')
1093		return -1;
1094
1095	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1096		/*
1097		 * We currently assume a one-to-one mapping between links
1098		 * and interfaces, so we simply use interface indices for
1099		 * like-local scopes.
1100		 */
1101		scopeid = if_nametoindex(scope);
1102		if (scopeid == 0)
1103			goto trynumeric;
1104		return(scopeid);
1105	}
1106
1107	/* still unclear about literal, allow numeric only - placeholder */
1108	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1109		goto trynumeric;
1110	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1111		goto trynumeric;
1112	else
1113		goto trynumeric;	/* global */
1114
1115	/* try to convert to a numeric id as a last resort */
1116  trynumeric:
1117	scopeid = (int)strtoul(scope, &ep, 10);
1118	if (*ep == '\0')
1119		return scopeid;
1120	else
1121		return -1;
1122}
1123#endif
1124
1125#ifdef RESOLVSORT
1126struct addr_ptr {
1127	struct addrinfo *ai;
1128	int aval;
1129};
1130
1131static int
1132addr4sort(struct addrinfo *sentinel)
1133{
1134	struct addrinfo *ai;
1135	struct addr_ptr *addrs, addr;
1136	struct sockaddr_in *sin;
1137	int naddrs, i, j;
1138	int needsort = 0;
1139
1140	if (!sentinel)
1141		return -1;
1142	naddrs = 0;
1143	for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
1144		naddrs++;
1145	if (naddrs < 2)
1146		return 0;		/* We don't need sorting. */
1147	if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
1148		return -1;
1149	i = 0;
1150	for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
1151		sin = (struct sockaddr_in *)ai->ai_addr;
1152		for (j = 0; (unsigned)j < _res.nsort; j++) {
1153			if (_res.sort_list[j].addr.s_addr ==
1154			    (sin->sin_addr.s_addr & _res.sort_list[j].mask))
1155				break;
1156		}
1157		addrs[i].ai = ai;
1158		addrs[i].aval = j;
1159		if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
1160			needsort = i;
1161		i++;
1162	}
1163	if (!needsort) {
1164		free(addrs);
1165		return 0;
1166	}
1167
1168	while (needsort < naddrs) {
1169	    for (j = needsort - 1; j >= 0; j--) {
1170		if (addrs[j].aval > addrs[j+1].aval) {
1171		    addr = addrs[j];
1172		    addrs[j] = addrs[j + 1];
1173		    addrs[j + 1] = addr;
1174		} else
1175		    break;
1176	    }
1177	    needsort++;
1178	}
1179
1180	ai = sentinel;
1181	for (i = 0; i < naddrs; ++i) {
1182		ai->ai_next = addrs[i].ai;
1183		ai = ai->ai_next;
1184	}
1185	ai->ai_next = NULL;
1186	free(addrs);
1187	return 0;
1188}
1189#endif /*RESOLVSORT*/
1190
1191#ifdef DEBUG
1192static const char AskedForGot[] =
1193	"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1194#endif
1195static FILE *hostf = NULL;
1196
1197static struct addrinfo *
1198getanswer(answer, anslen, qname, qtype, pai)
1199	const querybuf *answer;
1200	int anslen;
1201	const char *qname;
1202	int qtype;
1203	const struct addrinfo *pai;
1204{
1205	struct addrinfo sentinel, *cur;
1206	struct addrinfo ai;
1207	const struct afd *afd;
1208	char *canonname;
1209	const HEADER *hp;
1210	const u_char *cp;
1211	int n;
1212	const u_char *eom;
1213	char *bp, *ep;
1214	int type, class, ancount, qdcount;
1215	int haveanswer, had_error;
1216	char tbuf[MAXDNAME];
1217	int (*name_ok)(const char *);
1218	char hostbuf[8*1024];
1219
1220	memset(&sentinel, 0, sizeof(sentinel));
1221	cur = &sentinel;
1222
1223	canonname = NULL;
1224	eom = answer->buf + anslen;
1225	switch (qtype) {
1226	case T_A:
1227	case T_AAAA:
1228	case T_ANY:	/*use T_ANY only for T_A/T_AAAA lookup*/
1229		name_ok = res_hnok;
1230		break;
1231	default:
1232		return (NULL);	/* XXX should be abort(); */
1233	}
1234	/*
1235	 * find first satisfactory answer
1236	 */
1237	hp = &answer->hdr;
1238	ancount = ntohs(hp->ancount);
1239	qdcount = ntohs(hp->qdcount);
1240	bp = hostbuf;
1241	ep = hostbuf + sizeof hostbuf;
1242	cp = answer->buf + HFIXEDSZ;
1243	if (qdcount != 1) {
1244		h_errno = NO_RECOVERY;
1245		return (NULL);
1246	}
1247	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1248	if ((n < 0) || !(*name_ok)(bp)) {
1249		h_errno = NO_RECOVERY;
1250		return (NULL);
1251	}
1252	cp += n + QFIXEDSZ;
1253	if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1254		/* res_send() has already verified that the query name is the
1255		 * same as the one we sent; this just gets the expanded name
1256		 * (i.e., with the succeeding search-domain tacked on).
1257		 */
1258		n = strlen(bp) + 1;		/* for the \0 */
1259		if (n >= MAXHOSTNAMELEN) {
1260			h_errno = NO_RECOVERY;
1261			return (NULL);
1262		}
1263		canonname = bp;
1264		bp += n;
1265		/* The qname can be abbreviated, but h_name is now absolute. */
1266		qname = canonname;
1267	}
1268	haveanswer = 0;
1269	had_error = 0;
1270	while (ancount-- > 0 && cp < eom && !had_error) {
1271		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1272		if ((n < 0) || !(*name_ok)(bp)) {
1273			had_error++;
1274			continue;
1275		}
1276		cp += n;			/* name */
1277		type = _getshort(cp);
1278 		cp += INT16SZ;			/* type */
1279		class = _getshort(cp);
1280 		cp += INT16SZ + INT32SZ;	/* class, TTL */
1281		n = _getshort(cp);
1282		cp += INT16SZ;			/* len */
1283		if (class != C_IN) {
1284			/* XXX - debug? syslog? */
1285			cp += n;
1286			continue;		/* XXX - had_error++ ? */
1287		}
1288		if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1289		    type == T_CNAME) {
1290			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1291			if ((n < 0) || !(*name_ok)(tbuf)) {
1292				had_error++;
1293				continue;
1294			}
1295			cp += n;
1296			/* Get canonical name. */
1297			n = strlen(tbuf) + 1;	/* for the \0 */
1298			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1299				had_error++;
1300				continue;
1301			}
1302			strlcpy(bp, tbuf, ep - bp);
1303			canonname = bp;
1304			bp += n;
1305			continue;
1306		}
1307		if (qtype == T_ANY) {
1308			if (!(type == T_A || type == T_AAAA)) {
1309				cp += n;
1310				continue;
1311			}
1312		} else if (type != qtype) {
1313#ifdef DEBUG
1314			if (type != T_KEY && type != T_SIG)
1315				syslog(LOG_NOTICE|LOG_AUTH,
1316	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1317				       qname, p_class(C_IN), p_type(qtype),
1318				       p_type(type));
1319#endif
1320			cp += n;
1321			continue;		/* XXX - had_error++ ? */
1322		}
1323		switch (type) {
1324		case T_A:
1325		case T_AAAA:
1326			if (strcasecmp(canonname, bp) != 0) {
1327#ifdef DEBUG
1328				syslog(LOG_NOTICE|LOG_AUTH,
1329				       AskedForGot, canonname, bp);
1330#endif
1331				cp += n;
1332				continue;	/* XXX - had_error++ ? */
1333			}
1334			if (type == T_A && n != INADDRSZ) {
1335				cp += n;
1336				continue;
1337			}
1338			if (type == T_AAAA && n != IN6ADDRSZ) {
1339				cp += n;
1340				continue;
1341			}
1342#ifdef FILTER_V4MAPPED
1343			if (type == T_AAAA) {
1344				struct in6_addr in6;
1345				memcpy(&in6, cp, sizeof(in6));
1346				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1347					cp += n;
1348					continue;
1349				}
1350			}
1351#endif
1352			if (!haveanswer) {
1353				int nn;
1354
1355				canonname = bp;
1356				nn = strlen(bp) + 1;	/* for the \0 */
1357				bp += nn;
1358			}
1359
1360			/* don't overwrite pai */
1361			ai = *pai;
1362			ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1363			afd = find_afd(ai.ai_family);
1364			if (afd == NULL) {
1365				cp += n;
1366				continue;
1367			}
1368			cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1369			if (cur->ai_next == NULL)
1370				had_error++;
1371			while (cur && cur->ai_next)
1372				cur = cur->ai_next;
1373			cp += n;
1374			break;
1375		default:
1376			abort();
1377		}
1378		if (!had_error)
1379			haveanswer++;
1380	}
1381	if (haveanswer) {
1382#if defined(RESOLVSORT)
1383		/*
1384		 * We support only IPv4 address for backward
1385		 * compatibility against gethostbyname(3).
1386		 */
1387		if (_res.nsort && qtype == T_A) {
1388			if (addr4sort(&sentinel) < 0) {
1389				freeaddrinfo(sentinel.ai_next);
1390				h_errno = NO_RECOVERY;
1391				return NULL;
1392			}
1393		}
1394#endif /*RESOLVSORT*/
1395		if (!canonname)
1396			(void)get_canonname(pai, sentinel.ai_next, qname);
1397		else
1398			(void)get_canonname(pai, sentinel.ai_next, canonname);
1399		h_errno = NETDB_SUCCESS;
1400		return sentinel.ai_next;
1401	}
1402
1403	h_errno = NO_RECOVERY;
1404	return NULL;
1405}
1406
1407/*ARGSUSED*/
1408static int
1409_dns_getaddrinfo(rv, cb_data, ap)
1410	void	*rv;
1411	void	*cb_data;
1412	va_list	 ap;
1413{
1414	struct addrinfo *ai;
1415	querybuf *buf, *buf2;
1416	const char *name;
1417	const struct addrinfo *pai;
1418	struct addrinfo sentinel, *cur;
1419	struct res_target q, q2;
1420
1421	name = va_arg(ap, char *);
1422	pai = va_arg(ap, const struct addrinfo *);
1423
1424	memset(&q, 0, sizeof(q2));
1425	memset(&q2, 0, sizeof(q2));
1426	memset(&sentinel, 0, sizeof(sentinel));
1427	cur = &sentinel;
1428
1429	buf = malloc(sizeof(*buf));
1430	if (!buf) {
1431		h_errno = NETDB_INTERNAL;
1432		return NS_NOTFOUND;
1433	}
1434	buf2 = malloc(sizeof(*buf2));
1435	if (!buf2) {
1436		free(buf);
1437		h_errno = NETDB_INTERNAL;
1438		return NS_NOTFOUND;
1439	}
1440
1441	switch (pai->ai_family) {
1442	case AF_UNSPEC:
1443		/* prefer IPv6 */
1444		q.name = name;
1445		q.qclass = C_IN;
1446		q.qtype = T_AAAA;
1447		q.answer = buf->buf;
1448		q.anslen = sizeof(buf->buf);
1449		q.next = &q2;
1450		q2.qclass = C_IN;
1451		q2.qtype = T_A;
1452		q2.answer = buf2->buf;
1453		q2.anslen = sizeof(buf2->buf);
1454		break;
1455	case AF_INET:
1456		q.name = name;
1457		q.qclass = C_IN;
1458		q.qtype = T_A;
1459		q.answer = buf->buf;
1460		q.anslen = sizeof(buf->buf);
1461		break;
1462	case AF_INET6:
1463		q.name = name;
1464		q.qclass = C_IN;
1465		q.qtype = T_AAAA;
1466		q.answer = buf->buf;
1467		q.anslen = sizeof(buf->buf);
1468		break;
1469	default:
1470		free(buf);
1471		free(buf2);
1472		return NS_UNAVAIL;
1473	}
1474	if (res_searchN(name, &q) < 0) {
1475		free(buf);
1476		free(buf2);
1477		return NS_NOTFOUND;
1478	}
1479	ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1480	if (ai) {
1481		cur->ai_next = ai;
1482		while (cur && cur->ai_next)
1483			cur = cur->ai_next;
1484	}
1485	if (q.next) {
1486		ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1487		if (ai)
1488			cur->ai_next = ai;
1489	}
1490	free(buf);
1491	free(buf2);
1492	if (sentinel.ai_next == NULL)
1493		switch (h_errno) {
1494		case HOST_NOT_FOUND:
1495			return NS_NOTFOUND;
1496		case TRY_AGAIN:
1497			return NS_TRYAGAIN;
1498		default:
1499			return NS_UNAVAIL;
1500		}
1501	*((struct addrinfo **)rv) = sentinel.ai_next;
1502	return NS_SUCCESS;
1503}
1504
1505static void
1506_sethtent()
1507{
1508	if (!hostf)
1509		hostf = fopen(_PATH_HOSTS, "r" );
1510	else
1511		rewind(hostf);
1512}
1513
1514static void
1515_endhtent()
1516{
1517	if (hostf) {
1518		(void) fclose(hostf);
1519		hostf = NULL;
1520	}
1521}
1522
1523static struct addrinfo *
1524_gethtent(name, pai)
1525	const char *name;
1526	const struct addrinfo *pai;
1527{
1528	char *p;
1529	char *cp, *tname, *cname;
1530	struct addrinfo hints, *res0, *res;
1531	int error;
1532	const char *addr;
1533	char hostbuf[8*1024];
1534
1535	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1536		return (NULL);
1537again:
1538	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
1539		return (NULL);
1540	if (*p == '#')
1541		goto again;
1542	if (!(cp = strpbrk(p, "#\n")))
1543		goto again;
1544	*cp = '\0';
1545	if (!(cp = strpbrk(p, " \t")))
1546		goto again;
1547	*cp++ = '\0';
1548	addr = p;
1549	cname = NULL;
1550	/* if this is not something we're looking for, skip it. */
1551	while (cp && *cp) {
1552		if (*cp == ' ' || *cp == '\t') {
1553			cp++;
1554			continue;
1555		}
1556		tname = cp;
1557		if (cname == NULL)
1558			cname = cp;
1559		if ((cp = strpbrk(cp, " \t")) != NULL)
1560			*cp++ = '\0';
1561		if (strcasecmp(name, tname) == 0)
1562			goto found;
1563	}
1564	goto again;
1565
1566found:
1567	/* we should not glob socktype/protocol here */
1568	memset(&hints, 0, sizeof(hints));
1569	hints.ai_family = pai->ai_family;
1570	hints.ai_socktype = SOCK_DGRAM;
1571	hints.ai_protocol = 0;
1572	hints.ai_flags = AI_NUMERICHOST;
1573	error = getaddrinfo(addr, "0", &hints, &res0);
1574	if (error)
1575		goto again;
1576#ifdef FILTER_V4MAPPED
1577	/* XXX should check all items in the chain */
1578	if (res0->ai_family == AF_INET6 &&
1579	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) {
1580		freeaddrinfo(res0);
1581		goto again;
1582	}
1583#endif
1584	for (res = res0; res; res = res->ai_next) {
1585		/* cover it up */
1586		res->ai_flags = pai->ai_flags;
1587		res->ai_socktype = pai->ai_socktype;
1588		res->ai_protocol = pai->ai_protocol;
1589
1590		if (pai->ai_flags & AI_CANONNAME) {
1591			if (get_canonname(pai, res, cname) != 0) {
1592				freeaddrinfo(res0);
1593				goto again;
1594			}
1595		}
1596	}
1597	return res0;
1598}
1599
1600/*ARGSUSED*/
1601static int
1602_files_getaddrinfo(rv, cb_data, ap)
1603	void	*rv;
1604	void	*cb_data;
1605	va_list	 ap;
1606{
1607	const char *name;
1608	const struct addrinfo *pai;
1609	struct addrinfo sentinel, *cur;
1610	struct addrinfo *p;
1611
1612	name = va_arg(ap, char *);
1613	pai = va_arg(ap, struct addrinfo *);
1614
1615	memset(&sentinel, 0, sizeof(sentinel));
1616	cur = &sentinel;
1617
1618	_sethtent();
1619	while ((p = _gethtent(name, pai)) != NULL) {
1620		cur->ai_next = p;
1621		while (cur && cur->ai_next)
1622			cur = cur->ai_next;
1623	}
1624	_endhtent();
1625
1626	*((struct addrinfo **)rv) = sentinel.ai_next;
1627	if (sentinel.ai_next == NULL)
1628		return NS_NOTFOUND;
1629	return NS_SUCCESS;
1630}
1631
1632#ifdef YP
1633static char *__ypdomain;
1634
1635/*ARGSUSED*/
1636static struct addrinfo *
1637_yphostent(line, pai)
1638	char *line;
1639	const struct addrinfo *pai;
1640{
1641	struct addrinfo sentinel, *cur;
1642	struct addrinfo hints, *res, *res0;
1643	int error;
1644	char *p = line;
1645	const char *addr, *canonname;
1646	char *nextline;
1647	char *cp;
1648
1649	addr = canonname = NULL;
1650
1651	memset(&sentinel, 0, sizeof(sentinel));
1652	cur = &sentinel;
1653
1654nextline:
1655	/* terminate line */
1656	cp = strchr(p, '\n');
1657	if (cp) {
1658		*cp++ = '\0';
1659		nextline = cp;
1660	} else
1661		nextline = NULL;
1662
1663	cp = strpbrk(p, " \t");
1664	if (cp == NULL) {
1665		if (canonname == NULL)
1666			return (NULL);
1667		else
1668			goto done;
1669	}
1670	*cp++ = '\0';
1671
1672	addr = p;
1673
1674	while (cp && *cp) {
1675		if (*cp == ' ' || *cp == '\t') {
1676			cp++;
1677			continue;
1678		}
1679		if (!canonname)
1680			canonname = cp;
1681		if ((cp = strpbrk(cp, " \t")) != NULL)
1682			*cp++ = '\0';
1683	}
1684
1685	hints = *pai;
1686	hints.ai_flags = AI_NUMERICHOST;
1687	error = getaddrinfo(addr, NULL, &hints, &res0);
1688	if (error == 0) {
1689		for (res = res0; res; res = res->ai_next) {
1690			/* cover it up */
1691			res->ai_flags = pai->ai_flags;
1692
1693			if (pai->ai_flags & AI_CANONNAME)
1694				(void)get_canonname(pai, res, canonname);
1695		}
1696	} else
1697		res0 = NULL;
1698	if (res0) {
1699		cur->ai_next = res0;
1700		while (cur && cur->ai_next)
1701			cur = cur->ai_next;
1702	}
1703
1704	if (nextline) {
1705		p = nextline;
1706		goto nextline;
1707	}
1708
1709done:
1710	return sentinel.ai_next;
1711}
1712
1713/*ARGSUSED*/
1714static int
1715_yp_getaddrinfo(rv, cb_data, ap)
1716	void	*rv;
1717	void	*cb_data;
1718	va_list	 ap;
1719{
1720	struct addrinfo sentinel, *cur;
1721	struct addrinfo *ai = NULL;
1722	static char *__ypcurrent;
1723	int __ypcurrentlen, r;
1724	const char *name;
1725	const struct addrinfo *pai;
1726
1727	name = va_arg(ap, char *);
1728	pai = va_arg(ap, const struct addrinfo *);
1729
1730	memset(&sentinel, 0, sizeof(sentinel));
1731	cur = &sentinel;
1732
1733	if (!__ypdomain) {
1734		if (_yp_check(&__ypdomain) == 0)
1735			return NS_UNAVAIL;
1736	}
1737	if (__ypcurrent)
1738		free(__ypcurrent);
1739	__ypcurrent = NULL;
1740
1741	/* hosts.byname is only for IPv4 (Solaris8) */
1742	if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1743		r = yp_match(__ypdomain, "hosts.byname", name,
1744			(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1745		if (r == 0) {
1746			struct addrinfo ai4;
1747
1748			ai4 = *pai;
1749			ai4.ai_family = AF_INET;
1750			ai = _yphostent(__ypcurrent, &ai4);
1751			if (ai) {
1752				cur->ai_next = ai;
1753				while (cur && cur->ai_next)
1754					cur = cur->ai_next;
1755			}
1756		}
1757	}
1758
1759	/* ipnodes.byname can hold both IPv4/v6 */
1760	r = yp_match(__ypdomain, "ipnodes.byname", name,
1761		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1762	if (r == 0) {
1763		ai = _yphostent(__ypcurrent, pai);
1764		if (ai) {
1765			cur->ai_next = ai;
1766			while (cur && cur->ai_next)
1767				cur = cur->ai_next;
1768		}
1769	}
1770
1771	if (sentinel.ai_next == NULL) {
1772		h_errno = HOST_NOT_FOUND;
1773		return NS_NOTFOUND;
1774	}
1775	*((struct addrinfo **)rv) = sentinel.ai_next;
1776	return NS_SUCCESS;
1777}
1778#endif
1779
1780/* resolver logic */
1781
1782extern const char *__hostalias(const char *);
1783extern int h_errno;
1784
1785/*
1786 * Formulate a normal query, send, and await answer.
1787 * Returned answer is placed in supplied buffer "answer".
1788 * Perform preliminary check of answer, returning success only
1789 * if no error is indicated and the answer count is nonzero.
1790 * Return the size of the response on success, -1 on error.
1791 * Error number is left in h_errno.
1792 *
1793 * Caller must parse answer and determine whether it answers the question.
1794 */
1795static int
1796res_queryN(name, target)
1797	const char *name;	/* domain name */
1798	struct res_target *target;
1799{
1800	u_char *buf;
1801	HEADER *hp;
1802	int n;
1803	struct res_target *t;
1804	int rcode;
1805	int ancount;
1806
1807	rcode = NOERROR;
1808	ancount = 0;
1809
1810	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1811		h_errno = NETDB_INTERNAL;
1812		return (-1);
1813	}
1814
1815	buf = malloc(MAXPACKET);
1816	if (!buf) {
1817		h_errno = NETDB_INTERNAL;
1818		return -1;
1819	}
1820
1821	for (t = target; t; t = t->next) {
1822		int class, type;
1823		u_char *answer;
1824		int anslen;
1825
1826		hp = (HEADER *)(void *)t->answer;
1827		hp->rcode = NOERROR;	/* default */
1828
1829		/* make it easier... */
1830		class = t->qclass;
1831		type = t->qtype;
1832		answer = t->answer;
1833		anslen = t->anslen;
1834#ifdef DEBUG
1835		if (_res.options & RES_DEBUG)
1836			printf(";; res_query(%s, %d, %d)\n", name, class, type);
1837#endif
1838
1839		n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
1840		    buf, MAXPACKET);
1841		if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
1842			n = res_opt(n, buf, MAXPACKET, anslen);
1843		if (n <= 0) {
1844#ifdef DEBUG
1845			if (_res.options & RES_DEBUG)
1846				printf(";; res_query: mkquery failed\n");
1847#endif
1848			free(buf);
1849			h_errno = NO_RECOVERY;
1850			return (n);
1851		}
1852		n = res_send(buf, n, answer, anslen);
1853#if 0
1854		if (n < 0) {
1855#ifdef DEBUG
1856			if (_res.options & RES_DEBUG)
1857				printf(";; res_query: send error\n");
1858#endif
1859			free(buf);
1860			h_errno = TRY_AGAIN;
1861			return (n);
1862		}
1863#endif
1864
1865		if (n < 0 || n > anslen)
1866			hp->rcode = FORMERR; /* XXX not very informative */
1867		if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1868			rcode = hp->rcode;	/* record most recent error */
1869#ifdef DEBUG
1870			if (_res.options & RES_DEBUG)
1871				printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1872				    ntohs(hp->ancount));
1873#endif
1874			continue;
1875		}
1876
1877		ancount += ntohs(hp->ancount);
1878
1879		t->n = n;
1880	}
1881
1882	free(buf);
1883
1884	if (ancount == 0) {
1885		switch (rcode) {
1886		case NXDOMAIN:
1887			h_errno = HOST_NOT_FOUND;
1888			break;
1889		case SERVFAIL:
1890			h_errno = TRY_AGAIN;
1891			break;
1892		case NOERROR:
1893			h_errno = NO_DATA;
1894			break;
1895		case FORMERR:
1896		case NOTIMP:
1897		case REFUSED:
1898		default:
1899			h_errno = NO_RECOVERY;
1900			break;
1901		}
1902		return (-1);
1903	}
1904	return (ancount);
1905}
1906
1907/*
1908 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1909 * Return the size of the response on success, -1 on error.
1910 * If enabled, implement search rules until answer or unrecoverable failure
1911 * is detected.  Error code, if any, is left in h_errno.
1912 */
1913static int
1914res_searchN(name, target)
1915	const char *name;	/* domain name */
1916	struct res_target *target;
1917{
1918	const char *cp, * const *domain;
1919	HEADER *hp = (HEADER *)(void *)target->answer;	/*XXX*/
1920	u_int dots;
1921	int trailing_dot, ret, saved_herrno;
1922	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1923
1924	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1925		h_errno = NETDB_INTERNAL;
1926		return (-1);
1927	}
1928
1929	errno = 0;
1930	h_errno = HOST_NOT_FOUND;	/* default, if we never query */
1931	dots = 0;
1932	for (cp = name; *cp; cp++)
1933		dots += (*cp == '.');
1934	trailing_dot = 0;
1935	if (cp > name && *--cp == '.')
1936		trailing_dot++;
1937
1938	/*
1939	 * if there aren't any dots, it could be a user-level alias
1940	 */
1941	if (!dots && (cp = __hostalias(name)) != NULL)
1942		return (res_queryN(cp, target));
1943
1944	/*
1945	 * If there are dots in the name already, let's just give it a try
1946	 * 'as is'.  The threshold can be set with the "ndots" option.
1947	 */
1948	saved_herrno = -1;
1949	if (dots >= _res.ndots) {
1950		ret = res_querydomainN(name, NULL, target);
1951		if (ret > 0)
1952			return (ret);
1953		saved_herrno = h_errno;
1954		tried_as_is++;
1955	}
1956
1957	/*
1958	 * We do at least one level of search if
1959	 *	- there is no dot and RES_DEFNAME is set, or
1960	 *	- there is at least one dot, there is no trailing dot,
1961	 *	  and RES_DNSRCH is set.
1962	 */
1963	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1964	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1965		int done = 0;
1966
1967		for (domain = (const char * const *)_res.dnsrch;
1968		   *domain && !done;
1969		   domain++) {
1970
1971			ret = res_querydomainN(name, *domain, target);
1972			if (ret > 0)
1973				return (ret);
1974
1975			/*
1976			 * If no server present, give up.
1977			 * If name isn't found in this domain,
1978			 * keep trying higher domains in the search list
1979			 * (if that's enabled).
1980			 * On a NO_DATA error, keep trying, otherwise
1981			 * a wildcard entry of another type could keep us
1982			 * from finding this entry higher in the domain.
1983			 * If we get some other error (negative answer or
1984			 * server failure), then stop searching up,
1985			 * but try the input name below in case it's
1986			 * fully-qualified.
1987			 */
1988			if (errno == ECONNREFUSED) {
1989				h_errno = TRY_AGAIN;
1990				return (-1);
1991			}
1992
1993			switch (h_errno) {
1994			case NO_DATA:
1995				got_nodata++;
1996				/* FALLTHROUGH */
1997			case HOST_NOT_FOUND:
1998				/* keep trying */
1999				break;
2000			case TRY_AGAIN:
2001				if (hp->rcode == SERVFAIL) {
2002					/* try next search element, if any */
2003					got_servfail++;
2004					break;
2005				}
2006				/* FALLTHROUGH */
2007			default:
2008				/* anything else implies that we're done */
2009				done++;
2010			}
2011			/*
2012			 * if we got here for some reason other than DNSRCH,
2013			 * we only wanted one iteration of the loop, so stop.
2014			 */
2015			if (!(_res.options & RES_DNSRCH))
2016			        done++;
2017		}
2018	}
2019
2020	/*
2021	 * if we have not already tried the name "as is", do that now.
2022	 * note that we do this regardless of how many dots were in the
2023	 * name or whether it ends with a dot.
2024	 */
2025	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
2026		ret = res_querydomainN(name, NULL, target);
2027		if (ret > 0)
2028			return (ret);
2029	}
2030
2031	/*
2032	 * if we got here, we didn't satisfy the search.
2033	 * if we did an initial full query, return that query's h_errno
2034	 * (note that we wouldn't be here if that query had succeeded).
2035	 * else if we ever got a nodata, send that back as the reason.
2036	 * else send back meaningless h_errno, that being the one from
2037	 * the last DNSRCH we did.
2038	 */
2039	if (saved_herrno != -1)
2040		h_errno = saved_herrno;
2041	else if (got_nodata)
2042		h_errno = NO_DATA;
2043	else if (got_servfail)
2044		h_errno = TRY_AGAIN;
2045	return (-1);
2046}
2047
2048/*
2049 * Perform a call on res_query on the concatenation of name and domain,
2050 * removing a trailing dot from name if domain is NULL.
2051 */
2052static int
2053res_querydomainN(name, domain, target)
2054	const char *name, *domain;
2055	struct res_target *target;
2056{
2057	char nbuf[MAXDNAME];
2058	const char *longname = nbuf;
2059	size_t n, d;
2060
2061	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2062		h_errno = NETDB_INTERNAL;
2063		return (-1);
2064	}
2065#ifdef DEBUG
2066	if (_res.options & RES_DEBUG)
2067		printf(";; res_querydomain(%s, %s)\n",
2068			name, domain?domain:"<Nil>");
2069#endif
2070	if (domain == NULL) {
2071		/*
2072		 * Check for trailing '.';
2073		 * copy without '.' if present.
2074		 */
2075		n = strlen(name);
2076		if (n >= MAXDNAME) {
2077			h_errno = NO_RECOVERY;
2078			return (-1);
2079		}
2080		if (n > 0 && name[--n] == '.') {
2081			strncpy(nbuf, name, n);
2082			nbuf[n] = '\0';
2083		} else
2084			longname = name;
2085	} else {
2086		n = strlen(name);
2087		d = strlen(domain);
2088		if (n + d + 1 >= MAXDNAME) {
2089			h_errno = NO_RECOVERY;
2090			return (-1);
2091		}
2092		snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2093	}
2094	return (res_queryN(longname, target));
2095}
2096