Vraag een iOS-app of de telefoon op een VPN zit, en het eerlijke antwoord is dat hij dat niet kan weten op de manier die u bedoelt. De SDK biedt geen vlag voor «het apparaat zit in een tunnel», en de private interfaces die daar in de buurt zouden kunnen komen, zijn gesloten voor apps die worden uitgegeven. U kunt de configuratie van uw eigen app observeren, de status die eraan hangt, en een of twee indirecte hints uit de netwerkstack. Elk beantwoordt een andere vraag, en de meeste kapotte controles ontstaan doordat men een ervan als het hele antwoord beschouwt.

De mythe van de enkele VPN-vlag

Het geloof is dat er ergens in de SDK een eigenschap is die meldt of het apparaat in een tunnel zit, zoals een bereikbaarheidsvlag meldt of een host antwoordt. Zo'n openbare eigenschap bestaat niet. En zelfs als die bestond, zijn «er is een tunnel» en «mijn verkeer gebruikt hem» verschillende beweringen, en voor de meeste apps telt alleen de tweede.

Precies die kloof is de reden dat bibliotheken die adverteren met een eenregelige VPN-detector meestal iets breekbaars lezen, zoals een interfacenaam of een proxysleutel, en dat als een vonnis presenteren.

Laad de voorkeuren voordat u een nil vertrouwt

De gedeelde manager-instantie bestaat zodra u erom vraagt, maar de protocoleigenschap blijft nil tot de laad-callback is voltooid. Een nil-protocol betekent dus «nog niet geladen» minstens zo vaak als «niet geïnstalleerd». Lees binnen de completion-blok en beslis pas daarna: een protocolobject dat bestaat, met de activeringsvlag aan, zo ziet «geïnstalleerd» eruit.

Een tweede signaal zit op het verbindingsobject: de ongeldige status, die het systeem meldt wanneer deze app geen configuratie geïnstalleerd heeft. Ongeldige status samen met een nil-protocol na een voltooide lading is echte afwezigheid, geen timing-race.

Verbindingswijzigingen komen als meldingen

Handlers die aan load en save worden gegeven, melden wat er met de configuratie is gebeurd, niet wat de tunnel doet. Wachten tot een van hen afgaat bij het verbinden is een race die nooit wordt opgelost. Let in plaats daarvan op de melding van de statuswijziging en lees de huidige waarde van het verbindingsobject wanneer die binnenkomt.

Zodra een configuratie is geïnstalleerd, doorloopt de verbindingsstatus een korte reeks: verbroken, verbindt, verbonden, bevestigt opnieuw, verbreekt. «Verbonden» beschrijft de tunnel en niet de server erachter, dus het is geen bewijs dat verkeer stroomt. On-demand kan ook een tunnel opzetten terwijl de app is opgeschort, en dan komt de melding binnen voordat u iets te updaten hebt.

De beperkte proxy-momentopname is een hint, geen vonnis

CFNetwork kan de app de huidige systeemproxyinstellingen geven, en binnen dat resultaat zit een beperkt woordenboek met de interfacenaam als sleutel. Een naam zien die begint met tun, utun, ppp, ipsec of tap is een hint dat er een tunnel is. Het blijft een momentopname van wat deze app kan zien, geen uitspraak over waar pakketten reizen.

Aanbieders zijn het oneens over naamgeving, dus een ontbrekend voorvoegsel bewijst niets, en een aanwezige interface kan bestaan zonder verkeer te dragen. Bereikbaarheid is nog zwakker: een geslaagd verzoek naar een privéadres toont dat het pad voor dat verzoek op dat moment werkte, niet dat er een VPN is geïnstalleerd.

De simulator leent de Mac, en andere apps blijven onzichtbaar

De simulator heeft geen eigen netwerkstack; elke verbinding die hij maakt is die van de Mac. Een VPN op de host-Mac geldt dus al voor de gesimuleerde app, en de instellingen van de simulator zelf tonen niets. Als de tunnel omhoogkwam nadat de simulator startte, is opnieuw starten meestal sneller dan de app debuggen. Een host op een niet-standaardpoort heeft die poort in de URL nodig, of een lokale doorstuur zoals socat TCP-LISTEN:12345,fork TCP:host:12345.

Openbare API's zullen geen VPN-profielen opsommen die toebehoren aan andere apps of aan configuratieprofielen. Voor één bekende app is een URL-schema-probe via canOpenURL de draagbare truc, en sinds iOS 9 moet het bevraagde schema in je Info.plist worden gedeclareerd; laat je het weg, dan geeft de aanroep false terug. OpenVPN Connect antwoordt op openvpn://, wat het een goed voorbeeld en een slechte algemene detector maakt.

Combineer drie observaties en zeg wat ze betekenen

Stapel in de praktijk drie resultaten: een configuratie die is geladen en geactiveerd, een verbindingsstatus die niet ongeldig is, en een verzoek naar een adres dat alleen via de tunnel bereikbaar is. Elk afzonderlijk misleidt; samen zeggen ze wat de app kan weten in plaats van wat de gebruiker aanneemt.

Schrijf het resultaat als drie regels in je diagnostiek, niet als één boolean. Wanneer een gebruiker zegt dat de VPN uit staat terwijl je app het oneens is, tonen de drie regels welke observatie afweek, en dat is het verschil tussen een supportticket waar je iets mee kunt en een dat eindigt met «bij mij werkt het».

Gerelateerde artikelen