Files
nx9-wg/docs/ARCHITECTURE.md
T
2026-09-02 15:19:19 +05:30

12 KiB

NX9 WireGuard — System Architecture & Workspace Structure

nx9-wg is structured as a modular six-crate Rust workspace designed for separation of concerns, strict failure domains, and testability.

nx9-wg (Workspace Root & Binary Executable)
 ├── crates/nx9-wg-core     (Domain models, validation, cryptography, config)
 ├── crates/nx9-wg-db       (SQLite store, migrations, repositories, WAL)
 ├── crates/nx9-wireguard   (WireGuard Netlink execution, config builder, QR engine)
 ├── crates/nx9-wg-network   (RTNETLINK networking, route management, nftables, procfs)
 ├── crates/nx9-wg-api       (Axum REST API, WebSockets, auth, reconciliation, allocator)
 └── crates/nx9-wg-ui        (Design tokens, CSS engine, view models, SPA integration)

1. Crate Inventory & Layer Responsibilities

nx9-wg-core

  • Domain Entities: Typed domain structures (Interface, Peer, Network, Route, FirewallRule, Setting, Admin, Session, ApiToken, BackupMeta, AuditEvent).
  • Validation: Strict RFC-compliant validators for CIDRs, IP addresses, MTU ranges, listen ports, interface names, peer names, and password strength.
  • Cryptography: Argon2id password hashing, SHA-256 token digest generation, X25519 keypair generation, and secure random string generation.
  • Configuration: Hierarchical TOML and NX9_WG_* environment variable configuration loader.

nx9-wg-db

  • Authoritative Persistence: Migration-driven SQLite storage using sqlx in Write-Ahead Logging (WAL) mode.
  • Single Admin Invariant: SQL constraint CHECK (id = 1) enforcing single-administrator identity.
  • Repositories: Isolated data access layers for admin, auth, audit, backups, client profiles, interfaces, login attempts, networks, peers, routes, sessions, settings, and tokens.
  • Transactional Consistency: Foreign key cascades (ON DELETE CASCADE) between interfaces and peers.

nx9-wireguard

  • Native Netlink Engine: NativeLinuxWireGuardEngine interacting with Linux RTNETLINK for link lifecycle and Generic Netlink family wireguard (SET_DEVICE, GET_DEVICE, ReplacePeers).
  • Client Config Generation: Pure Rust .conf generation supporting full-tunnel and split-tunnel topologies.
  • QR Code Engine: High-resolution SVG, PNG byte streams, and UTF-8 ASCII terminal QR code rendering.
  • Simulation Engine: SimulatedWireGuardEngine for non-Linux platform development and testing.

nx9-wg-network

  • Native Network Engine: NativeLinuxNetworkEngine managing RTNETLINK interfaces, IPv4/IPv6 addresses, and route tables.
  • nftables Netfilter Engine: NativeLinuxNftablesEngine utilizing libnftables.so.1 for transactional rule generation in table inet nx9_wg.
  • Kernel IP Forwarding: Direct /proc/sys/net/ipv4/ip_forward and /proc/sys/net/ipv6/conf/all/forwarding mutation.
  • Simulation Engine: SimulatedNetworkEngine for local platform testing.

nx9-wg-api

  • REST Router: Axum HTTP handlers for auth, interfaces, peers, networks, routes, firewall, NAT, forwarding, settings, backups, diagnostics, and audit logs.
  • WebSocket Event Bus: Tokio broadcast channel broadcasting real-time system events (AuditEvent, InterfaceChanged, PeerChanged, PeerHandshake, SettingsChanged).
  • Reconciliation Engine: Mutex-serialized continuous drift detection and convergence controller.
  • Deterministic IP Allocator: Collision-resistant next-IP allocation engine for managed subnets.
  • Backup & Restore Service: Online SQLite atomic snapshot (VACUUM INTO) and verification engine.

nx9-wg-ui

  • Design Tokens: Structured CSS variable tokens for Dark and Light themes.
  • Stylesheet Generator: In-process CSS compiler producing responsive layouts (@media (max-width: 768px)).
  • View Models: Strongly-typed Rust UI state representations for dashboards, diagnostics, client export modals, and peer management tables.

2. End-to-End Control and Execution Plane

flowchart TD
    subgraph ControlPlane["Control Plane (User & Administration)"]
        User["Administrator (Browser / CLI)"]
        SPA["Embedded SPA Web UI"]
        CLI["Native CLI (nx9-wg)"]
        API["Axum REST API / WebSockets"]
        DB[("Authoritative SQLite Database")]
    end

    subgraph ReconciliationLayer["Reconciliation & Engine Layer"]
        Reconciler["Reconciliation Engine (Serialized Mutex)"]
        WGEngine["WireGuard Engine (Genl / RTNETLINK)"]
        NetEngine["Network Engine (RTNETLINK & procfs)"]
        NftEngine["Nftables Engine (libnftables Netfilter)"]
    end

    subgraph LinuxKernel["Linux Kernel Execution Plane"]
        WGSocket["WireGuard Kernel Module (wireguard.ko)"]
        RTNL["Kernel RTNETLINK (Links, Addrs, Routes)"]
        Procfs["/proc/sys/net (IP Forwarding)"]
        Netfilter["Netfilter Subsystem (table inet nx9_wg)"]
    end

    User -->|HTTPS / WSS| SPA
    User -->|CLI Invocations| CLI
    SPA -->|REST API Calls| API
    CLI -->|In-Process Service Calls| API
    API -->|Authoritative Mutations| DB
    DB -->|Desired State Snapshot| Reconciler
    Reconciler -->|Read Live Telemetry| WGEngine
    Reconciler -->|Read Live Routes/Forwarding| NetEngine
    Reconciler -->|Read Live Ruleset| NftEngine
    WGEngine -->|Generic Netlink Messages| WGSocket
    NetEngine -->|RTM_NEWLINK / NEWROUTE| RTNL
    NetEngine -->|Write 1/0| Procfs
    NftEngine -->|Atomic Netfilter Transactions| Netfilter

