From cfc9fee931c70554353ce6c4acc3407baac08745 Mon Sep 17 00:00:00 2001 From: Kirill Isakov Date: Fri, 25 Mar 2022 20:09:36 +0600 Subject: [PATCH] Add support for building tinc with MSVC Tests are not supported because of their strong dependence on running under Unix-like environment. --- meson.build | 62 +++++++++++++++++++++++++---------------- src/dropin.c | 9 ++++++ src/dropin.h | 28 ++++++++++++++++++- src/ed25519/fixedint.h | 2 +- src/ethernet.h | 6 ++-- src/fsck.c | 5 ++-- src/git_tag.sh | 3 -- src/have.h | 21 ++++++++++++++ src/include/meson.build | 2 +- src/invitation.c | 32 ++++++++++----------- src/ipv4.h | 4 +-- src/ipv6.h | 8 +++--- src/logger.h | 2 ++ src/meson.build | 3 ++ src/mingw/meson.build | 12 ++++++-- src/net.c | 4 +-- src/net_packet.c | 11 ++++---- src/nolegacy/prf.c | 16 ++++++----- src/openssl/digest.c | 6 ++-- src/openssl/prf.c | 4 +-- src/protocol.c | 5 ++-- src/protocol_auth.c | 45 +++++++++++++++++------------- src/protocol_key.c | 24 +++++++++------- src/script.c | 8 ++++-- src/sptps.c | 24 ++++++++-------- src/tincctl.c | 2 -- src/upnp.c | 4 +-- test/meson.build | 5 +++- 28 files changed, 225 insertions(+), 132 deletions(-) delete mode 100755 src/git_tag.sh diff --git a/meson.build b/meson.build index 38062a9c..f0c2fa12 100644 --- a/meson.build +++ b/meson.build @@ -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 diff --git a/src/dropin.c b/src/dropin.c index e732fa09..1489ee6c 100644 --- a/src/dropin.c +++ b/src/dropin.c @@ -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 +} diff --git a/src/dropin.h b/src/dropin.h index 2aa6df10..9b196b6d 100644 --- a/src/dropin.h +++ b/src/dropin.h @@ -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 diff --git a/src/ed25519/fixedint.h b/src/ed25519/fixedint.h index 553f8880..41cdda4f 100644 --- a/src/ed25519/fixedint.h +++ b/src/ed25519/fixedint.h @@ -7,7 +7,7 @@ Not a compatible replacement for , 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 #define FIXEDINT_H_INCLUDED diff --git a/src/ethernet.h b/src/ethernet.h index 3b074b7f..4ef9dab9 100644 --- a/src/ethernet.h +++ b/src/ethernet.h @@ -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 diff --git a/src/fsck.c b/src/fsck.c index 3a64959d..fdd584e7 100644 --- a/src/fsck.c +++ b/src/fsck.c @@ -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 index 25677e29..00000000 --- a/src/git_tag.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -git describe --always --tags --match='release-*' "$@" | sed 's/release-//' diff --git a/src/have.h b/src/have.h index d1dd91d7..f19c5992 100644 --- a/src/have.h +++ b/src/have.h @@ -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 @@ -36,17 +38,34 @@ #include #include #include +#ifdef HAVE_UNISTD_H #include +#endif #include #include #include +#ifdef HAVE_ALLOCA_H +#include +#elif defined(HAVE_NETBSD) +#define alloca(size) __builtin_alloca(size) +#endif + #ifdef HAVE_MINGW +#ifdef HAVE_W32API_H #include +#endif + #include #include #include + +#ifdef _MSC_VER +#include +#include +#include #endif +#endif // HAVE_MINGW #ifdef HAVE_TERMIOS_H #include @@ -109,6 +128,8 @@ #ifdef HAVE_DIRENT_H #include +#elif defined(_MSC_VER) +#include "dirent.h" #endif /* SunOS really wants sys/socket.h BEFORE net/if.h, diff --git a/src/include/meson.build b/src/include/meson.build index f6f4e043..05509967 100644 --- a/src/include/meson.build +++ b/src/include/meson.build @@ -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', diff --git a/src/invitation.c b/src/invitation.c index e71a4889..d1e1e61d 100644 --- a/src/invitation.c +++ b/src/invitation.c @@ -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; } diff --git a/src/ipv4.h b/src/ipv4.h index 708e5c1f..a412c605 100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@ -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 diff --git a/src/ipv6.h b/src/ipv6.h index cfa6f239..7c06de3d 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -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 diff --git a/src/logger.h b/src/logger.h index 66c32ab3..5302582b 100644 --- a/src/logger.h +++ b/src/logger.h @@ -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 */ diff --git a/src/meson.build b/src/meson.build index 43f70bfa..92f42fa5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -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 diff --git a/src/mingw/meson.build b/src/mingw/meson.build index 796d62b9..5cd2c7ba 100644 --- a/src/mingw/meson.build +++ b/src/mingw/meson.build @@ -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') diff --git a/src/net.c b/src/net.c index 7efe7fa3..7f844216 100644 --- 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) { diff --git a/src/net_packet.c b/src/net_packet.c index eb438b08..2722fb23 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -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) { diff --git a/src/nolegacy/prf.c b/src/nolegacy/prf.c index 1e5bb9f9..5db6430b 100644 --- a/src/nolegacy/prf.c +++ b/src/nolegacy/prf.c @@ -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; } diff --git a/src/openssl/digest.c b/src/openssl/digest.c index 6e27b153..5778c523 100644 --- a/src/openssl/digest.c +++ b/src/openssl/digest.c @@ -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); } diff --git a/src/openssl/prf.c b/src/openssl/prf.c index 5d597d9a..ddad522f 100644 --- a/src/openssl/prf.c +++ b/src/openssl/prf.c @@ -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 */ diff --git a/src/protocol.c b/src/protocol.c index 3539ca7c..02dbf5bf 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -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) { diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 0049cd93..19859b75 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -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 */ diff --git a/src/protocol_key.c b/src/protocol_key.c index 1d1bee15..1efeaa83 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -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, diff --git a/src/script.c b/src/script.c index cb3d2934..b380931f 100644 --- a/src/script.c +++ b/src/script.c @@ -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; diff --git a/src/sptps.c b/src/sptps.c index 38ff16cc..9fe93cc7 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -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)) { diff --git a/src/tincctl.c b/src/tincctl.c index 0e7d083f..946e7498 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -19,8 +19,6 @@ #include "system.h" -#include - #ifdef HAVE_READLINE #include "readline/readline.h" #include "readline/history.h" diff --git a/src/upnp.c b/src/upnp.c index eb68998b..8223b2df 100644 --- a/src/upnp.c +++ b/src/upnp.c @@ -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); } } diff --git a/test/meson.build b/test/meson.build index 48e66898..36d9753f 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,3 +1,6 @@ -subdir('integration') +if cc_name != 'msvc' + subdir('integration') +endif + subdir('unit') -- 2.20.1