mirror of
https://github.com/passepartoutvpn/wireguard-apple.git
synced 2025-02-12 02:42:02 +00:00
Model, Tunnels manager: Rewrite the model for VPN-on-demand
The VPN-on-demand settings should not be part of the tunnel configuration. Rather, the onDemandRules stored in the tunnel provider configuration serve as the one place where the VPN-on-demand settings are stored. Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
parent
39a067cb96
commit
cc122d7463
@ -1,66 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// Copyright © 2018 WireGuard LLC. All Rights Reserved.
|
|
||||||
|
|
||||||
enum ActivationType {
|
|
||||||
case activateManually
|
|
||||||
case useOnDemandOverWifiAndCellular
|
|
||||||
case useOnDemandOverWifiOnly
|
|
||||||
case useOnDemandOverCellularOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ActivationType: Codable {
|
|
||||||
// We use separate coding keys in case we might have a enum with associated values in the future
|
|
||||||
enum CodingKeys: CodingKey {
|
|
||||||
case activateManually
|
|
||||||
case useOnDemandOverWifiAndCellular
|
|
||||||
case useOnDemandOverWifiOnly
|
|
||||||
case useOnDemandOverCellularOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoding error
|
|
||||||
enum DecodingError: Error {
|
|
||||||
case invalidInput
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encoding
|
|
||||||
func encode(to encoder: Encoder) throws {
|
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
||||||
switch self {
|
|
||||||
case .activateManually:
|
|
||||||
try container.encode(true, forKey: CodingKeys.activateManually)
|
|
||||||
case .useOnDemandOverWifiAndCellular:
|
|
||||||
try container.encode(true, forKey: CodingKeys.useOnDemandOverWifiAndCellular)
|
|
||||||
case .useOnDemandOverWifiOnly:
|
|
||||||
try container.encode(true, forKey: CodingKeys.useOnDemandOverWifiOnly)
|
|
||||||
case .useOnDemandOverCellularOnly:
|
|
||||||
try container.encode(true, forKey: CodingKeys.useOnDemandOverCellularOnly)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoding
|
|
||||||
init(from decoder: Decoder) throws {
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
|
|
||||||
if let isValid = try? container.decode(Bool.self, forKey: CodingKeys.activateManually), isValid {
|
|
||||||
self = .activateManually
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let isValid = try? container.decode(Bool.self, forKey: CodingKeys.useOnDemandOverWifiAndCellular), isValid {
|
|
||||||
self = .useOnDemandOverWifiAndCellular
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let isValid = try? container.decode(Bool.self, forKey: CodingKeys.useOnDemandOverWifiOnly), isValid {
|
|
||||||
self = .useOnDemandOverWifiOnly
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let isValid = try? container.decode(Bool.self, forKey: CodingKeys.useOnDemandOverCellularOnly), isValid {
|
|
||||||
self = .useOnDemandOverCellularOnly
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
throw DecodingError.invalidInput
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,14 +4,12 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@available(OSX 10.14, iOS 12.0, *)
|
@available(OSX 10.14, iOS 12.0, *)
|
||||||
final class TunnelConfiguration {
|
final class TunnelConfiguration: Codable {
|
||||||
var interface: InterfaceConfiguration
|
var interface: InterfaceConfiguration
|
||||||
let peers: [PeerConfiguration]
|
let peers: [PeerConfiguration]
|
||||||
var activationType: ActivationType
|
|
||||||
init(interface: InterfaceConfiguration, peers: [PeerConfiguration]) {
|
init(interface: InterfaceConfiguration, peers: [PeerConfiguration]) {
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
self.peers = peers
|
self.peers = peers
|
||||||
self.activationType = .activateManually
|
|
||||||
|
|
||||||
let peerPublicKeysArray = peers.map { $0.publicKey }
|
let peerPublicKeysArray = peers.map { $0.publicKey }
|
||||||
let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
|
let peerPublicKeysSet = Set<Data>(peerPublicKeysArray)
|
||||||
@ -57,21 +55,3 @@ struct PeerConfiguration: Codable {
|
|||||||
if (publicKey.count != 32) { fatalError("Invalid public key") }
|
if (publicKey.count != 32) { fatalError("Invalid public key") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TunnelConfiguration: Encodable { }
|
|
||||||
extension TunnelConfiguration: Decodable {
|
|
||||||
enum CodingKeys: CodingKey {
|
|
||||||
case interface
|
|
||||||
case peers
|
|
||||||
case activationType
|
|
||||||
}
|
|
||||||
convenience init(from decoder: Decoder) throws {
|
|
||||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
let interface = try values.decode(InterfaceConfiguration.self, forKey: .interface)
|
|
||||||
let peers = try values.decode([PeerConfiguration].self, forKey: .peers)
|
|
||||||
let activationType = (try? values.decode(ActivationType.self, forKey: .activationType)) ?? .activateManually
|
|
||||||
|
|
||||||
self.init(interface: interface, peers: peers)
|
|
||||||
self.activationType = activationType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -14,7 +14,7 @@ extension NETunnelProviderProtocol {
|
|||||||
providerBundleIdentifier = "\(appId).network-extension"
|
providerBundleIdentifier = "\(appId).network-extension"
|
||||||
providerConfiguration = [
|
providerConfiguration = [
|
||||||
"tunnelConfiguration": serializedTunnelConfiguration,
|
"tunnelConfiguration": serializedTunnelConfiguration,
|
||||||
"tunnelConfigurationVersion": 2
|
"tunnelConfigurationVersion": 1
|
||||||
]
|
]
|
||||||
|
|
||||||
let endpoints = tunnelConfiguration.peers.compactMap({$0.endpoint})
|
let endpoints = tunnelConfiguration.peers.compactMap({$0.endpoint})
|
||||||
|
@ -49,8 +49,7 @@
|
|||||||
6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; };
|
6FFA5D952194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; };
|
||||||
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; };
|
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */; };
|
||||||
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; };
|
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */; };
|
||||||
6FFA5DA42197085D0001E2F7 /* ActivationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivationType.swift */; };
|
6FFA5DA42197085D0001E2F7 /* ActivateOnDemandSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivateOnDemandSetting.swift */; };
|
||||||
6FFA5DA521970B370001E2F7 /* ActivationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFA5DA32197085D0001E2F7 /* ActivationType.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -135,7 +134,7 @@
|
|||||||
6FF4AC482120B9E0002C96EB /* WireGuard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuard.entitlements; sourceTree = "<group>"; };
|
6FF4AC482120B9E0002C96EB /* WireGuard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuard.entitlements; sourceTree = "<group>"; };
|
||||||
6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NETunnelProviderProtocol+Extension.swift"; sourceTree = "<group>"; };
|
6FFA5D942194454A0001E2F7 /* NETunnelProviderProtocol+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NETunnelProviderProtocol+Extension.swift"; sourceTree = "<group>"; };
|
||||||
6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorNotifier.swift; sourceTree = "<group>"; };
|
6FFA5D9F21958ECC0001E2F7 /* ErrorNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorNotifier.swift; sourceTree = "<group>"; };
|
||||||
6FFA5DA32197085D0001E2F7 /* ActivationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivationType.swift; sourceTree = "<group>"; };
|
6FFA5DA32197085D0001E2F7 /* ActivateOnDemandSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandSetting.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -232,7 +231,6 @@
|
|||||||
6F7774E9217229DB006A79B3 /* IPAddressRange.swift */,
|
6F7774E9217229DB006A79B3 /* IPAddressRange.swift */,
|
||||||
6F693A552179E556008551C1 /* Endpoint.swift */,
|
6F693A552179E556008551C1 /* Endpoint.swift */,
|
||||||
6F628C3E217F3413003482A3 /* DNSServer.swift */,
|
6F628C3E217F3413003482A3 /* DNSServer.swift */,
|
||||||
6FFA5DA32197085D0001E2F7 /* ActivationType.swift */,
|
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -241,6 +239,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */,
|
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */,
|
||||||
|
6FFA5DA32197085D0001E2F7 /* ActivateOnDemandSetting.swift */,
|
||||||
);
|
);
|
||||||
path = VPN;
|
path = VPN;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -498,7 +497,6 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
6FFA5DA521970B370001E2F7 /* ActivationType.swift in Sources */,
|
|
||||||
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */,
|
6FFA5DA021958ECC0001E2F7 /* ErrorNotifier.swift in Sources */,
|
||||||
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
6FFA5D96219446380001E2F7 /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||||
6FFA5D8E2194370D0001E2F7 /* Configuration.swift in Sources */,
|
6FFA5D8E2194370D0001E2F7 /* Configuration.swift in Sources */,
|
||||||
@ -540,7 +538,7 @@
|
|||||||
6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */,
|
6FDEF802218646BA00D8FBF6 /* ZipArchive.swift in Sources */,
|
||||||
6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */,
|
6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */,
|
||||||
6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */,
|
6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */,
|
||||||
6FFA5DA42197085D0001E2F7 /* ActivationType.swift in Sources */,
|
6FFA5DA42197085D0001E2F7 /* ActivateOnDemandSetting.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
75
WireGuard/WireGuard/VPN/ActivateOnDemandSetting.swift
Normal file
75
WireGuard/WireGuard/VPN/ActivateOnDemandSetting.swift
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2018 WireGuard LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
import NetworkExtension
|
||||||
|
|
||||||
|
struct ActivateOnDemandSetting {
|
||||||
|
var isActivateOnDemandEnabled: Bool
|
||||||
|
var activateOnDemandOption: ActivateOnDemandOption
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ActivateOnDemandOption {
|
||||||
|
case none // Valid only when isActivateOnDemandEnabled is false
|
||||||
|
case useOnDemandOverWifiOrCellular
|
||||||
|
case useOnDemandOverWifiOnly
|
||||||
|
case useOnDemandOverCellularOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ActivateOnDemandSetting {
|
||||||
|
func apply(on tunnelProviderManager: NETunnelProviderManager) {
|
||||||
|
tunnelProviderManager.isOnDemandEnabled = isActivateOnDemandEnabled
|
||||||
|
let rules: [NEOnDemandRule]?
|
||||||
|
let connectRule = NEOnDemandRuleConnect()
|
||||||
|
let disconnectRule = NEOnDemandRuleDisconnect()
|
||||||
|
switch (activateOnDemandOption) {
|
||||||
|
case .none:
|
||||||
|
rules = nil
|
||||||
|
case .useOnDemandOverWifiOrCellular:
|
||||||
|
rules = [connectRule]
|
||||||
|
case .useOnDemandOverWifiOnly:
|
||||||
|
connectRule.interfaceTypeMatch = .wiFi
|
||||||
|
disconnectRule.interfaceTypeMatch = .cellular
|
||||||
|
rules = [connectRule, disconnectRule]
|
||||||
|
case .useOnDemandOverCellularOnly:
|
||||||
|
connectRule.interfaceTypeMatch = .cellular
|
||||||
|
disconnectRule.interfaceTypeMatch = .wiFi
|
||||||
|
rules = [connectRule, disconnectRule]
|
||||||
|
}
|
||||||
|
tunnelProviderManager.onDemandRules = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
init(from tunnelProviderManager: NETunnelProviderManager) {
|
||||||
|
let rules = tunnelProviderManager.onDemandRules ?? []
|
||||||
|
let activateOnDemandOption: ActivateOnDemandOption
|
||||||
|
switch (rules.count) {
|
||||||
|
case 0:
|
||||||
|
activateOnDemandOption = .none
|
||||||
|
case 1:
|
||||||
|
let rule = rules[0]
|
||||||
|
precondition(rule.action == .connect)
|
||||||
|
activateOnDemandOption = .useOnDemandOverWifiOrCellular
|
||||||
|
case 2:
|
||||||
|
let connectRule = rules.first(where: { $0.action == .connect })!
|
||||||
|
let disconnectRule = rules.first(where: { $0.action == .disconnect })!
|
||||||
|
if (connectRule.interfaceTypeMatch == .wiFi && disconnectRule.interfaceTypeMatch == .cellular) {
|
||||||
|
activateOnDemandOption = .useOnDemandOverWifiOnly
|
||||||
|
} else if (connectRule.interfaceTypeMatch == .cellular && disconnectRule.interfaceTypeMatch == .wiFi) {
|
||||||
|
activateOnDemandOption = .useOnDemandOverCellularOnly
|
||||||
|
} else {
|
||||||
|
fatalError("Unexpected onDemandRules set on tunnel provider manager")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fatalError("Unexpected number of onDemandRules set on tunnel provider manager")
|
||||||
|
}
|
||||||
|
self.activateOnDemandOption = activateOnDemandOption
|
||||||
|
if (activateOnDemandOption == .none) {
|
||||||
|
self.isActivateOnDemandEnabled = false
|
||||||
|
} else {
|
||||||
|
self.isActivateOnDemandEnabled = tunnelProviderManager.isOnDemandEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ActivateOnDemandSetting {
|
||||||
|
static var defaultSetting = ActivateOnDemandSetting(isActivateOnDemandEnabled: false, activateOnDemandOption: .none)
|
||||||
|
}
|
@ -54,7 +54,9 @@ class TunnelsManager {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(tunnelConfiguration: TunnelConfiguration, completionHandler: @escaping (TunnelContainer?, TunnelManagementError?) -> Void) {
|
func add(tunnelConfiguration: TunnelConfiguration,
|
||||||
|
activateOnDemandSetting: ActivateOnDemandSetting = ActivateOnDemandSetting.defaultSetting,
|
||||||
|
completionHandler: @escaping (TunnelContainer?, TunnelManagementError?) -> Void) {
|
||||||
let tunnelName = tunnelConfiguration.interface.name
|
let tunnelName = tunnelConfiguration.interface.name
|
||||||
if tunnelName.isEmpty {
|
if tunnelName.isEmpty {
|
||||||
completionHandler(nil, TunnelManagementError.tunnelAlreadyExistsWithThatName)
|
completionHandler(nil, TunnelManagementError.tunnelAlreadyExistsWithThatName)
|
||||||
@ -72,13 +74,7 @@ class TunnelsManager {
|
|||||||
tunnelProviderManager.localizedDescription = tunnelName
|
tunnelProviderManager.localizedDescription = tunnelName
|
||||||
tunnelProviderManager.isEnabled = true
|
tunnelProviderManager.isEnabled = true
|
||||||
|
|
||||||
if (tunnelConfiguration.activationType == .activateManually) {
|
activateOnDemandSetting.apply(on: tunnelProviderManager)
|
||||||
tunnelProviderManager.onDemandRules = []
|
|
||||||
tunnelProviderManager.isOnDemandEnabled = false
|
|
||||||
} else {
|
|
||||||
tunnelProviderManager.onDemandRules = onDemandRules(for: tunnelConfiguration.activationType)
|
|
||||||
tunnelProviderManager.isOnDemandEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
tunnelProviderManager.saveToPreferences { [weak self] (error) in
|
tunnelProviderManager.saveToPreferences { [weak self] (error) in
|
||||||
defer { self?.isAddingTunnel = false }
|
defer { self?.isAddingTunnel = false }
|
||||||
@ -114,7 +110,8 @@ class TunnelsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func modify(tunnel: TunnelContainer, with tunnelConfiguration: TunnelConfiguration, completionHandler: @escaping (TunnelManagementError?) -> Void) {
|
func modify(tunnel: TunnelContainer, tunnelConfiguration: TunnelConfiguration,
|
||||||
|
activateOnDemandSetting: ActivateOnDemandSetting, completionHandler: @escaping (TunnelManagementError?) -> Void) {
|
||||||
let tunnelName = tunnelConfiguration.interface.name
|
let tunnelName = tunnelConfiguration.interface.name
|
||||||
if tunnelName.isEmpty {
|
if tunnelName.isEmpty {
|
||||||
completionHandler(TunnelManagementError.tunnelAlreadyExistsWithThatName)
|
completionHandler(TunnelManagementError.tunnelAlreadyExistsWithThatName)
|
||||||
@ -138,13 +135,7 @@ class TunnelsManager {
|
|||||||
tunnelProviderManager.localizedDescription = tunnelName
|
tunnelProviderManager.localizedDescription = tunnelName
|
||||||
tunnelProviderManager.isEnabled = true
|
tunnelProviderManager.isEnabled = true
|
||||||
|
|
||||||
if (tunnelConfiguration.activationType == .activateManually) {
|
activateOnDemandSetting.apply(on: tunnelProviderManager)
|
||||||
tunnelProviderManager.onDemandRules = []
|
|
||||||
tunnelProviderManager.isOnDemandEnabled = false
|
|
||||||
} else {
|
|
||||||
tunnelProviderManager.onDemandRules = onDemandRules(for: tunnelConfiguration.activationType)
|
|
||||||
tunnelProviderManager.isOnDemandEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
tunnelProviderManager.saveToPreferences { [weak self] (error) in
|
tunnelProviderManager.saveToPreferences { [weak self] (error) in
|
||||||
defer { self?.isModifyingTunnel = false }
|
defer { self?.isModifyingTunnel = false }
|
||||||
@ -229,26 +220,6 @@ class TunnelsManager {
|
|||||||
t.refreshConnectionStatus()
|
t.refreshConnectionStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func onDemandRules(for activationType: ActivationType) -> [NEOnDemandRule] {
|
|
||||||
switch (activationType) {
|
|
||||||
case .activateManually: return []
|
|
||||||
case .useOnDemandOverWifiAndCellular:
|
|
||||||
return [NEOnDemandRuleConnect()]
|
|
||||||
case .useOnDemandOverWifiOnly:
|
|
||||||
let connectOnWifiRule = NEOnDemandRuleConnect()
|
|
||||||
connectOnWifiRule.interfaceTypeMatch = .wiFi
|
|
||||||
let disconnectOnCellularRule = NEOnDemandRuleDisconnect()
|
|
||||||
disconnectOnCellularRule.interfaceTypeMatch = .cellular
|
|
||||||
return [connectOnWifiRule, disconnectOnCellularRule]
|
|
||||||
case .useOnDemandOverCellularOnly:
|
|
||||||
let connectOnCellularRule = NEOnDemandRuleConnect()
|
|
||||||
connectOnCellularRule.interfaceTypeMatch = .cellular
|
|
||||||
let disconnectOnWifiRule = NEOnDemandRuleDisconnect()
|
|
||||||
disconnectOnWifiRule.interfaceTypeMatch = .wiFi
|
|
||||||
return [connectOnCellularRule, disconnectOnWifiRule]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TunnelContainer: NSObject {
|
class TunnelContainer: NSObject {
|
||||||
@ -275,6 +246,10 @@ class TunnelContainer: NSObject {
|
|||||||
return (tunnelProvider.protocolConfiguration as! NETunnelProviderProtocol).tunnelConfiguration()
|
return (tunnelProvider.protocolConfiguration as! NETunnelProviderProtocol).tunnelConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func activateOnDemandSetting() -> ActivateOnDemandSetting {
|
||||||
|
return ActivateOnDemandSetting(from: tunnelProvider)
|
||||||
|
}
|
||||||
|
|
||||||
func refreshConnectionStatus() {
|
func refreshConnectionStatus() {
|
||||||
let status = TunnelStatus(from: self.tunnelProvider.connection.status)
|
let status = TunnelStatus(from: self.tunnelProvider.connection.status)
|
||||||
self.status = status
|
self.status = status
|
||||||
|
Loading…
Reference in New Issue
Block a user