Detectar unha VPN activa dentro dunha app de Mac con sandbox
Non hai unha API pública para esta pregunta, e o truco do nome de interface é só unha heurística. Seis comprobacións para decidir de que debe depender realmente a túa app.
Necesitas que unha pantalla se comporte de forma distinta cando o túnel está activo, e non hai ningunha chamada que cho diga. Esa é a restrición de entrega: en macOS ningún framework público informa se unha VPN arbitraria está conectada, e en iOS o estado pertence á app que instalou a configuración. As comprobacións seguintes van dese límite a algo que podes entregar, e calquera delas pode rematar a busca antes de tempo.
Comprobación 1: a pregunta ten resposta sequera?
O sandbox resolve a pregunta antes que calquera API. Un proceso de terceiros non pode enumerar a extensión doutro fabricante nin pode ler a configuración desa extensión, así que non hai ningún obxecto compatible ao que preguntar.
Todos os rodeos chocan co mesmo muro. As listas de interfaces, scutil --nc list e as lecturas directas da configuración do sistema ou ben requiren dereitos que o sandbox retén ou ben dependen dun comportamento que Apple nunca prometeu. Se o plan necesita unha desas cousas, o problema é o plan. Unha función construída sobre un detalle non documentado é un ticket de soporte con data de entrega.
Comprobación 2: a túa app xestiona o túnel ela mesma?
Se o fai, tes unha resposta compatible para a túa propia configuración. Carga as preferencias, xestiona o erro e despois le o estado e subscríbete aos cambios en lugar de sondar:
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
}Sé preciso sobre o que devolve isto: o estado do túnel que instalaches. Un usuario que execute outro cliente aparecerá como desconectado, e iso non é un erro no teu código. Decide cal desas dúas preguntas formula realmente a túa función antes de construír sobre a resposta.
Comprobación 3: que che diría realmente unha heurística?
O enfoque amplamente copiado pide ao dicionario de proxy do sistema as súas entradas con ámbito e le as claves, que resultan ser nomes de interface:
let settings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as NSDictionary?
let scoped = settings?["__SCOPED__"] as? [String: Any]
let names = scoped?.keys ?? []Unha clave que comece por tap, tun, ppp, ipsec ou utun implica que hai presente unha interface con ámbito de túnel. Comparar o nome completo falla de inmediato, porque iOS 12 chegou con utun1 e utun2 e algúns perfís aparecen como ipsec4, ppp0 ou utun0. Compara prefixos no seu lugar.
Aínda así, un nome non identifica ningún propietario. As funcións do sistema e as extensións doutros fabricantes tamén crean interfaces utun, e unha pode existir sen levar nada do teu tráfico. Léra como unha pista de que hai algo con forma de túnel preto, nada máis forte. Un falso positivo aquí é barato se só condicionas unha función, e caro se condicionas a pantalla de inicio de sesión.
Comprobación 4: podes probar o destino no seu lugar?
Se a app só necesita saber se un servizo interno é alcanzable, proba ese servizo. Unha sonda curta con tempo de espera responde á pregunta da que depende realmente a función, e segue funcionando cando o usuario cambia de cliente ou o túnel cambia de forma.
A alcanzabilidade é unha observación sobre a túa ruta. Un nome de interface é unha inferencia sobre algo adxacente á túa ruta, e por iso a heurística produce discusións nos informes de erros e a sonda produce probas. Se a sonda falla mentres o usuario insiste en que a VPN está activa, agora tes unha ruta concreta que depurar: resolución de nomes, ruta ou permiso do servizo.
Comprobación 5: pode a plataforma impor o que necesitas?
Cando o requisito é a garantía de que nada escapa do túnel, o perfil é o seu sitio, non o detector. Activar includeAllNetworks nunha configuración de túnel completo en iOS 14 ou posterior cambia o comportamento da plataforma en lugar de pedirlle á túa app que o infira. O indicador está documentado en a referencia de NEVPNProtocol.
Esa é outra clase de resposta: imposición en lugar de observación. Ademais só se aplica a perfís que controlas, así que non axuda a unha app de consumo que vixía o túnel doutra persoa.
Comprobación 6: fai que o fallo sexa seguro e observable
Apaga só a capacidade que necesita o túnel e deixa o resto da app utilizábel. Un detector que esconde toda a interface cada vez que non está seguro fabrica unha caída para calquera cuxo túnel use un nome que nunca anticipaches. Volve máis ben ao comportamento conservador: as funcións locais seguen funcionando e só se desactiva a chamada remota que de verdade necesita o túnel. Esa elección é unha decisión de produto, e merece escribirse xunto á heurística.
Rexistra o que observaches: nomes de interface, versión da plataforma e o resultado dunha sonda. Iso converte o seguinte informe dunha discusión nunha comprobación. Despois prefire unha declaración compatible cando a teñas, porque unha configuración xestionada pode levar a intención de forma explícita e eliminar a maior parte da razón para inspeccionar nomes.
Se as comprobacións 1 a 5 te deixaron sen unha resposta compatible, entrega a sonda e etiqueta o resultado con honestidade. Un sinal documentado de mellor esforzo é unha mellor decisión de produto que unha API privada que se rompe na próxima versión.