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