25 Commits
0.5.0 ... 0.6.0

Author SHA1 Message Date
Sergey Abramchuk
fb3604c237 Merge branch 'release/0.6.0' 2020-06-10 10:41:58 +03:00
Sergey Abramchuk
0a535eca5a Update changelog 2020-06-10 10:35:14 +03:00
Sergey Abramchuk
a2ea36a673 Update podspec 2020-06-10 10:29:54 +03:00
Sergey Abramchuk
95c413b5e8 Bump version number 2020-06-10 10:28:42 +03:00
Sergey Abramchuk
c6214f0974 Merge branch 'feature/reconnection-issue' into develop 2020-06-10 10:20:36 +03:00
Sergey Abramchuk
d916ec4b96 Add assertion to check if delegate is nil 2020-06-10 08:58:50 +03:00
Sergey Abramchuk
8fa49f5e57 Update readme 2020-06-10 08:50:08 +03:00
Sergey Abramchuk
27c6233e3f Update tests 2020-06-10 08:45:07 +03:00
Sergey Abramchuk
7f32ff342d Add assertion to check packetFlow property 2020-06-10 08:45:01 +03:00
Sergey Abramchuk
b357c50067 Use method argument instead of property to provide packet flow 2020-06-10 08:44:43 +03:00
Sergey Abramchuk
d16a8ddade Update readme 2020-06-09 23:15:56 +03:00
Sergey Abramchuk
6de79ecaf8 Light refactoring of the packetFlow assignment 2020-06-09 23:06:25 +03:00
Sergey Abramchuk
2ec2827e5e Update readme 2020-06-09 21:27:47 +03:00
Sergey Abramchuk
fcb699d7c3 Update tests 2020-06-09 21:10:53 +03:00
Sergey Abramchuk
8941e49792 Disable empty initializer and error should be nullable 2020-06-09 21:10:43 +03:00
Sergey Abramchuk
4a9ebe3e25 Set sockets as NULL during invalidation 2020-06-09 21:03:18 +03:00
Sergey Abramchuk
bdf829e80a Change argument type of the completion handler and add packetFlow parameter to initializer 2020-06-09 21:02:40 +03:00
Sergey Abramchuk
0326b93bea Invalidate sockets instead of setting flow as nil 2020-06-09 19:30:48 +03:00
Sergey Abramchuk
abe0870828 Extract sockets invalidation to the separate method 2020-06-09 19:29:59 +03:00
Sergey Abramchuk
baba768941 Comment the line configuring tun persistent option 2020-05-20 23:29:07 +03:00
Sergey Abramchuk
dcbc7b034b Merge branch 'hotfix/missing-key' 2020-03-19 12:30:33 +03:00
Sergey Abramchuk
af6e1e48b2 Merge tag 'missing-key' into develop 2020-03-19 12:30:33 +03:00
Sergey Abramchuk
5deb73311f Bump version number 2020-03-19 12:29:07 +03:00
Sergey Abramchuk
1efcef1637 Set current project version 2020-03-19 11:28:42 +03:00
Sergey Abramchuk
47725b0c34 Merge tag '0.5.0' into develop 2020-03-11 13:28:32 +03:00
9 changed files with 116 additions and 66 deletions

View File

@@ -1,5 +1,9 @@
# Changelog # Changelog
## 0.6.0
- **Updated**: Slightly changed API of the framework.
- **Fixed**: Reading packets issue affecting on connection when network interface is changed.
## 0.5.0 ## 0.5.0
- **Added**: Swift Package Manager support; - **Added**: Swift Package Manager support;
- **Updated**: openvpn3 library 3.5.4 version; - **Updated**: openvpn3 library 3.5.4 version;

View File

@@ -3,7 +3,7 @@ Pod::Spec.new do |s|
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
s.name = "OpenVPNAdapter" s.name = "OpenVPNAdapter"
s.version = "0.5.0" s.version = "0.6.0"
s.summary = "Objective-C wrapper for OpenVPN library. Compatible with iOS and macOS." s.summary = "Objective-C wrapper for OpenVPN library. Compatible with iOS and macOS."
s.description = <<-DESC s.description = <<-DESC
OpenVPNAdapter is an Objective-C framework that allows to easily configure and establish VPN connection using OpenVPN protocol. OpenVPNAdapter is an Objective-C framework that allows to easily configure and establish VPN connection using OpenVPN protocol.

View File

