From c58b36dead2f233e49e90f56dcb4055129383b75 Mon Sep 17 00:00:00 2001 From: altaib Date: Wed, 2 Sep 2026 00:11:05 +0300 Subject: [PATCH] cgo_bridge: export CGoSetEnv so hosts can reach xray-core env knobs The Go runtime snapshots environ when the c-archive image initializes, so a setenv() performed later by a non-Go host is never visible to os.LookupEnv, which common/platform.EnvFlag relies on. That makes platform.TunFdKey ("xray.tun.fd") unreachable on iOS: the tun descriptor only exists after NEPacketTunnelProvider.startTunnel, long after the snapshot, so the "iOS: use provided fd from NetworkExtension" branch in proxy/tun/tun_darwin.go can never be taken. NewTun falls through to creating its own utun via an AF_SYSTEM socket, which the app sandbox denies, and the inbound fails with "failed to start proxy > operation not permitted". --- cgo_bridge/main.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cgo_bridge/main.go b/cgo_bridge/main.go index 2b9ed660..03739f05 100644 --- a/cgo_bridge/main.go +++ b/cgo_bridge/main.go @@ -6,6 +6,7 @@ package main import "C" import ( + "os" "unsafe" libXray "github.com/xtls/libxray" @@ -23,3 +24,22 @@ func CGoInvoke(requestJSON *C.char) *C.char { func CGoFree(value *C.char) { C.free(unsafe.Pointer(value)) } + +// CGoSetEnv sets an environment variable inside the Go runtime. +// +// The Go runtime snapshots environ when the c-archive image initializes, so a +// libc setenv() performed later by the host application is never visible to +// os.LookupEnv. That makes xray-core's env-based knobs unreachable from a +// non-Go host — most importantly platform.TunFdKey ("xray.tun.fd"), which +// proxy/tun/tun_darwin.go reads to adopt an existing tun descriptor. +// +// On iOS the descriptor only exists after NEPacketTunnelProvider.startTunnel, +// long after the snapshot, so the "iOS: use provided fd from NetworkExtension" +// branch can never be taken: NewTun falls through to creating its own utun via +// an AF_SYSTEM socket, which the app sandbox denies, and the inbound fails with +// "app/proxyman/inbound: failed to start proxy > operation not permitted". +// +//export CGoSetEnv +func CGoSetEnv(name *C.char, value *C.char) { + _ = os.Setenv(C.GoString(name), C.GoString(value)) +}