Add OpenVPNNetworkSettingsBuilder

Add OpenVPNPacketFlowAdapter
This commit is contained in:
Jonathan Downing
2017-10-12 13:06:25 +01:00
parent 3bb4ff773a
commit f5c85fcb12
6 changed files with 549 additions and 399 deletions

View File

@@ -7,6 +7,18 @@
objects = {
/* Begin PBXBuildFile section */
ABD6EF091F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = ABD6EF071F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h */; };
ABD6EF0A1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = ABD6EF071F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h */; };
ABD6EF0B1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = ABD6EF081F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m */; };
ABD6EF0C1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = ABD6EF081F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m */; };
ABD6EF101F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = ABD6EF0E1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h */; };
ABD6EF111F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = ABD6EF0E1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h */; };
ABD6EF121F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD6EF0F1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm */; };
ABD6EF131F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD6EF0F1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm */; };
ABD6EF171F8F9C38007D3D90 /* OpenVPNAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = ABD6EF151F8F9C37007D3D90 /* OpenVPNAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; };
ABD6EF181F8F9C38007D3D90 /* OpenVPNAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD6EF161F8F9C38007D3D90 /* OpenVPNAdapter.mm */; };
ABD6EF191F8F9C3B007D3D90 /* OpenVPNAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = ABD6EF151F8F9C37007D3D90 /* OpenVPNAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; };
ABD6EF1A1F8F9C3B007D3D90 /* OpenVPNAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD6EF161F8F9C38007D3D90 /* OpenVPNAdapter.mm */; };
C90BAD311E73FF6C00DEFB32 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C90BAD301E73FF6C00DEFB32 /* SystemConfiguration.framework */; };
C912BB251E7C3339002B9414 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C912BB241E7C3339002B9414 /* NetworkExtension.framework */; };
C915F1F41F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -99,8 +111,6 @@
C9BB47601E71663A00F3F98C /* Umbrella-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB475E1E71663A00F3F98C /* Umbrella-Header.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9BB47711E7171A100F3F98C /* OpenVPNError.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB476F1E7171A100F3F98C /* OpenVPNError.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9BB47721E7171A100F3F98C /* OpenVPNAdapterEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB47701E7171A100F3F98C /* OpenVPNAdapterEvent.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9BB477F1E7173C700F3F98C /* OpenVPNAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB477B1E7173C700F3F98C /* OpenVPNAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9BB47821E7173C700F3F98C /* OpenVPNAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9BB477E1E7173C700F3F98C /* OpenVPNAdapter.mm */; };
C9BB47911E71821A00F3F98C /* OpenVPNAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47901E71821A00F3F98C /* OpenVPNAdapterTests.swift */; };
C9BB47931E71821A00F3F98C /* OpenVPNAdapter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9BB475C1E71663A00F3F98C /* OpenVPNAdapter.framework */; };
C9BB47A21E7183DB00F3F98C /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47A11E7183DB00F3F98C /* Bundle.swift */; };
@@ -116,12 +126,10 @@
C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; };
C9CA4DE11F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; };
C9CA4DE21F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; };
C9D2ABDB1EA20F99007EDF9D /* OpenVPNAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9BB477E1E7173C700F3F98C /* OpenVPNAdapter.mm */; };
C9D2ABDE1EA20F99007EDF9D /* ovpncli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9FD92191E9A667600374FC4 /* ovpncli.cpp */; };
C9D2ABE01EA20F99007EDF9D /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C912BB241E7C3339002B9414 /* NetworkExtension.framework */; };
C9D2ABE11EA20F99007EDF9D /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C90BAD301E73FF6C00DEFB32 /* SystemConfiguration.framework */; };
C9D2ABE41EA20F99007EDF9D /* OpenVPNAdapterEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB47701E7171A100F3F98C /* OpenVPNAdapterEvent.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9D2ABE51EA20F99007EDF9D /* OpenVPNAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB477B1E7173C700F3F98C /* OpenVPNAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9D2ABE61EA20F99007EDF9D /* Umbrella-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB475E1E71663A00F3F98C /* Umbrella-Header.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9D2ABE81EA20F99007EDF9D /* OpenVPNError.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BB476F1E7171A100F3F98C /* OpenVPNError.h */; settings = {ATTRIBUTES = (Public, ); }; };
C9D2ABEA1EA20F99007EDF9D /* ovpncli.hpp in Headers */ = {isa = PBXBuildFile; fileRef = C9FD92181E9A667600374FC4 /* ovpncli.hpp */; };
@@ -154,6 +162,12 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
ABD6EF071F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenVPNNetworkSettingsBuilder.h; sourceTree = "<group>"; };
ABD6EF081F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OpenVPNNetworkSettingsBuilder.m; sourceTree = "<group>"; };
ABD6EF0E1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenVPNPacketFlowAdapter.h; sourceTree = "<group>"; };
ABD6EF0F1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNPacketFlowAdapter.mm; sourceTree = "<group>"; };
ABD6EF151F8F9C37007D3D90 /* OpenVPNAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNAdapter.h; sourceTree = "<group>"; };
ABD6EF161F8F9C38007D3D90 /* OpenVPNAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNAdapter.mm; sourceTree = "<group>"; };
C90BAD261E73F47E00DEFB32 /* Info-Framework.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-Framework.plist"; sourceTree = "<group>"; };
C90BAD271E73F47E00DEFB32 /* Info-Tests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-Tests.plist"; sourceTree = "<group>"; };
C90BAD291E73F56800DEFB32 /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = "<group>"; };
@@ -211,8 +225,6 @@
C9BB475E1E71663A00F3F98C /* Umbrella-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Umbrella-Header.h"; sourceTree = "<group>"; };
C9BB476F1E7171A100F3F98C /* OpenVPNError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = OpenVPNError.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
C9BB47701E7171A100F3F98C /* OpenVPNAdapterEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNAdapterEvent.h; sourceTree = "<group>"; };
C9BB477B1E7173C700F3F98C /* OpenVPNAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNAdapter.h; sourceTree = "<group>"; };
C9BB477E1E7173C700F3F98C /* OpenVPNAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = OpenVPNAdapter.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
C9BB478E1E71821A00F3F98C /* OpenVPNAdapterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenVPNAdapterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
C9BB47901E71821A00F3F98C /* OpenVPNAdapterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenVPNAdapterTests.swift; sourceTree = "<group>"; };
C9BB47A11E7183DB00F3F98C /* Bundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
@@ -414,8 +426,12 @@
C9BB47671E7169F000F3F98C /* Adapter */ = {
isa = PBXGroup;
children = (
C9BB477B1E7173C700F3F98C /* OpenVPNAdapter.h */,
C9BB477E1E7173C700F3F98C /* OpenVPNAdapter.mm */,
ABD6EF151F8F9C37007D3D90 /* OpenVPNAdapter.h */,
ABD6EF161F8F9C38007D3D90 /* OpenVPNAdapter.mm */,
ABD6EF071F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h */,
ABD6EF081F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m */,
ABD6EF0E1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h */,
ABD6EF0F1F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm */,
);
name = Adapter;
sourceTree = "<group>";
@@ -536,7 +552,7 @@
C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */,
C9BCE25E1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h in Headers */,
C9BB47721E7171A100F3F98C /* OpenVPNAdapterEvent.h in Headers */,
C9BB477F1E7173C700F3F98C /* OpenVPNAdapter.h in Headers */,
ABD6EF171F8F9C38007D3D90 /* OpenVPNAdapter.h in Headers */,
C915F1FE1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */,
C9657A4C1EB0CD6C00EFF210 /* OpenVPNProperties.h in Headers */,
C9657A571EB0CDFB00EFF210 /* OpenVPNProperties+Internal.h in Headers */,
@@ -546,6 +562,7 @@
C98467AB1EAA5BE100272A9A /* OpenVPNConfiguration+Internal.h in Headers */,
C98467A61EAA5B7700272A9A /* OpenVPNConfiguration.h in Headers */,
C9B7956B1F1D26C900CF35FE /* OpenVPNReachability+Internal.h in Headers */,
ABD6EF101F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h in Headers */,
C9657A2B1EB0B6FA00EFF210 /* OpenVPNTransportStats+Internal.h in Headers */,
C9BB47601E71663A00F3F98C /* Umbrella-Header.h in Headers */,
C9657A5E1EB0D60700EFF210 /* OpenVPNTransportProtocol.h in Headers */,
@@ -556,6 +573,7 @@
C9BB47711E7171A100F3F98C /* OpenVPNError.h in Headers */,
C9B795641F1D182500CF35FE /* OpenVPNReachabilityTracker.h in Headers */,
C9E4401D1F6086A1001D7C41 /* NSError+Message.h in Headers */,
ABD6EF091F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h in Headers */,
C9657A611EB0D64E00EFF210 /* OpenVPNIPv6Preference.h in Headers */,
C9657A671EB0D73200EFF210 /* OpenVPNMinTLSVersion.h in Headers */,
C93779D51EAE32670030A362 /* OpenVPNCredentials.h in Headers */,
@@ -577,7 +595,7 @@
C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */,
C9BCE25F1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h in Headers */,
C9D2ABE41EA20F99007EDF9D /* OpenVPNAdapterEvent.h in Headers */,
C9D2ABE51EA20F99007EDF9D /* OpenVPNAdapter.h in Headers */,
ABD6EF191F8F9C3B007D3D90 /* OpenVPNAdapter.h in Headers */,
C915F1FF1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */,
C9657A4D1EB0CD6C00EFF210 /* OpenVPNProperties.h in Headers */,
C9657A561EB0CDFA00EFF210 /* OpenVPNProperties+Internal.h in Headers */,
@@ -587,6 +605,7 @@
C98467AC1EAA5BE200272A9A /* OpenVPNConfiguration+Internal.h in Headers */,
C98467A71EAA5B7700272A9A /* OpenVPNConfiguration.h in Headers */,
C9B7956C1F1D26C900CF35FE /* OpenVPNReachability+Internal.h in Headers */,
ABD6EF111F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.h in Headers */,
C9657A2F1EB0B79500EFF210 /* OpenVPNTransportStats+Internal.h in Headers */,
C9D2ABE61EA20F99007EDF9D /* Umbrella-Header.h in Headers */,
C9657A5F1EB0D60700EFF210 /* OpenVPNTransportProtocol.h in Headers */,
@@ -597,6 +616,7 @@
C9D2ABE81EA20F99007EDF9D /* OpenVPNError.h in Headers */,
C9B795651F1D182500CF35FE /* OpenVPNReachabilityTracker.h in Headers */,
C9E4401E1F6086A1001D7C41 /* NSError+Message.h in Headers */,
ABD6EF0A1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h in Headers */,
C9657A621EB0D64E00EFF210 /* OpenVPNIPv6Preference.h in Headers */,
C9657A681EB0D73200EFF210 /* OpenVPNMinTLSVersion.h in Headers */,
C93779D61EAE32670030A362 /* OpenVPNCredentials.h in Headers */,
@@ -811,10 +831,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
ABD6EF181F8F9C38007D3D90 /* OpenVPNAdapter.mm in Sources */,
C9657A421EB0CAC200EFF210 /* OpenVPNServerEntry.mm in Sources */,
C9BCE25A1EB3C0D9009D6AC1 /* OpenVPNSessionToken.mm in Sources */,
C9BB47821E7173C700F3F98C /* OpenVPNAdapter.mm in Sources */,
ABD6EF0B1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m in Sources */,
C98467A81EAA5B7700272A9A /* OpenVPNConfiguration.mm in Sources */,
ABD6EF121F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm in Sources */,
C9E4401F1F6086A1001D7C41 /* NSError+Message.m in Sources */,
C9657A311EB0B7A900EFF210 /* OpenVPNTransportStats.mm in Sources */,
C9B795661F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */,
@@ -847,10 +869,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
ABD6EF1A1F8F9C3B007D3D90 /* OpenVPNAdapter.mm in Sources */,
C9657A431EB0CAC200EFF210 /* OpenVPNServerEntry.mm in Sources */,
C9BCE25B1EB3C0D9009D6AC1 /* OpenVPNSessionToken.mm in Sources */,
C9D2ABDB1EA20F99007EDF9D /* OpenVPNAdapter.mm in Sources */,
ABD6EF0C1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m in Sources */,
C98467A91EAA5B7700272A9A /* OpenVPNConfiguration.mm in Sources */,
ABD6EF131F8F93AB007D3D90 /* OpenVPNPacketFlowAdapter.mm in Sources */,
C9E440201F6086A1001D7C41 /* NSError+Message.m in Sources */,
C9657A301EB0B7A600EFF210 /* OpenVPNTransportStats.mm in Sources */,
C9B795671F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */,

View File

@@ -12,8 +12,6 @@
#import <client/ovpncli.hpp>
#import <openvpn/tun/client/tunbase.hpp>
#import <openvpn/ip/ip.hpp>
#import <openvpn/addr/ipv4.hpp>
#import <NetworkExtension/NetworkExtension.h>
#import "OpenVPNAdapterEvent.h"
#import "OpenVPNCredentials+Internal.h"
@@ -21,56 +19,23 @@
#import "OpenVPNConnectionInfo+Internal.h"
#import "OpenVPNError.h"
#import "OpenVPNInterfaceStats+Internal.h"
#import "OpenVPNNetworkSettingsBuilder.h"
#import "OpenVPNPacketFlowAdapter.h"
#import "OpenVPNProperties+Internal.h"
#import "OpenVPNSessionToken+Internal.h"
#import "OpenVPNTransportStats+Internal.h"
class Client;
@interface OpenVPNAdapter () {
CFSocketRef _tunSocket;
CFSocketRef _vpnSocket;
}
@interface OpenVPNAdapter ()
@property (nonatomic) Client *client;
@property (nonatomic) NEPacketTunnelFlow *packetFlow;
@property (nonatomic) NSString *remoteAddress;
@property (nonatomic) NSString *ipv4DefaultGateway;
@property (nonatomic) NSString *ipv6DefaultGateway;
@property (nonatomic) NSNumber *mtu;
@property (nonatomic) NSMutableArray<NSString *> *ipv4LocalAddresses;
@property (nonatomic) NSMutableArray<NSString *> *ipv4SubnetMasks;
@property (nonatomic) NSMutableArray<NEIPv4Route *> *ipv4IncludedRoutes;
@property (nonatomic) NSMutableArray<NEIPv4Route *> *ipv4ExcludedRoutes;
@property (nonatomic) NSMutableArray<NSString *> *ipv6LocalAddresses;
@property (nonatomic) NSMutableArray<NSNumber *> *ipv6NetworkPrefixLengths;
@property (nonatomic) NSMutableArray<NEIPv6Route *> *ipv6IncludedRoutes;
@property (nonatomic) NSMutableArray<NEIPv6Route *> *ipv6ExcludedRoutes;
@property (nonatomic) NSMutableArray<NSString *> *dnsServers;
@property (nonatomic) NSMutableArray<NSString *> *searchDomains;
@property (nonatomic) NSMutableArray<NSString *> *proxyExceptionList;
@property (nonatomic) NSString *sessionName;
@property (nonatomic) BOOL autoProxyConfigurationEnabled;
@property (nonatomic) NSURL *proxyAutoConfigurationURL;
@property (nonatomic) BOOL httpProxyServerEnabled;
@property (nonatomic) NEProxyServer *httpProxyServer;
@property (nonatomic) BOOL httpsProxyServerEnabled;
@property (nonatomic) NEProxyServer *httpsProxyServer;
@property (nonatomic, readonly) NEPacketTunnelNetworkSettings *networkSettings;
@property (nonatomic) OpenVPNNetworkSettingsBuilder *networkSettingsBuilder;
- (CFSocketNativeHandle)configureSockets;
- (void)readTUNPackets;
- (void)teardownTunnel:(BOOL)disconnect;
@property (nonatomic) OpenVPNPacketFlowAdapter *packetFlowAdapter;
- (OpenVPNAdapterError)errorByName:(NSString *)errorName;
- (OpenVPNAdapterEvent)eventByName:(NSString *)errorName;
@@ -88,7 +53,7 @@ public:
bool tun_builder_set_remote_address(const std::string& address, bool ipv6) override {
NSString *remoteAddress = [[NSString alloc] initWithUTF8String:address.c_str()];
client.remoteAddress = remoteAddress;
client.networkSettingsBuilder.remoteAddress = remoteAddress;
return true;
}
@@ -97,14 +62,14 @@ public:
NSString *gatewayAddress = [[NSString alloc] initWithUTF8String:gateway.c_str()];
NSString *defaultGateway = gatewayAddress.length == 0 || [gatewayAddress isEqualToString:@"UNSPEC"] ? nil : gatewayAddress;
if (ipv6) {
client.ipv6DefaultGateway = defaultGateway;
[client.ipv6LocalAddresses addObject:localAddress];
[client.ipv6NetworkPrefixLengths addObject:@(prefix_length)];
client.networkSettingsBuilder.ipv6DefaultGateway = defaultGateway;
[client.networkSettingsBuilder.ipv6LocalAddresses addObject:localAddress];
[client.networkSettingsBuilder.ipv6NetworkPrefixLengths addObject:@(prefix_length)];
} else {
NSString *subnetMask = [[NSString alloc] initWithUTF8String:IPv4::Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()];
client.ipv4DefaultGateway = defaultGateway;
[client.ipv4LocalAddresses addObject:localAddress];
[client.ipv4SubnetMasks addObject:subnetMask];
client.networkSettingsBuilder.ipv4DefaultGateway = defaultGateway;
[client.networkSettingsBuilder.ipv4LocalAddresses addObject:localAddress];
[client.networkSettingsBuilder.ipv4SubnetMasks addObject:subnetMask];
}
return true;
}
@@ -112,13 +77,13 @@ public:
bool tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) override {
if (ipv4) {
NEIPv4Route *includedRoute = [NEIPv4Route defaultRoute];
includedRoute.gatewayAddress = client.ipv4DefaultGateway;
[client.ipv4IncludedRoutes addObject:includedRoute];
includedRoute.gatewayAddress = client.networkSettingsBuilder.ipv4DefaultGateway;
[client.networkSettingsBuilder.ipv4IncludedRoutes addObject:includedRoute];
}
if (ipv6) {
NEIPv6Route *includedRoute = [NEIPv6Route defaultRoute];
includedRoute.gatewayAddress = client.ipv6DefaultGateway;
[client.ipv6IncludedRoutes addObject:includedRoute];
includedRoute.gatewayAddress = client.networkSettingsBuilder.ipv6DefaultGateway;
[client.networkSettingsBuilder.ipv6IncludedRoutes addObject:includedRoute];
}
return true;
}
@@ -127,13 +92,13 @@ public:
NSString *route = [[NSString alloc] initWithUTF8String:address.c_str()];
if (ipv6) {
NEIPv6Route *includedRoute = [[NEIPv6Route alloc] initWithDestinationAddress:route networkPrefixLength:@(prefix_length)];
includedRoute.gatewayAddress = client.ipv6DefaultGateway;
[client.ipv6IncludedRoutes addObject:includedRoute];
includedRoute.gatewayAddress = client.networkSettingsBuilder.ipv6DefaultGateway;
[client.networkSettingsBuilder.ipv6IncludedRoutes addObject:includedRoute];
} else {
NSString *subnetMask = [[NSString alloc] initWithUTF8String:IPv4::Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()];
NEIPv4Route *includedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnetMask];
includedRoute.gatewayAddress = client.ipv4DefaultGateway;
[client.ipv4IncludedRoutes addObject:includedRoute];
includedRoute.gatewayAddress = client.networkSettingsBuilder.ipv4DefaultGateway;
[client.networkSettingsBuilder.ipv4IncludedRoutes addObject:includedRoute];
}
return true;
}
@@ -142,29 +107,29 @@ public:
NSString *route = [[NSString alloc] initWithUTF8String:address.c_str()];
if (ipv6) {
NEIPv6Route *excludedRoute = [[NEIPv6Route alloc] initWithDestinationAddress:route networkPrefixLength:@(prefix_length)];
[client.ipv6ExcludedRoutes addObject:excludedRoute];
[client.networkSettingsBuilder.ipv6ExcludedRoutes addObject:excludedRoute];
} else {
NSString *subnetMask = [[NSString alloc] initWithUTF8String:IPv4::Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()];
NEIPv4Route *excludedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnetMask];
[client.ipv4ExcludedRoutes addObject:excludedRoute];
[client.networkSettingsBuilder.ipv4ExcludedRoutes addObject:excludedRoute];
}
return true;
}
bool tun_builder_add_dns_server(const std::string& address, bool ipv6) override {
NSString *dnsAddress = [[NSString alloc] initWithUTF8String:address.c_str()];
[client.dnsServers addObject:dnsAddress];
[client.networkSettingsBuilder.dnsServers addObject:dnsAddress];
return true;
}
bool tun_builder_add_search_domain(const std::string& domain) override {
NSString *searchDomain = [[NSString alloc] initWithUTF8String:domain.c_str()];
[client.searchDomains addObject:searchDomain];
[client.networkSettingsBuilder.searchDomains addObject:searchDomain];
return true;
}
bool tun_builder_set_mtu(int mtu) override {
client.mtu = @(mtu);
client.networkSettingsBuilder.mtu = @(mtu);
return true;
}
@@ -175,28 +140,28 @@ public:
bool tun_builder_add_proxy_bypass(const std::string& bypass_host) override {
NSString *bypassHost = [[NSString alloc] initWithUTF8String:bypass_host.c_str()];
[client.proxyExceptionList addObject:bypassHost];
[client.networkSettingsBuilder.proxyExceptionList addObject:bypassHost];
return true;
}
bool tun_builder_set_proxy_auto_config_url(const std::string& urlString) override {
NSURL *url = [[NSURL alloc] initWithString:[[NSString alloc] initWithUTF8String:urlString.c_str()]];
client.autoProxyConfigurationEnabled = url != nil;
client.proxyAutoConfigurationURL = url;
client.networkSettingsBuilder.autoProxyConfigurationEnabled = url != nil;
client.networkSettingsBuilder.proxyAutoConfigurationURL = url;
return true;
}
bool tun_builder_set_proxy_http(const std::string& host, int port) override {
NSString *address = [[NSString alloc] initWithUTF8String:host.c_str()];
client.httpProxyServerEnabled = YES;
client.httpProxyServer = [[NEProxyServer alloc] initWithAddress:address port:port];
client.networkSettingsBuilder.httpProxyServerEnabled = YES;
client.networkSettingsBuilder.httpProxyServer = [[NEProxyServer alloc] initWithAddress:address port:port];
return true;
}
bool tun_builder_set_proxy_https(const std::string& host, int port) override {
NSString *address = [[NSString alloc] initWithUTF8String:host.c_str()];
client.httpsProxyServerEnabled = YES;
client.httpsProxyServer = [[NEProxyServer alloc] initWithAddress:address port:port];
client.networkSettingsBuilder.httpsProxyServerEnabled = YES;
client.networkSettingsBuilder.httpsProxyServer = [[NEProxyServer alloc] initWithAddress:address port:port];
return true;
}
@@ -205,29 +170,38 @@ public:
}
bool tun_builder_new() override {
reset_network_parameters();
reset_tun();
return true;
}
int tun_builder_establish() override {
NEPacketTunnelNetworkSettings *networkSettings = client.networkSettingsBuilder.networkSettings;
if (!networkSettings) {
return -1;
}
__block NEPacketTunnelFlow *packetFlow;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[client.delegate openVPNAdapter:client configureTunnelWithNetworkSettings:client.networkSettings completionHandler:^(NEPacketTunnelFlow * _Nullable packetFlow) {
client.packetFlow = packetFlow;
[client.delegate openVPNAdapter:client configureTunnelWithNetworkSettings:networkSettings completionHandler:^(NEPacketTunnelFlow * _Nullable flow) {
packetFlow = flow;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC));
if (client.packetFlow) {
[client readTUNPackets];
return [client configureSockets];
if (packetFlow) {
client.packetFlowAdapter = [[OpenVPNPacketFlowAdapter alloc] initWithPacketFlow:packetFlow];
}
if (client.packetFlowAdapter) {
return client.packetFlowAdapter.socketHandle;
} else {
return -1;
}
}
void tun_builder_teardown(bool disconnect) override {
reset_network_parameters();
[client teardownTunnel:disconnect];
reset_tun();
}
bool tun_builder_persist() override {
@@ -277,29 +251,10 @@ public:
}
}
void reset_network_parameters() {
client.remoteAddress = nil;
client.ipv4DefaultGateway = nil;
client.ipv6DefaultGateway = nil;
client.mtu = nil;
client.ipv4LocalAddresses = nil;
client.ipv4SubnetMasks = nil;
client.ipv4IncludedRoutes = nil;
client.ipv4ExcludedRoutes = nil;
client.ipv6LocalAddresses = nil;
client.ipv6NetworkPrefixLengths = nil;
client.ipv6IncludedRoutes = nil;
client.ipv6ExcludedRoutes = nil;
client.dnsServers = nil;
client.searchDomains = nil;
void reset_tun() {
client.packetFlowAdapter = nil;
client.networkSettingsBuilder = nil;
client.sessionName = nil;
client.proxyExceptionList = nil;
client.autoProxyConfigurationEnabled = NO;
client.proxyAutoConfigurationURL = nil;
client.httpProxyServerEnabled = NO;
client.httpProxyServer = nil;
client.httpsProxyServerEnabled = NO;
client.httpsProxyServer = nil;
}
private:
OpenVPNAdapter *client;
@@ -307,6 +262,8 @@ private:
@implementation OpenVPNAdapter
#pragma mark - Initialization
- (instancetype)init {
if ((self = [super init])) {
self.client = new Client(self);
@@ -314,216 +271,11 @@ private:
return self;
}
static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
if (type == kCFSocketDataCallBack) {
[(__bridge OpenVPNAdapter *)info readVPNPacket:(__bridge NSData *)data];
}
}
- (CFSocketNativeHandle)configureSockets {
[self invalidateSockets];
int sockets[2];
if (socketpair(PF_LOCAL, SOCK_DGRAM, IPPROTO_IP, sockets) == -1) {
NSLog(@"Failed to create a pair of connected sockets: %@", [NSString stringWithUTF8String:strerror(errno)]);
return NO;
}
if (![self configureBufferSizeForSocket: sockets[0]] || ![self configureBufferSizeForSocket: sockets[1]]) {
NSLog(@"Failed to configure buffer size of the sockets");
return NO;
}
CFSocketContext socketCtxt = {0, (__bridge void *)self, NULL, NULL, NULL};
_vpnSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[0], kCFSocketDataCallBack, SocketCallback, &socketCtxt);
_tunSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[1], kCFSocketNoCallBack, NULL, NULL);
if (!_vpnSocket || !_tunSocket) {
[self invalidateSockets];
NSLog(@"Failed to create core foundation sockets from native sockets");
return NO;
}
CFRunLoopSourceRef tunSocketSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _vpnSocket, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), tunSocketSource, kCFRunLoopDefaultMode);
CFRelease(tunSocketSource);
return CFSocketGetNative(_tunSocket);
}
- (void)teardownTunnel:(BOOL)disconnect {
[self invalidateSockets];
}
- (void)invalidateSockets {
if (_vpnSocket) {
CFSocketInvalidate(_vpnSocket);
CFRelease(_vpnSocket);
_vpnSocket = nil;
}
if (_tunSocket) {
CFSocketInvalidate(_tunSocket);
CFRelease(_tunSocket);
_tunSocket = nil;
}
}
- (BOOL)configureBufferSizeForSocket:(int)socket {
int buf_value = 65536;
socklen_t buf_len = sizeof(buf_value);
if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_value, buf_len) == -1) {
NSLog(@"Failed to setup buffer size for input: %@", [NSString stringWithUTF8String:strerror(errno)]);
return NO;
}
if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_value, buf_len) == -1) {
NSLog(@"Failed to setup buffer size for output: %@", [NSString stringWithUTF8String:strerror(errno)]);
return NO;
}
return YES;
}
- (void)readTUNPackets {
[self.packetFlow readPacketsWithCompletionHandler:^(NSArray<NSData *> * _Nonnull packets, NSArray<NSNumber *> * _Nonnull protocols) {
[self writeVPNPackets:packets protocols:protocols];
[self readTUNPackets];
}];
}
- (void)writeVPNPackets:(NSArray<NSData *> *)packets protocols:(NSArray<NSNumber *> *)protocols {
[packets enumerateObjectsUsingBlock:^(NSData *data, NSUInteger idx, BOOL *stop) {
if (!_vpnSocket) {
*stop = YES;
return;
}
// Prepare data for sending
NSData *packet = [self prepareVPNPacket:data protocol:protocols[idx]];
// Send data to the VPN server
CFSocketSendData(_vpnSocket, NULL, (CFDataRef)packet, 0.05);
}];
}
- (NSData *)prepareVPNPacket:(NSData *)packet protocol:(NSNumber *)protocol {
NSMutableData *data = [NSMutableData new];
#if TARGET_OS_IPHONE
// Prepend data with network protocol. It should be done because OpenVPN on iOS uses uint32_t prefixes containing network protocol.
uint32_t prefix = CFSwapInt32HostToBig((uint32_t)[protocol unsignedIntegerValue]);
[data appendBytes:&prefix length:sizeof(prefix)];
#endif
[data appendData:packet];
return [data copy];
}
- (void)readVPNPacket:(NSData *)packet {
#if TARGET_OS_IPHONE
// Get network protocol from prefix
NSUInteger prefixSize = sizeof(uint32_t);
if (packet.length < prefixSize) {
NSLog(@"Incorrect OpenVPN packet size");
return;
}
uint32_t protocol = PF_UNSPEC;
[packet getBytes:&protocol length:prefixSize];
protocol = CFSwapInt32BigToHost(protocol);
NSRange range = NSMakeRange(prefixSize, packet.length - prefixSize);
NSData *data = [packet subdataWithRange:range];
#else
// Get network protocol from header
uint8_t header = 0;
[packet getBytes:&header length:1];
uint32_t version = openvpn::IPHeader::version(header);
uint8_t protocol = [self protocolFamilyForVersion:version];
NSData *data = packet;
#endif
// Send the packet to the TUN interface
if (![self.packetFlow writePackets:@[data] withProtocols:@[@(protocol)]]) {
NSLog(@"Failed to send OpenVPN packet to the TUN interface");
}
}
- (uint8_t)protocolFamilyForVersion:(uint32_t)version {
switch (version) {
case 4: return PF_INET;
case 6: return PF_INET6;
default: return PF_UNSPEC;
}
}
- (NEPacketTunnelNetworkSettings *)networkSettings {
NEPacketTunnelNetworkSettings *networkSettings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:self.remoteAddress];
NEIPv4Settings *ipv4Settings = [[NEIPv4Settings alloc] initWithAddresses:self.ipv4LocalAddresses subnetMasks:self.ipv4SubnetMasks];
ipv4Settings.includedRoutes = self.ipv4IncludedRoutes;
ipv4Settings.excludedRoutes = self.ipv4ExcludedRoutes;
networkSettings.IPv4Settings = ipv4Settings;
NEIPv6Settings *ipv6Settings = [[NEIPv6Settings alloc] initWithAddresses:self.ipv6LocalAddresses networkPrefixLengths:self.ipv6NetworkPrefixLengths];
ipv6Settings.includedRoutes = self.ipv6IncludedRoutes;
ipv6Settings.excludedRoutes = self.ipv6ExcludedRoutes;
networkSettings.IPv6Settings = ipv6Settings;
NEDNSSettings *dnsSettings = [[NEDNSSettings alloc] initWithServers:self.dnsServers];
dnsSettings.searchDomains = self.searchDomains;
networkSettings.DNSSettings = dnsSettings;
NEProxySettings *proxySettings = [[NEProxySettings alloc] init];
proxySettings.autoProxyConfigurationEnabled = self.autoProxyConfigurationEnabled;
proxySettings.proxyAutoConfigurationURL = self.proxyAutoConfigurationURL;
proxySettings.exceptionList = self.proxyExceptionList;
proxySettings.HTTPServer = self.httpProxyServer;
proxySettings.HTTPEnabled = self.httpProxyServerEnabled;
proxySettings.HTTPSServer = self.httpsProxyServer;
proxySettings.HTTPSEnabled = self.httpsProxyServerEnabled;
networkSettings.proxySettings = proxySettings;
networkSettings.MTU = self.mtu;
return networkSettings;
}
+ (NSString *)copyright {
return [[NSString alloc] initWithUTF8String:Client::copyright().c_str()];
}
+ (NSString *)platform {
return [[NSString alloc] initWithUTF8String:Client::platform().c_str()];
}
- (OpenVPNConnectionInfo *)connectionInformation {
ClientAPI::ConnectionInfo information = self.client->connection_info();
return information.defined ? [[OpenVPNConnectionInfo alloc] initWithConnectionInfo:information] : nil;
}
- (OpenVPNInterfaceStats *)interfaceStatistics {
return [[OpenVPNInterfaceStats alloc] initWithInterfaceStats:self.client->tun_stats()];
}
- (OpenVPNSessionToken *)sessionToken {
ClientAPI::SessionToken token;
return self.client->session_token(token) ? [[OpenVPNSessionToken alloc] initWithSessionToken:token] : nil;
}
- (OpenVPNTransportStats *)transportStatistics {
return [[OpenVPNTransportStats alloc] initWithTransportStats:self.client->transport_stats()];
}
#pragma mark - OpenVPNClient Lifecycle
- (OpenVPNProperties *)applyConfiguration:(OpenVPNConfiguration *)configuration error:(NSError * _Nullable __autoreleasing *)error {
ClientAPI::EvalConfig eval = self.client->eval_config(configuration.config);
if (eval.error) {
if (error) {
NSString *errorReason = [self reasonForError:OpenVPNAdapterErrorConfigurationFailure];
@@ -556,19 +308,11 @@ static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type,
dispatch_async(connectQueue, ^{
Client::init_process();
ClientAPI::Status status = self.client->connect();
[self handleStatus:status];
[self handleConnectionStatus:status];
Client::uninit_process();
});
}
- (void)pauseWithReason:(NSString *)reason {
self.client->pause(std::string(reason.UTF8String));
}
- (void)resume {
self.client->resume();
}
- (void)reconnectAfterTimeInterval:(NSTimeInterval)timeInterval {
self.client->reconnect(timeInterval);
}
@@ -577,7 +321,15 @@ static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type,
self.client->stop();
}
- (void)handleStatus:(ClientAPI::Status)status {
- (void)pauseWithReason:(NSString *)reason {
self.client->pause(std::string(reason.UTF8String));
}
- (void)resume {
self.client->resume();
}
- (void)handleConnectionStatus:(ClientAPI::Status)status {
if (!status.error) {
return;
}
@@ -588,6 +340,36 @@ static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type,
[self.delegate openVPNAdapter:self handleError:error];
}
#pragma mark - OpenVPNClient Information
+ (NSString *)copyright {
return [[NSString alloc] initWithUTF8String:Client::copyright().c_str()];
}
+ (NSString *)platform {
return [[NSString alloc] initWithUTF8String:Client::platform().c_str()];
}
- (OpenVPNConnectionInfo *)connectionInformation {
ClientAPI::ConnectionInfo information = self.client->connection_info();
return information.defined ? [[OpenVPNConnectionInfo alloc] initWithConnectionInfo:information] : nil;
}
- (OpenVPNInterfaceStats *)interfaceStatistics {
return [[OpenVPNInterfaceStats alloc] initWithInterfaceStats:self.client->tun_stats()];
}
- (OpenVPNSessionToken *)sessionToken {
ClientAPI::SessionToken token;
return self.client->session_token(token) ? [[OpenVPNSessionToken alloc] initWithSessionToken:token] : nil;
}
- (OpenVPNTransportStats *)transportStatistics {
return [[OpenVPNTransportStats alloc] initWithTransportStats:self.client->transport_stats()];
}
#pragma mark - OpenVPNAdapterEvent Helpers
- (OpenVPNAdapterEvent)eventByName:(NSString *)eventName {
NSDictionary *events = @{@"DISCONNECTED": @(OpenVPNAdapterEventDisconnected),
@"CONNECTED": @(OpenVPNAdapterEventConnected),
@@ -609,6 +391,8 @@ static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type,
return event;
}
#pragma mark - OpenVPNAdapterError Helpers
- (OpenVPNAdapterError)errorByName:(NSString *)errorName {
NSDictionary *errors = @{@"NETWORK_RECV_ERROR": @(OpenVPNAdapterErrorNetworkRecvError),
@"NETWORK_EOF_ERROR": @(OpenVPNAdapterErrorNetworkEOFError),
@@ -679,6 +463,7 @@ static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type,
}
- (NSString *)reasonForError:(OpenVPNAdapterError)error {
// TODO: Add missing error reasons
switch (error) {
case OpenVPNAdapterErrorConfigurationFailure: return @"See OpenVPN error message for more details.";
case OpenVPNAdapterErrorCredentialsFailure: return @"See OpenVPN error message for more details.";
@@ -749,82 +534,16 @@ static inline void SocketCallback(CFSocketRef socket, CFSocketCallBackType type,
}
}
- (NSMutableArray<NSString *> *)ipv4LocalAddresses {
if (!_ipv4LocalAddresses) {
_ipv4LocalAddresses = [[NSMutableArray alloc] init];
#pragma mark - Lazy Initialization
- (OpenVPNNetworkSettingsBuilder *)networkSettingsBuilder {
if (!_networkSettingsBuilder) {
_networkSettingsBuilder = [[OpenVPNNetworkSettingsBuilder alloc] init];
}
return _ipv4LocalAddresses;
return _networkSettingsBuilder;
}
- (NSMutableArray<NSString *> *)ipv4SubnetMasks {
if (!_ipv4SubnetMasks) {
_ipv4SubnetMasks = [[NSMutableArray alloc] init];
}
return _ipv4SubnetMasks;
}
- (NSMutableArray<NEIPv4Route *> *)ipv4IncludedRoutes {
if (!_ipv4IncludedRoutes) {
_ipv4IncludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv4IncludedRoutes;
}
- (NSMutableArray<NEIPv4Route *> *)ipv4ExcludedRoutes {
if (!_ipv4ExcludedRoutes) {
_ipv4ExcludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv4ExcludedRoutes;
}
- (NSMutableArray<NSString *> *)ipv6LocalAddresses {
if (!_ipv6LocalAddresses) {
_ipv6LocalAddresses = [[NSMutableArray alloc] init];
}
return _ipv6LocalAddresses;
}
- (NSMutableArray<NSNumber *> *)ipv6NetworkPrefixLengths {
if (!_ipv6NetworkPrefixLengths) {
_ipv6NetworkPrefixLengths = [[NSMutableArray alloc] init];
}
return _ipv6NetworkPrefixLengths;
}
- (NSMutableArray<NEIPv6Route *> *)ipv6IncludedRoutes {
if (!_ipv6IncludedRoutes) {
_ipv6IncludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv6IncludedRoutes;
}
- (NSMutableArray<NEIPv6Route *> *)ipv6ExcludedRoutes {
if (!_ipv6ExcludedRoutes) {
_ipv6ExcludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv6ExcludedRoutes;
}
- (NSMutableArray<NSString *> *)dnsServers {
if (!_dnsServers) {
_dnsServers = [[NSMutableArray alloc] init];
}
return _dnsServers;
}
- (NSMutableArray<NSString *> *)searchDomains {
if (!_searchDomains) {
_searchDomains = [[NSMutableArray alloc] init];
}
return _searchDomains;
}
- (NSMutableArray<NSString *> *)proxyExceptionList {
if (!_proxyExceptionList) {
_proxyExceptionList = [[NSMutableArray alloc] init];
}
return _proxyExceptionList;
}
#pragma mark - Dealloc
- (void)dealloc {
delete _client;

View File

@@ -0,0 +1,52 @@
//
// OpenVPNNetworkSettingsBuilder.h
// OpenVPN Adapter
//
// Created by Jonathan Downing on 12/10/2017.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class NEIPv4Route;
@class NEIPv6Route;
@class NEPacketTunnelNetworkSettings;
@class NEProxyServer;
@interface OpenVPNNetworkSettingsBuilder : NSObject
@property (nonatomic, copy, nullable) NSString *remoteAddress;
@property (nonatomic, copy, nullable) NSString *ipv4DefaultGateway;
@property (nonatomic, copy, nullable) NSString *ipv6DefaultGateway;
@property (nonatomic, copy, nullable) NSNumber *mtu;
@property (nonatomic, readonly) NSMutableArray<NSString *> *ipv4LocalAddresses;
@property (nonatomic, readonly) NSMutableArray<NSString *> *ipv4SubnetMasks;
@property (nonatomic, readonly) NSMutableArray<NEIPv4Route *> *ipv4IncludedRoutes;
@property (nonatomic, readonly) NSMutableArray<NEIPv4Route *> *ipv4ExcludedRoutes;
@property (nonatomic, readonly) NSMutableArray<NSString *> *ipv6LocalAddresses;
@property (nonatomic, readonly) NSMutableArray<NSNumber *> *ipv6NetworkPrefixLengths;
@property (nonatomic, readonly) NSMutableArray<NEIPv6Route *> *ipv6IncludedRoutes;
@property (nonatomic, readonly) NSMutableArray<NEIPv6Route *> *ipv6ExcludedRoutes;
@property (nonatomic, readonly) NSMutableArray<NSString *> *dnsServers;
@property (nonatomic, readonly) NSMutableArray<NSString *> *searchDomains;
@property (nonatomic, readonly) NSMutableArray<NSString *> *proxyExceptionList;
@property (nonatomic) BOOL autoProxyConfigurationEnabled;
@property (nonatomic, copy, nullable) NSURL *proxyAutoConfigurationURL;
@property (nonatomic) BOOL httpProxyServerEnabled;
@property (nonatomic, copy, nullable) NEProxyServer *httpProxyServer;
@property (nonatomic) BOOL httpsProxyServerEnabled;
@property (nonatomic, copy, nullable) NEProxyServer *httpsProxyServer;
@property (nonatomic, readonly, nullable) NEPacketTunnelNetworkSettings *networkSettings;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,152 @@
//
// OpenVPNNetworkSettingsBuilder.m
// OpenVPN Adapter
//
// Created by Jonathan Downing on 12/10/2017.
//
#import "OpenVPNNetworkSettingsBuilder.h"
#import <NetworkExtension/NetworkExtension.h>
@interface OpenVPNNetworkSettingsBuilder ()
@property (nonatomic) NSMutableArray<NSString *> *ipv4LocalAddresses;
@property (nonatomic) NSMutableArray<NSString *> *ipv4SubnetMasks;
@property (nonatomic) NSMutableArray<NEIPv4Route *> *ipv4IncludedRoutes;
@property (nonatomic) NSMutableArray<NEIPv4Route *> *ipv4ExcludedRoutes;
@property (nonatomic) NSMutableArray<NSString *> *ipv6LocalAddresses;
@property (nonatomic) NSMutableArray<NSNumber *> *ipv6NetworkPrefixLengths;
@property (nonatomic) NSMutableArray<NEIPv6Route *> *ipv6IncludedRoutes;
@property (nonatomic) NSMutableArray<NEIPv6Route *> *ipv6ExcludedRoutes;
@property (nonatomic) NSMutableArray<NSString *> *dnsServers;
@property (nonatomic) NSMutableArray<NSString *> *searchDomains;
@property (nonatomic) NSMutableArray<NSString *> *proxyExceptionList;
@end
@implementation OpenVPNNetworkSettingsBuilder
#pragma mark - NEPacketTunnelNetworkSettings Generation
- (NEPacketTunnelNetworkSettings *)networkSettings {
if (!self.remoteAddress.length) {
return nil;
}
NEPacketTunnelNetworkSettings *networkSettings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:self.remoteAddress];
if (self.ipv4LocalAddresses.count && (self.ipv4LocalAddresses.count == self.ipv4SubnetMasks.count)) {
NEIPv4Settings *ipv4Settings = [[NEIPv4Settings alloc] initWithAddresses:self.ipv4LocalAddresses subnetMasks:self.ipv4SubnetMasks];
ipv4Settings.includedRoutes = self.ipv4IncludedRoutes;
ipv4Settings.excludedRoutes = self.ipv4ExcludedRoutes;
networkSettings.IPv4Settings = ipv4Settings;
}
if (self.ipv6LocalAddresses.count && (self.ipv6LocalAddresses.count == self.ipv6NetworkPrefixLengths.count)) {
NEIPv6Settings *ipv6Settings = [[NEIPv6Settings alloc] initWithAddresses:self.ipv6LocalAddresses networkPrefixLengths:self.ipv6NetworkPrefixLengths];
ipv6Settings.includedRoutes = self.ipv6IncludedRoutes;
ipv6Settings.excludedRoutes = self.ipv6ExcludedRoutes;
networkSettings.IPv6Settings = ipv6Settings;
}
if (self.dnsServers.count) {
NEDNSSettings *dnsSettings = [[NEDNSSettings alloc] initWithServers:self.dnsServers];
dnsSettings.searchDomains = self.searchDomains;
networkSettings.DNSSettings = dnsSettings;
}
if (self.autoProxyConfigurationEnabled || self.httpProxyServerEnabled || self.httpsProxyServerEnabled) {
NEProxySettings *proxySettings = [[NEProxySettings alloc] init];
proxySettings.autoProxyConfigurationEnabled = self.autoProxyConfigurationEnabled;
proxySettings.proxyAutoConfigurationURL = self.proxyAutoConfigurationURL;
proxySettings.exceptionList = self.proxyExceptionList;
proxySettings.HTTPServer = self.httpProxyServer;
proxySettings.HTTPEnabled = self.httpProxyServerEnabled;
proxySettings.HTTPSServer = self.httpsProxyServer;
proxySettings.HTTPSEnabled = self.httpsProxyServerEnabled;
networkSettings.proxySettings = proxySettings;
}
networkSettings.MTU = self.mtu;
return networkSettings;
}
#pragma mark - Lazy Initializers
- (NSMutableArray<NSString *> *)ipv4LocalAddresses {
if (!_ipv4LocalAddresses) {
_ipv4LocalAddresses = [[NSMutableArray alloc] init];
}
return _ipv4LocalAddresses;
}
- (NSMutableArray<NSString *> *)ipv4SubnetMasks {
if (!_ipv4SubnetMasks) {
_ipv4SubnetMasks = [[NSMutableArray alloc] init];
}
return _ipv4SubnetMasks;
}
- (NSMutableArray<NEIPv4Route *> *)ipv4IncludedRoutes {
if (!_ipv4IncludedRoutes) {
_ipv4IncludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv4IncludedRoutes;
}
- (NSMutableArray<NEIPv4Route *> *)ipv4ExcludedRoutes {
if (!_ipv4ExcludedRoutes) {
_ipv4ExcludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv4ExcludedRoutes;
}
- (NSMutableArray<NSString *> *)ipv6LocalAddresses {
if (!_ipv6LocalAddresses) {
_ipv6LocalAddresses = [[NSMutableArray alloc] init];
}
return _ipv6LocalAddresses;
}
- (NSMutableArray<NSNumber *> *)ipv6NetworkPrefixLengths {
if (!_ipv6NetworkPrefixLengths) {
_ipv6NetworkPrefixLengths = [[NSMutableArray alloc] init];
}
return _ipv6NetworkPrefixLengths;
}
- (NSMutableArray<NEIPv6Route *> *)ipv6IncludedRoutes {
if (!_ipv6IncludedRoutes) {
_ipv6IncludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv6IncludedRoutes;
}
- (NSMutableArray<NEIPv6Route *> *)ipv6ExcludedRoutes {
if (!_ipv6ExcludedRoutes) {
_ipv6ExcludedRoutes = [[NSMutableArray alloc] init];
}
return _ipv6ExcludedRoutes;
}
- (NSMutableArray<NSString *> *)dnsServers {
if (!_dnsServers) {
_dnsServers = [[NSMutableArray alloc] init];
}
return _dnsServers;
}
- (NSMutableArray<NSString *> *)searchDomains {
if (!_searchDomains) {
_searchDomains = [[NSMutableArray alloc] init];
}
return _searchDomains;
}
- (NSMutableArray<NSString *> *)proxyExceptionList {
if (!_proxyExceptionList) {
_proxyExceptionList = [[NSMutableArray alloc] init];
}
return _proxyExceptionList;
}
@end

View File

@@ -0,0 +1,24 @@
//
// OpenVPNPacketFlowAdapter.h
// OpenVPN Adapter
//
// Created by Jonathan Downing on 12/10/2017.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class NEPacketTunnelFlow;
@interface OpenVPNPacketFlowAdapter : NSObject
@property (nonatomic, readonly) CFSocketNativeHandle socketHandle;
- (instancetype)init NS_UNAVAILABLE;
- (nullable instancetype)initWithPacketFlow:(NEPacketTunnelFlow *)packetFlow NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,179 @@
//
// OpenVPNPacketFlowAdapter.mm
// OpenVPN Adapter
//
// Created by Jonathan Downing on 12/10/2017.
//
#import "OpenVPNPacketFlowAdapter.h"
#import <NetworkExtension/NetworkExtension.h>
#import <openvpn/ip/ip.hpp>
@interface OpenVPNPacketFlowAdapter () {
CFSocketRef _openVPNClientSocket;
CFSocketRef _packetFlowSocket;
}
@property (nonatomic) NEPacketTunnelFlow *packetFlow;
@end
@implementation OpenVPNPacketFlowAdapter
- (instancetype)initWithPacketFlow:(NEPacketTunnelFlow *)packetFlow {
if ((self = [super init])) {
self.packetFlow = packetFlow;
if (![self configureSockets]) {
return nil;
}
[self readPacketFlowPackets];
}
return self;
}
- (CFSocketNativeHandle)socketHandle {
return CFSocketGetNative(_openVPNClientSocket);
}
static inline void PacketFlowSocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
if (type == kCFSocketDataCallBack) {
[(__bridge OpenVPNPacketFlowAdapter *)info writeDataToPacketFlow:(__bridge NSData *)data];
}
}
- (BOOL)configureSockets {
int sockets[2];
if (socketpair(PF_LOCAL, SOCK_DGRAM, IPPROTO_IP, sockets) == -1) {
NSLog(@"Failed to create a pair of connected sockets: %@", [NSString stringWithUTF8String:strerror(errno)]);
return NO;
}
if (![self configureBufferSizeForSocket:sockets[0]] || ![self configureBufferSizeForSocket:sockets[1]]) {
NSLog(@"Failed to configure buffer size of the sockets");
return NO;
}
CFSocketContext socketCtxt = {0, (__bridge void *)self, NULL, NULL, NULL};
_packetFlowSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[0], kCFSocketDataCallBack, PacketFlowSocketCallback, &socketCtxt);
_openVPNClientSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[1], kCFSocketNoCallBack, NULL, NULL);
if (!_packetFlowSocket || !_openVPNClientSocket) {
NSLog(@"Failed to create core foundation sockets from native sockets");
return NO;
}
CFRunLoopSourceRef packetFlowSocketSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _packetFlowSocket, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), packetFlowSocketSource, kCFRunLoopDefaultMode);
CFRelease(packetFlowSocketSource);
return YES;
}
- (BOOL)configureBufferSizeForSocket:(int)socket {
int buf_value = 65536;
socklen_t buf_len = sizeof(buf_value);
if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_value, buf_len) == -1) {
NSLog(@"Failed to setup buffer size for input: %@", [NSString stringWithUTF8String:strerror(errno)]);
return NO;
}
if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_value, buf_len) == -1) {
NSLog(@"Failed to setup buffer size for output: %@", [NSString stringWithUTF8String:strerror(errno)]);
return NO;
}
return YES;
}
- (void)readPacketFlowPackets {
[self.packetFlow readPacketsWithCompletionHandler:^(NSArray<NSData *> * _Nonnull packets, NSArray<NSNumber *> * _Nonnull protocols) {
[self writeVPNPackets:packets protocols:protocols];
[self readPacketFlowPackets];
}];
}
- (void)writeVPNPackets:(NSArray<NSData *> *)packets protocols:(NSArray<NSNumber *> *)protocols {
[packets enumerateObjectsUsingBlock:^(NSData *data, NSUInteger idx, BOOL *stop) {
if (!_packetFlowSocket) {
*stop = YES;
return;
}
// Prepare data for sending
NSData *packet = [self prepareVPNPacket:data protocol:protocols[idx]];
// Send data to the VPN server
CFSocketSendData(_packetFlowSocket, NULL, (CFDataRef)packet, 0.05);
}];
}
- (NSData *)prepareVPNPacket:(NSData *)packet protocol:(NSNumber *)protocol {
NSMutableData *data = [NSMutableData new];
#if TARGET_OS_IPHONE
// Prepend data with network protocol. It should be done because OpenVPN on iOS uses uint32_t prefixes containing network protocol.
uint32_t prefix = CFSwapInt32HostToBig((uint32_t)[protocol unsignedIntegerValue]);
[data appendBytes:&prefix length:sizeof(prefix)];
#endif
[data appendData:packet];
return [data copy];
}
- (void)writeDataToPacketFlow:(NSData *)packet {
#if TARGET_OS_IPHONE
// Get network protocol from prefix
NSUInteger prefixSize = sizeof(uint32_t);
if (packet.length < prefixSize) {
NSLog(@"Incorrect OpenVPN packet size");
return;
}
uint32_t protocol = PF_UNSPEC;
[packet getBytes:&protocol length:prefixSize];
protocol = CFSwapInt32BigToHost(protocol);
NSRange range = NSMakeRange(prefixSize, packet.length - prefixSize);
NSData *data = [packet subdataWithRange:range];
#else
// Get network protocol from header
uint8_t header = 0;
[packet getBytes:&header length:1];
uint32_t version = openvpn::IPHeader::version(header);
uint8_t protocol = [self protocolFamilyForVersion:version];
NSData *data = packet;
#endif
// Send the packet to the TUN interface
if (![self.packetFlow writePackets:@[data] withProtocols:@[@(protocol)]]) {
NSLog(@"Failed to send OpenVPN packet to the TUN interface");
}
}
- (uint8_t)protocolFamilyForVersion:(uint32_t)version {
switch (version) {
case 4: return PF_INET;
case 6: return PF_INET6;
default: return PF_UNSPEC;
}
}
- (void)dealloc {
if (_packetFlowSocket) {
CFSocketInvalidate(_packetFlowSocket);
CFRelease(_packetFlowSocket);
}
if (_openVPNClientSocket) {
CFSocketInvalidate(_openVPNClientSocket);
CFRelease(_openVPNClientSocket);
}
}
@end