fix: apple platform network switch fix (#2359)

* Apple platform network switch fix

* macos_ne exclusion fixed
This commit is contained in:
yyy-amnezia
2026-03-20 14:51:36 +02:00
committed by GitHub
parent 67bd880cdf
commit ddecfcad26
2 changed files with 54 additions and 9 deletions

View File

@@ -126,8 +126,13 @@ extension PacketTunnelProvider {
} }
vpnReachability.startTracking { [weak self] status in vpnReachability.startTracking { [weak self] status in
guard status == .reachableViaWiFi else { return } switch status {
self?.ovpnAdapter?.reconnect(afterTimeInterval: 5) case .reachableViaWiFi, .reachableViaWWAN:
ovpnLog(.info, message: "Reachability changed, reconnecting OpenVPN session")
self?.ovpnAdapter?.reconnect(afterTimeInterval: 1)
default:
break
}
} }
startHandler = completionHandler startHandler = completionHandler

View File

@@ -41,10 +41,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
var ovpnAdapter: OpenVPNAdapter? var ovpnAdapter: OpenVPNAdapter?
private lazy var openVPNPacketFlowAdapter = PacketTunnelFlowAdapter(flow: packetFlow) private lazy var openVPNPacketFlowAdapter = PacketTunnelFlowAdapter(flow: packetFlow)
private let pathMonitorQueue = DispatchQueue(label: Constants.processQueueName + ".path-monitor") private let pathMonitorQueue = DispatchQueue(label: Constants.processQueueName + ".path-monitor")
private let networkChangeQueue = DispatchQueue(label: Constants.processQueueName + ".network-change")
private let pathMonitor = NWPathMonitor() private let pathMonitor = NWPathMonitor()
private var didReceiveInitialPathUpdate = false private var didReceiveInitialPathUpdate = false
private var currentPath: Network.NWPath? private var currentPath: Network.NWPath?
private var currentPathSignature: String? private var currentPathSignature: String?
private var pendingNetworkChangeWorkItem: DispatchWorkItem?
private var isApplyingNetworkChange = false
var splitTunnelType: Int? var splitTunnelType: Int?
var splitTunnelSites: [String]? var splitTunnelSites: [String]?
@@ -78,14 +81,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
guard hasMeaningfulChange, let proto = self.protoType else { return } guard hasMeaningfulChange, let proto = self.protoType else { return }
// WireGuard/AWG manages network changes internally; avoid restarting the tunnel here. // OpenVPN and WireGuard/AWG handle network changes internally.
if proto == .wireguard { // Restarting them here can race their own reconnect logic and break tunnel setup.
if proto == .wireguard || proto == .openvpn {
return return
} }
DispatchQueue.main.async { self.scheduleNetworkChangeHandling(for: proto, path: path)
self.handle(networkChange: path) { _ in }
}
} }
pathMonitor.start(queue: pathMonitorQueue) pathMonitor.start(queue: pathMonitorQueue)
@@ -259,9 +261,47 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
} }
private func handle(networkChange changePath: Network.NWPath, completion: @escaping (Error?) -> Void) { private func handle(networkChange changePath: Network.NWPath, completion: @escaping (Error?) -> Void) {
guard protoType == .xray else {
updateActiveInterfaceIndex(for: changePath)
completion(nil)
return
}
updateActiveInterfaceIndex(for: changePath) updateActiveInterfaceIndex(for: changePath)
wg_log(.info, message: "Tunnel restarted.") reasserting = true
startTunnel(options: nil, completionHandler: completion) xrayLog(.info, message: "Applying network change to xray tunnel")
stopXray { }
startXray { [weak self] error in
self?.reasserting = false
completion(error)
}
}
private func scheduleNetworkChangeHandling(for proto: TunnelProtoType, path: Network.NWPath) {
guard proto == .xray else { return }
pendingNetworkChangeWorkItem?.cancel()
let workItem = DispatchWorkItem { [weak self] in
guard let self else { return }
if self.isApplyingNetworkChange {
xrayLog(.debug, message: "Skipping network change while restart is already in progress")
return
}
self.isApplyingNetworkChange = true
DispatchQueue.main.async {
self.handle(networkChange: path) { [weak self] _ in
self?.networkChangeQueue.async {
self?.isApplyingNetworkChange = false
}
}
}
}
pendingNetworkChangeWorkItem = workItem
networkChangeQueue.asyncAfter(deadline: .now() + 1.0, execute: workItem)
} }
} }