diff --git a/crates/tsunagi/src/dataplane/wireguard/device.rs b/crates/tsunagi/src/dataplane/wireguard/device.rs index b6c905c..a13e4b2 100644 --- a/crates/tsunagi/src/dataplane/wireguard/device.rs +++ b/crates/tsunagi/src/dataplane/wireguard/device.rs @@ -18,13 +18,15 @@ //! ourselves, and we do: //! //! * outbound, a packet is routed to the peer that **owns** its destination -//! address, where ownership is the derivation in [`super::overlay`]; +//! address, where ownership is the signed claim the system level agreed; //! * inbound, a decrypted packet is dropped unless its **source** is exactly -//! the address derived for the peer whose tunnel decrypted it. +//! the address that peer holds. //! //! So a participant cannot receive traffic addressed to someone else, and -//! cannot forge traffic that appears to come from someone else, no matter -//! what it announced. +//! cannot forge traffic that appears to come from someone else. Neither +//! check consults anything the peer said here: an address is claimed at the +//! system level and signed by its holder, and that is what is compared +//! against. use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr}; diff --git a/crates/tsunagi/src/dataplane/wireguard/mod.rs b/crates/tsunagi/src/dataplane/wireguard/mod.rs index ec989e1..d088acf 100644 --- a/crates/tsunagi/src/dataplane/wireguard/mod.rs +++ b/crates/tsunagi/src/dataplane/wireguard/mod.rs @@ -1,43 +1,37 @@ -//! The WireGuard data plane plugin. +//! The WireGuard protocol plugin. //! -//! WireGuard is the first IP plugin. It creates real IP connectivity between -//! participants, while the control plane keeps doing what it does: agreeing on -//! who is in the network and carrying each participant's opaque announcement. +//! The first of them. It carries IP packets between participants; deciding +//! who is in the network, what addresses they hold and which interface those +//! sit on belongs to the system level, which configures this and then leaves +//! it to get on with it. //! -//! The two planes stay separate: +//! Where the line falls: //! //! * **The plugin knows nothing about reachability.** It is handed a //! [`PacketLink`](crate::dataplane::transport::PacketLink) per peer and -//! bridges the kernel WireGuard device onto it. Hole punching and relaying -//! belong to the transport. -//! * **The announcement says who, not where.** It carries a public key, so -//! there is no address for a peer to lie about. -//! * **The core never parses these announcements.** It moves a bounded opaque -//! blob; only [`announcement`] interprets it. -//! * **Keys are separate.** The plugin has its own key per network, in its own -//! store, unrelated to the iroh device key and to the network secret. -//! * **WireGuard's own crypto is untouched.** The bridge is a pipe; the -//! handshake and encryption run end to end between the two kernels. +//! moves datagrams over it. Hole punching and relaying belong to the +//! transport. +//! * **The plugin knows nothing about addresses either.** They are allocated +//! and signed at the system level, the same ones whichever protocol is +//! moving the packets. Nothing here derives one. +//! * **The announcement says who, not where.** A public key and the network +//! it is for, so there is nothing about reachability for a peer to lie +//! about. +//! * **The core never parses these announcements.** It moves a bounded +//! opaque blob; only [`announcement`] interprets it. +//! * **Keys are separate.** One key per network, in its own store, unrelated +//! to the iroh device key and to the network secret. +//! * **WireGuard's own crypto is untouched.** The handshake and encryption +//! run end to end between the two ends of a tunnel. //! -//! # How a mesh forms +//! WireGuard itself is [`boringtun`]'s protocol state machine, running in +//! this process: no kernel module, no `wg` tool, the same code on every +//! platform. [`device::WireguardDevice`] drives one tunnel per peer. //! -//! Every participant derives its own overlay address from the network id and -//! its own WireGuard public key ([`overlay`]), so no coordinator hands out -//! addresses. Because that derivation is public, each agent computes every -//! peer's `AllowedIPs` itself instead of believing what the peer claims — a -//! member cannot route another member's traffic to itself. -//! -//! WireGuard itself is [`boringtun`]'s protocol state machine, running in this -//! process: no kernel module, no `wg` tool, the same code on every platform. -//! [`device::WireguardDevice`] drives one tunnel per peer and routes packets -//! between them and a [`tun::TunDevice`]. -//! -//! The only part that needs privileges is the packet interface. With -//! [`tun::MemoryTunFactory`] the whole data plane — handshake, encryption, -//! routing, address ownership — runs and is tested with no privileges at all. -//! For real traffic there is [`provision::ManagedTunFactory`], where the -//! agent creates and configures the interface itself over netlink and -//! removes it again on exit. +//! The interface underneath comes from [`crate::overlay`], and with its +//! in-memory implementation the whole data plane — handshake, encryption, +//! routing, address ownership — runs and is tested with no privileges at +//! all. //! //! See `docs/wireguard.md` for the full picture. diff --git a/crates/tsunagi/src/overlay/tun.rs b/crates/tsunagi/src/overlay/tun.rs index afd69fa..63538c4 100644 --- a/crates/tsunagi/src/overlay/tun.rs +++ b/crates/tsunagi/src/overlay/tun.rs @@ -1,8 +1,8 @@ //! The boundary to the operating system's packet interface. //! -//! The WireGuard implementation in [`super::device`] is pure userspace and -//! needs no kernel WireGuard module and no `wg` tool. It does still need a way -//! to hand IP packets to the operating system, which is what this trait is. +//! One agent has one of these, and it belongs to the agent rather than to +//! any protocol: a packet arriving here is routed to whichever peer owns its +//! destination, over whichever protocol has a link to that peer. //! //! Two implementations: //!