Killswitch

When using a VPN service to secure your internet connection and protect your privacy online, an unexpected disconnection from the VPN server can potentially expose your real IP address and traffic. This is where the VPN Killswitch feature comes in.

What is a VPN Killswitch?

The killswitch module activates when the VPN tunnel is initiated, before the secure connection is fully established. Once enabled, the killswitch blocks all network traffic outside of the VPN tunnel, with the following exceptions:

  • Local network traffic: A separate module manages local network traffic, allowing communication within the local network environment.

  • Bypassed processes and domains: The killswitch allows direct connections for specific processes or domains that are explicitly permitted through user-defined rules.

Use Cases

Use Case
Description

Securing communications in iOS messaging apps

Businesses often need to communicate sensitive information via iOS messaging apps. If the VPN drops while these apps are in use, the messages could be intercepted. An automatic killswitch maintains the confidentiality of business communications within iOS messaging apps.

Handling network transitions on iOS devices

iOS devices frequently transition between different networks - from office Wi-Fi to cellular data, or when moving between office locations. These transitions can sometimes cause VPN disconnections on iOS. A killswitch prevents sensitive work done in iOS apps from being exposed during these network switches.

Maintaining location privacy for GPS and location services

Many iOS apps use GPS and location services for mapping, tracking, and geo-targeted content. For professionals who travel frequently or work in sensitive industries, keeping their location private is important. If the VPN disconnects, this location information could leak through iOS location services. An iOS killswitch prevents unexpected location exposure.

Preventing leaks from iOS background app refresh

iOS allows apps to refresh content in the background, which can leak data over an unsecured connection if the VPN disconnects. An iOS killswitch can block background network traffic if the VPN is down, preventing data leaks from background app refresh.

Enabling Killswitch

To implement a killswitch in an iOS VPN application, you can take advantage of the vpnWillStop method. This method is called when the VPN is about to stop, either due to an error or user-initiated action.

The method signature looks like this:

func vpnWillStop(withError error: VPNTunnelError?,
                 availableRestartCompletion: ((_ shouldRestart: Bool) -> Void)?)  

The error parameter indicates the reason for the VPN stoppage:

Condition
Description

error is nil

It means the stop was user-initiated.

error has a value

It specifies the tunnel error that caused the stop.

The availableRestartCompletion parameter is key for implementing the killswitch:

Condition
Description

availableRestartCompletion is nil

the VPN is stopping without any error. In this case, the killswitch feature is not needed. Note that we do not provide availableRestartCompletion if the shutdown is requested by the system, even if there is an error in that process.

availableRestartCompletion has a non-nil value

it means the VPN is stopping unexpectedly with an error. The extension will enter "killswitch mode", blocking all network traffic until availableRestartCompletion is called.

Inside the closure passed to availableRestartCompletion, you can decide whether to restart the VPN connection:

Condition
Description

Passing true e.g. completion(true)

Restarts the VPN extension immediately without killing it, using the same delegate object.

Passing false (or not calling the closure) e.g. completion(false) or not calling

  • Will terminate the extension. A new delegate object is created on the next launch.

  • Note that there is a risk of a IP leak. When the extension is killed, there will be a brief period before the new instance starts, during which an IP leak might occur.

Code Samples

Here's an example implementation of vpnWillStop to enable the killswitch:

extension PacketTunnelProvider: BaseNetworkExtensionDelegate {
    // ...
    func vpnWillStop(withError error: HydraTunnelProvider.VPNTunnelError?, availableRestartCompletion: ((_ shouldRestart: Bool) -> Void)?) {
        guard let completion = availableRestartCompletion else {
            return // No error, killswitch not needed
        }
    
        // Decide whether to restart based on the error
        let shouldRestart: Bool
        switch error {
        case .connectionCouldNotBeEstablished:
            // Server disconnected or connection couldn't be established
            print("Server disconnected or connection couldn't be established. Attempting to restart.")
            shouldRestart = true
        default:
            // For other cases, no need to restart
            shouldRestart = false
        }

        completion(shouldRestart)
    }
    // ...
}

In this example:

  1. If availableRestartCompletion is nil, the method returns early since no killswitch is needed.

  2. If there is an availableRestartCompletion, the code decides whether to restart based on the specific error. Here it restarts only for a .connectionCouldNotBeEstablished error as an example.

  3. It calls completion(_:) with this boolean to either restart the tunnel or let it terminate.

Last updated