FSP wire format revision (TASK-2026-0007): Introduce the FIPS Session Protocol (FSP) wire format with a 4-byte common prefix [ver_phase:1][flags:1][payload_len:2 LE] replacing the old 1-byte msg_type dispatch. All session messages share this prefix with phase-based dispatch (Established, Setup, Ack, Unencrypted). - New session_wire.rs: FSP constants, header types, parse/build helpers - SessionMessageType enum: DataPacket (0x10), SenderReport (0x11), ReceiverReport (0x12), PathMtuNotification (0x13) - FspFlags (CP/K/U) and FspInnerFlags (SP) for flag management - SessionSenderReport, SessionReceiverReport, PathMtuNotification message structs with encode/decode - FSP send pipeline: 12-byte header as AAD, 6-byte inner header (timestamp + msg_type + inner_flags), encrypt_with_aad() - FSP receive pipeline: parse header, extract cleartext coords (CP), AEAD decrypt with AAD, strip inner header, msg_type dispatch - Forwarding: transit nodes parse cleartext coords without decryption - Removed DataPacket struct and associated types - SessionEntry: session_start_ms, mark_established(), session_timestamp() - FIPS_OVERHEAD: 144 → 150 bytes (+6 for FSP inner header) - Design docs updated for new wire format Session-layer MMP implementation (TASK-2026-0008): Implement complete session-layer MMP reusing the link-layer algorithm modules (SenderState, ReceiverState, MmpMetrics, SpinBitState) with independent configuration and higher report interval clamps. - SessionMmpConfig: separate config section (node.session_mmp.*) - MmpSessionState: session-specific wrapper with PathMtuState tracking - Session-layer constants (500ms-10s report intervals, 1s cold start) - Parameterized interval methods (new_with_cold_start, update_report_interval_with_bounds) on SenderState/ReceiverState - Bidirectional From conversions between link/session report types - SessionEntry: mmp and is_initiator fields, initialized on Established - send_session_msg() for reports/notifications - Per-message RX recording with spin bit state tracking - Handlers for SenderReport, ReceiverReport, PathMtuNotification - path_mtu threaded from SessionDatagram envelope through to handlers - check_session_mmp_reports() tick handler with collect-then-send pattern - Periodic and teardown operator logging for session metrics - PathMtuState: destination observes incoming MTU on all session messages, source seeded from outbound transport MTU, decrease-immediate / increase-requires-3-consecutive rules Link-layer MMP fix: - Stop feeding spin bit RTT samples into SRTT estimator; inter-frame timing in the mesh is irregular, inflating spin-bit RTT by variable processing delays; timestamp-echo provides accurate RTT 29 files changed, 602 tests pass, 0 clippy warnings.
11 KiB
FIPS Configuration
FIPS uses YAML-based configuration with a cascading multi-file priority system. All parameters have sensible defaults; a node can run with no configuration file at all (it will generate an ephemeral identity and listen on default addresses).
Configuration Loading
Search Paths
When started without the -c flag, FIPS searches for fips.yaml in these
locations, lowest to highest priority:
| Priority | Path | Purpose |
|---|---|---|
| 1 (lowest) | /etc/fips/fips.yaml |
System-wide defaults |
| 2 | ~/.config/fips/fips.yaml |
User preferences |
| 3 | ~/.fips.yaml |
Legacy user config |
| 4 (highest) | ./fips.yaml |
Deployment-specific overrides |
All found files are loaded and merged in priority order. Values from higher
priority files override those from lower priority files. This allows a system
administrator to set site-wide defaults in /etc/fips/fips.yaml while
individual deployments override specific values in ./fips.yaml.
CLI Option
fips -c /path/to/config.yaml
When -c is specified, only that file is loaded (search paths are skipped).
Partial Configuration
Every field has a built-in default. A configuration file only needs to specify values that differ from defaults. For example, a minimal config might contain only the identity and peer list, inheriting all other defaults.
YAML Structure
The configuration is organized into five top-level sections:
node: # Node behavior, protocol parameters, and tuning
tun: # TUN virtual interface
dns: # DNS responder for .fips domain
transports: # Network transports (UDP, future: TCP, Tor)
peers: # Static peer list
All tunable protocol parameters live under node.*, organized as sysctl-style
dotted paths. The top-level sections (tun, dns, transports, peers)
handle infrastructure concerns only.
Node Parameters (node.*)
Identity (node.identity.*)
| Parameter | Type | Default | Description |
|---|---|---|---|
node.identity.nsec |
string | (generate random) | Hex-encoded secret key. If omitted, an ephemeral identity is generated on each start. |
General
| Parameter | Type | Default | Description |
|---|---|---|---|
node.leaf_only |
bool | false |
Leaf-only mode: node does not forward traffic or participate in routing |
node.tick_interval_secs |
u64 | 1 |
Periodic maintenance tick interval (retry checks, timeout cleanup, tree refresh) |
node.base_rtt_ms |
u64 | 100 |
Initial RTT estimate for new links before measurements converge |
Resource Limits (node.limits.*)
Controls capacity for connections, peers, and links.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.limits.max_connections |
usize | 256 |
Max handshake-phase connections |
node.limits.max_peers |
usize | 128 |
Max authenticated peers |
node.limits.max_links |
usize | 256 |
Max active links |
node.limits.max_pending_inbound |
usize | 1000 |
Max pending inbound handshakes |
Rate Limiting (node.rate_limit.*)
Handshake rate limiting protects against DoS on the Noise IK handshake path.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.rate_limit.handshake_burst |
u32 | 100 |
Token bucket burst capacity |
node.rate_limit.handshake_rate |
f64 | 10.0 |
Tokens per second refill rate |
node.rate_limit.handshake_timeout_secs |
u64 | 30 |
Stale handshake cleanup timeout |
Retry / Backoff (node.retry.*)
Connection retry with exponential backoff.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.retry.max_retries |
u32 | 5 |
Max connection retry attempts |
node.retry.base_interval_secs |
u64 | 5 |
Base backoff interval |
node.retry.max_backoff_secs |
u64 | 300 |
Cap on exponential backoff (5 minutes) |
Cache Parameters (node.cache.*)
Controls caching of tree coordinates and identity mappings.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.cache.coord_size |
usize | 50000 |
Max entries in coordinate cache |
node.cache.coord_ttl_secs |
u64 | 300 |
Coordinate cache entry TTL (5 minutes) |
node.cache.identity_size |
usize | 10000 |
Max entries in identity cache (LRU, no TTL) |
Discovery Protocol (node.discovery.*)
Controls flood-based node discovery (LookupRequest/LookupResponse).
| Parameter | Type | Default | Description |
|---|---|---|---|
node.discovery.ttl |
u8 | 64 |
Hop limit for LookupRequest flood |
node.discovery.timeout_secs |
u64 | 10 |
Lookup completion timeout |
node.discovery.recent_expiry_secs |
u64 | 10 |
Dedup cache expiry for recent request IDs |
Spanning Tree (node.tree.*)
Controls tree construction and parent selection.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.tree.announce_min_interval_ms |
u64 | 500 |
Per-peer TreeAnnounce rate limit |
node.tree.parent_switch_threshold |
usize | 1 |
Min depth improvement required to switch parents |
Bloom Filter (node.bloom.*)
| Parameter | Type | Default | Description |
|---|---|---|---|
node.bloom.update_debounce_ms |
u64 | 500 |
Debounce interval for filter update propagation |
Bloom filter size (1 KB), hash count (5), and size classes are protocol constants and not configurable.
Session / Data Plane (node.session.*)
Controls end-to-end session behavior and packet queuing.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.session.default_hop_limit |
u8 | 64 |
Default SessionDatagram hop limit |
node.session.pending_packets_per_dest |
usize | 16 |
Queue depth per destination during session establishment |
node.session.pending_max_destinations |
usize | 256 |
Max destinations with pending packets |
node.session.idle_timeout_secs |
u64 | 90 |
Idle session timeout; established sessions with no activity for this duration are removed |
node.session.coords_warmup_packets |
u8 | 5 |
Number of initial data packets per session that include the CP flag for transit cache warmup; also the reset count on CoordsRequired receipt |
The anti-replay window size (2048 packets) is a compile-time constant and not configurable.
Internal Buffers (node.buffers.*)
Channel sizes affecting throughput and memory. Primarily useful for performance tuning under high load or on memory-constrained devices.
| Parameter | Type | Default | Description |
|---|---|---|---|
node.buffers.packet_channel |
usize | 1024 |
Transport to Node packet channel capacity |
node.buffers.tun_channel |
usize | 1024 |
TUN to Node outbound channel capacity |
node.buffers.dns_channel |
usize | 64 |
DNS to Node identity channel capacity |
TUN Interface (tun.*)
| Parameter | Type | Default | Description |
|---|---|---|---|
tun.enabled |
bool | false |
Enable TUN virtual interface |
tun.name |
string | "fips0" |
Interface name |
tun.mtu |
u16 | 1280 |
Interface MTU (IPv6 minimum) |
DNS Responder (dns.*)
Resolves <npub>.fips queries to FIPS IPv6 addresses. Resolution is pure
computation (npub to public key to address); resolved identities are registered
with the node for routing.
| Parameter | Type | Default | Description |
|---|---|---|---|
dns.enabled |
bool | false |
Enable DNS responder |
dns.bind_addr |
string | "127.0.0.1" |
Bind address |
dns.port |
u16 | 5354 |
Listen port |
dns.ttl |
u32 | 300 |
AAAA record TTL in seconds |
The dns.ttl value should not exceed node.cache.coord_ttl_secs to avoid
stale address mappings.
Transports (transports.*)
UDP (transports.udp.*)
| Parameter | Type | Default | Description |
|---|---|---|---|
transports.udp.bind_addr |
string | "0.0.0.0:4000" |
UDP bind address and port |
transports.udp.mtu |
u16 | 1280 |
Transport MTU |
Peers (peers[])
Static peer list. Each entry defines a peer to connect to.
| Parameter | Type | Default | Description |
|---|---|---|---|
peers[].npub |
string | (required) | Peer's Nostr public key (npub-encoded) |
peers[].alias |
string | (none) | Human-readable name for logging |
peers[].addresses[].transport |
string | (required) | Transport type (udp) |
peers[].addresses[].addr |
string | (required) | Transport address (e.g., "10.0.0.2:4000") |
peers[].addresses[].priority |
u8 | 100 |
Address priority (lower = preferred) |
peers[].connect_policy |
string | "auto_connect" |
Connection policy: auto_connect, on_demand, or manual |
Minimal Example
A typical node configuration enabling TUN, DNS, and a single peer:
node:
identity:
nsec: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
port: 53
transports:
udp:
bind_addr: "0.0.0.0:4000"
mtu: 1197
peers:
- npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le"
alias: "node-b"
addresses:
- transport: udp
addr: "172.20.0.11:4000"
connect_policy: auto_connect
All node.* parameters use their defaults. To override specific values, add
only the relevant sections:
node:
identity:
nsec: "..."
limits:
max_peers: 64
retry:
max_retries: 10
max_backoff_secs: 600
cache:
coord_size: 100000
Complete Reference
The full YAML structure with all defaults:
node:
identity:
nsec: null # hex secret key (null = generate ephemeral)
leaf_only: false
tick_interval_secs: 1
base_rtt_ms: 100
limits:
max_connections: 256
max_peers: 128
max_links: 256
max_pending_inbound: 1000
rate_limit:
handshake_burst: 100
handshake_rate: 10.0
handshake_timeout_secs: 30
retry:
max_retries: 5
base_interval_secs: 5
max_backoff_secs: 300
cache:
coord_size: 50000
coord_ttl_secs: 300
identity_size: 10000
discovery:
ttl: 64
timeout_secs: 10
recent_expiry_secs: 10
tree:
announce_min_interval_ms: 500
parent_switch_threshold: 1
bloom:
update_debounce_ms: 500
session:
default_hop_limit: 64
pending_packets_per_dest: 16
pending_max_destinations: 256
idle_timeout_secs: 90
coords_warmup_packets: 5
buffers:
packet_channel: 1024
tun_channel: 1024
dns_channel: 64
tun:
enabled: false
name: "fips0"
mtu: 1280
dns:
enabled: false
bind_addr: "127.0.0.1"
port: 5354
ttl: 300
transports:
udp:
bind_addr: "0.0.0.0:4000"
mtu: 1280
peers: []