O túnel dividido nunha aplicación VpnService rompe en poucos puntos concretos, e a reparación é distinta en cada un. O cliente só amosa un destino que falla, así que a primeira tarefa é descubrir contra que límite chocas: as rutas que recibiu o builder, o proxy que non podes autenticar, o resolver que só anunciaches ou a lista de aplicacións que a plataforma aplica por usuario. Por iso manteño unha comprobación de catro pasos. Execútase na orde de abaixo e detense no primeiro fallo.

Confirma que lle entregou o builder á plataforma

VpnService.Builder é unha lista de declaracións. establish() devolve un ParcelFileDescriptor para unha interface virtual, e a plataforma só envía a ese descritor o tráfico que coincide cos prefixos de addAddress e addRoute; addDnsServer indica aos clientes que resolver deben consultar. Un destino fóra de todos os prefixos que engadiches nunca chega á túa aplicación, diga o que diga a interface. Ese único feito explica a maioría dos informes de túnel dividido roto antes de tocar código.

Rexistra as listas de enderezos, rutas e DNS que montou o teu builder e compáraas cos destinos que fallan. Un /32 ausente para un host de xestión é moito máis habitual que un túnel roto. Se a lista é correcta, segue adiante; se non o é, o resto da lista de comprobación é esforzo perdido.

excludeRoute só existe desde a API 33

A exclusión por destino é a petición que máis veces acaba nun fío de soporte. builder.excludeRoute(IpPrefix) chegou na API 33; antes, a única aproximación admitida é engadir rutas para todo menos o prefixo excluído, o que obriga a calcular ti mesmo os prefixos complementarios. As dúas chamadas non son imaxes especulares: unha resta do conxunto de rutas da interface, a outra constrúe o conxunto desde cero, e un dispositivo antigo lanzará ou ignorará en silencio unha chamada que non recoñece. Ramifica segundo Build.VERSION.SDK_INT e proba ambos os camiños en hardware real.

Cando calcules complementos, vixía a aliñación dos prefixos. Unha exclusión /24 dentro dunha ruta /16 necesita os prefixos de cobertura que describen de verdade o resto, non un /8 mal formado. Rexistra a lista final e comproba que o host excluído aínda se resolve por un camiño fóra do túnel.

As credenciais do proxy non se poden expresar

setHttpProxy(ProxyInfo) apunta a interface a un proxy HTTP ou SOCKS, e unha URL PAC pode escoller entre ambos por destino. Nin ProxyInfo nin o formato PAC levan usuario e contrasinal, así que un proxy autenticado queda fóra da API da plataforma. As aplicacións que o necesitan adoitan incrustar unha pila de espazo de usuario, tun2socks ou un motor similar, e responden elas mesmas ao reto 407.

Esa decisión ten consecuencias. Unha pila de espazo de usuario só ve o tráfico que encamiñas cara a ela, así que debe vivir dentro do mesmo límite do descritor, e herda o mesmo requisito de protect() para o seu propio socket de subida. Se prescindes de protect(), o túnel captura o seu propio transporte, o que aparece como un handshake que se atasca tras o primeiro paquete. Proba contra un proxy que esixa credenciais, porque un proxy aberto pasa polo camiño da plataforma e non demostra nada.

As listas por aplicación e o DNS tamén son declaracións

Builder ten addAllowedApplication e addDisallowedApplication, e son mutuamente excluíntes: chamar a ambos lanza unha excepción. En calquera caso a lista aplícase por usuario ao configurar a interface, así que unha aplicación do perfil de traballo réxese polo túnel do perfil de traballo e non polo teu. O que ningunha API che dá é control sobre a decisión doutra aplicación: non podes forzar un paquete cara ao teu túnel desde fóra nin pechar ou reconfigurar unha VPN xa activa.

O DNS segue o mesmo patrón. addDnsServer anuncia un enderezo de resolver; non permite que a túa aplicación responda consultas. Se queres resolver nomes ti mesmo, executa un resolver e encamiña o seu enderezo ao túnel. As aplicacións que usan DoT ou DoH cara a un nome de host fixo poden saltarse o enderezo que anunciaches, así que trata a resolución de nomes como mellor esforzo salvo que tamén interceptes o camiño da consulta.

Manifesto, always-on e a proba de catro pasos

A elegibilidade declárase no manifesto: BIND_VPN_SERVICE, o filtro de intents android.net.VpnService e un servizo en primeiro plano se o túnel debe sobrevivir en segundo plano. Always-on VPN ademais esixe un onRevoke limpo, porque o sistema chámao cando o usuario cambia axustes ou outra aplicación toma o control.

Executa as comprobacións en orde e detente no primeiro fallo. Primeiro, volca as listas de enderezos, rutas e DNS que recibiu o builder. Segundo, confirma que establish() devolveu un descritor e que o socket de transporte está protexido. Terceiro, pide un destino dentro dun prefixo incluído e outro dentro dun prefixo excluído. Cuarto, comproba que resolver respondeu de verdade consultando un nome de host que só o teu resolver pode resolver.

Un handshake completado non demostra ningún dos pasos posteriores. Cada comprobación illa unha capa, así que un éxito no segundo paso non di nada sobre o cuarto.

A referencia de VpnService.Builder enumera toda a superficie do builder. Todo o que necesites máis aló é outra API, outra aplicación ou a túa propia pila de espazo de usuario, e iso é unha decisión de deseño, non un fallo do túnel dividido.

Artigos relacionados