From 343def4c884a0187aa0d5736bf1a827b448bd150 Mon Sep 17 00:00:00 2001 From: therealaleph Date: Tue, 21 Apr 2026 19:58:06 +0300 Subject: [PATCH] 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. --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 32 +++++++++++++++++++++++++++++++- src/proxy_server.rs | 11 +++++++---- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e240c0..885ab08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,7 +365,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mhrv-rs" -version = "0.2.1" +version = "0.2.2" dependencies = [ "base64", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 6757319..536cd5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mhrv-rs" -version = "0.2.1" +version = "0.2.2" edition = "2021" description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting" license = "MIT" diff --git a/README.md b/README.md index 09a9aaa..1441971 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ This port focuses on the **`apps_script` mode** which is the only one that relia - [x] Auto-blacklist failing scripts on 429 / quota errors (10-minute cooldown) - [x] Response cache (50 MB, FIFO + TTL, parses `Cache-Control: max-age`, heuristics for static assets) - [x] Request coalescing: concurrent identical GETs share one upstream fetch -- [x] SNI-rewrite tunnels for YouTube / googlevideo / doubleclick / etc. — bypass the relay entirely and go direct to Google's edge with SNI=`front_domain` +- [x] SNI-rewrite tunnels (direct-to-Google-edge bypassing the relay) for `google.com`, `youtube.com`, `youtu.be`, `youtube-nocookie.com`, `fonts.googleapis.com`. Extra domains can be added via the `hosts` map in config — see "Known limitations" below. - [x] Automatic redirect handling on the relay (`/exec` → `googleusercontent.com`) - [x] Header filtering (strip connection-specific + brotli) - [x] `mhrv-rs test` subcommand — one-shot end-to-end relay probe @@ -136,6 +136,22 @@ Intentionally NOT implemented (rationale included so future contributors don't s - [ ] **Range-based parallel download** — edge cases (non-Range servers, chunked mid-stream, content-encoding) are real; YouTube-style video already bypasses Apps Script via SNI-rewrite tunnel - [ ] **Other modes** (`domain_fronting`, `google_fronting`, `custom_domain`) — Cloudflare killed generic domain fronting in 2024; Cloud Run needs paid plan; skip unless specifically requested +## Known limitations + +These are inherent to the Apps Script + domain-fronting approach, not bugs in this client. Same issues exist in the original Python version. + +- **User-Agent is fixed to `Google-Apps-Script`** for any request going through the relay. Google's `UrlFetchApp.fetch()` does not allow overriding it. Consequence: sites that detect bots (e.g., `google.com` search, some CAPTCHAs) will serve degraded / no-JavaScript fallback pages to relayed requests. Workaround: add the affected domain to the `hosts` map in `config.json` so it's routed via the SNI-rewrite tunnel (real browser UA) instead of the relay. `google.com`, `youtube.com`, `fonts.googleapis.com` are already done by default. + +- **Video playback is slow and quota-limited** for anything that goes through the relay. YouTube HTML loads via the tunnel (fast) but chunks from `googlevideo.com` go through Apps Script. Each Apps Script account has a ~2 million `UrlFetchApp` calls/day consumer quota and a 50 MB body limit per fetch. Fine for text browsing, painful for 1080p video. Use multiple `script_id`s in rotation for more headroom, or use a real VPN for video. + +- **Brotli compression is stripped** from forwarded `Accept-Encoding` headers. Apps Script can decompress gzip but not brotli; forwarding `br` would produce garbled responses. Gzip still works. Minor size overhead for responses that would've been brotli. + +- **WebSockets don't work** through Apps Script (the relay does single request/response JSON). Sites that upgrade to WS fail. This covers `chat.openai.com` streaming, Discord voice, etc. + +- **HTTPS sites your browser has pinned** (HSTS preloaded list, extended validation) will reject the MITM cert. Most sites work fine because we install our CA as trusted; a few hard-pinned ones won't. + +- **Google/YouTube 2FA / sensitive logins** may see "unrecognized device" warnings because the request originates from Google's Apps Script infrastructure IP, not your real IP. Log in via tunnel first (`google.com` is in the rewrite list) to avoid this. + ## License MIT. See [LICENSE](LICENSE). @@ -203,6 +219,20 @@ mhrv-rs.exe --install-cert Proxy مرورگر را روی `127.0.0.1:8085` بگذارید (هم HTTP و هم HTTPS). +### محدودیت‌های شناخته‌شده + +این‌ها محدودیت‌های ذاتی روش Apps Script هستند، نه باگ در این کلاینت. نسخه اصلی Python هم همین مشکلات را دارد. + +- **User-Agent همیشه `Google-Apps-Script` است** برای هر درخواستی که از رله رد می‌شود. `UrlFetchApp.fetch()` گوگل اجازه تغییر این را نمی‌دهد. نتیجه: سایت‌هایی که ربات را تشخیص می‌دهند (مثل جست‌وجوی `google.com`، بعضی CAPTCHA‌ها) نسخه ساده بدون JS را سرو می‌کنند. راه‌حل: دامنه مورد نظر را به `hosts` در `config.json` اضافه کنید تا از مسیر SNI-rewrite (با UA واقعی مرورگر) بگذرد. `google.com`، `youtube.com`، `fonts.googleapis.com` از قبل در این لیست هستند. + +- **پخش ویدیو کند است و محدودیت سهمیه دارد** برای چیزهایی که از رله رد می‌شوند. صفحه HTML یوتوب از طریق تونل می‌آید (سریع)، ولی chunk‌های ویدیو از `googlevideo.com` از طریق Apps Script می‌آیند. هر اکانت Apps Script روزانه ~۲ میلیون فراخوانی و هر درخواست حداکثر ۵۰ مگابایت. برای متن مرور اوکی، برای ۱۰۸۰p دردناک. چند `script_id` بگذارید یا برای ویدیو از VPN واقعی استفاده کنید. + +- **فشرده‌سازی Brotli فیلتر می‌شود**. Apps Script gzip می‌تواند باز کند ولی brotli نه. + +- **WebSocket کار نمی‌کند** (رله تک‌درخواستی است). پیام‌رسان‌ها و استریم OpenAI chat روی این کار نمی‌کنند. + +- **ورود دومرحله‌ای گوگل/یوتوب** ممکن است "دستگاه ناشناس" بگوید چون درخواست از IP Apps Script می‌آید نه IP شما. اول با تونل (`google.com` در لیست است) لاگین کنید. + ### اعتبار پروژه اصلی: توسط [@masterking32](https://github.com/masterking32). تمام ایده، پروتکل Apps Script، و نگهداری متعلق به ایشان است. این پورت Rust فقط برای ساده کردن توزیع سمت کلاینت است. diff --git a/src/proxy_server.rs b/src/proxy_server.rs index 6c0c128..1fa9289 100644 --- a/src/proxy_server.rs +++ b/src/proxy_server.rs @@ -16,11 +16,14 @@ use crate::mitm::MitmCertManager; // Domains that are served from Google's core frontend IP pool and therefore // respond correctly when we connect to `google_ip` with SNI=`front_domain` -// and Host=. Kept conservative: anything on a separate CDN -// (googlevideo, ytimg, doubleclick, etc.) is DROPPED because routing to the -// wrong backend breaks rather than helps. Those fall through to the normal -// MITM+relay path, where they'll work (slower) through Apps Script. +// and Host=. Routing these via the tunnel instead of the +// Apps Script relay also avoids Apps Script's fixed "Google-Apps-Script" +// User-Agent, which makes Google serve the bot/no-JS fallback for search. +// Kept conservative: anything on a separate CDN (googlevideo, ytimg, +// doubleclick, etc.) is DROPPED because routing to the wrong backend breaks +// rather than helps. Those fall through to MITM+relay (slower but works). const SNI_REWRITE_SUFFIXES: &[&str] = &[ + "google.com", "youtube.com", "youtu.be", "youtube-nocookie.com",