You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(udpgw): move magic IP out of tun2proxy virtual-DNS range (#251, #1143)
Closes#251. In Android Full mode, Telegram worked but Google search and most other websites failed silently. `apps_script` mode on the same setup was unaffected.
**Root cause**: the udpgw magic destination (`198.18.0.1:7300`) was inside `198.18.0.0/15` — the exact range tun2proxy's `--dns virtual` allocator uses to synthesise fake IPs for hostname lookups. Whenever virtual DNS assigned `198.18.0.1` to a real hostname, that hostname's traffic was intercepted by tun2proxy *itself* as a udpgw connection and dropped. Telegram was immune because it uses hardcoded numeric IPs; `apps_script` mode was immune because it never sets `--udpgw-server`.
**Fix**: move `UDPGW_MAGIC_IP` to `192.0.2.1` (RFC 5737 TEST-NET-1) — outside any virtual-DNS allocation pool. Coordinated change across the tunnel-node constant and the Android `--udpgw-server` flag.
## Back-compat
v1.9.25 tunnel-nodes still recognise the legacy `198.18.0.1:7300` for one deprecation cycle (removal in v1.10.0).
| Android | Tunnel-node | Full-mode UDP |
|---|---|---|
| v1.9.25 | v1.9.25 | ✅ fully fixed |
| ≤v1.9.24 | v1.9.25 | ⚠️ handshake works (legacy IP still recognised), but the old client still asks tun2proxy for `198.18.0.1`, so the #251 virtual-DNS collision is still live on-device |
| v1.9.25 | ≤v1.9.24 | ❌ breaks silently (old node rejects `192.0.2.1`) |
The fix lives on the client side (which magic IP it asks tun2proxy to reserve). The back-compat is on the tunnel-node side (accepting both during the deprecation window).
## Verified locally
- `cargo test --lib --release`: 231/231 ✅
- `cargo build --release --features ui --bin mhrv-rs-ui`: clean ✅
- `(cd tunnel-node && cargo test --release)`: 38/38 ✅ (+2 new tests for the IP change)
## Version bump
Cargo.toml already bumped to 1.9.25 in this PR; `docs/changelog/v1.9.25.md` pre-baked. Will combine with any other PRs landing into v1.9.25 before tagging.
Reviewed via Anthropic Claude.
Co-Authored-By: dazzling-no-more <noreply@github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
<!-- see docs/changelog/v1.1.0.md for the file format: Persian, then `---`, then English. -->
2
+
<divdir="rtl">
3
+
4
+
• **رفع باگ Full mode «Google و اکثر سایتها خراب، تلگرام سالم» — `udpgw magic IP از داخل virtual-DNS range tun2proxy منتقل شد`** ([#251](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/251) by @dazzling-no-more).
5
+
6
+
در Full mode روی Android، تلگرام کار میکرد ولی Google search و اکثر سایتها silently fail میشدن — `apps_script` mode روی همون device سالم بود و VPS هم idle.
7
+
8
+
**علت**: آدرس magic مربوط به udpgw (یعنی `198.18.0.1:7300`) داخل `198.18.0.0/15` بود، یعنی دقیقاً همون rangeای که `tun2proxy --dns virtual` ازش IPهای ساختگی رو برای hostname lookupها اختصاص میده. هر دفعه که virtual DNS اتفاقاً `198.18.0.1` رو به یک hostname مثل `www.google.com` allocate میکرد، traffic اون host بهعنوان udpgw connection مصادره میشد و drop میشد. تلگرام immune بود چون native clientش از IPهای عددی hardcoded استفاده میکنه؛ همچنین `apps_script` mode هم immune بود چون اصلاً `--udpgw-server` ست نمیکنه.
9
+
10
+
**راهحل**: ثابت `UDPGW_MAGIC_IP` به `192.0.2.1` (RFC 5737 TEST-NET-1) منتقل شد. دو فایل تغییر کرده: یکی `tunnel-node/src/udpgw.rs` (constant + tests) و دیگری `android/.../MhrvVpnService.kt` (که حالا از یک companion const به اسم `UDPGW_MAGIC_DEST` استفاده میکنه).
11
+
12
+
**سازگاری با نسخههای قدیمی**: نسخهٔ جدید tunnel-node همچنان `198.18.0.1:7300` قدیمی رو هم accept میکنه برای یک deprecation cycle (حذف در v1.10.0) — یعنی اگه VPS رو زودتر آپدیت کنی، Android قدیمی هنوز کار میکنه. **ولی اگه Android رو زودتر آپدیت کنی، tunnel-node قدیمی UDP relay رو در Full mode break میکنه**. توصیه: اول tunnel-node رو آپدیت کن، بعد APK رو.
13
+
14
+
</div>
15
+
---
16
+
• **Fix Full mode "Google + most websites broken while Telegram works" — `udpgw magic IP moved out of tun2proxy virtual-DNS range`** ([#251](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/251) by @dazzling-no-more). Users on Android Full mode reported that Telegram worked fine but Google search and most other websites failed to load — while apps_script mode on the same device + same `google_ip` worked perfectly and the VPS was sitting idle.
17
+
18
+
**Root cause**: the udpgw magic destination address (`198.18.0.1:7300`) lived inside `198.18.0.0/15` — the exact same range that tun2proxy's `--dns virtual` allocator uses to synthesise fake IPs for hostname lookups. Whenever virtual DNS happened to assign `198.18.0.1` to a real hostname (e.g. `www.google.com`), that hostname's connections were intercepted by tun2proxy *itself* as a udpgw request before they ever reached the SOCKS5 proxy. Result: a random subset of DNS-resolved hosts silently broke per session, depending on which hostname won the `198.18.0.1` allocation. Telegram was unaffected because its native client uses hardcoded numeric IPs (no DNS allocation needed). apps_script mode was unaffected because it doesn't pass `--udpgw-server` to tun2proxy at all.
19
+
20
+
**Fix**: relocate `UDPGW_MAGIC_IP` from `198.18.0.1` to `192.0.2.1` (RFC 5737 TEST-NET-1). TEST-NET-1 is reserved for documentation, never routed on the public internet, and — critically — outside any virtual-DNS allocation pool. Structurally equivalent to the old address as a "guaranteed-not-real-destination", just no longer colliding with tun2proxy's reserved range.
21
+
22
+
Coordinated two-side change:
23
+
24
+
1.**`tunnel-node/src/udpgw.rs`**: `UDPGW_MAGIC_IP = [192, 0, 2, 1]`, doc comment now cites RFC 5737 + explicitly explains why it must stay out of `198.18.0.0/15`. Test additions: `is_udpgw_dest_works` covers both the new IP and the legacy IP (back-compat assertion); new `magic_ip_outside_virtual_dns_range` enforces the invariant at the `198.18.0.0/15`*range* level, so any future move to `198.19.x.y` would also fail the test rather than re-introducing the same class of bug.
25
+
2.**`android/.../MhrvVpnService.kt`**: `--udpgw-server $UDPGW_MAGIC_DEST` where `UDPGW_MAGIC_DEST = "192.0.2.1:7300"` is a new companion-object constant, with a docstring pointing back at the Rust constant — gives the next editor a single, labelled place to update if the convention ever changes again.
26
+
27
+
**Back-compatibility — partial, one-way**:
28
+
29
+
The udpgw magic IP is a wire-protocol convention between the Android client and the `mhrv-tunnel` Docker container. v1.9.25 tunnel-nodes accept both the new `192.0.2.1:7300` and the legacy `198.18.0.1:7300` for one deprecation cycle (slated for removal in v1.10.0). That softens — but does *not* fully resolve — the asymmetric-upgrade matrix:
30
+
31
+
| Android | Tunnel-node | Full-mode UDP relay |
32
+
|---|---|---|
33
+
| v1.9.25 | v1.9.25 | ✅ fully fixed |
34
+
| ≤v1.9.24 | v1.9.25 | ⚠️ udpgw handshake works (legacy IP still recognised by the node), but the **old client still asks tun2proxy for `--udpgw-server 198.18.0.1:7300`** — meaning the underlying #251 virtual-DNS-pool collision is still live on the device. Telegram works; the random Google-search-style breakage persists until the APK is updated. |
35
+
| v1.9.25 | ≤v1.9.24 | ❌ **breaks silently** — new client sends `192.0.2.1`, old node treats it as a real TCP destination and the connect fails |
36
+
| ≤v1.9.24 | ≤v1.9.24 | unchanged from before (still has the original #251 bug) |
37
+
38
+
**Recommended upgrade order**: update **both halves** to v1.9.25. The fix is on the *client* side (which magic IP it asks tun2proxy to reserve) — the tunnel-node back-compat shim only prevents a hard handshake break during the window where the node is upgraded first; it does not fix the original bug. If you can only update one half right now: do the **APK first** (or both together), since updating just the tunnel-node leaves clients still hitting the virtual-DNS collision. `apps_script`-only users are unaffected (the udpgw path isn't used in apps_script mode).
39
+
40
+
**Diagnostic note for stuck users**: if Telegram works on Full mode but Google search / random websites silently fail on v1.9.24 or earlier, this is your bug. As a workaround pending upgrade, add Google domains to `passthrough_hosts` to route them through tunnel-node like Telegram does:
0 commit comments