From c52c46f8717aac6904f32766d774fa3fdf9611d8 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Mon, 16 Jul 2012 16:48:24 +0200 Subject: [PATCH] Add an easy way to export and import host configuration files. --- doc/tinc.texi | 11 ++++ doc/tincctl.8.in | 10 ++++ src/tincctl.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) diff --git a/doc/tinc.texi b/doc/tinc.texi index 876fe43..fb1cd38 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -2060,6 +2060,16 @@ If no @var{value} is given, all configuration variables with the same name will Start an editor for the given configuration file. You do not need to specify the full path to the file. +@item export +Export the host configuration file of the local node to standard output. + +@item export-all +Export all host configuration files to standard output. + +@item import [--force] +Import host configuration file(s) from standard input. +Already existing host configuration files are not overwritten unless the option --force is used. + @item start [tincd options] Start @samp{tincd}, optionally with the given extra options. @@ -2153,6 +2163,7 @@ tincctl -n vpn init foo tincctl -n vpn config Subnet 192.168.1.0/24 tincctl -n vpn config bar.Address bar.example.com tincctl -n vpn config ConnectTo bar +tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com @end example @c ================================================================== diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in index 8693dc0..4b6d426 100644 --- a/doc/tincctl.8.in +++ b/doc/tincctl.8.in @@ -71,6 +71,15 @@ is given, all configuration variables with the same name will be removed. .It edit Ar filename Start an editor for the given configuration file. You do not need to specify the full path to the file. +.It export +Export the host configuration file of the local node to standard output. +.It export-all +Export all host configuration files to standard output. +.It import Op Fl -force +Import host configuration file(s) from standard input. +Already existing host configuration files are not overwritten unless the option +.Fl -force +is used. .It start Op tincd options Start .Xr tincd 8 , @@ -172,6 +181,7 @@ tincctl -n vpn init foo tincctl -n vpn config Subnet 192.168.1.0/24 tincctl -n vpn config bar.Address bar.example.com tincctl -n vpn config ConnectTo bar +tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com .Sh TOP The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters. It displays a list of all the known nodes in the left-most column, diff --git a/src/tincctl.c b/src/tincctl.c index f3a73b7..057ff7c 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -56,6 +56,7 @@ static char line[4096]; static int code; static int req; static int result; +static bool force = false; #ifdef HAVE_MINGW static struct WSAData wsa_state; @@ -75,6 +76,7 @@ static struct option const long_options[] = { {"chroot", no_argument, NULL, 0}, {"user", required_argument, NULL, 0}, {"option", required_argument, NULL, 0}, + {"force", no_argument, NULL, 6}, {NULL, 0, NULL, 0} }; @@ -131,6 +133,9 @@ static void usage(bool status) { #endif " pcap [snaplen] Dump traffic in pcap format [up to snaplen bytes per packet]\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" "\n"); printf("Report bugs to tinc@tinc-vpn.org.\n"); } @@ -165,6 +170,10 @@ static bool parse_options(int argc, char **argv) { pidfilename = xstrdup(optarg); break; + case 6: + force = true; + break; + case '?': usage(true); return false; @@ -1363,6 +1372,131 @@ static int cmd_edit(int argc, char *argv[]) { return 0; } +static int export(const char *name, FILE *out) { + char *filename; + xasprintf(&filename, "%s/%s", hosts_dir, name); + FILE *in = fopen(filename, "r"); + if(!in) { + fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno)); + return 1; + } + + fprintf(out, "Name = %s\n", name); + char buf[4096]; + while(fgets(buf, sizeof buf, in)) + fputs(buf, out); + + if(ferror(in)) { + fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno)); + return 1; + } + + fclose(in); + return 0; +} + +static int cmd_export(int argc, char *argv[]) { + char *name = get_my_name(); + if(!name) + return 1; + + return export(name, stdout); +} + +static int cmd_export_all(int argc, char *argv[]) { + DIR *dir = opendir(hosts_dir); + if(!dir) { + fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno)); + return 1; + } + + bool first = true; + int result = 0; + struct dirent *ent; + + while((ent = readdir(dir))) { + if(!check_id(ent->d_name)) + continue; + + if(first) + first = false; + else + printf("#---------------------------------------------------------------#\n"); + + result |= export(ent->d_name, stdout); + } + + closedir(dir); + return result; +} + +static int cmd_import(int argc, char *argv[]) { + FILE *in = stdin; + FILE *out = NULL; + + char buf[4096]; + char name[4096]; + char *filename; + int count = 0; + bool firstline = true; + + while(fgets(buf, sizeof buf, in)) { + if(sscanf(buf, "Name = %s", name) == 1) { + if(!check_id(name)) { + fprintf(stderr, "Invalid Name in input!\n"); + return 1; + } + + if(out) + fclose(out); + + free(filename); + xasprintf(&filename, "%s/%s", hosts_dir, name); + + if(!force && !access(filename, F_OK)) { + fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename); + out = NULL; + continue; + } + + out = fopen(filename, "w"); + if(!out) { + fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno)); + return 1; + } + + count++; + firstline = false; + continue; + } else if(firstline) { + fprintf(stderr, "Junk at the beginning of the input, ignoring.\n"); + firstline = false; + } + + + if(!strcmp(buf, "#---------------------------------------------------------------#\n")) + continue; + + if(out) { + if(fputs(buf, out) < 0) { + fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno)); + return 1; + } + } + } + + if(out) + fclose(out); + + if(count) { + fprintf(stderr, "Imported %d host configuration files.\n", count); + return 0; + } else { + fprintf(stderr, "No host configuration files imported.\n"); + return 1; + } +} + static const struct { const char *command; int (*function)(int argc, char *argv[]); @@ -1390,6 +1524,9 @@ static const struct { {"version", cmd_version}, {"info", cmd_info}, {"edit", cmd_edit}, + {"export", cmd_export}, + {"export-all", cmd_export_all}, + {"import", cmd_import}, {NULL, NULL}, }; -- 2.25.1