On Sun, 29 Nov 2020 19:38:04 +0000 (UTC) Matt Macy <mm...@freebsd.org> wrote:
> 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" "make installkernel" fails for me in a non-DEBUG environment with the error shown below. Recent CURRENT source tree is r368226, failing systems are running at r368055 or r368226. [...] ===> i2c/cyapa (install) --- realinstall_subdir_if_wg --- install -T dbg -o root -g wheel -m 555 if_wg.ko.debug /usr/lib/debug/boot/kernel/ install: /usr/lib/debug/boot/kernel/: No such file or directory --- realinstall_subdir_iflib --- --- _kmodinstall --- --- realinstall_subdir_if_wg --- *** [_kmodinstall] Error code 71 make[4]: stopped in /usr/src/sys/modules/if_wg 1 error make[4]: stopped in /usr/src/sys/modules/if_wg --- realinstall_subdir_iflib --- install -T release -o root -g wheel -m 555 iflib.ko /boot/kernel/ --- realinstall_subdir_if_wg --- --- realinstall_subdir_geom --- --- realinstall_subdir_iflib --- --- realinstall_subdir_i2c --- *** [modules-install] Error code 2 [...] _______________________________________________ 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"