如果只按项目名称排列代理软件的发展史,很容易得到一条看似合理的路线:
SOCKS → Shadowsocks → V2Ray → Clash → Mihomo / sing-box
但这条线把不同层级的事物混在了一起:Shadowsocks 是代理协议;V2Ray 更接近模块化代理平台;Clash 把规则和策略路由放到了中心;TUNTUNNetwork TUNnel一种在内核网络栈与用户态程序之间传递 IP packet 的虚拟网络接口;与处理以太网帧的 TAP 相对。查看详细解释 → 是操作系统提供的虚拟网络接口;Mihomo 和 sing-box 则逐渐承担起完整的主机流量处理职责。
真正值得追踪的不是“哪个项目取代了哪个项目”,而是代理软件的职责边界如何不断扩大。它最初只帮助应用建立一条代理连接,后来开始接管系统流量、恢复目标身份、参与 DNS、执行规则、选择出口,最终形成一个运行在用户态的网络策略层。
显式代理:应用先决定是否加入
理解后面的变化,最适合从 SOCKS 开始。
1996 年发布的 RFC 1928 把 SOCKS5SOCKS5SOCKS Protocol Version 5一种让客户端通过代理服务器建立 TCP 连接或转发 UDP 数据报的应用层代理协议,由 RFC 1928 定义。查看详细解释 → 描述为位于应用层与传输层之间的“垫片层”。它让 TCP 和 UDP 客户端借助代理服务器穿越网络防火墙,但并不提供 ICMP 转发之类的网络层网关能力。
它的基本路径很短:
Application → SOCKS Client → SOCKS Server → Internet
这里有一个重要前提:应用必须知道代理存在。
浏览器可以配置 SOCKS,支持代理的程序也可以主动连接 SOCKS 服务器;不读取代理设置的游戏、系统服务或其他程序,则不会自动进入这条路径。早期代理解决的是一个相对局部的问题:
应用已经决定走代理之后,代理应该怎样代它建立连接?
系统代理仍然沿用类似的显式协作模型。它部署简单,但覆盖范围取决于应用是否读取并遵守系统设置,通常也无法自然覆盖所有 UDP 和 ICMP 流量。
透明代理:让应用不再感知代理
随着使用场景扩大,人们开始希望应用完全不需要知道代理存在,于是出现了透明接管。
在 Linux 上,经典做法是通过 iptables 或 nftables 匹配流量,再把连接送到本地代理。REDIRECT 可以完成这种重定向,但它依赖 NAT 修改数据包的目标地址。代理收到连接后,还要恢复连接原本要去哪里。
Linux 内核的 TPROXY 文档 特别指出了 REDIRECT 的限制:UDP 下可能无法取得原始目标;TCP 下恢复原始目标也存在竞态。TPROXYTPROXYTransparent ProxyLinux 中不依赖 NAT 改写目标地址的透明代理机制,通常结合 netfilter、packet mark、策略路由和透明 socket 使用。查看详细解释 → 采用了不同路径:
packet
→ socket match / TPROXY rule
→ packet mark
→ policy routing
→ transparent socket
→ local proxy
它不依赖 NAT 改写目标地址,而是结合 packet mark、策略路由和启用了 IP_TRANSPARENT 的 socket,让本来不属于本机的数据包交给本地程序处理。对于 Linux 网关、旁路由和服务器,它至今仍是一种有价值的透明代理入口。
代价也很明显:代理客户端开始深入依赖操作系统网络机制。Linux 有 netfilter 和策略路由,Windows、macOS 及移动系统则各有自己的过滤与 VPN 接口。跨平台客户端如果逐个平台实现透明截获,维护成本会迅速上升。
TUN:把流量入口统一成一张虚拟网卡
TUN 的思路比连接重定向更直接:与其在系统里逐条截获连接,不如给操作系统提供一张虚拟网络接口。
Linux TUN/TAP 文档 将其描述为用户态程序与内核网络栈之间的虚拟设备:TUN 读写 IP packet,TAP 读写 Ethernet frame。内核把原本要送往网卡的数据包交给用户态程序;用户态程序处理后,也可以把数据重新写回虚拟设备。
Application
→ OS TCP/IP stack
→ Routing
→ TUN interface
→ Userspace proxy core
这使浏览器、游戏、命令行程序和大量系统服务不必知道代理存在。Android 和 iOS 上的代理客户端也常借助系统提供的 VPN 类接口获得类似入口。
不过,TUN 只回答了一个问题:
IP 数据包怎样进入用户态代理核心?
它不会自动完成连接重组、DNS 管理、域名恢复、进程识别或出口选择。拿到数据包以后,代理核心仍要把三层流量转换成可以路由的 TCP、UDP 等会话,并补齐作出决策所需的上下文。
sing-box 的客户端说明 把常见入口归纳为 System Proxy、Firewall Redirection 和 Virtual Interface,恰好体现了这种从应用协作、内核截获到虚拟接口的变化。
模块化:协议从“整个客户端”退到一个适配器
流量入口变化的同时,另一条演进也在发生:代理协议与代理核心逐渐分离。
早期工具往往与协议强绑定,一个客户端对应一种协议,一个服务器实现同一种协议。入口、路由逻辑和出口传输被打包在一起。
V2Ray 的核心设计 是这一阶段很有代表性的例子。它把系统拆成应用层、代理层和传输层;代理层又分成相互独立的 Inbound 与 Outbound,由 Dispatcher 和 Router 等模块把两端连接起来。
于是,同一个核心可以表达不同组合:
SOCKS inbound → Router → VMess outbound
HTTP inbound → Router → Shadowsocks outbound
入口与出口不再一一绑定。SOCKS、Shadowsocks、VMess 或其他协议可以只是系统里的一个模块。问题也从“实现哪一种协议的客户端”变成了:
流量从哪里进入,带着什么信息,经过哪些规则,最后应该交给哪个出口?
Clash:核心问题从“怎么传”转向“往哪走”
Clash 对自己的经典定义不是一种新协议,而是 “A rule-based tunnel”。它把 HTTP/SOCKS 入口、多种代理出口、规则匹配、Fake-IP DNS、Proxy Group、健康检查、fallback 和负载均衡放进同一个配置模型。
早期代理的主路径可以简化成:
Connection → Proxy Server
Clash 类核心更接近:
Connection
→ Metadata
→ Rules
→ Policy Group
→ Proxy A / Proxy B / DIRECT / REJECT
这里最重要的抽象不是某一种代理协议,而是策略。规则的结果不一定是某台服务器,也可以是一个会自动测速、故障转移、负载均衡或等待用户选择的策略组代理策略组Proxy Group把多个具体出口组织成一个可被路由规则选择的策略,能够执行手动选择、自动测速、故障转移或负载均衡。查看详细解释 →。
这改变了普通用户理解代理软件的方式。更换 Shadowsocks、VMess、Trojan 或其他出口协议时,规则、DNS 和策略组仍可保持稳定。协议成为出口的一部分,长期留在系统中心的是:
- 流量匹配规则;
- DNS 与域名语义;
- 策略组和出口编排;
- 远程规则或节点提供者;
- 健康检查与故障转移。
因此,Clash 真正有影响力的地方不是简单地“支持更多协议”,而是把代理客户端变成了一台可以配置的流量决策器。
为什么 DNS 和流量识别进入了核心
策略越精细,就越依赖流量的语义信息。
假设应用访问 example.com,普通解析过程会先把域名变成 IP:
example.com → DNS → 1.2.3.4 → TCP connection
连接真正到达代理核心时,它可能只剩下 1.2.3.4:443。但域名规则真正想知道的是:“这个连接最初是不是要访问 example.com?”
Fake-IPFake-IP由代理核心的内置 DNS 分配并维护映射的虚拟 IP,用来在后续连接处理中恢复原始域名。查看详细解释 → 从这个问题出发。内置 DNS 不立即把真实目标 IP 交给应用,而是返回一个由代理核心管理的虚拟地址,并保存虚拟地址与域名之间的映射:
example.com
→ internal DNS
→ fake IP
→ application connects
→ proxy core looks up the mapping
→ example.com
这样,三层流量进入核心时仍然带有可用于域名规则的身份。Clash DNS 文档 对这一映射过程给出了直接说明。
协议嗅探协议嗅探Protocol Sniffing通过解析连接初期可见的协议字段,尝试恢复目标域名或识别上层协议的流量识别方法。查看详细解释 →是另一种恢复信息的手段。核心可以从 TLS、HTTP 或其他协议暴露的字段中尝试识别目标域名。它不是无条件可靠的答案:加密协议演进、ECH、非标准流量和应用行为都可能降低可见性,因此嗅探应被理解为补充信息来源,而不是永远准确的真相。
现代规则还可能使用更多元数据:
domain · destination IP · source IP · process
package · UID · protocol · inbound · network interface
这些字段并非在每个平台、每种入口下都可获得。是否能取得进程、UID 或接口信息,取决于操作系统、权限和核心实现;TUN 本身只提供 IP 数据包,不会凭空附带所有应用身份。
Mihomo 的 DNS 配置 支持 Fake-IP、nameserver-policy 和让 DNS 连接遵守路由规则;其 TUN 配置 又包含自动路由、DNS 劫持、严格路由和出口接口检测。DNS、入口和规则因此不再是三个互不相干的附件,而是同一条决策路径上的组件。
现代核心:主机网络策略运行时
走到今天,再把 Mihomo 或 sing-box 只称作“代理客户端”,已经不足以描述它们的职责。
一个现代核心往往同时包含以下职责:
| 层次 | 典型能力 | 回答的问题 |
|---|---|---|
| 流量获取 | HTTP、SOCKS、REDIRECT、TPROXY、TUN | 流量怎样进入核心? |
| 会话重建 | 用户态 TCP/IP 栈、L3 到 L4 转换 | IP packet 属于哪条连接? |
| 身份恢复 | DNS、Fake-IP、协议嗅探 | 连接原本要访问谁? |
| 规则判断 | 域名、IP、进程、UID、入口、接口 | 这条流量符合什么条件? |
| 策略选择 | 手动选择、测速、fallback、负载均衡 | 应该使用哪个出口? |
| 传输适配 | DIRECT、REJECT、SOCKS、Shadowsocks、VLESS 等 | 最后怎样送达或终止? |
Mihomo 的入口文档 已经把应用代理、透明代理、TUN、端口转发和多类加密协议入口放进同一个核心;sing-box 项目 则直接把自己称为 “The universal proxy platform”,其配置文档覆盖 DNS、路由、规则集、多类入站与出站、网络接口及服务组件。
从系统结构看,它们正在接近一种“主机网络策略运行时”:
接收主机流量,重建流量的身份和上下文,根据规则作出决策,再把流量交给具体出口。
这也说明了两条经常被混淆的发展路线:
- Shadowsocks、VLESS、Trojan、Hysteria 或 TUIC 等协议,主要解决两个网络端点之间怎样传输数据;
- SOCKS、REDIRECT、TPROXY、TUN、DNS、规则和策略组,主要解决主机内部怎样获得、理解和调度流量。
现代代理核心把这两条路线重新汇合:一边接管和理解主机流量,一边把可替换的传输协议作为出口适配器。
TUN 不是“全能模式”
把 TUN 视为统一入口很有帮助,但不能把它等同于“所有流量、所有信息、所有平台行为都自动得到正确处理”。
实际部署仍要面对几类边界:
- 路由边界:流量只有被系统路由送入 TUN,才会进入核心;排除路由、其他 VPN、容器网络和多网卡都可能改变路径。
- DNS 边界:私有 DNS、局域网解析器、应用内置解析和加密 DNS 可能绕开预期的劫持路径。
- 身份边界:IP packet 不天然包含进程名、包名和 UID,这些信息需要平台额外提供。
- 协议边界:嗅探只能识别自己理解且仍暴露相应字段的协议。
- 回环边界:代理核心自己的出站必须避开再次进入 TUN,否则会形成路由环。
- 权限与平台差异:Linux、Windows、macOS、Android 和 iOS 提供的接口与限制并不相同。
因此,现代核心的复杂度并不只是功能堆积。它来自一个更根本的变化:过去分散在应用、系统路由、DNS 解析器和单协议客户端里的职责,如今被集中到了一个可编程的用户态控制层。
结语:从转发连接到调度流量
代理软件最初处理的是一条已经决定走代理的连接。
透明代理让应用不再需要知道代理存在;模块化核心把入口与出口解耦;Clash 类系统让规则、DNS 和策略组成为中心;TUN 又提供了更统一的主机流量入口。
最终形成的系统已经不只是网络转发器,而是一条完整的处理管线:
Traffic acquisition
+ connection reconstruction
+ metadata recovery
+ DNS
+ routing policy
+ health and selection
+ transport adapters
从这个角度看,过去十多年的核心变化可以概括为:
代理程序从“替应用建立连接的工具”,逐渐演变成“运行在主机上的可编程网络策略层”。
这也是为什么今天一份 Mihomo 或 sing-box 配置会远比早期 SOCKS 或单协议客户端复杂:它配置的已经不是一条隧道,而是一套小型网络运行时。
参考资料
- IETF:RFC 1928 — SOCKS Protocol Version 5
- Linux Kernel:Transparent proxy support
- Linux Kernel:Universal TUN/TAP device driver
- Project V:V2Ray 核心设计
- Clash 文档镜像:Clash README
- Clash Core:Clash DNS
- Mihomo:Inbound Configuration
- Mihomo:TUN Configuration
- Mihomo:DNS Configuration
- sing-box:Client modes
- sing-box:Project repository