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