From baba768941d1848e2ee1c253eb58f303e3753463 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 20 May 2020 23:29:07 +0300 Subject: [PATCH 01/18] Comment the line configuring tun persistent option --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c2f243e..5578a96 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,8 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // 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 - configuration.tunPersist = true + // Uncomment this line if you want to keep TUN interface active during pauses or reconnections + // configuration.tunPersist = true // Apply OpenVPN configuration let properties: OpenVPNProperties From abe08708280fa62c263e9f24b4df381351cd4386 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 19:29:59 +0300 Subject: [PATCH 02/18] Extract sockets invalidation to the separate method --- .../library/OpenVPNPacketFlowBridge.h | 2 ++ .../library/OpenVPNPacketFlowBridge.mm | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h index 7f77b42..f8dc55d 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h +++ b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h @@ -21,6 +21,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithPacketFlow:(id)packetFlow NS_DESIGNATED_INITIALIZER; - (BOOL)configureSocketsWithError:(NSError **)error; +- (void)invalidateSocketsIfNeeded; + - (void)startReading; @end diff --git a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm index 5b64e26..884514c 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm @@ -131,6 +131,18 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData return YES; } +- (void)invalidateSocketsIfNeeded { + if (_openVPNSocket) { + CFSocketInvalidate(_openVPNSocket); + CFRelease(_openVPNSocket); + } + + if (_packetFlowSocket) { + CFSocketInvalidate(_packetFlowSocket); + CFRelease(_packetFlowSocket); + } +} + - (void)startReading { __weak typeof(self) weakSelf = self; @@ -170,11 +182,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData #pragma mark - - (void)dealloc { - CFSocketInvalidate(_openVPNSocket); - CFRelease(_openVPNSocket); - - CFSocketInvalidate(_packetFlowSocket); - CFRelease(_packetFlowSocket); + [self invalidateSocketsIfNeeded]; } @end From 0326b93bea090ffc40099372907126856c902607 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 19:30:48 +0300 Subject: [PATCH 03/18] Invalidate sockets instead of setting flow as nil --- Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm index 5064fb4..40cc860 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm @@ -319,7 +319,7 @@ void (^completionHandler)(id _Nullable) = ^(id flow) { __strong typeof(self) self = weakSelf; - if (flow) { + if (flow && (self.packetFlowBridge == nil || self.packetFlowBridge != flow)) { self.packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:flow]; } @@ -403,7 +403,7 @@ } - (void)resetTun { - _packetFlowBridge = nil; + [_packetFlowBridge invalidateSocketsIfNeeded]; dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); From bdf829e80a8135a8596a6afb021921b7630162b1 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 21:02:40 +0300 Subject: [PATCH 04/18] Change argument type of the completion handler and add packetFlow parameter to initializer --- .../OpenVPNAdapter/library/OpenVPNAdapter.h | 7 ++- .../OpenVPNAdapter/library/OpenVPNAdapter.mm | 61 ++++++++++++++----- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h index 3105daa..1286875 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h @@ -39,7 +39,7 @@ typedef NS_ENUM(NSInteger, OpenVPNAdapterEvent); */ - (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter configureTunnelWithNetworkSettings:(nullable NEPacketTunnelNetworkSettings *)networkSettings - completionHandler:(void (^)(id _Nullable packetFlow))completionHandler + completionHandler:(void (^)(NSError *error))completionHandler NS_SWIFT_NAME(openVPNAdapter(_:configureTunnelWithNetworkSettings:completionHandler:)); /** @@ -126,6 +126,11 @@ NS_SWIFT_NAME(openVPNAdapter(_:handleEvent:message:)); */ @property (nonatomic, readonly) OpenVPNTransportStats *transportStatistics; +/** + + */ +- (instancetype)initWithPacketFlow:(id)packetFlow; + /** Applies the given configuration object. Call this method prior to connecting, this method has no effect after calling connect. diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm index 40cc860..cf31cd4 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm @@ -40,9 +40,10 @@ @implementation OpenVPNAdapter -- (instancetype)init { +- (instancetype)initWithPacketFlow:(id)packetFlow { if (self = [super init]) { _vpnClient = new OpenVPNClient(self); + _packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:packetFlow]; } return self; } @@ -56,7 +57,7 @@ if (error) { NSString *message = [NSString stringWithUTF8String:eval.message.c_str()]; *error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorConfigurationFailure - description:@"Failed to apply OpenVPN configuration" + description:@"Failed to apply OpenVPN configuration." message:message fatal:YES]; } @@ -74,7 +75,7 @@ if (error) { NSString *message = [NSString stringWithUTF8String:status.message.c_str()]; *error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorCredentialsFailure - description:@"Failed to provide OpenVPN credentials" + description:@"Failed to provide OpenVPN credentials." message:message fatal:YES]; } @@ -87,7 +88,7 @@ - (void)connect { 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, ^{ OpenVPNClient::init_process(); @@ -123,7 +124,7 @@ NSString *message = [NSString stringWithUTF8String:status.message.c_str()]; NSError *error = [NSError ovpn_errorObjectForAdapterError:adapterError - description:@"Failed to establish connection with OpenVPN server" + description:@"Failed to establish connection with OpenVPN server." message:message fatal:YES]; @@ -315,23 +316,35 @@ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - __weak typeof(self) weakSelf = self; - void (^completionHandler)(id _Nullable) = ^(id flow) { - __strong typeof(self) self = weakSelf; - - if (flow && (self.packetFlowBridge == nil || self.packetFlowBridge != flow)) { - self.packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:flow]; - } - + __block NSError *configurationError; + void (^completionHandler)(NSError *error) = ^(NSError *error) { + configurationError = error; dispatch_semaphore_signal(semaphore); }; [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; - if (self.packetFlowBridge && [self.packetFlowBridge configureSocketsWithError:&socketError]) { + if ([self.packetFlowBridge configureSocketsWithError:&socketError]) { [self.packetFlowBridge startReading]; return YES; } else { @@ -407,13 +420,29 @@ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - void (^completionHandler)(id _Nullable) = ^(id flow) { + __block NSError *configurationError; + void (^completionHandler)(NSError *error) = ^(NSError *error) { + configurationError = error; dispatch_semaphore_signal(semaphore); }; [self.delegate openVPNAdapter:self configureTunnelWithNetworkSettings:nil completionHandler:completionHandler]; 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 - From 4a9ebe3e25ccb41f5113466cdeaa562a0c2a778c Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 21:03:18 +0300 Subject: [PATCH 05/18] Set sockets as NULL during invalidation --- .../library/OpenVPNPacketFlowBridge.mm | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm index 884514c..249db65 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm @@ -46,7 +46,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData if (socketpair(PF_LOCAL, SOCK_DGRAM, IPPROTO_IP, sockets) == -1) { if (error) { 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)], OpenVPNAdapterErrorFatalKey: @(YES) }; @@ -68,7 +68,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData if (!(_packetFlowSocket && _openVPNSocket)) { if (error) { NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: @"Failed to create core foundation sockets from native sockets", + NSLocalizedDescriptionKey: @"Failed to create core foundation sockets from native sockets.", OpenVPNAdapterErrorFatalKey: @(YES) }; @@ -99,7 +99,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData if (setsockopt(socketHandle, SOL_SOCKET, SO_RCVBUF, &buf_value, buf_len) == -1) { if (error) { NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: @"Failed to setup buffer size for input", + NSLocalizedDescriptionKey: @"Failed to setup buffer size for input.", NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], OpenVPNAdapterErrorFatalKey: @(YES) }; @@ -115,7 +115,7 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData if (setsockopt(socketHandle, SOL_SOCKET, SO_SNDBUF, &buf_value, buf_len) == -1) { if (error) { NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: @"Failed to setup buffer size for output", + NSLocalizedDescriptionKey: @"Failed to setup buffer size for output.", NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], OpenVPNAdapterErrorFatalKey: @(YES) }; @@ -135,11 +135,15 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData if (_openVPNSocket) { CFSocketInvalidate(_openVPNSocket); CFRelease(_openVPNSocket); + + _openVPNSocket = NULL; } if (_packetFlowSocket) { CFSocketInvalidate(_packetFlowSocket); CFRelease(_packetFlowSocket); + + _packetFlowSocket = NULL; } } @@ -157,6 +161,8 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData #pragma mark - TUN -> VPN - (void)writePackets:(NSArray *)packets protocols:(NSArray *)protocols toSocket:(CFSocketRef)socket { + if (socket == NULL) { return; } + [packets enumerateObjectsUsingBlock:^(NSData *data, NSUInteger idx, BOOL *stop) { NSNumber *protocolFamily = protocols[idx]; OpenVPNPacket *packet = [[OpenVPNPacket alloc] initWithPacketFlowData:data protocolFamily:protocolFamily]; From 8941e497926531606045ec31412d0126c35a1fc1 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 21:10:43 +0300 Subject: [PATCH 06/18] Disable empty initializer and error should be nullable --- Sources/OpenVPNAdapter/library/OpenVPNAdapter.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h index 1286875..9019147 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h @@ -39,7 +39,7 @@ typedef NS_ENUM(NSInteger, OpenVPNAdapterEvent); */ - (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter configureTunnelWithNetworkSettings:(nullable NEPacketTunnelNetworkSettings *)networkSettings - completionHandler:(void (^)(NSError *error))completionHandler + completionHandler:(void (^)(NSError * _Nullable error))completionHandler NS_SWIFT_NAME(openVPNAdapter(_:configureTunnelWithNetworkSettings:completionHandler:)); /** @@ -181,6 +181,8 @@ NS_SWIFT_NAME(apply(configuration:)); */ - (void)disconnect; +- (instancetype) init NS_UNAVAILABLE; + @end NS_ASSUME_NONNULL_END From fcb699d7c3c38f2f39fcfdde2c4eb354b88b8008 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 21:10:53 +0300 Subject: [PATCH 07/18] Update tests --- Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift b/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift index 11b7ec0..e6ddbb6 100644 --- a/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift +++ b/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift @@ -32,7 +32,7 @@ class OpenVPNAdapterTests: XCTestCase { func testApplyConfiguration() { guard let vpnConfiguration = VPNProfile.configuration.data(using: .utf8) else { fatalError() } - let adapter = OpenVPNAdapter() + let adapter = OpenVPNAdapter(packetFlow: customFlow) let configuration = OpenVPNConfiguration() configuration.fileContent = vpnConfiguration @@ -52,7 +52,7 @@ class OpenVPNAdapterTests: XCTestCase { } func testProvideCredentials() { - let adapter = OpenVPNAdapter() + let adapter = OpenVPNAdapter(packetFlow: customFlow) let credentials = OpenVPNCredentials() credentials.username = "username" @@ -71,7 +71,7 @@ class OpenVPNAdapterTests: XCTestCase { func testConnection() { guard let vpnConfiguration = VPNProfile.configuration.data(using: .utf8) else { fatalError() } - let adapter = OpenVPNAdapter() + let adapter = OpenVPNAdapter(packetFlow: customFlow) let configuration = OpenVPNConfiguration() configuration.fileContent = vpnConfiguration @@ -110,9 +110,8 @@ class OpenVPNAdapterTests: XCTestCase { } extension OpenVPNAdapterTests: OpenVPNAdapterDelegate { - - func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (OpenVPNAdapterPacketFlow?) -> Void) { - completionHandler(customFlow) + func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (Error?) -> Void) { + completionHandler(nil) } func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleEvent event: OpenVPNAdapterEvent, message: String?) { From 2ec2827e5e33c7137cff7d51a9ab46e373750cf4 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 21:27:47 +0300 Subject: [PATCH 08/18] Update readme --- README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5578a96..ead18ca 100644 --- a/README.md +++ b/README.md @@ -141,10 +141,15 @@ Packet Tunnel Provider extension uses [`NEPacketTunnelProvider`](https://develop import NetworkExtension 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 { lazy var vpnAdapter: OpenVPNAdapter = { - let adapter = OpenVPNAdapter() + let adapter = OpenVPNAdapter(packetFlow: packetFlow) adapter.delegate = self return adapter @@ -226,7 +231,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // WiFi the adapter still uses cellular data. Changing reachability forces // reconnection so the adapter will use actual connection. vpnReachability.startTracking { [weak self] status in - guard status != .notReachable else { return } + guard status == .reachableViaWiFi else { return } self?.vpnAdapter.reconnect(interval: 5) } @@ -255,15 +260,13 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate { // `OpenVPNAdapterPacketFlow` method signatures are similar to `NEPacketTunnelFlow` so // you can just extend that class to adopt `OpenVPNAdapterPacketFlow` protocol and // 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 // send empty string to NEDNSSettings.matchDomains networkSettings?.dnsSettings?.matchDomains = [""] - // Specify the network settings for the current tunneling session. - setTunnelNetworkSettings(settings) { (error) in - completionHandler(error == nil ? self.packetFlow : nil) - } + // Set the network settings for the current tunneling session. + setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler) } // 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 From 6de79ecaf8d3950b42efe6aa793679f6a4b1fe2c Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 23:06:25 +0300 Subject: [PATCH 09/18] Light refactoring of the packetFlow assignment --- Sources/OpenVPNAdapter/library/OpenVPNAdapter.h | 12 +++++------- Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm | 14 ++++++++++++-- .../library/OpenVPNPacketFlowBridge.h | 5 ++--- .../library/OpenVPNPacketFlowBridge.mm | 13 ------------- Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift | 7 ++++--- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h index 9019147..7847bd8 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h @@ -96,6 +96,11 @@ NS_SWIFT_NAME(openVPNAdapter(_:handleEvent:message:)); */ @property (nonatomic, class, readonly) NSString *platform; +/** + + */ +@property (nonatomic, weak) id packetFlow; + /** The object that acts as the delegate of the adapter. */ @@ -126,11 +131,6 @@ NS_SWIFT_NAME(openVPNAdapter(_:handleEvent:message:)); */ @property (nonatomic, readonly) OpenVPNTransportStats *transportStatistics; -/** - - */ -- (instancetype)initWithPacketFlow:(id)packetFlow; - /** Applies the given configuration object. Call this method prior to connecting, this method has no effect after calling connect. @@ -181,8 +181,6 @@ NS_SWIFT_NAME(apply(configuration:)); */ - (void)disconnect; -- (instancetype) init NS_UNAVAILABLE; - @end NS_ASSUME_NONNULL_END diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm index cf31cd4..53bfd22 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm @@ -40,10 +40,10 @@ @implementation OpenVPNAdapter -- (instancetype)initWithPacketFlow:(id)packetFlow { +- (instancetype)init { if (self = [super init]) { _vpnClient = new OpenVPNClient(self); - _packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:packetFlow]; + _packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] init]; } return self; } @@ -87,6 +87,8 @@ } - (void)connect { + NSAssert(self.packetFlow != nil, @"packetFlow property shouldn't be nil, set it before trying to establish connection."); + 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_async(connectQueue, ^{ @@ -166,6 +168,14 @@ return _networkSettingsBuilder; } +- (id)packetFlow { + return self.packetFlowBridge.packetFlow; +} + +- (void)setPacketFlow:(id)packetFlow { + self.packetFlowBridge.packetFlow = packetFlow; +} + #pragma mark - OpenVPNClientDelegate - (BOOL)setRemoteAddress:(NSString *)address { diff --git a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h index f8dc55d..f99258f 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h +++ b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.h @@ -14,12 +14,11 @@ NS_ASSUME_NONNULL_BEGIN @interface OpenVPNPacketFlowBridge: NSObject +@property (nonatomic, weak) id packetFlow; + @property (nonatomic, readonly) CFSocketRef openVPNSocket; @property (nonatomic, readonly) CFSocketRef packetFlowSocket; -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPacketFlow:(id)packetFlow NS_DESIGNATED_INITIALIZER; - - (BOOL)configureSocketsWithError:(NSError **)error; - (void)invalidateSocketsIfNeeded; diff --git a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm index 249db65..c464901 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm @@ -15,21 +15,8 @@ #import "OpenVPNPacket.h" #import "OpenVPNAdapterPacketFlow.h" -@interface OpenVPNPacketFlowBridge () - -@property (nonatomic) id packetFlow; - -@end - @implementation OpenVPNPacketFlowBridge -- (instancetype)initWithPacketFlow:(id)packetFlow { - if (self = [super init]) { - _packetFlow = packetFlow; - } - return self; -} - #pragma mark - Sockets Configuration static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *obj) { diff --git a/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift b/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift index e6ddbb6..a8940ea 100644 --- a/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift +++ b/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift @@ -32,7 +32,7 @@ class OpenVPNAdapterTests: XCTestCase { func testApplyConfiguration() { guard let vpnConfiguration = VPNProfile.configuration.data(using: .utf8) else { fatalError() } - let adapter = OpenVPNAdapter(packetFlow: customFlow) + let adapter = OpenVPNAdapter() let configuration = OpenVPNConfiguration() configuration.fileContent = vpnConfiguration @@ -52,7 +52,7 @@ class OpenVPNAdapterTests: XCTestCase { } func testProvideCredentials() { - let adapter = OpenVPNAdapter(packetFlow: customFlow) + let adapter = OpenVPNAdapter() let credentials = OpenVPNCredentials() credentials.username = "username" @@ -71,7 +71,7 @@ class OpenVPNAdapterTests: XCTestCase { func testConnection() { guard let vpnConfiguration = VPNProfile.configuration.data(using: .utf8) else { fatalError() } - let adapter = OpenVPNAdapter(packetFlow: customFlow) + let adapter = OpenVPNAdapter() let configuration = OpenVPNConfiguration() configuration.fileContent = vpnConfiguration @@ -99,6 +99,7 @@ class OpenVPNAdapterTests: XCTestCase { expectations[.connection] = expectation(description: "me.ss-abramchuk.openvpn-adapter.connection") + adapter.packetFlow = customFlow adapter.delegate = self adapter.connect() From d16a8ddade0431adc7c4525fcc6da22d1fba1b56 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Tue, 9 Jun 2020 23:15:56 +0300 Subject: [PATCH 10/18] Update readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ead18ca..c5f7c5f 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,9 @@ extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {} class PacketTunnelProvider: NEPacketTunnelProvider { lazy var vpnAdapter: OpenVPNAdapter = { - let adapter = OpenVPNAdapter(packetFlow: packetFlow) + let adapter = OpenVPNAdapter() + + adapter.packetFlow = self.packetFlow adapter.delegate = self return adapter From b357c50067ba28724f7b233b6a3896cff513718e Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 08:44:43 +0300 Subject: [PATCH 11/18] Use method argument instead of property to provide packet flow --- Sources/OpenVPNAdapter/library/OpenVPNAdapter.h | 9 +++------ Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm | 12 ++---------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h index 7847bd8..70b007b 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.h @@ -96,11 +96,6 @@ NS_SWIFT_NAME(openVPNAdapter(_:handleEvent:message:)); */ @property (nonatomic, class, readonly) NSString *platform; -/** - - */ -@property (nonatomic, weak) id packetFlow; - /** The object that acts as the delegate of the adapter. */ @@ -154,8 +149,10 @@ NS_SWIFT_NAME(apply(configuration:)); /** Starts the tunnel. + + @param packetFlow The object implementing OpenVPNAdapterPacketFlow protocol. */ -- (void)connect; +- (void)connectUsingPacketFlow:(id)packetFlow NS_SWIFT_NAME(connect(using:)); /** Pauses the tunnel. diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm index 53bfd22..62780e8 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm @@ -86,8 +86,8 @@ return YES; } -- (void)connect { - NSAssert(self.packetFlow != nil, @"packetFlow property shouldn't be nil, set it before trying to establish connection."); +- (void)connectUsingPacketFlow:(id)packetFlow { + 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_t connectQueue = dispatch_queue_create("me.ss-abramchuk.openvpn-adapter.connection.", attributes); @@ -168,14 +168,6 @@ return _networkSettingsBuilder; } -- (id)packetFlow { - return self.packetFlowBridge.packetFlow; -} - -- (void)setPacketFlow:(id)packetFlow { - self.packetFlowBridge.packetFlow = packetFlow; -} - #pragma mark - OpenVPNClientDelegate - (BOOL)setRemoteAddress:(NSString *)address { From 7f32ff342da2c7161971c0b22f6734b8c0b3121a Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 08:45:01 +0300 Subject: [PATCH 12/18] Add assertion to check packetFlow property --- Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm index c464901..72e73c0 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNPacketFlowBridge.mm @@ -135,6 +135,8 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData } - (void)startReading { + NSAssert(self.packetFlow != nil, @"packetFlow property shouldn't be nil, set it before start reading packets."); + __weak typeof(self) weakSelf = self; [self.packetFlow readPacketsWithCompletionHandler:^(NSArray *packets, NSArray *protocols) { @@ -161,6 +163,8 @@ static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData #pragma mark - VPN -> TUN - (void)writePackets:(NSArray *)packets toPacketFlow:(id)packetFlow { + NSAssert(packetFlow != nil, @"packetFlow shouldn't be nil, check provided parameter before start writing packets."); + NSMutableArray *flowPackets = [[NSMutableArray alloc] init]; NSMutableArray *protocols = [[NSMutableArray alloc] init]; From 27c6233e3f2dbc358afe67f9fea71a39da7bbb6c Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 08:45:07 +0300 Subject: [PATCH 13/18] Update tests --- Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift b/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift index a8940ea..52d5e94 100644 --- a/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift +++ b/Tests/OpenVPNAdapter/OpenVPNAdapterTests.swift @@ -99,9 +99,8 @@ class OpenVPNAdapterTests: XCTestCase { expectations[.connection] = expectation(description: "me.ss-abramchuk.openvpn-adapter.connection") - adapter.packetFlow = customFlow adapter.delegate = self - adapter.connect() + adapter.connect(using: customFlow) waitForExpectations(timeout: 30.0) { (error) in adapter.disconnect() From 8fa49f5e57249f3240fe6bbd46f4abfc351f05d4 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 08:50:08 +0300 Subject: [PATCH 14/18] Update readme --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index c5f7c5f..428e4ea 100644 --- a/README.md +++ b/README.md @@ -150,8 +150,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider { lazy var vpnAdapter: OpenVPNAdapter = { let adapter = OpenVPNAdapter() - - adapter.packetFlow = self.packetFlow adapter.delegate = self return adapter @@ -239,7 +237,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // Establish connection and wait for .connected event startHandler = completionHandler - vpnAdapter.connect() + vpnAdapter.connect(using: packetFlow) } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { From d916ec4b962a1e10416ab1aeb64757b52156f001 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 08:58:50 +0300 Subject: [PATCH 15/18] Add assertion to check if delegate is nil --- Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm index 62780e8..44bc498 100644 --- a/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm +++ b/Sources/OpenVPNAdapter/library/OpenVPNAdapter.mm @@ -87,6 +87,8 @@ } - (void)connectUsingPacketFlow:(id)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); From 95c413b5e83c546a8e90f55dd2d13117be2df8b3 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 10:28:42 +0300 Subject: [PATCH 16/18] Bump version number --- OpenVPNAdapter.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenVPNAdapter.xcodeproj/project.pbxproj b/OpenVPNAdapter.xcodeproj/project.pbxproj index 6134291..31292a3 100644 --- a/OpenVPNAdapter.xcodeproj/project.pbxproj +++ b/OpenVPNAdapter.xcodeproj/project.pbxproj @@ -1524,7 +1524,7 @@ "$(inherited)", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", ); - MARKETING_VERSION = 0.5.1; + MARKETING_VERSION = 0.6.0; OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = OpenVPNAdapter; PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; @@ -1553,7 +1553,7 @@ "$(inherited)", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", ); - MARKETING_VERSION = 0.5.1; + MARKETING_VERSION = 0.6.0; OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = OpenVPNAdapter; PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; From a2ea36a6731e9ed18bd7e5ab698ae9dda0035130 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 10:29:54 +0300 Subject: [PATCH 17/18] Update podspec --- OpenVPNAdapter.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenVPNAdapter.podspec b/OpenVPNAdapter.podspec index 37bb028..3cc20df 100644 --- a/OpenVPNAdapter.podspec +++ b/OpenVPNAdapter.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.name = "OpenVPNAdapter" - s.version = "0.5.1" + s.version = "0.6.0" s.summary = "Objective-C wrapper for OpenVPN library. Compatible with iOS and macOS." s.description = <<-DESC OpenVPNAdapter is an Objective-C framework that allows to easily configure and establish VPN connection using OpenVPN protocol. From 0a535eca5a5ead6c2b9f87bee36061795726faca Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 10 Jun 2020 10:35:14 +0300 Subject: [PATCH 18/18] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a8811d..adac210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # 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 - **Added**: Swift Package Manager support; - **Updated**: openvpn3 library – 3.5.4 version;