Å oppdaga ein aktiv VPN i ein sandboxa Mac-app
Det finst ikkje noko offentleg API for dette spørsmålet, og trikset med grensesnittnamnet er berre ein heuristikk. Seks kontrollar for å avgjere kva appen din eigentleg bør vere avhengig av.
Du treng éin skjerm som oppfører seg annleis når tunnelen er oppe, og det finst ikkje noko kall som fortel deg det. Det er utgivingsavgrensinga: på macOS rapporterer ingen offentleg ramme om ein vilkårleg VPN er tilkopla, og på iOS høyrer statusen til appen som installerte konfigurasjonen. Kontrollane nedanfor går frå den grensa til noko du kan gje ut, og kvar av dei kan avslutte søket tidleg.
Kontroll 1: kan spørsmålet i det heile svarast?
Sandboxing avgjer spørsmålet før nokon API gjer det. Ein tredjepartsprosess kan ikkje ramse opp utvidinga til ein annan leverandør, og kan heller ikkje lese konfigurasjonen til den utvidinga, så det finst ikkje noko støtta objekt å spørje.
Kvar omveg møter den same veggen. Grensesnittlister, scutil --nc list og direkte lesing av systemkonfigurasjonen krev anten rettar som sandkassen held attende, eller er avhengige av åtferd Apple aldri lova. Viss planen treng ein av desse, er planen problemet. Ein funksjon bygd på ein udokumentert detalj er ein støttebillett med leveringsdato.
Kontroll 2: styrer appen din tunnelen sjølv?
Viss han gjer det, har du eit støtta svar for din eigen konfigurasjon. Last inn innstillingane, handsam feilen, les deretter statusen og abonner på endringar i staden for å polle:
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
}Ver presis på kva dette returnerer: tilstanden til tunnelen du installerte. Ein brukar som køyrer ein annan klient vil visast som fråkopla, og det er ikkje ein feil i koden din. Avgjer kva av desse to spørsmåla funksjonen din eigentleg stiller før du byggjer på svaret.
Kontroll 3: kva ville ein heuristikk eigentleg fortelje deg?
Den mykje kopierte tilnærminga spør systemet sin proxy-ordbok om dei avgrensa oppføringane og les nøklane, som tilfeldigvis er grensesnittnamn:
let settings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?
let scoped = settings?["__SCOPED__"] as? [String: Any]
let names = scoped?.keys ?? []Ein nøkkel som byrjar med tap, tun, ppp, ipsec eller utun tyder på at det finst eit tunnelavgrensa grensesnitt. Å matche heile namnet feilar med ein gong, fordi iOS 12 kom med utun1 og utun2, og nokre profilar viser seg som ipsec4, ppp0 eller utun0. Samanlikn prefiks i staden.
Likevel identifiserer eit namn ingen eigar. Systemfunksjonar og utvidingar frå andre leverandørar lagar også utun-grensesnitt, og eitt kan eksistere utan å bere noko av trafikken din. Les det som eit hint om at noko tunnelforma er i nærleiken, ikkje meir. Ein falsk positiv er billeg her viss du berre sperrar éin funksjon, og dyr viss du sperrar innloggingsskjermen.
Kontroll 4: kan du teste destinasjonen i staden?
Viss appen berre treng å vite om ein intern teneste er tilgjengeleg, test den tenesta. Ein kort probe med tidsavbrot svarar på spørsmålet funksjonen faktisk er avhengig av, og han held fram med å verke når brukaren byter klient eller tunnelen endrar form.
Tilgjenge er ei observasjon om vegen din. Eit grensesnittnamn er ei slutning om noko som grensar til vegen din, og difor skapar heuristikken diskusjonar i feilrapportar medan proben skapar bevis. Viss proben feilar medan brukaren insisterer på at VPN-en er på, har du no ein konkret veg å feilsøkje: namneoppslag, rute eller tenestetillating.
Kontroll 5: kan plattforma handheve det du treng?
Når kravet er ein garanti for at ingenting slepp ut av tunnelen, høyrer profilen heime der, ikkje detektoren. Å slå på includeAllNetworks i ein fulltunnelkonfigurasjon på iOS 14 eller nyare endrar åtferda til plattforma i staden for å be appen din utleie det. Flagget er dokumentert i NEVPNProtocol-referansen.
Det er ein annan type svar: handheving i staden for observasjon. Det gjeld også berre profilar du kontrollerer, så det hjelper ikkje ein forbrukarapp som følgjer med på tunnelen til nokon andre.
Kontroll 6: gjer feilen trygg og observerbar
Slå berre av den eigenskapen som treng tunnelen, og la resten av appen vere brukande. Ein detektor som skjuler heile grensesnittet kvar gong han er usikker, lagar eit avbrot for alle kvar tunnel brukar eit namn du aldri såg føre deg. Fall tilbake til den konservative åtferda i staden: lokale funksjonar held fram med å verke, og berre fjernkallet som verkeleg treng tunnelen, blir deaktivert. Det valet er ei produktavgjerd, og ho fortener å bli skriven ned ved sida av heuristikken.
Logg det du observerte: grensesnittnamn, plattformversjon og resultatet av éin probe. Det gjer den neste rapporten frå ein diskusjon til ein kontroll. Føretrekk deretter ein støtta erklæring der du har ein, fordi ein administrert konfigurasjon kan bere hensikta eksplisitt og fjerne mesteparten av grunnen til å inspisere namn i det heile.
Viss kontrollane 1 til 5 lét deg stå utan eit støtta svar, gje ut proben og merk resultatet ærleg. Eit dokumentert best-effort-signal er ei betre produktavgjerd enn eit privat API som bryt i neste utgiving.