diff options
Diffstat (limited to 'Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift')
-rw-r--r-- | Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift b/Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift new file mode 100644 index 0000000..c75e9c5 --- /dev/null +++ b/Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved. + +import NetworkExtension +import WireGuardKit + +enum PacketTunnelProviderError: String, Error { + case savedProtocolConfigurationIsInvalid + case dnsResolutionFailure + case couldNotStartBackend + case couldNotDetermineFileDescriptor + case couldNotSetNetworkSettings +} + +extension NETunnelProviderProtocol { + convenience init?(tunnelConfiguration: TunnelConfiguration, previouslyFrom old: NEVPNProtocol? = nil) { + self.init() + + guard let name = tunnelConfiguration.name else { return nil } + guard let appId = Bundle.main.bundleIdentifier else { return nil } + providerBundleIdentifier = "\(appId).network-extension" + passwordReference = Keychain.makeReference(containing: tunnelConfiguration.asWgQuickConfig(), called: name, previouslyReferencedBy: old?.passwordReference) + if passwordReference == nil { + return nil + } + #if os(macOS) + providerConfiguration = ["UID": getuid()] + #endif + + let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint } + if endpoints.count == 1 { + serverAddress = endpoints[0].stringRepresentation + } else if endpoints.isEmpty { + serverAddress = "Unspecified" + } else { + serverAddress = "Multiple endpoints" + } + } + + func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? { + if let passwordReference = passwordReference, + let config = Keychain.openReference(called: passwordReference) { + return try? TunnelConfiguration(fromWgQuickConfig: config, called: name) + } + if let oldConfig = providerConfiguration?["WgQuickConfig"] as? String { + return try? TunnelConfiguration(fromWgQuickConfig: oldConfig, called: name) + } + return nil + } + + func destroyConfigurationReference() { + guard let ref = passwordReference else { return } + Keychain.deleteReference(called: ref) + } + + func verifyConfigurationReference() -> Bool { + guard let ref = passwordReference else { return false } + return Keychain.verifyReference(called: ref) + } + + @discardableResult + func migrateConfigurationIfNeeded(called name: String) -> Bool { + /* This is how we did things before we switched to putting items + * in the keychain. But it's still useful to keep the migration + * around so that .mobileconfig files are easier. + */ + if let oldConfig = providerConfiguration?["WgQuickConfig"] as? String { + #if os(macOS) + providerConfiguration = ["UID": getuid()] + #elseif os(iOS) + providerConfiguration = nil + #else + #error("Unimplemented") + #endif + guard passwordReference == nil else { return true } + wg_log(.debug, message: "Migrating tunnel configuration '\(name)'") + passwordReference = Keychain.makeReference(containing: oldConfig, called: name) + return true + } + #if os(macOS) + if passwordReference != nil && providerConfiguration?["UID"] == nil && verifyConfigurationReference() { + providerConfiguration = ["UID": getuid()] + return true + } + #endif + return false + } +} |