mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
Rename FIPS Link Protocol (FLP) to FIPS Mesh Protocol (FMP)
The "Link Protocol" name understated the layer's scope — spanning tree
construction, bloom filter routing, greedy forwarding, and mesh-wide
coordination go well beyond link-level concerns. Rename fips-link-layer.md
to fips-mesh-layer.md, update FLP→FMP throughout docs and source code
(FLP_VERSION→FMP_VERSION, wire.rs, rx_loop.rs, spanning_tree.rs).
New SVG illustrations
- Protocol stack: color-coded layer diagram replacing ASCII art
- OSI mapping: side-by-side comparison with traditional networking layers
- Bloom filter propagation: 6-node tree with sender-colored filter boxes
showing split-horizon computation per link
- Routing decision flowchart: 5-step priority chain with candidate ranking
by tree distance and link performance
- Coordinate discovery: sequence diagram showing LookupRequest propagation,
response caching, and SessionSetup cache warming
Redesigned existing SVGs
- Architecture overview: uniform node layout, U-shaped encrypted link
connectors, separate end-to-end session line
- Node architecture: split Router Core into FSP and FMP layers, reorganize
transports into Overlay/Shared Medium/Point-to-Point categories
- Identity derivation: wider boxes, visible encode arrow, dashed npub line
fips-intro.md revisions
- Add inline references to prior work: Yggdrasil/Ironwood for coordinate
routing, Noise Protocol Framework for IK handshakes, WireGuard for
index-based session dispatch, Wikipedia for bloom filters, split-horizon,
and greedy embedding
- Add explanatory paragraphs after bloom filter diagram describing
split-horizon filter computation and candidate selection behavior
- Simplify transport abstraction language, remove I2P/LoRa references
- Fix LookupRequest wording ("propagates" not "floods"), note intermediate
node coordinate caching on lookup responses
- Rewrite architecture overview prose to match redesigned diagrams
388 lines
14 KiB
Markdown
388 lines
14 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 |
|
|
| `node.heartbeat_interval_secs` | u64 | `10` | Heartbeat send interval per peer for liveness detection |
|
|
| `node.link_dead_timeout_secs` | u64 | `30` | No-traffic timeout before a peer is declared dead and removed |
|
|
|
|
### 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 |
|
|
| `node.rate_limit.handshake_resend_interval_ms` | u64 | `1000` | Initial handshake message resend interval |
|
|
| `node.rate_limit.handshake_resend_backoff` | f64 | `2.0` | Resend backoff multiplier (1s, 2s, 4s, 8s, 16s with defaults) |
|
|
| `node.rate_limit.handshake_max_resends` | u32 | `5` | Max resends per handshake attempt |
|
|
|
|
### 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) |
|
|
|
|
Auto-reconnect (triggered by MMP link-dead removal) uses the same backoff
|
|
parameters but bypasses `max_retries`, retrying indefinitely. See
|
|
`peers[].auto_reconnect` below.
|
|
|
|
### 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_ttl` | u8 | `64` | Default SessionDatagram TTL |
|
|
| `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 application data for this duration are removed. MMP reports (SenderReport, ReceiverReport, PathMtuNotification) do not count as activity |
|
|
| `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/PathBroken receipt |
|
|
| `node.session.coords_response_interval_ms` | u64 | `2000` | Minimum interval (ms) between standalone CoordsWarmup responses to CoordsRequired/PathBroken signals per destination |
|
|
|
|
The anti-replay window size (2048 packets) is a compile-time constant and not
|
|
configurable.
|
|
|
|
### Link-Layer MMP (`node.mmp.*`)
|
|
|
|
Metrics Measurement Protocol for per-peer link measurement. See
|
|
[fips-mesh-layer.md](fips-mesh-layer.md) for behavioral details.
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `node.mmp.mode` | string | `"full"` | Operating mode: `full` (sender + receiver reports), `lightweight` (receiver reports only), or `minimal` (spin bit + CE echo only, no reports) |
|
|
| `node.mmp.log_interval_secs` | u64 | `30` | Periodic operator log interval for link metrics |
|
|
| `node.mmp.owd_window_size` | usize | `32` | One-way delay trend ring buffer size |
|
|
|
|
### Session-Layer MMP (`node.session_mmp.*`)
|
|
|
|
Metrics Measurement Protocol for end-to-end session measurement. Configured
|
|
independently from link-layer MMP because session reports are routed through
|
|
every transit link, consuming bandwidth proportional to path length.
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `node.session_mmp.mode` | string | `"full"` | Operating mode: `full`, `lightweight`, or `minimal` |
|
|
| `node.session_mmp.log_interval_secs` | u64 | `30` | Periodic operator log interval for session metrics |
|
|
| `node.session_mmp.owd_window_size` | usize | `32` | One-way delay trend ring buffer size |
|
|
|
|
### 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 |
|
|
| `transports.udp.recv_buf_size` | usize | `2097152` | UDP socket receive buffer size in bytes (2 MB). Linux kernel doubles the requested value internally. Host `net.core.rmem_max` must be >= this value. |
|
|
| `transports.udp.send_buf_size` | usize | `2097152` | UDP socket send buffer size in bytes (2 MB). Host `net.core.wmem_max` must be >= this value. |
|
|
|
|
## 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` |
|
|
| `peers[].auto_reconnect` | bool | `true` | Automatically reconnect after MMP link-dead removal (exponential backoff, unlimited retries) |
|
|
|
|
## 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
|
|
heartbeat_interval_secs: 10
|
|
link_dead_timeout_secs: 30
|
|
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
|
|
handshake_resend_interval_ms: 1000
|
|
handshake_resend_backoff: 2.0
|
|
handshake_max_resends: 5
|
|
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_ttl: 64
|
|
pending_packets_per_dest: 16
|
|
pending_max_destinations: 256
|
|
idle_timeout_secs: 90
|
|
coords_warmup_packets: 5
|
|
coords_response_interval_ms: 2000
|
|
mmp:
|
|
mode: full # full | lightweight | minimal
|
|
log_interval_secs: 30
|
|
owd_window_size: 32
|
|
session_mmp:
|
|
mode: full # full | lightweight | minimal
|
|
log_interval_secs: 30
|
|
owd_window_size: 32
|
|
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
|
|
recv_buf_size: 2097152 # 2 MB (kernel doubles to 4 MB actual)
|
|
send_buf_size: 2097152 # 2 MB
|
|
|
|
peers: # static peer list
|
|
# - npub: "npub1..."
|
|
# alias: "node-b"
|
|
# addresses:
|
|
# - transport: udp
|
|
# addr: "10.0.0.2:4000"
|
|
# priority: 100
|
|
# connect_policy: auto_connect
|
|
# auto_reconnect: true # reconnect after link-dead removal
|
|
```
|