]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
Revert "[REVERT ME SOON] TunnelsManager: Workaround for macOS Catalina deleting tunne...
authorJason A. Donenfeld <Jason@zx2c4.com>
Fri, 11 Dec 2020 11:50:31 +0000 (12:50 +0100)
committerJason A. Donenfeld <Jason@zx2c4.com>
Fri, 11 Dec 2020 11:51:16 +0000 (12:51 +0100)
This reverts commit 028e76eb3fda127d84eb88dc5cb96d4278f37b96.

It's been over a year. I really hope this is fixed by Apple.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Sources/WireGuardApp/Tunnel/TunnelsManager.swift

index dea541febbc26547273459c63f47bf37095becc7..024c3fd10e448c25d5148bb88fb163a55a0ab518 100644 (file)
@@ -20,23 +20,17 @@ protocol TunnelsManagerActivationDelegate: class {
 }
 
 class TunnelsManager {
-    fileprivate var tunnels: [TunnelContainer]
+    private var tunnels: [TunnelContainer]
     weak var tunnelsListDelegate: TunnelsManagerListDelegate?
     weak var activationDelegate: TunnelsManagerActivationDelegate?
     private var statusObservationToken: AnyObject?
     private var waiteeObservationToken: AnyObject?
     private var configurationsObservationToken: AnyObject?
-    private var catalinaWorkaround: Any?
 
     init(tunnelProviders: [NETunnelProviderManager]) {
         tunnels = tunnelProviders.map { TunnelContainer(tunnel: $0) }.sorted { TunnelsManager.tunnelNameIsLessThan($0.name, $1.name) }
         startObservingTunnelStatuses()
         startObservingTunnelConfigurations()
-        #if os(macOS)
-        if #available(macOS 10.15, *) {
-            self.catalinaWorkaround = CatalinaWorkaround(tunnelsManager: self)
-        }
-        #endif
     }
 
     static func create(completionHandler: @escaping (Result<TunnelsManager, TunnelsManagerError>) -> Void) {
@@ -81,15 +75,7 @@ class TunnelsManager {
                     tunnelManagers.remove(at: index)
                 }
             }
-            #if os(macOS)
-            if #available(macOS 10.15, *) {
-                // Don't delete orphaned keychain refs. We need them to restore tunnels as a workaround.
-            } else {
-                Keychain.deleteReferences(except: refs)
-            }
-            #else
             Keychain.deleteReferences(except: refs)
-            #endif
             #if os(iOS)
             RecentTunnelsTracker.cleanupTunnels(except: tunnelNames)
             #endif
