mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 05:44:35 +03:00
40c2b6c509
Adds end-to-end UDP support: SOCKS5 client UDP ASSOCIATE → tunnel-mux
udp_open/udp_data ops → tunnel-node UDP sessions → real UDP to upstream.
QUIC/HTTP3, DNS, and STUN now traverse full mode without falling back to
TCP or leaking outside the tunnel.
Apps Script proxies the new ops opaquely through the existing batch
endpoint; CodeFull.gs only gets a doc-comment update.
Highlights:
- proxy_server.rs: SOCKS5 UDP ASSOCIATE handler with per-session task,
bounded uplink mpsc channel, adaptive empty-poll backoff (500 ms → 30 s),
source-IP validation against the control TCP peer, port-locking on
first valid datagram, and self-removal from the dispatch map on eof.
- tunnel_client.rs: UdpOpen / UdpData / close_session mux variants
alongside the existing TCP plumbing; pkts decoder helper.
- tunnel-node: UdpSessionInner with bounded VecDeque queue, drop-oldest
on overflow with queue_drops counter and warn-then-throttled logs,
last_active refreshed only on real activity (uplink send or upstream
recv — empty polls do not refresh), independent TCP/UDP drain in
handle_batch Phase 2, separate active-drain (150 ms) and retry
(250 ms) windows for UDP, idle long-poll (5 s).
- Tests: SOCKS5 UDP packet parser (IPv4/IPv6/DOMAIN round-trips,
truncation rejects, fragmented rejects), UDP queue overflow drop +
counter, regression test that batch with both UDP and TCP-data ops
still runs the TCP retry pass.
Docs: README + android.{md,fa.md} updated to reflect UDP availability
in full mode; tunnel-node/README documents the new ops.
281 lines
15 KiB
Markdown
281 lines
15 KiB
Markdown
# Android app
|
||
|
||
Full guide for the mhrv-rs Android app: install, first-run setup, troubleshooting, known limits.
|
||
|
||
- [Overview](#overview)
|
||
- [Requirements](#requirements)
|
||
- [1. Install the APK](#1-install-the-apk)
|
||
- [2. Deploy the Apps Script](#2-deploy-the-apps-script)
|
||
- [3. Enter your config in the app](#3-enter-your-config-in-the-app)
|
||
- [4. Run the SNI tester](#4-run-the-sni-tester)
|
||
- [5. Install the MITM certificate](#5-install-the-mitm-certificate)
|
||
- [6. Start the tunnel](#6-start-the-tunnel)
|
||
- [UI quick reference](#ui-quick-reference)
|
||
- [Known limitations](#known-limitations)
|
||
- [Troubleshooting](#troubleshooting)
|
||
- [Uninstall](#uninstall)
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
The Android app is the exact same `mhrv-rs` Rust crate that powers the desktop build, wrapped in a Compose UI and fed a TUN file descriptor via `VpnService` + [`tun2proxy`](https://crates.io/crates/tun2proxy). Every app on the device is routed through the proxy — no per-app setup.
|
||
|
||
```
|
||
Any app on the device
|
||
│
|
||
▼
|
||
VpnService TUN ──► tun2proxy (in-process)
|
||
│
|
||
▼
|
||
Local SOCKS5 listener ──► mhrv-rs dispatcher
|
||
│
|
||
┌───────────────────────┤
|
||
▼ ▼
|
||
sni-rewrite tunnel Apps Script relay
|
||
(Google-owned hosts (everything else,
|
||
direct to google_ip) via your /exec URL)
|
||
```
|
||
|
||
Setup time: **~10 minutes** if your Apps Script deployment already exists, ~15 min if you're deploying fresh.
|
||
|
||
---
|
||
|
||
## Requirements
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Android version** | 7.0 (API 24) or later |
|
||
| **Device architecture** | Any. The APK is universal: arm64-v8a, armeabi-v7a, x86_64, x86 |
|
||
| **Google account** | Yes — you'll deploy the Apps Script under it. A throwaway Gmail works |
|
||
| **Screen lock** | PIN, pattern, password, or biometric + fallback. **Required by Android for user-CA install.** Can be removed after install; the cert stays trusted |
|
||
| **Data usage** | ~5 MB for the APK, then ~2 MB overhead per GB of browsing (base64 + JSON wrapping) |
|
||
|
||
> **Scope note.** mhrv-rs relays through Apps Script. That's what makes it cheap and DPI-resilient, but it's also what imposes the [known limitations](#known-limitations) below. If you're evaluating against a real VPN (WireGuard/Tailscale/OpenVPN), skim that section first.
|
||
|
||
---
|
||
|
||
## 1. Install the APK
|
||
|
||
1. On your phone, open the browser and go to <https://github.com/therealaleph/MasterHttpRelayVPN-RUST/releases/latest>.
|
||
2. Download `mhrv-rs-android-universal-v*.apk`.
|
||
3. Tap the download to open the installer.
|
||
4. When Android asks **"Allow this source to install apps?"**:
|
||
- Tap **Settings**
|
||
- Toggle **Allow from this source**
|
||
- Tap **← Back** → **Install**
|
||
5. Tap **Open** once install finishes.
|
||
|
||
> If Android refuses with "App not installed": an old build signed with a different key is still present. `Settings → Apps → mhrv-rs → Uninstall`, then try again. (From v1.0.2 onward this is a one-time thing — updates are signed with a stable key.)
|
||
|
||
---
|
||
|
||
## 2. Deploy the Apps Script
|
||
|
||
Skip this step if you already have a working `/exec` URL.
|
||
|
||
Do this on a laptop — it's a browser-heavy flow that's painful on a phone.
|
||
|
||
1. Go to <https://script.google.com> → **New project**.
|
||
2. Copy the full contents of [`assets/apps_script/Code.gs`](../assets/apps_script/Code.gs) from this repo.
|
||
3. In the script editor, select the default `function myFunction() {}` and paste over it.
|
||
4. Find the line near the top:
|
||
```js
|
||
const AUTH_KEY = "CHANGE_ME_TO_A_STRONG_SECRET";
|
||
```
|
||
Replace the placeholder with a strong random secret (20+ chars, letters + digits). Save this value — you'll paste it into the app too.
|
||
5. **File → Save** (⌘S / Ctrl+S). Name the project something like `mhrv-relay`.
|
||
6. **Deploy → New deployment**.
|
||
7. Click the gear icon → **Web app**. Fill in:
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Description | `mhrv-relay v1` (or whatever) |
|
||
| Execute as | **Me** |
|
||
| Who has access | **Anyone** |
|
||
|
||
8. Click **Deploy**. First time only: Google asks for permissions.
|
||
- Click **Authorize access** → pick your account
|
||
- On "Google hasn't verified this app" → **Advanced** → **Go to <project name> (unsafe)** → **Allow**
|
||
9. Copy the **Web app URL**. It looks like `https://script.google.com/macros/s/AKfyc.../exec`.
|
||
|
||
<details>
|
||
<summary>What the script does</summary>
|
||
|
||
It receives `POST { method, url, headers, body_base64 }` from our proxy, calls `UrlFetchApp.fetch(url, ...)` inside Google's datacenter, and returns `{ status, headers, body_base64 }`. DPI bypass comes from us connecting to `script.google.com` using a different TLS SNI than the HTTP `Host` header — the ISP sees `www.google.com`, Google's edge routes by the Host header inside the encrypted stream.
|
||
</details>
|
||
|
||
---
|
||
|
||
## 3. Enter your config in the app
|
||
|
||
Back on the phone:
|
||
|
||
| Field | What to enter |
|
||
|---|---|
|
||
| **Deployment URL(s) or script ID(s)** | The `/exec` URL you copied. You can paste multiple — one per line — and the proxy will round-robin between them (useful when you hit the 20k/day per-script quota) |
|
||
| **auth_key** | The exact string you put in `AUTH_KEY` inside `Code.gs` |
|
||
| **google_ip** | Leave the default. The next step will auto-populate it |
|
||
| **front_domain** | Leave at `www.google.com` |
|
||
|
||
Tap anywhere outside the text fields to dismiss the keyboard.
|
||
|
||
---
|
||
|
||
## 4. Run the SNI tester
|
||
|
||
Before starting the tunnel, verify the outbound leg works. Expand **SNI pool + tester** and tap **Test all**.
|
||
|
||
| Result | Meaning | Action |
|
||
|---|---|---|
|
||
| ✅ Green check + `NNN ms` | `google_ip` is reachable + accepts the SNI | Proceed |
|
||
| ❌ `connect timeout` on every row | Configured `google_ip` is unreachable | Tap **Auto-detect google_ip** under the Network card, then Test all again |
|
||
| ❌ `connect timeout` on some rows | Those specific SNIs are DPI-filtered on your network | Leave them unchecked; rotation pool uses only ticked boxes |
|
||
| ❌ `dns: ...` | Device can't resolve `www.google.com` at all | Fix Wi-Fi / airplane mode |
|
||
|
||
If you tap Auto-detect and it still fails on every row, your network is blocking Google's edge entirely — mhrv-rs can't help there.
|
||
|
||
---
|
||
|
||
## 5. Install the MITM certificate
|
||
|
||
The proxy terminates TLS locally (re-encrypts before routing through Apps Script), so your phone needs to trust a cert we minted on first run.
|
||
|
||
1. In the app, tap **Install MITM certificate**.
|
||
2. The confirmation dialog shows the certificate fingerprint. Tap **Install**.
|
||
3. The app:
|
||
- saves a PEM copy to `Downloads/mhrv-ca.crt`
|
||
- opens the Android **Settings** app
|
||
4. **If you don't have a screen lock** — Android will prompt you to set one now. You have to. User CAs require it. You can remove it after install; the cert stays trusted.
|
||
5. In Settings, tap the **search bar** at the top and type `CA certificate`. Open the result labelled **"CA certificate"** (or "Install CA certificate" on some OEMs).
|
||
|
||
> **Don't** pick "VPN & app user certificate" or "Wi-Fi certificate" — wrong category, won't work.
|
||
|
||
Searching is more reliable than navigating menus: Pixel/Samsung/Xiaomi all bury CA install under different paths, but all of them index it under "CA certificate" in search.
|
||
|
||
6. Android warns **"Your network may be monitored by an unknown third party"**. That's us. Tap **Install anyway**.
|
||
7. Pick **Downloads** → tap **mhrv-ca.crt**. Give it a friendly name (or accept the default). Tap **OK**.
|
||
8. Switch back to the mhrv-rs app. A snackbar confirms **Certificate installed ✓** — the app verifies by fingerprint against `AndroidCAStore`.
|
||
|
||
If it says "not yet installed", repeat step 5.
|
||
|
||
<details>
|
||
<summary>Why can't the app install the cert directly?</summary>
|
||
|
||
Android 11 removed the inline `KeyChain.createInstallIntent` flow. That intent used to open a category picker directly inside the app. On current Android it opens a dead-end dialog with just a Close button — Google wants CA installs to be deliberate. We do the grunt work (save file, open Settings, verify afterwards), but the manual navigation step is unavoidable.
|
||
</details>
|
||
|
||
---
|
||
|
||
## 6. Start the tunnel
|
||
|
||
1. Tap **Start**.
|
||
2. Android shows the VPN-permission dialog: *"mhrv-rs wants to set up a VPN connection..."*. Tap **OK**.
|
||
3. A key icon appears in the status bar. That's your VPN indicator.
|
||
4. Open Chrome. Try `https://www.cloudflare.com`, `https://yahoo.com`, `https://discord.com` as stress tests — all should render normally.
|
||
|
||
Expand **Live logs** to watch the traffic flow:
|
||
|
||
| Log line | What it means |
|
||
|---|---|
|
||
| `SOCKS5 CONNECT -> <host>:443` | Browser opened a TCP flow; TUN captured it |
|
||
| `dispatch <host>:443 -> MITM + Apps Script relay` | Routing decision |
|
||
| `MITM TLS -> <host>:443 (sni=<host>)` | Our leaf cert was accepted by the browser |
|
||
| `relay GET https://<host>/...` | Forwarded to Apps Script |
|
||
| `preflight 204 <url>` | CORS preflight we answered ourselves (normal, don't worry about these) |
|
||
|
||
---
|
||
|
||
## UI quick reference
|
||
|
||
| Control | Location | Notes |
|
||
|---|---|---|
|
||
| **Deployment URL(s) or script ID(s)** | Apps Script relay section | One per line; round-robin dispatch |
|
||
| **auth_key** | Apps Script relay section | Must match `AUTH_KEY` in `Code.gs` |
|
||
| **google_ip** / **front_domain** | Network section | Auto-detect button fills google_ip via DNS |
|
||
| **Auto-detect google_ip** | Under the Network row | Re-resolves `www.google.com` + repairs `front_domain` if corrupted to an IP |
|
||
| **SNI pool + tester** | Collapsible | Checkboxes for rotation; per-row Test + Test all |
|
||
| **Advanced** | Collapsible | verify_ssl, log_level, parallel_relay, upstream_socks5 |
|
||
| **Start / Stop** | Bottom row | 2-second debounce between taps |
|
||
| **Install MITM certificate** | Below Start/Stop | Save PEM → open Settings → search "CA certificate" |
|
||
| **Live logs** | Collapsible (below the Install button) | 500ms poll of the proxy's log ring buffer |
|
||
| **v1.0.x (version badge)** | Top bar, right | Tap to check GitHub for a newer release |
|
||
|
||
---
|
||
|
||
## Known limitations
|
||
|
||
Read this before reporting a bug — most "it doesn't work" reports fall into one of these.
|
||
|
||
### Cloudflare Turnstile ("Verify you are human") loops
|
||
|
||
On Cloudflare-protected sites that challenge **every** request, you'll solve the Turnstile, reach the page, then get challenged again on the next click. This is inherent to the Apps Script relay model:
|
||
|
||
| Factor | Normal browser | Apps Script relay |
|
||
|---|---|---|
|
||
| Egress IP | Stable (your ISP) | Rotates across Google's datacenter pool per request |
|
||
| User-Agent | Chrome's | Fixed `Google-Apps-Script` (locked by Google; we can't override) |
|
||
| TLS JA3/JA4 | Chrome's | Google-datacenter's |
|
||
|
||
Cloudflare's `cf_clearance` cookie is bound to the `(IP, UA, JA3)` tuple the challenge was solved against. Different IP next request → re-challenge.
|
||
|
||
**Sites that only gate the first page load** (most of CF's Bot Fight Mode customers) work fine after one solve. Sites that challenge every request (crypto exchanges, adult, some forums) fundamentally can't hold a session through this architecture — use a different tunnel for those.
|
||
|
||
### UDP / QUIC (HTTP/3)
|
||
|
||
In `full` mode, the SOCKS5 listener handles `UDP ASSOCIATE` and tunnels UDP datagrams through Apps Script to `tunnel-node`, which then sends real UDP to the destination. Your ISP still only sees HTTPS to Google. In `apps_script` mode, UDP still falls back the old way: Chrome tries HTTP/3 first and then uses HTTP/2 over TCP.
|
||
|
||
### IPv6 leaks
|
||
|
||
The TUN only routes IPv4 (`addRoute 0.0.0.0/0`). IPv6 goes out your normal interface, including WebRTC. If you're using mhrv-rs for privacy rather than DPI bypass, disable IPv6 on your Wi-Fi network entirely.
|
||
|
||
### Apps Script daily quota
|
||
|
||
Each `/exec` has a daily execution limit (20k/day for consumer Google accounts, higher for Workspace). Heavy streaming or infinite-scroll sites burn through it. Mitigation: deploy 2–3 scripts, paste all their `/exec` URLs into the app, one per line — the proxy round-robins.
|
||
|
||
### Most non-browser apps ignore user CAs
|
||
|
||
By default, Android apps opt out of trusting user-installed CAs (Android 7+ `Network Security Config` default). Banking apps, Netflix, Spotify, most messengers — they'll fail with cert errors through mhrv-rs. The TUN routes their traffic to us; they just refuse our leaf. Only apps that explicitly opt in (browsers, curl, some developer tools) will work. This is a general MITM-proxy limitation.
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
| Symptom | Likely cause | Fix |
|
||
|---|---|---|
|
||
| `504 Relay timeout` in Chrome | Apps Script deployment not responding | Re-check the `/exec` URL (must end in `/exec`, not `/dev`). Watch Live logs for `Relay timeout` vs `connect:` errors |
|
||
| `NET::ERR_CERT_AUTHORITY_INVALID` | MITM CA not installed / not found | Redo [step 5](#5-install-the-mitm-certificate). Make sure you picked "CA certificate" in Settings, not VPN or Wi-Fi |
|
||
| `NET::ERR_CERT_COMMON_NAME_INVALID` on Cloudflare sites | Pre-v1.0 bug | Upgrade to v1.0.0 or later |
|
||
| JS parts of a site don't load | Pre-v1.0 OPTIONS rejection | Upgrade to v1.0.0+. If still present: Live logs → grep for `Relay failed`, report |
|
||
| All SNIs time out in the tester | `google_ip` is stale (Google rotated the A record) | Tap **Auto-detect google_ip** |
|
||
| SNI tester red on some rows only | Those SNIs are DPI-filtered on your network | Uncheck the failing ones in the rotation pool |
|
||
| App closes when tapping Stop | Was a v1.0.0/1.0.1 race bug | Upgrade to v1.0.2. If still present on v1.0.2+: `adb logcat -s MhrvVpnService mhrv-crash mhrv_rs` and report |
|
||
| `INSTALL_FAILED_UPDATE_INCOMPATIBLE` when upgrading | Old APK signed with a different key (pre-v1.0.2) | Uninstall first, then install the new APK. Only a one-time thing — v1.0.2 onward has a stable signature |
|
||
| Chrome white-pages with no error | Often a rendering bug on the emulator with software GPU | Test on real hardware. Check `Live logs` to verify the relay is actually making requests |
|
||
| Cloudflare Turnstile loop | [Known limitation](#cloudflare-turnstile-verify-you-are-human-loops) | No fix inside this architecture |
|
||
| Banking/streaming apps show cert errors | [Known limitation](#most-non-browser-apps-ignore-user-cas) | No fix — app chose not to trust user CAs |
|
||
|
||
### Collecting a useful log
|
||
|
||
If you need to report a bug:
|
||
|
||
```sh
|
||
adb logcat -c # clear
|
||
# reproduce the issue in the app
|
||
adb logcat -d | grep -E "MhrvVpnService|mhrv_rs|mhrv-crash|tun2proxy" > mhrv.log
|
||
```
|
||
|
||
Attach `mhrv.log` to your issue. Also include:
|
||
- Android version (Settings → About phone → Android version)
|
||
- OEM (Pixel / Samsung / Xiaomi / …)
|
||
- App version (tap the version badge in the top bar)
|
||
- What you did, what you expected, what happened
|
||
|
||
---
|
||
|
||
## Uninstall
|
||
|
||
1. `Settings → Apps → mhrv-rs → Uninstall`.
|
||
2. Optional: remove the MITM CA — `Settings → Security → Encryption & credentials → User credentials → mhrv-rs MITM CA → Remove`. (On OEMs where that path is buried, search Settings for `user credentials`.)
|
||
3. The VPN profile is auto-revoked on uninstall — nothing to clean up there.
|