· via Hacker News – Front Page (native)
Firezone releases sanstun, a sans-IO WireGuard implementation in Rust
Firezone has released sanstun, a Rust library implementing the WireGuard state machine with no built-in IO, aiming for testability, type-safe protocol handling and parallel-friendly encryption.
Firezone has announced sanstun, a new userspace implementation of the WireGuard protocol written in Rust. The library implements the WireGuard state machine as a sans-IO component, meaning it performs no network, file, timing or randomness operations itself, and exposes an API that the company describes as parallel-friendly and idiomatic, with a focus on ease of use, security and performance.
A library that does no IO
Sans-IO is a design philosophy in which side effects are kept strictly separate from state and business logic. As Firezone explains, that means not only file and network operations but also time and randomness: a sans-IO component is handed timestamps and random values rather than fetching them itself. According to the announcement, such components compose well, are comparatively easy to test, avoid the function-coloring problems associated with async/await, and fit naturally with Rust's ownership rules. The pattern is not Rust-specific, Firezone notes, and can be applied in any language.
Grown out of two years of patching boringtun
Sanstun emerged from Firezone's experience with boringtun, the implementation the company originally adopted. Over more than two years of production use, the team accumulated over 70 pull requests on their fork, excluding dependency bumps — fixing edge cases, adding APIs and making behaviour configurable. Keeping full API compatibility with upstream grew increasingly difficult as product requirements evolved, and the fork eventually became the blueprint for a fresh library.
Two lessons shaped the new API. First, Firezone made time handling sans-IO by adding API variants that accept an explicit timestamp, which is what makes it possible to simulate an entire system accurately. Second, it removed internal buffering. Boringtun would queue packets while a session was being established and required callers to drain that buffer by invoking a parse function with an empty datagram — an approach Firezone found unintuitive and allocation-heavy. Sanstun does not buffer at all: if you send a packet before a session exists, buffering it is the caller's responsibility.
Enforcing WireGuard's rules in the type system
The API is built around two types: an Interface, identified by a single key, and Tunnels, which represent connections between interfaces. Every inbound UDP datagram must pass through Interface::receive, the only public function that parses a raw datagram. It parses the header, verifies the message authentication code, checks cookies, applies rate limits, and returns an enum with one variant per WireGuard message type — or a cookie reply to send when the interface is under load.
The design maps protocol invariants onto types so that certain bugs cannot compile. WireGuard is vulnerable to CPU exhaustion: an attacker who knows an endpoint's public key can flood it with bogus handshake initiations, and the receiver must run its half of the Diffie-Hellman exchange before detecting the forgery. The protocol's defense is a cookie mechanism that proves ownership of the claimed source IP, enabling per-IP rate limiting that applies across a whole interface. In sanstun, the message types returned by Interface::receive, such as HandshakeInitiation, have crate-private constructors, so the only way to obtain one is through the rate-limited entry point — forgetting the limiter is not a mistake you can ship. Routing errors get similar treatment: handshake initiations are matched by the initiator's static public key, while other messages carry a session index that identifies both the tunnel and the session within it.
Outbound packets go through a single encapsulation entry point, timers are advanced and polled explicitly, and handshakes can be initiated at any time. Firezone also highlights the parallel-friendly API for encryption and decryption as one of the library's standout features.
Why it matters
Usable userspace WireGuard implementations are scarce, and Firezone's experience illustrates the maintenance cost of bending an existing one to new requirements. For developers embedding WireGuard in VPN clients, gateways or test harnesses, a library that separates protocol logic from IO, makes timers explicit, and enforces rate limiting at the type level lowers both the testing burden and the risk of shipping subtle protocol bugs. Beyond WireGuard itself, sanstun is a concrete case study in how sans-IO architecture can turn a network protocol into a composable, deterministic and safe building block.
- #rust
- #wireguard
- #vpn
- #networking
- #security