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