Mesh VPN: LXMF-Negotiated WireGuard Tunnels
Source:
styrened/docs/mesh-vpn-architecture.mdStatus: Architecture / Design — Phase 1 implementation planned
Problem
Reticulum excels at identity, discovery, and reliable messaging across constrained links. It does not excel at bulk IP traffic — tunneling IP packets through RNS links wastes the bandwidth of co-located high-speed transports (WiFi, Ethernet) that could carry the same traffic at orders of magnitude higher throughput.
LXMF gives us authenticated, encrypted, store-and-forward messaging between nodes with cryptographic identity. WireGuard gives us high-performance encrypted IP tunnels. The missing piece: using one to bootstrap the other.
Core Idea
Use LXMF messages as the signaling and key exchange channel to negotiate WireGuard tunnels over whatever high-bandwidth transport is available (802.11s WiFi mesh, Ethernet, IP backhaul). Reticulum provides identity, discovery, and mutual authentication — eliminating the need for traditional PKI, IKE daemons, or manual key distribution.
The result: a mesh VPN that bootstraps itself from RNS identity alone.
Architecture
Separation of Planes
┌──────────────────────────────────────────────────────┐
│ Application Traffic (SSH, HTTP, git, monitoring) │
├──────────────────────────────────────────────────────┤
│ WireGuard Tunnel (wg-styrene interface) │
│ Overlay: 10.73.0.0/24 │
├──────────────────────────────────────────────────────┤
│ 802.11s Mesh or IP backhaul (Layer 2/3) │ DATA PLANE
╞══════════════════════════════════════════════════════╡
│ Styrene Wire Protocol (tunnel negotiation msgs) │
│ LXMF (reliable delivery, store-and-forward) │ CONTROL PLANE
│ RNS (identity, path discovery, link encryption) │
│ Any RNS transport (LoRa, serial, TCP, 802.11s) │
└──────────────────────────────────────────────────────┘
Control and data planes are physically separable — the control plane can run over LoRa while the data plane runs over WiFi.
Trust Model
No certificate authority. No PKI infrastructure. No key distribution ceremony:
RNS Identity (Curve25519 key pair, already exists)
└─ authenticates LXMF message sender
└─ LXMF TunnelOffer carries WireGuard public key
└─ WireGuard key trusted because sender is authenticated
└─ Tunnel traffic authenticated by WireGuard key
Trust is scoped by fleet membership (via hub registry) and explicit allow-lists.
Wire Protocol Extension
Tunnel negotiation uses the Styrene wire protocol (StyreneEnvelope over LXMF FIELD_CUSTOM_DATA). New message types in the reserved 0xD8–0xDF range:
| Type | Code | Purpose |
|---|---|---|
TUNNEL_OFFER | 0xD8 | Initiate tunnel — carries WireGuard pubkey, mesh address, proposed overlay IP |
TUNNEL_ACCEPT | 0xD9 | Accept tunnel — carries responder’s parameters |
TUNNEL_REJECT | 0xDA | Reject with reason code (untrusted, capacity, disabled, address conflict) |
TUNNEL_TEARDOWN | 0xDB | Graceful or best-effort tunnel teardown |
TUNNEL_REKEY | 0xDC | Rotate WireGuard keys with coordinated switchover |
TUNNEL_KEEPALIVE | 0xDD | Health check with tunnel statistics |
TUNNEL_TOPOLOGY | 0xDE | Share active tunnel peer list (optional) |
All payloads are msgpack-encoded, consistent with the existing wire format.
Replay Protection
Every TUNNEL_OFFER and TUNNEL_ACCEPT includes a 16-byte random nonce and timestamp. Receivers reject stale messages (>60s), cache seen nonces (120s), and drop messages from unknown identities before parsing — zero processing cost for spam.
Transport Tier Model
Nodes automatically promote and demote connections through four tiers:
| Tier | Transport | Capability | Bandwidth |
|---|---|---|---|
| 3: FULL | WireGuard over 802.11s/Ethernet | Full IP connectivity | 10–100+ Mbps |
| 2: RNS_WIFI | RNS Link over 802.11s | LXMF messaging, file transfer, terminal | 1–50 Mbps |
| 1: RNS_LORA | RNS over LoRa | LXMF messaging only | 0.3–21.9 kbps |
| 0: OFFLINE | None | Queued for later delivery | — |
Promotion is opportunistic and automatic — 802.11s peer detected → RNS link available → tunnel negotiated → full IP. Demotion is event-driven — WireGuard handshake timeout → tunnel torn down → fall back to next available transport.
Overlay IP Assignment
Three strategies, selectable per deployment:
- Deterministic (default): Derived from RNS identity hash via BLAKE2b. No coordination needed. Collision probability ~0.4% for 10 nodes in a /24; collisions resolved by lower-hash-wins rule.
- Hub-assigned: Fleet hub maintains an IP allocation table (SQLite). Nodes request addresses before offering tunnels.
- Manual: Static config for permanent infrastructure nodes (hubs, gateways).
Default overlay subnet: 10.73.0.0/24 (253 peers; /16 available for larger fleets).
802.11s Mesh Integration
802.11s (IEEE 802.11s-2011) provides Layer 2 mesh networking with HWMP path selection. Supported by most modern WiFi chipsets on Linux via mac80211.
- SAE encryption: Optional WPA3-grade L2 encryption. Passphrase distributed via encrypted LXMF messages or hub CONFIG_UPDATE.
- Channel selection: Fleet-wide config parameter. Default: channel 6 (2.4 GHz). DFS deferred.
- Hardware: Pi 4B (BCM43455 ✓), Pi Zero 2W (BCM43436s ✓), USB RTL8812AU (varies). ESP32 uses proprietary ESP-MESH, not 802.11s — participates via gateway bridging.
Relation to Existing Features
| Feature | Current Transport | With Active Tunnel |
|---|---|---|
| Terminal sessions | RNS Link via LXMF | Plain SSH over overlay (optional) |
| File transfer | LXMF FILE_OFFER/CHUNK | SCP/rsync over overlay |
| Fleet RPC | LXMF | HTTP API over overlay (lower latency) |
| git-over-styrene | Custom git-remote-rns | Standard SSH/HTTPS git (overlay) |
The custom transports remain valuable for Tier 1 (mesh-only) scenarios where no tunnel is available.
Implementation Plan
Phase 1: Wire Protocol + Negotiation (No 802.11s)
Two styrened nodes on the same LAN negotiate a WireGuard tunnel via LXMF:
- TUNNEL_* message types added to
StyreneMessageTypeenum TunnelManagerservice: FSM (idle → offered → established → rekeying → teardown)- WireGuard configured via
pyroute2netlink (no shell-outs towg/ip) - Tunnel capability advertised in RNS announce data
- New dependency:
pyroute2for netlink
Phase 2: 802.11s Integration
Automatic mesh setup and tunnel promotion:
MeshWifiManagerservice: creates mesh0 interface, monitors mesh peer events- Tier promotion/demotion FSM connected to TunnelManager
- SAE passphrase distribution via CONFIG_UPDATE
- Bare-metal testing on Pi 4B fleet
Phase 3: Fleet-Wide Mesh VPN
Hub-coordinated overlay network:
- Hub-side IP allocation (SQLite)
- TUNNEL_TOPOLOGY exchange for mesh-wide routing
- TUI integration: tunnel status in fleet view
- Graceful degradation testing: kill WiFi → verify LoRa signaling continues → restore WiFi → verify tunnel re-establishes
styrene-rs Parity
Same wire protocol (0xD8–0xDE), same msgpack payloads, same negotiation FSM. Rust implementation uses wireguard-uapi, rtnetlink, and nl80211 crates. Python ↔ Rust interop is a design requirement.
Security
| Layer | Protection | Provider |
|---|---|---|
| Signaling (LXMF) | End-to-end encryption | RNS Link / LXMF |
| Tunnel negotiation | Authenticated key exchange | RNS identity verification |
| WireGuard handshake | Noise IK | WireGuard |
| Tunnel traffic | ChaCha20-Poly1305 | WireGuard |
| 802.11s L2 (optional) | SAE (WPA3) | mac80211 |
Key rotation via TUNNEL_REKEY: default every 24 hours, configurable per fleet. Grace period for in-flight packets during switchover.
Open Questions
- WireGuard key derivation: Derive from RNS identity (simpler, shared blast radius) or generate independently (defense in depth)?
- IPv6 overlay:
fe80::+ EUI-64 from RNS hash eliminates address assignment entirely. - Bridge mode: Should tunnel-capable nodes with LoRa + WiFi route IP between the two? Powerful but complex.
- Non-Linux: 802.11s is Linux-specific. WireGuard is cross-platform. Degrade to WireGuard-over-IP on macOS/Windows?
- Power budget: Disable mesh WiFi on battery-powered devices?
See Also
- wire-protocol-migration — Wire protocol v2 that tunnel messages extend
- fleet-provisioning-rpc — Fleet RPC that tunnels can accelerate
- BATMAN-adv — Alternative L2 mesh (BATMAN V vs 802.11s trade-offs)
- ble-mesh-transport — BLE fills the gap between LoRa and WiFi
- reticulum — Foundation transport layer