VPN en Android sin root: quién posee el consentimiento, las rutas y el bloqueo
El consentimiento, la interfaz TUN y la política de bloqueo del sistema son tres permisos distintos. Rastrea qué componente posee cada uno antes de revisar una aplicación VPN de Android.
El root no es lo que permite que una aplicación VPN de Android transporte tráfico, bloquee fugas o sobreviva a un reinicio. La gente resume todo eso como «la aplicación tiene permiso de VPN», lo que oculta tres mecanismos separados: un consentimiento otorgado por el usuario, una interfaz de paquetes que establece el sistema y una política de bloqueo de la plataforma que no corresponde a la aplicación definir. Revisar un diseño de VPN de Android significa preguntar en cuál de los tres se apoya realmente una afirmación, porque cada uno tiene un propietario y un modo de fallo distintos.
El consentimiento llega mediante una actividad del sistema
VpnService.prepare() no concede nada. Devuelve un intent a la actividad de consentimiento del sistema cuando falta el consentimiento, y la aplicación lanza ese diálogo para que el usuario apruebe el servicio. Iniciar el propio proceso de la aplicación, añadir un permiso al manifiesto o mostrar una pantalla personalizada de «activar VPN» no crea la concesión.
La concesión también tiene alcance. Pertenece a un paquete dentro de un perfil de usuario, así que la copia personal y la copia de trabajo son decisiones separadas, y el propietario de un dispositivo puede preparar un perfil gestionado de forma distinta a uno personal. Si el diálogo nunca aparece y prepare() devuelve null, el consentimiento ya existe para ese paquete en ese perfil; no es prueba de que la aplicación sea fiable, solo de que la concesión está en su lugar.
La interfaz es una petición que el sistema cumple
Tras el consentimiento, la aplicación describe lo que quiere con VpnService.Builder: direcciones, rutas, servidores DNS, MTU y, donde se admite, las aplicaciones que se incluyen o excluyen. establish() pide al sistema que cree la interfaz de túnel y enrute hacia ella el tráfico correspondiente. El sistema posee la decisión de enrutamiento; la aplicación recibe el descriptor de archivo y entonces debe hacer algo útil con los paquetes.
| What you observe | Who actually owns it |
|---|---|
| VPN consent dialog | The system, triggered by prepare() |
| Routes, DNS and app lists | The app requests them; the system applies them |
| One active VPN per profile | The platform; a new service replaces the old one |
| Always-on and block-without-VPN | Device policy enforced by the platform |
Esa tabla es la arquitectura en un solo lugar. La aplicación participa en el manejo de paquetes; no posee la interfaz, la tabla de enrutamiento ni el número de servicios que pueden ejecutarse.
El socket del túnel tiene que escapar de su propio túnel
La conexión que transporta el tráfico cifrado es ella misma un socket. Si se enruta de vuelta a la interfaz que la aplicación acaba de crear, el túnel depende del túnel y se atasca. VpnService.protect() vincula ese socket a la red subyacente para que evite la captura, y por eso un cliente correcto protege su socket exterior antes del primer apretón de manos.
adb shell dumpsys connectivity | grep -i -A5 vpn
adb shell settings get global always_on_vpn_app
adb shell settings get global always_on_vpn_lockdown
Estos comandos muestran la red VPN instalada, el paquete de activación permanente y si el bloqueo está configurado. Son observaciones de solo lectura: si los valores no coinciden con lo que afirma el diseño, la afirmación es sobre la interfaz de la aplicación y no sobre el estado del sistema.
El bloqueo puede pertenecer a la plataforma
Android documenta una política que bloquea las conexiones que no usan la VPN. Esa aplicación es un contrato de la plataforma, no una aplicación que reintenta conexiones en bucle. El interruptor está en los ajustes de VPN del dispositivo como Bloquear conexiones sin VPN, y en un dispositivo gestionado el propietario puede activarlo para todo el perfil. La distinción importa cuando evalúas una afirmación de marketing: un cliente puede mostrar un icono de candado y reconectar con agresividad mientras el tráfico directo sigue siendo posible, o las aplicaciones cubiertas pueden quedarse sin conexión porque el sistema aplica el bloqueo.
El icono de candado lo dibuja la aplicación, así que solo demuestra que la aplicación cree que está conectada. Si otra aplicación pierde su acceso a la red lo decide la plataforma, así que la comprobación útil es ver fallar a esa aplicación con el túnel activo.
La etiqueta «siempre activo» de la tienda de aplicaciones tampoco sustituye ese contrato. La activación permanente y el bloqueo son ajustes del dispositivo, a menudo aplicados por su propietario, y su comportamiento para las aplicaciones excluidas lo define la plataforma. Lee el ajuste, no la insignia.
Cuatro preguntas para una revisión de diseño
Primero, quién consintió: qué paquete, qué perfil y si fue el usuario o una política de dispositivo gestionado. Segundo, qué pidió la aplicación: qué rutas, qué familias de direcciones, qué aplicaciones incluidas o excluidas. Tercero, qué ocurre cuando el túnel no está disponible: ¿bloquea el sistema o el tráfico recurre a la red subyacente? Cuarto, qué hace la aplicación con los paquetes que recibe.
La cuarta pregunta es la que el modelo de permisos no puede responder. El consentimiento y una interfaz TUN demuestran que la aplicación puede recibir tráfico, no que lo cifre, autentique a un par o se recupere limpiamente. Son propiedades de implementación, y ahí es donde una revisión honesta pasa su tiempo.
Una petición de root innecesaria no se vuelve legítima por llamar al resultado interruptor de emergencia, y un diálogo de consentimiento no es una auditoría de seguridad. Mantén las tres concesiones separadas y cada afirmación se vuelve comprobable.