PageRenderTime 59ms CodeModel.GetById 12ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/lwres/getaddrinfo.c

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