修复:macOS 网络切换与唤醒后恢复系统 DNS 和 TUN - #334
Closed
uclort wants to merge 2 commits into
Closed
Conversation
Contributor
Author
|
macOS 系统相关问题未修复,继续观察,稳定后重新提交 PR。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
这是对 #319 的后续修复。
上游已通过
00bd2157采纳了原 #320 中的系统 DNS 备份/恢复、退出恢复以及 TUN/总开关联动逻辑。本 PR 基于当前最新main(e553fe2b)重新整理,不重复提交或描述这些已合入内容,只处理 macOS 在运行期间发生网络环境变化时的恢复问题。典型场景均已脱敏:
223.5.5.5,但部分 DIRECT 请求持续 DNS 超时;重新切换 TUN 后恢复。相关修复版本已在真实使用环境中持续验证 2~3 天,上述场景未再次复现。
与此前提交的关系
#320 虽然处于关闭状态,但维护者已通过
00bd2157合入等价实现。本 PR 已排除其中的 DNS 备份、恢复、退出清理和开关联动代码,不会重复提交或重复描述已采纳内容。源代码存在的问题与修复
1. 同类型 Wi-Fi 切换可能没有进入恢复回调
源代码使用:
connectivity_plus的公开流会对连接类型列表执行去重。Wi-Fi「网络 A」切换到 Wi-Fi「网络 B」时,前后类型都可能仍为[wifi],事件因而被过滤,回调内的固定延迟和updateDns()根本不会执行。macOS 新逻辑改为监听平台原始事件,其他平台仍保留原实现:
这项改动只绕过 macOS 上的 Dart 层去重,不改变 Android、Windows、Linux 等平台的事件语义。
2. 固定等待 1 秒无法确认 DHCP、默认路由和网络服务已经稳定
源代码在收到事件后固定等待 1 秒,再按当时的默认路由更新 DNS。网络切换过程中,这一时刻仍可能读到旧接口、旧网关或未完成的 DHCP 信息。
新逻辑读取并比较两次默认网络指纹:
只有连续采样一致后才优先执行恢复;最多重试 5 次,并允许更新的网络事件取消旧任务。这样既能识别同一接口上的 Wi-Fi/租约变化,也避免把 DNS 写入刚刚失效的网络服务。
3. 系统 DNS 需要从旧服务迁移到当前服务
原有备份/恢复能力已经由上游实现,但网络切换时
_setDns()会再次自行查找默认服务,恢复流程与写入流程之间若默认路由继续变化,可能操作不同服务。新逻辑把稳定采样得到的服务名传入同一 DNS 临界区:
启用自动系统 DNS 时,当前服务只写入 Bettbox 接管地址:
原始 DNS 仍沿用上游现有逻辑持久化备份,并在停用、退出或迁移服务时恢复。这样避免 DHCP DNS 排在
223.5.5.5前面绕过接管,同时没有改变关闭 Bettbox 后由系统自动获取 DNS 的行为。4. 只刷新 DNS/连接无法修复失效的 TUN 数据面
源代码在网络变化后主要关闭连接并重写系统 DNS。实际故障中,Mihomo 的 TUN listener、默认出口和路由仍可能保留切换前状态,因此会出现“系统 DNS 正确,但必须手动切换 TUN 才恢复”的现象。
新逻辑在 Bettbox 已启动且 TUN 已开启时执行一次受控重建:
恢复顺序为:临时关闭 Core TUN → 停止 listener → 关闭旧连接并迁移系统 DNS → 清理 Core DNS/Fake-IP 缓存 → 重启 listener → 重新应用 TUN。临时关闭不会写入用户偏好,因此不会把恢复过程误保存为用户主动关闭 TUN。
5. 覆盖安装并授权辅助工具后的 TUN 启动顺序不完整
源代码可能先进入全局启动流程,再异步应用 TUN;如果授权过程要求重启 Core,listener 和配置应用之间会出现时序窗口,界面状态可能已开启,但 TUN 数据面没有完整建立。
新逻辑把 macOS 启动调整为原子顺序:
任一步失败都会显式中止;若应用 TUN 失败,会停止刚启动的 listener,避免留下半启动状态。非 macOS 的启动路径保持上游行为。
6. macOS 唤醒不一定产生可用的网络类型事件
锁屏/休眠后,网络类型和默认网络指纹都可能与休眠前相同,但底层 socket、路由或 TUN 状态已经失效。仅监听 connectivity 事件无法可靠覆盖这一场景。
本 PR 在 macOS 原生层监听:
事件通过现有
appMethodChannel 发送到 Dart,并强制执行一次稳定检测与恢复;Swift 观察者在窗口释放时同步注销。该桥接仅存在于 macOS Runner。7. 新网络事件与手动停止不能共用同一种取消语义
网络连续变化可能排队多个恢复任务;若用户主动停止或退出,较旧任务不应在停止完成后重新开启 listener/TUN。源代码最初使用同一个
recoveryCancelled()同时表示“出现了更新的网络事件”和“用户主动停止/退出”,并把它传给 TUN 重建的finally。唤醒恢复会主动关闭旧 TUN,这个动作本身也可能产生 connectivity 事件。新事件递增调度 generation 后,正在执行的恢复会被判定为过期;旧实现随后跳过
startListener()和重新启用 TUN,可能留下“旧 TUN 已关闭、新 TUN 未启动”的半完成状态。此时日志可出现batch read packet: bad file descriptor,界面仍显示运行,但实际流量需要重新加载 Core 才能恢复。修复将取消条件拆为两级:
finally必须先恢复 listener/TUN,不能把数据面留在关闭状态。finally保持 listener/TUN 关闭。isLifecycleCancelled: lifecycleCancelled,这样既保留“手动停止优先于后台恢复”的原设计,也避免唤醒恢复被自身产生的 connectivity 事件打断。
平台边界与明确排除项
proxy-server-nameserver;此前相关现象已确认来自用户配置,不属于 Bettbox 代码问题。验证
flutter analyze:通过,无问题。flutter test:20/20 通过。Follow-up to #319