IOS OpenVPN Library and NEFramework integration

We are trying to use NE Framework to setup a VPN based on OpenVPN.

We have integrated OpenVPN library in our App that semms to work correctly; we can get the tun network configuration from VPN server.

The problem is the next step: how to configure the device tun interface via NEFramework ?

We already got the Apple entitlements to use NEPacketTunnelProvider


Specific questions:


1) We try to use this code for set the VPN configuration


TunProviderManager = nil;

[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray<NETunnelProviderManager *> * _Nullable managers, NSError * _Nullable error) {

if(managers != nil)

{

for(int8_t i = 0; i < [managers count]; i++)

{

if([[[managers objectAtIndex:i] localizedDescription] isEqualToString:@"iPCallVPN"])

{

TunProviderManager = [managers objectAtIndex:i];

}

}

}

else

{

}

if(TunProviderManager == nil)

{

TunProviderManager = [[NETunnelProviderManager alloc] init];

NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];

protocol.providerBundleIdentifier = @"com.infiniteplay.ipCall.vpnex"; /

/

protocol.serverAddress = @"195.78.202.220"; /

TunProviderManager.localizedDescription = @"iPCallVPN";

TunProviderManager.protocolConfiguration = protocol;

[TunProviderManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error)

{

if(error)

{

}

else

{

}

}];

}

/

NSError *startError;

[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];

if(startError) {

NSLog(@"Start error: %@", startError.localizedDescription);

} else {

NSLog(@"Connection established!");

}

*/

NETunnelProviderSession *session = (NETunnelProviderSession*) TunProviderManager.connection;

/

NSError *err;

[session startTunnelWithOptions:nil andReturnError:&err];

if(err)

{

}

}];

How must be the server address format ?

After start session we have a return error DomainError 1

2) How exactly use the NEPacketTunnelProvider extension added in our App ?

The idea is to use this code to setup the tun parameters obtained

- (void)setNetwork

{

NSArray *addresses = @[@"10.80.0.94"];

NSArray *subnetMasks = @[@"255.255.255.0"];

NSArray<NSString *> *dnsServers = @[@"8.8.8.8", @"8.8.4.4"];

NEPacketTunnelNetworkSettings *settings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"195.78.202.220"];

settings.IPv4Settings = [[NEIPv4Settings alloc] initWithAddresses:addresses subnetMasks:subnetMasks];

NEIPv4Route *defaultRoute = [NEIPv4Route defaultRoute];

NEIPv4Route *localRoute = [[NEIPv4Route alloc] initWithDestinationAddress:@"10.80.0.0" subnetMask:@"255.255.255.0"]; /

settings.IPv4Settings.includedRoutes = @[defaultRoute, localRoute];

settings.IPv4Settings.excludedRoutes = @[];

settings.MTU = [NSNumber numberWithInt:1500];

[PckTunProvider setTunnelNetworkSettings:settings completionHandler:^(NSError * _Nullable error)

{

if (error)

{

NSLog(@"setTunnelNetworkSettings error: %@", error);

}

else

{

}

}];

NSError *startError;

[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];

}

But how can we use the class declared in the app extensions ?

If we do

PckTunProvider = [PacketTunnelProvider alloc];

we obtain linker error

Thanks for any suggestion

1) We try to use this code for set the VPN configuration

How must be the server address format ?

That address is interpreted by your code (the NEPacketTunnelProvider subclass in your extension). As such, it’s up to you how to format it. Most folks use a DNS name or IP address, but I don’t think there’s anything in the system that requires it to be formatted that way when you’re creating a custom VPN transport.

I recently wrote up a discussion of how settings flow through the system when you’re creating a custom VPN transport as part of a DTS incident (s. 644618748). I’ve pasted it in below because I think you’ll find it useful.

2) How exactly use the NEPacketTunnelProvider extension added in our App ?

But how can we use the class declared in the app extensions ?

When you start the VPN connection (by calling methods on the NETunnelProviderSession instance you get via the

connection
property of the NETunnelProviderManager), the system starts your extension process, instantiates your NEPacketTunnelProvider subclass inside that process, and calls
-startTunnelWithOptions:completionHandler:
. That extension is responsible for running the tunnel. Critically:
  • It can transfer packets to and from the kernel via the NEPacketTunnelFlow instance accessed via the by

    packetFlow
    property.
  • It can use NEProvider methods (

    -createTCPConnectionToEndpoint:enableTLS:TLSParameters:delegate:
    and
    -createUDPSessionToEndpoint:fromEndpoint:
    ) or BSD Sockets to open a tunnel connection to the VPN server and transfer packets to and from that tunnel.

Presumably the OpenVPN library can help with this last part but I’m not an expert on that library and can’t advise you on that front.

Share and Enjoy

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

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

