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