Files
fips/docs/design/fips-configuration.md
T
Johnathan Corgan 04d9fd625d FSP wire format revision and session-layer MMP implementation
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.
2026-02-19 03:15:05 +00:00

328 lines
11 KiB
Markdown

# 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
```text
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:
```yaml
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:
```yaml
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:
```yaml
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:
```yaml
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: []
```