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.


Fiche de lecture : Cavanna, paléontologue !

Auteur(s) du livre : Pascal Tassy
Éditeur : Éditions Matériologiques
978-2-37361-252-3
Publié en 2020
Première rédaction de cet article le 7 avril 2021


Si, comme beaucoup de personnes (comme moi, par exemple), vous ignoriez que Cavanna était féru de paléontologie, vous allez l'apprendre dans ce court livre où l'auteur nous raconte ses échanges scientifiques avec le fondateur de Charlie Hebdo.

Cavanna avait de nombreuses cordes à son arc. Mais ce récit de Pascal Tassy se focalise sur une seule corde : la passion du « rital » pour l'étude des espèces disparues. Cavanna était curieux de sciences et aimait discuter avec les scientifiques. Son arrivée à la soutenance de thèse de l'auteur (thèse sur les mastodontes) avait sérieusement déstabilisé le bientôt docteur. Ils ont finalement parlé d'adaptation, de sélection naturelle, de cladistique, d'écologie… pendant de nombreuses années.

Si Cavanna et Pascal Tassy étaient d'accord sur beaucoup de choses (par exemple pour se moquer des créationnistes), il leur restait des sujets de controverses. J'ai ainsi appris que Cavanna, contrairement à son ami, était plutôt favorable au transhumanisme et tenté par l'idée d'immatérialisme.

Il était même prévu entre les deux amis d'écrire ensemble un livre… qui ne s'est finalement pas fait. À défaut, vous aurez dans ce récit quelques idées sur ce qu'aurait pu être ce livre.

Autre compte-rendu de ce livre, dans Charlie Hebdo.


L'article seul

RFC 9018: Interoperable Domain Name System (DNS) Server Cookies

Date de publication du RFC : Avril 2021
Auteur(s) du RFC : O. Sury (Internet Systems Consortium), W. Toorop (NLnet Labs), D. Eastlake 3rd (Futurewei Technologies), M. Andrews (Internet Systems Consortium)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 6 avril 2021


Le RFC 7873 normalisait un mécanisme, les cookies, pour qu'un serveur DNS authentifie raisonnablement l'adresse IP du client (ce qui, normalement, n'est pas le cas en UDP). Comme seul le serveur avait besoin de reconnaitre ses cookies, le RFC 7873 n'imposait pas un algorithme particulier pour les générer. Cela posait problème dans certains cas et notre nouveau RFC propose donc un mécanisme standard pour fabriquer ces cookies.

L'un des scénarios d'utilisation de ces « cookies standards » est le cas d'un serveur anycast dont on voudrait que toutes les instances génèrent des cookies standardisés, pour qu'une instance puisse reconnaitre les cookies d'une autre. Le RFC 7873, section 6, disait bien que toutes les instances avaient intérêt à partir du même secret mais ce n'était pas plus détaillé que cela. La situation actuelle, où chaque serveur peut faire différemment, est décrite dans le RFC par un mot en anglais que je ne connaissais pas, gallimaufry. D'où l'idée de spécifier cet algorithme, pour simplifier la vie des programmeuses et programmeurs avec un algorithme de génération de cookie bien étudié et documenté ; plus besoin d'en inventer un. Et cela permet de créer un service anycast avec des logiciels d'auteurs différents. S'ils utilisent cet algorithme, ils seront compatibles. Il ne s'agit que d'une possibilité : les serveurs peuvent utiliser cet algorithme mais ne sont pas obligés, le RFC 7873 reste d'actualité.

Comment, donc, construire un cookie ? Commençons par celui du client (section 3). Rappel : le but est d'authentifier un minimum donc, par exemple, le client doit choisir un cookie différent par serveur (sinon, un serveur pourrait se faire passer pour un autre, d'autant plus que le cookie circule en clair), et, donc, il faut utiliser quelque chose de spécifique au serveur dans l'algorithme, par exemple son adresse IP. Par contre, pas besoin de le changer souvent, il peut parfaitement durer des mois, sauf évidemment si un élément entrant dans sa construction change, ou est compromis. Autrefois, il était suggéré d'utiliser l'adresse IP du client dans la construction du cookie client, mais cette suggestion a été retirée car le logiciel ne connait parfois son adresse IP que trop tard (ça dépend de l'API réseau utilisée et, par exemple, avec l'API sockets de si on a déjà fait un bind() et, de toute façon, si on est derrière un routeur NAT, connaitre l'adresse IP locale ne sert pas à grand'chose). Néanmoins, pour éviter qu'un cookie ne permette à un observateur de relier deux requêtes d'une même machine, le cookie doit changer quand l'adresse IP change, comme rappelé par la section 8.1. (C'est particulièrement important si on utilise des techniques de protection de la vie privée comme celle du RFC 8981.)

Voilà, c'est tout parce que ce qui est important dans notre RFC, c'est le cookie serveur (section 4), puisque c'est là qu'on voudrait un cookie identique pour toutes les instances du service. Les éléments utilisés pour le générer sont le cookie du client, l'adresse IP du serveur, quelques métadonnées et un secret (qu'il faudra donc partager au sein du service anycast). Le secret changera, par exemple une fois par mois. Une fois qu'on a tous ces éléments, on va ensuite condenser le tout, ici avec SipHash (cf. J. Aumasson, et D. J. Bernstein, « SipHash: A Fast Short- Input PRF »). (Parmi les critères de choix d'une fonction de condensation, il y a les performances, un serveur DNS actif pouvant avoir à faire ce calcul souvent, pour vérifier les cookies.) Le cookie comprendra un numéro de version, un champ réservé, une estampille temporelle et le condensat. L'algorithme de génération du condensat inclus dans le cookie est donc : Condensat = SipHash-2-4 ( Cookie client | Version | Réservé | Estampille | Client-IP, Secret ), avec :

  • Le signe | indique la concaténation.
  • Le champ Version vaut actuellement 1 (les futures versions seront dans un registre IANA).
  • Le champ Réservé ne comporte pour l'instant que des zéros.
  • L'estampille temporelle sert à éviter les attaques par rejeu et permet de donner une durée de validité aux cookies (le RFC recommande une heure, avec cinq minutes de battement pour tenir compte des horloges mal synchronisées).

On a vu qu'il fallait changer le secret connu du serveur de temps en temps (voire plus rapidement s'il est compromis). Pour que ça ne casse pas tout (un serveur ne reconnaissant pas les cookies qu'il avait lui-même émis avec l'ancien secret…), il faut une période de recouvrement où le serveur connait déjà le nouveau secret (et accepte les cookies ainsi générés, par exemple par les autres instances du service anycast), puis une période où le serveur génère les cookies avec le nouveau secret, mais continue à accepter les cookies anciens (par exemple gardés par des clients). La section 5 rappelle, comme on le fait pour les remplacements de clés DNSSEC, de tenir compte des TTL pour calculer les délais nécessaires.

Si vous voulez mettre en œuvre vous-même cet algorithme, notez que l'annexe A du RFC contient des vecteurs de test, permettant de vérifier si vous ne vous êtes pas trompé.

La section 2 de notre RFC décrit les changements depuis le RFC 7873. Les algorithmes données comme simples suggestions dans les annexes A.1 et B.1 sont trop faibles et ne doivent pas être utilisés. Celui de l'annexe B.2 ne pose pas de problèmes de sécurité mais celui de notre nouveau RFC est préféré.

Plusieurs mises en œuvre de ce nouvel algorithme ont été faites, et leur interopérabilité testée (notamment au cours du hackathon de la réunion IETF 104 à Prague). Au moins BIND, Knot et getdns ont déjà cet algorithme dans leurs versions publiées.


Téléchargez le RFC 9018


L'article seul

Faut-il forcément passer du temps à étudier les techniques qui semblent farfelues ?

Première rédaction de cet article le 29 mars 2021


J'ai vu récemment, mais ce n'était la première fois, une personne se prétendant « inventeur » affirmer que ceux qui riaient de ses prétentions fantaisistes n'avaient pas pris le temps d'examiner son travail et que leurs critiques n'étaient donc pas pertinentes. Le bon sens dit en effet qu'il ne faut pas critiquer sans connaitre, et que connaitre nécessite de passer un peu de temps sur l'objet de la critique. Est-ce que le bon sens a raison ?

Le cas précis auquel je fais allusion concernait la sécurité informatique et l'inventeur prétendait avoir trouvé une solution de sécurité universelle. J'ai rencontré ce cas plusieurs fois en informatique (les participants à l'IETF penseront bien sûr à « IPv10 »). Mais ce serait la même chose avec quelqu'un prétendant avoir trouvé un remède contre toutes les maladies, ou bien une personne affirmant avoir mis au point le mouvement perpétuel. (On trouve même ce syndrome de l'inventeur génial dans les sciences humaines, par exemple les gens annonçant avoir déchiffré le disque de Phaistos.) Dans tous ces cas, face aux première réactions négatives, l'inventeur génial se drape dans sa dignité et dit bien haut que ses opposants n'ont pas lu ses textes, n'ont pas étudié sa machine, et qu'on ne doit donc pas les croire puisqu'ils n'ont même pas fait l'effort minimal de chercher à comprendre.

Ce raisonnement semble s'appuyer sur un principe de base de la science et de la technique : comprendre une invention n'est pas facile, il faut y passer du temps, et, tant qu'on ne l'a pas fait, on doit rester prudent dans ses affirmations. Mais il faut poursuivre plus loin ce raisonnement : c'est justement parce qu'évaluer sérieusement une invention prend du temps qu'on ne peut pas le faire pour chaque type qui annonce à l'univers qu'il a inventé un truc extraordinaire. Toute personne connue dans son domaine voit passer de nombreuses annonces d'inventions géniales, et si elle consacrait à chacune le temps nécessaire pour être absolument sûre de sa vacuité, cette personne n'aurait pas le temps de faire du travail sérieux.

Est-ce injuste ? Peut-être. Mais c'est ainsi. Les journées n'ont que 24 heures et il faut bien dormir de temps en temps. Si vous êtes inventeur, ne croyez pas qu'un·e expert·e du domaine va consacrer gratuitement des heures ou des jours de son temps à analyser patiemment tout ce que vous racontez. Trépigner du pied en enjoignant les expert·es de se pencher sur vos élucubrations ne produira pas de succès.

Mais, alors, une invention disruptive, surprenante, remettant en cause des certitudes n'a aucune chance de percer ? On ne travaillera que sur des choses déjà connues, sans surprise ? Non, évidemment. Mais on sélectionnera. L'expert·e passera du temps sur les propositions dont ielle estime, à première vue, qu'elles offrent des chances sérieuses de ne pas être une perte d'efforts. Pour celles qui sont très surprenantes, inhabituelles, et qui remettent en cause des certitudes, l'expert·e va d'abord utiliser des « signaux d'alarme ». Ce sont des heuristiques (terme prétentieux pour dire qu'elles ne sont pas parfaites, mais quand même utiles). Si vous êtes inventeur génial et que vous voulez augmenter vos chances d'être écouté, ne déclenchez pas ces signaux d'alarme :

  • Prétentions délirantes (« Ce mode de communication […] est insaisissable, intraçable, anonyme et totalement sécurisé »). Rappelez-vous que les annonces extraordinaires nécessitent des preuves extraordinaires. Plus vous vous vantez, plus vous aurez du mal à convaincre.
  • Applicabilité excessive. Les vraies inventions marchent dans certains cas, résolvent certains problèmes, et pas d'autres. Affirmer que vous allez « stopper les cyberattaques, les demandes de rançons informatiques ou encore les usurpations d'identité » ou « il pourrait aussi s'avérer très utile pour l'armée, puisqu'il s'agit là d'un outil idéal pour transmettre des ordres, des plans » ne contribue pas à votre crédibilité. Au contraire, une preuve de sérieux est quand vous exposez clairement les limites de votre invention (toute technique a des limites).
  • Ignorance complète des bases du domaine dans lequel vous prétendez avoir inventé quelque chose. Cette heuristique est d'un usage délicat car, parfois (« parfois » au sens de « une fois sur un zillion »), quelqu'un d'extérieur au domaine fait une percée, en partie justement car ielle n'était pas du domaine et pouvait donc penser « en dehors de la boite ». Mais c'est beaucoup plus rare que le cas où l'inventeur est simplement ignorant des difficultés du domaine. Un exemple est, en cryptographie, quelqu'un qui ne saurait pas ce qu'est une attaque de l'homme du milieu, ou qui ne comprendrait pas la différence entre cryptographie symétrique et asymétrique (« votre correspondant, une fois le message reçu, passe de la même façon sa carte, qui a la même clé de chiffrement que la vôtre »).
  • Propos vagues. Annoncer des résultats mirobolants sans donner de détails précis va allumer un signal d'alarme. Prétendre que cette absence de détails est due à votre souci d'éviter que les Chinois vous copient n'arrange rien (voir le point suivant).
  • Paranoïa. Un inventeur qui commence par « je suis génial mais le système / les puissants / les GAFA / Framasoft / les polytechniciens / les énarques conspirent pour me faire taire » allume également le plus puissant des signaux d'alarme. (J'en profite pour signaler que se comparer à Galilée n'aide pas. 1) Galilée n'a pas été rejeté par les autres scientifiques mais par les religieux, qui sont toujours opposés à la science 2) pour un Galilée, combien d'escrocs ?)
  • Grands mots. Ajouter « blockchain », « quantique » ou « IA » n'ajoute pas de la crédibilité à votre discours, sauf si vous pouvez expliquer en détail ce que ces techniques apportent à votre œuvre.
  • La forme compte aussi. Bien sûr, un inventeur génial peut avoir une orthographe catastrophique. Mais un texte bacler PLEIN D'AFFIRMATIONS EN MAJUSCULES et de ponctation !!! eksèssive car votre invantion est GÉNIALE !!! ne va pas vous aider. Respirez et prenez le temps de relire. (Au passage, n'avoir comme documentation que des vidéos convient si vous êtes influenceur beauté, pas si vous prétendez être inventeur.)

Tous les inventeurs ne déclenchent pas la totalité de ces signaux d'alarme. Mais ils en allument en général plusieurs. Comme toutes les heuristiques, elles ne sont pas parfaites. On ne connait pas de mécanisme parfait pour déterminer si une invention est géniale ou débile. Et les expert·es, comme tout le monde, peuvent se tromper. Mais, en raison de la finitude de la journée de travail, on doit utilise ces heuristiques, sinon on ne produirait jamais rien.


L'article seul

RFC 9006: TCP Usage Guidance in the Internet of Things (IoT)

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : C. Gomez (UPC), J. Crowcroft (University of Cambridge), M. Scharf (Hochschule Esslingen)
Pour information
Réalisé dans le cadre du groupe de travail IETF lwig
Première rédaction de cet article le 28 mars 2021


À côté de machines disposant de ressources matérielles suffisantes (électricité, processeur, etc), qui peuvent faire tourner des protocoles comme TCP sans ajustements particuliers, il existe des machines dites contraintes, et des réseaux de machines contraintes, notamment dans le cadre de l'Internet des Objets. Ces machines, pauvres en énergie ou en capacités de calcul, doivent, si elles veulent participer à des communications sur l'Internet, adapter leur usage de TCP. Ce RFC documente les façons de faire du TCP « léger ».

