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.
This commit is contained in:
therealaleph
2026-04-21 19:34:02 +03:00
parent ea5c6ca9a4
commit 33bba7a0f7
3 changed files with 28 additions and 14 deletions
Generated
+1 -1
View File
@@ -365,7 +365,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "mhrv-rs"
version = "0.2.0"
version = "0.2.1"
dependencies = [
"base64",
"bytes",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "mhrv-rs"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting"
license = "MIT"
+26 -12
View File
@@ -14,22 +14,16 @@ use crate::config::Config;
use crate::domain_fronter::DomainFronter;
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=<the real domain>. 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.
const SNI_REWRITE_SUFFIXES: &[&str] = &[
"youtube.com",
"youtu.be",
"youtube-nocookie.com",
"youtubeeducation.com",
"googlevideo.com",
"ytimg.com",
"ggpht.com",
"gvt1.com",
"gvt2.com",
"doubleclick.net",
"googlesyndication.com",
"googleadservices.com",
"google-analytics.com",
"googletagmanager.com",
"googletagservices.com",
"fonts.googleapis.com",
];
@@ -229,6 +223,11 @@ fn parse_request_head(head: &[u8]) -> Option<(String, String, String, Vec<(Strin
let method = parts.next()?.to_string();
let target = parts.next()?.to_string();
let version = parts.next().unwrap_or("HTTP/1.1").to_string();
if !is_valid_http_method(&method) {
return None;
}
let mut headers = Vec::new();
for l in lines {
if l.is_empty() {
@@ -241,6 +240,21 @@ fn parse_request_head(head: &[u8]) -> Option<(String, String, String, Vec<(Strin
Some((method, target, version, headers))
}
fn is_valid_http_method(m: &str) -> bool {
matches!(
m,
"GET"
| "POST"
| "PUT"
| "DELETE"
| "HEAD"
| "OPTIONS"
| "PATCH"
| "TRACE"
| "CONNECT"
)
}
// ---------- CONNECT handling ----------
async fn do_connect(