guard/docs/research/architecture.md
loki5512344 15f474486a
feat!: universal redesign — drop Minecraft stack, single-crate architecture
- remove Java plugins (velocity/paper), dashboard, all MC-specific code
  (handshake, death_code, varint, hostname-HMAC); available in history pre-v0.2
- merge crates/* into one package with src/bin/{rampart,rampart-manager,rampart-cli}
- ProtocolHandler trait + registry (no implementations yet), universal PoW kept
- XDP: universal L3/L4 filter (xdp/core/) + pluggable hook API (xdp/hooks/),
  fix IPv6 saddr bug; clang build verified
- docs: bilingual knowledge base (docs/kb/: attacks x4, defense-levels,
  practice x3), rewrite README/architecture for universal concept
- TODO.md v4.0: <=300-line module limit, competitor benchmark section (ref/)
- deploy/CI/docs cleanup: no MC references, new binary names

cargo build/clippy(-D warnings)/test green (55 tests)
2026-08-24 01:50:22 +02:00

15 KiB
Raw Permalink Blame History

Architecture — Rampart

Relevant for: v0.3+ (universal redesign) Status: primary design document Language: English (research notes) — see RU summary at the end


What changed

Rampart began as a 6-layer, Minecraft-specific protection stack: XDP filter with hardcoded Minecraft handshake states → PoW → Rust L7 core → Velocity proxy (Java) → Paper agent (Java) → Traffic Intel. The big-bang redesign turns it into a universal L3/L4/L7 network protection platform for any TCP service:

  • VDS / dedicated servers,
  • web services and APIs,
  • game servers of any kind (Minecraft is now just a plugin, not the core).

The layer count drops from 6 to 4. Everything protocol-specific is extracted from the core into compile-time protocol plugins; everything Java-based is removed.

Layered architecture

┌──────────────────────────────────────────────────────────────────────┐
│  LAYER 1: XDP/eBPF (C)            drop L3/L4 before kernel TCP stack │
│  ─────────────────────────────                                       │
│  Universal (protocol-agnostic):                                      │
│    + Generic TCP state machine (SYN → ESTABLISHED lifecycle,         │
│      per-connection seq tracking, bpf_timer idle cleanup)            │
│    + SYN throttle per-IP                                             │
│    + IP/CIDR blacklist + whitelist (LPM_TRIE)                        │
│    + Invalid TCP flags drop (SYN+FIN, SYN+RST, URG, empty)           │
│    + UDP policy (configurable: pass / drop / rate-limit)             │
│    + Pluggable BPF protocol hooks (see ADR-002)                      │
├──────────────────────────────────────────────────────────────────────┤
│  LAYER 2: Universal PoW Challenge (Rust)     anti-handshake-flood    │
│  ─────────────────────────────                                       │
│    SHA256 hashcash over any TCP protocol (see ADR-004):              │
│      1. Edge sends challenge (random + timestamp + difficulty)       │
│      2. Client solves PoW (nonce brute-force)                        │
│      3. Edge verifies SHA256(data + nonce) prefix                    │
│    + Dynamic difficulty: rises when CPS > threshold                  │
│    + Per-connection one-time challenge (nonce replay protection)     │
├──────────────────────────────────────────────────────────────────────┤
│  LAYER 3: Rust Userspace Core                L7 filtering            │
│  ─────────────────────────────                                       │
│    + L7 handshake analysis (via active protocol plugin)              │
│    + Rate limit (token bucket per-IP)                                │
│    + HMAC signatures (constant-time compare)                         │
│    + Death-code patterns (auto-ban on malicious payloads)            │
├──────────────────────────────────────────────────────────────────────┤
│  LAYER 4: Protocol Plugins (compile-time feature crates)             │
│  ─────────────────────────────                                       │
│    + minecraft — first plugin (existing MC-handshake code moved in)  │
│    + http, grpc — planned                                            │
└──────────────────────────────────────────────────────────────────────┘

  TRAFFIC INTEL (cross-cutting, Rust + Redis):
    + EWMA adaptive thresholds
    + Traffic profiling (per-slot baselines)
    + IP reputation system

Traffic path

Attacker (botnet)
    |
    v
[1] XDP/eBPF ─── universal TCP state machine ─── CIDR lists ─── SYN throttle
    |           drop: SYN flood, invalid flags, blacklisted CIDRs,
    |                 UDP policy violations, failed BPF hook checks
    v (clean TCP that passed state machine + hooks)
[2] PoW Challenge ─── SHA256 hashcash ─── dynamic difficulty   [OFF by default]
    |           drop: did not solve PoW in time
    v (valid PoW)
[3] Userspace Core ─── plugin handshake parse ─── rate limit ─── death codes
    |           drop: rate limit, malformed packets
    v (validated application-layer client)
[4] Consumer service (game server, web backend, ...)

Component diagram

flowchart TB
    subgraph Kernel["Layer 1 — Kernel"]
        XDP["XDP/eBPF filter (C)<br/>TCP state machine · SYN throttle<br/>CIDR black/white · UDP policy"]
        HOOKS["BPF protocol hooks<br/>(pluggable modules)"]
        XDP --- HOOKS
    end

    subgraph Core["rampart-core (Rust)"]
        LOADER["XDP loader<br/>(libbpf / aya)"]
        POW["PoW challenge engine<br/>(SHA256 hashcash)"]
        L7["L7 filtering core<br/>rate limit · HMAC · death codes"]
        INTEL["Traffic Intel<br/>EWMA · profiling · reputation"]
        LOADER --> XDP
        POW --> L7 --> PLUGINAPI
        INTEL -.->|thresholds & scores| L7
        INTEL -.->|dynamic difficulty| POW
    end

    subgraph Plugins["Layer 4 — Protocol plugins (feature crates)"]
        PLUGINAPI["Plugin trait API<br/>(stabilization in progress)"]
        MC["minecraft plugin"]
        HTTP["http plugin<br/>(planned)"]
        GRPC["grpc plugin<br/>(planned)"]
        PLUGINAPI --> MC
        PLUGINAPI -.-> HTTP
        PLUGINAPI -.-> GRPC
    end

    subgraph Control["Control plane"]
        MANAGER["rampart-manager<br/>(axum API)"]
        REDIS[(Redis)]
        CLI["rampart-cli"]
        MANAGER <--> REDIS
        CLI --> MANAGER
    end

    L7 --> BACKEND["Protected service<br/>(game server / web backend / VDS)"]

    style HTTP stroke-dasharray: 5 5
    style GRPC stroke-dasharray: 5 5

Architecture Decision Records

ADR-004: Compile-time protocol plugins instead of hardcoded Minecraft

Context. The Rust userspace core originally parsed only Minecraft handshakes (VarInt decoding, hostname bounds checks). Every non-Minecraft use case required forking the codebase.

Decision. Protocol-specific parsing moves behind an internal plugin trait API implemented by separate feature crates (rampart-plugin-minecraft, later rampart-plugin-http, rampart-plugin-grpc). Plugins are selected at compile time via Cargo features — no dynamic loading, no ABI stability burden. The first plugin, minecraft, receives the existing MC-handshake code as-is.

Consequences.

  • (+) The core becomes protocol-neutral; one platform covers VDS, web, and games.
  • (+) Compile-time selection keeps dispatch static and the hot path monomorphic.
  • (−) Supporting multiple protocols simultaneously requires composing feature sets per build; runtime protocol multiplexing is out of scope until the plugin API stabilizes.
  • (−) The trait API must stabilize before third-party plugins appear (roadmap).

ADR-005: Pluggable BPF hooks instead of hardcoded Minecraft states

Context. The XDP program contained a Minecraft-specific TCP state machine: AWAIT_ACK → AWAIT_MC_HANDSHAKE → AWAIT_LOGIN → verified. This made Layer 1 unusable for any non-Minecraft traffic.

Decision. The XDP filter keeps only generic, protocol-agnostic logic: a universal TCP lifecycle state machine, SYN throttle, CIDR black/white lists, TCP-flag sanity checks, and configurable UDP policy. Deep protocol parsing moves into separate BPF hook modules attached to the main filter at load time. Each hook can inspect payload after the TCP header and return allow/drop/skip.

Consequences.

  • (+) Layer 1 works for arbitrary TCP services out of the box.
  • (+) Hook modules keep the main filter small, auditable, and verifiable.
  • (−) Hook attachment adds a map-dispatch indirection on the hot path; measured cost is acceptable, but the full benchmark suite is still in progress.
  • (−) Hooks are more constrained than userspace parsing (no loops without bounded verification); anything complex stays in Layer 3.

ADR-006: Remove Java layers (Velocity/Paper) and React dashboard

Context. Layers 4–5 were Java services: a Velocity proxy performing domain checks, HMAC verification, physics/CAPTCHA challenges, plus a Paper agent doing Redis heartbeat and server auto-registration. A React dashboard covered the control plane UI.

Decision. All Java components and the dashboard are removed from the repository. Consumers integrate with Rampart through the Manager API (axum + Redis sync) instead of embedding proxy-side Java plugins. See Migration notes.

Consequences.

  • (+) Universality: Rampart no longer assumes Minecraft or the JVM at all; it protects whatever sits behind it.
  • (+) Dramatically smaller deployment surface: edge nodes are pure Rust + C.
  • (−) Capabilities unique to the Java layers (physics checks, in-game CAPTCHA) are gone; where needed they become responsibilities of consumer-side plugins built against the Manager API.
  • (−) Existing Velocity/Paper deployments must migrate or stay on pre-redesign git history.

ADR-007: Universal PoW stays, off by default

Context. The SHA256 hashcash challenge previously assumed a Minecraft text-challenge flow, which vanilla clients could not solve. In the universal platform the challenge is redefined to work over any TCP protocol.

Decision. Keep the PoW layer as a core capability, redesigned as a protocol-independent challenge, but ship it disabled by default (pow.enabled = false). Operators enable it when their client ecosystem can answer the challenge (custom clients, modded protocols, HTTP integrations).

Consequences.

  • (+) Anti-handshake-flood capability remains available platform-wide.
  • (+) Default configuration never breaks clients that cannot solve PoW.
  • (−) Out of the box, handshake floods are mitigated only by Layer 1 throttling and Layer 3 rate limits until PoW is explicitly enabled.

ADR-008: Bilingual knowledge base as documentation-first strategy

Context. Operational experience (attack anatomy, defense levels, practice guides) was scattered across research notes, runbooks, and chat history. New operators repeatedly rediscovered the same lessons.

Decision. Maintain docs/kb/ as a curated, bilingual (EN/RU) knowledge base: attack anatomy, defense level explanations, and practice guides. Documentation-first: every new attack class or defense mechanism gets a KB entry as part of the change, not after the fact.

Consequences.

  • (+) Onboarding cost drops; operational decisions cite KB articles.
  • (+) EN/RU mirroring serves both the international audience and the original Russian-speaking operator community.
  • (−) Bilingual maintenance doubles writing effort; entries may temporarily lag in one language.

Migration notes

Removed from the repository (recoverable from git history):

  • plugins/ — Java Velocity plugin (domain whitelist, physics checks, CAPTCHA, TPS-aware routing) and Paper agent (Redis heartbeat, auto-registration).
  • velocity/, paper/ — build scaffolding for the Java layers.
  • dashboard/ — React + Vite + TypeScript control plane UI.

All removed sources remain accessible in git history (git log --follow -- plugins/ velocity/ paper/ dashboard/).

Moved into the plugin crate:

  • Minecraft handshake parsing (VarInt, bounds checks) from the Rust core → minecraft protocol plugin crate.
  • Minecraft-specific connection states in the XDP state machine → replaced by the universal state machine; MC-specific deep parsing will reappear as a BPF hook module (planned).

Kept in place:

  • XDP/eBPF generic filtering (maps, LPM trie, throttle timers).
  • SHA256 hashcash PoW engine (redesigned to be protocol-agnostic, off by default).
  • Rate limiting, HMAC, death-code pattern matching in the userspace core.
  • Traffic Intel (EWMA thresholds, profiling, reputation).
  • Manager API (axum) + Redis sync, CLI.

Integration path for former Java-layer consumers: talk to rampart-manager's HTTP API for server registration, blacklists, and event streams. There is no in-process Java integration anymore.

Requirements (edge node)

Item Requirement
Virtualization KVM / Bare Metal (XDP does not work under OpenVZ/LXC; check systemd-detect-virt)
Kernel 5.10+
CPU/RAM 2–4 vCPU, 2–4 GB
XDP drivers native: Intel i40e, Mellanox ConnectX; virtio falls back to generic mode

Historical ADRs (pre-redesign, still valid)

  • ADR-001: Rust for the edge core. Rust + tokio over Go (GC pauses), C (memory safety), Java (footprint). Zero-cost abstractions + libbpf-rs.
  • ADR-002: Redis as state store. Redis + local cache on edge nodes; edges keep operating from cache if Redis is down; Redis Cluster/Sentinel for scale/HA.
  • ADR-003: NATS for critical events. NATS JetStream for blacklist updates, attack events, audit log — at-least-once delivery instead of Redis Pub/Sub's fire-and-forget.

RU summary (краткая выжимка)

Rampart переработан из 6-слойной Minecraft-специфичной защиты в универсальную платформу сетевой защиты уровня L3/L4/L7 для любых сервисов. Слоёв стало четыре: (1) XDP/eBPF в ядре — только протоколо-независимая логика (универсальный TCP state machine, SYN throttle, CIDR-списки, UDP policy), глубокий парсинг вынесен в подключаемые BPF hook-модули; (2) универсальный PoW-challenge (SHA256 hashcash) поверх любого TCP-протокола, выключен по умолчанию; (3) userspace-ядро на Rust — L7-анализ, rate limit, HMAC, death-code паттерны; (4) компайл-тайм протокол-плагины (feature crates), первый — minecraft, далее http и grpc. Traffic Intel (EWMA, профилирование, репутация) работает поперёк всех слоёв. Java-слои (velocity/paper) и React dashboard удалены — потребители интегрируются через Manager API (axum + Redis). Документация строится вокруг двуязычной базы знаний docs/kb. Полные детали миграции и ссылки на git-историю — в Migration notes выше.