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