fix(macos): killswitch 撤掉 includeAllNetworks(堵死整机网络) — 改 enforceRoutes+on-demand
实测 includeAllNetworks=true 把所有流量(含 sing-box 连服务器握手、app 调控制面 请求)在隧道建起前就塞进隧道 → 握手出不去 → 连接失败 + on-demand 死循环 + 整机 断网(连「我的」页账户信息都拉不到、显示 —)。 改为不会误伤握手/控制面的组合: - configureKillSwitch:includeAllNetworks 恒 false;保留 enforceRoutes(连接期防漏) + excludeLocalNetworks + NEOnDemandRule 常开(兜重连) - 撤回 start() 的 killSwitch option 及扩展侧 includeAllNetworks 透传(回 false) - 诚实标注:当前 L1→L2 之间,未到 includeAllNetworks-L3;要拿「扛进程被杀」须先 在扩展内放行服务器/控制面连接,留待真机验证 docs/killswitch-design.html: §6.5 加踩坑修正、状态表 macOS 改「L1→L2 之间」 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -63,12 +63,7 @@ final class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
LibboxSetup(setup, &setupErr)
|
||||
if let setupErr { throw setupErr }
|
||||
|
||||
// KillSwitch:主 app 经 startVPNTunnel options 下发;OS on-demand 自动拉起时
|
||||
// options 为 nil → 默认 true(on-demand 仅在 killswitch 开时存在)。libbox 平台回调
|
||||
// includeAllNetworks() 据此与 NE 层 includeAllNetworks 对齐,避免装绕行路由。
|
||||
let killSwitch = (options?["killSwitch"] as? NSNumber)?.boolValue ?? true
|
||||
log.info("startTunnel: killSwitch=\(killSwitch, privacy: .public)")
|
||||
let platform = PangolinPlatformInterface(provider: self, includeAllNetworks: killSwitch)
|
||||
let platform = PangolinPlatformInterface(provider: self)
|
||||
self.platform = platform
|
||||
|
||||
var newErr: NSError?
|
||||
@@ -187,11 +182,9 @@ final class PangolinPlatformInterface: NSObject, LibboxPlatformInterfaceProtocol
|
||||
private var monitor: NWPathMonitor?
|
||||
private var defaultInterfaceIndex: Int32 = -1
|
||||
private let monitorQueue = DispatchQueue(label: "pangolin.tunnel.pathmonitor")
|
||||
private let includeAllNetworksFlag: Bool
|
||||
|
||||
init(provider: NEPacketTunnelProvider, includeAllNetworks: Bool) {
|
||||
init(provider: NEPacketTunnelProvider) {
|
||||
self.provider = provider
|
||||
self.includeAllNetworksFlag = includeAllNetworks
|
||||
super.init()
|
||||
}
|
||||
|
||||
@@ -276,7 +269,7 @@ final class PangolinPlatformInterface: NSObject, LibboxPlatformInterfaceProtocol
|
||||
// MARK: 其余协议方法(取合理默认)
|
||||
func underNetworkExtension() -> Bool { true }
|
||||
func useProcFS() -> Bool { false }
|
||||
func includeAllNetworks() -> Bool { includeAllNetworksFlag }
|
||||
func includeAllNetworks() -> Bool { false }
|
||||
func clearDNSCache() {}
|
||||
func readWIFIState() -> LibboxWIFIState? { nil }
|
||||
func systemCertificates() -> (any LibboxStringIteratorProtocol)? { nil }
|
||||
|
||||
@@ -131,7 +131,6 @@ final class VpnChannel: NSObject {
|
||||
vpnLog("step③ startVPNTunnel(options: configContent) …")
|
||||
try mgr.connection.startVPNTunnel(options: [
|
||||
"configContent": configJson as NSString,
|
||||
"killSwitch": NSNumber(value: killSwitchEnabled),
|
||||
])
|
||||
vpnLog("step③ startVPNTunnel 调用已返回(实际起停由 NEVPNStatus 流驱动)✓")
|
||||
result(nil)
|
||||
@@ -181,14 +180,18 @@ final class VpnChannel: NSObject {
|
||||
|
||||
// ── KillSwitch(断网保护)NE 配置 ────────────────────────────────
|
||||
// 把当前 killSwitchEnabled 写入 manager 的 NE 字段(不保存,由调用方保存):
|
||||
// L2 OS 强制:includeAllNetworks=true 全量入隧道 + enforceRoutes=true 隧道路由优先,
|
||||
// 非隧道流量被 neagent 系统级阻断(扛 app/内核崩溃)。
|
||||
// L3 常开:NEOnDemandRule 让 OS 在掉线/开机窗口自动拉起隧道,全程 fail-closed。
|
||||
// excludeLocalNetworks=true 放行 LAN(打印机/AirPlay 等),不影响防泄漏目标。
|
||||
// enforceRoutes=true:隧道 includedRoutes(0.0.0.0/0 默认路由)优先于物理接口,
|
||||
// 连接期间所有流量强制走隧道、不从旁路接口泄漏。
|
||||
// NEOnDemandRule 常开:OS 在掉线/开机窗口自动拉起隧道,缩小重连缺口。
|
||||
// excludeLocalNetworks=true:放行 LAN(打印机/AirPlay 等),不影响防泄漏目标。
|
||||
// ⚠️ 刻意不设 includeAllNetworks:它会把「所有」流量(含 sing-box 连服务器的握手、
|
||||
// app 调控制面的请求)在隧道建起来前就塞进隧道 → 握手出不去 → 连接失败 + on-demand
|
||||
// 死循环 + 整机断网(实测)。要拿「扛进程被杀」那一档须先在扩展内正确放行服务器/
|
||||
// 控制面连接,留待真机验证后再评估,见 docs/killswitch-design.html §6.5。
|
||||
// enforceRoutes/excludeLocalNetworks 为 macOS 11+ API,Runner 部署目标 10.15 → #available 守卫。
|
||||
private func configureKillSwitch(on mgr: NETunnelProviderManager) {
|
||||
if let proto = mgr.protocolConfiguration as? NETunnelProviderProtocol {
|
||||
proto.includeAllNetworks = killSwitchEnabled
|
||||
proto.includeAllNetworks = false
|
||||
if #available(macOS 11.0, *) {
|
||||
proto.enforceRoutes = killSwitchEnabled
|
||||
proto.excludeLocalNetworks = true
|
||||
@@ -203,7 +206,7 @@ final class VpnChannel: NSObject {
|
||||
mgr.onDemandRules = []
|
||||
mgr.isOnDemandEnabled = false
|
||||
}
|
||||
vpnLog(" killSwitch 配置: includeAllNetworks=\(killSwitchEnabled) enforceRoutes=\(killSwitchEnabled) onDemand=\(killSwitchEnabled)")
|
||||
vpnLog(" killSwitch 配置: enforceRoutes=\(killSwitchEnabled) onDemand=\(killSwitchEnabled) includeAllNetworks=false")
|
||||
}
|
||||
|
||||
/// 即时应用 killswitch(改字段 + 保存 + 重载)。供 setKillSwitch 在 manager 已装配时调用。
|
||||
|
||||
Reference in New Issue
Block a user