Files
firezone/rust
Thomas Eizinger a5e398b843 fix(connlib): avoid competing and expired WireGuard sessions (#7704)
When `connlib` detects that no data is being sent on a connection, it
enters a "low-power" mode within which timers are set to a much longer
interval than usual. For `boringtun` this moves the timer from 1s to
30s.

At present, this timer also guards, how often we actually update the
timer state within `boringtun`. Instead of following a "only update
exactly when this timer fires"-policy, we now adopt a "update at least
this often"-policy. The difference here is that while we are executing
the `handle_timeout` function, we might as well call into `boringtun`
and update its timer state too.

Another side-effect of this timer is that `boringtun` may not be woken
in time to initiate a rekey when the session expires. WireGuard sessions
without activity expire after 3 minutes. Only the initiater should then
recreate the session. If this doesn't happen in time, the responder
(Gateway) may trigger a keep-alive timeout. Without an active session,
keep-alives also initiate sessions, resulting in us having two competing
sessions.

This fixes the failing test cases added in this PR: There, we ran into a
situation where a WireGuard tunnel idled for so long that the spec
requires the session to expire. In the test, we then sent a packet using
such an expired session but that packet got discarded by the Gateway
because of the expired session. The timers are what check whether a
session is expired:

- By calling `update_timers_at` more often, we can expire the session in
time and `boringtun` will buffer the to-be-sent packet until the new
session is established.
- By deactivating the keep-alive on the Gateway, we ensure that we only
ever have a single WireGuard session active.
- With https://github.com/firezone/boringtun/pull/53, we ensure the
Gateway doesn't initiate a new session in the beginning.
- With https://github.com/firezone/boringtun/pull/51, we ensure the
Client only ever initiates a single session.

To be entirely reliable, we also had to remove the idle WG timer and
update `boringtun`'s state every second. This is unfortunate but can
long-term be fixed by patching WireGuard to tell us, when it exactly
wants to be woken instead of us having to proactively wake it every
second _in case_ it needs to act on a timer.

Related: https://github.com/firezone/boringtun/issues/54.
2025-01-09 15:11:14 +00:00
..
2023-05-10 07:58:32 -07:00

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:

  1. Ensure the binary you are profiling is compiled with the release profile.
  2. sudo perf record -g --freq 10000 --pid $(pgrep <your-binary>).
  3. Run the speed test or whatever load-inducing task you want to measure.
  4. sudo perf script > profile.perf
  5. 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.