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_private.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 #if defined(ANDROID) || defined(__ANDROID__)
47 # include <sys/system_properties.h>
48 # include "ares_android.h"
49 /* From the Bionic sources */
50 # define DNS_PROP_NAME_PREFIX "net.dns"
51 # define MAX_DNS_PROPERTIES 8
52 #endif
53
54 #if defined(CARES_USE_LIBRESOLV)
55 # include <resolv.h>
56 #endif
57
58 #include "ares_inet_net_pton.h"
59
60 #if OHOS_DNS_PROXY_BY_NETSYS
61 #define MAX_SERVER_NUM 8
62 #define MAX_SERVER_LENGTH 50
63
64 struct resolv_config {
65 int32_t error;
66 int32_t timeout_ms;
67 uint32_t retry_count;
68 uint32_t non_public;
69 char nameservers[MAX_SERVER_NUM][MAX_SERVER_LENGTH + 1];
70 };
71
72 int32_t NetSysGetResolvConfExt(uint16_t netid, struct resolv_config *config);
73
ares_init_sysconfig_netsys(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)74 static ares_status_t ares_init_sysconfig_netsys(const ares_channel_t *channel,
75 ares_sysconfig_t *sysconfig)
76 {
77 struct resolv_config config = {0};
78 int ret = 0;
79 int netid = 0;
80 ares_status_t status = ARES_EFILE;
81
82 ret = NetSysGetResolvConfExt(netid, &config);
83 if (ret < 0) {
84 return ARES_ENONAME;
85 }
86 for (int i = 0; i < MAX_SERVER_NUM; ++i) {
87 if (config.nameservers[i] == NULL || config.nameservers[i][0] == 0) {
88 continue;
89 }
90 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig,
91 config.nameservers[i], ARES_TRUE);
92 if (status != ARES_SUCCESS) {
93 return status;
94 }
95 }
96 return status;
97 }
98 #endif
99
100 #if defined(__MVS__)
ares_init_sysconfig_mvs(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)101 static ares_status_t ares_init_sysconfig_mvs(const ares_channel_t *channel,
102 ares_sysconfig_t *sysconfig)
103 {
104 struct __res_state *res = 0;
105 size_t count4;
106 size_t count6;
107 int i;
108 __STATEEXTIPV6 *v6;
109 arse__llist_t *sconfig = NULL;
110 ares_status_t status;
111
112 if (0 == res) {
113 int rc = res_init();
114 while (rc == -1 && h_errno == TRY_AGAIN) {
115 rc = res_init();
116 }
117 if (rc == -1) {
118 return ARES_ENOMEM;
119 }
120 res = __res();
121 }
122
123 v6 = res->__res_extIPv6;
124 if (res->nscount > 0) {
125 count4 = (size_t)res->nscount;
126 }
127
128 if (v6 && v6->__stat_nscount > 0) {
129 count6 = (size_t)v6->__stat_nscount;
130 } else {
131 count6 = 0;
132 }
133
134 for (i = 0; i < count4; i++) {
135 struct sockaddr_in *addr_in = &(res->nsaddr_list[i]);
136 struct ares_addr addr;
137
138 addr.addr.addr4.s_addr = addr_in->sin_addr.s_addr;
139 addr.family = AF_INET;
140
141 status = ares_sconfig_append(channel, &sysconfig->sconfig, &addr,
142 htons(addr_in->sin_port),
143 htons(addr_in->sin_port), NULL);
144
145 if (status != ARES_SUCCESS) {
146 return status;
147 }
148 }
149
150 for (i = 0; i < count6; i++) {
151 struct sockaddr_in6 *addr_in = &(v6->__stat_nsaddr_list[i]);
152 struct ares_addr addr;
153
154 addr.family = AF_INET6;
155 memcpy(&(addr.addr.addr6), &(addr_in->sin6_addr),
156 sizeof(addr_in->sin6_addr));
157
158 status = ares_sconfig_append(channel, &sysconfig->sconfig, &addr,
159 htons(addr_in->sin_port),
160 htons(addr_in->sin_port), NULL);
161
162 if (status != ARES_SUCCESS) {
163 return status;
164 }
165 }
166
167 return ARES_SUCCESS;
168 }
169 #endif
170
171 #if defined(__riscos__)
ares_init_sysconfig_riscos(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)172 static ares_status_t ares_init_sysconfig_riscos(const ares_channel_t *channel,
173 ares_sysconfig_t *sysconfig)
174 {
175 char *line;
176 ares_status_t status = ARES_SUCCESS;
177
178 /* Under RISC OS, name servers are listed in the
179 system variable Inet$Resolvers, space separated. */
180 line = getenv("Inet$Resolvers");
181 if (line) {
182 char *resolvers = ares_strdup(line);
183 char *pos;
184 char *space;
185
186 if (!resolvers) {
187 return ARES_ENOMEM;
188 }
189
190 pos = resolvers;
191 do {
192 space = strchr(pos, ' ');
193 if (space) {
194 *space = '\0';
195 }
196 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, pos,
197 ARES_TRUE);
198 if (status != ARES_SUCCESS) {
199 break;
200 }
201 pos = space + 1;
202 } while (space);
203
204 ares_free(resolvers);
205 }
206
207 return status;
208 }
209 #endif
210
211 #if defined(WATT32)
ares_init_sysconfig_watt32(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)212 static ares_status_t ares_init_sysconfig_watt32(const ares_channel_t *channel,
213 ares_sysconfig_t *sysconfig)
214 {
215 size_t i;
216 ares_status_t status;
217
218 sock_init();
219
220 for (i = 0; def_nameservers[i]; i++) {
221 struct ares_addr addr;
222
223 addr.family = AF_INET;
224 addr.addr.addr4.s_addr = htonl(def_nameservers[i]);
225
226 status =
227 ares_sconfig_append(channel, &sysconfig->sconfig, &addr, 0, 0, NULL);
228
229 if (status != ARES_SUCCESS) {
230 return status;
231 }
232 }
233
234 return ARES_SUCCESS;
235 }
236 #endif
237
238 #if defined(ANDROID) || defined(__ANDROID__)
ares_init_sysconfig_android(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)239 static ares_status_t ares_init_sysconfig_android(const ares_channel_t *channel,
240 ares_sysconfig_t *sysconfig)
241 {
242 size_t i;
243 char **dns_servers;
244 char *domains;
245 size_t num_servers;
246 ares_status_t status = ARES_EFILE;
247
248 /* Use the Android connectivity manager to get a list
249 * of DNS servers. As of Android 8 (Oreo) net.dns#
250 * system properties are no longer available. Google claims this
251 * improves privacy. Apps now need the ACCESS_NETWORK_STATE
252 * permission and must use the ConnectivityManager which
253 * is Java only. */
254 dns_servers = ares_get_android_server_list(MAX_DNS_PROPERTIES, &num_servers);
255 if (dns_servers != NULL) {
256 for (i = 0; i < num_servers; i++) {
257 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig,
258 dns_servers[i], ARES_TRUE);
259 if (status != ARES_SUCCESS) {
260 return status;
261 }
262 }
263 for (i = 0; i < num_servers; i++) {
264 ares_free(dns_servers[i]);
265 }
266 ares_free(dns_servers);
267 }
268
269 domains = ares_get_android_search_domains_list();
270 sysconfig->domains = ares_strsplit(domains, ", ", &sysconfig->ndomains);
271 ares_free(domains);
272
273 # ifdef HAVE___SYSTEM_PROPERTY_GET
274 /* Old way using the system property still in place as
275 * a fallback. Older android versions can still use this.
276 * it's possible for older apps not not have added the new
277 * permission and we want to try to avoid breaking those.
278 *
279 * We'll only run this if we don't have any dns servers
280 * because this will get the same ones (if it works). */
281 if (sysconfig->sconfig == NULL) {
282 char propname[PROP_NAME_MAX];
283 char propvalue[PROP_VALUE_MAX] = "";
284 for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
285 snprintf(propname, sizeof(propname), "%s%zu", DNS_PROP_NAME_PREFIX, i);
286 if (__system_property_get(propname, propvalue) < 1) {
287 break;
288 }
289 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig,
290 propvalue, ARES_TRUE);
291 if (status != ARES_SUCCESS) {
292 return status;
293 }
294 }
295 }
296 # endif /* HAVE___SYSTEM_PROPERTY_GET */
297
298 return status;
299 }
300 #endif
301
302 #if defined(__QNX__)
303 static ares_status_t
ares_init_sysconfig_qnx(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)304 ares_init_sysconfig_qnx(const ares_channel_t *channel,
305 ares_sysconfig_t *sysconfig)
306 {
307 /* QNX:
308 * 1. use confstr(_CS_RESOLVE, ...) as primary resolv.conf data, replacing
309 * "_" with " ". If that is empty, then do normal /etc/resolv.conf
310 * processing.
311 * 2. We want to process /etc/nsswitch.conf as normal.
312 * 3. if confstr(_CS_DOMAIN, ...) this is the domain name. Use this as
313 * preference over anything else found.
314 */
315 ares_buf_t *buf = ares_buf_create();
316 unsigned char *data = NULL;
317 size_t data_size = 0;
318 ares_bool_t process_resolvconf = ARES_TRUE;
319 ares_status_t status = ARES_SUCCESS;
320
321 /* Prefer confstr(_CS_RESOLVE, ...) */
322 buf = ares_buf_create();
323 if (buf == NULL) {
324 status = ARES_ENOMEM;
325 goto done;
326 }
327
328 data_size = 1024;
329 data = ares_buf_append_start(buf, &data_size);
330 if (data == NULL) {
331 status = ARES_ENOMEM;
332 goto done;
333 }
334
335 data_size = confstr(_CS_RESOLVE, (char *)data, data_size);
336 if (data_size > 1) {
337 /* confstr returns byte for NULL terminator, strip */
338 data_size--;
339
340 ares_buf_append_finish(buf, data_size);
341 /* Its odd, this uses _ instead of " " between keywords, otherwise the
342 * format is the same as resolv.conf, replace. */
343 ares_buf_replace(buf, (const unsigned char *)"_", 1,
344 (const unsigned char *)" ", 1);
345
346 status = ares_sysconfig_process_buf(channel, sysconfig, buf,
347 ares_sysconfig_parse_resolv_line);
348 if (status != ARES_SUCCESS) {
349 /* ENOMEM is really the only error we'll get here */
350 goto done;
351 }
352
353 /* don't read resolv.conf if we processed *any* nameservers */
354 if (ares_llist_len(sysconfig->sconfig) != 0) {
355 process_resolvconf = ARES_FALSE;
356 }
357 }
358
359 /* Process files */
360 status = ares_init_sysconfig_files(channel, sysconfig, process_resolvconf);
361 if (status != ARES_SUCCESS) {
362 goto done;
363 }
364
365 /* Read confstr(_CS_DOMAIN, ...), but if we had a search path specified with
366 * more than one domain, lets prefer that instead. Its not exactly clear
367 * the best way to handle this. */
368 if (sysconfig->ndomains <= 1) {
369 char domain[256];
370 size_t domain_len;
371
372 domain_len = confstr(_CS_DOMAIN, domain, sizeof(domain_len));
373 if (domain_len != 0) {
374 ares_strsplit_free(sysconfig->domains, sysconfig->ndomains);
375 sysconfig->domains = ares_strsplit(domain, ", ", &sysconfig->ndomains);
376 if (sysconfig->domains == NULL) {
377 status = ARES_ENOMEM;
378 goto done;
379 }
380 }
381 }
382
383 done:
384 ares_buf_destroy(buf);
385
386 return status;
387 }
388 #endif
389
390 #if defined(CARES_USE_LIBRESOLV)
391 static ares_status_t
ares_init_sysconfig_libresolv(const ares_channel_t * channel,ares_sysconfig_t * sysconfig)392 ares_init_sysconfig_libresolv(const ares_channel_t *channel,
393 ares_sysconfig_t *sysconfig)
394 {
395 struct __res_state res;
396 ares_status_t status = ARES_SUCCESS;
397 union res_sockaddr_union addr[MAXNS];
398 int nscount;
399 size_t i;
400 size_t entries = 0;
401 ares_buf_t *ipbuf = NULL;
402
403 memset(&res, 0, sizeof(res));
404
405 if (res_ninit(&res) != 0 || !(res.options & RES_INIT)) {
406 return ARES_EFILE;
407 }
408
409 nscount = res_getservers(&res, addr, MAXNS);
410
411 for (i = 0; i < (size_t)nscount; ++i) {
412 char ipaddr[INET6_ADDRSTRLEN] = "";
413 char *ipstr = NULL;
414 unsigned short port = 0;
415 unsigned int ll_scope = 0;
416
417 sa_family_t family = addr[i].sin.sin_family;
418 if (family == AF_INET) {
419 ares_inet_ntop(family, &addr[i].sin.sin_addr, ipaddr, sizeof(ipaddr));
420 port = ntohs(addr[i].sin.sin_port);
421 } else if (family == AF_INET6) {
422 ares_inet_ntop(family, &addr[i].sin6.sin6_addr, ipaddr, sizeof(ipaddr));
423 port = ntohs(addr[i].sin6.sin6_port);
424 ll_scope = addr[i].sin6.sin6_scope_id;
425 } else {
426 continue;
427 }
428
429
430 /* [ip]:port%iface */
431 ipbuf = ares_buf_create();
432 if (ipbuf == NULL) {
433 status = ARES_ENOMEM;
434 goto done;
435 }
436
437 status = ares_buf_append_str(ipbuf, "[");
438 if (status != ARES_SUCCESS) {
439 goto done;
440 }
441
442 status = ares_buf_append_str(ipbuf, ipaddr);
443 if (status != ARES_SUCCESS) {
444 goto done;
445 }
446
447 status = ares_buf_append_str(ipbuf, "]");
448 if (status != ARES_SUCCESS) {
449 goto done;
450 }
451
452 if (port) {
453 status = ares_buf_append_str(ipbuf, ":");
454 if (status != ARES_SUCCESS) {
455 goto done;
456 }
457 status = ares_buf_append_num_dec(ipbuf, port, 0);
458 if (status != ARES_SUCCESS) {
459 goto done;
460 }
461 }
462
463 if (ll_scope) {
464 status = ares_buf_append_str(ipbuf, "%");
465 if (status != ARES_SUCCESS) {
466 goto done;
467 }
468 status = ares_buf_append_num_dec(ipbuf, ll_scope, 0);
469 if (status != ARES_SUCCESS) {
470 goto done;
471 }
472 }
473
474 ipstr = ares_buf_finish_str(ipbuf, NULL);
475 ipbuf = NULL;
476 if (ipstr == NULL) {
477 status = ARES_ENOMEM;
478 goto done;
479 }
480
481 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, ipstr,
482 ARES_TRUE);
483
484 ares_free(ipstr);
485 if (status != ARES_SUCCESS) {
486 goto done;
487 }
488 }
489
490 while ((entries < MAXDNSRCH) && res.dnsrch[entries]) {
491 entries++;
492 }
493
494 if (entries) {
495 sysconfig->domains = ares_malloc_zero(entries * sizeof(char *));
496 if (sysconfig->domains == NULL) {
497 status = ARES_ENOMEM;
498 goto done;
499 } else {
500 sysconfig->ndomains = entries;
501 for (i = 0; i < sysconfig->ndomains; i++) {
502 sysconfig->domains[i] = ares_strdup(res.dnsrch[i]);
503 if (sysconfig->domains[i] == NULL) {
504 status = ARES_ENOMEM;
505 goto done;
506 }
507 }
508 }
509 }
510
511 if (res.ndots >= 0) {
512 sysconfig->ndots = (size_t)res.ndots;
513 }
514 /* Apple does not allow configuration of retry, so this is a static dummy
515 * value, ignore */
516 # ifndef __APPLE__
517 if (res.retry > 0) {
518 sysconfig->tries = (size_t)res.retry;
519 }
520 # endif
521 if (res.options & RES_ROTATE) {
522 sysconfig->rotate = ARES_TRUE;
523 }
524
525 if (res.retrans > 0) {
526 /* Apple does not allow configuration of retrans, so this is a dummy value
527 * that is extremely high (5s) */
528 # ifndef __APPLE__
529 if (res.retrans > 0) {
530 sysconfig->timeout_ms = (unsigned int)res.retrans * 1000;
531 }
532 # endif
533 }
534
535 done:
536 ares_buf_destroy(ipbuf);
537 res_ndestroy(&res);
538 return status;
539 }
540 #endif
541
ares_sysconfig_free(ares_sysconfig_t * sysconfig)542 static void ares_sysconfig_free(ares_sysconfig_t *sysconfig)
543 {
544 ares_llist_destroy(sysconfig->sconfig);
545 ares_strsplit_free(sysconfig->domains, sysconfig->ndomains);
546 ares_free(sysconfig->sortlist);
547 ares_free(sysconfig->lookups);
548 memset(sysconfig, 0, sizeof(*sysconfig));
549 }
550
ares_sysconfig_apply(ares_channel_t * channel,const ares_sysconfig_t * sysconfig)551 static ares_status_t ares_sysconfig_apply(ares_channel_t *channel,
552 const ares_sysconfig_t *sysconfig)
553 {
554 ares_status_t status;
555
556 if (sysconfig->sconfig && !(channel->optmask & ARES_OPT_SERVERS)) {
557 status = ares_servers_update(channel, sysconfig->sconfig, ARES_FALSE);
558 if (status != ARES_SUCCESS) {
559 return status;
560 }
561 }
562
563 if (sysconfig->domains && !(channel->optmask & ARES_OPT_DOMAINS)) {
564 /* Make sure we duplicate first then replace so even if there is
565 * ARES_ENOMEM, the channel stays in a good state */
566 char **temp =
567 ares_strsplit_duplicate(sysconfig->domains, sysconfig->ndomains);
568 if (temp == NULL) {
569 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
570 }
571
572 ares_strsplit_free(channel->domains, channel->ndomains);
573 channel->domains = temp;
574 channel->ndomains = sysconfig->ndomains;
575 }
576
577 if (sysconfig->lookups && !(channel->optmask & ARES_OPT_LOOKUPS)) {
578 char *temp = ares_strdup(sysconfig->lookups);
579 if (temp == NULL) {
580 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
581 }
582
583 ares_free(channel->lookups);
584 channel->lookups = temp;
585 }
586
587 if (sysconfig->sortlist && !(channel->optmask & ARES_OPT_SORTLIST)) {
588 struct apattern *temp =
589 ares_malloc(sizeof(*channel->sortlist) * sysconfig->nsortlist);
590 if (temp == NULL) {
591 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
592 }
593 memcpy(temp, sysconfig->sortlist,
594 sizeof(*channel->sortlist) * sysconfig->nsortlist);
595
596 ares_free(channel->sortlist);
597 channel->sortlist = temp;
598 channel->nsort = sysconfig->nsortlist;
599 }
600
601 if (!(channel->optmask & ARES_OPT_NDOTS)) {
602 channel->ndots = sysconfig->ndots;
603 }
604
605 if (sysconfig->tries && !(channel->optmask & ARES_OPT_TRIES)) {
606 channel->tries = sysconfig->tries;
607 }
608
609 if (sysconfig->timeout_ms && !(channel->optmask & ARES_OPT_TIMEOUTMS)) {
610 channel->timeout = sysconfig->timeout_ms;
611 }
612
613 if (!(channel->optmask & (ARES_OPT_ROTATE | ARES_OPT_NOROTATE))) {
614 channel->rotate = sysconfig->rotate;
615 }
616
617 if (sysconfig->usevc) {
618 channel->flags |= ARES_FLAG_USEVC;
619 }
620
621 return ARES_SUCCESS;
622 }
623
ares_init_by_sysconfig(ares_channel_t * channel)624 ares_status_t ares_init_by_sysconfig(ares_channel_t *channel)
625 {
626 ares_status_t status;
627 ares_sysconfig_t sysconfig;
628
629 memset(&sysconfig, 0, sizeof(sysconfig));
630 sysconfig.ndots = 1; /* Default value if not otherwise set */
631
632 #if defined(USE_WINSOCK)
633 status = ares_init_sysconfig_windows(channel, &sysconfig);
634 #elif defined(__MVS__)
635 status = ares_init_sysconfig_mvs(channel, &sysconfig);
636 #elif defined(__riscos__)
637 status = ares_init_sysconfig_riscos(channel, &sysconfig);
638 #elif defined(WATT32)
639 status = ares_init_sysconfig_watt32(channel, &sysconfig);
640 #elif defined(ANDROID) || defined(__ANDROID__)
641 status = ares_init_sysconfig_android(channel, &sysconfig);
642 #elif defined(__APPLE__)
643 status = ares_init_sysconfig_macos(channel, &sysconfig);
644 #elif defined(CARES_USE_LIBRESOLV)
645 status = ares_init_sysconfig_libresolv(channel, &sysconfig);
646 #elif defined(__QNX__)
647 status = ares_init_sysconfig_qnx(channel, &sysconfig);
648 #elif OHOS_DNS_PROXY_BY_NETSYS
649 status = ares_init_sysconfig_netsys(channel, &sysconfig);
650 #else
651 status = ares_init_sysconfig_files(channel, &sysconfig, ARES_TRUE);
652 #endif
653
654 if (status != ARES_SUCCESS) {
655 goto done;
656 }
657
658 /* Environment is supposed to override sysconfig */
659 status = ares_init_by_environment(&sysconfig);
660 if (status != ARES_SUCCESS) {
661 goto done;
662 }
663
664 /* Lock when applying the configuration to the channel. Don't need to
665 * lock prior to this. */
666
667 ares_channel_lock(channel);
668
669 status = ares_sysconfig_apply(channel, &sysconfig);
670 ares_channel_unlock(channel);
671
672 if (status != ARES_SUCCESS) {
673 goto done;
674 }
675
676 done:
677 ares_sysconfig_free(&sysconfig);
678
679 return status;
680 }
681