Quand vous construisez un écran VPN dans une app iOS, la première surprise est que la liste des protocoles de l’app Réglages n’est pas la liste de l’API. Le framework Network Extension permet à votre app de créer une configuration VPN personnelle, détenue par cette app, et il n’accepte que quelques objets de protocole. Tout le reste de ce que les gens attendent, du L2TP à un profil téléchargé, se trouve hors de cette surface ou appartient à Apple. Les échecs qui suivent ne sont généralement pas des bugs, c’est l’API qui refuse un travail qu’on ne lui a jamais confié.

Le mythe : l’API est un éditeur des Réglages

On croit que, parce qu’iOS sait configurer des profils IKEv1, IKEv2, L2TP et IPsec, une app peut en créer n’importe lequel par programme. C’est faux. Le framework expose exactement un emplacement de configuration à l’app appelante, et cet emplacement n’accepte qu’un petit ensemble de classes de protocole publiques. Tout le reste de ce que les gens attendent, du L2TP à un profil téléchargé, se trouve hors de cette surface ou appartient à Apple.

Les échecs qui suivent ne sont généralement pas des bugs. C’est l’API qui refuse un travail qu’on ne lui a jamais confié, et le correctif consiste à concevoir l’écran autour de ce que l’API possède.

Trois objets de protocole et ceux qui n’existent pas

Vos options sont IKEv1 via NEVPNProtocolIPSec, IKEv2 via NEVPNProtocolIKEv2, et NETunnelProviderProtocol si vous livrez votre propre extension de tunnel par paquets. La référence NEVPNManager liste les objets de protocole acceptés. L2TP et PPTP n’y apparaissent jamais, car Apple n’a publié aucune classe pour eux. Tenter l’un ou l’autre se termine à l’enregistrement par une erreur, ou pire, par une configuration que le système refuse silencieusement d’utiliser.

Le code de bureau suit d’autres règles. Sur macOS, SCNetworkInterfaceCreateWithInterface empile un type d’interface comme L2TP sur IPv4 et l’attache à un service réseau, et networksetup -connectpppoeservice démarre le résultat. Des droits d’administrateur et un outil d’assistance sont requis, car le secret partagé et le mot de passe vont dans le trousseau système. Copiez ce design sur iOS et rien ne compile.

Passez une référence de trousseau, pas le mot de passe

Aucune des deux classes IKE n’accepte un mot de passe en texte. Les deux propriétés passwordReference et sharedSecretReference veulent une référence de trousseau persistante, que vous obtenez de SecItemCopyMatching en demandant kSecReturnPersistentRef. Passer les données de l’élément, ou forcer une chaîne dans le champ, produit un échec d’enregistrement ou une connexion avec des identifiants vides. La référence n’est aussi durable que l’élément de trousseau derrière elle, c’est pourquoi l’élément doit exister avant que la configuration soit assemblée. Créez-le dans la même transaction que l’enregistrement et vous éliminez toute une classe de bugs d’ordre.

L’authentification par certificat prend une autre route : identityData plus identityDataPassword pour un blob PKCS#12. Livrer ce blob dans le bundle de l’app est une habitude héritée du code d’exemple plutôt qu’une décision de production, car le mot de passe voyage avec lui et chaque copie de l’app porte la même identité.

L’habilitation et la disponibilité conditionnent tout

Le gestionnaire peut ne pas exister du tout, et la raison est le provisionnement. L’identifiant de votre app a besoin de la capacité Network Extension ainsi que de l’habilitation VPN personnelle, et le profil qui signe le build doit porter les deux.

Ignorez cela et l’instance partagée renvoie nil, ou l’enregistrement échoue avec une erreur qui ne mentionne jamais l’habilitation. La disponibilité est l’autre barrière. Ciblez quoi que ce soit de plus ancien qu’iOS 8 et le symbole manque à l’exécution, donc l’échec est un crash ou un gestionnaire nil plutôt qu’un gestionnaire sans configuration. Vérifiez l’exécution et l’habilitation avant de déboguer votre graphe d’objets.

Charger, modifier, enregistrer, puis surveiller l’ordre à la demande

Traitez le cycle de vie comme charger, modifier, enregistrer, et ne sautez jamais le chargement. Tant que loadFromPreferences n’est pas terminé, le gestionnaire ne détient rien et l’objet de protocole ne peut être lu ni remplacé.

Un second enregistrement remplace la configuration au lieu d’en ajouter une autre, donc un enregistrement à moitié terminé peut endommager un profil qui fonctionnait. Les règles à la demande forment un tableau ordonné, et cet ordre est la politique. Placez une règle de connexion partout avant la règle de déconnexion et une déconnexion manuelle est suivie d’une reconnexion immédiate, ce qui ressemble à un défaut mais suit l’évaluation documentée.

Déplacez la règle de déconnexion à l’avant quand l’action de l’utilisateur doit l’emporter. Ce qui reste hors du contrôle de l’app compte tout autant. Les routes viennent du tunnel ou de la politique du serveur plutôt que d’une préférence que vous définissez, un fournisseur de tunnel par paquets les signalant au démarrage. L’app ne peut ni lister ni modifier les profils installés par d’autres apps ou profils de configuration, donc ne promettez pas un écran qui montre tous les VPN de l’appareil.

Articles similaires