Revert "Use git description as the tinc version."
[tinc] / src / tincctl.c
index 81e7a7a..799da0a 100644 (file)
@@ -38,6 +38,7 @@
 #include "utils.h"
 #include "tincctl.h"
 #include "top.h"
+#include "version.h"
 
 #ifndef MSG_NOSIGNAL
 #define MSG_NOSIGNAL 0
@@ -85,7 +86,7 @@ static struct option const long_options[] = {
 
 static void version(void) {
        printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
-                  VERSION, __DATE__, __TIME__, PROT_MAJOR, PROT_MINOR);
+                  VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
        printf("Copyright (C) 1998-2012 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"
@@ -116,9 +117,9 @@ static void usage(bool status) {
                                "  restart [tincd options]    Restart tincd.\n"
                                "  reload                     Partially reload configuration of running tincd.\n"
                                "  pid                        Show PID of currently running tincd.\n"
-                               "  generate-keys [bits]       Generate new RSA and ECDSA public/private keypairs.\n"
+                               "  generate-keys [bits]       Generate new RSA and Ed25519 public/private keypairs.\n"
                                "  generate-rsa-keys [bits]   Generate a new RSA public/private keypair.\n"
-                               "  generate-ecdsa-keys        Generate a new ECDSA public/private keypair.\n"
+                               "  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"
                                "    edges                    - all known connections in the VPN\n"
@@ -246,19 +247,19 @@ static void disable_old_keys(const char *filename, const char *what) {
 
        while(fgets(buf, sizeof buf, r)) {
                if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
-                       if((strstr(buf, " EC ") && strstr(what, "ECDSA")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
+                       if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
                                disabled = true;
                                block = true;
                        }
                }
 
-               bool ecdsapubkey = !strncasecmp(buf, "ECDSAPublicKey", 14) && strchr(" \t=", buf[14]) && strstr(what, "ECDSA");
+               bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
 
-               if(ecdsapubkey)
+               if(ed25519pubkey)
                        disabled = true;
 
                if(w) {
-                       if(block || ecdsapubkey)
+                       if(block || ed25519pubkey)
                                fputc('#', w);
                        if(fputs(buf, w) < 0) {
                                error = true;
@@ -355,15 +356,15 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
 }
 
 /*
-  Generate a public/private ECDSA keypair, and ask for a file to store
+  Generate a public/private Ed25519 keypair, and ask for a file to store
   them in.
 */
-static bool ecdsa_keygen(bool ask) {
+static bool ed25519_keygen(bool ask) {
        ecdsa_t *key;
        FILE *f;
        char *pubname, *privname;
 
-       fprintf(stderr, "Generating ECDSA keypair:\n");
+       fprintf(stderr, "Generating Ed25519 keypair:\n");
 
        if(!(key = ecdsa_generate())) {
                fprintf(stderr, "Error during key generation!\n");
@@ -371,8 +372,8 @@ static bool ecdsa_keygen(bool ask) {
        } else
                fprintf(stderr, "Done.\n");
 
-       xasprintf(&privname, "%s" SLASH "ecdsa_key.priv", confbase);
-       f = ask_and_open(privname, "private ECDSA key", "a", ask, 0600);
+       xasprintf(&privname, "%s" SLASH "ed25519_key.priv", confbase);
+       f = ask_and_open(privname, "private Ed25519 key", "a", ask, 0600);
        free(privname);
 
        if(!f)
@@ -390,16 +391,16 @@ static bool ecdsa_keygen(bool ask) {
        if(name)
                xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
        else
-               xasprintf(&pubname, "%s" SLASH "ecdsa_key.pub", confbase);
+               xasprintf(&pubname, "%s" SLASH "ed25519_key.pub", confbase);
 
-       f = ask_and_open(pubname, "public ECDSA key", "a", ask, 0666);
+       f = ask_and_open(pubname, "public Ed25519 key", "a", ask, 0666);
        free(pubname);
 
        if(!f)
                return false;
 
        char *pubkey = ecdsa_get_base64_public_key(key);
-       fprintf(f, "ECDSAPublicKey = %s\n", pubkey);
+       fprintf(f, "Ed25519PublicKey = %s\n", pubkey);
        free(pubkey);
 
        fclose(f);
@@ -417,6 +418,15 @@ static bool rsa_keygen(int bits, bool ask) {
        FILE *f;
        char *pubname, *privname;
 
+       // Make sure the key size is a multiple of 8 bits.
+       bits &= ~0x7;
+
+       // Force them to be between 1024 and 8192 bits long.
+       if(bits < 1024)
+               bits = 1024;
+       if(bits > 8192)
+               bits = 8192;
+
        fprintf(stderr, "Generating %d bits keys:\n", bits);
 
        if(!(key = rsa_generate(bits, 0x10001))) {
@@ -476,7 +486,7 @@ bool recvline(int fd, char *line, size_t len) {
 
        while(!(newline = memchr(buffer, '\n', blen))) {
                int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
-               if(result == -1 && errno == EINTR)
+               if(result == -1 && sockerrno == EINTR)
                        continue;
                else if(result <= 0)
                        return false;
@@ -502,7 +512,7 @@ bool recvdata(int fd, char *data, size_t len) {
 
        while(blen < len) {
                int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
-               if(result == -1 && errno == EINTR)
+               if(result == -1 && sockerrno == EINTR)
                        continue;
                else if(result <= 0)
                        return false;
@@ -534,7 +544,7 @@ bool sendline(int fd, char *format, ...) {
 
        while(blen) {
                int result = send(fd, p, blen, MSG_NOSIGNAL);
-               if(result == -1 && errno == EINTR)
+               if(result == -1 && sockerrno == EINTR)
                        continue;
                else if(result <= 0)
                        return false;
@@ -714,7 +724,7 @@ bool connect_tincd(bool verbose) {
 
        if(getaddrinfo(host, port, &hints, &res) || !res) {
                if(verbose)
-                       fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, strerror(errno));
+                       fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, sockstrerror(sockerrno));
                return false;
        }
 
@@ -800,16 +810,31 @@ static int cmd_start(int argc, char *argv[]) {
        int nargc = 0;
        char **nargv = xzalloc((optind + argc) * sizeof *nargv);
 
-       nargv[nargc++] = c;
+       char *arg0 = c;
+#ifdef HAVE_MINGW
+       /*
+          Windows has no real concept of an "argv array". A command line is just one string.
+          The CRT of the new process will decode the command line string to generate argv before calling main(), and (by convention)
+          it uses quotes to handle spaces in arguments.
+          Therefore we need to quote all arguments that might contain spaces. No, execvp() won't do that for us (see MSDN).
+          If we don't do that, then execvp() will run fine but any spaces in the filename contained in arg0 will bleed
+          into the next arguments when the spawned process' CRT parses its command line, resulting in chaos.
+       */
+       xasprintf(&arg0, "\"%s\"", arg0);
+#endif
+       nargv[nargc++] = arg0;
        for(int i = 1; i < optind; i++)
                nargv[nargc++] = orig_argv[i];
        for(int i = 1; i < argc; i++)
                nargv[nargc++] = argv[i];
 
 #ifdef HAVE_MINGW
-       execvp(c, nargv);
-       fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
-       return 1;
+       int status = spawnvp(_P_WAIT, c, nargv);
+       if (status == -1) {
+               fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
+               return 1;
+       }
+       return status;
 #else
        pid_t pid = fork();
        if(pid == -1) {
@@ -976,6 +1001,8 @@ static int cmd_dump(int argc, char *argv[]) {
                char subnet[4096];
                char host[4096];
                char port[4096];
+               char local_host[4096];
+               char local_port[4096];
                char via[4096];
                char nexthop[4096];
                int cipher, digest, maclength, compression, distance, socket, weight;
@@ -1016,8 +1043,8 @@ static int cmd_dump(int argc, char *argv[]) {
                        } break;
 
                        case REQ_DUMP_EDGES: {
-                               int n = sscanf(line, "%*d %*d %s %s %s port %s %x %d", from, to, host, port, &options, &weight);
-                               if(n != 6) {
+                               int n = sscanf(line, "%*d %*d %s %s %s port %s %s port %s %x %d", from, to, host, port, local_host, local_port, &options, &weight);
+                               if(n != 8) {
                                        fprintf(stderr, "Unable to parse edge dump from tincd.\n");
                                        return 1;
                                }
@@ -1029,7 +1056,7 @@ static int cmd_dump(int argc, char *argv[]) {
                                        else if(do_graph == 2)
                                                printf(" %s -> %s [w = %f, weight = %f];\n", node1, node2, w, w);
                                } else {
-                                       printf("%s to %s at %s port %s options %x weight %d\n", from, to, host, port, options, weight);
+                                       printf("%s to %s at %s port %s local %s port %s options %x weight %d\n", from, to, host, port, local_host, local_port, options, weight);
                                }
                        } break;
 
@@ -1294,7 +1321,7 @@ const var_t variables[] = {
        {"Device", VAR_SERVER},
        {"DeviceType", VAR_SERVER},
        {"DirectOnly", VAR_SERVER},
-       {"ECDSAPrivateKeyFile", VAR_SERVER},
+       {"Ed25519PrivateKeyFile", VAR_SERVER},
        {"ExperimentalProtocol", VAR_SERVER},
        {"Forwarding", VAR_SERVER},
        {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
@@ -1332,8 +1359,8 @@ const var_t variables[] = {
        {"ClampMSS", VAR_SERVER | VAR_HOST},
        {"Compression", VAR_SERVER | VAR_HOST},
        {"Digest", VAR_SERVER | VAR_HOST},
-       {"ECDSAPublicKey", VAR_HOST},
-       {"ECDSAPublicKeyFile", VAR_SERVER | VAR_HOST},
+       {"Ed25519PublicKey", VAR_HOST},
+       {"Ed25519PublicKeyFile", VAR_SERVER | VAR_HOST},
        {"IndirectData", VAR_SERVER | VAR_HOST},
        {"MACLength", VAR_SERVER | VAR_HOST},
        {"PMTU", VAR_SERVER | VAR_HOST},
@@ -1604,7 +1631,7 @@ static int cmd_config(int argc, char *argv[]) {
        if(action < -1) {
                if(!found)
                        fprintf(stderr, "No matching configuration variables found.\n");
-               return 0;
+               return 1;
        }
 
        // Make sure we wrote everything...
@@ -1617,7 +1644,7 @@ static int cmd_config(int argc, char *argv[]) {
        if(action < 0 && !removed) {
                remove(tmpfile);
                fprintf(stderr, "No configuration variables deleted.\n");
-               return *value != 0;
+               return 1;
        }
 
        // Replace the configuration file with the new one
@@ -1773,7 +1800,7 @@ static int cmd_init(int argc, char *argv[]) {
        fprintf(f, "Name = %s\n", name);
        fclose(f);
 
-       if(!rsa_keygen(2048, false) || !ecdsa_keygen(false))
+       if(!rsa_keygen(2048, false) || !ed25519_keygen(false))
                return 1;
 
        check_port(name);
@@ -1805,7 +1832,7 @@ static int cmd_generate_keys(int argc, char *argv[]) {
        if(!name)
                name = get_my_name(false);
 
-       return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ecdsa_keygen(true));
+       return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ed25519_keygen(true));
 }
 
 static int cmd_generate_rsa_keys(int argc, char *argv[]) {
@@ -1820,7 +1847,7 @@ static int cmd_generate_rsa_keys(int argc, char *argv[]) {
        return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
 }
 
-static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
+static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
        if(argc > 1) {
                fprintf(stderr, "Too many arguments!\n");
                return 1;
@@ -1829,7 +1856,7 @@ static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
        if(!name)
                name = get_my_name(false);
 
-       return !ecdsa_keygen(true);
+       return !ed25519_keygen(true);
 }
 
 static int cmd_help(int argc, char *argv[]) {
@@ -2138,6 +2165,8 @@ static int cmd_network(int argc, char *argv[]) {
                free(fname);
        }
 
+       closedir(dir);
+
        return 0;
 }
 
@@ -2168,7 +2197,7 @@ static const struct {
        {"init", cmd_init},
        {"generate-keys", cmd_generate_keys},
        {"generate-rsa-keys", cmd_generate_rsa_keys},
-       {"generate-ecdsa-keys", cmd_generate_ecdsa_keys},
+       {"generate-ed25519-keys", cmd_generate_ed25519_keys},
        {"help", cmd_help},
        {"version", cmd_version},
        {"info", cmd_info},