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