Skip to content

Routing: process supports macOS as well#6447

Merged
RPRX merged 4 commits into
XTLS:mainfrom
OneXray:macos-process-rule
Jul 8, 2026
Merged

Routing: process supports macOS as well#6447
RPRX merged 4 commits into
XTLS:mainfrom
OneXray:macos-process-rule

Conversation

@yiguodev

@yiguodev yiguodev commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a Darwin implementation of common/net.FindProcess so routing rules with process can work on macOS.

The implementation uses libproc to inspect process file descriptors and socket endpoints without cgo or external commands. It supports TCP and UDP, returns PID/name/path, and keeps the existing ErrNotLocal / unsupported-network behavior.

Notes

  • Uses proc_pidinfo, proc_pidfdinfo, and proc_pidpath from /usr/lib/libproc.dylib.
  • Adds socket match fallback levels for macOS TUN traffic where the TUN source address or sniffed destination may differ from the socket table endpoint.
  • Verified with a local macOS TUN process-rule config: curl / Chrome helper traffic matched processProxy and routed through the proxy outbound.

Tests

  • go test ./common/net -count=1
  • CGO_ENABLED=0 go test ./common/net -count=1
  • go test ./app/router ./proxy/tun -count=1
  • GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go test -c ./common/net -o /tmp/common_net_darwin_amd64.test
  • GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go test -c ./common/net -o /tmp/common_net_darwin_arm64.test
  • git diff --check

AI Coding by GPT-5.5 Extra High.

Tested on macOS (Only Apple Silicon)

Copilot AI review requested due to automatic review settings July 7, 2026 14:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a macOS (Darwin) implementation of common/net.FindProcess so process-based routing rules can resolve PID/name/path on macOS without cgo or external commands.

Changes:

  • Excludes darwin from the generic “unsupported platform” FindProcess implementation.
  • Introduces a Darwin FindProcess implementation using libproc (proc_pidinfo, proc_pidfdinfo, proc_pidpath) and socket endpoint matching/fallback levels.
  • Adds Darwin-only unit tests and per-arch assembly trampolines (amd64/arm64) to call libproc dynamically.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
common/net/find_process_others.go Updates build tags so Darwin uses its dedicated implementation.
common/net/find_process_darwin.go Implements Darwin process lookup via libproc and socket table matching.
common/net/find_process_darwin_test.go Adds Darwin-only tests for TCP/UDP, non-local, and fallback matching behavior.
common/net/find_process_darwin_arm64.s Adds arm64 trampoline symbols for libproc dynamic imports.
common/net/find_process_darwin_amd64.s Adds amd64 trampoline symbols for libproc dynamic imports.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread common/net/find_process_darwin.go Outdated
Comment thread common/net/find_process_darwin.go
Comment thread common/net/find_process_darwin.go
@RPRX

RPRX commented Jul 7, 2026

Copy link
Copy Markdown
Member

@yiguodev ready 了吗

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Yes

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

那俩 .s 文件貌似内容没区别,需要分成两个文件吗

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Fixed

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

Darwin 就编译这俩架构应该不用加判断吧,话说 go 原生 syscall 没有那些能力吗

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

看起来似乎只是定义了 syscall6 的目标 API,话又说回来了有必要 linkname 吗,目前需要回答这两个问题,你问下 AI

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

已简化为 //go:build darwin

Go 当前 Darwin 目标只有 darwin/amd64darwin/arm64,这里不需要额外按架构判断。

syscall / x/sys/unix 目前没有现成的 proc_pidinfo / proc_pidfdinfo / proc_pidpath 封装。这几个是 libproc.dylib 里的函数,不是普通 syscall number,所以这里沿用 Darwin 下常见的 go:cgo_import_dynamic + trampoline + syscall.syscall6 调用方式;类似的动态导入方式在 x/sys/unix 里也有使用。

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

上面这些就是 AI 直接回的。

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

syscall / x/sys/unix 没有相关封装,且它们也都不允许自定义系统函数目标 API,所以只能 linkname 把内部方法取出来?

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

是的,当前约束下基本只能这样做。

