Network Extension Setup

Network extension setup

You should already have prepared application target in order to continue, if you haven't done it yet, please check this.

Create network extension target

You need to create network extension in order to use Hydra and WireGuard protocols.

Go to Project -> Targets, and in menu bar select Editor > Add Target. Select needed platform (iOS or macOS), then choose Network Extension type, provide the name and bundle ID for this Network Extension target.

NOTE: It is recommended to give distinctive names to your targets and bundle IDs with mention of target protocol, e.g. for Hydra:

  • Application target: MyApp, com.blabla.myapp

  • Network extension target: MyApp Hydra Provider, com.blabla.myapp.hydraprovider

Install tunnel provider SDK

At this point you have to have at least two targets:

  • Application target

  • Network Extension target

Now you should link tunnel provider SDK to the Network Extension target. We're providing SDK packed as xcframework, which means it can be used both for iOS and macOS apps.

Manual

  1. Link frameworks:

Hydra

  • Copy HydraTunnelProvider.xcframework file to some place inside your project folder on disk.

  • Go to Project -> Network Extension Target -> General and drag copied framework to Frameworks, Libraries and Embedded Content section.

  • Set Do Not Embed under Embed and sign option for HydraTunnelProvider.framework.

WireGuard

  • Copy WireguardTunnelProvider.framework file to some place inside your project folder on disk.

  • Go to Project -> Network Extension Target -> General and drag copied framework to Frameworks, Libraries and Embedded Content section.

  • Set Do Not Embed under Embed and sign option for WireguardTunnelProvider.framework.

  1. Link NetworkExtension system framework to the Network Extension target.

  2. Link libz.tbd and libresolv.tbd libraries to the Network Extension target.

  3. Go to Project -> Network Extension Target -> Build Settings and:

  • Set Enable Bitcode to NO;

  • Add -ObjC to Other Linker Flags.

Conform to Network Extension delegate

After the Network Extension target is created, you should observe that new class is added to your project (file PacketTunnelProvider.swift). Go to the PacketTunnelProvider.swift, rename it to ProviderDelegate and make this class implement BaseNetworkExtensionDelegate instead of NEPacketTunnelProvider. It should now look like:

import HydraTunnelProvider

class ProviderDelegate: NSObject, BaseNetworkExtensionDelegate {
	// ...
}

Remove Xcode-generated empty PacketTunnelProvider's implementation. Now you can implement needed methods from BaseNetworkExtensionDelegate. Also, if you want to use Fireshield related methods in network extension you can make your ProviderDelagate class conform to FireshieldNetworkExtensionDelegate protocol which extends base delegate. Pay attention that it makes sense only if you're using Hydra protocol, otherwise Fireshield methods won't be called.

Setup Info.plist

  1. Staying in Network Extension target, set NSExtensionPrincipalClass in NSExtension dictionary of Info.plist to corresponding value depending on protocol:

  • Hydra: AFHydraTunnelProvider

  • WireGuard: AFWireGuardTunnelProvider

  1. Add new key to a plist root: NetworkExtensionDelegate with a value that is your provider delegate class from the previous step. For example, if your class named ProviderDelegate, then the value would be $(PRODUCT_MODULE_NAME).ProviderDelegate.

Read more about Creating a Packet Tunnel Provider Extension from Apple docs.

Setup App ID

Next you need to perform all needed setup on Apple developer portal.

Setup on developer portal

You should already have app ID for Application target, now you need another one for Network Extension target. Go to Apple developer portal->Certificates, Identifiers & Profiles->Identifiers and add new identifier for your Network Extension. Turn on following capabilities for both app IDs (Application and Network Extension):

  • Access WiFi Information

  • App Groups

  • Network Extensions

  • Personal VPN

Create App Group

Since HydraSDK is mostly a Network Extension you also have to create an App Group and provide group ID to the SDK to allow Hydra to interact with Packet Tunnel Provider Extension. See Configuring App Groups for more information about how to create app group.

You need to assign this group to both, the Application and the Network Extension targets and App IDs.

Turn on capabilities in project

