xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/irs/getaddrinfo.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: getaddrinfo.c,v 1.1 2024/02/18 20:57:47 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0.  If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 /**
19  *    getaddrinfo() is used to get a list of IP addresses and port
20  *    numbers for host hostname and service servname as defined in RFC3493.
21  *    hostname and servname are pointers to null-terminated strings
22  *    or NULL. hostname is either a host name or a numeric host address
23  *    string: a dotted decimal IPv4 address or an IPv6 address. servname is
24  *    either a decimal port number or a service name as listed in
25  *    /etc/services.
26  *
27  *    If the operating system does not provide a struct addrinfo, the
28  *    following structure is used:
29  *
30  * \code
31  * struct  addrinfo {
32  *         int             ai_flags;       // AI_PASSIVE, AI_CANONNAME
33  *         int             ai_family;      // PF_xxx
34  *         int             ai_socktype;    // SOCK_xxx
35  *         int             ai_protocol;    // 0 or IPPROTO_xxx for IPv4 and IPv6
36  *         size_t          ai_addrlen;     // length of ai_addr
37  *         char            *ai_canonname;  // canonical name for hostname
38  *         struct sockaddr *ai_addr;       // binary address
39  *         struct addrinfo *ai_next;       // next structure in linked list
40  * };
41  * \endcode
42  *
43  *
44  *    hints is an optional pointer to a struct addrinfo. This structure can
45  *    be used to provide hints concerning the type of socket that the caller
46  *    supports or wishes to use. The caller can supply the following
47  *    structure elements in *hints:
48  *
49  * <ul>
50  *    <li>ai_family:
51  *           The protocol family that should be used. When ai_family is set
52  *           to PF_UNSPEC, it means the caller will accept any protocol
53  *           family supported by the operating system.</li>
54  *
55  *    <li>ai_socktype:
56  *           denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
57  *           SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
58  *           will accept any socket type.</li>
59  *
60  *    <li>ai_protocol:
61  *           indicates which transport protocol is wanted: IPPROTO_UDP or
62  *           IPPROTO_TCP. If ai_protocol is zero the caller will accept any
63  *           protocol.</li>
64  *
65  *    <li>ai_flags:
66  *           Flag bits. If the AI_CANONNAME bit is set, a successful call to
67  *           getaddrinfo() will return a null-terminated string
68  *           containing the canonical name of the specified hostname in
69  *           ai_canonname of the first addrinfo structure returned. Setting
70  *           the AI_PASSIVE bit indicates that the returned socket address
71  *           structure is intended for used in a call to bind(2). In this
72  *           case, if the hostname argument is a NULL pointer, then the IP
73  *           address portion of the socket address structure will be set to
74  *           INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
75  *           address.<br /><br />
76  *
77  *           When ai_flags does not set the AI_PASSIVE bit, the returned
78  *           socket address structure will be ready for use in a call to
79  *           connect(2) for a connection-oriented protocol or connect(2),
80  *           sendto(2), or sendmsg(2) if a connectionless protocol was
81  *           chosen. The IP address portion of the socket address structure
82  *           will be set to the loopback address if hostname is a NULL
83  *           pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
84  *
85  *           If ai_flags is set to AI_NUMERICHOST it indicates that hostname
86  *           should be treated as a numeric string defining an IPv4 or IPv6
87  *           address and no name resolution should be attempted.
88  * </li></ul>
89  *
90  *    All other elements of the struct addrinfo passed via hints must be
91  *    zero.
92  *
93  *    A hints of NULL is treated as if the caller provided a struct addrinfo
94  *    initialized to zero with ai_familyset to PF_UNSPEC.
95  *
96  *    After a successful call to getaddrinfo(), *res is a pointer to a
97  *    linked list of one or more addrinfo structures. Each struct addrinfo
98  *    in this list cn be processed by following the ai_next pointer, until a
99  *    NULL pointer is encountered. The three members ai_family, ai_socktype,
100  *    and ai_protocol in each returned addrinfo structure contain the
101  *    corresponding arguments for a call to socket(2). For each addrinfo
102  *    structure in the list, the ai_addr member points to a filled-in socket
103  *    address structure of length ai_addrlen.
104  *
105  *    All of the information returned by getaddrinfo() is dynamically
106  *    allocated: the addrinfo structures, and the socket address structures
107  *    and canonical host name strings pointed to by the addrinfostructures.
108  *    Memory allocated for the dynamically allocated structures created by a
109  *    successful call to getaddrinfo() is released by freeaddrinfo().
110  *    ai is a pointer to a struct addrinfo created by a call to getaddrinfo().
111  *
112  * \section irsreturn RETURN VALUES
113  *
114  *    getaddrinfo() returns zero on success or one of the error codes
115  *    listed in gai_strerror() if an error occurs. If both hostname and
116  *    servname are NULL getaddrinfo() returns #EAI_NONAME.
117  *
118  * \section irssee SEE ALSO
119  *
120  *    getaddrinfo(), freeaddrinfo(),
121  *    gai_strerror(), RFC3493, getservbyname(3), connect(2),
122  *    sendto(2), sendmsg(2), socket(2).
123  */
124 
125 #include <errno.h>
126 #include <inttypes.h>
127 #include <stdbool.h>
128 #include <stdlib.h>
129 #include <string.h>
130 
131 #ifdef _WIN32
132 #include <windows.h>
133 #include <winsock2.h>
134 #include <ws2tcpip.h>
135 #endif /* ifdef _WIN32 */
136 
137 #include <isc/app.h>
138 #include <isc/buffer.h>
139 #include <isc/lib.h>
140 #include <isc/mem.h>
141 #include <isc/mutex.h>
142 #include <isc/print.h>
143 #include <isc/sockaddr.h>
144 #include <isc/string.h>
145 #include <isc/util.h>
146 
147 #include <dns/client.h>
148 #include <dns/fixedname.h>
149 #include <dns/name.h>
150 #include <dns/rdata.h>
151 #include <dns/rdataset.h>
152 #include <dns/rdatastruct.h>
153 #include <dns/rdatatype.h>
154 #include <dns/result.h>
155 
156 #include <irs/context.h>
157 #include <irs/netdb.h>
158 #include <irs/resconf.h>
159 
160 #define SA(addr)     ((struct sockaddr *)(addr))
161 #define SIN(addr)    ((struct sockaddr_in *)(addr))
162 #define SIN6(addr)   ((struct sockaddr_in6 *)(addr))
163 #define SLOCAL(addr) ((struct sockaddr_un *)(addr))
164 
165 /*! \struct addrinfo
166  */
167 static struct addrinfo *
168 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2),
169 	*ai_reverse(struct addrinfo *oai),
170 	*ai_clone(struct addrinfo *oai, int family),
171 	*ai_alloc(int family, int addrlen);
172 #ifdef AF_LOCAL
173 static int
174 get_local(const char *name, int socktype, struct addrinfo **res);
175 #endif /* ifdef AF_LOCAL */
176 
177 static int
178 resolve_name(int family, const char *hostname, int flags, struct addrinfo **aip,
179 	     int socktype, int port);
180 
181 static int
182 add_ipv4(const char *hostname, int flags, struct addrinfo **aip, int socktype,
183 	 int port);
184 static int
185 add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype,
186 	 int port);
187 static void
188 set_order(int, int (**)(const char *, int, struct addrinfo **, int, int));
189 static void
190 _freeaddrinfo(struct addrinfo *ai);
191 
192 #define FOUND_IPV4 0x1
193 #define FOUND_IPV6 0x2
194 #define FOUND_MAX  2
195 
196 /*%
197  * Try converting the scope identifier in 'src' to a network interface index.
198  * Upon success, return true and store the resulting index in 'dst'.  Upon
199  * failure, return false.
200  */
201 static bool
parse_scopeid(const char * src,uint32_t * dst)202 parse_scopeid(const char *src, uint32_t *dst) {
203 	uint32_t scopeid = 0;
204 
205 	REQUIRE(src != NULL);
206 	REQUIRE(dst != NULL);
207 
208 #ifdef HAVE_IF_NAMETOINDEX
209 	/*
210 	 * Try using if_nametoindex() first if it is available.  As it does not
211 	 * handle numeric scopes, we do not simply return if it fails.
212 	 */
213 	scopeid = (uint32_t)if_nametoindex(src);
214 #endif /* ifdef HAVE_IF_NAMETOINDEX */
215 
216 	/*
217 	 * Fall back to numeric scope processing if if_nametoindex() either
218 	 * fails or is unavailable.
219 	 */
220 	if (scopeid == 0) {
221 		char *endptr = NULL;
222 		scopeid = (uint32_t)strtoul(src, &endptr, 10);
223 		/*
224 		 * The scope identifier must not be empty and no trailing
225 		 * characters are allowed after it.
226 		 */
227 		if (src == endptr || endptr == NULL || *endptr != '\0') {
228 			return (false);
229 		}
230 	}
231 
232 	*dst = scopeid;
233 
234 	return (true);
235 }
236 
237 #define ISC_AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
238 /*%
239  * Get a list of IP addresses and port numbers for host hostname and
240  * service servname.
241  */
242 int
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)243 getaddrinfo(const char *hostname, const char *servname,
244 	    const struct addrinfo *hints, struct addrinfo **res) {
245 	struct servent *sp;
246 	const char *proto;
247 	int family, socktype, flags, protocol;
248 	struct addrinfo *ai, *ai_list;
249 	int err = 0;
250 	int port, i;
251 	int (*net_order[FOUND_MAX + 1])(const char *, int, struct addrinfo **,
252 					int, int);
253 
254 	if (hostname == NULL && servname == NULL) {
255 		return (EAI_NONAME);
256 	}
257 
258 	proto = NULL;
259 	if (hints != NULL) {
260 		if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) {
261 			return (EAI_BADFLAGS);
262 		}
263 		if (hints->ai_addrlen || hints->ai_canonname ||
264 		    hints->ai_addr || hints->ai_next)
265 		{
266 			errno = EINVAL;
267 			return (EAI_SYSTEM);
268 		}
269 		family = hints->ai_family;
270 		socktype = hints->ai_socktype;
271 		protocol = hints->ai_protocol;
272 		flags = hints->ai_flags;
273 		switch (family) {
274 		case AF_UNSPEC:
275 			switch (hints->ai_socktype) {
276 			case SOCK_STREAM:
277 				proto = "tcp";
278 				break;
279 			case SOCK_DGRAM:
280 				proto = "udp";
281 				break;
282 			}
283 			break;
284 		case AF_INET:
285 		case AF_INET6:
286 			switch (hints->ai_socktype) {
287 			case 0:
288 				break;
289 			case SOCK_STREAM:
290 				proto = "tcp";
291 				break;
292 			case SOCK_DGRAM:
293 				proto = "udp";
294 				break;
295 			case SOCK_RAW:
296 				break;
297 			default:
298 				return (EAI_SOCKTYPE);
299 			}
300 			break;
301 #ifdef AF_LOCAL
302 		case AF_LOCAL:
303 			switch (hints->ai_socktype) {
304 			case 0:
305 				break;
306 			case SOCK_STREAM:
307 				break;
308 			case SOCK_DGRAM:
309 				break;
310 			default:
311 				return (EAI_SOCKTYPE);
312 			}
313 			break;
314 #endif /* ifdef AF_LOCAL */
315 		default:
316 			return (EAI_FAMILY);
317 		}
318 	} else {
319 		protocol = 0;
320 		family = 0;
321 		socktype = 0;
322 		flags = 0;
323 	}
324 
325 #ifdef AF_LOCAL
326 	/*!
327 	 * First, deal with AF_LOCAL.  If the family was not set,
328 	 * then assume AF_LOCAL if the first character of the
329 	 * hostname/servname is '/'.
330 	 */
331 
332 	if (hostname != NULL &&
333 	    (family == AF_LOCAL || (family == 0 && *hostname == '/')))
334 	{
335 		return (get_local(hostname, socktype, res));
336 	}
337 
338 	if (servname != NULL &&
339 	    (family == AF_LOCAL || (family == 0 && *servname == '/')))
340 	{
341 		return (get_local(servname, socktype, res));
342 	}
343 #endif /* ifdef AF_LOCAL */
344 
345 	/*
346 	 * Ok, only AF_INET and AF_INET6 left.
347 	 */
348 	ai_list = NULL;
349 
350 	/*
351 	 * First, look up the service name (port) if it was
352 	 * requested.  If the socket type wasn't specified, then
353 	 * try and figure it out.
354 	 */
355 	if (servname != NULL) {
356 		char *e;
357 
358 		port = strtol(servname, &e, 10);
359 		if (*e == '\0') {
360 			if (socktype == 0) {
361 				return (EAI_SOCKTYPE);
362 			}
363 			if (port < 0 || port > 65535) {
364 				return (EAI_SERVICE);
365 			}
366 			port = htons((unsigned short)port);
367 		} else {
368 #ifdef _WIN32
369 			WORD wVersionRequested;
370 			WSADATA wsaData;
371 
372 			wVersionRequested = MAKEWORD(2, 0);
373 
374 			err = WSAStartup(wVersionRequested, &wsaData);
375 			if (err != 0) {
376 				return (EAI_FAIL);
377 			}
378 #endif /* ifdef _WIN32 */
379 			sp = getservbyname(servname, proto);
380 			if (sp != NULL) {
381 				port = sp->s_port;
382 			}
383 #ifdef _WIN32
384 			WSACleanup();
385 #endif /* ifdef _WIN32 */
386 			if (sp == NULL) {
387 				return (EAI_SERVICE);
388 			}
389 			if (socktype == 0) {
390 				if (strcmp(sp->s_proto, "tcp") == 0) {
391 					socktype = SOCK_STREAM;
392 				} else if (strcmp(sp->s_proto, "udp") == 0) {
393 					socktype = SOCK_DGRAM;
394 				}
395 			}
396 		}
397 	} else {
398 		port = 0;
399 	}
400 
401 	/*
402 	 * Next, deal with just a service name, and no hostname.
403 	 * (we verified that one of them was non-null up above).
404 	 */
405 	if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
406 		if (family == AF_INET || family == 0) {
407 			ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
408 			if (ai == NULL) {
409 				return (EAI_MEMORY);
410 			}
411 			ai->ai_socktype = socktype;
412 			ai->ai_protocol = protocol;
413 			SIN(ai->ai_addr)->sin_port = port;
414 			ai->ai_next = ai_list;
415 			ai_list = ai;
416 		}
417 
418 		if (family == AF_INET6 || family == 0) {
419 			ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
420 			if (ai == NULL) {
421 				_freeaddrinfo(ai_list);
422 				return (EAI_MEMORY);
423 			}
424 			ai->ai_socktype = socktype;
425 			ai->ai_protocol = protocol;
426 			SIN6(ai->ai_addr)->sin6_port = port;
427 			ai->ai_next = ai_list;
428 			ai_list = ai;
429 		}
430 
431 		*res = ai_list;
432 		return (0);
433 	}
434 
435 	/*
436 	 * If the family isn't specified or AI_NUMERICHOST specified, check
437 	 * first to see if it is a numeric address.
438 	 * Though the gethostbyname2() routine will recognize numeric addresses,
439 	 * it will only recognize the format that it is being called for.  Thus,
440 	 * a numeric AF_INET address will be treated by the AF_INET6 call as
441 	 * a domain name, and vice versa.  Checking for both numerics here
442 	 * avoids that.
443 	 */
444 	if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0))
445 	{
446 		char abuf[sizeof(struct in6_addr)];
447 		char nbuf[NI_MAXHOST];
448 		int addrsize, addroff;
449 		char ntmp[NI_MAXHOST];
450 		uint32_t scopeid = 0;
451 
452 		/*
453 		 * Scope identifier portion.
454 		 */
455 		ntmp[0] = '\0';
456 		if (strchr(hostname, '%') != NULL) {
457 			char *p;
458 			strlcpy(ntmp, hostname, sizeof(ntmp));
459 			p = strchr(ntmp, '%');
460 
461 			if (p != NULL && parse_scopeid(p + 1, &scopeid)) {
462 				*p = '\0';
463 			} else {
464 				ntmp[0] = '\0';
465 			}
466 		}
467 
468 		if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) == 1) {
469 			if (family == AF_INET6) {
470 				/*
471 				 * Convert to a V4 mapped address.
472 				 */
473 				struct in6_addr *a6 = (struct in6_addr *)abuf;
474 				memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4);
475 				memset(&a6->s6_addr[10], 0xff, 2);
476 				memset(&a6->s6_addr[0], 0, 10);
477 				goto inet6_addr;
478 			}
479 			addrsize = sizeof(struct in_addr);
480 			addroff = offsetof(struct sockaddr_in, sin_addr);
481 			family = AF_INET;
482 			goto common;
483 		} else if (ntmp[0] != '\0' &&
484 			   inet_pton(AF_INET6, ntmp, abuf) == 1)
485 		{
486 			if (family && family != AF_INET6) {
487 				return (EAI_NONAME);
488 			}
489 			addrsize = sizeof(struct in6_addr);
490 			addroff = offsetof(struct sockaddr_in6, sin6_addr);
491 			family = AF_INET6;
492 			goto common;
493 		} else if (inet_pton(AF_INET6, hostname, abuf) == 1) {
494 			if (family != 0 && family != AF_INET6) {
495 				return (EAI_NONAME);
496 			}
497 		inet6_addr:
498 			addrsize = sizeof(struct in6_addr);
499 			addroff = offsetof(struct sockaddr_in6, sin6_addr);
500 			family = AF_INET6;
501 
502 		common:
503 			ai = ai_alloc(family,
504 				      ((family == AF_INET6)
505 					       ? sizeof(struct sockaddr_in6)
506 					       : sizeof(struct sockaddr_in)));
507 			if (ai == NULL) {
508 				return (EAI_MEMORY);
509 			}
510 			ai_list = ai;
511 			ai->ai_socktype = socktype;
512 			SIN(ai->ai_addr)->sin_port = port;
513 			memmove((char *)ai->ai_addr + addroff, abuf, addrsize);
514 			if (ai->ai_family == AF_INET6) {
515 				SIN6(ai->ai_addr)->sin6_scope_id = scopeid;
516 			}
517 			if ((flags & AI_CANONNAME) != 0) {
518 				if (getnameinfo(ai->ai_addr,
519 						(socklen_t)ai->ai_addrlen, nbuf,
520 						sizeof(nbuf), NULL, 0,
521 						NI_NUMERICHOST) == 0)
522 				{
523 					ai->ai_canonname = strdup(nbuf);
524 					if (ai->ai_canonname == NULL) {
525 						_freeaddrinfo(ai);
526 						return (EAI_MEMORY);
527 					}
528 				} else {
529 					/* XXX raise error? */
530 					ai->ai_canonname = NULL;
531 				}
532 			}
533 			goto done;
534 		} else if ((flags & AI_NUMERICHOST) != 0) {
535 			return (EAI_NONAME);
536 		}
537 	}
538 
539 	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
540 		set_order(family, net_order);
541 		for (i = 0; i < FOUND_MAX; i++) {
542 			if (net_order[i] == NULL) {
543 				break;
544 			}
545 			err = (net_order[i])(hostname, flags, &ai_list,
546 					     socktype, port);
547 			if (err != 0) {
548 				if (ai_list != NULL) {
549 					_freeaddrinfo(ai_list);
550 					ai_list = NULL;
551 				}
552 				break;
553 			}
554 		}
555 	} else {
556 		err = resolve_name(family, hostname, flags, &ai_list, socktype,
557 				   port);
558 	}
559 
560 	if (ai_list == NULL) {
561 		if (err == 0) {
562 			err = EAI_NONAME;
563 		}
564 		return (err);
565 	}
566 
567 done:
568 	ai_list = ai_reverse(ai_list);
569 
570 	*res = ai_list;
571 	return (0);
572 }
573 
574 typedef struct gai_restrans {
575 	dns_clientrestrans_t *xid;
576 	bool is_inprogress;
577 	int error;
578 	struct addrinfo ai_sentinel;
579 	struct gai_resstate *resstate;
580 } gai_restrans_t;
581 
582 typedef struct gai_resstate {
583 	isc_mem_t *mctx;
584 	struct gai_statehead *head;
585 	dns_fixedname_t fixedname;
586 	dns_name_t *qname;
587 	gai_restrans_t *trans4;
588 	gai_restrans_t *trans6;
589 	ISC_LINK(struct gai_resstate) link;
590 } gai_resstate_t;
591 
592 typedef struct gai_statehead {
593 	int ai_family;
594 	int ai_flags;
595 	int ai_socktype;
596 	int ai_port;
597 	isc_appctx_t *actx;
598 	dns_client_t *dnsclient;
599 	isc_mutex_t list_lock;
600 	ISC_LIST(struct gai_resstate) resstates;
601 	unsigned int activestates;
602 } gai_statehead_t;
603 
604 static isc_result_t
make_resstate(isc_mem_t * mctx,gai_statehead_t * head,const char * hostname,const char * domain,gai_resstate_t ** statep)605 make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname,
606 	      const char *domain, gai_resstate_t **statep) {
607 	isc_result_t result;
608 	gai_resstate_t *state;
609 	dns_fixedname_t fixeddomain;
610 	dns_name_t *qdomain;
611 	unsigned int namelen;
612 	isc_buffer_t b;
613 	bool need_v4 = false;
614 	bool need_v6 = false;
615 
616 	state = isc_mem_get(mctx, sizeof(*state));
617 
618 	/* Construct base domain name */
619 	namelen = strlen(domain);
620 	isc_buffer_constinit(&b, domain, namelen);
621 	isc_buffer_add(&b, namelen);
622 	qdomain = dns_fixedname_initname(&fixeddomain);
623 	result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL);
624 	if (result != ISC_R_SUCCESS) {
625 		isc_mem_put(mctx, state, sizeof(*state));
626 		return (result);
627 	}
628 
629 	/* Construct query name */
630 	namelen = strlen(hostname);
631 	isc_buffer_constinit(&b, hostname, namelen);
632 	isc_buffer_add(&b, namelen);
633 	state->qname = dns_fixedname_initname(&state->fixedname);
634 	result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL);
635 	if (result != ISC_R_SUCCESS) {
636 		isc_mem_put(mctx, state, sizeof(*state));
637 		return (result);
638 	}
639 
640 	if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET) {
641 		need_v4 = true;
642 	}
643 	if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6) {
644 		need_v6 = true;
645 	}
646 
647 	state->trans6 = NULL;
648 	state->trans4 = NULL;
649 	if (need_v4) {
650 		state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t));
651 		state->trans4->error = 0;
652 		state->trans4->xid = NULL;
653 		state->trans4->resstate = state;
654 		state->trans4->is_inprogress = true;
655 		state->trans4->ai_sentinel.ai_next = NULL;
656 	}
657 	if (need_v6) {
658 		state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t));
659 		state->trans6->error = 0;
660 		state->trans6->xid = NULL;
661 		state->trans6->resstate = state;
662 		state->trans6->is_inprogress = true;
663 		state->trans6->ai_sentinel.ai_next = NULL;
664 	}
665 
666 	state->mctx = mctx;
667 	state->head = head;
668 	ISC_LINK_INIT(state, link);
669 
670 	*statep = state;
671 
672 	return (ISC_R_SUCCESS);
673 }
674 
675 static isc_result_t
make_resstates(isc_mem_t * mctx,const char * hostname,gai_statehead_t * head,irs_resconf_t * resconf)676 make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head,
677 	       irs_resconf_t *resconf) {
678 	isc_result_t result;
679 	irs_resconf_searchlist_t *searchlist;
680 	irs_resconf_search_t *searchent;
681 	gai_resstate_t *resstate, *resstate0;
682 
683 	resstate0 = NULL;
684 	result = make_resstate(mctx, head, hostname, ".", &resstate0);
685 	if (result != ISC_R_SUCCESS) {
686 		return (result);
687 	}
688 
689 	searchlist = irs_resconf_getsearchlist(resconf);
690 	for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL;
691 	     searchent = ISC_LIST_NEXT(searchent, link))
692 	{
693 		resstate = NULL;
694 		result = make_resstate(mctx, head, hostname,
695 				       (const char *)searchent->domain,
696 				       &resstate);
697 		if (result != ISC_R_SUCCESS) {
698 			break;
699 		}
700 
701 		ISC_LIST_APPEND(head->resstates, resstate, link);
702 		head->activestates++;
703 	}
704 
705 	/*
706 	 * Insert the original hostname either at the head or the tail of the
707 	 * state list, depending on the number of labels contained in the
708 	 * original name and the 'ndots' configuration parameter.
709 	 */
710 	if (dns_name_countlabels(resstate0->qname) >
711 	    irs_resconf_getndots(resconf) + 1)
712 	{
713 		ISC_LIST_PREPEND(head->resstates, resstate0, link);
714 	} else {
715 		ISC_LIST_APPEND(head->resstates, resstate0, link);
716 	}
717 	head->activestates++;
718 
719 	if (result != ISC_R_SUCCESS) {
720 		while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) {
721 			ISC_LIST_UNLINK(head->resstates, resstate, link);
722 			if (resstate->trans4 != NULL) {
723 				isc_mem_put(mctx, resstate->trans4,
724 					    sizeof(*resstate->trans4));
725 			}
726 			if (resstate->trans6 != NULL) {
727 				isc_mem_put(mctx, resstate->trans6,
728 					    sizeof(*resstate->trans6));
729 			}
730 
731 			isc_mem_put(mctx, resstate, sizeof(*resstate));
732 		}
733 	}
734 
735 	return (result);
736 }
737 
738 static void
process_answer(isc_task_t * task,isc_event_t * event)739 process_answer(isc_task_t *task, isc_event_t *event) {
740 	int error = 0, family;
741 	gai_restrans_t *trans = event->ev_arg;
742 	gai_resstate_t *resstate;
743 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
744 	dns_rdatatype_t qtype;
745 	dns_name_t *name;
746 	bool wantcname;
747 
748 	REQUIRE(trans != NULL);
749 	resstate = trans->resstate;
750 	REQUIRE(resstate != NULL);
751 	REQUIRE(task != NULL);
752 
753 	if (trans == resstate->trans4) {
754 		family = AF_INET;
755 		qtype = dns_rdatatype_a;
756 	} else {
757 		INSIST(trans == resstate->trans6);
758 		family = AF_INET6;
759 		qtype = dns_rdatatype_aaaa;
760 	}
761 
762 	INSIST(trans->is_inprogress);
763 	trans->is_inprogress = false;
764 
765 	switch (rev->result) {
766 	case ISC_R_SUCCESS:
767 	case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */
768 	case DNS_R_NCACHENXRRSET:
769 		break;
770 	default:
771 		switch (rev->vresult) {
772 		case DNS_R_SIGINVALID:
773 		case DNS_R_SIGEXPIRED:
774 		case DNS_R_SIGFUTURE:
775 		case DNS_R_KEYUNAUTHORIZED:
776 		case DNS_R_MUSTBESECURE:
777 		case DNS_R_COVERINGNSEC:
778 		case DNS_R_NOTAUTHORITATIVE:
779 		case DNS_R_NOVALIDKEY:
780 		case DNS_R_NOVALIDDS:
781 		case DNS_R_NOVALIDSIG:
782 			error = EAI_INSECUREDATA;
783 			break;
784 		default:
785 			error = EAI_FAIL;
786 		}
787 		goto done;
788 	}
789 
790 	wantcname = ((resstate->head->ai_flags & AI_CANONNAME) != 0);
791 
792 	/* Parse the response and construct the addrinfo chain */
793 	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
794 	     name = ISC_LIST_NEXT(name, link))
795 	{
796 		isc_result_t result;
797 		dns_rdataset_t *rdataset;
798 		char cname[1024];
799 
800 		if (wantcname) {
801 			isc_buffer_t b;
802 
803 			isc_buffer_init(&b, cname, sizeof(cname));
804 			result = dns_name_totext(name, true, &b);
805 			if (result != ISC_R_SUCCESS) {
806 				error = EAI_FAIL;
807 				goto done;
808 			}
809 			isc_buffer_putuint8(&b, '\0');
810 		}
811 
812 		for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
813 		     rdataset = ISC_LIST_NEXT(rdataset, link))
814 		{
815 			if (!dns_rdataset_isassociated(rdataset)) {
816 				continue;
817 			}
818 			if (rdataset->type != qtype) {
819 				continue;
820 			}
821 
822 			for (result = dns_rdataset_first(rdataset);
823 			     result == ISC_R_SUCCESS;
824 			     result = dns_rdataset_next(rdataset))
825 			{
826 				struct addrinfo *ai;
827 				dns_rdata_t rdata;
828 				dns_rdata_in_a_t rdata_a;
829 				dns_rdata_in_aaaa_t rdata_aaaa;
830 
831 				ai = ai_alloc(
832 					family,
833 					((family == AF_INET6)
834 						 ? sizeof(struct sockaddr_in6)
835 						 : sizeof(struct sockaddr_in)));
836 				if (ai == NULL) {
837 					error = EAI_MEMORY;
838 					goto done;
839 				}
840 				ai->ai_socktype = resstate->head->ai_socktype;
841 				ai->ai_next = trans->ai_sentinel.ai_next;
842 				trans->ai_sentinel.ai_next = ai;
843 
844 				/*
845 				 * Set AF-specific parameters
846 				 * (IPv4/v6 address/port)
847 				 */
848 				dns_rdata_init(&rdata);
849 				switch (family) {
850 				case AF_INET:
851 					dns_rdataset_current(rdataset, &rdata);
852 					result = dns_rdata_tostruct(
853 						&rdata, &rdata_a, NULL);
854 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
855 					SIN(ai->ai_addr)->sin_port =
856 						resstate->head->ai_port;
857 					memmove(&SIN(ai->ai_addr)->sin_addr,
858 						&rdata_a.in_addr, 4);
859 					dns_rdata_freestruct(&rdata_a);
860 					break;
861 				case AF_INET6:
862 					dns_rdataset_current(rdataset, &rdata);
863 					result = dns_rdata_tostruct(
864 						&rdata, &rdata_aaaa, NULL);
865 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
866 					SIN6(ai->ai_addr)->sin6_port =
867 						resstate->head->ai_port;
868 					memmove(&SIN6(ai->ai_addr)->sin6_addr,
869 						&rdata_aaaa.in6_addr, 16);
870 					dns_rdata_freestruct(&rdata_aaaa);
871 					break;
872 				}
873 
874 				if (wantcname) {
875 					ai->ai_canonname = strdup(cname);
876 					if (ai->ai_canonname == NULL) {
877 						error = EAI_MEMORY;
878 						goto done;
879 					}
880 				}
881 			}
882 		}
883 	}
884 
885 done:
886 	dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist);
887 	dns_client_destroyrestrans(&trans->xid);
888 
889 	isc_event_free(&event);
890 
891 	/* Make sure that error == 0 iff we have a non-empty list */
892 	if (error == 0) {
893 		if (trans->ai_sentinel.ai_next == NULL) {
894 			error = EAI_NONAME;
895 		}
896 	} else {
897 		if (trans->ai_sentinel.ai_next != NULL) {
898 			_freeaddrinfo(trans->ai_sentinel.ai_next);
899 			trans->ai_sentinel.ai_next = NULL;
900 		}
901 	}
902 	trans->error = error;
903 
904 	/* Check whether we are done */
905 	if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) &&
906 	    (resstate->trans6 == NULL || !resstate->trans6->is_inprogress))
907 	{
908 		/*
909 		 * We're done for this state.  If there is no other outstanding
910 		 * state, we can exit.
911 		 */
912 		resstate->head->activestates--;
913 		if (resstate->head->activestates == 0) {
914 			isc_app_ctxsuspend(resstate->head->actx);
915 			return;
916 		}
917 
918 		/*
919 		 * There are outstanding states, but if we are at the head
920 		 * of the state list (i.e., at the highest search priority)
921 		 * and have any answer, we can stop now by canceling the
922 		 * others.
923 		 */
924 		LOCK(&resstate->head->list_lock);
925 		if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) {
926 			if ((resstate->trans4 != NULL &&
927 			     resstate->trans4->ai_sentinel.ai_next != NULL) ||
928 			    (resstate->trans6 != NULL &&
929 			     resstate->trans6->ai_sentinel.ai_next != NULL))
930 			{
931 				gai_resstate_t *rest;
932 
933 				for (rest = ISC_LIST_NEXT(resstate, link);
934 				     rest != NULL;
935 				     rest = ISC_LIST_NEXT(rest, link))
936 				{
937 					if (rest->trans4 != NULL &&
938 					    rest->trans4->xid != NULL)
939 					{
940 						dns_client_cancelresolve(
941 							rest->trans4->xid);
942 					}
943 					if (rest->trans6 != NULL &&
944 					    rest->trans6->xid != NULL)
945 					{
946 						dns_client_cancelresolve(
947 							rest->trans6->xid);
948 					}
949 				}
950 			} else {
951 				/*
952 				 * This search fails, so we move to the tail
953 				 * of the list so that the next entry will
954 				 * have the highest priority.
955 				 */
956 				ISC_LIST_UNLINK(resstate->head->resstates,
957 						resstate, link);
958 				ISC_LIST_APPEND(resstate->head->resstates,
959 						resstate, link);
960 			}
961 		}
962 		UNLOCK(&resstate->head->list_lock);
963 	}
964 }
965 
966 static int
resolve_name(int family,const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)967 resolve_name(int family, const char *hostname, int flags, struct addrinfo **aip,
968 	     int socktype, int port) {
969 	isc_result_t result;
970 	irs_context_t *irsctx;
971 	irs_resconf_t *conf;
972 	isc_mem_t *mctx;
973 	isc_appctx_t *actx;
974 	isc_task_t *task;
975 	int terror = 0;
976 	int error = 0;
977 	dns_client_t *client;
978 	gai_resstate_t *resstate;
979 	gai_statehead_t head;
980 	bool all_fail = true;
981 
982 	/* get IRS context and the associated parameters */
983 	irsctx = NULL;
984 	result = irs_context_get(&irsctx);
985 	if (result != ISC_R_SUCCESS) {
986 		return (EAI_FAIL);
987 	}
988 	actx = irs_context_getappctx(irsctx);
989 
990 	mctx = irs_context_getmctx(irsctx);
991 	task = irs_context_gettask(irsctx);
992 	conf = irs_context_getresconf(irsctx);
993 	client = irs_context_getdnsclient(irsctx);
994 
995 	/* construct resolution states */
996 	head.activestates = 0;
997 	head.ai_family = family;
998 	head.ai_socktype = socktype;
999 	head.ai_flags = flags;
1000 	head.ai_port = port;
1001 	head.actx = actx;
1002 	head.dnsclient = client;
1003 	isc_mutex_init(&head.list_lock);
1004 
1005 	ISC_LIST_INIT(head.resstates);
1006 	result = make_resstates(mctx, hostname, &head, conf);
1007 	if (result != ISC_R_SUCCESS) {
1008 		isc_mutex_destroy(&head.list_lock);
1009 		return (EAI_FAIL);
1010 	}
1011 
1012 	LOCK(&head.list_lock);
1013 	for (resstate = ISC_LIST_HEAD(head.resstates); resstate != NULL;
1014 	     resstate = ISC_LIST_NEXT(resstate, link))
1015 	{
1016 		if (resstate->trans4 != NULL) {
1017 			result = dns_client_startresolve(
1018 				client, resstate->qname, dns_rdataclass_in,
1019 				dns_rdatatype_a, 0, task, process_answer,
1020 				resstate->trans4, &resstate->trans4->xid);
1021 			if (result == ISC_R_SUCCESS) {
1022 				resstate->trans4->is_inprogress = true;
1023 				all_fail = false;
1024 			} else {
1025 				resstate->trans4->is_inprogress = false;
1026 			}
1027 		}
1028 		if (resstate->trans6 != NULL) {
1029 			result = dns_client_startresolve(
1030 				client, resstate->qname, dns_rdataclass_in,
1031 				dns_rdatatype_aaaa, 0, task, process_answer,
1032 				resstate->trans6, &resstate->trans6->xid);
1033 			if (result == ISC_R_SUCCESS) {
1034 				resstate->trans6->is_inprogress = true;
1035 				all_fail = false;
1036 			} else {
1037 				resstate->trans6->is_inprogress = false;
1038 			}
1039 		}
1040 	}
1041 	UNLOCK(&head.list_lock);
1042 
1043 	if (!all_fail) {
1044 		/* Start all the events */
1045 		isc_app_ctxrun(actx);
1046 	} else {
1047 		error = EAI_FAIL;
1048 	}
1049 
1050 	/* Cleanup */
1051 	while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) {
1052 		int terror4 = 0, terror6 = 0;
1053 
1054 		ISC_LIST_UNLINK(head.resstates, resstate, link);
1055 
1056 		if (*aip == NULL) {
1057 			struct addrinfo *sentinel4 = NULL;
1058 			struct addrinfo *sentinel6 = NULL;
1059 
1060 			if (resstate->trans4 != NULL) {
1061 				sentinel4 =
1062 					resstate->trans4->ai_sentinel.ai_next;
1063 				resstate->trans4->ai_sentinel.ai_next = NULL;
1064 			}
1065 			if (resstate->trans6 != NULL) {
1066 				sentinel6 =
1067 					resstate->trans6->ai_sentinel.ai_next;
1068 				resstate->trans6->ai_sentinel.ai_next = NULL;
1069 			}
1070 			*aip = ai_concat(sentinel4, sentinel6);
1071 		}
1072 
1073 		if (resstate->trans4 != NULL) {
1074 			INSIST(resstate->trans4->xid == NULL);
1075 			terror4 = resstate->trans4->error;
1076 			isc_mem_put(mctx, resstate->trans4,
1077 				    sizeof(*resstate->trans4));
1078 		}
1079 		if (resstate->trans6 != NULL) {
1080 			INSIST(resstate->trans6->xid == NULL);
1081 			terror6 = resstate->trans6->error;
1082 			isc_mem_put(mctx, resstate->trans6,
1083 				    sizeof(*resstate->trans6));
1084 		}
1085 
1086 		/*
1087 		 * If the entire lookup fails, we need to choose an appropriate
1088 		 * error code from individual codes.  We'll try to provide as
1089 		 * specific a code as possible.  In general, we are going to
1090 		 * find an error code other than EAI_NONAME (which is too
1091 		 * generic and may actually not be problematic in some cases).
1092 		 * EAI_NONAME will be set below if no better code is found.
1093 		 */
1094 		if (terror == 0 || terror == EAI_NONAME) {
1095 			if (terror4 != 0 && terror4 != EAI_NONAME) {
1096 				terror = terror4;
1097 			} else if (terror6 != 0 && terror6 != EAI_NONAME) {
1098 				terror = terror6;
1099 			}
1100 		}
1101 
1102 		isc_mem_put(mctx, resstate, sizeof(*resstate));
1103 	}
1104 
1105 	if (*aip == NULL) {
1106 		error = terror;
1107 		if (error == 0) {
1108 			error = EAI_NONAME;
1109 		}
1110 	}
1111 
1112 #if 1 /*  XXX: enabled for finding leaks.  should be cleaned up later. */
1113 	isc_app_ctxfinish(actx);
1114 	irs_context_destroy(&irsctx);
1115 #endif /* if 1 */
1116 
1117 	isc_mutex_destroy(&head.list_lock);
1118 	return (error);
1119 }
1120 
1121 static void
set_order(int family,int (** net_order)(const char *,int,struct addrinfo **,int,int))1122 set_order(int family,
1123 	  int (**net_order)(const char *, int, struct addrinfo **, int, int)) {
1124 	char *order, *tok, *last;
1125 	int found;
1126 
1127 	if (family) {
1128 		switch (family) {
1129 		case AF_INET:
1130 			*net_order++ = add_ipv4;
1131 			break;
1132 		case AF_INET6:
1133 			*net_order++ = add_ipv6;
1134 			break;
1135 		}
1136 	} else {
1137 		order = getenv("NET_ORDER");
1138 		found = 0;
1139 		if (order != NULL) {
1140 			last = NULL;
1141 			for (tok = strtok_r(order, ":", &last); tok;
1142 			     tok = strtok_r(NULL, ":", &last))
1143 			{
1144 				if (strcasecmp(tok, "inet6") == 0) {
1145 					if ((found & FOUND_IPV6) == 0) {
1146 						*net_order++ = add_ipv6;
1147 					}
1148 					found |= FOUND_IPV6;
1149 				} else if (strcasecmp(tok, "inet") == 0 ||
1150 					   strcasecmp(tok, "inet4") == 0)
1151 				{
1152 					if ((found & FOUND_IPV4) == 0) {
1153 						*net_order++ = add_ipv4;
1154 					}
1155 					found |= FOUND_IPV4;
1156 				}
1157 			}
1158 		}
1159 
1160 		/*
1161 		 * Add in anything that we didn't find.
1162 		 */
1163 		if ((found & FOUND_IPV4) == 0) {
1164 			*net_order++ = add_ipv4;
1165 		}
1166 		if ((found & FOUND_IPV6) == 0) {
1167 			*net_order++ = add_ipv6;
1168 		}
1169 	}
1170 	*net_order = NULL;
1171 	return;
1172 }
1173 
1174 static char v4_loop[4] = { 127, 0, 0, 1 };
1175 
1176 static int
add_ipv4(const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)1177 add_ipv4(const char *hostname, int flags, struct addrinfo **aip, int socktype,
1178 	 int port) {
1179 	struct addrinfo *ai;
1180 
1181 	UNUSED(hostname);
1182 	UNUSED(flags);
1183 
1184 	ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */
1185 	if (ai == NULL) {
1186 		return (EAI_MEMORY);
1187 	}
1188 
1189 	*aip = ai;
1190 	ai->ai_socktype = socktype;
1191 	SIN(ai->ai_addr)->sin_port = port;
1192 	memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
1193 
1194 	return (0);
1195 }
1196 
1197 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1198 
1199 static int
add_ipv6(const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)1200 add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype,
1201 	 int port) {
1202 	struct addrinfo *ai;
1203 
1204 	UNUSED(hostname);
1205 	UNUSED(flags);
1206 
1207 	ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */
1208 	if (ai == NULL) {
1209 		return (EAI_MEMORY);
1210 	}
1211 
1212 	*aip = ai;
1213 	ai->ai_socktype = socktype;
1214 	SIN6(ai->ai_addr)->sin6_port = port;
1215 	memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
1216 
1217 	return (0);
1218 }
1219 
1220 /*% Free address info. */
1221 void
freeaddrinfo(struct addrinfo * ai)1222 freeaddrinfo(struct addrinfo *ai) {
1223 	_freeaddrinfo(ai);
1224 }
1225 
1226 static void
_freeaddrinfo(struct addrinfo * ai)1227 _freeaddrinfo(struct addrinfo *ai) {
1228 	struct addrinfo *ai_next;
1229 
1230 	while (ai != NULL) {
1231 		ai_next = ai->ai_next;
1232 		if (ai->ai_addr != NULL) {
1233 			free(ai->ai_addr);
1234 		}
1235 		if (ai->ai_canonname) {
1236 			free(ai->ai_canonname);
1237 		}
1238 		free(ai);
1239 		ai = ai_next;
1240 	}
1241 }
1242 
1243 #ifdef AF_LOCAL
1244 static int
get_local(const char * name,int socktype,struct addrinfo ** res)1245 get_local(const char *name, int socktype, struct addrinfo **res) {
1246 	struct addrinfo *ai;
1247 	struct sockaddr_un *slocal;
1248 
1249 	if (socktype == 0) {
1250 		return (EAI_SOCKTYPE);
1251 	}
1252 
1253 	ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
1254 	if (ai == NULL) {
1255 		return (EAI_MEMORY);
1256 	}
1257 
1258 	slocal = SLOCAL(ai->ai_addr);
1259 	strlcpy(slocal->sun_path, name, sizeof(slocal->sun_path));
1260 
1261 	ai->ai_socktype = socktype;
1262 	/*
1263 	 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
1264 	 * and ai->ai_next were initialized to zero.
1265 	 */
1266 
1267 	*res = ai;
1268 	return (0);
1269 }
1270 #endif /* ifdef AF_LOCAL */
1271 
1272 /*!
1273  * Allocate an addrinfo structure, and a sockaddr structure
1274  * of the specified length.  We initialize:
1275  *	ai_addrlen
1276  *	ai_family
1277  *	ai_addr
1278  *	ai_addr->sa_family
1279  *	ai_addr->sa_len	(IRS_PLATFORM_HAVESALEN)
1280  * and everything else is initialized to zero.
1281  */
1282 static struct addrinfo *
ai_alloc(int family,int addrlen)1283 ai_alloc(int family, int addrlen) {
1284 	struct addrinfo *ai;
1285 
1286 	ai = (struct addrinfo *)calloc(1, sizeof(*ai));
1287 	if (ai == NULL) {
1288 		return (NULL);
1289 	}
1290 
1291 	ai->ai_addr = SA(calloc(1, addrlen));
1292 	if (ai->ai_addr == NULL) {
1293 		free(ai);
1294 		return (NULL);
1295 	}
1296 	ai->ai_addrlen = addrlen;
1297 	ai->ai_family = family;
1298 	ai->ai_addr->sa_family = family;
1299 #ifdef IRS_PLATFORM_HAVESALEN
1300 	ai->ai_addr->sa_len = addrlen;
1301 #endif /* ifdef IRS_PLATFORM_HAVESALEN */
1302 	return (ai);
1303 }
1304 
1305 static struct addrinfo *
ai_clone(struct addrinfo * oai,int family)1306 ai_clone(struct addrinfo *oai, int family) {
1307 	struct addrinfo *ai;
1308 
1309 	ai = ai_alloc(family,
1310 		      ((family == AF_INET6) ? sizeof(struct sockaddr_in6)
1311 					    : sizeof(struct sockaddr_in)));
1312 
1313 	if (ai == NULL) {
1314 		return (NULL);
1315 	}
1316 	if (oai == NULL) {
1317 		return (ai);
1318 	}
1319 
1320 	ai->ai_flags = oai->ai_flags;
1321 	ai->ai_socktype = oai->ai_socktype;
1322 	ai->ai_protocol = oai->ai_protocol;
1323 	ai->ai_canonname = NULL;
1324 	ai->ai_next = oai;
1325 	return (ai);
1326 }
1327 
1328 static struct addrinfo *
ai_reverse(struct addrinfo * oai)1329 ai_reverse(struct addrinfo *oai) {
1330 	struct addrinfo *nai, *tai;
1331 
1332 	nai = NULL;
1333 
1334 	while (oai != NULL) {
1335 		/*
1336 		 * Grab one off the old list.
1337 		 */
1338 		tai = oai;
1339 		oai = oai->ai_next;
1340 		/*
1341 		 * Put it on the front of the new list.
1342 		 */
1343 		tai->ai_next = nai;
1344 		nai = tai;
1345 	}
1346 	return (nai);
1347 }
1348 
1349 static struct addrinfo *
ai_concat(struct addrinfo * ai1,struct addrinfo * ai2)1350 ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) {
1351 	struct addrinfo *ai_tmp;
1352 
1353 	if (ai1 == NULL) {
1354 		return (ai2);
1355 	} else if (ai2 == NULL) {
1356 		return (ai1);
1357 	}
1358 
1359 	for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL;
1360 	     ai_tmp = ai_tmp->ai_next)
1361 	{
1362 	}
1363 
1364 	ai_tmp->ai_next = ai2;
1365 
1366 	return (ai1);
1367 }
1368