getaddrinfo.c revision 111618
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 111618 2003-02-27 13:40:01Z nectar $");
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#include "libc_private.h"
99
100#if defined(__KAME__) && defined(INET6)
101# define FAITH
102#endif
103
104#define SUCCESS 0
105#define ANY 0
106#define YES 1
107#define NO  0
108
109static const char in_addrany[] = { 0, 0, 0, 0 };
110static const char in_loopback[] = { 127, 0, 0, 1 };
111#ifdef INET6
112static const char in6_addrany[] = {
113	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
114};
115static const char in6_loopback[] = {
116	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
117};
118#endif
119
120static const struct afd {
121	int a_af;
122	int a_addrlen;
123	int a_socklen;
124	int a_off;
125	const char *a_addrany;
126	const char *a_loopback;
127	int a_scoped;
128} afdl [] = {
129#ifdef INET6
130#define	N_INET6 0
131	{PF_INET6, sizeof(struct in6_addr),
132	 sizeof(struct sockaddr_in6),
133	 offsetof(struct sockaddr_in6, sin6_addr),
134	 in6_addrany, in6_loopback, 1},
135#define	N_INET 1
136#else
137#define	N_INET 0
138#endif
139	{PF_INET, sizeof(struct in_addr),
140	 sizeof(struct sockaddr_in),
141	 offsetof(struct sockaddr_in, sin_addr),
142	 in_addrany, in_loopback, 0},
143	{0, 0, 0, 0, NULL, NULL, 0},
144};
145
146struct explore {
147	int e_af;
148	int e_socktype;
149	int e_protocol;
150	const char *e_protostr;
151	int e_wild;
152#define WILD_AF(ex)		((ex)->e_wild & 0x01)
153#define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
154#define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
155};
156
157static const struct explore explore[] = {
158#if 0
159	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
160#endif
161#ifdef INET6
162	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
163	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
164	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
165#endif
166	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
167	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
168	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
169	{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
170	{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
171	{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
172	{ -1, 0, 0, NULL, 0 },
173};
174
175#ifdef INET6
176#define PTON_MAX	16
177#else
178#define PTON_MAX	4
179#endif
180
181static const ns_src default_dns_files[] = {
182	{ NSSRC_FILES, 	NS_SUCCESS },
183	{ NSSRC_DNS, 	NS_SUCCESS },
184	{ 0 }
185};
186
187#define MAXPACKET	(64*1024)
188
189typedef union {
190	HEADER hdr;
191	u_char buf[MAXPACKET];
192} querybuf;
193
194struct res_target {
195	struct res_target *next;
196	const char *name;	/* domain name */
197	int qclass, qtype;	/* class and type of query */
198	u_char *answer;		/* buffer to put answer */
199	int anslen;		/* size of answer buffer */
200	int n;			/* result length */
201};
202
203static int str_isnumber(const char *);
204static int explore_fqdn(const struct addrinfo *, const char *,
205	const char *, struct addrinfo **);
206static int explore_null(const struct addrinfo *,
207	const char *, struct addrinfo **);
208static int explore_numeric(const struct addrinfo *, const char *,
209	const char *, struct addrinfo **);
210static int explore_numeric_scope(const struct addrinfo *, const char *,
211	const char *, struct addrinfo **);
212static int get_canonname(const struct addrinfo *,
213	struct addrinfo *, const char *);
214static struct addrinfo *get_ai(const struct addrinfo *,
215	const struct afd *, const char *);
216static int get_portmatch(const struct addrinfo *, const char *);
217static int get_port(struct addrinfo *, const char *, int);
218static const struct afd *find_afd(int);
219static int addrconfig(struct addrinfo *);
220#ifdef INET6
221static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
222#endif
223
224static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
225	const struct addrinfo *);
226static int _dns_getaddrinfo(void *, void *, va_list);
227static void _sethtent(void);
228static void _endhtent(void);
229static struct addrinfo *_gethtent(const char *, const struct addrinfo *);
230static int _files_getaddrinfo(void *, void *, va_list);
231#ifdef YP
232static struct addrinfo *_yphostent(char *, const struct addrinfo *);
233static int _yp_getaddrinfo(void *, void *, va_list);
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	errno = 0;
350	(void)strtoul(p, &ep, 10);
351	if (errno == 0 && ep && *ep == '\0')
352		return YES;
353	else
354		return NO;
355}
356
357int
358getaddrinfo(hostname, servname, hints, res)
359	const char *hostname, *servname;
360	const struct addrinfo *hints;
361	struct addrinfo **res;
362{
363	struct addrinfo sentinel;
364	struct addrinfo *cur;
365	int error = 0;
366	struct addrinfo ai;
367	struct addrinfo ai0;
368	struct addrinfo *pai;
369	const struct explore *ex;
370
371	memset(&sentinel, 0, sizeof(sentinel));
372	cur = &sentinel;
373	pai = &ai;
374	pai->ai_flags = 0;
375	pai->ai_family = PF_UNSPEC;
376	pai->ai_socktype = ANY;
377	pai->ai_protocol = ANY;
378	pai->ai_addrlen = 0;
379	pai->ai_canonname = NULL;
380	pai->ai_addr = NULL;
381	pai->ai_next = NULL;
382
383	if (hostname == NULL && servname == NULL)
384		return EAI_NONAME;
385	if (hints) {
386		/* error check for hints */
387		if (hints->ai_addrlen || hints->ai_canonname ||
388		    hints->ai_addr || hints->ai_next)
389			ERR(EAI_BADHINTS); /* xxx */
390		if (hints->ai_flags & ~AI_MASK)
391			ERR(EAI_BADFLAGS);
392		switch (hints->ai_family) {
393		case PF_UNSPEC:
394		case PF_INET:
395#ifdef INET6
396		case PF_INET6:
397#endif
398			break;
399		default:
400			ERR(EAI_FAMILY);
401		}
402		memcpy(pai, hints, sizeof(*pai));
403
404		/*
405		 * if both socktype/protocol are specified, check if they
406		 * are meaningful combination.
407		 */
408		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
409			for (ex = explore; ex->e_af >= 0; ex++) {
410				if (pai->ai_family != ex->e_af)
411					continue;
412				if (ex->e_socktype == ANY)
413					continue;
414				if (ex->e_protocol == ANY)
415					continue;
416				if (pai->ai_socktype == ex->e_socktype &&
417				    pai->ai_protocol != ex->e_protocol) {
418					ERR(EAI_BADHINTS);
419				}
420			}
421		}
422	}
423
424	/*
425	 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
426	 * AF_INET6 query.  They need to be ignored if specified in other
427	 * occassions.
428	 */
429	switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
430	case AI_V4MAPPED:
431	case AI_ALL | AI_V4MAPPED:
432		if (pai->ai_family != AF_INET6)
433			pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
434		break;
435	case AI_ALL:
436#if 1
437		/* illegal */
438		ERR(EAI_BADFLAGS);
439#else
440		pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
441#endif
442		break;
443	}
444
445	/*
446	 * check for special cases.  (1) numeric servname is disallowed if
447	 * socktype/protocol are left unspecified. (2) servname is disallowed
448	 * for raw and other inet{,6} sockets.
449	 */
450	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
451#ifdef PF_INET6
452	    || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
453#endif
454	    ) {
455		ai0 = *pai;	/* backup *pai */
456
457		if (pai->ai_family == PF_UNSPEC) {
458#ifdef PF_INET6
459			pai->ai_family = PF_INET6;
460#else
461			pai->ai_family = PF_INET;
462#endif
463		}
464		error = get_portmatch(pai, servname);
465		if (error)
466			ERR(error);
467
468		*pai = ai0;
469	}
470
471	ai0 = *pai;
472
473	/* NULL hostname, or numeric hostname */
474	for (ex = explore; ex->e_af >= 0; ex++) {
475		*pai = ai0;
476
477		/* PF_UNSPEC entries are prepared for DNS queries only */
478		if (ex->e_af == PF_UNSPEC)
479			continue;
480
481		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
482			continue;
483		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
484			continue;
485		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
486			continue;
487
488		if (pai->ai_family == PF_UNSPEC)
489			pai->ai_family = ex->e_af;
490		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
491			pai->ai_socktype = ex->e_socktype;
492		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
493			pai->ai_protocol = ex->e_protocol;
494
495		if (hostname == NULL)
496			error = explore_null(pai, servname, &cur->ai_next);
497		else
498			error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
499
500		if (error)
501			goto free;
502
503		while (cur && cur->ai_next)
504			cur = cur->ai_next;
505	}
506
507	/*
508	 * XXX
509	 * If numreic representation of AF1 can be interpreted as FQDN
510	 * representation of AF2, we need to think again about the code below.
511	 */
512	if (sentinel.ai_next)
513		goto good;
514
515	if (pai->ai_flags & AI_NUMERICHOST)
516		ERR(EAI_NONAME);
517	if (hostname == NULL)
518		ERR(EAI_NODATA);
519
520	if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
521		ERR(EAI_FAIL);
522
523	/*
524	 * hostname as alphabetical name.
525	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
526	 * outer loop by AFs.
527	 */
528	for (ex = explore; ex->e_af >= 0; ex++) {
529		*pai = ai0;
530
531		/* require exact match for family field */
532		if (pai->ai_family != ex->e_af)
533			continue;
534
535		if (!MATCH(pai->ai_socktype, ex->e_socktype,
536				WILD_SOCKTYPE(ex))) {
537			continue;
538		}
539		if (!MATCH(pai->ai_protocol, ex->e_protocol,
540				WILD_PROTOCOL(ex))) {
541			continue;
542		}
543
544		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
545			pai->ai_socktype = ex->e_socktype;
546		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
547			pai->ai_protocol = ex->e_protocol;
548
549		error = explore_fqdn(pai, hostname, servname,
550			&cur->ai_next);
551
552		while (cur && cur->ai_next)
553			cur = cur->ai_next;
554	}
555
556	/* XXX */
557	if (sentinel.ai_next)
558		error = 0;
559
560	if (error)
561		goto free;
562	if (error == 0) {
563		if (sentinel.ai_next) {
564 good:
565			*res = sentinel.ai_next;
566			return SUCCESS;
567		} else
568			error = EAI_FAIL;
569	}
570 free:
571 bad:
572	if (sentinel.ai_next)
573		freeaddrinfo(sentinel.ai_next);
574	*res = NULL;
575	return error;
576}
577
578/*
579 * FQDN hostname, DNS lookup
580 */
581static int
582explore_fqdn(pai, hostname, servname, res)
583	const struct addrinfo *pai;
584	const char *hostname;
585	const char *servname;
586	struct addrinfo **res;
587{
588	struct addrinfo *result;
589	struct addrinfo *cur;
590	int error = 0;
591	static const ns_dtab dtab[] = {
592		NS_FILES_CB(_files_getaddrinfo, NULL)
593		{ NSSRC_DNS, _dns_getaddrinfo, NULL },	/* force -DHESIOD */
594		NS_NIS_CB(_yp_getaddrinfo, NULL)
595		{ 0 }
596	};
597
598	result = NULL;
599
600	THREAD_LOCK();
601
602	/*
603	 * if the servname does not match socktype/protocol, ignore it.
604	 */
605	if (get_portmatch(pai, servname) != 0) {
606		THREAD_UNLOCK();
607		return 0;
608	}
609
610	switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
611			default_dns_files, hostname, pai)) {
612	case NS_TRYAGAIN:
613		error = EAI_AGAIN;
614		goto free;
615	case NS_UNAVAIL:
616		error = EAI_FAIL;
617		goto free;
618	case NS_NOTFOUND:
619		error = EAI_NODATA;
620		goto free;
621	case NS_SUCCESS:
622		error = 0;
623		for (cur = result; cur; cur = cur->ai_next) {
624			GET_PORT(cur, servname);
625			/* canonname should be filled already */
626		}
627		break;
628	}
629	THREAD_UNLOCK();
630
631	*res = result;
632
633	return 0;
634
635free:
636	THREAD_UNLOCK();
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		u_int32_t 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 (ip6_str2scopeid(scope, sin6, &scopeid) == -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		strlcpy(ai->ai_canonname, str, strlen(str) + 1);
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 = atoi(servname);
984		if (port < 0 || port > 65535)
985			return EAI_SERVICE;
986		port = htons(port);
987	} else {
988		switch (ai->ai_socktype) {
989		case SOCK_DGRAM:
990			proto = "udp";
991			break;
992		case SOCK_STREAM:
993			proto = "tcp";
994			break;
995		default:
996			proto = NULL;
997			break;
998		}
999
1000		if ((sp = getservbyname(servname, proto)) == NULL)
1001			return EAI_SERVICE;
1002		port = sp->s_port;
1003	}
1004
1005	if (!matchonly) {
1006		switch (ai->ai_family) {
1007		case AF_INET:
1008			((struct sockaddr_in *)(void *)
1009			    ai->ai_addr)->sin_port = port;
1010			break;
1011#ifdef INET6
1012		case AF_INET6:
1013			((struct sockaddr_in6 *)(void *)
1014			    ai->ai_addr)->sin6_port = port;
1015			break;
1016#endif
1017		}
1018	}
1019
1020	return 0;
1021}
1022
1023static const struct afd *
1024find_afd(af)
1025	int af;
1026{
1027	const struct afd *afd;
1028
1029	if (af == PF_UNSPEC)
1030		return NULL;
1031	for (afd = afdl; afd->a_af; afd++) {
1032		if (afd->a_af == af)
1033			return afd;
1034	}
1035	return NULL;
1036}
1037
1038/*
1039 * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
1040 * will take care of it.
1041 * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
1042 * if the code is right or not.
1043 *
1044 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
1045 * _dns_getaddrinfo.
1046 */
1047static int
1048addrconfig(pai)
1049	struct addrinfo *pai;
1050{
1051	int s, af;
1052
1053	/*
1054	 * TODO:
1055	 * Note that implementation dependent test for address
1056	 * configuration should be done everytime called
1057	 * (or apropriate interval),
1058	 * because addresses will be dynamically assigned or deleted.
1059	 */
1060	af = pai->ai_family;
1061	if (af == AF_UNSPEC) {
1062		if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1063			af = AF_INET;
1064		else {
1065			_close(s);
1066			if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1067				af = AF_INET6;
1068			else
1069				_close(s);
1070		}
1071	}
1072	if (af != AF_UNSPEC) {
1073		if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
1074			return 0;
1075		_close(s);
1076	}
1077	pai->ai_family = af;
1078	return 1;
1079}
1080
1081#ifdef INET6
1082/* convert a string to a scope identifier. XXX: IPv6 specific */
1083static int
1084ip6_str2scopeid(scope, sin6, scopeid)
1085	char *scope;
1086	struct sockaddr_in6 *sin6;
1087	u_int32_t *scopeid;
1088{
1089	u_long lscopeid;
1090	struct in6_addr *a6;
1091	char *ep;
1092
1093	a6 = &sin6->sin6_addr;
1094
1095	/* empty scopeid portion is invalid */
1096	if (*scope == '\0')
1097		return -1;
1098
1099	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1100		/*
1101		 * We currently assume a one-to-one mapping between links
1102		 * and interfaces, so we simply use interface indices for
1103		 * like-local scopes.
1104		 */
1105		*scopeid = if_nametoindex(scope);
1106		if (*scopeid == 0)
1107			goto trynumeric;
1108		return 0;
1109	}
1110
1111	/* still unclear about literal, allow numeric only - placeholder */
1112	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1113		goto trynumeric;
1114	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1115		goto trynumeric;
1116	else
1117		goto trynumeric;	/* global */
1118
1119	/* try to convert to a numeric id as a last resort */
1120  trynumeric:
1121	errno = 0;
1122	lscopeid = strtoul(scope, &ep, 10);
1123	*scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1124	if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1125		return 0;
1126	else
1127		return -1;
1128}
1129#endif
1130
1131#ifdef RESOLVSORT
1132struct addr_ptr {
1133	struct addrinfo *ai;
1134	int aval;
1135};
1136
1137static int
1138addr4sort(struct addrinfo *sentinel)
1139{
1140	struct addrinfo *ai;
1141	struct addr_ptr *addrs, addr;
1142	struct sockaddr_in *sin;
1143	int naddrs, i, j;
1144	int needsort = 0;
1145
1146	if (!sentinel)
1147		return -1;
1148	naddrs = 0;
1149	for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
1150		naddrs++;
1151	if (naddrs < 2)
1152		return 0;		/* We don't need sorting. */
1153	if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
1154		return -1;
1155	i = 0;
1156	for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
1157		sin = (struct sockaddr_in *)ai->ai_addr;
1158		for (j = 0; (unsigned)j < _res.nsort; j++) {
1159			if (_res.sort_list[j].addr.s_addr ==
1160			    (sin->sin_addr.s_addr & _res.sort_list[j].mask))
1161				break;
1162		}
1163		addrs[i].ai = ai;
1164		addrs[i].aval = j;
1165		if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
1166			needsort = i;
1167		i++;
1168	}
1169	if (!needsort) {
1170		free(addrs);
1171		return 0;
1172	}
1173
1174	while (needsort < naddrs) {
1175	    for (j = needsort - 1; j >= 0; j--) {
1176		if (addrs[j].aval > addrs[j+1].aval) {
1177		    addr = addrs[j];
1178		    addrs[j] = addrs[j + 1];
1179		    addrs[j + 1] = addr;
1180		} else
1181		    break;
1182	    }
1183	    needsort++;
1184	}
1185
1186	ai = sentinel;
1187	for (i = 0; i < naddrs; ++i) {
1188		ai->ai_next = addrs[i].ai;
1189		ai = ai->ai_next;
1190	}
1191	ai->ai_next = NULL;
1192	free(addrs);
1193	return 0;
1194}
1195#endif /*RESOLVSORT*/
1196
1197#ifdef DEBUG
1198static const char AskedForGot[] =
1199	"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1200#endif
1201static FILE *hostf = NULL;
1202
1203static struct addrinfo *
1204getanswer(answer, anslen, qname, qtype, pai)
1205	const querybuf *answer;
1206	int anslen;
1207	const char *qname;
1208	int qtype;
1209	const struct addrinfo *pai;
1210{
1211	struct addrinfo sentinel, *cur;
1212	struct addrinfo ai;
1213	const struct afd *afd;
1214	char *canonname;
1215	const HEADER *hp;
1216	const u_char *cp;
1217	int n;
1218	const u_char *eom;
1219	char *bp, *ep;
1220	int type, class, ancount, qdcount;
1221	int haveanswer, had_error;
1222	char tbuf[MAXDNAME];
1223	int (*name_ok)(const char *);
1224	char hostbuf[8*1024];
1225
1226	memset(&sentinel, 0, sizeof(sentinel));
1227	cur = &sentinel;
1228
1229	canonname = NULL;
1230	eom = answer->buf + anslen;
1231	switch (qtype) {
1232	case T_A:
1233	case T_AAAA:
1234	case T_ANY:	/*use T_ANY only for T_A/T_AAAA lookup*/
1235		name_ok = res_hnok;
1236		break;
1237	default:
1238		return (NULL);	/* XXX should be abort(); */
1239	}
1240	/*
1241	 * find first satisfactory answer
1242	 */
1243	hp = &answer->hdr;
1244	ancount = ntohs(hp->ancount);
1245	qdcount = ntohs(hp->qdcount);
1246	bp = hostbuf;
1247	ep = hostbuf + sizeof hostbuf;
1248	cp = answer->buf + HFIXEDSZ;
1249	if (qdcount != 1) {
1250		h_errno = NO_RECOVERY;
1251		return (NULL);
1252	}
1253	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1254	if ((n < 0) || !(*name_ok)(bp)) {
1255		h_errno = NO_RECOVERY;
1256		return (NULL);
1257	}
1258	cp += n + QFIXEDSZ;
1259	if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1260		/* res_send() has already verified that the query name is the
1261		 * same as the one we sent; this just gets the expanded name
1262		 * (i.e., with the succeeding search-domain tacked on).
1263		 */
1264		n = strlen(bp) + 1;		/* for the \0 */
1265		if (n >= MAXHOSTNAMELEN) {
1266			h_errno = NO_RECOVERY;
1267			return (NULL);
1268		}
1269		canonname = bp;
1270		bp += n;
1271		/* The qname can be abbreviated, but h_name is now absolute. */
1272		qname = canonname;
1273	}
1274	haveanswer = 0;
1275	had_error = 0;
1276	while (ancount-- > 0 && cp < eom && !had_error) {
1277		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1278		if ((n < 0) || !(*name_ok)(bp)) {
1279			had_error++;
1280			continue;
1281		}
1282		cp += n;			/* name */
1283		type = _getshort(cp);
1284 		cp += INT16SZ;			/* type */
1285		class = _getshort(cp);
1286 		cp += INT16SZ + INT32SZ;	/* class, TTL */
1287		n = _getshort(cp);
1288		cp += INT16SZ;			/* len */
1289		if (class != C_IN) {
1290			/* XXX - debug? syslog? */
1291			cp += n;
1292			continue;		/* XXX - had_error++ ? */
1293		}
1294		if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1295		    type == T_CNAME) {
1296			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1297			if ((n < 0) || !(*name_ok)(tbuf)) {
1298				had_error++;
1299				continue;
1300			}
1301			cp += n;
1302			/* Get canonical name. */
1303			n = strlen(tbuf) + 1;	/* for the \0 */
1304			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1305				had_error++;
1306				continue;
1307			}
1308			strlcpy(bp, tbuf, ep - bp);
1309			canonname = bp;
1310			bp += n;
1311			continue;
1312		}
1313		if (qtype == T_ANY) {
1314			if (!(type == T_A || type == T_AAAA)) {
1315				cp += n;
1316				continue;
1317			}
1318		} else if (type != qtype) {
1319#ifdef DEBUG
1320			if (type != T_KEY && type != T_SIG)
1321				syslog(LOG_NOTICE|LOG_AUTH,
1322	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1323				       qname, p_class(C_IN), p_type(qtype),
1324				       p_type(type));
1325#endif
1326			cp += n;
1327			continue;		/* XXX - had_error++ ? */
1328		}
1329		switch (type) {
1330		case T_A:
1331		case T_AAAA:
1332			if (strcasecmp(canonname, bp) != 0) {
1333#ifdef DEBUG
1334				syslog(LOG_NOTICE|LOG_AUTH,
1335				       AskedForGot, canonname, bp);
1336#endif
1337				cp += n;
1338				continue;	/* XXX - had_error++ ? */
1339			}
1340			if (type == T_A && n != INADDRSZ) {
1341				cp += n;
1342				continue;
1343			}
1344			if (type == T_AAAA && n != IN6ADDRSZ) {
1345				cp += n;
1346				continue;
1347			}
1348#ifdef FILTER_V4MAPPED
1349			if (type == T_AAAA) {
1350				struct in6_addr in6;
1351				memcpy(&in6, cp, sizeof(in6));
1352				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1353					cp += n;
1354					continue;
1355				}
1356			}
1357#endif
1358			if (!haveanswer) {
1359				int nn;
1360
1361				canonname = bp;
1362				nn = strlen(bp) + 1;	/* for the \0 */
1363				bp += nn;
1364			}
1365
1366			/* don't overwrite pai */
1367			ai = *pai;
1368			ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1369			afd = find_afd(ai.ai_family);
1370			if (afd == NULL) {
1371				cp += n;
1372				continue;
1373			}
1374			cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1375			if (cur->ai_next == NULL)
1376				had_error++;
1377			while (cur && cur->ai_next)
1378				cur = cur->ai_next;
1379			cp += n;
1380			break;
1381		default:
1382			abort();
1383		}
1384		if (!had_error)
1385			haveanswer++;
1386	}
1387	if (haveanswer) {
1388#if defined(RESOLVSORT)
1389		/*
1390		 * We support only IPv4 address for backward
1391		 * compatibility against gethostbyname(3).
1392		 */
1393		if (_res.nsort && qtype == T_A) {
1394			if (addr4sort(&sentinel) < 0) {
1395				freeaddrinfo(sentinel.ai_next);
1396				h_errno = NO_RECOVERY;
1397				return NULL;
1398			}
1399		}
1400#endif /*RESOLVSORT*/
1401		if (!canonname)
1402			(void)get_canonname(pai, sentinel.ai_next, qname);
1403		else
1404			(void)get_canonname(pai, sentinel.ai_next, canonname);
1405		h_errno = NETDB_SUCCESS;
1406		return sentinel.ai_next;
1407	}
1408
1409	h_errno = NO_RECOVERY;
1410	return NULL;
1411}
1412
1413/*ARGSUSED*/
1414static int
1415_dns_getaddrinfo(rv, cb_data, ap)
1416	void	*rv;
1417	void	*cb_data;
1418	va_list	 ap;
1419{
1420	struct addrinfo *ai;
1421	querybuf *buf, *buf2;
1422	const char *name;
1423	const struct addrinfo *pai;
1424	struct addrinfo sentinel, *cur;
1425	struct res_target q, q2;
1426
1427	name = va_arg(ap, char *);
1428	pai = va_arg(ap, const struct addrinfo *);
1429
1430	memset(&q, 0, sizeof(q2));
1431	memset(&q2, 0, sizeof(q2));
1432	memset(&sentinel, 0, sizeof(sentinel));
1433	cur = &sentinel;
1434
1435	buf = malloc(sizeof(*buf));
1436	if (!buf) {
1437		h_errno = NETDB_INTERNAL;
1438		return NS_NOTFOUND;
1439	}
1440	buf2 = malloc(sizeof(*buf2));
1441	if (!buf2) {
1442		free(buf);
1443		h_errno = NETDB_INTERNAL;
1444		return NS_NOTFOUND;
1445	}
1446
1447	switch (pai->ai_family) {
1448	case AF_UNSPEC:
1449		/* prefer IPv6 */
1450		q.name = name;
1451		q.qclass = C_IN;
1452		q.qtype = T_AAAA;
1453		q.answer = buf->buf;
1454		q.anslen = sizeof(buf->buf);
1455		q.next = &q2;
1456		q2.name = name;
1457		q2.qclass = C_IN;
1458		q2.qtype = T_A;
1459		q2.answer = buf2->buf;
1460		q2.anslen = sizeof(buf2->buf);
1461		break;
1462	case AF_INET:
1463		q.name = name;
1464		q.qclass = C_IN;
1465		q.qtype = T_A;
1466		q.answer = buf->buf;
1467		q.anslen = sizeof(buf->buf);
1468		break;
1469	case AF_INET6:
1470		q.name = name;
1471		q.qclass = C_IN;
1472		q.qtype = T_AAAA;
1473		q.answer = buf->buf;
1474		q.anslen = sizeof(buf->buf);
1475		break;
1476	default:
1477		free(buf);
1478		free(buf2);
1479		return NS_UNAVAIL;
1480	}
1481	if (res_searchN(name, &q) < 0) {
1482		free(buf);
1483		free(buf2);
1484		return NS_NOTFOUND;
1485	}
1486	ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1487	if (ai) {
1488		cur->ai_next = ai;
1489		while (cur && cur->ai_next)
1490			cur = cur->ai_next;
1491	}
1492	if (q.next) {
1493		ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1494		if (ai)
1495			cur->ai_next = ai;
1496	}
1497	free(buf);
1498	free(buf2);
1499	if (sentinel.ai_next == NULL)
1500		switch (h_errno) {
1501		case HOST_NOT_FOUND:
1502			return NS_NOTFOUND;
1503		case TRY_AGAIN:
1504			return NS_TRYAGAIN;
1505		default:
1506			return NS_UNAVAIL;
1507		}
1508	*((struct addrinfo **)rv) = sentinel.ai_next;
1509	return NS_SUCCESS;
1510}
1511
1512static void
1513_sethtent()
1514{
1515	if (!hostf)
1516		hostf = fopen(_PATH_HOSTS, "r" );
1517	else
1518		rewind(hostf);
1519}
1520
1521static void
1522_endhtent()
1523{
1524	if (hostf) {
1525		(void) fclose(hostf);
1526		hostf = NULL;
1527	}
1528}
1529
1530static struct addrinfo *
1531_gethtent(name, pai)
1532	const char *name;
1533	const struct addrinfo *pai;
1534{
1535	char *p;
1536	char *cp, *tname, *cname;
1537	struct addrinfo hints, *res0, *res;
1538	int error;
1539	const char *addr;
1540	char hostbuf[8*1024];
1541
1542	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1543		return (NULL);
1544again:
1545	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
1546		return (NULL);
1547	if (*p == '#')
1548		goto again;
1549	if (!(cp = strpbrk(p, "#\n")))
1550		goto again;
1551	*cp = '\0';
1552	if (!(cp = strpbrk(p, " \t")))
1553		goto again;
1554	*cp++ = '\0';
1555	addr = p;
1556	cname = NULL;
1557	/* if this is not something we're looking for, skip it. */
1558	while (cp && *cp) {
1559		if (*cp == ' ' || *cp == '\t') {
1560			cp++;
1561			continue;
1562		}
1563		tname = cp;
1564		if (cname == NULL)
1565			cname = cp;
1566		if ((cp = strpbrk(cp, " \t")) != NULL)
1567			*cp++ = '\0';
1568		if (strcasecmp(name, tname) == 0)
1569			goto found;
1570	}
1571	goto again;
1572
1573found:
1574	/* we should not glob socktype/protocol here */
1575	memset(&hints, 0, sizeof(hints));
1576	hints.ai_family = pai->ai_family;
1577	hints.ai_socktype = SOCK_DGRAM;
1578	hints.ai_protocol = 0;
1579	hints.ai_flags = AI_NUMERICHOST;
1580	error = getaddrinfo(addr, "0", &hints, &res0);
1581	if (error)
1582		goto again;
1583#ifdef FILTER_V4MAPPED
1584	/* XXX should check all items in the chain */
1585	if (res0->ai_family == AF_INET6 &&
1586	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) {
1587		freeaddrinfo(res0);
1588		goto again;
1589	}
1590#endif
1591	for (res = res0; res; res = res->ai_next) {
1592		/* cover it up */
1593		res->ai_flags = pai->ai_flags;
1594		res->ai_socktype = pai->ai_socktype;
1595		res->ai_protocol = pai->ai_protocol;
1596
1597		if (pai->ai_flags & AI_CANONNAME) {
1598			if (get_canonname(pai, res, cname) != 0) {
1599				freeaddrinfo(res0);
1600				goto again;
1601			}
1602		}
1603	}
1604	return res0;
1605}
1606
1607/*ARGSUSED*/
1608static int
1609_files_getaddrinfo(rv, cb_data, ap)
1610	void	*rv;
1611	void	*cb_data;
1612	va_list	 ap;
1613{
1614	const char *name;
1615	const struct addrinfo *pai;
1616	struct addrinfo sentinel, *cur;
1617	struct addrinfo *p;
1618
1619	name = va_arg(ap, char *);
1620	pai = va_arg(ap, struct addrinfo *);
1621
1622	memset(&sentinel, 0, sizeof(sentinel));
1623	cur = &sentinel;
1624
1625	_sethtent();
1626	while ((p = _gethtent(name, pai)) != NULL) {
1627		cur->ai_next = p;
1628		while (cur && cur->ai_next)
1629			cur = cur->ai_next;
1630	}
1631	_endhtent();
1632
1633	*((struct addrinfo **)rv) = sentinel.ai_next;
1634	if (sentinel.ai_next == NULL)
1635		return NS_NOTFOUND;
1636	return NS_SUCCESS;
1637}
1638
1639#ifdef YP
1640static char *__ypdomain;
1641
1642/*ARGSUSED*/
1643static struct addrinfo *
1644_yphostent(line, pai)
1645	char *line;
1646	const struct addrinfo *pai;
1647{
1648	struct addrinfo sentinel, *cur;
1649	struct addrinfo hints, *res, *res0;
1650	int error;
1651	char *p = line;
1652	const char *addr, *canonname;
1653	char *nextline;
1654	char *cp;
1655
1656	addr = canonname = NULL;
1657
1658	memset(&sentinel, 0, sizeof(sentinel));
1659	cur = &sentinel;
1660
1661nextline:
1662	/* terminate line */
1663	cp = strchr(p, '\n');
1664	if (cp) {
1665		*cp++ = '\0';
1666		nextline = cp;
1667	} else
1668		nextline = NULL;
1669
1670	cp = strpbrk(p, " \t");
1671	if (cp == NULL) {
1672		if (canonname == NULL)
1673			return (NULL);
1674		else
1675			goto done;
1676	}
1677	*cp++ = '\0';
1678
1679	addr = p;
1680
1681	while (cp && *cp) {
1682		if (*cp == ' ' || *cp == '\t') {
1683			cp++;
1684			continue;
1685		}
1686		if (!canonname)
1687			canonname = cp;
1688		if ((cp = strpbrk(cp, " \t")) != NULL)
1689			*cp++ = '\0';
1690	}
1691
1692	hints = *pai;
1693	hints.ai_flags = AI_NUMERICHOST;
1694	error = getaddrinfo(addr, NULL, &hints, &res0);
1695	if (error == 0) {
1696		for (res = res0; res; res = res->ai_next) {
1697			/* cover it up */
1698			res->ai_flags = pai->ai_flags;
1699
1700			if (pai->ai_flags & AI_CANONNAME)
1701				(void)get_canonname(pai, res, canonname);
1702		}
1703	} else
1704		res0 = NULL;
1705	if (res0) {
1706		cur->ai_next = res0;
1707		while (cur && cur->ai_next)
1708			cur = cur->ai_next;
1709	}
1710
1711	if (nextline) {
1712		p = nextline;
1713		goto nextline;
1714	}
1715
1716done:
1717	return sentinel.ai_next;
1718}
1719
1720/*ARGSUSED*/
1721static int
1722_yp_getaddrinfo(rv, cb_data, ap)
1723	void	*rv;
1724	void	*cb_data;
1725	va_list	 ap;
1726{
1727	struct addrinfo sentinel, *cur;
1728	struct addrinfo *ai = NULL;
1729	static char *__ypcurrent;
1730	int __ypcurrentlen, r;
1731	const char *name;
1732	const struct addrinfo *pai;
1733
1734	name = va_arg(ap, char *);
1735	pai = va_arg(ap, const struct addrinfo *);
1736
1737	memset(&sentinel, 0, sizeof(sentinel));
1738	cur = &sentinel;
1739
1740	if (!__ypdomain) {
1741		if (_yp_check(&__ypdomain) == 0)
1742			return NS_UNAVAIL;
1743	}
1744	if (__ypcurrent)
1745		free(__ypcurrent);
1746	__ypcurrent = NULL;
1747
1748	/* hosts.byname is only for IPv4 (Solaris8) */
1749	if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1750		r = yp_match(__ypdomain, "hosts.byname", name,
1751			(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1752		if (r == 0) {
1753			struct addrinfo ai4;
1754
1755			ai4 = *pai;
1756			ai4.ai_family = AF_INET;
1757			ai = _yphostent(__ypcurrent, &ai4);
1758			if (ai) {
1759				cur->ai_next = ai;
1760				while (cur && cur->ai_next)
1761					cur = cur->ai_next;
1762			}
1763		}
1764	}
1765
1766	/* ipnodes.byname can hold both IPv4/v6 */
1767	r = yp_match(__ypdomain, "ipnodes.byname", name,
1768		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1769	if (r == 0) {
1770		ai = _yphostent(__ypcurrent, pai);
1771		if (ai) {
1772			cur->ai_next = ai;
1773			while (cur && cur->ai_next)
1774				cur = cur->ai_next;
1775		}
1776	}
1777
1778	if (sentinel.ai_next == NULL) {
1779		h_errno = HOST_NOT_FOUND;
1780		return NS_NOTFOUND;
1781	}
1782	*((struct addrinfo **)rv) = sentinel.ai_next;
1783	return NS_SUCCESS;
1784}
1785#endif
1786
1787/* resolver logic */
1788
1789extern const char *__hostalias(const char *);
1790extern int h_errno;
1791
1792/*
1793 * Formulate a normal query, send, and await answer.
1794 * Returned answer is placed in supplied buffer "answer".
1795 * Perform preliminary check of answer, returning success only
1796 * if no error is indicated and the answer count is nonzero.
1797 * Return the size of the response on success, -1 on error.
1798 * Error number is left in h_errno.
1799 *
1800 * Caller must parse answer and determine whether it answers the question.
1801 */
1802static int
1803res_queryN(name, target)
1804	const char *name;	/* domain name */
1805	struct res_target *target;
1806{
1807	u_char *buf;
1808	HEADER *hp;
1809	int n;
1810	struct res_target *t;
1811	int rcode;
1812	int ancount;
1813
1814	rcode = NOERROR;
1815	ancount = 0;
1816
1817	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1818		h_errno = NETDB_INTERNAL;
1819		return (-1);
1820	}
1821
1822	buf = malloc(MAXPACKET);
1823	if (!buf) {
1824		h_errno = NETDB_INTERNAL;
1825		return -1;
1826	}
1827
1828	for (t = target; t; t = t->next) {
1829		int class, type;
1830		u_char *answer;
1831		int anslen;
1832
1833		hp = (HEADER *)(void *)t->answer;
1834		hp->rcode = NOERROR;	/* default */
1835
1836		/* make it easier... */
1837		class = t->qclass;
1838		type = t->qtype;
1839		answer = t->answer;
1840		anslen = t->anslen;
1841#ifdef DEBUG
1842		if (_res.options & RES_DEBUG)
1843			printf(";; res_query(%s, %d, %d)\n", name, class, type);
1844#endif
1845
1846		n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
1847		    buf, MAXPACKET);
1848		if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
1849			n = res_opt(n, buf, MAXPACKET, anslen);
1850		if (n <= 0) {
1851#ifdef DEBUG
1852			if (_res.options & RES_DEBUG)
1853				printf(";; res_query: mkquery failed\n");
1854#endif
1855			free(buf);
1856			h_errno = NO_RECOVERY;
1857			return (n);
1858		}
1859		n = res_send(buf, n, answer, anslen);
1860#if 0
1861		if (n < 0) {
1862#ifdef DEBUG
1863			if (_res.options & RES_DEBUG)
1864				printf(";; res_query: send error\n");
1865#endif
1866			free(buf);
1867			h_errno = TRY_AGAIN;
1868			return (n);
1869		}
1870#endif
1871
1872		if (n < 0 || n > anslen)
1873			hp->rcode = FORMERR; /* XXX not very informative */
1874		if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1875			rcode = hp->rcode;	/* record most recent error */
1876#ifdef DEBUG
1877			if (_res.options & RES_DEBUG)
1878				printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1879				    ntohs(hp->ancount));
1880#endif
1881			continue;
1882		}
1883
1884		ancount += ntohs(hp->ancount);
1885
1886		t->n = n;
1887	}
1888
1889	free(buf);
1890
1891	if (ancount == 0) {
1892		switch (rcode) {
1893		case NXDOMAIN:
1894			h_errno = HOST_NOT_FOUND;
1895			break;
1896		case SERVFAIL:
1897			h_errno = TRY_AGAIN;
1898			break;
1899		case NOERROR:
1900			h_errno = NO_DATA;
1901			break;
1902		case FORMERR:
1903		case NOTIMP:
1904		case REFUSED:
1905		default:
1906			h_errno = NO_RECOVERY;
1907			break;
1908		}
1909		return (-1);
1910	}
1911	return (ancount);
1912}
1913
1914/*
1915 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1916 * Return the size of the response on success, -1 on error.
1917 * If enabled, implement search rules until answer or unrecoverable failure
1918 * is detected.  Error code, if any, is left in h_errno.
1919 */
1920static int
1921res_searchN(name, target)
1922	const char *name;	/* domain name */
1923	struct res_target *target;
1924{
1925	const char *cp, * const *domain;
1926	HEADER *hp = (HEADER *)(void *)target->answer;	/*XXX*/
1927	u_int dots;
1928	int trailing_dot, ret, saved_herrno;
1929	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1930
1931	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1932		h_errno = NETDB_INTERNAL;
1933		return (-1);
1934	}
1935
1936	errno = 0;
1937	h_errno = HOST_NOT_FOUND;	/* default, if we never query */
1938	dots = 0;
1939	for (cp = name; *cp; cp++)
1940		dots += (*cp == '.');
1941	trailing_dot = 0;
1942	if (cp > name && *--cp == '.')
1943		trailing_dot++;
1944
1945	/*
1946	 * if there aren't any dots, it could be a user-level alias
1947	 */
1948	if (!dots && (cp = __hostalias(name)) != NULL)
1949		return (res_queryN(cp, target));
1950
1951	/*
1952	 * If there are dots in the name already, let's just give it a try
1953	 * 'as is'.  The threshold can be set with the "ndots" option.
1954	 */
1955	saved_herrno = -1;
1956	if (dots >= _res.ndots) {
1957		ret = res_querydomainN(name, NULL, target);
1958		if (ret > 0)
1959			return (ret);
1960		saved_herrno = h_errno;
1961		tried_as_is++;
1962	}
1963
1964	/*
1965	 * We do at least one level of search if
1966	 *	- there is no dot and RES_DEFNAME is set, or
1967	 *	- there is at least one dot, there is no trailing dot,
1968	 *	  and RES_DNSRCH is set.
1969	 */
1970	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1971	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1972		int done = 0;
1973
1974		for (domain = (const char * const *)_res.dnsrch;
1975		   *domain && !done;
1976		   domain++) {
1977
1978			ret = res_querydomainN(name, *domain, target);
1979			if (ret > 0)
1980				return (ret);
1981
1982			/*
1983			 * If no server present, give up.
1984			 * If name isn't found in this domain,
1985			 * keep trying higher domains in the search list
1986			 * (if that's enabled).
1987			 * On a NO_DATA error, keep trying, otherwise
1988			 * a wildcard entry of another type could keep us
1989			 * from finding this entry higher in the domain.
1990			 * If we get some other error (negative answer or
1991			 * server failure), then stop searching up,
1992			 * but try the input name below in case it's
1993			 * fully-qualified.
1994			 */
1995			if (errno == ECONNREFUSED) {
1996				h_errno = TRY_AGAIN;
1997				return (-1);
1998			}
1999
2000			switch (h_errno) {
2001			case NO_DATA:
2002				got_nodata++;
2003				/* FALLTHROUGH */
2004			case HOST_NOT_FOUND:
2005				/* keep trying */
2006				break;
2007			case TRY_AGAIN:
2008				if (hp->rcode == SERVFAIL) {
2009					/* try next search element, if any */
2010					got_servfail++;
2011					break;
2012				}
2013				/* FALLTHROUGH */
2014			default:
2015				/* anything else implies that we're done */
2016				done++;
2017			}
2018			/*
2019			 * if we got here for some reason other than DNSRCH,
2020			 * we only wanted one iteration of the loop, so stop.
2021			 */
2022			if (!(_res.options & RES_DNSRCH))
2023			        done++;
2024		}
2025	}
2026
2027	/*
2028	 * if we have not already tried the name "as is", do that now.
2029	 * note that we do this regardless of how many dots were in the
2030	 * name or whether it ends with a dot.
2031	 */
2032	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
2033		ret = res_querydomainN(name, NULL, target);
2034		if (ret > 0)
2035			return (ret);
2036	}
2037
2038	/*
2039	 * if we got here, we didn't satisfy the search.
2040	 * if we did an initial full query, return that query's h_errno
2041	 * (note that we wouldn't be here if that query had succeeded).
2042	 * else if we ever got a nodata, send that back as the reason.
2043	 * else send back meaningless h_errno, that being the one from
2044	 * the last DNSRCH we did.
2045	 */
2046	if (saved_herrno != -1)
2047		h_errno = saved_herrno;
2048	else if (got_nodata)
2049		h_errno = NO_DATA;
2050	else if (got_servfail)
2051		h_errno = TRY_AGAIN;
2052	return (-1);
2053}
2054
2055/*
2056 * Perform a call on res_query on the concatenation of name and domain,
2057 * removing a trailing dot from name if domain is NULL.
2058 */
2059static int
2060res_querydomainN(name, domain, target)
2061	const char *name, *domain;
2062	struct res_target *target;
2063{
2064	char nbuf[MAXDNAME];
2065	const char *longname = nbuf;
2066	size_t n, d;
2067
2068	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2069		h_errno = NETDB_INTERNAL;
2070		return (-1);
2071	}
2072#ifdef DEBUG
2073	if (_res.options & RES_DEBUG)
2074		printf(";; res_querydomain(%s, %s)\n",
2075			name, domain?domain:"<Nil>");
2076#endif
2077	if (domain == NULL) {
2078		/*
2079		 * Check for trailing '.';
2080		 * copy without '.' if present.
2081		 */
2082		n = strlen(name);
2083		if (n >= MAXDNAME) {
2084			h_errno = NO_RECOVERY;
2085			return (-1);
2086		}
2087		if (n > 0 && name[--n] == '.') {
2088			strncpy(nbuf, name, n);
2089			nbuf[n] = '\0';
2090		} else
2091			longname = name;
2092	} else {
2093		n = strlen(name);
2094		d = strlen(domain);
2095		if (n + d + 1 >= MAXDNAME) {
2096			h_errno = NO_RECOVERY;
2097			return (-1);
2098		}
2099		snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2100	}
2101	return (res_queryN(longname, target));
2102}
2103