Installer et utiliser un VPN sur un serveur linux avec un client Android

Dans cet article je vais vous expliquer toutes les étapes par lesquelles je suis passé pour avoir un VPN permanent sur mon téléphone Android, et vous allez voir que ce n’est pas si simple !

Ca faisait un bout de temps que je voulais configurer un VPN pour utiliser sur mon téléphone. Le vote de la loi PJL et ses fameuses boites noires (si vous ne connaissez pas, je vous renvoie vers l’association LQDN https://www.laquadrature.net/fr) a été l’élément déclencheur.

Le but était d’avoir un VPN activé en permanence sur mon téléphone pour chiffrer les données qui transitent entre mon téléphone et internet.

J’auto-héberge la majorité de mes données sur mon serveur, mais je voulais en utiliser un spécialement pour cet usage.

J’ai donc pris un VPS chez un petit hébergeur (Onet Solutions) qui a l’avantage d’avoir un excellent rapport prix / espace disque (2 euros par mois pour 100 Go, c’est quand même pas mal). Firstheberg est aussi à ce tarif, mais pour un espace disque moindre. Je n’ai pas trouvé de VPS moins cher, du moins pas en France ou dans un pays francophone.

Quand je mets en place des outils, j’aime bien m’appuyer sur des solutions ouvertes et autant que possible déjà incluses dans les produits que j’utilise. Il me fallait donc un produit serveur qui me permette d’utiliser le client VPN déjà présent dans Android, ce qui excluait d’office OpenVPN et son client Android dédié (qui est par ailleurs une solution très simple à mettre en place, donc si vous ne voulez pas vous prendre la tête, c’est peut-être la meilleure solution pour vous).

Une fois mon VPS installé avec une debian, me voilà parti à la recherche du tutoriel pour réaliser ce que je voulais. Je suis d’abord tombé sur cet article :

http://pazpop.fr/installer-un-serveur-vpn-pptp-sous-gnulinux-debian/

Bon, ça a l’air simple, donc je fais la config. Wow, ça marche du premier coup dis-donc !

Fichier /etc/pptpd.conf :

option /etc/ppp/pptpd-options
logwtmp
localip 10.9.0.1
remoteip 10.9.0.2-10

Fichier /etc/ppp/pptpd-options :

name pptpd
proxyarp
nodefaultroute
debug
lock
nobsdcomp
novj
novjccomp
ms-dns 8.8.8.8
ms-dns 8.8.4.4

Les DNS de google sont pratiques pour tester, mais tankafer je vous conseille plutôt ceux du projet OpenNIC, plus respectueux de la vie privée (https://www.opennicproject.org/)

Fichier /etc/ppp/chap-secrets :

compte<TAB>pptpd<TAB>motdepasse<TAB>*

Puis les commandes :

echo 1 > /proc/sys/net/ipv4/ip_forward (à mettre dans sysctl)

iptables -t nat -A POSTROUTING -s 10.9.0.0/24 -o venet0 -j MASQUERADE (à mettre dans un script de boot)

/etc/init.d/pptpd start

Bon là, la règle iptables à mettre en place dépend de votre serveur : si c’est un VPS de type OpenVZ il faut parfois une règle supplémentaire, cf les commentaires du lien ci-dessus. Egalement, certains hébergeurs filtrent les paquets GRE utilisés par PPP (incloudibly par exemple), et du coup bah ça peut pas marcher. Donc renseignez-vous auprès de votre hébergeur au lieu de vous arracher les cheveux comme j’ai fait pendant quelques heures avant d’apprendre que « ah non, mon brave monsieur, on filtre ! ».

Dans l’appareil Android, il faut aller dans Réglages (ou paramètres), choisir VPNle paramétrage VPN, ajouter un VPN de type PPTP, mettre l’IP du serveur et laisser la compression PPP activée :

Screenshot_2016-03-20-15-35-31

Ensuite, vous lancez le VPN, il vous demande le compte et le mot de passe mis dans le fichier chap-secrets ci-dessus, et tadam !

Bon, me v’là tout content avec mon VPN qui marche ! Y a plus qu’à le mettre actif en permanence !

Sauf que.

Sauf que quand on va dans la configuration VPN, et qu’on essaie d’activer always-on VPN (ou VPN permanent en bon français), il ne propose pas le VPN qu’on vient d’ajouter. Mais qu’est-ce que c’est que ce binz.

Après quelques recherches sur le net, il s’avère que Google a décidé qu’un VPN de type PPTP c’était pas assez secure pour être utilisé avec l’option VPN permanent, et ils ont donc désactivé cette possibilité. Bon, à leur décharge il semble qu’effectivement PPTP ce soit pas l’idéal. Allez pas grave, on va essayer autre chose alors ! Qu’est-ce qu’il sait faire d’autre le client VPN de Google ? L2TP/IPsec et IPsec ? On va essayer le premier.

Re-recherche d’un tutoriel, et je tombe là-dessus :

https://wiki.debian.org/HowTo/AndroidVPNServer

Et c’est parti !

Bon, je mets en place toute la configuration et je démarre racoon, et vlà qu’il me dit :

racoon – IKE keying daemon will not be started as /proc/net/pfkey is not
available or a suitable 2.6 (or 2.4 with IPSEC backport)
kernel with af_key.[k]o module installed.

Ah, il lui manque juste le module af_key dans le kernel, pas de problème je l’ajoute.

Sauf que.

Sauf que quand on a un VPS on n’a pas toujours le choix des modules disponibles, et pas possible de recompiler le module nécessaire si on n’a pas les sources du kernel mis à disposition par l’hébergeur. Après moult tickets à ONET pour leur expliquer ma situation, ils continuaient à affirmer que j’avais tous les outils à disposition pour monter mon VPN.

Bon, on va pas se battre pendant des heures. Bye-bye ONET, bonjour incloudibly. C’est un peu plus cher, mais ils sont en Suisse, un pays qui a une longue tradition de respect du secret 😉

Je remets la configuration de l’article, et je refais mes tests mais malgré tous mes efforts, je n’ai pas pu faire fonctionner la configuration du site de Debian, ni celle décrite sur ce site qui est pourtant plus simple à mettre en place puisqu’on se passe de la partie L2TP pour faire un tunnel IPsec pur :

http://jsharkey.org/blog/2012/09/22/deploying-a-pure-ipsec-pki-vpn-server-for-android-devices/

Au final j’ai eu l’impression que mes problèmes venaient de racoon (malgré le fait que la page debian indique qu’il fonctionne mieux avec les équipements Android), et du coup j’ai décidé de tester la dernière option compatible Android, un tunnel IPsec pur, et je suis donc passé sur un autre outil : StrongSwan. Et me revoilà parti à chercher un nouveau tutoriel ! Celui-là est ressorti dans les premiers :

http://danielpocock.com/strongswan-debian-rhel-fedora-with-android-client

Et c’est reparti pour un tour !

L’article ci-dessus fournit un script pour créer les fichiers de certificats pour les clients, c’est très pratique quand on veut en générer plus d’un.

Du coup, je mets la même config que dans l’article, et je créé un profil dans le téléphone :

Screenshot_2016-03-20-15-43-03

Je lance la connexion et là, messages d’erreur dans la syslog :

Mar  7 19:35:44 monserveur ipsec[31641]: 11[NET] received packet: from x.x.x.x[500] to y.y.y.y[500] (720 bytes)
Mar  7 19:35:44 monserveur ipsec[31641]: 11[ENC] parsed ID_PROT request 0 [ SA V V V V V V V V ]
Mar  7 19:35:44 monserveur ipsec[31641]: 11[IKE] no IKE config found for y.y.y.y…x.x.x.x, sending NO_PROPOSAL_CHOSEN
Mar  7 19:35:44 monserveur ipsec[31641]: 11[ENC] generating INFORMATIONAL_V1 request 128690932 [ N(NO_PROP) ]
Mar  7 19:35:44 monserveur ipsec[31641]: 11[NET] sending packet: from y.y.y.y[500] to x.x.x.x[500] (40 bytes)

Ici x.x.x.x est l’IP de mon client, y.y.y.y est l’IP de mon serveur StrongSwan, et monserveur est son nom.

Hum, de ce que j’en comprends et de ce que je trouve sur internet, il ne trouve pas de config utilisable avec mon client dans le fichier ipsec.conf.

Dans ce cas, c’est ma variable left= qui pointait vers le nom FQDN du serveur, mais mon serveur ne le résolvait pas en local. Un petit edit du fichier /etc/hosts et je relance la connexion :

Mar  7 20:42:04 monserveur charon: 14[CFG] looking for XAuthInitRSA peer configs matching y.y.y.y…x.x.x.x[CN=monclient.mondomaine]
Mar  7 20:42:04 monserveur charon: 14[IKE] found 1 matching config, but none allows XAuthInitRSA authentication using Main Mode
Mar  7 20:42:04 monserveur charon: 14[ENC] generating INFORMATIONAL_V1 request 1796323428 [ HASH N(AUTH_FAILED) ]
Mar  7 20:42:04 monserveur charon: 14[NET] sending packet: from y.y.y.y[4500] to x.x.x.x[4500] (108 bytes)

Ah, un problème d’authentification lié au fait qu’il ne trouve pas de configuration qui autorise le mode XAuthInitRSA. Pour ce problème, il fallait ajouter deux lignes dans /etc/ipsec.conf avec :

rightauth=pubkey
rightauth2=xauth

Re-relance et là :

Mar  7 20:47:40 monserveur charon: 16[CFG] no issuer certificate found for « CN=monclient »
Mar  7 20:47:40 monserveur charon: 16[IKE] no trusted RSA public key found for ‘CN=monclient’
Mar  7 20:47:40 monserveur charon: 16[CFG] no alternative config found
Mar  7 20:47:40 monserveur charon: 16[ENC] generating INFORMATIONAL_V1 request 1397311563 [ HASH N(AUTH_FAILED) ]
Mar  7 20:47:40 monserveur charon: 16[NET] sending packet: from y.y.y.y[4500] to x.x.x.x[4500] (108 bytes)

Pour celle-là, j’ai galéré. En fait, le blog de Daniel Pocock renvoie vers le wiki de StrongSwan (https://wiki.strongswan.org/projects/strongswan/wiki/SimpleCA) qui indique que :

/etc/ipsec.d/cacerts/caCert.der holds the CA certificate which issued and signed all peer certificates.

Or dans le blog, Daniel nous fait copier vpnKey.der et vpnCert.der au bon endroit, mais pas caCert.der ! Un petit cp et re-re-relance :

May  8 21:03:12 vdsgugux ipsec[6153]: 14[CFG] no XAuth method found

Hum, après une petite recherche il me manque le module xauth-generic. Sur debian il est dans le paquet libcharon-extra-plugins. Un coup d’install et là :

Mar  7 20:53:10 monserveur charon: 01[ENC] parsed TRANSACTION response 3292374011 [ HASH CPA(X_STATUS) ]
Mar  7 20:53:10 monserveur charon: 01[IKE] destroying IKE_SA after failed XAuth authentication

Ca progresse ! Maintenant il me dit que je n’ai pas passé l’authentification. Là la solution est simple, ajouter dans le fichier /etc/ipsec.secrets la ligne ci-dessous (ce n’est pas précisé par Daniel non plus, il faut que je pense à lui remonter ces infos) :

monutilisateur : XAUTH « monmotdepasse »

Et là, victoire ! Mon client Android se connecte ! Alleluia !

Bon, maintenant je me dis qu’il n’y a plus qu’une seule étape : activer le VPN en permanence sur le client Android. Fastoche !

Sauf que.

Eh oui, encore.

Sauf que, quand on active le VPN en permanence, il se connecte bien mais le trafic ne passe plus du tout. Arg !

Après une nouvelle recherche sur Internet, il s’avère qu’il y a un bug (signalé depuis un bout de temps à Google) qui empêche le trafic de passer quand on utilise l’option Always-on :

https://code.google.com/p/android/issues/detail?id=63450

Il semble que le problème se situe au niveau des règles iptables. J’ai essayé les commandes conseillées dans le bug report mais pas mieux.

Ici il semble que certaines personnes aient réussi à corriger les règles iptables qui empêchaient le trafic de passer :

http://www.tinc-vpn.org/pipermail/tinc/2015-March/004078.html

J’ai fait quelques tests mais pour ma part ça n’a pas marché non plus.

Ce fil de discussion chez XDA est intéressant également sur le sujet :

http://forum.xda-developers.com/showthread.php?t=1994344

Il y a des tentatives de contournement du bug disponibles à droite et à gauche : cette application n’a pas fonctionné pour ma part :

https://play.google.com/store/apps/details?id=ru.microlana.android.alwaysonvpnfix

Et je n’ai pas testé celle-ci :

https://github.com/GiantTreeLP

Bref, rien à faire ! Là j’ai un peu réfléchi et je me suis dit qu’après tout, on n’était pas obligé d’utiliser l’option et qu’on pouvait passer par un outil d’automatisation comme Tasker pour pallier le problème.

En regardant un peu ce que sait faire Tasker, il semble qu’il ne soit pas capable de lancer une connexion VPN sans passer par une application Android supplémentaire appelée Secure Settings. Du coup, j’ai regardé si celle-ci était compatible avec une autre application d’automatisation (vu que Tasker est payant et qu’à part cette histoire de VPN, j’en ai pas trop l’utilité) et je suis tombé sur E-Robot :

https://play.google.com/store/apps/details?id=com.bartat.android.robot

Donc je l’installe, ainsi que Secure Settings :

https://play.google.com/store/apps/details?id=com.intangibleobject.securesettings.plugin

Dans E-Robot, il faut ajouter une commande qu’on appelle VPN par exemple, que si déclenche quand le réseau Mobile ou Wi-Fi monte, et qui lance la connexion VPN, comme ceci :

Screenshot_2016-03-20-16-23-43

Pour ajouter l’action, il faut aller dans l’onglet 3eme Partie -> Secure Settings -> Root Actions -> VPN puis activer la connexion de son VPN :

Screenshot_2016-03-20-16-26-03

Maintenant E-Robot doit lancer la connexion VPN dès qu’il voit le réseau monter. Bon, c’est moins transparent et efficace que l’option Always-On VPN, car parfois E-Robot n’arrive pas à mettre le VPN en place, et c’est moins sécurisé car l’option Always-On VPN est censée bloquer le trafic quand le VPN n’est pas actif, mais comme au final elle le bloque tout le temps …

Nous voilà à la fin de l’article. J’attends la disponibilité d’une ROM avec Android 6.0 (Marshmallow) sur mon téléphone pour voir si Always-On VPN remarche, je vous tiendrais au courant !

Si vous avez des commentaires / questions / critiques, n’hésitez pas !

[Edit 08/05/2016] Je suis passé à MarshMallow et non seulement Always-On VPN ne marche toujours pas, mais Secure Settings ne marche plus ! Bon, va encore falloir se creuser les méninges … La suite bientôt !

[Edit 19/04/2020] J’étais passé à Android 7 l’année dernière et ça ne marchait toujours pas, mais depuis une mise à jour récente de ma ROM alternative, le problème du « Always-On VPN » est résolu ! Il faut croire que Google a corrigé le fameux bug (il était temps) … Pour info j’utilise cette ROM :https://forum.xda-developers.com/z5-compact/development/lineageos-14-1-bernis-alternative-builds-t3694904