/*
tincctl.c -- Controlling a running tincd
- Copyright (C) 2007-2014 Guus Sliepen <guus@tinc-vpn.org>
+ Copyright (C) 2007-2015 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "control_common.h"
#include "crypto.h"
#include "ecdsagen.h"
+#include "fsck.h"
#include "info.h"
#include "invitation.h"
#include "names.h"
static int code;
static int req;
static int result;
-static bool force = false;
+bool force = false;
bool tty = true;
bool confbasegiven = false;
bool netnamegiven = false;
static void version(void) {
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
- VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
+ BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n"
"See the AUTHORS file for a complete list.\n\n"
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
" -c, --config=DIR Read configuration options from DIR.\n"
" -n, --net=NETNAME Connect to net NETNAME.\n"
" --pidfile=FILENAME Read control cookie from FILENAME.\n"
+ " --force Force some commands to work despite warnings.\n"
" --help Display this help and exit.\n"
" --version Output version information and exit.\n"
"\n"
" restart [tincd options] Restart tincd.\n"
" reload Partially reload configuration of running tincd.\n"
" pid Show PID of currently running tincd.\n"
+#ifdef DISABLE_LEGACY
+ " generate-keys Generate a new Ed25519 public/private keypair.\n"
+#else
" generate-keys [bits] Generate new RSA and Ed25519 public/private keypairs.\n"
" generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n"
+#endif
" generate-ed25519-keys Generate a new Ed25519 public/private keypair.\n"
" dump Dump a list of one of the following things:\n"
" [reachable] nodes - all known nodes in the VPN\n"
" subnets - all known subnets in the VPN\n"
" connections - all meta connections with ourself\n"
" [di]graph - graph of the VPN in dotty format\n"
+ " invitations - outstanding invitations\n"
" info NODE|SUBNET|ADDRESS Give information about a particular NODE, SUBNET or ADDRESS.\n"
" purge Purge unreachable nodes\n"
" debug N Set debug level\n"
" log [level] Dump log output [up to the specified level]\n"
" export Export host configuration of local node to standard output\n"
" export-all Export all host configuration files to standard output\n"
- " import [--force] Import host configuration file(s) from standard input\n"
- " exchange [--force] Same as export followed by import\n"
- " exchange-all [--force] Same as export-all followed by import\n"
+ " import Import host configuration file(s) from standard input\n"
+ " exchange Same as export followed by import\n"
+ " exchange-all Same as export-all followed by import\n"
" invite NODE [...] Generate an invitation for NODE\n"
- " join INVITATION Join a VPN using an INVITIATION\n"
+ " join INVITATION Join a VPN using an INVITATION\n"
" network [NETNAME] List all known networks, or switch to the one named NETNAME.\n"
+ " fsck Check the configuration files for problems.\n"
"\n");
printf("Report bugs to tinc@tinc-vpn.org.\n");
}
return true;
}
+#ifndef DISABLE_LEGACY
/*
Generate a public/private RSA keypair, and ask for a file to store
them in.
return true;
}
+#endif
char buffer[4096];
size_t blen = 0;
}
+static int dump_invitations(void) {
+ char dname[PATH_MAX];
+ snprintf(dname, sizeof dname, "%s" SLASH "invitations", confbase);
+ DIR *dir = opendir(dname);
+ if(!dir) {
+ if(errno == ENOENT) {
+ fprintf(stderr, "No outstanding invitations.\n");
+ return 0;
+ }
+
+ fprintf(stderr, "Cannot not read directory %s: %s\n", dname, strerror(errno));
+ return 1;
+ }
+
+ struct dirent *ent;
+ bool found = false;
+
+ while((ent = readdir(dir))) {
+ char buf[MAX_STRING_SIZE];
+ if(b64decode(ent->d_name, buf, 24) != 18)
+ continue;
+
+ char fname[PATH_MAX];
+ snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ent->d_name);
+ FILE *f = fopen(fname, "r");
+ if(!f) {
+ fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno));
+ fclose(f);
+ continue;
+ }
+
+ buf[0] = 0;
+ if(!fgets(buf, sizeof buf, f)) {
+ fprintf(stderr, "Invalid invitation file %s", fname);
+ fclose(f);
+ continue;
+ }
+ fclose(f);
+
+ char *eol = buf + strlen(buf);
+ while(strchr("\t \r\n", *--eol))
+ *eol = 0;
+ if(strncmp(buf, "Name = ", 7) || !check_id(buf + 7)) {
+ fprintf(stderr, "Invalid invitation file %s", fname);
+ continue;
+ }
+
+ found = true;
+ printf("%s %s\n", ent->d_name, buf + 7);
+ }
+
+ closedir(dir);
+
+ if(!found)
+ fprintf(stderr, "No outstanding invitations.\n");
+
+ return 0;
+}
+
static int cmd_dump(int argc, char *argv[]) {
bool only_reachable = false;
return 1;
}
+ if(!strcasecmp(argv[1], "invitations"))
+ return dump_invitations();
+
if(!connect_tincd(true))
return 1;
{"ScriptsInterpreter", VAR_SERVER},
{"StrictSubnets", VAR_SERVER},
{"TunnelServer", VAR_SERVER},
+ {"UDPDiscovery", VAR_SERVER},
+ {"UDPDiscoveryKeepaliveInterval", VAR_SERVER},
+ {"UDPDiscoveryInterval", VAR_SERVER},
+ {"UDPDiscoveryTimeout", VAR_SERVER},
+ {"MTUInfoInterval", VAR_SERVER},
+ {"UDPInfoInterval", VAR_SERVER},
{"UDPRcvBuf", VAR_SERVER},
{"UDPSndBuf", VAR_SERVER},
{"VDEGroup", VAR_SERVER},
}
set = true;
continue;
+ // Add
+ } else if(action > 0) {
+ // Check if we've already seen this variable with the same value
+ if(!strcasecmp(bvalue, value))
+ found = true;
}
}
}
// Add new variable if necessary.
- if(action > 0 || (action == 0 && !set)) {
+ if((action > 0 && !found)|| (action == 0 && !set)) {
if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
return 1;
fprintf(f, "Name = %s\n", name);
fclose(f);
- if(!rsa_keygen(2048, false) || !ed25519_keygen(false))
+#ifndef DISABLE_LEGACY
+ if(!rsa_keygen(2048, false))
+ return 1;
+#endif
+
+ if(!ed25519_keygen(false))
return 1;
check_port(name);
}
static int cmd_generate_keys(int argc, char *argv[]) {
+#ifdef DISABLE_LEGACY
+ if(argc > 1) {
+#else
if(argc > 2) {
+#endif
fprintf(stderr, "Too many arguments!\n");
return 1;
}
if(!name)
name = get_my_name(false);
- return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ed25519_keygen(true));
+#ifndef DISABLE_LEGACY
+ if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true))
+ return 1;
+#endif
+
+ if(!ed25519_keygen(true))
+ return 1;
+
+ return 0;
}
+#ifndef DISABLE_LEGACY
static int cmd_generate_rsa_keys(int argc, char *argv[]) {
if(argc > 2) {
fprintf(stderr, "Too many arguments!\n");
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
}
+#endif
static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
if(argc > 1) {
free(netname);
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
- make_names();
xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
xasprintf(&prompt, "%s> ", identname);
return 0;
}
+static int cmd_fsck(int argc, char *argv[]) {
+ if(argc > 1) {
+ fprintf(stderr, "Too many arguments!\n");
+ return 1;
+ }
+
+ return fsck(orig_argv[0]);
+}
+
static const struct {
const char *command;
int (*function)(int argc, char *argv[]);
{"restart", cmd_restart},
{"reload", cmd_reload},
{"dump", cmd_dump},
+ {"list", cmd_dump},
{"purge", cmd_purge},
{"debug", cmd_debug},
{"retry", cmd_retry},
{"set", cmd_config},
{"init", cmd_init},
{"generate-keys", cmd_generate_keys},
+#ifndef DISABLE_LEGACY
{"generate-rsa-keys", cmd_generate_rsa_keys},
+#endif
{"generate-ed25519-keys", cmd_generate_ed25519_keys},
{"help", cmd_help},
{"version", cmd_version},
{"invite", cmd_invite},
{"join", cmd_join},
{"network", cmd_network},
+ {"fsck", cmd_fsck},
{NULL, NULL},
};