Date: Mon, 15 Mar 2021 08:56:56 -0600 From: Scott Long <scottl@samsco.org> To: Kyle Evans <kevans@FreeBSD.org> Cc: "src-committers@freebsd.org" <src-committers@FreeBSD.org>, "dev-commits-src-all@freebsd.org" <dev-commits-src-all@FreeBSD.org>, "dev-commits-src-main@freebsd.org" <dev-commits-src-main@FreeBSD.org> Subject: Re: git: 74ae3f3e33b8 - main - if_wg: import latest fixup work from the wireguard-freebsd project Message-ID: <13F91280-2246-4A7B-BAC2-B9ABA07B561F@samsco.org> In-Reply-To: <202103150452.12F4qxjV047368@gitrepo.freebsd.org> References: <202103150452.12F4qxjV047368@gitrepo.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
Here is the response I sent to you and Donenfeld in private. I won=E2=80=99= t include my direct conversation with you from Slack/IRC, but I made my concerns and objections pretty clear. This commit is quite disappointing. See = below: The good: - I=E2=80=99m happy that the community is taking a strong interest in = wireguard in FreeBSD. More hands make light work, and all that, and it=E2=80=99s = why we participate in open source. - I was excited that some of the issues that people have complained about were getting addressed, like packet queueing during re-keying. I know that vnet/jail was a sore spot, and while it=E2=80=99s not = something that Netgate depends on, I knew that it=E2=80=99s important to the community. - I was happy to hear that there=E2=80=99s going to be a new = wireguard-tools with =E2=80=9Cofficial=E2=80=9D FreebSD support. Again, growing = ecosystem, community interest, collaborative work. - I was happy to learn about the test code being ported to FreeBSD. We=E2=80=99re ramping up major resources into testing, and I want to get = my hands on anything and everything that will improve quality and drive better development. The bad: - I want to be pragmatic about code APIs. Maybe iflib isn=E2=80=99t = ready for pseudo interfaces yet, and fixing it is non-trivial and out of scope. Going back to ifnet puts it back in line with openbsd and likely does fix the vnet problems. However, it=E2=80=99s a radical change to the = driver, and not something that I can support as a last-minute action for FreeBSD 13.0 or for pfSense. Therefore, I=E2=80=99m advising against its = immediate inclusion. The final choice is not mine to make for FreeBSD, but that=E2=80=99s my recommendation. For pfSense, I=E2=80=99ll be = discussing this with the rest of the engineering staff on Monday. - The LKML wouldn=E2=80=99t accept this kind of submission, they=E2=80=99d= insist that it be broken down into consumable pieces, and that bug fixes be considered and provided that don=E2=80=99t rely on massive re-writes. = I=E2=80=99ve been dealing with linux for 20+ years and BSD for almost 30 years, and I=E2=80=99ve got to say that despite my distaste for how the LKML is = run, they get results. Does fixing a segfault or packet drop/reorder require the removal of iflib? The Ugly: - An accusation was made, tonight, to me, that the code Netgate=20 sponsored was not reviewed and was shoved into the tree at the last minute. This grossly ignores the actual history to the point of weakening my tolerance for this entire discussion. It shows a pretty irrational bias against mmacy and Netgate and a gross ignorance of the history and provenience of the work. - The Netgate copyright was unilaterally removed. Yes, it was re- instated a few minutes ago, and with good reason. Please don=E2=80=99t do that again. - The removal of the ASM crypto bits really confuses me. An accusation was made, again tonight, that Netgate merely paid to benchmark the code, that we contributed nothing to it, and that it=E2=80=99= s bad code that can=E2=80=99t be audited. What I see is that the meat of = the implementation is copyrighted by Jason and others. There=E2=80=99s a modest but non-trivial amount of glue code that has (or had) the Netgate copyright. I=E2=80=99m not going to touch the audit nonsense. I need data here, and I=E2=80=99m not seeing it. There seems to be a lot of bad blood, poor understanding, and misinformation going on. I need all of this bullshit to stop. This is 5000-ish lines of a nice way to get a point-to-point VPN going without the hassle of IPSec or the performance problems of OpenVPN. It=E2=80=99s consuming way more time and energy than it=E2=80=99= s worth to me, and I=E2=80=99d much rather spend time and money to implement OpenVPN DCO and work on profiling and optimizing IPSec. Wireguard is important to Netgate because we recognize that it=E2=80=99s a feature that customers want, we=E2=80=99re committed = to making security accessible, and we strongly believe in open source and FreeBSD. It=E2=80=99s not perfect code, not by a long shot, but I expect better collaboration and communication than what I=E2=80=99m seeing = here. Scott > On Mar 14, 2021, at 10:52 PM, Kyle Evans <kevans@FreeBSD.org> wrote: >=20 > The branch main has been updated by kevans: >=20 > URL: = https://cgit.FreeBSD.org/src/commit/?id=3D74ae3f3e33b810248da19004c58b3581= cd367843 >=20 > commit 74ae3f3e33b810248da19004c58b3581cd367843 > Author: Kyle Evans <kevans@FreeBSD.org> > AuthorDate: 2021-03-15 02:25:40 +0000 > Commit: Kyle Evans <kevans@FreeBSD.org> > CommitDate: 2021-03-15 04:52:04 +0000 >=20 > if_wg: import latest fixup work from the wireguard-freebsd project >=20 > 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: >=20 > - Jason A. Donenfeld <Jason@zx2c4.com> > - Matt Dunwoodie <ncon@noconroy.net> > - Kyle Evans <kevans@FreeBSD.org> >=20 > 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 >=20 > 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. >=20 > 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. >=20 > 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. >=20 > Also note that this is still a work in progress; work going further = will > be much smaller in nature. >=20 > 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 =3D> }/wg_cookie.c | 105 +- > sys/dev/if_wg/{include/sys =3D> }/wg_cookie.h | 81 +- > sys/dev/if_wg/{module =3D> }/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(-) >=20 > 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=3D bsm cam geom net net80211 netgraph = netinet netinet6 \ > LSUBDIRS=3D 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=3D ${INCLUDEDIR}/sys > MLX5=3D mlx5io.h > MLX5DIR=3D ${INCLUDEDIR}/dev/mlx5 >=20 > +.PATH: ${SRCTOP}/sys/dev/if_wg > +WG=3D if_wg.h > +WGDIR=3D ${INCLUDEDIR}/dev/if_wg > + > INCSGROUPS=3D INCS \ > ACPICA \ > AGP \ > @@ -182,7 +186,8 @@ INCSGROUPS=3D INCS \ > PCI \ > RPC \ > TEKEN \ > - VERIEXEC > + VERIEXEC \ > + WG >=20 > .if ${MK_IPFILTER} !=3D "no" > INCSGROUPS+=3D 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> >=20 > +#include <dev/if_wg/if_wg.h> > + > #include <assert.h> > #include <ctype.h> > #include <err.h> > @@ -65,40 +67,60 @@ __FBSDID("$FreeBSD$"); >=20 > #include "ifconfig.h" >=20 > -typedef enum { > - WGC_GET =3D 0x5, > - WGC_SET =3D 0x6, > -} wg_cmd_t; > +static void wgfinish(int s, void *arg); > + > +static bool wgfinish_registered; >=20 > -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; >=20 > #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 >=20 > +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 =3D true; > +} > + > +static nvlist_t * > +nvl_device(void) > +{ > + static nvlist_t *_nvl_device; > + > + if (_nvl_device =3D=3D NULL) > + _nvl_device =3D 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) > { >=20 > - if (strlen(base64) !=3D WG_KEY_LEN_BASE64 - 1) { > - warnx("bad key len - need %d got %zu\n", = WG_KEY_LEN_BASE64 - 1, strlen(base64)); > + if (strlen(base64) !=3D 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] !=3D '=3D') { > - warnx("bad key terminator, expected '=3D' got '%c'", = base64[WG_KEY_LEN_BASE64 - 2]); > + if (base64[WG_KEY_SIZE_BASE64 - 2] !=3D '=3D') { > + warnx("bad key terminator, expected '=3D' 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)); > } >=20 > static void > @@ -128,7 +150,7 @@ parse_endpoint(const char *endpoint_) > err =3D 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) > } >=20 > 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; >=20 > - bzero(&aip->a_addr, sizeof(aip->a_addr)); > + ret =3D true; > + bzero(aip, sizeof(*aip)); > bzero(&hints, sizeof(hints)); > hints.ai_family =3D AF_UNSPEC; > hints.ai_flags =3D AI_NUMERICHOST; > @@ -240,10 +264,21 @@ parse_ip(struct allowedip *aip, const char = *value) > if (err) > errx(1, "%s", gai_strerror(err)); >=20 > - memcpy(&aip->a_addr, res->ai_addr, res->ai_addrlen); > + *family =3D res->ai_family; > + if (res->ai_family =3D=3D AF_INET) { > + struct sockaddr_in *sin =3D (struct sockaddr_in = *)res->ai_addr; > + > + aip->ip4 =3D sin->sin_addr; > + } else if (res->ai_family =3D=3D AF_INET6) { > + struct sockaddr_in6 *sin6 =3D (struct sockaddr_in6 = *)res->ai_addr; > + > + aip->ip6 =3D sin6->sin6_addr; > + } else { > + ret =3D false; > + } >=20 > freeaddrinfo(res); > - return (true); > + return (ret); > } >=20 > static void > @@ -271,61 +306,84 @@ sa_ntop(const struct sockaddr *sa, char *buf, = int *port) > } >=20 > 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; >=20 > printf("[Peer]\n"); > - if (nvlist_exists_binary(nvl_peer, "public-key")) { > - key =3D nvlist_get_binary(nvl_peer, "public-key", = &size); > + if (nvlist_exists_binary(nvl_peer_cfg, "public-key")) { > + key =3D nvlist_get_binary(nvl_peer_cfg, "public-key", = &size); > b64_ntop((const uint8_t *)key, size, outbuf, = WG_MAX_STRLEN); > printf("PublicKey =3D %s\n", outbuf); > } > - if (nvlist_exists_binary(nvl_peer, "endpoint")) { > - endpoint =3D nvlist_get_binary(nvl_peer, "endpoint", = &size); > + if (nvlist_exists_binary(nvl_peer_cfg, "preshared-key")) { > + key =3D nvlist_get_binary(nvl_peer_cfg, "preshared-key", = &size); > + b64_ntop((const uint8_t *)key, size, outbuf, = WG_MAX_STRLEN); > + printf("PresharedKey =3D %s\n", outbuf); > + } > + if (nvlist_exists_binary(nvl_peer_cfg, "endpoint")) { > + endpoint =3D nvlist_get_binary(nvl_peer_cfg, "endpoint", = &size); > sa_ntop(endpoint, addr_buf, &port); > printf("Endpoint =3D %s:%d\n", addr_buf, ntohs(port)); > } > - if (nvlist_exists_number(nvl_peer, = "persistent-keepalive-interval")) { > - persistent_keepalive =3D nvlist_get_number(nvl_peer, > + if (nvlist_exists_number(nvl_peer_cfg, > + "persistent-keepalive-interval")) { > + persistent_keepalive =3D nvlist_get_number(nvl_peer_cfg, > "persistent-keepalive-interval"); > printf("PersistentKeepalive =3D %d\n", = persistent_keepalive); > } > - if (!nvlist_exists_binary(nvl_peer, "allowed-ips")) > + if (!nvlist_exists_nvlist_array(nvl_peer_cfg, "allowed-ips")) > return; > - aips =3D nvlist_get_binary(nvl_peer, "allowed-ips", &size); > - if (size =3D=3D 0 || size % sizeof(struct allowedip) !=3D 0) { > - errx(1, "size %zu not integer multiple of allowedip", = size); > - } > + > + nvl_aips =3D nvlist_get_nvlist_array(nvl_peer_cfg, = "allowed-ips", &aip_count); > + if (nvl_aips =3D=3D NULL || aip_count =3D=3D 0) > + return; > + > printf("AllowedIPs =3D "); > - count =3D size / sizeof(struct allowedip); > - for (int i =3D 0; i < count; i++) { > - int mask; > + for (size_t i =3D 0; i < aip_count; i++) { > + uint8_t cidr; > + struct sockaddr_storage ss; > sa_family_t family; > - void *bitmask; > - struct sockaddr *sa; > - > - sa =3D __DECONST(void *, &aips[i].a_addr); > - bitmask =3D __DECONST(void *, > - ((const struct sockaddr = *)&(&aips[i])->a_mask)->sa_data); > - family =3D aips[i].a_addr.ss_family; > - getnameinfo(sa, sa->sa_len, addr_buf, INET6_ADDRSTRLEN, = NULL, > - 0, NI_NUMERICHOST); > - if (family =3D=3D AF_INET) > - mask =3D in_mask2len(bitmask); > - else if (family =3D=3D AF_INET6) > - mask =3D 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 =3D nvlist_get_number(nvl_aips[i], "cidr"); > + if (nvlist_exists_binary(nvl_aips[i], "ipv4")) { > + struct sockaddr_in *sin =3D (struct sockaddr_in = *)&ss; > + const struct in_addr *ip4; > + > + ip4 =3D nvlist_get_binary(nvl_aips[i], "ipv4", = &size); > + if (ip4 =3D=3D NULL || cidr > 32) > + continue; > + sin->sin_len =3D sizeof(*sin); > + sin->sin_family =3D AF_INET; > + sin->sin_addr =3D *ip4; > + } else if (nvlist_exists_binary(nvl_aips[i], "ipv6")) { > + struct sockaddr_in6 *sin6 =3D (struct = sockaddr_in6 *)&ss; > + const struct in6_addr *ip6; > + > + ip6 =3D nvlist_get_binary(nvl_aips[i], "ipv6", = &size); > + if (ip6 =3D=3D NULL || cidr > 128) > + continue; > + sin6->sin6_len =3D sizeof(*sin6); > + sin6->sin6_family =3D AF_INET6; > + sin6->sin6_addr =3D *ip6; > + } else { > + continue; > + } > + > + family =3D 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; >=20 > - memset(&ifd, 0, sizeof(ifd)); > + memset(&wgd, 0, sizeof(wgd)); >=20 > - strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name)); > - ifd.ifd_cmd =3D op; > - ifd.ifd_len =3D 0; > - ifd.ifd_data =3D NULL; > + strlcpy(wgd.wgd_name, name, sizeof(wgd.wgd_name)); > + wgd.wgd_size =3D 0; > + wgd.wgd_data =3D NULL; >=20 > - err =3D ioctl(sock, SIOCGDRVSPEC, &ifd); > + err =3D ioctl(sock, op, &wgd); > if (err) > return (err); > - *size =3D ifd.ifd_len; > + *size =3D wgd.wgd_size; > return (0); > } >=20 > static int > do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) > { > - struct ifdrv ifd; > + struct wg_data_io wgd; >=20 > - memset(&ifd, 0, sizeof(ifd)); > + memset(&wgd, 0, sizeof(wgd)); >=20 > - strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name)); > - ifd.ifd_cmd =3D op; > - ifd.ifd_len =3D argsize; > - ifd.ifd_data =3D arg; > + strlcpy(wgd.wgd_name, name, sizeof(wgd.wgd_name)); > + wgd.wgd_size =3D argsize; > + wgd.wgd_data =3D arg; >=20 > - return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); > + return (ioctl(sock, op, &wgd)); > } >=20 > 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; >=20 > - 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 =3D malloc(size)) =3D=3D 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"); >=20 > nvl =3D nvlist_unpack(packed, size, 0); > - if (!nvlist_exists_nvlist_array(nvl, "peer-list")) > + if (!nvlist_exists_nvlist_array(nvl, "peers")) > return; > - nvl_peerlist =3D nvlist_get_nvlist_array(nvl, "peer-list", = &peercount); > + nvl_peerlist =3D nvlist_get_nvlist_array(nvl, "peers", = &peercount); >=20 > for (int i =3D 0; i < peercount; i++, nvl_peerlist++) { > - nvl_peer =3D *nvl_peerlist; > - dump_peer(nvl_peer); > + dump_peer(*nvl_peerlist); > } > } >=20 > 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 =3D nvl_device(); > + if (nvl_peer !=3D NULL) { > + if (!nvlist_exists_binary(nvl_peer, "public-key")) > + errx(1, "must specify a public-key for adding = peer"); > + if (allowed_ips_count !=3D 0) { > + nvlist_add_nvlist_array(nvl_peer, "allowed-ips", > + (const nvlist_t * const *)allowed_ips, > + allowed_ips_count); > + for (size_t i =3D 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 =3D nvlist_pack(nvl_dev, &size); >=20 > - if ((nvl =3D nvlist_create(0)) =3D=3D NULL) > - errx(1, "failed to allocate nvlist"); > - if ((nvl_array =3D calloc(sizeof(void *), 1)) =3D=3D 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 =3D=3D 0) > - errx(1, "must specify at least one range of allowed-ips = to add a peer"); > - > - nvl_array[0] =3D nvl_params; > - nvlist_add_nvlist_array(nvl, "peer-list", (const nvlist_t * = const *)nvl_array, 1); > - packed =3D 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"); > } >=20 > static > DECL_CMD_FUNC(peerstart, val, d) > { > - do_peer =3D true; > - callback_register(peerfinish, NULL); > - allowed_ips =3D malloc(ALLOWEDIPS_START * sizeof(struct = allowedip)); > + > + if (nvl_peer !=3D NULL) > + errx(1, "cannot both add and remove a peer"); > + register_wgfinish(); > + nvl_peer =3D nvlist_create(0); > + allowed_ips =3D calloc(ALLOWEDIPS_START, sizeof(*allowed_ips)); > allowed_ips_max =3D ALLOWEDIPS_START; > if (allowed_ips =3D=3D NULL) > errx(1, "failed to allocate array for allowedips"); > } >=20 > +static > +DECL_CMD_FUNC(peerdel, val, d) > +{ > + > + if (nvl_peer !=3D NULL) > + errx(1, "cannot both add and remove a peer"); > + register_wgfinish(); > + nvl_peer =3D 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 =3D ntohs((u_short)ul); > - nvlist_add_number(nvl_params, "listen-port", ul); > + nvlist_add_number(nvl_device(), "listen-port", ul); > } >=20 > static > DECL_CMD_FUNC(setwgprivkey, val, d) > { > - uint8_t key[WG_KEY_LEN]; > + uint8_t key[WG_KEY_SIZE]; >=20 > 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); > } >=20 > static > DECL_CMD_FUNC(setwgpubkey, val, d) > { > - uint8_t key[WG_KEY_LEN]; > + uint8_t key[WG_KEY_SIZE]; >=20 > - if (!do_peer) > + if (nvl_peer =3D=3D NULL) > errx(1, "setting public key only valid when adding = peer"); >=20 > 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); > } >=20 > +static > +DECL_CMD_FUNC(setwgpresharedkey, val, d) > +{ > + uint8_t key[WG_KEY_SIZE]; > + > + if (nvl_peer =3D=3D 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; >=20 > - if (!do_peer) > + if (nvl_peer =3D=3D NULL) > errx(1, "setting persistent keepalive only valid when = adding peer"); >=20 > errno =3D 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); > } >=20 > @@ -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; >=20 > - if (!do_peer) > + if (nvl_peer =3D=3D NULL) > errx(1, "setting allowed ip only valid when adding = peer"); > if (allowed_ips_count =3D=3D allowed_ips_max) { > - /* XXX grow array */ > + allowed_ips_max *=3D 2; > + allowed_ips =3D reallocarray(allowed_ips, = allowed_ips_max, > + sizeof(*allowed_ips)); > + if (allowed_ips =3D=3D NULL) > + errx(1, "failed to grow allowed ip array"); > } > - aip =3D &allowed_ips[allowed_ips_count]; > + > + allowed_ips[allowed_ips_count] =3D nvl_aip =3D nvlist_create(0); > + if (nvl_aip =3D=3D NULL) > + errx(1, "failed to create new allowedip nvlist"); > + > base =3D allowedip =3D strdup(val); > mask =3D index(allowedip, '/'); > if (mask =3D=3D NULL) > errx(1, "mask separator not found in allowedip %s", = val); > *mask =3D '\0'; > mask++; > - parse_ip(aip, allowedip); > + > + parse_ip(&aip, &family, allowedip); > ul =3D strtoul(mask, &endp, 0); > if (*endp !=3D '\0') > errx(1, "invalid value for allowedip mask"); > - bzero(&aip->a_mask, sizeof(aip->a_mask)); > - if (aip->a_addr.ss_family =3D=3D AF_INET) > - in_len2mask((struct in_addr *)&((struct sockaddr = *)&aip->a_mask)->sa_data, ul); > - else if (aip->a_addr.ss_family =3D=3D 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 =3D=3D AF_INET) { > + nvlist_add_binary(nvl_aip, "ipv4", &aip.ip4, = sizeof(aip.ip4)); > + } else if (family =3D=3D 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)); >=20 > - dump_peer(nvl_params); > +out: > free(base); > } >=20 > static > DECL_CMD_FUNC(setendpoint, val, d) > { > - if (!do_peer) > + if (nvl_peer =3D=3D 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; >=20 > - if (get_nvl_out_size(s, WGC_GET, &size)) > + if (get_nvl_out_size(s, SIOCGWG, &size)) > return; > if ((packed =3D malloc(size)) =3D=3D NULL) > return; > - if (do_cmd(s, WGC_GET, packed, size, 0)) > + if (do_cmd(s, SIOCGWG, packed, size, 0)) > return; > nvl =3D nvlist_unpack(packed, size, 0); > if (nvlist_exists_number(nvl, "listen-port")) { > @@ -583,10 +686,14 @@ wireguard_status(int s) > } >=20 > static struct cmd wireguard_cmds[] =3D { > - 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 =3D { > static void > wg_create(int s, struct ifreq *ifr) > { > - struct iovec iov; > - void *packed; > - size_t size; >=20 > 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 =3D nvlist_pack(nvl_params, &size); > - if (packed =3D=3D NULL) > - errx(1, "failed to setup create request"); > - iov.iov_len =3D size; > - iov.iov_base =3D packed; > - ifr->ifr_data =3D (caddr_t)&iov; > - if (ioctl(s, SIOCIFCREATE2, ifr) < 0) > - err(1, "SIOCIFCREATE2"); > - return; > -legacy: > - ifr->ifr_data =3D=3D NULL; > + > + ifr->ifr_data =3D NULL; > if (ioctl(s, SIOCIFCREATE, ifr) < 0) > err(1, "SIOCIFCREATE"); > } > @@ -632,7 +722,6 @@ wireguard_ctor(void) > { > int i; >=20 > - nvl_params =3D nvlist_create(0); > for (i =3D 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=3D' 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=3D' > +.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@nconroy.net > -and ported to > -.Fx > -by > -.An Matt Macy Aq Mt mmacy@FreeBSD.org . > +device driver written by > +.An Jason A. Donenfeld Aq Mt Jason@zx2c4.com , > +.An Matt Dunwoodie Aq Mt ncon@nconroy.net , > +and > +.An Kyle Evans Aq Mt kevans@FreeBSD.org . > .Pp > This manual page was written by > .An Gordon Bergling Aq Mt gbe@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@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 =3D 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 =3D cpu_to_le32(*buf); > + ++buf; > + } > +} > +static inline void le32_to_cpu_array(uint32_t *buf, unsigned int = words) > +{ > + while (words--) { > + *buf =3D 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 =3D 0; i < len; ++i) > + dst[i] =3D src1[i] ^ src2[i]; > +} > + > +#define QUARTER_ROUND(x, a, b, c, d) ( \ > + x[a] +=3D x[b], \ > *** 50620 LINES SKIPPED ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?13F91280-2246-4A7B-BAC2-B9ABA07B561F>