mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
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.
This commit is contained in:
@@ -148,7 +148,7 @@ Controls end-to-end session behavior and packet queuing.
|
||||
| `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 DataPackets per session that include COORDS_PRESENT for transit cache warmup; also the reset count on CoordsRequired receipt |
|
||||
| `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.
|
||||
|
||||
@@ -121,13 +121,14 @@ after all layers of wrapping.
|
||||
| ----- | -------- | ------- |
|
||||
| Link encryption | 37 bytes | 16-byte outer header + 5-byte inner header + 16-byte AEAD tag |
|
||||
| SessionDatagram envelope | 36 bytes | type + ttl + path_mtu + src_addr + dest_addr |
|
||||
| DataPacket header | 12 bytes | type + flags + counter + payload_len |
|
||||
| Session encryption | 16 bytes | ChaCha20-Poly1305 AEAD tag |
|
||||
| **Minimal total** | **101 bytes** | |
|
||||
| FSP header | 12 bytes | 4-byte prefix + 8-byte counter (used as AEAD AAD) |
|
||||
| FSP inner header | 6 bytes | 4-byte timestamp + 1-byte msg_type + 1-byte inner_flags (inside AEAD) |
|
||||
| Session AEAD tag | 16 bytes | ChaCha20-Poly1305 tag on session-encrypted payload |
|
||||
| **Minimal total** | **107 bytes** | |
|
||||
| Coordinates (if present) | ~43 bytes | Depth-dependent, first few packets only |
|
||||
| **Worst case total** | **144 bytes** | With COORDS_PRESENT for depth-3 paths |
|
||||
| **Worst case total** | **150 bytes** | With CP flag set for depth-3 paths |
|
||||
|
||||
The `FIPS_OVERHEAD` constant (144 bytes) is used for conservative MTU
|
||||
The `FIPS_OVERHEAD` constant (150 bytes) is used for conservative MTU
|
||||
calculations.
|
||||
|
||||
### Effective IPv6 MTU
|
||||
@@ -142,14 +143,14 @@ For typical deployments:
|
||||
|
||||
| Transport MTU | Effective IPv6 MTU | Notes |
|
||||
| ------------- | ------------------ | ----- |
|
||||
| 1472 (UDP/Ethernet) | 1328 | Standard deployment |
|
||||
| 1280 (UDP minimum) | 1136 | Below IPv6 minimum |
|
||||
| 1472 (UDP/Ethernet) | 1322 | Standard deployment |
|
||||
| 1280 (UDP minimum) | 1130 | Below IPv6 minimum |
|
||||
|
||||
IPv6 mandates that every link support at least 1280 bytes. The minimum
|
||||
transport path MTU for the IPv6 adapter is therefore:
|
||||
|
||||
```text
|
||||
1280 + 144 = 1424 bytes
|
||||
1280 + 150 = 1430 bytes
|
||||
```
|
||||
|
||||
Transports with smaller MTUs (LoRa at ~250 bytes, serial at 256 bytes) cannot
|
||||
@@ -315,13 +316,13 @@ decryption (opens attack surface).
|
||||
|
||||
Endpoint-only fragmentation (fragment before session encryption, reassemble
|
||||
after decryption) is a future direction that avoids these objections. Each
|
||||
fragment would be independently encrypted and look like a normal DataPacket
|
||||
fragment would be independently encrypted and look like a normal data packet
|
||||
to transit nodes.
|
||||
|
||||
## References
|
||||
|
||||
- [fips-intro.md](fips-intro.md) — Protocol overview and architecture
|
||||
- [fips-session-layer.md](fips-session-layer.md) — FSP (below the adapter)
|
||||
- [fips-wire-formats.md](fips-wire-formats.md) — DataPacket and SessionDatagram
|
||||
- [fips-wire-formats.md](fips-wire-formats.md) — FSP and SessionDatagram wire
|
||||
formats
|
||||
- [fips-configuration.md](fips-configuration.md) — TUN configuration parameters
|
||||
|
||||
@@ -212,8 +212,7 @@ be made.
|
||||
### Unified Cache
|
||||
|
||||
The coordinate cache is a single unified cache. All sources — SessionSetup
|
||||
transit, COORDS_PRESENT DataPackets, LookupResponse — write to the same
|
||||
cache.
|
||||
transit, CP-flagged data packets, LookupResponse — write to the same cache.
|
||||
|
||||
### Population Sources
|
||||
|
||||
@@ -221,7 +220,7 @@ cache.
|
||||
| ------ | ---- | ---- |
|
||||
| SessionSetup transit | Session establishment | Both src and dest coordinates |
|
||||
| SessionAck transit | Session establishment | Responder's coordinates |
|
||||
| DataPacket with COORDS_PRESENT | Warmup or recovery | Both src and dest coordinates |
|
||||
| CP-flagged data packet | Warmup or recovery | Both src and dest coordinates (cleartext) |
|
||||
| LookupResponse | Discovery | Target's coordinates |
|
||||
|
||||
### Eviction
|
||||
@@ -312,7 +311,7 @@ Destination Unreachable.
|
||||
## SessionSetup Self-Bootstrapping
|
||||
|
||||
SessionSetup is the mechanism that warms transit node coordinate caches
|
||||
along a path, enabling subsequent DataPackets to route efficiently.
|
||||
along a path, enabling subsequent data packets to route efficiently.
|
||||
|
||||
### How It Works
|
||||
|
||||
@@ -335,18 +334,19 @@ coordinates and warming caches in the other direction.
|
||||
### Result
|
||||
|
||||
After the handshake completes, the entire forward and reverse paths have
|
||||
cached coordinates for both endpoints. Subsequent DataPackets use minimal
|
||||
cached coordinates for both endpoints. Subsequent data packets use minimal
|
||||
headers (no coordinates) and route efficiently through the warmed caches.
|
||||
|
||||
## COORDS_PRESENT Warmup
|
||||
## CP (Coords Present) Warmup
|
||||
|
||||
The COORDS_PRESENT flag on DataPackets provides a secondary cache-warming
|
||||
The CP flag in the FSP common prefix provides a secondary cache-warming
|
||||
mechanism that complements SessionSetup. See
|
||||
[fips-session-layer.md](fips-session-layer.md) for the warmup-then-reactive
|
||||
strategy.
|
||||
|
||||
Transit nodes process DataPackets with COORDS_PRESENT by extracting and
|
||||
caching both source and destination coordinates — the same operation
|
||||
Transit nodes parse the CP flag from the FSP header and extract source and
|
||||
destination coordinates from the cleartext section between the header and
|
||||
ciphertext — no decryption needed. This is the same caching operation
|
||||
performed for SessionSetup coordinates.
|
||||
|
||||
## Error Recovery
|
||||
@@ -367,8 +367,7 @@ coordinates for the destination. It cannot make a forwarding decision.
|
||||
|
||||
**Source recovery**:
|
||||
1. Initiate discovery (LookupRequest flood) for the destination
|
||||
2. Reset COORDS_PRESENT warmup counter — subsequent DataPackets include
|
||||
coordinates
|
||||
2. Reset CP warmup counter — subsequent data packets include coordinates
|
||||
3. When discovery completes, warmup counter resets again (covers timing gap)
|
||||
|
||||
The crypto session remains active throughout — only routing state is
|
||||
@@ -386,7 +385,7 @@ source.
|
||||
**Source recovery**:
|
||||
1. Remove stale coordinates from cache
|
||||
2. Initiate discovery for the destination
|
||||
3. Reset COORDS_PRESENT warmup counter
|
||||
3. Reset CP warmup counter
|
||||
|
||||
### Error Signal Rate Limiting
|
||||
|
||||
@@ -397,11 +396,11 @@ packets to the same destination hit the same routing failure simultaneously.
|
||||
### Error Routing Limitation
|
||||
|
||||
Error signals route back to the source using `find_next_hop(src_addr)`. For
|
||||
steady-state DataPackets (after the COORDS_PRESENT warmup window), the
|
||||
steady-state data packets (after the CP warmup window), the
|
||||
transit node may lack cached coordinates for the source. If so, the error is
|
||||
silently dropped.
|
||||
|
||||
This blind spot is partially addressed by COORDS_PRESENT warmup: transit
|
||||
This blind spot is partially addressed by CP warmup: transit
|
||||
nodes receive source coordinates during the warmup phase. But after warmup
|
||||
expires and transit caches for the source expire, errors may be lost. The
|
||||
session idle timeout (90s) limits the window — if traffic stops long enough
|
||||
@@ -423,8 +422,8 @@ sequence:
|
||||
returns the destination's coordinates
|
||||
4. **Session establishment**: SessionSetup carries coordinates, warming
|
||||
transit caches along the path
|
||||
5. **Warmup**: First N DataPackets include COORDS_PRESENT, reinforcing
|
||||
transit caches
|
||||
5. **Warmup**: First N data packets include CP flag, reinforcing transit
|
||||
caches
|
||||
|
||||
The first packet to a new destination always triggers this sequence. The
|
||||
packet is queued (bounded) until the session is established.
|
||||
@@ -435,7 +434,7 @@ After session establishment and warmup:
|
||||
|
||||
- Transit nodes have cached coordinates for both endpoints
|
||||
- Bloom filters have converged for the destination
|
||||
- DataPackets use minimal headers (no coordinates)
|
||||
- Data packets use minimal headers (no coordinates)
|
||||
- Routing decisions are fast: bloom candidate selection + distance ranking
|
||||
|
||||
### Steady State
|
||||
@@ -445,7 +444,7 @@ In steady state, the mesh is mostly self-maintaining:
|
||||
- TreeAnnounce gossip keeps the spanning tree current
|
||||
- FilterAnnounce gossip keeps bloom filters current
|
||||
- Coordinate caches are refreshed by active routing traffic
|
||||
- Occasional cache misses trigger COORDS_PRESENT or discovery, but these
|
||||
- Occasional cache misses trigger CP warmup or discovery, but these
|
||||
are rare when traffic is flowing
|
||||
|
||||
### Cache Expiry and Recovery
|
||||
@@ -511,8 +510,8 @@ routing decisions but retains its own end-to-end encryption and identity.
|
||||
| LookupResponse | ~400 bytes | Response to discovery | Yes (greedy routed) |
|
||||
| SessionDatagram + SessionSetup | ~232–402 bytes | Session establishment | Yes (routed) |
|
||||
| SessionDatagram + SessionAck | ~122 bytes | Session confirmation | Yes (routed) |
|
||||
| SessionDatagram + DataPacket (minimal) | 40 bytes + payload | Bulk traffic | Yes (routed) |
|
||||
| SessionDatagram + DataPacket (with coords) | ~172 bytes + payload | Warmup/recovery | Yes (routed) |
|
||||
| SessionDatagram + Data (minimal) | ~107 bytes + payload | Bulk traffic | Yes (routed) |
|
||||
| SessionDatagram + Data (with CP) | ~150 bytes + payload | Warmup/recovery | Yes (routed) |
|
||||
| SessionDatagram + CoordsRequired | 70 bytes | Cache miss error | Yes (routed) |
|
||||
| SessionDatagram + PathBroken | 70+ bytes | Dead-end error | Yes (routed) |
|
||||
| Disconnect | 2 bytes | Link teardown | No (peer-to-peer) |
|
||||
@@ -550,7 +549,7 @@ recovery).
|
||||
| Flush coord cache on parent change | **Implemented** |
|
||||
| LookupRequest/LookupResponse discovery | **Implemented** |
|
||||
| SessionSetup self-bootstrapping | **Implemented** |
|
||||
| COORDS_PRESENT warmup-then-reactive | **Implemented** |
|
||||
| CP warmup-then-reactive | **Implemented** |
|
||||
| CoordsRequired recovery | **Implemented** |
|
||||
| PathBroken recovery | **Implemented** |
|
||||
| Error signal rate limiting | **Implemented** |
|
||||
|
||||
@@ -125,7 +125,7 @@ and transmitted after the session is established.
|
||||
SessionSetup is self-bootstrapping for routing. It carries the source's and
|
||||
destination's tree coordinates in the clear (not inside the Noise payload).
|
||||
As the message transits intermediate nodes, each node caches these coordinates,
|
||||
warming the path for subsequent DataPackets that carry only addresses (no
|
||||
warming the path for subsequent data packets that carry only addresses (no
|
||||
coordinates).
|
||||
|
||||
SessionAck carries the responder's coordinates back along the reverse path,
|
||||
@@ -145,12 +145,14 @@ This ensures exactly one handshake completes.
|
||||
|
||||
### Data Transfer
|
||||
|
||||
Once established, sessions carry DataPacket messages containing encrypted
|
||||
application data. Each DataPacket includes:
|
||||
Once established, sessions carry encrypted data using the FSP pipeline. Each
|
||||
encrypted message includes:
|
||||
|
||||
- An explicit 8-byte counter for replay protection (used as the AEAD nonce)
|
||||
- A flags byte (including COORDS_PRESENT for cache warming)
|
||||
- The encrypted payload
|
||||
- A 12-byte cleartext header (used as AEAD AAD) containing the counter and
|
||||
flags (including the CP flag for coordinate cache warming)
|
||||
- Optional cleartext coordinates when the CP flag is set
|
||||
- An AEAD-encrypted payload containing a 6-byte inner header (session-relative
|
||||
timestamp, message type, inner flags) followed by the application data
|
||||
|
||||
### Session Idle Timeout
|
||||
|
||||
@@ -239,9 +241,9 @@ discarded after the handshake.
|
||||
## Replay Protection
|
||||
|
||||
FSP uses explicit 8-byte counters on the wire for replay protection. Each side
|
||||
maintains a monotonically increasing send counter, transmitted with every
|
||||
DataPacket. The receiver maintains a sliding window (2048-entry bitmap)
|
||||
tracking which counters have been seen.
|
||||
maintains a monotonically increasing send counter, included in the 12-byte
|
||||
cleartext header of every encrypted message. The receiver maintains a sliding
|
||||
window (2048-entry bitmap) tracking which counters have been seen.
|
||||
|
||||
This design is critical for operation over unreliable transports. Under UDP
|
||||
packet loss or reordering, implicit nonce counters (where the receiver
|
||||
@@ -253,34 +255,34 @@ regardless of what packets were lost or reordered.
|
||||
The same `ReplayWindow` and `decrypt_with_replay_check()` implementation is
|
||||
used at both the link and session layers.
|
||||
|
||||
## COORDS_PRESENT Warmup Strategy
|
||||
## CP (Coords Present) Warmup Strategy
|
||||
|
||||
Session establishment (SessionSetup/SessionAck) warms transit node coordinate
|
||||
caches along the path. But coordinate caches have a finite TTL (default 300s),
|
||||
and entries may be evicted under memory pressure. When a transit node's cache
|
||||
entry expires, it cannot forward DataPackets (which carry only addresses, not
|
||||
entry expires, it cannot forward data packets (which carry only addresses, not
|
||||
coordinates) and sends a CoordsRequired error.
|
||||
|
||||
FSP uses a warmup-then-reactive strategy to keep transit caches populated:
|
||||
|
||||
### Warmup Phase
|
||||
|
||||
After session establishment, the first N DataPackets (configurable, default 5)
|
||||
include both source and destination coordinates via the COORDS_PRESENT flag.
|
||||
Transit nodes cache these coordinates as packets pass through, reinforcing the
|
||||
path established by SessionSetup.
|
||||
After session establishment, the first N data packets (configurable, default 5)
|
||||
include both source and destination coordinates via the CP flag in the FSP
|
||||
common prefix. The coordinates appear in cleartext between the 12-byte header
|
||||
and the ciphertext, allowing transit nodes to cache them without decryption.
|
||||
|
||||
### Steady State
|
||||
|
||||
After the warmup count is reached, FSP clears the COORDS_PRESENT flag and
|
||||
sends minimal DataPackets (4-byte header instead of ~136 bytes with
|
||||
coordinates). Transit nodes serve from their coordinate caches.
|
||||
After the warmup count is reached, FSP clears the CP flag and sends minimal
|
||||
data packets (12-byte header + ciphertext). Transit nodes serve from their
|
||||
coordinate caches.
|
||||
|
||||
### Reactive Recovery
|
||||
|
||||
When FSP receives a CoordsRequired signal:
|
||||
|
||||
1. The warmup counter resets — subsequent DataPackets include coordinates again
|
||||
1. The warmup counter resets — subsequent data packets include coordinates again
|
||||
2. A new LookupRequest may be initiated to rediscover the destination's
|
||||
current coordinates
|
||||
3. When the LookupResponse arrives for an established session, the warmup
|
||||
@@ -343,7 +345,7 @@ either fall back to bloom-filter-only routing or signal CoordsRequired.
|
||||
|
||||
The coordinate cache is a single unified cache (merged from previously
|
||||
separate coord_cache and route_cache). All coordinate sources — SessionSetup
|
||||
transit, COORDS_PRESENT DataPackets, LookupResponse — write to the same cache.
|
||||
transit, CP-flagged data packets, LookupResponse — write to the same cache.
|
||||
|
||||
### Eviction Policy
|
||||
|
||||
@@ -380,7 +382,9 @@ node caches (still within their 300s TTL) are re-warmed.
|
||||
| Session establishment (Noise IK) | **Implemented** |
|
||||
| End-to-end encryption (ChaCha20-Poly1305) | **Implemented** |
|
||||
| Explicit counter replay protection | **Implemented** |
|
||||
| COORDS_PRESENT warmup-then-reactive | **Implemented** |
|
||||
| CP warmup-then-reactive | **Implemented** |
|
||||
| FSP wire format (prefix, AAD, inner header) | **Implemented** |
|
||||
| Session-layer MMP report types | **Implemented** (wire format) |
|
||||
| Identity cache (LRU-only) | **Implemented** |
|
||||
| Coordinate cache (unified, TTL + refresh) | **Implemented** |
|
||||
| Session idle timeout | **Implemented** |
|
||||
|
||||
@@ -396,103 +396,166 @@ Orderly link teardown with reason code.
|
||||
| 0x07 | Timeout | Keepalive or stale detection timeout |
|
||||
| 0xFF | Other | Unspecified reason |
|
||||
|
||||
## Session-Layer Message Types
|
||||
## Session-Layer Message Formats
|
||||
|
||||
These messages are carried as the payload of a SessionDatagram (0x00).
|
||||
Session-layer messages are carried as the payload of a SessionDatagram (0x00).
|
||||
All FSP messages begin with a **4-byte common prefix** that identifies the
|
||||
protocol version, session lifecycle phase, per-packet flags, and payload length.
|
||||
|
||||
### SessionSetup (0x00)
|
||||
### FSP Common Prefix (4 bytes)
|
||||
|
||||
| Field | Size | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| version | 4 bits (high) | Protocol version. Currently 0x0 |
|
||||
| phase | 4 bits (low) | Session lifecycle phase (see table) |
|
||||
| flags | 1 byte | Per-packet signal flags (zero during handshake) |
|
||||
| payload_len | 2 bytes LE | Length of payload after phase-specific header |
|
||||
|
||||
### FSP Phase Table
|
||||
|
||||
| Phase | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| 0x0 | Established | Post-handshake encrypted traffic or plaintext error signals |
|
||||
| 0x1 | Handshake msg1 | SessionSetup (Noise IK msg1) |
|
||||
| 0x2 | Handshake msg2 | SessionAck (Noise IK msg2) |
|
||||
|
||||
### FSP Flags (Established Phase Only)
|
||||
|
||||
| Bit | Name | Description |
|
||||
| --- | ---- | ----------- |
|
||||
| 0 | CP (coords present) | Source and destination coordinates follow the header in cleartext |
|
||||
| 1 | K (key epoch) | Selects active key during rekeying |
|
||||
| 2 | U (unencrypted) | Payload is plaintext (error signals) |
|
||||
| 3-7 | — | Reserved (must be zero) |
|
||||
|
||||
Flags must be zero in handshake packets (phase 0x1 and 0x2).
|
||||
|
||||
### FSP Encrypted Message (phase 0x0, U flag clear)
|
||||
|
||||
Post-handshake encrypted data. The 12-byte cleartext header is used as AEAD
|
||||
AAD. Coordinates may appear in cleartext between the header and ciphertext
|
||||
when the CP flag is set.
|
||||
|
||||
**Cleartext header** (12 bytes, used as AEAD AAD):
|
||||
|
||||
| Field | Size | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| common prefix | 4 bytes | ver=0, phase=0, flags, payload_len |
|
||||
| counter | 8 bytes LE | Monotonic nonce, used as AEAD nonce and for replay detection |
|
||||
|
||||
**Optional cleartext coordinates** (when CP flag is set):
|
||||
|
||||
| Field | Size | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| src_coords_count | 2 bytes LE | Number of source coordinate entries |
|
||||
| src_coords | 16 x n bytes | Source's ancestry (NodeAddr, self -> root) |
|
||||
| dest_coords_count | 2 bytes LE | Number of dest coordinate entries |
|
||||
| dest_coords | 16 x m bytes | Destination's ancestry |
|
||||
|
||||
Transit nodes parse the CP flag and extract coordinates without decryption.
|
||||
|
||||
**Encrypted inner header** (6 bytes, first bytes of AEAD plaintext):
|
||||
|
||||
| Field | Size | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| timestamp | 4 bytes LE | Session-relative milliseconds (u32) |
|
||||
| msg_type | 1 byte | Session-layer message type |
|
||||
| inner_flags | 1 byte | Bit 0: SP (spin bit for RTT measurement) |
|
||||
|
||||
After the inner header, the remaining plaintext is the message-type-specific
|
||||
body.
|
||||
|
||||
**Complete encrypted message**:
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────┬─────────────────┬───────────────────────────┐
|
||||
│ header (12 bytes, used as AAD) │ [coords if CP] │ ciphertext + AEAD tag │
|
||||
│ │ │ (inner_hdr + body) + 16 │
|
||||
└─────────────────────────────────┴─────────────────┴───────────────────────────┘
|
||||
```
|
||||
|
||||
### FSP Session Message Types
|
||||
|
||||
| Type | Message | Description |
|
||||
| ---- | ------- | ----------- |
|
||||
| 0x10 | Data | Application data (IPv6 payload via TUN) |
|
||||
| 0x11 | SenderReport | MMP sender-side metrics report |
|
||||
| 0x12 | ReceiverReport | MMP receiver-side metrics report |
|
||||
| 0x13 | PathMtuNotification | End-to-end path MTU echo |
|
||||
| 0x20 | CoordsRequired | Error: transit node lacks destination coordinates |
|
||||
| 0x21 | PathBroken | Error: greedy routing reached dead end |
|
||||
|
||||
Message types 0x10-0x13 are carried inside the AEAD ciphertext (dispatched
|
||||
by the `msg_type` field in the encrypted inner header). Types 0x20-0x21 are
|
||||
plaintext error signals (U flag set, no encryption).
|
||||
|
||||
### SessionSetup (phase 0x1)
|
||||
|
||||
Establishes a session and warms transit coordinate caches.
|
||||
Encoded with FSP prefix: ver=0, phase=0x1, flags=0, payload_len.
|
||||
|
||||
**Body** (after 4-byte FSP prefix):
|
||||
|
||||
| Offset | Field | Size | Description |
|
||||
| ------ | ----- | ---- | ----------- |
|
||||
| 0 | msg_type | 1 byte | 0x00 |
|
||||
| 1 | flags | 1 byte | Bit 0: REQUEST_ACK, Bit 1: BIDIRECTIONAL |
|
||||
| 2 | src_coords_count | 2 bytes LE | Number of source coordinate entries |
|
||||
| 4 | src_coords | 16 x n bytes | Source's ancestry (NodeAddr, self -> root) |
|
||||
| 0 | flags | 1 byte | Bit 0: REQUEST_ACK, Bit 1: BIDIRECTIONAL |
|
||||
| 1 | src_coords_count | 2 bytes LE | Number of source coordinate entries |
|
||||
| 3 | src_coords | 16 x n bytes | Source's ancestry (NodeAddr, self -> root) |
|
||||
| ... | dest_coords_count | 2 bytes LE | Number of dest coordinate entries |
|
||||
| ... | dest_coords | 16 x m bytes | Destination's ancestry |
|
||||
| ... | handshake_len | 2 bytes LE | Noise payload length |
|
||||
| ... | handshake_payload | variable | Noise IK msg1 (82 bytes typical) |
|
||||
|
||||
**Example** (depth-3 source, depth-4 destination):
|
||||
|
||||
```text
|
||||
SessionDatagram header: 36 bytes
|
||||
SessionSetup payload: 1 + 1 + 2 + 48 + 2 + 64 + 2 + 82 = 202 bytes
|
||||
Total: 238 bytes
|
||||
```
|
||||
|
||||
### SessionAck (0x01)
|
||||
### SessionAck (phase 0x2)
|
||||
|
||||
Confirms session establishment, completes the Noise handshake.
|
||||
Encoded with FSP prefix: ver=0, phase=0x2, flags=0, payload_len.
|
||||
|
||||
**Body** (after 4-byte FSP prefix):
|
||||
|
||||
| Offset | Field | Size | Description |
|
||||
| ------ | ----- | ---- | ----------- |
|
||||
| 0 | msg_type | 1 byte | 0x01 |
|
||||
| 1 | flags | 1 byte | Reserved |
|
||||
| 2 | src_coords_count | 2 bytes LE | Number of coordinate entries |
|
||||
| 4 | src_coords | 16 x n bytes | Acknowledger's ancestry (for cache warming) |
|
||||
| 0 | flags | 1 byte | Reserved |
|
||||
| 1 | src_coords_count | 2 bytes LE | Number of coordinate entries |
|
||||
| 3 | src_coords | 16 x n bytes | Acknowledger's ancestry (for cache warming) |
|
||||
| ... | handshake_len | 2 bytes LE | Noise payload length |
|
||||
| ... | handshake_payload | variable | Noise IK msg2 (33 bytes typical) |
|
||||
|
||||
### DataPacket (0x10)
|
||||
### Data (0x10)
|
||||
|
||||
Encrypted application data with explicit replay protection counter.
|
||||
|
||||
**Minimal header** (COORDS_PRESENT = 0):
|
||||
|
||||
| Offset | Field | Size | Description |
|
||||
| ------ | ----- | ---- | ----------- |
|
||||
| 0 | msg_type | 1 byte | 0x10 |
|
||||
| 1 | flags | 1 byte | Bit 0: COORDS_PRESENT |
|
||||
| 2 | counter | 8 bytes LE | Session encryption counter / replay nonce |
|
||||
| 10 | payload_length | 2 bytes LE | Length of encrypted payload |
|
||||
| 12 | payload | variable | Encrypted application data + 16-byte AEAD tag |
|
||||
|
||||
**Header size**: 12 bytes (`DATA_HEADER_SIZE`)
|
||||
|
||||
**With coordinates** (COORDS_PRESENT = 1):
|
||||
|
||||
| Offset | Field | Size | Description |
|
||||
| ------ | ----- | ---- | ----------- |
|
||||
| 0 | msg_type | 1 byte | 0x10 |
|
||||
| 1 | flags | 1 byte | 0x01 (COORDS_PRESENT) |
|
||||
| 2 | counter | 8 bytes LE | Session encryption counter |
|
||||
| 10 | payload_length | 2 bytes LE | Length of encrypted payload |
|
||||
| 12 | src_coords_count | 2 bytes LE | Source coordinate entries |
|
||||
| 14 | src_coords | 16 x n bytes | Source's ancestry |
|
||||
| ... | dest_coords_count | 2 bytes LE | Dest coordinate entries |
|
||||
| ... | dest_coords | 16 x m bytes | Destination's ancestry |
|
||||
| ... | payload | variable | Encrypted application data |
|
||||
Application data (typically IPv6 payload). This is the `msg_type` byte
|
||||
inside the encrypted inner header — there is no separate DataPacket struct.
|
||||
The body after the inner header is delivered directly to the TUN interface.
|
||||
|
||||
### CoordsRequired (0x20)
|
||||
|
||||
Link-layer error signal — transit node lacks coordinates for destination.
|
||||
Plaintext (not end-to-end encrypted), generated by transit nodes.
|
||||
Plaintext error signal — transit node lacks coordinates for destination.
|
||||
Encoded with FSP prefix: ver=0, phase=0x0, U flag set, payload_len.
|
||||
|
||||
**Body** (after 4-byte FSP prefix + 1-byte msg_type):
|
||||
|
||||
| Offset | Field | Size | Description |
|
||||
| ------ | ----- | ---- | ----------- |
|
||||
| 0 | msg_type | 1 byte | 0x20 |
|
||||
| 1 | flags | 1 byte | Reserved |
|
||||
| 2 | dest_addr | 16 bytes | NodeAddr we couldn't route to |
|
||||
| 18 | reporter | 16 bytes | NodeAddr of reporting router |
|
||||
| 0 | flags | 1 byte | Reserved |
|
||||
| 1 | dest_addr | 16 bytes | NodeAddr we couldn't route to |
|
||||
| 17 | reporter | 16 bytes | NodeAddr of reporting router |
|
||||
|
||||
**Payload**: 34 bytes. Wrapped in SessionDatagram: 70 bytes total.
|
||||
**Body size**: 33 bytes. Total with prefix + msg_type: 38 bytes.
|
||||
|
||||
### PathBroken (0x21)
|
||||
|
||||
Link-layer error signal — greedy routing reached a dead end. Plaintext,
|
||||
generated by transit nodes.
|
||||
Plaintext error signal — greedy routing reached a dead end.
|
||||
Encoded with FSP prefix: ver=0, phase=0x0, U flag set, payload_len.
|
||||
|
||||
**Body** (after 4-byte FSP prefix + 1-byte msg_type):
|
||||
|
||||
| Offset | Field | Size | Description |
|
||||
| ------ | ----- | ---- | ----------- |
|
||||
| 0 | msg_type | 1 byte | 0x21 |
|
||||
| 1 | flags | 1 byte | Reserved |
|
||||
| 2 | dest_addr | 16 bytes | Unreachable NodeAddr |
|
||||
| 18 | reporter | 16 bytes | NodeAddr of reporting router |
|
||||
| 34 | last_coords_count | 2 bytes LE | Number of stale coordinate entries |
|
||||
| 36 | last_known_coords | 16 x n bytes | Stale coordinates that failed |
|
||||
| 0 | flags | 1 byte | Reserved |
|
||||
| 1 | dest_addr | 16 bytes | Unreachable NodeAddr |
|
||||
| 17 | reporter | 16 bytes | NodeAddr of reporting router |
|
||||
| 33 | last_coords_count | 2 bytes LE | Number of stale coordinate entries |
|
||||
| 35 | last_known_coords | 16 x n bytes | Stale coordinates that failed |
|
||||
|
||||
## Encapsulation Walkthrough
|
||||
|
||||
@@ -507,19 +570,19 @@ Layer 4: Application data
|
||||
1024 bytes
|
||||
|
||||
Layer 3: Session encryption (FSP)
|
||||
DataPacket header (12 bytes) + encrypted payload (1024) + AEAD tag (16)
|
||||
= 1052 bytes
|
||||
FSP header (12 bytes) + AEAD(inner_hdr (6) + payload (1024)) + AEAD tag (16)
|
||||
= 1058 bytes
|
||||
|
||||
Layer 2: SessionDatagram envelope (FLP routing)
|
||||
msg_type (1) + ttl (1) + path_mtu (2) + src_addr (16) + dest_addr (16) + payload (1052)
|
||||
= 1088 bytes
|
||||
msg_type (1) + ttl (1) + path_mtu (2) + src_addr (16) + dest_addr (16) + payload (1058)
|
||||
= 1094 bytes
|
||||
|
||||
Layer 1: Link encryption (FLP per-hop)
|
||||
outer header (16) + encrypted(inner_hdr (5) + datagram (1088)) + AEAD tag (16)
|
||||
= 1125 bytes
|
||||
outer header (16) + encrypted(inner_hdr (5) + datagram (1094)) + AEAD tag (16)
|
||||
= 1131 bytes
|
||||
|
||||
Layer 0: Transport
|
||||
UDP datagram containing 1125 bytes
|
||||
UDP datagram containing 1131 bytes
|
||||
```
|
||||
|
||||
### Overhead Budget
|
||||
@@ -528,11 +591,12 @@ Layer 0: Transport
|
||||
| ----- | -------- | --------- |
|
||||
| Link encryption | 37 bytes | 16 outer header (AAD) + 5 inner header + 16 AEAD tag |
|
||||
| SessionDatagram | 36 bytes | 1 type + 1 ttl + 2 path_mtu + 16 src + 16 dest |
|
||||
| DataPacket header | 12 bytes | 1 type + 1 flags + 8 counter + 2 length |
|
||||
| FSP header | 12 bytes | 4 prefix + 8 counter |
|
||||
| FSP inner header | 6 bytes | 4 timestamp + 1 msg_type + 1 inner_flags (inside AEAD) |
|
||||
| Session AEAD tag | 16 bytes | Poly1305 tag on session-encrypted payload |
|
||||
| **Minimal total** | **101 bytes** | |
|
||||
| **Minimal total** | **107 bytes** | |
|
||||
| Coordinates (if present) | ~43 bytes | Varies with tree depth |
|
||||
| **Worst case** | **144 bytes** | `FIPS_OVERHEAD` constant |
|
||||
| **Worst case** | **150 bytes** | `FIPS_OVERHEAD` constant |
|
||||
|
||||
### At Each Transit Node
|
||||
|
||||
@@ -581,20 +645,23 @@ endpoint session keys).
|
||||
| ------- | ------------ | ----- |
|
||||
| SessionSetup | ~200 bytes | Depth-dependent |
|
||||
| SessionAck | ~80 bytes | Depth-dependent |
|
||||
| DataPacket (minimal) | 12 + payload bytes | Steady state |
|
||||
| DataPacket (with coords) | 12 + ~130 + payload bytes | Warmup/recovery |
|
||||
| CoordsRequired | 34 bytes | Fixed |
|
||||
| PathBroken | 36 + 16n bytes | Includes stale coords |
|
||||
| Data (minimal) | 12 + 6 + payload + 16 bytes | Steady state |
|
||||
| Data (with coords) | 12 + ~130 + 6 + payload + 16 bytes | Warmup/recovery |
|
||||
| SenderReport | 12 + 6 + 46 + 16 bytes | MMP metrics |
|
||||
| ReceiverReport | 12 + 6 + 66 + 16 bytes | MMP metrics |
|
||||
| PathMtuNotification | 12 + 6 + 2 + 16 bytes | MTU signal |
|
||||
| CoordsRequired | 38 bytes | Fixed (prefix + msg_type + body) |
|
||||
| PathBroken | 35 + 16n bytes | Includes stale coords |
|
||||
|
||||
### Complete Packet Sizes (link + session)
|
||||
|
||||
| Scenario | Wire Size | Notes |
|
||||
| -------- | --------- | ----- |
|
||||
| Encrypted frame minimum | 37 bytes | Empty body |
|
||||
| SessionDatagram + DataPacket (minimal) | 37 + 36 + 12 + payload + 16 | 101 + payload |
|
||||
| SessionDatagram + DataPacket (with coords) | ~144 + payload | Worst case |
|
||||
| SessionDatagram + Data (minimal) | 37 + 36 + 12 + 6 + payload + 16 | 107 + payload |
|
||||
| SessionDatagram + Data (with coords) | ~150 + payload | Worst case |
|
||||
| SessionDatagram + SessionSetup | ~275 bytes | Depth-3, both dirs |
|
||||
| SessionDatagram + CoordsRequired | 37 + 36 + 34 = 107 bytes | Including link overhead |
|
||||
| SessionDatagram + CoordsRequired | 37 + 36 + 38 = 111 bytes | Including link overhead |
|
||||
|
||||
## References
|
||||
|
||||
|
||||
Reference in New Issue
Block a user