1 /* MIT License
2 *
3 * Copyright (c) 1998 Massachusetts Institute of Technology
4 * Copyright (c) 2007 Daniel Stenberg
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * SPDX-License-Identifier: MIT
26 */
27
28 #include "ares_setup.h"
29
30 #ifdef HAVE_SYS_PARAM_H
31 # include <sys/param.h>
32 #endif
33
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37
38 #ifdef HAVE_NETDB_H
39 # include <netdb.h>
40 #endif
41
42 #ifdef HAVE_ARPA_INET_H
43 # include <arpa/inet.h>
44 #endif
45
46 #include "ares_nameser.h"
47
48 #if defined(ANDROID) || defined(__ANDROID__)
49 # include <sys/system_properties.h>
50 # include "ares_android.h"
51 /* From the Bionic sources */
52 # define DNS_PROP_NAME_PREFIX "net.dns"
53 # define MAX_DNS_PROPERTIES 8
54 #endif
55
56 #if defined(CARES_USE_LIBRESOLV)
57 # include <resolv.h>
58 #endif
59
60 #if defined(USE_WINSOCK)
61 # if defined(HAVE_IPHLPAPI_H)
62 # include <iphlpapi.h>
63 # endif
64 # if defined(HAVE_NETIOAPI_H)
65 # include <netioapi.h>
66 # endif
67 #endif
68
69 #include "ares.h"
70 #include "ares_inet_net_pton.h"
71 #include "ares_platform.h"
72 #include "ares_private.h"
73
74 #ifdef WATT32
75 # undef WIN32 /* Redefined in MingW/MSVC headers */
76 #endif
77
78
79 #ifdef WIN32
80 /*
81 * get_REG_SZ()
82 *
83 * Given a 'hKey' handle to an open registry key and a 'leafKeyName' pointer
84 * to the name of the registry leaf key to be queried, fetch it's string
85 * value and return a pointer in *outptr to a newly allocated memory area
86 * holding it as a null-terminated string.
87 *
88 * Returns 0 and nullifies *outptr upon inability to return a string value.
89 *
90 * Returns 1 and sets *outptr when returning a dynamically allocated string.
91 *
92 * Supported on Windows NT 3.5 and newer.
93 */
get_REG_SZ(HKEY hKey,const char * leafKeyName,char ** outptr)94 static ares_bool_t get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
95 {
96 DWORD size = 0;
97 int res;
98
99 *outptr = NULL;
100
101 /* Find out size of string stored in registry */
102 res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, NULL, &size);
103 if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size) {
104 return ARES_FALSE;
105 }
106
107 /* Allocate buffer of indicated size plus one given that string
108 might have been stored without null termination */
109 *outptr = ares_malloc(size + 1);
110 if (!*outptr) {
111 return ARES_FALSE;
112 }
113
114 /* Get the value for real */
115 res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, (unsigned char *)*outptr,
116 &size);
117 if ((res != ERROR_SUCCESS) || (size == 1)) {
118 ares_free(*outptr);
119 *outptr = NULL;
120 return ARES_FALSE;
121 }
122
123 /* Null terminate buffer always */
124 *(*outptr + size) = '\0';
125
126 return ARES_TRUE;
127 }
128
commanjoin(char ** dst,const char * const src,const size_t len)129 static void commanjoin(char **dst, const char * const src, const size_t len)
130 {
131 char *newbuf;
132 size_t newsize;
133
134 /* 1 for terminating 0 and 2 for , and terminating 0 */
135 newsize = len + (*dst ? (ares_strlen(*dst) + 2) : 1);
136 newbuf = ares_realloc(*dst, newsize);
137 if (!newbuf) {
138 return;
139 }
140 if (*dst == NULL) {
141 *newbuf = '\0';
142 }
143 *dst = newbuf;
144 if (ares_strlen(*dst) != 0) {
145 strcat(*dst, ",");
146 }
147 strncat(*dst, src, len);
148 }
149
150 /*
151 * commajoin()
152 *
153 * RTF code.
154 */
commajoin(char ** dst,const char * src)155 static void commajoin(char **dst, const char *src)
156 {
157 commanjoin(dst, src, ares_strlen(src));
158 }
159
160 /* A structure to hold the string form of IPv4 and IPv6 addresses so we can
161 * sort them by a metric.
162 */
163 typedef struct {
164 /* The metric we sort them by. */
165 ULONG metric;
166
167 /* Original index of the item, used as a secondary sort parameter to make
168 * qsort() stable if the metrics are equal */
169 size_t orig_idx;
170
171 /* Room enough for the string form of any IPv4 or IPv6 address that
172 * ares_inet_ntop() will create. Based on the existing c-ares practice.
173 */
174 char text[INET6_ADDRSTRLEN + 8 + 64]; /* [%s]:NNNNN%iface */
175 } Address;
176
177 /* Sort Address values \a left and \a right by metric, returning the usual
178 * indicators for qsort().
179 */
compareAddresses(const void * arg1,const void * arg2)180 static int compareAddresses(const void *arg1, const void *arg2)
181 {
182 const Address * const left = arg1;
183 const Address * const right = arg2;
184 /* Lower metric the more preferred */
185 if (left->metric < right->metric) {
186 return -1;
187 }
188 if (left->metric > right->metric) {
189 return 1;
190 }
191 /* If metrics are equal, lower original index more preferred */
192 if (left->orig_idx < right->orig_idx) {
193 return -1;
194 }
195 if (left->orig_idx > right->orig_idx) {
196 return 1;
197 }
198 return 0;
199 }
200
201 /* There can be multiple routes to "the Internet". And there can be different
202 * DNS servers associated with each of the interfaces that offer those routes.
203 * We have to assume that any DNS server can serve any request. But, some DNS
204 * servers may only respond if requested over their associated interface. But
205 * we also want to use "the preferred route to the Internet" whenever possible
206 * (and not use DNS servers on a non-preferred route even by forcing request
207 * to go out on the associated non-preferred interface). i.e. We want to use
208 * the DNS servers associated with the same interface that we would use to
209 * make a general request to anything else.
210 *
211 * But, Windows won't sort the DNS servers by the metrics associated with the
212 * routes and interfaces _even_ though it obviously sends IP packets based on
213 * those same routes and metrics. So, we must do it ourselves.
214 *
215 * So, we sort the DNS servers by the same metric values used to determine how
216 * an outgoing IP packet will go, thus effectively using the DNS servers
217 * associated with the interface that the DNS requests themselves will
218 * travel. This gives us optimal routing and avoids issues where DNS servers
219 * won't respond to requests that don't arrive via some specific subnetwork
220 * (and thus some specific interface).
221 *
222 * This function computes the metric we use to sort. On the interface
223 * identified by \a luid, it determines the best route to \a dest and combines
224 * that route's metric with \a interfaceMetric to compute a metric for the
225 * destination address on that interface. This metric can be used as a weight
226 * to sort the DNS server addresses associated with each interface (lower is
227 * better).
228 *
229 * Note that by restricting the route search to the specific interface with
230 * which the DNS servers are associated, this function asks the question "What
231 * is the metric for sending IP packets to this DNS server?" which allows us
232 * to sort the DNS servers correctly.
233 */
getBestRouteMetric(IF_LUID * const luid,const SOCKADDR_INET * const dest,const ULONG interfaceMetric)234 static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */
235 const SOCKADDR_INET * const dest,
236 const ULONG interfaceMetric)
237 {
238 /* On this interface, get the best route to that destination. */
239 # if defined(__WATCOMC__)
240 /* OpenWatcom's builtin Windows SDK does not have a definition for
241 * MIB_IPFORWARD_ROW2, and also does not allow the usage of SOCKADDR_INET
242 * as a variable. Let's work around this by returning the worst possible
243 * metric, but only when using the OpenWatcom compiler.
244 * It may be worth investigating using a different version of the Windows
245 * SDK with OpenWatcom in the future, though this may be fixed in OpenWatcom
246 * 2.0.
247 */
248 return (ULONG)-1;
249 # else
250 MIB_IPFORWARD_ROW2 row;
251 SOCKADDR_INET ignored;
252 if (GetBestRoute2(/* The interface to use. The index is ignored since we are
253 * passing a LUID.
254 */
255 luid, 0,
256 /* No specific source address. */
257 NULL,
258 /* Our destination address. */
259 dest,
260 /* No options. */
261 0,
262 /* The route row. */
263 &row,
264 /* The best source address, which we don't need. */
265 &ignored) != NO_ERROR
266 /* If the metric is "unused" (-1) or too large for us to add the two
267 * metrics, use the worst possible, thus sorting this last.
268 */
269 || row.Metric == (ULONG)-1 ||
270 row.Metric > ((ULONG)-1) - interfaceMetric) {
271 /* Return the worst possible metric. */
272 return (ULONG)-1;
273 }
274
275 /* Return the metric value from that row, plus the interface metric.
276 *
277 * See
278 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa814494(v=vs.85).aspx
279 * which describes the combination as a "sum".
280 */
281 return row.Metric + interfaceMetric;
282 # endif /* __WATCOMC__ */
283 }
284
285 /*
286 * get_DNS_Windows()
287 *
288 * Locates DNS info using GetAdaptersAddresses() function from the Internet
289 * Protocol Helper (IP Helper) API. When located, this returns a pointer
290 * in *outptr to a newly allocated memory area holding a null-terminated
291 * string with a space or comma separated list of DNS IP addresses.
292 *
293 * Returns 0 and nullifies *outptr upon inability to return DNSes string.
294 *
295 * Returns 1 and sets *outptr when returning a dynamically allocated string.
296 *
297 * Implementation supports Windows XP and newer.
298 */
299 # define IPAA_INITIAL_BUF_SZ 15 * 1024
300 # define IPAA_MAX_TRIES 3
301
get_DNS_Windows(char ** outptr)302 static ares_bool_t get_DNS_Windows(char **outptr)
303 {
304 IP_ADAPTER_DNS_SERVER_ADDRESS *ipaDNSAddr;
305 IP_ADAPTER_ADDRESSES *ipaa;
306 IP_ADAPTER_ADDRESSES *newipaa;
307 IP_ADAPTER_ADDRESSES *ipaaEntry;
308 ULONG ReqBufsz = IPAA_INITIAL_BUF_SZ;
309 ULONG Bufsz = IPAA_INITIAL_BUF_SZ;
310 ULONG AddrFlags = 0;
311 int trying = IPAA_MAX_TRIES;
312 ULONG res;
313
314 /* The capacity of addresses, in elements. */
315 size_t addressesSize;
316 /* The number of elements in addresses. */
317 size_t addressesIndex = 0;
318 /* The addresses we will sort. */
319 Address *addresses;
320
321 union {
322 struct sockaddr *sa;
323 struct sockaddr_in *sa4;
324 struct sockaddr_in6 *sa6;
325 } namesrvr;
326
327 *outptr = NULL;
328
329 ipaa = ares_malloc(Bufsz);
330 if (!ipaa) {
331 return ARES_FALSE;
332 }
333
334 /* Start with enough room for a few DNS server addresses and we'll grow it
335 * as we encounter more.
336 */
337 addressesSize = 4;
338 addresses = (Address *)ares_malloc(sizeof(Address) * addressesSize);
339 if (addresses == NULL) {
340 /* We need room for at least some addresses to function. */
341 ares_free(ipaa);
342 return ARES_FALSE;
343 }
344
345 /* Usually this call succeeds with initial buffer size */
346 res = GetAdaptersAddresses(AF_UNSPEC, AddrFlags, NULL, ipaa, &ReqBufsz);
347 if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) {
348 goto done;
349 }
350
351 while ((res == ERROR_BUFFER_OVERFLOW) && (--trying)) {
352 if (Bufsz < ReqBufsz) {
353 newipaa = ares_realloc(ipaa, ReqBufsz);
354 if (!newipaa) {
355 goto done;
356 }
357 Bufsz = ReqBufsz;
358 ipaa = newipaa;
359 }
360 res = GetAdaptersAddresses(AF_UNSPEC, AddrFlags, NULL, ipaa, &ReqBufsz);
361 if (res == ERROR_SUCCESS) {
362 break;
363 }
364 }
365 if (res != ERROR_SUCCESS) {
366 goto done;
367 }
368
369 for (ipaaEntry = ipaa; ipaaEntry; ipaaEntry = ipaaEntry->Next) {
370 if (ipaaEntry->OperStatus != IfOperStatusUp) {
371 continue;
372 }
373
374 /* For each interface, find any associated DNS servers as IPv4 or IPv6
375 * addresses. For each found address, find the best route to that DNS
376 * server address _on_ _that_ _interface_ (at this moment in time) and
377 * compute the resulting total metric, just as Windows routing will do.
378 * Then, sort all the addresses found by the metric.
379 */
380 for (ipaDNSAddr = ipaaEntry->FirstDnsServerAddress; ipaDNSAddr;
381 ipaDNSAddr = ipaDNSAddr->Next) {
382 char ipaddr[INET6_ADDRSTRLEN] = "";
383 namesrvr.sa = ipaDNSAddr->Address.lpSockaddr;
384
385 if (namesrvr.sa->sa_family == AF_INET) {
386 if ((namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_ANY) ||
387 (namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_NONE)) {
388 continue;
389 }
390
391 /* Allocate room for another address, if necessary, else skip. */
392 if (addressesIndex == addressesSize) {
393 const size_t newSize = addressesSize + 4;
394 Address * const newMem =
395 (Address *)ares_realloc(addresses, sizeof(Address) * newSize);
396 if (newMem == NULL) {
397 continue;
398 }
399 addresses = newMem;
400 addressesSize = newSize;
401 }
402
403 addresses[addressesIndex].metric = getBestRouteMetric(
404 &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)),
405 ipaaEntry->Ipv4Metric);
406
407 /* Record insertion index to make qsort stable */
408 addresses[addressesIndex].orig_idx = addressesIndex;
409
410 if (!ares_inet_ntop(AF_INET, &namesrvr.sa4->sin_addr, ipaddr,
411 sizeof(ipaddr))) {
412 continue;
413 }
414 snprintf(addresses[addressesIndex].text,
415 sizeof(addresses[addressesIndex].text), "[%s]:%u", ipaddr,
416 ntohs(namesrvr.sa4->sin_port));
417 ++addressesIndex;
418 } else if (namesrvr.sa->sa_family == AF_INET6) {
419 unsigned int ll_scope = 0;
420 struct ares_addr addr;
421
422 if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any,
423 sizeof(namesrvr.sa6->sin6_addr)) == 0) {
424 continue;
425 }
426
427 /* Allocate room for another address, if necessary, else skip. */
428 if (addressesIndex == addressesSize) {
429 const size_t newSize = addressesSize + 4;
430 Address * const newMem =
431 (Address *)ares_realloc(addresses, sizeof(Address) * newSize);
432 if (newMem == NULL) {
433 continue;
434 }
435 addresses = newMem;
436 addressesSize = newSize;
437 }
438
439 /* See if its link-local */
440 memset(&addr, 0, sizeof(addr));
441 addr.family = AF_INET6;
442 memcpy(&addr.addr.addr6, &namesrvr.sa6->sin6_addr, 16);
443 if (ares__addr_is_linklocal(&addr)) {
444 ll_scope = ipaaEntry->Ipv6IfIndex;
445 }
446
447 addresses[addressesIndex].metric = getBestRouteMetric(
448 &ipaaEntry->Luid, (SOCKADDR_INET *)((void *)(namesrvr.sa)),
449 ipaaEntry->Ipv6Metric);
450
451 /* Record insertion index to make qsort stable */
452 addresses[addressesIndex].orig_idx = addressesIndex;
453
454 if (!ares_inet_ntop(AF_INET6, &namesrvr.sa6->sin6_addr, ipaddr,
455 sizeof(ipaddr))) {
456 continue;
457 }
458
459 if (ll_scope) {
460 snprintf(addresses[addressesIndex].text,
461 sizeof(addresses[addressesIndex].text), "[%s]:%u%%%u",
462 ipaddr, ntohs(namesrvr.sa6->sin6_port), ll_scope);
463 } else {
464 snprintf(addresses[addressesIndex].text,
465 sizeof(addresses[addressesIndex].text), "[%s]:%u", ipaddr,
466 ntohs(namesrvr.sa6->sin6_port));
467 }
468 ++addressesIndex;
469 } else {
470 /* Skip non-IPv4/IPv6 addresses completely. */
471 continue;
472 }
473 }
474 }
475
476 /* Sort all of the textual addresses by their metric (and original index if
477 * metrics are equal). */
478 qsort(addresses, addressesIndex, sizeof(*addresses), compareAddresses);
479
480 /* Join them all into a single string, removing duplicates. */
481 {
482 size_t i;
483 for (i = 0; i < addressesIndex; ++i) {
484 size_t j;
485 /* Look for this address text appearing previously in the results. */
486 for (j = 0; j < i; ++j) {
487 if (strcmp(addresses[j].text, addresses[i].text) == 0) {
488 break;
489 }
490 }
491 /* Iff we didn't emit this address already, emit it now. */
492 if (j == i) {
493 /* Add that to outptr (if we can). */
494 commajoin(outptr, addresses[i].text);
495 }
496 }
497 }
498
499 done:
500 ares_free(addresses);
501
502 if (ipaa) {
503 ares_free(ipaa);
504 }
505
506 if (!*outptr) {
507 return ARES_FALSE;
508 }
509
510 return ARES_TRUE;
511 }
512
513 /*
514 * get_SuffixList_Windows()
515 *
516 * Reads the "DNS Suffix Search List" from registry and writes the list items
517 * whitespace separated to outptr. If the Search List is empty, the
518 * "Primary Dns Suffix" is written to outptr.
519 *
520 * Returns 0 and nullifies *outptr upon inability to return the suffix list.
521 *
522 * Returns 1 and sets *outptr when returning a dynamically allocated string.
523 *
524 * Implementation supports Windows Server 2003 and newer
525 */
get_SuffixList_Windows(char ** outptr)526 static ares_bool_t get_SuffixList_Windows(char **outptr)
527 {
528 HKEY hKey;
529 HKEY hKeyEnum;
530 char keyName[256];
531 DWORD keyNameBuffSize;
532 DWORD keyIdx = 0;
533 char *p = NULL;
534
535 *outptr = NULL;
536
537 if (ares__getplatform() != WIN_NT) {
538 return ARES_FALSE;
539 }
540
541 /* 1. Global DNS Suffix Search List */
542 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hKey) ==
543 ERROR_SUCCESS) {
544 get_REG_SZ(hKey, SEARCHLIST_KEY, outptr);
545 if (get_REG_SZ(hKey, DOMAIN_KEY, &p)) {
546 commajoin(outptr, p);
547 ares_free(p);
548 p = NULL;
549 }
550 RegCloseKey(hKey);
551 }
552
553 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NT_DNSCLIENT, 0, KEY_READ, &hKey) ==
554 ERROR_SUCCESS) {
555 if (get_REG_SZ(hKey, SEARCHLIST_KEY, &p)) {
556 commajoin(outptr, p);
557 ares_free(p);
558 p = NULL;
559 }
560 RegCloseKey(hKey);
561 }
562
563 /* 2. Connection Specific Search List composed of:
564 * a. Primary DNS Suffix */
565 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0, KEY_READ, &hKey) ==
566 ERROR_SUCCESS) {
567 if (get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, &p)) {
568 commajoin(outptr, p);
569 ares_free(p);
570 p = NULL;
571 }
572 RegCloseKey(hKey);
573 }
574
575 /* b. Interface SearchList, Domain, DhcpDomain */
576 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0,
577 KEY_READ, &hKey) == ERROR_SUCCESS) {
578 for (;;) {
579 keyNameBuffSize = sizeof(keyName);
580 if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, 0, NULL,
581 NULL, NULL) != ERROR_SUCCESS) {
582 break;
583 }
584 if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) !=
585 ERROR_SUCCESS) {
586 continue;
587 }
588 /* p can be comma separated (SearchList) */
589 if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p)) {
590 commajoin(outptr, p);
591 ares_free(p);
592 p = NULL;
593 }
594 if (get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p)) {
595 commajoin(outptr, p);
596 ares_free(p);
597 p = NULL;
598 }
599 if (get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) {
600 commajoin(outptr, p);
601 ares_free(p);
602 p = NULL;
603 }
604 RegCloseKey(hKeyEnum);
605 }
606 RegCloseKey(hKey);
607 }
608
609 return *outptr != NULL ? ARES_TRUE : ARES_FALSE;
610 }
611
ares__init_sysconfig_windows(ares_sysconfig_t * sysconfig)612 static ares_status_t ares__init_sysconfig_windows(ares_sysconfig_t *sysconfig)
613 {
614 char *line = NULL;
615 ares_status_t status = ARES_SUCCESS;
616
617 if (get_DNS_Windows(&line)) {
618 status = ares__sconfig_append_fromstr(&sysconfig->sconfig, line, ARES_TRUE);
619 ares_free(line);
620 if (status != ARES_SUCCESS) {
621 goto done;
622 }
623 }
624
625 if (get_SuffixList_Windows(&line)) {
626 sysconfig->domains = ares__strsplit(line, ", ", &sysconfig->ndomains);
627 ares_free(line);
628 if (sysconfig->domains == NULL) {
629 status = ARES_EFILE;
630 }
631 if (status != ARES_SUCCESS) {
632 goto done;
633 }
634 }
635
636 done:
637 return status;
638 }
639 #endif
640
641 #if defined(__MVS__)
ares__init_sysconfig_mvs(ares_sysconfig_t * sysconfig)642 static ares_status_t ares__init_sysconfig_mvs(ares_sysconfig_t *sysconfig)
643 {
644 struct __res_state *res = 0;
645 size_t count4;
646 size_t count6;
647 int i;
648 __STATEEXTIPV6 *v6;
649 arse__llist_t *sconfig = NULL;
650 ares_status_t status;
651
652 if (0 == res) {
653 int rc = res_init();
654 while (rc == -1 && h_errno == TRY_AGAIN) {
655 rc = res_init();
656 }
657 if (rc == -1) {
658 return ARES_ENOMEM;
659 }
660 res = __res();
661 }
662
663 v6 = res->__res_extIPv6;
664 if (res->nscount > 0) {
665 count4 = (size_t)res->nscount;
666 }
667
668 if (v6 && v6->__stat_nscount > 0) {
669 count6 = (size_t)v6->__stat_nscount;
670 } else {
671 count6 = 0;
672 }
673
674 for (i = 0; i < count4; i++) {
675 struct sockaddr_in *addr_in = &(res->nsaddr_list[i]);
676 struct ares_addr addr;
677
678 addr.addr.addr4.s_addr = addr_in->sin_addr.s_addr;
679 addr.family = AF_INET;
680
681 status =
682 ares__sconfig_append(&sysconfig->sconfig, &addr, htons(addr_in->sin_port),
683 htons(addr_in->sin_port), NULL);
684
685 if (status != ARES_SUCCESS) {
686 return status;
687 }
688 }
689
690 for (i = 0; i < count6; i++) {
691 struct sockaddr_in6 *addr_in = &(v6->__stat_nsaddr_list[i]);
692 struct ares_addr addr;
693
694 addr.family = AF_INET6;
695 memcpy(&(addr.addr.addr6), &(addr_in->sin6_addr),
696 sizeof(addr_in->sin6_addr));
697
698 status =
699 ares__sconfig_append(&sysconfig->sconfig, &addr, htons(addr_in->sin_port),
700 htons(addr_in->sin_port), NULL);
701
702 if (status != ARES_SUCCESS) {
703 return status;
704 }
705 }
706
707 return ARES_SUCCESS;
708 }
709 #endif
710
711 #if defined(__riscos__)
ares__init_sysconfig_riscos(ares_sysconfig_t * sysconfig)712 static ares_status_t ares__init_sysconfig_riscos(ares_sysconfig_t *sysconfig)
713 {
714 char *line;
715 ares_status_t status = ARES_SUCCESS;
716
717 /* Under RISC OS, name servers are listed in the
718 system variable Inet$Resolvers, space separated. */
719 line = getenv("Inet$Resolvers");
720 if (line) {
721 char *resolvers = ares_strdup(line);
722 char *pos;
723 char *space;
724
725 if (!resolvers) {
726 return ARES_ENOMEM;
727 }
728
729 pos = resolvers;
730 do {
731 space = strchr(pos, ' ');
732 if (space) {
733 *space = '\0';
734 }
735 status =
736 ares__sconfig_append_fromstr(&sysconfig->sconfig, pos, ARES_TRUE);
737 if (status != ARES_SUCCESS) {
738 break;
739 }
740 pos = space + 1;
741 } while (space);
742
743 ares_free(resolvers);
744 }
745
746 return status;
747 }
748 #endif
749
750 #if defined(WATT32)
ares__init_sysconfig_watt32(ares_sysconfig_t * sysconfig)751 static ares_status_t ares__init_sysconfig_watt32(ares_sysconfig_t *sysconfig)
752 {
753 size_t i;
754 ares_status_t status;
755
756 sock_init();
757
758 for (i = 0; def_nameservers[i]; i++) {
759 struct ares_addr addr;
760
761 addr.family = AF_INET;
762 addr.addr.addr4.s_addr = htonl(def_nameservers[i]);
763
764 status = ares__sconfig_append(&sysconfig->sconfig, &addr, 0, 0, NULL);
765
766 if (status != ARES_SUCCESS) {
767 return status;
768 }
769 }
770
771 return ARES_SUCCESS;
772 }
773 #endif
774
775 #if defined(ANDROID) || defined(__ANDROID__)
ares__init_sysconfig_android(ares_sysconfig_t * sysconfig)776 static ares_status_t ares__init_sysconfig_android(ares_sysconfig_t *sysconfig)
777 {
778 size_t i;
779 char **dns_servers;
780 char *domains;
781 size_t num_servers;
782 ares_status_t status = ARES_EFILE;
783
784 /* Use the Android connectivity manager to get a list
785 * of DNS servers. As of Android 8 (Oreo) net.dns#
786 * system properties are no longer available. Google claims this
787 * improves privacy. Apps now need the ACCESS_NETWORK_STATE
788 * permission and must use the ConnectivityManager which
789 * is Java only. */
790 dns_servers = ares_get_android_server_list(MAX_DNS_PROPERTIES, &num_servers);
791 if (dns_servers != NULL) {
792 for (i = 0; i < num_servers; i++) {
793 status = ares__sconfig_append_fromstr(&sysconfig->sconfig, dns_servers[i],
794 ARES_TRUE);
795 if (status != ARES_SUCCESS) {
796 return status;
797 }
798 }
799 for (i = 0; i < num_servers; i++) {
800 ares_free(dns_servers[i]);
801 }
802 ares_free(dns_servers);
803 }
804
805 domains = ares_get_android_search_domains_list();
806 sysconfig->domains = ares__strsplit(domains, ", ", &sysconfig->ndomains);
807 ares_free(domains);
808
809 # ifdef HAVE___SYSTEM_PROPERTY_GET
810 /* Old way using the system property still in place as
811 * a fallback. Older android versions can still use this.
812 * it's possible for older apps not not have added the new
813 * permission and we want to try to avoid breaking those.
814 *
815 * We'll only run this if we don't have any dns servers
816 * because this will get the same ones (if it works). */
817 if (sysconfig->sconfig == NULL) {
818 char propname[PROP_NAME_MAX];
819 char propvalue[PROP_VALUE_MAX] = "";
820 for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
821 snprintf(propname, sizeof(propname), "%s%u", DNS_PROP_NAME_PREFIX, i);
822 if (__system_property_get(propname, propvalue) < 1) {
823 break;
824 }
825 status =
826 ares__sconfig_append_fromstr(&sysconfig->sconfig, propvalue, ARES_TRUE);
827 if (status != ARES_SUCCESS) {
828 return status;
829 }
830 }
831 }
832 # endif /* HAVE___SYSTEM_PROPERTY_GET */
833
834 return status;
835 }
836 #endif
837
838 #if defined(CARES_USE_LIBRESOLV)
ares__init_sysconfig_libresolv(ares_sysconfig_t * sysconfig)839 static ares_status_t ares__init_sysconfig_libresolv(ares_sysconfig_t *sysconfig)
840 {
841 struct __res_state res;
842 ares_status_t status = ARES_SUCCESS;
843 union res_sockaddr_union addr[MAXNS];
844 int nscount;
845 size_t i;
846 size_t entries = 0;
847 ares__buf_t *ipbuf = NULL;
848
849 memset(&res, 0, sizeof(res));
850
851 if (res_ninit(&res) != 0 || !(res.options & RES_INIT)) {
852 return ARES_EFILE;
853 }
854
855 nscount = res_getservers(&res, addr, MAXNS);
856
857 for (i = 0; i < (size_t)nscount; ++i) {
858 char ipaddr[INET6_ADDRSTRLEN] = "";
859 char *ipstr = NULL;
860 unsigned short port = 0;
861 unsigned int ll_scope = 0;
862
863 sa_family_t family = addr[i].sin.sin_family;
864 if (family == AF_INET) {
865 ares_inet_ntop(family, &addr[i].sin.sin_addr, ipaddr, sizeof(ipaddr));
866 port = ntohs(addr[i].sin.sin_port);
867 } else if (family == AF_INET6) {
868 ares_inet_ntop(family, &addr[i].sin6.sin6_addr, ipaddr, sizeof(ipaddr));
869 port = ntohs(addr[i].sin6.sin6_port);
870 ll_scope = addr[i].sin6.sin6_scope_id;
871 } else {
872 continue;
873 }
874
875
876 /* [ip]:port%iface */
877 ipbuf = ares__buf_create();
878 if (ipbuf == NULL) {
879 status = ARES_ENOMEM;
880 goto done;
881 }
882
883 status = ares__buf_append_str(ipbuf, "[");
884 if (status != ARES_SUCCESS) {
885 goto done;
886 }
887
888 status = ares__buf_append_str(ipbuf, ipaddr);
889 if (status != ARES_SUCCESS) {
890 goto done;
891 }
892
893 status = ares__buf_append_str(ipbuf, "]");
894 if (status != ARES_SUCCESS) {
895 goto done;
896 }
897
898 if (port) {
899 status = ares__buf_append_str(ipbuf, ":");
900 if (status != ARES_SUCCESS) {
901 goto done;
902 }
903 status = ares__buf_append_num_dec(ipbuf, port, 0);
904 if (status != ARES_SUCCESS) {
905 goto done;
906 }
907 }
908
909 if (ll_scope) {
910 status = ares__buf_append_str(ipbuf, "%");
911 if (status != ARES_SUCCESS) {
912 goto done;
913 }
914 status = ares__buf_append_num_dec(ipbuf, ll_scope, 0);
915 if (status != ARES_SUCCESS) {
916 goto done;
917 }
918 }
919
920 ipstr = ares__buf_finish_str(ipbuf, NULL);
921 ipbuf = NULL;
922 if (ipstr == NULL) {
923 status = ARES_ENOMEM;
924 goto done;
925 }
926
927 status =
928 ares__sconfig_append_fromstr(&sysconfig->sconfig, ipstr, ARES_TRUE);
929
930 ares_free(ipstr);
931 if (status != ARES_SUCCESS) {
932 goto done;
933 }
934 }
935
936 while ((entries < MAXDNSRCH) && res.dnsrch[entries]) {
937 entries++;
938 }
939
940 if (entries) {
941 sysconfig->domains = ares_malloc_zero(entries * sizeof(char *));
942 if (sysconfig->domains == NULL) {
943 status = ARES_ENOMEM;
944 goto done;
945 } else {
946 sysconfig->ndomains = entries;
947 for (i = 0; i < sysconfig->ndomains; i++) {
948 sysconfig->domains[i] = ares_strdup(res.dnsrch[i]);
949 if (sysconfig->domains[i] == NULL) {
950 status = ARES_ENOMEM;
951 goto done;
952 }
953 }
954 }
955 }
956
957 if (res.ndots > 0) {
958 sysconfig->ndots = (size_t)res.ndots;
959 }
960 if (res.retry > 0) {
961 sysconfig->tries = (size_t)res.retry;
962 }
963 if (res.options & RES_ROTATE) {
964 sysconfig->rotate = ARES_TRUE;
965 }
966
967 if (res.retrans > 0) {
968 if (res.retrans > 0) {
969 sysconfig->timeout_ms = (unsigned int)res.retrans * 1000;
970 }
971 # ifdef __APPLE__
972 if (res.retry >= 0) {
973 sysconfig->timeout_ms /=
974 ((unsigned int)res.retry + 1) *
975 (unsigned int)(res.nscount > 0 ? res.nscount : 1);
976 }
977 # endif
978 }
979
980 done:
981 ares__buf_destroy(ipbuf);
982 res_ndestroy(&res);
983 return status;
984 }
985 #endif
986
ares_sysconfig_free(ares_sysconfig_t * sysconfig)987 static void ares_sysconfig_free(ares_sysconfig_t *sysconfig)
988 {
989 ares__llist_destroy(sysconfig->sconfig);
990 ares__strsplit_free(sysconfig->domains, sysconfig->ndomains);
991 ares_free(sysconfig->sortlist);
992 ares_free(sysconfig->lookups);
993 memset(sysconfig, 0, sizeof(*sysconfig));
994 }
995
ares_sysconfig_apply(ares_channel_t * channel,const ares_sysconfig_t * sysconfig)996 static ares_status_t ares_sysconfig_apply(ares_channel_t *channel,
997 const ares_sysconfig_t *sysconfig)
998 {
999 ares_status_t status;
1000
1001 if (sysconfig->sconfig && !(channel->optmask & ARES_OPT_SERVERS)) {
1002 status = ares__servers_update(channel, sysconfig->sconfig, ARES_FALSE);
1003 if (status != ARES_SUCCESS) {
1004 return status;
1005 }
1006 }
1007
1008 if (sysconfig->domains && !(channel->optmask & ARES_OPT_DOMAINS)) {
1009 /* Make sure we duplicate first then replace so even if there is
1010 * ARES_ENOMEM, the channel stays in a good state */
1011 char **temp =
1012 ares__strsplit_duplicate(sysconfig->domains, sysconfig->ndomains);
1013 if (temp == NULL) {
1014 return ARES_ENOMEM;
1015 }
1016
1017 ares__strsplit_free(channel->domains, channel->ndomains);
1018 channel->domains = temp;
1019 channel->ndomains = sysconfig->ndomains;
1020 }
1021
1022 if (sysconfig->lookups && !(channel->optmask & ARES_OPT_LOOKUPS)) {
1023 char *temp = ares_strdup(sysconfig->lookups);
1024 if (temp == NULL) {
1025 return ARES_ENOMEM;
1026 }
1027
1028 ares_free(channel->lookups);
1029 channel->lookups = temp;
1030 }
1031
1032 if (sysconfig->sortlist && !(channel->optmask & ARES_OPT_SORTLIST)) {
1033 struct apattern *temp =
1034 ares_malloc(sizeof(*channel->sortlist) * sysconfig->nsortlist);
1035 if (temp == NULL) {
1036 return ARES_ENOMEM;
1037 }
1038 memcpy(temp, sysconfig->sortlist,
1039 sizeof(*channel->sortlist) * sysconfig->nsortlist);
1040
1041 ares_free(channel->sortlist);
1042 channel->sortlist = temp;
1043 channel->nsort = sysconfig->nsortlist;
1044 }
1045
1046 if (sysconfig->ndots && !(channel->optmask & ARES_OPT_NDOTS)) {
1047 channel->ndots = sysconfig->ndots;
1048 }
1049
1050 if (sysconfig->tries && !(channel->optmask & ARES_OPT_TRIES)) {
1051 channel->tries = sysconfig->tries;
1052 }
1053
1054 if (sysconfig->timeout_ms && !(channel->optmask & ARES_OPT_TIMEOUTMS)) {
1055 channel->timeout = sysconfig->timeout_ms;
1056 }
1057
1058 if (!(channel->optmask & (ARES_OPT_ROTATE | ARES_OPT_NOROTATE))) {
1059 channel->rotate = sysconfig->rotate;
1060 }
1061
1062 return ARES_SUCCESS;
1063 }
1064
ares__init_by_sysconfig(ares_channel_t * channel)1065 ares_status_t ares__init_by_sysconfig(ares_channel_t *channel)
1066 {
1067 ares_status_t status;
1068 ares_sysconfig_t sysconfig;
1069
1070 memset(&sysconfig, 0, sizeof(sysconfig));
1071
1072 #ifdef _WIN32
1073 status = ares__init_sysconfig_windows(&sysconfig);
1074 #elif defined(__MVS__)
1075 status = ares__init_sysconfig_mvs(&sysconfig);
1076 #elif defined(__riscos__)
1077 status = ares__init_sysconfig_riscos(&sysconfig);
1078 #elif defined(WATT32)
1079 status = ares__init_sysconfig_watt32(&sysconfig);
1080 #elif defined(ANDROID) || defined(__ANDROID__)
1081 status = ares__init_sysconfig_android(&sysconfig);
1082 #elif defined(CARES_USE_LIBRESOLV)
1083 status = ares__init_sysconfig_libresolv(&sysconfig);
1084 #else
1085 status = ares__init_sysconfig_files(channel, &sysconfig);
1086 #endif
1087
1088 if (status != ARES_SUCCESS) {
1089 goto done;
1090 }
1091
1092 /* Environment is supposed to override sysconfig */
1093 status = ares__init_by_environment(&sysconfig);
1094 if (status != ARES_SUCCESS) {
1095 goto done;
1096 }
1097
1098 status = ares_sysconfig_apply(channel, &sysconfig);
1099 if (status != ARES_SUCCESS) {
1100 goto done;
1101 }
1102
1103 done:
1104 ares_sysconfig_free(&sysconfig);
1105
1106 return status;
1107 }
1108