Що NEVPNManager може створити в iOS (а що ні)
VPN-API в iOS будує одну конфігурацію, що належить застосунку, з трьох класів протоколів. L2TP, PPTP і підписані профілі не входять до цієї поверхні.
Коли ви будуєте екран VPN у застосунку iOS, перший сюрприз — список протоколів у застосунку «Налаштування» не є списком API. Фреймворк Network Extension дає змогу застосунку створити одну особисту конфігурацію VPN, що належить цьому застосунку, і приймає лише кілька об'єктів протоколу. Усе інше, чого люди очікують, від L2TP до завантаженого профілю, лежить поза цією поверхнею або є приватним для Apple. Помилки, що йдуть далі, зазвичай не баги: це API відмовляється від роботи, якої йому ніколи не давали.
Міф: API — це редактор «Налаштувань»
Вважається, що якщо iOS уміє налаштовувати профілі IKEv1, IKEv2, L2TP і IPsec, застосунок може створити будь-який із них програмно. Не може. Фреймворк надає застосунку, що викликає, рівно один слот конфігурації, і цей слот приймає лише невеликий набір публічних класів протоколів. Усе інше, чого люди очікують, від L2TP до завантаженого профілю, лежить поза цією поверхнею або є приватним для Apple.
Помилки, що йдуть далі, зазвичай не баги. Це API відмовляється від роботи, якої йому ніколи не давали, а рішення — проєктувати екран навколо того, чим володіє API.
Три об'єкти протоколу і ті, яких немає
Ваші варіанти — IKEv1 через NEVPNProtocolIPSec, IKEv2 через NEVPNProtocolIKEv2 і NETunnelProviderProtocol, якщо ви постачаєте власне розширення пакетного тунелю. Довідник NEVPNManager перелічує прийняті об'єкти протоколу. L2TP і PPTP ніколи не з'являються в цьому списку, бо Apple не опублікувала для них класів. Спроба будь-якого з них закінчується під час збереження помилкою або, що гірше, конфігурацією, яку система мовчки відмовляється використовувати.
Код для настільних систем дотримується інших правил. У macOS SCNetworkInterfaceCreateWithInterface укладає тип інтерфейсу, наприклад L2TP поверх IPv4, і прикріплює його до мережевої служби, а networksetup -connectpppoeservice запускає результат. Потрібні права адміністратора й допоміжний інструмент, адже спільний секрет і пароль потрапляють до системної зв'язки ключів. Скопіюйте цей дизайн на iOS — і нічого не скомпілюється.
Передавайте посилання на зв'язку ключів, а не пароль
Жоден із двох класів IKE не приймає пароль як текст. Дві властивості passwordReference і sharedSecretReference хочуть постійне посилання на зв'язку ключів, яке ви отримуєте з SecItemCopyMatching, запросивши kSecReturnPersistentRef. Передача даних елемента або вставляння рядка в поле дає збій збереження або з'єднання з порожніми обліковими даними. Посилання довговічне рівно настільки, наскільки довговічний елемент зв'язки ключів за ним, тому елемент має існувати до складання конфігурації. Створіть його в тій самій транзакції, що й збереження, і ви приберете цілий клас помилок порядку.
Автентифікація сертифікатом іде іншим шляхом: identityData плюс identityDataPassword для блоба PKCS#12. Постачання цього блоба всередині пакета застосунку — звичка, перенесена з прикладу коду, а не рішення про випуск, бо пароль подорожує разом із ним і кожна копія застосунку несе ту саму ідентичність.
Право й доступність замикають усе
Менеджера може не бути взагалі, і причина — провіжинінг. Ідентифікатору вашого застосунку потрібна можливість Network Extension разом із правом на особистий VPN, а профіль, що підписує збірку, має нести обидва.
Пропустіть це, і спільний екземпляр поверне nil, або збереження не вдасться з помилкою, яка ніколи не згадує право. Доступність — інші ворота. Якщо ви націлені на щось старше за iOS 8, символу немає під час виконання, тож збій — це падіння або nil-менеджер, а не менеджер без конфігурації. Перевірте середовище виконання й право, перш ніж налагоджувати граф об'єктів.
Завантажте, змініть, збережіть, потім стежте за порядком на запит
Ставтеся до життєвого циклу як до завантаження, зміни та збереження і ніколи не пропускайте завантаження. Поки loadFromPreferences не завершиться, менеджер нічого не тримає, і об'єкт протоколу не можна прочитати чи замінити.
Друге збереження замінює конфігурацію, а не додає ще одну, тож незавершене збереження може пошкодити профіль, що працював. Правила на запит утворюють упорядкований масив, і цей порядок і є політикою. Поставте правило підключення звідусіль перед правилом відключення, і після ручного відключення одразу станеться повторне підключення, що виглядає як дефект, але відповідає задокументованій оцінці.
Перемістіть правило відключення наперед, коли дія користувача має перемогти. Те, що залишається поза контролем застосунку, важливе не менше. Маршрути надходять із тунелю або політики сервера, а не з налаштування, яке задаєте ви, і постачальник пакетного тунелю повідомляє про них під час запуску. Застосунок не може перелічити або редагувати профілі, встановлені іншими застосунками чи профілями конфігурації, тому не обіцяйте екран, що показує кожен VPN на пристрої.