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
- 1. Configuration Réseau
- 2. L’interface virtuelle TUN
- 3. Un tunnel simple pour IPv4
- 4. Validation Fonctionnelle
- 5. Améliorations
- 6. FAQ
- 6.1. Comment ouvrir un shell en root ?
- 6.2. Le JRE est différent entre la machine hôte et la VM
- 6.3. Java, ce n’est pas la fête pour les appels système
- 6.4. Les interfaces TUN n’apparaissent pas dans l’interface graphique
- 6.5. Comment envoyer un seul paquet ICMP avec ping ?
- 6.6. Les paquets lus sur tun0 sont incomplets ?
- 6.7. Les commandes de configuration de tun0 échouent : “RTNETLINK answers: Network is down“
- 6.8. J’ai mis en place la redirection de ports sur virtualbox mais le ping/ping6 ne fonctionne pas ?
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
- Configurer l’interface
tun0
avec l’adresse172.16.2.1
, mettre un masque adéquat. Ecrire un scriptconfigure-tun.sh
reprenant vos commandes de configuration. - Routage : Suite à la disparition tragique de VM2, faut-il modifier les informations de routage sur VM1 ? ou sur VM1-6 ?
- Faire un
ping 172.16.2.1
. Donner la capture surtun0
(avecwireshark
). Que constatez-vous ? - Faire
ping 172.16.2.10
. Que constatez-vous ? - 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
.
- Compléter la bibliothèque
iftun
avec une fonction avec deux descripteurs de fichiers en paramètressrc
etdst
, qui, étant donné un descripteursrc
correspondant à une interface TUN, recopie perpétuellement toutes les données lisibles sursrc
dans le fichier décrit pardst
. - Tester avec
dst=1
(sortie standard). Comme ce qui est recopié est du binaire, on filtrera la sortie du programme de test avechexdump
. Par exemple en faisantVM$ test_iftun tun0 | hexdump -C
- Refaire
ping 172.16.2.1
puisping 172.16.2.10
. Comparer et expliquer. Quel type de trafic voyez-vous? Refaire une capture avecwireshark
dans le second cas et comparer avec ce qui est obtenu par votre programmetest_iftun
. - 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.
- Ecrire une fonction
ext-out
qui crée un serveur écoutant sur le port123
, et redirige les données reçues sur la sortie standard. - Ecrire une fonction
ext-in
qui ouvre une connexion TCP avec l’autre extrémité du tunnel, puis lit le trafic provenant detun0
et le retransmet dans la socket.
- 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 éventuellementnetcat
. L’option-u
permet d’envoyer en UDP (puisque votre tunnel est unidirectionnel pour l’instant).VM$ nc -u fc00:1234.1 123
- Mettre en place une extrémité
ext-in
et une extrémitéext-out
sur deux VMs distinctes. - Tester avec un “client”
ping 172.16.2.10
pour injecter du trafic comme dans la partie précédente.
- Mettre en place une extrémité
3.2. Redirection du trafic sortant
- Compléter la fonction
ext-out
de la bibliothèqueextremite
pour créer une extrémité qui retransmet le trafic provenant de la socket TCP dans letun0
local. - 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
? - 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.
- 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
- Compléter la bibliothèque pour pouvoir avoir un flux bidirectionnel
- 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
- Créer un exécutable
tunnel46d
qui, en s’appuyant sur la bibliothèqueextremite
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 avecioctl
.
- Tester en configurant et lançant
tunnel46d
sur deux VMs différentes. - 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.
- Compléter la bibliothèque
traitement
en ajoutant des méthodestaillentete_in
ettaillentête_out
permettant de mettre en place ce prétraitement. - 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.
- Ajoute des méthodes
frag_in
etfrag_out
permettant de mettre en place un tel traitement.
5.4. Tunnels entre VMs
- 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
. - 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.