My impression is that you’re asking about how configuration parameters flow through the Network Extension system. For example, how does your tunnel provider know the DNS name of the VPN server to contact? There are three parts to this:

configuration profiles — The system administrator can install a configuration profile that configures the VPN. You can learn more about this in the [Configuration Profile Reference][profile]. Specifically, search the doc for

VPNSubType
.

[profile] https://developer.apple.com/library/ios/featuredarticles/iPhoneConfigurationProfileRef/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010206-CH1-SW44

  • application — The app that hosts your packet tunnel provider extension can create new VPN configurations by allocating an instance of NETunnelProviderManager and saving it via

    -saveToPreferencesWithCompletionHandler:
    (a method that NETunnelProviderManager inherits from NEVPNManager).

    The app can also call

    +[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:]
    to get a list of all the available VPN configurations, including those it created and those installed via a configuration profile.

    Finally, the app can access the actual configuration parameters via the

    protocolConfiguration
    property of NEVPNManager. For a tunnel provider this will be of type NETunnelProviderProtocol, which gives access to standard configuration parameters (for example, the
    serverAddress
    property from the NEVPNProtocol subclass) and custom configuration parameters (via the
    providerConfiguration
    property).
  • from the server — When the tunnel provider starts, it can access its specific configuration via the

    protocolConfiguration
    property of its NETunnelProvider subclass. The
    serverAddress
    property tells it what VPN server to connect to, at which point it opens a connection to the server and, as part of the VPN handshake, the server can send it more configuration parameters. It merges these, if any, with the parameters it got from
    protocolConfiguration
    and then uses those final parameters to set up the tunnel.

IMPORTANT Remember that the on-the-wire protocol is your concern. I’m not sure if [your on-the-wire protocol] provides this sort of server-to-client configuration, although I suspect it does (it’s a pretty common feature of VPN protocols). Regardless, the mechanics of how you get such parameters over the wire, and how you merge them into your own configuration, is your business.

Thanks for the reply.

but it has not yet entirely clear.

I'll try to better sum up our situation.


Thanks to OpenVPN library that we have integrated in our app, we can obtain all tun network parameters (ip, route ..) from OpenVPN server.

The initial handshake from App and Server to validate SSL certificate and key it's succesfully completed by OpenVPN library that call some callback in our App (for example tun_builder_add_address(), tun_builder_add_route() etc)

Our problem is: how we can configure IOS device VPN tunnel with that tun parameters obtained ?


As starting point (but I'm not sure that this is the correct starting point), we first try to setup a configuration using NETunnelProviderManager, but when we call NETunnelProviderSession with connection method we obtain Domain Error 1 and the startTunnelWithOptions:completionHandler of the extension is never called !

This is already a problem for us !

I re-attach our code for this first step


TunProviderManager = nil;

[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray<NETunnelProviderManager *> * _Nullable managers, NSError * _Nullable error) {

if(managers != nil)

{

for(int8_t i = 0; i < [managers count]; i++)

{

if([[[managers objectAtIndex:i] localizedDescription] isEqualToString:@"iPCallVPN"])

{

TunProviderManager = [managers objectAtIndex:i];

}

}

}

else

{

}

if(TunProviderManager == nil)

{

TunProviderManager = [[NETunnelProviderManager alloc] init];

NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];

protocol.providerBundleIdentifier = @"com.infiniteplay.ipCall.vpnex"; /

/

protocol.serverAddress = @"195.78.202.220"; /

TunProviderManager.localizedDescription = @"iPCallVPN";

TunProviderManager.protocolConfiguration = protocol;

[TunProviderManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error)

{

if(error)

{

}

else

{

}

}];

}

NETunnelProviderSession *session = (NETunnelProviderSession*) TunProviderManager.connection;

NSError *err;

[session startTunnelWithOptions:nil andReturnError:&err];

if(err)

{

// At this point we obtain Domain Error 1

}

}];


Thanks

Our problem is: how we can configure IOS device VPN tunnel with that tun parameters obtained ?

Packet tunnel providers don’t get direct access to the BSD

tun
device. Rather, they read and write that via the
packetFlow
property of NEPacketTunnelProvider, and they configure routing information and so on by calling
-[NETunnelProvider setTunnelNetworkSettings:completionHandler:]
.

For more details, take a look at the SimpleTunnel sample code.

Also, presumably your OpenVPN library you’re using comes from OpenVPN. If so, you might be better off talking to them about how best to integrate it with iOS’s Network Extension provider architecture. You can’t be the first person to do this (-:

Share and Enjoy

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

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

Hi,

I need to integrate openVPN in my own VPN client application.

I've searched for openVPN library, but i couldn't get any information.

Could you please let me know the openVPN library that you have used.

IOS OpenVPN Library and NEFramework integration
 
 
Q