Updated Modifié

Nous sommes dans le futur, la transition avec IPv6 est terminée, ne subsiste que quelques machines encore en IPv4 seulement. Le but de ce projet est de permettre des communications entre îlots IPv4 au sein d’un monde IPv6. Dans une première partie, on utilisera des tunnels simples au-dessus de IPv6.

Mode Opératoire

Le projet se déroule en binôme ou trinôme (du même groupe de TP) sur l’ensemble des séances de TP restantes plus une soutenance le jeudi 23 novembre 2023 après-midi. Vous devrez respecter l’ensemble des instructions données dans ce sujet ainsi que les dates de rendu des livrables.

0.1. Livrables

Vos livrables contiendront une archive sous forme zip ainsi qu’un fichier pdf décrivant votre travail et répondant aux questions du sujet.

Dates :

  • lundi 30 octobre 18h: inscription des binômes sur AMETICE
  • vendredi 10 novembre 18h : livrable intermédiaire (archive zippée de votre dépôt git), correspondant au minimum à la partie 1 et aux premières parties de la partie 2 à déposer sur AMETICE
  • jeudi 23 novembre: livrable final, à déposer avant 19h00 (aucun dépôt ultérieur possible) sur AMETICE
  • Soutenance : jeudi 23 novembre 2023 après-midi

0.2. Présentation du code

Le choix du langage est libre (parmi C, java, ou python). Pensez à expliquer pourquoi vous avez retenu l’un plutôt que l’autre.

A priori C ou python sont sans doute plus avantageux étant donnée l’utilisation des appels systèmes. Voir la FAQ, si vous souhaitez utiliser java.

Une attention particulière sera portée à la lisibilité du code, les commentaires sont indispensables. Un soin particulier sera porté à la modularité du code.

Il est indispensable de mettre proprement en place des tests, fonctionnels a minima.

Par exemple, en C, pour chaque partie on écrira un (ou plusieurs) fichiers .h et .c correspondant. L’exécutable principal pour tester la bibliothèque bibli (correspondant à bibli.c et bibli.h ) se nommera test_bibli sauf instructions explicites.

Un makefile permettra de compiler le code. En outre, pour chaque test de bibliothèque, une cible tester_bibli sera ajouté qui lancera le programme test_bibli une ou plusieurs fois avec des paramètres adéquats.

Il est conseillé de bien organiser votre travail : un gestionnaire de versions comme git est indispensable.

0.3. Rendu

Le rendu s’effectuera sur AMETICE.

Notez que vous pouvez rendre plusieurs versions de votre projet tant que vous ne validez pas définitivement.

Aucun fichier ne sera accepté par courriel.

0.4. Soutenance

La soutenance consiste à une démonstration de votre système. Vous avez 12 min de préparation, 8 minutes de présentation + 4 minutes de questions. La présentation pourra suivre l’ordre des parties de l’énoncé et des tests associés. Il n’est pas demandé de présenter votre code (celui-ci sera évalué ultérieurement) mais plutôt le fonctionnement des tunnels. Pensez à préparer des fichiers de configuration ou des scripts permettant de montrer plusieurs scénarios (avec autant de VMs que nécessaire) en temps limité.

Le déroulé pourra suivre le plan suivant:

  • tunnel: montrer quels tests fonctionnent
  • illuster concrètement la circulation d’un paquet donné.

1. Configuration Réseau

1.1. Topologie et Adressage

Notre point de départ est le réseau constitué des 6 machines virtuelles avec le plan d’adressage suivant (ne pas le mettre en place si vous ne l’avez pas fini au TP précédent).

LAN1 LAN2 LAN3 LAN4 LAN1-6 LAN2-6
réseau 172.16.2.128/28 172.16.2.160/28 172.16.2.144/28 172.16.2.176/28 fc00:1234:1::/64 fc00:1234:2::/64
VM1 172.16.2.131 172.16.2.151
VM2 172.16.2.132 172.16.2.162
VM3 172.16.2.163 172.16.2.183
VM1-6 172.16.2.156 auto
VM2-6 fc00:1234:1::26 fc00:1234:2::26
VM3-6 172.16.2.186 auto

