Skip to content

Commit 343def4

Browse files
committed
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.
1 parent 33bba7a commit 343def4

4 files changed

Lines changed: 40 additions & 7 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mhrv-rs"
3-
version = "0.2.1"
3+
version = "0.2.2"
44
edition = "2021"
55
description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting"
66
license = "MIT"

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ This port focuses on the **`apps_script` mode** which is the only one that relia
121121
- [x] Auto-blacklist failing scripts on 429 / quota errors (10-minute cooldown)
122122
- [x] Response cache (50 MB, FIFO + TTL, parses `Cache-Control: max-age`, heuristics for static assets)
123123
- [x] Request coalescing: concurrent identical GETs share one upstream fetch
124-
- [x] SNI-rewrite tunnels for YouTube / googlevideo / doubleclick / etc. — bypass the relay entirely and go direct to Google's edge with SNI=`front_domain`
124+
- [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.
125125
- [x] Automatic redirect handling on the relay (`/exec``googleusercontent.com`)
126126
- [x] Header filtering (strip connection-specific + brotli)
127127
- [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
136136
- [ ] **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
137137
- [ ] **Other modes** (`domain_fronting`, `google_fronting`, `custom_domain`) — Cloudflare killed generic domain fronting in 2024; Cloud Run needs paid plan; skip unless specifically requested
138138

139+
## Known limitations
140+
141+
These are inherent to the Apps Script + domain-fronting approach, not bugs in this client. Same issues exist in the original Python version.
142+
143+
- **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.
144+
145+
- **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.
146+
147+
- **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.
148+
149+
- **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.
150+
151+
- **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.
152+
153+
- **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.
154+
139155
## License
140156

141157
MIT. See [LICENSE](LICENSE).
@@ -203,6 +219,20 @@ mhrv-rs.exe --install-cert
203219

204220
Proxy مرورگر را روی `127.0.0.1:8085` بگذارید (هم HTTP و هم HTTPS).
205221

222+
### محدودیت‌های شناخته‌شده
223+
224+
این‌ها محدودیت‌های ذاتی روش Apps Script هستند، نه باگ در این کلاینت. نسخه اصلی Python هم همین مشکلات را دارد.
225+
226+
- **User-Agent همیشه `Google-Apps-Script` است** برای هر درخواستی که از رله رد می‌شود. `UrlFetchApp.fetch()` گوگل اجازه تغییر این را نمی‌دهد. نتیجه: سایت‌هایی که ربات را تشخیص می‌دهند (مثل جست‌وجوی `google.com`، بعضی CAPTCHA‌ها) نسخه ساده بدون JS را سرو می‌کنند. راه‌حل: دامنه مورد نظر را به `hosts` در `config.json` اضافه کنید تا از مسیر SNI-rewrite (با UA واقعی مرورگر) بگذرد. `google.com`، `youtube.com`، `fonts.googleapis.com` از قبل در این لیست هستند.
227+
228+
- **پخش ویدیو کند است و محدودیت سهمیه دارد** برای چیزهایی که از رله رد می‌شوند. صفحه HTML یوتوب از طریق تونل می‌آید (سریع)، ولی chunk‌های ویدیو از `googlevideo.com` از طریق Apps Script می‌آیند. هر اکانت Apps Script روزانه ~۲ میلیون فراخوانی و هر درخواست حداکثر ۵۰ مگابایت. برای متن مرور اوکی، برای ۱۰۸۰p دردناک. چند `script_id` بگذارید یا برای ویدیو از VPN واقعی استفاده کنید.
229+
230+
- **فشرده‌سازی Brotli فیلتر می‌شود**. Apps Script gzip می‌تواند باز کند ولی brotli نه.
231+
232+
- **WebSocket کار نمی‌کند** (رله تک‌درخواستی است). پیام‌رسان‌ها و استریم OpenAI chat روی این کار نمی‌کنند.
233+
234+
- **ورود دومرحله‌ای گوگل/یوتوب** ممکن است "دستگاه ناشناس" بگوید چون درخواست از IP Apps Script می‌آید نه IP شما. اول با تونل (`google.com` در لیست است) لاگین کنید.
235+
206236
### اعتبار
207237

208238
پروژه اصلی: <https://github.com/masterking32/MasterHttpRelayVPN> توسط [@masterking32](https://github.com/masterking32). تمام ایده، پروتکل Apps Script، و نگهداری متعلق به ایشان است. این پورت Rust فقط برای ساده کردن توزیع سمت کلاینت است.

src/proxy_server.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ use crate::mitm::MitmCertManager;
1616

1717
// Domains that are served from Google's core frontend IP pool and therefore
1818
// respond correctly when we connect to `google_ip` with SNI=`front_domain`
19-
// and Host=<the real domain>. Kept conservative: anything on a separate CDN
20-
// (googlevideo, ytimg, doubleclick, etc.) is DROPPED because routing to the
21-
// wrong backend breaks rather than helps. Those fall through to the normal
22-
// MITM+relay path, where they'll work (slower) through Apps Script.
19+
// and Host=<the real domain>. Routing these via the tunnel instead of the
20+
// Apps Script relay also avoids Apps Script's fixed "Google-Apps-Script"
21+
// User-Agent, which makes Google serve the bot/no-JS fallback for search.
22+
// Kept conservative: anything on a separate CDN (googlevideo, ytimg,
23+
// doubleclick, etc.) is DROPPED because routing to the wrong backend breaks
24+
// rather than helps. Those fall through to MITM+relay (slower but works).
2325
const SNI_REWRITE_SUFFIXES: &[&str] = &[
26+
"google.com",
2427
"youtube.com",
2528
"youtu.be",
2629
"youtube-nocookie.com",

0 commit comments

Comments
 (0)