VPN

O Android oferece APIs para que os desenvolvedores criem uma rede privada virtual (VPN) soluções. Após ler este guia, você saberá como desenvolver e testar próprio cliente VPN para dispositivos com tecnologia Android.

Visão geral

As VPNs permitem que os dispositivos que não estão fisicamente em uma rede acessem com segurança os em uma rede VPC.

O Android inclui um cliente VPN integrado (PPTP e L2TP/IPSec), que às vezes é chamada VPN legada. O Android 4.0 (API de nível 14) introduziu APIs para que o aplicativo os desenvolvedores podem fornecer soluções de VPN próprias. Crie um pacote com sua solução de VPN em um app que as pessoas instalam no dispositivo. Os desenvolvedores normalmente criam VPNs app por um destes motivos:

  • Oferecer protocolos VPN incompatíveis com o cliente integrado.
  • Ajudar as pessoas a se conectarem a um serviço de VPN sem configuração complexa.

O restante deste guia explica como desenvolver apps de VPN (incluindo sempre ativada e por app) e não abrange os integrado ao cliente VPN.

Experiência do usuário

O Android fornece uma interface do usuário (UI) para ajudar alguém a configurar, iniciar e interromper sua solução de VPN. A IU do sistema também torna o usuário do dispositivo cientes de uma conexão VPN ativa. O Android mostra os seguintes componentes de IU para Conexões VPN:

  • Antes de ativar um app de VPN pela primeira vez, o sistema mostra uma caixa de diálogo do pedido de conexão. A caixa de diálogo solicita que o usuário do dispositivo confirme se confia na VPN e aceita a solicitação.
  • A tela "Configurações de VPN" (Configurações > Rede e Internet > VPN) mostra a VPN apps em que uma pessoa aceitava pedidos de conexão. Há um botão para configurar as opções do sistema ou esquecer a VPN.
  • A bandeja "Configurações rápidas" mostra um painel de informações quando há uma conexão ativos. Tocar no marcador abre uma caixa de diálogo com mais informações e um link em "Configurações".
  • A barra de status inclui o ícone de VPN (chave) para indicar uma conexão ativa.

Seu app também precisa fornecer uma interface para que o usuário do dispositivo possa e configure as opções do seu serviço. Por exemplo, sua solução pode precisar capturar as configurações de autenticação da conta. Os apps devem exibir a seguinte IU:

  • Controles para iniciar e interromper manualmente uma conexão. VPN sempre ativada podem se conectar quando necessário, mas permitem que as pessoas configurem a conexão primeiro sempre que eles usarem a VPN.
  • Uma notificação não dispensável quando o serviço está ativo. A notificação pode mostrar o status da conexão ou fornecer mais informações, como estatísticas da rede. O toque na notificação coloca o app em primeiro plano. Remova o depois que o serviço ficar inativo.

Serviço de VPN

Seu aplicativo conecta a rede do sistema para um usuário (ou um trabalho ) para um gateway de VPN. Cada usuário (ou perfil de trabalho) pode executar um um app de VPN diferente. Você cria um serviço de VPN que o sistema usa para iniciar e interromper a VPN e monitorar o status da conexão. Seu serviço de VPN herda do VpnService

O serviço também funciona como um contêiner para as conexões de gateway de VPN e as interfaces de dispositivos locais. Sua chamada de instância de serviço VpnService.Builder para estabelecer uma nova interface local.

Figura 1. Como o VpnService conecta o Android rede até o gateway de VPN
Diagrama da arquitetura de blocos mostrando como o VpnService cria um TUN local
         na rede do sistema.

O app transfere os seguintes dados para conectar o dispositivo ao gateway da VPN:

  • Lê pacotes IP de saída a partir do descritor de arquivos da interface local, criptografa e as envia para o gateway da VPN.
  • Grava pacotes de entrada (recebidos e descriptografados do gateway de VPN) no descritor de arquivos da interface local.
.

Há apenas um serviço ativo por usuário ou perfil. Ao iniciar um novo serviço, interrompe automaticamente um serviço existente.

Adicionar um serviço

Para adicionar um serviço de VPN ao app, crie um serviço do Android que herde de VpnService Declarar o serviço de VPN no app de manifesto do app com as seguintes adições:

  • Proteja o serviço com o BIND_VPN_SERVICE. permissão para que apenas o sistema possa se vincular ao seu serviço.
  • Anuncie o serviço com o filtro de intent "android.net.VpnService" para que o sistema poderá encontrar o serviço.

Este exemplo mostra como declarar o serviço no arquivo de manifesto do app:

<service android:name=".MyVpnService"
         android:permission="android.permission.BIND_VPN_SERVICE">
     <intent-filter>
         <action android:name="android.net.VpnService"/>
     </intent-filter>
</service>

Agora que o app declara o serviço, o sistema pode iniciar automaticamente e interromper o serviço de VPN do app quando necessário. Por exemplo, o sistema controla seu serviço ao executar a VPN sempre ativa.

