Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

Ce blog n'a d'autre prétention que de me permettre de mettre à la disposition de tous des petits textes que j'écris. On y parle surtout d'informatique mais d'autres sujets apparaissent parfois.


RFC 8973: DDoS Open Threat Signaling (DOTS) Agent Discovery

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : M. Boucadair (Orange), T. Reddy (McAfee)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dots
Première rédaction de cet article le 13 janvier 2021


Le protocole DOTS, normalisé dans les RFC 8811, RFC 8782 et RFC 8783, sert à coordonner la réponse à une attaque par déni de service, entre la victime de l'attaque (le client DOTS) et un service d'atténuation de l'attaque (le serveur DOTS). Mais comment le client trouve-t-il son serveur ? Il peut y avoir une configuration manuelle, mais ce RFC propose aussi des moyens automatiques, basés sur un choix de plusieurs techniques, dont DHCP et NAPTR.

Attention, cela permet de trouver le serveur, mais pas le fournisseur du service d'atténuation. Car il faut un accord (souvent payant) avec ce fournisseur, et un échange de mécanismes d'authentification. Cette partie doit se faire manuellement. Le protocole de notre RFC prend ensuite le relais.

Notez aussi qu'il n'y a pas un seul moyen de découverte du serveur. La section 3 du RFC explique en effet que, vu la variété des cas d'utilisation de DOTS, on ne peut pas s'en tirer avec un seul mécanisme. Parfois le client a un CPE géré par le FAI, sur lequel on peut s'appuyer pour trouver le serveur DOTS, et parfois pas. Parfois, il faudra utiliser les résolveurs DNS d'un opérateur et parfois ce ne sera pas nécessaire. Parfois l'atténuateur est le FAI et parfois pas. Bref, il faut plusieurs solutions.

Voyons d'abord la procédure générale (section 4). Personnellement, je pense que le client DOTS doit donner la priorité aux configurations manuelles (DOTS est un système de sécurité, un strict contrôle de ce qui se passe est préférable). Mais le RFC ne décrit pas les choses ainsi. Il expose trois mécanismes, le premier, qualifié de configuration explicite, étant composé de deux techniques très différentes, la configuration manuelle ou bien DHCP. À noter au passage que la configuration manuelle peut indiquer le nom ou l'adresse IP mais, si elle indique l'adresse IP, le nom sera quand même obligatoire car il servira pour la vérification du certificat.

L'ordre des préférences entre ces mécanismes est imposé, pour que le résultat de la découverte soit prédictible. D'abord l'explicite (manuel ou DHCP, section 5), puis la résolution de service (section 6) puis la découverte de service (section 7).