3. Subsystem Invariants & Security Boundaries

  1. Subprocess Isolation: Zero invocations of std::process::Command or shell scripts across the entire production codebase.
  2. Persistence Authority: SQLite remains the single authoritative source of truth. Kernel state is continuously reconciled to match database state.
  3. Firewall Isolation: All nftables operations are confined to table inet nx9_wg. Unmanaged host tables are untouched.
  4. Route Safety: Default gateway routes and physical host networking routes are protected against accidental deletion or flushing.
  5. Secret Redaction: Private keys, preshared keys, password hashes, and token hashes are masked in Debug formatters, CLI outputs, and API responses.

4. Interface Roles & Upstream Architecture

nx9-wg implements explicit InterfaceRole categorization across domain models, Netlink device configuration, and reconciliation:

┌────────────────────────────────────────────────────────────────────────────────────────┐
│                                   Linux Host Network                                   │
│                                                                                        │
│   ┌────────────────────────────────┐            ┌──────────────────────────────────┐   │
│   │   Primary Overlay (wg0)        │            │   Optional Upstream (proton0)    │   │
│   │   Role: Overlay                │            │   Role: Upstream                 │   │
│   │   Local Listen Port: 51820     │            │   Local Listen Port: Auto (Dyn)  │   │
│   │   Peers: 1..N Clients (Mobile) │            │   Peers: Exactly 1 Provider Peer │   │
│   │   Cryptokey AllowedIPs: /32    │            │   Cryptokey AllowedIPs: 0/0, ::0 │   │
│   └────────────────────────────────┘            └──────────────────────────────────┘   │
│                   │                                              │                     │
│                   ▼                                              ▼                     │
│   ┌────────────────────────────────┐            ┌──────────────────────────────────┐   │
│   │  Private Overlay Clients       │            │  Remote Provider Endpoint        │   │
│   │  (10.100.0.0/24 Subnet)        │            │  (37.19.199.155:51820)           │   │
│   └────────────────────────────────┘            └──────────────────────────────────┘   │
│                                                                  │                     │
│                                                                  ▼                     │
│                             ┌────────────────────────────────────────┐                 │
│                             │ Physical WAN Default Route (eno2)      │                 │
│                             │ Gateway: 192.168.1.1 (FIB Unchanged)   │                 │
│                             └────────────────────────────────────────┘                 │
└────────────────────────────────────────────────────────────────────────────────────────┘

A. Role Discriminator & Invariants

  • InterfaceRole::Overlay: The primary private WireGuard overlay network. Exactly one instance exists (wg0). It binds to an explicit listen port (51820), hosts enrolled client peers, and is protected from deletion or disabling.
  • InterfaceRole::Upstream: Optional third-party WireGuard VPN interfaces (e.g. proton0). Zero or more instances may exist concurrently. Each Upstream interface connects NX9-WG to an external service provider through exactly one provider peer.

B. Optional Local Listen Port & Ephemeral Kernel Binding

  • Interface.listen_port is modeled as Option<u16>.
  • Standard third-party .conf imports (e.g. ProtonVPN) omit [Interface] ListenPort. NX9-WG preserves listen_port = None without defaulting to 51820.
  • In configure_device, omitting the WireguardAttribute::ListenPort Netlink attribute signals the Linux kernel to assign an ephemeral dynamic UDP port automatically.
  • This prevents local UDP port contention and allows wg0 (51820) and proton0 (dynamic) to coexist without -EADDRINUSE errors.
  • Dynamic kernel ports produce 0 false drift actions in the reconciliation engine when desired listen_port is None.

C. Cryptokey Routing vs. Linux FIB Default Routes

  • An Upstream provider peer often specifies AllowedIPs = 0.0.0.0/0, ::/0 in its .conf.
  • In WireGuard, AllowedIPs defines the device-level cryptokey packet routing filter; it does not install a Linux kernel route.
  • NX9-WG preserves 0.0.0.0/0, ::/0 on the proton0 WireGuard device without modifying the server's Linux FIB default gateway (192.168.1.1).
  • The provider endpoint (37.19.199.155:51820) remains reachable via the host physical WAN interface.

D. NAT Masquerade Isolation

  • Outbound NAT masquerading compiled into table inet nx9_wg is strictly scoped to Overlay client subnets (10.100.0.0/24).
  • Upstream tunnel addresses (10.2.0.2/32) are not treated as client subnets and do not trigger unsolicited global masquerading.