mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
Session 53: Route cache warming and session protocol refinements
Session protocol (fips-session-protocol.md): - Clarified DNS entry point applies to IP-based apps; native FIPS uses npub - Updated transport failover examples (UDP → WiFi, WiFi → LTE) - Added roaming description to session independence section - Expanded §5 with coords-on-demand mechanism for route cache recovery - Added Noise IK vs XK privacy tradeoff note to §6 Routing (fips-routing.md): - DataPacket now has optional coordinates (COORDS_PRESENT flag) - Updated handle_data_packet to cache coords from packets - Sender state machine: WARM/COLD based on CoordsRequired errors - Updated packet type summary table Architecture (fips-architecture.md): - Fixed cross-references to session protocol sections
This commit is contained in:
@@ -931,7 +931,8 @@ this node wants to reach. This is the primary cache for endpoint nodes.
|
|||||||
> **Terminology note**: These parameters configure *routing sessions*—hop-by-hop
|
> **Terminology note**: These parameters configure *routing sessions*—hop-by-hop
|
||||||
> cached state at intermediate routers. For *crypto session* (end-to-end
|
> cached state at intermediate routers. For *crypto session* (end-to-end
|
||||||
> encryption) parameters, see the Crypto Session section below. See
|
> encryption) parameters, see the Crypto Session section below. See
|
||||||
> [fips-session-protocol.md](fips-session-protocol.md) §5 for the distinction.
|
> [fips-session-protocol.md](fips-session-protocol.md) §3 for crypto sessions
|
||||||
|
> and §5 for route cache warming.
|
||||||
|
|
||||||
| Parameter | Type | Default | Description |
|
| Parameter | Type | Default | Description |
|
||||||
|-----------|------|---------|-------------|
|
|-----------|------|---------|-------------|
|
||||||
|
|||||||
+53
-18
@@ -298,8 +298,8 @@ No global routing tables. Each node makes purely local decisions.
|
|||||||
> **Terminology note**: This section describes *routing sessions*—hop-by-hop
|
> **Terminology note**: This section describes *routing sessions*—hop-by-hop
|
||||||
> cached state at intermediate routers. FIPS also has *crypto sessions*—end-to-end
|
> cached state at intermediate routers. FIPS also has *crypto sessions*—end-to-end
|
||||||
> authenticated encryption between source and destination. See
|
> authenticated encryption between source and destination. See
|
||||||
> [fips-session-protocol.md](fips-session-protocol.md) §5 for the distinction and §6
|
> [fips-session-protocol.md](fips-session-protocol.md) §3 for crypto session details
|
||||||
> for crypto session details.
|
> and §5 for route cache warming.
|
||||||
|
|
||||||
### Routing Session Purpose
|
### Routing Session Purpose
|
||||||
|
|
||||||
@@ -349,13 +349,18 @@ struct SessionAck {
|
|||||||
handshake_payload: Option<Vec<u8>>, // Noise IK message 2
|
handshake_payload: Option<Vec<u8>>, // Noise IK message 2
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Minimal data packet
|
/// Data packet with optional coordinates
|
||||||
struct DataPacket {
|
struct DataPacket {
|
||||||
flags: u8,
|
flags: u8, // Bit 0: COORDS_PRESENT
|
||||||
hop_limit: u8,
|
hop_limit: u8,
|
||||||
payload_length: u16,
|
payload_length: u16,
|
||||||
src_addr: Ipv6Addr, // 16 bytes
|
src_addr: Ipv6Addr, // 16 bytes
|
||||||
dest_addr: Ipv6Addr, // 16 bytes
|
dest_addr: Ipv6Addr, // 16 bytes
|
||||||
|
|
||||||
|
// Optional: present only if COORDS_PRESENT flag is set
|
||||||
|
src_coords: Option<Vec<NodeId>>,
|
||||||
|
dest_coords: Option<Vec<NodeId>>,
|
||||||
|
|
||||||
payload: Vec<u8>,
|
payload: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,9 +380,10 @@ struct CoordsRequired {
|
|||||||
| payload_length | 2 bytes |
|
| payload_length | 2 bytes |
|
||||||
| src_addr | 16 bytes |
|
| src_addr | 16 bytes |
|
||||||
| dest_addr | 16 bytes |
|
| dest_addr | 16 bytes |
|
||||||
| **Total header** | **36 bytes** |
|
| **Minimal header** | **36 bytes** |
|
||||||
|
|
||||||
Comparable to IPv6 (40 bytes). No coordinates in data packets.
|
Comparable to IPv6 (40 bytes). When COORDS_PRESENT flag is set, coordinates
|
||||||
|
add variable overhead based on tree depth (typically 200-400 bytes).
|
||||||
|
|
||||||
### Routing Session Setup Flow
|
### Routing Session Setup Flow
|
||||||
|
|
||||||
@@ -419,6 +425,23 @@ impl Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_data_packet(&mut self, packet: DataPacket, from: PeerId) {
|
fn handle_data_packet(&mut self, packet: DataPacket, from: PeerId) {
|
||||||
|
// If packet carries coordinates, cache them
|
||||||
|
if packet.flags & COORDS_PRESENT != 0 {
|
||||||
|
if let (Some(src_coords), Some(dest_coords)) =
|
||||||
|
(&packet.src_coords, &packet.dest_coords)
|
||||||
|
{
|
||||||
|
self.coord_cache.insert(packet.dest_addr, CacheEntry {
|
||||||
|
coords: dest_coords.clone(),
|
||||||
|
expires: now() + CACHE_TTL,
|
||||||
|
});
|
||||||
|
self.coord_cache.insert(packet.src_addr, CacheEntry {
|
||||||
|
coords: src_coords.clone(),
|
||||||
|
expires: now() + CACHE_TTL,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route using cache (now populated if coords were present)
|
||||||
match self.coord_cache.get(&packet.dest_addr) {
|
match self.coord_cache.get(&packet.dest_addr) {
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
entry.last_used = now();
|
entry.last_used = now();
|
||||||
@@ -467,13 +490,16 @@ by:
|
|||||||
When a router's cache entry is evicted mid-session:
|
When a router's cache entry is evicted mid-session:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
1. Data packet arrives, cache miss
|
1. Data packet arrives (minimal header), cache miss
|
||||||
2. Router sends CoordsRequired to packet source
|
2. Router sends CoordsRequired to packet source
|
||||||
3. Source receives error, re-sends SessionSetup (or packet with coords)
|
3. Source marks route as cold
|
||||||
4. Path warms again, data flow resumes
|
4. Source resends with COORDS_PRESENT flag set
|
||||||
|
5. Router caches coordinates from packet, forwards
|
||||||
|
6. After N successful packets, source clears flag
|
||||||
```
|
```
|
||||||
|
|
||||||
From application perspective: brief latency spike, transparent recovery.
|
The crypto session remains active throughout—only routing state is refreshed.
|
||||||
|
From application perspective: one packet delayed, transparent recovery.
|
||||||
|
|
||||||
### Sender Behavior
|
### Sender Behavior
|
||||||
|
|
||||||
@@ -481,21 +507,29 @@ From application perspective: brief latency spike, transparent recovery.
|
|||||||
impl Sender {
|
impl Sender {
|
||||||
fn send(&mut self, dest: Ipv6Addr, data: &[u8]) {
|
fn send(&mut self, dest: Ipv6Addr, data: &[u8]) {
|
||||||
if !self.session_established(dest) {
|
if !self.session_established(dest) {
|
||||||
// Need to establish session first
|
// Need to establish crypto session first
|
||||||
let dest_coords = self.discover_or_cached(dest)?;
|
let dest_coords = self.discover_or_cached(dest)?;
|
||||||
self.send_session_setup(dest, &dest_coords);
|
self.send_session_setup(dest, &dest_coords);
|
||||||
self.await_session_ack(dest)?;
|
self.await_session_ack(dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_data_packet(dest, data);
|
// Check route state
|
||||||
|
let include_coords = self.route_state(dest) == RouteCold;
|
||||||
|
self.send_data_packet(dest, data, include_coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_coords_required(&mut self, err: CoordsRequired) {
|
fn handle_coords_required(&mut self, err: CoordsRequired) {
|
||||||
// Path went cold, re-establish
|
// Route cache expired at intermediate router
|
||||||
self.mark_session_cold(err.dest_addr);
|
// Crypto session still valid - just need to re-warm route
|
||||||
self.send_session_setup(err.dest_addr, &self.cached_coords(err.dest_addr));
|
self.mark_route_cold(err.dest_addr);
|
||||||
|
// Next send() will include coordinates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RouteState {
|
||||||
|
RouteWarm, // Send minimal headers
|
||||||
|
RouteCold, // Include coordinates until warm
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -509,12 +543,13 @@ impl Sender {
|
|||||||
| LookupResponse | Return coordinates | ~400 bytes | Reply to discovery |
|
| LookupResponse | Return coordinates | ~400 bytes | Reply to discovery |
|
||||||
| SessionSetup | Warm router caches + crypto init | ~400-700 bytes | Before data transfer |
|
| SessionSetup | Warm router caches + crypto init | ~400-700 bytes | Before data transfer |
|
||||||
| SessionAck | Confirm session + crypto response | ~300-500 bytes | Session confirmation |
|
| SessionAck | Confirm session + crypto response | ~300-500 bytes | Session confirmation |
|
||||||
| DataPacket | Application data | 36 bytes + payload | Bulk of traffic |
|
| DataPacket | Application data | 36 bytes + payload (minimal) | Bulk of traffic |
|
||||||
| CoordsRequired | Request retransmit | ~50 bytes | Cache miss recovery |
|
| DataPacket | With coordinates | ~300-500 bytes + payload | After CoordsRequired |
|
||||||
|
| CoordsRequired | Request coords in next packet | ~50 bytes | Cache miss recovery |
|
||||||
|
|
||||||
> **Note**: SessionSetup/SessionAck sizes vary based on coordinate depth and
|
> **Note**: SessionSetup/SessionAck sizes vary based on coordinate depth and
|
||||||
> whether they carry crypto handshake payloads (combined establishment per
|
> whether they carry crypto handshake payloads (combined establishment per
|
||||||
> [fips-session-protocol.md](fips-session-protocol.md) §5.5).
|
> [fips-session-protocol.md](fips-session-protocol.md) §3.4 and §5.1).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ including peer discovery, authentication, tree announcements, and data routing.
|
|||||||
|
|
||||||
## 1. Application-Initiated Traffic Flow
|
## 1. Application-Initiated Traffic Flow
|
||||||
|
|
||||||
|
> **Note**: This section applies to traditional IP-based applications using the
|
||||||
|
> TUN interface. Applications using the native FIPS datagram service address
|
||||||
|
> destinations directly by npub, and routing proceeds from there without DNS.
|
||||||
|
|
||||||
Traffic flow begins at the application layer with a DNS query, which triggers
|
Traffic flow begins at the application layer with a DNS query, which triggers
|
||||||
a cascade of events through the FIPS stack.
|
a cascade of events through the FIPS stack.
|
||||||
|
|
||||||
@@ -17,10 +21,10 @@ a cascade of events through the FIPS stack.
|
|||||||
An application wants to send IPv6 traffic to another FIPS node, identified by
|
An application wants to send IPv6 traffic to another FIPS node, identified by
|
||||||
an npub. The flow:
|
an npub. The flow:
|
||||||
|
|
||||||
1. **DNS Query**: Application queries a local FIPS DNS server for the npub
|
1. **DNS Query**: Application queries the local FIPS DNS service for the npub
|
||||||
(format TBD - perhaps `npub1xxx...xxx.fips` or similar)
|
mapping to an IPv6 address
|
||||||
|
|
||||||
2. **FIPS DNS Server** performs two functions:
|
2. **FIPS DNS service** performs two functions:
|
||||||
- **Address derivation**: Converts the npub to an identity and derives the
|
- **Address derivation**: Converts the npub to an identity and derives the
|
||||||
corresponding `fd::/8` IPv6 address
|
corresponding `fd::/8` IPv6 address
|
||||||
- **Cache priming**: Stores the identity mapping (IPv6 address ↔ npub ↔ node_id)
|
- **Cache priming**: Stores the identity mapping (IPv6 address ↔ npub ↔ node_id)
|
||||||
@@ -34,6 +38,8 @@ an npub. The flow:
|
|||||||
5. **TUN Processing**: When the packet arrives at the TUN, FIPS already has the
|
5. **TUN Processing**: When the packet arrives at the TUN, FIPS already has the
|
||||||
cached mapping from the DNS lookup, enabling immediate routing decisions
|
cached mapping from the DNS lookup, enabling immediate routing decisions
|
||||||
|
|
||||||
|
6. **Note**: This identity cache is only necessary when using the FIPS IPv6 shim
|
||||||
|
|
||||||
### 1.2 Design Rationale
|
### 1.2 Design Rationale
|
||||||
|
|
||||||
Using DNS as the trigger point ensures the routing cache is populated *before*
|
Using DNS as the trigger point ensures the routing cache is populated *before*
|
||||||
@@ -194,12 +200,13 @@ management) and transmitted after the session is established.
|
|||||||
FIPS sessions exist above the routing layer. A session between two npubs
|
FIPS sessions exist above the routing layer. A session between two npubs
|
||||||
survives:
|
survives:
|
||||||
|
|
||||||
- Transport failover (UDP → Tor → back to UDP)
|
- Transport failover (UDP → WiFi → back to UDP)
|
||||||
- Route changes (different intermediate hops)
|
- Route changes (different intermediate hops)
|
||||||
- Transport address changes on either end
|
- Transport address changes on either end (WiFi → LTE → WiFi)
|
||||||
|
|
||||||
The session is bound to **npub identities**, not transport addresses or routing
|
The session is bound to **npub identities**, not transport addresses or routing
|
||||||
paths.
|
paths. This allows FIPS endpoints to roam over their transports as needed while
|
||||||
|
maintaining an established session.
|
||||||
|
|
||||||
### 3.4 Session Establishment Flow
|
### 3.4 Session Establishment Flow
|
||||||
|
|
||||||
@@ -207,7 +214,7 @@ FIPS uses Noise IK for session establishment. The initiator knows the
|
|||||||
destination's npub; the responder learns the initiator's identity from the
|
destination's npub; the responder learns the initiator's identity from the
|
||||||
handshake. This is the same asymmetry as link-layer connections.
|
handshake. This is the same asymmetry as link-layer connections.
|
||||||
|
|
||||||
The handshake is carried inside SessionSetup/SessionAck messages (see §5.5),
|
The handshake is carried inside SessionSetup/SessionAck messages (see §5.1),
|
||||||
which also establish routing session state at intermediate nodes.
|
which also establish routing session state at intermediate nodes.
|
||||||
|
|
||||||
### 3.5 Simultaneous Session Initiation (Crossing Hellos)
|
### 3.5 Simultaneous Session Initiation (Crossing Hellos)
|
||||||
@@ -255,61 +262,67 @@ Route cache entries:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Session Terminology
|
## 5. Route Cache Warming
|
||||||
|
|
||||||
FIPS uses two distinct session concepts at different layers:
|
### 5.1 Initial Warming via Handshake
|
||||||
|
|
||||||
| Term | Layer | Purpose | Endpoints |
|
The crypto session handshake (SessionSetup/SessionAck) warms route caches at
|
||||||
|---------------------|-------------|------------------------------|------------------------|
|
intermediate routers as it transits. Each message carries the sender's
|
||||||
| **Crypto Session** | End-to-end | Authentication + encryption | Source ↔ Destination |
|
coordinates; routers extract and cache `(src_addr, dest_addr) → next_hop` for
|
||||||
| **Routing Session** | Hop-by-hop | Cache coordinates at routers | Along the path |
|
both directions. After the handshake completes, data packets use minimal
|
||||||
|
36-byte headers and routers forward based on cached routes.
|
||||||
|
|
||||||
### 5.1 Crypto Session
|
### 5.2 Cache Miss Recovery
|
||||||
|
|
||||||
- Established between two npub identities
|
When an intermediate router's cache entry expires or is evicted, it cannot
|
||||||
- Provides confidentiality and authenticity via Noise IK
|
forward data packets (which carry only addresses, not coordinates). The router
|
||||||
- Survives route changes and transport failover
|
returns a CoordsRequired error to the sender.
|
||||||
- Keyed by: `(local_npub, remote_npub)`
|
|
||||||
|
|
||||||
### 5.2 Routing Session
|
The crypto session remains valid—only the routing state is lost. Recovery uses
|
||||||
|
coords-on-demand: data packets include an optional coordinates field. When the
|
||||||
|
sender receives CoordsRequired:
|
||||||
|
|
||||||
- Warms coordinate caches at intermediate routers
|
1. Sender marks the route as "cold"
|
||||||
- Enables minimal 36-byte data packet headers
|
2. Subsequent data packets include coordinates (flag bit set)
|
||||||
- Must be re-established when router caches expire
|
3. Routers along the path cache coordinates as packets transit
|
||||||
- Keyed by: `(src_addr, dest_addr)` at each router
|
4. Once route is warm again, sender clears the flag and resumes minimal headers
|
||||||
|
|
||||||
### 5.3 Combined Establishment
|
This avoids a full SessionSetup round-trip for what is purely a routing cache
|
||||||
|
refresh.
|
||||||
|
|
||||||
Both sessions are established together: the routing session setup carries the
|
### 5.3 DataPacket Coordinate Flag
|
||||||
crypto handshake, minimizing round-trips.
|
|
||||||
|
The DataPacket `flags` field includes a `COORDS_PRESENT` bit:
|
||||||
|
|
||||||
|
| Bit | Meaning |
|
||||||
|
|-----|------------------------------------------------------|
|
||||||
|
| 0 | COORDS_PRESENT - coordinates follow the fixed header |
|
||||||
|
|
||||||
|
When set, the packet includes `src_coords` and `dest_coords` after the standard
|
||||||
|
header fields. Routers process these coordinates the same way as SessionSetup:
|
||||||
|
cache both directions and forward using greedy routing.
|
||||||
|
|
||||||
|
### 5.4 Sender State Machine
|
||||||
|
|
||||||
```text
|
```text
|
||||||
1. Route discovery (if needed)
|
┌──────────────┐
|
||||||
└─► LookupRequest/Response → obtain destination coordinates
|
│ WARM │ ◄── Normal: send minimal headers
|
||||||
|
└──────┬───────┘
|
||||||
2. SessionSetup + Crypto Init
|
│ CoordsRequired received
|
||||||
└─► Source sends SessionSetup containing:
|
▼
|
||||||
- src/dest coordinates (for router caching)
|
┌──────────────┐
|
||||||
- Noise IK handshake initiation (for destination)
|
│ COLD │ ◄── Send packets with coords
|
||||||
└─► Routers cache coordinates as packet transits
|
└──────┬───────┘
|
||||||
└─► Destination receives crypto init, begins handshake
|
│ N packets sent successfully
|
||||||
|
▼
|
||||||
3. SessionAck + Crypto Response
|
┌──────────────┐
|
||||||
└─► Destination sends SessionAck containing:
|
│ WARM │
|
||||||
- Its coordinates (for reverse path caching)
|
└──────────────┘
|
||||||
- Noise IK handshake response
|
|
||||||
└─► Routers cache reverse path
|
|
||||||
└─► Source completes crypto handshake
|
|
||||||
|
|
||||||
4. Data flow
|
|
||||||
└─► Encrypted payloads with minimal 36-byte headers
|
|
||||||
└─► Both crypto session and routing session now active
|
|
||||||
```
|
```
|
||||||
|
|
||||||
SessionSetup and SessionAck messages carry both routing information (coordinates
|
The sender transitions back to WARM after sending a configurable number of
|
||||||
for router caching) and crypto payload (handshake messages, opaque to routers).
|
packets with coordinates (e.g., 3) without receiving CoordsRequired. This
|
||||||
Routers process the routing portion and forward; only endpoints process the
|
provides confidence that caches along the path are populated.
|
||||||
crypto portion.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -325,6 +338,14 @@ FIPS uses two independent Noise Protocol handshakes at different layers:
|
|||||||
Both use `Noise_IK_secp256k1_ChaChaPoly_SHA256` with the same cryptographic
|
Both use `Noise_IK_secp256k1_ChaChaPoly_SHA256` with the same cryptographic
|
||||||
primitives, but with separate keys and sessions.
|
primitives, but with separate keys and sessions.
|
||||||
|
|
||||||
|
> **Privacy note**: Noise IK does not provide initiator anonymity if the
|
||||||
|
> responder's static key is compromised—an attacker who obtains the responder's
|
||||||
|
> nsec can decrypt the initiator's identity from captured handshake messages.
|
||||||
|
> Noise XK would protect initiator identity in this scenario, but requires an
|
||||||
|
> additional round-trip (3 handshake messages vs 2), increasing session setup
|
||||||
|
> from 3 packets to 4. Further deployment experience is needed to evaluate
|
||||||
|
> whether the privacy benefit justifies the latency cost.
|
||||||
|
|
||||||
### 6.1 Why Two Layers?
|
### 6.1 Why Two Layers?
|
||||||
|
|
||||||
**Link encryption** protects against passive observers on each hop but allows
|
**Link encryption** protects against passive observers on each hop but allows
|
||||||
|
|||||||
Reference in New Issue
Block a user