92 lines
5.5 KiB
Markdown
92 lines
5.5 KiB
Markdown
# Native Linux WireGuard Engine (`NativeLinuxWireGuardEngine`)
|
|
|
|
The `NativeLinuxWireGuardEngine` provides direct, in-process communication with the Linux kernel WireGuard subsystem via Linux Netlink sockets.
|
|
|
|
---
|
|
|
|
## 1. Protocol Architecture: RTNETLINK & Generic Netlink
|
|
|
|
Unlike traditional WireGuard management tools that spawn external CLI processes (`wg`, `wg-quick`), `nx9-wg` uses native kernel sockets:
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────┐
|
|
│ NativeLinuxWireGuardEngine │
|
|
└───────────────┬────────────────────────┬───────────────┘
|
|
│ │
|
|
Link Lifecycle (Create / Up / Down) │ Cryptographic Config & Telemetry
|
|
via RTNETLINK (AF_NETLINK, NETLINK_ROUTE)│ via Generic Netlink (family "wireguard")
|
|
│ │
|
|
┌───────────────▼────────────────────────▼───────────────┐
|
|
│ Linux Kernel (wireguard.ko) │
|
|
└────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### A. RTNETLINK Link Lifecycle
|
|
- **Interface Creation**: Sends `RTM_NEWLINK` with link type `wireguard`.
|
|
- **Interface Deletion**: Sends `RTM_DELLINK` by interface index or name.
|
|
- **Interface State**: Toggles `IFF_UP` and `IFF_DOWN` flags without invoking `ip link set up/down`.
|
|
- **MTU Assignment**: Configures interface MTU directly in the `RTM_NEWLINK` netlink attributes.
|
|
|
|
### B. WireGuard Generic Netlink Protocol
|
|
- Resolves the dynamic Generic Netlink family ID for `"wireguard"`.
|
|
- **`WG_CMD_SET_DEVICE`**: Atomically configures the interface private key, UDP listen port (if explicitly configured), and peer list.
|
|
- **Optional ListenPort**: If `interface.listen_port` is `Some(port)` and `port != 0`, `WGDEVICE_A_LISTEN_PORT` is emitted. If `None` (standard for Upstream interfaces like `proton0`), the attribute is omitted, allowing the Linux kernel to automatically bind an ephemeral dynamic UDP port.
|
|
- **`WG_CMD_GET_DEVICE`**: Queries live kernel device state, active listen port, public key, peer public keys, endpoints, allowed IPs, last handshake timestamps, and transfer byte counters.
|
|
- **`WGDEVICE_F_REPLACE_PEERS`**: When syncing peers, setting this flag instructs the kernel to atomically replace all existing peers with the supplied desired set, removing stale peers in a single transaction.
|
|
|
|
---
|
|
|
|
## 2. Peer Cryptographic Synchronization & Role-Aware AllowedIPs
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
autonumber
|
|
participant Engine as NativeLinuxWireGuardEngine
|
|
participant Genl as Generic Netlink Socket
|
|
participant Kernel as Linux Kernel (wireguard.ko)
|
|
|
|
Engine->>Genl: Send WG_CMD_SET_DEVICE (Interface wg0, ReplacePeers=true)
|
|
Note over Engine,Genl: Encodes ListenPort (if Some), PrivateKey, Peer Array
|
|
Genl->>Kernel: Transmit Netlink Message
|
|
Kernel->>Kernel: Validate Keys, Bind UDP Port (or dynamic), Apply Peers
|
|
Kernel-->>Genl: NLMSG_ERROR (error=0 / Success)
|
|
Genl-->>Engine: Ok(())
|
|
|
|
Engine->>Genl: Send WG_CMD_GET_DEVICE (Interface wg0)
|
|
Genl->>Kernel: Query Live State
|
|
Kernel-->>Genl: Return Device Attributes & Peer Telemetry
|
|
Genl-->>Engine: Live Telemetry (Handshakes, Bytes Tx/Rx)
|
|
```
|
|
|
|
### Role-Aware Cryptographic Attribute Encoding:
|
|
- **Keys**: 32-byte binary Curve25519 keys (`WGPEER_A_PUBLIC_KEY`, `WGPEER_A_PRESHARED_KEY`).
|
|
- **Role-Aware Allowed IPs**:
|
|
- **Overlay Peers**: Scoped to `/32` (IPv4) or `/128` (IPv6) derived from the peer's assigned tunnel address.
|
|
- **Upstream Provider Peers**: Preserves full-tunnel AllowedIPs (`0.0.0.0/0, ::/0`) on the WireGuard device without modifying the server's Linux FIB default routing table.
|
|
- **Endpoint**: `sockaddr_in` (IPv4) or `sockaddr_in6` (IPv6) socket address structures representing the remote destination (e.g. `37.19.199.155:51820`), independent of the local interface listen port.
|
|
- **Persistent Keepalive**: Interval in seconds (`WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL`).
|
|
|
|
---
|
|
|
|
## 3. Telemetry & Handshake Monitoring
|
|
|
|
The engine queries live kernel transfer statistics without writing temporary files:
|
|
- **`last_handshake_at`**: Calculated from `WGPEER_A_LAST_HANDSHAKE_TIME` (seconds and nanoseconds since UNIX epoch).
|
|
- **`rx_bytes` / `tx_bytes`**: 64-bit byte counters (`WGPEER_A_RX_BYTES`, `WGPEER_A_TX_BYTES`).
|
|
- **`endpoint`**: Actual remote socket address learned dynamically by the kernel through authenticated roaming.
|
|
|
|
---
|
|
|
|
## 4. Security & Memory Safety Invariants
|
|
|
|
1. **Zero Subprocesses**: No calls to `wg`, `wg-quick`, or `ip`.
|
|
2. **Secret Redaction**: Private keys and preshared keys implement custom `std::fmt::Debug` formatters emitting `[REDACTED]`.
|
|
3. **Memory Scrubbing**: Sensitive cryptographic buffers are wrapped in types that zeroize memory upon drop.
|
|
4. **Linux Capability Boundary**: Requires `CAP_NET_ADMIN` to open Netlink route and generic sockets.
|
|
|
|
---
|
|
|
|
## 5. Non-Linux Platform Fallback
|
|
|
|
On non-Linux platforms (macOS, Windows), `nx9-wg` automatically switches to `SimulatedWireGuardEngine`. This allows frontend UI and CLI development on local workstations while preserving the exact same `WireGuardEngine` trait interface.
|