VPN

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

Figura 1: Cómo VpnService conecta Android a la puerta de enlace de VPN
Diagrama de arquitectura de bloques que muestra cómo VpnService crea un TUN local
         en las redes del sistema.
.

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:

  1. Llama a VpnService.prepare() para solicitar permiso (cuando necesario).
  2. 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.
  3. Llama a DatagramSocket.connect() para conectar el túnel de tu app. a la puerta de enlace de VPN.
  4. Llama a los métodos VpnService.Builder para configurar un nuevo entorno local. interfaz TUN en la dispositivo para el tráfico de VPN.
  5. 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:

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:

  1. Inhabilitar cualquier IU que desconecte la conexión porque el sistema y la Configuración la app controlan la conexión.
  2. 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:

  1. Crea una instancia Intent para iniciar el servicio VPN.
  2. Marca el servicio VPN poniendo un servicio adicional en el intent.
  3. En el método onStartCommand() del servicio, busca la marca en los extras del argumento intent.

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.