This is similar to #4097 and #4585 but for the entire `ClientState` and `GatewayState`. We also do it in the context of a property-based test with the vision that we can deterministically explore a large space of state transitions and see where our main property breaks: Being able to send an ICMP packet from the client to the gateway. In other words, we now correctly pass all the `Transmit`s back and forth between the components as if they would receive it from the network. Due to the nature of property-based tests, this already exercises a very large input space. For example, if the client does not have an IPv6 socket and the gateway doesn't have an IPv4 socket, this test already checks whether we then correctly fall back to using a relay (because the allocation we make on the relay is the only network path where the STUN requests pass through). What this does not (yet) do is set up a proper network topology. The `dispatch_transmit` function will happily "route" a `Transmit` from e.g. the client to the gateway even if they are in different subnets. In other words, these tests assume that the actual network itself works and we can exchange UDP packets between the components. For now, we only send ICMPs to CIDR resources. As a next step, we can extend this to DNS resources by sending DNS queries for our DNS resources and then sending an ICMP to the resolved IP.
relay
This crate houses a minimalistic STUN & TURN server.
Features
We aim to support the following feature set:
- STUN binding requests
- TURN allocate requests
- TURN refresh requests
- TURN channel bind requests
- TURN channel data requests
Relaying of data through other means such as DATA frames is not supported.
Building
You can build the relay using: cargo build --release --bin firezone-relay
You should then find a binary in target/release/firezone-relay.
Running
The Firezone Relay supports Linux only. To run the Relay binary on your Linux host:
- Generate a new Relay token from the "Relays" section of the admin portal and save it in your secrets manager.
- Ensure the
FIREZONE_TOKEN=<relay_token>environment variable is set securely in your Relay's shell environment. The Relay expects this variable at startup. - Now, you can start the Firezone Relay with:
firezone-relay
To view more advanced configuration options pass the --help flag:
firezone-relay --help
Ports
The relay listens on port 3478. This is the standard port for STUN/TURN and
not configurable. Additionally, the relay needs to have access to the port range
49152 - 65535 for the allocations.
Portal Connection
When given a token, the relay will connect to the Firezone portal and wait for
an init message before commencing relay operations.
Design
The relay is designed in a sans-IO fashion, meaning the core components do not cause side effects but operate as pure, synchronous state machines. They take in data and emit commands: wake me at this point in time, send these bytes to this peer, etc.
This allows us to very easily unit-test all kinds of scenarios because all inputs are simple values.
The main server runs in a single task and spawns one additional task for each allocation. Incoming data that needs to be relayed is forwarded to the main task where it gets authenticated and relayed on success.