Как мы можем обновить параметры NEVPNProtocol, такие как serverAddress и имя пользователя?

Мое приложение действует как VPN-клиент для VPN-сервера IPSec (strongSwan). Я использовал 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;
}

Здесь такие значения, как имя пользователя, пароль, адрес сервера, хранятся в макросах, определенных выше. Согласно требуемому дизайну, пароль и sharedSecret должны храниться как элементы Persistent KeyChain. В этой настройке, как я могу изящно изменить такие значения, как имя пользователя, пароль, serverAddress, sharedSecret?

Что я пробовал до сих пор:

  1. Я изменил значения, такие как адрес сервера, имя пользователя в коде. Я использовал функции storeData для перезаписи пароля и постоянных элементов связки ключей sharedSecret. Однако, когда я запустил приложение после внесения этих изменений, я не смог подключиться к новому VPN-серверу. Обратите внимание, что я не ошибся с новыми значениями, которые мне пришлось использовать. Я дважды проверял перед обновлением. Также обратите внимание, что я смог подключиться к VPN-серверу, когда создал файл .mobileconfig из этих новых параметров. Просто мое клиентское приложение VPN больше не могло подключаться к серверу. Он попытается подключиться и снова отключится. Удаление приложения также не дало результата.

  2. Настройка manager.protocolConfiguration = nil. Это не имеет никакого эффекта. Установленная конфигурация протокола остается неизменной.

Я не хочу удалять профиль VPN, вызывая менеджера removePreferencesWithCompletionHandler:], так как пользователь снова увидит всплывающее окно, связанное с VPN, когда попытается подключиться к VPN-серверу. Если кто-то делал это раньше, пожалуйста, помогите. Спасибо.


person Varun Singh    schedule 14.02.2017    source источник


Ответы (1)


Чтобы изменить учетную запись VPN, вы должны иметь возможность просто изменить параметры учетной записи VPN, а затем запустить VPNManager с новыми значениями. Вам не нужно останавливать текущую сессию VPN, и вам, конечно же, не нужно удалять профиль, просто вызовите NEVPNManager.shared.locadFromPreferences, внесите изменения, затем .saveToPreferences и startVPNTunnel, как обычно.

Поскольку вы не можете запустить VPN-туннель даже с известными надежными учетными данными, используя переменные вместо макросов, то вы, вероятно, неправильно передаете значения из цепочки для ключей или не то, что ожидаете. Я бы сравнил каждый параметр, используя операторы печати, сначала с вашим текущим рабочим решением, использующим макросы, а затем с неработающим кодом цепочки для ключей.

person hungri-yeti    schedule 24.03.2017
comment
Спасибо. Я попробую это и дам вам знать, что происходит. Похоже, мне придется хотя бы разорвать текущее соединение. Только тогда вызов startVPNunnel будет иметь смысл. Тем не менее, я могу жить с этим. - person Varun Singh; 27.03.2017