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