2018-11-08 10:24:12 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2019-01-02 00:56:33 +00:00
|
|
|
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
2018-11-08 10:24:12 +00:00
|
|
|
|
|
|
|
import NetworkExtension
|
|
|
|
|
2018-12-22 02:41:54 +00:00
|
|
|
enum PacketTunnelProviderError: String, Error {
|
|
|
|
case savedProtocolConfigurationIsInvalid
|
|
|
|
case dnsResolutionFailure
|
|
|
|
case couldNotStartBackend
|
|
|
|
case couldNotDetermineFileDescriptor
|
|
|
|
case couldNotSetNetworkSettings
|
|
|
|
}
|
|
|
|
|
2018-11-08 10:24:12 +00:00
|
|
|
extension NETunnelProviderProtocol {
|
2019-02-04 06:37:26 +00:00
|
|
|
convenience init?(tunnelConfiguration: TunnelConfiguration, previouslyFrom old: NEVPNProtocol? = nil) {
|
2018-11-08 10:24:12 +00:00
|
|
|
self.init()
|
2018-12-21 22:34:56 +00:00
|
|
|
|
2019-02-04 06:37:26 +00:00
|
|
|
guard let name = tunnelConfiguration.name else { return nil }
|
|
|
|
guard let appId = Bundle.main.bundleIdentifier else { return nil }
|
2018-11-08 10:24:12 +00:00
|
|
|
providerBundleIdentifier = "\(appId).network-extension"
|
2019-02-04 06:37:26 +00:00
|
|
|
passwordReference = Keychain.makeReference(containing: tunnelConfiguration.asWgQuickConfig(), called: name, previouslyReferencedBy: old?.passwordReference)
|
|
|
|
if passwordReference == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2018-12-21 22:34:56 +00:00
|
|
|
|
2018-12-21 04:52:45 +00:00
|
|
|
let endpoints = tunnelConfiguration.peers.compactMap { $0.endpoint }
|
2018-11-08 10:24:12 +00:00
|
|
|
if endpoints.count == 1 {
|
2018-12-21 04:52:45 +00:00
|
|
|
serverAddress = endpoints[0].stringRepresentation
|
2018-11-08 10:24:12 +00:00
|
|
|
} else if endpoints.isEmpty {
|
|
|
|
serverAddress = "Unspecified"
|
|
|
|
} else {
|
|
|
|
serverAddress = "Multiple endpoints"
|
|
|
|
}
|
|
|
|
}
|
2018-12-21 22:34:56 +00:00
|
|
|
|
2018-12-21 23:28:18 +00:00
|
|
|
func asTunnelConfiguration(called name: String? = nil) -> TunnelConfiguration? {
|
2019-02-04 06:37:26 +00:00
|
|
|
migrateConfigurationIfNeeded(called: name ?? "unknown")
|
|
|
|
//TODO: in the case where migrateConfigurationIfNeeded is called by the network extension,
|
|
|
|
// before the app has started, and when there is, in fact, configuration that needs to be
|
|
|
|
// put into the keychain, this will generate one new keychain item every time it is started,
|
|
|
|
// until finally the app is open. Would it be possible to call saveToPreferences here? Or is
|
|
|
|
// that generally not available to network extensions? In which case, what should our
|
|
|
|
// behavior be?
|
2019-02-06 02:23:51 +00:00
|
|
|
|
2019-02-04 06:37:26 +00:00
|
|
|
guard let passwordReference = passwordReference else { return nil }
|
|
|
|
guard let config = Keychain.openReference(called: passwordReference) else { return nil }
|
|
|
|
return try? TunnelConfiguration(fromWgQuickConfig: config, called: name)
|
2018-12-19 10:32:48 +00:00
|
|
|
}
|
2018-12-21 22:34:56 +00:00
|
|
|
|
2019-02-04 06:37:26 +00:00
|
|
|
func destroyConfigurationReference() {
|
|
|
|
guard let ref = passwordReference else { return }
|
|
|
|
Keychain.deleteReference(called: ref)
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyConfigurationReference() -> Data? {
|
|
|
|
guard let ref = passwordReference else { return nil }
|
|
|
|
return Keychain.verifyReference(called: ref) ? ref : nil
|
|
|
|
}
|
2019-02-06 02:23:51 +00:00
|
|
|
|
2019-02-06 01:01:12 +00:00
|
|
|
@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.
|
|
|
|
*/
|
|
|
|
guard let oldConfig = providerConfiguration?["WgQuickConfig"] as? String else { return false }
|
|
|
|
providerConfiguration = nil
|
|
|
|
guard passwordReference == nil else { return true }
|
|
|
|
passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
|
|
|
|
return true
|
|
|
|
}
|
2018-11-08 10:24:12 +00:00
|
|
|
}
|