Si l’on ne souhaite pas utiliser l’auto-configuration IPv6, on pourra utiliser fc00:1234:1::16 pour VM1-6 dans LAN1-6 et fc00:1234:2::36 pour VM3-6 dans LAN2-6.

1.2. Un grand malheur !

La machine VM2 s’est arrêtée ! VM1 n’a donc plus accès directement à VM3.

Mettre en place cette topologie ci-dessous.

Comment pourrait-on faire ? Nous allons relier nos deux îlots IPv4 via le réseau IPv6…

1.3. Mise en place du réseau

On commence par mettre en place le réseau qui servira à déployer notre système.

Vous pouvez soit reprendre et modifier votre réseau du TP 3.

2. L’interface virtuelle TUN

Afin de pouvoir injecter le trafic dans un tunnel, nous devons récupérer le trafic depuis l’espace noyau pour le mettre en espace utilisateur. Pour ceci, Linux offre la possibilité de créer des interfaces réseaux virtuelles TUN. Les paramètres réseau de ces interfaces pourront être configurées comme n’importe quelle interface. Vous devrez être root (via sudo) pour pouvoir créer l’interface.

Certaines parties du projet exigeant des droits root, elles seront donc à réaliser dans une machine virtuelle.

Si vous rencontrez de sérieux problèmes de quotas voir la FAQ Dans tous les cas, évaluer votre place disponible

2.1. Création de l’interface

En lisant préalablement le code exemple de la documentation (section 3), utiliser le code tunalloc.c qui crée une telle interface virtuelle pour créer une bibliothèque iftun. Le nom de l’interface pourra être défini à l’exécution. Prendre "tun0" pour les tests de cette partie.

NB l’interface n’est pas persistante par défaut et disparaît dès que le processus l’ayant créée termine : mettre votre programme en pause permet de pouvoir configurer tun0.

2.2. Configuration de l’interface

  1. Configurer l’interface tun0 avec l’adresse 172.16.2.1, mettre un masque adéquat. Ecrire un script configure-tun.sh reprenant vos commandes de configuration.
  2. Routage : Suite à la disparition tragique de VM2, faut-il modifier les informations de routage sur VM1 ? ou sur VM1-6 ?
  3. Faire un ping 172.16.2.1. Donner la capture sur tun0 (avec wireshark). Que constatez-vous ?
  4. Faire ping 172.16.2.10. Que constatez-vous ?
  5. Expliquez.

2.3. Récupération des paquets

A la création de tun0, un descripteur de fichier est renvoyé (cf l’exemple). C’est ce descripteur qui permet de lire ce qui est envoyé à l’interface par un appel read.

  1. Compléter la bibliothèque iftun avec une fonction avec deux descripteurs de fichiers en paramètres src et dst, qui, étant donné un descripteur src correspondant à une interface TUN, recopie perpétuellement toutes les données lisibles sur src dans le fichier décrit par dst.

  2. Tester avec dst=1 (sortie standard). Comme ce qui est recopié est du binaire, on filtrera la sortie du programme de test avec hexdump. Par exemple en faisant
    VM$ test_iftun tun0 | hexdump -C
    

  3. Refaire ping 172.16.2.1 puis ping 172.16.2.10. Comparer et expliquer. Quel type de trafic voyez-vous? Refaire une capture avec wireshark dans le second cas et comparer avec ce qui est obtenu par votre programme test_iftun.

  4. A quoi sert l’option IFF_NO_PI ? Que ce passe-t-il si vous ajoutez cette option lors de la création de l’interface ?

3. Un tunnel simple pour IPv4

Le but de cette partie est de créer un tunnel simple encapsulant un trafic IPv4 dans des paquets TCP/IPv6.

3.1. Redirection du trafic entrant

On utilisera par défaut le port 123.

