From 4360ae705d564e5da1c8e8a98368719ee1e92253 Mon Sep 17 00:00:00 2001 From: Tamim Hossain <132823494+codewithtamim@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:06:38 +0600 Subject: [PATCH] add Android process finder feature --- android_wrapper.go | 30 ++++++++++++++++++++++++++++++ controller/controller_android.go | 22 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/android_wrapper.go b/android_wrapper.go index 1e18a9eb..bf46ee88 100644 --- a/android_wrapper.go +++ b/android_wrapper.go @@ -11,6 +11,21 @@ type DialerController interface { ProtectFd(int) bool } +// ProcessFinder is an interface for Android process finding functionality. +// Apps should implement FindProcessByConnection() +// and pass the implementation to RegisterProcessFinder() before starting the core. +type ProcessFinder interface { + // FindProcessByConnection finds the UID of the process that owns the given connection. + // + // network: Protocol type: "tcp" or "udp" + // srcIP: Source IP address + // srcPort: Source port + // destIP: Destination IP address + // destPort: Destination port + // Returns the UID of the owning process, or -1 if not found. + FindProcessByConnection(network, srcIP string, srcPort int, destIP string, destPort int) int +} + func InitDns(controller DialerController, server string) { dns.InitDns(server, func(fd uintptr) { controller.ProtectFd(int(fd)) @@ -32,3 +47,18 @@ func RegisterListenerController(controller DialerController) { controller.ProtectFd(int(fd)) }) } + +// RegisterProcessFinder registers an Android process finder with Xray-core, +// enabling per-app routing based on UID. Must be called before starting the +// core for process-based routing rules to work. +// Pass nil to unregister a previously registered finder. +func RegisterProcessFinder(finder ProcessFinder) { + if finder == nil { + c.RegisterProcessFinder(nil) + return + } + + c.RegisterProcessFinder(func(network, srcIP string, srcPort int, destIP string, destPort int) int { + return finder.FindProcessByConnection(network, srcIP, srcPort, destIP, destPort) + }) +} diff --git a/controller/controller_android.go b/controller/controller_android.go index f3db07fd..82dc0b67 100644 --- a/controller/controller_android.go +++ b/controller/controller_android.go @@ -3,8 +3,10 @@ package controller import ( + "fmt" "syscall" + corenet "github.com/xtls/xray-core/common/net" xinternet "github.com/xtls/xray-core/transport/internet" ) @@ -23,3 +25,23 @@ func RegisterListenerController(controller func(fd uintptr)) { return conn.Control(controller) }) } + +// RegisterProcessFinder registers an Android process finder with Xray-core, +// enabling per-app routing based on UID. Must be called before starting the +// core for process-based routing rules to work. +// Pass nil to unregister a previously registered finder. +func RegisterProcessFinder(finder func(network, srcIP string, srcPort int, destIP string, destPort int) int) { + if finder == nil { + corenet.RegisterAndroidProcessFinder(nil) + return + } + + corenet.RegisterAndroidProcessFinder(func(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (int, string, string, error) { + if destPort == 0 || destIP == "" { + return 0, "", "", fmt.Errorf("process finder: no destination for %s %s:%d", network, srcIP, srcPort) + } + + uid := finder(network, srcIP, int(srcPort), destIP, int(destPort)) + return uid, fmt.Sprintf("%d", uid), "", nil + }) +}