Networking

从 SOCKS 到 TUN:代理软件如何演变成网络策略运行时

代理软件的演进并不是一串协议或项目的替代史,而是职责从连接转发、透明接管一路扩展到 DNS、流量识别、规则决策和出口编排的过程。

Networking#SOCKS#TUN#TPROXY#Clash#Mihomo#sing-box

如果只按项目名称排列代理软件的发展史,很容易得到一条看似合理的路线:

SOCKS → Shadowsocks → V2Ray → Clash → Mihomo / sing-box

但这条线把不同层级的事物混在了一起:Shadowsocks 是代理协议;V2Ray 更接近模块化代理平台;Clash 把规则和策略路由放到了中心;TUNTUNNetwork TUNnel一种在内核网络栈与用户态程序之间传递 IP packet 的虚拟网络接口;与处理以太网帧的 TAP 相对。查看详细解释 → 是操作系统提供的虚拟网络接口;Mihomo 和 sing-box 则逐渐承担起完整的主机流量处理职责。

真正值得追踪的不是“哪个项目取代了哪个项目”,而是代理软件的职责边界如何不断扩大。它最初只帮助应用建立一条代理连接,后来开始接管系统流量、恢复目标身份、参与 DNS、执行规则、选择出口,最终形成一个运行在用户态的网络策略层。

代理软件从显式代理、透明接管、模块化核心和策略中心演进到 TUN 网络策略运行时的五阶段示意图
这不是项目更替时间线,而是代理程序职责边界的扩张过程。来源:本站根据公开技术资料重绘

显式代理:应用先决定是否加入

理解后面的变化,最适合从 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 只称作“代理客户端”,已经不足以描述它们的职责。

流量从应用经过 SOCKS、透明代理或 TUN 入口,进入 DNS、嗅探和元数据重建,再由规则策略选择直连、代理、拒绝或代理链出口
现代代理核心把流量获取、上下文重建、规则决策和出口适配组织成一条完整的数据路径。来源:本站根据 Linux、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 视为统一入口很有帮助,但不能把它等同于“所有流量、所有信息、所有平台行为都自动得到正确处理”。

实际部署仍要面对几类边界:

  1. 路由边界:流量只有被系统路由送入 TUN,才会进入核心;排除路由、其他 VPN、容器网络和多网卡都可能改变路径。
  2. DNS 边界:私有 DNS、局域网解析器、应用内置解析和加密 DNS 可能绕开预期的劫持路径。
  3. 身份边界:IP packet 不天然包含进程名、包名和 UID,这些信息需要平台额外提供。
  4. 协议边界:嗅探只能识别自己理解且仍暴露相应字段的协议。
  5. 回环边界:代理核心自己的出站必须避开再次进入 TUN,否则会形成路由环。
  6. 权限与平台差异: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 或单协议客户端复杂:它配置的已经不是一条隧道,而是一套小型网络运行时。

参考资料

文中术语

相关文章