Passerelle VPN L2TP/IPsec pour smartphone avec OpenBSD

logo.pngDans cet article, je vais présenter la marche à suivre pour configurer une passerelle VPN utilisant les protocoles L2TP/IPsec sur un système OpenBSD (en version 5.1). Cette passerelle vous permettra de vous y connecter à l’aide de votre smartphone Android (testé avec Android 4.0 ICS) ou iPhone, puisque ces terminaux supportent maintenant nativement ces types de VPN.

Le protocole L2TP (Layer 2 Tunneling Protocol) est un protocole de tunneling à la popularité grandissante, car supporté nativement par de nombreux OS : Windows, MacOS X, Linux, etc. mais également par les plate-formes mobiles populaires que sont Android et iOS. De plus, L2TP permet aisément de réaliser des VPN au dessus d’infrastructures existantes puisqu’il est transporté dans des paquets IP/UDP sur le port 1701. Dans la suite du document, nous allons utiliser le nouveau daemon npppd(8), inclus dans le système de base d’OpenBSD.

Afin de rendre le VPN plus sûr, la méthode est de chiffrer le trafic L2TP dans un tunnel IPsec. Ici rien de bien nouveau, nous nous reposerons sur l’extrême simplicité de configuration offerte par OpenBSD.

Un petit HOWTO est disponible avec les sources du ‘daemon’ npppd(8) que nous allons utiliser à cette adresse. Seulement, cet exemple de configuration ne s’intéresse qu’au cas générique et ne peut pas être repris tel quel dans certains scénarios.

1. Eléments d’architecture

Mon opérateur internet est Free. J’utilise une Freebox Revolution (v6) en mode routeur afin d’utiliser toutes les fonctionnalités multimedia qu’elle offre. Il faut donc noter que ma passerelle VPN possède une adresse IPv4 privée (192.168.0.1) sur le réseau interne de ma Freebox. Il ne faut donc pas oublier de configurer la Freebox pour rediriger le trafic IPsec et L2TP (chiffré avec IPsec) sur la passerelle VPN, en utilisant une IP « DMZ » dans l’interface de configuration de la Freebox.

Note : Les simples redirections de ports ne fonctionnent pas, car il faut non seulement rediriger le trafic UDP sur les ports 500 et 4500 (pour respectivement les protocoles ISAKMP et NAT-Traversal concernant la gestion de clés) mais également le trafic ESP (Encap Security Payload), qui a le numéro de protocole IP n°50 ; et qui concerne nos données utiles chiffrées.

Ensuite, mon opérateur mobile est également Free. Free ne pouvant techniquement pas assigner une adresse IP publique à chaque équipement mobile sur son réseau, lorsque vous utilisez des connexions pour de la donnée, vous vous retrouvez avec une IP en adressage privé (10.X.X.X).

Ces points sont à prendre en compte, surtout concernant la configuration IPsec qui devient légèrement plus complexe sur notre passerelle.

2. Configuration de la passerelle VPN

L’étape d’installation de l’OS OpenBSD ne sera pas détaillée puisque c’est une installation tout ce qu’il y a de plus standard. Deux points sont cependant à noter.

D’une part, vous aurez besoin d’utiliser au minimum OpenBSD 5.1 dont la date de sortie est comme d’habitude (cycles de développement de 6 mois) fixée au 1er mai 2012. A l’heure où je rédige cet article, OpenBSD 5.1 est seulement taggé dans le CVS, vous pouvez donc utiliser un snapshot de -current.

D’autre part, vous aurez besoin d’installer les sources de l’OS (src, pas xenocara ni les ports). J’utilise pour ma part une machine à base de Soekris net5501 avec le système installé sur une carte flash. Ne pouvant pas vraiment installer les sources et compiler les outils nécessaires, du fait de l’utilisation d’une carte flash, je monte les répertoires (/usr/obj et /usr/src) via un partage NFS exporté par une autre machine.

Je vous invite à lire la FAQ d’OpenBSD qui est un modèle du genre pour de plus amples informations sur l’installation de l’OS.

Une fois l’OS OpenBSD 5.1 installé, ainsi que ses sources, il faut modifier le fichier /etc/sysctl.conf pour autoriser certaines fonctionnalités au niveau du noyau d’OpenBSD. Pour cela, il faut s’assurer que ces lignes soient dé-commentées :
net.inet.ip.forwarding=1 # transfert IP entre interfaces
net.inet.gre.allow=1 # autorise le protocole de tunneling GRE
net.pipex.enable=1 # accélérateur de transfert IP pour PPP

4. Installation et configuration de npppd(8)

