## 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>
Rust development guide
Firezone uses Rust for all data plane components. This directory contains the Linux and Windows clients, and low-level networking implementations related to STUN/TURN.
We target the last stable release of Rust using rust-toolchain.toml.
If you are using rustup, that is automatically handled for you.
Otherwise, ensure you have the latest stable version of Rust installed.
Reading Client logs
The Client logs are written as JSONL for machine-readability.
To make them more human-friendly, pipe them through jq like this:
cd path/to/logs # e.g. `$HOME/.cache/dev.firezone.client/data/logs` on Linux
cat *.log | jq -r '"\(.time) \(.severity) \(.message)"'
Resulting in, e.g.
2024-04-01T18:25:47.237661392Z INFO started log
2024-04-01T18:25:47.238193266Z INFO GIT_VERSION = 1.0.0-pre.11-35-gcc0d43531
2024-04-01T18:25:48.295243016Z INFO No token / actor_name on disk, starting in signed-out state
2024-04-01T18:25:48.295360641Z INFO null
Benchmarking on Linux
The recommended way for benchmarking any of the Rust components is Linux' perf utility.
For example, to attach to a running application, do:
- Ensure the binary you are profiling is compiled with the
releaseprofile. sudo perf record -g --freq 10000 --pid $(pgrep <your-binary>).- Run the speed test or whatever load-inducing task you want to measure.
sudo perf script > profile.perf- Open profiler.firefox.com and load
profile.perf
Instead of attaching to a process with --pid, you can also specify the path to executable directly.
That is useful if you want to capture perf data for a test or a micro-benchmark.