Preparar um serviço

Para preparar o app para se tornar o serviço de VPN atual do usuário, chame VpnService.prepare() Se o usuário do dispositivo não já tiver recebido permissão para o app, o método retornará uma intent de atividade. Use esse intent para iniciar uma atividade do sistema que solicite a permissão. A sistema mostra uma caixa de diálogo semelhante a outras caixas de diálogo de permissões, como acesso à câmera ou aos contatos. Se o aplicativo já estiver preparado, o método retornará null:

Apenas um app pode ser o atual serviço de VPN preparado. Sempre ligar VpnService.prepare() porque uma pessoa pode ter definido uma como o serviço de VPN desde a última vez que seu app chamou o método. Para saber mais, consulte a seção Ciclo de vida do serviço.

Conectar um serviço

Quando o serviço estiver em execução, será possível estabelecer uma nova interface local conectados a um gateway de VPN. Para solicitar permissão e se conectar ao seu serviço para gateway da VPN, conclua as etapas na seguinte ordem:

  1. Chame VpnService.prepare() para pedir permissão (quando necessário).
  2. Chame VpnService.protect() para manter o soquete do túnel do seu app fora da VPN do sistema e evitar uma conexão circular.
  3. Chame DatagramSocket.connect() para conectar o túnel do app para o gateway de VPN.
  4. Chame métodos VpnService.Builder para configurar um novo local interface TUN na para o tráfego VPN.
  5. Chame VpnService.Builder.establish() para que o sistema estabelece a interface TUN local e começa a rotear o tráfego por meio da interface gráfica do usuário.

Um gateway de VPN normalmente sugere configurações para a interface TUN local durante aperto de mão. O app chama métodos VpnService.Builder para configurar uma serviço, conforme mostrado no exemplo a seguir:

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();

O exemplo na seção VPN por app mostra uma configuração IPv6, incluindo mais opções. Você precisa adicionar os seguintes valores VpnService.Builder antes de estabelecer uma nova interface:

addAddress()
Adicionar pelo menos um endereço IPv4 ou IPv6 com uma máscara de sub-rede que o sistema atribui como o endereço da interface TUN local. Normalmente, seu app recebe o IP endereços IP e máscaras de sub-rede de um gateway VPN durante o handshake.
addRoute()
Adicionar pelo menos uma rota se você quiser que o sistema envie tráfego pela VPN interface gráfica do usuário. As rotas são filtradas por endereços de destino. Para aceitar todo o tráfego, defina um rota aberta, como 0.0.0.0/0 ou ::/0.

O método establish() retorna uma ParcelFileDescriptor usada pelo app para ler e gravar pacotes de entrada e saída do buffer da interface. O establish() O método retornará null se o aplicativo não estiver preparado ou se se alguém revogar o permissão.

Ciclo de vida do serviço

Seu app precisa rastrear o status da VPN selecionada pelo sistema e as conexões de rede. Atualize a interface do usuário (interface) do seu app para manter a pessoa usando o dispositivo ciente de quaisquer alterações.

Iniciar um serviço

O serviço de VPN pode ser iniciado das seguintes maneiras:

  • Seu app inicia o serviço, normalmente porque o usuário tocou em um botão de conexão.
  • O sistema inicia o serviço porque a VPN sempre ativa está ligada.

Seu app inicia o serviço de VPN transmitindo uma intent para startService() Para saber mais, leia Como iniciar um serviço.

O sistema inicia seu serviço em segundo plano chamando onStartCommand() No entanto, o Android impõe restrições Apps em segundo plano na versão 8.0 (nível 26 da API) ou mais recente. Se você oferecer suporte a essas níveis de API, é necessário fazer a transição do serviço para o primeiro plano chamando Service.startForeground() Para saber mais, leia Como executar um serviço em primeiro plano.

Interromper um serviço

O usuário do dispositivo pode interromper o serviço usando a IU do seu app. Pare o em vez de apenas encerrar a conexão. O sistema também interrompe um evento quando o usuário faz o seguinte na tela da VPN do app Configurações:

  • Desconecta ou esquece o app de VPN.
  • Troca a VPN sempre ativa por uma conexão ativa.

O sistema chama o método onRevoke() do serviço, mas essa chamada pode não acontecer na linha de execução principal. Quando o sistema chama esse método, um interface de rede alternativa já está roteando o tráfego. Você pode descartar um dos seguintes recursos:

VPN sempre ativa

O Android pode iniciar um serviço de VPN quando o dispositivo for inicializado e mantê-lo em execução enquanto o dispositivo está ligado. Esse recurso é chamado de VPN sempre ativa e está disponível em Android 7.0 (nível 24 da API) ou mais recente Enquanto o Android mantém o serviço seu serviço de VPN é responsável pela configuração do gateway de VPN uma conexão com a Internet. A VPN sempre ativa também pode bloquear conexões que não usam a VPN.

