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