Files
pyxray/docs/transparent-iptables.md
2026-05-27 15:51:28 +08:00

8.7 KiB
Raw Permalink Blame History

透明代理 iptables 规则说明

本文说明 transparent.type = "redirect" 时,pyxray 当前会生成哪些 iptables 规则、这些规则是什么意思,以及如何查看宿主机当前是否生效。

当前配置

当前 data/settings.toml 中透明代理相关配置类似:

[transparent]
mode = "pac"
type = "redirect"
port = 52345
docker_transparent = true
docker_transparent_cidrs = "172.16.0.0/12"
output_bypass_rules = "all 117.72.47.28"

含义:

配置 含义
mode = "pac" 透明代理流量进入 Xray 后,复用 [routing].mode 的分流策略。
type = "redirect" 使用 iptables nat 表的 REDIRECT,主要处理 TCP 流量。
port = 52345 被拦截的 TCP 流量会转发到本机 Xray transparent inbound 端口。
docker_transparent = true 额外处理来自 Docker 网段的容器流量。
docker_transparent_cidrs = "172.16.0.0/12" 只有源地址在该 CIDR 内的 Docker 容器流量会进入 PREROUTING 透明代理规则。
output_bypass_rules = "all 117.72.47.28" 宿主机本机访问 117.72.47.28 时直接放行,不进入透明代理。redirect 下实际只生成 TCP 绕过规则。

生成文件

透明代理规则文件生成在:

data/transparent/

常用文件:

文件 作用
transparent-iptables-setup.sh 安装 iptables 规则。
transparent-iptables-cleanup.sh 清理 iptables 规则。
transparent-nft-setup.sh nftables 后端安装脚本。
transparent-nft-cleanup.sh nftables 后端清理脚本。
v2raya.nft nftables 后端规则表。
ip-forward-apply.sh /proc/sys/net/ipv4/ip_forward 和 IPv6 forwarding。
resolv-hijack-setup.sh DNS 劫持时改写 /etc/resolv.conf
resolv-hijack-cleanup.sh 停止或回滚时恢复 /etc/resolv.conf

直接查看生成的 iptables 脚本:

sed -n '1,220p' data/transparent/transparent-iptables-setup.sh
sed -n '1,220p' data/transparent/transparent-iptables-cleanup.sh

如果在 Docker 宿主机上查看挂载目录:

sed -n '1,220p' ./data/transparent/transparent-iptables-setup.sh

当前会生成的 redirect 规则

当前 redirect 模式使用 nat 表,并创建 3 条自定义链:

作用
TP_OUT 处理宿主机本机进程发起的 TCP 流量,也就是 OUTPUT 流量。
TP_PRE 处理进入宿主机的 TCP 流量,也就是 PREROUTING 流量;主要用于 Docker 容器或其它转发流量。
TP_RULE 统一判断哪些目标直连,哪些目标重定向到 Xray。

核心结构:

iptables -t nat -N TP_OUT
iptables -t nat -N TP_PRE
iptables -t nat -N TP_RULE

iptables -t nat -I OUTPUT -p tcp -j TP_OUT
iptables -t nat -I PREROUTING -p tcp -j TP_PRE

iptables -t nat -A TP_PRE -s 172.16.0.0/12 -j TP_RULE
iptables -t nat -A TP_OUT -j TP_RULE
iptables -t nat -A TP_RULE -p tcp -j REDIRECT --to-ports 52345

执行路径:

流量来源 路径
宿主机本机进程访问外部 TCP nat OUTPUT -> TP_OUT -> TP_RULE -> REDIRECT :52345
Docker 容器访问外部 TCP,源地址匹配 172.16.0.0/12 nat PREROUTING -> TP_PRE -> TP_RULE -> REDIRECT :52345
Docker 容器源地址不匹配 docker_transparent_cidrs 进入 TP_PRE 后不会跳到 TP_RULE,不会被 pyxray redirect。
访问保留地址、内网地址、本机接口地址、绕过目标 TP_RULERETURN,不进入 Xray。

TP_RULE 里的 RETURN 是什么意思

TP_RULE 前半段是一批 RETURN 规则,用来避免把不该代理的流量送进 Xray。

常见规则:

iptables -t nat -A TP_RULE -d 10.0.0.0/8 -j RETURN
iptables -t nat -A TP_RULE -d 127.0.0.0/8 -j RETURN
iptables -t nat -A TP_RULE -d 172.16.0.0/12 -j RETURN
iptables -t nat -A TP_RULE -d 192.168.0.0/16 -j RETURN
iptables -t nat -A TP_RULE -m mark --mark 0x80/0x80 -j RETURN
iptables -t nat -A TP_RULE -i wg+ -j RETURN
iptables -t nat -A TP_RULE -i ppp+ -j RETURN

含义:

