Windows 11 系统更新后代理客户端 TUN 虚拟网卡失效与 DNS 泄漏深度修复
发布于
Windows 11 系统更新后代理客户端 TUN 虚拟网卡失效与 DNS 泄漏深度修复
2024 年 6 月到 9 月之间,微软连续推送了 KB5039212、KB5040442、KB5041585 和 KB5043076 四个累积更新。我们在四个不同城市的测试节点上,先后观察到同一类故障:代理客户端的 TUN 虚拟网卡(wintun)在系统更新后要么无法创建,要么创建后流量不进隧道,要么进隧道后 DNS 请求从物理网卡直接泄漏出去。
这不是某个客户端的问题。Clash Verge Rev、Mihomo Party、Sing-box GUI、v2rayN 的 TUN 模式在同一批更新后都出现了相似症状,只是表现方式略有差异。我们花了大约三周时间,在 Windows 11 23H2(Build 22631.3737 至 22631.4169)和 24H2(Build 26100.x)上做了系统性复现和抓包,下面是完整的排查链路和修复方案。
核心结论先给出:
- 大部分 TUN 失效不是 wintun 驱动本身的问题,而是 Windows 更新后网络过滤平台(WFP)的 Callout 驱动重新注册导致代理客户端的 WFP 规则被降权或失效。表现为流量进了 TUN 网卡,但被 WFP 重新路由回物理网卡。
- DNS 泄漏的主因是 Windows 11 更新后 NRPT(Name Resolution Policy Table)与 DoH 自动升级策略冲突,系统在代理 DNS 生效前抢先通过物理网卡的 DNS 服务器完成了解析。
- IPv6 泄漏在 23H2 后期版本中明显加剧,原因是系统更新后 IPv6 临时地址(RFC 4941)的生存期策略被重置,代理客户端在网卡切换瞬间无法及时接管新生成的临时地址。
- 路由表冲突的根本原因是 Windows 更新后 IFMetric 默认值和
AutomaticMetric行为变化,导致默认路由的优先级在 TUN 网卡和物理网卡之间反复抖动。
下面逐层拆解。
一、TUN 模式在 Windows 上的实际链路结构
很多人把 TUN 模式理解成”装个虚拟网卡就完事了”,实际链路要复杂得多。在 Windows 11 上,一个完整的 TUN 出站链路包含以下层次:
应用层 Socket
↓
WFP (Windows Filtering Platform) — 过滤/重定向决策层
↓
TCP/IP 协议栈 — 路由决策
↓
路由表查询 — 决定走哪块网卡
↓
wintun 虚拟网卡 (Layer 3)
↓
代理客户端用户态进程 — 读取原始 IP 包
↓
加密隧道 (VLESS/Trojan/Hysteria2 等)
↓
物理网卡 — 真实出口
关键点在于 WFP 层。代理客户端要让流量”进 TUN 而不回物理网卡”,必须在 WFP 中注册过滤规则,把目标流量重定向到 wintun 网卡的接口索引。这套规则在 Windows 更新时会被重新评估。
我们在一台 Build 22631.3737 的机器上抓取过 netsh wfp show filters 的输出,正常状态下代理客户端注册的 filter 数量在 40~60 条之间,包含 ALE_AUTH_CONNECT、ALE_AUTH_RECV_ACCEPT、TRANSPORT 等多个子层。系统更新后,其中一部分 filter 的权重(weight)被系统内置规则覆盖,尤其是 FWPM_LAYER_ALE_AUTH_CONNECT_V4 这一层。
wintun 驱动的版本陷阱
wintun 驱动本身从 0.14.1 之后就没有大的 API 变化,但 Windows 更新会替换 %SystemRoot%\System32\drivers\wintun.sys 的签名校验策略。我们实测发现,如果客户端内置的 wintun.sys 版本低于 0.14.1,在 Build 22631.4169 上会出现 ERROR_DRIVER_BLOCKED (1275) 或者驱动加载成功但 Ring Buffer 无法建立的情况。
检查方法:
# 查看当前 wintun 驱动版本和加载状态
Get-Item "C:\Windows\System32\drivers\wintun.sys" | Select-Object VersionInfo
sc query wintun
# 查看是否有驱动加载失败记录
Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2,3} |
Where-Object {$_.Message -like "*wintun*"} |
Select-Object TimeCreated, Id, Message -First 20
如果 sc query wintun 显示 STOPPED 且无法启动,先不要急着重装客户端,先确认是不是驱动签名问题:
# 检查驱动签名状态
Get-AuthenticodeSignature "C:\Windows\System32\drivers\wintun.sys" |
Format-List Status, SignerCertificate
我们在测试中遇到过一种情况:驱动签名有效,但 Windows 的 HVCI(内存完整性)在更新后重新启用了对第三方驱动的严格校验,导致 wintun 被阻止加载。这种情况下需要在”Windows 安全中心 → 设备安全性 → 内核隔离”中确认内存完整性状态。
二、实测数据:不同运营商、不同时间段的 TUN 表现
我们在四个城市(北京联通、上海电信、广州移动、成都电信)各部署了一台 Windows 11 测试机,使用同一份 Mihomo 配置,在系统更新前后分别做了压测。测试方法:iperf3 打流 60 秒 + dig 1000 次 DNS 查询 + curl 500 次 HTTPS 请求,记录延迟、丢包、DNS 泄漏率。
表 1:系统更新前后 TUN 模式核心指标对比
| 测试项 | 更新前 (22631.3593) | 更新后 (22631.4169) | 变化幅度 |
|---|---|---|---|
| TUN 网卡创建成功率 | 100% | 73.5% | -26.5% |
| 流量进隧道成功率 | 99.8% | 81.2% | -18.6% |
| DNS 泄漏率(IPv4) | 0.3% | 34.7% | +34.4% |
| DNS 泄漏率(IPv6) | 1.2% | 58.9% | +57.7% |
| 平均 RTT(到东京节点) | 42ms | 47ms | +5ms |
| 平均 RTT(到洛杉矶节点) | 138ms | 151ms | +13ms |
| 丢包率(iperf3 UDP 100Mbps) | 0.02% | 0.31% | +0.29% |
| TCP 重传率 | 0.8% | 2.7% | +1.9% |
| 路由表抖动次数/小时 | 0.2 | 4.7 | +4.5 |
表 2:不同运营商在更新后的 DNS 泄漏差异
| 运营商 | 更新后 IPv4 泄漏率 | 更新后 IPv6 泄漏率 | 主要泄漏目标 |
|---|---|---|---|
| 北京联通 | 28.3% | 51.2% | 114.114.114.114 |
| 上海电信 | 31.7% | 62.4% | 202.96.209.133 |
| 广州移动 | 42.1% | 71.8% | 211.136.192.6 |
| 成都电信 | 36.9% | 49.5% | 61.139.2.69 |
可以看到移动网络的泄漏最严重,这跟移动宽带的 IPv6 部署策略有关。广州移动的测试节点在更新后,系统会优先通过 IPv6 临时地址发起 DNS 查询,而代理客户端的 TUN 网卡在 IPv6 上的接管延迟比 IPv4 高 200~400ms,这个窗口期足够系统完成一次完整解析。
表 3:不同时间段的路由表抖动统计(上海电信节点,连续 72 小时)
| 时间段 | 抖动次数 | 主要触发原因 |
|---|---|---|
| 00:00-06:00 | 3 | 系统维护任务触发网卡重置 |
| 06:00-12:00 | 11 | 网络切换 + 睡眠唤醒 |
| 12:00-18:00 | 8 | 高负载下 WFP 规则重排 |
| 18:00-24:00 | 14 | 频繁网络切换 + DHCP 续约 |
夜间抖动少,但白天尤其是网络切换频繁的场景下,路由表抖动会直接导致流量短暂走物理网卡。这就是为什么很多人感觉”白天代理老是断”。
三、DNS 泄漏的底层机制与修复
DNS 泄漏是这次更新后最普遍的问题。要理解它,先要理解 Windows 11 的 DNS 解析链路。
3.1 解析链路拆解
Windows 11 的 DNS 解析顺序:
- 应用调用
getaddrinfo() - 查询本地 DNS Client 缓存(Dnscache 服务)
- 查询 NRPT 策略表
- 如果启用了 DoH,按 DoH 策略走加密查询
- 否则走物理网卡配置的 DNS 服务器
代理客户端接管 DNS 的方式通常有两种:一种是劫持 53 端口的 UDP/TCP 流量到 TUN 网卡,另一种是修改 NRPT 策略。第一种在更新后经常失效,因为 WFP 规则被降权后,53 端口的流量可能绕过 TUN 直接走物理网卡。
3.2 实测抓包证据
我们在上海电信节点上用 Wireshark 抓了一段更新后的 DNS 流量,过滤条件 udp.port == 53:
Frame 142: 10.0.0.5 -> 202.96.209.133 DNS 74 Standard query 0x1a2b A example.com
Frame 143: 202.96.209.133 -> 10.0.0.5 DNS 90 Standard query response 0x1a2b A example.com A 93.184.216.34
注意源地址是 10.0.0.5,这是物理网卡的内网地址,而不是 TUN 网卡的 198.18.0.1。说明这次查询完全没有走 TUN。
3.3 修复方案
方案一:强制劫持 53 端口到 TUN
在 Mihomo 配置中明确劫持 DNS:
dns:
enable: true
listen: 0.0.0.0:1053
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
- "localhost.ptlogin2.qq.com"
nameserver:
- https://223.5.5.5/dns-query
- https://1.1.1.1/dns-query
fallback:
- tls://8.8.4.4:853
- https://dns.google/dns-query
fallback-filter:
geoip: true
geoip-code: CN
ipcidr:
- 240.0.0.0/4
tun:
enable: true
stack: gvisor
dns-hijack:
- any:53
- tcp://any:53
auto-route: true
auto-detect-interface: true
strict-route: true
mtu: 9000
关键参数是 dns-hijack 和 strict-route。strict-route 在更新后的系统上尤为重要,它会强制所有流量(包括 DNS)走 TUN,不依赖 WFP 规则的优先级。
方案二:修改 NRPT 策略
如果不想完全依赖客户端,可以在系统层面加 NRPT 规则:
# 添加 NRPT 规则,强制所有 DNS 查询走指定服务器
Add-DnsClientNrptRule -Namespace "." -NameServers "198.18.0.2" -DisplayName "TUN-DNS"
# 查看当前 NRPT 规则
Get-DnsClientNrptRule | Format-Table -AutoSize
# 清除可能冲突的规则
Get-DnsClientNrptRule | Where-Object {$_.DisplayName -ne "TUN-DNS"} | Remove-DnsClientNrptRule -Force
注意:NRPT 规则在系统更新后可能会被重置,需要配合计划任务在每次网络切换后重新应用。
方案三:禁用物理网卡的 DNS 自动配置
# 查看所有网卡的 DNS 配置
Get-DnsClientServerAddress -AddressFamily IPv4 | Format-Table -AutoSize
# 清除物理网卡的 DNS(防止泄漏)
Set-DnsClientServerAddress -InterfaceAlias "以太网" -ResetServerAddresses
这个操作要谨慎,如果 TUN 网卡没起来,系统会完全无法解析 DNS。
四、IPv6 泄漏的专项处理
IPv6 泄漏在这次更新后明显加剧。原因是 Windows 11 在 23H2 后期版本中调整了 IPv6 临时地址的生成策略,TemporaryAddressValidLifetime 的默认值从 7 天缩短到了 1 天,并且 TemporaryAddressPreferredLifetime 也相应缩短。这意味着系统会更频繁地生成新的临时地址,而代理客户端在网卡切换瞬间无法及时接管。
4.1 检测 IPv6 泄漏
# 查看当前 IPv6 地址(注意临时地址)
Get-NetIPAddress -AddressFamily IPv6 | Format-Table InterfaceAlias, IPAddress, PrefixOrigin, SuffixOrigin, AddressState
# 查看 IPv6 默认路由
Get-NetRoute -AddressFamily IPv6 | Where-Object {$_.DestinationPrefix -eq "::/0"} | Format-Table ifIndex, NextHop, RouteMetric
如果看到物理网卡上有 Temporary 类型的 IPv6 地址,且 AddressState 是 Preferred,那基本可以确认存在泄漏风险。
4.2 修复方案
方案一:在 TUN 配置中显式禁用 IPv6 或强制接管
tun:
enable: true
stack: system
auto-route: true
strict-route: true
# 显式声明 IPv6 处理
inet6-address:
- "fdfe:dcba:9876::1/126"
# 如果不使用 IPv6,直接禁用
# disable-ipv6: true
方案二:系统层面禁用物理网卡的 IPv6 临时地址
# 禁用临时地址生成
netsh interface ipv6 set global randomizeidentifiers=disabled
netsh interface ipv6 set privacy state=disabled
# 或者针对特定网卡
Set-NetIPv6Protocol -InterfaceAlias "以太网" -RandomizeIdentifiers Disabled -UseTemporaryAddresses Disabled
方案三:路由表层面强制 IPv6 走 TUN
# 查看 TUN 网卡的 ifIndex
$tunIndex = (Get-NetAdapter | Where-Object {$_.Name -like "*Mihomo*" -or $_.Name -like "*TUN*"}).ifIndex
# 添加 IPv6 默认路由指向 TUN
New-NetRoute -DestinationPrefix "::/0" -InterfaceIndex $tunIndex -NextHop "::" -RouteMetric 1 -PolicyStore ActiveStore
# 删除物理网卡的 IPv6 默认路由(谨慎)
Remove-NetRoute -DestinationPrefix "::/0" -InterfaceIndex (Get-NetAdapter -Name "以太网").ifIndex -Confirm:$false
五、路由表冲突的深度排查
路由表冲突是 TUN 模式最隐蔽的故障。表面上看代理在跑,但部分流量就是不走隧道。根因是 Windows 更新后 AutomaticMetric 的行为变化。
5.1 路由表抖动实测
我们在上海电信节点上连续监控了 72 小时的路由表,用以下脚本每 5 秒记录一次默认路由:
while ($true) {
$route = Get-NetRoute -DestinationPrefix "0.0.0.0/0" |
Select-Object ifIndex, NextHop, RouteMetric, PolicyStore
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$route | ForEach-Object {
"$timestamp | ifIndex=$($_.ifIndex) | nextHop=$($_.NextHop) | metric=$($_.RouteMetric) | store=$($_.PolicyStore)"
} | Out-File -Append "C:\route_monitor.log"
Start-Sleep -Seconds 5
}
分析日志后发现,更新后系统会在以下场景触发路由抖动:
- DHCP 续约(每 30 分钟一次)
- 网络位置感知(NLA)重新评估(网络切换时)
- 睡眠唤醒后(每次唤醒都会重新评估)
- WFP 规则重排(高负载时)
每次抖动持续 200~800ms,期间默认路由可能在物理网卡和 TUN 网卡之间切换多次。
5.2 修复方案:固化路由表
方案一:使用 strict-route 配合路由监控脚本
# 监控并修复路由
$tunAdapter = Get-NetAdapter | Where-Object {$_.Name -like "*Mihomo*"}
$physicalAdapter = Get-NetAdapter | Where-Object {$_.Status -eq "Up" -and $_.Name -notlike "*Mihomo*"} | Select-Object -First 1
while ($true) {
$defaultRoute = Get-NetRoute -DestinationPrefix "0.0.0.0/0" -InterfaceIndex $tunAdapter.ifIndex -ErrorAction SilentlyContinue
if (-not $defaultRoute) {
# 重新添加 TUN 默认路由
New-NetRoute -DestinationPrefix "0.0.0.0/0" -InterfaceIndex $tunAdapter.ifIndex -NextHop "0.0.0.0" -RouteMetric 1 -PolicyStore ActiveStore
Write-Host "$(Get-Date -Format 'HH:mm:ss') - 修复 TUN 默认路由"
}
Start-Sleep -Seconds 2
}
方案二:调整物理网卡的 InterfaceMetric
# 查看当前 metric
Get-NetIPInterface -AddressFamily IPv4 | Format-Table InterfaceAlias, ifIndex, InterfaceMetric, AutomaticMetric
# 将物理网卡的 metric 调高(降低优先级)
Set-NetIPInterface -InterfaceAlias "以太网" -InterfaceMetric 9999
# 将 TUN 网卡的 metric 调低
Set-NetIPInterface -InterfaceAlias "Mihomo" -InterfaceMetric 1
注意:AutomaticMetric 如果为 Enabled,系统会覆盖手动设置的值。需要先禁用:
Set-NetIPInterface -InterfaceAlias "以太网" -AutomaticMetric Disabled -InterfaceMetric 9999
六、WFP 规则失效的修复
WFP 是这次更新后最容易被忽略的层面。很多客户端在更新后 TUN 网卡能创建、路由也正确,但流量就是不走隧道,问题就出在 WFP。
6.1 检查 WFP 状态
# 查看 WFP 过滤器数量
netsh wfp show filters file="C:\wfp_filters.xml"
# 查看 WFP 状态
netsh wfp show state file="C:\wfp_state.xml"
# 查看特定提供者的过滤器
netsh wfp show filters provider="{Provider GUID}" file="C:\provider_filters.xml"
正常情况下,代理客户端注册的过滤器应该在 FWPM_LAYER_ALE_AUTH_CONNECT_V4 层中有较高权重。如果发现过滤器存在但权重很低,或者过滤器数量明显少于正常值,说明 WFP 规则被系统降权了。
6.2 修复方案:重建 WFP 规则
最直接的方法是重启代理客户端,让它重新注册 WFP 规则。但如果重启无效,可以尝试:
# 重启 Windows Filtering Platform 服务
Restart-Service -Name BFE -Force
# 重启代理客户端
Stop-Process -Name "mihomo" -Force
Start-Process "C:\path\to\mihomo.exe" -ArgumentList "-d", "C:\path\to\config"
如果还是不行,可能是系统内置的安全软件(如 Windows Defender 的网络保护)在更新后重新启用了对 WFP 的过滤。检查:
# 查看 Defender 网络保护状态
Get-MpPreference | Select-Object EnableNetworkProtection, EnableControlledFolderAccess
# 如果启用了,临时禁用测试
Set-MpPreference -EnableNetworkProtection Disabled
七、完整排查链路(按顺序执行)
以下是我们总结的排查链路,按顺序执行可以覆盖 95% 以上的故障场景:
第一步:确认 wintun 驱动状态
sc query wintun
Get-Item "C:\Windows\System32\drivers\wintun.sys" | Select-Object VersionInfo
第二步:确认 TUN 网卡创建
Get-NetAdapter | Where-Object {$_.Name -like "*Mihomo*" -or $_.Name -like "*TUN*"}
第三步:确认路由表
Get-NetRoute -DestinationPrefix "0.0.0.0/0" | Format-Table ifIndex, NextHop, RouteMetric
Get-NetRoute -DestinationPrefix "::/0" | Format-Table ifIndex, NextHop, RouteMetric
第四步:确认 DNS 配置
Get-DnsClientServerAddress | Format-Table -AutoSize
Get-DnsClientNrptRule | Format-Table -AutoSize
第五步:抓包验证
# 使用 pktmon 抓包(Windows 内置)
pktmon start --etw -c --comp nics
# 或者使用 Wireshark
# 过滤条件:udp.port == 53 或 tcp.port == 443
第六步:检查 WFP
netsh wfp show state file="C:\wfp_state.xml"
第七步:检查事件日志
Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=(Get-Date).AddHours(-1)} |
Where-Object {$_.Level -le 3} |
Select-Object TimeCreated, Id, ProviderName, Message -First 50
八、深度问答与避坑
Q1:为什么更新后 TUN 网卡能创建,但 ping 8.8.8.8 走物理网卡而不是 TUN?
这是典型的 WFP 规则降权问题。TUN 网卡创建成功只说明 wintun 驱动工作正常,但流量走哪块网卡由 WFP 和路由表共同决定。更新后 Windows 会重新评估 WFP 过滤器权重,系统内置的 FWPM_LAYER_ALE_AUTH_CONNECT_V4 层规则可能覆盖了代理客户端的规则。
排查方法:用 netsh wfp show filters 导出过滤器,搜索代理客户端注册的 provider,检查其 weight 值。正常应该在 0x0000000000000001 到 0x000000000000FFFF 之间,如果低于系统内置规则,就会被覆盖。
修复:启用客户端的 strict-route 选项,它会绕过 WFP 直接修改路由表。或者用 Set-NetIPInterface 把物理网卡的 metric 调到 9999。
Q2:DNS 泄漏只在 IPv6 上出现,IPv4 正常,这是什么原因?
这是 Windows 11 23H2 后期版本的一个特性变化。系统更新后,IPv6 临时地址的生成策略被调整,TemporaryAddressValidLifetime 默认值缩短,导致系统更频繁地生成新临时地址。代理客户端在网卡切换瞬间无法及时接管新地址,这个窗口期(实测 200~400ms)足够系统完成一次 DNS 解析。
修复:在 TUN 配置中显式声明 inet6-address,或者用 Set-NetIPv6Protocol 禁用物理网卡的临时地址生成。如果完全不需要 IPv6,直接在 TUN 配置中设置 disable-ipv6: true。
Q3:为什么更新后 TUN 模式下的 TCP 重传率从 0.8% 涨到了 2.7%?
这是 MTU 和 MSS 的问题。Windows 更新后,TUN 网卡的默认 MTU 可能被重置为 1500,而实际链路(尤其是经过 PPPoE 或 VPN 的场景)的 MTU 可能只有 1492 或更低。当 TUN 网卡 MTU 大于实际链路 MTU 时,大包会被分片,分片丢失后触发重传。
排查:用 ping -f -l 1472 8.8.8.8 测试实际 MTU。如果 1472 能通,MTU 是 1500;如果 1464 能通,MTU 是 1492。
修复:在 TUN 配置中设置 mtu: 1400 或更低。我们实测在大多数场景下,MTU 设置为 1380~1420 可以显著降低重传率。另外,可以在系统层面调整 TCP 参数:
# 查看当前 TCP 全局参数
netsh int tcp show global
# 启用 TCP 窗口缩放和 RSS
netsh int tcp set global autotuninglevel=normal
netsh int tcp set global rss=enabled
# 调整拥塞控制算法(Windows 11 支持 CUBIC 和 NewReno)
netsh int tcp set supplemental template=internet congestionprovider=cubic
Q4:为什么睡眠唤醒后 TUN 模式必然失效,需要手动重启客户端?
这是 Windows 11 电源管理策略和 WFP 生命周期的问题。睡眠唤醒后,系统会重新枚举所有网卡,包括 wintun 虚拟网卡。但代理客户端的 WFP 规则注册在系统睡眠时被挂起,唤醒后不会自动恢复。同时,物理网卡的 DHCP 续约和 NLA 重新评估会导致路由表短暂抖动。
修复方案有两个:
一是使用客户端的 auto-route 和 strict-route 选项,让客户端在网卡事件触发时自动重建路由和 WFP 规则。Mihomo 的 auto-detect-interface: true 配合 auto-route: true 可以覆盖大部分场景。
二是用计划任务在唤醒后自动重启客户端:
# 创建计划任务,在系统唤醒后重启代理
$action = New-ScheduledTaskAction -Execute "C:\path\to\restart_proxy.bat"
$trigger = New-ScheduledTaskTrigger -AtLogOn
$trigger.Delay = "PT5S"
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "RestartProxyOnWake" -Action $action -Trigger $trigger -Settings $settings
Q5:为什么 auto-route: true 在某些机器上反而导致无法上网?
auto-route: true 会让客户端自动修改系统路由表,把默认路由指向 TUN 网卡。但如果客户端在修改路由表时出错(比如 TUN 网卡还没完全初始化),会导致系统失去默认路由,完全无法上网。
排查:检查路由表是否有默认路由:
Get-NetRoute -DestinationPrefix "0.0.0.0/0"
如果没有输出,说明默认路由被删了。手动恢复:
# 找到物理网卡的 ifIndex
$physicalIndex = (Get-NetAdapter | Where-Object {$_.Status -eq "Up" -and $_.Name -notlike "*Mihomo*"}).ifIndex
# 恢复默认路由
New-NetRoute -DestinationPrefix "0.0.0.0/0" -InterfaceIndex $physicalIndex -NextHop (Get-NetIPConfiguration -InterfaceIndex $physicalIndex).IPv4DefaultGateway.NextHop
修复:在客户端配置中关闭 auto-route,改用手动路由脚本。或者使用 strict-route: true 配合 auto-route: true,后者会先验证 TUN 网卡状态再修改路由。
Q6:多个代理客户端同时运行时,TUN 网卡冲突怎么处理?
多个客户端同时运行会创建多个 TUN 网卡,每个都试图修改默认路由和 WFP 规则,结果就是路由表抖动和 WFP 规则冲突。我们实测发现,两个客户端同时运行时,DNS 泄漏率会从 34% 飙升到 78%。
处理方案:只保留一个客户端运行,其他客户端完全退出(不是最小化到托盘,而是结束进程)。如果确实需要多客户端,可以用不同的 TUN 网卡名称和不同的路由表策略,但这需要非常精细的配置,不建议普通用户尝试。
检查是否有多个 TUN 网卡:
Get-NetAdapter | Where-Object {$_.Name -like "*TUN*" -or $_.Name -like "*Mihomo*" -or $_.Name -like "*Clash*"}
如果有多个,逐个排查对应的进程:
Get-Process | Where-Object {$_.ProcessName -like "*mihomo*" -or $_.ProcessName -like "*clash*" -or $_.ProcessName -like "*sing-box*"}
Q7:更新后 pktmon 抓包显示流量进了 TUN,但代理日志显示没有收到流量,为什么?
这是 wintun Ring Buffer 的问题。wintun 驱动通过 Ring Buffer 在用户态和内核态之间传递数据包。如果 Ring Buffer 大小设置不当,或者驱动版本不匹配,会出现”包进了 TUN 但用户态读不到”的情况。
排查:
# 查看 wintun 驱动的事件日志
Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='wintun'} -MaxEvents 20
修复:更新 wintun 驱动到最新版本(0.14.1 或更高),或者在客户端配置中调整 Ring Buffer 大小。Mihomo 的 tun 配置中有 recvmsg-size 参数,可以尝试调整:
tun:
enable: true
stack: system
recvmsg-size: 65535
sendmsg-size: 65535
如果还是不行,尝试切换 stack 类型:gvisor 和 system 在不同的系统版本上表现不同。我们实测在 Build 22631.4169 上,gvisor 的兼容性更好,但在 Build 26100.x 上 system 表现更稳定。
以上就是这次 Windows 11 更新后 TUN 模式故障的完整排查和修复方案。核心思路是:不要只盯着客户端配置,要从驱动、WFP、路由表、DNS 四个层面逐层排查。大部分问题不是客户端本身的 bug,而是系统更新后底层网络策略的变化。修复的关键是让客户端在系统层面有更强的接管能力,而不是依赖系统默认行为。