Labo 2 : Equipements réseaux virtuels basé sur les namespaces Linux ========================================================================== Les **namespaces** permettent une virtualisation extrêmement légère et sans nécessité de support par le matériel au niveau du CPU : conceptuellement, il s'agit d'une simple indirection logicielle supplémentaire associée à un processus, implémentée au sein du noyau du système d'exploitation. Concrètement, si on se réfère uniquement à la pile TCP/IP, on peut probablement instancier des dizaines de milliers de piles TCP/IP indépendantes sur un PC typique, alors qu'on sera rapidement limité à une centaine de VM si on virtualise l'ensemble de la machine avec qemu, virtualbox ou autre. Dans ce laboratoire, nous allons mettre en oeuvre les **namespaces réseau** linux au travers de la commande ``ip`` du package debian ``iproute2``. Ils permettent d'instancier une pile TCP/IP entière et de l'associer à un ensemble de processus, c'est à dire virtualiser au niveau de l'OS une ressource dédiée uniquement au réseau. Nous utiliserons cette fonctionnalité pour instancier un routeur virtuel hosté par un autre routeur en se basant sur les namespaces réseaux du kernel Linux. Ce laboratoire est divisé en 3 parties : - Préparation de la configuration du routage et de l'adressage de la topologie sans routeur virtuel. - Mise en oeuvre des **namespaces réseau** sous Linux pour instancier un routeur dans un routeur. - Implémenter une variante basée sur les bridges en instanciant un routeur virtuel dont les interfaces réseaux sont bridgées avec celles de l'hôte. - Généraliser l'idée à deux routeurs virtuels exécutés sur la même machine. 1 - Topologie ********************* Téléchargez le labo :download:`router_in_router <../source/gns3/router_in_router.gns3project>`. Vous devriez obtenir la topologie indiquée en figure :numref:`figrouterinrouter`. Utilisez votre script écrit dans le labo précédent pour installer l'accès SSH sur les machines R1 et H1 et leur donner un ``hostname`` correspondant à celui indiqué sur la topologie. .. _figrouterinrouter: .. figure:: images/router_in_router.png :alt: Topologie d'un routeur dans un routeur :align: center Topologie d'un routeur dans un routeur .. _preparation: A - Préparation du routeur hôte ---------------------------------- Dans un premier temps, la topogie indiquée par GNS3 correspondra exactement au réseau qu'on veut constuire : un hôte H1 connecté à R1 qui est un routeur et une passerelle NAT en direction du nuage Internet. Vous écrirez un shell script bash exécuté depuis votre machine, qui mettra en place la configuration suivante, en partant du labo initial importé dans GNS3. - Installation de tcpdump sur `H1` et `R1` avec la commande ``apt install -y tcpdump``. - Comme R1 est un routeur, il forwarde des paquets et devra avoir ``/proc/sys/net/ipv4/ip_forward`` posé à 1. - L'IP obtenue par R1 coté ``eth0`` sera obtenue par DHCP avec la commande ``dhclient -v eth0``, car un serveur DHCP est disponible coté ``nat0`` - L'IP de R1 coté ``eth1`` et de H1 ``eth0`` sera configurée statiquement avec ``iproute2``, dans le segment IP ``10.0.0.0/24``. La configuration d'une IP avec iproute est disponible dans la documentation [#addrmgmt]_ - La route par défaut de H1 passera par R1, référez vous à la documentation d'iproute pour installer une route par défaut [#routesmgmt]_ - R1 implémentera une passerelle NAT à l'aide de nftables pour cela, il faut exécuter le script nftables suivant sur R1 :: #!/usr/sbin/nft -f flush ruleset table ip nat { chain masq { type nat hook postrouting priority 100; oifname "eth0" counter masquerade } } Ce script dit simplement que tout paquet routé sur l'interface ``eth0`` devra avoir son adresse IP source modifiée par l'IP de cette interface. B - Vérification du bon fonctionnement ------------------------------------------ A la fin de cette implémentation, H1 doit pouvoir accéder à Internet, vérifiez le avec la commande ping suivante :: ping 1.1.1.1 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=55 time=3.99 ms 64 bytes from 1.1.1.1: icmp_seq=2 ttl=55 time=2.93 ms 64 bytes from 1.1.1.1: icmp_seq=3 ttl=55 time=3.05 ms **Attention** : Il est possible de pinger la destination sans passer par R1, car les équipements disposent d'une interface de management, ``mgmt0`` qui donne accès à Internet si elle est pointée par la route par défaut. Pour être sûr que ``mgmt0`` n'est pas utilisé pour sortir sur Internet, on peut le vérifier avec la commande ``traceroute`` :: root@H1:~# traceroute -n 1.1.1.1 traceroute to 1.1.1.1 (1.1.1.1), 30 hops max, 60 byte packets 1 10.0.0.1 1.170 ms 0.883 ms 0.694 ms 2 172.21.1.1 1.783 ms 1.614 ms 1.443 m 2 - Routeur virtuel routé *********************************** A - Préparation -------------------- Dans un deuxième temps, il faudra instancier un routeur dans R1, sur la base des namespaces réseaux et des interfaces de type veth [#iprouteveth]_ vus en cours, en utilisant aussi la commande ``iproute2`` [#netns]_ et sans modifier la topologie indiquée par GNS3 car elle représente, en quelque sorte, la topologie physique de notre laboratoire. Le routeur R2 existera uniquement par la création d'un nouveau namespace réseau appelé ``ns2``, les autres namespaces resterons attachés à la machine hôte. .. _fignsrouterinrouter: .. figure:: images/nsrouter_in_router_shema.svg :width: 400 :alt: Topologie d'un routeur dans un routeur :align: center Rajout d'un routeur dans R1 La figure :numref:`fignsrouterinrouter` illustre le schéma de la nouvelle topologie. Les paquets, plutôt que de passer directement de l'interface ``eth1`` à l'interface ``eth0`` seront : - redirigés vers R2 au travers d'interfaces virtuelles de type ``veth`` créées avec ``iproute2``. - source natés par R2 sur l'interface ``veth0``, de la même manière que dans la partie précédente, pour permettre une connexion de bout en bout vers Internet. Les sous-réseaux du routeur R2 seront les suivants : - sur le lien ``veth0-veth0`` : 192.168.0.0/24 - sur le lien ``veth1-veth1`` : 192.168.1.0/24 Comme le trafic transite par un routeur virtuel présent sur l'hôte R1, il faut pouvoir distinguer le trafic qui provient de l'hôte du trafic qui provient de R2 au niveau de la destination par défaut. Pour cela nous utiliserons le policy routing et ``ip rule`` [#policyrouting]_ de la manière suivante sur R1 :: # Effacement de la route par défaut obtenue par dhclient. ip route delete default # Redirection des paquets via l'interface veth qui mène à R2. ip route add default via 192.168.1.1 # Utilisation du policy routing pour passer par eth0 si le trafic vient de R2. # 172.21.1.1 est la passerelle obtenue par DHCP sur le Nuage Internet. echo 100 custom >> /etc/iproute2/rt_tables ip rule add iif veth0 table custom ip route add default via 172.21.1.1 table custom N'oubliez pas de rajouter une route vers le réseau 10.0.0.0/24 dans R2, qui passe par une interface différente que celle par défaut, autrement les paquets ne pourrons que sortir de H1, mais pas revenir. Vous écrirez un shell script qui met en place cette configuration, le shell script sera à fournir dans votre carnet de laboratoire. B - Vérification du bon fonctionnement --------------------------------------- A la fin de cette implémentation, H1 doit toujours pouvoir accéder à Internet, avec une différence importante : ses paquets transiteront par R2. Pour le démontrer vous fournirez une capture d'écran de l'exécution de tcpdump dans le namespace de R2 et dans le namespace de R1, en même temps qu'un ping vers ``1.1.1.1`` depuis H1. - Les paquets qui sortent de ``veth0`` devront être source natés avec l'IP assignée à R2 sur veth1. - Le TTL des paquets qui sortent de ``eth0`` sur R1 devra être décrémenté trois fois par rapport à ceux qui entrent sur ``eth1`` depuis H1, car ils traversent en réalité 3 piles TCP/IP comme indiqué sur la figure :numref:`fignsrouterinrouterttl` : l'une entre ``eth1`` et ``veth1``, c'est à dire en entrant sur R2, l'autre entre ``veth0`` eth ``eth0``, c'est à dire en sortant de R2, et la dernière en sortant de R1. .. _fignsrouterinrouterttl: .. figure:: images/nsrouter_in_router_ttl.svg :width: 400 :alt: Décrément du TTL avec un routeur virtuel :align: center Décrément du TTL avec un routeur virtuel - Lorsque R2 n'est pas utilisé, le TTL des paquets est incrémenté de 2 (valeur 55) pas rapport à lorsqu'il n'est pas utilisé (valeur 53), expliquez pourquoi ? :: # Sans utiliser R2 root@H1:~# ping 1.1.1.1 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=55 time=3.78 ms 64 bytes from 1.1.1.1: icmp_seq=2 ttl=55 time=2.95 ms # En utilisant R2 root@H1:~# ping 1.1.1.1 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=53 time=4.71 ms 64 bytes from 1.1.1.1: icmp_seq=2 ttl=53 time=3.28 ms 64 bytes from 1.1.1.1: icmp_seq=3 ttl=53 time=3.24 ms 64 bytes from 1.1.1.1: icmp_seq=4 ttl=53 time=3.25 ms 3 - Routeur virtuel bridgé ***************************** Effacer toute la configuration précédente, qui n'a rien a voir avec celle qu'on va implémenter maintenant. Pour ce faire, le mieux est d'importer à nouveau le labo dans GNS3. .. _figrouterbridge: .. figure:: images/router_bridge.svg :width: 400 :alt: Routeur bridgé physiquement :align: center Routeur bridgé physiquement La configuration est schématisée sur la figure :numref:`figrouterbridge`. Cette fois, nous implémenterons routeur virtuel en bridgant les interfaces veth directement sur les interfaces physique eth1 eth0. Ceci aura pour effet d'isoler la pile TCP/IP du routeur, mais de présenter ses interfaces sur le même domaine de broadcast que H1 et le noeud qui fournit Internet. L'avantage de cette configuration est qu'elle ne nécessite pas de faire du policy routing. Concrètement ceci veut dire que la configuration de ce routeur virtuel sera identifique à celle présentée dans la partie :ref:`preparation`, sauf que toute la configuration aura lieu dans le namespace ``ns2`` et que les interfaces connectées à un routeur ne sont plus les interfaces ``eth0`` ou ``eth1`` mais les interfaces ``veth0`` et ``veth1``. - Donner dans votre carnet de laboratoire les scripts utilisés pour réaliser cette configuration. - Donner une capture d'écran une suite de commande qui montre que la configuration du routeur tourne bien dans une instance à part. Avec cette configuration, le TTL ne devrait être décrémenté qu'une seule fois, c'est à dire lorsqu'il traverse la pile TCP/IP du routeur instancié dans ns2:: # Sans utiliser R1, mais en passant par R2 hosté sur R1. root@H1:~# ping 1.1.1.1 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=55 time=3.78 ms 64 bytes from 1.1.1.1: icmp_seq=2 ttl=55 time=2.95 ms 4 - Instanciation de plusieurs routeurs virtuels sur R1 ********************************************************* Dans cette dernière étape, vous mettrez en place deux routeurs virtuels R2 et R3, sur la base des scripts écrits précédemment. La figure :numref:`fignsrouterin2router` illustre la topologie qu'on veut implémenter : Les paquets qui proviennent de H1 traverserons R2 et R3 avant d'être envoyés en sortie. .. _fignsrouterin2router: .. figure:: images/nsrouter_in_2router.svg :width: 400 :alt: Deux routeurs virtuels basés sur les namespaces :align: center Deux routeurs virtuels basés sur les namespaces - Les interfaces ``veth`` coté hôtes pourrons être bridgées ou routées, selon votre préférence. - Vous fournirez le script bash pour pour construire cette topologie, en supposant qu'on part du labo initial importé dans GNS3 et sur les machines sont toutes présentes dans ssh_config. - Votre cahier de laboratoire devra fournir les captures d'écran des ping et wireshark associés qui démontrent que la topologie est fonctionnelle, c'est à dire que le trafic passe bien par R2 et R3 avant de ressortir de R1. .. [#routesmgmt] https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md#route-management .. [#addrmgmt] https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md#address-management .. [#policyrouting] https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md#policy-based-routing .. [#iprouteveth] https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md#create-a-pair-of-virtual-ethernet-devices .. [#netns] https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md#network-namespace-management