svn commit: r368163 - in head: sbin/ifconfig sys/dev/if_wg sys/dev/if_wg/include sys/dev/if_wg/include/crypto sys/dev/if_wg/include/sys sys/dev/if_wg/include/zinc sys/dev/if_wg/module sys/dev/if_wg...

Matt Macy mmacy at FreeBSD.org
Sun Nov 29 19:38:05 UTC 2020


Author: mmacy
Date: Sun Nov 29 19:38:03 2020
New Revision: 368163
URL: https://svnweb.freebsd.org/changeset/base/368163

Log:
  Import kernel WireGuard support
  
  Data path largely shared with the OpenBSD implementation by
  Matt Dunwoodie <ncon at nconroy.net>
  
  Reviewed by:	grehan at freebsd.org
  MFC after:	1 month
  Sponsored by:	Rubicon LLC, (Netgate)
  Differential Revision:	https://reviews.freebsd.org/D26137

Added:
  head/sbin/ifconfig/ifwg.c   (contents, props changed)
  head/sys/dev/if_wg/
  head/sys/dev/if_wg/include/
  head/sys/dev/if_wg/include/crypto/blake2s.h   (contents, props changed)
  head/sys/dev/if_wg/include/crypto/curve25519.h   (contents, props changed)
  head/sys/dev/if_wg/include/crypto/zinc.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/
  head/sys/dev/if_wg/include/sys/if_wg_session.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/if_wg_session_vars.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/simd-x86_64.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/support.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/wg_cookie.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/wg_module.h   (contents, props changed)
  head/sys/dev/if_wg/include/sys/wg_noise.h   (contents, props changed)
  head/sys/dev/if_wg/include/zinc/blake2s.h   (contents, props changed)
  head/sys/dev/if_wg/include/zinc/chacha20.h   (contents, props changed)
  head/sys/dev/if_wg/include/zinc/chacha20poly1305.h   (contents, props changed)
  head/sys/dev/if_wg/include/zinc/curve25519.h   (contents, props changed)
  head/sys/dev/if_wg/include/zinc/poly1305.h   (contents, props changed)
  head/sys/dev/if_wg/module/
  head/sys/dev/if_wg/module/blake2s.c   (contents, props changed)
  head/sys/dev/if_wg/module/blake2s.h   (contents, props changed)
  head/sys/dev/if_wg/module/chacha20-x86_64.S   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-arm-glue.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-arm.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-arm64.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-mips-glue.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-mips.S   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-unrolled-arm.S   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-x86_64-glue.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20-x86_64.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/chacha20.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20poly1305.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-arm-glue.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-arm.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-arm64.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-donna32.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-donna64.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-mips-glue.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-mips.S   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-mips64.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-x86_64-glue.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305-x86_64.pl   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/poly1305.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/blake2s.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/chacha20.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/chacha20poly1305.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/curve25519.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/poly1305.c   (contents, props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/run.h   (contents, props changed)
  head/sys/dev/if_wg/module/curve25519.c   (contents, props changed)
  head/sys/dev/if_wg/module/if_wg_session.c   (contents, props changed)
  head/sys/dev/if_wg/module/module.c   (contents, props changed)
  head/sys/dev/if_wg/module/poly1305-x86_64.S   (contents, props changed)
  head/sys/dev/if_wg/module/wg_cookie.c   (contents, props changed)
  head/sys/dev/if_wg/module/wg_noise.c   (contents, props changed)
  head/sys/modules/if_wg/
  head/sys/modules/if_wg/Makefile   (contents, props changed)
Directory Properties:
  head/sys/dev/if_wg/include/crypto/   (props changed)
  head/sys/dev/if_wg/include/zinc/   (props changed)
  head/sys/dev/if_wg/module/crypto/   (props changed)
  head/sys/dev/if_wg/module/crypto/zinc/   (props changed)
  head/sys/dev/if_wg/module/crypto/zinc/chacha20/   (props changed)
  head/sys/dev/if_wg/module/crypto/zinc/poly1305/   (props changed)
  head/sys/dev/if_wg/module/crypto/zinc/selftest/   (props changed)
Modified:
  head/sbin/ifconfig/Makefile
  head/sys/kern/subr_gtaskqueue.c
  head/sys/modules/Makefile
  head/sys/net/iflib_clone.c
  head/sys/sys/gtaskqueue.h

Modified: head/sbin/ifconfig/Makefile
==============================================================================
--- head/sbin/ifconfig/Makefile	Sun Nov 29 19:06:32 2020	(r368162)
+++ head/sbin/ifconfig/Makefile	Sun Nov 29 19:38:03 2020	(r368163)
@@ -35,6 +35,7 @@ SRCS+=	ifvxlan.c		# VXLAN support
 SRCS+=	ifgre.c			# GRE keys etc
 SRCS+=	ifgif.c			# GIF reversed header workaround
 SRCS+=	ifipsec.c		# IPsec VTI
+SRCS+=	ifwg.c		# Wireguard
 
 SRCS+=	sfp.c			# SFP/SFP+ information
 LIBADD+=	ifconfig m util
@@ -68,6 +69,7 @@ CFLAGS+= -DINET
 CFLAGS+= -DJAIL
 LIBADD+=	jail
 .endif
+LIBADD+=	nv
 
 MAN=	ifconfig.8
 

Added: head/sbin/ifconfig/ifwg.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sbin/ifconfig/ifwg.c	Sun Nov 29 19:38:03 2020	(r368163)
@@ -0,0 +1,618 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef RESCUE
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/nv.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stddef.h>		/* NB: for offsetof */
+#include <locale.h>
+#include <langinfo.h>
+#include <resolv.h>
+
+#include "ifconfig.h"
+
+typedef enum {
+	WGC_GET = 0x5,
+	WGC_SET = 0x6,
+} wg_cmd_t;
+
+static nvlist_t *nvl_params;
+static bool do_peer;
+static int allowed_ips_count;
+static int allowed_ips_max;
+struct allowedip {
+	struct sockaddr_storage a_addr;
+	struct sockaddr_storage a_mask;
+};
+struct allowedip *allowed_ips;
+
+#define	ALLOWEDIPS_START 16
+#define	WG_KEY_LEN 32
+#define	WG_KEY_LEN_BASE64 ((((WG_KEY_LEN) + 2) / 3) * 4 + 1)
+#define	WG_KEY_LEN_HEX (WG_KEY_LEN * 2 + 1)
+#define	WG_MAX_STRLEN 64
+
+static bool
+key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
+{
+
+	if (strlen(base64) != WG_KEY_LEN_BASE64 - 1) {
+		warnx("bad key len - need %d got %zu\n", WG_KEY_LEN_BASE64 - 1, strlen(base64));
+		return false;
+	}
+	if (base64[WG_KEY_LEN_BASE64 - 2] != '=') {
+		warnx("bad key terminator, expected '=' got '%c'", base64[WG_KEY_LEN_BASE64 - 2]);
+		return false;
+	}
+	return (b64_pton(base64, key, WG_KEY_LEN));
+}
+
+static void
+parse_endpoint(const char *endpoint_)
+{
+	int err;
+	char *base, *endpoint, *port, *colon, *tmp;
+	struct addrinfo hints, *res;
+
+	endpoint = base = strdup(endpoint_);
+	colon = rindex(endpoint, ':');
+	if (colon == NULL)
+		errx(1, "bad endpoint format %s - no port delimiter found", endpoint);
+	*colon = '\0';
+	port = colon + 1;
+
+	/* [::]:<> */
+	if (endpoint[0] == '[') {
+		endpoint++;
+		tmp = index(endpoint, ']');
+		if (tmp == NULL)
+			errx(1, "bad endpoint format %s - '[' found with no matching ']'", endpoint);
+		*tmp = '\0';
+	}
+	bzero(&hints, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	err = getaddrinfo(endpoint, port, &hints, &res);
+	if (err)
+		errx(1, "%s", gai_strerror(err));
+	nvlist_add_binary(nvl_params, "endpoint", res->ai_addr, res->ai_addrlen);
+	freeaddrinfo(res);
+	free(base);
+}
+
+static void
+in_len2mask(struct in_addr *mask, u_int len)
+{
+	u_int i;
+	u_char *p;
+
+	p = (u_char *)mask;
+	memset(mask, 0, sizeof(*mask));
+	for (i = 0; i < len / NBBY; i++)
+		p[i] = 0xff;
+	if (len % NBBY)
+		p[i] = (0xff00 >> (len % NBBY)) & 0xff;
+}
+
+static u_int
+in_mask2len(struct in_addr *mask)
+{
+	u_int x, y;
+	u_char *p;
+
+	p = (u_char *)mask;
+	for (x = 0; x < sizeof(*mask); x++) {
+		if (p[x] != 0xff)
+			break;
+	}
+	y = 0;
+	if (x < sizeof(*mask)) {
+		for (y = 0; y < NBBY; y++) {
+			if ((p[x] & (0x80 >> y)) == 0)
+				break;
+		}
+	}
+	return x * NBBY + y;
+}
+
+static void
+in6_prefixlen2mask(struct in6_addr *maskp, int len)
+{
+	static const u_char maskarray[NBBY] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+	int bytelen, bitlen, i;
+
+	/* sanity check */
+	if (len < 0 || len > 128) {
+		errx(1, "in6_prefixlen2mask: invalid prefix length(%d)\n",
+		    len);
+		return;
+	}
+
+	memset(maskp, 0, sizeof(*maskp));
+	bytelen = len / NBBY;
+	bitlen = len % NBBY;
+	for (i = 0; i < bytelen; i++)
+		maskp->s6_addr[i] = 0xff;
+	if (bitlen)
+		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
+}
+
+static int
+in6_mask2len(struct in6_addr *mask, u_char *lim0)
+{
+	int x = 0, y;
+	u_char *lim = lim0, *p;
+
+	/* ignore the scope_id part */
+	if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
+		lim = (u_char *)mask + sizeof(*mask);
+	for (p = (u_char *)mask; p < lim; x++, p++) {
+		if (*p != 0xff)
+			break;
+	}
+	y = 0;
+	if (p < lim) {
+		for (y = 0; y < NBBY; y++) {
+			if ((*p & (0x80 >> y)) == 0)
+				break;
+		}
+	}
+
+	/*
+	 * when the limit pointer is given, do a stricter check on the
+	 * remaining bits.
+	 */
+	if (p < lim) {
+		if (y != 0 && (*p & (0x00ff >> y)) != 0)
+			return -1;
+		for (p = p + 1; p < lim; p++)
+			if (*p != 0)
+				return -1;
+	}
+
+	return x * NBBY + y;
+}
+
+static bool
+parse_ip(struct allowedip *aip, const char *value)
+{
+	struct addrinfo hints, *res;
+	int err;
+
+	bzero(&aip->a_addr, sizeof(aip->a_addr));
+	bzero(&hints, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_flags = AI_NUMERICHOST;
+	err = getaddrinfo(value, NULL, &hints, &res);
+	if (err)
+		errx(1, "%s", gai_strerror(err));
+
+	memcpy(&aip->a_addr, res->ai_addr, res->ai_addrlen);
+
+	freeaddrinfo(res);
+	return (true);
+}
+
+static void
+sa_ntop(const struct sockaddr *sa, char *buf, int *port)
+{
+	const struct sockaddr_in *sin;
+	const struct sockaddr_in6 *sin6;
+	int err;
+
+	err = getnameinfo(sa, sa->sa_len, buf, INET6_ADDRSTRLEN, NULL,
+	    0, NI_NUMERICHOST);
+
+	if (sa->sa_family == AF_INET) {
+		sin = (const struct sockaddr_in *)sa;
+		if (port)
+			*port = sin->sin_port;
+	} else if (sa->sa_family == AF_INET6) {
+		sin6 = (const struct sockaddr_in6 *)sa;
+		if (port)
+			*port = sin6->sin6_port;
+	}
+
+	if (err)
+		errx(1, "%s", gai_strerror(err));
+}
+
+static void
+dump_peer(const nvlist_t *nvl_peer)
+{
+	const void *key;
+	const struct allowedip *aips;
+	const struct sockaddr *endpoint;
+	char outbuf[WG_MAX_STRLEN];
+	char addr_buf[INET6_ADDRSTRLEN];
+	size_t size;
+	int count, port;
+
+	printf("[Peer]\n");
+	if (nvlist_exists_binary(nvl_peer, "public-key")) {
+		key = nvlist_get_binary(nvl_peer, "public-key", &size);
+		b64_ntop((const uint8_t *)key, size, outbuf, WG_MAX_STRLEN);
+		printf("PublicKey = %s\n", outbuf);
+	}
+	if (nvlist_exists_binary(nvl_peer, "endpoint")) {
+		endpoint = nvlist_get_binary(nvl_peer, "endpoint", &size);
+		sa_ntop(endpoint, addr_buf, &port);
+		printf("Endpoint = %s:%d\n", addr_buf, ntohs(port));
+	}
+
+	if (!nvlist_exists_binary(nvl_peer, "allowed-ips"))
+		return;
+	aips = nvlist_get_binary(nvl_peer, "allowed-ips", &size);
+	if (size == 0 || size % sizeof(struct allowedip) != 0) {
+		errx(1, "size %zu not integer multiple of allowedip", size);
+	}
+	printf("AllowedIPs = ");
+	count = size / sizeof(struct allowedip);
+	for (int i = 0; i < count; i++) {
+		int mask;
+		sa_family_t family;
+		void *bitmask;
+		struct sockaddr *sa;
+
+		sa = __DECONST(void *, &aips[i].a_addr);
+		bitmask = __DECONST(void *,
+		    ((const struct sockaddr *)&aips->a_mask)->sa_data);
+		family = aips[i].a_addr.ss_family;
+		getnameinfo(sa, sa->sa_len, addr_buf, INET6_ADDRSTRLEN, NULL,
+		    0, NI_NUMERICHOST);
+		if (family == AF_INET)
+			mask = in_mask2len(bitmask);
+		else if (family == AF_INET6)
+			mask = in6_mask2len(bitmask, NULL);
+		else
+			errx(1, "bad family in peer %d\n", family);
+		printf("%s/%d", addr_buf, mask);
+		if (i < count -1)
+			printf(", ");
+	}
+	printf("\n");
+}
+
+static int
+get_nvl_out_size(int sock, u_long op, size_t *size)
+{
+	struct ifdrv ifd;
+	int err;
+
+	memset(&ifd, 0, sizeof(ifd));
+
+	strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name));
+	ifd.ifd_cmd = op;
+	ifd.ifd_len = 0;
+	ifd.ifd_data = NULL;
+
+	err = ioctl(sock, SIOCGDRVSPEC, &ifd);
+	if (err)
+		return (err);
+	*size = ifd.ifd_len;
+	return (0);
+}
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+	struct ifdrv ifd;
+
+	memset(&ifd, 0, sizeof(ifd));
+
+	strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name));
+	ifd.ifd_cmd = op;
+	ifd.ifd_len = argsize;
+	ifd.ifd_data = arg;
+
+	return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static
+DECL_CMD_FUNC(peerlist, val, d)
+{
+	size_t size, peercount;
+	void *packed;
+	const nvlist_t *nvl, *nvl_peer;
+	const nvlist_t *const *nvl_peerlist;
+
+	if (get_nvl_out_size(s, WGC_GET, &size))
+		errx(1, "can't get peer list size");
+	if ((packed = malloc(size)) == NULL)
+		errx(1, "malloc failed for peer list");
+	if (do_cmd(s, WGC_GET, packed, size, 0))
+		errx(1, "failed to obtain peer list");
+
+	nvl = nvlist_unpack(packed, size, 0);
+	if (!nvlist_exists_nvlist_array(nvl, "peer-list"))
+		return;
+	nvl_peerlist = nvlist_get_nvlist_array(nvl, "peer-list", &peercount);
+
+	for (int i = 0; i < peercount; i++, nvl_peerlist++) {
+		nvl_peer = *nvl_peerlist;
+		dump_peer(nvl_peer);
+	}
+}
+
+static void
+peerfinish(int s, void *arg)
+{
+	nvlist_t *nvl, **nvl_array;
+	void *packed;
+	size_t size;
+
+	if ((nvl = nvlist_create(0)) == NULL)
+		errx(1, "failed to allocate nvlist");
+	if ((nvl_array = calloc(sizeof(void *), 1)) == NULL)
+		errx(1, "failed to allocate nvl_array");
+	if (!nvlist_exists_binary(nvl_params, "public-key"))
+		errx(1, "must specify a public-key for adding peer");
+	if (!nvlist_exists_binary(nvl_params, "endpoint"))
+		errx(1, "must specify an endpoint for adding peer");
+	if (allowed_ips_count == 0)
+		errx(1, "must specify at least one range of allowed-ips to add a peer");
+
+	nvl_array[0] = nvl_params;
+	nvlist_add_nvlist_array(nvl, "peer-list", (const nvlist_t * const *)nvl_array, 1);
+	packed = nvlist_pack(nvl, &size);
+
+	if (do_cmd(s, WGC_SET, packed, size, true))
+		errx(1, "failed to install peer");
+}
+
+static
+DECL_CMD_FUNC(peerstart, val, d)
+{
+	do_peer = true;
+	callback_register(peerfinish, NULL);
+	allowed_ips = malloc(ALLOWEDIPS_START * sizeof(struct allowedip));
+	allowed_ips_max = ALLOWEDIPS_START;
+	if (allowed_ips == NULL)
+		errx(1, "failed to allocate array for allowedips");
+}
+
+static
+DECL_CMD_FUNC(setwglistenport, val, d)
+{
+	struct addrinfo hints, *res;
+	const struct sockaddr_in *sin;
+	const struct sockaddr_in6 *sin6;
+
+	u_long ul;
+	int err;
+
+	bzero(&hints, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_flags = AI_NUMERICHOST;
+	err = getaddrinfo(NULL, val, &hints, &res);
+	if (err)
+		errx(1, "%s", gai_strerror(err));
+
+	if (res->ai_family == AF_INET) {
+		sin = (struct sockaddr_in *)res->ai_addr;
+		ul = sin->sin_port;
+	} else if (res->ai_family == AF_INET6) {
+		sin6 = (struct sockaddr_in6 *)res->ai_addr;
+		ul = sin6->sin6_port;
+	} else {
+		errx(1, "unknown family");
+	}
+	ul = ntohs((u_short)ul);
+	nvlist_add_number(nvl_params, "listen-port", ul);
+}
+
+static
+DECL_CMD_FUNC(setwgprivkey, val, d)
+{
+	uint8_t key[WG_KEY_LEN];
+
+	if (!key_from_base64(key, val))
+		errx(1, "invalid key %s", val);
+	nvlist_add_binary(nvl_params, "private-key", key, WG_KEY_LEN);
+}
+
+static
+DECL_CMD_FUNC(setwgpubkey, val, d)
+{
+	uint8_t key[WG_KEY_LEN];
+
+	if (!do_peer)
+		errx(1, "setting public key only valid when adding peer");
+
+	if (!key_from_base64(key, val))
+		errx(1, "invalid key %s", val);
+	nvlist_add_binary(nvl_params, "public-key", key, WG_KEY_LEN);
+}
+
+static
+DECL_CMD_FUNC(setallowedips, val, d)
+{
+	char *base, *allowedip, *mask;
+	u_long ul;
+	char *endp;
+	struct allowedip *aip;
+
+	if (!do_peer)
+		errx(1, "setting allowed ip only valid when adding peer");
+	if (allowed_ips_count == allowed_ips_max) {
+		/* XXX grow array */
+	}
+	aip = &allowed_ips[allowed_ips_count];
+	base = allowedip = strdup(val);
+	mask = index(allowedip, '/');
+	if (mask == NULL)
+		errx(1, "mask separator not found in allowedip %s", val);
+	*mask = '\0';
+	mask++;
+	parse_ip(aip, allowedip);
+	ul = strtoul(mask, &endp, 0);
+	if (*endp != '\0')
+		errx(1, "invalid value for allowedip mask");
+	bzero(&aip->a_mask, sizeof(aip->a_mask));
+	if (aip->a_addr.ss_family == AF_INET)
+		in_len2mask((struct in_addr *)&((struct sockaddr *)&aip->a_mask)->sa_data, ul);
+	else if (aip->a_addr.ss_family == AF_INET6)
+		in6_prefixlen2mask((struct in6_addr *)&((struct sockaddr *)&aip->a_mask)->sa_data, ul);
+	else
+		errx(1, "invalid address family %d\n", aip->a_addr.ss_family);
+	allowed_ips_count++;
+	if (allowed_ips_count > 1)
+		nvlist_free_binary(nvl_params, "allowed-ips");
+	nvlist_add_binary(nvl_params, "allowed-ips", allowed_ips,
+					  allowed_ips_count*sizeof(*aip));
+
+	dump_peer(nvl_params);
+	free(base);
+}
+
+static
+DECL_CMD_FUNC(setendpoint, val, d)
+{
+	if (!do_peer)
+		errx(1, "setting endpoint only valid when adding peer");
+	parse_endpoint(val);
+}
+
+static void
+wireguard_status(int s)
+{
+	size_t size;
+	void *packed;
+	nvlist_t *nvl;
+	char buf[WG_KEY_LEN_BASE64];
+	const void *key;
+	uint16_t listen_port;
+
+	if (get_nvl_out_size(s, WGC_GET, &size))
+		return;
+	if ((packed = malloc(size)) == NULL)
+		return;
+	if (do_cmd(s, WGC_GET, packed, size, 0))
+		return;
+	nvl = nvlist_unpack(packed, size, 0);
+	if (nvlist_exists_number(nvl, "listen-port")) {
+		listen_port = nvlist_get_number(nvl, "listen-port");
+		printf("\tlisten-port: %d\n", listen_port);
+	}
+	if (nvlist_exists_binary(nvl, "private-key")) {
+		key = nvlist_get_binary(nvl, "private-key", &size);
+		b64_ntop((const uint8_t *)key, size, buf, WG_MAX_STRLEN);
+		printf("\tprivate-key: %s\n", buf);
+	}
+	if (nvlist_exists_binary(nvl, "public-key")) {
+		key = nvlist_get_binary(nvl, "public-key", &size);
+		b64_ntop((const uint8_t *)key, size, buf, WG_MAX_STRLEN);
+		printf("\tpublic-key:  %s\n", buf);
+	}
+}
+
+static struct cmd wireguard_cmds[] = {
+    DEF_CLONE_CMD_ARG("listen-port",  setwglistenport),
+    DEF_CLONE_CMD_ARG("private-key",  setwgprivkey),
+    DEF_CMD("peer-list",  0, peerlist),
+    DEF_CMD("peer",  0, peerstart),
+    DEF_CMD_ARG("public-key",  setwgpubkey),
+    DEF_CMD_ARG("allowed-ips",  setallowedips),
+    DEF_CMD_ARG("endpoint",  setendpoint),
+};
+
+static struct afswtch af_wireguard = {
+	.af_name	= "af_wireguard",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = wireguard_status,
+};
+
+static void
+wg_create(int s, struct ifreq *ifr)
+{
+	struct iovec iov;
+	void *packed;
+	size_t size;
+
+	setproctitle("ifconfig %s create ...\n", name);
+	if (!nvlist_exists_number(nvl_params, "listen-port"))
+		goto legacy;
+	if (!nvlist_exists_binary(nvl_params, "private-key"))
+		goto legacy;
+
+	packed = nvlist_pack(nvl_params, &size);
+	if (packed == NULL)
+		errx(1, "failed to setup create request");
+	iov.iov_len = size;
+	iov.iov_base = packed;
+	ifr->ifr_data = (caddr_t)&iov;
+	if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+		err(1, "SIOCIFCREATE2");
+	return;
+legacy:
+	ifr->ifr_data == NULL;
+	if (ioctl(s, SIOCIFCREATE, ifr) < 0)
+		err(1, "SIOCIFCREATE");
+}
+
+static __constructor void
+wireguard_ctor(void)
+{
+	int i;
+
+	nvl_params = nvlist_create(0);
+	for (i = 0; i < nitems(wireguard_cmds);  i++)
+		cmd_register(&wireguard_cmds[i]);
+	af_register(&af_wireguard);
+	clone_setdefcallback_prefix("wg", wg_create);
+}
+
+#endif

Added: head/sys/dev/if_wg/include/crypto/blake2s.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/if_wg/include/crypto/blake2s.h	Sun Nov 29 19:38:03 2020	(r368163)
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason at zx2c4.com>. All Rights Reserved.
+ */
+
+#include <sys/types.h>
+
+#ifndef _BLAKE2S_H_
+#define _BLAKE2S_H_
+
+
+enum blake2s_lengths {
+	BLAKE2S_BLOCK_SIZE = 64,
+	BLAKE2S_HASH_SIZE = 32,
+	BLAKE2S_KEY_SIZE = 32
+};
+
+struct blake2s_state {
+	uint32_t h[8];
+	uint32_t t[2];
+	uint32_t f[2];
+	uint8_t buf[BLAKE2S_BLOCK_SIZE];
+	size_t buflen;
+	uint8_t last_node;
+};
+
+void blake2s_init(struct blake2s_state *state, const size_t outlen);
+void blake2s_init_key(struct blake2s_state *state, const size_t outlen,
+		      const void *key, const size_t keylen);
+void blake2s_update(struct blake2s_state *state, const uint8_t *in, size_t inlen);
+void blake2s_final(struct blake2s_state *state, uint8_t *out, const size_t outlen);
+
+static inline void blake2s(uint8_t *out, const uint8_t *in, const uint8_t *key,
+			   const size_t outlen, const size_t inlen,
+			   const size_t keylen)
+{
+	struct blake2s_state state;
+#ifdef __linux___
+	WARN_ON(IS_ENABLED(DEBUG) && ((!in && inlen > 0) || !out || !outlen ||
+		outlen > BLAKE2S_HASH_SIZE || keylen > BLAKE2S_KEY_SIZE ||
+		(!key && keylen)));
+#endif
+
+	if (keylen)
+		blake2s_init_key(&state, outlen, key, keylen);
+	else
+		blake2s_init(&state, outlen);
+
+	blake2s_update(&state, in, inlen);
+	blake2s_final(&state, out, outlen);
+}
+
+void blake2s_hmac(uint8_t *out, const uint8_t *in, const uint8_t *key,
+		const size_t outlen, const size_t inlen, const size_t keylen);
+
+#endif /* _BLAKE2S_H_ */

Added: head/sys/dev/if_wg/include/crypto/curve25519.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/if_wg/include/crypto/curve25519.h	Sun Nov 29 19:38:03 2020	(r368163)
@@ -0,0 +1,74 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019-2020 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CURVE25519_H_
+#define _CURVE25519_H_
+
+#include <sys/systm.h>
+
+#define CURVE25519_KEY_SIZE 32
+
+void curve25519_generic(u8 [CURVE25519_KEY_SIZE],
+			const u8 [CURVE25519_KEY_SIZE],
+			const u8 [CURVE25519_KEY_SIZE]);
+
+static inline void curve25519_clamp_secret(u8 secret[CURVE25519_KEY_SIZE])
+{
+	secret[0] &= 248;
+	secret[31] = (secret[31] & 127) | 64;
+}
+
+static const u8 null_point[CURVE25519_KEY_SIZE] = { 0 };
+
+static inline int curve25519(u8 mypublic[CURVE25519_KEY_SIZE],
+		const u8 secret[CURVE25519_KEY_SIZE],
+		const u8 basepoint[CURVE25519_KEY_SIZE])
+{
+	curve25519_generic(mypublic, secret, basepoint);
+	return timingsafe_bcmp(mypublic, null_point, CURVE25519_KEY_SIZE);
+}
+
+static inline int curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE],
+				const u8 secret[CURVE25519_KEY_SIZE])
+{
+	static const u8 basepoint[CURVE25519_KEY_SIZE] __aligned(32) = { 9 };
+
+	if (timingsafe_bcmp(secret, null_point, CURVE25519_KEY_SIZE) == 0)
+		return 0;
+
+	return curve25519(pub, secret, basepoint);
+}
+
+static inline void curve25519_generate_secret(u8 secret[CURVE25519_KEY_SIZE])
+{
+	arc4random_buf(secret, CURVE25519_KEY_SIZE);
+	curve25519_clamp_secret(secret);
+}
+
+#endif /* _CURVE25519_H_ */

