diff options
4 files changed, 58 insertions, 58 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index a5bc1234df..937a3ae636 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -3620,7 +3620,7 @@ repositoryURL = "https://github.com/mullvad/wireguard-apple.git"; requirement = { kind = revision; - revision = 309bb8d58a3ed25ff11c4630b88bbe883e53e835; + revision = 68e84fb1083637d90c6a9ef41193f940569af0f3; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d47178827b..685bd558b2 100644 --- a/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,7 +14,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mullvad/wireguard-apple.git", "state" : { - "revision" : "309bb8d58a3ed25ff11c4630b88bbe883e53e835" + "revision" : "68e84fb1083637d90c6a9ef41193f940569af0f3" } } ], diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift index 4a7e10e471..c388b1519d 100644 --- a/ios/PacketTunnel/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider.swift @@ -160,7 +160,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { } ) - tunnelMonitor = TunnelMonitor(delegateQueue: dispatchQueue, adapter: adapter) + tunnelMonitor = TunnelMonitor( + delegateQueue: dispatchQueue, + packetTunnelProvider: self, + adapter: adapter + ) tunnelMonitor.delegate = self } diff --git a/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift b/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift index d1ceddad40..f47ecaf98f 100644 --- a/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift +++ b/ios/PacketTunnel/TunnelMonitor/TunnelMonitor.swift @@ -55,7 +55,7 @@ final class TunnelMonitor: PingerDelegate { case stopped /// Preparing to start. - /// Intermediate state before recieving the first path update. + /// Intermediate state before receiving the first path update. case pendingStart /// Establishing connection. @@ -228,7 +228,8 @@ final class TunnelMonitor: PingerDelegate { private let delegateQueue: DispatchQueue private let pinger: Pinger - private var pathMonitor: NWPathMonitor? + private weak var packetTunnelProvider: NEPacketTunnelProvider? + private var defaultPathObserver: NSKeyValueObservation? private var timer: DispatchSourceTimer? private var state = State() @@ -252,11 +253,16 @@ final class TunnelMonitor: PingerDelegate { } } - init(delegateQueue: DispatchQueue, adapter anAdapter: WireGuardAdapter) { + init( + delegateQueue: DispatchQueue, + packetTunnelProvider: NEPacketTunnelProvider, + adapter: WireGuardAdapter + ) { self.delegateQueue = delegateQueue - adapter = anAdapter + self.packetTunnelProvider = packetTunnelProvider + self.adapter = adapter - pinger = Pinger(delegateQueue: delegateQueue) + pinger = Pinger(delegateQueue: eventQueue) pinger.delegate = self } @@ -278,7 +284,7 @@ final class TunnelMonitor: PingerDelegate { self.probeAddress = probeAddress state.connectionState = .pendingStart - startPathMonitor() + addDefaultPathObserver() } func stop() { @@ -297,10 +303,10 @@ final class TunnelMonitor: PingerDelegate { switch state.connectionState { case .connecting, .connected: startConnectivityCheckTimer() - startPathMonitor() + addDefaultPathObserver() case .waitingConnectivity, .pendingStart: - startPathMonitor() + addDefaultPathObserver() case .stopped, .recovering: break @@ -314,7 +320,7 @@ final class TunnelMonitor: PingerDelegate { logger.trace("Prepare to sleep.") stopConnectivityCheckTimer() - stopPathMonitor() + removeDefaultPathObserver() } // MARK: - PingerDelegate @@ -347,41 +353,53 @@ final class TunnelMonitor: PingerDelegate { probeAddress = nil - stopPathMonitor() + removeDefaultPathObserver() stopMonitoring(resetRetryAttempt: !forRestart) state.connectionState = .stopped } - private func startPathMonitor() { - let pathMonitor = NWPathMonitor() - pathMonitor.pathUpdateHandler = { [weak self] path in - self?.handleNetworkPathUpdate(path) - } - pathMonitor.start(queue: eventQueue) + private func addDefaultPathObserver() { + guard let packetTunnelProvider = packetTunnelProvider else { return } + + defaultPathObserver?.invalidate() - self.pathMonitor?.cancel() - self.pathMonitor = pathMonitor + logger.trace("Add default path observer.") - logger.trace("Start path monitor.") + defaultPathObserver = packetTunnelProvider + .observe(\.defaultPath, options: [.new]) { [weak self] _, change in + guard let self = self else { return } + + self.nslock.lock() + defer { self.nslock.unlock() } + + let newValue = change.newValue.flatMap { $0 } + if let newPath = newValue { + self.handleNetworkPathUpdate(newPath) + } + } + + if let currentPath = packetTunnelProvider.defaultPath { + handleNetworkPathUpdate(currentPath) + } } - private func stopPathMonitor() { - guard let pathMonitor = pathMonitor else { return } + private func removeDefaultPathObserver() { + guard let defaultPathObserver = defaultPathObserver else { return } - logger.trace("Stop path monitor.") + logger.trace("Remove default path observer.") - pathMonitor.cancel() - self.pathMonitor = nil + defaultPathObserver.invalidate() + self.defaultPathObserver = nil } private func checkConnectivity() { nslock.lock() defer { nslock.unlock() } - guard let probeAddress = probeAddress, let newStats = getStats() else { - return - } + guard let probeAddress = probeAddress, let newStats = getStats(), + state.connectionState == .connecting || state.connectionState == .connected + else { return } // Check if counters were reset. let isStatsReset = newStats.bytesReceived < state.netStats.bytesReceived || @@ -444,7 +462,7 @@ final class TunnelMonitor: PingerDelegate { #endif private func startConnectionRecovery() { - stopPathMonitor() + removeDefaultPathObserver() stopMonitoring(resetRetryAttempt: false) state.retryAttempt = state.retryAttempt.saturatingAddition(1) @@ -465,25 +483,13 @@ final class TunnelMonitor: PingerDelegate { } } - private func handleNetworkPathUpdate(_ networkPath: Network.NWPath) { - nslock.lock() - defer { nslock.unlock() } - + private func handleNetworkPathUpdate(_ networkPath: NetworkExtension.NWPath) { let pathStatus = networkPath.status - let isReachable = pathStatus == .requiresConnection || pathStatus == .satisfied - let hasPhysicalNetworkInterface = networkPath.availableInterfaces.contains { nw in - return nw.type == .wifi || nw.type == .cellular || nw.type == .wiredEthernet - } - - lazy var isRoutableViaUtun = isTunnelInterfaceUp(networkPath) && - hasPhysicalNetworkInterface && isReachable + let isReachable = pathStatus == .satisfiable || pathStatus == .satisfied switch state.connectionState { case .pendingStart: - // Wait for tunnel interface to appear first. - guard isTunnelInterfaceUp(networkPath) else { return } - - if isReachable, hasPhysicalNetworkInterface { + if isReachable { logger.debug("Start monitoring connection.") startMonitoring() sendDelegateNetworkStatusChange(true) @@ -494,14 +500,14 @@ final class TunnelMonitor: PingerDelegate { } case .waitingConnectivity: - guard isRoutableViaUtun else { return } + guard isReachable else { return } logger.debug("Network is reachable. Resume monitoring.") startMonitoring() sendDelegateNetworkStatusChange(true) case .connecting, .connected: - guard !isRoutableViaUtun else { return } + guard !isReachable else { return } logger.debug("Network is unreachable. Pause monitoring.") state.connectionState = .waitingConnectivity @@ -664,14 +670,4 @@ final class TunnelMonitor: PingerDelegate { return newStats } - - private func isTunnelInterfaceUp(_ networkPath: Network.NWPath) -> Bool { - guard let tunName = adapter.interfaceName else { return false } - - let utunUp = networkPath.availableInterfaces.contains { interface in - return interface.name == tunName - } - - return utunUp - } } |
