From e0a0d14420892cf273510f6ebefee16f9e4e2378 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 13 May 2026 20:03:11 +0200 Subject: [PATCH] cli: add --mtu flag for tun2proxy-bin The bin always passes `tun::DEFAULT_MTU` (1500) to `general_run_async`, which the userspace TCP stack then uses to derive the MSS of segments written into the TUN. When the TUN traffic is forwarded onwards over a link with a smaller MTU (a WireGuard underlay at 1420 is the common case), the kernel either fragments or, with the DF bit set, silently drops segments larger than the next-hop MTU, and the resulting black-hole is hard to diagnose because the proxy-side TCP looks healthy end to end. Setting the iface MTU alone is not enough because the userspace stack derives MSS from the value passed at startup, not from the live iface MTU. `tun2proxy::general_api::general_run_for_api` already takes a `tun_mtu` parameter from the C/JNI APIs, so this just plumbs the same value through the CLI path. Default stays at 1500, so behaviour for existing users is unchanged. Signed-off-by: DL6ER --- src/args.rs | 9 +++++++++ src/bin/main.rs | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/args.rs b/src/args.rs index fe87fac..27bffe3 100644 --- a/src/args.rs +++ b/src/args.rs @@ -104,6 +104,14 @@ pub struct Args { #[arg(short, long, value_name = "IP/CIDR")] pub bypass: Vec, + /// MTU of the TUN device. Userspace TCP stack uses (MTU - 40) as the + /// effective MSS for synthesized segments going to the kernel side, so + /// lower this when the kernel forwards the traffic onwards through a + /// link with a smaller MTU (e.g. a WireGuard tunnel at 1420) to avoid + /// having the bigger segments silently dropped. + #[arg(long, value_name = "bytes", default_value_t = tun::DEFAULT_MTU)] + pub mtu: u16, + /// TCP timeout in seconds #[arg(long, value_name = "seconds", default_value = "600")] pub tcp_timeout: u64, @@ -181,6 +189,7 @@ impl Default for Args { dns: ArgDns::default(), dns_addr: "8.8.8.8".parse().unwrap(), bypass: vec![], + mtu: tun::DEFAULT_MTU, tcp_timeout: 600, udp_timeout: 10, verbosity: ArgVerbosity::Info, diff --git a/src/bin/main.rs b/src/bin/main.rs index 3269452..5712452 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -77,7 +77,8 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - let ret = tun2proxy::general_run_async(args, tun::DEFAULT_MTU, cfg!(target_os = "macos"), shutdown_token).await; + let mtu = args.mtu; + let ret = tun2proxy::general_run_async(args, mtu, cfg!(target_os = "macos"), shutdown_token).await; if let Err(err) = &ret { log::error!("main loop error: {err}"); }