1/*	$NetBSD: getaddrinfo.c,v 1.2.6.2 2012/12/15 05:40:13 riz Exp $	*/
2
3/*
4 * Copyright (C) 2004-2008, 2012  Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001  Internet Software Consortium.
6 *
7 * This code is derived from software contributed to ISC by
8 * Berkeley Software Design, Inc.
9 *
10 * Permission to use, copy, modify, and/or distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
15 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
17 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
20 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23/* Id: getaddrinfo.c,v 1.54 2008/11/25 23:47:23 tbox Exp  */
24
25/*! \file */
26
27/**
28 *    lwres_getaddrinfo() is used to get a list of IP addresses and port
29 *    numbers for host hostname and service servname. The function is the
30 *    lightweight resolver's implementation of getaddrinfo() as defined in
31 *    RFC2133. hostname and servname are pointers to null-terminated strings
32 *    or NULL. hostname is either a host name or a numeric host address
33 *    string: a dotted decimal IPv4 address or an IPv6 address. servname is
34 *    either a decimal port number or a service name as listed in
35 *    /etc/services.
36 *
37 *    If the operating system does not provide a struct addrinfo, the
38 *    following structure is used:
39 *
40 * \code
41 * struct  addrinfo {
42 *         int             ai_flags;       // AI_PASSIVE, AI_CANONNAME
43 *         int             ai_family;      // PF_xxx
44 *         int             ai_socktype;    // SOCK_xxx
45 *         int             ai_protocol;    // 0 or IPPROTO_xxx for IPv4 and IPv6
46 *         size_t          ai_addrlen;     // length of ai_addr
47 *         char            *ai_canonname;  // canonical name for hostname
48 *         struct sockaddr *ai_addr;       // binary address
49 *         struct addrinfo *ai_next;       // next structure in linked list
50 * };
51 * \endcode
52 *
53 *
54 *    hints is an optional pointer to a struct addrinfo. This structure can
55 *    be used to provide hints concerning the type of socket that the caller
56 *    supports or wishes to use. The caller can supply the following
57 *    structure elements in *hints:
58 *
59 * <ul>
60 *    <li>ai_family:
61 *           The protocol family that should be used. When ai_family is set
62 *           to PF_UNSPEC, it means the caller will accept any protocol
63 *           family supported by the operating system.</li>
64 *
65 *    <li>ai_socktype:
66 *           denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
67 *           SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
68 *           will accept any socket type.</li>
69 *
70 *    <li>ai_protocol:
71 *           indicates which transport protocol is wanted: IPPROTO_UDP or
72 *           IPPROTO_TCP. If ai_protocol is zero the caller will accept any
73 *           protocol.</li>
74 *
75 *    <li>ai_flags:
76 *           Flag bits. If the AI_CANONNAME bit is set, a successful call to
77 *           lwres_getaddrinfo() will return a null-terminated string
78 *           containing the canonical name of the specified hostname in
79 *           ai_canonname of the first addrinfo structure returned. Setting
80 *           the AI_PASSIVE bit indicates that the returned socket address
81 *           structure is intended for used in a call to bind(2). In this
82 *           case, if the hostname argument is a NULL pointer, then the IP
83 *           address portion of the socket address structure will be set to
84 *           INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
85 *           address.<br /><br />
86 *
87 *           When ai_flags does not set the AI_PASSIVE bit, the returned
88 *           socket address structure will be ready for use in a call to
89 *           connect(2) for a connection-oriented protocol or connect(2),
90 *           sendto(2), or sendmsg(2) if a connectionless protocol was
91 *           chosen. The IP address portion of the socket address structure
92 *           will be set to the loopback address if hostname is a NULL
93 *           pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
94 *
95 *           If ai_flags is set to AI_NUMERICHOST it indicates that hostname
96 *           should be treated as a numeric string defining an IPv4 or IPv6
97 *           address and no name resolution should be attempted.
98 * </li></ul>
99 *
100 *    All other elements of the struct addrinfo passed via hints must be
101 *    zero.
102 *
103 *    A hints of NULL is treated as if the caller provided a struct addrinfo
104 *    initialized to zero with ai_familyset to PF_UNSPEC.
105 *
106 *    After a successful call to lwres_getaddrinfo(), *res is a pointer to a
107 *    linked list of one or more addrinfo structures. Each struct addrinfo
108 *    in this list cn be processed by following the ai_next pointer, until a
109 *    NULL pointer is encountered. The three members ai_family, ai_socktype,
110 *    and ai_protocol in each returned addrinfo structure contain the
111 *    corresponding arguments for a call to socket(2). For each addrinfo
112 *    structure in the list, the ai_addr member points to a filled-in socket
113 *    address structure of length ai_addrlen.
114 *
115 *    All of the information returned by lwres_getaddrinfo() is dynamically
116 *    allocated: the addrinfo structures, and the socket address structures
117 *    and canonical host name strings pointed to by the addrinfostructures.
118 *    Memory allocated for the dynamically allocated structures created by a
119 *    successful call to lwres_getaddrinfo() is released by
120 *    lwres_freeaddrinfo(). ai is a pointer to a struct addrinfo created by
121 *    a call to lwres_getaddrinfo().
122 *
123 * \section lwresreturn RETURN VALUES
124 *
125 *    lwres_getaddrinfo() returns zero on success or one of the error codes
126 *    listed in gai_strerror() if an error occurs. If both hostname and
127 *    servname are NULL lwres_getaddrinfo() returns #EAI_NONAME.
128 *
129 * \section lwressee SEE ALSO
130 *
131 *    lwres(3), lwres_getaddrinfo(), lwres_freeaddrinfo(),
132 *    lwres_gai_strerror(), RFC2133, getservbyname(3), connect(2),
133 *    sendto(2), sendmsg(2), socket(2).
134 */
135
136#include <config.h>
137
138#include <errno.h>
139
140#include <isc/string.h>
141
142#include <lwres/lwres.h>
143#include <lwres/net.h>
144#include <lwres/netdb.h>
145#include <lwres/stdlib.h>
146
147#define SA(addr)	((struct sockaddr *)(addr))
148#define SIN(addr)	((struct sockaddr_in *)(addr))
149#define SIN6(addr)	((struct sockaddr_in6 *)(addr))
150#define SLOCAL(addr)	((struct sockaddr_un *)(addr))
151
152/*! \struct addrinfo
153 */
154static struct addrinfo
155	*ai_reverse(struct addrinfo *oai),
156	*ai_clone(struct addrinfo *oai, int family),
157	*ai_alloc(int family, int addrlen);
158#ifdef AF_LOCAL
159static int get_local(const char *name, int socktype, struct addrinfo **res);
160#endif
161
162static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
163    int socktype, int port);
164static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
165    int socktype, int port);
166static void set_order(int, int (**)(const char *, int, struct addrinfo **,
167	 int, int));
168
169#define FOUND_IPV4	0x1
170#define FOUND_IPV6	0x2
171#define FOUND_MAX	2
172
173#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
174/*% Get a list of IP addresses and port numbers for host hostname and service servname. */
175int
176lwres_getaddrinfo(const char *hostname, const char *servname,
177	const struct addrinfo *hints, struct addrinfo **res)
178{
179	struct servent *sp;
180	const char *proto;
181	int family, socktype, flags, protocol;
182	struct addrinfo *ai, *ai_list;
183	int port, err, i;
184	int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
185		 int, int);
186
187	if (hostname == NULL && servname == NULL)
188		return (EAI_NONAME);
189
190	proto = NULL;
191	if (hints != NULL) {
192		if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
193			return (EAI_BADFLAGS);
194		if (hints->ai_addrlen || hints->ai_canonname ||
195		    hints->ai_addr || hints->ai_next) {
196			errno = EINVAL;
197			return (EAI_SYSTEM);
198		}
199		family = hints->ai_family;
200		socktype = hints->ai_socktype;
201		protocol = hints->ai_protocol;
202		flags = hints->ai_flags;
203		switch (family) {
204		case AF_UNSPEC:
205			switch (hints->ai_socktype) {
206			case SOCK_STREAM:
207				proto = "tcp";
208				break;
209			case SOCK_DGRAM:
210				proto = "udp";
211				break;
212			}
213			break;
214		case AF_INET:
215		case AF_INET6:
216			switch (hints->ai_socktype) {
217			case 0:
218				break;
219			case SOCK_STREAM:
220				proto = "tcp";
221				break;
222			case SOCK_DGRAM:
223				proto = "udp";
224				break;
225			case SOCK_RAW:
226				break;
227			default:
228				return (EAI_SOCKTYPE);
229			}
230			break;
231#ifdef	AF_LOCAL
232		case AF_LOCAL:
233			switch (hints->ai_socktype) {
234			case 0:
235				break;
236			case SOCK_STREAM:
237				break;
238			case SOCK_DGRAM:
239				break;
240			default:
241				return (EAI_SOCKTYPE);
242			}
243			break;
244#endif
245		default:
246			return (EAI_FAMILY);
247		}
248	} else {
249		protocol = 0;
250		family = 0;
251		socktype = 0;
252		flags = 0;
253	}
254
255#ifdef	AF_LOCAL
256	/*!
257	 * First, deal with AF_LOCAL.  If the family was not set,
258	 * then assume AF_LOCAL if the first character of the
259	 * hostname/servname is '/'.
260	 */
261
262	if (hostname != NULL &&
263	    (family == AF_LOCAL || (family == 0 && *hostname == '/')))
264		return (get_local(hostname, socktype, res));
265
266	if (servname != NULL &&
267	    (family == AF_LOCAL || (family == 0 && *servname == '/')))
268		return (get_local(servname, socktype, res));
269#endif
270
271	/*
272	 * Ok, only AF_INET and AF_INET6 left.
273	 */
274	ai_list = NULL;
275
276	/*
277	 * First, look up the service name (port) if it was
278	 * requested.  If the socket type wasn't specified, then
279	 * try and figure it out.
280	 */
281	if (servname != NULL) {
282		char *e;
283
284		port = strtol(servname, &e, 10);
285		if (*e == '\0') {
286			if (socktype == 0)
287				return (EAI_SOCKTYPE);
288			if (port < 0 || port > 65535)
289				return (EAI_SERVICE);
290			port = htons((unsigned short) port);
291		} else {
292			sp = getservbyname(servname, proto);
293			if (sp == NULL)
294				return (EAI_SERVICE);
295			port = sp->s_port;
296			if (socktype == 0) {
297				if (strcmp(sp->s_proto, "tcp") == 0)
298					socktype = SOCK_STREAM;
299				else if (strcmp(sp->s_proto, "udp") == 0)
300					socktype = SOCK_DGRAM;
301			}
302		}
303	} else
304		port = 0;
305
306	/*
307	 * Next, deal with just a service name, and no hostname.
308	 * (we verified that one of them was non-null up above).
309	 */
310	if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
311		if (family == AF_INET || family == 0) {
312			ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
313			if (ai == NULL)
314				return (EAI_MEMORY);
315			ai->ai_socktype = socktype;
316			ai->ai_protocol = protocol;
317			SIN(ai->ai_addr)->sin_port = port;
318			ai->ai_next = ai_list;
319			ai_list = ai;
320		}
321
322		if (family == AF_INET6 || family == 0) {
323			ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
324			if (ai == NULL) {
325				lwres_freeaddrinfo(ai_list);
326				return (EAI_MEMORY);
327			}
328			ai->ai_socktype = socktype;
329			ai->ai_protocol = protocol;
330			SIN6(ai->ai_addr)->sin6_port = port;
331			ai->ai_next = ai_list;
332			ai_list = ai;
333		}
334
335		*res = ai_list;
336		return (0);
337	}
338
339	/*
340	 * If the family isn't specified or AI_NUMERICHOST specified,
341	 * check first to see if it is a numeric address.
342	 * Though the gethostbyname2() routine
343	 * will recognize numeric addresses, it will only recognize
344	 * the format that it is being called for.  Thus, a numeric
345	 * AF_INET address will be treated by the AF_INET6 call as
346	 * a domain name, and vice versa.  Checking for both numerics
347	 * here avoids that.
348	 */
349	if (hostname != NULL &&
350	    (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
351		char abuf[sizeof(struct in6_addr)];
352		char nbuf[NI_MAXHOST];
353		int addrsize, addroff;
354#ifdef LWRES_HAVE_SIN6_SCOPE_ID
355		char *p, *ep;
356		char ntmp[NI_MAXHOST];
357		lwres_uint32_t scopeid;
358#endif
359
360#ifdef LWRES_HAVE_SIN6_SCOPE_ID
361		/*
362		 * Scope identifier portion.
363		 */
364		ntmp[0] = '\0';
365		if (strchr(hostname, '%') != NULL) {
366			strncpy(ntmp, hostname, sizeof(ntmp) - 1);
367			ntmp[sizeof(ntmp) - 1] = '\0';
368			p = strchr(ntmp, '%');
369			ep = NULL;
370
371			/*
372			 * Vendors may want to support non-numeric
373			 * scopeid around here.
374			 */
375
376			if (p != NULL)
377				scopeid = (lwres_uint32_t)strtoul(p + 1,
378								  &ep, 10);
379			if (p != NULL && ep != NULL && ep[0] == '\0')
380				*p = '\0';
381			else {
382				ntmp[0] = '\0';
383				scopeid = 0;
384			}
385		} else
386			scopeid = 0;
387#endif
388
389	       if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
390		   == 1)
391	       {
392			if (family == AF_INET6) {
393				/*
394				 * Convert to a V4 mapped address.
395				 */
396				struct in6_addr *a6 = (struct in6_addr *)abuf;
397				memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
398				memset(&a6->s6_addr[10], 0xff, 2);
399				memset(&a6->s6_addr[0], 0, 10);
400				goto inet6_addr;
401			}
402			addrsize = sizeof(struct in_addr);
403			addroff = offsetof(struct sockaddr_in, sin_addr);
404			family = AF_INET;
405			goto common;
406#ifdef LWRES_HAVE_SIN6_SCOPE_ID
407		} else if (ntmp[0] != '\0' &&
408			   lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
409		{
410			if (family && family != AF_INET6)
411				return (EAI_NONAME);
412			addrsize = sizeof(struct in6_addr);
413			addroff = offsetof(struct sockaddr_in6, sin6_addr);
414			family = AF_INET6;
415			goto common;
416#endif
417		} else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
418			if (family != 0 && family != AF_INET6)
419				return (EAI_NONAME);
420		inet6_addr:
421			addrsize = sizeof(struct in6_addr);
422			addroff = offsetof(struct sockaddr_in6, sin6_addr);
423			family = AF_INET6;
424
425		common:
426			ai = ai_clone(ai_list, family);
427			if (ai == NULL)
428				return (EAI_MEMORY);
429			ai_list = ai;
430			ai->ai_socktype = socktype;
431			SIN(ai->ai_addr)->sin_port = port;
432			memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
433			if (flags & AI_CANONNAME) {
434#if defined(LWRES_HAVE_SIN6_SCOPE_ID)
435				if (ai->ai_family == AF_INET6)
436					SIN6(ai->ai_addr)->sin6_scope_id =
437									scopeid;
438#endif
439				if (lwres_getnameinfo(ai->ai_addr,
440				    ai->ai_addrlen, nbuf, sizeof(nbuf),
441						      NULL, 0,
442						      NI_NUMERICHOST) == 0) {
443					ai->ai_canonname = strdup(nbuf);
444					if (ai->ai_canonname == NULL) {
445						lwres_freeaddrinfo(ai_list);
446						return (EAI_MEMORY);
447					}
448				} else {
449					/* XXX raise error? */
450					ai->ai_canonname = NULL;
451				}
452			}
453			goto done;
454		} else if ((flags & AI_NUMERICHOST) != 0) {
455			return (EAI_NONAME);
456		}
457	}
458
459	set_order(family, net_order);
460	for (i = 0; i < FOUND_MAX; i++) {
461		if (net_order[i] == NULL)
462			break;
463		err = (net_order[i])(hostname, flags, &ai_list,
464				     socktype, port);
465		if (err != 0)
466			return (err);
467	}
468
469	if (ai_list == NULL)
470		return (EAI_NODATA);
471
472done:
473	ai_list = ai_reverse(ai_list);
474
475	*res = ai_list;
476	return (0);
477}
478
479static char *
480lwres_strsep(char **stringp, const char *delim) {
481	char *string = *stringp;
482	char *s;
483	const char *d;
484	char sc, dc;
485
486	if (string == NULL)
487		return (NULL);
488
489	for (s = string; *s != '\0'; s++) {
490		sc = *s;
491		for (d = delim; (dc = *d) != '\0'; d++)
492			if (sc == dc) {
493				*s++ = '\0';
494				*stringp = s;
495				return (string);
496			}
497	}
498	*stringp = NULL;
499	return (string);
500}
501
502static void
503set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
504					int, int))
505{
506	char *order, *tok;
507	int found;
508
509	if (family) {
510		switch (family) {
511		case AF_INET:
512			*net_order++ = add_ipv4;
513			break;
514		case AF_INET6:
515			*net_order++ = add_ipv6;
516			break;
517		}
518	} else {
519		order = getenv("NET_ORDER");
520		found = 0;
521		while (order != NULL) {
522			/*
523			 * We ignore any unknown names.
524			 */
525			tok = lwres_strsep(&order, ":");
526			if (strcasecmp(tok, "inet6") == 0) {
527				if ((found & FOUND_IPV6) == 0)
528					*net_order++ = add_ipv6;
529				found |= FOUND_IPV6;
530			} else if (strcasecmp(tok, "inet") == 0 ||
531			    strcasecmp(tok, "inet4") == 0) {
532				if ((found & FOUND_IPV4) == 0)
533					*net_order++ = add_ipv4;
534				found |= FOUND_IPV4;
535			}
536		}
537
538		/*
539		 * Add in anything that we didn't find.
540		 */
541		if ((found & FOUND_IPV4) == 0)
542			*net_order++ = add_ipv4;
543		if ((found & FOUND_IPV6) == 0)
544			*net_order++ = add_ipv6;
545	}
546	*net_order = NULL;
547	return;
548}
549
550static char v4_loop[4] = { 127, 0, 0, 1 };
551
552/*
553 * The test against 0 is there to keep the Solaris compiler
554 * from complaining about "end-of-loop code not reached".
555 */
556#define SETERROR(code) \
557	do { result = (code);			\
558		if (result != 0) goto cleanup;	\
559	} while (/*CONSTCOND*/0)
560
561static int
562add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
563	int socktype, int port)
564{
565	struct addrinfo *ai;
566	lwres_context_t *lwrctx = NULL;
567	lwres_gabnresponse_t *by = NULL;
568	lwres_addr_t *addr;
569	lwres_result_t lwres;
570	int result = 0;
571
572	lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
573	if (lwres != LWRES_R_SUCCESS)
574		SETERROR(EAI_FAIL);
575	(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
576	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
577		ai = ai_clone(*aip, AF_INET);
578		if (ai == NULL) {
579			lwres_freeaddrinfo(*aip);
580			SETERROR(EAI_MEMORY);
581		}
582
583		*aip = ai;
584		ai->ai_socktype = socktype;
585		SIN(ai->ai_addr)->sin_port = port;
586		memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
587	} else {
588		lwres = lwres_getaddrsbyname(lwrctx, hostname,
589					     LWRES_ADDRTYPE_V4, &by);
590		if (lwres != LWRES_R_SUCCESS) {
591			if (lwres == LWRES_R_NOTFOUND)
592				goto cleanup;
593			else
594				SETERROR(EAI_FAIL);
595		}
596		addr = LWRES_LIST_HEAD(by->addrs);
597		while (addr != NULL) {
598			ai = ai_clone(*aip, AF_INET);
599			if (ai == NULL) {
600				lwres_freeaddrinfo(*aip);
601				SETERROR(EAI_MEMORY);
602			}
603			*aip = ai;
604			ai->ai_socktype = socktype;
605			SIN(ai->ai_addr)->sin_port = port;
606			memcpy(&SIN(ai->ai_addr)->sin_addr,
607			       addr->address, 4);
608			if (flags & AI_CANONNAME) {
609				ai->ai_canonname = strdup(by->realname);
610				if (ai->ai_canonname == NULL)
611					SETERROR(EAI_MEMORY);
612			}
613			addr = LWRES_LIST_NEXT(addr, link);
614		}
615	}
616 cleanup:
617	if (by != NULL)
618		lwres_gabnresponse_free(lwrctx, &by);
619	if (lwrctx != NULL) {
620		lwres_conf_clear(lwrctx);
621		lwres_context_destroy(&lwrctx);
622	}
623	return (result);
624}
625
626static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
627
628static int
629add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
630	 int socktype, int port)
631{
632	struct addrinfo *ai;
633	lwres_context_t *lwrctx = NULL;
634	lwres_gabnresponse_t *by = NULL;
635	lwres_addr_t *addr;
636	lwres_result_t lwres;
637	int result = 0;
638
639	lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
640	if (lwres != LWRES_R_SUCCESS)
641		SETERROR(EAI_FAIL);
642	(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
643
644	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
645		ai = ai_clone(*aip, AF_INET6);
646		if (ai == NULL) {
647			lwres_freeaddrinfo(*aip);
648			SETERROR(EAI_MEMORY);
649		}
650
651		*aip = ai;
652		ai->ai_socktype = socktype;
653		SIN6(ai->ai_addr)->sin6_port = port;
654		memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
655	} else {
656		lwres = lwres_getaddrsbyname(lwrctx, hostname,
657					     LWRES_ADDRTYPE_V6, &by);
658		if (lwres != LWRES_R_SUCCESS) {
659			if (lwres == LWRES_R_NOTFOUND)
660				goto cleanup;
661			else
662				SETERROR(EAI_FAIL);
663		}
664		addr = LWRES_LIST_HEAD(by->addrs);
665		while (addr != NULL) {
666			ai = ai_clone(*aip, AF_INET6);
667			if (ai == NULL) {
668				lwres_freeaddrinfo(*aip);
669				SETERROR(EAI_MEMORY);
670			}
671			*aip = ai;
672			ai->ai_socktype = socktype;
673			SIN6(ai->ai_addr)->sin6_port = port;
674			memcpy(&SIN6(ai->ai_addr)->sin6_addr,
675			       addr->address, 16);
676			if (flags & AI_CANONNAME) {
677				ai->ai_canonname = strdup(by->realname);
678				if (ai->ai_canonname == NULL)
679					SETERROR(EAI_MEMORY);
680			}
681			addr = LWRES_LIST_NEXT(addr, link);
682		}
683	}
684 cleanup:
685	if (by != NULL)
686		lwres_gabnresponse_free(lwrctx, &by);
687	if (lwrctx != NULL) {
688		lwres_conf_clear(lwrctx);
689		lwres_context_destroy(&lwrctx);
690	}
691	return (result);
692}
693
694/*% Free address info. */
695void
696lwres_freeaddrinfo(struct addrinfo *ai) {
697	struct addrinfo *ai_next;
698
699	while (ai != NULL) {
700		ai_next = ai->ai_next;
701		if (ai->ai_addr != NULL)
702			free(ai->ai_addr);
703		if (ai->ai_canonname)
704			free(ai->ai_canonname);
705		free(ai);
706		ai = ai_next;
707	}
708}
709
710#ifdef AF_LOCAL
711static int
712get_local(const char *name, int socktype, struct addrinfo **res) {
713	struct addrinfo *ai;
714	struct sockaddr_un *slocal;
715
716	if (socktype == 0)
717		return (EAI_SOCKTYPE);
718
719	ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
720	if (ai == NULL)
721		return (EAI_MEMORY);
722
723	slocal = SLOCAL(ai->ai_addr);
724	strncpy(slocal->sun_path, name, sizeof(slocal->sun_path));
725
726	ai->ai_socktype = socktype;
727	/*
728	 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
729	 * and ai->ai_next were initialized to zero.
730	 */
731
732	*res = ai;
733	return (0);
734}
735#endif
736
737/*!
738 * Allocate an addrinfo structure, and a sockaddr structure
739 * of the specificed length.  We initialize:
740 *	ai_addrlen
741 *	ai_family
742 *	ai_addr
743 *	ai_addr->sa_family
744 *	ai_addr->sa_len	(LWRES_PLATFORM_HAVESALEN)
745 * and everything else is initialized to zero.
746 */
747static struct addrinfo *
748ai_alloc(int family, int addrlen) {
749	struct addrinfo *ai;
750
751	ai = (struct addrinfo *)calloc(1, sizeof(*ai));
752	if (ai == NULL)
753		return (NULL);
754
755	ai->ai_addr = SA(calloc(1, addrlen));
756	if (ai->ai_addr == NULL) {
757		free(ai);
758		return (NULL);
759	}
760	ai->ai_addrlen = addrlen;
761	ai->ai_family = family;
762	ai->ai_addr->sa_family = family;
763#ifdef LWRES_PLATFORM_HAVESALEN
764	ai->ai_addr->sa_len = addrlen;
765#endif
766	return (ai);
767}
768
769static struct addrinfo *
770ai_clone(struct addrinfo *oai, int family) {
771	struct addrinfo *ai;
772
773	ai = ai_alloc(family, ((family == AF_INET6) ?
774	    sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
775
776	if (ai == NULL) {
777		lwres_freeaddrinfo(oai);
778		return (NULL);
779	}
780	if (oai == NULL)
781		return (ai);
782
783	ai->ai_flags = oai->ai_flags;
784	ai->ai_socktype = oai->ai_socktype;
785	ai->ai_protocol = oai->ai_protocol;
786	ai->ai_canonname = NULL;
787	ai->ai_next = oai;
788	return (ai);
789}
790
791static struct addrinfo *
792ai_reverse(struct addrinfo *oai) {
793	struct addrinfo *nai, *tai;
794
795	nai = NULL;
796
797	while (oai != NULL) {
798		/*
799		 * Grab one off the old list.
800		 */
801		tai = oai;
802		oai = oai->ai_next;
803		/*
804		 * Put it on the front of the new list.
805		 */
806		tai->ai_next = nai;
807		nai = tai;
808	}
809	return (nai);
810}
811