From fb8d8d8fcaf39fc5e7e38526b5c95e3d923ad4b8 Mon Sep 17 00:00:00 2001 From: Leadaxe <247031499+Leadaxe@users.noreply.github.com> Date: Sun, 21 Jun 2026 15:49:57 +0300 Subject: [PATCH] fix(010): never enable UDP_GRO on android (GRO split-brain killed download) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit runtime.GOOS=="android" (not "linux"), so StdNetBind enabled UDP_GRO and read rxOffload=true, but the GRO receive dispatcher in bind_std.go is gated on GOOS=="linux" → dead on android. A coalesced GRO super-packet was read as one datagram, corrupting the WG transport stream → download died on no-detour WG-endpoint (detour path uses ClientBind, no offload, so it worked). Gate both the UDP_GRO setsockopt (controlfns_linux.go) and the rxOffload readback (features_linux.go) behind !android. TX/GSO untouched, so non-android linux performance is unchanged. Confirmed on device (CPH2411/Android-15: probe gave rxOffload=true + dispatch=single). See SPECS/010-B-O-WG_ENDPOINT_GRO_SPLIT_BRAIN. --- conn/controlfns_linux.go | 9 +++++++++ conn/features_linux.go | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/conn/controlfns_linux.go b/conn/controlfns_linux.go index 752fbca..7602665 100644 --- a/conn/controlfns_linux.go +++ b/conn/controlfns_linux.go @@ -60,6 +60,15 @@ func init() { // Attempt to enable UDP_GRO func(network, address string, c syscall.RawConn) error { + // lx(010): skip UDP_GRO on android. The GRO receive path in bind_std.go + // is gated on runtime.GOOS=="linux", which is false on android — so a + // coalesced super-packet is never split and corrupts the WG stream + // (download dies). Belt-and-suspenders with the rxOffload guard in + // features_linux.go. TX/GSO untouched. + // See SPECS/010-B-O-WG_ENDPOINT_GRO_SPLIT_BRAIN. + if runtime.GOOS == "android" { + return nil + } c.Control(func(fd uintptr) { _ = unix.SetsockoptInt(int(fd), unix.IPPROTO_UDP, socketOptionUDPGRO, 1) }) diff --git a/conn/features_linux.go b/conn/features_linux.go index 513202e..b74c398 100644 --- a/conn/features_linux.go +++ b/conn/features_linux.go @@ -7,6 +7,7 @@ package conn import ( "net" + "runtime" "golang.org/x/sys/unix" ) @@ -29,6 +30,15 @@ func supportsUDPOffload(conn *net.UDPConn) (txOffload, rxOffload bool) { return } txOffload = true + // lx(010): never advertise RX offload on android. runtime.GOOS=="android" + // (not "linux"), so the GRO receive dispatcher in bind_std.go (gated on + // GOOS=="linux") is dead there — a coalesced GRO super-packet would be read + // as one datagram and corrupt the WG transport stream, killing download. + // Confirmed on device (CPH2411/Android-15: rxOffload=true, dispatch=single). + // TX is left untouched. See SPECS/010-B-O-WG_ENDPOINT_GRO_SPLIT_BRAIN. + if runtime.GOOS == "android" { + return + } opt, errSyscall := unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, socketOptionUDPGRO) if errSyscall != nil { return