iOS Personal VPN and Network Extensions: A Developer's Guide
When to use Personal VPN and what is Network Extension?
Introduction
In today's interconnected world, the ability to control and secure network traffic is paramount for mobile applications. From safeguarding user data to enabling specialized communication, robust networking capabilities are no longer just a feature but a fundamental requirement. Apple provides powerful frameworks within iOS and macOS to empower developers with this control: Personal VPN and Network Extensions. These frameworks offer a deep level of integration with the operating system's networking stack, allowing for sophisticated solutions that range from content filtering to custom virtual private networks.
Years ago, when they were not so popular like today, I’ve worked on plain IPsec VPN protocols and now, after years, again working on implementing such features for agricultural company in Europe. They have many representatives “in-field”. But access to shared company storages is required since there are no unified application to provide such ability. That’s how I opened the doors of a VPN apps again.
We will delve into what Network Extensions and Personal VPN capabilities are, explore their distinct functionalities, and clarify when to leverage each for your application's needs. Furthermore, we will address a critical question for many developers: the persistence of VPN connections even after the main application terminates. By the end of this guide, you will have a comprehensive understanding of these frameworks, enabling you to build more secure, efficient, and feature-rich network-aware applications for the Apple ecosystem.
Let’s start!
Personal VPN with built-in protocols
Within the broader Network Extension framework, Personal VPN stands out as a specific capability designed to simplify the creation and management of Virtual Private Network (VPN) configurations using Apple's built-in protocols. This capability allows your application to establish and control a VPN connection for the entire device, providing a secure and private tunnel for all network traffic. It is particularly useful for applications that aim to offer a straightforward VPN service to their users without needing to implement complex custom tunneling protocols.
Key features and aspects of the Personal VPN capability include:
Built-in Protocols: Personal VPN primarily leverages Apple's native support for IPsec (Internet Protocol Security) and IKEv2 (Internet Key Exchange version 2) protocols. These are widely adopted and secure VPN protocols, ensuring compatibility and reliability with a broad range of VPN servers. This focus on built-in protocols simplifies development, as you don't need to implement the low-level details of the VPN tunnel yourself.
NEVPNManager and NEVPNConnection: The core of Personal VPN management. The NEVPNManager class is a singleton that allows your app to create, load, modify, and save VPN configurations to the system's preferences. Once a configuration is saved and activated, the NEVPNConnection class is used to control the VPN connection, enabling you to start, stop, and monitor its status.
Personal VPN is the ideal choice when your application's primary objective is to provide a standard VPN connection using the well-established IPsec or IKEv2 protocols. This is common for consumer-facing VPN applications, privacy tools, or enterprise apps that integrate with existing VPN infrastructure. If your needs are met by these built-in protocols and you don't require the deeper customization or specialized functionalities offered by other Network Extension capabilities (like custom packet tunneling or content filtering), Personal VPN offers a streamlined and efficient solution.
For comprehensive details on implementing and managing Personal VPN connections, consult the official Apple Developer Documentation: Personal VPN.
Simple IPSec Connection
import NetworkExtension
final class VPNConnector {
func configureAndConnectVPN() {
let vpnManager = NEVPNManager.shared()
// Load existing configuration first
vpnManager.loadFromPreferences { error in
if let error = error {
print("Failed to load VPN preferences: \(error)")
return
}
// Create IPSec protocol configuration
let protocolConfiguration = NEVPNProtocolIPSec()
protocolConfiguration.username = "your-username"
protocolConfiguration.serverAddress = "vpn.example.com"
// Store password in Keychain and reference it
protocolConfiguration.passwordReference = self.getKeychainPasswordReference(for: "vpn-password")
protocolConfiguration.authenticationMethod = .sharedSecret
protocolConfiguration.sharedSecretReference = self.getKeychainPasswordReference(for: "vpn-shared-secret")
// Additional protocol settings
protocolConfiguration.useExtendedAuthentication = true
protocolConfiguration.disconnectOnSleep = false
// Assign configuration to VPN Manager
vpnManager.protocolConfiguration = protocolConfiguration
vpnManager.localizedDescription = "My VPN"
vpnManager.isEnabled = true
// Save the updated preferences
vpnManager.saveToPreferences { error in
if let error = error {
print("Failed to save VPN preferences: \(error)")
return
}
print("VPN configuration saved.")
// Known bug
// See https://forums.developer.apple.com/thread/25928
vpnManager.loadFromPreferences { [weak self] error in
if let error = error {
print("Failed to reload VPN preferences: \(error)")
return
}
// Start VPN connection
do {
try vpnManager.connection.startVPNTunnel()
print("VPN connection started.")
} catch {
print("Failed to start VPN: \(error)")
}
}
}
}
}
// Helper: Retrieve Keychain reference for stored credentials
private func getKeychainPasswordReference(for account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecReturnPersistentRef as String: true
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else { return nil }
return (item as? Data)
}
}
If you are planning for something more flexible or secured, you are stepping into Network Extension area…
Understanding Network Extensions Capability
Network Extensions is a comprehensive framework provided by Apple that allows developers to customize and extend the core networking features of iOS and macOS. It provides a powerful set of APIs to interact with the system's network stack, enabling applications to implement a wide range of network-related functionalities that go beyond typical app-level networking. This framework is essential for applications that require deep integration with the operating system's network infrastructure, such as security applications, parental control software, or specialized enterprise tools.
The versatility of Network Extensions is evident in the various types of capabilities it offers, each designed for a specific aspect of network control:
App Proxy: This capability allows your application to provide a virtual private network (VPN) client for a flow-oriented, custom VPN protocol. Unlike traditional packet-based VPNs, an app proxy operates at the application layer, allowing for more granular control over network traffic on a per-app basis. This is particularly useful for scenarios where specific application traffic needs to be routed through a custom tunnel, while other traffic remains unaffected.
Content Filter: With the Content Filter capability, your app can examine user content as it passes through the network stack and determine whether the system should allow or block it. This is the foundation for building robust content filtering solutions, parental control apps, or enterprise security tools that can enforce network usage policies. The filter can inspect network data and make real-time decisions, providing a powerful mechanism for network security and compliance.
Packet Tunnel: This is the capability used for implementing a VPN client for a packet-oriented, custom VPN protocol. In contrast to App Proxy, Packet Tunnel operates at a lower level, handling IP packets directly. This allows for the creation of traditional VPNs that tunnel all network traffic from the device through a secure connection. Developers can implement their own custom VPN protocols, offering flexibility beyond the built-in IPsec or IKEv2 options.
DNS Proxy: The DNS Proxy capability enables your app to be responsible for resolving all DNS queries on-device using a custom protocol. This is invaluable for applications that need to implement custom DNS resolution logic, such as ad-blockers that resolve known ad domains to a non-existent IP address, or privacy-focused apps that route DNS queries through encrypted channels.
DNS Settings: This capability allows your app to create and manage a system-wide DNS configuration using modern DNS protocols like DNS-over-TLS (DoT) and DNS-over-HTTP (DoH). By leveraging this, applications can ensure that all DNS traffic on the device uses secure and private channels, enhancing user privacy and security by preventing DNS tampering or eavesdropping.
Developers should consider using Network Extensions when their application requires advanced network functionalities that go beyond simple data transmission. This includes scenarios such as building a custom VPN client with a proprietary protocol, creating a comprehensive content filtering solution for parental controls or enterprise security, implementing a custom DNS resolver, or managing system-wide DNS settings for enhanced privacy. The framework provides the necessary tools to deeply integrate with the operating system's networking stack, offering unparalleled control and flexibility.
For more detailed information on configuring and utilizing these capabilities, refer to the official Apple Developer Documentation: Configuring network extensions.
Provider Deployment Restriction: deploying different types of Extension meet different restriction. Some work only on managed devices, some on supervised.
All explained in TN3134.
Simple Custom Connection
By creating such Extension from Xcode → New Target and choosing Packet Tunnel, you will get a placeholder implementation of NEPacketTunnelProvider
. It holds the main logic of connection and service lifecycle. Implementation is varies from protocol to protocol. WireGuard, OpenVPN (with his own variations), Xray, etc.
Sharing a stub with you:
class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
// Add code here to start the process of connecting the tunnel.
}
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Add code here to start the process of stopping the tunnel.
completionHandler()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
// Add code here to handle the message.
if let handler = completionHandler {
handler(messageData)
}
}
override func sleep(completionHandler: @escaping () -> Void) {
// Add code here to get ready to sleep.
completionHandler()
}
override func wake() {
// Add code here to wake up.
}
}
For all those who are wondering “How deep is the rabbit hole?“ - there is a corner stone of all VPN implementations: Partout
Network extension is steel need to be configured on the main app!
NEVPNManager
is still required to save the configuration. This is unavoidable because you might establish VPN connection without app. It’s the independence feature of a NEtwork eXtension and will be explained further.
Now let’s split when you should use each of the VPN branches.
Network Extensions vs. Personal VPN: Key Differences and Use Cases
While Personal VPN is a component of the broader Network Extension framework (as I mention before), understanding their distinct roles and capabilities is crucial for iOS developers. The choice between leveraging the general Network Extensions framework and specifically the Personal VPN capability depends entirely on the complexity and nature of the network control your application requires.
Here’s a breakdown of their key differences:
Choose Personal VPN when:
Your primary goal is to provide a standard VPN connection using the widely supported IPsec or IKEv2 protocols.
Want to leverage Apple's built-in VPN client infrastructure, which handles much of the underlying complexity of establishing and maintaining the VPN tunnel.
Application is a consumer-facing VPN service that aims for ease of use and compatibility with standard VPN servers.
Need to establish a system-wide VPN connection that routes all device traffic through the VPN, without needing to differentiate traffic per application or implement custom filtering logic.
Choose Network Extensions when:
You need to implement a custom VPN protocol that is not IPsec or IKEv2. This would involve using NEPacketTunnelProvider for packet-level tunneling or NEAppProxyProvider for flow-based proxying.
Application requires content filtering capabilities, such as blocking specific websites, categories of content, or enforcing network usage policies. The NEFilterDataProvider and NEFilterControlProvider are key here.
Building a custom DNS solution, like an ad-blocker that operates at the DNS level, or a privacy tool that encrypts DNS queries. This involves NEDNSProxyProvider or NEDNSSettingsManager.
Need to inspect or modify network traffic at a low level for security, analytics, or optimization purposes.
Apple also have a Technical Note regarding Network Extensions usage.
TN3120: Expected use cases for Network Extension packet tunnel providers.
In essence, if your needs are met by a standard IPsec or IKEv2 VPN connection, Personal VPN offers a simpler and more direct path. However, if your application demands deeper network control, custom protocols, or specialized traffic manipulation (like content filtering or custom DNS), the broader Network Extensions framework provides the necessary tools and flexibility. Understanding this distinction is fundamental to designing robust and efficient network-aware applications for iOS.
VPN Persistence and Connection Management
One of the most critical considerations for any application providing VPN services is the ability of the VPN connection to persist, even when the main application that initiated it is no longer running. For iOS developers, this is a frequently asked question: Can a VPN connection established via Network Extension persist on main app termination? Is it possible?
The answer is a resounding yes, and this capability is a cornerstone of the Network Extension framework's design. Apple has engineered this framework to allow VPN connections to operate at a system level, independent of the lifecycle of the application that configured them. This is a significant advantage, as it ensures continuous network security and privacy for the user, even if they close your application or if the operating system terminates it due to resource constraints.
How VPN Persistence Works
The key to VPN persistence lies in how Network Extension providers operate. When you configure a VPN using NEVPNManager and save it to the system preferences, you are essentially instructing the operating system to manage this VPN configuration. The actual VPN tunnel is not established or maintained by your main application's process. Instead, it is handled by a separate, privileged process known as a Network Extension provider (e.g., NEPacketTunnelProvider for custom packet-based VPNs or NEAppProxyProvider for flow-oriented VPNs).
These Network Extension providers run as system extensions, meaning they operate outside of your application's sandbox and are managed directly by the iOS or macOS kernel. Therefore, once the VPN connection is established and activated, the operating system takes over its management. If your main application is terminated—whether by the user swiping it away from the app switcher, a system memory warning, or even a device restart—the VPN connection can remain active in the background, continuously managed by the system's Network Extension process.
Key Mechanisms for Persistence
Several mechanisms contribute to the robust persistence of VPN connections configured through Network Extensions:
System-Level Management: As mentioned, Network Extension providers are system processes. This architectural design ensures that they are not tied to the lifecycle of the foreground application. They can start, stop, and maintain connections as needed by the operating system, providing a stable and reliable VPN service.
VPN On Demand: iOS and macOS offer a powerful feature called "VPN On Demand." This allows developers to define rules that automatically trigger the VPN connection based on specific network conditions or events. For example, you can configure the VPN to connect automatically when the device joins a particular Wi-Fi network, attempts to access certain domains, or when a specific application tries to access the internet. This ensures that the VPN is active precisely when needed, without requiring the user to manually open your application or activate the VPN.
Background Modes (Indirectly): While background modes in your main application do not directly maintain the VPN connection (that's the job of the extension), they can play an indirect role in managing the VPN. For instance, your main application might use background fetch or silent push notifications to periodically check the VPN status, re-authenticate if necessary, or update the VPN configuration. This allows for a more dynamic and responsive VPN service.
Important Considerations
While VPN persistence is a powerful feature, there are several important considerations for developers:
User Authorization: The user must explicitly authorize the VPN configuration when it is first saved to the system. This is a crucial security and privacy measure, ensuring that users are fully aware that their network traffic will be routed through your VPN service. Without this initial authorization, the VPN cannot be established or persisted.
System Resources: Although Network Extension providers are designed to be resilient, the system may still terminate them under extreme memory pressure or if they consume excessive resources. Developers should optimize their extension code to be as efficient as possible to minimize the chances of being terminated by the system.
Basic tips are:
- Handle sleep
and wake
events to restore state.
Store necessary connection info in App Group shared storage for recovery.
Configuration Updates: If the VPN configuration (e.g., server address, authentication credentials) needs to be updated, the main application is typically responsible for this. The app would load the existing configuration using NEVPNManager, modify it, and then save the updated configuration back to the system preferences. The system will then apply the new configuration to the running VPN extension.
On-Demand rules: Use triggers like specific Wi-Fi networks or domain matches. Basic setup for SSID detection with Wi-FI interface connection:
let onDemandRule = NEOnDemandRuleConnect()
onDemandRule.interfaceTypeMatch = .wiFi
onDemandRule.ssidMatch = ["OfficeNetwork"]
manager.onDemandRules = [onDemandRule]
manager.isOnDemandEnabled = true
manager.saveToPreferences { error in
if let error = error {
print("Failed to save on-demand rules: \(error)")
} else {
print("On-demand rules saved")
}
}
You can also use NEOnDemandRuleEvaluateConnection
with NEEvaluateConnectionRule
to trigger the VPN based on matching domains.
Conclusion
Apple's Network Extensions framework, encompassing capabilities like Personal VPN, Content Filtering, and DNS Proxying, offers iOS developers an unparalleled level of control over the device's networking stack. As we've explored, understanding the nuances between the general Network Extensions framework and the specific Personal VPN capability is crucial for building effective and secure applications.
Network Extensions provides the foundational tools for deep network integration, allowing for custom VPN protocols, granular content filtering, and advanced DNS management. It's the go-to choice when your application demands specialized network manipulation beyond standard VPN connections.
Personal VPN, on the other hand, streamlines the process of establishing system-wide VPN connections using Apple's built-in IPsec and IKEv2 protocols. It's ideal for consumer-facing VPN services that prioritize ease of use and compatibility with established VPN standards.
For developers, mastering these frameworks unlocks the potential to create highly secure, efficient, and feature-rich network-aware applications. Whether you're building a security solution, a privacy tool, or an enterprise application requiring specific network behaviors, the Network Extension framework provides the necessary power and flexibility. By carefully considering your application's specific networking needs and leveraging the appropriate capabilities, you can deliver a superior and more reliable user experience in the ever-evolving landscape of mobile connectivity.
DNS proxy and content filtering are only available on fully managed devices