From 87c16ea95cb320742fbdda73bbb5e1d1a923938d Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Fri, 17 Jan 2025 12:31:13 -0500 Subject: [PATCH] Fix iOS 16 support (#222) In older versions of iOS, it's not possible to call `NETunnelProviderManager.loadAllFromPreferences()` from inside the network extension process. We were seeing `NETunnelProviderManager objects cannot be instantiated from NEProvider processes` errors in iOS 16. It's unclear exactly when the change happened to allow it, but as far as we can tell it was in iOS 17. To Test: 1. On a real device running iOS 16, ensure that enrolling as a Managed Nebula host works correctly. 2. Start the site. 3. Update the host in the admin panel and wait at least 15 minutes for a `checkForUpdate` from the mobile client. You should get a `Host renewed` audit log for the host. 4. Verify that there's a log for "Reloading Nebula" in the mobile host, and that it has an up-to-date config. --- .../PacketTunnelProvider.swift | 20 ++++++++++++------- ios/Runner/DNUpdate.swift | 5 ++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift index 07c1cb1..dffb054 100644 --- a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift +++ b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift @@ -52,14 +52,20 @@ class PacketTunnelProvider: NEPacketTunnelProvider { var config: Data var key: String - manager = try await self.findManager() - - guard let foundManager = manager else { - throw VPNStartError.couldNotFindManager - } - do { - self.site = try Site(manager: foundManager) + // Cannot use NETunnelProviderManager.loadAllFromPreferences() in earlier versions of iOS + // TODO: Remove else once we drop support for iOS 16 + if ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 17, minorVersion: 0, patchVersion: 0)) { + manager = try await self.findManager() + guard let foundManager = manager else { + throw VPNStartError.couldNotFindManager + } + self.site = try Site(manager: foundManager) + } else { + // This does not save the manager with the site, which means we cannot update the + // vpn profile name when updates happen (rare). + self.site = try Site(proto: self.protocolConfiguration as! NETunnelProviderProtocol) + } config = try self.site!.getConfig() } catch { //TODO: need a way to notify the app diff --git a/ios/Runner/DNUpdate.swift b/ios/Runner/DNUpdate.swift index 5b59e27..fd566ea 100644 --- a/ios/Runner/DNUpdate.swift +++ b/ios/Runner/DNUpdate.swift @@ -63,7 +63,10 @@ class DNUpdater { return } - newSite?.save(manager: site.manager) { error in + let siteManager = site.manager + let shouldSaveToManager = siteManager != nil || ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 17, minorVersion: 0, patchVersion: 0)) + + newSite?.save(manager: site.manager, saveToManager: shouldSaveToManager) { error in if (error != nil) { self.log.error("failed to save update: \(error!.localizedDescription, privacy: .public)") }