Commit Graph

15 Commits

Author SHA1 Message Date
therealaleph eed64caf87 v0.3.1: IP-literal destinations -> plain TCP passthrough (always)
User reported log spam on Windows with many 'relay failed: خطای SSL'
errors for IP-literal targets like 172.105.237.214:443. Root cause:
xray/VLESS, torrent, SSH, and other app-level clients use raw IPs in
CONNECT/SOCKS5 targets. Our previous logic would MITM these, see
'POST /' inside the xhttp wrapping, forward to Apps Script, which
would then fail SSL-verifying the app's self-signed backend.

New heuristic: if the CONNECT target is an IP literal, skip MITM
entirely and do plain TCP passthrough. Reasoning: browsers never
use raw IPs in CONNECT -- they always have a domain. Any client
using an IP literal is using a custom protocol that we have no
business MITMing.

Effect: xray/VLESS tunnels now work through mhrv-rs SOCKS5 (the
app's own TLS wrap passes through untouched). Browser HTTPS still
MITM'd + relayed as before (domain CONNECTs).

Also downgraded 'relay failed' logs from error to warn so they don't
spam the ERROR channel on misrouted traffic.
v0.3.1
2026-04-21 20:58:48 +03:00
therealaleph a2d0cece46 gitignore .DS_Store 2026-04-21 20:29:34 +03:00
therealaleph f5397bef43 v0.3.0: SOCKS5 listener + smart TLS/HTTP/plain-TCP dispatch
Ports the SOCKS5 + fallback-chain design from @masterking32's
MasterHTTP-WithSOCKS branch so xray / Telegram / app-level TCP
clients work through this proxy.

Changes:
- New SOCKS5 listener on listen_port+1 (configurable via socks5_port)
  - RFC 1928 CONNECT handshake (v5, no-auth, ATYP IPv4/domain/IPv6)
  - Shared smart dispatch with the HTTP-CONNECT path
- Unified dispatch_tunnel() used by both CONNECT entry points:
  1. If host matches SNI-rewrite suffix or hosts override: go direct
     to google_ip via the MITM+TLS tunnel (fast path for google.com,
     youtube, etc.)
  2. Peek the first byte (300ms timeout for server-first protocols):
     - 0x16: TLS client hello -> MITM + relay via Apps Script (scheme=https)
     - HTTP method signature: HTTP relay via Apps Script (scheme=http)
     - Anything else or timeout: plain TCP passthrough to the target
- handle_mitm_request() now takes a scheme arg (http/https) so the
  same code path handles both MITM'd HTTPS and port-80 plain HTTP
- New plain_tcp_passthrough helper: bidirectional TCP bridge used as
  the final fallback (covers MTProto / raw TCP / server-first protos)

Config:
- Added optional socks5_port field; defaults to listen_port+1

README:
- Added browser vs xray/Telegram instructions under 'Step 6'

Live-tested: HTTP proxy, HTTP proxy -> HTTPS, SOCKS5 -> HTTP,
SOCKS5 -> HTTPS, Google search via SNI-tunnel (now returns full
JS page) all pass.
v0.3.0
2026-04-21 20:29:24 +03:00
therealaleph 343def4c88 v0.2.2: route google.com via SNI-tunnel to avoid bot UA
Context: user reported Google search showing no-JS fallback page
('JS is off apparently'). Root cause is Apps Script's fixed
'Google-Apps-Script; beanserver' User-Agent that UrlFetchApp.fetch
does not let you override. Google detects the bot UA and serves
the degraded HTML.

Fix: add google.com to SNI_REWRITE_SUFFIXES so google.com requests
bypass Apps Script entirely and go direct to Google's edge via the
MITM+TLS tunnel. Real browser UA is sent; full JS version is served.

Also documented this and other inherent limitations (WebSockets,
2FA 'unknown device', video chunk slowness, brotli stripping) in
the README under 'Known limitations' in English + Persian so users
aren't surprised. These are platform limits of Apps Script, not
bugs -- same issues exist in the original Python project.
v0.2.2
2026-04-21 19:58:06 +03:00
therealaleph 33bba7a0f7 v0.2.1: fix PRI/HTTP2-preface leak + shrink SNI-rewrite list
Two bug fixes surfaced in user testing:

1. Invalid HTTP methods forwarded to Apps Script
   - Browser/xray sent HTTP/2 PRI preface through our MITM despite ALPN
     being set to http/1.1 only (some clients ignore ALPN).
   - Our parser accepted 'PRI' as a method and forwarded to Apps Script,
     which rejected it: 'Exception: parameter provided with invalid value: method'.
   - Fix: validate method against the standard list (GET/POST/PUT/DELETE/
     HEAD/OPTIONS/PATCH/TRACE/CONNECT) at parse time. Non-matching requests
     close the connection cleanly instead of forwarding garbage.

2. YouTube video playback broken by over-broad SNI-rewrite list
   - Previous list included googlevideo.com, ytimg.com, doubleclick.net,
     etc. -- but these are served from SEPARATE CDN pools, NOT from
     Google's 216.239.38.120 frontend. Rewriting sent traffic to the
     wrong backend, which Google dropped.
   - Shrunk to a conservative list that's actually served from the
     main Google frontend: youtube.com, youtu.be, youtube-nocookie.com,
     fonts.googleapis.com. Everything else falls through to MITM+relay
     (slower but actually works).
   - YouTube video chunks now route through Apps Script which is slow
     and quota-limited. This is a known limitation inherent to the
     approach; same issue exists in the original Python version.
v0.2.1
2026-04-21 19:34:02 +03:00
therealaleph ea5c6ca9a4 bump to v0.2.0 + update README
Features added since v0.1.0 (all live-tested against real Apps Script):
- Response cache (FIFO+TTL, Cache-Control aware, 50MB cap)
- Request coalescing for concurrent identical GETs
- Auto-blacklist failing scripts on 429/quota (10m cooldown)
- SNI-rewrite MITM tunnels for YouTube/googlevideo/doubleclick/etc.
- Gzip response decoding (was breaking all requests in v0.1.0)
- Firefox NSS cert install (best effort via certutil)
- Periodic stats log (60s)
- 'mhrv-rs test' subcommand (end-to-end relay probe)
- 'mhrv-rs scan-ips' subcommand (28 Google IPs, sorted by latency)
- Script IDs masked in logs

Intentionally skipped with rationale (documented in README):
- HTTP/2 multiplexing: coalesce+pool already parallelizes enough
- Request batching: marginal gain over current async pool
- Range-based parallel download: video bypasses via SNI-rewrite

25 tests pass. 2.5 MB stripped release binary.
v0.2.0
2026-04-21 18:37:30 +03:00
therealaleph 3f0e266508 add 'test' and 'scan-ips' subcommands
test: one-shot end-to-end probe. Issues a GET to api.ipify.org through
the configured relay and prints status + body + timing. Clear pass/fail
with specific diagnostics for 502/504 (auth_key mismatch, quota, etc).
Verified live: 3.8s round-trip returning the caller's real IP.

scan-ips: parallel TLS probe of 28 known Google frontend IPs with
SNI=front_domain. Reports which are reachable and sorts by latency.
Users pick the fastest and paste into google_ip. Verified live:
7/28 reachable (the others were Windscribe'd out), top 3 ranked.

Both subcommands share the existing config.json and require no extra
flags. Default 'mhrv-rs' with no subcommand runs the proxy as before.
2026-04-21 18:33:52 +03:00
therealaleph c17afddcb9 periodic stats log every 60s at info level
Tracks relay_calls, failures, bytes, coalesced requests, cache hit rate,
and active scripts (total minus blacklisted). Logs only if there's been
traffic since the last tick. Visible when running with RUST_LOG=info or
log_level=info in config.
2026-04-21 18:30:43 +03:00
therealaleph b3e0de5f18 add Firefox NSS cert install (best effort)
After the OS trust store install, also try to add the MITM CA to all
discovered Firefox profiles via NSS certutil. Silently no-ops if:
- NSS certutil is not installed (macOS ships a different certutil; linux
  needs libnss3-tools; Windows needs NSS binaries)
- No Firefox profiles exist
- Firefox is currently running (lock on cert.db)

Scans profiles in:
- macOS:   ~/Library/Application Support/Firefox/Profiles
- Linux:   ~/.mozilla/firefox and ~/snap/firefox/common/.mozilla/firefox
- Windows: %APPDATA%\Mozilla\Firefox\Profiles

Existing CA-install error path is unchanged; this is purely additive.
2026-04-21 18:29:23 +03:00
therealaleph f3e0d929fd add SNI-rewrite MITM tunnels for YouTube/googlevideo + fix gzip decode
SNI-rewrite tunnels (src/proxy_server.rs):
- CONNECT to youtube.com / googlevideo.com / doubleclick / etc. now bypasses
  the Apps Script relay entirely and goes direct to the Google edge IP
  with SNI=front_domain.
- Accepts browser TLS with our MITM cert, opens outbound TLS to
  config.google_ip with SNI=config.front_domain, bridges decrypted bytes.
- Matches Python's _do_sni_rewrite_tunnel behavior. Faster than relay for
  large streams (video).
- Also respects config.hosts override map (custom IP per suffix).

gzip decode fix (src/domain_fronter.rs):
- Apps Script outer response is gzipped. Previous stub always failed,
  causing 'non-utf8 json' errors. Swapped in flate2::GzDecoder.
- Verified end-to-end: HTTP and HTTPS requests through apps_script
  relay succeed and return real Google IPs.
2026-04-21 18:27:49 +03:00
therealaleph d62b31989c auto-blacklist failing scripts in round-robin rotation
When a script returns 429, 403, or a quota/rate-limit error body,
drop it from the active rotation for 10 minutes. next_script_id
skips blacklisted IDs; if all are blacklisted, picks the one
coming off cooldown soonest.

Script IDs are masked in logs (prefix...suffix) to avoid leaking
the deployment ID even at info level.
2026-04-21 18:21:58 +03:00
therealaleph 534066c4a9 coalesce concurrent identical GETs
First concurrent caller for a cache key does the relay; subsequent
callers subscribe to a broadcast channel and receive the same response.
Only applies to cacheable (GET/HEAD) requests without body.
2026-04-21 18:19:44 +03:00
therealaleph 52d00312ab add response cache with TTL + Cache-Control parsing
- New cache.rs: FIFO-eviction cache with max_bytes cap
- Cacheable: GET/HEAD only, no-store/no-cache/private/Set-Cookie reject
- TTL from Cache-Control: max-age=, or heuristics by extension (css/js/fonts/images -> 1h)
- Hook in DomainFronter::relay: check cache before network, store after 2xx
- 10 new unit tests (23 total)
2026-04-21 18:18:21 +03:00
therealaleph 00e0d411fc fix Code.gs link: it's on the python_testing branch 2026-04-21 18:08:47 +03:00
therealaleph 2dd8be72ca initial release: Rust port of MasterHttpRelayVPN apps_script mode
Faithful port of @masterking32's MasterHttpRelayVPN. All credit for
the original idea, protocol, and Python implementation goes to him.

Implemented:
- Local HTTP proxy (CONNECT + plain HTTP)
- MITM with on-the-fly per-domain cert generation via rcgen
- CA auto-install for macOS / Linux / Windows
- Apps Script JSON relay, protocol-compatible with Code.gs
- TLS client with SNI spoofing (connect to Google IP, SNI=www.google.com,
  inner HTTP Host=script.google.com)
- Connection pooling (45s TTL, max 20 idle)
- Multi-script round-robin for higher quota
- Header filtering (strips connection-specific + brotli)
- Config-driven, JSON schema matches Python version

Deferred (TODOs in code):
- HTTP/2 multiplexing
- Request batching / coalescing / response cache
- Range-based parallel download
- SNI-rewrite tunnels for YouTube/googlevideo
- Firefox NSS cert install
- domain_fronting / google_fronting / custom_domain modes
  (mostly broken post-Cloudflare 2024, not a priority)

13 unit tests pass, 2.4MB stripped release binary.
v0.1.0
2026-04-21 18:03:03 +03:00