@@ -636,7 +622,7 @@ class TunnelContainer: NSObject {
 }
 
 extension NETunnelProviderManager {
-    fileprivate static var cachedConfigKey: UInt8 = 0
+    private static var cachedConfigKey: UInt8 = 0
 
     var tunnelConfiguration: TunnelConfiguration? {
         if let cached = objc_getAssociatedObject(self, &NETunnelProviderManager.cachedConfigKey) as? TunnelConfiguration {
@@ -659,148 +645,3 @@ extension NETunnelProviderManager {
         return localizedDescription == tunnel.name && tunnelConfiguration == tunnel.tunnelConfiguration
     }
 }
-
-#if os(macOS)
-@available(macOS 10.15, *)
-class CatalinaWorkaround {
-
-    // In macOS Catalina, for some users, the tunnels get deleted arbitrarily
-    // by the OS. It's not clear what triggers that.
-
-    // As a workaround, in macOS Catalina, when we realize that tunnels have been
-    // deleted outside the app, we reinstate those tunnels using the information
-    // in the keychain.
-
-    unowned let tunnelsManager: TunnelsManager
-    private var configChangeSubscriber: Any?
-
-    struct ReinstationData {
-        let tunnelConfiguration: TunnelConfiguration
-        let keychainPasswordRef: Data
-    }
-
-    init(tunnelsManager: TunnelsManager) {
-        self.tunnelsManager = tunnelsManager
-
-        // Attempt reinstation when there's a change in tunnel configurations,
-        // which indicates that tunnels may have been deleted outside the app.
-        // We use debounce to wait for all change notifications to arrive
-        // before attempting to reinstate, so that we don't have saveToPreferences
-        // being called while another saveToPreferences is in progress.
-        self.configChangeSubscriber = NotificationCenter.default
-            .publisher(for: .NEVPNConfigurationChange, object: nil)
-            .debounce(for: .seconds(1), scheduler: RunLoop.main)
-            .subscribe(on: RunLoop.main)
-            .sink { [weak self] _ in
-                self?.reinstateTunnelsDeletedOutsideApp()
-        }
-
-        // Attempt reinstation on app launch
-        reinstateTunnelsDeletedOutsideApp()
-    }
-
-    func reinstateTunnelsDeletedOutsideApp() {
-        let data = reinstationDataForTunnelsDeletedOutsideApp()
-        reinstateTunnels(ArraySlice(data), completionHandler: nil)
-    }
-
-    private func reinstateTunnels(_ rdArray: ArraySlice<ReinstationData>, completionHandler: (() -> Void)?) {
-        guard let head = rdArray.first else {
-            completionHandler?()
-            return
-        }
-        let tail = rdArray.dropFirst()
-        self.tunnelsManager.reinstateTunnel(reinstationData: head) { _ in
-            DispatchQueue.main.async {
-                self.reinstateTunnels(tail, completionHandler: completionHandler)
-            }
-        }
-    }
-
-    private func reinstationDataForTunnelsDeletedOutsideApp() -> [ReinstationData] {
-        let knownRefs: [Data] = self.tunnelsManager.tunnels
-            .compactMap { $0.tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol }
-            .compactMap { $0.passwordReference }
-        let knownRefsSet: Set<Data> = Set(knownRefs)
-        var result: CFTypeRef?
-        let ret = SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
-                                       kSecAttrService as String: Bundle.main.bundleIdentifier as Any,
-                                       kSecMatchLimit as String: kSecMatchLimitAll,
-                                       kSecReturnAttributes as String: true,
-                                       kSecReturnPersistentRef as String: true] as CFDictionary,
-                                      &result)
-        guard ret == errSecSuccess, let resultDicts = result as? [[String: Any]] else { return [] }
-        let labelPrefix = "WireGuard Tunnel: "
-        var reinstationData: [ReinstationData] = []
-        for resultDict in resultDicts {
-            guard let ref = resultDict[kSecValuePersistentRef as String] as? Data else { continue }
-            guard let label = resultDict[kSecAttrLabel as String] as? String else { continue }
-            guard label.hasPrefix(labelPrefix) else { continue }
-            if !knownRefsSet.contains(ref) {
-                let tunnelName = String(label.dropFirst(labelPrefix.count))
-                if let configStr = Keychain.openReference(called: ref),
-                    let config = try? TunnelConfiguration(fromWgQuickConfig: configStr, called: tunnelName) {
-                    reinstationData.append(ReinstationData(tunnelConfiguration: config, keychainPasswordRef: ref))
-                }
-            }
-        }
-        return reinstationData
-    }
-}
-#endif
-
-#if os(macOS)
-@available(macOS 10.15, *)
-extension TunnelsManager {
-    fileprivate func reinstateTunnel(reinstationData: CatalinaWorkaround.ReinstationData, completionHandler: @escaping (Bool) -> Void) {
-        let tunnelName = reinstationData.tunnelConfiguration.name ?? ""
-        if tunnelName.isEmpty {
-            completionHandler(false)
-            return
-        }
-
-        if tunnels.contains(where: { $0.name == tunnelName }) {
-            completionHandler(false)
-            return
-        }
-
-        let tunnelProviderProtocol = NETunnelProviderProtocol()
-        guard let appId = Bundle.main.bundleIdentifier else { fatalError() }
-        tunnelProviderProtocol.providerBundleIdentifier = "\(appId).network-extension"
-        tunnelProviderProtocol.passwordReference = reinstationData.keychainPasswordRef
-        tunnelProviderProtocol.providerConfiguration = ["UID": getuid()]
-        tunnelProviderProtocol.serverAddress = {
-            let endpoints = reinstationData.tunnelConfiguration.peers.compactMap { $0.endpoint }
-            if endpoints.count == 1 {
-                return endpoints[0].stringRepresentation
-            } else if endpoints.isEmpty {
-                return "Unspecified"
-            } else {
-                return "Multiple endpoints"
-            }
-        }()
-
-        let tunnelProvider = NETunnelProviderManager()
-        tunnelProvider.localizedDescription = tunnelName
-        tunnelProvider.protocolConfiguration = tunnelProviderProtocol
-        objc_setAssociatedObject(tunnelProvider, &NETunnelProviderManager.cachedConfigKey, reinstationData.tunnelConfiguration, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
-        tunnelProvider.isEnabled = true
-
-        tunnelProvider.saveToPreferences { [weak self] error in
-            guard error == nil else {
-                wg_log(.error, message: "Reinstate: Saving configuration failed: \(error!)")
-                completionHandler(false)
-                return
-            }
-
-            guard let self = self else { return }
-
-            let tunnel = TunnelContainer(tunnel: tunnelProvider)
-            self.tunnels.append(tunnel)
-            self.tunnels.sort { TunnelsManager.tunnelNameIsLessThan($0.name, $1.name) }
-            self.tunnelsListDelegate?.tunnelAdded(at: self.tunnels.firstIndex(of: tunnel)!)
-            completionHandler(true)
-        }
-    }
-}
-#endif