Understanding modern Linux routing (and wg-quick)
ro-che.info
ro-che.info
Isn't this the same problem the old VPN problems had though? If it fails to delete its two rules then your routing is still boned.
For comparison OpenVPN doesn't use the ip rule infrastructure, instead it installs two rules directly on your routing table, but not for 0.0.0.0/0. Instead it installs rules for 0.0.0.0/1 and 128.0.0.0/1, creating a rule that has slightly higher priority than the default route so it can leave the default in place and not get burned with NetworkManager decides to delete and re-add the default route for whatever reason.
Not having the routes cleaned up after the VPN exits is usually not the problem, as they are tied to the TUN interface and get cleaned up by the kernel when that interface is destroyed anyway. The bigger issue is clients that forget to install the host route to the VPN endpoint. I see that error a lot and it always drives people crazy because their VPN client negotiates and connects properly, and then everything breaks for no obvious reason.
The host route to the VPN endpoint is sometimes there, but sometimes it's to a p-2-p interface, sometimes just the local device IP. Depends on the OS, tunnel interface, routes, etc.
I'm curious is the priority you referring to just longest prefix match by having two /1s, or are you referring to something else like setting a metric on the interface?
More specific prefix isn’t slightly better, prefix length is one of the most significant rules of routing. This trick is quite common in networking - you point more specific routes to the main link and less specific to a backup. It the main link go down the specifics are getting withdrawn (some mechanism like dynamic routing should be in place for that) and the less specific route takes place, redirecting the traffic over the backup link.
But tbh I see it as something of a “hack”. My gut tells me it’s not the right way for something like OpenVPN to do by default.
A metric would be better on 0/0, but I can see how the two /1 routes is gonna fix things in a whole bunch of edge cases.
> Isn't this the same problem the old VPN problems had though? If it fails to delete its two rules then your routing is still boned.
You're right, that's not the reason.
The real reason WireGuard doesn't use the traditional technique of replacing the default route is, straight from the horse's mouth https://www.wireguard.com/netns/:
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*.
And right below that, is the reason WireGuard doesn't use the OpenVPN technique: 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*.
Both emphases mine.Most I found still use old and outdated commands, or don't really explain thing in depth.
[1] Book Review: Linux Routers - A Primer for Network Administrators, 2nd Ed
It's high time for somebody to write a guide to linux networking.
The closest thing to a comprehensive guide is the Linux Advanced Routing & Traffic Control HOWTO (https://lartc.org) but the last update (as far as I can tell from the website) is from 2012.
You're right that a new, easy to read guide is needed, but I think it would have to be just a website.
The tools you need for Linux networking, mostly ip and tc, are as crude-but-powerful as they were 20 years ago, but now have much more functionality and complexity. Things are actively getting worse: a tool like brctl (bridge control) was obsoleted for the same functionality in iproute2 -- but brctl was much more intuitive to use.
Some nicer frontends than iproute2 would really help here.
This also allows to isolate the DNS queries by bind-mounting nsswitch.conf and resolv.conf as well as manage the isolated firewall for the namespace.
This can become important if you want to have redundant gateways or something like that - you can have overlapping AllowedIPs, it just won't work out of the box with wg-quick.
For example, systemd-networkd started also adding routes by default in v250 but (rightly so IMO[0]) reverted to not doing it in 250.3.
[0]: This comment captures it quite well: https://github.com/systemd/systemd/issues/14176#issuecomment...
Naive approach does not work: wireguard establishes connection and if backend server changes, this connection stuck for a few minutes until wireguard decided to establish new connection. Persistent Keep Alive does not help for some reason. Eventually it'll re-establish new session and will work from now on, but this delay is unacceptable.
- High Availability WireGuard on AWS [https://www.procustodibus.com/blog/2021/02/ha-wireguard-on-a...]
- High Availability WireGuard on Azure [https://www.procustodibus.com/blog/2021/06/ha-wireguard-on-a...]
- High Availability WireGuard Site to Site [https://www.procustodibus.com/blog/2021/10/ha-wireguard-site...]
An additional "fun fact" is that 51820 is also the default port number used by WireGuard servers.
I’ve been trying to use Tailscale together with my company’s enterprisey CloudFlare VPN and Tailscale rules never seem to evaluate, even with split tunneling etc enabled. Need to dig into those routing tables one of these days…