Closed m1a7 closed 3 years ago
// .h
@import NetworkExtension;
@import OpenVPNAdapter;
NS_ASSUME_NONNULL_BEGIN
@interface PacketTunnelProvider : NEPacketTunnelProvider<OpenVPNAdapterDelegate>
@property(nonatomic,strong) OpenVPNAdapter *vpnAdapter;
@property(nonatomic,strong) OpenVPNReachability *openVpnReach;
typedef void(^StartHandler)(NSError * _Nullable);
typedef void(^StopHandler)(void);
@property(nonatomic,nullable, copy) StartHandler startHandler;
@property(nonatomic,nullable, copy) StopHandler stopHandler;
@end
NS_ASSUME_NONNULL_END
// .m
#import "PacketTunnelProvider.h"
@implementation PacketTunnelProvider
-(OpenVPNAdapter*)vpnAdapter{
if(!_vpnAdapter){
_vpnAdapter = [[OpenVPNAdapter alloc] init];
_vpnAdapter.delegate = self;
}
return _vpnAdapter;
}
-(OpenVPNReachability*)openVpnReach{
if(!_openVpnReach){
_openVpnReach = [[OpenVPNReachability alloc] init];
}
return _openVpnReach;
}
-(void)startTunnelWithOptions:(NSDictionary<NSString *,NSObject *> *)options completionHandler:(void (^)(NSError * _Nullable))completionHandler
{
NETunnelProviderProtocol* protocolConfiguration = (NETunnelProviderProtocol*)self.protocolConfiguration;
NSDictionary<NSString*,id>* providerConfiguration = protocolConfiguration.providerConfiguration;
NSData* ovpnFileContent = providerConfiguration[@"ovpn"];
if (!ovpnFileContent){
@throw [NSException exceptionWithName:@"!ovpnFileContent" reason:nil userInfo:nil];
return;
}
OpenVPNConfiguration *openVpnConfiguration = [[OpenVPNConfiguration alloc] init];
openVpnConfiguration.fileContent = ovpnFileContent;
openVpnConfiguration.settings = @{};
NSError* errorEvaluation = nil;
[self.vpnAdapter applyConfiguration:openVpnConfiguration error:&errorEvaluation];
if (errorEvaluation){
completionHandler(errorEvaluation); return;
}
__weak typeof(self) weak = self;
[self.openVpnReach startTrackingWithCallback:^(OpenVPNReachabilityStatus status) {
if(status==OpenVPNReachabilityStatusReachableViaWiFi){
return;;
}
if(status==OpenVPNReachabilityStatusNotReachable){
[weak.vpnAdapter reconnectAfterTimeInterval:5];
}
}];
self.startHandler = completionHandler;
[self.vpnAdapter connectUsingPacketFlow:(id<OpenVPNAdapterPacketFlow>)self.packetFlow];
}
-(void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler
{
self.stopHandler = completionHandler;
if ([self.openVpnReach isTracking]) {
[self.openVpnReach stopTracking];
}
[self.vpnAdapter disconnect];
}
-(void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter handleError:(NSError *)error{
BOOL isOpen = (BOOL)[error userInfo][OpenVPNAdapterErrorFatalKey];
if(isOpen){
if (self.openVpnReach.isTracking) {
[self.openVpnReach stopTracking];
}
if (self.startHandler){
self.startHandler(error);
self.startHandler = nil;
}else {
[self cancelTunnelWithError:error];
}
}
}
-(void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter handleEvent:(OpenVPNAdapterEvent)event message:(NSString *)message{
switch (event) {
case OpenVPNAdapterEventConnected:
if(self.reasserting){
self.reasserting = NO;
}
if (!self.startHandler) return;
self.startHandler(nil);
self.startHandler = nil;
break;
case OpenVPNAdapterEventDisconnected:
if (!self.stopHandler) return;
if (self.openVpnReach.isTracking) {
[self.openVpnReach stopTracking];
}
self.stopHandler();
self.stopHandler = nil;
break;
case OpenVPNAdapterEventReconnecting:
self.reasserting = YES;
break;
default:
break;
}
}
-(void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter
configureTunnelWithNetworkSettings:(NEPacketTunnelNetworkSettings *)networkSettings
completionHandler:(void (^)(NSError* _Nullable error))completionHandler
{
networkSettings.DNSSettings.matchDomains = @[@""];
[self setTunnelNetworkSettings:networkSettings completionHandler:completionHandler];
}
@end
Good afternoon @ss-abramchuk ! Please, could you give a link/implementation code of (PacketTunnelProvider : NEPacketTunnelProvider) on objective-c ?