<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://vincent.riquer.fr/blog/"?>
<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:admin="http://webns.net/mvcb/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Vincent Riquer</title>
<atom:link href="http://vincent.riquer.fr/blog/rss.xml" rel="self" type="application/rss+xml" />
<link>http://vincent.riquer.fr/blog</link>
<description>mini-Howtos, astuces, et bidouilles</description>
<dc:language>fr</dc:language>
<dc:creator>Vincent Riquer</dc:creator>
<dc:date>2011-09-30T15:58:52+02:00</dc:date>
<admin:generatorAgent rdf:resource="http://nanoblogger.sourceforge.net" />
<item>
<link>http://vincent.riquer.fr/blog/archives/2011/05/09/ipv4_vs__ipv6_renumérotation_de_réseau_en_adressage_dynamique/index.html</link>
<guid isPermaLink="true">http://vincent.riquer.fr/blog/archives/2011/05/09/ipv4_vs__ipv6_renumérotation_de_réseau_en_adressage_dynamique/index.html</guid>
<title>IPv4 vs. IPv6: Renumérotation de réseau en adressage dynamique</title>
<dc:date>2011-05-09T12:10:34+02:00</dc:date>
<dc:creator>Vincent Riquer</dc:creator>
<dc:subject>Bricolage</dc:subject>
<description>
<![CDATA[
<h2>Processus classique (IPv4 DHCP)</h2>

<ol>
<li>On configure DHCP avec la nouvelle plage.</li>
<li>Les machines renouvellent leur bail avec un DHCPREQUEST.</li>
<li>Le DHCP répond NAK.</li>
<li>Le client déconfigure son adresse.</li>
<li>Client et serveur font la série DHCPDISCOVER / DHCPOFFER / DHCPREQUEST /
DHCPACK</li>
</ol>

<h3>Impact</h3>

<ul>
<li>Les connexions existantes sont cassées</li>
<li>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</li>
</ul>

<h2>Processus moderne (IPv6 Router Advertisements)</h2>

<ol>
<li>On configure le routeur avec la nouvelle plage.</li>
<li>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 :)</li>
<li>À expiration de ce délai, les clients suppriment leur ancienne adresse.</li>
</ol>

<h3>Impact</h3>

<ul>
<li>Les connexions existantes surivent pendant la durée de validité de l'ancienne
adresse. Ça ne devrait pas poser de soucis donc.</li>
<li>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)</li>
</ul>

<h2>Conclusion</h2>

