aboutsummaryrefslogtreecommitdiffstats
path: root/Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift')
-rw-r--r--Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift88
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
+ }
+}