diff --git a/swift/apple/FirezoneNetworkExtension/Adapter.swift b/swift/apple/FirezoneNetworkExtension/Adapter.swift index 0d64c4fb2..27f051f09 100644 --- a/swift/apple/FirezoneNetworkExtension/Adapter.swift +++ b/swift/apple/FirezoneNetworkExtension/Adapter.swift @@ -58,6 +58,11 @@ class Adapter { private var gateways: [Network.NWEndpoint] = [] #endif +#if os(macOS) + /// Used for finding system DNS resolvers on macOS when network conditions have changed. + private let systemConfigurationResolvers = SystemConfigurationResolvers() +#endif + /// Track our last fetched DNS resolvers to know whether to tell connlib they've updated private var lastFetchedResolvers: [String] = [] @@ -453,7 +458,7 @@ extension Adapter: CallbackHandlerDelegate { private func getSystemDefaultResolvers(interfaceName: String?) -> [String] { #if os(macOS) - let resolvers = SystemConfigurationResolvers().getDefaultDNSServers( + let resolvers = self.systemConfigurationResolvers.getDefaultDNSServers( interfaceName: interfaceName) #elseif os(iOS) let resolvers = resetToSystemDNSGettingBindResolvers() diff --git a/swift/apple/FirezoneNetworkExtension/SystemConfigurationResolvers.swift b/swift/apple/FirezoneNetworkExtension/SystemConfigurationResolvers.swift index c94a49188..b10acfc0e 100644 --- a/swift/apple/FirezoneNetworkExtension/SystemConfigurationResolvers.swift +++ b/swift/apple/FirezoneNetworkExtension/SystemConfigurationResolvers.swift @@ -26,23 +26,30 @@ class SystemConfigurationResolvers { } } } - private var dynamicStore: SCDynamicStore? + + /// We use a computed property to memoize the creation of SC Dynamic Store, since this + /// can fail in some circumstances to initialize, like because of allocation failures. + private var _dynamicStore: SCDynamicStore? + private var dynamicStore: SCDynamicStore? { + get { + if self._dynamicStore == nil { + guard let dynamicStore = SCDynamicStoreCreate(nil, storeName, nil, nil) + else { + let code = SCError() + Log.error(SystemConfigurationError.failedToCreateDynamicStore(code: code)) + return nil + } + + self._dynamicStore = dynamicStore + } + + return self._dynamicStore + } + } // Arbitrary name for the connection to the store private let storeName = "dev.firezone.firezone.dns" as CFString - init() { - guard let dynamicStore = SCDynamicStoreCreate(nil, storeName, nil, nil) - else { - let code = SCError() - Log.error(SystemConfigurationError.failedToCreateDynamicStore(code: code)) - self.dynamicStore = nil - return - } - - self.dynamicStore = dynamicStore - } - /// 1. First, find the service ID that corresponds to the interface we're interested in. /// We do this by searching the configuration store at "Setup:/Network/Service//Interface" /// for a matching "InterfaceName".