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