Skip to content

Instantly share code, notes, and snippets.

@zqqf16
Last active May 29, 2020 08:11
Show Gist options
  • Save zqqf16/cbcbd2254e6cb965f1a3 to your computer and use it in GitHub Desktop.
Save zqqf16/cbcbd2254e6cb965f1a3 to your computer and use it in GitHub Desktop.
Start IPSec programmatically in iOS 8
- (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;
}
@zqqf16
Copy link
Author

zqqf16 commented Nov 13, 2015

@Yiranfantexi 差别不大,具体参见这个 Gist
据我现在掌握的,在 iOS 中,IKEv2 的“设备鉴定”方式只能是证书和共享密钥二选一。
至于那两个描述文件,可以用 Apple Configurator 打开看看,能看见 VPN 的配置信息。

@Yiranfantexi
Copy link

我试过买的账号,当p.authenticationMethod=NEVPNIKEAuthenticationMethodNone ,不要证书和密钥也是可以实现连接的!我也是用strong swan 搭建的服务器安卓的可以实现连接,但是苹果的ikev2不行 只有ipsec 可以!醉了!!

@zqqf16
Copy link
Author

zqqf16 commented Nov 23, 2015

@Yiranfantexi IPSec IKE(v1/v2) 各个公司的实现方式都不一样,支持的加密算法什么的也是乱七八糟 😂

@Cutezhao
Copy link

你好,我使用共享密钥来的方式连接,再ios9的时候没有问题,但是ios8再安装描述文件的时候也出现了上边的描述文件未签名,还会出现闪退,有什么解决的办法吗

@Cutezhao
Copy link

@lhs71173717你好我问一下 你那个ios8 描述文件的问题有解决办法吗 ?

@weqeo
Copy link

weqeo commented Mar 16, 2016

@Cutezhao,你好,请问你的描述文件会不会提示 Save config faild[(null),我的会提示,请问你现在解决了吗?

@al-ht10
Copy link

al-ht10 commented Mar 21, 2016

How to use the above demo if .ovpn file is provided?

@duoduoyi
Copy link

点击按钮的时候 提示“Start VPN failed: [The operation couldn’t be completed. (NEVPNErrorDomain error 1.)]” 这怎么回事啊

Copy link

ghost commented Jun 6, 2016

Just call loadFromPreferencesWithCompletionHandler right before startVPNTunnelAndReturnError.
It should helps you. @duoduoyi

@vetrek
Copy link

vetrek commented Jul 3, 2016

Out of curiosity, is it possible to ignore local and remote identifier? or are they both mandatory?

@zhangyang91
Copy link

请问想要开发VPN的话是必须要申请开发权限吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment