summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2016-01-04 22:43:36 -0500
committerirungentoo <irungentoo@gmail.com>2016-01-04 22:43:36 -0500
commitc6bed82d47aa39709bdd568fccc3847714ed1b74 (patch)
tree4e2dd8676a53e78a5b84e3abd68cdbe82a636737
parent760f20c9455c2ef33ec9d242f209a1543f6acaf4 (diff)
parent9d1efd594914629204d4cd1a84678daf67eb8068 (diff)
Merge branch 'tox-bootstrapd-docker-support' of https://github.com/nurupo/InsertProjectNameHere
-rw-r--r--build/Makefile.am2
-rw-r--r--other/DHT_bootstrap.c2
-rw-r--r--other/Makefile.inc4
-rw-r--r--other/bootstrap_daemon/Makefile.inc27
-rw-r--r--other/bootstrap_daemon/README.md137
-rw-r--r--other/bootstrap_daemon/docker/Dockerfile59
-rw-r--r--other/bootstrap_daemon/docker/get-nodes.py49
-rw-r--r--other/bootstrap_daemon/src/Makefile.inc38
-rw-r--r--other/bootstrap_daemon/src/command_line_arguments.c145
-rw-r--r--other/bootstrap_daemon/src/command_line_arguments.h42
-rw-r--r--other/bootstrap_daemon/src/config.c426
-rw-r--r--other/bootstrap_daemon/src/config.h52
-rw-r--r--other/bootstrap_daemon/src/config_defaults.h42
-rw-r--r--other/bootstrap_daemon/src/global.h34
-rw-r--r--other/bootstrap_daemon/src/log.c117
-rw-r--r--other/bootstrap_daemon/src/log.h64
-rw-r--r--other/bootstrap_daemon/src/tox-bootstrapd.c342
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.c730
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.service2
-rw-r--r--other/bootstrap_daemon/tox-bootstrapd.sh2
-rw-r--r--other/bootstrap_node_packets.c2
-rw-r--r--other/bootstrap_node_packets.h35
22 files changed, 1581 insertions, 772 deletions
diff --git a/build/Makefile.am b/build/Makefile.am
index c0e59645..ea844b3f 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -10,5 +10,5 @@ include ../toxencryptsave/Makefile.inc
10include ../toxav/Makefile.inc 10include ../toxav/Makefile.inc
11include ../other/Makefile.inc 11include ../other/Makefile.inc
12include ../testing/Makefile.inc 12include ../testing/Makefile.inc
13include ../other/bootstrap_daemon/Makefile.inc 13include ../other/bootstrap_daemon/src/Makefile.inc
14include ../auto_tests/Makefile.inc 14include ../auto_tests/Makefile.inc
diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c
index 52e84315..16dc87b9 100644
--- a/other/DHT_bootstrap.c
+++ b/other/DHT_bootstrap.c
@@ -40,7 +40,7 @@
40#include "../testing/misc_tools.c" 40#include "../testing/misc_tools.c"
41 41
42#ifdef DHT_NODE_EXTRA_PACKETS 42#ifdef DHT_NODE_EXTRA_PACKETS
43#include "./bootstrap_node_packets.c" 43#include "./bootstrap_node_packets.h"
44 44
45#define DHT_VERSION_NUMBER 1 45#define DHT_VERSION_NUMBER 1
46#define DHT_MOTD "This is a test motd" 46#define DHT_MOTD "This is a test motd"
diff --git a/other/Makefile.inc b/other/Makefile.inc
index 368a32f2..c86b7922 100644
--- a/other/Makefile.inc
+++ b/other/Makefile.inc
@@ -2,7 +2,9 @@ bin_PROGRAMS += DHT_bootstrap
2 2
3DHT_bootstrap_SOURCES = ../other/DHT_bootstrap.c \ 3DHT_bootstrap_SOURCES = ../other/DHT_bootstrap.c \
4 ../toxcore/DHT.h \ 4 ../toxcore/DHT.h \
5 ../toxcore/friend_requests.h 5 ../toxcore/friend_requests.h \
6 ../other/bootstrap_node_packets.h \
7 ../other/bootstrap_node_packets.c
6 8
7DHT_bootstrap_CFLAGS = -I$(top_srcdir)/other \ 9DHT_bootstrap_CFLAGS = -I$(top_srcdir)/other \
8 $(LIBSODIUM_CFLAGS) \ 10 $(LIBSODIUM_CFLAGS) \
diff --git a/other/bootstrap_daemon/Makefile.inc b/other/bootstrap_daemon/Makefile.inc
deleted file mode 100644
index f274aba0..00000000
--- a/other/bootstrap_daemon/Makefile.inc
+++ /dev/null
@@ -1,27 +0,0 @@
1if BUILD_DHT_BOOTSTRAP_DAEMON
2
3bin_PROGRAMS += tox-bootstrapd
4
5tox_bootstrapd_SOURCES = \
6 ../other/bootstrap_daemon/tox-bootstrapd.c
7
8tox_bootstrapd_CFLAGS = \
9 -I$(top_srcdir)/other/bootstrap_daemon \
10 $(LIBSODIUM_CFLAGS) \
11 $(NACL_CFLAGS) \
12 $(LIBCONFIG_CFLAGS)
13
14tox_bootstrapd_LDADD = \
15 $(LIBSODIUM_LDFLAGS) \
16 $(NACL_LDFLAGS) \
17 libtoxcore.la \
18 $(LIBCONFIG_LIBS) \
19 $(LIBSODIUM_LIBS) \
20 $(NACL_LIBS)
21
22endif
23
24EXTRA_DIST += \
25 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.conf \
26 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.sh
27
diff --git a/other/bootstrap_daemon/README.md b/other/bootstrap_daemon/README.md
index e77e3ae0..93e390ef 100644
--- a/other/bootstrap_daemon/README.md
+++ b/other/bootstrap_daemon/README.md
@@ -1,17 +1,29 @@
1#Instructions 1#Instructions
2 2
3- [For `systemd` users](#systemd) 3- [For `systemd` users](#systemd)
4 - [Setting up](#systemd-setting-up)
5 - [Updating](#systemd-updating)
4 - [Troubleshooting](#systemd-troubleshooting) 6 - [Troubleshooting](#systemd-troubleshooting)
5<br> 7<br>
6- [For `init.d` users](#initd) 8- [For `SysVinit` users](#sysvinit)
7 - [Troubleshooting](#initd-troubleshooting) 9 - [Setting up](#sysvinit-setting-up)
10 - [Updating](#sysvinit-updating)
11 - [Troubleshooting](#sysvinit-troubleshooting)
12<br>
13- [For `Docker` users](#docker)
14 - [Setting up](#docker-setting-up)
15 - [Updating](#docker-updating)
16 - [Troubleshooting](#docker-troubleshooting)
8 17
9 18
10These instructions are primarily tested on Debian Linux, Wheezy for init.d and Jessie for systemd, but they should work on other POSIX-compliant systems too. 19These instructions are primarily tested on Debian Linux, Wheezy for SysVinit and Jessie for systemd, but they should work on other POSIX-compliant systems too.
11 20
12 21
13<a name="systemd" /> 22<a name="systemd" />
14##For `systemd` users: 23##For `systemd` users
24
25<a name="systemd-setting-up" />
26###Setting up
15 27
16For security reasons we run the daemon under its own user. 28For security reasons we run the daemon under its own user.
17 29
@@ -56,8 +68,31 @@ Get your public key and check that the daemon initialized correctly:
56sudo grep "tox-bootstrapd" /var/log/syslog 68sudo grep "tox-bootstrapd" /var/log/syslog
57``` 69```
58 70
71<a name="systemd-updating" />
72###Updating
73
74You want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.
75
76To update the daemon first stop it:
77
78```sh
79sudo systemctl stop tox-bootstrapd.service
80```
81
82Then update your toxcore git repository, rebuild the toxcore and the daemon and make sure to install them.
83
84Check if `tox-bootstrapd.service` in toxcore git repository was modified since the last time you copied it, as you might need to update it too.
85
86After all of this is done, simply start the daemon back again:
87
88```sh
89sudo systemctl start tox-bootstrapd.service
90```
91
92Note that `tox-bootstrapd.service` file might
93
59<a name="systemd-troubleshooting" /> 94<a name="systemd-troubleshooting" />
60###Troubleshooting: 95###Troubleshooting
61 96
62- Check daemon's status: 97- Check daemon's status:
63```sh 98```sh
@@ -80,8 +115,11 @@ sudo journalctl -f _SYSTEMD_UNIT=tox-bootstrapd.service
80- Make sure tox-bootstrapd location matches its path in tox-bootstrapd.service file. 115- Make sure tox-bootstrapd location matches its path in tox-bootstrapd.service file.
81 116
82 117
83<a name="initd" /> 118<a name="sysvinit" />
84##For `init.d` users 119##For `SysVinit` users
120
121<a name="sysvinit-setting-up" />
122###Setting up
85 123
86For security reasons we run the daemon under its own user. 124For security reasons we run the daemon under its own user.
87 125
@@ -126,8 +164,29 @@ Get your public key and check that the daemon initialized correctly:
126sudo grep "tox-bootstrapd" /var/log/syslog 164sudo grep "tox-bootstrapd" /var/log/syslog
127``` 165```
128 166
129<a name="initd-troubleshooting" /> 167<a name="sysvinit-updating" />
130###Troubleshooting: 168###Updating
169
170You want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.
171
172To update the daemon first stop it:
173
174```sh
175sudo service tox-bootstrapd stop
176```
177
178Then update your toxcore git repository, rebuild the toxcore and the daemon and make sure to install them.
179
180Check if `tox-bootstrapd.sh` in toxcore git repository was modified since the last time you copied it, as you might need to update it too.
181
182After all of this is done, simply start the daemon back again:
183
184```sh
185sudo service tox-bootstrapd start
186```
187
188<a name="sysvinit-troubleshooting" />
189###Troubleshooting
131 190
132- Check daemon's status: 191- Check daemon's status:
133```sh 192```sh
@@ -146,3 +205,63 @@ sudo grep "tox-bootstrapd" /var/log/syslog
146- Make sure tox-bootstrapd has read permission for the config file. 205- Make sure tox-bootstrapd has read permission for the config file.
147 206
148- Make sure tox-bootstrapd location matches its path in the `/etc/init.d/tox-bootstrapd` init script. 207- Make sure tox-bootstrapd location matches its path in the `/etc/init.d/tox-bootstrapd` init script.
208
209
210<a name="docker" />
211##For `Docker` users:
212
213<a name="docker-setting-up" />
214###Setting up
215
216If you are familiar with Docker and would rather run the daemon in a Docker container, run the following from this directory:
217
218```sh
219sudo docker build -t tox-bootstrapd docker/
220
221sudo useradd --home-dir /var/lib/tox-bootstrapd --create-home --system --shell /sbin/nologin --comment "Account to run Tox's DHT bootstrap daemon" --user-group tox-bootstrapd
222sudo chmod 700 /var/lib/tox-bootstrapd
223
224sudo docker run -d --name tox-bootstrapd --restart always -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ -p 443:443 -p 3389:3389 -p 33445:33445 -p 33445:33445/udp tox-bootstrapd
225```
226
227We create a new user and protect its home directory in order to mount it in the Docker image, so that the kyepair the daemon uses would be stored on the host system, which makes it less likely that you would loose the keypair while playing with or updating the Docker container.
228
229You can check logs for your public key or any errors:
230```sh
231sudo docker logs tox-bootstrapd
232```
233
234Note that the Docker container runs a script which pulls a list of bootstrap nodes off https://nodes.tox.chat/ and adds them in the config file.
235
236<a name="docker-updating" />
237###Updating
238
239You want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.
240
241To update the daemon, all you need is to erase current container with its image:
242
243```sh
244sudo docker stop tox-bootstrapd
245sudo docker rm tox-bootstrapd
246sudo docker rmi tox-bootstrapd
247```
248
249Then rebuild and run the image again:
250
251```sh
252sudo docker build -t tox-bootstrapd docker/
253sudo docker run -d --name tox-bootstrapd --restart always -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ -p 443:443 -p 3389:3389 -p 33445:33445 -p 33445:33445/udp tox-bootstrapd
254```
255
256<a name="docker-troubleshooting" />
257###Troubleshooting
258
259- Check if the container is running:
260```sh
261sudo docker ps -a
262```
263
264- Check the log for errors:
265```sh
266sudo docker logs tox-bootstrapd
267```
diff --git a/other/bootstrap_daemon/docker/Dockerfile b/other/bootstrap_daemon/docker/Dockerfile
new file mode 100644
index 00000000..ef9d525c
--- /dev/null
+++ b/other/bootstrap_daemon/docker/Dockerfile
@@ -0,0 +1,59 @@
1FROM debian:jessie
2
3# get all deps
4RUN apt-get update && apt-get install -y \
5 build-essential \
6 libtool \
7 autotools-dev \
8 automake \
9 checkinstall \
10 check \
11 git \
12 yasm \
13 libsodium-dev \
14 libconfig-dev \
15 python3 \
16 && apt-get clean \
17 && rm -rf /var/lib/apt/lists/*
18
19# install toxcore and daemon
20WORKDIR /root/
21RUN git clone https://github.com/irungentoo/toxcore
22WORKDIR /root/toxcore/
23RUN ./autogen.sh
24RUN ./configure --enable-daemon
25RUN make -j`nproc`
26RUN make install -j`nproc`
27RUN ldconfig
28
29WORKDIR /root/toxcore/other/bootstrap_daemon/
30
31# add new user
32RUN useradd --home-dir /var/lib/tox-bootstrapd --create-home \
33 --system --shell /sbin/nologin \
34 --comment "Account to run Tox's DHT bootstrap daemon" \
35 --user-group tox-bootstrapd
36RUN chmod 700 /var/lib/tox-bootstrapd
37
38RUN cp tox-bootstrapd.conf /etc/tox-bootstrapd.conf
39
40# remove all the example bootstrap nodes from the config file
41RUN N=-1 && \
42 while grep -q "bootstrap_nodes =" /etc/tox-bootstrapd.conf; \
43 do \
44 head -n $N tox-bootstrapd.conf > /etc/tox-bootstrapd.conf; \
45 N=$((N-1)); \
46 done
47
48# add bootstrap nodes from https://nodes.tox.chat/
49RUN python3 docker/get-nodes.py >> /etc/tox-bootstrapd.conf
50
51USER tox-bootstrapd
52
53ENTRYPOINT /usr/local/bin/tox-bootstrapd \
54 --config /etc/tox-bootstrapd.conf \
55 --log-backend stdout \
56 --foreground
57
58EXPOSE 443 3389 33445
59EXPOSE 33445/udp
diff --git a/other/bootstrap_daemon/docker/get-nodes.py b/other/bootstrap_daemon/docker/get-nodes.py
new file mode 100644
index 00000000..9a284748
--- /dev/null
+++ b/other/bootstrap_daemon/docker/get-nodes.py
@@ -0,0 +1,49 @@
1#!/usr/bin/env python3
2"""
3Copyright (c) 2016 by nurupo <nurupo.contributions@gmail.com>
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22"""
23
24# Gets a list of nodes from https://nodes.tox.chat/json and prints them out
25# in the format of tox-bootstrapd config file.
26
27import urllib.request
28import json
29
30response = urllib.request.urlopen('https://nodes.tox.chat/json')
31raw_json = response.read().decode('ascii', 'ignore')
32nodes = json.loads(raw_json)['nodes']
33
34output = 'bootstrap_nodes = ('
35
36for node in nodes:
37 node_output = ' { // ' + node['maintainer'] + '\n'
38 node_output += ' public_key = "' + node['public_key'] + '"\n'
39 node_output += ' port = ' + str(node['port']) + '\n'
40 node_output += ' address = "'
41 if len(node['ipv4']) > 4:
42 output += node_output + node['ipv4'] + '"\n },\n'
43 if len(node['ipv6']) > 4:
44 output += node_output + node['ipv6'] + '"\n },\n'
45
46# remove last comma
47output = output[:-2] + '\n)\n'
48
49print(output)
diff --git a/other/bootstrap_daemon/src/Makefile.inc b/other/bootstrap_daemon/src/Makefile.inc
new file mode 100644
index 00000000..a0d75fa0
--- /dev/null
+++ b/other/bootstrap_daemon/src/Makefile.inc
@@ -0,0 +1,38 @@
1if BUILD_DHT_BOOTSTRAP_DAEMON
2
3bin_PROGRAMS += tox-bootstrapd
4
5tox_bootstrapd_SOURCES = \
6 ../other/bootstrap_daemon/src/command_line_arguments.c \
7 ../other/bootstrap_daemon/src/command_line_arguments.h \
8 ../other/bootstrap_daemon/src/config.c \
9 ../other/bootstrap_daemon/src/config_defaults.h \
10 ../other/bootstrap_daemon/src/config.h \
11 ../other/bootstrap_daemon/src/log.c \
12 ../other/bootstrap_daemon/src/log.h \
13 ../other/bootstrap_daemon/src/tox-bootstrapd.c \
14 ../other/bootstrap_node_packets.c \
15 ../other/bootstrap_node_packets.h
16
17
18tox_bootstrapd_CFLAGS = \
19 -I$(top_srcdir)/other/bootstrap_daemon \
20 $(LIBSODIUM_CFLAGS) \
21 $(NACL_CFLAGS) \
22 $(LIBCONFIG_CFLAGS)
23
24tox_bootstrapd_LDADD = \
25 $(LIBSODIUM_LDFLAGS) \
26 $(NACL_LDFLAGS) \
27 libtoxcore.la \
28 $(LIBCONFIG_LIBS) \
29 $(LIBSODIUM_LIBS) \
30 $(NACL_LIBS)
31
32endif
33
34EXTRA_DIST += \
35 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.conf \
36 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.service \
37 $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.sh
38
diff --git a/other/bootstrap_daemon/src/command_line_arguments.c b/other/bootstrap_daemon/src/command_line_arguments.c
new file mode 100644
index 00000000..187fa786
--- /dev/null
+++ b/other/bootstrap_daemon/src/command_line_arguments.c
@@ -0,0 +1,145 @@
1/* command_line_arguments.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Command line argument handling.
5 *
6 * Copyright (C) 2015-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 "command_line_arguments.h"
26
27#include "global.h"
28
29#include <getopt.h>
30
31#include <stdlib.h>
32#include <string.h>
33
34
35/**
36 * Prints --help message
37 */
38void print_help()
39{
40 // 2 space ident
41 // make sure all lines fit into 80 columns
42 // make sure options are listed in alphabetical order
43 write_log(LOG_LEVEL_INFO,
44 "Usage: tox-bootstrapd [OPTION]... --config=FILE_PATH\n"
45 "\n"
46 "Options:\n"
47 " --config=FILE_PATH Specify path to the config file.\n"
48 " This is a required option.\n"
49 " Set FILE_PATH to a path to an empty file in order to\n"
50 " use default settings.\n"
51 " --foreground Run the daemon in foreground. The daemon won't fork\n"
52 " (detach from the terminal) and won't use the PID file.\n"
53 " --help Print this help message.\n"
54 " --log-backend=BACKEND Specify which logging backend to use.\n"
55 " Valid BACKEND values (case sensetive):\n"
56 " syslog Writes log messages to syslog.\n"
57 " Default option when no --log-backend is\n"
58 " specified.\n"
59 " stdout Writes log messages to stdout/stderr.\n"
60 " --version Print version information.\n");
61}
62
63void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground)
64{
65 if (argc < 2) {
66 write_log(LOG_LEVEL_ERROR, "Error: No arguments provided.\n\n");
67 print_help();
68 exit(1);
69 }
70
71 opterr = 0;
72
73 static struct option long_options[] = {
74 {"config", required_argument, 0, 'c'}, // required option
75 {"foreground", no_argument, 0, 'f'},
76 {"help", no_argument, 0, 'h'},
77 {"log-backend", required_argument, 0, 'l'}, // optional, defaults to syslog
78 {"version", no_argument, 0, 'v'},
79 {0, 0, 0, 0 }
80 };
81
82 bool cfg_file_path_set = false;
83 bool log_backend_set = false;
84
85 *run_in_foreground = false;
86
87 int opt;
88
89 while ((opt = getopt_long(argc, argv, ":", long_options, NULL)) != -1) {
90
91 switch (opt) {
92
93 case 'c':
94 *cfg_file_path = optarg;
95 cfg_file_path_set = true;
96 break;
97
98 case 'f':
99 *run_in_foreground = true;
100 break;
101
102 case 'h':
103 print_help();
104 exit(0);
105
106 case 'l':
107 if (strcmp(optarg, "syslog") == 0) {
108 *log_backend = LOG_BACKEND_SYSLOG;
109 log_backend_set = true;
110 } else if (strcmp(optarg, "stdout") == 0) {
111 *log_backend = LOG_BACKEND_STDOUT;
112 log_backend_set = true;
113 } else {
114 write_log(LOG_LEVEL_ERROR, "Error: Invalid BACKEND value for --log-backend option passed: %s\n\n", optarg);
115 print_help();
116 exit(1);
117 }
118 break;
119
120 case 'v':
121 write_log(LOG_LEVEL_INFO, "Version: %lu\n", DAEMON_VERSION_NUMBER);
122 exit(0);
123
124 case '?':
125 write_log(LOG_LEVEL_ERROR, "Error: Unrecognized option %s\n\n", argv[optind-1]);
126 print_help();
127 exit(1);
128
129 case ':':
130 write_log(LOG_LEVEL_ERROR, "Error: No argument provided for option %s\n\n", argv[optind-1]);
131 print_help();
132 exit(1);
133 }
134 }
135
136 if (!log_backend_set) {
137 *log_backend = LOG_BACKEND_SYSLOG;
138 }
139
140 if (!cfg_file_path_set) {
141 write_log(LOG_LEVEL_ERROR, "Error: The required --config option wasn't specified\n\n");
142 print_help();
143 exit(1);
144 }
145}
diff --git a/other/bootstrap_daemon/src/command_line_arguments.h b/other/bootstrap_daemon/src/command_line_arguments.h
new file mode 100644
index 00000000..c73cd15e
--- /dev/null
+++ b/other/bootstrap_daemon/src/command_line_arguments.h
@@ -0,0 +1,42 @@
1/* command_line_arguments.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Command line argument handling.
5 *
6 * Copyright (C) 2015-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#ifndef COMMAND_LINE_ARGUMENTS_H
26#define COMMAND_LINE_ARGUMENTS_H
27
28#include "log.h"
29
30/**
31 * Handles command line arguments, setting cfg_file_path and log_backend.
32 * Terminates the application if incorrect arguments are specified.
33 *
34 * @param argc Argc passed into main().
35 * @param argv Argv passed into main().
36 * @param cfg_file_path Sets to the provided by the user config file path.
37 * @param log_backend Sets to the provided by the user log backend option.
38 * @param run_in_foreground Sets to the provided by the user foreground option.
39 */
40void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground);
41
42#endif // COMMAND_LINE_ARGUMENTS_H
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}
diff --git a/other/bootstrap_daemon/src/config.h b/other/bootstrap_daemon/src/config.h
new file mode 100644
index 00000000..13cf929a
--- /dev/null
+++ b/other/bootstrap_daemon/src/config.h
@@ -0,0 +1,52 @@
1/* config.h
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#ifndef CONFIG_H
26#define CONFIG_H
27
28#include "../../../toxcore/DHT.h"
29
30/**
31 * Gets general config options from the config file.
32 *
33 * Important: You are responsible for freeing `pid_file_path` and `keys_file_path`
34 * also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports`
35 * and also `motd` iff `enable_motd` is set.
36 *
37 * @return 1 on success,
38 * 0 on failure, doesn't modify any data pointed by arguments.
39 */
40int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
41 int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
42 int *tcp_relay_port_count, int *enable_motd, char **motd);
43
44/**
45 * Bootstraps off nodes listed in the config file.
46 *
47 * @return 1 on success, some or no bootstrap nodes were added
48 * 0 on failure, a error accured while parsing config file.
49 */
50int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6);
51
52#endif // CONFIG_H
diff --git a/other/bootstrap_daemon/src/config_defaults.h b/other/bootstrap_daemon/src/config_defaults.h
new file mode 100644
index 00000000..17bffd3a
--- /dev/null
+++ b/other/bootstrap_daemon/src/config_defaults.h
@@ -0,0 +1,42 @@
1/* config_defaults.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Default config options for when they are missing in 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#ifndef CONFIG_DEFAULTS_H
26#define CONFIG_DEFAULTS_H
27
28#include "global.h"
29
30#define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid"
31#define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys"
32#define DEFAULT_PORT 33445
33#define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false
34#define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false
35#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
36#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false
37#define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly
38#define DEFAULT_TCP_RELAY_PORTS_COUNT 3
39#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false
40#define DEFAULT_MOTD DAEMON_NAME
41
42#endif // CONFIG_DEFAULTS_H
diff --git a/other/bootstrap_daemon/src/global.h b/other/bootstrap_daemon/src/global.h
new file mode 100644
index 00000000..9ae3ec45
--- /dev/null
+++ b/other/bootstrap_daemon/src/global.h
@@ -0,0 +1,34 @@
1/* global.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Globally used defines.
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#ifndef GLOBAL_H
26#define GLOBAL_H
27
28#define DAEMON_NAME "tox-bootstrapd"
29#define DAEMON_VERSION_NUMBER 2016010100UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day
30
31#define MIN_ALLOWED_PORT 1
32#define MAX_ALLOWED_PORT 65535
33
34#endif // GLOBAL_H
diff --git a/other/bootstrap_daemon/src/log.c b/other/bootstrap_daemon/src/log.c
new file mode 100644
index 00000000..d441b98e
--- /dev/null
+++ b/other/bootstrap_daemon/src/log.c
@@ -0,0 +1,117 @@
1/* log.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Logging utility with support of multipel logging backends.
5 *
6 * Copyright (C) 2015-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 "log.h"
26
27#include "global.h"
28
29#include <syslog.h>
30
31#include <stdarg.h>
32#include <stdio.h>
33
34LOG_BACKEND current_backend = -1;
35
36bool open_log(LOG_BACKEND backend)
37{
38 if (current_backend != -1) {
39 return false;
40 }
41
42 if (backend == LOG_BACKEND_SYSLOG) {
43 openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
44 }
45
46 current_backend = backend;
47
48 return true;
49}
50
51bool close_log()
52{
53 if (current_backend == -1) {
54 return false;
55 }
56
57 if (current_backend == LOG_BACKEND_SYSLOG) {
58 closelog();
59 }
60
61 current_backend = -1;
62
63 return true;
64}
65
66int level_syslog(LOG_LEVEL level)
67{
68 switch (level) {
69 case LOG_LEVEL_INFO:
70 return LOG_INFO;
71 case LOG_LEVEL_WARNING:
72 return LOG_WARNING;
73 case LOG_LEVEL_ERROR:
74 return LOG_ERR;
75 }
76}
77
78void log_syslog(LOG_LEVEL level, const char *format, va_list args)
79{
80 vsyslog(level_syslog(level), format, args);
81}
82
83FILE* level_stdout(LOG_LEVEL level)
84{
85 switch (level) {
86 case LOG_LEVEL_INFO:
87 return stdout;
88 case LOG_LEVEL_WARNING: // intentional fallthrough
89 case LOG_LEVEL_ERROR:
90 return stderr;
91 }
92}
93
94void log_stdout(LOG_LEVEL level, const char *format, va_list args)
95{
96 vfprintf(level_stdout(level), format, args);
97 fflush(level_stdout(level));
98}
99
100bool write_log(LOG_LEVEL level, const char *format, ...)
101{
102 va_list args;
103 va_start(args, format);
104
105 switch (current_backend) {
106 case LOG_BACKEND_SYSLOG:
107 log_syslog(level, format, args);
108 break;
109 case LOG_BACKEND_STDOUT:
110 log_stdout(level, format, args);
111 break;
112 }
113
114 va_end(args);
115
116 return current_backend != -1;
117}
diff --git a/other/bootstrap_daemon/src/log.h b/other/bootstrap_daemon/src/log.h
new file mode 100644
index 00000000..61cb2ee3
--- /dev/null
+++ b/other/bootstrap_daemon/src/log.h
@@ -0,0 +1,64 @@
1/* log.h
2 *
3 * Tox DHT bootstrap daemon.
4 * Logging utility with support of multipel logging backends.
5 *
6 * Copyright (C) 2015-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#ifndef LOG_H
26#define LOG_H
27
28#include <stdbool.h>
29
30typedef enum LOG_BACKEND {
31 LOG_BACKEND_SYSLOG,
32 LOG_BACKEND_STDOUT
33} LOG_BACKEND;
34
35typedef enum LOG_LEVEL {
36 LOG_LEVEL_INFO,
37 LOG_LEVEL_WARNING,
38 LOG_LEVEL_ERROR
39} LOG_LEVEL;
40
41/**
42 * Initializes logger.
43 * @param backend Specifies which backend to use.
44 * @return true on success, flase if log is already opened.
45 */
46bool open_log(LOG_BACKEND backend);
47
48/**
49 * Releases all used resources by the logger.
50 * @return true on success, flase if log is already closed.
51 */
52bool close_log();
53
54/**
55 * Writes a message to the log.
56 * @param level Log level to use.
57 * @param format printf-like format string.
58 * @param ... Zero or more arguments, similar to printf function.
59 * @return true on success, flase if log is closed.
60 */
61bool write_log(LOG_LEVEL level, const char *format, ...);
62
63
64#endif // LOG_H
diff --git a/other/bootstrap_daemon/src/tox-bootstrapd.c b/other/bootstrap_daemon/src/tox-bootstrapd.c
new file mode 100644
index 00000000..e252a37d
--- /dev/null
+++ b/other/bootstrap_daemon/src/tox-bootstrapd.c
@@ -0,0 +1,342 @@
1/* tox-bootstrapd.c
2 *
3 * Tox DHT bootstrap daemon.
4 * Main 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// system provided
26#include <unistd.h>
27
28// C
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33// toxcore
34#include "../../../toxcore/LAN_discovery.h"
35#include "../../../toxcore/onion_announce.h"
36#include "../../../toxcore/TCP_server.h"
37#include "../../../toxcore/util.h"
38
39// misc
40#include "../../bootstrap_node_packets.h"
41
42#include "command_line_arguments.h"
43#include "config.h"
44#include "global.h"
45#include "log.h"
46
47
48#define SLEEP_MILLISECONDS(MS) usleep(1000*MS)
49
50// Uses the already existing key or creates one if it didn't exist
51//
52// retirns 1 on success
53// 0 on failure - no keys were read or stored
54
55int manage_keys(DHT *dht, char *keys_file_path)
56{
57 const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
58 uint8_t keys[KEYS_SIZE];
59 FILE *keys_file;
60
61 // Check if file exits, proceed to open and load keys
62 keys_file = fopen(keys_file_path, "r");
63
64 if (keys_file != NULL) {
65 const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
66
67 if (read_size != KEYS_SIZE) {
68 fclose(keys_file);
69 return 0;
70 }
71
72 memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
73 memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
74 } else {
75 // Otherwise save new keys
76 memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
77 memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
78
79 keys_file = fopen(keys_file_path, "w");
80
81 if (!keys_file)
82 return 0;
83
84 const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
85
86 if (write_size != KEYS_SIZE) {
87 fclose(keys_file);
88 return 0;
89 }
90 }
91
92 fclose(keys_file);
93
94 return 1;
95}
96
97// Prints public key
98
99void print_public_key(const uint8_t *public_key)
100{
101 char buffer[2 * crypto_box_PUBLICKEYBYTES + 1];
102 int index = 0;
103
104 size_t i;
105
106 for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {
107 index += sprintf(buffer + index, "%02hhX", public_key[i]);
108 }
109
110 write_log(LOG_LEVEL_INFO, "Public Key: %s\n", buffer);
111
112 return;
113}
114
115// Demonizes the process, appending PID to the PID file and closing file descriptors based on log backend
116// Terminates the application if the daemonization fails.
117
118void daemonize(LOG_BACKEND log_backend, char *pid_file_path)
119{
120 // Check if the PID file exists
121 FILE *pid_file;
122
123 if ((pid_file = fopen(pid_file_path, "r"))) {
124 write_log(LOG_LEVEL_WARNING, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path);
125 fclose(pid_file);
126 }
127
128 // Open the PID file for writing
129 pid_file = fopen(pid_file_path, "a+");
130 if (pid_file == NULL) {
131 write_log(LOG_LEVEL_ERROR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path);
132 exit(1);
133 }
134
135 // Fork off from the parent process
136 const pid_t pid = fork();
137
138 if (pid > 0) {
139 fprintf(pid_file, "%d", pid);
140 fclose(pid_file);
141 write_log(LOG_LEVEL_INFO, "Forked successfully: PID: %d.\n", pid);
142 exit(0);
143 } else {
144 fclose(pid_file);
145 }
146
147 if (pid < 0) {
148 write_log(LOG_LEVEL_ERROR, "Forking failed. Exiting.\n");
149 exit(1);
150 }
151
152 // Create a new SID for the child process
153 if (setsid() < 0) {
154 write_log(LOG_LEVEL_ERROR, "SID creation failure. Exiting.\n");
155 exit(1);
156 }
157
158 // Change the file mode mask
159 umask(0);
160
161 // Change the current working directory
162 if ((chdir("/")) < 0) {
163 write_log(LOG_LEVEL_ERROR, "Couldn't change working directory to '/'. Exiting.\n");
164 exit(1);
165 }
166
167 // Go quiet
168 if (log_backend != LOG_BACKEND_STDOUT) {
169 close(STDOUT_FILENO);
170 close(STDIN_FILENO);
171 close(STDERR_FILENO);
172 }
173}
174
175int main(int argc, char *argv[])
176{
177 char *cfg_file_path;
178 LOG_BACKEND log_backend;
179 bool run_in_foreground;
180
181 // choose backend for printing command line argument parsing output based on whether the daemon is being run from a terminal
182 log_backend = isatty(STDOUT_FILENO) ? LOG_BACKEND_STDOUT : LOG_BACKEND_SYSLOG;
183
184 open_log(log_backend);
185 handle_command_line_arguments(argc, argv, &cfg_file_path, &log_backend, &run_in_foreground);
186 close_log();
187
188 open_log(log_backend);
189
190 write_log(LOG_LEVEL_INFO, "Running \"%s\" version %lu.\n", DAEMON_NAME, DAEMON_VERSION_NUMBER);
191
192 char *pid_file_path, *keys_file_path;
193 int port;
194 int enable_ipv6;
195 int enable_ipv4_fallback;
196 int enable_lan_discovery;
197 int enable_tcp_relay;
198 uint16_t *tcp_relay_ports;
199 int tcp_relay_port_count;
200 int enable_motd;
201 char *motd;
202
203 if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback,
204 &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {
205 write_log(LOG_LEVEL_INFO, "General config read successfully\n");
206 } else {
207 write_log(LOG_LEVEL_ERROR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
208 return 1;
209 }
210
211 if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {
212 write_log(LOG_LEVEL_ERROR, "Invalid port: %d, should be in [%d, %d]. Exiting.\n", port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
213 return 1;
214 }
215
216 if (!run_in_foreground) {
217 daemonize(log_backend, pid_file_path);
218 }
219
220 free(pid_file_path);
221
222 IP ip;
223 ip_init(&ip, enable_ipv6);
224
225 Networking_Core *net = new_networking(ip, port);
226
227 if (net == NULL) {
228 if (enable_ipv6 && enable_ipv4_fallback) {
229 write_log(LOG_LEVEL_WARNING, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n");
230 enable_ipv6 = 0;
231 ip_init(&ip, enable_ipv6);
232 net = new_networking(ip, port);
233
234 if (net == NULL) {
235 write_log(LOG_LEVEL_ERROR, "Couldn't fallback to IPv4. Exiting.\n");
236 return 1;
237 }
238 } else {
239 write_log(LOG_LEVEL_ERROR, "Couldn't initialize networking. Exiting.\n");
240 return 1;
241 }
242 }
243
244 DHT *dht = new_DHT(net);
245
246 if (dht == NULL) {
247 write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox DHT instance. Exiting.\n");
248 return 1;
249 }
250
251 Onion *onion = new_onion(dht);
252 Onion_Announce *onion_a = new_onion_announce(dht);
253
254 if (!(onion && onion_a)) {
255 write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox Onion. Exiting.\n");
256 return 1;
257 }
258
259 if (enable_motd) {
260 if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) {
261 write_log(LOG_LEVEL_INFO, "Set MOTD successfully.\n");
262 } else {
263 write_log(LOG_LEVEL_ERROR, "Couldn't set MOTD: %s. Exiting.\n", motd);
264 return 1;
265 }
266
267 free(motd);
268 }
269
270 if (manage_keys(dht, keys_file_path)) {
271 write_log(LOG_LEVEL_INFO, "Keys are managed successfully.\n");
272 } else {
273 write_log(LOG_LEVEL_ERROR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
274 return 1;
275 }
276
277 free(keys_file_path);
278
279 TCP_Server *tcp_server = NULL;
280
281 if (enable_tcp_relay) {
282 if (tcp_relay_port_count == 0) {
283 write_log(LOG_LEVEL_ERROR, "No TCP relay ports read. Exiting.\n");
284 return 1;
285 }
286
287 tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_secret_key, onion);
288
289 // tcp_relay_port_count != 0 at this point
290 free(tcp_relay_ports);
291
292 if (tcp_server != NULL) {
293 write_log(LOG_LEVEL_INFO, "Initialized Tox TCP server successfully.\n");
294 } else {
295 write_log(LOG_LEVEL_ERROR, "Couldn't initialize Tox TCP server. Exiting.\n");
296 return 1;
297 }
298 }
299
300 if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
301 write_log(LOG_LEVEL_INFO, "List of bootstrap nodes read successfully.\n");
302 } else {
303 write_log(LOG_LEVEL_ERROR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path);
304 return 1;
305 }
306
307 print_public_key(dht->self_public_key);
308
309 uint64_t last_LANdiscovery = 0;
310 const uint16_t htons_port = htons(port);
311
312 int waiting_for_dht_connection = 1;
313
314 if (enable_lan_discovery) {
315 LANdiscovery_init(dht);
316 write_log(LOG_LEVEL_INFO, "Initialized LAN discovery successfully.\n");
317 }
318
319 while (1) {
320 do_DHT(dht);
321
322 if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
323 send_LANdiscovery(htons_port, dht);
324 last_LANdiscovery = unix_time();
325 }
326
327 if (enable_tcp_relay) {
328 do_TCP_server(tcp_server);
329 }
330
331 networking_poll(dht->net);
332
333 if (waiting_for_dht_connection && DHT_isconnected(dht)) {
334 write_log(LOG_LEVEL_INFO, "Connected to another bootstrap node successfully.\n");
335 waiting_for_dht_connection = 0;
336 }
337
338 SLEEP_MILLISECONDS(30);
339 }
340
341 return 1;
342}
diff --git a/other/bootstrap_daemon/tox-bootstrapd.c b/other/bootstrap_daemon/tox-bootstrapd.c
deleted file mode 100644
index 267e7238..00000000
--- a/other/bootstrap_daemon/tox-bootstrapd.c
+++ /dev/null
@@ -1,730 +0,0 @@
1/* tox-bootstrapd.c
2 *
3 * Tox DHT bootstrap daemon.
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// system provided
25#include <arpa/inet.h>
26#include <syslog.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <unistd.h>
30
31// C
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36// 3rd party
37#include <libconfig.h>
38
39// ./configure
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
43
44// toxcore
45#include "../../toxcore/LAN_discovery.h"
46#include "../../toxcore/onion_announce.h"
47#include "../../toxcore/TCP_server.h"
48#include "../../toxcore/util.h"
49
50// misc
51#include "../bootstrap_node_packets.c"
52#include "../../testing/misc_tools.c"
53
54
55#define DAEMON_NAME "tox-bootstrapd"
56#define DAEMON_VERSION_NUMBER 2014101200UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day
57
58#define SLEEP_TIME_MILLISECONDS 30
59#define sleep usleep(1000*SLEEP_TIME_MILLISECONDS)
60
61#define DEFAULT_PID_FILE_PATH "tox-bootstrapd.pid"
62#define DEFAULT_KEYS_FILE_PATH "tox-bootstrapd.keys"
63#define DEFAULT_PORT 33445
64#define DEFAULT_ENABLE_IPV6 1 // 1 - true, 0 - false
65#define DEFAULT_ENABLE_IPV4_FALLBACK 1 // 1 - true, 0 - false
66#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
67#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false
68#define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly
69#define DEFAULT_TCP_RELAY_PORTS_COUNT 3
70#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false
71#define DEFAULT_MOTD DAEMON_NAME
72
73#define MIN_ALLOWED_PORT 1
74#define MAX_ALLOWED_PORT 65535
75
76
77// Uses the already existing key or creates one if it didn't exist
78//
79// retirns 1 on success
80// 0 on failure - no keys were read or stored
81
82int manage_keys(DHT *dht, char *keys_file_path)
83{
84 const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
85 uint8_t keys[KEYS_SIZE];
86 FILE *keys_file;
87
88 // Check if file exits, proceed to open and load keys
89 keys_file = fopen(keys_file_path, "r");
90
91 if (keys_file != NULL) {
92 const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
93
94 if (read_size != KEYS_SIZE) {
95 fclose(keys_file);
96 return 0;
97 }
98
99 memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
100 memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
101 } else {
102 // Otherwise save new keys
103 memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
104 memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
105
106 keys_file = fopen(keys_file_path, "w");
107
108 if (!keys_file)
109 return 0;
110
111 const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
112
113 if (write_size != KEYS_SIZE) {
114 fclose(keys_file);
115 return 0;
116 }
117 }
118
119 fclose(keys_file);
120
121 return 1;
122}
123
124// Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array
125//
126// Supposed to be called from get_general_config only
127//
128// Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`
129
130void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)
131{
132 const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports";
133
134 *tcp_relay_port_count = 0;
135
136 config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);
137
138 if (ports_array == NULL) {
139 syslog(LOG_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS);
140 syslog(LOG_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS);
141
142 uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};
143
144 int i;
145
146 for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
147 syslog(LOG_WARNING, "Port #%d: %u\n", i, default_ports[i]);
148 }
149
150 // similar procedure to the one of reading config file below
151 *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));
152
153 for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
154
155 (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];
156
157 if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
158 || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
159 syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
160 (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
161 continue;
162 }
163
164 (*tcp_relay_port_count) ++;
165 }
166
167 // the loop above skips invalid ports, so we adjust the allocated memory size
168 if ((*tcp_relay_port_count) > 0) {
169 *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
170 } else {
171 free(*tcp_relay_ports);
172 *tcp_relay_ports = NULL;
173 }
174
175 return;
176 }
177
178 if (config_setting_is_array(ports_array) == CONFIG_FALSE) {
179 syslog(LOG_WARNING, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n",
180 NAME_TCP_RELAY_PORTS);
181 return;
182 }
183
184 int config_port_count = config_setting_length(ports_array);
185
186 if (config_port_count == 0) {
187 syslog(LOG_WARNING, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS);
188 return;
189 }
190
191 *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));
192
193 int i;
194
195 for (i = 0; i < config_port_count; i ++) {
196 config_setting_t *elem = config_setting_get_elem(ports_array, i);
197
198 if (elem == NULL) {
199 // 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
200 syslog(LOG_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i);
201 break;
202 }
203
204 if (config_setting_is_number(elem) == CONFIG_FALSE) {
205 syslog(LOG_WARNING, "Port #%d: Not a number. Skipping.\n", i);
206 continue;
207 }
208
209 (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);
210
211 if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT
212 || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
213 syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i,
214 (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
215 continue;
216 }
217
218 (*tcp_relay_port_count) ++;
219 }
220
221 // the loop above skips invalid ports, so we adjust the allocated memory size
222 if ((*tcp_relay_port_count) > 0) {
223 *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
224 } else {
225 free(*tcp_relay_ports);
226 *tcp_relay_ports = NULL;
227 }
228}
229
230// Gets general config options
231//
232// Important: you are responsible for freeing `pid_file_path` and `keys_file_path`
233// also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports`
234// and also `motd` iff `enable_motd` is set
235//
236// returns 1 on success
237// 0 on failure, doesn't modify any data pointed by arguments
238
239int get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port,
240 int *enable_ipv6,
241 int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,
242 int *tcp_relay_port_count, int *enable_motd, char **motd)
243{
244 config_t cfg;
245
246 const char *NAME_PORT = "port";
247 const char *NAME_PID_FILE_PATH = "pid_file_path";
248 const char *NAME_KEYS_FILE_PATH = "keys_file_path";
249 const char *NAME_ENABLE_IPV6 = "enable_ipv6";
250 const char *NAME_ENABLE_IPV4_FALLBACK = "enable_ipv4_fallback";
251 const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
252 const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay";
253 const char *NAME_ENABLE_MOTD = "enable_motd";
254 const char *NAME_MOTD = "motd";
255
256 config_init(&cfg);
257
258 // Read the file. If there is an error, report it and exit.
259 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
260 syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
261 config_destroy(&cfg);
262 return 0;
263 }
264
265 // Get port
266 if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
267 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
268 syslog(LOG_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
269 *port = DEFAULT_PORT;
270 }
271
272 // Get PID file location
273 const char *tmp_pid_file;
274
275 if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
276 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
277 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
278 tmp_pid_file = DEFAULT_PID_FILE_PATH;
279 }
280
281 *pid_file_path = malloc(strlen(tmp_pid_file) + 1);
282 strcpy(*pid_file_path, tmp_pid_file);
283
284 // Get keys file location
285 const char *tmp_keys_file;
286
287 if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
288 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
289 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
290 tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
291 }
292
293 *keys_file_path = malloc(strlen(tmp_keys_file) + 1);
294 strcpy(*keys_file_path, tmp_keys_file);
295
296 // Get IPv6 option
297 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
298 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
299 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
300 *enable_ipv6 = DEFAULT_ENABLE_IPV6;
301 }
302
303 // Get IPv4 fallback option
304 if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) {
305 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV4_FALLBACK);
306 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV4_FALLBACK,
307 DEFAULT_ENABLE_IPV4_FALLBACK ? "true" : "false");
308 *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK;
309 }
310
311 // Get LAN discovery option
312 if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
313 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
314 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
315 DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
316 *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
317 }
318
319 // Get TCP relay option
320 if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {
321 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY);
322 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY,
323 DEFAULT_ENABLE_TCP_RELAY ? "true" : "false");
324 *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;
325 }
326
327 if (*enable_tcp_relay) {
328 parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);
329 } else {
330 *tcp_relay_port_count = 0;
331 }
332
333 // Get MOTD option
334 if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {
335 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD);
336 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD,
337 DEFAULT_ENABLE_MOTD ? "true" : "false");
338 *enable_motd = DEFAULT_ENABLE_MOTD;
339 }
340
341 if (*enable_motd) {
342 // Get MOTD
343 const char *tmp_motd;
344
345 if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {
346 syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_MOTD);
347 syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_MOTD, DEFAULT_MOTD);
348 tmp_motd = DEFAULT_MOTD;
349 }
350
351 size_t tmp_motd_length = strlen(tmp_motd) + 1;
352 size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;
353 *motd = malloc(motd_length);
354 strncpy(*motd, tmp_motd, motd_length);
355 (*motd)[motd_length - 1] = '\0';
356 }
357
358 config_destroy(&cfg);
359
360 syslog(LOG_DEBUG, "Successfully read:\n");
361 syslog(LOG_DEBUG, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
362 syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
363 syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port);
364 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
365 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? "true" : "false");
366 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
367
368 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false");
369
370 // show info about tcp ports only if tcp relay is enabled
371 if (*enable_tcp_relay) {
372 if (*tcp_relay_port_count == 0) {
373 syslog(LOG_DEBUG, "No TCP ports could be read.\n");
374 } else {
375 syslog(LOG_DEBUG, "Read %d TCP ports:\n", *tcp_relay_port_count);
376 int i;
377
378 for (i = 0; i < *tcp_relay_port_count; i ++) {
379 syslog(LOG_DEBUG, "Port #%d: %u\n", i, (*tcp_relay_ports)[i]);
380 }
381 }
382 }
383
384 syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false");
385
386 if (*enable_motd) {
387 syslog(LOG_DEBUG, "'%s': %s\n", NAME_MOTD, *motd);
388 }
389
390 return 1;
391}
392
393// Bootstraps nodes listed in the config file
394//
395// returns 1 on success, some or no bootstrap nodes were added
396// 0 on failure, a error accured while parsing config file
397
398int bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6)
399{
400 const char *NAME_BOOTSTRAP_NODES = "bootstrap_nodes";
401
402 const char *NAME_PUBLIC_KEY = "public_key";
403 const char *NAME_PORT = "port";
404 const char *NAME_ADDRESS = "address";
405
406 config_t cfg;
407
408 config_init(&cfg);
409
410 if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
411 syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
412 config_destroy(&cfg);
413 return 0;
414 }
415
416 config_setting_t *node_list = config_lookup(&cfg, NAME_BOOTSTRAP_NODES);
417
418 if (node_list == NULL) {
419 syslog(LOG_WARNING, "No '%s' setting in the configuration file. Skipping bootstrapping.\n", NAME_BOOTSTRAP_NODES);
420 config_destroy(&cfg);
421 return 1;
422 }
423
424 if (config_setting_length(node_list) == 0) {
425 syslog(LOG_WARNING, "No bootstrap nodes found. Skipping bootstrapping.\n");
426 config_destroy(&cfg);
427 return 1;
428 }
429
430 int bs_port;
431 const char *bs_address;
432 const char *bs_public_key;
433
434 config_setting_t *node;
435
436 int i = 0;
437
438 while (config_setting_length(node_list)) {
439
440 node = config_setting_get_elem(node_list, 0);
441
442 if (node == NULL) {
443 config_destroy(&cfg);
444 return 0;
445 }
446
447 // Check that all settings are present
448 if (config_setting_lookup_string(node, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE) {
449 syslog(LOG_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PUBLIC_KEY);
450 goto next;
451 }
452
453 if (config_setting_lookup_int(node, NAME_PORT, &bs_port) == CONFIG_FALSE) {
454 syslog(LOG_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_PORT);
455 goto next;
456 }
457
458 if (config_setting_lookup_string(node, NAME_ADDRESS, &bs_address) == CONFIG_FALSE) {
459 syslog(LOG_WARNING, "Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\n", i, NAME_ADDRESS);
460 goto next;
461 }
462
463 // Process settings
464 if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES * 2) {
465 syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_PUBLIC_KEY,
466 bs_public_key);
467 goto next;
468 }
469
470 if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {
471 syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\n", i, NAME_PORT,
472 bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
473 goto next;
474 }
475
476 uint8_t *bs_public_key_bin = hex_string_to_bin((char *)bs_public_key);
477 const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
478 bs_public_key_bin);
479 free(bs_public_key_bin);
480
481 if (!address_resolved) {
482 syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_ADDRESS, bs_address);
483 goto next;
484 }
485
486 syslog(LOG_DEBUG, "Successfully added bootstrap node #%d: %s:%d %s\n", i, bs_address, bs_port, bs_public_key);
487
488next:
489 // config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly
490 // though it's freed when the element is removed, so we free it right away in order to keep memory
491 // consumption minimal
492 config_setting_remove_elem(node_list, 0);
493 i++;
494 }
495
496 config_destroy(&cfg);
497
498 return 1;
499}
500
501// Prints public key
502
503void print_public_key(const uint8_t *public_key)
504{
505 char buffer[2 * crypto_box_PUBLICKEYBYTES + 1];
506 int index = 0;
507
508 size_t i;
509
510 for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {
511 index += sprintf(buffer + index, "%02hhX", public_key[i]);
512 }
513
514 syslog(LOG_INFO, "Public Key: %s\n", buffer);
515
516 return;
517}
518
519int main(int argc, char *argv[])
520{
521 openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
522
523 syslog(LOG_INFO, "Running \"%s\" version %lu.\n", DAEMON_NAME, DAEMON_VERSION_NUMBER);
524
525 if (argc < 2) {
526 syslog(LOG_ERR, "Please specify a path to a configuration file as the first argument. Exiting.\n");
527 return 1;
528 }
529
530 const char *cfg_file_path = argv[1];
531 char *pid_file_path, *keys_file_path;
532 int port;
533 int enable_ipv6;
534 int enable_ipv4_fallback;
535 int enable_lan_discovery;
536 int enable_tcp_relay;
537 uint16_t *tcp_relay_ports;
538 int tcp_relay_port_count;
539 int enable_motd;
540 char *motd;
541
542 if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback,
543 &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {
544 syslog(LOG_DEBUG, "General config read successfully\n");
545 } else {
546 syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
547 return 1;
548 }
549
550 if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {
551 syslog(LOG_ERR, "Invalid port: %d, should be in [%d, %d]. Exiting.\n", port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
552 return 1;
553 }
554
555 // Check if the PID file exists
556 FILE *pid_file;
557
558 if ((pid_file = fopen(pid_file_path, "r"))) {
559 syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path);
560 fclose(pid_file);
561 }
562
563 IP ip;
564 ip_init(&ip, enable_ipv6);
565
566 Networking_Core *net = new_networking(ip, port);
567
568 if (net == NULL) {
569 if (enable_ipv6 && enable_ipv4_fallback) {
570 syslog(LOG_DEBUG, "Couldn't initialize IPv6 networking. Falling back to using IPv4.\n");
571 enable_ipv6 = 0;
572 ip_init(&ip, enable_ipv6);
573 net = new_networking(ip, port);
574
575 if (net == NULL) {
576 syslog(LOG_DEBUG, "Couldn't fallback to IPv4. Exiting.\n");
577 return 1;
578 }
579 } else {
580 syslog(LOG_DEBUG, "Couldn't initialize networking. Exiting.\n");
581 return 1;
582 }
583 }
584
585
586 DHT *dht = new_DHT(net);
587
588 if (dht == NULL) {
589 syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n");
590 return 1;
591 }
592
593 Onion *onion = new_onion(dht);
594 Onion_Announce *onion_a = new_onion_announce(dht);
595
596 if (!(onion && onion_a)) {
597 syslog(LOG_ERR, "Couldn't initialize Tox Onion. Exiting.\n");
598 return 1;
599 }
600
601 if (enable_motd) {
602 if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) {
603 syslog(LOG_DEBUG, "Set MOTD successfully.\n");
604 } else {
605 syslog(LOG_ERR, "Couldn't set MOTD: %s. Exiting.\n", motd);
606 return 1;
607 }
608
609 free(motd);
610 }
611
612 if (manage_keys(dht, keys_file_path)) {
613 syslog(LOG_DEBUG, "Keys are managed successfully.\n");
614 } else {
615 syslog(LOG_ERR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
616 return 1;
617 }
618
619 TCP_Server *tcp_server = NULL;
620
621 if (enable_tcp_relay) {
622 if (tcp_relay_port_count == 0) {
623 syslog(LOG_ERR, "No TCP relay ports read. Exiting.\n");
624 return 1;
625 }
626
627 tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_secret_key, onion);
628
629 // tcp_relay_port_count != 0 at this point
630 free(tcp_relay_ports);
631
632 if (tcp_server != NULL) {
633 syslog(LOG_DEBUG, "Initialized Tox TCP server successfully.\n");
634 } else {
635 syslog(LOG_ERR, "Couldn't initialize Tox TCP server. Exiting.\n");
636 return 1;
637 }
638 }
639
640 if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
641 syslog(LOG_DEBUG, "List of bootstrap nodes read successfully.\n");
642 } else {
643 syslog(LOG_ERR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path);
644 return 1;
645 }
646
647 print_public_key(dht->self_public_key);
648
649 // Write the PID file
650 FILE *pidf = fopen(pid_file_path, "a+");
651
652 if (pidf == NULL) {
653 syslog(LOG_ERR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path);
654 return 1;
655 }
656
657 free(pid_file_path);
658 free(keys_file_path);
659
660 // Fork off from the parent process
661 const pid_t pid = fork();
662
663 if (pid > 0) {
664 fprintf(pidf, "%d", pid);
665 fclose(pidf);
666 syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid);
667 return 0;
668 } else {
669 fclose(pidf);
670 }
671
672 if (pid < 0) {
673 syslog(LOG_ERR, "Forking failed. Exiting.\n");
674 return 1;
675 }
676
677 // Change the file mode mask
678 umask(0);
679
680 // Create a new SID for the child process
681 if (setsid() < 0) {
682 syslog(LOG_ERR, "SID creation failure. Exiting.\n");
683 return 1;
684 }
685
686 // Change the current working directory
687 if ((chdir("/")) < 0) {
688 syslog(LOG_ERR, "Couldn't change working directory to '/'. Exiting.\n");
689 return 1;
690 }
691
692 // Go quiet
693 close(STDOUT_FILENO);
694 close(STDIN_FILENO);
695 close(STDERR_FILENO);
696
697 uint64_t last_LANdiscovery = 0;
698 const uint16_t htons_port = htons(port);
699
700 int waiting_for_dht_connection = 1;
701
702 if (enable_lan_discovery) {
703 LANdiscovery_init(dht);
704 syslog(LOG_DEBUG, "Initialized LAN discovery.\n");
705 }
706
707 while (1) {
708 do_DHT(dht);
709
710 if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
711 send_LANdiscovery(htons_port, dht);
712 last_LANdiscovery = unix_time();
713 }
714
715 if (enable_tcp_relay) {
716 do_TCP_server(tcp_server);
717 }
718
719 networking_poll(dht->net);
720
721 if (waiting_for_dht_connection && DHT_isconnected(dht)) {
722 syslog(LOG_DEBUG, "Connected to other bootstrap node successfully.\n");
723 waiting_for_dht_connection = 0;
724 }
725
726 sleep;
727 }
728
729 return 1;
730}
diff --git a/other/bootstrap_daemon/tox-bootstrapd.service b/other/bootstrap_daemon/tox-bootstrapd.service
index db54cc41..20f698d2 100644
--- a/other/bootstrap_daemon/tox-bootstrapd.service
+++ b/other/bootstrap_daemon/tox-bootstrapd.service
@@ -8,7 +8,7 @@ RuntimeDirectory=tox-bootstrapd
8RuntimeDirectoryMode=750 8RuntimeDirectoryMode=750
9PIDFile=/var/run/tox-bootstrapd/tox-bootstrapd.pid 9PIDFile=/var/run/tox-bootstrapd/tox-bootstrapd.pid
10WorkingDirectory=/var/lib/tox-bootstrapd 10WorkingDirectory=/var/lib/tox-bootstrapd
11ExecStart=/usr/local/bin/tox-bootstrapd /etc/tox-bootstrapd.conf 11ExecStart=/usr/local/bin/tox-bootstrapd --config /etc/tox-bootstrapd.conf
12User=tox-bootstrapd 12User=tox-bootstrapd
13Group=tox-bootstrapd 13Group=tox-bootstrapd
14#CapabilityBoundingSet=CAP_NET_BIND_SERVICE 14#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
diff --git a/other/bootstrap_daemon/tox-bootstrapd.sh b/other/bootstrap_daemon/tox-bootstrapd.sh
index 1431bde0..d33c38da 100644
--- a/other/bootstrap_daemon/tox-bootstrapd.sh
+++ b/other/bootstrap_daemon/tox-bootstrapd.sh
@@ -15,7 +15,7 @@ DESC="Tox DHT bootstrap daemon"
15NAME=tox-bootstrapd 15NAME=tox-bootstrapd
16DAEMON=/usr/local/bin/$NAME 16DAEMON=/usr/local/bin/$NAME
17CFGFILE=/etc/$NAME.conf 17CFGFILE=/etc/$NAME.conf
18DAEMON_ARGS="$CFGFILE" 18DAEMON_ARGS="--config $CFGFILE"
19PIDDIR=/var/run/$NAME 19PIDDIR=/var/run/$NAME
20PIDFILE=$PIDDIR/$NAME.pid 20PIDFILE=$PIDDIR/$NAME.pid
21SCRIPTNAME=/etc/init.d/$NAME 21SCRIPTNAME=/etc/init.d/$NAME
diff --git a/other/bootstrap_node_packets.c b/other/bootstrap_node_packets.c
index 0bf9b9b0..21bb2894 100644
--- a/other/bootstrap_node_packets.c
+++ b/other/bootstrap_node_packets.c
@@ -23,7 +23,7 @@
23 * 23 *
24 */ 24 */
25 25
26#define MAX_MOTD_LENGTH 256 /* I recommend you use a maximum of 96 bytes. The hard maximum is this though. */ 26#include "bootstrap_node_packets.h"
27 27
28#define INFO_REQUEST_PACKET_LENGTH 78 28#define INFO_REQUEST_PACKET_LENGTH 78
29 29
diff --git a/other/bootstrap_node_packets.h b/other/bootstrap_node_packets.h
new file mode 100644
index 00000000..43356e7b
--- /dev/null
+++ b/other/bootstrap_node_packets.h
@@ -0,0 +1,35 @@
1/* bootstrap_node_packets.h
2 *
3 * Special bootstrap node only packets.
4 *
5 * Include it in your bootstrap node and use: bootstrap_set_callbacks() to enable.
6 *
7 * Copyright (C) 2015 Tox project All Rights Reserved.
8 *
9 * This file is part of Tox.
10 *
11 * Tox is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * Tox is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#ifndef BOOTSTRAP_NODE_PACKETS_H
27#define BOOTSTRAP_NODE_PACKETS_H
28
29#include "../toxcore/network.h"
30
31#define MAX_MOTD_LENGTH 256 /* I recommend you use a maximum of 96 bytes. The hard maximum is this though. */
32
33int bootstrap_set_callbacks(Networking_Core *net, uint32_t version, uint8_t *motd, uint16_t motd_length);
34
35#endif // BOOTSTRAP_NODE_PACKETS_H