-
-
Save zqqf16/cbcbd2254e6cb965f1a3 to your computer and use it in GitHub Desktop.
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// init VPN manager | |
self.vpnManager = [NEVPNManager sharedManager]; | |
// load config from perference | |
[_vpnManager loadFromPreferencesWithCompletionHandler:^(NSError *error) { | |
if (error) { | |
NSLog(@"Load config failed [%@]", error.localizedDescription); | |
return; | |
} | |
NEVPNProtocolIPSec *p = _vpnManager.protocol; | |
if (p) { | |
// Protocol exists. | |
// If you don't want to edit it, just return here. | |
} else { | |
// create a new one. | |
p = [[NEVPNProtocolIPSec alloc] init]; | |
} | |
// config IPSec protocol | |
p.username = @"[Your username]"; | |
p.serverAddress = @"[Your server address]";; | |
// Get password persistent reference from keychain | |
// If password doesn't exist in keychain, should create it beforehand. | |
// [self createKeychainValue:@"your_password" forIdentifier:@"VPN_PASSWORD"]; | |
p.passwordReference = [self searchKeychainCopyMatching:@"VPN_PASSWORD"]; | |
// PSK | |
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret; | |
// [self createKeychainValue:@"your_psk" forIdentifier:@"PSK"]; | |
p.sharedSecretReference = [self searchKeychainCopyMatching:@"PSK"]; | |
/* | |
// certificate | |
p.identityData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]]; | |
p.identityDataPassword = @"[Your certificate import password]"; | |
*/ | |
p.localIdentifier = @"[VPN local identifier]"; | |
p.remoteIdentifier = @"[VPN remote identifier]"; | |
p.useExtendedAuthentication = YES; | |
p.disconnectOnSleep = NO; | |
_vpnManager.protocol = p; | |
_vpnManager.localizedDescription = @"IPSec Demo"; | |
[_vpnManager saveToPreferencesWithCompletionHandler:^(NSError *error) { | |
if (error) { | |
NSLog(@"Save config failed [%@]", error.localizedDescription); | |
} | |
}]; | |
}]; | |
} | |
- (IBAction)startVPNConnection:(id)sender { | |
//[[VodManager sharedManager] installVPNProfile]; | |
NSError *startError; | |
[_vpnManager.connection startVPNTunnelAndReturnError:&startError]; | |
if (startError) { | |
NSLog(@"Start VPN failed: [%@]", startError.localizedDescription); | |
} | |
} | |
#pragma mark - KeyChain | |
static NSString * const serviceName = @"im.zorro.ipsec_demo.vpn_config"; | |
- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier { | |
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init]; | |
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; | |
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding]; | |
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric]; | |
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount]; | |
[searchDictionary setObject:serviceName forKey:(__bridge id)kSecAttrService]; | |
return searchDictionary; | |
} | |
- (NSData *)searchKeychainCopyMatching:(NSString *)identifier { | |
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier]; | |
// Add search attributes | |
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; | |
// Add search return types | |
// Must be persistent ref !!!! | |
[searchDictionary setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef]; | |
CFTypeRef result = NULL; | |
SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &result); | |
return (__bridge_transfer NSData *)result; | |
} | |
- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier { | |
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier]; | |
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dictionary); | |
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; | |
[dictionary setObject:passwordData forKey:(__bridge id)kSecValueData]; | |
status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL); | |
if (status == errSecSuccess) { | |
return YES; | |
} | |
return NO; | |
} |
我试过买的账号,当p.authenticationMethod=NEVPNIKEAuthenticationMethodNone ,不要证书和密钥也是可以实现连接的!我也是用strong swan 搭建的服务器安卓的可以实现连接,但是苹果的ikev2不行 只有ipsec 可以!醉了!!
@Yiranfantexi IPSec IKE(v1/v2) 各个公司的实现方式都不一样,支持的加密算法什么的也是乱七八糟 😂
你好,我使用共享密钥来的方式连接,再ios9的时候没有问题,但是ios8再安装描述文件的时候也出现了上边的描述文件未签名,还会出现闪退,有什么解决的办法吗
@lhs71173717你好我问一下 你那个ios8 描述文件的问题有解决办法吗 ?
@Cutezhao,你好,请问你的描述文件会不会提示 Save config faild[(null),我的会提示,请问你现在解决了吗?
How to use the above demo if .ovpn file is provided?
点击按钮的时候 提示“Start VPN failed: [The operation couldn’t be completed. (NEVPNErrorDomain error 1.)]” 这怎么回事啊
Just call loadFromPreferencesWithCompletionHandler right before startVPNTunnelAndReturnError.
It should helps you. @duoduoyi
Out of curiosity, is it possible to ignore local and remote identifier? or are they both mandatory?
请问想要开发VPN的话是必须要申请开发权限吗?
@Yiranfantexi 差别不大,具体参见这个 Gist
据我现在掌握的,在 iOS 中,IKEv2 的“设备鉴定”方式只能是证书和共享密钥二选一。
至于那两个描述文件,可以用 Apple Configurator 打开看看,能看见 VPN 的配置信息。