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>
This commit is contained in:
dazzling-no-more
2026-05-13 23:45:23 +04:00
committed by GitHub
parent 283073fe77
commit e70947ff0d
6 changed files with 120 additions and 9 deletions
+2 -2
View File
@@ -14,8 +14,8 @@ android {
applicationId = "com.therealaleph.mhrv"
minSdk = 24 // Android 7.0 — covers 99%+ of live devices.
targetSdk = 34
versionCode = 158
versionName = "1.8.1"
versionCode = 159
versionName = "1.9.25"
// Ship all four mainstream Android ABIs:
// - arm64-v8a — 95%+ of real-world Android phones since 2019
@@ -268,7 +268,7 @@ class MhrvVpnService : VpnService() {
append(" --dns virtual")
append(" --verbosity info")
append(" --close-fd-on-drop true")
if (cfg.mode == Mode.FULL) append(" --udpgw-server 198.18.0.1:7300")
if (cfg.mode == Mode.FULL) append(" --udpgw-server $UDPGW_MAGIC_DEST")
}
val worker = Thread({
try {
@@ -499,5 +499,14 @@ class MhrvVpnService : VpnService() {
private const val NOTIF_ID = 0x1001
private const val MTU = 1500
const val ACTION_STOP = "com.therealaleph.mhrv.STOP"
// Magic udpgw destination passed to tun2proxy in Full mode. MUST stay
// outside tun2proxy's --dns virtual range (198.18.0.0/15) — otherwise
// virtual DNS can synthesise the magic IP for a real hostname and
// silently mis-route its traffic into the udpgw path. See issue #251
// and `UDPGW_MAGIC_IP` / `UDPGW_MAGIC_PORT` in tunnel-node/src/udpgw.rs.
// Wire-protocol convention: both sides must agree. v1.9.25+ tunnel-nodes
// also accept the legacy 198.18.0.1:7300 for one deprecation cycle.
private const val UDPGW_MAGIC_DEST = "192.0.2.1:7300"
}
}
@@ -114,7 +114,7 @@ object Native {
* Start tun2proxy via its CLI args C API (`tun2proxy_run_with_cli_args`).
* Resolved at runtime via dlsym from libtun2proxy.so — no fork needed.
*
* @param cliArgs full CLI string, e.g. "tun2proxy --proxy socks5://... --tun-fd 42 --udpgw-server 198.18.0.1:7300"
* @param cliArgs full CLI string, e.g. "tun2proxy --proxy socks5://... --tun-fd 42 --udpgw-server 192.0.2.1:7300"
* @param tunMtu TUN MTU (typically 1500)
* @return 0 on normal shutdown, negative on error. BLOCKS.
*/