Files
fips/docs/design
Johnathan Corgan 8b396b662d Keep the daemon's copy of a native API descriptor until the client holds it
A native API flow's descriptor reaches the client inside a message: an
arrival for a flow a listener accepts, or a connect or listen reply. The
daemon closed its own copy once the message was written, so until the client
read it, the message was the only reference to the socket. xnu's descriptor
collector flushes a socket in that state, and the client then receives a
flow that reads as end of file with the datagrams the daemon held for it
gone. That is the intermittent macOS failure of the two listener tests.

A listener now keeps the daemon's copy of each flow it hands over until the
client's first write on the flow, the listener's close, or the flow's end, on
every platform the listener builds on. The flow is recorded before its reader
starts, so a write already queued cannot race the record. The connection's
serving loop, now a method on the connection so a test can run it over a real
socket, keeps the copy sent in a connect or listen reply until the client's
next command on that connection or the connection's end of file. A client
sends its next command only after reading the reply, so either event means
the descriptor has left the message. The shipped client closes the connection
as soon as it has the reply, so it sees no change.

The cost is accepted and documented: a flow a client accepts and closes
without ever writing stays open, holding its port and a flow slot, until the
listener closes, so a server that refuses flows by dropping them pays for each
one until then; a client speaking the protocol directly that leaves its setup
connection open sees a flow or listener it closes stay open until its next
command or the connection's close. The reference and how-to pages, the client
rustdoc on FipsStream, FipsListener and accept, and the design note say so,
and the security reference records that a remote peer opening flows from many
source ports to such a server can exhaust the node-wide max_flows ceiling.

Tests cover an arrival surviving a provoked collection (deterministic on
macOS), a held flow outliving its dropped descriptor until the listener
closes, a client's write releasing it, a flow its client still holds working
after the listener has closed and let its copy go, and a reply's copy kept
until the next command and let go when the connection ends. The native API
harness asserts the new lifetime of a refused flow. On macOS and FreeBSD the
daemon notices a client's close only when a reader retries its read, up to a
quarter second later, so the test helpers that wait for a close (forgotten,
rebind, settle_closed) retry for up to five seconds by the clock rather than
for a count of yields, and still_open waits two retry intervals there before
asserting a flow is still open.
2026-10-01 22:40:40 +00:00
..
2026-08-30 10:42:59 +00:00
2026-08-30 10:42:59 +00:00

FIPS Design

Architectural and protocol-level explanations for FIPS — the why and the how behind the wire and the system. For wire formats and configuration keys, see reference/. For task recipes, see how-to/. For end-to-end lessons, see tutorials/.

Reading Order

Start with fips-concepts.md for the novice-friendly framing of what FIPS is and why, then move to fips-architecture.md for the protocol stack, identity model, and two-layer encryption walkthrough. From there, follow the protocol stack from bottom to top. After the stack, fips-mesh-operation.md explains how the pieces work together at runtime. Cross-cutting and supporting documents cover specific subsystems in detail.

Foundations

Document Description
fips-concepts.md What FIPS is, why it exists, mental model
fips-architecture.md Protocol stack, identity, two-layer encryption
fips-prior-work.md Designs and protocols FIPS builds on

Protocol Stack

Document Description
fips-transport-layer.md Transport layer: datagram delivery over arbitrary media
fips-mesh-layer.md FIPS Mesh Protocol (FMP): peer authentication, link encryption, forwarding
fips-session-layer.md FIPS Session Protocol (FSP): end-to-end encryption, sessions
fips-ipv6-adapter.md IPv6 adaptation: TUN interface, DNS, MTU enforcement
fips-native-api.md Native datagram API: pubkey-addressed flows over FSP, and what it is instead of the TUN path

Cross-Cutting

Document Description
fips-mmp.md Metrics Measurement Protocol (link + session)
fips-mtu.md Path MTU model, encapsulation overhead, PMTUD
fips-security.md fips0 interface threat model and default-deny baseline

Mesh Behavior

Document Description
fips-mesh-operation.md How the mesh operates: routing, discovery, error recovery
fips-nostr-discovery.md Optional Nostr-mediated peer discovery and UDP NAT hole-punch
port-advertisement-and-nat-traversal.md Nostr-signaled port advertisement and UDP NAT-traversal protocol; generic, with FIPS as an example implementation

Deeper Dives

Document Description
fips-spanning-tree.md Spanning tree algorithms: root discovery, parent selection, coordinates
fips-bloom-filters.md Bloom filter properties: FPR analysis, size classes, split-horizon
spanning-tree-dynamics.md Spanning tree walkthroughs: convergence scenarios, worked examples

Adjacent Components

Document Description
fips-gateway.md fips-gateway service: outbound (LAN-to-mesh) DNS-proxy + virtual-IP NAT and inbound (mesh-to-LAN) port-forwarding, sharing one nftables table