Les RFC (Request For Comments) sont les documents de référence de l'Internet. Produits par l'IETF pour la plupart, ils spécifient des normes, documentent des expériences, exposent des projets...
Leur gratuité et leur libre distribution ont joué un grand rôle dans le succès de l'Internet, notamment par rapport aux protocoles OSI de l'ISO organisation très fermée et dont les normes coûtent cher.
Je ne tente pas ici de traduire les RFC en français (un projet pour cela existe mais je n'y participe pas, considérant que c'est une mauvaise idée), mais simplement, grâce à une courte introduction en français, de donner envie de lire ces excellents documents. (Au passage, si vous les voulez présentés en italien...)
Le public visé n'est pas le gourou mais l'honnête ingénieur ou l'étudiant.
Date de publication du RFC : Octobre 2016
Auteur(s) du RFC : T. King, C. Dietzel (DE-CIX
Management), J. Snijders
(NTT), G. Doering (SpaceNet
AG), G. Hankins (Nokia)
Pour information
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 20 octobre 2016
Lorsqu'on est soumis à une sérieuse attaque par déni
de service volumétrique, il faut parfois sacrifier la
machine qui en est la cible, afin de préserver le reste des
ressources réseau. On demande alors à son opérateur de jeter le
trafic à destination de cette machine, avant qu'il n'emprunte la
liaison qu'on veut préserver. Cela peut se faire manuellement mais
c'est évidemment plus rapide et moins risqué si on le fait
automatiquement, via une annonce BGP vers
le préfixe visé. Pour
cela, on marque l'annonce BGP avec une
communauté (RFC 1997)
qui veut dire « poubelle donc tout ce trafic ». Ce nouveau
RFC normalise une communauté standard,
« bien connue », pour cela, BLACKHOLE
(0xFFFF029A). Ainsi, il n'y aura plus besoin d'utiliser une
communauté différente pour chaque opérateur.
Cette méthode consistant à envoyer le trafic destiné à la victime vers un « trou noir » (blackholing) est décrite dans les RFC 3882 et RFC 5635. Comme elle agit au niveau IP, elle ne nécessite pas d'équipements spéciaux, et elle est très rapide, ne prenant que peu de ressources chez les routeurs. Par contre, elle est peu subtile : tout le trafic à destination d'un préfixe donné (préfixe en général réduit à une seule adresse IP, celle de la machine attaquée) est jeté, qu'il fasse partie de l'attaque ou pas. Quel est l'intérêt de couper tout le trafic ? Cela réalise l'objectif de l'attaquant, non ? C'est en effet une mesure désespérée mais rationnelle : son but est de préserver les ressources réseau pour que les autres machines fonctionnent. Si vous êtes connecté à l'Internet par une liaison à 10 Gb/s, et qu'une attaque de 20 Gb/s frappe votre opérateur, votre ligne va être complètement inutilisable. Aucune action de votre côté n'y changerait rien, dès que les paquets sont arrivés chez vous, c'est trop tard. Ce RFC traite le cas où on demande à l'opérateur de jeter le trafic avant qu'il ne soit envoyé sur la ligne entre l'opérateur et vous.
Le problème (section 1 du RFC) est qu'il existait plusieurs méthodes pour déclencher cet envoi dans un trou noir, ce qui compliquait la tâche des équipes réseau, une annonce BGP marquée avec une certaine communauté, une annonce BGP avec un certain next hop, et des méthodes non-BGP (dont le coup de téléphone au NOC). D'où la solution de notre RFC, définir une communauté standard. Plus besoin de se poser de question (à part celle de savoir si votre opérateur accepte cette commande, voir les sections 3.3 et 4). Au passage, les communautés BGP sont décrites dans le RFC 1997.
Une communauté BLACKHOLE
est donc définie
(section 2)
et mise dans le registre IANA des
communautés bien connues. Sa valeur est 0xFFFF029A. Le 666 à la
fin vient de la Bible et
était déjà couramment employé par les opérateurs. Notez donc que
ce RFC n'invente pas une nouvelle technique (demander à son pair
de jeter certains paquets est une technique très ancienne), il lui
donne juste une communauté standard.
Voilà, c'est tout, juste une réservation d'un nom et d'une
valeur. Si vous êtes intéressés par les détails pratiques, la
section 3 est consacrée aux problèmes opérationnels. D'abord, un
point essentiel : accepter des annonces BGP étiquetées
BLACKHOLE
est un choix local. Aucun opérateur
n'est obligé de respecter cette demande et, dans ce cas, ladite
communauté est ignorée. Lorsqu'on se connecte à
un nouveau pair BGP, il peut donc être prudent de lire leur
documentation ou de leur poser la question. N'utilisez
BLACKHOLE
qu'entre des adultes
consentants. (Notez que cet avertissement du RFC est un peu
contradictoire avec l'avantage proclamé de la normalisation de
BLACKHOLE
: en pratique, on est toujours
obligé de savoir ce que fait son pair, on ne peut pas compter sur
une méthode standard qui marcherait partout.) Une liste des
opérateurs et points d'échange qui acceptent
BLACKHOLE
est disponible
en ligne.
Si tout le monde accepte BLACKHOLE
, on
s'en sert comment ? Lorsqu'une attaque DoS
est en cours, on annonce un préfixe qui couvre l'adresse IP visée,
et on y ajoute cette communauté. On peut aussi utiliser
BLACKHOLE
pour les annonces du RFC 5635 (mais pas avec celles du RFC 5575).
Attention à ne pas propager ces annonces ! En effet, étant en
général très spécifiques (souvent une seule adresse IP), elles
seraient préférées, si elles étaient insérées dans une table de
routage. Leur effet est prévu
pour être strictement local et, donc, les annonces doivent être marquées avec la
communauté NO_EXPORT
(ou
NO_ADVERTISE
).
En parlant de spécificité, quelle doit être la longueur des
préfixes annoncés avec un BLACKHOLE
attaché ?
Souvent, l'attaque ne vise qu'une seule adresse et, donc, les
annonces BLACKHOLE
seront souvent des /32 (en
IPv4) et /128 (en IPv6), afin de ne sacrifier que le strict
minimum de son réseau. Si vous avez une politique BGP de n'accepter
que des préfixes plus généraux, c'est un point à
modifier. Aujourd'hui (RFC 7454, section
6.1.3), les préfixes plus spécifiques que /24 (IPv4) et /48 (IPv6)
sont rarement acceptés. Il faut donc faire des exceptions pour les
trous noirs.
Lorsqu'un opérateur reçoit une de ces annonces « envoie-moi
tout ça dans un trou noir », que doit-il vérifier ? Comme le
résultat de cette annonce est de jeter tout le trafic, une attaque
avec une annonce mensongère, ou bien une erreur d'un opérateur
maladroit, pourrait avoir de sérieuses conséquences. Notre RFC
recommande donc un certain nombre de tests de vraisemblance :
vérifier que le pair est autorisé à annoncer un préfixe couvrant
celui qu'il annonce avec BLACKHOLE
, et
vérifier que BLACKHOLE
avec ce pair a été
spécifiquement permis (le RFC recommande plus loin que ce ne soit
pas permis par défaut). Même chose s'il y a des
serveurs de route (RFC 7947) sur le trajet.
Par contre, il faut, pour le cas spécifique des annonces
BLACKHOLE
, débrayer les techniques de
validation comme celle du RFC 6811. Par
exemple, si un ROA (Route Origin Authorisation, RFC 6482) autorise une longueur maximale de préfixe de /48,
l'annonce BLACKHOLE
de longueur /128 doit
quand même être acceptée.
À des fins de traçabilité, pour faciliter l'analyse a
posteriori d'une attaque, et du traitement qu'elle a reçu, le RFC
recommande de journaliser toutes les
annonces BLACKHOLE
. (Cela permettra, par
exemple, de repérer les pairs qui abusent du mécanisme,
cf. section 6.)
Si vous travaillez chez un éditeur de logiciels pour routeurs,
n'oubliez pas les conseils de la section 4, destinés aux
programmeurs. D'abord, l'acceptation des annonces « trou noir » ne
devrait pas être faite par défaut. Le RFC demande qu'une action
explicite de l'administrateur réseau soit nécessaire. D'autre
part, pour ne pas
avoir à taper la valeur numérique de cette communauté, le RFC
suggère de permettre une valeur texte à indiquer, par exemple
blackhole
.
Quelques petits points sur la sécurité pour finir (section
6). D'abord, bien se rappeler que BGP n'a par défaut aucun
mécanisme pour empêcher ou détecter les modifications des
annonces. Si un attaquant actif retire ou ajoute la communauté
BLACKHOLE
, ça ne se voit pas. Même le futur
BGPSec ne l'empêchera pas, puisqu'il ne protège pas les
communautés. Il y a donc des possibilités d'attaques par déni de
service de ce côté.
C'est entre autre pour cela que le RFC demande qu'on vérifie
qu'un pair qui annonce un préfixe avec
BLACKHOLE
est autorisé à le faire (RFC 7454, section 6.2.1.1.2).
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : P. Hoffman (ICANN), J. Hildebrand (Cisco)
Pour information
Première rédaction de cet article le 16 décembre 2016
Depuis la sortie du RFC 7990, le format canonique des RFC est le format XML. C'est un texte écrit en XML, selon le vocabulaire du RFC 7991 qui sera la version de référence, archivée et faisant autorité, pour tous les RFC. Comme les auteurs enverront souvent un XML imparfait, un outil de préparation sera nécessaire, pour compléter ce XML imparfait et permettre au RFC Editor de travailler sur une base sérieuse. Ce nouveau RFC décrit ce futur outil de préparation.
Ainsi, les outils qui travailleront sur le format canonique des RFC (par exemple les outils qui produiront le PDF, le HTML, etc) pourront compter sur un document complet et n'auront pas à gérer les écarts des auteurs : seul l'outil de préparation devra s'en soucier.
Cet outil de préparation servira aux RFC une fois qu'ils seront soumis au RFC production center (cf. RFC 8728) mais aussi aux Internet-Drafts pendant leur élaboration.
Dans le second cas (section 3 de notre RFC), le futur outil de préparation prendra un Internet-Draft en entrée et produira un document complet (par exemple avec addition des boilerplates).
Et ce sera à peu près la même chose lorsque le RFC sera presque fini. On passera la version finale dans l'outil de préparation, qui résoudra les références externes et ajoutera les éléments obligatoires manquants.
Bon, et en quoi vont consister exactement ces modifications ? Elle sont décrites dans la section 5, qui forme le gros de ce RFC. Contrairement à l'outil actuel idnits qui se contente de vérifier les Internet-Drafts, le nouvel outil va également corriger le texte, ajoutant des éléments, et changeant les valeurs erronées.
C'est ainsi que l'outil de préparation va traiter les éléments
XInclude, les remplaçant par la valeur
incluse. Il va traiter les DTD pour les
supprimer ensuite (donc, remplacer les entités par leur valeur, et
inclure les fichiers inclus par ce mécanisme). Ces deux actions
peuvent aujourd'hui être faites par l'outil
xmllint, avec xmllint --xinclude
--noent --dropdtd NOMDUFICHIER.xml
.
Outre ces mécanismes d'inclusion de XML, l'outil de préparation
va aussi traiter les inclusions spécifiques au vocabulaire du RFC 7991. Ainsi,
<artwork>
a un attribut
src
indiquant la source du graphique, et
l'outil de préparation va donc inclure ce graphique. (Idem avec
<sourcecode>
pour inclure le code source.)
Les instructions XML (PI, Processing Instructions) seront supprimées (ça, je ne sais pas le faire avec xmllint).
L'outil va valider le résultat produit, en utilisant la grammaire Relax NG du RFC 7991. Ça peut aujourd'hui se faire avec xmllint mais aussi avec rnv :
% rnv rfc-v3.rnc rfc-v3-sample.xml rfc-v3-sample.xml
ou bien avec jing :
% java -jar ./jing-20091111/bin/jing.jar -c rfc-v3.rnc rfc-v3-sample.xml
Parmi les nombreuses transformations possibles, citons l'ajout
(s'il n'était pas déjà présent) de l'élément
<seriesInfo>
qui indique s'il s'agit
d'un Internet-Draft ou d'un RFC, l'ajout d'un
élément <date>
s'il manque (sa valeur
étant la date du traitement), changement de l'ancien attribut
title
en name
, le
retrait des
commentaires XML...
Il est fréquent dans les Internet-Drafts de
voir des paragraphes qui ne devront pas être inclus dans le futur
RFC. C'est le cas s'ils contiennent des exemples réels qui
risquent de ne pas être éternels (les RFC peuvent durer longtemps
et ne sont jamais modifiés). C'est également le cas s'il s'agit de
l'état actuel des mises en œuvre d'un RFC, comme décrit dans le
RFC 7942. Dans le système actuel, ces
paragraphes sont marqués par un texte en langue naturelle. Dans le
nouveau vocabulaire du RFC 7991, ce sera
fait avec un attribut removeInRFC
. L'outil de
préparation pourra enlever automatiquement ce paragraphe quand il
préparera un RFC.
L'outil de prépartion devra également arranger le XML. Cela peut se
faire aujourd'hui avec xmllint (ses options
--format
ou bien
--pretty
). Par contre, il n'est pas prévu de
mettre le XML sous sa forme canonique.
Il y aura d'autres opérations faites par l'outil de préparation, voir le RFC pour les détails.
L'outil n'est pas encore développé, un appel d'offres a été lancé et les gagnants ont été les sociétés SeanTek et Elf Tools.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : H. Flanagan (RFC Editor)
Pour information
Première rédaction de cet article le 16 décembre 2016
Les RFC sont forcément écrits en anglais, qui restera la langue officielle (cf. RFC 7322). L'anglais peut s'écrire avec uniquement les caractères ASCII (avec quelques exceptions : resume et résumé ne sont pas le même mot). Mais on pourra désormais inclure des caractères non-ASCII, par exemple pour le nom des auteurs (chic, je pourrais écrire correctement mon prénom dans les RFC). Cette possibilité permettra aussi aux exemples de protocoles Internet utilisant Unicode (la grande majorité) d'être plus lisibles.
Cette nouvelle possibilité fait partie de celles qu'offre le nouveau format des RFC, décrit dans le RFC 7990. Il n'y a quand même pas d'autorisation générale d'inclure n'importe quel caractère Unicode dans les RFC, à n'importe quel endroit. Le RFC Editor pourra toujours refuser tel ou tel caractère, par exemple parce qu'il n'existe pas de police permettant de l'afficher. Et le « non-ASCII » n'est autorisé que dans certains cas, décrits plus loin. La grande majorité du texte sera donc du pur ASCII (RFC 20).
Il ne suffit pas de proclamer « on a droit à Unicode ». Il faut aussi adapter les outils. Par exemple, notre RFC impose (section 2) que les outils de recherche dans les RFC gèrent correctement la recherche Unicode. (C'est pour traiter le cas des outils imparfaits que le RFC demande aussi que les noms d'auteurs en Unicode soient accompagnés d'une version en ASCII.) Et que le RFC soit affichable correctement sur un bon nombre de plate-formes (d'où la possibilité de rejeter les caractères les plus rares).
Ce problème du repli (vers une version en ACSII pur) est souvent cité dans le RFC. Ainsi, lorsqu'on veut mentionner un caractère Unicode (mettons le thorn islandais), le RFC permet désormais de l'afficher proprement, mais il demande qu'on l'accompagne du numéro du point de code, et, si possible, de son nom Unicode. Cela donnerait, par exemple « For instance, U+00FE, "LATIN SMALL LETTER THORN", þ, is interesting because... ». Notez que cette façon de désigner des caractères Unicode que tout le monde n'arrivera pas forcément à afficher n'est pas vraiment standardisée. Dans les RFC actuels, on trouve des variantes (voir cette discussion). Le RFC contient plusieurs exemples sur la façon d'écrire la phrase « Temperature changes in the Temperature Control Protocol are indicated by the U+2206 character (∆, "INCREMENT") », tous acceptés (le nom Unicode n'est pas obligatoire, il peut être placé avant ou après le caractère lui-même, etc.) Autre cas, ce texte du RFC 8264, « For example, the characters U+13DA U+13A2 U+13B5 U+13AC U+13A2 U+13AC U+13D2 from the Cherokee block look similar to the ASCII characters "STPETER" » deviendrait « For example, the characters U+13DA U+13A2 U+13B5 U+13AC U+13A2 U+13AC U+13D2 (ᏚᎢᎵᎬᎢᎬᏒ) from the Cherokee block look similar to the ASCII characters "STPETER" ». Des tables comme celles des identificateurs et mots de passe Unicode légaux (RFC 8265) seraient ainsi bien plus lisibles.
Pour les noms, par exemple ceux des auteurs. On aurait du « non-ASCII » et un texte de repli, comme (en utilisant le vocabulaire XML du RFC 7991) :
<author fullname="רוני אבן" asciiFullname="R. Even"/> <author fullname="吴钦" asciiFullname="Q. Wu"/> <author fullname="J. Smith" asciiFullname="J. Smith"/> <!-- Oui, dans ce cas, il faut le dire deux fois -->
Cela permettra enfin d'écrire correctement les noms des auteurs de RFC.
La bibliographie d'un RFC est également un bon endroit où mettre des caractères Unicode, par exemple lorsqu'on cite des textes non-anglo-saxons. Ainsi, la bibliographie du RFC 5933 pourrait inclure :
[GOST3410] "Information technology. Cryptographic data security. Signature and verification processes of [electronic] digital signature.", GOST R 34.10-2001, Gosudarstvennyi Standard of Russian Federation, Government Committee of Russia for Standards, 2001. (In Russian) "Информационная технология. Криптографическая защита информации. Процессы формирования и проверки электронной цифровой подписи", GOST R 34.10-2001, Государственный стандарт Российской Федерации, 2001.
Le second texte étant l'original russe.
Les règles exactes figurent dans la section 3. D'abord, on peut mettre du « non-ASCII » comme on veut quand il fait partie d'un exemple. Ainsi, la communication XMPP pourrait être décrite de manière plus naturelle. Au lieu de cet exemple de communication en tchèque (RFC 6121) :
<message from='juliet@example.com/balcony' id='z94nb37h' to='romeo@example.net' type='chat' xml:lang='en'> <body>Wherefore art thou, Romeo?</body> <body xml:lang='cs'> PročeŽ jsi ty, Romeo? </body> </message>
On pourra écrire la forme lisible :
<message from='juliet@example.com/balcony' id='z94nb37h' to='romeo@example.net' type='chat' xml:lang='en'> <body>Wherefore art thou, Romeo?</body> <body xml:lang='cs'> PročeŽ jsi ty, Romeo? </body> </message>
Ensuite, on peut utiliser le « non-ASCII » pour les cas cités plus haut (noms d'auteurs, textes non-anglophones dans la bibliographie, etc). Pour les exemples utilisant un langage de programmation, notre RFC spécifie qu'il faut suivre les règles du langage en question. Ainsi, Python 3 autorisant l'Unicode même dans les noms de variables, on peut écrire :
a = "chocolat" b = "café" # Accentué ç = "lait" print(a+b+ç)
Enfin, un petit mot sur la normalisation Unicode, pour rappeler que le format des RFC ne garantit rien à ce sujet (on aurait pu décider que NFC serait systématiquement utilisée...) et que les auteurs de RFC ne doivent donc pas compter dessus.
Le premier RFC publié avec des caractères Unicode a été le RFC 8187, en septembre 2017.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : N. Brownlee (University of Auckland)
Pour information
Première rédaction de cet article le 16 décembre 2016
Dans la longue liste de RFC décrivant le nouveau format des RFC (commencez par le RFC 7990), ce document décrit l'utilisation de SVG pour faire (enfin) des graphiques dans les RFC.
Traditionnellement, en effet, seul le texte était possible dans
les RFC. (On pouvait toutefois faire des
graphiques en art ASCII, dont on imagine
bien que ce n'était ni très pratique à écrire - malgré l'excellent
mode Emacs picture-mode
,
ni très facile à lire.) Il y avait de bonnes raisons à cet état de
fait, notamment le manque d'un format d'images ouvert et largement
répandu. Je parle bien sûr d'images
vectorielles car, a priori, dans un RFC, il
y aura beaucoup plus de schémas que de photos.
Le processus de décision a été long et compliqué. En 2013, le RFC 6949 notait déjà la décision de permettre des images, en indiquant « Graphics may include ASCII art and a more complex form to be defined, such as SVG line art ». C'est désormais possible. Au fait, c'est quoi, SVG ? Il s'agit d'une norme d'un format d'images vectoriel, gérée par le W3C, et fondée sur XML. Voici un exemple d'un simple dessin en SVG :
<svg xmlns="http://www.w3.org/2000/svg" version="1.2"> <rect x="25" y="25" width="200" height="200" fill="white" stroke-width="4" stroke="black" /> <circle cx="125" cy="125" r="75" fill="black" /> <polyline points="50,150 50,200 200,200 200,100" stroke="black" stroke-width="4" fill="none" /> <line x1="50" y1="50" x2="200" y2="200" stroke="white" stroke-width="4" /> </svg>
Et voici son rendu :
Les RFC n'utiliseront qu'un sous-ensemble de SVG, spécifié ici. Il existe d'autres sous-ensembles de SVG comme SVG Tiny, prévu pour des équipements contraints, genre smartphones. Ce SVG Tiny a servi de base au SVG des RFC, sous-ensemble limité car on n'attend pas de dessins artistiques et compliqués dans les RFC.
SVG RFC est donc SVG Tiny moins les éléments permettant le multimédia et l'animation (pas de vidéos dans les RFC), l'interaction (pas d'interface utilisateur active dans un RFC), l'utilisation de langages de programmation (pas de JavaScript actif dans un RFC). Plusieurs autres restrictions ont été apportées : pas de couleur (RFC 6949, section 3.2), pas d'IRI, seulement des URI, et pas de choix arbitraire de police.
Comment on écrit du SVG ? S'il est évidemment possible de le faire entièrement à la main avec un éditeur ordinaire, gageons que peu de gens le tenteront. Notre RFC cite des éditeurs graphiques, produisant du SVG, comme les logiciels libres Inkscape et Dia. (Et, si on aime programmer en Python, il y a svgwrite, que je présente plus en détail à la fin.) Attention, Inkscape et Dia produisent du SVG généraliste, pas du SVG RFC, qui est plus restreint. (Je ne connais personnellement pas d'outil pour produire du SVG RFC, ou pour « réduire » un fichier SVG généraliste en enlevant tout ce qui n'appartient pas à SVG RFC. Un tel outil était prévu mais je ne sais pas où il en est. C'était une des fonctions attendues du futur svgcheck.)
Et l'accessibilité (section 4) ? Il est crucial que les RFC soient accessibles à tou·te·s, non seulement que que soit le matériel utilisé, mais également quels que soient les handicaps dont souffre leur propriétaire. C'est bien joli de vouloir ajouter des tas de choses dans les RFC mais encore faut-il ne pas creuser ainsi davantage le fossé entre les utilisateurs. Ainsi, accepter de la couleur (le RFC 6949 limite les futurs RFC au noir et blanc) fait courir le risque que les daltoniens ne puissent pas comprendre un RFC. De même, les graphiques, qui ont l'air comme ça d'être une bonne idée, peuvent aggraver la situation des malvoyants. Le texte seul peut toujours être lu à voix haute par un synthétiseur de parole mais pas le graphique. Comme le note le RFC avec humour, « lire le source SVG à voix haute ne va pas le faire ».
Le texte « Tips for Creating Accessible SVG » donne des bons conseils pour faire du SVG accessible. Et il y a bien sûr la norme ARIA, dont il existe une introduction et de bons exemples. (Désolé, je n'ai pas suivi ces excellents principes dans les exemples ci-dessous, mais j'accepte les patches.)
Si vous voulez voir des exemples concrets, regardez https://www.cs.auckland.ac.nz/~nevil/SVG_RFC_1.2/
. Ainsi,
l'exemple de schéma d'un en-tête TCP
donnera :
Et le schéma de la communication SIP du
RFC 4321 fera
L'annexe A de notre RFC donne un schéma complet (formulé en
Relax
NG) du SVG des RFC. Il est extrait ici dans le fichier
svg-rfc.rnc
, que vous pouvez utiliser pour tester
la conformité de vos SVG. Par exemple, avec
rnv :
% rnv files/svg-rfc.rnc files/tcp-header.svg files/tcp-header.svg
En revanche, avec du SVG trop « riche » (ici, utilisant les couleurs), on aurait :
% rnv files/svg-rfc.rnc /tmp/test1.svg ... /tmp/test1.svg:2:267: error: attribute ^fill with invalid value "red" required: value ^token "none" value ^token "black" value ^token "white" value ^token "#000000" value ^token "#FFFFFF" value ^token "#ffffff" value ^token "inherit"
Une alternative, pour tester la validité des SVG conformes à ce profil, sera svgcheck quand il sera développé.
Avec Inkscape, il faut veiller à sauver le
fichier en Plain SVG (autrement, on a des
ennuis avec les éléments spécifiques d'Inkscape,
ex-Sodipodi). Mais il reste malgré cela deux ou trois trucs à
corriger manuellement, avant que le document produit par Inkscape
soit accepté. Pour Dia, il faut utiliser
l'action Export (par défaut, Dia n'enregistre
pas en SVG), mais Dia produit alors un document avec une
DTD. Si on la retire (manuellement, ou bien
avec xmllint --dropdtd
), tout se passe bien,
le document SVG est alors conforme au profil demandé pour les
RFC.
Autre solution que j'aime bien pour faire du SVG, dès qu'on a des éléménts répétitifs et qu'on veut donc automatiser (en Python), svgwrite. Ce schéma en art ASCII :
+--------------+ +----------------+ | Alice |------------------------------------| Bob | | 2001:db8::1 | | 2001:db8::2 | +--------------+ +----------------+
aurait pu être créé avec svgwrite avec network-schema-svgwrite.py
, qui donne
Bien sûr, pour un schéma aussi simple, le gain n'est pas évident, mais il le devient pour les schémas comportant beaucoup d'éléments récurrents. Mais notez que svgwrite ne connait pas le profil « SVG pour RFC » et, par défaut, peut donc produire des SVG invalides (par exemple avec de la couleur). Le programmeur doit donc faire attention.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : T. Hansen (AT&T
Laboratories), L. Masinter, M. Hardy
(Adobe)
Pour information
Première rédaction de cet article le 16 décembre 2016
Parmi les nombreux formats de publication des RFC prévus suite à l'adoption du nouveau format (RFC 7990), ce RFC décrit l'utilisation de PDF. On pourra donc, en suivant ces règles, avoir une jolie version papier des RFC.
Actuellement, les RFC peuvent bien sûr être imprimés mais c'est un peu tristoune (cf. annexe A). Avec le nouveau cadre de gestion des RFC, le format canonique du RFC sera du XML (RFC 7991), à partir duquel seront produits automatiquement (par des outils qui ne sont pas encore développés) divers formats. HTML sera sans doute le principal pour une publication en ligne (RFC 7992), mais il y a des partisans de PDF, surtout pour l'impression sur le bon vieux papier. Ce RFC 7995 décrit donc l'utilisation de PDF comme format de sortie pour les RFC. À noter que ce format, créé et piloté par une entreprise privée n'est pas à proprement parler un « format Internet » et est sans doute moins connu des participants à l'IETF que ne l'est HTML.
La norme PDF est déposée à l'ISO (ISO 32000-1) mais l'archaïque ISO ne distribue toujours pas librement ces documents. Si on veut apprendre PDF, il faut donc le télécharger sur le site d'Adobe.
Première question (section 2 de notre RFC), quelle version de PDF choisir ? PDF a évolué dans le temps, chaque version ajoutant de nouvelles fonctions. C'est aujourd'hui un format très complexe, difficile à mettre en œuvre complètement. C'est pour cela qu'il existe des profils de PDF, restreignant ce format pour des usages spécifiques. Ainsi, PDF/X est conçu pour l'échange de fichiers avec l'imprimeur. Pour les RFC, documents souvent normatifs, et à longue durée de vie, les exigences principales sont l'accessibilité et la stabilité. C'est ce que fournissent les profils PDF/UA (accessibilité) et PDF/A-3 (archivage à long terme).
Pour les RFC, les profils choisis sont la version 1.7 de PDF, suffisamment ancienne pour être gérée par la plupart des logiciels, le profil PDF/A-3 pour limiter le nombre de fonctions à gérer, et PDF/UA pour l'accessibilité.
La section 3 de notre RFC détaille ensuite toutes les exigences particulières des RFC, pour le format de sortie PDF. Je ne les commente pas toutes ici, seulement celles qui me semblent importantes. Par exemple, la délicate question des polices. PDF permet d'inclure une police dans le document, ou bien de se référer simplement à une police par son nom. Dans ce dernier cas, si le logiciel qui lit le PDF ne trouve pas exactement cette police, il se rabat sur une police « proche », avec un résultat qui n'est pas forcément satisfaisant. De toute façon, PDF/A, le profil « archivage » impose d'inclure la police utilisée, pour éviter de dépendre de logiciels futurs. À noter que cela peut impliquer de payer : peu de polices sont gratuites pour l'auteur. L'annexe C.4 discute des polices acceptables. Il y a les gratuites, mais sans support Unicode complet, comme Source Sans Pro, Source Serif Pro ou Source Code Pro. Bien meilleure du point de vue de la couverture Unicode, mais payante, est Skolar. L'idéal sera peut-être la nouvelle police Noto. Les RFC ayant maintenant le droit d'utiliser des caractères non-ASCII, mais avec des restrictions (cf. RFC 7997), il est possible que des caractères soient refusés par le RFC Editor uniquement parce qu'ils ne sont pas présents dans les polices utilisées.
Le choix des caractéristiques des polices (chasse fixe ou variable, empattement ou pas) devra suivre les mêmes règles que pour HTML et CSS, règles qui figurent dans le RFC 7993. À propos de HTML, notons d'ailleurs que notre RFC sur PDF demande que le PDF ressemble visuellement autant que possible au document HTML. Si vous écrivez un logiciel qui produit le PDF pour un RFC et que vous hésitez sur tel ou tel aspect graphique, consultez le RFC 7992 sur la sortie HTML.
Parmi les autres exigences pour la production de PDF, notre RFC demande qu'on évite les césures.
PDF permet de mettre des liens hypertextes. L'intérêt est faible puisque PDF est surtout utilisé pour le papier (si on regarde sur un écran PDF n'a aucun avantage par rapport au format bien plus ouvert qu'est HTML), mais le RFC prévoit quand même cette possibilité. Il y aura donc des liens, à la fois externes (vers des URL, y compris vers d'autres RFC et, dans ce cas, le RFC 7322 requiert que cela soit vers la page d'information officielle du RFC Editor) et internes (une section du RFC référençant une autre). Les liens internes sont parfois produits automatiquement (par exemple depuis la table des matières vers les sections du texte).
Un problème délicat est celui de la façon dont le texte est stocké dans le document PDF. PDF permet en effet plusieurs façons de réaliser ce stockage. Elles donnent le même résultat visuel mais se comportent différemment pour des fonctions comme la recherche de texte. Ainsi, le mot « IETF » peut être stocké comme une image, comme quatre lettres positionnées indépendamment, ou comme un mot unique. Le stockage en image posera évidemment des problèmes aux outils comme pdftotext (mais ce n'est pas forcément grave pour les RFC, on a toujours le source XML) ou aux outils de synthèse vocale, nécessaires aux malvoyants. Pour la recherche de texte, la solution du mot unique est certainement meilleure, même si elle ne permet pas une typographie aussi subtile. Mais il y a aussi le placement des phrases. La phrase « The IETF supports the Internet » peut être stockée comme cinq mots différents stockés indépendamment (y compris dans un ordre différent de celui de la phrase) et positionnés ensuite, ou bien comme un objet unique.
Notre RFC recommande d'au moins garder les mots dans l'ordre du texte (PDF/UA l'impose).
Pour les images, si le source XML contenait à la fois de
l'art ASCII et du
SVG, notre RFC impose bien sûr qu'on
utilise le SVG pour produire le PDF. Le texte alternatif aux
images, indispensable
pour l'accessibilité, doit être mis dans le PDF (dans la
propriété /Alt
).
Les métadonnées (noms des auteurs, date, etc) sont très utiles pour l'indexation et la recherche et doivent donc être mises dans le PDF. PDF a plusieurs façons d'embarquer des métadonnées, et la recommandation est d'utiliser XMP.
Parmi les zillions de fonctions de PDF, il peut agir en
container d'autres fichiers (oui, comme tar
ou AVI). Tous les logiciels PDF ne savent
pas extraire ces fichiers embarqués dans le PDF mais c'est une
fonction utile, au cas où. Le RFC recommande donc que des fichiers
utiles soient ainsi embarqués : le source XML du RFC, les codes
sources (dans les éléments <sourcecode>
du RFC), les images (dont les sources
SVG)...
Dernier point, les éventuelles signatures. Pour l'instant, il n'y a pas de mécanisme standard pour signer les RFC et en garantir l'authenticité mais, lorsque ce sera le cas, PDF permettra d'inclure une signature dans le fichier produit. (Cette fonction existe dans PDF depuis longtemps.)
Le RFC contient aussi trois annexes intéressantes. L'annexe A
est un historique de la relation compliquée entre les RFC et
PDF. Depuis longtemps, une version
PostScript du RFC était acceptée par le
RFC Editor et publiée, même si très peu
d'auteurs en ont profité. Cela concernait surtout les RFC ayant
des images ou des formules mathématiques comme les RFC 1119 ou RFC 1142. Le PDF produit
par le RFC Editor pour tous les RFC (ou par
) n'était,
lui, qu'une simple « impression » du RFC en texte brut.https://tools.ietf.org/
L'annexe B rappelle ce que doit faire un bon logiciel de production de contenu imprimé, avec découpage en pages. C'est plus dur que cela n'en a l'air, car il faut gérer les veuves et les orphelines, ne pas couper juste après le titre d'une section, ne pas couper les dessins en art ASCII, placer les tableaux intelligemment, etc.
Enfin, l'annexe C décrit une partie des outils disponibles pour le producteur de documents PDF. Si les logiciels de visualisation sont nombreux, il faut noter que tous n'ont pas la totalité des fonctions qu'utilise le format de sortie des RFC (par exemple les liens hypertexte). Du côté des imprimantes (le papier étant le but final de la plupart des documents PDF), certaines savent même gérer le PDF directement (dans les autres cas, ce sera au logiciel de visualisation de produire le format attendu par l'imprimante, souvent PostScript).
Et pour produire le PDF à partir du XML des RFC ? Une solution possible, puisqu'il existe une feuille de style XSLT (disponible en ligne) est de produire du FO qui sera ensuite transformé en PDF, par exemple avec FOP (je n'ai personnellement eu que des expériences décevantes avec FO). Mais il existe plein de bibliothèques qui produisent du PDF, et qui pourraient être utilisées.
Comme notre RFC impose l'utilisation de profils de PDF comme PDF/A, un outil important est le logiciel de vérification qui s'assure que le résultat est bien conforme aux exigences de ce profil. Pour l'instant, il semble qu'il n'existe pas grand'chose dans ce domaine. Il faudra donc compter sur l'outil de production de PDF pour qu'il fasse un travail correct.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC :
H. Flanagan (RFC Editor)
Pour information
Première rédaction de cet article le 16 décembre 2016
Dans la grande série des nombreux RFC spécifiant le nouveau format de ces documents (avec XML étant désormais la référence), ce court RFC décrit le format de publication « texte brut » des RFC.
En effet, si le format « texte brut » n'est plus la référence des RFC, ce format reste toujours utile. Dans le nouveau mécanisme (RFC 7990), il y a désormais plusieurs formats de publication, obtenus à partir du format canonique (celui qui est en XML). Le texte brut est l'un d'eux. Ce format, historiquement le seul utilisé par les RFC, ne disparait pas, mais perd de son importance. Il n'est plus qu'un des formats de publication parmi d'autres (comme HTML, voir le RFC 7992). Le RFC 6949 expliquait ce choix.
À noter que les RFC produits avant ce changement ne sont pas affectés : leur format de référence reste le texte brut (et en ASCII seul).
Bon, désormais, on aura un format de sortie (parmi d'autres) en « texte seul » ou « texte brut ». Mais c'est quoi, le texte brut ? Notre RFC reprend la définition du consortium Unicode : « du texte encodé pour les ordinateurs composé uniquement de points de code d'une norme donnée, sans instructions de format ou de structure ». Bref, les caractères indiqués ne valent que pour eux-mêmes, ils n'indiquent jamais de formatage ou de style. Selon cette définition, HTML, LaTeX et Markdown (RFC 7763) ne sont donc pas du texte brut. (La définition n'est pas 100 % parfaite. La norme Unicode, par exemple, inclut des caractères qui influencent le format.) Le texte brut est donc ce qui est le plus portable : tous les acteurs qui connaissent la norme de jeu de caractères sous-jacente (aujourd'hui, quasiment toujours Unicode) peuvent lire et écrire du texte brut. C'est d'ailleurs une des raisons pour lesquelles les RFC ont si longtemps gardé ce format comme format canonique.
Mais si le texte brut n'est pas idéal comme format de référence, il reste un format de sortie très utile, notamment pour son interopérabilité, ou en raison de l'existence de nombreux outils qui peuvent le traiter (à commencer par grep...) Désormais, donc, le format canonique est le XML décrit dans le RFC 7991 et le texte brut sera produit automatiquement par les nouveaux outils. Mais ce texte brut a des règles qui sont légèrement différentes du texte brut original (« RFC canal historique ») et notre RFC 7994 les décrit. Il est très court, car le format « texte brut » est un format simple.
D'abord, le jeu de caractères (section 2). Ce sera
bien sûr Unicode, mais avec les
restrictions indiquées dans le RFC 7997. En pratique, là où les caractères non-ASCII ne
sont pas autorisés, il faudra utiliser l'ASCII équivalent, donné
dans les attributs XML prévus à cet effet
(ascii
, RFC 7991 en section 2.23.1,
asciiFullname
en 2.7.1, etc). L'encodage sera obligatoirement
UTF-8 (RFC 3629). Curieusement, il est prévu de mettre
une BOM au début du document.
Que faire avec les graphiques, désormais autorisés par le RFC 7990, et écrits en
SVG (RFC 7996) ? Ces graphiques sont, dans le source XML, à
l'intérieur d'un élément
<artwork>
. Comment les rendre dans du
texte brut (section 3 de notre RFC) ? D'abord, si le graphique
n'est pas en SVG mais dans le traditionnel art
ASCII (indiqué par
type=ascii-art
), on utilise cet art ASCII.
Autrement, notre RFC ne propose pas de solution générale. Il est
recommandé aux auteurs de diagrammes et schémas de prévoir une
alternative en art ASCII, même quand ils font du SVG.
Enfin, la section 4 du RFC couvre le problème de la « mise en page ». Un caractère de fin de page (U+000C) sera inclus automatiquement toutes les 58 lignes (les outils auront probablement une option pour ne pas inclure de telles marques). L'outil devra gérer le délicat problème des veuves et des orphelines. Les lignes feront 72 caractères, suivies de deux caractères marquant la fin (U+000D U+000A).
Les textes de début du RFC (RFC 5741) seront automatiquement mis comme avant, mais les en-têtes et pieds de page disparaissent. Autre disparition, il n'y aura plus, dans le format de sortie en texte brut, de numéros de pages dans la table des matières (dommage, je trouve, mais c'est au nom de la cohérence avec les autres formats de sortie).
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : H. Flanagan (RFC Editor)
Pour information
Première rédaction de cet article le 16 décembre 2016
Le nouveau format des RFC, décrit dans le RFC 7990, prévoit un format canonique, XML, à partir duquel seront automatiquement produits des versions texte brut, PDF, etc. Il y aura évidemment la possibilité de produire une version HTML (RFC 7992) et celle-ci sera bien sûr « stylée » avec CSS. Ce RFC décrit donc le cahier des charges de la feuille de style CSS à développer, avec tous les mots-clés du moment (comme responsive design).
Cette future feuille de style sera le style par défaut (le lecteur pourra toujours la redéfinir). Son but (section 2 du RFC) est de respecter le contenu du RFC (ceux-ci sont parfois des normes : pas question de toucher au texte !) tout en permettant une accessibilité maximale, pour tous les lecteurs, quelle que soit la machine qu'ils utilisent pour accéder au Web.
Plus précisément, la section 3 exige de :
La section 4 donne ensuite les principes de présentation à suivre. Je ne vais pas les reprendre ici dans leur intégralité mais on y trouve :
Il y aura également une feuille de style pour l'impression (comme pour le blog que vous êtes en train de lire, d'ailleurs.) La police par défaut sera cette fois avec empattement.
Enfin, la section 7 et l'annexe A de notre RFC font la liste des classes CSS
employées. Par exemple, .pilcrow
sera utilisé
pour les marques de paragraphe, qui ne seront affichées que
lorsque le pointeur passera dessus. .url
servira à marquer les URL de manière
visuellement distinctive. La classe .cref
ne
servira que dans les
Internet-Drafts, pour
afficher les commentaires, mais pas dans les RFC (où les
commentaires des auteurs sont supprimés).
La merveilleuse feuille de style qui met en œuvre ces exigences n'est pas encore finie. Un appel d'offres a eu lieu (après relecture). Et on peut voir la feuille temporaire en ligne (pour le développement et les commentaires, c'est sur Github).
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : J. Hildebrand (Cisco
Systems), P. Hoffman (ICANN)
Pour information
Première rédaction de cet article le 16 décembre 2016
Depuis la sortie du RFC 7990 et ses copains, le format canonique (le format de référence) des RFC n'est plus le texte seul mais un langage XML, normalisé dans le RFC 7991. Les formats « de publication » seront produits automatiquement à partir de ce XML. C'est ainsi que notre RFC 7992 décrit la sortie HTML, qui permettra de publier des beaux RFC sur le Web.
HTML, trop riche et trop mouvant, est en effet mal adapté à l'écriture et à la maintenance de documents. Il n'était donc pas envisageable de le choisir comme format canonique. En revanche, il est incontournable comme format de publication. C'est en effet le langage du Web, et il y a donc logiquement une forte demande pour pouvoir lire les RFC en HTML. Avant, lorsque le format canonique était le texte brut, des versions non officielles étaient publiées en HTML (voir un exemple) mais, le texte brut n'ayant pas de formatage précis, ces versions n'avaient pas vraiment l'air de vraies pages Web...
(Notez que ce blog que vous êtes en train de lire est produit par un mécanisme analogue à celui que les RFC suivront désormais : tapé en XML, avec le HTML produit automatiquement.)
La section 1 de notre RFC résume les principes de l'HTML utilisé. D'abord, ce sera un sous-ensemble de HTML (HTML a bien trop de fonctions). Ensuite, la présentation sera largement délégué à une feuille de style CSS, dont les caractéristiques sont mentionnées dans le RFC 7993.
La section 2, elle, est le « cahier des charges » du HTML des RFC. Elle précise les exigences du RFC 6949. Elle concerne les auteurs du ou des logiciels de production des RFC (pour ces logiciels, voir le RFC 7998). Les auteurs de RFC, eux, n'ont pas à s'en soucier, ils écrivent du XML, et le HTML sera produit par les outils.
Le but principal est que l'HTML produit soit parfaitement lisible sur la grande majorité des navigateurs utilisés. Pas question bien sûr d'ajouter une de des ridicules mentions « optimisé pour Internet Explorer » qui étaient si communes sur les sites Web d'amateurs, dans les années 2000. Notre RFC mentionne explicitement l'exigence que les textes soient lisibles avec au moins un navigateur « texte », comme Lynx, certaines personnes accédant au Web ainsi (par obligation ou par goût). C'est l'une des raisons de la décision de ne pas accepter la totalité de HTML.
Le fichier HTML devra être autonome (ne pas dépendre de fichiers extérieurs), de manière à pouvoir être transmis facilement par des mécanismes tels que rsync ou le courrier électronique.
Le JavaScript est accepté mais à condition qu'il ne modifie en aucun cas le texte du RFC. (Il peut, par exemple, ajouter des éléments de navigation, ou afficher des métadonnées.)
On l'a dit, CSS sera utilisé pour la présentation, mais le cahier des charges exige qu'on puisse facilement remplacer la feuille de style par une de son choix, pour s'adapter aux goûts locaux.
Le Web étant fondé sur la notion de lien hypertexte, il y aura évidemment des liens, aussi bien ceux mis explicitement par l'auteur (« ce point est développé en section N »), que ceux ajoutés automatiquement (de la table des matières vers les différentes sections, par exemple).
Un point crucial est évidemment l'accessibilité. Comme le savent tous ceux et toutes celles qui vont régulièrement à Paris Web, c'est un point essentiel mais souvent oublié. Notre RFC note donc que les publications en HTML des futurs RFC devront être accessibles aux malvoyants, aux daltoniens, et aux utilisateurs de petits écrans, par exemple les smartphones. (Note personnelle : ce dernier point ne devrait pas être dans une section sur l'accessibilité. Le Web est prévu - contrairement aux formats du monde du papier, comme PDF - pour être visible sur tous les périphériques.)
Au fait, quelle version de HTML sera utilisée (section 3 de notre RFC) ? Ce sera HTML5 (et pas, et je le déplore, XHTML ; l'inconvénient, souvent cité contre XHTML, de la difficulté à l'écrire n'a pas de sens ici, puisque le HTML sera produit automatiquement).
La section 4 précise la syntaxe utilisée (rappelez-vous qu'on n'accepte pas la totalité de HTML5) : encodage en UTF-8, sauts de ligne en style Unix (un U+000A et rien d'autre), pas de caractères de contrôle comme la tabulation (U+0009). Les éventuels commentaires du source XML ne seront pas mis dans le HTML (l'idée est qu'ils sont pour les auteurs, pas pour les lecteurs).
Il y a des objets divers qu'on retrouve souvent dans le source
XML. Ils sont rassemblés dans la section 5. Par exemple, on
trouve les identificateurs qui seront mis comme valeur des
attributs id
dans le HTML produit. Ce sont
parfois des identificateurs mis explicitement par l'auteur, et
parfois des identificateurs produits par le logiciel, par exemple
pour que les entrées de la table des matières pointent vers la
section correspondante.
Autre objet récurrent, la marque de paragraphe (pilcrow pied-de-mouche, caractère Unicode U+00B6, celui-ci : ¶), qui sera mise automatiquement derrière chaque paragraphe, mais pas affiché par défaut (il faudra promener le pointeur dessus pour le voir).
Maintenant, attaquons les différentes parties du RFC rendu en
HTML. D'abord (section 6), les premiers objets HTML qu'on
rencontrera, notamment les métadonnées du
RFC. Il y aura évidemment un
DOCTYPE
identifiant le document comme du HTML5. L'élément racine sera <html>
,
avec une étiquette de langue qui sera bien
sûr en
,
l'anglais. L'élément
<head>
qui suivra contiendra une
déclaration de jeu de caractère, un titre,
et diverses métadonnées :
<meta charset="utf-8"> <title>The Mother of all RFCs</title> <meta name="author" content="Joe Hildebrand"> <meta name="author" content="Heather Flanagan"> <meta name="description" content="This document defines..."> <meta name="generator" content="xmljade v0.2.4"> <meta name="keywords" content="html,css,rfc">
(Rappelez-vous que le HTML produit n'est hélas pas du
XHTML donc il est normal que les
<meta>
ne soient pas explicitement
fermés.)
Il y aura aussi un lien vers la licence des RFC, en utilisant le
cadre général des liens (RFC 8288) :
<link rel="license" href="https://www.rfc-editor.org/copyright/">
Cette première partie du RFC produit contiendra aussi une feuille de style, ainsi qu'un lien vers une éventuelle feuille locale, au cas où un lecteur souhaiterait lire le RFC selon un style différent :
<style> body {} ... </style> <link rel="stylesheet" type="text/css" href="rfc-local.css">
Le début de la partie visible du RFC sera composée d'une
<dl>
pour les métadonnées affichées, et
d'une table des matières. Les métadonnées seront donc du genre :
<dl id="identifiers"> <dt>Workgroup:</dt> <dd class="workgroup">rfc-interest</dd> <dt>Series:</dt> <dd class="series">Internet-Draft</dd> <dt>Status:</dt> <dd class="status">Informational</dd> <dt>Published:</dt> <dd><time datetime="2014-10-25" class="published">2014-10-25</time></dd> ...
La partie principale du RFC sera, elle, rendue selon les principes décrits en section 9 pour chacun des éléments XML qui composent le source.
La dernière partie du RFC incluera un index (si le source XML
avait un attribut indexInclude
dans l'élément
<rfc>
), les adresses des auteurs
(formatées en hCard), et les métadonnées
considérées comme les moins importantes (les autres ayant été
mises au début).
La section 9 de notre RFC est particulièrement longue car elle
décrit le rendu en HTML de tous les éléments du vocabulaire XML du
RFC 7991. Je ne vais pas tout décrire ici,
juste donner quelques exemples. Ainsi,
<artwork>
sera rendu dans un élément
HTML <pre>
, si le schéma était en
art ASCII, sera inclus tel quel dans le
HTML si le schéma était en SVG (RFC 7996), et sera mis sous forme d'un
<img>
(avec contenu de plan
data:
) dans les autres
cas. <sourcecode>
, lui, est toujours
restitué sous forme d'un <pre>
HTML.
La traduction de certains éléments en HTML est plus
directe. Par exemple,
<em>
est simplement rendu par le même
élément HTML.
Et, pour finir, un petit mot sur la sécurité (section 11) : comme les RFC en HTML ne sont pas forcément téléchargés depuis le Web mais peuvent être lus depuis un fichier local (après, par exemple, synchronisation via rsync), on ne bénéficie pas forcément des protections du navigateur. Donc, prudence.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : P. Hoffman (ICANN)
Pour information
Première rédaction de cet article le 16 décembre 2016
Contrairement à beaucoup de SDO, l'IETF n'avait pas de format standard pour l'écriture de ses documents. Désormais, avec le nouveau cadre décrit dans le RFC 7990, c'est fait. XML, avec le vocabulaire décrit dans ce nouveau RFC, est le format canonique des RFC.
Vous voulez écrire un RFC ? Il est fortement recommandé d'utiliser dès le début le format standard XML, fondé sur un vocabulaire spécifique aux RFC, et mis en œuvre dans la future version de l'outil xml2rfc. Voici donc le vocabulaire « XML2RFC version 3 », succédant à deux versions qui n'étaient pas officiellement standard (les changements depuis la v2, spécifiée dans le RFC 7749, ne sont pas énormes). Notez que le vocabulaire XML et les outils continuent à évoluer, donc ce RFC n'est pas éternel. Et que la version 2 restera sans doute en service pendant encore des années : cela prend du temps de changer les habitudes !
Voici le squelette d'un Internet-Draft écrit avec ce XML :
<?xml version="1.0" encoding="utf-8"?> <rfc docName="draft-ietf-dnsop-qname-minimisation-09" submissionType="IETF" ipr="trust200902"> <front> <title abbrev="Qname minimisation">DNS query name minimisation to improve privacy</title> ... <middle> <section anchor="intro" title="Introduction and background"> <t>The problem statement is described in <xref target="RFC7626"/>. [...] ... </back> </rfc>
Sur ce squelette simple, on voit l'élément racine
(<rfc>
), l'utilisation des attributs
(comme submissionType
qui indique la voie
prise par le document, ici, l'IETF,
cf. RFC 7841), la séparation en trois parties,
<front>
, qui regroupe les
métadonnées,
<middle>
, qui est le texte principal,
et <back>
, où se trouvent la
bibliographie, les annexes, etc.
Parmi les attributs de cet élément racine
<rfc>
, notez ipr
,
qui indique les conditions légales d'utilisation de ce RFC. Dans
cet example, la valeur est la plus couramment utilisée :
trust200902
(cf. l'annexe A.1) indique les règles de
l'IETF Trust datant de 2009 (qui disent en
gros que le texte du RFC peut être librement copié, reproduit,
distribué et mis en œuvre dans des programmes). L'annexe A de
notre RFC détaille ce qu'on appelle le
boilerplate, ces textes juridiques obligatoires
qui sont ajoutés automatiquement par le logiciel xml2rfc. Ainsi,
si on met ipr="trust200902"
dans l'élément
<rfc>
, xml2rfc va automatiquement
ajouter « Copyright (c) 2015 IETF Trust and the persons identified as the
document authors. All rights reserved. \ This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents [...] »...
Le gros morceau du RFC est la section 2, qui donne la liste des éléments XML acceptés. Je ne vais pas reproduire ici cette liste, juste parler de quelques éléments qui me semblent rigolos.
<section>
contient une partie du
RFC. Cet élément est hiérarchique : on crée des sous-sections en
les mettant sous les sections existantes, et ainsi de suite,
récursivement. (Contrairement à ce qui se passe avec
HTML, où on indique explicitement le niveau
de la section, <h1>
,
<h2>
, etc.) On a aussi
<abstract>
, qui indique le résumé au
début du RFC.
<t>
contient un paragraphe et est
donc l'équivalent du <p>
de HTML.
<artwork>
permet de spécifier du texte qui sera représenté comme tel,
sans aucune justification, mise à la ligne, etc. (Les
tabulations sont interdites, ce qui règle
le vieux débat « tabs
vs. spaces ».) <artwork>
permet
de mettre de l'art ASCII dans un RFC, mais la
méthode préférée pour les images est désormais
SVG, voir le RFC 7996. Le SVG peut être mis directement dans le source
XML ou bien inclus par différentes méthodes, dont l'attribut
src
. Cet attribut
src
permet de spécifier un fichier externe,
l'art ASCII ne servant alors que de solution de secours, pour le
format en texte seul. Un attribut type
permet
d'indiquer le type du dessin (par exemple
svg
pour les images en SVG). La liste des types
possibles sera en ligne.
Voici un exemple d'art ASCII :
<artwork type="ascii-art"> +--------------+ +----------------+ | Alice |------------------------------------| Bob | | 2001:db8::1 | | 2001:db8::2 | +--------------+ +----------------+ </artwork>
Le code source, lui, se fait avec
l'élément <sourcecode>
, un attribut
type
permettant d'indiquer le langage utilisé
(une liste des valeurs possibles sera en ligne). Voici un exemple :
<sourcecode type="python"> print("Hello, world") </sourcecode>
Comme le langage utilisé peut utiliser des caractères qui sont spéciaux pour XML (comme < ou &), il est souvent préférable de mettre le code source dans une section CDATA.
<eref>
permet de faire un lien
hypertexte vers l'extérieur :
<t>More text and a <eref target="http://www.rfc-editor.org/">lien vers le site du RFC Editor</eref>.</t>
<ul>
permet de représenter les
traditionnelles listes à puces :
<t>There are three sorts of DNS requests being issued:</t> <ul> <li>Primary request: [...]</li> <li>Secondary requests: [...]</li> <li>Tertiary requests: [...]</li> </ul>
<references>
permet d'indiquer une
bibliographie. Il y en a typiquement deux
dans un RFC (cf. la section 4.8.6 du RFC 7322), la bibliographie normative (ce qu'il faut absolument
avoir lu et compris car le RFC en dépend) et l'informative (ce
qu'on peut sauter si on est pressé). Pour aider, le RFC
Editor distribue des fichiers XML contenant les
références aux RFC publiés, comme http://www.rfc-editor.org/refs/bibxml/reference.RFC.7626.xml
.
Le nom d'un auteur de RFC se met avec l'attribut
<author>
. Comme il peut être en
caractères non-ASCII, des attributs permettent d'indiquer une
variante en ASCII seul. Par exemple :
<author fullname="Patrik Fältström" asciiFullname="Patrik Faltstrom"> <organization>Netnod</organization> </author>
Ce format de RFC s'appuie sur XML et il faut donc suivre les règles de XML, notamment sur les caractères spéciaux. Ainsi, le chevron ouvrant doit être remplacé par une séquence d'échappement (< au lieu de <). Si cette contrainte est trop forte, on peut aussi enclore les parties à « échapper » dans une section CDATA.
Le format des RFC permet d'autres caractères que ceux du jeu ASCII, mais avec certaines restrictions (voir RFC 7997).
Le format actuel permet l'inclusion d'autres documents, via des
attributs comme l'attribut src
pour le code
source :
<sourcecode type="python" src="hello.py"/>
On peut aussi utiliser les mécanismes génériques d'inclusion de XML, comme XInclude (cf. annexe B.1) ou les entités, et c'est souvent utilisé pour la bibliographie :
<!DOCTYPE rfc [ <!ENTITY rfc7830 PUBLIC "http://xml.resource.org/public/rfc/bibxml/reference.RFC.7830.xml"> ]> [...] <references> &rfc7830; </references>
À noter qu'il existe un type
MIME pour les sources XML de RFC,
application/rfc+xml
(section 8 de notre RFC).
Si vous voulez voir le schéma XML complet, il est en annexe
C (j'en ai exporté une version utilisable telle quelle, sans les
sauts de page des RFC, en rfc-v3.rnc
). Comme il est
écrit en Relax NG, il
permet l'utilisation de tous les outils Relax NG, comme le mode
emacs nxml-mode et comme
rnv. Ainsi, une fois le fichier
rfc-v3.rnc
chargé dans emacs (menus XML puis
Set schema puis File), on
dispose de fonctions d'édition bien pratiques (par exemple, on
tape un < puis une tabulation et emacs propose de compléter
uniquement avec les éléments autorisés à cet endroit). Cela évite
bien des erreurs.
À noter que ce RFC ne décrit que les éléments et attributs XML, pas de processing instructions (PI), qui ne sont plus acceptées.
Avec un logiciel comme rnv, on peut tester la syntaxe (uniquement la syntaxe : certaines contraintes dans le RFC ne sont pas exprimables dans le schéma, il a fallu les formuler en langue naturelle dans le texte du RFC) :
% rnv rfc-v3.rnc rfc-v3-sample.xml rfc-v3-sample.xml
Parfait, ici, tout est bon. S'il y avait eu une erreur :
% rnv rfc-v3.rnc rfc-v3-sample-wrong.xml rfc-v3-sample-wrong.xml rfc-v3-sample-wrong.xml:9:6: error: element ^t not allowed required: element ^section rfc-v3-sample-wrong.xml:11:2: error: unfinished content of element ^middle required: element ^section error: some documents are invalid
Si le RFC contient des références externes (que rnv ne sait pas traiter), on peut utiliser xmllint pour les remplacer :
% xmllint --dropdtd --noent draft-dupont-my-protocol.xml | rnv rfc-v3.rnc
On peut aussi utiliser Jing (annexe C.1). Mode d'emploi très court, on télécharge :
% wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jing-trang/jing-20091111.zip % unzip jing-20091111.zip % java -jar ./jing-20091111/bin/jing.jar -c rfc-v3.rnc draft-dupont-my-protocol.xml %
Les changements depuis le texte précédent, le RFC 7749, qui décrivait la version 2 (notre RFC est la version 3), sont décrits dans l'annexe D et résumés en section 1.3. L'idée était notamment d'avoir un vocabulaire plus facile à utiliser, sans pour autant trop changer par rapport au format v2, qui était bien connu des auteurs.
Le changement le plus spectaculaire concerne les listes, qui
sont désormais faites, comme en HTML, avec
des <dl>
,
<ul>
et
<ol>
. Dans une liste, le contenu est
marqué par <li>
et plus
<t>
. Autre inspiration HTML,
l'apparition des tables, avec <table>
(et éléments associés comme <tr>
et
<td>
). D'autre part, de nouveaux éléments
apparaissent pour marquer du texte, par exemple s'il est
important (<em>
,
qui n'avait pas d'équivalent en v2, dont le seul format de sortie
était le texte brut). Il y a aussi un
<blockquote>
pour les citations. Bien que l'IETF se
vante souvent de pratiquer le culte du « running
code », il n'y avait pas d'élément XML particulier pour
indiquer du code source dans un RFC (on se contentait
d'<artwork>
). C'est désormais fait avec
<sourcecode>
. Quelques autres éléments
XML nouveaux (je ne les cite pas tous, le RFC fait 159 pages !) :
<displayreference>
pour associer un
chouette texte aux références, <link>
pour les liens externes (contrairement à
<eref>
, qui existait déjà,
<link>
est spécifique à certains types
de documents, par exemple les Internet-Drafts) ou encore
<br>
pour forcer des sauts de ligne
(mauvaise idée que de mettre des éléments de présentation, si vous
voulez mon avis).
Il y a aussi de nouveaux attributs XML aux éléments
existants. Pour remplacer les PI (processing
instructions comme <?rfc
toc="yes"?>
), on a tocInclude
et tocDepth
dans l'élément
<rfc>
, afin de contrôler la
table des matières. De même, pour gérer
l'internationalisation, il y a désormais un attribut
ascii
pour les éléments qui acceptent du
contenu non-ASCII, afin de fournir une
alternative pour les anglophones. Il y a aussi des attributs plus
orientés présentation comme keepWithNext
ou
keepWithPrevious
, attributs de
<t>
, qui expriment un souhait de garder
ce paragraphe avec le suivant ou le précédent, pour mieux
contrôler la pagination.
En revanche, certains éléments et attributs sont retirés de la
circulation. Ils seront encore acceptés par les outils, mais
temporairement. <list>
subit ce trist sort
(remplacé par les éléments HTMLisant comme
<ul>
et
<ol>
). <facsimile>
disparait également, victime des évolutions technologiques. Parmi
les attributs, title
disparait (il était
utilisé dans des éléments comme
<section>
) au profit de
name
(changement assez gratuit, je
trouve).
Les autres changements sont bien sûr l'acceptation de caractères non-ASCII, et plein de modifications de détail.
Question mise en œuvre, il faudra patienter. S'il y a déjà eu des mises en œuvre expérimentales et partielles, les vrais logiciels officiels ne sont pas encore, en octobre 2016, développés.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : H. Flanagan (RFC Editor)
Pour information
Première rédaction de cet article le 16 décembre 2016
Voici enfin la série de RFC décrivant le nouveau format des RFC. Ce projet a commencé il y a plusieurs années, mais les discussions ont été longues. Ce nouveau RFC et les huit autres qui l'accompagnent, marquent un changement important dans ces « textes sacrés » de l'Internet : l'ancien format « texte brut » n'est plus le format de référence. Désormais, tout RFC sera fait en XML, format d'où seront produits automatiquement des versions texte brut, HTML, PDF, etc.
Les RFC sont des documents cruciaux pour l'Internet. C'est sous forme de RFC que sont publiées les normes techniques de la famille de protocoles TCP/IP. Et il y a bien d'autres RFC qui ne sont pas forcément des normes (cf. RFC 1796). Librement disponibles en ligne (contrairement aux normes techniques des organisations traditionnelles du mésozoïque), dans un format ouvert, la disponibilité des RFC est l'une des raisons du succès de l'Internet.
Parlons de format, justement. Les RFC, jusqu'à maintenant, étaient sous forme de texte brut, et en ASCII seul. (Certes, des versions PDF et HTML non-officielles étaient diffusées mais on voyait bien qu'elles avaient été produites à partir du texte brut... Certes, il était possible depuis dix ans d'écrire les RFC en XML, cf. RFC 2629, mais ce n'était pas le format de référence.) Pourquoi donc se limiter à ce format ? Il y avait plusieurs bonnes (et d'autres moins bonnes) raisons mais il ne faut pas de cacher qu'une des raisons les plus importantes était qu'il est difficile de faire changer un processus de production bien établi, même s'il comprend des archaïsmes, comme l'utilisation de troff pour traiter des documents. L'actuelle éditrice des RFC, Heather Flanagan, a donc eu bien du mérite à faire aboutir ce projet de changement. Il a fallu beaucoup de discussions, dans une communauté souvent divisée. (Que les informaticiens pensent aux grands débats du genre « vi ou emacs ? »)
Le projet de réforme des RFC avait sérieusement commencé en 2013 avec le RFC 6949, le véritable cahier des charges du nouveau format. La décision formelle de migrer vers le nouveau format, et donc de décider que le format de référence serait désormais le XML et non plus le texte brut a été prise en mai 2013. Avant et pendant cette décision, d'innombrables messages ont été échangés sur la liste de diffusion rfc-interest.
Il est important de noter que cette discussion portait sur le processus de publication des RFC terminés. L'élaboration des Internet-Drafts, la décision de les publier ou pas (qui dépend de chaque voie, cf. RFC 8729) ne sont pas concernées.
La section 2 de notre RFC résume le problème que veut résoudre le nouveau format. Le monde a bien changé depuis que seuls une poignée de Californiens anglophones venait aux réunions IETF. Les participants viennent aujourd'hui de 45 pays, situés dans le monde entier, les lecteurs des RFC sont plus divers que jamais, utilisent des engins très variés, et il est toujours aussi crucial que les RFC soient largement disponibles et accessibles, et sur une très longue période (mon favori est le RFC 768, publié en 1980 et toujours d'actualité). Le format de référence en texte ASCII brut ne permettait clairement pas cela.
Mais choisir un successeur n'était pas facile : notre RFC insiste sur le fait qu'il y a aujourd'hui plusieurs groupes qui utilisent les RFC (pas seulement des techniciens, juristes et chefs accèdent aujourd'hui à des RFC), et sur le fait qu'il fallait un compromis entre les besoins actuels et l'importance d'une disponibilité à long terme (par exemple, adopter le format à la mode du moment pourrait se payer cher plus tard lorsque ce format n'intéressera plus personne).
Un peu de terminologie (section 3) est nécessaire pour bien comprendre le choix effectué :
Et aussi un terme important : texte réagencable (ou réajustable, reflowable text). C'est du texte qui s'ajuste automatiquement à la largeur du dispositif de lecture. C'est banal dans le monde HTML, où c'est fait automatiquement depuis toujours. Mais c'était un des principaux inconvénients de l'ancien format des RFC : le texte avait une largeur fixe.
Quel sera donc exactement le format canonique ? La section 6 répond à cette question :
<sourcecode
src="[un URI externe]"...
(RFC 7991, section 2.48), le code en question sera inclus
dans la version canonique. Idem si l'auteur a utilisé XInclude.Notez donc que les images (en SVG) seront désormais possibles (voir le RFC 7996).
Le guide du style des RFC (RFC 7322) avait été révisé pour tenir compte de ce nouveau format. Notamment, il se concentre désormais sur le contenu du texte, ne demandant plus aux auteurs des efforts de présentation. (La section 5 résume les changements importants pour les auteurs.)
Enfin, la section 7 décrit les formats de publication. À partir du source XML, seront automatiquement produits HTML, PDF, texte brut et peut-être plus tard d'autres. Le HTML est évidemment la cible évidente. Son utilisation pour les RFC est décrite dans le RFC 7992. Le résultat sera certainement bien meilleur que les versions HTML non-officielles actuelles, qui sont produites à partir du texte brut, qui ne contient pas assez de structure pour faire du bon HTML. La mise en page sera évidemment assurée par CSS (RFC 7993), il y aura une feuille de style standard, que chacun sera bien sûr libre de remplacer. Le SVG sera inclus dans l'HTML (il faudra donc un navigateur qui gère bien SVG). Il y aura même du JavaScript mais avec de sévères restrictions. Notamment, le code JavaScript ne devra pas changer le texte, ou supprimer du texte.
PDF, quant à lui, est spécifié dans le RFC 7995. Il devra suivre le profil PDF/A-3, spécialement prévu pour de l'archivage à long terme, et pour pouvoir être relu par des logiciels PDF n'ayant pas tous les derniers gadgets.
Naturellement, le texte brut n'est pas abandonné. Comme indiqué dans le RFC 7994, il y aura une version en texte brut produite automatiquement à partir du XML, même si elle ne sera plus la version canonique. Parmi les nouveautés par rapport à l'ancien format, UTF-8 sera désormais autorisé, même si c'est de façon limitée (voir les limitations dans le RFC 7997). Il pourra y avoir une variante non découpée en pages.
Dans le futur, il est possible que le format EPUB soit ajouté à cette liste.
Au passage, comment a été décidé cet important changement dans le format des RFC ? La section 4 résume cette histoire. Comme indiqué plus haut, cela a pris très longtemps et nécessité beaucoup de discussions, qui ont notamment eu lieu sur la liste de diffusion rfc-interest, et au cours des réunions physiques de l'IETF. Le cahier des charges a été formalisé en 2013 dans le RFC 6949. Une fois le cahier des charges décidé, une équipe spécialisée a été désignée par le RFC Editor pour mettre au point les détails, notamment en adaptant le langage XML utilisé, partant de la dernière version (RFC 7749), pour arriver au futur langage, RFC 7991. Des éditeurs professionnels ont également été consultés, ainsi d'autres SDO et même des juristes (oui, car aux États-Unis, rien n'est désormais à l'abri d'actions en justice, même pas les RFC, le choix du format de sortie PDF/A-3 venait en partie de la nécessité de répondre aux subpoenas). Le tout était bien sûr fait sous la supervision du RFC Series Oversight Committee. Certaines décisions furent consensuelles, les autres tranchées par le RFC Editor (cf. RFC 8728). Le tout a été approuvé par l'IAB en août 2016.
Après ce tour du passé, le futur. Comment se fera la transition vers le nouveau système (section 10) ? C'est qu'il va falloir créer de nouveaux outils (cf. RFC 7998). L'appel d'offres pour leur développement a été fait en septembre 2016. La description des outils est une très intéressante lecture (l'appel d'offres formel est sur la page des Request For Proposal). L'appel d'offres a été gagné par les sociétés SeanTek et Elf Tools.
Pendant une période intermédiaire, le texte seul sera toujours utilisé comme format canonique, mais les nouveaux RFC passeront également par le nouveau workflow, pour vérifier que tout se passe bien et que le résultat est correct. Double travail, donc, mais nécessaire pour s'assurer que tout est en place.
Notez que, même une fois la transition finie, les auteurs ne seront pas forcés de soumettre leur document sous forme d'un fichier XML (ils seront simplement très fortement encouragés à le faire). S'ils envoient le texte seul comme avant, le RFC Editor devra produire le XML lui-même, et c'est ce XML qui sera la version canonique. Rappelez-vous que beaucoup de RFC sont des documents normatifs et que chaque mot, voire chaque virgule peut compter ! Voici pourquoi il faudra s'assurer que tout est parfait, même si, au début, cela entrainera certainement des retards dans la publication.
Dans le cas où l'auteur envoie du XML suivant le RFC 7991, il y aura moins de travail pour le RFC Editor, juste convertir ce XML au XML canonique (résoudre les références extérieures, par exemple) et passer ce XML canonique dans les nouveaux outils.
Notez que le RFC Editor maintient une FAQ très utile sur toutes les questions que pose le nouveau format. Et la RFC Editor avait fait un très drôle Pecha Kucha à Séoul en novembre 2016, sur le cahier des charges du nouveau format.
Le premier RFC au nouveau format a été le RFC 8651, sorti en octobre 2019.
Date de publication du RFC : Août 2016
Auteur(s) du RFC : E. Lear, R. Housley
Pour information
Réalisé dans le cadre du groupe de travail IETF ianaplan
Première rédaction de cet article le 30 août 2016
Un certain nombre de fonctions administrativo-politico-techniques dans l'Internet sont assurées par un service nommé l'IANA (Internet Assigned Numbers Authority). Cela va du spectaculaire (l'instruction des demandes d'ajout ou de suppression des TLD) jusqu'au routinier (la gestion des innombrables registres techniques que l'IANA maintient pour le compte de l'IETF). L'IANA est un service de l'ICANN et l'ICANN est sous tutelle du gouvernement états-unien pour effectuer ce travail, dit « fonction IANA ». Le gouvernement états-unien a annoncé en 2014 qu'il envisageait peut-être dans le futur de diminuer la dépendance de l'ICANN et a demandé, en attendant, aux parties intéressées, de soumettre des propositions. L'ICANN, toujours ravie qu'on propose des discussions et des réunions, a créé le ICG (IANA stewardship transition Coordination Group) qui a à son tour sollicité des commentaires. Ce nouveau RFC est la réponse de l'IETF à cet appel, ne concernant que la gestion des registres techniques. La gestion des noms de domaine et des adresses IP, bien plus politicienne et bien plus brûlante (surtout pour les noms de domaine) n'y figure pas. Voici donc « la position de l'IETF concernant l'avenir de la gestion des registres IANA, dans l'hypothèse où le gouvernement états-unien relâcherait son emprise ». Pour résumer cette position : la gestion des registres des paramètres des protocoles fonctionne actuellement bien et, quelles que soient les manœuvres autour de l'évolution du rôle du gouvernement US, il ne faut pas la changer. Ce RFC a été terminé en janvier 2015 mais n'est publié que maintenant, après l'approbation du plan de transition par l'ICANN en mars 2016 à sa réunion de Marrakech, et après l'accord du gouvernement états-unien en août.
L'agence du gouvernement états-unien chargée de superviser l'ICANN se nomme NTIA, dépendant du ministère du commerce (notez la vision de l'Internet que cela implique). Notez que cette supervision n'est pas le seul levier direct de ce gouvernement sur la gestion de ressources critiques de l'Internet. Il y a aussi la gestion de la racine du DNS, effectuée via Verisign. En mars 2014, génée par les révélations de Snowden, la NTIA a annoncé un projet d'évolution du statut de l'ICANN, passant du gouvernement états-unien à quelque chose de nouveau, encore à discuter. La NTIA a posé ses conditions (par exemple que le quelque chose de nouveau ne devait pas être multi-gouvernemental), et annoncé que, s'il n'y avait pas de plan satisfaisant (satisfaisant pour la NTIA) proposé, le projet serait abandonné ou redéfini.
C'est là qu'a été créé l'ICG (IANA Stewardship Coordination Group) dont la charte figure en annexe B de ce RFC. C'est cet ICG qui a émis l'appel aux commentaires (qui figure en annexe C du RFC). Cet appel demande entre autre de préciser si les réponses concernent la partie « noms de domaine », la partie « adresses IP » ou bien la partie « paramètres des protocoles » du travail de l'IANA (ce RFC concerne la troisième partie). Les réponses sont disponibles en ligne.
La section 2 de ce RFC est la réponse formelle de l'IETF, suivant le plan de l'appel à commentaires de l'ICG. D'abord, l'IETF répond à la question « l'IANA sert à quoi, pour vous ? » Bien des protocoles conçus ou gérés par l'IETF ont besoin de registres pour des paramètres du protocole. Par exemple, le protocole HTTP (RFC 7231) a des codes de retour des opérations (comme le célèbre 404) qui sont stockés à l'IANA. Ajouter un tel code (par exemple 451 pour « contenu censuré ») ne nécessite donc pas de modifier la norme HTTP. Ou bien, pour prendre un exemple nettement moins connu, le protocole PCP (RFC 6887) dispose d'un certain nombre d'options, qui ne sont pas fixées une fois pour toutes dans la norme mais sont notées dans un registre IANA, ce qui permet d'en ajouter facilement de nouvelles.
Pour que l'Internet fonctionne, il faut que ces paramètres des protocoles soient utilisés de la même manière par tous. Par exemple, cela signifie que les développeurs de logiciels Internet doivent utiliser les mêmes registres, en l'occurrence, ceux de l'IANA. Ainsi, un serveur HTTP peut renvoyer le code 403 en sachant bien que cela sera interprété par tous les clients comme signifiant « Accès interdit », car le code 403 figure dans le registre IANA avec cette définition. Ce rôle de l'IANA pour l'IETF est documenté dans le RFC 5226.
L'IANA gère également le TLD
.arpa
, qui est
considéré comme un des registres de paramètres (RFC 3172).
Ce travail de l'IANA pour le compte de l'IETF est effectué en application du RFC 2860 (voir aussi ses déclinaisons concrètes), qui est le « contrat » entre les deux activités.
La question suivante est « qui êtes-vous ? » L'IETF se présente donc, SDO internationale, ouverte et dont la mission est décrite dans le RFC 3935. L'IETF fait les normes techniques de l'Internet « de la couche 3 jusqu'au bas de la couche 7 ». C'est elle qui est responsable d'IP de BGP, du DNS, de HTTP, etc. (Oui, tous les lecteurs de ce blog savent cela mais la réponse de l'IETF est conçue pour être lue par un public plus large.) Le côté ouvert de l'IETF est précisé dans le RFC 6852, le processus de création des normes dans le RFC 2026.
Une question difficile dans l'appel à commentaires était « quels recouvrements y a-t-il entre votre activité et celles d'autres organisations ou groupes ? » D'abord, la réponse met en avant le fait que les participants à l'IETF sont souvent membres d'autres organisations. (On parle de « participants » car l'IETF n'a pas de mécanisme d'adhésion formel.)
Ensuite, l'IETF a évidemment des activités qui s'approchent de très près de celles d'autres groupes, avec parfois des discussions sur la frontière. Ainsi, le RFC 6761, qui fait l'objet de beaucoup de débats en ce moment, prévoit un mécanisme d'enregistrement de noms de domaine par l'IETF, alors que certains voudraient que cela soit un monopole de l'ICANN. C'est aussi le cas des adresses IP (mais cela suscite bien moins d'intérêt car c'est plus important mais moins spectaculaire). Ainsi, si l'IANA gère l'espace d'adressage IP, l'IETF alloue également des portions de cet espace (RFC 7020, RFC 7249, et un exemple concret, les ULA du RFC 4193). Il y a aussi bien sûr des recouvrements envers ce que fait l'IETF, et le travail des opérationnels qui décident (ou pas) de déployer les protocoles normalisés. Par exemple, la gestion des serveurs racine du DNS est à la fois un secteur de l'IETF (RFC 7720) et des opérateurs de ces serveurs.
Les activités de l'IETF concernant IP et le routage l'amènent par contre du côté des RIR (par exemple lorsque l'IETF a ses propres allocations d'adresse, comme dans le RFC 6890). Un changement de norme technique peut impacter les opérationnels (nouvelles choses à gérer) et les RIR. Ainsi, l'extension de la taille des numéros d'AS de deux à quatre octets (RFC 6793) imposait évidemment aux RIR de changer leur logiciel et leur politique, pour allouer ces nouveaux numéros.
Pour tous ces points, le RFC insiste sur l'importance de la coordination entre ces acteurs, et sur les nombreux contacts que l'IETF maintient avec toutes ces communautés.
L'appel à commentaires de l'ICG demande ensuite comment les politiques sont décidées et comment les conflits sont gérés. Pour l'IETF, les principes figurent dans les RFC 6220 et RFC 5226. En gros, quelqu'un qui veut changer la politique de l'IETF, par exemple modifier le RFC 5226 (c'est justement en cours de discussion) va écrire un premier document, un Internet Draft, essayer de susciter de l'intérêt, en général le faire adopter par un des groupes de travail (à moins qu'un groupe soit créé spécialement), la proposition doit réunir un consensus (RFC 7282) et c'est souvent l'IESG qui prend la décision finale. Le tout est scandé par des last calls où les organisateurs demandent aux participants un dernier avis avant que le document n'avance. (Pour le fonctionnement des groupes de travail, on peut lire le RFC 2418, mais il n'est plus complètement à jour.)
Et les conflits ? Ils sont normalement réglés dans les groupes de travail mais, si c'est grave, la section 6.5 du RFC 2026 décrit un mécanisme d'appels successifs.
Un concept souvent cité en ce moment dans les discussions autour de l'ICANN et celui de redevabilité (accountability). L'organisation est-elle redevable à quelqu'un, ou bien est-ce un clan mafieux fermé qui décide de tout en interne et ne rend de comptes à personne (comme le CIO ou la FIFA) ? L'appel à commentaires demande donc de la documentation sur les mécanismes de redevabilité du répondeur. Pour l'IETF, c'est l'IAB qui joue ce rôle, en confirmant (ou pas) les nominations et en traitant les appels mentionnés un peu plus haut. C'est aussi l'IAB qui gère les canaux de communication (liaisons) avec les autres organisations. Et c'est l'IAB qui décide quel opérateur gère les registres de paramètres de protocole, actuellement l'ICANN via sa fonction IANA. L'IAB est officiellement décrite dans le RFC 2850. Elle est elle-même redevable devant les participants à l'IETF, par son mécanisme de désignation (RFC 3777).
Quel est le degré de formalisation de votre relation avec l'IANA, demande ensuite l'appel à commentaires ? Un MoU existe (RFC 2860). Son suivi quotidien est assuré par l'IAD (IETF Administrative Director), lui-même sous contrôle de l'IAOC (IETF Administrative Oversight Committee, cf. RFC 4071). Une de leurs tâches est de suivre les rapports de l'IANA sur ses résultats.
En théorie, si un conflit grave surgissait entre l'IETF et l'IANA, l'IETF pourrait mettre fin au travail en commun et choisir un nouvel opérateur pour ses registres (et ce RFC serait alors sans objet). Mais cela ne s'est jamais produit et une telle perspective semble peu probable.
L'appel à commentaires demande aussi à ceux qui répondent d'indiquer de quelle juridiction ils dépendent et quelles sont les lois qui leur sont applicables. L'IETF répond que son activité est mondiale (ce qui est vrai) et que les textes entre l'IANA et l'IETF ne spécifient pas de juridiction (ce qui est exact mais incomplet : l'IETF étant une activité de l'ISOC, l'IETF dépend de la juridiction états-unienne, comme le montrent, par exemple, les injonctions reçues).
Commencent ensuite les questions sensibles, par exemple les demandes de suggestions concernant les mécanismes futurs qui remplaceraient la NTIA. La réponse du RFC est qu'aucun changement n'est demandé par l'IETF : le système actuel avec l'IETF, l'ICANN, l'IAB, etc, a bien fonctionné, sans implication du NTIA, et n'a donc aucun besoin d'être remplacé ou « amélioré ». Les RFC 2860 et RFC 6220 fournissent un cadre satisfaisant et le résultat l'est également.
Cette partie de la réponse contient quand même quelques souhaits, pas forcément de changement mais de points importants à garder en tête :
Et le RFC réaffirme les principes que l'IAB avait posé en mars 2014 :
J'avais signalé plus haut que la NTIA avait posé un certain nombre d'exigences pour accepter un éventuel plan de transition. La suite de l'appel à commentaires rappelle ces exigences et demande dans quelle mesure les propositions faites sont conformes à ces oukases. D'abord, la NTIA demande de « continuer avec le modèle multi-partiesprenantes » (ne me demandez pas de définir ce modèle...) L'IETF répond qu'en tant qu'organisation ouverte à tous, elle suit déjà ce modèle (même réponse à la demande de la NTIA que le futur éventuel système « conserve l'ouverture de l'Internet »). Ensuite, la NTIA exige de préserver « la sécurité et la stabilité du DNS » (une des phrases les plus citées dans les milieux de la gouvernance Internet...) L'IETF ne proposant pas de changement, la stabilité est certainement préservée. Puis le gouvernement états-unien veut que les propositions « satisfassent les utilisateurs et répondent à leurs besoins ». Le RFC estime que l'utilisation massive dans le monde des protocoles TCP/IP et donc des registres de l'IANA montre clairement que les utilisateurs sont contents. Dernier ordre de la NTIA : que la solution future ne soit pas multi-gouvernementale (rappelons que le mécanisme actuel de supervision de l'ICANN est mono-gouvernemental). L'IETF réplique que l'IAB n'est pas une organisation gouvernementale et que l'ordre est donc suivi.
L'appel à commentaires de l'ICG demande également par quel processus la réponse a été élaborée, une bonne façon de vérifier que le répondant a appliqué ses beaux principes, y compris lors de la conception de sa réponse. L'IETF explique que la réponse a été développée par le groupe de travail IANAPLAN, qui, comme tous les groupes de travail de l'IETF, était ouvert à tous et faisait tout son travail publiquement (cf. les archives de la liste de diffusion du groupe). Pour le montrer, comme le demande l'appel à commentaire, l'IETF cite de nombreux documents publiquement accessibles :
Le RFC estime que tout ce processus montre un net consensus de
l'IETF en faveur de cette réponse. Quelques points sont restés
contentieux jusqu'au bout (comme la demande que le nom de domaine
iana.org
soit transféré à l'IETF Trust).
Quelques lectures supplémentaires sur cette opération de transition :
.gov
et .mil
),Date de publication du RFC : Octobre 2016
Auteur(s) du RFC : M. Stiemerling (Hochschule
Darmstadt, S. Kiesel (University of
Stuttgart), M. Scharf
(Nokia), H. Seidel
(BENOCS), S. Previdi (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF alto
Première rédaction de cet article le 22 novembre 2016
Il est fréquent aujourd'hui sur l'Internet qu'une application cherche à accéder à un contenu (mettons un film, ou bien la mise à jour d'un gros logiciel) qui est disponible à plusieurs endroits. Dans ce cas (qui est notamment fréquent pour le téléchargement en pair-à-pair), quelle source utiliser ? La « meilleure », bien sûr, mais comment la connaître ? Le but du protocole ALTO est de permettre de distribuer de l'information sur la topologie du réseau, afin que les applications puissent choisir la source la plus proche d'elles. ALTO est déjà normalisé (RFC 7285), ce nouveau RFC sert juste à décrire les scénarios d'usage et à donner des conseils pratiques de déploiement (déploiement qui semble très limité pour l'instant).
Outre le RFC décrivant le protocole (RFC 7285), il peut être utile de lire la description du problème qu'ALTO veut résoudre, le RFC 5693, et le cahier des charges, dans le RFC 6708.
La section 2 de notre RFC résume le fonctionnement d'ALTO. C'est un protocole client-serveur, le serveur ALTO connait l'information (la topologie du réseau, qui est connecté à qui, par quel genre de liens), le client est l'application qui veut accéder au contenu, il connait un ensemble potentiel de sources, et il veut savoir quelle est la « meilleure ». Par exemple, dans le cas de BitTorrent, le client a les adresses IP de l'essaim, il veut savoir à laquelle ou lesquelles demander les bouts de fichier (chunks) qui forment le contenu. Le client ALTO peut être un processus séparé, tournant en permanence, ou bien une bibliothèque liée à l'application. Il doit évidemment parler le protocole ALTO, donc connaitre HTTP et JSON.
Pour déployer ALTO, il y a donc quatre entités logiques à considérer :
Ces entités sont typiquement gérées par des organisations différentes. Un exemple typique (mais ce n'est pas la seule possibilité) est que le FAI soit à l'origine de l'information (il connait son réseau), et la mette dans un serveur ALTO qu'il gère, ses abonnés ayant installé une application de partage de fichiers qui inclut un client ALTO. Dans ce cas, il y aurait deux organisations, le FAI gérant les deux premières entités et l'abonné les deux dernières. Mais d'autres répartitions peuvent exister.
Les organisations qui peuvent être impliquées sont en effet multiples : FAI et opérateurs réseau, bien sûr, utilisateurs, évidemment (agissant, soit seuls, soit en groupes se répartissant le travail), mais aussi des tiers, spécialisés dans la collecte et la distribution de cette information (par exemple des CDN). On pourrait même voir apparaitre des sociétés qui ne font que de l'ALTO.
Tout ceci a des conséquences sur le déploiement. Par exemple, un utilisateur peut faire confiance à un FAI mais pas à des tiers. Un FAI peut souhaiter distribuer de l'information à ses abonnés mais pas à tout l'Internet. ALTO définit un protocole, pas une politique : ce protocole permet différents modèles, y compris celui de serveurs ALTO spécialisés et payants. Autre conséquence de l'utilisation de telle ou telle répartition du travail, on pourrait avoir des serveurs ALTO partiels, qui ne contiennent de l'information que sur certains réseaux.
Dans tous les cas, le RFC rappelle qu'ALTO est juste une optimisation : une application doit fonctionner même si elle ne trouve aucun serveur ALTO, ou bien s'ils sont en panne.
Un petit rappel utile sur ALTO : il existe deux modes de
fonctionnement différents, qui ont tous les deux des conséquences
importantes, notamment sur la confidentialité. Dans le premier
mode, le serveur ALTO fournit l'information qu'il a (sous forme de
maps, des ensembles de données sur le réseaux,
les liens, leur coût, etc) et le client
cherche dedans ce qui l'intéresse. Ce mode préserve la vie privée
du client (qui ne dit pas au serveur ce qui l'intéresse) mais pas
celle du serveur (qui doit tout envoyer). Il n'est pas évident que
beaucoup de FAI acceptent cela. Dans le second mode, le
serveur permet des interrogations sur un point particulier (« qui
est le plus proche de moi ? 192.0.2.87
,
203.0.113.122
ou bien
198.51.100.20
? »). Ce mode évite au serveur
de tout divulguer mais oblige en revanche le client à révéler ses
intentions (ici, les adresses IP des pairs potentiels, ce qui peut
intéresser des organisations répressives comme la
HADOPI). Notez que la fuite d'informations
du serveur
existe aussi dans le second mode : plusieurs clients ALTO peuvent
coopérer pour poser beaucoup de questions et extraire ainsi une
partie substantive de la base.
La partie 3 de notre RFC en vient aux conseils concrets pour les FAI. On considère que l'objectif du FAI est de minimiser ses coûts, donc a priori de garder le maximum de trafic en local (il y a des exceptions, que liste le RFC). Le serveur ALTO que gère le FAI va donc annoncer des coûts plus faibles pour les liens locaux.
Mais, d'abord, le FAI doit « remplir » le serveur ALTO avec de l'information. Cette étape d'avitaillement commence par la récolte d'informations sur le réseau. A priori, le FAI connait son propre réseau, et n'a donc pas de mal à récolter ces informations. Outre sa propre documentation interne, le FAI peut aussi utiliser de l'information issue d'autres sources, par exemple les protocoles de routage comme BGP (cf., entre autres, le RFC 7752) ou bien des mesures actives ou passives (cf. entre autres, le RFC 7491). Rappelez-vous qu'ALTO est uniquement un protocole permettant d'accéder à de l'information sur la topologie. Comment cette information a été récoltée et agrégée n'est pas de la responsabilité d'ALTO, de même que le protocole HTTP ne se soucie pas de comment est fabriquée la page HTML qu'il sert.
Le FAI doit ensuite appliquer ses critères (coût, performance, etc) à la topologie. Ces critères sont forcément imparfaits. Le client ALTO ne doit pas s'attendre à ce que l'information qui lui est donnée soit idéale dans tous les cas. Par exemple, le serveur ALTO peut indiquer un lien rapide et pas cher mais qui, au moment où le téléchargement commencera, sera saturé par un trafic intense (ALTO ne prétend pas être temps-réel). Et il y a bien d'autres choses qui ne seront pas connues de ceux qui ont compilé l'information, ou bien qui n'auront pas été incluses dans la base de données du serveur ALTO (« la carte n'est pas le territoire »). Les données distribuées par ALTO, les maps, sont supposées être relativement statiques. Mais, dans le monde réel, les choses changent et le client recevra donc peut-être une information légèrement dépassée.
Si vous trouvez le concept de map un peu abstrait, la section 3.5 du RFC donne plusieurs exemples. Par exemple, dans le cas le plus simple, celui d'un petit FAI ayant un seul opérateur de transit, les adresses dudit FAI seront dans le PID (Provider-defined IDentifier, cf. RFC 7285, section 5.1) 1, tout le reste de l'Internet étant le PID 2. Cela donnera une map (syntaxe décrite dans le RFC 7285, section 9.2) :
{ ... "network-map" : { "PID1" : { "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25" ], "ipv6" : [ "2001:db8:100::/48" ] }, "PID2" : { "ipv4" : [ "0.0.0.0/0" ], "ipv6" : [ "::/0" ] } } }
Un FAI plus gros, et à la topologie plus complexe, a plein de possibilités. Par exemple, ses propres réseaux peuvent être dans des PID différents, s'il veut pouvoir garder le trafic local à un de ses réseaux. Un exemple est celui où le même FAI a des abonnés fixes et mobiles, et où on souhaite limiter les transferts des abonnés fixes vers les mobiles, pour réduire l'utilisation des liens hertziens.
Reste ensuite à effectuer le déploiement des serveurs ALTO. Il
existe plusieurs mises en œuvre logicielles d'ALTO et des compte-rendus d'expérience figurent dans
les Internet-Drafts
draft-seidel-alto-map-calculation
et draft-lee-alto-chinatelecom-trial
et dans le RFC 6875
(ainsi que, pour un protocole antérieur à ALTO, dans le RFC 5632). Cette
expérience montre que certaines façons de collecter l'information
peuvent être coûteuses : si un FAI a plusieurs liens avec
l'Internet, et reçoit un flux BGP complet,
et veut mettre chaque préfixe de la DFZ
dans ses maps, il doit prévoir des machines
assez costaud pour traiter cette information importante et assez
changeante. Et le résultat serait une map qu'il
serait difficile d'envoyer à tous les clients, vu sa taille. Il
faut donc prévoir, dans ce cas extrême, de l'agrégation vigoureuse
des préfixes IP.
La section 4 de notre RFC couvre ensuite l'utilisation d'ALTO, une fois qu'il est déployé. Normalement, tout le monde a intérêt à ce que ALTO soit utilisé : le FAI veut que les utilisateurs épargnent les liens réseaux les plus lents et les plus coûteux et les utilisateurs veulent les meilleures perfomances. En théorie, tout le monde trouvera son intérêt à utiliser ALTO.
Un exemple est celui de BitTorrent. Si les pairs BitTorrent incluent un client ALTO, chaque pair, quand il reçoit une liste d'adresses IP de l'essaim, peut alors interroger le serveur ALTO et trouver les « meilleurs » pairs. Ils peuvent même échanger cette information entre eux (PEX, Peer EXchange, dans le monde BitTorrent). Mais une autre possibilité est que ce ne soient pas les pairs qui interrogent le serveur ALTO mais le tracker (pour les essaims fonctionnant avec une machine qui sert de tracker, ce qui n'est pas toujours le cas). Ainsi, il n'est pas nécessaire de mettre un client BitTorrent dans chaque pair, c'est le tracker qui, grâce à l'information ALTO, choisit les meilleurs pairs pour chacun, et ne leur envoie que cela.
Le RFC se conclut pas une section 7 sur la sécurité. Parmi les problèmes à considérer, il y a le fait qu'un serveur ALTO malveillant, ou bien un serveur se faisant passer pour un serveur ALTO légitime, peut empoisonner le client avec de fausses données.
Date de publication du RFC : Novembre 2016
Auteur(s) du RFC : R. Danyliw (CERT)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF mile
Première rédaction de cet article le 1 décembre 2016
Pour rendre plus facilement analysables les innombrables rapports d'incidents de sécurité qui circulent sur Internet tous les jours, ce RFC spécifie un format standard XML, nommé IODEF, pour décrire ces incidents. Ici, il s'agit de la version 2 de ce format IODEF, la version 1 était dans le RFC 5070.
Tous les jours, des organisations comme les CERT et CSIRT, mais aussi les OIV, envoient et reçoivent des rapports détaillés concernant une attaque sur un réseau informatique ou un serveur. Ces rapports sont longs et détaillés mais, la plupart du temps, ce n'est pas une attaque isolée qui est intéressante, c'est l'image qui apparait lorsqu'on synthétise tous les rapports, et qu'on voit alors les tendances, par exemple l'arrivée d'un nouveau ver ou bien une attaque concertée contre un pays donné. D'où l'importance de pouvoir analyser automatiquement ces rapports, ce qui impose un modèle de données et un format standard, ce que fournit ce RFC.
Le modèle de données est proche des modèles
objet, par
exemple dans la descriptions des classes d'objets
manipulés (comme la classe Incident en section 3.2, avec la
cardinalité des attributs). Ces classes sont
composés avec des données élémentaires (booléens, entiers, dates)
décrites dans la section 2. Par exemple, parmi les attributs de la
classe Incident
, on trouve l'heure de début et de
fin de l'incident, l'heure de détection, etc. Le schéma XML complet, écrit en W3C Schema,
figure dans la section 8.
On trouve énormément de choses dans ce schéma (le RFC fait plus de
160 pages), pour traiter tous les cas prévus. Par exemple, on peut
exprimer une liste de ports comprenant à la fois des ports
individuels et des intervalles :
22,53,80,1024-2047
. De nombreuses classes
existent pour utiliser ces informations élémentaires. Ainsi, la classe
Discovery
, une nouveauté de la version 2, permet
d'indiquer comment l'incident a été découvert (avec un attribut
source
qui a vingt valeurs possibles, comme
av
- antivirus,
os-log
- journal,
passive-dns
- un système comme DNSdb, etc). Et
BusinessImpact
permet de décrire les conséquences
de l'incident sur l'activité (breach-privacy
,
loss-of-service
,
theft-financial
, etc). Ça peut même se quantifier
financièrement avec la classe MonetaryImpact
. Si
on met les incidents de sécurité dans une base de données (ça
s'appelle un SIEM, comme Prelude), on peut donc imaginer de regarder
d'abord les incidents qui ont coûté le plus cher...
Voici un exemple d'un rapport d'incident, tiré du RFC (section 7), et qui
décrit et qui décrit les systèmes de C&C
(quatre serveurs)
d'une campagne donnée (dans le RFC 5070,
l'exemple était une simple reconnaissance avec
nmap...). Cet exemple a l'avantage d'illustrer
la classe IndicatorData
, une nouveauté de la
version 2 :
<?xml version="1.0" encoding="UTF-8"?> <!-- A list of C2 domains associated with a campaign --> <IODEF-Document version="2.00" xml:lang="en" xmlns="urn:ietf:params:xml:ns:iodef-2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "https://www.iana.org/assignments/xml-registry/schema/ iodef-2.0.xsd"> <Incident purpose="watch" restriction="green"> <IncidentID name="csirt.example.com">897923</IncidentID> <RelatedActivity> <ThreatActor> <ThreatActorID> TA-12-AGGRESSIVE-BUTTERFLY </ThreatActorID> <Description>Aggressive Butterfly</Description> </ThreatActor> <Campaign> <CampaignID>C-2015-59405</CampaignID> <Description>Orange Giraffe</Description> </Campaign> </RelatedActivity> <GenerationTime>2015-10-02T11:18:00-05:00</GenerationTime> <Description>Summarizes the Indicators of Compromise for the Orange Giraffe campaign of the Aggressive Butterfly crime gang. </Description> <Assessment> <BusinessImpact type="breach-proprietary"/> </Assessment> <Contact type="organization" role="creator"> <ContactName>CSIRT for example.com</ContactName> <Email> <EmailTo>contact@csirt.example.com</EmailTo> </Email> </Contact> <IndicatorData> <Indicator> <IndicatorID name="csirt.example.com" version="1"> G90823490 </IndicatorID> <Description>C2 domains</Description> <StartTime>2014-12-02T11:18:00-05:00</StartTime> <Observable> <BulkObservable type="fqdn"> <BulkObservableList> kj290023j09r34.example.com 09ijk23jfj0k8.example.net klknjwfjiowjefr923.example.org oimireik79msd.example.org </BulkObservableList> </BulkObservable> </Observable> </Indicator> </IndicatorData> </Incident> </IODEF-Document>
Le RFC note sagement que le partage d'informations n'est pas uniquement une question technique, mais qu'elle dépend aussi des procédures bureaucratiques de chaque organisation, des contraintes légales, de la confiance (ou de l'absence de confiance, souvent justifiée) et enfin de la simple bonne ou mauvaise volonté. (Mon opinion personnelle est que, en France, le partage d'informations précises sur les incidents de sécurité est très insuffisant.)
Les changements depuis la version 1 (celle du RFC 5070) sont listés dans la section 1.4. Beaucoup de détails, beaucoup d'ajouts, parmi lesquels je note :
Contact
permette désormais d'indiquer une
adresse postale en un jeu de caractères quelconque,IndicatorData
ou
Discovery
cités
plus haut, ou comme DomainData
, pour des
informations sur un nom de domaine), et nouveaux attributs dans les classes
existantes (par exemple, Incident
y gagne
observable-id
, un identificateur qui peut être
utilisé dans des références croisées).
Si l'ajout de nouvelles classes ne rendent pas les anciennes
descriptions IODEF incorrectes, en revanche, certains changements cassent la compatibilité et un fichier
IODEF version 1 parfait ne sera pas forcément légal pour la version
2 (cf. section 4.4). Par exemple, la sous-classe
NodeRole
(qui permet de décrire si on est attaqué
par
une caméra de vidéosurveillance
ou bien par un routeur) a changé
de classe parente.
Et les mises en œuvre d'IODEF ? Un résumé de l'état de ces mises
en œuvre figure dans
l'Internet-Draft
draft-ietf-mile-implementreport
,
et qui référence une liste des programmes
IODEF (j'ai aussi trouvé celle-ci). Parmi d'autres, on peut noter la bibliothèque de
Prelude (et qui a une version pour l'IODEF v2 de
notre RFC), un
module Perl, un autre en
PHP, et un troisième
en Python. On trouve aussi des
moyens de connecter IODEF à des logiciels existants par exemple au
logiciel de suivi de tâche
Mantis, avec ce connecteur.
Pour des articles ou présentations sur IODEF, vous pouvez voir la Rump (session rapide) de Thomas Andrejak au SSTIC 2016 (vidéo en ligne).
Notez en France l'existence du projet SECEF (SECurity Exchange Format) qui a pour objectif de promouvoir et de faciliter l’usage des deux formats de fichier IDMEF (RFC 4765) et IODEF. Vous pouvez consulter leur Wiki, et leur tutoriel IODEF. Il y a aussi un article de synthèse sur SECEF, et un compte-rendu d'une de leurs réunions (mais vite fait et avec des erreurs). Enfin, le RFC 8274 donne quelques conseils sur la mise en œuvre d'IODEF.
Date de publication du RFC : Août 2016
Auteur(s) du RFC : J. Saldana (University of
Zaragoza), A. Arcia-Moret (University of
Cambridge), B. Braem
(iMinds), E. Pietrosemoli (The Abdus Salam
ICTP), A. Sathiaseelan (University of
Cambridge), M. Zennaro (The Abdus Salam ICTP)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF gaia
Première rédaction de cet article le 17 septembre 2016
On pourrait croire que la seule façon d'accéder à l'Internet est via un FAI commercial, géré hiérarchiquement (avec directeur, plein de sous-directeurs, etc), dont les utilisateurs paient pour bénéficier de l'accès (mais sans avoir leur mot à dire sur le fonctionnement du FAI), et disposant de grands moyens financiers et techniques. C'est certainement la vision dominante et elle arrange bien les gens des médias et des gouvernements, qui se retrouvent dans une situation connue, avec un petit nombre d'acteurs « professionnels ». Heureusement, l'Internet n'est pas comme cela : c'est une confédération de réseaux très variés, certains effectivement gérés comme indiqué plus haut, mais d'autres fonctionnant sur des modèles très différents, ayant fait des choix techniques, de gouvernance et de financement très différents et très variés. Cet excellent RFC décrit et classe les réseaux « alternatifs ».
Il a été écrit dans le cadre du groupe de recherche GAIA (Global Access to the Internet for All) de l'IRTF. GAIA vise à documenter ces déploiements « alternatifs » et à faciliter le partage d'expérience. Outre le simple rappel de l'existence de ces réseaux « alternatifs », son mérite est de proposer une taxonomie de ces réseaux (forcément imparfaite, vu leur variété) et de donner une idée de la variété des technologies qu'ils utilisent.
Ces techniques sont en effet souvent différentes de celles utilisées dans les réseaux « officiels » (mainstream). Ces réseaux « alternatifs » visent en général des situations difficiles, comme la connexion de lieux lointains, où l'argent ne coule pas à flots. À part cela, ces réseaux n'ont rien en commun, ni leur organisation, ni leurs buts. Qu'est-ce qui motive leur création ? (Au passage, le RFC fait comme si ces réseaux « alternatifs » étaient une création récente ; certains sont au contraire aussi vieux que l'Internet.) Les raisons de ces projets sont elles aussi très diverses : absence pure et simple de FAI commercial, insatisfaction vis-à-vis des FAI officiels existants, désir d'essayer quelque chose d'autre...
Passons au difficile jeu des définitions. Le RFC (section 1.1) définit le réseau « officiel » (mainstream) ainsi :
Et les réseaux « alternatifs », comment se définissent-ils (section 1.2) ? C'est plus difficile car il en existe de nombreuses variantes :
Ce problème des définitions est évidemment très présent dans tout le RFC. Par exemple, comment parler des pays qui ne sont pas les membres de l'OCDE (et encore, l'OCDE compte deux ou trois membres « intermédiaires ») ? Le Tiers-Monde ? Le Sud ? Les pays pauvres ? Les sous-développés ? Les « en voie de développement » ? La section 2 du RFC propose des définitions :
Maintenant, les cas où on déploie ces réseaux « alternatifs » (section 3 du RFC). Il y aurait actuellement 60 % de gens sur Terre sans connectivité Internet. Et la répartition est très inégale (20 % sans connexion au « Nord », 69 % au « Sud »). Parmi les facteurs qui vont intervenir :
Dans les zones rurales, on a vu que c'était souvent pire. Johnson, D., Pejovic, V., Belding, E., et G. van Stam, dans leur article « Traffic Characterization and Internet Usage in Rural Africa » (In Proceedings of the 20th International Conference Companion on World Wide Web) rapportent des latences mesurées à plusieurs secondes. Les problèmes des zones rurales sont souvent cruciaux : faible revenu monétaire, manque d'infrastructures de base comme l'électricité et les routes, densité de population réduite, manque de compétences (les techniciens compétents quittent rapidement ces zones pour aller en ville), etc.
La section 4 de notre RFC s'attaque ensuite au difficile problème de la classification de ces réseaux « alternatifs ». Sur quels critères faire cette classification ? Les auteurs du RFC en trouvent cinq. D'abord, quelle organisation gère le réseau ? Un groupe plus ou moins formel d'utilisateurs ? Une collectivité publique ? Une société privée ? Un organisme de recherche ou d'enseignement ? (En France, on aurait ajouté « Une association loi 1901 ? »)
Second critère de classification, le but de la création de ce réseau : fournir un accès qui n'existerait pas du tout autrement ? Fournir une alternative bon marché ? Expérimenter et tester ? S'attaquer à d'autres problèmes de fracture numérique (comme la littératie numérique) ? Fournir un accès d'urgence suite à une catastrophe ? Ou bien un but plus politique, par exemple des mécanismes de gouvernance différents, une approche davantage « bien commun » ? Ou fournir un accès libre et neutre, contrairement à ce que font la quasi-totalité des FAI ? (Ce dernier point est présenté de manière très modérée dans le RFC qui, globalement, évite de parler des choses qui fâchent, comme la politique.)
Bien sûr, un réseau alternatif peut avoir plusieurs de ces mobiles. Et ceux-ci peuvent être plus ou moins explicites, et ils évoluent dans le temps. Le réseau Redhook avait commencé plutôt comme outil local, avant de devenir le seul réseau à fonctionner après Sandy.
Un autre critère, proche du premier, est celui du modèle de gouvernance : très ouvert, avec une participation active des utilisateurs, ou bien plus traditionnelle, avec une organisation centrale qui s'occupe de tout ? (On peut avoir un réseau qui est la propriété d'un groupe d'utilisateurs mais qui, en pratique, est géré par une petite organisation structurée.)
Autre critère, qui va plaire aux techniciens, quelles sont les techniques employées dans ce réseau ? Wi-Fi traditionnel ? Wi-Fi modifié pour les longues distances (WiLD) ? WiMAX ? Espaces blancs de la télévision (cf. RFC 7545) ? Satellite comme dans le projet RIFE ? Voire des fibres optiques terrestres ?
Enfin, dernier critère de classification, le contexte : zone rurale ou urbaine, Nord ou Sud.
Avec ces critères, on peut maintenant procéder à la classification (section 5 du RFC). Notre RFC distingue (un peu arbitrairement) six catégories, caractérisées par les réponses à ces cinq critères. Première catégorie, les réseaux d'un groupe local (community networks). Géré par un groupe de citoyens proches, ils ont typiquement un fonctionnement très ouvert et participatif. Leur croissance est en général non planifiée et non organisée : les premiers membres se connectent puis d'autres volontaires les rejoignent. Le mécanisme de décision est la plupart du temps très décentralisé. En général, ils utilisent le Wi-Fi et chaque membre contribue donc à la croissance du réseau « physique » sous-jacent. Plusieurs exemples de tels réseaux sont décrits dans l'article de Braem, B., Baig Vinas, R., Kaplan, A., Neumann, A., Vilata i Balaguer, I., Tatum, B., Matson, M., Blondia, C., Barz, C., Rogge, H., Freitag, F., Navarro, L., Bonicioli, J., Papathanasiou, S., et P. Escrich, « A case for research with and on community networks », et une analyse technique détaillée d'un réseau d'un groupe local figure dans Vega, D., Baig, R., Cerda-Alabern, L., Medina, E., Meseguer, R., et L. Navarro, « A technological overview of the guifi.net community network ».
Seconde catégorie, les WISP (Wireless Internet Service Providers). Cette fois, le réseau est géré par une société traditionnelle, mais il est « alternatif » par le public visé (typiquement des régions rurales mal desservies, où l'infrastructure est minimale, et où les FAI traditionnels ne vont pas). C'est par exemple le cas de la société Airjaldi en Inde, ou d'EveryLayer.
Troisième catégorie de réseaux alternatifs, l'infrastructure partagée (Shared Infrastructure model). L'infrastructure du réseau est partagée entre un opérateur traditionnel et les utilisateurs. C'est le cas lorsque les utilisateurs détiennent le matériel (par exemple femtocell) mais que la gestion est assurée par un FAI. Les utilisateurs sont payés, soit directement par le FAI qui leur loue l'infrastructure, soit indirectement par l'accès à l'Internet qu'ils obtiennent via ce FAI. Dans pas mal de régions rurales dans le monde, la 3G a été déployée ainsi, via les femtocells. Prévue à l'origine pour fournir une meilleure couverture dans les bâtiments, cette technologie peut aussi être utilisée pour fournir des accès aux téléphones mobiles sans que l'opérateur ait eu à supporter de gros investissements.
Un exemple d'infrastructure partagée est le projet TUCAN3G, en utilisant WiLD Ce projet est décrit par Simo-Reigadas, J., Morgado, E., Municio, E., Prieto-Egido, I., et A. Martinez-Fernandez dans « Assessing IEEE 802.11 and IEEE 802.16 as backhaul technologies for rural 3G femtocells in rural areas of developing countries » et par Simo-Reigadas, J., Municio, E., Morgado, E., Castro, E., Martinez-Fernandez, A., Solorzano, L., et I. Prieto- Egido dans « Sharing low-cost wireless infrastructures with telecommunications operators to bring 3G services to rural communities ».
Autre catégorie possible, les approches « foule de volontaires » (Crowdshared approaches) où des utilisateurs qui ne se connaissent pas forcément mettent la main au portefeuille pour participer à un projet commun, qui sera géré par une une société ou par eux-mêmes. Typiquement, les utilisateurs mettent à la disposition de tous une partie de leur capacité réseau, et l'entité qui gère le réseau est une simple coordination, elle ne possède rien. C'est ce que promeut le mouvement OpenWireless. Parmi les exemples, on peut citer des sociétés comme FON, les projets municipaux comme décrit dans l'article de Heer, T., Hummen, R., Viol, N., Wirtz, H., Gotz, S., et K. Wehrle, « Collaborative municipal Wi-Fi networks- challenges and opportunities », ou les réseaux Wi-Fi de Sathiaseelan, A., Crowcroft, J., Goulden, M., Greiffenhagen, C., Mortier, R., Fairhurst, G., et D. McAuley, « Public Access WiFi Service (PAWS) ».
Il y a aussi des réseaux montés par des coopératives en milieu rural, ce qui forme la cinquième catégorie identifiée. Ce genre de coopératives fournissant un service local est courant et ancien. Le RFC cite l'exemple des États-Unis où l'électricité en milieu rural est souvent fournie ainsi, et ce depuis les années 1930. Ces coopératives peuvent même passer leurs propres fibres optiques (« CO-MO'S D.I.Y. model for building broadband »). Des partenariats sont possibles avec ceux qui fournissent d'autres services que l'Internet, comme l'électricité dans l'exemple ci-dessus. Deux exemples sont donnés dans l'article de Mitchell « Broadband at the Speed of Light: How Three Communities Built Next-Generation Networks » ou dans le guide « Broadband Guide for Electric Utilities ».
Enfin, dernière catégorie de réseau alternatif, ceux créés à des fins de recherche. Par exemple, le réseau est créé par une université pour explorer une technique et/ou des usages (comme Bernardi, B., Buneman, P., et M. Marina, « Tegola tiered mesh network testbed in rural Scotland »).
Après cette catégorisation des réseaux alternatifs, penchons-nous sur les technologies utilisées (section 6 du RFC). Le cas de réseaux filaires est rare mais existe (comme à Lowenstedt ou dans certains endroits de Guifi.net). La plupart du temps, les réseaux alternatifs utilisent l'hertzien. Les normes techniques en œuvre sont en général celles du groupe IEEE 802.
La plus connue est évidemment Wi-Fi (802.11). Mais on trouve aussi du GSM (une norme ETSI) par exemple dans un village mexicain ou dans le projet Village Base Station. Il y a même du GSM en logiciel libre, dans les projets OpenBTS ou OpenBSC. Ces projets sont en train de migrer vers des technologies plus rapides (mais, ce que le RFC oublie de dire, bien moins libres, notamment car pourries de brevets) comme la 4G.
On a signalé plus haut que certains réseaux peuvent utiliser les espaces blancs laissés par la télévision, découvrant les fréquences utilisables via une base de données (RFC 7545) ou bien en regardant le trafic existant pour voir si l'espace est vraiment blanc.
Le Wi-Fi est limité en portée, et certains réseaux utilisent des techniques plus adaptées aux longues distances comme WiMAX (IEEE 802.16) ou bien 802.22, qui utilise justement ces espaces blancs.
Et dans les couches au-dessus de ces couches 1 et 2, quelles techniques utilisent les réseaux alternatifs ? La section 7 du RFC décrit rapidement les divers choix. D'abord, la couche 3. La plupart des réseaux n'utilisent qu'IPv4 et, ne pouvant pas obtenir suffisamment d'adresses IP des RIR sans gros efforts, se limitent aux adresses IP privées du RFC 1918. (Avant l'épuisement des adresses IPv4, obtenir des adresses des RIR était plus simple que beaucoup de gens ne le croyaient, mais il fallait quand même se taper une bureaucratie complexe et des règles difficiles.)
Pour la plupart des réseaux alternatifs, IPv6 était déjà normalisé depuis longtemps lorsqu'ils ont démarré leur projet. Mais peu l'utilisent (ninux.org est une exception), probablement essentiellement par ignorance. (Le questionnaire « Questionnaire based Examination of Community Networks » incluait des questions sur IPv6).
Pour le routage, les choix dépendent souvent de la structure du réseau alternatif. Certains sont de type mesh, avec peu ou pas d'autorité centrale, d'autres sont plus structurés. Il y a donc des protocoles de routage traditionnels comme OSPF (le RFC cite aussi BGP, ce qui me surprend pour un réseau alternatif).
Mais il y a aussi des protocoles prévus pour des réseaux moins
structurés, comme ceux utilisés dans les
MANET. On peut trouver de
l'OLSR (RFC 3626),
parfois dans des versions modifiées (ce qui est le cas de http://olsr.org/
), ou parfois sa récente version 2 (RFC 7181). D'autres réseaux utilisent du
BATMAN. Le RFC cite l'excellent
Babel (RFC 8966) mais
n'indique pas s'il est très employé sur le terrain (il semble
moins connu, dans un milieu où l'information circule mal).
Et la couche au-dessus, la couche transport ? L'un des problèmes que doit traiter cette couche est celui de la congestion : il faut assurer le partage de la capacité réseau entre plusieurs acteurs. Dans les réseaux alternatifs, pas forcément gérés centralement, et aux frontières pas toujours nettement délimitées, le défi est encore plus important. Il peut donc être intéressant d'enourager des protocoles « raisonnables » (RFC 6297), qui cèdent le pas systématiquement aux autres protocoles, afin que les activités non-critiques ne rentrent pas en compétition avec le trafic « important ».
Enfin, les utilisateurs ne s'intéressent typiquement qu'à une seule chose, les services, et il est donc utile de se demander ce que ces réseaux alternatifs proposent. Il y a bien sûr tous les services de base, notamment le Web. Certains services très répandus (vidéo haute définition, par exemple), peuvent être très coûteux pour les ressources souvent limités du réseau alternatif. Leur utilisation peut donc être restreinte. Et il y a aussi des services spécifiques des réseaux alternatifs : des VPN comme IC-VPN, des portails d'intérêt local comme Tidepools, des télévisions ou radios locales, des systèmes de relais de VoIP pour permettre des appels bon marché, des réseaux de capteurs permettant de la citizen science, etc.
Voilà, c'est terminé, cet article était long mais le RFC est plus long encore, et il se termine par une impressionnante bibliographie dont je n'ai cité que quelques extraits : plein de choses passionnantes à lire.
Date de publication du RFC : Septembre 2016
Auteur(s) du RFC : F. Martin (LinkedIn), E. Lear (Cisco Systems), T. Draegen (dmarcian), E. Zwicky (Yahoo), K. Andersen (LinkedIn)
Pour information
Réalisé dans le cadre du groupe de travail IETF dmarc
Première rédaction de cet article le 11 octobre 2016
Le mécanisme DMARC permet d'indiquer
dans le DNS la politique d'un domaine
concernant l'authentification du courrier. Si je reçois un message
prétendant venir de ma-banque.example
, et
qu'il n'est pas authentifié (ni SPF, ni
DKIM, ni autre chose), comment savoir si
c'est parce que ma banque est nulle en sécurité du courrier, ou bien parce
que le message est un faux ? DMARC (normalisé dans le RFC 7489) permet de répondre à cette
question en publiant un enregistrement qui indique si le courrier
est censé être authentifié ou pas. Comme toutes les techniques de
sécurité, ce mécanisme est imparfait et il pose notamment des
problèmes avec les messages indirects. Par
exemple, si vous avez une adresse à votre ancienne université,
alice@univ.example
et que le courrier qui lui
est adressé est automatiquement transmis à votre adresse
professionnelle, alice@evilcorp.example
,
comment DMARC va-t-il réagir avec cette indirection ? C'est ce
qu'explore ce RFC.
Voici la politique DMARC de Gmail. Elle
est tolérante (p=none
, accepter les messages
non authentifiés) :
% dig TXT _dmarc.gmail.com ... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59294 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ... ;; ANSWER SECTION: _dmarc.gmail.com. 600 IN TXT "v=DMARC1; p=none; rua=mailto:mailauth-reports@google.com" ...
_dmarc.paypal.com. 300 IN TXT "v=DMARC1; p=reject; rua=mailto:d@rua.agari.com; ruf=mailto:dk@bounce.paypal.com,mailto:d@ruf.agari.com"
La question de départ de l'administrateur système est « si je
mets une politique DMARC restrictive (genre
p=reject
), vais-je perdre des courriers
légitimes, à cause d'indirections comme les listes de diffusion ? » (section 1 du
RFC). Il est d'autant plus difficile de répondre à cette question
que l'architecture du courrier électronique
est complexe et mal spécifiée (RFC 5598). Bien des logiciels ne suivent pas les règles,
d'autant plus que beaucoup de ces règles n'ont pas été explicites
dès le début. (Un bon exemple : avec un
.forward
, le serveur de courrier doit-il
garder l'expéditeur indiqué dans l'enveloppe
du message ? Essayez de trouver un RFC qui spécifie cela !)
La section 2 de notre RFC décrit les causes des problèmes
DMARC. Si un message est légitime (le destinataire veut le
recevoir), et qu'il est en outre techniquement correct, un
problème, au sens de ce RFC, est quand la politique de DMARC (qui
peut être de rejet) est appliquée à ce message, parce qu'il a été
transmis indirectement. C'est injuste. Évidemment, si la politique
DMARC est p=none
(ne rien faire), ce n'est
pas un vrai problème. Mais un p=reject
peut
être très ennuyeux.
Première cause de problèmes, des différences entre les
identificateurs utilisés. DMARC n'authentifie pas directement, il
dépend de SPF (RFC 7208) et DKIM (RFC 6376) pour cela. Ce qui intéresse l'utilisateur,
évidemment, c'est le nom dans le champ From:
(RFC 5322)
du message. Pour lui, c'est ça l'expéditeur. Mais DKIM, et surtout
SPF, n'ont pas la même conception : ils peuvent utiliser d'autres
identificateurs. DMARC considère que l'accord
(alignment, cf. RFC 7489, section 3.1) entre les identificateurs
authentifiés par SPF et DKIM, et le champ
From:
du message peut être strict ou
laxiste. « Strict » indique une correspondance parfaite, laxiste
se limite à vérifier que le nom de domaine
est le même.
Le principal identificateur utilisé par SPF est celui donné par
la commande
MAIL FROM
dans la session SMTP (RFC 5321). C'est la principale cause de
désaccord : si SPF authentifie cet identificateur et qu'il est
différent de l'adresse utilisée dans le champ
From:
de l'en-tête du message, que
faire ?
Deuxième cause de problème, le relayage d'un message. Si Bob
bob@isp.example
écrit à
alice@univ.example
, et qu'elle (ou son
administrateur système) a demandé un relayage automatique vers
alice@evilcorp.example
, les serveurs
de courrier de evilcorp.example
verront un
message prétendant être de isp.example
, mais
transmis par les serveurs de
univ.example
... SPF sera content ou pas,
selon la façon exacte dont a été fait le relayage (en préservant
le MAIL FROM
ou pas). DMARC ne sera jamais
content car, si le MAIL FROM
a été changé
(reflétant le relais), SPF authentifiera mais il n'y aura plus
d'accord entre les identificateurs.
Évidemment, si le message est modifié en cours de route, c'est encore pire. SPF ne protège pas l'intégrité du message, mais DKIM le fait. Mais qui diantre se permet de modifier les messages ? Hélas, pas mal de gestionnaires de listes de diffusion le font. DKIM a une option (déconseillée... voir la section 8.2 du RFC 6376) pour ne signer que le début du message, évitant ainsi que la signature soit invalidée par l'ajout, par exemple, d'un paragraphe final. Cela ne couvre que le cas des messages simples, sans MIME, où la modification est un simple ajout à la fin. Autre possibilité de DKIM pour éviter d'invalider les signatures en cas de modification du message, le mode relaxed de canonicalisation du contenu, qui permet de supporter des modifications triviales comme la transformation de N espaces consécutifs en un seul.
Reprenant le vocabulaire du RFC 5598
(relisez-le d'abord !), la section 3 de notre RFC liste les
différents composants de la messagerie qui peuvent jouer un rôle
dans les transmissions indirectes, et les problèmes qu'elles
posent. D'abord, le MSA (Message Submission
Agent.) C'est la première ligne de vérification : il fait
respecter les règles d'une organisation (ADMD,
ADministrative Management Domain). S'il accepte
un message où le champ From:
du RFC 5322 n'est pas dans un domaine contrôlé par
l'ADMD, il y a des chances que DMARC râle par la suite. Le RFC
cite plusieurs cas d'usage où cela se produit : la fonction
« envoyer cet article à un ami » de certains sites Web, par
exemple, puisque le message va partir avec le domaine du lecteur
de l'article, pas avec celui du site Web. On peut trouver de
nombreux autres exemples, comme un service de gestion d'agenda qui
envoie des courriers de rappel, en utilisant comme expéditeur
l'adresse de l'utilisateur, ce qui est plutôt une bonne chose
(pour des messages du genre « l'heure de la réunion a changé »)
mais peut gêner DMARC. (Mon exemple
préféré est le cas où
on a une adresse de courrier mais pas de moyen de soumettre du
courrier via cette organisation, ce qui est fréquent avec les
adresses de fonction. Par exemple, on est membre d'une
organisation qui fournit des adresses à ses membres et/ou
responsables, ce qui permet de recevoir du courrier, mais on n'a
pas de MSA pour en envoyer, on doit donc utiliser celui d'une
autre organisation.)
Et les MTA, eux, quel est leur rôle dans les problèmes DKIM ? S'il change l'encodage (par exemple en passant du « 8 bits » à l'abominable Quoted-Printable), il va invalider les signatures DKIM (la canonicalisation de DKIM ne prévoit pas des transformations aussi radicales, même si elles ne modifient pas le message final). Idem si le MTA corrige les en-têtes du message pour les rendre conformes (une tâche qui relève plutôt du MSA, le MTA devant lui, transmettre fidèlement les messages qu'il a choisi d'accepter) : cela sort également du champ de la canonicalisation DKIM et cela invalide donc les éventuelles signatures. Enfin, le changement ou la suppression de certaines parties MIME (par exemple l'élision d'un document ZIP attaché, pour des raisons de protection contre les logiciels malveillants transmis par courrier) va évidemment également rendre les signatures invalides.
Et le MDA ? Peut-il casser des choses, également ? Oui, s'il passe les messages par Sieve (RFC 5228), qui a la possibilité d'ajouter ou de retirer des en-têtes, voire de modifier le corps (extension Sieve du RFC 5703). Si les tests DMARC sont faits après le passage de Sieve, ou bien si le message est ensuite réinjecté dans le système de courrier, des problèmes peuvent se produire.
Reste le cas des intermédiaires
(mediators). Ce sont les entités qui prennent
un message, puis le ré-expédient (parfois après modification). Un
exemple est l'alias. Via une entrée dans
/etc/aliases
ou bien via un
.forward
, ou bien via le
redirect
de Sieve, ou encore via encore une autre
méthode, un message initialement destiné à une adresse est
finalement transmis à une autre. C'est par exemple courant pour
les adresses « ancien élève », que fournissent certaines
universités, et qui permettent de garder à vie une adresse dans le
domaine de l'établissement où on a fait ses études. Un certain
nombre d'associations professionnelles fournissent un service
équivalent. En général, ces intermédiaires ne cassent pas DKIM
(ils ne modifient pas le message) mais, selon la façon dont ils
redirigent, peuvent invalider l'autorisation SPF.
Un autre exemple d'intermédiaire classique est le gestionnaire
de listes de
diffusion. En plus de rediriger un message (ce qui
fait que le message écrit par
alice@univ.example
n'est
pas émis par les serveurs de courrier de
l'université), ces logiciels changent souvent le message, par
exemple en ajoutant une inutile étiquette [Ma jolie
liste]
aux sujets des messages, en ajoutant un texte à
la fin (instructions de désabonnement, pourtant déjà possibles
avec l'en-tête List-Unsubscribe:
), en retirant des pièces jointes, ou bien
(surtout dans les théocraties comme les États-Unis) en remplaçant
des gros mots par des termes plus acceptables.
Toutes ces modifications vont probablement invalider les
signatures DKIM (cf. RFC 6377) et faire que les
messages envoyés par certains participants à la liste (ceux qui
ont une politique DMARC p=reject
) ne seront
pas reçus par les destinataires qui testent cette politique. (Si
un avis de non-remise est transmis, le logiciel de gestion de la
liste peut en déduire que l'adresse n'existe pas, et désabonner
d'autorité le destinataire.)
Et les filtres ? Certaines organisations insèrent dans le
réseau des dispositifs qui vont analyser le courrier, par exemple
à la recherche de logiciel
malveillant. Souvent, ils vont modifier les messages,
afin de supprimer ces contenus indésirables. Ces modifications
vont évidemment invalider les signatures. Idem si on change ou
supprime des URL contenus dans le message
et considérés « dangereux ». Même chose avec un
système anti-spam qui ajouterait un [SPAM]
dans le sujet.
En revanche, le courrier reçu d'un serveur secondaire (MX de secours), qui a pris le relais pendant une panne du primaire, puis expédié le courrier quand le primaire remarche, ne pose pas de problèmes. Bien sûr, les tests SPF échoueront mais, normalement, on ne fait pas ces tests sur le courrier qui vient de son propre serveur secondaire.
Bon, voici le tour d'horizon complet de tout ce qui peut marcher mal. Mais que faire ? La section 4 du RFC s'attaque aux solutions. Elles sont nombreuses et très différentes. Mais attention : DMARC est là pour rejeter des messages considérés comme invalides. On peut arranger les choses pour que certains de ces messages « passent » mais cela va contre le but de DMARC. Si les messages sont de grande valeur (transactions financières, par exemple), il vaut mieux ne pas chercher de solutions, et simplement se contenter de messages transmis directement, ne subissant pas de traitements qui vont invalider SPF ou DKIM.
C'est d'autant plus vrai que l'écosystème du courrier électronique est très complexe. On trouve un zillion de logiciels différents, plus ou moins bien écrits. Par exemple, des gens utilisent encore Qmail, qui n'a plus eu une seule mise à jour depuis 1998. Certaines des mesures ou contre-mesures utilisées pour la sécurité du courrier sont parfaitement légales, mais vont casser tel ou tel logiciel qui est utilisé à certains endroits.
Assez d'avertissements, les solutions. D'abord, du côté de
l'expéditeur. Celui-ci (ou son premier MTA)
peut faire des efforts pour améliorer l'accord entre les
identificateurs. Un logiciel sur info.example
qui envoie du courrier pour le compte de
bob@univ.example
peut ainsi décider
d'utiliser un en-tête From:
qui ne posera pas
de problème, celui du vrai envoyeur, et de mettre l'adresse de
Bob dans un Reply-To:
. Comme la plupart des
solutions présentées dans cette section 4, elle est imparfaite (le
destinataire peut se demander qui est cet envoyeur qu'il ne
connait pas). Le RFC fournit de nombreux autres exemples de
désaccord entre identités, qui peuvent être réparés en changeant
un peu le processus d'envoi du message. Comme le disait ma
grand-mère, « il y a toujours une solution, pour peu que chacun y
mette du sien ».
Les envoyeurs peuvent aussi limiter le risque de modifications invalidantes, en ne signant pas trop d'en-têtes avec DKIM, ou en envoyant des messages parfaitement formés (pour éviter aux serveurs ultérieurs la tentation de les « réparer »).
Les receveurs peuvent aussi agir mais leurs possibilités sont plus limitées, note le RFC.
Entre les expéditeurs et les receveurs, il y a tous les
intermédiaires qui prennent un message et le ré-expédient. Ce sont
souvent eux qui causent le problème, et ils sont donc souvent en
position de le réparer. Par exemple, ils peuvent changer le
From:
du message pour mettre le leur, ce qui
permettrait à peu près n'importe quelle modification, et serait
plus « franc » (puisque le message n'est plus tout à fait
l'original, autant changer l'auteur...) Évidemment, dans ce cas,
assez violent,
il faut au minimum garder l'information sur l'émetteur originel,
avec l'en-tête Original-From:
(RFC 5703). Le problème est que le récepteur humain sera sans
doute déconcerté par cet expéditeur (d'autant plus
qu'Original-From:
est peu ou pas
affiché).
Comme les modifications invalident les signatures, les ré-expéditeurs pourraient les éviter, par exemple en ajoutant des en-têtes au lieu de modifier les existants, lorsqu'ils veulent ajouter un contenu (du genre « ceci est un spam »). Il serait peut-être préférable, dans certains cas, de rejeter les messages plutôt que de les modifier, ce qui cassera la vérification de signatures plus loin.
Et, en parlant des ré-expéditeurs, les listes de diffusion, pas vraiment prévues par DKIM, que
faire pour elles ? Le RFC 6377 a déjà traité
leur cas. Une technique courante est de modifier le champ
From:
pour mettre l'adresse de la liste,
réduisant l'auteur original à un commentaire dans cet en-tête
(avis personnel : je déteste ça). Comme cela rend difficile de
répondre en privé au vrai auteur d'un message, l'ajout d'un
Reply-To:
peut aider. Une autre solution est
d'emballer le message original dans une partie
MIME
message/rfc822
. Cette partie resterait intact
et le message emballant aurait comme expéditeur la liste. Mais peu
de MUA savent afficher proprement ce genre
de messages (spécialement dans le monde des mobiles).
Encore plus fasciste, le gestionnaire de liste pourrait
interdire l'abonnement des gens utilisant une adresse où il y a
une politique DMARC autre que p=none
. (Le RFC
oublie de parler du cas où une politique
p=reject
n'existait pas au moment de
l'abonnement mais a été rajoutée après.)
Enfin, il existe aussi des solutions qui sont encore en cours de discussion à l'IETF, et dont le RFC décourage l'usage dans un environnement de production. Ce sont entre autres des extensions au modèle du RFC 8601 pour créer une chaîne d'authentification où chaque acteur important signerait le message en route. Ou, plus radical, des mécanismes stockant l'état initial d'un message avant transformation, pour pouvoir retrouver cet état original et vérifier la signature.
Bref, le problème n'est pas résolu...
Date de publication du RFC : Août 2016
Auteur(s) du RFC : J. Abley (Dyn), J. Schlyter (Kirei), G. Bailey (Microsoft)
Pour information
Première rédaction de cet article le 1 septembre 2016
Le mécanisme d'authentification des informations DNS nommé DNSSEC repose sur la même structure arborescente que le DNS : une zone publie un lien sécurisé vers les clés de ses sous-zones. Un résolveur DNS validant n'a donc besoin, dans la plupart des cas, que d'une seule clé publique, celle de la racine. Elle lui servira à vérifier les clés des TLD, qui serviront à valider les clés des domaines de deuxième niveau et ainsi de suite. Reste donc à configurer la clé de la racine dans le résolveur : c'est évidemment crucial, puisque toute la sécurité du système en dépend. Si un résolveur est configuré avec une clé fausse pour la racine, toute la validation DNSSEC est menacée. Comment est-ce que l'ICANN, qui gère la clé principale de la racine, publie cette clé cruciale ? Six ans après la signature de la racine du DNS, c'est enfin documenté, dans ce RFC.
Cela donne une idée de la vitesse des processus ICANN, organisation qui produit beaucoup de papier. Notez que ce nouveau RFC documente l'existant, déjà mis en œuvre, et ne prétend pas décrire la meilleure méthode. Notez aussi que ce format et cette méthode de distribution pourraient changer à l'avenir.
Si vous voulez réviser DNSSEC d'abord, outre les RFC de base sur ce système (RFC 4033, RFC 4034, RFC 4035...), notez surtout le RFC 6781, qui décrit les questions opérationnelles liées au bon fonctionnement de DNSSEC.
Les clés publiques configurées dans les résolveurs qui valident avec DNSSEC, sont appelées « points de départ de la confiance » trust anchors. Un point de départ de la confiance est une clé dont l'authenticité est admise, et non pas dérivée d'une autre clé, via une chaîne de signatures. Il en faut au moins un, celui de la racine, bien que certains résolveurs en ajoutent parfois deux ou trois pour des zones qu'ils veulent vérifier indépendamment. Lorsque le résolveur recevra une réponse de la racine, signée, il l'authentifiera avec la clé publique de la racine (le point de départ de la confiance). S'il veut vérifier une réponse d'un TLD, il l'authentifiera avec la clé publique du TLD, elle-même signée (et donc authentifiée) par la clé de la racine. Et ainsi de suite même pour les zones les plus profondes.
(Notez qu'il existe deux clés pour la plupart des zones, la KSK - Key Signing Key, et la ZSK - Zone Signing Key, mais on ne s'intéresse ici qu'aux KSK, c'est elles qui sont signées par la zone parente, et configurées comme points de départ de la confiance.)
La gestion de la clé de la racine par l'ICANN est décrite dans leur DNSSEC Practice Statement.
Le RFC rappelle aussi qu'il y a d'autres possibilités d'installation d'un point de départ de la confiance. Par exemple, si un tel point a été configuré une fois, ses remplacements éventuels peuvent être faits via le RFC 5011.
La section 2 du RFC décrit le format des clés publiées par l'IANA. Les trois formats, en fait :
Voici un exemple du fichier XML (à ne pas prendre comme s'il faisait autorité, évidemment) :
<TrustAnchor id="AD42165F-3B1A-4778-8F42-D34A1D41FD93" source="http://data.iana.org/root-anchors/root-anchors.xml"> <Zone>.</Zone> <KeyDigest id="Kjqmt7v" validFrom="2010-07-15T00:00:00+00:00"> <KeyTag>19036</KeyTag> <Algorithm>8</Algorithm> <DigestType>2</DigestType> <Digest> 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5 </Digest> </KeyDigest> </TrustAnchor>
L'élément <KeyTag>
indique
l'identifiant de la clé, actuellement 19036, comme on peut le
voir avec dig :
% dig +multi +nodnssec DNSKEY . ... ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ... ;; ANSWER SECTION: . 147724 IN DNSKEY 257 3 8 ( AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQ bSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh ... ) ; KSK; alg = RSASHA256; key id = 19036 ...
L'attribut id
de l'élément
<KeyDigest>
sert à
identifier un condensat particulier, et est utilisé pour nommer
les autres fichiers. Par exemple, le certificat PKIX va se trouver
dans le fichier Kjqmt7v.crt
.
Pour produire un enregistrement DS à
partir de ce fichier XML, il suffit de mettre
<KeyTag>
,
<Algorithm>
, <DigestType>
et <Digest>
bout à bout. Par exemple,
avec le fichier XML ci-dessus, cela donnerait :
. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
(Des résolveurs comme Unbound acceptent ce format, pour le point de confiance de départ.)
Quant aux certificats, ils sont encodés en
DER et signés par
l'ICANN et leur champ
SubjectPublicKeyInfo
est la clé publique
DNSSEC. Voici ce qu'en voit OpenSSL :
% openssl x509 -text -inform DER -in Kjqmt7v.crt Certificate: Data: Version: 3 (0x2) Serial Number: 7 (0x7) Signature Algorithm: sha256WithRSAEncryption Issuer: O=ICANN, CN=ICANN DNSSEC CA/emailAddress=dnssec@icann.org Validity Not Before: Jun 11 18:43:20 2014 GMT Not After : Jun 10 18:43:20 2017 GMT Subject: O=ICANN, OU=IANA, CN=Root Zone KSK 2010-06-16T21:19:24+00:00/1.3.6.1.4.1.1000.53=. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5 Subject Public Key Info: Public Key Algorithm: rsaEncryption ... X509v3 extensions: X509v3 Basic Constraints: critical CA:FALSE X509v3 Authority Key Identifier: keyid:8F:B2:42:69:C3:9D:E4:3C:FA:13:B9:FF:F2:C0:A4:EF:D8:0F:E8:22 X509v3 Subject Key Identifier: 41:1A:92:FA:1B:56:76:1E:62:2B:71:CD:1A:FD:BB:43:99:5F:09:C9 Signature Algorithm: sha256WithRSAEncryption ...
Comment récupérer le fichier XML
de manière à être sûr de son authenticité ? C'est ce que spécifie
la section 3 du RFC : on utilise HTTPS. L'URL est https://data.iana.org/root-anchors/root-anchors.xml
.
Une autre solution (section 4) est de le récupérer en
HTTP et de le vérifier avec une des
signatures fournies : l'une est en CMS
(RFC 5652) - son URL est https://data.iana.org/root-anchors/root-anchors.p7s
,
l'autre est en PGP (RFC 9580) - son URL est https://data.iana.org/root-anchors/root-anchors.asc
. Cette
signature PGP devrait être abandonnée à l'avenir.
Pour les amateurs d'histoire, l'annexe A rappelle que la clé actuelle, la 19036, a été générée au cours d'une cérémonie à Culpeper, le 16 juin 2010. Elle a été publiée dans le DNS pour la première fois le 15 juillet 2010.
Sinon, l'ISOC a écrit un bon article sur ce RFC, moins technique.
Date de publication du RFC : Septembre 2016
Auteur(s) du RFC : L. Iannone (Telecom
ParisTech), R. Jorgensen (Bredbandsfylket
Troms), D. Conrad (Virtualized,
LLC), G. Huston (APNIC)
Intérêt historique uniquement
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 23 septembre 2016
Le RFC 7954 réservait un préfixe
IP, 2001:5::/32
, pour
les identificateurs du protocole expérimental
LISP. Ce RFC 7955 décrit les
mécanismes d'allocation à l'intérieur de ce préfixe. Ils sont
simples et légers : un peu de documentation et on a son sous-préfixe.
Le RIPE-NCC assure la gestion de ce préfixe. La politique d'enregistrement est simple (sections 4 et 9 de notre RFC) :
2001:5::/32
. Si l'expérience
se termine et que le 2001:5::/32
cesse
d'être utilisé, tous ses sous-préfixes disparaitront aussi.Quelles sont les règles que suivra le registre de
2001:5::/32
(section 5) ?
ip6.arpa
correspondants au préfixe géré.La section 6, en effet, contient les informations demandées aux titulaires (ce sont à peu près les mêmes que pour obtenir un numéro d'organisation privé). On y trouve les grands classiques, nom de l'organisation qui demande, adresse, informations de contact, taille du préfixe demandé, raisons de la demande...
Comme indiqué plus haut, c'est le RIPE-NCC qui gérera le préfixe. Normalement, tout est déjà en place mais pas encore annoncé (cela sera mis en ligne après la publication du RFC).
Date de publication du RFC : Septembre 2016
Auteur(s) du RFC : L. Iannone (Telecom ParisTech), D. Lewis (Cisco), D. Meyer (Brocade), V. Fuller
Intérêt historique uniquement
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 23 septembre 2016
Le protocole expérimental LISP a besoin
d'identificateurs pour les machines qui participent à
l'expérimentation. Comme les identificateurs LISP sont pris dans
le même espace de nommage que les adresses IP, il était préférable d'avoir un
préfixe IP spécifique. C'est désormais chose faite, avec ce
RFC, qui demande et obtient le préfixe
2001:5::/32
. Si vous voyez quelque chose qui
ressemble à une adresse IP et qui emploie ce préfixe, c'est qu'il
s'agit d'un identificateur LISP.
En effet, LISP (RFC 6830) repose sur le principe de
la séparation
de l'identificateur et du localisateur. Les identificateurs
sont stables et servent à... identifier une machine, les
localisateurs sont liés aux connexions qu'on a au réseau et
servent au routage. Les deux ont la forme physique d'une adresse
IP, et on ne peut donc pas les distinguer par leur syntaxe. Les
identificateurs sont formellement nommés EID (Endpoint
IDentifier) et c'est pour eux que
2001:5::/32
a été réservé (section 1 du RFC).
La section 3 explique les raisons de cette réservation :
2001:5::/32
au
lieu de devoir découper une partie de son espace
d'adressage.D'où cette réservation d'un préfixe dédié, en suivant les règles du RFC 3692.
Les réseaux qui utiliseront ce préfixe ne doivent évidemment pas annoncer de routes dans la DFZ (section 4 du RFC), ce préfixe ne servant qu'à des identificateurs et pas aux localisateurs. Pour la communication entre un réseau LISP numéroté avec le nouveau préfixe, et un réseau IP traditionnel, il faut utiliser les techniques d'interconnexion des RFC 6832 et RFC 7215. Le préfixe complet pourra être annoncé (comme un tout, ou comme des sous-préfixes très généraux, pour ne pas surcharger la table de routage) par des routeurs d'interconnexion (section 8 du RFC). Pour les routeurs non-LISP, ce sera un préfixe comme un autre, et il n'y a aucune raison de lui appliquer un traitement particulier.
Notre RFC exige également que ce nouveau préfixe
2001:5::/32
ne soit utilisé que par
configuration explicite et ne soit donc pas mis en dur dans le
logiciel des routeurs, d'abord parce que LISP pourra en utiliser
d'autres dans le futur, ensuite parce que des réseaux feront quand
même du LISP avec leurs propres adresses.
Pourquoi un préfixe de 32 bits ? Pourquoi pas plus spécifique ou moins spécifique (cela a été une grosse discussion dans le groupe de travail) ? La section 5 donne les raisons de ce choix :
Le préfixe 2001:5::/32
est alloué pour
trois ans, ce qui est suffisant pour l'expérimentation (sections
6 et 7). À la fin de celle-ci, le préfixe sera rendu ou bien transformé
en allocation permanente (qu'il faudra justifier et
documenter, cf. RFC 2860, section 4.3). L'allocation, faite en octobre 2015, est notée dans le registre IANA.
L'allocation des préfixes à l'intérieur de
2001:5::/32
est décrite dans le RFC 7955.
Date de publication du RFC : Août 2016
Auteur(s) du RFC : M. Bjorklund (Tail-f Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF netmod
Première rédaction de cet article le 10 octobre 2016
Le protocole standard Netconf (normalisé dans le RFC 6241) permet de configurer un équipement réseau (par exemple un commutateur) à distance. Netconf fonctionne par des RPC dont les paramètres sont des actions à faire effectuer par l'équipement configuré, ou bien les nouvelles valeurs que peut prendre telle ou telle des variables de configuration de cet équipement. Mais comment savoir quelles actions sont possibles, quelles variables existent, et quelles valeurs elles peuvent prendre ? Jusqu'à présent, cela pouvait se spécifier uniquement dans une documentation en langue naturelle fournie avec l'équipement. Désormais, il est possible de spécifier ces informations dans un langage formel, YANG. La première version de YANG était normalisée dans RFC 6020, ce nouveau RFC normalise la nouvelle version, la 1.1, qui a peu de changements, mais certains cassent la compatibilité ascendante.
Ce RFC 7950 est très détaillé, plus de deux cents pages. Et je n'ai pas personnellement d'expérience pratique avec YANG. Donc, je ne donne ici qu'un très bref résumé. Un tel survol se trouve également dans la section 4 du RFC : YANG modélise les données (configuration et état) qui seront utilisées par Netconf. Ces données sont représentées sous forme arborescente. YANG est modulaire (section 5.1 du RFC), un module YANG pouvant se référer à d'autres modules. YANG définit un ensemble de types pour décrire les données (section 9 et RFC 6991). Il permet également d'indiquer les contraintes que doivent respecter les données. YANG, langage de haut niveau, ne décrit pas l'encodage utilisé sur le câble.
Notez que YANG peut être utilisé avec d'autres protocoles que Netconf, comme RESTCONF (décrit dans le RFC 8040).
YANG a donc bien des points communs avec le SMI des RFC 2578 et RFC 2579. Avant Netconf, beaucoup de gens pensaient que toute la gestion des équipements réseau se ferait en SNMP, en s'appuyant sur ce modèle SMI. Si, pour la lecture des variables, SNMP s'est largement imposé, force est de constater que, pour l'écriture de variables et pour les actions, SNMP reste très peu utilisé, au profit de toute une galaxie de mécanismes privés (Web, REST, SSH + CLI, etc), galaxie que Netconf vise à remplacer. Une MIB du SMI peut donc être traduite en YANG, l'inverse n'étant pas vrai (YANG étant plus riche).
La syntaxe de YANG utilise des groupes emboîtés, délimités par des accolades. Mais une syntaxe équivalente, en XML, existe, sous le nom de Yin. Tout module YANG peut être traduit en Yin sans perte et réciproquement (voir la section 13 pour plus de détails sur Yin).
Donc, un engin donné, routeur ou autre équipement qu'on veut gérer, est décrit par des modules YANG. Lorsqu'un serveur Netconf à bord dudit engin met en œuvre un module YANG, cela veut dire qu'il permet de modifier, via Netconf, les variables décrites dans le module (le serveur typique met en œuvre plusieurs modules). Voici le début d'un module possible :
// Only an example, not a real module. module acme-system { namespace "http://acme.example.com/system"; prefix "acme"; organization "ACME Inc."; contact "joe@acme.example"; description "The module for entities implementing the ACME system."; revision 2010-08-05 { description "Initial revision."; } ...
On l'a dit, YANG est arborescent. Les feuilles de l'arbre (section 4.2.2.1 du RFC) contiennent une valeur particulière, par exemple, ici, le nom de l'engin géré :
leaf host-name { type string; description "Hostname for this system"; }
Ici, leaf
est un mot-clé de YANG qui indique une
feuille de l'arbre (plus de nœuds en dessous),
host-name
est le nom que l'auteur du module a
donné à une variable, de type « chaîne de caractères ». Lorsqu'un
serveur Netconf enverra cette information à un client (ou
réciproquement), elle sera encodée en XML ainsi
(Netconf utilise XML pour l'encodage des messages mais d'autres
encodages sont possibles, cf. RFC 7951) :
<host-name>my-router.example.com</host-name>
Donc, pour résumer, YANG modélise ce qu'on peut lire ou modifier, Netconf permet de le lire ou de le modifier effectivement.
Par contre, si un nœud de l'arbre YANG n'est pas une feuille,
il est désigné par le mot-clé container
. Par
exemple, il y a ici deux containers
emboîtés et
une feuille :
container system { container login { leaf message { type string; description "Message given at start of login session"; } } }
Lorsque Netconf utilise cette donnée, cela ressemblera, sur le câble, à ceci :
<system> <login> <message>Good morning</message> </login> </system>
YANG dispose d'un certain nombre de types pour représenter les données (section 4.2.4 et RFC 6991), mais on peut aussi créer ses types (sections 4.2.5 et 7.3) par exemple ainsi :
typedef percent { type uint8 { range "0 .. 100"; } description "Percentage"; } leaf completed { type percent; }
On a ajouté un intervalle de validité au type prédéfini uint8
.
Autre exemple, en indiquant une valeur par défaut, et en dérivant d'un
type défini dans le module inet
:
typedef listen-ipv4-address { type inet:ipv4-address; default "0.0.0.0"; }
YANG a bien d'autres possibilités, décrites en détail dans les
sections suivantes. Par exemple, dans un monde idéal, tous les engins
mettant en œuvre un module YANG donné géreraient la totalité des
variables du module. Mais, comme ce n'est pas forcément le cas, YANG
permet des déviations (sections 5.6.3 et 7.20.3). Prenons l'exemple du RFC, un
routeur BGP qui suit un module YANG BGP. Le
module ne donne pas de limite au nombre de pairs BGP mais un routeur
bas de gamme pourrait avoir une limite, disons à 16 pairs. Un client
Netconf qui tenterait de configurer un dix-septième pair recevrait
donc une erreur. Le mot-clé YANG deviation
permettrait audit client de savoir à l'avance en quoi ce routeur
particulier dévie du modèle BGP général. Le client Netconf n'aurait
donc pas à essayer pour voir, il pourrait savoir à l'avance que
l'opération de configuration du dix-septième pair ne marchera pas.
La syntaxe formelle de YANG est décrite en section 6. Elle ressemble à celle de langages de programmation comme C ou à celle de SMIng du RFC 3780 (RFC qui n'a pas eu de succès). Cette syntaxe favorise la lisibilité par des humains, le cahier des charges étant de privilégier les lecteurs, pas les auteurs de modules, ni les programmeurs d'outils YANG. À noter que, comme dans toutes les normes modernes, YANG n'est pas limité à l'ASCII et peut utiliser tout Unicode.
Bien que YANG n'utilise pas XML, il réutilise un langage de ce monde, XPath (sections 6.4 et 7.5.3). XPath sert à indiquer les dépendances entre nœuds de l'arbre.
YANG permet en effet de définir des contraintes (section 8) que doivent
respecter les variables, avec la directive
must
. Par exemple :
must "ifType != 'ethernet' or " + "(ifType = 'ethernet' and ifMTU = 1500)" { error-message "An ethernet MTU must be 1500"; }
Voici un exemple de requête Netconf complète, correspondant à une
variable YANG. Soit un équipement muni d'un serveur
SSH et d'un serveur Netconf pour
sa configuration. Disons que le serveur Netconf met en œuvre la variable
YANG port
, définie ainsi :
leaf port { type inet:port-number; default 22; description "The port which the SSH server listens to" }
La requête Netconf <edit-config>
(RFC 6241, section 7.2) qui configure le serveur SSH pour écouter sur le
port 2022 serait :
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <edit-config> <target> <running/> </target> <config> <system xmlns="http://example.com/schema/config"> <services> <ssh> <port>2022</port> </ssh> </services> </system> </config> </edit-config> </rpc>
Le choix de YANG comme langage standard pour la description des capacités d'un serveur Netconf ne s'était pas fait sans mal. Plusieurs concurrents avaient été envisagés notamment Relax NG, un choix logique puisque Netconf utilise XML. Un langage de description de schémas comme Relax NG semblait donc un choix raisonnable. Parmi les discussions à ce sujet, citons par exemple le débat qui avait eu lieu sur la liste du secteur Applications de l'IETF. Les raisons du choix de YANG, telles que vues par les concepteurs de YANG, sont décrites sur le site officiel du projet mais je trouve cette comparaison très unilatérale.
Un bon tutoriel Netconf, couvrant également YANG, est disponible en
http://www.aims-conference.org/issnsm-2008/06-netconf-yang.pdf
.
Quelles sont les mises en œuvre de YANG ? Il en existe une
liste sur le
site officiel. Voyons par exemple l'outil pyang, qui sert à valider
des schémas YANG (y compris de la nouvelle version 1.1 décrite dans ce
RFC) et à les convertir dans d'autres formats. Il ne
semble pas trop maintenu mais, bon, il marche. Il peut produire du XSD et
du RelaxNG - enfin du DSDL mais c'est presque
pareil. Voici un exemple de test d'un schéma invalide
(leaf
a été tapé laf
) :
% pyang test.yang test.yang:11: error: unexpected keyword "laf"
Et, si on corrige :
% pyang test.yang %
Maintenant, convertissons en Yin :
% cat test.yang module acme-foo { namespace "http://acme.example.com/foo"; prefix "acfoo"; list interface { key "name"; leaf name { type string; } leaf mtu { type uint32; description "The MTU of the interface."; } } } % pyang -fyin test.yang <?xml version="1.0" encoding="UTF-8"?> <module name="acme-foo" xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:acfoo="http://acme.example.com/foo"> <namespace uri="http://acme.example.com/foo"/> <prefix value="acfoo"/> <list name="interface"> <key value="name"/> <leaf name="name"> <type name="string"/> </leaf> <leaf name="mtu"> <type name="uint32"/> <description> <text>The MTU of the interface.</text> </description> </leaf> </list> </module>
Et voici une conversion du même code en DSL :
% pyang -fdsdl test.yang <?xml version='1.0' encoding='UTF-8'?> <grammar datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" ns="http://acme.example.com/foo" xmlns="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns:acfoo="http://acme.example.com/foo" xmlns:dc="http://purl.org/dc/terms" xmlns:dsrl="http://purl.oclc.org/dsdl/dsrl" xmlns:nm="urn:ietf:params:xml:ns:netmod:dsdl-attrib:1" xmlns:sch="http://purl.oclc.org/dsdl/schematron"> <dc:source>YANG module 'acme-foo' (automatic translation)</dc:source> <start> <zeroOrMore> <element name="interface" nm:key="name"> <element name="name"> <data type="string"/> </element> <optional> <element name="mtu"><a:documentation>The MTU of the interface.</a:documentation> <data type="unsignedInt"/> </element> </optional> </element> </zeroOrMore> </start> </grammar>
Le site officiel du projet, http://www.yang-central.org/
, contient beaucoup d'autre
information sur YANG.
Notez que l'ancien YANG, 1.0, décrit dans le RFC 6020, n'est pas abandonné. L'ancien RFC reste
d'actualité pour décrire la version 1.0, qui restera en usage un
certain temps. Les principaux changements apportés par la version
1.1 de YANG sont décrits dans la
section 1.1 du RFC. La liste est très longue, mais la plupart ne
sont que des points de détail. Parmi les changements qui peuvent
rendre illégaux des modèles YANG qui étaient légaux avant, il y a
par exemple le changement d'interprétation des échappements dans
les chaînes de caractères, ou bien le fait qu'une chaîne de
caractères qui n'est pas encadrée par des apostrophes ou des
guillemets n'a plus le droit de contenir des apostrophes ou
guillemets (section 6.1.3). De même, les clés (identificateurs
uniques) ne peuvent plus être conditionnelles (instructions
when
ou if-feature
) ce
qui est logique, mais rend également invalide certains anciens
modèles YANG.
Date de publication du RFC : Septembre 2016
Auteur(s) du RFC : N. Hilliard (INEX), E. Jasinska (Netflix), R. Raszuk (Mirantis), N. Bakker (Akamai Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 9 septembre 2016
Les points d'échange Internet sont un des maillons essentiels du bon fonctionnement de l'Internet, permettant des connexions faciles et relativement bon marché entre opérateurs. Une fois physiquement connecté au point d'échange, l'opérateur Internet doit encore établir une connexion BGP (RFC 4271) avec ses pairs. Si ceux-ci sont nombreux, établir N connexions bilatérales représente un coût administratif important. Il est souvent préférable d'établir une seule connexion multilatérale, par l'intermédiaire d'un serveur de routes (route server). Celui-ci récolte les annonces BGP de tous ses pairs et les redistribue. Ainsi, il suffit à l'opérateur d'une seule connexion, avec le serveur de routes. Ce nouveau RFC documente les questions opérationnelles liées aux serveurs de routes.
Le principe et le fonctionnement d'un serveur de routes sont expliqués dans le RFC 7947, produit par un autre groupe de travail IETF. Ce RFC 7948 se consacre aux détails opérationnels. Un serveur de routes est l'équivalent, pour le BGP externe (eBGP) de ce qu'est un « réflecteur de routes » (route reflector, RFC 4456) pour le BGP interne (iBGP). Le serveur de routes, lorsqu'il existe, est un composant crucial du point d'échange. Par exemple, s'il tombe en panne, les sessions BGP sont coupées, les annonces retirées et, même si les commutateurs et le réseau du point d'échange continuent à fonctionner, plus aucun trafic ne passe (à part si des sessions BGP bilatérales existent également). D'où l'importance d'une bonne gestion de ce composant.
Les sections 2 et 3 de notre RFC rappelent la différence entre sessions BGP bilatérales et multilatérales à un point d'échange. Si on ne fait que des sessions bilatérales (pas de serveur de routes), avec seulement quatre routeurs BGP sur le point d'échange, il faudra six sessions BGP pour une connectivité complète. Avec dix routeurs, il en faudrait quarante-cinq ! Établir, superviser et maintenir toutes ces sessions représente du travail. Les sessions multilatérales, via un serveur de routes, sont une bien meilleure solution. Avec dix routeurs au point d'échange, il n'y a plus besoin que de dix sessions BGP, chacun des dix routeurs ne faisant que BGP qu'avec le serveur de routes.
Le serveur de routes doit
juste veiller à ne pas toucher à l'attribut BGP
NEXT_HOP
(RFC 4271, section
5.1.3), qui ne doit pas indiquer le serveur de
routes, mais le routeur qui a annoncé la route (le serveur de routes
n'est pas un routeur, et ne fait pas de
transmission du trafic IP). Pour le point d'échange typique, il n'y a
pas besoin de faire de la résolution récursive (utiliser un protocole
de routage pour trouver comment joindre le routeur suivant) du
NEXT_HOP
: tous les routeurs sont sur le même
réseau L2 et sont donc
joignables directement. Par exemple, si je regarde le looking glass du France-IX et que
lui demande les routes vers 194.0.9.0/24
, il me
montre :
194.0.9.0/24 via 37.49.236.20 on eth1 [RS1_PAR 2016-08-11 from 37.49.236.250] * (100) [AS2484i] via 37.49.236.21 on eth1 [RS1_PAR 2016-08-11 from 37.49.236.250] (100) [AS2486i] ...
(L'AFNIC est connectée sur deux points de
présence de ce point d'échange, d'où les deux routeurs.) Les
NEXT_HOP
sont les adresses des routeurs dans le
point d'échange, 37.49.236.0/23
.
La section 4, le gros morceau de notre RFC, décrit ensuite divers points que le serveur de routes doit garder en tête, pour faire un bon travail.
D'abord, le cas où on n'envoie pas exactement les mêmes informations à tous les clients. Sauf si le client BGP coopère, cela implique que le serveur garde une base des routes par groupe de clients, un groupe étant composé de tous les clients pour qui on applique la même politique de filtrage. Attention, cela consomme pas mal de mémoire (autant de base que de groupes) et de processeur (il faut faire tourner les algorithmes de sélection BGP pour tous les groupes) mais heureusement, en pratique, on utilise rarement ces politiques différentes. Traiter tous les clients de la même façon permet de garder une consommation de ressources raisonnable.
Qu'en est-il du risque de fuite de préfixes ? Si un routeur connecté au serveur de routes fuit et envoie, par exemple, la totalité de la DFZ au serveur de routes, celui-ci va-t-il transmettre tous ces préfixes à ses infortunés clients ? Cela serait très ennuyeux car tout le trafic partirait alors vers le routeur fautif, qui ne serait peut-être pas capable de le gérer. Il est donc très recommandé que le serveur de routes prenne des précautions contre les fuites. Au minimum, imposer un nombre maximal de préfixes à chaque client, et, idéalement, filtrer les préfixes autorisés pour chaque client. C'est moins grossier que la simple limite quantitative, mais c'est aussi plus dur à maintenir (on ne peut pas espérer que tous les clients tiennent à jour leurs préfixes dans les IRR...). Il est certainement préférable que les administrateurs des clients et du serveur de routes regardent le journal de leur routeur pour repérer les différences entre ce qui est théoriquement annoncé et ce qu'il l'est réellement.
Question fiabilité, notre RFC recommande que le serveur de routes soit redondant : s'il n'est composé que d'une seule machine, et qu'elle plante, le point d'échange ne servira plus. Il faut donc au moins deux machines, et prendre soin qu'elles soient configurées de manière à annoncer les mêmes routes. (C'est trivial si les machines sont identiques, il suffit qu'elles aient la même configuration, cela l'est moins si, pour augmenter la redondance, on choisit des machines ayant des logiciels différents.)
Autre précaution à prendre, côté client, ne pas vérifier que le chemin d'AS est cohérent. Par exemple, le serveur de routes ne va pas mettre son propre AS tout à gauche du chemin d'AS (RFC 7947, section 2.2.2) et le client ne doit donc pas vérifier que son pair, le serveur de routes, a un chemin d'AS incluant l'AS du pair BGP.
Comment contrôler l'exportation des routes vers certains clients ? La section 4.6 liste plusieurs méthodes :
On a vu que la grande majorité des points d'échange travaillaient au niveau 2. Normalement, toute machine connectée au réseau du point d'échange peut donc joindre n'importe quelle autre. Mais, en pratique, on a déjà vu des bogues dans un commutateur qui menaient à des communications non transitives. Par exemple, les routeurs A et B peuvent tous les deux joindre le serveur de routes mais ne peuvent pas se joindre mutuellement. Dans ce cas, A reçoit bien les routes de B (et réciproquement) mais, lorsqu'il essaie de transmettre des paquets à B, ceux-ci finissent dans un trou noir. Ce problème est spécifique aux serveurs de route : lorsqu'on a une connexion bilatérale, les paquets de contrôle (ceux envoyés en BGP) suivent en général le même chemin que ceux de données (les paquets IP transmis) et partagent donc le même sort, bon ou mauvais.
La solution à ce problème passe peut-être par des solutions comme BFD (RFC 5881), pour tester la connectivité entre les deux routeurs. Mais BFD nécessite une configuration bilatérale entre les deux routeurs et il n'existe actuellement aucun protocole pour faire cette configuration automatiquement. On retombe donc dans les problèmes de configuration manuelle d'un grand nombre de connexions bilatérales. Même si un protocole de configuration automatique existait, il resterait le problème d'informer le serveur de routes. En effet, un échec BFD indiquerait à A qu'il ne peut pas joindre B, et lui ferait marquer les routes vers B comme invalides mais le serveur de routes, n'étant pas au courant, continuerait à n'envoyer à A que la route invalide (un pair BGP ne transmet que la meilleure route vers une destination donnée).
Dernier piège, le détournement de NEXT_HOP
. On
a vu que le fonctionnement normal d'un serveur de routes est de ne pas
se mettre comme « routeur suivant » mais au contraire de relayer
aveuglément les
NEXT_HOP
indiqués en BGP par ses clients.
Un
client malveillant pourrait annoncer des routes au serveur de routes en
indiquant comme « routeur suivant » le routeur d'un concurrent, pour
lui faire acheminer son trafic, par exemple ou, pire, pour faire une
attaque par déni de service en annonçant des
préfixes très populaires avec le concurrent comme routeur
suivant. Contrairement au problème précédent, celui-ci n'est pas
spécifique aux serveurs de route, il existe aussi avec des sessions
BGP bilatérales. Mais il peut faire davantage de dégâts lorsqu'on
utilise un serveur de routes, tous les clients croyant l'annonce
mensongère. Pour empêcher cela, il faudrait que les serveurs de route
vérifient que l'attribut BGP NEXT_HOP
corresponde
à l'adresse IP du client. (Les clients ne peuvent pas faire ce test,
ils doivent croire le serveur de routes, qui annonce des
NEXT_HOP
qui ne sont pas son adresse IP.)
Et pour finir, une sortie complète du looking
glass du route server du France-IX
concernant un serveur racine du DNS, M.root-servers.net
(et, au
passage, attention en anglais à ne pas confondre route
server et root server) :
RS1 show route for 202.12.27.33/32 all - View the BGP map 202.12.27.0/24 via 37.49.237.106 on eth1 [RS1 2015-08-21 from 37.49.236.250] * (100) [AS7500i] Type: BGP unicast univ BGP.origin: IGP BGP.as_path: 7500 BGP.next_hop: 37.49.237.106 BGP.med: 500 BGP.local_pref: 100 BGP.atomic_aggr: BGP.aggregator: 192.50.45.1 AS7500 BGP.community: (51706,51706) (51706,64601) (51706,64650)
Les pages de présentation de quelques serveurs de route :
Merci à Arnaud Fenioux pour sa relecture et ses ajouts et corrections.
Date de publication du RFC : Septembre 2016
Auteur(s) du RFC : E. Jasinska (BigWave
IT), N. Hilliard (INEX), R. Raszuk
(Bloomberg LP), N. Bakker (Akamai)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 9 septembre 2016
Ce nouveau RFC spécifie le comportement des serveurs de routes des points d'échange Internet. Un serveur de route collecte avec BGP les routes envoyées par ses pairs et les redistribue. Cela nécessite quelques ajustements du protocole BGP, expliqués ici. Un autre RFC, le RFC 7948, décrit le côté opérationnel.
Un point d'échange Internet connecte un certain nombre d'acteurs (opérateurs, hébergeurs, FAI, etc) à un réseau commun, en général au niveau de la couche 2, et avec Ethernet. Chacun de ces acteurs gère son ou ses routeurs, connecté au·x commutateur·s commun·s. Pour savoir à quel pair envoyer des paquets IP, ces routeurs ont besoin de s'informer mutuellement des préfixes IP qu'ils gèrent. Cela se fait avec le protocole BGP (RFC 4271).
Si le point d'échange rassemble N acteurs, connecter tout le monde nécessiterait N*(N-1)/2 sessions BGP. À chaque fois qu'un participant arriverait, il faudrait qu'il négocie N-1 accords de peering. Et, en fonctionnement quotidien, il devrait superviser N-1 sessions BGP. L'idée de base du serveur de routes est d'introduire un intermédiaire (le serveur de routes, route server), qui reçoit les routes de chacun et les redistribue à tous. Ainsi, il n'y a qu'une seule session BGP à établir, avec le serveur de routes. Il est en général géré par l'opérateur du point d'échange. (Sur la plupart des points d'échange, l'usage de ce serveur de routes n'est pas obligatoire, et il y a donc également des sessions BGP directes entre les participants, pour des raisons variées.)
Le serveur de routes parle BGP avec ses pairs (les routeurs des participants au point d'échange) mais lui-même n'est pas un routeur : il ne transmet pas les paquets IP. Il travaille sur le plan de contrôle, pas sur celui des données.
Un serveur de routes est donc très proche d'un réflecteur (RFC 4456). La différence est que le réflecteur de routes travaille à l'intérieur d'un AS (protocole iBGP), alors que le serveur de routes travaille entre AS différents (protocole eBGP).
Un serveur de routes ressemble aussi à un collecteur de routes, comme ceux du RIS. La différence est que le collecteur ne redistribue pas d'information à ses pairs BGP, il collecte des données, pour analyse, affichage, etc.
La section 2 du RFC forme le cœur de ce document. Elle
rassemble les modifications du protocole BGP qui sont nécessaires
pour le bon fonctionnement du serveur de routes. D'abord, le
serveur ne doit pas modifier sans bonne raison les annonces qu'il
reçoit : son but est de distribuer de l'information, pas de la
bricoler. Le RFC demande ainsi que les attributs BGP bien connus
(comme AS_PATH
)
ne soient pas modifiés, sauf très bonne raison. Ainsi, l'attribut
NEXT_HOP
qui indique l'adresse IP du routeur
à qui faire suivre les paquets, ne doit pas être changé (ce que
demandait la section 5.1.3 du RFC 4271) : le
serveur de routes n'est pas un routeur, c'est à l'annonceur
original qu'il faut transmettre les paquets. Idem pour
AS_PATH
cité plus haut : le serveur de routes
ne doit pas mettre son propre numéro d'AS
dans le chemin. De même, MULTI_EXIT_DISC
(qui
sert à choisir entre plusieurs routeurs d'un même AS voisin) doit
être propagé aux clients du serveur de routes (normalement, il
n'est pas propagé aux autres AS). Et, enfin, les communautés BGP
(RFC 1997)
indiquées dans une annonce ne doivent pas être changées, sauf
évidemment si elles sont destinées au serveur de routes
lui-même. On trouve des exemples de communautés destinées au
serveur de routes dans la
documentation du serveur de routes d'AMS-IX ou bien dans celle de celui de
Netnod, alors que celle
de France-IX se trouve dans un objet RIPE. Il y a aussi des
serveurs de routes (comme ceux du France-IX
qui étiquettent les annonces apprises avec une communauté
indiquant où la route a été apprise (dans quel POP.)
Par défaut, toutes les routes de tous les clients sont
distribuées à tous les autres clients. C'est le but d'un serveur
de routes. Mais on peut souhaiter parfois une certaine restriction
à cette redistribution. Cela peut être mis en œuvre par le serveur
de routes (puisque le routeur original de l'annonce parle au
serveur de routes, pas au client final). Idéalement, le serveur de
routes devrait donc maintenir une base de routes, et un processus
de décision BGP, pour chacun de ses clients. Cela permet de coller
au mode de fonctionnement normal de BGP. Et cela ne nécessite
aucun changement chez les clients. Mais c'est plus coûteux en
ressources pour le serveur de routes. (Pour
BIRD, voir l'option
secondary
, qui réduit l’usage mémoire et CPU
de manière importante, expliquée dans
cet exposé.)
Les autres solutions à ce problème d'un filtrage par client
nécessitent des extensions à BGP, comme le Diverse
path du RFC 6774 ou comme la future option
ADD-PATH
.
L'annexe de ce RFC consacrée aux remerciements résume un peu d'histoire des serveurs de routes. La première description de ce système date de 1995, dans le RFC 1863 (depuis reclassé comme « d'intérêt historique seulement », cf. RFC 4223).
Plusieurs mises en œuvre de serveurs de route existent évidemment, conformes à ce RFC. C'est par exemple le cas chez Cisco, BIRD et Quagga (voir le rapport technique sur ces programmes).
Merci à Arnaud Fenioux pour sa relecture et ses ajouts et corrections.
Date de publication du RFC : Juillet 2016
Auteur(s) du RFC : Y. Sheffer (Intuit), A. Farrel
(Juniper)
Première rédaction de cet article le 23 juillet 2016
L'IETF se vante souvent de ne pas croire au blabla des marketeux, mais uniquement au code qui tourne. Comme le dit fièrement sa devise, « We believe in rough consensus and running code ». Mais, en pratique, les normes produites et publiées en RFC ne contiennent pas toujours la mention d'une mise en œuvre effective de cette norme. Parfois, c'est parce qu'il n'y en a pas (contrairement à une légende tenace, ce n'est nullement une obligation pour la publication d'un RFC). Parfois, c'est parce qu'elle n'est pas mentionnée. Avant la publication d'un RFC, lorsque le document est encore un simple Internet-Draft, la mention de l'existence de programmes mettant en œuvre le protocole ou le format décrit est facultative. Ce RFC propose de formaliser et d'encourager cette mention. Son prédecesseur, le RFC 6982 avait lancé l'idée, comme une expérimentation. Elle a été un grand succès et ce nouveau RFC passe donc au stade supérieur : publier l'état des implémentations d'un draft est désormais une Bonne Pratique (BCP, « Best Common Practice »).
Cela ne concerne que les Internet-Drafts, pas les RFC. En effet, les RFC sont stables (jamais modifiés) alors que les URL pointant vers un programme ne le sont pas : un programme peut être abandonné, plus maintenu, on peut se retrouver avec des 404, etc. Donc, un RFC n'est pas le bon endroit pour stocker un catalogue de mises en œuvre d'un protocole. Ce RFC 7942 ne vise que les Internet-Drafts, afin d'aider à l'évaluation d'une proposition. La section décrivant les mises en œuvre est donc typiquement supprimée lors de la publication du RFC. Comparez par exemple le draft-ietf-dnsop-qname-minimisation (dont la section 8 décrit les mises en œuvre existantes) avec le RFC 7816 (qui n'a plus cette section).
Le concept de running code est décrit dans le Tao (cf. RFC 4677 et RFC 6722). Il synthétise l'approche pragmatique de l'IETF : une norme qui n'est pas mise en œuvre ne sert à rien. Malgré cela, bien des RFC n'ont jamais connu la moindre mise en œuvre. En effet, ce principe général du running code n'a jamais été traduit dans une exigence formalisée et globale pour les auteurs de RFC. Il existe par contre des règles locales. Ainsi, la Routing Area de l'IETF (les groupes de travail qui normalisent les protocoles de routage) a longtemps demandé (RFC 1264) au moins une mise en œuvre avant la publication d'un RFC sur le chemin des normes. Le RFC 4794 a supprimé cette règle, qui reste appliquée par certains groupes de la Routing Area comme IDR. À noter qu'avant le RFC 6982, il y avait déjà des compte-rendus de mise en œuvre (implementation reports) qui étaient des documents séparés, racontant des expériences concrètes de développement.
Notre RFC 7942 n'impose pas une règle (la section Implementation Status reste facultative), mais il encourage fortement à formaliser une section dans les Internet-Drafts, qui permettra de documenter les mises en œuvre connues. L'idée est que les Internet-Drafts ayant cette section seront examinés avec plus de bienveillance, sans toutefois qu'elle soit obligatoire.
La section 4 du RFC fait la liste de tous les avantages qu'il y a à indiquer ces mises en œuvre dans l'Internet-Draft : meilleure information pour la prise de décision (aussi bien sur la publication de l'Internet-Draft que sur le statut du futur RFC), encouragement aux tests d'interopérabilité, possibilité (lorsque le code est publié) de mieux comprendre le protocole (beaucoup de programmeurs préfèrent lire le source plutôt que le RFC mais attention, la référence doit rester le RFC, le code n'est pas une spécification), et enfin assurance que telle fonction du RFC peut effectivement être mise en œuvre. C'est en effet souvent le cas (par exemple lors de la discussion qui a mené au RFC 5155) que certaines personnes affirment que la technologie envisagée est tout simplement trop complexe pour être programmée. L'existence d'un programme qu'on peut tester permet de d'assurer que, si, la technologie est réaliste (bien d'autres SDO produisent sans hésiter des technologies impossible à programmer dans des conditions raisonnables).
Cette section, « Implementation status » est décrite en section 2 de ce RFC. Elle est située vers la fin (comme l'actuelle - et obligatoire, elle - « Security considerations ») et peut comporter les points suivants :
Cette section peut aussi indiquer l'expérience tirée de cette mise en œuvre, ainsi que des informations sur l'interopérabilité, au cas où plusieurs mises en œuvre existent. Les présidents des groupes de travail sont explicitement chargés de vérifier que cette section ne dégénère pas en simple marketing pour le produit d'un vendeur. Notre RFC propose aussi un texte standard d'avertissement (« boilerplate ») à inclure au début de cette section « Implementation status ».
D'autres endroits que l'Internet-Draft lui-même auraient pu être utilisés pour informer sur les mises en œuvre existantes. Le RFC suggère (section 3) de passer au wiki de l'IETF lorsque la liste des programmes devient trop longue, lorsqu'il semble préférable que cette liste soit maintenue par les implémenteurs plutôt que par les auteurs de l'Internet-Draft, lorsque le groupe de travail maintient activement un wiki, ou enfin lorsque la liste en question semble utile, même après la publication en RFC (pour indiquer le niveau d'adoption par les programmeurs). Dans tous ces cas, il est bon d'indiquer l'URL du wiki en question dans l'Internet-Draft.
De très nombreux
Internet-Drafts incluent
désormais une telle section Implementation
Status, « bien trop pour qu'on puisse les compter », note
l'IESG dans son approbation de ce
document. Quelques exemples d'Internet-Drafts qui
incluent actuellement cette section : draft-ietf-dnsop-nxdomain-cut
ou
draft-ietf-dane-openpgpkey
.
Le principal changement par rapport au RFC précédent, le RFC 6982 est un changement de statut. On passe de « expérimental » à « Bonne Pratique », reflétant le succès de cette expérience. Autrement, il n'y a que des changements de rédaction, rien de crucial.
Date de publication du RFC : Août 2016
Auteur(s) du RFC : K. Davies (ICANN), A. Freytag
(ASMUS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF lager
Première rédaction de cet article le 29 août 2016
Lorsqu'on a des identificateurs en Unicode (par exemple pour les noms de domaine internationalisés), on souhaite souvent limiter le nombre de caractères autorisés, et avoir des possibilités de variante (par exemple, dire que deux chaînes de caractères Unicode sont en fait équivalentes sémantiquement). Il faut donc rédiger ces règles, et un langage formel est certainement utile pour cela. C'est ce que propose ce nouveau RFC, qui normalise un langage XML pour décrire les règles d'enregistrement de ces identificateurs Unicode.
Le terme utilisé par le RFC est LGR, pour Label Generation Ruleset. Label est le composant de base d'un nom de domaine, et Ruleset fait référence à l'ensemble des règles décrites en XML et qui permettront de savoir si un composant est valide, et quelles transformations éventuellement effectuer avant de l'enregistrer. C'est un concept qui vient de l'ICANN, qui a toujours présenté les IDN comme une chose dangereuse (bien à tort), nécessitant des variant tables ou autres algorithmes compliqués. Donc, si vous ne travaillez pas avec l'ICANN, il n'est pas nécessaire de connaitre ce RFC.
Le langage présenté dans ce RFC est assez complexe, mais le problème est complexe. Ceci dit, dans les cas « simples » (alphabet latin), les règles LGR seront également simples. Si on veut juste dire que é, è et ë sont autorisés dans les noms, et avec e comme variante, c'est trivial à faire, à peine plus compliqué que les tables du RFC 4290.
Notez que l'algorithme décrit par un LGR ne suffit pas comme règle d'enregistrements des noms de domaine : il existe d'autres règles (comme la priorité aux entreprises titulaires de propriété intellectuelle) qui ne sont pas exprimables par ces algorithmes.
Avant ce RFC, les règles concernant les
IDN étaient publiées en langue naturelle,
ou parfois dans le langage formel des RFC 3743 et/ou RFC 4290. Le langage
décrit ici a vocation à les remplacer. Il est structuré, donc
lisible par un programme, et permet de dériver automatiquement les
programmes de vérification d'un nom (par exemple ceux qui sont
lancés par un serveur EPP recevant un ordre
<domain:create>
, RFC 5731, section 3.2.1).
Le format est relativement simple si on a une politique simple mais permet le cas échéant de mettre en œuvre des politiques très complexes (qui sont utiles pour certaines écritures asiatiques, par exemple). Il est conçu pour les IDN mais peut être utilisé si on a à enregistrer des identificateurs Unicode dans un autre contexte.
Le cahier des charges du format des LGR figure en section 2 du RFC :
Un point important de ce RFC est qu'il décrit un format, pas une politique : le RFC ne dit pas si le caractère Unicode U+00E8 (è) doit être considéré comme une variante du U+0065 (e) : il fournit juste le moyen d'exprimer cette équivalence, si on le décide.
La section 4 du RFC spécifie le format exact. (Le schéma formel
- en
Relax NG - est dans l'annexe D.) Un
ensemble de règles LGR est mise dans un élément XML
<lgr>
. Il contient quelques
métadonnées, dont la date et la langue ou
l'écriture pour lesquels ce LGR est prévu. Comme l'ICANN, dans ses
politiques IDN, mélange très souvent langue et écriture (par
exemple en parlant de « domaines multilingues », ce qui est
absurde), il faut préciser que la plupart des politiques portent
sur des écritures (un nom de domaine n'a pas de langue :
coca-cola.com
est-il de l'anglais ?) La
valeur de l'élément XML <language>
est
une étiquette du RFC 5646, avec la langue
marquée comme « non définie » (und
pour
undeterminate). Un exemple pour une politique
consacrée à l'alphabet cyrillique :
<language>und-Cyrl</language>
.
Les règles elle-mêmes sont en section 5. La plus simple est
celle qui autorise un caractère donné, ici le
tiret (cp
=
Code Point Unicode, ici U+002D) :
<char cp="002D"/>
On peut aussi autoriser un intervalle, ici tous les chiffres arabes :
<range first-cp="0030" last-cp="0039"/>
Comme on le voit, les caractères sont identifiés par leur point de code Unicode, écrit sans le « U+ » initial. Bien que XML permettre de représenter nativement tous les caractères Unicode, cette possibilité n'est pas exploitée par ce RFC (cf. Unicode Standard Annex #42).
Voici maintenant un exemple de règle qui précise que le point médian U+00B7 n'est autorisé qu'entre deux l (c'est le cas en catalan mais notez qu'en français, il est aussi utilisé dans une perspective féministe). Cela se fait en indiquant une séquence :
<char cp="006C 00B7 006C" comment="Catalan middle dot"/>
Et voici une règle contextuelle plus complexe. On veut n'autoriser
le gluon de largeur nulle U+200D qu'après un virāma. Si une règle
follows-virama
(non montrée ici) a été
définie, on peut écrire :
<char cp="200D" when="follows-virama" />
Et les variantes ? Voici d'abord comment exprimer que le é est une simple variante du e (non pas que je recommande cette politique : c'est juste un exemple) :
<char cp="00E8"> <var cp="0065"/> </char>
Et une variante où un caractère (œ) est mis en correspondance avec deux caractères (oe) :
<char cp="00F6"> <var cp="006F 0065"/> </char>
Ces règles portaient sur des caractères qui formaient une partie d'un composant d'un nom. Mais il y a aussi des règles qui portent sur la totalité du composant (section 6 du RFC). Pour cela, d'abord un petit mot sur la notion de classe. On définit une classe de caractères à partir de propriétés Unicode. Ici, on a la classe des virāma, définie à partir de la propriété Unicode CCC (Canonical Combining Class) :
<class name="virama" property="ccc:9" />
On peut ensuite combiner les classes par intersection, union, etc.
Les règles permettent aussi d'utiliser des opérateurs
booléens. Voici par exemple la règle
traditionnelle des noms de machines (et pas des noms de domaine,
contrairement aux bêtises qu'on lit souvent), autorisant lettres
ASCII, chiffres et tiret. Elle utilise
<choice>
, qui fait un OU logique entre
les termes :
<rule name="ldh"> <choice count="1+"> <class by-ref="letter"/> <class by-ref="digit"/> <char cp="002D" comment="literal HYPHEN"/> </choice> </rule>
Des exemples plus réalistes et plus détaillés figurent dans l'annexe A.
Le document XML complet a le type MIME
application/lgr+xml
.
Quelques petits mots sur la sécurité (section 12 du RFC). Le RFC part du préjugé (qui est faux) comme quoi les noms en Unicode poseraient des problèmes de sécurité. La section 12 note ensuite (si on accepte cette prémisse) que les règles de ce RFC ne résolvent pas complètement le problème (qui est largement imaginaire). Il reste possible de faire des noms « trompeurs » même avec les règles les plus strictes. Outre question de sécurité à garder en tête : les règles de ce RFC peuvent permettre de concevoir des politiques LGR très complexes, qui peuvent épuiser les ressources de la machine qui tenterait de les évaluer.
Si vous voulez pratiquer avec vos propres LGR, l'ICANN a fait développer un outil qui est accessible en ligne (lisez la documentation pour connaitre le mot de passe) ou bien en source sur GitHub : lgr-core et lgr-django pour l'interface Web en Django.
Date de publication du RFC : Août 2016
Auteur(s) du RFC : F. Le
Faucheur, G. Bertrand, I. Oprescu, R. Peterkofsky
(Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF cdni
Première rédaction de cet article le 16 septembre 2016
Ce RFC fait partie de la série qui normalise les interactions entre un CDN amont (celui choisi par le client) et un CDN aval (celui auquel, pour une raison ou pour une autre, une partie du trafic est délégué). Il traite la question de la journalisation : comment est-ce que le CDN aval remonte au CDN amont le journal d'activité ?
Cette idée d'interconnexion standard des CDN est expliquée dans le RFC 6707, le cadre général est dans le RFC 7336, dont la section 4.4 identifie le besoin d'un mécanisme de journalisation, et le cahier des charges est dans le RFC 7337, la journalisation étant couverte dans sa section 8.
Notre nouveau RFC décrit d'abord (section 2) le modèle de la journalisation. Certains des aspects de celle-ci (comme la possibilité pour le CDN amont de configurer ce que le CDN aval va journaliser ou pas) sont considérés comme hors-sujet. Dans le modèle, la seule activité normalisée est la remontée des journaux depuis le CDN aval. Cela permettra au CDN amont de faire de jolies statistiques, de payer son CDN aval selon son activité, etc.
Après, on descend dans le concret : la section 3 décrit le
format des journaux. Il est très inspiré du format
ELF. Un fichier journal est composé d'enregistrements,
chacun composé de champs. Voici un exemple d'une requête
HTTP (où
<HTAB>
désigne une
tabulation horizontale) :
2013-05-17<HTAB>00:39:09.145<HTAB>15.32<HTAB>FR/PACA/NCE/06100<HTAB>GET<HTAB>http://cdni-ucdn.dcdn-1.example.com/video/movie118.mp4<HTAB>HTTP/1.1<HTAB>200<HTAB>15799210<HTAB>"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.127 Safari/533.4"<HTAB>"host1.example.com"<HTAB>1
Mais attention en lisant cet exemple, le format effectif peut être modifié par des directives placées au début du fichier. (La liste des directives figure dans un registre IANA.)
Le fichier journal peut être transmis par divers protocoles (sections 4 et 5 du RFC) mais celui décrit dans ce RFC est fondé sur Atom (RFC 4287). Le CDN aval publie un flux Atom où le CDN amont trouvera les noms des fichiers à télécharger, a priori en HTTP (et même plutôt HTTPS puisque ces journaux sont confidentiels, cf. section 7.3).
Date de publication du RFC : Juillet 2016
Auteur(s) du RFC : L. Colitti (Google), V. Cerf
(Google), S. Cheshire
(Apple), D. Schinazi (Apple)
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 24 juillet 2016
Combien d'adresses IPv6 faut-il permettre à une machine qui se connecte ? « Une » est évidemment le minimum mais est-ce suffisant ? Non, explique ce RFC qui recommande aux opérateurs et FAI de permettre aux machines de s'allouer autant d'adresses IPv6 qu'elles en ont besoin.
IPv6 est juste une nouvelle version d'IP. Ce n'est pas un nouveau protocole. Néanmoins, la taille bien plus importante de son espace d'adressage a des conséquences qui sont souvent oubliées par les administrateurs de réseaux. Ainsi, il est fréquent que la gestion des réseaux soit faite en limitant chaque machine à une seule adresse IPv6. En IPv4, il n'y a évidemment pas d'autre choix possible, en raison de la pénurie d'adresses publiques. Mais en IPv6, il n'y a aucune raison de se limiter, et beaucoup de raisons de permettre davantage d'adresses. Bref, bien qu'IPv6 ne soit pas complètement nouveau, cela ne veut pas dire que les bonnes pratiques IPv4 s'appliquent directement à IPv6.
Il est banal de faire remarquer que les adresses IPv6 sont, en pratique, illimitées. Un simple lien réseau (numéroté avec un préfixe de 64 bits) offre quatre milliards de fois plus d'adresses que tout l'Internet IPv4 ! Il n'est donc pas du tout obligatoire de rationner. IPv6 est conçu depuis le début (section 2 de notre RFC) avec l'idée que chaque machine (et même chaque interface réseau de chaque machine) aura plusieurs adresses IP (par exemple, une adresse locale au lien, une adresse publique stable, et au moins une adresse temporaire du RFC 8981). Et toutes les mises en œuvre d'IPv6 existantes gèrent cela correctement.
Mais quel est l'intérêt de permettre plusieurs adresses ? La section 3 de ce RFC répond à la question :
draft-herbert-nvo3-ila
).Et quels sont les problèmes si on ne fait pas ce que recommande ce RFC ? La section 4 les liste. Évidemment, si ajouter des adresses IP est complètement impossible, on est fichus. Et si la connexion au réseau permet d'ajouter des adresses IPv6 mais que cela nécessite une action explicite (par exemple via l'interface Web de l'hébergeur) ? Cela entraine :
Pourquoi les opérateurs restreindraient-ils ainsi l'obtention d'adresses IPv6 supplémentaires ? Par pur sadisme ? Non, il peut y avoir des raisons objectives :
Avec le temps, il faut espérer que les limites matérielles reculent et que la raison business (faire payer) soit rejetée par les utilisateurs (ils peuvent la contourner, par exemple en faisant du NAT, ce qui serait un comble pour IPv6).
À propos de NAT, est-ce que c'est une bonne stratégie pour résoudre le problème d'un opérateur qui ne laisserait pas assez d'adresses IPv6 à ses clients (section 5 du RFC) ? Les problèmes et limites du NAT sont bien connus (RFC 2993). Les applications sont plus complexes (car leurs programmeurs doivent déployer des trésors d'ingéniosité pour contourner le NAT), la gestion de la durée de vie des correspondances entre adresses dans le routeur NAT est pénible (quel intervalle entre les paquets d'entretien de la connexion ?), etc. C'est pour cela que le NAT sur IPv6 est très déconseillé (RFC 5902).
Ce n'est pas faute de mises en œuvre (le NAT66 est dans Linux depuis 2012...), un vendeur de virtualisation l'a aussi développé, précisement pour contourner ce manque d'adresses IPv6 allouées, mais il n'est pas souhaitable que cela continue. Le but d'IPv6 est d'avoir une vraie connectivité de bout en bout, qui ne soit limitée que par des choix délibérés (Alice ne veut plus parler à Bob), pas par des limites techniques inutiles.
Et si l'opérateur du réseau où se connecte la machine a été convaincu par ce RFC, et veut permettre à ses clients d'allouer les multiples adresses IPv6 dont ils ont besoin, quels sont les mécanismes techniques dont il dispose pour cela ? La section 6 les couvre :
Un tableau à la fin de la section 6 résume les forces et faiblesses de chaque solution.
Au fait, combien d'adresses exactement peut-on s'attendre à voir sur une seule machine ? La section 7 se lance dans la spéculation. Les adresses « vie privée » du RFC 8981 peuvent consommer jusqu'à huit adresses en même temps. Avec une demi-douzaine de services réseau, et une demi-douzaine de machines virtuelles (ou de containers) hébergés, avoir vingt adresses sur une seule machine peut donc être raisonnable. Mais, bien sûr, il est difficile de prévoir les usages futurs et, en pratique, ce sera peut-être bien plus.
Allez, c'est presque fini, la section 8 du RFC synthétise les recommendations officielles :
Ces recommandations, si elles sont suivies, auront quelques conséquences pratiques (section 9). Par exemple, elles ne permettent pas de garder trace de quelles adresses sont utilisées par quelle machine. (Alors qu'avec une demande d'allocation explicite, par exemple par le biais d'une nouvelle interface virtuelle, comme c'est le cas actuellement chez Gandi, ce suivi est possible.) C'est ennuyeux si on veut remonter d'une adresse IP qui pose un problème (par exemple parce qu'il a téléchargé Les tortues Ninja) à son propriétaire. Une solution de remplacement est de superviser le réseau et de relever les réponses NDP, permettant ainsi de se constituer une base de la relation entre les adresses IP et les adresses MAC. Le logiciel NDPMon permet de faire cela. (On peut aussi interroger les commutateurs en SNMP, pour avoir un résultat analogue.) Les auteurs du RFC notent que tous leurs employeurs ont déjà un tel système en place, et ils citent plusieurs gros campus universitaires qui font de même, ce qui montre le caractère réaliste de la proposition.
Puisqu'on parle de sécurité, il faut noter que de ne pas permettre officiellement aux machines de s'attribuer des adresses IP supplémentaires ne signifiera pas qu'elles ne le feront pas. Si on n'a pas de sécurité dans la couche 2 (cf. RFC 7039), les machines peuvent toujours se configurer ce qu'elles veulent. En outre, si le mode d'allocation est DHCP, les efforts actuels pour améliorer la vie privée des utilisateurs de DHCP (RFC 7844) vont de toute façon diminuer l'intérêt de DHCP pour la sécurité.
Autre problème pratique pour les administrateurs réseau, les limites du matériel. Si un commutateur connecte mille machines, sa table de correspondance adresses IP <-> adresses MAC aura mille entrées. Si chaque machine s'alloue dix adresses, cette table devra stocker dix mille entrées. Le commutateur a-t-il cette capacité ? S'il ne l'a pas, on risque des pertes de connectivité. Certes, le matériel va évoluer. Mais il existe une autre solution, suggérée par notre RFC : utiliser un préfixe IP par machine. Ainsi, le commutateur n'aura à gérer qu'une seule entrée par machine, quel que soit son nombre d'adresses. Évidemment, cela consommera davantage d'adresses IPv6, et cela compliquera un peu la gestion des adresses. Cette proposition est donc légèrement plus sujette à controverse que la principale (permettre plusieurs adresses par machine) qui, elle, est largement reconnue comme justifiée.
Date de publication du RFC : Août 2016
Auteur(s) du RFC : P. Wouters (Red Hat)
Expérimental
Réalisé dans le cadre du groupe de travail IETF dane
Première rédaction de cet article le 25 août 2016
Dernière mise à jour le 12 décembre 2017
Un problème classique du système de
cryptographie
OpenPGP, normalisé dans le RFC 9580 est de vérifier les clés publiques des
correspondants. Les trouver, c'est relativement facile : le
correspondant pense à vous les envoyer ou bien on se sert tout
simplement d'un serveur de clés. Mais
ceux-ci ne garantissent rien sur la clé. N'importe qui peut créer
une clé marquée flotus@whitehouse.gov
et la
mettre sur les serveurs de clé, même si cette clé n'a rien à voir
avec la Maison-Blanche. Avant la solution
de ce nouveau RFC, il n'existait pas de
mécanisme sécurisé pour récupérer une clé publique PGP. Que
propose ce RFC ? De mettre les clés dans le
DNS (nouveau type d'enregistrement OPENPGPKEY
), dans le domaine de la partie droite de
l'adresse de courrier, sécurisée par
DNSSEC. En gros, il s'agit de faire pour le
courrier et PGP ce que fait déjà DANE (RFC 6698) pour
le Web/TLS.
Les serveurs de clés utilisent le protocole HKP (jamais décrit dans un RFC). Ils fournissent un service très utile en permettant de chercher une clé, par son identificateur, ou par l'adresse de courrier associé. Voici un exemple par identificateur :
% gpg --recv-key 0xF3396311465F8E5D gpg: requesting key 465F8E5D from hkps server hkps.pool.sks-keyservers.net gpg: key 465F8E5D: public key "Amaelle G <amaelle.guiton@techn0polis.net>" imported ... gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1)
et un par adresse (notez que les adresses sont probablement toutes fausses) :
% gpg --search-key elysee.fr gpg: searching for "elysee.fr" from hkps server hkps.pool.sks-keyservers.net (1) hollande (flamby) <hollande@elysee.fr> 2048 bit RSA key CF22758A, created: 2014-01-06 (2) jacques chirac (ancienne adresse) <jacques-chirac@elysee.fr> 2048 bit RSA key 2A97F759, created: 2007-11-15, expires: 2007-11-16 (expired) (3) kaziwan <kaziwan@elysee.gouv.fr> 1024 bit DSA key AA7FD67C, created: 2005-11-28 (4) Gerard Calestroupat <gerard.calestroupat@elysee.fr> 1024 bit DSA key 82F02C73, created: 2003-08-05, expires: 2003-08-08 (expired) (5) Toto Berlingo <T.Berlingo@Elysee.fr> 1024 bit DSA key E9E920B7, created: 1999-06-10
Ces serveurs n'offrent aucune garantie : n'importe qui peut y publier une clé, avec n'importe quelle adresse et certaines clés sont clairement mensongères. L'usage normal est de récupérer la clé et ses signatures, puis de vérifier les signatures. Si elles sont faites par des gens qu'on a validés (directement, ou bien transitivement, jusqu'à une certaine profondeur), on estime la clé correcte (c'est ce qu'on nomme le web of trust). Autrement, la clé ne vaut rien. En outre, le seul système de révocation est de signer une révocation avec sa clé privée : si on l'a perdue, on ne pourra jamais retirer la clé des serveurs de clé. Pour ces deux raisons (fausses clés, et clés devenues inutilisables), il est donc difficile d'utiliser automatiquement, depuis un MUA ou un MTA, ces serveurs.
La solution proposée dans ce RFC est, comme souvent aujourd'hui, d'utiliser le DNS, qui a montré sa fiabilité et son ubiquité. Tout le monde peut faire des requêtes DNS, même coincé derrière un pare-feu, et tout le monde peut les valider, grâce à DNSSEC (RFC 4035).
On va donc publier dans sa zone DNS des enregistrements de type
OPENPGPKEY
, indexés par la partie gauche de
l'adresse de courrier (c'est un peu plus compliqué, car elle peut
contenir des caractères qui sont spéciaux pour le DNS ; voir plus
loin). Le correspondant qui veut envoyer du courrier à quelqu'un
cherchera cet enregistrement dans le DNS, et, s'il en trouve un,
le validera avec DNSSEC et récupérera ainsi une clé PGP
relativement sûre. La révocation d'une clé se fait simplement en
retirant l'enregistrement du DNS.
La solution de ce RFC rend envisageable de récupérer et de vérifier automatiquement une clé avant l'envoi d'un message. Mais le RFC note bien qu'elle ne remplace pas complètement le web of trust, qui reste nécessaire si on veut une vérification sérieuse.
Ce RFC a le statut « Expérimental ». Il s'agit de tester l'idée
et de voir si elle marche bien, et n'a pas trop
d'inconvénients (par exemple de taille des zones DNS pour les
domaines gérant beaucoup de comptes de courrier, surtout vu la
taille des enregistrements OPENPGPKEY
). Si le nombre de messages chiffrés avec OpenPGP
augmente significativement suite à ce RFC, ce sera bon
signe.
Notez qu'une expérience ressemblant à celle-ci avait déjà
été faite avec le type d'enregistrement DNS
CERT
du RFC 4398. Ce fut un échec
(peu de déploiement, peut-être en raison de la complexité du type
CERT
).
La section 2 de notre RFC décrit le format du nouveau type d'enregistrement DNS. Chaque enregistrement contient une et une seule clé. Si un utilisateur a plusieurs clés, il doit créer plusieurs enregistrements. Le type est 61 (et enregistré à l'IANA depuis août 2014). La partie droite de l'enregistrement (les données) contient la clé et au moins un ID et une auto-signature. Les clés PGP complètes, avec des tas de signatures, peuvent être grosses, trop pour le DNS ; le RFC recommande de ne publier que des clés minimales (pas trop de signatures, par exemple, et évidemment pas les photos qu'on peut inclure dans un attribut de la clé, cf. RFC 9580, section 5.12.1). Avec GnuPG, regardez l'exportation de ma clé avec toutes ses méta-données, et en exportation minimale (l'annexe A du RFC décrit les commandes GnuPG à utiliser) :
% gpg --export CCC66677 > key.pgp % ls -lh key.pgp -rw-r--r-- 1 bortzmeyer bortzmeyer 86K Aug 25 17:17 key.pgp % gpg --export --export-options export-minimal,no-export-attributes CCC66677 > key.pgp % ls -lh key.pgp -rw-r--r-- 1 bortzmeyer bortzmeyer 5.8K Aug 25 17:18 key.pgp
Le format utilisé est celui du RFC 9580,
section 10.1. C'est donc du binaire qui circule sur le réseau
(rappelez-vous bien que, dans le DNS, le format de présentation,
celui des fichiers de zone, et de la sortie de
dig, n'a rien à voir avec le format binaire
utilisé sur le réseau.) Les formats « texte » d'OpenPGP
(« ASCII armor ») ne sont pas utilisés sur le
réseau. (Donc, avec GnuPG, pas d'option --armor
.)
Le format de présentation (celui des fichiers de zone et de la sortie de dig) encode la clé en Base64.
Et la partie gauche de l'enregistrement DNS ? Quel est le nom de domaine utilisé ? La section 3 du RFC fixe les règles :
OPENPGPKEY
. La clé pour l'adresse
stephane+chose@trucmachin.example
sera donc dans
la zone trucmachin.example
.stephane+chose
, dans l'exemple ci-dessus),
et du composant _openpgpkey
,
avec le domaine de l'adresse de courrier
(trucmachin.example
dans l'exemple
ci-dessus). Le condensat est tronqué à 28 octets. (Le nom de domaine n'est pas utilisé dans le
condensat, pour faciliter la vie des opérateurs qui proposent la
même adresse dans différents domaines.)"jipoune le meilleur"@example.com
est une
adresse de courrier légale) sont retirés.
Ainsi, si l'adresse de l'utilisateur est
hugh@example.com
, la requête
OPENPGPKEY
devra chercher
c93f1e400f26708f98cb19d936620da35eec8f72e57f9eec01c1afd6._openpgpkey.example.com
.
Voici comment calculer cela avec les outils du
shell Unix (28
octets = 56 caractères dans la représentation en hexadécimal) :
% echo -n hugh | sha256sum | cut -c -56 c93f1e400f26708f98cb19d936620da35eec8f72e57f9eec01c1afd6
Une des difficultés pour trouver le bon nom de domaine est que
les applications doivent traiter la partie gauche des adresses de
courrier comme opaque (pas le droit d'analyser sa structure) et
qu'elles ne connaissent pas les règles de canonicalisation
qu'appliquera le domaine de destination, comme
d'ignorer la casse de la partie locale (ce
qui est souvent fait, mais pas toujours). Par exemple,
Gmail ignore les points dans les adresses
(donc foobar@gmail.com
et
foo.bar@gmail.com
arrivent dans la même boîte
aux lettres). L'émetteur qui ne connait pas cette règle va
chercher la clé dans un domaine qui ne sera pas le bon. Idem avec
les sous-adresses utilisées par certains domaines (en général
avec le séparateur plus, comme
stephane+blog
,
stephane+ietf
, etc). Le RFC rappelle que
l'émetteur ne peut pas se permettre de deviner ces règles locales,
et qu'elles peuvent changer à tout moment. C'est au destinataire
de se débrouiller, en publiant la clé à plusieurs noms, et en
faisant attention aux variantes qu'il publie.
L'internationalisation des adresses de courrier complique évidemment encore un peu les choses (voir par exemple la section 10.1 du RFC 6530).
La section 6 du RFC se penche sur un problème pratique qu'on rencontre parfois avec le DNS : la difficulté à recevoir des réponses au-delà d'une certaine taille (il y a trois limites fréquemment rencontrées, la très ancienne limite de 512 octets du DNS, largement dépassée de nos jours, la limite de la MTU à 1 500 octets, au-delà de laquelle peut commencer la fragmentation, et la limite par défaut de la plupart des clients DNS à 4 096 octets). Les clés PGP peuvent être grosses, et le RFC recommende donc si possible de les récupérer sur TCP, pas UDP.
La section 7 de notre RFC analyse les questions de sécurité
liées à cette technique. Elle rappelle que
DNSSEC doit être
utilisé : les enregistrements OPENPGPKEY
récupérés ne doivent être utilisés que s'ils sont signés, et que
la signature est valide. (Autrement, il serait trop facile à un
attaquant de répondre avec une fausse clé.) Mais si DNSSEC est
nécessaire, il n'est pas suffisant et la validation habituelle des
clés PGP reste nécessaire si on veut un haut niveau de
confidentialité. Ceci dit, comme souvent en sécurité, le mieux est
l'ennemi du bien, et il vaut mieux une clé pas très vérifiée
plutôt que d'envoyer le message en clair, comme le fait presque
tout le monde aujourd'hui.
Et, évidemment, la sécurité DNSSEC doit être équivalente à la sécurité PGP puisqu'un attaquant qui aurait cassé la clé DNSSEC pourrait remplacer toutes les clés PGP du domaine. Il faut donc une cohérence dans les politiques de sécurité entre PGP et DNSSEC (section 7.6).
Autre problème de sécurité, cette fois lié à la vie
privée : les requêtes DNS révèlent avec qui on veut
communiquer de manière sécurisée par courrier (RFC 7626). Le fait que le nom de domaine utilisé soit un
condensat de la partie locale de l'adresse de courrier limite un
peu les risques, mais pas suffisamment (si on soupçonne qu'Alice
écrit à bob@example.com
mais qu'on n'en est
pas sûr, il suffit de construire le nom où se trouve
l'enregistrement OPENPGPKEY
et de vérifier
que ce nom est demandé, cf. section 7.4). C'est d'autant plus grave que les clients
DNS actuels envoient en général le nom de domaine complet à
tous les serveurs, même ceux qui n'en ont pas
besoin. La minimisation de la requête (RFC 9156) limite ce problème. Le chiffrement des requêtes
DNS (RFC 7858) peut faire le reste. Le cache
du DNS limite un peu les risques et il est donc essentiel de ne
pas faire une requête DNS externe à chaque fois qu'on envoie un
message PGP à quelqu'un, cela ferait fuiter bien trop
d'informations (section 7.5).
Pour limiter les risques qu'un attaquant récolte toutes les adresses de courrier du domaine, le RFC recommande de signer la zone en utilisant NSEC3 (RFC 5155).
À l'inverse de ce souci de protection de la vie privée, si une organisation veut lire le courrier de ses employés, la solution est qu'elle publie une clé d'organisation dans le DNS, pour pouvoir déchiffrer les messages entrants.
Un autre problème de sécurité est le risque d'utilisation dans
des attaques par
amplification. La taille importante des enregistrements
OPENPGPKEY
(surtout avec les clés
RSA) aggrave ce risque. Le RFC suggère de
n'envoyer ces enregistrements via UDP que si l'adresse IP source de la
requête a été vérifiée, par exemple avec les petits gâteaux du
RFC 7873.
Où en sont les mises en œuvre de ce RFC ? GnuPG contient le code pour gérer ces clés dans le DNS depuis la version 2.1.9. Même chose pour openpgp-milter.
L'outil hash-slinger
permet quant à lui de générer et de vérifier des enregistrements
OPENPGPKEY
:
% openpgpkey --fetch --uid paul@nohats.ca paul@nohats.ca -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: paul@nohats.ca key obtained from DNS Comment: key transfer was protected by DNSSEC Version: GnuPG v1 mQENBFaJkKsBCADDSwQawRsKYqY/DuxWZjNNn39f14tDaswbpuF+PorNnt0MrepI 0yVY28NQ+5P09j75Os1jlqksK06aAVBtkJvr+T1ip85AxPUdTjD3U3zhM5/YATMi ...
On peut alors enregistrer la clé dans le trousseau PGP :
% openpgpkey --fetch --uid paul@nohats.ca paul@nohats.ca | gpg --import gpg: key BBAE5D31: public key "Paul Wouters (online key) <paul@nohats.ca>" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1)
Voici un exemple de récupération de ma clé :
% openpgpkey --fetch --uid 'stephane@bortzmeyer.org' stephane@bortzmeyer.org |gpg pub 4096R/CCC66677 2014-02-08 Stéphane Bortzmeyer (Main key) <stephane@bortzmeyer.org> uid Stéphane Bortzmeyer <stephane@sources.org> uid Stéphane Bortzmeyer (Work address) <bortzmeyer@nic.fr> uid TextSecure fingerprint (05 d6 3b dc b7 e4 d7 69 2f f6 24 d5 51 31 88 2f a5 59 ae 96 e0 fb a5 75 ab e6 6c 64 ca e9 bb 6a 77) <BdY73Lfk12kv9iTVUTGIL6VZrpbg+6V1q+ZsZMrpu2p3@base64> sub 4096R/96A4A254 2014-02-09 [expires: 2018-01-10] sub 4096R/57F02AA1 2014-02-09 [expires: 2017-01-10]
Mais comment ai-je fait pour que ça marche ? hash-slinger permet de créer la clé directement au bon format :
% openpgpkey --create stephane@bortzmeyer.org ; keyid: 555F5B15CCC66677 28182f0a278161989f90f090dabd6cab331663d8509ddbae617bb1e7._openpgpkey.bortzmeyer.org. IN OPENPGPKEY mQINBFL2VNABE...
Il n'y a plus qu'à la mettre dans le fichier de zone, et à re-signer.
Mais, car il y a un mais, cela ne marche que si on a des logiciels
récents, qui connaissent le type 61
(OPENPGPKEY
). Si ce n'est pas le cas, le signeur
refusera de signer, ou le serveur de recharger la zone. C'était mon
cas, en raison d'une trop vieille version
d'OpenDNSSEC. Trois solutions, commençons par la
plus simple, demander à hash-slinger de générer un enregistrement DNS
à la syntaxe générique (« types inconnus », du RFC 3597) :
% openpgpkey --create stephane@bortzmeyer.org --output generic ; keyid: 555F5B15CCC66677 28182f0a278161989f90f090dabd6cab331663d8509ddbae617bb1e7._openpgpkey.bortzmeyer.org. IN TYPE61 \# 5874 99020d0452f654d001100096b30513d96c42e697fd06674b1...
Et c'est cet enregistrement à la syntaxe générique qu'on met dans le fichier de zone. Sinon, si on aime bien faire l'encodage soi-même, utilisons xxd :
% openpgpkey --create stephane@bortzmeyer.org > key.zone [Edit to keep the zone data] % base64 -d key.zone > key.bin [wc -c key.bin to know what number to put in the zone file] % xxd -p key.bin > key.hex
Et on met le contenu de key.hex
dans le fichier
de zone.
Sinon, l'annexe A du RFC fournit une variante de cette solution,
utilisant hexdump.
Voici la récupération de cette clé dans le DNS, avec un
dig récent, qui connait ce type
OPENPGPKEY
et sait formater le résultat :
% dig OPENPGPKEY 28182f0a278161989f90f090dabd6cab331663d8509ddbae617bb1e7._openpgpkey.bortzmeyer.org ;; Truncated, retrying in TCP mode. ... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36368 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 9, ADDITIONAL: 13 ... ;; ANSWER SECTION: 28182f0a278161989f90f090dabd6cab331663d8509ddbae617bb1e7._openpgpkey.bortzmeyer.org. 85841 IN OPENPGPKEY ( mQINBFL2VNABEACWswUT2WxC5pf9BmdLHzPeXzHZfvik ExJHaQ7LHPRVjAQtBiBN0vI3Uh0VgFzjA+0H2sqTduJY tqd8mrTh9clDnCbrMU8svc7MeWxkW21ogjqBYL8puA3d ...
Notez le « Truncated, retrying in TCP mode ». L'enregistrement est trop gros pour les paquets UDP qu'accepte dig par défaut (il fait huit kilo-octets, dig accepte quatre par défaut). Notez aussi le bit AD (Authentic Data) dans la réponse : celle-ci a bien été validée par DNSSEC.
Avec un dig ancien, qui ne connait pas ce nouveau type (et, cette fois, on demande directement en TCP, comme le recommande le RFC) :
% dig +tcp -t TYPE61 28182f0a278161989f90f090dabd6cab331663d8509ddbae617bb1e7._openpgpkey.bortzmeyer.org ... ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19989 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 9, ADDITIONAL: 29 ... ;; ANSWER SECTION: 28182f0a278161989f90f090dabd6cab331663d8509ddbae617bb1e7._openpgpkey.bortzmeyer.org. 86206 IN TYPE61 \# 5874 ( 99020D0452F654D001100096B30513D96C42E697FD06 674B1F33DE5F31D97EF8A4131247690ECB1CF4558C04 2D06204DD2F237521D15805CE303ED07DACA9376E258 B6A77C9AB4E1F5C9439C26EB314F2CBDCECC796C645B ...
Sur ce sujet, vous pouvez aussi lire l'article de Johannes Weber, qui détaille une utilisation de l'outil de Shumon Huque.
Date de publication du RFC : Juillet 2016
Auteur(s) du RFC : D. Kutscher (NEC), S. Eum (NICT), K. Pentikousis (EICT), I. Psaras (UCL), D. Corujo (Universidade de Aveiro), D. Saucez (INRIA), T. Schmidt (HAW HAmburg), M. Waehlisch (FU Berlin)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF icnrg
Première rédaction de cet article le 25 août 2016
Quels sont les défis qui attendent l'ICN (Information-Centric Networking), ce paradigme où le composant de base du réseau n'est pas la machine ou l'interface réseau mais l'unité d'information ? Le concept est à la mode depuis pas mal d'années mais ne progresse guère sur plusieurs points importants. Ce RFC de synthèse fait le point sur ce qui ne marche pas ou pas parfaitement dans l'ICN, et les axes de recherche souhaitables.
L'idée de base de l'ICN (également nommé
CCN pour Content-Centric Networking) est de
considérer que le réseau sert surtout à accéder à du contenu (un
point de vue Minitel 2.0 très contestable)
et qu'il faut donc architecturer le réseau autour de cet accès au
contenu. Une unité d'information a un nom et
le réseau permet avant tout d'accéder à cette unité d'information,
en échange de ce nom (get(NOM)
...) L'unité
d'information est parfois nommée NDO pour Named Data
Object. On voit
que la localisation de l'information (que ce soit dans l'espace
physique, ou dans celui défini par la topologie du réseau
Internet) n'est pas prise en compte. Cette
approche permettrait, en théorie, une meilleure efficacité (la
mise en cache par les composants du réseau améliorerait les
performances), un meilleur passage à l'échelle (la réplication de
données populaires serait simple), et une meilleure résilience (le
contenu serait à plusieurs endroits). Cette idée
est décrite plus longuement dans le RFC 7476
(lecture recommandée, avant ce RFC 7927), et j'en ai
déjà écrit une critique.
Pour la mettre en œuvre, on peut envisager une couche supplémentaire « accès au contenu » au-dessus de l'Internet actuel, ou bien une approche « table rase » où on remplace IP par un protocole orienté ICN. Notez qu'il existe déjà des mécanismes pour accéder à du contenu par son nom, en ne se souciant pas de la localisation, mécanismes qui fournissent la rapidité, le passage à l'échelle et la robustesse dont on parlait plus haut. Le plus évident est bien sûr BitTorrent mais on notera que les promoteurs de l'ICN n'en parlent quasiment jamais...
D'abord, une synthèse des problèmes avec l'approche actuelle, vus du point de vue des partisans de l'ICN (section 2 du RFC). Cette approche, qualifiée de host-centric, met au centre du réseau la machine. Identifiée par des noms de domaine et/ou des adresses IP, c'est l'unité de base du réseau. On peut bien sûr bâtir une couche ICN (ou para-ICN) au-dessus de cette approche (un CDN est un exemple partiel) mais, comme le réseau n'est pas au courant, cela entraine des limitations :
Pour ce dernier point, celui de la validation, je suis personnellement toujours stupéfait que le Web n'ait toujours pas un mécanisme standard pour authentifier une page qu'on a récupéré. À l'heure actuelle, il faut toujours se contenter de mécanismes ad hoc, comme une signature PGP détachée du fichier qu'on veut valider. (Non, HTTPS n'est pas une solution, d'abord parce qu'il ne fonctionne qu'en transfert, pas après, donc on ne peut pas valider quelque chose qui stationne dans un cache, et ensuite parce qu'il est incompatible avec des miroirs, sauf à distribuer une clé privée à plein d'autres acteurs.)
Avant d'aller plus loin, la section 3 du RFC nous apporte une petite révision des termes et concepts essentiels en ICN. Pour les termes, il faut se souvenir de :
Une fois armé de cette terminologie, on peut expliquer le concept central de l'ICN : un réseau dont l'objet de base est le NDO (pas le paquet, pas la machine), et dont le service de base est d'envoyer des NDO aux demandeurs.
Ceux qui ont assisté à mon exposé à Pas
Sage En Seine 2016 ont pu voir un exemple d'ICN mis en
œuvre sur la chaîne de blocs (exemple FindByHash
).
Sur le papier, c'est très joli, mais voyons maintenant les défis que cela pose (section 4 du RFC, le gros morceau de ce texte). D'abord, le nommage et l'authentification (les deux sont en général liés dans l'ICN). Nommer un NDO est aussi crucial dans l'ICN que de donner une adresse IP à une machine dans l'Internet classique. Et comme l'objet nommé peut être récupéré à partir de divers endroits dans le réseau ICN, vérifier l'authenticité par le biais de l'origine marche encore moins que dans le Web actuel. Il y a des tas de solutions possibles, résumées dans des études comme « Naming in Content-Oriented Architectures » de Ghodsi, A., Koponen, T., Rajahalme, J., Sarolahti, P., et S. Shenker ou bien « A Survey of Information-Centric Networking » de Ahlgren, B., Dannewitz, C., Imbrenda, C., Kutscher, D., et B. Ohlman.
Il y a deux grandes façons d'organiser le nommage dans l'ICN :
espace de nommage hiérarchique, ou bien espace de nommage
plat. Par exemple, un nommage hiérarchique pourrait produire des
noms comme pays/éditeur/date/NDO
. Cette façon
de nommer simplifie nettement le routage et le passage à
l'échelle. La structure des noms permet de faire une structure
identique pour la PKI qui servira à
authentifier le contenu (ainsi, une AC pour
un éditeur donné ne pourra pas signer des certificats d'un autre
éditeur, contrairement à ce qu'on voit sur le Web aujourd'hui, où
la structure arborescente des noms de domaine n'est pas utilisée pour
limiter les dégâts que peut faire une AC.) Cette structure hiérarchique peut aussi permettre de faire des noms lisibles par des
humains. (Par contre, le RFC oublie de noter que de tels
noms suscitent d'innombrables disputes de
gouvernance : tout le monde veut être à la racine,
veut tel nom, etc.)
Autre solution, l'espace de nommage plat. Typiquement, le NDO est désigné par un condensat cryptographique de son contenu. Cela permet l'authentification de manière évidente : on récupère le contenu, on calcule le condensat, et on doit retrouver le nom. Et un tel système peut être complètement réparti, sans autorité jouant un rôle particulier. Par contre, l'absence de structure dans le nom nécessitera un système de résolution adapté (comme une DHT). Une telle solution est même déjà décrite dans un RFC, le RFC 6920.
Aucune des deux façons de gérer l'espace de nommage n'est parfaite (cf. le triangle de Zooko). Par exemple, les condensats cryptographique ne sont pas maniables par un humain, mais les noms hiérarchiques ne peuvent pas être alloués de manière complètement pair-à-pair.
Les sujets de recherche existants sur le nommage sont :
En parlant de restriction d'accès, la sécurité, dans son ensemble est un difficile problème pour l'ICN (section 4.2). C'est le cas de la plupart des solutions miracles qui sont proposées pour l'Internet : une idée simple qui semble bien marcher, puis, dès qu'on creuse les détails pratiques, les ennuis surgissent puis, dès qu'on arrive à la sécurité, l'idée simple s'effondre. Dans le cas de l'ICN, le RFC suggère plusieurs pistes de travail. D'abord, l'authentification des données, sans doute la partie la plus facile à réaliser (et celles, on l'a vu, où le Web actuel est défaillant). Comme on peut récupérer un NDO depuis n'importe où, pas forcément depuis le serveur d'origine, il est crucial de l'authentifier. Évidemment, si le nom de l'objet est un condensat de son contenu, comme c'est le cas avec le RFC 6920, la vérification de l'intégrité est facile : on récupère l'objet, on condense et on regarde si on tombe bien sur la même valeur. Pour des objets générés dynamiquement, cette solution ne fonctionne pas et il faut donc signer l'objet avec de la cryptographie asymétrique. D'ailleurs, cette cryptographie est nécessaire dans tous les cas : vérifier le nom-qui-est-un-condensat prouve l'intégrité de l'objet, pas que l'objet vient bien de l'auteur attendu. Ici, une signature cryptographique est donc également nécessaire. Comme toujours avec la cryptographie à clés publiques, cela laisse ouvert l'énorme problème de la distribution des clés... (cf. RFC 5280 pour une approche possible).
Pour l'utilisateur normal, vérifier que l'objet
148aec5042e7c05df755d9ce8adec80a1e9c10b1557194fd94e45146416a0de8
a bien un contenu qui correspond à ce condensat n'a qu'un intérêt
limité. M. Michu voudrait une authentification plus forte,
vérifier qu'il s'agit bien du guide
de sécurité Java de l'ANSSI ou que c'est bien la série télé qu'il
cherchait. Et, là, le problème est difficile. Les
défenseurs du pair-à-pair prétendent par exemple souvent que
BitTorrent est pair-à-pair, qu'il
fonctionne sans centre mais, pour la très grande majorité des
usages, c'est faux. M. Michu utilise un moteur de recherche
centralisé, comme The Pirate Bay ou comme
isoHunt. Il récupère alors un
magnet (qui contient un
condensat du fichier convoité), et, ensuite, on est vraiment en
pair-à-pair : on télécharge, on vérifie le condensat et on
s'installe dans son fauteuil pour regarder. Mais l'étape du moteur
de recherche, avec ses pubs mensongères, était tout, sauf
pair-à-pair.
En ICN, comment lier un NDO à une identité du monde extérieur, par exemple un acteur connu et de confiance ? C'est un problème essentiel mais non encore résolu.
Le contrôle d'accès, on l'a vu, est également un problème difficile. Comment faire si je veux vendre du contenu sans permettre aux destinataires de le redistribuer ? Il n'y a pas de solution évidente. Les approches intégrées sont celles où l'entité qui publie utilise des mesures pour limiter la redistribution (typiquement des menottes numériques), les approches séparées comptent sur une tierce-partie qui gère les accès (je vous laisse imaginer les conséquences en terme de liberté de choix de son logiciel par M. Michu...) On peut bien sûr chiffrer le contenu qu'on va distribuer (ah, Canal+...) mais il reste à distribuer les clés ensuite.
La cryptographie n'est pas éternelle, les algorithmes de cryptographie finissant par être affaiblis, puis cassés. Ce n'est pas un problème si on publie du contenu à courte durée de vie mais, si le contenu est encore utile et payant dans dix ans, l'efficacité de la cryptographie devient incertaine : comment garantir que l'algorithme utilisé sera toujours incassé ? L'idéal serait un mécanisme de re-signature et de re-chiffrement mais cela pose encore le problème de la gestion des clés privées.
Autre conséquence de la mise en cache et de la distribution à partir de plusieurs endroits, l'auteur d'un contenu n'aura plus de statistiques d'accès fiables. De la même façon, retirer un contenu publié sera encore plus difficile que sur le Web actuel (un contenu populaire est davantage répliqué et donc plus dur à supprimer).
Autre problème de sécurité avec l'ICN, le risque d'attaque par déni de service via le cache. Un des buts de l'ICN est de permettre, et même d'encourager, la mise en cache automatique du contenu par les éléments du réseau, comme les routeurs. Cela ouvre une possibilité d'attaque où le méchant téléchargerait plein de choses sans intérêt juste pour remplir les caches. Pire : comme l'ICN renonce explicitement au principe de bout en bout, ces éléments intermédiaires mantiennent un état et peuvent également être attaqués par ce biais. Par exemple, en annonçant plein de contenus divers, on pourrait remplir la table de routage.
Après la sécurité, le routage dans l'ICN pose également des défis intéressants. Le terme n'a pas tout à fait le même sens dans l'ICN que dans l'Internet actuel. L'ICN permet d'obtenir un contenu (le NDO, Named Data Object) en échange d'un nom. Cela nécessite trois étapes : la première est de résoudre le nom en un localisateur, plus concret. La deuxième est d'envoyer la demande de contenu à cet endroit. La troisième est d'obtenir la réponse (le NDO). Ces trois étapes peuvent être faites de différentes manières, catégorisées comme routage par nom (route-by-name), recherche par nom (lookup-by-name) et hybride.
Le routage par nom consiste à ne pas avoir la première étape, celle de résolution, ce qui simplifie le modèle : le réseau comprend directement les noms. Il faut donc une « table de routage » dont la taille permette de stocker tous les NDO. Comme on envisage entre 10^15 et 10^22 NDO, le défi technique est colossal. Sans compter qu'il faut aussi identifier la source de la requête, puisqu'il faudra bien lui envoyer le contenu demandé (c'est ce que fait l'algorithme des miettes de pain, cf. Rosensweig, E. et J. Kurose, « Breadcrumbs: Efficient, Best-Effort Content Location in Cache Networks »). Les sujets de recherche sur le routage par nom comportent donc, entre autres :
/IETF/IRTF/ICN/Research challenges
pour ce
RFC) afin de permettre l'agrégation, comment permettre aux
utilisateurs d'utiliser des noms plus simples ? (Se servir d'un
moteur de recherche serait de la triche,
puisqu'on voulait se dispenser de l'étape de résolution.)La catégorie « recherche par nom » regroupe les mécanismes de routage qui, eux, ont une étape de résolution explicite. On résout le nom (qui est pratique pour un humain, et stable) en un localisateur (qui est pratique pour le réseau et qui pourrait être une simple adresse IP). C'est par exemple ainsi que fonctionne le système « MDHT: A hierarchical name resolution service for information-centric networks ». Les défis techniques à relever sont l'accès rapide au localisateur (en se rappelant que le contenu peut être à plusieurs endroits) et la mise à jour efficace (car le contenu peut changer de localisation, c'est même un des buts de l'ICN). Notez que les gens de l'ICN aiment bien réinventer la roue et que le DNS n'est même pas mentionné.
Enfin, il y a les solutions de la catégorie hybride. Par exemple, on fait du routage par le nom en local mais on résout le nom en un localisateur dès qu'on sort de ce domaine local.
Vous aimez les défis techniques et la liste n'est pas encore assez longue pour vous ? Il reste plusieurs problèmes à affronter. Par exemple, le contrôle de congestion. Il n'a pas à être de bout en bout puisque, dans l'ICN, la communication peut se faire via des éléments intermédiaires (voir par exemple « ConTug: A Receiver-Driven Transport Protocol for Content-Centric Networks »).
On a vu qu'un des intérêts principaux de l'ICN était de permettre la mise en cache automatique par des éléments du réseau, et l'accès au contenu à partir de ces caches. La bonne utilisation de ceux-ci soulève plusieurs questions :
ni:
du RFC 6920) ne résout pas le problème : il faut maintenant un
mécanisme pour informer les clients du nouveau nom.Les administrateurs réseau sont habitués à des outils comme ping et traceroute pour tester et déboguer leur réseau. Comment feront-ils avec l'ICN ? C'est un autre défi. Étant donné que ping et traceroute ne sont apparus que de nombreuses années après IP, on peut prévoir que, pendant un certain temps, les administrateurs des réseaux ICN souffriront du manque d'outils adaptés.
Quelles applications utiliseront l'ICN, si tous ces défis sont relevés, et avec succès ? Le RFC se termine par une liste d'applications potentielles (cf. RFC 7476) :
GET
). Les noms des NDO
remmplaceront-ils les URI ? Il n'est pas
évident que tous les usages du Web (POST
,
PUT
, et autres méthodes utilisées par les
applications REST) s'adaptent aussi bien
à l'ICN.Une conclusion personnelle ? Il y a plein d'idées intéressantes dans l'ICN, et c'est donc un sujet de recherche utile, malgré la prémisse de départ (« tout est accès au contenu ») qui est fausse.
Date de publication du RFC : Juillet 2016
Auteur(s) du RFC : H. Tschofenig (ARM), T. Fossati
(Nokia)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dice
Première rédaction de cet article le 20 juillet 2016
Dans le futur, nous répètent les consultants, il y aura partout dans nos maisons, bureaux et usines, des petits objets électroniques connectés à l'Internet. C'est le fameux Internet des Objets. Ces choses serviront à mesurer le monde et à le modifier et poseront donc des problèmes de sécurité. Par exemple, sans précautions particulières, un capteur dans une usine qui envoie en Wi-Fi les informations qu'il récolte permettrait à un écoutant indiscret, même situé en dehors de l'usine, de surveiller l'activité de celle-ci. Il va donc de soi qu'il faut utiliser de la cryptographie dans ces objets. Mais celle-ci est parfois coûteuse en ressources machine, et ce nouveau RFC propose donc des profils du protocole TLS, limitant les options possibles de façon à économiser les ressources des objets.
Ces objets sont en effet contraints au sens du RFC 7228. Un TLS complet serait trop pour eux. Bien sûr, on pourrait concevoir des protocoles cryptographiques spécialement conçus à leur intention mais il faudrait développer, valider et déboguer ces protocoles et l'expérience de la cryptographie sur l'Internet montre que c'est beaucoup plus difficile que ça n'en a l'air. D'où le choix d'utiliser TLS (RFC 5246), protocole connu et éprouvé.
Notons au passage que, contrairement à ce que dit le RFC, le principal danger que pose l'Internet des Objets ne vient pas forcément d'un tiers inconnu : presque toute la domotique actuelle fonctionne avec le cloud, toutes les données récoltées étant envoyées sur les serveurs du vendeur, qui peut en faire ce qu'il veut. Chiffrer le trafic entre l'objet et ces serveurs ne comble pas cette énorme faille de sécurité.
Les profils de TLS (et de DTLS, son équivalent pour UDP, cf. RFC 6347) spécifiés dans ce RFC peuvent s'appliquer aux communications utilisant CoAP (RFC 7252) comme à celles utilisant d'autres protocoles applicatifs. Ce sont des profils, des restrictions de TLS, et ils n'introduisent donc pas un nouveau protocole, ni même de nouvelles extensions à ces protocoles.
Par exemple (section 4.4), ce RFC impose que, si on authentifie avec un certificat, les certificats X.509 utilisent ECDSA uniquement. (Gérer tous les algorithmes possibles dans un objet contraint serait trop coûteux, par exemple en occupation de la flash.) Au revoir, RSA, donc.
Toujours sur les certificats, le profil abandonne OCSP (RFC 6960) et les CRL (qui ne marchent guère, en pratique) : la révocation des certificats devra se faire uniquement par le biais d'une mise à jour du logiciel de l'objet.
Toujours concernant la cryptographie, ce RFC impose (section
13) de n'utiliser que des suites de chiffrement intègres
(AEAD) comme
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
(AES
avec CCM,
cf. RFC 7251).
Comme l'utilisation de TLS dans ces objets contraints est récente, il n'y a pas trop à se préoccuper de la base installée. On peut donc décider de ne jamais gérer des trucs trop anciens. C'est ainsi que la version minimale de TLS acceptée dans les profils de ce RFC est la 1.2 (section 18).
Il y a quelques points où ce RFC rend obligatoire des fonctions qui étaient optionnelles dans TLS, parce qu'elles sont cruciales pour des objets contraints. C'est le cas de la reprise de session TLS précédente, qui permet d'éviter de refaire des opérations cryptographiques coûteuses à chaque démarrage. Par contre, certaines fonctions sont déconseillées, comme la compression, coûteuse et sans doute inutile dans l'Internet des Objets où les protocoles sont déjà optimisés pour réduire la taille des données échangées. (En outre, il existe de bonnes raisons de sécurité de couper la compression TLS, RFC 7525, section 3.3.) Idem pour la renégotiation du RFC 5746, qui est exclue.
Un problème courant en cryptographie est celui de la génération de nombres aléatoires (TLS en utilise plusieurs). Il est encore plus aigu dans l'Internet des Objets car ces objets n'ont souvent pas beaucoup de sources d'entropie (section 12 du RFC). Pas de disque dur mobile, pas de clavier, pas de souris dont les mouvements sont partiellement aléatoires. Il y a donc un risque élevé que tous les objets identiques génèrent les mêmes nombres « aléatoires ». Bref, il faut que les développeurs fassent très attention aux conseils du RFC 4086.
Autre manque des objets contraints, celui d'une horloge fiable. Pour des opérations comme la validation de la non-expiration d'un certificat, cela peut être très gênant.
Les objets contraints sont... contraints de bien d'autre façon, comme en puissance du processeur. Cela peut rendre certaines opérations cryptographiques irréalistes en logiciel. La section 19 du RFC donne des conseils sur la mise en œuvre matérielle de ces opérations :
Toujours en cryptographie, la section 20 donne des recommendations sur la longueur des clés. Un point important, et spécifique aux objets, est que les engins déployés restent souvent sur le terrain très longtemps, par exemple dix ans. On ne remplace pas les capteurs, ou l'ordinateur embarqué dans une machine, comme on change d'iPhone ! La longueur des clés doit donc être prévue pour les attaques du futur, pas pour celles d'aujourd'hui.
Les objets dont on parle dans ce RFC sont souvent déployés dans des environnements où les contraintes de vie privée sont fortes. Cela peut être une usine qui ne veut pas que ses processus soient espionnés, ou bien une maison dont les habitants ne veulent pas être surveillés (section 22 du RFC). TLS ne protège pas contre tout et certaines fuites d'information persistent même quand il est utilisé. Elles peuvent venir du protocole TLS lui-même (la reprise de session utilise des informations qui permettent de suivre une machine à la trace) ou bien provenir de métadonnées diverses. Par exemple, s'il existe un capteur de présence qui envoie un message lorsque quelqu'un rentre dans l'appartement, chiffrer ce message ne fait pas gagner grand'chose : une fois qu'un observateur a identifié le capteur de présence, le seul envoi du message suffit à l'informer d'une arrivée. Une vraie protection de la vie privée peut donc nécessiter des méthodes additionnelles comme l'envoi de trafic bidon.
Le RFC se termine en rappelant qu'il est crucial de fournir un mécanisme de mise à jour simple des engins. Les objets de l'Internet des Objets sont souvent de type « je pose et puis j'oublie », sans aucun moyen de mettre à jour leur logiciel. Or, la sécurité peut nécessiter une telle mise à jour, soit pour corriger une bogue dans la bibliothèque TLS, soit pour révoquer des clés et en mettre d'autres. Un exemple d'un mécanisme de mise à jour adapté est LWM2M.
Si vous voulez rire un peu, l'annexe A du RFC précise comment faire tourner DTLS sur... SMS.
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : A. Atlas (Juniper), T. Nadeau
(Brocade), D. Ward (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF i2rs
Première rédaction de cet article le 21 juillet 2016
Autrefois, la configuration des routeurs était relativement statique. On indiquait la politique de routage (le coût de tel ou tel lien, par exemple), les préfixes IP, les pairs BGP, parfois des routes statiques, et le routeur parlait avec ses copains routeurs, construisant ses tables qu'il allait ensuite utiliser pour la transmission des paquets. La configuration n'était pas modifiée tous les jours et quand c'était nécessaire, on se connectait à tous les routeurs qu'il fallait changer et on modifiait la config. Dans les organisations plus modernes, on édite la config, on la commite dans un VCS et on la pushe vers les routeurs avec Ansible ou un truc équivalent. Aujourd'hui, même cela ne suffit pas, on voudrait être plus agile. On voudrait modifier la configuration des routeurs à peu près en temps réel, pour répondre à des considérations de business (créer un nouveau service pour un client, profiter de variations de prix chez les transitaires...) ou à des problèmes de sécurité (déployer des filtres subtils). Cette exigence nécessite une interface vers le routeur, utilisable par des programmes. C'est le projet I2RS, Interface To the Routing System. Ce premier RFC du groupe de travail décrit précisement le problème qu'on essaie de résoudre. (Notez que le buzzword SDN n'apparait pas une seule fois dans ce RFC...)
C'est que les réseaux modernes sont grands et complexes : il n'est plus possible de faire les choses à la main en se connectant sur chaque routeur isolément. Il faut donc automatiser, et il faut donc qu'un programme puisse se connecter aux routeurs et changer leurs configurations. Cela se fait bien sûr depuis longtemps (cf. Rancid et l'exposé de Joe Abley à NANOG et l'annexe A de notre RFC qui liste les solutions existantes), mais, en l'absence d'interface normalisée, c'était assez pénible à programmer et maintenir. Il s'agit donc de standardiser ce qui existe déjà, ce qui ne devrait pas être une tâche insurmontable.
La terminologie utilisée par I2RS est décrite dans un autre RFC, le RFC 7921. Pour le résumer (section 2 du RFC) : le routeur contient un agent I2RS, qui sait parler aux différents composants du routeur (sa base de données indiquant les différents liens connectés, son système de gestion de la configuration, sa base de routes - RIB, etc). Le logiciel qui pilote les changements est le client I2RS. Il y aura sans doute un seul client pour beaucoup d'agents, installé dans le système de gestion du réseau. Entre le client et l'agent, le protocole I2RS, qui sera normalisé dans les futurs RFC du groupe de travail I2RS. A priori, le client sera juste un intermédiaire pour des applications qui piloteront le routage (le but du découplage client/application étant d'éviter que chaque application doive parler I2RS : elles pourront interagir avec le client au-dessus d'un protocole plus classique comme REST).
Pour que le client puisse parler intelligemment à l'agent, il devra avoir en tête un modèle de données décrivant le routeur, ce qu'il sait faire, ce qu'on peut lui demander.
La section 3 de notre RFC présente la nécessité de ce modèle de données. Un tel modèle avait déjà été développé pour le projet ForCES (RFC 3746), en se focalisant sur la transmission, alors que I2RS est surtout intéressé par le routage (le plan de contrôle, accès à la RIB, etc).
Comme le note la section 4, un logiciel qui voudrait vraiment donner des instructions au routeur devrait apprendre la topologie du réseau, quels sont les liens physiques ou virtuels auxquels le routeur est connecté, leur état, etc. C'est évidemment le routeur qui connait le mieux cette information et il est donc nécessaire de lui demander.
L'application aura souvent besoin de connaitre en outre le trafic réellement échangé. IPFIX (RFC 5470) est certainement utilisable pour cela, si l'application peut le configurer dynamiquement.
Enfin, la section 5 rassemble les « points divers ». Elle rappelle qu'I2RS n'impose pas forcément le développement d'un nouveau protocole ; si un protocole, ou un ensemble de protocoles existant(s) suffit, c'est parfait (l'annexe A du RFC propose des pistes en ce sens). Mais la solution doit penser à :
Voici pour le cahier des charges. L'annexe A propose quelques pistes qui vont en ce sens. À l'heure actuelle, l'interface la plus générale des routeurs est la CLI. Elle permet d'apprendre l'état du routeur et de changer sa configuration. Voici un exemple sur un Juniper :
bortzmeyer@MX-1> show interfaces ... Physical interface: ge-1/1/9, Enabled, Physical link is Up Interface index: 177, SNMP ifIndex: 531 Description: To infinity and beyond Link-level type: Ethernet, MTU: 1514, MRU: 1522, Speed: 1000mbps, BPDU Error: None, MAC-REWRITE Error: None, Loopback: Disabled, Source filtering: Disabled, Flow control: Enabled, Auto-negotiation: Enabled, Remote fault: Online Pad to minimum frame size: Disabled Device flags : Present Running Interface flags: SNMP-Traps Internal: 0x0 Link flags : None CoS queues : 8 supported, 8 maximum usable queues Current address: 5c:5e:ab:0e:4b:f1, Hardware address: 5c:5e:ab:0e:4b:f1 Last flapped : 2016-02-12 11:31:56 CET (22w5d 23:10 ago) Input rate : 672 bps (1 pps) Output rate : 672 bps (1 pps) Active alarms : None Active defects : None Interface transmit statistics: Disabled Physical interface: xe-0/0/2, Enabled, Physical link is Up Interface index: 156, SNMP ifIndex: 510 Link-level type: Ethernet, MTU: 1514, MRU: 1522, LAN-PHY mode, Speed: 10Gbps, BPDU Error: None, MAC-REWRITE Error: None, Loopback: None, Source filtering: Disabled, Flow control: Enabled Pad to minimum frame size: Disabled Device flags : Present Running Interface flags: SNMP-Traps Internal: 0x0 Link flags : None CoS queues : 8 supported, 8 maximum usable queues Current address: 5c:5e:ab:0e:4b:72, Hardware address: 5c:5e:ab:0e:4b:72 Last flapped : 2016-07-07 14:28:31 CEST (1w6d 21:11 ago) Input rate : 0 bps (0 pps) Output rate : 0 bps (0 pps) Active alarms : None Active defects : None PCS statistics Seconds Bit errors 0 Errored blocks 1 Interface transmit statistics: Disabled ...
Ce shell n'est pas normalisé : chaque marque de routeur a le sien. Comme l'information retournée n'est pas structurée, si on veut la traiter depuis un programme, il faut faire du scraping, ce qui est pénible et peu gratifiant (d'autant plus que le « format » peut changer sans prévenir lors de la sortie d'une nouvelle version du système d'exploitation du routeur).
Les routeurs ont aussi des interfaces reposant sur un protocole et des données structurées. La plus connue est SNMP. SNMP est très utilisé pour récupérer de l'information (état des interfaces, quantité de trafic qui passe) mais, bien qu'il permette en théorie la configuration des équipements réseau, en pratique, cette possibilité a été très peu utilisée. Les raisons de cette non-utilisation sont nombreuses (complexité, absence de sémantiques avancées comme le regroupement de plusieurs changements dans une « transaction » unique, sur laquelle on peut revenir globalement, etc). SNMP ne semble donc pas envisageable pour I2RS.
Enfin, cette annexe A cite Netconf comme étant sans doute la solution disponible la plus proche, même si elle n'est pas parfaite et aurait besoin d'être complétée (voir les travaux en cours dans le RFC 7921).
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : C. Bao, X. Li (CERNET
Center/Tsinghua University), F. Baker (Cisco
Systems), T. Anderson (Redpill
Linpro), F. Gont (Huawei
Technologies)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 22 juillet 2016
Parmi les nombreuses techniques de coexistence d'IPv4 et IPv6, l'ex-groupe de travail Behave développait un mécanisme de traduction permettant à une machine IPv6 de communiquer avec une machine v4 et réciproquement. Une des pièces de ce mécanisme (désormé transféré au groupe de travail v6ops) est l'algorithme de traduction, présenté dans ce RFC 7915. (Il remplace l'ancien RFC 6145, avec assez peu de changements.)
Ce nouveau mécanisme de traduction entre IPv4 et IPv6 s'inscrit dans le cadre décrit dans le RFC 6144. Il vise à remplacer « NAT-PT » (RFC 2765 et RFC 2766), officiellement retiré, après n'avoir eu aucun succès.
Plus spécifiquement, notre RFC 7915 est la version sans état du traducteur, c'est-à-dire que le traducteur peut traiter chaque paquet indépendamment des autres. Le traducteur n'a pas de table des flots en cours. S'il redémarre et perd toute mémoire, pas de problème, il peut immédiatement reprendre son travail. Cette technique permet notamment le passage à l'échelle : un traducteur d'adresses peut gérer un très grand nombre de clients sans épuiser sa mémoire. Et on peut mettre plusieurs traducteurs en parallèle, sans coordination entre eux : les paquets d'un même flot peuvent passer par des traducteurs différents. Mais cette technique a aussi quelques inconvénients comme le fait que les fragments ICMP ne seront pas traduits. Il existe donc également une version avec état du nouveau mécanisme, normalisée dans le RFC 6146. La section 1.3 discute plus en détail ces deux possibilités, avec ou sans état.
Donc, le NAT64 (son nom non officiel) vise à traduire des adresses IP entre deux réseaux, l'un v4 et l'autre v6. Comme notre RFC 7915 ne traite que le cas sans état, les adresses doivent être converties de manière purement algorithmique, sans référence à leur histoire (cf. RFC 6052, et la section 6 de ce RFC, pour ces algorithmes).
Dit comme ça, cela a l'air simple mais la traduction entre deux protocoles différents porte pas mal de pièges. Ainsi, les en-têtes de paquet n'ont pas la même taille en v4 (20 octets ou plus) et en v6 (40 octets, fixe), ce qui fait que des problèmes de MTU peuvent se poser (section 1.4). Le traducteur doit se comporter comme un routeur, donc fragmenter les paquets trop gros (en IPv4) ou retourner un message ICMP « Packet too big ».
La section 4 du RFC décrit en détail les opérations que doit faire le traducteur depuis IPv4 vers IPv6 (rappelez-vous que la traduction des adresses v4 en v6 est essentiellement dans le RFC 6052, section 2). Il y a des détails que ne connaissent pas les routeurs NAT44, qui se contentent de changer adresses et ports. En effet, ici, il faut traduire tout l'en-tête. Je ne vais pas résumer complètement cette section, juste pointer quelques pièges possibles. Ainsi, les en-têtes n'étant pas les mêmes en v4 et en v6, notre RFC doit spécifier quoi en faire. Certains cas sont évidents (comme le champ Longueur), d'autres moins. Ainsi, le champ TOS de IPv4 doit être copié verbatim dans le champ Traffic Class de IPv6. Mais le traducteur doit aussi offrir une option pour ignorer le TOS et mettre systématiquement zéro comme Traffic Class. Le champ TTL de IPv4 doit être copié dans Hop limit mais après avoir été décrémenté (rappelez-vous que le traducteur est un routeur).
La vraie difficulté n'est pas tellement dans la traduction d'IP que dans celle d'ICMP. En effet, le paquet ICMP contient le début du paquet IP qui a motivé son envoi, et ce début de paquet doit être traduit, également, sans quoi le destinataire du paquet ICMP n'y comprendra rien (par exemple, sans traduction ICMP, il recevrait en IPv6 un paquet ICMP dont le contenu est un paquet IPv4...). Notre RFC détaille donc les traductions à faire pour tous les modèles de paquets ICMP.
Le traducteur doit aussi veiller au champ Type d'ICMP, dont les valeurs sont différentes entre IPv4 et IPv6 (par exemple, Echo Reply est 0 en v4 et 129 en v6). Certains types n'ont pas d'équivalent (comme les types Timestamp ou Address Mask d'ICMPv4, absents d'ICMPv6) et le paquet ICMP doit donc être abandonné.
Enfin, le traducteur doit aussi prendre en charge les en-têtes de la couche 4 car la traduction des adresses peut ne pas être neutre pour la somme de contrôle (section 4.5) et il peut donc être nécessaire de recalculer cette dernière.
Et en sens inverse ? La section 5 décrit la traduction d'IPv6 vers IPv4. On retrouve TOS et Traffic Class, les problèmes de MTU et de fragmentation, et la traduction des messages ICMP.
La section 6 de notre RFC, une nouveauté depuis le RFC 6145, revient sur les algorithmes de correspondance entre les adresses IPv4 et IPv6. Les algorithmes obligatoires sont décrits dans le RFC 6052, mais un traducteur peut en ajouter d'autres.
Les problèmes de MTU et de fragmentation sont des cauchemars habituels sur l'Internet, notamment en raison d'équipements intermédiaires (typiquement des pare-feux) programmés avec les pieds par des anonymes, ou bien configurés n'importe comment, et qui bloquent les paquets ICMP, voire les modifient, en ignorant complètement le RFC 4890. Les traducteurs v4<->v6 auront donc ce problème, comme tant d'autres techniques utiles. La section 7 doit donc se pencher sur le traitement des paquets ICMP Packet too big qui signalent normalement que la MTU est plus réduite que ne le croit l'émetteur et qu'il faut fragmenter. Comme ces paquets sont parfois interceptés, voire modifiés, par des machines gérées par des incompétents, le traducteur doit donc parfois faire des efforts spécifiques. Si les paquets sont interceptés, la détection de la MTU du chemin n'est plus possible (RFC 2923) et il ne restera plus que la solution du RFC 4821 (faire faire le travail par les couches supérieures).
Rien n'étant parfait en ce bas monde, les traducteurs NAT64 vont aussi introduire de nouvelles questions de sécurité. La section 8 tente de prévoir lesquelles mais reste optimiste en considérant que la plupart des problèmes existent déjà dans IPv4 ou dans IPv6. Ainsi, comme avec le NAT traditionnel, l'authentification des paquets par IPsec (RFC 4302) ne marchera pas.
Pour les gens qui aiment bien les exposés concrets, avec des 0 et
des 1, l'annexe A explique en grand détail le
processus de traduction avec un réseau simple d'exemple, connectant le
réseau traditionnel 198.51.100.0/24
et le réseau
nouveau 2001:db8::/32
, via un
traducteur. Deux machines, H4 et H6, Alice et Bob du NAT64, vont tenter de communiquer. Le traducteur
utilise le préfixe 2001:db8:100::/40
pour
représenter les adresses IPv4 et 192.0.2.0/24
pour représenter les adresses IPv6. Ainsi,
H6, qui a l'adresse 2001:db8:1c0:2:21::
est
représenté en v4 par 192.0.2.33
. H4 a l'adresse
198.51.100.2
. Une fois le routage
correctement configuré pour passer par le traducteur, suivez le RFC
pour voir le trajet des paquets et les opérations qu'ils subissent,
dans le cas où c'est H6 qui initie la connexion, et dans le cas inverse.
Au moins deux mises en œuvre existent déjà, faite par Ecdysis/Viagénie (avec état) et Tayga (sans état, mais nettement plus simple, d'après ses utilisateurs). Pour compenser l'absence de traduction avec état chez Tayga, on peut, sur Linux, le coupler avec SNAT/MASQUERADE (merci à Guillaume Leclanché pour sa suggestion).
Quels sont les changements entre ce mécanisme et celui du RFC 6145 ? Rien de dramatique. Ils sont résumés en section 2. Certains traitent les bogues détectées dans l'ancien RFC. D'autres changements tiennent compte du conseil actuel qui est de ne plus compter sur les « fragments atomiques » du RFC 6946 (ils ont même été franchement abandonnés avec le RFC 8021.)
Pour réfléchir à la grande question « avec état ou sans état », un article « pro-état » : « Stateless NAT64 is useless ».
Date de publication du RFC : Août 2016
Auteur(s) du RFC : C. Percival (Tarsnap), S. Josefsson
(SJD AB)
Pour information
Première rédaction de cet article le 29 août 2016
Ce RFC normalise la fonction de dérivation de clé scrypt.
À quoi ça sert, une fonction de dérivation de clé ? Comme leur nom l'indique, elles permettent d'obtenir des clés cryptographiques (ou autre matériel cryptographique) à partir des données qu'on leur fournit. Une utilisation courante est de fabriquer une clé pour un algorithme de chiffrement, à partir d'une phrase de passe. Cela permet d'obtenir une clé (longueur fixe, format donné) pour les opérations cryptographiques tout en laissant l'utilisateur manipuler uniquement des textes mémorisables. Par exemple, pour chiffrer un disque dur, l'utilisateur va indiquer une phrase de passe, mais le disque sera chiffré à partir de la clé obtenue en appliquant la fonction de dérivation de clé (KDF, pour Key Derivation Function) à cette phrase. Une autre utilisation est pour transformer un mot de passe qu'on doit stocker dans un fichier en une information inutilisable pour un attaquant qui mettrait la main dessus. Pour se connecter, on tape le mot de passe, on refait tourner la KDF et on vérifie qu'on obtient bien le résultat stocké.
Problème de cette méthode, l'ennemi peut tenter de faire lui-même la dérivation : il essaie des tas de mots de passe et regarde s'il obtient le résultat stocké. C'est pour cela qu'une des qualités d'une bonne fonction de dérivation est, paradoxalement, d'être lente : les gens qui connaissent le mot de passe ne seront pas gênés (ils ne font qu'un seul essai) alors que l'attaquant par force brute qui essaie des milliards de mots sera ralenti. Idéalement, on voudrait une fonction qui ne puisse pas facilement être mise en œuvre dans des ASIC, pour qu'un attaquant riche ne puisse pas investir dans une « machine à deviner les mots de passe ». C'est l'un des avantages de scrypt. (Les fanas de chaîne de blocs noteront que des chaînes comme Litecoin utilisent scrypt justement pour cette raison : rendre le minage plus accessible à tous en contrariant les ASIC.)
Pourquoi encore ajouter des fonctions de dérivation de clés (section 1 du RFC) ? Il y en a eu plein dans l'histoire, de la vénérable crypt à PBKDF2 (RFC 2898) puis aux récents bcrypt et Argon2. On en imagine souvent de nouvelles, par exemple celle-ci qui n'utilise pas du tout de chiffrement, juste de la condensation. Pour résister aux attaques par force brute (que la loi de Moore rend plus efficace chaque année), certaines ont un nombre d'itérations variables. On applique plusieurs fois l'opération de dérivation, si les machines deviennent plus rapides, on augmente ce nombre d'itérations. Cela ne marche bien que si l'attaquant utilise les mêmes logiciels que les utilisateurs normaux. Mais si la fonction de dérivation est facilement programmable dans des circuits matériels spécialisés, l'attaquant pas trop pauvre pourra s'acheter une ferme de cassage de mots de passe, remplie de circuits conçus spécifiquement, et travaillant en parallèle (les circuits deviennent plus rapides mais aussi plus petits : on peut en entasser davantage). Il ne joue alors plus dans la même catégorie que les utilisateurs légitimes.
C'est là que scrypt intervient : l'algorithme a été délibérement conçu pour être difficile à mettre dans un ASIC. scrypt a été publié en 2009 (voir l'article original qui fut présenté à USENIX). Ce RFC a commencé en 2013 et a eu une longue gestation. Il ne décrit pas scrypt, renvoyant au papier original, mais se contente de préciser les points qui sont nécessaires pour des mises en œuvre interopérables.
La section 2 du RFC décrit les paramètres de la fonction. Le plus évident est la phrase de passe, souvent choisie par un humain. Il y a aussi un sel, en général choisi aléatoirement (RFC 4086), et divers paramètres techniques, permettant notamment d'ajuster l'algorithme aux caractéristiques des machines dont on dispose. Une taille de bloc de 8 et un facteur de parallélisation de 1 conviennent bien à l'heure actuelle, mais vont sans doute augmenter dans le futur.
scrypt dépend de la fonction de condensation Salsa20 Core, plus exactement de sa version simplifiée Salsa20/8 Core (section 3 du RFC). Une mise en œuvre en C est incluse dans le RFC. (Voir la description originelle et la spécification de Salsa20.)
scrypt est un « chef d'orchestre », qui dépend de plusieurs autres algorithmes comme BlockMix (section 4), ROMix (section 5), le PBKDF2 du RFC 2898 et le HMAC-SHA-256 du RFC 6234. L'algorithme de scrypt, qui fait fonctionner ensemble tout cela, figure en section 6.
Si vous êtes programmeur et que vous mettez en œuvre scrypt,
les sections 8 à 13 du RFC contiennent des vecteurs
de test pour les différents algorithmes
utilisés. Par exemple, avec la phrase de passe
pleaseletmein, le sel
SodiumChloride
(exemple contestable, ce sel
n'a pas été généré aléatoirement), le facteur CPU/mémoire à
16384, la taille de bloc 8 et le facteur de parallélisation 1,
la clé dérivée par scrypt sera 70 23 bd cb 3a fd 73 48
46 1c 06 cd 81 fd 38 eb fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54
5d a1 f2 d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9 e6 1e
85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87
. Si vous
trouvez une autre valeur, vérifiez votre programme.
Lisez aussi la section 14, consacrée aux questions de sécurité. Par exemple, scrypt peut consommer beaucoup de mémoire (c'est fait exprès, cela fait partie des techniques qui rendent difficile sa mise en œuvre en ASIC) et il y a donc un risque de déni de service si on accepte d'exécuter scrypt avec des paramètres quelconques, fournis depuis l'extérieur.
scrypt est, entre autres, présents dans OpenSSL depuis le 1.1.0, officiellement publiée juste après le RFC.
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : K. Sriram, D. Montgomery (US NIST), D. McPherson, E. Osterweil (Verisign), B. Dickson
Pour information
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 8 juillet 2016
Il est bien connu que le protocole de routage BGP connait fréquemment des « fuites de route » (route leaks). Les forums où les opérateurs discutent sont plein de discussions et d'alertes sur la dernière fuite en cours, il existe un compte Twitter dédié pour les alertes automatiques de fuites, le rapport sur la résilience de l'Internet en France en parle longuement. Bref, le sujet est bien connu. Curieusement, il n'y a pas de définition simple et consensuelle de ce qu'est une fuite. Il en existe en fait plusieurs sortes, et ce nouveau RFC tente de faire le point et de définir rigoureusement les différents types de fuite.
La fuite est en effet un sérieux problème : des routeurs vont recevoir des routes incorrectes et, s'ils les acceptent, le routage normal peut être perturbé, menant à des pannes, ou à du tromboning (paquets IP routés par un chemin bien plus long que l'optimum).
La liste des incidents de routage médiatiquement connus est longue : le détournement de YouTube par Pakistan Telecom, la fuite venue de Malaisie, et bien d'autres décrites dans l'abondante bibliographie de notre RFC (cf. section 1 du RFC). L'IETF travaille depuis longtemps à des solutions techniques à ce problème (notamment via son groupe de travail SIDR) mais, pour résoudre un problème, il vaut mieux bien le comprendre. C'est le travail de ce nouveau RFC, qui tente une taxonomie des fuites.
Donc, d'abord, une (tentative de) définition (section 2 du RFC). Une fuite est la propagation de l'annonce d'une route au-delà de la portée prévue. Ce n'est donc pas la seule annonce qui est le problème, c'est sa propagation. Si le Pakistan veut annoncer les routes de YouTube dans le pays, à des fins de censure, ce n'est pas une fuite de route, mais un détournement délibéré (comme celui de Google Public DNS en Turquie). La fuite a commencé quand Pakistan Telecom a bêtement laissé se propager cette annonce au monde entier.
La définition s'appuie donc sur une politique de routage qui définit « ce qui est prévu ». La politique de routage est décidée par chaque acteur (l'Internet n'a pas de Chef, chacun est maître de sa politique) et mise en œuvre dans la configuration des routeurs, sous forme de règles disant ce qui est accepté et ce qui est refusé. Si les opérateurs ne commettaient jamais d'erreurs, on pourrait dire que ces règles suffiraient à décrire la politique de routage. Mais ils en commettent (par exemple, le transitaire de Pakistan Telecom aurait dû n'accepter de son client qu'un ensemble fini de routes, celles correspondant aux préfixes alloués à Pakistan Telecom et à ses clients). Une fuite de route est donc l'équivalent pour les opérateurs réseau de ce qu'est une bogue pour les programmeurs : « ce n'est pas ce que je voulais, mais c'est ce que j'ai dit ».
La définition de la politique de routage dépend des relations entre acteurs (on n'accepte pas la même chose d'un client, d'un transitaire, d'un pair...) Le RFC cite (section 2) plusieurs études expliquant ces relations compliquées.
Au fait, on a supposé que les « fuites de routes » étaient mauvaises et qu'il fallait les combattre. Mais pourquoi ? Parce qu'elles peuvent mener à des pannes (la route annoncée à tort ne fonctionne pas) ou à des chemins sous-optimaux (un long détour). Cela concerne les fuites accidentelles, de loin les plus nombreuses (il y a davantage de maladroits que de malveillants). Mais il y a aussi des fuites délibérées, provoquées pour faire une attaque par déni de service, ou bien pour forcer le trafic à passer en un point où il pourra être plus facilement surveillé.
C'est pour cela que les gens qui ne chiffrent pas leurs communications avec des arguments du genre « non, mais ça ne sort pas du pays, de toute façon », ont gravement tort. La vulnérabilité du routage fait que leur trafic peut soudainement partir bien plus loin.
Voyons maintenant la classification des fuites (section 3). Le RFC les classe en différents types, identifiés par un numéro. Le type 1 est « virage en épingle à cheveux avec un préfixe complet ». C'est ce qui se produit quand un AS de bordure apprend un préfixe d'un de ses transitaires et le ré-annonce à un autre transitaire (d'où l'épingle à cheveux). Le second transitaire, s'il ne filtre pas les préfixes que peut annoncer son client, risque fort d'accepter la route (préférence donnée aux routes des clients sur celles des fournisseurs) et le trafic sera donc envoyé à l'AS de bordure (qui pourra ou pas le gérer). Ce fut le cas de l'incident Dodo, ainsi que de la fuite en Malaisie citée plus haut.
Le type 2, lui, est « fuite latérale ». Un acteur reçoit une route d'un pair et la transmet à un autre pair. (Voir la conférence de Jared Mauch à NANOG, où il observe qu'il n'est pas facile de détecter automatiquement ces fuites, car les relations entre acteurs peuvent être compliquées.)
L'incident de type 3, lui, se produit lorsque un AS apprend d'un transitaire des routes qu'il annonce à son pair (normalement, on n'annonce à un pair que ses routes à soi). L'exposé de Mauch en cite également des exemples.
Le type 4 est l'inverse : un pair laisse fuir les préfixes d'un pair vers un transitaire. Ce fut le cas de l'incident Moratel contre Google, ou d'un problème frappant Amazon.
Le type 5 se nomme « ré-origination ». L'AS maladroit annonce les routes comme si elles venaient de lui, et c'est son numéro d'AS qui apparait comme origine (le début du chemin d'AS). Ce fut le cas lors de grande fuite chinoise de 2010, ou pendant le curieux détournement islando-biélorusse (un des rares cas où le shunt semblait volontaire).
Le type 6 est la « fuite de préfixes plus spécifiques ». Un AS typique annonce dans son IGP des préfixes bien plus spécifiques que ce qu'il annonce publiquement, afin de contrôler plus finement le routage interne. Une erreur (redistribution de l'IGP dans l'EGP...) et paf, les préfixes spécifiques fuient. Étant plus spécifiques que le préfixe « normal », ils seront préférés lors de la transmission des paquets. Le cas le plus spectaculaire fut celui de l'AS 701.
Le RFC ne discute pas des solutions possibles, ce n'est pas son but. Les curieux pourront regarder du côté des systèmes d'alerte ou de RPKI/ROA.
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : A. Langley (Google), W. Chang
(Google), N. Mavrogiannopoulos (Red
Hat), J. Strombergson (Secworks
Sweden), S. Josefsson (SJD)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 8 juillet 2016
Ce court RFC ajoute les algorithmes de cryptographie ChaCha20 et Poly1305 à la liste de ceux utilisables dans le protocole TLS.
ChaCha20 (dérivé de l'ancien Salsa20) est un algorithme de chiffrement symétrique et Poly1305 un authentificateur. Tous les deux ont été conçus par Dan Bernstein et sont décrits dans le RFC 8439. (Ce nouveau RFC ne fait que de les adapter à leur usage dans le cas spécifique de TLS.) ChaCha a été utilisé dans BLAKE, la version de ce RFC, ChaCha20 doit son nom au fait qu'il exécute 20 tours (rounds). Quant à Poly1305, c'est un authentificateur de Wegman-Carter. Que fait un authentificateur ? Il prend une clé, un message et fabrique une étiquette. Un attaquant n'a qu'une probabilité infime de produire une étiquette valide.
Les deux algorithmes ont été conçus en pensant surtout à une mise en œuvre en logiciel (AES restant sans doute plus rapide quand on peut utiliser du matériel spécialisé. On trouve des mesures de performance dans cet article de Google ou cet article de Cloudflare.)
Les algorithmes potentiellement concurrents ont des faiblesses : risques de sécurité pour AES-CBC ou RC4 (cf. RFC 7465), problèmes de performance pour les autres algorithmes AEAD comme AES-GCM. Comme RC4, ChaCha20 est un algorithme à flot continu, mais il n'a pas ses failles de sécurité.
Pour le cas de TLS (section 2 du RFC), ChaCha20 et Poly1305
sont utilisés ensemble, pour former un algorithme
AEAD (RFC 5116). Son identifiant TLS
est AEAD_CHACHA20_POLY1305
et il peut
s'utiliser avec les différents algorithmes d'authentification
utilisés dans TLS. Par exemple, on peut avoir une session TLS dont
la cipher suite est
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
ce qui veut dire :
Ces identifiants ont été ajoutés dans le registre IANA pour TLS.
Quel est le niveau de sécurité du nouvel algorithme ? Son prédécesseur Salsa20 a bénéficié d'analyses de sécurité sérieuses (Salsa20 security et The eSTREAM Portfolio). ChaCha20 traite les failles connues de Salsa. Et il était utilisé dans un des finalistes du concours SHA-3, ce qui lui a valu d'autres examens de près.
Si, en plus de ChaCha20 et Poly1305, on utilise Curve25519 pour la cryptographie asymétrique, on aura une cryptographie tout-Bernstein, ce qui peut aussi amener à se poser des questions.
Et les mises en œuvre ? ChaCha20 est dans OpenSSL depuis la version 1.1.0 (pas encore officiellement publiée, et qui semble encore peu répandue) et dans GnuTLS depuis la 3.4.0. Il existe une liste apparemment à jour des mises en œuvre.
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : P. Wouters (Red Hat)
Expérimental
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 24 juin 2016
Lorsqu'un client DNS parle à un résolveur, il pose une question et obtient une réponse. Avant DNSSEC, ce mode de fonctionnement simple était souvent satisfaisant. Mais, avec DNSSEC, il est beaucoup plus fréquent de devoir faire plusieurs requêtes pour obtenir toute l'information nécessaire pour valider les réponses. (Il faut les clés de toutes les zones situées entre la racine et la zone visée.) Cela coûtait cher en latence. Cette extension EDNS expérimentale permet au client DNS de demander au résolveur de chercher et de renvoyer toutes les réponses d'un coup.
Cette extension est particulièrement utile pour le cas de
machines terminales hébergeant leur propre résolveur validant (ce
qui est la meilleure configuration, question confiance et
sécurité). Ce n'est donc pas un hasard si l'auteur du
RFC travaille chez
Red Hat, système qui est livré par défaut avec
une telle configuration. Mais, lorsqu'un tel résolveur validant veut
vérifier les informations obtenues sur
foo.bar.example
, il devra (en supposant qu'il y
a une zone par composant du nom de domaine)
obtenir la délégation sécurisée de example
(dig @la-racine DS example
), la clé de
example
(dig @ns-example DNSKEY
example
), la délégation sécurisée de
bar.example
, etc (la clé de la racine,
elle, est en dur dans le résolveur, il faut bien partir de quelque part). À faire séquentiellement,
cela serait beaucoup de requêtes, donc du temps passé à attendre les
réponses. Sur des liens à latence élevée (ce qui arrive souvent aux
machines terminales), cela peut être pénible, même si le
cache DNS aidera, pour les requêtes suivantes.
L'idée de cette extension (sections 1 et 3 du RFC) est donc que le résolveur validant
local ait un forwarder (attention, le RFC utilise
un vocabulaire erroné, en donnant à forwarder un
sens différent de celui qu'il a dans les RFC 2308 et RFC 8499 ; j'utilise, moi, la terminologie standard). Le résolveur
validant local va demander à ce forwarder, grâce
à la nouvelle extension EDNS CHAIN
, d'envoyer tout
d'un coup (tous les DS et
DNSKEY nécessaires). Bien sûr, le
forwarder, lui, devra faire toutes les requêtes
mais, a priori, il a un plus gros cache et sera mieux connecté.
Cette nouvelle extension est donc conçue pour des résolveurs, et est ignorée par les serveurs faisant autorité. Notez que le résolveur validant local peut être un démon autonome (Unbound tournant sur mon portable Unix) ou bien une partie d'une application qui embarquerait ses propres fonctions de résolution de noms.
Le format de l'extension est décrit en section 4 du RFC. C'est
une option EDNS (RFC 6891), encodée, comme les autres options EDNS, en
TLV. Le type (le code) est 13. La valeur est composée d'un seul champ,
l'ancêtre le plus proche (Closest Trust Point)
dont on connaisse les informations nécessaires à la validation. Le
résolveur validant local a en effet certaines informations (dans sa
configuration ou dans son cache) qu'il n'est pas nécessaire de lui
envoyer. Dans l'exemple plus haut, si le résolveur validant local
connait déjà la clé DNSSEC de example
, il
mettra dans le champ Closest Trust Point ce nom
de domaine, indiquant au forwarder qu'il peut se
contenter des informations situées plus bas, dans l'arbre du
DNS. Ce nom est encodé dans le format habituel du DNS (qui n'est
pas le format texte avec les
points).
La section 5 du RFC décrit comment utiliser cette extension au
DNS. Si on veut tester les capacités du résolveur qu'on interroge,
on peut utiliser une option CHAIN
vide
(longueur nulle). Si le serveur à qui on a envoyé cette option
répond avec la même option nulle, c'est bon. Attention, les serveurs
récursifs qui mettent en œuvre CHAIN
n'accepteront des requêtes « réelles » (longueur non nulle) qu'au-dessus d'un transport où l'adresse IP source est vérifiée. Le but
est d'éviter les attaques par
réflexion avec amplification (voir aussi la section 7.2). Pour vérifier l'adresse IP
source (ce qui ne se fait normalement pas en
UDP), il y a plusieurs solutions, notamment
TCP (RFC 7766) et les
gâteaux (RFC 7873).
Une fois qu'on a un tel transport, et que le client DNS a testé
que le serveur qu'il interroge gère bien CHAIN
,
on peut y aller. Le client met l'ancêtre le plus proche (dont il a
les clés) du nom
demandé dans le champ Closest Trust Point. Dans
le cas le plus courant (résolveur validant configuré avec une seule
clé, celle de la racine), le résolveur « froid », qui vient de
démarrer et dont le cache est vide, il commencera par mettre la
racine en Closest Trust Point puis, au fur et à
mesure qu'il se « réchauffera » (que son cache se peuplera), il
pourra mettre des noms plus proches du nom demandé (et donc plus
éloignés de la racine). Par exemple, si le résolveur validant local
est configuré avec la clé de la racine, et qu'il a appris par les
réponses précédentes la clé de example
, mais
pas celle de bar.example
, et qu'il veut des
informations sur le nom foo.bar.example
, son
option CHAIN
vaudra {type = 13, longueur = 9,
valeur = 0x07 0x65 0x78 0x61 0x6d 0x70 0x6c 0x65 0x00} (la longueur
est celle de la partie « valeur » uniquement, le nom
example
est encodé selon la norme DNS). S'il
connaissait également la clé de bar.example
, son option
CHAIN
vaudrait {type = 13, longueur = 13,
valeur = 0x03 0x62 0x61 0x72 0x07 0x65 0x78 0x61 0x6d 0x70 0x6c 0x65
0x00}. D'autres exemples figurent en section 9 du RFC.
Faut-il envoyer l'option CHAIN
à chaque
requête ? On peut mais il est recommandé de se souvenir de quels
serveurs la gèrent et de n'envoyer qu'à ceux-ci (autrement, non
seulement on fait du travail inutile mais on renseigne des serveurs
extérieurs sur l'état de son cache). Comme il existe des
middleboxes boguées sur
certains trajets, la stratégie de repli du RFC 6891, section 6.2.2 peut être utile.
Et le serveur interrogé, que fait-il ? S'il accepte de répondre à
une requête contenant l'extension CHAIN
, il
doit :
CHAIN
dans la réponse, avec
la valeur Closest Trust Point mise au nom le
plus bas (le plus éloigné de la racine) pour lequel ces
informations sont nécessaires. (C'est surtout utile lorsque le
serveur n'envoie pas une chaîne complète, par exemple pour
économiser le réseau.)
Évidemment, si la question avait une erreur de syntaxe (taille de la
partie Valeur inférieure à la Longueur, par exemple), le serveur
répond FORMERR
(FORmat
ERRor).
La section 7 sur la sécurité étudie quelques
programmes que peut poser cette extension au DNS. D'abord, mettre en
œuvre cette option fatigue davantage le serveur interrogé, en terme
de travail et de capacité du réseau. Un serveur est donc toujours
libre d'ignorer les options CHAIN
et de s'en
tenir au service minimum.
Ensuite, comme vu plus haut, les réponses suivant une question
qui utilise CHAIN
vont être évidemment plus
grosses que les réponses DNS habituelles. Il y a donc un risque d'attaques par
réflexion avec amplification, si un attaquant usurpe
l'adresse IP de sa victime. C'est pour cela que notre RFC impose de
ne répondre avec une chaîne complète que si l'adresse IP du client a
été vérifiée (par exemple parce qu'il utilise
TCP, ou bien les cookies
du RFC 7873).
CHAIN
a aussi quelques effets sur la
vie privée. Le résolveur validant local va
indiquer à son forwarder (et à tout espion qui
surveille le trafic) comment il est
configuré et ce qu'il y a dans son cache.
Il ne semble pas qu'il existe de mise en œuvre de cette option
CHAIN
pour l'instant, même si c'est en projet pour Go.
Si vous vous intéressez à la conception des protocoles réseaux, notez que cette extension a fait l'objet d'une discussion pour savoir s'il ne valait pas mieux, pour réduire la latence, envoyer toutes les requêtes possibles en parallèle (cette idée a finalement été rejetée).
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : D. Bryan (Cogent Force), P. Matthews (Alcatel-Lucent), E. Shim (Samsung Electronics), D. Willis (Softarmor Systems), S. Dawkins (Huawei)
Pour information
Réalisé dans le cadre du groupe de travail IETF p2psip
Première rédaction de cet article le 19 juillet 2016
Le mécanisme de signalisation d'appels SIP, largement utilisé pour la téléphonie sur IP, dépend de serveurs stables et connectés en permanence (proxies, registrars, etc), pour la mise en relation des participants. Une solution entièrement pair-à-pair est en cours de développement, P2PSIP (peer to peer SIP). Ce nouveau RFC décrit ses concepts et le vocabulaire qu'elle emploie.
C'est en effet le cœur du problème de toute solution
pair-à-pair sur l'Internet : le
rendez-vous. Comment deux machines pas
toujours allumées, pas toujours connectées, coincées derrière des
équipements qui leur interdisent les connexions entrantes,
peuvent-elles rentrer en relation ? Si Alice appelle Bob via des
téléphones SIP, comment faire sonner la
machine de Bob, bloquée derrière son routeur
NAT ? La solution classique de SIP (RFC 3261) est de d'abord faire correspondre une adresse SIP
(appelée AoR pour Address of Record) avec un ou
plusieurs URI, qui indiquent les machines à
contacter. Ces machines sont des intermédiaires, reliés à
l'Internet en permanence, et qui peuvent donc tout le temps
recevoir le message INVITE
d'établissement de
connexion (cf. RFC 3263). L'idée de base du
SIP pair-à-pair, P2PSIP, est de remplacer ces intermédiaires, ces
relais, par un réseau P2P.
Le mécanisme exact, nommé RELOAD, est spécifié dans le RFC 6940 (notez que le protocole RELOAD peut servir à d'autres applications que SIP). Les machines des utilisateurs s'enregistrent dans une DHT, où les appelants vont trouver le moyen de les contacter. (Par défaut, la DHT utilisée est Chord.)
La section 2 de notre RFC donne une présentation générale de la solution complète. Un réseau pair-à-pair overlay sert à établir la correspondance entre adresses (AoR) et les URI indiquant les moyens de connexion. Ce même réseau sert également à acheminer les messages SIP, si les machines d'Alice et Bob n'arrivent pas à se parler directement (un problème fréquent dans l'Internet ossifié et fermé d'aujourd'hui). Ce réseau overlay de pairs stocke les correspondances, et les duplique sur plusieurs nœuds (comme dans tout réseau pair-à-pair, chaque machine peut faire défection à tout moment). Ce sont les services de base de l'overlay, ceux qui sont absolument indispensables au bon fonctionnement de P2PSIP. Mais certains pairs peuvent accepter de participer à d'autres services, comme un service de répondeur audio, pour les cas où Bob a éteint sa machine (cf. RFC 7374). De même, certains pairs peuvent assurer des services de proxy ou de registrar SIP traditionnel, pour permettre aux clients SIP anciens de se connecter via P2PSIP.
On n'est pas obligé d'être un pair dans ce réseau P2PSIP. Un softphone SIP peut être un simple client, utilisant les services de l'overlay sans y contribuer.
Notez qu'il existe d'autres moyens de faire du SIP sans l'appareil traditionnel des serveurs relais centraux. Ces moyens sont en général limités au réseau local (par exemple les RFC 6762 et RFC 6763).
Le cœur du RFC est sa section 4, qui regroupe les définitions. Je ne vais pas les reprendre ici. La plupart sont classiques dans le monde du pair-à-pair (overlay, peer...). À noter les termes de Node ID (l'identificateur unique d'un pair - RFC 6940, section 4.1) et de peer admission (le mécanisme par lequel on admet un nouveau pair : RELOAD permet un réseau fermé, où il faut montrer patte blanche à un serveur d'inscription avant de rentrer - RFC 6940, section 11.3.)
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : JM. Valin (Mozilla), C. Bran
(Plantronics)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 21 juin 2016
Ce très court RFC expose les exigences en matière de codec audio pour WebRTC. Opus et G.711 sont ainsi obligatoires.
WebRTC permet de communiquer (texte, audio et vidéo) entre deux machines, typiquement via les navigateurs Web (ainsi, Firefox et Chrome sont tous les deux capables de faire du WebRTC.) On sait qu'il existe un grand nombre de moyens de représenter les sons sous forme d'un flux de données numériques et, pour que la communication puisse se faire, il faut que les participants aient au moins un de ces moyens en commun. C'est le but de ce RFC. D'autres codecs peuvent évidemment être gérés par le logiciel mais ceux-ci sont obligatoires (section 3 du RFC) :
audio/telephone-event
du
RFC 4733 (DTMF), qui permet d'envoyer les indispensables
signaux « si vous voulez de la musique d'attente pendant une
heure, tapez 1, si vous voulez parler à un incompétent sous-payé
qui ne
comprendra pas votre problème, tapez 2 ».Les autres codecs facultatifs sont décrits dans le RFC 7875, ce qui a permis à chacun de faire citer son codec favori.
Notre RFC spécifie également le niveau sonore (section 4). Contrairement aux recommandations UIT G.169 et G.115, il n'est pas constant car il dépend de la bande passante.
Il y a aussi une mention de la suppression d'écho (section 5 du RFC), mais sans solution unique imposée.
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : Donald Eastlake (Huawei), Mark
Andrews (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 10 juin 2016
La grande majorité des requêtes DNS passent aujourd'hui sur UDP. Ce protocole ne fournit aucun mécanisme permettant de vérifier un tant soit peu l'adresse IP source de la requête. Contrairement à ce qui arrive avec TCP, il est trivial de mentir sur l'adresse IP source, sans être détecté. Cela permet des comportements négatifs, comme les attaques par réflexion. Ce nouveau RFC propose un mécanisme simple et léger pour s'assurer de l'adresse IP source du client : des petits gâteaux, les cookies.
Le principe est le même que pour les cookies de HTTP (décrits dans le RFC 6265) : le serveur DNS génère un nombre imprévisible qu'il transmet au client. Celui-ci renvoie ce nombre à chaque requête, prouvant qu'il recevait bien les réponses, et n'avait donc pas triché sur son adresse IP. (Notez une grosse différence avec les cookies du Web : ils changent quand l'adresse IP du client change et ils ne peuvent donc pas être utilisés pour suivre à la trace un client mobile.)
Bien sûr, une autre solution serait d'utiliser TCP (comme proposé dans le RFC 7766) ou bien DTLS (RFC en cours de discussion). Mais les petits gâteaux se veulent une solution moins radicale, de déploiement peut-être plus facile. Ils ne sont pas forcément utilisés seuls, ils peuvent être combinés avec d'autres mesures anti-usurpation, comme celles du RFC 5452.
Comme avec toute technique de sécurité, il faut regarder en détail les menaces auxquelles elle répond (section 2 du RFC). En usurpant l'adresse IP source, un méchant peut effectuer des attaques par déni de service, et il peut empoisonner un cache. Voyons ces deux cas.
D'abord, l'attaque par déni de service : en usurpant l'adresse IP source, on peut effectuer une attaque par réflexion. Dans ces attaques, le méchant envoie un paquet à un tiers, le réflecteur, en mentant sur son adresse IP source : le méchant met celle de la victime. Lorsque le réflecteur répondra, il enverra un message à la victime. Cette attaque est surtout intéressante lorsqu'elle est combinée avec l'amplification. Si la réponse est plus grosse que la question (ce qui est en général le cas avec le DNS), le méchant aura frappé la victime avec davantage d'octets que ce qu'il a lui-même envoyé.
Avec les cookies, cette attaque ne serait pas possible, la réponse à une requête ayant un cookie erroné étant plus petite que la question.
Notez que les cookies ne protègent pas contre un attaquant situé sur le chemin (on-path attacker) et qui peut lire le trafic réseau : voyant les paquets, il verra le cookie et pourra le transmettre. Les cookies n'empêchent donc pas toutes les attaques. D'autre part, si l'attaquant matraque directement le serveur DNS (sans réflexion), les cookies n'empêcheront pas l'attaque mais ils permettent de s'assurer que l'adresse IP source est exacte, ce qui autorisera de remonter à la source de l'attaque.
Le déni de service peut aussi viser le serveur DNS (au lieu de simplement l'utiliser comme réflecteur dans une attaque par réflexion). Chaque requête DNS va donner du travail au serveur et un nombre excessif peut dépasser ses capacités (comme dans l'attaque dafa888). Le problème est surtout aigu pour les serveurs récursifs, qui ont nettement plus à faire lorsqu'une requête arrive. Et ceux qui ont le plus de travail sont les serveurs récursifs qui valident avec DNSSEC : lors de la réception d'une réponse, il faut faire des calculs cryptographiques pour cette validation. Ces attaques par déni de service, au contraire de celles faites par réflexion, n'imposent pas de tricher sur l'adresse IP source mais, en le faisant, l'attaquant a l'avantage de rendre plus difficile son identification. Et cela peut lui permettre de faire traiter des requêtes qui seraient normalement refusées. Par exemple, si un résolveur n'accepte de requêtes que de son réseau (ce qui est la bonne pratique, cf. RFC 5358), et si on a oublié de filtrer en entrée les requêtes prétendant venir du réseau local, une attaque reste possible, en usurpant les adresses IP locales (une telle attaque est décrite dans l'exposé de Lars Nøring).
Après les attaques par déni de service, voyons les attaques visant à faire accepter de fausses réponses, ce qui peut mener à empoisonner le cache. Le principe est de répondre à la place du vrai serveur faisant autorité, en usurpant son adresse IP. Si le méchant est plus rapide, sa réponse peut, dans certains cas, être acceptée par un résolveur (qui la mettra peut-être dans son cache, ce qui sera encore pire). L'attaque Kaminsky est une version améliorée de cette vieille attaque. Les cookies sont une bonne protection contre ce genre d'attaques.
Après les attaques, voyons les défenses. Il n'y a pas que les cookies dans la vie. D'abord, il y a DNSSEC (RFC 4034 et RFC 4035). DNSSEC permet d'authentifier les réponses DNS, résolvant ainsi complètement les attaques par empoisonnement. Par contre, il ne résout pas les attaques par déni de service et, pire, les calculs cryptographiques qu'il impose et la taille des réponses plus élevées peuvent dans certains cas aggraver une partie de ces attaques. (Le RFC ne le note pas, mais DNSSEC a une autre limite, que les cookies résolvent : s'il empêche l'empoisonnement, il ne permet pas pour autant d'obtenir la réponse DNS correcte. DNSSEC protège bien du hameçonnage, beaucoup moins de la censure.)
Autre solution de sécurité, TSIG (RFC 8945). TSIG est meilleur que les cookies dans la mesure où il permet de vérifier cryptographiquement l'identité de la machine avec qui on parle DNS. Mais il est non trivial à déployer : reposant sur de la cryptographie symétrique, il impose un partage des clés préalable. Cela le limite à des usages entre parties qui se connaissent bien (typiquement pour sécuriser les transferts de zone). On note aussi que, comme DNSSEC, mais contrairement aux cookies, il nécessite des horloges synchronisées.
Pour résoudre ce problème de déployabilité, on peut envisager le mécanisme de distribution de clés TKEY (RFC 2930) ou bien passer à de la cryptographie asymétrique avec SIG(0) (RFC 2931). Mais aucune de ces deux techniques n'a connu de déploiement significatif.
Bref, les solutions de sécurité existantes ne résolvent pas réellement les problèmes que veulent traiter les cookies. Mais assez parlé de la « concurrence », venons-en aux cookies, comment marchent-ils (section 4 de notre RFC) ? Les cookies s'appuient sur EDNS (RFC 6891). Ils sont donc une option dans l'enregistrement EDNS. L'option cookie de EDNS porte le numéro 10. Comme toutes les options EDNS, elle est codée en TLV : le type 10, la longueur et la valeur, qui comprend un ou deux cookies. S'il n'y a que le cookie client, la longueur est fixe, de 8 octets. S'il y a en plus le cookie serveur, la longueur peut aller de 16 à 40 octets.
Le cookie client est normalement le résultat d'une fonction non-prévisible des adresses IP du client et du serveur, et d'un secret connu du client (par exemple, généré aléatoirement en suivant le RFC 4086, et changé de temps en temps). Cette fonction est, par exemple, une condensation mais le client prend ce qu'il veut : il est le seul à avoir besoin d'interpréter ses propres cookies, ils sont opaques pour tout autre acteur. L'adresse IP du client est incluse dans les paramètres de la fonction notamment pour des raisons de vie privée : empêcher le client d'être reconnu s'il change d'adresse IP (le but de nos cookies DNS n'est pas du tout le même que celui des fameux cookies du Web).
Le cookie serveur prend comme paramètres de sa propre fonction (qui n'est pas forcément la même) l'adresse IP de son client, un secret (mêmes propriétés que chez le client), et le cookie du client (et pourquoi le cookie client ne se sert pas du cookie serveur ? Voyez la section 6.) Voilà comment on fabrique les gâteaux.
Mais comment les utilise-t-on ? La section 5 l'explique. Le client qui gère les gâteaux fabrique un cookie client qu'il envoie dans ses requêtes DNS. S'il n'a jamais parlé au serveur, il envoie une option cookie de forme courte, ne comprenant qu'un seul cookie, le sien. S'il a déjà parlé au serveur et mémorisé le cookie de celui-ci, il fabrique une option EDNS cookie longue, incluant les deux cookies.
Si le serveur ne comprend rien aux cookies, il ne met pas l'option dans la réponse, et le client sait alors qu'il s'agit d'un vieux serveur, sans gestion des cookies. (Ou bien c'était une attaque par repli ; le cas ne semble pas traité dans le RFC, la solution est sans doute que le client mémorise les serveurs cookie-capable, pour détecter ces attaques.)
Si, par contre, le serveur gère les cookies, il y a cinq possibilités :
FORMERR
(FORmat
ERRor).BADCOOKIE
(valeur 23), incluant le
cookie du serveur, ou enfin de répondre
normalement, en ajoutant son cookie. En
effet, dans ce cas, le client n'est pas « authentifié ». On n'a
pas vérifié son adresse IP source. Il peut donc être justifié
de ne pas donner la réponse tout de suite (le
BADCOOKIE
) ou bien, par exemple, de
limiter le trafic de ce client (comme
on le fait
aujourd'hui, avant les cookies, puisqu'on n'est jamais sûr de l'adresse IP
du client).
Lorsqu'il reçoit une réponse, le client doit mémoriser le
cookie du serveur. C'est particulièrement
important la première fois, lorsque le client n'est pas encore
authentifié. Si la réponse était BADCOOKIE
,
cela veut dire qu'on a affaire à un serveur grognon qui ne veut
pas répondre sans qu'on lui donne un cookie
correct : on retransmet alors la requête, cette fois en incluant
le cookie transmis par le serveur.
Voilà, c'est tout. Avec ce système, on a une authentification légère et simple de l'adresse IP du client. Dans la vraie vie, il y aura peut-être quelques problèmes pratiques, que couvre la section 6 de notre RFC. Par exemple, si le client est derrière du NAT (RFC 3022), un méchant situé sur le même réseau local que lui pourrait faire une requête au serveur, obtenir le cookie du serveur et envoyer ensuite des requêtes en usurpant l'adresse IP locale du client légitime. Le serveur ne peut pas distinguer ces deux clients, le bon et le méchant. C'est pour cela que le cookie serveur inclut dans les paramètres de sa fonction le cookie du client. Ainsi, les deux machines, la gentille et la méchante auront des cookies serveur différents.
Un problème du même genre (plusieurs machines derrière une même adresse IP) pourrait survenir côté serveur, par exemple en raison de l'anycast. Mais on ne peut pas appliquer la même solution : si le cookie serveur dépend du cookie client et le cookie client du cookie serveur, on a une boucle sans fin. Le serveur doit donc se débrouiller : soit avoir le même secret (et donc les mêmes cookies) sur toutes les machines (c'est l'approche la plus simple, et c'est celle recommandée par le RFC), soit faire en sorte qu'un client donné arrive toujours sur la même machine.
D'autres considérations pratiques figurent en section 7, notamment sur le remplacement d'un secret (ce qui invalidera les cookies précédemment distribués).
Et quelques discussions sur la sécurité, pour finir (section 9 du RFC). L'« authentification » fournie par les cookies est faible : elle ne protège pas contre un attaquant situé sur le chemin de communication entre client et serveur, lorsqu'il peut lire le trafic. Dans ce cas, l'attaquant a en effet accès au cookie et peut facilement le rejouer. Par exemple, si on est connecté à un réseau Wi-Fi public sans sécurité (pas de WPA), n'importe quel client du même réseau peut voir passer les cookies. Néanmoins, les cookies réduisent quand même sérieusement l'ampleur du problème. Une attaque (l'usurpation d'adresse IP) que tout l'Internet pouvait faire est maintenant restreinte à un sous-ensemble de l'Internet. Si cela est encore trop, il faut passer à une sécurisation cryptographique comme celle que fournit le RFC 7858.
L'algorithme utilisé pour calculer les cookies est évidemment crucial. Il n'a pas besoin d'être normalisé, puisque seule la machine qui émet le cookie original a besoin de le comprendre. Mais il doit garantir des cookies très difficiles à prévoir par un attaquant. On peut par exemple utiliser SHA-256 (RFC 6234, mais il n'y a pas forcément besoin de cryptographie top canon, les cookies n'étant qu'une authentification faible, de toute façon). Depuis la parution de notre RFC, le RFC 9018 a décrit un algorithme recommandé si des serveurs veulent être compatibles, par exemple s'ils font partie du même service anycast.
Des exemples d'algorithmes figurent dans les annexes A et B (mais le RFC 9018 en a abandonné certains). Pour le client DNS, un algorithme simple serait d'appliquer la fonction simple et rapide FNV-64 à la concaténation des adresses IP du client et du serveur, et du secret. Un algorithme plus compliqué, mais plus sûr, serait de remplacer FNV par SHA-256, plus coûteux.
Pour le serveur, l'algorithme simple serait un FNV-64 de la concaténation de l'adresse IP du client, du cookie du client, et du secret. Pour l'algorithme compliqué, on peut tirer profit de la longueur plus grande du cookie serveur pour y mettre davantage d'informations : par exemple, huit octets calculés comme dans l'algorithme simple suivis de l'heure de génération du cookie (pour détecter plus facilement les vieux cookies, avant même toute opération cryptographique).
Et les mises en œuvre ? Les cookies sont gérés par BIND à partir de la version 9.11 (pas encore officiellement publiée). Ils sont activés par défaut. Et Wireshark sait les afficher. Ici, un client nouveau (il ne connait pas encore le cookie serveur) :
No. Time Source Destination Protocol Length Info 1 0.000000 192.168.2.9 192.168.2.7 DNS 97 Standard query 0x0000 SOA foobar.example OPT ... Domain Name System (query) ... Additional records <Root>: type OPT ... Data length: 12 Option: COOKIE Option Code: COOKIE (10) Option Length: 8 Option Data: fb40ce9a68a6f1f0 Client Cookie: fb40ce9a68a6f1f0 Server Cookie: <MISSING> No. Time Source Destination Protocol Length Info 2 0.003910 192.168.2.7 192.168.2.9 DNS 200 Standard query response 0x0000 SOA foobar.example SOA ns1.foobar.example NS ns1.nic.fr NS ns2.nic.fr OPT ... Additional records <Root>: type OPT ... Data length: 28 Option: COOKIE Option Code: COOKIE (10) Option Length: 24 Option Data: fb40ce9a68a6f1f0727e7501575acc5977ced0351ad20d56 Client Cookie: fb40ce9a68a6f1f0 Server Cookie: 727e7501575acc5977ced0351ad20d56
L'algorithme de condensation peut être choisi mais, apparemment,
uniquement à la compilation (avec
--with-cc-alg=ALG
où
ALG
vaut aes|sha1|sha256
).
Le dig livré avec cette version de BIND peut passer des cookies :
% dig +cookie @192.168.2.7 foobar.example ... ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags: do; udp: 4096 ; COOKIE: 51648e4b14ad9db8eb0d28c7575acbdde8f541a0cb52e2c2 (good) ;; QUESTION SECTION: ;foobar.example. IN A ...
Pour les programmeurs en Go, la bibliothèque Go DNS gère désormais les cookies. Un exemple de code Go pour les envoyer :
m := new(dns.Msg) m.Question = make([]dns.Question, 1) c := new(dns.Client) m.Question[0] = dns.Question{zone, dns.TypeSOA, dns.ClassINET} o := new(dns.OPT) o.Hdr.Name = "." o.Hdr.Rrtype = dns.TypeOPT o.Hdr.Class = 4096 e := new(dns.EDNS0_COOKIE) e.Code = dns.EDNS0COOKIE e.Cookie = "fb40ce9a68a6f1f0" o.Option = append(o.Option, e) m.Extra = make([]dns.RR, 1) m.Extra[0] = o
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : F. Gont (SI6 Networks /
UTN-FRH), J. Linkova
(Google), T. Chown (University of
Southampton), W. Liu (Huawei)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 5 juillet 2016
Normalement, l'Internet est un monde idéal où la machine d'Alice peut envoyer à celle de Bob les paquets qu'elle veut, Bob les recevra intacts (s'il le veut). Dans la réalité, pas mal de machines intermédiaires ne respectent pas ce principe de bout en bout. Il est fréquent que les paquets « inhabituels » soient jetés en route. Cela peut être le résultat d'une politique délibérée (pare-feu appliquant le principe « dans le doute, on jette ») ou bien, souvent, de l'incompétence des programmeurs qui n'ont pas lu les RFC et ne connaissent pas telle ou telle option. Par exemple, IPv6 permet d'ajouter au paquet, entre l'en-tête proprement dit et la charge utile du paquet, un ou plusieurs en-têtes d'extension. C'est rare en pratique. Est-ce que les programmeurs des middleboxes ont fait attention à cette possibilité ? Les paquets ayant ces en-têtes d'extension ont-ils de bonne chances d'arriver au but ? Ce nouveau RFC est un compte-rendu de mesures effectuées dans l'Internet pour essayer de quantifier l'ampleur exacte du problème.
Un point important du travail effectué par les auteurs du RFC
est qu'ils ne sont pas contentés de chercher
si les paquets étaient jetés mais également
où ils étaient jetés. La différence est
politiquement cruciale. Si le paquet IPv6
portant un en-tête d'extension est jeté par la machine de Bob, car
Bob n'aime pas ces en-têtes et il a configuré son
Netfilter pour les envoyer vers
DROP
, pas de problème : Bob est libre
d'accepter ou de refuser ce qu'il veut. Si, par contre, le paquet
a été jeté par le FAI d'Alice ou de Bob,
ou, encore pire, par un opérateur de transit entre les deux FAI,
c'est grave, c'est une violation de la neutralité du réseau,
violation qui empêche deux adultes consentants de s'envoyer les
paquets qu'ils veulent. Le mécanisme de mesure cherche donc à
trouver dans quel AS le paquet a
disparu.
Les mesures ont été faites en août 2014 et juin 2015. Le RFC détaille suffisamment la façon dont elles ont été faites (annexe A) pour qu'une autre équipe puisse recommencer les mesures à une date ultérieure, pour voir si la situation s'améliore.
Les en-têtes d'extension IPv6 sont décrits dans le RFC 2460, section 4. Ils sont de deux plusieurs sortes, entre autre :
Outre la fragmentation, un exemple d'utilisation de ces en-têtes est le protocole CONEX (RFC 7837). Si vous voulez ajouter des options pour la destination dans un paquet IPv6, vous pouvez regarder mon tutoriel.
Quelles sont les chances de survie des paquets portant ces en-têtes d'extension dans le sauvage Internet ? Des études comme « Discovering Path MTU black holes on the Internet using RIPE Atlas », « Fragmentation and Extension header Support in the IPv6 Internet » ou bien « IPv6 Extension Headers in the Real World v2.0 » s'étaient déjà penchées sur la question. Les mesures de ce RFC détaillent et complètent ces résultats préliminaires, notamment sur la différenciation entre perte de paquet près de la destination, et perte du paquet en transit. La conclusion est, qu'hélas, les paquets IPv6 portant des en-têtes d'extension font effectivement l'objet d'une discrimination négative (« entêtophobie » ?).
Donc, qu'est-ce que ça donne dans l'Internet réel (section 2) ?
Deux listes de serveurs IPv6 ont été utilisées, celle du
World IPv6
Launch Day et le premier million d'Alexa. De ces listes de
domaines ont été extraits les adresses IP des sites Web
(dig AAAA LE-DOMAINE
et, oui, je sais que
c'est un sérieux raccourci de supposer que tout domaine a un
serveur Web à l'apex), des relais de
messagerie (dig MX LE-DOMAINE
puis obtenir
l'adresse IPv6 des serveurs), et des serveurs de noms
(dig NS LE-DOMAINE
). Les adresses absurdes (::1
...)
ont été retirées. Ensuite, pour chaque adresse ainsi obtenue,
trois types de paquets ont été envoyés :
Les paquets étaient tous du TCP à destination d'un port correspondant au service (25 pour les serveurs de messagerie, par exemple).
Un point très important et original de cette expérience était la recherche d'information sur où se produisait l'éventuelle perte de paquets (dans quel AS). L'hypothèse de base est qu'une élimination du paquet dans l'AS de destination peut être acceptable, parce qu'elle résulte d'une décision consciente du destinataire. En tout cas, il sera plus facile de changer la politique de l'AS de destination. En revanche, une élimination dans un AS intermédiaire est inacceptable : elle indique filtrage ou erreur de configuration dans un réseau qui devrait être neutre. Notez que l'hypothèse n'est pas parfaite : si un particulier héberge un serveur chez lui et que son FAI filtre les paquets IPv6 avec en-tête d'extension, c'est quand même inacceptable, et c'est difficile pour le particulier de le faire corriger.
Comment identifier l'AS qui jette le paquet ? L'idée est de faire l'équivalent d'un traceroute (en fait, deux, un avec l'en-tête de destination et un sans, pour comparer : cf. annexe B.1) et de voir quel est le dernier routeur qui a répondu. C'est loin d'être idéal. Des routeurs ne répondent pas, pour d'autres, il est difficile d'évaluer à quel AS ils appartiennent (dans un lien de peering entre deux acteurs A et B, les adresses IP utilisées ont pu être fournies par A ou bien par B ; cf. annexe B.2). Et l'absence d'un routeur dans le résultat de traceroute ne prouve pas que le routeur n'a pas transmis le paquet juste avant. La mesure indique donc deux cas, l'optimiste, où on suppose, en l'absence de preuve opposée, que les paquets manquant ont été jetés par l'AS de destination et le pessimiste où on fait la supposition inverse.
Les résultats complets des mesures figurent dans le RFC. Je résume ici une partie. Pour les serveurs Web de la liste du World IPv6 Launch Day :
Les résultats ne sont guère différents pour les autres services (comme SMTP), indiquant que le problème, quand il est présent, est bien dans la couche 3. Idem avec le jeu de données Alexa : peu de différences.
On voit que les paquets utilisant l'en-tête d'extension « Options pour chaque intermédiaire » sont ceux qui s'en tirent le plus mal (c'est un peu logique, cet en-tête étant censé être examiné par tous les routeurs intermédiaires). Les fragments passent assez mal également. Enfin, on note qu'un pourcentage significatif des paquets sont jetés par un AS de transit, qui viole ainsi massivement le principe de bout en bout. Triste état de l'Internet actuel, pourri de middleboxes qui se permettent tout.
Si vous voulez refaire l'expérience vous-même, pour contrôler
les résultats, ou bien pour mesurer l'évolution dans quelque
temps, l'annexe A vous donne les éléments nécessaires. Vous aurez
besoin du toolkit de
SI6. Les données d'Alexa sont disponibles
en ligne. L'outil
script6
dans le toolkit
SI6 permet d'obtenir les adresses IP nécessaires. Par exemple :
% cat top-1m.txt | script6 get-mx | script6 get-aaaa
Et on obtient ainsi les adresses IP des relais de messagerie. Pour
supprimer les adresses incorrectes (par exemple
::1
), on utilise l'outil
addr6
du toolkit :
% cat top-1m-mail-aaaa.txt | addr6 -i -q -B multicast -B unspec -k global
Il n'y a plus maintenant qu'à envoyer les paquets portant les en-têtes d'extension, ou fragmentés. Ici, les serveurs de messagerie avec l'en-tête Destination Options (« do8 ») :
% cat top-1m-mail-aaaa-unique.txt | script6 trace6 do8 tcp 25
L'annexe B de notre RFC contient quelques avertissements méthodologiques.
Un
traceroute ordinaire ne suffit pas à faire
les mesures décrites plus haut pour identifier le routeur
responsable d'une perte de paquet (le traceroute ordinaire ne
permet pas d'ajouter l'en-tête d'extension aux paquets utilisés). Il faut utiliser un outil
spécial comme le path6
du
toolkit SI6. Encore plus simple, dans le même
paquetage, l'outil blackhole6
. Voyons d'abord
path6
pour comprendre les détails :
% sudo path6 -d yeti.ipv6.ernet.in Tracing path to yeti.ipv6.ernet.in (2001:e30:1c1e:1::333)... 1 (2001:4b98:dc0:41::250) 1.1 ms 0.5 ms 0.4 ms 2 (2001:4b98:1f::c3d3:249) 1.2 ms 3.5 ms 3.4 ms 3 (2001:7f8:54::173) 1.1 ms 0.8 ms 0.6 ms 4 (2001:1a00:1:cafe::e) 141.3 ms 140.7 ms 140.6 ms 5 (2001:1a00:1:cafe::145) 118.8 ms 118.8 ms 119.5 ms 6 (2001:1a00:1:cafe::141) 140.7 ms 137.2 ms 137.3 ms 7 (2001:1a00:1:cafe::10b) 144.0 ms 144.3 ms 144.1 ms 8 (2001:1a00:1:cafe::212) 140.5 ms 140.5 ms 140.5 ms 9 (2001:1a00:1:cafe::207) 137.0 ms 137.0 ms 136.9 ms 10 (2001:1a00:acca:101f::2) 136.5 ms 136.4 ms 136.5 ms 11 (2001:4528:ffff:ff04::1) 152.2 ms 152.1 ms 152.2 ms 12 (2001:4528:fff:c48::1) 163.6 ms 163.7 ms 163.6 ms 13 (2001:e30:1c1e::1) 162.6 ms 162.3 ms 162.2 ms 14 (2001:e30:1c1e:1::333) 174.5 ms 175.1 ms 175.2 ms
OK, on arrive à joindre la machine en Inde. Maintenant, ajoutons l'en-tête Hop-by-Hop Options :
% sudo path6 --hbh-opt-hdr 8 -d yeti.ipv6.ernet.in Tracing path to yeti.ipv6.ernet.in (2001:e30:1c1e:1::333)... 1 (2001:4b98:dc0:41::250) 20.9 ms 20.0 ms 19.0 ms 2 (2001:4b98:1f::c3d3:249) 20.8 ms 20.2 ms 18.5 ms 3 (2001:4b98:1f::c3c4:3) 20.7 ms 20.4 ms 18.5 ms 4 (2001:1a00:1:cafe::e) 154.3 ms 14.4 ms 152.1 ms 5 (2001:1a00:1:cafe::e) 151.0 ms 129.6 ms 148.9 ms 6 (2001:1a00:1:cafe::141) 151.2 ms 126.2 ms 148.8 ms 7 (2001:1a00:1:cafe::141) 156.5 ms 156.8 ms 158.6 ms 8 (2001:1a00:1:cafe::212) 153.6 ms 191.2 ms 151.4 ms 9 (2001:1a00:1:cafe::212) 155.3 ms 151.1 ms 157.7 ms 10 (2001:1a00:1:cafe::207) * 155.619995 ms * 11 () * * * 12 () * * * 13 () * * * ...
Aïe, ça n'arrive plus. Le routeur situé après
2001:1a00:1:cafe::207
a jeté le paquet. En
comparant les deux path6
, on peut voir que le
coupable est 2001:1a00:acca:101f::2
(Flag, désormais une marque de Reliance). L'outil
blackhole6
fait tout ce travail
automatiquement (EH = Extension Header, HBH 8 =
Hop-by-Hop, size 8) :
% sudo blackhole6 yeti.ipv6.ernet.in hbh8 SI6 Networks IPv6 Toolkit v2.0 (Guille) blackhole6: A tool to find IPv6 blackholes Tracing yeti.ipv6.ernet.in (2001:e30:1c1e:1::333)... Dst. IPv6 address: 2001:e30:1c1e:1::333 (AS2697 - ERX-ERNET-AS Education and Research Network, IN) Last node (no EHs): 2001:e30:1c1e:1::333 (AS2697 - ERX-ERNET-AS Education and Research Network, IN) (14 hop(s)) Last node (HBH 8): 2001:1a00:1:cafe::207 (AS15412 - FLAG-AS Flag Telecom Global Internet AS, GB) (10 hop(s)) Dropping node: 2001:1a00:acca:101f::2 (AS15412 - FLAG-AS Flag Telecom Global Internet AS, GB || AS Unknown - Unknown)
Sur ce sujet et ces tests, on peut aussi regarder l'exposé de Mehdi Kouhen au symposium Polytechnique/Cisco, ou bien celui d'Eric Vyncke à Protosec à Buenos Aires.
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : C. Contavalli, W. van der Gaast
(Google), D. Lawrence (Akamai
Technologies), W. Kumari (Google)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 20 juin 2016
Dernière mise à jour le 13 juin 2022
Ce nouveau RFC décrit une option EDNS qui permet à un client DNS d'indiquer au serveur l'adresse IP d'origine de la requête DNS. Pourquoi diable ferait-on cela, au prix de la vie privée ? Cette option est surtout utile dans le cas de l'utilisation d'un gros résolveur DNS public (comme Google Public DNS) et d'un CDN.
Pour comprendre pourquoi, il faut se rappeler que le
DNS ne fonctionne pas de bout en bout. La
machine de M. Michu émet des requêtes DNS à un
résolveur (en général fourni par le
FAI ou par le réseau local, mais certaines
personnes, victimes du marketing, préfèrent les résolveurs publics
comme OpenDNS, plus lointains et plus
lents). Ce résolveur, à son tour, interroge les serveurs
faisant autorité. Si M. Michu voulait se connecter à un
site Web pour voir des vidéos de chats, il est possible qu'un nouvel
acteur soit présent, le CDN (comme
Akamai) qui héberge les
dites vidéos. Les serveurs DNS faisant autorité pour le CDN
renvoient souvent une adresse IP différente selon l'adresse IP du
résolveur qui les interroge. Si l'adresse IP du client est au
Sénégal, l'adresse IP du serveur de vidéos
qui sera renvoyée sera celle du centre de
données le plus « proche » du Sénégal. En temps normal,
cela fonctionne plus ou moins. Bien sûr, le serveur DNS faisant
autorité pour le CDN ne voit pas le « vrai » client, M. Michu, il
voit le résolveur DNS utilisé mais les deux sont proches : si
M. Michu est en Colombie, son résolveur DNS le sera aussi. Voici un
exemple, vu avec les sondes RIPE Atlas, où on
demande, au Sénégal (SN) puis en Colombie (CO) l'adresse IP de www.elysee.fr
, hébergé
sur un CDN états-unien :
% blaeu-resolve --country SN www.elysee.fr [207.123.59.254 209.84.7.126 8.27.7.254] : 1 occurrences [209.84.7.126 8.253.3.254 8.27.7.254] : 1 occurrences [4.26.233.254 4.26.236.126 8.254.119.126] : 1 occurrences [207.123.59.254 209.84.7.126 8.253.3.254] : 1 occurrences [207.123.59.254 8.26.223.254 8.27.7.254] : 1 occurrences Test #4106632 done at 2016-06-15T22:52:44Z % blaeu-resolve --country CO www.elysee.fr [192.221.116.253] : 3 occurrences [205.128.71.253 4.27.25.125 8.27.155.126] : 1 occurrences [206.33.52.253 209.84.20.126 8.253.16.126] : 1 occurrences Test #4106633 done at 2016-06-15T22:52:46Z
On voit qu'on a obtenu des adresses IP très différentes et, espérons-le, adaptées à chaque pays.
Autre exemple, avec un service de PowerDNS, qui renvoyait (il semble ne plus marcher) une géolocalisation du client. Ici, j'utilise dig depuis deux machines différentes, une en France et l'autre aux États-Unis :
% dig +short -t txt www.geo.powerdns.com "bonjour france 2a01:db8:8bd9:85cb:21e:8cff:fe76:29b6/26" % dig +short -t txt www.geo.powerdns.com "hello USA 204.62.14.153/22"
On voit que le résolveur que j'utilise (qui, à chaque fois, était sur le réseau local de la machine cliente), a bien été géolocalisé. Si j'utilise un résolveur public :
% dig @8.8.8.8 +short -t txt www.geo.powerdns.com "bonjour france XX.YY.152.0/11"
Ici, cela a marché car Google Public DNS a des serveurs en France. Si cela n'avait pas été le cas, j'aurais été géolocalisé... quelque part ailleurs.
Tout change (section 1 du RFC) si on utilise un résolveur DNS public comme Verisign Public DNS ou bien Yandex DNS. Dans ce cas, l'adresse IP du résolveur, vue par le serveur faisant autorité pour le CDN, n'a plus grand'chose à voir avec celle du vrai client, elle peut être très lointaine. Les serveurs DNS faisant autorité risquent donc de renvoyer une adresse IP de serveur Web qui ne soit pas optimale. Certes, tout marchera quand même mais ça sera plus lent alors qu'officiellement, le but des CDN est d'accélerer l'arrivée de la vidéo du chat (non, de François Hollande).
On voit que ce RFC résout donc un problème que n'a pas tout le monde. Seuls ceux qui se servent d'un résolveur public lointain, et qui visitent des sites Web hébergés sur un CDN (en général les gros sites commerciaux) auront le problème. C'est une des raisons qui expliquent que ce RFC a pas mal trainé (voyez cet article, qui date de plusieurs années) à l'IETF : son intérêt n'est pas évident, et il y avait beaucoup de contestation. Mais l'IETF a finalement choisi de documenter cette option (qui est effectivement déployée), sans forcément la recommander.
Donc, comment est-ce que cela résout le problème décrit plus
haut ? L'idée est de standardiser une option EDNS que les résolveurs
publics ajouteront dans leur requête aux serveurs faisant autorité,
et qui indiquera la « vraie » adresse IP d'origine (section 5 du RFC). Imaginons que
M. Michu ait pour adresse IP 192.0.2.56
et
qu'il utilise Google Public DNS. Ce dernier va transmettre la
requête au CDN et ajoutera l'option Client
Subnet (ce n'est donc pas M. Michu qui le fera). Le serveur DNS du CDN verra
une requête arriver de, mettons,
74.125.17.1
. L'option EDNS Client
Subnet contiendra le préfixe de l'adresse IP de M. Michu,
192.0.2.0/25
. Il saura alors qu'il doit adapter
ses réponses, non pas au préfixe 74.125.17.0/24
(son client direct) mais au préfixe
192.0.2.0/25
(le vrai client). C'est donc une
option entre résolveur et serveur faisant autorité, pas entre
machine terminale et résolveur.
Le format de l'option est décrite dans la section 6 du RFC. Comme toutes les options EDNS (RFC 6891), elle est encodée en TLV : le type est 8, la valeur est composée de :
192.0.2.0
dans
l'exemple plus haut).La section 7 du RFC décrit les détails du protocole. Le résolveur va mettre dans son cache les réponses du serveur faisant autorité. Normalement, l'information dans le cache est indexée par le nom de domaine (et le type de données demandé, mais je simplifie). Avec ECS (EDNS Client Subnet), l'information est indexée par le couple {nom de domaine, préfixe IP}. En effet, deux requêtes pour le même nom peuvent avoir donné des résultats différents selon le préfixe IP (c'est bien le but !).
Le résolveur qui met cette option doit choisir la longueur du préfixe envoyé. Il tient compte de deux choses :
Mais l'affaire est un peu plus compliquée : le client d'origine (la machine de M. Michu, le stub resolver) a pu mettre une option ECS elle-même (ce n'est pas courant aujourd'hui mais ça pourrait arriver). Dans ce cas, le résolveur doit en tenir compte et mettre comme longueur la plus courte entre celle demandée par le client (a priori pour protéger sa vie privée) et celle que le résolveur aurait choisi tout seul.
Si la requête reçue par le résolveur avait l'option ECS et une longueur de zéro, cela indique le souhait du client qu'on ne transmette pas son adresse IP du tout. Le résolveur doit évidemment respecter cette demande.
Et le serveur faisant autorité, que doit-il mettre dans sa réponse ? (S'il envoie des réponses différentes selon la source, et s'il gère l'option ECS, EDNS Client Subnet ; autrement, c'est simple, il ne fait rien de particulier.) Il met une option ECS dans la réponses, avec :
(Notez que le RFC est bien plus détaillé que ce résumé, car il y a plein de cas rigolos. Je me suis limité à une présentation générale, je n'essaie pas de traduire tout le RFC.)
En recevant cette réponse, le résolveur va la mettre dans son
cache, en tenant compte de la longueur du préfixe (et, bien sûr,
le résolveur transmet la réponse à son client). Une réponse
valable pour 2001:db8:43:bef::/64
ne pourra
pas être utilisée pour le client
2001:db8:43:bed::1
. Quelle longueur sera
utilisée pour indexer le cache ? Celle demandée ou bien celle
effective ? Les régles exactes sont un peu complexes (il faut
tenir compte de la longueur effective, mais aussi des limites du
cache, qui ne veut pas stocker une réponse pour des préfixes trop spécifiques), je vous
renvoie à la section 7.3.1 du RFC.
Les questions ultérieures des clients du résolveur pourront
recevoir une réponse tirée du cache, sans repasser par les
serveurs faisant autorité. Mais ECS impose d'organiser le cache
différemment. Avec le DNS classique, si on a dans le cache la
réponse à une question pour cat.example.com
(je simplifie en ne tenant pas compte du type des données DNS),
et qu'on reçoit une question pour ce nom, on peut répondre avec
les données du cache. Avec ECS, le cache doit en plus tenir compte
du préfixe stocké avec la réponse, et de l'adresse IP du
client.
Et avec DNSSEC, ça se passe comment (section 9 du RFC) ? Les CDN ne signent pas leur zone en général. Mais s'ils s'y mettent (il le faudrait), il y aura quelques précautions à prendre.
Et avec le NAT ? Il n'y a normalement pas de problèmes, sauf évidemment si le résolveur est NATé et ne le sait pas : il mettrait, dans ce cas, une adresse privée dans l'option ECS, ce qui serait idiot.
Reste à regarder les problèmes de sécurité et notamment de vie privée. ECS diminue forcément votre vie privée. Il ajoute en effet une information qui n'était pas là sans lui (et le RFC 8165 dit bien que c'est mal). C'est pour limiter les dégâts que le RFC recommande aux résolveurs qui ajoutent une option Client Subnet de la limiter aux 24 premiers bits en IPv4 et aux 56 premiers en IPv6. Un résolveur qui connait bien la topologie de son réseau peut faire encore mieux : s'il sait que tous ses clients sont proches, et couverts par le même /20, il peut ainsi ne transmettre que les vingt premiers bits, sans diminuer l'intérêt du service.
Notez que, avec les clients DNS d'aujourd'hui, votre résolveur mettra votre adresse IP dans ses requêtes sortantes. On peut en sortir (opt-out en mettant une option ECS avec une longueur nulle) mais cela nécessite une action explicite (que ne permettent pas forcément les clients DNS actuels, notamment les stub resolvers, ceux qui sont intégrés dans le système d'exploitation). Le RFC recommande donc que cette option ECS soit désactivée par défaut, en raison de ces risques.
L'option ECS peut être vue par les serveurs faisant autorité, mais également par les tiers qui espionnent le trafic. Pour empêcher cela, il faudra déployer des solutions de chiffrement du trafic DNS, comme celles sur lesquelles travaille le groupe DPRIVE.
Un bon article sur les problèmes de vie privée liés à ECS est le « Understanding the Privacy Implications of ECS » de Panagiotis Kintis, Yacin Nadji, David Dagon, Michael Farrell et Manos Antonakakis. Un autre bon article sur cette question est celui de Frank Denis.
Voyons maintenant cette option ECS en action. Elle est par exemple utilisée par Google dont le résolveur public ajoute cette option avant de l'envoyer aux serveurs faisant autorité. Mais on trouve une liste d'utilisateurs plus détaillée sur le site de promotion de la technologie.
Parmi les logiciels libres qui la mettent en œuvre, on note la
bibliothèque getdns. Ou
bien le programme dig livré avec
BIND. Voici un exemple avec la nouvelle
option +subnet
de dig (prise sur un BIND
9.11, l'option était déjà en 9.10) :
% dig +subnet=8.189.152.0/25 @ns-1568.awsdns-04.co.uk A www.amazon.com ... ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ; CLIENT-SUBNET: 8.189.152.0/25/0 ... ;; ANSWER SECTION: www.amazon.com. 60 IN A 54.239.25.192 ...
Et ce que voit le serveur faisant autorité ? On peut le savoir
en faisant tourner tcpdump sur un serveur
faisant autorité qu'on contrôle, mais il y a plus simple, utiliser
un domaine dont les serveurs faisant autorité renverront
l'information ECS qu'ils ont reçu. J'en connais trois, qui
répondent aux requêtes DNS de type TXT
:
_country.pool.ntp.org
,whoami.fastly.net
et
whoami6.fastly.net
,ecs.dyn.bortzmeyer.fr
(qui
utilise le logiciel Drink).Voici un exemple :
% dig ecs.dyn.bortzmeyer.fr TXT ... ;; ANSWER SECTION: ecs.dyn.bortzmeyer.fr. 0 IN TXT "78.196.62.0/24" ;; Query time: 15 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: lun. juin 13 14:08:23 CEST 2022
Un service analogue, edns-client-sub.net
renvoie sous
forme d'un objet JSON les options ECS reçues, ainsi que la
géolocalisation. Ici, mon résolveur n'envoie pas ECS :
% dig +short -t txt edns-client-sub.net "{'ecs':'False','ts':'1447875683.94','recursive':{'cc':'FR','srcip':'XX.YY.152.187','sport':'37512'}}"
Mais Google, lui, le fait (et heureusement, sinon j'aurais été géolocalisé en Belgique, où se trouve le serveur de Google utilisé) :
% dig @8.8.8.8 +short -t txt edns-client-sub.net "{'ecs_payload':{'family':'1','optcode':'0x08','cc':'FR','ip':'XX.YY.152.0','mask':'24','scope':'0'}, 'ecs':'True','ts':'1447875689.25','recursive':{'cc':'BE','srcip':'74.125.47.152','sport':'41735'}}"
Mais ce service ne semble plus fonctionner, en juin 2022.
Enfin, voici un exemple de code Python qui coupe ECS chez le résolveur, pour protéger la vie privée de l'utilisateur. Il utilise la bibliothèque dnspython :
opt = dns.edns.ECSOption(address='', srclen=0) # Disable ECS (RFC 7871, section 7.1.2) options = [opt] message = dns.message.make_query(qname, dns.rdatatype.from_text(qtype), use_edns=True, options=options)
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : Z. Hu, L. Zhu, J. Heidemann
(USC/Information Sciences Institute), A. Mankin, D. Wessels (Verisign
Labs), P. Hoffman (ICANN)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 18 mai 2016
Traditionnellement, les requêtes DNS voyageaient sur le réseau en clair, visibles par tous. Ce n'est évidemment plus acceptable, notamment depuis les révélations de Snowden, et ce RFC normalise donc un mécanisme, DoT (DNS over TLS) qui permet de chiffrer les requêtes DNS pour en assurer la confidentialité vis-à-vis d'un éventuel surveillant.
Le chiffrement est le deuxième pilier de la protection des données, après la minimisation des données (qui, pour le DNS, est spécifiée dans le RFC 9156). Ce chiffrement est motivé notamment par le développement de la surveillance de masse (RFC 7258), par le souci de protéger la vie privée (RFC 6973) et par la prise de conscience des risques spécifiques au DNS (RFC 7626).
Il y avait plusieurs choix possibles pour le groupe de travail DPRIVE qui a produit ce RFC. Il pouvait utiliser une technique extérieure à l'IETF comme DNSCrypt. Il pouvait s'appuyer sur un protocole existant comme IPsec ou TLS. Et il pouvait développer un nouveau protocole (plusieurs propositions avaient été faites en ce sens). Finalement, le choix s'est porté sur un protocole facile à déployer, bien connu, et éprouvé, TLS. D'où le surnom de DoT (DNS over TLS) pour ce protocole. Pour résumer techniquement ce RFC (section 1) : on met les requêtes DNS sur un canal TLS lui-même évidemment transporté sur TCP. (Le groupe DPRIVE travaille également sur une future solution utilisant DTLS et donc UDP.) Outre la confidentialité, TLS permet de protéger les données contre une modification en cours de route.
Notons au passage que DNSSEC ne résout pas ces problèmes : son but est d'authentifier les réponses, pas de protéger contre l'espionnage.
Il y a deux liens à protéger dans une requête DNS, celui entre la machine de l'utilisateur et le résolveur, et celui entre le résolveur et les serveurs faisant autorité. La charte du groupe DPRIVE précisait qu'il fallait d'abord s'attaquer au premier problème, plus facile (une machine ne parle qu'à peu de résolveurs, et elle a une relation avec eux, alors qu'un résolveur parle à beaucoup de serveurs faisant autorité, qu'il ne connait pas.)
La section 3 décrit la gestion des connexions TLS. TLS tourne sur TCP (un de ses copains, DTLS, tourne sur UDP), et il faut donc utiliser ce protocole (notez que l'évolution récente du DNS fait de plus en plus de place à TCP, cf. RFC 7766). DNS-sur-TLS tourne sur un port fixe, le port 853 (les premières versions de ce protocole utilisaient un protocole de négociation de TLS, comme pour SMTP mais, trop compliqué et trop dangereux, il a été abandonné). Le serveur DNS-sur-TLS écoute donc sur le port 853, le client se connecte à ce port, et démarre tout de suite une session TLS (RFC 5246). Ensuite, il y fait circuler le DNS, encodé comme sur TCP (le message DNS précédé de deux octets indiquant sa taille, cf. RFC 1035, section 4.2.2). Comme pour tout usage de DNS sur TCP (RFC 7766), le client et le serveur ne doivent évidemment pas couper la connexion après une seule requête. S'ils le faisaient, les performances seraient catastrophiques, vu le temps qu'il faut pour établir la connexion TCP et la session TLS. Au contraire, la session doit être réutilisée (section 3.4) pour les requêtes ultérieures (et le RFC demande aussi qu'un serveur traite les requêtes en parallèle, pas séquentiellement dans leur ordre d'arrivée, section 3.3.) Un autre moyen de gagner du temps lors de l'établissement d'une nouvelle connexion TCP, moyen recommandé par notre RFC, est d'utiliser TCP Fast Open (RFC 7413).
Notez bien la règle : jamais de contenu chiffré sur le port 53, jamais de contenu en clair sur le port 853. Si le serveur ne répond pas aux requêtes sur le port 853, cela peut être parce qu'une affreuse middlebox bloque tout le trafic vers le port 853, ou tout simplement parce que ce résolveur ne gère pas encore DNS sur TLS. Le client doit alors décider, selon sa politique de sécurité, s'il se rabat sur du trafic DNS en clair ou bien s'il renonce à communiquer. Le RFC recommande que le client se souvienne des serveurs qui répondent sur le port 853, pour détecter un filtrage récemment apparu.
À noter aussi que je n'ai pas parlé encore d'authentification du serveur. Comment être sûr qu'on parle bien au serveur à qui on veut parler et pas au terrible Homme du Milieu ? Pour l'instant, gardez la question de côté, on y reviendra.
Dit comme cela, c'est peut-être un peu compliqué, mais l'un des gros avantages du choix de TLS est qu'il existe déjà des bibliothèques toutes faites pour ce protocole. Ajouter TLS à un client ou un serveur existant est donc relativement simple. (Plus simple que la gestion du RFC 7766, qui est un pré-requis pour DNS-sur-TLS.)
Revenons à l'authentification. A priori, elle est indispensable. Si on n'authentifie pas, on risque d'envoyer ses requêtes DNS à un serveur qui n'est pas le bon, et, dans ce cas, le chiffrement n'aura servi à rien. Pour se faire passer pour le bon serveur DNS, les attaquants actifs ont bien des moyens à leur disposition, comme d'injecter des fausses routes, comme en Turquie. Un chiffrement sans authentification ne protégerait que contre des attaquants strictement passifs.
Oui, mais l'authentification, c'est difficile. Il y a plein de pièges, de problèmes possibles, et d'argent à dépenser (par exemple pour acheter un certificat). Imposer dès le début une authentification stricte dans tous les cas aurait tué le projet dans l'œuf. Le choix a donc été de prévoir un certain nombre de profils d'authentification, que le client choisit, en fonction du degré de sécurité souhaité. (Le serveur, lui, n'authentifie pas le client, en tout cas aucun mécanisme n'est prévu pour cela.) Notre RFC propose deux profils d'authentification (section 4), et d'autres ont décrits par la suite dans le RFC 8310.
Le premier profil est celui « opportuniste » (opportunistic privacy). Le client DNS qui utilise ce profil va tenter de chiffrer, il peut même essayer d'authentifier mais, si cela échoue, il continue quand même à envoyer des requêtes DNS, se disant qu'il est au moins protégé contre les attaques passives.
Le second profil est celui de l'« épinglage de clé »
(out-of-band key-pinned »). La clé publique (SPKI
pour Subject Public Key Info) du
serveur DNS est connue du client (par un mécanisme non spécifié dans
ce RFC), et il ne se connecte à un serveur
DNS-sur-TLS que s'il utilise une des clés correspondant à son
adresse. C'est un mécanisme analogue à l'épinglage
HTTP du RFC 7469. Une
syntaxe possible, pour un /etc/resolv.conf
sur
Unix serait, par exemple (l'annexe A propose
une autre syntaxe) :
domain example.net nameserver 2001:db8:90e:241a::1 NjAwZGI5YTVhMzBiY2EzOWY1OTY5YzM0ZGYzMTllYTVkNmYxNjAwYjJmNzZhOGFhYTNhMDEyMzU4MTIwNjNkMwo=
Où le dernier champ est le condensat de la clé publique.
Au passage, si vous voulez trouver le condensat de votre clé, vous
pouvez le faire avec gnutls-cli
(cela dépend de
comment est fait l'échange de clés) ou bien, si le certificat est dans
le fichier tmp.pem
, avec cette commande utilisant
OpenSSL :
openssl x509 -pubkey -in tmp.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
Ce mécanisme est sûr, empêchant toute attaque de l'Homme du Milieu. Il est peut-être même trop sûr, par exemple pour les réseaux qui utilisent ces horribles portails captifs qui font des attaques de l'Homme du Milieu pour vous rediriger vers le portail. Il peut donc être préférable de ne pas activer ce profil avant de s'être authentifié auprès du portail. (dnssec-trigger utilise un mécanisme analogue.)
J'ai déjà parlé des performances au moment de l'établissement de la connexion, et des problèmes de latence qui peuvent survenir en raison de l'utilisation de TCP et de TLS. La section 5 revient sur ces histoires (il est également recommandé de lire le rapport « T-DNS: Connection-Oriented DNS to Improve Privacy and Security »). Évidemment, une connexion TCP plus une requête DNS, c'est plus coûteux qu'une requête DNS tout court. La requête et la réponse DNS nécessitent deux voyages entre client et serveur, l'etablissement de la connexion TCP en nécessite trois à lui seul, et TLS deux de plus. On pourrait en déduire que DNS-sur-TLS-sur-TCP aura une latence plus élevée de 250 %. On peut réduire ce coût avec des trucs TCP qui réduisent le temps d'établissement de la connexion, comme le TCP Fast Open du RFC 7413 et avec des trucs TLS comme la reprise de session du RFC 5077. Mais, de toute façon, ce calcul n'est vrai que si on établit une connexion TCP par requête DNS, ce qui n'est pas conseillé, la bonne méthode étant au contraire, dans l'esprit du RFC 7766, de réutiliser les connexions.
D'autre part, TCP nécessite de stocker un état dans le serveur. Pour éviter que beaucoup de clients n'écroulent celui-ci, il faut donc ajuster les délais d'inactivité, pour couper les connexions TCP inutilisées.
La section 7 de notre RFC intéressera les ingénieurs qui se
demandent pourquoi les choses sont comme elles sont et pourquoi un
autre choix n'a pas été fait. Elle est consacrée à l'évolution de la
solution de chiffrement du DNS, au sein du groupe de travail
DPRIVE. Comme indiqué plus haut, le premier projet prévoyait de tout
faire passer sur le port 53, avec un passage en TLS à la demande du
client, lorsqu'il envoyait une requête DNS « bidon » avec un nouveau
bit EDNS, TO
(TLS OK), mis à un, et avec le QNAME
(Query NAME) STARTTLS
(reprenant un mot-clé utilisé par SMTP, dans
le RFC 3207).
Cette méthode avait des avantages : elle permettait par exemple à un serveur d'accepter TLS quand il n'était pas trop chargé, et de le refuser autrement. Et, réutilisant le port existant, elle ne nécessitait pas de changer les ACL sur les pare-feux. Mais elle avait aussi des inconvénients : les affreuses middleboxes ont une longue habitude d'interférence avec EDNS et il n'était pas du tout sûr qu'elles laissent passer le bit TO. Et puis, même si le RFC ne le mentionne pas, il y avait un risque qu'une middlebox trop zélée ne fasse du DPI sur le port 53, s'aperçoive que ce qui passe n'est pas du DNS, et coupe la communication. Mais le principal problème de cette approche était qu'elle rendait les attaques par repli triviales. Un attaquant actif n'avait qu'à supprimer le bit TO et le client n'avait alors plus aucun moyen de savoir si l'absence de TLS était due à un serveur trop ancien, à une middlebox boguée... ou bien à une attaque par repli.
Une proposition alternative amusante avait été de mêler le trafic chiffré et non chiffré sur le port 53 sans signalisation : la structure de l'en-tête TLS est telle qu'une machine interprétant le TLS comme étant du DNS en clair aurait vu une réponse DNS (bit QR à 1) et il n'y aurait donc pas eu de confusion avec le trafic DNS en clair. Astucieux mais évidemment très fragile.
La section 8 de notre RFC synthétise les questions de sécurité. D'abord, TLS n'est évidemment pas une formule magique. Il y a eu plein d'attaques contre TLS (par exemple pour forcer un repli vers des algorithmes de chiffrement faibles), ou contre ses mises en œuvre (on pense évidemment tout de suite à OpenSSL). Pour éviter cela, outre le respect des bonnes pratiques TLS (RFC 7525), le client prudent tâchera de se souvenir quels serveurs acceptaient DNS-sur-TLS. Si un serveur qui l'acceptait ne répond tout à coup plus sur le port 853, c'est peut-être qu'un attaquant tente de forcer un repli sur le port 53, en clair. Le client prudent peut ainsi détecter une attaque possible. Si c'est un nouveau serveur, que le client ne connait pas, la marche à suivre dépend de la politique du client (sécurisé ou laxiste).
Quant aux attaques non-TLS (comme le blocage du port 853 mentionné ci-dessus), c'est également au client, en fonction de son profil de sécurité, de décider ce qu'il va faire (renoncer à communiquer, essayer un mécanisme de résolution alternatif, s'en foutre et tout passer en clair, etc).
Revenons à TLS pour noter que ce protocole ne fait pas d'effort pour dissimuler la taille des paquets. Un attaquant passif peut donc, en observant cette taille, et d'autres informations comme le temps écoulé entre deux paquets, en déduire certaines informations, malgré le chiffrement. L'option de remplissage du RFC 7830 permet de remplir les paquets avec des données bidons, afin de rendre cette analyse plus difficile.
Pour un bilan d'étape du projet « DNS et vie privée » à l'IETF, vous pouvez regarder mon exposé State of the "DNS privacy" project: running code à l'OARC.
Question mises en œuvre de ce RFC, où en est-on ? Aujourd'hui, le résolveur Unbound a le code nécessaire depuis longtemps (depuis la version 1.4.14). On peut génerer les clés nécessaires avec OpenSSL ainsi :
openssl req -x509 -newkey rsa:4096 \ -keyout privatekeyfile.key -out publiccertfile.pem \ -days 1000 -nodes
et configurer le serveur ainsi :
server: interface: 2001:db8:1::dead:beef@853 ssl-service-key: "/etc/unbound/privatekeyfile.key" ssl-service-pem: "/etc/unbound/publiccertfile.pem" ssl-port: 853
Unbound va alors activer DNS sur TLS au démarrage et annoncer fièrement « setup TCP for SSL [sic] service ». Les clients pourront alors l'interroger en DNS sur TLS.
Bon, mais quel client utiliser ? Dans la bibliothèque getdns, le logiciel d'exemple
getdns_query
sait faire du DNS sur TLS :
% ./getdns_query @2001:db8:1::dead:beef -s -a -A -l L www.bortzmeyer.org ... Response code was: GOOD. Status was: At least one response was returned
(C'est l'option -l L
qui lui indique de faire du TLS.)
Si on capture le trafic entre getdns_query
et Unbound, on peut afficher le résultat avec
tshark :
% tshark -n -d tcp.port==853,ssl -r /tmp/dnstls.pcap 4 0.002996 2001:db8:1::63a:671 -> 2001:db8:1::dead:beef SSL Client Hello 6 0.594206 2001:db8:1::dead:beef -> 2001:db8:1::63a:671 TLSv1.2 Server Hello, Certificate, Server Key Exchange, Server Hello Done 8 0.734094 2001:db8:1::63a:671 -> 2001:db8:1::dead:beef TLSv1.2 Client Key Exchange 16 0.751614 2001:db8:1::dead:beef -> 2001:db8:1::63a:671 TLSv1.2 Application Data 17 0.759223 2001:db8:1::63a:671 -> 2001:db8:1::dead:beef TLSv1.2 Application Data
On voit un trafic TLS classique, chiffré. Notez que tshark, par défaut, ne sait pas que c'est du TLS sur le
port 853 (cela sera fait lors de la prochaine version majeure). On lui indique donc explicitement (-d
tcp.port==853,ssl
).
Et si j'ai la flemme d'installer un Unbound configuré pour TLS,
est-ce que je peux quand même tester un client DNS-sur-TLS ? Oui, si
les serveurs de test publics listés en
veulent bien répondre.https://portal.sinodun.com/wiki/display/TDNS/DNS-over-TLS+test+servers
Question client, vous avez aussi le démon Stubby. Vous le lancez en indiquant le résolveur à qui il va tout relayer en DNS-sur-TLS :
% sudo stubby @145.100.185.16 -L
Et vous pouvez alors l'utiliser comme résolveur (il écoute par
défaut sur 127.0.0.1
.)
Et vous pouvez aussi utiliser Unbound comme client ! Par rapport à Stubby, il a l'avantage d'être un vrai résolveur, validant et avec un cache, et l'inconvénient de ne pas savoir authentifier le résolveur auquel il va parler. Pour configurer Unbound en client DNS-sur-TLS (et non plus en serveur comme dans l'exemple précédent) :
server: ... ssl-upstream: yes forward-zone: name: "." forward-addr: 2001:4b98:dc2:43:216:3eff:fea9:41a@853 forward-first: no
Si vous préférez développer en Go, l'excellente bibliothèque GoDNS gère DNS sur TLS (depuis janvier 2016) et vous permet de faire vos propres programmes. Par exemple, ce code Go :
c := new(dns.Client) c.Net = "tcp-tls" if *insecure { c.TLSConfig = new(tls.Config) c.TLSConfig.InsecureSkipVerify = true } in, rtt, err := c.Exchange(m, net.JoinHostPort(myResolver, "853"))
va ouvrir une connexion avec le serveur
myResolver
, sur le port 853, et utiliser TLS. Par
défaut, la bibliothèque TLS de Go vérifie le certificat, et que le nom
(ou l'adresse IP) dans le certificat correspond bien (ce qui est la
bonne approche). Mais cela peut être embêtant si on n'a pas acheté de
certificat. D'où l'option (dangereuse !) pour
débrayer la vérification (les trois lignes qui commencent par
if *insecure
). Voici un exemple d'utilisation (au
fait, le programme est en dns-tls.go
,
-k
active l'option dangereuse) :
% ./dns-tls my-resolver internautique.fr Error in query: x509: certificate signed by unknown authority % ./dns-tls -k my-resolver internautique.fr (time 43051 µs) 2 keys. TC=false
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : R. Penno (Cisco), S. Perreault (Jive Communications), M. Boucadair (Orange), S. Sivakumar (Cisco), K. Naito (NTT)
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 29 avril 2016
Le mécanisme de traduction d'adresses IPv4 connu sous le nom de NAT (et qui devrait plutôt être appelé NAPT pour Network Address and Port Translation, car il ne se contente pas de traduire les adresses IP) cause beaucoup de problèmes, car il casse le modèle normal de fonctionnement d'IP, modèle de bout en bout. Pour limiter les problèmes dus à ce mécanisme, plusieurs RFC posent certaines exigences que doivent respecter (en théorie) les routeurs NAT. Ce nouveau document met à jour certaines de ses exigences. Il met donc légèrement à jour les règles des RFC 4787, RFC 5382 et RFC 5508.
Ce RFC de maintenance ne s'applique qu'au « NAT44 » traditionnel, où une adresse IP publique n'est partagée que par les membres d'un même foyer, ou bien les employés d'une même entreprise. Pour le CGN, les exigences sont dans le RFC 6888.
D'abord, le suivi de connexions TCP (section 2 du RFC). Notre RFC formalise rigoureusement la machine à états que doit suivre un routeur NAT (elle est proche de celle du RFC 6146). Le RFC 5382 spécifiait bien des délais pour certains états mais sans décrire précisement la machine complète. Par exemple, l'exigence 5 du RFC 5382 donne un délai pour le temps minimum d'attente avant de considérer une connexion partiellement ouverte, ou fermée, comme abandonnée, mais il n'était pas clair si ces deux cas devaient avoir le même délai. Notre RFC tranche donc : le cas des connexions partiellement ouvertes et celui des connexions fermées sont différents et les délais devraient pouvoir être configurés différemment.
Et les paquets TCP RST
(ReSeT), on en fait quoi ? Notre RFC précise
clairement (suivant ce que faisait déjà le RFC 6146) qu'un paquet RST doit être considéré comme
détruisant la connexion TCP et donc comme mettant fin à la
correspondance dans le routeur NAT (après un délai, pour tenir
compte du fait que le paquet RST
a pu être
reçu par le routeur NAT mais pas par la machine terminale). Attention, il faut d'abord
vérifier que ce paquet RST
correspond bien à
une connexion existante, sinon, on permet des attaques
par déni de service faciles (RFC 5961).
Les RFC 4787 et RFC 5382 précisaient qu'on pouvait utiliser le même couple {adresse IP externe, port externe} pour des connexions allant vers des machines extérieures différentes. Mais ils ne traitaient que du cas où il n'y avait qu'une machine interne qui allait vers ces machines extérieures. Désormais, on précise (section 3 de notre RFC) que cette utilisation est également valables si plusieurs machines internes se connectent. Sans cette règle, il faudrait beaucoup plus de ports externes disponibles, ce qui poserait un problème avec les environnements où le facteur de partage d'adresses est important (cf. RFC 6269).
Est-ce qu'un routeur NAT doit/peut utiliser les mêmes correspondances pour UDP et TCP (section 5 de notre RFC) ? Ce n'est pas précisé dans les RFC 4787 (exigence 1) et RFC 5382 (exigence 1). On fait une connexion TCP sortante, est-ce qu'un paquet UDP sortant va réutiliser la même correspondance ? La règle est désormais explicite : non, il ne faut pas ; par défaut, les correspondances doivent être spécifiques à un protocole (donc, différentes pour UDP et TCP).
Autre piège du NAT, le fait qui peut parfois changer une distribution aléatoire des ports en une distribution prévisible. Cela pose un problème pour certaines méthodes de sécurité qui dépendent du caractères imprévisible (par exemple le RFC 5452). Notre RFC reprend (section 9) une recommandation de la section 4 du RFC 6056 : un routeur NAT ne doit pas choisir les ports de sortie de manière prévisible ou régulière.
Comme d'habitude, la fragmentation est une source d'ennuis (section 10). Notre RFC rappelle donc qu'il faut suivre les règles de la section 5.3.1 du RFC 6864, notamment sur le caractère unique et imprévisible de l'identificateur de fragment.
Le routeur NAT voit parfois passer des paquets en « épingle à
cheveux » (hairpinning). Cela désigne les
paquets (section 12) qui, venus du réseau interne, y retournent,
après être passés par le routeur. Si le réseau interne est
172.17.42.0/24
, et qu'un serveur
HTTP est sur la machine
172.17.41.1
et accessible de l'extérieur en
192.0.2.71
, alors, une machine interne qui
tente d'aller en http://192.0.2.71/
va
envoyer des paquets qui iront au routeur NAT, prendront un
virage en épingle à cheveux et reviendront
dans le réseau interne, vers
172.17.41.1
. Historiquement, pas mal de
routeurs NAT étaient incapables de gérer ce cas. La situation est
désormais meilleure mais il reste des cas limites. Ainsi,
l'exigence 7 du RFC 5508 devait rappeler
que le virage en épingle à cheveux était possible même en
ICMP. Notre RFC insiste sur le respect de
cette règle.
Enfin, la sécurité (section 13). Notre RFC estime que ses exigences renforcées vont améliorer la sécurité. Par exemple, des règles strictes (sections 7 et 11) sur la suppression des correspondances dans la table du routeur NAT évitent qu'un attaquant puisse garder ouvertes des correspondances qui devraient être fermées (et la mémoire récupérée). Les règles sur les ports sources imprévisibles de la section 9 rendront (entre autres) plus difficile le suivi des machines situées derrière un routeur NAT.
Notez enfin qu'il y a des gens qui prétendent avoir un brevet sur certaines de ces recommandations...
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Previdi, C. Filsfils (Cisco
Systems), B. Decraene, S. Litkowski
(Orange), M. Horneffer (Deutsche
Telekom), R. Shakir (Jive
Communications)
Pour information
Réalisé dans le cadre du groupe de travail IETF spring
Première rédaction de cet article le 22 juin 2016
Traditionnellement, la transmission d'un paquet IP au routeur suivant était faite uniquement sur la base de l'adresse de destination, sans tenir compte du reste du paquet. Et la décision est prise par chaque routeur, sur le trajet, en complète indépendance. Or, l'émetteur d'un paquet voudrait souvent décider de la route suivie ou, au minimum, l'influencer. C'est pour cela qu'il existe des mécanismes de routage par la source (source routing). Leurs défauts et leurs limites ont mené à la recherche d'une meilleure solution, dite SPRING (Source Packet Routing In NetworkinG). Ce RFC est la description du problème.
Notez que le terme « source » a, pour SPRING, un sens plus large que lorsqu'on parle habituellement de source routing. Dans ce dernier cas, la source était uniquement l'émetteur original. Pour SPRING, la source est l'endroit où on définit la politique de routage ultérieur, elle peut se situer au milieu du trajet.
Avant SPRING, il y avait plusieurs solutions permettant à la source de décider du routage mais aucune n'a été largement déployée (à part MPLS). C'est dû en partie à leur manque de souplesse, en partie à des problèmes de sécurité.
La future solution SPRING doit être un meilleur système (section 1 du RFC), et déployable de manière incréméntale (il ne serait évidemment pas réaliste de devoir changer tout l'Internet). En outre, l'état doit être maintenu dans le paquet lui-même, pas dans les routeurs intermédiaires. L'expérience de l'Internet a en effet largement montré que pour faire marcher un grand réseau complexe, il ne faut pas maintenir d'état dans les nœuds intermédiaires.
SPRING devra être assez général marcher avec plusieurs mécanismes de transmission des paquets (dataplanes, cf. section 2). Les principaux visés sont MPLS et IPv6 avec un nouvel en-tête de routage (cf. RFC 2460, section 4.4).
La section 3 présente plusieurs scénarios d'usage, pour montrer pourquoi un système tel que SPRING est utile. Il y a par exemple la création de tunnels pour faire des VPN (RFC 4364).
Il y a aussi le reroutage rapide de paquets (FRR, Fast ReRoute), et bien sûr l'ingéniérie de trafic. Pour ce dernier scénario, notre RFC demande que la future solution SPRING permette des options strictes (le paquet suit exactement le chemin spécifié) ou laxistes (le paquet suit à peu près le chemin spécifié), puisse fonctionner en centralisé (SDN) ou en décentralisé, etc.
Une des raisons du peu de déploiement des solutions de routage par la source est évidemment la sécurité (section 4 du RFC). SPRING met le chemin désiré dans le paquet (pour éviter de garder un état dans le réseau). Or, si on suit aveuglément les desiderata de chaque paquet, on ouvre la voie à des tas d'attaques. Par exemple, un paquet spécifie un détour considérable par un autre pays, et cela occupe pour rien les liaisons internationales. Un paquet spécifie un trajet qui boucle et les routeurs qui lui obéiraient feraient une attaque par déni de service contre eux-mêmes.
Le RFC impose donc que SPRING fournisse un mécanisme de « domaines de confiance » avec des frontières bien claires. Si un paquet vient d'un domaine de confiance, on lui obéit. S'il vient de n'importe où sur l'Internet, on ignore ses demandes (ou bien on vire ces options de routage par la source lorsque le paquet change de domaine).
La réalisation concrète de SPRING sur un système de transmission donné (comme MPLS ou IPv6) doit également documenter les risques spécifiques à ce dataplane. Par exemple, MPLS est en général utilisé uniquement à l'intérieur d'un domaine contrôlé et connu (le réseau d'un opérateur) alors qu'IPv6 est de bout en bout donc pose davantage de risques (mais il dispose de possibilités supplémentaires, comme la signature cryptographique des en-têtes).
Il faut maintenant attendre les RFC décrivant les solutions, ils sont en cours de développement dans le groupe SPRING.
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : J. Scudder (Juniper
Networks), R. Fernando
(Cisco), S. Stuart (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 28 juin 2016
Ce nouveau protocole BMP
(BGP Monitoring
Protocol) va faciliter le travail des administrateurs
réseaux qui font du BGP. Il permet d'obtenir sous une forme
structurée les tables BGP. Avant, la solution la plus répandue
était d'utiliser l'interface en ligne de
commande du routeur (show ip bgp
routes
sur un Cisco), et d'analyser le résultat depuis
son programme, une méthode qui est très fragile, le format de
sortie ayant été conçu pour des humains et pas pour des
programmes.
Les tables convoitées sont bien sûr la RIB mais aussi des informations comme les mises à jour de routes reçues. BMP donne accès à une table BGP nommée Adj-RIB-In, « Adjacent [peers] Routing Information Base - Incoming », définie dans le RFC 4271, section 1.1. Elle stocke les informations brutes (avant les décisions par le routeur) transmises par les pairs BGP.
BMP fonctionne (section 3) en établissant une connexion TCP avec le routeur convoité. Celui-ci envoie ensuite l'information qu'il veut. Il n'y a pas de négociation ou de discussion au début. Dès que la connexion est établie, le routeur transmet. Il envoie d'abord des messages Peer Up pour chacun de ses pairs, puis des messages Route Monitoring pour toute sa base de routes (la section 5 les décrit plus en détails). Une fois que c'est fait, le routeur transmet des messages indiquant les changements : Route Monitoring en cas d'annonce ou de retrait d'une route, Peer Up ou Peer Down s'il y a des changements chez les pairs. Autres messages possibles : Stats Report pour envoyer des statistiques globales (voir les sections 4.8 et 7), Initiation et Termination pour les débuts et fins de sessions, Route Mirroring pour envoyer verbatim les annonces BGP reçues (c'est une vision de plus bas niveau que Route Monitoring et cela permet, par exemple, d'analyser des annonces BGP syntaxiquement incorrectes, cf. section 6).
Le client BMP ne transmet jamais de message au serveur (au routeur), à tel point que le routeur peut parfaitement fermer la moitié de la connexion TCP, ou mettre sa fenêtre d'envoi à zéro (ou encore, jeter tous les messages qui seraient envoyés). Toute la configuration est dans le routeur.
Le format des messages est décrit en section 4. C'est du classique. On trouve dans le message un numéro de version (actuellement 1), la longueur du message, le type du message (la liste des types est indiquée plus haut) représentée par un entier (0 pour Route Monitoring, 1 pour Stats Report (ou Statistics Report), etc), puis les données. À noter que le type arrive après la longueur, alors que c'est en général le contraire (encodage TLV).
Pour la plupart des messages BMP, il y aura un second en-tête, rassemblant les informations sur le pair (son adresse IP, son AS, etc).
Les différents paramètres numériques sont désormais stockés dans un registre IANA.
Quelques petits mots sur la sécurité pour finir. Pour économiser ses ressources, le routeur peut évidemment (section 3.2) restreindre l'ensemble des adresses IP autorisées à se connecter en BMP à lui, tout comme il peut limiter le nombre de sessions BMP (par exemple, une au maximum par adresse IP, cinq au total). Il peut aussi y avoir des questions de confidentialité (section 11). Bien sûr, la liste des routes dans la DFZ est publique, mais ce n'est pas forcément le cas des peerings privés ou de VPN utilisant BGP comme ceux du RFC 4364. Donc, attention à bien restreindre l'accès.
BMP est en cours d'élaboration depuis pas mal de temps déjà. Résultat, des mises en œuvre ont eu le temps d'apparaitre. Wireshark sait analyser le BMP. Et il existe deux récepteurs (clients) libres, BMPreceiver et OpenBMP. Côté serveur (routeur), Cisco et Juniper savent envoyer du BMP.
Date de publication du RFC : Juin 2016
Auteur(s) du RFC : G. Lozano (ICANN)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF eppext
Première rédaction de cet article le 28 juin 2016
Les registres de noms de domaine ont parfois des règles d'enregistrement spéciales, pendant une période limitée, lorsqu'on ouvre un nouveau TLD, ou si on change radicalement ses règles d'enregistrement. Ces règles spéciales pour les périodes de « lever de soleil » (sunrise, lorsque le nouveau TLD est créé) servent en général à favoriser les détenteurs de marques ou autres titres de propriété intellectuelle. L'idée est que, pendant le lever de soleil, seuls ces détenteurs aient le privilège d'enregistrer un nom, les autres attendront. Pour que le registre puisse facilement vérifier la possession d'une marque déposée, il faut un format standard pour les décrire, et c'est ce que contient ce RFC. Il a été écrit par un employé de l'ICANN car il vise surtout un service de l'ICANN, la TMCH (Trade Mark Clearing House).
La TMCH est un registre de marques créé par l'ICANN (voir sa
description
officielle). Il a
suscité d'innombrables débats (par exemple, de quel droit l'ICANN crée un
registre mondial faisant autorité, excluant les marques qui n'ont
pas voulu passer par ce processus ?) mais ce RFC ne concerne que la
partie technique, le format de description de ces marques. Il
s'applique a priori aux TLD ICANN comme
.pizza
ou .maif
mais les
autres sont libres de s'en servir également. Comme les objets
décrits dans ce RFC peuvent être signés, il faut avoir une
PKI. Dans le cas des TLD ICANN, elle est
décrite dans le document officiel cité plus haut. Les objets
eux-mêmes sont décrits en XML, pour pouvoir
être utilisés dans le protocole EPP (RFC 5730).
Les objets sont dans les espaces de noms
urn:ietf:params:xml:ns:mark-1.0
(abrégé en
mark:
dans ce RFC) et
urn:ietf:params:xml:ns:signedMark-1.0
(abrégé
en smd:
dans ce RFC).
Les objets XML décrivant les marques incluent des informations
sur les personnes ou entités qui gèrent les marques. Il y a ainsi
des <mark:holder>
et des
<mark:contact>
, qui comprennent des
éléments classiques : nom, adresse postale (qui comprend elle-même
ville, pays...), adresse de courrier
électronique, etc.
Les marques sont décrites par un élément
<mark:mark>
. Celui-ci contient le nom
de la marque, des
références au registre initial (par exemple, en France,
l'INPI), le contact et le titulaire
(décrits au paragraphe précédent) et d'autres informations utiles
aux juristes (comme les biens et services couverts par cette
marque, puisque les marques, contrairement aux noms de domaine,
sont normalement spécifiques).
Les objets décrivant une marque peuvent être signés, grâce à XML Signature. Voici un exemple (très simplifié, voir la section 2.3 du RFC pour le XML complet) d'une marque avec sa signature :
<?xml version="1.0" encoding="UTF-8"?> <smd:signedMark xmlns:smd="urn:ietf:params:xml:ns:signedMark-1.0" id="smd1"> <smd:issuerInfo issuerID="65535"> <smd:org>ICANN TMCH TESTING TMV</smd:org> <smd:email>notavailable@example.com</smd:email> ... </smd:issuerInfo> <mark:mark xmlns:mark="urn:ietf:params:xml:ns:mark-1.0"> <mark:trademark> <mark:id>00052013734689731373468973-65535</mark:id> <mark:markName>Test & Validate</mark:markName> <mark:holder entitlement="owner"> <mark:org>Ag corporation</mark:org> ... <mark:jurisdiction>US</mark:jurisdiction> <mark:class>15</mark:class> <mark:label>testandvalidate</mark:label> ... <mark:regNum>1234</mark:regNum> <mark:regDate>2012-12-31T23:00:00.000Z</mark:regDate> </mark:trademark> </mark:mark> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> ... <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> ... <SignatureValue> jMu4PfyQGiJBF0GWSEPFCJjmywCEqR2h4LD+ge6XQ+JnmKFFCuCZS/3SLKAx0L1w ... </Signature> </smd:signedMark>
L'élement XML peut aussi être intégralement encodé en
Base64 (RFC 4648), et
ça sera alors un <smd:encodedSignedMark>
.
La syntaxe exacte est spécifiée dans la section 3 du RFC, avec le langage W3C Schema.
Quelles sont les mises en œuvre de ce format ? Le kit de
développement logiciel de Verisign
l'intègre (il est disponible
en ligne), et c'est aussi le cas de Net::DRI (dans
Net::DRI::Protocol::EPP::Extensions::ICANN::MarkSignedMark
,
ouf). Côté serveur, le serveur
EPP de Verisign pour des TLD comme
.com
. D'autres
serveurs EPP peuvent utiliser ce format comme REngin, ou celui d'Uniregistry.
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : C. Huitema (Microsoft), T. Mrugalski
(ISC), S. Krishnan (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 29 mai 2016
Vous vous connectez à un réseau IP, vous obtenez la configuration via un serveur DHCP, mais vous voulez rester relativement anonyme, et vous n'avez pas envie que le serveur, ou que des indiscrets qui écoutent, sachent qui vous êtes ? C'est là que ce RFC est utile en proposant un profil de requête DHCP qui envoie le moins d'informations possibles.
C'est que DHCP, par défaut, est trop bavard. Comme l'expliquent bien les RFC 7819 et RFC 7824, une requête DHCP comporte pas mal de champs et d'options qui peuvent contenir des identificateurs stables, qui permettront au serveur DHCP, ou à des espions qui écoutent le trafic, de reconnaitre une machine. Un exemple d'une telle surveillance est celle effectuée dans les aéroports canadiens mais ce n'est certainement pas la seule. Un des buts de cette surveillance peut être, pour quelqu'un qui peut écouter en plusieurs endroits, de suivre à la trace les utilisateurs en déplacement, en reconnaissant les requêtes spécifiques de leur ordinateur portable ou smartphone. Bien sûr, DHCP n'est pas le seul outil pour faire cela. L'identificateur stable le plus évident est l'adresse MAC, mais c'est aussi le plus connu : les utilisateurs soucieux de leur vie privée prennent souvent des mesures pour la changer de temps en temps. Mais peu de gens pensent aux risques pour la vie privée associés à DHCP. Ceux-ci sont désormais bien établis, et documentés dans les RFC 7819 et RFC 7824.
Mais pourquoi en faire un RFC, une norme ? Après tout, on pourrait se contenter d'attendre que les différents fournisseurs de clients DHCP minimisent les informations envoyées. Le problème est qu'ils risquent de le faire légèrement différemment (certains supprimant une option de la requête que d'autres garderont, par exemple). Cette différence permettra une différenciation des utilisateurs, justement ce qu'on veut éviter (cf. la section 2.4). Au contraire, si tout le monde met en œuvre ce profil standard, tous les clients seront pareils, ce qui protège nettement mieux leur anonymat.
La section 2 de notre RFC détaille certains problèmes concrets. J'ai dit plus haut que l'identificateur le plus évident pour suivre une machine à la trace était l'adresse MAC. En Wi-Fi, n'importe qui peut la voir, même si le réseau utilise le chiffrement, puisqu'elle est dans la partie en clair du paquet. En la corrélant avec d'autres informations qu'on retrouve ailleurs, on peut remonter à l'individu qui utilise la machine en question. Le danger est donc réel.
La contre-mesure évidente est de changer l'adresse MAC, en la remplaçant par une valeur aléatoire, par exemple avec macchanger. Cela a fait d'ailleurs l'objets de tests en grand à la réunion IETF de Honolulu, ainsi que dans d'autres réunions. Il n'y a pas de norme technique décrivant cette « aléatoirisation ». Parmi les choix possibles :
En tout cas, un changement de l'adresse MAC est nécessaire, sinon, le profil DHCP « anonyme » de ce RFC aura une utilité limitée. Mais, inversement, attention à ne pas se contenter de changer un seul identificateur. Si on change d'adresse MAC en gardant tout le reste, la tâche d'un surveillant est trop facile, et il déduira sans problème la nouvelle adresse MAC. Il faut changer l'adresse MAC, l'adresse IP et les identificateurs DHCP en même temps.
Notre RFC mentionne qu'il existe des techniques de plus bas niveau (couche 1) qui peuvent défaire tout le travail de protection de la vie privée. Par exemple, certains récepteurs radio permettent d'identifier des particularités d'un émetteur physique et, en observant le trafic Wi-Fi, on peut ainsi identifier une machine donnée quels que soient ses efforts pour ne pas laisser de traces (cf. « Wireless Device Identification with Radiometric Signatures »). Heureusement, tous les surveillants n'ont pas les moyens de placer ce genre de récepteurs. S'ils doivent se contenter de capter le trafic, sans pouvoir analyser le signal physique, les précautions recommandées plus loin dans ce RFC vont suffire.
Le profil d'« anonymat » décrit dans ce RFC n'est pas explicite. On ne peut pas distinguer les clients DHCP qui appliquent ce profil de ceux qui n'ont simplement pas mis en œuvre les options trop révélatrices. Il y avait eu une discussion à l'IETF sur une mention explicite, un bit dans la requête disant « je veux être anonyme et ne vous étonnez donc pas si je ne publie pas grand'chose ». Cette idée avait été rejetée avec l'idée que proclamer publiquement qu'on veut être anonyme peut être au contraire un excellent moyen de se distinguer, comme de sortir dans la rue avec un masque de Guy Fawkes. Au contraire, le vrai anonymat s'obtient en ne faisant rien de trop extraordinaire.
Enfin, comme toute mesure de sécurité, celles qui préservent la vie privée ont des inconvénients. La plus évidente est que l'« anonymat » va rendre plus difficile la gestion des réseaux. Si l'administrateur réseaux suit les machines sur le réseau local en les identifiant par leurs adresses MAC, il devra s'adapter. D'autre part, il y a un conflit entre la protection de la vie privée, qui requiert des changements fréquents d'adresse MAC, et le bon fonctionnement du réseau, qui demande qu'on limite le trafic DHCP (mais aussi ARP et NDP). Attention donc à ne pas changer d'adresse MAC « trop souvent ».
Autre inconvénient, le changement de l'identificateur DHCP par le client, s'il permet davantage de vie privée, empêchera d'obtenir des paramètres de connexion stables (comme l'adresse IP, cf. RFC 7618) dans le temps. On n'a rien sans rien !
Et la vie privée du serveur DHCP, on en parle ? On ne s'est préoccupé jusqu'à présent que du client. C'est parce que le RFC considère que c'est le client qui est aujourd'hui suivi à la trace, et c'est son cas qui nécessite des solutions urgentes. Pour le serveur, cela peut attendre (par exemple parce qu'un serveur qui veut être discret peut ne répondre qu'aux clients authentifiés au niveau 2).
Bien, assez de préliminaires, voyons maintenant le profil proposé. D'abord, pour IPv4 (section 3). Donc, le client qui veut minimiser la surveillance doit donc :
DHCPDISCOVER
,
mettre les options « identificateur de client » et « paramètres
demandés » mais rien d'autre. (Voir comme contre-exemple cette
bogue
de Tails.)DHCPREQUEST
,
ajouter éventuellement la demande d'une adresse IP précise.L'option « identificateur de client » (Client Identifier, RFC 2132, code 61) est, comme son nom l'indique, dangereuse pour la vie privée. Elle permet un suivi très efficace d'une machine, précisement ce qu'on voudrait empêcher. Ne pas la mettre n'est pas une solution car tous les clients DHCP l'incluent. Ne pas le faire serait se singulariser (voir la remarque sur Guy Fawkes plus haut). Notre RFC demande donc qu'on envoie cette option mais qu'on lui donne comme valeur l'adresse MAC (qui est déjà dans l'en-tête couche 2 du paquet). Cela contredit le RFC 4361, section 6.1, mais ce changement de politique reflète l'accent désormais mis sur la préservation de la vie privée. Si on n'a pas d'adresse MAC (cas de certaines liaisons point à point), on doit tirer au hasard (après avoir lu le RFC 4086 et la section 5 du RFC 7217) un identificateur.
Et l'autre option acceptable, la liste des paramètres demandés (Parameter Request List, RFC 2132, code 55) ? La liste doit être réduite au minimum, et ordonnée au hasard, pour éviter qu'on reconnaisse le type de client DHCP utilisé.
L'adresse MAC est indispensable, on ne peut pas ne pas la mettre dans le paquet, et, donc, il ne sert à rien de l'omettre du champ correspondant dans la requête DHCP, mais il est recommandé de la changer (et que le client DHCP utilise cette adresse dans son paquet, qu'il ne garde surtout pas l'ancienne).
Le champ « adresse IP du client » ne pose guère de problème de vie privée (puisque la même adresse IP figure dans l'en-tête IP du paquet) sauf si le client est nouveau sur ce réseau, l'adresse IP indiquée étant alors celle du précédent réseau. Donc : pensez à effacer l'adresse IP lorsque le matériel signale qu'on vient de changer de réseau. Pour la même raison, le profil anonyme ne comprend pas l'option « adresse IP souhaitée » (RFC 2132, code 50). Elle est certes bien pratique (permettant de conserver son adresse IP) mais très révélatrice.
Parmi les autres options, le nom de la machine (code 12) est très
révélateur. Même si ce n'est pas un FQDN, il
peut être très spécifique
(« pc-de-jean-dupont
»). Il ne doit pas être
utilisé dans ce profil. Si on doit quand même le faire, le nom doit
être choisi aléatoirement. Une méthode possible est de
condenser un secret et l'adresse MAC, puis
prendre la représentation en hexadécimal de six premiers octets
(quelque chose comme echo -n "$SECRET" "$MACADDRESS" |
sha256sum | cut -c 1-12
en shell Unix).
L'option Client FQDN (RFC 4702, code 81) est évidemment également à proscrire. Ou alors, il faut l'« anonymiser » avec la même méthode qu'au paragraphe précédent.
Le RFC 4578 décrit une option UUID, prévue pour PXE, et identifiant de manière unique un client DHCP. Normalement, on n'utilise PXE que dans des environnements contrôlés et sécurisés. Dans un cyber-café inconnu, télécharger son système d'exploitation serait une très mauvaise idée. Il ne faut donc utiliser cette option que dans un réseau que l'on sait sûr.
Enfin, les options indiquant le type de logiciel utilisé (comme Vendor Specific Information, code 43, ou Vendor Class, code 60 sont évidemment à rejeter.
Pour éviter le fingerprinting, le client ne devrait pas ajouter d'autres options, mêmes si celles-ci sont inoffensives du point de vue de la vie privée. En effet, si certains clients mettent telle option, quel que soit son contenu, ils diffusent une information. Et, si on envoie des options DHCP, leur ordre doit être tiré au hasard avant l'envoi, là encore, pour éviter de révéler le type de client utilisé (DHCP permet pas mal de choix, et le choix facilite le fingerprinting). Si on n'a pas de bon générateur de nombres aléatoires, un repli possible est d'envoyer toujours les options dans l'ordre de leur code : ainsi, tous les logiciels (qui sont dans ce cas) feront pareil.
La section 4 du RFC fait la même chose, mais pour IPv6. DHCP v6 a d'autres possibilités (comme l'existence de deux modes, avec ou sans état). Le profil est donc un peu plus compliqué mais bien des conseils sont identiques (par exemple ceux sur les options Client FQDN, sections 3.8 et 4.9), et je ne les répéterai donc pas ici. Dans le mode sans état, les clients configurent l'adresse avec d'autres mécanismes, comme le SLAAC et ne se servent de DHCP que pour récupérer des informations générales. Le choix entre les deux modes dépend d'options publiées dans les Router Advertisement (RFC 4861, section 4.2, les bits M et O).
Parmi les messages spécifiques à DHCP v6,
Confirm
(RFC 8415,
section 16.5) est dangereux, car il contient de
l'information sur le précédent réseau où on s'est connecté. En mode
« anonyme », il ne faut pas l'envoyer, sauf si on est certains qu'on
est toujours sur le même réseau (ce qui est une vérification pas
toujours triviale, le RFC recommande d'utiliser
802.1X).
L'option Client Identifier (code 1) en DHCP v6 contient un identificateur unique, le DUID (DHCP Unique Identifier, RFC 8415, section 11). Elle rend donc le suivi d'un client très facile. Pour empêcher ce suivi, le profil demande d'utiliser le format 3, « adresse MAC », du DUID (RFC 8415, section 11.4), avec une adresses MAC changée comme indiquée plus haut. Dans les cas où cette option n'est pas exigée par le protocole (comme les Information-Request, RFC 8415, section 18.2.6, qui sont sans état), elle ne doit pas être envoyée.
DHCP v6 permet évidemment d'obtenir des adresses IPv6 (mais ce n'est pas le seul moyen, contrairement à ce qui se passe en IPv4). Une option semble intéressante pour la vie privée, la demande d'adresses temporaires (RFC 8415, section 13.2). Mais elle n'est pas si utile que ça : car peu de serveurs la mettent en œuvre (le client ne peut donc pas se reposer dessus), le renouvellement de ces adresses n'est pas spécifié, et le fait que le client doive la demander est déjà une fuite d'informations (« je veux être anonyme »). Elle est donc déconseillée.
Notre RFC met également en garde contre des options qui peuvent être amusantes mais qui sont rares : les utiliser revient, pour le client DHCP, à « sortir du lot ». C'est le cas par exemple de la demande de délégation de préfixe (RFC 8415), que le PC typique n'utilise pas.
Le RFC se termine par quelques considérations opérationnelles (section 5). La plus évidente, et la plus « gênante » est que l'application de ce profil va cache l'identité du client au serveur DHCP. C'est le but. Mais cela peut être ennuyeux. Des fonctions comme la publication de l'adresses du client dans le DNS, ou comme la relative stabilité des adresses IP (redonner la même adresse lorsqu'un client revient) ne seront plus possibles. On n'a rien sans rien.
D'autre part, les clients utilisant ce profil consommeront davantage de ressources. Par exemple, à chaque changement au niveau 2, ils réclameront une nouvelle adresse IP, alors que l'ancienne reste réservée, jusqu'à la fin du bail.
Et certains serveurs DHCP fascistes ne donnent une adresse IP qu'aux clients connus, interdisant ainsi l'anonymat. Pour ces raisons, le RFC recommande aux programmeurs de permettre la configuration du client DHCP, configuration allant jusqu'à permettre de débrayer l'anonymisation.
Ce profil a été mis en œuvre dans un client Microsoft, ce qui a donné lieu à un compte-rendu d'expérience à une réunion IETF.
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : R. Sparks (Oracle)
Pour information
Première rédaction de cet article le 13 avril 2016
Un des gros avantages de travailler à l'IETF est qu'il existe un ensemble d'outils de travail en groupe très perfectionnés, permettant de gérer un grand nombre de documents qui changent tout le temps. Dans la plupart des SDO, ou organisations similaires, on a juste des piles de documents Word (ou, dans les dernières années, Google Docs) inexploitables. Comme le gros du travail IETF est fait sur des listes de diffusion, un des outils les plus cruciaux est le moteur de recherche dans ces listes de diffusion. Mais aucun outil n'est parfait et ce nouveau RFC est une liste de points à améliorer dans l'outil actuel, liste fondée sur l'expérience récente.
Ce
permet notamment
de retrouver un ou plusieurs messages, parmi les centaines de
messages échangés sur les listes IETF chaque jour. Voici un
exemple de recherche de « tcp encryption
eliot » (Eliot = Eliot Lear, auteur entre autres des
RFC 1918, RFC 4192,
RFC 6557...). On y voit la liste des
messages correspondants en haut à droite, à gauche les noms des
listes (en général, des groupes de travail IETF) où les messages
apparaissent, en bas à droite l'URL stable
du message en cours (ce qui permet des références précises
lorsqu'on affirme « Brian Trammel a dit que ») :
https://mailarchive.ietf.org/
L'outil actuel avait eu comme cahier des charges le RFC 6778 et avait été déployé en janvier 2014. Notre nouveau RFC liste les améliorations souhaitées.
Par exemple, lorsqu'on choisit « Group by Thread », la liste résultante est plate, sans hiérarchie. Cela rend difficile de voir où un fil de discussion commence et où il finit :
Notre RFC demande que, dans les améliorations de l'outil, l'affichage montre la hiérarchie.
Autre problème, il n'y a pas actuellement de boutons de navigation (message suivant/précédent par date, ou suivant le fil de discussion), que cela soit dans la liste des messages affichés, ou bien lorsqu'on regarde un seul message. Le RFC demande que ces boutons soient ajoutés.
C'est en lisant ce RFC que j'ai appris qu'on pouvait changer la taille de la fenêtre où s'affiche la liste des messages. Je la croyais fixe, et c'était apparemment le cas de bien des utilisateurs. Le RFC demande donc qu'on rende cette possibilité d'agrandissement plus évidente (personnellement, je n'ai pas trouvé). En prime, la façon dont est faite la troncation aujourd'hui ne semble pas rationnelle. Ici, on voit bien que les sujets sont coupés (et la fin remplacée par des ellipses) sans vraiment de raison.
Le service actuel est difficile à utiliser sur un petit écran, comme celui des phono sapiens puisque les divers éléments de l'interface sont toujours présents. Pour une interface riche, il vaudrait mieux être responsive, ce que demande le RFC (par exemple, on pourrait supprimer le menu des filtres quand l'écran est trop petit).
Par contre, sur des grands écrans, l'interface actuelle est au contraire trop économe et sous-utilise l'écran.
Enfin, notre RFC regrette que l'interface actuelle ne marche guère sans JavaScript. La prochaine version doit évidemment être capable de fonctionner sans JavaScript, quitte à accepter quelques fonctions en moins (comme les filtres appliquées dynamiquement).
Reste à développer, maintenant... Je n'ai pas encore vu d'appel d'offres.
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : J. Halpern, L. Daigle, O. Kolkman (Internet Society), Internet Architecture Board (IAB)
Pour information
Première rédaction de cet article le 29 mai 2016
Les textes sacrés de l'Internet, les RFC, comprennent un certain nombre d'éléments obligatoires, souvent collectivement appelés boilerplates et comprenant, par exemple, les conditions légales d'utilisation du RFC. Ce RFC 7841 écrit par l'IAB les décrit et les précise.
Les éléments utilisés autrefois comme Category: Experimental ne suffisaient pas à transporter toute l'information nécessaire. Depuis la formalisation des voies dans le RFC 4844, les différents circuits de publication des RFC, il était devenu crucial de déterminer facilement de quelle voie venait un RFC. (Les anciens RFC étaient tous marqués comme provenant d'un mystérieux Network Working Group, cf. RFC 3.) Cela avait été fait dans le RFC 5741, que notre RFC 7841 remplace.
Donc, dans sa section 2, notre méta-RFC rappelle que, non seulement tous les RFC ne sont pas des normes (RFC 1796), mais que tous ne sont pas des documents issus de l'IETF, qui n'est qu'une voie parmi d'autres (quoique la plus prolifique). Ainsi, un RFC peut très bien être publié sans que l'IETF n'aie pu donner un avis sur des points comme la sécurité ou le contrôle de congestion, par le biais de procédures comme le IETF Last Call ou l'examen par l'IESG. En termes para-légaux, disons que l'IETF refuse toute responsabilité pour les RFC non-IETF. (À noter que, si tous les RFC ne sont pas des normes IETF, en revanche, toutes les normes IETF sont publiées sous forme d'un RFC.) Si vous tenez à tout connaitre sur les processus de l'IETF, et la publication des RFC, consultez les RFC 2026, RFC 8728, RFC 8729, RFC 5742, RFC 6410 et RFC 7127.
La section 3 liste les éléments qui forment la structure d'un RFC. Leur forme exacte, plus susceptible de changer, figure sur une page Web séparée. Il y a l'en-tête général (section 3.1) qui, pour notre RFC, est :
Internet Architecture Board (IAB) J. Halpern, Ed. Request for Comments: 7841 Obsoletes: 5741 L. Daigle, Ed. Updates: 7322 Category: Informational O. Kolkman, Ed. ISSN: 2070-1721 Internet Architecture Board (IAB) April 2016
indiquant qu'il est issu de la voie IAB, qu'il porte le numéro 7841, qu'il est de la catégorie « Pour information » (les catégories sont décrites dans le RFC 2026), etc. Les autres voies sont IETF, IRTF et « contribution indépendante ».
Après cet en-tête vient un paragraphe (section 3.2) qui décrit clairement la voie par laquelle ce RFC est passé. Par exemple, pour une soumission indépendante, le texte (qui est sujet à évolution, en synchronisation avec la définition des voies) actuel est « This is a contribution to the RFC Series, independently of any other RFC stream. The RFC Editor has chosen to publish this document at its discretion and makes no statement about its value for implementation or deployment. ».
Cet en-tête indique également les relations de ce RFC avec d'autres RFC. Par exemple, notre RFC 7841 indique :
Obsoletes: 5741
car il remplace le RFC 5741, qui n'a désormais plus qu'un un intérêt historique.
Je ne reprends pas ici tous les éléments, qui sont décrits dans cette section 3. Notons simplement le copyright, issu des RFC 5378 et RFC 8179, et l'ISSN des RFC, 2070-1721. Pour le reste du RFC, il faut utiliser le guide stylistique du RFC 7322.
Notre RFC ne décrit que les principes gouvernant ce boilerplate. Les détails, qui sont changeants, sont désormais sur une page Web dédiée à l'IAB. C'est l'un des gros changements depuis le RFC 5741. L'annexe A de notre RFC contient l'état initial de ces textes. Ainsi, un RFC de l'IETF sur le chemin des normes commencera par « This is an Internet Standards Track document. This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). »
Outre ce déplacement du texte effectif depuis le RFC (document rigide et stable) vers une page Web, le principal changement depuis le RFC 5741 est l'allègement de certaines règles de présentation, pour tenir compte du projet de réforme du format de publication des RFC (qui, dans le futur, ne seront plus publiés uniquement sous forme de texte brut).
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : M. Nottingham (Akamai), P. McManus
(Mozilla), J. Reschke (greenbytes)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 15 avril 2016
Une nouveauté dans le monde HTTP : ce RFC décrit un mécanisme permettant d'indiquer des endroits alternatifs où trouver le contenu demandé. Ce n'est pas une classique redirection : l'URI reste le même, on découple simplement l'identificateur (l'URI) et le localisateur (l'endroit où chercher et le protocole à utiliser).
Ce concept est assez nouveau dans le monde
HTTP (section 1 du RFC). En effet, le RFC 7230 tend à mélanger l'identificateur d'une
ressource (http://www.example.com/foo/bar
) et
les moyens d'y accéder (la même ressource peut aussi être en
https://www.example.com/foo/bar
voire sur un
miroir à un URL très
différent). Le but du mécanisme de ce nouveau RFC 7838 est de séparer plus clairement
identificateur et
localisateur.
Quelques exemples pratiques sont donnés dans cette section 1 :
Actuellement, ce genre de choses est fait par des redirections
HTTP explicites (codes 301, 302, 307 ou 308, voir le RFC 7231, section 6.4). L'URL vers lequel on est
redirigé est montré par le navigateur (ce qui n'est clairement pas
une bonne idée dans le cas de redirections temporaires comme
307). Autre façon de faire, un relais, qui se
connecte au serveur effectif, sans le dire du tout au client
HTTP. Les « services alternatifs » de ce RFC 7838
sont situés entre les deux façons : annoncés au client HTTP mais pas mémorisés
et pas montrés à l'utilisateur (l'URI ne
change pas). Le contexte de sécurité n'est
pas modifié (si l'URI commençait par le plan
https://
, le service alternatif devra donc
présenter un certificat valide), le champ
Host:
de la requête HTTP contiendra toujours
le nom original (notez qu'il existe désormais un champ
Alt-Used:
pour indiquer le nom alternatif,
cf. section 5). Normalement, l'utilisateur ne verra donc pas
qu'on utilise un
service alternatif (ceci dit, comme son logiciel client, lui, est
au courant, des options de débogage pourront permettre de
l'afficher, contrairement à ce qui se passe avec un relais).
La solution est en deux parties : des concepts abstraits
(section 2) puis des mécanismes concrets pour les différents
protocoles, dans les sections 3 et 4. Commençons par le cadre
abstrait. Un « service alternatif » existe lorsqu'un serveur
d'origine (concept lui-même défini dans le RFC 6454, section 4) sait que ses ressources sont accessibles avec une
combinaison {protocole, serveur, port} différente. Un tel service
alternatif fait autorité (au sens du RFC 7230, section 9.1), ce n'est pas un simple miroir, ni un
cache. Notez
que la granularité est pour une origine complète (la combinaison
{protocole, serveur, port}) : on ne peut pas faire un service
alternatif qui couvrirait uniquement le chemin /foo
de
l'URI.
Un exemple de service alternatif ? Mettons que l'origine soit {http, www.example.com, 80} et que les mêmes ressources soient accessibles en HTTP 2 à {h2, new.example.com, 81}, alors on peut dire que ce {h2, new.example.com, 81} est un service alternatif de l'origine.
Notez que j'ai appelé « protocole » le premier membre du
tuple. Ce n'est pas le plan
(scheme) dans l'URI (plan que pas mal de gens
appellent à tort protocole). En effet, cette valeur est plus
spécifique que le plan, elle peut inclure des détails techniques
supplémentaires (par exemple, lorsque le plan est
http://
, on peut y accéder avec les
protocoles http
ou h2
,
ce second désignant HTTP 2.) Le protocole, pour les services
alternatifs, est un nom ALPN (RFC 7301 et le registre IANA ALPN).
Le tuple {protocole, serveur, port} peut être accompagné d'une durée de vie, indiquant combien de temps le client HTTP peut garder en mémoire l'information sur le service alternatif.
Au passage, un mot de sécurité : le client doit évidemment être conscient que, si la communication n'est pas sécurisée (par exemple par TLS), il peut être envoyé vers un faux service alternatif (section 9). Si le service d'origine n'a pas TLS mais que le service alternatif l'a, et présente un certificat au nom du service d'origine, c'est bon. Si aucun des deux n'a TLS, le risque d'avoir été trompé est bien plus élevé. Il n'est donc pas forcément prudent d'utiliser les services alternatifs sans TLS.
Notons enfin que les services alternatifs sont optionnels. Le client n'est pas obligé de les utiliser (d'autant plus que les clients HTTP actuels ne gèrent pas ces services et n'utiliseront donc pas les alternatives, tant qu'ils n'ont pas été mis à jour). Le serveur d'origine doit donc rester prêt à assurer les requêtes.
Maintenant, les mécanismes pour signaler ces services
alternatifs. En HTTP 1, en utilise l'en-tête
Alt-Svc:
(section 3, et désormais dans le
registre IANA). La réponse contient,
par exemple :
Alt-Svc: h2="new.example.org:80"
Cela indique que le client devrait plutôt aller voir avec le
protocole h2
(HTTP 2), sur la machine
new.example.org
. Si on ne change que le
protocole et le
port, on pourrait avoir :
Alt-Svc: h2=":8000"
Il peut y avoir plusieurs valeurs, dans l'ordre des préférences décroissantes :
Alt-Svc: h2="alt.example.com:8000", h2=":443"
Par défaut, le service alternatif peut être mémorisé par le
client pendant 24 h. Si on veut changer cette durée, on utilise
le paramètre ma
(Maximum
Age, en secondes) :
Alt-Svc: h2=":443"; ma=3600
Si le serveur veut qu'on oublie tout ce qu'on a mémorisé sur les
services alternatifs, et n'a pas envie d'attendre l'expiration des
caches, il envoie la valeur spéciale
clear
:
Alt-Svc: clear
À part ce paramètre ma
, et un autre
paramètre persist
(qui indique que,
contrairement au comportement par défaut, le client HTTP ne
devrait pas vider cette information de son cache si sa
configuration réseau change), d'autres paramètres sont possibles
dans le futur. Ils devront passer par le procédure « Examen par un
expert » du RFC 5226 et seront mis dans
le registre IANA.
Et si on utilise HTTP 2, où on est en binaire et plus en texte,
et où les en-têtes sont représentés d'une
façon complètement différente ? Dans ce cas, on se sert de trames du
type ALTSVC
(section 4). C'est une extension
au protocole original. La trame
ALTSVC
a le type 0xa (10, dans le registre IANA) et contient un
champ Longueur (de l'origine), l'origine, et le service
alternatif sous une syntaxe identique à celle de la section
précédente.
On l'a vu, le service alternatif fait normalement autorité et doit donc gérer les mêmes ressources. Que se passe-t-il si un serveur maladroit redirige vers une machine qui n'est pas configurée comme service alternatif ? Idéalement, cette machine ne faisant pas autorité doit répondre 421 (RFC 7540, section 9.1.2). Le client doit alors réessayer avec un autre service alternatif, s'il existe, ou bien avec le serveur d'origine. (Aujourd'hui, je crois qu'il est plus fréquent que la machine ne faisant pas autorité renvoie les ressources de sa configuration par défaut.)
Un petit mot d'histoire : ce système des services alternatifs
vient d'une solution spécifique à Chrome qui
se nommait Alternate-Protocol:
. Un bon
article de synthèse sur ces services alternatifs est celui de
l'auteur du RFC.
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Krishnan (Ericsson), M. Kuehlewind (ETH Zurich), B. Briscoe (Simula Research Laboratory), C. Ralli (Telefonica)
Expérimental
Réalisé dans le cadre du groupe de travail IETF conex
Première rédaction de cet article le 15 mai 2016
Le mécanisme ConEx, normalisé dans le RFC 7713, permet d'informer les routeurs situés en aval qu'un flot de données se heurte à la congestion. Il y a plusieurs façons d'indiquer cette congestion, et ce RFC le fait par une option dans l'en-tête Destination Options d'IPv6.
En effet, le mécanisme décrit dans le RFC 7713 est abstrait : il spécifie des concepts, pas comment ils sont représentés sur le câble. Notre RFC 7837, au contraire, est concret : il indique comment mettre l'information ConEx dans des champs du paquet que les équipements réseau, notamment les routeurs, pourront lire. ConEx est actuellement un projet expérimental (et même très expérimental) et il n'est pas sûr qu'il soit déployé avec enthousiasme. En attendant, puisque c'est expérimental, le but est de récolter de l'information et, pour cela, il faut du code qui tourne, avec des paquets concrets (section 1 de notre RFC). Mettre l'information ConEx dans le champ Options d'IPv4 est délicat : ce champ est de taille limitée, et pose souvent des problèmes dans le réseau. L'idée est donc d'utiliser le protocole du futur, IPv6, et ses en-têtes d'extension (RFC 2460, section 4).
La section 3 détaille les choix techniques effectués et leurs raisons. Les sections 3.3 et 4 du RFC 7713 expliquent les contraintes d'encodage concret de ConEx dans les paquets. Ici, les exigences considérées ont été :
Quatre solutions IPv6 avaient été envisagées par le groupe de travail à l'IETF :
L'en-tête d'extension Hop-by-hop aurait été l'option logique puisqu'elle est examinée par chaque routeur, ce qui est bien ce qu'on veut pour ConEx. Elle aurait été conforme aux principes d'IPv6. Mais, dans les routeurs actuels, le traitement de cette option se fait de manière extrêmement lente (elle n'emprunte pas le chemin rapide dans le routeur, mis en œuvre en ASIC ou FPGA), ce qui viole la troisième exigence. Le choix de l'en-tête Destination, qui est normalement de bout en bout et que les intermédiaires ne sont pas censés regarder, est donc surprenant, mais justifié. Il viole un peu la première exigence (si le paquet est encapsulé, le routeur aura du mal à voir cet en-tête). Et, surtout, analyser la chaîne des en-têtes d'extension IPv6 est anormalement compliqué. Mais il n'y avait guère d'autre choix réaliste. En pratique, certains routeurs auront donc besoin d'un changement de leurs règles de traitement des en-têtes d'extension s'ils veulent voir les marques ConEx.
(Sur la survivabilité des en-têtes d'extension IPv6 dans l'Internet, voir l'étude de Mehdi Kouhen en février 2016 et le RFC 7872.)
La section 4 présente le format concret. La nouvelle option Destination se nomme CDO, pour ConEx Destination Option. Elle est mise dans un en-tête d'extension Destination Options (RFC 2460, section 4.6). Comme les autres options Destination, elle est encodée en TLV. Le type de l'option est 0x1E (30, valeur réservée aux expérimentations, non définitive), sa longueur est 1 (un seul octet, et encore, tous les bits ne sont pas utilisés) et sa valeur est composée de quatre bits (RFC 7713, notamment la section 2.1) : X (« je sais faire du ConEx »), L (« des paquets ont été perdus »), E (« de la congestion a été signalée par ECN ») et C (« pas (encore) de congestion, j'accumule des crédits »). Le dernier bit, C, est à utiliser avant qu'on détecte la congestion (RFC 7713, notamment la section 5.5).
Au passage, si vous écrivez des programmes en C qui veulent ajouter des options dans l'en-tête Destination, vous pouvez consulter mon article.
On a dit plus haut que la principale raison pour utiliser l'en-tête Destination et pas le Hop-by-Hop (qui aurait été plus logique), est le souci que les paquets restent sur le fast path des routeurs (le traitement fait par le matériel, par opposition au slow path, confié au processeur généraliste, bien plus lent). Mais le problème est que l'en-tête Destination, n'étant pas prévu pour être lu par les équipements réseau sur le chemin, peut se trouver n'importe où dans la chaîne des en-têtes (alors que l'en-tête Hop-by-hop est forcément au début, cf. RFC 2460, section 4.1). Et l'option CDO pourrait, en théorie, se trouver n'importe où dans l'en-tête Destination. Notre RFC est donc obligé de recommander (section 5) que l'option CDO soit la première dans l'en-tête Destination.
Reste à voir s'il sera effectivement possible de déployer cette option. L'ossification de l'Internet rend tout déploiement de ce type difficile (les en-têtes d'extension sont rares dans les paquets IPv6 actuels).
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : D. Saucez (INRIA), L. Iannone
(Telecom ParisTech), O. Bonaventure (Université
catholique de Louvain)
Pour information
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 30 avril 2016
Le protocole LISP (à ne pas confondre avec le langage de programmation) est un protocole à séparation de l'identificateur et du localisateur. Ces protocoles présentent des défis de sécurité particuliers et ce RFC est donc consacré à une étude détaillée des menaces et risques associés à LISP.
LISP est normalisé dans le RFC 6830. Il peut être utilisé dans un réseau interne ou bien sur l'Internet public et ce RFC étudie sa sécurité dans ce dernier cas, évidemment plus difficile.
Le RFC est en trois parties : la section 2 détaille le modèle de menaces (qui est l'attaquant), la section 3 expose les techniques que peut utiliser l'attaquant, la section 5 décrit les solutions possibles. Il s'agit bien de regarder les attaques génériques contre LISP, pas celles contre une mise en œuvre particulière de LISP, qui peut évidemment avoir ses bogues spécifiques.
Commençons donc par le modèle de menace (section 2). On suppose un attaquant situé quelque part sur l'Internet, éventuellement en plusieurs points de celui-ci. Il peut être sur le chemin des paquets (on path) ou pas (off path). Le premier est évidemment le plus dangereux. S'il est attaquant actif, il peut modifier des paquets et même faire des attaques de l'Homme du Milieu. Si l'attaquant est en dehors du chemin, cela va être plus difficile pour lui. Il ne peut pas modifier les paquets échangés, il peut par contre envoyer des paquets mais, pour que ceux-ci soient acceptés, il faudra qu'ils correspondent à ce qu'attendent les parties légitimes, ce qui fait que l'attaquant devra souvent deviner des informations et compter sur la chance.
Autre façon de classer les attaquants, il y a ceux qui sont internes à un site LISP et ceux qui sont externes. Les attaquants de l'intérieur sont plus dangereux car la machine qu'ils contrôlent (suite à une trahison ou un piratage) est a priori jugée de confiance.
Il faut aussi distinguer les attaquants permanents (live) des attaquants ponctuels (time-shifted). L'attaquant permanent est celui qui reste actif pendant toute la durée de l'attaque. Dès qu'il est neutralisé, l'attaque stoppe. L'attaquant ponctuel peut lancer une attaque, puis se retirer et les effets de l'attaque vont continuer. Ce genre d'attaques est évidemment bien plus dangereux.
L'attaquant peut viser le système de contrôle (control plane) de LISP ou bien son système de transmission des données (data plane). Un exemple typique est le mécanisme de correspondance (mapping) qui permet aux routeurs LISP de trouver le localisateur (le RLOC) en échange de l'identificateur (l'EID). Ce mécanisme de correspondance fait partie du système de contrôle. Si un attaquant veut détourner les paquets, il n'est pas obligé de trouver une faille dans le routage lui-même : s'il arrive à modifier les correspondances, il obtiendra le même résultat. (Comme le ferait une attaque DNS dans l'Internet classique.)
Plusieurs types d'attaques peuvent être faites contre un protocole réseau comme LISP. Il y a les attaques par rejeu, où un attaquant capture des paquets légitimes pour les rejouer intacts plus tard. Ces attaques marchent souvent, même quand les paquets sont protégés par de la cryptographie (l'attaquant n'a pas besoin de modifier les paquets, ni même de les comprendre). Il y a les manipulations de paquets (l'attaquant prend un paquet légitime et le réinjecte). Il y a la suppression complète des paquets.
Plus complexe et plus vicieux, il y a l'usurpation (spoofing). L'attaquant injecte des paquets prétendant venir d'une autre machine. C'est quelque chose qu'on voit souvent sur l'Internet. LISP est une technologie de tunnel et l'usurpation peut donc porter sur deux endroits : l'adresse externe, celle que voient les routeurs IP ordinaires (c'est le RLOC), et l'adresse interne, celle du paquet encapsulé (c'est l'EID). Identifier un usurpateur est bien plus compliqué lorsque des tunnels sont en jeu !
L'attaquant n'est pas forcément un usurpateur. Il peut très bien dire la vérité sur son adresse (rogue attack) par exemple parce qu'il se moque d'être identifié, ou bien parce qu'il est un zombie.
Autre type d'attaque, évidemment, les attaques par déni de service, où l'attaquant ne cherche pas à prendre le contrôle du système, mais à le paralyser (ou à le ralentir).
Parfois, la cible immédiate de l'attaque n'est pas la principale victime : dans les attaques par réflexion, un attaquant utilise un tiers pour renvoyer ses paquets vers la vraie victime. C'est surtout utilisé en combinaison avec l'amplification : lorsque la réponse est plus grosse que la question, un attaquant peut amplifier son trafic. En outre, pour LISP, le système de transmission est certainement bien plus rapide que celui de contrôle et il y a donc en théorie une possibilité d'attaquer le second avec le premier.
Et, bien sûr, il y a les attaques d'espionnage passif, où des grandes oreilles écoutent votre trafic pour vous surveiller, sans eux-mêmes envoyer de paquets. Grâce à Edward Snowden, l'ampleur de ce type d'attaques par les États est désormais bien connu (RFC 7258).
Bon, assez de théorie, comment fait-on avec LISP quand on est un méchant et qu'on veut effectuer une des attaques en question ? Rentrons désormais dans les détails techniques (qui nécessitent de connaitre un peu LISP : relisez les RFC 6830, RFC 7215, RFC 6832, RFC 9301 et RFC 6834). D'abord, le « glanage » (gleaning), la collecte passive d'informations sur les correspondances identificateur->localisateur (RFC 6830, section 6). Il peut être utilisé pour empoisonner le cache des correspondances d'un routeur : le méchant envoie un paquet LISP fabriqué, les routeurs innocents l'observent et enregistrent la correspondance entre l'EID et le RLOC dans leur cache et paf, le méchant a pu détourner le trafic futur. C'est un exemple d'attaque ponctuelle : l'attaquant envoie juste un paquet puis plus rien, mais l'effet persiste pendant toute la durée de vie de l'information dans le cache (quelques secondes, si on suit fidèlement les conseils du RFC 6830, section 6.2).
Autre exemple d'empoisonnement d'un routeur LISP avec de fausses informations, le champ LSB (Locator Status Bits), qui indique l'état (joignable ou pas) des machines situées sur le site de départ du paquet (RFC 6830, section 6.3). En envoyant un paquet usurpé avec un faux LSB, on peut tromper des routeurs innocents. On peut par exemple mettre tous les bits à zéro (qui signifie que le préfixe est injoignable par ce routeur), menant à une attaque par déni de service ou bien les mettre tous à zéro sauf un, menant à une surcharge de cet unique routeur. C'est également une attaque ponctuelle : ses effets se feront sentir même si l'attaquant est neutralisé.
Un point important de LISP est le test de la « joignabilité » (reachability, RFC 6830, section 6.3). LISP vérifie que la machine qui prétend être joignable, et par tel routeur, l'est effectivement. Un des outils pour cela est un numnique envoyé à l'autre machine et qu'elle doit renvoyer. Un attaquant qui arriverait à tricher avec la joignabilité pourrait pousser un routeur LISP d'entrée du tunnel (un ITR) à changer de routeur de sortie (l'ETR) au profit d'un routeur qui ne marche pas. Cela réaliserait une attaque par déni de service. Même s'il n'arrive pas à faire changer de routeur, il pourrait perturber le routage en envoyant des tas de numniques différents. (Rassurez-vous, cette attaque est plus dure à réussir qu'il ne semble, voyez la section 5.)
LISP permet que plusieurs espaces d'adressage coexistent, différenciés par leur instance ID indiquée dans l'en-tête (RFC 6830, section 5.5). Elle n'est pas authentifiée et un attaquant peut donc envoyer des paquets à une autre instance ID que la sienne.
LISP permet de l'interconnexion avec des réseaux non-LISP (RFC 6832). Ces mécanismes ont des attaques très similaires à celles qu'on peut faire contre LISP lui-même. Par exemple, un paquet avec une adresse source usurpée peut être transmis sur l'Internet par la passerelle LISP.
Mais les pires attaques se situeront sans doute sur le système de correspondance (mapping). Le point central de tous les systèmes à séparation de l'identificateur et du localisateur est de découpler deux fonctions qui, dans IP, sont confondues. Cela suit un grand principe de l'informatique : « tout problème peut être résolu en ajoutant un degré d'indirection ». Sauf que cette séparation se paie en sécurité : il faut bien, à un moment, faire correspondre identificateur et localisateur et, là, cette nouvelle fonction, la correspondance, offre de nouvelles possibilités d'attaque.
Ainsi, les messages Map-Request
(RFC 6830, section 6) peuvent
être utilisés de plusieurs façons. Envoyés en masse, à un système
de contrôle qui est bien moins rapide que le système de
transmission, ils peuvent saturer les routeurs. Comme la réponse
(Map-Reply
) est plus grosse que la question,
ils peuvent servir à des attaques par amplification.
Et si un attaquant réussit à fabriquer de fausses réponses
(Map-Reply
) et à les faire accepter ? Il
devra pour cela mettre le numnique correct dans ses paquets. Comme
il fait 64 bits, si on a suivi les bons principes du RFC 4086 pour le générer, un attaquant qui n'est
pas sur le chemin (et doit donc deviner le numnique) n'a que peu
de chances de réussir. Mais attention, le numnique n'est pas une
signature : il indique juste que le paquet est bien une réponse à
une question posée. Si l'attaquant peut modifier les paquets, il
peut empoisonner le cache de correspondance du routeur. Variante
de cette attaque, si le méchant est un routeur légitime
(rogue attack), il peut répondre, mais avec de
fausses réponses. Il ne peut pas annoncer des préfixes quelconques
mais il peut annoncer des préfixes plus généraux que ceux qu'il
gère réellement (par exemple annoncer qu'il gère
192.0.2.0/24
alors qu'il ne contrôle que 192.0.2.0/26
), ce qui lui permet de détourner le trafic.
Enfin, il y a les Map-Register, ces messages envoyés par les routeurs aux serveurs de correspondance pour les informer des préfixes gérés (RFC 9301, section 4.2). Ils sont authentifiés donc, normalement, un attaquant quelconque ne peut pas les usurper. Mais il reste des attaques résiduelles comme l'annonce de préfixes plus généraux que les siens.
Au passage, un problème de sécurité qu'on oublie parfois est celui de la vie privée (section 4). Les correspondances LISP sont publiques (comme les tables BGP dans l'Internet classique) et il ne faut donc pas oublier qu'on ne peut pas participer à LISP discrètement.
Et pour finir, les solutions (section 5). Comment faire pour éviter ces menaces ? Le RFC donne des conseils très généraux (« déployer soigneusement », « appliquer les règles habituelles de sécurité ») mais aussi des indications plus précises et spécifiques à LISP. Clairement, le plan de contrôle est la partie la plus sensible. Il est donc important d'utiliser les techniques d'authentification décrites dans le RFC 9301 (voir notamment sa section 6). Des extensions de sécurisation de LISP sont en cours de développement.
D'autre part, les conseils de sécurité du RFC 6830 doivent être suivis. Par exemple, quand ce RFC
écrit qu'il faut limiter le rythme des
Map-Request
, cela doit être appliqué.
L'information obtenue par examen des paquets (comme le glanage cité plus haut) n'est évidemment pas de confiance : à n'utiliser que pour le flot de données qui contenait cette information, ou alors à vérifier avant. (Voir aussi « How to mitigate the effect of scans on mapping systems ».)
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : A. Mayrhofer (nic.at GmbH)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 11 mai 2016
Ce nouveau RFC fait partie de la série de ceux qui tentent d'améliorer la situation du DNS pour tout ce qui concerne la protection de la vie privée. Parmi les efforts dans ce domaine, il y a une possibilité de chiffrement des communications DNS, dans le RFC 7858 (DNS-sur-TLS). Elle utilise le protocole TLS. Ce dernier ne fait rien pour dissimuler la longueur des requêtes et réponses DNS. Or, de telles métadonnées peuvent suffire à identifier les requêtes faites. Il est donc important de compléter le chiffrement avec un mécanisme de remplissage (padding). C'est ce que permet la nouvelle option EDNS normalisée dans ce RFC.
Trouver la requête effectuée uniquement à partir de la taille de la réponse est d'autant plus facile que les données DNS ne sont pas confidentielles. Un espion qui soupçonne que M. Michu fait des requêtes pour tel nom de domaine peut faire la même requête, noter la taille de la réponse chiffrée, et voir s'il trouve la même taille dans les réponses reçues par M. Michu. Voilà pourquoi il faut ajouter aux requêtes et aux réponses un certain nombre d'octets, pour rendre plus difficile cette analyse des métadonnées.
Ce RFC est court car le mécanisme est très simple (section 3 du RFC). Ce mécanisme utilise une nouvelle option EDNS (EDNS est normalisé dans le RFC 6891.) Cette option porte le numéro 12 et sa partie « données » porte le remplissage. (Comme toute option EDNS, elle est encodée en TLV : un champ indique le type de l'option, ici, 12, un champ indique la longueur de l'option, et le dernier contient les données.)
Que mettre comme remplissage ? Cette question a été la plus discutée lors de la création de ce RFC (qui a été plutôt calme et consensuelle, pour le reste.) Le RFC précise que l'émetteur d'un message DNS devrait remplir avec des octets nuls (0x00). Si l'émetteur craint que certains traitements (par exemple de la compression, voyez cependant la section 6 qui demande de ne pas l'utiliser) appliqués avant le chiffrement ne suppriment l'essentiel du remplissage, il est autorisé à mettre une autre valeur. De toute façon, le récepteur doit accepter n'importe quelle valeur, pour permettre les évolutions futures. En pratique, il doit donc ignorer le contenu des données de cette option.
Pourquoi n'avoir pas simplement dit que l'émetteur pouvait mettre ce qu'il voulait, dans ce cas ? Parce qu'il semblait possible, dans ce cas, que des programmeurs naïfs utilisent de la variable non initialisée, et laissent ainsi fuiter le contenu de leur mémoire (comme dans la faille Heartbleed.) Et pourquoi n'avoir pas spécifié un remplissage avec des données aléatoires ? Parce que ce n'est pas normalement nécessaire : pour un observateur, le contenu chiffré doit apparaitre aléatoire, quel que soit le texte en clair (si TLS ne fournissait pas cette propriété, des tas d'attaques seraient possibles, par exemple à base de texte en clair connu.)
Voilà, l'essentiel du RFC tient dans cette courte section 3. Mais quelques détails suivent. Par exemple, quelle quantité d'octets mettre dans la nouvelle option ? Le RFC ne fournit pas de guide à ce sujet, il rappelle juste qu'il ne faut pas aboutir à des messages plus gros que ce que le client spécifiait dans son champ Payload size EDNS (souvent 4 096 octets mais cela dépend du client.) Des règles plus précises sur la politique de remplissage ont été normalisées par la suite dans le RFC 8467. Le serveur DNS ne doit évidemment pas utiliser cette option si la requête ne contenait pas d'EDNS. Si elle contenait de l'EDNS sans cette option, le serveur est libre de remplir ou pas. Si la requête contenait de l'EDNS avec l'option Padding, alors, le serveur doit effectuer du remplissage.
Quelques trucs à ne pas oublier en section 6 : le remplissage augmente la taille des paquets (évidemment). Cela mènera donc à un accroissement du trafic. Dans l'Internet d'aujourd'hui, où tous les États qui en ont les moyens procèdent à une surveillance massive de leurs citoyens (RFC 7258), c'est un petit prix à payer, pour l'avantage de compliquer le travail des surveillants.
Autre piège, l'option de remplissage ne doit être utilisée que si le trafic DNS est chiffré. Autrement, non seulement elle ne servirait à rien, mais elle augmenterait le risque d'attaques avec amplification.
À noter que, comme plein d'autres champs des messages DNS (comme par exemple le QNAME, le Query Name), cette option peut servir de canal caché. Peut-être verra-t-on un jour une mise en œuvre d'IP-sur-DNS utilisant cette option ?
Notez que cette technique est indépendante du protocole de chiffrement sous-jacent, puisqu'elle est faite au niveau applicatif. DNScrypt pourrait l'utiliser (sauf qu'il a son propre système de remplissage.)
Et les mises en œuvre de cette technique ? A-t-on du code qui tourne ? getdns a le remplissage depuis sa version 0.5.1 (cf. le Changelog.) GoDNS y travaille. Wireshark peut analyser cette option. La page officielle sur cette option de remplissage liste d'autres mises en œuvre.
Depuis la sortie de ce RFC, les clients et serveurs DNS ont peu à peu intégré cette option de remplissage. Voyons ici kdig avec le serveur public de Cloudflare :
% kdig +dnssec +tls +padding @1.1.1.1 A chatons.org ... ;; EDNS PSEUDOSECTION: ;; Version: 0; flags: do; UDP size: 1232 B; ext-rcode: NOERROR ;; PADDING: 301 B
Notez que 1.1.1.1
met du remplissage même si
le client ne l'a pas demandé, ce que permet la section 4 du RFC.
Daniel Kahn Gillmor, qui avait programmé cette extension dans getdns, en a profité pour faire quelques statistiques :
Ethernet Frame sizes for packet containing DNS query Transport | query to | query to used | example.com | www.example.com --------------------------+--------------+------------------- cleartext UDP | 82 octets | 86 octets cleartext TCP | 108 octets | 112 octets TLS over TCP | 137 octets | 141 octets (padded to 512) TLS over TCP | 609 octets | 609 octets
On voit que le remplissage brouille la différence de taille entre les deux requêtes. Mais restons prudents : le remplissage est une bonne technique pour rendre plus difficile l'analyse des métadonnées mais il n'est pas parfait. Lisez par exemple l'excellent « Peek-a-Boo, I Still See You : Why Efficient Traffic Analysis Countermeasures Fail ».
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : P. Wouters (Red Hat), J. Abley
(Dyn), S. Dickinson
(Sinodun), R. Bellis (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 11 avril 2016
Dernière mise à jour le 12 avril 2016
Historiquement, le DNS utilisait surtout UDP et le transport sur TCP ne servait qu'à des cas particuliers, comme lorsqu'un client DNS ré-essayait avec TCP de récupérer des données trop grosses pour UDP. Depuis le RFC 7766, ce n'est clairement plus le cas : TCP est désormais aussi utilisable qu'UDP pour le DNS. Mais les mises en œuvre typique du DNS sur TCP ont des restrictions, par exemple des délais maximum d'attente avant de « raccrocher » qui sont trop courtes, de l'ordre de quelques secondes lorsqu'il n'y a plus de trafic sur la connexion. Ce nouveau RFC propose un mécanisme EDNS permettant au client DNS de signaler au serveur qu'il souhaite garder la connexion ouverte, si le serveur est d'accord, s'il vous plait. (Notez qu'il existe une autre façon d'indiquer le temps pendant lequel on souhaite garder la session, celle des DSO du RFC 8490 ».)
Utiliser une connexion TCP par requête
DNS serait en effet très inefficace,
notamment question latence. Il
faudrait effectuer la triple poignée de
mains TCP à chaque requête. Le DNS sur TCP n'est
envisageable que si les connexions restent ouvertes et que la même
connexion peut servir pour plusieurs requêtes. Dans ce cas,
lorsque la connexion a déjà été ouverte, la latence peut être
aussi faible qu'avec UDP, voire meilleure (dans le cas de données
de grande taille, par exemple avec DNSSEC,
plus besoin d'essayer d'abord sur UDP). Reste une question pour le
serveur DNS : faut-il laisser la connexion ouverte dès
qu'il n'y a plus de requêtes à traiter ? Cette nouvelle option
EDNS
edns-tcp-keepalive
permet au client DNS
d'indiquer que, lui, il est prêt à réutiliser la connexion et
qu'il souhaite qu'on la garde ouverte.
Le serveur souhaite économiser ses ressources (mémoire, notamment). Contrairement à UDP, TCP nécessite que le serveur garde un état. Imaginons que chaque connexion TCP prenne une entrée dans un grand tableau des connexions TCP en cours. Si c'était « open bar » pour les clients, qu'ils puissent ouvrir autant de connexions qu'ils veulent, et les garder éternellement ensuite, le tableau serait vite rempli, menant à un déni de service. (Et si vous pensez qu'à la place du tableau, une structure de données dynamique, grossissant automatiquement, résoudrait le problème, rappelez-vous que la mémoire du serveur est finie...) Le serveur choisit donc s'il garde les connexions ouvertes, et combien de temps.
Au passage, la section 1 du RFC rappelle aussi qu'UDP a des problèmes sérieux, notamment parce qu'il permet des attaques par réflexion et parce qu'il implique, pour les grosses données, de la fragmentation, qui est en général une source d'ennuis (voir par exemple « Fragmentation Considered Poisonous de Herzberg et Shulman). D'où cet encouragement, depuis des années, à utiliser de plus en plus TCP.
La section 3 est la partie centrale du RFC, la spécification de la nouvelle option. Elle utilise EDNS (RFC 6891). Elle permet d'indiquer le délai d'attente avant la fermeture de la connexion, délai qui commence à courir lorsque la connexion devient inactive (« idle », cf. la section 3 du RFC 7766).
L'option se nomme edns-tcp-keepalive
et a
reçu le code 11 (stocké dans le registre
des options EDNS). Elle prend un seul argument, encodé sur
deux octets, TIMEOUT
qui indique la durée
du délai de garde, exprimée en unités de 100
millisecondes. Cette valeur n'apparait que dans les réponses du
serveur, pas dans les requêtes du client. Si TIMEOUT
vaut 600, cela
signifie que les connexions restent
ouvertes pendant une minute après la dernière requête reçue.
Ensuite, une fois cette option définie, comment on s'en sert ?
Elle ne doit évidemment pas être utilisée sur UDP, où elle
n'aurait aucune signification. Le client doit utiliser cette
option pour signaler qu'il souhaiterait garder cette connexion
ouverte (il ne doit pas indiquer de valeur pour
TIMEOUT
). Le serveur utilise cette option
pour indiquer le temps pendant lequel il va garder la
connexion (rappelez-vous que le client peut demander ce qu'il
veut, c'est le serveur qui décide). Le client est censé « raccrocher » juste avant
l'expiration de ce délai. Une valeur de 0 pour TIMEOUT
signifie « raccroche tout de suite » (un serveur
l'envoie, par exemple, lorsqu'il est soumis à un fort stress et
n'a plus de ressources disponibles.)
Au passage, si le serveur n'a plus envie de supporter cette
connexion, pourquoi ne raccroche-t-il pas lui-même, au lieu de
demander au client de le faire ? C'est parce que le pair TCP qui
ferme la connexion le premier passe ensuite en état
TIME-WAIT
(RFC 793,
section 3.5) et que cela l'oblige à garder un état pendant deux
fois la durée de vie maximale d'un segment TCP (soit quatre
minutes en tout). Il vaut donc mieux demander au client de le
faire. Par contre, après avoir envoyé le
TIMEOUT=0
, le serveur va avoir un délicat
arbitrage à faire entre attendre que le client raccroche et fermer
de lui-même la connexion (et donc garder une prise en état
TIME-WAIT
) quand le client n’obtempère pas
suffisamment vite.
La section 5 du RFC recommande d'ailleurs aux serveurs de suivre l'activité de leurs clients et de « punir », d'une façon ou d'une autre, ceux qui violeraient ces règles, par exemple en continuant à envoyer des requêtes alors qu'on leur a demandé de raccrocher.
J'insiste mais cela vaut la peine d'être dit et répété : cette
option edns-tcp-keepalive
ne diminue pas la liberté des clients et des serveurs
DNS. En cas de problème (tableau des connexions TCP en cours
presque plein, par exemple), clients et serveurs sont libres de
couper les connexions TCP plus tôt, ce qu'on appelle le
« TCP session management ».
Comme d'habitude avec toute nouvelle option, on peut s'attendre à des problèmes avec les stupides middleboxes. Une requête contenant cette option peut ainsi être jetée alors qu'elle ne l'aurait pas été sans l'option. Une stratégie de repli comme celle de la section 6.2.2 du RFC 6891 peut donc être utile.
Merci à Kim-Minh Kaplan pour d'utiles précisions sur TCP.
Date de publication du RFC : Décembre 2016
Auteur(s) du RFC : H. Schulzrinne (Columbia University), A. Rao (Cisco), R. Lanphier, M. Westerlund (Ericsson AB), M. Stiemerling (NEC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF mmusic
Première rédaction de cet article le 28 décembre 2016
Voici la version 2 du protocole bien connu RTSP, protocole servant à accéder à des flux vidéo. Comme c'est ce que j'utilise pour regarder la télévision sur l'écran de mon PC, je suis ravi que l'IETF se préoccupe de l'améliorer.
Comme beaucoup de protocoles dans le monde du multimédia (SIP, par exemple), RTSP est en fait uniquement un protocole de contrôle, permettant de déclencher ou d'arrêter des flux audio ou vidéo. Ces flux peuvent être temps-réel ou bien avoir simplement été stockés sur le disque d'un serveur. Donc, RTSP est une zapette logicielle. RTSP fait le contrôle et plusieurs protocoles peuvent être utilisés pour le transport des données, UDP, TCP, RTP, etc. À noter la taille impressionnante de ce RFC, avec plus de 300 pages. Ce n'est pas que le protocole soit si compliqué que cela, mais il y a beaucoup d'options et de choix.
La section 2 du RFC résume le protocole : RTSP est client/serveur,
le client RTSP se connecte au serveur, un certain nombre de choix
techniques sont faits et ensuite l'envoi des données
commence. Physiquement, les messages sont du texte (la syntaxe de RTSP
ressemble beaucoup à celle d'HTTP) bien que du
binaire soit parfois possible. La ressource convoitée est identifiée
par un URI de plan rtsp
(ou rtsps
pour TLS) et cet URI contient le nom de la
machine qui sera utilisée comme serveur. Par exemple, si je dis à mon logiciel
RTSP d'utiliser
rtsp://mafreebox.freebox.fr/fbxtv_pub/stream?namespace=1&service=658&flavour=ld
,
la connexion RTSP sur TCP (ou TCP avec TLS) se fera avec
mafreebox.freebox.fr
. La requête RTSP inclus un
certain nombre d'en-têtes comme dans HTTP, et parfois un corps
(toujours comme en HTTP). Voici un exemple avec le client
VLC. Je le lance avec vlc
'rtsp://mafreebox.freebox.fr/fbxtv_pub/stream?namespace=1&service=897'
et on voit (tcpdump ne sait pas
apparemment décoder le RTSP mais Wireshark y
arrive très bien) :
Internet Protocol Version 4, Src: 192.168.2.1 (192.168.2.1), Dst: 212.27.38.253 (212.27.38.253) Transmission Control Protocol, Src Port: 45854 (45854), Dst Port: rtsp (554), Seq: 563, Ack: 873, Len: 204 Real Time Streaming Protocol Request: PLAY rtsp://mafreebox.freebox.fr/fbxtv_pub/stream?namespace=1&service=897 RTSP/1.0\r\n CSeq: 5\r\n User-Agent: LibVLC/2.0.3 (LIVE555 Streaming Media v2012.05.17)\r\n Session: pokf6CQWbA8CUyC Range: npt=0.000-\r\n \r\n
Dans l'exemple ci-dessus, le protocole était RTSP version 1.0
(rappelez-vous que ce RFC décrit la version 2), la requête était
PLAY
(dont le nom dit bien ce qu'elle fait et
vous ne serez pas surpris d'apprendre qu'il existe une commande PAUSE
) et
l'un des en-têtes, User-Agent:
montre que
j'utilise bien vlc.
Quand au trafic lui-même, on voit (ici avec tcpdump) d'abord du RTSP sur TCP puis un gros flux UDP :
21:34:36.179830 IP (tos 0x10, ttl 64, id 20888, offset 0, flags [DF], proto UDP (17), length 1356) 212.27.38.253.46099 > 192.168.2.1.34324: [udp sum ok] UDP, length 1328 21:34:36.180040 IP (tos 0x10, ttl 64, id 20889, offset 0, flags [DF], proto UDP (17), length 1356) 212.27.38.253.46099 > 192.168.2.1.34324: [udp sum ok] UDP, length 1328 21:34:36.180738 IP (tos 0x10, ttl 64, id 20890, offset 0, flags [DF], proto UDP (17), length 1356) 212.27.38.253.46099 > 192.168.2.1.34324: [udp sum ok] UDP, length 1328
Les contenus auxquels on accède avec RTSP peuvent être de type très variés. Il faut donc une description formalisée des caractéristiques de ce contenu. RTSP peut utiliser plusieurs formats pour cela, le plus répandu étant sans doute SDP (RFC 4566). C'est en tout cas celui utilisé entre mon VLC et ma Freebox. La description peut inclure le nombre de flux (souvent un flux vidéo et plusieurs audios), le protocole de délivrance (RTP - RFC 3550 - dans l'exemple ci-dessous), le format (MPEG-2 ici), etc :
Session Description Protocol Session Description Protocol Version (v): 0 Owner/Creator, Session Id (o): leCDN 1395332443 1395332443 IN IP4 kapoueh.proxad.net ... Media Description, name and address (m): video 0 RTP/AVP 33 Media Type: video Media Port: 0 Media Protocol: RTP/AVP Media Format: MPEG-II transport streams Media Attribute (a): control:rtsp://mafreebox.freebox.fr/fbxtv_pub/stream?namespace=1&service=658&flavour=ld Media Attribute Fieldname: control Media Attribute Value: rtsp://mafreebox.freebox.fr/fbxtv_pub/stream?namespace=1&service=658&flavour=ld
Quels sont les changements par rapport à RTSP version 1, la version
du RFC 2326 ? Les deux
versions, quoique identiques dans leurs principes, ne sont pas
compatibles (par exemple, la commande PLAY
n'a
plus le même comportement, des en-têtes ont changé de syntaxe sans
changer de nom, etc). C'est toujours un choix difficile que de casser la
compatibilité d'un protocole mais, là, c'était nécessaire vu le nombre
de modifications. En outre, RTSP 1 ne
permettait pas de déployer facilement des extensions (en-têtes à la
syntaxe trop rigide) et le modèle d'extension a changé. L'annexe I de
notre RFC résume ce qu'il faut savoir sur ces différences :
suppression des requêtes RECORD
et
ANNOUNCE
, suppression de l'option qui permettait
de faire passer RTSP (le contrôle, pas les données) sur UDP, gestion
complète d'IPv6 (qui manquait en version 1),
refactorisation du RFC (les en-têtes qui sont proches de ceux de HTTP
sont désormais décrits par un texte spécifique, sans renvoyer au RFC
HTTP), etc.
Il y a apparemment au moins une mise en œuvre de RTSP qui a la version 2, et plusieurs des nouveautés de la version 2 ont été mises en œuvre de manière séparée.
Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Krishnan (Ericsson), T. Mrugalski
(ISC), S. Jiang (Huawei
Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 12 juin 2016
Le protocole DHCP sert à transmettre à une machine qui vient de se connecter au réseau, des informations utiles pour sa connexion. Il est surtout connu pour son utilisation avec IPv4 mais DHCP existe aussi pour IPv6 (il est normalisé dans le RFC 8415). Comme son équivalent IPv4, DHCP pour IPv6 pose un certain nombre de problèmes de vie privée, que ce RFC explore.
Il fait donc partie de la série de RFC développés après le RFC 6973 et, surtout, après les révélations de Snowden qui ont mené l'IETF à s'engager plus vigoureusement contre la surveillance massive. Ce RFC ne propose pas de solutions (elles sont décrites dans le RFC 7844), il décrit le problème.
Le problème fondamental est le même qu'en IPv4 (RFC 7819) : le client DHCP, lorsqu'il vient de se connecter à un réseau et émet des requêtes, publie des informations trop détaillées, dont certaines sont des véritables identificateurs stables (cf. section 2 de notre RFC), permettant au serveur DHCP, mais aussi à toute machine qui écoute le réseau, de suivre à la trace une machine donnée. Au contraire des solutions comme SLAAC, où le client est purement passif, DHCP impose au client d'annoncer son existence et de donner des informations. Bref, si vous avez déjà lu le RFC équivalent pour IPv4, le RFC 7819, vous n'apprendrez pas grand'chose de nouveau.
La section 3 du RFC donne une liste aussi complète que possible
des options DHCPv6 qui peuvent servir à la surveillance. D'abord,
l'adresse IP source. Bon, elle ne fait pas partie
de DHCP à proprement parler et tout protocole va la publier,
puisqu'elle apparait dans tous les paquets émis. (Dans le cas
de DHCP, la requête du client est émise depuis une adresse locale
au lien, link-local, celles qui commencent par
fe80::
.) Néanmoins, l'adresse IP source
mérite une mention car certains mécanismes de génération d'une
adresse IPv6 peuvent poser des problèmes de vie privée (cf. RFC 7721). Il faut
donc utiliser des mécanismes comme ceux du RFC 8981 ou du RFC 7217.
L'exemple suivant est celui d'une option particulièrement dangereuse pour la vie privée, Client Identifier, qui envoie au serveur le DUID (DHCPv6 Unique Identifier, RFC 8415, section 11) du client. Comme son nom l'indique, il identifie chaque machine de manière unique et, par défaut, il est stable. La méthode la plus courante pour le générer est d'utiliser l'adresse MAC, elle-même un identificateur unique et stable. Même si on prend la précaution de changer l'adresse MAC, le DUID ne change pas. C'est donc un excellent moyen de suivre une machine, cassant complètement la sécurité de techniques comme celle du RFC 8981.
Certaines options peuvent être moins clairement indiscrètes mais peuvent néanmoins révéler indirectement l'identité du client. C'est le cas de l'option Option Request qui dit au serveur quelles options on souhaiterait qu'il utilise. Cette liste de choix peut servir à distinguer entre plusieurs clients DHCP : toutes les fois où il y a un choix dans un protocole, il y a une possibilité de fingerprinting.
Certaines options n'envoient pas directement un identificateur unique mais envoient de l'information sur une classe à laquelle appartient la machine. Par exemple, les options Vendor Class et Vendor-specific Information (sections 21.16 et 21.17 du RFC 8415), ou encore l'option Client System Architecture (RFC 5970), indiquent le matériel et le logiciel du client.
On n'a vu ici que des options allant du client vers le serveur mais l'inverse existe aussi, et certaines options qu'un serveur peut envoyer sont révélatrices (par exemple Civic Location, RFC 4776). Mais les problèmes de vie privée du serveur sont moins graves que ceux du client et notre RFC passe donc rapidement (voir aussi la section 5.3).
En dehors des options DHCP, certains mécanismes utilisés dans le cadre de DHCP peuvent être bien indiscrets. C'est par exemple le cas de la demande d'adresses temporaires (RFC 8415, section 6.5), pourtant bien intentionnée. Le but était de pouvoir obtenir des adresses qui ne soient pas stables, pour minimiser justement les risques pour la vie privée. Le RFC détaille les nombreux problèmes et pièges que récèle ce mécanisme. Mais le principal problème est que la seule demande de ces adresses, visible par tout surveillant, est déjà très révélatrice ! Cela revient à sa promener avec une cagoule sur sa tête pour préserver sa vie privée.
Autre mécanisme qui peut être révélateur, la mise à jour du DNS que font certains serveurs DHCP. Si le nom utilisé est stable (cf. l'option Client FQDN mentionnée plus haut), tout surveillant ayant accès au DNS (c'est-à-dire tout le monde) pourra suivre les changements d'adresse IP de la machine, connaissant ainsi ses déplacements d'un réseau à l'autre.
Les stratégies d'allocation d'adresses du serveur DHCP peuvent également être dangereuses pour la vie privée. Le serveur DHCP dispose d'une certaine plage d'adresses. S'il alloue les adresses en commençant toujours par la plus basse adresse libre, les adresses attribuées vont être assez prévisibles, ce qui n'est en général pas bon pour la discrétion. (Et ce mécanisme, qui a certes l'avantage d'être simple et rapide, tend à concentrer les adresses allouées au début de la plage.) Autre possibilité, allouer des adresses fixes (le même client - identifié par une option comme Client Identifier - a toujours la même adresse IP). C'est évidemment très pratique pour l'administrateur du réseau local. Mais c'est la pire solution pour la vie privée, puisque cela oblige le client à divulguer son identité, et cela permet même aux serveurs extérieurs de le suivre à la trace lorsqu'il communique avec eux avec son adresse fixe. Pour la vie privée, la meilleure stratégie d'allocation est sans doute le tirage au sort parmi les adresses libres de la plage.
Maintenant qu'on a vu les vulnérabilités de DHCPv6, voyons ce qu'un attaquant peut en faire (section 5 du RFC). D'abord, il peut découvrir le type de machine chez le client (matériel et/ou logiciel), ce qui peut être utile, par exemple pour sélectionner une attaque spécifique à un système d'exploitation, ou bien, si le matériel/logiciel utilisé est rare, pour identifier un client particulier. Cette information sur le type de machine peut être trouvé dans l'adresse MAC (les premiers octets identifient le vendeur), dans les identificateurs dérivés de l'adresse MAC, ou dans les options comme Vendor Class.
L'espion peut également utiliser ces faiblesses de DHCPv6 pour identifier les réseaux visités précédemment (je n'en ai pas parlé plus haut, mais il existe une option qui indique la précédente adresse IP utilisée : elle est pratique pour obtenir une adresse stable, mais elle est indiscrète).
Plus généralement, le surveillant peut essayer de découvrir une identité stable, lui permettant de savoir combien de machines utilisent ce serveur DHCP, et lui permettant également de corréler deux machines sur deux réseaux, découvrant qu'il s'agit en fait de la même. Le DUID est particulièrement sensible ici.
Le surveillant peut ainsi suivre une machine, soit dans le temps (toutes ses activités en un réseau donné), soit dans l'espace (suivre à la trace un engin mobile).
Si le surveillant a les moyens d'une agence d'un État riche
(par exemple si le surveillant est la NSA),
il peut effectuer une surveillance massive très efficace (RFC 7258). Il est par exemple conceptuellement
aisé de bâtir une liste de très nombreuses machines, en observant
beaucoup de réseaux : les failles de sécurité de DHCPv6 citées
dans ce RFC permettront de reconnaitre chaque machine
individuelle. Ainsi, un organisme comme la NSA peut se faire une
base de données permettant de répondre très vite à des questions
du genre « où était 38:59:f9:7d:b6:47
la
dernière fois qu'on l'a vu ? »
Enfin, la section 6 de notre RFC rappelle une triste réalité : en sécurité, il faut en général faire des compromis. Ici, le RFC note que toute authentification du client va à l'encontre du souhait de préserver la vie privée. Ce genre de choix (sécurité de son réseau, ou bien vie privée des utilisateurs) est bien embêtant pour l'administrateur système.
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : S. Jiang (Huawei
Technologies), S. Krishnan
(Ericsson), T. Mrugalski (ISC)
Pour information
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 3 mai 2016
Le protocole DHCP est bien connu : la grande majorité des machines « client » qui se connectent à l'Internet l'utilisent pour récupérer des éléments de configuration indispensables, comme l'adresse IP à utiliser. Mais peu de gens sont conscients que DHCP peut être dangereux pour la vie privée : le client DHCP n'est en effet pas passif, il envoie au serveur des informations qui peuvent permettre de suivre à la trace une machine mobile.
DHCP pour IPv4 est normalisé dans le RFC 2131. (Le RFC 7824 traite le cas de DHCP pour IPv6, qui pose des problèmes similaires.) Son principe de fonctionnement est simple : le client DHCP (la machine de M. Michu) envoie à la cantonade une requête pour demander des informations de configuration réseau, le serveur DHCP se reconnait, il répond avec ces informations. Voici une transaction DHCP, vue par tcpdump :
21:32:13.284690 IP (tos 0x0, ttl 64, id 960, offset 0, flags [none], proto UDP (17), length 377) 0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from b8:27:eb:84:35:e3, length 349, xid 0x4feaaa6f, Flags [none] (0x0000) Client-Ethernet-Address b8:27:eb:84:35:e3 Vendor-rfc1048 Extensions Magic Cookie 0x63825363 DHCP-Message Option 53, length 1: Request Client-ID Option 61, length 19: hardware-type 255, eb:84:35:e3:00:01:00:01:c7:92:bc:8a:b8:27:eb:ba:90:94 Requested-IP Option 50, length 4: 192.168.2.9 MSZ Option 57, length 2: 1500 Vendor-Class Option 60, length 46: "dhcpcd-6.9.0:Linux-4.4.8-2-ARCH:armv6l:BCM2708" Hostname Option 12, length 5: "amour" T145 Option 145, length 1: 1 Parameter-Request Option 55, length 14: Subnet-Mask, Classless-Static-Route, Static-Route, Default-Gateway Domain-Name-Server, Hostname, Domain-Name, BR NTP, Lease-Time, Server-ID, RN RB, Option 119 END Option 255, length 0 21:32:13.299825 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 576) 192.168.2.254.67 > 192.168.2.9.68: [udp sum ok] BOOTP/DHCP, Reply, length 548, xid 0x4feaaa6f, Flags [none] (0x0000) Your-IP 192.168.2.9 Client-Ethernet-Address b8:27:eb:84:35:e3 Vendor-rfc1048 Extensions Magic Cookie 0x63825363 DHCP-Message Option 53, length 1: ACK Server-ID Option 54, length 4: 192.168.2.254 Lease-Time Option 51, length 4: 43200 Subnet-Mask Option 1, length 4: 255.255.255.0 Default-Gateway Option 3, length 4: 192.168.2.254 Domain-Name-Server Option 6, length 8: 192.168.2.254,149.20.64.21 BR Option 28, length 4: 192.168.2.255 END Option 255, length 0 PAD Option 0, length 0, occurs 264
Malheureusement, dans la requête du client se trouvent plein de détails sur la machine demanderesse (section 1 du RFC). Compte-tenu de la sensibilité aux problèmes de vie privée (RFC 6973) et de l'ampleur de la surveillance de masse exercée par les États (RFC 7258), il était nécessaire de limiter cette fuite d'informations. Ce premier RFC va décrire le problème, et proposer quelques pratiques qui le limitent. Le RFC 7844 détaille un profil DHCP qui limite sérieusement la fuite. Dans une prochaine étape, il y aura peut-être des modifications au protocole DHCP mais ce n'est pas encore fait.
Pour cette analyse de sécurité, la section 2 de notre RFC introduit la notion d'identificateur stable. Un identificateur stable (stable identifier) est une information envoyée par le client DHCP qui change peu ou pas dans le temps (et qui peut donc permettre de tracer une machine mobile). La stabilité peut dépendre de la mise en œuvre logicielle utilisée. Ainsi, une adresse MAC est typiquement un identificateur stable mais, si macchanger est utilisé, ce n'est plus le cas. Un identificateur stable n'est pas forcément mondialement unique.
Le gros de ce RFC est la section 3, qui liste les identificateurs envoyés par le client DHCP. Le plus évident, car il est prévu pour cela, est l'option DHCP Client Identifier (RFC 2131, section 2, et RFC 2132, section 9.14). Il est en général stable (le RFC 1533, prédécesseur du RFC 2132, recommandait même d'utiliser une adresse MAC, mais on voit parfois un nom de domaine, ou bien un DUID - décrit dans le RFC 4361). Même si on utilise un logiciel comme macchanger pour changer d'adresse MAC, pas mal de mises en œuvre de DHCP utiliseront la valeur initiale et la stockeront... pour toujours.
Moins spectaculaire, plusieurs champs de la
requête transportent des identificateurs fondés sur une adresse. C'est le cas de
yiadrr
, qui indique l'adresse IP actuelle du
client ou chaddr
qui indique l'adresse MAC. Plusieurs options font de même comme
la Requested IP Address (qui permet d'indiquer
l'adresse IP qu'on souhaiterait recevoir).
Autre option qui envoie un identificateur stable, et souvent unique, l'option Client FQDN (RFC 4702) qui transmet au serveur le FQDN.
Après les adresses et les noms de domaine, un autre danger se
présente avec les options qui permettent au client d'indiquer le
logiciel qu'il utilise. C'est le cas de l'option Vendor
class (RFC 2132, section 9.13,
une sorte d'équivalent du User-Agent:
de
HTTP,
dans l'exemple plus haut, elle indique une machine
ARM sous Linux), du
Vendor-Identifying du RFC 3925, et de toutes les options
Vendor-specific information (RFC 2132, section 8.4), qui peuvent
indiquer le numéro de version du logiciel utilisé, sa
configuration spécifique, etc. Certes, elles ne
sont pas uniques (elles ne désignent pas une machine particulière)
mais elles font quand même fuiter de l'information sur le client
et, combinées avec d'autres informations, elles peuvent mener à
une identification unique. Une option analogue est Client
System Architecture Type (RFC 4578) qui indique
le type exact d'architecture pour les clients DHCP qui vont
démarrer sur le réseau (par exemple avec PXE), en téléchargeant une version particulière
du système d'exploitation. Si l'architecture utilisée est un peu
rare, cette option donne des informations précieuses à un observateur.
En lisant cette liste, le paranoïaque peut se dire que la NSA a envoyé des gens à l'IETF pour faire normaliser le plus grand nombre possible d'extensions indiscrètes, de façon à être sûr d'identifier tous les clients DHCP observés. Il y a même une option pour indiquer l'adresse (civile, dans le monde physique, pas sur le réseau), Civic Location, dans le RFC 4776. Il est vrai que, contrairement à la plupart des options listées ici, elle est fournie par le serveur et pas par le client, et ne permet donc pas de suivre un client à la trace. Mais elle peut permettre à un observateur de savoir où, dans le monde physique, se situe le client.
Outre tous ces champs et ces options par lesquels une information souvent excessive est transmise, DHCP dispose de certains mécanismes qui peuvent être utilisés pour compromettre la vie privée (section 4 du RFC). Par exemple, l'option Client FQDN du RFC 4702, citée plus haut, sert souvent à faire des mises à jour dynamiques du DNS (RFC 2136), et, dans ce cas, l'adresse IP du client DHCP (qui peut indiquer sa localisation) et son nom, identificateur stable, sont publiés dans le DNS, que tout le monde peut consulter. On peut connaitre les déplacements d'une machine simplement en consultant ce DNS public, sans avoir besoin d'espionner des milliers de réseaux. L'observateur peut être très discret et, en toute légalité, vous suivre.
Autre mécanisme dangereux, la stratégie d'allocation du serveur DHCP. Lorsqu'un client DHCP réclame une adresse IP, le serveur peut la choisir de plusieurs façons, et certaines ont des conséquences pour la vie privée :
La taille très restreinte de l'espace d'adressage IPv4 complique le problème, en limitant les possibilités du serveur d'utiliser certaines stratégies d'allocation, comme l'allocation fondée sur un identificateur (le serveur DHCP n'a pas forcément assez d'adresses IP pour tous ses clients potentiels.)
Bon, OK, le client DHCP envoie des tas d'identificateurs stables. Mais en quoi est-ce dangereux ? Qu'est-ce qu'un observateur indiscret peut en faire (section 5 du RFC) ? Déjà, il peut découvrir le type de machine qu'est le client (directement, via des options comme Vendor Class, ou indirectement, via l'adresse MAC (dont le préfixe, l'OUI, dépend en général du matériel utilisé). L'espion peut aussi trouver le système d'exploitation utilisé.
Il peut aussi apprendre les réseaux que le client avait visité précédemment. Le client met en effet dans l'option Requested IP Address la précédente adresse IP qu'il avait obtenue. Si c'est une adresse publique (pas issue du RFC 1918), cela renseigne sur le précédent réseau utilisé.
L'observateur peut facilement trouver un identificateur stable à partir d'une requête DHCP (en combinant les options comme Client FQDN). Cela lui permet, s'il a accès au trafic de plusieurs serveurs DHCP, de suivre les déplacements d'une machine (c'est ce qui se produit dans les cas de surveillance massive, cf. RFC 7258.)
Dans certains cas, l'observateur n'a même pas besoin d'être présent sur le réseau du serveur DHCP : si on fait des mises à jour dynamiques du DNS, il lui suffit de faire des requêtes DNS pour suivre les changements d'adresse IP (et donc de réseau) du client.
Bref, un client DHCP en dit en général trop à son serveur, et cela permet aux machines mobiles d'être facilement pistées. Notre RFC ne fournit pas de solutions immédiates, une solution est décrite dans le RFC 7844, d'autres feront l'objet d'un futur travail.
Date de publication du RFC : Mars 2016
Auteur(s) du RFC : S. Bortzmeyer (AFNIC)
Expérimental
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 23 mars 2016
La meilleure façon de protéger les données contre la surveillance, c'est de ne pas avoir de données. Ce principe de base de la protection de la vie privée est souvent oublié. C'est pourtant un des deux piliers de la confidentialité, avec la protection technique des données. Le DNS a pendant longtemps transmis trop de données, et ce RFC décrit une technique qui va limiter les fuites, la QNAME minimisation, ou « réduction de la question posée ». (Il a depuis été remplacé par le RFC 9156.) Demandez à votre FAI ou à votre service informatique de l'activer !
Si vous regardez les vidéos sur le fonctionnement du
DNS (comme celle-ci) ou lisez les textes expliquant « le
DNS pour les nuls », vous y trouverez souvent une fausse
explication de la résolution DNS, où les serveurs faisant autorité
ne reçoivent que la question strictement nécessaire. Ainsi, dans
la vidéo citée ci-dessus, le serveur de la
racine reçoit une question où ne figure que le
TLD. Mais la réalité du DNS, aujourd'hui,
est tout autre : les serveurs faisant autorité reçoivent la
totalité de question originale. Ainsi, si vous visitez
www.alcooliques-anonymes.fr
, la racine voit
que vous vous intéressez à l'alcoolisme, alors que ce n'était
nullement nécessaire pour son travail (puisqu'elle ne connait que
les TLD). Si votre logiciel
BitTorrent demande
_bittorrent-tracker._tcp.domain.example
, les
serveurs faisant autorité pour .example
sauront que vous faites du BitTorrent, alors qu'ils ne
connaissaient que les domaines situés immédiatement sous
.example
. Le RFC 7626
décrit plus en détail les problèmes de vie privée liés au DNS.
Dans le dernier cas, pour que la
résolution se passe bien, il aurait suffit de demander à la racine
« quels sont les serveurs de noms de .example
»
et à ces serveurs « quels sont les serveurs de noms de
domain.example
». C'est le principe de base
de la QNAME minimisation.
Bien sûr, on pourrait chiffrer le trafic DNS (et le groupe de travail DPRIVE de l'IETF travaille précisément sur ce sujet). Mais cela ne protège que contre un tiers écoutant le réseau : les serveurs faisant autorité verraient quand même les données et pourraient en faire ce qu'ils veulent. C'est pour cela qu'un principe de base en matière de protection de la vie privée est de marcher sur deux jambes (RFC 6973) : minimiser les données envoyées et les protéger. Lorsqu'on parle de vie privée, pas mal d'informaticiens réagissent en criant « cryptographie ! » alors que celle-ci ne protège pas contre tout et notamment pas contre le serveur à qui on parle.
Et pourquoi est-ce que les résolveurs DNS envoyaient la question complète (full QNAME où QNAME veut dire Query NAME) ? Uniquement parce que la protection de la vie privée n'était pas tellement prise en compte à l'époque ? Pas uniquement : il y avait quelques raisons techniques spécifiques à l'époque (le RFC les détaille mais, surtout, il ne faut pas oublier que toutes les décisions concernant le DNS n'ont pas forcément été mûrement réfléchies).
La section 2 décrit la QNAME minimisation. Elle est mise en œuvre dans le
résolveur DNS (aucun changement n'est fait
dans le serveur faisant autorité, la QNAME minimisation ne change pas le protocole DNS). Avant,
lorsqu'il recevait une requête demandant l'adresse
IPv6 pour
_foobar._tcp.sub.internautique.fr
et qu'il
connaissait les serveurs faisant autorité pour
.fr
, mais pas ceux
faisant autorité pour internautique.fr
, le
résolveur envoyait à l'AFNIC une requête
avec comme QNAME (Query NAME) le nom complet
_foobar._tcp.sub.internautique.fr
et comme
QTYPE (Query TYPE) AAAA
(indiquant une demande d'adresse IPv6). Désormais, le résolveur
moderne qui met en œuvre la QNAME minimisation
enverra une requête avec le QNAME
internautique.fr
et le QTYPE
NS
(demande des serveurs de noms). Plus
rigoureusement, la requête est faite avec un QNAME qui est
l'original, où on a retiré les premiers composants, jusqu'à un
seul composant de plus que celui pour lequel on connait les
serveurs faisant autorité.
Les experts en DNS ont noté un problème : il n'y a pas
forcément un jeu de serveurs faisant autorité pour chaque
composant. Si je prends
www.st-cyr.terre.defense.gouv.fr
, il n'y a
par exemple aujourd'hui pas de serveurs de noms pour
gouv.fr
, ce sont ceux de
.fr
. En termes
techniques, il n'y a pas de limite de zone (zone
cut, cf. RFC 2181, section 6) à
chaque composant. Dans le cas de ce dernier nom, il y a une limite
de zone entre la racine et .fr
, une autre
entre fr
et
defense.gouv.fr
mais pas entre
.fr
et gouv.fr
. Un
résolveur qui veut faire de la QNAME minimisation doit donc tenir compte des limites de
zone. S'il valide avec DNSSEC, pas de
problème, il les connait déjà, car leur connaissance est
nécessaire au bon fonctionnement de DNSSEC. Sinon, il doit les
trouver tout seul, par exemple avec l'algorithme de l'annexe
A.
Est-ce un changement « légal » du fonctionnement du résolveur DNS ? La section 4 discute ce problème et conclut que oui. La QNAME minimisation est permise par les RFC existants (RFC 1034, section 5.3.3 et RFC 1035, section 7.2). C'est un changement unilatéral de la part du résolveur, ne nécessitant pas de changement dans les serveurs faisant autorité. Comme c'est un changement unilatéral, différents résolveurs pourront choisir de la mettre en œuvre de façon légèrement différente. L'annexe B décrit certaines de ces alternatives, comme d'utiliser des requêtes « traditionnelles » avec le nom de domaine complet, au démarrage du résolveur, attendant que le cache soit peuplé pour passer à la QNAME minimisation, qui préserve la vie privée mais peut nécessiter davantage de paquets.
La QNAME minimisation ne change pas le protocole DNS. Elle ne pose donc pas de problème avec les vieux serveurs. En théorie car, en pratique, il existe pas mal de serveurs incorrects qui ne suivent pas les règles et poseront quelques problèmes (section 3 du RFC, voir aussi un intéressant exposé et un « storify » d'une discussion.) Le problème n'est en général pas dû aux serveurs en logiciel libre sérieux qui forment l'essentiel de l'infrastructure du DNS (BIND, NSD, Knot...) mais plutôt aux appliances boguées que certains s'obstinent à placer devant des serveurs qui marcheraient parfaitement autrement.
C'est par exemple le cas de certains répartiteurs de
charge qui répondent aux requêtes pour certains QTYPE
mais qui échouent lorsque le QTYPE vaut NS
(répondant, par exemple REFUSED
). Pire,
certains ne répondent pas du tout, comme ceux de
www.ratp.fr
.
Il s'agit bien d'une bogue, et qui cause plein de
problèmes, pas seulement à la QNAME minimisation.
Un autre problème est celui des serveurs bogués (comme
djbns) qui ne réagissent pas correctement aux
ENT. Qu'est-ce qu'un ENT ? Un Empty
Non-Terminal (terme décrit dans le RFC 8499, section 7) est un domaine qui n'a pas
d'enregistrements DNS mais qui a des sous-domaines qui en
ont. gouv.fr
, cité plus haut, est un ENT mais
ceux-ci sont particulièrement fréquents sous
ip6.arpa
. Normalement, la bonne réponse à un
ENT est le code NOERROR
, sans enregistrements
(ce qu'on appelle parfois NODATA
, bien que ce
dernier ne soit pas un code de retour explicite dans le
DNS). Mais certains serveurs boguées répondent à la place
NXDOMAIN
, code qui indique normalement que le
domaine n'existe pas (ce qui est faux). Voici ce que répond djbdns à une requête sur l'ENT
temporary.cr.yp.to
:
% dig A temporary.cr.yp.to ... ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 23636
C'est bien un ENT puisqu'il y a des noms en dessous (par exemple pairings.temporary.cr.yp.to
).
Le résolveur qui se
fierait à ce NXDOMAIN
croirait alors que sa
recherche est terminée et que le nom demandé n'existe pas. C'est
pour cela que les mises en œuvre existantes de la QNAME minimisation ont des comportements spécifiques pour les
réponses NXDOMAIN
, pour contourner cette
bogue.
La protection de la vie privée fait qu'on enverra moins de données. C'est bien le but. Résultat, les serveurs faisant autorité et les sniffeurs recevront moins d'information. Cela peut gêner certains gros silos de données, qui exploitaient cette information.
Et les performances ? Elles seront parfois meilleures et
parfois pires, avec la QNAME minimisation. Meilleures car le résolveur enverra
moins de requêtes aux serveurs faisant autorité. Aujourd'hui, si
un résolveur reçoit trois requêtes successives, pour
A.example
, B.example
et
C.example
, les trois requêtes seront envoyées
aux serveurs racine, et donneront toutes
les trois un NXDOMAIN
(puisque
.example
n'est pas délégué). Avec la QNAME minimisation,
seule la première requête déclenchera une demande à la racine,
pour le nom example
. Cela suffira au résolveur.
Par contre, les performances peuvent se dégrader dans certains
cas. Si un nom comporte beaucoup de composants (c'est
fréquent dans ip6.arpa
), la recherche
initiale des limites de zone nécessitera bien plus de
paquets. Ceci dit, cela ne durera que le temps de remplir le
cache, tout ira plus vite après, une fois que le résolveur
connaitra les limites de zone.
Ce RFC est issu du projet « DNS privacy », lancé initialement au CENTR, puis passé à l'IETF (le premier RFC de ce projet avait été le RFC 7626 ; comme lui, cette idée de QNAME minimisation était née dans un avion de la KLM).
À noter que Verisign a un brevet dont ils prétendent qu'il couvre la QNAME minimisation. Ils promettent une licence (attention, le diable est dans les détails) gratuite et non-discriminatoire. Ces brevets ont bien perturbé la réflexion du groupe de travail. Personnellement, je pense que ce brevet n'a pas de sens : l'idée de QNAME minimisation est évidente et avait déjà été discuté plusieurs fois, mais sans laisser de trace écrite précise, ce qui permet à Verisign de prétendre qu'il n'y a pas de prior art. Ce n'est sans doute pas un hasard si les deux premières mises en œuvre de la QNAME minimisation ont été faites en Europe, où il n'y a (normalement) pas de brevet logiciel. Ceci dit, lors des discussions sur la licence de ces brevets, en marge de la réunion IETF d'Honolulu, c'est Verisign qui a payé les boissons, reconnaissons-leur ce mérite.
La QNAME minimisation est mise en œuvre dans Unbound et
dans le résolveur
Knot (ce dernier n'étant pas encore officiellement publié).
Pour Knot (qui le fait par défaut), voici le résultat vu par tcpdump d'une requête
dig -x
d'une adresse
IPv6. Par exemple, le serveur racine n'a reçu
qu'une demande pour
.arpa
. Notez aussi que
Knot fait varier la casse (une protection
contre certains empoisonnements) :
02:36:39.673268 IP6 2400:8900::f03c:91ff:fe69:60d3.54216 > 2001:e30:1c1e:1::333.53: 38773% [1au] NS? aRpA. (33) 02:36:40.114074 IP6 2400:8900::f03c:91ff:fe69:60d3.59934 > 2001:dc3::35.53: 22056% [1au] NS? Ip6.aRPa. (37) 02:36:40.428545 IP6 2400:8900::f03c:91ff:fe69:60d3.47793 > 2001:500:86::86.53: 43002% [1au] NS? 2.ip6.arPA. (39) ...
Pour se protéger contre les serveurs bogués dont je parlais plus haut
(ceux qui répondent NXDOMAIN
en cas d'ENT), Knot
réessaie avec le QNAME complet lorsqu'il reçoit un
NXDOMAIN
(les deux dernières lignes). Mauvais pour la vie privée mais sans
doute nécessaire aujourd'hui (ici, par la faute d'Akamai) :
02:34:45.050913 IP 106.186.29.14.51228 > 128.175.13.17.53: 24014% [1au] A? WwW.UpENn.edU. (42) 02:34:45.227102 IP 128.175.13.17.53 > 106.186.29.14.51228: 24014*- 2/0/1 CNAME www.upenn.edu-dscg.edgesuite.net., RRSIG (270) 02:34:45.228413 IP6 2400:8900::f03c:91ff:fe69:60d3.46525 > 2001:503:231d::2:30.53: 52576% [1au] NS? edGeSUItE.NEt. (42) 02:34:45.297319 IP6 2001:503:231d::2:30.53 > 2400:8900::f03c:91ff:fe69:60d3.46525: 52576- 0/17/15 (1034) 02:34:45.298284 IP 106.186.29.14.45604 > 23.61.199.64.53: 22228 [1au] NS? EdU-DScG.EdGesUITe.nET. (51) 02:34:45.373238 IP 23.61.199.64.53 > 106.186.29.14.45604: 22228 NXDomain*- 0/1/1 (114) 02:34:45.373795 IP 106.186.29.14.34320 > 72.246.46.66.53: 1355 [1au] A? WWW.UPenN.edu-dSCG.EdgESuItE.net. (61)
Un autre exemple de ce repli sur les requêtes classiques est donné
ici, lorsque je demande
www.long.verylong.detail.example
. Comme le
TLD .example
n'existe pas,
Knot débraye hélas la QNAME minimisation :
20:08:49.615421 IP6 2400:8900::f03c:91ff:fe69:60d3.51723 > 2001:1398:1:21::8001.53: 19881% [1au] NS? ExaMpLE. (36) 20:08:49.900009 IP6 2400:8900::f03c:91ff:fe69:60d3.59917 > 2001:6d0:6d06::53.53: 40708% [1au] AAAA? www.LONg.VeRylONG.DEtaIl.eXamPLE. (61)
Même chose avec un ENT où la réponse est pourtant correcte. Knot se méfie et réessaie sans QNAME minimisation :
20:14:15.479872 IP6 2400:8900::f03c:91ff:fe69:60d3.45418 > 2001:67c:1010:11::53.53: 18200% [1au] NS? gOUV.Fr. (36) 20:14:15.740424 IP 106.186.29.14.33850 > 194.0.36.1.53: 54260% [1au] A? www.ST-cYr.TerRE.DeFeNSe.GouV.fR. (61)
Lorsque le cache commence à être rempli, Knot a besoin de moins de
requêtes. Ici, je lui ai demandé
l'adresse de www.bortzmeyer.org
, et il connaissait déjà les
serveurs de .org
, il passe
donc directement à la question « quels sont les serveurs de noms de
bortzmeyer.org
? » :
20:08:20.420757 IP 106.186.29.14.41889 > 199.249.120.1.53: 39126% [1au] NS? bOrtzMEYeR.oRg. (43) 20:08:20.941797 IP 106.186.29.14.35536 > 217.70.190.232.53: 33709% [1au] AAAA? Www.bOrtZmEyER.Org. (47)
Unbound a la QNAME minimisation depuis la version 1.5.7 (sortie en décembre 2015, cf. l'historique de ce travail). Ce n'est pas activé par défaut, il faut mettre dans la configuration :
server: qname-minimisation: yes
(Un pcap est disponible.)
Pour vérifier si votre résolveur met bien en œuvre la QNAME minimisation, vous
pouvez tester avec le domaine
qnamemintest.internet.nl
. Ici, le résolveur est un Unbound
récent :
% dig +nodnssec +short TXT qnamemintest.internet.nl a.b.qnamemin-test.internet.nl. "HOORAY - QNAME minimisation is enabled on your resolver :)!"
Avec un résolveur traditionnel (ici, Verisign Public DNS, qui utilise Unbound mais une vieille version) :
% dig @64.6.64.6 +nodnssec +short TXT qnamemintest.internet.nl a.b.qnamemin-test.internet.nl. "NO - QNAME minimisation is NOT enabled on your resolver :("
À noter qu'à la réunion de l'OARC à Buenos Aires, Ralph Dolmans a présenté un très intéressant exposé technique sur la mise en œuvre de la QNAME minimisation dans Unbound.
Questions articles sur la QNAME minimisation, notez celui de Robert Graham.
Date de publication du RFC : Mars 2016
Auteur(s) du RFC : M. Douglass (Spherical Cow
Group), C. Daboo (Apple)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tzdist
Première rédaction de cet article le 1 avril 2016
Ah, les fuseaux horaires... Quelle source infinie de complications pour le programmeur, pour l'administrateur système de machines situées partout dans le monde, ou tout simplement pour le voyageur ou l'organisateur de télé-réunions internationales... Comme tout serait plus simple si, comme dans le roman d'Asimov « Les cavernes d'acier », les hommes vivaient en permanence sous terre, utilisant un temps uniforme. Mais, en attendant ce futur béni, il faut bien gérer les fuseaux horaires (time zones). Il existe une base de données officielle de ces fuseaux, il ne reste plus qu'à la distribuer efficacement, pour que toute machine connectée à l'Internet ait la même information. C'est le but du protocole normalisé dans ce RFC.
Que contient une base de données des fuseaux horaires (section 1 du RFC) ? Typiquement une liste de ces fuseaux avec, pour chacun d'entre eux, son décalage par rapport à UTC et ses règles concernant l'heure d'été. Les fuseaux ne suivent pas strictement le méridien, ils collent en général à des frontières inter ou intra-étatiques. Les fuseaux eux-même, et leurs décalages avec UTC, sont très stables. Mais les règles concernant l'heure d'été changent, elles, souvent. Il y a aussi le problème des secondes intercalaires, qui sont ajoutées (ou, en théorie, retirées) par l'IERS de manière imprévisible (car la rotation de la Terre n'est pas prévisible). La base actuelle représente un travail d'érudition formidable.
Au passage, un point de terminologie. Le RFC parle de « time zone » là où on dit en général en français « fuseau horaire ». Le terme français n'est pas idéal car il fait penser à un fuseau allant d'un pôle à l'autre (et englobant donc des pays différents, ayant des heures d'été différentes) alors qu'une time zone est plus restreinte. Il faut donc bien se rappeler qu'on parle ici de zones limitées à un pays, et ayant des règles (décalage avec UTC, heure d'été) uniformes. Il faut donc peut-être mieux dire « zone » ou « zone horaire » en français.
Cette information est essentielle pour les protocoles et les
formats qui gèrent le temps, comme
iCalendar (RFC 5545),
ainsi que pour les systèmes
d'exploitation. Il faut donc maintenir à jour la base
de données et, jusqu'à ce RFC, il n'existait pas de mécanisme
standard pour cela. Par exemple, pour un système d'exploitation
comme Debian, la mise à jour se fait
typiquement via le mainteneur d'un paquetage « base des fuseaux
horaires » (chez Debian, le paquetage se nomme tzdata
), qui introduit les changements dans son paquetage,
paquetage qui est ensuite installé sur chaque machine lorsque
l'administrateur système décide des mises à jour. Si le système
est vieux et plus maintenu, ce sera à l'administratreur système
local de « patcher » ses fichiers. Parfois, des
paquetages viennent avec leur propre base des fuseaux horaires,
distincte de celle du système, pour compliquer un peu les choses.
Au passage, signalons que ce RFC normalise le protocole mais qu'il faut également disposer d'une source de données de référence. Il en existe une à l'IANA, décrite dans le RFC 6557.
La section 2 décrit à grands traits l'architecture du système. Tout en amont, des contributeurs envoient des données sur les fuseaux horaires, elles sont agrégées par le fournisseur de référence (root provider, par exemple l'IANA citée plus haut). Ce fournisseur l'envoie ensuite aux clients (par exemple par le protocole de ce RFC). Le schéma du RFC est un peu plus compliqué, supposant que divers intermédiaires pourraient apparaitre. Notez que le protocole décrit ici est entre fournisseur et clients. En amont (entre contributeurs et fournisseur), il n'y a pas de mécanisme spécifié.
La section 3 de notre RFC définit la terminologie. Une zone
(time zone) se caractérise donc par un ensemble
de règles uniformes. La zone a un nom (utilisé par exemple dans la
propriété TZID
du RFC 5545) mais il n'existe pas de norme pour cela. Chaque
fournisseur pourrait utiliser son schéma de nommage. Ainsi, la
base IANA utilise un nom de région, une
barre oblique et un nom de pays ou de ville comme
Europe/Paris
ou Indian/Cocos
. En tout
cas, il faut se méfier des abréviations ambigues, n'ayant souvent
qu'une signification locale, comme PST (qui peut désigner
trois
zones différentes).
L'information sur les zones change (autrement, on n'aurait pas besoin d'un protocole pour télécharger les mises à jour) et il est donc important d'avoir un numéro de version permettant de savoir si on a bien la dernière version. Il peut être global à la base, ou bien spécifique à chaque zone.
Maintenant, le protocole lui-même (section 4 du RFC). Il repose, comme souvent de nos jours, sur le couple « HTTP (RFC 7230) et JSON (RFC 8259) », ce dernier servant à représenter les méta-données sur les zones. Les ressources auxquelles on accède en HTTP utilisent les gabarits d'URI du RFC 6570. Et les données elle-mêmes, les informations sur une zone horaire, en quoi sont-elles codées ? Le format par défaut est celui d'iCalendar (RFC 5545). Mais on peut aussi utiliser la représentation en XML du RFC 6321 ou celle en JSON du RFC 7265. La classique négociation de contenu de HTTP (RFC 7231, section 5.3.2) sert au client à choisir son format parmi ceux que le serveur veut bien fournir.
La base peut être assez grosse et les clients vouloir la toute dernière version. La charge sur le réseau des fournisseurs risquerait alors de devenir insupportable. C'est pourquoi il est possible de faire des requêtes conditionnelles, de façon à ne récupérer des données que si elles sont nouvelles. Là encore, c'est du classique HTTP avec les Etags (RFC 7232). Un client peut alors interroger le serveur du fournisseur une fois par jour (valeur recommandée par le RFC) sans risque de saturer le réseau.
Si le client reçoit uniquement le décalage avec UTC et les règles pour l'heure d'été, calculer une heure dans le futur peut être délicat car ces règles sont complexes. Le protocole prévoit donc la possibilité pour le client de demander au serveur de faire ces calculs et de lui envoyer les résultats.
Et si ça ne marche pas, que le serveur, pour une raison ou pour une autre, ne peut pas envoyer ce qui lui est demandé ? Il doit alors utiliser les erreurs structurées du RFC 7807 pour signaler ce qui ne va pas. (Les types d'erreurs possibles figurent dans un registre IANA.)
Comment est-ce qu'un client de ce protocole trouve le serveur ?
Il doit de toute façon connaître le nom de
domaine de son fournisseur, supposons ici
example.net
. Ensuite, il y a au moins deux
méthodes :
_timezone._tcp.example.net
. Il obtiendra
ainsi le nom du serveur et le port à
utiliser. Un enregistrement supplémentaire, sous le même nom que
l'enregistrement SRV, de type TXT, indique un éventuel chemin à
ajouter dans l'URI..well-known
du RFC 8615, en faisant une requête HTTP pour la ressource timezone
.La section 5 du RFC décrit ensuite les actions que le serveur
peut effectuer à la demande. Elles sont spécifiées en utilisant
les gabarits du RFC 6570. Donc, par exemple,
un gabarit {/service-prefix}/capabilities
indique que le client doit ajouter
/capabilities
au préfixe de chemin découvert comme
indiqué précédemment. Prenons un exemple complet : le client sait
que son fournisseur de zones horaires est
example.net
. Il fait deux requêtes
DNS et obtient deux enregistrements :
_timezone._tcp.example.net. SRV 0 1 8081 tz.example.com. _timezone._tcp.example.net. TXT "path=/timezones"
S'il cherche à déterminer les capacités du serveur, il va alors
faire une requête à l'URL
http://tz.example.com:8081/timezones/capabilities
.
C'est quoi, ces capabilities que je viens
d'utiliser dans l'exemple ? C'est la première des actions
possibles sur un serveur. Comme son nom l'indique, elle renverra
un objet JSON contenant un membre
actions
qui sera la liste des actions
possibles sur ce serveur (avec, pour chacune, le gabarit d'URI à
utiliser). Une liste des actions standards possibles figure dans un
registre IANA.
L'action list
, elle, donne la liste des
zones horaires connues du serveur. Et l'action
get
renvoie les données pour une zone
précise. Son gabarit est
{/service-prefix,data-prefix}/zones{/tzid}{?start,end}
(tzid
étant l'identificateur de la zone, par
exemple Pacific/Noumea
)
et un exemple d'utilisation est :
[Requête] GET /timezones/zones/America%2FNew_York HTTP/1.1 Host: tz.example.com:8081 Accept:text/calendar [Réponse] HTTP/1.1 200 OK Date: Wed, 4 Jun 2008 09:32:12 GMT Content-Type: text/calendar; charset="utf-8" Content-Length: xxxx ETag: "123456789-000-111" BEGIN:VCALENDAR ... BEGIN:VTIMEZONE TZID:America/New_York ... END:VTIMEZONE END:VCALENDAR
Les codes d'erreur habituels de HTTP sont utilisés donc,
par exemple, si on demande un tzid
inconnu,
on récupérera un beau 404, mais avec le corps de la réponse en
JSON, suivant le RFC 7807 :
[Requête] GET /timezones/zones/Atlantid%2FPlutopolis HTTP/1.1 Host: tz.example.com:8081 Accept:text/calendar [Réponse] HTTP/1.1 404 Not Found Date: Wed, 4 Jun 2008 09:32:12 GMT Content-Type: application/problem+json; charset="utf-8" Content-Language: en Content-Length: xxxx { "type": "urn:ietf:params:tzdist:error:tzid-not-found", "title": "Time zone identifier was not found on this server", "status": 404 }
Il existe plusieurs autres actions, comme
expand
qui dit au serveur de faire les
calculs d'heure d'été lui-même, ou find
, qui
permet de chercher une zone par une partie de son nom.
Notez bien qu'il n'y a pas d'URI fixe et pré-déterminé pour les actions : il faut utiliser les gabarits pour les générer.
Les détails des objets JSON qui peuvent être renvoyés en réponse à ces actions figurent en section 6 de notre RFC.
Et la sécurité ? Elle est cruciale car, si on peut changer la connaissance qu'une machine a de l'heure, plein d'attaques deviennent possibles (fausser les estampilles temporelles dans les journaux, activer ou désactiver un certificat, etc). Il faut donc prendre soin d'utiliser un fournisseur fiable, et de récupérer la base de manière sécurisée. (HTTPS, forcément, et avec vérification sérieuse de l'identité du serveur, en suivant le RFC 6125 ou bien le RFC 6698).
Il n'y a apparemment pour le moment qu'une mise en œuvre, dans
le système de calendrier
Bedework. Je
ne connais pas encore de service disponible qui serve la base
de données suivant ce protocole (c'est pour cela que je ne montre
pas d'exemple réel). Notamment, l'IANA ne le fait pas (ce n'était
pas demandé dans le RFC). Il existe des services qui distribue la base,
mais avec un autre protocole, comme https://timezonedb.com/api
.
Date de publication du RFC : Mars 2016
Auteur(s) du RFC : M. Nottingham
(Akamai), E. Wilde
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 1 avril 2016
Lorsqu'on fait une requête HTTP, on récupère un code à trois chiffres qui indique notamment si tout s'est bien passé (si le code commence par 2, c'est bon, s'il commence par 4 ou 5, c'est qu'il y a un problème). Ces codes ne sont pas toujours assez fins et bien des API de services REST (donc reposant sur HTTP) voudraient des précisions. Plutôt que de créer un nouveau code, ce RFC propose un mécanisme qui permet d'envoyer du JSON normalisé indiquant tous les détails sur le problème survenu. (Ce RFC a depuis été remplacé par le RFC 9457.)
Les codes de statut de HTTP sont définis dans la section 6 du RFC 7231. Parmi les plus célèbres, on note 200 (qui veut dire que tout s'est bien passé) ou 404 (qui indique que le serveur n'a pas trouvé la ressource demandée). Si le serveur veut fournir des détails, il envoie traditionnellement de l'HTML dans le corps de sa réponse. Le navigateur Web peut alors l'afficher. Mais si la requête n'était pas envoyée par un humain derrière son navigateur, si elle venait d'un client REST ? HTML ne convient alors pas et il faut passer à une information analysable par une machine. C'est ce que fait ce RFC, qui définit deux formats, un en JSON (RFC 8259) et un en XML. Le client REST va donc avoir un résumé simple (le code de statut) et tous les détails nécessaires s'il le souhaite. « Comprenant » l'erreur exacte, le client pourra même, dans certains cas, la corriger.
Le RFC utilise surtout des exemples avec l'erreur 403 Forbidden mais j'ai préféré me servir de 402 Payment required. Ce code n'a jamais été clairement documenté (il est marqué « réservé pour un usage futur » dans le RFC 7231, section 6.5.3) et c'est sans doute pour cela que notre RFC ne l'utilise pas, mais je le trouve plus rigolo. Voici par exemple une page Web payante :
% wget https://www.bortzmeyer.org/faut-vraiment-payer.html --2016-03-26 15:54:00-- https://www.bortzmeyer.org/faut-vraiment-payer.html Resolving www.bortzmeyer.org (www.bortzmeyer.org)... 2001:4b98:dc0:41:216:3eff:fece:1902, 2605:4500:2:245b::42, 204.62.14.153 Connecting to www.bortzmeyer.org (www.bortzmeyer.org)|2001:4b98:dc0:41:216:3eff:fece:1902|:443... connected. HTTP request sent, awaiting response... 402 Payment Required 2016-03-26 15:54:00 ERROR 402: Payment Required.
On peut envisager plein de choses dans cette réponse analysable par une machine, comme un URI unique pour ce problème donné, qui pourrait être, par exemple, transmis au support pour faciliter la communication. Ou bien un URI d'un service REST de paiement permettant d'envoyer l'argent souhaité. Mais, naturellement, l'utilisation de cette réponse est facultative : parfois, le code de statut est suffisant et il n'y a rien à ajouter (c'est souvent le cas du 404), et parfois il vaut mieux utiliser un format spécifique à l'application utilisée (c'est d'ailleurs le cas pour toutes les API développées avant ce RFC). Ceci dit, pour les nouvelles applications, le mécanisme décrit dans ce RFC peut être très utile, pour doter toutes les applications d'un mécanisme commun de signalement des erreurs et problèmes.
Le modèle de données utilisé est celui de
JSON et le type MIME
est application/problem+json
. Comme je l'ai
dit plus haut, il y a aussi une version XML
mais la référence est le JSON. La section 3 du RFC décrit ce
modèle. Commençons par un exemple, une API qui demandait entre
autres d'indiquer un âge et à qui on a envoyé un nombre négatif :
HTTP/1.1 400 Bad Request Content-Type: application/problem+json Content-Language: en { "type": "https://example.net/validation-error", "title": "Your request parameters didn't validate.", "invalid-params": [ { "name": "age", "reason": "must be a positive integer" } ] }
Ce message d'erreur est de type
https://example.net/validation-error
, une
explication en langue naturelle est donnée par le membre
title
, et la liste des paramètres invalides
est donnée dans le membre (une extension à la norme) invalid-params
.
Quels sont les membres possibles de l'objet JSON renvoyé ?
type
est un
URI (il est donc unique) servant
d'identificateur au problème, par exemple lorsqu'on va écrire au support. Il est recommandé qu'il soit
déréférençable (c'est-à-dire qu'on puisse le visiter avec un
navigateur Web et obtenir des informations sur le problème en
question). S'il est absent, sa valeur par défaut est le très
vide about:blank
(RFC 6694, section 3).title
est un titre conçu pour des
humains, par exemple pour les messages d'erreurs présentés à l'utilisateur. Étant en
langue naturelle, il est, contrairement au
type
, ambigu. Il peut être
adapté à la langue de l'utilisateur, via l'habituelle
négociation de contenu de HTTP. detail
(absent dans l'exemple ci-dessus) le complète éventuellement. Le
RFC précise que detail
est fait pour
l'utilisateur, pas pour le programmeur qui a conçu le
service. Il devrait donc contenir des informations aidant
l'utilisateur à corriger sa requête, pas des informations de
débogage (pas de pile d'appels
Java, par exemple...) D'ailleurs, envoyer
ces informations de débogage poserait un problème de sécurité
(cf. section 5).instance
(absent dans l'exemple) est un URI qui,
contrairement à type
, n'identifie pas la
classe du problème mais une instance particulière. Si
http://example.com/not-enough-credit
indique la
classe « pas assez d'argent »,
https://example.com/account/12345/msgs/abc
va indiquer le problème d'argent d'un compte particulier.Notez que type
et
instance
peuvent être des URI relatifs.
Voici maintenant un exemple sur mon blog (c'est conçu comme une application REST donc les résultats sont toujours en JSON et, en effet, ce n'est pas en HTTPS, ce serait intolérable en production) :
% curl -v https://www.bortzmeyer.org/apps/payme ... < HTTP/1.1 402 Payment required ... < Content-Length: 253 < Content-Type: application/problem+json < { "type": "http://errors.bortzmeyer.org/nopay", "detail": "Bitcoin address 1HtNJ6ZFUc9yu9u2qAwB4tGdGwPQasQGax, Ethereum address 0xbe1f2ac71a9703275a4d3ea01a340f378c931740, Flattr https://flattr.com/profile/bortzmeyer", "title": "You must pay" } % curl -v https://www.bortzmeyer.org/apps/payme\?pay=30 ... < HTTP/1.1 200 OK < Content-Length: 36 < Content-Type: application/json < { "title": "OK, 30 credits paid" }
Le code Python WSGI correspondant est :
def payme(start_response, environ): form = cgi.parse_qs(environ['QUERY_STRING']) response_headers = [] amount = 0 if form.has_key("pay"): try: amount = int(form["pay"][0]) except ValueError: # Bad syntax amount = 0 if amount > 0: status = '200 OK' response_headers.append(('Content-type', 'application/json')) output = json.dumps({"title": "OK, %i credits paid" % amount}, indent=2) else: status = '402 Payment required' response_headers.append(('Content-type', 'application/problem+json')) output = json.dumps({"type": "http://errors.bortzmeyer.org/nopay", "title": "You must pay", "detail": "Bitcoin address 1HtNJ6ZFUc9yu9u2qAwB4tGdGwPQasQGax, Ethereum address 0xbe1f2ac71a9703275a4d3ea01a340f378c931740, Flattr https://flattr.com/profile/bortzmeyer"}, indent=2) response_headers.append(('Content-Length', str(len(output)))) start_response(status, response_headers) return [output]
Si vous n'avez pas ce que vous voulez dans les membres prévus,
vous pouvez étendre l'objet JSON. Les clients doivent donc ignorer
les membres inconnus. C'est le cas du
invalid-params
dans l'exemple, qui n'est pas
un membre standard.
Bien, maintenant, vous êtes programmeur dans une start-up, vous créez un nouveau
service qui a une API, un nom de domaine en
.io
, un
business plan pipeau et vous vous demandez si
vous devez utiliser ce RFC et comment. La section 4 du RFC fournit
quelques conseils. D'abord, je le répète, ce n'est pas un outil de
débogage pour vous, ne serait-ce que pour
des raisons de sécurité (cf. section 5). C'est un outil pour aider
vos utilisateurs. Ensuite, si le problème est un problème
classique et standard, il est inutile de se servir de ce RFC. Si
l'utilisateur demande une ressource qui n'existe pas, le
traditionnel et générique 404 (RFC 7231,
section 6.5.4) convient parfaitement et je ne vois pas de raison
d'ajouter des détails analysables par une machine (dans une page
HTML d'erreur, c'est différent, on peut
fournir des conseils aux visiteurs, mais rappelez-vous que ce RFC
est pour les API, quand le client est un programme).
D'autre part, une application peut avoir de très bonnes raisons d'utiliser un format à elle pour décrire en détail les problèmes. (Sans compter les applications existantes qui ne vont évidemment pas modifier la définition de leur API juste pour coller à ce RFC.)
En revanche, une application nouvelle, qui n'a pas de format d'erreur établi, a tout intérêt à utiliser le cadre de ce RFC plutôt que de réinventer la roue. Dans ce cas, vous allez devoir définir :
type
(le seul type prédéfini est about:blank
),invalid-params
plus haut).Ces extensions peuvent utiliser les liens de HTTP (RFC 8288).
Le format principal décrit par ce RFC utilise JSON. Mais, comme il y a des goûts différents, il y a aussi une variante XML, décrite dans l'annexe A. Elle est spécifiée en Relax NG. Le modèle de données étant le même, cela donne à peu près :
start = problem problem = element problem { ( element type { xsd:anyURI }? & element title { xsd:string }? & element detail { xsd:string }? & element status { xsd:positiveInteger }? & element instance { xsd:anyURI }? ), anyNsElement }
Et le résultat serait :
HTTP/1.1 400 Bad Request Content-Type: application/problem+xml Content-Language: en <?xml version="1.0" encoding="UTF-8"?> <problem xmlns="urn:ietf:rfc:XXXX"> <type>https://example.net/validation-error</type> <title>Your request parameters didn't validate.</title> <invalid-params><param><name>age</name><reason>must be a positive integer</reason></param></invalid-params> </problem>
On a presque fini, quelques petits mots sur la sécurité en section 5 : attention à ne pas laisser fuiter de l'information qui pourrait aider un attaquant à préparer son attaque. Il faut notamment se méfier des détails de mise en œuvre (du genre afficher la requête SQL qui a échoué...)
Les deux nouveaux types MIME,
application/problem+json
et
application/problem+xml
figurent désormais
dans le registre IANA.
Les développeurs d'API n'ont pas attendu ce RFC pour renvoyer des
messages d'erreurs structurés, utilisant d'autres schémas (voici, par
exemple, les erreurs possibles
de l'API Github). Un concurrent sérieux à ce RFC est, par
exemple,
qui a son propre mécanisme de
signalement d'erreur.
http://jsonapi.org/
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : F. Baker, R. Pan (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF aqm
Première rédaction de cet article le 21 avril 2016
Au cœur de l'Internet se trouvent les routeurs, et la façon dont ils traitent les paquets IP est cruciale pour le bon fonctionnement du réseau. C'est particulièrement important lorsque le trafic augmente et que les files d'attente dans les routeurs se remplissent. Que faire, alors ? Ce nouveau RFC discute des stratégies des routeurs confrontés à des files d'attente bien remplies.
Pas de « bonne » ou de « mauvaise » méthode dans ce RFC mais une discussion des possibilités. Il y a longtemps que le sujet est discuté, souvent avec des termes dangereux, car trop chargés, comme « juste » (qu'est-ce qui est juste ? Quels paquets jeter lorsque la file d'attente est pleine ? Les plus anciens ? Les plus gros ? Ceux venant de certains réseaux ?) Ainsi, le RFC 970 parle de gestion juste de la file d'attente... Le problème (à part la question de philosophie « qu'est-ce que la justice ? ») est que toute politique de gestion de la file d'attente peut entrainer des adaptations non souhaitées de la part des machines connectées au réseau (si on jette en priorité les paquets les plus gros, on encourage les machines à envoyer des paquets plus petits, comme dans le Silly Window Syndrome).
Sur la question de principe de l'équité ou de la justice, il faut toujours lire l'article de référence, « Flow Fairness: Dismantling a Religion ».
Historiquement, des modèles de trafic peu réalistes avaient été utilisés. Par exemple, certains modèles partent du débit moyen d'un flot tout au long de son existence et raisonnent là-dessus. Mais le trafic Internet est tout, sauf moyen. Il est plutôt en quanta, avec des sursauts brusques. Par exemple, une caméra va envoyer trente images par seconde et cela se traduira par beaucoup de données lorsqu'une nouvelle image est disponible, puis un silence d'un trentième de seconde avant l'image suivante.
Au passage, j'ai parlé de flot sans l'expliquer. Le terme est courant dans les discussions réseau mais souvent assez flou. Cela peut désigner une session du protocole de transport (identifiée par le fameux tuple à cinq éléments du RFC 2990), tous les paquets entre deux machines données, tous les paquets vers une machine donnée...
Autre question pratique dès qu'on discute d'équité entre les flots, comment est-ce qu'on la mesure, pour déterminer si elle est respectée ou pas ? Le RFC 7141, entre autres, se penche sur cette question.
Le gros du RFC est formé par la section 3, qui discute des outils habituels de gestion des paquets par les routeurs : mettre en file d'attente (queuing), marquer les paquets (marking) et les jeter (dropping). Tous ces outils sont indispensables (tant que la mémoire des routeurs sera finie, et donc les files d'attente n'auront pas une taille illimitée, il faudra parfois jeter des paquets) et sont interprétés par le reste du réseau comme des signaux indiquant l'approche ou le début de la congestion.
Ce RFC discute de divers concepts, il ne spécifie pas un algorithme. Pour un exemple d'algorithme récent de gestion des files d'attente des routeurs, voir FQ-Codel, même s'il ne suit pas forcément les avis du RFC (CoDel a été finalement publié dans le RFC 8289.)
Date de publication du RFC : Avril 2016
Auteur(s) du RFC : A. Zimmermann (NetApp), W. Eddy (MTI
Systems), L. Eggert (NetApp)
Pour information
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 11 avril 2016
Un peu de nettoyage dans l'imposante bibliothèque des RFC sur le protocole TCP. Bien des extensions à TCP n'ont jamais connu de déploiement réel dans la nature et d'autres, qui ont été déployées, ne sont plus utilisées depuis longtemps. Un grand nombre de RFC sont donc reclassifiés « intérêt historique seulement » ou bien « pour information ». Cela concerne surtout des vieux RFC, qui étaient bien oubliés de toute façon.
Le RFC 7414 (le guide des normes sur TCP) avait déjà fait cette classification mais sans mentionner le changement de statut dans la base de l'éditeur des RFC. C'est désormais chose faite. Il y a aussi des RFC très anciens qui n'avaient jamais été classés comme le RFC 675, la première norme TCP, à l'époque où les RFC n'avaient pas de statut clair. Remplacé par le RFC 793 (avec des modifications sérieuses du format des paquets), ce RFC 675 est désormais « intérêt historique seulement ». (À noter que le précédent grand nettoyage de TCP était dans le RFC 6247.)
Dans la liste, le RFC 1078 (TCPMUX) a suscité quelques controverses car il est apparemment mis en œuvre dans certains systèmes d'exploitation (la partie serveur, pas la partie client, qui semble absente). On ne peut donc pas le caractériser comme « non déployé ». Néanmoins, les failles, notamment de sécurité, de TCPMUX font que le RFC 1078 se retrouve lui aussi classé « intérêt historique seulement ». Notre RFC donne la liste des problèmes techniques qu'il pose.
Ce sort touche aussi des RFC récents comme le RFC 6013, proposition d'une ouverture de connexion TCP plus rapide et plus légère, publiée en 2011, implémentée, mais jamais déployée, et remplacée depuis par des RFC qui ont eu plus de succès comme le RFC 7413.
D'autres RFC sont seulement classés « pour information ». C'est le cas du RFC 700 car il ne décrivait pas un protocole mais était une analyse des premiers résultats du déploiement de TCP, ou du RFC 814, un important document de réflexion sur des concepts comme les adresses, les ports et les routes, toujours d'actualité, mais qui n'avait jamais reçu de classement auparavant. Parmi les autres RFC désormais classés, le RFC 889, qui était également un compte-rendu d'expérience sur la variation de certains paramètres numériques de TCP, comme le délai maximal d'attente. Faisons enfin une place à part pour le très utile RFC 1071 qui n'est pas abandonné, bien au contraire, juste classé comme « pour information ».
Date de publication du RFC : Mars 2016
Auteur(s) du RFC : V. Dolmatov (Research Computer Center MSU)
Pour information
Première rédaction de cet article le 25 mars 2016
Encore un algorithme de cryptographie venu de l'Est, avec cette spécification sous forme de RFC d'un algorithme GOST, connu sous le petit nom de « Kuznyechik » (dans la transcription anglo-saxonne), et, plus formellement, sous celui de GOST R 34.12-2015. C'est un algorithme de chiffrement symétrique par blocs.