summaryrefslogtreecommitdiff
path: root/other/bootstrap_serverdaemon
diff options
context:
space:
mode:
authorMaxim Biro <nurupo.contributions@gmail.com>2014-01-19 00:43:31 -0500
committerMaxim Biro <nurupo.contributions@gmail.com>2014-01-19 04:34:58 -0500
commit28edc23329ff630a7ce3d594f2d972d47eb5c6f9 (patch)
tree2e9f77fe204670fe642ce841e735abc5dd8d7bf7 /other/bootstrap_serverdaemon
parent91b06da0c3aa399edf7e00e33a8f380b42e44f43 (diff)
Improved DHT bootstrap daemon
Supports "unlimited" number of bootstrap nodes in the config file, instead of just 32. PID and keys file paths are not limited by 512 chars anymore. Doesn't read the whole list of bootstrap servers into a global datastructure that just sits there after being processed once -- reads bootstrap servers one by one, processing them between reads. Supports IPv6. Has an option for IPv6. Supports LAN discovery. Has an option for LAN discovery. Writes to syslog. Uses new functions introduced in the core. `status` in the bash script now works. Has a simple README, with instructions for Debian-based distros.
Diffstat (limited to 'other/bootstrap_serverdaemon')
-rw-r--r--other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c460
-rw-r--r--other/bootstrap_serverdaemon/Makefile.inc8
-rw-r--r--other/bootstrap_serverdaemon/README34
-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.c446
7 files changed, 532 insertions, 506 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..2607bfee 100644
--- a/other/bootstrap_serverdaemon/Makefile.inc
+++ b/other/bootstrap_serverdaemon/Makefile.inc
@@ -1,9 +1,9 @@
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 = \ 5DHT_bootstrap_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 = \ 8DHT_bootstrap_daemon_CFLAGS = \
9 -I$(top_srcdir)/other/bootstrap_serverdaemon \ 9 -I$(top_srcdir)/other/bootstrap_serverdaemon \
@@ -22,5 +22,5 @@ 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
diff --git a/other/bootstrap_serverdaemon/README b/other/bootstrap_serverdaemon/README
new file mode 100644
index 00000000..d1444ee6
--- /dev/null
+++ b/other/bootstrap_serverdaemon/README
@@ -0,0 +1,34 @@
1Instructions 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: `mv tox-dht-bootstrap-server-daemon /etc/init.d/tox-dht-bootstrap-server-daemon`
13
144. Give the right permissions to this file: `chmod 755 /etc/init.d/tox-dht-bootstrap-server-daemon`
15
165. Execute: `update-rc.d tox-dht-bootstrap-server-daemon defaults`
17
186. Start the service: `service tox-dht-bootstrap-server-daemon start`
19
207. Verify that the service is running: `service tox-dht-bootstrap-server-daemon status`
21
22You can see daemon's log with `grep "tox-dht-bootstrap-server-daemon" /var/log/syslog`
23
24Troubleshooting:
25
261. Check the log for errors with `grep "tox-dht-bootstrap-server-daemon" /var/log/syslog`
27
282. Check that paths in the beginning of `/etc/init.d/tox-dht-bootstrap-server-daemon` are valid
29
303. Make sure that `PIDFILE` from `/etc/init.d/tox-dht-bootstrap-server-daemon` matches with the `pid_file_path` from `conf`
31
324. Make sure you have write premmision to keys and pid files
33
345. Make sure you have read premission to 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..b24e1e6c
--- /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 premission 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..20639af8 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..9aa28533
--- /dev/null
+++ b/other/bootstrap_serverdaemon/tox-dht-bootstrap-server-daemon.c
@@ -0,0 +1,446 @@
1/* tox-dht-bootstrap-server-daemon
2 *
3 * A simple DHT boostrap 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> /* pid_t */
25#include <sys/stat.h> /* umask */
26#include <unistd.h> /* POSIX things */
27#include <syslog.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#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// Uses the already existing key or creates one if it didn't exist
57//
58// retirns 1 on success
59// 0 on failure - no keys were read or stored
60
61int manage_keys(DHT *dht, char *keys_file_path)
62{
63 const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
64 uint8_t keys[KEYS_SIZE];
65 FILE *keys_file;
66
67 // Check if file exits, proceed to open and load keys
68 keys_file = fopen(keys_file_path, "r");
69 if (keys_file != NULL) {
70 size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
71
72 if (read_size != KEYS_SIZE) {
73 return 0;
74 }
75
76 load_keys(dht->c, keys);
77 } else {
78 // Otherwise save new keys
79 new_keys(dht->c);
80 save_keys(dht->c, keys);
81
82 keys_file = fopen(keys_file_path, "w");
83
84 if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file) != KEYS_SIZE) {
85 return 0;
86 }
87 }
88
89 fclose(keys_file);
90
91 return 1;
92}
93
94// Gets general config options
95//
96// Important: you are responsibl for freeing `pid_file_path` and `keys_file_path`
97//
98// returns 1 on success
99// 0 on failure, doesn't modify any data pointed by arguments
100
101int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6, int *enable_lan_discovery)
102{
103 config_t cfg;
104
105 const char *NAME_PORT = "port";
106 const char *NAME_PID_FILE = "pid_file_path";
107 const char *NAME_KEYS_FILE = "keys_file_path";
108 const char *NAME_ENABLE_IPV6 = "enable_ipv6";
109 const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
110
111 config_init(&cfg);
112
113 // Read the file. If there is an error, report it and exit.
114 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
115 syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
116 config_destroy(&cfg);
117 return 0;
118 }
119
120 // Get port
121 if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
122 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
123 syslog(LOG_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
124 *port = DEFAULT_PORT;
125 }
126
127 // Get PID file location
128 const char *tmp_pid_file;
129
130 if (config_lookup_string(&cfg, NAME_PID_FILE, &tmp_pid_file) == CONFIG_FALSE) {
131 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE);
132 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_PID_FILE, DEFAULT_PID_FILE_PATH);
133 tmp_pid_file = DEFAULT_PID_FILE_PATH;
134 }
135 *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
136 strcpy(*pid_file_path, tmp_pid_file);
137
138 // Get keys file location
139 const char *tmp_keys_file;
140
141 if (config_lookup_string(&cfg, NAME_KEYS_FILE, &tmp_keys_file) == CONFIG_FALSE) {
142 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE);
143 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE, DEFAULT_KEYS_FILE_PATH);
144 tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
145 }
146 *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
147 strcpy(*keys_file_path, tmp_keys_file);
148
149 // Get IPv6 option
150 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
151 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
152 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
153 *enable_ipv6 = DEFAULT_ENABLE_IPV6;
154 }
155
156 // Get LAN discovery option
157 if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
158 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
159 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
160 *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
161 }
162
163 config_destroy(&cfg);
164
165 syslog(LOG_DEBUG, "Successfully read:\n");
166 syslog(LOG_DEBUG, "'%s': %s\n", NAME_PID_FILE, *pid_file_path);
167 syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE, *keys_file_path);
168 syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port);
169 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
170 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
171
172 return 1;
173}
174
175// Bootstraps servers listed in the config file
176//
177// returns 1 on success
178// 0 on failure, either no or only some servers were bootstraped
179
180int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6)
181{
182 const char *NAME_BOOTSTRAP_SERVERS = "bootstrap_servers";
183
184 const char *NAME_PUBLIC_KEY = "public_key";
185 const char *NAME_PORT = "port";
186 const char *NAME_ADDRESS = "address";
187
188 config_t cfg;
189
190 config_init(&cfg);
191
192 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
193 syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
194 config_destroy(&cfg);
195 return 0;
196 }
197
198 config_setting_t *server_list = config_lookup(&cfg, NAME_BOOTSTRAP_SERVERS);
199
200 if (server_list == NULL) {
201 syslog(LOG_ERR, "No '%s' setting in configuration file.\n", NAME_BOOTSTRAP_SERVERS);
202 config_destroy(&cfg);
203 return 0;
204 }
205
206 int bs_port;
207 const char *bs_address;
208 const char *bs_public_key;
209
210 config_setting_t *server;
211
212 int i = 0;
213
214 while (config_setting_length(server_list)) {
215
216 server = config_setting_get_elem(server_list, 0);
217
218 if (server == NULL) {
219 return 0;
220 }
221
222 /* Proceed only if all parts are present */
223 if (config_setting_lookup_string(server, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE ||
224 config_setting_lookup_int (server, NAME_PORT, &bs_port) == CONFIG_FALSE ||
225 config_setting_lookup_string(server, NAME_ADDRESS, &bs_address) == CONFIG_FALSE ) {
226 goto next;
227 }
228
229 if (strlen(bs_public_key) != 64) {
230 syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %s.\n", i, NAME_PUBLIC_KEY, bs_public_key);
231 goto next;
232 }
233
234 // not (1 <= port <= 65535)
235 if (bs_port < 1 || bs_port > 65535) {
236 syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %d.\n", i, NAME_PORT, bs_port);
237 goto next;
238 }
239
240 const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port), hex_string_to_bin((char*)bs_public_key));
241
242 if (!address_resolved) {
243 syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %s.\n", i, NAME_ADDRESS, bs_address);
244 goto next;
245 }
246
247 syslog(LOG_DEBUG, "Successfully connected to %s:%d %s\n", bs_address, bs_port, bs_public_key);
248
249 next:
250 // config_setting_lookup_string() allocates string inside and doesn't allow us to free it
251 // so in order to reuse `bs_public_key` and `bs_address` we have to remove the element
252 // which will cause libconfig to free allocated strings
253 config_setting_remove_elem(server_list, 0);
254 i++;
255 }
256
257 config_destroy(&cfg);
258
259 return 1;
260}
261
262// Checks if we are connected to the DHT
263//
264// returns 1 on success
265// 0 on failure
266
267int is_conencted(DHT *dht, int port, int enable_lan_discovery)
268{
269 uint16_t htons_port = htons(port);
270
271 int i;
272 for (i = 0; i < 100; i ++) {
273 do_DHT(dht);
274
275 if (enable_lan_discovery) {
276 send_LANdiscovery(htons_port, dht->c);
277 }
278
279 networking_poll(dht->c->lossless_udp->net);
280
281 if (DHT_isconnected(dht)) {
282 return 1;
283 }
284
285 sleep;
286 }
287
288 return 0;
289}
290
291// Prints public key
292
293void print_public_key(uint8_t *public_key)
294{
295 char buffer[64 + 1];
296 int index = 0;
297
298 int i;
299 for (i = 0; i < 32; i++) {
300 if (public_key[i] < 16) {
301 index += sprintf(buffer + index, "0");
302 }
303 index += sprintf(buffer + index, "%hhX", public_key[i]);
304 }
305
306 syslog(LOG_INFO, "Public Key: %s\n", buffer);
307
308 return;
309}
310
311int main(int argc, char *argv[])
312{
313 openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
314
315 if (argc < 2) {
316 syslog(LOG_ERR, "Please specify a configuration file. Exiting.\n");
317 return 1;
318 }
319
320 char *cfg_file_path = argv[1];
321 char *pid_file_path, *keys_file_path;
322 int port;
323 int enable_ipv6;
324 int enable_lan_discovery;
325
326 if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery)) {
327 syslog(LOG_DEBUG, "General config read successfully\n");
328 } else {
329 syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
330 return 1;
331 }
332
333 // not (1 <= port <= 65535)
334 if (port < 1 || port > 65535) {
335 syslog(LOG_ERR, "Invalid port: %d, must be 1 <= port <= 65535. Exiting.\n", port);
336 return 1;
337 }
338
339 // Check if the PId file exists
340 if (fopen(pid_file_path, "r")) {
341 syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists. Exiting.\n", pid_file_path);
342 return 1;
343 }
344
345 IP ip;
346 ip_init(&ip, enable_ipv6);
347
348 DHT *dht = new_DHT(new_net_crypto(new_networking(ip, port)));
349 if (dht == NULL) {
350 syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n");
351 return 1;
352 }
353
354 if (enable_lan_discovery) {
355 LANdiscovery_init(dht);
356 }
357
358 if (manage_keys(dht, keys_file_path)) {
359 syslog(LOG_DEBUG, "Keys are managed successfully\n");
360 } else {
361 syslog(LOG_ERR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
362 return 1;
363 }
364
365 if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
366 syslog(LOG_DEBUG, "List of bootstrap servers read successfully\n");
367 } else {
368 syslog(LOG_ERR, "Couldn't read list of bootstrap servers in %s. Exiting.\n", cfg_file_path);
369 return 1;
370 }
371
372 if (is_conencted(dht, port, enable_lan_discovery)) {
373 syslog(LOG_INFO, "Successfully connected to DHT\n");
374 } else {
375 syslog(LOG_ERR, "Couldn't connect to the DHT. Check settings and network connections. Exiting.\n");
376 return 1;
377 }
378
379 print_public_key(dht->c->self_public_key);
380
381 // Write the PID file
382 FILE *pidf = fopen(pid_file_path, "w");
383 if (pidf == NULL) {
384 syslog(LOG_ERR, "Can't open the PID file for writing: %s. Exiting.\n", pid_file_path);
385 return 1;
386 }
387
388 free(pid_file_path);
389 free(keys_file_path);
390
391 // Fork off from the parent process
392 pid_t pid = fork();
393
394 if (pid < 0) {
395 syslog(LOG_ERR, "Forking failed. Exiting.\n");
396 return 1;
397 }
398
399 if (pid > 0) {
400 syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid);
401
402 return 0;
403 }
404
405 // Change the file mode mask
406 umask(0);
407
408 fprintf(pidf, "%d\n", pid);
409 fclose(pidf);
410
411 /* Create a new SID for the child process */
412
413 if (setsid() < 0) {
414 syslog(LOG_ERR, "SID creation failure. Exiting.\n");
415 return 1;
416 }
417
418 /* Change the current working directory */
419 if ((chdir("/")) < 0) {
420 syslog(LOG_ERR, "Couldn't change working directory to '/'. Exiting.\n");
421 return 1;
422 }
423
424 /* Go quiet */
425 close(STDOUT_FILENO);
426 close(STDIN_FILENO);
427 close(STDERR_FILENO);
428
429 uint64_t last_LANdiscovery = 0;
430 uint16_t htons_port = htons(port);
431
432 while (1) {
433 do_DHT(dht);
434
435 if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
436 send_LANdiscovery(htons_port, dht->c);
437 last_LANdiscovery = unix_time();
438 }
439
440 networking_poll(dht->c->lossless_udp->net);
441
442 sleep;
443 }
444
445 return 1;
446}