Added: head/sys/dev/if_wg/include/crypto/zinc.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/if_wg/include/crypto/zinc.h	Sun Nov 29 19:38:03 2020	(r368163)
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason at zx2c4.com>. All Rights Reserved.
+ */
+
+#ifndef _WG_ZINC_H
+#define _WG_ZINC_H
+
+int chacha20_mod_init(void);
+int poly1305_mod_init(void);
+int chacha20poly1305_mod_init(void);
+int blake2s_mod_init(void);
+int curve25519_mod_init(void);
+
+#endif

Added: head/sys/dev/if_wg/include/sys/if_wg_session.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/if_wg/include/sys/if_wg_session.h	Sun Nov 29 19:38:03 2020	(r368163)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 Matt Dunwoodie <ncon at noconroy.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __IF_WG_H__
+#define __IF_WG_H__
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+/*
+ * This is the public interface to the WireGuard network interface.
+ *
+ * It is designed to be used by tools such as ifconfig(8) and wg(4).
+ */
+
+#define WG_KEY_SIZE 32
+
+#define WG_DEVICE_HAS_PUBKEY		(1 << 0)
+#define WG_DEVICE_HAS_PRIVKEY		(1 << 1)
+#define WG_DEVICE_HAS_MASKED_PRIVKEY	(1 << 2)
+#define WG_DEVICE_HAS_PORT		(1 << 3)
+#define WG_DEVICE_HAS_RDOMAIN		(1 << 4)
+#define WG_DEVICE_REPLACE_PEERS		(1 << 5)
+
+#define WG_PEER_HAS_PUBKEY		(1 << 0)
+#define WG_PEER_HAS_SHAREDKEY		(1 << 1)
+#define WG_PEER_HAS_MASKED_SHAREDKEY	(1 << 2)
+#define WG_PEER_HAS_ENDPOINT		(1 << 3)
+#define WG_PEER_HAS_PERSISTENTKEEPALIVE	(1 << 4)
+#define WG_PEER_REPLACE_CIDRS		(1 << 5)
+#define WG_PEER_REMOVE			(1 << 6)
+
+#define SIOCSWG _IOWR('i', 200, struct wg_device_io)
+#define SIOCGWG _IOWR('i', 201, struct wg_device_io)
+
+#define WG_PEERS_FOREACH(p, d) \
+	for (p = (d)->d_peers; p < (d)->d_peers + (d)->d_num_peers; p++)
+#define WG_CIDRS_FOREACH(c, p) \
+	for (c = (p)->p_cidrs; c < (p)->p_cidrs + (p)->p_num_cidrs; c++)
+
+struct wg_allowedip {
+	struct sockaddr_storage a_addr;
+	struct sockaddr_storage a_mask;
+};
+
+enum {
+	WG_PEER_CTR_TX_BYTES,
+	WG_PEER_CTR_RX_BYTES,
+	WG_PEER_CTR_NUM,
+};
+
+struct wg_device_io {
+	char			 d_name[IFNAMSIZ];
+	uint8_t			 d_flags;
+	in_port_t		 d_port;
+	int			 d_rdomain;
+	uint8_t			 d_pubkey[WG_KEY_SIZE];
+	uint8_t			 d_privkey[WG_KEY_SIZE];
+	size_t			 d_num_peers;
+	size_t			 d_num_cidrs;
+	struct wg_peer_io	*d_peers;
+};
+
+
+#ifndef ENOKEY
+#define	ENOKEY	ENOTCAPABLE
+#endif
+
+typedef enum {
+	WGC_GET = 0x5,
+	WGC_SET = 0x6,
+} wg_cmd_t;
+
+#endif /* __IF_WG_H__ */

