3741a17c20
In order to avoid chaos from multiple profiles, retain the profile to be installed and remove all the other ones. Also, make sure to do the removal AFTER install, as doing it before would trigger the VPN permission alert again. XXX: there is some weird behavior from NetworkExtension occasionally sending notifications with a bogus NEVPNManager object having a nil .localizedDescription and other properties set to nonsensical values. Discard the notification when such an object is identified. Encapsulate extra NetworkExtension settings: - passwordReference - onDemandRules - disconnectsOnSleep Also: - Only set on-demand if any rules are set - Assume VPN is enabled even with on-demand disabled - Use DataCount instead of raw Int pair Attach useful information to VPN notifications: - VPN isEnabled - VPN status - VPN command error - Tunnel bundle identifier (if available) Expose specific OpenVPN/WireGuard shared data via extensions in UserDefaults/FileManager. Finally, drop incomplete IKE support. No fit.
156 lines
4.8 KiB
Swift
156 lines
4.8 KiB
Swift
//
|
|
// WireGuard+ProviderConfiguration.swift
|
|
// TunnelKit
|
|
//
|
|
// Created by Davide De Rosa on 11/21/21.
|
|
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
|
|
//
|
|
// https://github.com/passepartoutvpn
|
|
//
|
|
// This file is part of TunnelKit.
|
|
//
|
|
// TunnelKit is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// TunnelKit is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
import Foundation
|
|
import NetworkExtension
|
|
import TunnelKitManager
|
|
import TunnelKitWireGuardCore
|
|
import WireGuardKit
|
|
import __TunnelKitUtils
|
|
import SwiftyBeaver
|
|
|
|
private let log = SwiftyBeaver.self
|
|
|
|
extension WireGuard {
|
|
|
|
/// Specific configuration for WireGuard.
|
|
public struct ProviderConfiguration: Codable {
|
|
fileprivate enum Filenames: String {
|
|
case debugLog = "WireGuard.Tunnel.log"
|
|
}
|
|
|
|
fileprivate enum Keys: String {
|
|
case lastError = "WireGuard.LastError"
|
|
}
|
|
|
|
public let title: String
|
|
|
|
public let appGroup: String
|
|
|
|
public let configuration: WireGuard.Configuration
|
|
|
|
public var shouldDebug = false
|
|
|
|
public init(_ title: String, appGroup: String, configuration: WireGuard.Configuration) {
|
|
self.title = title
|
|
self.appGroup = appGroup
|
|
self.configuration = configuration
|
|
}
|
|
|
|
private init(_ title: String, appGroup: String, wgQuickConfig: String) throws {
|
|
self.title = title
|
|
self.appGroup = appGroup
|
|
configuration = try WireGuard.Configuration(wgQuickConfig: wgQuickConfig)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: NetworkExtensionConfiguration
|
|
|
|
extension WireGuard.ProviderConfiguration: NetworkExtensionConfiguration {
|
|
|
|
/// :nodoc:
|
|
public func asTunnelProtocol(
|
|
withBundleIdentifier tunnelBundleIdentifier: String,
|
|
extra: NetworkExtensionExtra?
|
|
) throws -> NETunnelProviderProtocol {
|
|
let protocolConfiguration = NETunnelProviderProtocol()
|
|
protocolConfiguration.providerBundleIdentifier = tunnelBundleIdentifier
|
|
protocolConfiguration.serverAddress = configuration.endpointRepresentation
|
|
protocolConfiguration.passwordReference = extra?.passwordReference
|
|
protocolConfiguration.disconnectOnSleep = extra?.disconnectsOnSleep ?? false
|
|
protocolConfiguration.providerConfiguration = try asDictionary()
|
|
return protocolConfiguration
|
|
}
|
|
}
|
|
|
|
// MARK: Shared data
|
|
|
|
extension WireGuard.ProviderConfiguration {
|
|
public var lastError: WireGuardProviderError? {
|
|
get {
|
|
return defaults?.wireGuardLastError
|
|
}
|
|
set {
|
|
defaults?.wireGuardLastError = newValue
|
|
}
|
|
}
|
|
|
|
private var defaults: UserDefaults? {
|
|
return UserDefaults(suiteName: appGroup)
|
|
}
|
|
|
|
public var urlForDebugLog: URL? {
|
|
return FileManager.default.wireGuardURLForDebugLog(appGroup: appGroup)
|
|
}
|
|
|
|
public var debugLog: String? {
|
|
return FileManager.default.wireGuardDebugLog(appGroup: appGroup)
|
|
}
|
|
}
|
|
|
|
/// :nodoc:
|
|
extension UserDefaults {
|
|
public var wireGuardLastError: WireGuardProviderError? {
|
|
get {
|
|
guard let rawValue = string(forKey: WireGuard.ProviderConfiguration.Keys.lastError.rawValue) else {
|
|
return nil
|
|
}
|
|
return WireGuardProviderError(rawValue: rawValue)
|
|
}
|
|
set {
|
|
guard let newValue = newValue else {
|
|
removeObject(forKey: WireGuard.ProviderConfiguration.Keys.lastError.rawValue)
|
|
return
|
|
}
|
|
set(newValue.rawValue, forKey: WireGuard.ProviderConfiguration.Keys.lastError.rawValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// :nodoc:
|
|
extension FileManager {
|
|
public func wireGuardURLForDebugLog(appGroup: String) -> URL? {
|
|
return documentsURL(appGroup: appGroup)?
|
|
.appendingPathComponent(WireGuard.ProviderConfiguration.Filenames.debugLog.rawValue)
|
|
}
|
|
|
|
public func wireGuardDebugLog(appGroup: String) -> String? {
|
|
guard let url = wireGuardURLForDebugLog(appGroup: appGroup) else {
|
|
return nil
|
|
}
|
|
do {
|
|
return try String(contentsOf: url)
|
|
} catch {
|
|
log.error("Unable to access debug log: \(error)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
private func documentsURL(appGroup: String) -> URL? {
|
|
return containerURL(forSecurityApplicationGroupIdentifier: appGroup)
|
|
}
|
|
}
|