Real-IP Tun Example
Real-IP 模式的复杂性主要来自于两个方面:
  • 如何使得 Clash Outbound 还能正确的连接互联网
  • 如何使得 DIRECT 出口的流量不要经过 Tun NIC 回到 Clash 造成回环
很显然,不能使用添加 Default 路由到 Tun NIC 的方式使用 Clash Tun 模式。否则 Clash 将无法连接远程代理服务器。
需要注意的是,当 Clash 作为网关工作,如果运行 Clash 的主机本身并不需要通过 Tun 代理,仅仅是转发其他设备的流量,那么上述两个复杂性将不会存在,相应的也会后更简单的配置方法。
本章将以运行 Clash 的 Linux 的主机本身也需要代理的条件下,给出一个使用方法。

解决思路

  • 将 Clash 运行在一个单独的用户下,用以给操作系统一个区分网络流量是否是 Clash 发出的特征。
  • 使用 iptables 在 mangle 表中,将流量打上 fwmark,再由 IP rule 决定将这些有 mark的 流量使用策略路由 (policy route)将流量转发给 Tun NIC。
    • 在 mangle 表 OUTPUT 链中使用 uid-owner 排除 Clash 发出的流量
    • 在 mangle 表 PREROUTING 中,将其他设备发来的流量打上 fwmark

实施方案

假设 clash 运行在 alice 用户下,该用户的 UID 为 129,我们 fwmark 也用 129,clash 策略路由的路由表 id 也为 129。
用户 uid,fwmark ,路由表 id 是三个不相关的值。这里仅仅是为了举例方便都设置成 129.

创建NIC

配置 iptables 和 ip rule 前最好提前配置好 Tun NIC 并 bring up。创建 NIC 的方法可以参考前面的部分
这里假设 Tun NIC 已经提前创建好,名称为 clash0,owner 也为 alice,并且已经被 bring up.

配置 iptables

首先在 mangle 表中创建 CLASH 链,主要用于排除一些局域网地址。如果你会使用 ipset ,可以参考下面被注释的 chnroute 项,排除一些国内地址。
1
iptables -t mangle -N CLASH # 创建 Clash Chain
2
# 排除一些局域网地址
3
iptables -t mangle -A CLASH -d 0.0.0.0/8 -j RETURN
4
iptables -t mangle -A CLASH -d 10.0.0.0/8 -j RETURN
5
iptables -t mangle -A CLASH -d 127.0.0.0/8 -j RETURN
6
iptables -t mangle -A CLASH -d 169.254.0.0/16 -j RETURN
7
iptables -t mangle -A CLASH -d 172.16.0.0/12 -j RETURN
8
iptables -t mangle -A CLASH -d 192.168.0.0/16 -j RETURN
9
iptables -t mangle -A CLASH -d 224.0.0.0/4 -j RETURN
10
iptables -t mangle -A CLASH -d 240.0.0.0/4 -j RETURN
11
# iptables -t mangle -A CLASH -m set --match-set chnroute dst -j RETURN
12
iptables -t mangle -A CLASH -j MARK --set-xmark 129
Copied!
然后在 PREROUTING 链中,给所有转发(forward)流量打上 fwmark。PREROUTING 链的流量来自于其他设备。如果有必要,可以限制高目标端口以防止 BT 流量被转发到 Clash
1
# 限制高目标端口的流量
2
# iptables -t mangle -A PREROUTING -p udp -m udp --dport 4096:65535 -j RETURN
3
# iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 8192:65535 -j RETURN
4
iptables -t mangle -A PREROUTING -j CLASH
Copied!
最后在 OUTPUT 链中,将本机外出流量打上 fwmark。
1
iptables -t mangle -A OUTPUT -m owner --uid-owner 129 -j RETURN
2
# 如果本机有某些不想被代理的应用(如BT),可以将其运行在特定用户下,加以屏蔽
3
# iptables -t mangle -A OUTPUT -m owner --uid-owner xxx -j RETURN
4
iptables -t mangle -A OUTPUT -j CLASH
5
Copied!
下面添加策略路由,使得被打上 fwmark 的流量交由特定路由表(129)处理,并转发到 Clash 监听的 Tun NIC 上。
1
ip route add default dev clash0 table 129
2
ip rule add fwmark 129 lookup 129
Copied!
可以用 ip route验证下策略路由是否生效
1
ip route get 1.1.1.1 mark 129
Copied!
返回应和下面类似,注意加粗的部分。0x81 是 129 的 16进制表示。
1.2.3.4 dev clash0 table 129 src 192.168.31.194 mark 0x81 uid 1000 cache

排除 rp_filter 的故障

这时,如果 clash 已经启动,可以验证下 clash 能否正常工作了。如果不能,可以使用 tcpdump -n -i clash0 抓包诊断下,如果看起来 clash0 端口两个方向的包都有,有可能是 Linux 的 rp_filter 导致了问题。
rp_filter 是 Linux 的安全功能。 rp_filter 会在计算路由决策的时候,计算包的反向路由,也就是将包中的 源地址和目的地址对调再查找路由表。由本机或者其他设备流向 clash0 的 IP Packet一般不会有问题,但是当 rp_filter 检查 clash0 流出的包时,由于这些包不会带有 fwmark,检查反向路由时不会走刚才定义的策略路由,导致 rp_filter 检查失败,包被丢弃。
解决方法时关闭 clash0 NIC 的 rp_filter功能。
1
sysctl -w net.ipv4.conf.clash0.rp_filter=0
2
sysctl -w net.ipv4.conf.all.rp_filter=0
Copied!
all.rp_filter设置为 0 是必须的。
将 all.rp_filter 设置为 0 并不会将所有其他网卡的 rp_filter一并关闭。此时其他网卡的 rp_filter由它们各自的rp_filter控制。
Last modified 1yr ago