下面的内容完全是 AI 大模型生成的,与本人毫无关系,本人不对内容负任何责任。

理解篇

Clash 代理逻辑可以分为三部分:

  • 如何获取流量:接管系统代理,其他应用的网络请求可以会被 Clash 接管,或者 TUN 模式直接彻底接管流量
  • 如何分类流量:按照域名或 IP 地址等进行分类处理
  • 如何转发流量:按照代理组的各种策略进行转发,最终流量走向一个具体的物理节点

如何获取流量

首先关注如何获取流量:存在主动和被动两类方式。

先关注被动方式:只要 clash 本身在运行,就一直在监听对应端口,如果使用环境变量或者程序提供的代理选项指向了这个端口,就可以使用 clash 提供的代理。

对于命令行工具,建议通过环境变量设置代理。

然后关注主动方式:在 Windows 上存在 System Proxy 和 Tun mode 两种主动接管流量的方式,对应不同层次的接管逻辑:

  • System Proxy:设置系统 http 代理(指向 clash 目前监听的端口),由应用自愿决定是否使用代理,应用可以选择绕过,对于大部分命令行工具和网络游戏可能不会生效。
  • TUN Mode(虚拟网卡):Clash 创建一个虚拟网卡(TUN),修改系统路由表,强制接管 IP 层流量。(某些游戏加速器也会这么做,因此两者可能会冲突)

这两个模式不是相互冲突的,但是建议只开启其中一个即可,某些 GUI 会让用户只选择其中一个,另一个会被自动关闭。

对于 Linux,通常没有提供与 System Proxy 等效的方式,但是还有一些其他方式(例如 redir-port)。

如何分类和转发流量

然后关注如何分类和转发流量,首先需要理解从机场的订阅链接获得的配置文件:
一个机场必须提供一组分散在各个地区的实际节点,它提供的配置文件包括这些节点的实际信息以及连接方式(密码),还有代理组和规则。

下面依次解释这三个核心概念:

  • 节点(Proxy / Node):节点是最终网络出口
    • 对应一台真实服务器,包含协议、地址、端口、密钥等,不包含任何策略
    • 某个连接的流量最终一定落到某个具体节点(DIRECT 直接连接也会被视作一个 Proxy)
  • 代理组(Proxy Group):策略控制单元,决定流量下一跳的选择
    • 它包括一组候选目标作为流量的下一跳,候选目标可以是某个具体的 Proxy,也可以是其他的 Proxy Group,从而形成一个多层策略树结构
    • 它对于下一跳目标的选择策略通常是固定在配置文件中的,包括如下几种:
      • select:手动选择(运行时由用户在 UI 层面选择,不会写入到配置文件中)
      • load-balance:负载均衡
      • url-test:自动测速选最优
      • fallback:故障转移(按顺序尝试,直到找到可用的)
  • 规则(Rule):流量分类的匹配入口,实质是一个 swich 语句,将特定类型的流量导向一个 Proxy 或者 Proxy Group,或者直接连接,例如
    • 根据目标域名或者 IP 地址进行匹配
      • DOMAIN-SUFFIX,google.com,节点组:如果目标域名是 google.com 的,则使用 节点组 这个 Proxy Group
      • GEOIP,CN,DIRECT:如果目标地址是 CN 的 IP 地址,则使用 DIRECT 也就是直接连接
    • 匹配规则的兜底语句例如 MATCH,其他流量:如果没有匹配的规则,选择 其他流量 这个 Proxy Group

配置文件中的 select 部分提供给用户进行手动选择,通常会在 Clash 的 UI 中体现:

  • 对于策略为 select 的 Proxy Group,可以手动选择一个测试延迟较低的下一跳目标,这种 UI 层面的选择是持续性的,如果不选择,则会使用第一个;
  • 在其他策略的 Proxy Group 中,没有选中其中一个目标的概念,也没有对应的 UI 操作。

整体控制

在配置文件之上,Clash 还有更高层次的整体控制逻辑:

  • 可以在多个订阅之间切换,此时使用对应的配置文件进行处理;(DIRECT 也可能作为一个默认的订阅方案被提供)
  • 可以设置运行模式:
    • 直连(DIRECT):对所有流量不经过任何代理,直接连接
    • 规则(策略模式)(RULE):基于当前选择的订阅所对应的配置文件,使用其中设置的规则和代理组对流量进行分类处理;
    • 全局(GLOBAL):基于当前选择的订阅所对应的配置文件,绕过规则匹配(即不区分流量特征),所有流量都送入当前在 UI 层面选择的一个 Proxy Group 或 Proxy。