Added: head/sys/dev/if_wg/include/sys/if_wg_session_vars.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/if_wg/include/sys/if_wg_session_vars.h	Sun Nov 29 19:38:03 2020	(r368163)
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2019 Matt Dunwoodie <ncon at noconroy.net>
+ * Copyright (c) 2019-2020 Rubicon Communications, LLC (Netgate)
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_WG_VARS_H_
+#define _IF_WG_VARS_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <crypto/siphash/siphash.h>
+
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <net/pfvar.h>
+#include <net/iflib.h>
+
+#include <sys/wg_noise.h>
+#include <sys/wg_cookie.h>
+/* This is only needed for wg_keypair. */
+#include <sys/if_wg_session.h>
+
+#define UNIMPLEMENTED() panic("%s not implemented\n", __func__)
+
+#define WG_KEY_SIZE		 	32
+#define WG_MSG_PADDING_SIZE 		16
+
+
+/* Constant for session */
+#define REKEY_TIMEOUT			5
+#define REKEY_TIMEOUT_JITTER		500 /* TODO ok? jason */
+#define REJECT_AFTER_TIME		180
+#define KEEPALIVE_TIMEOUT		10
+#define MAX_TIMER_HANDSHAKES		(90 / REKEY_TIMEOUT)
+#define NEW_HANDSHAKE_TIMEOUT		(REKEY_TIMEOUT + KEEPALIVE_TIMEOUT)
+
+#define MAX_QUEUED_INCOMING_HANDSHAKES	4096 /* TODO: replace this with DQL */
+#define MAX_QUEUED_PACKETS		1024 /* TODO: replace this with DQL */
+
+#define HASHTABLE_PEER_SIZE		(1 << 6)			//1 << 11
+#define HASHTABLE_INDEX_SIZE		(HASHTABLE_PEER_SIZE * 3)	//1 << 13
+
+#define PEER_MAGIC1	0xCAFEBABEB00FDADDULL
+#define PEER_MAGIC2	0xCAAFD0D0D00DBABEULL
+#define PEER_MAGIC3	0xD00DBABEF00DFADEULL
+
+
+enum message_type {
+	MESSAGE_INVALID = 0,
+	MESSAGE_HANDSHAKE_INITIATION = 1,
+	MESSAGE_HANDSHAKE_RESPONSE = 2,
+	MESSAGE_HANDSHAKE_COOKIE = 3,
+	MESSAGE_DATA = 4
+};
+
+struct wg_softc;
+
+#if __FreeBSD_version > 1300000
+typedef void timeout_t (void *);
+#endif
+
+/* Socket */
+struct wg_endpoint {
+	union wg_remote {
+		struct sockaddr		r_sa;
+		struct sockaddr_in	r_sin;
+		struct sockaddr_in6	r_sin6;
+	} e_remote;
+	union wg_source {
+		struct in_addr		l_in;
+		struct in6_pktinfo	l_pktinfo6;
+#define l_in6 l_pktinfo6.ipi6_addr
+	} e_local;
+};
+
+struct wg_socket {
+	struct mtx	 so_mtx;
+	in_port_t	 so_port;
+	struct socket	*so_so4;
+	struct socket	*so_so6;
+};
+
+struct wg_queue {
+	struct mtx			q_mtx;
+	struct mbufq			q;
+};
+
+struct wg_index {
+	LIST_ENTRY(wg_index)	 i_entry;
+	SLIST_ENTRY(wg_index)	 i_unused_entry;
+	uint32_t		 i_key;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list