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:
wangjia
2026-07-01 06:09:04 +08:00
parent 97c0fdbbad
commit a32d87c9c0
3 changed files with 32 additions and 35 deletions
@@ -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 }
+10 -7
View File
@@ -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