
你是否遇到过这样的情况:明明已经开启了代理软件,但终端里的 curl 依然连不上 GitHub,Docker 拉取镜像还是慢如蜗牛,或者某些游戏根本无法联机?
为了解决这些“漏网之鱼”,我们通常会开启 Clash 等代理工具的 TUN 模式。今天,我们就来扒一扒 TUN 模式到底是什么,以及它是如何在底层接管你电脑上的所有网络流量的。
1. 什么是 TUN 模式?
TUN(Network TUNnel)是一种基于虚拟网卡技术的网络流量接管方式。
理解它的工作原理,最简单的方法是把它看作是操作系统里的一个“网络流量黑洞”。一旦开启,它会在底层无差别地拦截系统的所有网络请求,不管这些请求是来自浏览器、命令行,还是某个固执己见的老旧软件。
2. 为什么我们需要 TUN 模式?
在解释 TUN 之前,我们需要先对比一下传统的系统代理(HTTP/SOCKS5 代理)模式。
默认情况下,大多数代理软件工作在 OSI 模型的应用层(Layer 7)。它的致命痛点在于:它极度依赖应用程序的“自觉性”。 很多软件(比如终端命令行工具、大部分游戏、Windows UWP 应用,或者硬编码了直连逻辑的脚本)根本不理会操作系统的代理设置。它们会直接绕过代理,把流量发往物理网卡。
TUN 模式就是为了降维打击而诞生的。它工作在更底层的网络层(Layer 3),强制接管所有 IP 数据包,实现真正的全局代理。
3. TUN 模式是如何工作的?
当你开启代理软件的 TUN 模式时,后台其实按顺序执行了以下一套“偷天换日”的操作:
-
创建虚拟网卡 (Virtual Network Interface) 软件会向操作系统申请创建一个虚拟的网卡设备(Windows 上通常是
wintun驱动,macOS/Linux 上是原生的utun或tun设备)。在操作系统看来,这个虚拟网卡和你的真实 Wi-Fi 或以太网卡没有任何区别。 -
篡改系统路由表 (Modifying the Routing Table) 这是最核心的一步。软件会修改操作系统的路由表,将这个新创建的虚拟网卡设置为默认网关,或者添加指向它的全路由规则(例如
0.0.0.0/0)。 这样一来,系统里所有的应用程序发出的 IP 数据包,都会被操作系统“傻乎乎”地直接扔进这个虚拟网卡里。 -
用户态网络协议栈解析 (User-space TCP/IP Stack) 进入虚拟网卡的,都是最底层的原始 IP 数据包(Raw IP Packets)。但代理软件(如 Clash)本质上是一个应用层程序,它看不懂也无法直接处理这些原始数据。 因此,软件内部必须内置一个用户态的 TCP/IP 协议栈(例如 gVisor 或 lwIP)。这个协议栈负责将拦截到的 IP 数据包重新“组装”,还原成代理软件能看懂的 TCP 连接或 UDP 数据流。
-
配合 Fake-IP 获取域名 (DNS Hijacking) 虽然 TUN 拦截了所有 IP 包并还原了 TCP/UDP 连接,但网络层的包里只有目标 IP,没有域名。为了让代理软件能根据域名规则(如
geosite:google)进行分流,我们需要 Fake-IP 技术。 当应用发起 DNS 解析时,代理软件会返回一个伪造的 IP(Fake-IP,如198.18.0.1)并记录映射关系。当应用向这个 Fake-IP 发起 TCP 连接并被 TUN 拦截时,代理软件就能通过查表,知道它真正想访问的是哪个域名。 -
规则匹配与分流 (Rule Matching & Routing) 拿到目标域名或真实 IP 后,代理软件就会根据你的配置规则进行匹配:
- Direct(直连):如果规则判定为直连,软件会把流量从真实的物理网卡发出去。
- Proxy(代理):如果判定需要代理,软件会将流量加密封装,发送给远端的代理服务器。
4. 优缺点分析
优势:
- 100% 接管率:无论是命令行(
curl,git)、虚拟机、Docker 还是游戏,统统都能被代理,再也不用为每个软件单独配环境变量。 - 更好的 UDP 支持:对于支持 UDP 转发的节点,TUN 模式能完美处理游戏的 UDP 流量和 P2P 流量。
劣势与前置条件:
- 需要最高权限:因为涉及创建虚拟网卡和修改系统核心路由表,每次开启 TUN 模式都需要 UAC 提权(Windows)或 Root 权限(macOS/Linux)。(注:很多现代 GUI 客户端通过安装后台 Service 绕过了每次弹窗的麻烦)。
- 轻微的性能损耗:所有流量都要经历一次
内核态 -> 用户态协议栈(gVisor/lwIP) -> 代理引擎的转换。相比纯粹的端口转发,会有极少量的 CPU 消耗和延迟增加,但在现代 CPU 上基本可以忽略不计。
5. 真实世界的验证
理论说完了,我们如何在终端里验证这套机制?以下是我在 macOS 上开启代理(或类似 Tailscale 的虚拟网络)后的实操记录。
第一步:查看虚拟网卡
通过 ifconfig 命令,我们可以看到系统多出了一个 utun 设备:
ifconfig | grep -A 3 "utun"
输出示例:
utun7: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1280
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
inet 100.100.100.100 --> 100.100.100.100 netmask 0xffffffff
nd6 options=201<PERFORMNUD,DAD>
第二步:检查路由表被篡改的痕迹
通过 netstat 查看 IPv4 的路由表,找到 utun7 的记录,就能确定流量的走向:
netstat -nr -f inet
输出示例:
default 192.168.1.1 UGScIg en0
default link#35 UCSIg utun7
100.64/10 link#35 UCS utun7
可以看到,虽然默认网关依然有真实的 en0(Wi-Fi),但代理软件通过注入更具体的路由规则(或者调整优先级),利用路由表的最长前缀匹配原则,成功将流量劫持到了 utun7。
第三步:追踪特定域名的流量走向
如果你想知道某个具体的域名或 IP 到底走的是哪张网卡,可以使用 route 命令:
route get www.google.com
输出示例:
route to: r-199-59-148-229.twttr.com
destination: default
mask: default
gateway: 192.168.1.1
interface: utun8
flags: <UP,GATEWAY,DONE,STATIC,PRCLONING,GLOBAL>
这里的 interface: utun8 明确告诉我们,发往 Google 的流量已经被虚拟网卡接管了。
6. 排错与边缘情况
在实际使用中,TUN 模式的全局接管特性很容易与其他网络工具产生冲突。以下是两个常见的踩坑案例及解决方案。
冲突案例 1:与 Tailscale 等虚拟局域网冲突
Tailscale 也会创建自己的 TUN 网卡并接管特定网段(如 100.64.0.0/10)。如果代理软件的 TUN 路由规则过于霸道,就会导致 Tailscale 的节点无法互访。
解决方案: 在代理软件的 TUN 配置中,排除 Tailscale 的网段,让这部分流量不进入代理的 TUN,而是走系统原路由。
tun:
enable: true
stack: system
auto-route: true
# 排除 Tailscale 的默认 CGNAT 网段,这部分流量系统会直接走原路由,不进代理的 TUN
route-exclude-address:
- 100.64.0.0/10
冲突案例 2:与 OrbStack 的 .local 域名冲突
OrbStack(macOS 上的 Docker 替代品)会使用 .local 域名(如 ubuntu.orb.local)来访问容器。
由于 .local 域名由 macOS 底层的 mDNSResponder 处理(你可以通过 scutil --dns 验证),它没有传统的 DNS 服务器。如果代理软件的 Fake-IP 机制强行劫持了 .local,就会导致无法解析出 OrbStack 分配的真实局域网 IP。
解决方案:
我们需要在代理配置中对 .local 域名进行“三步走”的豁免处理:
dns:
nameserver-policy:
# 1. 委派解析:遇到该域名,别走代理 DNS,交还给 macOS 系统的原生 DNS 处理
"+.orb.local": "system"
fake-ip-filter:
# 2. 绕过污染:将该域名移出 Fake-IP 池,确保系统拿到的是真实的局域网 IP
- "+.orb.local"
prepend-rules:
# 3. 流量直连:确保解析出真实 IP 后,流量直接在本地物理网卡流转,不被塞进 TUN 隧道
- DOMAIN-SUFFIX,orb.local,DIRECT