Files
shater/docs-shater/ROADMAP.md
T

7.3 KiB
Raw Permalink Blame History

Roadmap

Phased plan for shater v0.2. Each phase ends with something verifiable on the test VM (see CONTEXT.md for the testbed). Port proven logic from the v0.1 branch; build new logic in the shater/, panel/, openwrt/ overlay.

Phase 0 — Repo reset & context ✅

  • Preserve the working xray-based project on branch v0.1.
  • Clean main to a docs-first scaffold; write CONTEXT / DECISIONS / ARCHITECTURE / ROADMAP / FEATURES / README. License → GPL-3.0. Keep the feed key.

Phase 1 — Fork & embedding prototype ✅ DONE (2026-07-14)

  • ✅ main is the fork: merged Leadaxe/sing-box-lx v1.14.0-lx.3 (--allow-unrelated-histories), overlay dirs kept, submodules/wireguard-go pinned 1adc4c71 (AWG 2.0 engine).
  • ✅ Embed proven: shater/cmd/shater-proto drives the engine via box.New (not a subprocess); real socks5 request flows through it on the VM. tproxy + a real protocol outbound constructed in Go and validated via box.New.
  • ✅ AmneziaWG 2.0 E2E: our client did a real handshake against live Cloudflare WARP (config lifted from the router's warp2); cdn-cgi/trace flipped warp=off→warp=on through the tunnel. WARP/AWG params + the i1 CPS packet map 1:1 to sing-box's endpoints[] (wireguard type) — no transform needed.
  • ✅ Size: raw static ~40–43 MB → UPX-lzma ~9–11 MB (well under ≤18 MB).
  • ✅ Cross-compiled x86_64 + aarch64 (arm64); runs on the musl OpenWrt VM using the router tag set (see DECISIONS.md D9 — drop with_naive_outbound,with_purego).
  • Gate: PASSED → proceed to Phase 2.

Phase 2 — Control-plane port ✅ DONE (E2E gate PASSED 2026-07-15)

  • Port from v0.1 (adapt to sing-box types): UCI model, config generator (→ sing-box config, not xray JSON), share-link handling (reuse sing-box's parser where possible), atomic apply/validate/rollback, nft inet shater + policy routing, idempotent reconcile under flock, kill-switch, management-bypass, live-flag, hotplug/boot persistence, subscription fetch (+ HAPP), rulesets/lists.
  • procd init + uci-defaults in openwrt/ (from v0.1 shater-core).
  • DPI-bypass, native presets (D13): egress gains an optional dpi preset; off|fragment|record|spoof map to the already-compiled route-action fields (tls_fragment/tls_record_fragment/tls_spoof) on a direct outbound. Lets a ruleset go direct + fragmented (DPI-blocked-but-not-IP-blocked domains) with no tunnel, no new binary. ✅ Wired in generate: a direct egress with dpi emits an egress-<name> direct outbound and buildRoute stamps the matching route-action flag on every rule routed to it (fragment/record/spoof; fragment↔record mutual exclusion enforced). spoof injects a decoy ClientHello and validates on the router build.
  • Gate: a real LAN client on the VM is proxied end-to-end through a sing-box outbound, DNS anti-leak holds, kill-switch is honest. ✅ PASSED on the OpenWrt VM (netns client → tproxy → engine → live Cloudflare WARP/AmneziaWG): client egress 104.28.212.73 warp=on (direct = warp=off); DNS anti-leak holds with dnsmasq stopped (engine hijack-dns answers, no WAN :53 leak); kill-switch honest (SIGKILL engine → client blocked, no WAN leak). Three bugs found+fixed by the gate: fail-closed forward drop (4f618140), engine apply-swap close-first fallback (9b6b9406), DNS hijack-dns per D14 (86194ce6).

Phase 2b — DPI-bypass egress = ByeDPI (D13)

  • The one external desync tool is ByeDPI (ciadpi) — chosen over zapret because it is a SOCKS egress (fits shater's "routing picks the egress" model with zero packet-plane conflict); zapret is explicitly rejected (see D13).
  • Add egress dpi value byedpi: a supervised local ciadpi SOCKS5 instance + a socks outbound pointed at it. New openwrt/ procd package + musl-static cross-build of ciadpi (~100 KB); model reserves the egress kind, generate wires the socks outbound.
  • QUIC gap closed by routing (drop udp/443 for desync-domains → TCP+TLS fallback), not by adopting a packet plane.
  • The byedpi package (openwrt/byedpi/, SEPARATE & optional) provides the ciadpi process behind a type='byedpi' egress: it cross-compiles ciadpi via the SDK toolchain and ships a procd init that supervises one ciadpi SOCKS5 desync instance per enabled config instance in /etc/config/byedpi (127.0.0.1:<port>). Install it only when you want a byedpi egress; a type='byedpi' egress with no matching ciadpi listener simply has nothing to dial. shater-core does NOT depend on it (opt-in).
  • Gate: a DPI-blocked domain (that plain fragment can't crack) loads via the byedpi egress on the VM, direct (no tunnel), kill-switch still honest.

Phase 3 — Admin panel MVP + thin LuCI launcher ✅ DONE (2026-07-15)

  • panel/: embedded web server on its own port + session store; token-mint ubus method in the thin LuCI app; token-handoff auth (see ARCHITECTURE §2).
  • Thin LuCI app: mini dashboard (status + throughput) + "Open panel" button; reuse the v0.1 "instrument panel" design language.
  • Panel SPA MVP: status/overview, node/subscription management, basic routing rules, apply/rollback. Frontend build embedded into the binary.
  • Gate: log into the panel from LuCI via token, configure a proxy, apply.

Phase 4 — DNS filter & blocklists ✅ DONE (gate PASSED 2026-07-15)

  • ✅ Foundation (D15): model blocklist/allowlist + generate rule-sets + reject/allow DNS rules (box.New-validated); panel DNS/Blocklists page; seeds StevenBlack/OISD/AdGuard; cache_file + blocklist update verb; blocks return NXDOMAIN/0.0.0.0. Gate PASSED on VM (blocked→NXDOMAIN, normal resolves, allowlist overrides, geosite megalist RSS ~39MB).
  • In-process DNS filter hooking sing-box DNS: blocklists with flexible sources (inline/file/url/geosite), allowlist overrides, NXDOMAIN/0.0.0.0.
  • Efficient matcher for megalists (compiled/cached, dedup, bloom prefilter); seed well-known lists (StevenBlack/OISD/AdGuard).
  • Gate: ad/tracker domains blocked network-wide; big list loads fast; RAM sane.

Phase 5 — Statistics (per-domain / client / device)

  • Stats aggregator consuming the engine's DNS/routing/stats observability + nft counters: top domains, allowed vs blocked, per-device breakdown, timelines, per-node/per-rule traffic, live query log with one-click block.
  • Panel dashboards for all of the above.
  • Gate: live, accurate per-domain and per-device stats in the panel.

Phase 6 — Per-device control & parental ✅ DONE (gate PASSED)

  • Devices page: discover (dhcp.leases + ip neigh), name, live status; per-device toggles (proxy on/off, blocklists, exit country), per-device domain block/allow.
  • Gate: block a domain for one device only; route one device via a chosen exit.

Phase 7 — Schedules & alerts ✅ DONE

  • Time-based rules (bedtime/school hours) via the ported scheduler; Telegram/ webhook alerts (sub expiry, node down, kill-switch trip, new device).

Phase 8 — Ship it ✅ DONE

  • Adapt CI to build/sign the single forked binary for both arches; publish the signed opkg feed (reuse key 5ac4b177689cb8e0); install/upgrade docs.
  • Set an upstream-rebase cadence (merge new sing-box-lx tags, run the smoke suite).

Cross-cutting (every phase)

Tests + live VM verification before commit; keep the fork overlay conflict-free; document as we go.