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