For both, Application and Network Extension targets, go to Project -> Target -> Capabilities and enable the following capabilities:

  • Access WiFi Information

  • App Groups

  • Network Extensions

    • Packet Tunnel

  • Personal VPN

For macOS targets, enable Keychain Sharing capability with your Group ID

NOTE: Make sure that respective .entitlement files are added to the project for both targets.

Re/Generate Provision Profiles

Application and Network Extension, both have to have its respective Provision Profiles generated from the Developer Portal. When creating and/or regenerating Provision Profiles, make sure you select Network Extension entitlement.

NOTE: The Provision Profiles' entitlements must corresponds to entitlements configured through Xcode's project Capabilities tab. If there is a missconfiguration between the two, VPN connection will not be established.

Integration Checklist

Checklist that should help you to verify correct integration:

Category
Description

Network Extension

Ensure it is created

Frameworks

  • VPNApplicationSDK.framework is added to the Application target.

  • HydraTunnelProvider.framework is added to the Extension target (for Hydra).

  • WireguardTunnelProvider.framework is added to the Extension target (for WireGuard)

Libraries

libz.tbd and libresolv.tbd are added to the Extension target

Linker Flags

  • In User-Defined, ENABLE_BITCODE is set to No.

  • In Linking-General, Other Linker Flags is set to -ObjC .

App Groups

You have created and enabled App Groups (General > Capabilities) for both targets, active App Group is set to "builder.groupId" (App Groups is enabled for both bundle ids (Application and Extension) in Apple Developer Portal).

Personal VPN

Personal VPN (General > Capabilities) is enabled for both targets (Personal VPN is enabled for both bundle ids (Application and Extension) in Apple Developer Portal).

Entitlements

You have added Network Extension (iOS) entitlement for both Application and Extension provisioning profiles.

SDK Configuration

SDK instance is configured with correct groupData and extensionBundleID.

Troubleshooting

The bundle identifier of the embedded binary does not have the parent application's bundle identifier as a prefix.

To resolve this:

  1. Log in to your Apple Developer account and navigate to the "Certificates, Identifiers & Profiles" section.

  2. Remove the existing Identifiers and Profiles associated with the embedded extensions of your app.

You do not need to remove the main app identifier, only the extension identifiers.

  1. Create new Identifiers and Profiles for the extensions you removed in the previous step. Ensure that the bundle identifiers for the new Identifiers are properly prefixed with the parent app's bundle identifier.

  2. Open your Xcode project and navigate to the "Signing & Capabilities" tab for each of the affected targets (i.e., the extensions).

  3. Under the "Provisioning Profile" section, click on the "Download Profile" button to download the new Profiles you created in step 3.

  4. Select the appropriate downloaded Provisioning Profile for each target.

  5. Clean and rebuild your project.

Xcode won’t pause at this breakpoint because it has not been resolved

When you're developing an app extension, such as a PacketTunnelProvider, and you find that Xcode won't pause at your breakpoints, you might see the following message:

Xcode won't pause at this breakpoint because it has not been resolved.

resolving it requires:
- library for the breakpoint is loaded 
- line at the breakpoint is compiled
- compiler generates .. that is not stripped out

Follow these steps to resolve the issue and get your breakpoints working again:

  1. In Xcode, clean and rebuild your project. Enable the VPN connection within the app.

  2. Click on Debug in the menu bar, then select Attach to Process by PID or Name….

  1. In the dialog that appears, enter the name of your extension target. For example, VPNSDK Demo Hydra Provider, type that into the field. Keep in mind that your app and extension run as separate processes, so be sure to attach to the correct one.

  2. Once you've selected the correct process, click the Attach button.

  1. You should now see breakpoint highlighted, indicating it is active.

It's important to note that if you want to set a breakpoint in start lifecycle methods (such as vpnWillStart), you need to attach the debugger before connecting to the VPN. Otherwise, these methods will have already been called by the time you attach, and the breakpoint will not be hit.

If Xcode seems to be stuck while waiting to attach to your extension process, please ensure that:

  1. Your app is already running

  2. The VPN connection is active (VPN icon is visible in the status bar)

Last updated