My podfile
objective-c
platform :ios, '10.0'
use_frameworks!
target 'VPNClient' do
pod 'OpenVPNAdapter', :git = 'https://github.com/ss-abramchuk/OpenVPNAdapter.git', :tag = '0.7.0'
end
target 'iOSPacketTunnel' do
pod 'OpenVPNAdapter', :git = 'https://github.com/ss-abramchuk/OpenVPNAdapter.git', :tag = '0.7.0'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'
end
end
end
Post
Replies
Boosts
Views
Activity
Swift example
swift
import Foundation
import NetworkExtension
import OpenVPNAdapter
class VPNConnection {
var connectionStatus = "Disconnected"
var myProviderManager: NETunnelProviderManager?
func manageConnectionChanges( manager:NETunnelProviderManager ) - String {
NSLog("Waiting for changes");
var status = "Disconnected"
NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main, using: { notification in
let baseText = "VPN Status is "
switch manager.connection.status {
case .connected:
status = "Connected"
case .connecting:
status = "Connecting"
case .disconnected:
status = "Disconnected"
case .disconnecting:
status = "Disconnecting"
case .invalid:
status = "Invalid"
case .reasserting:
status = "Reasserting"
default:
status = "Connected"
}
self.connectionStatus = status
NSLog(baseText+status)
});
return status
}
func createProtocolConfiguration() - NETunnelProviderProtocol {
guard
let configurationFileURL = Bundle.main.url(forResource: "clientVPN", withExtension: "ovpn"),
let configurationFileContent = try? Data(contentsOf: configurationFileURL)
else {
fatalError()
}
let tunnelProtocol = NETunnelProviderProtocol()
tunnelProtocol.serverAddress = "21.182.222.81 53152" // There should be your individual address here (!)
tunnelProtocol.providerBundleIdentifier = "mysecretVPN.com.SwiftOpenVPNAdapter.iOSPacketTunnel"
tunnelProtocol.providerConfiguration = ["ovpn": configurationFileContent as Data]
tunnelProtocol.disconnectOnSleep = false
return tunnelProtocol
}
func startConnection(completion:@escaping () - Void){
self.myProviderManager?.loadFromPreferences(completionHandler: { (error) in
guard error == nil else {
// Handle an occurred error
return
}
do {
try self.myProviderManager?.connection.startVPNTunnel()
print("Tunnel started")
} catch {
fatalError()
}
})
}
func loadProviderManager(completion:@escaping () - Void) {
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
guard error == nil else {
fatalError()
return
}
self.myProviderManager = managers?.first ?? NETunnelProviderManager()
self.manageConnectionChanges(manager: self.myProviderManager!)
self.myProviderManager?.loadFromPreferences(completionHandler: { (error) in
guard error == nil else {
fatalError()
return
}
let tunnelProtocol = self.createProtocolConfiguration()
self.myProviderManager?.protocolConfiguration = tunnelProtocol
self.myProviderManager?.localizedDescription = "OpenVPN Client"
self.myProviderManager?.isEnabled = true
self.myProviderManager?.isOnDemandEnabled = false
self.myProviderManager?.saveToPreferences(completionHandler: { (error) in
if error != nil {
// Handle an occurred error
fatalError()
}
self.startConnection {
print("VPN loaded")
}
})
})
}
}
}
Below I will give an example of my connection code.
objective-c
#import Foundation/Foundation.h
@import NetworkExtension;
@import OpenVPNAdapter;
NS_ASSUME_NONNULL_BEGIN
@interface VPNManager : NSObject
@property(strong,nonatomic) NETunnelProviderManager *providerManager;
// Properties has data/string from .ovpn file
@property(strong,nonatomic) NSData* configData;
// Ip addres of server from json
@property(strong,nonatomic) NSString* remoteIp;
(instancetype)sharedInstance;
(void) loadProviderManager;
(void) uninstallVPNConfigurationFromManagers;
(void) startConnection:(void(^)(void))completion;
(void) stopConnection:(void(^)(void))completion;
@end
NS_ASSUME_NONNULL_END
objective-c
#import "VPNManager.h"
#import os/log.h
@interface VPNManager ()
@property os_log_t log;
@end
@implementation VPNManager
@synthesize log;
/*
Method initialize 'NETunnelProviderManager *providerManager' ---------------------------------------------------------------------------------------------------------*/
(void) loadProviderManager
{
__weak typeof(self) weak = self;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
weak.log = os_log_create("secretVPN.com.VPNClient.iOSPacketTunnel", "ios_app");
});
[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArrayNETunnelProviderManager** _Nullable managers, NSError* _Nullable error) {
if(error){
NSLog(@"loadAllFromPreferencesWithCompletionHandler error: %@",error); return;
}
if (managers.count 1) {
[weak uninstallVPNConfigurationFromManagers];
}
weak.providerManager = managers.firstObject ? managers.firstObject : [NETunnelProviderManager new];
[weak.providerManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if(error){
NSLog(@"weak.providerManager loadAllFromPreferencesWithCompletionHandler error: %@",error); return;
}
NETunnelProviderProtocol *tunnelProtocol = [weak createProtocolConfiguration];
weak.providerManager.protocolConfiguration = tunnelProtocol;
weak.providerManager.localizedDescription = @"secretVPN";
weak.providerManager.enabled = YES;
weak.providerManager.onDemandEnabled = NO;
[weak.providerManager saveToPreferencesWithCompletionHandler:^(NSError *error) {
NSLog(@"%@", (error) ? @"Saved with error" : @"Save successfully");
if(error) return;
}];
}];
}];
}
/*
Unistall managers ---------------------------------------------------------------------------------------------------------*/
(void) uninstallVPNConfigurationFromManagers
{
[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArrayNETunnelProviderManager** _Nullable managers, NSError * _Nullable error) {
if (error != nil) {
os_log_debug(self.log, "ERROR Uninstall vpn config: %{public}@", error.localizedDescription);
return;
}
for (NETunnelProviderManager *manager in managers) {
[manager removeFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
os_log_debug(self.log, "ERROR Uninstall vpn config: %{public}@", error.localizedDescription);
return;
} else {
os_log_debug(self.log, "Successful uninstall %{public}@", manager.description);
}
}];
}
os_log_debug(self.log, "Uninstalled vpn config");
}];
}
/*
Start connection ---------------------------------------------------------------------------------------------------------*/
(void) startConnection:(void(^)(void))completion
{
__weak typeof(self) weak = self;
[self.providerManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if(error){
NSLog(@"weak.providerManager loadAllFromPreferencesWithCompletionHandler error: %@",error); return;
}
[weak.providerManager.connection startVPNTunnelAndReturnError:&error];
NSLog(@"%@", (error) ? @"Saved with error" : @"Connection established!");
}];
}
/*
Stop connection ---------------------------------------------------------------------------------------------------------*/
(void) stopConnection:(void(^)(void))completion
{
__weak typeof(self) weak = self;
[self.providerManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if(error){
NSLog(@"weak.providerManager loadAllFromPreferencesWithCompletionHandler error: %@",error); return;
}
[weak.providerManager.connection stopVPNTunnel];
NSLog(@"stopVPNTunnel");
}];
}
/*
Create providerProtocols ---------------------------------------------------------------------------------------------------------*/
(NETunnelProviderProtocol*) createProtocolConfiguration
{
NETunnelProviderProtocol *tunel = [[NETunnelProviderProtocol alloc] init];
tunel.serverAddress = self.remoteIp;
tunel.providerBundleIdentifier = @"secretVPN.com.VPNClient.iOSPacketTunnel";
tunel.providerConfiguration = @{ @"ovpn" : self.configData };
tunel.disconnectOnSleep = NO;
return tunel;
}
#pragma mark - Helpers
/*
Convert Connection.Status to NSString ---------------------------------------------------------------------------------------------------------*/
(void)onVpnStateChange:(NSNotification *)Notification {
switch (self.providerManager.connection.status) {
case NEVPNStatusInvalid:
NSLog(@"NEVPNStatusInvalid");
break;
case NEVPNStatusDisconnected:
NSLog(@"NEVPNStatusDisconnected");
break;
case NEVPNStatusConnecting:
NSLog(@"NEVPNStatusConnecting");
break;
case NEVPNStatusConnected:
NSLog(@"NEVPNStatusConnected");
break;
case NEVPNStatusDisconnecting:
NSLog(@"NEVPNStatusDisconnecting");
break;
case NEVPNStatusReasserting:
NSLog(@"******************ReConnecting****************");
break;
default:
break;
}
}
Hello everyone !
I have solved my problem and now I will tell you how.
First of all I wanted to thank @meaton for the help and assistance, thank you!
So let's get started.
The concept of a vpn application was arranged in the following way:
Json comes to me from the server, one of the fields of which contains an .opvn file in string format.
In my case, passwords and username are not required (! THIS IS IMPORTANT), I only use the certificate itself.
The main mistake was my non-fundamental knowledge of the principles of the protocols.
When I received .opvn that value for the 'serverAddress' property I took opposite the 'remote' field.
I took only the first part ! This was the main mistake.
objective-c
// Example of the file I received:
client
remote 32.185.104.19 53513
resolv-retry infinite
nobind
setenv opt block-outside-dns
script-security 2
dhcp-option DNS 1.1.1.1
I extracted only "32.185.104.19", and I need everything at once (along with a space) "32.185.104.19 53513".
Once again, I used the OpenVPNAdapter external library.
Dear @meaton,
I just submitted my application.
I was assigned the code: Follow-up: 762793516
Regards,
@iosdev000
You're right. I'm currently working on submitting my code for review in TSI.
Dear @meaton,
I implemented os_log, but it didn't help me. This is an anomaly, logs are not output.
Show my code here:
objective-c
@interface PacketTunnelProvider ()
@property os_log_t log;
@end
In 'os_log_create' I pass my extension bundleID and Target name.
objective-c (id) init
{
if( self = [super init] ) {
self.log = os_log_create("site.com.MyVPN.PacketTunnel", "PacketTunnel");
os_log_debug(self.log, "[PacketTunnelProvider][init]");
}
return self;
}
objective-c(void)handleAppMessage:(NSData *)messageData completionHandler:(void (^)(NSData * _Nullable))completionHandler{
os_log_debug(self.log, "handleAppMessage");
}
Even i tried use 'OS_LOG_DEFAULT'
objective-c
os_log_debug(OS_LOG_DEFAULT, "handleAppMessage");
@meaton, I followed your recommendation and removed PersonalVPN.
But it didn't help me.
All the methods I call in this sequence:
objective-c(void)initProvider
{
__weak typeof(self) weak = self;
// (1) load
[NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArrayNETunnelProviderManager** _Nullable managers, NSError* _Nullable error) {
if(error){
NSLog(@"loadAllFromPreferencesWithCompletionHandler error: %@",error); return;
}
// (2) create providerProtocol
NETunnelProviderProtocol *tunel = [[NETunnelProviderProtocol alloc] init];
tunel.providerBundleIdentifier = @"mySite.com.MyVPN.PacketTunnel";
tunel.providerConfiguration = @{ @"ovpn" : self.configData };
tunel.serverAddress = @"vpn.mySite.com";
tunel.disconnectOnSleep = NO;
// (3) create providerManager
weak.providerManager = managers.firstObject ? managers.firstObject : [NETunnelProviderManager new];
weak.providerManager.protocolConfiguration = tunel;
weak.providerManager.localizedDescription = @"MYVPN";
[weak.providerManager setEnabled:YES];
// (4) save configuration
[weak.providerManager saveToPreferencesWithCompletionHandler:^(NSError *error) {
NSLog(@"%@", (error) ? @"Saved with error" : @"Save successfully");
if(error) return;
// (5) load again
[weak.providerManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if(error){
NSLog(@"loadFromPreferencesWithCompletionHandler error: %@",error); return;
}
// (6) connect
[weak connection];
}];
}];
}];
}
Selector for UIButton
objective-c (void)connection
{
__weak typeof(self) weak = self;
[self.providerManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if(!error){
[weak.providerManager.connection startVPNTunnelAndReturnError:&error];
if(error) {
NSLog(@"Start error: %@", error.localizedDescription);
}else{
NSLog(@"Connection established!");
}
}else{
NSLog(@"connection error:%@",error);
}
}];
}
My Info.plist and .entitlements configurations (link to images).
objective-c
https://ibb.co/k22ksfj
https://ibb.co/GpYbZCs
https://ibb.co/9sSkr5y
P.S.
Before building application, I press "Debug""Attach to process by PID"(Select 'PacketTunnel').
Then I run application.
But my NSLog in PacketTunnelProviders don't print (!).
I don't know what I must do....
@meaton
Hmm, I suspect that you have mixed up the sequence of actions.
Can you give a pseudo or real code?
Sorry, but step 6 can't be done.
Get the NEVPNConnection from the NETunnelProviderSession inside of the callback from (5) and call startTunnelWithOptions.
NETunnelProviderSession hasn't method, that can return 'NEVPNConnection'.
objective-c
@interface NETunnelProviderSession : NEVPNConnection
(BOOL)startTunnelWithOptions:(nullable NSDictionaryNSString *,id *)options andReturnError:(NSError **)error;
(void)stopTunnel;
(BOOL)sendProviderMessage:(NSData *)messageData returnError:(NSError **)error responseHandler:(nullable void (^)( NSData * __nullable responseData))responseHandler;
@end
Hi, I have the same problem - https://developer.apple.com/forums/thread/674644 and haven't found a solution yet.
Did you manage to solve it?
I think the main problem is in certificates and identifiers.
Try updating your Info. plist by adding new values there, as shown here:
https://developer.apple.com/forums/thread/669690?answerId=653497022#653497022
Please, if you manage to solve this problem, let me know:)
Also, for a more in-depth study of this problem, I'm going to review these videos:
Watch them too if you haven't solved this problem yet.
Creating and Debugging iOS Network Extensions, Jeroen Leenarts (English) - https://www.youtube.com/watch?v=f9A1nGqEgIw
[Andrii Doroshko - Network Extension (Built-in VPN) @ Kharkiv iOS User Group #4 15.06.19 (Russian)]
https://www.youtube.com/watch?v=bPHgicqCfzQ