<p>IPv6 Saybien™</p>]]>
</description>
</item>
<item>
<link>http://vincent.riquer.fr/blog/archives/2010/04/11/openvpn__ipv6__bind__happiness/index.html</link>
<guid isPermaLink="true">http://vincent.riquer.fr/blog/archives/2010/04/11/openvpn__ipv6__bind__happiness/index.html</guid>
<title>OpenVPN + IPv6 + Bind = Happiness</title>
<dc:date>2010-04-11T17:06:30+02:00</dc:date>
<dc:creator>Vincent Riquer</dc:creator>
<dc:subject>Bricolage</dc:subject>
<description>
<![CDATA[<h1>Matériel nécessaire :</h1>
<ul>
<li>un routeur <code>GNU/Linux</code> (Debian ici)</li>
<li><code>OpenVPN</code></li>
<li><code>radvd</code> (envoi des <em>Router Advertisements</em>, pour
l'autoconfiguration <code>IPv6</code>)</li>
<li><code>Bind</code></li>
<li><code>ipv6calc</code></li>
<li>un nom de domaine ou sous-domaine</li>
<li>un bloc <code>IPv6</code> suffisamment grand pour pouvoir sacrifier un /64
aux VPNs (conformément à la <a href="http://www.ietf.org/rfc/rfc3849.txt">RFC
3849</a>, cette documentation utilise le bloc <code>2001:DB8::/32)</code></li>
<li>Idéalement, la délégation du <em>reverse</em> <code>IPv6</code></li>
<li><code>bash</code>, pour lier le tout</li>
</ul>

<h1>Configuration d'<code>OpenVPN</code></h1>
<p>
<em>RTFM</em> ! Je ne vais pas couvrir la configuration
d'<code>OpenVPN</code> ici, c'est déjà expliqué un peu partout sur la toile. Je
vais juste lister les paramètres spécifiques à notre projet.</p>
<p><code>OpenVPN</code> n'étant pas très doué pour l'<code>IPv6</code>, nous
allons devoir monter un tunnel de type <code>TAP</code> (Ethernet donc). En
effet, si le client supporte <code>IPv6</code> en mode <code>tun</code> (tunnel
IP) via l'option <code>tun-ipv6</code>, ceci n'est pas encore implémenté côté
serveur. Un tunnel <code>tap</code> encapsule de l'ethernet, ce qui nous permet
de passer n'importe quel protocole de couche 3, dont <code>IPv6</code>.
</p>

<h2>Côté concentrateur</h2>
<p>
Pour plus de lisibilité, je nomme l'interface <em>roadwarriors</em>. Très
important, nous allons demander à <code>OpenVPN</code> de maintenir un fichier
de statut, qui nous servira à générer nos zones DNS à grands coups de bash.
<br />

Ce qui nous donne quelque chose comme ceci :
</p>
<pre>
# 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'<code>OpenVPN</code> pour 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'<code>OpenVPN</code>
client-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
</pre>

<h2>Côté client</h2>
<p>
Ici, rien de bien particulier. À noter que j'ai dû employer la directive
<code>pull</code> pour que le client prenne en compte les paramètres
<em>poussés</em> par le serveur.
</p>
<p>
Une chose à noter : nous allons utiliser le <code>CommonName</code> 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.
</p>
<pre>
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
</pre>

<h2>Ça pingue ?</h2>
<p>
À cette étape, nous avons donc un concentrateur <code>OpenVPN</code> 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
<code>192.168.1.0/24</code>. 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.
</p>

<h1>Mettons de l'<code>IPv6</code> dans notre tunnel…</h1>
<p>Nous avons à notre disposition le bloc <code>2001:DB8::/32</code>. Il nous
faut choisir un <code>/64</code> dans ce bloc, mettons
<code>2001:DB8:2FC:3849::/64</code>.
</p>
<p>
La première étape consiste à assigner une adresse à l'interface VPN de notre
concentrateur :
</p>
<pre>
root@routeur:~# ip addr add 2001:DB8:2FC:3849::1/64 dev roadwarriors
</pre>
<p>
Fastoche!
</p>
<p>
Notre routeur a une adresse, mais pas notre client. Toute machine bien
configurée paramètre son <code>IPv6</code> à la réception d'un <em>Router
Advertisement</em>. Nous allons donc paramétrer notre concentrateur pour en
envoyer à ses clients.
</p>
<p>
Pour cette tâche, nous allons utiliser <code>radvd</code>. Il est également
possible d'utiliser <code>quagga</code>, ou <code>rtadvd</code>. Ce dernier a 
l'avantage d'être plus adapté aux systèmes pauvres en ressources, type routeurs 
WiFi.
</p>

<h2>Paramétrage de <code>radvd</code></h2>
<p>
Après avoir installé <code>radvd</code> 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
<code>/etc/radvd.conf</code> :
</p>
<pre>
interface roadwarriors {
    AdvSendAdvert on;
    prefix 2001:DB8:2FC:3849::/64
    {
        AdvOnLink on;
        AdvAutonomous on;
    };
};
</pre>

<h2>Lancement de <code>radvd</code></h2>
<p>
Si on ne veut pas se faire insulter par <code>radvd</code> au moment de son
lancement, il nous faut d'abord effectuer l'équivalent <code>IPv6</code> de
<code>sysctl net.ipv4.ip_forward=1</code> :
</p>
<pre>
root@routeur:~# sysctl net.ipv6.conf.all.forwarding=1
</pre>
<p>
On placera cette instruction dans <code>/etc/sysctl.conf</code> pour automatiser
ce paramétrage.
</p>
<p>
Reste maintenant à lancer <code>radvd</code> :
</p>
<pre>
root@routeur:~# /etc/init.d/radvd start
</pre>
<p>
Si tout va bien, notre client devrait configurer son interface
<code>IPv6</code>, ce que nous pouvons constater avec <code>ip</code> :
</p>
<pre>
user@client:~$ ip -6 addr show dev ipv6
31: ipv6: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; 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
</pre>

<h1>Et maintenant, le vrai fun : les zones DNS</h1>
<p>
Là, normalement, on est déjà assez fier de nous : on a monté un VPN et mis de
l'<code>IPv6</code> dedans malgré les limitations de l'outil utilisé. Mais
pourquoi s'arrêter en si bon chemin ? D'autant que notre client calcule son
<code>IPv6</code> par rapport à sa MAC, et celle-ci est différente à chaque
lancement d'<code>OpenVPN</code>… Bref, pas pratique, il nous faut un DNS. Et
pourquoi pas de la résolution inverse, tant qu'on y est ?
</p>

<h2>Le fichier <code>status.log</code> d'<code>OpenVPN</code></h2>
<p>
Plus haut, nous avons demandé à <code>OpenVPN</code> de créer un fichier de
statut, <code>roadwarriors-status.log</code>. Regardons le contenu de ce fichier
lorsque nous avons deux clients connectés :
</p>
<pre>
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
</pre>
<p>
Les informations sur les lignes commençant par <code>1e:71:[…]</code> et
<code>76:00:[…]</code> sont intéressantes, puisqu'elles contiennent, dans
l'ordre :
<ol>
<li>l'adresse <code>MAC</code> de l'interface VPN du client</li>
<li>le <em>Common Name</em> du certificat du client</li>
</ol>
</p>

<h2>Utilisons le fichier <code>status.log</code></h2>
<p>
Nous avons donc le nom du client, ainsi que son adresse <code>MAC</code>, à
partir de laquelle nous pouvons calculer l'<code>IPv6</code>. En effet, l'outil
<code>ipv6calc</code> permet, à partir du préfixe, que nous connaissons, et de
l'adresse <code>MAC</code>, donnée par ce fichier, l'adresse <code>IPv6</code>
que le client prendra en autoconfiguration. La syntaxe pour ce faire est :
</p>
<pre>
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
</pre>
<p>
<code>ipv6calc</code> permet également de calculer le <em>reverse</em> d'une
adresse <code>IPv6</code> :
</p>
<pre>
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.
</pre>
<p>
Nous avons donc le nom, l'adresse IP et le <em>reverse</em> 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.
</p>
<pre>
#!/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
} &
</pre>
<p>
Enregistrons ce script dans le répertoire de configuration
d'<code>OpenVPN</code> sous le nom <code>openvpn2named</code> et rendons-le
exécutable. Il ne nous reste maintenant qu'à configurer <code>OpenVPN</code>
pour qu'il appelle ce script à chaque nouvelle connexion, en ajoutant la
directive suivante à notre fichier de configuration :
</p>
<pre>
client-connect openvpn2named
</pre>
<p>
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é <code>configure_v6</code> :
</p>
<pre>
#!/bin/sh

{
    sleep 3
    ip a a 2001:db8:2fc:3849::1/64 dev roadwarriors
    invoke-rc.d radvd restart
} &
</pre>
<p>
et ajouter la directive suivante à notre concentrateur :
</p>
<pre>
up configure_v6
</pre>

<h1>Derniers détails</h1>
<h2><code>OpenVPN</code></h2>
<p>
<code>OpenVPN</code> n'accepte pas, par défaut, d'exécuter des scripts
arbitraires. Nous devons donc le forcer à accepter nos scripts avec la directive
<code>script-security</code>
</p>
<pre>
script-security 2
</pre>

<h2>Configuration de <code>Bind</code></h2>
<p>
Il ne nous reste plus qu'à configurer <code>Bind</code> pour qu'il utilise les
fichiers générés par notre script.
</p>
<pre>
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";
};
</pre>

<h1>C'est fini</h1>
<p>
Voilà, si tout s'est bien passé, il ne nous reste qu'à (re)lancer les démons
<code>OpenVPN</code> et <code>Bind</code>, et à connecter un client. Nous
devrions pouvoir résoudre son nom en adresse <code>IP</code> et son adresse
<code>IP</code> en nom. Sinon, bonne chance :)
</p>

<h1>Licence</h1>
<p>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/2.0/fr/">
<img alt="Creative Commons logo" src="http://vincent.riquer.fr/blog/images/cc0.gif" />
</a>
Cette documentation est distribuée sous licence Creative Commons BY-SA 2.0 Fr
</p>
<p>
Les scripts exécutables et les extraits de configuration sont sous licence
<a rel="license" href="http://sam.zoy.org/wtfpl/">WTFPL 2.0</a>
</p>]]>
</description>
</item>
</channel>
</rss>