@@ -1451,6 +1451,7 @@
baseConfigurationReference = C9EABF7524111E9C00D828D4 /* LZ4.xcconfig */; baseConfigurationReference = C9EABF7524111E9C00D828D4 /* LZ4.xcconfig */;
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1480,6 +1481,7 @@
baseConfigurationReference = C9EABF7524111E9C00D828D4 /* LZ4.xcconfig */; baseConfigurationReference = C9EABF7524111E9C00D828D4 /* LZ4.xcconfig */;
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1510,6 +1512,7 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1521,7 +1524,7 @@
"$(inherited)", "$(inherited)",
"$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx",
); );
MARKETING_VERSION = 0.5.0; MARKETING_VERSION = 0.6.0;
OTHER_SWIFT_FLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = OpenVPNAdapter; PRODUCT_BUNDLE_IDENTIFIER = OpenVPNAdapter;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
@@ -1538,6 +1541,7 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1549,7 +1553,7 @@
"$(inherited)", "$(inherited)",
"$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx",
); );
MARKETING_VERSION = 0.5.0; MARKETING_VERSION = 0.6.0;
OTHER_SWIFT_FLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = OpenVPNAdapter; PRODUCT_BUNDLE_IDENTIFIER = OpenVPNAdapter;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
@@ -1590,6 +1594,7 @@
baseConfigurationReference = C9EABF7324111AEE00D828D4 /* OpenVPNClient.xcconfig */; baseConfigurationReference = C9EABF7324111AEE00D828D4 /* OpenVPNClient.xcconfig */;
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1620,6 +1625,7 @@
baseConfigurationReference = C9EABF7324111AEE00D828D4 /* OpenVPNClient.xcconfig */; baseConfigurationReference = C9EABF7324111AEE00D828D4 /* OpenVPNClient.xcconfig */;
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1650,6 +1656,7 @@
baseConfigurationReference = C9EABF7624111F1600D828D4 /* mbedTLS.xcconfig */; baseConfigurationReference = C9EABF7624111F1600D828D4 /* mbedTLS.xcconfig */;
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@@ -1678,6 +1685,7 @@
baseConfigurationReference = C9EABF7624111F1600D828D4 /* mbedTLS.xcconfig */; baseConfigurationReference = C9EABF7624111F1600D828D4 /* mbedTLS.xcconfig */;
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (

View File

@@ -35,7 +35,7 @@ To install OpenVPNAdapter with Cocoapods, add the following lines to your `Podfi
```ruby ```ruby
target 'Your Target Name' do target 'Your Target Name' do
use_frameworks! use_frameworks!
pod 'OpenVPNAdapter', :git => 'https://github.com/ss-abramchuk/OpenVPNAdapter.git', :tag => '0.5.0' pod 'OpenVPNAdapter', :git => 'https://github.com/ss-abramchuk/OpenVPNAdapter.git', :tag => '0.5.1'
end end
``` ```
@@ -141,6 +141,11 @@ Packet Tunnel Provider extension uses [`NEPacketTunnelProvider`](https://develop
import NetworkExtension import NetworkExtension
import OpenVPNAdapter import OpenVPNAdapter
// Extend NEPacketTunnelFlow to adopt OpenVPNAdapterPacketFlow protocol so that
// `self.packetFlow` could be sent to `completionHandler` callback of OpenVPNAdapterDelegate
// method openVPNAdapter(openVPNAdapter:configureTunnelWithNetworkSettings:completionHandler).
extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {}
class PacketTunnelProvider: NEPacketTunnelProvider { class PacketTunnelProvider: NEPacketTunnelProvider {
lazy var vpnAdapter: OpenVPNAdapter = { lazy var vpnAdapter: OpenVPNAdapter = {
@@ -182,8 +187,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
// Additional parameters as key:value pairs may be provided here // Additional parameters as key:value pairs may be provided here
] ]
// Add this line if you want to keep TUN interface active during pauses or reconnections // Uncomment this line if you want to keep TUN interface active during pauses or reconnections
configuration.tunPersist = true // configuration.tunPersist = true
// Apply OpenVPN configuration // Apply OpenVPN configuration
let properties: OpenVPNProperties let properties: OpenVPNProperties
@@ -226,13 +231,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
// WiFi the adapter still uses cellular data. Changing reachability forces // WiFi the adapter still uses cellular data. Changing reachability forces
// reconnection so the adapter will use actual connection. // reconnection so the adapter will use actual connection.
vpnReachability.startTracking { [weak self] status in vpnReachability.startTracking { [weak self] status in
guard status != .notReachable else { return } guard status == .reachableViaWiFi else { return }
self?.vpnAdapter.reconnect(interval: 5) self?.vpnAdapter.reconnect(interval: 5)
} }
// Establish connection and wait for .connected event // Establish connection and wait for .connected event
startHandler = completionHandler startHandler = completionHandler
vpnAdapter.connect() vpnAdapter.connect(using: packetFlow)
} }
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
@@ -255,15 +260,13 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
// `OpenVPNAdapterPacketFlow` method signatures are similar to `NEPacketTunnelFlow` so // `OpenVPNAdapterPacketFlow` method signatures are similar to `NEPacketTunnelFlow` so
// you can just extend that class to adopt `OpenVPNAdapterPacketFlow` protocol and // you can just extend that class to adopt `OpenVPNAdapterPacketFlow` protocol and
// send `self.packetFlow` to `completionHandler` callback. // send `self.packetFlow` to `completionHandler` callback.
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (OpenVPNAdapterPacketFlow?) -> Void) { func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (Error?) -> Void) {
// In order to direct all DNS queries first to the VPN DNS servers before the primary DNS servers // In order to direct all DNS queries first to the VPN DNS servers before the primary DNS servers
// send empty string to NEDNSSettings.matchDomains // send empty string to NEDNSSettings.matchDomains
networkSettings?.dnsSettings?.matchDomains = [""] networkSettings?.dnsSettings?.matchDomains = [""]
// Specify the network settings for the current tunneling session. // Set the network settings for the current tunneling session.
setTunnelNetworkSettings(settings) { (error) in setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
completionHandler(error == nil ? self.packetFlow : nil)
}
} }
// Process events returned by the OpenVPN library // Process events returned by the OpenVPN library
@@ -322,11 +325,6 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
} }
} }
// Extend NEPacketTunnelFlow to adopt OpenVPNAdapterPacketFlow protocol so that
// `self.packetFlow` could be sent to `completionHandler` callback of OpenVPNAdapterDelegate
// method openVPNAdapter(openVPNAdapter:configureTunnelWithNetworkSettings:completionHandler).
extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {}
``` ```
## Contributing ## Contributing

View File

@@ -39,7 +39,7 @@ typedef NS_ENUM(NSInteger, OpenVPNAdapterEvent);
*/ */
- (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter - (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter
configureTunnelWithNetworkSettings:(nullable NEPacketTunnelNetworkSettings *)networkSettings configureTunnelWithNetworkSettings:(nullable NEPacketTunnelNetworkSettings *)networkSettings
completionHandler:(void (^)(id<OpenVPNAdapterPacketFlow> _Nullable packetFlow))completionHandler completionHandler:(void (^)(NSError * _Nullable error))completionHandler
NS_SWIFT_NAME(openVPNAdapter(_:configureTunnelWithNetworkSettings:completionHandler:)); NS_SWIFT_NAME(openVPNAdapter(_:configureTunnelWithNetworkSettings:completionHandler:));
/** /**
@@ -149,8 +149,10 @@ NS_SWIFT_NAME(apply(configuration:));
/** /**
Starts the tunnel. Starts the tunnel.
@param packetFlow The object implementing OpenVPNAdapterPacketFlow protocol.
*/ */
- (void)connect; - (void)connectUsingPacketFlow:(id<OpenVPNAdapterPacketFlow>)packetFlow NS_SWIFT_NAME(connect(using:));
/** /**
Pauses the tunnel. Pauses the tunnel.

View File

@@ -43,6 +43,7 @@
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
_vpnClient = new OpenVPNClient(self); _vpnClient = new OpenVPNClient(self);
_packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] init];
} }
return self; return self;
} }
@@ -56,7 +57,7 @@
if (error) { if (error) {
NSString *message = [NSString stringWithUTF8String:eval.message.c_str()]; NSString *message = [NSString stringWithUTF8String:eval.message.c_str()];
*error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorConfigurationFailure *error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorConfigurationFailure
description:@"Failed to apply OpenVPN configuration" description:@"Failed to apply OpenVPN configuration."
message:message message:message
fatal:YES]; fatal:YES];
} }
@@ -74,7 +75,7 @@
if (error) { if (error) {
NSString *message = [NSString stringWithUTF8String:status.message.c_str()]; NSString *message = [NSString stringWithUTF8String:status.message.c_str()];
*error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorCredentialsFailure *error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorCredentialsFailure
description:@"Failed to provide OpenVPN credentials" description:@"Failed to provide OpenVPN credentials."
message:message message:message
fatal:YES]; fatal:YES];
} }
@@ -85,9 +86,13 @@
return YES; return YES;
} }
- (void)connect { - (void)connectUsingPacketFlow:(id<OpenVPNAdapterPacketFlow>)packetFlow {
NSAssert(self.delegate != nil, @"delegate property shouldn't be nil, set it before trying to establish connection.");
self.packetFlowBridge.packetFlow = packetFlow;
dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0); dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.openvpn-adapter.connection", attributes); dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.openvpn-adapter.connection.", attributes);
dispatch_async(connectQueue, ^{ dispatch_async(connectQueue, ^{
OpenVPNClient::init_process(); OpenVPNClient::init_process();
@@ -123,7 +128,7 @@
NSString *message = [NSString stringWithUTF8String:status.message.c_str()]; NSString *message = [NSString stringWithUTF8String:status.message.c_str()];
NSError *error = [NSError ovpn_errorObjectForAdapterError:adapterError NSError *error = [NSError ovpn_errorObjectForAdapterError:adapterError
description:@"Failed to establish connection with OpenVPN server" description:@"Failed to establish connection with OpenVPN server."
message:message message:message
fatal:YES]; fatal:YES];
@@ -315,23 +320,35 @@
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__weak typeof(self) weakSelf = self; __block NSError *configurationError;
void (^completionHandler)(id<OpenVPNAdapterPacketFlow> _Nullable) = ^(id<OpenVPNAdapterPacketFlow> flow) { void (^completionHandler)(NSError *error) = ^(NSError *error) {
__strong typeof(self) self = weakSelf; configurationError = error;
if (flow) {
self.packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:flow];
}
dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore);
}; };
[self.delegate openVPNAdapter:self configureTunnelWithNetworkSettings:networkSettings completionHandler:completionHandler]; [self.delegate openVPNAdapter:self configureTunnelWithNetworkSettings:networkSettings completionHandler:completionHandler];
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, TUNNEL_CONFIGURATION_TIMEOUT * NSEC_PER_SEC)); long timeout = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, TUNNEL_CONFIGURATION_TIMEOUT * NSEC_PER_SEC));
if (timeout) { return NO; }
if (configurationError) {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"Failed to configure tunnel using provided settings. Check underlying error for more details.",
NSUnderlyingErrorKey: configurationError,
OpenVPNAdapterErrorFatalKey: @(YES)
};
NSError *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain
code:OpenVPNAdapterErrorTUNSetupFailed
userInfo:userInfo];
[self.delegate openVPNAdapter:self handleError:error];
return NO;
}
NSError *socketError; NSError *socketError;
if (self.packetFlowBridge && [self.packetFlowBridge configureSocketsWithError:&socketError]) { if ([self.packetFlowBridge configureSocketsWithError:&socketError]) {
[self.packetFlowBridge startReading]; [self.packetFlowBridge startReading];
return YES; return YES;
} else { } else {
@@ -403,17 +420,33 @@
} }
- (void)resetTun { - (void)resetTun {
_packetFlowBridge = nil; [_packetFlowBridge invalidateSocketsIfNeeded];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
void (^completionHandler)(id<OpenVPNAdapterPacketFlow> _Nullable) = ^(id<OpenVPNAdapterPacketFlow> flow) { __block NSError *configurationError;
void (^completionHandler)(NSError *error) = ^(NSError *error) {
configurationError = error;
dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore);
}; };
[self.delegate openVPNAdapter:self configureTunnelWithNetworkSettings:nil completionHandler:completionHandler]; [self.delegate openVPNAdapter:self configureTunnelWithNetworkSettings:nil completionHandler:completionHandler];
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, TUNNEL_CONFIGURATION_TIMEOUT * NSEC_PER_SEC)); dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, TUNNEL_CONFIGURATION_TIMEOUT * NSEC_PER_SEC));
if (configurationError) {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"Failed to reset tunnel. Check underlying error for more details.",
NSUnderlyingErrorKey: configurationError,
OpenVPNAdapterErrorFatalKey: @(YES)
};
NSError *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain
code:OpenVPNAdapterErrorTUNSetupFailed
userInfo:userInfo];
[self.delegate openVPNAdapter:self handleError:error];
}
} }
#pragma mark - #pragma mark -

View File

@@ -14,13 +14,14 @@ NS_ASSUME_NONNULL_BEGIN
@interface OpenVPNPacketFlowBridge: NSObject @interface OpenVPNPacketFlowBridge: NSObject
@property (nonatomic, weak) id<OpenVPNAdapterPacketFlow> packetFlow;
@property (nonatomic, readonly) CFSocketRef openVPNSocket; @property (nonatomic, readonly) CFSocketRef openVPNSocket;
@property (nonatomic, readonly) CFSocketRef packetFlowSocket; @property (nonatomic, readonly) CFSocketRef packetFlowSocket;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithPacketFlow:(id<OpenVPNAdapterPacketFlow>)packetFlow NS_DESIGNATED_INITIALIZER;
- (BOOL)configureSocketsWithError:(NSError **)error; - (BOOL)configureSocketsWithError:(NSError **)error;
- (void)invalidateSocketsIfNeeded;
- (void)startReading; - (void)startReading;
@end @end

View File

@@ -15,21 +15,8 @@
#import "OpenVPNPacket.h" #import "OpenVPNPacket.h"
#import "OpenVPNAdapterPacketFlow.h" #import "OpenVPNAdapterPacketFlow.h"
@interface OpenVPNPacketFlowBridge ()
@property (nonatomic) id<OpenVPNAdapterPacketFlow> packetFlow;
@end
@implementation OpenVPNPacketFlowBridge @implementation OpenVPNPacketFlowBridge
- (instancetype)initWithPacketFlow:(id<OpenVPNAdapterPacketFlow>)packetFlow {
if (self = [super init]) {
_packetFlow = packetFlow;
}
return self;
}
#pragma mark - Sockets Configuration #pragma mark - Sockets Configuration
static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *obj) { static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *obj) {
@@ -46,7 +33,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
if (socketpair(PF_LOCAL, SOCK_DGRAM, IPPROTO_IP, sockets) == -1) { if (socketpair(PF_LOCAL, SOCK_DGRAM, IPPROTO_IP, sockets) == -1) {
if (error) { if (error) {
NSDictionary *userInfo = @{ NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"Failed to create a pair of connected sockets", NSLocalizedDescriptionKey: @"Failed to create a pair of connected sockets.",
NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)],
OpenVPNAdapterErrorFatalKey: @(YES) OpenVPNAdapterErrorFatalKey: @(YES)
}; };
@@ -68,7 +55,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
if (!(_packetFlowSocket && _openVPNSocket)) { if (!(_packetFlowSocket && _openVPNSocket)) {
if (error) { if (error) {
NSDictionary *userInfo = @{ NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"Failed to create core foundation sockets from native sockets", NSLocalizedDescriptionKey: @"Failed to create core foundation sockets from native sockets.",
OpenVPNAdapterErrorFatalKey: @(YES) OpenVPNAdapterErrorFatalKey: @(YES)
}; };
@@ -99,7 +86,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
if (setsockopt(socketHandle, SOL_SOCKET, SO_RCVBUF, &buf_value, buf_len) == -1) { if (setsockopt(socketHandle, SOL_SOCKET, SO_RCVBUF, &buf_value, buf_len) == -1) {
if (error) { if (error) {
NSDictionary *userInfo = @{ NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"Failed to setup buffer size for input", NSLocalizedDescriptionKey: @"Failed to setup buffer size for input.",
NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)],
OpenVPNAdapterErrorFatalKey: @(YES) OpenVPNAdapterErrorFatalKey: @(YES)
}; };
@@ -115,7 +102,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
if (setsockopt(socketHandle, SOL_SOCKET, SO_SNDBUF, &buf_value, buf_len) == -1) { if (setsockopt(socketHandle, SOL_SOCKET, SO_SNDBUF, &buf_value, buf_len) == -1) {
if (error) { if (error) {
NSDictionary *userInfo = @{ NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"Failed to setup buffer size for output", NSLocalizedDescriptionKey: @"Failed to setup buffer size for output.",
NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)],
OpenVPNAdapterErrorFatalKey: @(YES) OpenVPNAdapterErrorFatalKey: @(YES)
}; };
@@ -131,7 +118,25 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
return YES; return YES;
} }
- (void)invalidateSocketsIfNeeded {
if (_openVPNSocket) {
CFSocketInvalidate(_openVPNSocket);
CFRelease(_openVPNSocket);
_openVPNSocket = NULL;
}
if (_packetFlowSocket) {
CFSocketInvalidate(_packetFlowSocket);
CFRelease(_packetFlowSocket);
_packetFlowSocket = NULL;
}
}
- (void)startReading { - (void)startReading {
NSAssert(self.packetFlow != nil, @"packetFlow property shouldn't be nil, set it before start reading packets.");
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
[self.packetFlow readPacketsWithCompletionHandler:^(NSArray<NSData *> *packets, NSArray<NSNumber *> *protocols) { [self.packetFlow readPacketsWithCompletionHandler:^(NSArray<NSData *> *packets, NSArray<NSNumber *> *protocols) {
@@ -145,6 +150,8 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
#pragma mark - TUN -> VPN #pragma mark - TUN -> VPN
- (void)writePackets:(NSArray<NSData *> *)packets protocols:(NSArray<NSNumber *> *)protocols toSocket:(CFSocketRef)socket { - (void)writePackets:(NSArray<NSData *> *)packets protocols:(NSArray<NSNumber *> *)protocols toSocket:(CFSocketRef)socket {
if (socket == NULL) { return; }
[packets enumerateObjectsUsingBlock:^(NSData *data, NSUInteger idx, BOOL *stop) { [packets enumerateObjectsUsingBlock:^(NSData *data, NSUInteger idx, BOOL *stop) {
NSNumber *protocolFamily = protocols[idx]; NSNumber *protocolFamily = protocols[idx];
OpenVPNPacket *packet = [[OpenVPNPacket alloc] initWithPacketFlowData:data protocolFamily:protocolFamily]; OpenVPNPacket *packet = [[OpenVPNPacket alloc] initWithPacketFlowData:data protocolFamily:protocolFamily];
@@ -156,6 +163,8 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
#pragma mark - VPN -> TUN #pragma mark - VPN -> TUN
- (void)writePackets:(NSArray<OpenVPNPacket *> *)packets toPacketFlow:(id<OpenVPNAdapterPacketFlow>)packetFlow { - (void)writePackets:(NSArray<OpenVPNPacket *> *)packets toPacketFlow:(id<OpenVPNAdapterPacketFlow>)packetFlow {
NSAssert(packetFlow != nil, @"packetFlow shouldn't be nil, check provided parameter before start writing packets.");
NSMutableArray<NSData *> *flowPackets = [[NSMutableArray alloc] init]; NSMutableArray<NSData *> *flowPackets = [[NSMutableArray alloc] init];
NSMutableArray<NSNumber *> *protocols = [[NSMutableArray alloc] init]; NSMutableArray<NSNumber *> *protocols = [[NSMutableArray alloc] init];
@@ -170,11 +179,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
#pragma mark - #pragma mark -
- (void)dealloc { - (void)dealloc {
CFSocketInvalidate(_openVPNSocket); [self invalidateSocketsIfNeeded];
CFRelease(_openVPNSocket);
CFSocketInvalidate(_packetFlowSocket);
CFRelease(_packetFlowSocket);
} }
@end @end

View File

@@ -100,7 +100,7 @@ class OpenVPNAdapterTests: XCTestCase {
expectations[.connection] = expectation(description: "me.ss-abramchuk.openvpn-adapter.connection") expectations[.connection] = expectation(description: "me.ss-abramchuk.openvpn-adapter.connection")
adapter.delegate = self adapter.delegate = self
adapter.connect() adapter.connect(using: customFlow)
waitForExpectations(timeout: 30.0) { (error) in waitForExpectations(timeout: 30.0) { (error) in
adapter.disconnect() adapter.disconnect()
@@ -110,9 +110,8 @@ class OpenVPNAdapterTests: XCTestCase {
} }
extension OpenVPNAdapterTests: OpenVPNAdapterDelegate { extension OpenVPNAdapterTests: OpenVPNAdapterDelegate {
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (Error?) -> Void) {
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (OpenVPNAdapterPacketFlow?) -> Void) { completionHandler(nil)
completionHandler(customFlow)
} }
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleEvent event: OpenVPNAdapterEvent, message: String?) { func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleEvent event: OpenVPNAdapterEvent, message: String?) {