1 /* MIT License
2 *
3 * Copyright (c) 1998 Massachusetts Institute of Technology
4 * Copyright (c) 2008 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_ARPA_INET_H
31 # include <arpa/inet.h>
32 #endif
33
34 #include "ares.h"
35 #include "ares_data.h"
36 #include "ares_inet_net_pton.h"
37 #include "ares_private.h"
38
ares_destroy_options(struct ares_options *options)39 void ares_destroy_options(struct ares_options *options)
40 {
41 int i;
42
43 ares_free(options->servers);
44
45 for (i = 0; options->domains && i < options->ndomains; i++) {
46 ares_free(options->domains[i]);
47 }
48
49 ares_free(options->domains);
50 ares_free(options->sortlist);
51 ares_free(options->lookups);
52 ares_free(options->resolvconf_path);
53 ares_free(options->hosts_path);
54 }
55
ares_save_opt_servers(ares_channel_t *channel, int *nservers)56 static struct in_addr *ares_save_opt_servers(ares_channel_t *channel,
57 int *nservers)
58 {
59 ares__slist_node_t *snode;
60 struct in_addr *out =
61 ares_malloc_zero(ares__slist_len(channel->servers) * sizeof(*out));
62
63 *nservers = 0;
64
65 if (out == NULL) {
66 return NULL;
67 }
68
69 for (snode = ares__slist_node_first(channel->servers); snode != NULL;
70 snode = ares__slist_node_next(snode)) {
71 const struct server_state *server = ares__slist_node_val(snode);
72
73 if (server->addr.family != AF_INET) {
74 continue;
75 }
76
77 memcpy(&out[*nservers], &server->addr.addr.addr4, sizeof(*out));
78 (*nservers)++;
79 }
80
81 return out;
82 }
83
84 /* Save options from initialized channel */
ares_save_options(ares_channel_t *channel, struct ares_options *options, int *optmask)85 int ares_save_options(ares_channel_t *channel, struct ares_options *options,
86 int *optmask)
87 {
88 size_t i;
89
90 /* NOTE: We can't zero the whole thing out, this is because the size of the
91 * struct ares_options changes over time, so if someone compiled
92 * with an older version, their struct size might be smaller and
93 * we might overwrite their memory! So using the optmask is critical
94 * here, as they could have only set options they knew about.
95 *
96 * Unfortunately ares_destroy_options() doesn't take an optmask, so
97 * there are a few pointers we *must* zero out otherwise we won't
98 * know if they were allocated or not
99 */
100 options->servers = NULL;
101 options->domains = NULL;
102 options->sortlist = NULL;
103 options->lookups = NULL;
104 options->resolvconf_path = NULL;
105 options->hosts_path = NULL;
106
107 if (!ARES_CONFIG_CHECK(channel)) {
108 return ARES_ENODATA;
109 }
110
111 if (channel->optmask & ARES_OPT_FLAGS) {
112 options->flags = (int)channel->flags;
113 }
114
115 /* We convert ARES_OPT_TIMEOUT to ARES_OPT_TIMEOUTMS in
116 * ares__init_by_options() */
117 if (channel->optmask & ARES_OPT_TIMEOUTMS) {
118 options->timeout = (int)channel->timeout;
119 }
120
121 if (channel->optmask & ARES_OPT_TRIES) {
122 options->tries = (int)channel->tries;
123 }
124
125 if (channel->optmask & ARES_OPT_NDOTS) {
126 options->ndots = (int)channel->ndots;
127 }
128
129 if (channel->optmask & ARES_OPT_MAXTIMEOUTMS) {
130 options->maxtimeout = (int)channel->maxtimeout;
131 }
132
133 if (channel->optmask & ARES_OPT_UDP_PORT) {
134 options->udp_port = channel->udp_port;
135 }
136 if (channel->optmask & ARES_OPT_TCP_PORT) {
137 options->tcp_port = channel->tcp_port;
138 }
139
140 if (channel->optmask & ARES_OPT_SOCK_STATE_CB) {
141 options->sock_state_cb = channel->sock_state_cb;
142 options->sock_state_cb_data = channel->sock_state_cb_data;
143 }
144
145 if (channel->optmask & ARES_OPT_SERVERS) {
146 options->servers = ares_save_opt_servers(channel, &options->nservers);
147 if (options->servers == NULL) {
148 return ARES_ENOMEM;
149 }
150 }
151
152 if (channel->optmask & ARES_OPT_DOMAINS) {
153 options->domains = NULL;
154 if (channel->ndomains) {
155 options->domains = ares_malloc(channel->ndomains * sizeof(char *));
156 if (!options->domains) {
157 return ARES_ENOMEM;
158 }
159
160 for (i = 0; i < channel->ndomains; i++) {
161 options->domains[i] = ares_strdup(channel->domains[i]);
162 if (!options->domains[i]) {
163 options->ndomains = (int)i;
164 return ARES_ENOMEM;
165 }
166 }
167 }
168 options->ndomains = (int)channel->ndomains;
169 }
170
171 if (channel->optmask & ARES_OPT_LOOKUPS) {
172 options->lookups = ares_strdup(channel->lookups);
173 if (!options->lookups && channel->lookups) {
174 return ARES_ENOMEM;
175 }
176 }
177
178 if (channel->optmask & ARES_OPT_SORTLIST) {
179 options->sortlist = NULL;
180 if (channel->nsort) {
181 options->sortlist = ares_malloc(channel->nsort * sizeof(struct apattern));
182 if (!options->sortlist) {
183 return ARES_ENOMEM;
184 }
185 for (i = 0; i < channel->nsort; i++) {
186 options->sortlist[i] = channel->sortlist[i];
187 }
188 }
189 options->nsort = (int)channel->nsort;
190 }
191
192 if (channel->optmask & ARES_OPT_RESOLVCONF) {
193 options->resolvconf_path = ares_strdup(channel->resolvconf_path);
194 if (!options->resolvconf_path) {
195 return ARES_ENOMEM;
196 }
197 }
198
199 if (channel->optmask & ARES_OPT_HOSTS_FILE) {
200 options->hosts_path = ares_strdup(channel->hosts_path);
201 if (!options->hosts_path) {
202 return ARES_ENOMEM;
203 }
204 }
205
206 if (channel->optmask & ARES_OPT_SOCK_SNDBUF &&
207 channel->socket_send_buffer_size > 0) {
208 options->socket_send_buffer_size = channel->socket_send_buffer_size;
209 }
210
211 if (channel->optmask & ARES_OPT_SOCK_RCVBUF &&
212 channel->socket_receive_buffer_size > 0) {
213 options->socket_receive_buffer_size = channel->socket_receive_buffer_size;
214 }
215
216 if (channel->optmask & ARES_OPT_EDNSPSZ) {
217 options->ednspsz = (int)channel->ednspsz;
218 }
219
220 if (channel->optmask & ARES_OPT_UDP_MAX_QUERIES) {
221 options->udp_max_queries = (int)channel->udp_max_queries;
222 }
223
224 if (channel->optmask & ARES_OPT_QUERY_CACHE) {
225 options->qcache_max_ttl = channel->qcache_max_ttl;
226 }
227
228 if (channel->optmask & ARES_OPT_EVENT_THREAD) {
229 options->evsys = channel->evsys;
230 }
231
232 *optmask = (int)channel->optmask;
233
234 return ARES_SUCCESS;
235 }
236
ares__init_options_servers(ares_channel_t *channel, const struct in_addr *servers, size_t nservers)237 static ares_status_t ares__init_options_servers(ares_channel_t *channel,
238 const struct in_addr *servers,
239 size_t nservers)
240 {
241 ares__llist_t *slist = NULL;
242 ares_status_t status;
243
244 status = ares_in_addr_to_server_config_llist(servers, nservers, &slist);
245 if (status != ARES_SUCCESS) {
246 return status;
247 }
248
249 status = ares__servers_update(channel, slist, ARES_TRUE);
250
251 ares__llist_destroy(slist);
252
253 return status;
254 }
255
ares__init_by_options(ares_channel_t *channel, const struct ares_options *options, int optmask)256 ares_status_t ares__init_by_options(ares_channel_t *channel,
257 const struct ares_options *options,
258 int optmask)
259 {
260 size_t i;
261
262 if (channel == NULL) {
263 return ARES_ENODATA;
264 }
265
266 if (options == NULL) {
267 if (optmask != 0) {
268 return ARES_ENODATA;
269 }
270 return ARES_SUCCESS;
271 }
272
273 /* Easy stuff. */
274
275 /* Event Thread requires threading support and is incompatible with socket
276 * state callbacks */
277 if (optmask & ARES_OPT_EVENT_THREAD) {
278 if (!ares_threadsafety()) {
279 return ARES_ENOTIMP;
280 }
281 if (optmask & ARES_OPT_SOCK_STATE_CB) {
282 return ARES_EFORMERR;
283 }
284 channel->evsys = options->evsys;
285 }
286
287 if (optmask & ARES_OPT_FLAGS) {
288 channel->flags = (unsigned int)options->flags;
289 }
290
291 if (optmask & ARES_OPT_TIMEOUTMS) {
292 /* Apparently some integrations were passing -1 to tell c-ares to use
293 * the default instead of just omitting the optmask */
294 if (options->timeout <= 0) {
295 optmask &= ~(ARES_OPT_TIMEOUTMS);
296 } else {
297 channel->timeout = (unsigned int)options->timeout;
298 }
299 } else if (optmask & ARES_OPT_TIMEOUT) {
300 optmask &= ~(ARES_OPT_TIMEOUT);
301 /* Apparently some integrations were passing -1 to tell c-ares to use
302 * the default instead of just omitting the optmask */
303 if (options->timeout > 0) {
304 /* Convert to milliseconds */
305 optmask |= ARES_OPT_TIMEOUTMS;
306 channel->timeout = (unsigned int)options->timeout * 1000;
307 }
308 }
309
310 if (optmask & ARES_OPT_TRIES) {
311 if (options->tries <= 0) {
312 optmask &= ~(ARES_OPT_TRIES);
313 } else {
314 channel->tries = (size_t)options->tries;
315 }
316 }
317
318 if (optmask & ARES_OPT_NDOTS) {
319 if (options->ndots <= 0) {
320 optmask &= ~(ARES_OPT_NDOTS);
321 } else {
322 channel->ndots = (size_t)options->ndots;
323 }
324 }
325
326 if (optmask & ARES_OPT_MAXTIMEOUTMS) {
327 if (options->maxtimeout <= 0) {
328 optmask &= ~(ARES_OPT_MAXTIMEOUTMS);
329 } else {
330 channel->maxtimeout = (size_t)options->maxtimeout;
331 }
332 }
333
334 if (optmask & ARES_OPT_ROTATE) {
335 channel->rotate = ARES_TRUE;
336 }
337
338 if (optmask & ARES_OPT_NOROTATE) {
339 channel->rotate = ARES_FALSE;
340 }
341
342 if (optmask & ARES_OPT_UDP_PORT) {
343 channel->udp_port = options->udp_port;
344 }
345
346 if (optmask & ARES_OPT_TCP_PORT) {
347 channel->tcp_port = options->tcp_port;
348 }
349
350 if (optmask & ARES_OPT_SOCK_STATE_CB) {
351 channel->sock_state_cb = options->sock_state_cb;
352 channel->sock_state_cb_data = options->sock_state_cb_data;
353 }
354
355 if (optmask & ARES_OPT_SOCK_SNDBUF) {
356 if (options->socket_send_buffer_size <= 0) {
357 optmask &= ~(ARES_OPT_SOCK_SNDBUF);
358 } else {
359 channel->socket_send_buffer_size = options->socket_send_buffer_size;
360 }
361 }
362
363 if (optmask & ARES_OPT_SOCK_RCVBUF) {
364 if (options->socket_receive_buffer_size <= 0) {
365 optmask &= ~(ARES_OPT_SOCK_RCVBUF);
366 } else {
367 channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
368 }
369 }
370
371 if (optmask & ARES_OPT_EDNSPSZ) {
372 if (options->ednspsz <= 0) {
373 optmask &= ~(ARES_OPT_EDNSPSZ);
374 } else {
375 channel->ednspsz = (size_t)options->ednspsz;
376 }
377 }
378
379 /* Copy the domains, if given. Keep channel->ndomains consistent so
380 * we can clean up in case of error.
381 */
382 if (optmask & ARES_OPT_DOMAINS && options->ndomains > 0) {
383 channel->domains =
384 ares_malloc_zero((size_t)options->ndomains * sizeof(char *));
385 if (!channel->domains) {
386 return ARES_ENOMEM;
387 }
388 channel->ndomains = (size_t)options->ndomains;
389 for (i = 0; i < (size_t)options->ndomains; i++) {
390 channel->domains[i] = ares_strdup(options->domains[i]);
391 if (!channel->domains[i]) {
392 return ARES_ENOMEM;
393 }
394 }
395 }
396
397 /* Set lookups, if given. */
398 if (optmask & ARES_OPT_LOOKUPS) {
399 if (options->lookups == NULL) {
400 optmask &= ~(ARES_OPT_LOOKUPS);
401 } else {
402 channel->lookups = ares_strdup(options->lookups);
403 if (!channel->lookups) {
404 return ARES_ENOMEM;
405 }
406 }
407 }
408
409 /* copy sortlist */
410 if (optmask & ARES_OPT_SORTLIST && options->nsort > 0) {
411 channel->nsort = (size_t)options->nsort;
412 channel->sortlist =
413 ares_malloc((size_t)options->nsort * sizeof(struct apattern));
414 if (!channel->sortlist) {
415 return ARES_ENOMEM;
416 }
417 for (i = 0; i < (size_t)options->nsort; i++) {
418 channel->sortlist[i] = options->sortlist[i];
419 }
420 }
421
422 /* Set path for resolv.conf file, if given. */
423 if (optmask & ARES_OPT_RESOLVCONF) {
424 if (options->resolvconf_path == NULL) {
425 optmask &= ~(ARES_OPT_RESOLVCONF);
426 } else {
427 channel->resolvconf_path = ares_strdup(options->resolvconf_path);
428 if (channel->resolvconf_path == NULL) {
429 return ARES_ENOMEM;
430 }
431 }
432 }
433
434 /* Set path for hosts file, if given. */
435 if (optmask & ARES_OPT_HOSTS_FILE) {
436 if (options->hosts_path == NULL) {
437 optmask &= ~(ARES_OPT_HOSTS_FILE);
438 } else {
439 channel->hosts_path = ares_strdup(options->hosts_path);
440 if (channel->hosts_path == NULL) {
441 return ARES_ENOMEM;
442 }
443 }
444 }
445
446 if (optmask & ARES_OPT_UDP_MAX_QUERIES) {
447 if (options->udp_max_queries <= 0) {
448 optmask &= ~(ARES_OPT_UDP_MAX_QUERIES);
449 } else {
450 channel->udp_max_queries = (size_t)options->udp_max_queries;
451 }
452 }
453
454 if (optmask & ARES_OPT_QUERY_CACHE) {
455 /* qcache_max_ttl is unsigned unlike the others */
456 if (options->qcache_max_ttl == 0) {
457 optmask &= ~(ARES_OPT_QUERY_CACHE);
458 } else {
459 channel->qcache_max_ttl = options->qcache_max_ttl;
460 }
461 }
462
463 /* Initialize the ipv4 servers if provided */
464 if (optmask & ARES_OPT_SERVERS) {
465 if (options->nservers <= 0) {
466 optmask &= ~(ARES_OPT_SERVERS);
467 } else {
468 ares_status_t status;
469 status = ares__init_options_servers(channel, options->servers,
470 (size_t)options->nservers);
471 if (status != ARES_SUCCESS) {
472 return status;
473 }
474 }
475 }
476
477 channel->optmask = (unsigned int)optmask;
478
479 return ARES_SUCCESS;
480 }
481