summaryrefslogtreecommitdiff
path: root/other/bootstrap_daemon/src/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'other/bootstrap_daemon/src/config.c')
-rw-r--r--other/bootstrap_daemon/src/config.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/other/bootstrap_daemon/src/config.c b/other/bootstrap_daemon/src/config.c
new file mode 100644
index 00000000..861a3803
--- /dev/null
+++ b/other/bootstrap_daemon/src/config.c
@@ -0,0 +1,426 @@
1/* config.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Functionality related to dealing with the config file.
5 *
6 * Copyright (C) 2014-2016 Tox project All Rights Reserved.
7 *
8 * This file is part of Tox.
9 *
10 * Tox is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * Tox is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include "config.h"
26
27#include "config_defaults.h"
28#include "log.h"
29
30#include <stdlib.h>
31#include <string.h>
32#include <string.h>
33
34#include <libconfig.h>
35
36#include "../../bootstrap_node_packets.h"
37
38/**
39 * Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array.
40 *
41 * Supposed to be called from get_general_config only.
42 *
43 * Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`.
44 */
45void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)
46{
47 const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports";
48
49 *tcp_relay_port_count = 0;
50
51 config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);
52
53 if (ports_array == NULL) {
54 write_log(LOG_LEVEL_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS);
55 write_log(LOG_LEVEL_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS);
56
57 uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};
58
59 int i;
60
61 for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
62 write_log(LOG_LEVEL_INFO, "Port #%d: %u\n", i, default_ports[i]);
63 }
64
65 // similar procedure to the one of reading config file below
66 *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));
67
68 for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
69
70 (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];
71
72 if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
73 || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
74 write_log(LOG_LEVEL_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
75 (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
76 continue;
77 }
78
79 (*tcp_relay_port_count) ++;
80 }
81
82 // the loop above skips invalid ports, so we adjust the allocated memory size
83 if ((*tcp_relay_port_count) > 0) {
84 *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
85 } else {
86 free(*tcp_relay_ports);
87 *tcp_relay_ports = NULL;
88 }
89
90 return;
91 }
92
93 if (config_setting_is_array(ports_array) == CONFIG_FALSE) {
94 write_log(LOG_LEVEL_ERROR, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n",
95 NAME_TCP_RELAY_PORTS);
96 return;
97 }
98
99 int config_port_count = config_setting_length(ports_array);
100
101 if (config_port_count == 0) {
102 write_log(LOG_LEVEL_ERROR, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS);
103 return;
104 }
105
106 *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));
107
108 int i;
109
110 for (i = 0; i < config_port_count; i ++) {
111 config_setting_t *elem = config_setting_get_elem(ports_array, i);
112
113 if (elem == NULL) {
114 // it's NULL if `ports_array` is not an array (we have that check earlier) or if `i` is out of range, which should not be
115 write_log(LOG_LEVEL_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i);
116 break;
117 }
118
119 if (config_setting_is_number(elem) == CONFIG_FALSE) {
120 write_log(LOG_LEVEL_WARNING, "Port #%d: Not a number. Skipping.\n", i);
121 continue;
122 }
123
124 (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);
125
126 if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
127 || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
128 write_log(LOG_LEVEL_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
129 (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
130 continue;
131 }
132
133 (*tcp_relay_port_count) ++;
134 }
135
136 // the loop above skips invalid ports, so we adjust the allocated memory size
137 if ((*tcp_relay_port_count) > 0) {
138 *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
139 } else {
140 free(*tcp_relay_ports);
141 *tcp_relay_ports = NULL;
142 }
143}
144
145int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
146 int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
147 int *tcp_relay_port_count, int *enable_motd, char **motd)
148{
149 config_t cfg;
150
151 const char *NAME_PORT = "port";
152 const char *NAME_PID_FILE_PATH = "pid_file_path";
153 const char *NAME_KEYS_FILE_PATH = "keys_file_path";
154 const char *NAME_ENABLE_IPV6 = "enable_ipv6";
155 const char *NAME_ENABLE_IPV4_FALLBACK = "enable_ipv4_fallback";
156 const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
157 const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay";
158 const char *NAME_ENABLE_MOTD = "enable_motd";
159 const char *NAME_MOTD = "motd";
160
161 config_init(&cfg);
162
163 // Read the file. If there is an error, report it and exit.
164 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
165 write_log(LOG_LEVEL_ERROR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
166 config_destroy(&cfg);
167 return 0;
168 }
169
170 // Get port
171 if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
172 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
173 write_log(LOG_LEVEL_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
174 *port = DEFAULT_PORT;
175 }
176
177 // Get PID file location
178 const char *tmp_pid_file;
179
180 if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
181 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
182 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
183 tmp_pid_file = DEFAULT_PID_FILE_PATH;
184 }
185
186 *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
187 strcpy(*pid_file_path, tmp_pid_file);
188
189 // Get keys file location
190 const char *tmp_keys_file;
191
192 if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
193 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
194 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
195 tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
196 }
197
198 *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
199 strcpy(*keys_file_path, tmp_keys_file);
200
201 // Get IPv6 option
202 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
203 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
204 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
205 *enable_ipv6 = DEFAULT_ENABLE_IPV6;
206 }
207
208 // Get IPv4 fallback option
209 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) {
210 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK);
211 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK,
212 DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false");
213 *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK;
214 }
215
216 // Get LAN discovery option
217 if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
218 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
219 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
220 DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
221 *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
222 }
223
224 // Get TCP relay option
225 if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {
226 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY);
227 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY,
228 DEFAULT_ENABLE_TCP_RELAY ? "true" : "false");
229 *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;
230 }
231
232 if (*enable_tcp_relay) {
233 parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);
234 } else {
235 *tcp_relay_port_count = 0;
236 }
237
238 // Get MOTD option
239 if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {
240 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD);
241 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD,
242 DEFAULT_ENABLE_MOTD ? "true" : "false");
243 *enable_motd = DEFAULT_ENABLE_MOTD;
244 }
245
246 if (*enable_motd) {
247 // Get MOTD
248 const char *tmp_motd;
249
250 if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {
251 write_log(LOG_LEVEL_WARNING, "No '%s' setting in configuration file.\n", NAME_MOTD);
252 write_log(LOG_LEVEL_WARNING, "Using default '%s': %s\n", NAME_MOTD, DEFAULT_MOTD);
253 tmp_motd = DEFAULT_MOTD;
254 }
255
256 size_t tmp_motd_length = strlen(tmp_motd) + 1;
257 size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;
258 *motd = malloc(motd_length);
259 strncpy(*motd, tmp_motd, motd_length);
260 (*motd)[motd_length - 1] = '\0';
261 }
262
263 config_destroy(&cfg);
264
265 write_log(LOG_LEVEL_INFO, "Successfully read:\n");
266 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
267 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
268 write_log(LOG_LEVEL_INFO, "'%s': %d\n", NAME_PORT, *port);
269 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
270 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false");
271 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
272
273 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false");
274
275 // show info about tcp ports only if tcp relay is enabled
276 if (*enable_tcp_relay) {
277 if (*tcp_relay_port_count == 0) {
278 write_log(LOG_LEVEL_ERROR, "No TCP ports could be read.\n");
279 } else {
280 write_log(LOG_LEVEL_INFO, "Read %d TCP ports:\n", *tcp_relay_port_count);
281 int i;
282
283 for (i = 0; i < *tcp_relay_port_count; i ++) {
284 write_log(LOG_LEVEL_INFO, "Port #%d: %u\n", i, (*tcp_relay_ports)[i]);
285 }
286 }
287 }
288
289 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false");
290
291 if (*enable_motd) {
292 write_log(LOG_LEVEL_INFO, "'%s': %s\n", NAME_MOTD, *motd);
293 }
294
295 return 1;
296}
297
298/**
299 *
300 * Converts a hex string with even number of characters into binary.
301 *
302 * Important: You are responsible for freeing the return value.
303 *
304 * @return binary on success,
305 * NULL on failure.
306 */
307uint8_t *hex_string_to_bin(char *hex_string)
308{
309 if (strlen(hex_string) % 2 != 0) {
310 return NULL;
311 }
312
313 size_t len = strlen(hex_string) / 2;
314 uint8_t *ret = malloc(len);
315
316 char *pos = hex_string;
317 size_t i;
318 for (i = 0; i < len; ++i, pos += 2) {
319 sscanf(pos, "%2hhx", &ret[i]);
320 }
321
322 return ret;
323}
324
325int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6)
326{
327 const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes";
328
329 const char *NAME_PUBLIC_KEY = "public_key";
330 const char *NAME_PORT = "port";
331 const char *NAME_ADDRESS = "address";
332
333 config_t cfg;
334
335 config_init(&cfg);
336
337 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
338 write_log(LOG_LEVEL_ERROR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
339 config_destroy(&cfg);
340 return 0;
341 }
342
343 config_setting_t *node_list = config_lookup(&cfg, NAME_BOOTSTRAP_NODES);
344
345 if (node_list == NULL) {
346 write_log(LOG_LEVEL_WARNING, "No '%s' setting in the configuration file. Skipping bootstrapping.\n", NAME_BOOTSTRAP_NODES);
347 config_destroy(&cfg);
348 return 1;
349 }
350
351 if (config_setting_length(node_list) == 0) {
352 write_log(LOG_LEVEL_WARNING, "No bootstrap nodes found. Skipping bootstrapping.\n");
353 config_destroy(&cfg);
354 return 1;
355 }
356
357 int bs_port;
358 const char *bs_address;
359 const char *bs_public_key;
360
361 config_setting_t *node;
362
363 int i = 0;
364
365 while (config_setting_length(node_list)) {
366
367 node = config_setting_get_elem(node_list, 0);
368
369 if (node == NULL) {
370 config_destroy(&cfg);
371 return 0;
372 }
373
374 // Check that all settings are present
375 if (config_setting_lookup_string(node, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE) {
376 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PUBLIC_KEY);
377 goto next;
378 }
379
380 if (config_setting_lookup_int(node, NAME_PORT, &bs_port) == CONFIG_FALSE) {
381 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PORT);
382 goto next;
383 }
384
385 if (config_setting_lookup_string(node, NAME_ADDRESS, &bs_address) == CONFIG_FALSE) {
386 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_ADDRESS);
387 goto next;
388 }
389
390 // Process settings
391 if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES * 2) {
392 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_PUBLIC_KEY,
393 bs_public_key);
394 goto next;
395 }
396
397 if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {
398 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\n", i, NAME_PORT,
399 bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
400 goto next;
401 }
402
403 uint8_t *bs_public_key_bin = hex_string_to_bin((char *)bs_public_key);
404 const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
405 bs_public_key_bin);
406 free(bs_public_key_bin);
407
408 if (!address_resolved) {
409 write_log(LOG_LEVEL_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_ADDRESS, bs_address);
410 goto next;
411 }
412
413 write_log(LOG_LEVEL_INFO, "Successfully added bootstrap node #%d: %s:%d %s\n", i, bs_address, bs_port, bs_public_key);
414
415next:
416 // config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly
417 // though it's freed when the element is removed, so we free it right away in order to keep memory
418 // consumption minimal
419 config_setting_remove_elem(node_list, 0);
420 i++;
421 }
422
423 config_destroy(&cfg);
424
425 return 1;
426}