Issue with Establishing VPN Connection Through Custom App

Description:

I am experiencing a persistent issue with establishing a VPN connection through a custom app I've developed using Swift. While the VPN configuration appears to be loaded successfully, attempts to connect result in immediate disconnection. Here are the details:

Problem Summary: I have implemented a VPN connection using Swift with the NetworkExtension and TunnelKit frameworks. My application successfully loads the VPN configuration, but when attempting to connect, the VPN status quickly changes from connecting to disconnected without ever achieving a stable connection. Manually attempting to toggle the connection from device settings results in the toggle switching off as soon as it is turned on. The console logs indicate a transition from 'connecting' to 'disconnected' almost simultaneously.

Technical Details: Here is an overview of the relevant part of the code used for setting up and managing the VPN connection:

import TunnelKitOpenVPNCore
import NetworkExtension
import TunnelKit

class VPNManager {
    static let shared = VPNManager()
    private var providerManager: NETunnelProviderManager?

    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(vpnStatusDidChange), name: .NEVPNStatusDidChange, object: nil)
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    @objc func vpnStatusDidChange(notification: Notification) {
        guard let status = self.providerManager?.connection.status else { return }
        switch status {
        case .connecting:
            print("VPN is connecting")
        case .connected:
            print("VPN is connected")
        case .disconnecting:
            print("VPN is disconnecting")
        case .disconnected:
            print("VPN is disconnected")
        case .invalid:
            print("VPN configuration is invalid")
        case .reasserting:
            print("VPN is reasserting")
        @unknown default:
            print("Unknown VPN status")
        }
    }

    func loadAndCreateVPNProfile(completion: @escaping (Bool, Error?) -> Void) {
        self.providerManager = NETunnelProviderManager()
        
        guard let ovpnURL = Bundle.main.url(forResource: "client", withExtension: "ovpn"),
              let ovpnContents = try? String(contentsOf: ovpnURL) else {
            completion(false, NSError(domain: "VPNManagerError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Configuration file could not be read or found."]))
            return
        }

        // Parsing and configuration logic here...

        self.providerManager?.saveToPreferences { error in
            if let error = error {
                print("Error saving preferences: \(error.localizedDescription)")
                completion(false, error)
            } else {
                print("VPN profile saved successfully.")
                completion(true, nil)
            }
        }
    }

    func connect() {
        self.providerManager?.loadFromPreferences { [weak self] error in
            guard let strongSelf = self else {
                print("Reference to VPNManager lost.")
                return
            }
            if let error = error {
                print("Failed to load preferences: \(error.localizedDescription)")
                return
            }

            do {
                try strongSelf.providerManager?.connection.startVPNTunnel()
            } catch NEVPNError.configurationInvalid {
                print("VPN Configuration is invalid.")
            } catch NEVPNError.configurationDisabled {
                print("VPN Configuration is disabled.")
            } catch let error {
                print("Unexpected error: \(error.localizedDescription)")
            }
        }
    }
    
    func disconnect() {
        providerManager?.connection.stopVPNTunnel()
    }
}

Replies

I have implemented a VPN connection using Swift with the NetworkExtension and TunnelKit frameworks.

I can’t help you with third-party tools or libraries. You can either:

  • Escalate this via the support resources for that library.

  • Or, if the library is open source, dig into the code to find out where things are going wrong.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

How can I establish an OpenVPN connection without using third-party libraries?

How can I establish an OpenVPN connection without using third-party libraries?

You can’t. Well, you can, but lemme explain…

Our platforms include support for IKEv2 and IPsec VPNs [1]. If your VPN server speaks these protocols, you can create and manage a configuration for it using the Personal VPN API. If not, you need to add support for a custom VPN transport by creating a Network Extension packet tunnel provider.

If you do the latter, you are responsible for implementing the on-the-wire protocol spoken by your VPN server. If that server speaks a well-known protocol, there might be third-party libraries you can use for this. If not, or if you don’t want to depend on a third-party library, you can write your own implementation based on our networking APIs.

If you choose to use a third-party library for this, I can’t help you with that code.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] And the deprecated L2TP.