Ensuite, il faut compiler le daemon npppd(8). Celui-ci est déjà stable ; il n’est cependant pas compilé par défaut, suite à un manque de documentation mais également à une configuration qui doit être ré-écrite, afin de coller à la syntaxe des autres daemons d’OpenBSD. Pour compiler npppd(8) :
$ cd /usr/src/usr.sbin/npppd
$ make
$ sudo make install

Pour compiler npppdctl(8), son outil de contrôle :
$ cd /usr/src/usr.sbin/npppctl
$ make
$ sudo make install

Créer le fichier npppd.conf (issu du HOWTO évoqué précédemment) :
interface_list: tun0
interface.tun0.ip4addr: 10.0.0.1
pool.dyna_pool: 10.0.0.0/25
pool.pool: 10.0.0.128/25
auth.local.realm_list: local
auth.local.realm.acctlist: /etc/npppd/npppd-users.csv
realm.local.concentrate: tun0
lcp.mru: 1400
auth.method: mschapv2 chap
pptpd.enabled: true
pptpd.ip4_allow: 0.0.0.0/0
l2tpd.enabled: true
l2tpd.ip4_allow: 0.0.0.0/0
l2tpd.require_ipsec: false

Adapter ce fichier à votre convenance, en particulier les paramètres :

  • interface_list : l’interface tun(4) à utiliser, « tun0 » si aucun autre tunnel n’existe.
  • interface.tunX.ip4addr : l’adresse de l’interface tun(4).
  • pool.dyna_pool : la plage dynamique des IP attribuées à vos utilisateurs.
  • pool.pool : la plage utilisée pour les utilisateurs disposant d’adresses statiques (précisé plus bas).
  • realm.local.concentrate : doit correspondre à l’interface tun(4) configurée précédemment.

Créer le fichier npppd-users.csv (issu du HOWTO évoqué précédemment) :
Username,Passwd,IP-Address,IP-Netmask,Descr,Calling-Id
user1,user1's secret,10.0.0.129,,memo for user1

Ce fichier contiendra les noms d’utilisateurs, leur mot de passe, l’adresse IP statique qui leur est affectée, ainsi que des informations optionnelles.

Une fois ces fichiers créés et ajustés à vos besoins, placez-les à l’endroit approprié :
$ sudo mkdir -m 0755 /etc/npppd
$ sudo cp npppd.conf /etc/npppd/
$ sudo cp npppd-users.csv /etc/npppd/

Ensuite, nous pouvons démarrer npppd(8) :
$ sudo npppd -D

5. Confiruration IPsec

Sous OpenBSD, la configuration IPsec est extrêmement simple et se trouve centralisée dans le fichier /etc/ipsec.conf. Éditer ce fichier, pour y ajouter la configuration IPsec :
ike dynamic esp transport \
proto udp from AA.AA.AA.AA (192.168.0.1) to any port 1701 \
aggressive auth "hmac-sha" enc "3des" group modp1024 \
quick auth "hmac-sha" enc "aes" \
srcid "server@my.domain" dstid "client@my.domain" \
psk "myandroidpsk"

Quelques précisions :

  • dynamic : aide les configurations dans lequel le client a une IP qui change constemment.
  • AA.AA.AA.AA : adresse IP publique de la connexion internet de notre passerelle VPN.
  • 192.168.0.1 : adresse IP privée de notre passerelle VPN.
  • aggressive : ce mode est nécessaire lors de l’utilisation d’ID spécifiques pour la connexion.
  • srcid "server@my.domain" : ID IPsec du serveur, utilisé comme identité de la passerelle.
  • dstid "client@my.domain" : ID IPsec du client, à configurer dans le client VPN du smartphone.

Note : ici, nous utilisons des ID spécifiques (srcid et dstid) car par défaut, les ID utilisés sont les IP des machines : c’est-à-dire les IP privées du smartphone et de la passerelle sur leur réseau respectif. Or, nos deux connexions à internet (celle du smartphone et celle de la passerelle VPN) sont derrière du NAT. Donc les ID utilisés par défaut ne sont pas reconnus par la machine distante, puisque la machine locale ne voit que l’IP publique de la machine distante.

Une fois la configuration IPsec effectuée, il faut :

  • Démarrer l’interface virtuelle enc(4), sur laquelle le trafic IPsec déchiffré va circuler,
  • Démarrer le ‘daemon’ isakmpd(8) qui a pour but d’assurer la gestion des clés IPsec avec le protocole IKEv1,
  • Charger la configuration IPsec.

Cela se traduit par les commandes :
$ sudo ifconfig enc0 up
$ sudo isakmpd -Kv
$ sudo ipsecctl -f /etc/ipsec.conf

6. Le filtrage avec PF

Je ne vais pas détailler l’utilisation de Packet Filter (PF), le filtre de paquets d’OpenBSD ; pour celà vous pouvez vous référer à l’excellente FAQ de PF.

