Skip to content

Commit 446df14

Browse files
FanglidingRPRX
authored andcommitted
Routing config: Replace processName with process (full-name/abs-path/abs-folder) (#5496)
About `self/` & `xray/`: #5496 (comment) Replaces #5489
1 parent d902585 commit 446df14

File tree

9 files changed

+187
-141
lines changed

9 files changed

+187
-141
lines changed

app/router/condition.go

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package router
33
import (
44
"context"
55
"os"
6+
"path/filepath"
67
"regexp"
8+
"slices"
79
"strings"
810

911
"github.com/xtls/xray-core/common/errors"
@@ -350,7 +352,51 @@ func ParseAttrs(attrs []string) *GeoAttributeList {
350352
}
351353

352354
type ProcessNameMatcher struct {
353-
names []string
355+
ProcessNames []string
356+
AbsPaths []string
357+
Folders []string
358+
MatchXraySelf bool
359+
}
360+
361+
func NewProcessNameMatcher(names []string) *ProcessNameMatcher {
362+
processNames := []string{}
363+
folders := []string{}
364+
absPaths := []string{}
365+
matchXraySelf := false
366+
for _, name := range names {
367+
if name == "self/" {
368+
matchXraySelf = true
369+
continue
370+
}
371+
// replace xray/ with self executable path
372+
if name == "xray/" {
373+
xrayPath, err := os.Executable()
374+
if err != nil {
375+
errors.LogError(context.Background(), "Failed to get xray executable path: ", err)
376+
continue
377+
}
378+
name = xrayPath
379+
}
380+
name := filepath.ToSlash(name)
381+
// /usr/bin/
382+
if strings.HasSuffix(name, "/") {
383+
folders = append(folders, name)
384+
continue
385+
}
386+
// /usr/bin/curl
387+
if strings.Contains(name, "/") {
388+
absPaths = append(absPaths, name)
389+
continue
390+
}
391+
// curl.exe or curl
392+
processNames = append(processNames, strings.TrimSuffix(name, ".exe"))
393+
}
394+
return &ProcessNameMatcher{
395+
ProcessNames: processNames,
396+
AbsPaths: absPaths,
397+
Folders: folders,
398+
MatchXraySelf: matchXraySelf,
399+
}
354400
}
355401

356402
func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
@@ -369,18 +415,26 @@ func (m *ProcessNameMatcher) Apply(ctx routing.Context) bool {
369415
if err != nil {
370416
return false
371417
}
372-
pid, name, err := net.FindProcess(src)
418+
pid, name, absPath, err := net.FindProcess(src)
373419
if err != nil {
374420
if err != net.ErrNotLocal {
375421
errors.LogError(context.Background(), "Unables to find local process name: ", err)
376422
}
377423
return false
378424
}
379-
for _, n := range m.names {
380-
if name == "/self" && pid == os.Getpid() {
425+
if m.MatchXraySelf {
426+
if pid == os.Getpid() {
381427
return true
382428
}
383-
if n == name {
429+
}
430+
if slices.Contains(m.ProcessNames, name) {
431+
return true
432+
}
433+
if slices.Contains(m.AbsPaths, absPath) {
434+
return true
435+
}
436+
for _, f := range m.Folders {
437+
if strings.HasPrefix(absPath, f) {
384438
return true
385439
}
386440
}

app/router/config.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,8 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
126126
conds.Add(matcher)
127127
}
128128

129-
if len(rr.ProcessName) > 0 {
130-
refinedNames := make([]string, 0, len(rr.ProcessName))
131-
for _, name := range rr.ProcessName {
132-
refinedNames = append(refinedNames, strings.TrimSuffix(name, ".exe"))
133-
}
134-
conds.Add(&ProcessNameMatcher{refinedNames})
129+
if len(rr.Process) > 0 {
130+
conds.Add(NewProcessNameMatcher(rr.Process))
135131
}
136132

137133
if conds.Len() == 0 {

app/router/config.pb.go

Lines changed: 66 additions & 66 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/router/config.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ message RoutingRule {
113113
xray.common.net.PortList local_port_list = 18;
114114

115115
xray.common.net.PortList vless_route_list = 20;
116-
repeated string process_name = 21;
116+
repeated string process = 21;
117117
}
118118

119119
message BalancingRule {

common/net/find_process_linux.go

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import (
1313
"github.com/xtls/xray-core/common/errors"
1414
)
1515

16-
func FindProcess(dest Destination) (int, string, error) {
16+
func FindProcess(dest Destination) (PID int, Name string, AbsolutePath string, err error) {
1717
isLocal, err := IsLocal(dest.Address.IP())
1818
if err != nil {
19-
return 0, "", errors.New("failed to determine if address is local: ", err)
19+
return 0, "", "", errors.New("failed to determine if address is local: ", err)
2020
}
2121
if !isLocal {
22-
return 0, "", ErrNotLocal
22+
return 0, "", "", ErrNotLocal
2323
}
2424
if dest.Network != Network_TCP && dest.Network != Network_UDP {
2525
panic("Unsupported network type for process lookup.")
@@ -51,36 +51,39 @@ func FindProcess(dest Destination) (int, string, error) {
5151

5252
targetHexAddr, err := formatLittleEndianString(dest.Address, dest.Port)
5353
if err != nil {
54-
return 0, "", errors.New("failed to format address: ", err)
54+
return 0, "", "", errors.New("failed to format address: ", err)
5555
}
5656

5757
inode, err := findInodeInFile(procFile, targetHexAddr)
5858
if err != nil {
59-
return 0, "", errors.New("could not search in ", procFile).Base(err)
59+
return 0, "", "", errors.New("could not search in ", procFile).Base(err)
6060
}
6161
if inode == "" {
62-
return 0, "", errors.New("connection for ", dest.Address, ":", dest.Port, " not found in ", procFile)
62+
return 0, "", "", errors.New("connection for ", dest.Address, ":", dest.Port, " not found in ", procFile)
6363
}
6464

6565
pidStr, err := findPidByInode(inode)
6666
if err != nil {
67-
return 0, "", errors.New("could not find PID for inode ", inode, ": ", err)
67+
return 0, "", "", errors.New("could not find PID for inode ", inode, ": ", err)
6868
}
6969
if pidStr == "" {
70-
return 0, "", errors.New("no process found for inode ", inode)
70+
return 0, "", "", errors.New("no process found for inode ", inode)
7171
}
7272

73-
procName, err := getProcessName(pidStr)
73+
absPath, err := getAbsPath(pidStr)
7474
if err != nil {
75-
return 0, "", fmt.Errorf("could not get process name for PID %s: %w", pidStr, err)
75+
return 0, "", "", errors.New("could not get process name for PID ", pidStr, ":", err)
7676
}
7777

78+
nameSplit := strings.Split(absPath, "/")
79+
procName := nameSplit[len(nameSplit)-1]
80+
7881
pid, err := strconv.Atoi(pidStr)
7982
if err != nil {
80-
return 0, "", errors.New("failed to parse PID: ", err)
83+
return 0, "", "", errors.New("failed to parse PID: ", err)
8184
}
8285

83-
return pid, procName, nil
86+
return pid, procName, absPath, nil
8487
}
8588

8689
func formatLittleEndianString(addr Address, port Port) (string, error) {
@@ -167,12 +170,7 @@ func findPidByInode(inode string) (string, error) {
167170
return "", nil
168171
}
169172

170-
func getProcessName(pid string) (string, error) {
171-
path := fmt.Sprintf("/proc/%s/comm", pid)
172-
content, err := os.ReadFile(path)
173-
if err != nil {
174-
return "", err
175-
}
176-
// remove trailing \n
177-
return strings.TrimSpace(string(content)), nil
173+
func getAbsPath(pid string) (string, error) {
174+
path := fmt.Sprintf("/proc/%s/exe", pid)
175+
return os.Readlink(path)
178176
}

0 commit comments

Comments
 (0)