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