From: Guus Sliepen <guus@tinc-vpn.org>
Date: Sun, 16 Jan 2022 22:02:09 +0000 (+0100)
Subject: Enable and fix many extra warnings supported by GCC and Clang.
X-Git-Url: https://tinc-vpn.org/git/browse?a=commitdiff_plain;h=28b7a53b6;p=tinc

Enable and fix many extra warnings supported by GCC and Clang.

This enables many extra warning options when hardening is enabled, and
fixes the definition of _FORTITY_SOURCE. -Wshadow is not (yet) enabled,
as this generates quite some warnings that are less trivial to fix.
---

diff --git a/configure.ac b/configure.ac
index e5bd2883..0ed205d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
 
 origcflags="$CFLAGS"
 
-AC_PREREQ(2.69)
+AC_PREREQ([2.69])
 AC_INIT([tinc], m4_esyscmd_s((git describe || echo UNKNOWN) | sed 's/release-//'))
 AC_CONFIG_SRCDIR([src/tincd.c])
 AM_INIT_AUTOMAKE([std-options subdir-objects nostdinc silent-rules -Wall])
@@ -14,9 +14,10 @@ AC_USE_SYSTEM_EXTENSIONS
 
 dnl Checks for programs.
 AC_PROG_CC
-AC_PROG_CC_STDC
+AC_PROG_CC_C99
 AC_PROG_CPP
 AC_PROG_INSTALL
+AC_PROG_LN_S
 AM_PROG_CC_C_O
 
 dnl Check whether to enable code coverage testing, and if so, clear the default CFLAGS.
@@ -67,7 +68,7 @@ case $host_os in
   *mingw*)
     mingw=true
     AC_DEFINE(HAVE_MINGW, 1, [MinGW])
-    LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32 -liphlpapi"
+    LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32 -liphlpapi -lwinpthread"
     LDFLAGS="$LDFLAGS -static"
     CPPFLAGS="$CPPFLAGS -DMINIUPNP_STATICLIB"
   ;;
