mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Merge pull request #688 from nurupo/dht_bootstrap_daemon
Improved DHT bootstrap daemon
This commit is contained in:
commit
6b7dff37c8
@ -1,460 +0,0 @@
|
||||
/* DHT boostrap
|
||||
*
|
||||
* A simple DHT boostrap server for tox - daemon edition.
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* pid_t */
|
||||
#include <sys/stat.h> /* umask */
|
||||
#include <unistd.h> /* POSIX things */
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libconfig.h>
|
||||
#include <arpa/inet.h> /* htons() */
|
||||
#include <string.h> /* strcpy() */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "../../toxcore/DHT.h"
|
||||
#include "../../toxcore/friend_requests.h"
|
||||
|
||||
#define DEFAULT_PORT 33445
|
||||
#define DEFAULT_PID_FILE "bootstrap_server.pid"
|
||||
#define DEFAULT_KEYS_FILE "bootstrap_server.keys"
|
||||
|
||||
/* Server info struct */
|
||||
struct server_info_s {
|
||||
int valid;
|
||||
IP_Port conn;
|
||||
uint8_t bs_pk[32];
|
||||
};
|
||||
|
||||
/* This is the struct configure_server() uses to return its data to */
|
||||
struct server_conf_s {
|
||||
int err;
|
||||
int port;
|
||||
char pid_file[512];
|
||||
char keys_file[512];
|
||||
struct server_info_s info[32];
|
||||
};
|
||||
|
||||
int b16_to_key(char b16_string[], uint8_t *bs_pubkey)
|
||||
{
|
||||
|
||||
int i;
|
||||
unsigned int num1 = 0, num2 = 0;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
sscanf(&b16_string[i * 2], "%1X", &num1);
|
||||
sscanf(&b16_string[i * 2 + 1], "%1X", &num2);
|
||||
num1 = num1 << 4;
|
||||
bs_pubkey[i] = bs_pubkey[i] | num1;
|
||||
bs_pubkey[i] = bs_pubkey[i] | num2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
resolve_addr():
|
||||
address should represent IPv4 or a hostname with a record
|
||||
|
||||
returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i
|
||||
returns 0 on failure
|
||||
|
||||
TODO: Fix ipv6 support
|
||||
*/
|
||||
|
||||
uint32_t resolve_addr(const char *address)
|
||||
{
|
||||
struct addrinfo *server = NULL;
|
||||
struct addrinfo hints;
|
||||
int rc;
|
||||
uint32_t addr;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET; // IPv4 only right now.
|
||||
hints.ai_socktype = SOCK_DGRAM; // Type of socket Tox uses.
|
||||
|
||||
rc = getaddrinfo(address, "echo", &hints, &server);
|
||||
|
||||
// Lookup failed.
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// IPv4 records only..
|
||||
if (server->ai_family != AF_INET) {
|
||||
freeaddrinfo(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
addr = ((struct sockaddr_in *)server->ai_addr)->sin_addr.s_addr;
|
||||
|
||||
freeaddrinfo(server);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* This function connects to all specified servers
|
||||
and connect to them.
|
||||
returns 1 if the connection to the DHT is up
|
||||
returns -1 if all attempts failed
|
||||
*/
|
||||
int connect_to_servers(DHT *dht, struct server_info_s *info)
|
||||
{
|
||||
int i;
|
||||
int c;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if (info[i].valid) {
|
||||
/* Actual bootstrapping code goes here */
|
||||
//puts("Calling DHT_bootstrap");
|
||||
DHT_bootstrap(dht, info[i].conn, info[i].bs_pk);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we're connected to the DHT */
|
||||
for (c = 0; c != 100; ++c) {
|
||||
usleep(10000);
|
||||
|
||||
if (DHT_isconnected(dht)) {
|
||||
//puts("Connected");
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (DHT_isconnected(dht) == 0 && c == 99) {
|
||||
//puts("Not connected");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
do_DHT(dht);
|
||||
|
||||
networking_poll(dht->c->lossless_udp->net);
|
||||
}
|
||||
|
||||
/* This probably never happens */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manage_keys(DHT *dht, char *keys_file)
|
||||
{
|
||||
const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
||||
uint8_t keys[KEYS_SIZE];
|
||||
struct stat existence;
|
||||
FILE *keysf;
|
||||
|
||||
/* Check if file exits, proceed to open and load keys */
|
||||
if (stat(keys_file, &existence) >= 0) {
|
||||
keysf = fopen(keys_file, "r");
|
||||
size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keysf);
|
||||
|
||||
if (read_size != KEYS_SIZE) {
|
||||
printf("Error while reading the key file\nExiting.\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("Keys loaded successfully\n");
|
||||
}
|
||||
|
||||
load_keys(dht->c, keys);
|
||||
|
||||
} else {
|
||||
/* Otherwise save new keys */
|
||||
/* Silly work-around to ignore any errors coming from new_keys() */
|
||||
new_keys(dht->c);
|
||||
save_keys(dht->c, keys);
|
||||
keysf = fopen(keys_file, "w");
|
||||
|
||||
if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keysf) != KEYS_SIZE) {
|
||||
printf("Error while writing the key file.\nExiting.\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("Keys saved successfully\n");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(keysf);
|
||||
}
|
||||
|
||||
/* This reads the configuration file, and returns a struct server_conf_s with:
|
||||
*an error number:
|
||||
*-1 = file wasn't read, for whatever reason
|
||||
*-2 = no bootstrap servers found
|
||||
*the port
|
||||
*the location of the keys file
|
||||
*the location of the PID file
|
||||
*the list of bootstrap servers
|
||||
*/
|
||||
struct server_conf_s configure_server(char *cfg_file)
|
||||
{
|
||||
config_t cfg;
|
||||
config_setting_t *server_list;
|
||||
|
||||
/* This one will be strcpy'd into the pid_file array in server_conf */
|
||||
const char *pid_file_tmp;
|
||||
const char *keys_file_tmp;
|
||||
|
||||
/* Remote bootstrap server variables */
|
||||
int bs_port;
|
||||
const char *bs_ip;
|
||||
const char *bs_pk;
|
||||
|
||||
/* The big struct */
|
||||
static struct server_conf_s server_conf;
|
||||
|
||||
/* Set both to their default values. If there's an error
|
||||
with opening/reading the config file, we return right away */
|
||||
server_conf.port = DEFAULT_PORT;
|
||||
strcpy(server_conf.pid_file, DEFAULT_PID_FILE);
|
||||
strcpy(server_conf.keys_file, DEFAULT_KEYS_FILE);
|
||||
|
||||
config_init(&cfg);
|
||||
|
||||
/* Read the file. If there is an error, report it and exit. */
|
||||
if (! config_read_file(&cfg, cfg_file)) {
|
||||
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
|
||||
config_error_line(&cfg), config_error_text(&cfg));
|
||||
config_destroy(&cfg);
|
||||
server_conf.err = -1;
|
||||
return server_conf;
|
||||
}
|
||||
|
||||
/* Get the port to listen on */
|
||||
if (config_lookup_int(&cfg, "port", &server_conf.port)) {
|
||||
//printf("Port: %d\n", port);
|
||||
} else {
|
||||
fprintf(stderr, "No 'port' setting in configuration file.\n");
|
||||
}
|
||||
|
||||
/* Get PID file location */
|
||||
if (config_lookup_string(&cfg, "pid_file", &pid_file_tmp)) {
|
||||
//printf("PID file: %s\n", pid_file_tmp);
|
||||
strcpy(server_conf.pid_file, pid_file_tmp);
|
||||
} else {
|
||||
fprintf(stderr, "No 'pid_file' setting in configuration file.\n");
|
||||
}
|
||||
|
||||
/* Get keys file location */
|
||||
if (config_lookup_string(&cfg, "keys_file", &keys_file_tmp)) {
|
||||
//printf("Keys file: %s\n", keys_file_tmp);
|
||||
strcpy(server_conf.keys_file, keys_file_tmp);
|
||||
} else {
|
||||
fprintf(stderr, "No 'keys_file' setting in configuration file.\n");
|
||||
}
|
||||
|
||||
/* Get all the servers in the list */
|
||||
server_list = config_lookup(&cfg, "bootstrap_servers");
|
||||
|
||||
if (server_list != NULL) {
|
||||
int count = config_setting_length(server_list);
|
||||
int i;
|
||||
|
||||
char tmp_ip[30]; /* IP */
|
||||
char tmp_pk[64]; /* bs_pk */
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
config_setting_t *server = config_setting_get_elem(server_list, i);
|
||||
/* Get a pointer on the key array */
|
||||
uint8_t *bs_pk_p = server_conf.info[i].bs_pk;
|
||||
|
||||
/* Only output the record if all of the expected fields are present. */
|
||||
if (!(config_setting_lookup_string(server, "ip", &bs_ip)
|
||||
&& config_setting_lookup_int(server, "port", &bs_port)
|
||||
&& config_setting_lookup_string(server, "bs_pk", &bs_pk)))
|
||||
continue;
|
||||
|
||||
/* Converting all that stuff into usable formats and storing
|
||||
it away in the server_info struct */
|
||||
server_conf.info[i].valid = 1;
|
||||
|
||||
if (resolve_addr(strcpy(tmp_ip, bs_ip)) == 0) {
|
||||
server_conf.info[i].valid = 0;
|
||||
printf("bootstrap_server %d: Invalid IP.\n", i);
|
||||
}
|
||||
|
||||
if (strlen(bs_pk) != 64) {
|
||||
server_conf.info[i].valid = 0;
|
||||
printf("bootstrap_server %d: Invalid public key.\n", i);
|
||||
}
|
||||
|
||||
if (!bs_port) {
|
||||
server_conf.info[i].valid = 0;
|
||||
printf("bootstrap_server %d: Invalid port.\n", i);
|
||||
}
|
||||
|
||||
server_conf.info[i].conn.ip.family = AF_INET;
|
||||
server_conf.info[i].conn.ip.ip4.uint32 = resolve_addr(strcpy(tmp_ip, bs_ip));
|
||||
server_conf.info[i].conn.port = htons(bs_port);
|
||||
b16_to_key(strcpy(tmp_pk, bs_pk), bs_pk_p);
|
||||
}
|
||||
|
||||
/* Check if at least one server entry is valid */
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if (server_conf.info[i].valid)
|
||||
break;
|
||||
else
|
||||
server_conf.err = -2;
|
||||
}
|
||||
|
||||
} else {
|
||||
server_conf.err = -2;
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
return server_conf;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
pid_t pid, sid; /* Process- and Session-ID */
|
||||
struct server_conf_s server_conf;
|
||||
|
||||
FILE *pidf; /* The PID file */
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Please specify a configuration file.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server_conf = configure_server(argv[1]);
|
||||
|
||||
/* Initialize networking
|
||||
bind to ip 0.0.0.0:PORT */
|
||||
IP ip;
|
||||
ip_init(&ip, 0);
|
||||
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, server_conf.port)));
|
||||
/* Read the config file */
|
||||
printf("PID file: %s\n", server_conf.pid_file);
|
||||
printf("Key file: %s\n", server_conf.keys_file);
|
||||
|
||||
if (server_conf.err == -1)
|
||||
printf("Config file not read.\n");
|
||||
|
||||
if (server_conf.err == -2)
|
||||
printf("No valid servers in list.\n");
|
||||
|
||||
/* Open PID file for writing - if an error happens,
|
||||
it will be caught down the line */
|
||||
pidf = fopen(server_conf.pid_file, "w");
|
||||
|
||||
/* Manage the keys */
|
||||
/* for now, just ignore any errors after this call. */
|
||||
int tmperr = errno;
|
||||
manage_keys(dht, server_conf.keys_file);
|
||||
errno = tmperr;
|
||||
|
||||
/* Public key */
|
||||
int i;
|
||||
printf("\nPublic Key: ");
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
uint8_t ln, hn;
|
||||
ln = 0x0F & dht->c->self_public_key[i];
|
||||
hn = 0xF0 & dht->c->self_public_key[i];
|
||||
hn = hn >> 4;
|
||||
printf("%X%X", hn, ln);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
/* Bootstrap the DHT
|
||||
This one throws odd errors, too. Ignore. I assume they come
|
||||
from somewhere in the core. */
|
||||
tmperr = errno;
|
||||
connect_to_servers(dht, server_conf.info);
|
||||
errno = tmperr;
|
||||
|
||||
if (!DHT_isconnected(dht)) {
|
||||
puts("Could not establish DHT connection. Check server settings.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
printf("Connected to DHT successfully.\n");
|
||||
}
|
||||
|
||||
/* If there's been an error, exit before forking off */
|
||||
if (errno != 0) {
|
||||
perror("Error");
|
||||
printf("Error(s) occured during start-up. Exiting.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Things that make the daemon work come past here.
|
||||
There should be nothing here but the daemon code and
|
||||
the main loop. */
|
||||
|
||||
/* Fork off from the parent process */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
printf("Forking failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* If we got a good PID, then
|
||||
we can exit the parent process. */
|
||||
if (pid > 0) {
|
||||
printf("Forked successfully: %d.\n", pid);
|
||||
|
||||
/* Write the PID file */
|
||||
fprintf(pidf, "%d\n", pid);
|
||||
fclose(pidf);
|
||||
|
||||
/* Exit parent */
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
|
||||
if (sid < 0) {
|
||||
printf("SID creation failure.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Change the current working directory */
|
||||
if ((chdir("/")) < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Go quiet */
|
||||
close(STDOUT_FILENO);
|
||||
close(STDIN_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
while (1) {
|
||||
do_DHT(dht);
|
||||
|
||||
networking_poll(dht->c->lossless_udp->net);
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
//shutdown_networking();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
if BUILD_DHT_BOOTSTRAP_DAEMON
|
||||
|
||||
noinst_PROGRAMS += DHT_bootstrap_daemon
|
||||
noinst_PROGRAMS += tox_dht_bootstrap_server_daemon
|
||||
|
||||
DHT_bootstrap_daemon_SOURCES = \
|
||||
../other/bootstrap_serverdaemon/DHT_bootstrap_daemon.c
|
||||
tox_dht_bootstrap_server_daemon_SOURCES = \
|
||||
../other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c
|
||||
|
||||
DHT_bootstrap_daemon_CFLAGS = \
|
||||
tox_dht_bootstrap_server_daemon_CFLAGS = \
|
||||
-I$(top_srcdir)/other/bootstrap_serverdaemon \
|
||||
$(LIBSODIUM_CFLAGS) \
|
||||
$(NACL_CFLAGS) \
|
||||
$(LIBCONFIG_CFLAGS)
|
||||
|
||||
DHT_bootstrap_daemon_LDADD = \
|
||||
tox_dht_bootstrap_server_daemon_LDADD = \
|
||||
$(LIBSODIUM_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
libtoxcore.la \
|
||||
@ -22,5 +22,6 @@ DHT_bootstrap_daemon_LDADD = \
|
||||
endif
|
||||
|
||||
EXTRA_DIST += \
|
||||
$(top_srcdir)/other/bootstrap_serverdaemon/server.cfg \
|
||||
$(top_srcdir)/other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh
|
||||
$(top_srcdir)/other/bootstrap_serverdaemon/conf \
|
||||
$(top_srcdir)/other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon
|
||||
|
61
other/bootstrap_serverdaemon/README.md
Normal file
61
other/bootstrap_serverdaemon/README.md
Normal file
@ -0,0 +1,61 @@
|
||||
##Instructions for Debian
|
||||
|
||||
The following commands are to be executed as root:
|
||||
|
||||
1. In `tox_dht_bootstrap_server_daemon` file change:
|
||||
- `CFG` to where your config file (`conf`) will be; read rights required
|
||||
- `DAEMON` to point to the executable
|
||||
- `PIDFILE` to point to a pid file daemon would have rights to create
|
||||
|
||||
2. Go over everything in `conf`. Make sure `pid_file_path` matches `PIDFILE` from `tox_dht_bootstrap_server_daemon`
|
||||
|
||||
3. Execute:
|
||||
```
|
||||
mv tox_dht_bootstrap_server_daemon /etc/init.d/tox_dht_bootstrap_server_daemon
|
||||
```
|
||||
|
||||
4. Give the right permissions to this file:
|
||||
```
|
||||
chmod 755 /etc/init.d/tox_dht_bootstrap_server_daemon
|
||||
```
|
||||
|
||||
5. Execute:
|
||||
```
|
||||
update-rc.d tox_dht_bootstrap_server_daemon defaults
|
||||
```
|
||||
|
||||
6. Start the service:
|
||||
```
|
||||
service tox_dht_bootstrap_server_daemon start
|
||||
```
|
||||
|
||||
7. Verify that the service is running:
|
||||
```
|
||||
service tox_dht_bootstrap_server_daemon status
|
||||
```
|
||||
|
||||
--
|
||||
|
||||
You can see daemon's log with
|
||||
```
|
||||
grep "tox_dht_bootstrap_server_daemon" /var/log/syslog
|
||||
```
|
||||
|
||||
**Note that system log is where you find your public key**
|
||||
|
||||
--
|
||||
|
||||
###Troubleshooting:
|
||||
|
||||
1. Check the log for errors with
|
||||
```
|
||||
grep "tox_dht_bootstrap_server_daemon" /var/log/syslog
|
||||
```
|
||||
|
||||
2. Check that paths in the beginning of `/etc/init.d/tox_dht_bootstrap_server_daemon` are valid
|
||||
|
||||
3. Make sure that `PIDFILE` from `/etc/init.d/tox_dht_bootstrap_server_daemon` matches with the `pid_file_path` from `conf`
|
||||
|
||||
4. Make sure you have write permission to keys and pid files
|
||||
|
||||
5. Make sure you have read permission for config file
|
40
other/bootstrap_serverdaemon/conf
Normal file
40
other/bootstrap_serverdaemon/conf
Normal file
@ -0,0 +1,40 @@
|
||||
// ProjectTox bootstrap server configuration file
|
||||
|
||||
// listening port
|
||||
port = 33445
|
||||
|
||||
// The key file is like a password, so keep it where no one can read it
|
||||
// The daemon should have permission to read/write to it
|
||||
// Remember to replace the provided example with
|
||||
// your own path
|
||||
keys_file_path = "/home/tom/.tox_dht_bootstrap_server_daemon/keys"
|
||||
|
||||
// The PID file written to by daemon,
|
||||
// make sure that the user who runs the server
|
||||
// does have permissions to write to it
|
||||
// Remember to replace the provided example with
|
||||
// your own path
|
||||
pid_file_path = "/home/tom/.tox_dht_bootstrap_server_daemon/pid"
|
||||
|
||||
enable_ipv6 = false
|
||||
|
||||
// Automatically bootstrap with nodes on local network
|
||||
enable_lan_discovery = true
|
||||
|
||||
// Any number of nodes the daemon will bootstrap itself from
|
||||
// Remember to replace the provided example with
|
||||
// your own server list
|
||||
bootstrap_servers = (
|
||||
{ // Server 1
|
||||
// any ipv4 or ipv6, depending if `enable_ipv6` is set or not
|
||||
// also any US-ASCII domain name
|
||||
address = "198.46.136.167"
|
||||
port = 33445
|
||||
public_key = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854"
|
||||
},
|
||||
{ // Server 2
|
||||
address = "example.org"
|
||||
port = 33445
|
||||
public_key = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858"
|
||||
}
|
||||
)
|
@ -1,34 +0,0 @@
|
||||
// ProjectTox bootstrap server configuration file
|
||||
|
||||
// The port used by bootstrap_server to listen on
|
||||
port = 33445;
|
||||
|
||||
// The key file
|
||||
// make sure that the user who runs the server
|
||||
// does have permissions to read it/write to it
|
||||
// Remember to replace the provided example with
|
||||
// the directory the DHT server will run in.
|
||||
keys_file = "/home/tom/.bootstrap_server.keys"
|
||||
|
||||
// The PID file written to by bootstrap_server,
|
||||
// make sure that the user who runs the server
|
||||
// does have permissions to write to it
|
||||
// Remember to replace the provided example with
|
||||
// the directory the DHT server will run in.
|
||||
pid_file = "/home/tom/.bootstrap_server.pid";
|
||||
|
||||
// The info of the node bootstap_server will
|
||||
// bootstrap itself from.
|
||||
bootstrap_servers = (
|
||||
{ // Server 1
|
||||
ip = "198.46.136.167";
|
||||
port = 33445;
|
||||
bs_pk = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854";
|
||||
// }
|
||||
},
|
||||
{ // Server 2
|
||||
ip = "192.81.133.111";
|
||||
port = 33445;
|
||||
bs_pk = "8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858";
|
||||
}
|
||||
);
|
16
other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh → other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon
Executable file → Normal file
16
other/bootstrap_serverdaemon/DHT_bootstrap_daemon.sh → other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon
Executable file → Normal file
@ -1,23 +1,23 @@
|
||||
#! /bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: DHT_bootstrap_daemon
|
||||
# Provides: tox_dht_bootstrap_server_daemon
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start the Tox bootstrapping server
|
||||
# Description: Use this piece of junk to start the Tox
|
||||
# bootstrap server.
|
||||
# Short-Description: Starts the Tox bootstrapping server
|
||||
# Description: Starts the Tox bootstrapping server
|
||||
### END INIT INFO
|
||||
|
||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC="ProjectTox bootstrap server daemon"
|
||||
NAME=DHT_bootstrap_daemon
|
||||
CFG=/home/$USER/server.cfg
|
||||
NAME=tox_dht_bootstrap_server_daemon
|
||||
USER=tom
|
||||
CFG=/home/$USER/.$NAME/conf
|
||||
DAEMON=/home/$USER/$NAME
|
||||
DAEMON_ARGS="$CFG"
|
||||
PIDFILE=/home/$USER/.$NAME.pid
|
||||
PIDFILE=/home/$USER/.$NAME/pid
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
# Exit if the package is not installed
|
||||
@ -81,7 +81,7 @@ case "$1" in
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
|
||||
restart) #|force-reload)
|
459
other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c
Normal file
459
other/bootstrap_serverdaemon/tox_dht_bootstrap_server_daemon.c
Normal file
@ -0,0 +1,459 @@
|
||||
/* tox_dht_bootstrap_server_daemon
|
||||
*
|
||||
* A simple DHT bootstrap server for tox - daemon edition.
|
||||
*
|
||||
* Copyright (C) 2014 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libconfig.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "../../toxcore/DHT.h"
|
||||
#include "../../toxcore/friend_requests.h"
|
||||
#include "../../toxcore/LAN_discovery.h"
|
||||
|
||||
#include "../../testing/misc_tools.c"
|
||||
|
||||
#define DAEMON_NAME "tox_dht_bootstrap_server_daemon"
|
||||
|
||||
#define SLEEP_TIME_MILLISECONDS 30
|
||||
#define sleep usleep(1000*SLEEP_TIME_MILLISECONDS)
|
||||
|
||||
#define DEFAULT_PID_FILE_PATH ".tox_dht_bootstrap_server_daemon.pid"
|
||||
#define DEFAULT_KEYS_FILE_PATH ".tox_dht_bootstrap_server_daemon.keys"
|
||||
#define DEFAULT_PORT 33445
|
||||
#define DEFAULT_ENABLE_IPV6 0 // 1 - true, 0 - false
|
||||
#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
|
||||
|
||||
|
||||
// Uses the already existing key or creates one if it didn't exist
|
||||
//
|
||||
// retirns 1 on success
|
||||
// 0 on failure - no keys were read or stored
|
||||
|
||||
int manage_keys(DHT *dht, char *keys_file_path)
|
||||
{
|
||||
const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
|
||||
uint8_t keys[KEYS_SIZE];
|
||||
FILE *keys_file;
|
||||
|
||||
// Check if file exits, proceed to open and load keys
|
||||
keys_file = fopen(keys_file_path, "r");
|
||||
|
||||
if (keys_file != NULL) {
|
||||
size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
|
||||
|
||||
if (read_size != KEYS_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
load_keys(dht->c, keys);
|
||||
} else {
|
||||
// Otherwise save new keys
|
||||
new_keys(dht->c);
|
||||
save_keys(dht->c, keys);
|
||||
|
||||
keys_file = fopen(keys_file_path, "w");
|
||||
|
||||
size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);
|
||||
|
||||
if (write_size != KEYS_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(keys_file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Gets general config options
|
||||
//
|
||||
// Important: you are responsible for freeing `pid_file_path` and `keys_file_path`
|
||||
//
|
||||
// returns 1 on success
|
||||
// 0 on failure, doesn't modify any data pointed by arguments
|
||||
|
||||
int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
|
||||
int *enable_lan_discovery)
|
||||
{
|
||||
config_t cfg;
|
||||
|
||||
const char *NAME_PORT = "port";
|
||||
const char *NAME_PID_FILE_PATH = "pid_file_path";
|
||||
const char *NAME_KEYS_FILE_PATH = "keys_file_path";
|
||||
const char *NAME_ENABLE_IPV6 = "enable_ipv6";
|
||||
const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
|
||||
|
||||
config_init(&cfg);
|
||||
|
||||
// Read the file. If there is an error, report it and exit.
|
||||
if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
|
||||
syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
|
||||
config_destroy(&cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get port
|
||||
if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {
|
||||
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PORT);
|
||||
syslog(LOG_WARNING, "Using default '%s': %d\n", NAME_PORT, DEFAULT_PORT);
|
||||
*port = DEFAULT_PORT;
|
||||
}
|
||||
|
||||
// Get PID file location
|
||||
const char *tmp_pid_file;
|
||||
|
||||
if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {
|
||||
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_PID_FILE_PATH);
|
||||
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);
|
||||
tmp_pid_file = DEFAULT_PID_FILE_PATH;
|
||||
}
|
||||
|
||||
*pid_file_path = malloc(strlen(tmp_pid_file) + 1);
|
||||
strcpy(*pid_file_path, tmp_pid_file);
|
||||
|
||||
// Get keys file location
|
||||
const char *tmp_keys_file;
|
||||
|
||||
if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {
|
||||
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_KEYS_FILE_PATH);
|
||||
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);
|
||||
tmp_keys_file = DEFAULT_KEYS_FILE_PATH;
|
||||
}
|
||||
|
||||
*keys_file_path = malloc(strlen(tmp_keys_file) + 1);
|
||||
strcpy(*keys_file_path, tmp_keys_file);
|
||||
|
||||
// Get IPv6 option
|
||||
if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {
|
||||
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_IPV6);
|
||||
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? "true" : "false");
|
||||
*enable_ipv6 = DEFAULT_ENABLE_IPV6;
|
||||
}
|
||||
|
||||
// Get LAN discovery option
|
||||
if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {
|
||||
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_LAN_DISCOVERY);
|
||||
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_LAN_DISCOVERY,
|
||||
DEFAULT_ENABLE_LAN_DISCOVERY ? "true" : "false");
|
||||
*enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
|
||||
syslog(LOG_DEBUG, "Successfully read:\n");
|
||||
syslog(LOG_DEBUG, "'%s': %s\n", NAME_PID_FILE_PATH, *pid_file_path);
|
||||
syslog(LOG_DEBUG, "'%s': %s\n", NAME_KEYS_FILE_PATH, *keys_file_path);
|
||||
syslog(LOG_DEBUG, "'%s': %d\n", NAME_PORT, *port);
|
||||
syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
|
||||
syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Bootstraps servers listed in the config file
|
||||
//
|
||||
// returns 1 on success
|
||||
// 0 on failure, either no or only some servers were bootstrapped
|
||||
|
||||
int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6)
|
||||
{
|
||||
const char *NAME_BOOTSTRAP_SERVERS = "bootstrap_servers";
|
||||
|
||||
const char *NAME_PUBLIC_KEY = "public_key";
|
||||
const char *NAME_PORT = "port";
|
||||
const char *NAME_ADDRESS = "address";
|
||||
|
||||
config_t cfg;
|
||||
|
||||
config_init(&cfg);
|
||||
|
||||
if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {
|
||||
syslog(LOG_ERR, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
|
||||
config_destroy(&cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
config_setting_t *server_list = config_lookup(&cfg, NAME_BOOTSTRAP_SERVERS);
|
||||
|
||||
if (server_list == NULL) {
|
||||
syslog(LOG_ERR, "No '%s' setting in configuration file.\n", NAME_BOOTSTRAP_SERVERS);
|
||||
config_destroy(&cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bs_port;
|
||||
const char *bs_address;
|
||||
const char *bs_public_key;
|
||||
|
||||
config_setting_t *server;
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (config_setting_length(server_list)) {
|
||||
|
||||
server = config_setting_get_elem(server_list, 0);
|
||||
|
||||
if (server == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Proceed only if all parts are present
|
||||
if (config_setting_lookup_string(server, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE ||
|
||||
config_setting_lookup_int (server, NAME_PORT, &bs_port) == CONFIG_FALSE ||
|
||||
config_setting_lookup_string(server, NAME_ADDRESS, &bs_address) == CONFIG_FALSE ) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (strlen(bs_public_key) != 64) {
|
||||
syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %s.\n", i, NAME_PUBLIC_KEY, bs_public_key);
|
||||
goto next;
|
||||
}
|
||||
|
||||
// not (1 <= port <= 65535)
|
||||
if (bs_port < 1 || bs_port > 65535) {
|
||||
syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %d.\n", i, NAME_PORT, bs_port);
|
||||
goto next;
|
||||
}
|
||||
|
||||
const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),
|
||||
hex_string_to_bin((char *)bs_public_key));
|
||||
|
||||
if (!address_resolved) {
|
||||
syslog(LOG_WARNING, "bootstrap_server #%d: Invalid '%s': %s.\n", i, NAME_ADDRESS, bs_address);
|
||||
goto next;
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, "Successfully connected to %s:%d %s\n", bs_address, bs_port, bs_public_key);
|
||||
|
||||
next:
|
||||
// config_setting_lookup_string() allocates string inside and doesn't allow us to free it
|
||||
// so in order to reuse `bs_public_key` and `bs_address` we have to remove the element
|
||||
// which will cause libconfig to free allocated strings
|
||||
config_setting_remove_elem(server_list, 0);
|
||||
i++;
|
||||
}
|
||||
|
||||
config_destroy(&cfg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Checks if we are connected to the DHT
|
||||
//
|
||||
// returns 1 on success
|
||||
// 0 on failure
|
||||
|
||||
int is_conencted(DHT *dht, int port, int enable_lan_discovery)
|
||||
{
|
||||
uint16_t htons_port = htons(port);
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 100; i ++) {
|
||||
do_DHT(dht);
|
||||
|
||||
if (enable_lan_discovery) {
|
||||
send_LANdiscovery(htons_port, dht->c);
|
||||
}
|
||||
|
||||
networking_poll(dht->c->lossless_udp->net);
|
||||
|
||||
if (DHT_isconnected(dht)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
sleep;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prints public key
|
||||
|
||||
void print_public_key(uint8_t *public_key)
|
||||
{
|
||||
char buffer[64 + 1];
|
||||
int index = 0;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (public_key[i] < 16) {
|
||||
index += sprintf(buffer + index, "0");
|
||||
}
|
||||
|
||||
index += sprintf(buffer + index, "%hhX", public_key[i]);
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "Public Key: %s\n", buffer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
|
||||
|
||||
if (argc < 2) {
|
||||
syslog(LOG_ERR, "Please specify a configuration file. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *cfg_file_path = argv[1];
|
||||
char *pid_file_path, *keys_file_path;
|
||||
int port;
|
||||
int enable_ipv6;
|
||||
int enable_lan_discovery;
|
||||
|
||||
if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery)) {
|
||||
syslog(LOG_DEBUG, "General config read successfully\n");
|
||||
} else {
|
||||
syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// not (1 <= port <= 65535)
|
||||
if (port < 1 || port > 65535) {
|
||||
syslog(LOG_ERR, "Invalid port: %d, must be 1 <= port <= 65535. Exiting.\n", port);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if the PID file exists
|
||||
if (fopen(pid_file_path, "r")) {
|
||||
syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists. Exiting.\n", pid_file_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
IP ip;
|
||||
ip_init(&ip, enable_ipv6);
|
||||
|
||||
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, port)));
|
||||
|
||||
if (dht == NULL) {
|
||||
syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (enable_lan_discovery) {
|
||||
LANdiscovery_init(dht);
|
||||
}
|
||||
|
||||
if (manage_keys(dht, keys_file_path)) {
|
||||
syslog(LOG_DEBUG, "Keys are managed successfully\n");
|
||||
} else {
|
||||
syslog(LOG_ERR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
|
||||
syslog(LOG_DEBUG, "List of bootstrap servers read successfully\n");
|
||||
} else {
|
||||
syslog(LOG_ERR, "Couldn't read list of bootstrap servers in %s. Exiting.\n", cfg_file_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_conencted(dht, port, enable_lan_discovery)) {
|
||||
syslog(LOG_INFO, "Successfully connected to DHT\n");
|
||||
} else {
|
||||
syslog(LOG_ERR, "Couldn't connect to the DHT. Check settings and network connections. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_public_key(dht->c->self_public_key);
|
||||
|
||||
// Write the PID file
|
||||
FILE *pidf = fopen(pid_file_path, "w");
|
||||
|
||||
if (pidf == NULL) {
|
||||
syslog(LOG_ERR, "Can't open the PID file for writing: %s. Exiting.\n", pid_file_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(pid_file_path);
|
||||
free(keys_file_path);
|
||||
|
||||
// Fork off from the parent process
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
syslog(LOG_ERR, "Forking failed. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Change the file mode mask
|
||||
umask(0);
|
||||
|
||||
fprintf(pidf, "%d\n", pid);
|
||||
fclose(pidf);
|
||||
|
||||
// Create a new SID for the child process
|
||||
if (setsid() < 0) {
|
||||
syslog(LOG_ERR, "SID creation failure. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Change the current working directory
|
||||
if ((chdir("/")) < 0) {
|
||||
syslog(LOG_ERR, "Couldn't change working directory to '/'. Exiting.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Go quiet
|
||||
close(STDOUT_FILENO);
|
||||
close(STDIN_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
uint64_t last_LANdiscovery = 0;
|
||||
uint16_t htons_port = htons(port);
|
||||
|
||||
while (1) {
|
||||
do_DHT(dht);
|
||||
|
||||
if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {
|
||||
send_LANdiscovery(htons_port, dht->c);
|
||||
last_LANdiscovery = unix_time();
|
||||
}
|
||||
|
||||
networking_poll(dht->c->lossless_udp->net);
|
||||
|
||||
sleep;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user