Skip to content

Commit

Permalink
Merge pull request #398 from ivpn/feature/network-protection-block-la…
Browse files Browse the repository at this point in the history
…n-traffic

Add “Block LAN traffic” action for untrusted networks
  • Loading branch information
jurajhilje authored Dec 1, 2023
2 parents 5e83050 + ff2de04 commit c9120ee
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 100 deletions.
18 changes: 18 additions & 0 deletions IVPNClient/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ class AppDelegate: UIResponder {

switch endpoint {
case Config.urlTypeConnect:
guard !UserDefaults.shared.disableWidgetPrompt else {
if UserDefaults.shared.networkProtectionEnabled {
Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect)
return
}
Application.shared.connectionManager.connectShortcut(closeApp: true, actionType: .connect)
return
}

viewController.showActionAlert(title: "Please confirm", message: "Do you want to connect to VPN?", action: "Connect", actionHandler: { _ in
if UserDefaults.shared.networkProtectionEnabled {
Application.shared.connectionManager.resetRulesAndConnectShortcut(closeApp: true, actionType: .connect)
Expand All @@ -154,6 +163,15 @@ class AppDelegate: UIResponder {
Application.shared.connectionManager.connectShortcut(closeApp: true, actionType: .connect)
})
case Config.urlTypeDisconnect:
guard !UserDefaults.shared.disableWidgetPrompt else {
if UserDefaults.shared.networkProtectionEnabled {
Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect)
return
}
Application.shared.connectionManager.disconnectShortcut(closeApp: true, actionType: .disconnect)
return
}

viewController.showActionAlert(title: "Please confirm", message: "Do you want to disconnect from VPN?", action: "Disconnect", actionHandler: { _ in
if UserDefaults.shared.networkProtectionEnabled {
Application.shared.connectionManager.resetRulesAndDisconnectShortcut(closeApp: true, actionType: .disconnect)
Expand Down
214 changes: 120 additions & 94 deletions IVPNClient/Scenes/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class AdvancedViewController: UITableViewController {

@IBOutlet weak var disableLanAccessSwitch: UISwitch!
@IBOutlet weak var askToReconnectSwitch: UISwitch!
@IBOutlet weak var widgetPromptSwitch: UISwitch!
@IBOutlet weak var preventSameCountryMultiHopSwitch: UISwitch!
@IBOutlet weak var preventSameISPMultiHopSwitch: UISwitch!
@IBOutlet weak var loggingSwitch: UISwitch!
Expand All @@ -49,7 +50,7 @@ class AdvancedViewController: UITableViewController {

@IBAction func toggleDisableLanAccess(_ sender: UISwitch) {
if sender.isOn && Application.shared.settings.connectionProtocol.tunnelType() == .ipsec {
showAlert(title: "IKEv2 not supported", message: "Disable LAN traffic is supported only for OpenVPN and WireGuard protocols.") { _ in
showAlert(title: "IKEv2 not supported", message: "Block LAN traffic is supported only for OpenVPN and WireGuard protocols.") { _ in
sender.setOn(false, animated: true)
}
return
Expand Down Expand Up @@ -91,6 +92,10 @@ class AdvancedViewController: UITableViewController {
UserDefaults.shared.set(!sender.isOn, forKey: UserDefaults.Key.notAskToReconnect)
}

@IBAction func toggleWidgetPrompt(_ sender: UISwitch) {
UserDefaults.shared.set(!sender.isOn, forKey: UserDefaults.Key.disableWidgetPrompt)
}

@IBAction func togglePreventSameCountryMultiHop(_ sender: UISwitch) {
UserDefaults.standard.set(sender.isOn, forKey: UserDefaults.Key.preventSameCountryMultiHop)
}
Expand Down Expand Up @@ -118,6 +123,7 @@ class AdvancedViewController: UITableViewController {
tableView.backgroundColor = UIColor.init(named: Theme.ivpnBackgroundQuaternary)
disableLanAccessSwitch.setOn(UserDefaults.shared.disableLanAccess, animated: false)
askToReconnectSwitch.setOn(!UserDefaults.shared.notAskToReconnect, animated: false)
widgetPromptSwitch.setOn(!UserDefaults.shared.disableWidgetPrompt, animated: false)
preventSameCountryMultiHopSwitch.setOn(UserDefaults.standard.preventSameCountryMultiHop, animated: false)
preventSameISPMultiHopSwitch.setOn(UserDefaults.standard.preventSameISPMultiHop, animated: false)
loggingSwitch.setOn(UserDefaults.shared.isLogging, animated: false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import UIKit
class NetworkProtectionRulesViewController: UITableViewController {

@IBOutlet weak var untrustedConnectSwitch: UISwitch!
@IBOutlet weak var untrustedBlockLanSwitch: UISwitch!
@IBOutlet weak var trustedDisconnectSwitch: UISwitch!
let defaults = UserDefaults.shared

Expand All @@ -38,6 +39,22 @@ class NetworkProtectionRulesViewController: UITableViewController {
}
}

@IBAction func toggleUntrustedBlockLan(_ sender: UISwitch) {
if sender.isOn && Application.shared.settings.connectionProtocol.tunnelType() == .ipsec {
showAlert(title: "IKEv2 not supported", message: "Block LAN traffic is supported only for OpenVPN and WireGuard protocols.") { _ in
sender.setOn(false, animated: true)
}
return
}

defaults.set(sender.isOn, forKey: UserDefaults.Key.networkProtectionUntrustedBlockLan)
evaluateReconnect(sender: sender as UIView)
}

@IBAction func blockLanInfo(_ sender: UIButton) {
showAlert(title: "Info", message: "When enabled, LAN traffic will be blocked when connected to an untrusted network.")
}

@IBAction func toggleTrustedDisconnect(_ sender: UISwitch) {
defaults.set(sender.isOn, forKey: UserDefaults.Key.networkProtectionTrustedDisconnect)
Application.shared.connectionManager.evaluateConnection { [self] error in
Expand All @@ -51,6 +68,7 @@ class NetworkProtectionRulesViewController: UITableViewController {
super.viewDidLoad()
tableView.backgroundColor = UIColor.init(named: Theme.ivpnBackgroundQuaternary)
untrustedConnectSwitch.setOn(defaults.networkProtectionUntrustedConnect, animated: false)
untrustedBlockLanSwitch.setOn(defaults.networkProtectionUntrustedBlockLan, animated: false)
trustedDisconnectSwitch.setOn(defaults.networkProtectionTrustedDisconnect, animated: false)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ extension NetworkProtectionViewController {
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
switch section {
case 0:
return "On iOS 13 and above, current Wi-Fi name is available only when IVPN profile is saved in iOS VPN Configurations."
return "Current Wi-Fi name is available only when IVPN profile is saved in iOS VPN Configurations."
default:
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ class ProtocolViewController: UITableViewController {
return false
}

if UserDefaults.shared.networkProtectionUntrustedBlockLan && connectionProtocol == .ipsec {
return false
}

return true
}

Expand Down Expand Up @@ -391,6 +395,7 @@ extension ProtocolViewController {
switch index {
case 0:
UserDefaults.shared.set(false, forKey: UserDefaults.Key.disableLanAccess)
UserDefaults.shared.set(false, forKey: UserDefaults.Key.networkProtectionUntrustedBlockLan)
tableView.reloadData()
default:
break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ class WireGuardSettingsViewController: UITableViewController {
present(viewController, animated: true)
}

@IBAction func quantumInfo(_ sender: UIButton) {
showAlert(title: "Info", message: "Quantum Resistance: Indicates whether your current WireGuard VPN connection is using additional protection measures against potential future quantum computer attacks.\n\nWhen Enabled, a Pre-shared key has been securely exchanged between your device and the server using post-quantum Key Encapsulation Mechanism (KEM) algorithms. If Disabled, the current VPN connection, while secure under today's standards, does not include this extra layer of quantum resistance.")
}

// MARK: - View Lifecycle -

override func viewDidLoad() {
Expand Down
20 changes: 16 additions & 4 deletions IVPNClient/Utilities/Extensions/NETunnelProviderProtocol+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ extension NETunnelProviderProtocol {
}

if #available(iOS 14.2, *) {
proto.includeAllNetworks = UserDefaults.shared.disableLanAccess
proto.excludeLocalNetworks = !UserDefaults.shared.disableLanAccess
proto.includeAllNetworks = disableLanAccess()
proto.excludeLocalNetworks = !disableLanAccess()
}

return proto
Expand Down Expand Up @@ -190,8 +190,8 @@ extension NETunnelProviderProtocol {
}

if #available(iOS 14.2, *) {
configuration.includeAllNetworks = UserDefaults.shared.disableLanAccess
configuration.excludeLocalNetworks = !UserDefaults.shared.disableLanAccess
configuration.includeAllNetworks = disableLanAccess()
configuration.excludeLocalNetworks = !disableLanAccess()
}

return configuration
Expand Down Expand Up @@ -231,4 +231,16 @@ extension NETunnelProviderProtocol {
return settings.port()
}

private static func disableLanAccess() -> Bool {
let defaultTrust = StorageManager.getDefaultTrust()
let networkTrust = Application.shared.network.trust ?? NetworkTrust.Default.rawValue
let trust = StorageManager.trustValue(trust: networkTrust, defaultTrust: defaultTrust)

if UserDefaults.shared.networkProtectionEnabled && UserDefaults.shared.networkProtectionUntrustedBlockLan && trust == NetworkTrust.Untrusted.rawValue {
return true
}

return UserDefaults.shared.disableLanAccess
}

}
12 changes: 12 additions & 0 deletions IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extension UserDefaults {
static let isLogging = "isLogging"
static let networkProtectionEnabled = "networkProtection.enabled"
static let networkProtectionUntrustedConnect = "networkProtection.untrusted.connect"
static let networkProtectionUntrustedBlockLan = "networkProtection.untrusted.blockLan"
static let networkProtectionTrustedDisconnect = "networkProtection.trusted.disconnect"
static let isCustomDNS = "isCustomDNS"
static let customDNSProtocol = "customDNSProtocol"
Expand Down Expand Up @@ -93,6 +94,7 @@ extension UserDefaults {
static let v2raySettings = "v2raySettings"
static let v2rayProtocol = "v2rayProtocol"
static let isV2ray = "isV2ray"
static let disableWidgetPrompt = "disableWidgetPrompt"
}

@objc dynamic var wireguardTunnelProviderError: String {
Expand Down Expand Up @@ -123,6 +125,10 @@ extension UserDefaults {
return bool(forKey: Key.networkProtectionUntrustedConnect)
}

@objc dynamic var networkProtectionUntrustedBlockLan: Bool {
return bool(forKey: Key.networkProtectionUntrustedBlockLan)
}

@objc dynamic var networkProtectionTrustedDisconnect: Bool {
return bool(forKey: Key.networkProtectionTrustedDisconnect)
}
Expand Down Expand Up @@ -251,6 +257,10 @@ extension UserDefaults {
return bool(forKey: Key.isV2ray)
}

@objc dynamic var disableWidgetPrompt: Bool {
return bool(forKey: Key.disableWidgetPrompt)
}

static func registerUserDefaults() {
shared.register(defaults: [Key.networkProtectionUntrustedConnect: true])
shared.register(defaults: [Key.networkProtectionTrustedDisconnect: true])
Expand All @@ -268,6 +278,7 @@ extension UserDefaults {
shared.removeObject(forKey: Key.isLogging)
shared.removeObject(forKey: Key.networkProtectionEnabled)
shared.removeObject(forKey: Key.networkProtectionUntrustedConnect)
shared.removeObject(forKey: Key.networkProtectionUntrustedBlockLan)
shared.removeObject(forKey: Key.networkProtectionTrustedDisconnect)
shared.removeObject(forKey: Key.isCustomDNS)
shared.removeObject(forKey: Key.customDNS)
Expand All @@ -290,6 +301,7 @@ extension UserDefaults {
shared.removeObject(forKey: Key.v2raySettings)
shared.removeObject(forKey: Key.v2rayProtocol)
shared.removeObject(forKey: Key.isV2ray)
shared.removeObject(forKey: Key.disableWidgetPrompt)
standard.removeObject(forKey: Key.serviceStatus)
standard.removeObject(forKey: Key.selectedHost)
standard.removeObject(forKey: Key.selectedExitHost)
Expand Down

0 comments on commit c9120ee

Please sign in to comment.