25

使用 clash 和路由表实现透明代理

 2 years ago
source link: https://h-cheung.gitlab.io/post/%E4%BD%BF%E7%94%A8_clash_%E5%92%8C%E8%B7%AF%E7%94%B1%E8%A1%A8%E5%AE%9E%E7%8E%B0%E9%80%8F%E6%98%8E%E4%BB%A3%E7%90%86/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文内容如有错误,请在评论区指出

需要的工具

要进行全局代理,常见的方式是转发到特定端口、使用 tun 虚拟设备和使用 TPROXY。clash 有 redir port 可以直接转发实现代理,但是只支持 TCP,IPv6 的支持也尚未合并。TPROXY 是 v2ray-core 的推荐方式。而另一种方式则是 tun。本文介绍的是使用 tun 的方式

要使用这种方式,首先需要一个使用 tun 转发流量的工具,目前 clash 主线并不支持 tun,clash 作者有一个支持 tun 的闭源版本,另外 comzyh 有一个支持 tun 的分支,性能不错,稳定性一般。然后有一个通用的工具 tun2socks,稳定性较好但性能一般。后两者都不错。

comzyh 的 clash 分支

go-tun2socks

需要的知识

基本的路由表、iptables 操作

设置转发路由

首先需要使用 ip tuntap add <tun name> mode tun user <tun user> 创建一个 tun 设备,并使用 ip link set <tun name> up 启用。

然后设置路由 ip address replace <tun address> dev <tun name>,tun address 取一个不常用的 IP 段,比如 kr328 的脚本中使用 172.31.255.253/30,又比如 go-tun2socks 默认的 10.255.0.1/24。

然后设置路由规则

ip route replace default dev <tun name> table <route table id>
ip rule add fwmark <fwmark id> lookup <route table id>

把有特定 fwmark 标记的流量路由到 tun 其中 fwmark 号和 route 表号可以自行设定(不要和其他的规则重复)。

然后用 iptables 在 mangle 表上,把需要代理的流量打上 fwmark 标记,使用 -j MARK --set-mark <fwmark id> 即可

绕过部分流量

利用 iptables 支持的丰富规则,我们可以灵活地绕过各种流量,列出几个比较常用的:

  • -m owner --uid-owner <username or uid> 匹配某个用户的流量,类似的还有 --gid-owner
  • -p <'tcp', 'udp' or 'icmp'> 匹配某种类型流量
  • --dport <port num> 匹配目的端口,类似的 --sport 匹配源端口,需要和 -p tcp 等连用
  • -d <network name, hostname, subnet(IP CIDR) or IP> 匹配目的网络/主机名/子网/IP
  • -m set --match-set <ipset name> <'dst' or 'src'> 匹配 ipset,可以用于简化规则,ipset 用法自行搜索
  • -m cgroup --cgroup <cgroup id> 匹配 cgroup

有较多规则时可以创建规则链,并把 OUTPUT 或 PREROUTING 链中的流量转入该链(ip6tables 也一样):

iptables -t mangle -N <chain name>
iptables -t mangle -F <chain name>
iptables -t mangle -I OUTPUT -j <chain name>

然后在规则链上编写规则即可,需要打标记走代理就 -j MARK --set-mark <fwmark id>,需要绕过就 -j RETURN,一般建议先写绕过规则,最后无条件地打标记。注意一定要绕过 clash 的流量(建议 uid/gid 或 cgroup)

使用 cgroup net_cls

cgroup 是 Linux 内核的一个功能,这里需要用到它的 net_cls 子系统。使用起来简单,我们首先运行以下命令创建一个组:

mkdir -p /sys/fs/cgroup/net_cls/<cgroup name>
echo <cgroup id> > /sys/fs/cgroup/net_cls/bypass_proxy/net_cls.classid
chmod 666 /sys/fs/cgroup/net_cls/<cgroup name>/tasks

上述命令可以在开机时运行

这样,如果一个进程的 pid 在 /sys/fs/cgroup/net_cls/<cgroup name>/tasks 中,它就会被 iptables 的 -m cgroup --cgroup <cgroup id> 规则匹配到,并且这些进程的子进程 pid 会自动被添加。如果对安全比较敏感,你可以对该文件进行适当的权限控制。

可以使用一个脚本,以它作为 wrapper 来运行需要的命令

#!/bin/bash
echo $$ > /sys/fs/cgroup/net_cls/<cgroup name>/tasks
exec "$@"

单独转发 DNS

与 v2ray 不同,clash 不能通过其规则把流量转到 clash 的内置 DNS,且 clash 不支持 sni 解析域名,需要内置 DNS 反查域名。

因此,需要使用 nat 表把 DNS 流量转发到 clash 的 DNS 端口,对 UDP 53 端口的流量,设置适当的绕过规则过滤后,-j REDIRECT --to-ports <clash dns port> 即可。

tun 工具配置

comzyh 的 clash 分支需要在配置文件中设置以下内容

tun:
  enable: true
  device-url: dev://<tun name>

go-tun2socks 用以下命令启动

tun2socks -tunName <tun name> -proxyServer <clash socks server> -tunAddr <tun address> -tunGw <tun gateway> -tunMask <tun mask> -tunPersist -blockOutsideDns

选一个不常用的 subnet,并取该 subnet 内两个不同地址作为 tun gateway 和 tun address。

比如要使用 172.31.255.253/30 子网。则 tun mask 为 255.255.255.252,tun gateway 可以用 172.31.255.253,tun address 可以用 172.31.255.254,默认参数对应的子网是 10.255.0.1/24


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK