用 Firewalld + systemd.slice + redir 實現 TCP + UDP 透明代理
现在网上已经有不少用 iptables 或 nftables 实现透明代理(Tproxy)的例子了。绝大多数关于透明代理的教程都是通过 iptables 实现的,也有少量使用新一代的 nftables 内核防火墙前端来实现。然而,消费级电脑上通常会装有更简化的防火墙程序,例如 Fedora/CentOS/SUSE 自带的 Firewalld,或 Ubuntu 的 UFW。在用这些简化前端的同时,直接操作 nftables 和 iptables 的话可能会造成冲突,更好的解法是全部工作都由 firewalld/ufw 来做。
本文就以 firewalld 为例,用它的 direct rules 来实现透明代理(没错,firewalld 并不提供关于透明代理的抽象,所以并不比 iptables 有优势)。
想要实现的效果
- TCP 和 UDP 流量自动转给 Clash(或 shadowsocks 等)
- Clash 本身不会把流量转发给自己
- 可以让某些 程序 不转发给 clash,直接联网
Get started
先来设置变量,指向 clash 的 redir-port
:
export proxy_port=7892 # 按你 clash 的设置修改
接着设置 firewalld 和 ip route。 Firewalld 的 direct rules 语法几乎等同于 iptables(因为实际上就是调用 iptables 来执行 direct rules)。所以这里直接照抄 systemd.slice + iptables + redir:如何在 Arch Linux 上配置透明代理 的规则,稍有修改:
#tcp sudo firewall-cmd --direct --add-chain ipv4 nat clash sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -m cgroup --path "clash.slice" -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 0.0.0.0/8 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 10.0.0.0/8 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 127.0.0.0/8 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 169.254.0.0/16 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 172.16.0.0/12 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 192.168.0.0/16 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 224.0.0.0/4 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -d 240.0.0.0/4 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 nat clash 2 -p tcp -j REDIRECT --to-port "$proxy_port" sudo firewall-cmd --direct --add-rule ipv4 nat OUTPUT 1 -p tcp -j clash #udp sudo ip rule add fwmark 1 table 100 sudo ip route add local default dev lo table 100 sudo firewall-cmd --direct --add-chain ipv4 mangle clash sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -m cgroup --path "clash.slice" -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 0.0.0.0/8 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 10.0.0.0/8 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 127.0.0.0/8 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 169.254.0.0/16 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 172.16.0.0/12 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 192.168.0.0/16 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 224.0.0.0/4 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 1 -d 240.0.0.0/4 -j RETURN sudo firewall-cmd --direct --add-rule ipv4 mangle clash 2 -p udp -j TPROXY --on-port "$proxy_port" --tproxy-mark 1 sudo firewall-cmd --direct --add-rule ipv4 mangle OUTPUT 0 -p udp -j clash # 这里可能有错(`failed: iptables-restore: line 3 failed`),欢迎指正 sudo firewall-cmd --direct --add-chain ipv4 nat CLASH_DNS sudo firewall-cmd --direct --remove-rules ipv4 nat CLASH_DNS sudo firewall-cmd --direct --add-rule ipv4 nat CLASH_DNS 1 -p udp -j REDIRECT --to-port 1053 sudo firewall-cmd --direct --add-rule ipv4 nat OUTPUT 0 -p udp --dport 53 -j CLASH_DNS
其中,sudo firewall-cmd --direct --add-rule ipv4 nat clash 1 -m cgroup --path "clash.slice" -j RETURN
将放到 clash.slice
下的 service 给绕过 clash 了。
Clash 要以 systemd unit 的形式 来运行。为了让 clash 不把自己的流量循环转回给自己,给它的 unit 分配给 clash.slice
。
[Service] Slice=clash.slice
其它不想走 clash 的程序也可以以类似方式分配给 clash.slice。
Like my work? Don't forget to support and clap, let me know that you are with me on the road of creation. Keep this enthusiasm together!
- Author
- More