Je vais par contre détailler les points importants concernant notre utilisation dans le cadre de cette passerelle VPN L2TP/IPsec.

PF est maintenant activé par défaut dans OpenBSD, il est seulement nécessaire d’éditer sa configuration qui se fait dans le fichier /etc/pf.conf.

Tout d’abord, commençons par établir quelques variables utiles :
# Interface réseau physique
$ext_if = vr3
# Interface réseau virtuelle tun(4)
$tun_if = tun0
# Plage des clients VPN
$vpn_net = "10.0.0.0/24"
# Ports pour IPsec en UDP
$serv_udp = "{ isakmp, ipsec-nat-t }"
# Ports pour IPsec en TCP ainsi que SSH pour le management
$serv_tcp = "{ ssh, ipsec-nat-t }"

Notre règle par défaut bloque tout en entrée, mais pas en sortie ; par défaut avec PF, ce qui n’est pas bloqué est autorisé :
block in all

Ensuite, définissons une règle de NAT pour que les clients VPN qui arrivent sur l’interface virtuelle, puissent sortir sur l’interface physique, et donc les réseaux locaux de notre passerelle (et internet).
match out on $ext_if inet from $vpn_net nat-to $ext_if

Passons maintenant au filtrage à proprement dit. Commençons par autoriser le trafic IPsec sur notre interface physique :

  • Le protocole ESP (le trafic L2TP chiffré avec IPsec),
  • Les protocoles IKEv1 et NAT-Traversal pour les échanges de clés

Cela se traduit par les règles :
pass in on $ext_if proto esp to $ext_if
pass in on $ext_if proto udp to $ext_if port $serv_udp
pass in on $ext_if proto tcp to $ext_if port $serv_tcp

Puis, autorisons le trafic déchiffré, c’est à dire le trafic L2TP venant du smartphone vers notre passerelle, à passer sur l’interface enc(4) :
pass in on enc0 proto udp to $ext_if port l2tp keep state (if-bound)

Note : le mot clé ‘keep state (if-bound)’ est nécessaire sur une interface enc(4). Il permet de lier l’état créé dans PF à l’interface enc0 (par défaut, les états sont flottants), évitant ainsi d’avoir des flux non chiffrés sur d’autres interfaces.

Pour finir, autorisons le trafic utile de notre VPN : le trafic encapsulé dans le VPN, à destination de notre réseau local, d’internet, etc. à entrer sur l’interface virtuelle tun0. Celui-ci sera ensuite automatiquement routé vers la bonne interface :
pass in on $tun_if inet proto { icmp, tcp, udp } from $vpn_net

7. Rendre permanente la configuration

Pour configurer l’interface enc0 à chaque démarrage :
$ sudo sh -c "echo up > /etc/hostname.enc0"
$ sudo chmod 640 /etc/hostname.enc0

Pour démarrer isakmpd(8) au démarrage, ajouter ces lignes au fichier /etc/rc.conf.local :
ipsec=YES
isakmpd_flags="-K"

Pour démarrer npppd(8) automatiquement, ajouter ces lignes au fichier /etc/rc.local :
echo -n 'starting site daemons:'
if [ -x /usr/sbin/npppd ] ; then
/usr/sbin/npppd -D
echo -n ' npppd'
fi
echo '.'

8. Configuration du client

La configuration d’un VPN sur un téléphone Android est très simple. Pour cela, allons dans les paramètres, puis les paramètres sans fil, puis dans la section VPN :

01_parametres.png02_sans_fil.png03_ajout_VPN.png

Ajoutons maintenant un nouveau VPN en sélectionnant le type « L2TP/IPsec PSK », puis remplissons les données que nous avons indiquées précédemment :

04_l2tpipsec_psk.png

  • Nom : peut être ce que vous souhaitez,
  • Type : doit être « L2TP/IPsec PSK »,
  • Adresse du serveur : l’adresse IP publique de votre connexion internet ou alors votre nom de domaine si vous en possédez un,
  • Secret L2TP : laissez vide,
  • Identifiant IPsec : doit correspondre à ce que vous avez indiqué pour le paramètre « dstid » dans le fichier /etc/ipsec.conf de la passerelle,
  • Clé pré-partagée IPsec : doit correspondre à ce que vous avez indiqué pour le paramètre « psk » dans le fichier /etc/ipsec.conf de la passerelle.

Une fois les paramètres renseignés, démarrons la connexion, en fournissant le nom d’utilisateur et le mot de passe indiqués dans le fichier npppd-users.conf :

05_connexion.png

La connexion VPN est démarrée une fois que la petite clé est présente dans la barre de notification en haut à gauche :

06_connecte.png

9. Gestion de la passerelle

