VpnService protect() ou exclusión da app: que arranxa o encamiñamento
Protexa o socket que transporta o túnel ou exclúa toda a aplicación: as tres condicións que deciden que alcance necesita a súa VPN de Android.
Ten dúas formas de manter os paquetes do propio túnel fóra do túnel: protexer o socket de transporte ou sacar toda a aplicación da VPN. Resolven problemas distintos, e escoller a máis ampla porque é máis doada de conectar é xusto como as aplicacións perden o acceso á rede local e o DNS dividido sen decatarse. Comece polo que debe quedar fóra do túnel e logo escolla o alcance máis pequeno que o consegue.
Que quita protect() do túnel
VpnService.protect() é unha chamada por socket. Entrégalle o socket ou o descritor que transporta o túnel, e Android marca ese socket para que o seu tráfico use a rede subxacente en lugar da interface da VPN. Todo o demais que envía a aplicación segue a ruta normal da VPN.
Ese alcance estreito é a clave. Un socket protexido non cambia como o seu cliente HTTP resolve nomes, que interface usan as súas chamadas de analítica nin que ocorre cunha segunda conexión aberta máis tarde.
Tres condicións que deciden o alcance
A primeira condición é se só debe escapar o transporte do túnel. Se o resto do tráfico da aplicación debe seguir pasando pola VPN, a protección do socket é o alcance correcto. A segunda condición é se vostede controla a creación do socket. Unha biblioteca que abre o seu propio socket moi dentro non lle deixa onde chamar a protect() salvo que expoña un hook ou acepte un socket xa construído. A terceira condición é se a aplicación debe chegar directamente á rede local ou a un captive portal, o que é un requisito distinto de manter vivo o túnel.
Excluír a aplicación con addDisallowedApplication() é a ferramenta tosca. Saca da VPN cada conexión que fai a aplicación, incluídas as que quería inspeccionar, e nalgúns dispositivos tamén cambia como se comporta o descubrimento local.
Unha terceira opción é atar o transporte a unha rede elixida con bindProcessToNetwork() ou cun identificador de rede a nivel de socket. Iso é útil cando o dispositivo ten Wi-Fi e móbil á vez e quere que o túnel vaia por unha ligazón de subida concreta.
Chámeo mentres se crea o transporte
Chame a protect() no mesmo bloque que crea o transporte, antes de connect() ou send(). Se a chamada devolve false, peche o socket e faga fallar a configuración; continuar déixalle un transporte cuxos paquetes poden volver entrar na súa propia interface.
A forma é o bastante pequena para tela nun só sitio:
DatagramSocket transport = new DatagramSocket();
if (!protect(transport)) {
transport.close();
throw new IOException("transport not protected");
}
transport.connect(serverAddress);Tres detalles morden aquí. Primeiro,o booleano é o único sinal que recibe, así que rexistre o fallo con contexto suficiente para distinguir un consentimento revogado dunha chamada rexeitada. Segundo,protect() cobre o socket, non o número de descritor: se pecha o socket e máis tarde reutiliza o mesmo enteiro para outro socket, o novo socket non queda protexido. Terceiro, cando unha biblioteca nativa abre o transporte, protexa o descritor antes de que o código nativo se conecte, ou a ruta pode estar xa elixida.A referencia de VpnService é o lugar onde confirmar que sobrecargas ofrece realmente o seu nivel de API obxectivo.
Probe a ruta bloqueada, non só a ruta feliz
Verifique co túnel levantado, porque é o único estado no que os dous camiños poden diferir. Envíe unha petición polo transporte protexido e outra desde unha ruta de código que nunca chamou a protect(), e despois compare o que ve o extremo remoto: a conexión protexida debería chegar coa rede subxacente como orixe, mentres que a non protexida mostra o enderezo propio do túnel e move os seus contadores de bytes. No dispositivo,ss ou netstat mostra a mesma división antes de que nada saia da radio.
Probe a revogación por separado, porque un cambio de consentimento derruba a interface sen tocar o seu código de socket. Revogue o consentimento da VPN ou deteña o servizo, reconstrua o transporte e confirme que protect() segue devolvendo true e que o transporte se reconecta en canto se volve conceder o consentimento.
Se a petición protexida segue o túnel de todos os xeitos, a chamada de protección probablemente ocorre despois de que o socket xa se encamiñase. Móvaa antes e volva probar.
Manteña a decisión escrita xunto á configuración do transporte: que sockets están protexidos, que tráfico da aplicación está excluído e que fai a aplicación cando falla a protección. Esa liña é o que impide que unha refactorización posterior amplíe a exclusión a toda a aplicación porque unha soa proba fallaba. Tamén lle dá á seguinte persoa unha forma de comprobar a intención sen enxeñería inversa do manifesto.