Was NEVPNManager unter iOS erstellen kann (und was nicht)
Die iOS-VPN-API baut aus drei Protokollklassen eine app-eigene Konfiguration. L2TP, PPTP und signierte Profile gehören nicht zu dieser Oberfläche.
Bauen Sie einen VPN-Bildschirm in eine iOS-App ein, und die erste Überraschung ist, dass die Protokollliste in der Einstellungen-App nicht die API-Liste ist. Das Network Extension-Framework lässt Ihre App eine persönliche VPN-Konfiguration anlegen, die dieser App gehört, und akzeptiert nur wenige Protokollobjekte. Alles andere, was Leute erwarten, von L2TP bis zum heruntergeladenen Profil, liegt außerhalb dieser Oberfläche oder ist Apples Privatsache. Die Fehler, die folgen, sind meist keine Bugs: Die API lehnt eine Aufgabe ab, die sie nie bekommen hat.
Der Mythos: Die API ist kein Einstellungs-Editor
Die Annahme lautet, weil iOS IKEv1-, IKEv2-, L2TP- und IPsec-Profile konfigurieren kann, könne eine App jedes davon programmatisch anlegen. Kann sie nicht. Das Framework bietet der aufrufenden App genau einen Konfigurationsplatz, und dieser Platz akzeptiert eine kleine Menge öffentlicher Protokollklassen. Alles andere, was Leute erwarten, von L2TP bis zum heruntergeladenen Profil, liegt außerhalb dieser Oberfläche oder ist Apples Privatsache.
Die Fehler, die folgen, sind meist keine Bugs. Die API lehnt eine Aufgabe ab, die sie nie bekommen hat, und die Lösung ist, den Bildschirm um das herum zu entwerfen, was die API besitzt.
Drei Protokollobjekte und die, die es nicht gibt
Ihre Möglichkeiten sind IKEv1 über NEVPNProtocolIPSec, IKEv2 über NEVPNProtocolIKEv2 und NETunnelProviderProtocol, wenn Sie eine eigene Pakettunnel-Erweiterung ausliefern. Die NEVPNManager-Referenz listet die akzeptierten Protokollobjekte auf. L2TP und PPTP erscheinen dort nie, weil Apple dafür keine Klassen veröffentlicht hat. Ein Versuch endet beim Speichern mit einem Fehler oder, schlimmer, mit einer Konfiguration, die das System stillschweigend nicht nutzt.
Desktop-Code folgt anderen Regeln. Unter macOS stapelt SCNetworkInterfaceCreateWithInterface einen Schnittstellentyp wie L2TP über IPv4 und hängt ihn an einen Netzwerkdienst, und networksetup -connectpppoeservice startet das Ergebnis. Administratorrechte und ein Hilfswerkzeug sind nötig, weil das gemeinsame Geheimnis und das Passwort in den Systemschlüsselbund wandern. Übertragen Sie dieses Design auf iOS, und nichts kompiliert.
Übergeben Sie eine Schlüsselbundreferenz, nicht das Passwort
Keine der IKE-Klassen akzeptiert ein Passwort als Text. Die beiden Eigenschaften passwordReference und sharedSecretReference wollen eine dauerhafte Schlüsselbundreferenz, die Sie von SecItemCopyMatching erhalten, indem Sie kSecReturnPersistentRef anfordern. Die Elementdaten zu übergeben oder eine Zeichenkette in das Feld zu zwingen, erzeugt einen Speicherfehler oder eine Verbindung mit leeren Anmeldedaten. Die Referenz ist nur so haltbar wie das Schlüsselbund-Element dahinter, deshalb muss das Element existieren, bevor die Konfiguration zusammengesetzt wird. Legen Sie es in derselben Transaktion wie das Speichern an, und Sie beseitigen eine ganze Klasse von Reihenfolgefehlern.
Zertifikatsauthentifizierung nimmt einen anderen Weg: identityData plus identityDataPassword für einen PKCS#12-Blob. Diesen Blob im App-Bundle auszuliefern ist eine aus Beispielcode übernommene Angewohnheit und keine Auslieferungsentscheidung, weil das Passwort mitreist und jede Kopie der App dieselbe Identität trägt.
Berechtigung und Verfügbarkeit entscheiden über alles
Der Manager existiert vielleicht gar nicht, und der Grund ist das Provisioning. Ihre App-Kennung braucht die Network Extension-Fähigkeit zusammen mit der Berechtigung für persönliches VPN, und das Profil, das den Build signiert, muss beides tragen.
Lassen Sie das weg, und die geteilte Instanz gibt nil zurück, oder das Speichern scheitert mit einem Fehler, der die Berechtigung nie erwähnt. Die Verfügbarkeit ist das andere Tor. Zielen Sie auf etwas Älteres als iOS 8, und das Symbol fehlt zur Laufzeit, sodass der Fehler ein Absturz oder ein nil-Manager ist statt eines Managers ohne Konfiguration. Prüfen Sie Laufzeit und Berechtigung, bevor Sie Ihren Objektgraphen debuggen.
Laden, ändern, speichern und dann die On-Demand-Reihenfolge beachten
Behandeln Sie den Lebenszyklus als Laden, Ändern, Speichern, und überspringen Sie nie das Laden. Bis loadFromPreferences abgeschlossen ist, hält der Manager nichts, und das Protokollobjekt kann weder gelesen noch getauscht werden.
Ein zweites Speichern ersetzt die Konfiguration, statt eine weitere hinzuzufügen, daher kann ein halbfertiges Speichern ein funktionierendes Profil beschädigen. On-Demand-Regeln bilden ein geordnetes Array, und diese Reihenfolge ist die Richtlinie. Setzen Sie eine Verbinden-von-überall-Regel vor die Trennregel, und auf ein manuelles Trennen folgt sofort ein Wiederverbinden, was wie ein Defekt aussieht, aber der dokumentierten Auswertung folgt.
Rücken Sie die Trennregel nach vorn, wenn die Nutzeraktion gewinnen muss. Was außerhalb der Kontrolle der App bleibt, zählt genauso. Routen kommen vom Tunnel oder von der Serverrichtlinie statt von einer Einstellung, die Sie setzen, wobei ein Pakettunnel-Anbieter sie beim Start meldet. Die App kann Profile weder auflisten noch bearbeiten, die von anderen Apps oder Konfigurationsprofilen installiert wurden, versprechen Sie also keinen Bildschirm, der jedes VPN auf dem Gerät zeigt.