From nobody Sun Nov 13 05:38:02 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4N91SB6vTsz4hZQy; Sun, 13 Nov 2022 05:38:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4N91SB654Mz3JKc; Sun, 13 Nov 2022 05:38:02 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1668317882; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5kshnPQQbDaw00aNtDB0AF5GfiiRhlOJrVZSYJ5pvWw=; b=rXjrWatB7ZmB+Fm2JBeYoEOWcsCH9oLRM8/kv9dG0w4JhR2GepWOHbR0xxOh+tXU2l/XG8 0u2h8CoDnXbN8oXsw+WadOanqUb9Cqff1TBhDKXrfya7UYa0WZMKVBRcwXopBr7MD7Oiu7 Hnq4QcRjcT5px40y4NmEX5NVF5ttGE7+R/S/awuSko7r7j53YcT/IviuAHAcJXwxhkO/op NdePGAQ3uKHOqHJvEHTgQi9sr7mBWEOjodhYCYZZiwwSpr0DNZdilYTOhXtRrWNNjauBXV aSMZtzP9Gj1g4T+c4r64CiVeXrBflsgr+Sg+0XsFJw2l0ajvnkB5lRKFBC8shA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1668317882; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5kshnPQQbDaw00aNtDB0AF5GfiiRhlOJrVZSYJ5pvWw=; b=uBxa5ynkDIy+TWWhg2o+YHaESpx3ucs8obH45/FY2r9K/Hw4ClyxkWMdRYEDDJl0y++nR2 ls/1wHyFV6PbAKoS0ecARU9tlubGmsBEisnBXkTFJ39mMtwQCISV9Lpv7qwZBuBI234ZHQ WVi2LfACiXCmh196LJ1yKop3RHWbUOA6QuXRsoZfymjeraHXFcHFIbiuUVzq2smVeAGhYQ /g8iggcd2lvKW09ZsUSMRGL1HTTn7r826cMDyPRqyIj/6abxNBUjvoomVC6+P/cjBcA8Zq qS5U5ft2/NErR/z7TXSVkvbOW2dc34TZjwhVbJ4xTRdsPapVgi9SfNzj0bhMEQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1668317882; a=rsa-sha256; cv=none; b=vghCSLMysVppxN+YxA5cXX/rw38B+rb+tFVpqL+kmD+sVmgb/UdquEH550hGU+nxW+bfRf bJO8yAt97z+8+I91j7oq9EZ6uLnEOUTvdYdCNvEuwtTuRFkR5m5D28lUDuMmmdjPUrVzhu r7VmmsnSRI/96AAwQnelrX9PdZ2/reMD2eNUROpzNuw6X9+x0MYPG9AgPex2J5+IcKhUlt NKzj/dRBY16zwtap3zKJC5kiQ0ugTTj77WpuCKb0h/vEvzOLkFpTQFrvrKwO4V/vb3QSpJ Zeg0/N7q2AqOcqte57roek1CFojY2HcqQ1gXTepc1Xq7napR2V9sPsrtGRO6hg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4N91SB4tk4zrTG; Sun, 13 Nov 2022 05:38:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 2AD5c2aq096511; Sun, 13 Nov 2022 05:38:02 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 2AD5c2OS096510; Sun, 13 Nov 2022 05:38:02 GMT (envelope-from git) Date: Sun, 13 Nov 2022 05:38:02 GMT Message-Id: <202211130538.2AD5c2OS096510@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kyle Evans Subject: git: 919fc568b68f - stable/13 - Add 'contrib/wireguard-tools/' from commit '7e00bf8773b93a2a3ee28dba2710d2ae443989f1' List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 919fc568b68f4f68fe897eacdce7fc34bc646fe5 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=919fc568b68f4f68fe897eacdce7fc34bc646fe5 commit 919fc568b68f4f68fe897eacdce7fc34bc646fe5 Author: Kyle Evans AuthorDate: 2022-10-29 03:05:14 +0000 Commit: Kyle Evans 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 . All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 . All Rights Reserved. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include + +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 . All Rights Reserved. + */ + +#ifndef CONTAINERS_H +#define CONTAINERS_H + +#include +#include +#include +#include +#include +#include +#if defined(__linux__) +#include +#elif defined(__OpenBSD__) +#include +#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 . All Rights Reserved. + * + * Specialized constant-time ctype.h reimplementations that aren't locale-specific. + */ + +#ifndef CTYPE_H +#define CTYPE_H + +#include + +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 . All Rights Reserved. + * + * This is a machine-generated formally verified implementation of Curve25519 + * ECDH from: . 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 ***