Bug 272842 - Missing WireGuard integration into the base system rc.d scripts
Summary: Missing WireGuard integration into the base system rc.d scripts
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: conf (show other bugs)
Version: 13.2-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL: https://blog.rlwinm.de/the-missing-wi...
Keywords: easy, feature
Depends on:
Blocks:
 
Reported: 2023-07-31 12:28 UTC by crest
Modified: 2024-03-17 16:56 UTC (History)
8 users (show)

See Also:


Attachments
A WireGuard rc.d script (23.72 KB, text/plain)
2023-07-31 12:28 UTC, crest
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description crest 2023-07-31 12:28:50 UTC
Created attachment 243735 [details]
A WireGuard rc.d script

FreeBSD 13.2 and newer include WireGuard support in the base system, but lack an rc.d script to make it easy to take advantage of the imported WireGuard implementation. These are the steps I used before to configure a WireGuard interface: https://blog.rlwinm.de/wireguard-configuration-for-freebsd-13-2 .

As a quality of life improvement I reimplemented most of wg-quick(8) features in /bin/sh as rc.d script: https://gist.githubusercontent.com/Crest/c5f408b8d347f41cf3f84bfee6a9224d/raw/8a1f219bf1957d7e1ecbeaa72998961707e27984/wireguard.sh . More details can be found here: https://blog.rlwinm.de/the-missing-wireguard-integration-into-rc-d-for-freebsd-13-2 .

I did *not* reimplement the saving the configuration or spawning a daemon that continually messes with the routing table since FreeBSD provides better ways to isolate routing tables (multiple FIBs, vnets).
Comment 1 Baptiste Daroussin freebsd_committer freebsd_triage 2023-07-31 13:06:15 UTC
that looks great, I will look into it. would it be possible for you to open a review in phabricator?: https://reviews.freebsd.org so we can interact and comment inline ?

If you prefer this is also doable via a pull request on github.
Comment 2 crest 2023-08-03 18:59:17 UTC
The rc.d script doesn't work as is on 14-CURRENT because the driver inside if_wg.ko has been renamed from just wg to if_wg. Changing the required_modules from "if_wg:wg" to "if_wg:if_wg" is enough.
Comment 3 crest 2023-08-03 19:06:40 UTC
(In reply to crest from comment #2)
As the module was renammed in https://cgit.freebsd.org/src/commit/?id=61b95bcb42993b24633b280791438266d78f2747 to conform to the convention of prefixing virtual interface driver names with "if_".
Comment 4 crest 2023-08-04 10:47:02 UTC
(In reply to Baptiste Daroussin from comment #1)

I submitted the patch for review: https://reviews.freebsd.org/D41318.
Comment 5 Baptiste Daroussin freebsd_committer freebsd_triage 2023-08-04 11:34:58 UTC
I'll release the PR, as I am going afk for a bit of time, to let other the ability to take it in the meantime, I will grab it back if noone merged it, when I will be back online.
Comment 6 Florian Smeets freebsd_committer freebsd_triage 2023-10-15 12:30:01 UTC
I'm wondering how the routes should be set with this script.

None of the two blog posts go into that and the script does not support it if I understand correctly.

I'm in the process of preparing my 14.0 upgrades and replacing the old wireguard/wg-quick script, which set the necessary routes for a configuration that looks like this automatically.

AllowedIPs = 10.10.10.103/32, 172.17.6.0/24, 10.17.6.0/24

If I manually set them everything works; how can we make this automatic?
Comment 7 crest 2023-10-24 17:25:29 UTC
The problem is harder than it looks. The wg-quick script contains an ugly hack that amounts to a daemon monitoring a route socket to allow WireGuard not just collect all peers AllowedIPs per tunnel and add an interface route once, but also resolve conflicts inside a single routing table at runtime which is broken by design. FreeBSD has the required features (setfib, vnet) to express such a setup without fragile racy hacks or shells scripts with O(n^2) overhead (with n = number of routes).

This is the third version of this shell script and I removed a few features because the rc.d script ran into Greenspun's tenth rule and turned /bin/sh into a dynamically scoped LISP. That version contained higher order functions to loop over peers and their settings for use in the {Pre,Post}x{Up,Down} hooks which would make it trivial to inject the routes from the PostUp hook.

The version I've submitted in this PR lacks such features. To automate it using this rc.d script you have to parse the WireGuard configuration inside a hook. It implements both the wg-quick style hooks (it executes them in /bin/sh instead of /bin/bash) and well as call into /etc/rc.d/netif allowing all the usual ways to hook interfaces configuration changes to work too.

I can dig out the "semi sentient" rc.d script if you really want to dig through it, but the version in this PR already contains code to extract only the fields understood by the kernel from a wg-quick configuration. As long as you only want to collect the AllowedIPs per interface without preserving which peer they belong to collecting the AllowedIPs into a single variable would work the same as collecting multiple Address lines into a single variable.
Comment 8 crest 2023-10-26 14:09:14 UTC
Just to spell out the implications of calling /etc/rc.d/netif from the wireguard rc.d script: Static routing works for WireGuard tunnels like any other interface via rc.conf. If you need just three routes you can use something like this:

sysrc static_routes+=" route1:wg0 route2:wg0 route3:wg0"
sysrc route_route1="10.10.10.103/32 -iface wg0"
sysrc route_route2="172.17.6.0/24 -iface wg0"
sysrc route_route3="10.17.6.0/24 -iface wg0"

to have netif call routing to set up static routes tied to a specific interface. The routes only need a next hop interface because from kernel IP stack point of view WireGuard interfaces are point to point interfaces. The next hop resolution on among the peers is done according to the peer AllowedIPs configuration. The details of this so call cryptokey routing are documented in the WireGuard whitepaper. It may be a layering violation offending purists, but I prefer it over the complicated fragile Cisco style DM-VPN with NHRP providing dynamic multi-point GRE next-hop resolution (or not).