Le routage
Pourquoi
Camille, depuis son poste, tape curl https://signalements.exemple.fr/sante. Une fraction de seconde plus tard, la réponse s'affiche. Entre les deux, la requête a traversé sa box, le réseau de son fournisseur d'accès, plusieurs opérateurs, le réseau de Scaleway, un répartiteur de charge, et elle est arrivée sur sig-app-1, une machine qui n'a même pas d'adresse publique. Aucun de ces équipements ne connaissait le chemin complet. Chacun a seulement pris une décision locale : à qui passer ce paquet ensuite.
Cette décision, c'est le routage, et c'est elle qui tombe en panne dans une bonne partie des incidents réseau que l'on rencontre en exploitation :
- une instance qui ne peut plus faire
apt updateparce qu'on lui a retiré son adresse publique et qu'elle n'a pas de route par défaut (le piège signalé à la leçon 6 du cours cloud) ; - un VPN qui « casse Internet » sur le poste, parce qu'il a remplacé la route par défaut ;
- une machine à deux interfaces qui reçoit les requêtes par l'une et répond par l'autre, réponses que personne n'accepte ;
- et, à l'échelle mondiale, Facebook, Instagram et WhatsApp injoignables pendant six heures en octobre 2021, parce que leurs routes avaient disparu d'Internet.
Savoir lire une table de routage et prédire le chemin d'un paquet, c'est pouvoir répondre en une commande à la question « par où ce paquet va-t-il sortir ? », au lieu de la deviner.
Les concepts
Remise directe et remise indirecte
Quand une machine doit envoyer un paquet IP, elle se pose d'abord une seule question : la destination est-elle sur un réseau auquel je suis directement relié ?
- Oui : c'est la remise directe. La machine cherche l'adresse matérielle de la destination (par ARP, leçon 2) et lui envoie la trame elle-même.
- Non : c'est la remise indirecte. La machine envoie la trame à un routeur (on dit aussi une passerelle, gateway) qui, lui, est plus proche de la destination. L'adresse IP de destination du paquet ne change pas ; seule l'adresse matérielle de la trame désigne le routeur.
Ce second point est la clé de tout le reste. L'en-tête IP porte l'adresse de la destination finale du début à la fin du voyage (sauf traduction d'adresses, leçon 7). Ce qui change à chaque saut, c'est l'enveloppe de niveau 2 : la trame Ethernet, qui ne va que d'une machine à la suivante.
La RFC 1122, qui fixe les exigences pour les hôtes d'Internet, décrit cette décision : si la destination est sur le même réseau que l'émetteur, le datagramme est envoyé directement ; sinon, il l'est à une passerelle choisie dans la table de routage.
La table de routage
La table de routage est la liste des règles que la machine applique pour prendre cette décision. Chaque route associe un préfixe de destination à une façon de l'atteindre : directement par une interface, ou via l'adresse d'un routeur.
Voici la table principale du poste de Camille, telle que l'affiche ip route (sortie réelle, adresses et nom d'interface remplacés, réseaux propres au poste retirés) :
$ ip route
default via 192.168.1.1 dev ens2 proto dhcp src 192.168.1.23 metric 600
192.168.1.0/24 dev ens2 proto kernel scope link src 192.168.1.23 metric 600
Deux routes suffisent à une machine ordinaire :
192.168.1.0/24 dev ens2: le réseau local. Tout ce qui est dans ce préfixe se joint directement par l'interfaceens2. Cette route a été créée par le noyau quand l'adresse192.168.1.23/24a été attribuée à l'interface.default via 192.168.1.1 dev ens2: la route par défaut. Tout le reste part vers la box,192.168.1.1, parens2.defaultest un raccourci pour0.0.0.0/0, le préfixe de longueur zéro qui contient toutes les adresses.
Les autres mots de chaque ligne, d'après la page de manuel ip-route(8) :
| Champ | Exemple | Sens |
|---|---|---|
via | via 192.168.1.1 | l'adresse du routeur suivant (next hop) ; absent pour une route directe |
dev | dev ens2 | l'interface de sortie |
proto | proto kernel, proto dhcp, proto static | qui a installé la route : le noyau à l'attribution d'une adresse, le client DHCP, un administrateur, un démon de routage (bird, bgp...) |
scope | scope link | la portée : link pour une destination joignable directement sur le lien, host pour la machine elle-même, global (implicite) pour les routes via un routeur |
src | src 192.168.1.23 | l'adresse source préférée pour les paquets émis par cette route |
metric | metric 600 | une préférence : à préfixe égal, la plus petite métrique l'emporte |
La métrique 600 est celle que NetworkManager donne par défaut aux interfaces Wi-Fi (les interfaces filaires ont 100) : quand un portable est branché au câble et au Wi-Fi à la fois, deux routes par défaut coexistent et le câble l'emporte. Sur un serveur, on rencontre plutôt proto dhcp sans métrique, ou proto static.
La règle du plus long préfixe
Une destination correspond souvent à plusieurs routes. 192.168.1.40 correspond à la fois à 192.168.1.0/24 et à default (0.0.0.0/0), puisque la route par défaut correspond à tout. Laquelle choisir ?
La règle est universelle, chez les hôtes comme chez les routeurs : la route au préfixe le plus long l'emporte, parce qu'elle est la plus précise. La RFC 1812, qui fixe les exigences pour les routeurs IPv4, en fait la règle de base de la décision de transmission. Ici, /24 est plus long que /0 : remise directe.
La métrique ne départage que des routes de même longueur. Une route /24 avec une métrique de 1 000 l'emporte toujours sur une route /16 de métrique 1.
Prenons la table, simplifiée, de sig-app-1, augmentée de deux routes vers un réseau de partenaire 10.42.0.0/16, dont une partie (10.42.7.0/24) passe par un autre routeur. Le petit programme suivant applique la règle, comme le fait le noyau :
import ipaddress
# Table de routage de sig-app-1 (simplifiée)
table = [
("0.0.0.0/0", "via 172.16.20.1 dev ens2"),
("172.16.20.0/22", "dev ens2 (remise directe)"),
("10.42.0.0/16", "via 172.16.20.250 dev ens2"),
("10.42.7.0/24", "via 172.16.20.251 dev ens2"),
]
def choisir(destination):
adresse = ipaddress.ip_address(destination)
candidates = [(ipaddress.ip_network(p), sortie) for p, sortie in table
if adresse in ipaddress.ip_network(p)]
reseau, sortie = max(candidates, key=lambda c: c[0].prefixlen)
return f"{destination:<15} candidates : {len(candidates)} retenue : {reseau} {sortie}"
for d in ["172.16.20.12", "10.42.7.9", "10.42.9.1", "203.0.113.10"]:
print(choisir(d))$ python3 lpm.py
172.16.20.12 candidates : 2 retenue : 172.16.20.0/22 dev ens2 (remise directe)
10.42.7.9 candidates : 3 retenue : 10.42.7.0/24 via 172.16.20.251 dev ens2
10.42.9.1 candidates : 2 retenue : 10.42.0.0/16 via 172.16.20.250 dev ens2
203.0.113.10 candidates : 1 retenue : 0.0.0.0/0 via 172.16.20.1 dev ens2
10.42.7.9 correspond à trois routes ; le /24 l'emporte. 203.0.113.10 ne correspond qu'à la route par défaut. C'est toute la mécanique. Le noyau utilise une structure de données bien plus efficace qu'une liste (un arbre de préfixes), mais le résultat est le même.
La route par défaut, et son absence
Une machine sans route par défaut ne peut joindre que les réseaux qu'elle connaît explicitement. C'est parfois voulu (une base de données qui n'a rien à faire sur Internet), souvent accidentel. Le message est alors immédiat :
$ ip route get 192.0.2.1 from 192.0.2.5
RTNETLINK answers: Network is unreachable
Cette sortie réelle vient d'une recherche de route avec une adresse source qu'aucune interface ne porte, ce qui ne laisse aucune route utilisable : c'est le même message que celui que vous obtiendrez d'un ping ou d'un curl (connect: Network is unreachable) sur une machine sans route vers la destination. Il ne dit pas qu'un équipement distant a refusé quoi que ce soit : la décision a été prise localement, avant l'émission du moindre paquet.
Sur un réseau, la route par défaut est généralement fournie par DHCP : le serveur annonce l'adresse du routeur (l'option Router de la RFC 2132), et le client installe la route (proto dhcp). C'est ce que fait la passerelle publique de Scaleway quand on l'attache à un réseau privé avec push-default-route=true (leçon 6 du cours cloud) : les instances apprennent par DHCP que leur route par défaut passe par elle.
Ce que fait un routeur
Un routeur est une machine qui accepte de transmettre des paquets qui ne lui sont pas destinés. Pour chacun, d'après la RFC 1812 :
- Il vérifie l'en-tête (version, longueur, somme de contrôle).
- Il décrémente le TTL (Time To Live, le nombre de sauts restants). S'il tombe à zéro, il détruit le paquet et renvoie à l'émetteur un message ICMP Time Exceeded. C'est ce qui empêche un paquet de tourner indéfiniment dans une boucle de routage, et c'est le mécanisme qu'exploite
traceroute(leçon 6). - Il recalcule la somme de contrôle de l'en-tête, puisque le TTL a changé.
- Il cherche la destination dans sa table de routage (plus long préfixe), et choisit l'interface et le routeur suivant.
- Il fragmente le paquet si nécessaire et si c'est permis, ou renvoie une erreur ICMP (leçon 6).
- Il l'emballe dans une nouvelle trame, adressée au routeur suivant ou à la destination.
Une machine Linux ordinaire ne transmet pas : un paquet reçu qui ne lui est pas destiné est ignoré. Le réglage net.ipv4.ip_forward active la transmission ; la documentation du noyau précise que sa valeur par défaut est 0 et que le modifier remet les autres paramètres à leurs valeurs par défaut, celles d'un hôte (RFC 1122) ou d'un routeur (RFC 1812). Sur une machine qui fait tourner Docker, vous le trouverez à 1 : Docker l'active pour router le trafic de ses conteneurs.
Plusieurs tables, et des règles pour choisir
Linux n'a pas une table de routage, mais plusieurs, et une liste de règles qui dit dans quel ordre les consulter. Sans configuration particulière, ip rule montre trois règles :
$ ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
- La table
local(numéro 255) est remplie par le noyau : les adresses de la machine elle-même et les adresses de diffusion. Elle est consultée en premier, ce qui garantit qu'un paquet destiné à une adresse locale ne sorte jamais. - La table
main(254) est celle qu'afficheip route: c'est là que vivent les routes habituelles. - La table
default(253) est vide par défaut.
$ ip route show table local
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 192.168.1.23 dev ens2 proto kernel scope host src 192.168.1.23
broadcast 192.168.1.255 dev ens2 proto kernel scope link src 192.168.1.23
On ajoute des règles (ip rule add from 172.16.30.0/24 lookup 100) quand le choix du chemin doit dépendre d'autre chose que la destination : l'adresse source, l'interface d'entrée, une marque posée par le pare-feu. C'est le routage par politique (policy routing), que l'on retrouve dans les machines à plusieurs fournisseurs d'accès, les VPN et Kubernetes. Le cours Le réseau sous Linux : nftables, namespaces, bridges le pratique ; ici, retenez seulement que ip route ne montre pas tout.
Le routage asymétrique
Rien n'oblige la réponse à suivre le même chemin que la requête. Chaque machine décide pour les paquets qu'elle émet, avec sa table. Quand l'aller et le retour passent par des chemins différents, on parle de routage asymétrique. Sur Internet, c'est courant et sans conséquence. Sur un réseau local, c'est souvent une erreur de configuration qui se manifeste par des connexions qui n'aboutissent jamais.
Le cas typique : une instance a deux interfaces, une publique (ens2) et une privée (ens5), et sa route par défaut passe par l'interface publique. Un client du réseau privé d'un autre site lui envoie une requête, qui arrive par ens5. La réponse, destinée à une adresse que la table ne connaît pas, part par la route par défaut, donc par ens2. Elle sort avec la mauvaise adresse source, ou se fait jeter par un pare-feu à état qui n'a jamais vu passer la requête.
Le noyau a d'ailleurs une protection contre une variante de ce problème : le filtrage du chemin inverse (reverse path filtering, réglage rp_filter). À la réception d'un paquet, le noyau se demande : « si je devais répondre à cette source, est-ce que ce serait par l'interface où le paquet est arrivé ? ». La documentation du noyau décrit trois valeurs : 0 pas de vérification, 1 mode strict de la RFC 3704 (le paquet est rejeté si l'interface d'arrivée n'est pas le meilleur chemin de retour), 2 mode souple (rejeté seulement si la source n'est joignable par aucune interface). Le but est de rejeter les paquets à adresse source usurpée. Ubuntu active le mode souple :
$ cat /etc/sysctl.d/10-network-security.conf
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks.
net.ipv4.conf.default.rp_filter=2
net.ipv4.conf.all.rp_filter=2
Ce fichier appartient au paquet procps. En mode strict, l'instance à deux interfaces de l'exemple jetterait la requête arrivée par ens5, sans aucun message. Si un trafic légitime disparaît sur une machine à plusieurs interfaces, vérifiez rp_filter (le noyau retient la plus grande valeur entre all et l'interface).
Le routage d'Internet : systèmes autonomes et BGP
Votre box a une route par défaut vers votre fournisseur d'accès. Mais le routeur de ce fournisseur, lui, ne peut pas se contenter d'une route par défaut : à un moment, quelqu'un doit savoir que 203.0.113.0/24 se trouve chez Scaleway. Ce quelqu'un, ce sont les routeurs de bordure des opérateurs, qui échangent leurs routes avec BGP (Border Gateway Protocol, version 4, RFC 4271).
Internet est fait de plus de soixante-dix mille systèmes autonomes visibles dans les tables de routage (AS, Autonomous System) : des réseaux sous une administration unique (un opérateur, un hébergeur, une grande entreprise, une université), identifiés chacun par un numéro (ASN). Chaque AS annonce à ses voisins les préfixes qu'il héberge, et relaie, selon ses accords commerciaux, les annonces qu'il a reçues. Chaque annonce porte le chemin d'AS qu'elle a traversé, ce qui permet d'éviter les boucles et de préférer les chemins courts. Un routeur du cœur d'Internet a ainsi une table d'environ un million de préfixes IPv4, sans route par défaut.
flowchart LR
P["Poste<br/>192.168.1.23"] --> B["Box<br/>192.168.1.1"]
B --> F["AS du fournisseur<br/>d'accès"]
F -->|"BGP"| T["AS de transit"]
T -->|"BGP"| S["AS de Scaleway<br/>annonce 203.0.113.0/24"]
S --> LB["Répartiteur<br/>203.0.113.10"]
LB --> A["sig-app-1<br/>172.16.20.11"]
BGP repose sur la confiance : un AS accepte, en principe, ce que ses voisins lui annoncent. Deux incidents célèbres montrent ce que cela implique.
YouTube, février 2008. D'après l'étude de cas du RIPE NCC, YouTube annonçait 208.65.152.0/22. Le 24 février à 18 h 47 UTC, Pakistan Telecom, qui voulait bloquer YouTube dans le pays, a annoncé 208.65.153.0/24, un préfixe plus long inclus dans celui de YouTube, et son fournisseur de transit l'a relayé au monde entier. Règle du plus long préfixe oblige, une grande partie du trafic mondial vers YouTube est partie au Pakistan. YouTube a répondu en annonçant à son tour ce /24, puis deux /25 encore plus spécifiques ; l'incident a pris fin vers 21 h 01 UTC, quand le transitaire a retiré les annonces de Pakistan Telecom. Deux heures de panne, et la démonstration que la règle du plus long préfixe vaut aussi à l'échelle de la planète.
Facebook, octobre 2021. Le compte rendu publié par Meta décrit une commande lancée pendant une maintenance pour mesurer la capacité du réseau dorsal, qui a coupé par erreur toutes ses connexions ; l'outil d'audit censé bloquer ce type de commande avait un défaut. Les serveurs DNS de Facebook, conçus pour retirer leurs annonces BGP quand ils ne joignent plus les centres de données (signe d'un réseau malade), l'ont fait. Résultat : ils fonctionnaient encore, mais plus personne sur Internet ne savait comment les joindre. Et le retour a été lent, parce que les équipes devaient intervenir physiquement dans des centres de données conçus pour être difficiles d'accès.
La réponse principale aux détournements d'annonces est la RPKI (Resource Public Key Infrastructure) : le titulaire d'un bloc d'adresses publie un certificat signé (un ROA, Route Origin Authorization) qui dit quel AS a le droit d'annoncer ce préfixe, et jusqu'à quelle longueur. Les routeurs qui pratiquent la validation d'origine (RFC 6811) classent chaque annonce en valide, invalide ou inconnue, et peuvent rejeter les invalides. La RFC précise elle-même la limite : le mécanisme ne vérifie que l'origine, pas le chemin, et ne protège pas contre un attaquant qui ajoute l'AS légitime en tête d'une annonce forgée. Un ROA avec une longueur maximale /22 aurait fait classer invalide l'annonce de 208.65.153.0/24 de 2008.
En pratique
Demander au noyau quelle route il prendrait
ip route get est la commande la plus utile de cette leçon. Elle demande au noyau quelle route il utiliserait pour une destination, exactement comme il la voit, règles et tables comprises. La page de manuel précise qu'aucun paquet n'est réellement envoyé : on peut l'utiliser sans risque, même vers une adresse qui n'existe pas.
$ ip route get 203.0.113.10
203.0.113.10 via 192.168.1.1 dev ens2 src 192.168.1.23 uid 1000
cache
$ ip route get 127.0.0.1
local 127.0.0.1 dev lo src 127.0.0.1 uid 1000
cache <local>
Pour 203.0.113.10, l'adresse publique du répartiteur de Signalements : sortie par ens2, via la box, avec 192.168.1.23 comme adresse source. Pour 127.0.0.1 : une route de type local, trouvée dans la table local, par l'interface de bouclage. uid 1000 rappelle que la recherche a été faite pour l'utilisateur courant (des règles peuvent dépendre de l'utilisateur), et cache indique une entrée du cache de routes.
L'option fibmatch montre la route de la table qui a été retenue, plutôt que le résultat résolu :
$ ip route get fibmatch 203.0.113.10
default via 192.168.1.1 dev ens2 proto dhcp src 192.168.1.23 metric 600
C'est la route par défaut. Avec from, iif ou oif, on peut poser des questions plus précises : « par où partirait une réponse émise avec cette adresse source ? », « que deviendrait un paquet arrivant par telle interface ? » (ce dernier cas simule la transmission sur un routeur).
Suivre GET /sante saut par saut
Reprenons le voyage de la requête de Camille, avec ce que chaque équipement décide. Les tables des équipements que vous ne contrôlez pas sont données en prose.
- Le poste (
192.168.1.23).ip route get 203.0.113.10: via192.168.1.1. Remise indirecte : la trame est adressée à la box, le paquet IP à203.0.113.10. - La box (
192.168.1.1). Elle traduit l'adresse source privée en son adresse publique (leçon 7), puis applique sa propre route par défaut vers le réseau du fournisseur d'accès. TTL décrémenté. - Les routeurs du fournisseur d'accès et des opérateurs. Ils ont appris par BGP que
203.0.113.0/24est annoncé par l'AS de Scaleway, et transmettent de proche en proche. Chacun décrémente le TTL. - Le répartiteur de charge (
203.0.113.10). Le paquet lui est destiné : il termine la connexion TCP (et TLS), puis ouvre une autre connexion vers un serveur de son groupe,172.16.20.11, avec son adresse privée comme source. - Sur le réseau privé. Le répartiteur et
sig-app-1sont dans le même172.16.20.0/22: remise directe. Sursig-app-1,ip route get 172.16.20.x(l'adresse privée du répartiteur) donnerait une routedev ens2sansvia. - La réponse.
sig-app-1répond au répartiteur, toujours en remise directe ; le répartiteur répond à Camille par Internet, et la réponse retraverse les opérateurs, peut-être par un autre chemin (routage asymétrique, sans conséquence ici).
sig-app-1 n'a jamais eu besoin de connaître l'adresse de Camille ni de router vers Internet pour servir la requête. Sa route par défaut (via la passerelle 172.16.20.1) ne sert que pour le trafic qu'elle initie : mises à jour, téléchargement d'images, appels à des API extérieures.
Ajouter et retirer des routes
Sur une machine de test, avec sudo, la syntaxe est la suivante (ces commandes modifient la configuration en cours, et sont perdues au redémarrage) :
$ sudo ip route add 10.42.0.0/16 via 172.16.20.250 dev ens2
$ sudo ip route add 10.42.7.0/24 via 172.16.20.251
$ sudo ip route del 10.42.7.0/24
$ sudo ip route replace default via 172.16.20.1
addajoute une route, et échoue si elle existe déjà ;replacel'ajoute ou la remplace.viadoit désigner une adresse joignable directement : un routeur sur un réseau auquel la machine est reliée. Sinon, le noyau refuse la route (Nexthop has invalid gateway).devest facultatif quandviasuffit à déterminer l'interface.
Pour qu'une route survive au redémarrage, elle se déclare dans la configuration du réseau : sur Ubuntu Server, un fichier Netplan (/etc/netplan/*.yaml, section routes:), et sur un réseau cloud, de préférence par le DHCP ou les tables de routage du fournisseur, pour que les instances recréées l'obtiennent toutes seules.
Sous le capot
Du paquet à la décision. Quand une application appelle connect() sur une socket TCP, le noyau fait une recherche de route avant même d'émettre le premier paquet : c'est elle qui choisit l'interface de sortie et, si l'application n'a pas fixé d'adresse source, l'adresse source (le champ src de la route). C'est pourquoi Network is unreachable arrive instantanément : aucun paquet n'est parti.
La structure de la table. Le noyau Linux range les routes IPv4 dans un arbre de préfixes compressé (un LC-trie, visible dans /proc/net/fib_trie), qui trouve le plus long préfixe en quelques comparaisons même avec un million de routes, ce dont a besoin un routeur Linux connecté à BGP. Les routeurs matériels font la même recherche dans des mémoires spécialisées (TCAM), en une seule opération.
La résolution du routeur suivant. Une fois la route choisie, il reste à trouver l'adresse matérielle du routeur (via) ou de la destination (route directe) : c'est le rôle de la table des voisins, remplie par ARP en IPv4 (ip neigh, leçon 2). Une route correcte vers un routeur qui ne répond pas à ARP se traduit par des paquets qui ne partent jamais, et une entrée FAILED dans ip neigh.
Le TTL de départ. Linux émet ses paquets avec un TTL de 64, valeur par défaut documentée de net.ipv4.ip_default_ttl. C'est ce que montre ttl=64 dans les réponses de ping 127.0.0.1 (leçon 6) : le paquet n'a traversé aucun routeur. Une réponse d'un serveur Linux distant arrivant avec ttl=55 a traversé neuf routeurs.
Pièges courants
Retirer l'adresse publique d'une instance sans lui donner de route par défaut. Elle sert toujours ses clients par le répartiteur, mais ne peut plus rien télécharger. Symptôme : apt update qui reste bloqué sur Connecting to..., et ip route sans ligne default. Correction : une passerelle qui annonce la route par défaut (leçon 6 du cours cloud).
Deux routes par défaut. Deux interfaces configurées en DHCP, deux routes default : celle de plus petite métrique gagne, et ce n'est pas toujours celle qu'on croit. ip route get tranche.
La route via une adresse injoignable. ip route add 10.42.0.0/16 via 10.99.0.1 sur une machine qui n'a aucune interface dans le réseau de 10.99.0.1 : refusé par le noyau. Le routeur suivant doit toujours être un voisin direct.
Les routes perdues au redémarrage. Une route ajoutée avec ip route add vit en mémoire. Le jour où la machine redémarre, le service qui en dépendait tombe. Toute route manuelle doit être reportée dans la configuration persistante, ou mieux, fournie par le réseau.
Le VPN qui capture tout. Un client VPN qui installe une route 0.0.0.0/0 (ou deux /1, 0.0.0.0/1 et 128.0.0.0/1, astuce courante pour l'emporter sur la route par défaut sans la supprimer, par la règle du plus long préfixe) fait passer tout le trafic du poste par le VPN. C'est parfois voulu, souvent une surprise.
Accuser le réseau d'un rp_filter strict. Un trafic qui arrive (on le voit avec tcpdump) mais auquel l'application ne répond jamais, sur une machine à plusieurs interfaces : regardez rp_filter avant d'ouvrir un ticket chez le fournisseur.
Sécurité
Le routage n'est pas un contrôle d'accès. L'absence de route vers un réseau empêche les connexions sortantes de la machine, pas les connexions entrantes depuis ce réseau si un autre équipement y route. Une base de données « sans route par défaut » reste joignable par tout ce qui est sur son réseau. Le filtrage se fait par pare-feu et groupes de sécurité.
Ne transformez pas une machine en routeur par accident. ip_forward=1 sur une machine à deux pattes (une publique, une privée) en fait potentiellement un pont vers le réseau privé, si des routes ou des règles de traduction le permettent. Activez-le seulement là où c'est le rôle de la machine, et accompagnez-le de règles de pare-feu dans la chaîne de transmission.
Les redirections ICMP. Un routeur peut dire à un hôte « pour cette destination, passe plutôt par tel autre routeur » (ICMP Redirect). Accepter ces messages permet à un attaquant du réseau local de détourner du trafic ; les guides de durcissement recommandent de les ignorer sur les serveurs (net.ipv4.conf.all.accept_redirects=0). Le cours Durcissement Linux y revient.
L'usurpation d'adresse source. Le filtrage du chemin inverse, côté hôte, et le filtrage d'entrée des opérateurs (la RFC 3704 et les bonnes pratiques qu'elle prolonge), côté réseau, rendent plus difficile l'émission de paquets avec une fausse adresse source, base des attaques par réflexion et amplification.
BGP, un risque que vous ne contrôlez pas, mais que vous pouvez réduire. Si votre organisation possède ses propres blocs d'adresses, publiez des ROA pour eux : c'est gratuit auprès de votre registre régional (le RIPE NCC en Europe) et cela permet aux opérateurs qui valident l'origine de rejeter un détournement.
En production
Dans le cloud, les tables de routage sont aussi des ressources. Chez AWS, chaque sous-réseau est associé à une route table du VPC ; chez Scaleway, la passerelle publique annonce la route par défaut, et les VPC ont leurs propres routes pour relier les réseaux privés entre eux. Ce sont des objets que l'on décrit en infrastructure as code, et que l'on vérifie comme du code. Le cours Réseau cloud : VPC, load balancers, DNS les détaille.
Les routes se déclarent, elles ne s'ajoutent pas à la main. Une route ajoutée à chaud pour dépanner doit finir dans la configuration (Netplan, DHCP, infrastructure as code), ou être retirée. Sinon, la prochaine instance recréée ne l'aura pas, et l'incident recommencera.
Documentez le chemin attendu. Pour chaque flux important (clients vers répartiteur, applications vers base, instances vers Internet), notez par où il doit passer. Le jour d'un incident, comparer le chemin réel (ip route get, traceroute) au chemin attendu va beaucoup plus vite que de reconstituer l'architecture de mémoire.
Les routeurs Linux existent. Les passerelles des fournisseurs cloud, les nœuds Kubernetes, les machines de VPN sont souvent des Linux qui transmettent des paquets. Les mêmes commandes (ip route, ip rule, ip route get ... iif) servent à les diagnostiquer.
Exercices
1. Lire une table (niveau 100). Voici la table d'une instance :
default via 172.16.20.1 dev ens2 proto dhcp
172.16.20.0/22 dev ens2 proto kernel scope link src 172.16.20.11
10.200.0.0/16 via 172.16.20.30 dev ens2 proto staticPour chaque destination, dites quelle route est choisie, et si la remise est directe ou indirecte : (a) 172.16.21.4 ; (b) 10.200.3.3 ; (c) 10.201.0.1 ; (d) 203.0.113.10.
Solution
(a) 172.16.20.0/22 : 172.16.21.4 est dans le /22 (de 172.16.20.0 à 172.16.23.255). Remise directe par ens2. (b) 10.200.0.0/16, plus long que default : indirecte, via 172.16.20.30. (c) Seule la route par défaut correspond (10.201 n'est pas dans 10.200.0.0/16) : indirecte via 172.16.20.1. (d) Route par défaut, via 172.16.20.1. La route static a été ajoutée par un administrateur ; elle disparaîtra au redémarrage si elle n'est pas dans la configuration persistante.
2. Le plus long préfixe (niveau 200). On ajoute à la table de l'exercice 1 une route 172.16.22.0/24 via 172.16.20.40. Que devient la remise vers 172.16.22.9 ? Est-ce une bonne idée ?
Solution
Le /24 l'emporte sur le /22 : 172.16.22.9 sera envoyé à 172.16.20.40, alors qu'il est sur le même segment que l'instance. Si 172.16.20.40 le transmet, cela fonctionne avec un détour ; sinon, la destination devient injoignable. Surtout, la réponse de 172.16.22.9, qui voit 172.16.20.11 dans son propre /22, reviendra directement : routage asymétrique. Ce genre de route signale en général un plan d'adressage à revoir.
3. Prédire avec ip route get (niveau 100). Sur votre machine, lancez ip route get pour 127.0.0.1, pour l'adresse de votre passerelle et pour 192.0.2.1. Pour chacune, notez le type de route, l'interface, et la présence ou non de via. Pourquoi cette commande est-elle sans danger ?
Solution
127.0.0.1 : type local, interface lo, pas de via. La passerelle : route directe sur l'interface du réseau local, pas de via (elle est sur le même segment). 192.0.2.1 : route par défaut, via la passerelle. La commande interroge le noyau sans émettre de paquet, comme le précise ip-route(8) : on peut l'utiliser vers n'importe quelle adresse, y compris de documentation.
4. L'instance muette (niveau 200). Une instance a deux interfaces : ens2 (publique, route par défaut) et ens5 (privée, 172.16.20.11/22). Un client d'un autre réseau privé, 10.50.0.7, joint via un VPN qui arrive sur le réseau privé, lui envoie des requêtes. tcpdump -i ens5 montre les requêtes qui arrivent, mais le client ne reçoit jamais de réponse. Donnez deux causes possibles et leurs corrections.
Solution
Première cause : le routage asymétrique. La table ne connaît pas 10.50.0.0/16 ; la réponse part par la route par défaut, sur ens2, et se perd (mauvaise adresse source, ou rejet par un équipement à état). Correction : une route 10.50.0.0/16 via <routeur VPN> dev ens5, de préférence annoncée par le réseau. Deuxième cause : rp_filter en mode strict (1) sur ens5. Le noyau constate que la réponse à 10.50.0.7 partirait par ens2, et rejette la requête arrivée par ens5, sans message. Correction : la même route (qui rend ens5 légitime), ou le mode souple (2). Dans les deux cas, ip route get 10.50.0.7 montre le problème.
5. BGP (niveau 200). Une organisation détient 198.51.100.0/22, annoncé par son AS. Un autre AS annonce par erreur 198.51.100.0/24. (a) Où part le trafic destiné à 198.51.100.10 ? À 198.51.103.10 ? (b) Quel ROA aurait permis aux opérateurs qui valident l'origine de rejeter l'annonce ? (c) Que n'aurait pas empêché ce ROA ?
Solution
(a) 198.51.100.10 tombe dans le /24 annoncé par erreur, plus long que le /22 : chez les opérateurs qui ont accepté l'annonce, le trafic part vers le mauvais AS. 198.51.103.10 n'est que dans le /22 : il arrive à bon port. (b) Un ROA pour 198.51.100.0/22, AS de l'organisation, longueur maximale /22. L'annonce du /24 est alors couverte par un ROA mais ne lui correspond pas (mauvais AS, longueur supérieure au maximum) : invalide. (c) Une annonce forgée qui reprendrait l'AS légitime comme origine dans le chemin : la validation d'origine ne vérifie pas le chemin, comme le rappelle la RFC 6811.
Récapitulatif
- Chaque équipement prend une décision locale : remise directe si la destination est sur un réseau relié, indirecte via un routeur sinon. L'adresse IP de destination ne change pas ; l'adresse de la trame, si.
- La table de routage associe des préfixes à une interface (
dev) et éventuellement un routeur (via) ;proto,scope,srcetmetriccomplètent chaque route. - Le plus long préfixe l'emporte ; la métrique ne départage que des préfixes de même longueur. La route par défaut (
0.0.0.0/0) attrape tout le reste. ip route getdit, sans émettre de paquet, quelle route le noyau utiliserait ;ip rulemontre que plusieurs tables existent (local,main,default).- Un routeur décrémente le TTL, recalcule la somme de contrôle, choisit le saut suivant ; Linux ne transmet que si
ip_forwardvaut 1. - Le routage asymétrique est normal sur Internet et piégeux en local ; le filtrage du chemin inverse (
rp_filter, souple sur Ubuntu) peut jeter du trafic légitime en mode strict. - Entre opérateurs, BGP échange les routes de dizaines de milliers de systèmes autonomes ; il repose sur la confiance, et la RPKI valide l'origine des annonces.
Pour aller plus loin
- La page de manuel
ip-route(8), en particulier les sections sur les types de routes et surip route get. - Le compte rendu de Meta sur la panne d'octobre 2021, et l'étude de cas du RIPE NCC sur YouTube : deux lectures courtes qui rendent BGP concret.
- Le chapitre sur le routage IP de TCP/IP Illustrated, Volume 1 de Stevens et Fall.
- La leçon suivante, qui montre comment ICMP rend visibles les décisions des routeurs, et ce qui arrive quand un paquet est trop gros pour le chemin.
Sources
- RFC 1122, Requirements for Internet Hosts, section 3.3.1 : routage des datagrammes sortants
- RFC 1812, Requirements for IP Version 4 Routers
- Linux man-pages, ip-route(8)
- Linux man-pages, ip-rule(8)
- Documentation du noyau Linux, IP Sysctl (ip_forward, rp_filter, ip_default_ttl)
- RFC 3704, Ingress Filtering for Multihomed Networks (filtrage du chemin inverse)
- RFC 2132, DHCP Options and BOOTP Vendor Extensions (option Router)
- RFC 4271, A Border Gateway Protocol 4 (BGP-4)
- RFC 6811, BGP Prefix Origin Validation
- Meta Engineering, More details about the October 4 outage (2021)
- RIPE NCC, YouTube Hijacking: A RIPE NCC RIS case study (2008)