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 <n...@nconroy.net> Reviewed by: gre...@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 <ja...@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 <ja...@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 <n...@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 <n...@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 *** _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"