@@ -149,13 +150,14 @@ AX_CFLAGS_WARN_ALL(CFLAGS)
 
 AC_ARG_ENABLE([hardening], AS_HELP_STRING([--disable-hardening], [disable compiler and linker hardening flags]))
 AS_IF([test "x$enable_hardening" != "xno"],
-  [AX_CHECK_COMPILE_FLAG([-DFORTIFY_SOURCE=2], [CPPFLAGS="$CPPFLAGS -DFORTIFY_SOURCE=2"])
+  [AX_CHECK_COMPILE_FLAG([-D_FORTIFY_SOURCE=2], [CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"])
    AX_CHECK_COMPILE_FLAG([-fwrapv], [CPPFLAGS="$CPPFLAGS -fwrapv"],
    AX_CHECK_COMPILE_FLAG([-fno-strict-overflow], [CPPFLAGS="$CPPFLAGS -fno-strict-overflow"]))
    case $host_os in
      *mingw*)
        AX_CHECK_LINK_FLAG([-Wl,--dynamicbase], [LDFLAGS="$LDFLAGS -Wl,--dynamicbase"])
        AX_CHECK_LINK_FLAG([-Wl,--nxcompat], [LDFLAGS="$LDFLAGS -Wl,--nxcompat"])
+       AX_CHECK_LINK_FLAG([-lssp], [LDFLAGS="$LDFLAGS -lssp"])
        ;;
      *)
        AX_CHECK_COMPILE_FLAG([-fPIE], [CPPFLAGS="$CPPFLAGS -fPIE"])
@@ -164,6 +166,8 @@ AS_IF([test "x$enable_hardening" != "xno"],
    esac
    AX_CHECK_LINK_FLAG([-Wl,-z,relro], [LDFLAGS="$LDFLAGS -Wl,-z,relro"])
    AX_CHECK_LINK_FLAG([-Wl,-z,now], [LDFLAGS="$LDFLAGS -Wl,-z,now"])
+   AX_CHECK_COMPILE_FLAG([-W -Wextra -pedantic -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],
+     [CPPFLAGS="$CPPFLAGS -W -Wextra -pedantic -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"])
   ]
 );
 
@@ -233,8 +237,8 @@ AC_ARG_ENABLE(legacy-protocol,
 
 dnl These are defined in files in m4/
 
-dnl AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
-dnl AC_ARG_WITH(openssl, AC_HELP_STRING([--without-openssl], [disable support for OpenSSL])], [])
+dnl AC_ARG_WITH(libgcrypt, AS_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
+dnl AC_ARG_WITH(openssl, AS_HELP_STRING([--without-openssl], [disable support for OpenSSL])], [])
 
 tinc_CURSES
 tinc_READLINE
diff --git a/src/autoconnect.c b/src/autoconnect.c
index 9f4abece..d771078a 100644
--- a/src/autoconnect.c
+++ b/src/autoconnect.c
@@ -1,6 +1,6 @@
 /*
     autoconnect.c -- automatic connection establishment
-    Copyright (C) 2017 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2017-2022 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
@@ -19,13 +19,14 @@
 
 #include "system.h"
 
+#include "autoconnect.h"
 #include "connection.h"
 #include "crypto.h"
 #include "logger.h"
 #include "node.h"
 #include "xalloc.h"
 
-static void make_new_connection() {
+static void make_new_connection(void) {
 	/* Select a random node we haven't connected to yet. */
 	uint32_t count = 0;
 
@@ -74,7 +75,7 @@ static void make_new_connection() {
 	}
 }
 
-static void connect_to_unreachable() {
+static void connect_to_unreachable(void) {
 	/* Select a random known node. The rationale is that if there are many
 	 * reachable nodes, and only a few unreachable nodes, we don't want all
 	 * reachable nodes to try to connect to the unreachable ones at the
@@ -111,7 +112,7 @@ static void connect_to_unreachable() {
 	}
 }
 
-static void drop_superfluous_outgoing_connection() {
+static void drop_superfluous_outgoing_connection(void) {
 	/* Choose a random outgoing connection to a node that has at least one other connection. */
 	uint32_t count = 0;
 
@@ -146,7 +147,7 @@ static void drop_superfluous_outgoing_connection() {
 	}
 }
 
-static void drop_superfluous_pending_connections() {
+static void drop_superfluous_pending_connections(void) {
 	for list_each(outgoing_t, o, &outgoing_list) {
 		/* Only look for connections that are waiting to be retried later. */
 		bool found = false;
@@ -167,7 +168,7 @@ static void drop_superfluous_pending_connections() {
 	}
 }
 
-void do_autoconnect() {
+void do_autoconnect(void) {
 	/* Count number of active connections. */
 	uint32_t nc = 0;
 
diff --git a/src/bsd/device.c b/src/bsd/device.c
index fe2d6c52..0c1a62f4 100644
--- a/src/bsd/device.c
+++ b/src/bsd/device.c
@@ -1,7 +1,7 @@
 /*
     device.c -- Interaction BSD tun/tap device
     Copyright (C) 2001-2005 Ivo Timmermans,
-                  2001-2021 Guus Sliepen <guus@tinc-vpn.org>
+                  2001-2022 Guus Sliepen <guus@tinc-vpn.org>
                   2009      Grzegorz Dymarek <gregd72002@googlemail.com>
 
     This program is free software; you can redistribute it and/or modify
@@ -76,7 +76,9 @@ static bool setup_utun(void) {
 		return false;
 	}
 
-	struct ctl_info info = {};
+	struct ctl_info info;
+
+	memset(&info, 0, sizeof(info));
 
 	strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
 
diff --git a/src/bsd/tunemu.h b/src/bsd/tunemu.h
index c67cfae3..7dcd2d59 100644
--- a/src/bsd/tunemu.h
+++ b/src/bsd/tunemu.h
@@ -20,7 +20,7 @@
 #ifndef TUNEMU_H
 #define TUNEMU_H
 
-#include "system.h"
+#include "../system.h"
 
 typedef char tunemu_device[7];
 
diff --git a/src/cipher.c b/src/cipher.c
index 0bab3bd9..5ac790a1 100644
--- a/src/cipher.c
+++ b/src/cipher.c
@@ -1,9 +1,30 @@
+/*
+    crypto.c -- stub cipher handling functions
+    Copyright (C) 2007-2022 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
 #include "cipher.h"
 #include "xalloc.h"
 
 #ifndef DISABLE_LEGACY
 
-cipher_t *cipher_alloc() {
+cipher_t *cipher_alloc(void) {
 	return xzalloc(sizeof(cipher_t));
 }
 
diff --git a/src/cipher.h b/src/cipher.h
index 1224210c..966a8640 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -3,7 +3,7 @@
 
 /*
     cipher.h -- header file cipher.c
-    Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -38,7 +38,7 @@
 
 typedef struct cipher cipher_t;
 
-extern cipher_t *cipher_alloc() __attribute__((__malloc__));
+extern cipher_t *cipher_alloc(void) __attribute__((__malloc__));
 extern void cipher_free(cipher_t **cipher);
 extern bool cipher_open_by_name(cipher_t *cipher, const char *name);
 extern bool cipher_open_by_nid(cipher_t *cipher, int nid);
diff --git a/src/conf.c b/src/conf.c
index 4dd8fe7a..a40fdfa8 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -4,7 +4,7 @@
                   1998-2005 Ivo Timmermans
                   2000      Cris van Pelt
                   2010-2011 Julien Muchembled <jm@jmuchemb.eu>
-                  2000-2021 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 Guus Sliepen <guus@tinc-vpn.org>
                   2013      Florent Clairambault <florent@clairambault.fr>
 
     This program is free software; you can redistribute it and/or modify
@@ -75,7 +75,7 @@ splay_tree_t config_tree = {
 	.delete = (splay_action_t) free_config,
 };
 
-splay_tree_t *create_configuration() {
+splay_tree_t *create_configuration(void) {
 	splay_tree_t *tree = splay_alloc_tree(NULL, NULL);
 	init_configuration(tree);
 	return tree;
@@ -107,14 +107,14 @@ void config_add(splay_tree_t *config_tree, config_t *cfg) {
 	splay_insert(config_tree, cfg);
 }
 
-config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
-	config_t cfg, *found;
+config_t *lookup_config(splay_tree_t *config_tree, const char *variable) {
+	const config_t cfg = {
+		.variable = (char *)variable,
+		.file = NULL,
+		.line = 0,
+	};
 
-	cfg.variable = variable;
-	cfg.file = NULL;
-	cfg.line = 0;
-
-	found = splay_search_closest_greater(config_tree, &cfg);
+	config_t *found = splay_search_closest_greater(config_tree, &cfg);
 
 	if(!found) {
 		return NULL;
diff --git a/src/conf.h b/src/conf.h
index 8672ad79..2d55edde 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -4,7 +4,7 @@
 /*
     conf.h -- header for conf.c
     Copyright (C) 1998-2005 Ivo Timmermans
-                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -40,13 +40,13 @@ extern int maxtimeout;
 extern bool bypass_security;
 extern list_t cmdline_conf;
 
-extern splay_tree_t *create_configuration();
+extern splay_tree_t *create_configuration(void);
 extern void init_configuration(splay_tree_t *);
 extern void exit_configuration(splay_tree_t **config_tree);
 extern config_t *new_config(void) __attribute__((__malloc__));
 extern void free_config(config_t *config);
 extern void config_add(splay_tree_t *config_tree, config_t *config);
-extern config_t *lookup_config(splay_tree_t *config_tree, char *variable);
+extern config_t *lookup_config(splay_tree_t *config_tree, const char *variable);
 extern config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *config);
 extern bool get_config_bool(const config_t *config, bool *result);
 extern bool get_config_int(const config_t *config, int *result);
diff --git a/src/connection.h b/src/connection.h
index d9340fdb..60ec60a7 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -35,22 +35,21 @@
 #define OPTION_VERSION(x) ((x) >> 24) /* Top 8 bits are for protocol minor version */
 
 typedef struct connection_status_t {
-	bool pinged: 1;                 /* sent ping */
-	bool unused_active: 1;
-	bool connecting: 1;             /* 1 if we are waiting for a non-blocking connect() to finish */
-	bool unused_termreq: 1;         /* the termination of this connection was requested */
-	bool remove_unused: 1;          /* Set to 1 if you want this connection removed */
-	bool timeout_unused: 1;         /* 1 if gotten timeout */
-	bool encryptout: 1;             /* 1 if we can encrypt outgoing traffic */
-	bool decryptin: 1;              /* 1 if we have to decrypt incoming traffic */
-	bool mst: 1;                    /* 1 if this connection is part of a minimum spanning tree */
-	bool control: 1;                /* 1 if this is a control connection */
-	bool pcap: 1;                   /* 1 if this is a control connection requesting packet capture */
-	bool log: 1;                    /* 1 if this is a control connection requesting log dump */
-	bool invitation: 1;             /* 1 if this is an invitation */
-	bool invitation_used: 1;        /* 1 if the invitation has been consumed */
-	bool tarpit: 1;                 /* 1 if the connection should be added to the tarpit */
-	uint32_t unused: 17;
+	uint32_t pinged: 1;                 /* sent ping */
+	uint32_t unused_active: 1;
+	uint32_t connecting: 1;             /* 1 if we are waiting for a non-blocking connect() to finish */
+	uint32_t unused_termreq: 1;         /* the termination of this connection was requested */
+	uint32_t remove_unused: 1;          /* Set to 1 if you want this connection removed */
+	uint32_t timeout_unused: 1;         /* 1 if gotten timeout */
+	uint32_t encryptout: 1;             /* 1 if we can encrypt outgoing traffic */
+	uint32_t decryptin: 1;              /* 1 if we have to decrypt incoming traffic */
+	uint32_t mst: 1;                    /* 1 if this connection is part of a minimum spanning tree */
+	uint32_t control: 1;                /* 1 if this is a control connection */
+	uint32_t pcap: 1;                   /* 1 if this is a control connection requesting packet capture */
+	uint32_t log: 1;                    /* 1 if this is a control connection requesting log dump */
+	uint32_t invitation: 1;             /* 1 if this is an invitation */
+	uint32_t invitation_used: 1;        /* 1 if the invitation has been consumed */
+	uint32_t tarpit: 1;                 /* 1 if the connection should be added to the tarpit */
 } connection_status_t;
 
 #include "ecdsa.h"
diff --git a/src/digest.c b/src/digest.c
index 85bea7d5..4ef98cd8 100644
--- a/src/digest.c
+++ b/src/digest.c
@@ -1,9 +1,30 @@
+/*
+    digest.c -- stub digest handling functions
+    Copyright (C) 2007-2022 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
 #include "digest.h"
 #include "xalloc.h"
 
 #ifndef DISABLE_LEGACY
 
-digest_t *digest_alloc() {
+digest_t *digest_alloc(void) {
 	return xzalloc(sizeof(digest_t));
 }
 
diff --git a/src/digest.h b/src/digest.h
index 9fb12483..dba6ee44 100644
--- a/src/digest.h
+++ b/src/digest.h
@@ -3,7 +3,7 @@
 
 /*
     digest.h -- header file digest.c
-    Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -39,7 +39,7 @@ typedef struct digest digest_t;
 
 extern bool digest_open_by_name(digest_t *digest, const char *name, size_t maclength);
 extern bool digest_open_by_nid(digest_t *digest, int nid, size_t maclength);
-extern digest_t *digest_alloc() __attribute__((__malloc__));
+extern digest_t *digest_alloc(void) __attribute__((__malloc__));
 extern void digest_free(digest_t **digest);
 extern void digest_close(digest_t *digest);
 extern bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) __attribute__((__warn_unused_result__));
diff --git a/src/dropin.c b/src/dropin.c
index 3c950ada..e732fa09 100644
--- a/src/dropin.c
+++ b/src/dropin.c
@@ -1,7 +1,7 @@
 /*
     dropin.c -- a set of drop-in replacements for libc functions
     Copyright (C) 2000-2005 Ivo Timmermans,
-                  2000-2018 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -145,11 +145,3 @@ int gettimeofday(struct timeval *tv, void *tz) {
 	return 0;
 }
 #endif
-
-#ifndef HAVE_NANOSLEEP
-int nanosleep(const struct timespec *req, struct timespec *rem) {
-	(void)rem;
-	struct timeval tv = {req->tv_sec, req->tv_nsec / 1000};
-	return select(0, NULL, NULL, NULL, &tv);
-}
-#endif
diff --git a/src/dropin.h b/src/dropin.h
index d1919e1c..14783ffb 100644
--- a/src/dropin.h
+++ b/src/dropin.h
@@ -4,7 +4,7 @@
 /*
     dropin.h -- header file for dropin.c
     Copyright (C) 2000-2005 Ivo Timmermans,
-                  2000-2016 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -36,10 +36,6 @@ extern int vasprintf(char **, const char *, va_list ap);
 extern int gettimeofday(struct timeval *, void *);
 #endif
 
-#ifndef HAVE_NANOSLEEP
-extern int nanosleep(const struct timespec *req, struct timespec *rem);
-#endif
-
 #ifndef timeradd
 #define timeradd(a, b, r) do {\
 		(r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
diff --git a/src/ed25519/ecdsa.c b/src/ed25519/ecdsa.c
index 0e80d910..f0ce2c16 100644
--- a/src/ed25519/ecdsa.c
+++ b/src/ed25519/ecdsa.c
@@ -38,7 +38,7 @@ ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
 	size_t len = strlen(p);
 
 	if(len != 43) {
-		logger(DEBUG_ALWAYS, LOG_ERR, "Invalid size %zu for public key!", len);
+		logger(DEBUG_ALWAYS, LOG_ERR, "Invalid size %lu for public key!", (unsigned long)len);
 		return 0;
 	}
 
@@ -46,7 +46,7 @@ ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
 	len = b64decode_tinc(p, ecdsa->public, len);
 
 	if(len != 32) {
-		logger(DEBUG_ALWAYS, LOG_ERR, "Invalid format of public key! len = %zu", len);
+		logger(DEBUG_ALWAYS, LOG_ERR, "Invalid format of public key! len = %lu", (unsigned long)len);
 		free(ecdsa);
 		return 0;
 	}
diff --git a/src/event.c b/src/event.c
index c547c46d..899b62a0 100644
--- a/src/event.c
+++ b/src/event.c
@@ -1,6 +1,6 @@
 /*
     event.c -- I/O, timeout and signal event handling
-    Copyright (C) 2012-2021 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2012-2022 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
@@ -18,12 +18,14 @@
 */
 
 #include "system.h"
-#include "dropin.h"
+
+#include <assert.h>
 
 #ifdef HAVE_SYS_EPOLL_H
 #include <sys/epoll.h>
 #endif
 
+#include "dropin.h"
 #include "event.h"
 #include "utils.h"
 #include "net.h"
@@ -46,7 +48,7 @@ static DWORD event_count = 0;
 static bool running;
 
 #ifdef HAVE_SYS_EPOLL_H
-static inline int event_epoll_init() {
+static inline int event_epoll_init(void) {
 	/* NOTE: 1024 limit is only used on ancient (pre 2.6.27) kernels.
 	        Decent kernels will ignore this value making it unlimited.
 	        epoll_create1 might be better, but these kernels would not be supported
@@ -290,11 +292,14 @@ void timeout_del(timeout_t *timeout) {
 
 static io_t signalio;
 static int pipefd[2] = {-1, -1};
-static signal_t *signal_handle[NSIG + 1] = {};
+static signal_t *signal_handle[NSIG + 1] = {NULL};
 
 static void signal_handler(int signum) {
 	unsigned char num = signum;
-	write(pipefd[1], &num, 1);
+
+	if(write(pipefd[1], &num, 1) != 1) {
+		// Pipe full or broken, nothing we can do about it.
+	}
 }
 
 static void signalio_handler(void *data, int flags) {
@@ -480,6 +485,7 @@ bool event_loop(void) {
 	}
 
 #else
+	assert(WSA_WAIT_EVENT_0 == 0);
 
 	while(running) {
 		struct timeval diff;
@@ -541,12 +547,12 @@ bool event_loop(void) {
 				break;
 			}
 
-			if(result < WSA_WAIT_EVENT_0 || result >= WSA_WAIT_EVENT_0 + event_count - event_offset) {
+			if(result >= event_count - event_offset) {
 				return false;
 			}
 
 			/* Look up io in the map by index. */
-			event_index = result - WSA_WAIT_EVENT_0 + event_offset;
+			event_index = result + event_offset;
 			io_t *io = io_map[event_index];
 
 			if(io->fd == -1) {
diff --git a/src/fd_device.c b/src/fd_device.c
index f21e475c..6e85be0d 100644
--- a/src/fd_device.c
+++ b/src/fd_device.c
@@ -1,7 +1,7 @@
 /*
     fd_device.c -- Interaction with Android tun fd
     Copyright (C)   2001-2005   Ivo Timmermans,
-                    2001-2021   Guus Sliepen <guus@tinc-vpn.org>
+                    2001-2022   Guus Sliepen <guus@tinc-vpn.org>
                     2009        Grzegorz Dymarek <gregd72002@googlemail.com>
                     2016-2020   Pacien TRAN-GIRARD <pacien@pacien.net>
 
@@ -53,7 +53,7 @@ static int read_fd(int socket) {
 	msg.msg_controllen = sizeof(cmsgbuf);
 
 	if((ret = recvmsg(socket, &msg, 0)) < 1) {
-		logger(DEBUG_ALWAYS, LOG_ERR, "Could not read from unix socket (error %zd)!", ret);
+		logger(DEBUG_ALWAYS, LOG_ERR, "Could not read from unix socket (error %ld)!", (long)ret);
 		return -1;
 	}
 
@@ -83,8 +83,8 @@ static int read_fd(int socket) {
 	}
 
 	if(cmsgptr->cmsg_len != CMSG_LEN(sizeof(device_fd))) {
-		logger(DEBUG_ALWAYS, LOG_ERR, "Wrong CMSG data length: %zu, expected %zu!",
-		       cmsgptr->cmsg_len, CMSG_LEN(sizeof(device_fd)));
+		logger(DEBUG_ALWAYS, LOG_ERR, "Wrong CMSG data length: %lu, expected %lu!",
+		       (unsigned long)cmsgptr->cmsg_len, (unsigned long)CMSG_LEN(sizeof(device_fd)));
 		return -1;
 	}
 
diff --git a/src/fsck.c b/src/fsck.c
index 5c7762a8..3a64959d 100644
--- a/src/fsck.c
+++ b/src/fsck.c
@@ -1,6 +1,6 @@
 /*
     fsck.c -- Check the configuration files for problems
-    Copyright (C) 2014-2021 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2014-2022 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
@@ -187,7 +187,7 @@ static void check_conffile(const char *nodename, bool server) {
 #ifdef HAVE_MINGW
 typedef int uid_t;
 
-static uid_t getuid() {
+static uid_t getuid(void) {
 	return 0;
 }
 
@@ -220,7 +220,7 @@ static void check_key_file_mode(const char *fname) {
 }
 #endif // HAVE_MINGW
 
-static char *read_node_name() {
+static char *read_node_name(void) {
 	if(access(tinc_conf, R_OK) == 0) {
 		return get_my_name(true);
 	}
@@ -438,7 +438,7 @@ static bool check_config_mode(const char *fname) {
 	return true;
 }
 
-static bool check_script_confdir() {
+static bool check_script_confdir(void) {
 	char fname[PATH_MAX];
 	DIR *dir = opendir(confbase);
 
@@ -616,7 +616,7 @@ static void check_config_variables(const char *host_dir) {
 	}
 }
 
-static bool check_scripts_and_configs() {
+static bool check_scripts_and_configs(void) {
 	// Check whether scripts are executable.
 	if(!check_script_confdir()) {
 		return false;
diff --git a/src/gcrypt/cipher.c b/src/gcrypt/cipher.c
index 0f7b008d..c1ecf50a 100644
--- a/src/gcrypt/cipher.c
+++ b/src/gcrypt/cipher.c
@@ -1,6 +1,6 @@
 /*
     cipher.c -- Symmetric block cipher handling
-    Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -17,11 +17,12 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "system.h"
+#include "../system.h"
 
 #include "cipher.h"
-#include "logger.h"
-#include "xalloc.h"
+#include "../cipher.h"
+#include "../logger.h"
+#include "../xalloc.h"
 
 static struct {
 	const char *name;
@@ -53,9 +54,7 @@ static struct {
 };
 
 static bool nametocipher(const char *name, int *algo, int *mode) {
-	size_t i;
-
-	for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
+	for(size_t i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
 		if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
 			*algo = ciphertable[i].algo;
 			*mode = ciphertable[i].mode;
@@ -67,9 +66,7 @@ static bool nametocipher(const char *name, int *algo, int *mode) {
 }
 
 static bool nidtocipher(int nid, int *algo, int *mode) {
-	size_t i;
-
-	for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
+	for(size_t i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
 		if(nid == ciphertable[i].nid) {
 			*algo = ciphertable[i].algo;
 			*mode = ciphertable[i].mode;
@@ -81,9 +78,7 @@ static bool nidtocipher(int nid, int *algo, int *mode) {
 }
 
 static bool ciphertonid(int algo, int mode, int *nid) {
-	size_t i;
-
-	for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
+	for(size_t i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
 		if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
 			*nid = ciphertable[i].nid;
 			return true;
@@ -136,10 +131,6 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
 	return cipher_open(cipher, algo, mode);
 }
 
-bool cipher_open_blowfish_ofb(cipher_t *cipher) {
-	return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
-}
-
 void cipher_close(cipher_t *cipher) {
 	if(cipher->handle) {
 		gcry_cipher_close(cipher->handle);
@@ -185,11 +176,9 @@ size_t cipher_blocksize(const cipher_t *cipher) {
 	return cipher->blklen;
 }
 
-void cipher_get_key(const cipher_t *cipher, void *key) {
-	memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
-}
-
 bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
+	(void)encrypt;
+
 	memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
 
 	gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
@@ -199,23 +188,12 @@ bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
 }
 
 bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
-	memcpy(cipher->key,
-	       key + len - cipher->keylen,
-	       cipher->keylen);
-	gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
-
-	memcpy(cipher->key + cipher->keylen,
-	       key + len - cipher->blklen - cipher->keylen,
-	       cipher->blklen);
-	gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
-
-	return true;
-}
-
-bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
-	gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
+	(void)encrypt;
 
+	memcpy(cipher->key, (char *)key + len - cipher->keylen, cipher->keylen);
 	gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
+
+	memcpy((char *)cipher->key + cipher->keylen, (char *)key + len - cipher->blklen - cipher->keylen, cipher->blklen);
 	gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
 
 	return true;
@@ -258,7 +236,7 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
 	}
 
 	if(cipher->padding) {
-		if((err = gcry_cipher_encrypt(cipher->handle, outdata + inlen, cipher->blklen, pad, cipher->blklen))) {
+		if((err = gcry_cipher_encrypt(cipher->handle, (char *)outdata + inlen, cipher->blklen, pad, cipher->blklen))) {
 			logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
 			return false;
 		}
diff --git a/src/gcrypt/cipher.h b/src/gcrypt/cipher.h
index 41450c41..2067db68 100644
--- a/src/gcrypt/cipher.h
+++ b/src/gcrypt/cipher.h
@@ -3,7 +3,7 @@
 
 /*
     cipher.h -- header file cipher.c
-    Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -20,35 +20,17 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "system.h"
+#include "../system.h"
 
 #include <gcrypt.h>
 
-#define CIPHER_MAX_BLOCK_SIZE 32
-#define CIPHER_MAX_IV_SIZE 16
-#define CIPHER_MAX_KEY_SIZE 32
-
-typedef struct cipher {
+struct cipher {
 	gcry_cipher_hd_t handle;
 	uint8_t *key;
 	int nid;
 	uint16_t keylen;
 	uint16_t blklen;
 	bool padding;
-} cipher_t;
-
-extern bool cipher_open_by_name(struct cipher *, const char *);
-extern bool cipher_open_by_nid(struct cipher *, int);
-extern bool cipher_open_blowfish_ofb(struct cipher *);
-extern void cipher_close(struct cipher *);
-extern size_t cipher_keylength(const struct cipher *);
-extern void cipher_get_key(const struct cipher *, void *);
-extern bool cipher_set_key(struct cipher *, void *, bool);
-extern bool cipher_set_key_from_rsa(struct cipher *, void *, size_t, bool);
-extern bool cipher_regenerate_key(struct cipher *, bool);
-extern bool cipher_encrypt(struct cipher *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot);
-extern bool cipher_decrypt(struct cipher *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot);
-extern int cipher_get_nid(const struct cipher *);
-extern bool cipher_active(const struct cipher *);
+};
 
 #endif
diff --git a/src/gcrypt/crypto.c b/src/gcrypt/crypto.c
index dc92b3e0..cf5d0e64 100644
--- a/src/gcrypt/crypto.c
+++ b/src/gcrypt/crypto.c
@@ -1,6 +1,6 @@
 /*
     crypto.c -- Cryptographic miscellaneous functions and initialisation
-    Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -17,16 +17,16 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "system.h"
+#include "../system.h"
 
 #include <gcrypt.h>
 
-#include "crypto.h"
+#include "../crypto.h"
 
-void crypto_init() {
+void crypto_init(void) {
 }
 
-void crypto_exit() {
+void crypto_exit(void) {
 }
 
 void randomize(void *out, size_t outlen) {
diff --git a/src/gcrypt/crypto.h b/src/gcrypt/crypto.h
deleted file mode 100644
index c77d4f46..00000000
--- a/src/gcrypt/crypto.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef TINC_GCRYPT_CRYPTO_H
-#define TINC_GCRYPT_CRYPTO_H
-
-/*
-    crypto.h -- header for crypto.c
-    Copyright (C) 2007-2009 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
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-extern void crypto_init();
-extern void crypto_exit();
-extern void randomize(void *, size_t);
-
-#endif
diff --git a/src/gcrypt/digest.c b/src/gcrypt/digest.c
index c8d4b314..1795277e 100644
--- a/src/gcrypt/digest.c
+++ b/src/gcrypt/digest.c
@@ -1,6 +1,6 @@
 /*
     digest.c -- Digest handling
-    Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -17,10 +17,11 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "system.h"
+#include "../system.h"
 
 #include "digest.h"
-#include "logger.h"
+#include "../digest.h"
+#include "../logger.h"
 
 static struct {
 	const char *name;
@@ -35,9 +36,7 @@ static struct {
 };
 
 static bool nametodigest(const char *name, enum gcry_md_algos *algo) {
-	int i;
-
-	for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
+	for(size_t i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
 		if(digesttable[i].name && !strcasecmp(name, digesttable[i].name)) {
 			*algo = digesttable[i].algo;
 			return true;
@@ -48,7 +47,7 @@ static bool nametodigest(const char *name, enum gcry_md_algos *algo) {
 }
 
 static bool nidtodigest(int nid, enum gcry_md_algos *algo) {
-	for(int i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
+	for(size_t i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
 		if(nid == digesttable[i].nid) {
 			*algo = digesttable[i].algo;
 			return true;
@@ -59,7 +58,7 @@ static bool nidtodigest(int nid, enum gcry_md_algos *algo) {
 }
 
 static bool digesttonid(enum gcry_md_algos algo, int *nid) {
-	for(int i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
+	for(size_t i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
 		if(algo == digesttable[i].algo) {
 			*nid = digesttable[i].nid;
 			return true;
@@ -77,7 +76,7 @@ static bool digest_open(digest_t *digest, enum gcry_md_algos algo, size_t maclen
 
 	unsigned int len = gcry_md_get_algo_dlen(algo);
 
-	if(maclength > len || maclength < 0) {
+	if(maclength > len) {
 		digest->maclength = len;
 	} else {
 		digest->maclength = maclength;
@@ -111,10 +110,6 @@ bool digest_open_by_nid(digest_t *digest, int nid, size_t maclength) {
 	return digest_open(digest, algo, maclength);
 }
 
-bool digest_open_sha1(digest_t *digest, size_t maclength) {
-	return digest_open(digest, GCRY_MD_SHA1, maclength);
-}
-
 void digest_close(digest_t *digest) {
 	if(digest->hmac) {
 		gcry_md_close(digest->hmac);
diff --git a/src/gcrypt/digest.h b/src/gcrypt/digest.h
index 9a9c611e..a83535d3 100644
--- a/src/gcrypt/digest.h
+++ b/src/gcrypt/digest.h
@@ -3,7 +3,7 @@
 
 /*
     digest.h -- header file digest.c
-    Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -22,8 +22,6 @@
 
 #include <gcrypt.h>
 
-#define DIGEST_MAX_SIZE 64
-
 typedef struct digest {
 	enum gcry_md_algos algo;
 	int nid;
@@ -31,15 +29,4 @@ typedef struct digest {
 	gcry_md_hd_t hmac;
 } digest_t;
 
-extern bool digest_open_by_name(struct digest *, const char *name, size_t maclength);
-extern bool digest_open_by_nid(struct digest *, int nid, size_t maclength);
-extern bool digest_open_sha1(struct digest *, size_t maclength);
-extern void digest_close(struct digest *);
-extern bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
-extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
-extern bool digest_set_key(struct digest *, const void *key, size_t len);
-extern int digest_get_nid(const struct digest *);
-extern size_t digest_length(const struct digest *);
-extern bool digest_active(const struct digest *);
-
 #endif
diff --git a/src/gcrypt/pem.c b/src/gcrypt/pem.c
index b22d0e40..b2eca3d4 100644
--- a/src/gcrypt/pem.c
+++ b/src/gcrypt/pem.c
@@ -1,5 +1,26 @@
+/*
+    pem.c -- PEM encoding and decoding
+    Copyright (C) 2007-2022 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "../system.h"
+
 #include "pem.h"
-#include "utils.h"
+#include "../utils.h"
 
 // Base64 decoding table
 
@@ -35,7 +56,7 @@ static const char b64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 // Heavily based on code by Jouni Malinen <j@w1.fi>
 // https://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c
 static size_t b64encode(char *dst, const void *src, const size_t length) {
-	const uint8_t *end = src + length;
+	const uint8_t *end = (const uint8_t *)src + length;
 	const uint8_t *in = src;
 	char *pos = dst;
 
diff --git a/src/gcrypt/pem.h b/src/gcrypt/pem.h
index 119c114b..f7d1d6ec 100644
--- a/src/gcrypt/pem.h
+++ b/src/gcrypt/pem.h
@@ -1,6 +1,25 @@
 #ifndef TINC_GCRYPT_PEM_H
 #define TINC_GCRYPT_PEM_H
 
+/*
+    pem.h -- PEM encoding and decoding
+    Copyright (C) 2007-2022 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
 #include "../system.h"
 
 bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize);
diff --git a/src/gcrypt/rsa.c b/src/gcrypt/rsa.c
index 5d12985d..1b151648 100644
--- a/src/gcrypt/rsa.c
+++ b/src/gcrypt/rsa.c
@@ -1,6 +1,6 @@
 /*
     rsa.c -- RSA key handling
-    Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -17,14 +17,16 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "system.h"
+#include "../system.h"
 
 #include <gcrypt.h>
 
-#include "logger.h"
-#include "rsa.h"
 #include "pem.h"
-#include "xalloc.h"
+
+#include "rsa.h"
+#include "../logger.h"
+#include "../rsa.h"
+#include "../xalloc.h"
 
 // BER decoding functions
 
@@ -62,7 +64,7 @@ static size_t ber_read_len(unsigned char **p, size_t *buflen) {
 
 	if(**p & 0x80) {
 		size_t result = 0;
-		int len = *(*p)++ & 0x7f;
+		size_t len = *(*p)++ & 0x7f;
 		(*buflen)--;
 
 		if(len > *buflen) {
@@ -117,11 +119,14 @@ static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
 	return mpi ? !err : true;
 }
 
-rsa_t *rsa_set_hex_public_key(char *n, char *e) {
+rsa_t *rsa_set_hex_public_key(const char *n, const char *e) {
 	rsa_t *rsa = xzalloc(sizeof(rsa_t));
 
-	gcry_error_t err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
-	                   ? : gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
+	gcry_error_t err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL);
+
+	if(!err) {
+		err = gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
+	}
 
 	if(err) {
 		logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
@@ -132,12 +137,18 @@ rsa_t *rsa_set_hex_public_key(char *n, char *e) {
 	return rsa;
 }
 
-rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) {
+rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) {
 	rsa_t *rsa = xzalloc(sizeof(rsa_t));
 
-	gcry_error_t err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
-	                   ? : gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL)
-	                   ? : gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
+	gcry_error_t err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL);
+
+	if(!err) {
+		err = gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
+	}
+
+	if(!err) {
+		err = gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
+	}
 
 	if(err) {
 		logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
@@ -203,7 +214,7 @@ rsa_t *rsa_read_pem_private_key(FILE *fp) {
 	return rsa;
 }
 
-size_t rsa_size(rsa_t *rsa) {
+size_t rsa_size(const rsa_t *rsa) {
 	return (gcry_mpi_get_nbits(rsa->n) + 7) / 8;
 }
 
@@ -214,7 +225,7 @@ size_t rsa_size(rsa_t *rsa) {
 // TODO: get rid of this macro, properly clean up gcry_ structures after use
 #define check(foo) { gcry_error_t err = (foo); if(err) {logger(DEBUG_ALWAYS, LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
 
-bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+bool rsa_public_encrypt(rsa_t *rsa, const void *in, size_t len, void *out) {
 	gcry_mpi_t inmpi;
 	check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
 
@@ -223,17 +234,18 @@ bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
 
 	size_t out_bytes = (gcry_mpi_get_nbits(outmpi) + 7) / 8;
 	size_t pad = len - MIN(out_bytes, len);
+	unsigned char *pout = out;
 
 	for(; pad; --pad) {
-		*(char *)out++ = 0;
+		*pout++ = 0;
 	}
 
-	check(gcry_mpi_print(GCRYMPI_FMT_USG, out, len, NULL, outmpi));
+	check(gcry_mpi_print(GCRYMPI_FMT_USG, pout, len, NULL, outmpi));
 
 	return true;
 }
 
-bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+bool rsa_private_decrypt(rsa_t *rsa, const void *in, size_t len, void *out) {
 	gcry_mpi_t inmpi;
 	check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
 
@@ -241,12 +253,13 @@ bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
 	gcry_mpi_powm(outmpi, inmpi, rsa->d, rsa->n);
 
 	size_t pad = len - (gcry_mpi_get_nbits(outmpi) + 7) / 8;
+	unsigned char *pout = out;
 
 	for(; pad; --pad) {
-		*(char *)out++ = 0;
+		*pout++ = 0;
 	}
 
-	check(gcry_mpi_print(GCRYMPI_FMT_USG, out, len, NULL, outmpi));
+	check(gcry_mpi_print(GCRYMPI_FMT_USG, pout, len, NULL, outmpi));
 
 	return true;
 }
diff --git a/src/gcrypt/rsa.h b/src/gcrypt/rsa.h
index c27f1967..e6bb5ec9 100644
--- a/src/gcrypt/rsa.h
+++ b/src/gcrypt/rsa.h
@@ -3,7 +3,7 @@
 
 /*
     rsa.h -- RSA key handling
-    Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -22,6 +22,7 @@
 
 #include <gcrypt.h>
 
+#define TINC_RSA_INTERNAL
 typedef struct rsa {
 	gcry_mpi_t n;
 	gcry_mpi_t e;
diff --git a/src/gcrypt/rsagen.c b/src/gcrypt/rsagen.c
index acf96acf..01bb1378 100644
--- a/src/gcrypt/rsagen.c
+++ b/src/gcrypt/rsagen.c
@@ -1,6 +1,6 @@
 /*
     rsagen.c -- RSA key generation and export
-    Copyright (C) 2008-2012 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2008-2022 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
@@ -17,15 +17,15 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "system.h"
+#include "../system.h"
 
 #include <gcrypt.h>
 #include <assert.h>
 
-#include "../rsagen.h"
-#include "xalloc.h"
 #include "rsa.h"
 #include "pem.h"
+#include "../rsagen.h"
+#include "../xalloc.h"
 
 // ASN.1 tags.
 typedef enum {
@@ -106,7 +106,7 @@ static size_t der_fill(uint8_t *derbuf, bool is_private, const gcry_mpi_t mpi[],
 		der += len;
 	}
 
-	assert(der - derbuf == derlen);
+	assert((size_t)(der - derbuf) == derlen);
 	return derlen;
 }
 
diff --git a/src/hash.h b/src/hash.h
index 11d132a4..531c6639 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -3,7 +3,7 @@
 
 /*
     hash.h -- header file for hash.c
-    Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2012-2022 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
@@ -37,10 +37,10 @@ uint32_t modulo(uint32_t hash, size_t n);
 		t keys[n]; \
 		const void *values[n]; \
 	} hash_ ## t; \
-	static uint32_t inline hash_modulo_ ## t(uint32_t hash) { \
+	static inline uint32_t hash_modulo_ ## t(uint32_t hash) { \
 		return hash & (n - 1); \
 	} \
-	void hash_insert_ ## t (hash_ ##t *hash, const t *key, const void *value) { \
+	static inline void hash_insert_ ## t (hash_ ##t *hash, const t *key, const void *value) { \
 		uint32_t i = hash_modulo_ ## t(hash_function_ ## t(key)); \
 		for(uint8_t f=0; f< (HASH_SEARCH_ITERATIONS - 1); f++){ \
 			if(hash->values[i] == NULL || !memcmp(key, &hash->keys[i], sizeof(t))) { \
@@ -54,7 +54,7 @@ uint32_t modulo(uint32_t hash, size_t n);
 		memcpy(&hash->keys[i], key, sizeof(t)); \
 		hash->values[i] = value; \
 	} \
-	void *hash_search_ ## t (const hash_ ##t *hash, const t *key) { \
+	static inline void *hash_search_ ## t (const hash_ ##t *hash, const t *key) { \
 		uint32_t i = hash_modulo_ ## t(hash_function_ ## t(key)); \
 		for(uint8_t f=0; f<HASH_SEARCH_ITERATIONS; f++){ \
 			if(!memcmp(key, &hash->keys[i], sizeof(t))) { \
@@ -64,7 +64,7 @@ uint32_t modulo(uint32_t hash, size_t n);
 		} \
 		return NULL; \
 	} \
-	void hash_delete_ ## t (hash_ ##t *hash, const t *key) { \
+	static inline void hash_delete_ ## t (hash_ ##t *hash, const t *key) { \
 		uint32_t i = hash_modulo_ ## t(hash_function_ ## t(key)); \
 		for(uint8_t f=0; f<HASH_SEARCH_ITERATIONS; f++){ \
 			if(!memcmp(key, &hash->keys[i], sizeof(t))) { \
@@ -74,7 +74,7 @@ uint32_t modulo(uint32_t hash, size_t n);
 			if(++i == n) i = 0; \
 		} \
 	} \
-	void hash_clear_ ## t(hash_ ##t *hash) { \
+	static inline void hash_clear_ ## t(hash_ ##t *hash) { \
 		memset(hash->values, 0, n * sizeof(*hash->values)); \
 		memset(hash->keys, 0, n * sizeof(*hash->keys)); \
 	}
diff --git a/src/have.h b/src/have.h
index bb236622..96e35fd7 100644
--- a/src/have.h
+++ b/src/have.h
@@ -22,7 +22,8 @@
 */
 
 #ifdef HAVE_MINGW
-#define WINVER WindowsXP
+#define WINVER 0x0600
+#define _WIN32_WINNT 0x0600
 #define WIN32_LEAN_AND_MEAN
 #endif
 
diff --git a/src/info.c b/src/info.c
index c324df94..25e6b60c 100644
--- a/src/info.c
+++ b/src/info.c
@@ -1,6 +1,6 @@
 /*
     info.c -- Show information about a node, subnet or address
-    Copyright (C) 2012-2017 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2012-2022 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
@@ -20,9 +20,10 @@
 #include "system.h"
 
 #include "control_common.h"
+#include "info.h"
+#include "logger.h"
 #include "subnet.h"
 #include "tincctl.h"
-#include "info.h"
 #include "utils.h"
 
 void logger(int level, int priority, const char *format, ...) {
diff --git a/src/invitation.c b/src/invitation.c
index f2f4d76c..e71a4889 100644
--- a/src/invitation.c
+++ b/src/invitation.c
@@ -1,6 +1,6 @@
 /*
     invitation.c -- Create and accept invitations
-    Copyright (C) 2013-2017 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2013-2022 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
@@ -97,7 +97,7 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port
 	fclose(f);
 }
 
-char *get_my_hostname() {
+static char *get_my_hostname(void) {
 	char *hostname = NULL;
 	char *port = NULL;
 	char *hostport = NULL;
@@ -545,14 +545,12 @@ int cmd_invite(int argc, char *argv[]) {
 }
 
 static int sock;
-static char cookie[18];
+static char cookie[18], hash[18];
 static sptps_t sptps;
 static char *data;
 static size_t datalen;
 static bool success = false;
 
-static char cookie[18], hash[18];
-
 static char *get_line(const char **data) {
 	if(!data || !*data) {
 		return NULL;
@@ -1087,7 +1085,7 @@ ask_netname:
 static bool invitation_send(void *handle, uint8_t type, const void *vdata, size_t len) {
 	(void)handle;
 	(void)type;
-	const uint8_t *data = vdata;
+	const char *data = vdata;
 
 	while(len) {
 		ssize_t result = send(sock, data, len, 0);
@@ -1227,7 +1225,8 @@ int cmd_join(int argc, char *argv[]) {
 	}
 
 	if(!port || !*port) {
-		port = "655";
+		static char default_port[] = "655";
+		port = default_port;
 	}
 
 	if(!b64decode_tinc(slash, hash, 24) || !b64decode_tinc(slash + 24, cookie, 24)) {
diff --git a/src/invitation.h b/src/invitation.h
index 6517fe84..e176c4da 100644
--- a/src/invitation.h
+++ b/src/invitation.h
@@ -3,7 +3,7 @@
 
 /*
     invitation.h -- header for invitation.c.
-    Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2013-2022 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
diff --git a/src/logger.c b/src/logger.c
index 1a2e95ff..caaf038d 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -1,6 +1,6 @@
 /*
     logger.c -- logging code
-    Copyright (C) 2004-2017 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2004-2022 Guus Sliepen <guus@tinc-vpn.org>
                   2004-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -91,8 +91,11 @@ static void real_logger(debug_t level, int priority, const char *message) {
 		}
 
 		if(umbilical && do_detach) {
-			write(umbilical, message, strlen(message));
-			write(umbilical, "\n", 1);
+			size_t len = strlen(message);
+
+			if(write(umbilical, message, len) != (ssize_t)len || write(umbilical, "\n", 1) != 1) {
+				// Other end broken, nothing we can do about it.
+			}
 		}
 	}
 
@@ -113,7 +116,7 @@ static void real_logger(debug_t level, int priority, const char *message) {
 
 			size_t len = strlen(message);
 
-			if(send_request(c, "%d %d %zu", CONTROL, REQ_LOG, len)) {
+			if(send_request(c, "%d %d %lu", CONTROL, REQ_LOG, (unsigned long)len)) {
 				send_meta(c, message, len);
 			}
 		}
@@ -220,7 +223,7 @@ void openlogger(const char *ident, logmode_t mode) {
 	}
 }
 
-void reopenlogger() {
+void reopenlogger(void) {
 	if(logmode != LOGMODE_FILE) {
 		return;
 	}
diff --git a/src/meta.c b/src/meta.c
index f6a9ba18..6a217d61 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -56,8 +56,8 @@ bool send_meta(connection_t *c, const void *buffer, size_t length) {
 		abort();
 	}
 
-	logger(DEBUG_META, LOG_DEBUG, "Sending %zu bytes of metadata to %s (%s)",
-	       length, c->name, c->hostname);
+	logger(DEBUG_META, LOG_DEBUG, "Sending %lu bytes of metadata to %s (%s)",
+	       (unsigned long)length, c->name, c->hostname);
 
 	if(c->protocol_minor >= 2) {
 		return sptps_send_record(&c->sptps, 0, buffer, length);
@@ -100,8 +100,8 @@ void send_meta_raw(connection_t *c, const void *buffer, size_t length) {
 		abort();
 	}
 
-	logger(DEBUG_META, LOG_DEBUG, "Sending %zu bytes of raw metadata to %s (%s)",
-	       length, c->name, c->hostname);
+	logger(DEBUG_META, LOG_DEBUG, "Sending %lu bytes of raw metadata to %s (%s)",
+	       (unsigned long)length, c->name, c->hostname);
 
 	buffer_add(&c->outbuf, buffer, length);
 
diff --git a/src/mingw/device.c b/src/mingw/device.c
index b7a191f4..03a1d48c 100644
--- a/src/mingw/device.c
+++ b/src/mingw/device.c
@@ -1,7 +1,7 @@
 /*
     device.c -- Interaction with Windows tap driver in a MinGW environment
     Copyright (C) 2002-2005 Ivo Timmermans,
-                  2002-2018 Guus Sliepen <guus@tinc-vpn.org>
+                  2002-2022 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
@@ -45,9 +45,7 @@ char *device = NULL;
 char *iface = NULL;
 static const char *device_info = "Windows tap device";
 
-extern char *myport;
-
-static void device_issue_read() {
+static void device_issue_read(void) {
 	int status;
 
 	for(;;) {
diff --git a/src/multicast_device.c b/src/multicast_device.c
index 907eb100..79239a19 100644
--- a/src/multicast_device.c
+++ b/src/multicast_device.c
@@ -188,7 +188,7 @@ static bool read_packet(vpn_packet_t *packet) {
 	}
 
 	if(!memcmp(&ignore_src, DATA(packet) + 6, sizeof(ignore_src))) {
-		logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %zd bytes from %s", lenin, device_info);
+		logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %ld bytes from %s", (long)lenin, device_info);
 		return false;
 	}
 
diff --git a/src/net_packet.c b/src/net_packet.c
index 89172670..459b2413 100644
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -1,7 +1,7 @@
 /*
     net_packet.c -- Handles in- and outgoing VPN packets
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2021 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 Guus Sliepen <guus@tinc-vpn.org>
                   2010      Timothy Redaelli <timothy@redaelli.eu>
                   2010      Brandon Black <blblack@gmail.com>
 
@@ -992,8 +992,8 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
 		overhead += sizeof(to->id) + sizeof(from->id);
 	}
 
-	uint8_t buf[len + overhead];
-	uint8_t *buf_ptr = buf;
+	char buf[len + overhead];
+	char *buf_ptr = buf;
 
 	if(relay_supported) {
 		if(direct) {
@@ -1165,7 +1165,7 @@ static void send_udp_probe_packet(node_t *n, size_t len) {
 	vpn_packet_t packet;
 
 	if(len > sizeof(packet.data)) {
-		logger(DEBUG_TRAFFIC, LOG_INFO, "Truncating probe length %zu to %s (%s)", len, n->name, n->hostname);
+		logger(DEBUG_TRAFFIC, LOG_INFO, "Truncating probe length %lu to %s (%s)", (unsigned long)len, n->name, n->hostname);
 		len = sizeof(packet.data);
 	}
 
@@ -1175,7 +1175,7 @@ static void send_udp_probe_packet(node_t *n, size_t len) {
 	packet.len = len;
 	packet.priority = 0;
 
-	logger(DEBUG_TRAFFIC, LOG_INFO, "Sending UDP probe length %zu to %s (%s)", len, n->name, n->hostname);
+	logger(DEBUG_TRAFFIC, LOG_INFO, "Sending UDP probe length %lu to %s (%s)", (unsigned long)len, n->name, n->hostname);
 
 	send_udppacket(n, &packet);
 }
@@ -1261,7 +1261,7 @@ static length_t choose_initial_maxmtu(node_t *n) {
 	int ip_mtu;
 	socklen_t ip_mtu_len = sizeof(ip_mtu);
 
-	if(getsockopt(sock, IPPROTO_IP, IP_MTU, &ip_mtu, &ip_mtu_len)) {
+	if(getsockopt(sock, IPPROTO_IP, IP_MTU, (void *)&ip_mtu, &ip_mtu_len)) {
 		logger(DEBUG_TRAFFIC, LOG_ERR, "getsockopt(IP_MTU) on %s (%s) failed: %s", n->name, n->hostname, sockstrerror(sockerrno));
 		close(sock);
 		return MTU;
@@ -1424,7 +1424,7 @@ static void try_mtu(node_t *n) {
 				        on the precise MTU as we are approaching it.
 				        The last probe of the cycle is always 1 byte in size - this is to make sure we'll get at least one
 				        reply per cycle so that we can make progress. */
-				offset = (length_t) powf(interval, multiplier * cycle_position / ((float) probes_per_cycle - 1.0f));
+				offset = lrintf(powf(interval, multiplier * cycle_position / (float)(probes_per_cycle - 1)));
 			}
 
 			length_t maxmtu = n->maxmtu;
diff --git a/src/node.c b/src/node.c
index 7655cae9..fce1217e 100644
--- a/src/node.c
+++ b/src/node.c
@@ -202,12 +202,12 @@ bool dump_nodes(connection_t *c) {
 		}
 
 		id[sizeof(id) - 1] = 0;
-		send_request(c, "%d %d %s %s %s %d %d %zu %d %x %x %s %s %d %d %d %d %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_NODES,
+		send_request(c, "%d %d %s %s %s %d %d %lu %d %x %x %s %s %d %d %d %d %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_NODES,
 		             n->name, id, n->hostname ? n->hostname : "unknown port unknown",
 #ifdef DISABLE_LEGACY
 		             0, 0, 0UL,
 #else
-		             cipher_get_nid(n->outcipher), digest_get_nid(n->outdigest), digest_length(n->outdigest),
+		             cipher_get_nid(n->outcipher), digest_get_nid(n->outdigest), (unsigned long)digest_length(n->outdigest),
 #endif
 		             n->outcompression, n->options, bitfield_to_int(&n->status, sizeof(n->status)),
 		             n->nexthop ? n->nexthop->name : "-", n->via && n->via->name ? n->via->name : "-", n->distance,
diff --git a/src/node.h b/src/node.h
index f312043d..d0700825 100644
--- a/src/node.h
+++ b/src/node.h
@@ -29,20 +29,19 @@
 #include "subnet.h"
 
 typedef struct node_status_t {
-	bool unused_active: 1;          /* 1 if active (not used for nodes) */
-	bool validkey: 1;               /* 1 if we currently have a valid key for him */
-	bool waitingforkey: 1;          /* 1 if we already sent out a request */
-	bool visited: 1;                /* 1 if this node has been visited by one of the graph algorithms */
-	bool reachable: 1;              /* 1 if this node is reachable in the graph */
-	bool indirect: 1;               /* 1 if this node is not directly reachable by us */
-	bool sptps: 1;                  /* 1 if this node supports SPTPS */
-	bool udp_confirmed: 1;          /* 1 if the address is one that we received UDP traffic on */
-	bool send_locally: 1;           /* 1 if the next UDP packet should be sent on the local network */
-	bool udppacket: 1;              /* 1 if the most recently received packet was UDP */
-	bool validkey_in: 1;            /* 1 if we have sent a valid key to him */
-	bool has_address: 1;            /* 1 if we know an external address for this node */
-	bool ping_sent: 1;              /* 1 if we sent a UDP probe but haven't received the reply yet */
-	uint32_t unused: 19;
+	uint32_t unused_active: 1;          /* 1 if active (not used for nodes) */
+	uint32_t validkey: 1;               /* 1 if we currently have a valid key for him */
+	uint32_t waitingforkey: 1;          /* 1 if we already sent out a request */
+	uint32_t visited: 1;                /* 1 if this node has been visited by one of the graph algorithms */
+	uint32_t reachable: 1;              /* 1 if this node is reachable in the graph */
+	uint32_t indirect: 1;               /* 1 if this node is not directly reachable by us */
+	uint32_t sptps: 1;                  /* 1 if this node supports SPTPS */
+	uint32_t udp_confirmed: 1;          /* 1 if the address is one that we received UDP traffic on */
+	uint32_t send_locally: 1;           /* 1 if the next UDP packet should be sent on the local network */
+	uint32_t udppacket: 1;              /* 1 if the most recently received packet was UDP */
+	uint32_t validkey_in: 1;            /* 1 if we have sent a valid key to him */
+	uint32_t has_address: 1;            /* 1 if we know an external address for this node */
+	uint32_t ping_sent: 1;              /* 1 if we sent a UDP probe but haven't received the reply yet */
 } node_status_t;
 
 typedef struct node_t {
diff --git a/src/nolegacy/crypto.c b/src/nolegacy/crypto.c
index 424fac27..d9df8288 100644
--- a/src/nolegacy/crypto.c
+++ b/src/nolegacy/crypto.c
@@ -67,14 +67,14 @@ void randomize(void *vout, size_t outlen) {
 #include <wincrypt.h>
 HCRYPTPROV prov;
 
-void random_init(void) {
+static void random_init(void) {
 	if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
 		fprintf(stderr, "CryptAcquireContext() failed!\n");
 		abort();
 	}
 }
 
-void random_exit(void) {
+static void random_exit(void) {
 	CryptReleaseContext(prov, 0);
 }
 
diff --git a/src/openssl/cipher.c b/src/openssl/cipher.c
index 08b81de7..6b2affc0 100644
--- a/src/openssl/cipher.c
+++ b/src/openssl/cipher.c
@@ -1,6 +1,6 @@
 /*
     cipher.c -- Symmetric block cipher handling
-    Copyright (C) 2007-2017 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -23,6 +23,7 @@
 #include <openssl/err.h>
 #include <openssl/evp.h>
 
+#include "cipher.h"
 #include "../cipher.h"
 #include "../logger.h"
 
diff --git a/src/openssl/cipher.h b/src/openssl/cipher.h
index 6f3e6b7b..360596c6 100644
--- a/src/openssl/cipher.h
+++ b/src/openssl/cipher.h
@@ -1,6 +1,25 @@
 #ifndef TINC_OPENSSL_CIPHER_H
 #define TINC_OPENSSL_CIPHER_H
 
+/*
+    cipher.h -- header file cipher.c
+    Copyright (C) 2007-2022 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
 #include <openssl/evp.h>
 
 struct cipher {
diff --git a/src/openssl/crypto.c b/src/openssl/crypto.c
index 7cfdbbaf..34009d69 100644
--- a/src/openssl/crypto.c
+++ b/src/openssl/crypto.c
@@ -70,14 +70,14 @@ void randomize(void *vout, size_t outlen) {
 #include <wincrypt.h>
 HCRYPTPROV prov;
 
-void random_init(void) {
+static void random_init(void) {
 	if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
 		fprintf(stderr, "CryptAcquireContext() failed!\n");
 		abort();
 	}
 }
 
-void random_exit(void) {
+static void random_exit(void) {
 	CryptReleaseContext(prov, 0);
 }
 
diff --git a/src/openssl/digest.h b/src/openssl/digest.h
index 35153532..66d54164 100644
--- a/src/openssl/digest.h
+++ b/src/openssl/digest.h
@@ -3,7 +3,7 @@
 
 /*
     digest.h -- header file digest.c
-    Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2013-2022 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
diff --git a/src/openssl/rsa.c b/src/openssl/rsa.c
index e7428add..d50ba1d7 100644
--- a/src/openssl/rsa.c
+++ b/src/openssl/rsa.c
@@ -1,6 +1,6 @@
 /*
     rsa.c -- RSA key handling
-    Copyright (C) 2007-2021 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -31,7 +31,7 @@ typedef RSA rsa_t;
 
 // Set RSA keys
 
-rsa_t *rsa_set_hex_public_key(char *n, char *e) {
+rsa_t *rsa_set_hex_public_key(const char *n, const char *e) {
 	BIGNUM *bn_n = NULL;
 	BIGNUM *bn_e = NULL;
 
@@ -52,7 +52,7 @@ rsa_t *rsa_set_hex_public_key(char *n, char *e) {
 	return rsa;
 }
 
-rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) {
+rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) {
 	BIGNUM *bn_n = NULL;
 	BIGNUM *bn_e = NULL;
 	BIGNUM *bn_d = NULL;
@@ -106,7 +106,7 @@ size_t rsa_size(const rsa_t *rsa) {
 	return RSA_size(rsa);
 }
 
-bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+bool rsa_public_encrypt(rsa_t *rsa, const void *in, size_t len, void *out) {
 	if((size_t)RSA_public_encrypt((int) len, in, out, rsa, RSA_NO_PADDING) == len) {
 		return true;
 	}
@@ -115,7 +115,7 @@ bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
 	return false;
 }
 
-bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+bool rsa_private_decrypt(rsa_t *rsa, const void *in, size_t len, void *out) {
 	if((size_t)RSA_private_decrypt((int) len, in, out, rsa, RSA_NO_PADDING) == len) {
 		return true;
 	}
diff --git a/src/openssl/rsagen.c b/src/openssl/rsagen.c
index 277df231..ce0bd0bf 100644
--- a/src/openssl/rsagen.c
+++ b/src/openssl/rsagen.c
@@ -1,6 +1,6 @@
 /*
     rsagen.c -- RSA key generation and export
-    Copyright (C) 2008-2013 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2008-2022 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
@@ -17,6 +17,8 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include "system.h"
+
 #include <openssl/pem.h>
 #include <openssl/err.h>
 
diff --git a/src/process.c b/src/process.c
index f3e190c2..7d528f7e 100644
--- a/src/process.c
+++ b/src/process.c
@@ -46,7 +46,8 @@ static SERVICE_STATUS_HANDLE statushandle = 0;
 
 static bool install_service(void) {
 	char command[4096] = "\"";
-	SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
+	char description_buffer[] = "Virtual Private Network daemon";
+	SERVICE_DESCRIPTION description = {description_buffer};
 
 	manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
 
@@ -107,7 +108,7 @@ static bool install_service(void) {
 
 io_t stop_io;
 
-DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID data, LPVOID context) {
+static DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID data, LPVOID context) {
 	(void)type;
 	(void)data;
 	(void)context;
@@ -141,7 +142,7 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID data, LPVOID conte
 	return NO_ERROR;
 }
 
-VOID WINAPI run_service(DWORD argc, LPTSTR *argv) {
+static VOID WINAPI run_service(DWORD argc, LPTSTR *argv) {
 	extern int main2(int argc, char **argv);
 
 	status.dwServiceType = SERVICE_WIN32;
diff --git a/src/protocol.c b/src/protocol.c
index 8f0efb2a..3539ca7c 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -1,7 +1,7 @@
 /*
     protocol.c -- handle the meta-protocol, basic functions
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -49,7 +49,7 @@ static bool (*request_handlers[])(connection_t *, const char *) = {
 
 /* Request names */
 
-static char (*request_name[]) = {
+static const char (*request_name[]) = {
 	"ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
 	"STATUS", "ERROR", "TERMREQ",
 	"PING", "PONG",
diff --git a/src/protocol_auth.c b/src/protocol_auth.c
index 12dc144a..02b7399c 100644
--- a/src/protocol_auth.c
+++ b/src/protocol_auth.c
@@ -1,7 +1,7 @@
 /*
     protocol_auth.c -- handle the meta-protocol, authentication
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2017 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -287,7 +287,12 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat
 
 	// Read the new node's Name from the file
 	char buf[1024] = "";
-	fgets(buf, sizeof(buf), f);
+
+	if(!fgets(buf, sizeof(buf), f)) {
+		logger(DEBUG_ALWAYS, LOG_ERR, "Could not read invitation file %s\n", cookie);
+		return false;
+	}
+
 	size_t buflen = strlen(buf);
 
 	// Strip whitespace at the end
diff --git a/src/protocol_key.c b/src/protocol_key.c
index c14dfcac..1d1bee15 100644
--- a/src/protocol_key.c
+++ b/src/protocol_key.c
@@ -383,11 +383,11 @@ bool send_ans_key(node_t *to) {
 
 	to->status.validkey_in = true;
 
-	return send_request(to->nexthop->connection, "%d %s %s %s %d %d %zu %d", ANS_KEY,
+	return send_request(to->nexthop->connection, "%d %s %s %s %d %d %lu %d", ANS_KEY,
 	                    myself->name, to->name, key,
 	                    cipher_get_nid(to->incipher),
 	                    digest_get_nid(to->indigest),
-	                    digest_length(to->indigest),
+	                    (unsigned long)digest_length(to->indigest),
 	                    to->incompression);
 #endif
 }
@@ -399,11 +399,11 @@ bool ans_key_h(connection_t *c, const char *request) {
 	char address[MAX_STRING_SIZE] = "";
 	char port[MAX_STRING_SIZE] = "";
 	int cipher, digest;
-	size_t maclength;
+	unsigned long maclength;
 	int compression;
 	node_t *from, *to;
 
-	if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %zu %d "MAX_STRING" "MAX_STRING,
+	if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %lu %d "MAX_STRING" "MAX_STRING,
 	                from_name, to_name, key, &cipher, &digest, &maclength,
 	                &compression, address, port) < 7) {
 		logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
diff --git a/src/protocol_misc.c b/src/protocol_misc.c
index 088a5242..cef7e3d0 100644
--- a/src/protocol_misc.c
+++ b/src/protocol_misc.c
@@ -1,7 +1,7 @@
 /*
     protocol_misc.c -- handle the meta-protocol, miscellaneous functions
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -75,8 +75,8 @@ bool pong_h(connection_t *c, const char *request) {
 }
 
 static bool random_early_drop(connection_t *c) {
-	if(c->outbuf.len > maxoutbufsize / 2) {
-		if((c->outbuf.len - maxoutbufsize / 2) > prng((maxoutbufsize) / 2)) {
+	if(c->outbuf.len > (size_t)maxoutbufsize / 2) {
+		if((c->outbuf.len - (size_t)maxoutbufsize / 2) > prng((size_t)maxoutbufsize / 2)) {
 			return true;
 		}
 	}
@@ -125,7 +125,7 @@ bool send_sptps_tcppacket(connection_t *c, const void *packet, size_t len) {
 		return true;
 	}
 
-	if(!send_request(c, "%d %zu", SPTPS_PACKET, len)) {
+	if(!send_request(c, "%d %lu", SPTPS_PACKET, (unsigned long)len)) {
 		return false;
 	}
 
diff --git a/src/route.c b/src/route.c
index 166b8b24..25f2be5e 100644
--- a/src/route.c
+++ b/src/route.c
@@ -585,7 +585,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
 	todo = ntohs(ip.ip_len) - ip_size;
 
 	if(ether_size + ip_size + todo != packet->len) {
-		logger(DEBUG_TRAFFIC, LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%zu)", packet->len, ether_size + ip_size + todo);
+		logger(DEBUG_TRAFFIC, LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%lu)", packet->len, (unsigned long)(ether_size + ip_size + todo));
 		return;
 	}
 
diff --git a/src/rsa.h b/src/rsa.h
index 4410d5c2..f7e9dbfa 100644
--- a/src/rsa.h
+++ b/src/rsa.h
@@ -3,7 +3,7 @@
 
 /*
     rsa.h -- RSA key handling
-    Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -27,12 +27,12 @@ typedef struct rsa rsa_t;
 #endif
 
 extern void rsa_free(rsa_t *rsa);
-extern rsa_t *rsa_set_hex_public_key(char *n, char *e) __attribute__((__malloc__));
-extern rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) __attribute__((__malloc__));
+extern rsa_t *rsa_set_hex_public_key(const char *n, const char *e) __attribute__((__malloc__));
+extern rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) __attribute__((__malloc__));
 extern rsa_t *rsa_read_pem_public_key(FILE *fp) __attribute__((__malloc__));
 extern rsa_t *rsa_read_pem_private_key(FILE *fp) __attribute__((__malloc__));
 extern size_t rsa_size(const rsa_t *rsa);
-extern bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) __attribute__((__warn_unused_result__));
-extern bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) __attribute__((__warn_unused_result__));
+extern bool rsa_public_encrypt(rsa_t *rsa, const void *in, size_t len, void *out) __attribute__((__warn_unused_result__));
+extern bool rsa_private_decrypt(rsa_t *rsa, const void *in, size_t len, void *out) __attribute__((__warn_unused_result__));
 
 #endif
diff --git a/src/script.c b/src/script.c
index 1336ff37..cb3d2934 100644
--- a/src/script.c
+++ b/src/script.c
@@ -1,7 +1,7 @@
 /*
     script.c -- call an external script
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2018 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 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
@@ -80,7 +80,12 @@ int environment_add(environment_t *env, const char *format, ...) {
 	if(format) {
 		va_list ap;
 		va_start(ap, format);
-		vasprintf(&env->entries[env->n], format, ap);
+
+		if(vasprintf(&env->entries[env->n], format, ap) == -1) {
+			// Assume we are out of memory.
+			abort();
+		}
+
 		va_end(ap);
 	} else {
 		env->entries[env->n] = NULL;
@@ -93,7 +98,11 @@ void environment_update(environment_t *env, int pos, const char *format, ...) {
 	free(env->entries[pos]);
 	va_list ap;
 	va_start(ap, format);
-	vasprintf(&env->entries[pos], format, ap);
+
+	if(vasprintf(&env->entries[pos], format, ap) == -1) {
+		abort();
+	}
+
 	va_end(ap);
 }
 
diff --git a/src/solaris/device.c b/src/solaris/device.c
index a8ddd04f..98c63167 100644
--- a/src/solaris/device.c
+++ b/src/solaris/device.c
@@ -2,7 +2,7 @@
     device.c -- Interaction with Solaris tun device
     Copyright (C) 2001-2005 Ivo Timmermans,
                   2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
-                  2001-2014 Guus Sliepen <guus@tinc-vpn.org>
+                  2001-2022 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
@@ -160,7 +160,8 @@ static bool setup_device(void) {
 
 	{
 		/* Remove muxes just in case they are left over from a crashed tincd */
-		struct lifreq ifr = {};
+		struct lifreq ifr;
+		memset(&ifr, 0, sizeof(ifr));
 		strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
 
 		if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
@@ -182,7 +183,8 @@ static bool setup_device(void) {
 	int arp_fd = -1;
 
 	if(device_type == DEVICE_TYPE_TAP) {
-		struct lifreq ifr = {};
+		struct lifreq ifr;
+		memset(&ifr, 0, sizeof(ifr));
 
 		if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
 			logger(DEBUG_ALWAYS, LOG_ERR, "Could not set flags on %s %s!", device_info, device);
@@ -263,7 +265,9 @@ static bool setup_device(void) {
 		close(arp_fd);
 	}
 
-	struct lifreq ifr = {};
+	struct lifreq ifr;
+
+	memset(&ifr, 0, sizeof(ifr));
 
 	strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
 
@@ -297,7 +301,8 @@ static bool setup_device(void) {
 
 static void close_device(void) {
 	if(iface) {
-		struct lifreq ifr = {};
+		struct lifreq ifr;
+		memset(&ifr, 0, sizeof(ifr));
 		strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
 
 		if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
diff --git a/src/sptps_keypair.c b/src/sptps_keypair.c
index bf7de125..22433b93 100644
--- a/src/sptps_keypair.c
+++ b/src/sptps_keypair.c
@@ -1,6 +1,6 @@
 /*
     sptps_test.c -- Simple Peer-to-Peer Security test program
-    Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2011-2022 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
@@ -39,7 +39,7 @@ void logger(debug_t level, int priority, const char *format, ...) {
 	fputc('\n', stderr);
 }
 
-static void usage() {
+static void usage(void) {
 	fprintf(stderr, "Usage: %s [options] private_key_file public_key_file\n\n", program_name);
 	fprintf(stderr, "Valid options are:\n"
 	        "  --help  Display this help and exit.\n"
diff --git a/src/sptps_speed.c b/src/sptps_speed.c
index 8e6f5bed..cc05b865 100644
--- a/src/sptps_speed.c
+++ b/src/sptps_speed.c
@@ -1,6 +1,6 @@
 /*
     sptps_speed.c -- SPTPS benchmark
-    Copyright (C) 2013-2014 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2013-2022 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
@@ -26,14 +26,23 @@
 #include "ecdh.h"
 #include "ecdsa.h"
 #include "ecdsagen.h"
+#include "meta.h"
+#include "protocol.h"
 #include "sptps.h"
 
 // Symbols necessary to link with logger.o
-bool send_request(void *c, const char *msg, ...) {
+bool send_request(struct connection_t *c, const char *msg, ...) {
+	(void)c;
+	(void)msg;
 	return false;
 }
-struct list_t *connection_list = NULL;
-bool send_meta(void *c, const char *msg, int len) {
+
+list_t connection_list;
+
+bool send_meta(struct connection_t *c, const void *msg, size_t len) {
+	(void)c;
+	(void)msg;
+	(void)len;
 	return false;
 }
 char *logfilename = NULL;
@@ -41,12 +50,17 @@ bool do_detach = false;
 struct timeval now;
 
 static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
+	(void)type;
 	int fd = *(int *)handle;
 	send(fd, data, len, 0);
 	return true;
 }
 
 static bool receive_record(void *handle, uint8_t type, const void *data, uint16_t len) {
+	(void)handle;
+	(void)type;
+	(void)data;
+	(void)len;
 	return true;
 }
 
@@ -73,7 +87,7 @@ double elapsed;
 double rate;
 unsigned int count;
 
-static void clock_start() {
+static void clock_start(void) {
 	count = 0;
 	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
 }
@@ -165,7 +179,7 @@ int main(int argc, char *argv[]) {
 		return 1;
 	}
 
-	struct pollfd pfd[2] = {{fd[0], POLLIN}, {fd[1], POLLIN}};
+	struct pollfd pfd[2] = {{fd[0], POLLIN, 0}, {fd[1], POLLIN, 0}};
 
 	fprintf(stderr, "SPTPS/TCP authenticate for %lg seconds: ", duration);
 
diff --git a/src/sptps_test.c b/src/sptps_test.c
index 2c013223..0f62af01 100644
--- a/src/sptps_test.c
+++ b/src/sptps_test.c
@@ -1,6 +1,6 @@
 /*
     sptps_test.c -- Simple Peer-to-Peer Security test program
-    Copyright (C) 2011-2014 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2011-2022 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
@@ -31,6 +31,8 @@
 
 #include "crypto.h"
 #include "ecdsa.h"
+#include "meta.h"
+#include "protocol.h"
 #include "sptps.h"
 #include "utils.h"
 
@@ -39,15 +41,15 @@
 #endif
 
 // Symbols necessary to link with logger.o
-bool send_request(void *c, const char *msg, ...) {
+bool send_request(struct connection_t *c, const char *msg, ...) {
 	(void)c;
 	(void)msg;
 	return false;
 }
 
-struct list_t *connection_list = NULL;
+list_t connection_list;
 
-bool send_meta(void *c, const char *msg, int len) {
+bool send_meta(struct connection_t *c, const void *msg, size_t len) {
 	(void)c;
 	(void)msg;
 	(void)len;
@@ -64,7 +66,7 @@ static bool readonly;
 static bool writeonly;
 static int in = 0;
 static int out = 1;
-static int addressfamily = AF_UNSPEC;
+int addressfamily = AF_UNSPEC;
 
 static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
 	(void)type;
@@ -72,13 +74,22 @@ static bool send_data(void *handle, uint8_t type, const void *data, size_t len)
 	bin2hex(data, hex, len);
 
 	if(verbose) {
-		fprintf(stderr, "Sending %zu bytes of data:\n%s\n", len, hex);
+		fprintf(stderr, "Sending %lu bytes of data:\n%s\n", (unsigned long)len, hex);
 	}
 
 	const int *sock = handle;
+	const char *p = data;
 
-	if((size_t)send(*sock, data, len, 0) != len) {
-		return false;
+	while(len) {
+		ssize_t sent = send(*sock, p, len, 0);
+
+		if(sent <= 0) {
+			fprintf(stderr, "Error sending data: %s\n", strerror(errno));
+			return false;
+		}
+
+		p += sent;
+		len -= sent;
 	}
 
 	return true;
@@ -91,8 +102,22 @@ static bool receive_record(void *handle, uint8_t type, const void *data, uint16_
 		fprintf(stderr, "Received type %d record of %u bytes:\n", type, len);
 	}
 
-	if(!writeonly) {
-		write(out, data, len);
+	if(writeonly) {
+		return true;
+	}
+
+	const char *p = data;
+
+	while(len) {
+		ssize_t written = write(out, p, len);
+
+		if(written <= 0) {
+			fprintf(stderr, "Error writing received data: %s\n", strerror(errno));
+			return false;
+		}
+
+		p += written;
+		len -= written;
 	}
 
 	return true;
@@ -113,9 +138,11 @@ static struct option const long_options[] = {
 
 const char *program_name;
 
-static void usage() {
-	fprintf(stderr, "Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n\n", program_name);
-	fprintf(stderr, "Valid options are:\n"
+static void usage(void) {
+	static const char *message =
+	        "Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n"
+	        "\n"
+	        "Valid options are:\n"
 	        "  -d, --datagram          Enable datagram mode.\n"
 	        "  -q, --quit              Quit when EOF occurs on stdin.\n"
 	        "  -r, --readonly          Only send data from the socket to stdout.\n"
@@ -129,8 +156,10 @@ static void usage() {
 	        "  -v, --verbose           Display debug messages.\n"
 	        "  -4                      Use IPv4.\n"
 	        "  -6                      Use IPv6.\n"
-	        "\n");
-	fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
+	        "\n"
+	        "Report bugs to tinc@tinc-vpn.org.\n";
+
+	fprintf(stderr, message, program_name);
 }
 
 #ifdef HAVE_MINGW
@@ -142,7 +171,7 @@ int stdin_sock_fd = -1;
 // separate thread between the stdin and the sptps loop way below. This thread
 // reads stdin and sends its content to the main thread through a TCP socket,
 // which can be properly select()'ed.
-void *stdin_reader_thread(void *arg) {
+static void *stdin_reader_thread(void *arg) {
 	struct sockaddr_in sa;
 	socklen_t sa_size = sizeof(sa);
 
@@ -158,7 +187,7 @@ void *stdin_reader_thread(void *arg) {
 			fprintf(stderr, "New connection received from :%d\n", ntohs(sa.sin_port));
 		}
 
-		uint8_t buf[1024];
+		char buf[1024];
 		ssize_t nread;
 
 		while((nread = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
@@ -166,7 +195,7 @@ void *stdin_reader_thread(void *arg) {
 				fprintf(stderr, "Read %lld bytes from input\n", nread);
 			}
 
-			uint8_t *start = buf;
+			char *start = buf;
 			ssize_t nleft = nread;
 
 			while(nleft) {
@@ -199,9 +228,10 @@ void *stdin_reader_thread(void *arg) {
 
 	closesocket(stdin_sock_fd);
 	stdin_sock_fd = -1;
+	return NULL;
 }
 
-int start_input_reader() {
+static int start_input_reader(void) {
 	if(stdin_sock_fd != -1) {
 		fprintf(stderr, "stdin thread can only be started once.\n");
 		return -1;
@@ -473,7 +503,7 @@ int main(int argc, char *argv[]) {
 		} else {
 			fprintf(stderr, "Listening...\n");
 
-			uint8_t buf[65536];
+			char buf[65536];
 			struct sockaddr addr;
 			socklen_t addrlen = sizeof(addr);
 
@@ -643,10 +673,10 @@ int main(int argc, char *argv[]) {
 			if(verbose) {
 				char hex[len * 2 + 1];
 				bin2hex(buf, hex, len);
-				fprintf(stderr, "Received %zd bytes of data:\n%s\n", len, hex);
+				fprintf(stderr, "Received %ld bytes of data:\n%s\n", (long)len, hex);
 			}
 
-			if(packetloss && prng(100) < packetloss) {
+			if(packetloss && (int)prng(100) < packetloss) {
 				if(verbose) {
 					fprintf(stderr, "Dropped.\n");
 				}
diff --git a/src/subnet.c b/src/subnet.c
index fe7d23ef..1ddf11e5 100644
--- a/src/subnet.c
+++ b/src/subnet.c
@@ -1,6 +1,6 @@
 /*
     subnet.c -- handle subnet lookups and lists
-    Copyright (C) 2000-2017 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2000-2022 Guus Sliepen <guus@tinc-vpn.org>,
                   2000-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -162,7 +162,7 @@ void subnet_cache_flush_tables(void) {
 	hash_clear(mac_t, &mac_cache);
 }
 
-void subnet_cache_flush(subnet_t *subnet) {
+static void subnet_cache_flush(subnet_t *subnet) {
 	switch(subnet->type) {
 	case SUBNET_IPV4:
 		if(subnet->net.ipv4.prefixlength == 32) {
@@ -322,7 +322,7 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
 
 void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
 	char netstr[MAXNETSTR];
-	char *name, *address, *port;
+	char *address, *port;
 	char empty[] = "";
 
 	// Prepare environment variables to be passed to the script
@@ -342,7 +342,7 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
 	int env_subnet = environment_add(&env, NULL);
 	int env_weight = environment_add(&env, NULL);
 
-	name = up ? "subnet-up" : "subnet-down";
+	const char *name = up ? "subnet-up" : "subnet-down";
 
 	if(!subnet) {
 		for splay_each(subnet_t, subnet, &owner->subnet_tree) {
diff --git a/src/tincctl.c b/src/tincctl.c
index b6c4fc89..215d757c 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -1,6 +1,6 @@
 /*
     tincctl.c -- Controlling a running tincd
-    Copyright (C) 2007-2021 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2007-2022 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
@@ -72,7 +72,8 @@ bool force = false;
 bool tty = true;
 bool confbasegiven = false;
 char *scriptinterpreter = NULL;
-char *scriptextension = "";
+static char defaultextension[] = "";
+char *scriptextension = defaultextension;
 static char *prompt;
 char *device = NULL;
 char *iface = NULL;
@@ -90,88 +91,95 @@ static struct option const long_options[] = {
 };
 
 static void version(void) {
-	printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
-	       BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
-	printf("Features:"
+	static const char *message =
+	        "%s version %s (built %s %s, protocol %d.%d)\n"
+	        "Features:"
 #ifdef HAVE_READLINE
-	       " readline"
+	        " readline"
 #endif
 #ifdef HAVE_CURSES
-	       " curses"
+	        " curses"
 #endif
 #ifndef DISABLE_LEGACY
-	       " legacy_protocol"
+	        " legacy_protocol"
 #endif
-	       "\n\n");
-	printf("Copyright (C) 1998-2018 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"
-	       "and you are welcome to redistribute it under certain conditions;\n"
-	       "see the file COPYING for details.\n");
+	        "\n\n"
+	        "Copyright (C) 1998-2018 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"
+	        "and you are welcome to redistribute it under certain conditions;\n"
+	        "see the file COPYING for details.\n";
+
+	printf(message, PACKAGE, BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
 }
 
 static void usage(bool status) {
 	if(status) {
 		fprintf(stderr, "Try `%s --help\' for more information.\n", program_name);
 	} else {
-		printf("Usage: %s [options] command\n\n", program_name);
-		printf("Valid options are:\n"
-		       "  -b, --batch             Don't ask for anything (non-interactive mode).\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"
-		       "Valid commands are:\n"
-		       "  init [name]                Create initial configuration files.\n"
-		       "  get VARIABLE               Print current value of VARIABLE\n"
-		       "  set VARIABLE VALUE         Set VARIABLE to VALUE\n"
-		       "  add VARIABLE VALUE         Add VARIABLE with the given VALUE\n"
-		       "  del VARIABLE [VALUE]       Remove VARIABLE [only ones with watching VALUE]\n"
-		       "  start [tincd options]      Start tincd.\n"
-		       "  stop                       Stop tincd.\n"
-		       "  restart [tincd options]    Restart tincd.\n"
-		       "  reload                     Partially reload configuration of running tincd.\n"
-		       "  pid                        Show PID of currently running tincd.\n"
+		static const char *message =
+		        "Usage: %s [options] command\n"
+		        "\n"
+		        "Valid options are:\n"
+		        "  -b, --batch             Don't ask for anything (non-interactive mode).\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"
+		        "Valid commands are:\n"
+		        "  init [name]                Create initial configuration files.\n"
+		        "  get VARIABLE               Print current value of VARIABLE\n"
+		        "  set VARIABLE VALUE         Set VARIABLE to VALUE\n"
+		        "  add VARIABLE VALUE         Add VARIABLE with the given VALUE\n"
+		        "  del VARIABLE [VALUE]       Remove VARIABLE [only ones with watching VALUE]\n"
+		        "  start [tincd options]      Start tincd.\n"
+		        "  stop                       Stop tincd.\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 key pair.\n"
+		        "  generate-keys              Generate a new Ed25519 public/private key pair.\n"
 #else
-		       "  generate-keys [bits]       Generate new RSA and Ed25519 public/private key pairs.\n"
-		       "  generate-rsa-keys [bits]   Generate a new RSA public/private key pair.\n"
+		        "  generate-keys [bits]       Generate new RSA and Ed25519 public/private key pairs.\n"
+		        "  generate-rsa-keys [bits]   Generate a new RSA public/private key pair.\n"
 #endif
-		       "  generate-ed25519-keys      Generate a new Ed25519 public/private key pair.\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"
-		       "    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"
-		       "  retry                      Retry all outgoing connections\n"
-		       "  disconnect NODE            Close meta connection with NODE\n"
+		        "  generate-ed25519-keys      Generate a new Ed25519 public/private key pair.\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"
+		        "    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"
+		        "  retry                      Retry all outgoing connections\n"
+		        "  disconnect NODE            Close meta connection with NODE\n"
 #ifdef HAVE_CURSES
-		       "  top                        Show real-time statistics\n"
+		        "  top                        Show real-time statistics\n"
 #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                     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 INVITATION\n"
-		       "  network [NETNAME]          List all known networks, or switch to the one named NETNAME.\n"
-		       "  fsck                       Check the configuration files for problems.\n"
-		       "  sign [FILE]                Generate a signed version of a file.\n"
-		       "  verify NODE [FILE]         Verify that a file was signed by the given NODE.\n"
-		       "\n");
-		printf("Report bugs to tinc@tinc-vpn.org.\n");
+		        "  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                     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 INVITATION\n"
+		        "  network [NETNAME]          List all known networks, or switch to the one named NETNAME.\n"
+		        "  fsck                       Check the configuration files for problems.\n"
+		        "  sign [FILE]                Generate a signed version of a file.\n"
+		        "  verify NODE [FILE]         Verify that a file was signed by the given NODE.\n"
+		        "\n"
+		        "Report bugs to tinc@tinc-vpn.org.\n";
+
+		printf(message, program_name);
 	}
 }
 
@@ -282,8 +290,12 @@ ask_filename:
 
 	if(filename[0] != '/') {
 #endif
+
 		/* The directory is a relative path or a filename. */
-		getcwd(directory, sizeof(directory));
+		if(!getcwd(directory, sizeof(directory))) {
+			fprintf(stderr, "Could not get current directory: %s\n", strerror(errno));
+			return NULL;
+		}
 
 		if((size_t)snprintf(buf2, sizeof(buf2), "%s" SLASH "%s", directory, filename) >= sizeof(buf2)) {
 			fprintf(stderr, "Filename too long: %s" SLASH "%s\n", directory, filename);
@@ -508,7 +520,7 @@ static bool recvdata(int fd, char *data, size_t len) {
 	return true;
 }
 
-bool sendline(int fd, char *format, ...) {
+bool sendline(int fd, const char *format, ...) {
 	static char buffer[4096];
 	char *p = buffer;
 	ssize_t blen;
@@ -578,8 +590,8 @@ static void pcap(int fd, FILE *out, uint32_t snaplen) {
 
 	while(recvline(fd, line, sizeof(line))) {
 		int code, req;
-		size_t len;
-		int n = sscanf(line, "%d %d %zd", &code, &req, &len);
+		unsigned long len;
+		int n = sscanf(line, "%d %d %lu", &code, &req, &len);
 		gettimeofday(&tv, NULL);
 
 		if(n != 3 || code != CONTROL || req != REQ_PCAP || len > sizeof(data)) {
@@ -884,12 +896,10 @@ static int cmd_start(int argc, char *argv[]) {
 
 #endif
 
-	char *default_c = "tincd";
-
 	if(slash++) {
 		xasprintf(&c, "%.*stincd", (int)(slash - program_name), program_name);
 	} else {
-		c = default_c;
+		c = xstrdup("tincd");
 	}
 
 	int nargc = 0;
@@ -921,10 +931,7 @@ static int cmd_start(int argc, char *argv[]) {
 	int status = spawnvp(_P_WAIT, c, nargv);
 
 	free(nargv);
-
-	if(c != default_c) {
-		free(c);
-	}
+	free(c);
 
 	if(status == -1) {
 		fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
@@ -938,11 +945,7 @@ static int cmd_start(int argc, char *argv[]) {
 	if(socketpair(AF_UNIX, SOCK_STREAM, 0, pfd)) {
 		fprintf(stderr, "Could not create umbilical socket: %s\n", strerror(errno));
 		free(nargv);
-
-		if(c != default_c) {
-			free(c);
-		}
-
+		free(c);
 		return 1;
 	}
 
@@ -951,11 +954,7 @@ static int cmd_start(int argc, char *argv[]) {
 	if(pid == -1) {
 		fprintf(stderr, "Could not fork: %s\n", strerror(errno));
 		free(nargv);
-
-		if(c != default_c) {
-			free(c);
-		}
-
+		free(c);
 		return 1;
 	}
 
@@ -988,7 +987,9 @@ static int cmd_start(int argc, char *argv[]) {
 			len--;
 		}
 
-		write(2, buf, len);
+		if(write(2, buf, len) != len) {
+			// Nothing we can do about it.
+		}
 	}
 
 	if(len) {
@@ -1011,9 +1012,7 @@ static int cmd_start(int argc, char *argv[]) {
 		fprintf(stderr, "Error starting %s\n", c);
 	}
 
-	if(c != default_c) {
-		free(c);
-	}
+	free(c);
 
 	return failed ? EXIT_FAILURE : EXIT_SUCCESS;
 #endif
@@ -1244,7 +1243,8 @@ static int cmd_dump(int argc, char *argv[]) {
 		char nexthop[4096];
 		int cipher, digest, maclength, compression, distance, socket, weight;
 		short int pmtu, minmtu, maxmtu;
-		unsigned int options, status_int;
+		unsigned int options;
+		uint32_t status_int;
 		node_status_t status;
 		long int last_state_change;
 		int udp_ping_rtt;
@@ -1252,7 +1252,7 @@ static int cmd_dump(int argc, char *argv[]) {
 
 		switch(req) {
 		case REQ_DUMP_NODES: {
-			int n = sscanf(line, "%*d %*d %4095s %4095s %4095s port %4095s %d %d %d %d %x %x %4095s %4095s %d %hd %hd %hd %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change, &udp_ping_rtt, &in_packets, &in_bytes, &out_packets, &out_bytes);
+			int n = sscanf(line, "%*d %*d %4095s %4095s %4095s port %4095s %d %d %d %d %x %"PRIx32" %4095s %4095s %d %hd %hd %hd %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change, &udp_ping_rtt, &in_packets, &in_bytes, &out_packets, &out_bytes);
 
 			if(n != 22) {
 				fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
@@ -3158,6 +3158,7 @@ static int cmd_shell(int argc, char *argv[]) {
 
 #ifdef HAVE_READLINE
 	rl_readline_name = "tinc";
+	rl_basic_word_break_characters = "\t\n ";
 	rl_completion_entry_function = complete_nothing;
 	rl_attempted_completion_function = completion;
 	rl_filename_completion_desired = 0;
@@ -3170,7 +3171,6 @@ static int cmd_shell(int argc, char *argv[]) {
 		if(tty) {
 			free(copy);
 			free(line);
-			rl_basic_word_break_characters = "\t\n ";
 			line = readline(prompt);
 			copy = line ? xstrdup(line) : NULL;
 		} else {
@@ -3261,7 +3261,7 @@ static int cmd_shell(int argc, char *argv[]) {
 	return result;
 }
 
-static void cleanup() {
+static void cleanup(void) {
 	free(tinc_conf);
 	free(hosts_dir);
 	free_names();
diff --git a/src/tincctl.h b/src/tincctl.h
index d09013d8..4018bb32 100644
--- a/src/tincctl.h
+++ b/src/tincctl.h
@@ -3,7 +3,7 @@
 
 /*
     tincctl.h -- header for tincctl.c.
-    Copyright (C) 2011-2016 Guus Sliepen <guus@tinc-vpn.org>
+    Copyright (C) 2011-2022 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
@@ -49,10 +49,9 @@ extern const var_t variables[];
 extern size_t rstrip(char *value);
 extern char *get_my_name(bool verbose);
 extern bool connect_tincd(bool verbose);
-extern bool sendline(int fd, char *format, ...);
+extern bool sendline(int fd, const char *format, ...);
 extern bool recvline(int fd, char *line, size_t len);
 extern int check_port(const char *name);
-extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms);
 extern ecdsa_t *get_pubkey(FILE *f);
 
 #endif
diff --git a/src/tincd.c b/src/tincd.c
index f9e31c19..022fb536 100644
--- a/src/tincd.c
+++ b/src/tincd.c
@@ -1,7 +1,7 @@
 /*
     tincd.c -- the main file for tincd
     Copyright (C) 1998-2005 Ivo Timmermans
-                  2000-2021 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2022 Guus Sliepen <guus@tinc-vpn.org>
                   2008      Max Rijevski <maksuf@gmail.com>
                   2009      Michael Tokarev <mjt@tls.msk.ru>
                   2010      Julien Muchembled <jm@jmuchemb.eu>
@@ -119,26 +119,31 @@ static void usage(bool status) {
 		fprintf(stderr, "Try `%s --help\' for more information.\n",
 		        program_name);
 	else {
-		printf("Usage: %s [option]...\n\n", program_name);
-		printf("  -c, --config=DIR              Read configuration options from DIR.\n"
-		       "  -D, --no-detach               Don't fork and detach.\n"
-		       "  -d, --debug[=LEVEL]           Increase debug level or set it to LEVEL.\n"
-		       "  -n, --net=NETNAME             Connect to net NETNAME.\n"
+		static const char *message =
+		        "Usage: %s [option]...\n"
+		        "\n"
+		        "  -c, --config=DIR              Read configuration options from DIR.\n"
+		        "  -D, --no-detach               Don't fork and detach.\n"
+		        "  -d, --debug[=LEVEL]           Increase debug level or set it to LEVEL.\n"
+		        "  -n, --net=NETNAME             Connect to net NETNAME.\n"
 #ifdef HAVE_MLOCKALL
-		       "  -L, --mlock                   Lock tinc into main memory.\n"
+		        "  -L, --mlock                   Lock tinc into main memory.\n"
 #endif
-		       "      --logfile[=FILENAME]      Write log entries to a logfile.\n"
-		       "  -s  --syslog                  Use syslog instead of stderr with --no-detach.\n"
-		       "      --pidfile=FILENAME        Write PID and control socket cookie to FILENAME.\n"
-		       "      --bypass-security         Disables meta protocol security, for debugging.\n"
-		       "  -o, --option[HOST.]KEY=VALUE  Set global/host configuration value.\n"
+		        "      --logfile[=FILENAME]      Write log entries to a logfile.\n"
+		        "  -s  --syslog                  Use syslog instead of stderr with --no-detach.\n"
+		        "      --pidfile=FILENAME        Write PID and control socket cookie to FILENAME.\n"
+		        "      --bypass-security         Disables meta protocol security, for debugging.\n"
+		        "  -o, --option[HOST.]KEY=VALUE  Set global/host configuration value.\n"
 #ifndef HAVE_MINGW
-		       "  -R, --chroot                  chroot to NET dir at startup.\n"
-		       "  -U, --user=USER               setuid to given USER at startup.\n"
+		        "  -R, --chroot                  chroot to NET dir at startup.\n"
+		        "  -U, --user=USER               setuid to given USER at startup.\n"
 #endif
-		       "      --help                    Display this help and exit.\n"
-		       "      --version                 Output version information and exit.\n\n");
-		printf("Report bugs to tinc@tinc-vpn.org.\n");
+		        "      --help                    Display this help and exit.\n"
+		        "      --version                 Output version information and exit.\n"
+		        "\n"
+		        "Report bugs to tinc@tinc-vpn.org.\n";
+
+		fprintf(stderr, message, program_name);
 	}
 }
 
@@ -378,7 +383,7 @@ static BOOL WINAPI console_ctrl_handler(DWORD type) {
 # define setpriority(level) (setpriority(PRIO_PROCESS, 0, (level)))
 #endif
 
-static void cleanup() {
+static void cleanup(void) {
 	splay_empty_tree(&config_tree);
 	list_empty_list(&cmdline_conf);
 	free_names();
@@ -392,49 +397,51 @@ int main(int argc, char **argv) {
 	}
 
 	if(show_version) {
-		printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
-		       BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
-		printf("Features:"
+		static const char *message =
+		        "%s version %s (built %s %s, protocol %d.%d)\n"
+		        "Features:"
 #ifdef HAVE_OPENSSL
-		       " openssl"
+		        " openssl"
 #endif
 #ifdef HAVE_LIBGCRYPT
-		       " libgcrypt"
+		        " libgcrypt"
 #endif
 #ifdef HAVE_LZO
-		       " comp_lzo"
+		        " comp_lzo"
 #endif
 #ifdef HAVE_ZLIB
-		       " comp_zlib"
+		        " comp_zlib"
 #endif
 #ifdef HAVE_LZ4
-		       " comp_lz4"
+		        " comp_lz4"
 #endif
 #ifndef DISABLE_LEGACY
-		       " legacy_protocol"
+		        " legacy_protocol"
 #endif
 #ifdef ENABLE_JUMBOGRAMS
-		       " jumbograms"
+		        " jumbograms"
 #endif
 #ifdef ENABLE_TUNEMU
-		       " tunemu"
+		        " tunemu"
 #endif
 #ifdef HAVE_MINIUPNPC
-		       " miniupnpc"
+		        " miniupnpc"
 #endif
 #ifdef ENABLE_UML
-		       " uml"
+		        " uml"
 #endif
 #ifdef ENABLE_VDE
-		       " vde"
+		        " vde"
 #endif
-		       "\n\n");
-		printf("Copyright (C) 1998-2021 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"
-		       "and you are welcome to redistribute it under certain conditions;\n"
-		       "see the file COPYING for details.\n");
+		        "\n\n"
+		        "Copyright (C) 1998-2021 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"
+		        "and you are welcome to redistribute it under certain conditions;\n"
+		        "see the file COPYING for details.\n";
 
+		printf(message, PACKAGE, BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
 		return 0;
 	}
 
@@ -446,7 +453,10 @@ int main(int argc, char **argv) {
 	make_names(true);
 	atexit(cleanup);
 
-	chdir(confbase);
+	if(chdir(confbase) == -1) {
+		logger(DEBUG_ALWAYS, LOG_ERR, "Could not change to configuration directory: %s", strerror(errno));
+		return 1;
+	}
 
 #ifdef HAVE_MINGW
 
@@ -601,7 +611,10 @@ int main2(int argc, char **argv) {
 	logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready");
 
 	if(umbilical) { // snip!
-		write(umbilical, "", 1);
+		if(write(umbilical, "", 1) != 1) {
+			// Pipe full or broken, nothing we can do about it.
+		}
+
 		close(umbilical);
 		umbilical = 0;
 	}
diff --git a/src/uml_device.c b/src/uml_device.c
index 970e462a..f35ae0d2 100644
--- a/src/uml_device.c
+++ b/src/uml_device.c
@@ -1,7 +1,7 @@
 /*
     device.c -- UML network socket
     Copyright (C) 2002-2005 Ivo Timmermans,
-                  2002-2017 Guus Sliepen <guus@tinc-vpn.org>
+                  2002-2022 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
@@ -163,7 +163,7 @@ static bool setup_device(void) {
 	return true;
 }
 
-void close_device(void) {
+static void close_device(void) {
 	if(listen_fd >= 0) {
 		close(listen_fd);
 		listen_fd = -1;
@@ -249,7 +249,12 @@ static bool read_packet(vpn_packet_t *packet) {
 			return false;
 		}
 
-		write(request_fd, &data_sun, sizeof(data_sun));
+		if(write(request_fd, &data_sun, sizeof(data_sun)) != sizeof(data_sun)) {
+			logger(DEBUG_ALWAYS, LOG_ERR, "Error while responding to request from %s %s: %s", device_info, device, strerror(errno));
+			event_exit();
+			return false;
+		}
+
 		device_fd = data_fd;
 
 		logger(DEBUG_ALWAYS, LOG_INFO, "Connection with UML established");
diff --git a/src/upnp.c b/src/upnp.c
index 93c207fa..eb68998b 100644
--- a/src/upnp.c
+++ b/src/upnp.c
@@ -1,6 +1,6 @@
 /*
     upnp.c -- UPnP-IGD client
-    Copyright (C) 2015-2018 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2015-2022 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
@@ -17,22 +17,20 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "upnp.h"
+#include "system.h"
 
-#ifndef HAVE_MINGW
 #include <pthread.h>
-#endif
 
 #include "miniupnpc/miniupnpc.h"
 #include "miniupnpc/upnpcommands.h"
 #include "miniupnpc/upnperrors.h"
 
-#include "system.h"
 #include "logger.h"
 #include "names.h"
 #include "net.h"
 #include "netutl.h"
 #include "utils.h"
+#include "upnp.h"
 
 static bool upnp_tcp;
 static bool upnp_udp;
@@ -107,7 +105,7 @@ static void upnp_add_mapping(struct UPNPUrls *urls, struct IGDdatas *data, const
 	free(port);
 }
 
-static void upnp_refresh() {
+static void upnp_refresh(void) {
 	logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Discovering IGD devices");
 
 	int error;
@@ -180,20 +178,10 @@ void upnp_init(bool tcp, bool udp) {
 	get_config_int(lookup_config(&config_tree, "UPnPDiscoverWait"), &upnp_discover_wait);
 	get_config_int(lookup_config(&config_tree, "UPnPRefreshPeriod"), &upnp_refresh_period);
 
-#ifdef HAVE_MINGW
-	HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)upnp_thread, NULL, 0, NULL);
-
-	if(!handle) {
-		logger(DEBUG_ALWAYS, LOG_ERR, "Unable to start UPnP-IGD client thread");
-	}
-
-#else
 	pthread_t thread;
 	int error = pthread_create(&thread, NULL, upnp_thread, NULL);
 
 	if(error) {
 		logger(DEBUG_ALWAYS, LOG_ERR, "Unable to start UPnP-IGD client thread: [%d] %s", error, strerror(error));
 	}
-
-#endif
 }
diff --git a/src/xoshiro.c b/src/xoshiro.c
index 469c74ab..481c2d52 100644
--- a/src/xoshiro.c
+++ b/src/xoshiro.c
@@ -6,7 +6,7 @@ worldwide. This software is distributed without any warranty.
 
 See <http://creativecommons.org/publicdomain/zero/1.0/>. */
 
-#include <stdint.h>
+#include "system.h"
 
 #include "crypto.h"