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