Dans cette partie, on créera une bibliothèque extremite qui gérera le trafic entre extrémités du tunnel.

  1. Ecrire une fonction ext-out qui crée un serveur écoutant sur le port 123, et redirige les données reçues sur la sortie standard.

  2. Ecrire une fonction ext-in qui ouvre une connexion TCP avec l’autre extrémité du tunnel, puis lit le trafic provenant de tun0 et le retransmet dans la socket.
  1. La commance nc (netcat) permet de transférer des données sur un port réseau. Pour le support simple d’envoi IPv4 sur vos VMs, il est possible d’installer éventuellement netcat. L’option -u permet d’envoyer en UDP (puisque votre tunnel est unidirectionnel pour l’instant).

    VM$ nc -u fc00:1234.1 123 
    

    1. Mettre en place une extrémité ext-in et une extrémité ext-out sur deux VMs distinctes.
    2. Tester avec un “client” ping 172.16.2.10 pour injecter du trafic comme dans la partie précédente.

3.2. Redirection du trafic sortant

  1. Compléter la fonction ext-out de la bibliothèque extremite pour créer une extrémité qui retransmet le trafic provenant de la socket TCP dans le tun0 local.
  2. Que devrait-il se passer alors pour ce trafic ? Indication : Que se passe-t-il lorsque l’on écrit dans le fichier correspondant à (au descripteur de) tun0?
  3. Vérifier avec l’un de vos paquets capturés dans le cas précédent. Pensez à le modifier éventuellement (avec un éditeur hexadécimal) pour que cela corresponde à tous vos paramètres réseau.
  4. Proposer des tests de connectivité. Tester et vérifier !

Indication : Les commandes nc/nc6 (netcat) permet également de transférer le contenu d’un fichier sur un port réseau

VM$ nc6 IPDEST 123 < fichier.bin

Indication : Que se passe-t-il si le paquet est modifié sans modifier le CRC? Comment pourrait-on calculer le nouveau CRC ?

Indication : Vous pouvez également utiliser comme données à écrire le fichier suivant.

3.3. Intégration Finale du Tunnel

  1. Compléter la bibliothèque pour pouvoir avoir un flux bidirectionnel

  2. Assurez-vous que les communications sont bien asynchrones.

3.4. Mise en place du tunnel entre VM1-6 et VM3-6 : Schémas

On veut utiliser VM1-6 et VM3-6 pour pouvoir faire un tunnel entre LAN3 et LAN4.

  • Compléter le schéma simplifié en expliquant en détail le parcours complet d’un paquet.

3.5. Mise en place du tunnel entre VM1 et VM3 : Système

  1. Créer un exécutable tunnel46d qui, en s’appuyant sur la bibliothèque extremite crée un service offrant un tunnel TCP bidirectionnel.

    Cet exécutable lira sa configuration dans un fichier de la forme suivante:
    # interface tun
    tun=tun0
    # adresse locale 
    inip=
    inport=
    options=
    # adresse distante
    outip=
    outport=
    

    Il pourra appeler le script de configuration réseau avec ces paramètres une fois que l’interface est créée. Il est également possible de faire des appels systèmes directs avec ioctl.
  1. Tester en configurant et lançant tunnel46d sur deux VMs différentes.

  2. Comparer le trafic direct et celui passant par le tunnel.

4. Validation Fonctionnelle

Il s’agit des tests minimaux à mettre en oeuvre pour valider votre tunnel.

4.1. Configuration

Sur VM1-6, VM1,VM2-6,VM3,VM3-6, afficher les paramètres réseaux significatifs avec ip addr et ip route.

4.2. Couche 3

Depuis VM1, effectuer ping 172.16.2.183. Proposer éventuellement d’autre tests au niveau “Réseau”.

4.3. Couche 4

Depuis VM1, créer un fichier “msg.txt” puis l’envoyer sur le service echo de VM3.

VM1$ echo "Test" > msg.txt
VM1$ nc 172.16.2.183  VOTREPORTECHO < msg.txt

4.4. Couche 4 : bande passante

Afin de tester les performances réseaux, nous allons utiliser l’utilitaire iperf3, qui permet de tester les performances d’une connexion.

Ce banc d’essai fonctionne en mode client/serveur, lancer le serveur sur VM3

VM3$ iperf3 -s

Tester avec un petit, un moyen, un gros et un très gros tampon.

VM1-6$ iperf3  -c 172.16.2.183 -n 1 -l 10
VM1-6$ iperf3  -c 172.16.2.183 -n 1 -l 2K
VM1-6$ iperf3  -c 172.16.2.183 -n 1 -l 128K
VM1-6$ iperf3  -c 172.16.2.183 -n 1 -l 1M

