Add support for building tinc with MSVC
authorKirill Isakov <bootctl@gmail.com>
Fri, 25 Mar 2022 14:09:36 +0000 (20:09 +0600)
committerKirill Isakov <bootctl@gmail.com>
Mon, 28 Mar 2022 15:38:29 +0000 (21:38 +0600)
Tests are not supported because of their strong dependence on running
under Unix-like environment.

28 files changed:
meson.build
src/dropin.c
src/dropin.h
src/ed25519/fixedint.h
src/ethernet.h
src/fsck.c
src/git_tag.sh [deleted file]
src/have.h
src/include/meson.build
src/invitation.c
src/ipv4.h
src/ipv6.h
src/logger.h
src/meson.build
src/mingw/meson.build
src/net.c
src/net_packet.c
src/nolegacy/prf.c
src/openssl/digest.c
src/openssl/prf.c
src/protocol.c
src/protocol_auth.c
src/protocol_key.c
src/script.c
src/sptps.c
src/tincctl.c
src/upnp.c
test/meson.build

index 38062a9..f0c2fa1 100644 (file)
@@ -1,5 +1,5 @@
 project('tinc', 'c',
-  version: run_command('./src/git_tag.sh', check: true).stdout().strip(),
+  version: '1.18pre',
   license: 'GPL-2.0-or-later',
   meson_version: '>=0.51',
   default_options: [
@@ -12,6 +12,7 @@ project('tinc', 'c',
 dir_run_state = get_option('runstatedir')
 opt_crypto = get_option('crypto')
 opt_curses = get_option('curses')
+opt_debug = get_option('debug')
 opt_docs = get_option('docs')
 opt_harden = get_option('hardening')
 opt_jumbograms = get_option('jumbograms')
@@ -31,6 +32,7 @@ meson_version = meson.version()
 
 cc = meson.get_compiler('c')
 os_name = host_machine.system()
+cpu_family = host_machine.cpu_family()
 cc_name = cc.get_id()
 
 cc_defs = ['-D_GNU_SOURCE']
@@ -47,33 +49,45 @@ else
   static = opt_static.enabled()
 endif
 
-if static
+if static and cc_name != 'msvc'
   ld_flags += '-static'
 endif
 
 if opt_harden
-  cc_flags += [
-    '-D_FORTIFY_SOURCE=2',
-    '-fwrapv',
-    '-fno-strict-overflow',
-    '-Wreturn-type',
-    '-Wold-style-definition',
-    '-Wmissing-declarations',
-    '-Wmissing-prototypes',
-    '-Wstrict-prototypes',
-    '-Wredundant-decls',
-    '-Wbad-function-cast',
-    '-Wwrite-strings',
-    '-fdiagnostics-show-option',
-    '-fstrict-aliasing',
-    '-Wmissing-noreturn',
-  ]
-  if cc_name == 'clang'
-    cc_flags += '-Qunused-arguments'
-  endif
-  ld_flags += ['-Wl,-z,relro', '-Wl,-z,now']
-  if os_name == 'windows'
-    ld_flags += ['-Wl,--dynamicbase', '-Wl,--nxcompat']
+  if cc_name == 'msvc'
+    # Most of these flags are already ON by default in the latest version of MSVC.
+    # Add anyway in case someone is building using an old toolchain.
+    cc_flags += ['/guard:cf', '/GS']
+    ld_flags += [
+      '/guard:cf',
+      '/NXCOMPAT',
+      '/DYNAMICBASE',
+      cpu_family.endswith('64') ? '/HIGHENTROPYVA' : '/SAFESEH',
+    ]
+  else
+    cc_flags += [
+      '-D_FORTIFY_SOURCE=2',
+      '-fwrapv',
+      '-fno-strict-overflow',
+      '-Wreturn-type',
+      '-Wold-style-definition',
+      '-Wmissing-declarations',
+      '-Wmissing-prototypes',
+      '-Wstrict-prototypes',
+      '-Wredundant-decls',
+      '-Wbad-function-cast',
+      '-Wwrite-strings',
+      '-fdiagnostics-show-option',
+      '-fstrict-aliasing',
+      '-Wmissing-noreturn',
+    ]
+    if cc_name == 'clang'
+      cc_flags += '-Qunused-arguments'
+    endif
+    ld_flags += ['-Wl,-z,relro', '-Wl,-z,now']
+    if os_name == 'windows'
+      ld_flags += ['-Wl,--dynamicbase', '-Wl,--nxcompat']
+    endif
   endif
 endif
 
index e732fa0..1489ee6 100644 (file)
@@ -145,3 +145,12 @@ int gettimeofday(struct timeval *tv, void *tz) {
        return 0;
 }
 #endif
+
+bool sleep_millis(unsigned int ms) {
+#ifdef _MSC_VER
+       Sleep(ms);
+       return true;
+#else
+       return !usleep(ms * 1000);
+#endif
+}
index 2aa6df1..9b196b6 100644 (file)
@@ -71,4 +71,30 @@ extern int gettimeofday(struct timeval *, void *);
 #define MAX(a,b) (((a)>(b))?(a):(b))
 #endif
 
-#endif
+#ifdef _MSC_VER
+
+#define __attribute(args)
+#define __attribute__(args)
+
+#define PATH_MAX MAX_PATH
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define __const const
+
+typedef int mode_t;
+typedef int pid_t;
+typedef SSIZE_T ssize_t;
+
+static const int STDIN_FILENO = 0;
+static const int F_OK = 0;
+static const int X_OK = 0;
+static const int W_OK = 2;
+static const int R_OK = 4;
+
+#else // _MSC_VER
+
+#endif // _MSC_VER
+
+extern bool sleep_millis(unsigned int ms);
+
+#endif // TINC_DROPIN_H
index 553f888..41cdda4 100644 (file)
@@ -7,7 +7,7 @@
     Not a compatible replacement for <stdint.h>, do not blindly use it as such.
 */
 
-#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
+#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
 #include <stdint.h>
 #define FIXEDINT_H_INCLUDED
 
index 3b074b7..4ef9dab 100644 (file)
@@ -65,7 +65,7 @@ struct ether_header {
        uint8_t ether_dhost[ETH_ALEN];
        uint8_t ether_shost[ETH_ALEN];
        uint16_t ether_type;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #endif
 
 #ifndef HAVE_STRUCT_ARPHDR
@@ -75,7 +75,7 @@ struct arphdr {
        uint8_t ar_hln;
        uint8_t ar_pln;
        uint16_t ar_op;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 
 #define ARPOP_REQUEST 1
 #define ARPOP_REPLY 2
@@ -93,7 +93,7 @@ struct  ether_arp {
        uint8_t arp_spa[4];
        uint8_t arp_tha[ETH_ALEN];
        uint8_t arp_tpa[4];
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #define arp_hrd ea_hdr.ar_hrd
 #define arp_pro ea_hdr.ar_pro
 #define arp_hln ea_hdr.ar_hln
index 3a64959..fdd584e 100644 (file)
@@ -141,8 +141,9 @@ static void check_conffile(const char *nodename, bool server) {
                ++total_vars;
        }
 
-       int count[total_vars];
-       memset(count, 0, sizeof(count));
+       const size_t countlen = total_vars * sizeof(int);
+       int *count = alloca(countlen);
+       memset(count, 0, countlen);
 
        for splay_each(config_t, conf, &config) {
                int var_type = 0;
diff --git a/src/git_tag.sh b/src/git_tag.sh
deleted file mode 100755 (executable)
index 25677e2..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-git describe --always --tags --match='release-*' "$@" | sed 's/release-//'
index d1dd91d..f19c599 100644 (file)
@@ -25,6 +25,8 @@
 #define WINVER 0x0600
 #define _WIN32_WINNT 0x0600
 #define WIN32_LEAN_AND_MEAN
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_NONSTDC_NO_WARNINGS
 #endif
 
 #include <stdio.h>
 #include <signal.h>
 #include <errno.h>
 #include <fcntl.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <limits.h>
 #include <math.h>
 #include <time.h>
 
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#elif defined(HAVE_NETBSD)
+#define alloca(size) __builtin_alloca(size)
+#endif
+
 #ifdef HAVE_MINGW
+#ifdef HAVE_W32API_H
 #include <w32api.h>
+#endif
+
 #include <winsock2.h>
 #include <windows.h>
 #include <ws2tcpip.h>
+
+#ifdef _MSC_VER
+#include <io.h>
+#include <process.h>
+#include <direct.h>
 #endif
+#endif // HAVE_MINGW
 
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
 
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>
+#elif defined(_MSC_VER)
+#include "dirent.h"
 #endif
 
 /* SunOS really wants sys/socket.h BEFORE net/if.h,
index f6f4e04..0550996 100644 (file)
@@ -1,7 +1,7 @@
 configure_file(output: 'config.h', configuration: cdata)
 
 src_lib_common += vcs_tag(
-  command: './git_tag.sh',
+  command: ['git', 'describe', '--always', '--tags', '--match=release-*'],
   fallback: 'unknown',
   input: '../version_git.h.in',
   output: 'version_git.h',
index e71a488..d1e1e61 100644 (file)
@@ -457,11 +457,13 @@ int cmd_invite(int argc, char *argv[]) {
        randomize(cookie, 18);
 
        // Create a filename that doesn't reveal the cookie itself
-       uint8_t buf[18 + strlen(fingerprint)];
+       const size_t buflen = 18 + strlen(fingerprint);
+       uint8_t *buf = alloca(buflen);
+
        char cookiehash[64];
        memcpy(buf, cookie, 18);
-       memcpy(buf + 18, fingerprint, sizeof(buf) - 18);
-       sha512(buf, sizeof(buf), cookiehash);
+       memcpy(buf + 18, fingerprint, buflen - 18);
+       sha512(buf, buflen, cookiehash);
        b64encode_tinc_urlsafe(cookiehash, cookiehash, 18);
 
        free(fingerprint);
@@ -551,7 +553,7 @@ static char *data;
 static size_t datalen;
 static bool success = false;
 
-static char *get_line(const char **data) {
+static char *get_line(char *line, size_t linelen, const char **data) {
        if(!data || !*data) {
                return NULL;
        }
@@ -561,11 +563,10 @@ static char *get_line(const char **data) {
                return NULL;
        }
 
-       static char line[1024];
        const char *end = strchr(*data, '\n');
        size_t len = end ? (size_t)(end - *data) : strlen(*data);
 
-       if(len >= sizeof(line)) {
+       if(len >= linelen) {
                fprintf(stderr, "Maximum line length exceeded!\n");
                return NULL;
        }
@@ -587,7 +588,9 @@ static char *get_line(const char **data) {
 }
 
 static char *get_value(const char *data, const char *var) {
-       char *line = get_line(&data);
+       static char buf[1024];
+
+       char *line = get_line(buf, sizeof(buf), &data);
 
        if(!line) {
                return NULL;
@@ -654,18 +657,13 @@ static char *grep(const char *data, const char *var) {
 }
 
 static bool finalize_join(void) {
-       const char *temp_name = get_value(data, "Name");
+       const char *name = get_value(data, "Name");
 
-       if(!temp_name) {
+       if(!name) {
                fprintf(stderr, "No Name found in invitation!\n");
                return false;
        }
 
-       size_t len = strlen(temp_name);
-       char name[len + 1];
-       memcpy(name, temp_name, len);
-       name[len] = 0;
-
        if(!check_id(name)) {
                fprintf(stderr, "Invalid Name found in invitation!\n");
                return false;
@@ -772,7 +770,9 @@ make_names:
        const char *p = data;
        char *l, *value;
 
-       while((l = get_line(&p))) {
+       static char line[1024];
+
+       while((l = get_line(line, sizeof(line), &p))) {
                // Ignore comments
                if(*l == '#') {
                        continue;
@@ -879,7 +879,7 @@ make_names:
                        return false;
                }
 
-               while((l = get_line(&p))) {
+               while((l = get_line(line, sizeof(line), &p))) {
                        if(!strcmp(l, "#---------------------------------------------------------------#")) {
                                continue;
                        }
index 708e5c1..a412c60 100644 (file)
@@ -83,7 +83,7 @@ struct ip {
        uint8_t ip_p;
        uint16_t ip_sum;
        struct in_addr ip_src, ip_dst;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #endif
 
 #ifndef IP_OFFMASK
@@ -145,7 +145,7 @@ struct icmp {
 #define icmp_radv icmp_dun.id_radv
 #define icmp_mask icmp_dun.id_mask
 #define icmp_data icmp_dun.id_data
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #endif
 
 #endif
index cfa6f23..7c06de3 100644 (file)
@@ -51,7 +51,7 @@ struct ip6_hdr {
        } ip6_ctlun;
        struct in6_addr ip6_src;
        struct in6_addr ip6_dst;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #define ip6_vfc ip6_ctlun.ip6_un2_vfc
 #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
 #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
@@ -70,7 +70,7 @@ struct icmp6_hdr {
                uint16_t icmp6_un_data16[2];
                uint8_t icmp6_un_data8[4];
        } icmp6_dataun;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #define ICMP6_DST_UNREACH_NOROUTE 0
 #define ICMP6_DST_UNREACH 1
 #define ICMP6_PACKET_TOO_BIG 2
@@ -90,7 +90,7 @@ struct icmp6_hdr {
 struct nd_neighbor_solicit {
        struct icmp6_hdr nd_ns_hdr;
        struct in6_addr nd_ns_target;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #define ND_OPT_SOURCE_LINKADDR 1
 #define ND_OPT_TARGET_LINKADDR 2
 #define nd_ns_type nd_ns_hdr.icmp6_type
@@ -103,7 +103,7 @@ struct nd_neighbor_solicit {
 struct nd_opt_hdr {
        uint8_t nd_opt_type;
        uint8_t nd_opt_len;
-} __attribute__((__gcc_struct__)) __attribute((__packed__));
+};
 #endif
 
 #endif
index 66c32ab..5302582 100644 (file)
@@ -21,6 +21,8 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include "system.h"
+
 typedef enum debug_t {
        DEBUG_UNSET = -1,               /* Used by tinc as the default debug level. */
        DEBUG_NOTHING = 0,              /* Quiet mode, only show starting/stopping of the daemon */
index 43f70bf..92f42fa 100644 (file)
@@ -16,6 +16,7 @@ foreach attr : ['malloc', 'nonnull', 'warn_unused_result']
 endforeach
 
 check_headers = [
+  'alloca.h',
   'arpa/inet.h',
   'arpa/nameser.h',
   'dirent.h',
@@ -48,7 +49,9 @@ check_headers = [
   'sys/types.h',
   'sys/wait.h',
   'syslog.h',
+  'string.h',
   'termios.h',
+  'unistd.h',
 ]
 
 # 'struct msghdr' misses some required fields
index 796d62b..5cd2c7b 100644 (file)
@@ -1,11 +1,17 @@
-win_common_libs = ['ws2_32', 'iphlpapi', 'winpthread']
+check_headers += 'w32api.h'
 
-if opt_harden
+win_common_libs = ['ws2_32', 'iphlpapi', 'threads']
+
+if opt_harden and cc_name != 'msvc'
   win_common_libs += 'ssp'
 endif
 
 foreach libname : win_common_libs
-  deps_common += cc.find_library(libname)
+  dep = dependency(libname, required: false)
+  if not dep.found()
+    dep = cc.find_library(libname)
+  endif
+  deps_common += dep
 endforeach
 
 src_tincd += files('device.c')
index 7efe7fa..7f84421 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -269,9 +269,7 @@ static void periodic_handler(void *data) {
 
        if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
                logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
-               nanosleep(&(struct timespec) {
-                       sleeptime, 0
-               }, NULL);
+               sleep_millis(sleeptime * 1000);
                sleeptime *= 2;
 
                if(sleeptime < 0) {
index eb438b0..2722fb2 100644 (file)
@@ -962,7 +962,8 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
 
        if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && origlen > relay->minmtu)) {
                if(type != SPTPS_HANDSHAKE && (to->nexthop->connection->options >> 24) >= 7) {
-                       uint8_t buf[len + sizeof(to->id) + sizeof(from->id)];
+                       const size_t buflen = len + sizeof(to->id) + sizeof(from->id);
+                       uint8_t *buf = alloca(buflen);
                        uint8_t *buf_ptr = buf;
                        memcpy(buf_ptr, &to->id, sizeof(to->id));
                        buf_ptr += sizeof(to->id);
@@ -970,10 +971,10 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
                        buf_ptr += sizeof(from->id);
                        memcpy(buf_ptr, data, len);
                        logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (TCP)", from->name, from->hostname, to->name, to->hostname, to->nexthop->name, to->nexthop->hostname);
-                       return send_sptps_tcppacket(to->nexthop->connection, buf, sizeof(buf));
+                       return send_sptps_tcppacket(to->nexthop->connection, buf, buflen);
                }
 
-               char buf[B64_SIZE(len)];
+               char *buf = alloca(B64_SIZE(len));
                b64encode_tinc(data, buf, len);
 
                /* If this is a handshake packet, use ANS_KEY instead of REQ_KEY, for two reasons:
@@ -993,7 +994,7 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
                overhead += sizeof(to->id) + sizeof(from->id);
        }
 
-       char buf[len + overhead];
+       char *buf = alloca(len + overhead);
        char *buf_ptr = buf;
 
        if(relay_supported) {
@@ -1904,7 +1905,7 @@ void handle_device_data(void *data, int flags) {
                myself->in_bytes += packet.len;
                route(myself, &packet);
        } else {
-               usleep(errors * 50000);
+               sleep_millis(errors * 50);
                errors++;
 
                if(errors > 10) {
index 1e5bb9f..5db6430 100644 (file)
@@ -32,7 +32,8 @@ static const size_t mdlen = 64;
 static const size_t blklen = 128;
 
 static bool hmac_sha512(const uint8_t *key, size_t keylen, const uint8_t *msg, size_t msglen, uint8_t *out) {
-       uint8_t tmp[blklen + mdlen];
+       const size_t tmplen = blklen + mdlen;
+       uint8_t *tmp = alloca(tmplen);
        sha512_context md;
 
        if(keylen <= blklen) {
@@ -69,7 +70,7 @@ static bool hmac_sha512(const uint8_t *key, size_t keylen, const uint8_t *msg, s
        // opad
        memxor(tmp, 0x36 ^ 0x5c, blklen);
 
-       if(sha512(tmp, sizeof(tmp), out) != 0) {
+       if(sha512(tmp, tmplen, out) != 0) {
                return false;
        }
 
@@ -86,28 +87,29 @@ bool prf(const uint8_t *secret, size_t secretlen, uint8_t *seed, size_t seedlen,
           It consists of the previous HMAC result plus the seed.
         */
 
-       uint8_t data[mdlen + seedlen];
+       const size_t datalen = mdlen + seedlen;
+       uint8_t *data = alloca(datalen);
        memset(data, 0, mdlen);
        memcpy(data + mdlen, seed, seedlen);
 
-       uint8_t hash[mdlen];
+       uint8_t *hash = alloca(mdlen);
 
        while(outlen > 0) {
                /* Inner HMAC */
-               if(!hmac_sha512(secret, secretlen, data, sizeof(data), data)) {
+               if(!hmac_sha512(secret, secretlen, data, datalen, data)) {
                        return false;
                }
 
                /* Outer HMAC */
                if(outlen >= mdlen) {
-                       if(!hmac_sha512(secret, secretlen, data, sizeof(data), out)) {
+                       if(!hmac_sha512(secret, secretlen, data, datalen, out)) {
                                return false;
                        }
 
                        out += mdlen;
                        outlen -= mdlen;
                } else {
-                       if(!hmac_sha512(secret, secretlen, data, sizeof(data), hash)) {
+                       if(!hmac_sha512(secret, secretlen, data, datalen, hash)) {
                                return false;
                        }
 
index 6e27b15..5778c52 100644 (file)
@@ -138,7 +138,7 @@ void digest_close(digest_t *digest) {
 
 bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
        size_t len = EVP_MD_size(digest->digest);
-       unsigned char tmpdata[len];
+       unsigned char *tmpdata = alloca(len);
 
        if(digest->hmac_ctx) {
                bool ok;
@@ -152,7 +152,7 @@ bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *out
 
                ok = mac_ctx
                     && EVP_MAC_update(mac_ctx, indata, inlen)
-                    && EVP_MAC_final(mac_ctx, tmpdata, NULL, sizeof(tmpdata));
+                    && EVP_MAC_final(mac_ctx, tmpdata, NULL, len);
 
                EVP_MAC_CTX_free(mac_ctx);
 #endif
@@ -184,7 +184,7 @@ bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *out
 
 bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
        size_t len = digest->maclength;
-       unsigned char outdata[len];
+       unsigned char *outdata = alloca(len);
 
        return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, digest->maclength);
 }
index 5d597d9..ddad522 100644 (file)
@@ -48,11 +48,11 @@ static bool prf_xor(int nid, const uint8_t *secret, size_t secretlen, uint8_t *s
           It consists of the previous HMAC result plus the seed.
         */
 
-       char data[len + seedlen];
+       char *data = alloca(len + seedlen);
        memset(data, 0, len);
        memcpy(data + len, seed, seedlen);
 
-       uint8_t hash[len];
+       uint8_t *hash = alloca(len);
 
        while(outlen > 0) {
                /* Inner HMAC */
index 3539ca7..02dbf5b 100644 (file)
@@ -118,10 +118,11 @@ void forward_request(connection_t *from, const char *request) {
 
        // Create a temporary newline-terminated copy of the request
        size_t len = strlen(request);
-       char tmp[len + 1];
+       const size_t tmplen = len + 1;
+       char *tmp = alloca(tmplen);
        memcpy(tmp, request, len);
        tmp[len] = '\n';
-       broadcast_meta(from, tmp, sizeof(tmp));
+       broadcast_meta(from, tmp, tmplen);
 }
 
 bool receive_request(connection_t *c, const char *request) {
index 0049cd9..19859b7 100644 (file)
@@ -71,7 +71,8 @@ static bool send_proxyrequest(connection_t *c) {
                        return false;
                }
 
-               uint8_t s4req[9 + (proxyuser ? strlen(proxyuser) : 0)];
+               const size_t s4reqlen = 9 + (proxyuser ? strlen(proxyuser) : 0);
+               uint8_t *s4req = alloca(s4reqlen);
                s4req[0] = 4;
                s4req[1] = 1;
                memcpy(s4req + 2, &c->address.in.sin_port, 2);
@@ -81,9 +82,9 @@ static bool send_proxyrequest(connection_t *c) {
                        memcpy(s4req + 8, proxyuser, strlen(proxyuser));
                }
 
-               s4req[sizeof(s4req) - 1] = 0;
+               s4req[s4reqlen - 1] = 0;
                c->tcplen = 8;
-               return send_meta(c, s4req, sizeof(s4req));
+               return send_meta(c, s4req, s4reqlen);
        }
 
        case PROXY_SOCKS5: {
@@ -94,7 +95,8 @@ static bool send_proxyrequest(connection_t *c) {
                        len += 3 + strlen(proxyuser) + strlen(proxypass);
                }
 
-               uint8_t s5req[len];
+               uint8_t *s5req = alloca(len);
+
                size_t i = 0;
                s5req[i++] = 5;
                s5req[i++] = 1;
@@ -140,7 +142,7 @@ static bool send_proxyrequest(connection_t *c) {
                        abort();
                }
 
-               return send_meta(c, s5req, sizeof(s5req));
+               return send_meta(c, s5req, len);
        }
 
        case PROXY_SOCKS4A:
@@ -244,11 +246,12 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat
 
        // Recover the filename from the cookie and the key
        char *fingerprint = ecdsa_get_base64_public_key(invitation_key);
-       char hashbuf[18 + strlen(fingerprint)];
+       const size_t hashbuflen = 18 + strlen(fingerprint);
+       char *hashbuf = alloca(hashbuflen);
        char cookie[64];
        memcpy(hashbuf, data, 18);
-       memcpy(hashbuf + 18, fingerprint, sizeof(hashbuf) - 18);
-       sha512(hashbuf, sizeof(hashbuf), cookie);
+       memcpy(hashbuf + 18, fingerprint, hashbuflen - 18);
+       sha512(hashbuf, hashbuflen, cookie);
        b64encode_tinc_urlsafe(cookie, cookie, 18);
        free(fingerprint);
 
@@ -486,15 +489,17 @@ bool id_h(connection_t *c, const char *request) {
 
        if(c->protocol_minor >= 2) {
                c->allow_request = ACK;
-               char label[25 + strlen(myself->name) + strlen(c->name)];
+
+               const size_t labellen = 25 + strlen(myself->name) + strlen(c->name);
+               char *label = alloca(labellen);
 
                if(c->outgoing) {
-                       snprintf(label, sizeof(label), "tinc TCP key expansion %s %s", myself->name, c->name);
+                       snprintf(label, labellen, "tinc TCP key expansion %s %s", myself->name, c->name);
                } else {
-                       snprintf(label, sizeof(label), "tinc TCP key expansion %s %s", c->name, myself->name);
+                       snprintf(label, labellen, "tinc TCP key expansion %s %s", c->name, myself->name);
                }
 
-               return sptps_start(&c->sptps, c, c->outgoing, false, myself->connection->ecdsa, c->ecdsa, label, sizeof(label), send_meta_sptps, receive_meta_sptps);
+               return sptps_start(&c->sptps, c, c->outgoing, false, myself->connection->ecdsa, c->ecdsa, label, labellen, send_meta_sptps, receive_meta_sptps);
        } else {
                return send_metakey(c);
        }
@@ -539,9 +544,9 @@ bool send_metakey(connection_t *c) {
        }
 
        const size_t len = rsa_size(c->rsa);
-       char key[len];
-       char enckey[len];
-       char hexkey[2 * len + 1];
+       char *key = alloca(len);
+       char *enckey = alloca(len);
+       char *hexkey = alloca(2 * len + 1);
 
        /* Create a random key */
 
@@ -603,8 +608,8 @@ bool metakey_h(connection_t *c, const char *request) {
        char hexkey[MAX_STRING_SIZE];
        int cipher, digest, maclength, compression;
        const size_t len = rsa_size(myself->connection->rsa);
-       char enckey[len];
-       char key[len];
+       char *enckey = alloca(len);
+       char *key = alloca(len);
 
        if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, hexkey) != 5) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, c->hostname);
@@ -613,7 +618,7 @@ bool metakey_h(connection_t *c, const char *request) {
 
        /* Convert the challenge from hexadecimal back to binary */
 
-       size_t inlen = hex2bin(hexkey, enckey, sizeof(enckey));
+       size_t inlen = hex2bin(hexkey, enckey, len);
 
        /* Check if the length of the meta key is all right */
 
@@ -667,7 +672,7 @@ bool metakey_h(connection_t *c, const char *request) {
 
 bool send_challenge(connection_t *c) {
        const size_t len = rsa_size(c->rsa);
-       char buffer[len * 2 + 1];
+       char *buffer = alloca(len * 2 + 1);
 
        c->hischallenge = xrealloc(c->hischallenge, len);
 
@@ -724,7 +729,7 @@ bool challenge_h(connection_t *c, const char *request) {
 bool send_chal_reply(connection_t *c) {
        const size_t len = rsa_size(myself->connection->rsa);
        size_t digestlen = digest_length(&c->indigest);
-       char digest[digestlen * 2 + 1];
+       char *digest = alloca(digestlen * 2 + 1);
 
        /* Calculate the hash from the challenge we received */
 
index 1d1bee1..1efeaa8 100644 (file)
@@ -103,7 +103,7 @@ static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data
        node_t *to = handle;
        to->sptps.send_data = send_sptps_data_myself;
 
-       char buf[B64_SIZE(len)];
+       char *buf = alloca(B64_SIZE(len));
        b64encode_tinc(data, buf, len);
 
        return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf);
@@ -117,14 +117,16 @@ bool send_req_key(node_t *to) {
                        return true;
                }
 
-               char label[25 + strlen(myself->name) + strlen(to->name)];
-               snprintf(label, sizeof(label), "tinc UDP key expansion %s %s", myself->name, to->name);
+               const size_t labellen = 25 + strlen(myself->name) + strlen(to->name);
+               char *label = alloca(labellen);
+               snprintf(label, labellen, "tinc UDP key expansion %s %s", myself->name, to->name);
+
                sptps_stop(&to->sptps);
                to->status.validkey = false;
                to->status.waitingforkey = true;
                to->last_req_key = now.tv_sec;
                to->incompression = myself->incompression;
-               return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof(label), send_initial_sptps_data, receive_sptps_record);
+               return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, labellen, send_initial_sptps_data, receive_sptps_record);
        }
 
        return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
@@ -238,13 +240,14 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, no
                        return true;
                }
 
-               char label[25 + strlen(from->name) + strlen(myself->name)];
-               snprintf(label, sizeof(label), "tinc UDP key expansion %s %s", from->name, myself->name);
+               const size_t labellen = 25 + strlen(from->name) + strlen(myself->name);
+               char *label = alloca(labellen);
+               snprintf(label, labellen, "tinc UDP key expansion %s %s", from->name, myself->name);
                sptps_stop(&from->sptps);
                from->status.validkey = false;
                from->status.waitingforkey = true;
                from->last_req_key = now.tv_sec;
-               sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof(label), send_sptps_data_myself, receive_sptps_record);
+               sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, labellen, send_sptps_data_myself, receive_sptps_record);
                sptps_receive_data(&from->sptps, buf, len);
                send_mtu_info(myself, from, MTU);
                return true;
@@ -336,7 +339,7 @@ bool send_ans_key(node_t *to) {
        return false;
 #else
        size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1;
-       char key[keylen * 2 + 1];
+       char *key = alloca(keylen * 2 + 1);
 
        randomize(key, keylen);
 
@@ -519,8 +522,9 @@ bool ans_key_h(connection_t *c, const char *request) {
        /* SPTPS or old-style key exchange? */
 
        if(from->status.sptps) {
-               uint8_t buf[strlen(key)];
-               size_t len = b64decode_tinc(key, buf, strlen(key));
+               const size_t buflen = strlen(key);
+               uint8_t *buf = alloca(buflen);
+               size_t len = b64decode_tinc(key, buf, buflen);
 
                if(!len || !sptps_receive_data(&from->sptps, buf, len)) {
                        /* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
index cb3d293..b380931 100644 (file)
@@ -42,7 +42,7 @@ static void unputenv(const char *p) {
        len++;
 #endif
 #endif
-       char var[len + 1];
+       char *var = alloca(len + 1);
        strncpy(var, p, len);
        var[len] = 0;
 #ifdef HAVE_UNSETENV
@@ -159,9 +159,11 @@ bool execute_script(const char *name, environment_t *env) {
 
                size_t pathlen = strlen(pathext);
                size_t scriptlen = strlen(scriptname);
-               char fullname[scriptlen + pathlen + 1];
+
+               const size_t fullnamelen = scriptlen + pathlen + 1;
+               char *fullname = alloca(fullnamelen);
                char *ext = fullname + scriptlen;
-               strncpy(fullname, scriptname, sizeof(fullname));
+               strncpy(fullname, scriptname, fullnamelen);
 
                const char *p = pathext;
                bool found = false;
index 38ff16c..9fe93cc 100644 (file)
@@ -92,7 +92,7 @@ static void warning(sptps_t *s, const char *format, ...) {
 
 // Send a record (datagram version, accepts all record types, handles encryption and authentication).
 static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
-       uint8_t buffer[len + 21UL];
+       uint8_t *buffer = alloca(len + 21UL);
 
        // Create header with sequence number, length and record type
        uint32_t seqno = s->outseqno++;
@@ -117,7 +117,7 @@ static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_
                return send_record_priv_datagram(s, type, data, len);
        }
 
-       uint8_t buffer[len + 19UL];
+       uint8_t *buffer = alloca(len + 19UL);
 
        // Create header with sequence number, length and record type
        uint32_t seqno = s->outseqno++;
@@ -187,8 +187,9 @@ static bool send_sig(sptps_t *s) {
        size_t siglen = ecdsa_size(s->mykey);
 
        // Concatenate both KEX messages, plus tag indicating if it is from the connection originator, plus label
-       uint8_t msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
-       uint8_t sig[siglen];
+       const size_t msglen = (1 + 32 + keylen) * 2 + 1 + s->labellen;
+       uint8_t *msg = alloca(msglen);
+       uint8_t *sig = alloca(siglen);
 
        msg[0] = s->initiator;
        memcpy(msg + 1, s->mykex, 1 + 32 + keylen);
@@ -196,12 +197,12 @@ static bool send_sig(sptps_t *s) {
        memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
 
        // Sign the result.
-       if(!ecdsa_sign(s->mykey, msg, sizeof(msg), sig)) {
+       if(!ecdsa_sign(s->mykey, msg, msglen, sig)) {
                return error(s, EINVAL, "Failed to sign SIG record");
        }
 
        // Send the SIG exchange record.
-       return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof(sig));
+       return send_record_priv(s, SPTPS_HANDSHAKE, sig, siglen);
 }
 
 // Generate key material from the shared secret created from the ECDHE key exchange.
@@ -226,7 +227,7 @@ static bool generate_key_material(sptps_t *s, const uint8_t *shared, size_t len)
        }
 
        // Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
-       uint8_t seed[s->labellen + 64 + 13];
+       uint8_t *seed = alloca(s->labellen + 64 + 13);
        memcpy(seed, "key expansion", 13);
 
        if(s->initiator) {
@@ -317,7 +318,8 @@ static bool receive_sig(sptps_t *s, const uint8_t *data, uint16_t len) {
        }
 
        // Concatenate both KEX messages, plus tag indicating if it is from the connection originator
-       uint8_t msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
+       const size_t msglen = (1 + 32 + keylen) * 2 + 1 + s->labellen;
+       uint8_t *msg = alloca(msglen);
 
        msg[0] = !s->initiator;
        memcpy(msg + 1, s->hiskex, 1 + 32 + keylen);
@@ -325,7 +327,7 @@ static bool receive_sig(sptps_t *s, const uint8_t *data, uint16_t len) {
        memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
 
        // Verify signature.
-       if(!ecdsa_verify(s->hiskey, msg, sizeof(msg), data)) {
+       if(!ecdsa_verify(s->hiskey, msg, msglen, data)) {
                return error(s, EIO, "Failed to verify SIG record");
        }
 
@@ -522,7 +524,7 @@ bool sptps_verify_datagram(sptps_t *s, const void *vdata, size_t len) {
                return false;
        }
 
-       uint8_t buffer[len];
+       uint8_t *buffer = alloca(len);
        size_t outlen;
        return chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen);
 }
@@ -558,7 +560,7 @@ static bool sptps_receive_data_datagram(sptps_t *s, const uint8_t *data, size_t
 
        // Decrypt
 
-       uint8_t buffer[len];
+       uint8_t *buffer = alloca(len);
        size_t outlen;
 
        if(!chacha_poly1305_decrypt(s->incipher, seqno, data, len, buffer, &outlen)) {
index 0e7d083..946e749 100644 (file)
@@ -19,8 +19,6 @@
 
 #include "system.h"
 
-#include <getopt.h>
-
 #ifdef HAVE_READLINE
 #include "readline/readline.h"
 #include "readline/history.h"
index eb68998..8223b2d 100644 (file)
@@ -159,9 +159,7 @@ static void *upnp_thread(void *data) {
                time_t now = time(NULL);
 
                if(now < refresh_time) {
-                       nanosleep(&(struct timespec) {
-                               refresh_time - now, 0
-                       }, NULL);
+                       sleep_millis((refresh_time - now) * 1000);
                }
        }
 
index 48e6689..36d9753 100644 (file)
@@ -1,3 +1,6 @@
-subdir('integration')
+if cc_name != 'msvc'
+  subdir('integration')
+endif
+
 subdir('unit')