Clash 还有一个值得关注的点是 DNS 覆写,如果使用规则模式,建议开启,这会让 Clash 也接管 DNS 查询环节,使得代理操作更安全一点。

网络连接视角

下面从本地应用发起一个网络连接的视角,来理解 Clash 在规则模式下的处理:

  • 第一步,流量是否进入 Clash(接管阶段),包括两种情况:

    • System Proxy:应用愿意用系统代理,则进入 Clash,不愿意则可以绕过
    • TUN 模式:不管应用愿不愿意,流量都进 Clash
  • 第二步,流量怎么分类(规则阶段)

    • Clash 查看 域名 / IP / 端口信息,按配置文件里的 Rule 从上到下匹配,根据匹配结果交给某个 Proxy Group 或者 Proxy。
  • 第三步,流量具体怎么走(代理组阶段)

    • 由 Proxy Group 根据自己的策略决定下一跳:
      • select:用 UI 中用户选的那个,没选过就用第一个
      • url-test / load-balance / fallback:顾名思义,用内置规则来选择下一跳
    • 如果代理组里还是代理组,就一层层往下找,直到找到一个具体的 Proxy,直接连接也视作一个 Proxy。
    • 如果规则阶段直接指定了一个具体的 Proxy,那么代理组阶段就跳过了。
  • 第四步,建立连接并转发

    • Clash 用该节点的信息建立真实连接,数据开始来回转发,这条连接期间一般不会再重新选路。

全局模式相对于规则模式的不同是,忽略规则阶段,全部流量都使用 UI 当前选的一个 Proxy / Proxy Group,如果是 Proxy Group,则继续往下,直到找到一个具体的 Proxy。

在直连模式下,进入 Clash 的流量通常会被统一按 DIRECT 处理,即不经过远端代理节点;规则和代理组选择基本被绕过,但 Clash 仍可能参与接管、DNS 和连接转发过程。

补充:分流代理的危险性

目前绝大多数的代理都采用了国内国外分流代理的策略,但是这种做法存在显而易见的危险。
使用分流代理的方式容易泄露自身的隐私信息,包括但不限于 IP 地址,浏览器以及硬件指纹等等一系列信息,并且可以将代理 IP 与真实 IP 进行身份关联。
一个最常见的例子就是如果某个国外的网站使用了百度统计脚本,此时代理 IP 与真实 IP 的对应关系就可以轻松被这个网站获取。另一个例子就是一些恶意的邮件,比如使用国外的邮箱服务时,接收到了一个恶意邮件,这个邮件中嵌入了一些国内的资源如图片,那么真实 IP 等信息也可以被轻松获取。—— Arch Linux 安装使用教程之魔法学院

可以在 https://www.ip111.cn 测试访问不同网站所使用的 IP。

使用篇

原版 Clash 内核的作者已经删库跑路了,早期的一些基于内核封装的 GUI 软件例如 Clash for Windows,Clash For Android 也已经删库或停止更新。

目前还有一些 fork 或重写的延续性项目仍然在更新,例如 MetaCubeX/mihomo 内核以及基于这个内核封装的 GUI 软件。这里的选择方案是:

在 Windows 和 Android 使用的是可视化软件,因此非常容易,下面只记录一下在 Linux 上直接使用 mihomo 内核的方法。

参考资料:

Linux 使用 mihomo

MetaCubeX/mihomo 下载 Mihomo 内核的预编译包(区分v1/v2/v3,取决于CPU是否支持部分指令以加速优化,通常可以直接选v3),然后放在 ~/.local/bin 中即可

1
2
3
4
wget https://github.com/MetaCubeX/mihomo/releases/download/v1.19.24/mihomo-linux-amd64-v3-v1.19.24.gz

gzip -dc mihomo-linux-amd64-v3-v1.19.24.gz > ~/.local/bin/mihomo
chmod +x ~/.local/bin/mihomo

然后测试一下

1
mihomo -v

Mihomo 的正常运行需要两个文件:

  • 配置文件 config.yaml
  • Country.mmdb 文件,这是一个 IP 地址定位数据库,利用 GeoIP2 服务识别互联网用户的地点位置,以供规则分流时使用,如果在启动时没有找到会尝试自动下载。

