Detectar una VPN activa dins d'una app de Mac amb sandbox
No hi ha cap API pública per a aquesta pregunta, i el truc del nom d'interfície és només una heurística. Sis comprovacions per decidir de què ha de dependre realment la vostra app.
Necessiteu una pantalla que es comporti de manera diferent quan el túnel està actiu, i no hi ha cap crida que us ho digui. Aquesta és la restricció d'enviament: a macOS cap framework públic informa si una VPN arbitrària està connectada, i a iOS l'estat pertany a l'app que va instal·lar la configuració. Les comprovacions següents van d'aquest límit a alguna cosa que podeu enviar, i qualsevol d'elles pot acabar la recerca abans d'hora.
Comprovació 1: la pregunta té resposta, almenys?
El sandbox resol la pregunta abans que cap API. Un procés de tercers no pot enumerar l'extensió d'un altre fabricant ni pot llegir la configuració d'aquesta extensió, així que no hi ha cap objecte compatible a qui preguntar.
Tots els pedaços topen amb la mateixa paret. Els llistats d'interfícies, scutil --nc list i les lectures directes de la configuració del sistema o bé requereixen drets que el sandbox reté o bé depenen d'un comportament que Apple mai no va prometre. Si el pla necessita una d'aquestes coses, el problema és el pla. Una funcionalitat construïda sobre un detall no documentat és un tiquet de suport amb data d'entrega.
Comprovació 2: la vostra app gestiona el túnel ella mateixa?
Si ho fa, teniu una resposta compatible per a la vostra pròpia configuració. Carregueu les preferències, gestioneu l'error i després llegiu l'estat i subscriviu-vos als canvis en lloc de fer sondejos periòdics:
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
}Sigueu precisos sobre què retorna això: l'estat del túnel que heu instal·lat. Un usuari que executi un altre client apareixerà com a desconnectat, i això no és un error del vostre codi. Decidiu quina d'aquestes dues preguntes fa realment la vostra funcionalitat abans de construir sobre la resposta.
Comprovació 3: què us diria realment una heurística?
L'enfocament àmpliament copiat demana al diccionari de proxy del sistema les seves entrades amb abast i llegeix les claus, que resulten ser noms d'interfície:
let settings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?
let scoped = settings?["__SCOPED__"] as? [String: Any]
let names = scoped?.keys ?? []Una clau que comenci per tap, tun, ppp, ipsec o utun implica que hi ha una interfície amb abast de túnel. Fer coincidir el nom sencer falla de seguida, perquè iOS 12 va arribar amb utun1 i utun2 i alguns perfils es mostren com ipsec4, ppp0 o utun0. Compareu prefixos en lloc d'això.
Tot i així, un nom no identifica cap propietari. Les funcions del sistema i les extensions d'altres fabricants també creen interfícies utun, i una pot existir sense portar res del vostre trànsit. Llegiu-ho com un indici que hi ha alguna cosa amb forma de túnel a prop, res més fort. Un fals positiu aquí és barat si només condicioneu una funcionalitat, i car si condicioneu la pantalla d'inici de sessió.
Comprovació 4: podeu provar la destinació en lloc d'això?
Si l'app només necessita saber si un servei intern és abastable, proveu aquest servei. Una sonda curta amb temps d'espera respon la pregunta de la qual depèn realment la funcionalitat, i continua funcionant quan l'usuari canvia de client o el túnel canvia de forma.
L'abastabilitat és una observació sobre el vostre camí. Un nom d'interfície és una inferència sobre alguna cosa adjacent al vostre camí, i per això l'heurística produeix discussions als informes d'errors i la sonda produeix proves. Si la sonda falla mentre l'usuari insisteix que la VPN està activa, ara teniu un camí concret per depurar: resolució de noms, ruta o permís del servei.
Comprovació 5: la plataforma pot imposar el que necessiteu?
Quan el requisit és una garantia que res s'escapa del túnel, el perfil és on pertany, no el detector. Activar includeAllNetworks en una configuració de túnel complet a iOS 14 o posterior canvia el comportament de la plataforma en lloc de demanar a la vostra app que ho infereixi. L'indicador està documentat a la referència de NEVPNProtocol.
Aquesta és una mena de resposta diferent: imposició en lloc d'observació. A més, només s'aplica als perfils que controleu, així que no ajuda una app de consum que vigila el túnel d'una altra persona.
Comprovació 6: feu que el fracàs sigui segur i observable
Apagueu només la capacitat que necessita el túnel i deixeu la resta de l'app utilitzable. Un detector que amaga tota la interfície sempre que no està segur fabrica una caiguda per a qualsevol el túnel del qual faci servir un nom que no vau anticipar mai. Torneu en canvi al comportament conservador: les funcions locals continuen funcionant i només es desactiva la crida remota que realment necessita el túnel. Aquesta tria és una decisió de producte i mereix ser escrita al costat de l'heurística.
Registreu què heu observat: noms d'interfície, versió de la plataforma i el resultat d'una sonda. Això converteix el proper informe d'una discussió en una comprovació. Després preferiu una declaració compatible quan en tingueu una, perquè una configuració gestionada pot portar la intenció explícitament i eliminar la major part de la raó per inspeccionar noms.
Si les comprovacions de l'1 al 5 us han deixat sense una resposta compatible, envieu la sonda i etiqueteu el resultat amb honestedat. Un senyal documentat de millor esforç és una millor decisió de producte que una API privada que es trenca a la propera versió.