Ces CNN (Constrained-Node Networks, réseaux contenant beaucoup d'objets contraints) sont décrits dans le RFC 7228. On parle bien d'objets contraints, soit en processeur, soit en énergie. Un Raspberry Pi ou une télévision connectée ne sont pas des objets contraints, ils peuvent utiliser les systèmes habituels, avec un TCP normal, au contraire des objets contraints, qui nécessitent des technologies adaptées. Le RFC 8352 explique ainsi les problèmes liés à la consommation électrique de certains protocoles. Des protocoles spéciaux ont été développés pour ces objets contraints, comme 6LoWPAN (RFC 4944, RFC 6282 et RFC 6775) ou comme le RPL du RFC 6550 ou, au niveau applicatif, le CoAP du RFC 7252.

Côté transport, on sait que les principaux protocoles de transport actuels sur l'Internet sont UDP et TCP. TCP a été parfois critiqué comme inadapté à l'Internet des Objets. Ces critiques n'étaient pas forcément justifiées mais il est sûr que le fait que TCP ait des en-têtes plutôt longs, pas de multicast et qu'il impose d'accuser réception de toutes les données peut ne pas être optimal pour ces réseaux d'objets contraints. D'autres reproches pouvaient être traités, comme expliqué dans l'article «  TCP in the Internet of Things: from ostracism to prominence ». Notez que CoAP, à l'origine, tournait uniquement sur UDP mais que depuis il existe aussi sur TCP (RFC 8323). Les CNN (Constrained-Node Networks) utilisent parfois d'autres protocoles applicatifs tournant sur TCP comme HTTP/2 (RFC 7540) ou MQTT.

TCP est certes complexe si on veut utiliser toutes les optimisations qui ont été développées au fil du temps. Mais elles ne sont pas nécessaires pour l'interopérabilité. Un TCP minimum peut parfaitement communiquer avec des TCP optimisés, et notre RFC explique comment réduire l'empreinte de TCP, tout en restant évidemment parfaitement compatible avec les TCP existants. (Notez qu'il y avait déjà eu des travaux sur l'adaptation de TCP à certains environnements, voir par exemple le RFC 3481.)

Bon, maintenant, au travail. Quelles sont les propriétés des CNN (RFC 7228) qui posent problème avec TCP (section 2 du RFC) ? Ils manquent d'énergie et il ne peuvent donc pas émettre et recevoir en permanence (RFC 8352), ils manquent de processeur, ce qui limite la complexité des protocoles, et ils utilisent souvent des réseaux physiques qui ont beaucoup de pertes (voire qui corrompent souvent les paquets), pas vraiment les réseaux avec lesquels TCP est le plus à l'aise (RFC 3819).

La communication d'un objet contraint se fait parfois à l'intérieur du CNN, avec un autre objet contraint et parfois avec une machine « normale » sur l'Internet. Les types d'interaction peuvent aller de l'unidirectionnel (un capteur transmet une mesure qu'il a faite), à la requête/réponse en passant par des transferts de fichiers (mise à jour du logiciel de l'objet contraint, par exemple). Voyons maintenant comment TCP peut s'adapter (section 3 du RFC).

D'abord, la MTU. En IPv6, faire des paquets de plus de 1 280 octets, c'est prendre le risque de la fragmentation, qui n'est pas une bonne chose pour des objets contraints en mémoire (RFC 8900), qui n'ont en plus pas très envie de faire de la Path MTU discovery (RFC 8201). Donc, notre RFC conseille d'utiliser la MSS (Maximum Segment Size) de TCP pour limiter la taille des paquets. Attention, les CNN tournent parfois sur des réseaux physiques assez spéciaux, où la MTU est bien inférieure aux 1 280 octets dont IPv6 a besoin (RFC 8200, section 5). Par exemple, IEEE 802.15.4 a une MTU de 127 octets seulement. Dans ce cas, il faut prévoir une couche d'adaptation entre IPv6 et le réseau physique (ce que fait le RFC 4944 pour IEE 802.15.4, le RFC 7668 pour Bluetooth LE, le RFC 8105 pour DECT LE, etc). Heureusement, d'autres technologies de réseau physique utilisées dans le monde des CNN n'ont pas ces limites de MTU, c'est le cas par exemple de Master-Slave/Token-Passing (cf. RFC 8163), IEEE 802.11ah, etc.

Deuxième endroit où on peut optimiser, ECN (RFC 3168). ECN permet aux routeurs intermédiaires de marquer dans un paquet que la congestion est proche ; le destinataire peut alors prévenir l'émetteur de ralentir. Le RFC 8087 décrit les avantages de l'ECN. Permettant de détecter l'approche de la congestion avant qu'on ait perdu un seul paquet (et donc sans qu'on ait à dépenser des watts pour retransmettre), l'ECN est particulièrement intéressant pour les CNN. Le RFC 7567 donne des conseils pratiques pour son déploiement.

Un problème classique de TCP sur les liens radio est que TCP interprète une perte de paquet comme signal de congestion, le poussant à ralentir, alors que cette perte peut en fait être due à la corruption d'un paquet (suite à une perturbation radio-électrique, par exemple). Il serait donc intéressant de pouvoir signaler explicitement ce genre de perte (la question était déjà discutée dans le RFC 2757 mais aussi dans l'article « Explicit Transport Error Notification (ETEN) for Error-Prone Wireless and Satellite Networks »). Pour l'instant, il n'existe aucun mécanisme standard pour cela, ce qui est bien dommage.

Pour faire tourner TCP sur une machine contrainte, une technique parfois utilisée est de n'envoyer qu'un segment à la fois (et donc d'annoncer une fenêtre dont la taille est d'un MSS - Maximum Segment Size). Dans ce cas, pas besoin de mémoriser plus qu'un segment de données envoyé mais dont l'accusé de réception n'a pas encore été reçu. C'est très économique, mais ça se paie cher en performances puisqu'il faut attendre l'accusé de réception de chaque segment avant d'en envoyer un autre. La capacité effective du lien va chuter, d'autant plus que certaines optimisations de TCP comme le fast recovery dépendent d'une fenêtre plus grande qu'un seul segment. Au niveau applicatif, on voit la même technique avec CoAP, qui est par défaut purement requête/réponse.

Si on veut faire du TCP « un seul segment », le code peut être simplifié, ce qui permet de gagner encore en octets, mais notre RFC rappelle quand même que des options comme MSS (évidemment), NoOp et EndOfOptions restent nécessaires. En revanche, on peut réduire le code en ne gérant pas les autres options comme WindowScaling (RFC 7323), Timestamps (RFC 7323) ou SACK (RFC 2018). TCP a le droit d'ignorer ces options, qui, en « un seul segment » sont parfois inutiles (WindowScaling, SACK) et parfois moins importantes (Timestamps). En tout cas, si la machine a assez de mémoire, il est sûr que transmettre plusieurs segments avant d'avoir eu l'accusé de réception du premier, et utiliser des algorithmes comme le fast recovery améliore certainement les performances. Même chose pour les accusés de réception sélectifs, les SACK du RFC 2018.

La détermination du RTO (Retransmission TimeOut) est un des points cruciaux de TCP (RFC 6298). S'il est trop long, on attendra longtemps la retransmission, quand un paquet est perdu, s'il est trop court, on ré-émettra parfois pour rien, gâchant des ressources alors que le paquet était juste en retard. Bref, une mise en œuvre de TCP pour les CNN doit soigner ses algorithmes de choix du RTO (cf. RFC 8961).

Continuons avec des conseils sur TCP dans les réseaux d'objets contraints. Notre RFC rappelle que les accusés de réception retardés, utiles pour accuser réception d'une plus grande quantité de données et ainsi diminuer le nombre de ces accusés, peuvent améliorer les performances… ou pas. Cela dépend du type de trafic. Si, par exemple, le trafic est surtout dans une direction, avec des messages courts (ce sera typiquement le cas avec CoAP), retarder les accusés de réception n'est sans doute pas une bonne idée.

Les paramètres par défaut de TCP sont parfois inadaptés aux CNN. Ainsi, le RFC 5681 recommande une taille de fenêtre initiale d'environ quatre kilo-octets. Le RFC 6298 fait des recommandations qui peuvent aboutir à des tailles de fenêtre initiale encore plus grandes. C'est très bien pour un PC connecté via la fibre mais pas pour la plupart des objets contraints, qui demandent des paramètres adaptés. Bref, il ne faut pas lire le RFC 6298 trop littéralement, car il faut en général une taille de fenêtre initiale plus petite.

Il n'y a pas que TCP lui-même, il y a aussi les applications qui l'utilisent. C'est l'objet de la section 4 du RFC. En général, si un objet contraint communique avec un non-contraint, c'est le premier qui initie la connexion (cela lui permet de dormir, et donc d'économiser l'énergie, s'il n'a rien à dire). L'objet contraint a tout intérêt à minimiser le nombre de connexions TCP, pour économiser la mémoire. Certes, cela crée des problèmes de head-of-line blocking (une opération un peu lente bloque les opérations ultérieures qui passent sur la même connexion TCP) mais cela vaut souvent la peine.

Et combien de temps garder la connexion TCP ouverte ? Tant qu'on a des choses à dire, c'est évident, on continue. Mais lorsqu'on n'a plus rien à dire, l'application doit-elle fermer les connexions, qui consomment de la mémoire, sachant que rouvrir la connexion prendra du temps et des ressources (la triple poignée de mains…). C'est un peu le problème de l'automobiliste arrêté qui se demande s'il doit couper son moteur. S'il faut redémarrer tout de suite, il consommera davantage de carburant. D'un autre côté, s'il laisse son moteur tourner, ce sera également un gaspillage. Le problème est soluble si l'application sait exactement quand elle aura à nouveau besoin d'émettre, ou si l'automobiliste sait exactement combien de temps durera l'arrêt mais, en pratique, on ne le sait pas toujours. (Ceci dit, pour l'automobile, le système d'arrêt-démarrage automatique dispense désormais le conducteur du choix.)

Une autre raison pour laquelle il faut être prudent avec les connexions TCP inactives est le NAT. Si un routeur NAT estime que la connexion est finie, il va retirer de ses tables la correspondance entre l'adresse IP interne et l'externe et, lorsqu'on voudra recommencer à transmettre des paquets, ils seront perdus. Le RFC 5382 donne des durées minimales avant ce retrait (deux heures…) mais elles ne sont pas forcément respectées par les routeurs NAT. Ainsi, l'étude « An Experimental Study of Home Gateway Characteristics » trouve que la moitié des boitiers testés ne respectent pas la recommandation du RFC 5382, avec des délais parfois aussi courts que quelques minutes ! Une des façons d'empêcher ces coupures est d'utiliser le mécanisme keep-alive de TCP (RFC 1122, section 4.2.3.6), qui envoie régulièrement des paquets dont le seul but est d'empêcher le routeur NAT d'oublier la connexion. Une autre est d'avoir des « battements de cœur » réguliers dans les applications, comme le permet CoAP (RFC 8323). Et, si on coupe rapidement les connexions TCP inutilisées, avant qu'une stupide middlebox ne le fasse, comment reprendre rapidement ensuite, si le trafic repart ? TCP Fast open (RFC 7413) est une solution possible.

Enfin, la sécurité pose des problèmes particuliers dans les CNN, où les ressources de certaines machines peuvent être insuffisantes pour certaines solutions de sécurité. Ainsi, pour TCP, la solution d'authentification AO (RFC 5925) augmente la taille des paquets et nécessite des calculs supplémentaires.

Il existe un certain nombre de mises en œuvre de TCP qui visent les objets contraints mentionnés dans ce RFC. Une machine 32 bits alimentée en courant en permanence, comme un vieux Raspberry Pi, n'est pas concernée, elle fait tourner le TCP habituel de Linux. On parle ici de TCP pour objets vraiment contraints. C'est par exemple (annexe A du RFC) le cas de :

  • uIP, qui vise les microcontrôleurs à 8 et 16 bits. Elle est utilisée dans Contiki et sur la carte d'extension Ethernet (shield) pour Arduino. En 5 ko, elle réussit à faire IP (dont IPv6 dans les dernières versions) et TCP. Elle fait partie de celles qui utilisent le « un segment à la fois », ce qui évite les calculs de fenêtres (qui nécessitent des calculs sur 32 bits, qui seraient lents sur ces processeurs). Et c'est à l'application de se souvenir de ce qu'elle a envoyé, TCP ne le fait pas pour elle. L'utiliser est donc difficile pour le programmeur.
  • lwIP, qui vise le même genre de processeurs, mais dont l'empreinte mémoire est supérieure (entre 14 et 22 ko). Il faut dire qu'elle n'est pas limitée à envoyer un segment à la fois et que TCP mémorise les données envoyées, déchargeant l'application de ce travail. Et elle dispose de nombreuses optimisations comme SACK.
  • RIOT a sa propre mise en œuvre de TCP, nommée GNRC TCP. Elle vise aussi les engins de classe 1 (cf. RFC 7228 pour cette terminologie). Elle est de type « un segment à la fois » mais c'est TCP, et pas l'application, qui se charge de mémoriser les données envoyées (et qu'il faudra peut-être retransmettre). Par défaut, une application ne peut avoir qu'une seule connexion et il faut recompiler si on veut changer cela. Par contre, RIOT dispose d'une interface sockets, familière à beaucoup de programmeurs.
  • freeRTOS a aussi un TCP, pouvant envoyer plusieurs segments (mais une option à un seul segment est possible, pour économiser la mémoire). Il a même les accusés de réception retardés.
  • uC/OS peut également faire du TCP avec plusieurs segments en vol.

Un tableau comparatif en annexe A.7 résume les principales propriétés de ces différentes mises en œuvre de TCP sur objets contraints.


Téléchargez le RFC 9006


L'article seul

RFC 8997: Deprecation of TLS 1.1 for Email Submission and Access

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : L. Velvindron (cyberstorm.mu), S. Farrell (Trinity College Dublin)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF uta
Première rédaction de cet article le 24 mars 2021


Dans le cadre général de l'abandon des versions 1.0 et 1.1 du protocole TLS (cf. RFC 8996), ce RFC déclare que ces vieilles versions ne doivent plus être utilisées pour le courrier (mettant ainsi à jour le RFC 8314).

Ce RFC 8314 spécifiait l'usage de TLS pour la soumission et la récupération de courrier. Sa section 4.1 imposait une version minimale de TLS, la 1.1. Cette 1.1 étant officiellement abandonnée pour obsolescence dans le RFC 8996, la version minimale est maintenant la 1.2. C'est tout, ce RFC est simple et court.


Téléchargez le RFC 8997


L'article seul

RFC 8996: Deprecating TLSv1.0 and TLSv1.1

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : K. Moriarty (Dell EMC), S. Farrell (Trinity College Dublin)
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 24 mars 2021
Dernière mise à jour le 25 mars 2021


Ce RFC est très court, car il s'agit juste de formaliser une évidence : les versions 1.0 et 1.1 du protocole de cryptographie TLS ne devraient plus être utilisées, elles souffrent de diverses failles, notamment de sécurité. Les seules versions de TLS à utiliser sont la 1.2 (recommandée depuis 2008 !) et la 1.3 (publiée en 2018). Ainsi, une bibliothèque TLS pourra retirer tout le code correspondant à ces versions abandonnées, ce qui diminuera les risques (moins de code, moins de bogues).

Que reproche-t-on exactement à ces vieux protocoles (section 1 du RFC) ?

  • Ils utilisent des algorithmes de cryptographie dépassés et dangereux, par exemple TLS 1.0 impose de gérer Triple DES, et SHA-1 est utilisé à plusieurs endroits. Un des points les plus problématiques à propos des vieilles versions de TLS est en effet leur dépendance vis-à-vis de cet algorithme de condensation SHA-1. Celui-ci est connu comme vulnérable.
  • Ils ne permettent pas d'utiliser les algorithmes modernes, notamment le chiffrement intègre.
  • Indépendamment des défauts de ces vieux protocoles, le seul fait d'avoir quatre versions à gérer augmente les risques d'erreur, pouvant mener à des attaques par repli.
  • Des développeurs de bibliothèques TLS ont manifesté leur souhait de retirer les vieilles versions de TLS, ce qui implique leur abandon officiel par l'IETF.
  • Pour davantage de détails sur les faiblesses reprochées aux vieilles versions de TLS, regardez le rapport SP800-52r2 du NIST ou bien le RFC 7457. S'il existe bien des contournements connus pour certaines de ces vulnérabilités, il est quand même plus simple et plus sûr d'abandonner ces anciennes versions 1.0 et 1.1.

Désormais, la programmeuse ou le programmeur qui veut faire mincir son code en retirant TLS 1.0 et 1.1 peut, si des utilisateurs contestent, s'appuyer sur cette décision de l'IETF. Désormais, la règle est simple : le client ne doit pas proposer TLS 1.0 et 1.1, et s'il le fait le serveur ne doit pas l'accepter. Cela concerne de nombreux RFC, qui mentionnaient 1.0 et 1.1, et tous n'ont pas encore été mis à jour. Ainsi, le RFC 7562 est toujours d'actualité, simplement la mention qu'il fait de TLS 1.1 est réputée supprimée. De même, le RFC 7525, qui résume les bonnes pratiques d'utilisation de TLS doit désormais se lire en oubliant les quelques endroits où il cite encore TLS 1.1. D'autres RFC avaient déjà été abandonnés, comme par exemple le RFC 5101.

Donc, pour résumer les points pratiques de ce RFC (sections 4 et 5) :

  • N'utilisez pas TLS 1.0. Le client TLS ne doit pas le proposer dans son ClientHello, le serveur TLS ne doit jamais l'accepter.
  • N'utilisez pas TLS 1.1. Le client TLS ne doit pas le proposer dans son ClientHello, le serveur TLS ne doit jamais l'accepter.

Si vous êtes programmeu·r·se, virez le code de TLS 1.0 et 1.1 de vos logiciels. (OpenSSL a prévu de le faire en 2022.) Notez que certains protocoles récents comme Gemini ou DoH (RFC 8484) imposaient déjà TLS 1.2 au minimum.

Comme le note la section 7 du RFC, suivre les recommandations de sécurité exposées ici va affecter l'interopérabilité : on ne pourra plus communiquer avec les vieilles machines. J'ai à la maison une vieille tablette pour laquelle le constructeur ne propose pas de mise à jour logicielle et qui, limitée à TLS 1.0, ne peut d'ores et déjà plus se connecter à beaucoup de sites Web en HTTPS. L'obsolescence programmée en raison de la sécurité… Plus grave, des organisations peuvent être coincées avec une vieille version de TLS sur des équipements, par exemple de contrôle industriel, qu'on ne peut pas mettre à jour. (Lors des discussions à l'IETF sur ce RFC, des personnes avaient suggéré d'attendre que le niveau d'utilisation de TLS 1.0 et 1.1 tombe en dessous d'une certaine valeur, avant d'abandonner officiellement ces protocoles. L'IETF a finalement choisi une approche plus volontariste. Mais pensez aux établissements comme les hôpitaux, avec tous les systèmes contrôlés par des vieux PC pas mettables à jour.) Comme toujours en sécurité, il n'y a pas de solution parfaite, uniquement des compromis. Le site de test TLS https://www.ssllabs.com/ montre ici un site Web d'une banque qui continue à proposer TLS 1.0 et 1.1, ce qui baisse sa note globale mais est peut-être justifié par le désir de ne pas laisser tomber les clients qui ne peuvent pas facilement changer leur logiciel : labanquepostale-tls1.png

Au contraire, voici ce qu'affiche un Firefox récent quand on essaie de se connecter à un vieux site Web qui n'accepte toujours pas TLS 1.2 : cig-old-tls.png

À noter que DTLS 1.0 (RFC 4347) est également abandonné. Cela laisse DTLS 1.2, le 1.1 n'ayant jamais été normalisé, et le 1.3 n'étant pas prêt.

Les RFC 2246 (TLS 1.0) et RFC 4346 (TLS 1.1) ont été officiellement reclassifiés comme n'ayant plus qu'un intérêt historique. Le RFC 7507 est également déclassé, le mécanisme qu'il décrit n'étant utile qu'avec TLS 1.0 et 1.1.


Téléchargez le RFC 8996


L'article seul

RFC 9007: Handling Message Disposition Notification with the JSON Meta Application Protocol (JMAP)

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : R. Ouazana (Linagora)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jmap
Première rédaction de cet article le 23 mars 2021


Les avis de remise d'un message (MDN, Message Disposition Notification) sont normalisés dans le RFC 8098. Ce nouveau RFC normalise la façon de les gérer depuis le protocole d'accès au courrier JMAP (qui est, lui, dans les RFC 8620 et RFC 8621).

Un petit rappel sur JMAP : c'est un protocole générique pour accéder à des données distantes, qu'elles concernent la gestion d'un agenda ou celle du courrier. Il est normalisé dans le RFC 8620. Une extension spécifique, JMAP for Mail, décrit comment l'utiliser pour le cas du courrier (rôle pour lequel JMAP concurrence IMAP).

Quant à MDN (Message Disposition Notifications), c'est un format qui décrit des accusés de réception du courrier. Il a été spécifié dans le RFC 8098. Un MDN est un message structuré (en MIME, avec une partie de type message/disposition-notification) qui indique ce qui est arrivé au message. On peut donc envoyer un MDN en réponse à un message (c'est un accusé de réception, ou avis de remise), on peut demander l'envoi d'un tel MDN lorsqu'on envoie un message, on peut recevoir des MDN et vouloir les analyser, par exemple pour les mettre en rapport avec un message qu'on a envoyé.

Avant de manier les MDN, il faut les modéliser (section 2). Comme tout en JMAP, un MDN est un objet JSON comprenant entre autres les membres :

  • forEmailId : l'identifiant JMAP du message auquel se réfère ce MDN,
  • originalMessageId, le Message ID du message auquel se réfère ce MDN, à ne pas confondre avec l'identifiant JMAP,
  • includeOriginalMessage, qui indique qu'un envoyeur souhaite recevoir le message original dans les éventuels MDN,
  • disposition : voir le RFC 8098, section 3.2.6, pour cette notion. Elle indique ce qui est arrivé au message, et les conditions dans lesquelles l'action d'émission du MDN a été prise, par exemple automatiquement, ou bien par une action explicite de l'utilisateur.

L'objet JSON MDN sert à modéliser les MDN reçus mais aussi les options envoyées, comme la demande de génération de MDN par le receveur.

Pour envoyer un MDN, notre RFC introduit une nouvelle méthode JMAP, MDN/send. Pour analyser un MDN entrant, la méthode se nomme MDN/parse. Voici un exemple de MDN JMAP :

  
[[ "MDN/send", {
...
  "send": {
     ...
     "forEmailId": "Md45b47b4877521042cec0938",
     "subject": "Read receipt for: World domination",
     "textBody": "This receipt shows that the email has been
         displayed on your recipient's computer. There is no
         guaranty it has been read or understood.",
     "reportingUA": "joes-pc.cs.example.com; Foomail 97.1",
     "disposition": {
       "actionMode": "manual-action",
       "sendingMode": "mdn-sent-manually",
       "type": "displayed"
     },
     ...

On y voit l'identifiant du message concerné, et l'action qui a été entreprise : le destinataire a activé manuellement l'envoi du message, après avoir vu ledit message.

Et pour demander l'envoi d'un MDN lorsqu'on crée un message ? C'est la méthode Email/set du RFC 8621 qui permet de créer le message. On doit juste ajouter l'en-tête Disposition-Notification-To: du RFC 8098 :

[[ "Email/set", {
     "accountId": "ue150411c",
     "create": {
        ...
        "header:Disposition-Notification-To:asText": "joe@example.com",
        "subject": "World domination",
...
  

Comme un serveur JMAP annonce ses capacités lors de la connexion (RFC 8620, section 2), notre RFC ajoute une nouvelle capacité, urn:ietf:params:jmap:mdn, ce qui permet à un serveur de dire qu'il sait gérer les MDN. Elle est enregistrée à l'IANA.

Question mise en œuvre de JMAP qui gère les MDN, il y a le serveur Cyrus, voir ce code, et aussi Apache James.

Merci à Raphaël Ouazana pour sa relecture.


Téléchargez le RFC 9007


L'article seul

Fiche de lecture : La fabuleuse histoire de l'invention de l'écriture

Auteur(s) du livre : Silvia Ferrara
Éditeur : Seuil
978-2-02-146412-2
Publié en 2021
Première rédaction de cet article le 22 mars 2021


L'écriture est un sujet passionnant, sur lequel beaucoup a déjà été écrit. Un livre de plus sur cette géniale invention et ses débuts ? Pas tout à fait, ce livre n'est pas un cours, ou un livre de vulgarisation, c'est une suite de réflexions de l'auteure sur la façon dont l'écriture a (peut-être) été inventée et sur le travail de ceux et celles qui essaient de jeter quelques lumières sur ce processus d'invention.

Comme vous le savez, il y a quatre (ou cinq ? ou six ? ou seulement trois ?) inventions indépendantes de l'écriture, en Égypte, en Mésopotamie, en Chine et en Méso-Amérique. Le processus est donc, sinon courant, du moins pas exceptionnel, et rentre donc tout à fait dans les capacités humaines. Mais comment en est-on arrivé là ? Quelles ont été les prémisses ? Typiquement, on part de petits dessins, puis on les abstrait de plus en plus et on finit par avoir une écriture. (Le cas de l'écriture chinoise est plus compliqué car on n'a pas retrouvé les étapes préalables.) L'excellent dessin p. 224 nous donne une idée de comment ça a pu se passer. Le processus étant continu, il est parfois difficile de dire à partir de quand on a affaire à une « vraie » écriture. C'est d'ailleurs un des obstacles qui se posent aux déchiffreurs d'écritures inconnues : cet ensemble d'émojis est-il une vraie écriture ? L'aveuglement des déchiffreurs, leur tendance à s'illusionner, peut les aider ou les freiner (comme dans le cas de l'écriture maya, longtemps tenue, à tort, pour « juste des dessins »).

L'auteure nous fait voyager, au rythme de sa fantaisie, de la Crète (sa spécialité scientifique) à l'île de Pâques en passant par le Mexique. Vous y trouverez les écritures inconnues les plus célèbres (le linéaire A ou l'IVS) et les Mystères Mystérieux comme évidemment le disque de Phaistos. L'auteure suggère d'ailleurs de ne pas passer trop de temps sur ce disque : vu le nombre réduit de caractères, elle estime qu'il n'y a aucune chance qu'on le déchiffre un jour. (Au fait, si vous voulez vous informer sur toutes les écritures connues, je vous recommande « The World's Writing Systems ».)

Mais la partie la plus intéressante concerne l'évolution des écritures, les mécanismes à l'œuvre, les tendances, les « lois » de l'évolution. Si certaines écritures sont très stables (à part à leur origine), d'autres ont changé, ont grandi, parfois ont disparu.

De même que M. Bidouille reçoit régulièrement des messages de gens qui ont découvert le mouvement perpétuel, de même que les chercheurs en réseaux informatiques sont agacés par les personnes qui ont trouvé la FUSSP, la solution au problème du spam, les chercheuses et chercheurs en écritures anciennes ont des lettres annonçant le déchiffrement du chypro-minoen ou celui du manuscrit de Voynich. L'auteure leur donne (p. 251) dix conseils très instructifs si vous voulez mieux comprendre comment s'analysent les écritures. Et le dixième conseil est « ne m'écrivez pas » (la quasi-totalité de ces annonces sont bidon).


L'article seul

Fiche de lecture : How the Internet really works

Auteur(s) du livre : Article 19, Catnip
Éditeur : No Starch Press
978-1-7185-0029-7
Publié en 2021
Première rédaction de cet article le 21 mars 2021


L'Internet, c'est important, toute notre vie et nos activités s'y passent, mais c'est compliqué. Tout le monde ne comprend pas comment ça marche. En fait, même les professionnels de l'informatique ne savent pas forcément. C'est ennuyeux car cette ignorance laisse les acteurs dominants dicter les règles et faire ce qu'ils veulent. Il serait préférable que les citoyen·nes puissent accéder à un minimum de compréhension de fonctionnement du réseau. C'est ce que propose ce livre.

D'abord, un point important : contrairement à la grande majorité des reportages, documentaires, livres, articles prétendant expliquer le fonctionnement de l'Internet, celui-ci est écrit par des gens qui connaissent et savent de quoi ils parlent. (Notez que deux des auteurs, Niels ten Oever et Corinne Cath, sont les auteurs du RFC 8280). Vous n'y trouverez pas d'erreur technique (ou pas beaucoup), d'explication bâclée ou de raccourcis journalistiques, genre « l'ICANN est le régulateur mondial d'Internet ».

Mais être correct ne suffit pas, il faut encore pouvoir expliquer des concepts complexes et un réseau dont le moins qu'on puisse dire est qu'il n'est pas évident à assimiler. Les auteur·es ont beaucoup travaillé l'aspect pédagogique. (Et, oui, il y a des dessins, et c'est un chat qui explique.) Le livre est relativement court, mais complet, et présente bien le sujet. Il sera très utile à tous les gens qui font de l'EMI, de la formation à la littératie numérique et autres activités d'éducation. Le livre couvre IP, TCP, DNS, BGP, HTTP, mais aussi le chiffrement, les points d'échange, l'allocation d'adresses IP, etc.

Je l'ai dit, les auteur·es sont impliqué·es dans les activités politiques de l'Internet (ce qu'on nomme « gouvernance de l'Internet », mais, bon, c'est juste de la politique sous un nouveau nom). Le livre insiste donc sur les aspects qui touchent aux droits humains fondamentaux comme le droit à la vie privée, la lutte contre la censure, et bien sûr les mécanismes de décision dans l'Internet : qui fait les choix ?

Sur cette question du pouvoir, le livre décrit également le fonctionnement d'organismes qui contribuent à façonner l'Internet tel qu'il est (comme l'IETF) et encourage la participation de tous et toutes à ces organismes, pour faire bouger les choses dans le bon sens.


L'article seul

Deux mots sur les NFT

Première rédaction de cet article le 13 mars 2021


Je suis la mode, tout le monde parle des NFT donc je m'y mets aussi. Comment ça marche et ça sert à quoi ?

L'idée de base s'inspire de l'humoriste Alphonse Allais. Un de ses personnages a déposé un brevet pour « enlever au caoutchouc cette élasticité qui le fait impropre à tant d'usages. Au besoin, il le rend fragile comme du verre. ». Les données numériques ont la propriété de pouvoir être copiées à un coût très bas, diffusées largement (grâce à l'Internet) et sans priver le détenteur originel de ces données. Les NFT visent à supprimer cette propriété et à faire des données numériques uniques et non copiables. Pourquoi donc, à part pour rendre hommage à Alphonse Allais ? Parce que cette rareté artificiellement créée permet de mettre en place un marché d'objets uniques, donc chers.

L'idée est que cela permettra des ventes d'objets numériques, ce qui intéresse particulièrement le marché de l'art. Ainsi, il y a deux jours, une vente d'une œuvre d'art (ou plutôt d'un NFT) a rapporté des millions d'euros. Mais l'idée est relativement ancienne, les premiers NFT populaires ayant été les CryptoKitties.

Mais comment peut-on transformer un fichier numérique en un truc unique et non copiable ? Je vous le dis tout de suite, on ne peut pas. C'est en fait le NFT dont on peut « prouver » le propriétaire (et l'unicité), pas l'œuvre d'art elle-même. Descendons un peu dans la technique. Fondamentalement, un NFT (Non-Fungible Token) est un certificat numérique, rassemblant un condensat cryptographique de l'œuvre d'art et une signature par une place de marché. Ce certificat est ensuite placé sur une chaîne de blocs (en général Ethereum) où un contrat automatique permettra de gérer les transactions sur ce certificat, et donc de déterminer de manière fiable le propriétaire. Sur cette idée de base, on peut ajouter diverses améliorations, comme le versement automatique d'un pourcentage des ventes successives au créateur de l'œuvre.

On le voit, le NFT est une idée simple mais qui ne garantit pas grand'chose : si la place de marché est sérieuse, et que le contrat automatique est correct, le NFT garantit uniquement :

  • que la place de marché a certifié l'œuvre d'art,
  • qu'il n'y a à un moment donné, qu'un seul propriétaire (la traçabilité est le point fort des chaînes de blocs).

C'est tout. Les places de marché peuvent générer n'importe quel NFT (il faut leur faire une confiance aveugle), le fichier original peut toujours être copié. Le cours d'un NFT, comme celui de toute monnaie ou bien, dépend uniquement de la valeur qu'on lui accorde. Comme l'argent, le NFT est « une illusion partagée ».

Pour les technicien·ne·s, fabriquons un NFT pour voir. Je prends une image de chat. Elle n'est pas de moi mais cela n'est pas un problème. Calculons un condensat cryptographique avec SHA-256 :

% sha256sum Cat_November_2010-1a.jpg
59ec9bf12a5b63e0913e986b9566b96228c9f8921fda4fb87bf2a7f9acff3dd2  Cat_November_2010-1a.jpg
  

Puis ajoutons quelques métadonnées et signons le tout en OpenPGP (RFC 4880) :

% gpg --sign --armor > Cat_November_2010-1a.asc 
gpg: using "CCC66677" as default secret key for signing
Je soussigné, Stéphane Bortzmeyer, certifie que cette image représente un chat.
https://commons.wikimedia.org/wiki/File:Cat_November_2010-1a.jpg
59ec9bf12a5b63e0913e986b9566b96228c9f8921fda4fb87bf2a7f9acff3dd2  Cat_November_2010-1a.jpg
  

Le fichier Cat_November_2010-1a.asc va alors contenir une signature, vérifiable :


% gpg --decrypt Cat_November_2010-1a.asc 
Je soussigné, Stéphane Bortzmeyer, certifie que cette image représente un chat.
https://commons.wikimedia.org/wiki/File:Cat_November_2010-1a.jpg
59ec9bf12a5b63e0913e986b9566b96228c9f8921fda4fb87bf2a7f9acff3dd2  Cat_November_2010-1a.jpg
gpg: Signature made Sat Mar 13 13:10:27 2021 CET
gpg:                using RSA key C760CAFC6387B0E8886C823B3FA836C996A4A254
gpg: Good signature from "Stéphane Bortzmeyer (Main key) <stephane@bortzmeyer.org>" [unknown]
...

  

En fait, vu la façon dont fonctionnent les signatures OpenPGP, j'aurais pu me passer de l'étape du calcul du condensat. C'était juste pour illustrer le principe des NFT.

Bref, un NFT est un pointeur vers l'œuvre, pas l'œuvre. Contrairement à l'adage bien connu, avec les NFT, quand on montre la lune, il faut regarder le doigt. Et j'emprunte à Framasky une blague de programmeur :

/*  À vendre, pointeur, peu servi */
char *my_nft;
  

Du fait que le NFT n'est qu'un pointeur, il faut penser à stocker l'œuvre originale proprement (avec sauvegardes).

Il reste bien sûr à tout mettre sur une chaîne de blocs, sous le contrôle d'un contrat automatique qui se chargera entre autres des achats successifs. Je n'ai rien publié, pour éviter de payer des frais. (Prudence si vous entendez que les NFT permettront aux artistes de gagner enfin de l'argent. La seule certitude, avec les NFT, c'est que l'artiste va payer pour publier le NFT. Son NFT sera-t-il acheté ? Il n'y a évidemment aucune certitude. Tout le monde n'est pas Grimes ou Jack Dorsey.) Si j'avais publié les métadonnées signées plus haut, cela aurait été un vrai NFT. Je vous en aurais bien montré un vrai, mais la plupart des places de marché, tout en se réclamant bien fort de la « blockchain » ne font pas preuve de transparence et ne donnent pas beaucoup de détails sur, par exemple, l'adresse dans la chaîne où se trouve le NFT.

Notez qu'il n'existe pas de normes sur les NFT, chaque place de marché a la sienne. Tout au plus existe-t-il des normes sur l'interface des NFT (et d'autres jetons), comme ERC-721, qui standardise des opérations communes à tous les NFT, comme ownerOf (renvoie le propriétaire actuel) ou Transfer (vente par le propriétaire).

Il est tout à fait mensonger, comme on le lit souvent, de prétendre que le NFT garantit « l’authenticité ». N'importe qui, pas seulement l'auteur de l'œuvre, peut générer un NFT, et cela s'est déjà produit sans l'autorisation de l'auteur. (Pour celles et ceux qui ne connaissent pas, David Revoy est l'auteur de Pepper & Carrot).

Quelle confiance faire à un NFT ? Pour la première étape, la génération du NFT, il faut faire confiance à la place de marché. Pour la seconde, les opérations de vente et de revente successives, on a les garanties qu'offre la chaine de blocs et le contrat automatique.

Est-ce une escroquerie ? S'il y a des prétentions malhonnêtes (comme l'authenticité de l'œuvre) dans le discours marketing sur les NFT, d'un autre côté, on peut dire que vendre du virtuel n'a rien de mal en soi, cela se fait tout le temps, entre autre dans le marché de l'art, qui est souvent du grand n'importe quoi (mon projet actuel est de laisser un fromage dehors, d'attendre qu'il se couvre de moisissure et de le vendre ensuite comme œuvre d'art). Si des gens achètent, et sont bien informés et conscients de ce qu'ils achètent, pourquoi pas ?

Quelques lectures en plus :


L'article seul

Un exemple de nom de domaine inhabituel (IDN et émojis)

Première rédaction de cet article le 12 mars 2021


C'est vendredi, bientôt le week-end, détendons-nous avec un nom de domaine rigolo, 📪.ws. Oui, vous avez déjà vu des noms de domaines avec des émojis. Mais celui-ci a une particularité.

Un petit retour en arrière s'impose. D'abord, contrairement à une légende répandue, le DNS, le protocole qui résoud les noms de domaine en informations concrètes, ce protocole n'est pas limité à l'ASCII, encore moins au sous-ensemble LDH (Letters-Digits-Hyphen) d'ASCII. On peut mettre n'importe quel octet dans un nom de domaine. Toutefois, le faire peut entrainer des surprises, parce qu'il n'existe pas d'encodage standard (si le DNS était créé aujourd'hui, UTF-8 serait l'encodage standard mais, à l'époque, ce n'était pas aussi clair) et surtout parce qu'il n'y a pas de règles de canonicalisation (depuis, le RFC 5198 fournirait certainement une solution mais, là encore, c'est trop tard). Et, surtout, pas mal d'applications (mais, répétons-le, pas le DNS lui-même) seraient surprises de recevoir des noms qui ne sont pas en ASCII. C'est pour ces raisons (que j'ai détaillées dans un autre article) que, si on veut de l'Unicode dans les noms de domaine (que l'on nommera alors IDN), on doit utiliser la norme décrite dans les RFC 5890 et suivants. Cette norme impose notamment :

Mais il y a les normes techniques (les RFC) et il y a la réalité. Il n'existe pas de police de l'Internet qui ferait régner l'ordre normatif et fusillerait les contrevenants qui violent les normes techniques. Si l'ICANN impose ce respect des normes dans les TLD qu'elle contrôle, ce n'est pas le cas dans les autres TLD. Donc, on voit des TLD (comme .ws) autoriser des noms théoriquement invalides comme i❤️tacos.ws.

Mais revenons à notre 📪.ws. Si nous essayons de résoudre ce nom en adresse IP avec l'outil dig (il faut une version compilée avec la gestion des IDN) :

% dig  A 📪.ws         
dig: 'xn--gu8h.ws.' is not a legal IDNA2008 name (string contains a disallowed character), use +noidnout
  

dig a protesté, et à juste titre, la norme (IDNA2008 : norme IDN in Applications, version 2008, c'est celle du RFC 5890) ne permettant pas les émojis. Comme dig nous le suggère, essayons avec l'option +noidnout qui lui dit de ne pas afficher d'Unicode en sortie :


% dig +noidnout A 📪.ws
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10659
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
...
;; QUESTION SECTION:
;xn--gu8h.ws.		IN A

Cette fois, on a une réponse (status: NOERROR) mais pas de données (ANSWER: 0). C'est parce que dig, comme il l'affiche dans sa répétition de la question, a converti en Punycode, comme dicté par la norme, et qu'il n'y avait pas de données pour le nom en Punycode. Maintenant, débrayons complètement IDN et essayons le nom dans son encodage natif ce qui, sur ma machine, est UTF-8 :


% dig +noidnout +noidnin A 📪.ws
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45985
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 9, ADDITIONAL: 7
...
;; QUESTION SECTION:
;\240\159\147\170.ws.	IN A

;; ANSWER SECTION:
\240\159\147\170.ws.	300 IN A 64.70.19.203
...

  

Cette fois, on a des données (et même deux, car il y a aussi la signature DNSSEC), et on récupère une adresse IP, 64.70.19.203. La question (\240\159\147\170.ws) est le nom en UTF-8, \240\159\147\170.ws étant bien la représentation en UTF-8 du caractère Unicode U+1F4EA, l'émoji « boite aux lettres ».

C'est donc un cas assez rare : un IDN qui a des données pour l'encodage UTF-8 mais rien en Punycode. (J'ai trouvé des noms qui avaient les deux.) À cause de cela, il est très probable que l'URL http://📪.ws/ ne marchera pas dans votre navigateur (qui, sans doute, suit la norme technique fidèlement).

John Shaft m'a mis sur la piste de l'explication de cette étrangeté. Le domaine encodé en UTF-8 n'existe pas, donc les serveurs faisant autorité pour .ws devraient répondre NXDOMAIN (No Such Domain). Mais .ws a un joker dans la zone et répond donc pour tous les noms inexistants avec cette adresse IP, 64.70.19.203.

Merci à Sean Conner pour avoir attiré mon attention sur ce domaine, dans le cadre d'une discussion sur le projet Gemini. Victor Héry m'a appris ensuite que ce nom de domaine faisait partie du projet Mailoji, une pure escroquerie (car les noms vendus aux pigeons ne marcheront que dans un environnement fermé et contrôlé par le vendeur).


L'article seul

RFC 8998: ShangMi (SM) Cipher Suites for TLS 1.3

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : P. Yang (Ant Group)
Pour information
Première rédaction de cet article le 11 mars 2021


La cryptographie est un outil essentiel pour la sécurité sur les réseaux numériques. N'avoir comme algorithmes de cryptographie que des algorithmes développés à l'étranger peut être jugé dangereux pour la sécurité nationale. Des pays comme la Russie et, bien sûr, les États-Unis, recommandent ou imposent des algorithmes « nationaux ». La Chine s'y met, avec les algorithmes de chiffrement ShangMi (« SM »), dont ce RFC décrit l'utilisation dans TLS.

Comme ces algorithmes sont obligatoires en Chine pour certaines applications (comme c'est le cas de l'algorithme russe Magma décrit dans le RFC 8891), il était nécessaire que TLS (RFC 8446) puisse les utiliser, indépendamment de l'opinion des cryptographes « occidentaux » à leur sujet. Ce RFC traite de deux algorithmes de chiffrement symétrique (« SM4 ») avec chiffrement intègre, une courbe elliptique (« curveSM2 «), un algorithme de condensation (« SM3 »), un algorithme de signature (« SM2 ») utilisant curveSM2 et SM3, et un d'échange de clés fondé sur ECDHE sur SM2. (Au passage, saviez-vous qu'il existe une courbe elliptique française officielle ?)

On notera que les Chinois n'ont pas poussé leurs algorithmes qu'à l'IETF, certains sont aussi normalisés à l'ISO (ISO/IEC 14888-3:2018, ISO/IEC 10118-3:2018 et ISO/IEC 18033-3:2010).

Le RFC ne décrit pas les algorithmes eux-mêmes, uniquement comment les utiliser dans le contexte de TLS 1.3 (RFC 8446). Si vous êtes curieux, les normes chinoises sont :

Les deux algorithmes de chiffrement symétrique sont désormais dans le registre IANA sous les noms de TLS_SM4_GCM_SM3 et TLS_SM4_CCM_SM3. L'algorithme de signature, sm2sig_sm3 est dans le registre approprié. La courbe elliptique curveSM2 a été ajoutée à un autre registre.

Je ne connais pas de mise en œuvre de ces algorithmes dans les bibliothèques TLS habituelles. Si vous avez des informations… Mais Wireshark va bientôt savoir les afficher.

Ah, et si vous vous intéressez à l'Internet en Chine, je vous recommande le livre de Simone Pieranni, Red Mirror.


Téléchargez le RFC 8998


L'article seul

RFC 8978: Reaction of Stateless Address Autoconfiguration (SLAAC) to Flash-Renumbering Events

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : F. Gont (SI6 Networks), J. Zorz (6connect), R. Patterson (Sky UK)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 11 mars 2021


Au moment où je commençais à écrire cet article, mon FAI a trouvé drôle de changer le préfixe IPv6 attribué à mon réseau à la maison. Cela a parfaitement illustré le problème que décrit ce RFC : comment réagissent les machines IPv6 qui ont obtenu une adresse dynamique lors d'une rénumérotation brutale et sans avertissement ? En résumé : ça ne se passe pas toujours bien.

Posons le problème. Notre RFC se concentre sur le cas des machines qui ont obtenu une adresse par le système SLAAC (StateLess Address AutoConfiguration), normalisé dans le RFC 4862. Le routeur émet des messages RA (Router Advertisement) qui indiquent quel est le préfixe d'adresses IP utilisé sur le réseau local. Les machines vont alors prendre une adresse dans ce préfixe, tester qu'elle n'est pas déjà utilisée et c'est parti. Le routeur n'a pas besoin de mémoriser quelles adresses sont utilisées, d'où le terme de « sans état ». L'information distribuée par ces RA a une durée de vie, qui peut être de plusieurs jours, voire davantage.

Maintenant, envisageons un changement du préfixe, quelle que soit sa raison. Si ce changement est planifié, le routeur va accepter les deux préfixes, il va annoncer le nouveau mais l'ancien marchera encore, pendant la durée de vie qui était annoncée, et tout le monde sera heureux et communiquera. Mais si le changement de préfixe n'est pas planifié ? Par exemple, si le routeur obtient lui-même le préfixe dynamiquement (par exemple par le DHCP-PD du RFC 8415) puis qu'il redémarre et qu'il n'avait pas noté le préfixe précédent ? Il ne pourra alors pas continuer à router l'ancien préfixe, que les machines du réseau local utiliseront encore pendant un certain temps, à leur grand dam.

C'est ce qui s'est passé le 19 janvier 2021 (et les jours suivants), lorsque Free a subitement renuméroté les préfixes IPv6 d'un bon nombre de clients. Free n'utilise pas DHCP-PD, je suppose que les Freebox étaient configurées par un autre procédé, en tout cas, les utilisateurs n'ont pas été prévenus. Sur le réseau local, les machines avaient acquis les deux préfixes, l'ancien, conservé en mémoire, et le nouveau. Et l'ancien préfixe ne marchait plus (n'était pas routé), entrainant plein de problèmes. (Notons que l'adresse IPv4 avait également été changée mais ce n'est pas le sujet ici.) Il a fallu redémarrer toutes les machines, pour qu'elles oublient l'ancien préfixe. Une illustration parfaite du problème qui a motivé ce RFC : SLAAC avait été prévu pour des préfixes qui changent rarement et de manière planifiée (avec réduction préalable de la durée de vie, pour que la transition soit rapide). Les surprises, qu'elles soient dues à un problème technique ou simplement au manque de planification, ne sont pas prises en compte.

À part le mode Yolo de Free, dans quelles conditions aura-t-on de ces renumérotages brutaux, ces flash-renumbering events ? Un exemple est celui où le RA qui doit annoncer la fin de l'ancien préfixe (avec une durée de vie nulle) s'est perdu (le multicast n'est pas toujours fiable). Mais, de toute façon, envoyer ce RA d'avertissement suppose de savoir qu'un nouveau préfixe a remplacé l'ancien. Or, cette information n'est pas toujours disponible. Un exemple est celui où il n'y a même pas de RA d'avertissement, car le CPE obtient son préfixe IPv6 par DHCP-PD (Prefix Delegation, RFC 8415, section 6.3), avant de le redistribuer sur le réseau local en SLAAC. Si ce CPE redémarre, et n'a pas de mémoire permanente, il va peut-être obtenir un autre préfixe via DHCP-PD, ce qui fera un flash-renumbering event sur le réseau local. (Il peut aussi y avoir désynchronisation entre la durée de vie des RA faits via SLAAC et la durée du bail DHCP. En théorie, c'est interdit, mais certains CPE où les deux protocoles sont gérés par des modules logiciels différents font cette erreur.)

La Freebox n'utilise apparemment pas DHCP-PD mais le même problème d'ignorance du préfixe précédent peut survenir si la mise à jour des box est faite par un autre moyen de synchronisation. Bref, des tas de choses peuvent aller mal, particulièrement si l'opérateur réseau est négligent (ce qui a été le cas de Free) mais même parfois s'il essaie de bien faire. À partir de là, si certaines machines du réseau local continuent à utiliser l'ancien préfixe, leurs paquets seront probablement jetés par le routeur et aucune communication ne sera possible.

Le RFC 4861 suggère, dans sa section 6.2.1, pour les durées de validité des préfixes annoncés, des valeurs très élevées (une semaine pour la durée préférée et un mois pour la durée maximale). En cas de renumérotation brutale, c'est beaucoup trop (voir aussi la section 2.2), une machine pourrait rester déconnectée pendant une semaine, voire davantage. Divers trucs permettent d'améliorer un peu les choses, mais avec d'autres inconvénients. Il n'y a pas de méthode propre pour nettoyer les machines du réseau local de la mauvaise information. Bien sûr, le mieux serait qu'il n'y ait pas de renumérotation brutale mais ne nous faisons pas d'illusions : cela arrivera et il faut des solutions pour réparer.

La section 2 du RFC analyse en détail certains aspects du problème. Ainsi, est-ce qu'on ne pourrait pas tout simplement attribuer des préfixes IP fixes aux clients ? Cela simplifierait certainement beaucoup de choses. Mais une étude récente indique qu'un tiers des FAI britanniques utilisent des préfixes dynamiques pour IPv6. C'est certainement pénible pour les clients qui veulent, par exemple, héberger un serveur. Mais c'est un état des choses qu'il va falloir traiter. Même si ces FAI changeaient leurs pratiques, des problèmes subsisteraient, par exemple avec des routeurs à la maison qui sous-alloueraient des préfixes plus spécifiques à une partie de la maison et le feraient de façon dynamique. D'autant plus que l'idéal serait que les clients aient le choix, les adresses fixes pouvant (RFC 7721) poser des problèmes de vie privée (le RFC 4941 ne fait varier que la partie de l'adresse IP spécifique à la machine). Ainsi, la DPA allemande suggère de ne pas les utiliser.

Le fond du problème est évidemment que le routeur qui émet des RA n'a aucun moyen de supprimer les préfixes anciens s'il ne les connait pas. S'ils les connaissait, cela serait trivial, en les annonçant avec une durée de vie de zéro mais attention, lisez plus loin. Dans les cas de redémarrage d'un routeur qui n'a pas de mémoire permanente, ce qui est oublié est oublié et le routeur ne peut pas dire « ce préfixe n'existe plus ». Mais même si le routeur connait les anciens préfixes, il y a un piège avec le point e) de la section 5.5.3 du RFC 4862 : on ne peut pas réduire la durée de vie en dessous de deux heures. C'est déjà mieux qu'une semaine mais c'est encore trop long. Autre piège, même une fois qu'un préfixe n'est plus utilisé pour de nouvelles communications, il peut encore servir pour répondre aux anciennes, donc est encore considéré comme valide pour ce réseau, ce qui fait qu'il n'est pas possible de communiquer avec le nouveau titulaire de ce préfixe (s'il y en a un).Par exemple ce patch Linux viole le RFC 4862 pour permettre une meilleure robustesse en cas de renumérotation.

Autre sujet sur lequel il faudrait peut-être améliorer les protocoles, l'interaction entre DHCP et SLAAC, qui reste peu spécifiée. Au minimum, le logiciel dans le routeur qui reçoit les préfixes par DHCP-PD devrait transmettre au logiciel qui envoie les RA quelles sont les durées de vie à utiliser pour qu'elles soient cohérentes avec la durée du bail DHCP.

Bon, et qu'est-ce qu'on peut faire aujourd'hui pour atténuer les conséquences du problème ? Comme dit plus haut, on pourrait n'utiliser que des préfixes fixes, mais cela ne semble pas réaliste. On pourrait surtout changer les paramètres SLAAC pour des valeurs plus réalistes, en mettant 45 minutes comme durée de vie préférée et 90 minutes comme durée maximale de validité. De telles valeurs conviendraient mieux à la grande majorité des réseaux que les valeurs du RFC 4861. En l'absence de mécanisme pour invalider rapidement les anciens préfixes, de courtes durées de vie sont préférables. Dans certains cas (si on est sûrs qu'il n'y aura pas de rénumérotation brutale et/ou si des machines sont longtemps déconnectées du réseau), des valeurs plus longues peuvent être préférables.

Dans le futur, des travaux sur les CPE (cf. RFC 7084) pourront améliorer les choses .


Téléchargez le RFC 8978


L'article seul

RFC 8981: Temporary Address Extensions for Stateless Address Autoconfiguration in IPv6

Date de publication du RFC : Février 2021
Auteur(s) du RFC : F. Gont (SI6 Networks), S. Krishnan (Kaloom), T. Narten, R. Draves (Microsoft Research)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 1 mars 2021


Une des particularités d'IPv6 est de disposer d'un mécanisme, l'autoconfiguration sans état qui permet à une machine de se fabriquer une adresse IP globale sans serveur DHCP. Autrefois, ce mécanisme créait souvent l'adresse IP à partir de l'adresse MAC de la machine et une même machine avait donc toujours le même identifiant (IID, Interface IDentifier, les 64 bits les plus à droite de l'adresse IPv6), même si elle changeait de réseau et donc de préfixe. Il était donc possible de « suivre à la trace » une machine, ce qui pouvait poser des problèmes de protection de la vie privée. Notre RFC, qui remplace le RFC 4941 fournit une solution, sous forme d'un mécanisme de création d'adresses temporaires, partiellement aléatoires (ou en tout cas imprévisibles). Les changements sont assez importants depuis le RFC 4941, qui traitait un peu les adresses IPv6 temporaires comme des citoyennes de deuxième classe. Désormais, elles sont au contraire le choix préféré.

L'autoconfiguration sans état (SLAAC, pour Stateless Address Autoconfiguration), normalisée dans le RFC 4862, est souvent présentée comme un des gros avantages d'IPv6. Sans nécessiter de serveur central (contrairement à DHCP), ce mécanisme permet à chaque machine d'obtenir une adresse globale (IPv4, via le protocole du RFC 3927, ne permet que des adresses purement locales) et unique. Cela se fait en concaténant un préfixe (par exemple 2001:db8:32:aa12::), annoncé par le routeur, à un identifiant d'interface (par exemple 213:e8ff:fe69:590d, l'identifiant de mon PC portable - les machines individuelles, non partagées, comme les ordiphones sont particulièrement sensibles puisque la connaissance de la machine implique celle de son maître), typiquement dérivé de l'adresse MAC.

Partir de l'adresse MAC présente des avantages (quasiment toute machine en a une, et, comme elle est relativement unique, l'unicité de l'adresse IPv6 est obtenue facilement) mais aussi un inconvénient : comme l'identifiant d'interface est toujours le même, cela permet de reconnaître une machine, même lorsqu'elle change de réseau. Dès qu'on voit une machine XXXX:213:e8ff:fe69:590d (où XXXX est le préfixe), on sait que c'est mon PC. Un tiers qui écoute le réseau peut ainsi suivre « à la trace » une machine, et c'est pareil pour les machines avec lesquelles on correspond sur l'Internet. Or, on ne peut pas cacher son adresse IP, il faut l'exposer pour communiquer. Le RFC 7721 analyse le problème plus en détail (voir aussi le RFC 7707).

Les sections 1.2 et 2 de notre RFC décrivent la question à résoudre. Elles notent entre autre que le problème n'est pas aussi crucial que l'avaient prétendu certains. En effet, il existe bien d'autres façons, parfois plus faciles, de suivre une machine à la trace, par exemple par les fameux petits gâteaux de HTTP (RFC 6265) mais aussi par des moyens de plus haute technologie comme les métadonnées de la communication (taille des paquets, écart entre les paquets) ou les caractéristiques matérielles de l'ordinateur, que l'on peut observer sur le réseau. Parmi les autres méthodes, notons aussi que si on utilise les adresses temporaires de notre RFC 8981 mais qu'on configure sa machine pour mettre dynamiquement à jour un serveur DNS avec cette adresse, le nom de domaine suffirait alors à suivre l'utilisateur à la trace !

La section 2.2 commence à discuter des solutions possibles. DHCPv6 (RFC 3315, notamment la section 12) serait évidemment une solution, mais qui nécessite l'administration d'un serveur. L'idéal serait une solution qui permette, puisque IPv6 facilite l'existence de plusieurs adresses IP par machine, d'avoir une adresse stable pour les connexions entrantes et une adresse temporaire, non liée à l'adresse MAC, pour les connexions sortantes, celles qui « trahissent » la machine. C'est ce que propose notre RFC, en générant les adresses temporaires selon un mécanisme pseudo-aléatoire (ou en tout cas imprévisible à un observateur extérieur).

Enfin, la section 3 décrit le mécanisme de protection lui-même. Deux algorithmes sont proposés mais il faut bien noter qu'une machine est toujours libre d'en ajouter un autre, le mécanisme est unilatéral et ne nécessite pas que les machines avec qui on correspond le comprennent. Il suffit que l'algorithme respecte ces principes :

  • Les adresses IP temporaires sont utilisées pour les connexions sortantes (pour les entrantes, on a besoin d'un identificateur stable, un serveur n'a pas de vie privée),
  • Elles sont… temporaires (typiquement quelques heures),
  • Cette durée de vie limitée suit les durées de vie indiquées par SLAAC, et, en prime, on renouvelle les IID (identifiants d'interface) tout de suite lorsque la machine change de réseau, pour éviter toute corrélation,
  • L'identifiant d'interface est bien sûr différent pour chaque interface, pour éviter qu'un observateur ne puisse détecter que l'adresse IP utilisée en 4G et celle utilisée en WiFi désignent la même machine,
  • Ces adresses temporaires ne doivent pas avoir de sémantique visible (cf. RFC 7136) et ne pas être prévisibles par un observateur.

Le premier algorithme est détaillé dans la section 3.3.1 et nécessite l'usage d'une source aléatoire, selon le RFC 4086. On génère un identifiant d'interface avec cette source (attention, certains bits sont réservés, cf. RFC 7136), on vérifie qu'il ne fait pas partie des identifiants réservés du RFC 5453, puis on la préfixe avec le préfixe du réseau.

Second algorithme possible, en section 3.3.2, une génération à partir de l'algorithme du RFC 7217, ce qui permet d'utiliser le même algorithme pour ces deux catégories d'adresses, qui concernent des cas d'usage différents. Le principe est de passer les informations utilisées pour les adresses stables du RFC 7217 (dont un secret, pour éviter qu'un observateur ne puisse déterminer si deux adresses IP appartiennent à la même machine), en y ajoutant le temps (pour éviter la stabilité), à travers une PRF comme SHA-256. Plus besoin de générateur aléatoire dans ce cas.

Une fois l'adresse temporaire générée (les détails sont dans la section 3.4), et testée (DAD), il faut la renouveler de temps en temps (sections 3.5 et 3.6, cette dernière expliquant pourquoi renouveler une fois par jour est plus que suffisant). L'ancienne adresse peut rester active pour les connexions en cours mais plus pour de nouvelles connexions.

Notez que le RFC impose de fournir un moyen pour activer ou débrayer ces adresses temporaires, et que cela soit par préfixe IP, par exemple pour débrayer les adresses temporaires pour les adresses locales du RFC 4193.

Maintenant que l'algorithme est spécifié, la section 4 du RFC reprend de la hauteur et examine les conséquences de l'utilisation des adresses temporaires. C'est l'occasion de rappeler un principe de base de la sécurité : il n'y a pas de solution idéale, seulement des compromis. Si les adresses temporaires protègent davantage contre le « flicage », elles ont aussi des inconvénients comme de rendre le déboguage des réseaux plus difficile. Par exemple, si on note un comportement bizarre associé à certaines adresses IP, il sera plus difficile de savoir s'il s'agit d'une seule machine ou de plusieurs. (Le RFC 7217 vise justement à traiter ce cas.)

Et puis les adresses temporaires de notre RFC ne concernent que l'identifiant d'interface, le préfixe IP reste, et il peut être révélateur, surtout s'il y a peu de machines dans le réseau. Si on veut vraiment éviter le traçage par adresse IP, il faut utiliser Tor ou une technique équivalente (cf. section 9).

L'utilisation des adresses temporaires peut également poser des problèmes avec certaines pratiques prétendument de sécurité comme le fait, pour un serveur, de refuser les connexions depuis une machine sans enregistrement DNS inverse (un nom correspondant à l'adresse, via un enregistrement PTR). Cette technique est assez ridicule mais néanmoins largement utilisée.

Un autre conflit se produira, note la section 8, si des mécanismes de validation des adresses IP source sont en place dans le réseau. Il peut en effet être difficile de distinguer une machine qui génère des adresses IP temporaires pour se protéger contre les indiscrets d'une machine qui se fabrique de fausses adresses IP source pour mener une attaque.

Quelles sont les différences entre le précédent RFC et celui-ci ? La section 5 du RFC résume les importants changements qu'il y a eu depuis le RFC 4941. Notamment :

  • Abandon de MD5 (cf. RFC 6151),
  • Autorisation de n'avoir que des adresses temporaires (le RFC 4941 imposait qu'une adresse stable reste présente),
  • Autoriser les adresses temporaires à être utilisées par défaut, ce qui était déjà le cas en pratique sur la plupart des systèmes d'exploitation (depuis l'époque du RFC 4941, la gravité de la surveillance de masse est mieux perçue),
  • Réduction de la durée de vie recommandée, et recommandation qu'elle soit partiellement choisie au hasard, pour éviter que toutes les adresses soient refaites en même temps,
  • Un algorithme de génération des identifiants d'interface, reposant sur une mémoire stable de la machine, a été supprimé,
  • Un autre a été ajouté, se fondant sur le RFC 7217,
  • Intégration des analyses plus détaillées qui ont été faites de la sécurité d'IPv6 (RFC 7707, RFC 7721 et RFC 7217),
  • Correction des bogues.

Passons maintenant aux mises en œuvre. L'ancienne norme, le RFC 4941, est appliqué par presque tous les systèmes d'exploitation, souvent de manière plus protectrice de la vie privée, par exemple en étant activé par défaut. Les particularités de notre nouveau RFC ne sont pas toujours d'ores et déjà présentes. Ainsi, il existe des patches pour FreeBSD et pour Linux mais pas forcément intégrés aux versions officielles. Sur Linux, le paramètre sysctl qui contrôle ce protocole est net.ipv6.conf.XXX.use_tempaddr où XXX est le nom de l'interface réseau, par exemple eth0. En mettant dans le fichier /etc/sysctl.conf :

# Adresses temporaires du RFC 8981
net.ipv6.conf.default.use_tempaddr = 2

On met en service les adresses temporaires, non « pistables » pour toutes les interfaces (c'est le sens de la valeur default). Pour s'assurer que les réglages soient bien pris en compte, il vaut mieux faire en sorte que le module ipv6 soit chargé tout de suite (sur Debian, le mettre dans /etc/modules) et que les interfaces fixes aient leur propre réglage. Par exemple, sur Debian, on peut mettre dans /etc/network/interfaces :

iface eth2 inet dhcp
   pre-up sysctl -w net.ipv6.conf.eth2.use_tempaddr=2

Ou alors il faut nommer explicitement ses interfaces :

net.ipv6.conf.eth0.use_tempaddr = 2

Notez aussi qu'ifconfig n'affiche pas quelles adresses sont les temporaires (mais ip addr show le fait).

Notons que l'adresse « pistable » est toujours présente mais vient s'y ajouter une adresse temporaire choisie au hasard. Selon les règles du RFC 6724, rappelées dans la section 3.1 de notre RFC, c'est cette adresse temporaire qui sera choisie, en théorie, pour les connexions sortantes (voir aussi le RFC 5014 pour une API permettant de contrôler ce choix). Avec Linux, il faut pour cela que use_tempaddr vale plus que un (sinon, l'adresse temporaire est bien configurée mais pas utilisée par défaut). ifconfig affichera donc :

wlan0     Link encap:Ethernet  HWaddr 00:13:e8:69:59:0d  
...
          inet6 addr: 2001:db8:32:aa12:615a:c7ba:73fb:e2b7/64 Scope:Global
          inet6 addr: 2001:db8:32:aa12:213:e8ff:fe69:590d/64 Scope:Global

puis, au démarrage suivant, l'adresse temporaire (la première ci-dessus) changera :

wlan0     Link encap:Ethernet  HWaddr 00:13:e8:69:59:0d
...
          inet6 addr: 2001:db8:32:aa12:48a9:bf44:5167:463e/64 Scope:Global
          inet6 addr: 2001:db8:32:aa12:213:e8ff:fe69:590d/64 Scope:Global

Sur NetBSD, il n'y a qu'une seule variable syscvtl pour toutes les interfaces. Il suffit donc de mettre dans /etc/sysctl.conf :

net.inet6.ip6.use_tempaddr=1

Pour que l'adresse temporaire soit utilisée par défaut, c'est net.inet6.ip6.prefer_tempaddr. Sur FreeBSD, je n'ai pas essayé, mais je suppose que les variables sysctl au nom bien parlant net.inet6.ip6.use_tempaddr et net.inet6.ip6.prefer_tempaddr sont là pour cela.


Téléchargez le RFC 8981


L'article seul

RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP

Date de publication du RFC : Février 2021
Auteur(s) du RFC : Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 23 février 2021


Ce RFC normalise un nouvel algorithme pour la détection de paquets perdus dans TCP. Dans des cas comme celui où l'application n'a rien à envoyer (fin des données, ou attente d'une requête), RACK-TLP détecte les pertes plus rapidement, en utilisant des mesures fines du RTT, et en sollicitant des accusés de réception dans de nouveaux cas.

Pour comprendre cet algorithme et son intérêt, il faut revoir à quoi sert un protocole de transport comme TCP. Les données sont transmises sous forme de paquets (au format IP, dans le cas de l'Internet), paquets qui peuvent être perdus en route, par exemple si les files d'attente d'un routeur sont pleines. Le premier travail d'un protocole de transport est de réémettre les paquets perdus, de façon à ce que les applications reçoivent bien toutes les données (et dans l'ordre car, en prime, les paquets peuvent arriver dans le désordre, ce qu'on nomme un réordonnancement, qui peut être provoqué, par exemple, lorsque deux chemins sont utilisés pour les paquets). Un protocole de transport a donc besoin de détecter les pertes. Ce n'est pas si évident que cela. La méthode « on note quand on a émis un paquet et, si on n'a pas reçu d'accusé de réception au bout de N millisecondes, on le réémet » fonctionne, mais elle serait très inefficace. Notamment, le choix de N est difficile : trop court, et on déclarerait à tort des paquets comme perdus, réémettant pour rien, trop long et et ne détecterait la perte que trop tard, diminuant la capacité effective.

Le RFC original sur TCP, le RFC 793, expliquait déjà que N devait être calculé dynamiquement, en tenant compte du RTT attendu. En effet, si l'accusé de réception n'est pas arrivé au bout d'une durée égale au RTT, attendre davantage ne sert à rien. (Bien sûr, c'est plus compliqué que cela : le RTT peut être difficile à mesurer lorsque des paquets sont perdus, il varie dans le temps, puisque le réseau a pu changer, et il peut y avoir des temps de traitement qui s'ajoutent au RTT, il faut donc garder un peu de marge.) Armé de cette mesure dynamique du RTT, TCP peut calculer un RTO (Retransmission TimeOut, RFC 793, section 3.7) qui donne le temps d'attente. Le concept de RTO a été ensuite détaillé dans le RFC 6298 qui imposait un minimum d'une seconde (ce qui est beaucoup, par exemple à l'intérieur d'un même centre de données).

Mais d'autres difficultés surgissent ensuite. Par exemple, les accusés de réception de TCP indiquent le dernier octet reçu. Si on envoie trois paquets (plus rigoureusement trois segments, le terme utilisé par TCP) de cent octets, et qu'on reçoit un accusé de réception pour le centième octet indique que le premier paquet est arrivé mais ne dit rien du troisième. Peut-être est-il arrivé et que le second est perdu. Dans ce cas, la réémission du troisième paquet serait du gaspillage. Les accusés de réception cumulatifs de TCP ne permettent pas au récepteur de dire qu'il a reçu les premier et troisième paquets. Les SACK (Selective Acknowledgments) du RFC 2018 ont résolu ce problème. Dans l'exemple ci-dessus, SACK aurait permis au récepteur de dire « j'ai reçu les octets 0 - 100 et 200 - 300 [le second nombre de chaque bloc indique l'octet suivant le bloc] ».

Ensuite, on peut optimiser l'opération en n'attendant pas le RTO, dont on a vu qu'il était souvent trop long. L'idée de base est que, si le récepteur reçoit des données qui ne sont pas dans l'ordre attendu (le troisième paquet, alors qu'on n'a toujours pas vu le second), on renvoie un accusé de réception pour les données déjà reçues et déjà confirmées. Lorsque l'émetteur reçoit un accusé de réception qu'il a déjà vu (en fait, plusieurs), il comprend que des données manquent et il peut réémettre tout de suite, même si le RTO n'est pas écoulé. Ce mécanisme d'accusés de réception dupliqués (DUPACK, pour DUPlicate ACKnowledgment) a été décrit dans le RFC 5681, puis le RFC 6675. Une de ses faiblesses, que corrige notre RFC, est qu'il ne peut pas être utilisé à la fin d'une transmission, puisqu'il n'y a plus de données qui arrivent, empêchant le récepteur de détecter les pertes ou réordonnancements, et obligeant à attendre le RTO.

Et enfin, il faut se rappeler que le protocole de transport a une autre importante responsabilité : s'il doit s'assurer que toutes les données arrivent, et donc réémettre les paquets manquants, il doit aussi le faire en évitant la congestion (RFC 5681). Si des paquets se perdent, c'est peut-être que le réseau est saturé et réémettre trop brutalement pourrait encore aggraver la situation. Ceci dit, l'algorithme RACK-TLP décrit dans notre RFC ne traite que de la détection de pertes, les méthodes précédentes pour le contrôle de congestion restent valables. (C'est une des nouveautés de RACK-TLP : il sépare la détection de pertes du contrôle de congestion, pour lequel il existe plusieurs algorithmes comme le NewReno du RFC 6582 ou le CUBIC du RFC 8312. Ce découplage permet de faire évoluer séparement les algorithmes, et rend donc le système plus souple.)

Voici, désolé pour cette introduction un peu longue, on peut maintenant passer au sujet principal de ce RFC, RACK-TLP. Cet algorithme, ou plutôt ces deux algorithmes, vont être plus efficaces (détecter les pertes plus vite) que DUPACK, notamment à la fin d'une transmission, ou lorsqu'il y a des pertes des paquets retransmis, ou encore des réordonnancements fréquents des paquets (section 2.2 de notre RFC). RACK (Recent ACKnowledgment) va utiliser le RTT des accusés de réception pour détecter certaines pertes, alors que TLP (Tail Loss Probe) va émettre des paquets de données pour provoquer l'envoi d'accusés de réception par le récepteur.

La section 3 du RFC donne une vision générale des deux algorithmes. Commençons par RACK (Recent ACKnowledgment). Son but va être de détecter plus rapidement les pertes lorsque un paquet arrive au récepteur dans le désordre (paquet des octets 200 à 300 alors que le précédent était de 0 à 100, par exemple). Il va utiliser SACK (RFC 2018) pour cela, et RACK dépend donc du bon fonctionnement de SACK (section 4) et en outre, au lieu de ne regarder que les numéros de séquence contenus dans les ACK, comme le faisait DUPACK, il va également regarder le temps écoulé depuis l'émission d'un paquet. Les détails figurent en section 6 du RFC.

Quant à TLP (Tail Loss Probe), son rôle est de titiller le récepteur pour que celui-ci émette des accusés de récéption, même s'il n'en voyait pas la nécessité. Par exemple, si on arrive à la fin d'une session, l'émetteur a fini d'envoyer ses paquets, mais pas encore reçu les accusés de réception. Aucun envoi ne déclenchera donc DUPACK. Le principe de TLP est donc de solliciter un accusé de réception pour voir si on obtient un duplicata. RACK pourra alors utiliser cet accusé dupliqué. (Les deux algorithmes sont forcément utilisés ensemble, on n'utilise pas TLP sans RACK.) Les détails de TLP sont dans la section 7.

La résolution doit être meilleure qu'un quart du RTT. À l'intérieur d'un centre de données, cela implique de pouvoir compter les microsecondes, et, sur l'Internet public, les millisecondes.

La section 9 du RFC discute des avantages et inconvénients de RACK-TLP. Le gros avantage est que tout segment de données envoyé, même si c'est une retransmission, peut permettre de détecter des pertes. C'est surtout intéressant lorsqu'on est à la fin des données (et il n'y a donc plus rien à transmettre) ou lorsque des retransmissions sont perdues. Outre le cas de la fin du flot de données, les propriétés de RACK-TLP sont également utiles lorsque l'application garde la connexion ouverte mais n'a temporairement rien à transmettre (cas de sessions interactives, ou de protocoles requête/réponse comme EPP, où il ne se passe pas forcément quelque chose en permanence).

Mais comme la perfection n'existe pas en ce bas monde, RACK-TLP a aussi des inconvénients. Le principal est qu'il oblige à garder davantage d'état puisqu'il faut mémoriser l'heure de départ de chaque segment (contrairement à ce que proposait le RFC 6675), et avec une bonne résolution (un quart du RTT, demande le RFC). Une telle résolution n'est pas facile à obtenir dans un centre de données où les RTT sont très inférieurs à la milliseconde. Ceci dit, certaines mises en œuvre de TCP font déjà cela, même si, en théorie, elles pourraient se contenter de moins.

RACK-TLP coexiste avec d'autres algorithmes de détection de pertes, comme le classique RTO (RFC 6298) mais aussi avec ceux des RFC 7765, RFC 5682 et RFC 3522. De même, il coexiste avec divers algorithmes de contrôle de la congestion (RFC 5681, RFC 6937) puisqu'il se contente de détecter les pertes, il ne décide pas de comment on évite la congestion. En gros, RACK-TLP dit « ce segment est perdu » et la décision de réémission de celui-ci passera par l'algorithme de contrôle de la congestion, qui verra quand envoyer ces données à nouveau.

RACK-TLP est explicitement conçu pour TCP, mais il pourra aussi être utilisé dans le futur avec d'autres protocoles de transport, comme le futur QUIC.

RACK-TLP ne date pas d'aujourd'hui et il est déjà mis en œuvre dans Linux, FreeBSD et dans des systèmes d'exploitation moins connus comme Windows.


Téléchargez le RFC 8985


L'article seul

Fiche de lecture : Red Mirror

Auteur(s) du livre : Simone Pieranni
Éditeur : C&F Éditions
978-2-37662-021-1
Publié en 2021
Première rédaction de cet article le 23 février 2021


Autrefois, quand on voulait voir le futur, il fallait regarder ce qui se passe aux États-Unis, en se disant que cela allait arriver chez nous quelques années plus tard (que cela soit une bonne ou une mauvaise chose…) Aujourd'hui, faut-il plutôt regarder vers la Chine ? Ce livre explore l'état du numérique en Chine, et ce qu'il peut nous promettre comme futur plus ou moins positif.

Il est loin, le temps où la Chine était un pays pauvre où tout le monde passait son temps à cultiver du riz, en étant toujours au bord de la famine. Même le temps où la Chine était uniquement un atelier géant de construction de jouets en plastique parait bien éloigné. Aujourd'hui, la Chine est en avance sur bien des sujets, touchant notamment au numérique. Le film de propagande « La Bataille de la Montagne du Tigre » commence d'ailleurs, avant de raconter une bataille du passé, par montrer une Chine moderne, pleine de trains à grande vitesse et de gadgets électroniques. Est-ce que cette « avance » de la Chine est une bonne chose ? Plus « perfectionné » et plus « avancé » ne veut pas forcément dire « meilleur ». La Chine a souvent été citée pour le caractère dystopique de son utilisation du numérique, où les libertés individuelles et la protection des données personnelles n'existent pas. Le numérique y est souvent utilisé pour opprimer et pas pour libérer, d'où le titre de ce livre, jeu avec le titre d'une série télévisée connue.

Alors, la Chine est-elle le paradis du numérique comme le présentent certains techno-béats ou bien un enfer dystopique ? L'intérêt du livre de Simone Pieranni, expert de la Chine, est d'étudier la question plus en profondeur. Car la Chine est aussi un grand réservoir à fantasmes en Occident et fait l'objet de nombreux discours contradictoires et parfois peu informés. Il faut donc aller y voir de plus près. (« C'est comment, la Chine ? » « C'est comme vivre en Grande-Bretagne pendant la révolution industrielle. », commente l'auteur.)

Car le paysage est contrasté. Oui, les libertés individuelles et la protection des données personnelles sont complètement absentes. L'accès à l'Internet est largement censuré et très surveillé. L'État sait tout, d'autant plus que de nombreuses activités autrefois effectuées hors ligne sont passés sur l'Internet très récemment (ça bouge vite en Chine). Ainsi, l'application WeChat (qu'on connait en Occident uniquement comme une application de messagerie instantanée, concurrente de WhatsApp) est devenue la plate-forme d'accès à tout, une « super-app » sans laquelle rien n'est possible en Chine et notamment sans laquelle on ne peut rien acheter. Résultat, WeChat sait tout de tous les citoyens et, évidemment, l'État y a un accès complet, sans contrôle.

D'un autre côté, tout n'est pas aussi dystopique que c'est parfois présenté à l'étranger. Le fameux « crédit social », par exemple, n'est pas encore un système généralisé et centralisé de contrôle mais plutôt (pour l'instant), une série de projets locaux pas forcément coordonnés. Et l'auteur rappelle que certains systèmes chinois baptisés « crédit social » ne sont pas très éloignés de systèmes utilisés en Occident, par exemple par Uber où tout le monde note tout le monde (sans compter ce que font des horreurs comme Equifax). Il est amusant de voir l'auteur, p. 172, s'inquiéter des systèmes de vidéoconférence chinois qui surveillent l'attention portée par les utilisateurs à la réunion, alors que Zoom fait déjà cela.

Le gouvernement chinois ne veut pas s'arrêter là et il promeut fortement les idées les plus négatives comme la smart city de surveillance encore plus généralisée. Et il veut continuer à utiliser l'Internet pour assurer un contrôle politique des citoyens, par exemple via l'« armée des cinquante centimes » où on peut être payé pour noyer les rares critiques exprimées sur des forums sous des messages pro-gouvernementaux. Et les ambitions de la dictature chinoise ne s'arrêtent pas à son pays, le projet dit de « nouvelle route de la soie » sert de couverture à une promotion du contrôle à la chinoise dans d'autres pays. Bien des dictateurs, et même des dirigeants élus démocratiquement dans le monde, prêtent une oreille favorable à des discours promettant un meilleur contrôle du pays grâce à la technologie.

Le livre a quelques défauts. Par exemple, il ne mentionne pas les faiblesses techniques de la position chinoise. Si la Chine a rattrapé l'Occident sur certains points, et dépassé sur d'autres, elle n'est pas en position de force partout. Ainsi, comme l'a montré la crise entre Huawei et Google, provoquée par un refus du précédent gouvernement états-unien de laisser Google fournir un Android complet à Huawei, la Chine n'a pas encore un système d'exploitation pour ordiphone, tâche il est vrai difficile. Ces faiblesses sont d'autant plus importantes à analyser que le gouvernement chinois n'est pas avare de propagande présentant les résultats miraculeux obtenus en Chine, et qu'il faut garder la tête froide par rapport à des affirmations publicitaires. P. 70, l'auteur parle ainsi de la 5G en reprenant sans nuances le discours des techno-béats, chinois ou étrangers, discours qui mériterait d'être nuancé. De même, p. 160, il s'embrouille complètement sur les technologies quantiques, mélangeant QKD (sur laquelle la Chine a déjà fait des promesses exagérées, que l'auteur reprend à son compte sans aucune distance, surtout p. 163) et calculateurs quantiques.

Mais ce sont des détails. L'important est que ce livre analyse en détail ce qui se fait réellement et ce qui ne se fait pas (encore ?) en Chine, et permet de se faire une meilleure idée de ce qui nous attend si nous n'accompagnons pas le progrès technique d'une attention très serrée pour les questions de droits humains.


L'article seul

RFC 8980: Report from the IAB Workshop on Design Expectations vs. Deployment Reality in Protocol Development

Date de publication du RFC : Février 2021
Auteur(s) du RFC : J. Arkko, T. Hardie
Pour information
Première rédaction de cet article le 20 février 2021


L'atelier de l'IAB DEDR (Design Expectations vs. Deployment Reality) s'est tenu à Kirkkonummi en juin 2019 (oui, il faut du temps pour publier un RFC de compte-rendu). Son but était, par delà la constatation que le déploiement effectif des protocoles conçus par l'IETF ne suit pas toujours les attentes initiales, d'explorer pourquoi cela se passait comme cela et ce qu'on pouvait y changer.

Souvent, lors de la mise au point d'un nouveau protocole, les personnes qui y travaillent ont en tête un modèle de déploiement. Par exemple, pour le courrier électronique, l'idée dominante était qu'il y aurait souvent un serveur de messagerie par personne. On sait que ce n'est pas la situation actuelle. En raison de soucis de sécurité, de pressions économiques et/ou politiques, et d'autres facteurs, on a aujourd'hui un courrier nettement plus centralisé, avec un caractère oligopolistique marqué, dominé par une poignée d'acteurs qui dictent les règles. Cette centralisation n'est pas souhaitable (sauf pour les GAFA). Mais où est-ce que le dérapage a commencé ? Parfois, cela a été rapide, et parfois cela a pris beaucoup de temps.

Quelques exemples :

  • Le courrier électronique, on l'a dit, était conçu autour de l'idée qu'il y aurait beaucoup de serveurs, gérés par des acteurs différents. (À une époque, dans le monde universitaire, il était courant que chaque station de travail ait un serveur de courrier, et ses propres adresses.) Aujourd'hui, il est assez centralisé, chez des monstres comme Gmail et Outlook.com. Un des facteurs de cette centralisation est le spam, contre lequel il est plus facile de se défendre si on est gros.
  • Le DNS avait été prévu pour une arborescence de noms assez profonde (l'exemple traditionnel était l'ancien domaine de premier niveau .us qui était découpé en entités géographiques de plus en plus spécifiques). Mais l'espace des noms est aujourd'hui plus plat que prévu. On voit même des organisations qui ont, mettons, example.com et qui, lançant un nouveau produit, mettons foobar, réservent foobar.com, voire foobar-example.com au lieu de tout simplement créer foobar.example.com (ce qui serait en outre moins cher). Un autre exemple de centralisation est la tendance à abandonner les résolveurs locaux (qui, il est vrai, sont souvent mal gérés ou menteurs) pour des gros résolveurs publics comme Google Public DNS ou Quad9 (et cette centralisation, contrairement à ce qui est souvent prétendu, n'a rien à voir avec DoH).
  • Le Web est également un exemple de déviation des principes originels, vers davantage de centralisation. Le concept de base est très décentralisé. N'importe qui peut installer un serveur HTTP sur son Raspberry Pi et faire partie du World Wide Web. Mais cela laisse à la merci, par exemple, des dDoS ou, moins dramatiquement, de l'effet Slashdot (même si un site Web statique peut encaisser une charge importante). On constate que de plus en plus de sites Web dépendent donc de services centralisés, CDN ou gros relais comme Cloudflare.
  • Et ça ne va pas forcément s'arranger avec de nouvelles technologies, par exemple l'apprentissage automatique, qui sont difficiles à décentraliser.

L'IAB avait produit un RFC sur la question « qu'est-ce qui fait qu'un protocole a du succès », le RFC 5218. Dans un autre document, le RFC 8170, l'IAB étudiait la question des transitions (passage d'un protocole à un autre, ou d'une version d'un protocole à une autre). L'atelier de Kirkkonummi avait pour but de poursuivre la réflexion, en se focalisant sur les cas où les suppositions de base n'ont pas tenu face à la réalité.

L'agenda de l'atelier était structuré en cinq sujets, le passé (qu'avons-nous appris), les principes (quelles sont les forces à l'œuvre et comment les contrer ou les utiliser), la centralisation (coûts et bénéfices), la sécurité et le futur (fera-t-on mieux à l'avenir et savons-nous comment). 21 articles ont été reçus (ils sont en ligne), et 30 personnes ont participé.

Sur le passé, l'atelier a étudié des exemples de déploiement de protocoles, comme PKIX, DNSSEC, le NAT, l'IoT, etc. Souvent, ce qui a été effectivement déployé ne correspondait pas à ce qui était prévu. Par exemple, un protocole très demandé n'a pas eu le succès attendu (c'est le cas de DNSSEC : tout le monde réclame de la sécurité, mais quand il faut travailler pour la déployer, c'est autre chose) ou bien il n'a pas été déployé comme prévu. C'est d'autant plus vrai que l'IETF n'a pas de pouvoir : elle produit des normes et, ensuite, d'autres acteurs décident ou pas de déployer, et de la manière qu'ils veulent (le « marché » sacré). Le RFC cite quelques leçons de l'expérience passée :

  • Les retours du terrain arrivent toujours trop tard, bien après que la norme technique ait été bouclée. C'est particulièrement vrai pour les retours des utilisateurs individuels (ceux que, d'après le RFC 8890, nous devons prioriser).
  • Les acteurs de l'Internet font des choses surprenantes.
  • On constate la centralisation mais on ne peut pas forcément l'expliquer par les caractéristiques des protocoles. Rien dans HTTP ou dans SMTP n'impose la centralisation qu'on voit actuellement.
  • En revanche, certaines forces qui poussent à la centralisation sont connues : cela rend certains déploiements plus faciles (c'est un argument donné pour refuser la décentralisation). Et les solutions centralisées ont nettement la faveur des gens au pouvoir, car ils préfèrent travailler avec un petit nombre d'acteurs bien identifiés. (C'est pour cela qu'en France, tous les hommes politiques disent du mal des GAFA tout en combattant les solutions décentralisées, qui seraient plus difficiles à contrôler.)
  • On ne sait pas toujours si un nouveau protocole sera vraiment utile ou pas (cf. la 5G et le porno dans l'ascenseur).
  • Il est facile de dire que l'IETF devrait davantage interagir avec tel ou tel groupe, mais certains groupes sont difficiles à toucher (le RFC 8890 détaille ce problème).

Sur les principes, on a quand même quelques conclusions solides. Par exemple, il est clair qu'un nouveau protocole qui dépend de plusieurs autres services qui ne sont pas encore déployés aura davantage de mal à s'imposer qu'un protocole qui peut s'installer unilatéralement sans dépendre de personne. Et puis bien sûr, il y a l'inertie. Quand quelque chose marche suffisamment bien, il est difficile de la remplacer. (Le RFC donne l'exemple de BGP, notamment de sa sécurité.) Et cette inertie génère le phénomène bien reconnu de la prime au premier arrivant. Si un protocole fournit un nouveau service, un remplaçant aura le plus grand mal à s'imposer, même s'il est meilleur, face au tenant du titre. Le monde du virtuel est lourd et ne bouge pas facilement. Quand un protocole a eu un succès fou (terme défini et discuté dans le RFC 5218), le remplacer devient presque impossible. Autre principe analysé : l'IETF ne devrait de toute façon pas avoir d'autorité sur la façon dont ses protocoles sont déployés. Ce n'est pas son rôle et elle n'a pas de légitimité pour cela. Et, on l'a dit, les usages sont durs à prévoir. L'atelier a aussi constaté que certains modèles de déploiement, qui s'appliquent à beaucoup de cas, n'avaient pas été prévus et planifiés. C'est le cas de l'extrême centralisation, bien sûr, mais également le cas de « tout via le Web » qui fait que tout nouveau service sur l'Internet tend à être accessible uniquement à distance, avec les protocoles et les formats du Web. Cela tend à créer des silos fermés, même s'ils utilisent des protocoles ouverts. (C'est en réponse à ce problème qu'a été créée la licence Affero.)

Concernant le troisième sujet, la centralisation, l'atelier a constaté que la tendance à la centralisation n'est pas toujours claire dès le début. Le RFC cite l'exemple (très mauvais, à mon avis) de DoH. Autre constatation, la sécurité, et notamment le risque d'attaques par déni de services réparties est un puissant facteur de centralisation. Si vous voulez gérer un site Web sur un sujet controversé, avec des opposants puissants et prêts à tout, vous êtes quasiment obligé de faire appel à un hébergement de grande taille (face aux dDoS, la taille compte). Ceci dit, l'atelier a aussi identifié des forces qui peuvent aller en sens contraire à la centralisation. Une fédération peut mieux résister aux attaques (qui ne sont pas forcément techniques, cela peut être aussi la censure) qu'un gros silo centralisé, le chiffrement peut permettre même aux petits de limiter la surveillance exercée par les gros, les navigateurs Web peuvent adopter de meilleures pratiques pour limiter les données envoyées à la grosse plate-forme à laquelle on accède (toute cette liste du RFC est d'un optimisme souvent injustifié…), l'interopérabilité peut permettre davantage de concurrence (cf. le bon rapport du Conseil National du Numérique), et certaines tendance lourdes peuvent être combattues également par des moyens non-techniques (le RFC cite la régulation, ce qui n'est pas facilement accepté par les libertariens, même si ceux-ci ne sont pas plus nombreux à l'IETF qu'ailleurs).

Quatrième sujet, la sécurité. Traditionnellement, le modèle de menace de l'Internet (RFC 3552 mais aussi RFC 7258) est que tout ce qui est entre les deux machines qui communiquent peut être un ennemi. Cela implique notamment le choix du chiffrement de bout en bout. Toutefois, ce modèle de menace ne marche pas si c'est l'autre pair qui vous trahit. Ainsi, utiliser TLS quand vous parlez à Facebook vous protège contre des tiers mais pas contre Facebook lui-même. À l'heure où tant de communications en ligne sont médiées par des GAFA, c'est un point à prendre en considération. (Attention à ne pas jeter le bébé avec l'eau du bain ; le chiffrement de bout en bout reste nécessaire, mais n'est pas suffisant. Certains FAI remettent en cause le modèle de menace traditionnel pour combattre ou restreindre le chiffrement, en faisant comme si les GAFA étaient les seuls à faire de la surveillance.) Les participants à l'atelier sont plutôt tombés d'accord sur la nécessité de faire évoluer le modèle de menace mais il faudra veiller à ce que ne soit pas un prétexte pour relativiser l'importance du chiffrement, qui reste indispensable. À noter une autre limite d'un modèle de menace qui ne mentionnerait que les tiers situés sur le trajet : non seulement la partie distante (par exemple Facebook) peut être une menace, mais votre propre machine peut vous trahir, par exemple si vous n'utilisez pas du logiciel libre.

Enfin, cinquième et dernier sujet, le futur. L'IETF n'a pas de pouvoir contraignant sur les auteurs de logiciels, sur les opérateurs ou sur les utilisateurs (et heureusement). Elle ne peut agir que via ses normes. Par exemple, pour l'Internet des Objets, le RFC 8520 permet davantage d'ouverture dans la description des utilisations qu'un objet fera du réseau. Outre la production de bonnes normes, l'IETF peut être disponible quand on a besoin d'elle, par exemple comme réserve de connaissance et d'expertise.

La conclusion du RFC (section 5) indique que le problème est complexe, notamment en raison de la variété des parties prenantes : tout le monde n'est pas d'accord sur les problèmes, et encore moins sur les solutions. (Il n'existe pas de « communauté Internet », à part dans des discours politiciens.) D'autre part, certains des problèmes n'ont pas de solution évidente. Le RFC cite ainsi les dDoS, ou le spam. Cette absence de solution satisfaisante peut mener à déployer des « solutions » qui ont un rôle négatif. Le RFC note ainsi à juste titre que l'absence d'une solution de paiement en ligne correcte (anonyme, simple, bon marché, reposant sur des normes ouvertes, etc) pousse à faire dépendre la rémunération des créateurs de la publicité, avec toutes ses conséquences néfastes. Et l'Internet fait face à de nombreux autres défis stratégiques, comme la non-participation des utilisateurs aux questions qui les concernent, ou comme la délégation de décisions à des logiciels, par exemple le navigateur Web.

On l'a dit, la conclusion est que l'IETF doit se focaliser sur ce qu'elle sait faire et bien faire, la production de normes. Cela implique :

  • Travailler sur une mise à jour du modèle de menace cité plus haut,
  • Réfléchir aux mesures qui peuvent être prises pour limiter la centralisation,
  • Mieux documenter les principes architecturaux de l'Internet, notamment le principe de bout en bout,
  • Travailler sur les systèmes de réputation (cf. RFC 7070),
  • Etc.

Un autre compte-rendu de cet atelier, mais très personnel, avait été fait par Geoff Huston.


Téléchargez le RFC 8980


L'article seul

RFC 8976: Message Digest for DNS Zones

Date de publication du RFC : Février 2021
Auteur(s) du RFC : D. Wessels (Verisign), P. Barber (Verisign), M. Weinberg (Amazon), W. Kumari (Google), W. Hardaker (USC/ISI)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 10 février 2021


Ce nouveau RFC normalise un mécanisme pour ajouter aux zones DNS un condensat qui permet de vérifier leur intégrité. Pourquoi, alors qu'on a TSIG, TLS et SSH pour les transporter, et PGP et DNSSEC pour les signer ? Lisez jusqu'au bout, vous allez voir.

Le nouveau type d'enregistrement DNS créé par ce RFC se nomme ZONEMD et sa valeur est un condensat de la zone. L'idée est de permettre au destinataire d'une zone DNS de s'assurer qu'elle n'a pas été modifiée en route. Elle est complémentaire des différentes techniques de sécurité citées plus haut. Contrairement à DNSSEC, elle protège une zone, pas un enregistrement.

Revenons un peu sur la terminologie. Une zone (RFC 8499, section 7) est un ensemble d'enregistrements servi par les mêmes serveurs. Ces serveurs reçoivent typiquement la zone depuis un maître, et utilisent souvent la technique AXFR (RFC 5936) pour cela. Ce transfert est souvent (mais pas toujours) protégé par le mécanisme TSIG (RFC 8945), qui permet de s'assurer que la zone est bien celle servie par le maître légitime. D'autres techniques de transfert peuvent être utilisées, avec leur propre mécanisme de sécurité. On peut par exemple utiliser rsync sur SSH. Les zones sont souvent stockées dans des fichiers de zone, du genre :

@ IN  SOA ns4.bortzmeyer.org. hostmaster.bortzmeyer.org. (
        2018110902
        7200
        3600
        604800
        43200 )

  IN  NS  ns4.bortzmeyer.org.
  IN  NS  ns2.bortzmeyer.org.
  IN  NS  ns1.bortzmeyer.org.
  IN  NS  puck.nether.net.

  IN MX 0 mail.bortzmeyer.org.
  IN TXT  "v=spf1 mx -all"

  IN  A 92.243.4.211
  IN AAAA 2001:4b98:dc0:41:216:3eff:fe27:3d3f
  
www  IN CNAME ayla.bortzmeyer.org.

sub IN NS toto.example.  
  

Donc, les motivations de notre RFC sont d'abord le désir de pouvoir vérifier une zone après son transfert, indépendamment de la façon dont elle a été transférée. Une zone candidate évidente est la racine du DNS (cf. section 1.4.1), publiquement disponible, et que plusieurs résolveurs copient chez eux (RFC 8806). Ensuite, l'idée est de disposer d'un contrôle minimum (une somme de contrôle) pour détecter les modifications accidentelles (le rayon cosmique qui passe). Un exemple de modification accidentelle serait une troncation de la fin de la zone, d'habitude difficile à détecter puisque les fichiers de zone n'ont pas de marques de fin (contrairement à, par exemple, un fichier JSON). Notez que la « vraie » vérification nécessite DNSSEC. Si la zone n'est pas signée, le mécanisme décrit dans ce RFC ne fournit que la somme de contrôle : c'est suffisant contre les accidents, pas contre les attaques délibérées. Mais, de toute façon, tous les gens sérieux utilisent DNSSEC, non ?

Il existe de nombreuses techniques qui fournissent un service qui ressemble plus ou moins à un des deux services mentionnés ci-dessus. L'un des plus utilisés est certainement TSIG (RFC 8945). Beaucoup de transferts de zone (cf. RFC 5936) sont ainsi protégés par TSIG. Il a l'inconvénient de nécessiter un secret partagé entre serveur maître et serveur esclave. SIG(0) (RFC 2931) n'a pas cet inconvénient mais n'est quasiment jamais mis en œuvre. Toujours dans la catégories des protections du canal, on a TLS et l'IETF travaille sur un mécanisme de protection des transferts par TLS, mais on peut aussi imaginer d'utiliser simplement DoT (RFC 7858).

Ceci dit, toutes ces techniques de protection du canal ont le même défaut : une fois le transfert fait, elles ne servent plus à rien. Pas moyen de vérifier si le fichier est bien le fichier authentique. Ainsi, un serveur faisant autorité qui charge une zone à partir d'un fichier sur le disque ne peut pas vérifier que ce fichier n'a pas été modifié. Bien sûr, les protections fournies par le système de fichiers offrent certaines garanties, mais pas parfaites, par exemple si un programme a planté et laissé le fichier dans un état invalide (oui, ça s'est déjà produit). Bref, on préférerait une protection des données et pas seulement du canal.

Alors, pourquoi ne pas simplement utiliser DNSSEC, qui fournit effectivement cette sécurité des données ? Le problème est que dans une zone, seules les informations faisant autorité sont signées. Les délégations (vers un sous-domaine, comme sub.bortzmeyer.org dans l'exemple plus haut) et les colles (adresses IP des serveurs de noms qui sont dans la zone qu'ils servent) ne sont pas signés. Pour une zone comme la racine, où il n'y a quasiment que des délégations, ce serait un problème. Et ce serait encore pire avec les zones qui utilisent NSEC3 (RFC 5155) avec opt-out puisqu'on ne sait même plus si un nom non-signé existe ou pas. Donc, DNSSEC est très bien, mais ne suffit pas pour notre cahier des charges.

On a d'autres outils pour la sécurité des données, le plus évident étant PGP (RFC 4880). D'ailleurs, ça tombe bien, la racine des noms de domaine est déjà distribuée avec une signature PGP :


% wget -q https://www.internic.net/domain/root.zone 
% wget -q https://www.internic.net/domain/root.zone.sig
% gpg --verify root.zone.sig root.zone     
gpg: Signature made Wed Jan 13 08:22:50 2021 CET
gpg:                using DSA key 937BB869E3A238C5
gpg: Good signature from "Registry Administrator <nstld@verisign-grs.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: F0CB 1A32 6BDF 3F3E FA3A  01FA 937B B869 E3A2 38C5

  

Notez que Verisign utilise une signature détachée du fichier. Cela permet que le fichier reste un fichier de zone normal et chargeable, mais cela casse le lien entre la signature et le fichier. Bref, cela ne résout pas complètement le problème. (Les historiens et historiennes s'amuseront de noter qu'une autre solution, très proche de celle de notre RFC, figurait déjà dans le RFC 2065, mais qu'elle n'avait eu aucun succès.)

Bon, passons maintenant à la solution (section 1.3). On l'a dit, le principe est d'avoir un enregistrement de type ZONEMD qui contient un condensat de la zone. Il est généré par le responsable de la zone et quiconque a téléchargé la zone, par quelque moyen que ce soit, peut vérifier qu'il correspond bien à la zone. En prime, si la zone est signée avec DNSSEC, on peut vérifier que ce ZONEMD est authentique.

Du fait que ce condensat couvre l'intégralité de la zone, il faut le recalculer entièrement si la zone change, si peu que ce soit. Cette solution ne convient donc pas aux grosses zones très dynamiques (comme .fr). Dans le futur, le ZONEMD est suffisamment extensible pour que des solutions à ce problème lui soient ajoutées. En attendant, ZONEMD convient mieux pour des zones comme la racine (rappel, elle est disponible en ligne), ou comme la zone d'une organisation. La racine est un cas particulièrement intéressant car elle est servie par un grand nombre de serveurs, gérés par des organisations différentes. Sans compter les gens qui la récupèrement localement (RFC 8806). Le contrôle de son intégrité est donc crucial. Il y a une discussion en ce moment au sein du RZERC pour proposer l'ajout de ZONEMD dans la racine.

Pour la zone d'une organisation, notre RFC rappelle qu'il est recommandé d'avoir une diversité des serveurs de nom, afin d'éviter les SPOF et que c'est donc une bonne idée d'avoir des serveurs esclaves dans d'autres organisations. Comme cette diversité peut entrainer des risques (le serveur esclave est-il vraiment honnête ? le transfert s'est-il bien passé ?), là aussi, la vérification de l'intégrité s'impose. Autre scénario d'usage, les distributions de fichiers de zone, comme le fait l'ICANN avec CZDS ou comme le fait le registre du .ch (téléchargez ici). D'une manière générale, ce contrôle supplémentaire ne peut pas faire de mal.

Plongeons maintenant dans les détails techniques avec la section 2 du RFC, qui explique le type d'enregistrement ZONEMD (code 63). Il se trouve forcément à l'apex de la zone. Il comprend quatre champs :

  • Numéro de série, il permet de s'assurer qu'il couvre bien la zone qu'on veut vérifier (dont le numéro de série est dans le SOA).
  • Plan, la méthode utilisée pour génerer le condensat. Pour l'instant, un seul plan est normalisé, nommé Simple, il fonctionne par un calcul sur l'entièreté de la zone. On peut ajouter des plans au registre, selon la procédure « Spécification nécessaire ».
  • Algorithme, est l'algorithme de condensation utilisé, SHA-384 ou SHA-512 à l'heure actuelle mais on pourra en ajouter d'autres au registre (« Spécification nécessaire », là encore).
  • Et le condensat lui-même.

Question présentation dans les fichiers de zone, ça ressemble à :

example.com. 86400 IN ZONEMD 2018031500 1 1 (
       FEBE3D4CE2EC2FFA4BA99D46CD69D6D29711E55217057BEE
       7EB1A7B641A47BA7FED2DD5B97AE499FAFA4F22C6BD647DE )
  

Ici, le numéro de série est 2018031500, le plan 1 (Simple) et l'algorithme de condensation SHA-384.

Il peut y avoir plusieurs ZONEMD dans un fichier, ils doivent avoir des couples {Plan, Algorithme} différents. (Le but est de fournir plusieurs techniques de vérification, et de permettre de passer en souplesse de l'une à l'autre.)

Comment exactement se fait le calcul du condensat ? La section 3 le détaille. D'abord, on supprime de la zone les éventuels ZONEMD existants, et on place un ZONEMD bidon (il en faut un, en cas de signature DNSSEC, pour éviter de casser la signature). Si on a DNSSEC, on signe alors la zone (et il faudra re-faire le RRSIG du ZONEMD après), on canonicalise la zone (le condensat est calculé sur le format « sur le câble » pas sur le format texte), et on calcule ensuite le condensat sur la concaténation des enregistrements (à l'exclusion du ZONEMD bidon, qui avait été mis pour DNSSEC, et de sa signature). On génère ensuite le vrai ZONEMD, puis, si on a DNSSEC, on recalcule sa signature. Autant dire que vous ne le ferez pas à la main ! L'endroit logique pour faire ce calcul du ZONEMD est dans le logiciel qui fait les signatures DNSSEC. Notez que, contrairement à DNSSEC, tous les enregistrements sont utilisés, y compris ceux qui ne font pas autorité comme les délégations et les colles.

Un mot sur la canonicalisation. Tout calcul d'un condensat cryptographique doit se faire sur des données canonicalisées, c'est-à-dire mises sous une forme canonique, une forme unique et standardisée. Comme le changement d'un seul bit change complètement le condensat, il ne faut pas laisser des petites variations de détail (par exemple, pour le DNS, entre noms comprimés et non-comprimés) à l'imagination de chaque programmeur. Voilà pourquoi notre RFC spécifie rigoureusement une forme canonique (par exemple, les noms ne doivent pas être comprimés).

La vérification se fait de la même façon (section 4 du RFC). On vérifie que le numéro de série est le même, on canonicalise, on concatène, on condense et on vérifie qu'on trouve bien ce qui était dans le ZONEMD. (S'il y a plusieurs ZONEMD, le premier qui marche suffit.) Le mieux est évidemment de tout valider avec DNSSEC, en plus.

La section 6 de notre RFC revient sur la sécurité du ZONEMD, ce qu'il garantit et ce qu'il ne garantit pas. D'abord, le point le plus important : sans DNSSEC, ZONEMD n'est qu'une somme de contrôle, il garantit l'intégrité mais pas l'authenticité, et il ne protège donc que contre les modifications accidentelles (ce qui est déjà très bien !) Le bit flipping sera détecté mais pas l'attaque délibérée et soignée. Ainsi, sans DNSSEC, un attaquant n'aurait, par exemple, qu'à retirer l'enregistrement ZONEMD de la zone avant de faire ses modifications (une attaque par repli).

D'autre part, les algorithmes de cryptographie vieillissent (RFC 7696) et ZONEMD ne peut donc pas garantir de sécurité sur le long terme. D'ailleurs, sur le long terme, on n'aurait probablement plus les clés DNSSEC disponibles.

Plus drôle, ZONEMD permet, comme toute technique de sécurité, de nouveaux modes de déni de service, comme l'a déjà expérimenté tout utilisateur de la cryptographie. Comme le condensat est strictement binaire (il colle aux données, ou pas du tout), la zone entière peut être considérée comme invalide si un problème modifie ne serait-ce qu'un seul bit. Le souci de l'intégrité de la zone et celui de sa disponibilité sont ici en conflit, et le responsable de la zone doit choisir.

Si vous aimez les comparatifs de performance, la section 7 du RFC discute de chiffres. Par exemple, une zone de 300 000 enregistrements a été ZONEMDifiée en deux secondes et demi sur un serveur ordinaire. C'est encore trop lent pour être utilisable sur des zones comme .com mais cela montre que des grandes zones qui ne changent pas trop souvent peuvent être protégées.

Et question mises en œuvre, ça se passe comment ? J'ai testé l'excellente bibliothèque ldns. Le code avec calcul de ZONEMD devrait être publié dans une version officielle en 2021 mais, en attendant, c'est déjà dans git, en https://github.com/NLnetLabs/ldns. Une fois compilée, on peut fabriquer le ZONEMD (ici, avec la zone d'exemple montrée au début de cet article). On génère une clé, puis on signe, avec calcul de ZONEMD :

%  ./ldns-keygen -a ED25519 bortzmeyer.org
Kbortzmeyer.org.+015+00990

% ./ldns-signzone -o bortzmeyer.org -z 1:1  bortzmeyer-org.zone  Kbortzmeyer.org.+015+00990

% cat bortzmeyer-org.zone.signed
...
bortzmeyer.org.	3600	IN	ZONEMD	2018110902 1 1 b1af60c3c3e88502746cf831d2c64a5399c1e3c951136d79e63db2ea99898ba9f2c4f9b29e6208c09640aaa9deafe012
bortzmeyer.org.	3600	IN	RRSIG	ZONEMD 15 2 3600 20210215174229 20210118174229 990 bortzmeyer.org. FJ98//KDBF/iMl1bBkjGEBT3eeuH/rJDoGRDAoCBEocudLbA7F/38qwLpsPkr7oQcgbkLzhyHA7BXG/5fAwkAg==

(L'argument 1:1 signifie plan Simple et algorithme SHA-384.) On peut ensuite vérifier la zone. Si elle a un enregistrement ZONEMD, il est inclus dans la vérification :

% ./ldns-verify-zone  bortzmeyer-org.zone.signed
Zone is verified and complete             
   

Si je modifie une délégation (qui n'est pas protégée par DNSSEC mais qui l'est par ZONEMD) :

% ./ldns-verify-zone  bortzmeyer-org.zone.signed 
There were errors in the zone
  

Il y a aussi les dns-tools des gens du .cl. Pour BIND, c'est en cours de réflexion. Apparemment, Unbound y travaille également.


Téléchargez le RFC 8976


L'article seul

RFC 8982: Registration Data Access Protocol (RDAP) Partial Response

Date de publication du RFC : Février 2021
Auteur(s) du RFC : M. Loffredo, M. Martinelli (IIT-CNR/Registro.it)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 10 février 2021


Le protocole de récupération d'informations auprès d'un registre RDAP peut parfois rapporter une grande quantité d'informations pour chaque objet récupéré (un nom de domaine, par exemple). Le RDAP originel ne permettait pas au serveur de ne renvoyer qu'une information partielle s'il trouvait que cela faisait trop. C'est désormais possible avec l'extension de ce RFC.

Le but est évidemment d'économiser les ressources du serveur, aussi bien que celles du client, en récupérant et en transférant moins de données. Avant notre RFC, la seule solution était de tout envoyer au client, même s'il n'en utiliserait pas la plus grande partie. (Si, au lieu de ne vouloir qu'une partie de chaque objet, on veut une partie des objets, il faut regarder le RFC 8977.)

Ce RFC étend donc le langage de requêtes de RDAP (normalisé dans le RFC 7482), avec un paramètre fieldSet (section 2 de notre RFC) qui permet de sélectionner une partie des champs de la réponse. Voici un exemple d'URL pour une requête de tous les noms de domaine de .com :

https://rdap.verisign.example/domains?name=*.com&fieldSet=afieldset
  

Et comment on connait les champs possibles ? Notre RFC introduit un subsetting_metadata qui indique l'ensemble de champs courant, et les ensembles possibles, chacun identifié par un nom, et comportant les liens (RFC 8288) à utiliser. (Vous aurez une erreur HTTP 400 si vous êtes assez vilain·e pour faire une requête RDAP avec un ensemble inexistant.) Et pour savoir si le serveur RDAP que vous interrogez accepte cette nouvelle extension permettant d'avoir des réponses partielles, regardez si subsetting apparait dans le tableau rdapConformance de la réponse du serveur (cette extension est désormais dans le registre IANA). Voici l'exemple que donne le RFC :


{
     "rdapConformance": [
       "rdap_level_0",
       "subsetting"
     ],
     ...
     "subsetting_metadata": {
       "currentFieldSet": "afieldset",
       "availableFieldSets": [
         {
         "name": "anotherfieldset",
         "description": "Contains some fields",
         "default": false,
         "links": [
           {
           "value": "https://example.com/rdap/domains?name=example*.com
                     &fieldSet=afieldset",
           "rel": "alternate",
           "href": "https://example.com/rdap/domains?name=example*.com
                    &fieldSet=anotherfieldset",
           "title": "Result Subset Link",
           "type": "application/rdap+json"
           }
         ]
         },
       ...
       ]
     },
     ...
     "domainSearchResults": [
       ...
     ]
}

  

Mais il y a encore plus simple que de regarder subsetting_metadata : notre RFC décrit, dans sa section 4, trois ensembles de champs standards qui, espérons-le, seront présents sur la plupart des serveurs RDAP :

  • id, qui ne renvoie dans la réponse que les identificateurs des objets (handle pour les contacts, unicodeName pour les noms de domaine, etc).
  • brief, un peu plus bavard, qui renvoie l'information minimale (telle qu'estimée par le serveur) sur les objets.
  • full, qui renvoie la réponse complète (actuellement, avant le déploiement de ce RFC 8982, c'est la valeur par défaut).

Un exemple de réponse avec l'ensemble id, où on n'a que le nom (ASCII) des domaines :


   {
     "rdapConformance": [
       "rdap_level_0",
       "subsetting"
     ],
     ...
     "domainSearchResults": [
       {
         "objectClassName": "domain",
         "ldhName": "example1.com",
         "links": [
           {
           "value": "https://example.com/rdap/domain/example1.com",
           "rel": "self",
           "href": "https://example.com/rdap/domain/example1.com",
           "type": "application/rdap+json"
           }
         ]
       },
       {
         "objectClassName": "domain",
         "ldhName": "example2.com",
         "links": [
           {
           "value": "https://example.com/rdap/domain/example2.com",
           "rel": "self",
           "href": "https://example.com/rdap/domain/example2.com",
           "type": "application/rdap+json"
           }
         ]
       },
       ...
     ]
   }

  

Quelles mises en œuvre sont disponibles ? Il en existe une chez .it mais elle n'est accessible sur leur serveur de test que si on est authentifié.

Comme RDAP, contrairement à whois, permet l'authentification des clients (RFC 7481), on pourra imaginer des cas où l'ensemble complet de la réponse ne sera envoyé qu'à certains utilisateurs (section 8).

L'annexe A du RFC revient sur un choix sur lequel je suis passé rapidement : le fait que le client spécifie le nom d'un ensemble pré-défini de champs, plutôt que la liste des champs qui l'intéressent, ce qui serait plus souple. Mais cela aurait été compliqué pour les structures JSON profondes (il faudrait une syntaxe riche et peu lisible), et cela aurait compliqué les autorisations : que faire si un client demande deux champs et qu'il n'est autorisé que pour un seul ? Outre ces questions génériques de tout protocole utilisant JSON, il y avait des problèmes spécifiques à RDAP, comme le fait que le contenu sur une entité peut être réparti dans plusieurs structures JSON (ah, le jCard…) Des solutions existent, comme le langage de requêtes CQL, mais il a semblé trop coûteux pour un intérêt limité.


Téléchargez le RFC 8982


L'article seul

RFC 8942: HTTP Client Hints

Date de publication du RFC : Février 2021
Auteur(s) du RFC : I. Grigorik, Y. Weiss (Google)
Expérimental
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 9 février 2021


Aux débuts du Web, il allait de soi que le contenu renvoyé à un client était identique quel que soit le client. On demandait un article scientifique, le même article était donné à tout le monde. La séparation du contenu et de la présentation que permet HTML faisait en sorte que ce contenu s'adaptait automatiquement aux différents clients et notamment à leur taille. Mais petit à petit l'habitude s'est prise d'envoyer un contenu différent selon le client. C'était parfois pour de bonnes raisons (s'adapter à la langue de l'utilisateur) et parfois pour des mauvaises (incompréhension de la séparation du contenu et de la présentation, ignorance du Web par des commerciaux qui voulaient contrôler l'apparence exacte de la page). Cette adaptation au client peut se faire en tenant compte des en-têtes envoyés par le navigateur dans sa requête, notamment l'affreux User-Agent:, très indiscret et en général mensonger. Mais la tendance actuelle est de ne pas utiliser systématiquement ces en-têtes, très dangereux pour la vie privée et parfois inutiles : si le serveur HTTP n'adapte pas le contenu en fonction des en-têtes, pourquoi les envoyer ? Ce nouveau RFC propose une solution : un en-tête Accept-CH: envoyé par le serveur qui indique ce que le serveur va faire des en-têtes d'indication envoyés par le client (client hints) dans ses futures requêtes. Il s'agit d'un projet Google, déjà mis en œuvre dans Chrome mais, pour l'instant, seulement avec le statut « Expérimental ».

Le Web a toujours été prévu pour être accédé par des machines très différentes, en terme de taille d'écran, de logiciels utilisés, de capacités de traitement. Sans compter les préférences propres à l'utilisateur, par exemple sa langue. C'est ainsi que, par exemple, les lignes de texte ne sont pas définies dans le source en HTML, elles seront calculées dynamiquement par le navigateur qui, lui, connait la largeur de la fenêtre. Mais il a été difficile de faire comprendre cela à des marketeux habitués de la page imprimée et qui insistaient pour contrôler tout au pixel près.

Bref, il y a longtemps que des gens qui ne connaissent pas le Web font n'importe quoi, par exemple en regardant l'en-tête User-Agent: (RFC 7231, section 5.5.3) et en ajustant le contenu Web à cet en-tête, ce qui nécessite une base de données de tous les User-Agent: possibles puisque chaque nouvelle version d'un navigateur peut changer les choses. (D'où ces User-Agent: ridicules et mensongers qu'on voit aujourd'hui, où chaque navigateur met le nom de tous les autres, par exemple Edge annonce Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.2704.79 Safari/537.36 Edge/18.014.) Ces techniques sont évidemment très mauvaises : elles compliquent les serveurs, elles ne permettent pas de gérer le cas d'un nouveau navigateur (sauf à ce qu'il annonce les noms de ces prédécesseurs dans User-Agent:, ce qui se fait couramment), elles ne permettent pas facilement à l'utilisateur ou à son navigateur de savoir quels critères ont été utilisés par le serveur pour adapter le contenu. Et elles sont très indiscrètes, exposant par défaut bien plus d'informations que ce qui est nécessaire au serveur pour adapter son contenu. C'est ainsi que des services comme Panopticlick ou Am I unique? peuvent fonctionner, démontrant la possibilité d'identifier un utilisateur sans biscuits, avec juste du fingerprinting passif.

Un site Web peut aussi ajuster son contenu en fonction d'un utilisateur particulier, suivi, par exemple, par les biscuits du RFC 6265, ou via des paramètres dans l'URL mais cela complique les choses, par exemple en obligeant à mettre des informations dans l'URL de chaque ressource du site Web.

Une meilleure solution, au moins en théorie, est la négociation de contenu HTTP (RFC 7231, section 3.4.1) : le client utilise alors des en-têtes bien définis (comme Accept-Language: pour la langue) auxquels le serveur peut répondre par un contenu spécifique. La négociation de contenu pose toutefois un problème, note le RFC, c'est que les en-têtes sont systématiquement envoyés par le client, qui ne sait pas si le serveur en fera quelque chose. Cela peut notamment avoir des conséquences en terme de vie privée, un client pouvant être identifié par le jeu complet des en-têtes qu'il envoie, même en l'absence de biscuits de traçage. (En outre, pour le cas particulier de la langue, la négociation de contenu n'aide guère car elle ne prend pas en compte des questions comme la notion de version originale.)

Au contraire, estime le RFC (avec pas mal d'optimisme), le mécanisme décrit ici peut potentiellement être davantage protecteur, en obligeant le serveur à annoncer quelles informations il va utiliser et en n'envoyant les informations permettant l'ajustement du contenu que lorsqu'elles sont explicitement demandées.

En quoi consiste ce mécanisme, justement ? La section 2 du RFC le décrit. Un en-tête CH (Client Hint, indication par le client) est un en-tête HTTP qui va envoyer des données permettant au serveur de modifier le contenu. Les clients HTTP (les navigateurs Web, par exemple) envoient les en-tête CH en fonction de leur propre configuration, et des demandes du serveur, via l'en-tête Accept-CH:. Le projet de spécification « Client Hints Infrastructure » discute de telles politiques et donne un jeu minimal d'indications qui n'identifient pas trop le client. Notre RFC ajoute que, par défaut, le client HTTP ne devrait pas envoyer de données autres que celles contenues dans ce jeu minimal. On verra bien si les navigateurs Web suivront cette recommandation. En tout cas, le RFC insiste bien sur le risque d'identification (fingerprinting), avec toute technique où le client exprime des préférences. Notez qu'à l'heure actuelle, les indications client ne sont pas encore spécifiées, mais il existe des propositions.

Si le client envoie des en-têtes CH (Client Hint), le serveur peut alors ajuster son contenu. Comme celui-ci dépend des en-têtes CH, le serveur doit penser à ajouter un en-tête Vary: (RFC 7231, section 7.1.4). Le serveur doit ignorer les indications qu'il ne comprend pas (ce qui permettra d'en déployer des nouvelles sans tout casser).

Comment est-ce que le serveur HTTP indique qu'il accepte le système des indications client (client hints) ? La section 3 de notre RFC décrit l'en-tête Accept-CH: (Accept Client Hints) qui sert à indiquer que le serveur connait bien ce système. Il figure désormais dans le registre des en-têtes. Accept-CH: est un en-tête structuré (RFC 8941) et sa valeur est une liste des indications qu'il accepte. Ainsi :

Accept-CH: CH-Example, CH-Example-again
  

indique que le serveur HTTP connait le système décrit dans notre RFC et qu'il utilise deux indications client, CH-Example et CH-Example-again. (À l'heure actuelle, il n'y a pas encore d'indications client normalisées, donc le RFC et cet article utilisent des exemples bidons.)

Voici un exemple plus complet. Le serveur veut savoir quel logiciel utilise le client et sur quel système d'exploitation. Il envoie :

Accept-CH: Sec-CH-UA-Full-Version, Sec-CH-UA-Platform
  

(UA = User Agent, le client HTTP, il s'agit ici de propositions d'indications client ; Sec- et CH- sont expliqués plus loin.) Le navigateur va alors, dans ses requêtes suivantes, et s'il est d'accord, envoyer :

Sec-CH-UA: "Examplary Browser"; v="73"
Sec-CH-UA-Full-Version: "73.3R8.2H.1"
Sec-CH-UA-Platform: "Windows"
  

(Notez que cet exemple particulier suppose que Sec-CH-UA: est envoyé systématiquement, même non demandé, point qui est encore en discussion.)

Ce système des indications client pose évidemment des problèmes de sécurité, analysés dans la section 4. D'abord, si les indications client ont été conçues pour mieux respecter la vie privée, elles ne sont pas non plus une solution magique. Un serveur malveillant peut indiquer une liste très longue dans son Accept-CH: espérant que les clients naïfs lui enverront plein d'informations. (Notons que les chercheurs en sécurité pourront analyser les réponses des serveurs HTTP et compiler des listes de ceux qui abusent, contrairement au système actuel où le serveur peut capter l'information de manière purement passive.) Le client prudent ne doit envoyer au serveur que ce qui est déjà accessible audit serveur par d'autres moyens (API JavaScript par exemple). Et il doit tenir compte des critères suivants :

  • Entropie : il ne faut pas envoyer d'information rare, qui pourrait aider à identifier une machine. Indiquer qu'on tourne sur Windows n'est pas bien grave, cela n'est pas rare. Mais un client tournant sur Plan 9 ne devrait pas s'en vanter auprès du serveur.
  • Sensibilité : les informations sensibles ne devraient pas être envoyées (le RFC ne donne pas d'exemple mais cela inclut certainement la localisation).
  • Stabilité : les informations qui changent rapidement ne devraient pas être envoyées.

À noter que des indications apparemment utiles, comme la langue, peuvent être dangereuses ; s'il s'agit d'une langue rare, elle peut aider à l'identification d'un utilisateur, s'il s'agit de la langue d'une minorité persécutée, elle peut être une information sensible.

Le RFC recommande (reste à savoir si cela sera suivi) que les clients HTTP devraient lier le Accept-CH: à une origine (RFC 6454) et n'envoyer donc les informations qu'à l'origine qui les demande. Ils devraient également être configurables, permettant à l'utilisateur d'envoyer plus ou moins d'informations selon son degré de méfiance. (Le RFC n'en parle pas, mais j'ajoute que la valeur par défaut - très bavarde ou au contraire très discrète - est un choix crucial, car peu d'utilisateurs changeront ce réglage.) Et le RFC demande que tout logiciel client permette également la discrétion totale, en n'envoyant aucune indication client. (André Sintzoff me fait remarquer à juste titre que « l'absence d'information est déjà une information ». Signaler qu'on ne veut pas être suivi à la trace peut vous signaler comme élement suspect, à surveiller.)

La liste des indications à envoyer pour chaque origine doit évidemment être remise à zéro lorsqu'on effectue des opérations de nettoyage, comme de supprimer les biscuits.

La même section 4 donne des conseils aux auteurs de futures indications client. On a vu qu'à l'heure actuelle aucune n'était encore normalisée mais des projets existent déjà, notamment pour remplacer User-Agent:. Un des choix cruciaux est de décider si les indications peuvent être générées par une application (typiquement du code JavaScript exécuté par le navigateur Web) ou bien seulement par le client. Les secondes sont évidemment plus sûres et c'est pour cela que leur nom est préfixée par Sec- (pour Secure). C'est une idée qui vient de la spécification Fetch.

Toujours côté nommage des indications client, le RFC recommande que le nom soit préfixé de CH- pour Client Hints, ce qui peut permettre de les distinguer facilement.

À l'heure actuelle, Chromium met déjà en œuvre ce système des indications client.


Téléchargez le RFC 8942


L'article seul

RFC 8941: Structured Field Values for HTTP

Date de publication du RFC : Février 2021
Auteur(s) du RFC : M. Nottingham (Fastly), P-H. Kamp (The Varnish Cache Project)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 9 février 2021


Plusieurs en-têtes HTTP sont structurés, c'est-à-dire que le contenu n'est pas juste une suite de caractères mais est composé d'éléments qu'un logiciel peut analyser. C'est par exemple le cas de Accept-Language: ou de Content-Disposition:. Mais chaque en-tête ainsi structuré a sa propre syntaxe, sans rien en commun avec les autres en-têtes structurés, ce qui en rend l'analyse pénible. Ce nouveau RFC propose donc des types de données et des algorithmes que les futurs en-têtes qui seront définis pourront utiliser pour standardiser un peu l'analyse d'en-têtes HTTP. Les en-têtes structurés existants ne seront pas changés, pour préserver la compatibilité.

Imaginez : vous êtes un concepteur ou une conceptrice d'une extension au protocole HTTP qui va nécessiter la définition d'un nouvel en-tête. La norme HTTP, le RFC 7231, section 8.3.1, vous guide en expliquant ce à quoi il faut penser quand on conçoit un en-tête HTTP. Mais même avec ce guide, les pièges sont nombreux. Et, une fois votre en-tête spécifié, il vous faudra attendre que tous les logiciels, serveurs, clients, et autres (comme Varnish, pour lequel travaille un des auteurs du RFC) soient mis à jour, ce qui sera d'autant plus long que le nouvel en-tête aura sa syntaxe spécifique, avec ses amusantes particularités. Amusantes pour tout le monde, sauf pour le programmeur ou la programmeuse qui devra écrire l'analyse.

La solution est donc que les futurs en-têtes structurés réutilisent les éléments fournis par notre RFC, ainsi que son modèle abstrait, et la sérialisation proposée pour envoyer le résultat sur le réseau. Le RFC recommande d'appliquer strictement ces règles, le but étant de favoriser l'interopérabilité, au contraire du classique principe de robustesse, qui mène trop souvent à du code compliqué (et donc dangereux) car voulant traiter tous les cas et toutes les déviations. L'idée est que s'il y a la moindre erreur dans un en-tête structuré, celui-ci doit être ignoré complètement.

La syntaxe est spécifiée en ABNF (RFC 5234) mais le RFC fournit aussi des algorithmes d'analyse et, malheureusement, exige que, en cas de désaccord entre les algorithmes et la grammaire, ce soit les algorithmes qui l'emportent.

Voici un exemple fictif d'en-tête structuré très simple (tellement simple que, si tous étaient comme lui, on n'aurait sans doute pas eu besoin de ce RFC) : Foo-Example: est défini comme ne prenant qu'un élément comme valeur, un entier compris entre 0 et 10. Voici à quoi il ressemblera en HTTP :

Foo-Example: 3
  

Il accepte des paramètres après un point-virgule, un seul paramètre est défini, foourl dont la valeur est un URI. Cela pourrait donner :

Foo-Example: 2; foourl="https://foo.example.com/"    
  

Donc, ces solutions pour les en-têtes structurés ne serviront que pour les futurs en-têtes, pas encore définis, et qui seront ajoutés au registre IANA. Imaginons donc que vous soyez en train de mettre au point une norme qui inclut, entre autres, un en-tête HTTP structuré. Que devez-vous mettre dans le texte de votre norme ? La section 2 de notre RFC vous le dit :

  • Inclure une référence à ce RFC 8941.
  • J'ai parlé jusqu'à présent d'en-tête structuré mais en fait ce RFC 8941 s'applique aussi aux pieds (trailers) (RFC 7230, sections 4.1.2 et 4.4 ; en dépit de leur nom, les pieds sont des en-têtes eux aussi). La norme devra préciser si elle s'applique seulement aux en-têtes classiques ou bien aussi aux pieds.
  • Spécifier si la valeur sera une liste, un dictionnaire ou juste un élément (ces termes sont définis en section 3). Dans l'exemple ci-dessus Foo-Example:, la valeur était un élément, de type entier.
  • Penser à définir la sémantique.
  • Et ajouter les règles supplémentaires sur la valeur du champ, s'il y en a. Ainsi, l'exemple avec Foo-Example: imposait une valeur entière entre 0 et 10.

Une spécification d'un en-tête structuré ne peut que rajouter des contraintes à ce que prévoit ce RFC 8941. S'il en retirait, on ne pourrait plus utiliser du code générique pour analyser tous les en-têtes structurés.

Rappelez-vous que notre RFC est strict : si une erreur est présente dans l'en-tête, il est ignoré. Ainsi, s'il était spécifié que la valeur est un élément de type entier et qu'on trouve une chaîne de caractères, on ignore l'en-tête. Idem dans l'exemple ci-dessus si on reçoit Foo-Example: 42, la valeur excessive mène au rejet de l'en-tête.

Les valeurs peuvent inclure des paramètres (comme le foourl donné en exemple plus haut), et le RFC recommande d'ignorer les paramètres inconnus, afin de permettre d'étendre leur nombre sans tout casser.

On a vu qu'une des plaies du Web était le laxisme trop grand dans l'analyse des données reçues (c'est particulièrement net pour HTML). Mais on rencontre aussi des cas contraires, des systèmes (par exemple les pare-feux applicatifs) qui, trop fragiles, chouinent lorsqu'ils rencontrent des cas imprévus, parce que leurs auteurs avaient mal lu le RFC. Cela peut mener à l'ossification, l'impossibilité de faire évoluer l'Internet parce que des nouveautés, pourtant prévues dès l'origine, sont refusées. Une solution récente est le graissage, la variation délibérée des messages pour utiliser toutes les possibilités du protocole. (Un exemple pour TLS est décrit dans le RFC 8701.) Cette technique est recommandée par notre RFC.

La section 3 du RFC décrit ensuite les types qui sont les briques de base avec lesquelles on va pouvoir définir les en-têtes structurés. La valeur d'un en-tête peut être une liste, un dictionnaire ou un élément. Les listes et les dictionnaires peuvent à leur tour contenir des listes. Une liste est une suite de termes qui, dans le cas de HTTP, sont séparés par des virgules :

ListOfStrings-Example: "foo", "bar", "It was the best of times."    
  

Et si les éléments d'une liste sont eux-mêmes des listes, on met ces listes internes entre parenthèses (et notez la liste vide à la fin) :

ListOfListsOfStrings-Example: ("foo" "bar"), ("baz"), ("bat" "one"), ()    
  

Le cas des listes vides avait occupé une bonne partie des discussions à l'IETF (le vide, ça remplit…) Ainsi, un en-tête structuré dans la valeur est une liste a toujours une valeur, la liste vide, même si l'en-tête est absent.

Un dictionnaire est une suite de termes nom=valeur. En HTTP, cela donnera :

Dictionary-Example: en="Applepie", fr="Tarte aux pommes"
  

Et nous avons déjà vu les éléments simples dans le premier exemple. Les éléments peuvent être de type entier, chaîne de caractères, booléen, identificateur, valeur binaire, et un dernier type plus exotique (lisez le RFC pour en savoir plus). L'exemple avec Foo-Example: utilisait un entier. Les exemples avec listes et dictionnaires se servaient de chaînes de caractères. Ces chaînes sont encadrées de guillemets (pas d'apostrophes). Compte-tenu des analyseurs HTTP existants, les chaînes doivent hélas être en ASCII (RFC 20). Si on veut envoyer de l'Unicode, il faudra utiliser le type « contenu binaire » en précisant l'encodage (sans doute UTF-8). Quant aux booléens, notez qu'il faut écrire 1 et 0 (pas true et false), et préfixé d'un point d'interrogation.

Toutes ces valeurs peuvent prendre des paramètres, qui sont eux-mêmes une suite de couples clé=valeur, après un point-virgule qui les sépare de la valeur principale (ici, on a deux paramètres) :

ListOfParameters: abc;a=1;b=2    
  

J'ai dit au début que ce RFC définit un modèle abstrait, et une sérialisation concrète pour HTTP. La section 4 du RFC spécifie cette sérialisation, et son inverse, l'analyse des en-têtes (pour les programmeu·r·se·s seulement).

Ah, et si vous êtes fana de formats structurés, ne manquez pas l'annexe A du RFC, qui répond à la question que vous vous posez certainement depuis plusieurs paragraphes : pourquoi ne pas avoir tout simplement décidé que les en-têtes structurés auraient des valeurs en JSON (RFC 8259), ce qui évitait d'écrire un nouveau RFC, et permettait de profiter du code JSON existant ? Le RFC estime que le fait que les chaînes de caractères JSON soient de l'Unicode est trop risqué, par exemple pour l'interopérabilité. Autre problème de JSON, les structures de données peuvent être emboîtées indéfiniment, ce qui nécessiterait des analyseurs dont la consommation mémoire ne peut pas être connue et limitée. (Notre RFC permet des listes dans les listes mais cela s'arrête là : on ne peut pas poursuivre l'emboîtement.)

Une partie des problèmes avec JSON pourrait se résoudre en se limitant à un profil restreint de JSON, par exemple en utilisant le RFC 7493 comme point de départ. Mais, dans ce cas, l'argument « on a déjà un format normalisé, et mis en œuvre partout » tomberait.

Enfin, l'annexe A note également qu'il y avait des considérations d'ordre plutôt esthétiques contre JSON dans les en-têtes HTTP.

Toujours pour les programmeu·r·se·s, l'annexe B du RFC donne quelques conseils pour les auteur·e·s de bibliothèques mettant en œuvre l'analyse d'en-têtes structurés. Pour les aider à suivre ces conseils, une suite de tests est disponible. Quant à une liste de mises en œuvre du RFC, vous pouvez regarder celle-ci.

Actuellement, il n'y a dans le registre des en-têtes qu'un seul en-tête structuré, le Accept-CH: du RFC 8942. Sa valeur est une liste d'identificateurs. Mais plusieurs autres en-têtes structurés sont en préparation.

Si vous voulez un exposé synthétique sur ces en-têtes structuré, je vous recommande cet article par un des auteurs du RFC.

Voyons maintenant un peu de pratique avec une des mises en œuvre citées plus haut, http_sfv, une bibliothèque Python. Une fois installée :

  
% python3
>>> import http_sfv
>>> my_item=http_sfv.Item()
>>> my_item.parse(b"2")
>>> print(my_item)
2

On a analysé la valeur « 2 » en déclarant que cette valeur devait être un élément et, pas de surprise, ça marche. Avec une valeur syntaxiquement incorrecte :

     
>>> my_item.parse(b"2, 3")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/stephane/.local/lib/python3.6/site-packages/http_sfv-0.9.1-py3.6.egg/http_sfv/util.py", line 57, in parse
ValueError: Trailing text after parsed value

   

Et avec un paramètre (il sera accessible après l'analyse, via le dictionnaire Python params) :

     
>>> my_item.parse(b"2; foourl=\"https://foo.example.com/\"")
>>> print(my_item.params['foourl'])
https://foo.example.com/

   

Avec une liste :

     
>>> my_list.parse(b"\"foo\", \"bar\", \"It was the best of times.\"")
>>> print(my_list)
"foo", "bar", "It was the best of times."

   

Et avec un dictionnaire :

     
>>> my_dict.parse(b"en=\"Applepie\", fr=\"Tarte aux pommes\"")
>>> print(my_dict)
en="Applepie", fr="Tarte aux pommes"
>>> print(my_dict["fr"])
"Tarte aux pommes"


Téléchargez le RFC 8941


L'article seul

RFC 8989: Additional Criteria for Nominating Committee Eligibility

Date de publication du RFC : Février 2021
Auteur(s) du RFC : B.E. Carpenter (Univ. of Auckland), S. Farrell (Trinity College Dublin)
Expérimental
Première rédaction de cet article le 8 février 2021


L'épidémie de Covid-19 a remis en cause pas mal de choses dans nos sociétés, certaines fois très gravement. En moins dramatique, elle oblige l'IETF à adapter ses processus, étant donné qu'aucune réunion en présentiel n'a pu se tenir en 2020 et qu'on ne sait pas quand cela pourra reprendre. Or, la présence physique aux réunions était nécessaire pour se qualifier pour le NomCom, le comité de nomination. Ce RFC propose à titre expérimental de nouveaux critères de sélection.

Ce NomCom a pour tâche, décrite dans le RFC 8713, de désigner des personnes nommées pour remplir certains rôles à l'IETF. Il est composé de volontaires qui, normalement, doivent avoir participé en présentiel à un minimum de réunions IETF. Aujourd'hui, comme vous le savez, les réunions physiques ne sont plus possibles (à l'heure où j'écris, la réunion de San Francisco est très incertaine). Ce RFC modifie donc les règles pour l'année 2021 (le RFC 8788 avait déjà traité le cas de 2020). Il est officiellement expérimental (cf. RFC 3933) ; si les vaccins tiennent leur promesse, l'idée pourra être abandonnée et on reviendra aux pratiques d'avant. Mais, à l'heure actuelle, personne ne peut faire de pronostics sérieux dans ce domaine… Peut-être faudra-t-il se résigner à une modification permanente du RFC 8713 (section 2 de notre RFC).

En attendant que le futur s'éclaircisse, les règles pour cette année sont donc modifiées (section 4). Au lieu du seul critère de présence physique aux réunions, on accepte désormais pour sièger au NomCom les gens qui ont participé aux réunions en ligne (qui nécessitent une inscription et un enregistrement de « présence »), ou bien ont été président d'un groupe de travail ou bien auteur d'au moins deux RFC dans les cinq dernières années. Comme pour le critère précédent de présence physique, le but (section 3) est de vérifier que les membres du NomCom connaissent bien l'IETF.

D'autres critères auraient été possibles, mais ont été rejetés (section 5), comme l'écriture d'Internet-Drafts ou l'envoi de messages sur les listes de diffusion de l'IETF. Notez que la qualité des contributions à l'IETF ne rentre pas en ligne de compte, car elle est subjective.

Pour déterminer la liste des critères, le RFC se fonde sur une analyse de données (annexe A). Les données de départ ne sont pas parfaites (si quelqu'un s'inscrit à une réunion sous le nom de John Smith et à la suivante en mettant J. A. Smith, il apparaitra comme deux personnes différentes) mais c'est mieux que rien. Les jolis diagrammes de Venn en art ASCII montrent que les nouveaux critères permettent en effet d'élargir l'ensemble des volontaires potentiels, et que les critères rejetés n'auraient de toute façon pas eu d'influence.


Téléchargez le RFC 8989


L'article seul

RFC 8959: The "secret-token" URI Scheme

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : M. Nottingham
Pour information
Première rédaction de cet article le 30 janvier 2021


Enregistrer une clé privée (ou tout autre secret) dans un dépôt public (par exemple sur GitHub) est un gag courant. La nature des VCS fait qu'il est souvent difficile de retirer cette clé. Pour limiter un peu les dégâts, ce RFC enregistre un nouveau plan d'URI, secret-token:, qui permettra de marquer ces secrets, autorisant par exemple le VCS à rejeter leur enregistrement.

Ce RFC se focalise sur les secrets qui sont « au porteur » (bearer tokens) c'est-à-dire que leur seule connaissance suffit à les utiliser ; aucune autre vérification n'est faite. Ce peut être un mot de passe, une clé d'API, etc. Voici un exemple avec une clé GitLab (je vous rassure, je l'ai révoquée depuis) : gitlab-api-key.png

La révélation de ces secrets via un enregistrement accidentel, par exemple dans un dépôt logiciel public, est un grand classique. Lisez par exemple le témoignage « I Published My AWS Secret Key to GitHub », ou une aventure similaire, « Exposing your AWS access keys on Github can be extremely costly. A personal experience. », un avertissement de Github à ses utilisateurs, ou enfin une étude détaillée publiée à NDSS. Un git add de trop (ou bien un secret mis dans le code source) et, au prochain commit, le secret se retrouve dans le dépôt, puis publié au premier git push.

L'idée de ce RFC est de marquer clairement ces secrets pour que, par exemple, des audits du dépôt les repèrent plus facilement. Ou pour que les systèmes d'intégration continue puissent les rejeter automatiquement.

Le plan d'URI est simple (section 2 du RFC) : la chaîne secret-token: suivie du secret. Un exemple serait secret-token:E92FB7EB-D882-47A4-A265-A0B6135DC842%20foo (notez l'échappement du caractère d'espacement). Par exemple avec les secrets au porteur pour HTTP du RFC 6750, cela donnerait un envoi au serveur :

GET /authenticated/stuff HTTP/1.1
Host: www.example.com
Authorization: Bearer secret-token:E92FB7EB-D882-47A4-A265-A0B6135DC842%20foo
  

Le plan secret-token: est désormais dans le registre IANA.

Je n'ai pas encore trouvé d'organisation qui distribue ces secrets au porteur en utilisant ce plan d'URI mais il semble que GitHub soit tenté.


Téléchargez le RFC 8959


L'article seul

RFC 8977: Registration Data Access Protocol (RDAP) Query Parameters for Result Sorting and Paging

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : M. Loffredo (IIT-CNR/Registro.it), M. Martinelli (IIT-CNR/Registro.it), S. Hollenbeck (Verisign Labs)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 24 janvier 2021


Le protocole RDAP, normalisé notamment dans les RFC 7482 et RFC 7483, permet de récupérer des informations structurées sur des trucs (oui, j'ai écrit « trucs ») enregistrés auprès d'un registre, par exemple des domaines auprès d'un registre de noms de domaine. Voici un RFC tout juste publié qui ajoute à RDAP la possibilité de trier les résultats et également de les afficher progressivement (paging). C'est évidemment surtout utile pour les requêtes de type « recherche », qui peuvent ramener beaucoup de résultats.

Avec des requêtes « exactes » (lookup dans le RFC 7482), le problème est moins grave. Ici, je cherche juste de l'information sur un nom de domaine et un seul :

% curl https://rdap.nic.bzh/domain/chouchen.bzh
...
   "events" : [
      {
         "eventDate" : "2017-07-12T10:18:12Z",
         "eventAction" : "registration"
      },
      {
         "eventDate" : "2020-07-09T09:49:06Z",
         "eventAction" : "last changed"
      },
...
  

Mais si je me lançais dans une recherche plus ouverte (search dit le RFC 7482), avec par exemple la requête domains (notez le S à la fin, cf. RFC 7482, section 3.2.1), le nombre de résultats pourrait être énorme. Par exemple, si je demandais tous les domaines en .bzh avec https://rdap.nic.bzh/rdap/domains?name=*.bzh, j'aurais une réponse d'une taille conséquente. (Et je ne vous dis pas pour .com…)

En pratique, cette requête ne fonctionnera pas car je ne connais aucun registre qui autorise les recherches RDAP aux utilisateurs anonymes. Ceux-ci ne peuvent faire que des requêtes exactes, à la fois pour épargner les ressources informatiques (cf. la section 7 du RFC sur la charge qu'impose les recherches), et pour éviter de distribuer trop d'informations à des inconnus pas toujours bien intentionnés. Pour effectuer ces recherches, il faut donc un compte et une autorisation. Autrement, vous récupérez un code 401, 403 ou bien carrément une liste vide.

Et si vous avez une telle autorisation, comment gérer une masse importante de résultats ? Avec le RDAP originel, vous récupérez la totalité des réponses, que vous devrez analyser, et ce sera à vous, client, de trier. (Si le serveur n'envoie qu'une partie des réponses, pour épargner le client et ses propres ressources, il n'a malheureusement aucun moyen de faire savoir au client qu'il a tronqué la liste.) C'est tout le but de notre RFC que de faire cela côté serveur. Des nouveaux paramètres dans la requête RDAP vont permettre de mieux contrôler les réponses, ce qui réduira les efforts du client RDAP, du serveur RDAP et du réseau, et permettra d'avoir des résultats plus pertinents.

La solution ? La section 2 de notre RFC décrit les nouveaux paramètres :

  • count : le client demande à être informé du nombre de trucs que contient la liste des réponses.
  • sort : le client demande à trier les résultats.
  • cursor : ce paramètre permet d'indiquer un endroit particulier de la liste (par exemple pour la récupérer progressivement, par itérations successives).

Par exemple, https://example.com/rdap/domains?name=example*.com&count=true va récupérer dans .com (si le registre de .com acceptait cette requête…) tous les noms de domaine dont le nom commence par example, et indiquer leur nombre. Une réponse serait, par exemple :

"paging_metadata": {
       "totalCount": 43
},
"domainSearchResults": [
       ...
]    
  

(paging_metadata est expliqué plus loin.)

Pour le paramètre sort, le client peut indiquer qu'il veut un tri, sur quel critère se fait le tri, et que celui-ci doit être dans l'ordre croissant (a pour ascending) ou décroissant (d pour descending). Ainsi, https://example.com/rdap/domains?name=*.com&sort=name demande tous les noms en .com triés par nom. https://example.com/rdap/domains?name=*.com&sort=registrationDate:d demanderait tous les noms triés par date d'enregistrement, les plus récents en premier.

L'ordre de tri dépend de la valeur JSON du résultat (comparaison lexicographique pour les chaînes de caractères et numérique pour les nombres), sauf pour les adresses IP, qui sont triées selon l'ordre des adresses et pour les dates qui sont triées dans l'ordre chronologique. Ainsi, l'adresse 9.1.1.1 est inférieure à 10.1.1.1 (ce qui n'est pas le cas dans l'ordre lexicographique). Le RFC fait remarquer que tous les SGBD sérieux ont des fonctions pour traiter ce cas. Ainsi, dans PostgreSQL, la comparaison des deux chaînes de caractères donnera :

=> SELECT '10.1.1.1' < '9.1.1.1';
 t
  

Alors que si les adresses IP sont mises dans une colonne ayant le type correct (INET), on a le bon résultat :

=> SELECT '10.1.1.1'::INET < '9.1.1.1'::INET;
 f
  

Après le sort=, on trouve le nom de la propriété sur laquelle on trie. C'est le nom d'un membre de l'objet JSON de la réponse. Non, en fait, c'est plus compliqué que cela. Certains membres de la réponse ne sont pas utilisables (comme roles, qui est multi-valué) et des informations importantes (comme registrationDate cité en exemple plus haut) ne sont pas explicitement dans la réponse. Notre RFC définit donc une liste de propriétés utilisables, et explique comment on les calcule (par exempe, registrationDate peut se déduire des events). Plutôt que ces noms de propriétés, on aurait tout pu faire en JSONpath ou JSON Pointer (RFC 6901) mais ces deux syntaxes sont complexes et longues ($.domainSearchResults[*].events[?(@.eventAction='registration')].eventDate est le JSONPath pour registrationDate). La mention en JSONPath du critère de tri est donc facultative.

Et, bien sûr, si le client envoie un nom de propriété qui n'existe pas, il récupérera une erreur HTTP 400 avec une explication en JSON :

{
       "errorCode": 400,
       "title": "Domain sorting property 'unknown' is not valid",
       "description": [
           "Supported domain sorting properties are:"
           "'aproperty', 'anotherproperty'"
       ]

}
  

Et le troisième paramètre, cursor ? Ce RFC fournit deux méthodes pour indiquer où on en est dans la liste des résultats, la pagination par décalage (offset pagination) et celle par clé (keyset pagination, qu'on trouve parfois citée sous le nom ambigu de cursor pagination, qui désigne plutôt une méthode avec état sur le serveur). Ces deux méthodes ont en commun de ne pas nécessiter d'état du côté du serveur. La pagination par décalage consiste à fournir un décalage depuis le début de la liste et un nombre d'éléments désiré, par exemple « donne-moi 3 éléments, commençant au numéro 10 ». Elle est simple à mettre en œuvre, par exemple avec SQL :

SELECT truc FROM Machins ORDER BY chose LIMIT 3 OFFSET 9;  
  

Mais elle n'est pas forcément robuste si la base est modifiée pendant ce temps : passer d'une page à l'autre peut faire rater des données si une insertion a eu lieu entretemps (cela dépend aussi de si la base est relue à chaque requête paginée) et elle peut être lente (surtout avec RDAP où la construction des réponses prend du temps, alors que celles situées avant le début de la page seront jetées). L'autre méthode est la pagination par clé où on indique une caractéristique du dernier objet vu. Si les données sont triées, il est facile de récupérer les N objets suivants. Par exemple en SQL :

SELECT truc FROM Machins WHERE chose > [la valeur] ORDER BY chose LIMIT 3;
  

Un inconvénient de cette méthode est qu'il faut un champ (ou un ensemble de champs) ayant un ordre (et pas de duplicata). RDAP rend cela plus difficile, en agrégeant des informations provenant de différentes tables (cf. l'annexe B du RFC). (Voir des descriptions de cette pagination par clé dans « Paginating Real-Time Data with Keyset Pagination » ou « Twitter Ads API », pour Twitter.) RDAP permet les deux méthodes, chacune ayant ses avantages et ses inconvénients. L'annexe B du RFC explique plus en détail ces méthodes et les choix faits. (Sinon, en dehors de RDAP, un bon article sur le choix d'une méthode de pagination, avec leur mise en œuvre dans PostgreSQL est « Five ways to paginate in Postgres, from the basic to the exotic ».) Pour RDAP, un https://example.com/rdap/domains?name=*.com&cursor=offset:9,limit:3 récupérerait une page de trois éléments, commençant au dixième, et https://example.com/rdap/domains?name=*.com&cursor=key:foobar.com trouverait les noms qui suivent foobar.com. Notez qu'en réalité, vous ne verrez pas directement le décalage, la clé et la taille de la page dans l'URL : ils sont encodés pour permettre d'utiliser des caractères quelconques (et aussi éviter que le client ne les bricole, il est censé suivre les liens, pas fabriquer les URL à la main). Les exemples du RFC utilisent Base64 pour l'encodage, en notant qu'on peut certainement faire mieux.

La capacité du serveur à mettre en œuvre le tri et la pagination s'indiquent dans le tableau rdapConformance avec les chaînes sorting et paging (qui sont désormais dans le registre IANA). Par exemple (pagination mais pas tri) :

"rdapConformance": [
           "rdap_level_0",
           "paging"
     ]
  

Il est recommandé que le serveur documente ces possibilités dans deux nouveaux éléments qui peuvent être présents dans une réponse, sorting_metadata et paging_metadata. Cela suit les principes d'auto-découverte de HATEOAS. Dans la description sorting_metadata, on a currentSort qui indique le critère de tri utilisé, et availableSorts qui indique les critères possibles. Chaque critère est indiqué avec un nom (property), le fait qu'il soit le critère par défaut ou pas, éventuellement une expression JSONPath désignant le champ de la réponse utilisé et enfin une série de liens (RFC 8288) qui vont nous indiquer les URL à utiliser. Pour paging_metadata, on a totalCount qui indique le nombre d'objets sélectionnés, pageSize qui indique le nombre récupérés à chaque itération, pageNumber qui dit à quelle page on en est et là encore les liens à suivre. Ce pourrait, par exemple, être :

"sorting_metadata": {
        "currentSort": "name",
        "availableSorts": [
          {
          "property": "registrationDate",
          "jsonPath": "$.domainSearchResults[*].events[?(@.eventAction==\"registration\")].eventDate",
          "default": false,
          "links": [
            {
            "value": "https://example.com/rdap/domains?name=example*.com&sort=name",
            "rel": "alternate",
            "href": "https://example.com/rdap/domains?name=example*.com&sort=registrationDate",
            "title": "Result Ascending Sort Link",
            "type": "application/rdap+json"
            },
            {
            "value": "https://example.com/rdap/domains?name=example*.com&sort=name",
            "rel": "alternate",
            "href": "https://example.com/rdap/domains?name=example*.com&sort=registrationDate:d",
            "title": "Result Descending Sort Link",
            "type": "application/rdap+json"
            }
          ]
	  ...
  

Ici, sorting_metadata nous indique que le tri se fera sur la base du nom, mais nous donne les URL à utiliser pour trier sur la date d'enregistrement. Quant à la pagination, voici un exemple de réponse partielle, avec les liens permettant de récupérer la suite :

"paging_metadata": {
       "totalCount": 73,
       "pageSize": 50,
       "pageNumber": 1,
       "links": [
         {
         "value": "https://example.com/rdap/domains?name=example*.com",
         "rel": "next",
         "href": "https://example.com/rdap/domains?name=example*.com&cursor=wJlCDLIl6KTWypN7T6vc6nWEmEYe99Hjf1XY1xmqV-M=",
         "title": "Result Pagination Link",
         "type": "application/rdap+json"
         }
       ]
  

L'idée de permettre le contrôle des réponses via des nouveaux paramètres (count, sort et cursor, présentés ci-dessus), vient entre autre du protocole OData. Une autre solution aurait été d'utiliser des en-têtes HTTP (RFC 7231). Mais ceux-ci ne sont pas contrôlables depuis le navigateur, ce qui aurait réduit le nombre de clients possibles. Et puis cela rend plus difficile l'auto-découverte des extensions, qui est plus pratique via des URL, cette auto-découverte étant en général considérée comme une excellente pratique REST.

Il existe à l'heure actuelle une seule mise en œuvre de ce RFC dans le RDAP non public de .it. La documentation est en ligne.

Notre RFC permet donc de ne récupérer qu'une partie des objets qui correspondent à la question posée. Si on veut plutôt récupérer une partie seulement de chaque objet, il faut utiliser le RFC 8982.


Téléchargez le RFC 8977


L'article seul

RFC 8963: Evaluation of a Sample of RFCs Produced in 2018

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : C. Huitema (Private Octopus)
Pour information
Première rédaction de cet article le 23 janvier 2021


On raconte souvent que la publication d'un RFC prend longtemps, très longtemps, trop longtemps, et on dit parfois que cela est dû à une bureaucratie excessive dans le processus de publication. Peut-on objectiver cette opinion ? Dans ce RFC, l'auteur étudie le trajet de plusieurs RFC (pris au hasard) publiés en 2018 et regarde où étaient les goulets d'étranglement, et ce qui a pris du temps. Les RFC étudiés ont mis en moyenne trois ans et quatre mois à être publiés, depuis le premier document écrit jusqu'à la publication finale. (Mais il y a de grandes variations.) La majorité du temps est passée dans le groupe de travail, ce ne sont donc pas forcément les étapes « bureaucratiques » qui retardent.

Heureusement pour cette étude, le DataTracker enregistre les différentes étapes de la vie d'un document et permet donc au chercheur de travailler sur des données solides. Mais attention, si les données sont fiables, leur interprétation est toujours délicate. Et, si une métrique devient un objectif, elle cesse d'être une bonne métrique. Si l'IETF ne cherchait qu'à raccourci le délai de publication, ce serait simple, il suffirait d'approuver sans discussion et immédiatement toutes les propositions, même mauvaises. (Ce qu'on nomme le rubber stamping en anglais.)

La section 2 expose la méthodologie suivie. D'abord, déterminer les dates importantes dans la vie d'un RFC. Tous les RFC ne suivent pas le même parcours, loin de là. Le cas typique est celui d'un document individuel, qui est ensuite adopté par un groupe de travail, approuvé par l'IESG, puis publié par le RFC Editor. Dans cette analyse, trois périodes sont prises en compte :

  • Le temps de traitement dans le groupe de travail, qui part de la première publication et s'arrête au dernier appel à l'IETF,
  • Le temps de traitement par l'IETF, qui part du dernier appel à l'IETF et se termine par l'approbation par l'IESG,
  • Le temps de traitement par le RFC Editor, qui part de l'approbation par l'IESG et se termine par la publication en RFC.

Ainsi, pour le dernier RFC publié au moment où j'écris cet article (et qui n'est donc pas pris en compte dans l'analyse, qui couvre des RFC de 2018), pour ce RFC 9003, on voit sur le DataTracker qu'il a été documenté pour la première fois en décembre 2017, adopté par un groupe de travail en avril 2018, soumis à l'IESG en avril 2020, a eu un IETF Last Call en juin 2020, a été approuvé par l'IESG en novembre 2020 et enfin publié en RFC début janvier 2021. Mais beaucoup d'autres RFC suivent un autre parcours. Pour la voie indépendante (décrite dans le RFC 4846), l'analyse de ce RFC 8963 considère l'approbation par l'ISE (Independent Submission Editor) comme terminant la première période et l'envoi au RFC Editor comme terminant la deuxième.

Les vingt RFC qui sont utilisés dans l'étude ont été pris au hasard parmi ceux publiés en 2018. Le RFC reconnait que c'est un échantillon bien petit mais c'est parce que les données disponibles ne fournissaient pas toutes les informations nécessaires et qu'il fallait étudier « manuellement » chaque RFC, ce qui limitait forcément leur nombre. Je ne vais pas lister ici tous les RFC étudiés, juste en citer quelques uns que je trouve intéressant à un titre ou l'autre :

  • Le RFC 8446 est un très gros morceau. C'est la nouvelle version d'un protocole absolument critique, TLS. Non seulement le RFC est gros et complexe, mais le souci de sécurité a entrainé des études particulièrement poussées. Et, pour couronner le tout, ce RFC a été au cœur de polémiques politiques, certains reprochant à cette version de TLS d'être trop efficace, d'empêcher d'accéder aux données. La phase finale chez le RFC Editor, dite « AUTH48 » (car elle se fait normalement en 48 heures…) n'a pas pris moins de deux mois ! C'est en partie dû à une nouveauté de l'époque, utiliser GitHub pour suivre les changements à apporter. Pour chaque RFC étudié, l'auteur note également son succès ou insuccès en terme de déploiement et TLS 1.3 est un succès massif, avec des dizaines de mises en œuvre différentes et une présence très forte sur l'Internet.
  • Le RFC 8324 est un cas très différent. Consacré à une série d'opinions sur le DNS et ses évolutions récentes, il ne s'agit pas, contrairement au précédent, d'une norme IETF, mais d'une contribution individuelle. N'engageant que son auteur, elle ne nécessite pas le même niveau d'examen. C'est donc ce RFC qui est le titulaire du record dans l'étude : neuf mois seulement entre la première publication et le RFC.
  • Le RFC 8429 avait pour but de documenter l'abandon de plusieurs protocoles de cryptographie désormais dépassés. A priori très simple et très consensuel, il a été retardé par une discussion plus bureaucratique à propos de ses conséquences exactes sur le RFC 4757, puis par un délai très long d'un des auteurs à répondre lors de la phase finale (« AUTH48 » a pris trois mois).
  • Le RFC 8312 portait aussi sur un sujet consensuel, l'algorithme de lutte contre la congestion CUBIC étant aujourd'hui largement adopté. Mais il a quand même pris des années, en partie car, justement, CUBIC étant consensuel et largement déployé, il ne semblait pas crucial de le documenter. (Rappelez-vous que le travail à l'IETF est fait par des volontaires.)
  • Le RFC 8492 a également pris longtemps car c'était un projet individuel, dont l'auteur n'avait pas le temps de s'occuper, ce qui explique des longs délais à certains points. En outre, il a été retardé par la nécessité d'attendre un changement de politique d'enrgistrements dans certains registres à l'IANA, changements qui dépendaient de TLS 1.3, qui prenait du temps.
  • Un autre RFC qui a souffert du fait que même ses auteurs ne le considéraient pas comme urgent a été le RFC 8378, un projet très expérimental et dont la publication en RFC a pris plus de quatre ans.
  • Un des buts de l'étude était de voir s'il y avait une corrélation entre le délai total et certaines caractéristiques du RFC, par exemple sa longueur. Mais le RFC 8472, quoique simple, a pris plus de trois ans, en partie pour un problème bureaucratique sur le meilleur groupe de travail à utiliser.
  • En revanche, le RFC 8362 n'a pas de mal à expliquer le temps qu'il a pris : il modifie sérieusement le protocole OSPF et nécessite des mécanismes de transition depuis les anciennes versions, qui ont eux-même pris du temps.

Bien, après cette sélection d'un échantillon de RFC, qu'observe-t-on (section 4 de notre RFC) ? Le délai moyen entre le premier Internet Draft et la publication en RFC est de trois ans et trois mois. Mais les variations sont telles que cette moyenne n'a guère de sens (c'est souvent le cas avec la moyenne). Le plus malheureux est le RFC 8492, six ans et demi au total, mais ce cas n'est pas forcément généralisable. Pour les RFC de l'IETF, où le délai moyen est presque le même, le temps passé dans le groupe de travail est de deux ans et neuf mois, à l'IESG de trois à quatre mois et à peu près pareil chez le RFC Editor. Bref, 80 % du temps se passe en « vrai » travail, dans le groupe, les passages plus « bureaucratiques » n'occupent que 20 % du temps et ne sont donc pas les principaux responsables des délais.

L'étude regarde aussi des échantillons de RFC publiés en 2008 et en 1998 (en utilisant cette fois, à juste titre, des valeurs médianes) et note que le délai était à peu près le même en 2008 mais qu'il était trois à quatre fois plus court en 1998.

Et la partie purement éditoriale, chez le RFC Editor ? On a vu qu'elle prenait de trois à quatre mois. C'est quatre en moyenne mais si on exclut l'extrême RFC 8492, c'est plutôt trois mois, ce que je trouve plutôt court pour relire et préparer des documents longs et complexes, où une coquille peut être très gênante (ce ne sont pas des romans !) Quelles sont les caractéristiques des RFC que l'on pourrait corréler à ce délai chez le RFC Editor ? L'étude montre une corrélation entre le délai et la longueur du document, ce qui n'est pas surprenant. Même chose pour la corrélation entre le nombre de changements faits depuis l'approbation par l'IESG et la publication. (Une des tâches du RFC Editor est de faire en sorte que les RFC soient en bon anglais alors que beaucoup d'auteurs ne sont pas anglophones.) Plus étonnant, le nombre d'auteurs ne diminue pas le délai, au contraire, il l'augmente. Un nouveau cas de « quand on ajoute des gens au projet, le projet n'avance pas plus vite » ? Il ne faut pas oublier qu'il existe une zone grise entre « changement purement éditorial », où le RFC Editor devrait décider, et « changement qui a des conséquences techniques » et où l'approbation des auteurs est cruciale. Il n'est pas toujours facile de s'assurer de la nature d'un changement proposé par le RFC Editor. Et, si le changement a des conséquences techniques, il faut mettre les auteurs d'accord entre eux, ce qui est long (ils peuvent être dans des fuseaux horaires différents, avec des obligations professionnelles différentes) et peut soulever des désaccords de fond.

Et pour la voie indépendante ? Trois des RFC de l'échantillon étaient sur cette voie. Ils ont été publiés plus vite que sur la voie IETF, ce qui est logique puisqu'ils ne nécessitent pas le consensus de l'IETF (voir le RFC 8789). En revanche, le fait que la fonction d'ISE (Independant Stream Editor, cf. RFC 8730) soit une tâche assurée par un seul volontaire peut entrainer des retards ce qui a été le cas, ironiquement, de ce RFC 8963.

L'étude se penche aussi sur le nombre de citations dont bénéficie chaque RFC (section 5) car elle peut donner une idée sommaire de leur impact. Elle a utilisé l'API de Semantic Scholar. Par exemple, pour le RFC 8483, publié l'année de l'étude mais pas inclus dans l'échantillon :

% curl -s https://api.semanticscholar.org/v1/paper/10.17487/rfc8483\?include_unknown_references=true \
   jq .
  

On voit qu'il est cité une fois, précisément par ce RFC. En revanche, le RFC 8446, sur TLS 1.3 est cité pas moins de 773 fois :

% curl -s https://api.semanticscholar.org/v1/paper/10.17487/rfc8446\?include_unknown_references=true | \
   jq .citations\|length         
773
  

C'est de très loin le plus « populaire » dans le corpus (l'échantillon étudié). C'est bien sûr en partie en raison de l'importance critique de TLS, mais c'est aussi parce que TLS 1.3 a été étudié par des chercheurs et fait l'objet d'une validation formelle, un sujet qui génère beaucoup d'articles dans le monde académique. C'est aussi le cas du RFC 8312, sur Cubic, car la congestion est également un sujet de recherche reconnu. Notez que le passage du temps est impitoyable : les RFC des échantillons de 2008 et 1998 ne sont quasiment plus cités (sauf le RFC 2267, qui résiste). Est-ce que le nombre de citations est corrélé à l'ampleur du déploiement ? Dans le cas des RFC 8446 et RFC 8312, on pourrait le croire, mais le RFC 8441 a également un très vaste déploiement, et quasiment aucune citation. À l'inverse, un RFC qui a un nombre de citations record, le RFC 5326, n'a quasiment pas eu de déploiement, mais a excité beaucoup de chercheurs académiques (et même médiatique, vu son sujet cool), ce qui explique le nombre de citations. Bref, le monde de la recherche et celui des réseaux n'ont pas des jugements identiques.

On avait noté que le RFC 2267 était beaucoup cité. Or, il n'est plus d'actualité, ayant officiellement été remplacé par le RFC 2827. Mais les citations privilégient la première occurrence, et ne reflètent donc pas l'état actuel de la normalisation.

Bon, on a vu que les citations dans le monde de la recherche ne reflétaient pas réellement l'« importance » d'un RFC. Et le nombre d'occurrences dans un moteur de recherche, c'est mieux ? L'auteur a donc compté le nombre de références aux RFC dans Google et Bing. Il y a quelques pièges. Par exemple, en cherchant « RFC8441 », Bing trouve beaucoup de références à ce RFC 8441, qui parle de WebSockets, mais c'est parce qu'il compte des numéros de téléphone se terminant par 8441, ou des adresses postales « 8441 Main Street ». Google n'a pas cette amusante bogue. Ceci dit, il est noyé par le nombre très élevé de miroirs des RFC, puisque l'IETF permet et encourage ces copies multiples (contrairement aux organisations de normalisation fermées comme l'AFNOR). Ceci dit, les RFC 8441 et RFC 8471 sont plus souvent cités, notamment car ils apparaissent fréquemment dans les commentaires du code source d'un logiciel qui les met en œuvre. Le « test Google » est donc assez pertinent pour évaluer le déploiement effectif.

Quelles conclusions en tirer (section 6 du RFC) ? D'abord, si on trouve le délai de publication trop long, il faut se focaliser sur le temps passé dans le groupe de travail, car c'est clairement le principal contributeur au délai. [En même temps, c'est logique, c'est là où a lieu le « vrai » travail.] Malheureusement, c'est là où le DataTracker contient le moins d'information alors que les phases « bureaucratiques » comme le temps passé à l'IESG bénéficient d'une traçabilité plus détaillée. Ainsi, on ne voit pas les derniers appels (Last Calls) internes aux groupes de travail. Bien sûr, on pourrait rajouter ces informations mais attention, cela ferait une charge de travail supplémentaire pour les présidents des groupes de travail (des volontaires). Récolter des données pour faire des études, c'est bien, mais cela ne doit pas mener à encore plus de bureaucratie.

Du fait que l'étude ne porte que sur des RFC effectivement publiés, elle pourrait être accusée de sensibilité au biais du survivant. Peut-être que les RFC qui n'ont pas été publiés auraient aussi des choses à nous dire ? L'abandon d'un projet de normalisation est fréquent (pensons par exemple à DBOUND ou RPZ) et parfaitement normal et souhaitable ; toutes les idées ne sont pas bonnes et le travail de tri est une bonne chose. Mais, en n'étudiant que les RFC publiés, on ne peut pas savoir si le tri n'a pas été trop violent et si de bonnes idées n'en ont pas été victimes. L'IETF ne documente pas les abandons et une étude de drafts sans successeur pourrait être intéressante.

Pour terminer, je me suis amusé à regarder ce qu'il en était des trois RFC que j'ai écrit :

  • Le RFC 7626 a été publié moins de deux ans après le premier document ce qui, on l'a vu, est inférieur à la moyenne. Fortement poussé par l'engagement de l'IETF à agir après les révélations de Snowden, il n'a guère connu d'obstacles.
  • Le RFC 7816 a pris deux ans. Il a passé à peine plus d'un mois chez le RFC Editor, ce qui est très peu. Comme le précédent, il faisait partie d'un projet porteur, visant à améliorer le respect de la vie privée dans le DNS. Il a connu des objections techniques mais son statut « Expérimental » ne nécessite pas une solution parfaite. Une partie du temps a été passée dans un problème dont le RFC 8963 ne parle pas : une histoire de brevets et de négociations juridico-politiques.
  • Le RFC 8020 est le seul des trois à être sur le chemin des normes, en théorie bien plus exigeant. Mais il bat tous les records en n'ayant mis qu'un an à être publié. C'est en partie parce qu'il est simple, et relativement consensuel (il y a quand même eu des objections, par exemple sur le danger qu'il pouvait poser si la zone n'était pas signée avec DNSSEC).

Téléchargez le RFC 8963


L'article seul

RFC 8975: Network Coding for Satellite Systems

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : N. Kuhn (CNES), E. Lochin (ENAC)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF nwcrg
Première rédaction de cet article le 23 janvier 2021


Prenons de la hauteur (c'est le cas de le dire). Les communications via satellite posent des tas de problèmes techniques. L'envoi de chaque bit coûte cher, et dans certains cas d'usage, les pertes de paquets sont nombreuses, et on cherche donc à optimiser. Ce RFC explique comment on peut utiliser le network coding pour améliorer les performances de ces liaisons. Mais c'est encore un travail en cours.

Le network coding est un mécanisme d'encodage des données qui combine différentes données dans une même chaîne de bits, avant de les re-séparer à l'autre bout. Dans le cas le plus trivial on fait un XOR des données. Mais il y a d'autres moyens comme la convolution. Le network coding n'est pas un algorithme unique mais une classe de méthodes. Ces méthodes permettent de faire voyager davantage de données sur un même canal et/ou de diminuer le délai de transmission total, en ajoutant de la redondance. Le nom de network coding venait de l'encodage réalisé dans le réseau, pour tenir compte de sa topologie. Mais on peut utiliser des techniques du même genre de bout en bout (c'est le cas de FEC, dans le RFC 5052). (Je vous laisse en apprendre davantage sur Wikipédia). La question de l'encodage des données étant complexe, je vous renvoie également au RFC 8406 qui décrit le travail du groupe Network Coding de l'IRTF et définit les notions importantes.

Une idée de la latence dans une liaison satellite ? Le RFC observe que le RTT est typiquement de 0,7 secondes (deux passages par le satellite, la limite de la vitesse de la lumière, et le temps de traitement).

On peut se servir des satellites pour des tas de choses dans le domaine des télécommunications mais ce RFC se focalise sur l'accès à l'Internet par satellite, tel que normalisé par l'ETSI dans « Digital Video Broadcasting (DVB); Second Generation DVB Interactive Satellite System (DVB-RCS2); Part 2: Lower Layers for Satellite standard ». (Le RFC recommande également l'article de Ahmed, T., Dubois, E., Dupe, JB., Ferrus, R., Gelard, P., et N. Kuhn, « Software-defined satellite cloud RAN ».)

Le RFC décrit des scénarios où le network coding permet de gagner en capacité et en latence effective, en encodant plus efficacement les communications. Par exemple, en combinant le trafic de deux utilisateurs, on obtient parfois une quantité de données à transmettre qui est inférieure à celle de deux transmissions séparées, économisant ainsi de la capacité. Le RFC cite également l'exemple du multicast où, lorsqu'un des destinataires n'a pas reçu un paquet, on peut, pour éviter de faire attendre tout le monde, utiliser le network coding pour ré-envoyer les données en même temps que la suite du transfert. Là encore, la combinaison de toutes les données fait moins d'octets que lors de transmissions séparées. Cela pourrait s'adapter à des protocoles multicast comme NORM (RFC 5740) ou FLUTE (RFC 6726).

Le network coding permet également d'ajouter de la redondance aux données, sinon gratuitement, du moins à un « coût » raisonnable. Cela peut servir pour les cas de pertes de données comme le précédent. Un autre cas de perte est celui où la liaison satellite marche bien mais c'est tout près de l'utilisateur, par exemple dans son WiFi, que les paquets se perdent. Vu la latence très élevée des liaisons satellite, réémettre a des conséquences très désagréables sur la capacité effective (et sur le délai total). Une solution traditionnellement utilisée était le PEP (qui pose d'ailleurs souvent des problèmes de neutralité). Vous pouvez voir ici un exemple où le résultat est plutôt bon. Mais avec le chiffrement systématique, ces PEP deviennent moins efficaces. Cela redonne toute son importance au network coding.

Enfin, des pertes de paquets, avec leurs conséquences sur la latence car il faudra réémettre, se produisent également quand un équipement terminal passe d'une station de base à l'autre. Là encore, le network coding peut permettre d'éviter de bloquer le canal pendant la réémission.

Tout cela ne veut pas dire que le network coding peut être déployé immédiatement partout et va donner des résultats mirifiques. La section 4 du RFC décrit les défis qui restent à surmonter. Par exemple, les PEP (RFC 3135) ont toujours un rôle à jouer dans la communication satellitaire mais comment combiner leur rôle dans la lutte contre la congestion avec le network coding ? Faut-il réaliser cet encodage dans le PEP ? D'autre part, le network coding n'est pas complètement gratuit. Comme tout ajout de redondance, il va certes permettre de rattrapper certaines pertes de paquet, mais il occupe une partie du réseau. Et dans quelle couche ajouter cette fonction ? (Les couches hautes ont l'avantage de fenêtres - le nombre d'octets en transit - plus grandes, alors que les couches basses ne voient pas plus loin que le bout du paquet.)

Outre l'utilisation de satelittes pour la connectivité Internet des Terriens, il y a aussi une utilisation des communications spatiales pour échanger avec des vaisseaux lointains. La latence très élevée et l'indisponibilité fréquente de la liaison posent des défis particuliers. C'est ce qu'on nomme le DTN (Delay/Disruption Tolerant Network, décrit dans le RFC 4838). Le network coding peut aussi être utilisé ici, comme présenté dans l'article de Thai, T., Chaganti, V., Lochin, E., Lacan, J., Dubois, E., et P. Gelard, «  Enabling E2E reliable communications with adaptive re-encoding over delay tolerant networks ».

Et, comme le rappelle la section 9 du RFC, il faut aussi tenir compte du chiffrement, qui est évidemment obligatoire puisque les liaisons avec les satellites peuvent trop facilement être écoutées.

Merci à Nicolas Kuhn et Emmanuel Lochin pour leur relecture attentive, sans laquelle il y aurait bien plus d'erreurs. (Je me suis aventuré très en dehors de mon domaine de compétence.) Les erreurs qui restent sont évidemment de mon fait.


Téléchargez le RFC 8975


L'article seul

RFC 8972: Simple Two-Way Active Measurement Protocol Optional Extensions

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : G. Mirsky, X. Min (ZTE Corp), H. Nydell (Accedian Networks), R. Foote (Nokia), A. Masputra (Apple), E. Ruffini (OutSys)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 22 janvier 2021


Le protocole STAMP, normalisé dans le RFC 8762, est un protocole pour piloter des mesures de performance vers un réflecteur qui renverra les paquets de test. Ce nouveau RFC étend STAMP pour ajouter un identificateur de session, et la possibilité d'ajouter des tas d'options sous forme de TLV.

Commençons par l'identificateur de session. Une session STAMP est normalement identifiée par le tuple classique {protocole (forcément UDP), adresse IP source, adresse IP destination, port source, port destination}. Ce n'est pas toujours pratique donc notre RFC ajoute un identificateur explicite, le SSID (STAMP Session Identifier). Il fait deux octets et est choisi par l'envoyeur. Mais où le mettre dans le paquet ? Le format original prévoyait qu'une partie du paquet STAMP soit composée de zéros, et c'est dans cette partie qu'on logera le SSID. Donc, si, après l'estimation de l'erreur de mesure, on trouve deux octets qui ne sont pas nuls, c'est le SSID.

La section 4 liste les TLV qui peuvent désormais être ajoutés aux paquets STAMP. Ces TLV sont situés à la fin du paquet STAMP. Ils commencent par une série de bits qui indiquent si le réflecteur connait le TLV en question, et si le réflecteur a détecté des problèmes par exemple un TLV à la syntaxe incorrecte (cf. le registre IANA). Les principaux TLV sont :

  • Le type 1 permet de faire du remplissage, pour créer des paquets de la taille souhaitée,
  • Le type 2 demande au réflecteur des informations sur son adresse MAC et autres identificateurs,
  • Le type 3 demande une estampille temporelle (avec en prime indication de la méthode de synchronisation d'horloge utilisée, par exemple NTP),
  • Le type 8 permet de vérifier l'intégrité du paquet par HMAC (voir la section 6 du RFC pour les détails),
  • Etc.

Si cela ne suffit pas, d'autres types de TLV pourront être créés dans le futur et mis dans le registre IANA. La politique d'enregistrement (cf. RFC 8126) est « examen par l'IETF » pour la première moitié de la plage disponible et « premier arrivé, premier servi » ensuite.


Téléchargez le RFC 8972


L'article seul

RFC 8832: WebRTC Data Channel Establishment Protocol

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : R. Jesup (Mozilla), S. Loreto (Ericsson), M. Tuexen (Muenster Univ. of Appl. Sciences)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 19 janvier 2021


Ce RFC est un des composants de WebRTC. Il spécifie comment on établit le canal de communication des données entre deux pairs WebRTC.

WebRTC est résumé dans le RFC 8825 et la notion de « canal de communication de données » est dans le RFC 8831. Ces données sont protégées par DTLS et transportées en SCTP (RFC 8261).

Le principe est de connecter deux flux de données WebRTC, un entrant et un sortant, pour faire un seul canal bi-directionnel. Le protocole est simple, reposant sur seulement deux messages, un DATA_CHANNEL_OPEN envoyé sur le flux sortant, auquel le pair WebRTC répond par un DATA_CHANNEL_ACK qui va arriver sur le flux entrant. Pour éviter les ouvertures simultanées (un protocole à deux messages n'est pas très robuste), le client DTLS utilise des flux ayant un identificateur (stream identifier) pair, et le serveur des flux à identificateurs impairs. Le format de ces deux messages est décrit dans la section 5 du RFC.

Les paquets SCTP contiennent un PPID (Payload Protocol IDentifier, RFC 4960, section 3.3.1 et 14.4) qui indique le protocole applicatif qui utilise SCTP. Dans le cas de notre protocole d'établissement de canal WebRTC, DCEP (Data Channel Establishement Protocol), le PPID vaut 50 (et figure dans le registre IANA sous le nom de WebRTC DCEP).


Téléchargez le RFC 8832


L'article seul

RFC 8863: Interactive Connectivity Establishment Patiently Awaiting Connectivity (ICE PAC)

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : C. Holmberg (Ericsson), J. Uberti (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ice
Première rédaction de cet article le 19 janvier 2021


Le protocole ICE, normalisé dans le RFC 8445 permet de découvrir et de choisir, quand on est coincé derrière un routeur NAT, les adresses IP que vos correspondants verront. Parfois, au début du processus ICE, il n'y a pas d'adresses acceptables. Au lieu de renoncer tout de suite, ce nouveau RFC modifie le RFC 8445 pour demander qu'on patiente un peu : des adresses IP acceptables peuvent apparaitre par la suite.

Résumons le fonctionnement de base d'ICE. ICE sert lorsqu'une des deux machines qui correspondent a le malheur d'être derrière du NAT : le but est de choisir une paire d'adresses IP, pour les deux machines qui correspondent. ICE compte sur des protocoles comme STUN pour la découverte d'adresses possibles. Ensuite, il teste ces adresses et réussit lorsque la communication a pu s'établir avec l'autre machine. Un effet de bord de ce processus est qu'il « crée » parfois de nouvelles adresses IP possibles, qu'il faut donc ajouter à la liste et tester. Le problème que résout notre nouveau RFC est que ces nouvelles adresses peuvent être détectées trop tard, alors qu'ICE a déjà renoncé à trouver une paire qui marche. La solution ? Attendre un peu, même si la liste des paires candidates est vide, ou qu'aucune des paires d'adresses de la liste n'a marché.

La section 3 de notre RFC note que le problème n'est pas si fréquent en pratique car ICE est lent ; cela prend du temps d'établir la liste des paires d'adresses IP possibles, et de les tester, d'autant plus qu'on ne reçoit pas forcément tout de suite un rejet, il faut souvent attendre la fin du délai de garde. Bref, la plupart du temps, les nouvelles adresses apparaissant en cours de route auront le temps d'être intégrées à la liste des paires à tester. Il y a toutefois quelques cas où le risque d'échec complet existe. Par exemple, si une machine purement IPv6 essaie de contacter une machine purement IPv4, aucune paire d'adresses IP satisfaisante ne sera trouvée, menant ICE à renoncer tout de suite. Or, si le réseau local de la machine IPv6 avait NAT64, la connexion reste possible, il faut juste tester et apprendre ainsi qu'une solution existe. Cela demande un peu de patience.

La section 4 formalise la solution : un chronomètre global est créé, le PAC timer (PAC pour Patiently Awaiting Connectivity) et mis en route au tout début du processus ICE. ICE ne doit pas renoncer, même s'il croit ne plus avoir de solutions, avant que ce chronomètre n'ait mesuré au moins 39,5 secondes (cette durée vient du RFC 5389, section 7.2.1, mais peut être modifiée dans certains cas).


Téléchargez le RFC 8863


L'article seul

RFC 8831: WebRTC Data Channels

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : R. Jesup (Mozilla), S. Loreto (Ericsson), M. Tuexen (Muenster Univ. of Appl. Sciences)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 19 janvier 2021


Ce RFC décrit le canal de données (à l'exclusion de l'audio et de la vidéo) entre deux navigateurs Web se parlant avec WebRTC. Ce canal utilise le protocole de transport SCTP.

Le canal de données WebRTC est une modélisation d'un tuyau virtuel entre les deux parties qui communiquent, tuyau dans lequel circuleront les données. SCTP (RFC 4960) n'est pas utilisé pour les données « multimédia » comme la vidéo ou l'audio, mais seulement en cas de transfert d'autres données. On peut ainsi utiliser WebRTC pour se transmettre un fichier. (Je ne connais pas à l'heure actuelle de service WebRTC permettant cela. Vous avez un exemple ?) Le multimédia, lui, passe via SRTP, les données nécessitant une plus grande fiabilité passent par SCTP lui-même transporté sur DTLS (RFC 6347) lui même sur UDP. Du fait de cette encapsulation, vous ne verrez pas SCTP avec un logiciel comme Wireshark. La raison pour laquelle UDP est utilisé ? Permettre le passage des données même à travers le pire routeur NAT (cf. RFC 6951).

La section 3 de notre RFC décrit certains scénarios d'usage. Notons que dans certains, la fiabilité du canal de données n'est pas indispensable :

  • Un jeu en ligne, où on est informé des mouvements des autres joueurs,
  • Des notifications pendant une visioconférence du genre « Mamadou a coupé son micro »,
  • Des transferts de fichiers (pour l'anecdote, ce n'est pas le point où les systèmes précédant WebRTC, comme IRC ou XMPP, se débrouillaient le mieux…),
  • Le bavardage textuel entre les participants à une visioconférence.

La section 4, elle, décrit les exigences du canal de données. Notamment :

La section 5 décrit une solution à ces exigences, l'utilisation de SCTP sur DTLS. SCTP (RFC 4960) fournit (entre autres) le contrôle de congestion (par contre, on n'utilise pas ses capacités de multihoming). Son encapsulation dans DTLS est décrite dans le RFC 8261. DTLS lui fournit authentification et confidentialité. L'utilisation d'ICE (RFC 8445) lui permet de passer à travers les routeurs NAT et certains pare-feux.

Petit détail : le fait de mettre SCTP sur DTLS (et non pas le contraire comme dans le RFC 6083) fait que, si DTLS est mis en œuvre dans l'espace utilisateur du système d'exploitation, SCTP devra l'être aussi. (Voir par exemple third_party/usrsctp/usrsctplib dans le code de Chromium, qui vient de https://github.com/sctplab/usrsctp.) Autre conséquence de ce choix : SCTP ne recevra pas les messages ICMP associés, et il devra donc compter, pour la découverte de la MTU du chemin, sur le RFC 4821.

Quelques extensions de SCTP sont nécessaires (section 6) comme celles du RFC 6525, du RFC 5061 (enfin, une partie d'entre elles) et du RFC 3758.

La section 6 décrit les détails protocolaires de l'ouverture du canal de données, puis de son utilisation et enfin de sa fermeture.

Pour les programmeurs, cette bibliothèque WebRTC met en œuvre, entre autres, le canal de données.


Téléchargez le RFC 8831


L'article seul

RFC 8827: WebRTC Security Architecture

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : E. Rescorla (RTFM)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 19 janvier 2021


Le système WebRTC permet des communications audio et vidéo entre deux navigateurs Web. Comme tout service Internet, il pose des problèmes de sécurité (RFC 8826), et ce RFC étudie l'architecture générale de WebRTC, du point de vue de la sécurité, et comment résoudre les problèmes.

D'abord, il faut réviser les généralités sur WebRTC (RFC 8825). WebRTC a pour but de permettre à deux utilisateurs ou utilisatrices de navigateurs Web de s'appeler et de bavarder en audio et vidéo. Pas besoin d'installer un logiciel de communication spécifique (comme le Skype de Microsoft, ou comme un softphone tel que Twinkle), il suffit d'un navigateur ordinaire. Pour permettre cela, WebRTC repose sur une API JavaScript normalisée par le W3C et sur un ensemble de protocoles normalisés par l'IETF, et résumés dans le RFC 8825. Si on prend l'exemple du service WebRTC FramaTalk, Alice et Bob visitent tous les deux https://framatalk.org/, récupèrent du code JavaScript qui va utiliser l'API WebRTC pour accéder au micro et à la caméra, pendant que, derrière, FramaTalk va établir une communication entre eux, permettant à leurs navigateurs d'échanger du son et des images. Cet établissement de connexion (qui peut impliquer plusieurs serveurs, s'il y a fédération) n'est pas spécifié par WebRTC. (Il n'y a pas automatiquement d'interopérabilité entre services WebRTC.) Cela peut utiliser SIP (RFC 3261), par exemple.

Cela soulève plein de problèmes de sécurité amusants, étudiés dans le RFC 8826, et que notre RFC 8827 tente de résoudre.

Toute solution de sécurité dépend d'un modèle de confiance (section 3 de notre RFC). Si on ne fait confiance à rien ni personne, on ne peut résoudre aucun problème de sécurité. Pour WebRTC, la racine de toute confiance est le navigateur. C'est lui qui devra faire respecter un certain nombre de règles. (En conséquence de quoi, si le navigateur n'est pas de confiance, par exemple parce qu'il s'agit de logiciel non libre, ou bien parce que vous êtes sur une machine sur laquelle vous n'avez aucun contrôle, par exemple un cybercafé, tout est fichu.) Mais le navigateur ne suffit pas, il faut également faire confiance à des entités extérieures, comme le site Web où vous allez récupérer le code JavaScript. Certaines de ces entités peuvent être authentifiées par le navigateur, ce qui donne certaines garanties. Et d'autres, hélas, ne le peuvent pas. Dans la première catégorie, on trouve :

Le reste des entités avec qui on communique est considéré comme potentiellement malveillant, et il faut donc se méfier (mais, évidemment, dans la vie, on ne communique pas qu'avec des gens qu'on connait bien et à qui on fait confiance : ce serait trop limité).

Pour revenir aux entités authentifiées, notez qu'on n'a parlé que d'authentification, pas de confiance. La cryptographie permet de vérifier qu'on parle bien au diable, pas que le diable est honnête !

La section 4 résume le fonctionnement général de WebRTC, afin de pouvoir analyser sa sécurité, et définir une architecture de sécurité. Notez que WebRTC permet pas mal de variantes et que le schéma présenté ici est un cas « typique », pas forcément identique partout dans tous ses détails. Donc, ici, Alice et Bob veulent se parler. Tous les deux utilisent un navigateur. Chacun va visiter le site Web du service qu'ils utilisent, mettons https://meet.example/ (en HTTPS, donc, avec authentification via un certificat). Ils récupèrent un code JavaScript qui, appelant l'API WebRTC, va déclencher l'envoi d'audio et de vidéo, transportés sur SRTP, lui-même sur DTLS (les données en dehors du « multimédia » passent sur du SCTP sur DTLS). Avant d'autoriser l'accès au micro et à la caméra, chaque navigateur demandera l'autorisation à son utilisat·eur·rice. Quant au fait que la machine en face accepte de recevoir (en direct, en pair-à-pair) ce déluge de données multimédia, la vérification sera faite par ICE (cf. RFC 8826, section 4.2). ICE n'intervient qu'à la connexion initiale, des messages périodiques seront nécessaires pendant la communication pour s'assurer qu'il y a toujours consentement à recevoir. Pendant l'échange de données audio et vidéo, le site Web https://meet.example/ va assurer la signalisation et, par exemple, si Alice part, indiquer à Bob qu'il n'y a plus personne en face (notez que cet échange entre site Web et utilisateur ne se fait pas avec un protocole normalisé). Notre RFC ajoute une possibilité : qu'Alice et Bob utilisent un fournisseur d'identité, permettant à chacun d'identifier et d'authentifier l'autre (par exemple via OpenID Connect).

Ce cas où les deux participant·e·s partagent le même serveur est le cas le plus courant aujourd'hui (c'est ce que vous verrez si vous faites une visioconférence via https://meet.jit.si/). Le RFC le complique ensuite légèrement en introduisant de la fédération : Alice et Bob se connectent à des sites Web différents, mais qui ont un mécanisme de fédération commun. Les deux sites vont alors devoir s'échanger de l'information de signalisation, utilisant des protocoles existants comme SIP ou XMPP (qui n'étaient pas utilisés dans le cas initial).

Armés de ces informations, nous pouvons lire la section 6, qui plonge dans les détails techniques. D'abord, la securité de la connexion entre navigateur et site Web. Elle dépend de HTTPS (RFC 2818), de la vérification du certificat, bien sûr (RFC 6125 et RFC 5280) et de la vérification de l'origine (RFC 6454). La sécurité entre les pairs qui communiquent impose également l'usage de la cryptographie et il faut donc utiliser SRTP (RFC 3711) sur DTLS (RFC 6347 et RFC 5763). Pas question de faire du RTP en clair directement sur UDP ! Le niveau de sécurité (par exemple les paramètres TLS choisis) doivent être accessibles à l'utilisateur.

Ensuite, la securité de l'accès au micro et à la caméra. Le site Web qu'on visite peut être malveillant, et le navigateur ne permet évidemment pas à du code JavaScript de ce site d'ouvrir silencieusement la caméra. Il demande donc la permission à l'utilisateur, qui ne la donne que s'il était vraiment en train de passer un appel. De même, le navigateur doit afficher si micro et caméra sont utilisés, et ne doit pas permettre à du code JavaScript de supprimer cet affichage.

Dans WebRTC, l'échange des données audio et vidéo se fait en pair-à-pair, directement entre Alice et Bob. Il y a donc le risque qu'un méchant envoie plein de données vidéo à quelqu'un qui n'a rien demandé (la section 9.3 détaille le risque de déni de service). Il faut donc vérifier le consentement à recevoir. Comme indiqué plus haut, cela se fait avec ICE (RFC 8445). Comme le consentement initial n'est pas éternel, et comme on ne peut pas se fier aux accusés de réception, que DTLS n'envoie pas, ni aux réponses (il n'y en a pas forcément, par exemple si on regarde juste une vidéo), il faut envoyer de temps en temps des nouveaux messages ICE (cf. RFC 7675).

Parmi les questions de sécurité liées à WebRTC, il en est une qui a fait beaucoup de bruit, celle de la vie privée, notamment le problème de l'adresse IP qui est transmise au pair avec qui on communique. (Notez que le serveur du site Web où on se connecter initialement verra toujours, lui, cette adresse IP, sauf si on utilise une technique comme Tor.) Notre RFC impose donc, en cas d'appel entrant, de ne pas commencer la négociation ICE avant que l'utilisatrice n'ait décidé de répondre à l'appel, et que WebRTC permette de décider de n'utiliser que TURN, qui ne communique pas l'adresse IP au pair puisqu'on ne se parle plus directement, mais via le relais TURN. Évidemment, cela se fait au détriment des performances (les détails sont dans la section 9.2).

On a vu plus haut que les deux pairs qui communiquent peuvent désirer s'authentifier (sans se fier au site Web qu'ils utilisent pour la signalisation), par exemple via des fournisseurs d'identité externes (comme FranceConnect ?) C'est notamment indispensable pour une fédération puisque, dans ce cas, on n'a même plus de site Web commun. La section 7 de notre RFC détaille ce cas. WebRTC ne normalise pas une technique unique (comme OAuth) pour cela (WebRTC est un cadre, pas vraiment un protocole, encore moins un système complet), mais fixe quelques principes. Notamment, l'utilisateur s'authentifie auprès du fournisseur d'identité, pas auprès du site Web de signalisation. Le navigateur Web doit donc faire attention à tout faire lui-même et à ne pas laisser ce site Web interférer avec ce processus.

Enfin, il reste des problèmes de sécurité de WebRTC qui ne sont pas couverts par le RFC 8826 ni par les précédentes sections de notre RFC 8827. Ainsi, il est important que le code JavaScript téléchargé depuis le site Web du fournisseur de service WebRTC ne puisse pas directement fabriquer des messages chiffrés et signés pour DTLS, car il pourrait alors fabriquer de vraies/fausses signatures. Tout doit passer par le navigateur qui est le seul à pouvoir utiliser les clés de DTLS pour chiffrer et surtout signer.

Une bonne analyse de la sécurité de WebRTC se trouve en « A Study of WebRTC Security ».


Téléchargez le RFC 8827


L'article seul

RFC 8825: Overview: Real Time Protocols for Browser-Based Applications

Date de publication du RFC : Janvier 2021
Auteur(s) du RFC : H. Alvestrand (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 19 janvier 2021


WebRTC sert à faire communiquer en temps réel (avec audio et vidéo) deux navigateurs Web. Il est déjà largement déployé, ce RFC arrive bien après la bataille, et décrit les généralités sur WebRTC. Ce protocole est complexe et offre beaucoup de choix au concepteur d'applications.

En fait, WebRTC n'est pas vraiment un protocole. Deux applications utilisant WebRTC peuvent parfaitement être dans l'incapacité de communiquer. WebRTC est plutôt un cadre (framework) décrivant des composants, parmi lesquels le concepteur d'applications choisira. Vu cette complexité, ce RFC 8825 est un point de départ nécessaire, pour comprendre l'articulation des différents composants. D'ailleurs, il y a un abus de langage courant : WebRTC désigne normalement uniquement l'API JavaScript normalisée par le W3C. La communication sur le réseau se nomme rtcweb, et c'est le nom de l'ex-groupe de travail à l'IETF. Mais tout le monde fait cet abus de langage et moi aussi, j'utiliserai WebRTC pour désigner l'ensemble du système.

L'auteur du RFC est un « vieux de la vieille » et a vu passer beaucoup de protocoles. Il est donc logique qu'il commence par quelques rappels historiques en section 1. L'idée de faire passer de l'audio et de la vidéo sur l'Internet est aussi ancienne que l'Internet lui-même, malgré les prédictions pessimistes des telcos, qui avaient toujours prétendu que cela ne marcherait jamais. (La variante d'aujourd'hui est « si on ne nous laisse pas violer la neutralité du réseau, la vidéo ne marchera jamais ».)

Mais c'est vrai que les débuts ont été laborieux, la capacité du réseau étant très insuffisante, et les processeurs trop lents. Ça s'est amélioré par la suite. Mais si le matériel a progressé, les protocoles continuaient à manquer : il existe bien sûr des protocoles standards pour traiter certains aspects de la communication (comme SIPRFC 3261 - pour la signalisation) mais, pour une communication complète, il faut un jeu de protocoles couvrant tous les aspects, de la signalisation à l'encodage du flux vidéo, en passant par les identificateurs à utiliser (comme les adresses de courrier électronique), et qu'on puisse compter sur ce jeu, de même qu'on peut compter sur la disponibilité de clients et serveurs HTTP, par exemple. Comme le note l'auteur, « la Solution Universelle s'est avérée difficile à développer ». (Cela a d'ailleurs laissé un boulevard à des entreprises privées, proposant un produit très fermé et complètement intégré comme le Skype de Microsoft.)

Depuis quelques années, la disponibilité très répandue de navigateurs Web ayant des possibilités très avancées a changé la donne. Plus besoin d'installer tel ou tel plugin, telle ou telle application, désormais, les possibilités qu'offre HTML5 sont largement répandues, et accessibles en JavaScript via une API standard. Un groupe de travail du W3C développe de nouvelles possibilités et WebRTC peut donc être vu comme un effort commun du W3C et de l'IETF. C'est sur ces nouvelles possibilités du navigateur que se fonde WebRTC (son cahier des charges figure dans le RFC 7478).

Notre RFC note que WebRTC change pas mal l'architecture des techniques de communication temps-réel et multimédia. Autant les solutions fondées sur SIP comptaient sur des éléments intermédiaires dans le réseau pour travailler (par exemple des ALG), autant WebRTC est nettement plus « bout en bout », et utilise la cryptographie pour faire respecter ce principe, bien menacé par les FAI.

Question histoire, WebRTC a lui-même eu une histoire compliquée. La première réunion du groupe à l'IETF a eu lieu en 2011, pour une fin prévue en 2012. En fait, il y a eu des retards, et même une longue période d'arrêt du travail. Ce RFC de survol de WebRTC, par exemple, a vu sa première version publiée il y a huit ans. Le premier RFC du projet n'a été publié qu'en 2015. Globalement, ce fut l'un des plus gros efforts de l'IETF, mais pas le plus efficace en terme de rapidité. Le groupe de travail rtcweb a finalement été clos en août 2019, le travail étant terminé.

La section 2 de notre RFC résume les principes de WebRTC : permettre une communication audio, vidéo et données la plus directe possible entre les deux participants. Ce RFC 8825 est la description générale, les protocoles effectifs figurent dans d'autres RFC comme le RFC 8832 pour le protocole de création du canal de données ou le RFC 8831 pour la communication via le canal de données. Techniquement, WebRTC a deux grandes parties :

La section 2 décrit également le vocabulaire, si vous voulez réviser des concepts comme la notion de protocole ou de signalisation.

La section 3 de notre RFC présente l'architecture générale. Chaque navigateur WebRTC se connecte à un serveur Web où il récupère automatiquement un code JavaScript qui appelle les fonctions WebRTC, qui permettent d'accéder au canal de données, ouvert avec l'autre navigateur, et aux services multimédia de son ordinateur local (le micro, la caméra, etc). On y voit notamment (figure 2) que les données (la voix, la vidéo, etc) passent directement (enfin, presque, voir plus loin) entre les deux navigateurs, alors que la signalisation se fait entre les deux serveurs Web. On note, et c'est très important, que WebRTC ne gère que le canal de données, pas celui de signalisation, qui peut utiliser SIP (RFC 3261), XMPP (RFC 6120) ou même un protocole privé. C'est entre autres pour cette raison que deux services WebRTC différents ne peuvent pas forcément interopérer. Voici un schéma de WebRTC lorsque les deux parties se connectent au même site Web (la signalisation est alors faite à l'intérieur de ce site) : webrtc-centralized.png

Et ici une image d'une fédération, où les deux parties qui communiquent utilisent des services différents, mais qui se sont mis d'accord sur un protocole de signalisation : webrtc-federated.png

Le canal de données nécessite déjà beaucoup de spécifications, notamment le transport et l'encodage du contenu. Il est spécifié dans le RFC 8831.

Le transport, justement (section 4 du RFC). Il faut envoyer les données à l'autre navigateur, et assurer la retransmission des données perdues, le contrôle de congestion, etc. Tout cela est décrit dans le RFC 8835. Ce RFC spécifie, pour transporter les données multimédia, l'utilisation de SRTP sur DTLS, lui-même sur UDP (cf. RFC 8834). Des systèmes de relais comme TURN (RFC 5766) peuvent être nécessaires si les deux malheureux navigateurs Web soint coincés derrière des middleboxes méchantes, NAT ou pare-feu par exemple.

Ce n'est pas tout d'avoir un protocole de transport. Il faut aussi découper les données d'une manière compréhensible par l'autre bout (framing, section 5 de notre RFC). WebRTC utilise RTP (RFC 3550, et voir aussi le RFC 8083) et SRTP (RFC 3711 et RFC 5764). Le RFC 8834 détaille leur utilisation. La sécurité est, elle, couverte dans les RFC 8826 et RFC 8827. L'établissement du canal de données est normalisé dans le RFC 8832 et le canal de données lui-même dans le RFC 8831.

On le sait, les formats d'audio et de vidéo sont un problème compliqué, le domaine est pourri de brevets souvent futiles, et la variété des formats rend difficile l'interopérabilité. Notre RFC impose au minimum l'acceptation des codecs décrits dans le RFC 7874 pour l'audio (Opus est obligatoire) et RFC 7742 pour la vidéo (H.264 et VP8, après une longue lutte). D'autres codecs pourront s'y ajouter par la suite.

La section 7 mentionne la gestion des connexions, pour laquelle la solution officielle est le JSEP (JavaScript Session Establishment Protocol, RFC 8829).

La section 9 du RFC décrit les fonctions locales (l'accès par le navigateur aux services de la machine qui l'héberge). Le RFC rappelle que ces fonctions doivent inclure des choses comme la suppression d'écho, la protection de la vie privée (demander l'autorisation avant d'accéder à la caméra…) Le RFC 7874 fournit des détails. Ici, un exemple d'une demande d'autorisation par Firefox : webrtc-auth.png

Parmi les logiciels qui permettent de faire du WebRTC, on peut citer Jitsi, qui est derrière le service Framatalk, mais qui est également accessible via d'autres services comme https://meet.jit.si/.

Regarder du trafic WebRTC avec un logiciel comme Wireshark est frustrant, car tout est chiffré. Pour Jitsi, on voit beaucoup de STUN, pour contourner les problèmes posés par le NAT, puis du DTLS évidemment impossible à décrypter.

Il y a de nombreux autres logiciels avec WebRTC. C'est le cas par exemple de PeerTube mais attention, seul l'échange de vidéo entre pairs qui regardent au même moment utilise WebRTC (plus exactement WebTorrent, qui utilise WebRTC). La récupération de la vidéo depuis le serveur se fait en classique HTTPS.

Si vous voulez voir une session WebRTC, le mieux est d'utiliser un service comme https://appr.tc/, qui journalise tout, et d'activer la console de Firefox. Vous voyez alors :

Console (Webdeveloper tools) Firefox
9.569: Initializing; server= undefined.
    

Puis l'établissement des canaux nécessaires :

37.252: Opening signaling channel.
39.348: Joined the room.
39.586: Retrieved ICE server information.
39.927: Signaling channel opened.
39.930: Registering signaling channel.
39.932: Signaling channel registered.
    

Là, Firefox vous demande l'autorisation d'utiliser micro et caméra, que vous acceptez :

44.452: Got access to local media with mediaConstraints:
  '{"audio":true,"video":true}'
44.453: User has granted access to local media.
    

Le navigateur peut alors utiliser ICE (RFC 8445) pour trouver le bon moyen de communiquer avec le pair (dans mon test, les deux pairs étaient sur le même réseau local, et s'en aperçoivent, ce qui permet une communication directe par la suite) :

44.579: Creating RTCPeerConnnection with:
  config: '{"rtcpMuxPolicy":"require","bundlePolicy":"max-bundle","iceServers":[{"urls":["stun:74.125.140.127:19302","stun:[2a00:1450:400c:c08::7f]:19302"]},{"urls":["turn:74.125.140.127:19305?transport=udp","turn:[2a00:1450:400c:c08::7f]:19305?transport=udp","turn:74.125.140.127:19305?transport=tcp","turn:[2a00:1450:400c:c08::7f]:19305?transport=tcp"],"username":"CP/Bl+UXXXXXXX","credential":"XXXXXXXXXXX=","maxRateKbps":"8000"}],"certificates":[{}]}';
  constraints: '{"optional":[]}'.
44.775: Created PeerConnectionClient
    

On peut alors négocier les codecs à utiliser (ici VP9) :

44.979: Set remote session description success.
44.980: Waiting for remote video.
44.993: No preference on audio receive codec.
44.993: Prefer video receive codec: VP9
    

Et, ici, on voit passer le descripteur de session (section 7 de notre RFC), au format SDP (RFC 4566 et RFC 3264, et notez la blague entre SDP et le film 300) :

    
44.997: C->WSS: {"sdp":"v=0\r\no=mozilla...THIS_IS_SDPARTA-60.5.1 6947646294855805442 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=fingerprint:sha-256 23:80:53:8A:DD:D7:BF:77:B5:C7:4E:0F:F4:6D:F2:FB:B8:EE:59:D1:91:6A:F5:21:11:22:C0:E3:E0:ED:54:39\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 126\r\nc=IN IP4 0.0.0.0\r\na=sendrecv\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:111 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:126 0-15\r\na=ice-pwd:bb7169d301496c0119c5ea3a69940a55\r\na=ice-ufrag:3d465335\r\na=mid:0\r\na=msid:{d926a161-3011-48af-9236-06e15377dfea} {a2597b07-7e80-47fe-8542-761dd93efb94}\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:126 telephone-event/8000/1\r\na=setup:active\r\na=ssrc:2096893919 cname:{e60fd6dc-6c2d-4132-bb6a-1178e1611d16}\r\nm=video 9 UDP/TLS/RTP/SAVPF 98\r\nc=IN IP4 0.0.0.0\r\na=recvonly\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:98 max-fs=12288;max-fr=60\r\na=ice-pwd:bb7169d301496c0119c5ea3a69940a55\r\na=ice-ufrag:3d465335\r\na=mid:1\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-mux\r\na=rtpmap:98 VP9/90000\r\na=setup:active\r\na=ssrc:4025254123 cname:{e60fd6dc-6c2d-4132-bb6a-1178e1611d16}\r\n","type":"answer"}

Et c'est bon, tout marche :

45.924: Call setup time: 1399ms.
   

Du fait de son caractère pair-à-pair (les données sont échangées, autant que le NAT le permet, directement entre les navigateurs), WebRTC soulève des questions de vie privée. Votre correspondant va voir votre adresse IP. Le point est discuté plus longuement dans le RFC 8826. (PeerTube met en bas un mot d'avertissement à ce sujet.)

WebRTC est présent depuis pas mal d'années dans tous les navigateurs graphiques comme Firefox, Chrome ou Edge. Côté bibliothèques, il existe de nombreuses mises en œuvre de WebRTC comme OpenWebRTC (abandonné depuis) ou comme l'implémentation de référence. Il y a également du WebRTC dans des serveurs comme Asterisk, WebEx ou MeetEcho (ce dernier étant utilisé par l'IETF pour ses réunions à distance). Mais rappelez-vous que WebRTC n'est pas un ensemble cohérent permettant l'interopérabilité. Vous pouvez avoir deux services WebRTC qui n'arrivent pas à interagir, et ce n'est pas une bogue, c'est un choix de conception.

Et, pour finir, quelques lectures et activités supplémentaires :


Téléchargez le RFC 8825


L'article seul

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 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

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

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.