这里要区分两个东西:

  • 公开的 syscall.Syscall6 在 Darwin 上走的是 syscall trap(SVC $0x80),参数里的第一个值是 syscall number,不是任意 C 函数地址。它不能直接拿来调用 libproc.dylib 里的 proc_pidinfo / proc_pidfdinfo / proc_pidpath
  • x/sys/unix 内部用的 syscall.syscall6 是另一条路径,可以调用动态导入的 libSystem/libc 函数地址,但这个方法没有公开,所以 x/sys/unix 自己也是通过 go:linkname 取出来用。

目前 syscall / x/sys/unix 没有 proc_pidinfo 这组封装。如果不使用 cgo、不调用外部命令,实际可选方案就是:

  1. x/sys/unix 补官方封装,然后这里再依赖它;
  2. 自己维护更底层的 per-arch 调用汇编;
  3. 像现在这样使用 go:cgo_import_dynamic + trampoline + syscall.syscall6

这个 PR 选的是第 3 种,和 x/sys/unix 在 Darwin 上调用动态库函数的方式一致,维护成本最低。

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

.s 的必要性倒是没啥异议了,毕竟这是 c 函数而不是 number,需要动态获取 API 内存地址

#5496 (comment) Linux 上的代码我没看,是不是也能用这方法来优化一下

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Linux 这边不是同一类问题。

当前 Linux 实现是:

  1. /proc/net/tcp|tcp6|udp|udp6,通过 local address/port 找 socket inode;
  2. /proc/<pid>/fd,通过 socket:[inode] 反查 PID;
  3. 再读 /proc/<pid>/exe 得到路径。

Darwin 这次用 trampoline 是因为需要调用 libproc.dylib 的 C 函数。Linux 这里主要依赖 procfs,不是缺一个可动态导入的 C API,所以这个方法不能直接迁移过去。

Linux 后续如果要优化,方向应该更像是单独评估 netlink/sock_diag、procfs 扫描缓存或 inode->pid 查找策略,而不是用 Darwin 这套动态导入方案。这个可以单独开 PR 处理,不建议混在这次 macOS 支持里。

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

我的意思是 Linux 上有没有系统函数提供了类似的功能,可以 syscall 调用,就不需要现在这种比较普通的方法了

@yiguodev

yiguodev commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Linux 没有一个等价于 “按 socket tuple 直接返回 PID/进程路径” 的系统调用。

能考虑的内核接口主要是 NETLINK_SOCK_DIAG / inet_diag,它可以比解析 /proc/net/tcp 更结构化地拿到 socket 信息,例如 inode、uid、cookie、local/remote endpoint 等。但它通常仍然不给 owning PID。要从 inode 找到 PID,还是需要看哪个进程的 fd 指向 socket:[inode],也就是继续扫 /proc/<pid>/fd,或者自己维护 inode -> pid 缓存。

所以 Linux 上最多可以优化第一步:

  • 现在:解析 /proc/net/tcp|udp 找 inode;
  • 可选优化:用 sock_diag 找 inode。

但第二步 inode -> PID 仍绕不开 /procSO_PEERCRED 这类接口也不适用,它主要是 Unix domain socket 的 peer credential,不是通用 TCP/UDP 五元组查 owner。

因此 Linux 可以单独研究 sock_diag + /proc fd cache 的优化,但不存在像 macOS proc_pidinfo 这样一次性解决 socket owner 的系统函数。

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

就咋说呢文件只是表象,或许可以调用 Linux 代码里的内部函数而不是公开函数,有空可以研究下优化下

@Fangliding

Copy link
Copy Markdown
Member

这是在和agent聊天吗

@RPRX

RPRX commented Jul 8, 2026

Copy link
Copy Markdown
Member

就是在和 agent 聊天,现阶段的 AI 写代码还有点小问题,不过当文档来用是挺方便的,不用自己去翻文档或代码

@RPRX RPRX changed the title Add macOS process lookup Routing: process supports macOS as well Jul 8, 2026
@RPRX
RPRX merged commit 987290b into XTLS:main Jul 8, 2026
40 checks passed
@yiguodev
yiguodev deleted the macos-process-rule branch July 9, 2026 06:58
@RPRX

RPRX commented Jul 16, 2026

