Commit Graph

2 Commits

Author SHA1 Message Date
Thomas Eizinger
58fe527b0e feat(connlib): mirror ECN bits on TUN device (#8511)
From the perspective of any application, Firezone is a layer-3 network
and will thus use the host's networking stack to form IP packets for
whichever application protocol is in use (UDP, TCP, etc). These packets
then get encapsulated into UDP packets by Firezone and sent to a
Gateway.

As a result of this design, the IP header seen by the networking stacks
of the Client and the receiving service are not visible to any
intermediary along the network path of the Client and Gateway.

In case this network path is congested and middleboxes such as routers
need to drop packets, they will look at the ECN bits in the IP header
(of the UDP packet generated by a Client or Gateway) and flip a bit in
case the previous value indicated support for ECN (`0x01` or `0x10`).
When received by a network stack that supports ECN, seeing `0x11` means
that the network path is congested and that it must reduce its
send/receive windows (or otherwise throttle the connection).

At present, this doesn't work with Firezone because of the
aforementioned encapsulation of IP packets. To support ECN, we need to
therefore:

- Copy ECN bits from a received IP packet to the datagram that
encapsulates it: This ensures that if the Client's network stack support
ECN, we mirror that support on the wire.
- Copy ECN bits from a received datagram to the IP packet the is sent to
the TUN device: This ensures that if the "Congestion Experienced" bit
get set along the network path between Client and Gateway, we reflect
that accordingly on the IP packet emitted by the TUN device.

Resolves: #3758

---------

Signed-off-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
2025-03-26 20:55:51 +00:00
Thomas Eizinger
d1d0874699 refactor(rust): introduce etherparse-ext crate (#8500)
Within Firezone's Rust codebase, we use the `etherparse` crate
extensively to parse network packets. To provide a more ergonomic API,
this is all encapsulated in our `ip-packet` crate.

For #7518, we need to write an eBPF kernel that parses and manipulates
network packets. Etherparse itself doesn't provide any facilities to
manipulate network packets. That is an open feature request:
https://github.com/JulianSchmid/etherparse/issues/9. For the packet
manipulation that we are doing in `connlib`, we already wrote certain
extensions to the `etherparse` crate but today, those are all within the
`ip-packet` crate.

In order to reuse that within the eBPF kernel, we cannot just depend on
`ip-packet` directly because eBPF is a no-std and no-alloc environment,
thus no crate in the dependency tree is allowed to depend on Rust's
std-lib. `etherparse` itself actually has an `std` feature flag that we
can turn off. Introducing the same in `ip-packet` would require a lot of
conditional-compilation gates using `#[cfg]`. it is much easier to just
introduce a new crate that houses all our in-house extensions to
`etherparse`. Eventually, we can hopefully upstream those which is
another motivator to separate this out.
2025-03-25 22:33:14 +00:00