git: 919fc568b68f - stable/13 - Add 'contrib/wireguard-tools/' from commit '7e00bf8773b93a2a3ee28dba2710d2ae443989f1'
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 13 Nov 2022 05:38:02 UTC
The branch stable/13 has been updated by kevans:
URL: https://cgit.FreeBSD.org/src/commit/?id=919fc568b68f4f68fe897eacdce7fc34bc646fe5
commit 919fc568b68f4f68fe897eacdce7fc34bc646fe5
Author: Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2022-10-29 03:05:14 +0000
Commit: Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2022-11-13 05:37:05 +0000
Add 'contrib/wireguard-tools/' from commit '7e00bf8773b93a2a3ee28dba2710d2ae443989f1'
git-subtree-dir: contrib/wireguard-tools
git-subtree-mainline: 9142a2a37b2fe65d46ace08a098ad26b8ff81541
git-subtree-split: 7e00bf8773b93a2a3ee28dba2710d2ae443989f1
(cherry picked from commit adf376485712c8fffbf3be330d505a969647f479)
---
contrib/wireguard-tools/.gitignore | 16 +
contrib/wireguard-tools/config.c | 650 +++++++++++++++++++++
contrib/wireguard-tools/config.h | 27 +
contrib/wireguard-tools/containers.h | 107 ++++
contrib/wireguard-tools/ctype.h | 29 +
contrib/wireguard-tools/curve25519-fiat32.h | 860 ++++++++++++++++++++++++++++
contrib/wireguard-tools/curve25519-hacl64.h | 784 +++++++++++++++++++++++++
contrib/wireguard-tools/curve25519.c | 98 ++++
contrib/wireguard-tools/curve25519.h | 24 +
contrib/wireguard-tools/encoding.c | 125 ++++
contrib/wireguard-tools/encoding.h | 24 +
contrib/wireguard-tools/genkey.c | 99 ++++
contrib/wireguard-tools/ipc-freebsd.h | 350 +++++++++++
contrib/wireguard-tools/ipc-uapi-unix.h | 119 ++++
contrib/wireguard-tools/ipc-uapi.h | 297 ++++++++++
contrib/wireguard-tools/ipc.c | 98 ++++
contrib/wireguard-tools/ipc.h | 17 +
contrib/wireguard-tools/man/wg.8 | 258 +++++++++
contrib/wireguard-tools/pubkey.c | 50 ++
contrib/wireguard-tools/set.c | 41 ++
contrib/wireguard-tools/setconf.c | 156 +++++
contrib/wireguard-tools/show.c | 454 +++++++++++++++
contrib/wireguard-tools/showconf.c | 103 ++++
contrib/wireguard-tools/subcommands.h | 17 +
contrib/wireguard-tools/terminal.c | 76 +++
contrib/wireguard-tools/terminal.h | 51 ++
contrib/wireguard-tools/version.h | 3 +
contrib/wireguard-tools/wg.c | 66 +++
28 files changed, 4999 insertions(+)
diff --git a/contrib/wireguard-tools/.gitignore b/contrib/wireguard-tools/.gitignore
new file mode 100644
index 000000000000..4343ea95a0a2
--- /dev/null
+++ b/contrib/wireguard-tools/.gitignore
@@ -0,0 +1,16 @@
+# GPL-2.0, not used on FreeBSD:
+Makefile
+completion
+fuzz/
+ipc-uapi-windows.h
+ipc-windows.h
+netlink.h
+uapi/
+wg-quick/
+wincompat/
+
+# License OK, but not needed for FreeBSD
+ipc-linux.h
+ipc-openbsd.h
+man/wg-quick.8
+systemd/
diff --git a/contrib/wireguard-tools/config.c b/contrib/wireguard-tools/config.c
new file mode 100644
index 000000000000..81ccb479c367
--- /dev/null
+++ b/contrib/wireguard-tools/config.c
@@ -0,0 +1,650 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#include <arpa/inet.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "config.h"
+#include "containers.h"
+#include "ipc.h"
+#include "encoding.h"
+#include "ctype.h"
+
+#define COMMENT_CHAR '#'
+
+static const char *get_value(const char *line, const char *key)
+{
+ size_t linelen = strlen(line);
+ size_t keylen = strlen(key);
+
+ if (keylen >= linelen)
+ return NULL;
+
+ if (strncasecmp(line, key, keylen))
+ return NULL;
+
+ return line + keylen;
+}
+
+static inline bool parse_port(uint16_t *port, uint32_t *flags, const char *value)
+{
+ int ret;
+ struct addrinfo *resolved;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_protocol = IPPROTO_UDP,
+ .ai_flags = AI_PASSIVE
+ };
+
+ if (!strlen(value)) {
+ fprintf(stderr, "Unable to parse empty port\n");
+ return false;
+ }
+
+ ret = getaddrinfo(NULL, value, &hints, &resolved);
+ if (ret) {
+ fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value);
+ return false;
+ }
+
+ ret = -1;
+ if (resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) {
+ *port = ntohs(((struct sockaddr_in *)resolved->ai_addr)->sin_port);
+ ret = 0;
+ } else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)) {
+ *port = ntohs(((struct sockaddr_in6 *)resolved->ai_addr)->sin6_port);
+ ret = 0;
+ } else
+ fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s'\n", value);
+
+ freeaddrinfo(resolved);
+ if (!ret)
+ *flags |= WGDEVICE_HAS_LISTEN_PORT;
+ return ret == 0;
+}
+
+static inline bool parse_fwmark(uint32_t *fwmark, uint32_t *flags, const char *value)
+{
+ unsigned long ret;
+ char *end;
+ int base = 10;
+
+ if (!strcasecmp(value, "off")) {
+ *fwmark = 0;
+ *flags |= WGDEVICE_HAS_FWMARK;
+ return true;
+ }
+
+ if (!char_is_digit(value[0]))
+ goto err;
+
+ if (strlen(value) > 2 && value[0] == '0' && value[1] == 'x')
+ base = 16;
+
+ ret = strtoul(value, &end, base);
+ if (*end || ret > UINT32_MAX)
+ goto err;
+
+ *fwmark = ret;
+ *flags |= WGDEVICE_HAS_FWMARK;
+ return true;
+err:
+ fprintf(stderr, "Fwmark is neither 0/off nor 0-0xffffffff: `%s'\n", value);
+ return false;
+}
+
+static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
+{
+ if (!key_from_base64(key, value)) {
+ fprintf(stderr, "Key is not the correct length or format: `%s'\n", value);
+ memset(key, 0, WG_KEY_LEN);
+ return false;
+ }
+ return true;
+}
+
+static bool parse_keyfile(uint8_t key[static WG_KEY_LEN], const char *path)
+{
+ FILE *f;
+ int c;
+ char dst[WG_KEY_LEN_BASE64];
+ bool ret = false;
+
+ f = fopen(path, "r");
+ if (!f) {
+ perror("fopen");
+ return false;
+ }
+
+ if (fread(dst, WG_KEY_LEN_BASE64 - 1, 1, f) != 1) {
+ /* If we're at the end and we didn't read anything, we're /dev/null or an empty file. */
+ if (!ferror(f) && feof(f) && !ftell(f)) {
+ memset(key, 0, WG_KEY_LEN);
+ ret = true;
+ goto out;
+ }
+
+ fprintf(stderr, "Invalid length key in key file\n");
+ goto out;
+ }
+ dst[WG_KEY_LEN_BASE64 - 1] = '\0';
+
+ while ((c = getc(f)) != EOF) {
+ if (!char_is_space(c)) {
+ fprintf(stderr, "Found trailing character in key file: `%c'\n", c);
+ goto out;
+ }
+ }
+ if (ferror(f) && errno) {
+ perror("getc");
+ goto out;
+ }
+ ret = parse_key(key, dst);
+
+out:
+ fclose(f);
+ return ret;
+}
+
+static inline bool parse_ip(struct wgallowedip *allowedip, const char *value)
+{
+ allowedip->family = AF_UNSPEC;
+ if (strchr(value, ':')) {
+ if (inet_pton(AF_INET6, value, &allowedip->ip6) == 1)
+ allowedip->family = AF_INET6;
+ } else {
+ if (inet_pton(AF_INET, value, &allowedip->ip4) == 1)
+ allowedip->family = AF_INET;
+ }
+ if (allowedip->family == AF_UNSPEC) {
+ fprintf(stderr, "Unable to parse IP address: `%s'\n", value);
+ return false;
+ }
+ return true;
+}
+
+static inline int parse_dns_retries(void)
+{
+ unsigned long ret;
+ char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end;
+
+ if (!retries)
+ return 15;
+ if (!strcmp(retries, "infinity"))
+ return -1;
+
+ ret = strtoul(retries, &end, 10);
+ if (*end || ret > INT_MAX) {
+ fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries);
+ exit(1);
+ }
+ return (int)ret;
+}
+
+static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value)
+{
+ char *mutable = strdup(value);
+ char *begin, *end;
+ int ret, retries = parse_dns_retries();
+ struct addrinfo *resolved;
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_protocol = IPPROTO_UDP
+ };
+ if (!mutable) {
+ perror("strdup");
+ return false;
+ }
+ if (!strlen(value)) {
+ free(mutable);
+ fprintf(stderr, "Unable to parse empty endpoint\n");
+ return false;
+ }
+ if (mutable[0] == '[') {
+ begin = &mutable[1];
+ end = strchr(mutable, ']');
+ if (!end) {
+ free(mutable);
+ fprintf(stderr, "Unable to find matching brace of endpoint: `%s'\n", value);
+ return false;
+ }
+ *end++ = '\0';
+ if (*end++ != ':' || !*end) {
+ free(mutable);
+ fprintf(stderr, "Unable to find port of endpoint: `%s'\n", value);
+ return false;
+ }
+ } else {
+ begin = mutable;
+ end = strrchr(mutable, ':');
+ if (!end || !*(end + 1)) {
+ free(mutable);
+ fprintf(stderr, "Unable to find port of endpoint: `%s'\n", value);
+ return false;
+ }
+ *end++ = '\0';
+ }
+
+ #define min(a, b) ((a) < (b) ? (a) : (b))
+ for (unsigned int timeout = 1000000;; timeout = min(20000000, timeout * 6 / 5)) {
+ ret = getaddrinfo(begin, end, &hints, &resolved);
+ if (!ret)
+ break;
+ /* The set of return codes that are "permanent failures". All other possibilities are potentially transient.
+ *
+ * This is according to https://sourceware.org/glibc/wiki/NameResolver which states:
+ * "From the perspective of the application that calls getaddrinfo() it perhaps
+ * doesn't matter that much since EAI_FAIL, EAI_NONAME and EAI_NODATA are all
+ * permanent failure codes and the causes are all permanent failures in the
+ * sense that there is no point in retrying later."
+ *
+ * So this is what we do, except FreeBSD removed EAI_NODATA some time ago, so that's conditional.
+ */
+ if (ret == EAI_NONAME || ret == EAI_FAIL ||
+ #ifdef EAI_NODATA
+ ret == EAI_NODATA ||
+ #endif
+ (retries >= 0 && !retries--)) {
+ free(mutable);
+ fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value);
+ return false;
+ }
+ fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value, timeout / 1000000.0);
+ usleep(timeout);
+ }
+
+ if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
+ (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
+ memcpy(endpoint, resolved->ai_addr, resolved->ai_addrlen);
+ else {
+ freeaddrinfo(resolved);
+ free(mutable);
+ fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s'\n", value);
+ return false;
+ }
+ freeaddrinfo(resolved);
+ free(mutable);
+ return true;
+}
+
+static inline bool parse_persistent_keepalive(uint16_t *interval, uint32_t *flags, const char *value)
+{
+ unsigned long ret;
+ char *end;
+
+ if (!strcasecmp(value, "off")) {
+ *interval = 0;
+ *flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
+ return true;
+ }
+
+ if (!char_is_digit(value[0]))
+ goto err;
+
+ ret = strtoul(value, &end, 10);
+ if (*end || ret > 65535)
+ goto err;
+
+ *interval = (uint16_t)ret;
+ *flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
+ return true;
+err:
+ fprintf(stderr, "Persistent keepalive interval is neither 0/off nor 1-65535: `%s'\n", value);
+ return false;
+}
+
+static bool validate_netmask(struct wgallowedip *allowedip)
+{
+ uint32_t *ip;
+ int last;
+
+ switch (allowedip->family) {
+ case AF_INET:
+ last = 0;
+ ip = (uint32_t *)&allowedip->ip4;
+ break;
+ case AF_INET6:
+ last = 3;
+ ip = (uint32_t *)&allowedip->ip6;
+ break;
+ default:
+ return true; /* We don't know how to validate it, so say 'okay'. */
+ }
+
+ for (int i = last; i >= 0; --i) {
+ uint32_t mask = ~0;
+
+ if (allowedip->cidr >= 32 * (i + 1))
+ break;
+ if (allowedip->cidr > 32 * i)
+ mask >>= (allowedip->cidr - 32 * i);
+ if (ntohl(ip[i]) & mask)
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **last_allowedip, const char *value)
+{
+ struct wgallowedip *allowedip = *last_allowedip, *new_allowedip;
+ char *mask, *mutable = strdup(value), *sep, *saved_entry;
+
+ if (!mutable) {
+ perror("strdup");
+ return false;
+ }
+ peer->flags |= WGPEER_REPLACE_ALLOWEDIPS;
+ if (!strlen(value)) {
+ free(mutable);
+ return true;
+ }
+ sep = mutable;
+ while ((mask = strsep(&sep, ","))) {
+ unsigned long cidr;
+ char *end, *ip;
+
+ saved_entry = strdup(mask);
+ ip = strsep(&mask, "/");
+
+ new_allowedip = calloc(1, sizeof(*new_allowedip));
+ if (!new_allowedip) {
+ perror("calloc");
+ free(saved_entry);
+ free(mutable);
+ return false;
+ }
+
+ if (!parse_ip(new_allowedip, ip)) {
+ free(new_allowedip);
+ free(saved_entry);
+ free(mutable);
+ return false;
+ }
+
+ if (mask) {
+ if (!char_is_digit(mask[0]))
+ goto err;
+ cidr = strtoul(mask, &end, 10);
+ if (*end || (cidr > 32 && new_allowedip->family == AF_INET) || (cidr > 128 && new_allowedip->family == AF_INET6))
+ goto err;
+ } else if (new_allowedip->family == AF_INET)
+ cidr = 32;
+ else if (new_allowedip->family == AF_INET6)
+ cidr = 128;
+ else
+ goto err;
+ new_allowedip->cidr = cidr;
+
+ if (!validate_netmask(new_allowedip))
+ fprintf(stderr, "Warning: AllowedIP has nonzero host part: %s/%s\n", ip, mask);
+
+ if (allowedip)
+ allowedip->next_allowedip = new_allowedip;
+ else
+ peer->first_allowedip = new_allowedip;
+ allowedip = new_allowedip;
+ free(saved_entry);
+ }
+ free(mutable);
+ *last_allowedip = allowedip;
+ return true;
+
+err:
+ free(new_allowedip);
+ free(mutable);
+ fprintf(stderr, "AllowedIP is not in the correct format: `%s'\n", saved_entry);
+ free(saved_entry);
+ return false;
+}
+
+static bool process_line(struct config_ctx *ctx, const char *line)
+{
+ const char *value;
+ bool ret = true;
+
+ if (!strcasecmp(line, "[Interface]")) {
+ ctx->is_peer_section = false;
+ ctx->is_device_section = true;
+ return true;
+ }
+ if (!strcasecmp(line, "[Peer]")) {
+ struct wgpeer *new_peer = calloc(1, sizeof(struct wgpeer));
+
+ if (!new_peer) {
+ perror("calloc");
+ return false;
+ }
+ ctx->last_allowedip = NULL;
+ if (ctx->last_peer)
+ ctx->last_peer->next_peer = new_peer;
+ else
+ ctx->device->first_peer = new_peer;
+ ctx->last_peer = new_peer;
+ ctx->is_peer_section = true;
+ ctx->is_device_section = false;
+ ctx->last_peer->flags |= WGPEER_REPLACE_ALLOWEDIPS;
+ return true;
+ }
+
+#define key_match(key) (value = get_value(line, key "="))
+
+ if (ctx->is_device_section) {
+ if (key_match("ListenPort"))
+ ret = parse_port(&ctx->device->listen_port, &ctx->device->flags, value);
+ else if (key_match("FwMark"))
+ ret = parse_fwmark(&ctx->device->fwmark, &ctx->device->flags, value);
+ else if (key_match("PrivateKey")) {
+ ret = parse_key(ctx->device->private_key, value);
+ if (ret)
+ ctx->device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
+ } else
+ goto error;
+ } else if (ctx->is_peer_section) {
+ if (key_match("Endpoint"))
+ ret = parse_endpoint(&ctx->last_peer->endpoint.addr, value);
+ else if (key_match("PublicKey")) {
+ ret = parse_key(ctx->last_peer->public_key, value);
+ if (ret)
+ ctx->last_peer->flags |= WGPEER_HAS_PUBLIC_KEY;
+ } else if (key_match("AllowedIPs"))
+ ret = parse_allowedips(ctx->last_peer, &ctx->last_allowedip, value);
+ else if (key_match("PersistentKeepalive"))
+ ret = parse_persistent_keepalive(&ctx->last_peer->persistent_keepalive_interval, &ctx->last_peer->flags, value);
+ else if (key_match("PresharedKey")) {
+ ret = parse_key(ctx->last_peer->preshared_key, value);
+ if (ret)
+ ctx->last_peer->flags |= WGPEER_HAS_PRESHARED_KEY;
+ } else
+ goto error;
+ } else
+ goto error;
+ return ret;
+
+#undef key_match
+
+error:
+ fprintf(stderr, "Line unrecognized: `%s'\n", line);
+ return false;
+}
+
+bool config_read_line(struct config_ctx *ctx, const char *input)
+{
+ size_t len, cleaned_len = 0;
+ char *line, *comment;
+ bool ret = true;
+
+ /* This is what strchrnul is for, but that isn't portable. */
+ comment = strchr(input, COMMENT_CHAR);
+ if (comment)
+ len = comment - input;
+ else
+ len = strlen(input);
+
+ line = calloc(len + 1, sizeof(char));
+ if (!line) {
+ perror("calloc");
+ ret = false;
+ goto out;
+ }
+
+ for (size_t i = 0; i < len; ++i) {
+ if (!char_is_space(input[i]))
+ line[cleaned_len++] = input[i];
+ }
+ if (!cleaned_len)
+ goto out;
+ ret = process_line(ctx, line);
+out:
+ free(line);
+ if (!ret)
+ free_wgdevice(ctx->device);
+ return ret;
+}
+
+bool config_read_init(struct config_ctx *ctx, bool append)
+{
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->device = calloc(1, sizeof(*ctx->device));
+ if (!ctx->device) {
+ perror("calloc");
+ return false;
+ }
+ if (!append)
+ ctx->device->flags |= WGDEVICE_REPLACE_PEERS | WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_FWMARK | WGDEVICE_HAS_LISTEN_PORT;
+ return true;
+}
+
+struct wgdevice *config_read_finish(struct config_ctx *ctx)
+{
+ struct wgpeer *peer;
+
+ for_each_wgpeer(ctx->device, peer) {
+ if (!(peer->flags & WGPEER_HAS_PUBLIC_KEY)) {
+ fprintf(stderr, "A peer is missing a public key\n");
+ goto err;
+ }
+ }
+ return ctx->device;
+err:
+ free_wgdevice(ctx->device);
+ return NULL;
+}
+
+static char *strip_spaces(const char *in)
+{
+ char *out;
+ size_t t, l, i;
+
+ t = strlen(in);
+ out = calloc(t + 1, sizeof(char));
+ if (!out) {
+ perror("calloc");
+ return NULL;
+ }
+ for (i = 0, l = 0; i < t; ++i) {
+ if (!char_is_space(in[i]))
+ out[l++] = in[i];
+ }
+ return out;
+}
+
+struct wgdevice *config_read_cmd(const char *argv[], int argc)
+{
+ struct wgdevice *device = calloc(1, sizeof(*device));
+ struct wgpeer *peer = NULL;
+ struct wgallowedip *allowedip = NULL;
+
+ if (!device) {
+ perror("calloc");
+ return false;
+ }
+ while (argc > 0) {
+ if (!strcmp(argv[0], "listen-port") && argc >= 2 && !peer) {
+ if (!parse_port(&device->listen_port, &device->flags, argv[1]))
+ goto error;
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "fwmark") && argc >= 2 && !peer) {
+ if (!parse_fwmark(&device->fwmark, &device->flags, argv[1]))
+ goto error;
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "private-key") && argc >= 2 && !peer) {
+ if (!parse_keyfile(device->private_key, argv[1]))
+ goto error;
+ device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "peer") && argc >= 2) {
+ struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
+
+ allowedip = NULL;
+ if (!new_peer) {
+ perror("calloc");
+ goto error;
+ }
+ if (peer)
+ peer->next_peer = new_peer;
+ else
+ device->first_peer = new_peer;
+ peer = new_peer;
+ if (!parse_key(peer->public_key, argv[1]))
+ goto error;
+ peer->flags |= WGPEER_HAS_PUBLIC_KEY;
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "remove") && argc >= 1 && peer) {
+ peer->flags |= WGPEER_REMOVE_ME;
+ argv += 1;
+ argc -= 1;
+ } else if (!strcmp(argv[0], "endpoint") && argc >= 2 && peer) {
+ if (!parse_endpoint(&peer->endpoint.addr, argv[1]))
+ goto error;
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "allowed-ips") && argc >= 2 && peer) {
+ char *line = strip_spaces(argv[1]);
+
+ if (!line)
+ goto error;
+ if (!parse_allowedips(peer, &allowedip, line)) {
+ free(line);
+ goto error;
+ }
+ free(line);
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "persistent-keepalive") && argc >= 2 && peer) {
+ if (!parse_persistent_keepalive(&peer->persistent_keepalive_interval, &peer->flags, argv[1]))
+ goto error;
+ argv += 2;
+ argc -= 2;
+ } else if (!strcmp(argv[0], "preshared-key") && argc >= 2 && peer) {
+ if (!parse_keyfile(peer->preshared_key, argv[1]))
+ goto error;
+ peer->flags |= WGPEER_HAS_PRESHARED_KEY;
+ argv += 2;
+ argc -= 2;
+ } else {
+ fprintf(stderr, "Invalid argument: %s\n", argv[0]);
+ goto error;
+ }
+ }
+ return device;
+error:
+ free_wgdevice(device);
+ return false;
+}
diff --git a/contrib/wireguard-tools/config.h b/contrib/wireguard-tools/config.h
new file mode 100644
index 000000000000..443cf2147446
--- /dev/null
+++ b/contrib/wireguard-tools/config.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <stdbool.h>
+
+struct wgdevice;
+struct wgpeer;
+struct wgallowedip;
+
+struct config_ctx {
+ struct wgdevice *device;
+ struct wgpeer *last_peer;
+ struct wgallowedip *last_allowedip;
+ bool is_peer_section, is_device_section;
+};
+
+struct wgdevice *config_read_cmd(const char *argv[], int argc);
+bool config_read_init(struct config_ctx *ctx, bool append);
+bool config_read_line(struct config_ctx *ctx, const char *line);
+struct wgdevice *config_read_finish(struct config_ctx *ctx);
+
+#endif
diff --git a/contrib/wireguard-tools/containers.h b/contrib/wireguard-tools/containers.h
new file mode 100644
index 000000000000..a82e8ddee46a
--- /dev/null
+++ b/contrib/wireguard-tools/containers.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#ifndef CONTAINERS_H
+#define CONTAINERS_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#if defined(__linux__)
+#include <linux/wireguard.h>
+#elif defined(__OpenBSD__)
+#include <net/if_wg.h>
+#endif
+
+#ifndef WG_KEY_LEN
+#define WG_KEY_LEN 32
+#endif
+
+/* Cross platform __kernel_timespec */
+struct timespec64 {
+ int64_t tv_sec;
+ int64_t tv_nsec;
+};
+
+struct wgallowedip {
+ uint16_t family;
+ union {
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ };
+ uint8_t cidr;
+ struct wgallowedip *next_allowedip;
+};
+
+enum {
+ WGPEER_REMOVE_ME = 1U << 0,
+ WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
+ WGPEER_HAS_PUBLIC_KEY = 1U << 2,
+ WGPEER_HAS_PRESHARED_KEY = 1U << 3,
+ WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
+};
+
+struct wgpeer {
+ uint32_t flags;
+
+ uint8_t public_key[WG_KEY_LEN];
+ uint8_t preshared_key[WG_KEY_LEN];
+
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } endpoint;
+
+ struct timespec64 last_handshake_time;
+ uint64_t rx_bytes, tx_bytes;
+ uint16_t persistent_keepalive_interval;
+
+ struct wgallowedip *first_allowedip, *last_allowedip;
+ struct wgpeer *next_peer;
+};
+
+enum {
+ WGDEVICE_REPLACE_PEERS = 1U << 0,
+ WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
+ WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
+ WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
+ WGDEVICE_HAS_FWMARK = 1U << 4
+};
+
+struct wgdevice {
+ char name[IFNAMSIZ];
+ uint32_t ifindex;
+
+ uint32_t flags;
+
+ uint8_t public_key[WG_KEY_LEN];
+ uint8_t private_key[WG_KEY_LEN];
+
+ uint32_t fwmark;
+ uint16_t listen_port;
+
+ struct wgpeer *first_peer, *last_peer;
+};
+
+#define for_each_wgpeer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
+#define for_each_wgallowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
+
+static inline void free_wgdevice(struct wgdevice *dev)
+{
+ if (!dev)
+ return;
+ for (struct wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer; peer = np, np = peer ? peer->next_peer : NULL) {
+ for (struct wgallowedip *allowedip = peer->first_allowedip, *na = allowedip ? allowedip->next_allowedip : NULL; allowedip; allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
+ free(allowedip);
+ free(peer);
+ }
+ free(dev);
+}
+
+#endif
diff --git a/contrib/wireguard-tools/ctype.h b/contrib/wireguard-tools/ctype.h
new file mode 100644
index 000000000000..7c9942c29265
--- /dev/null
+++ b/contrib/wireguard-tools/ctype.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * Specialized constant-time ctype.h reimplementations that aren't locale-specific.
+ */
+
+#ifndef CTYPE_H
+#define CTYPE_H
+
+#include <stdbool.h>
+
+static inline bool char_is_space(int c)
+{
+ unsigned char d = c - 9;
+ return (0x80001FU >> (d & 31)) & (1U >> (d >> 5));
+}
+
+static inline bool char_is_digit(int c)
+{
+ return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1);
+}
+
+static inline bool char_is_alpha(int c)
+{
+ return (unsigned int)(('a' - 1 - (c | 32)) & ((c | 32) - ('z' + 1))) >> (sizeof(c) * 8 - 1);
+}
+
+#endif
diff --git a/contrib/wireguard-tools/curve25519-fiat32.h b/contrib/wireguard-tools/curve25519-fiat32.h
new file mode 100644
index 000000000000..66f3309c8d88
--- /dev/null
+++ b/contrib/wireguard-tools/curve25519-fiat32.h
@@ -0,0 +1,860 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2015-2016 The fiat-crypto Authors.
+ * Copyright (C) 2018-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * This is a machine-generated formally verified implementation of Curve25519
+ * ECDH from: <https://github.com/mit-plv/fiat-crypto>. Though originally
+ * machine generated, it has been tweaked to be suitable for use in the kernel.
+ * It is optimized for 32-bit machines and machines that cannot work efficiently
+ * with 128-bit integer types.
+ */
+
+/* fe means field element. Here the field is \Z/(2^255-19). An element t,
+ * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+ * t[3]+2^102 t[4]+...+2^230 t[9].
+ * fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc.
+ * Multiplication and carrying produce fe from fe_loose.
+ */
+typedef struct fe { u32 v[10]; } fe;
+
+/* fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc
+ * Addition and subtraction produce fe_loose from (fe, fe).
+ */
+typedef struct fe_loose { u32 v[10]; } fe_loose;
+
+static __always_inline void fe_frombytes_impl(u32 h[10], const u8 *s)
+{
+ /* Ignores top bit of s. */
+ u32 a0 = get_unaligned_le32(s);
+ u32 a1 = get_unaligned_le32(s+4);
+ u32 a2 = get_unaligned_le32(s+8);
+ u32 a3 = get_unaligned_le32(s+12);
+ u32 a4 = get_unaligned_le32(s+16);
+ u32 a5 = get_unaligned_le32(s+20);
+ u32 a6 = get_unaligned_le32(s+24);
+ u32 a7 = get_unaligned_le32(s+28);
+ h[0] = a0&((1<<26)-1); /* 26 used, 32-26 left. 26 */
+ h[1] = (a0>>26) | ((a1&((1<<19)-1))<< 6); /* (32-26) + 19 = 6+19 = 25 */
+ h[2] = (a1>>19) | ((a2&((1<<13)-1))<<13); /* (32-19) + 13 = 13+13 = 26 */
+ h[3] = (a2>>13) | ((a3&((1<< 6)-1))<<19); /* (32-13) + 6 = 19+ 6 = 25 */
+ h[4] = (a3>> 6); /* (32- 6) = 26 */
+ h[5] = a4&((1<<25)-1); /* 25 */
+ h[6] = (a4>>25) | ((a5&((1<<19)-1))<< 7); /* (32-25) + 19 = 7+19 = 26 */
+ h[7] = (a5>>19) | ((a6&((1<<12)-1))<<13); /* (32-19) + 12 = 13+12 = 25 */
+ h[8] = (a6>>12) | ((a7&((1<< 6)-1))<<20); /* (32-12) + 6 = 20+ 6 = 26 */
+ h[9] = (a7>> 6)&((1<<25)-1); /* 25 */
+}
+
+static __always_inline void fe_frombytes(fe *h, const u8 *s)
+{
+ fe_frombytes_impl(h->v, s);
+}
+
+static __always_inline u8 /*bool*/
+addcarryx_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
+{
+ /* This function extracts 25 bits of result and 1 bit of carry
+ * (26 total), so a 32-bit intermediate is sufficient.
+ */
+ u32 x = a + b + c;
+ *low = x & ((1 << 25) - 1);
+ return (x >> 25) & 1;
+}
+
+static __always_inline u8 /*bool*/
+addcarryx_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
+{
+ /* This function extracts 26 bits of result and 1 bit of carry
+ * (27 total), so a 32-bit intermediate is sufficient.
+ */
+ u32 x = a + b + c;
+ *low = x & ((1 << 26) - 1);
+ return (x >> 26) & 1;
+}
+
*** 4227 LINES SKIPPED ***