Add support of IPv6 addresses

This commit is contained in:
Sergey Abramchuk
2017-03-20 21:23:00 +03:00
parent 6dc4f7c0b7
commit 40eeafc99d
5 changed files with 155 additions and 91 deletions
+7 -6
View File
@@ -17,17 +17,18 @@ using namespace openvpn;
- (BOOL)configureSockets; - (BOOL)configureSockets;
- (BOOL)setRemoteAddress:(NSString *)address; - (BOOL)setRemoteAddress:(NSString *)address isIPv6:(BOOL)isIPv6;
- (BOOL)addLocalAddress:(NSString *)address subnet:(NSString *)subnet gateway:(NSString *)gateway; - (BOOL)addLocalAddress:(NSString *)address prefixLength:(NSNumber *)prefixLength gateway:(NSString *)gateway isIPv6:(BOOL)isIPv6;
- (BOOL)addRoute:(NSString *)route subnet:(NSString *)subnet; - (BOOL)defaultGatewayRerouteIPv4:(BOOL)rerouteIPv4 rerouteIPv6:(BOOL)rerouteIPv6;
- (BOOL)excludeRoute:(NSString *)route subnet:(NSString *)subnet; - (BOOL)addRoute:(NSString *)route prefixLength:(NSNumber *)prefixLength isIPv6:(BOOL)isIPv6;
- (BOOL)excludeRoute:(NSString *)route prefixLength:(NSNumber *)prefixLength isIPv6:(BOOL)isIPv6;
- (BOOL)addDNSAddress:(NSString *)address; - (BOOL)addDNSAddress:(NSString *)address isIPv6:(BOOL)isIPv6;
- (BOOL)addSearchDomain:(NSString *)domain; - (BOOL)addSearchDomain:(NSString *)domain;
- (BOOL)setMTU:(NSInteger)mtu; - (BOOL)setMTU:(NSNumber *)mtu;
- (NSInteger)establishTunnel; - (NSInteger)establishTunnel;
+131 -47
View File
@@ -38,15 +38,23 @@ NSString * const OpenVPNAdapterErrorEventKey = @"me.ss-abramchuk.openvpn-adapter
@property OpenVPNClient *vpnClient; @property OpenVPNClient *vpnClient;
@property (strong, nonatomic) TUNConfiguration *tunConfiguration;
@property CFSocketRef vpnSocket; @property CFSocketRef vpnSocket;
@property CFSocketRef tunSocket; @property CFSocketRef tunSocket;
@property (strong, nonatomic) NSString *remoteAddress;
@property (strong, nonatomic) TUNConfiguration *tunConfigurationIPv6;
@property (strong, nonatomic) TUNConfiguration *tunConfigurationIPv4;
@property (strong, nonatomic) NSMutableArray *searchDomains;
@property (strong, nonatomic) NSNumber *mtu;
@property (weak, nonatomic) id<OpenVPNAdapterPacketFlow> packetFlow; @property (weak, nonatomic) id<OpenVPNAdapterPacketFlow> packetFlow;
- (void)readTUNPackets; - (void)readTUNPackets;
- (void)readVPNData:(NSData *)data; - (void)readVPNData:(NSData *)data;
- (NSString *)getSubnetFromPrefixLength:(NSNumber *)prefixLength;
@end @end
@@ -94,108 +102,159 @@ static void socketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
#pragma mark TUN Configuration #pragma mark TUN Configuration
- (BOOL)setRemoteAddress:(NSString *)address { - (BOOL)setRemoteAddress:(NSString *)address isIPv6:(BOOL)isIPv6 {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized");
if (address == nil) { if (address == nil) {
return NO; return NO;
} }
self.tunConfiguration.remoteAddress = address; self.remoteAddress = address;
return YES; return YES;
} }
- (BOOL)addLocalAddress:(NSString *)address subnet:(NSString *)subnet gateway:(NSString *)gateway { - (BOOL)addLocalAddress:(NSString *)address prefixLength:(NSNumber *)prefixLength gateway:(NSString *)gateway isIPv6:(BOOL)isIPv6 {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized"); if (address == nil || prefixLength == nil) {
if (address == nil || subnet == nil) {
return NO; return NO;
} }
[self.tunConfiguration.localAddresses addObject:address]; if (isIPv6) {
[self.tunConfiguration.subnets addObject:subnet]; [self.tunConfigurationIPv6.localAddresses addObject:address];
[self.tunConfigurationIPv6.prefixLengths addObject:prefixLength];
} else {
[self.tunConfigurationIPv4.localAddresses addObject:address];
[self.tunConfigurationIPv4.prefixLengths addObject:prefixLength];
}
return YES; return YES;
} }
- (BOOL)addRoute:(NSString *)route subnet:(NSString *)subnet { - (BOOL)defaultGatewayRerouteIPv4:(BOOL)rerouteIPv4 rerouteIPv6:(BOOL)rerouteIPv6 {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized"); if (rerouteIPv6) {
NEIPv6Route *includedRoute = [NEIPv6Route defaultRoute];
[self.tunConfigurationIPv6.includedRoutes addObject:includedRoute];
}
if (route == nil || subnet == nil) { if (rerouteIPv4) {
NEIPv4Route *includedRoute = [NEIPv4Route defaultRoute];
[self.tunConfigurationIPv4.includedRoutes addObject:includedRoute];
}
return YES;
}
- (BOOL)addRoute:(NSString *)route prefixLength:(NSNumber *)prefixLength isIPv6:(BOOL)isIPv6 {
if (route == nil || prefixLength == nil) {
return NO; return NO;
} }
if (isIPv6) {
NEIPv6Route *includedRoute = [[NEIPv6Route alloc] initWithDestinationAddress:route networkPrefixLength:prefixLength];
[self.tunConfigurationIPv6.includedRoutes addObject:includedRoute];
} else {
NSString *subnet = [self getSubnetFromPrefixLength:prefixLength];
NEIPv4Route *includedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnet]; NEIPv4Route *includedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnet];
[self.tunConfiguration.includedRoutes addObject:includedRoute]; [self.tunConfigurationIPv4.includedRoutes addObject:includedRoute];
}
return YES; return YES;
} }
- (BOOL)excludeRoute:(NSString *)route subnet:(NSString *)subnet { - (BOOL)excludeRoute:(NSString *)route prefixLength:(NSNumber *)prefixLength isIPv6:(BOOL)isIPv6 {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized"); if (route == nil || prefixLength == nil) {
if (route == nil || subnet == nil) {
return NO; return NO;
} }
if (isIPv6) {
NEIPv6Route *excludedRoute = [[NEIPv6Route alloc] initWithDestinationAddress:route networkPrefixLength:prefixLength];
[self.tunConfigurationIPv6.excludedRoutes addObject:excludedRoute];
} else {
NSString *subnet = [self getSubnetFromPrefixLength:prefixLength];
NEIPv4Route *excludedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnet]; NEIPv4Route *excludedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnet];
[self.tunConfiguration.excludedRoutes addObject:excludedRoute]; [self.tunConfigurationIPv4.excludedRoutes addObject:excludedRoute];
}
return YES; return YES;
} }
- (BOOL)addDNSAddress:(NSString *)address { - (BOOL)addDNSAddress:(NSString *)address isIPv6:(BOOL)isIPv6 {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized");
if (address == nil) { if (address == nil) {
return NO; return NO;
} }
[self.tunConfiguration.dnsAddresses addObject:address]; if (isIPv6) {
[self.tunConfigurationIPv6.dnsAddresses addObject:address];
} else {
[self.tunConfigurationIPv4.dnsAddresses addObject:address];
}
return YES; return YES;
} }
- (BOOL)addSearchDomain:(NSString *)domain { - (BOOL)addSearchDomain:(NSString *)domain {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized");
if (domain == nil) { if (domain == nil) {
return NO; return NO;
} }
[self.tunConfiguration.searchDomains addObject:domain]; [self.searchDomains addObject:domain];
return YES; return YES;
} }
- (BOOL)setMTU:(NSInteger)mtu { - (BOOL)setMTU:(NSNumber *)mtu {
NSAssert(self.tunConfiguration != nil, @"TUN configuration should be initialized"); self.mtu = mtu;
self.tunConfiguration.mtu = @(mtu);
return YES; return YES;
} }
- (NSInteger)establishTunnel { - (NSInteger)establishTunnel {
NSAssert(self.delegate != nil, @"delegate property should not be nil"); NSAssert(self.delegate != nil, @"delegate property should not be nil");
NEIPv4Settings *ipSettings = [[NEIPv4Settings alloc] initWithAddresses:@[self.tunConfiguration.localAddresses] subnetMasks:@[self.tunConfiguration.subnets]]; NEPacketTunnelNetworkSettings *networkSettings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:self.remoteAddress];
ipSettings.includedRoutes = self.tunConfiguration.includedRoutes;
ipSettings.excludedRoutes = self.tunConfiguration.excludedRoutes; // Configure IPv6 addresses and routes
if (self.tunConfigurationIPv6.initialized) {
NEIPv6Settings *settingsIPv6 = [[NEIPv6Settings alloc] initWithAddresses:self.tunConfigurationIPv6.localAddresses networkPrefixLengths:self.tunConfigurationIPv6.prefixLengths];
settingsIPv6.includedRoutes = self.tunConfigurationIPv6.includedRoutes;
settingsIPv6.excludedRoutes = self.tunConfigurationIPv6.excludedRoutes;
networkSettings.IPv6Settings = settingsIPv6;
}
// Configure IPv4 addresses and routes
if (self.tunConfigurationIPv4.initialized) {
NSMutableArray *subnets = [NSMutableArray new];
[self.tunConfigurationIPv4.prefixLengths enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *subnet = [self getSubnetFromPrefixLength:obj];
[subnets addObject:subnet];
}];
NEIPv4Settings *ipSettings = [[NEIPv4Settings alloc] initWithAddresses:self.tunConfigurationIPv4.localAddresses subnetMasks:subnets];
ipSettings.includedRoutes = self.tunConfigurationIPv4.includedRoutes;
ipSettings.excludedRoutes = self.tunConfigurationIPv4.excludedRoutes;
NEPacketTunnelNetworkSettings *networkSettings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:self.tunConfiguration.remoteAddress];
networkSettings.IPv4Settings = ipSettings; networkSettings.IPv4Settings = ipSettings;
if (self.tunConfiguration.dnsAddresses.count > 0) {
networkSettings.DNSSettings = [[NEDNSSettings alloc] initWithServers:self.tunConfiguration.dnsAddresses];
if (self.tunConfiguration.searchDomains.count > 0) {
networkSettings.DNSSettings.searchDomains = self.tunConfiguration.searchDomains;
}
} }
networkSettings.MTU = self.tunConfiguration.mtu; // Configure DNS addresses and search domains
NSMutableArray *dnsAddresses = [NSMutableArray new];
if (self.tunConfigurationIPv6.dnsAddresses.count > 0) {
[dnsAddresses addObjectsFromArray:self.tunConfigurationIPv6.dnsAddresses];
}
if (self.tunConfigurationIPv4.dnsAddresses.count > 0) {
[dnsAddresses addObjectsFromArray:self.tunConfigurationIPv4.dnsAddresses];
}
if (dnsAddresses.count > 0) {
networkSettings.DNSSettings = [[NEDNSSettings alloc] initWithServers:dnsAddresses];
}
if (networkSettings.DNSSettings && self.searchDomains.count > 0) {
networkSettings.DNSSettings.searchDomains = self.searchDomains;
}
// Set MTU
networkSettings.MTU = self.mtu;
dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_semaphore_t sema = dispatch_semaphore_create(0);
@@ -368,7 +427,11 @@ static void socketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
// TODO: Describe why we use async invocation here // TODO: Describe why we use async invocation here
dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.openvpn-ios-client.connection", NULL); dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.openvpn-ios-client.connection", NULL);
dispatch_async(connectQueue, ^{ dispatch_async(connectQueue, ^{
self.tunConfiguration = [TUNConfiguration new]; self.tunConfigurationIPv6 = [TUNConfiguration new];
self.tunConfigurationIPv4 = [TUNConfiguration new];
self.searchDomains = [NSMutableArray new];
OpenVPNClient::init_process(); OpenVPNClient::init_process();
try { try {
@@ -391,7 +454,15 @@ static void socketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
} }
OpenVPNClient::uninit_process(); OpenVPNClient::uninit_process();
self.tunConfiguration = nil;
self.remoteAddress = nil;
self.tunConfigurationIPv6 = nil;
self.tunConfigurationIPv4 = nil;
self.searchDomains = nil;
self.mtu = nil;
self.username = nil; self.username = nil;
self.password = nil; self.password = nil;
@@ -475,6 +546,19 @@ static void socketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData
} }
} }
#pragma mark Utils
- (NSString *)getSubnetFromPrefixLength:(NSNumber *)prefixLength {
uint32_t bitmask = UINT_MAX << (sizeof(uint32_t) * 8 - prefixLength.integerValue);
uint8_t first = (bitmask >> 24) & 0xFF;
uint8_t second = (bitmask >> 16) & 0xFF;
uint8_t third = (bitmask >> 8) & 0xFF;
uint8_t fourth = bitmask & 0xFF;
return [NSString stringWithFormat:@"%uc.%uc.%uc.%uc", first, second, third, fourth];
}
#pragma mark Deallocation #pragma mark Deallocation
- (void)dealloc { - (void)dealloc {
+7 -22
View File
@@ -24,49 +24,34 @@ bool OpenVPNClient::tun_builder_new() {
} }
bool OpenVPNClient::tun_builder_set_remote_address(const std::string &address, bool ipv6) { bool OpenVPNClient::tun_builder_set_remote_address(const std::string &address, bool ipv6) {
// TODO: Adapter should be able to set IPv6 remote address
NSString *remoteAddress = [NSString stringWithUTF8String:address.c_str()]; NSString *remoteAddress = [NSString stringWithUTF8String:address.c_str()];
return [(__bridge OpenVPNAdapter *)adapter setRemoteAddress:remoteAddress]; return [(__bridge OpenVPNAdapter *)adapter setRemoteAddress:remoteAddress isIPv6:ipv6];
} }
bool OpenVPNClient::tun_builder_add_address(const std::string &address, int prefix_length, const std::string &gateway, bool ipv6, bool net30) { bool OpenVPNClient::tun_builder_add_address(const std::string &address, int prefix_length, const std::string &gateway, bool ipv6, bool net30) {
// TODO: Adapter should be able to add IPv6 addresses
NSString *localAddress = [NSString stringWithUTF8String:address.c_str()]; NSString *localAddress = [NSString stringWithUTF8String:address.c_str()];
NSString *subnet = [NSString stringWithUTF8String:get_subnet(prefix_length).c_str()];
NSString *gatewayAddress = [NSString stringWithUTF8String:gateway.c_str()]; NSString *gatewayAddress = [NSString stringWithUTF8String:gateway.c_str()];
return [(__bridge OpenVPNAdapter *)adapter addLocalAddress:localAddress subnet:subnet gateway:gatewayAddress]; return [(__bridge OpenVPNAdapter *)adapter addLocalAddress:localAddress prefixLength:@(prefix_length) gateway:gatewayAddress isIPv6:ipv6];
} }
bool OpenVPNClient::tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) { bool OpenVPNClient::tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) {
return true; return [(__bridge OpenVPNAdapter *)adapter defaultGatewayRerouteIPv4:ipv4 rerouteIPv6:ipv6];
} }
bool OpenVPNClient::tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) { bool OpenVPNClient::tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) {
// TODO: Adapter should be able to add IPv6 routes
NSString *route = [NSString stringWithUTF8String:address.c_str()]; NSString *route = [NSString stringWithUTF8String:address.c_str()];
NSString *subnet = [NSString stringWithUTF8String:get_subnet(prefix_length).c_str()]; return [(__bridge OpenVPNAdapter *)adapter addRoute:route prefixLength:@(prefix_length) isIPv6:ipv6];
return [(__bridge OpenVPNAdapter *)adapter addRoute:route subnet:subnet];
} }
bool OpenVPNClient::tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) { bool OpenVPNClient::tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) {
// TODO: Adapter should be able to exclude IPv6 routes
NSString *route = [NSString stringWithUTF8String:address.c_str()]; NSString *route = [NSString stringWithUTF8String:address.c_str()];
NSString *subnet = [NSString stringWithUTF8String:get_subnet(prefix_length).c_str()]; return [(__bridge OpenVPNAdapter *)adapter excludeRoute:route prefixLength:@(prefix_length) isIPv6:ipv6];
return [(__bridge OpenVPNAdapter *)adapter excludeRoute:route subnet:subnet];
} }
bool OpenVPNClient::tun_builder_add_dns_server(const std::string& address, bool ipv6) { bool OpenVPNClient::tun_builder_add_dns_server(const std::string& address, bool ipv6) {
// TODO: Adapter should be able to add IPv6 DNS
NSString *dnsAddress = [NSString stringWithUTF8String:address.c_str()]; NSString *dnsAddress = [NSString stringWithUTF8String:address.c_str()];
return [(__bridge OpenVPNAdapter *)adapter addDNSAddress:dnsAddress]; return [(__bridge OpenVPNAdapter *)adapter addDNSAddress:dnsAddress isIPv6:ipv6];
} }
bool OpenVPNClient::tun_builder_add_search_domain(const std::string& domain) { bool OpenVPNClient::tun_builder_add_search_domain(const std::string& domain) {
@@ -75,7 +60,7 @@ bool OpenVPNClient::tun_builder_add_search_domain(const std::string& domain) {
} }
bool OpenVPNClient::tun_builder_set_mtu(int mtu) { bool OpenVPNClient::tun_builder_set_mtu(int mtu) {
return [(__bridge OpenVPNAdapter *)adapter setMTU:mtu]; return [(__bridge OpenVPNAdapter *)adapter setMTU:@(mtu)];
} }
bool OpenVPNClient::tun_builder_set_session_name(const std::string& name) { bool OpenVPNClient::tun_builder_set_session_name(const std::string& name) {
+6 -11
View File
@@ -8,21 +8,16 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@class NEIPv4Route;
@interface TUNConfiguration : NSObject @interface TUNConfiguration : NSObject
@property (strong, nonatomic) NSString *remoteAddress; @property (nonatomic) BOOL initialized;
@property (readonly, strong, nonatomic) NSMutableArray<NSString *> *localAddresses; @property (readonly, strong, nonatomic) NSMutableArray *localAddresses;
@property (readonly, strong, nonatomic) NSMutableArray<NSString *> *subnets; @property (readonly, strong, nonatomic) NSMutableArray *prefixLengths;
@property (readonly, strong, nonatomic) NSMutableArray<NEIPv4Route *> *includedRoutes; @property (readonly, strong, nonatomic) NSMutableArray *includedRoutes;
@property (readonly, strong, nonatomic) NSMutableArray<NEIPv4Route *> *excludedRoutes; @property (readonly, strong, nonatomic) NSMutableArray *excludedRoutes;
@property (readonly, strong, nonatomic) NSMutableArray<NSString *> *dnsAddresses; @property (readonly, strong, nonatomic) NSMutableArray *dnsAddresses;
@property (readonly, strong, nonatomic) NSMutableArray<NSString *> *searchDomains;
@property (strong, nonatomic) NSNumber *mtu;
@end @end
+1 -2
View File
@@ -15,13 +15,12 @@
self = [super init]; self = [super init];
if (self) { if (self) {
_localAddresses = [NSMutableArray new]; _localAddresses = [NSMutableArray new];
_subnets = [NSMutableArray new]; _prefixLengths = [NSMutableArray new];
_includedRoutes = [NSMutableArray new]; _includedRoutes = [NSMutableArray new];
_excludedRoutes = [NSMutableArray new]; _excludedRoutes = [NSMutableArray new];
_dnsAddresses = [NSMutableArray new]; _dnsAddresses = [NSMutableArray new];
_searchDomains = [NSMutableArray new];
} }
return self; return self;
} }