Android fournit des API permettant aux développeurs de créer des solutions de réseau privé virtuel (VPN). Après avoir lu ce guide, vous saurez comment développer et tester votre propre client VPN pour les appareils Android.
Présentation
Les VPN permettent aux appareils qui ne se trouvent pas physiquement sur un réseau d'y accéder de manière sécurisée.
Android inclut un client VPN intégré (PPTP et L2TP/IPSec), parfois appelé VPN ancien. Android 4.0 (niveau d'API 14) a introduit des API permettant aux développeurs d'applications de fournir leurs propres solutions de VPN. Vous empaquetez votre solution VPN dans une application que les utilisateurs installent sur l'appareil. Les développeurs créent généralement une application VPN pour l'une des raisons suivantes :
- Proposer des protocoles VPN qui ne sont pas compatibles avec le client intégré
- Aider les utilisateurs à se connecter à un service VPN sans configuration complexe
Le reste de ce guide explique comment développer des applications VPN (y compris les VPN toujours activés et par application) et ne couvre pas le client VPN intégré.
Expérience utilisateur
Android fournit une interface utilisateur (UI) pour aider les utilisateurs à configurer, démarrer et arrêter votre solution VPN. L'UI du système informe également l'utilisateur de l'appareil qu'une connexion VPN est active. Android affiche les composants d'interface utilisateur suivants pour les connexions VPN :
- Avant qu'une application VPN ne puisse devenir active pour la première fois, le système affiche une boîte de dialogue de demande de connexion. La boîte de dialogue invite la personne qui utilise l'appareil à confirmer qu'elle fait confiance au VPN et à accepter la demande.
- L'écran des paramètres VPN (Paramètres > Réseau et Internet > VPN) affiche les applications VPN pour lesquelles l'utilisateur a accepté les demandes de connexion. Un bouton permet de configurer les options du système ou d'oublier le VPN.
- Le panneau "Réglages rapides" affiche un panneau d'informations lorsqu'une connexion est active. Appuyer sur le libellé affiche une boîte de dialogue contenant plus d'informations et un lien vers les paramètres.
- La barre d'état inclut une icône de clé représentant le VPN pour indiquer qu'une connexion est active.
Votre application doit également fournir une UI pour que la personne qui utilise l'appareil puisse configurer les options de votre service. Par exemple, votre solution peut avoir besoin de capturer les paramètres d'authentification du compte. Les applications doivent afficher l'interface utilisateur suivante :
- Commandes permettant de démarrer et d'arrêter manuellement une connexion. Le VPN permanent peut se connecter si nécessaire, mais permet aux utilisateurs de configurer la connexion la première fois qu'ils utilisent votre VPN.
- Une notification persistante lorsque le service est actif. La notification peut afficher l'état de la connexion ou fournir plus d'informations, telles que des statistiques réseau. Appuyer sur la notification permet de faire passer votre application au premier plan. Supprimez la notification une fois que le service est devenu inactif.
Service VPN
Votre application connecte le réseau système d'un utilisateur (ou d'un profil professionnel) à une passerelle VPN. Chaque utilisateur (ou profil professionnel) peut exécuter une application VPN différente. Vous créez un service VPN que le système utilise pour démarrer et arrêter votre VPN, et suivre l'état de la connexion. Votre service VPN hérite de VpnService.
Le service sert également de conteneur pour les connexions de la passerelle VPN et leurs interfaces d'appareil local. Votre instance de service appelle les méthodes VpnService.Builder pour établir une nouvelle interface locale.
VpnService connecte le réseau Android à la passerelle VPNVotre application transfère les données suivantes pour connecter l'appareil à la passerelle VPN :
- Lit les paquets IP sortants à partir du descripteur de fichier de l'interface locale, les chiffre et les envoie à la passerelle VPN.
- Écrit les paquets entrants (reçus et déchiffrés à partir de la passerelle VPN) dans le descripteur de fichier de l'interface locale.
Il n'y a qu'un seul service actif par utilisateur ou profil. Le démarrage d'un nouveau service arrête automatiquement un service existant.
Ajouter un service
Pour ajouter un service VPN à votre application, créez un service Android héritant de VpnService. Déclarez le service VPN dans le fichier manifeste de votre application en ajoutant les éléments suivants :
- Protégez le service avec l'autorisation
BIND_VPN_SERVICEafin que seul le système puisse s'y associer. - Annoncez le service avec le filtre d'intent
"android.net.VpnService"pour que le système puisse le trouver.
Cet exemple montre comment déclarer le service dans le fichier manifeste de votre application :
<service android:name=".MyVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
Maintenant que votre application déclare le service, le système peut démarrer et arrêter automatiquement le service VPN de votre application si nécessaire. Par exemple, le système contrôle votre service lors de l'exécution d'un VPN toujours activé.
Préparer un service
Pour préparer l'application à devenir le service VPN actuel de l'utilisateur, appelez VpnService.prepare(). Si la personne qui utilise l'appareil n'a pas encore accordé l'autorisation à votre application, la méthode renvoie un intent d'activité.
Vous utilisez cet intent pour démarrer une activité système qui demande une autorisation. Le système affiche une boîte de dialogue semblable à d'autres boîtes de dialogue d'autorisation, telles que l'accès à l'appareil photo ou aux contacts. Si votre application est déjà préparée, la méthode renvoie null.
Une seule application peut être le service VPN préparé actuel. Appelez toujours VpnService.prepare(), car une personne peut avoir défini une autre application comme service VPN depuis le dernier appel de la méthode par votre application. Pour en savoir plus, consultez la section Cycle de vie des services.
Connecter un service
Une fois le service en cours d'exécution, vous pouvez établir une nouvelle interface locale connectée à une passerelle VPN. Pour demander l'autorisation et connecter votre service à la passerelle VPN, vous devez suivre les étapes dans l'ordre suivant :
- Appelez
VpnService.prepare()pour demander l'autorisation (si nécessaire). - Appelez
VpnService.protect()pour conserver le socket du tunnel de votre application en dehors du VPN du système et éviter une connexion circulaire. - Appelez
DatagramSocket.connect()pour connecter le socket du tunnel de votre application à la passerelle VPN. - Appelez les méthodes
VpnService.Builderpour configurer une nouvelle interface TUN locale sur l'appareil pour le trafic VPN. - Appelez
VpnService.Builder.establish()pour que le système établisse l'interface TUN locale et commence à acheminer le trafic via l'interface.
Une passerelle VPN suggère normalement des paramètres pour l'interface TUN locale lors de l'établissement de liaison. Votre application appelle les méthodes VpnService.Builder pour configurer un service, comme illustré dans l'exemple suivant :
// 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()
L'exemple de la section VPN par application montre une configuration IPv6 incluant d'autres options. Vous devez ajouter les valeurs VpnService.Builder suivantes avant de pouvoir établir une nouvelle interface :
addAddress()- Ajoutez au moins une adresse IPv4 ou IPv6 ainsi qu'un masque de sous-réseau que le système attribue en tant qu'adresse d'interface TUN locale. Votre application reçoit généralement les adresses IP et les masques de sous-réseau d'une passerelle VPN lors de l'établissement de la liaison.
addRoute()- Ajoutez au moins une route si vous souhaitez que le système envoie du trafic via l'interface VPN. Les routes filtrent par adresse de destination. Pour accepter tout le trafic, définissez une route ouverte telle que
0.0.0.0/0ou::/0.
La méthode establish() renvoie une instance ParcelFileDescriptor que votre application utilise pour lire et écrire des paquets vers et depuis le tampon de l'interface. La méthode establish() renvoie null si votre application n'est pas préparée ou si quelqu'un révoque l'autorisation.
Cycle de vie du service
Votre application doit suivre l'état du VPN sélectionné par le système et de toutes les connexions actives. Mettez à jour l'interface utilisateur de votre application pour que la personne qui utilise l'appareil soit informée de toute modification.
Démarrer un service
Votre service VPN peut être démarré de différentes manières :
- Votre application démarre le service, généralement parce qu'un utilisateur a appuyé sur un bouton de connexion.
- Le système démarre le service, car le VPN permanent est activé.
Votre application démarre le service VPN en transmettant un intent à startService(). Pour en savoir plus, consultez Démarrer un service.
Le système démarre votre service en arrière-plan en appelant onStartCommand(). Toutefois, Android impose des restrictions aux applications en arrière-plan dans la version 8.0 (niveau d'API 26) ou ultérieure. Si vous prenez en charge ces niveaux d'API, vous devez faire passer votre service au premier plan en appelant Service.startForeground(). Pour en savoir plus, consultez Exécuter un service au premier plan.
Arrêter un service
Une personne utilisant l'appareil peut arrêter votre service à l'aide de l'UI de votre application. Arrêtez le service au lieu de simplement fermer la connexion. Le système arrête également une connexion active lorsque la personne qui utilise l'appareil effectue les opérations suivantes sur l'écran "VPN" de l'application Paramètres :
- déconnecte ou supprime l'application VPN ;
- Désactive le VPN toujours activé pour une connexion active
Le système appelle la méthode onRevoke() de votre service, mais cet appel peut ne pas se produire sur le thread principal. Lorsque le système appelle cette méthode, une autre interface réseau achemine déjà le trafic. Vous pouvez supprimer les ressources suivantes en toute sécurité :
- Fermez le socket du tunnel protégé vers la passerelle VPN en appelant
DatagramSocket.close(). - Fermez le descripteur de fichier Parcel (vous n'avez pas besoin de le vider) en appelant
ParcelFileDescriptor.close().
VPN permanent
Android peut lancer un service VPN lors du démarrage de l'appareil et le laisser fonctionner tant que l'appareil est activé. Cette fonctionnalité est appelée VPN permanent et est disponible sur Android 7.0 (niveau d'API 24) ou version ultérieure. Bien qu'Android gère le cycle de vie du service, c'est votre service VPN qui est responsable de la connexion à la passerelle VPN. Le VPN toujours activé peut également bloquer les connexions qui n'utilisent pas le VPN.
Expérience utilisateur
Sous Android 8.0 ou version ultérieure, le système affiche les boîtes de dialogue suivantes pour informer l'utilisateur de l'appareil que le VPN est toujours activé :
- Lorsque les connexions VPN toujours activées se déconnectent ou ne peuvent pas se connecter, les utilisateurs voient une notification qu'ils ne peuvent pas ignorer. Appuyer sur la notification affiche une boîte de dialogue qui fournit plus d'explications. La notification disparaît lorsque le VPN se reconnecte ou que quelqu'un désactive l'option "VPN permanent".
- Le VPN toujours activé permet à la personne qui utilise un appareil de bloquer toutes les connexions réseau qui n'utilisent pas le VPN. Lorsque cette option est activée, l'application Paramètres avertit les utilisateurs qu'ils ne disposent pas d'une connexion Internet avant que le VPN ne se connecte. L'application Paramètres invite l'utilisateur de l'appareil à continuer ou à annuler.
Étant donné que le système (et non une personne) démarre et arrête une connexion toujours activée, vous devez adapter le comportement et l'interface utilisateur de votre application :
- Désactivez toute interface utilisateur qui déconnecte la connexion, car le système et l'application Paramètres contrôlent la connexion.
- Enregistrez toute configuration entre chaque démarrage de l'application et configurez une connexion avec les derniers paramètres. Étant donné que le système démarre votre application à la demande, l'utilisateur de l'appareil ne souhaite pas toujours configurer une connexion.
Vous pouvez également utiliser des configurations gérées pour configurer une connexion. Les configurations gérées aident un administrateur informatique à configurer votre VPN à distance.
Détecter l'affichage permanent
Android n'inclut pas d'API permettant de confirmer si le système a démarré votre service VPN. Toutefois, lorsque votre application signale les instances de service qu'elle démarre, vous pouvez supposer que le système a démarré des services non signalés pour le VPN toujours activé. Voici un exemple :
- Créez une instance
Intentpour démarrer le service VPN. - Signalez le service VPN en ajoutant un extra à l'intent.
- Dans la méthode
onStartCommand()du service, recherchez l'indicateur dans les extras de l'argumentintent.
Connexions bloquées
Une personne utilisant l'appareil (ou un administrateur informatique) peut forcer tout le trafic à utiliser le VPN. Le système bloque tout le trafic réseau qui n'utilise pas le VPN. Les utilisateurs de l'appareil peuvent trouver le bouton Bloquer les connexions sans VPN dans le panneau des options VPN des paramètres.
Désactiver le mode toujours activé
Si votre application n'est pas compatible avec le VPN toujours activé, vous pouvez désactiver cette fonctionnalité (sur Android 8.1 ou version ultérieure) en définissant les métadonnées du service SERVICE_META_DATA_SUPPORTS_ALWAYS_ON sur false. L'exemple de fichier manifeste d'application suivant montre comment ajouter l'élément de métadonnées :
<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>
Lorsque votre application désactive le VPN toujours activé, le système désactive les commandes d'interface utilisateur des options dans les paramètres.
VPN par application
Les applications VPN peuvent filtrer les applications installées qui sont autorisées à envoyer du trafic via la connexion VPN. Vous pouvez créer une liste d'autorisation ou une liste de refus, mais pas les deux. Si vous ne créez pas de listes d'autorisation ou de blocage, le système envoie tout le trafic réseau via le VPN.
Votre application VPN doit définir les listes avant que la connexion ne soit établie. Si vous devez modifier les listes, établissez une nouvelle connexion VPN. Une application doit être installée sur l'appareil lorsque vous l'ajoutez à une liste.
// 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()
Applications autorisées
Pour ajouter une application à la liste d'autorisation, appelez VpnService.Builder.addAllowedApplication(). Si la liste inclut une ou plusieurs applications, seules celles qui figurent dans la liste peuvent utiliser le VPN.
Toutes les autres applications (qui ne sont pas dans la liste) utilisent les réseaux du système, comme si le VPN n'était pas actif. Lorsque la liste des applications autorisées est vide, toutes les applications utilisent le VPN.
Applications non autorisées
Pour ajouter une application à la liste des applications non autorisées, appelez VpnService.Builder.addDisallowedApplication().
Les applications non autorisées utilisent les réseaux du système comme si le VPN n'était pas actif. Toutes les autres applications utilisent le VPN.
Contourner le VPN
Votre VPN peut autoriser les applications à le contourner et à sélectionner leur propre réseau. Pour contourner le VPN, appelez VpnService.Builder.allowBypass() lors de l'établissement d'une interface VPN. Vous ne pouvez pas modifier cette valeur après avoir démarré votre service VPN. Si une application ne lie pas son processus ou un socket à un réseau spécifique, son trafic réseau continue de passer par le VPN.
Les applications qui se lient à un réseau spécifique ne disposent pas de connexion lorsque quelqu'un bloque le trafic qui ne passe pas par le VPN. Pour envoyer du trafic via un réseau spécifique, les applications appellent des méthodes telles que ConnectivityManager.bindProcessToNetwork() ou Network.bindSocket() avant de connecter le socket.
Exemple de code
Le projet Open Source Android inclut un exemple d'application appelé ToyVPN. Cette application montre comment configurer et connecter un service VPN.