aboutsummaryrefslogtreecommitdiffstats
path: root/WireGuard
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2018-12-03 15:34:58 +0530
committerRoopesh Chander <roop@roopc.net>2018-12-03 18:51:42 +0530
commite1b258353c312a87129d771405148e83f0af5a04 (patch)
treec2f70b3985167cd2bb321a6992fcb23e29ad1de5 /WireGuard
parentSettings: Export log file (diff)
downloadwireguard-apple-e1b258353c312a87129d771405148e83f0af5a04.tar.xz
wireguard-apple-e1b258353c312a87129d771405148e83f0af5a04.zip
VPN: Error out when tunnel activation fails because there's no internet
Signed-off-by: Roopesh Chander <roop@roopc.net>
Diffstat (limited to 'WireGuard')
-rw-r--r--WireGuard/WireGuard.xcodeproj/project.pbxproj4
-rw-r--r--WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift6
-rw-r--r--WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift9
-rw-r--r--WireGuard/WireGuard/VPN/InternetReachability.swift51
-rw-r--r--WireGuard/WireGuard/VPN/TunnelsManager.swift46
5 files changed, 109 insertions, 7 deletions
diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj
index c41bede..d308075 100644
--- a/WireGuard/WireGuard.xcodeproj/project.pbxproj
+++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj
@@ -44,6 +44,7 @@
6FE254FF219C60290028284D /* ZipExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE254FE219C60290028284D /* ZipExporter.swift */; };
6FF4AC1F211EC472002C96EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC1E211EC472002C96EB /* Assets.xcassets */; };
6FF4AC22211EC472002C96EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6FF4AC20211EC472002C96EB /* LaunchScreen.storyboard */; };
+ 6FF717E521B2CB1E0045A474 /* InternetReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF717E421B2CB1E0045A474 /* InternetReachability.swift */; };
6FFA5D8921942F320001E2F7 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C472183C6A3000F85AD /* PacketTunnelSettingsGenerator.swift */; };
6FFA5D8E2194370D0001E2F7 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E72172020C006A79B3 /* Configuration.swift */; };
6FFA5D8F2194370D0001E2F7 /* IPAddressRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7774E9217229DB006A79B3 /* IPAddressRange.swift */; };
@@ -139,6 +140,7 @@
6FF4AC2B211EC776002C96EB /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Config.xcconfig; path = Config/Config.xcconfig; sourceTree = "<group>"; };
6FF4AC462120B9E0002C96EB /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
6FF4AC482120B9E0002C96EB /* WireGuard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WireGuard.entitlements; sourceTree = "<group>"; };
+ 6FF717E421B2CB1E0045A474 /* InternetReachability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternetReachability.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>"; };
6FFA5DA32197085D0001E2F7 /* ActivateOnDemandSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivateOnDemandSetting.swift; sourceTree = "<group>"; };
@@ -248,6 +250,7 @@
children = (
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */,
6FFA5DA32197085D0001E2F7 /* ActivateOnDemandSetting.swift */,
+ 6FF717E421B2CB1E0045A474 /* InternetReachability.swift */,
);
path = VPN;
sourceTree = "<group>";
@@ -556,6 +559,7 @@
6FDEF806218725D200D8FBF6 /* SettingsTableViewController.swift in Sources */,
6F7774E1217181B1006A79B3 /* MainViewController.swift in Sources */,
6FFA5DA42197085D0001E2F7 /* ActivateOnDemandSetting.swift in Sources */,
+ 6FF717E521B2CB1E0045A474 /* InternetReachability.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift
index 8aa0c1a..1116f61 100644
--- a/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift
+++ b/WireGuard/WireGuard/UI/iOS/ErrorPresenter.swift
@@ -21,8 +21,12 @@ class ErrorPresenter {
return ("Unable to remove tunnel", "Internal error")
// TunnelActivationError
- case TunnelActivationError.tunnelActivationFailed:
+ case TunnelActivationError.tunnelActivationAttemptFailed:
return ("Activation failure", "The tunnel could not be activated due to an internal error")
+ case TunnelActivationError.tunnelActivationFailedInternalError:
+ return ("Activation failure", "The tunnel could not be activated due to an internal error")
+ case TunnelActivationError.tunnelActivationFailedNoInternetConnection:
+ return ("Activation failure", "No internet connection")
// Importing a zip file
case ZipArchiveError.cantOpenInputZipFile:
diff --git a/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift b/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift
index 6e77433..c2c7b58 100644
--- a/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift
+++ b/WireGuard/WireGuard/UI/iOS/TunnelsListTableViewController.swift
@@ -80,6 +80,7 @@ class TunnelsListTableViewController: UIViewController {
busyIndicator.stopAnimating()
tunnelsManager.delegate = s
+ tunnelsManager.activationDelegate = s
s.tunnelsManager = tunnelsManager
s.onTunnelsManagerReady?(tunnelsManager)
s.onTunnelsManagerReady = nil
@@ -312,6 +313,14 @@ extension TunnelsListTableViewController: TunnelsManagerDelegate {
}
}
+// MARK: TunnelActivationDelegate
+
+extension TunnelsListTableViewController: TunnelActivationDelegate {
+ func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelActivationError) {
+ ErrorPresenter.showErrorAlert(error: error, from: self)
+ }
+}
+
class TunnelsListTableViewCell: UITableViewCell {
static let id: String = "TunnelsListTableViewCell"
var tunnel: TunnelContainer? {
diff --git a/WireGuard/WireGuard/VPN/InternetReachability.swift b/WireGuard/WireGuard/VPN/InternetReachability.swift
new file mode 100644
index 0000000..7298d3f
--- /dev/null
+++ b/WireGuard/WireGuard/VPN/InternetReachability.swift
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018 WireGuard LLC. All Rights Reserved.
+
+import SystemConfiguration
+
+class InternetReachability {
+
+ enum Status {
+ case unknown
+ case notReachable
+ case reachableOverWiFi
+ case reachableOverCellular
+ }
+
+ static func currentStatus() -> Status {
+ var status: Status = .unknown
+ if let reachabilityRef = InternetReachability.reachabilityRef() {
+ var flags = SCNetworkReachabilityFlags(rawValue: 0)
+ SCNetworkReachabilityGetFlags(reachabilityRef, &flags)
+ status = Status(reachabilityFlags: flags)
+ }
+ return status
+ }
+
+ private static func reachabilityRef() -> SCNetworkReachability? {
+ let addrIn = sockaddr_in(sin_len: UInt8(MemoryLayout<sockaddr_in>.size),
+ sin_family: sa_family_t(AF_INET),
+ sin_port: 0,
+ sin_addr: in_addr(s_addr: 0),
+ sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+ return withUnsafePointer(to: addrIn) { (addrInPtr) -> SCNetworkReachability? in
+ addrInPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) { (addrPtr) -> SCNetworkReachability? in
+ return SCNetworkReachabilityCreateWithAddress(nil, addrPtr)
+ }
+ }
+ }
+}
+
+extension InternetReachability.Status {
+ init(reachabilityFlags flags: SCNetworkReachabilityFlags) {
+ var status: InternetReachability.Status = .notReachable
+ if (flags.contains(.reachable)) {
+ if (flags.contains(.isWWAN)) {
+ status = .reachableOverCellular
+ } else {
+ status = .reachableOverWiFi
+ }
+ }
+ self = status
+ }
+}
diff --git a/WireGuard/WireGuard/VPN/TunnelsManager.swift b/WireGuard/WireGuard/VPN/TunnelsManager.swift
index 0a3dd87..4306fd1 100644
--- a/WireGuard/WireGuard/VPN/TunnelsManager.swift
+++ b/WireGuard/WireGuard/VPN/TunnelsManager.swift
@@ -12,8 +12,14 @@ protocol TunnelsManagerDelegate: class {
func tunnelRemoved(at: Int)
}
+protocol TunnelActivationDelegate: class {
+ func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelActivationError)
+}
+
enum TunnelActivationError: Error {
- case tunnelActivationFailed
+ case tunnelActivationAttemptFailed // startTunnel() throwed
+ case tunnelActivationFailedInternalError // startTunnel() succeeded, but activation failed
+ case tunnelActivationFailedNoInternetConnection // startTunnel() succeeded, but activation failed since no internet
case attemptingActivationWhenTunnelIsNotInactive
case attemptingDeactivationWhenTunnelIsInactive
}
@@ -30,6 +36,7 @@ class TunnelsManager {
private var tunnels: [TunnelContainer]
weak var delegate: TunnelsManagerDelegate?
+ weak var activationDelegate: TunnelActivationDelegate?
private var isAddingTunnel: Bool = false
private var isModifyingTunnel: Bool = false
@@ -212,14 +219,27 @@ class TunnelsManager {
completionHandler(TunnelActivationError.attemptingActivationWhenTunnelIsNotInactive)
return
}
+
+ func _startActivation(of tunnel: TunnelContainer, completionHandler: @escaping (Error?) -> Void) {
+ tunnel.onActivationCommitted = { [weak self] (success) in
+ if (!success) {
+ let error = (InternetReachability.currentStatus() == .notReachable ?
+ TunnelActivationError.tunnelActivationFailedNoInternetConnection :
+ TunnelActivationError.tunnelActivationFailedInternalError)
+ self?.activationDelegate?.tunnelActivationFailed(tunnel: tunnel, error: error)
+ }
+ }
+ tunnel.startActivation(completionHandler: completionHandler)
+ }
+
if let tunnelInOperation = tunnels.first(where: { $0.status != .inactive }) {
tunnel.status = .waiting
tunnelInOperation.onDeactivationComplete = {
- tunnel.startActivation(completionHandler: completionHandler)
+ _startActivation(of: tunnel, completionHandler: completionHandler)
}
startDeactivation(of: tunnelInOperation)
} else {
- tunnel.startActivation(completionHandler: completionHandler)
+ _startActivation(of: tunnel, completionHandler: completionHandler)
}
}
@@ -249,6 +269,8 @@ class TunnelContainer: NSObject {
}
}
+ var isAttemptingActivation: Bool = false
+ var onActivationCommitted: ((Bool) -> Void)?
var onDeactivationComplete: (() -> Void)?
fileprivate let tunnelProvider: NETunnelProviderManager
@@ -289,8 +311,8 @@ class TunnelContainer: NSObject {
guard let tunnelConfiguration = tunnelConfiguration() else { fatalError() }
onDeactivationComplete = nil
- startActivation(tunnelConfiguration: tunnelConfiguration,
- completionHandler: completionHandler)
+ isAttemptingActivation = true
+ startActivation(tunnelConfiguration: tunnelConfiguration, completionHandler: completionHandler)
}
fileprivate func startActivation(recursionCount: UInt = 0,
@@ -299,7 +321,7 @@ class TunnelContainer: NSObject {
completionHandler: @escaping (Error?) -> Void) {
if (recursionCount >= 8) {
os_log("startActivation: Failed after 8 attempts. Giving up with %{public}@", log: OSLog.default, type: .error, "\(lastError!)")
- completionHandler(TunnelActivationError.tunnelActivationFailed)
+ completionHandler(TunnelActivationError.tunnelActivationAttemptFailed)
return
}
@@ -386,6 +408,18 @@ class TunnelContainer: NSObject {
object: connection,
queue: nil) { [weak self] (_) in
guard let s = self else { return }
+ if (s.isAttemptingActivation) {
+ if (connection.status == .connecting || connection.status == .connected) {
+ // We tried to start the tunnel, and that attempt is on track to become succeessful
+ s.onActivationCommitted?(true)
+ s.onActivationCommitted = nil
+ } else if (connection.status == .disconnecting || connection.status == .disconnected) {
+ // We tried to start the tunnel, but that attempt didn't succeed
+ s.onActivationCommitted?(false)
+ s.onActivationCommitted = nil
+ }
+ s.isAttemptingActivation = false
+ }
if ((s.status == .restarting) && (connection.status == .disconnected || connection.status == .disconnecting)) {
// Don't change s.status when disconnecting for a restart
if (connection.status == .disconnected) {