Experiência do usuário

No Android 8.0 ou versões mais recentes, o sistema mostra as seguintes caixas de diálogo para tornar a pessoa que usa o dispositivo ciente da VPN sempre ativa:

  • Quando as conexões VPN sempre ativa se desconectam ou não conseguem se conectar, as pessoas veem um não dispensável. Tocar na notificação mostra uma caixa de diálogo que explica mais. A notificação desaparece quando a VPN é reconectada ou quando alguém desativa a opção de VPN sempre ativa.
  • A VPN sempre ativada permite que o usuário do dispositivo bloqueie qualquer rede que não usam a VPN. Ao ativar essa opção, as Configurações avisa as pessoas de que não há uma conexão com a Internet antes da VPN se conecta. O app Configurações solicita que o usuário do dispositivo continue ou cancelar.

Como o sistema (e não uma pessoa) inicia e interrompe uma conexão sempre ativa, você precisa adaptar o comportamento e a interface do usuário do seu aplicativo:

  1. Desativa qualquer interface que desconecte a conexão por causa do sistema e das configurações controlar a conexão.
  2. Salve as configurações entre cada inicialização do app e configure uma conexão com o configurações mais recentes. Como o sistema inicia o app sob demanda, a pessoa usando o dispositivo nem sempre quer configurar uma conexão.

Também é possível usar configurações gerenciadas para definir um uma conexão com a Internet. As configurações gerenciadas ajudam o administrador de TI a configurar sua VPN remotamente.

Detectar a opção "sempre ativa"

O Android não inclui APIs para confirmar se o sistema iniciou a VPN serviço. Mas, quando o app sinaliza qualquer instância de serviço que é iniciada, é possível presumir que o sistema iniciou serviços não sinalizados para a VPN sempre ativa. Veja um exemplo:

  1. Crie uma instância Intent para iniciar o serviço de VPN.
  2. Sinalize o serviço de VPN colocando um extra no intent.
  3. No método onStartCommand() do serviço, procure o flag nos extras do argumento intent.

Conexões bloqueadas

Um usuário do dispositivo (ou um administrador de TI) pode forçar todo o tráfego a usar a VPN. O sistema bloqueará qualquer tráfego de rede que não use a VPN. Pessoas que usam o dispositivo poderá encontrar a chave Bloquear conexões sem VPN nas opções de VPN em "Configurações".

Desativar a opção "sempre ativa"

Se o app não oferece suporte à VPN sempre ativa, é possível desativá-la (no Android 8.1 ou superior) ao definir a SERVICE_META_DATA_SUPPORTS_ALWAYS_ON metadados do serviço para false. O exemplo de manifesto do app abaixo mostra como adicionar o elemento de metadados:

<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>

Quando o app desativa a VPN sempre ativa, o sistema desativa a interface de opções controles nas Configurações.

VPN por app

Os apps de VPN podem filtrar quais apps instalados têm permissão para enviar tráfego pelo Conexão VPN. É possível criar uma lista de permissões ou de permissões mas não os dois. Se você não criar listas de permissão ou proibição, o sistema enviará todo o tráfego de rede pela VPN.

O app de VPN precisa definir as listas antes que a conexão seja estabelecida. Se você alterar as listas e estabelecer uma nova conexão VPN. O app precisa ser instalado no dispositivo quando você o adiciona a uma 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 permitidos

Para adicionar um app à lista de permissões, chame VpnService.Builder.addAllowedApplication() Se a lista incluir um ou mais apps, somente os apps na lista usarão a VPN. Todos os outros apps (que não estejam na lista) vão usar as redes do sistema como se a VPN não está em execução. Quando a lista de permissões está vazia, todos os apps usam a VPN.

Apps não permitidos

Para adicionar um app à lista de não permitidos, chame VpnService.Builder.addDisallowedApplication() Os apps não permitidos usam a rede do sistema como se a VPN não estivesse em execução. Todos os outros usam a VPN.

Ignorar a VPN

A VPN pode permitir que os apps a ignorem e selecionem a própria rede. Para ignorar a VPN, chame VpnService.Builder.allowBypass() quando estabelecendo uma interface VPN. Não será possível mudar esse valor depois de iniciar a serviço de VPN. Se um app não vincular o processo ou um soquete a uma determinada o tráfego de rede do app vai continuar pela VPN.

Apps que se vinculam a uma rede específica não têm uma conexão quando alguém bloqueia o tráfego que não passa pela VPN. Para enviar tráfego por uma rede rede, os aplicativos chamam métodos, como ConnectivityManager.bindProcessToNetwork() ou Network.bindSocket() antes de conectar o soquete.

Exemplo de código

O Android Open Source Project inclui uma amostra de app denominada ToyVPN. Esse app mostra como configurar e conectar um serviço de VPN.