Routing All Your Traffic
A less obvious usage, but extremely powerful nonetheless, is to use this characteristic of WireGuard for redirecting all of your ordinary Internet traffic over WireGuard. But first, let's review the old usual solutions for doing this:
The Classic Solutions
The classic solutions rely on different types of routing table configurations. For all of these, we need to set some explicit route for the actual WireGuard endpoint. For these examples, let's assume the WireGuard endpoint is demo.wireguard.com, which, as of writing, resolves to 163.172.161.0. Further, let's assume we usually connect to the Internet using eth0 and the classic gateway of 192.168.1.1.
Replacing The Default Route
The most straightforward technique is to just replace the default route, but add an explicit rule for the WireGuard endpoint:
# ip route del default
# ip route add default dev wg0
# ip route add 163.172.161.0/32 via 192.168.1.1 dev eth0
This works and is relatively straightforward, but DHCP daemons and such like to undo what we've just did, unfortunately.
Overriding The Default Route
So, instead of replacing the default route, we can just override it with two more specific rules that add up in sum to the default, but match before the default:
# ip route add 0.0.0.0/1 dev wg0
# ip route add 128.0.0.0/1 dev wg0
# ip route add 163.172.161.0/32 via 192.168.1.1 dev eth0
This way, we don't clobber the default route. This also works quite well, though, unfortunately when eth0 goes up and down, the explicit route for demo.wireguard.com will be forgotten, which is annoying.
Rule-based Routing
Some folks prefer to use rule-based routing and multiple routing tables. The way this works is we create one routing table for WireGuard routes and one routing table for plaintext Internet routes, and then add rules to determine which routing table to use for each:
# ip rule add to 163.172.161.0 lookup main pref 30
# ip rule add to all lookup 80 pref 40
# ip route add default dev wg0 table 80
Now, we're able to to keep the routing tables separate. Unfortunately the downside is that explicit endpoint rules still need to be added, and there's no cleanup when the interface is removed, and more complicated routing rules now need to be duplicated.
Improved Rule-based Routing
The prior solution relies on us knowing the explicit endpoint IP that should be exempt from the tunnel, but WireGuard endpoints can roam, which means this rule may go stale. Fortunately, we are able to set an fwmark on all packets going out of WireGuard's UDP socket, which will then be exempt from the tunnel:
# wg set wg0 fwmark 1234
# ip route add default dev wg0 table 2468
# ip rule add not fwmark 1234 table 2468
# ip rule add table main suppress_prefixlength 0
We first set the fwmark on the interface and set a default route on an alternative routing table. Then we indicate that packets that do not have the fwmark should go to this alternative routing table. And finally we add a convenience feature for still accessing the local network, whereby we allow packets without the fwmark to use the main routing table, not the WireGuard interface's routing table, if it matches any routes in it with a prefix length greater than zero, such as non-default local routes. This is the technique used by the
wg-quick(8) tool.
Improving the Classic Solutions
The WireGuard authors are interested in adding a feature called "notoif" to the kernel to cover tunnel use cases. This would allow interfaces to say "do not route this packet using myself as an interface, to avoid the routing loop". WireGuard would be able to add a line like .flowi4_not_oif = wg0_idx, and userspace tun-based interfaces would be able to set an option on their outgoing socket like setsockopt(fd, SO_NOTOIF, tun0_idx);. Unfortuantely this hasn't yet been merged, but you can
read the LKML thread here