From 5d757982ba26ab3d9a26d16b8d03ea038e6568f2 Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Sat, 23 Feb 2019 13:56:51 +0530 Subject: on-demand: Infrastructure for supporting SSID-based rules Signed-off-by: Roopesh Chander --- .../WireGuard/Tunnel/ActivateOnDemandSetting.swift | 82 +++++++++++++++++----- 1 file changed, 66 insertions(+), 16 deletions(-) (limited to 'WireGuard/WireGuard/Tunnel') diff --git a/WireGuard/WireGuard/Tunnel/ActivateOnDemandSetting.swift b/WireGuard/WireGuard/Tunnel/ActivateOnDemandSetting.swift index 0cb3f98..28612c7 100644 --- a/WireGuard/WireGuard/Tunnel/ActivateOnDemandSetting.swift +++ b/WireGuard/WireGuard/Tunnel/ActivateOnDemandSetting.swift @@ -8,11 +8,11 @@ struct ActivateOnDemandSetting { var activateOnDemandOption: ActivateOnDemandOption } -enum ActivateOnDemandOption { +enum ActivateOnDemandOption: Equatable { case none // Valid only when isActivateOnDemandEnabled is false - case wiFiInterfaceOnly + case wiFiInterfaceOnly(ActivateOnDemandSSIDOption) case nonWiFiInterfaceOnly - case anyInterface + case anyInterface(ActivateOnDemandSSIDOption) } #if os(iOS) @@ -23,25 +23,29 @@ private let nonWiFiInterfaceType: NEOnDemandRuleInterfaceType = .ethernet #error("Unimplemented") #endif +enum ActivateOnDemandSSIDOption: Equatable { + case anySSID + case onlySpecificSSIDs([String]) + case exceptSpecificSSIDs([String]) +} + 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 .wiFiInterfaceOnly: - connectRule.interfaceTypeMatch = .wiFi - disconnectRule.interfaceTypeMatch = nonWiFiInterfaceType - rules = [connectRule, disconnectRule] + case .wiFiInterfaceOnly(let ssidOption): + rules = ssidOnDemandRules(option: ssidOption) + [NEOnDemandRuleDisconnect(interfaceType: nonWiFiInterfaceType)] case .nonWiFiInterfaceOnly: - connectRule.interfaceTypeMatch = nonWiFiInterfaceType - disconnectRule.interfaceTypeMatch = .wiFi - rules = [connectRule, disconnectRule] - case .anyInterface: - rules = [connectRule] + rules = [NEOnDemandRuleConnect(interfaceType: nonWiFiInterfaceType), NEOnDemandRuleDisconnect(interfaceType: .wiFi)] + case .anyInterface(let ssidOption): + if case .anySSID = ssidOption { + rules = [NEOnDemandRuleConnect(interfaceType: .any)] + } else { + rules = ssidOnDemandRules(option: ssidOption) + [NEOnDemandRuleConnect(interfaceType: nonWiFiInterfaceType)] + } } tunnelProviderManager.onDemandRules = rules } @@ -55,17 +59,33 @@ extension ActivateOnDemandSetting { case 1: let rule = rules[0] precondition(rule.action == .connect) - activateOnDemandOption = .anyInterface + activateOnDemandOption = .anyInterface(.anySSID) case 2: let connectRule = rules.first(where: { $0.action == .connect })! let disconnectRule = rules.first(where: { $0.action == .disconnect })! if connectRule.interfaceTypeMatch == .wiFi && disconnectRule.interfaceTypeMatch == nonWiFiInterfaceType { - activateOnDemandOption = .wiFiInterfaceOnly + activateOnDemandOption = .wiFiInterfaceOnly(.anySSID) } else if connectRule.interfaceTypeMatch == nonWiFiInterfaceType && disconnectRule.interfaceTypeMatch == .wiFi { activateOnDemandOption = .nonWiFiInterfaceOnly } else { fatalError("Unexpected onDemandRules set on tunnel provider manager") } + case 3: + let ssidRule = rules.first(where: { $0.interfaceTypeMatch == .wiFi && $0.ssidMatch != nil })! + let nonWiFiRule = rules.first(where: { $0.interfaceTypeMatch == nonWiFiInterfaceType })! + let ssids = ssidRule.ssidMatch! + switch (ssidRule.action, nonWiFiRule.action) { + case (.connect, .connect): + activateOnDemandOption = .anyInterface(.onlySpecificSSIDs(ssids)) + case (.connect, .disconnect): + activateOnDemandOption = .wiFiInterfaceOnly(.onlySpecificSSIDs(ssids)) + case (.disconnect, .connect): + activateOnDemandOption = .anyInterface(.exceptSpecificSSIDs(ssids)) + case (.disconnect, .disconnect): + activateOnDemandOption = .wiFiInterfaceOnly(.exceptSpecificSSIDs(ssids)) + default: + fatalError("Unexpected SSID onDemandRules set on tunnel provider manager") + } default: fatalError("Unexpected number of onDemandRules set on tunnel provider manager") } @@ -82,3 +102,33 @@ extension ActivateOnDemandSetting { extension ActivateOnDemandSetting { static var defaultSetting = ActivateOnDemandSetting(isActivateOnDemandEnabled: false, activateOnDemandOption: .none) } + +private extension NEOnDemandRuleConnect { + convenience init(interfaceType: NEOnDemandRuleInterfaceType, ssids: [String]? = nil) { + self.init() + interfaceTypeMatch = interfaceType + ssidMatch = ssids + } +} + +private extension NEOnDemandRuleDisconnect { + convenience init(interfaceType: NEOnDemandRuleInterfaceType, ssids: [String]? = nil) { + self.init() + interfaceTypeMatch = interfaceType + ssidMatch = ssids + } +} + +private func ssidOnDemandRules(option: ActivateOnDemandSSIDOption) -> [NEOnDemandRule] { + switch option { + case .anySSID: + return [NEOnDemandRuleConnect(interfaceType: .wiFi)] + case .onlySpecificSSIDs(let ssids): + assert(!ssids.isEmpty) + return [NEOnDemandRuleConnect(interfaceType: .wiFi, ssids: ssids), + NEOnDemandRuleDisconnect(interfaceType: .wiFi)] + case .exceptSpecificSSIDs(let ssids): + return [NEOnDemandRuleDisconnect(interfaceType: .wiFi, ssids: ssids), + NEOnDemandRuleConnect(interfaceType: .wiFi)] + } +} -- cgit v1.2.3-59-g8ed1b