Routing: process supports UID on Android (#5915)

Example: https://github.com/XTLS/Xray-core/pull/5915#issuecomment-4232122895

---------

Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
This commit is contained in:
Exclude0122
2026-04-13 09:17:53 -04:00
committed by GitHub
parent c93478b891
commit f27edc3172
5 changed files with 70 additions and 43 deletions

View File

@@ -390,8 +390,10 @@ func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
if len(ctx.GetSourceIPs()) == 0 { if len(ctx.GetSourceIPs()) == 0 {
return false return false
} }
srcPort := ctx.GetSourcePort().String()
srcPort := uint16(ctx.GetSourcePort())
srcIP := ctx.GetSourceIPs()[0].String() srcIP := ctx.GetSourceIPs()[0].String()
var network string var network string
switch ctx.GetNetwork() { switch ctx.GetNetwork() {
case net.Network_TCP: case net.Network_TCP:
@@ -401,11 +403,15 @@ func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
default: default:
return false return false
} }
src, err := net.ParseDestination(strings.Join([]string{network, srcIP, srcPort}, ":"))
if err != nil { var dstIP string
return false var dstPort uint16 = 0
if len(ctx.GetTargetIPs()) > 0 {
dstIP = ctx.GetTargetIPs()[0].String()
dstPort = uint16(ctx.GetTargetPort())
} }
pid, name, absPath, err := net.FindProcess(src)
pid, name, absPath, err := net.FindProcess(network, srcIP, uint16(srcPort), dstIP, uint16(dstPort))
if err != nil { if err != nil {
if err != net.ErrNotLocal { if err != net.ErrNotLocal {
errors.LogError(context.Background(), "Unables to find local process name: ", err) errors.LogError(context.Background(), "Unables to find local process name: ", err)

View File

@@ -0,0 +1,20 @@
//go:build android
package net
import (
"github.com/xtls/xray-core/common/errors"
)
var androidProcessFinder func(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (int, string, string, error)
func RegisterAndroidProcessFinder(f func(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (int, string, string, error)) {
androidProcessFinder = f
}
func FindProcess(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (int, string, string, error) {
if androidProcessFinder != nil {
return androidProcessFinder(network, srcIP, srcPort, destIP, destPort)
}
return 0, "", "", errors.New("android process lookup must be registered before use")
}

View File

@@ -1,4 +1,4 @@
//go:build linux //go:build linux && !android
package net package net
@@ -6,6 +6,7 @@ import (
"bufio" "bufio"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"net"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@@ -13,43 +14,38 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
) )
func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, err error) { func FindProcess(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (PID int, Name string, AbsolutePath string, err error) {
isLocal, err := IsLocal(dest.Address.IP()) isLocal, err := IsLocal(net.ParseIP(srcIP))
if err != nil { if err != nil {
return 0, "", "", errors.New("failed to determine if address is local: ", err) return 0, "", "", errors.New("failed to determine if address is local: ", err)
} }
if !isLocal { if !isLocal {
return 0, "", "", ErrNotLocal return 0, "", "", ErrNotLocal
} }
if dest.Network != Network_TCP && dest.Network != Network_UDP { if network != "tcp" && network != "udp" {
panic("Unsupported network type for process lookup.") panic("Unsupported network type for process lookup.")
} }
// the core should never has a domain as source(?
if dest.Address.Family() == AddressFamilyDomain {
panic("Domain addresses are not supported for process lookup.")
}
var procFile string var procFile string
switch dest.Network { switch network {
case Network_TCP: case "tcp":
if dest.Address.Family() == AddressFamilyIPv4 { if net.ParseIP(srcIP).To4() != nil {
procFile = "/proc/net/tcp" procFile = "/proc/net/tcp"
} } else {
if dest.Address.Family() == AddressFamilyIPv6 {
procFile = "/proc/net/tcp6" procFile = "/proc/net/tcp6"
} }
case Network_UDP: case "udp":
if dest.Address.Family() == AddressFamilyIPv4 { if net.ParseIP(srcIP).To4() != nil {
procFile = "/proc/net/udp" procFile = "/proc/net/udp"
} } else {
if dest.Address.Family() == AddressFamilyIPv6 {
procFile = "/proc/net/udp6" procFile = "/proc/net/udp6"
} }
default: default:
panic("Unsupported network type for process lookup.") panic("Unsupported network type for process lookup.")
} }
targetHexAddr, err := formatLittleEndianString(dest.Address, dest.Port) targetHexAddr, err := formatLittleEndianString(net.ParseIP(srcIP), Port(srcPort))
if err != nil { if err != nil {
return 0, "", "", errors.New("failed to format address: ", err) return 0, "", "", errors.New("failed to format address: ", err)
} }
@@ -59,7 +55,7 @@ func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, e
return 0, "", "", errors.New("could not search in ", procFile).Base(err) return 0, "", "", errors.New("could not search in ", procFile).Base(err)
} }
if inode == "" { if inode == "" {
return 0, "", "", errors.New("connection for ", dest.Address, ":", dest.Port, " not found in ", procFile) return 0, "", "", errors.New("connection for ", srcIP, ":", srcPort, " not found in ", procFile)
} }
pidStr, err := findPidByInode(inode) pidStr, err := findPidByInode(inode)
@@ -86,16 +82,16 @@ func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, e
return pid, procName, absPath, nil return pid, procName, absPath, nil
} }
func formatLittleEndianString(addr Address, port Port) (string, error) { func formatLittleEndianString(addr net.IP, port Port) (string, error) {
ip := addr.IP() ip := addr
var ipBytes []byte var ipBytes []byte
if addr.Family() == AddressFamilyIPv4 { if ip.To4() != nil {
ipBytes = ip.To4() ipBytes = ip.To4()
} else { } else {
ipBytes = ip.To16() ipBytes = ip.To16()
} }
if ipBytes == nil { if ipBytes == nil {
return "", errors.New("invalid IP format for ", addr.Family(), ": ", ip) return "", errors.New("invalid IP format for ", addr, ": ", ip)
} }
for i, j := 0, len(ipBytes)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(ipBytes)-1; i < j; i, j = i+1, j-1 {

View File

@@ -1,4 +1,4 @@
//go:build !windows && !linux //go:build !windows && !linux && !android
package net package net
@@ -6,6 +6,6 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
) )
func FindProcess(dest Destination) (int, string, string, error) { func FindProcess(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (int, string, string, error) {
return 0, "", "", errors.New("process lookup is not supported on this platform") return 0, "", "", errors.New("process lookup is not supported on this platform")
} }

View File

@@ -3,6 +3,7 @@
package net package net
import ( import (
"net"
"net/netip" "net/netip"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -49,41 +50,37 @@ func initWin32API() error {
return nil return nil
} }
func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, err error) { func FindProcess(network, srcIP string, srcPort uint16, destIP string, destPort uint16) (PID int, Name string, AbsolutePath string, err error) {
once.Do(func() { once.Do(func() {
initErr = initWin32API() initErr = initWin32API()
}) })
if initErr != nil { if initErr != nil {
return 0, "", "", initErr return 0, "", "", initErr
} }
isLocal, err := IsLocal(dest.Address.IP()) isLocal, err := IsLocal(net.ParseIP(srcIP))
if err != nil { if err != nil {
return 0, "", "", errors.New("failed to determine if address is local: ", err) return 0, "", "", errors.New("failed to determine if address is local: ", err)
} }
if !isLocal { if !isLocal {
return 0, "", "", ErrNotLocal return 0, "", "", ErrNotLocal
} }
if dest.Network != Network_TCP && dest.Network != Network_UDP { if network != "tcp" && network != "udp" {
panic("Unsupported network type for process lookup.") panic("Unsupported network type for process lookup.")
} }
// the core should never has a domain as source(?
if dest.Address.Family() == AddressFamilyDomain {
panic("Domain addresses are not supported for process lookup.")
}
var class int var class int
var fn uintptr var fn uintptr
switch dest.Network { switch network {
case Network_TCP: case "tcp":
fn = getExTCPTable fn = getExTCPTable
class = tcpTablePidConn class = tcpTablePidConn
case Network_UDP: case "udp":
fn = getExUDPTable fn = getExUDPTable
class = udpTablePid class = udpTablePid
default: default:
panic("Unsupported network type for process lookup.") panic("Unsupported network type for process lookup.")
} }
ip := dest.Address.IP() ip := net.ParseIP(srcIP)
port := int(dest.Port) port := int(srcPort)
addr, ok := netip.AddrFromSlice(ip) addr, ok := netip.AddrFromSlice(ip)
if !ok { if !ok {
@@ -101,7 +98,15 @@ func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, e
return 0, "", "", err return 0, "", "", err
} }
s := newSearcher(dest.Network, dest.Address.Family()) networkType := Network_TCP
if network == "udp" {
networkType = Network_UDP
}
familyType := AddressFamilyIPv4
if addr.Is6() {
familyType = AddressFamilyIPv6
}
s := newSearcher(networkType, familyType)
pid, err := s.Search(buf, addr, uint16(port)) pid, err := s.Search(buf, addr, uint16(port))
if err != nil { if err != nil {