Android ofrece APIs para que los desarrolladores creen redes privadas virtuales (VPN) de Google Cloud. Después de leer esta guía, sabrás cómo desarrollar y probar tu propio cliente de VPN para dispositivos con Android.
Descripción general
Las VPN permiten que los dispositivos que no se encuentran físicamente en una red accedan de forma segura a la en cada red.
Android incluye un cliente de VPN integrado (PPTP y L2TP/IPSec), que a veces llamada VPN heredada. Android 4.0 (nivel de API 14) introdujo APIs para que la los desarrolladores pueden proporcionar sus propias soluciones de VPN. Empaquetas tu solución de VPN en una app que las personas instalan en el dispositivo. Los desarrolladores suelen crear una VPN app por uno de los siguientes motivos:
- Ofrecer protocolos de VPN que el cliente integrado no admite
- Ayudar a las personas a conectarse a un servicio VPN sin una configuración compleja
El resto de esta guía explica cómo desarrollar apps de VPN (incluido VPN siempre activada y por app) y no incluye la un cliente de VPN integrado.
Experiencia del usuario
Android proporciona una interfaz de usuario (IU) para ayudar a alguien a configurar, iniciar para detener tu solución de VPN. La IU del sistema también hace que la persona que usa el dispositivo de una conexión VPN activa. Android muestra los siguientes componentes de IU para Conexiones VPN:
- Antes de que una app de VPN pueda activarse por primera vez, el sistema muestra Cuadro de diálogo de solicitud de conexión. El diálogo solicita a la persona que usa el dispositivo que confirmar que confía en la VPN y aceptar la solicitud.
- La pantalla de configuración de VPN (Configuración > Internet y redes > VPN) muestra la VPN aplicaciones en las que una persona acepta solicitudes de conexión. Hay un botón para configurar del sistema u olvidar la VPN.
- La bandeja de Configuración rápida muestra un panel de información cuando hay una conexión activo. Al presionar la etiqueta, se muestra un diálogo con más información y un vínculo a Configuración.
- La barra de estado incluye un ícono de VPN (clave) para indicar una conexión activa.
Tu app también debe proporcionar una IU para que la persona que usa el dispositivo pueda configurar las opciones de tu servicio. Por ejemplo, tu solución podría necesitar capturar la configuración de autenticación de la cuenta. Las apps deben mostrar las siguientes IU:
- Controles para iniciar y detener manualmente una conexión. VPN siempre activada pueden conectarse cuando sea necesario, pero permiten que las personas configuren la conexión la primera cada vez que usan la VPN.
- Una notificación no descartable cuando el servicio está activo. La notificación solo puede mostrar el estado de la conexión o proporcionar más información, como estadísticas de la red. Si presionas la notificación, tu app se abre en primer plano. Quita el después de que el servicio se vuelve inactivo.
Servicio de VPN
Tu app conecta las redes del sistema para un usuario (o una página
) a una puerta de enlace de VPN. Cada usuario (o perfil de trabajo) puede ejecutar una
otra app de VPN. Creas un servicio VPN que el sistema usa para iniciar y
detener la VPN y hacer un seguimiento del estado de conexión. Tu servicio VPN hereda de
VpnService
El servicio también actúa como tu contenedor para las conexiones de puerta de enlace VPN y
y sus interfaces de dispositivos locales. La llamada de tu instancia de servicio
VpnService.Builder
para establecer una nueva interfaz local
Tu app transfiere los siguientes datos para conectar el dispositivo a la puerta de enlace VPN:
- Lee paquetes IP salientes del descriptor de archivos de la interfaz local, encripta los envía a la puerta de enlace de VPN.
- Escribe los paquetes entrantes (recibidos y desencriptados de la puerta de enlace VPN) en la descriptor de archivo de la interfaz local.
Solo hay un servicio activo por usuario o perfil. Cuando se inicia un nuevo servicio, detiene automáticamente un servicio existente.
Agrega un servicio
Para agregar un servicio de VPN a tu app, crea un servicio de Android que herede de
VpnService
Declara el servicio de VPN en tu app
de manifiesto con las siguientes adiciones:
- Protege el servicio con las
BIND_VPN_SERVICE
permiso para que solo el sistema pueda vincularse con tu servicio. - Publicita el servicio con el filtro de intents
"android.net.VpnService"
para que el sistema pueda encontrar tu servicio.
En este ejemplo, se muestra cómo puedes declarar el servicio en el archivo de manifiesto de tu app:
<service android:name=".MyVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
Ahora que tu app declara el servicio, el sistema puede iniciar y detener el servicio de VPN de tu app cuando sea necesario. Por ejemplo, el sistema controla tu servicio cuando ejecutas la VPN siempre activada.
Prepara un servicio
Si quieres preparar la app para que se convierta en el servicio VPN actual del usuario, llama a
VpnService.prepare()
Si la persona que usa el dispositivo no
permiso para tu app, el método devuelve un intent de actividad.
Usa ese intent para iniciar una actividad del sistema que solicita permiso. El
muestra un diálogo similar a otros diálogos de permisos, como
acceso a la cámara o a los contactos. Si tu app ya está preparada, el método devuelve
null
Solo una app puede ser el servicio VPN preparado actual. Llamar siempre
VpnService.prepare()
porque una persona podría haber configurado un
app como el servicio de VPN desde la última vez que tu app llamó al método. Para obtener más información, consulta
la sección Ciclo de vida del servicio.
Conecta un servicio
Cuando se ejecuta el servicio, puede establecer una nueva interfaz local conectadas a una puerta de enlace de VPN. Para solicitar permiso y conectarse a tu servicio, sigue estos pasos: la puerta de enlace de VPN, debes completar los pasos en el siguiente orden:
- Llama a
VpnService.prepare()
para solicitar permiso (cuando necesario). - Llama a
VpnService.protect()
para mantener el socket de túnel de tu app. fuera de la VPN del sistema y evitar una conexión circular. - Llama a
DatagramSocket.connect()
para conectar el túnel de tu app. a la puerta de enlace de VPN. - Llama a los métodos
VpnService.Builder
para configurar un nuevo entorno local. interfaz TUN en la dispositivo para el tráfico de VPN. - Llama a
VpnService.Builder.establish()
para que el sistema establece la interfaz TUN local y comienza a enrutar el tráfico a través del interfaz de usuario.
Una puerta de enlace de VPN suele sugerir configuraciones para la interfaz TUN local durante
el protocolo de enlace. Tu app llama a los métodos VpnService.Builder
para configurar una
servicio, como se muestra en el siguiente ejemplo:
Kotlin
// Configure a new interface from our VpnService instance. This must be done // from inside a VpnService. val builder = Builder() // Create a local TUN interface using predetermined addresses. In your app, // you typically use values returned from the VPN gateway during handshaking. val localTunnel = builder .addAddress("192.168.2.2", 24) .addRoute("0.0.0.0", 0) .addDnsServer("192.168.1.1") .establish()
Java
// Configure a new interface from our VpnService instance. This must be done // from inside a VpnService. VpnService.Builder builder = new VpnService.Builder(); // Create a local TUN interface using predetermined addresses. In your app, // you typically use values returned from the VPN gateway during handshaking. ParcelFileDescriptor localTunnel = builder .addAddress("192.168.2.2", 24) .addRoute("0.0.0.0", 0) .addDnsServer("192.168.1.1") .establish();
El ejemplo de la sección VPN por app muestra una configuración de IPv6 que incluye
más opciones. Debes agregar los siguientes valores de VpnService.Builder
antes de establecer una nueva interfaz:
addAddress()
- Agrega al menos una dirección IPv4 o IPv6 junto con una máscara de subred que el sistema asigna como la dirección local de la interfaz TUN. Por lo general, tu app recibe la IP y máscaras de subred de una puerta de enlace de VPN durante el protocolo de enlace.
addRoute()
- Agrega al menos una ruta si deseas que el sistema envíe tráfico a través de la VPN
interfaz de usuario. Las rutas filtran por direcciones de destino. Para aceptar todo el tráfico, establece una
ruta abierta, como
0.0.0.0/0
o::/0
.
El método establish()
devuelve un
Instancia ParcelFileDescriptor
que usa tu app para leer y escribir
paquetes desde y hacia el búfer de la interfaz. La establish()
muestra null
si tu app no está preparada o si alguien revoca la
permiso.
Ciclo de vida del servicio
Tu app debe hacer un seguimiento del estado de la VPN seleccionada del sistema y de cualquier conexiones de red. Actualiza la interfaz de usuario (IU) de tu aplicación para que la persona siga usando la de que el dispositivo esté al tanto de los cambios.
Cómo iniciar un servicio
Tu servicio VPN se puede iniciar de las siguientes maneras:
- Tu app inicia el servicio, normalmente porque una persona presionó un botón de conexión.
- El sistema inicia el servicio porque la VPN siempre activada está encendida.
Tu app inicia el servicio VPN pasando un intent a
startService()
Para obtener más información, consulta Cómo iniciar un
servicio.
El sistema inicia tu servicio en segundo plano llamando
onStartCommand()
Sin embargo, Android impone restricciones en
en segundo plano en la versión 8.0 (nivel de API 26) o versiones posteriores. Si admites estas
niveles de API, debes realizar la transición de tu servicio al primer plano llamando
Service.startForeground()
Para obtener más información, lee Ejecutar un
servicio en primer plano.
Cómo detener un servicio
Una persona que usa el dispositivo puede detener su servicio usando la IU de tu app. Detén el en lugar de solo cerrar la conexión. El sistema también detiene una instancia cuando la persona que usa el dispositivo hace lo siguiente en la pantalla de VPN de la app de Configuración:
- desconecta la app de VPN o se olvida de ella
- apaga la VPN siempre activada para una conexión activa
El sistema llama al método onRevoke()
de tu servicio, pero esta llamada
podría no ocurrir en el subproceso principal. Cuando el sistema llama a este método, se
o una interfaz de red alternativa
ya está enrutando el tráfico. Puedes desecharlos de manera segura
de los siguientes recursos:
- Cierra el socket del túnel protegido a la puerta de enlace de VPN mediante una llamada
DatagramSocket.close()
- Cierra el descriptor de archivos de parcela (no es necesario que lo vacíes) llamando a
ParcelFileDescriptor.close()
VPN siempre activada
Android puede iniciar un servicio de VPN cuando se inicia el dispositivo y mantenerlo en ejecución mientras que el dispositivo esté encendido. Esta función se llama VPN siempre activada y está disponible en Android 7.0 (nivel de API 24) o una versión posterior Mientras Android mantiene el servicio ciclo de vida, es tu servicio de VPN responsable de las conexiones conexión. La función de VPN siempre activada también puede bloquear las conexiones que no usan la VPN.
Experiencia del usuario
En Android 8.0 o versiones posteriores, el sistema muestra los siguientes diálogos para realizar la por persona que usa la VPN siempre activada en el dispositivo:
- Cuando las conexiones VPN siempre activadas se desconectan o no se pueden conectar, las personas verán un notificación que no se puede descartar. Cuando se presiona la notificación, aparece un diálogo explica más. La notificación desaparece cuando la VPN se vuelve a conectar o desactiva la opción VPN siempre activada.
- La VPN siempre activada permite que la persona que usa un dispositivo bloquee cualquier red conexiones que no usan la VPN. Si activas esta opción, la Configuración app advierte a las personas que no tienen conexión a Internet antes de que la VPN se conecta. La app de Configuración solicita a la persona que usa el dispositivo que continúe. cancelar.
Como el sistema (y no una persona) inicia y detiene una conexión siempre activa, debes adaptar el comportamiento y la interfaz de usuario de tu aplicación:
- Inhabilitar cualquier IU que desconecte la conexión porque el sistema y la Configuración la app controlan la conexión.
- Guarda cualquier configuración entre cada inicio de la app y configura una conexión con el la configuración más reciente. Como el sistema inicia tu app a pedido, la persona usando el dispositivo podría no siempre querer configurar una conexión.
También puedes usar parámetros de configuración administrados para establecer una conexión. Las configuraciones administradas ayudan a un administrador de TI a configurar tu VPN de forma remota.
Detección de la función siempre activada
Android no incluye APIs para confirmar si el sistema inició tu VPN. servicio. Sin embargo, cuando tu app marca cualquier instancia de servicio que inicia, puedes suponer que que el sistema inició servicios sin marcar para VPN siempre activa. Veamos un ejemplo:
- Crea una instancia
Intent
para iniciar el servicio VPN. - Marca el servicio VPN poniendo un servicio adicional en el intent.
- En el método
onStartCommand()
del servicio, busca la marca en los extras del argumentointent
.
Conexiones bloqueadas
Una persona que usa el dispositivo (o un administrador de TI) puede forzar todo el tráfico para que use la VPN. El sistema bloquea cualquier tráfico de red que no use la VPN. Personas que utilizan el el dispositivo puede encontrar el interruptor Bloquear conexiones sin VPN en las opciones de VPN en Configuración.
Inhabilita la función siempre activada
Si tu app no es compatible actualmente con la VPN siempre activa, puedes inhabilitarla (en Android
8.1 o una versión posterior) estableciendo el
SERVICE_META_DATA_SUPPORTS_ALWAYS_ON
metadatos del servicio a false
. En el siguiente ejemplo de manifiesto de la app, se muestra cómo agregar
el elemento de metadatos:
<service android:name=".MyVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
<meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
android:value=false/>
</service>
Cuando tu app inhabilita la VPN siempre activada, el sistema inhabilita la IU de opciones controles en Configuración.
VPN por app
Las aplicaciones de VPN pueden filtrar qué aplicaciones instaladas tienen permitido enviar tráfico a través del una conexión de VPN. Puedes crear una lista permitida o una lista no permitida pero no ambas. Si no creas listas permitidas o no permitidas, el sistema todo el tráfico de red a través de la VPN.
Tu app de VPN debe configurar las listas antes de establecer la conexión. Si si necesitas cambiar las listas y establecer una nueva conexión VPN. Una app debe tener las siguientes características: instalada en el dispositivo cuando lo agregues a una lista.
Kotlin
// The apps that will have access to the VPN. val appPackages = arrayOf( "com.android.chrome", "com.google.android.youtube", "com.example.a.missing.app") // Loop through the app packages in the array and confirm that the app is // installed before adding the app to the allowed list. val builder = Builder() for (appPackage in appPackages) { try { packageManager.getPackageInfo(appPackage, 0) builder.addAllowedApplication(appPackage) } catch (e: PackageManager.NameNotFoundException) { // The app isn't installed. } } // Complete the VPN interface config. val localTunnel = builder .addAddress("2001:db8::1", 64) .addRoute("::", 0) .establish()
Java
// The apps that will have access to the VPN. String[] appPackages = { "com.android.chrome", "com.google.android.youtube", "com.example.a.missing.app"}; // Loop through the app packages in the array and confirm that the app is // installed before adding the app to the allowed list. VpnService.Builder builder = new VpnService.Builder(); PackageManager packageManager = getPackageManager(); for (String appPackage: appPackages) { try { packageManager.getPackageInfo(appPackage, 0); builder.addAllowedApplication(appPackage); } catch (PackageManager.NameNotFoundException e) { // The app isn't installed. } } // Complete the VPN interface config. ParcelFileDescriptor localTunnel = builder .addAddress("2001:db8::1", 64) .addRoute("::", 0) .establish();
Apps permitidas
Para agregar una app a la lista permitida, llama
VpnService.Builder.addAllowedApplication()
Si
la lista incluye una o más apps, entonces solo las apps de la lista usan la VPN.
Todas las demás apps (que no están en la lista) usan las redes del sistema como si la VPN
no se está ejecutando. Cuando la lista permitida está vacía, todas las aplicaciones usan la VPN.
Apps no permitidas
Para agregar una app a la lista no permitida, llama a
VpnService.Builder.addDisallowedApplication()
Las apps no permitidas usan las redes del sistema como si la VPN no estuviera en ejecución; todas las demás
cuando las apps usan la VPN.
Omite la VPN
Tu VPN puede permitir que las apps la omitan y seleccionen su propia red. Para
omitir la VPN, llamar a VpnService.Builder.allowBypass()
cuando
estableciendo una interfaz de VPN. No puede cambiar este valor después de iniciar
servicio de VPN. Si una app no vincula su proceso o un socket a un
de red, el tráfico de red de la app continúa a través de la VPN.
Las apps que se vinculan a una red específica no tienen conexión cuando alguien
bloquea el tráfico que no pasa por la VPN. Para enviar tráfico a través de un
la red, las apps llaman a métodos, como
ConnectivityManager.bindProcessToNetwork()
o
Network.bindSocket()
antes de conectar el enchufe.
Código de muestra
El Proyecto de código abierto de Android incluye una app de muestra llamada ToyVPN. Esta app muestra cómo configurar y conectar un servicio VPN.