xref: /netbsd-src/lib/libc/net/getaddrinfo.c (revision 3b435a73967be44dfb4a27315acd72bfacde430c)
1 /*	$NetBSD: getaddrinfo.c,v 1.13 1999/09/20 04:39:11 lukem Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
34  *
35  * Issues to be discussed:
36  * - Thread safe-ness must be checked.
37  * - Return values.  There are nonstandard return values defined and used
38  *   in the source code.  This is because RFC2133 is silent about which error
39  *   code must be returned for which situation.
40  * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
41  */
42 
43 #include "namespace.h"
44 #include <sys/param.h>
45 #include <sys/sysctl.h>
46 #include <sys/socket.h>
47 
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <arpa/nameser.h>
51 
52 #include <assert.h>
53 #include <ctype.h>
54 #include <errno.h>
55 #include <netdb.h>
56 #include <resolv.h>
57 #include <stddef.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61 
62 #if 0	/*quickhack*/
63 #if defined(__KAME__) && defined(INET6)
64 # define FAITH
65 #endif
66 #endif
67 
68 #define SUCCESS 0
69 #define ANY 0
70 #define YES 1
71 #define NO  0
72 
73 #ifdef FAITH
74 static int translate = NO;
75 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
76 #endif
77 
78 static const char in_addrany[] = { 0, 0, 0, 0 };
79 static const char in6_addrany[] = {
80 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
81 };
82 static const char in_loopback[] = { 127, 0, 0, 1 };
83 static const char in6_loopback[] = {
84 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
85 };
86 
87 struct sockinet {
88 	u_char	si_len;
89 	u_char	si_family;
90 	u_short	si_port;
91 };
92 
93 static struct afd {
94 	int a_af;
95 	int a_addrlen;
96 	int a_socklen;
97 	int a_off;
98 	const char *a_addrany;
99 	const char *a_loopback;
100 } afdl [] = {
101 #ifdef INET6
102 #define N_INET6 0
103 	{PF_INET6, sizeof(struct in6_addr),
104 	 sizeof(struct sockaddr_in6),
105 	 offsetof(struct sockaddr_in6, sin6_addr),
106 	 in6_addrany, in6_loopback},
107 #define N_INET  1
108 #else
109 #define N_INET  0
110 #endif
111 	{PF_INET, sizeof(struct in_addr),
112 	 sizeof(struct sockaddr_in),
113 	 offsetof(struct sockaddr_in, sin_addr),
114 	 in_addrany, in_loopback},
115 	{0, 0, 0, 0, NULL, NULL},
116 };
117 
118 #ifdef INET6
119 #define PTON_MAX	16
120 #else
121 #define PTON_MAX	4
122 #endif
123 
124 
125 static int get_name __P((const char *, struct afd *,
126 			  struct addrinfo **, char *, struct addrinfo *,
127 			  int));
128 static int get_addr __P((const char *, int, struct addrinfo **,
129 			struct addrinfo *, int));
130 static int get_addr0 __P((const char *, int, struct addrinfo **,
131 			struct addrinfo *, int));
132 static int str_isnumber __P((const char *));
133 
134 static char *ai_errlist[] = {
135 	"Success",
136 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
137 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
138 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
139 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
140 	"ai_family not supported",			/* EAI_FAMILY     */
141 	"Memory allocation failure", 			/* EAI_MEMORY     */
142 	"No address associated with hostname", 		/* EAI_NODATA     */
143 	"hostname nor servname provided, or not known",/* EAI_NONAME     */
144 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
145 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
146 	"System error returned in errno", 		/* EAI_SYSTEM     */
147 	"Invalid value for hints",			/* EAI_BADHINTS	  */
148 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
149 	"Unknown error", 				/* EAI_MAX        */
150 };
151 
152 #define GET_CANONNAME(ai, str) \
153 if (pai->ai_flags & AI_CANONNAME) {\
154 	if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
155 		strcpy((ai)->ai_canonname, (str));\
156 	} else {\
157 		error = EAI_MEMORY;\
158 		goto free;\
159 	}\
160 }
161 
162 #define GET_AI(ai, afd, addr, port) {\
163 	char *p;\
164 	if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
165 					      ((afd)->a_socklen)))\
166 	    == NULL) {\
167 		error = EAI_MEMORY;\
168 		goto free;\
169 	}\
170 	memcpy(ai, pai, sizeof(struct addrinfo));\
171 	(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
172 	memset((ai)->ai_addr, 0, (afd)->a_socklen);\
173 	(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\
174 	(ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
175 	((struct sockinet *)(ai)->ai_addr)->si_port = port;\
176 	p = (char *)((ai)->ai_addr);\
177 	memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
178 }
179 
180 #define ERR(err) { error = (err); goto bad; }
181 
182 char *
183 gai_strerror(ecode)
184 	int ecode;
185 {
186 	if (ecode < 0 || ecode > EAI_MAX)
187 		ecode = EAI_MAX;
188 	return ai_errlist[ecode];
189 }
190 
191 void
192 freeaddrinfo(ai)
193 	struct addrinfo *ai;
194 {
195 	struct addrinfo *next;
196 
197 	_DIAGASSERT(ai != NULL);
198 
199 	do {
200 		next = ai->ai_next;
201 		if (ai->ai_canonname)
202 			free(ai->ai_canonname);
203 		/* no need to free(ai->ai_addr) */
204 		free(ai);
205 	} while ((ai = next) != NULL);
206 }
207 
208 static int
209 str_isnumber(p)
210 	const char *p;
211 {
212 	char *q = (char *)p;
213 
214 	_DIAGASSERT(p != NULL);
215 
216 	while (*q) {
217 		if (! isdigit(*q))
218 			return NO;
219 		q++;
220 	}
221 	return YES;
222 }
223 
224 int
225 getaddrinfo(hostname, servname, hints, res)
226 	const char *hostname, *servname;
227 	const struct addrinfo *hints;
228 	struct addrinfo **res;
229 {
230 	struct addrinfo sentinel;
231 	struct addrinfo *top = NULL;
232 	struct addrinfo *cur;
233 	int i, error = 0;
234 	char pton[PTON_MAX];
235 	struct addrinfo ai;
236 	struct addrinfo *pai;
237 	u_short port;
238 
239 #ifdef FAITH
240 	static int firsttime = 1;
241 
242 	if (firsttime) {
243 		/* translator hack */
244 		{
245 			char *q = getenv("GAI");
246 			if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
247 				translate = YES;
248 		}
249 		firsttime = 0;
250 	}
251 #endif
252 
253 	/* hostname may be NULL */
254 	/* servname may be NULL */
255 	/* hints may be NULL */
256 	_DIAGASSERT(res != NULL);
257 
258 	/* initialize file static vars */
259 	sentinel.ai_next = NULL;
260 	cur = &sentinel;
261 	pai = &ai;
262 	pai->ai_flags = 0;
263 	pai->ai_family = PF_UNSPEC;
264 	pai->ai_socktype = ANY;
265 	pai->ai_protocol = ANY;
266 	pai->ai_addrlen = 0;
267 	pai->ai_canonname = NULL;
268 	pai->ai_addr = NULL;
269 	pai->ai_next = NULL;
270 	port = ANY;
271 
272 	if (hostname == NULL && servname == NULL)
273 		return EAI_NONAME;
274 	if (hints) {
275 		/* error check for hints */
276 		if (hints->ai_addrlen || hints->ai_canonname ||
277 		    hints->ai_addr || hints->ai_next)
278 			ERR(EAI_BADHINTS); /* xxx */
279 		if (hints->ai_flags & ~AI_MASK)
280 			ERR(EAI_BADFLAGS);
281 		switch (hints->ai_family) {
282 		case PF_UNSPEC:
283 		case PF_INET:
284 #ifdef INET6
285 		case PF_INET6:
286 #endif
287 			break;
288 		default:
289 			ERR(EAI_FAMILY);
290 		}
291 		memcpy(pai, hints, sizeof(*pai));
292 		switch (pai->ai_socktype) {
293 		case ANY:
294 			switch (pai->ai_protocol) {
295 			case ANY:
296 				break;
297 			case IPPROTO_UDP:
298 				pai->ai_socktype = SOCK_DGRAM;
299 				break;
300 			case IPPROTO_TCP:
301 				pai->ai_socktype = SOCK_STREAM;
302 				break;
303 			default:
304 				pai->ai_socktype = SOCK_RAW;
305 				break;
306 			}
307 			break;
308 		case SOCK_RAW:
309 			break;
310 		case SOCK_DGRAM:
311 			if (pai->ai_protocol != IPPROTO_UDP &&
312 			    pai->ai_protocol != ANY)
313 				ERR(EAI_BADHINTS);	/*xxx*/
314 			pai->ai_protocol = IPPROTO_UDP;
315 			break;
316 		case SOCK_STREAM:
317 			if (pai->ai_protocol != IPPROTO_TCP &&
318 			    pai->ai_protocol != ANY)
319 				ERR(EAI_BADHINTS);	/*xxx*/
320 			pai->ai_protocol = IPPROTO_TCP;
321 			break;
322 		default:
323 			ERR(EAI_SOCKTYPE);
324 			break;
325 		}
326 	}
327 
328 	/*
329 	 * service port
330 	 */
331 	if (servname) {
332 		if (str_isnumber(servname)) {
333 			if (pai->ai_socktype == ANY) {
334 				/* caller accept *ANY* socktype */
335 				pai->ai_socktype = SOCK_DGRAM;
336 				pai->ai_protocol = IPPROTO_UDP;
337 			}
338 			port = htons(atoi(servname));
339 		} else {
340 			struct servent *sp;
341 			char *proto;
342 
343 			proto = NULL;
344 			switch (pai->ai_socktype) {
345 			case ANY:
346 				proto = NULL;
347 				break;
348 			case SOCK_DGRAM:
349 				proto = "udp";
350 				break;
351 			case SOCK_STREAM:
352 				proto = "tcp";
353 				break;
354 			default:
355 				fprintf(stderr, "panic!\n");
356 				break;
357 			}
358 			if ((sp = getservbyname(servname, proto)) == NULL)
359 				ERR(EAI_SERVICE);
360 			port = sp->s_port;
361 			if (pai->ai_socktype == ANY) {
362 				if (strcmp(sp->s_proto, "udp") == 0) {
363 					pai->ai_socktype = SOCK_DGRAM;
364 					pai->ai_protocol = IPPROTO_UDP;
365 				} else if (strcmp(sp->s_proto, "tcp") == 0) {
366 					pai->ai_socktype = SOCK_STREAM;
367 					pai->ai_protocol = IPPROTO_TCP;
368 				} else
369 					ERR(EAI_PROTOCOL);	/*xxx*/
370 			}
371 		}
372 	}
373 
374 	/*
375 	 * hostname == NULL.
376 	 * passive socket -> anyaddr (0.0.0.0 or ::)
377 	 * non-passive socket -> localhost (127.0.0.1 or ::1)
378 	 */
379 	if (hostname == NULL) {
380 		struct afd *afd;
381 		int s;
382 
383 		for (afd = &afdl[0]; afd->a_af; afd++) {
384 			if (!(pai->ai_family == PF_UNSPEC
385 			   || pai->ai_family == afd->a_af)) {
386 				continue;
387 			}
388 
389 			/*
390 			 * filter out AFs that are not supported by the kernel
391 			 * XXX errno?
392 			 */
393 			s = socket(afd->a_af, SOCK_DGRAM, 0);
394 			if (s < 0)
395 				continue;
396 			close(s);
397 
398 			if (pai->ai_flags & AI_PASSIVE) {
399 				GET_AI(cur->ai_next, afd, afd->a_addrany, port);
400 				/* xxx meaningless?
401 				 * GET_CANONNAME(cur->ai_next, "anyaddr");
402 				 */
403 			} else {
404 				GET_AI(cur->ai_next, afd, afd->a_loopback,
405 					port);
406 				/* xxx meaningless?
407 				 * GET_CANONNAME(cur->ai_next, "localhost");
408 				 */
409 			}
410 			cur = cur->ai_next;
411 		}
412 		top = sentinel.ai_next;
413 		if (top)
414 			goto good;
415 		else
416 			ERR(EAI_FAMILY);
417 	}
418 
419 	/* hostname as numeric name */
420 	for (i = 0; afdl[i].a_af; i++) {
421 		if (inet_pton(afdl[i].a_af, hostname, pton)) {
422 			u_long v4a;
423 			u_char pfx;
424 
425 			switch (afdl[i].a_af) {
426 			case AF_INET:
427 				v4a = ntohl(((struct in_addr *)pton)->s_addr);
428 				if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
429 					pai->ai_flags &= ~AI_CANONNAME;
430 				v4a >>= IN_CLASSA_NSHIFT;
431 				if (v4a == 0 || v4a == IN_LOOPBACKNET)
432 					pai->ai_flags &= ~AI_CANONNAME;
433 				break;
434 #ifdef INET6
435 			case AF_INET6:
436 				pfx = ((struct in6_addr *)pton)->s6_addr8[0];
437 				if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
438 					pai->ai_flags &= ~AI_CANONNAME;
439 				break;
440 #endif
441 			}
442 
443 			if (pai->ai_family == afdl[i].a_af ||
444 			    pai->ai_family == PF_UNSPEC) {
445 				if (! (pai->ai_flags & AI_CANONNAME)) {
446 					GET_AI(top, &afdl[i], pton, port);
447 					goto good;
448 				}
449 				/*
450 				 * if AI_CANONNAME and if reverse lookup
451 				 * fail, return ai anyway to pacify
452 				 * calling application.
453 				 *
454 				 * XXX getaddrinfo() is a name->address
455 				 * translation function, and it looks strange
456 				 * that we do addr->name translation here.
457 				 */
458 				get_name(pton, &afdl[i], &top, pton, pai, port);
459 				goto good;
460 			} else
461 				ERR(EAI_FAMILY);	/*xxx*/
462 		}
463 	}
464 
465 	if (pai->ai_flags & AI_NUMERICHOST)
466 		ERR(EAI_NONAME);
467 
468 	/* hostname as alphabetical name */
469 	error = get_addr(hostname, pai->ai_family, &top, pai, port);
470 	if (error == 0) {
471 		if (top) {
472  good:
473 			*res = top;
474 			return SUCCESS;
475 		} else
476 			error = EAI_FAIL;
477 	}
478  free:
479 	if (top)
480 		freeaddrinfo(top);
481  bad:
482 	*res = NULL;
483 	return error;
484 }
485 
486 static int
487 get_name(addr, afd, res, numaddr, pai, port0)
488 	const char *addr;
489 	struct afd *afd;
490 	struct addrinfo **res;
491 	char *numaddr;
492 	struct addrinfo *pai;
493 	int port0;
494 {
495 	u_short port = port0 & 0xffff;
496 	struct hostent *hp;
497 	struct addrinfo *cur;
498 	int error = 0;
499 #ifdef USE_GETIPNODEBY
500 	int h_error;
501 #endif
502 
503 	_DIAGASSERT(addr != NULL);
504 	_DIAGASSERT(afd != NULL);
505 	_DIAGASSERT(res != NULL);
506 	_DIAGASSERT(numaddr != NULL);
507 	_DIAGASSERT(pai != NULL);
508 
509 #ifdef USE_GETIPNODEBY
510 	hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
511 #else
512 	hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
513 #endif
514 	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
515 		GET_AI(cur, afd, hp->h_addr_list[0], port);
516 		GET_CANONNAME(cur, hp->h_name);
517 	} else
518 		GET_AI(cur, afd, numaddr, port);
519 
520 #ifdef USE_GETIPNODEBY
521 	if (hp)
522 		freehostent(hp);
523 #endif
524 	*res = cur;
525 	return SUCCESS;
526  free:
527 	if (cur)
528 		freeaddrinfo(cur);
529 #ifdef USE_GETIPNODEBY
530 	if (hp)
531 		freehostent(hp);
532 #endif
533  /* bad: */
534 	*res = NULL;
535 	return error;
536 }
537 
538 static int
539 get_addr(hostname, af, res0, pai, port0)
540 	const char *hostname;
541 	int af;
542 	struct addrinfo **res0;
543 	struct addrinfo *pai;
544 	int port0;
545 {
546 #ifndef USE_GETIPNODEBY
547 	int i, error, ekeep;
548 	struct addrinfo *cur;
549 	struct addrinfo **res;
550 	int retry;
551 	int s;
552 #endif
553 
554 	_DIAGASSERT(hostname != NULL);
555 	_DIAGASSERT(res != NULL);
556 	_DIAGASSERT(pai != NULL);
557 
558 #ifdef USE_GETIPNODEBY
559 	return get_addr0(hostname, af, res0, pai, port0);
560 #else
561 	res = res0;
562 	ekeep = 0;
563 	error = 0;
564 	for (i = 0; afdl[i].a_af; i++) {
565 		retry = 0;
566 		if (af == AF_UNSPEC) {
567 			/*
568 			 * filter out AFs that are not supported by the kernel
569 			 * XXX errno?
570 			 */
571 			s = socket(afdl[i].a_af, SOCK_DGRAM, 0);
572 			if (s < 0)
573 				continue;
574 			close(s);
575 		} else {
576 			if (af != afdl[i].a_af)
577 				continue;
578 		}
579 		/* It is WRONG, we need getipnodebyname(). */
580 again:
581 		error = get_addr0(hostname, afdl[i].a_af, res, pai, port0);
582 		switch (error) {
583 		case EAI_AGAIN:
584 			if (++retry < 3)
585 				goto again;
586 			/* FALL THROUGH*/
587 		default:
588 			if (ekeep == 0)
589 				ekeep = error;
590 			break;
591 		}
592 		if (*res) {
593 			/* make chain of addrs */
594 			for (cur = *res;
595 			     cur && cur->ai_next;
596 			     cur = cur->ai_next)
597 				;
598 			if (!cur)
599 				return EAI_FAIL;
600 			res = &cur->ai_next;
601 		}
602 	}
603 
604 	/* if we got something, it's okay */
605 	if (*res0)
606 		return 0;
607 
608 	return error ? error : ekeep;
609 #endif
610 }
611 
612 static int
613 get_addr0(hostname, af, res, pai, port0)
614 	const char *hostname;
615 	int af;
616 	struct addrinfo **res;
617 	struct addrinfo *pai;
618 	int port0;
619 {
620 	u_short port = port0 & 0xffff;
621 	struct addrinfo sentinel;
622 	struct hostent *hp;
623 	struct addrinfo *top, *cur;
624 	struct afd *afd;
625 	int i, error = 0, h_error;
626 	char *ap;
627 #ifndef USE_GETIPNODEBY
628 	extern int h_errno;
629 #endif
630 
631 	_DIAGASSERT(hostname != NULL);
632 	_DIAGASSERT(res != NULL);
633 	_DIAGASSERT(pai != NULL);
634 
635 	top = NULL;
636 	sentinel.ai_next = NULL;
637 	cur = &sentinel;
638 #ifdef USE_GETIPNODEBY
639 	if (af == AF_UNSPEC) {
640 		hp = getipnodebyname(hostname, AF_INET6,
641 				AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
642 	} else
643 		hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
644 #else
645 	if (af == AF_UNSPEC) {
646 		error = EAI_FAIL;
647 		goto bad;
648 	}
649 	hp = gethostbyname2(hostname, af);
650 	h_error = h_errno;
651 #endif
652 	if (hp == NULL) {
653 		switch (h_error) {
654 		case HOST_NOT_FOUND:
655 		case NO_DATA:
656 			error = EAI_NODATA;
657 			break;
658 		case TRY_AGAIN:
659 			error = EAI_AGAIN;
660 			break;
661 		case NO_RECOVERY:
662 		case NETDB_INTERNAL:
663 		default:
664 			error = EAI_FAIL;
665 			break;
666 		}
667 		goto bad;
668 	}
669 
670 	if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
671 	    (hp->h_addr_list[0] == NULL))
672 		ERR(EAI_FAIL);
673 
674 	for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
675 		switch (af) {
676 #ifdef INET6
677 		case AF_INET6:
678 			afd = &afdl[N_INET6];
679 			break;
680 #endif
681 #ifndef INET6
682 		default:	/* AF_UNSPEC */
683 #endif
684 		case AF_INET:
685 			afd = &afdl[N_INET];
686 			break;
687 #ifdef INET6
688 		default:	/* AF_UNSPEC */
689 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
690 				ap += sizeof(struct in6_addr) -
691 					sizeof(struct in_addr);
692 				afd = &afdl[N_INET];
693 			} else
694 				afd = &afdl[N_INET6];
695 			break;
696 #endif
697 		}
698 #ifdef FAITH
699 		if (translate && afd->a_af == AF_INET) {
700 			struct in6_addr *in6;
701 
702 			GET_AI(cur->ai_next, &afdl[N_INET6], ap, port);
703 			in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
704 			memcpy(&in6->s6_addr32[0], &faith_prefix,
705 			    sizeof(struct in6_addr) - sizeof(struct in_addr));
706 			memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
707 		} else
708 #endif /* FAITH */
709 		GET_AI(cur->ai_next, afd, ap, port);
710 		if (cur == &sentinel) {
711 			top = cur->ai_next;
712 			GET_CANONNAME(top, hp->h_name);
713 		}
714 		cur = cur->ai_next;
715 	}
716 #ifdef USE_GETIPNODEBY
717 	freehostent(hp);
718 #endif
719 	*res = top;
720 	return SUCCESS;
721  free:
722 	if (top)
723 		freeaddrinfo(top);
724 #ifdef USE_GETIPNODEBY
725 	if (hp)
726 		freehostent(hp);
727 #endif
728  bad:
729 	*res = NULL;
730 	return error;
731 }
732