Je hebt één scherm nodig dat zich anders gedraagt wanneer de tunnel actief is, en er is geen aanroep die je dat vertelt. Dat is de beperking bij het uitbrengen: op macOS meldt geen enkel openbaar framework of een willekeurige VPN is verbonden, en op iOS hoort de status bij de app die de configuratie heeft geïnstalleerd. De controles hieronder gaan van die grens naar iets wat je kunt uitbrengen, en elk ervan kan de zoektocht vroegtijdig beëindigen.

Controle 1: is de vraag überhaupt beantwoordbaar?

Sandboxing beslecht de vraag voordat welke API dan ook dat doet. Een proces van een derde partij kan de extensie van een andere leverancier niet opsommen en kan de configuratie van die extensie ook niet lezen, dus er is geen ondersteund object om te vragen.

Elke omweg stuit op dezelfde muur. Interfacelijsten, scutil --nc list en rechtstreekse lezingen van de systeemconfiguratie vereisen ofwel rechten die de sandbox achterhoudt, ofwel gedrag dat Apple nooit heeft beloofd. Als het plan een van die dingen nodig heeft, is het plan het probleem. Een functie die op een ongedocumenteerd detail is gebouwd, is een supportticket met een leverdatum.

Controle 2: beheert je app de tunnel zelf?

Als dat zo is, heb je een ondersteund antwoord voor je eigen configuratie. Laad de voorkeuren, behandel de fout, lees dan de status en abonneer je op wijzigingen in plaats van te pollen:

vpnManager.loadFromPreferences { error in
    // handle a load failure before reading status
}

NotificationCenter.default.addObserver(
    forName: .NEVPNStatusDidChange,
    object: nil,
    queue: nil
) { note in
    let status = (note.object as? NEVPNConnection)?.status
}

Wees precies over wat dit teruggeeft: de toestand van de tunnel die je hebt geïnstalleerd. Een gebruiker met een andere client verschijnt als verbroken, en dat is geen bug in je code. Bepaal welke van die twee vragen je functie werkelijk stelt voordat je op het antwoord bouwt.

Controle 3: wat zou een heuristiek je echt vertellen?

De breed gekopieerde aanpak vraagt het systeem-proxywoordenboek om zijn gescopete items en leest de sleutels, die toevallig interfacenamen zijn:

let settings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?
let scoped = settings?["__SCOPED__"] as? [String: Any]
let names = scoped?.keys ?? []

Een sleutel die begint met tap, tun, ppp, ipsec of utun impliceert dat er een tunnelgescopeerde interface aanwezig is. De hele naam matchen mislukt meteen, omdat iOS 12 met utun1 en utun2 kwam en sommige profielen als ipsec4, ppp0 of utun0 verschijnen. Vergelijk in plaats daarvan prefixen.

Toch identificeert een naam geen eigenaar. Systeemfuncties en extensies van andere leveranciers maken ook utun-interfaces, en er kan een bestaan zonder iets van jouw verkeer te dragen. Lees het als een hint dat er iets tunnelvormigs in de buurt is, niets sterkers. Een fout-positief is hier goedkoop als je maar één functie afschermt, en duur als je het inlogscherm afschermt.

Controle 4: kun je in plaats daarvan de bestemming testen?

Als de app alleen hoeft te weten of een interne dienst bereikbaar is, test die dienst. Een korte probe met een time-out beantwoordt de vraag waarvan de functie echt afhangt, en hij blijft werken wanneer de gebruiker van client wisselt of de tunnel van vorm verandert.

Bereikbaarheid is een observatie over je pad. Een interfacenaam is een gevolgtrekking over iets naast je pad, en daarom levert de heuristiek discussies op in bugrapporten en de probe bewijs. Als de probe faalt terwijl de gebruiker volhoudt dat de VPN aan staat, heb je nu een concreet pad om te debuggen: naamresolutie, route of diensttoestemming.

Controle 5: kan het platform afdwingen wat je nodig hebt?

Wanneer de eis een garantie is dat er niets aan de tunnel ontsnapt, hoort het profiel daar, niet de detector. includeAllNetworks aanzetten in een volledige-tunnelconfiguratie op iOS 14 of later verandert het gedrag van het platform in plaats van je app te vragen het af te leiden. De vlag is gedocumenteerd in de NEVPNProtocol-referentie.

Dat is een ander soort antwoord: afdwinging in plaats van observatie. Het geldt ook alleen voor profielen die je beheert, dus het helpt een consumentenapp niet die iemand anders' tunnel in de gaten houdt.

Controle 6: maak de fout veilig en waarneembaar

Schakel alleen de mogelijkheid uit die de tunnel nodig heeft en laat de rest van de app bruikbaar. Een detector die de hele interface verbergt zodra hij onzeker is, creëert een storing voor iedereen wiens tunnel een naam gebruikt die je nooit had voorzien. Val in plaats daarvan terug op het conservatieve gedrag: lokale functies blijven werken en alleen de externe aanroep die de tunnel echt nodig heeft, wordt uitgeschakeld. Die keuze is een productbeslissing, en ze verdient het om naast de heuristiek te worden opgeschreven.

Log wat je hebt waargenomen: interfacenamen, platformversie en het resultaat van één probe. Dat maakt het volgende rapport van een discussie een controle. Geef daarna de voorkeur aan een ondersteunde verklaring waar je er een hebt, want een beheerde configuratie kan de bedoeling expliciet dragen en het grootste deel van de reden wegnemen om namen überhaupt te inspecteren.

Als controles 1 tot en met 5 je zonder ondersteund antwoord hebben achtergelaten, breng de probe dan uit en label het resultaat eerlijk. Een gedocumenteerd best-effortsignaal is een betere productbeslissing dan een privé-API die bij de volgende release breekt.

Gerelateerde artikelen