diff --git a/Cargo.lock b/Cargo.lock index 4b21695..fc42871 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3961,7 +3961,8 @@ dependencies = [ [[package]] name = "tun2proxy" version = "0.7.21" -source = "git+https://github.com/yyoyoian-pixel/tun2proxy?branch=feat%2Fudpgw-jni-param#dfc24ed12cdee69987bdd321ea55c6b940f2d0f0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336ad07beb04a9e219972fcdc54a71d2586cdfd35ac03551a629e4ca328db3c" dependencies = [ "android_logger", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 2ef3b1f..003d362 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,12 +100,6 @@ tun2proxy = { version = "0.7", default-features = false, features = ["udpgw"] } # Used in mitm tests to sanity-check the cert extensions we emit. x509-parser = "0.16" -# Temporary patch: adds udpgw_server parameter to the Android JNI run() -# function. Upstream PR: https://github.com/tun2proxy/tun2proxy/pull/247 -# Remove this section once tun2proxy >= 0.8 ships with the change. -[patch.crates-io] -tun2proxy = { git = "https://github.com/yyoyoian-pixel/tun2proxy", branch = "feat/udpgw-jni-param" } - [profile.release] panic = "abort" codegen-units = 1 diff --git a/android/app/src/main/java/com/github/shadowsocks/bg/Tun2proxy.kt b/android/app/src/main/java/com/github/shadowsocks/bg/Tun2proxy.kt index 4b1e3bf..03953be 100644 --- a/android/app/src/main/java/com/github/shadowsocks/bg/Tun2proxy.kt +++ b/android/app/src/main/java/com/github/shadowsocks/bg/Tun2proxy.kt @@ -59,7 +59,6 @@ object Tun2proxy { tunMtu: Char, verbosity: Int, dnsStrategy: Int, - udpgwServer: String, ): Int /** Signals the running `run()` to shut down. Idempotent. */ diff --git a/android/app/src/main/java/com/therealaleph/mhrv/MhrvVpnService.kt b/android/app/src/main/java/com/therealaleph/mhrv/MhrvVpnService.kt index 69ceb74..58e3dbf 100644 --- a/android/app/src/main/java/com/therealaleph/mhrv/MhrvVpnService.kt +++ b/android/app/src/main/java/com/therealaleph/mhrv/MhrvVpnService.kt @@ -259,21 +259,20 @@ class MhrvVpnService : VpnService() { // the sole owner once it's running. val detachedFd = parcelFd.detachFd() tun2proxyRunning.set(true) - // In full mode, enable udpgw so UDP traffic (DNS, QUIC, …) is - // forwarded through the tunnel-node's native udpgw handler. - // 198.18.0.1:7300 is a magic address the tunnel-node intercepts. - val udpgwAddr = if (cfg.mode == Mode.FULL) "198.18.0.1:7300" else "" + // Use tun2proxy_run_with_cli_args C API via dlsym — gives full + // CLI flexibility including --udpgw-server, no fork needed. + val cliArgs = buildString { + append("tun2proxy") + append(" --proxy socks5://127.0.0.1:$socks5Port") + append(" --tun-fd $detachedFd") + 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") + } val worker = Thread({ try { - val rc = Tun2proxy.run( - "socks5://127.0.0.1:$socks5Port", - detachedFd, - /* closeFdOnDrop = */ true, - MTU.toChar(), - /* verbosity = info */ 3, - /* dnsStrategy = virtual */ 0, - udpgwAddr, - ) + val rc = Native.runTun2proxy(cliArgs, MTU) Log.i(TAG, "tun2proxy exited rc=$rc") } catch (t: Throwable) { Log.e(TAG, "tun2proxy crashed: ${t.message}", t) diff --git a/android/app/src/main/java/com/therealaleph/mhrv/Native.kt b/android/app/src/main/java/com/therealaleph/mhrv/Native.kt index f016d87..517e46d 100644 --- a/android/app/src/main/java/com/therealaleph/mhrv/Native.kt +++ b/android/app/src/main/java/com/therealaleph/mhrv/Native.kt @@ -95,4 +95,14 @@ object Native { * Cheap — just reads atomics. Safe to poll on a second-scale timer. */ external fun statsJson(handle: Long): String + + /** + * 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 tunMtu TUN MTU (typically 1500) + * @return 0 on normal shutdown, negative on error. BLOCKS. + */ + external fun runTun2proxy(cliArgs: String, tunMtu: Int): Int } diff --git a/src/android_jni.rs b/src/android_jni.rs index 6f467be..6bb5a97 100644 --- a/src/android_jni.rs +++ b/src/android_jni.rs @@ -482,3 +482,53 @@ pub extern "system" fn Java_com_therealaleph_mhrv_Native_statsJson<'a>( })); env.new_string(out).map(|s| s.into_raw()).unwrap_or(std::ptr::null_mut()) } + +// --------------------------------------------------------------------------- +// tun2proxy CLI API wrapper (dlsym — no fork or patch needed) +// --------------------------------------------------------------------------- + +/// `Native.runTun2proxy(cliArgs, tunMtu)` -> int +/// +/// Calls `tun2proxy_run_with_cli_args` from libtun2proxy.so via dlsym. +/// This is the C API the tun2proxy maintainer recommends for callers that +/// need full CLI flexibility (e.g. --udpgw-server). BLOCKS until shutdown. +#[no_mangle] +pub extern "system" fn Java_com_therealaleph_mhrv_Native_runTun2proxy<'a>( + mut env: JNIEnv<'a>, + _class: JClass, + cli_args: JString, + tun_mtu: jni::sys::jint, +) -> jni::sys::jint { + safe(-1, AssertUnwindSafe(|| { + let args_str = jstring_to_string(&mut env, &cli_args); + tracing::info!("runTun2proxy: cli={}", args_str); + + unsafe { + use std::ffi::{CStr, CString}; + + let lib = CString::new("libtun2proxy.so").unwrap(); + let handle = libc::dlopen(lib.as_ptr(), libc::RTLD_NOW); + if handle.is_null() { + let err = CStr::from_ptr(libc::dlerror()); + tracing::error!("dlopen libtun2proxy.so failed: {:?}", err); + return -10; + } + + let sym = CString::new("tun2proxy_run_with_cli_args").unwrap(); + let func = libc::dlsym(handle, sym.as_ptr()); + if func.is_null() { + let err = CStr::from_ptr(libc::dlerror()); + tracing::error!("dlsym tun2proxy_run_with_cli_args: {:?}", err); + libc::dlclose(handle); + return -11; + } + + type RunFn = unsafe extern "C" fn(*const std::ffi::c_char, u16, bool) -> i32; + let run: RunFn = std::mem::transmute(func); + let c_args = CString::new(args_str).unwrap(); + let rc = run(c_args.as_ptr(), tun_mtu as u16, false); + libc::dlclose(handle); + rc + } + })) +}