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.
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.
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 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
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 :
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 :
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.Update
(type 8) contient notamment un préfixe
(avec sa longueur), un numéro de séquence, et une métrique.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 :
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 :
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).Hello
peuvent désormais
avoir un intervalle entre deux messages qui est nul, ce qui
n'existait pas avant.
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.)
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 RIP - RFC 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 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 ».
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 :
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.
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.
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.
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 :
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 » :
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 :
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.
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.
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 :
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
? Mais, s'ils ont
bien le format RPZ, ils ne rendent pas ces flux accessibles en AXFR,
ce qui complique leur mise à jour.https://block.energized.pro/
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.
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.
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 :
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).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 :
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.
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.