mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-02-11 00:00:08 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb3604c237 | ||
|
|
0a535eca5a | ||
|
|
a2ea36a673 | ||
|
|
95c413b5e8 | ||
|
|
c6214f0974 | ||
|
|
d916ec4b96 | ||
|
|
8fa49f5e57 | ||
|
|
27c6233e3f | ||
|
|
7f32ff342d | ||
|
|
b357c50067 | ||
|
|
d16a8ddade | ||
|
|
6de79ecaf8 | ||
|
|
2ec2827e5e | ||
|
|
fcb699d7c3 | ||
|
|
8941e49792 | ||
|
|
4a9ebe3e25 | ||
|
|
bdf829e80a | ||
|
|
0326b93bea | ||
|
|
abe0870828 | ||
|
|
baba768941 | ||
|
|
dcbc7b034b | ||
|
|
af6e1e48b2 | ||
|
|
5deb73311f | ||
|
|
1efcef1637 | ||
|
|
47725b0c34 |
@@ -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;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 = (
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 -
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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?) {
|
||||||
|
|||||||
Reference in New Issue
Block a user