Detectarea unui VPN activ într-o aplicație Mac sandboxată
Nu există un API public pentru această întrebare, iar trucul cu numele interfeței este doar o euristică. Șase verificări pentru a decide de ce ar trebui să depindă de fapt aplicația ta.
Ai nevoie de un ecran care să se comporte diferit când tunelul este activ și nu există niciun apel care să îți spună asta. Aceasta este constrângerea de livrare: pe macOS niciun framework public nu raportează dacă un VPN arbitrar este conectat, iar pe iOS starea aparține aplicației care a instalat configurația. Verificările de mai jos merg de la această limită la ceva ce poți livra, iar oricare dintre ele poate încheia căutarea mai devreme.
Verificarea 1: întrebarea are măcar răspuns?
Sandboxul rezolvă întrebarea înaintea oricărui API. Un proces terț nu poate enumera extensia altui furnizor și nu poate citi nici configurația acelei extensii, așa că nu există niciun obiect acceptat căruia să îi pui întrebarea.
Fiecare ocol lovește același zid. Listele de interfețe, scutil --nc list și citirile directe ale configurației sistemului fie cer drepturi pe care sandboxul le reține, fie depind de un comportament pe care Apple nu l-a promis niciodată. Dacă planul are nevoie de unul dintre acestea, problema este planul. O funcționalitate construită pe un detaliu nedocumentat este un tichet de suport cu dată de livrare.
Verificarea 2: aplicația ta administrează singură tunelul?
Dacă da, ai un răspuns acceptat pentru propria configurație. Încarcă preferințele, tratează eroarea, apoi citește starea și abonează-te la modificări în loc să faci interogări repetate:
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
}Fii precis cu privire la ce returnează asta: starea tunelului pe care l-ai instalat. Un utilizator care rulează alt client va apărea ca deconectat, iar asta nu este un defect în codul tău. Decide care dintre cele două întrebări este pusă de fapt de funcționalitatea ta înainte de a construi pe răspuns.
Verificarea 3: ce ți-ar spune de fapt o euristică?
Abordarea copiată pe scară largă cere dicționarului de proxy al sistemului intrările sale cu domeniu și citește cheile, care se întâmplă să fie nume de interfețe:
let settings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?
let scoped = settings?["__SCOPED__"] as? [String: Any]
let names = scoped?.keys ?? []O cheie care începe cu tap, tun, ppp, ipsec sau utun implică faptul că există o interfață cu domeniu de tunel. Potrivirea numelui complet eșuează imediat, pentru că iOS 12 a venit cu utun1 și utun2, iar unele profiluri apar ca ipsec4, ppp0 sau utun0. Compară prefixele în schimb.
Chiar și așa, un nume nu identifică niciun proprietar. Funcționalitățile sistemului și extensiile altor furnizori creează și ele interfețe utun, iar una poate exista fără să transporte nimic din traficul tău. Citește asta ca un indiciu că în apropiere există ceva în formă de tunel, nimic mai puternic. Un rezultat fals pozitiv este ieftin aici dacă limitezi o singură funcționalitate și scump dacă limitezi ecranul de autentificare.
Verificarea 4: poți testa în schimb destinația?
Dacă aplicația trebuie doar să știe dacă un serviciu intern este accesibil, testează acel serviciu. O sondă scurtă cu timeout răspunde la întrebarea de care depinde de fapt funcționalitatea și continuă să funcționeze când utilizatorul schimbă clientul sau tunelul își schimbă forma.
Accesibilitatea este o observație despre calea ta. Un nume de interfață este o inferență despre ceva adiacent căii tale, de aceea euristica produce dispute în rapoartele de erori, iar sonda produce dovezi. Dacă sonda eșuează în timp ce utilizatorul insistă că VPN-ul este pornit, ai acum o cale concretă de depanat: rezolvarea numelor, ruta sau permisiunea serviciului.
Verificarea 5: poate platforma să impună ce ai nevoie?
Când cerința este garanția că nimic nu scapă din tunel, profilul este locul potrivit, nu detectorul. Activarea includeAllNetworks într-o configurație de tunel complet pe iOS 14 sau mai nou schimbă comportamentul platformei în loc să ceară aplicației tale să îl deducă. Indicatorul este documentat în referința NEVPNProtocol.
Este un alt tip de răspuns: impunere în loc de observare. Se aplică, de asemenea, doar profilurilor pe care le controlezi, așa că nu ajută o aplicație de consum care urmărește tunelul altcuiva.
Verificarea 6: fă eșecul sigur și observabil
Oprește doar capacitatea care are nevoie de tunel și lasă restul aplicației utilizabil. Un detector care ascunde întreaga interfață ori de câte ori nu este sigur creează o întrerupere pentru oricine al cărui tunel folosește un nume la care nu te-ai așteptat niciodată. Revino la comportamentul conservator: funcționalitățile locale continuă să funcționeze și doar apelul de la distanță care are cu adevărat nevoie de tunel este dezactivat. Această alegere este o decizie de produs și merită să fie scrisă lângă euristică.
Înregistrează ce ai observat: nume de interfețe, versiunea platformei și rezultatul unei sonde. Asta transformă următorul raport dintr-o dispută într-o verificare. Apoi preferă o declarație acceptată atunci când o ai, pentru că o configurație administrată poate purta intenția explicit și poate elimina cea mai mare parte a motivului de a inspecta nume.
Dacă verificările de la 1 la 5 te-au lăsat fără un răspuns acceptat, livrează sonda și etichetează rezultatul cu onestitate. Un semnal documentat de efort maxim este o decizie de produs mai bună decât un API privat care se strică la următoarea versiune.