1 /*
2  * Copyright (C) 2004-2008, 2012, 2014  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 #include <string.h>
138 
139 #include <lwres/lwres.h>
140 #include <lwres/net.h>
141 #include <lwres/netdb.h>
142 #include <lwres/stdlib.h>
143 #include <lwres/string.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  */
152 static 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
157 static int get_local(const char *name, int socktype, struct addrinfo **res);
158 #endif
159 
160 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
161     int socktype, int port);
162 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
163     int socktype, int port);
164 static 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. */
173 int
lwres_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)174 lwres_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 				memmove(&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 = offsetof(struct sockaddr_in, sin_addr);
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 = offsetof(struct sockaddr_in6, sin6_addr);
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 = offsetof(struct sockaddr_in6, sin6_addr);
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 			memmove((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 
470 done:
471 	ai_list = ai_reverse(ai_list);
472 
473 	*res = ai_list;
474 	return (0);
475 }
476 
477 static char *
lwres_strsep(char ** stringp,const char * delim)478 lwres_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 
500 static void
set_order(int family,int (** net_order)(const char *,int,struct addrinfo **,int,int))501 set_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 
548 static 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 
559 static int
add_ipv4(const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)560 add_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 			SETERROR(EAI_MEMORY);
578 
579 		*aip = ai;
580 		ai->ai_socktype = socktype;
581 		SIN(ai->ai_addr)->sin_port = port;
582 		memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
583 	} else {
584 		lwres = lwres_getaddrsbyname(lwrctx, hostname,
585 					     LWRES_ADDRTYPE_V4, &by);
586 		if (lwres != LWRES_R_SUCCESS) {
587 			if (lwres == LWRES_R_NOTFOUND)
588 				goto cleanup;
589 			else
590 				SETERROR(EAI_FAIL);
591 		}
592 		addr = LWRES_LIST_HEAD(by->addrs);
593 		while (addr != NULL) {
594 			ai = ai_clone(*aip, AF_INET);
595 			if (ai == NULL)
596 				SETERROR(EAI_MEMORY);
597 			*aip = ai;
598 			ai->ai_socktype = socktype;
599 			SIN(ai->ai_addr)->sin_port = port;
600 			memmove(&SIN(ai->ai_addr)->sin_addr,
601 				addr->address, 4);
602 			if (flags & AI_CANONNAME) {
603 				ai->ai_canonname = strdup(by->realname);
604 				if (ai->ai_canonname == NULL)
605 					SETERROR(EAI_MEMORY);
606 			}
607 			addr = LWRES_LIST_NEXT(addr, link);
608 		}
609 	}
610  cleanup:
611 	if (by != NULL)
612 		lwres_gabnresponse_free(lwrctx, &by);
613 	if (lwrctx != NULL) {
614 		lwres_conf_clear(lwrctx);
615 		lwres_context_destroy(&lwrctx);
616 	}
617 	return (result);
618 }
619 
620 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
621 
622 static int
add_ipv6(const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)623 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
624 	 int socktype, int port)
625 {
626 	struct addrinfo *ai;
627 	lwres_context_t *lwrctx = NULL;
628 	lwres_gabnresponse_t *by = NULL;
629 	lwres_addr_t *addr;
630 	lwres_result_t lwres;
631 	int result = 0;
632 
633 	lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
634 	if (lwres != LWRES_R_SUCCESS)
635 		SETERROR(EAI_FAIL);
636 	(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
637 
638 	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
639 		ai = ai_clone(*aip, AF_INET6);
640 		if (ai == NULL)
641 			SETERROR(EAI_MEMORY);
642 
643 		*aip = ai;
644 		ai->ai_socktype = socktype;
645 		SIN6(ai->ai_addr)->sin6_port = port;
646 		memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
647 	} else {
648 		lwres = lwres_getaddrsbyname(lwrctx, hostname,
649 					     LWRES_ADDRTYPE_V6, &by);
650 		if (lwres != LWRES_R_SUCCESS) {
651 			if (lwres == LWRES_R_NOTFOUND)
652 				goto cleanup;
653 			else
654 				SETERROR(EAI_FAIL);
655 		}
656 		addr = LWRES_LIST_HEAD(by->addrs);
657 		while (addr != NULL) {
658 			ai = ai_clone(*aip, AF_INET6);
659 			if (ai == NULL)
660 				SETERROR(EAI_MEMORY);
661 			*aip = ai;
662 			ai->ai_socktype = socktype;
663 			SIN6(ai->ai_addr)->sin6_port = port;
664 			memmove(&SIN6(ai->ai_addr)->sin6_addr,
665 				addr->address, 16);
666 			if (flags & AI_CANONNAME) {
667 				ai->ai_canonname = strdup(by->realname);
668 				if (ai->ai_canonname == NULL)
669 					SETERROR(EAI_MEMORY);
670 			}
671 			addr = LWRES_LIST_NEXT(addr, link);
672 		}
673 	}
674  cleanup:
675 	if (by != NULL)
676 		lwres_gabnresponse_free(lwrctx, &by);
677 	if (lwrctx != NULL) {
678 		lwres_conf_clear(lwrctx);
679 		lwres_context_destroy(&lwrctx);
680 	}
681 	return (result);
682 }
683 
684 /*% Free address info. */
685 void
lwres_freeaddrinfo(struct addrinfo * ai)686 lwres_freeaddrinfo(struct addrinfo *ai) {
687 	struct addrinfo *ai_next;
688 
689 	while (ai != NULL) {
690 		ai_next = ai->ai_next;
691 		if (ai->ai_addr != NULL)
692 			free(ai->ai_addr);
693 		if (ai->ai_canonname)
694 			free(ai->ai_canonname);
695 		free(ai);
696 		ai = ai_next;
697 	}
698 }
699 
700 #ifdef AF_LOCAL
701 static int
get_local(const char * name,int socktype,struct addrinfo ** res)702 get_local(const char *name, int socktype, struct addrinfo **res) {
703 	struct addrinfo *ai;
704 	struct sockaddr_un *slocal;
705 
706 	if (socktype == 0)
707 		return (EAI_SOCKTYPE);
708 
709 	if (strlen(name) >= sizeof(slocal->sun_path))
710 		return (EAI_OVERFLOW);
711 
712 	ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
713 	if (ai == NULL)
714 		return (EAI_MEMORY);
715 
716 	slocal = SLOCAL(ai->ai_addr);
717 	strncpy(slocal->sun_path, name, sizeof(slocal->sun_path));
718 	slocal->sun_path[sizeof(slocal->sun_path) - 1] = '\0';
719 
720 	ai->ai_socktype = socktype;
721 	/*
722 	 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
723 	 * and ai->ai_next were initialized to zero.
724 	 */
725 
726 	*res = ai;
727 	return (0);
728 }
729 #endif
730 
731 /*!
732  * Allocate an addrinfo structure, and a sockaddr structure
733  * of the specificed length.  We initialize:
734  *	ai_addrlen
735  *	ai_family
736  *	ai_addr
737  *	ai_addr->sa_family
738  *	ai_addr->sa_len	(LWRES_PLATFORM_HAVESALEN)
739  * and everything else is initialized to zero.
740  */
741 static struct addrinfo *
ai_alloc(int family,int addrlen)742 ai_alloc(int family, int addrlen) {
743 	struct addrinfo *ai;
744 
745 	ai = (struct addrinfo *)calloc(1, sizeof(*ai));
746 	if (ai == NULL)
747 		return (NULL);
748 
749 	ai->ai_addr = SA(calloc(1, addrlen));
750 	if (ai->ai_addr == NULL) {
751 		free(ai);
752 		return (NULL);
753 	}
754 	ai->ai_addrlen = addrlen;
755 	ai->ai_family = family;
756 	ai->ai_addr->sa_family = family;
757 #ifdef LWRES_PLATFORM_HAVESALEN
758 	ai->ai_addr->sa_len = addrlen;
759 #endif
760 	return (ai);
761 }
762 
763 static struct addrinfo *
ai_clone(struct addrinfo * oai,int family)764 ai_clone(struct addrinfo *oai, int family) {
765 	struct addrinfo *ai;
766 
767 	ai = ai_alloc(family, ((family == AF_INET6) ?
768 	    sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
769 
770 	if (ai == NULL) {
771 		lwres_freeaddrinfo(oai);
772 		return (NULL);
773 	}
774 	if (oai == NULL)
775 		return (ai);
776 
777 	ai->ai_flags = oai->ai_flags;
778 	ai->ai_socktype = oai->ai_socktype;
779 	ai->ai_protocol = oai->ai_protocol;
780 	ai->ai_canonname = NULL;
781 	ai->ai_next = oai;
782 	return (ai);
783 }
784 
785 static struct addrinfo *
ai_reverse(struct addrinfo * oai)786 ai_reverse(struct addrinfo *oai) {
787 	struct addrinfo *nai, *tai;
788 
789 	nai = NULL;
790 
791 	while (oai != NULL) {
792 		/*
793 		 * Grab one off the old list.
794 		 */
795 		tai = oai;
796 		oai = oai->ai_next;
797 		/*
798 		 * Put it on the front of the new list.
799 		 */
800 		tai->ai_next = nai;
801 		nai = tai;
802 	}
803 	return (nai);
804 }
805