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