How to handle NWPath interface changes in a Packet Tunnel Extension in iOS?

While implementing a VPN using the Packet Tunnel Network Extension framework I've stumbled upon different problems I cannot see well documented.



I am monitoring the changes in the interface and its status observing defaultPath. How should I react to the interface changes.



  • Should I reset my tunnel when I go from WiFi to Cellular? Or should I reconnect it? I want to guarantee that when I perform an interface change my Internet traffic goes out using the tunnel interface.
  • What should I do when the status changes in NWPathStatus changes? I am having trouble when my status changes from WiFi (satisfied) to WiFi (satisfied). The VPN is still up but the outgoing traffic doesn't use the tunnel interface. I don't want to cancelTunnelWithError(_:) every time I see an interface change. While this solves the problem and forces the traffic to go out using the tunnel interface as it's reestablishing the tunnel again and again it drains the battery and it's not the correct approach. Specially when at home there are constant WiFi (satisfied) to WiFi (satisfied) network changes that I don't wrap my head around what they can mean.
  • How should I manage these changes when the device goes to and from sleep? There's a property, reasserting that specifies when the tunnel starts to reconnect, should I modify it when the device goes to sleep or when it wakes? And should I cancel or reconnect the tunnel when the device comes from sleep?



I haven't found much information on this so if someone could guide me a bit on how to solve this it'd be great.

Replies

I am monitoring the changes in the interface and its status observing

defaultPath
.

That seems like the wrong place to start. The standard approach is to monitor the path associated with your tunnel connection for:

  • The path failing

  • A better path becoming available

You can then attempt a new tunnel connection and transition to that.

Should I reset my tunnel when I go from WiFi to Cellular?

That depends on your underlying tunnel infrastructure. You could, for example, using Multipath TCP, in which case you don’t have to do anything (-: More realistically, if you are able to reconnect over WWAN without ‘breaking’ the tunnel interface — that is, without making changes to the tunnel network settings (

NETunnelNetworkSettings
) that would cause connections running over the tunnel interface to break — then go for it. That definitely produces the better experience for apps running connections through your tunnel.

It’s possible that the new tunnel will require new tunnel network settings. You can apply them directly, without cancelling the tunnel entirely, but that might break connections running over the tunnel interface.

You should only cancel the tunnel if you’ve exhausted the reconnection options and you’re sure that the tunnel is irrecoverable.

In all case, you generally want to set the status to

NEVPNStatusReasserting
while this is in progress.

Finally, it’s a good idea to debounce path notifications for half a second or so, just to avoid doing massive amounts of work based on a transient event.

How should I manage these changes when the device goes to and from sleep?

Have you seen my VPN and sleep post already?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

How could I monitor the path associated with my tunnel connection for the path failing or having a better one available? That's so I can transition to a newly established tunnel as you say.


> Have you seen my VPN and sleep post already?


Yes, it's pretty insightful but I also have some questions about it. I am quiescing my tunnel in the sleep method, actually pausing it and setting reasserting to true there. So when the device wakes up it knows that it has to reconnect/reactivate the tunnel. But I don't know how to monitor if the reactivation fails.


Also, should I do some adjusting to the network settings when my interfaces changes from Wifi (satisfied) to WiFi (satisfied), in some cases my tunnel works and in others not when this change of interface happens and I'd like to understand what's happening in this transition.

Are you using

NWConnection
for your tunnel? If not, what? And is it TCP or UDP?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"