跳到主要内容

首页 / 博客 / DNS 与网络

TUN 模式底层:虚拟网卡、路由表与 DNS 劫持是怎么配合的

DNS 与网络2026-06-261968 字约 5 分钟
TUN 模式底层:虚拟网卡、路由表与 DNS 劫持是怎么配合的

打开 TUN 开关的一瞬间,系统里发生了三件事:多了一块网卡、路由表被改写、53 端口被劫持。

理解这三件事,TUN 相关的所有疑难问题就都有了排查方向。

一、创建虚拟网卡

TUN 是操作系统提供的一种虚拟网络设备。它在系统看来是一块正常网卡,但另一端不是物理线缆,而是一个用户态程序——这里就是 Mihomo 内核。

数据包的旅程应用程序发出 IP 包系统路由决定从哪块网卡出去TUN 虚拟网卡包被交给内核程序Mihomo 处理按规则决定直连或转发
对应用来说完全透明,它以为自己在正常联网

各平台的实现:

平台实现需要的权限
Windowswintun 驱动管理员(安装驱动 + 系统服务)
macOSutun 内核扩展root(特权助手)
Linux/dev/net/tunCAP_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 后,前缀更长,稳定压过原默认路由,同时又不需要删除原路由——这样内核自己的出站流量还能通过原路由正常出去。

路由优先级(从高到低)1具体主机路由 322TUN 的两条 13原默认路由 0
节点服务器的 IP 必须走物理网卡,否则流量会绕回 TUN 形成死循环

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 能看到你查了哪些域名
有无 DNS 劫持的差别程序硬编码查 8.8.8.8发出 UDP 53 包无劫持包经 TUN 转发到 8.8.8.8有劫持包被内核截下自己回答结果前者可能被污染且泄漏,后者可控
TUN 模式下 dns-hijack 基本是必开项

四、协议栈:gvisor / system / mixed

TUN 拿到的是原始 IP 包,需要一个 TCP/IP 协议栈来还原成连接。三种实现:

三种 stack 的取舍gvisor用户态协兼容性最好性能略低默认推荐system交给操作性能最高对系统配置要求高、兼容性差些追求极限性能mixedTCP折中大多数场景的最优解Mihomo 常用默认
出问题时优先切 gvisor,它最不容易出错

选择建议:

情况
不确定 / 首次配置mixed
出现奇怪的连接问题gvisor
软路由、追求吞吐system
macOS 上 UDP 有问题gvisor

五、MTU 与分片

tun:
  mtu: 1500

MTU 是单个数据包的最大字节数。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-ipfilter 加 "+.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

应该能看到一块名为 MihomoutunX 的网卡。

看路由:

# Windows
route print -4
# Linux
ip route show

应该能看到两条指向 TUN 网卡的 /1 路由。

看流量是否真的经过:

打开 Clash Verge 的连接页,用一个明确不读系统代理的程序(比如命令行 curl 且没设环境变量)访问外网。如果连接页出现了记录,说明 TUN 生效了。

小结

TUN 的三件事:

  • 虚拟网卡——需要驱动和特权,靠服务模式解决
  • 路由表——两条 /1 接管全局,节点 IP 单独走物理网卡
  • DNS 劫持——防止硬编码 DNS 绕过内核

出问题时按这三层排查:网卡在不在 → 路由对不对 → DNS 通不通。

相关:DNS 与 fake-ip 详解分流实战


相关文档