Files
shater/docs-shater/ARCHITECTURE.md
T
omar d41a685d9b chore: relocate shater meta-docs to docs-shater/ (avoid upstream docs/ collision)
Upstream sing-box-lx already ships a docs/ mkdocs site; keep our project docs
separate and unambiguous in docs-shater/ (parallels upstream's docs-lx/).
Updated all references in README.md, CLAUDE.md, CONTEXT.md, ARCHITECTURE.md.
2026-07-14 14:19:34 +03:00

4.3 KiB
Raw Permalink Blame History

Architecture (v0.2)

One Go binary — a fork of sing-box-lx with our product embedded — runs the proxy engine, the control plane, the DNS filter, and the admin-panel web server in a single process. OpenWrt integration (a thin LuCI launcher + procd/system glue) wraps it. Config is UCI desired-state; the daemon renders and applies it; telemetry flows back to the panel.

Diagrams render on Gitea/GitHub.

1. Components & repository layout

flowchart TB
  subgraph BIN["shaterd — one binary (fork of sing-box-lx)"]
    ENG["sing-box engine (upstream tree)\nprotocols · Reality · AmneziaWG 2.0 · DNS · routing · stats"]
    CTRL["shater/ control-plane\nUCI model · config gen · apply/rollback · nft/routing · reconcile"]
    FILT["shater/ DNS filter + blocklists + per-device policy"]
    STAT["shater/ stats aggregator (per-domain/client/device)"]
    PANEL["panel/ admin web server + embedded SPA (own port, token auth)"]
  end
  subgraph WRT["OpenWrt glue (openwrt/)"]
    LUCI["thin LuCI app — mini dashboard + Open-panel button"]
    PROCD["procd init · hotplug · uci-defaults · fw4/routing"]
  end
  LUCI -->|"ubus: mint token"| PANEL
  PROCD --> BIN
  CTRL --> ENG
  FILT --> ENG
  ENG --> STAT
  STAT --> PANEL

Overlay dirs (added on top of the upstream sing-box-lx tree, conflict-free): shater/ (Go: control-plane, DNS filter, stats, engine host), panel/ (admin SPA + its Go server), openwrt/ (LuCI thin app, procd/shater-core, Makefiles, feed/CI), docs-shater/.

2. Auth handoff — LuCI → admin panel

sequenceDiagram
  participant U as Browser (LuCI, authed)
  participant L as LuCI (thin app)
  participant D as shaterd (panel server, own port)
  U->>L: click "Open panel"
  L->>D: ubus mint_token (LuCI session ACL-checked)
  D-->>L: short-lived one-time token
  L-->>U: redirect https://router:PORT/?t=TOKEN
  U->>D: GET /?t=TOKEN
  D-->>U: validate + set session cookie, drop token
  U->>D: SPA ⇄ panel API (session)

The panel never runs its own login; it trusts a token that only an authenticated, ACL-permitted LuCI session could have minted. Tokens are single-use and short-TTL.

3. Data plane — traffic path

flowchart LR
  C["LAN client"] -->|"nft tproxy, mark → tproxy port"| IN["sing-box tproxy inbound (sniff SNI/Host/QUIC)"]
  IN --> R{"route: rule match — src / dst / list / geo / client"}
  R -->|"proxied"| OUT["outbound / selector (balancer, chain)"]
  R -->|"direct"| DIR["direct (flow-offload on)"]
  R -->|"blocked"| BLK["block"]
  OUT --> NET["exit — VLESS/Reality/AmneziaWG2/Hysteria2/…"]

Reliability (ported from v0.1): own nft table inet shater + own marks/tables (never touch fw4); atomic validate→stage→swap; commit-confirm rollback; idempotent reconcile under flock; management-bypass always; fail-closed kill-switch (dead group → block, not a silent direct leak).

4. DNS + filtering + stats

flowchart LR
  C["client :53"] -->|"hijack"| DNS["sing-box DNS (in-process)"]
  DNS --> FILT{"shater filter: blocklists + allowlist + per-device policy"}
  FILT -->|"blocked"| NX["NXDOMAIN / 0.0.0.0"]
  FILT -->|"allowed"| RES["resolvers (DoH/DoT/plain/FakeIP) + nftset for routing"]
  DNS -->|"query events (engine observability)"| AGG["shater stats aggregator"]
  AGG --> PANEL["panel: top domains · per-device · allowed/blocked · timeline"]

Because the engine's DNS runs in our process, every query (domain, client, verdict, latency) is available to the stats aggregator without log-scraping — this is the payoff of embedding. Blocklist matching uses an efficient compiled matcher, not dnsmasq megalists (see DECISIONS.md D5). Per-device blocking = engine route/DNS rule keyed by client, or nftset(device) × nftset(blocked-domain) → drop.

5. Config & apply flow

stateDiagram-v2
  [*] --> Edit
  Edit --> Render: UCI → sing-box config (our generator, engine types)
  Render --> Validate: engine config check + nft -c
  Validate --> KeepOld: fail
  Validate --> Apply: ok (atomic swap: engine reload + nft/route reconcile)
  Apply --> ConfirmWindow
  ConfirmWindow --> Committed: confirmed
  ConfirmWindow --> Rollback: timeout
  Rollback --> LastGood

6. Roadmap tiers

See ROADMAP.md for the phased plan and FEATURES.md for the full feature list.