mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-28 02:18:50 +00:00
## Context On Linux, we create a dedicated routing table for all routes of the Firezone TUN device, including the `0.0.0.0/0` route. At a minimum, this routing table contains the following if the Internet Resource is active: ``` > ip route show table 539098368 default dev tun-firezone proto static 100.64.0.0/11 dev tun-firezone proto static 100.96.0.0/11 dev tun-firezone proto static 100.100.111.0/24 dev tun-firezone proto static ``` In addition, we also create a routing rule that bypasses this routing table for all packets that are tagged with the `0xfd002021` mark: ``` > ip rule list 0: from all lookup local 32765: not from all fwmark 0xfd002021 lookup 539098368 32766: from all lookup main 32767: from all lookup default ``` Firezone's internal UDP and TCP sockets are tagged with this mark and thus prevent routing loops where our own packets would otherwise get redirected back into the tunnel. Without the Internet Resource active, the rule `from all lookup main` triggers for local LAN traffic and correctly route the traffic out via that interface. For example, on my computer, the Linux kernel created the following route with the `link` scope in the main table: ``` 192.168.188.0/24 dev wlp192s0 proto kernel scope link src 192.168.188.112 metric 600 ``` ## The problem With the Internet Resource active, there is a problem. The default route matches ALL destinations, including those for local LAN destinations which should actually be sent out via a different interface. As a result, local LAN traffic is broken on Linux as soon as the Internet Resource is active. Instead of being sent out via the local interface, these packets get sent to `tun-firezone` where they get forwarded to the Gateway and then dropped because their source IP is not a Firezone Client IP. ## Solution Fixing this is unfortunately non-trivial. The best I could come up with is to create a copy of all link-scoped routes in the Firezone routing table and keep those in sync with all route changes that happen. For example, when we roam, the link-scoped routes obviously change because we join a new subnet. We therefore listen to change-events from netlink and create a debounced task that reads the current link-scoped routes from the main routing table, compares it to the ones in the Firezone table and adds any routes not present. We don't need to worry about removing routes as link-scoped routes automatically disappear once the resulting interface goes away. --------- Signed-off-by: Thomas Eizinger <thomas@eizinger.io> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>