git: 74ae3f3e33b8 - main - if_wg: import latest fixup work from the wireguard-freebsd project

Kevin Bowling kevin.bowling at kev009.com
Mon Mar 15 17:49:05 UTC 2021


Isn't this the quintessential candidate for Phabricator?  By your own
commit message this is code with lots of security implications.  It
also has (had? depending on how this goes) corporate stewardship that
should be given some chance to participate.  If it isn't going to re@
in time for 13.0 anyway, it does feel like an awful lot of theatrics
to get in some unnecessary passive aggressiveness.  You're going about
it in a strange way to first accuse the original of being a rush job
and unfit, to immediately heroing it without review like this and
expecting assumptions of good faith.  My 2c based on recent reviews
discussion.

On Sun, Mar 14, 2021 at 9:53 PM Kyle Evans <kevans at freebsd.org> wrote:
>
> The branch main has been updated by kevans:
>
> URL: https://cgit.FreeBSD.org/src/commit/?id=74ae3f3e33b810248da19004c58b3581cd367843
>
> commit 74ae3f3e33b810248da19004c58b3581cd367843
> Author:     Kyle Evans <kevans at FreeBSD.org>
> AuthorDate: 2021-03-15 02:25:40 +0000
> Commit:     Kyle Evans <kevans at FreeBSD.org>
> CommitDate: 2021-03-15 04:52:04 +0000
>
>     if_wg: import latest fixup work from the wireguard-freebsd project
>
>     This is the culmination of about a week of work from three developers to
>     fix a number of functional and security issues.  This patch consists of
>     work done by the following folks:
>
>     - Jason A. Donenfeld <Jason at zx2c4.com>
>     - Matt Dunwoodie <ncon at noconroy.net>
>     - Kyle Evans <kevans at FreeBSD.org>
>
>     Notable changes include:
>     - Packets are now correctly staged for processing once the handshake has
>       completed, resulting in less packet loss in the interim.
>     - Various race conditions have been resolved, particularly w.r.t. socket
>       and packet lifetime (panics)
>     - Various tests have been added to assure correct functionality and
>       tooling conformance
>     - Many security issues have been addressed
>     - if_wg now maintains jail-friendly semantics: sockets are created in
>       the interface's home vnet so that it can act as the sole network
>       connection for a jail
>     - if_wg no longer fails to remove peer allowed-ips of 0.0.0.0/0
>     - if_wg now exports via ioctl a format that is future proof and
>       complete.  It is additionally supported by the upstream
>       wireguard-tools (which we plan to merge in to base soon)
>     - if_wg now conforms to the WireGuard protocol and is more closely
>       aligned with security auditing guidelines
>
>     Note that the driver has been rebased away from using iflib.  iflib
>     poses a number of challenges for a cloned device trying to operate in a
>     vnet that are non-trivial to solve and adds complexity to the
>     implementation for little gain.
>
>     The crypto implementation that was previously added to the tree was a
>     super complex integration of what previously appeared in an old out of
>     tree Linux module, which has been reduced to crypto.c containing simple
>     boring reference implementations.  This is part of a near-to-mid term
>     goal to work with FreeBSD kernel crypto folks and take advantage of or
>     improve accelerated crypto already offered elsewhere.
>
>     There's additional test suite effort underway out-of-tree taking
>     advantage of the aforementioned jail-friendly semantics to test a number
>     of real-world topologies, based on netns.sh.
>
>     Also note that this is still a work in progress; work going further will
>     be much smaller in nature.
>
>     MFC after:      1 month (maybe)
> ---
>  etc/mtree/BSD.include.dist                         |    2 +
>  include/Makefile                                   |    9 +-
>  sbin/ifconfig/ifwg.c                               |  395 +-
>  share/man/man4/wg.4                                |   26 +-
>  sys/dev/if_wg/crypto.c                             | 1705 ++++
>  sys/dev/if_wg/crypto.h                             |  114 +
>  sys/dev/if_wg/if_wg.c                              | 3454 ++++++++
>  sys/dev/if_wg/if_wg.h                              |   36 +
>  sys/dev/if_wg/include/crypto/blake2s.h             |   56 -
>  sys/dev/if_wg/include/crypto/curve25519.h          |   74 -
>  sys/dev/if_wg/include/crypto/zinc.h                |   15 -
>  sys/dev/if_wg/include/sys/if_wg_session.h          |   89 -
>  sys/dev/if_wg/include/sys/if_wg_session_vars.h     |  319 -
>  sys/dev/if_wg/include/sys/simd-x86_64.h            |   74 -
>  sys/dev/if_wg/include/sys/support.h                |  342 -
>  sys/dev/if_wg/include/sys/wg_module.h              |  121 -
>  sys/dev/if_wg/include/sys/wg_noise.h               |  286 -
>  sys/dev/if_wg/include/zinc/blake2s.h               |   50 -
>  sys/dev/if_wg/include/zinc/chacha20.h              |   68 -
>  sys/dev/if_wg/include/zinc/chacha20poly1305.h      |   48 -
>  sys/dev/if_wg/include/zinc/curve25519.h            |   28 -
>  sys/dev/if_wg/include/zinc/poly1305.h              |   29 -
>  sys/dev/if_wg/module/blake2s.c                     |  256 -
>  sys/dev/if_wg/module/blake2s.h                     |   58 -
>  sys/dev/if_wg/module/chacha20-x86_64.S             | 2834 -------
>  .../crypto/zinc/chacha20/chacha20-arm-glue.c       |   98 -
>  .../module/crypto/zinc/chacha20/chacha20-arm.pl    | 1227 ---
>  .../module/crypto/zinc/chacha20/chacha20-arm64.pl  | 1163 ---
>  .../crypto/zinc/chacha20/chacha20-mips-glue.c      |   27 -
>  .../module/crypto/zinc/chacha20/chacha20-mips.S    |  424 -
>  .../crypto/zinc/chacha20/chacha20-x86_64-glue.c    |  132 -
>  .../module/crypto/zinc/chacha20/chacha20-x86_64.pl | 4106 ----------
>  .../if_wg/module/crypto/zinc/chacha20/chacha20.c   |  238 -
>  .../if_wg/module/crypto/zinc/chacha20poly1305.c    |  196 -
>  .../crypto/zinc/poly1305/poly1305-arm-glue.c       |  140 -
>  .../module/crypto/zinc/poly1305/poly1305-arm.pl    | 1276 ---
>  .../module/crypto/zinc/poly1305/poly1305-arm64.pl  |  974 ---
>  .../module/crypto/zinc/poly1305/poly1305-donna32.c |  205 -
>  .../module/crypto/zinc/poly1305/poly1305-donna64.c |  182 -
>  .../crypto/zinc/poly1305/poly1305-mips-glue.c      |   37 -
>  .../module/crypto/zinc/poly1305/poly1305-mips.S    |  407 -
>  .../module/crypto/zinc/poly1305/poly1305-mips64.pl |  467 --
>  .../crypto/zinc/poly1305/poly1305-x86_64-glue.c    |  171 -
>  .../module/crypto/zinc/poly1305/poly1305-x86_64.pl | 4266 ----------
>  .../if_wg/module/crypto/zinc/poly1305/poly1305.c   |  163 -
>  .../if_wg/module/crypto/zinc/selftest/blake2s.c    | 2090 -----
>  .../if_wg/module/crypto/zinc/selftest/chacha20.c   | 2703 -------
>  .../module/crypto/zinc/selftest/chacha20poly1305.c | 8443 --------------------
>  .../if_wg/module/crypto/zinc/selftest/curve25519.c | 1315 ---
>  .../if_wg/module/crypto/zinc/selftest/poly1305.c   | 1110 ---
>  sys/dev/if_wg/module/crypto/zinc/selftest/run.h    |   43 -
>  sys/dev/if_wg/module/curve25519.c                  |  867 --
>  sys/dev/if_wg/module/if_wg_session.c               | 1984 -----
>  sys/dev/if_wg/module/module.c                      |  954 ---
>  sys/dev/if_wg/module/poly1305-x86_64.S             | 3021 -------
>  sys/dev/if_wg/support.h                            |   56 +
>  sys/dev/if_wg/{module => }/wg_cookie.c             |  105 +-
>  sys/dev/if_wg/{include/sys => }/wg_cookie.h        |   81 +-
>  sys/dev/if_wg/{module => }/wg_noise.c              |  409 +-
>  sys/dev/if_wg/wg_noise.h                           |  191 +
>  sys/kern/kern_jail.c                               |    1 +
>  sys/kern/uipc_socket.c                             |   11 +
>  sys/kern/uipc_syscalls.c                           |    4 +-
>  sys/modules/if_wg/Makefile                         |   30 +-
>  sys/net/if_types.h                                 |    1 +
>  sys/netinet6/nd6.c                                 |    4 +-
>  sys/sys/priv.h                                     |    1 +
>  sys/sys/socketvar.h                                |    1 +
>  tests/sys/netinet/Makefile                         |   10 +-
>  tests/sys/netinet/if_wg_test.sh                    |  188 +
>  70 files changed, 6333 insertions(+), 43677 deletions(-)
>
> diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist
> index e7784cbb0a47..0f85798815d5 100644
> --- a/etc/mtree/BSD.include.dist
> +++ b/etc/mtree/BSD.include.dist
> @@ -64,6 +64,8 @@
>          ..
>          iicbus
>          ..
> +        if_wg
> +        ..
>          io
>          ..
>          mfi
> diff --git a/include/Makefile b/include/Makefile
> index 3a34ddb8aa18..31e207f6b199 100644
> --- a/include/Makefile
> +++ b/include/Makefile
> @@ -44,7 +44,7 @@ LDIRS=        bsm cam geom net net80211 netgraph netinet netinet6 \
>  LSUBDIRS=      cam/ata cam/mmc cam/nvme cam/scsi \
>         dev/acpica dev/agp dev/an dev/ciss dev/filemon dev/firewire \
>         dev/hwpmc dev/hyperv \
> -       dev/ic dev/iicbus dev/io dev/mfi dev/mmc dev/nvme \
> +       dev/ic dev/iicbus dev/if_wg dev/io dev/mfi dev/mmc dev/nvme \
>         dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/pwm \
>         dev/smbus dev/speaker dev/tcp_log dev/veriexec dev/vkbd \
>         fs/devfs fs/fdescfs fs/msdosfs fs/nfs fs/nullfs \
> @@ -170,6 +170,10 @@ NVPAIRDIR= ${INCLUDEDIR}/sys
>  MLX5=          mlx5io.h
>  MLX5DIR=       ${INCLUDEDIR}/dev/mlx5
>
> +.PATH: ${SRCTOP}/sys/dev/if_wg
> +WG=            if_wg.h
> +WGDIR=         ${INCLUDEDIR}/dev/if_wg
> +
>  INCSGROUPS=    INCS \
>                 ACPICA \
>                 AGP \
> @@ -182,7 +186,8 @@ INCSGROUPS= INCS \
>                 PCI \
>                 RPC \
>                 TEKEN \
> -               VERIEXEC
> +               VERIEXEC \
> +               WG
>
>  .if ${MK_IPFILTER} != "no"
>  INCSGROUPS+=   IPFILTER
> diff --git a/sbin/ifconfig/ifwg.c b/sbin/ifconfig/ifwg.c
> index 86bacc59f50d..a102f392cf80 100644
> --- a/sbin/ifconfig/ifwg.c
> +++ b/sbin/ifconfig/ifwg.c
> @@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$");
>  #include <netinet/in.h>
>  #include <arpa/inet.h>
>
> +#include <dev/if_wg/if_wg.h>
> +
>  #include <assert.h>
>  #include <ctype.h>
>  #include <err.h>
> @@ -65,40 +67,60 @@ __FBSDID("$FreeBSD$");
>
>  #include "ifconfig.h"
>
> -typedef enum {
> -       WGC_GET = 0x5,
> -       WGC_SET = 0x6,
> -} wg_cmd_t;
> +static void wgfinish(int s, void *arg);
> +
> +static bool wgfinish_registered;
>
> -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;
> +static nvlist_t **allowed_ips, *nvl_peer;
>
>  #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_KEY_SIZE_BASE64 ((((WG_KEY_SIZE) + 2) / 3) * 4 + 1)
> +#define        WG_KEY_SIZE_HEX (WG_KEY_SIZE * 2 + 1)
>  #define        WG_MAX_STRLEN 64
>
> +struct allowedip {
> +       union {
> +               struct in_addr ip4;
> +               struct in6_addr ip6;
> +       };
> +};
> +
> +static void
> +register_wgfinish(void)
> +{
> +
> +       if (wgfinish_registered)
> +               return;
> +       callback_register(wgfinish, NULL);
> +       wgfinish_registered = true;
> +}
> +
> +static nvlist_t *
> +nvl_device(void)
> +{
> +       static nvlist_t *_nvl_device;
> +
> +       if (_nvl_device == NULL)
> +               _nvl_device = nvlist_create(0);
> +       register_wgfinish();
> +       return (_nvl_device);
> +}
> +
>  static bool
> -key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
> +key_from_base64(uint8_t key[static WG_KEY_SIZE], 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));
> +       if (strlen(base64) != WG_KEY_SIZE_BASE64 - 1) {
> +               warnx("bad key len - need %d got %zu\n", WG_KEY_SIZE_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]);
> +       if (base64[WG_KEY_SIZE_BASE64 - 2] != '=') {
> +               warnx("bad key terminator, expected '=' got '%c'", base64[WG_KEY_SIZE_BASE64 - 2]);
>                 return false;
>         }
> -       return (b64_pton(base64, key, WG_KEY_LEN));
> +       return (b64_pton(base64, key, WG_KEY_SIZE));
>  }
>
>  static void
> @@ -128,7 +150,7 @@ parse_endpoint(const char *endpoint_)
>         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);
> +       nvlist_add_binary(nvl_peer, "endpoint", res->ai_addr, res->ai_addrlen);
>         freeaddrinfo(res);
>         free(base);
>  }
> @@ -227,12 +249,14 @@ in6_mask2len(struct in6_addr *mask, u_char *lim0)
>  }
>
>  static bool
> -parse_ip(struct allowedip *aip, const char *value)
> +parse_ip(struct allowedip *aip, uint16_t *family, const char *value)
>  {
>         struct addrinfo hints, *res;
>         int err;
> +       bool ret;
>
> -       bzero(&aip->a_addr, sizeof(aip->a_addr));
> +       ret = true;
> +       bzero(aip, sizeof(*aip));
>         bzero(&hints, sizeof(hints));
>         hints.ai_family = AF_UNSPEC;
>         hints.ai_flags = AI_NUMERICHOST;
> @@ -240,10 +264,21 @@ parse_ip(struct allowedip *aip, const char *value)
>         if (err)
>                 errx(1, "%s", gai_strerror(err));
>
> -       memcpy(&aip->a_addr, res->ai_addr, res->ai_addrlen);
> +       *family = res->ai_family;
> +       if (res->ai_family == AF_INET) {
> +               struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
> +
> +               aip->ip4 = sin->sin_addr;
> +       } else if (res->ai_family == AF_INET6) {
> +               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
> +
> +               aip->ip6 = sin6->sin6_addr;
> +       } else {
> +               ret = false;
> +       }
>
>         freeaddrinfo(res);
> -       return (true);
> +       return (ret);
>  }
>
>  static void
> @@ -271,61 +306,84 @@ sa_ntop(const struct sockaddr *sa, char *buf, int *port)
>  }
>
>  static void
> -dump_peer(const nvlist_t *nvl_peer)
> +dump_peer(const nvlist_t *nvl_peer_cfg)
>  {
>         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;
> +       size_t aip_count, size;
> +       int port;
>         uint16_t persistent_keepalive;
> +       const nvlist_t * const *nvl_aips;
>
>         printf("[Peer]\n");
> -       if (nvlist_exists_binary(nvl_peer, "public-key")) {
> -               key = nvlist_get_binary(nvl_peer, "public-key", &size);
> +       if (nvlist_exists_binary(nvl_peer_cfg, "public-key")) {
> +               key = nvlist_get_binary(nvl_peer_cfg, "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);
> +       if (nvlist_exists_binary(nvl_peer_cfg, "preshared-key")) {
> +               key = nvlist_get_binary(nvl_peer_cfg, "preshared-key", &size);
> +               b64_ntop((const uint8_t *)key, size, outbuf, WG_MAX_STRLEN);
> +               printf("PresharedKey = %s\n", outbuf);
> +       }
> +       if (nvlist_exists_binary(nvl_peer_cfg, "endpoint")) {
> +               endpoint = nvlist_get_binary(nvl_peer_cfg, "endpoint", &size);
>                 sa_ntop(endpoint, addr_buf, &port);
>                 printf("Endpoint = %s:%d\n", addr_buf, ntohs(port));
>         }
> -       if (nvlist_exists_number(nvl_peer, "persistent-keepalive-interval")) {
> -               persistent_keepalive = nvlist_get_number(nvl_peer,
> +       if (nvlist_exists_number(nvl_peer_cfg,
> +           "persistent-keepalive-interval")) {
> +               persistent_keepalive = nvlist_get_number(nvl_peer_cfg,
>                     "persistent-keepalive-interval");
>                 printf("PersistentKeepalive = %d\n", persistent_keepalive);
>         }
> -       if (!nvlist_exists_binary(nvl_peer, "allowed-ips"))
> +       if (!nvlist_exists_nvlist_array(nvl_peer_cfg, "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);
> -       }
> +
> +       nvl_aips = nvlist_get_nvlist_array(nvl_peer_cfg, "allowed-ips", &aip_count);
> +       if (nvl_aips == NULL || aip_count == 0)
> +               return;
> +
>         printf("AllowedIPs = ");
> -       count = size / sizeof(struct allowedip);
> -       for (int i = 0; i < count; i++) {
> -               int mask;
> +       for (size_t i = 0; i < aip_count; i++) {
> +               uint8_t cidr;
> +               struct sockaddr_storage ss;
>                 sa_family_t family;
> -               void *bitmask;
> -               struct sockaddr *sa;
> -
> -               sa = __DECONST(void *, &aips[i].a_addr);
> -               bitmask = __DECONST(void *,
> -                   ((const struct sockaddr *)&(&aips[i])->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)
> +
> +               if (!nvlist_exists_number(nvl_aips[i], "cidr"))
> +                       continue;
> +               cidr = nvlist_get_number(nvl_aips[i], "cidr");
> +               if (nvlist_exists_binary(nvl_aips[i], "ipv4")) {
> +                       struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
> +                       const struct in_addr *ip4;
> +
> +                       ip4 = nvlist_get_binary(nvl_aips[i], "ipv4", &size);
> +                       if (ip4 == NULL || cidr > 32)
> +                               continue;
> +                       sin->sin_len = sizeof(*sin);
> +                       sin->sin_family = AF_INET;
> +                       sin->sin_addr = *ip4;
> +               } else if (nvlist_exists_binary(nvl_aips[i], "ipv6")) {
> +                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
> +                       const struct in6_addr *ip6;
> +
> +                       ip6 = nvlist_get_binary(nvl_aips[i], "ipv6", &size);
> +                       if (ip6 == NULL || cidr > 128)
> +                               continue;
> +                       sin6->sin6_len = sizeof(*sin6);
> +                       sin6->sin6_family = AF_INET6;
> +                       sin6->sin6_addr = *ip6;
> +               } else {
> +                       continue;
> +               }
> +
> +               family = ss.ss_family;
> +               getnameinfo((struct sockaddr *)&ss, ss.ss_len, addr_buf,
> +                   INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
> +               printf("%s/%d", addr_buf, cidr);
> +               if (i < aip_count - 1)
>                         printf(", ");
>         }
>         printf("\n");
> @@ -334,36 +392,34 @@ dump_peer(const nvlist_t *nvl_peer)
>  static int
>  get_nvl_out_size(int sock, u_long op, size_t *size)
>  {
> -       struct ifdrv ifd;
> +       struct wg_data_io wgd;
>         int err;
>
> -       memset(&ifd, 0, sizeof(ifd));
> +       memset(&wgd, 0, sizeof(wgd));
>
> -       strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name));
> -       ifd.ifd_cmd = op;
> -       ifd.ifd_len = 0;
> -       ifd.ifd_data = NULL;
> +       strlcpy(wgd.wgd_name, name, sizeof(wgd.wgd_name));
> +       wgd.wgd_size = 0;
> +       wgd.wgd_data = NULL;
>
> -       err = ioctl(sock, SIOCGDRVSPEC, &ifd);
> +       err = ioctl(sock, op, &wgd);
>         if (err)
>                 return (err);
> -       *size = ifd.ifd_len;
> +       *size = wgd.wgd_size;
>         return (0);
>  }
>
>  static int
>  do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
>  {
> -       struct ifdrv ifd;
> +       struct wg_data_io wgd;
>
> -       memset(&ifd, 0, sizeof(ifd));
> +       memset(&wgd, 0, sizeof(wgd));
>
> -       strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name));
> -       ifd.ifd_cmd = op;
> -       ifd.ifd_len = argsize;
> -       ifd.ifd_data = arg;
> +       strlcpy(wgd.wgd_name, name, sizeof(wgd.wgd_name));
> +       wgd.wgd_size = argsize;
> +       wgd.wgd_data = arg;
>
> -       return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
> +       return (ioctl(sock, op, &wgd));
>  }
>
>  static
> @@ -371,62 +427,83 @@ DECL_CMD_FUNC(peerlist, val, d)
>  {
>         size_t size, peercount;
>         void *packed;
> -       const nvlist_t *nvl, *nvl_peer;
> +       const nvlist_t *nvl;
>         const nvlist_t *const *nvl_peerlist;
>
> -       if (get_nvl_out_size(s, WGC_GET, &size))
> +       if (get_nvl_out_size(s, SIOCGWG, &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))
> +       if (do_cmd(s, SIOCGWG, packed, size, 0))
>                 errx(1, "failed to obtain peer list");
>
>         nvl = nvlist_unpack(packed, size, 0);
> -       if (!nvlist_exists_nvlist_array(nvl, "peer-list"))
> +       if (!nvlist_exists_nvlist_array(nvl, "peers"))
>                 return;
> -       nvl_peerlist = nvlist_get_nvlist_array(nvl, "peer-list", &peercount);
> +       nvl_peerlist = nvlist_get_nvlist_array(nvl, "peers", &peercount);
>
>         for (int i = 0; i < peercount; i++, nvl_peerlist++) {
> -               nvl_peer = *nvl_peerlist;
> -               dump_peer(nvl_peer);
> +               dump_peer(*nvl_peerlist);
>         }
>  }
>
>  static void
> -peerfinish(int s, void *arg)
> +wgfinish(int s, void *arg)
>  {
> -       nvlist_t *nvl, **nvl_array;
>         void *packed;
>         size_t size;
> +       static nvlist_t *nvl_dev;
> +
> +       nvl_dev = nvl_device();
> +       if (nvl_peer != NULL) {
> +               if (!nvlist_exists_binary(nvl_peer, "public-key"))
> +                       errx(1, "must specify a public-key for adding peer");
> +               if (allowed_ips_count != 0) {
> +                       nvlist_add_nvlist_array(nvl_peer, "allowed-ips",
> +                           (const nvlist_t * const *)allowed_ips,
> +                           allowed_ips_count);
> +                       for (size_t i = 0; i < allowed_ips_count; i++) {
> +                               nvlist_destroy(allowed_ips[i]);
> +                       }
> +
> +                       free(allowed_ips);
> +               }
> +
> +               nvlist_add_nvlist_array(nvl_dev, "peers",
> +                   (const nvlist_t * const *)&nvl_peer, 1);
> +       }
> +
> +       packed = nvlist_pack(nvl_dev, &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 (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");
> +       if (do_cmd(s, SIOCSWG, packed, size, true))
> +               errx(1, "failed to configure");
>  }
>
>  static
>  DECL_CMD_FUNC(peerstart, val, d)
>  {
> -       do_peer = true;
> -       callback_register(peerfinish, NULL);
> -       allowed_ips = malloc(ALLOWEDIPS_START * sizeof(struct allowedip));
> +
> +       if (nvl_peer != NULL)
> +               errx(1, "cannot both add and remove a peer");
> +       register_wgfinish();
> +       nvl_peer = nvlist_create(0);
> +       allowed_ips = calloc(ALLOWEDIPS_START, sizeof(*allowed_ips));
>         allowed_ips_max = ALLOWEDIPS_START;
>         if (allowed_ips == NULL)
>                 errx(1, "failed to allocate array for allowedips");
>  }
>
> +static
> +DECL_CMD_FUNC(peerdel, val, d)
> +{
> +
> +       if (nvl_peer != NULL)
> +               errx(1, "cannot both add and remove a peer");
> +       register_wgfinish();
> +       nvl_peer = nvlist_create(0);
> +       nvlist_add_bool(nvl_peer, "remove", true);
> +}
> +
>  static
>  DECL_CMD_FUNC(setwglistenport, val, d)
>  {
> @@ -454,39 +531,53 @@ DECL_CMD_FUNC(setwglistenport, val, d)
>                 errx(1, "unknown family");
>         }
>         ul = ntohs((u_short)ul);
> -       nvlist_add_number(nvl_params, "listen-port", ul);
> +       nvlist_add_number(nvl_device(), "listen-port", ul);
>  }
>
>  static
>  DECL_CMD_FUNC(setwgprivkey, val, d)
>  {
> -       uint8_t key[WG_KEY_LEN];
> +       uint8_t key[WG_KEY_SIZE];
>
>         if (!key_from_base64(key, val))
>                 errx(1, "invalid key %s", val);
> -       nvlist_add_binary(nvl_params, "private-key", key, WG_KEY_LEN);
> +       nvlist_add_binary(nvl_device(), "private-key", key, WG_KEY_SIZE);
>  }
>
>  static
>  DECL_CMD_FUNC(setwgpubkey, val, d)
>  {
> -       uint8_t key[WG_KEY_LEN];
> +       uint8_t key[WG_KEY_SIZE];
>
> -       if (!do_peer)
> +       if (nvl_peer == NULL)
>                 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);
> +       nvlist_add_binary(nvl_peer, "public-key", key, WG_KEY_SIZE);
>  }
>
> +static
> +DECL_CMD_FUNC(setwgpresharedkey, val, d)
> +{
> +       uint8_t key[WG_KEY_SIZE];
> +
> +       if (nvl_peer == NULL)
> +               errx(1, "setting preshared-key only valid when adding peer");
> +
> +       if (!key_from_base64(key, val))
> +               errx(1, "invalid key %s", val);
> +       nvlist_add_binary(nvl_peer, "preshared-key", key, WG_KEY_SIZE);
> +}
> +
> +
>  static
>  DECL_CMD_FUNC(setwgpersistentkeepalive, val, d)
>  {
>         unsigned long persistent_keepalive;
>         char *endp;
>
> -       if (!do_peer)
> +       if (nvl_peer == NULL)
>                 errx(1, "setting persistent keepalive only valid when adding peer");
>
>         errno = 0;
> @@ -496,7 +587,7 @@ DECL_CMD_FUNC(setwgpersistentkeepalive, val, d)
>         if (persistent_keepalive > USHRT_MAX)
>                 errx(1, "persistent-keepalive '%lu' too large",
>                     persistent_keepalive);
> -       nvlist_add_number(nvl_params, "persistent-keepalive-interval",
> +       nvlist_add_number(nvl_peer, "persistent-keepalive-interval",
>             persistent_keepalive);
>  }
>
> @@ -506,45 +597,57 @@ DECL_CMD_FUNC(setallowedips, val, d)
>         char *base, *allowedip, *mask;
>         u_long ul;
>         char *endp;
> -       struct allowedip *aip;
> +       struct allowedip aip;
> +       nvlist_t *nvl_aip;
> +       uint16_t family;
>
> -       if (!do_peer)
> +       if (nvl_peer == NULL)
>                 errx(1, "setting allowed ip only valid when adding peer");
>         if (allowed_ips_count == allowed_ips_max) {
> -               /* XXX grow array */
> +               allowed_ips_max *= 2;
> +               allowed_ips = reallocarray(allowed_ips, allowed_ips_max,
> +                   sizeof(*allowed_ips));
> +               if (allowed_ips == NULL)
> +                       errx(1, "failed to grow allowed ip array");
>         }
> -       aip = &allowed_ips[allowed_ips_count];
> +
> +       allowed_ips[allowed_ips_count] = nvl_aip = nvlist_create(0);
> +       if (nvl_aip == NULL)
> +               errx(1, "failed to create new allowedip nvlist");
> +
>         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);
> +
> +       parse_ip(&aip, &family, 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);
> +
> +       nvlist_add_number(nvl_aip, "cidr", ul);
> +       if (family == AF_INET) {
> +               nvlist_add_binary(nvl_aip, "ipv4", &aip.ip4, sizeof(aip.ip4));
> +       } else if (family == AF_INET6) {
> +               nvlist_add_binary(nvl_aip, "ipv6", &aip.ip6, sizeof(aip.ip6));
> +       } else {
> +               /* Shouldn't happen */
> +               nvlist_destroy(nvl_aip);
> +               goto out;
> +       }
> +
>         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);
> +out:
>         free(base);
>  }
>
>  static
>  DECL_CMD_FUNC(setendpoint, val, d)
>  {
> -       if (!do_peer)
> +       if (nvl_peer == NULL)
>                 errx(1, "setting endpoint only valid when adding peer");
>         parse_endpoint(val);
>  }
> @@ -555,15 +658,15 @@ wireguard_status(int s)
>         size_t size;
>         void *packed;
>         nvlist_t *nvl;
> -       char buf[WG_KEY_LEN_BASE64];
> +       char buf[WG_KEY_SIZE_BASE64];
>         const void *key;
>         uint16_t listen_port;
>
> -       if (get_nvl_out_size(s, WGC_GET, &size))
> +       if (get_nvl_out_size(s, SIOCGWG, &size))
>                 return;
>         if ((packed = malloc(size)) == NULL)
>                 return;
> -       if (do_cmd(s, WGC_GET, packed, size, 0))
> +       if (do_cmd(s, SIOCGWG, packed, size, 0))
>                 return;
>         nvl = nvlist_unpack(packed, size, 0);
>         if (nvlist_exists_number(nvl, "listen-port")) {
> @@ -583,10 +686,14 @@ wireguard_status(int s)
>  }
>
>  static struct cmd wireguard_cmds[] = {
> -    DEF_CLONE_CMD_ARG("listen-port",  setwglistenport),
> -    DEF_CLONE_CMD_ARG("private-key",  setwgprivkey),
> +    DEF_CMD_ARG("listen-port",  setwglistenport),
> +    DEF_CMD_ARG("private-key",  setwgprivkey),
> +    /* XXX peer-list is deprecated. */
>      DEF_CMD("peer-list",  0, peerlist),
> +    DEF_CMD("peers",  0, peerlist),
>      DEF_CMD("peer",  0, peerstart),
> +    DEF_CMD("-peer",  0, peerdel),
> +    DEF_CMD_ARG("preshared-key",  setwgpresharedkey),
>      DEF_CMD_ARG("public-key",  setwgpubkey),
>      DEF_CMD_ARG("persistent-keepalive",  setwgpersistentkeepalive),
>      DEF_CMD_ARG("allowed-ips",  setallowedips),
> @@ -602,27 +709,10 @@ static struct afswtch af_wireguard = {
>  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;
> +
> +       ifr->ifr_data = NULL;
>         if (ioctl(s, SIOCIFCREATE, ifr) < 0)
>                 err(1, "SIOCIFCREATE");
>  }
> @@ -632,7 +722,6 @@ 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);
> diff --git a/share/man/man4/wg.4 b/share/man/man4/wg.4
> index 335d3e70b64a..29215bd438ff 100644
> --- a/share/man/man4/wg.4
> +++ b/share/man/man4/wg.4
> @@ -23,7 +23,7 @@
>  .\"
>  .\" $FreeBSD$
>  .\"
> -.Dd March 9, 2021
> +.Dd March 12, 2021
>  .Dt WG 4
>  .Os
>  .Sh NAME
> @@ -68,7 +68,7 @@ interface.
>  The private key of the
>  .Nm
>  interface.
> -.It Cm pre-shared-key
> +.It Cm preshared-key
>  Defines a pre-shared key for the
>  .Nm
>  interface.
> @@ -76,9 +76,9 @@ interface.
>  A list of allowed IP addresses.
>  .It Cm endpoint
>  The IP address of the WiredGuard to connect to.
> -.It Cm peer-list
> +.It Cm peers
>  A list of peering IP addresses to connect to.
> -.It Cm persistent-keepalive
> +.It Cm persistent-keepalive-interval
>  Interval, in seconds, at which to send persistent keepalive packets.
>  .El
>  .Pp
> @@ -188,6 +188,11 @@ Connect to a specific endpoint using its public-key and set the allowed IP addre
>  .Bd -literal -offset indent
>  # ifconfig wg0 peer public-key '7lWtsDdqaGB3EY9WNxRN3hVaHMtu1zXw71+bOjNOVUw=' endpoint 10.0.1.100:54321 allowed-ips 192.168.2.100/32
>  .Ed
> +.Pp
> +Remove a peer
> +.Bd -literal -offset indent
> +# ifconfig wg0 -peer public-key '7lWtsDdqaGB3EY9WNxRN3hVaHMtu1zXw71+bOjNOVUw='
> +.Ed
>  .Sh DIAGNOSTICS
>  The
>  .Nm
> @@ -240,14 +245,11 @@ device driver first appeared in
>  .Sh AUTHORS
>  The
>  .Nm
> -device driver was originally written for
> -.Ox
> -by
> -.An Matt Dunwoodie Aq Mt ncon at nconroy.net
> -and ported to
> -.Fx
> -by
> -.An Matt Macy Aq Mt mmacy at FreeBSD.org .
> +device driver written by
> +.An Jason A. Donenfeld Aq Mt Jason at zx2c4.com ,
> +.An Matt Dunwoodie Aq Mt ncon at nconroy.net ,
> +and
> +.An Kyle Evans Aq Mt kevans at FreeBSD.org .
>  .Pp
>  This manual page was written by
>  .An Gordon Bergling Aq Mt gbe at FreeBSD.org
> diff --git a/sys/dev/if_wg/crypto.c b/sys/dev/if_wg/crypto.c
> new file mode 100644
> index 000000000000..f28585429272
> --- /dev/null
> +++ b/sys/dev/if_wg/crypto.c
> @@ -0,0 +1,1705 @@
> +/*
> + * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason at zx2c4.com>. All Rights Reserved.
> + *
> + * 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.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/endian.h>
> +#include <sys/systm.h>
> +
> +#include "crypto.h"
> +
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +#endif
> +#ifndef noinline
> +#define noinline __attribute__((noinline))
> +#endif
> +#ifndef __aligned
> +#define __aligned(x) __attribute__((aligned(x)))
> +#endif
> +#ifndef DIV_ROUND_UP
> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
> +#endif
> +
> +#define le32_to_cpup(a) le32toh(*(a))
> +#define le64_to_cpup(a) le64toh(*(a))
> +#define cpu_to_le32(a) htole32(a)
> +#define cpu_to_le64(a) htole64(a)
> +
> +static inline uint32_t get_unaligned_le32(const uint8_t *a)
> +{
> +       uint32_t l;
> +       __builtin_memcpy(&l, a, sizeof(l));
> +       return le32_to_cpup(&l);
> +}
> +static inline uint64_t get_unaligned_le64(const uint8_t *a)
> +{
> +       uint64_t l;
> +       __builtin_memcpy(&l, a, sizeof(l));
> +       return le64_to_cpup(&l);
> +}
> +static inline void put_unaligned_le32(uint32_t s, uint8_t *d)
> +{
> +       uint32_t l = cpu_to_le32(s);
> +       __builtin_memcpy(d, &l, sizeof(l));
> +}
> +static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
> +{
> +        while (words--) {
> +               *buf = cpu_to_le32(*buf);
> +               ++buf;
> +       }
> +}
> +static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
> +{
> +        while (words--) {
> +               *buf = le32_to_cpup(buf);
> +               ++buf;
> +        }
> +}
> +
> +static inline uint32_t rol32(uint32_t word, unsigned int shift)
> +{
> +        return (word << (shift & 31)) | (word >> ((-shift) & 31));
> +}
> +static inline uint32_t ror32(uint32_t word, unsigned int shift)
> +{
> +       return (word >> (shift & 31)) | (word << ((-shift) & 31));
> +}
> +
> +static void xor_cpy(uint8_t *dst, const uint8_t *src1, const uint8_t *src2,
> +                   size_t len)
> +{
> +       size_t i;
> +
> +       for (i = 0; i < len; ++i)
> +               dst[i] = src1[i] ^ src2[i];
> +}
> +
> +#define QUARTER_ROUND(x, a, b, c, d) ( \
> +       x[a] += x[b], \
> *** 50620 LINES SKIPPED ***
> _______________________________________________
> dev-commits-src-main at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
> To unsubscribe, send any mail to "dev-commits-src-main-unsubscribe at freebsd.org"


More information about the dev-commits-src-all mailing list