4.5. Couche 4 : facultatif

Proposer éventuellement d’autres tests afin de valider votre système.

Indication : En consultant notamment la documentation de iperf3, on pourra s’intéreser à l’évolution de la bande passante au cours du temps, à la gestion de la congestion, à la fragmentation, au MTU, à la gestion des TTL, etc…

5. Améliorations

Implémenter au moins l’une de ces améliorations.

5.1. Configuration ansible

Peut-on mettre en place le déploiement du tunnel via ansible. Quelles seraient les difficultés ? Proposer une solution et la mettre en oeuvre.

5.2. Une amélioration simple

Il est possible d’ajouter en tête du paquet la taille de celui-ci sur deux octets avant de l’envoyer dans le tunnel. A la sortie du tunnel, cette information est utilisée pour attendre tous les octets avant de les envoyer à l’interface virtuelle.

  1. Compléter la bibliothèque traitement en ajoutant des méthodes taillentete_in et taillentête_out permettant de mettre en place ce prétraitement.
  2. La taille du paquet étant donné dans l’entête IP, écrire un traitement tailleauto qui n’ajoute pas d’entête mais tient compte de la taille par lecture du champ taille de l’entête du paquet encapsulé.

5.3. Fragmentation et Réassemblage

Au lieu de mettre en attente les données comme dans le cas précédent, on peut gérer explicitement la fragmentation au niveau des extrémités du tunnel.

  1. Ajoute des méthodes frag_in et frag_out permettant de mettre en place un tel traitement.

5.4. Tunnels entre VMs

  1. Comment faire pour réaliser un tunnel entre VMs situés sur des hôtes différents ?

    Indication : Penser à utiliser la redirection de port de virtualbox.

  2. Faire une démonstration de communication par un tel tunnel entre un serveur echov6 et un client echov6 situé sur des VMs qui n’hébergent pas tunnel64d.

6. FAQ

6.1. Comment ouvrir un shell en root ?

Utiliser sudo -s

6.2. Le JRE est différent entre la machine hôte et la VM

Oui, notez qu’il est possible de spécifier la version cible à la compilation.

$ javac -source 1.7 -target 1.7 -bootclasspath /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar code.java

6.3. Java, ce n’est pas la fête pour les appels système

Le code java est compilé vers une machine virtuelle JAVA, ce qui rend le code portable d’un système d’exploitation à l’autre. Mais si vous souhaitez faire des appels système, il faudra sans doute utiliser JNA, ou encore JNI. pour accéder directement au système d’exploitation sous-jacent.

Notez également que dans tous les cas, vous pouvez faire les appels système en C, puis, par un appel exec(), passer la main (et surtout les descripteurs de fichiers) à un programme écrit dans un autre langage.

6.4. Les interfaces TUN n’apparaissent pas dans l’interface graphique

Il faudra utiliser ip link show pour les voir. Vous pouvez les configurer via ip a ... (puis via ansible).

6.5. Comment envoyer un seul paquet ICMP avec ping ?

Utiliser l’option -c : ping -c 1 123.45.67.89

6.6. Les paquets lus sur tun0 sont incomplets ?

Attention le paramètre MTU de votre interface (en général 1500) doit correspondre à votre propre traitement : si vous utilisez un tampon intermédiaire de taille inférieure au MTU, les données manquées seront perdues et vos paquets tronqués (c’est le même pĥénomène pour des sockets en mode datagramme).

Attention la MTU choisie doit être compatible avec IPv6.

6.7. Les commandes de configuration de tun0 échouent : “RTNETLINK answers: Network is down“

Il est possible qu’une manipulation malencontreuse ait désactivé tun0. Vous pouvez le voir avec

$ ip addr show tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
[...]

Pour remettre l’interface en fonctionnement, il faut faire

$ ip link set tun0 up

6.8. J’ai mis en place la redirection de ports sur virtualbox mais le ping/ping6 ne fonctionne pas ?

La redirection de port pour passer un NAT/PAT ne fonctionne que pour le protocole TCP.