lundi 9 mai 2011, 12:10:33 (UTC+0200)
IPv4 vs. IPv6: Renumérotation de réseau en adressage dynamique
Processus classique (IPv4 DHCP)
- On configure DHCP avec la nouvelle plage.
- Les machines renouvellent leur bail avec un DHCPREQUEST.
- Le DHCP répond NAK.
- Le client déconfigure son adresse.
- Client et serveur font la série DHCPDISCOVER / DHCPOFFER / DHCPREQUEST / DHCPACK
Impact
- Les connexions existantes sont cassées
- Quelque soit la façon dont on gère son DNS, il existe une fenêtre pendant laquelle les client n'obtiendront pas la bonne adresse
Processus moderne (IPv6 Router Advertisements)
- On configure le routeur avec la nouvelle plage.
- Les machines prennent une nouvelle adresse dans la nouvelle plage. L'ancienne adresse reste valide pendant une longue période, configurable au niveau des RA. 86400 secondes, soit 24h, par défaut avec radvd. La RFC 4861 recommande 30 jours :)
- À expiration de ce délai, les clients suppriment leur ancienne adresse.
Impact
- Les connexions existantes surivent pendant la durée de validité de l'ancienne adresse. Ça ne devrait pas poser de soucis donc.
- On a tout son temps pour gérer le DNS et les adresses qui traînent dans les fichiers de configuration. Si nécessaire on peut se donner plus de temps en augmentant la durée de validité des adresses avant d'effectuer la manip (AdvValidLifetime dans radvd.conf)
Conclusion
IPv6 Saybien™
dimanche 11 avril 2010, 17:06:30 (UTC+0200)
OpenVPN + IPv6 + Bind = Happiness
Matériel nécessaire :
- un routeur
GNU/Linux(Debian ici) OpenVPNradvd(envoi des Router Advertisements, pour l'autoconfigurationIPv6)Bindipv6calc- un nom de domaine ou sous-domaine
- un bloc
IPv6suffisamment grand pour pouvoir sacrifier un /64 aux VPNs (conformément à la RFC 3849, cette documentation utilise le bloc2001:DB8::/32) - Idéalement, la délégation du reverse
IPv6 bash, pour lier le tout
Configuration d'OpenVPN
RTFM ! Je ne vais pas couvrir la configuration
d'OpenVPN ici, c'est déjà expliqué un peu partout sur
la toile. Je vais juste lister les paramètres spécifiques à notre
projet.
OpenVPN n'étant pas très doué pour
l'IPv6, nous allons devoir monter un tunnel de type
TAP (Ethernet donc). En effet, si le client supporte
IPv6 en mode tun (tunnel IP) via l'option
tun-ipv6, ceci n'est pas encore implémenté côté
serveur. Un tunnel tap encapsule de l'ethernet, ce qui
nous permet de passer n'importe quel protocole de couche 3, dont
IPv6.
Côté concentrateur
Pour plus de lisibilité, je nomme l'interface
roadwarriors. Très important, nous allons demander à
OpenVPN de maintenir un fichier de statut, qui nous
servira à générer nos zones DNS à grands coups de bash.
Ce qui nous donne quelque chose comme ceci :
# Le choix importe peu ici proto tcp # Le nom de l'interface sur le routeur dev roadwarriors # On specifie un nom a l'interface, il faut donc preciser son type # (obligatoirement "tap", radvd ne connaît qu'Ethernet) dev-type tap # Configuration du TLS - Les secrets partages c'est mal tls-server # Voir la doc d'OpenVPNpour la configuration du TLS et # la creation des certificats ca ca-roadwarriors.crt cert roadwarriors.crt key roadwarriors.key dh dh1024.pem # On n'est pas radin, on donne aussi des IPv4 server 172.29.8.0 255.255.255.0 ifconfig-pool-persist ipp.txt push "route 192.168.1.0 255.255.255.0" # Notre LANv4 # blablabla - voir la doc d'OpenVPNclient-to-client comp-lzo persist-key persist-tun # Le précieux fichier que nous allons parser pour generer les zones status roadwarriors-status.log # Dans un premier temps, nous allons fonctionner en debug verb 5
Côté client
Ici, rien de bien particulier. À noter que j'ai dû employer la
directive pull pour que le client prenne en compte les
paramètres poussés par le serveur.
Une chose à noter : nous allons utiliser le
CommonName du certificat du client lors de la
génération des zones DNS. Il donc est préférable d'indiquer un nom
exploitable directement.
proto tcp-client
dev ipv6 # Ce coup ci, mon interface s'appelle ipv6, ce qui est somme toute
# logique
dev-type tap
tls-client
ca ca-roadwarriors.crt
cert Taff.vpn.example.com.crt
key Taff.vpn.example.com.key
remote fdn.example.com
comp-lzo
persist-key
persist-tun
verb 5
pull
Ça pingue ?
À cette étape, nous avons donc un concentrateur
OpenVPN et un client fonctionnel. Le client doit
pouvoir se connecter et recevoir une adresse du bloc indiqué plus
haut (ici 172.29.8.0/24), et recevoir la route vers
192.168.1.0/24. Si ce n'est pas le cas, inutile
d'aller plus loin. Examinez les logs et vérifiez votre
configuration, vos réglages OpenOffice^Wde parefeu, etc.
Mettons de l'IPv6 dans notre tunnel…
Nous avons à notre disposition le bloc
2001:DB8::/32. Il nous faut choisir un
/64 dans ce bloc, mettons
2001:DB8:2FC:3849::/64.
La première étape consiste à assigner une adresse à l'interface VPN de notre concentrateur :
root@routeur:~# ip addr add 2001:DB8:2FC:3849::1/64 dev roadwarriors
Fastoche!
Notre routeur a une adresse, mais pas notre client. Toute
machine bien configurée paramètre son IPv6 à la
réception d'un Router Advertisement. Nous allons donc
paramétrer notre concentrateur pour en envoyer à ses clients.
Pour cette tâche, nous allons utiliser radvd. Il
est également possible d'utiliser quagga, ou
rtadvd. Ce dernier a l'avantage d'être plus adapté aux
systèmes pauvres en ressources, type routeurs WiFi.
Paramétrage de radvd
Après avoir installé radvd suivant la méthode
préconisée par votre distribution, il reste à le configurer, tâche
relativement aisée pour une infrastructure basique. Cela se fait
dans le fichier /etc/radvd.conf :
interface roadwarriors {
AdvSendAdvert on;
prefix 2001:DB8:2FC:3849::/64
{
AdvOnLink on;
AdvAutonomous on;
};
};
Lancement de radvd
Si on ne veut pas se faire insulter par radvd au
moment de son lancement, il nous faut d'abord effectuer
l'équivalent IPv6 de sysctl
net.ipv4.ip_forward=1 :
root@routeur:~# sysctl net.ipv6.conf.all.forwarding=1
On placera cette instruction dans /etc/sysctl.conf
pour automatiser ce paramétrage.
Reste maintenant à lancer radvd :
root@routeur:~# /etc/init.d/radvd start
Si tout va bien, notre client devrait configurer son interface
IPv6, ce que nous pouvons constater avec
ip :
user@client:~$ ip -6 addr show dev ipv6
31: ipv6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 100
inet6 2001:DB8:2FC:3849:1c71:2aff:fe25:b828/64 scope global dynamic
valid_lft 2591850sec preferred_lft 604650sec
inet6 fe80::1c71:2aff:fe25:b828/64 scope link
valid_lft forever preferred_lft forever
user@client:~$ ip -6 route show
2001:DB8:2FC:3849::/64 dev ipv6 proto kernel metric 256 expires 2591939sec
mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0 proto kernel metric 256 mtu 1500 advmss 1440
hoplimit 4294967295
fe80::/64 dev ipv6 proto kernel metric 256 mtu 1500 advmss 1440
hoplimit 4294967295
default via fe80::2ff:51ff:fe25:84a4 dev ipv6 proto kernel metric 1024
expires 1577sec mtu 1500 advmss 1440 hoplimit 64
Et maintenant, le vrai fun : les zones DNS
Là, normalement, on est déjà assez fier de nous : on a monté un
VPN et mis de l'IPv6 dedans malgré les limitations de
l'outil utilisé. Mais pourquoi s'arrêter en si bon chemin ?
D'autant que notre client calcule son IPv6 par rapport
à sa MAC, et celle-ci est différente à chaque lancement
d'OpenVPN… Bref, pas pratique, il nous faut un DNS. Et
pourquoi pas de la résolution inverse, tant qu'on y est ?
Le fichier status.log d'OpenVPN
Plus haut, nous avons demandé à OpenVPN de créer un
fichier de statut, roadwarriors-status.log. Regardons
le contenu de ce fichier lorsque nous avons deux clients connectés
:
root@routeur:~# cat /etc/openvpn/roadwarriors-status.log OpenVPN CLIENT LIST Updated,Sun Apr 11 15:19:38 2010 Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since Abnethe.vpn.example.com,192.168.1.2:55604,17795,10178,Sun Apr 11 15:19:13 2010 Taff.vpn.example.com,80.14.205.176:55028,41653588,255794138,Wed Apr 7 18:49:16 2010 ROUTING TABLE Virtual Address,Common Name,Real Address,Last Ref 1e:71:2a:25:b8:28,Taff.vpn.example.com,80.14.205.176:55028,Sun Apr 11 15:17:24 2010 76:00:d5:51:d4:97,Abnethe.vpn.example.com,192.168.1.2:55604,Sun Apr 11 15:19:32 2010 GLOBAL STATS Max bcast/mcast queue length,5 END
Les informations sur les lignes commençant par
1e:71:[…] et 76:00:[…] sont
intéressantes, puisqu'elles contiennent, dans l'ordre :
- l'adresse
MACde l'interface VPN du client - le Common Name du certificat du client
Utilisons le fichier status.log
Nous avons donc le nom du client, ainsi que son adresse
MAC, à partir de laquelle nous pouvons calculer
l'IPv6. En effet, l'outil ipv6calc
permet, à partir du préfixe, que nous connaissons, et de l'adresse
MAC, donnée par ce fichier, l'adresse
IPv6 que le client prendra en autoconfiguration. La
syntaxe pour ce faire est :
user@host:~$ $ ipv6calc --in prefix+mac 2001:DB8:2FC:3849:: 1e:71:2a:25:b8:28 \
--out ipv6addr -A prefixmac2ipv6
2001:db8:2fc:3849:1c71:2aff:fe25:b828
ipv6calc permet également de calculer le
reverse d'une adresse IPv6 :
user@host:~$ ipv6calc --out revnibbles.arpa 2001:db8:2fc:3849:1c71:2aff:fe25:b828 No input type specified, try autodetection...found type: ipv6addr 8.2.8.b.5.2.e.f.f.f.a.2.1.7.c.1.9.4.8.3.c.f.2.0.8.b.d.0.1.0.0.2.ip6.arpa.
Nous avons donc le nom, l'adresse IP et le reverse du client, soit toutes les informations nécessaires pour générer une zone directe et une zone inverse, à l'aide d'un simple script shell. L'écriture des informations dans le fichier de status n'étant pas immédiate, nous allons devoir insérer un délai entre la connexion du client et la génération des zones.
#!/bin/bash
# Fichier contenant la zone direct
DIRECT=/tmp/direct
# zone inverse
REVERSE=/tmp/reverse
# préfixe ipv6
PREFIX=2001:db8:2fc:3849::
# inverse du préfixe IPv6
REVZONE=9.4.8.3.c.f.2.0.8.b.d.0.1.0.0.2.ip6.arpa.
# Domaine / sous-domaine des tunnels
ZONE=vpn.example.com.
# Serveurs autoritaires
NSNAME=ns0.example.com.
SECNSNAME=ns1.example.com.
# email de l'admin
ADMINMAIL=admin.email.tld.
# TTL - le plus court est le mieux dans notre cas
TTL=600
# Délai entre la connexion du client et la mise à jour des zones
DELAY=10
{
sleep $DELAY
echo "$ZONE $TTL IN SOA $NSNAME $ADMINMAIL" \
"$(date +%y%m%d%H%M) $TTL $TTL $TTL $TTL" > $DIRECT
echo -e "$ZONE $TTL IN NS $NSNAME\n$ZONE $TTL IN NS $SECNSNAME" >> $DIRECT
echo "$REVZONE $TTL IN SOA $NSNAME $ADMINMAIL" \
"$(date +%y%m%d%H%M) $TTL $TTL $TTL $TTL" > $REVERSE
echo -e "$REVZONE $TTL IN NS $NSNAME\n$REVZONE $TTL IN NS $SECNSNAME" >> $REVERSE
egrep '(..:){5}..' /etc/openvpn/roadwarriors-status.log \
| sed 's/\(.*\),\(.*\),.*,.*/\1 \2/' \
| while read mac host
do
echo -e $(ipv6calc --in prefix+mac $PREFIX $mac --out ipv6addr -A prefixmac2ipv6) $host
done \
| while read ip host ; do
echo $host. $TTL IN AAAA $ip >> $DIRECT
echo $(ipv6calc --out revnibbles.arpa $ip 2>/dev/null) $TTL IN PTR $host. >> $REVERSE
done
/etc/init.d/bind9 reload
} &
Enregistrons ce script dans le répertoire de configuration
d'OpenVPN sous le nom openvpn2named et
rendons-le exécutable. Il ne nous reste maintenant qu'à configurer
OpenVPN pour qu'il appelle ce script à chaque nouvelle
connexion, en ajoutant la directive suivante à notre fichier de
configuration :
client-connect openvpn2named
Dernier petit détail : nous avons dû configurer manuellement une
adresse IPv6 sur l'interface VPN du concentrateur. Pour ne pas
avoir à faire cette manipulation manuellement à chaque lancement,
nous allons créer dans le répertoire de configuration un script
nommé configure_v6 :
#!/bin/sh
{
sleep 3
ip a a 2001:db8:2fc:3849::1/64 dev roadwarriors
invoke-rc.d radvd restart
} &
et ajouter la directive suivante à notre concentrateur :
up configure_v6
Derniers détails
OpenVPN
OpenVPN n'accepte pas, par défaut, d'exécuter des
scripts arbitraires. Nous devons donc le forcer à accepter nos
scripts avec la directive script-security
script-security 2
Configuration de Bind
Il ne nous reste plus qu'à configurer Bind pour
qu'il utilise les fichiers générés par notre script.
zone "9.4.8.3.c.f.2.0.8.b.d.0.1.0.0.2.ip6.arpa. {
type master;
file "/tmp/reverse";
};
zone "vpn.example.com" {
type master;
file "/tmp/direct";
};
C'est fini
Voilà, si tout s'est bien passé, il ne nous reste qu'à
(re)lancer les démons OpenVPN et Bind, et
à connecter un client. Nous devrions pouvoir résoudre son nom en
adresse IP et son adresse IP en nom.
Sinon, bonne chance :)
Licence
Cette
documentation est distribuée sous licence Creative Commons BY-SA
2.0 Fr
Les scripts exécutables et les extraits de configuration sont sous licence WTFPL 2.0