Première technique automatique à utiliser, DHCP (section 5). Ce protocole va être utilisé pour récupérer le nom du serveur DOTS (le nom et pas seulement l'adresse IP car on en aura besoin pour authentifier la session TLS). Avec DHCPv6 (RFC 8415), l'option DHCP pour récupérer le nom est 141 en IPv6 et 147 pour IPv4. Une autre option permet de récupérer les adresses IP du serveur DOTS.

Deuxième technique, la résolution de service. Il faut partir d'un nom, qui peut être configuré manuellement ou bien obtenu par DHCP. Ce n'est pas le nom du serveur DOTS, contrairement au cas en DHCP pur, mais celui du domaine dans lequel le client DOTS se « trouve ». On va alors utiliser S-NAPTR (RFC 3958) sur ce nom, pour obtenir les noms des serveurs. L'étiquette à utiliser est DOTS pour le service (enregistré à l'IANA) et signal (RFC 8782) ou data (RFC 8783) pour le protocole (également à l'IANA). Par exemple si le client DOTS est dans le domaine example.net, il va faire une requête DNS de type NAPTR. Si le domaine comportait un enregistrement pour le service DOTS, il est choisi, et on continue le processus (compliqué !) de NAPTR ensuite. Si on cherche le serveur pour le protocole de signalisation, on pourrait avoir successivement quatre requêtes DNS :

example.net.   IN NAPTR 100 10 "" DOTS:signal.udp "" signal.example.net.

signal.example.net. IN NAPTR 100 10 "s" DOTS:signal.udp "" _dots-signal._udp.example.net.

_dots-signal._udp.example.net.  IN SRV   0 0 5000 a.example.net.

a.example.net.   IN AAAA  2001:db8::1    
  

Troisième technique, la découverte de service (DNS-SD) du RFC 6763. On cherche alors un enregistrement de type PTR dans _dots-signal.udp.example.net. Il nous donnera un nom pour lequel on fera une requête SRV.

DOTS servant en cas d'attaque, il faut prévoir la possibilité que l'attaquant tente de perturber ou de détourner ce mécanisme de découverte du serveur. Par exemple, on sait que DHCP n'est pas spécialement sécurisé (euphémisme !). D'autre part, DOTS impose TLS, il faut donc un nom à vérifier dans le certificat (oui, on peut mettre des adresses IP dans les certificats mais c'est rare). Quant aux techniques reposant sur le DNS, le RFC conseille d'utiliser DNSSEC, ce qui semble la moindre des choses pour une technique de sécurité. Il suggère également de faire la résolution DNS via un canal sûr par exemple avec DoT (RFC 7858) ou DoH (RFC 8484).

Apparemment, il existe au moins une mise en œuvre de DOTS qui inclut les procédures de découverte de notre RFC, mais j'ignore laquelle.


Téléchargez le RFC 8973


L'article seul

RFC 8966: The Babel Routing Protocol

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : J. Chroboczek (IRIF, University of Paris-Diderot), D. Schinazi (Google LLC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF babel
Première rédaction de cet article le 12 janvier 2021


Le travail sur les protocoles de routage ne désarme pas, motivé à la fois par les avancées de la science et par les nouvelles demandes (par exemple pour les réseaux ad hoc). Ainsi Babel est un protocole de routage, de la famille des protocoles à vecteur de distance, qui vise notammment à réduire drastiquement les probabilités de boucle. Il avait été décrit originellement dans le RFC 6126 ; ce nouveau RFC ne change pas fondamentalement le protocole Babel (quoique certains changements ne seront pas compris par les vieilles versions) mais il a désormais le statut de norme, et des solutions de sécurité plus riches. Ce manque de sécurité était la principale critique adressée à Babel.

Il y a deux familles de protocole de routage, ceux à vecteur de distance comme l'ancêtre RIP et ceux à états des liens comme OSPF (RFC 2328). Ce dernier est aujourd'hui bien plus utilisé que RIP, et à juste titre. Mais les problèmes de RIP n'ont pas forcément la même ampleur chez tous les membres de sa famille, et les protocoles à vecteurs de distance n'ont pas dit leur dernier mot.

Babel s'inspire de protocoles de routage plus récents comme DSDV. Il vise à être utilisable, à la fois sur les réseaux classiques, où le routage se fait sur la base du préfixe IP et sur les réseaux ad hoc, où il n'y a typiquement pas de regroupement par préfixe, où le routage se fait sur des adresses IP « à plat » (on peut dire que, dans un réseau ad hoc, chaque nœud est un routeur).

L'un des principaux inconvénients du bon vieux protocole RIP est sa capacité à former des boucles lorsque le réseau change de topologie. Ainsi, si un lien entre les routeurs A et B casse, A va envoyer les paquets à un autre routeur C, qui va probablement les renvoyer à A et ainsi de suite (le champ « TTL » pour IPv4 et « Hop limit » dans IPv6 a précisement pour but d'éviter qu'un paquet ne tourne sans fin). Babel, lui, évitera les boucles la plupart du temps mais, en revanche, il ne trouvera pas immédiatement la route optimale entre deux points. La section 1.1 du RFC spécifie plus rigoureusement les propriétés de Babel.

Babel peut fonctionner avec différentes métriques pour indiquer les coûts de telle ou telle route, le protocole lui-même étant indépendant de la métrique utilisée (cf. annexe A du RFC pour des conseils sur les choix). D'ailleurs, je vous recommande la lecture de l'Internet-Draft draft-chroboczek-babel-doesnt-care, pour mieux comprendre la philosophie de Babel.

Autre particularité de Babel, les associations entre deux machines pourront se faire même si elles utilisent des paramètres différents (par exemple pour la valeur de l'intervalle de temps entre deux « Hello » ; cf. l'annexe B pour une discussion du choix de ces paramètres, les compromis que ce choix implique entre intensité du trafic et détection rapide des changements, et les valeurs recommandées pour ces paramètres). Le RFC annonce ainsi que Babel est particulièrement adapté aux environnements « sans-fil » où certaines machines, devant économiser leur batterie, devront choisir des intervalles plus grands, ou bien aux environnements non gérés, où chaque machine est configurée indépendamment.

Je l'ai dit, rien n'est parfait en ce bas monde, et Babel a des limites, décrites en section 1.2. D'abord, Babel envoie périodiquement toutes les informations dont il dispose, ce qui, dans un réseau stable, mène à un trafic total plus important que, par exemple, OSPF (qui n'envoie que les changements). Ensuite, Babel a des mécanismes d'attente lorsqu'un préfixe disparait, qui s'appliquent aux préfixes plus généraux. Ainsi, lorsque deux préfixes deviennent agrégés, l'agrégat n'est pas joignable immédiatement.

Comment Babel atteint-il ses merveilleux objectifs ? La section 2 détaille les principes de base du protocole, la 3 l'échange de paquets et la 4 l'encodage d'iceux. Commençons par les principes. Babel est fondé sur le bon vieil algorithme de Bellman-Ford, tout comme RIP. Tout lien entre deux points A et B a un coût (qui n'est pas forcément un coût monétaire, c'est un nombre qui a la signification qu'on veut, cf. section 3.5.2). Le coût est additif (la somme des coûts d'un chemin complet faisant la métrique du chemin, section 2.1 et annexe A), ce qui veut dire que Métrique(A -> C) - pour une route passant par B >= Coût(A -> B) + Coût(B -> C). L'algorithme va essayer de calculer la route ayant la métrique le plus faible.

Un nœud Babel garde trace de ses voisins nœuds en envoyant périodiquement des messages Hello et en les prévenant qu'ils ont été entendus par des messages IHU (I Heard You). Le contenu des messages Hello et IHU permet de déterminer le coût.

Pour chaque source (d'un préfixe, pas d'un paquet), le nœud garde trace de la métrique vers cette source (lorsqu'un paquet tentera d'atteindre le préfixe annoncé) et du routeur suivant (next hop). Au début, évidemment la métrique est infinie et le routeur suivant indéterminé. Le nœud envoie à ses voisins les routes qu'il connait. Si celle-ci est meilleure que celle que connait le voisin, ce dernier l'adopte (si la distance était infinie - route inconnue, toute route sera meilleure).

L'algorithme « naïf » ci-dessus est ensuite amélioré de plusieurs façons : envoi immédiat de nouvelles routes (sans attendre l'émission périodique), mémorisation, non seulement de la meilleure route mais aussi de routes alternatives, pour pouvoir réagir plus vite en cas de coupure, etc.

La section 2.3 rappelle un problème archi-connu de l'algorithme de Bellman-Ford : la facilité avec laquelle des boucles se forment. Dans le cas d'un réseau simple comme celui-ci babel-simple-topo A annonce une route de métrique 1 vers S, B utilise donc A comme routeur suivant, avec une métrique de 2. Si le lien entre S (S = source de l'annonce) et A casse babel-simple-topo-cut comme B continue à publier une route de métrique 2 vers S, A se met à envoyer les paquets à B. Mais B les renvoie à A, créant ainsi une boucle. Les annonces ultérieures ne résolvent pas le problème : A annonce une route de métrique 3, passant par B, B l'enregistre et annonce une route de métrique 4 passant par A, etc. RIP résout le problème en ayant une limite arbitraire à la métrique, limite qui finit par être atteinte et stoppe la boucle (méthode dite du « comptage à l'infini »).

Cette méthode oblige à avoir une limite très basse pour la métrique. Babel a une autre approche : les mises à jour ne sont pas forcément acceptées, Babel teste pour voir si elles créent une boucle (section 2.4). Toute annonce est donc examinée au regard d'une condition, dite « de faisabilité ». Plusieurs conditions sont possibles. Par exemple, BGP utilise la condition « Mon propre numéro d'AS n'apparaît pas dans l'annonce. ». (Cela n'empêche pas les micro-boucles, boucles de courte durée en cas de coupure, cf. RFC 5715.) Une autre condition, utilisée par DSDV et AODV (RFC 3561), repose sur l'observation qu'une boucle ne se forme que lorsqu'une annonce a une métrique moins bonne que la métrique de la route qui a été retirée. En n'acceptant que les annonces qui améliorent la métrique, on peut donc éviter les boucles. Babel utilise une règle un peu plus complexe, empruntée à EIGRP, qui tient compte de l'histoire des annonces faites par le routeur.

Comme il n'y a pas de miracles en routage, cette idée de ne pas accepter n'importe quelle annonce de route a une contrepartie : la famine. Celle-ci peut se produire lorsqu'il existe une route mais qu'aucun routeur ne l'accepte (section 2.5). EIGRP résout le problème en « rédémarrant » tout le réseau (resynchronisation globale des routeurs). Babel, lui, emprunte à DSDV une solution moins radicale, en numérotant les annonces, de manière strictement croissante, lorsqu'un routeur détecte un changement dans ses liens. Une route pourra alors être acceptée si elle est plus récente (si elle a un numéro de séquence plus élevé), et un routeur Babel peut demander explicitement aux autres routeurs d'incrémenter ce nombre, pour accélérer la convergence. Ce numéro n'est par contre pas utilisé pour sélectionner la meilleure route (seule la métrique compte pour cela), uniquement pour voir si une annonce est récente.

À noter que tout se complique s'il existe plusieurs routeurs qui annoncent originellement la même route (section 2.7 ; un exemple typique est la route par défaut, annoncée par tous les routeurs ayant une connexion extérieure). Babel gère ce problème en associant à chaque préfixe l'identité du routeur qui s'est annoncé comme origine et considère par la suite ces annonces comme distinctes, même si le préfixe est le même. Conséquence : Babel ne peut plus garantir qu'il n'y aura pas de boucle (Babel essaie de construire un graphe acyclique mais l'union de plusieurs graphes acycliques n'est pas forcément acyclique). Par contre, il pourra détecter ces boucles a posteriori et les éliminer plus rapidement qu'avec du comptage vers l'infini.

Notez aussi que chaque routeur Babel est libre de rejeter les routes qui lui semblent déraisonnables, comme 127.0.0.1/32, sans affecter le fonctionnement du protocole (le détail de cette question du filtrage des routes est dans l'annexe C.)

Voilà pour les principes. Et le protocole ? La section 3 le décrit. Chaque routeur a une identité sur huit octets (le plus simple est de prendre l'adresse MAC d'une des interfaces). Les messages sont envoyés dans des paquets UDP et encodés en TLV. Le paquet peut être adressé à une destination unicast ou bien multicast. Les TLV peuvent contenir des sous-TLV dans leur partie Valeur.

Un routeur Babel doit se souvenir d'un certain nombre de choses (section 3.2), notamment :

  • Le numéro de séquence, qui croît strictement,
  • La liste des interfaces réseau où parler le protocole,
  • La liste des voisins qu'on a entendus,
  • La liste des sources (routeurs qui ont été à l'origine de l'annonce d'un préfixe). Elle sert pour calculer les critères d'acceptation (ou de rejet) d'une route. Babel consomme donc plus de mémoire que RIP, qui ne connait que son environnement immédiat, alors qu'un routeur Babel connaît tous les routeurs du réseau.
  • Et bien sûr la table des routes, celle qui, au bout du compte, sera utilisée pour la transmission des paquets.

Les préfixes annoncés sont sans rapport avec la version du protocole IP utilisée pour transporter l'annonce. Un préfixe IPv4 peut donc être envoyé en IPv6. Le RFC recommande de faire tourner Babel sur IPv6, même si le réseau est en partie en IPv4.

Les messages Babel ne bénéficient pas d'une garantie de délivrance (c'est de l'UDP, après tout), mais un routeur Babel peut demander à ses voisins d'accuser réception (section 3.3). La décision de le demander ou pas découle de la politique locale de chaque routeur. Si un routeur ne demande pas d'accusé de réception, l'envoi périodique des routes permettra de s'assurer que, au bout d'un certain temps, tous les routeurs auront toute l'information. Les accusés de réception peuvent toutefois être utiles en cas de mises à jour urgentes dont on veut être sûr qu'elles ont été reçues.

Comment un nœud Babel trouve t-il ses voisins ? La section 3.4 décrit ce mécanisme. Les voisins sont détectés par les messages Hello qu'ils émettent. Les messages IHU (I Heard You) envoyés en sens inverse permettent notamment de s'assurer que le lien est bien bidirectionnel.

Les détails de la maintenance de la table de routage figurent en section 3.5. Chaque mise à jour envoyée par un nœud Babel est un quintuplet {préfixe IP, longueur du préfixe, ID du routeur, numéro de séquence, métrique}. Chacune de ces mises à jour est évaluée en regard des conditions de faisabilité : une distance de faisabilité est un doublet {numéro de séquence, métrique} et ces distances sont ordonnées en comparant d'abord le numéro de séquence (numéro plus élevée => distance de faisabilité meilleure) et ensuite la métrique (où le critère est inverse). Une mise à jour n'est acceptée que si sa distance de faisabilité est meilleure.

Si la table des routes contient plusieurs routes vers un préfixe donné, laquelle choisir et donc réannoncer aux voisins (section 3.6) ? La politique de sélection n'est pas partie intégrante de Babel. Plusieurs mises en œuvre de ce protocole pourraient faire des choix différents. Les seules contraintes à cette politique sont qu'il ne faut jamais réannoncer les routes avec une métrique infinie (ce sont les retraits, lorsqu'une route n'est plus accessible), ou les routes infaisables (selon le critère de faisabilité cité plus haut). Si les différents routeurs ont des politiques différentes, cela peut mener à des oscillations (routes changeant en permanence) mais il n'existe pas à l'heure actuelle de critères scientifiques pour choisir une bonne politique. On pourrait imaginer que le routeur ne garde que la route avec la métrique le plus faible, ou bien qu'il privilégie la stabilité en gardant la première route sélectionnée, ou encore qu'il prenne en compte des critères comme la stabilité du routeur voisin dans le temps. En attendant les recherches sur ce point, la stratégie conseillée est de privilégier la route de plus faible métrique, en ajoutant un petit délai pour éviter de changer trop souvent. Notez que la méthode de calcul des métriques n'est pas imposée par Babel : tant que cette méthode obéit à certains critères, notamment de monotonie, elle peut être utilisée.

Une fois le routeur décidé, il doit envoyer les mises à jour à ses voisins (section 3.7). Ces mises à jour sont transportées dans des paquets multicast (mais peuvent l'être en unicast). Les changements récents sont transmis immédiatement, mais un nœud Babel transmet de toute façon la totalité de ses routes à intervalles réguliers. Petite optimisation : les mises à jour ne sont pas transmises sur l'interface réseau d'où la route venait, mais uniquement si on est sûr que ladite interface mène à un réseau symétrique (un Ethernet filaire est symétrique mais un lien WiFi ad hoc ne l'est pas forcément).

Un routeur Babel peut toujours demander explicitement des annonces de routes à un voisin (section 3.8). Il peut aussi demander une incrémentation du numéro de séquence, au cas où il n'existe plus aucune route pour un préfixe donné (problème de la famine, section 3.8.2.1).

La section 4 spécifie l'encodage des messages Babel sur le réseau. C'est un paquet UDP, envoyé à une adresse multicast (ff02::1:6 ou 224.0.0.111) ou bien unicast, avec un TTL de 1 (puisque les messages Babel n'ont jamais besoin d'être routés), et un port source et destination de 6696. En IPv6, les adresses IP de source et de destination unicast sont locales au lien et en IPv4 des adresses du réseau local.

Les données envoyées dans le message sont typées et la section 4.1 liste les types possibles, par exemple interval, un entier de 16 bits qui sert à représenter des durées en centisecondes (rappelez-vous que, dans Babel, un routeur informe ses voisins de ses paramètres temporels, par exemple de la fréquence à laquelle il envoie des Hello). Plus complexe est le type address, puisque Babel permet d'encoder les adresses par différents moyens (par exemple, pour une adresse IPv6 locale au lien, le préfixe fe80::/64 peut être omis). Quant à l'ID du routeur, cet identifiant est stocké sur huit octets.

Ensuite, ces données sont mises dans des TLV, eux-même placés derrière l'en-tête Babel, qui indique un nombre magique (42...) pour identifier un paquet Babel, un numéro de version (aujourd'hui 2) et la longueur du message. (La fonction babel_print_v2 dans le code de tcpdump est un bon moyen de découvrir les différents types et leur rôle.) Le message est suivi d'une remorque qui n'est pas comptée pour le calcul de la longueur du message, et qui sert notamment pour l'authentification (cf. RFC 8967). La remorque, une nouveauté qui n'existait pas explicitement dans le RFC 6126, est elle-même composée de TLV. Chaque TLV, comme son nom l'indique, comprend un type (entier sur huit bits), une longueur et une valeur, le corps, qui peut comprendre plusieurs champs (dépendant du type). Parmi les types existants :

  • 0 et 1, qui doivent être ignorés (ils servent si on a besoin d'aligner les TLV),
  • 2, qui indique une demande d'accusé de réception, comme le Echo Request d'ICMP (celui qui est utilisé par la commande ping). Le récepteur doit répondre par un message contenant un TLV de type 3.
  • 4, qui désigne un message Hello. Le corps contient notamment le numéro de séquence actuel du routeur. Le type 5 désigne une réponse au Hello, le IHU, et ajoute des informations comme le coût de la liaison entre les deux routeurs.
  • 6 sert pour transmettre l'ID du routeur.
  • 7 et 8 servent pour les routes elles-mêmes. 7 désigne le routeur suivant qui sera utilisé (next hop) pour les routes portées dans les TLV de type 8. Chaque TLV Update (type 8) contient notamment un préfixe (avec sa longueur), un numéro de séquence, et une métrique.
  • 9 est une demande explicite de route (lorsqu'un routeur n'a plus de route vers un préfixe donné ou simplement lorsqu'il est pressé et ne veut pas attendre le prochain message). 10 est la demande d'un nouveau numéro de séquence.

Les types de TLV sont stockés dans un registre IANA. On peut en ajouter à condition de fournir une spécification écrite (« Spécification nécessaire », cf. RFC 8126). Il y a aussi un registre des sous-TLV.

Quelle est la sécurité de Babel ? La section 6 dit franchement qu'elle est, par défaut, à peu près inexistante. Un méchant peut annoncer les préfixes qu'il veut, avec une bonne métrique pour être sûr d'être sélectionné, afin d'attirer tout le trafic.

En IPv6, une protection modérée est fournie par le fait que les adresses source et destination sont locales au lien. Comme les routeurs IPv6 ne sont pas censés faire suivre les paquets ayant ces adresses, cela garantit que le paquet vient bien du réseau local. Une raison de plus d'utiliser IPv6.

Ce manque de sécurité dans le Babel original du RFC 6126 avait suscité beaucoup de discussions à l'IETF lors de la mise de Babel sur le chemin des normes (voir par exemple cet examen de la direction de la sécurité). Normalement, l'IETF exige de tout protocole qu'il soit raisonnablement sécurisé (la règle figure dans le RFC 3365). Certaines personnes s'étaient donc vigoureusement opposées à la normalisation officielle de Babel tant qu'il n'avait pas de solution de sécurité disponible. D'autres faisaient remarquer que Babel était quand même déployable pour des réseaux fermés, « entre copains », même sans sécurité, mais les critiques pointaient le fait que tôt ou tard, tout réseau fermé risque de se retrouver ouvert. D'un autre côté, sécuriser des réseaux « ad hoc », par exemple un lot de machines mobiles qui se retrouvent ensemble pour un événement temporaire, est un problème non encore résolu.

Un grand changement de notre RFC est de permettre la signature des messages. Deux mécanismes existent, décrits dans les RFC 8967 (signature HMAC, pour authentifier, la solution la plus légère) et RFC 8968 (DTLS, qui fournit en plus la confidentialité). (Notons que, en matière de routage, la signature ne résout pas tout : c'est une chose d'authentifier un voisin, une autre de vérifier qu'il est autorisé à annoncer ce préfixe.)

J'ai parlé plus haut de la détermination des coûts des liens. L'annexe A du RFC contient des détails intéressants sur cette détermination. Ainsi, contrairement aux liens fixes, les liens radio ont en général une qualité variable, surtout en plein air. Déterminer cette qualité est indispensable pour router sur des liens radio, mais pas facile. L'algorithme ETX (décrit dans l'article de De Couto, D., Aguayo, D., Bicket, J., et R. Morris, « A high-throughput path metric for multi-hop wireless networks ») est recommandé pour cela.

L'annexe D est consacrée aux mécanismes d'extension du protocole, et reprend largement le RFC 7557, qu'elle remplace. Babel prévoyait des mécanismes d'extension en réservant certaines valeurs et en précisant le comportement d'un routeur Babel lors de la réception de valeurs inconnues. Ainsi :

  • Un paquet Babel avec un numéro de version différent de 2 doit être ignoré, ce qui permet de déployer une nouvelle future version de Babel sans que ses paquets ne cassent les implémentations existantes,
  • Un TLV de type inconnu doit être ignoré (section 4.3), ce qui permet d'introduire de nouveaux types de TLV en étant sûr qu'ils ne vont pas perturber les anciens routeurs,
  • Les données contenues dans un TLV au-delà de sa longueur indiquée, ou bien les données présentes après le dernier TLV, devaient, disait le RFC 7557 qui reprenait le RFC 6126, également être silencieusement ignorées (au lieu de déclencher une erreur). Ainsi, une autre voie d'extension était possible, pour glisser des données supplémentaires. Cette voie est désormais utilisée par les solutions de signature comme celle du RFC 8966.

Quelles sont donc les possibilités d'extensions propres ? Cela commence par une nouvelle version du protocole (l'actuelle version est la 2), qui utiliserait des numéros 3, puis 4... Cela ne doit être utilisé que si la nouvelle version est incompatible avec les précédentes et ne peut pas interopérer sur le même réseau.

Moins radicale, une extension de la version 2 peut introduire de nouveaux TLV (qui seront ignorés par les mises en œuvre anciennes de la version 2). Ces nouveaux TLV doivent suivre le format de la section 4.3. De la même façon, on peut introduire de nouveaux sous-TLV (des TLV contenus dans d'autres TLV, décrits en section 4.4).

Si on veut ajouter des données dans un TLV existant, en s'assurant qu'il restera correctement analysé par les anciennes mises en œuvre, il faut jouer sur la différence entre la taille explicite (explicit size) et la taille effective (natural size) du TLV. La taille explicite est celle qui est indiqué dans le champ Length spécifié dans la section 4.3. La taille effective est celle déduite d'une analyse des données (plus ou moins compliquée selon le type de TLV). Comme les implémentations de Babel doivent ignorer les données situées après la taille explicite, on peut s'en servir pour ajouter des données. Elles doivent être encodées sous forme de sous-TLV, chacun ayant type, longueur et valeur (leur format exact est décrit en section 4.4).

Enfin, après le dernier TLV (Babel est transporté sur UDP, qui indique une longueur explicite), on peut encore ajouter des données, une « remorque ». C'est ce que fait le RFC 8966.

Bon, mais alors quel mécanisme d'extension choisir ? La section 4 fournit des pistes aux développeurs. Le choix de faire une nouvelle version est un choix drastique. Il ne devrait être fait que si la nouvelle version est réellement incompatible avec la précédente.

Un nouveau TLV, ou bien un nouveau sous-TLV d'un TLV existant est la solution à la plupart des problèmes d'extension. Par exemple, si on veut mettre de l'information supplémentaire aux mises à jour de routes (TLV Update), on peut créer un nouveau TLV « Update enrichi » ou bien un sous-TLV de Update qui contiendra l'information supplémentaire. Attention, les conséquences de l'un ou l'autre choix ne seront pas les mêmes. Un TLV « Update enrichi » serait totalement ignoré par un Babel ancien, alors qu'un TLV Update avec un sous-TLV d'« enrichissement » verrait la mise à jour des routes acceptée, seule l'information supplémentaire serait perdue.

Il existe désormais, pour permettre le développement d'extensions, un registre IANA des types de TLV et un des sous-TLV (section 5 du RFC) et plusieurs extensions s'en servent déjà.

Enfin, l'annexe F du RFC résume les changements depuis le premier RFC, le RFC 6126, qui documentait la version 2 de Babel. On reste en version 2 car le protocole de notre RFC reste essentiellement compatible avec le précédent. Il y a toutefois trois fonctions de ce protocole qui pourraient créer des problèmes sur un réseau où certaines machines sont restées au RFC 6126 :

  • Les messages de type Hello en unicast sont une nouveauté. L'ancien RFC ne les mentionnait pas. Cela peut entrainer une mauvaise interprétation des numéros de séquence (qui sont distincts en unicast et multicast).
  • Les messages Hello peuvent désormais avoir un intervalle entre deux messages qui est nul, ce qui n'existait pas avant.
  • Les sous-TLV obligatoires n'existaient pas avant et leur utilisation peut donc être mal interprétée par les vieilles mises en œuvre de Babel.

Bref, si on veut déployer le Babel de ce RFC dans un réseau où il reste de vieilles mises en œuvre, il faut prendre garde à ne pas utiliser ces trois fonctions. Si on préfère mettre à jour les vieux programmes, sans toutefois y intégrer tout ce que contient notre RFC, il faut au minimum ignorer (ou bien gérer correctement) les Hello en unicast, ou bien avec un intervalle nul, et il faut ignorer un TLV qui contient un sous-TLV obligatoire mais inconnu.

Il y a d'autres changements depuis le RFC 6126 mais qui ne sont pas de nature à affecter l'interopérabilité ; voyez le RFC pour les détails.

Vous pourrez trouver plus d'informations sur Babel en lisant le RFC, ou bien sur la page Web officielle. Si vous voulez approfondir la question des protocoles de routage, une excellente comparaison a été faite par David Murray, Michael Dixon et Terry Koziniec dans « An Experimental Comparison of Routing Protocols in Multi Hop Ad Hoc Networks » où ils comparent Babel (qui l'emporte largement), OLSR (RFC 7181) et Batman (ce dernier est dans le noyau Linux officiel). Notez aussi que l'IETF a un protocole standard pour ce problème, RPL, décrit dans le RFC 6550. Si vous aimez les vidéos, l'auteur de Babel explique le protocole en anglais.

Qu'en est-il des mises en œuvre de ce protocole ? Il existe une implémentation d'exemple, babeld, assez éprouvée pour être disponible en paquetage dans plusieurs systèmes, comme babeld dans Debian ou dans OpenWrt, plateforme très souvent utilisée pour des routeurs libres (cf. https://openwrt.org/docs/guide-user/services/babeld). babeld ne met pas en œuvre les solutions de sécurité des RFC 8966 ou RFC 8967. Une autre implémentation se trouve dans Bird. Si vous voulez écrire votre implémentation, l'annexe E contient plusieurs conseils utiles, accompagnés de calculs, par exemple sur la consommation mémoire et réseau. Le RFC proclame que Babel est un protocole relativement simple et, par exemple, l'implémentation de référence contient environ 12 500 lignes de C.

Néanmoins, cela peut être trop, une fois compilé, pour des objets (le RFC cite les fours à micro-ondes...) et l'annexe E décrit donc des sous-ensembles raisonnables de Babel. Par exemple, une mise en œuvre passive pourrait apprendre des routes, sans rien annoncer. Plus utile, une mise en œuvre « parasite » n'annonce que la route vers elle-même et ne retransmet pas les routes apprises. Ne routant les paquets, elle ne risquerait pas de créer des boucles et pourrait donc omettre certaines données, comme la liste des sources. (Le RFC liste par contre ce que la mise en œuvre parasite doit faire.)

Toujours côté programmes, tcpdump et Wireshark savent afficher les paquets Babel.


Téléchargez le RFC 8966


L'article seul

RFC 8965: Applicability of the Babel Routing Protocol

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : J. Chroboczek (IRIF, University of Paris-Diderot)
Pour information
Réalisé dans le cadre du groupe de travail IETF babel
Première rédaction de cet article le 12 janvier 2021


Comme tout bon protocole, le protocole de routage Babel, normalisé dans le RFC 8966 ne fait pas de miracles et ne marche pas dans tous les cas. Il est donc utile de savoir quels sont les cas où Babel est efficace et utile. Ce RFC s'applique à identifier et documenter les créneaux pour Babel.

C'est qu'il en existe beaucoup de protocoles de routage internes à un AS. Le RFC cite OSPF (RFC 5340) et IS-IS (RFC 1195), qui ont la faveur des grands réseaux gérés par des professionnels, mais je trouve que Babel se situe plutôt du côté de protocoles prévus pour des réseaux moins organisés, comme Batman ou RPL (RFC 6550). Je vous laisse lire le RFC 8966 pour voir comment fonctionne Babel. Disons juste que c'est un protocole à vecteur de distances (comme RIPRFC 2453 - mais sans ses inconvénients) et qui considère la faisabilité de chaque route potentielle avant de l'ajouter, supprimant ainsi le risque de boucles. En refusant des routes qui pourraient peut-être créer une boucle, le risque est la famine, l'absence de route pour une destination, risque dont Babel se protège avec un mécanisme de numéro de séquence dans les annonces.

La section 2 de notre RFC explicite les caractéristiques de Babel, les bonnes et les mauvaises. D'abord, la simplicité. Babel est conceptuellement simple, ce qui facilite les analyses du protocole, et aussi sa mise en œuvre. Comme le note le RFC, Babel peut être expliqué en un micro-siècle. Et question programmation, le RFC cite une mise en œuvre de Babel réalisée en deux nuits (le RFC ne dit pas ce que le ou la programmeur·e faisait de jour…)

Ensuite, la résistance. Babel ne dépend que de quelques propriétés simples du réseau et peut donc fonctionner dans un large éventail de situations. Babel demande juste que les métriques soient strictement monotones croissantes (emprunter le chemin A puis le B, doit forcément coûter strictement plus cher que de juste prendre le chemin A, autrement des boucles pourraient se former) et distributives à gauche (cf. « Metarouting » de Griffin et Sobrinho). En revanche, Babel n'exige pas un transport fiable (les paquets ont le droit de se perdre, ou de doubler un autre paquet) et n'exige pas que la communication soit transitive (dans les liens radio, il peut arriver que A puisse joindre B et B puisse parler à C, sans que pour autant A puisse communiquer directement avec C). Des protocoles comme OSPF (RFC 5340) ou IS-IS sont bien plus exigeants de ce point de vue.

Babel est extensible : comme détaillé dans l'annexe C du RFC 8966, le protocole Babel peut être étendu. Cela a été fait, par exemple, pour permettre du routage en fonction de la source (draft-ietf-babel-source-specific) ou bien du routage en fonction du RTT (draft-ietf-babel-rtt-extension). Il y a aussi des extensions qui n'ont pas (encore ?) été déployées comme du routage en fonction des fréquences radio (draft-chroboczek-babel-diversity-routing) ou en fonction du ToS (draft-chouasne-babel-tos-specific).

Mais Babel a aussi des défauts, notamment :

  • Babel envoie périodiquement des messages, même quand il n'y a eu aucun changement. Cela permet de ne pas dépendre d'un transport fiable des paquets mais c'est du gaspillage lorsque le réseau est stable. Un grand réseau très stable et bien géré a donc plutôt intérêt à utiliser des protocoles comme OSPF, pour diminuer le trafic dû au routage. À l'autre extrémité, certains réseaux de machines contraintes (par exemple tournant uniquement sur batterie) n'auront pas intérêt à utiliser un protocole comme Babel, qui consomme de l'énergie même quand le réseau n'a pas changé.
  • Avec Babel, chaque routeur connait toute la table de routage. Si des routeurs sont limités en mémoire, cela peut être un problème, et des protocoles comme AODV (RFC 3561), RPL (RFC 6550) ou LOADng sont peut-être plus adaptés.
  • Babel peut être lent à récupérer lorsqu'il fait de l'agrégation de préfixes, et qu'une route plus spécifique est retirée.

Babel a connu plusieurs déploiements dans le monde réel (section 3). Certains de ces déploiements étaient dans des réseaux mixtes, mêlant des parties filaires, routant sur le préfixe, et des parties radio, avec du routage mesh sur les adresses IP. Babel a aussi été déployé dans des overlays, en utilisant l'extension tenant compte du RTT, citée plus haut. Il a aussi été utilisé dans des réseaux purement mesh. Voir à ce sujet les articles « An experimental comparison of routing protocols in multi hop ad hoc networks » et « Real-world performance of current proactive multi-hop mesh protocols ». Ces réseaux utilisent traditionnellement plutôt des protocoles comme OLSR (RFC 7181). Enfin, Babel a été déployé dans des petits réseaux non gérés (pas d'administrateur système).

Et la sécurité, pour finir (section 5). Comme tous les protocoles à vecteur de distance, Babel reçoit l'information de ses voisins. Il faut donc leur faire confiance, un voisin menteur peut annoncer ce qu'il veut. En prime, si le réseau sous-jacent n'est pas lui-même sécurisé (par exemple si c'est du WiFi sans WPA), il n'y a même pas besoin d'être routeur voisin, toute machine peut tripoter les paquets.

Pour empêcher cela, il y a deux solutions cryptographiques, dans les RFC 8967 (la solution la plus simple) et RFC 8968 (plus complexe mais plus sûre et qui fournit en prime de la confidentialité). La solution avec le MAC, normalisée dans le RFC 8967, est celle recommandée car elle convient mieux au caractère de la plupart des réseaux utilisant Babel. (Le RFC n'en parle apparamment pas, mais notez qu'authentifier le voisin ne résout pas complètement le problème. On peut être authentifié et mentir.)

Enfin, si on n'utilise pas de solution de confidentialité, un observateur peut déduire des messages Babel la position d'un routeur WiFi qui se déplacerait, ce qui peut être considéré comme un problème.

Sinon, pour creuser cette question de l'applicabilité de Babel, vous pouvez lire le texte, très vivant, « Babel does not care ».


Téléchargez le RFC 8965


L'article seul

RFC 8967: Message Authentication Code (MAC) Authentication for the Babel Routing Protocol

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : C. Dô, W. Kołodziejak, J. Chroboczek (IRIF, University of Paris-Diderot)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF babel
Première rédaction de cet article le 12 janvier 2021


Le protocole de routage Babel, normalisé dans le RFC 8966, avait à l'origine zéro sécurité. N'importe quelle machine pouvait se dire routeur et annoncer ce qu'elle voulait. Le RFC 7298 avait introduit un mécanisme d'authentification. Ce nouveau RFC le remplace avec un nouveau mécanisme. Chaque paquet est authentifié par HMAC, et les routeurs doivent donc partager une clé secrète.

Comme, par défaut, Babel croit aveuglément ce que ses voisins lui racontent, un méchant peut facilement, par exemple, détourner du trafic (en annonçant une route de plus forte préférence). Le problème est bien connu mais n'a pas de solution simple. Par exemple, Babel permet à la fois de l'unicast et du multicast, le second étant plus difficile à protéger. Une solution de sécurité, DTLS, spécifiée pour Babel dans le RFC 8968, résout le problème en ne faisant que de l'unicast. Notre RFC choisit une autre solution, qui marche pour l'unicast et le multicast. Chaque paquet est authentifié par un MAC attaché au paquet, calculé entre autres à partir d'une clé partagée.

La solution décrite dans ce RFC implique que tous les routeurs connectés au réseau partagent la clé secrète, et que tous ces routeurs soient eux-mêmes de confiance (l'authentification n'implique pas l'honnêteté du routeur authentifié, point très souvent oublié quand on parle d'authentification…) En pratique, c'est un objectif difficile à atteindre, il nécessite un réseau relativement bien géré. Pour un rassemblement temporaire où tout le monde partage sa connectivité, faire circuler ce mot de passe partagé sera difficile.

Ce mécanisme a par contre l'avantage de ne pas nécessiter que les horloges soient correctes ou synchronisées, et ne nécessite pas de stockage de données permanent (ce qui serait contraignant pour, par exemple, certains objets connectés).

Pour que tout marche bien et qu'on soit heureux et en sécurité, ce mécanisme d'authentification compte sur deux pré-requis :

  • Une fonction MAC sécurisée (évidemment), c'est-à-dire qu'on ne puisse pas fabriquer un MAC correct sans connaitre la clé secrète,
  • Que les nœuds Babel arrivent à ne pas répéter certaines valeurs qu'ils transmettent. Cela peut se faire avec un générateur aléatoire correct (RFC 4086) mais il existe aussi d'autres solutions pour générer des valeurs uniques, non réutilisables.

En échange de ces garanties, le mécanisme de ce RFC garantit l'intégrité des paquets et le rejet des rejeux (dans certaines conditions, voir le RFC).

La section 2 du RFC résume très bien le protocole : quand un routeur Babel envoie un paquet sur une des interfaces où la protection MAC a été activée, il calcule le MAC et l'ajoute à la fin du paquet. Quand il reçoit un paquet sur une des interfaces où la protection MAC a été activée, il calcule le MAC et, s'il ne correspond pas à ce qu'il trouve à la fin du paquet, le paquet est jeté. Simple, non ? Mais c'est en fait un peu plus compliqué. Pour protéger contre les attaques par rejeu, la machine qui émet doit maintenir un compteur des paquets envoyés, le PC (Packet Counter). Il est inclus dans les paquets envoyés et protégé par le MAC.

Ce PC ne protège pas dans tous les cas. Par exemple, si un routeur Babel vient de démarrer, et n'a pas de stockage permanent, il ne connait pas les PC de ses voisins et ne sait donc pas à quoi s'attendre. Dans ce cas, il doit ignorer le paquet et mettre l'émetteur au défi de répondre à un numnique qu'il envoie. Le voisin répond en incluant le numnique et son nouveau PC, prouvant ainsi qu'il ne s'agit pas d'un rejeu.

Petite difficulté, en l'absence de stockage permanent, le PC peut revenir en arrière et un PC être réutilisé. Outre le PC, il faut donc un autre nombre, l'index. Celui-ci n'est, comme le numnique utilisé dans les défis, jamais réutilisé. En pratique, un générateur aléatoire est une solution raisonnable pour fabriquer numniques et index.

La section 3 du RFC décrit les structures de données qu'il faut utiliser pour mettre en œuvre ce protocole. La table des interfaces (RFC 8966, section 3.2.3), doit être enrichie avec une indication de l'activation de la protection MAC sur l'interface, et la liste des clés à utiliser (Babel permet d'avoir plusieurs clés, notamment pour permettre le remplacement d'une clé, et le récepteur doit donc les tester toutes). Il faut également ajouter à la table des interfaces l'index et le PC décrits plus haut.

Quant à la table des (routeurs) voisins (RFC 8966, section 3.2.4), il faut y ajouter l'index et le PC de chaque voisin, et le numnique.

Enfin la section 4 détaille le fonctionnement. Comment calculer le MAC (avec un pseudo-en-tête), où mettre le TLV qui indique le PC, et celui qui contient la ou les MAC (dans la remorque, c'est-à-dire la partie du paquet après la longueur explicite), etc. La section 6 fournit quant à elle le format exact des TLV utilisés : le MAC TLV qui stocke le MAC, le PC TLV qui indique le compteur, et les deux TLV qui permettent de lancer un défi et d'obtenir une réponse, pour se resynchroniser en cas d'oubli du compteur. Ils ont été ajoutés au registre IANA.

Les gens de l'opérationnel aimeront la section 5, qui décrit comment déployer initialement cette option, et comment effectuer un changement de clé. Pour le déploiement initial, il faut configurer les machines dans un mode où elles signent mais ne vérifient pas les paquets entrants (il faut donc que les implémentations aient un tel mode). Cela permet de déployer progressivement. Une fois tous les routeurs ainsi configurés, on peut activer le mode normal, avec signature et vérification. Pour le remplacement de clés, on ajoute d'abord la nouvelle clé aux routeurs, qui signent donc avec les deux clés, l'ancienne et la nouvelle, puis, une fois que tous les routeurs ont la nouvelle clé, on retire l'ancienne.

Un petit bilan de la sécurité de ce mécanisme, en section 7 : d'abord un rappel qu'il est simple et qu'il ne fournit que le minimum, l'authentification et l'intégrité des paquets. Si on veut d'avantage, il faut passer à DTLS, avec le RFC 8968. Ensuite, certaines valeurs utilisées doivent être générées sans que l'attaquant puisse les deviner, ce qui nécessite, par exemple, un générateur de nombres aléatoires sérieux. D'autant plus que la taille limitée de certaines valeurs peut permettre des attaques à la force brute. Si, par exemple, les clés dérivent d'une phrase de passe, il faut une bonne phrase de passe, plus une fonction de dérivation qui gêne ces attaques, comme PBKDF2 (RFC 2898), bcrypt ou scrypt (RFC 7914).

Et, comme toujours, il y a la lancinante menace des attaques par déni de service, par exemple en envoyant des paquets délibérement conçus pour faire faire des calculs cryptographiques inutiles aux victimes. C'est pour limiter leurs conséquences que, par exemple, Babel impose de limiter le rythme d'envoi des défis, pour éviter de s'épuiser à défier un attaquant.

Je n'ai pas vu quelles mises en œuvre de Babel avaient ce mécanisme. il ne semble pas dans la version officielle de babeld, en tout cas, même si il y a du code dans une branche séparée. Et ce n'est pas encore dans une version officielle de BIRD mais le code est déjà écrit.

Le RFC ne décrit pas les changements depuis le RFC 7298 car il s'agit en fait d'un protocole différent, et incompatible (ce ne sont pas les mêmes TLV, par exemple).

Merci à Juliusz Chroboczek pour sa relecture.


Téléchargez le RFC 8967


L'article seul

RFC 8968: Babel Routing Protocol over Datagram Transport Layer Security

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : A. Decimo (IRIF, University of Paris-Diderot), D. Schinazi (Google LLC), J. Chroboczek (IRIF, University of Paris-Diderot)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF babel
Première rédaction de cet article le 12 janvier 2021


Le protocole de routage Babel, normalisé dans le RFC 8966, n'offre par défaut aucune sécurité. Notamment, il n'y a aucun moyen d'authentifier un routeur voisin, ni de s'assurer que les messages suivants viennent bien de lui. Sans même parler de la confidentialité de ces messages. Si on veut ces services, ce RFC fournit un moyen : sécuriser les paquets Babel avec DTLS.

La sécurité est évidemment souhaitable pour un protocole de routage. Sans elle, par exemple, une méchante machine pourrait détourner le trafic. Cela ne veut pas dire qu'on va toujours employer une solution de sécurité. Babel (RFC 8966) est conçu entre autres pour des réseaux peu ou pas gérés, par exemple un événement temporaire où chacun apporte son PC et où la connectivité se fait de manière ad hoc. Dans un tel contexte, déployer de la sécurité ne serait pas facile. Mais, si on y tient, Babel fournit désormais deux mécanismes de sécurité (cf. RFC 8966, section 6), l'un, plutôt simple et ne fournissant pas de confidentialité, est décrit dans le RFC 8967, l'autre, bien plus complet, figure dans notre RFC et repose sur DTLS (qui est normalisé dans le RFC 6347). DTLS, version datagramme de TLS, fournit authentification, intégrité et confidentialité.

L'adaptation de DTLS à Babel est décrite dans la section 2 du RFC. Parmi les problèmes, le fait que DTLS soit très asymétrique (client-serveur) alors que Babel est pair-à-pair, et le fait que DTLS ne marche qu'en unicast alors que Babel peut utiliser unicast ou multicast. Donc, chaque routeur Babel doit être un serveur DTLS, écoutant sur le port 6699 (qui n'est pas le 6696 du Babel non sécurisé). Le routeur Babel continue à écouter sur le port non chiffré, et, lorsqu'il entend un nouveau routeur s'annoncer en multicast, il va tenter de communiquer en DTLS avec lui. Puisque DTLS, comme TLS, est client-serveur, il faut décider de qui sera le client et qui sera le serveur : le routeur de plus faible adresse sera le client (par exemple, fe80::1:2 est inférieure à fe80::2:1. Le serveur différencie les sessions DTLS par le port source ou par les connection identifiers du draft draft-ietf-tls-dtls-connection-id. Comme avec le Babel non chiffré, les adresses IPv6 utilisées doivent être des adresses locales au lien. Client et serveur doivent s'authentifier, en suivant les méthodes TLS habituelles (chacun doit donc avoir un certificat).

Une fois que la session DTLS est en marche, les paquets Babel unicast passent sur cette session et sont donc intégralement (du premier au dernier octet) protégés par le chiffrement. Pour que la sécurité fournie par DTLS soit ne soit pas compromise, le routeur ne doit plus envoyer à son voisin de paquets sur le port non chiffré, à part des paquets Hello qui sont transmis en multicast (pour lequel DTLS ne marche pas) et qui permettent de découvrir d'éventuels nouveaux voisins (la règle exacte est un peu plus compliquée, regardez le RFC). On ne peut donc plus envoyer d'information en multicast (à part les Hello). En réception, un nœud Babel sécurisé doit ignorer les paquets non protégés par DTLS, sauf l'information de type Hello.

Une stricte sécurité nécessite qu'un routeur Babel sécurisé n'accepte plus de voisins qui ne gèrent pas DTLS, et ignore donc tous leurs paquets sauf ceux qui contiennent un TLV Hello. Autrement, les communications non sécurisées ficheraient en l'air la confidentialité de l'information. Si on veut une sécurité plus relaxée, un nœud peut faire tourner les deux versions du protocole, sécurisée et non sécurisée, mais alors, exige le RFC, uniquement sur des interfaces réseau différentes.

Comme toutes les fois où on rajoute des données, on risque de dépasser la MTU. La section 3 du RFC nous rappelle qu'il faut éviter d'envoyer des paquets qui seront fragmentés et donc qu'il faut éviter de fabriquer des paquets qui, après chiffrement, seraient plus gros que la MTU.

Rien n'est parfait en ce bas monde et l'ajout de DTLS, s'il résout quelques problèmes de sécurité, ne fait pas tout, et même parfois ajoute des ennuis. La section 5 du RFC rappelle ainsi qu'un méchant pourrait tenter des négociations DTLS nombreuses avec une machine afin de la faire travailler pour rien (une variante de Slowloris). Limiter le nombre de connexions par client n'aiderait pas puisqu'il pourrait toujours mentir sur son adresse IP.

Même en faisant tourner Babel sur DTLS, les messages de type Hello peuvent toujours être envoyés sans protection, et donc manipulés à loisir. Un routeur Babel doit donc toujours être capable d'utiliser des Hello unicast et protégés.

Et puis bien sûr, limitation classique de TLS, authentifier un routeur voisin et sécuriser la communication avec lui ne signifie pas que ce voisin est honnête ; il peut toujours mentir, par exemple en annonçant des routes vers des préfixes qu'il ne sait en fait pas joindre.

À ma connaissance, il n'existe pas encore de mise en œuvre de ce RFC.


Téléchargez le RFC 8968


L'article seul

happyDomain, pour gérer ses noms de domaine facilement

Première rédaction de cet article le 11 janvier 2021


Le logiciel happyDomain (ou happyDNS) est une interface Web permettant de gérer ses noms de domaine. Pourquoi ? Comment ? Quand est-ce qu'on mange ?

Voyons le pourquoi d'abord. Avoir un nom de domaine à soi est crucial pour une présence en ligne, qu'on soit une association, un particulier ou une entreprise. Si on n'a pas son propre nom de domaine, par exemple parce qu'on communique uniquement sur Facebook, on est à la merci d'une société qui peut changer ses algorithmes, voire vous virer du jour au lendemain. Et, dans ce cas, une fois trouvé un autre hébergement, il faudra prévenir tous vos visiteurs de la nouvelle adresse Web. Les noms de domaine permettent au contraire la stabilité de l'adresse que vous communiquez. Mais pour que ce nom de domaine fonctionne, il faut des serveurs DNS qui répondent aux requêtes des visiteurs, et il faut indiquer à ces serveurs DNS les informations techniques indispensables comme l'adresse IP de votre serveur Web. Une solution simple est de confier toutes ces tâches à l'organisation (par exemple le bureau d'enregistrement) où vous avez acheté le nom de domaine. Certes, vous dépendez d'un seul acteur mais, si l'intermédiaire est honnête, le nom de domaine est à vous et, si vous changez d'intermédiaire, vous n'aurez pas à recommencer le travail de communication sur votre adresse Web. À l'autre extrémité du spectre des solutions est l'hébergement de vos propres serveurs DNS, dans lesquels vous rentrez vous-même les informations nécessaires. C'est ce que je fais pour le domaine bortzmeyer.org où se trouve ce blog mais cela nécessite quelques compétences techniques et surtout du temps. Même si vous êtes un professionnel des serveurs Internet, vous n'avez pas forcément le temps et l'envie de vous en occuper vous-même.

Il peut aussi y avoir des solutions intermédiaires entre « tout sous-traiter » et « tout faire soi-même ». C'est là que se situe le projet happyDomain (à l'origine happyDNS), le « Comment » de mon introduction. À terme, le projet veut couvrir plusieurs aspects de la gestion de noms de domaines mais, ici, je vais parler de ce qui est immédiatement disponible, à savoir une interface perfectionnée et agréable pour gérer les informations que les serveurs DNS distribueront au monde entier. (Mais rappelez-vous que d'autres possibilités sont prévues.) Une telle interface est souvent fournie par les hébergeurs DNS mais je trouve qu'elles sont souvent de médiocre qualité, par exemple parce qu'elles ne permettent pas d'indiquer tous les types d'information nécessaires. Et, souvent, ces interfaces sont soit trop complexes pour les utilisateurs, soit trop limitées en ne permettant pas de faire des choses non triviales. En outre, comme elles sont dépendantes de l'hébergeur DNS, changer d'hébergeur nécessite de tout réapprendre. happyDomain, au contraire, vous rend indépendant de l'hébergeur.

Le principe est le suivant : si votre hébergeur est dans la liste des hébergeurs reconnus, vous configurez un accès à cet hébergeur (typiquement via son API) et vous pouvez ensuite gérer le contenu de votre domaine via happyDomain. Si vous changez d'hébergeur, ou si vous en avez plusieurs, pas besoin de réapprendre. happydns-providers.png

Ici, je vais utiliser Gandi. Dans l'interface de Gandi, le menu Paramètres puis Sécurité du compte permet de configurer une clé d'API que l'on indiquera à happyDomain : happydns-api-key-gandi-2.png

On voit alors dans happyDomain ses domaines et on peut les importer dans la base de happyDomain. On peut ensuite les gérer, ajouter des enregistrements, en retirer, etc. Il y a plein de bonnes idées de présentation, par exemple les alias, les surnoms d'un nom sont visualisés de manière claire et pas avec des termes techniques très trompeurs comme « CNAME » : happydns-cname-gandi.png

D'une manière générale, le but de happyDomain est de présenter une vision de plus haut niveau des modifications DNS, pour pouvoir se concentrer sur le contenu et pas sur des détails subtils de syntaxe. Ce n'est pas encore réalisé partout (ainsi, pour l'enregistrement SPF, il faut encore utiliser la syntaxe SPF qui est assez rébarbative) mais c'est un but sympa.

Les modifications qu'on veut faire sont bien représentées, lorsqu'on valide : happydns-changes-gandi.png

J'apprécie également le fait qu'on dispose d'un historique de ses contenus DNS, et qu'on ait plusieurs présentations possibles du contenu.

Je m'aperçois que je n'ai pas encore parlé des auteurs d'happyDomain. Ce n'est pas moi, je n'ai participé que comme donneur de conseils (c'est moins fatigant), les félicitations vont donc à Pierre-Olivier et à toute l'équipe qui a travaillé. J'avais écrit un article sur l'hébergement DNS qui a été partiellement une source d'inspiration pour happyDomain, mais, pour l'instant, la partie « hébergement » n'est pas encore développée. Mais le projet démarre déjà très bien.


L'article seul

RFC 9003: Extended BGP Administrative Shutdown Communication

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : J. Snijders (NTT), J. Heitz (Cisco), J. Scudder (Juniper), A. Azimov (Yandex)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 9 janvier 2021


Ce nouveau RFC normalise un mécanisme pour transmettre un texte en langue naturelle à un pair BGP afin de l'informer sur les raisons pour lesquelles on coupe la session. Il remplace le RFC 8203, notamment en augmentant la longueur maximale du message, afin de faciliter les messages en Unicode.

Le protocole de routage BGP offre un mécanisme de coupure propre de la session, le message NOTIFICATION avec le code Cease (RFC 4271, section 6.7). En prime, le RFC 4486 ajoutait à ce code des sous-codes permettant de préciser les raisons de la coupure. Une coupure volontaire et manuelle aura typiquement les sous-codes 2 (Administrative Shutdown), 3 (Peer De-configured) ou 4 (Administrative Reset). (Ces sous-codes sont enregistrés à l'IANA.) Et enfin le RFC 8203, déjà cité, ajoutait à ces sous-codes du texte libre, où on pouvait exprimer ce qu'on voulait, par exemple « [#56554] Coupure de toutes les sessions BGP au DE-CIX pour mise à jour logicielle, retour dans trente minutes ». Notre RFC ne modifie que légèrement cette possibilité introduite par le RFC 8203, en augmentant la taille maximale du texte envoyé.

Bien sûr, la raison de la coupure peut être connue par d'autres moyens. Cela a pu être, par exemple, pour une session au travers d'un point d'échange, un message envoyé sur la liste du point d'échange, annonçant la date (en UTC, j'espère !) et la raison de la coupure. De tels message se voient régulièrement sur les listes, ici au France-IX :

      
Date: Wed, 16 Dec 2020 11:54:21 +0000
From: Jean Bon <jbon@operator.example>
To: <paris@members.franceix.net>
Subject: [FranceIX members] [Paris] AS64530 [REF056255] Temporary shut FranceIX sessions

Hi France-IX members,

This mail is to inform you that we are going to shut down all our
sessions on France-IX' Paris POP on 2021-01-05 08:00:00 UTC for 30
minutes, in order to upgrade the router.

Please use the ticket number [REF056255] for every correspondance about
this action.


    

Mais quand la coupure effective se produit, on a parfois oublié le message d'avertissement, ou bien on a du mal à le retrouver. D'où l'importance de pouvoir rappeler les informations importantes dans le message de coupure, qui, espérons-le, sera affiché quelque part chez le pair, ou bien journalisé par syslog.

La section 2 décrit le format exact de ce mécanisme. La chaîne de caractères envoyée dans le message BGP NOTIFICATION doit être en UTF-8. Sa taille maximale est de 255 octets (ce qui ne fait pas 255 caractères, attention). À part ces exigences techniques, son contenu est laissé à l'appréciation de l'envoyeur.

La section 3 de notre RFC ajoute quelques conseils opérationnels. Par exemple, si vous utilisez un système de tickets pour suivre vos tâches, mettez le numéro du ticket correspondant à l'intervention de maintenance dans le message. Vos pairs pourront ainsi plus facilement vous signaler à quoi ils font référence.

Attention à ne pas agir aveuglément sur la seule base d'un message envoyé par BGP, notamment parce que, si la session BGP n'était pas sécurisée par, par exemple, IPsec, le message a pu être modifié en route.

L'annexe B du RFC résume les principaux changements depuis le RFC 8203. Le plus important est que la longueur maximale du message passe de 128 à 255 octets, notamment pour ne pas défavoriser les messages qui ne sont pas en ASCII. Comme l'avait fait remarquer lors de la discussion un opérateur du MSK-IX, si la phrase « Planned work to add switch to stack. Completion time - 30 minutes » fait 65 octets, sa traduction en russe aurait fait 119 octets.


Téléchargez le RFC 9003


L'article seul

Échec de RPZ à l'IETF

Première rédaction de cet article le 5 janvier 2021


RPZ (Response Policy Zones) est une technologie permettant de configurer les mensonges d'un résolveur DNS. Il était prévu de la normaliser à l'IETF mais le projet a finalement échoué. Pourquoi ?

Un résolveur DNS est censé transmettre fidèlement les réponses envoyées par les serveurs faisant autorité. S'il ne le fait pas, on parle de résolveur menteur ou, pour employer le terme plus corporate du RFC 8499, de « résolveur politique ». De tels résolveurs menteurs sont utilisés pour de nombreux usages, du blocage de la publicité (par exemple avec Pi-hole) à la censure étatique ou privée. L'administrateur d'un tel résolveur menteur peut configurer la liste des domaines où un mensonge sera fait à la main. Mais c'est évidemment un long travail que de suivre les changements d'une telle liste. Il peut être préférable de sous-traiter ce travail. RPZ (Response Policy Zones) est conçu pour faciliter cette sous-traitance.

Pour les principes techniques de RPZ, je vous laisse lire mon article technique, ou bien regarder le site « officiel ». RPZ est mis en œuvre dans plusieurs logiciels résolveurs comme BIND, Unbound (depuis la version 1.10, cf. cet article) ou Knot.

Comme RPZ est là pour permettre la communication entre le fournisseur de listes de mensonges et le résolveur, il serait intéressant techniquement qu'il soit normalisé. Un effort a donc été fait à l'IETF pour cela. Sur l'excellent DataTracker de l'IETF, vous pouvez suivre l'histoire de ce projet depuis 2016 : d'abord une contribution individuelle, draft-vixie-dns-rpz, puis après adoption par un groupe de travail de l'IETF, une version de groupe (qu'on reconnait à son nom commençant par draft-ietf-NOMDUGROUPE), draft-ietf-dnsop-dns-rpz puis, après une interruption d'une année, à nouveau un retour à la contribution individuelle, draft-vixie-dnsop-dns-rpz, finalement abandonnée depuis aujourd'hui plus de deux ans.

Pourquoi cet échec ? Notez d'abord que l'IETF ne documente pas explicitement les échecs. Il n'y a pas eu de décision officielle « on laisse tomber », avec un texte expliquant pourquoi. Il s'agit plutôt d'un document qui a eu à faire face à tellement de problèmes que plus personne n'avait envie de travailler dessus.

Quels étaient ces problèmes ? Commençons par le plus gros, le problème politique. Beaucoup de gens ne sont pas d'accord avec la censure faite via le DNS et craignaient que RPZ n'aide les méchants davantage que les gentils. À ce problème politique (tout le monde n'étant pas d'accord sur la légitimité de la censure) s'ajoutait un problème classique lors des débats politico-techniques, celui de la neutralité de la technique (j'en ai parlé dans mon livre, p. 148 et suivantes de l'édition papier). Le débat est récurrent à l'IETF et peut se simplifier en deux positions opposées :

  • Nous normalisons juste des techniques, les gens peuvent ensuite les utiliser pour le bien ou pour le mal et, de toute façon, si l'IETF ne normalise pas cette technique dans un RFC, elle sera utilisée quand même, et peut-être normalisée par des organismes moins scrupuleux comme l'UIT.
  • Nous ne pouvons pas nier les conséquences des décisions que nous prenons (RFC 8890), tout est politique (RFC 8280), et un RFC sera interprété comme une approbation ou quasi-approbation par l'IETF.

Pris entre ces deux positions, le document a ainsi été adopté par le groupe de travail DNSOP, puis abandonné, après de longues et parfois vigoureuses discussions.

Une autre raison de la non-normalisation de RPZ est peut-être le fait qu'en pratique, ce protocole n'a été adopté que par des acteurs commerciaux. Je n'ai pas trouvé de flux RPZ librement accessible, par exemple avec une liste de domaines liés à la publicité (ce serait bien pratique pour les bloquer). Peut-être https://block.energized.pro/ ? Mais, s'ils ont bien le format RPZ, ils ne rendent pas ces flux accessibles en AXFR, ce qui complique leur mise à jour.

Un problème supplémentaire est également survenu dans la discussion : le contrôle du changement. Normalement, une fois un protocole publié par l'IETF, c'est l'IETF qui gouverne les évolutions futures. Or, ici, les auteurs originaux de RPZ avaient écrit dans le document qu'ils gardaient le contrôle et pouvaient donc empêcher telle ou telle évolution de la norme. En contradiction avec les règles de l'IETF, cette mention a contribué à l'échec de RPZ dans le groupe de travail. Il aurait quand même pu être publié en RFC non-IETF mais le projet est finalement mort d'épuisement.


L'article seul

RFC 8956: Dissemination of Flow Specification Rules for IPv6

Date de publication du RFC : Décembre 2020
Auteur(s) du RFC : C. Loibl (next layer Telekom GmbH), R. Raszuk (NTT Network Innovations), S. Hares (Huawei)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 1 janvier 2021


Il existe un mécanisme de diffusion des règles de filtrage IP, FlowSpec, normalisé dans le RFC 8955. Ce mécanisme permet d'utiliser BGP pour envoyer à tous les routeurs d'un AS les mêmes règles, ce qui est très pratique, par exemple pour bloquer une attaque sur tous les routeurs d'entrée du domaine. Le FlowSpec original ne gérait qu'IPv4, voici son adaptation à IPv6.

En fait, il n'y avait pas grand'chose à faire. Après tout, IPv6 n'est pas un nouveau protocole, juste une nouvelle version du même protocole IP. Des concepts cruciaux, comme la définition d'un préfixe en préfixe/longueur, ou comme la règle du préfixe le plus spécifique restent les mêmes. Ce RFC est donc assez simple. Il ne reprend pas l'essentiel du RFC 8955, il ajoute juste ce qui est spécifique à IPv6. (À l'IETF, il avait été proposé de fusionner les deux documents mais, finalement, il y a un RFC générique + IPv4, le RFC 8955, et un spécifique à IPv6, notre RFC 8956.)

Petit rappel sur FlowSpec : les règles de filtrage sont transportées en BGP, les deux routeurs doivent annoncer la capacité « multi-protocole » (les capacités sont définies dans le RFC 5492) définie dans le RFC 4760, la famille de l'adresse (AFI pour Address Family Identifier) est 2 (qui indique IPv6) et le SAFI (Subsequent Address Family Identifier) est le même qu'en IPv4, 133.

Le gros de notre RFC (section 3) est l'énumération des différents types d'identifiant d'un trafic à filtrer. Ce sont les mêmes qu'en IPv4 mais avec quelques adaptations. Ainsi, le type 1, « préfixe de destination » permet par exemple de dire à ses routeurs « jette à la poubelle tout ce qui est destiné à 2001:db:96b:1::/64 ». Son encodage ressemble beaucoup à celui en IPv4 mais avec un truc en plus, le décalage (offset) depuis le début de l'adresse. Avec un décalage de 0, on est dans le classique préfixe/longueur mais on peut aussi ignorer des bits au début de l'adresse avec un décalage non-nul.

Le type 3, « protocole de niveau supérieur » est l'un de ceux dont la définition IPv6 est la plus différente de celle d'IPv4. En effet, IPv6 a les en-têtes d'extension (RFC 8200, section 4), une spécificité de cette version. Le champ « Next header » d'IPv6 (RFC 8200, section 3) n'a pas la même sémantique que le champ « Protocole » d'IPv4 puisqu'il peut y avoir plusieurs en-têtes avant celui qui indique le protocole de couche 4 (qui sera typiquement TCP ou UDP). Le choix de FlowSpec est que le type 3 désigne le dernier champ « Next header », celui qui identifie le protocole de transport, ce qui est logique, c'est bien là-dessus qu'on veut filtrer, en général. Rappelez-vous au passage que d'analyser les en-têtes d'extension IPv6 pour arriver au protocole de transport n'est hélas pas trivial. Et il y a d'autres pièges, expliqués dans les RFC 7112 et RFC 8883.

Autre type d'identifiant qui est différent en IPv6, le type 7, ICMP. Si le protocole est très proche, les types et les codes ne sont en effet pas les mêmes. Ainsi, l'un des types les plus célèbres, Echo Request, utilisé par ping, vaut 8 en IPv4 et 138 en IPv6.

Les autres types se comportent en IPv6 exactement comme en IPv4. Par exemple, si vous voulez dire à vos routeurs de filtrer sur le port, les types 4, 5 et 6, dédiés à cet usage, ont le même encodage et la même sémantique qu'en IPv4 (ce qui est logique, puisque le port est un concept de couche 4).

FlowSpec est aujourd'hui largement mis en œuvre dans les logiciels de routage, y compris en IPv6. Vous pouvez consulter à ce sujet le rapport de mise en œuvre. Si vous voulez jouer avec FlowSpec, le code Python d'exemple de l'annexe A est disponible en ligne.


Téléchargez le RFC 8956


L'article seul

RFC 8955: Dissemination of Flow Specification Rules

Date de publication du RFC : Décembre 2020
Auteur(s) du RFC : C. Loibl (next layer Telekom GmbH), S. Hares (Huawei), R. Raszuk (Bloomberg LP), D. McPherson (Verisign), M. Bacher (T-Mobile Austria)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 1 janvier 2021


Lorsqu'on a un grand réseau compliqué, diffuser à tous les routeurs des règles de filtrage, par exemple pour faire face à une attaque par déni de service, peut être complexe. Il existe des logiciels permettant de gérer ses routeurs collectivement mais ne serait-il pas plus simple de réutiliser pour cette tâche les protocoles existants et notamment BGP ? Après tout, des règles de filtrage sont une forme de route. On profiterait ainsi des configurations existantes et de l'expérience disponible. C'est ce que se sont dit les auteurs de ce RFC. « FlowSpec » (nom officieux de cette technique) consiste à diffuser des règles de traitement du trafic en BGP, notamment à des fins de filtrage. Ce RFC remplace le RFC FlowSpec original, le RFC 5575, le texte ayant sérieusement changé (mais le protocole est presque le même).

Les routeurs modernes disposent en effet de nombreuses capacités de traitement du trafic. Outre leur tâche de base de faire suivre les paquets, ils peuvent les classifier, limiter leur débit, jeter certains paquets, etc. La décision peut être prise en fonction de critères tels que les adresses IP source et destination ou les ports source et destination. Un flot (flow) est donc défini comme un tuple rassemblant les critères d'acceptation d'un paquet IP. Notre RFC 8955 encode ces critères dans un attribut NLRI (Network Layer Reachability Information est décrit dans la section 4.3 du RFC 4271) BGP, de manière à ce qu'ils puissent être transportés par BGP jusqu'à tous les routeurs concernés. Sans FlowSpec, il aurait fallu qu'un humain ou un programme se connecte sur tous les routeurs et y rentre l'ACL concernée.

Pour reconnaitre les paquets FlowSpec, ils sont marqués avec le SAFI (concept introduit dans le RFC 4760) 133 pour les règles IPv4 (et IPv6 grâce au RFC 8956) et 134 pour celles des VPN.

La section 4 du RFC donne l'encodage du NLRI. Un message UPDATE de BGP est utilisé, avec les attributs MP_REACH_NLRI et MP_UNREACH_NLRI du RFC 4760 et un NLRI FlowSpec. Celui-ci compte plusieurs couples {type, valeur} où l'interprétation de la valeur dépend du type (le type est codé sur un octet). Voici les principaux types :

  • Type 1 : préfixe de la destination, représenté par un octet pour la longueur, puis le préfixe, encodé comme traditionnellement en BGP (section 4.3 du RFC 4271). Ainsi, le préfixe 10.0.1.0/24 sera encodé (noté en hexadécimal) 01 18 0a 00 01 (type 1, longueur 24 - 18 en hexa - puis le préfixe dont vous noterez que seuls les trois premiers octets sont indiqués, le dernier n'étant pas pertinent ici).
  • Type 2 : préfixe de la source (lors d'une attaque DoS, il est essentiel de pouvoir filtrer aussi sur la source).
  • Type 3 : protocole (TCP, UDP, etc).
  • Types 4, 5 et 6 : port (source ou destination ou les deux). Là encore, c'est un critère très important lors du filtrage d'une attaque DoS. Attention, cela suppose que le routeur soit capable de sauter les en-têtes IP (y compris des choses comme ESP) pour aller décoder TCP ou UDP. Tous les routeurs ne savent pas faire cela (en IPv6, c'est difficile).
  • Type 9 : options activées de TCP, par exemple uniquement les paquets RST.

Tous les types de composants sont enregistrés à l'IANA.

Une fois qu'on a cet arsenal, à quoi peut-on l'utiliser ? La section 5 détaille le cas du filtrage. Autrefois, les règles de filtrage étaient assez statiques (je me souviens de l'époque où tous les réseaux en France avaient une ACL, installée manuellement, pour filtrer le réseau de l'EPITA). Aujourd'hui, avec les nombreuses DoS qui vont et viennent, il faut un mécanisme bien plus dynamique. La première solution apparue a été de publier via le protocole de routage des préfixes de destination à refuser. Cela permet même à un opérateur de laisser un de ses clients contrôler le filtrage, en envoyant en BGP à l'opérateur les préfixes, marqués d'une communauté qui va déclencher le filtrage (à ma connaissance, aucun opérateur n'a utilisé cette possibilité, en raison du risque qu'une erreur du client ne se propage). De toute façon, c'est très limité en cas de DoS (par exemple, on souhaite plus souvent filtrer sur la source que sur la destination). Au contraire, le mécanisme FlowSpec de ce RFC donne bien plus de critères de filtrage.

Cela peut d'ailleurs s'avérer dangereux : une annonce FlowSpec trop générale et on bloque du trafic légitime. C'est particulièrement vrai si un opérateur accepte du FlowSpec de ses clients : il ne faut pas permettre à un client de filtrer les autres. D'où la procédure suggérée par la section 6, qui demande de n'accepter les NLRI FlowSpec que s'ils contiennent un préfixe de destination, et que ce préfixe de destination est routé vers le même client qui envoie le NLRI. Ainsi, un client ne peut pas déclencher le filtrage d'un autre puisqu'il ne peut influencer que le filtrage des paquets qui lui sont destinés.

Au fait, en section 5, on a juste vu comment indiquer les critères de classification du trafic qu'on voulait filtrer. Mais comment indiquer le traitement qu'on veut voir appliqué aux paquets ainsi classés ? (Ce n'est pas forcément les jeter : on peut vouloir être plus subtil.) FlowSpec utilise les communautés étendues du RFC 4360. La valeur sans doute la plus importante est 0x8006, traffic-rate, qui permet de spécifier un débit maximal pour les paquets qui correspondent aux critères mis dans le NLRI. Le débit est en octets/seconde. En mettant zéro, on demande à ce que tous les paquets classés soient jetés. (Mais on peut aussi indiquer des paquets/seconde, c'est une nouveauté de ce RFC.) Les autres valeurs possibles permettent des actions comme de modifier les bits DSCP du trafic classé.

Comme toutes les armes, celle-ci peut être dangereuse pour celui qui la manipule. La section 12 est donc la bienvenue, pour avertir de ces risques. Par exemple, comme indiqué plus haut, si on permet aux messages FlowSpec de franchir les frontières entre AS, un AS maladroit ou méchant risque de déclencher un filtrage chez son voisin. D'où l'importance de la validation, n'accepter des règles FlowSpec que pour les préfixes de l'AS qui annonce ces règles.

Ensuite, comme tous les systèmes de commande des routeurs à distance, FlowSpec permet de déclencher un filtrage sur tous les routeurs qui l'accepteront. Si ce filtrage est subtil (par exemple, filtrer tous les paquets plus grands que 900 octets), les problèmes qui en résultent seront difficiles à diagnostiquer.

FlowSpec a joué un rôle important dans la panne Level 3 / CenturyLink d'août 2020. Et, avant cela, dans la panne CloudFlare du 3 mars 2013, où des critères incorrects (une taille de paquet supérieure au maximum permis par IP) avaient été envoyés à tous les routeurs. Ce n'est pas une bogue de FlowSpec : tout mécanisme de diffusion automatique de l'information à N machines différentes a le même problème potentiel. Si l'information était fausse, le mécanisme de diffusion transmet l'erreur à tous... (Dans le monde des serveurs Unix, le même problème peut se produire avec des logiciels comme Chef ou Puppet. Lisez un cas rigolo avec Ansible.) Comme le prévient notre RFC : « When automated systems are used, care should be taken to ensure the correctness of the automated system. » Toutefois, contrairement à ce que laisse entendre le RFC, il n'y a pas que les processus automatiques qui injectent des erreurs : les humains le font aussi.

Si vous voulez en apprendre plus sur FlowSpec :

Si vous vous intéressez à l'utilisation de BGP lors d'attaques par déni de service, vous pouvez aussi consulter les RFC 3882 et RFC 5635.

Les changements depuis la norme originale, le RFC 5575, sont résumés dans l'annexe B. Parmi les principaux :

  • Le RFC 7674 a été intégré ici, et n'est donc plus d'actualité,
  • Les comparaisons entre les valeurs indiquées dans les règles FlowSpec et les paquets qu'on voit passer sont désormais spécifiées plus strictement, avec du code d'exemple (en Python) dans l'annexe A,
  • Les actions fondées sur le trafic peuvent désormais s'exprimer en nombre de paquets et plus seulement en nombre d'octets (certaines attaques par déni de service sont dangereuses par leur nombre de paquets, même si ces paquets sont petits).

FlowSpec est utilisé depuis dix ans et de nombreuses mises en œuvre existent (cf. la liste). Sur les Juniper, on peut consulter leur documentation en ligne.


Téléchargez le RFC 8955


L'article seul

Articles des différentes années : 2021  2020  2019  2018  2017  2016  2015  Précédentes années

Syndication : Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu.

Un article de ce blog au hasard.