Pour avoir une vision de ce qu’il se passe en temps réel sur notre passerelle VPN, deux commandes sont très utiles.

Tout d’abord, pour consulter les sessions IPsec en cours et en particulier la Security Association Database (SAD) :
$ sudo ipsecctl -sa
FLOWS:
flow esp in proto udp from BB.BB.BB.BB to 192.168.0.1 peer BB.BB.BB.BB srcid server@my.domain dstid client@my.domain type use
flow esp out proto udp from 192.168.0.1 to BB.BB.BB.BB peer BB.BB.BB.BB srcid server@my.domain dstid client@my.domain type require

SAD:
esp transport from 192.168.0.1 to BB.BB.BB.BB spi 0x026f944d auth hmac-sha1 enc aes-256
esp transport from BB.BB.BB.BB to 192.168.0.1 spi 0x20510079 auth hmac-sha1 enc aes-256

Et ensuite pour consulter les sessions L2TP démarrées dans npppd(8) ainsi que des statistiques utiles :
$ sudo npppctl session all
Ppp Id = 14
Ppp Id : 14
Username : user1
Realm Name : local
Concentrated Interface : tun0
Assigned IPv4 Address : 10.0.0.129
Tunnel Protocol : L2TP
Tunnel From : BB-BB-BB-BB.romanichel.net:43682
Start Time : 2012/02/15 16:48:57
Elapsed Time : 114 sec (1 minute)
Input Bytes : 3214 (3.1 KB)
Input Packets : 45
Input Errors : 0 (0.0%)
Output Bytes : 6861 (6.7 KB)
Output Packets : 25
Output Errors : 0 (0.0%)

Note : Depuis OpenBSD 5.2, un certain nombre de corrections ont été apportées. Voici une configuration /etc/ipsec.conf qui devrait mieux fonctionner (testé avec Android 4.1 Jelly Bean) :
ike passive esp transport \
proto udp from AA.AA.AA.AA (192.168.0.1) to any port 1701 \
aggressive auth "hmac-sha" enc "aes" group modp1024 \
quick auth "hmac-sha" enc "aes" \
srcid "server@my.domain" dstid "client@my.domain" \
psk "myandroidpsk"

5 réponses to “Passerelle VPN L2TP/IPsec pour smartphone avec OpenBSD”

  1. xtalex a dit:

    Bonjour Matthieu,

    As-tu testé ta configuration avec un iPhone ? Je n’arrive pas à la faire fonctionner avec une architecture comme la tienne.

    La configuration VPN L2TP de l’iPhone est différente de celle d’Android. J’ai pourtant mis le « srcid » comme « Account » mais la connexion échoue. J’ai les messages d’erreur suivants :

    234918.291902 Default udp_create: no address configured for « peer-default »
    234918.291921 Default exchange_establish: transport « udp » for peer « peer-default » could not be created
    234918.715080 Default exchange_setup_p1: expected exchange type AGGRESSIVE got ID_PROT

    Je n’ai aucun souci sans NAT (des deux côtés) et donc sans srcid et dstid.

    As-tu une idée ? Merci d’avance.

  2. mattieu a dit:

    Bonjour,

    La conf IPsec est la même que celle que je donne dans l’article ?
    Je vais faire le test sur un iPhone les prochains jours, je te tiens au courant.

  3. xtalex a dit:

    Bonjour Matthieu,

    Oui j’ai la même configuration.

    Lorsque je passe en main au lieu de aggressive (j’ai une IP fixe côté serveur). J’obtiens aussi l’erreur :

    Default ike_phase_1_recv_ID: received remote ID other than expected client@my.domain.

    J’ai le même problème sous Mac OS X également. J’ai l’impression que le dstid n’est pas transmis (que j’ai mis dans le champ « Compte » du côté client), et je n’arrive pas à voir ce qui est envoyé à la place même en log/debug.

    Merci.

  4. mattieu a dit:

    D’après ce que je vois de la configuration d’iPhone (je n’ai pas d’iPhone sous la main), il faut renseigner :
    – Account : le nom d’utilisateur (celui dans /etc/npppd/npppd-users.csv)
    – Password : le mot de passe (celui dans /etc/npppd/npppd-users.csv)
    – Secret : la PSK.

    Je me suis probablement avancé, il ne semble pas que l’interface de configuration du client intégré à l’iPhone permette de renseigner le « dstid » IPsec, contrairement au client Android.

    Je ferai des tests ce week end, je devrais avoir accès à un iPhone.

  5. xtalex a dit:

    Oui j’ai essayé aussi au départ comme tu l’indiques, mais je ne pouvais pas établir de connexion non plus..

    J’attends ton retour suite à ton test. Merci.

Laisser un commentaire

Vous devez être connecté pour laisser un commentaire.