将这两个文件准备好,存放在 ~/.config/miholo 目录下。

除了复制已有的配置文件,也可以直接从订阅链接获取,例如使用 wget 命令(注意链接必须用引号包起来)

1
wget -O config.yaml 'http://example.com/shortURL'

使用 curl 命令则必须要加上 -L 选项,否则不会自动跟随重定向

1
curl -L -o config.yaml 'http://example.com/shortURL'

有的订阅链接可能需要在最后加上 &clash 的版本,否则无法正常识别。

在一个会话中手动启动 mihomo

1
miholo

代理并不会被其他程序主动使用,使用代理的方法通常包括:

  • 配置程序支持的相关环境变量,例如 https_proxyhttp_proxyall_proxyno_proxy
  • 使用程序自身提供的代理选项,例如 curl -x socks5h://localhost:7891 www.baidu.com

注意:需要保持 miholo 持续运行,其他程序才能使用代理。

默认情况下,miholo 通常会监听 127.0.0.1 的 7890,7891 端口或合并的 7890 端口(取决于配置文件),可以使用下面的命令检查当前相关端口(789*)的监听情况

1
ss -lntp | grep 789

输出形如

1
LISTEN 0      4096       127.0.0.1:7890       0.0.0.0:*    users:(("mihomo",pid=1196035,fd=3))

这对应配置文件中指定的混合端口

1
2
# HTTP 和 SOCKS5 混合代理端口
mixed-port: 7890

配置文件中还有一种常见的做法是把 HTTP 和 SOCKS5 代理端口分开:

1
2
3
port: 7890
socks-port: 7891
redir-port: 7892

我们需要在后台持续开启 clash,对于 Linux 远程服务器来说,一种简单的做法是 Linux 后台命令,另一种做法是使用 tmux 专门开启一个 session 来运行 clash。

更专业的做法是使用 systemd,下面简单记录一下用户级的 systemd 使用方法。

新建 service 文件 ~/.config/systemd/user/miholo.service,向其中添加内容

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=Mihomo proxy service
After=network-online.target

[Service]
Type=simple
ExecStart=%h/.local/bin/mihomo -d %h/.config/mihomo
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target

重新加载系统服务,启动并配置自动启动

1
2
3
systemctl --user daemon-reload
systemctl --user start mihomo
systemctl --user enable mihomo

检查状态

1
systemctl --user status mihomo

注意:Ubuntu 默认用户级 systemd 服务在用户登出后会自动终止,如果需要让服务持续运行,还需要 root 用户或 sudo 权限进行手动配置

1
sudo loginctl enable-linger SOME_USER

验证

1
loginctl show-user $USER | grep Linger

输出 Linger=yes 表示已启用。

控制 API

Clash 除了支持几个代理端口,还有一个 external-controller,这是 Clash 的控制 API 服务器端口,通常默认为 9090 端口,可以通过这个端口对 Clash 进行操作,包括切换配置,测试节点延迟等(GUI 功能都是对此的封装)。

例如使用如下命令测试节点的延迟

1
curl -s -X GET -H "Authorization: Bearer mypassword" http://127.0.0.1:9090/proxies?test=true > delay.json

对接 clash 的 external-controller,可以使用 yacd 在 web 端进行简单的管理,但是不包括更新链接的功能。
这个功能对 Linux 服务器很有用,使用 ssh 转发 9090 端口到本地,就可以使用 web 端进行管理。但是对 Windows 没什么用,因为 clash verge 等都是更好的 GUI 封装,而且 clash verge 默认把这个功能关闭了。

自定义规则

由于每次更新订阅时都会自动应用所有规则,但是我们有时需要对规则进行自定义的修改,此时就非常不便。Clash Verge 允许用户配置针对 Profile 进行修改的额外脚本,不会被更新覆盖。

例如对一些学术期刊网站不走代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Define main function (script entry)
const prependRule = [
"DOMAIN-SUFFIX,siam.org,DIRECT",
"DOMAIN-SUFFIX,elsevier.com,DIRECT",
"DOMAIN-SUFFIX,sciencedirect.com,DIRECT",
"DOMAIN-SUFFIX,springer.com,DIRECT",
"DOMAIN-SUFFIX,link.springer.com,DIRECT",
"DOMAIN-SUFFIX,doi.org,DIRECT",
];

function main(config, profileName) {
let oldrules = config["rules"];
config["rules"] = prependRule.concat(oldrules);
return config;
}