The Network Extension framework is one of the most customizable frameworks that Apple provides. Allowing you to customize and extend the core networking features of iOS and macOS.
While this article by Alexander Grebenyuk covers this topic in depth I would like to add some things I have learnt.
I have recently worked on a project implementing a VPN using the OpenVPN protocol. This is not supported natively by the networking framework and requires a third party library, like OpenVPNAdapter.
Imagine you want to tunnel all your outgoing traffic using the VPN connection. All your traffic will be sent to your VPN server, that is also your DNS server. This solution can be used to block certain websites, like gambling or adult content and to access an internal company website.
This can be done in iOS using a
Packet Tunnel and for this to be published to the App Store it couldn't be done with frameworks that require managed devices.
For unmanaged devices there are some things at our hand. Like playing around with the on demand rules. This allows the system to automatically start a VPN connection based on different rules. In this case forcing the system to establish a tunnel whenever it acquires internet connectivity, Cellular or WiFi.
OpenVPN has implemented their own solution for an always on VPN tunnel, called seamless tunnel. The implementation is not public but it seems to work for them.
Implementing a Packet Tunnel Network Extension will divide the app into two targets. Your main app where your app will reside and the target that subclasses
NEPacketTunnelProvider. Subclassing this class will grant us access to a virtual network interface. Creating a packet tunnel provider requires to configure the
The main app will only be in charge of doing tasks like configuring de VPN profile into the device Settings app. And the target will be doing all the networking operations: starting, stopping and managing all the states the tunnel could be in.
As there is not a lot of documentation or projects here are some of the things that explain how this framework works and how you can manage to build an always on VPN tunnel on iOS devices.
KEEPALIVE_TIMEOUTmessages are used to sense the other side of the tunnel and make sure it's up/down. If your device is unplugged the tunnel could have died and your traffic will be going out using another interface.
URLSessiondo not redirect traffic through the interface in the extension. Lower level APIs like
createTCPConnectionThroughTunnelcan force traffic to go out of the tunnel.
wakemethods. In the first one you should quiesce the tunnel as appropiate and with the latter reactivate the tunnel. More info here.
defaultPath, it's not a good idea to base your reconnecting logic on network changes. The standard approach is to monitor the path associated with your tunnel connection for: the path failing or a new tunnel connection and transition to that. Source.
URLSessiondone from the network extension doesn't leave the tunnel using the
tuninterface but this done from the main target the petition leaves the device using the
OpenVPNAdapterlibrary there are some properties that are
nilunless the tunnel is connected like
sessionName. I've checked if this value is
nilafter waking up and in cases where the tunnel was not active the returning value wasn't
nilso I am not completely sold on this working perfectly.
KEEPALIVE_TIMEOUTmessages. I've opened an issue in the OpenVPNAdapter library to treat this messages as errors instead.