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