NEPacketTunnelProvider

Hello, I am developing a vpn app using several protocols, one of them is Wireguard. When the app is terminated, there is a tunnel that vpn is still communicating with which is a subclass of NEPacketTunnelProvider. In some cases when stopping the tunnel using wireguardAdapter.stop(withcompletionHandler:) func it may throws an error of stopping the tunnel, in this case I want to force stop the tunnel, but when on-demand is on it will try to reconnect and the user will remains without internet connection on his wifi until he turns off the on-demand by his hand. I tried to call the NEVPNMnager and load preference and then turn on-demand of then stop the tunnel and it did not works. here is my code.

` let manager = NEVPNManager.shared()

        manager.loadFromPreferences { error in
            if let error = error {
              self.wgLogger.log("Error loading from preferences: \(error, privacy: .public)")
              return
            }

            manager.isOnDemandEnabled = false

            manager.saveToPreferences { error in
              if let error = error {
                self.wgLogger.log("Error saving to preferences: \(error, privacy: .public)")
                return
              }
              manager.connection.stopVPNTunnel()
              self.wgLogger.log("VPN tunnel stopped successfully.")
            }
        }
Answered by DTS Engineer in 756382022

i am just calling stopTunnel

Oi vey!, that’s not good. Quoting the docs for stopTunnel(with:completionHandler:):

This method is called by the system to stop the network tunnel.

and:

Do not use this method to stop the tunnel from the Packet Tunnel Provider. Use -cancelTunnelWithError: instead.

So, the system calls stopTunnel(with:completionHandler:) when it wants you to stop the tunnel. You are meant to override that to actually stop the tunnel. You are not meant to call it directly. Rather, to stop the tunnel from within your provider, call cancelTunnelWithError(_:).

This is reiterated in the docs for cancelTunnelWithError(_:):

The Packet Tunnel Provider should call this method when an unrecoverable error occurs, such as the tunnel server going down or the VPN authentication session expiring.

Share and Enjoy

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

I tried to call the NEVPNManager and load preference and then turn on-demand of then stop the tunnel and it did not works.

Are you trying to do that from within your provider? That won’t work. The configuration API can only be used by the container app.

As to what you can do about this, it kinda depend on the context. To start, is your packet tunnel provider working in destination IP or source IP (per-app VPN) mode?

Share and Enjoy

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

Thanks for your answer. Then what should I do to force stop the tunnel if an error occurs while stopping the tunnel or starting the tunnel since the user is goin in a zombie tunnel (can not connect to internet if he did not turn off on demand)

Then what should I do

A good place to start would be to answer the second question I posed in my previous post (-:

Share and Enjoy

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

destination IP

OK, cool.

Are your claiming the default route?

Share and Enjoy

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

No I am not using the default route

No I am not using the default route

Interesting. That wasn’t the answer I was expecting.

How have you configured VPN On Demand?

Share and Enjoy

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

              self.wireguardProvider.isOnDemandEnabled = autoReconnect
self.wireguardProvider.saveToPreferences { (error) -> Void in .... }

isOnDemandEnabled is just a Boolean, and I assume you had that set to true (-: I’m was asking about values you place in onDemandRules.

Share and Enjoy

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

Sorry, my bad

var onDemandRules = [NEOnDemandRule]()
let autoReconnectRule = NEOnDemandRuleConnect()
    autoReconnectRule.interfaceTypeMatch = .any
    onDemandRules.append(autoReconnectRule)

OK, thanks.

When the underlying VPN fails, do you call -cancelTunnelWithError:?

Share and Enjoy

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

No, i am just calling stopTunnel, does this function -cancelTunnelWithError: force stop the tunnel even when there is an error ?

Accepted Answer

i am just calling stopTunnel

Oi vey!, that’s not good. Quoting the docs for stopTunnel(with:completionHandler:):

This method is called by the system to stop the network tunnel.

and:

Do not use this method to stop the tunnel from the Packet Tunnel Provider. Use -cancelTunnelWithError: instead.

So, the system calls stopTunnel(with:completionHandler:) when it wants you to stop the tunnel. You are meant to override that to actually stop the tunnel. You are not meant to call it directly. Rather, to stop the tunnel from within your provider, call cancelTunnelWithError(_:).

This is reiterated in the docs for cancelTunnelWithError(_:):

The Packet Tunnel Provider should call this method when an unrecoverable error occurs, such as the tunnel server going down or the VPN authentication session expiring.

Share and Enjoy

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

NEPacketTunnelProvider
 
 
Q