How to deactivate on demand connect VPN from network extension?

814 Views Asked by At

I have configured an always on VPN with a NEOnDemandRuleConnect I retrieve some user data from a backend such as expiration date if the user has paid the subscription. If it expires I'd like to deactivate the VPN without opening the main app, doing it from the Network Extension. I retrieve the data from the backend using a daily timer and then check if the subscription has expired. Then I'd have a function that loads the VPN manager from the system settings app and then deactivate it and finally save it. If I don't deactivate the manager the device will be without connection as it's a VPN that has been configured to connect always with the NEOnDemandRule. The function will be more or less this one

func stopProtection(completion: @escaping (Result<Void>) -> Void) {

    NSLog("Called stopProtection")

    NETunnelProviderManager.loadAllFromPreferences { (managers, error) in

        if let error = error {
            NSLog("[SUBS] ERROR \(error)")
        }

        if let managers = managers {
            if managers.count > 0 {
                let index = managers.firstIndex(where: { $0.localizedDescription == Constants.vpnBundleId })

                guard let index = index else {
                    completion(.error(ProtectionServiceError.noKidsVpnInstalled))
                    return
                }

                let myManager = managers[index]

                myManager.loadFromPreferences(completionHandler: { (error) in
                    guard error == nil else {
                        completion(.error(ProtectionServiceError.errorStoppingTunnel))
                        return
                    }

                    // Deactivate the VPN and save it
                    myManager.isEnabled = false

                    myManager.saveToPreferences(completionHandler: { (error) in
                        guard error == nil else {
                            completion(.error(ProtectionServiceError.errorStoppingTunnel))
                            return
                        }

                        completion(.success(()))
                    })
                })
            } else {
                completion(.error(ProtectionServiceError.errorStoppingTunnel))
            }
        }
    }
}

All this code and logic is being performed in the extension with all the limitations it supposes. Using the previous function I'd only get the first NSLog saying Called stopProtection but it doesn't load any manager. Calling this from the main target it'd work. I don't know if I can load and modify the manager from the extension or it's another way to do it.

1

There are 1 best solutions below

1
On

Okay, I have debugged the network extension by attaching to the process and looking into the device Console and this error pops up,

NETunnelProviderManager objects cannot be instantiated from NEProvider processes

So nope, there's the answer!