规则 含义
-d 10.0.0.0/8 -j RETURN 访问私有网段时直连。
-d 127.0.0.0/8 -j RETURN 访问本机回环地址时直连,避免回环。
-d 172.16.0.0/12 -j RETURN 访问 Docker 或内网私有地址时直连。
-d 192.168.0.0/16 -j RETURN 访问局域网地址时直连。
-m mark --mark 0x80/0x80 -j RETURN 已打过特定标记的流量跳过,避免重复处理。
-i wg+ -j RETURN 从 WireGuard 之类接口进入的流量跳过。
-i ppp+ -j RETURN 从 PPP 之类接口进入的流量跳过。

pyxray 还会把宿主机当前 IPv4 地址所在 CIDR 加入 RETURN

ip -o -4 addr show | awk '{print $4}'

这部分用于避免访问宿主机本机地址或本地接口地址时被透明代理截获。

output_bypass_rules 生成的规则

当前配置:

output_bypass_rules = "all 117.72.47.28"

redirect 模式只处理 TCP,所以会生成:

iptables -t nat -A TP_OUT -p tcp -d 117.72.47.28 -j RETURN

它的位置在 TP_OUT -> TP_RULE 之前,含义是:

宿主机本机进程访问 117.72.47.28 的 TCP 流量直接 RETURN,不进入 TP_RULE,也不会 REDIRECT 到 52345。

这个规则只影响宿主机本机 OUTPUT 流量,不影响 Docker 容器从 PREROUTING 进入的流量。

如何查看当前生效状态

宿主机直接查看:

sudo iptables -t nat -S
sudo iptables -t nat -L -n -v
sudo iptables-save -t nat

只看 pyxray 透明代理相关链:

sudo iptables -t nat -S TP_OUT
sudo iptables -t nat -S TP_PRE
sudo iptables -t nat -S TP_RULE

在容器里查看:

docker exec -it pyxray iptables -t nat -S
docker exec -it pyxray iptables -t nat -S TP_OUT
docker exec -it pyxray iptables -t nat -S TP_PRE
docker exec -it pyxray iptables -t nat -S TP_RULE

当前 compose.yaml 使用:

network_mode: host
privileged: true

因此容器里执行的 iptables 作用在宿主机网络命名空间。正常情况下,宿主机和容器里看到的是同一套规则。

看不到规则时怎么判断原因

先确认 pyxray 是否还在运行:

docker ps | grep pyxray
docker logs pyxray --tail 80

查看 pyxray 自己的透明代理执行日志:

grep 'pyxray transparent' data/xray.log | tail -80

如果看到类似:

setup transparent iptables: /bin/sh data/transparent/transparent-iptables-setup.sh

说明启动时使用了 iptables 后端。

如果最后看到的是:

cleanup transparent iptables: /bin/sh data/transparent/transparent-iptables-cleanup.sh

说明停止或回滚时已经清理过规则,宿主机上可能就看不到 TP_OUTTP_PRETP_RULE

如果容器里能看到、宿主机看不到,检查 iptables 前端是否一致:

sudo iptables --version
docker exec pyxray iptables --version

sudo iptables-nft -t nat -S
sudo iptables-legacy -t nat -S
sudo nft list ruleset

有些系统同时存在 iptables-nftiptables-legacy。如果宿主机默认命令和容器里的命令使用不同后端,看到的规则可能不一致。

如何判断流量是否命中规则

查看计数器:

sudo iptables -t nat -L TP_OUT -n -v
sudo iptables -t nat -L TP_PRE -n -v
sudo iptables -t nat -L TP_RULE -n -v

关注字段:

字段 含义
pkts 命中该规则的数据包数量。
bytes 命中该规则的字节数。
REDIRECT tcp -- anywhere anywhere redir ports 52345 命中后会被转发到 Xray transparent inbound。
RETURN 命中后从当前自定义链返回,不继续走 pyxray 后续规则。

测试前可以清零计数器:

sudo iptables -t nat -Z TP_OUT
sudo iptables -t nat -Z TP_PRE
sudo iptables -t nat -Z TP_RULE

然后从宿主机发起一个 TCP 访问,再查看计数器是否增加。

清理规则

正常停止 pyxray 时会执行:

data/transparent/transparent-iptables-cleanup.sh

手动清理:

sudo sh data/transparent/transparent-iptables-cleanup.sh

容器里手动清理:

docker exec -it pyxray sh /config/transparent/transparent-iptables-cleanup.sh

清理脚本会删除:

nat OUTPUT -> TP_OUT
nat PREROUTING -> TP_PRE
TP_OUT
TP_PRE
TP_RULE

代码位置

路径 作用
pyxray/libs/xray_config/transparent_rules.py 生成 iptables/nftables 脚本。
pyxray/libs/xray_transparent_runtime.py 启动、停止、回滚时执行脚本。
data/transparent/transparent-iptables-setup.sh 当前配置实际生成出的安装脚本。
data/transparent/transparent-iptables-cleanup.sh 当前配置实际生成出的清理脚本。