Première rédaction de cet article le 3 septembre 2011
Dernière mise à jour le 14 septembre 2011
Si vous voulez connecter un réseau local à l'Internet IPv6, mais que vous êtes coincé derrière un FAI qui ne fournit encore, en 2011, qu'IPv4, que faire ? La solution évidente est de configurer un tunnel vers un fournisseur de connectivité IPv6. Ce cas est bien connu et on trouve d'innombrables HOWTO et articles de blog sur ce sujet. Mais, que faire si le routeur d'entrée du site n'a pas IPv6, et que la machine qui pourrait servir de routeur IPv6 n'a pas d'adresse IPv4 publique ? Simple, il suffit de créer un deuxième tunnel, entre le routeur d'entrée de site et le routeur IPv6, et de faire tourner le second tunnel sur le premier...
Le cas réel m'est arrivé à l'université de Yaoundé 1 pour une formation sur IPv6. Le Cameroun a pour l'instant zéro connectivité IPv6. L'université n'a que peu d'adresses IPv4 publiques mais il y en avait quand même une de disponible pour établir un tunnel « IPv6 dans IPv4 » (protocole 41) avec un fournisseur de connectivité IPv6 comme l'excellent Hurricane Electric. Le seul problème est que, pour des raisons matérielles, le réseau où se trouvaient les machines à adresse publique ne permettait pas de nouvelle installation. Dans ce réseau, un routeur Cisco 2800 aurait pu servir de routeur IPv6 (l'excellente interface Web de Hurricane Electric fournit des instructions IOS qu'on n'a qu'à copier/coller ou bien on peut utiliser ce tutoriel). Mais ce Cisco-là n'avait pas IPv6, protocole qui nécessite une licence spéciale (baptisée Advanced quelque chose) et une image d'IOS nouvelle. Après une heure passée à naviguer dans les options incompréhensibles du site Web de Cisco, pour essayer de trouver un moyen de mettre à jour la machine, nous avons renoncé.
Bon, il faut donc mettre le routeur IPv6 sur un PC Debian. Il y a encore plus de documentation pour ce système, et cela a l'avantage d'utiliser du logiciel libre. Mais il y avait des limites matérielles : pas de PC avec deux cartes Ethernet disponible, pas de possibilité de le mettre dans la salle machines, etc, qui ont mené à une deuxième décision : le routeur IPv6 sur PC reste dans les salles où se trouvent les autres PC de l'université, et on va créer un tunnel entre lui et le Cisco, « apportant » l'adresse IPv4 publique dont a besoin Hurricane Electric jusqu'à ce PC.
Donc, les acteurs vont être :
216.66.80.26
et IPv6
2001:470:1f08:1c8f::1
.172.16.0.76
et adresse IPv4
publique41.204.94.222
, en IPv6,
2001:470:1f08:1c8f::2
. Le réseau alloué à
l'unversité de Yaoundé est
2001:470:1f09:1c8f::/64
(avec les adresses IPv6, ouvrez
l'œil : 1f08 n'est pas 1f09).41.204.93.101
.
Le problème est donc de permettre à la machine d'HE (Hurricane
Electric) d'atteindre 41.204.94.222
. J'ai choisi
un tunnel GRE (RFC 2784)
pour sa simplicité, et son caractère normalisé (tout le monde sait
faire du GRE). Si le tunnel, au lieu d'être limité à l'université,
s'était étendu sur un réseau public, il aurait été plus prudent de le
protéger par la cryptographie. Mes
followers sur Twitter ont voté massivement pour OpenVPN mais, ici, GRE suffit.
Pour l'intérieur du tunnel GRE, j'ai choisi les adresses IP
192.0.2.1
(pour le Cisco) et
192.0.2.2
(pour le PC). Attention si vous tentez
une expérience similaire : il faut vraiment y aller par étapes, en
testant soigneusement le résultat à chaque étape. Autrement, le
débogage est cauchemardesque.
On va d'abord dire au Cisco de créer son côté du tunnel GRE, sur l'interface Tunnel0
:
int tunnel 0 ip address 192.0.2.1 255.255.255.0 tunnel source 41.204.93.101 tunnel destination 172.16.0.76 exit ip route 41.204.94.222/32 tunnel0
Ainsi, IOS envoit désormais les paquets qu'il reçoit pour
41.204.94.222
à 172.16.0.76
,
en GRE. Côté du PC destinataire, on va configurer l'interface tun0
:
ip tunnel add tun0 mode gre remote 41.204.93.101 local 172.16.0.76 ttl 255 ip link set tun0 up ip addr add 192.0.2.2 dev tun0 ip route add 192.0.2.1/24 dev tun0
puis mettre l'adresse IPv4 publique sur une interface
dummy0
:
ifconfig dummy0 up ifconfig dummy0 41.204.94.222/32
Attention, avec ce système, le routage est asymétrique. Un paquet
entrant passera par l'interface tun0
alors que la
réponse sortira par le normal eth0
. On peut
changer la table de routage pour forcer le passage par le tunnel GRE,
ou bien on peut tout simplement débrayer le contrôle du routage
asymétrique (qui est activé par défaut sur Debian, pour limiter les
risques d'usurpation d'adresses IP) en mettant les variables
sysctl
net.ipv4.conf.all.rp_filter
et
net.ipv4.conf.default.rp_filter
à 0. Autrement,
vous verrez les paquets être mystérieusement jetés par Linux.
Et voilà, le tunnel GRE fonctionne. Depuis tout l'Internet, on peut
pinguer 41.204.94.222
, bien que la machine soit
reléguée loin du routeur d'entrée, dans une zone uniquement RFC 1918. Un autre avantage de GRE est que tcpdump le
connait et l'analyse très bien, rendant bien plus facile le
débogage. Voici un exemple de paquet qui passe par le tunnel. On a
capturé le trafic sur l'interface Ethernet et on voit les paquets GRE
entre 41.204.93.101
(le routeur Cisco) et
172.16.1.2
(le PC à l'autre bout du tunnel
GRE). Ici, le trafic dans le tunnel était une connexion
SMTP depuis 66.216.133.144
vers 41.204.94.222
:
12:11:21.894937 IP 41.204.93.101 > 172.16.1.2: GREv0, length 56: \ IP 66.216.133.144.26892 > 41.204.94.222.25: \ Flags [S], seq 1940136218, win 8192, options [mss 1380,nop,wscale 8,nop,nop,sackOK], length 0
Via l'interface Web d'Hurricane Electric (qui teste la connectivité effective avec l'adresse donnée, donc la configuration préalable de GRE était nécessaire), on peut créer le tunnel IPv6-dans-IPv4. Reste à le configurer sur le PC (le Cisco n'a plus rien à faire, il laissera passer ce qu'il prend pour des paquets IPv4 normaux).
Les instructions de HE sont simples, on utilise une interface
nommée he-ipv6
:
ip tunnel add he-ipv6 mode sit remote 216.66.80.26 local 41.204.94.222 ttl 255 ip link set he-ipv6 up ip addr add 2001:470:1f08:1c8f::2/64 dev he-ipv6 ip route add ::/0 dev he-ipv6
La première ligne configure le tunnel IPv6-dans-IPv4. Notez que, grâce
à l'autre tunnel, celui en GRE, la machine croit que
216.66.80.26
est directement joignable.
On a donc bien deux tunnels emboîtés :
% ip tunnel show tun0: gre/ip remote 41.204.93.101 local 172.16.0.76 ttl 255 he-ipv6: ipv6/ip remote 216.66.80.26 local 41.204.94.222 ttl 255 6rd-prefix 2002::/16
À partir de là, IPv6 passe : on peut faire un ping6 -n
www.ietf.org
, on peut regarder le serveur Web du RIPE-NCC et voir
en haut à droite qu'on utilise bien IPv6, etc. Là encore, si cela ne
marche pas, les outils classiques, tcpdump,
ping et traceroute sont
là. Voici le trafic sur le câble physique Ethernet, vu par tcpdump :
12:11:24.217673 IP 41.204.94.222 > 216.66.80.26: \ IP6 2001:470:1f09:1c8f:21c:23ff:fe00:6b7f > 2001:660:3003:2::4:20: \ ICMP6, echo request, seq 3, length 64 12:11:24.364372 IP 41.204.93.101 > 172.16.1.2: GREv0, length 128: \ IP 216.66.80.26 > 41.204.94.222: \ IP6 2001:660:3003:2::4:20 > 2001:470:1f09:1c8f:21c:23ff:fe00:6b7f: \ ICMP6, echo reply, seq 3, length 64
On y voit 2001:470:1f09:1c8f:21c:23ff:fe00:6b7f
(la machine interne) pinguer
2001:660:3003:2::4:20
(un serveur quelque part
sur l'Internet). On voit bien le routage asymétrique. La requête a été
encapsulée une seule fois, dans le tunnel Hurricane Electric (de
41.204.94.222
vers
216.66.80.26
). La réponse, en revanche, a été
encapsulée deux fois, dans le tunnel Hurricane Electric, puis dans le
tunnel GRE. On note que tcpdump n'a pas de problème avec cette double
encapsulation et arrive à décapsuler sans problème, affichant ce qui
passe dans le tunnel.
Si on regardait, toujours avec tcpdump, non pas sur l'interface
physique eth0
mais sur les interfaces virtuelles
du tunnel (option -i
de tcpdump), on verrait
directement le trafic IPv6.
Mais, pour l'instant, seul le routeur IPv6, notre brave PC/Debian,
peut profiter de l'Internet en IPv6. Les autres machines du réseau
local n'y ont pas droit. Notre PC n'est pas encore un routeur. Pour
cela, il faut d'abord activer le routage IPv6 en mettant les variables
sysctl
net.ipv6.conf.all.forwarding
et
net.ipv6.conf.default.forwarding
à 1 (cela peut
se faire avec la commande sysctl - option -w - ou bien en éditant
/etc/sysctl.conf
et en rechargeant les paramètres avec sysctl -p
). Autrement,
la machine jetterait sans remords les paquets IPv6 qui ne lui sont pas
destinés.
Ensuite, il faut créer une route vers le réseau local, soit en dotant le routeur d'une adresse de ce réseau, soit simplement en ajoutant une route :
ip route add 2001:470:1f09:1c8f::/64 dev eth0
Enfin, il faut prévenir les machines du réseau local qu'un routeur
IPv6 est là pour les servir. Cela se fait en envoyant des RA
(Router Advertisment, RFC 4862). J'ai installé le paquetage Debian
radvd
qui fournit ce service. La configuration
est triviale :
# /etc/radvd.conf interface eth0 { AdvSendAdvert on; prefix 2001:470:1f09:1c8f::/64 {}; };
Et c'est magique : toutes les machines du réseau local, par le biais
de ces RA, reçoivent le préfixe du réseau et l'adresse du
routeur. Désormais, tout le monde peut faire un traceroute6 www.afnic.fr
.
La plaie traditionnelle des tunnels est qu'ils diminuent la MTU (à cause des quelques octets nécessaires pour l'en-tête du protocole d'encapsulation). Cela va donc souvent imposer de la fragmentation qui, en raison de l'incompétence de certains ingénieurs système qui bloquent l'ICMP, marche souvent mal sur l'Internet. Alors, avec deux tunnels emboîtés, cela risque d'être encore pire. Mais, si tout est correctement configuré (en gros, si on laisse ICMP passer sur tout le chemin), tout se passe bien. Testons depuis l'extérieur en demandant à ping des paquets plus gros que d'habitude pour qu'ils dépassent, avec les octets des en-têtes, la MTU :
% ping6 -s 1450 2001:470:1f09:1c8f:21d:92ff:fe7f:e0ab PING 2001:470:1f09:1c8f:21d:92ff:fe7f:e0ab(2001:470:1f09:1c8f:21d:92ff:fe7f:e0ab) 1450 data bytes From 2001:470:0:67::2 icmp_seq=1 Packet too big: mtu=1480 From 2001:470:0:67::2 icmp_seq=3 Packet too big: mtu=1456 1458 bytes from 2001:470:1f09:1c8f:21d:92ff:fe7f:e0ab: icmp_seq=5 ttl=59 time=138 ms 1458 bytes from 2001:470:1f09:1c8f:21d:92ff:fe7f:e0ab: icmp_seq=6 ttl=59 time=141 ms
Tout s'est bien passé. Les messages packet too big
montrent que les paquets ICMP émis par le routeur d'entrée du tunnel
(deux messages, un par tunnel) sont bien arrivés, ping en a tenu
compte et tout fonctionne. (Pour les paquets émis depuis le réseau
local, on pourrait s'épargner cela en configurant
radvd
pour n'indiquer qu'une MTU assez petite
pour passer dans le tunnel.)
PS : ce réseau étant de nature expérimental, ne vous étonnez pas si vous testez les adresses et que cela « ne marche pas ».
Quelques lectures possibles :
Merci à Janvier Ngnoulaye pour sa patience et sa participation active et compétente.
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)