打开 TUN 开关的一瞬间,系统里发生了三件事:多了一块网卡、路由表被改写、53 端口被劫持。
理解这三件事,TUN 相关的所有疑难问题就都有了排查方向。
一、创建虚拟网卡
TUN 是操作系统提供的一种虚拟网络设备。它在系统看来是一块正常网卡,但另一端不是物理线缆,而是一个用户态程序——这里就是 Mihomo 内核。
各平台的实现:
| 平台 | 实现 | 需要的权限 |
|---|---|---|
| Windows | wintun 驱动 | 管理员(安装驱动 + 系统服务) |
| macOS | utun 内核扩展 | root(特权助手) |
| Linux | /dev/net/tun | CAP_NET_ADMIN |
Clash Verge 的「服务模式」就是为了避免每次都要提权——装一次系统服务,之后由服务代为执行特权操作。
二、改写路由表
光有网卡不够,还要让系统把流量往这块网卡上送。这靠修改路由表实现。
auto-route: true 时,内核会添加类似这样的路由:
0.0.0.0/1 → TUN 网卡
128.0.0.0/1 → TUN 网卡为什么是两条 /1 而不是一条 0.0.0.0/0?
因为路由匹配遵循「最长前缀优先」。系统原有的默认路由是 0.0.0.0/0,如果 TUN 也写 0.0.0.0/0,两条同等长度的路由会产生歧义。拆成两条 /1 后,前缀更长,稳定压过原默认路由,同时又不需要删除原路由——这样内核自己的出站流量还能通过原路由正常出去。
auto-detect-interface: true 让内核自动识别真实出口网卡(Wi-Fi 还是有线),这样切换网络时能自动跟随。
strict-route 的作用
tun:
strict-route: true开启后会加更严格的路由规则和防火墙策略,确保没有流量能绕过 TUN。副作用是与其他 VPN 软件的冲突概率上升。
有 VPN 共存需求时关掉它。
排除特定网卡
和企业 VPN 共存时:
tun:
exclude-interface: ["ppp0", "Cisco AnyConnect"]三、DNS 劫持
tun:
dns-hijack:
- any:53含义:任何发往 53 端口的 DNS 查询,无论目标是哪个服务器,都截下来交给内核自己的 DNS 处理。
为什么必须劫持:有些程序会硬编码 DNS 服务器(比如直接查 8.8.8.8),绕过系统 DNS 设置。不劫持的话,这些查询会走原路径出去,导致:
- 解析结果不准(可能被污染)
- 域名信息丢失,内核只能拿 IP 做规则匹配
- DNS 泄漏——ISP 能看到你查了哪些域名
四、协议栈:gvisor / system / mixed
TUN 拿到的是原始 IP 包,需要一个 TCP/IP 协议栈来还原成连接。三种实现:
选择建议:
| 情况 | 选 |
|---|---|
| 不确定 / 首次配置 | mixed |
| 出现奇怪的连接问题 | gvisor |
| 软路由、追求吞吐 | system |
| macOS 上 UDP 有问题 | gvisor |
五、MTU 与分片
tun:
mtu: 1500MTU 是单个数据包的最大字节数。TUN 网卡的 MTU 如果设得比实际链路大,包会被分片,性能下降;设得太小,传输效率低。
1500 是以太网标准值,通常不用改。但如果你的节点走的是本身就有封装开销的链路(某些中转、PPPoE 拨号),实际可用 MTU 会小于 1500,可能需要下调到 1400~1450。
六、完整的 TUN 配置
tun:
enable: true
stack: mixed
device: Mihomo
auto-route: true
auto-detect-interface: true
auto-redirect: false # Linux 上的额外重定向
strict-route: false
mtu: 1500
dns-hijack:
- any:53
- tcp://any:53
# 排除某些网卡,避免和 VPN 冲突
# exclude-interface: ["ppp0"]
# 排除某些进程(Mihomo 支持)
# exclude-package: ["com.example.app"] # Android配合的 DNS 配置:
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
- "+.pool.ntp.org"
- "+.msftconnecttest.com"
- "+.msftncsi.com"
nameserver: [223.5.5.5, https://doh.pub/dns-query]必须同时配好 DNS——TUN 接管了所有流量,如果 DNS 没配好,什么都解析不了。
常见问题的底层原因
| 现象 | 底层原因 | 处理 |
|---|---|---|
| 开 TUN 后全网断 | 路由改写了但内核出站流量绕回自己 | 确认 auto-detect-interface: true;重启 |
| 关掉软件后网络恢复不了 | 强杀进程导致路由未撤销 | 重启 Clash Verge 后正常退出,或重启系统 |
| 局域网设备访问不了 | 内网 IP 段没有直连规则 | 加 IP-CIDR,192.168.0.0/16,DIRECT,no-resolve |
| NAS / 打印机找不到 | mDNS 域名被 fake-ip 拦了 | fake-ip-filter 加 "*.local"、"*.lan" |
| 和公司 VPN 冲突 | 两者都改路由表 | 关 strict-route,用 exclude-interface |
| 系统提示「无 Internet 连接」 | 连通性检测域名被 fake-ip | filter 加 "+.msftconnecttest.com" |
| 大文件下载卡住 | MTU 过大导致分片丢失 | mtu 调到 1400 |
| UDP 游戏连不上 | 节点不支持 UDP,或 stack 不合适 | 确认节点 udp: true,stack 换 gvisor |
| CPU 占用高 | 所有流量都过用户态协议栈 | stack 换 system,或关 TUN 只用系统代理 |
怎么验证 TUN 真的在工作
看网卡:
# Windows
Get-NetAdapter | Where-Object {$_.InterfaceDescription -like "*wintun*"}# Linux / macOS
ip link show # 或 ifconfig应该能看到一块名为 Mihomo 或 utunX 的网卡。
看路由:
# Windows
route print -4# Linux
ip route show应该能看到两条指向 TUN 网卡的 /1 路由。
看流量是否真的经过:
打开 Clash Verge 的连接页,用一个明确不读系统代理的程序(比如命令行 curl 且没设环境变量)访问外网。如果连接页出现了记录,说明 TUN 生效了。
小结
TUN 的三件事:
- 虚拟网卡——需要驱动和特权,靠服务模式解决
- 路由表——两条
/1接管全局,节点 IP 单独走物理网卡 - DNS 劫持——防止硬编码 DNS 绕过内核
出问题时按这三层排查:网卡在不在 → 路由对不对 → DNS 通不通。
相关:DNS 与 fake-ip 详解、分流实战。
相关文档
讲清楚 fake-ip 的工作原理、和 redir-host 的本质区别、nameserver 与 fallback 的分工、DNS 泄漏怎么防,以及内网域名解析失败的根因。
讲清楚游戏流量的特殊性:为什么 UDP 必须靠 TUN、NAT 类型是怎么回事、丢包比延迟更致命,以及一份面向低延迟的配置调整清单。