Implement the WireGuard data plane plugin
The first IP plugin, built on the data plane boundary the core already had. Plugin: - one X25519 key per network in the plugin's own wireguard.sqlite, separate from the iroh identity and from the network secret; a damaged store is an error, never a silently regenerated identity - deterministic IPv6 ULA overlay: every member derives the same /64 from the network id and its own /128 from its WireGuard public key, so no coordinator allocates addresses - AllowedIPs are derived locally, never taken from a peer's announcement, so a member cannot claim another member's overlay address; a mismatched claim is rejected - bounded, versioned, validated announcement carried as the existing opaque capability payload, which the core still never parses - each agent builds its own full-mesh configuration (N-1 peers) and reconciles on every change and on a timer, repairing drift - WireguardBackend abstraction: RecordingBackend in memory, and WgToolBackend driving real wg/ip on Linux, split into a pure planner plus parsers and a thin executor so everything interesting is testable without root Core, three generic additions the plugin needed: - IpPlugin::on_network_activated, so per-network state is ready before peers - PluginContext for re-announcements and error reports from plugin tasks, with errors counted by the owning network runtime - IpPlugin::shutdown, awaited with a grace period, so system objects go away 94 tests pass offline with no privileges: 35 new WireGuard unit tests and 12 integration tests over real iroh connections. The real wg/ip backend needs root and is behind --ignored in tests/wireguard_system.rs; it was not run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,15 +30,20 @@ A working library with **real iroh connections** and integration tests:
|
||||
- automatic reconnect with bounded exponential backoff and jitter;
|
||||
- status snapshots, an event stream and honest diagnostics;
|
||||
- configuration restored after a restart;
|
||||
- correct behaviour when the disposable cache is missing or corrupt.
|
||||
- correct behaviour when the disposable cache is missing or corrupt;
|
||||
- a **WireGuard data plane plugin**: its own key per network, deterministic
|
||||
IPv6 overlay addressing, a full-mesh configuration built locally, and
|
||||
reconciliation that repairs drift.
|
||||
|
||||
### What it deliberately does **not** do
|
||||
|
||||
Not implemented, and not pretended to be: WireGuard or any other IP plugin,
|
||||
Mainline DHT, DNS, routing through intermediate participants, a full CRDT,
|
||||
dynamically loaded plugins, a system service, a complete CLI, or a local
|
||||
control socket. Snapshot synchronisation and signed revocations are designed
|
||||
for but not implemented — see [docs/sync-model.md](docs/sync-model.md).
|
||||
Not implemented, and not pretended to be: Mainline DHT, DNS, routing through
|
||||
intermediate participants, a full CRDT, dynamically loaded plugins, a system
|
||||
service, a complete CLI, or a local control socket. Snapshot synchronisation
|
||||
and signed revocations are designed for but not implemented — see
|
||||
[docs/sync-model.md](docs/sync-model.md). The WireGuard plugin's own limits,
|
||||
including that its system backend is Linux-only, are in
|
||||
[docs/wireguard.md](docs/wireguard.md#limits-and-future-work).
|
||||
|
||||
**Only control messages travel over iroh. User IP traffic is not tunnelled
|
||||
through it.** Filtering user traffic is the operating system's and the user's
|
||||
@@ -61,11 +66,21 @@ cargo test --locked --workspace --all-targets
|
||||
The whole suite runs offline on loopback. Set `TSUNAGI_TEST_LOG=tsunagi=debug`
|
||||
to see agent logs while a test runs.
|
||||
|
||||
There is also a runnable demo, which is a demo and not a substitute for the
|
||||
There are also two runnable demos, which are demos and not substitutes for the
|
||||
tests:
|
||||
|
||||
```bash
|
||||
cargo run --example two_agents
|
||||
cargo run --example two_agents # control plane only
|
||||
cargo run --example wireguard_mesh # two agents forming a WireGuard overlay
|
||||
```
|
||||
|
||||
Both run with no privileges and change nothing on the host.
|
||||
|
||||
The one part that does change the host's network — the real `wg`/`ip` backend —
|
||||
is behind `--ignored` and needs Linux, wireguard-tools and `CAP_NET_ADMIN`:
|
||||
|
||||
```bash
|
||||
sudo -E cargo test --test wireguard_system -- --ignored --test-threads=1
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -127,12 +142,18 @@ paths; tests always use temporary directories.
|
||||
| `state.sqlite` | device identity, network configuration, hostname | clear error, never reset |
|
||||
| `cache.sqlite` | address hints and other recoverable data | discarded and recreated |
|
||||
|
||||
The WireGuard plugin keeps its own keys in its own `wireguard.sqlite`, wherever
|
||||
its configuration points, because plugin keys are neither the iroh identity nor
|
||||
the network secret.
|
||||
|
||||
One state directory belongs to one live agent, enforced with a real OS file
|
||||
lock rather than an existence check.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [docs/architecture.md](docs/architecture.md) — module boundaries and runtime.
|
||||
- [docs/wireguard.md](docs/wireguard.md) — the WireGuard plugin: overlay
|
||||
addressing, announcements, backends, reconciliation.
|
||||
- [docs/protocol.md](docs/protocol.md) — identity derivation, framing, handshake.
|
||||
- [docs/sync-model.md](docs/sync-model.md) — the planned signed-state model and
|
||||
what is deliberately not built yet.
|
||||
|
||||
Reference in New Issue
Block a user