Files
therealaleph cb3732f920 feat: v1.8.0 — DPI evasion, active-probing defense, full-mode usage counters
Five user-visible changes shipping together. Each is independently
useful + bounded; bundled because they're all "small architectural
hardening" that benefits from one release announcement.

1. Random payload padding (#313, #365 §1)

   Every outbound Apps Script JSON request now carries a `_pad` field
   of uniform-random length 0..1024 bytes (base64). Defeats DPI that
   fingerprints on the tight length distribution of mhrv-rs's previous
   per-mode-bound packet sizes. ~25% bandwidth on a typical 2 KB batch,
   negligible against Apps Script's per-call latency floor. Backward-
   compatible — old `Code.gs` deployments ignore the unknown field.
   Applied at all three payload-build sites: single relay, single
   tunnel op, batch tunnel.

2. Active-probing decoy: GAS bad-auth → 200 HTML (#365 §3)

   `Code.gs` and `CodeFull.gs` now return a benign Apps-Script-style
   placeholder HTML page on bad/missing AUTH_KEY instead of the JSON
   `{"e":"unauthorized"}`. To an active scanner the deployment looks
   like one of the millions of forgotten public Apps Script projects
   rather than an obvious API endpoint. New `DIAGNOSTIC_MODE` const
   restores JSON errors during setup; default false (production-strong).

3. Active-probing decoy: tunnel-node bad-auth → 404 nginx (#365 §3)

   `tunnel-node` returns an HTTP 404 with an nginx-style HTML body on
   bad auth instead of `{"e":"unauthorized"}`. Active scanners cataloging
   the host see "static web server, nothing tunnel-shaped here." New
   `MHRV_DIAGNOSTIC=1` env var restores verbose JSON during setup.

4. Fix: Full-mode usage counter stuck at zero (#230, #362)

   `today_calls` / `today_bytes` were only being incremented on the
   apps_script-mode relay path. Full-mode batches go through
   `tunnel_client::fire_batch` which never wired into the counter.
   Now `fire_batch` calls `record_today(response_bytes)` after each
   successful batch — bytes estimated from the `d` (TCP payload) and
   `pkts` (UDP datagrams) sizes in the BatchTunnelResponse. Full-mode
   users now see real usage numbers.

5. Fix: quota reset countdown was UTC, should be PT (#230, #362)

   Apps Script's UrlFetchApp daily quota resets at midnight Pacific
   Time, not UTC. We were displaying the countdown to UTC midnight,
   off by 7-8h depending on DST. New `current_pt_day_key()` and
   `seconds_until_pacific_midnight()` helpers with hand-rolled US DST
   detection (2nd Sunday March → 1st Sunday November = PDT, else PST)
   so we don't pull `chrono-tz` and a ~3 MB IANA tzdb just for one
   helper. UI label "UTC day" → "PT day". Tests pin DST window
   boundaries against March/November of 2024, 2026, 2027 to catch
   regressions in the day-of-week math.

Tested:
- cargo test --lib: 154 passed (was 152, +2 for DST window + day-of-week)
- cargo build --release: clean
- cargo build --release --bin mhrv-rs-ui --features ui: clean (macOS arm64)
- tunnel-node cargo test: 30 passed
- Android: ./gradlew assembleDebug succeeds; APK installs + launches
  on mhrv_test emulator (arm64-v8a), no UnsatisfiedLink, no crash

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 01:39:47 +03:00

7.4 KiB
Raw Permalink Blame History

• Padding random برای پایلود Apps Script (#313، #365 Section 1): هر request به Apps Script حالا یک فیلد _pad با طول uniform-random بین ۰-۱۰۲۴ بایت اضافه می‌کنه — به‌صورت base64 encoded. بدون این، طول request body در هر mode تقریباً ثابت می‌مونه + DPI ایران می‌تونه بر اساس distribution طول fingerprint بزنه. حالا packet sizes uniformly distributed هستن + length-clustering match نمی‌کنه. تأثیر bandwidth: متوسط ۵۱۲ بایت اضافه به batch ~۲KB = +۲۵٪، negligible در برابر floor latency Apps Script. backward-compatible: Code.gs قدیم هم کار می‌کنه (unknown JSON fields ignore می‌شن). • Defense active probing: decoy 200 HTML در Code.gs / CodeFull.gs روی AUTH_KEY بد (#365 Section 3): قبلاً request بدون auth {"e":"unauthorized"} JSON برمی‌گردوند — fingerprint مشخص "این یه API endpoint هست". حالا یه HTML benign placeholder برمی‌گردونه که شبیه یه Apps Script web app forgotten-but-public هست. scanner active که با AUTH_KEY ساختگی POST می‌کنه categorize می‌کنه به‌عنوان "non-tunnel، nothing interesting". flag DIAGNOSTIC_MODE برای setup که response قدیمی JSON رو برمی‌گردونه — default false (production-strong) • Defense active probing: decoy 404 nginx در tunnel-node روی auth بد: tunnel-node قبلاً {"e":"unauthorized"} JSON برمی‌گردوند. حالا response 404 با body HTML شبیه nginx default error می‌فرسته (active scanners "static web server هست، tunnel نیست" تشخیص می‌دن). env var MHRV_DIAGNOSTIC=1 برای setup behavior قدیمی رو فعال می‌کنه • رفع باگ "Usage today (estimated) در Full mode همیشه ۰" (#230، #362): counter today_calls و today_bytes فقط روی apps_script-mode relay path در domain_fronter::relay() افزایش می‌یافت. Full mode از tunnel_client::fire_batch می‌گذره که کانتر رو زد. حالا fire_batch بعد از batch موفق record_today(response_bytes) رو صدا می‌زنه — bytes از sum طول d و pkts در BatchTunnelResponse تخمین زده می‌شه. Full mode users حالا "Usage today" واقعی می‌بینن • رفع باگ "quota reset countdown با time UTC به‌جای PT نشون داده می‌شه" (#230، #362): Apps Script's UrlFetchApp quota در 00:00 Pacific Time ریست می‌شه (PST/PDT با DST)، نه UTC. ما UTC midnight رو نشون می‌دادیم — ۷-۸ ساعت off. fix: helpers جدید current_pt_day_key() + seconds_until_pacific_midnight() با hand-rolled DST detection (بدون اضافه کردن chrono-tz / 3MB tzdb). UI label "UTC day" → "PT day" تغییر کرد. ۲ test جدید برای DST window boundaries (مارس ۲۰۲۴/۲۰۲۶/۲۰۲۷، نوامبر ۲۰۲۴/۲۰۲۶) + Sakamoto's day-of-week

• Random payload padding for Apps Script requests (#313, #365 Section 1): every outbound request to Apps Script now carries a _pad field of uniform-random length 01024 bytes (base64 encoded). Before this, request body sizes within each mode were tightly clustered, giving ISP DPI a clean length-distribution fingerprint to match against. Now packet sizes are spread uniformly across the range so length-clustering DPI heuristics can't match. Bandwidth cost: ~512 bytes added to a typical 2 KB tunnel batch = +25%, negligible against Apps Script's per-call latency floor. Backward-compatible: old Code.gs deployments ignore the unknown field. Applied at all three payload-build sites: single relay, single tunnel op, batch tunnel. • Active-probing defense: decoy 200 HTML on bad AUTH_KEY in Code.gs and CodeFull.gs (#365 Section 3): previously a request with a missing/wrong AUTH_KEY got {"e":"unauthorized"} as a JSON body — a clear "this is some kind of API endpoint" signal that active scanners can fingerprint. Now bad-auth requests get a benign HTML placeholder page that looks like a forgotten-but-public Apps Script web app, indistinguishable from the millions of stale Apps Script projects on Google's infrastructure. New DIAGNOSTIC_MODE const (default false) restores the old JSON error response for setup/debugging — flip to true while configuring a misconfigured client, then back to false before sharing the deployment widely. • Active-probing defense: decoy 404 nginx-style HTML on bad auth in tunnel-node (#365 Section 3): previously a bad-auth request got {"e":"unauthorized"}. Now it gets an HTTP 404 with an nginx-style error page body, looking like a vanilla static web server. Active scanners that POST malformed payloads to /tunnel to discover proxy endpoints categorize this host as "boring" and move on. New MHRV_DIAGNOSTIC=1 env var restores the verbose JSON error during setup; default is the production decoy. • Fix "Usage today (estimated) is always 0 in Full mode" (#230, #362): the daily-usage counters (today_calls / today_bytes) were incremented only on the apps_script-mode relay path inside domain_fronter::relay(). Full-mode traffic goes through tunnel_client::fire_batch which never wired the counter. Now fire_batch calls record_today(response_bytes) after each successful batch — bytes are estimated from the sum of per-session d (TCP payload) and pkts (UDP datagrams) lengths in the BatchTunnelResponse, which is a stable proxy for "how much did this batch move." Full mode users now see real usage numbers instead of stuck-at-zero. • Fix "quota reset countdown shown in UTC instead of Pacific Time" (#230, #362): Apps Script's UrlFetchApp quota actually resets at midnight Pacific Time (PST/PDT — observes DST), not midnight UTC. We were displaying the countdown to UTC midnight, which is 78 hours off depending on DST. Fix: new current_pt_day_key() + seconds_until_pacific_midnight() helpers using a hand-rolled US DST detector (2nd Sunday of March → 1st Sunday of November = PDT, otherwise PST) so we don't pull chrono-tz and a ~3 MB IANA tzdb just for one helper. UI label updated from "UTC day" to "PT day". Two new tests pin down the DST window boundaries (March 2024 / 2026 / 2027, November 2024 / 2026) and Sakamoto's day-of-week formula.