<?xml version="1.0" encoding="utf-8"?>
<rfcdesc title="Stateful NAT64: Network Address and Protocol Translation from IPv6 Clients to IPv4 Servers" num="6146" status="standards" wg="behave">
<authors><author>M. Bagnulo (UC3M)</author><author>P. Matthews (Alcatel-Lucent)</author><author>I. van Beijnum (IMDEA Networks)</author></authors>
<rfcdate><month>April</month><year>2011</year></rfcdate>
<date>2011-04-28</date>
<content>
<p>Dans la grande série des techniques de coexistence entre
<wikipedia>IPv4</wikipedia> et <wikipedia>IPv6</wikipedia>, voici une
normalisation de <emphasis>NAT64</emphasis>, une technique de
traduction entre IPv6 et IPv4, permettant à une machine purement IPv6
de se connecter à une machine purement IPv4. Ce
<wikipedia name="Request for comments">RFC</wikipedia> fait partie de la série introduite par le
document d'architecture générale <rfc num="6144" local="true"/>.</p>
<p>Aujourd'hui, l'état de l'<wikipedia>Internet</wikipedia> est que la
majorité des serveurs sont accessibles uniquement en IPv4. Or, les
dernières adresses IPv4 disponibles à l'<wikipedia name="Internet Assigned Numbers Authority">IANA</wikipedia>
ont été distribuées le <link local="epuisement-adresses-ipv4">3 février
2011</link>. Demain, les nouvelles machines recevront donc de plus
en plus uniquement des adresses IPv6. Comment se connecteront-elles à
ces serveurs purement v4 ? Une des solutions est de traduire
automatiquement les paquets IPv6 du client en IPv4 pour les envoyer au
serveur, et de faire la traduction inverse au retour. Cela se nomme
<wikipedia xml:lang="en" name="IPv6 transition mechanisms" anchor="NAT64">NAT64</wikipedia> et notre RFC normalise la version « à
état » de cette méthode. « À état » car le traducteur garde un
souvenir des flux de données en cours et peut donc, pour la
traduction, tenir compte d'un état, des paquets précédents (la version
sans état est dans le <rfc num="7915" local="true"/>).</p>
<p>Notez le titre de ce <wikipedia name="Request for comments">RFC</wikipedia> : ses ambitions
sont limitées, il ne s'agit pas, comme l'essayait le défunt
<wikipedia xml:lang="en" name="IPv6 transition mechanisms" anchor="NAT-PT">NAT-PT</wikipedia> (<rfc num="2766"/>) de fournir
une solution générale à tous les problèmes de communication v4-v6 mais
seulement de permettre à des <emphasis>clients</emphasis> IPv6 de se
connecter à des <emphasis>serveurs</emphasis> IPv4.</p>
<p>NAT64 ressemble beaucoup à l'actuel <link local="nats">NAT44</link>
(celui que tout le monde est obligé d'utiliser à l'hôtel, chez lui s'il
a plusieurs machines, cf. <rfc num="3022" local="false"/>) dans la
mesure où il permet :
<enum>
<item>Aucune modification au client ou au serveur, tout est fait dans
le routeur du réseau IPv6-pur,</item>
<item>Les communications client-serveur, comme le titre de notre RFC
le précise,</item>
<item>Certaines communications <wikipedia>pair-à-pair</wikipedia>, en
utilisant des techniques comme <wikipedia xml:lang="en" name="Interactive Connectivity Establishment">ICE</wikipedia> (<rfc
num="5245" local="true"/>),</item>
<item>Des communications lancées depuis l'extérieur, si on a configuré
statiquement le traducteur pour reconnaître certaines adresses.</item>
</enum>
Il s'en distingue par le fait qu'on ne se contente pas de traduire les
adresses, il faut traduire tout l'en-tête du paquet, et par le fait
que, pour que les applications tournant sur la machine purement IPv6
trouvent une adresse IPv6, un serveur <wikipedia name="Domain Name System">DNS</wikipedia>
spécial, <wikipedia xml:lang="en" name="IPv6 transition mechanisms" anchor="DNS64">DNS64</wikipedia> (<rfc num="6147" local="true"/>) est
nécessaire. Vu la nécessité de faire plus de travail qu'en NAT44, la
spécification ne fonctionne que pour certains protocoles des couches
supérieures, pour l'instant uniquement <wikipedia name="Internet Control Message Protocol">ICMP</wikipedia>,
<wikipedia name="User Datagram Protocol">UDP</wikipedia> et <wikipedia name="Transmission Control Protocol">TCP</wikipedia>. Ne comptez
donc pas faire, par exemple, du <wikipedia name="Stream Control Transmission Protocol">SCTP</wikipedia>.</p>
<p>Notre RFC s'appuie sur plusieurs autres documents, celui
d'architecture (<rfc num="6144" local="true"/>), celui sur la traduction
des adresses (<rfc num="6052" local="true"/>), et celui sur
l'algorithme de traduction (<rfc num="7915" local="true"/>).</p>
<p>Les équipements qui font faire le travail sont donc :
<enum>
<item>Le traducteur, qui sera typiquement embarqué dans le routeur
(<wikipedia name="Customer Premises Equipment">CPE</wikipedia>,
<foreign><wikipedia name="Box (Internet)">box</wikipedia></foreign>, ou bien plus loin dans
le réseau de l'opérateur),</item>
<item>Le résolveur DNS64, qui pourra être inclus dans le même routeur
ou bien fourni séparement.</item>
</enum>
Normalement, les traducteurs qui suivront ce RFC seront conformes aux
recommandations qu'avait édicté le <link local="behave-wg">groupe de
travail Behave</link>, dans sa première version, à savoir les <rfc
num="4787" local="true"/>, <rfc num="5382" local="true"/>, <rfc
num="5508" local="false"/>... et ils permettront les techniques de
passage au travers des <wikipedia name="Network Address Translation">NAT</wikipedia> comme
<wikipedia xml:lang="en" name="Interactive Connectivity Establishment">ICE</wikipedia> (<rfc num="5245" local="true"/>).</p>
<p>La norme elle-même commence en section 3 mais une gentille
introduction, utilisable si vous ne connaissez pas grand'chose aux
NAT, figure en section 1.2. Essayons de la résumer sommairement en
prenant pas mal de raccourcis : le traducteur a
donc deux interfaces, une vers le réseau IPv6-pur et une vers un
réseau IPv4 (et peut-être aussi IPv6 mais, dans ce cas, pas besoin de
traduction). Le traducteur doit donc avoir une adresse IPv4
publique. Lorsqu'il reçoit un paquet IPv6 dont l'adresse de
destination indique qu'il doit être traduit, il le transforme en IPv4
(l'adresse IPv4 est encapsulée dans l'adresse IPv6), et l'envoie par
l'interface IPv4. Au retour, c'est un peu plus dur car l'adresse IPv4
de destination est celle du traducteur et, pour retrouver l'adresse IPv6 du vrai
destinataire, il doit consulter une table où il a stocké les clients
IPv6 qui parlaient à l'extérieur. Comme en NAT44, le numéro de
<wikipedia name="Port (logiciel)">port</wikipedia> est utilisé pour reconnaitre les clients
locaux. La combinaison d'une adresse IP et d'un port est appelée
« adresse de transport ». On le voit, cela ne marche bien que si c'est
le réseau IPv6 qui initie la communication (mais diverses astuces
permettent des communications un peu plus pair-à-pair).</p>
<p>Le NAT64 devrait donc être appelé <wikipedia xml:lang="en">NAPT</wikipedia>
(<foreign>Network Address AND PORT Translation</foreign>) car, dans
l'écrasante majorité des cas, le traducteur n'aura pas assez
d'adresses IPv4 pour tous les clients IPv6 qu'il sert (si on avait
assez d'adresses v4, il n'y aurait guère de raison de migrer vers
v6).</p>
<p>Comment le client IPv6 a-t-il trouvé l'adresse IPv6 de destination,
puisque le serveur n'a qu'une adresse IPv4 ? C'est le rôle du serveur
DNS64 qui ment (pour la bonne cause) en fabriquant un enregistrement
<wikipedia name="Domain Name System">DNS</wikipedia> de type <wikipedia xml:lang="en" name="List of DNS record types" anchor="AAAA">AAAA</wikipedia>
(adresse IPv6) à partir de l'enregistrement réel
<wikipedia xml:lang="en" name="List of DNS record types" anchor="A">A</wikipedia> (adresse IPv4). Les étapes complètes
effectuées par le client sont décrites en section 1.2.2<!-- TODO le résumer ? -->.</p>
<p>On a vu que cette opération nécessitait de réserver une partie de
l'espace d'adressage IPv6 pour représenter les adresses IPv4. Cette
partie peut être localement définie (après tout, seuls le traducteur
et le résolveur DNS64 auront besoin de la connaître) ou bien on peut
utiliser le préfixe standard <computer>64:FF9B::/96</computer>.
Ici, on voit un serveur DNS64 et un traducteur coopérer pour permettre
à une machine purement IPv6 de communiquer avec
<computer>www.example.com</computer>, qui n'a qu'une adresse IPv4 : <image name="nat64"/>.
</p>
<p>Du fait que le traducteur a un état, tous les paquets IPv4 venus de
l'extérieur ne sont pas acceptés. Seuls peuvent être transmis ceux qui
correspondent à une correspondance existante, en suivant les règles
des <rfc num="4787" local="true"/> et <rfc num="5382" local="true"/>
(<foreign>Endpoint-Independent Filtering</foreign> et
<foreign>Address-Dependent Filtering</foreign> ; suivre ces règles est
important pour que les applications <wikipedia>pair-à-pair</wikipedia>
fonctionnent).</p>
<p>Voilà pour l'introduction. Maintenant, pour lire la spécification
elle-même, il faut d'abord bien apprendre la terminologie, en section
2. Quelques termes qui ne sont sans doute pas familiers à tous :
<enum>
<item>Un <emphasis>quintuplet</emphasis> est l'identificateur d'une
session TCP ou UDP. Il est composé de {adresse IP source, port source,
adresse IP destination, port destination, protocole de
<wikipedia>couche 4</wikipedia>}.</item>
<item>La <emphasis>BIB</emphasis> (<foreign>Binding Information
Base</foreign>) est la liste des communications actuellement en cours,
pour un protocole de transport donné. Une liaison
(<foreign>binding</foreign>) est faite entre une adresse de transport
IPv4 et une IPv6, afin de déterminer à qui « appartient » un paquet
entrant dans le traducteur. Les liaisons peuvent être établies
automatiquement, lorsque le premier paquet passe, ou bien manuellement. Voir la section 3.1.</item>
<item>Un virage en <wikipedia name="Virages en lacets">épingle à cheveux</wikipedia> désigne le
cas où deux machines situées du même côté du traducteur communiquent
via le traducteur, qui doit alors renvoyer le paquet par là d'où il
est venu (cf. section 3.8).</item>
<item>Une <emphasis>adresse de transport</emphasis> est le doublet
formé d'une adresse IP et d'un <wikipedia name="Port (logiciel)">port</wikipedia>. Comme le
traducteur aura moins d'adresses IPv4 que de clients, l'ajout du port
est nécessaire pour différencier les sessions, lorsqu'un paquet IPv4
arrive.</item>
</enum>
</p>
<p>Vous avez bien retenu tout le vocabulaire ? Alors, vous pouvez lire
la norme elle-même, à partir de la section 3. Quelques points
importants à retenir :
<enum>
<item>NAT64 doit garder une table des <emphasis>sessions</emphasis>
TCP et UDP en cours, pour pouvoir déterminer leur fin (et donc la
suppression des liaisons associées).</item>
<item>Chaque entrée de la BIB peut être associée à plusieurs sessions
et il ne faut donc la supprimer que lorsque la dernière session est
finie.</item>
<item>La <wikipedia name="IP fragmentation" xml:lang="en">fragmentation</wikipedia> pose des défis
particuliers. Un traducteur NAT64 conforme à la norme doit gérer les
fragments, même s'ils arrivent dans le désordre. Il doit donc faire du
réassemblage (en limitant toutefois les ressources allouées à cette
tâche, pour se protéger contre les attaques
<wikipedia name="Attaque par déni de service">DoS</wikipedia> ; voir les <rfc num="1858"/>, <rfc
num="3128"/> et <rfc num="4963"/>). Le traducteur a aussi le droit d'ajouter
quelques contraintes comme le fait que tout l'en-tête TCP doit être
dans le premier fragment.</item>
<item>Comme le NAT64 avec état n'est défini que pour TCP, UDP et ICMP,
le traducteur doit jeter les paquets des autres protocoles (en
prévenant la source, via un paquet ICMP).</item>
<item>Le traducteur ayant une connaissance des sessions actives, il
peut jouer un rôle de filtre en bloquant les paquets ne correspondant
pas à une telle session.</item>
<item>Déterminer qu'une session est finie n'est pas forcément
évident. Ainsi, si la fin d'une session TCP est facile à observer
(échange des paquets <computer>FIN</computer> par les deux parties),
que faire pour une « session » UDP puisqu'il n'y a pas de connexion et
donc pas de fin explicite ? La solution est d'utiliser une minuterie,
remise à zéro par chaque paquet, et qui se déclenche après un certain
temps d'inactivité, coupant la session UDP.</item>
<item>Pour TCP, la section 3.5.2 décrit en détail les événements de la
<wikipedia name="Automate fini">machine à états</wikipedia> de TCP que le traducteur doit
observer pour découvrir début et fin de la session. Elle est très
longue et détaillée, j'espère que les programmeurs des routeurs bas de
gamme à 60 dollars prendront le temps de la lire !</item>
<item>Les règles de conversion des adresses IPv4 en IPv6 et
réciproquement sont celles du <rfc num="6052" local="true"/>.</item>
</enum>
</p>
<p>Vous avez noté qu'à plusieurs reprises, j'ai utilisé des termes
vagues comme « un certain temps ». Les valeurs numériques recommandées
pour les diverses constantes sont en section 4. Ainsi, avant de fermer
une session UDP, le traducteur doit attendre (par défaut) au moins
cinq minutes (cf. <rfc num="4787" local="true"/>), le traducteur doit
attendre les fragments manquants au moins deux secondes, etc.</p>
<p>Cette technique du NAT64 améliore-t-elle ou aggrave-t-elle les
problèmes de sécurité ? D'abord, cette section note que toute solution
de sécurité de bout en bout qui protège l'en-tête IP contre les
modifications (par exemple l'<wikipedia name="Authentication Header">AH</wikipedia>
d'<wikipedia name="Internet Protocol Security">IPsec</wikipedia>) va être cassée par NAT64, qui modifie
précisément l'en-tête. Si le NAT64 est obligatoire, IPsec peut, par
exemple, utiliser l'encapsulation UDP (<rfc num="3948"/>). La section
5 insiste d'autre part sur le fait qu'un traducteur n'est pas un
<wikipedia name="Pare-feu (informatique)">pare-feu</wikipedia> et que le filtrage réalisé par effet
de bord de la gestion d'état n'est <link local="nat-et-securite">pas forcément adapté à la
sécurité</link>.</p>
<p>D'autre part, NAT64 a ses propres vulnérabilités. Les principales
sont le risque d'attaques par <wikipedia name="Attaque par déni de service">déni de
service</wikipedia>. Par exemple, un attaquant situé à l'intérieur
(côté IPv6) peut utiliser toutes
les adresses (en général une seule) et ports disponibles et empêcher
ainsi l'accès des autres utilisateurs. Une autre attaque possible est
d'envoyer régulièrement des paquets de façon à maintenir une liaison
active et d'empêcher le traducteur de relâcher des ressources. Une
protection possible serait de ne remettre à zéro la minuterie que si
le paquet qui passe vient de l'intérieur (supposé plus fiable).</p>
<p>Quelles implémentations existent aujourd'hui ? <link url="http://www.viagenie.ca/">Viagénie</link>
en à une en <wikipedia>logiciel libre</wikipedia>, voir <link url="http://ecdysis.viagenie.ca/"/>.
Le terme de <foreign xml:lang="el">ecdysis</foreign> désigne la
<wikipedia>mue des arthropodes</wikipedia> puisque NAT64 permet à IP
de muer vers un nouveau protocole...
Voici un exemple d'installation et d'usage :
c'est un module noyau, donc il
faut installer les paquetages qui permettent la compilation de modules
noyau. Sur une <wikipedia>Debian</wikipedia> version « squeeze » avec
le noyau <wikipedia>Linux</wikipedia> 2.6.32-5 :
<code>
% sudo aptitude install linux-headers-2.6.32-5-686 linux-kbuild-2.6.32
...

% make
/bin/sh: [[: not found
make -C /lib/modules/2.6.32-5-686/build M=/home/stephane/tmp/ecdysis-nf-nat64-20101117 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-5-686'
  CC [M]  /home/stephane/tmp/ecdysis-nf-nat64-20101117/nf_nat64_main.o
  CC [M]  /home/stephane/tmp/ecdysis-nf-nat64-20101117/nf_nat64_session.o
  CC [M]  /home/stephane/tmp/ecdysis-nf-nat64-20101117/nf_nat64_config.o
  LD [M]  /home/stephane/tmp/ecdysis-nf-nat64-20101117/nf_nat64.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/stephane/tmp/ecdysis-nf-nat64-20101117/nf_nat64.mod.o
  LD [M]  /home/stephane/tmp/ecdysis-nf-nat64-20101117/nf_nat64.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.32-5-686'

% sudo make install
...

# On peut éditer le script avant pour changer les paramètres...
% sudo ./nat64-config.sh
</code>
Ensuite, on peut vérifier que tout s'est bien passé en regardant la
table de routage :
<code>
% netstat -r -n  -Ainet6
Kernel IPv6 routing table
Destination                    Next Hop                   Flag Met Ref Use If
64:ff9b::/96                   ::                         U    1024 0     0 nat64
...
</code>
Parfait, les paquets pour le préfixe NAT64 sont bien routés à
part. Tentons notre chance :
<code>
% telnet 64:ff9b::453f:bd0b
Trying 64:ff9b::453f:bd0b...
</code>
Et on voit bien les paquets IPv6 sur l'interface nat64 :
<code>
21:18:58.910669 IP6 2a01:e35:8bd9:8bb0:304b:5a4b:3b8c:7b1c.37033 > \
         64:ff9b::453f:bd0b.23: Flags [S], seq 3580860303, win 5760, \
           options [mss 1440,sackOK,TS val 23731660 ecr 0,nop,wscale 6], length 0
</code>
Et les IPv4 sur l'interface normale :
<code>
21:19:09.263613 IP 192.168.2.1.37038 > \
         69.63.189.11.23: Flags [S], seq 4043093045, win 5760, \
           options [mss 1440,sackOK,TS val 23734248 ecr 0,nop,wscale 6], length 0
</code>
</p>
<p>Un déploiement expérimental de NAT64 est <link
url="https://labs.ripe.net/Members/raimis/experimental-nat64-dns64-service/view">celui
du réseau de la recherche lituanien</link>. Voir <link
url="http://ipv6.lt/nat64_en.php">leur site Web</link>.</p>
<p>Pour un récit très détaillé, avec plein de technique, d'un test de
NAT64 avec DNS64, voir l'article de Jérôme Durand « <link
url="http://ipv6blog.cisco.fr/2011/09/26/jai-teste-pour-vous-stateful-nat64-avec-dns64/">J'ai
testé pour vous : Stateful NAT64 avec DNS64</link> ».</p>
</content>
</rfcdesc>
