summaryrefslogtreecommitdiff
path: root/other/bootstrap_serverdaemon
diff options
context:
space:
mode:
authorirungentoo <irungentoo@tox.im>2014-01-19 11:51:25 -0800
committerirungentoo <irungentoo@tox.im>2014-01-19 11:51:25 -0800
commit6b7dff37c822d63c2dbe626d091e1c40f48b9b7e (patch)
tree5df58f2b305392ec23b0a60897287de8da4b3134 /other/bootstrap_serverdaemon
parent91b06da0c3aa399edf7e00e33a8f380b42e44f43 (diff)
parentbffc3d96e5a9c08d8457737cfd2cb2cb54c35670 (diff)
Merge pull request #688 from nurupo/dht_bootstrap_daemon
Improved DHT bootstrap daemon
Diffstat (limited to 'other/bootstrap_serverdaemon')
-rw-r--r--other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c460
-rw-r--r--other/bootstrap_serverdaemon/Makefile.inc15
-rw-r--r--other/bootstrap_serverdaemon/README.md61
-rw-r--r--other/bootstrap_serverdaemon/conf40
-rw-r--r--other/bootstrap_serverdaemon/server.cfg34
-rw-r--r--[-rwxr-xr-x]other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon (renamed from other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh)16
-rw-r--r--other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c459
7 files changed, 576 insertions, 509 deletions
diff --git a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c b/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c
deleted file mode 100644
index dc519448..00000000
--- a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c
+++ /dev/null
@@ -1,460 +0,0 @@
1/* DHT boostrap
2 *
3 * A simple DHT boostrap server for tox - daemon edition.
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <sys/types.h> /* pid_t */
25#include <sys/stat.h> /* umask */
26#include <unistd.h> /* POSIX things */
27#include <errno.h>
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <libconfig.h>
32#include <arpa/inet.h> /* htons() */
33#include <string.h> /* strcpy() */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include "../../toxcore/DHT.h"
40#include "../../toxcore/friend_requests.h"
41
42#define DEFAULT_PORT 33445
43#define DEFAULT_PID_FILE "bootstrap_server.pid"
44#define DEFAULT_KEYS_FILE "bootstrap_server.keys"
45
46/* Server info struct */
47struct server_info_s {
48 int valid;
49 IP_Port conn;
50 uint8_t bs_pk[32];
51};
52
53/* This is the struct configure_server() uses to return its data to */
54struct server_conf_s {
55 int err;
56 int port;
57 char pid_file[512];
58 char keys_file[512];
59 struct server_info_s info[32];
60};
61
62int b16_to_key(char b16_string[], uint8_t *bs_pubkey)
63{
64
65 int i;
66 unsigned int num1 = 0, num2 = 0;
67
68 for (i = 0; i < 32; ++i) {
69 sscanf(&b16_string[i * 2], "%1X", &num1);
70 sscanf(&b16_string[i * 2 + 1], "%1X", &num2);
71 num1 = num1 << 4;
72 bs_pubkey[i] = bs_pubkey[i] | num1;
73 bs_pubkey[i] = bs_pubkey[i] | num2;
74 }
75
76 return 0;
77}
78
79/*
80 resolve_addr():
81 address should represent IPv4 or a hostname with a record
82
83 returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i
84 returns 0 on failure
85
86 TODO: Fix ipv6 support
87*/
88
89uint32_t resolve_addr(const char *address)
90{
91 struct addrinfo *server = NULL;
92 struct addrinfo hints;
93 int rc;
94 uint32_t addr;
95
96 memset(&hints, 0, sizeof(hints));
97 hints.ai_family = AF_INET; // IPv4 only right now.
98 hints.ai_socktype = SOCK_DGRAM; // Type of socket Tox uses.
99
100 rc = getaddrinfo(address, "echo", &hints, &server);
101
102 // Lookup failed.
103 if (rc != 0) {
104 return 0;
105 }
106
107 // IPv4 records only..
108 if (server->ai_family != AF_INET) {
109 freeaddrinfo(server);
110 return 0;
111 }
112
113
114 addr = ((struct sockaddr_in *)server->ai_addr)->sin_addr.s_addr;
115
116 freeaddrinfo(server);
117 return addr;
118}
119
120/* This function connects to all specified servers
121and connect to them.
122returns 1 if the connection to the DHT is up
123returns -1 if all attempts failed
124*/
125int connect_to_servers(DHT *dht, struct server_info_s *info)
126{
127 int i;
128 int c;
129
130 for (i = 0; i < 32; ++i) {
131 if (info[i].valid) {
132 /* Actual bootstrapping code goes here */
133 //puts("Calling DHT_bootstrap");
134 DHT_bootstrap(dht, info[i].conn, info[i].bs_pk);
135 }
136 }
137
138 /* Check if we're connected to the DHT */
139 for (c = 0; c != 100; ++c) {
140 usleep(10000);
141
142 if (DHT_isconnected(dht)) {
143 //puts("Connected");
144 return 1;
145 break;
146 }
147
148 if (DHT_isconnected(dht) == 0 && c == 99) {
149 //puts("Not connected");
150 return -1;
151 break;
152 }
153
154 do_DHT(dht);
155
156 networking_poll(dht->c->lossless_udp->net);
157 }
158
159 /* This probably never happens */
160 return 0;
161}
162
163void manage_keys(DHT *dht, char *keys_file)
164{
165 const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
166 uint8_t keys[KEYS_SIZE];
167 struct stat existence;
168 FILE *keysf;
169
170 /* Check if file exits, proceed to open and load keys */
171 if (stat(keys_file, &existence) >= 0) {
172 keysf = fopen(keys_file, "r");
173 size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keysf);
174
175 if (read_size != KEYS_SIZE) {
176 printf("Error while reading the key file\nExiting.\n");
177 exit(1);
178 } else {
179 printf("Keys loaded successfully\n");
180 }
181
182 load_keys(dht->c, keys);
183
184 } else {
185 /* Otherwise save new keys */
186 /* Silly work-around to ignore any errors coming from new_keys() */
187 new_keys(dht->c);
188 save_keys(dht->c, keys);
189 keysf = fopen(keys_file, "w");
190
191 if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keysf) != KEYS_SIZE) {
192 printf("Error while writing the key file.\nExiting.\n");
193 exit(1);
194 } else {
195 printf("Keys saved successfully\n");
196 }
197 }
198
199 fclose(keysf);
200}
201
202/* This reads the configuration file, and returns a struct server_conf_s with:
203 *an error number:
204 *-1 = file wasn't read, for whatever reason
205 *-2 = no bootstrap servers found
206 *the port
207 *the location of the keys file
208 *the location of the PID file
209 *the list of bootstrap servers
210*/
211struct server_conf_s configure_server(char *cfg_file)
212{
213 config_t cfg;
214 config_setting_t *server_list;
215
216 /* This one will be strcpy'd into the pid_file array in server_conf */
217 const char *pid_file_tmp;
218 const char *keys_file_tmp;
219
220 /* Remote bootstrap server variables */
221 int bs_port;
222 const char *bs_ip;
223 const char *bs_pk;
224
225 /* The big struct */
226 static struct server_conf_s server_conf;
227
228 /* Set both to their default values. If there's an error
229 with opening/reading the config file, we return right away */
230 server_conf.port = DEFAULT_PORT;
231 strcpy(server_conf.pid_file, DEFAULT_PID_FILE);
232 strcpy(server_conf.keys_file, DEFAULT_KEYS_FILE);
233
234 config_init(&cfg);
235
236 /* Read the file. If there is an error, report it and exit. */
237 if (! config_read_file(&cfg, cfg_file)) {
238 fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
239 config_error_line(&cfg), config_error_text(&cfg));
240 config_destroy(&cfg);
241 server_conf.err = -1;
242 return server_conf;
243 }
244
245 /* Get the port to listen on */
246 if (config_lookup_int(&cfg, "port", &server_conf.port)) {
247 //printf("Port: %d\n", port);
248 } else {
249 fprintf(stderr, "No 'port' setting in configuration file.\n");
250 }
251
252 /* Get PID file location */
253 if (config_lookup_string(&cfg, "pid_file", &pid_file_tmp)) {
254 //printf("PID file: %s\n", pid_file_tmp);
255 strcpy(server_conf.pid_file, pid_file_tmp);
256 } else {
257 fprintf(stderr, "No 'pid_file' setting in configuration file.\n");
258 }
259
260 /* Get keys file location */
261 if (config_lookup_string(&cfg, "keys_file", &keys_file_tmp)) {
262 //printf("Keys file: %s\n", keys_file_tmp);
263 strcpy(server_conf.keys_file, keys_file_tmp);
264 } else {
265 fprintf(stderr, "No 'keys_file' setting in configuration file.\n");
266 }
267
268 /* Get all the servers in the list */
269 server_list = config_lookup(&cfg, "bootstrap_servers");
270
271 if (server_list != NULL) {
272 int count = config_setting_length(server_list);
273 int i;
274
275 char tmp_ip[30]; /* IP */
276 char tmp_pk[64]; /* bs_pk */
277
278 for (i = 0; i < count; ++i) {
279 config_setting_t *server = config_setting_get_elem(server_list, i);
280 /* Get a pointer on the key array */
281 uint8_t *bs_pk_p = server_conf.info[i].bs_pk;
282
283 /* Only output the record if all of the expected fields are present. */
284 if (!(config_setting_lookup_string(server, "ip", &bs_ip)
285 && config_setting_lookup_int(server, "port", &bs_port)
286 && config_setting_lookup_string(server, "bs_pk", &bs_pk)))
287 continue;
288
289 /* Converting all that stuff into usable formats and storing
290 it away in the server_info struct */
291 server_conf.info[i].valid = 1;
292
293 if (resolve_addr(strcpy(tmp_ip, bs_ip)) == 0) {
294 server_conf.info[i].valid = 0;
295 printf("bootstrap_server %d: Invalid IP.\n", i);
296 }
297
298 if (strlen(bs_pk) != 64) {
299 server_conf.info[i].valid = 0;
300 printf("bootstrap_server %d: Invalid public key.\n", i);
301 }
302
303 if (!bs_port) {
304 server_conf.info[i].valid = 0;
305 printf("bootstrap_server %d: Invalid port.\n", i);
306 }
307
308 server_conf.info[i].conn.ip.family = AF_INET;
309 server_conf.info[i].conn.ip.ip4.uint32 = resolve_addr(strcpy(tmp_ip, bs_ip));
310 server_conf.info[i].conn.port = htons(bs_port);
311 b16_to_key(strcpy(tmp_pk, bs_pk), bs_pk_p);
312 }
313
314 /* Check if at least one server entry is valid */
315 for (i = 0; i < 32; ++i) {
316 if (server_conf.info[i].valid)
317 break;
318 else
319 server_conf.err = -2;
320 }
321
322 } else {
323 server_conf.err = -2;
324 }
325
326 config_destroy(&cfg);
327 return server_conf;
328}
329
330int main(int argc, char *argv[])
331{
332
333 pid_t pid, sid; /* Process- and Session-ID */
334 struct server_conf_s server_conf;
335
336 FILE *pidf; /* The PID file */
337
338 if (argc < 2) {
339 printf("Please specify a configuration file.\n");
340 exit(EXIT_FAILURE);
341 }
342
343 server_conf = configure_server(argv[1]);
344
345 /* Initialize networking
346 bind to ip 0.0.0.0:PORT */
347 IP ip;
348 ip_init(&ip, 0);
349 DHT *dht = new_DHT(new_net_crypto(new_networking(ip, server_conf.port)));
350 /* Read the config file */
351 printf("PID file: %s\n", server_conf.pid_file);
352 printf("Key file: %s\n", server_conf.keys_file);
353
354 if (server_conf.err == -1)
355 printf("Config file not read.\n");
356
357 if (server_conf.err == -2)
358 printf("No valid servers in list.\n");
359
360 /* Open PID file for writing - if an error happens,
361 it will be caught down the line */
362 pidf = fopen(server_conf.pid_file, "w");
363
364 /* Manage the keys */
365 /* for now, just ignore any errors after this call. */
366 int tmperr = errno;
367 manage_keys(dht, server_conf.keys_file);
368 errno = tmperr;
369
370 /* Public key */
371 int i;
372 printf("\nPublic Key: ");
373
374 for (i = 0; i < 32; ++i) {
375 uint8_t ln, hn;
376 ln = 0x0F & dht->c->self_public_key[i];
377 hn = 0xF0 & dht->c->self_public_key[i];
378 hn = hn >> 4;
379 printf("%X%X", hn, ln);
380 }
381
382 printf("\n");
383
384 /* Bootstrap the DHT
385 This one throws odd errors, too. Ignore. I assume they come
386 from somewhere in the core. */
387 tmperr = errno;
388 connect_to_servers(dht, server_conf.info);
389 errno = tmperr;
390
391 if (!DHT_isconnected(dht)) {
392 puts("Could not establish DHT connection. Check server settings.\n");
393 exit(EXIT_FAILURE);
394 } else {
395 printf("Connected to DHT successfully.\n");
396 }
397
398 /* If there's been an error, exit before forking off */
399 if (errno != 0) {
400 perror("Error");
401 printf("Error(s) occured during start-up. Exiting.\n");
402 exit(EXIT_FAILURE);
403 }
404
405 /* Things that make the daemon work come past here.
406 There should be nothing here but the daemon code and
407 the main loop. */
408
409 /* Fork off from the parent process */
410 pid = fork();
411
412 if (pid < 0) {
413 printf("Forking failed.\n");
414 exit(EXIT_FAILURE);
415 }
416
417 /* If we got a good PID, then
418 we can exit the parent process. */
419 if (pid > 0) {
420 printf("Forked successfully: %d.\n", pid);
421
422 /* Write the PID file */
423 fprintf(pidf, "%d\n", pid);
424 fclose(pidf);
425
426 /* Exit parent */
427 exit(EXIT_SUCCESS);
428 }
429
430 /* Change the file mode mask */
431 umask(0);
432
433 /* Create a new SID for the child process */
434 sid = setsid();
435
436 if (sid < 0) {
437 printf("SID creation failure.\n");
438 exit(EXIT_FAILURE);
439 }
440
441 /* Change the current working directory */
442 if ((chdir("/")) < 0) {
443 exit(EXIT_FAILURE);
444 }
445
446 /* Go quiet */
447 close(STDOUT_FILENO);
448 close(STDIN_FILENO);
449 close(STDERR_FILENO);
450
451 while (1) {
452 do_DHT(dht);
453
454 networking_poll(dht->c->lossless_udp->net);
455 usleep(10000);
456 }
457
458 //shutdown_networking();
459 exit(EXIT_SUCCESS);
460}
diff --git a/other/bootstrap_serverdaemon/Makefile.inc b/other/bootstrap_serverdaemon/Makefile.inc
index 73b078c3..287500b1 100644
--- a/other/bootstrap_serverdaemon/Makefile.inc
+++ b/other/bootstrap_serverdaemon/Makefile.inc
@@ -1,17 +1,17 @@
1if BUILD_DHT_BOOTSTRAP_DAEMON 1if BUILD_DHT_BOOTSTRAP_DAEMON
2 2
3noinst_PROGRAMS += DHT_bootstrap_daemon 3noinst_PROGRAMS += tox_dht_bootstrap_server_daemon
4 4
5DHT_bootstrap_daemon_SOURCES = \ 5tox_dht_bootstrap_server_daemon_SOURCES = \
6 ../other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c 6 ../other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c
7 7
8DHT_bootstrap_daemon_CFLAGS = \ 8tox_dht_bootstrap_server_daemon_CFLAGS = \
9 -I$(top_srcdir)/other/bootstrap_serverdaemon \ 9 -I$(top_srcdir)/other/bootstrap_serverdaemon \
10 $(LIBSODIUM_CFLAGS) \ 10 $(LIBSODIUM_CFLAGS) \
11 $(NACL_CFLAGS) \ 11 $(NACL_CFLAGS) \
12 $(LIBCONFIG_CFLAGS) 12 $(LIBCONFIG_CFLAGS)
13 13
14DHT_bootstrap_daemon_LDADD = \ 14tox_dht_bootstrap_server_daemon_LDADD = \
15 $(LIBSODIUM_LDFLAGS) \ 15 $(LIBSODIUM_LDFLAGS) \
16 $(NACL_LDFLAGS) \ 16 $(NACL_LDFLAGS) \
17 libtoxcore.la \ 17 libtoxcore.la \
@@ -22,5 +22,6 @@ DHT_bootstrap_daemon_LDADD = \
22endif 22endif
23 23
24EXTRA_DIST += \ 24EXTRA_DIST += \
25 $(top_srcdir)/other/bootstrap_serverdaemon/server.cfg \ 25 $(top_srcdir)/other/bootstrap_serverdaemon/conf \
26 $(top_srcdir)/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh 26 $(top_srcdir)/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon
27 \ No newline at end of file
diff --git a/other/bootstrap_serverdaemon/README.md b/other/bootstrap_serverdaemon/README.md
new file mode 100644
index 00000000..0c423675
--- /dev/null
+++ b/other/bootstrap_serverdaemon/README.md
@@ -0,0 +1,61 @@
1##Instructions for Debian
2
3The following commands are to be executed as root:
4
51. In `tox_dht_bootstrap_server_daemon` file change:
6 - `CFG` to where your config file (`conf`) will be; read rights required
7 - `DAEMON` to point to the executable
8 - `PIDFILE` to point to a pid file daemon would have rights to create
9
102. Go over everything in `conf`. Make sure `pid_file_path` matches `PIDFILE` from `tox_dht_bootstrap_server_daemon`
11
123. Execute:
13```
14mv tox_dht_bootstrap_server_daemon /etc/init.d/tox_dht_bootstrap_server_daemon
15```
16
174. Give the right permissions to this file:
18```
19chmod 755 /etc/init.d/tox_dht_bootstrap_server_daemon
20```
21
225. Execute:
23```
24update-rc.d tox_dht_bootstrap_server_daemon defaults
25```
26
276. Start the service:
28```
29service tox_dht_bootstrap_server_daemon start
30```
31
327. Verify that the service is running:
33```
34service tox_dht_bootstrap_server_daemon status
35```
36
37--
38
39You can see daemon's log with
40```
41grep "tox_dht_bootstrap_server_daemon" /var/log/syslog
42```
43
44**Note that system log is where you find your public key**
45
46--
47
48###Troubleshooting:
49
501. Check the log for errors with
51```
52grep "tox_dht_bootstrap_server_daemon" /var/log/syslog
53```
54
552. Check that paths in the beginning of `/etc/init.d/tox_dht_bootstrap_server_daemon` are valid
56
573. Make sure that `PIDFILE` from `/etc/init.d/tox_dht_bootstrap_server_daemon` matches with the `pid_file_path` from `conf`
58
594. Make sure you have write permission to keys and pid files
60
615. Make sure you have read permission for config file \ No newline at end of file
diff --git a/other/bootstrap_serverdaemon/conf b/other/bootstrap_serverdaemon/conf
new file mode 100644
index 00000000..70dbdb14
--- /dev/null
+++ b/other/bootstrap_serverdaemon/conf
@@ -0,0 +1,40 @@
1// ProjectTox bootstrap server configuration file
2
3// listening port
4port = 33445
5
6// The key file is like a password, so keep it where no one can read it
7// The daemon should have permission to read/write to it
8// Remember to replace the provided example with
9// your own path
10keys_file_path = "/home/tom/.tox_dht_bootstrap_server_daemon/keys"
11
12// The PID file written to by daemon,
13// make sure that the user who runs the server
14// does have permissions to write to it
15// Remember to replace the provided example with
16// your own path
17pid_file_path = "/home/tom/.tox_dht_bootstrap_server_daemon/pid"
18
19enable_ipv6 = false
20
21// Automatically bootstrap with nodes on local network
22enable_lan_discovery = true
23
24// Any number of nodes the daemon will bootstrap itself from
25// Remember to replace the provided example with
26// your own server list
27bootstrap_servers = (
28 { // Server 1
29 // any ipv4 or ipv6, depending if `enable_ipv6` is set or not
30 // also any US-ASCII domain name
31 address = "198.46.136.167"
32 port = 33445
33 public_key = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854"
34 },
35 { // Server 2
36 address = "example.org"
37 port = 33445
38 public_key = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858"
39 }
40)
diff --git a/other/bootstrap_serverdaemon/server.cfg b/other/bootstrap_serverdaemon/server.cfg
deleted file mode 100644
index 527c2a72..00000000
--- a/other/bootstrap_serverdaemon/server.cfg
+++ /dev/null
@@ -1,34 +0,0 @@
1// ProjectTox bootstrap server configuration file
2
3// The port used by bootstrap_server to listen on
4port = 33445;
5
6// The key file
7// make sure that the user who runs the server
8// does have permissions to read it/write to it
9// Remember to replace the provided example with
10// the directory the DHT server will run in.
11keys_file = "/home/tom/.bootstrap_server.keys"
12
13// The PID file written to by bootstrap_server,
14// make sure that the user who runs the server
15// does have permissions to write to it
16// Remember to replace the provided example with
17// the directory the DHT server will run in.
18pid_file = "/home/tom/.bootstrap_server.pid";
19
20// The info of the node bootstap_server will
21// bootstrap itself from.
22bootstrap_servers = (
23 { // Server 1
24 ip = "198.46.136.167";
25 port = 33445;
26 bs_pk = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854";
27// }
28 },
29 { // Server 2
30 ip = "192.81.133.111";
31 port = 33445;
32 bs_pk = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858";
33 }
34);
diff --git a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh b/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon
index 936bc808..678db5e3 100755..100644
--- a/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh
+++ b/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon
@@ -1,23 +1,23 @@
1#! /bin/sh 1#! /bin/sh
2### BEGIN INIT INFO 2### BEGIN INIT INFO
3# Provides: DHT_bootstrap_daemon 3# Provides: tox_dht_bootstrap_server_daemon
4# Required-Start: $remote_fs $syslog 4# Required-Start: $remote_fs $syslog
5# Required-Stop: $remote_fs $syslog 5# Required-Stop: $remote_fs $syslog
6# Default-Start: 2 3 4 5 6# Default-Start: 2 3 4 5
7# Default-Stop: 0 1 6 7# Default-Stop: 0 1 6
8# Short-Description: Start the Tox bootstrapping server 8# Short-Description: Starts the Tox bootstrapping server
9# Description: Use this piece of junk to start the Tox 9# Description: Starts the Tox bootstrapping server
10# bootstrap server.
11### END INIT INFO 10### END INIT INFO
12 11
13# PATH should only include /usr/* if it runs after the mountnfs.sh script 12# PATH should only include /usr/* if it runs after the mountnfs.sh script
14PATH=/sbin:/usr/sbin:/bin:/usr/bin 13PATH=/sbin:/usr/sbin:/bin:/usr/bin
15DESC="ProjectTox bootstrap server daemon" 14DESC="ProjectTox bootstrap server daemon"
16NAME=DHT_bootstrap_daemon 15NAME=tox_dht_bootstrap_server_daemon
17CFG=/home/$USER/server.cfg 16USER=tom
17CFG=/home/$USER/.$NAME/conf
18DAEMON=/home/$USER/$NAME 18DAEMON=/home/$USER/$NAME
19DAEMON_ARGS="$CFG" 19DAEMON_ARGS="$CFG"
20PIDFILE=/home/$USER/.$NAME.pid 20PIDFILE=/home/$USER/.$NAME/pid
21SCRIPTNAME=/etc/init.d/$NAME 21SCRIPTNAME=/etc/init.d/$NAME
22 22
23# Exit if the package is not installed 23# Exit if the package is not installed
@@ -81,7 +81,7 @@ case "$1" in
81 esac 81 esac
82 ;; 82 ;;
83 status) 83 status)
84 status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? 84 status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
85 ;; 85 ;;
86 86
87 restart) #|force-reload) 87 restart) #|force-reload)
diff --git a/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c b/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c
new file mode 100644
index 00000000..134346a1
--- /dev/null
+++ b/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c
@@ -0,0 +1,459 @@
1/* tox_dht_bootstrap_server_daemon
2 *
3 * A simple DHT bootstrap server for tox - daemon edition.
4 *
5 * Copyright (C) 2014 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <syslog.h>
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <libconfig.h>
32#include <arpa/inet.h>
33#include <string.h>
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include "../../toxcore/DHT.h"
40#include "../../toxcore/friend_requests.h"
41#include "../../toxcore/LAN_discovery.h"
42
43#include "../../testing/misc_tools.c"
44
45#define DAEMON_NAME "tox_dht_bootstrap_server_daemon"
46
47#define SLEEP_TIME_MILLISECONDS 30
48#define sleep usleep(1000*SLEEP_TIME_MILLISECONDS)
49
50#define DEFAULT_PID_FILE_PATH ".tox_dht_bootstrap_server_daemon.pid"
51#define DEFAULT_KEYS_FILE_PATH ".tox_dht_bootstrap_server_daemon.keys"
52#define DEFAULT_PORT 33445
53#define DEFAULT_ENABLE_IPV6 0 // 1 - true, 0 - false
54#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
55
56
57// Uses the already existing key or creates one if it didn't exist
58//
59// retirns 1 on success
60// 0 on failure - no keys were read or stored
61
62int manage_keys(DHT *dht, char *keys_file_path)
63{
64 const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
65 uint8_t keys[KEYS_SIZE];
66 FILE *keys_file;
67
68 // Check if file exits, proceed to open and load keys
69 keys_file = fopen(keys_file_path, "r");
70
71 if (keys_file != NULL) {
72 size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
73
74 if (read_size != KEYS_SIZE) {
75 return 0;
76 }
77
78 load_keys(dht->c, keys);
79 } else {
80 // Otherwise save new keys
81 new_keys(dht->c);
82 save_keys(dht->c, keys);
83
84 keys_file = fopen(keys_file_path, "w");
85
86 size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
87
88 if (write_size != KEYS_SIZE) {
89 return 0;
90 }
91 }
92
93 fclose(keys_file);
94
95 return 1;
96}
97
98// Gets general config options
99//
100// Important: you are responsible for freeing `pid_file_path` and `keys_file_path`
101//
102// returns 1 on success
103// 0 on failure, doesn't modify any data pointed by arguments
104
105int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
106 int *enable_lan_discovery)
107{
108 config_t cfg;
109
110 const char *NAME_PORT = "port";
111 const char *NAME_PID_FILE_PATH = "pid_file_path";
112 const char *NAME_KEYS_FILE_PATH = "keys_file_path";
113 const char *NAME_ENABLE_IPV6 = "enable_ipv6";
114 const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
115
116 config_init(&cfg);
117
118 // Read the file. If there is an error, report it and exit.
119 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
120 syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
121 config_destroy(&cfg);
122 return 0;
123 }
124
125 // Get port
126 if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
127 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
128 syslog(LOG_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
129 *port = DEFAULT_PORT;
130 }
131
132 // Get PID file location
133 const char *tmp_pid_file;
134
135 if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
136 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
137 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
138 tmp_pid_file = DEFAULT_PID_FILE_PATH;
139 }
140
141 *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
142 strcpy(*pid_file_path, tmp_pid_file);
143
144 // Get keys file location
145 const char *tmp_keys_file;
146
147 if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
148 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
149 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
150 tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
151 }
152
153 *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
154 strcpy(*keys_file_path, tmp_keys_file);
155
156 // Get IPv6 option
157 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
158 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
159 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
160 *enable_ipv6 = DEFAULT_ENABLE_IPV6;
161 }
162
163 // Get LAN discovery option
164 if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
165 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
166 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
167 DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
168 *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
169 }
170
171 config_destroy(&cfg);
172
173 syslog(LOG_DEBUG, "Successfully read:\n");
174 syslog(LOG_DEBUG, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
175 syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
176 syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port);
177 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
178 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
179
180 return 1;
181}
182
183// Bootstraps servers listed in the config file
184//
185// returns 1 on success
186// 0 on failure, either no or only some servers were bootstrapped
187
188int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6)
189{
190 const char *NAME_BOOTSTRAP_SERVERS = "bootstrap_servers";
191
192 const char *NAME_PUBLIC_KEY = "public_key";
193 const char *NAME_PORT = "port";
194 const char *NAME_ADDRESS = "address";
195
196 config_t cfg;
197
198 config_init(&cfg);
199
200 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
201 syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
202 config_destroy(&cfg);
203 return 0;
204 }
205
206 config_setting_t *server_list = config_lookup(&cfg, NAME_BOOTSTRAP_SERVERS);
207
208 if (server_list == NULL) {
209 syslog(LOG_ERR, "No '%s' setting in configuration file.\n", NAME_BOOTSTRAP_SERVERS);
210 config_destroy(&cfg);
211 return 0;
212 }
213
214 int bs_port;
215 const char *bs_address;
216 const char *bs_public_key;
217
218 config_setting_t *server;
219
220 int i = 0;
221
222 while (config_setting_length(server_list)) {
223
224 server = config_setting_get_elem(server_list, 0);
225
226 if (server == NULL) {
227 return 0;
228 }
229
230 // Proceed only if all parts are present
231 if (config_setting_lookup_string(server, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE ||
232 config_setting_lookup_int (server, NAME_PORT, &bs_port) == CONFIG_FALSE ||
233 config_setting_lookup_string(server, NAME_ADDRESS, &bs_address) == CONFIG_FALSE ) {
234 goto next;
235 }
236
237 if (strlen(bs_public_key) != 64) {
238 syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %s.\n", i, NAME_PUBLIC_KEY, bs_public_key);
239 goto next;
240 }
241
242 // not (1 <= port <= 65535)
243 if (bs_port < 1 || bs_port > 65535) {
244 syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %d.\n", i, NAME_PORT, bs_port);
245 goto next;
246 }
247
248 const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
249 hex_string_to_bin((char *)bs_public_key));
250
251 if (!address_resolved) {
252 syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %s.\n", i, NAME_ADDRESS, bs_address);
253 goto next;
254 }
255
256 syslog(LOG_DEBUG, "Successfully connected to %s:%d %s\n", bs_address, bs_port, bs_public_key);
257
258next:
259 // config_setting_lookup_string() allocates string inside and doesn't allow us to free it
260 // so in order to reuse `bs_public_key` and `bs_address` we have to remove the element
261 // which will cause libconfig to free allocated strings
262 config_setting_remove_elem(server_list, 0);
263 i++;
264 }
265
266 config_destroy(&cfg);
267
268 return 1;
269}
270
271// Checks if we are connected to the DHT
272//
273// returns 1 on success
274// 0 on failure
275
276int is_conencted(DHT *dht, int port, int enable_lan_discovery)
277{
278 uint16_t htons_port = htons(port);
279
280 int i;
281
282 for (i = 0; i < 100; i ++) {
283 do_DHT(dht);
284
285 if (enable_lan_discovery) {
286 send_LANdiscovery(htons_port, dht->c);
287 }
288
289 networking_poll(dht->c->lossless_udp->net);
290
291 if (DHT_isconnected(dht)) {
292 return 1;
293 }
294
295 sleep;
296 }
297
298 return 0;
299}
300
301// Prints public key
302
303void print_public_key(uint8_t *public_key)
304{
305 char buffer[64 + 1];
306 int index = 0;
307
308 int i;
309
310 for (i = 0; i < 32; i++) {
311 if (public_key[i] < 16) {
312 index += sprintf(buffer + index, "0");
313 }
314
315 index += sprintf(buffer + index, "%hhX", public_key[i]);
316 }
317
318 syslog(LOG_INFO, "Public Key: %s\n", buffer);
319
320 return;
321}
322
323int main(int argc, char *argv[])
324{
325 openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
326
327 if (argc < 2) {
328 syslog(LOG_ERR, "Please specify a configuration file. Exiting.\n");
329 return 1;
330 }
331
332 char *cfg_file_path = argv[1];
333 char *pid_file_path, *keys_file_path;
334 int port;
335 int enable_ipv6;
336 int enable_lan_discovery;
337
338 if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery)) {
339 syslog(LOG_DEBUG, "General config read successfully\n");
340 } else {
341 syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
342 return 1;
343 }
344
345 // not (1 <= port <= 65535)
346 if (port < 1 || port > 65535) {
347 syslog(LOG_ERR, "Invalid port: %d, must be 1 <= port <= 65535. Exiting.\n", port);
348 return 1;
349 }
350
351 // Check if the PID file exists
352 if (fopen(pid_file_path, "r")) {
353 syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists. Exiting.\n", pid_file_path);
354 return 1;
355 }
356
357 IP ip;
358 ip_init(&ip, enable_ipv6);
359
360 DHT *dht = new_DHT(new_net_crypto(new_networking(ip, port)));
361
362 if (dht == NULL) {
363 syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n");
364 return 1;
365 }
366
367 if (enable_lan_discovery) {
368 LANdiscovery_init(dht);
369 }
370
371 if (manage_keys(dht, keys_file_path)) {
372 syslog(LOG_DEBUG, "Keys are managed successfully\n");
373 } else {
374 syslog(LOG_ERR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
375 return 1;
376 }
377
378 if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
379 syslog(LOG_DEBUG, "List of bootstrap servers read successfully\n");
380 } else {
381 syslog(LOG_ERR, "Couldn't read list of bootstrap servers in %s. Exiting.\n", cfg_file_path);
382 return 1;
383 }
384
385 if (is_conencted(dht, port, enable_lan_discovery)) {
386 syslog(LOG_INFO, "Successfully connected to DHT\n");
387 } else {
388 syslog(LOG_ERR, "Couldn't connect to the DHT. Check settings and network connections. Exiting.\n");
389 return 1;
390 }
391
392 print_public_key(dht->c->self_public_key);
393
394 // Write the PID file
395 FILE *pidf = fopen(pid_file_path, "w");
396
397 if (pidf == NULL) {
398 syslog(LOG_ERR, "Can't open the PID file for writing: %s. Exiting.\n", pid_file_path);
399 return 1;
400 }
401
402 free(pid_file_path);
403 free(keys_file_path);
404
405 // Fork off from the parent process
406 pid_t pid = fork();
407
408 if (pid < 0) {
409 syslog(LOG_ERR, "Forking failed. Exiting.\n");
410 return 1;
411 }
412
413 if (pid > 0) {
414 syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid);
415
416 return 0;
417 }
418
419 // Change the file mode mask
420 umask(0);
421
422 fprintf(pidf, "%d\n", pid);
423 fclose(pidf);
424
425 // Create a new SID for the child process
426 if (setsid() < 0) {
427 syslog(LOG_ERR, "SID creation failure. Exiting.\n");
428 return 1;
429 }
430
431 // Change the current working directory
432 if ((chdir("/")) < 0) {
433 syslog(LOG_ERR, "Couldn't change working directory to '/'. Exiting.\n");
434 return 1;
435 }
436
437 // Go quiet
438 close(STDOUT_FILENO);
439 close(STDIN_FILENO);
440 close(STDERR_FILENO);
441
442 uint64_t last_LANdiscovery = 0;
443 uint16_t htons_port = htons(port);
444
445 while (1) {
446 do_DHT(dht);
447
448 if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
449 send_LANdiscovery(htons_port, dht->c);
450 last_LANdiscovery = unix_time();
451 }
452
453 networking_poll(dht->c->lossless_udp->net);
454
455 sleep;
456 }
457
458 return 1;
459}