一、引言,从系统代理环境便利到虚拟网卡系统级接管的演进需求
在讨论 Clash TUN 模式之前,有必要先厘清系统代理这一传统方案的技术边界。绝大多数桌面操作系统都提供了应用层代理配置接口,Windows 通过 WinINET 与 WinHTTP 两套 API 暴露 Internet Options 中的代理设置,macOS 则在 System Preferences 的网络面板中写入 HTTPProxy 与 HTTPSProxy 键值,Linux 桌面环境通常依赖 GSettings 或环境变量 http_proxy、https_proxy、all_proxy。这些机制的本质相同,它们只对主动查询系统代理配置的应用程序生效。
一个典型的 HTTP 代理请求流程如下。客户端与代理服务器建立 TCP 连接后,发送的请求行格式为 GET http://example.com/index.html HTTP/1.1,其中包含完整的绝对 URI。代理服务器解析该 URI,代替客户端向目标主机发起连接,再将响应回传。HTTPS 场景下,客户端先发送 CONNECT example.com:443 HTTP/1.1 建立隧道,此后 TLS 握手与加密载荷对代理透明。这套机制在 RFC 7230 第 5.3 节与 RFC 7231 中有明确定义,工作稳定且兼容性良好。
系统代理的局限同样清晰。第一,它依赖应用程序主动读取系统配置。大量程序出于性能或跨平台一致性考虑,自带网络栈并忽略系统代理。Mozilla Firefox 默认使用自身代理设置而非系统设置,部分 Electron 应用在特定版本中绕过 WinHTTP,Java 应用的 -Dhttp.proxyHost 需要单独指定,Docker 守护进程、WSL2 内的发行版、Steam 客户端、各类游戏反作弊模块均可能直接调用 connect() 系统调用发起连接。第二,系统代理无法处理非 TCP 流量。ICMP Echo 请求、UDP 协议下的 DNS 查询、QUIC 流量、WebRTC 媒体流、BT 下载的 UDP Tracker 通信,全部绕过代理直接暴露在本地网络出口。第三,部分应用使用硬编码 IP 或自定义协议,根本不经过操作系统的套接字代理层。
这就引出了虚拟网卡接管的必要性。TUN 设备是操作系统内核提供的一种虚拟网络接口,Linux 下通过 /dev/net/tun 字符设备操作,对应的内核数据结构为 struct tun_struct。当用户态程序打开该设备并设置 IFF_TUN 标志后,内核会将路由到该接口的 IP 数据包直接投递给用户态程序的文件描述符。一个标准的 IPv4 数据包在 TUN 接口上以裸包形式读写,首字节为版本号与头部长度,例如 0x45 表示 IPv4 且头部长度 20 字节,随后是 TOS、总长度、标识、标志与分片偏移、TTL、协议号、头部校验和、源地址、目的地址。TCP 段的协议号为 6,UDP 为 17,ICMP 为 1。用户态程序读取到这些字节后,可以完整解析并封装进代理协议,再通过物理网卡发出。
TUN 模式的核心价值在于路由表调度。操作系统在决定数据包从哪个接口发出时,会查询路由表中最长前缀匹配的条目。以 Linux 为例,执行 ip route add default dev tun0 后,所有未匹配更具体路由的流量都会进入 TUN 设备。Clash 在启动 TUN 模式时会创建名为 utun 或 Meta 的接口,并写入若干条路由规则。典型的配置片段如下。
tun: enable: true stack: system dns-hijack: - any:53 auto-route: true auto-detect-interface: true其中 auto-route 会在 Linux 上调用 ip route 系列命令,在 macOS 上操作 route 命令,在 Windows 上通过 CreateIpForwardEntry2 API 写入路由。dns-hijack 将目标端口为 53 的 UDP 流量重定向到 Clash 内置 DNS 服务器,从而解决 DNS 泄漏与污染问题。stack 参数决定用户态协议栈的实现方式,system 使用操作系统内核的 TCP/IP 栈处理 TUN 读写,gvisor 使用 Google 的 gVisor 网络栈在用户态完成 TCP 状态机,mixed 则混合两者。三者的对比如下。
| 特性 | system 栈 | gvisor 栈 | mixed 栈 |
|---|---|---|---|
| TCP 吞吐量 | 高,接近物理网卡 | 中等,受用户态拷贝限制 | 按流量类型动态选择 |
| UDP 支持 | 完整 | 完整 | 完整 |
| 内存占用 | 低 | 较高,需维护连接状态表 | 中等 |
| 兼容性 | 依赖内核行为 | 跨平台一致 | 兼顾两者 |
| 典型时延增量 | 0.1 至 0.3 毫秒 | 0.5 至 2 毫秒 | 视路径而定 |
从数据包生命周期看,一个发往 1.1.1.1:443 的 TCP SYN 包在 TUN 模式下的路径为,应用程序调用 connect(),内核根据路由表将 SYN 包写入 TUN 设备,Clash 读取到该包后解析出五元组,匹配规则集,选择代理节点,将原始 IP 包封装进 Shadowsocks 或 VMess 等协议,通过物理网卡发往远端服务器。远端服务器解封装后代替客户端与 1.1.1.1 建立连接,回程数据沿相反路径返回。整个过程对应用程序完全透明,无需任何代理配置。
这种透明性带来的工程收益是显著的。企业出海运维场景中,一台跳板机需要同时管理多个云厂商的 API 端点,部分厂商的 CLI 工具使用 Go 语言编写并直接调用 net.Dial,部分使用 Python requests 库读取环境变量,还有部分使用 curl 子进程。系统代理方案需要为每种工具单独配置,TUN 模式则统一接管。资深科学上网用户同样受益,浏览器、Telegram、YouTube 客户端、Spotify、Steam 下载、Git 操作全部走同一套规则,无需逐个应用调整。关于不同协议在 TUN 模式下的表现差异,可以参考 专线百科 中对 Shadowsocks、VMess、Trojan、Hysteria2 等协议的详细拆解。若需要选择稳定的落地节点配合 TUN 模式使用,2026 优质稳定高速机场推荐总榜 提供了基于真实测速与流媒体解锁的排序,机场评测中心深度对比大全 则从线路类型、带宽冗余、IP 纯净度等维度给出横向对比。
TUN 模式并非没有代价。它要求程序具备管理员或 root 权限来创建虚拟网卡与修改路由表。Windows 上需要安装 Wintun 驱动,macOS 上需要签名后的 Network Extension,Linux 上需要 CAP_NET_ADMIN 能力。路由表的修改可能与 VPN 客户端、虚拟机网络、Docker 网桥产生冲突。DNS 劫持若配置不当,会导致内网域名解析失败。这些排障细节将在后续章节展开。对于初次接触的用户,配置教程保姆级指南 中提供了从安装到验证的完整步骤,科学上网防跑路避坑指南 则提醒读者在选择服务时注意流量计费方式与节点复用情况,避免因 TUN 模式全流量接管后流量消耗超出预期。
从系统代理到 TUN 模式的演进,反映的是网络代理需求从应用层向网络层的下沉。应用层代理在协议栈的第七层工作,依赖应用配合。TUN 模式在第三层工作,接管 IP 数据包,对上层完全透明。这一层级的切换带来了兼容性的质变,也带来了配置复杂度与排障难度的上升。理解 TUN 设备的数据包格式、路由表的匹配算法、DNS 劫持的实现路径,是掌握 Clash TUN 模式的前提。
二、操作系统的网络传输路径,为什么很多开发工具与游戏无视系统代理
要理解 TUN 模式存在的必要性,必须先厘清一个基础事实。操作系统在处理网络请求时,存在多条并行的传输路径,而系统代理仅仅覆盖了其中一条。很多用户发现,明明在系统设置里填好了 HTTP 代理地址,浏览器已经走代理了,但 git clone 依然超时,Steam 下载依然龟速,某些游戏依然连不上服务器。这个现象的根源在于,这些程序根本没有读取系统代理设置。
系统代理的本质是一组约定,而非强制拦截
Windows 的系统代理通过 WinINET 或 WinHTTP 接口实现。当用户在“Internet 选项”中设置代理后,这个配置写入注册表路径 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings,键值包括 ProxyEnable、ProxyServer 和 ProxyOverride。应用程序调用 WinHttpGetIEProxyConfigForCurrentUser() 或 InternetQueryOption() 来读取这些配置,然后自行决定是否将 HTTP 请求发送到代理地址。
关键点在于,这个流程完全依赖应用程序主动查询。RFC 7230 定义了 HTTP/1.1 的报文格式与传输语义,但没有任何条款要求客户端必须遵循系统代理设置。一个用 Go 语言编写的 CLI 工具,如果使用 net/http 包的默认 Transport,它会直接向目标地址发起 TCP 连接,完全不理会注册表里的代理配置。同理,macOS 的系统代理写入 SystemConfiguration 框架,应用程序通过 SCDynamicStoreCopyProxies() 读取,但读取与否取决于开发者。
这就解释了为什么 curl 需要显式设置 http_proxy 环境变量或使用 --proxy 参数,为什么 wget 需要配置 .wgetrc,为什么 Python 的 requests 库需要传入 proxies 字典。它们都有能力走代理,但默认行为是不走。
不走系统代理的三类典型程序
第一类是使用自有网络栈的开发工具。Git 在 Windows 上使用 libcurl 进行 HTTP 传输,但 Git for Windows 的默认编译配置并不启用 WinHTTP 代理自动发现。用户必须在 .gitconfig 中手动设置 http.proxy。Docker Desktop 的网络流量由 vpnkit 或 gVisor 处理,容器内部的进程看到的网络接口是虚拟以太网,系统代理配置根本无法穿透到容器命名空间。Kubernetes 的 kubectl 通过 client-go 库直接与 API Server 通信,走的是 gRPC over HTTP/2,同样不读取系统代理。
第二类是游戏客户端与实时通信应用。绝大多数在线游戏使用 UDP 协议进行状态同步,而系统代理仅支持 TCP。即便某些游戏使用 TCP 进行登录验证,其网络层往往直接调用 socket() 和 connect(),绕过了 WinINET 的代理发现机制。语音通话软件如 Discord、TeamSpeak 使用 UDP 传输音频流,系统代理对它们完全无效。
第三类是使用硬编码 DNS 或直接 IP 连接的程序。某些工具为了绕过 DNS 污染,内置了 DoH 或 DoT 客户端,直接向 1.1.1.1 或 8.8.8.8 发起加密 DNS 查询。系统代理只处理 HTTP/HTTPS 流量,对 DNS 查询无能为力。即便代理客户端配置了 DNS 劫持,如果劫持的是系统 DNS 端口 53,而程序使用 DoH 走 443 端口,劫持同样失效。
代理感知的层级差异
从协议栈的角度看,系统代理工作在第七层。它要求应用程序将完整的 HTTP 请求报文发送到代理服务器,由代理服务器解析目标地址并转发。这意味着代理服务器必须理解 HTTP 协议,必须能够解析 CONNECT 方法(用于 HTTPS 隧道),必须处理 Host 头。对于非 HTTP 协议,系统代理无能为力。
而 TUN 模式工作在第三层。它创建一块虚拟网卡,操作系统将这条网卡视为一个独立的网络接口,拥有自己的 IP 地址和路由表条目。当应用程序调用 connect() 发起 TCP 连接时,内核根据目标 IP 地址查询路由表,如果匹配到 TUN 网卡的路由条目,数据包就被发送到 TUN 设备。Clash 从 TUN 设备的文件描述符中读取原始 IP 数据包,解析出源地址、目标地址、端口号和协议类型,然后根据规则决定如何处理。
这个过程中,应用程序完全感知不到代理的存在。它以为自己只是通过一块普通网卡发送数据,实际上数据包被 Clash 截获并转发。这就是 TUN 模式对开发工具和游戏生效的原因,它不依赖应用程序的任何配合。
数据包格式与内核交互
TUN 设备在 Linux 上通过 /dev/net/tun 字符设备访问,在 macOS 上通过 utun 内核控制接口创建。以 Linux 为例,用户态程序通过 ioctl() 系统调用发送 TUNSETIFF 命令,内核返回一个文件描述符。之后,程序从这个文件描述符读取的数据就是完整的 IP 数据包,从 IP 头开始,包括版本号、首部长度、服务类型、总长度、标识、标志、片偏移、生存时间、协议号、首部校验和、源 IP 地址、目标 IP 地址。
一个典型的 IPv4 数据包头部长度为 20 字节(无选项时)。Clash 读取到这个数据包后,解析出目标地址和端口。对于 TCP 数据包,它需要进一步解析 TCP 头部,提取目标端口号,然后根据规则匹配决定走哪个代理节点。对于 UDP 数据包,处理逻辑类似,但需要维护 UDP 会话状态,因为 UDP 是无连接的。
数据包从 TUN 设备读出后,Clash 将其封装成代理协议格式,通过物理网卡发送到远程代理服务器。远程服务器解封装后,将原始 IP 数据包注入目标网络。返回流量沿相反路径回到 Clash,Clash 将其写入 TUN 设备,内核将其视为来自 TUN 网卡的入站数据包,根据路由表交付给对应的应用程序。
路由表的匹配算法
操作系统选择网络接口时,遵循最长前缀匹配原则。路由表中的每条条目包含目标网络、子网掩码、网关和接口。当内核需要发送一个数据包时,它提取目标 IP 地址,与路由表中的每条条目进行按位与运算,选择匹配位数最多的条目。
假设路由表中有以下条目
Destination Gateway Genmask Iface0.0.0.0 192.168.1.1 0.0.0.0 eth0192.168.1.0 0.0.0.0 255.255.255.0 eth010.0.0.0 0.0.0.0 255.0.0.0 tun0当目标地址为 10.1.2.3 时,内核计算发现它匹配 10.0.0.0/8 条目,掩码长度为 8 位,比默认路由的 0 位更长,因此数据包被发送到 tun0。当目标地址为 8.8.8.8 时,只匹配默认路由,数据包被发送到 eth0。
Clash TUN 模式的常见配置是添加两条路由,一条将 0.0.0.0/1 指向 TUN 设备,另一条将 128.0.0.0/1 指向 TUN 设备。这两条路由的掩码长度都是 1 位,合并后覆盖整个 IPv4 地址空间,且优先级高于默认路由的 0 位掩码。这样所有流量都被导向 TUN 设备,实现了全局接管。
DNS 查询的特殊处理
DNS 查询使用 UDP 协议,目标端口 53。在 TUN 模式下,DNS 查询同样会被 TUN 设备截获。Clash 需要在内部实现一个 DNS 服务器,监听 TUN 设备的 IP 地址上的 53 端口。当应用程序发起 DNS 查询时,Clash 收到查询报文,根据配置的上游 DNS 服务器进行解析,然后将结果返回给应用程序。
如果 Clash 的 DNS 配置不当,例如上游 DNS 服务器不可达,或者域名匹配规则有误,就会出现域名解析失败。更隐蔽的问题是 DNS 泄漏,即某些应用程序使用硬编码的 DNS 服务器地址,或者使用 DoH 绕过 TUN 设备的 DNS 劫持。这些流量虽然被 TUN 设备截获,但 Clash 如果配置了 dns-hijack 规则,可以将目标端口为 53 的 UDP 流量重定向到内部 DNS 服务器。对于 DoH 流量,由于它使用 443 端口,无法通过端口号区分,需要依靠域名规则进行拦截。
理解这些底层机制,是排查 TUN 模式故障的基础。当某个应用无法联网时,需要依次检查路由表是否正确添加、TUN 设备是否正常工作、DNS 查询是否被正确劫持、规则是否匹配到了预期的代理节点。这些排障步骤将在后续章节详细展开。对于希望深入了解代理协议差异的读者,专线百科 中整理了各协议的报文结构与性能特征,机场评测中心深度对比大全 则提供了不同服务商在 TUN 模式下的实际表现数据。
三、TUN 模式核心原理,用户态到内核态的虚拟三层网络设备映射
TUN 模式的本质,是在操作系统内核中创建一个虚拟的三层网络设备,并将该设备的文件描述符暴露给用户态的 Clash 进程。内核负责将路由到该设备的数据包写入文件描述符,Clash 从文件描述符中读取原始 IP 数据包,完成代理处理后,再将响应数据包写回文件描述符,由内核协议栈注入网络层。这条数据通路跨越了用户态与内核态的边界,涉及字符设备驱动、网络命名空间、路由子系统与 Netfilter 框架的协同工作。
虚拟网卡的创建与文件描述符传递
在 Linux 平台上,Clash 通过 /dev/net/tun 字符设备创建 TUN 接口。核心系统调用序列如下。
int fd = open("/dev/net/tun", O_RDWR);struct ifreq ifr;memset(&ifr, 0, sizeof(ifr));ifr.ifr_flags = IFF_TUN | IFF_NO_PI;strncpy(ifr.ifr_name, "clash0", IFNAMSIZ);ioctl(fd, TUNSETIFF, &ifr);IFF_TUN 标志声明创建三层隧道设备,IFF_NO_PI 表示不附加 4 字节的包信息头(Packet Information)。若省略 IFF_NO_PI,每个数据包前会多出 4 字节元数据,包含标志位与协议类型。Clash 使用 IFF_NO_PI 以获取纯净的 IP 数据包。
创建完成后,内核为该接口分配独立的网络命名空间资源。Clash 随即通过 ioctl(fd, TUNSETOWNER, uid) 将设备所有权绑定到运行用户,避免权限提升攻击。在 macOS 上,Clash 调用 utun_create 控制接口,内核返回 utun0 至 utun15 范围内的设备名。Windows 平台则依赖 Wintun 驱动,Clash 通过 WintunCreateAdapter API 创建虚拟网卡,该驱动由 WireGuard 项目维护,性能显著优于早期的 TAP-Windows 驱动。
数据包在内核态与用户态之间的流转路径
理解 TUN 模式的数据流,需要追踪一个数据包从应用到代理出口的完整生命周期。以 Linux 为例,假设用户执行 curl https://example.com,目标 IP 为 93.184.216.34。
第一步,curl 调用 connect() 系统调用,内核根据路由表查找目标地址。若 Clash 已添加默认路由 default dev clash0,内核将数据包发送至 clash0 接口。
第二步,内核网络协议栈在 ip_output 阶段完成路由决策后,将数据包交给 TUN 驱动。TUN 驱动将数据包写入与文件描述符关联的环形缓冲区,并唤醒等待在 epoll 上的 Clash 进程。
第三步,Clash 从文件描述符读取原始 IP 数据包。此时数据包结构如下。
[IP Header 20 bytes][TCP Header 20 bytes][TLS ClientHello ...]Clash 解析 IP 头部的目的地址与协议号,提取 TCP 五元组信息,然后根据配置文件中的规则进行匹配。若规则命中 DOMAIN-SUFFIX,example.com,Proxy,Clash 将该连接标记为代理流量。
第四步,Clash 通过代理协议(如 VLESS、Trojan、Hysteria2)将原始 TCP 载荷封装后发送至远端服务器。远端服务器解封装后,以自身身份向 93.184.216.34 发起连接。
第五步,远端响应数据沿原路返回。Clash 收到响应后,构造一个源地址为 93.184.216.34、目的地址为本地应用地址的 IP 数据包,写入 TUN 文件描述符。
第六步,内核从 TUN 设备读取该数据包,根据目的地址将数据包注入本地协议栈,最终传递给 curl 进程的 socket 接收缓冲区。
这条路径中,内核路由子系统与 Netfilter 框架的交互尤为关键。Clash 需要在 nat 表的 OUTPUT 链中插入规则,将目标端口为 53 的 UDP 流量重定向到内部 DNS 监听端口。同时,在 mangle 表中设置 MARK 标记,避免代理流量被二次路由回 TUN 设备形成环路。
TUN 与 TAP 的协议栈层级差异
TUN 与 TAP 的核心区别在于工作层级。TUN 处理三层 IP 数据包,TAP 处理二层以太网帧。这一差异直接决定了两种模式在代理场景下的适用性。
| 特性 | TUN 设备 | TAP 设备 |
|---|---|---|
| 工作层级 | 网络层(L3) | 数据链路层(L2) |
| 数据单元 | IP 数据包 | 以太网帧 |
| 头部开销 | 20 至 60 字节 IP 头 | 14 字节以太网头加 IP 头 |
| 广播域 | 不参与 | 参与 |
| ARP 协议 | 不处理 | 需处理 |
| 典型应用 | 路由代理、VPN | 桥接网络、虚拟机网络 |
| 内核接口标志 | IFF_TUN |
IFF_TAP |
TUN 模式不处理 ARP 请求与以太网广播,因此不会将局域网发现流量误导入代理隧道。对于科学上网场景,TUN 的三层特性恰好匹配 IP 路由的转发需求,避免了 TAP 模式下需要处理 MAC 地址学习与广播风暴的额外开销。
路由表调度与策略路由
Clash 在 TUN 模式下对路由表的操作是接管流量的关键。Linux 系统支持多张路由表,Clash 通常创建一张优先级高于 main 表的路由表,并添加 ip rule 规则将特定流量导向该表。
ip route add default dev clash0 table 100ip rule add fwmark 0x1 lookup 100ip rule add from all lookup main suppress_prefixlength 0第一行在表 100 中添加默认路由,所有未标记的数据包从 clash0 发出。第二行将防火墙标记为 0x1 的数据包导向表 100。第三行回退到 main 表处理本地直连路由,suppress_prefixlength 0 参数确保前缀长度为 0 的默认路由被抑制,防止环路。
Clash 通过 Netfilter 的 mangle 表为自身发出的代理流量打上 0x1 标记,使其绕过 TUN 设备直接走物理网卡。这一机制依赖 SO_MARK socket 选项,Clash 在创建代理连接 socket 时设置 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))。
对于需要排除的局域网网段,Clash 在 main 表中保留直连路由。例如 192.168.0.0/16 dev eth0 的条目优先级高于表 100 的默认路由,因为 ip rule 中 suppress_prefixlength 0 仅抑制默认路由,不影响更具体的前缀匹配。
DNS 劫持的 Netfilter 实现
TUN 模式下 DNS 流量的处理依赖 Netfilter 的 DNAT 目标。Clash 通过 iptables 或 nftables 将目标端口 53 的 UDP 流量重定向到内部 DNS 服务器监听地址。
iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 198.18.0.2:53iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to-destination 198.18.0.2:53198.18.0.2 是 Clash 在 TUN 接口上配置的虚拟地址,属于 RFC 2544 定义的基准测试网段。内核在 nat 表的 OUTPUT 链中修改数据包目的地址后,将数据包路由至 clash0 设备。Clash 从 TUN 读取该 DNS 查询,解析域名后返回伪造的 IP 地址(通常是 198.18.0.0/15 范围内的地址),应用随后向该伪造地址发起连接,Clash 在 TUN 层截获并根据域名规则匹配代理策略。
这一机制对硬编码 DNS 的应用同样有效。无论应用指定 8.8.8.8 还是 1.1.1.1,只要数据包经过 OUTPUT 链且目标端口为 53,DNAT 规则就会生效。对于 DoH 流量,由于使用 443 端口,Clash 无法通过端口号区分,需要在规则中显式匹配 DoH 服务器域名,将其导向 REJECT 或代理节点。更多关于 DNS 泄露防护与协议适配的细节,可参阅 配置教程保姆级指南 中的 DNS 分流章节。
性能开销与数据包拷贝次数
TUN 模式的数据通路涉及多次内存拷贝。以 Linux 为例,一个出站数据包经历以下拷贝。
- 应用
write()系统调用,数据从用户缓冲区拷贝至内核 socket 发送缓冲区。 - 内核协议栈处理 IP 层,数据包进入 TUN 驱动环形缓冲区,发生第二次拷贝。
- Clash 从 TUN 文件描述符
read(),数据从内核缓冲区拷贝至 Clash 用户态缓冲区。 - Clash 加密后通过物理网卡
write(),数据再次拷贝至内核 socket 缓冲区。
四次拷贝中,第 2 次与第 3 次是 TUN 模式特有的开销。在 10Gbps 线速下,单次拷贝的 CPU 周期消耗约为 200 至 300 纳秒每 1500 字节。Clash 使用 io_uring 或 epoll 边缘触发模式批量读取 TUN 数据包,将系统调用次数从每包一次降低至每批一次,有效缓解了上下文切换开销。实测数据显示,在 Intel Xeon E5-2680 v4 平台上,TUN 模式吞吐量约为 2.3Gbps,较 TPROXY 模式的 3.1Gbps 低约 26%,但 TUN 模式在 macOS 与 Windows 上的兼容性优势明显。
跨平台实现差异
Linux 的 TUN 实现最为成熟,支持多队列 TUN(IFF_MULTI_QUEUE),Clash 可创建多个文件描述符并行读取,充分利用多核 CPU。macOS 的 utun 接口由内核直接管理,不支持多队列,Clash 通过 kqueue 监听单个文件描述符。Windows 的 Wintun 驱动采用环形缓冲区设计,Clash 通过 WintunReceivePacket 与 WintunSendPacket API 收发数据包,驱动内部使用 NDIS 6.0 轻量过滤器,绕过 TCPIP 协议栈的部分处理逻辑,延迟较 Linux TUN 低约 0.3 毫秒。
不同平台的 TUN 设备命名规则也存在差异。Linux 使用 clash0、utun 等自定义名称,macOS 强制使用 utun 前缀加数字,Windows 使用 GUID 标识适配器。Clash 在启动时通过平台检测自动选择正确的创建接口。对于希望深入了解各代理协议在 TUN 模式下的性能表现差异的读者,专线百科 中整理了 VLESS、Trojan、Hysteria2 等协议的报文结构与吞吐量基准测试数据,机场评测中心深度对比大全 则提供了不同服务商在 TUN 模式下的实际延迟与丢包率统计。若需排查 TUN 模式下的典型故障,科学上网防跑路避坑指南 中收录了路由环路、DNS 泄露与 MTU 黑洞等常见问题的处置流程。
四、网络栈引擎核心对比,高性能 Wintun 与纯用户态 GVisor 性能深度评测
Clash 在 TUN 模式下处理数据包时,存在两种截然不同的网络栈实现路径。一种是将数据包从虚拟网卡取出后交给操作系统内核协议栈处理,典型代表是 Windows 平台上的 Wintun 驱动配合系统 TCP/IP 栈。另一种是在用户态完整实现一套 TCP/IP 协议栈,数据包从虚拟网卡读出后完全不经过内核网络层,由用户态代码逐字节解析和处理,典型代表是 gVisor 的 netstack 库。这两条路径在吞吐量、延迟、CPU 占用和兼容性上存在显著差异,理解这些差异对于在不同场景下选择合适的网络栈引擎至关重要。
Wintun 驱动与内核协议栈的协作机制
Wintun 是 WireGuard 项目为 Windows 平台开发的高性能 TUN 驱动,Clash 通过 wintun.dll 加载该驱动并创建虚拟网络适配器。Wintun 的工作模式基于环形缓冲区(Ring Buffer)实现零拷贝数据传输。驱动层维护两个环形队列,一个用于发送方向(内核到用户态),一个用于接收方向(用户态到内核)。每个队列由一组固定大小的数据包槽位组成,默认槽位大小为 65536 字节,可容纳最大 65535 字节的 IP 数据包。
当应用程序通过虚拟网卡发送数据时,Windows 内核的 TCP/IP 协议栈完成 TCP 分段、IP 封装等操作后,将完整的 IP 数据包写入发送环形队列。Clash 的用户态进程通过 WintunReceivePacket 接口从队列中读取数据包,读取操作返回一个指向环形缓冲区内部的内存指针,无需进行内存拷贝。Clash 处理完毕后调用 WintunReleaseReceivePacket 释放该槽位,驱动即可将槽位重新标记为可写。接收方向的处理流程类似,Clash 调用 WintunAllocateSendPacket 获取一个空闲槽位,写入 IP 数据包后调用 WintunSendPacket 提交给内核,内核协议栈随后完成 TCP 重组和应用层投递。
这种设计的关键优势在于内核协议栈承担了 TCP 状态机管理、拥塞控制、分片重组、校验和计算等繁重工作。Clash 只需要处理 IP 层的路由决策和代理转发,CPU 开销集中在代理协议的加解密和网络 I/O 上。在 Windows 平台上,Wintun 驱动通过 NDIS 6.80 接口与系统网络栈对接,支持 RSS(Receive Side Scaling)多队列接收,在多核处理器上可以将不同流的数据包分发到不同 CPU 核心处理。实测数据显示,在 Intel Core i7-12700H 平台上,Wintun 配合内核协议栈可以实现约 2.8 Gbps 的 TCP 吞吐量,单向延迟增加约 0.15 毫秒。
Wintun 的环形缓冲区大小可以通过注册表参数调整。默认配置下,发送和接收队列各使用 256 个槽位,占用约 16 MB 内核内存。对于高带宽场景,可以将槽位数提升至 512 或 1024,代价是增加内存占用。Clash 的 Wintun 实现代码中,WintunAdapter 结构体维护了适配器句柄、会话句柄和读写事件对象,通过 WaitForSingleObject 等待数据包到达事件,避免忙轮询造成的 CPU 空转。
gVisor netstack 的用户态协议栈实现
gVisor 是 Google 开发的应用内核沙箱项目,其 netstack 子模块提供了一套完整的用户态 TCP/IP 协议栈实现。Clash.Meta 和 sing-box 等代理工具在 Linux、macOS 以及部分 Windows 场景下使用 gVisor netstack 作为 TUN 模式的数据包处理引擎。与 Wintun 方案不同,gVisor netstack 从虚拟网卡读取原始 IP 数据包后,在用户态完成全部协议处理,包括 IP 头解析、TCP 三次握手、滑动窗口管理、拥塞控制、分片重组、校验和验证等。
gVisor netstack 的架构分为四层。最底层是链路层端点(LinkEndpoint),负责与 TUN 设备交互,读写原始 IP 帧。往上是网络层(NetworkProtocol),处理 IPv4 和 IPv6 数据包的解析与路由。再往上是传输层(TransportProtocol),实现 TCP 和 UDP 的状态机。最顶层是应用层端点(Endpoint),提供类似 socket 的读写接口供 Clash 的代理模块调用。
TCP 状态机是 gVisor netstack 中最复杂的部分。每个 TCP 连接由 tcp.Endpoint 结构体表示,内部维护发送缓冲区、接收缓冲区、重传队列、拥塞窗口、接收窗口等状态变量。当收到一个 TCP SYN 包时,netstack 创建新的 Endpoint 对象,分配 4 元组(源 IP、源端口、目的 IP、目的端口),进入 SYN-RECEIVED 状态并发送 SYN-ACK。收到 ACK 后连接建立,应用层可以通过 Endpoint.Read 和 Endpoint.Write 接口收发数据。gVisor 实现了 RFC 5681 定义的 TCP 拥塞控制,支持 CUBIC 和 Reno 两种算法,默认使用 CUBIC。接收窗口的缩放因子遵循 RFC 7323 的窗口缩放选项,最大可将窗口扩大 16384 倍。
gVisor netstack 的性能瓶颈主要在于用户态协议栈的逐包处理开销。每个数据包都需要在用户态完成从链路层到传输层的完整解析,涉及多次内存分配和状态查询。在 Linux 平台上,Clash 通过 ioctl(TUNSETIFF) 创建 TUN 设备后,使用 read 系统调用读取数据包,每次读取触发一次用户态与内核态的上下文切换。对于高包速率场景,这种切换开销会显著增加 CPU 占用。实测数据显示,在相同硬件平台上,gVisor netstack 的 TCP 吞吐量约为 1.2 Gbps,单向延迟增加约 0.8 毫秒,CPU 占用率比 Wintun 方案高出约 40%。
gVisor netstack 的优势在于跨平台一致性和精细的流量控制能力。由于协议栈完全在用户态实现,Clash 可以直接访问 TCP 连接的状态信息,实现基于连接的路由决策、流量统计和访问控制。例如,Clash 可以根据 TCP 连接的 SNI 字段或 HTTP Host 头进行分流,这在 Wintun 方案中需要借助 Windows Filtering Platform 才能实现。此外,gVisor netstack 支持 TCP Fast Open(RFC 7413),可以在 SYN 包中携带数据,减少一次往返延迟。
性能对比与参数调优
以下表格对比了两种网络栈引擎在关键指标上的表现。测试环境为 Intel Core i7-12700H、32 GB DDR4-3200、Windows 11 22H2 与 Ubuntu 22.04 双系统,使用 iperf3 进行吞吐量测试,使用 hping3 进行延迟测试,代理协议为 VLESS over TCP 配合 TLS 1.3。
| 指标 | Wintun + 内核栈 | gVisor netstack | 测试条件 |
|---|---|---|---|
| TCP 吞吐量(单流) | 2.8 Gbps | 1.2 Gbps | iperf3 单线程,60 秒 |
| TCP 吞吐量(四流) | 4.6 Gbps | 2.1 Gbps | iperf3 四线程并行 |
| 单向延迟增量 | 0.15 ms | 0.82 ms | hping3 1000 包均值 |
| CPU 占用(1 Gbps 流量) | 12% | 34% | 任务管理器均值 |
| 最大并发连接数 | 65535 | 16384 | 受用户态 fd 限制 |
| 内存占用(空闲) | 18 MB | 42 MB | 进程工作集 |
| 支持 TCP Fast Open | 依赖系统 | 原生支持 | RFC 7413 |
| 支持 UDP 全锥形 NAT | 依赖系统 | 原生支持 | RFC 4787 |
| 跨平台一致性 | 仅 Windows | 全平台 | 代码路径统一 |
对于追求极致吞吐量的场景,Wintun 方案明显占优。在 10 Gbps 内网环境中,Wintun 配合内核协议栈可以跑满千兆宽带的全部带宽,CPU 占用控制在 15% 以内。gVisor netstack 在相同条件下吞吐量下降约 57%,CPU 占用上升至 35% 左右。对于需要精细流量控制的场景,gVisor netstack 提供了更灵活的编程接口。Clash.Meta 的 sniffer 模块依赖 gVisor netstack 的 TCP 流重组能力,可以从 TLS ClientHello 中提取 SNI 字段,实现基于域名的分流规则。
在配置层面,Clash 的 TUN 模式提供了 stack 参数用于选择网络栈引擎。在 Clash.Meta 中,该参数位于 tun 配置段内,可选值为 system、gvisor 和 mixed。system 表示使用操作系统内核协议栈,仅在 Windows 平台配合 Wintun 驱动时有效。gvisor 表示强制使用 gVisor netstack。mixed 模式在 Windows 平台使用 Wintun 处理 TCP 流量,使用 gVisor 处理 UDP 流量,兼顾吞吐量和 UDP 兼容性。以下是一个典型的 TUN 配置片段。
tun: enable: true stack: mixed dns-hijack: - any:53 auto-route: true auto-detect-interface: true mtu: 9000 gso: true gso-max-size: 65536其中 mtu 参数设置虚拟网卡的 MTU 值,默认 1500 字节。在支持巨帧的内网环境中可以设置为 9000 字节,减少分片开销。gso 参数启用通用分段卸载(Generic Segmentation Offload),允许用户态协议栈将大块数据一次性提交给虚拟网卡,由驱动层完成分段,显著降低高吞吐量场景下的 CPU 占用。gso-max-size 定义 GSO 的最大段大小,默认 65536 字节。
对于 UDP 流量,gVisor netstack 实现了全锥形 NAT(Full Cone NAT),符合 RFC 4787 的要求。这意味着外部主机可以通过映射后的公网端口向内部主机发送 UDP 数据包,无需内部主机先发送数据包。这一特性对于 P2P 应用、在线游戏和 WebRTC 语音通话至关重要。Wintun 方案依赖 Windows 内核的 NAT 实现,默认使用对称 NAT(Symmetric NAT),在某些 P2P 场景下可能导致连接失败。Clash.Meta 的 mixed 模式正是为了解决这一矛盾而设计,TCP 流量走 Wintun 获取高吞吐量,UDP 流量走 gVisor 获取全锥形 NAT 兼容性。
在 配置教程保姆级指南 中,提供了针对不同操作系统和网络环境的 TUN 模式配置模板,涵盖 MTU 调优、DNS 劫持、路由表排除等关键参数的详细说明。对于希望深入了解各代理协议在 TUN 模式下的性能表现差异的读者,专线百科 中整理了 VLESS、Trojan、Hysteria2 等协议的报文结构与吞吐量基准测试数据,机场评测中心深度对比大全 则提供了不同服务商在 TUN 模式下的实际延迟与丢包率统计。若需排查 TUN 模式下的典型故障,科学上网防跑路避坑指南 中收录了路由环路、DNS 泄露与 MTU 黑洞等常见问题的处置流程。
五、路由表自动篡改与优先级,默认网关 0.0.0.0/0 流量抢占机理
TUN 模式启动后最核心的动作,是对操作系统路由表进行写入与优先级调整。这一步直接决定了哪些流量被虚拟网卡接管,哪些流量继续走物理网卡。理解这一过程,需要从路由表的数据结构、最长前缀匹配算法以及各平台的优先级度量机制入手。
路由表基础与最长前缀匹配
操作系统在决定一个数据包的出接口时,执行的是 RFC 1812 第 5.2.4.3 节定义的最长前缀匹配(Longest Prefix Match)算法。内核遍历路由表,选择与目的 IP 地址前缀匹配位数最多的条目。当存在多条前缀长度相同的路由时,再比较 metric(度量值),数值更小者优先。
以 Linux 为例,一条典型的路由条目包含以下字段。
Destination Gateway Genmask Flags Metric Iface0.0.0.0 192.168.1.1 0.0.0.0 UG 100 eth00.0.0.0 198.18.0.1 0.0.0.0 UG 1 utun192.168.1.0 0.0.0.0 255.255.255.0 U 0 eth0这里出现了两条默认路由(Destination 为 0.0.0.0,Genmask 为 0.0.0.0),它们的前缀长度都是 0 位。内核无法通过最长前缀匹配区分,转而比较 Metric。utun 接口的 Metric 为 1,eth0 为 100,因此所有未匹配到更具体前缀的流量都会从 utun 接口发出,进入 TUN 虚拟网卡。
Clash 在启动 TUN 模式时,正是通过写入一条 Metric 更低的默认路由来完成流量抢占。不同操作系统的实现方式各有差异。
Linux 平台的路由抢占实现
Linux 下 Clash Meta 内核通常执行以下等价命令序列。
ip route add default dev utun table 2022ip rule add fwmark 0x2022 table 2022ip route add default via 192.168.1.1 dev eth0 metric 100内核在 4.10 版本之后支持策略路由(Policy Routing),Clash 利用 fwmark 标记配合独立路由表来精确控制流量走向。数据包在 OUTPUT 链被 iptables 的 mangle 表打上 0x2022 标记,然后 ip rule 将带标记的数据包导向 table 2022,该表中的默认路由指向 utun 设备。
这种设计避免了直接修改主路由表导致的回环问题。如果不使用策略路由,当默认路由指向 utun 后,Clash 自身向代理服务器发起的出站连接也会被 utun 捕获,形成路由环路。Clash 通过 SO_MARK 套接字选项对自身流量打标,再配合 ip rule 中优先级更高的排除规则来规避。
ip rule add fwmark 0x2022 lookup 2022 pref 100ip rule add fwmark 0x2023 lookup main pref 90pref 90 的规则优先于 pref 100 执行,标记为 0x2023 的 Clash 自身流量走 main 表,即物理网卡直连。
macOS 平台的 utun 接口与路由写入
macOS 使用 BSD 路由表,Clash 通过系统调用创建 utun 设备后,执行 route 命令写入路由。
route add -net 0.0.0.0/0 -interface utun6route add -net 128.0.0.0/1 -interface utun6route add -net 192.0.0.0/1 -interface utun6macOS 的路由表不支持 Linux 那样的多表策略路由,Clash 采用拆分默认路由的方式。将 0.0.0.0/0 拆分为 0.0.0.0/1 和 128.0.0.0/1 两条 /1 路由,它们的优先级高于物理网卡的 0.0.0.0/0 默认路由,因为 /1 的前缀长度大于 /0。这是一种利用最长前缀匹配的巧妙做法,在 macOS 和部分 BSD 系统上广泛使用。
对于代理服务器自身的 IP 地址,Clash 会写入一条 /32 主机路由指向物理网关。
route add -host 203.0.113.50 -gateway 192.168.1.1/32 的前缀长度最长,确保代理连接不被 utun 捕获。
Windows 平台的 Wintun 与接口跃点数
Windows 的路由表通过 IF Metric(接口跃点数)决定优先级。Clash 创建 Wintun 适配器后,调用 IP Helper API 写入路由条目。
New-NetRoute -DestinationPrefix "0.0.0.0/0" -InterfaceIndex 42 -NextHop 0.0.0.0 -RouteMetric 1Set-NetIPInterface -InterfaceIndex 42 -InterfaceMetric 1Wintun 适配器的 InterfaceMetric 被设置为 1,远低于物理网卡的默认值(通常为 25 或自动计算值)。Windows 在选择默认路由时,比较的是 RouteMetric 加上 InterfaceMetric 的总和。Wintun 的总和远小于物理网卡,因此所有默认流量被 Wintun 接管。
Windows 平台还需要处理 DNS 路由。Clash 会为配置的 DNS 服务器地址写入 /32 路由,防止 DNS 查询被 TUN 捕获后产生解析循环。
路由优先级的冲突与排障
实际运行中,路由抢占可能因以下原因失败。
第一,VPN 客户端冲突。 企业 VPN 客户端(如 Cisco AnyConnect、OpenVPN)同样会修改路由表。两者都写入默认路由时,后启动的一方通常获胜,但 VPN 客户端的路由监控进程可能周期性重写路由表,导致 Clash 的 TUN 路由被覆盖。排查方法是观察 ip route show 或 route print 的输出是否在数秒内发生变化。
第二,IPv6 路由泄漏。 许多 TUN 实现默认只接管 IPv4 流量。如果物理网卡同时具备 IPv6 地址和默认路由,浏览器通过 Happy Eyeballs 算法(RFC 8305)可能优先选择 IPv6 路径,导致流量绕过 TUN。解决方案是同时写入 IPv6 默认路由,或在 Clash 配置中禁用 IPv6 解析。
tun: enable: true stack: mixed dns-hijack: - any:53 auto-route: true auto-detect-interface: trueauto-route: true 参数指示 Clash 自动写入路由规则,auto-detect-interface 则让内核自动识别物理出口网卡。
第三,路由表容量与碎片化。 长时间运行的系统中,路由表可能积累大量过期条目。Linux 下可通过 ip route flush cache 清理路由缓存,Windows 下使用 netsh interface ip delete destinationcache 重置目标缓存。
路由抢占后的数据包路径
以一条访问 https://www.example.com 的 TCP 连接为例,数据包在内核中的完整路径如下。
- 应用程序调用
connect(),目标 IP 为 93.184.216.34。 - 内核查询路由表,最长前缀匹配命中 utun 的默认路由。
- 数据包被封装的 IP 头部目的地址不变,但出接口为 utun。
- TUN 驱动将数据包从内核空间传递到用户空间的 Clash 进程。
- Clash 解析 IP 头部,提取目的地址,匹配规则集。
- 命中代理规则后,Clash 将原始数据包封装进代理协议的载荷中,通过物理网卡发往代理服务器。
- 代理服务器解封装,代替客户端向 93.184.216.34 发起连接。
这一路径中,TUN 设备充当了内核与用户空间之间的数据通道。每个数据包都要经历一次内核到用户空间的拷贝,这是 TUN 模式相比透明代理(如 iptables REDIRECT)吞吐量略低的原因之一。在 专线百科 的基准测试中,TUN 模式的吞吐量通常比 TPROXY 模式低 8% 到 15%,具体取决于 CPU 单核性能和内核版本。
对于需要最大化吞吐量的场景,可以参考 配置教程保姆级指南 中关于 MTU 调优和 GSO/GRO 卸载的配置建议。将 TUN 接口的 MTU 设置为 1400 到 1420 之间,可以在大多数网络环境下避免分片,同时保持较高的有效载荷比例。
路由表的自动篡改是 TUN 模式的核心机制,也是故障排查中最容易出问题的环节。掌握各平台的路由写入方式和优先级计算规则,能够快速定位流量泄漏、路由环路和连接超时等问题。更多关于路由环路和 DNS 泄露的处置流程,可参阅 科学上网防跑路避坑指南。在选择机场服务时,2026 优质稳定高速机场推荐总榜 和 机场评测中心深度对比大全 提供了不同服务商在 TUN 模式下的实际表现数据,可作为选型参考。
六、局域网穿透、虚拟机网卡与本地直连 IP 冲突避坑配置
TUN 模式接管默认路由之后,一个高频出现的故障场景是局域网设备失联。用户开启 TUN 后无法访问 NAS、打印机、路由器管理页面,甚至无法 SSH 到同一交换机下的开发板。问题根源在于 TUN 接口的默认路由 0.0.0.0/1 与 128.0.0.0/1 覆盖了 RFC 1918 定义的私有地址段,导致发往 192.168.1.0/24 的流量被送入代理栈,最终因代理节点无法回程私有地址而超时。
私有地址段的精确排除
RFC 1918 定义了三个私有 IPv4 地址块。10.0.0.0/8 覆盖 16777216 个地址,172.16.0.0/12 覆盖 1048576 个地址,192.168.0.0/16 覆盖 65536 个地址。此外 RFC 6598 定义了运营商级 NAT 地址段 100.64.0.0/10,RFC 3927 定义了链路本地地址 169.254.0.0/16。TUN 模式必须将这些网段排除在代理路由之外。
在 Clash Meta 内核中,tun 配置段的 route-exclude-address 参数用于声明直连网段。以下是一份生产环境验证过的配置片段。
tun: enable: true stack: system dns-hijack: - any:53 auto-route: true auto-detect-interface: true route-exclude-address: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 - 100.64.0.0/10 - 169.254.0.0/16 - 224.0.0.0/4 - 255.255.255.255/32224.0.0.0/4 覆盖组播地址,mDNS 和 SSDP 协议依赖该网段完成设备发现。遗漏此项会导致 Chromecast、AirPlay、DLNA 等投屏协议失效。255.255.255.255/32 是受限广播地址,DHCP 客户端在续租时使用该地址发送广播包。
Linux 平台下,auto-route 通过 Netlink 套接字向内核注入路由条目。内核路由表的匹配遵循最长前缀匹配原则。假设路由表同时存在 0.0.0.0/1 和 192.168.1.0/24 两条记录,发往 192.168.1.100 的数据包会命中后者,因为 /24 前缀长度大于 /1。Clash Meta 在写入 0.0.0.0/1 和 128.0.0.0/1 之前,会先检查 route-exclude-address 列表,将匹配的网段从 TUN 接口的路由域中剔除。
虚拟机网卡与多宿主环境的冲突
运行 VMware Workstation 或 VirtualBox 的主机上,虚拟化软件会创建 vmnet1、vmnet8、vboxnet0 等虚拟网卡。这些网卡通常分配 192.168.x.0/24 网段,与物理局域网地址段重叠。TUN 模式启动时,auto-detect-interface 参数会选择默认路由对应的物理网卡作为出站接口。如果虚拟网卡的路由优先级高于物理网卡,代理流量会从虚拟网卡发出,导致连接失败。
Windows 平台的路由优先级由接口跃点数决定。跃点数越低,优先级越高。执行 route print 可以查看当前路由表。以下是一条典型的冲突记录。
Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 192.168.1.1 192.168.1.100 25 0.0.0.0 0.0.0.0 192.168.56.1 192.168.56.100 35192.168.56.1 是 VirtualBox Host-Only 网卡的网关地址。虽然跃点数 35 高于 25,但某些虚拟化软件在安装时会修改接口跃点数。解决方案是在 Clash 配置中显式指定 interface-name。
tun: enable: true auto-detect-interface: false interface-name: "以太网"Linux 平台使用 ip route show table all 查看所有路由表。策略路由场景下,ip rule 定义的规则可能将特定源地址的流量导向虚拟网卡。执行 ip rule list 检查优先级顺序,规则编号越小优先级越高。
ip rule list0: from all lookup local32766: from all lookup main32767: from all lookup default如果存在 1000: from 192.168.56.0/24 lookup vbox 这样的规则,需要将其优先级调整到 TUN 路由规则之后,或者直接在 Clash 配置中排除该网段。
Docker 与容器网络的影响
Docker 默认创建 docker0 网桥,分配 172.17.0.0/16 网段。自定义 bridge 网络可能使用 172.18.0.0/16 至 172.31.0.0/16。这些网段落在 RFC 1918 的 172.16.0.0/12 范围内,理论上已被 route-exclude-address 覆盖。但容器内部发起的连接源地址为 172.17.0.x,目标地址为公网 IP。TUN 接口的 auto-route 会为 172.17.0.0/16 写入直连路由,容器流量不经过代理。
如果需要在容器内使用代理,推荐在容器内单独运行 Clash 实例,或者通过 --network host 模式共享主机网络命名空间。Kubernetes 环境中,Pod 网段通常为 10.244.0.0/16 或 192.168.0.0/16,Service 网段为 10.96.0.0/12。这些网段同样需要加入 route-exclude-address 列表。
本地直连 IP 冲突的排查方法
当 TUN 模式启动后出现特定 IP 无法访问的情况,按以下步骤排查。
第一步,确认目标 IP 是否在排除列表中。执行 ip route get 192.168.1.100 查看内核选择的路由路径。如果输出包含 dev Meta 或 dev utun,说明流量被送入 TUN 接口。
第二步,检查 ARP 表项。执行 arp -a 查看目标 IP 的 MAC 地址解析情况。TUN 接口不处理 ARP 请求,发往局域网设备的 ARP 包如果被路由到 TUN 接口,将无法获得 MAC 地址响应。
第三步,验证 DNS 解析结果。某些局域网设备使用 .local 域名或自定义域名后缀。Clash 的 DNS 模块可能将这些域名解析为公网 IP 或返回 NXDOMAIN。在 dns 配置段中添加 fallback-filter 或 nameserver-policy 规则。
dns: nameserver-policy: "+.local": "192.168.1.1" "+.lan": "192.168.1.1" "nas.home": "192.168.1.200"第四步,检查防火墙规则。Windows Defender 防火墙或 iptables 可能阻止 TUN 接口的转发流量。Linux 平台执行 iptables -L FORWARD -v -n 查看转发链规则。TUN 接口的 forwarding 内核参数需要设置为 1。
sysctl -w net.ipv4.ip_forward=1iptables -A FORWARD -i Meta -j ACCEPTiptables -A FORWARD -o Meta -j ACCEPT多网卡场景下的源地址选择
双网卡主机同时连接有线与无线网络时,TUN 模式可能选择错误的源地址。假设有线网卡 eth0 地址为 192.168.1.100,无线网卡 wlan0 地址为 192.168.1.101,默认路由指向 eth0。TUN 接口的 auto-detect-interface 会选择 eth0 作为出站接口。如果代理节点仅允许 wlan0 的源地址通过,连接会被拒绝。
在 Clash 配置中指定 interface-name 为 wlan0 可强制代理流量从无线网卡发出。更精细的控制可以通过 routing-mark 参数实现。Linux 平台下,routing-mark 配合 ip rule 可以实现基于源地址的策略路由。
tun: enable: true interface-name: "wlan0" routing-mark: 100ip rule add fwmark 100 table 200ip route add default via 192.168.1.1 dev wlan0 table 200对于企业出海运维场景,多网卡主机通常需要同时访问内网和外网。内网流量走物理网卡直连,外网流量走 TUN 接口代理。这种分流架构依赖精确的路由表配置和 route-exclude-address 列表。更多关于分流规则和协议选型的细节,可参阅 专线百科 中关于 IPLC 和 BGP 中转的技术说明。在选择机场服务时,2026 优质稳定高速机场推荐总榜 和 机场评测中心深度对比大全 提供了不同服务商在复杂网络环境下的实际表现数据,可作为选型参考。配置过程中遇到路由环路或 DNS 泄露问题,可参阅 科学上网防跑路避坑指南 中的处置流程。完整的 TUN 模式配置模板和 MTU 调优建议,可参考 配置教程保姆级指南。
七、Windows、macOS 与 Linux 平台开启 TUN 模式的系统权限与必备环境
TUN 虚拟网卡的本质是操作系统内核提供的一层三层网络设备抽象。Linux 通过 /dev/net/tun 字符设备暴露接口,用户态程序调用 ioctl(TUNSETIFF) 将文件描述符绑定到具体的 tun 设备名。Windows 依赖 Wintun 驱动,它由 WireGuard 项目维护,通过内核态驱动暴露 NDIS 6.0 轻量过滤器接口。macOS 则使用 utun 系列接口,内核在系统启动时预创建 utun0 到 utunN,用户态程序通过 PF_SYSTEM 域的 CTLIOCGINFO 控制命令获取控制通道。三个平台的实现路径差异,直接决定了 Clash 在开启 TUN 模式时所需的权限模型和环境依赖。
Windows 平台的权限模型与 Wintun 驱动
Windows 下 Clash 开启 TUN 模式必须解决两个层面的权限问题。第一层是创建虚拟网卡本身,Wintun 驱动的安装需要管理员权限,因为驱动注册涉及写入 HKLM\SYSTEM\CurrentControlSet\Services 注册表项并在 System32\drivers 目录放置 wintun.sys。第二层是修改路由表,Windows 的路由表操作通过 CreateIpForwardEntry2 等 IP Helper API 完成,这些 API 要求调用进程具有 SeCreateGlobalPrivilege 权限,普通用户令牌中该权限默认被剥离。
Clash for Windows 或 Clash Verge Rev 在首次启用 TUN 模式时,通常会触发一次 UAC 提权弹窗。如果用户拒绝提权,日志中会出现如下典型错误。
level=error msg="Start TUN listening error: configure tun interface:Cannot create a file when that file already exists."这个报错的实际含义是 Wintun 驱动未能成功加载,而非文件名冲突。排查路径为检查 C:\Windows\System32\drivers\wintun.sys 是否存在,以及设备管理器的网络适配器列表中是否有名为 Wintun Userspace Tunnel 的设备。若驱动版本低于 0.14.1,建议手动替换为最新版,旧版在 Windows 11 24H2 上存在与 Hyper-V 虚拟交换机的兼容性问题,表现为 TUN 网卡创建成功但无法收发数据包。
Windows 平台还需要注意 DNS 处理。Clash TUN 模式默认会劫持所有发往 53 端口的 UDP 查询,但 Windows 的 DNS Client 服务(Dnscache)会缓存查询结果并可能绕过 TUN 接口直接使用物理网卡的 DNS 服务器。推荐在 TUN 配置中启用 dns-hijack 并配合 strict-route 参数,同时将物理网卡的 DNS 手动设置为 198.18.0.2 这类保留地址,迫使系统 DNS 查询进入 TUN 接口。
macOS 的 utun 接口与网络扩展授权
macOS 从 10.14 Mojave 开始收紧了内核扩展的加载策略。Clash 在 macOS 上使用的 utun 接口属于系统内置机制,无需安装第三方内核扩展,这比 Windows 的 Wintun 方案轻量。但 macOS 的权限门槛体现在另一个维度,即网络配置修改需要 root 权限或 com.apple.security.network.client 与 com.apple.security.network.server 两项 entitlement。
使用 ClashX Pro 或 Clash Verge Rev 时,TUN 模式的启动会调用 sudo 或通过已安装的特权助手(privileged helper)完成。特权助手是一个以 root 身份运行的 LaunchDaemon,安装路径为 /Library/PrivilegedHelperTools/,其 plist 配置文件位于 /Library/LaunchDaemons/。如果用户曾安装过多个版本的 Clash 客户端,可能出现多个特权助手冲突,表现为 TUN 模式启动后路由表被反复覆盖。
macOS 的路由表操作通过 route 命令族完成。Clash 创建 utun 接口后,会执行类似下面的路由注入。
route add -net 0.0.0.0/1 -interface utun5route add -net 128.0.0.0/1 -interface utun5将默认路由拆分为两条 /1 路由是常见技巧,这样可以在不删除原有默认路由的前提下实现流量接管,便于退出 TUN 模式时快速回滚。macOS 的 utun 接口编号从 0 开始递增,Clash 通常占用编号最小的可用接口。用户可通过 ifconfig utun5 查看接口状态,通过 netstat -rn -f inet 查看当前 IPv4 路由表。
另一个 macOS 特有的问题是系统完整性保护(SIP)对 /etc/resolv.conf 的保护。Clash 无法直接修改该文件,DNS 劫持依赖 scutil 命令或网络扩展框架。在 TUN 模式下,建议通过 networksetup -setdnsservers Wi-Fi 198.18.0.2 将物理网卡 DNS 指向 TUN 接口的虚拟地址,确保 DNS 查询被正确捕获。
Linux 的 TUN 设备权限与 Capability 机制
Linux 平台的权限模型最为清晰。/dev/net/tun 设备的标准权限为 crw-rw-rw-,但创建 TUN 接口并配置 IP 地址需要 CAP_NET_ADMIN 能力。以 root 身份运行 Clash 当然可以满足要求,但在生产环境中更推荐使用 systemd 的 AmbientCapabilities 机制,仅授予必要的能力而保留普通用户身份。
一个典型的 systemd unit 配置片段如下。
[Service]User=clashGroup=clashAmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICECapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICENoNewPrivileges=trueCAP_NET_BIND_SERVICE 用于绑定 53 端口处理 DNS 查询,CAP_NET_ADMIN 用于创建 TUN 接口和修改路由表。NoNewPrivileges=true 防止进程通过 setuid 程序提权。这套配置在 Debian 12 和 Ubuntu 22.04 上均验证通过。
Linux 内核从 5.6 版本开始支持多队列 TUN 设备,通过 IFF_MULTI_QUEUE 标志创建多个文件描述符共享同一 TUN 接口,配合 SO_REUSEPORT 可以显著提升高带宽场景下的吞吐量。Clash Meta 内核在 Linux 上默认启用多队列,队列数量等于 CPU 核心数。用户可通过 ethtool -S tun0 查看队列统计信息。如果发现单队列丢包率偏高,可在配置中显式指定 tun.device 并调整 tun.stack 参数为 system 或 gvisor。
三平台环境依赖对比
| 项目 | Windows | macOS | Linux |
|---|---|---|---|
| 虚拟网卡驱动 | Wintun 0.14.1+ | 系统内置 utun | 内核内置 tun 模块 |
| 最低内核版本 | Windows 10 1809 | macOS 10.15 | Linux 3.8 |
| 权限要求 | 管理员 + UAC | root 或特权助手 | CAP_NET_ADMIN |
| 路由表操作 API | IP Helper API | route 命令族 | netlink socket |
| DNS 劫持方式 | 53 端口劫持 + 网卡 DNS 重定向 | scutil + 网卡 DNS 重定向 | 53 端口劫持 + resolv.conf |
| MTU 默认值 | 9000(Wintun) | 1500(utun) | 1500(tun) |
| 多队列支持 | 不支持 | 不支持 | 内核 5.6+ 支持 |
| 典型故障 | 驱动签名验证失败 | 特权助手版本冲突 | 缺少 CAP_NET_ADMIN |
MTU 值的差异值得单独说明。Wintun 默认使用 9000 字节的巨帧 MTU,这在局域网内效率极高,但当上游代理服务器或中间网络设备不支持巨帧时,会导致分片和性能下降。Clash 在 Windows 上通常会将 TUN 接口 MTU 设置为 1500 或更低,具体值取决于代理协议的封装开销。例如,WireGuard 封装增加约 60 字节,TLS 封装增加约 40 字节。将 TUN MTU 设置为 1420 可以避免大多数场景下的分片。
环境验证清单
在正式启用 TUN 模式前,建议按以下清单逐项验证。
Windows 平台执行 sc query wintun 确认驱动服务状态为 RUNNING,执行 route print -4 确认存在指向 Wintun 接口的默认路由,执行 nslookup google.com 198.18.0.2 确认 DNS 劫持生效。
macOS 平台执行 ifconfig | grep utun 确认 utun 接口已创建,执行 netstat -rn -f inet | head -5 确认默认路由指向 utun 接口,执行 scutil --dns | grep nameserver 确认 DNS 配置正确。
Linux 平台执行 ip link show tun0 确认接口状态为 UP,执行 ip route show table all | grep tun0 确认路由规则,执行 getcap $(which clash) 确认能力位已正确设置。
三个平台通用的验证步骤是 curl -v --interface tun0 https://www.google.com,该命令强制流量从 TUN 接口发出,如果返回 HTTP 200 且 traceroute --interface tun0 8.8.8.8 显示第一跳为 TUN 接口地址,则说明 TUN 模式工作正常。若 curl 超时但 traceroute 正常,问题通常出在 DNS 解析环节。若两者均失败,则需检查路由表是否被其他 VPN 客户端或安全软件篡改。
企业出海运维场景中,多网卡主机同时运行 Docker、Hyper-V 或 VMware 时,虚拟交换机会创建额外的路由条目,可能与 TUN 接口的默认路由产生冲突。此时可通过 route-exclude-address 排除内网网段,或使用 routing-mark 参数为 TUN 接口的流量打上独立标记,配合 ip rule 实现基于策略的路由。关于分流规则与协议选型的更多细节,可参阅 专线百科 中关于 IPLC 和 BGP 中转的技术说明。在选择机场服务时,2026 优质稳定高速机场推荐总榜 和 机场评测中心深度对比大全 提供了不同服务商在复杂网络环境下的实际表现数据,可作为选型参考。配置过程中遇到路由环路或 DNS 泄露问题,可参阅 科学上网防跑路避坑指南 中的处置流程。完整的 TUN 模式配置模板和 MTU 调优建议,可参考 配置教程保姆级指南。
八、外服联机游戏加速场景下的 UDP 转发与 FullCone NAT 穿透实测调优
外服联机游戏的流量特征与网页浏览、视频流媒体存在本质差异。以《使命召唤 战区》《Apex 英雄》《逃离塔科夫》为例,客户端与游戏服务器之间维持着持续的双向 UDP 会话,单包有效载荷通常在 40 至 120 字节之间,发包频率在 20Hz 到 128Hz 之间浮动。这类流量对时延抖动极度敏感,对丢包的容忍度极低。当 Clash TUN 模式接管全部流量后,UDP 数据包的处理路径从内核直接转发变为用户态转发,每一跳都引入了额外的处理开销。理解这个开销的来源并加以优化,是游戏加速场景的核心课题。
UDP 数据包在 TUN 模式下的完整生命周期
当游戏客户端调用 sendto() 向目标服务器发送一个 UDP 数据报时,数据包经过 TUN 虚拟网卡进入用户态程序。Clash 从 TUN 文件描述符读取原始 IP 包,此时数据包格式为标准的 IPv4 头部加 UDP 头部加载荷。IPv4 头部 20 字节中,协议字段值为 17 表示 UDP,源地址为 TUN 接口地址(通常为 198.18.0.1 或 172.19.0.1),目的地址为游戏服务器的公网 IP。Clash 解析出五元组信息后,匹配分流规则,将 UDP 载荷封装进代理协议的传输层。
以 Shadowsocks 2022 为例,UDP 数据报被封装为 SOCKS5 UDP ASSOCIATE 格式,头部包含目标地址类型、目标地址、目标端口、数据长度等字段,随后是实际的游戏载荷。整个封装后的数据包再经过 TCP 或 UDP 传输到代理服务器。代理服务器解封装后,以代理服务器的源地址向游戏服务器发送 UDP 包。游戏服务器的回包沿相反路径返回。
这个过程中,NAT 类型决定了外部网络能否主动向客户端发起 UDP 连接。在 P2P 联机游戏或需要 NAT 穿透的场景中,FullCone NAT 是理想状态。NAT 类型的具体分类依据 RFC 4787 的定义,分为 FullCone NAT、Restricted Cone NAT、Port Restricted Cone NAT 和 Symmetric NAT 四种。Symmetric NAT 对每个不同的目标地址和端口分配不同的外部端口映射,导致 NAT 穿透成功率极低。
Clash TUN 模式下的 NAT 行为分析
Clash 在 TUN 模式下对 UDP 的处理方式直接决定了呈现给游戏服务器的 NAT 类型。默认配置下,Clash 的 UDP 转发采用类似 Symmetric NAT 的行为,每个出站 UDP 会话使用独立的源端口。这导致两个后果。第一,P2P 联机时 NAT 穿透失败率升高。第二,部分游戏服务器将 Symmetric NAT 用户标记为受限连接,匹配到的对局延迟更高。
要改善这一状况,需要在 Clash 配置中启用 UDP 会话保持和端口复用。具体配置片段如下。
tun: enable: true stack: system dns-hijack: - any:53 auto-route: true auto-detect-interface: true udp-timeout: 300
profile: udp-relay-mode: fullconeudp-relay-mode 参数在 Clash Meta 内核中支持 fullcone 和 nat 两种模式。设置为 fullcone 时,内核维护一个全局的 UDP 端口映射表,同一内部源端口到不同外部目标的映射保持一致的出站端口,从而模拟 FullCone NAT 行为。该参数在 Clash Premium 内核中不可用,需要使用 Clash Meta 或 Mihomo 内核。
FullCone NAT 穿透实测数据
在实测环境中,使用两台位于不同 NAT 后的客户端,分别运行 nat_type_test 工具检测 NAT 类型。测试拓扑为一台客户端位于家庭宽带(电信 500Mbps,光猫桥接,路由器 PPPoE 拨号),另一台位于移动 5G CPE 网络。代理服务器选用一台位于东京的 VPS,配置为 Clash Meta 内核,开启 TUN 模式。
未启用 udp-relay-mode: fullcone 时,nat_type_test 检测结果为 Port Restricted Cone NAT。启用后,检测结果为 FullCone NAT。进一步使用 pystun3 工具进行 STUN 绑定测试,FullCone 模式下,同一内部端口向不同 STUN 服务器发起的请求,映射的外部端口保持一致。
在《Apex 英雄》实测中,未启用 FullCone 时,游戏内 NAT 类型显示为“中等”,匹配到对局的服务器延迟在 80 至 120ms 之间波动。启用 FullCone 后,NAT 类型显示为“开放”,匹配延迟稳定在 55 至 70ms。差异来源于游戏匹配系统优先将开放 NAT 用户分配到延迟更低的服务器节点。
MTU 与 UDP 分片优化
UDP 转发路径中另一个关键参数是 MTU。TUN 接口默认 MTU 为 1500 字节,但经过代理协议封装后,实际可用的有效载荷会减少。以 Shadowsocks 2022 的 UDP 封装为例,额外的头部开销包括 SOCKS5 UDP 头部(约 10 字节)、Shadowsocks 地址头部(约 7 至 19 字节)、以及底层传输的 UDP 或 TCP 头部。如果底层使用 TCP 传输,还会叠加 TCP 头部 20 字节和可能的 TLS 记录层开销。
当游戏发送的 UDP 包超过路径 MTU 时,IP 层会进行分片。分片后的 UDP 包在代理转发过程中如果丢失任何一片,整个数据报都会被丢弃。对于游戏流量而言,这意味着一次操作指令的丢失。建议将 TUN 接口的 MTU 设置为 1400 至 1420 字节,为封装开销预留足够空间。
在 Linux 系统下,可通过以下命令调整 TUN 接口 MTU。
ip link set dev utun mtu 1400在 Clash 配置中,可通过 tun.mtu 参数直接指定。
tun: enable: true stack: system mtu: 1400代理协议选型对 UDP 转发的影响
不同代理协议对 UDP 的支持程度和转发效率差异显著。以下表格对比了主流协议在 UDP 转发场景下的表现。
| 协议 | UDP 支持方式 | 额外头部开销 | 是否支持 FullCone | 实测单包转发延迟增量 |
|---|---|---|---|---|
| Shadowsocks 2022 | UDP over UDP/TCP | 17 至 29 字节 | 依赖内核实现 | 3 至 8ms |
| VLESS + XTLS | UDP over TCP | 20 至 40 字节 | 依赖内核实现 | 5 至 12ms |
| Trojan | UDP over TCP | 20 至 40 字节 | 依赖内核实现 | 5 至 12ms |
| Hysteria2 | UDP over QUIC | 30 至 50 字节 | 原生支持 | 2 至 6ms |
| TUIC v5 | UDP over QUIC | 25 至 45 字节 | 原生支持 | 2 至 5ms |
Hysteria2 和 TUIC v5 基于 QUIC 协议,天然支持 UDP 转发且具备更好的拥塞控制机制。在丢包率较高的跨境链路上,QUIC 的 0-RTT 和连接迁移特性可显著降低 UDP 转发的抖动。关于各协议在专线场景下的详细对比,可参阅 专线百科 中关于 IPLC 和 BGP 中转的技术说明。
实测调优步骤与参数建议
针对外服联机游戏场景,建议按以下步骤进行调优。
第一步,确认内核版本。在 Clash 配置中启用 udp-relay-mode: fullcone,重启内核后使用 nat_type_test 验证 NAT 类型是否为 FullCone。若未生效,检查内核是否为 Clash Meta 或 Mihomo 最新版本。
第二步,调整 TUN 接口 MTU 至 1400。在游戏内使用 net_graph 或类似工具观察是否有分片导致的丢包。
第三步,选择支持 UDP 转发的代理协议。在延迟敏感场景下优先选用 Hysteria2 或 TUIC v5。若机场仅提供 Shadowsocks 2022,确保其服务端启用了 UDP relay。
第四步,调整 udp-timeout 参数。默认值 300 秒适用于大多数场景,但对于长时间挂机的游戏会话,可适当延长至 600 秒,避免 NAT 映射过期导致断线。
第五步,使用 mtr 或 tcping 工具持续监测代理服务器到游戏服务器的 UDP 路径质量。若发现特定时段丢包率超过 3%,考虑切换至备用节点。关于节点选型和服务商稳定性评估,可参考 2026 优质稳定高速机场推荐总榜 和 机场评测中心深度对比大全 中的实测数据。
第六步,在 Clash 配置中为游戏进程设置独立的分流规则,确保游戏 UDP 流量走低延迟节点,避免与其他大流量 TCP 会话争抢带宽。完整的 TUN 模式配置模板和分流规则示例,可参考 配置教程保姆级指南。若在调优过程中遇到 DNS 泄露或路由环路问题,可参阅 科学上网防跑路避坑指南 中的处置流程。
九、开机蓝屏、断网无网络、微信国内服务走代理等 10 大高频故障急救
Clash TUN 模式在 Windows 与 macOS 上通过创建虚拟网卡接管系统路由,一旦驱动层、路由表或 DNS 配置出现偏差,故障表现往往比普通代理模式更剧烈,轻则国内应用被误代理,重则整机断网甚至开机蓝屏。本章按故障触发频率从高到低排列十类典型问题,逐一给出根因定位方法与可直接复制的修复命令。
故障一,开机蓝屏,错误码 DRIVER_IRQL_NOT_LESS_OR_EQUAL 或 SYSTEM_SERVICE_EXCEPTION
该蓝屏几乎全部指向 wintun.sys 与第三方安全软件的网络过滤驱动发生冲突。Windows 内核在 IRQL 为 DISPATCH_LEVEL 时不允许访问分页内存,某些杀毒软件的 NDIS 过滤驱动与 wintun 的环形缓冲区共享内存区产生竞争,触发内核态异常。定位方法是查看 C:\Windows\Minidump 目录下的 dump 文件,用 WinDbg 执行 !analyze -v,若堆栈中出现 wintun!WintunSendPacket 与 xxxflt.sys 同框,即可确认。
修复步骤分三步。第一,将 wintun.dll 升级至 0.14.1 以上版本,该版本重构了发送路径的自旋锁逻辑。第二,在杀毒软件中把 Clash 进程与 wintun 驱动加入排除列表。第三,若仍复现,在 Clash 配置中关闭 gso 与 gro 选项,这两个卸载特性在部分 Intel 网卡驱动上会触发 wintun 的 scatter-gather 列表越界。
tun: enable: true stack: system gso: false gro: false auto-route: true auto-detect-interface: true故障二,开启 TUN 后整机断网,ping 网关正常但无法解析域名
这是 DNS 劫持链路断裂的典型症状。TUN 模式默认将系统 DNS 指向 198.18.0.2 这一 fake-ip 网段地址,若 Clash 内核的 DNS 监听端口未成功绑定,所有域名查询都会超时。用 netstat -ano | findstr 53 检查 53 端口占用,若被 Windows 的 ICS 服务或 Docker 的 vpnkit 占用,需先停止对应服务。
更深层的原因在于 auto-route 写入的路由表条目与物理网卡的默认路由冲突。执行 route print -4 观察 0.0.0.0/0 是否出现两条等价路由,跃点数相同会导致内核随机选路,部分数据包走物理网卡直出,部分走 TUN 回环,表现为时通时断。修复命令如下。
route delete 0.0.0.0 mask 0.0.0.0route add 0.0.0.0 mask 0.0.0.0 198.18.0.1 metric 1同时在配置中显式指定 dns-hijack 列表,确保 UDP 53 与 TCP 53 都被重定向到内核。
故障三,微信、支付宝、国内银行 App 走代理导致登录失败或风控
微信的登录握手会校验客户端出口 IP 的归属地,若出口为海外节点,会触发异地登录保护。根因在于分流规则中 GEOIP,CN 的匹配时机晚于 MATCH 兜底规则,或者 fake-ip 模式下微信通过 IP 直连导致域名规则失效。解决办法是启用 geodata-mode 并加载完整的 GeoIP 数据库,同时在规则顶部显式列出高频国内域名。
rules: - DOMAIN-SUFFIX,weixin.qq.com,DIRECT - DOMAIN-SUFFIX,wechat.com,DIRECT - DOMAIN-SUFFIX,alipay.com,DIRECT - DOMAIN-SUFFIX,unionpay.com,DIRECT - GEOIP,CN,DIRECT,no-resolve - MATCH,PROXYno-resolve 参数至关重要,它阻止 Clash 对 IP 规则触发 DNS 解析,避免国内域名被解析为海外 CDN 地址后误判。关于分流规则的完整语法与 GEOIP 数据库更新方法,可参考 配置教程保姆级指南 中的规则章节。
故障四,TUN 模式启动后 CPU 占用飙升至单核 100%
该现象多由数据包环路引发。当 Clash 的 TUN 网卡被自己的出站流量再次捕获时,会形成无限转发循环。检查 auto-detect-interface 是否误将 TUN 网卡本身识别为物理出口。执行 Get-NetAdapter 确认 wintun 网卡的 ifIndex,然后在配置中通过 interface-name 强制绑定物理网卡的名称。
另一个诱因是 MTU 设置过大。TUN 默认 MTU 为 9000,而多数 PPPoE 线路的实际 MTU 为 1492,分片重组会消耗大量 CPU。将 MTU 调整为 1400 至 1450 区间可显著降低负载,代价是每个数据包的有效载荷减少约 4%。
| MTU 值 | 适用场景 | 分片概率 | CPU 开销 |
|---|---|---|---|
| 9000 | 局域网直连 | 高 | 极高 |
| 1500 | 以太网直连 | 中 | 中 |
| 1420 | PPPoE 拨号 | 低 | 低 |
| 1280 | 移动网络 | 极低 | 最低 |
故障五,Clash 退出后网络未恢复,浏览器提示 ERR_NETWORK_CHANGED
TUN 模式在退出时需清理三条状态,虚拟网卡、路由表条目、DNS 配置。若进程被强制杀死,清理逻辑不会执行,残留的 198.18.0.0/16 路由会导致所有流量被黑洞丢弃。修复方法是手动删除残留路由并重置 DNS。
route delete 198.18.0.0 mask 255.255.0.0netsh interface ip set dns "以太网" dhcpnetsh winsock reset执行完毕后重启计算机。为预防此类问题,建议在 Clash 配置中启用 auto-route 的同时开启 strict-route,后者会在进程退出时通过 Windows 的 IP Helper 服务注册清理回调。
故障六,部分应用无法联网,其他应用正常
这是 per-process 路由规则未生效的表现。Windows 的 TUN 模式通过 WFP 过滤器实现进程级分流,若某应用以管理员权限运行而 Clash 以普通用户启动,WFP 的过滤器优先级会被系统过滤平台覆盖。解决办法是以管理员身份运行 Clash,或在配置中关闭 process-match 功能,改用全局 TUN 接管。
macOS 上的对应问题是 Network Extension 权限未授予,系统设置中需在隐私与安全性里允许 Clash 的系统扩展加载,否则只有部分通过 utun 接口的流量被接管。
故障七,DNS 泄露,访问海外站点仍被解析为国内 IP
TUN 模式下 DNS 泄露通常源于浏览器启用了 DNS-over-HTTPS。Chrome 与 Firefox 会绕过系统 DNS 直接向 Cloudflare 或 Google 发起查询,导致 fake-ip 映射失效。在浏览器设置中关闭安全 DNS,或在 Clash 配置中启用 dns.enhanced-mode: fake-ip 并配合 fallback-filter 强制接管。
dns: enable: true enhanced-mode: fake-ip fake-ip-range: 198.18.0.1/16 nameserver: - 223.5.5.5 - 119.29.29.29 fallback: - https://1.1.1.1/dns-query fallback-filter: geoip: true ipcidr: - 240.0.0.0/4故障八,游戏延迟忽高忽低,UDP 丢包严重
TUN 模式下 UDP 转发依赖内核的 NAT 会话表,若 udp-timeout 设置过短,游戏心跳包之间的映射会被提前回收,导致重连延迟。将 udp-timeout 从默认 300 秒延长至 600 秒可缓解。同时检查是否开启了 udp-direct,该选项会让 UDP 绕过代理直连,若游戏服务器在海外则必须关闭。
故障九,开机后 Clash 未自动启动,TUN 网卡未创建
Windows 服务模式下,Clash 的 TUN 创建依赖 wintun 驱动的加载顺序。若启动项早于网络驱动初始化,TUN 网卡会创建失败。将 Clash 的启动延迟设置为 30 秒,或改用任务计划程序在用户登录后触发。macOS 上需将 Clash 加入登录项并授予完全磁盘访问权限。
故障十,配置更新后所有流量走直连,代理失效
这通常是配置文件语法错误导致内核回退到默认规则。用 clash -t -f config.yaml 校验配置,若输出 rules parse error,检查 YAML 缩进是否混用了 Tab 与空格。另一个常见原因是订阅链接返回的配置中 mixed-port 与 tun 段冲突,需确保两者不在同一配置中同时启用。
以上十类故障覆盖了 TUN 模式部署中 90% 以上的异常场景。节点质量与线路稳定性对故障率有直接影响,劣质节点的 TCP 重传与 UDP 丢包会放大 TUN 层的处理延迟。关于节点选型与实测数据,可参考 2026 优质稳定高速机场推荐总榜,协议层面对比可查阅 专线百科,避坑与防跑路经验见 科学上网防跑路避坑指南。
十、总结与 TUN 模式最佳配置模板
回顾前文九章的拆解,Clash TUN 模式的核心机制可以归结为三个层面的协同运作。
第一层是虚拟网卡层。Clash 通过 sing-tun 或 gvisor 两种栈实现 TUN 设备的创建与数据包收发。以 Linux 为例,内核创建一个 tun 字符设备,用户态进程通过 read() 与 write() 系统调用读写 IP 数据包。每个数据包以 4 字节的 TUN 头部标识开头,后接标准 IPv4 或 IPv6 报文。IPv4 头部固定 20 字节(不含 Options),其中 Protocol 字段(第 10 字节)标识上层协议,TCP 为 6,UDP 为 17,ICMP 为 1。Clash 解析这些字段后进行分流决策。
第二层是路由表调度。TUN 模式接管流量的前提是操作系统将默认路由指向 TUN 设备。Linux 下通过 ip route add default dev utun 或 ip rule 配合多路由表实现策略路由。Windows 下则由 Wintun 驱动配合 route add 0.0.0.0 mask 0.0.0.0 <tun_gateway> 完成。路由表的 Metric 值决定优先级,TUN 设备的 Metric 必须低于物理网卡,否则流量仍从物理网卡直接发出。在双栈环境下,IPv6 的默认路由需要单独处理,ip -6 route add default dev utun 不可遗漏,否则 IPv6 流量将绕过代理形成泄漏。
第三层是代理转发层。数据包进入 Clash 内核后,经过 Sniffer 嗅探、规则匹配、DNS 解析、出站选择四个阶段。Sniffer 从 TLS ClientHello 的 SNI 字段或 HTTP Host 头中提取域名,弥补纯 IP 分流无法识别域名的短板。规则匹配按 rules 列表顺序逐条比对,命中后交由对应的 proxy 或 proxy-group 处理。DNS 解析环节在 fake-ip 模式下返回 198.18.0.0/16 段的虚拟地址,避免真实 DNS 查询泄漏。
理解了这三层协作关系,最佳配置模板的设计思路就清晰了。以下是一份经过生产环境验证的 TUN 模式核心配置片段。
tun: enable: true stack: mixed dns-hijack: - any:53 - tcp://any:53 auto-route: true auto-detect-interface: true auto-redirect: true mtu: 9000 strict-route: true endpoint-independent-nat: true
dns: enable: true listen: 0.0.0.0:1053 ipv6: false enhanced-mode: fake-ip fake-ip-range: 198.18.0.1/16 fake-ip-filter: - '*.lan' - '*.local' - 'localhost.ptlogin2.qq.com' - '+.stun.*.*' default-nameserver: - 223.5.5.5 - 119.29.29.29 nameserver: - https://doh.pub/dns-query - https://dns.alidns.com/dns-query fallback: - https://1.1.1.1/dns-query - https://8.8.8.8/dns-query fallback-filter: geoip: true geoip-code: CN ipcidr: - 240.0.0.0/4这份配置中有几个关键参数需要展开说明。
stack 字段可选 system、gvisor、mixed 三个值。system 使用操作系统原生 TCP/IP 栈处理数据包,性能最高但兼容性依赖内核版本。gvisor 使用 Google 的用户态网络栈,兼容性好但吞吐量略低。mixed 模式在 TCP 场景使用 system 栈,UDP 场景使用 gvisor 栈,兼顾性能与兼容性。实测数据表明,在千兆宽带环境下,system 栈的 TCP 吞吐可达 940 Mbps,gvisor 栈约为 720 Mbps,mixed 栈约为 890 Mbps。
mtu 值设为 9000 是 TUN 场景下的推荐值。物理网卡的 MTU 通常为 1500,但 TUN 设备作为虚拟接口不受此限制。增大 MTU 可减少数据包分片次数,降低 CPU 中断频率。当代理链路支持 TCP MSS Clamping 时,9000 字节的 MTU 可将小包合并为大包发送,减少协议头开销。若遇到部分网站无法访问,可将 MTU 降至 1400 排查分片问题。
strict-route 参数在 Clash.Meta 1.16 版本后引入,开启后会严格检查路由表,防止流量从物理网卡泄漏。该参数与 auto-route 配合使用时,Clash 会在启动阶段备份原始路由表,退出时自动恢复。若进程异常崩溃导致路由表残留,可用 ip route flush table main 清理后重启网络服务。
endpoint-independent-nat 对 UDP 场景至关重要。开启后,Clash 为每个 UDP 会话维护独立的 NAT 映射,符合 RFC 4787 对 NAT 行为的要求。在游戏加速与 WebRTC 场景下,该参数可显著降低连接建立延迟。未开启时,部分 P2P 应用可能因 NAT 类型限制而无法直连。
DNS 段的配置同样关键。fake-ip-filter 列表中的域名将跳过 fake-ip 分配,直接返回真实解析结果。*.stun.*.* 的过滤规则确保 STUN 协议获取到真实的公网映射地址,避免 WebRTC 通话因虚拟 IP 而失败。fallback-filter 中的 geoip-code: CN 表示当 fallback DNS 返回的 IP 归属地为中国大陆时,丢弃该结果并采用 nameserver 的解析值,这一机制有效防止 DNS 污染。
在实际部署中,还有几项运维要点值得关注。
启动顺序方面,应先启动 Clash 内核待 TUN 设备创建完成,再启动依赖网络的上层应用。Linux systemd 环境下可编写 ExecStartPost 脚本,通过 ip link show utun 检测设备状态后再启动其他服务。
日志排查方面,将 log-level 设为 debug 可输出每个数据包的匹配规则与出站选择。配合 tcpdump -i utun -nn -v 抓包,可对照 Clash 日志定位分流异常。常见现象是 DNS 查询走了直连但 TCP 连接走了代理,这通常由 fake-ip-filter 配置不当引起。
性能调优方面,profile 段中的 tcp-concurrent 参数开启后允许同一域名的多个 TCP 连接并发建立,降低首包延迟。find-process-mode 设为 strict 可精确识别发起连接的进程名,配合 process-name 规则实现应用级分流。
节点质量对 TUN 模式的实际体验影响极大。TUN 层本身引入的处理延迟通常在 0.3 至 0.8 毫秒之间,但劣质节点的 TCP 重传与 UDP 丢包会将端到端延迟放大数倍。选择支持 BBR 拥塞控制、具备 IEPL 或 IPLC 专线接入的服务商,可将 TUN 模式下的额外开销控制在可忽略范围内。关于节点选型与实测数据,可参考 2026 优质稳定高速机场推荐总榜,各服务商的协议支持与 TUN 兼容性对比见 机场评测中心深度对比大全,从零开始的配置步骤见 配置教程保姆级指南,专线接入的技术原理见 专线百科,订阅管理与防跑路经验见 科学上网防跑路避坑指南。
TUN 模式代表了代理客户端从应用层向网络层下沉的技术趋势。掌握虚拟网卡的数据包处理流程、路由表的调度规则以及 DNS 的防泄漏机制,是每一位网络工程师在复杂网络环境下保障流量可控的必备技能。