Copy link
Copy Markdown
Member

@Fangliding @yiguodev Linux 上的进程路由似乎有问题 2dust/v2rayN#9715 (comment)

@Fangliding

Copy link
Copy Markdown
Member

tun入站似乎不兼容 之前提过的 代码是对着socks5之类的常规入站写的

@RPRX

RPRX commented Jul 16, 2026

Copy link
Copy Markdown
Member

@Fangliding 我看了下 2dust/v2rayN#9715 (comment) 的日志,来源二元组是有的,可能 Linux 把 TUN 的连接记录放别处了?

@RPRX

RPRX commented Jul 20, 2026

Copy link
Copy Markdown
Member

@yiguodev #6434 (comment)

@autorepobot

Copy link
Copy Markdown

各位好,经过验证 Linux 进程路由还是有问题

Linux 会直接提示Unables to find local process name

Linux

Xray 26.7.11 (Xray, Penetrates Everything.) 50231ea (go1.26.5 linux/arm64)
A unified platform for anti-censorship.
2026/07/21 07:24:56.619257 [Info] infra/conf/serial: Reading config: &{Name:/home/Duhs/.local/share/v2rayN/binConfigs/config.json Format:json}
2026/07/21 07:24:56.997221 [Warning] core: Xray 26.7.11 started
2026/07/21 07:24:57.589095 [Error] app/router: Unables to find local process name: common/net: connection for 127.0.0.1:52250 not found in /proc/net/tcp
2026/07/21 07:24:57.589170 from tcp:127.0.0.1:52250 accepted tcp:www.google.com:443 [socks -> proxy]
2026/07/21 07:25:01.101767 [Error] app/router: Unables to find local process name: common/net: connection for 127.0.0.1:52254 not found in /proc/net/tcp
2026/07/21 07:25:01.101883 from tcp:127.0.0.1:52254 accepted tcp:www.google.com:443 [socks -> proxy]

macOS会提示Unables to find local process name,之后日志正常,但实测macOS无法访问Google等被屏蔽的网站

macOS

Xray 26.7.11 (Xray, Penetrates Everything.) 50231ea (go1.26.5 darwin/arm64)
A unified platform for anti-censorship.
2026/07/21 07:32:32.886108 [Info] infra/conf/serial: Reading config: &{Name:/Users/Duhs/Library/Application Support/v2rayN/binConfigs/config.json Format:json}
2026/07/21 07:32:33.321964 [Warning] core: Xray 26.7.11 started
2026/07/21 07:32:33.467676 from tcp:172.18.0.2:49355 accepted tcp:17.57.145.133:5223 [tun >> proxy]
2026/07/21 07:32:33.963594 [Error] app/router: Unables to find local process name: common/net: process not found for tcp connection from 127.0.0.1:49357 to :0
2026/07/21 07:32:33.963629 from tcp:127.0.0.1:49357 accepted tcp:www.google.com:443 [socks -> proxy]
2026/07/21 07:32:34 当前延迟: 44 ms,none
2026/07/21 07:32:39.065710 from udp:172.18.0.2:54122 accepted udp:31.13.92.37:443 [tun -> block]
2026/07/21 07:32:39.170327 from udp:172.18.0.2:57597 accepted udp:185.45.5.35:443 [tun -> block]
2026/07/21 07:32:39.170810 from tcp:172.18.0.2:49359 accepted tcp:31.13.92.37:443 [tun >> proxy]
2026/07/21 07:32:41.177897 from tcp:172.18.0.2:49361 accepted tcp:185.45.5.35:443 [tun >> proxy]
2026/07/21 07:32:41.261557 from tcp:172.18.0.2:49363 accepted tcp:123.6.82.137:443 [tun -> direct]
2026/07/21 07:32:44.289165 from tcp:172.18.0.2:49365 accepted tcp:17.137.162.3:443 [tun >> proxy]
2026/07/21 07:32:45.897410 from udp:172.18.0.2:50739 accepted udp:31.13.92.37:443 [tun -> block]
2026/07/21 07:32:46.002885 from udp:172.18.0.2:65524 accepted udp:185.45.5.35:443 [tun -> block]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants