13.2-RELEASE brings back the Wireguard driver to FreeBSD

Posted on May 9, 2023 | By Andrei Buzoianu | 8 minutes read

The release notes for FreeBSD 13.2-RELEASE contain a nice little gem: the kernel wg(4) WireGuard driver has been reintegrated. It provides Virtual Private Network (VPN) interfaces using the WireGuard protocol. The actual commit is 5ae69e2f10da, sponsored by Rubicon Communications, LLC (“Netgate”) and The FreeBSD Foundation. Thus, it is now possible to use wg(8) and wg-quick(8) like usual, but with the faster kernel implementation.

Controversy

If someone doesn’t already know, WireGuard is an encrypted point-to-point tunneling protocol, part of what most people think of as a Virtual Private Network (VPN). When Jim Thompson, the Chief Executive Officer of Netgate, recognized the need for FreeBSD to possess the same in-kernel WireGuard support as Linux, he reached out to Matthew Macy with a contract offer. For them, it seems that Macy was a perfectly reasonable choice to port WireGuard into the FreeBSD kernel. According to Ars Technica, WireGuard developer Jason Donenfeld didn’t even hear about the initiative, until the word was out on a FreeBSD mailing list. But, I don’t think they took into consideration the possible ramifications, since pursuing the course of action (sponsoring Macy’s work) definitely had a fallout. Netgate had a serious PR problem when, after about nine months of part-time development, Macy committed his work directly into the HEAD section of FreeBSD’s code repository, scheduled for inclusion into FreeBSD 13.0-RELEASE.

Soon after, Jason Donenfeld identified numerous problems with Macy’s code and decided to fix them with the help of FreeBSD developer Kyle Evans and Matt Dunwoodie, the developer who had worked on WireGuard for OpenBSD. After a week of work, the initial implementation was found to be sub-standard and removed from from stable/13 and releng/13.0 as well. In Donenfeld’s own words, that was the “best possible technical situation”, the rationale being that “Merging a week-old codebase into an operating system kernel is a bad idea.” It is only fair to acknowledge that the quality of the implementation would have also had a significant impact on the reputation of the Wireguard project.

In any case, at that moment, it was decided that waiting for 13.1-RELEASE rather than forcing rushed code into a kernel is pretty much the right call. More background here and here.

Netgate’s public response included messages and a blog post. I strongly recommend you to read them to form your own opinion.

Usage

Let’s create a Wireguard tunnel as shown in the following diagram, using 2 FreeBSD systems.

FreeBSD Wireguard

The private keys for WireGuard are 32 bytes long and are commonly encoded in base64 for ease of use. They can be generated using genkey subcomand:

$ wg genkey

First let’s create a wg interface on both nodes:

$ doas ifconfig wg0 create
$ doas ifconfig wg0 up

Each peer in the VPN network should have a unique IP address:

fbsd1 $ doas ifconfig wg0 inet 192.168.1.100/24
fbsd2 $ doas ifconfig wg0 inet 192.168.1.200/24

We can generate a private key and a corresponding public at the same time. Run the following commands on both nodes:

$ umask 077
$ mkdir -p /usr/local/etc/wireguard/wg
$ cd /usr/local/etc/wireguard/wg
$ wg genkey | tee private.key | wg set wg0 private-key /dev/stdin | wg show wg0 public-key > public.key

Set the listening port on both nodes:

$ doas wg set wg0 listen-port 54321

The public key can be obtain using wg show wg0 public-key; we’ll use it to configure peers. On the first node:

fbsd1 $ doas wg set wg0 peer 'dr5CQaqcpRHa7lxunAQi76mQt0I0nR1SSD4pWDc9ESg=' endpoint 198.51.100.200:54321 allowed-ips 192.168.1.200/32

On the second node:

fbsd2 $ doas wg set wg0 peer 'CYu46J6xV6S19oXVzYFnLMOzXggrslNu7pccgpxmK2Q=' endpoint 198.51.100.100:54321 allowed-ips 192.168.1.100/32

To show current WireGuard configuration and runtime information of specified interface (by default all):

fbsd1 $ wg
interface: wg0
  public key: tDwdK0IoTvLOEHPm3podXzZkk7Aj5zL/Hz0uLZ+Y6TI=
  private key: (hidden)
  listening port: 54321

peer: dr5CQaqcpRHa7lxunAQi76mQt0I0nR1SSD4pWDc9ESg=
  endpoint: 172.16.5.245:54321
  allowed ips: 192.168.1.200/32
  latest handshake: 1 hour, 32 minutes, 29 seconds ago
  transfer: 6.18 KiB received, 6.51 KiB sent

Testing connectivity:

freebsd1 # ping -c 1 192.168.1.200
PING 192.168.1.200 (192.168.1.200): 56 data bytes
64 bytes from 192.168.1.200: icmp_seq=0 ttl=64 time=1.393 ms

--- 192.168.1.200 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.393/1.393/1.393/0.000 ms

and from the second host:

freebsd2 # ping -c 1 192.168.1.100
PING 192.168.1.100 (192.168.1.100): 56 data bytes
64 bytes from 192.168.1.100: icmp_seq=0 ttl=64 time=1.664 ms

--- 192.168.1.100 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.664/1.664/1.664/0.000 ms

Show the current configuration of an interface:

$ wg showconf wg0
[Interface]
ListenPort = 54321
PrivateKey = gEOS22jnlOx7sYtJjiRYTvn/DCNhfNG9XuNkVPzb6ng=

[Peer]
PublicKey = dr5CQaqcpRHa7lxunAQi76mQt0I0nR1SSD4pWDc9ESg=
AllowedIPs = 192.168.1.200/32
Endpoint = 172.16.5.245:54321

Conclusion

FreeBSD has been a trusted operating system for over three decades, powering contemporary servers, desktops, and embedded devices. It is renowned for its powerful networking, security, and storage capabilities and continues to be the platform of choice for many of the world’s most popular websites. WireGuard is a fast and simple way to setup a Virtual Private Network and makes a nice addition to FreeBSD by providing modern cryptography and performance akin or better than competitors such as OpenVPN and IPsec with its smaller codebase, making it easier to audit and keep up to date.

References