我们如何更新NEVPNProtocol参数,如serverAddress和username?

时间:2017-02-14 12:01:25

标签: ios networkextension nevpnmanager

我的应用程序就像IPSec VPN服务器(strongSwan)的VPN客户端。 我使用NEVPNManager来设置VPN配置文件。代码是这样的:

#define KEY_PASSWORD @"password"
#define PASSWORD @"password"
#define VPN_SERVER @"10.1.1.1"
#define KEY_USERNAME @"username"
#define USERNAME @"myusername"
#define KEY_SHARED_SECRET @"sharedSecret"
#define SHARED_SECRET @"thisisthesecretekey"
#define LOCAL_IDENTIFIER @"myserver.com.client"
#define REMOTE_IDENTIFIER @"myserver.com.server"

-(void) setupVPNProfile {    
    NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];
    protocol.username = USERNAME;
    NSData *passwdRef = [self getData:KEY_PASSWORD];
    if (passwdRef == nil) {
        [self storeData:KEY_PASSWORD data:[PASSWORD dataUsingEncoding:NSUTF8StringEncoding]];
        passwdRef = [self getData:PASSWORD];
        NSLog(@"passwdRef: %@", [[NSString alloc] initWithData:passwdRef encoding:NSUTF8StringEncoding]);
    }
    protocol.passwordReference = passwdRef;

    protocol.serverAddress = VPN_SERVER;

    protocol.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
    NSData *sharedSecretRef = [self getData:KEY_SHARED_SECRET];
    if (sharedSecretRef == nil) {
        [self storeData:KEY_SHARED_SECRET data:[SHARED_SECRET dataUsingEncoding:NSUTF8StringEncoding]];
        sharedSecretRef = [self getData:KEY_SHARED_SECRET];
        NSLog(@"sharedSecretRef: %@", [[NSString alloc] initWithData:sharedSecretRef encoding:NSUTF8StringEncoding]);

    }
    protocol.sharedSecretReference = sharedSecretRef;

    protocol.localIdentifier = LOCAL_IDENTIFIER;
    protocol.remoteIdentifier = REMOTE_IDENTIFIER;

    protocol.useExtendedAuthentication = YES;

    protocol.disconnectOnSleep = NO;

    self.manager.protocolConfiguration = protocol;

    self.manager.enabled = YES;
}

#pragma mark - Keychain methods

- (void) storeData: (NSString * )key data:(NSData *)data {
    NSLog(@"Store Data");
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:data forKey:(__bridge id)kSecValueData];

    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
    if(errSecSuccess != status) {
        NSLog(@"Unable add item with key =%@ error:%d",key,(int)status);
    }
}

- (NSData *) getData: (NSString *)key {
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];

    CFTypeRef result = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);

    if( status != errSecSuccess) {
        NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
        return nil;
    }

    NSData *resultData = (__bridge NSData *)result;
   return resultData;
}

- (BOOL) removeData: (NSString *) key {
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];

    OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dict);

    if( status != errSecSuccess) {
        NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
        return NO;
    }

    return YES;
}

此处的用户名,密码服务器地址等值存储在上面定义的MACROS中。根据所需的设计,password和sharedSecret将存储为Persistent KeyChain项。 在此设置中,如何优雅地更改用户名,密码,serverAddress,sharedSecret等值?

到目前为止我尝试过:

  1. 我在代码中更改了服务器地址,用户名等值。一世 使用storeData函数覆盖密码和sharedSecret 持久性钥匙串项目。然而,当我在制作后运行应用程序 这些变化我无法连接到新的VPN服务器。请 请注意,我没有对我必须使用的新值进行任何错误 使用。我在更新前仔细检查过。还请注意我是 我创建.mobileconfig文件时能够连接到VPN服务器 在那些新的参数中。它只是我的VPN客户端应用程序不是 能够再连接到服务器了。它会尝试连接并且会 再次断开连接卸载应用程序也没有效果。

  2. 设置manager.protocolConfiguration = nil。这样做没有效果。已安装的protocolConfiguration保持不变。

  3. 我不想通过调用管理器removePreferencesWithCompletionHandler:]删除VPN配置文件,因为用户在尝试连接到VPN服务器时会再次看到VPN相关的弹出窗口。 如果有人这样做过,请帮助。 感谢。

1 个答案:

答案 0 :(得分:0)

要更改VPN帐户,您应该只需更改VPN帐户参数,然后使用新值启动VPNManager。您不需要停止当前运行的VPN会话,您当然不需要删除配置文件,只需调用NEVPNManager.shared.locadFromPreferences,进行更改,然后正常.saveToPreferences和startVPNTunnel。

由于即使使用已知的良好凭据使用变量而不是宏,您也无法启动VPN隧道,因此您可能错误地从钥匙串传递值,或者不是您所期望的。我会使用print语句比较每个参数,首先使用当前使用宏的工作解决方案,然后使用非工作密钥链代码。