• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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