VPN con chroot en Android: por qué el túnel funciona y las apps lo ignoran
chroot cambia la resolución de rutas, no el núcleo, el espacio de nombres de red ni el registro de VPN de Android. De ahí salen dos resultados y ambos sorprenden.
Instalas una distribución Linux dentro de un chroot en el teléfono, pones un cliente VPN y la shell anuncia un túnel completado. Luego abres el navegador y el tráfico sale por datos móviles como si nada hubiera pasado. O al revés: todas las apps pierden conexión porque el cliente añadió una ruta por defecto en el espacio de nombres que Android usa de verdad. Ambos síntomas vienen de la misma pieza ausente y ninguno es un fallo del cliente VPN.
La shell dice conectado, las apps no están de acuerdo
El primer resultado es el habitual. Un túnel de espacio de usuario abierto desde un chroot puede completar su handshake, imprimir sus estadísticas y llevar el tráfico que genera la misma shell, mientras las apps de Android siguen usando la red por defecto del teléfono. Nada las intercepta, porque nada le dijo a Android que existe una VPN.
El segundo resultado es el peligroso. Si el chroot comparte el espacio de nombres de red de Android, que es lo que pasa por defecto, un proceso con privilegios suficientes puede añadir rutas y una interfaz TUN que afectan a todo el teléfono. Entonces el túnel funciona para todas las apps, incluidas las que no querías enrutar, y la conectividad depende ahora de un demonio sin gestión de ciclo de vida, sin indicador de conexión y sin política de siempre activo.
Cuál de los dos obtuviste se responde con una orden. Compara ip route dentro del chroot con la misma orden desde una shell de Android fuera. Una salida idéntica significa que el chroot está en el espacio de nombres del host: cualquier cambio de red que haga es para todo el teléfono. Una salida distinta significa que el lanzador creó un espacio de nombres para él y su túnel es invisible para Android por construcción.
Qué cambió el chroot y qué no
| Object | Effect of a chroot |
|---|---|
| Pathname resolution | Changed: lookups start at the new root |
| Kernel and drivers | Unchanged: the phone's kernel, its TUN driver, its limits |
| Network namespace | Unchanged unless the launcher creates one |
| Android VPN registration | Unchanged: no app consented, no VPN is selected |
La llamada al sistema chroot hace una cosa: cambia el directorio usado para resolver rutas. La página de manual dice claramente que no es una frontera de seguridad y no dice nada de interfaces, rutas ni estado de VPN. Todo lo que la gente espera de un contenedor Linux — una pila de red privada, un sistema de archivos filtrado, límites de recursos — viene de otros mecanismos que el lanzador puede o no haber usado.
Por eso las afirmaciones de que un chroot aísla una VPN suelen responder a la pregunta equivocada. La pregunta relevante es en qué espacio de nombres corre el proceso y en qué dominio SELinux está confinado, y ambas son propiedades de cómo se inició, no de la palabra chroot.
TUN necesita tres cosas y el nodo de dispositivo es solo una
Un túnel tradicional de espacio de usuario necesita un dispositivo TUN que pueda abrir, soporte del núcleo para ese dispositivo y permiso para configurar la interfaz y las rutas. Son requisitos separados y crear un nombre de ruta bajo /dev no satisface ninguno por sí solo:
ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun
En Android el núcleo suele llevar el soporte TUN compilado, porque lo usa el propio servicio VPN de la plataforma, pero eso no significa que tu proceso pueda usarlo. Configurar la interfaz requiere la capacidad de administración de red y SELinux decide si el proceso puede llegar siquiera al nodo del dispositivo. Una denegación parece un error de permisos sin causa obvia y la respuesta está en el rastro de auditoría:
dmesg | grep avc
logcat -d | grep "avc: denied"
Root no lo resuelve. SELinux restringe los procesos con uid 0 igual que a los demás, así que un chroot iniciado desde una shell root puede seguir recibiendo una denegación por un dispositivo que ve. Desactivar la aplicación forzosa para que funcione un instalador viejo es una decisión para todo el teléfono con consecuencias mucho más allá del túnel y no es la solución para un binario obsoleto.
Por qué las apps de Android ignoran tu túnel
El modelo admitido de Android es una app VPN que se registra en el servicio VPN de la plataforma, pide consentimiento una vez y recibe un descriptor de archivo para su túnel. Luego la plataforma encamina el tráfico a ese descriptor y aplica el ámbito de apps que eligió el usuario o el administrador, por eso el mismo mecanismo puede ser por app, por perfil y combinarse con siempre activo y bloqueo sin VPN. La guía de desarrollo de VPN de Android describe ese handshake y la clave es que es un registro, no un truco de encaminamiento.
Un demonio dentro de un chroot nunca se registra. No hay diálogo de consentimiento, ni icono de llave en la barra de estado, ni lista de inclusión o exclusión por app, ni participación en la política de siempre activo. Por eso las apps siguen usando la red por defecto y el túnel solo lleva lo que envía la propia shell.
La otra dirección tampoco ayuda. Empujar rutas al espacio de nombres del host lo captura todo, incluido tráfico que la plataforma esperaba mantener local, y lo hace sin control por app y sin forma de que el usuario lo vea o lo revoque. No hay ajuste intermedio donde un demonio en chroot enrute el tráfico de una sola app.
La compatibilidad binaria es un muro aparte
Aunque el lado de red sea interesante, el ejecutable tiene sus requisitos: arquitectura de CPU, cargador dinámico, biblioteca C y las capacidades del núcleo que espera. Android usa bionic y no glibc, y un binario antiguo compilado para una distribución de escritorio puede necesitar bibliotecas que ya no existen en el dispositivo.
Enlazar el nombre de una biblioteca a una versión más nueva no crea compatibilidad ABI, y una biblioteca criptográfica archivada de un paquete de hace diez años no es un componente mantenido. Si el plan depende de eso, el plan es ejecutar código sin mantenimiento con privilegios de red en un teléfono.
Demuéstralo en el contexto de Android y limpia después
Prueba lo que de verdad te importa, desde el lado que importa: abre la app concreta, llega al destino privado concreto, confirma qué resolver respondió, luego desconecta el túnel y confirma el comportamiento documentado. Un resultado de un terminal dentro del chroot es evidencia sobre el contexto de ejecución de ese terminal y nada más.
Si cambiaste rutas del host durante el experimento, revuértelas y anota qué cambiaste. Luego comprueba si el teléfono tiene una VPN de siempre activo configurada, porque un experimento antiguo que dejó una regla puede parecer un fallo de la plataforma meses después.
Para una necesidad real de acceso remoto, usa el cliente admitido del servicio o un diseño de puerta de enlace aprobado. La pregunta que merece la pena no es si se puede hacer funcionar un instalador con root, sino si una implementación admitida lleva las apps que necesitas cruzar la frontera que pretendías, sin dejar cambios privilegiados sin dueño en el dispositivo.