Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

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.


RFC 7999: BLACKHOLE Community

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


Téléchargez le RFC 7999


L'article seul

RFC 7998: "xml2rfc" Version 3 Preparation Tool Description

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.


Téléchargez le RFC 7998


L'article seul

RFC 7997: The Use of Non-ASCII Characters in RFCs

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

L'encodage de ces caractères sera bien sûr UTF-8.

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&#x010D;e&#x017D; 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.


Téléchargez le RFC 7997


L'article seul

RFC 7996: SVG Drawings for RFCs: SVG 1.2 RFC

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 : simple-rfc-picture

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 : tcp-header Et le schéma de la communication SIP du RFC 4321 fera rfc4321-fig3.svg

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 network-schema-svgwrite

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.


Téléchargez le RFC 7996


L'article seul

RFC 7995: PDF Format for RFCs

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 https://tools.ietf.org/) n'était, lui, qu'une simple « impression » du RFC en texte brut.

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.


Téléchargez le RFC 7995


L'article seul

RFC 7994: Requirements for Plain-Text RFCs

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


Téléchargez le RFC 7994


L'article seul

RFC 7993: Cascading Style Sheets (CSS) Requirements for RFCs

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 :

  • Coller aux marquages sémantiques du RFC 7992,
  • Permettre l'accessibilité même aux gens en situation de handicap, comme décrit dans les « Best Practices for Authoring HTML »,
  • Permettre l'utilisation de petits écrans (ce qu'on appelle à tort les mobiles, alors que certains mobiles ne posent aucun problème particulier, car ils ont de grands écrans). Normalement, depuis le tout début du Web, c'est fait automatiquement, car le Web a toujours été prévu pour spécifier un contenu, pas une apparence. Mais certains pratiques ont mené à des pages Web très encombrées, difficiles à réduire automatiquement, ce qui a mené au mouvement du responsive design,
  • Permettre l'utilisation d'écritures diverses, pas juste l'alphabet latin, les RFC permettant désormais des caractères non-ASCII (cf. RFC 7997).

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 :

  • Le code source et les exemples de déroulement d'un protocole réseau seront en chasse fixe, ainsi que l'art ASCII,
  • Le texte devra se réagencer selon la taille de l'écran (ce qui devrait quand même aller de soi quand il s'agit de Web !),
  • Les paragraphes auront un identificateur qui devra être affiché lorsque le pointeur (par exemple la souris) passe au-dessus d'eux,
  • La police par défaut pour l'écran sera sans empattement, inclura Unicode, et sera disponible pour tous les navigateurs importants, avec une licence la rendant disponible.

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


Téléchargez le RFC 7993


L'article seul

RFC 7992: HTML Format for RFCs

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.


Téléchargez le RFC 7992


L'article seul

RFC 7991: The "xml2rfc" Version 3 Vocabulary

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 (&lt; 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.


Téléchargez le RFC 7991


L'article seul

RFC 7990: RFC Format Framework

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

  • Format canonique : le format de référence, archivé, utilisé en cas de conflit (XML, donc). Il est important d'en avoir un, au cas où une bogue dans les logiciels change une partie d'un RFC.
  • Formats de publication : les divers formats sous lesquels est publié le RFC (détaillés en section 7). Peu de gens liront le RFC en XML (quoique cela soit possible, une propriété qui est importante pour la conservation à long terme). Ils liront de l'HTML, du PDF, voire du texte seul pour les traditionnalistes. Tous ces formats seront produits (de préférence automatiquement) à partir du format canonique. Chacun a ses avantages et inconvénients (section 5). Par exemple, HTML avec JavaScript fournit des capacités de navigation bien meilleures que le texte brut.
  • Format révisable : le format que le RFC Editor utilisera pour son travail interne. Ce sera XML.
  • Format de soumission : le format sous lequel le texte sera transmis initialement par les auteurs au RFC Editor. Aujourd'hui, le texte brut est obligatoire, le XML autorisé en prime. Demain, ce sera du XML, mais avec des exigences moins strictes que pour le format canonique.

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 :

  • Le langage sera du XML avec le vocabulaire spécifié dans le RFC 7991 (nommé « v3 »). Il est normalement meilleur que les précédents vocabulaires utilisés depuis le RFC 2629.
  • Les auteurs pourront envoyer leur draft en suivant le format dit « v2 » (celui du RFC 7749), voire en texte brut, mais il sera ensuite converti dans le format v3 ci-dessus.
  • Le SVG sera autorisé dans le source XML.
  • Comme en v2, DTD est abandonné, la description officielle du schéma XML est en Relax NG.
  • Les textes obligatoires (RFC 5741) seront automatiquement insérés.
  • Le source XML du format canonique sera autonome. Cela veut dire qu'il n'aura pas de références à des sources extérieures. Ainsi, si un auteur référence un code source externe avec <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.
  • Il n'y aura pas de commentaires ou de processing instructions dans le source XML. Si l'auteur en a mis, ils seront retirés.

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.


Téléchargez le RFC 7990


L'article seul

RFC 7979: Response to the IANA Stewardship Transition Coordination Group (ICG) Request for Proposals on the IANA Protocol Parameters Registries

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 :

  • Les registres des paramètres de protocole sont dans le domaine public (ils sont un « bien commun ») et doivent le rester, quels que soient les changements futurs.
  • S'il y a un changement, il faudra que l'ICANN et le nouvel opérateur travaillent ensemble à rendre la transition la plus invisible possible.

Et le RFC réaffirme les principes que l'IAB avait posé en mars 2014 :

  • La « communauté technique Internet » se débrouille très bien à l'heure actuelle et n'a pas besoin d'intervention extérieure.
  • L'enregistrement des paramètres techniques des protocoles doit reposer sur l'ouverture, la transparence et la redevabilité.
  • Tout changement devrait respecter les textes et les accords existants (jolie façon de dire qu'aucun changement n'est souhaité).
  • Les registres des paramètres techniques des protocoles et les autres registres (comme les RIR pour les adresses IP) sont essentiels, et fonctionnent aujourd'hui correctement.
  • L'IETF va continuer dans son rôle.
  • La gestion des registres des paramètres techniques est un service public.

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 :


Téléchargez le RFC 7979


L'article seul

RFC 7971: Application-Layer Traffic Optimization (ALTO) Deployment Considerations

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 :

  • L'origine de l'information (celle qui a compilé les informations de topologie, par exemple en commençant par lister les préfixes IP connus),
  • Le serveur ALTO, qui va distribuer cette information,
  • Le client ALTO, qui va la récupérer,
  • L'application (resource consumer, dans le RFC), qui va en faire quelque chose d'utile.

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.


Téléchargez le RFC 7971


L'article seul

RFC 7970: The Incident Object Description Exchange Format Version 2

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 avantivirus, os-logjournal, 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 :

  • Meilleure internationalisation (voir à ce sujet la section 6 du RFC), comme le fait que la classe Contact permette désormais d'indiquer une adresse postale en un jeu de caractères quelconque,
  • Nouvelles classes (comme 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.


Téléchargez le RFC 7970


L'article seul

RFC 7962: Alternative Network Deployments: Taxonomy, Characterization, Technologies, and Architectures

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 :

  • De grande taille, par exemple à l'échelle d'un pays,
  • Gestion du réseau centralisée : tout part d'en haut,
  • Gros investissements dans l'infrastructure,
  • Les utilisateurs sont de purs consommateurs : ils n'ont absolument pas leur mot à dire, et, la plupart du temps, ils ne reçoivent aucune information, ils ne savent pas ce qui se passe dans le réseau qu'ils utilisent.

Et les réseaux « alternatifs », comment se définissent-ils (section 1.2) ? C'est plus difficile car il en existe de nombreuses variantes :

  • En général de petite taille, par exemple à l'échelle d'une région,
  • La gestion du réseau n'est pas forcément centralisée,
  • Les frais d'infrastructure peuvent être très répartis (les utilisateurs en paient parfois un bout, des infrastructures publiques peuvent être utilisées, etc),
  • Les utilisateurs ne sont pas forcément de purs consommateurs, ils peuvent être partie prenante à la gouvernance du réseau, et/ou à son fonctionnement technique.

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 :

  • Nord et Sud (« global north » et « global south ») sont utilisés pour parler, d'une part des pays riches (même si certains, comme l'Australie, sont au Sud) et des autres. Ce ne sont pas des termes parfaits mais aucun ne l'est.
  • Fracture numérique : la différence d'accès à l'Internet entre les favorisés et les autres. Elle n'est pas seulement entre pays, elle peut aussi être à l'intérieur d'un pays.
  • Zones « rurales » et « urbaines » : les définitions officielles vont varier selon les pays mais, en gros, il est plus difficile de convaincre les opérateurs à but lucratif de venir dans les zones à faible densité de population (zones « rurales »).
  • « Réseau libre » (Free Network) : c'est un terme délicat, car politiquement chargé, mais notre RFC reprend la définition de la Free Network Foundation. Dans un réseau libre, on peut utiliser le réseau librement (la liberté s'arrêtant évidemment là où commence la liberté des autres, donc pas le droit de faire des DoS par exemple), comprendre comment il marche (pas de secrets) et on peut soi-même fournir des services au-dessus de ce réseau.

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 :

  • La disponibilité de connexions internationales (ce n'est pas tout de se connecter entre soi, il faut aussi se relier au reste du monde), et de matériel,
  • Les problèmes d'alimentation électrique,
  • Le contexte légal. Ici, le RFC reprend telle quelle l'idéologie répandue à l'ISOC comme quoi la régulation, c'est mal, et qu'il faut tout privatiser.

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.


Téléchargez le RFC 7962


L'article seul

RFC 7960: Interoperability Issues between Domain-based Message Authentication, Reporting, and Conformance (DMARC) and Indirect Email Flows

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


Téléchargez le RFC 7960


L'article seul

RFC 7958: DNSSEC Trust Anchor Publication for the Root Zone

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.


Téléchargez le RFC 7958


L'article seul

RFC 7955: Management Guidelines for the Locator/ID Separation Protocol (LISP) Endpoint Identifier (EID) Block

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

  • Ce préfixe est expérimental et les allocations sont donc temporaires. N'espérez pas garder éternellement votre joli préfixe sous 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.
  • Les allocations doivent être renouvelées tous les ans, afin de s'assurer que le titulaire est toujours actif dans le banc de test LISP. (C'est bien un renouvellement, pas une nouvelle allocation, on conserve le même préfixe.)
  • Les préfixes abandonnés ne sont pas réutilisés, autant que possible, ou alors en attendant au moins une semaine.
  • Une organisation peut avoir plusieurs sous-préfixes.
  • Premier arrivé, premier servi.

Quelles sont les règles que suivra le registre de 2001:5::/32 (section 5) ?

  • Suivre les règles habituelles des registres d'adresses IP : collecter et archiver l'information envoyée par le titulaire, et la rendre accessible (par exemple via whois).
  • Gérer les noms de domaine dans ip6.arpa correspondants au préfixe géré.
  • Allouer un sous-préfixe à quiconque le demande, sous seule condition qu'il fournisse les informations demandées dans la section suivante.

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


Téléchargez le RFC 7955


L'article seul

RFC 7954: Locator/ID Separation Protocol (LISP) Endpoint Identifier (EID) Block

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 9300) 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 :

  • Identifier facilement le fait qu'une destination est accessible via LISP, et qu'on peut donc chercher son localisateur dans les tables de correspondance (RFC 9301). Actuellement, on ne peut pas savoir à l'avance, il faut demander au système de correspondance, peut-être pour rien.
  • Ainsi, si un routeur gère à la fois des destinations LISP et non-LISP (par exemple pour faire de l'ingénierie de trafic), cela lui permettra de ne pas pénaliser le trafic non-LISP, qui pourra être transmis immédiatement.
  • Si on souhaite traiter différemment le trafic LISP et le trafic non-LISP, cela dispensera d'utiliser du DPI pour le reconnaitre.
  • L'avantage précédent s'applique aussi au cas où on veut filtrer/bloquer l'un des deux trafics.
  • Cela facilitera la numérotation des réseaux qui sont mixtes : le ou les préfixes alloués pour l'IP traditionnel ne seront pas affectés, le réseau qui voudra faire du LISP prendra ses identificateurs dans 2001:5::/32 au lieu de devoir découper une partie de son espace d'adressage.
  • Conséquence : moins de fragmentation de l'espace d'adressage, et moins de routes dans la DFZ.

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 :

  • Cela fait assez de préfixes pour le réseau de test LISP actuel (qui a environ 250 sous-préfixes /48), et pour ce qu'on peut envisager dans les prochaines années.
  • C'est cohérent avec des expériences comme celle du RFC 3056.

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.


Téléchargez le RFC 7954


L'article seul

RFC 7950: The YANG 1.1 Data Modeling Language

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>

Outre pyang, il y a bien entendu même un mode Emacs, yang-mode.

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.


Téléchargez le RFC 7950


L'article seul

RFC 7948: Internet Exchange BGP Route Server Operations

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 :

  • Demander aux clients d'étiqueter les routes avec une communauté ordinaire (RFC 1997) ou bien une communauté étendue (RFC 4360). Attention, la taille limitée des valeurs des communautés ne permet pas d'y mettre deux numéros d'AS si ceux-ci sont sur quatre octets (RFC 4893). Comme exemple, regardez la politique des communautés BGP au France-IX.
  • Utiliser les politiques de distribution exprimées en RPSL (RFC 2622) dans les IRR.
  • Utiliser un IRR local au point d'échange, avec son interface spécifique pour y enregistrer des politiques. Cette posibilité est mentionnée par le RFC, mais quelqu'un connait un point d'échange qui fonctionne comme cela ? (Peut-être VIX et AMS-IX, à vérifier.)

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.


Téléchargez le RFC 7948


L'article seul

RFC 7947: Internet Exchange BGP Route Server

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.


Téléchargez le RFC 7947


L'article seul

RFC 7942: Improving Awareness of Running Code: The Implementation Status Section

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 :

  • Une description du programme,
  • L'organisation qui a développé le programme,
  • Un URL pour le téléchargement du programme, et les conditions de la licence (comme tous les points situés ici, il est facultatif : toutes ces mises en œuvre d'une norme IETF ne seront pas forcément en logiciel libre, ni même publiquement accessibles),
  • Le niveau de maturité du programme (une preuve que ça marche, vite faite en un week-end pour tester l'Internet-Draft, n'est pas la même chose qu'une version 1.0 testée et polie),
  • Le taux de couverture de la spécification par le programme (des mises en œuvre expérimentales peuvent sauter les parties les plus difficiles de la spécification...).

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.


Téléchargez le RFC 7942


L'article seul

RFC 7940: Representing Label Generation Rulesets Using XML

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 :

  • Doit pouvoir être programmé de manière raisonnablement directe (je n'ai pas essayé...)
  • Doit pouvoir être validé (l'ICANN, qui exige l'envoi d'une politique IDN pour les TLD qu'elle régule, peut ainsi tester automatiquement la validité de celles-ci). Notez aussi qu'un LGR sera développé pour la racine du DNS.
  • Doit pouvoir exprimer la notion de variantes (équivalence entre deux caractères, ou chaînes de caractère, par exemple entre les sinogrammes traditionnels et les simplifiés).
  • Doit pouvoir exprimer la notion de contexte (un caractère n'est valable que dans un certain contexte par exemple le sigma final grec, U+03F1 (ϱ) qui ne peut apparaître qu'en fin de mot).
  • Etc

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.


Téléchargez le RFC 7940


L'article seul

RFC 7937: Content Distribution Network Interconnection (CDNI) Logging Interface

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


Téléchargez le RFC 7937


L'article seul

RFC 7934: Host address availability recommendations

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 :

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 :

  • Délai supplémentaire avant de déployer un nouveau service sur la machine,
  • Risque qu'un problème survienne au cours de l'opération (tiens, c'était juste le jour où l'interface Web a un problème),
  • Complexité car il faut gérer une action en plus (pour laquelle il n'y a pas de mécanisme normalisé.)

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 :

  • Limites du matériel (TCAM limité en taille),
  • Souhait de garder une cohérence avec le style IPv4 (une adresse IP par machine, qui peut servir d'identificateur simple),
  • Volonté de faire payer par tous les moyens possibles, y compris par adresse IPv6 supplémentaire.

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 :

  • Naturellement, le moyen le plus simple est d'utiliser SLAAC (RFC 4862) : les routeurs annoncent les préfixes IP publics et chaque machine forme des adresses à volonté en utilisant ces préfixes. Comme SLAAC impose de détecter les éventuelles collisions, avant d'utiliser une adresse (RFC 4862, section 5.4), le risque que deux machines se retrouvent avec la même adresse est nul. C'est évidemment encore mieux si chaque machine a son propre préfixe /64, elle n'a même plus à tester les collisions.
  • On peut utiliser DHCP (RFC 8415). Le protocole permet de continuer à réclamer des adresses.
  • Et il y a aussi la délégation de préfixes IPv6 via DHCP (RFC 8415). Cela permet d'envoyer un /64 à chaque client, dont il fera ce qu'il voudra.

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 :

  • Il est recommandé que les hébergeurs et FAI qui déploient IPv6 permettent aux client d'avoir plusieurs adresses IP par machine.
  • Il est également recommandé qu'il n'y ait pas de limite stricte au nombre d'adresses utilisables.
  • Il est recommandé que cette allocation d'adresses supplémentaires puisse se faire sans requête explicite à l'hébergeur ou FAI.

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.


Téléchargez le RFC 7934


L'article seul

RFC 7929: DNS-Based Authentication of Named Entities (DANE) Bindings for OpenPGP

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 :

  • Le domaine de l'adresse de courrier (partie droite de l'adresse de courrier) est celui où on met les enregistrements DNS OPENPGPKEY. La clé pour l'adresse stephane+chose@trucmachin.example sera donc dans la zone trucmachin.example.
  • Le nom de domaine sera la concaténation d'un condensat de la partie gauche de l'adresse de courrier (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.)
  • En fait, la règle est plus compliquée en raison des équivalences entre certains caractères (voir les exemples plus loin). Une correspondance est donc faite pour certains caractères. (Ce fut l'un des points les plus discutés dans le groupe de travail à l'IETF.)
  • Par exemple, les guillemets (oui, "jipoune le meilleur"@example.com est une adresse de courrier légale) sont retirés.
  • La condensation de la partie gauche de l'adresse de courrier est faite en SHA-256 (RFC 5754). Cela permet une protection limitée (cf. section 7.4) de la vie privée : même si un méchant met la main sur tout le fichier de zone, il ne trouvera pas facilement toutes les adresses (qui sont des données personnelles). Mais le but principal de cette condensation est de résoudre le problème de certains caractères qui sont permis dans la partie locale d'une adresse de courrier, mais qui posent des problèmes dans le DNS.

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.


Téléchargez le RFC 7929


L'article seul

RFC 7927: Information-Centric Networking (ICN) Research Challenges

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 :

  • La circulation du trafic n'est pas optimale, puisque l'infrastructure du réseau (le routage, par exemple) ne peut pas optimiser pour le trafic des unités d'information,
  • Les capacités du réseau, par exemple en diffusion, ne sont pas ou peu utilisées,
  • Il n'est pas évident pour le réseau de savoir ce qu'il peut garder dans un cache local (le Web doit recourir à des CDN explicitement configurés),
  • La validation des données (la vérification de leur authenticité et de leur intégrité) n'est pas assurée par le réseau et doit utiliser d'autres mécanismes.

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 :

  • NDO (Named Data Object) : une unité de données ayant un nom,
  • Demandeur (requestor) : l'entité qui demande un NDO, en indiquant son nom,
  • Éditeur (publisher) : l'éditeur qui publie un NDO, le met en ligne. L'éditeur n'est pas forcément le créateur du NDO.

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 :

  • Le nommage d'objets qui n'existent pas encore (un flux vidéo filmé en temps réel, par exemple). On ne peut donc pas utiliser de condensat cryptographique. Mais peut-être un mécanisme à deux étapes, un structure de données non-cryptographique décrivant le contenu, qui serait elle-même condensée ?
  • La protection de la vie privée. Avec de l'ICN ordinaire, tout le monde voit à quel contenu vous accédez. Cela concerne même les équipements intermédiaires, puisque le but est justement que le réseau voit tout.
  • Nommer les nouvelles versions d'un objet. Un principe de base de l'ICN est que le nom désigne le contenu. On change une virgule à un texte, il faut un nouveau nom (c'est particulièrement évident pour les noms fondés sur un condensat cryptographique). Comment gérer la notion de « nouvelle version, légèrement modifiée » ? Une possibilité serait d'avoir des noms incluant un numéro de version, ce qui nécessiterait un mécanisme de résolution adapté (pour des opérations comme « je veux la dernière version »).
  • Restreindre l'accès dans certains cas. Le paradigme de l'ICN est que tout le monde a accès, ce qui permet aux éléments du réseau eux-même d'avoir accès à tout et, par exemple, de le mettre en cache. Si on veut des NDO à accès restreint, comment faire ? Les solutions de sécurité du monde réel, comme le chiffrement de bout en bout sont incompatibles avec le paradigme de l'ICN.

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 :

  • Les mécanismes d'agrégation permettant de réduire le nombre d'entrée dans la table de routage,
  • Si on utilise des noms hiérarchiques (par exemple /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 :

  • Placer ces caches sur le chemin des données (on-path caching), ou bien à côté, avec une redirection, comme avec les CDN actuels (off-path caching) ? Le cache sur le chemin est plus conforme aux principes d'architecture de l'ICN, mais il suppose des équipements capables de suivre tout le trafic, donc très rapides. Et ces équipements seront-ils rentabilisés ? Bien des contenus sont peu accédés et le cache ne servira donc pas autant qu'on ne pouvait l'espérer.
  • Combien d'équipements capable de gérer un cache faut-il placer ?
  • Comment gérer l'obsolescence ? Un contenu populaire va se trouver stocké dans de nombreux caches distribués un peu partout. Lorsque le contenu est modifié, ces caches auront une information obsolète. Il y a plusieurs approches pour ce problème. On les classe en général en approches directes, où l'information est stockée dans le NDO lui-même (par exemple une date d'expiration, après laquelle il faudra virer le contenu du cache), et approches indirectes, où on re-valide la fraicheur du contenu auprès du serveur original (ce qui suppose que son identité soit marquée dans le NDO). Les approches indirectes permettent de gérer le cas où la date d'expiration n'est pas connue à l'avance. Notez qu'un système où le nom change avec le contenu (comme les 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) :

  • Le Web semble un candidat évident, le paradigme « tout n'est qu'accès à du contenu » collant à peu près à une partie des usages du Web (en gros, les utilisations de la méthode HTTP 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.
  • La vidéo est typiquement un domaine où la pure consommation (on se contente d'accéder à du contenu) est très répandue. Elle semble donc un autre bon candidat pour l'ICN. Un autre document du groupe de recherche ICN de l'IRTF, le RFC 7933, étudie plus en détail cette application.
  • Et l'Internet des Objets ? L'article de Baccelli, E., Mehlis, C., Hahm, O., Schmidt, T., et M. Waehlisch, « Information Centric Networking in the IoT: Experiments with NDN in the Wild » étudie ses liens avec l'ICN. Par exemple, bien des applications IoT reposent sur un modèle PUSH, où l'objet envoie des données à son rythme, pas en réponse à une requête. Un tel modèle ne s'adapte pas 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.


Téléchargez le RFC 7927


L'article seul

RFC 7925: Transport Layer Security (TLS) / Datagram Transport Layer Security (DTLS) Profiles for the Internet of Things

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 :

  • Les rendre accessibles au programmeur, pas uniquement au système de base, de manière à ce que la mise en œuvre de TLS puisse bénéficier, par exemple, de l'AES présent dans le matériel, au lieu de devoir le réécrire en moins efficace.
  • Mais être souple, car un même algorithme cryptographique peut être utilisé de plusieurs façons. Ainsi, certaines mises en œuvre matérielles d'AES-CCM sont conçues pour Bluetooth avec un numnique de taille fixe, qui n'est pas celle utilisée par TLS, ce qui interdit leur réutilisation.
  • Penser à l'agilité cryptographique (la possibilité de changer d'algorithme cryptographique, pour suivre les progrès de la cryptanalyse). Par exemple, il faut se demander comment permettre à ChaCha20 (RFC 8439 et RFC 7905) de remplacer AES dans le futur.

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.


Téléchargez le RFC 7925


L'article seul

RFC 7920: Problem Statement for the Interface to the Routing System

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

  • Permettre des opérations asynchrones : pas question d'attendre la fin d'une opération avant de commencer la suivante.
  • Bonne granularité des opérations ; si on veut changer la configuration pour un préfixe IP, il ne faut pas verrouiller tout le routeur.
  • Possibilité que plusieurs clients parlent au routeur en même temps, avec le minimum de coordination entre eux.
  • Débit maximum élevé ; 10 000 opérations par seconde ne devraient pas être un problème.
  • Faible latence ; les opérations simples devraient pouvoir se faire en bien moins qu'une seconde (contrairement à, par exemple, un changement de configuration du routeur avec l'interface CLI des routeurs actuels, où le commit peut être très long).
  • Possibilité de filtrer l'information au départ du routeur, pour que l'application n'ait pas à tout récupérer avant le traitement.
  • Et, bien sûr, sécurité ; un système mettant en œuvre I2RS va pouvoir modifier la configuration du routeur, ce qui est potentiellement très dangereux. Il faut donc pouvoir authentifier et autoriser les accès.

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


Téléchargez le RFC 7920


L'article seul

RFC 7915: IP/ICMP Translation Algorithm

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. behave-xlate-stateless 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 ».


Téléchargez le RFC 7915


L'article seul

RFC 7914: The scrypt Password-Based Key Derivation Function

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


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


Téléchargez le RFC 7914


L'article seul

RFC 7908: Problem Definition and Classification of BGP Route Leaks

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.


Téléchargez le RFC 7908


L'article seul

RFC 7905: ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

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.


Téléchargez le RFC 7905


L'article seul

RFC 7901: CHAIN Query Requests in DNS

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 :

  • Ajouter à la réponse, dans la section Autorité, les enregistrements DNSSEC nécessaires (DS, DNSKEY et NSEC),
  • Mettre une 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).


Téléchargez le RFC 7901


L'article seul

RFC 7890: Concepts and Terminology for Peer to Peer SIP

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


Téléchargez le RFC 7890


L'article seul

RFC 7874: WebRTC Audio Codec and Processing Requirements

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

  • Opus (RFC 6716), avec le format du RFC 7587.
  • G.711, avec le format de la section 4.5.14 du RFC 3551.
  • La gestion du bruit de fond du RFC 3389. (Sauf pour Opus, qui a sa propre gestion.)
  • Le format 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.


Téléchargez le RFC 7874


L'article seul

RFC 7873: Domain Name System (DNS) Cookies

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 :

  • Si c'est le client qui est vieux, il n'envoie pas de cookie. Le serveur répond alors comme aujourd'hui. Les cookies ne posent donc pas de problème d'interopérabilité : vieux et récents logiciels peuvent cohabiter.
  • Si l'option EDNS cookie est présente, mais invalide (longueur inférieure à 8 octets, par exemple), le serveur répond FORMERR (FORmat ERRor).
  • Si la requête ne contient qu'un cookie client (client qui ne connaissait pas encore ce serveur), le serveur décide alors, selon sa politique à lui, de laisser tomber la requête (c'est violent, et cela implique de configurer le serveur avec les cookies des clients), d'envoyer un code d'erreur 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).
  • Il y a deux cookies dans la requête mais le cookie serveur est incorrect, par exemple parce que le secret utilisé par le serveur a changé. C'est parfaitement normal et cela n'indique, ni une erreur, ni une attaque, simplement qu'on ne peut pas authentifier le client. On répond donc comme dans le cas précédent (avec trois choix, dont seuls les deux derniers sont réalistes).
  • Il y a deux cookies dans la requête et le cookie serveur est correct. On a donc une certitude raisonnable que le client n'a pas usurpé son adresse IP (puisqu'il a reçu le bon cookie du serveur) et on va donc lui répondre. Les mesures de méfiance comme la limitation de trafic peuvent être débrayées pour cette requête.

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

Téléchargez le RFC 7873


L'article seul

RFC 7872: Observations on the Dropping of Packets with IPv6 Extension Headers in the Real World

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

  • L'en-tête de fragmentation, qui doit pouvoir passer si on veut que les paquets IP fragmentés arrivents (les principaux émetteurs de paquets IPv6 fragmentés sont sans doute les serveurs DNS, notamment avec DNSSEC, car UDP ne négocie pas la MSS).
  • L'en-tête « Options pour la destination » (Destination Options) qui, comme son nom l'indique, ne doit pas être examiné par les routeurs sur le chemin. Il contient des informations pour la machine terminale de destination.
  • L'en-tête « Options pour chaque intermédiaire » (Hop-by-Hop Options) qui, comme son nom l'indique, doit être examiné par les routeurs sur le trajet, il contient des informations pour eux.

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 :

  • Un avec en-tête d'extension Destination Options,
  • Un avec en-tête d'extension Hop-by-hop Options,
  • Un fragmenté en deux fragments d'à peu près 512 octets.

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

  • 12 % des serveurs n'ont pas reçu le paquet envoyé avec un en-tête Destination Options. Entre 18 % (optimiste) et 21 % (pessimiste) de ces pertes se sont produites avant l'AS de destination.
  • 41 % des serveurs n'ont pas reçu le paquet envoyé avec un en-tête Hop-by-hop Options. Entre 31 % (optimiste) et 40 % (pessimiste) de ces pertes se sont produites avant l'AS de destination.
  • 31 % des serveurs n'ont pas reçu le paquet fragmenté. Entre 5 % (optimiste) et 7 % (pessimiste) de ces pertes se sont produites avant l'AS de destination.

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.


Téléchargez le RFC 7872


L'article seul

RFC 7871: Client Subnet in DNS Queries

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 :

  • La famille d'adresses utilisée (IPv4 ou IPv6, l'exemple ci-dessus utilisait IPv4),
  • La longueur du préfixe indiqué dans la requête DNS (25 bits dans l'exemple ci-dessus),
  • La longueur significative du préfixe dans la réponse DNS (elle est mise à zéro dans les requêtes),
  • Le préfixe lui-même (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 :

  • La capacité de son cache : si le préfixe est trop spécifique, le cache devra stocker davantage de données (imaginons en IPv6 une réponse différente par adresse IP : le cache pourrait avoir à stocker 2^128 réponses par nom de domaine !)
  • La protection de la vie privée des utilisateurs. ECS la menace déjà, n'aggravons pas les choses. En utilisant un préfixe assez général, on limite l'indiscrétion.

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 :

  • La famille, la longueur du préfixe demandé, et le préfixe identiques à celui de la requête,
  • Une longueur effective (scope prefix length) qui indique pour quel préfixe la réponse est valable. Cette longueur effective peut être supérieure à la longueur demandée (le préfixe était trop général, pense le serveur), ou inférieure (le préfixe était inutilement spécifique, le serveur ne varie pas ses réponses à ce point).

(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 whoami​6.​fastly​.​net,
  • et mon 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)
    

Téléchargez le RFC 7871


L'article seul

RFC 7858: Specification for DNS over Transport Layer Security (TLS)

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 https://portal.sinodun.com/wiki/display/TDNS/DNS-over-TLS+test+servers veulent bien répondre.

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
  

Android a une mise en œuvre de DNS-sur-TLS (cf. ce commit).

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    

Téléchargez le RFC 7858


L'article seul

RFC 7857: Network Address Translation (NAT) Behavioral Requirements Updates

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


Téléchargez le RFC 7857


L'article seul

RFC 7855: Source Packet Routing in Networking (SPRING) Problem Statement and Requirements

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.


Téléchargez le RFC 7855


L'article seul

RFC 7854: BGP Monitoring Protocol (BMP)

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.


Téléchargez le RFC 7854


L'article seul

RFC 7848: Mark and Signed Mark Objects Mapping

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 &amp; 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.


Téléchargez le RFC 7848


L'article seul

RFC 7844: Anonymity profile for DHCP clients

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 :

  • Un tirage au hasard à chaque connexion à un réseau,
  • Un tirage au hasard pour chaque nouveau réseau mais on garde toujours la même adresse MAC pour un réseau donné,
  • Des changements de temps en temps, si on reste connecté sur des longues périodes. (Cela ne marchera pas en Wi-Fi où le changement d'adresse MAC nécessitera déconnexion/reconnexion donc peut-être changement d'adresse IP donc coupure des connexions TCP en cours.) Cette astuce n'est même pas forcément efficace : un observateur peut facilement noter le départ d'une machine et l'arrivée immédiate d'une autre, corrélant ces deux événements.

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 :

  • Dans le message DHCPDISCOVER, mettre les options « identificateur de client » et « paramètres demandés » mais rien d'autre. (Voir comme contre-exemple cette bogue de Tails.)
  • Dans un 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.


Téléchargez le RFC 7844


L'article seul

RFC 7842: Requirements for Improvements to the IETF Email List Archiving, Web-Based Browsing, and Search Tool

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 https://mailarchive.ietf.org/ 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 ») : mailarchive-ietf-general.png

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 : mailarchive-ietf-thread.png

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. mailarchive-ietf-ellipsis.png

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.


Téléchargez le RFC 7842


L'article seul

RFC 7841: On RFC Streams, Headers, and Boilerplate

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


Téléchargez le RFC 7841


L'article seul

RFC 7838: HTTP Alternative Services

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 :

  • Le serveur d'origine peut vouloir rediriger vers un serveur de secours si lui-même est sous forte charge, ou bien s'il sait qu'il existe un serveur plus proche de ce client particulier.
  • Le serveur d'origine peut rediriger le client vers une connexion sécurisée (avec HTTPS, cf. RFC 8164) ou vers un protocole plus moderne (HTTP 2, cf. RFC 7540).
  • Le serveur d'origine peut renvoyer certains clients à des serveurs spécialisés, par exemple pour le cas de clients ne gérant pas certaines options comme SNI (RFC 6066, section 3).

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.


Téléchargez le RFC 7838


L'article seul

RFC 7837: IPv6 Destination Option for Congestion Exposure (ConEx)

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

  • Les marques ConEx doivent être visibles par tous les nœuds ConEx du chemin (donc, pas question de les mettre tout au bout du paquet),
  • Pour que les paquets marqués arrivent à bon port, même en traversant les équipements actuels qui ne connaissent pas ConEx, il faut un mécanisme standard et déjà largement accepté (pas question de changer le format des paquets IP, cela empêcherait le déploiement incrémental),
  • La présence des marques ConEx ne doit pas ralentir le traitement des paquets (cf. section 5),
  • Les marques ConEx doivent pouvoir être protégées contre les manipulations ultérieures (exigence pas réellement satisfaite en pratique, sauf à utiliser IPsec).

Quatre solutions IPv6 avaient été envisagées par le groupe de travail à l'IETF :

  • Une option Hop-by-hop (RFC 2460, section 4.3).
  • Réutiliser le champ Flow label qui ne sert quasiment pas (cf. RFC 6437),
  • Créer un nouvel en-tête d'extension,
  • Une option Destination (RFC 2460, section 4.6), le choix qui a finalement été fait.

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


Téléchargez le RFC 7837


L'article seul

RFC 7835: Locator/ID Separation Protocol (LISP) Threat Analysis

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 9300. 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 9300, RFC 7215, RFC 6832, RFC 9301 et RFC 9302). 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 9300 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 ».)


Téléchargez le RFC 7835


L'article seul

RFC 7830: The EDNS(0) Padding Option

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


Téléchargez le RFC 7830


L'article seul

RFC 7828: The edns-tcp-keepalive EDNS0 Option

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.


Téléchargez le RFC 7828


L'article seul

RFC 7826: Real-Time Streaming Protocol Version 2.0

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 (RTPRFC 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.


Téléchargez le RFC 7826


L'article seul

RFC 7824: Privacy considerations for DHCPv6

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.

Également dangereuse, l'option Client FQDN (RFC 4704) qui envoie un FQDN.

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.


Téléchargez le RFC 7824


L'article seul

RFC 7819: Privacy considerations for DHCP

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 :

  • Allocation itérative : le serveur alloue les adresses IP dans l'ordre de la plage d'adresses dont il dispose. Elle est très simple et très rapide mais fournit des adresses IP qui sont très prévisibles. En outre, avec ce système, les premières adresses de la plage seront plus souvent utilisées, ce qui rendra encore plus facile des activités comme la reconnaissance d'un réseau avant une attaque.
  • Allocation fondée sur un identificateur : le serveur a une table et y cherche un des identificateurs transmis par le client, allouant l'adresse trouvée dans la table. C'est très pratique pour l'administrateur système, car une machine donnée aura toujours la même adresse IP. Mais c'est nettement moins bon pour la vie privée du client, qui sera ainsi trivialement pistable, par son adresse IP fixe.
  • Allocation aléatoire : le serveur DHCP prend au hasard une adresse IP libre. C'est sans doute la meilleure méthode, du point de vue de la protection de 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.


Téléchargez le RFC 7819


L'article seul

RFC 7816: DNS query name minimisation to improve privacy

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


Téléchargez le RFC 7816


L'article seul

RFC 7808: Time Zone Data Distribution Service

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 :

  • Utiliser les enregistrements SRV (RFC 2782), en demandant _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.
  • Ou bien utiliser les 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.


Téléchargez le RFC 7808


L'article seul

RFC 7807: Problem Details for HTTP APIs

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 :

  • L'URI qui servira de type (le seul type prédéfini est about:blank),
  • Le code de statut HTTP qui l'accompagne,
  • Les éventuelles extensions (comme le membre 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, http://jsonapi.org/ qui a son propre mécanisme de signalement d'erreur.


Téléchargez le RFC 7807


L'article seul

RFC 7806: On Queuing, Marking, and Dropping

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


Téléchargez le RFC 7806


L'article seul

RFC 7805: Moving Outdated TCP Extensions and TCP-related Documents to Historic and Informational Status

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


Téléchargez le RFC 7805


L'article seul

RFC 7801: GOST R 34.12-2015: Block Cipher "Kuznyechik"

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.

Comme d'autres algorithmes de cryptographie normalisés par GOST, Kuznyechik a été développé en partie par le secteur public (Service des communications spéciales et d'information du Service fédéral de protection de la Fédération de Russie) et par le secteur privé (InfoTeCS). Le décret n° 749 du 19 juin 2015, pris par l'Agence fédérale pour la régulation technique et la métrologie en a fait un algorithme russe officiel. C'est donc apparemment un concurrent d'AES.

Les sections 3 et 4 du RFC décrivent l'algorithme en détail. Pour les connaisseurs en cryptographie seulement, d'autant plus que le format actuel (c'est en cours de révision) des RFC n'est pas idéal pour décrire des mathématiques, il vaut mieux utiliser la version en anglais de la norme russe. Des vecteurs de test figurent en section 5.

Merci à André Sintzoff, qui sait utiliser Canard, canard, va.


Téléchargez le RFC 7801


L'article seul

RFC 7799: Active and Passive Metrics and Methods (with Hybrid Types In-Between)

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : A. Morton (AT&T Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 30 mai 2016


Dans le monde de la métrologie, il existe deux classes de mesures effectuées sur l'Internet : les mesures actives et les mesures passives. La signification de ces termes semble assez intuitive mais ce nouveau RFC fournit des définitions rigoureuses, qui n'étaient pas encore publiées. (Il y a aussi des mesures hybrides.)

Cela fait pourtant de très nombreuses années que ces deux termes sont largement utilisés. Par exemple, en 2000 s'est tenue une conférence « Passive and Active Measurement (PAM) ». Et les termes étaient certainement plus anciens.

En première approximation, on peut caractériser ces deux classes ainsi (section 1 du RFC) :

  • Une mesure active nécessite un envoi de paquets dédiés à cette mesure.
  • Une mesure passive ne dépend que des paquets qui seraient envoyés de toute façon, même si la mesure n'avait pas lieu.

Du point de vue des outils, on peut donc noter que les ultra-traditionnels ping et traceroute font des mesures actives et que tcpdump permet des mesures passives.

Mais, les choses étant plus compliquées dans la vraie vie des vrais réseaux, notre RFC va un peu plus loin que cela. Sa section 3 définit plus précisement les termes. Elle s'appuie sur des RFC précédents comme les RFC 2330 et RFC 6390 qui définissaient, par exemple, la notion de métrique (une grandeur qu'on mesure), ou comme le RFC 7011, qui définissait la notion de point d'observation. On s'appuie aussi sur des documents qui ne sont pas des RFC comme la norme UIT Y.1540 qui définit la notion de « population [de paquets] qui nous intéresse » (stream of interest) ou comme la norme UIT Y.1731.

Notez que les adjectifs « actif » et « passif » peuvent s'appliquer aux méthodes de mesure ou bien aux métriques.

Armé de ces définitions, on peut dire que les méthodes de mesure actives ont les caractéristiques suivantes :

  • La population de paquets qui nous intéresse est générée (synthétisée). Parfois un autre flux de paquets est généré, même si leur sort ne nous intéresse pas directement, par exemple pour générer de la charge.
  • Les paquets générés ont un contenu qui est spécifique à la mesure, qui n'a pas d'intérêt autrement. C'est par exemple le numéro de séquence dans les paquets ICMP (RFC 792) que génère ping, numéros qui permettent de faire correspondre une réponse à une question.
  • Source et destination des paquets sont connus a priori.
  • D'ailleurs, toutes les caractéristiques de la population sont connues à l'avance, ce qui facilite nettement l'observation. Parfois, certaines caractéristiques seront changées en route (comme le champ TTL dans l'en-tête IPv4).

Comme la mesure active introduit du trafic réseau qui n'existerait pas sans elle, elle perturbe le réseau qu'on veut mesurer. Un des défis importants des mesures actives est de minimiser cette perturbation ou, au minimum, de pouvoir quantifier cette perturbation pour l'indiquer comme marge d'erreur dans les résultats (section 4.1).

Une métrique active est simplement une métrique dont la définition inclut des méthodes actives. Par exemple, le type des paquets qu'on a injecté dans le réseau.

Les méthodes passives, par contre, ont ces propriétés :

  • Elles sont fondées sur l'observation de paquets non modifiés et non perturbés. Une méthode passive ne laisse aucune trace sur le réseau.
  • Elles ne sont donc utiles que s'il existe déjà des paquets intéressants, puisqu'elles n'en créent pas et n'en modifient pas.

Il faut faire attention en observant les paquets : comme on ne choisit pas leurs caractéristiques, on risque de ne pas voir le vrai phénomène, car on n'observait que le phénomène supposé. (Il m'est arrivé d'utiliser tcpdump pour observer un trafic LDAP et de filtrer sur l'adresse du serveur LDAP. Je ne comprenais pas pourquoi aucun trafic n'était visible. En fait, je ne capturais que les paquets IPv4 alors que le trafic se faisait en IPv6.)

Une observation passive peut se faire en un seul point, ou en plusieurs. Un exemple d'observation passive est ce que fait un routeur IPFIX (RFC 7011).

Une métrique passive est une métrique fondée uniquement sur l'observation passive. Par exemple, le temps de trajet entre deux points peut être formalisée dans une métrique passive : on observe le paquet à un point et à l'autre, et on en déduit le temps de son voyage.

Évidemment, dans le monde réel, les classifications ne sont pas toujours très simples. Par exemple, il existe des méthodes hybrides. Les « hybrides de type I » partent d'un flux de paquets existant mais le modifient, ou bien modifient le traitement qu'il subit. Par exemple, si on observe un flux existant mais qu'on envoie en même temps des données dans le réseau pour le charger, on est en présence d'une méthode hybride de type I. Les métriques spatiales du RFC 5644 sont un cas de métriques hybrides.

Et les hybrides de type II ? Le terme indique les méthodes où il y a plusieurs populations intéressantes générées activement (et d'autres qu'on observe passivement).

La section 4 de notre RFC discute de certains problèmes de métrologie et compare l'effet des méthodes et métriques actives ou passives. Par exemple, si on veut mesurer la capacité d'un lien, une méthode active serait de tenter d'envoyer le plus de données possible, une méthode passive d'observer le trafic et de regarder le débit maximum atteint. La première méthode va remplir le tuyau, gênant les applications en cours. La seconde risque de sous-estimer la capacité (si les machines sont lentes, elles peuvent ne pas réussir à remplir le tuyau.)

Au passage, l'importance des mesures est telle que l'IETF envisage un mécanisme de mesure instrumentant les paquets eux-mêmes : c'est l'option IPv6 PDM (Performance and Diagnostic Measurements, actuellement à l'état de projet), qui consiste à ajouter un nouvel en-tête d'extension aux paquets IP pour y noter les informations nécessaires aux mesures. Les mesures ainsi faites seraient plutôt des hybrides de type I. (On ajoute des données à des paquets existants.)


Téléchargez le RFC 7799


L'article seul

RFC 7793: Add 100.64.0.0/10 prefixes to IPv4 Locally-Served DNS Zones Registry

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : M. Andrews (ISC)
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 13 mai 2016


Il existe un registre des zones DNS qui doivent être gérées localement par le résolveur DNS et pour lesquelles les requêtes ne sont pas transmises aux serveurs de la racine. Ce nouveau RFC ajoute à ce registre les zones correspondant au préfixe IPv4 100.64.0.0/10, que le RFC 6598 avait réservé pour la numérotation des machines situées derrière les CGN.

Le but de ce registre est d'éviter de surcharger les serveurs racine avec des requêtes qui sont inutiles puisque les noms dans ces zones n'ont qu'une signification locale, et ne pourraient pas recevoir une réponse sensée de la racine. Le RFC 6303 avait donc créé ce registre des noms pour lesquels, par défaut, le résolveur DNS doit retourner NXDOMAIN (code indiquant que le nom n'existe pas) tout de suite. On y trouve par exemple la zone 10.in-addr.arpa, zone correspondant aux adresses IP du RFC 1918.

Le RFC 6598 avait réservé tout le préfixe 100.64.0.0/10 pour les CGN. Notre nouveau RFC met donc les zones 64.100.in-addr.arpa à 127.100.in-addr.arpa dans le registre des zones à servir localement. Au fur et à mesure des mises à jour des résolveurs (leur code, ou bien la configuration locale), toute requête PTR dans une de ces zones doit être traitée localement par le résolveur.

Ces zones sont déléguées aux serveurs de noms de l'IANA, pour attraper les requêtes qui ne suivent pas ces règles :

% dig +short NS 64.100.in-addr.arpa
a.iana-servers.net.
b.iana-servers.net.
c.iana-servers.net.

Sinon, aujourd'hui, par défaut, Unbound « délègue » ces zones à... localhost (si on veut un vrai contenu, il faut configurer explicitement ces zones) :

% dig +short NS 64.100.in-addr.arpa
localhost.
    
% dig +short  NS 64.100.in-addr.arpa 
64.100.IN-ADDR.ARPA.
    

Téléchargez le RFC 7793


L'article seul

RFC 7790: Mapping characters for PRECIS classes

Date de publication du RFC : Février 2016
Auteur(s) du RFC : Y. YONEYA (JPRS), T. Nemoto (Keio University)
Pour information
Réalisé dans le cadre du groupe de travail IETF precis
Première rédaction de cet article le 1 mars 2016


PRECIS (preparation, enforcement, and comparison of internationalized strings), décrit désormais dans le RFC 8264, est un cadre général pour l'internationalisation d'identificateurs sur l'Internet. Il expose un certain nombre de règles, parmi lesquelles les développeurs de protocoles Internet et d'applications vont pouvoir choisir, au lieu de partir de zéro à chaque fois. Ce nouveau et court RFC donne des indications aux concepteurs de nouveaux profils PRECIS sur les correspondances (mappings) à effectuer (par exemple, mais pas uniquement, entre des caractères majuscules et minuscules). Il n'est pas normatif : l'internationalisation est quelque chose de compliqué et il n'est pas facile d'obtenir un consensus. L'utilisateur indique un identificateur, en quoi peut-on le transformer ?

Au départ de cet identificateur, on trouve une saisie par l'utilisateur (clavier physique ou clavier virtuel), ou bien une sélection par ce même utilisateur (copier/coller depuis du texte, choix d'un signet, choix parmi les résultats d'un moteur de recherche...) À ce stade, l'utilisateur ne tient pas compte de certaines caractéristiques du texte, qu'il considère non pertinentes. C'est ainsi qu'il va ignorer la casse, ou bien la largeur du caractère (pour les caractères qui ont une version étroite et une version large comme le point d'exclamation, qui existe en U+0021, « ! » et U+FF01, « ! ») Il est donc souhaitable d'avoir une phase de correspondance (mapping) entre cette saisie ou cette sélection et le moment où l'identificateur est passé au programme. C'est lors que cette phase qu'on va, par exemple, tout mettre en minuscules, et remplacer les caractères larges par leur version étroite.

Pour le cas des noms de domaine (IDN), cette correspondance est déjà traitée dans le RFC 5895. Pour les autres identificateurs, le cadre PRECIS (PReparation, Enforcement, and Comparison of Internationalized Strings), dans le RFC 8264, s'en charge. Mais il ne traite qu'une partie des correspondances souhaitables (comme la casse) et il était donc souhaitable de l'étendre. C'est ce que fait ce nouveau RFC.

La section 2 de notre court RFC spécifie ces correspondances supplémentaires. Par exemple, les délimiteurs (comme le point). Chaque protocole et format a ses propres délimiteurs (@ pour le courrier électronique, / dans les URL, etc). L'idée est de faire correspondre les caractères qui ressemblent au(x) délimiteur(s) du protocole vers le caractère canonique. Ainsi, si un protocole utilise le point (U+002E) come délimiteur, et que le texte saisi par l'utilisateur contient un point idéographique (U+3002, alias « 。 »), il est logique de remplacer ces points par le point « officiel » du protocole.

Après la correspondance des délimiteurs, les « correspondances spéciales ». Le terme désigne des règles qui sont différentes des règles par défaut de PRECIS. Par exemple, supprimer les caractères de contrôle (pas les transformer en un autre caractère, non, les supprimer franchement) ou bien transformer des espaces différents du caractère espace d'ASCII en espaces ASCII (U+0020). C'est ce que font des protocoles comme EAP (RFC 3748) ou les ACL d'IMAP (RFC 4314).

Autre cas rigolo, celui où le changement de casse dépend de la locale, c'est-à-dire en général de la langue utilisée. L'exemple le plus fameux, toujours mentionné dans les discussions Unicode, vient du turc où la minuscule du I (U+0049) n'est pas i (U+0069) mais ı (U+0131, et encore, la règle exacte est un peu plus compliquée). Comme PRECIS est conçu pour des protocoles Internet, qui ne connaissent pas la langue, les applications (qui, elles, connaissent souvent la langue de leur utilisateur) doivent traiter ce cas, avant de passer l'information sur l'Internet (voir aussi l'annexe B et C, pour des cas spéciaux dans le cas spécial).

L'annexe A de notre RFC résume dans un tableau ces correspondances selon divers protocoles (IDN, iSCSI, EAP, etc).


Téléchargez le RFC 7790


L'article seul

RFC 7788: Home Networking Control Protocol

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : M. Stenberg, S. Barth (Independent), P. Pfister (Cisco)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF homenet
Première rédaction de cet article le 23 avril 2016


Ce nouveau protocole, HNCP (Home Networking Control Protocol), est conçu pour la domotique. Son rôle est de distribuer de l'information de configuration (les services comme celui d'impression, par exemple) à toutes les machines de la maison. C'est un profil (une instance particulière) du protocole DNCP du RFC 7787.

Cet HNCP est issu du projet Homenet, visant à créer à la maison des réseaux non gérés (M. Michu a autre chose à faire) et non limités à un seul lien (donc, avec des routeurs). L'architecture d'Homenet est décrite dans le RFC 7368. Dans ce cadre Homenet, HNCP doit permettre de :

  • découvrir les frontières du réseau (qu'est-ce qui est extérieur et qu'est-ce qui est intérieur), ce qui sera nécessaire pour la sécurité,
  • distribuer les préfixes IP (RFC 7695),
  • fournir l'accès à un service de résolution de noms.

HNCP n'est pas un protocole de routage (quoique on puisse considérer que le routage, c'est distribuer de l'information de configuration, mais HNCP n'est pas prévu pour cela), il faut l'utiliser avec un protocole de routage comme Babel (RFC 8966).

Comme HNCP est un profil de DNCP, il en hérite les caractéristiques (RFC 7787). Par exemple, il n'est pas adapté à de l'information très changeante. C'est pour cela que, pour la résolution de noms, HNCP distribue les adresses des serveurs de noms, mais n'assure pas cette fonction lui-même.

Le RFC sur DNCP décrit les points laissés libres dans DNCP et qu'un profil de DNCP doit spécifier (RFC 7787, section 9). La section 3 de notre RFC sur HNCP précise ces points :

  • HNCP est transporté sur UDP, port 8231, sur IPv6, bien sûr.
  • Le trafic est sécurisé par DTLS, port 8232.
  • HNCP ne marche que sur des réseaux capables de multicast, comme Ethernet (ce qui permet de découvrir les voisins facilement). Il est recommandé que l'identificateur d'interface soit dérivé de l'adresse IPv6.
  • L'identificateur de chaque nœud du réseau est choisi au hasard. (En cas - improbable - de collision, on recommence avec un nouvel identificateur.)
  • La fonction de condensation utilisée est MD5 (RFC 1321).
  • Les paramètres Trickle (RFC 6206) sont k=1, Imin=200ms, Imax=7.

Je n'ai pas d'expérience pratique avec HNCP donc je vais passer rapidement sur le reste du RFC. Parmi les points amusants à noter :

  • HNCP permet la configuration complète des adresses IP (section 6). Les nœuds situés aux frontières du réseau domestique apprennent du FAI les préfixes IP publics à utiliser (par exemple en DHCP, cf. RFC 8415), et les diffusent en HNCP. L'algorithme du RFC 7695 est utilisé pour répartir ces préfixes en sous-préfixes pour les différents liens (rappelez-vous que HNCP permet d'avoir un réseau domestique composé de plusieurs liens séparés par des routeurs.)
  • Les adresses IP des nœuds sont typiquement attribuées par le mécanisme du RFC 7217, qui dérive une adresse d'un certain nombre de paramètres du réseau local et de la machine qui se configure. (Ce qui permet d'avoir des adresses IP stables mais imprévisibles et qui ne permettent pas de traçabilité quand on change de réseau.) Les machines non-HNCP (section 7) sont, elles, configurées par les moyens classiques, comme SLAAC (RFC 4861).
  • La résolution de noms et la découverte des services sont évidemment des fonctions essentielles. L'utilisateur ne s'amuserait pas s'il devait manipuler des adresses IPv6. Chaque routeur HNCP fournit un nom pour les réseaux qu'il gère et le diffuse en HNCP. Il a aussi un nom pour lui-même. Le suffixe utilisé était .home, remplacé depuis par home.arpa par le RFC 8375.

Comme tous les protocoles instanciés à partir de DNCP, HNCP transporte l'information sous forme de TLV (section 10). Ces TLV peuvent être emboîtés (un sous-TLV dans la partie Valeur d'un TLV). Parmi les TLV possibles (la liste complète est dans un registre IANA), on trouve :

  • « Version HNCP », type 32, qui permet d'indiquer aux voisins quelle version de HNCP on gère. Cela ne se fait pas sous forme d'un numéro de version mais sous forme d'un groupe de bits décrivant les capacités du nœud HNCP.
  • « Connexion extérieure », type 33, rassemble les informations envoyées par un FAI, et que le réseau local doit connaitre. « Préfixe délégué », type 34, sous-TLV du précédent, indique les préfixes IP.
  • « Nom de domaine », type 40, est le suffixe qui sera utilisé pour nommer les machines et services, alors que « Nom de machine », type 41, indique le nom d'une machine et son adresse IP.
  • Etc (il y en a beaucoup).

La section 11 du RFC résume les exigences qui pèsent sur les nœuds d'un réseau HNCP. En plus de gérer le protocole HNCP lui-même, ils doivent aussi, s'ils sont routeurs, respecter le RFC 7084, qui spécifie les règles (légèrement assouplies dans notre RFC sur HNCP) que doivent suivre les routeurs IPv6 situés chez l'utilisateur.

Enfin, un petit mot sur la sécurité (section 12) : HNCP est conçu pour être simple pour l'utilisateur et pour marcher tout seul. Sa sécurité sera donc forcément très faible : un réseau à la maison sans administrateur système professionnel offrira plein de trous à un éventuel attaquant (le RFC 7368 parle de la sécurité des réseaux domotiques). On ne peut pas avoir à la fois le beurre (l'auto-configuration) et l'argent du beurre (la sécurité).

Quelles sont les mises en œuvre de HNCP aujourd'hui ? Il y a, en logiciel libre, hnetd (qui est accessible également sous forme de paquetages pour OpenWrt, depuis la version Barrier Breaker - 14.07 - en juillet 2014). hnetd fait partie du projet HomeWrt. Complètement indépendant de hnetd, il existe également shncpd. On peut aussi citer pysyma, écrit en Python.

En non-libre, il y a du HNCP en cours de développement dans des environnements aussi différents que les routeurs Cisco ou D-Link, les systèmes Nest, le système Xfinity de Comcast... Il parait même que c'est prévu pour les Freebox mais je n'ai pas trouvé de détails à ce sujet. D'autre part, HNCP est apparemment cité dans la spécification (fermée et non publique) Thread.

Les protocoles Homenet sont en développement depuis longtemps et, si vous allez à des salons ou des conférences, vous avez certainement vu des démonstrations utilisant HNCP.

Et si vous aimez l'histoire des protocoles, notez que HNCP, à l'origine, était prévu pour assurer l'auto-configuration de routeurs dans un réseau OSPF (RFC 7503). Cette idée d'« auto-configuration OSPF » n'a pas rencontré un grand succès car tout le monde n'aime pas OSPF et aurait préféré découpler le routage (OSPF, Babel, etc) de la distribution d'informations. HNCP, protocole limité à cette distribution, était né. Il a ensuite été abstrait dans le protocole DNCP (RFC 7787), dont HNCP n'est qu'un profil.


Téléchargez le RFC 7788


L'article seul

RFC 7787: Distributed Node Consensus Protocol

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : M. Stenberg, S. Barth (Independent)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF homenet
Première rédaction de cet article le 23 avril 2016


Ce nouveau protocole DNCP (Distributed Node Consensus Protocol) est prévu notamment pour les réseaux non organisés comportant beaucoup de petites machines, comme on peut en trouver en domotique (Internet des Trucs et tout ça). Il s'appuie sur l'algorithme Trickle (RFC 6206) pour distribuer dans le réseau des informations quelconques. Aucune machine ne joue un rôle particulier dans DNCP : pas de maître ou de racine. DNCP est un algorithme générique, et son utilisation effective nécessite la définition d'un profil, comme HNCP (Home Networking Control Protocol, RFC 7788) dans le cas du réseau « Homenet ».

L'information distribuée par DNCP est sous forme de TLV. Chaque tuple TLV fait 64 ko au maximum et, une fois que l'algorithme a convergé, tous les nœuds du réseau ont la même base de tuples : le réseau est synchronisé. L'état d'un nœud (l'ensemble des tuples qu'il connait) est représenté par un condensat des données (nommé network state hash). Au début, chaque nœud ne connait que ses propres tuples et son état reflète cela. Il diffuse cette information avec Trickle et chaque nœud apprend alors que la synchro n'est pas complète (puisqu'il existe des nœuds avec un condensat différent). Puis chaque nœud modifie l'état (le condensat) en intégrant les tuples des autres nœuds. À la fin, tous les nœuds ont le même état et trouvent donc le même condensat. Ils sont alors heureux et synchronisés. En situation stable, DNCP ne transmet que les condensats (pour que les nœuds puissent vérifier qu'il n'y a pas eu de changement), pas les données, ce qui le rend assez frugal.

DNCP est donc utile pour tous les cas complètement répartis, où des machines sans chef veulent se coordonner. Cela peut servir, par exemple, pour l'affectation automatique des préfixes IP dans un réseau non géré (RFC 7695). DNCP est à l'origine issu d'un projet moins général, le projet « Homenet » de l'IETF ; le groupe Homenet s'est aperçu que le protocole de synchronisation pouvait avoir son utilité en dehors de la domotique et a créé DNCP (et un protocole concret pour Homenet, HNCP).

Comme indiqué plus haut, DNCP est abstrait : plusieurs choix techniques essentiels sont laissés à de futurs profils (comme HNCP, décrit dans le RFC 7788). Parmi ces choix :

  • le mécanisme de transport (TCP, UDP, SCTP),
  • la sécurité (utiliser TLS ou pas),
  • le fait de ne fonctionner que sur un seul lien réseau, ou bien d'être capable de passer par des routeurs.

DNCP est très chouette mais le RFC précise qu'il ne peut pas servir à tout. Quelques exemples de cas où DNCP n'est pas adapté :

  • Si on a des données de grande taille (DNCP les limite à 64 ko),
  • Si on a beaucoup de voisins, et que la diffusion n'est pas possible,
  • Si les données changent tout le temps (DNCP est optimisé pour être économe dans l'état stable),
  • Si beaucoup de nœuds ont des contraintes de mémoire (DNCP nécessite de stocker toutes les données).

Si on a des données qui changent très souvent, il peut être préférable d'utiliser DNCP pour publier l'adresse d'un serveur où récupérer ces données.

DNCP est résumé en section 3 du RFC. Les nœuds sont découverts automatiquement (la méthode exacte dépend du profil) ou manuellement, et leur joignabilité est vérifiée. Les TLV peuvent être des demandes d'information ou bien les données elles-mêmes.

Chaque nœud commence par calculer le condensat des données (la fonction utilisée depend du profil) qu'il veut publier. Il l'annonce ensuite à ses voisins. Quand un voisin annonce un condensat différent, le nœud sait que le réseau n'est pas encore synchronisé. Il demande alors au voisin toutes ses données, les ajoute à sa base, met à jour son condensat et recommence.

Pour jouer son rôle, le nœud DNCP a besoin de quelques informations (section 5). Il a un identificateur unique (la façon doit il est choisi dépend du profil), ses données à publier, une ou plusieurs instances Trickle (le terme ne vient pas du RFC 6206 mais est défini ici : c'est un état Trickle autonome, avec les valeurs des paramètres Trickle), etc. Le nœud a également en mémoire un ensemble de voisins avec, pour chacun, son identificateur, son adresse IP, etc.

Les TLV et leur format sont décrits en section 7 : un type de deux octets, une longueur de deux octets et la valeur. Des TLV peuvent être inclus dans les TLV. Quelques exemples de types : REQ-NETWORK-STATE (type 1) sert à demander l'état du réseau (le condensat de tous les tuples), NETWORK-STATE (type 4) sert pour les réponses à ces requêtes et donne l'état du réseau, etc. L'ensemble des valeurs possibles figure dans un registre IANA.

La section 8 discute de la sécurité de DNCP. Le traitement de celle-ci dépend essentiellement du profil, qui peut décider, par exemple, d'utiliser TLS ou DTLS.

La section 9 discute en détail ce qu'on attend des profils, ce que doivent définir les protocoles concrets qui réalisent DNCP :

  • S'ils utilisent l'unicast ou le multicast.
  • Le protocole de transport, UDP ou TCP.
  • S'ils utilisent TLS pour la sécurité.
  • Quels TLV sont acceptés ou refusés.
  • Quelles valeurs ont les paramètres Trickle.
  • Quelle est la fonction de condensation.
  • Etc.

Des indications sur les choix à faire sont présentées dans l'annexe B. Par exemple, si on utilise UDP, il est recommandé que les données restent d'une taille inférieure à une MTU typique, notamment pour éviter la fragmentation. D'un autre côté, UDP donne davantage de contrôle sur l'envoi des données (mais pas forcément sur leur réception).

Un exemple de profil figure dans l'annexe A. On peut aussi regarder un vrai profil, dans le RFC 7788, qui normalise HNCP. Le profil d'exemple est pour un protocole fictif nommé SHSP (il a existé un projet de protocole nommé Simple Home Status Protocol mais qui semble abandonné, et sans lien avec ce SHSP fictif), un protocole pour l'automatisation de la maison. Ses choix sont :

  • Uniquement IPv6,
  • Unicast en TCP et multicast en UDP,
  • Zéro sécurité (ne doit être utilisé que sur des liens sûrs),
  • L'identificateur d'un nœud est un nombre de 32 bits choisi aléatoirement (en cas de collision, les deux machines en choisissent un autre),
  • Les paramètres quantitatifs de Trickle font que, dans l'état stable, au moins un paquet multicast est émis toutes les 25 secondes,
  • La fonction de condensation est une classique SHA-256,
  • Etc.

Téléchargez le RFC 7787


L'article seul

RFC 7786: TCP modifications for Congestion Exposure

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : M. Kuehlewind (ETH Zurich), R. Scheffenegger (NetApp)
Expérimental
Réalisé dans le cadre du groupe de travail IETF conex
Première rédaction de cet article le 15 mai 2016


C'est après une très longue genèse (ce document avait été adopté par le groupe de travail il y a plus de quatre ans) que voici les protocoles concrets pour la signalisation de la congestion aux routeurs situés en aval. Ici, l'utilisation de ce système avec TCP.

ConEx (pour Congestion Exposure, signalement de la congestion) est décrit dans le RFC 6789. L'idée de base est d'informer le réseau qu'un flot de données rencontre de la congestion, afin que les éléments actifs de ce réseau puissent prendre des décisions intelligentes. ConEx est divisé en une spécification abstraite (RFC 7713) et une ou plusieurs spécifications de protocoles concrets. Ce RFC ne spécifie pas un encodage sur le câble, juste le changement de comportement des mises en œuvre de TCP. (Un autre RFC concret spécifie un encodage pour IPv6, le RFC 7837.)

Il n'y a pas besoin de négociation au début (section 1 du RFC), comme avec les options TCP. Les émetteurs qui connaissent ConEx utilisent les informations existantes (pertes de paquets et ECN, stockées dans deux compteurs différents, cf. la section 3 du RFC).

Pour bien utiliser ConEx, le TCP de l'émetteur a besoin d'informations. Bien qu'il ne soit pas indispensable, c'est mieux si SACK (RFC 2018) est disponible.

La section 2 du RFC résume les modifications chez l'émetteur TCP (le récepteur n'a pas besoin d'être changé pour ConEx). Le comportement de l'émetteur dépendra du fait que le récepteur met en œuvre (ou pas) SACK et ECN. L'émetteur est responsable du marquage des paquets (suivant l'encodage du RFC 7837) avec des signaux ConEx. Il doit tenir compte du nombre d'octets, pas du nombre de paquets (RFC 7141).

En cas de perte de paquets, l'émetteur va mettre le signal ConEx L (loss experienced). Dans certains cas (retransmission inutile parce que le paquet était bien arrivé, c'est l'accusé de réception qui s'était perdu), l'émetteur ne connait pas le nombre exact d'octets perdus. Il peut donc surestimer la congestion dans les signaux ConEx qu'il envoie. Pour avoir de meilleurs mesures, l'émetteur peut toujours mettre en œuvre les RFC 5682, RFC 3708 ou RFC 3522.

Si c'est par des marques ECN, et non pas par des pertes de paquets, que l'émetteur a appris qu'il y avait congestion, il va utiliser les marques ConEx E (ECN experienced).

Dans tous les cas (perte de paquets ou bien ECN), les paquets marqués ConEx devront également porter une marque X, qui indique que l'émetteur sait faire du ConEx (section 4 du RFC).

Un émetteur ConEx est aussi censé envoyer des crédits lorsqu'il n'y a pas de congestion. Ces crédits seront ensuite « consommés » lors des épisodes de congestion. Cela se fait avec le signal C (Credit).

Les paquets contenant les signaux ConEx peuvent se perdre, comme tous les paquets IP (section 5 du RFC). Cela peut mener à des pénalités injustes (un émetteur détecte qu'il y a congestion en aval, le signale avec un L ou un E, le paquet portant le signal est perdu, un routeur qui fait de l'audit ConEx se dit alors « ah, ah, il essaie de tricher, il n'a pas signalé la congestion »). Le problème étant du second ordre (si la probabilité de perdre un paquet est P, la probabilité qu'il y ait perte du paquet et perte du signal est de P au carré), on peut choisir de l'ignorer.

Plus délicat, le problème de la fraîcheur des informations ConEx (section 6 du RFC). Ces informations ne sont utiles que si elles sont très récentes (typiquement moins d'un RTT depuis que la congestion est apparue). L'émetteur doit donc faire attention à ne pas retarder les signaux ConEx. Parfois, il n'a pas trop le choix, par exemple si l'application arrive d'envoyer des données, il n'y aura pas de paquets à marquer.


Téléchargez le RFC 7786


L'article seul

RFC 7776: IETF Anti-Harassment Procedures

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : P. Resnick (Qualcomm Technologies), A. Farrel (Juniper Networks)
Première rédaction de cet article le 13 mars 2016


La question du harcèlement dans le cadre des activités professionnelles (ou autres, d'ailleurs) est maintenant largement reconnue comme cruciale et toute organisation doit se demander « que dois-je faire ? » L'IETF décrit dans ce RFC ses procédures à ce sujet, avec notamment le rôle de l'ombudsteam, l'équipe de justice privée qui doit traiter les cas de harcèlement signalés.

Tout groupe humain est évidemment confronté au problème des comportements négatifs, les trolls, par exemple. L'IETF a eu sa dose, bien que mon impression soit que le problème est nettement moins grave que dans certains groupes, comme chez certains gamers. Mais c'est difficile à dire, c'est un domaine où on n'a pas facilement des statistiques précises. L'IETF a donc son « guide des bonnes manières » (RFC 7154), et les documents de cuisine procédurale interne (RFC 2418 et RFC 3934) prévoient la gestion des cas les plus sérieux. Ces documents se focalisent sur les comportements négatifs qui impactent directement le travail de l'IETF, et le mettent en péril (par exemple, un troll qui assomme le groupe de travail de longs messages répétés en quantité et n'apportant pas de contenu). Mais il y a aussi, et c'est le sujet de ce nouveau RFC, des pratiques négatives qui ne gênent pas directement l'IETF mais peuvent pourrir la vie des participant·e·s qui en sont victimes, par exemple du harcèlement sexuel lors d'une réunion physique. Ces pratiques sont évidemment interdites (déclaration de l'IESG) mais il restait à préciser quoi faire en cas de violation de cette règle.

Il faut noter (et c'est oublié dans la plupart des ces guides de bonnes manières d'origine états-unienne qui fleurissent dans beaucoup de conférences informatiques) que le harcèlement est déjà interdit par la loi dans la plupart des pays où l'IETF tient ses réunions. Comme le note le RFC, les règles de l'IETF ne remplacent pas la loi. Nul besoin d'une déclaration de l'IESG pour interdire, par exemple, les insultes racistes ou le harcèlement sexuel à une réunion IETF. C'est pour cela que la plupart de ces codes of conduct sont inutiles. Celui de l'IETF est très orienté par ses origines états-uniennes, mêlant la demande d'un comportement « professionnel » (comme si le harcèlement n'était fait que par des amateurs) et le puritanisme (« sexual imagery in public presentations », sachant qu'aux États-Unis, la vue d'un torse nu est déjà de la sexual imagery).

La déclaration de l'IESG citée plus haut donne une définition du harcèlement, définition forcément très large (il y a hélas bien des formes de harcèlement, et bien des raisons pour lesquelles un·e participant·e à l'IETF peut être pris·e pour cible). Le problème est-il fréquent à l'IETF ? Je n'ai jamais entendu parler d'un cas précis (contrairement aux cas documentés qui sont arrivés à DEFCON), mais, évidemment, toutes les victimes ne se signalent pas publiquement et le harcèlement est donc très difficile à mesurer scientifiquement.

En première ligne dans ce RFC est l'ombudsteam. Je n'ai pas essayé de traduire ce terme, d'origine suédoise (ombudsman, devenu en anglais ombudsperson pour éviter d'exclure les femmes, puis ombusteam pour marquer son caractère collectif). Disons que c'est une équipe chargée de gérer les cas d'accusation de harcèlement, et c'est la principale ligne de défense de l'IETF dans ces cas.

L'ombudsteam est composé d'au moins trois personnes. Elles sont désignées - pour deux ans, renouvelable - par le président de l'IETF (actuellement Jari Arkko), éventuellement après consultations. Il est recommandé de suivre une certaine diversité (éviter un ombudsteam qui serait uniquement composé d'hommes blancs d'âge mûr et issus des classes dominantes, comme l'est l'auteur de ces lignes...) et de faire en sorte qu'au moins un des membres soit un participant actif à l'IETF. Il n'est donc pas nécessaire, ni même souhaitable, que l'ombudsteam soit sélectionné uniquement en interne. L'idéal, demande le RFC, est que l'ombudsteam rassemble des compétences variées, par exemple des gens qui connaissent très bien l'IETF, des gens qui sont des experts en médiation et en gestion de conflits, etc.

Les membres de l'ombudsteam ne sont pas payés pour leur activité. (À mon humble avis, cela est en contradiction avec l'objectif d'avoir de la diversité : s'ils ne sont pas payés, on n'aura que des gens favorisés socialement.)

Si quelqu'un n'est pas content de la désignation de telle ou telle personne, il peut en appeler à l'IESG (section 6.5.4 du RFC 2026).

L'ombudsteam dispose d'une page Web officielle. La liste des membres du ombudsteam a été publiée deux semaines après le RFC.

Une fois l'ombudsteam constitué, que se passe-t-il en cas de plainte (section 4) ? La victime, ou un témoin du harcèlement, contacte l'ombudsteam, en présentiel ou bien par courrier (ombuds@ietf.org). Tout participant·e à l'IETF peut contacter l'ombudsteam, soit pour une plainte formelle, soit pour solliciter un avis.

Les pratiques de l'ombudsteam seront en grande partie définies par l'ombudsteam, qui est supposé en discuter avec l'IESG puis publier ses principes de fonctionnement. Au minimum, le RFC demande à l'ombudsteam que :

  • Les membres de l'ombudsteam soient présents aux réunions physiques de l'IETF, pour permettre des prises de contact AFK.
  • L'ombudsteam travaille dans la plus stricte confidentialité. Il s'agit de protéger aussi bien le ou la signaleur d'un harcèlement (qui peut hésiter à se plaindre, par exemple par crainte de représailles) que celui ou celle qui en est accusé, peut-être à tort (la section 8 revient en détail sur cette exigence de confidentialité). C'est une exception à la règle habituelle de l'IETF comme quoi tout doit se dérouler en public (une autre exception est le NomCom, cf. RFC 7437).
  • L'ombudsteam ne doit évidemment prendre aucune décision sans avoir entendu les deux parties - pas seulement celle qui signale le harcèlement.
  • Si les accusations s'avèrent infondées, aucune sanction ne doit être prise contre celui ou celle qui a signalé à tort, mais de bonne foi. Autrement, les problèmes ne seraient jamais remontés.
  • L'ombudsteam doit garder des traces écrites de toute son activité, ce qui n'est pas techniquement trivial, vues les exigences de confidentialité.

Bon, donc, des gens signalent des problèmes à l'ombudsteam, l'ombudsteam investigue, se réunit, discute et à la fin, il peut décider quoi ? La section 5 décrit les solutions disponibles pour l'ombudsteam :

  • Dans certains cas, les processus existants avant ce RFC peuvent être utilisés (voir par exemple les RFC 2418 et RFC 3934).
  • Dans les autres cas, l'ombudsteam doit chercher si une médiation entre les parties est possible, débouchant sur un accord qui empêchera la répétition des faits.
  • Dans les cas les plus graves, l'ombudsteam peut décider de sanctions, comme l'exclusion de tout ou partie des activités de l'IETF. Par exemple, le participant convaincu de harcèlement peut être banni d'une réunion et/ou des futures réunions.

Ces sanctions les plus sérieuses peuvent provoquer des problèmes délicats si le harceleur occupait une position de responsabilité à l'IETF. Bien sûr, ces personnes en position de responsabilité (président d'un groupe de travail, par exemple) n'ont pas d'immunité. Mais il ne faut pas non plus que l'ombudsteam puisse empêcher, de facto, un responsable de tenir son rôle. Une possibilité est, dans ce cas, que l'ombudsteam fasse jouer les procédures de révocation normales de l'IETF (RFC 7437, notamment la section 7). Dans le cas d'un poste qui passe par le NomCom (Nominating Commitee), l'ombudsteam demande alors le lancement de la procédure de révocation, et n'a pas besoin pour cela d'une pétition de 20 participants (RFC 7437, section 7.1). Dans le cas de poste pourvus par l'ISOC, l'IAB ou un autre organisme, l'ombudsteam peut demander à cet organisme la révocation du harceleur. Idem si le poste a été pourvu via un directeur de zone (AD, Area Director) ou un président de groupe de travail.

On le voit, l'ombudsteam dispose d'un large pouvoir, sans contrôle (en raison de l'obligation de confidentialité) et la section 5.1 du RFC dit bien que les organismes à qui l'ombudsteam demande une révocation doivent, sauf raison très sérieuse, donner suite à cette demande. Mais que se passe-t-il si quelqu'un est en désaccord avec l'ombudsteam ? La section 6 traite ce problème.

Après discussion avec l'ombudsteam la question doit être remontée au président de l'IETF. Si celui-ci préfère ne pas être impliqué (voir par exemple la section 7, sur les conflits d'intérêt), il peut demander à l'IESG de désigner un de ses membres pour jouer son rôle (les protocoles réseaux, c'est compliqué, mais la bureaucratie interne de l'IETF, c'est pire). Si la discussion entre le président et l'ombudsteam ne débouche pas sur une solution, un mécanisme formel d'appel est prévu. Le groupe qui étudiera l'appel est composé du président de l'IETF et de deux membres de l'IESG qu'il·elle a choisi. Ce groupe peut évaluer la question sur le fond. S'il y a un problème de forme, il existe un dernier mécanisme d'appel auprès de l'ISOC. Notez que les procédures ont été légèrement mises à jour par le RFC 8716.

Le RFC se termine par une jolie citation d'Aung San Suu Kyi : « Human beings the world over need freedom and security that they may be able to realize their full potential. »


Téléchargez le RFC 7776


L'article seul

RFC 7772: Reducing energy consumption of Router Advertisements

Date de publication du RFC : Février 2016
Auteur(s) du RFC : A. Yourtchenko (Cisco), L. Colitti (Google)
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 19 février 2016


Lorsque des machines parlent IPv6, elles reçoivent fréquemment des messages RA (Router Advertisment), que les routeurs émettent souvent avec trop d'enthousiasme. Le traitement de ces messages RA nécessite des ressources et, sur des petites machines alimentées par une pile et souhaitant économiser les ampèreheures, ces RA fréquents, qui les obligent à se réveiller et à travailler, sont une plaie. Ce court RFC suggère quelques moyens d'économiser l'énergie.

À l'époque où IPv6 avait été conçu, on ne pensait pas vraiment à l'Internet des Objets, à ces millions de petits machins connectés. Des messages RA (RFC 4861, section 3) fréquents ne sont pas un problème pour des serveurs alimentés électriquement en permanence. Mais le monde a changé, et il faut maintenant économiser la batterie (section 1 du RFC).

Regardons quelques cas typiques (section 2 du RFC). Un RA (Router Advertisement) peut être sollicité ou pas (RFC 4861). Un RA sollicité est typiquement dû à l'arrivée d'une machine dans le réseau. Elle émet alors un RS (Router Solicitation) et le ou les routeurs, en le recevant, répondent par un RA. Dans certains cas (par exemple si la machine émettrice n'a pas encore d'adresse IPv6 propre), ce RA est envoyé à une adresse multicast, ce qui fait que toutes les machines le recevront et devront le traiter. Si beaucoup de machines quittent et rejoignent le réseau fréquemment (ce qui arrive dans les réseaux sans-fil, lorsque la liaison est mauvaise), ces RA sollicités peuvent représenter un trafic non négligeable (un maximum d'un RA toutes les trois seconde et par routeur est toutefois imposé par les sections 6.2.6 et 10 du RFC 4861).

Même en l'absence de sollicitations, les routeurs IPv6 émettent des RA périodiques, parfois un toutes les cinq ou dix secondes, de manière à éviter que des machines ratent l'information importante.

Conséquences (section 3 du RFC) ? La batterie se vide plus vite, ce qui est très frustrant puisque la plupart de ces RA étaient « inutiles » pour la machine qui les recevait. Certaines machines traitent le problème en ignorant les RA lorsqu'elles sont dans un mode de basse consommation (par exemple Android, avec des conséquences négatives). C'est compréhensible mais cela fait qu'elles risquent, en se réveillant, d'avoir perdu leur connectivité car le réseau a changé ou, tout simplement, parce qu'elles ont « oublié » la route par défaut. Encore plus violent, certaines machines ignorent tous les paquets lorsqu'elles veulent économiser leur batterie. Ces comportements poussent certains administrateurs réseau à augmenter la fréquence des RA, aggravant ainsi encore le problème.

Une autre conséquence (merci à Gabriel Kerneis pour l'exemple), les NAS du constructeur Synology refusent de passer en hibernation profonde s’ils reçoivent des RA (ou des paquets DHCP d’ailleurs). Le seul moyen de faire fonctionner IPv6 sur ces machines tout en préservant l’hibernation est de configurer l’adresse manuellement.

Quelle serait la bonne fréquence d'envoi de RA (section 4) ? Un ordinateur de type portable ne verra pas grand'chose, même pour des RA envoyés toutes les cinq secondes. Sa batterie en a vu d'autres. Les engins plus petits (tablettes, téléphones, montres connectées et autres objets) ont davantage de contraintes. Aujourd'hui, un engin typique va consommer 5 mA quand il dort. Le traitement d'un RA qu'il n'a pas demandé va lui coûter 200 mA pendant un quart de seconde, ce qui fera en tout presque 14 µAh.

Pour limiter la consommation électrique due aux RA à moins de 2 % de la consommation du mode « économique », il faut rester en dessous de 100 µA, ce qui fait moins de 7 RA par heure. Comme des RA se perdent, le routeur ne peut pas être sûr que toutes les machines ont reçu cette information. Le RFC fait un choix conservateur : avec une moyenne de 8-9 minutes entre deux RA (afin de rester en dessous de 7 par heure), le routeur doit compter que l'information devra durer au moins 5 fois ce temps (ce qui fera 40-45 minutes). Pas question donc de changer de configuration IPv6 trop souvent.

Il est possible que certains environnements (réseaux de capteurs industriels) soient encore plus limités en énergie et doivent donc recevoir encore moins de RA.

Pour synthétiser, les recommandations de notre RFC pour les routeurs sont :

  • La possibilité de répondre aux RS par un RA unicast est autorisée par le RFC 4861 mais ce n'est pas obligatoire. Notre RFC demande que cela le devienne et qu'on puisse configurer tous les routeurs pour utiliser cette possibilité. (Si l'adresse source du RS le permet.)
  • Les réseaux ayant beaucoup de machines pauvres en énergie ne devraient pas hurler des RA inutiles en permanence. Ces RA devraient être envoyées rarement (voir les chiffres plus haut) quitte à être plus fréquents immédiatement après un changement de la configuration.

Notez que cela ne change pas le protocole IPv6 : ces recommandations sont déjà des comportements légaux.

Et les recommandations pour les machines terminales sont :

  • Si elles peuvent traiter des paquets IPv6 pendant le mode « économie d'énergie », elles doivent aussi traiter les RA (autrement, elles risquent de rater des changements importants dans la configuration du réseau), quitte à en limiter le traitement s'ils sont trop fréquents (par exemple un RA par minute maximum).
  • Si les machines préfèrent être vraiment silencieuses et inactives pendant cette phase d'économie d'énergie, elles peuvent ignorer les RA mais elles devraient alors se retirer explicitement du réseau lorsqu'elles s'endorment, et refaire la procédure d'arrivée dans un nouveau réseau (par exemple en suivant le RFC 6059) quand elles se réveillent avec du travail à faire (car le réseau aura pu changer pendant leur sommeil).

Enfin, la section 8 du RFC, portant sur la sécurité, rappelle qu'un routeur méchant peut ignorer ces conseils et envoyer beaucoup de RA exprès pour vider les batteries. Il faut donc prendre des mesures contre de tels routeurs (par exemple celle du RFC 6105).

Merci beaucoup à Benjamin Cama pour ses corrections, son analyse détaillée et ses excellentes références (reprises ici).


Téléchargez le RFC 7772


L'article seul

RFC 7766: DNS Transport over TCP - Implementation Requirements

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : J. Dickinson, S. Dickinson (Sinodun), R. Bellis (ISC), A. Mankin (Verisign Labs), D. Wessels (Verisign Labs)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 4 mars 2016


Ce nouveau RFC décrit des exigences bien plus importantes pour l'utilisation du DNS au-dessus de TCP : non seulement les serveurs DNS doivent gérer TCP (ce qui a toujours été le cas), mais ils doivent le faire sur un pied d'égalité avec UDP. TCP n'est pas une solution de secours pour des cas rares, c'est désormais une alternative complète à UDP pour le service DNS. La règle est donc désormais plus radicale qu'avec le RFC précédent, le RFC 5966, maintenant retiré.

Traditionnellement, surtout avant la sortie du RFC 5966, le DNS utilisait surtout UDP. Beaucoup de gens croyaient même, bien à tort, que TCP ne servait que pour des cas très particuliers comme le transfert de zones ou comme la récupération de données plus grosses que 512 octets. Ces croyances étaient déjà fausses lors de la sortie des RFC originels sur le DNS, mais le RFC 5966 leur a tordu le cou complètement. UDP a en effet des limites :

La formulation des sections 3.7 du RFC 1034 et 4.2 du RFC 1035 sur l'usage de TCP étaient assez claires (mais personne ne lit les RFC...) Par contre, la section 6.1.3.2 du RFC 1123 avait semé la confusion en laissant entendre que TCP était facultatif. C'est désormais corrigé, TCP est bien obligatoire pour le DNS.

Mais TCP, utilisé bêtement, souffre de plusieurs défauts : si on ouvre une connexion TCP à chaque requête DNS, la latence va être bien plus élevée qu'en UDP, et, si on fait passer toutes les requêtes séquentiellement sur une seule connexion TCP, et que le serveur les traite dans l'ordre, une requête lente peut faire attendre des requêtes qui auraient été rapides. Voici pourquoi notre RFC impose un certain nombre de comportements intelligents (section 3) :

  • Connexion persistente et réutilisable (ne pas fermer la connexion TCP, mais la réutiliser pour les requêtes suivantes),
  • Pipelining (pour un client DNS, ne pas attendre la réponse avant d'envoyer d'autres questions, mais en envoyer plusieurs dans le tuyau),
  • Traitement non-séquentiel (pour un serveur, le fait de traiter en parallèle les requêtes, pour éviter qu'une requête lente ne retarde celles qui suivent). Cela concerne surtout les résolveurs (car le temps de répondre à une requête peut varier considérablement, en fonction du cache et du temps de réponse des serveurs faisant autorité.)

J'ai parlé plus haut de la taille des réponses DNS (section 4 du RFC). C'était autrefois une des bonnes raisons de passer en TCP, afin d'obtenir des réponses supérieures à 512 octets. Les clients DNS le font typiquement automatiquement. Par exemple, ici, dig tente d'obtenir une réponse de plus de 512 octets, et elle est donc tronquée (flag TC pour TrunCation) :

  
% dig +bufsize=0 +noedns +nodnssec +ignore NS fox.com 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38102
;; flags: qr tc rd ra ad; QUERY: 1, ANSWER: 15, AUTHORITY: 0, ADDITIONAL: 0
...
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; MSG SIZE  rcvd: 494

J'ai utilisé l'option +ignore pour voir cette troncation. Si on ne l'utilise pas, dig passe automatiquement en TCP (le message « Truncated, retrying in TCP mode ») :


% dig +bufsize=0 +noedns +nodnssec NS fox.com 
;; Truncated, retrying in TCP mode.
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24693
;; flags: qr rd ra; QUERY: 1, ANSWER: 16, AUTHORITY: 0, ADDITIONAL: 0
...
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; MSG SIZE  rcvd: 522

Maintenant qu'on a EDNS (RFC 6891), TCP est moins utile pour ce problème de taille (il reste utile pour les autres raisons énumérées au début). Voici un exemple avec EDNS pour une donnée de grande taille (comme le note la section 4, une réponse négative, NXDOMAIN dans une zone signée avec DNSSEC/RSA et utilisant le NSEC3 du RFC 5155 va presque toujours faire plus de 512 octets) :


% dig +bufsize=4096 A nimportequoinexistepas.fr
...
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 27274
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
...
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; MSG SIZE  rcvd: 1012

Le +bufsize=4096 active EDNS, avec une taille maximale des réponses de 4 096 octets.

(Notez que la troncation est aussi utilisée pour des raisons de sécurité, lorsqu'un serveur détecte une attaque par amplification. Avec la technique RRL, le serveur répond alors avec des paquets tronqués - paquets nommés SLIP, pour forcer le client à réessayer en TCP, où il n'y aura pas d'usurpation d'adresse IP possible.)

Reste la question de la MTU. La réponse précédente faisait 1 012 octets, inférieure à la MTU typique (en général de 1 500 octets, à cause d'Ethernet). Si elle est plus grande, la réponse va être fragmentée et, là, les ennuis commencent. On ne peut pas compter sur la bonne réception des paquets fragmentés : trop de pare-feux configurés avec les pieds sont sur le trajet, et ils jettent souvent bêtement les fragments. En parlant de middleboxes, il faut aussi noter que certaines perturbent EDNS (RFC 5625). Les réponses supérieures à 1 500 octets, elles, auront peut-être besoin de TCP :

% dig DNSKEY cpsc.gov
...
;; MSG SIZE  rcvd: 1733

La section 5 du RFC est la partie normative. Elle contient la nouvelle règle : un serveur DNS doit parler TCP. Et un client DNS peut s'en servir, il n'est même pas forcé d'attendre la troncation.

Maintenant, les détails pratiques. D'abord (section 6), la gestion des connexions TCP. Compte-tenu de la « triple poignée de mains » qui ouvre les connexions TCP, et de son coût en latence, il est fortement recommandé d'éviter de faire une connexion TCP par requête DNS. L'idée est donc, pour le serveur, de ne pas fermer la connexion dès qu'elle est inactive mais de la garder ouverte (comme le font HTTP 1.1 - RFC 7230 et HTTP 2 - RFC 7540) et, pour les clients, de ne pas fermer après la première requête (ce qu'ils font actuellement, en général). Mais, contrairement à HTTP, le DNS n'a pas encore de mécanisme de fermeture explicite de ces connexions TCP persistentes (certains ont été proposés). Il faut donc utiliser des heuristiques pour savoir quand fermer une connexion.

Au fait, j'ai parlé de « connexion inactive » sans l'expliquer. La section 3 la définit comme « pour un client, lorsqu'il a reçu toutes les réponses à ses questions, pour un serveur, lorsqu'il a répondu à toutes les questions posées ».

Les serveurs actuels laissent en général les connexions assez longtemps (deux minutes par défaut, sur Unbound ou sur NSD), et ont un nombre de connexions TCP maximal assez faible. Cela permet des attaques par déni de service triviales (ouvrir N connexions TCP, attendre) ou même des simples accidents, où un petit nombre de clients, sans le faire exprès, épuisent complètement les maigres ressources allouées à TCP. Avec BIND, vous pouvez par exemple regarder combien de clients TCP sont actuellement actifs par rapport au maximum autorisé. Si le nombre de clients actifs se rapproche trop du maximum, il y a un risque :

% rndc status | grep tcp
tcp clients: 8/100

Notre RFC recommande donc (section 6.2) une série de bonnes pratiques qui vont permettre à TCP d'être utilisé massivement pour le DNS. D'abord, réutiliser les connexions, de façon à amortir le coût, relativement élevé, de l'établissement d'une connexion, sur plusieurs requêtes. Attention, le client DNS ne doit pas réutiliser l'identicateur de requête (Query ID, ou id: dans la sortie de dig) sur la même connexion, tant qu'il reste une question non répondue utilisant cet identificateur (autrement, le client ne saurait pas à quelle question correspond une réponse).

Ensuite, une requête ne devrait pas avoir à attendre la réponse à la requête précédente. Dès que le client a une question, il l'envoie (pipelining).

Au passage, un client DNS gourmand pourrait être tenté d'ouvrir plusieurs connexions TCP avec le serveur. Notre RFC le déconseille (sauf pour des cas ponctuels comme les longs transferts de zone) : cela use des ressources, et c'est inutile, si on a le pipelining et le traitement en parallèle. Un serveur a donc le droit de mettre des limites et, par exemple, de ne pas accepter plus de N connexions TCP par adresse IP (avec N probablement strictement supérieur à 1 car il faut tenir compter des clients différents situés derrière une même adresse IP, par exemple en cas de CGN).

Bon, et le quantitatif ? C'est bien de dire qu'un serveur ne devrait pas laisser les connexions TCP inactives ouvertes trop longtemps, mais combien, exactement ? Le RFC recommande quelques secondes, pas plus, après le traitement de la dernière requête, sauf si on a reçu une demande explicite (voir le RFC 7828). À comparer avec les 120 secondes actuelles de NSD ou Unbound... Cette durée peut évidemment être réglée dynamiquement, par exemple pour répondre à la disponibilité de ressources chez le serveur (nombre maximum de connexions TCP atteint, je coupe des connexions inactives...)

Dans tous les cas, outre la coupure d'une connexion par un client qui a fini son travail, le client doit aussi se rappeler qu'un serveur DNS a le droit de couper les connexions TCP quand ça lui chante, et sans prévenir à l'avance. Le client doit donc gérer ces coupures (détecter et reconnecter). C'est d'autant plus important qu'un serveur peut redémarrer (perdant ses sessions TCP) ou que tout simplement, le routage peut changer, amenant le client DNS vers une autre instance d'un nuage anycast, instance qui n'a pas les sessions TCP en cours.

Et le traitement en parallèle (section 7) ? C'est un des points importants de DNS sur TCP, sans lequel TCP n'aurait guère d'intérêt. Lorsqu'un résolveur minimum (rappel, la terminologie du DNS est dans le RFC 8499) se connecte à un résolveur complet en TCP, le résolveur complet va mettre un temps très variable à répondre aux questions. De quelques dizaines de micro-secondes si la réponse est dans le cache à des centaines de milli-secondes s'il a fallu interroger trois ou quatre serveurs faisant autorité avant d'avoir sa réponse. Si le traitement des requêtes était fait de manière strictement séquentielle, la requête rapide qui aurait la malchance d'être située après une requête lente devrait patienter très longtemps. Il est donc crucial de traiter les requêtes en parallèle.

Conséquence : il est parfaitement normal que, lorsqu'on envoie les questions Q1 puis Q2, la réponse R2 arrive avant R1. Tous les clients DNS doivent être prêts à cela. Le démultiplexage des réponses doit se faire sur le Query ID du DNS (et voilà pourquoi il ne faut pas le dupliquer) et, dans le cas le plus fréquent, également sur le nom demandé (QNAME, pour Query NAME).

L'encodage d'un message DNS en TCP est très légèrement différent de ce qu'il est en UDP. Un champ Longueur, de deux octets, précède en effet le message, pour faciliter la lecture. Cela permet au récepteur de savoir combien d'octets il va lire dans le flux TCP (qui, rappelons-le, n'a pas la notion de messages, c'est juste un flux d'octets sans séparateurs). Par exemple, en Go, on lirait ainsi :

// Lire le champ Longueur
smallbuf := make([]byte, 2)
n, error := connection.Read(smallbuf)
msglength := binary.BigEndian.Uint16(smallbuf) // RFC 1035, section 4.2.2 "TCP usage"

// Allouer un tampon pour le message
message := make([]byte, msglength)

// Lire le message DNS
n, error = connection.Read(message)

Le RFC recommande (section 8) que les émetteurs DNS passent ce champ Longueur et le message ensemble, dans un seul write() sur le réseau, de façon à maximiser les chances qu'ils se trouvent dans le même paquet IP, certaines mises en œuvre réagissant mal dans le cas contraire. Ce n'est pas une garantie absolue (TCP peut découper en paquets IP comme il veut). Les experts en Go noteront que le code ci-dessus ne tient pas compte de ce risque : Read() peut lire moins d'octets que la taille du tampon, il faudrait tester ce cas (ou bien utiliser ReadFull().) Et, naturellement, il faudrait tester les cas d'erreur.

On a vu qu'un des problèmes potentiels dus à l'utilisation de TCP était la latence liée à l'ouverture des connexions. Outre la réutilisation des connexions pour plusieurs requêtes, un autre mécanisme peut aider à limiter ce problème (section 9) : TCP Fast Open (RFC 7413). En permettant aux données d'être transportées dès le paquet initial (le paquet SYN), il fait gagner du temps. Contrairement à d'autres tentatives précédentes de faire de l'« ouverture rapide », TCP Fast Open ne permet pas d'attaques par réflexion, grâce à un cookie. C'est donc une solution à considérer, pour les clients et serveurs DNS utilisant TCP.

C'est un bon prétexte pour discuter de sécurité (section 10). Lors de la mise au point de ce RFC, il y a eu beaucoup de discussions concernant le risque d'attaque par déni de service pour les serveurs DNS. Le traitement d'une requête TCP (y compris l'établissement de la connexion) nécessite, après tout, davantage de ressources que celui d'une requête UDP. Mais on a aussi davantage d'expérience avec les attaques utilisant TCP (c'est le protocole sous HTTP, après tout, et de nombreuses attaques sont faites contre les serveurs Web). Outre la lecture du « Security Assessment of the Transmission Control Protocol (TCP) », notre RFC recommande de permettre de configurer le serveur DNS sur des points comme le nombre total de connexions TCP (tcp-clients pour BIND, tcp-count pour NSD, incoming-num-tcp pour Unbound), le nombre maximal de connexions TCP par adresse IP de client, la durée de vie des connexions inactives (tcp-timeout pour NSD et, attention, il faut redémarrer le serveur si on le change), le nombre maximal de requêtes DNS par connexion (tcp-query-count pour NSD), etc. Sans compter les réglages permis par le système d'exploitation (comme les innombrables paramètres sysctl net.ipv4.tcp_* de Linux et, oui, c'est ipv4 même pour IPv6).

En prime, le RFC rappelle que les résolveurs ne devraient pas accepter des connexions du monde entier (RFC 5358), mais, sauf cas rares, uniquement de certains préfixes IP, leurs clients. Cela contribue à limiter les risques.

Pour les amateurs de choix technologiques complexes, l'annexe A du RFC résume les avantages et les inconvénients de TCP pour le DNS. Avantages :

Inconvénients :

  • Coût par requête plus élevé à cause de l'établissement de la connexion. On peut réduire ce coût en réutilisant les connexions,
  • Davantage d'état à maintenir chez les clients et les serveurs,
  • Risques de plantage des connexions TCP si on se connecte à un serveur anycast et que le routage change,
  • Risque avec des middleboxes boguées (RFC 5625).

Le rapport « Connection-Oriented DNS to Improve Privacy and Security » discute bien plus en détail ces choix.

Enfin, l'annexe B liste les principaux changements depuis le RFC 5966. Ils sont importants puisqu'on passe d'un modèle « TCP dans certains cas » à un modèle « pouvoir faire tout en TCP si on veut ». Par exemple, un client peut désormais utiliser TCP avant d'avoir testé en UDP. Les autres changements sont des conséquences de ce principe : les logiciels DNS doivent désormais permettre la réutilisation des connexions, le pipelining et le traitement en parallèle des requêtes parce que, sans cela, TCP ne serait pas vraiment utilisable pour le DNS.

Allez, pour finir, un example avec dig où on demande explicitement du TCP :


% dig +tcp @d.nic.fr NS gouvernement.fr

; <<>> DiG 9.9.5-9+deb8u3-Debian <<>> +tcp @d.nic.fr NS gouvernement.fr
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14247
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;gouvernement.fr.	IN NS

;; AUTHORITY SECTION:
gouvernement.fr.	172800 IN NS ns2.produhost.net.
gouvernement.fr.	172800 IN NS ns33.produhost.net.
gouvernement.fr.	172800 IN NS ns1-sgg.produhost.net.
98dsof44tab20a3p7gv0cgelh01vlv9j.fr. 5400 IN NSEC3 1 1 1 D0D3AC0C (
				98ECUBNBQN7GCK4GQ1KQURRJTRUF6P83
				NS SOA TXT NAPTR RRSIG DNSKEY NSEC3PARAM )
98dsof44tab20a3p7gv0cgelh01vlv9j.fr. 5400 IN RRSIG NSEC3 8 2 5400 (
				20160213101014 20151215091014 1146 fr.
				MDAHRaeLGVQiK6KEQvFn8PNSl608bd5iMup4cwkqgStB
				uXEFWOpQLeSy37IattIDOt0AhwEirpNe7pzH+KMOdrM0
				mEWGiGa3iSdsF9hc29JDUtVyfalNmJqPIoDplw+Q0lpI
				Jxd8XlI/229PEH64Nua2jgLk5gxyZPCFt7yVvGg= )
ceast34o75e1lj5eprb3j5i82re4g1ug.fr. 5400 IN NSEC3 1 1 1 D0D3AC0C (
				CEB3B4VDS9MG7Q92A7FVCRQ5TTIVJ3LT
				NS DS RRSIG )
ceast34o75e1lj5eprb3j5i82re4g1ug.fr. 5400 IN RRSIG NSEC3 8 2 5400 (
				20160213054416 20151215054416 1146 fr.
				Eusw6LfnNPxmquf8JDHJnWZpBFJj8hrvJi1lx3bounyO
				YW8ceJsrm0AkjMHm5Sh40TDfXcVrLeTK5U9PWJYqpUAG
				7LABfh4nwwnlofvuyKtSx1yl44G6Gv/MSyQUnj0dIgQ5
				6MB+b3tsUx2rHI2D0w9kiV50xJeCYVBiViQP2y8= )

;; Query time: 19 msec
;; SERVER: 2001:678:c::1#53(2001:678:c::1)
;; WHEN: Tue Dec 15 22:07:36 CET 2015
;; MSG SIZE  rcvd: 607

Et le tcpdump correspondant :

% sudo tcpdump -n -vvv host 2001:678:c::1
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
22:08:08.073682 IP6 (hlim 64, next-header TCP (6) payload length: 40) 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105 > 2001:678:c::1.53: Flags [S], cksum 0x2782 (correct), seq 2640844175, win 28400, options [mss 1420,sackOK,TS val 2942466 ecr 0,nop,wscale 7], length 0
22:08:08.090127 IP6 (hlim 57, next-header TCP (6) payload length: 40) 2001:678:c::1.53 > 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105: Flags [S.], cksum 0xcb39 (correct), seq 1288542264, ack 2640844176, win 17856, options [mss 8940,sackOK,TS val 1674059577 ecr 2942466,nop,wscale 7], length 0
22:08:08.090175 IP6 (hlim 64, next-header TCP (6) payload length: 32) 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105 > 2001:678:c::1.53: Flags [.], cksum 0x5c1c (correct), seq 1, ack 1, win 222, options [nop,nop,TS val 2942470 ecr 1674059577], length 0
22:08:08.090246 IP6 (hlim 64, next-header TCP (6) payload length: 78) 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105 > 2001:678:c::1.53: Flags [P.], cksum 0x71d1 (correct), seq 1:47, ack 1, win 222, options [nop,nop,TS val 2942470 ecr 1674059577], length 4619356+ [1au] NS? gouvernement.fr. ar: . OPT UDPsize=4096 OK (44)
22:08:08.107559 IP6 (hlim 57, next-header TCP (6) payload length: 32) 2001:678:c::1.53 > 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105: Flags [.], cksum 0x5c2e (correct), seq 1, ack 47, win 140, options [nop,nop,TS val 1674059595 ecr 2942470], length 0
22:08:08.109126 IP6 (hlim 57, next-header TCP (6) payload length: 641) 2001:678:c::1.53 > 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105: Flags [P.], cksum 0x6c2e (correct), seq 1:610, ack 47, win 140, options [nop,nop,TS val 1674059595 ecr 2942470], length 60919356- q: NS? gouvernement.fr. 0/7/1 ns: gouvernement.fr. [2d] NS ns2.produhost.net., gouvernement.fr. [2d] NS ns33.produhost.net., gouvernement.fr. [2d] NS ns1-sgg.produhost.net., 98dsof44tab20a3p7gv0cgelh01vlv9j.fr. [1h30m] Type50, 98dsof44tab20a3p7gv0cgelh01vlv9j.fr. [1h30m] RRSIG, ceast34o75e1lj5eprb3j5i82re4g1ug.fr. [1h30m] Type50, ceast34o75e1lj5eprb3j5i82re4g1ug.fr. [1h30m] RRSIG ar: . OPT UDPsize=4096 OK (607)
22:08:08.109137 IP6 (hlim 64, next-header TCP (6) payload length: 32) 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105 > 2001:678:c::1.53: Flags [.], cksum 0x5961 (correct), seq 47, ack 610, win 244, options [nop,nop,TS val 2942474 ecr 1674059595], length 0
22:08:08.109743 IP6 (hlim 64, next-header TCP (6) payload length: 32) 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105 > 2001:678:c::1.53: Flags [F.], cksum 0x595f (correct), seq 47, ack 610, win 244, options [nop,nop,TS val 2942475 ecr 1674059595], length 0
22:08:08.130087 IP6 (hlim 57, next-header TCP (6) payload length: 32) 2001:678:c::1.53 > 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105: Flags [F.], cksum 0x59b3 (correct), seq 610, ack 48, win 140, options [nop,nop,TS val 1674059614 ecr 2942475], length 0
22:08:08.130133 IP6 (hlim 64, next-header TCP (6) payload length: 32) 2001:db8:cafe:1234:21e:8cff:fe76:29b6.60105 > 2001:678:c::1.53: Flags [.], cksum 0x5946 (correct), seq 48, ack 611, win 244, options [nop,nop,TS val 2942480 ecr 1674059614], length 0

Question mise en œuvre, remarquez que les dernières versions de BIND ont un outil nommé mdig qui permet d'envoyer plusieurs requêtes DNS sur une même connexion TCP (en pipeline, sans attendre la réponse à la première).


Téléchargez le RFC 7766


L'article seul

RFC 7764: Guidance on Markdown: Design Philosophies, Stability Strategies, and Select Registrations

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : S. Leonard (Penango)
Pour information
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 23 mars 2016


Ce RFC est un complément du RFC 7763, qui enregistrait le type MIME text/markdown. Il contient tout ce qui ne tenait pas dans le RFC original, c'est donc un pot-pourri de considérations philosophiques, de descriptions des variantes les plus courantes de Markdown, de techniques de stockage local de contenus en Markdown...

Le RFC 7763 était plus sec, contenant uniquement ce qui était nécessaire à l'enregistrement de text/markdown. Cet autre RFC est plus disert, expliquant d'abord (section 1) la philosophie de Markdown, et ses usages. Rappelons donc que Markdown est un format de marquage du texte. Lorsqu'on veut stocker des textes (romans, rapports techniques, articles scientifiques, lettres d'amour, etc) sur un système informatique, on a plusieurs solutions : elles vont du texte brut à un format binaire. Le texte brut est le stockage des seuls caractères Unicode (cf. RFC 6838, section 4.2.1 : le texte est distribué sur l'Internet avec un type MIME text/quelquechose, par exemple text/plain pour le texte brut). Son gros avantage est qu'il est lisible et modifiable avec n'importe quel logiciel. Bon, en fait, le texte brut n'est jamais tout à fait brut. Il contient quelques caractères de contrôle comme le saut de ligne ou la marque d'un nouveau paragraphe (U+2029 en Unicode, mais ce séparateur de paragraphe n'est que rarement géré par les logiciels).

À l'autre extrémité se trouve les formats binaires : lisibles et modifiables uniquement par des applications spécifiques (et c'est pour cela qu'ils sont distribués avec le type MIME application/quelquechose).

Entre les deux se trouvent le texte formaté ou marqué. Il s'agit à première vue de texte brut mais il inclut en fait quelques marques qui ont une signification non prévue par le jeu de caractères. Un exemple classique est la mise en évidence qui, en Markdown, se fait en encadrant le texte avec des étoiles : « il est *très* important de comprendre que... » Le texte reste lisible sans logiciel spécifique (d'autant plus qu'ici, Markdown reprend une ancienne convention d'écriture largement utilisée sur l'Internet). Et n'importe quel éditeur (et n'importe quel clavier) permet de créer un tel texte.

On sépare souvent les formats de texte marqués en formats stricts (markup) et formats légers (lightweight markup). Les premiers sont plus proches des formats binaires, dans la mesure où ils ont des marques bien séparées du texte, et suivent une syntaxe rigide. Ce sont par exemple XML et LaTeX. Cette syntaxe rigide permet de vérifier la qualité technique du document et mène à une meilleure interopérabilité. Mais elle peut être pénible pour les utilisateurs débutants ou occasionnels. Plus proches du texte brut, les formats de texte marqué légers ont des marques plus discrètes, et ont souvent une syntaxe moins formelle, plus tolérante (un cas extrême est Markdown, qui ne connait même pas la notion d'erreur de syntaxe). Ils sont conçus pour être facilement accessibles au nouvel utilisateur (ou à celui qui n'a pas pratiqué depuis longtemps). Jeff Atwood qualifiait ces formats légers d'« humains ».

Markdown est issu d'un langage originellement développé par John Gruber (et Aaron Swartz). Il a été rapidement un grand succès, notamment pour les tâches simples (comme de saisir un commentaire ou un rapport de bogue dans un formulaire Web). Et il a connu de nombreuses extensions. Beaucoup de programmes et de langages savent traiter le Markdown, chacun avec sa variante particulière.

Markdown est clairement dans le camp de l'« informalité ». Un des événements fondateurs fut un problème avec de nombreux flux de syndication rendus invalides juste par un article contenant du code incorrect (la norme XML dit bien qu'une fois qu'une erreur apparait dans un fichier XML, le processeur ne doit pas continuer). Avec Markdown, cela ne risque pas d'arriver, tout texte est du Markdown légal. Cela ressemble au fameux principe de robustesse des protocoles réseau. (À noter que ce principe a été suivi, en pratique, par la plupart des navigateurs Web, lorsqu'il s'agit d'analyser du HTML. Résultat, les auteurs se sont habitués à taper n'importe quoi et le Web est aujourd'hui une poubelle de fichiers HTML bourrés d'erreurs.) Lorsqu'on soumet un fichier Markdown à un processeur, cela « marche » toujours. Si on n'est pas satisfait du résultat, on modifie le source et on réessaie (cf. « The Talk Show: Ep. 88: 'Cat Pictures' (Side 1) ».) Pas de processus de validation, comme en XML ou HTML strict, seul le résultat compte.

Malgré ou bien à cause de ce principe, Markdown est un grand succès. On le trouve utilisé partout et il est probablement le plus populaire des langages de marquage « légers ». On peut l'éditer avec n'importe quel logiciel et lire le source, même sans avoir subi aucun apprentissage de sa syntaxe. Des gens utilisent Markdown pour des articles scientifiques, l'écriture de scénarios, ou pour faire des maths, le domaine qui était autrefois le bastion de LaTeX. (Personnellement, je m'en sers pour les rapports de bogue sur GitHub, les README de logiciels, les rapports techniques internes à mon employeur, LaTeX ou DocBook prenant le relais pour les choses plus « sérieuses ». Markdown avec les sites qui le gèrent permet aussi de faire du mini-blogging très simplement et très rapidement. Regardez aussi le témoignage de Yann Houry.)

Depuis le RFC 7763, il existe un type MIME pour identifier Markdown, text/markdown. (Une extension de nom de fichier comme .md ne suffit pas : tout le contenu n'est pas forcément dans des fichiers.) Un seul type MIME décrit toutes les variantes puisque n'importe quel processeur pourra traiter n'importe quelle variante (même si le résultat ne sera pas toujours celui voulu.) À noter que la plupart des variantes de Markdown n'ont pas de mécanisme pour mettre les métadonnées : il faut les placer à l'extérieur.

Comment préserver ce type MIME lorsque du contenu Markdown est copié sur l'Internet ? Parfois, la copie ne préserve pas cette information et Markdown n'a pas l'équivalent du <?xml version="1.0"> qui, au début des contenus en XML, indique sans ambiguité qu'il s'agit de XML (il a été proposé de l'introduire mais cela peut casser les mécanismes de métadonnées existants). Utiliser le contexte (le répertoire où se trouve un fichier, par exemple...) est casse-gueule car, justement, l'envoi d'un document fait facilement perdre le contexte. La section 2 du RFC propose et discute plusieurs stratégies. Utiliser le nom de fichier, lorsqu'on passe par des fichiers, est possible. mon-roman.md est un texte en Markdown, on le sait par l'extension. Et la variante ? On peut l'indiquer avant, par exemple mon-roman.pandoc.md si le texte est écrit dans la variante Pandoc. Si le système de fichiers permet de stocker des attributs ou métadonnées, c'est une autre bonne solution.

Mais il y en a d'autres. Une solution, suggérée par le RFC 6533, est de stocker les métadonnées et notamment l'en-tête MIME dans un fichier séparé, conventionnellement nommé. Si le fichier texte est mon-roman.md, le fichier des métadonnées pourrait être mon-roman.md.headers.

Ou alors dans le même fichier ? L'idée est de transformer le fichier Markdown en un fichier au format IMF (Internet Message Format, spécifié dans le RFC 5322) en mettant des en-têtes d'abord, puis le contenu en Markdown :

MIME-Version: 1.0
Content-Type: text/markdown; charset=utf-8
Date: Wed, 10 Feb 2016 20:59:06 +0100 (CET)
    
Exemple d'un fichier « armé »
=============================

Notez la ligne vide qui sépare les en-têtes du corps.

Il est *important* que son extension ne soit pas .md ou .markdown, ce
n'est plus du Markdown pur mais de l'IMF, son extension doit donc être
.eml ou .msg.

...
    

Le RFC contient plein d'autres stratégies rigolotes pour résoudre ce problème. Par exemple, on pourrait, lors de la réception, voire de l'envoi, d'un contenu en Markdown, générer/envoyer un script qui contienne les commandes permettant de le traiter convenablement. Ou on pourrait carrément envoyer le résultat du traitement, et pas le Markdown : si on veut juste que le destinataire puisse lire, pas la peine de lui envoyer le « source », on pourrait juste lui transmettre le XHTML (je ne suis pas sûr d'être d'accord avec cette curieuse idée : un des gros avantages de Markdown est qu'il est lisible même si on n'a aucun logiciel spécifique, et si on n'a jamais entendu parler de ce format).

Cette section 2 se termine avec le cas des VCS. Subversion offre un excellent mécanisme de stockage et de versionnement des méta-données. Il suffit donc de définir la métadonnée standard svn:mime-type et on ne risque plus de perdre cette information :

% svn propset svn:mime-type text/markdown mon-roman.md 
property 'svn:mime-type' set on 'mon-roman.md'

% svn commit -m "Type indiqué" mon-roman.md
...
    

Hélas, git n'a, lui, aucun moyen propre de stocker les métadonnées. Il faut donc recourir à une autre des stratégies mentionnées plus haut (fichier d'en-têtes avec un nom conventionnel, extension du fichier, etc).

La section 3 de notre RFC est consacrée aux formulaires d'enregistrement des différentes variantes de Markdown, désormais mémorisées à l'IANA. Cette section est utile si vous voulez vous renseigner sur une variante particulière, mais aussi si vous avez développé votre propre variante (sans doute une mauvaise idée mais les programmeurs adorent réinventer la roue) et que vous voulez l'enregistrer à l'IANA. Vous pouvez alors utiliser les cas de cette section comme exemples concrets, avant d'écrire votre propre demande.

Prenons par exemple la variante que j'utilise le plus souvent, Pandoc. Contrairement au Markdown originel, elle ne vise pas uniquement la génération de HTML mais également des tas d'autres formats de sortie. Elle a des tas d'extensions par rapport à l'original, comme les tableaux ou bien les notes de bas de page. Sa fiche contient :

   Identifier: pandoc

   Name: Pandoc

   ...
   
   Extensions to turn off (on by default):

                   escaped_line_breaks
                   blank_before_header
                   header_attributes
		   ...
		   
   References:
   <http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown>

   Contact Information:
     (individual) Prof. John MacFarlane <jgm@berkeley.edu>
                              <http://johnmacfarlane.net/>
    

Les autres variantes enregistrées via cette section 3 sont MultiMarkdown, GitHub, Fountain, CommonMark, Markdown for RFCs, Pandoc for RFCs (RFC 7328) et PHP Markdown (utilisé par plusieurs CMS comme Drupal).

La section 4 de notre RFC fournit des exemples de ces différentes variantes et de ce qu'elles apportent. Par exemple, la variante GitHub apporte la transformation automatique des URL en liens hypertexte.


Téléchargez le RFC 7764


L'article seul

RFC 7763: The text/markdown Media Type

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : S. Leonard (Penango)
Pour information
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 23 mars 2016


Le format Markdown est un excellent format léger de marquage de textes, permettant d'enrichir un texte, sans pour autant avoir à apprendre un gros langage de marquage comme LaTeX. Markdown est très bien adapté aux courts rapports, aux articles simples, aux fichiers README, à la génération de pages Web... Markdown a de nombreuses variantes et le but de ce nouveau RFC n'est pas de normaliser Markdown (une tâche probablement impossible) mais juste d'enregistrer un type MIME pour ce format, text/markdown. Donc, on décrit, on ne normalise pas.

Markdown est un langage de marquage du texte, comme ReST (utilisé dans le livre CNP3) ou comme les langages des Wiki. On peut donc éditer du Markdown avec n'importe quel éditeur (mes lecteurs ne seront pas surpris d'apprendre que j'utilise Emacs). Le source Markdown est donc du texte lisible tel quel, sans logiciel spécifique, mais un logiciel peut le traiter pour produire une forme plus agréable et plus efficace, par exemple du HTML pour publication sur le Web.

Voici un exemple de document Markdown n'utilisant, sauf erreur, que les constructions communes à toutes les variantes : test1.md. On peut le traiter, par exemple avec discount, une mise en œuvre simple de Markdown, en C, qui ne peut produire que du HTML :


% markdown  test1.md 
<h1>Début</h1>

<p>Un test très simple
en Markdown.</p>
...
<h2>Suite</h2>
...

Mais on peut aussi utiliser le bien plus riche Pandoc, qui a de nombreuses extensions à Markdown, et peut produire beaucoup de formats de sortie, ici du PDF, via LaTeX :

% pandoc --to latex --latex-engine=xelatex -o test1.pdf test1.md
% evince test1.pdf
...

Un point important de Markdown est qu'il n'y a jamais d'erreur de syntaxe (section 1 du RFC) : tout fichier texte est un fichier Markdown légal (même s'il ne donne pas toujours le résultat attendu par son auteur). C'est donc un monde très différent de LaTeX ou de XML (au passage, ce blog est écrit en XML). Markdown se veut un langage léger, imposant peu de contraintes et peu d'apprentissage. Avec Markdown, on a toujours un résultat, même suboptimal. Ce n'est pas considéré comme un problème. Si on veut du « sérieux », il faut utiliser LaTeX ou DocBook.

La « spécification » de Markdown est très grossière, et laisse le doute sur beaucoup de points mais le choix de l'IETF a été de ne pas essayer d'en écrire une correcte : Markdown est fait ainsi.

Un autre point important est le grand nombre de variantes, souvent incompatibles. L'auteur original, John Gruber, a toujours refusé de permettre des évolutions du langage et chacun a donc ajouté les siennes. Il y a eu plusieurs tentatives de normalisation (la principale étant CommonMark), mais sans résultat clair. Au début du processus long et compliqué qui a abouti à ce RFC, il était question de faire une nouvelle tentative, sous la houlette de l'IETF cette fois. Mais le projet RFC s'est assez vite rabattu sur une ambition plus modeste : enregistrer le type MIME et documenter (partiellement) l'état de Markdown. Un autre RFC, le RFC 7764, décrit les usages de Markdown. La discussion a été d'autant plus chaude que la « communauté » Markdown est largement extérieure à l'IETF.

On pourrait dire que Markdown n'est pas un langage, mais une famille de langages, ayant des éléments communs. Un bon exemple de la variété de Markdown est, par exemple, le cas des métadonnées. Pandoc permet d'écrire en début de fichier :

% Document title
% Document author
% Document date

Mais d'autres variantes de Markdown ne vont pas comprendre ces métadonnées, les laissant telles quelles. Autre exemple de variété, les commentaires, pour lesquels il n'existe pas de solution standard (il y a un bon article sur StackOverflow qui discute les différentes possibilités.)

Cet enregistrement du type MIME de Markdown s'inspire de celui de text/troff, un type pour un autre langage de marquage (RFC 4263). Après tout, beaucoup de gens considèrent que Markdown est « le troff d'aujourd'hui ».

La section 2 de notre RFC décrit formellement l'enregistrement du type MIME text/markdown et de l'extension associée, .md (.markdown est également accepté). Ce type a plusieurs paramètres possibles (les paramètres sont mis après un point-virgule, par exemple text/markdown; charset=UTF-8; variant=Original va désigner du Markdown à la syntaxe originale de Gruber, encodé en UTF-8).

Premier paramètre, et obligatoire (RFC 6838, section 4.2.1), charset, qui désigne l'encodage du texte. Les autres paramètres sont facultatifs.

Le plus important est sans doute variant qui désigne le dialecte Markdown particulier utilisé. Ce fut l'une des plus chaudes discussions à l'IETF avant la sortie de ce RFC. Notamment, fallait-il un registre IANA des variantes (une sorte de catalogue des dialectes) ou bien laisser les auteurs mettre ce qu'ils veulent, ce qui correspondait mieux au côté très peu organisé de la « communauté » Markdown, très informelle ? (Différentes versions du draft qui a mené à ce RFC faisaient des choix différents.) Le paramètre variant a finalement un registre (section 6.1) mais l'émetteur n'est pas obligé de se limiter aux valeurs de ce registre. Il faut considérer la valeur de ce paramètre comme une simple indication. Parmi les valeurs actuellement enregistrées : Original (le Markdown des débuts, celui de Gruber), GFM (celui de GitHub), pandoc (celui de ce logiciel), CommonMark (le candidat à la normalisation) etc. Notez que ce paramètre variant, au gré des évolutions du draft à l'IETF, s'est nommé syntax, flavor, processor...

Des valeurs sont interdites dans ce registre : Standard, Common et Markdown ne peuvent être enregistrés comme variantes. C'est parce que « une partie de la communauté » (en réalité Gruber seul) a protesté contre la volonté de déclarer une variante particulière comme étant « standard » ou « officielle ».

Et si on veut ajouter une entrée à ce registre des variantes de Markdown ? La politique d'enregistrement est le « Premier Arrivé, Premier Servi » du RFC 5226, donc très légère. Il suffit d'indiquer deux-trois trucs sur la variante et roulez, jeunesse. Dans des versions initiales de ce RFC, le gabarit d'enregistrement d'une variante était bien plus complexe, bien trop détaillé, avec des infos très volatiles comme currently maintained ou anticipated output types mais il est maintenant réduit à seulement cinq champs obligatoires.

Un des projets qui avaient été lancés était celui d'enregistrer non pas les noms des variantes mais leurs caractéristiques (« permet les notes de base de page », « permet la création automatique de liens hypertexte »). À la réunion IETF 90, la proposition était de pouvoir écrire des choses comme text/markdown;variations=footnotes,line_blocks pour désigner du texte Markdown utilisant les notes de bas de page et les blocs de lignes considérés comme un paragraphe. Une telle approche aurait nécessité la constitution d'un catalogue compliqué, et aurait imposé aux auteurs de garder trace de quelles extensions ils utilisent. Elle n'a finalement pas été retenue.

L'enregistrement d'un type MIME nécessite une analyse de ses risques de sécurité. Rien d'extraordinaire ici, le RFC note juste que du texte avec du marquage ne présente guère de risque (contrairement à un format comme TrueType qui inclut un langage de Turing). Attention toutefois : ce que le processeur Markdown ne comprend pas, il l'envoie verbatim dans le format de sortie (ce truc est souvent utilisé pour mettre du HTML spécifique, ou du JavaScript, lorsqu'on utilise Markdown pour produire des pages Web). Du logiciel malveillant peut donc être copié ainsi.

Et la section sur l'interopérabilité rappelle ce qui a été dit plus haut : les différents Markdown vont donner des résultats différents, d'autant plus différents qu'ils utilisent des techniques spécifiques d'une variante.

Et si on veut indiquer un point précis d'un document Markdown ? Contrairement à HTML, Markdown n'a pas d'identificateurs de fragments d'un texte (section 3 du RFC). Mais on peut réutiliser une partie de la syntaxe du RFC 5147 : en terminant un URI par #lines=N, on accède (si le logiciel client connait le RFC 5147) à la Nième ligne du document Markdown.

À noter qu'on peut écrire des RFC en Markdown : c'est expliqué dans le RFC 7328 et c'est utilisé, par exemple, pour ceux du groupe Human Rights Protocol Considerations de l'IRTF (ce groupe est typiquement moins geek que la moyenne de l'IETF/IRTF).

Un exemple plus important que l'exemple un peu artificiel test1.md que je donnais au début est mon rapport sur la panne DNS d'Oleane. On peut le traiter avec Pandoc et un Makefile comme :

TARGETS=panne-dns-oleane-2016.pdf panne-dns-oleane-2016.html

all: ${TARGETS}

%.pdf: %.md
	pandoc --latex-engine=xelatex -o $@ $^

%.html: %.md
	pandoc -o $@ $^

clean:
	rm -f ${TARGETS}
    

Markdown est souvent présent dans les « micro-éditeurs » qui permettent de remplir des documents via le Web. C'est le cas à GitHub où les gists dont le nom se termine par .md sont automatiquement convertis. C'est ainsi que j'ai fait un gist de ce rapport (cliquez sur le bouton Raw pour avoir le source).

Quelques lectures sur Markdown :


Téléchargez le RFC 7763


L'article seul

RFC 7754: Technical Considerations for Internet Service Blocking and Filtering

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : R. Barnes (Mozilla), A. Cooper (Cisco), O. Kolkman (ISOC), D. Thaler (Microsoft), E. Nordmark (Arista)
Pour information
Première rédaction de cet article le 10 mars 2016


Normalement, l'Internet est ouvert. C'est même une de ses principales caractéristiques : un outil de communication ouvert, où tout le monde peut s'exprimer. C'est cette ouverture qui est à la base de son succès. Mais une de ses conséquences est que certaines communications vont être indésirables pour certains. Il y a donc une demande pour du « blocage » ou du « filtrage », afin d'empêcher ces communications. Ce nouveau RFC, dû à l'IAB, examine les techniques de blocage et de filtrage et cherche lesquelles sont le plus compatibles avec une architecture saine et robuste de l'Internet. Évidemment, les techniques qui menacent le moins la robustesse de l'Internet sont celles qui se déroulent entièrement aux extrémités. Si je ne veux pas voir les publicités, j'installe un logiciel qui télécharge sur ma machine une liste noire de serveurs distribuant ces publicités, et je peux ainsi bloquer et filtrer sans risques pour l'utilisation de l'Internet par les autres. Mais, hélas, pas mal de gens puissants se moquent de fragiliser l'Internet (ou la démocratie) et bien d'autres méthodes de blocage ou de filtrage existent.

On voit tout de suite que ce RFC est très politique. Les filtrages dont il parle sont évidemment ceux de gens ayant du pouvoir (entreprises, États) et qui vont essayer d'empêcher M. Michu de voir ce qu'il veut. Mais l'IAB essaie de ne pas faire trop de politique, et se limite à analyser le problème technique. Ce RFC est un excellent document, analysant très finement les systèmes de filtrage et blocage, et restant sous l'angle technique, à la fois par désir de ne pas prendre position trop clairement et aussi parce que, pour l'Internet, une censure légale/légitime et une attaque ne sont pas différentes.

Le problème des « communications non souhaitées » est vaste. Il ne se limite pas aux pages Web qui déplaisent aux ministres et que ceux-ci souhaitent censurer. Il y a aussi le logiciel malveillant (qui remonte à loin), les attaques, le spam, etc. C'est donc depuis longtemps qu'il existe des techniques de blocage et de filtrage, et depuis aussi longtemps qu'elles sont vigoureusement contestées.

Le RFC 4084 notait déjà que certains FAI bloquaient l'accès à certains services. Parfois, cela se fait avec le consentement de l'utilisateur, consentement parfois très contestable : si, pour avoir un accès Internet à l'hôtel, vous devez cliquer « J'accepte » après un texte de vingt pages, y a-t-il réellement eu consentement ? Mais, souvent, il n'y a même pas de semblant de consentement : certains voudraient bloquer sans que l'utilisateur soit d'accord, et parfois sans même qu'il soit informé. Si ces « certains » ne contrôlent pas le réseau, ils cherchent à atteindre leurs fins en agissant sur des intermédiaires (comme les résolveurs DNS), et tant pis pour les dommages collatéraux.

J'ai parlé de « blocage » et de « filtrage », quelle est la différence ? On dit en général « blocage » quand on interdit complètement l'accès à un agrégat de ressources et « filtrage » quand il s'agit de sélectivement empêcher l'accès à certaines ressources seulement, dans cet agrégat. Si on empêche l'accès à tout YouTube, c'est du blocage. Si on empêche seulement l'accès à certaines vidéos, c'est du filtrage. Pour l'analyse dans ce RFC, cela ne change pas grand'chose, et on parlera indifféremment de filtrage ou de blocage.

Selon le pays, l'époque, les opinions politiques de la personne à qui on parle, ce filtrage peut être vu comme légal, illégal, éthique, acceptable, dégueulasse, souhaitable, stupide, scandaleux et contraire aux droits de l'homme, indispensable, etc. Mais, pour l'analyse technique qui est faite par l'IAB, cela ne fait pas de différence. Notamment, la distinction légale/illégale est non seulement très complexe (le gouvernement turc a-t-il le droit de détourner l'adresse IP d'un serveur états-unien ?) mais également sans conséquences pour la technique. (Un logiciel ne sait pas ce qui est légal ou illégal et il travaille de la même façon dans les deux cas.)

C'est encore plus vrai pour la distinction éthique/pas éthique, que notre RFC considère comme hors sujet, et sur laquelle il ne prend donc pas position.

La section 2 du RFC donne plusieurs exemples de filtrage ou blocage. Historiquement, les premiers systèmes qui se mettaient sur le trajet entre Alice et Bob étaient les pare-feux (RFC 2979). Ils peuvent être déployés sur les machines terminales (c'est aujourd'hui le cas du Netfilter de Linux) ou bien sur le réseau (souvenir personnel lointain : les débuts avaient été difficiles car certains systèmes supportaient mal qu'une machine soit joignable via certains ports et pas d'autres : c'est ainsi qu'au début des années 1990, Ultrix coupait toute communication avec une machine dès qu'il recevait un ICMP indiquant qu'un port était bloqué).

Il y a bien des sortes de pare-feux, le RFC 4949 contient des définitions, et le RFC 4948 décrit les différents types de trafic non souhaités, ceux qu'on veut typiquement bloquer avec le pare-feu. Notamment, on distingue traditionnellement (ces termes sont absents du RFC 4949, qui est assez ancien) :

  • Les pare-feux sans état, où chaque paquet est traité indépendemment des autres. Ce sont les plus simples à réaliser et les premiers apparus. Ils permettent, par exemple, de bloquer toute connexion sortant vers le port 25 (celui de SMTP), pour empêcher les zombies d'envoyer du spam.
  • Les pare-feux avec état, qui ont une mémoire des précédents paquets, ce qui permet des politiques plus subtiles comme de bloquer tout paquet entrant qui ne correspond pas à un flot de données déjà établi (une connexion TCP, par exemple). Ils sont plus complexe à réaliser (et donc plus fragiles) et l'état nécessite de la mémoire, les rendant très vulnérables en cas d'attaque par déni de service (le pare-feu à état plante souvent avant le serveur qu'il était censé protéger).
  • Les pare-feux capables de DPI. Le terme est assez flou mais il désigne en général, de façon assez arbitraire, les pare-feux qui examinent au-delà de la couche 4, par exemple en regardant le contenu applicatif.

Autre exemple de filtrage, celui du Web. Comme les dirigeants, en général, ne connaissent de l'Internet que le Web, c'est souvent sur celui-ci que portent les efforts de censure. Il est donc fréquent que le filtrage soit spécifique à certains URI, soit en détournant tout le trafic HTTP vers un proxy qui examine les URI, soit par DPI. Évidemment, HTTPS rend bien plus compliqué ce filtrage. Mais ne l'empêche pas complètement, en raison des failles du modèle de sécurité de X.509 : par exemple, le filtreur peut obtenir un faux certificat d'une autorité existante, ou bien faire installer sur les ordinateurs une autorité de certification qui validera les faux certificats générés par le système de filtrage.

Le filtrage n'est pas forcément fait par des méchants dictateurs voulant empêcher les citoyens d'accéder à des informations honnêtes. Un bon exemple d'un filtrage que la majorité des utilisateurs apprécie, et même réclame, est le filtrage du spam. C'est même sans doute dans la lutte contre le spam que le filtrage a trouvé une de ses premières applications. Une des armes utilisées, les listes noires, est, techniquement, tout à fait comparable aux outils de la censure (RFC 5782).

Un autre exemple cité dans le RFC d'un filtrage volontaire par les utilisateurs est le safe browsing, quand le navigateur Web connait une liste de sites Web méchants ou dangereux, et refuse de s'y connecter.

Et le filtrage des noms de domaine ? Cela peut se faire en supprimant ledit nom, par exemple par la procédure de justice privée UDRP (cf. Moore, T. et R. Clayton, « The Impact of Incentives on Notice and Take-down », Workshop on the Economics of Information Security 2008, et Chachra, N., McCoy, D., Savage, S., et G. Voelker « Empirically Characterizing Domain Abuse and the Revenue Impact of Blacklisting », Workshop on the Economics of Information Security 2014. Cette approche nécessite de disposer d'un moyen politique d'action contre le registre qui gère le nom (notez que c'est la loi du pays du registre qui compte, pas la loi du titulaire, comme l'avait illustré l'affaire RojaDirecta).

Mais la censure d'un nom de domaine peut aussi se faire dans le DNS. (Au passage, arrêtez de lire ici et allez, si ce n'est pas encore fait, allez voir l'excellent rapport du conseil scientifique de l'AFNIC « Conséquences du filtrage Internet par le DNS ».) Dans ce cas, un résolveur menteur va donner, pour ce nom de domaine, un autre résultat que celui prévu par le titulaire du nom (c'est ainsi que fonctionne la censure administrative française). Cette technique est utilisée dans de nombreux pays, même si elle fragilise l'Internet, par exemple en perturbant le déploiement de DNSSEC.

Une autre technologie d'infrastructure qui risque d'être utilisée pour le filtrage est le routage. En manipulant le routage de l'Internet, on peut empêcher l'utilisateur d'accéder où il veut. Un exemple typique a été l'action aux Pays-Bas contre le RIPE-NCC dans l'affaire DNSChanger.

Après ce tour des exemples de filtrage (le RFC en cite plusieurs autres que je n'ai pas repris ici), passons maintenant à la théorie et essayons de classer ces systèmes de blocage. Il y a quatre critères de classement importants :

  • Qui bloque ?
  • Pourquoi bloque-t-il ?
  • Quelle est la cible technique du blocage ?
  • Quoi, quel composant de l'Internet est utilisé pour le blocage ?

La liste des cas présentés à la section 2 était délibérement très variée, utilisant des cas qui se classent très différemment selon ces critères.

Commençons, par le premier critère, qui bloque. On a vu des blocages par la police, par des tribunaux, par des entreprises, par des opérateurs réseau et par des utilisateurs individuels. Souvent, la décision est prise par une entité et ensuite appliquée par une autre. Par exemple, le ministère de l'Intérieur décide de bloquer un site Web « djihadiste » mais c'est un FAI qui, via son résolveur DNS menteur, effectue le blocage. (Le RFC n'en parle pas mais un autre exemple est celui où une entreprise choisit d'utiliser un résolveur menteur, par exemple OpenDNS, comme résolveur. OpenDNS affirme toujours que leurs clients ont choisi le blocage. Mais, dans ce cas, l'employé de base a-t-il réellement choisi ?)

Second critère, pourquoi on bloque. On peut bloquer « pour des raisons de sécurité » (c'est souvent une excuse pipeau mais il y a aussi des vraies raisons de sécurité). Par exemple, on va bloquer les sites Web qui distribuent du logiciel malveillant. Ou bien on va bloquer les communications avec tel préfixe IP, d'où partent souvent des attaques.

On peut aussi bloquer un contenu dont on ne veut pas. Le RFC ne cite pas cet exemple mais on pense évidemment aux bloqueurs de pub. Il y a aussi bien sûr les cas de censure étatique, où l'État ne veut pas que les citoyens accèdent à tel site Web. Les raisons sont nombreuses, de la pédopornographie au jeu en ligne en passant par la vente de drogues, la propagande raciste ou la violation des droits sacrés des ayant-droits.

Le blocage peut aussi se faire pour des raisons économiques, par exemple un service d'accès à l'Internet gratuit mais qui bloquerait la plupart des sites, nécessitant une option payante pour y accéder.

Le blocage peut se faire par liste noire (on laisse passer par défaut, et on a une liste des choses interdites, c'est typiquement le cas avec la censure) ou carrément par liste blanche (on bloque par défaut et on a une liste des choses autorisées, c'est typiquement le cas des offres limitées). Une entreprise qui ne veut pas que ses employés passent du temps sur autre chose que les tâches qui leur sont affectées pourrait utiliser une liste noire (interdire ce qui leur ferait « perdre » du temps) ou la liste blanche (limiter les employés à quelques destinations connues).

Troisième critère de classification, quelle est la cible exacte ? Veut-on bloquer un service entier (par exemple la voix sur IP, pour protéger la vache à lait des opérateurs téléphoniques) ? Ou un contenu très spécifique (une seule vidéo sur YouTube) ? Certaines techniques bloquent facilement plus que la cible visé. Par exemple, supprimer un nom de domaine parce que le site Web sert un contenu à problèmes va aussi couper tous les services associés à ce nom de domaine (le courrier par exemple). Les demandes de take down (« le site Web en http://example.com/ vend de la contrefaçon, supprimez immédiatement ce nom ») prennent rarement en compte ce problème. Si on les écoutait, chaque fois que le WordPress d'une mairie est piraté et sert à du hameçonnage, on supprimerait le nom de domaine, coupant ainsi l'accès des citoyens à leur ville.

Enfin, quatrième cas, le comment, quels composants de l'Internet vont être utilisés pour le blocage. Cela peut être :

  • La machine terminale, client ou serveur (ou pair, dans le cas du pair à pair),
  • Le réseau, par exemple les routeurs,
  • Et un composant auquel on ne pense pas toujours, les services de rendez-vous, comme le DNS ou comme une DHT, qui ne sont pas dans le chemin direct entre les machines terminales, mais qui sont en général indispensables à l'établissement d'une communication.

Par exemple, lorsque M. Michu veut accéder à http://example.com/comment-partir-en-syrie avec son navigateur Web, les machines terminales sont son PC et le serveur HTTP, le réseau, ce sont tous les routeurs et autres équipements actifs sur le trajet, le service de rendez-vous, c'est le DNS (par exemple le registre de .com). Autre exemple, Alice appelle Bob en SIP, les machines terminales sont le smartphone d'Alice et le PC de Bob, le réseau, ce sont tous les routeurs et autres équipements actifs sur le trajet, le service de rendez-vous, c'est le proxy SIP.

Dans l'exemple HTTP ci-dessus, on peut empêcher M. Michu de regarder la page Web à de très nombreux endroits. Le RFC donne la liste complète mais voici quelques extraits, aux trois endroits possibles :

  • On peut empêcher le navigateur de faire des requêtes vers cet URL (c'est ce que font les bloqueurs de pub),
  • On peut configurer le réseau pour envoyer tout le trafic vers le serveur dans un trou noir,
  • On peut supprimer le nom de domaine example.com.

Le choix dépendra souvent de qui bloque. Si c'est l'utilisateur (cas des bloqueurs de pub), il fera en général le blocage sur sa machine terminale. Si c'est l'État, il utilisera plus souvent le réseau ou bien le système de rendez-vous (s'il est sur son territoire, ainsi, un .com peut être saisi par les autorités états-uniennes).

Le gros du RFC est représenté par la section 4, qui évalue les différentes techniques. Les critères d'évaluation sont la portée, la granularité, l'efficacité et la sécurité. Commençons par la portée (qui est affecté).

Si je configure Shorewall sur ma machine Linux pour bloquer le trafic vers 2001:db8:bad:1:ef5:34:aba1:96, je n'affecte qu'une toute petite partie de l'Internet. Si le gouvernement des États-Unis décidait de supprimer .ir de la racine du DNS, il affecterait bien plus de monde (« About 35,400,000 results » me dit Google). D'une manière générale, le blocage fait aux bords de l'Internet affecte peu de gens, celui fait dans le réseau affecte beaucoup de monde, sans doute bien plus que ce qui était nécessaire. Les exemples de « bavures » (le blocage « bave » au delà de sa portée normale) sont nombreux, de l'Inde censurant Oman, au célèbre cas de Pakistan Telecom bloquant YouTube, en passant par la censure chinoise débordant en Allemagne. Le « bon » blocage devrait avoir la portée la plus petite possible.

Et la granularité ? Est-ce qu'on pourra bloquer un service sans bloquer les autres ? Par exemple, si une machine héberge un serveur SMTP qui envoie du spam, peut-on la bloquer sans empêcher l'accès aux autres ressources qu'elle héberge, comme un serveur HTTP ? Idéalement, là encore, on souhaite que le blocage puisse être fait avec la granularité la plus fine possible.

Et l'efficacité ? Si on bloque, on veut qu'il ne soit pas facile de « débloquer », c'est-à-dire d'accéder aux ressources bloquées. Évidemment, si le blocage est fait par l'utilisateur (comme dans le cas des bloqueurs de publicité), pas de problème : il ne va évidemment pas chercher à contourner ce blocage. Mais si le blocage est imposé, l'expérience de l'Internet montre que les utilisateurs vont chercher à le contourner (voir par exemple les articles « Failures in a Hybrid Content Blocking System » et « Empirically Characterizing Domain Abuse and the Revenue Impact of Blacklisting »). Un service bloqué se déplace facilement, comme le montre les fréquents changements de TLD de The Pirate Bay. Du côté client, les solutions de contournement sont également nombreuses, du passage par Tor, à l'utilisation de son propre résolveur DNS pour contourner les résolveurs menteurs. Ces contournements mènent parfois à une escalade puis à une course aux armements comme dans le cas turc où le DNS menteur était contourné par l'utilisation de Google Public DNS, ce qui avait mené au piratage du routage de Google. Un autre exemple de course aux armements est le blocage des services par leur numéro de port, poussant les applications à toujours utiliser le port 80, celui de HTTP, poussant les bloqueurs à faire du DPI, poussant les applications à chiffrer, poussant les bloqueurs à faire de l'analyse de trafic pour essayer de détecter, sous le chiffrement, certains type de trafic, etc. Une telle course ne peut pas avoir de fin.

Certains de ces contournements ont d'ailleurs des conséquences pas forcément positives pour l'architecture de l'Internet. C'est ainsi que beaucoup d'applications se pressent sur le port 443, celui de HTTPS, car il est rarement filtré. Ou bien que des victimes d'un blocage de SIP passent à des solutions fermées comme Skype. Le RFC note au passage que le chiffrement rend évidemment plus difficile tout filtrage sélectif, et que cela va donc jouer dans la diabolisation du chiffrement.

Dernier exemple de technique de contournement du blocage, citée par le RFC mais jamais vue en pratique (mais elle amusera les nerds), l'ajout d'en-têtes d'extension dans les paquets IPv6 (par exemple une option Destination) suffit souvent aujourd'hui à rendre aveugles les filtres (ces en-têtes sont parfois difficiles à analyser).

Dans l'évaluation du blocage, reste la question de la sécurité : les techniques de sécurité sur l'Internet cherchent à empêcher toute interférence d'un tiers. Le blocage ne va-t-il pas entrer en conflit avec ce souhait ? Techniquement, rien ne distingue une attaque légale d'une attaque illégale : les mêmes techniques de sécurité vont réagir contre les deux. C'est le cas des protocoles qui visent (entre autres) à assurer l'intégrité des communications (TLSRFC 5246 ou IPsecRFC 4301). Lorsqu'on accède au site de sa banque en TLS, c'est précisement pour empêcher un tiers de modifier les données, justement ce que la censure aimerait bien faire.

La sécurité sur l'Internet repose en général sur des techniques de bout en bout, les seules sûres (RFC 4924). Certains blocages (comme le détournement des sessions TLS) nécessitent d'insérer dans le trafic un intermédiaire non prévu à l'origine, ce qui casse cette sécurité.

La section 4 du RFC se penche ensuite sur les trois lieux où on peut faire le blocage, le réseau, puis le rendez-vous, puis la machine terminale. D'abord, le réseau, par exemple via un pare-feu. Est-ce un bon endroit pour bloquer ? Si on bloque dans un réseau périphérique, proche d'une des machines terminales qui communiquent, la portée reste faible. Si, par contre, on bloque dans l'épine dorsale d'un grand réseau, la portée sera bien plus étendue (dans le cas d'une censure volontaire, une portée importante n'est pas un défaut...) Notez que le blocage dans le réseau nécessite que le réseau ait accès à suffisamment d'informations pour prendre sa décision. Cela peut mener à des pratiques comme le DPI.

Notez qu'un filtrage dans le réseau peut être complexe car rien ne dit qu'un point du réseau verra passer tout le trafic entre Alice et Bob. Pour des blocages sommaires (« couper toute communication avec 192.0.2.0/24 »), ce n'est pas un problème. Mais cela interdit des choses plus subtiles, par exemple de bloquer certains URI sur un site Web mais pas tous. Le routage dans l'Internet étant ce qu'il est, un point donné peut ne voir qu'une partie des paquets d'une même communication. C'est d'ailleurs pour cela que les censeurs essaient toujours d'obtenir que les réseaux soient architecturés de manière à faciliter le blocage, notamment en limitant le nombre de points de sortie vers l'extérieur et en empêchant l'asymétrie du routage (en se moquant des conséquences que cela peut avoir pour les performances et la fiabilité).

Quant à l'efficacité et la sécurité du blocage dans le réseau... Le chiffrement suffit à gêner une grande partie de ces blocages. Il ne laisse que quelques métadonnées comme les adresses IP, qui peuvent être trop grossières pour le système de filtrage.

Et les techniques de contournement sont nombreuses, comme cela a pu être vu dans la lutte des ayant-droits contre The Pirate Bay. Le site visé peut changer d'adresse IP, ou de nom, ses clients peuvent passer par Tor ou par un VPN, etc. Évidemment, plus le blocage reste en place longtemps, plus les techniques de contournement se développeront et seront déployées. Si on bloque dans le réseau, c'est en général parce que les deux parties qui communiquent ne sont pas d'accord avec ce blocage. Elles ont donc des bonnes motivations pour le contourner et la lutte de l'épée et de la cuirasse va donc durer longtemps.

Le bloqueur peut essayer de bloquer l'accès aux services qui permettent un contournement. Par exemple, il peut interdire TLS vers certains sites. Comme l'a montré le projet Telex, même cela n'est pas forcément suffisant : on peut toujours, avec la participation d'un pair accessible, faire des tunnels peu repérables. Plus radical, le censeur peut interdire tout le chiffrement (en France, des tas de politiciens ne demanderaient pas mieux). Cela serait évidemment catastrophique pour la sécurité de l'Internet.

Le RFC conclut donc que le blocage dans le réseau est en général une mauvaise idée.

Bon, mais alors, se dit le censeur qui lit les RFC (cela doit être rare...), pourquoi ne pas bloquer via les systèmes de rendez-vous à la place ? En effet, on a beau parler de pair à pair, presque toutes les communications réelles sur l'Internet nécessitent un mécanisme mettant en rapport les machines de Bob et d'Alice. C'est souvent le DNS mais cela peut être un moteur de recherches (Pirate Bay joue ce rôle, mettant en rapport un utilisateur de BitTorrent et le contenu convoité) ou bien d'autres mécanismes (comme les DHT ou une blockchain).

Le blocage sur le service de rendez-vous est surtout utile pour un État si ledit service est sous sa juridiction. Si vous utilisez un .ly, vous dépendez logiquement des lois libyennes. Si le service est global (c'est le cas d'un registre de noms de domaine), la portée du blocage est également globale. C'est ce qui fait qu'un service légal dans son pays a pu perdre son .com et donc tous ses clients. Si par contre le service est local (un résolveur DNS), la portée est limitée aux utilisateurs de ce service.

Lorsque le système de rendez-vous est le DNS, la granularité du blocage est mauvaise : supprimer le nom de domaine supprime tous les services associés. Quant à l'efficacité, elle n'est jamais parfaite (voir mon article pour une étude sur le cas du DNS ou bien le rapport de l'ISOC) : les utilisateurs peuvent souvent changer de point de rendez-vous (passer à un autre résolveur DNS, par exemple), d'autant plus que la plupart des systèmes de rendez-vous n'ont aucune sécurité (des techniques d'authentification comme DNSSEC pour le DNS changeront peut-être partiellement les choses).

Un autre système de rendez-vous est souvent oublié : les IRR et, d'une manière plus générale, le mécanisme d'allocation d'adresses IP. Dans au moins un cas (déjà cité plus haut), un État a essayé de l'utiliser pour bloquer un service illégal.

En résumé, le blocage par action sur un service de rendez-vous est simple (et donc tentant pour les autorités) car on n'agit que sur un seul point, ou un petit nombre de points, mais n'est pas très efficace et, comme il consiste à bricoler l'infrastructure de l'Internet, il est dangereux pour le bon fonctionnement de celui-ci.

Reste un dernier endroit, dans l'une des machines terminales. Quelles sont les propriétés d'un blocage fait à cet endroit ? À chaque instant, le logiciel installé sur ces machines ou bien leur utilisateur prend des décisions sur le fait de communiquer ou pas. Les utilisateurs choisissent (ou pas) de cliquer sur un lien hypertexte. Le logiciel de messagerie décide si un message doit être montré ou classé dans le dossier Spam. Netfilter jette les paquets ou pas. L'utilisateur installe un nouveau logiciel de communication (ou pas). Les choix du logiciel sont guidés par l'utiisateur (cas d'un filtre bayésien à qui l'utilisateur dit « ce message est un spam ») mais le contraire arrive aussi (SafeBrowsing).

La portée d'un tel blocage est strictement locale. Si j'installe Ghostery pour bloquer les mouchards, cela n'affecte (en bien ou en mal) que moi.

La granularité est très fine : la machine terminale maitrise tous les aspects de la connexion contrairement à, par exemple, le serveur DNS, qui n'a aucune idée de pourquoi on demande ce nom de domaine. Elle peut donc ne bloquer qu'un seul service. Encore mieux si le blocage est fait dans l'application (le cas, là encore, des bloqueurs de publicité) car ils ont la totalité de l'information sur la connexion, sous une forme qui permet des traitements sans ambiguité (cf. RFC 7288).

L'efficacité est bonne. D'abord, puisque le blocage est décidé par l'utilisateur, il ne va évidemment pas chercher à le contourner. Ensuite, les services bloqués peuvent, évidemment, essayer de s'adapter (le point de distribution d'un malware va changer souvent de nom de domaine et d'adresse IP, pour disparaitre des listes noires) mais la machine terminale ayant une visibilité complète (y compris de ces changements) est dans une meilleure position que quiconque pour s'y adapter. Comme le blocage se fait aux extrêmités, il ne gêne pas l'architecture de bout en bout (chacun est bien sûr libre d'accepter de communiquer avec qui il veut).

À noter qu'il existe deux extrêmités à la communication : le blocage peut aussi être fait de l'autre côté, par le serveur (dans le cas d'une communication client/serveur). Voici par exemple les compteurs du nombre de paquets rejetés sur le serveur qui porte ce blog. On voit que je n'accepte pas tout :-)

% sudo iptables -n -v -L net-fw
Chain net-fw (2 references)
 pkts bytes target     prot opt in     out     source               destination         
9360K  659M blacklst   all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 679K   49M smurfs     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID,NEW,UNTRACKED
9041K  625M tcpflags   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           
74720   11M Drop       all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 8881  631K DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    

On peut faire la même chose de tas de façons. Par exemple, un serveur HTTP comme Apache a plein de techniques permettant toutes sortes de blocages des visiteurs importuns. Et, évidemment, pour bloquer un service entier sur le serveur, c'est très facile, on ne fait tout simplement pas tourner le logiciel correspondant.

Bien sûr, ce blocage nécessite l'accord de la personne qui utilise ladite machine terminale et les censeurs ne seront donc pas enthousiastes à l'idée de lui demander.

Bref, le blocage sur une des machines terminales est de loin celui qui a le moins de chances de causer des dommages collatéraux sur l'Internet.

Comme tous les RFC, notre RFC 7754 contient une section dédiée à la sécurité, la section 5. Son point essentiel est que le blocage dans le réseau ou dans les services de rendez-vous est un danger pour la sécurité de l'Internet : il s'oppose frontalement aux mesures de sécurité. Par exemple, pour bloquer, on va essayer de casser le chiffrement, avec une attaque de l'homme du milieu, comme le font beaucoup d'entreprises, avec les produits de société comme Blue Coat, en fabriquant de faux certificats pour que les logiciels ne détectent pas cette attaque.

En outre, le système qui effectue cette attaque devient lui-même une cible tentante pour un attaquant extérieur puisqu'il donne accès à tout le trafic en clair. On a donc mis en péril toutes les machines de l'entreprise en introduisant cette « machine du milieu ». (En tant qu'ancien ingénieur système, je suis également sensible à la remarque du RFC comme quoi l'administrateur de cette machine court un gros risque juridique personnel, puisqu'il va avoir accès à des tas de données sensibles.)

La conclusion du RFC (section 6) est que, si on tient à faire du blocage, il faut le faire sur les machines terminales et laisser le réseau tranquille, afin qu'il puisse faire son travail avec rapidité et sécurité. Gageons que cet avis ne sera pas suivi. Parmi toutes les discussions sur le blocage, le filtrage et la censure, beaucoup de temps a été passé sur la légitimité ou non de ces blocages (« si vous vous opposez à la Main Rouge, c'est que vous sympathisez avec les terroristes ») et nettement moins sur les conséquences techniques de ces blocages. En gros, si on veut faire de la censure efficace, il faut ré-architecturer l'Internet pour la censure et non pas pour la communication. (Cf. mon exposé à l'Assemblée Générale de France-IX, et les supports.)

Un des auteurs du RFC, Olaf Kolkman, a écrit ses réflexions personnelles.


Téléchargez le RFC 7754


L'article seul

RFC 7749: The 'XML2RFC' version 2 Vocabulary

Date de publication du RFC : Février 2016
Auteur(s) du RFC : J. Reschke (greenbytes)
Pour information
Première rédaction de cet article le 7 février 2016


Contrairement à beaucoup de SDO, l'IETF n'a pas de format standard pour l'écriture de ses documents. XML est toutefois le plus répandu, avec le vocabulaire qui avait été autrefois décrit dans le RFC 2629, et qui est maintenant spécifié dans ce RFC. (Il a depuis été remplacé par le RFC 7991.)

Vous voulez écrire un RFC ? Un des choix possibles est un format XML, fondé sur un vocabulaire spécifique aux RFC, et mis en œuvre dans l'outil xml2rfc. Ce vocabulaire n'avait pas été mis à jour depuis seize ans (alors que l'outil évoluait) et c'est seulement maintenant, après un processus long et douloureux, que les auteurs d'Internet-Drafts et de RFC disposent enfin d'une description officielle et à jour du format dans lequel ils travaillent. Voici donc le vocabulaire « XML2RFC version 2 ».

Le format principal de publication des RFC est du texte brut, pour des raisons de portabilité, d'indépendance vis-à-vis de tout éditeur de logiciels spécifique, et de facilité de traitement automatique. Mais aucun auteur n'écrit les RFC directement dans ce format (rien que pour la numérotation des pages, cela serait infernal). Ils écrivent en des formats divers, et le convertissent ensuite en texte brut. À noter que certains éléments XML décrits ici ne produisent rien de particulier dans le texte final, mais sont utiles pour d'autres usages, comme l'indexation.

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"
     category="exp" 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>

    

(Un squelette plus détaillé est disponible en https://www.rfc-editor.org/materials/template-bare-06.txt.) Sur ce squelette simple, on voit l'élément racine (<rfc>), l'utilisation des attributs (comme category qui indique le statut du futur RFC, ici « expérimental »), 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.2) 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.)

<t> contient un paragraphe et est donc l'équivalent du <p> de HTML.

<artwork> est le seul élément qui permet de spécifier du texte qui sera représenté comme tel, sans aucune justification, mise à la ligne, etc. Il a gagné plusieurs attributs par rapport au RFC 2629, pour bien contrôler le résultat. <artwork> permet d'include du code source ou bien de mettre de l'art ASCII dans un RFC (pour l'instant, il n'y a pas encore d'autre mécanisme simple pour des images, mais c'est quand même possible, cf. le RFC 5598 avec ses différentes versions). Notez que l'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. Voici un exemple :


      <figure title="A network">
	<artwork>
 +--------------+				     +----------------+
 |  Alice       |------------------------------------|      Bob	      |
 | 2001:db8::1  |                                    |   2001:db8::2  |
 +--------------+				     +----------------+
	</artwork>
      </figure>

    

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

<list> permet de représenter les traditionnelles listes à puces :


<t>There are three sorts of DNS requests being issued:
<list>
<t>Primary request: [...]</t>
<t>Secondary requests: [...]</t>
<t>Tertiary requests: [...]</t>
</list>
</t>
    
    

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

Si vous voulez un exemple plus complet, regardez ce fichier. Vous pouvez le traiter avec xml2rfc :

% xml2rfc test-xml2rfc-v2.xml
[...]
Created file test-xml2rfc-v2.txt
    

Et vous obtenez un joli RFC.

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 (&lt; au lieu de <). Si cette contrainte est trop forte, on peut aussi enclore les parties à « échapper » dans une section CDATA.

Le format des RFC ne permet pas d'autres caractères que ceux du jeu ASCII. Néanmoins, certains caractères Unicode peuvent être utiles dans le source XML (section 4), pour contrôler certains aspects de la présentation :

  • Espace insécable U+00A0,
  • Tiret insécable U+2011,
  • Gluon de mots (empêche la césure entre deux lettres) U+2060.

La restriction actuelle à ASCII (elle était dans le RFC 2223, section 3a, mais n'a pas été formellement reprise dans son successeur, le RFC 7322) sera peut-être levée dans le futur, et ce RFC devra alors être mis à jour (section 6).

Le format actuel ne permet pas l'inclusion d'autres documents, donc un RFC doit être en une seule pièce, un seul fichier XML (section 5). On peut toutefois utiliser les mécanismes génériques d'inclusion de XML, 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 désormais 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-schema.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-schema.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 les processing instructions (PI) <?rfc ... ?> qui servent, par exemple, à contrôler si une table des matières est affichée. Pour connaitre celles acceptées par xml2rfc, il faut regarder la documentation de l'outil et la FAQ.

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.rnc test-xml2rfc-v2.xml
test-xml2rfc-v2.xml
    

Parfait, ici, tout est bon. S'il y avait eu une erreur :

% rnv rfc.rnc test-xml2rfc-v2.xml
test-xml2rfc-v2.xml
test-xml2rfc-v2.xml:9:4: error: element ^t not allowed
required:
	element ^section
    

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-ietf-dnsop-nxdomain-cut.xml | rnv rfc.rnc 
    

À noter que le RFC n'utilise pas rnv mais Jing (annexe C.1). Mode d'emploi très court, on télécharge :

%  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.rnc draft-ietf-dnsop-nxdomain-cut.xml
%
     

Les changements depuis le texte précédent, le RFC 2629, seize ans auparavant, sont résumés dans l'annexe B. L'élément <appendix>, qui servait pour les annexes des RFC (annexes assez fréquentes, de nos jours), a été supprimé. Pour faire une annexe, désormais, on met une <section> dans le <back>. En revanche, sept nouveaux éléments ont été ajoutés dont les plus importants, à mon avis, sont <texttable>, <ttcol> et <c>, qui permettent enfin de faire des tableaux proprement dans les RFC.


Téléchargez le RFC 7749


L'article seul

RFC 7748: Elliptic Curves for Security

Date de publication du RFC : Janvier 2016
Auteur(s) du RFC : A. Langley (Google), M. Hamburg (Rambus Cryptography Research), S. Turner (IECA)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF cfrg
Première rédaction de cet article le 24 janvier 2016
Dernière mise à jour le 29 janvier 2016


Ce nouveau RFC est la description de deux courbes elliptiques largement utilisées mais qui n'avaient pas fait l'objet d'une description formelle complète : curve25519 et curve448. Maintenant que c'est fait, elles pourront être utilisées dans des normes Internet utilisant la cryptographie comme TLS ou DNSSEC.

La cryptographie sur les courbes elliptiques est une alternative aux algorithmes traditionnels fondés sur la décomposition en facteurs premiers, comme le classique RSA. Il est toujours bon de ne pas mettre tous ses œufs dans le même panier, car on ne sait jamais quelle sera la prochaine victime de la cryptanalyse (d'où le RFC 7696, sur l'importance de ne pas être prisonnier d'un seul algorithme). Grâce aux courbes elliptiques, si RSA est cassé complètement, on aura une solution de rechange. En outre, la cryptographie sur les courbes elliptiques a des propriétés intéressantes, comme des clés de taille plus petite. Dans les deux cas, RSA ou courbes elliptiques, je n'y connais pas grand'chose donc n'espérez pas des explications plus pointues.

Le schéma général de la cryptographie sur courbes elliptiques est décrit dans le RFC 6090 (voir aussi le cours « SEC 1: Elliptic Curve Cryptography »). Ce schéma permet l'utilisation d'une infinité de courbes elliptiques mais attention, toutes n'ont pas les propriétés requises. La plus connue est la courbe P-256 normalisée par le NIST. Comme il y a de très bonnes raisons de se méfier du NIST (leur rôle dans l'affaiblissement délibéré de Dual EC DRBG, cf. l'article de Schneier et celui de Greenemeier), et comme les raisons des choix des paramètres de P-256 n'ont jamais été rendues publiques, beaucoup de gens se méfient de P-256 (voir une bonne discussion sur StackExchange). Il est donc important, là encore, d'avoir plusieurs fers au feu, et de disposer d'autres courbes.

Les deux courbes décrites dans ce RFC sont curve25519 et curve448. Elles sont de la famille des courbes de Montgomery (et donc ont une équivalence avec une courbe d'Edwards).

Il n'est pas facile de faire des maths dans un RFC, avec leur format actuel. La section 3 décrit la notation utilisée dans le RFC, mais je ne vais pas reproduire les équations ici (je suis complètement ignorant de MathML et ce blog ne le gère pas). Des formules comme (section 4.1) :

     (u, v) = ((1+y)/(1-y), sqrt(-486664)*u/x)
     (x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1))
    

sont nettement moins jolies dans le texte brut des RFC.

La section 4 du RFC décrit les deux courbes. Curve25519 doit son nom au fait qu'un des nombres premiers utilisés pour la génération des paramètres de la courbe est 2^255-19. Sa description originale est dans l'article de Bernstein « Curve25519 -- new Diffie-Hellman speed records », et son équivalent en courbe d'Edwards, ed25519 dans « High-speed high-security signatures ».

L'autre courbe, curve448, utilise le nombre premier 2^448-2^224-1. La courbe d'Edwards équivalente est nommée Goldilocks et est décrite dans « Ed448-Goldilocks, a new elliptic curve ».

La section 5 du RFC présente les fonctions X25519 et X448, utilisées pour faire du Diffie-Hellman avec ces courbes. Des vecteurs de test sont également fournis, si vous voulez vérifier votre implémentation (rappel au passage : il y a plein de pièges quand on programme de la crypto.)

En parlant de Diffie-Hellman, la section 6 est la description de l'utilisation de ces deux courbes pour un échange de clés ECDH, utilisant les deux fonctions de la section précédente.

Quelle est la sécurité de ces deux courbes (section 7) ? Le niveau de sécurité de curve25519 lors d'une attaque par force brute est d'un peu moins de 128 bits. Une attaque par force brute est normalement l'essai de toutes les clés possibles. Toutefois, le terme est souvent utilisé en cryptographie (avec un abus de langage) pour désigner des méthodes où on fait beaucoup d'essais, sans forcément tester toutes les clés (comme l'algorithme rho). D'autre part, le RFC rappelle qu'il n'est pas facile de comparer des algorithmes de cryptographie, surtout entre algorithmes symétriques et asymétriques, cf. l'article de Bernstein « Understanding brute force ».)

curve448 est normalement « meilleure », avec 224 bits de sécurité (mais plus lente : on n'a rien sans rien). Le RFC note que, pour des ordinateurs quantiques (si on en a un jour...), les deux courbes seront aussi faciles à casser l'une que l'autre. En attendant, curve25519 est parfaitement suffisant.

Notez que, si vous aimez la cryptographie quantique et les discussions sans fin, la NSA a publié en août 2015 un texte qui a stupéfié beaucoup de monde car il affirmait que, vu l'arrivée supposée proche des calculateurs quantiques, il n'était pas recommandé de faire des efforts pour migrer depuis RSA vers les courbes elliptiques. Certains en ont déduit que la NSA avait déjà des calculateurs quantiques et savaient donc que les courbes elliptiques étaient cassées ou proches de l'être, d'autres ont supposé que, si la NSA essayait de décourager les utilisateurs de se servir des courbes elliptiques, c'était au contraire une raison supplémentaire pour migrer vers ces courbes au plus vite. La polémique et l'état des informations disponibles sont très bien expliqués dans l'article « A riddle wrapped in an enigma ».

L'annexe A du RFC décrit comment les paramètres de ces deux courbes ont été générés. Des courbes comme la P-256 du NIST ou comme la courbe elliptique souveraine FRP256 de l'ANSSI ont été très critiquées car les différentes constantes utilisées sont juste annoncées, sans explication. Il n'y a pas besoin d'être excessivement paranoïaque, ou d'avoir lu les documents publiés par Snowden, pour se demander « Pourquoi ces valeurs plutôt que d'autres ? Ne serait-ce pas parce que ces constantes ont des propriétés qui facilitent leur décryptage par la NSA ou un organisme similaire ? ». Il y a consensus aujourd'hui pour dire qu'on ne doit utiliser que des courbes pour lesquelles le choix des paramètres a été fait « objectivement », selon une méthodologie expliquée et vérifiable. C'est ce que fait l'annexe A.

Notez que les paramètres des deux courbes de ces RFC n'ont pas été choisis complètement « objectivement ». Ils ont fait l'objet d'« optimisations », notamment pour des raisons de performance. Si on veut une courbe générée entièrement par un algorithme objectif et publiquement vérifiable, il faudra se tourner (elle est très récente) vers des courbes « publiquement vérifiables » comme la « courbe d'un million de dollars », qui proclame être « a procedure, more than a curve ».

Maintenant que ces courbes font l'objet d'une documentation complète, il sera plus facile de les utiliser depuis un protocole IETF (ceci dit, elles sont déjà dans au moins une norme, voir RFC 7479). Plusieurs travaux sont en cours pour cela ; il y avait un Internet-Draft pour permettre curve25519 dans TLS, draft-ietf-tls-curve25519 mais il a été remplacé par le plus général RFC 8422. Un autre Internet-Draft traite le cas de DNSSEC, draft-sury-dnskey-ed25519.

Notez que les deux courbes de ce RFC sont décrites selon un formalisme qui ne permet pas de les utiliser telles quelles dans un algorithme comme ECDSA (explications sur StackOverflow). Mais on peut avec EdDSA.

OpenSSH dispose de curve25519 depuis la version 6.5. (« Add support for key exchange using elliptic-curve Diffie Hellman in Daniel Bernstein's Curve25519. This key exchange method is the default when both the client and server support it. [...] Add support for Ed25519 as a public key type. Ed25519 is a elliptic curve signature scheme that offers better security than ECDSA and DSA and good performance. It may be used for both user and host keys. »). Dans les sources d'OpenSSH, ce sont les fichiers ayant 25519 dans leur nom :

/tmp/openssh-7.1p2 %   ls *25519*
ed25519.c  fe25519.c  fe25519.h  ge25519_base.data  ge25519.c  ge25519.h  kexc25519.c  kexc25519c.c  kexc25519s.c  sc25519.c  sc25519.h  smult_curve25519_ref.c  ssh-ed25519.c

Pour générer des clés utilisant cette courbe, on utilise le classique ssh-keygen :

% ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
...
Your identification has been saved in /home/stephane/.ssh/id_ed25519.
Your public key has been saved in /home/stephane/.ssh/id_ed25519.pub.
...      
    

Par contre, ces courbes ne sont pas encore dans OpenSSL (voir la discussion #309). Autrement, on trouve des mises en œuvre de curve25519 à plein d'endroits : https://github.com/msotoodeh/curve25519, https://code.google.com/p/curve25519-donna/ et bien sûr http://cr.yp.to/ecdh.html et https://nacl.cr.yp.to/.

Merci à Patrick Mevzek pour son exploration d'OpenSSH et OpenSSL, à Émilien Gaspar pour les discussions et à Manuel Pégourié-Gonnard pour des corrections, notamment sur la force brute.


Téléchargez le RFC 7748


L'article seul

RFC 7745: XML Schemas for Reverse DNS Management

Date de publication du RFC : Janvier 2016
Auteur(s) du RFC : T. Manderson (ICANN)
Pour information
Première rédaction de cet article le 21 janvier 2016


Ce court RFC décrit un schéma XML qu'utilise l'ICANN pour gérer les zones DNS dans les domaines ip6.arpa et in-addr.arpa. Rien de standard, juste la documentation d'une pratique locale.

Depuis 2011, l'ICANN utilise ce système pour gérer et produire les zones DNS dont elle a la responsabilité sous .arpa (in-addr.arpa est documenté dans le RFC 1034 et ip6.arpa dans le RFC 3152). L'ICANN délègue des zones aux RIR et ceux-ci souhaitent un système le plus fiable, simple et prévisible possible.

La gestion de ces zones se faisait, il y a fort longtemps, à la main, avec un éditeur ordinaire, mais cela n'est évidemment plus possible depuis le déploiement de DNSSEC : les clés changent, les enregistrements DS (Delegation Signer) doivent être mis à jour, etc. Et la plus petite erreur casse la validation cryptographique. Bref, pour ce service comme pour d'autres, DNSSEC pousse fortement à automatiser sérieusement les processus.

Le principe de base (section 3, le gros du RFC) est que le RIR prépare sa demande sous forme d'un fichier XML conforme au schéma décrit dans ce RFC, et l'envoie à l'ICANN par une requête REST. Elle est évidemment en HTTPS et authentifiée par un certificat client (et un pour le serveur, également). L'AC est l'ICANN elle-même. Recevant le XML, l'ICANN met à jour automatiquement les zones sous .arpa.

En bonne logique REST, les requêtes HTTP sont GET, PUT et DELETE. GET sert à interroger l'état actuel de la base (et le RIR n'utilise donc que l'URI, il n'envoie pas de XML).

Voici un exemple d'une requête en XML qui pourrait être envoyée (requête PUT) pour mettre à jour la zone 10.in-addr.arpa, avec deux enregistrements DS (pour la même clé, la 33682) :


<zone xmlns="http://download.research.icann.org/rdns/1.1"
     name="10.in-addr.arpa" cust="IANA" ipversion="ipv4"
     version="1.1" modified="2012-01-18T01:00:06"
     state="active" href="https://host.example.org/ipv4/10">
     <nserver>
       <fqdn>BLACKHOLE-1.IANA.ORG.</fqdn>
     </nserver>
     <nserver>
       <fqdn>BLACKHOLE-2.IANA.ORG.</fqdn>
     </nserver>
     <ds>
       <rdata>33682 5 1 ea8afb5fce7caf381ab101039</rdata>
     </ds>
     <ds>
       <rdata>33682 5 2 7d44874f1d93aaceb793a88001739a</rdata>
     </ds>
   </zone>	       

    

Notez que la modification n'est pas forcément instantanée : il peut y avoir un système de vérification manuelle et d'approbation explicite.

Les URL utilisés par le client sont variables. Par exemple, pour mettre à jour le domaine 10.in-addr.arpa cité plus haut, l'URL serait http://icann.example/4/10.in-addr.arpa (en remplaçant icann.example par le vrai nom du serveur REST à l'ICANN). Pour avoir une liste des demandes en attente (rappelez-vous que le système n'est pas synchrone), le client ferait un GET sur http://icann.example/queuelist, etc.

Les annexes A et B du RFC donnent le schéma Relax NG complet des éléments XML possibles. Par exemple, une zone DNS se définit ainsi :

      
   # A single zone record
   zone = element zone {
     # The zone record's name, eg 10.in-addr.arpa
     attribute name { text },
     ...
     # The administrative state of the zone (optional)
     attribute state { "active" | "pending" | "error" }?,
     # The last modified timestamp in UTC (optional)
     attribute modified  { xsd:dateTime }?,
     ...
     # A zone NS RRset MUST have at least two NS records
     nserver,
     nserver+,
     # It MAY contain some DS records
     ds*
   }

    

À noter que ce schéma ne permet pas d'indiquer de la colle (adresses IP de serveurs de noms situés dans la zone elle-même) puisqu'il ne sert que pour les zones sous .arpa (on ne voit jamais de serveurs de noms nommés ainsi).

Pourquoi développer un tel système plutôt que d'utiliser la norme EPP ? Le RFC ne le dit pas mais on peut supposer que c'est parce qu'EPP est bien plus complexe.


Téléchargez le RFC 7745


L'article seul

RFC 7742: WebRTC Video Processing and Codec Requirements

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : A.B. Roach (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 24 mars 2016


Ce court RFC expose les exigences portant sur les codecs vidéo de WebRTC. Le point principal était le choix du codec obligatoire. Après une très longue et très amère discussion à l'IETF, le choix a été plus politicien que technique : le codec H.264 est obligatoire au même titre que VP8.

Le système WebRTC (voir le RFC 7478) permet de faire de la vidéoconférence, notamment entre deux navigateurs Web. Il permet aux parties qui communiquent de choisir le codec. Un point important des protocoles IETF est que, lorsqu'il existe un tel choix, au moins un des choix doit être mis en œuvre dans toutes les implémentations. Le but est d'assurer l'interopérabilité, en vérifiant que les programmes ont tous au moins un codec en commun.

Mais quel codec choisir ? Il y avait deux concurrents, un codec de l'UIT, H.264 (normalisé ici), qui avait la faveur des compagnies de télécommunication traditionnelles, et un codec issu de l'Internet, VP8 (RFC 6386), qui était le plus apprécié par les entreprises Internet et par le monde du logiciel libre. Le débat a été très long et très houleux à l'IETF. Le problème n'était pas uniquement sentimental, il portait également sur les innombrables brevets qui verrouillent H.264 (son concurrent VP8 a aussi des brevets, mais avec une licence très libérale pour la plupart). Quant aux critiques sur VP8, elles portaient surtout sur sa relative jeunesse (en fait, certaines entreprises avaient investi pas mal dans H.264 et ne voulaient pas recommencer).

Le débat a donc duré, générant plus de mille messages sur la liste de diffusion du groupe de travail, et occupant une bonne partie des réunions physiques de l'IETF (réunions IETF 81, 82, 85, 86, et 88...), affectant notablement la patience des participants. Des tas de solutions ont été proposées pour sortir de l'affrontement, y compris un inhabituel vote (dans ce message, MTI = Mandatory To Implement). Le sujet est revenu sur le tapis et revenu encore. La solution, adoptée à la réunion IETF 91 à Honolulu, a finalement été de prendre les deux.

Notez bien que ce RFC n'est pas la description complète de WebRTC, loin de là. C'est juste le cahier des charges minimum des codecs (le cahier des charges du transport des données a été publié dans le RFC 8834).

D'abord, les considérations générales, indépendantes du codec (section 3). Par exemple, l'espace de couleur à utiliser est sRGB. Cette section conseille également sur l'utilisation de la caméra de capture : si elle le permet, il est recommandé d'utiliser ses capacités propres, comme la mise au point automatique, ou le réglage automatique de la luminosité. Le RFC rappelle également que la résolution de la source peut changer en cours de route (parce que la source est une fenêtre de l'écran qui change soudain de taille, ou bien parce que la source est la caméra d'un mobile qui change soudain d'orientation, cf. section 4) et que WebRTC doit donc s'y adapter.

La section 5 est le morceau sensible du RFC : la description du, ou plutôt des, codecs obligatoires. Le principe est que toute mise en œuvre de WebRTC doit accepter VP8 et H.264. Une note du RFC précise que, si le problème des brevets s'arrange pour un des codecs et pas pour l'autre, cette décision pourra être reconsidérée et un des codecs devenir optionnel (évidemment, tout le monde pense à H.264, beaucoup plus lardé de brevets avec licences hostiles). À noter que des codecs comme Theora ont été discutés, et sont possibles dans WebRTC, mais sans qu'il ait vraiment été envisagé de les rendre obligatoires.

La section 6 précise ensuite quelques exigences techniques pour chacun des codecs. Notamment, plusieurs options de H.264 ont une valeur fixe en WebRTC, pour simplifier la tâche des programmeurs. (H.264 a bien trop de variables possibles.)


Téléchargez le RFC 7742


L'article seul

RFC 7739: Security Implications of Predictable Fragment Identification Values

Date de publication du RFC : Février 2016
Auteur(s) du RFC : F. Gont (SI6 Networks / UTN-FRH)
Pour information
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 7 février 2016


Le protocole IPv6 a un mécanisme de fragmentation des paquets. L'en-tête d'un fragment contient un champ « Identification » (RFC 2460, section 4.5) qui, avec les deux adresses Source et Destination, identifie de manière unique un paquet fragmenté (tous les fragments de ce paquet ont le même identificateur), et permet donc le réassemblage à la destination. La façon la plus simple d'affecter ces identificateurs est d'avoir, dans chaque machine, un compteur global incrémenté à chaque paquet qu'on fragmente (section 1 du RFC). Une telle façon de faire mène à des identificateurs prévisibles : un observateur qui se connecte à cette machine peut prévoir quel sera l'identificateur du paquet suivant. Cela a de sérieuses conséquences en terme de sécurité. Ce RFC explore ces conséquences, et propose des solutions.

Petit rappel au passage sur la fragmentation IPv6 : contrairement à la fragmentation IPv4, elle ne peut se faire que dans la machine émettrice, pas dans les routeurs intermédiaires. Voici un exemple de paquet fragmenté, vu par tcpdump, la réponse DNS, trop grosse, a été fragmentée en deux :

10:45:24.818912 IP6 (hlim 56, next-header Fragment (44) payload length: 432) 2001:4b98:dc2:45:216:3eff:fe4b:8c5b > 2001:67c:1348:7::86:133: frag (0x000079cc:0|424) 53 > 37407: 25110*- q: ANY? . 24/0/1 . [1d] DNSKEY, . [1d] DNSKEY, . [1d] DNSKEY[|domain]
10:45:24.819008 IP6 (hlim 56, next-header Fragment (44) payload length: 1458) 2001:4b98:dc2:45:216:3eff:fe4b:8c5b > 2001:67c:1348:7::86:133: frag (0x000079cc:424|1450)
    

Le paquet a l'identificateur 0x000079cc, seul le premier fragment (de l'octet 0 à l'octet 423) a pu être analysé (il avait le début de la réponse DNS). Et voici les deux fragments, analysés par tshark :

    Type: IPv6 (0x86dd)
      Internet Protocol Version 6, Src: 2001:4b98:dc2:45:216:3eff:fe4b:8c5b, Dst: 2001:67c:1348:7::86:133
    Next header: Fragment Header for IPv6 (44)
    Fragment Header
        Next header: UDP (17)
        Reserved octet: 0x0000
        0000 0000 0000 0... = Offset: 0 (0 bytes)
        .... .... .... .00. = Reserved bits: 0
        .... .... .... ...1 = More Fragments: Yes
        Identification: 0x000079cc

    Type: IPv6 (0x86dd)
	Internet Protocol Version 6, Src: 2001:4b98:dc2:45:216:3eff:fe4b:8c5b, Dst: 2001:67c:1348:7::86:133
    Next header: Fragment Header for IPv6 (44)
    Fragment Header
        Next header: UDP (17)
        Reserved octet: 0x0000
        0000 0001 1010 1... = Offset: 53 (424 bytes)
        .... .... .... .00. = Reserved bits: 0
        .... .... .... ...0 = More Fragments: No
        Identification: 0x000079cc

  [2 IPv6 Fragments (1874 bytes): #2(424), #3(1450)]
        [Frame: 2, payload: 0-423 (424 bytes)]
        [Frame: 3, payload: 424-1873 (1450 bytes)]
        [Fragment count: 2]
        [Reassembled IPv6 length: 1874]
        [Reassembled IPv6 data: 0035921f0752901c6216850000010018000000010000ff00...]
    

Le RFC 2460, section 4.5, indique une seule obligation à la machine fragmenteuse : l'identificateur de paquet doit être unique parmi tous les paquets émis récemment par cette machine, pour éviter toute collision. Ce RFC 2460 donne même le conseil malheureux d'utiliser un compteur global, incrémenté à chaque paquet, pour cela.

Pourquoi, « malheureux » ? Parce que cela rend l'identificateur de paquet prévisible pour un observateur extérieur, faisant ainsi fuir de l'information qui peut être utilisée pour certaines attaques (section 3) :

  • L'observateur peut découvrir le débit de la machine émettrice,
  • Il peut procéder à des balayages de ports très discrets, en utilisant la machine aux identificateurs prévisibles (détails plus loin),
  • Il peut compter le nombre de machines situées derrière un routeur NAT,
  • Et surtout, il peut faire des attaques par déni de service (en empêchant le réassemblage, par exemple en envoyant des faux fragments recouvrant en partie des fragments légitimes) ou, encore pire, injecter du contenu dans un paquet (comme dans l'attaque Shulman contre le DNS).

Ces attaques n'ont rien de spécifique à IPv6 : des identificateurs de paquet prévisibles ont les mêmes conséquences en IPv4 (voir les articles pionniers de Sanfilippo ici ou , puis de nombreux autres papiers cités dans la bibliographie de notre RFC, en section 9). Le RFC 6274 décrit en détail ces attaques pour IPv4.

En IPv4, le champ Identification fait partie de chaque paquet (RFC 791, section 3.1) puisque tout routeur pourra fragmenter ce paquet. En IPv6, ce champ n'est présent que dans les paquets fragmentés, dans un « en-tête d'extension » optionnel. Cela rend les attaques un peu plus compliquées en IPv6 : l'attaquant doit d'abord forcer une fragmentation. Une des possibilités pour cela est d'envoyer un paquet ICMP Packet Too Big. Si, en plus, le paquet ICMP contient une MTU inférieure à 1 280 octets, les paquets ne seront pas fragmentés mais porteront quand même l'en-tête d'extension Fragment Header (c'est ce qu'on appellait des « fragments atomiques », cf. RFC 6946, fragments atomiques dont l'usage est désormais abandonné, voir le RFC 8021).

En théorie, rien de plus simple que d'envoyer un faux paquet ICMP Packet Too Big. En pratique, il y a quelques limitations pour l'attaquant :

  • Les mises en œuvre d'IPv6 mémorisent une PMTU par destination. Il faudra donc envoyer un paquet ICMP contenant l'adresse IP vers laquelle on veut que des fragments soient générés.
  • Comme les paquets ICMP ne sont pas signés, les mises en œuvre d'IP savent bien qu'elles doivent s'en méfier, et déploient souvent les précautions du RFC 5927.

Pour éviter ces attaques, que faudrait-il faire ? On souhaite des identificateurs de paquets imprévisibles, mais en même temps ils ne doivent pas être réutilisés, du moins tant qu'on n'est pas sûr que les paquets portant précédemment cet identificateur n'ont pas terminé leur voyage dans le réseau. Des identificateurs complètement aléatoires, par exemple, ne sont pas si idéaux qu'ils le paraissent : il y a un risque de réutilisation accidentelle. Autre contrainte sur les algorithmes de génération de ces identificateurs : ils doivent être très rapides, puisqu'il faut les faire tourner pour chaque paquet fragmenté.

La section 5 de notre RFC décrit les algorithmes possibles. On a vu que l'algorithme « compteur global » était exclu, car il produit des identificateurs prévisibles. Que reste-t-il ?

Le premier algorithme possible (section 5.1) est « un compteur par destination ». On maintient un compteur par adresse IP de destination utilisée, qu'on initialise avec une valeur aléatoire. Simple à mettre en œuvre (il faut juste un générateur de nombres aléatoires), sans réutilisation (pour qu'il y ait collision, il faudrait qu'on émette tellement de paquets vers une destination donnée que le compteur, de 32 bits, déborde), et très rapide (une fois la valeur initiale choisie). Par contre, le prochain identificateur de fragment reste prévisible, mais uniquement pour la machine de destination. Cela peut être utilisé dans certaines attaques. Et il consomme pas mal de mémoire (une entrée par destination), mémoire qu'on ne peut pas libérer, sauf à risquer des collisions d'identificateurs.

Deuxième algorithme envisageable, « identificateur aléatoire » (section 5.2). Idéal pour la sécurité, mais il fait courir des risques de réutilisation des identificateurs, et il est plus coûteux en temps de calcul.

Enfin, un troisième algorithme possible est « condensation de variables » (section 5.3). On prend des variables comme les adresses source et destination, un compteur (pas forcément global), une valeur secrète et on condense le tout. Non, je simplifie trop. En fait, pour être le plus rapide possible tout en étant imprévisible, on a un tableau de compteurs (pas un par destination, mais pas non plus un seul), la condensation des adresses et d'un secret donne l'index dans ce tableau, et on concatène ce compteur avec un autre condensat, fait avec un autre secret. Le résultat est imprévisible de l'extérieur (mais prévisible par le destinataire) et la réutilisation est plus lente qu'avec un compteur global, et cet algorithme peut être mis en œuvre de façon à être très rapide.

L'annexe B de notre RFC est le résultat d'une étude de la prédictabilité par système d'exploitation, en utilisant l'outil frag6, qui vient du toolkit SI6. On peut refaire la même étude chez soi :

% sudo frag6  --frag-id-policy -d www.example
Identifying the 'Fragment ID' generation policy of the target node....
Fragment ID policy: Per-destination IDs with increments of 2 (sdev: 1.112134)
      

La destination est un FreeBSD, qui utilise des identificateurs aléatoires depuis sa version 9 :

%  sudo frag6   --frag-id-policy -d www.freebsd.org
Identifying the 'Fragment ID' generation policy of the target node....
Fragment ID policy: Randomized IDs (Avg. inc.: 2101165500, sdev: 1531579889.681898)
      

Ici, un Linux récent, avec des compteurs par destination :

	%  sudo frag6   --frag-id-policy -d 2001:db8:9321:8bb0:9da8:f055:5381:d54c
Identifying the 'Fragment ID' generation policy of the target node....
Fragment ID policy: Per-destination IDs with increments of 1 (sdev: 1.504380)
      

On voit, après cet essai sur trois machines différentes, que les différents algorithmes sont toujours utilisés.


Téléchargez le RFC 7739


L'article seul

RFC 7735: Tracking Reviews of Documents

Date de publication du RFC : Janvier 2016
Auteur(s) du RFC : R. Sparks (Oracle), T. Kivinen (INSIDE Secure)
Pour information
Première rédaction de cet article le 14 janvier 2016


Le processus de production des normes par l'IETF suit de nombreuses étapes, toutes se déroulant en public. Il est en effet essentiel que de nombreux yeux puissent regarder les documents en voie de devenir des RFC. Et que de nombreux examens (reviews) aient lieu. Pour suivre ces examens, il est préférable de disposer d'outils et ce sont les futurs outils à développer que décrit ce RFC.

Parmi les équipes qui effectuent des examens des Internet-Drafts en cours d'avancement figurent Gen-ART et SecDir. Mais il en existe plusieurs autres, parfois très spécialisées, et qui n'examinent que les documents relevant de leur spécialité (par exemple les MIB par les MIB doctors ou bien les schémas YANG par les YANG doctors).

Les équipes en question doivent se tenir au courant des documents en cours, leur affecter un examinateur parmi ceux qui sont enregistrés pour cette tâche, fixer une date limite et relancer l'examinateur s'il est en retard, etc. Cela serait évidemment très pénible à faire à la main et ces équipes utilisent actuellement un outil, développé il y a longtemps. Du fait de son âge, il n'est pas bien intégré avec le principal outil de travail en groupe de l'IETF, le Datatracker. Par exemple, pour obtenir certaines informations, l'outil analyse des pages HTML du Datatracker :-) .

[Au passage, notez que le Datatracker est vraiment un excellent outil, qui facilite beaucoup la vie du participant à l'IETF. On voudrait tous avoir des outils de travail en groupe équivalents au bureau.]

Une meilleure intégration avec le Datatracker permettrait de simplifier l'accès à ces informations, et à d'autres qui ne sont pas utilisées actuellement, car trop pénibles à extraire. Ce nouveau RFC est le cahier des charges du futur outil (voir aussi le système de gestion de tickets de l'outil actuel).

Pour comprendre ce cahier des charges, il est utile de revenir sur l'utilisation actuelle de l'outil des examens (section 2 du RFC). Typiquement, l'équipe a un secrétariat qui, une fois par semaine environ, dresse une liste des documents qui sont prêts à subir un examen, par exemple parce qu'ils sont en IETF Last Call (dernier appel avant approbation) ou parce qu'ils sont sur l'agenda des réunions (virtuelles) de l'IESG.

Le secrétariat prend ensuite un examinateur parmi la liste des examinateurs possibles, en tenant compte de paramètres comme le fait qu'un auteur ne doit évidemment pas être examinateur de son propre Internet-Draft. L'idée est en général de prendre un examinateur qui a un regard neuf et n'a pas été impliqué dans le développement du document.

Les différentes équipes d'examen n'ont pas toutes le même fonctionnement. Certaines, comme indiqué plus haut, s'« auto-saisissent » alors que d'autres sont plutôt en mode « on examine si on nous le demande » (c'est le cas de l'équipe du routage, par exemple).

Les examinateurs eux-même n'utilisent pas en général l'outil directement : ils communiquent par courrier avec le secrétariat. Et c'est par courrier qu'ils envoient le résultat de leur examen, après avoir rempli un « courrier-type ». Voici par exemple l'examen fait par Gen-ART pour le futur RFC sur la QNAME minimisation ou bien celui de RTG-Dir pour un futur protocole d'HomeNet.

Voici donc le fonctionnement actuel. Pour le futur outil, les exigences sont dans la section 3 de notre RFC. D'abord, ce qui intéresse le secrétariat de l'IETF (section 3.1) :

  • Le secrétariat doit pouvoir configurer une équipe,
  • Et doit pouvoir effectuer toute action à la place du secrétariat de l'équipe (en cas de défaillance de celui-ci).

Plus importantes, les exigences pour le secrétariat de l'équipe d'examen (section 3.2), entre autres :

  • Pouvoir voir quels documents sont dans un état donné (par exemple IETF Last Call),
  • Possibilité de sélectionner les documents à examiner, soit automatiquement (« tous ceux qui sont sur l'agenda de l'IESG »), soit manuellement (ajouter explicitement un document intéressant),
  • Permettre les accès concurrents à l'outil (une équipe peut avoir plusieurs secrétaires),
  • Faciliter l'envoi des courriers, par exemple en remplissant automatiquement un gabarit, puis en permettant au secrétaire de faire des modifications, avant envoi,
  • Pouvoir voir les examinateurs libres,
  • Capacité à gérer les disponibilités des examinateurs (par exemple, on doit pouvoir indiquer « Machin ne sera pas libre avant le 2 février » et il ne doit alors pas être présenté dans la liste des examinateurs potentiels),
  • Gérer automatiquement l'exclusion des examinateurs de certains documents. L'outil actuel utilise une expression rationnelle. M. Michu, examinateur qui est très investi dans le groupe de travail DPRIVE, aura une expression d'exclusion pour les documents nommés ^draft-(michu|ietf-dprive).*, l'excluant de ses drafts et de ceux de DPRIVE,
  • Permettre le suivi des examens (certains examinateurs sont très occupés, peuvent « oublier » leur tâche, etc),
  • Par la même occasion, l'outil doit permettre de suivre les « performances » des examinateurs (afficher le retard moyen...) de manière à détecter les « maillons faibles »,
  • Autoriser le changement d'examinateur, l'ajout d'un examinateur...

Et pour l'examinateur lui-même, que doit savoir faire l'outil (section 3.3) ? Par exemple :

  • Il doit permettre à l'examinateur d'indiquer ses disponibilités, à la fois en dates (« en vacances tout le mois d'août ») et en fréquence (« pas plus d'un examen de document par trimestre »), avec notification du secrétariat par courrier,
  • L'examinateur doit avoir accès aux documents qui lui sont affectés, avec leur état, pour suivre son propre travail,
  • Possibilité de rejeter une affectation, avec explication optionnelle (et, là aussi, notification du secrétariat),
  • De même, l'examinateur doit pouvoir indiquer explicitement qu'il accepte une affectation,
  • Rappels automatiques (« il te reste 24 h pour ton examen du draft draft-ietf-cuterabbit-security-analysis-09.txt »),
  • Et bien sûr, puisque c'est le but de l'examen, l'examinateur doit pouvoir soumettre facilement le texte final, par un formulaire Web ou en téléversant un fichier, le texte étant alors automatiquement envoyé aux auteurs et au groupe de travail concerné,
  • Et cette soumission doit aussi être possible par courrier, pour les examinateurs qui sont allergiques au Web (c'est possible avec les bons outils de gestion de tâche, comme RT).

Comme tout le monde aime les statistiques, et qu'il est bon de pouvoir évaluer si une équipe d'examen marche bien ou pas, l'outil devra également fournir des chiffres (section 3.5) :

  • Pour une période donnée, indiquer combien d'examens ont été faits, combien sont en cours, combien ont été en retard et de combien, le temps moyen d'examen,
  • Mêmes résultats, mais pour un examinateur donné,
  • Ces chiffres doivent pouvoir être pondérés par des caractéristiques du document (notamment sa taille, mesurée en nombre de signes),
  • Et, autant que possible, ces statistiques, par exemple le nombre d'examens faits par un examinateur par an devraient pouvoir tenir compte des périodes d'indisponibilité,
  • Et si l'outil pouvait faire des jolis graphes avec les séries temporelles, ce serait encore mieux,
  • L'accès à ces chiffres doit être limité : le secrétariat d'une équipe peut tout voir pour son équipe, un examinateur peut voir ses résultats, ou bien les résultats globaux de son équipe,

Les outils actuels de l'IETF sont écrits en Django. Pour rendre ce cahier des charges plus concret, l'annexe A fournit un modèle Django tout prêt. Par exemple, l'état d'un examen peut être :

 class ReviewRequestStateName(NameModel):
     """ Requested, Accepted, Rejected, Withdrawn, Overtaken By Events,
         No Response , Completed  """
      

Un examinateur est ainsi modélisé :

class Reviewer(models.Model):
     """
     These records associate reviewers with review team, and keeps track
     of admin data associated with the reviewer in the particular team.
     There will be one record for each combination of reviewer and team.
     """
     role        = models.ForeignKey(Role)
     frequency   = models.IntegerField(help_text=
                                   "Can review every N days")
     available   = models.DateTimeField(blank=True,null=True, help_text=
                         "When will this reviewer be available again")
     filter_re   = models.CharField(blank=True)
     skip_next   = models.IntegerField(help_text=
                          "Skip the next N review assignments")
      

Et une demande d'examen est :

 class ReviewRequest(models.Model):
     """
     There should be one ReviewRequest entered for each combination of
     document, rev, and reviewer.
     """
     # Fields filled in on the initial record creation:
     time          = models.DateTimeField(auto_now_add=True)
     type          = models.ReviewTypeName()
     doc           = models.ForeignKey(Document,
                            related_name='review_request_set')
     team          = models.ForeignKey(Group)
     deadline      = models.DateTimeField()
     requested_rev = models.CharField(verbose_name="requested_revision",
                             max_length=16, blank=True)
     state         = models.ForeignKey(ReviewRequestStateName)
     # Fields filled in as reviewer is assigned, and as the review
     # is uploaded
     reviewer      = models.ForeignKey(Reviewer, null=True, blank=True)
     review        = models.OneToOneField(Document, null=True,
                                                    blank=True)
     reviewed_rev  = models.CharField(verbose_name="reviewed_revision",
                                      max_length=16, blank=True)
     result        = models.ForeignKey(ReviewResultName)
      

Vous avez envie de réaliser cet outil ? L'annonce a été publiée le 28 décembre 2015 et vous avez jusqu'au 18 janvier 2016 pour proposer vos services.


Téléchargez le RFC 7735


L'article seul

RFC 7725: An HTTP Status Code to Report Legal Obstacles

Date de publication du RFC : Février 2016
Auteur(s) du RFC : T. Bray (Textuality)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 1 mars 2016


Voici donc un nouveau code de retour HTTP qui a fait couler énormément d'encre : 451 est désormais l'erreur HTTP à utiliser lorsqu'un serveur HTTP ne peut pas envoyer la ressource demandée par son client pour des raisons légales, en clair lorsqu'il y a censure.

Rappelons que les codes d'erreur HTTP (RFC 7231, section 6) sont composés de trois chiffres, le premier indiquant la catégorie. 4 (RFC 7231, section 6.5) est une erreur due au client (et il ne sert donc à rien de réessayer plus tard).

Ce nouveau code 451 permet de la censure avouée, suivant les principes du RFC 4924 et de la section 4 du RFC 4084. On peut dire clairement à l'utilisateur que sa demande est légalement impossible à satisfaire. Notez que toutes les dictatures ne seront pas ravies de cette transparence. Du temps de Ben Ali, la censure tunisienne générait des faux 404 (Not found) pour faire croire que la ressource demandée n'existait pas.

La section 3 de notre RFC expose les détails techniques. Notez que le serveur qui répond 451 n'est pas forcément le serveur d'origine de la ressource (s'il l'était, il ne souhaiterait probablement pas mettre en œuvre la censure de son propre contenu). 451 sera donc sans doute plutôt renvoyé par des serveurs intermédiaires, genre proxy ou moteurs de recherche.

Vu l'objectif de transparence, le RFC demande que la réponse 451 soit accompagnée d'une explication, indiquant qui bloque, pourquoi, et selon quelle loi. Le RFC fournit un exemple amusant, inspiré du film La vie de Brian :

      
HTTP/1.1 451 Unavailable For Legal Reasons
Link: <https://spqr.example.org/legislatione>; rel="blocked-by"
Content-Type: text/html

<html>
 <head><title>Unavailable For Legal Reasons</title></head>
 <body>
  <h1>Unavailable For Legal Reasons</h1>
  <p>This request may not be serviced in the Roman Province
  of Judea due to the Lex Julia Majestatis, which disallows
  access to resources hosted on servers deemed to be
  operated by the People's Front of Judea.</p>
 </body>
</html>

    

Le RFC note bien que le code 451 n'indique pas si la ressource existe ou pas (par exemple, un proxy peut bloquer toutes les requêtes allant vers un nom de domaine donné).

Notre RFC fournit également des indications sur comment la censure peut être contournée, par exemple avec un VPN vers un pays plus libre, ou bien avec Tor. C'est d'ailleurs un des intérêts pratiques de ce code 451 : un client HTTP pourra agir automatiquement lorsqu'il rencontrera cette erreur. Ce code n'est donc pas purement décoratif (une objection qui lui avait souvent été faite au début du processus à l'IETF.) En prime, ce code pourra être utile à des systèmes de suivi de la censure, comme Lumen. Peut-être cela aidera-t-il à mesurer la censure (du moins dans les pays les plus légalistes, les autres n'utiliseront pas 451). Pour les mêmes raisons, des organisations de défense des droits de l'homme comme le CDT ou comme article 19 ont exprimé leur soutien pour ce code.

L'en-tête Link: dans l'exemple plus haut est là pour identifier formellement l'entité responsable du blocage (section 4 du RFC), en utilisant les liens du RFC 8288. Cela suppose évidemment que celle-ci assume ses décisions, ce qui n'est pas toujours le cas (section 5 du RFC, qui rappelle qu'il y aura toujours une censure hypocrite).

Le code 451 est désormais ajouté au registre IANA des codes de retour HTTP, et la relation blocked-by est dans le registre des relations. (Notez bien que l'exemple ci-dessus, copié du RFC, est erroné.)

« Thanks also to Ray Bradbury », dit l'annexe A du RFC, puisque ce code d'erreur est évidemment une référence geek au roman du célèbre écrivain.

Un exemple de mise en œuvre parmi tant d'autres : la bibliothèque Pylons. Le magasin d'applications de Firefox a 451 parmi ses réponses possibles si l'application est illégale dans le pays du client. Et 451 a une image parmi les fameux HTTP status cats, montrant Bradbury et son chat.

Ce code d'erreur a suscité beaucoup d'intérêt, il a une page Wikipédia, un site Web en Grande-Bretagne et a fait l'objet de nombreux articles dans les médias.

En France, le serveur « La Main Rouge » du Ministère de l'Intérieur n'utilise pas 451 lorsqu'on tente d'accéder à un site Web interdit. Au lieu de cela, leur serveur renvoie 200, ce qui est illogique. (Un point amusant : si on utilise wget - mais pas curl - le serveur renvoie 403.)

À la réunion IETF de Prague en juillet 2017, le hackathon a été l'occasion de travailler sur des utilisations de ce code 451. Voici la présentation qui a été faite et l'Internet-Draft draft-451-imp-report. Le code a été mis sur Github.


Téléchargez le RFC 7725


L'article seul

RFC 7723: Port Control Protocol (PCP) Anycast Addresses

Date de publication du RFC : Janvier 2016
Auteur(s) du RFC : S. Kiesel (University of Stuttgart), R. Penno (Cisco Systems), S. Cheshire (Apple)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pcp
Première rédaction de cet article le 23 janvier 2016


Le protocole PCP, normalisé dans le RFC 6887, permet à une machine de signaler à la box, au routeur CPE, au pare-feu, ses désirs en terme d'ouverture de ports, d'obtention d'information sur l'adresse IP externe, etc. Mais comment l'ordinateur de M. Michu trouve t-il l'adresse du serveur PCP ? Une des solutions est celle introduite par ce RFC : une adresse anycast « bien connue », 192.0.0.9 en IPv4 et 2001:1::1 en IPv6.

Souvent, l'adresse IP du serveur PCP est évidente : c'est l'adresse du routeur par défaut. Mais il y a des cas plus compliqués, par exemple en cas de CGN (section 1 du RFC). Avant notre RFC 7723, les seules autres solutions étaient la configuration manuelle, ou une option DHCP (RFC 7291).

Ce nouveau RFC ajoute une possibilité : le client PCP écrit tout simplement à l'adresse bien connue, 192.0.0.9 ou 2001:1::1, et le serveur PCP approprié répondra. L'anycast s'occupera de router le message du client au bon serveur. Une simple diffusion n'aurait pas suffi : le serveur PCP n'est pas forcément sur le réseau local (notamment en cas de CGN). Avec l'anycast, il n'y a pas besoin d'installer quoi que ce soit de particulier dans le réseau local ou les équipements CPE. Et l'adresse bien connue étant immuable, on peut la mettre en dur dans les applications PCP, sans avoir besoin de l'obtenir du système d'exploitation. (Personnellement, je trouve cela un peu optimiste : comme cette option anycast est nouvelle, et qu'elle ne sera pas forcément déployée partout, l'application aura toujours besoin d'un « plan B » en demandant au système d'exploitation « une idée de l'adresse IP du serveur PCP ? »)

Le comportement du client et du serveur PCP est décrit dans la section 2 du RFC. La liste des serveurs PCP possibles pour le client (section 8.1, étape 2 du RFC 6887) s'enrichit des adresses anycast bien connues. Le traitement de cette liste continue à suivre la norme PCP du RFC 7488. Le serveur, lui, a juste à écouter sur les adresses anycast bien connues, en plus de ses adresses habituelles. Le RFC ne le mentionne apparemment pas, mais l'administrateur réseaux doit aussi évidemment configurer le routage pour que la route vers le serveur PCP soit annoncée partout, et appliquée.

L'anycast peut être déroutant au début pour les administrateurs réseaux et la section 3 du RFC rappelle donc quelques règles de déploiement (en plus des documents existants sur l'anycast, RFC 4786 et RFC 7094). Par exemple, si le réseau a deux connexions vers l'extérieur, chacune avec son propre serveur PCP, l'anycast ne va pas forcément aider car le message PCP du client ne sera reçu que par un seul des deux serveurs (même si tous les serveurs ont été configurés pour écouter sur l'adresse anycast).

Si le routage est toujours symétrique, ce n'est pas un problème, car le serveur PCP qui recevra le message envoyé à l'adresse anycast est également celui qui verra passer tout le trafic, et pourra donc faire ce qui lui a été demandé par le client PCP. Même si le routage change, et qu'on passe subitement par un autre lien, avec un autre serveur PCP, ce n'est pas grave (c'est l'équivalent du redémarrage d'un serveur PCP, cas qui est géré par les clients PCP).

Mais, si le routage est asymétrique... Eh bien, dans ce cas, c'est fichu, c'est une limite de PCP plus que de ces adresses anycast. La seule solution est de développer un mécanisme (qui n'existe pas encore) pour synchroniser deux serveurs PCP.

La section 4 de notre RFC rappelle les enregistrements des deux adresses à l'IANA, dans les registres d'adresses spéciales IPv4 et IPv6.

(Les fanas de sécurité peuvent lire la section 5 mais il n'y a pas grand'chose à dire d'original : les messages PCP, anycast ou pas, peuvent être attaqués comme tous les autres paquets IP, ni plus, ni moins.)

Pour l'instant (PCP est, de toute façon, très peu déployé), je ne crois pas que quiconque utilise déjà ces adresses anycast.


Téléchargez le RFC 7723


L'article seul

RFC 7721: Privacy Considerations for IPv6 Address Generation Mechanisms

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : A. Cooper (Cisco), F. Gont (Huawei Technologies), D. Thaler (Microsoft)
Pour information
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 11 mars 2016


Il y a eu pas mal de trollage depuis les débuts d'IPv6, au sujet de son mécanisme de génération d'adresses, et des risques qu'il pouvait poser pour la vie privée. Ces débats étaient souvent motivés par une inquiétude de la nouveauté, davantage que par une réelle analyse des menaces. Plus d'un amateur a écrit sur les forums qu'IPv6 était un complot contre la vie privée, alors même que son navigateur Web faisait fuiter bien davantage d'informations personnelles. Ce nouveau RFC analyse l'état actuel des mécanismes de génération des adresses IPv6, leurs avantages et leurs inconvénients en terme de protection de la vie privée, et les compromis à faire lors du choix d'un mécanisme donné.

IPv6 permet des nouvelles façons d'allouer des adresses. Outre les méthodes qui existaient déjà en IPv4, comme l'allocation statique, et celle via DHCP, il permet une méthode dite « sans état ». Dans ce cas, le routeur annonce le préfixe IP du lien, et les machines ajoutent à ce préfixe un suffixe qui les identifie de manière unique sur le lien. Ainsi, on peut obtenir une adresse globale sans qu'un serveur ait besoin de maintenir un état des allocations faites.

Au début d'IPv6, des formulations malheurseuses dans les RFC ont pu faire croire que ce suffixe, l'IID (Interface IDentifier) était forcément dérivé de l'adresse MAC de la machine, mais cela n'a jamais été obligatoire (le RFC 7136 a clarifié ce point). D'autre part, on peut noter que préfixe et suffixe ont en général la même longueur, qui est de 64 bits, pour les raisons expliquées dans le RFC 7421.

Aujourd'hui, la liste complète des mécanismes possibles d'allocation d'adresses IPv6 est :

  • Manuelle, en fixant l'IID en partant de 1 (méthode dite low byte), ou bien selon une adresse IPv4 de la machine, ou encore selon un port (serveurs DNS dont l'adresse IPv6 se termine par :53...), ou enfin en utilisant un mot rigolo, en profitant de l'hexspeak.
  • Via la SLAAC, Stateless Address Auto-Configuration, en fabriquant l'IID à partir de l'adresse MAC (RFC 2464), d'une clé cryptographique (RFC 3972), d'un nombre temporaire et donc changeant souvent (RFC 8981), ou d'une valeur stable dérivée de certaines caractéristiques du réseau d'accueil (RFC 7217). Et ce n'était que les méthodes normalisées, mais il y en a d'autres, par exemple chez Microsoft.
  • Via DHCP (RFC 8415). Notez que le serveur DHCP peut avoir de nombreux moyens de choisir une adresse pour chaque client : cela peut être statique ou dynamique.
  • Enfin, il y a les méthodes d'allocation des techniques de coexistence IPv4-IPv6. L'adresse v6 peut être dérivée de l'adresse v4 (RFC 6052), dérivée de l'adresse et du port (RFC 4380, dérivée de l'adresse et d'un identifiant d'un ensemble de ports (RFC 7596 et suivants)...

Parmi ces nombreuses méthodes, la méthode « SLAAC et IID dérivé de l'adresse MAC » est celle qui pose le plus de problèmes, côté vie privée. Pourquoi ? Parce que l'adresse MAC d'une machine est en général stable (sauf si on utilise un logiciel comme macchanger) même lorsque la machine se déplace. Si on se connecte à un pair sur l'Internet, depuis un certain réseau, le pair verra l'adresse IP source et, si on change de réseau, l'adresse MAC, donc l'IID, dans les 64 derniers bits de l'adresse IP, seront les mêmes et le pair verra donc qu'il s'agit de la même machine.

La section 3 de notre RFC décrit plus précisement les vulnérabilités de cette méthode. La première vulnérabilité est le risque de corrélation. Un pair avec qui on communique, ou bien un observateur du trafic réseau, peuvent se rendre compte que deux machines d'adresses IPv6 différentes sont en fait la même machine, en raison de l'égalité des deux IID. Comme on ne change pas de carte Ethernet tous les mois, la corrélation, dans le cas d'un IID fondé sur l'adresse MAC peut durer des années (cf. RFC 8981 pour l'analyse).

Bien sûr, on peut faire de la corrélation avec autre chose que les adresses MAC, comme l'illustre très bien le Panopticlick (voir aussi la section 5.2.1 du RFC 6973) et une bonne partie des critiques contre ce risque de corrélation avec les IID liés aux adresses MAC étaient juste du FUD anti-IPv6 (des gens qui critiquent le manque de vie privée avec IPv6 mais qui ne filtrent pas les cookies...) Mais cela n'interdit pas d'essayer de résoudre le problème.

Un autre risque est celui de la localisation. Si une machine garde le même IID en changeant de réseau, on peut la suivre à la trace. « Tiens, c'est encore elle, et, cette fois, elle est en Allemagne. Tiens, elle est maintenant à l'université de Berlin. » Cette attaque n'aurait pas marché en IPv4 où l'adresse attribuée est complètement différente à chaque fois.

Les adresses IPv6 dérivées de l'adresse MAC présentent un autre risque : on peut balayer le réseau à la recherche de machines à attaquer. Normalement, la taille de l'espace d'adresssage IPv6 rend le balayage complet irréaliste. Mais, si on sait que le réseau visé n'utilise, par exemple, que des Apple, on peut réduire le nombre de paquets à envoyer en disant au logiciel de balayage de n'utiliser que des adresses IPv6 dérivées d'adresses MAC ayant le préfixe Apple. Et cette possibilité est mise en œuvre dans les outils réels, par exemple avec l'option --tgt-ieee-oui de scan6. (Voir le RFC 7707 pour plus de détail sur le balayage en IPv6.)

Enfin, le fait que les adresses MAC aient un préfixe qui indique le fabricant (sauf si on a pensé à utiliser macchanger ou un logiciel équivalent) fournit une information qui peut être utile à un attaquant, en lui dévoilant le type de machines qu'on utilise.

Bien sûr, ces adresses IPv6 dérivées de l'adresse MAC sont minoritaires, et sont de moins en moins utilisées. Mais les alternatives ne sont pas toujours parfaites. La section 4 de notre RFC fait le point sur les solutions, et leurs propriétés. Les adresses temporaires du RFC 8981 sont la première solution à laquelle on pense. Elles sont typiquement utilisées pour les connexions sortantes, une adresse stable, dérivée de l'adresse MAC, restant en place pour les connexions entrantes. À noter qu'au début, les problèmes de vie privée étant supposés moins importants que les considérations opérationnelles de gestion des réseaux, les RFC demandaient que les adresses temporaires ne soient pas utilisées par défaut. Plusieurs systèmes, comme Windows, ont décidé à juste titre d'ignorer cette demande, et c'est ce qui explique que les adresses dérivées d'une adresse MAC soient aujourd'hui minoritaires dans les journaux des serveurs Internet (voir les mesures à la fin de cet article). L'ancienne recommandation a été abandonné et le RFC 6724 dit clairement qu'il faut utiliser les adresses temporaires par défaut.

D'autre part, comme l'adresse stable fondée sur l'adresse MAC demeure, en plus de l'adresse temporaire, les inconvénients liés au balayage « optimisé » du réseau demeurent.

Il faut aussi noter qu'il n'y a pas que l'IID (la partie droite de l'adresse IP) qui est révélatrice. Le préfixe (la partie gauche) peut l'être également. Par exemple, si on suivait le RFC 3314, qui recommande un préfixe unique par téléphone en GPRS, ce préfixe, s'il était attribué de manière stable, serait caractéristique d'un téléphone donné.

Un tableau au début de la section 4 résume la vulnérabilité des différents choix d'allocation d'adresses IPv6 aux différents risques indiqués en section 3 (corrélation, localisation, balayage et indication du vendeur). Par exemple, une adresse attribuée manuellement permet la corrélation, tant que cette adresse dure (ces attributions manuelles concernent en général les serveurs, pour lesquels les problèmes de vie privée sont nettement moins graves) et une adresse dérivée de l'adresse MAC permet la corrélation tant qu'on ne change pas la carte Ethernet ou Wifi (ou son adresse MAC, ce que les gens oublient souvent, mais qui est possible avec la plupart des cartes).

En revanche, les adresses temporaires ne permettent la corrélation que pendant la durée de vie de ces adresses (une journée, par défaut), et les adresses stables et opaques du RFC 7217 permettent la corrélation tant que la machine ne change pas de réseau mais la bloquent dès qu'on bouge.

Le tableau est explicité dans les sections suivantes :

  • Les adresses dérivées de l'adresse MAC sont sensibles aux quatre risques.
  • Les adresses configurées manuellement sont sensibles aux deux premiers risques (corrélation et localisation).
  • Des adresses générées cryptographiquement (par exemple en suivant le RFC 3972) sont en théorie vulnérables à la corrélation (puisqu'on garde la clé publique, et donc l'IID, très longtemps) mais cela peut être limité en suivant la section 7.3 du RFC 3972.
  • Les adresses stables et opaques du RFC 7217 sont vulnérables à la corrélation tant qu'on reste sur le même réseau. Si une machine utilisant ces adresses change de réseau, il n'y a plus de corrélation possible mais, si elle revient sur le réseau d'origine, ses correspondants la reconnaitront à nouveau.
  • Les adresses temporaires du RFC 8981 sont à l'abri des quatre vulnérabilités citées (ce qui est assez normal : elles sont conçues spécialement pour la vie privée). Il reste le cas du balayage : si l'adresse stable, utilisée pour les connexions entrantes, se fonde sur l'adresse MAC, certaines techniques de balayage peuvent encore s'utiliser. Il est donc recommandé d'utiliser le RFC 7217 ou équivalent pour générer l'adresse stable.

Enfin, la section 5 de notre RFC traite de divers problèmes liés à ce souci de vie privée. Par exemple, il rappelle que des adresses qui changent (telles les adresses temporaires du RFC 8981) peuvent être une plaie pour l'administration de réseaux et que certaines organisations vont donc les désactiver sur les postes de travail, et tant pis pour la vie privée.

Autre cas embêtant, il existe apparemment des suites de test IPv6 qui vérifient que l'adresse IPv6 est bien dérivée de l'adresse MAC. C'est évidemment une mauvaise idée et notre RFC demande que ces suites soient mises à jour.

À noter qu'il existe un outil pratique, addr6, qui fait partie du SI6 toolkit. Utilisant divers techniques (et heuristiques : il se trompe parfois), il vous dit à quelle catégorie appartient une adresse :

[L'adresse de base d'une machine]
% addr6 -a 2a01:ff41:916b:3bb0:ba27:ebff:feaa:78b9
unicast=global=global=ieee-derived=b8-27-eb

[Une des adresses temporaires de la même machine (c'est un FreeBSD avec
ipv6_privacy="YES" dans rc.conf]
% addr6 -a 2a01:ff41:916b:3bb0:810e:9c6d:341:e7a 
unicast=global=global=randomized=unspecified

[Un serveur public, d.nic.fr]
% addr6 -a 2001:678:c::1
unicast=global=global=low-byte=unspecified
    

Quelle est la situation aujourd'hui ? Quels types d'adresses sont utilisés par les machines IPv6 ? J'ai fait un petit test avec les visiteurs de mon blog (qui ne sont pas forcément représentatifs : vus les sujets traités sur ce blog, les visiteurs sont sans doute techniquement plus avancés que la moyenne)  :

% zgrep -h -E  '^[0-9]+:' /var/log/apache2/access.log* | awk '{print $1}' | \
         sort | uniq | addr6 -i -s   

** IPv6 General Address Analysis **

Total IPv6 addresses: 1997
Unicast:    1997 (100.00%)              Multicast:       0 (0.00%)
Unspec.:       0 (0.00%)

** IPv6 Unicast Addresses **

Loopback:           0 (0.00%)           IPv4-mapped:        0 (0.00%)
IPv4-compat.:       0 (0.00%)           Link-local:         0 (0.00%)
Site-local:         0 (0.00%)           Unique-local:       0 (0.00%)
6to4:               9 (0.45%)           Teredo:             0 (0.00%)
Global:          1988 (99.55%)

** IPv6 Interface IDs **

Total IIDs analyzed: 1997
IEEE-based:     230 (11.52%)            Low-byte:            323 (16.17%)
Embed-IPv4:       0 (0.00%)             Embed-IPv4 (64):     122 (6.11%)
Embed-port:       7 (0.35%)             Embed-port (r):        1 (0.05%)
ISATAP:           1 (0.05%)             Byte-pattern:         23 (1.15%)
Randomized:    1190 (59.59%)
      

On voit que la majorité utilise des adresses temporaires (Randomized) ce qui est bon signe (et tord le cou à la légende comme quoi les adresses IPv6 permettraient de suivre un utilisateur à la trace). Le second type, en nombre d'adresses distinctes (je n'ai pas cherché à pondérer par le nombre de visites faites par chaque adresse), est celui des adresses manuelles avec un octet de faible valeur (Low-byte). Il peut s'agir de serveurs, par exemple des crawlers. Les adresses IPv6 fondées sur l'adresse MAC sont le troisième type, avec plus de 11 %, et des efforts seront sans doute nécessaires pour sensibiliser ces utilisateurs.


Téléchargez le RFC 7721


L'article seul

RFC 7720: DNS Root Name Service Protocol and Deployment Requirements

Date de publication du RFC : Décembre 2015
Auteur(s) du RFC : M. Blanchet (Viagenie), L-J. Liman (Netnod)
Première rédaction de cet article le 13 décembre 2015


L'Internet repose en grande partie sur le DNS (si ce dernier est en panne, presque plus rien ne fonctionne) et le DNS doit à sa nature arborescente de dépendre de sa racine ou plus exactement de ses serveurs racine. La gestion de ces derniers est donc une question cruciale, même si les débats sur la gouvernance de l'Internet se focalisent plutôt sur des sujets moins concrets comme la création (ou non) du TLD .vin. Ce très court RFC précise les obligations des serveurs racine en terme de protocoles réseau à suivre. D'autres documents décrivent les exigences opérationnelles. (Voir notamment le RSSAC 001: Service Expectation of Root Servers.)

Avant, ces obligations étaient dans un seul RFC, le RFC 2870. Il contenait des recommandations concernant les protocoles, donc plutôt du ressort de l'IETF, et d'autres concernant les règles quotidiennes des opérations d'un serveur racine, considérées aujourd'hui comme relevant plutôt du RSSAC (Root Server System Advisory Committee, qui publie ses propres recommandations dans le document nommé RSSAC-001). Ce RFC est donc encore plus court que son prédécesseur, désormais document historique.

À noter que les serveurs racine ne servent pas que la racine, mais aussi root-servers.net, domaine dans lequel ils sont nommés. Certains d'entre eux servent également .arpa.

Le cœur de notre RFC est la section 2 qui exige que les serveurs racine :

  • Suivent le protocole DNS (encore heureux...),
  • Soient capables de répondre en IPv4 et IPv6 (en octobre 2015, deux serveurs, E et G, n'avaient toujours pas d'IPv6),
  • Soient capables de répondre en UDP et en TCP,
  • Doivent gérer les sommes de contrôle UDP,
  • Doivent évidemment gérer DNSSEC, pour pouvoir servir la racine, qui est signée,
  • Doivent gérer EDNS (RFC 6891).

La plupart de ces règles vont de soi mais, en 2015, on rencontre hélas encore des serveurs DNS qui n'ont pas EDNS ou bien qui n'ont pas TCP (sans même parler d'IPv6...)

Moins liées aux protocoles, il y a deux autres exigences dans la section 3 :

  • Répondre à tous les clients (c'est un principe de neutralité du réseau, qui a d'amusantes conséquences de gouvernance, par exemple les serveurs gérés par l'armée US doivent répondre aux requêtes venant d'Iran...),
  • Servir l'unique racine « officielle », cf. RFC 2826 et pas une éventuelle racine alternative. Évidemment, cela implique de ne pas la modifier : les serveurs racine sont des imprimeurs, pas des éditeurs.

Merci à Lancelot et Atlal (et Opale), qui savent pourquoi...


Téléchargez le RFC 7720


L'article seul

RFC 7719: DNS Terminology

Date de publication du RFC : Décembre 2015
Auteur(s) du RFC : P. Hoffman (ICANN), A. Sullivan (Dyn), K. Fujiwara (JPRS)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 19 décembre 2015


Comme beaucoup de protocoles très utilisés sur l'Internet, le DNS est ancien. Très ancien (la première norme, le RFC 882, date de 1983). Les normes techniques vieillissent, avec l'expérience, on comprend mieux, on change les points de vue et donc, pour la plupart des protocoles, on se lance de temps en temps dans une révision de la norme. Mais le DNS est une exception : la norme actuelle reste fondée sur des textes de 1987, les RFC 1034 et RFC 1035. Ces documents ne sont plus à jour, modifiés qu'ils ont été par des dizaines d'autres RFC. Bref, aujourd'hui, pour comprendre le DNS, il faut s'apprêter à lire de nombreux documents. En attendant qu'un courageux et charismatique participant à l'IETF se lance dans la tâche herculéenne de faire un jeu de documents propre et à jour, ce nouveau RFC 7719 se limitait à une ambition plus modeste : fixer la terminologie du DNS. Depuis, il a été remplacé par un document plus récent, le RFC 8499.

En effet, chacun peut constater que les discussions portant sur le DNS sont difficiles : on manque de terminologie standard, et celle des RFC officielles ne suffit pas, loin de là. Souvent, le DNS a tellement changé que le RFC officiel est même trompeur : les mots ne veulent plus dire la même chose. D'autres protocoles ont connu des mises à jour de la norme. Cela a été le cas de SMTP, passé successivement du RFC 772 à l'actuel RFC 5321, en passant par plusieurs révisions successives. Ou de XMPP, qui a vu sa norme originale mise à jour dans le RFC 6120. Et bien sûr de HTTP, qui a connu récemment un toilettage complet. Mais personne n'a encore osé faire pareil pour le DNS. Au moins, ce nouveau RFC 7719 traite l'un des problèmes les plus criants, celui du vocabulaire. Le RFC est évidemment en anglais, les traductions proposées dans cet article, et qui n'ont pas de valeur « officielle » sont de moi seul.

Notre RFC 7719 rassemble donc des définitions pour des termes qui étaient parfois précisément définis dans d'autres RFC (et il fournit alors un lien vers ce RFC original), mais aussi qui n'étaient définis qu'approximativement ou parfois qui n'étaient pas définis du tout (et ce RFC fournit alors cette définition). Du fait du flou de certains RFC anciens, et des changements qui ont eu lieu depuis, certaines définitions sont différentes de l'original. Le document a fait l'objet d'un consensus relatif auprès des experts DNS mais quelques termes restent délicats. Notez aussi que d'autres organisations définissent des termes liés au DNS par exemple le W3C a sa propre définition de « domaine ».

Ironiquement, un des termes les plus difficiles à définir est « DNS » lui-même. D'accord, c'est le sigle de Domain Name System mais ça veut dire quoi ? « DNS » peut désigner le schéma de nommage (les noms de domaine comme signal.eu.org, leur syntaxe, leurs contraintes), la base de données répartie (et faiblement cohérente) qui associe à ces noms des informations (comme des certificats, des adresses IP, etc), ou le protocole requête/réponse (utilisant le port 53) qui permet d'interroger cette base. Parfois, « DNS » désigne uniquement le protocole, parfois, c'est une combinaison des trois éléments indiqués plus haut (personnellement, quand j'utilise « DNS », cela désigne uniquement le protocole).

Bon, et ces définitions rigoureuses et qui vont mettre fin aux discussions, ça vient ? Chaque section du RFC correspond à une catégorie particulière. D'abord, en section 2, les noms eux-même, ces fameux noms de domaine :

  • Nom de domaine (domain name) : on reprend la définition du RFC 1034, section 3.1, dans une structure arborescente, le nom est une suite de composants (labels), la racine de l'arbre étant à la fin. Aucune restriction n'est imposée dans ces composants (tant pis pour la légende comme quoi le DNS serait limité à ASCII). Comme on peut représenter les noms de domaine sous forme d'un arbre, ou bien sous forme texte (www.madmoizelle.com), le vocabulaire s'en ressent. Par exemple, on va dire que com est « au-dessus de madmoizelle.com » (vision arborescente) ou bien « à la fin de www.madmoizelle.com » (vision texte). Notez aussi que la représentation des noms de domaine dans les paquets IP n'a rien à voir avec leur représentation texte (par exemple, les points n'apparaissent pas).
  • FQDN (Fully Qualified Domain Name, nom de domaine complet) : apparu dans le RFC 819, ce terme désigne un nom de domaine où tous les composants sont cités (par exemple, ldap.potamochère.fr. est un FQDN alors que ldap tout court ne l'est pas). En toute rigueur, un FQDN devrait toujours s'écrire avec un point à la fin (pour représenter la racine) mais ce n'est pas toujours le cas.
  • Composant (label) : un nœud de l'arbre des noms de domaine, dans la chaîne qui compose un FQDN. Dans www.laquadrature.net, il y a trois composants, www, laquadrature et net.
  • Nom de machine (host name) : ce n'est pas la même chose qu'un nom de domaine. Utilisé dans de nombreux RFC (par exemple RFC 952) mais jamais défini, un nom de machine est un nom de domaine avec une syntaxe plus restrictive : uniquement des lettres, chiffres, points et le tiret. Ainsi, brienne.tarth.got.example peut être un nom de machine mais www.&#$%?.example ne peut pas l'être. Le terme de « nom de machine » est parfois aussi utilisé pour parler du premier composant d'un nom de domaine (brienne dans brienne.tarth.got.example).
  • TLD (Top Level Domain, domaine de premier niveau ou domaine de tête) : le dernier composant d'un nom de domaine, celui juste avant (ou juste en dessous) de la racine. Ainsi, fr ou name sont des TLD. N'utilisez surtout pas le terme erroné d'« extension ».
  • IDN (Internationalized Domain Name, nom de domaine internationalisé) : un nom de domaine en Unicode, normalisé dans le RFC 5890.
  • Sous-domaine (subdomain) : domaine situé sous un autre, dans l'arbre des noms de domaines. Sous forme texte, un domaine est sous-domaine d'un autre si cet autre est un suffixe. Ainsi, www.cl.cam.ac.uk est un sous-domaine de cl.cam.ac.uk, qui est un sous-domaine de cam.ac.uk et ainsi de suite, jusqu'à la racine, le seul domaine à n'être sous-domaine de personne.
  • Alias (alias) : attention, il y a un piège. Le DNS permet à un nom d'être un alias d'un autre, avec le type d'enregistrement CNAME (voir la définition suivante). L'alias est le terme de gauche de l'enregistrement CNAME. Ainsi, si on met dans un fichier de zone vader IN CNAME anakin, l'alias est vader (et c'est une erreur de dire que c'est « le CNAME »).
  • CNAME (Canonical Name, nom canonique, le « vrai » nom) : le membre droit dans l'enregistrement CNAME. Dans l'exemple de la définition précédente, anakin est le CNAME, le « nom canonique ».
  • Suffixe public (public suffix) : ce terme pas très officiel est parfois utilisé pour désigner un suffixe de noms de domaine qui est contrôlé par un registre public (au sens où il accepte des enregistrements du public). Le terme est ancien mais est apparu pour la première fois dans un RFC avec le RFC 6265, section 5.3. com, co.uk et eu.org sont des suffixes publics. Rien dans la syntaxe du nom n'indique qu'un nom de domaine est un suffixe public, puisque ce statut ne dépend que d'une politique d'enregistrement (qui peut changer).

Fini avec les noms, passons à l'en-tête des messages DNS et aux codes qu'il peut contenir. Cet en-tête est défini dans le RFC 1035, section 4.1. Il donne des noms aux champs mais pas forcément aux codes. Ainsi, le code de réponse 3 indiquant qu'un domaine demandé n'existe pas est juste décrit comme name error et n'a reçu son mnémonique de NXDOMAIN (No Such Domain) que plus tard. Notre RFC définit également :

  • NODATA : un mnémonique pour une réponse où le nom de domaine demandé existe bien mais ne contient aucun enregistrement du type souhaité. Le code de retour est 0, NOERROR, et le nombre de réponses (ANCOUNT pour Answer Count) est nul.
  • Réponse négative (negative answer) : le terme recouvre deux choses, une réponse disant que le nom de domaine demandé n'existe pas, ou bien une réponse indiquant que le serveur ne peut pas répondre (code de retour SERVFAIL ou REFUSED). Voir le RFC 2308.
  • Renvoi (referral) : le DNS étant décentralisé, il arrive qu'on pose une question à un serveur qui ne fait pas autorité pour le domaine demandé, mais qui sait vous renvoyer à un serveur plus proche. Ces renvois sont indiqués dans la section Authority d'une réponse.

Voici un renvoi depuis la racine vers .fr :


% dig @l.root-servers.net A blog.imirhil.fr 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16572
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 5, ADDITIONAL: 11
...
;; AUTHORITY SECTION:
fr.			172800 IN NS d.ext.nic.fr.
fr.			172800 IN NS d.nic.fr.
fr.			172800 IN NS e.ext.nic.fr.
fr.			172800 IN NS f.ext.nic.fr.
fr.			172800 IN NS g.ext.nic.fr.

    

Passons maintenant aux enregistrements DNS, stockés dans cette base de données répartie (section 4 du RFC) :

  • RR (Resource Record, un enregistrement DNS).
  • Ensemble d'enregistrements (RRset pour Resource Record set) : un ensemble d'enregistrements ayant le même nom (la même clé d'accès à la base), la même classe, le même type et le même TTL. Cette notion avait été introduite par le RFC 2181. Notez que la définition originale, reprise par notre RFC, parle malheureusement de label dans un sens incorrect. La terminologie du DNS est vraiment compliquée !
  • EDNS (Extension for DNS, également appelé EDNS0) : normalisé dans le RFC 6891, EDNS permet d'étendre l'en-tête du DNS, en spécifiant de nouvelles options, en faisant sauter l'antique limitation de taille de réponses à 512 octets, etc.
  • OPT (pour Option) : une astuce d'EDNS pour encoder les informations de l'en-tête étendu. C'est un enregistrement DNS un peu spécial, défini dans le RFC 6891, section 6.1.1.
  • Propriétaire (owner ou owner name) : le nom de domaine d'un enregistrement. Ce terme est très rarement utilisé, même par les experts.
  • Champs du SOA (SOA field names) : ces noms des enregistrements SOA (comme MNAME ou RNAME) sont peu connus et peu utilisés (RFC 1035, section 3.3.13). Notez que la sémantique du champ MINIMUM a complètement changé avec le RFC 2308.
  • TTL (Time To Live) : la durée de vie maximale d'un enregistrement dans les caches des résolveurs. C'est un entier non signé (même si le RFC 1035 dit le contraire), en secondes.

Voici un ensemble d'enregistrements (RRset), comptant ici deux enregistrements :


rue89.com.		600 IN MX 50 mx2.typhon.net.
rue89.com.		600 IN MX 10 mx1.typhon.net.	       
	       
    

Et voici un pseudo-enregistrement OPT, tel qu'affiché par dig, avec une indication de la taille maximale et l'option client subnet (RFC pas encore publié) :

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
; CLIENT-SUBNET: 13.176.144.0/24/0
    

Ensuite, un sujet chaud où le vocabulaire est particulièrement peu défini, et très mal utilisé (voir les forums grand public sur le DNS où les discussions prennent un temps fou car les gens utilisent mal les mots) : les différents types de serveurs et clients DNS (section 5) :

  • Résolveur (resolver) : un client DNS qui va produire une réponse finale (pas juste un renvoi, pas juste une information ponctuelle comme le fait dig). Il existe plusieurs types de résolveurs (voir ci-dessous) et, en pratique, quand on dit « résolveur » tout court, c'est en général un « résolveur complet ».
  • Résolveur minimum (stub resolver) : un résolveur qui ne sait pas suivre les renvois et qui dépend donc d'un ou de plusieurs résolveurs complets pour faire son travail. Ce type est défini dans la section 6.1.3.1 du RFC 1123. C'est ce résolveur minimum qu'appelent les applications lorsqu'elles font un getaddrinfo() ou getnameinfo(). Sur Unix, le résolveur minimum fait en général partie de la libc et trouve l'adresse du ou des résolveurs complets dans /etc/resolv.conf.
  • Résolveur complet (full resolver) : un résolveur qui sait suivre les renvois et donc fournir un service de résolution complet. Des logiciels comme Unbound ou PowerDNS Resolver assurent cette fonction. Le résolveur complet est en général situé chez le FAI ou dans le réseau local de l'organisation où on travaille, mais il peut aussi être sur la machine locale. On le nomme aussi « résolveur récursif ».
  • Serveur faisant autorité (authoritative server et traduire ce terme par « serveur autoritaire » montre une grande ignorance de l'anglais, un adjudant est autoritaire, un serveur DNS fait autorité) : un serveur DNS qui connait une partie des données du DNS (il « fait autorité » pour une ou plusieurs zones) et peut donc y répondre (RFC 2182, section 2). Ainsi, au moment de l'écriture de cet article, f.root-servers.net fait autorité pour la racine, d.nic.fr fait autorité pour pm, etc. Des logiciels comme NSD ou Knot assurent cette fonction. Les serveurs faisant autorité sont gérés par divers acteurs, les registres, les hébergeurs DNS (qui sont souvent en même temps bureaux d'enregistrement), mais aussi par M. Michu. La commande dig NS $ZONE vous donnera la liste des serveurs faisant autorité pour la zone $ZONE.
  • Serveur mixte : ce terme n'est pas dans ce RFC. Autrefois, il était courant que des serveurs DNS fassent à la fois résolveur et serveur faisant autorité. Cette pratique est fortement déconseillée depuis de nombreuses années (entre autres parce qu'elle complique sérieusement le débogage, mais aussi pour des raisons de sécurité parce qu'elle mène à du code plus complexe) et n'est donc pas dans ce RFC.
  • Initialisation (priming) : le processus par lequel un résolveur complet vérifie l'information sur les serveurs de la racine. Au démarrage, le résolveur ne sait rien. Pour pouvoir commencer la résolution de noms, il doit demander aux serveurs de la racine. Il a donc dans sa configuration leur liste. Mais ces configurations ne sont pas forcément mises à jour souvent. La liste peut donc être trop vieille. La première chose que fait un résolveur est donc d'envoyer une requête « NS . » à un des serveurs de sa liste. Ainsi, tant qu'un moins un des serveurs de la vieille liste répond, le résolveur est sûr d'apprendre la liste actuelle.
  • Mémorisation des négations (negative caching, ou « cache négatif ») : mémoriser le fait qu'il n'y a pas eu de réponse, ou bien une réponse disant qu'un nom de domaine n'existe pas.
  • Serveur primaire (primary server mais on dit aussi master server) : un serveur faisant autorité qui a accès à la source des données (fichier de zone, base de données, etc). Attention, il peut y avoir plusieurs serveurs primaires (autrefois, ce n'était pas clair et beaucoup de gens croient qu'il y a un serveur primaire, et qu'il est indiqué dans l'enregistrement SOA). Attention bis, le terme ne s'applique qu'à des serveurs faisant autorité, l'utiliser pour les résolveurs (« on met en premier dans /etc/resolv.conf le serveur primaire ») n'a pas de sens.
  • Serveur secondaire (secondary server mais on dit aussi « serveur esclave », slave server) : un serveur faisant autorité qui n'est pas la source des données, qui les a prises d'un serveur primaire (dit aussi serveur maître), via un transfert de zone (RFC 5936).
  • Serveur furtif (stealth server) : un serveur faisant autorité mais qui n'apparait pas dans l'ensemble des enregistrements NS. (Définition du RFC 1996, section 2.1.)
  • Maître caché (hidden master) : un serveur primaire qui n'est pas annoncé publiquement (et n'est donc accessible qu'aux secondaires). C'est notamment utile avec DNSSEC : s'il signe, et donc a une copie de la clé privée, il vaut mieux qu'il ne soit pas accessible de tout l'Internet (RFC 6781, section 3.4.3).
  • Transmission (forwarding) : le fait, pour un résolveur, de faire suivre les requêtes à un autre résolveur (probablement mieux connecté et ayant un cache partagé plus grand). On distingue parfois (mais ce n'est pas forcément clair, même dans le RFC 5625) la transmission, où on émet une nouvelle requête, du simple relayage de requêtes sans modification.
  • Transmetteur (forwarder) : le terme est confus (et a suscité plein de débats dans le groupe de travail DNSOP lors de la mise au point de ce RFC). Il désigne parfois la machine qui transmet une requête et parfois celle vers laquelle on transmet (c'est dans ce sens qu'il est utilisé dans la configuration de BIND, avec la directive forwarders).
  • Résolveur politique (policy-implementing resolver) : un résolveur qui modifie les réponses reçues, selon sa politique. On dit aussi, moins diplomatiquement, un « résolveur menteur ». C'est ce que permet, par exemple, le système RPZ. Sur l'utilisation de ces « résolveurs politiques » pour mettre en œuvre la censure, voir entre autres mon article aux RIPE Labs. Notez que le résolveur politique a pu être choisi librement par l'utilisateur (par exemple comme élément d'une solution de blocage des publicités) ou bien qu'il lui a été imposé.
  • Résolveur ouvert (open resolver) : un résolveur qui accepte des requêtes DNS depuis tout l'Internet. C'est une mauvaise pratique (cf. RFC 5358) et la plupart de ces résolveurs ouverts sont des erreurs de configuration. Quand ils sont délibérement ouverts, comme Google Public DNS, on parle plutôt de résolveurs publics.
  • Collecte DNS passive (passive DNS) : désigne les systèmes qui écoutent le trafic DNS, et stockent tout ou partie des messages DNS échangés. Le cas le plus courant est celui où le système de collecte ne garde que les réponses (ignorant donc les adresses IP des clients et serveurs), afin de constituer une base historique du contenu du DNS (c'est ce que font DNSDB ou le système de PassiveDNS.cn).
  • Anycast : le fait d'avoir un service en plusieurs sites physiques, chacun annonçant la même adresse IP de service (RFC 4786). Cela résiste mieux à la charge, et permet davantage de résilience en cas d'attaque par déni de service. Les serveurs de la racine, ceux des « grands » TLD, et ceux des importants hébergeurs DNS sont ainsi « anycastés ».

Voici, vu par tcpdump, un exemple d'initialisation d'un résolveur BIND utilisant la racineYeti :

15:07:36.736031 IP6 2a01:e35:8bd9:8bb0:21e:8cff:fe76:29b6.35721 > 2001:6d0:6d06::53.53: \
       21476% [1au] NS? . (28)
15:07:36.801982 IP6 2001:6d0:6d06::53.53 > 2a01:e35:8bd9:8bb0:21e:8cff:fe76:29b6.35721: \
       21476*- 16/0/1 NS yeti-ns.tisf.net., NS yeti-ns.lab.nic.cl., NS yeti-ns.wide.ad.jp., NS yeti.ipv6.ernet.in., NS yeti-ns.as59715.net., NS ns-yeti.bondis.org., NS yeti-dns01.dnsworkshop.org., NS dahu2.yeti.eu.org., NS dahu1.yeti.eu.org., NS yeti-ns.switch.ch., NS bii.dns-lab.net., NS yeti.bofh.priv.at., NS yeti-ns.conit.co., NS yeti.aquaray.com., NS yeti-ns.ix.ru., RRSIG (619)
    

La question était « NS . » (quels sont les serveurs de la racine) et la réponse contenait les noms des seize serveurs racine.

Voici aussi des exemples de résultats avec un résolveur ou bien avec un serveur faisant autorité. Si je demande à un serveur faisant autorité (ici, un serveur racine), avec mon client DNS qui, par défaut, demande un service récursif (flag RD, Recursion Desired) :


% dig @2001:620:0:ff::29 AAAA www.iab.org 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54197
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 9, ADDITIONAL: 13
;; WARNING: recursion requested but not available
...
;; AUTHORITY SECTION:
org.			172800 IN NS b0.org.afilias-nst.org.	       
...
	       
    

C'est pour cela que dig affiche WARNING: recursion requested but not available. Notez aussi que le serveur, ne faisant autorité que pour la racine, n'a pas donné la réponse mais juste un renvoi aux serveurs d'Afilias. Maintenant, interrogeons un serveur récursif (le service de résolveur public Yandex DNS) :


% dig @2a02:6b8::feed:0ff AAAA www.iab.org           
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63304
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
...
;; ANSWER SECTION:
www.iab.org.		1800 IN	AAAA 2001:1900:3001:11::2c
	       
    

Cette fois, j'ai obtenu une réponse, et avec le flag RA, Recursion Available. Si je pose une question sans le flag RD (Recursion Desired, avec l'option +norecurse de dig) :


% dig +norecurse @2a02:6b8::feed:0ff AAAA www.gq.com  
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59438
;; flags: qr ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
...
;; ANSWER SECTION:
www.gq.com.		293 IN CNAME condenast.map.fastly.net.
	       
    

J'ai obtenu ici une réponse car l'information était déjà dans le cache (la mémoire) de Yandex DNS (on le voit au TTL, qui n'est pas un chiffre rond, il a été décrémenté du temps passé dans le cache). Si l'information n'est pas dans le cache :

    
% dig +norecurse @2a02:6b8::feed:0ff AAAA blog.keltia.net
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19893
;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
...
	       
    

Je n'obtiens alors pas de réponse (ANSWER: 0). Si je demande au serveur faisant autorité pour cette zone :


% dig +norecurse @2a01:e0d:1:3:58bf:fa61:0:1 AAAA blog.keltia.net  
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62908
;; flags: qr aa; QUERY: 1, ANSWER: 2, AUTHORITY: 6, ADDITIONAL: 15
...
;; ANSWER SECTION:
blog.keltia.net.	86400 IN AAAA 2a01:240:fe5c:1::2
...
	       
    

J'ai évidemment une réponse et, comme il s'agit d'un serveur faisant autorité, elle porte le flag AA (Authoritative Answer, qu'un résolveur ne mettrait pas). Notez aussi le TTL qui est un chiffre rond (et qui ne change pas si on rejoue la commande).

Passons maintenant à un concept relativement peu connu, celui de zones, et le vocabulaire associé :

  • Zone : un groupe de domaines contigus et gérés ensemble, par le même ensemble de serveurs de noms (ma définition, celle du RFC étant très abstraite). Beaucoup de gens croient que tout domaine est une zone, mais c'est faux. Ainsi, au moment de la publication de ce RFC, gouv.fr n'est pas une zone séparée, il est dans la même zone que fr (cela se teste facilement : gouv.fr n'a pas d'enregistrement NS ou de SOA).
  • Parent : le domaine « du dessus ». Ainsi, le parent de wikipedia.org est org.
  • Apex : le sommet d'une zone, là où on trouve les enregistrements NS et SOA. Si la zone ne comprend qu'un domaine, l'apex est ce domaine. Si la zone est plus complexe, l'apex est le domaine le plus court.
  • Coupure de zone (zone cut) : l'endoit où on passe d'une zone à l'autre. Au-dessus de la coupure, la zone parente, en dessous, la zone fille.
  • Délégation (delegation) : un concept évidemment central dans le DNS, qui est un système décentralisé. En ajoutant un ensemble d'enregistrements NS pointant vers les serveurs de la zone fille, une zone parente délègue une partie de l'arbre des noms de domaine à une aure entité. L'endroit où se fait la délégation est donc une coupure de zone.
  • Colle (glue records) : lorsqu'une zone est déléguée à des serveurs dont le nom est dans la zone fille, la résolution DNS se heurte à un problème d'œuf et de poule. Pour trouver l'adresse de ns1.mazone.example, le résolveur doit passer par les serveurs de mazone.example, qui est déléguée à ns1.mazone.example et ainsi de suite... On rompt ce cercle vicieux en ajoutant, dans la zone parente, des données qui ne font pas autorité sur les adresses de ces serveurs (RFC 1034, section 4.2.1). Il faut donc bien veiller à les garder synchrones avec la zone fille. (Tanguy Ortolo me suggère d'utiliser « enregistrement de raccord » plutôt que « colle ». Cela décrit bien leur rôle, en effet.)
  • Dans le bailliage (in bailiwick) : terme absent des textes DNS originaux et qui peut désigner plusieurs choses. Il est (très rarement, selon mon expérience) parfois utilisé pour parler d'un serveur de noms dont le nom est dans la zone servie (et qui nécessite donc de la colle, voir la définition précédente), mais le sens le plus courant désigne des données pour lesquelles le serveur qui a répondu fait autorité, soit pour la zone, soit pour un ancêtre de cette zone. L'idée est qu'il est normal dans la réponse d'un serveur de trouver des données situées dans le bailliage et, par contre, que les données hors-bailliages sont suspectes (elles peuvent être là suite à une tentative d'empoisonnement DNS). Un résolveur DNS prudent ignorera donc les données hors-bailliage.
  • ENT (Empty Non-Terminal pour nœud non-feuille mais vide) : un domaine qui n'a pas d'enregistrements mais a des sous-domaines. C'est fréquent, par exemple, sous ip6.arpa ou sous les domaines très longs de certains CDN.
  • Zone de délégation (delegation-centric zone) : zone composée essentiellement de délégations vers d'autres zones. C'est typiquement le cas des TLD et autres suffixes publics.
  • Joker (wildcard) : une source de confusion considérable depuis les débuts du DNS. Si on pouvait refaire le DNS en partant de zéro, ces jokers seraient la première chose à supprimer. Pour les résumer, le nom * dans une zone déclenche la synthèse automatique de réponses pour les noms qui n'existent pas dans la zone. Si la zone foo.example contient bar.foo.example et *.foo.example, une requête pour thing.foo.example renverra le contenu de l'enregistrement avec le joker, une requête pour bar.foo.example donnera les données de bar.foo.example.
  • Changement rapide (fast flux) : une technique notamment utilisée par les botnets pour mettre leur centre de commande à l'abri des filtrages ou destructions. Elle consiste à avoir des enregistrements d'adresses IP avec des TTL très courts et à en changer fréquemment.

Voyons ici la colle retournée par un serveur faisant autorité (en l'occurrence un serveur de .net) :


% dig @a.gtld-servers.net AAAA labs.ripe.net 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18272
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 9
...
;; AUTHORITY SECTION:
ripe.net.		172800 IN NS ns3.nic.fr.
ripe.net.		172800 IN NS sec1.apnic.net.
ripe.net.		172800 IN NS sec3.apnic.net.
ripe.net.		172800 IN NS tinnie.arin.net.
ripe.net.		172800 IN NS sns-pb.isc.org.
ripe.net.		172800 IN NS pri.authdns.ripe.net.
...
;; ADDITIONAL SECTION:
sec1.apnic.net.		172800 IN AAAA 2001:dc0:2001:a:4608::59
sec1.apnic.net.		172800 IN A 202.12.29.59
sec3.apnic.net.		172800 IN AAAA 2001:dc0:1:0:4777::140
sec3.apnic.net.		172800 IN A 202.12.28.140
tinnie.arin.net.	172800 IN A 199.212.0.53
tinnie.arin.net.	172800 IN AAAA 2001:500:13::c7d4:35
pri.authdns.ripe.net.	172800 IN A 193.0.9.5
pri.authdns.ripe.net.	172800 IN AAAA 2001:67c:e0::5
	     
    

On notera :

  • La section ANSWER est vide, c'est un renvoi.
  • Le serveur indique la colle pour pri.authdns.ripe.net : ce serveur étant dans la zone qu'il sert, sans son adresse IP, on ne pourrait jamais le joindre.
  • Le serveur envoie également les adresses IP d'autres machines comme sec1.apnic.net. Ce n'est pas strictement indispensable (on pourrait l'obtenir par une nouvelle requête), juste une optimisation.
  • Les adresses de ns3.nic.fr et sns-pb.isc.org ne sont pas renvoyées. Le serveur ne les connait probablement pas et, de toute façon, elles seraient hors-bailliage.

Voyons maintenant, un ENT, gouv.fr :

   
% dig @d.nic.fr ANY gouv.fr 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42219
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 1

    

Le serveur fait bien autorité pour ce domaine (flag AA dans la réponse), le domaine existe (autrement, le status aurait été NXDOMAIN, pas NOERROR) mais il n'y a aucun enregistrement (ANSWER: 0).

Allez courage, ne faiblissons pas, il reste encore la question de l'enregistrement des noms de domaine (section 7) :

  • Registre (registry) : l'organisation ou la personne qui gère les délégations d'une zone. Le terme est parfois employé uniquement pour les gérants de grandes zones de délégation, mais ce n'est pas obligatoire. Je suis à moi tout seul le registre de bortzmeyer.org :-) C'est le registre qui décide de la politique d'enregistrement, qui peut être très variable selon les zones (sauf dans celles contrôlées par l'ICANN, où une certaine uniformité est imposée). Mes lecteurs français noteront que, comme le terme « registre » est court et largement utilisé, le gouvernement a inventé un nouveau mot, plus long et jamais vu auparavant, « office d'enregistrement ».
  • Titulaire (registrant, parfois holder) : la personne ou l'organisation qui a enregistré un nom de domaine.
  • Bureau d'enregistrement (registrar) : dans le modèle RRR (Registry-Registrar-Registrant, mais ce modèle n'est pas obligatoire et pas universel), c'est un intermédiaire entre le titulaire et le registre.
  • Hébergeur DNS (DNS operator) : la personne ou l'organisation qui gère les serveurs DNS. Cela peut être le titulaire, son bureau d'enregistrement, ou encore un acteur spécialisé dans cette gestion.
  • EPP (Extensible Provisioning Protocol) : normalisé dans le RFC 5730, c'est le protocole standard entre bureau d'enregistrement et registre. Ce protocole n'a pas de lien avec le DNS, et tous les registres ne l'utilisent pas.
  • Whois (nommé d'après la question Who Is?) : un protocole réseau, sans lien avec le DNS, normalisé dans le RFC 3912. Il permet d'interroger les bases de données du registre pour trouver les informations qui ne sont pas dans le DNS (comme le nom du titulaire, et des moyens de le contacter). Les termes de « base Whois » ou de « données Whois » sont parfois utilisés mais ils sont erronés puisque les mêmes bases peuvent être interrogées par d'autres protocoles que Whois, comme RDAP (voir définition suivante).
  • RDAP (Registration Data Access Protocol) : un protocole concurrent de Whois, mais plus moderne.

Enfin, pour terminer, la section 8 de notre RFC couvre DNSSEC. Pas grand'chose de nouveau ici, DNSSEC étant plus récent et donc mieux défini.

Je rappelle que ce RFC n'est plus le document final, ce rôle est désormais tenu par son successeur, le RFC 8499.


Téléchargez le RFC 7719


L'article seul

RFC 7713: Congestion Exposure (ConEx) Concepts, Abstract Mechanism and Requirements

Date de publication du RFC : Janvier 2016
Auteur(s) du RFC : M. Mathis (Google), B. Briscoe (BT)
Pour information
Réalisé dans le cadre du groupe de travail IETF conex
Première rédaction de cet article le 6 janvier 2016


Le projet ConEx de l'IETF vise à développer des mécanismes permettant à l'émetteur de paquets IP de prévenir le réseau situé en aval que ce flot de données rencontre de la congestion. Les routeurs pourront alors éventuellement prendre des décisions concernant ce flot. Ce nouveau RFC expose le mécanisme abstrait de signalisation (le mécanisme concret, dans des protocoles comme TCP, a été normalisé plus tard).

La spécification se fait donc en trois temps, décrire le problème et les scénarios d'utilisation (RFC 6789), décrire un mécanisme de signalisation de la congestion abstrait, sans se soucier des détails techniques (ce RFC 7713), puis enfin normaliser le protocole concret (RFC 7786 et RFC 7837), avec les inévitables compromis que cela implique.

Aujourd'hui, les équipements réseau comme les routeurs signalent la congestion vers l'aval, en utilisant ECN (RFC 3168), en retardant les paquets (car les files d'attente mettent du temps à se vider) ou, tout simplement, en laissant tomber des paquets. Ce signalement arrive au récepteur qui peut alors informer l'émetteur, par exemple en réduisant la fenêtre, dans TCP. Cette boucle de rétroaction préserve l'Internet de la congestion (RFC 5681). (De ces trois signaux, le temps d'acheminement est le moins utilisé, car il n'est pas un indicateur univoque de la congestion.)

Mais ce signalement n'est pas visible de tous les équipements réseau traversés par ce flot de paquets. Ceux situés en amont du premier routeur qui détecte la congestion ne sont pas prévenus, alors qu'ils auraient pu jouer un rôle. Le rôle de ConEx est justement que tout le monde soit informé. Le principe de base est que l'émetteur, une fois prévenu de la congestion, mette dans les paquets qu'il envoie un indicateur que ce flot rencontre de la congestion quelque part sur le trajet.

Pour que ConEx soit déployé, il faudra que les gens y trouvent un avantage, surtout au début où le déploiement sera limité. Ce problème est commun à tous les nouveaux protocoles mais il sera encore plus crucial pour un protocole qui permettra de signaler les gros consommateurs... Ceux-ci pourraient se retrouver pénalisés (« vos flots signalent tous de la congestion, vous devriez ne les lancer qu'aux heures creuses ») ou poussés à utiliser des protocoles moins gourmands comme LEDBAT (RFC 6817).

ConEx semblait moins nécessaire autrefois car les protocoles comme TCP étaient conçus pour limiter la congestion, en se calmant dès qu'ils la détectaient. Un problème jamais résolu était celui de machines qui ignorent délibérement cet objectif et, par exemple, utilisent des protocoles de transport qui maximisent le débit individuel et tant pis pour le reste de l'Internet. Difficile de lutter contre cet égoïsme. Il pourrait être contagieux puisque les bons citoyens se trouveraient alors défavorisés, et seraient donc tentés de suivre la voie égoïste à leur tour, poussant les gros consommateurs à faire des protocoles encore plus agressifs, etc. L'IETF a toujours découragé ces pratiques (comme celle d'ouvrir plusieurs connexions TCP simultanées pour avoir une plus grosse part du gâteau) avec un succès variable.

ConEx est une approche complémentaire : les gens peuvent consommer de la capacité réseau mais ils doivent le signaler.

Comme une des conséquences de ce signalement pourrait être un traitement différencié du flot en question (« il encombre le réseau, je le limite »), une partie importante du projet ConEx est de s'assurer qu'il n'y aura pas de triche (par exemple d'émetteur « négligeant » d'informer le réseau des problèmes qu'il pose). Les signaux ConEx doivent donc être auditables, pour détecter les tricheurs. (Voir Briscoe, « Re-feedback: Freedom with Accountability for Causing Congestion in a Connectionless Internetwork »).

Une dernière chose avant d'attaquer le cahier des charges exact de ConEx, le vocabulaire :

  • Transport qui ne peut pas faire du ConEx (Not-ConEx) : un mécanisme de transport des données qui ne connait pas du tout ConEx, ce qui est le cas de la totalité des mécanismes actuels.
  • Transport qui peut faire du ConEx (ConEx-capable) : les futurs mécanismes de transport qui sauront faire du ConEx.
  • Signal ConEx : quelque chose dans un paquet (transporté par un mécanisme capable de faire du ConEx) qui indique soit une perte de paquets (signal Re-Echo-Loss), soit une marque ECN (signal Re-Echo-ECN), soit que l'émetteur s'attend à déclencher de la congestion bientôt, par exemple parce qu'il démarre et teste la capacité du réseau (signal Credit), soit qu'il n'a rien à signaler, à part qu'il sait faire du ConEx (signal ConEx-Not-Marked).

La section 3 de notre RFC décrit les exigences précises de ConEx. D'abord, pour les signaux :

  • Le signal ConEx doit être visible par les éléments intermédiaires du réseau comme les routeurs. Il doit donc être mis dans l'en-tête IP, pas enfoui au fin fond du paquet. Il ne doit pas être modifié par ces éléments intermédiaires, l'émetteur met le signal, le reste du réseau ne fait que regarder.
  • Comme le déploiement ne sera pas instantané (et qu'il est très probable, quand on voit le déploiement très limité d'ECN, qu'il ne sera jamais complet), il est important que ConEx soit utilisable, et ait des bénéfices, même en cas de déploiement partiel.
  • Le signal doit être rapidement émis, pour bien rendre compte de la situation actuelle. Le RFC reconnait qu'il faudra évidemment au moins un RTT avant l'émission du signal (et davantage avec RTP, cf. RFC 3550 et RFC 6679).
  • Le signal doit être exact (évidemment...) et auditable, ce qui veut dire qu'un observateur extérieur doit pouvoir le vérifier, afin de détecter d'éventuels tricheurs.

Ces exigences sont parfois contradictoires et le RFC note qu'il faudra sans doute, en passant de ces abstractions à un protocole concret, accepter quelques compromis.

J'ai parlé de l'importance d'auditer les signaux ConEx. La fonction d'audition n'est pas normalisée dans ce RFC mais il pose des exigences qu'elle doit suivre, notamment :

  • Le moins de faux positifs possibles (flots honnêtes notés à tort comme tricheurs).
  • Le moins de faux négatifs possibles (tricheurs non détectés). Je note personnellement que ces deux premières exigences sont souvent en conflit...
  • Des sanctions suffisantes pour être dissuasives mais proportionnelle à la triche : en raison des faux positifs, des sanctions excessives n'encourageront pas à déployer le protocole (et pourraient représenter un vecteur d'attaque par déni de service).

Ce RFC décrit des mécanismes abstraits. Le futur travail du groupe de travail ConEx devra en faire un ensemble de mécanismes concrets, traitant entre autres de ces points :

  • L'encodage des signaux.
  • Les mécanismes d'authentification et d'intégrité.
  • Les techniques de coexistence entre des machines ConEx et non-ConEx.
  • L'extensibilité du protocole.

Là encore, il ne sera sans doute pas possible de tout satisfaire. Les futurs RFC ConEx devront donc noter quelles exigences ont été délibérement affaiblies, voire abandonnées.(Cf. les RFC 7837 et RFC 7786.)

Place à l'encodage, maintenant, pour satisfaire mes lecteurs qui préfèrent savoir à quoi vont ressembler les bits sur le câble. Je rappelle que le protocole précis n'est pas encore normalisé, cette section 4 du RFC ne fait que pointer les problèmes liés à l'encodage des signaux. Prenons en effet un encodage naïf : on décide d'un bit dans l'en-tête IP qu'on met à 1 dès qu'il y a eu une retransmission TCP (des données sans accusé de réception, qu'il a fallu réémettre), ou dès qu'on a réduit la fenêtre TCP en réponse à ECN. Cet encodage semble satisfaire les premières exigences de ConEx : il est trivial à réaliser (sans doute une seule ligne de code dans la plupart des mises en œuvre de TCP/IP), il est compatible avec les matériels et logiciels existants (les non-ConEx ignoreront tout simplement ce bit), tout routeur ConEx sur le trajet peut lire ce bit et agir en fonction de sa valeur.

Mais cet encodage trop simple a des défauts : comme dans le cas du RFC 3514, il ne permet pas un audit. On n'a aucun moyen de vérifier si l'émetteur triche ou pas. Bon, ne soyons pas trop critique : un tel encodage est utile pour aider à comprendre ConEx et à se représenter à quoi cela peut bien ressembler. Dans des environnements fermés où tout le monde est honnête, il peut suffire.

D'autres encodages sont imaginables. Par exemple, on pourrait ne rien encoder du tout et dire aux routeurs ConEx de regarder les flots TCP et d'en déduire s'il y a eu rencontre avec la congestion en aval ; en effet, si on voit des retransmissions, ou la fenêtre TCP se réduire, on peut en déduire que l'émetteur a vu de la congestion et a réagi. Cela implique que les routeurs analysent TCP (ce qu'ils ne font normalement pas) et gardent un état (au moins un RTT de données), ce qui serait coûteux. Mais cela dispenserait de toute modification des émetteurs. Et cela ne permet pas de triche.

Dans un routeur implémenté en logiciel, en bordure du réseau, cela pourrait être réaliste (dans un routeur de cœur traitant des milliards de paquets à la seconde, cela le serait moins). À noter que des protocoles de sécurité comme TLS ou SSH ne masquent pas TCP et ne seraient donc pas un problème pour une analyse ConEx (contrairement à IPsec avec ESP, mais qui est beaucoup moins répandu). Mais si ConEx était ainsi déployé, cela pourrait motiver certains pour tout faire passer dans un VPN qui empêcherait cette observation.

Et encoder avec ECN ? Il existe une proposition (Internet-Drafts draft-briscoe-conex-re-ecn-tcp et draft-briscoe-conex-re-ecn-motiv) d'intégration d'ECN avec ConEx, qui a l'avantage d'empêcher la triche.

L'inconvénient de l'approche précédente est de nécessiter ECN, que n'ont pas tous les récepteurs. Une approche purement ConEx à l'encodage serait d'avoir des bits dédiés à ConEx dans l'en-tête IP (ou dans un en-tête d'extension en IPv6). On peut utiliser un bit par signal ConEx (ConEx, Re-Echo-Loss, Re-Echo-ECN et Credit), ou bien essayer de profiter du fait que certains sont mutuellement exclusifs pour condenser un peu.

Un sous-problème intéressant est celui de savoir si on compte la congestion en bits ou bien en paquets ? Est-ce que la perte d'un paquet de 1 500 octets vaut celle d'un paquet de 64 octets ? La perte d'un gros paquet est-elle due à sa taille ou bien un petit paquet aurait-il été également jeté ? Certaines parties du réseau sont limitées en nombre de bits (c'est typiquement le cas des tuyaux), d'autres en nombre de paquets (c'est partiellement le cas des équipements actifs). Le RFC 7141 recommande d'utiliser plutôt les bits, le RFC 6789 suggère la même chose, au moins dans l'Internet actuel.

La section 5 du RFC décrit les composants du réseau qui auront un rôle à jouer dans ConEx (voir aussi la section 6). Les équipements intermédiaires (notamment les routeurs) d'aujourd'hui ignorent les signaux ConEx et passent les paquets tels quels (espérons qu'aucun pare-feu trop zélé ne se permettra de les bloquer). Ceux qui seront modifiés ConEx, soit des routeurs, soit des engins spécialisés (congestion policer ?) liront les signaux ConEx, les vérifieront (cf. la partie sur l'audit) et pourront agir, par exemple en shapant les émetteurs qui déclenchent de la congestion.

Les émetteurs, typiquement des machines terminales, devront voir leur code TCP/IP modifié pour émettre des signaux ConEx. A priori, ceux qui n'ont même pas encore ECN n'utiliseront pas ConEx non plus, mais ceux qui ont ECN trouveront peut-être l'ajout de ConEx intéressant.

Les récepteurs, typiquement des machines terminales, n'ont pas à être modifiés.

L'audit des signaux ConEx, pour détecter les tricheurs (pensez au RFC 3514) est évidemment essentiel (section 5.5). Si des équipements réseaux limitent le trafic des émetteurs qui déclenchent de la congestion, afin d'épargner le réseau aval, ces émetteurs auront évidemment un bon mobile pour tricher. Ils risquent de ne pas mettre les signaux ConEx. (Voir aussi la section 8, sur la sécurité.)

Comment détecter les tricheurs ? Une solution possible est de détecter les pertes de paquets et de voir si l'émetteur envoie bien des Re-Echo-Loss. Mais attention : rien ne dit que l'auditeur voit tous les paquets d'un flot. Si le trafic passe par deux liens différents, l'auditeur situé sur un des liens risque de ne pas voir certains paquets et croire à tort qu'ils sont perdus.

Les signaux ECN peuvent aussi servir à l'audit. Pour être sûr de les voir, il faut être en aval des points où il y a congestion.

Une autre solution est d'utiliser les retransmissions de TCP. Si l'émetteur réémet, c'est que que paquets ont été perdus. Là, il vaut mieux être proche de l'émetteur (donc le plus en amont possible), pour être sûr de voir tous ses paquets, même en cas de chemins multiples dans le réseau.

Le routeur qui doit jeter des paquets (ou les marquer avec ECN) car il n'arrive plus à tout transmettre est aussi un bon endroit pour faire de l'audit : il peut directement comparer ce qu'il fait (jeter les paquets d'un flot donné) avec l'apparition, un RTT plus tard, des signaux ConEx.

La thèse de B. Briscoe (un des auteurs du RFC), « Re-feedback: Freedom with Accountability for Causing Congestion in a Connectionless Internetwork » contient une analyse détaillée de toutes les techniques de triche, et d'audit, connues.


Téléchargez le RFC 7713


L'article seul

RFC 7710: Captive-Portal Identification Using DHCP or Router Advertisements (RAs)

Date de publication du RFC : Décembre 2015
Auteur(s) du RFC : W. Kumari (Google), O. Gudmundsson (CloudFlare), P. Ebersman (Comcast), S. Sheng (ICANN)
Chemin des normes
Première rédaction de cet article le 14 décembre 2015


Les portails captifs sont une des plaies de l'accès à l'Internet. À défaut de pouvoir les supprimer, ce nouveau RFC propose des options aux protocoles DHCP et RA pour permettre de signaler la présence d'un portail captif, au lieu que la malheureuse machine doive le détecter elle-même. depuis, il a été remplacé par le RFC 8910.

On trouve de tels portails captifs en de nombreux endroits où de l'accès Internet est fourni, par exemple dans des hôtels ou des cafés. Tant que l'utilisateur ne s'est pas authentifié auprès du portail captif, ses capacités d'accès à l'Internet sont très limitées. Quels sont les problèmes que pose un portail captif ?

  • Le plus important est qu'il détourne le trafic normal : en cela, le portail captif est une attaque de l'Homme du Milieu et a donc de graves conséquences en terme de sécurité. Il éduque les utilisateurs à trouver normal le fait de ne pas arriver sur l'objectif désiré, et facilite donc le hameçonnage.
  • Le portail captif ne marche pas ou mal si la première connexion est en HTTPS, ce qui est de plus en plus fréquent. Là encore, il éduque les utilisateurs à trouver normaux les avertissements de sécurité (« mauvais certificat, voulez-vous continuer ? »).
  • Le portail captif n'est pas authentifié, lui, et l'utilisateur est donc invité à donner ses informations de créance à un inconnu.
  • En Wifi, comme l'accès n'est pas protégé par WPA, le trafic peut être espionné par les autres utilisateurs.
  • Spécifique au Web, le portail captif ne marche pas avec les activités non-Web (comme XMPP). Même les clients HTTP non-interactifs (comme une mise à jour du logiciel via HTTP) sont affectés.

Pourquoi est-ce que ces hôtels et cafés s'obstinent à imposer le passage par un portail captif ? On lit parfois que c'est pour authentifier l'utilisateur mais c'est faux. D'abord, certains portails captifs ne demandent pas d'authentification, juste une acceptation des conditions d'utilisation. Ensuite, il existe une bien meilleure solution pour authentifier, qui n'a pas les défauts indiqués plus haut. C'est 802.1X, utilisé entre autres dans eduroam (voir RFC 7593). La vraie raison est plutôt une combinaison d'ignorance (les autres possibilités comme 802.1X ne sont pas connues) et de désir de contrôle (« je veux qu'ils voient mes publicités et mes CGU »).

L'IETF travaille à développer un jour un protocole complet d'interaction avec les portails captifs, pour limiter leurs conséquences. En attendant, ce RFC propose une option qui permet au moins au réseau local de signaler « attention, un portail captif est là, ne lance pas de tâches - comme Windows Update - avant l'authentification ». Cette option peut être annoncée par le serveur DHCP (RFC 2131 et RFC 8415) ou par le routeur qui envoie des RA (RFC 4861).

Cette option (section 2 du RFC) annonce au client qu'il est derrière un portail captif et lui fournit l'URI de la page d'authentification (ce qui évite d'être détourné, ce qui est grave quand on utilise HTTPS). Dans cet URI, le serveur HTTP doit être désigné par son adresse IP, pour éviter d'avoir à faire du mensonge DNS.

Les sections 2.1, 2.2 et 2.3 de notre RFC donnent le format de l'option en DHCP v4, DHCP v6 et en RA. Le code DHCP v4 est 160 (qui était malheureusement squatté, ce qui a nécessité son changement dans le RFC 8910), le DHCP v6 est 103 et le type RA est 37.

La section 4 de notre RFC étudie les conséquences de cette option pour la sécurité. Elle rappelle que DHCP et RA ne sont pas sécurisés, de toute façon. Donc, un méchant peut envoyer une fausse option « il y a un portail captif, allez à cet URI pour vous authentifier » mais le même méchant peut aussi bien annoncer un faux routeur...

Il est même possible que cette option nouvelle améliore la sécurité, en n'encourageant pas les utilisateurs à couper les mécanismes de validation comme la vérification des certificats, contrairement à ce que font les portails captifs actuels.

Pour DHCP, la plupart des serveurs permettent de servir une option quelconque, en mettant ses valeurs manuellement et une future mise à jour ne servira donc qu'à rendre l'usage de cette option plus simple. Autrement, il n'existe pas encore de mise en œuvre côté clients DHCP ou RA. (Pour des nouvelles plus récentes, voir le RFC 8910.)


Téléchargez le RFC 7710


L'article seul

RFC 7707: Network Reconnaissance in IPv6 Networks

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : F. Gont (Huawei Technologies), T. Chown (University of Southampton)
Pour information
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 11 mars 2016


Soit un pauvre petit réseau innocent, et un méchant attaquant qui va essayer de faire subir les derniers outrages au réseau en question. L'attaquant commence souvent par une phase de reconnaissance, où il cherche à améliorer sa connaissance du réseau visé. Un outil souvent utilisé dans cette phase est le balayage (scanning) systématique du réseau, à la recherche d'adresses IP de machines à attaquer. En IPv6, contrairement à IPv4, la tâche semble colossale, vu le nombre d'adresses IP possibles. Mais, comme l'avait déjà noté le RFC 5157, cette tâche n'est pas impossible. Ce nouveau RFC fait le point sur le balayage IPv6 et détaille les techniques utilisables.

Comme exemple de la différence de situation entre IPv4 et IPv6, prenons un réseau local typique. La densité de machines (nombre de machines réellement présentes par rapport au nombre d'adresses possibles) est bien inférieure en IPv6. Sur un /26 IPv4, on a 62 adresses théoriquement possibles et la plupart correspondront sans doute effectivement à une machine. Balayer ce /26 est à la fois très rapide et très avantageux. En IPv6, un simple /64 permet d'avoir plus de 10^19 adresses (c'est bien la principale motivation pour déployer IPv6 : avoir davantage d'adresses). Même si on a bien plus de machines, la densité sera infime. Si les adresses étaient attribuées au hasard et que le balayage se fasse également au hasard, les chances de tomber sur une machine réelle sont quasi-nulles. Heureusement pour l'attaquant, les adresses réelles ne sont pas attribuées au hasard, et le balayage n'est pas forcément fait au hasard. Ce nouveau RFC, deux fois plus long que l'ancien (le RFC 5157) fait le point sur ce que les défenseurs et les attaquants doivent savoir sur le balayage en IPv6.

Avant de tester, installons l'outil de balayage scan6, distribué avec le SI6 toolkit (et déjà utilisé dans mon article sur les attaques en IPv6) :

% wget http://www.si6networks.com/tools/ipv6toolkit/ipv6toolkit-v2.0.tar.gz
% tar xzvf ipv6toolkit-v2.0.tar.gz
% cd ipv6toolkit-v2.0
% make

C'est parti, en commençant par les techniques les plus classiques (section 3 de notre RFC). D'abord, lorsque le réseau visé configure les adresses IP avec le SLAAC du RFC 4862. Le SLAAC fonctionne en concaténant un préfixe appris du routeur avec un suffixe, l'IID (Interface IDentifier). Comment la machine choisit-elle son IID ? Il existe plusieurs techniques, qui ont des conséquences sur la facilité de balayage. Par exemple, une technique courante (mais de moins en moins employée) est de fabriquer l'IID à partir de l'adresse MAC de la machine, en mettant juste le bit 6 à 1 et en ajoutant au milieu 0xfffe. Ainsi, mon adresse MAC 38:59:f9:7d:b6:47 me donne actuellement une adresse IPv6 de 2003:88:6c71:c7f8:3a59:f9ff:fe7d:b647 (préfixe 2003:88:6c71:c7f8 chez Deutsche Telekom et IID 3a59:f9ff:fe7d:b647). A priori, il y a 64 bits possibles pour l'IID. Mais ce n'est pas tout à fait vrai. D'abord, 16 sont fixes (le 0xfffe). Ensuite, les 24 premiers bits identifient le vendeur de la carte via son OUI (sauf si, comme dans l'exemple ci-dessus, on a changé son adresse MAC...) Tous les OUI possibles n'étant pas encore affectés, cela réduit le champ de recherche. Et ceux qui sont affectés le sont souvent pour du matériel qui n'est plus fabriqué, réduisant encore ce champ. Enfin, un attaquant malin observera qu'une organisation donnée a souvent un parc matériel homogène (par exemple uniquement des ordinateurs Dell). Cela permet de réduire encore l'espace de recherche (option --tgt-vendor de scan6). En outre, si les machines ont été achetées en même temps, il est tout à fait possible qu'elles fassent partie du même lot et que leurs adresses MAC soient consécutives. Une fois qu'on en a trouvé une, on peut supposer que les autres sont proches.

Un cas particulier est celui des techniques de virtualisation. Par exemple, VirtualBox utilise l'OUI 08:00:27 et, avec le 0xfffe du milieu, cela fait que l'espace de recherche réel n'est que de 24 bits, bien moins que les 64 théoriques. VMware est encore pire, pour ses adresses MAC automatiques : l'OUI est 00:05:69, 16 bits sont tirés de l'adresse IPv4 de la console, 8 bits sont un condensat du nom du fichier de configuration. Il peut donc n'y avoir que 8 bits à chercher ! (Les adresses MAC manuelles de VMware ont 22 bits variables.)

Et les adresses temporaires du RFC 8981, n'avaient-elles pas été conçues justement pour éviter qu'on suive à la trace une machine ? L'IID est cette fois aléatoire, et change souvent (par exemple une fois par jour). Ces adresses temporaires sont une très bonne chose, mais elles ont quelques limites. D'abord, elles viennent en plus des adresses classiques, auxquelles la machine répond toujours. Les adresses temporaires étant utilisées pour les connexions sortantes, le risque de fuite de l'adresse globale permanente est plus faible mais elles n'empêchent pas le balayage, avec les techniques données plus haut.

C'est en partie pour combler les faiblesses des adresses temporaires que les adresses du RFC 7217 ont été développées. L'IID est un condensat de certaines caractéristiques de la machine et du réseau. Ces adresses sont stables tant que la machine ne change pas de réseau (ce qui permet de n'utiliser que ces adresses et d'oublier les adresses globales classiques). Du point de vue de la vie privée, elles représentent la meilleure solution, et devraient être systématiquement utilisées. Pour l'instant, comme l'indique « IPv6 Address Analysis - Privacy In, Transition Out », la grande majorité des clients IPv6 utilisent les adresses temporaires du RFC 8981 (et 7 % utilisent encore les adresses MAC).

Et DHCP ? La politique d'allocation des adresses dépend du serveur DHCP. Parfois, elle mène à des adresses prévisibles, mais pas toujours. Par exemple, si on configure un serveur DHCP pour allouer des adresses dans la plage 2001:db8:a35:b24::/64, et que le serveur DHCP décide qu'une allocation séquentielle (2001:db8:a35:b24::1 puis 2001:db8:a35:b24::2, puis 2001:db8:a35:b24::3...) est la meilleure solution, alors les adresses seront prévisibles. C'est pour cela que le RFC 5157 conseillait aux serveurs DHCP d'allouer au hasard à partir de la plage d'adresses configurée et ce conseil est répété ici.

Et les adresses attribuées manuellement, par l'administrateur système ? C'est utile pour les routeurs (qui ne peuvent pas utiliser SLAAC) et les serveurs (qui ne cherchent pas à se cacher, et pour qui il est très souhaitable d'avoir une adresse IP stable). En théorie, l'administrateur système peut choisir l'IID librement parmi 2^64 valeurs. En pratique, on observe que ces IID ne sont pas choisis au hasard mais que les ingénieurs suivent un de ces quatre schémas, utilisant :

  • Un nombre de faible valeur (schéma dit low byte) : PREFIX::1, PREFIX::2, etc. L'option --tgt-low-byte de scan6 permet de tester en premier ces valeurs. Dans le cas le plus simple, il suffit de tester les 256 valeurs correspondant aux huits bits finaux (certaines variantes de ce schéma utilisent les deux ou trois derniers octets, ce qui rend le balayage un peu plus long). Ce schéma est de loin le plus fréquent pour les serveurs et les routeurs (voir « IPv6 Network Reconnaissance: Theory & Practice », cité en section 3.1.5).
  • Une adresse IPv4, en profitant de ce que la représentation texte d'une adresse IPv6 peut se terminer par une adresse IPv4, comme dans 2001:db8:88:12a::192.0.2.21. Balayer ces adresses revient à balayer l'espace IPv4 correspondant (option --tgt-ipv4, de scan6).
  • Un numéro de port, le serveur DNS sera PREFIX::53, le serveur IMAP PREFIX::993, etc. Le cas le plus simple (numéro de port dans le dernier octet) est très rapide à balayer (option --tgt-port de scan6, il n'y a que quelques dizaines de ports populaires), certaines variantes sont un peu plus lentes.
  • Un terme amusant en hexspeak comme ::dead:beef ou ::a11. Balayer ces termes se fait à partir d'un dictionnaire.

Bon, armés de ces connaissances, voyons maintenant concrètement comment balayer un réseau. D'abord, un réseau distant (section 3.2). Un balayage par la force brute est impossible en IPv6 : un seul /64 peut avoir dans les 10^20 machines, ce qui, même à un million de paquets par seconde, prendrait trois millions d'années à examiner. Un balayeur IPv6 doit donc être plus astucieux que la force brute et exploiter les propriétés des adresses IPv6, qui font que l'espace réel à explorer est plus réduit que l'espace théorique. Ainsi, en balayant dans l'ordre, de PRÉFIXE:: puis PRÉFIXE::1, PRÉFIXE::2, etc, on tire profit des adressses de faible valeur. De même, on peut deviner le plan d'adresssage et utiliser les adresses IPv4 du réseau, les numéros des bâtiments, etc.

À noter que le balayage peut aussi être utilisé pour faire une attaque par déni de service. Certaines mises en œuvres d'IPv6 gèrent mal leur cache NDP et un grand nombre de requêtes pour des machines inexistantes peut planter certains routeurs IPv6 (RFC 6583).

Revenons au balayage fait dans le but de découvrir des adresses actives. Si on balaye le réseau local, celui où on se trouve, il y a encore d'autres possibilités, notamment les adresses multicast. Par exemple, en envoyant un seul paquet à l'adresse multicast ff02::1, on récupère plein de machines :

% ping6 -I eth0 ff02::1
PING ff02::1(ff02::1) from fe80::e349:a3a5:ad58:a21 eth0: 56 data bytes
64 bytes from fe80::e349:a3a5:ad58:a21: icmp_seq=1 ttl=64 time=0.250 ms
64 bytes from fe80::21e:8cff:fe76:29b6: icmp_seq=1 ttl=64 time=1.17 ms (DUP!)
64 bytes from fe80::f6ca:e5ff:fe4d:1f41: icmp_seq=1 ttl=64 time=4.96 ms (DUP!)
64 bytes from fe80::ce0d:dad3:6bc2:6da4: icmp_seq=1 ttl=64 time=4.96 ms (DUP!)
...
 

Ça ne marche pas avec les machines Windows, qui ne répondent pas à ce ping. Mais il y a d'autres astuces comme d'envoyer à cette adresse multicast un paquet IPv6 ayant une option inconnue et dont le type commence par 10 (qui signifie « si cette option n'est pas connue, jeter le paquet et envoyer une erreur ICMP », cf. RFC 2460, section 4.2). Windows répondra alors par un message ICMP Parameter problem. Voici le résultat de scan6 vu avec tcpdump, montrant cette technique :

19:01:06.204431 IP6 fe80::e349:a3a5:ad58:a21 > ff02::1: DSTOPT ICMP6, echo request, seq 34994, length 64
19:01:06.205469 IP6 fe80::21e:8cff:fe76:29b6 > fe80::e349:a3a5:ad58:a21: ICMP6, parameter problem, option - octet 42, length 120
19:01:06.214792 IP6 fe80::ba27:ebff:feaa:78b9 > fe80::e349:a3a5:ad58:a21: ICMP6, parameter problem, option - octet 42, length 120
...

Ces techniques ne sont pas purement théoriques. Certes, un outil comme nmap sait faire du balayage en IPv4 mais pas en IPv6 à distance, mais d'autres outils existent. Ces techniques sont mises en œuvre dans l'outil scan6 du SI6 toolkit, cité plus haut. Une fois compilé et installé, on peut utiliser cet outil pour découvrir ses voisins (sur le même réseau local) :

 % sudo scan6 -L -i eth0
 ...
2a01:f23:a65:6721:21e:8cff:fe76:29b6
2a01:f23:a65:6721::1
2a01:f23:a65:6721:666:6c7c:9bed:b390
2a01:f23:a65:6721:b5a5:dfd6:4e7b:2584
... 
 

Ou bien tester un réseau distant :

% sudo scan6 -d 2001:7b2:dc0:41::/64
2001:7b2:dc0:41::250
...
 

Le dernier exemple ci-dessus est évidemment complètement irréaliste (balayage d'un /64 en force brute), même si ici on a trouvé tout de suite une machine « low-byte ». Ne soyez pas trop optimiste : scan6, livré à lui-même, est très lent et vous trouverez rarement quelque chose. Un balayage d'un site où on connait le vendeur des cartes Ethernet (et donc l'OUI) :

 %  sudo scan6 --tgt-ieee-oui b8:27:eb -d 2001:db8:8469:a30::/64 -i eth0 -e print-global  
 

prend de très nombreuses heures et risque fortement d'être détecté. En pratique, pour utiliser scan6 avec succès, il faut récolter beaucoup d'informations sur le réseau qui vous intéresse, et guider scan6 en lui mettant beaucoup d'options. Un projet intéressant serait de tenter d'automatiser cette phase heuristique.

Une des conséquences de la difficulté de balayer en IPv6 est que la gestion de réseaux devient plus compliquée. L'administrateur réseaux ne peut pas découvrir facilement tout ce qui a été branché et fonctionne sur son réseau. Il doit donc changer ses pratiques. Une des approches, pour connaitre tout son réseau, est l'écoute passive, avec ndpmon, qui permet de se constituer automatiquement une base des machines et de leur adresse MAC.

Et l'administrateur réseaux qui veut défendre son réseau et limiter le balayage, que peut-il faire (section 3.5 du RFC) ? Il existe plusieurs techniques qui aident, en rendant les adresses moins prévisibles :

  • Utiliser les adresses stables mais opaques du RFC 7217. (Au passage, je ne connais pas encore de système d'exploitation où ce soit facile ou même possible.)
  • Utiliser un IDS pour détecter (ou un IPS pour bloquer) : les balayages IPv6 ne peuvent pas être faits discrètement, ils allument les systèmes d'alarme comme un arbre de Noël.
  • Peut-être filtrer certains types de paquets (avec prudence : voir le RFC 4890).
  • Configurer manuellement les adresses MAC (par exemple avec macchanger). Ainsi, même si les adresses IPv6 son dérivées de l'adresse MAC, elles ne seront plus prévisibles.
  • Si on utilise DHCP, configurer le serveur DHCP pour allouer dans un ordre aléatoire, et pas bêtement en partant de 1. (Je n'ai pas regardé les possibilités des serveurs DHCP actuels.)

Ces solutions ne sont pas parfaites. Consolez-vous avec l'idée que la sécurité de vos machines ne doit de toute façon pas dépendre uniquement de la résistance de votre réseau au balayage. Tôt ou tard, l'attaquant découvrira vos adresses IP, et les machines doivent donc être préparées à tout.

Le balayeur n'utilisera pas que des techniques de couche 3 comme décrit dans la précédente section, la section 3 du RFC. Il peut aussi se servir, par exemple, du DNS (section 4). Par exemple, s'il est possible de récupérer la zone DNS, le balayeur obtient beaucoup d'adresses IPv6. Mais il peut aussi tester des noms communs dans le DNS et obtenir ainsi des adresses (et, si votre algorithme d'allocation est prévisible, un petit nombre d'adresses lui permettra d'en déduire d'autres). Un tel balayage est facile à automatiser.

Mieux (du point de vue de l'attaquant), on peut énumérer les enregistrements PTR dans votre sous-arbre de ip6.arpa. (C'est automatisable, avec l'outil dnsrevenum6, qui fait partie de la boîte à outils THC.)

Outre le DNS classique, mDNS (RFC 6762) peut également aider (section 5) : des requêtes envoyées à la cantonade peuvent découvrir des machines qui se signaleraient imprudemment.

L'attaquant en mission de reconnaissance peut aussi utiliser des archives publiques (section 6). Par exemple, une liste de diffusion dont les messages seraient stockées intégralement, y compris les en-têtes Received:, qui contiennent souvent des adresses IP. Difficile d'être discret sur l'Internet !

Certaines applications peuvent également aider l'attaquant à récolter des adresses IP (section 7). Par exemple, BitTorrent ne fait aucun effort pour dissimuler l'adresse du pair avec qui on échange des fichiers. Même chose avec NTP, si les machines de votre réseau local se synchronisent directement à l'extérieur, ce qui les rend visibles à Shodan.)

On trouve également des adresses IP dans les caches NDP (section 8) - et ces caches peuvent parfois être examinés à distance avec SNMP (section 13), dans les journaux (gérer un serveur Web populaire permet d'en récolter beaucoup, cf. section 9), via les protocoles de routage (section 10), via traceroute (section 12)... Au passage, il est recommandé de lire l'excellent article de Bellovin, S., Cheswick, B., et A. Keromytis, « Worm propagation strategies in an IPv6 Internet » dans login: en 2006.

L'annexe A du RFC décrit une mise en œuvre des principales idées expliquées dans ce document. Si vous voulez tous les détails techniques sur le balayage en IPv6, c'est le texte à lire. Il faut par exemple être prudent : un balayage exhaustif en IPv6 peut nécessiter un nombre colossal de paquets et, si on les envoie trop vite, l'augmentation du trafic vous fera repérer (variante : vous surchargerez le réseau, des paquets seront perdsu et vous raterez ainsi des réponses). Cette annexe couvre également les méthodes de dissimulation, pour éviter d'être détecté (avec la plupart des IDS IPv6, il suffit d'ajouter des en-têtes d'extension au paquet). Le tout est évidemment très inspiré de l'expérience de l'un des auteurs du RFC avec l'outil scan6, déjà cité.

Je ne fais pas ici un résumé des différences avec son prédécesseur, le RFC 5157, car il y en a beaucoup trop (notre nouveau RFC est bien plus détaillé).


Téléchargez le RFC 7707


L'article seul

RFC 7706: Decreasing Access Time to Root Servers by Running One on Loopback

Date de publication du RFC : Novembre 2015
Auteur(s) du RFC : W. Kumari (Google), P. Hoffman (ICANN)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 26 novembre 2015


Toute résolution DNS commence par la racine (de l'arbre des noms de domaine). Bien sûr, la mémorisation (la mise en cache) des réponses fait qu'on n'a pas besoin tout le temps de contacter un serveur racine. Mais c'est quand même fréquent et les performances de la racine sont donc cruciales. L'idée documentée dans ce RFC est donc d'avoir en local un serveur esclave de la racine, copiant celle-ci et permettant donc de répondre localement aux requêtes. Notez que ce RFC a depuis été remplacé par le RFC 8806.

Le problème est particulièrement important pour les noms qui n'existent pas. Si les TLD existants comme .com ou .fr vont vite se retrouver dans la mémoire (le cache) du résolveur DNS, les fautes de frappe ou autres cas où un TLD n'existe pas vont nécessiter la plupart du temps un aller-retour jusqu'au serveur racine le plus proche. Les réponses négatives seront également mémorisées mais 1) il y a davantage de noms non existants que de noms existants 2) le TTL est plus court (actuellement deux fois plus court). Ces noms non existants représentent ainsi la majorité du trafic de la racine.

Bien qu'il existe aujourd'hui des centaines de sites dans le monde où se trouve une instance d'un serveur racine, ce nombre reste faible par rapport au nombre total de réseaux connectés à l'Internet. Dans certains endroits de la planète, le serveur racine le plus proche est assez lointain. Voici les RTT en millisecondes avec les serveurs racine observés depuis un réseau tunisien (notez les deux serveurs qui répondent bien plus vite que les autres, car ils ont une instance à Tunis) :

% check-soa -4 -i .
a.root-servers.net.
	198.41.0.4: OK: 2015112501 (54 ms)
b.root-servers.net.
	192.228.79.201: OK: 2015112501 (236 ms)
c.root-servers.net.
	192.33.4.12: OK: 2015112501 (62 ms)
d.root-servers.net.
	199.7.91.13: OK: 2015112501 (23 ms)
e.root-servers.net.
	192.203.230.10: OK: 2015112501 (18 ms)
f.root-servers.net.
	192.5.5.241: OK: 2015112501 (69 ms)
g.root-servers.net.
	192.112.36.4: OK: 2015112501 (62 ms)
h.root-servers.net.
	128.63.2.53: OK: 2015112501 (153 ms)
i.root-servers.net.
	192.36.148.17: OK: 2015112501 (67 ms)
j.root-servers.net.
	192.58.128.30: OK: 2015112501 (55 ms)
k.root-servers.net.
	193.0.14.129: OK: 2015112501 (72 ms)
l.root-servers.net.
	199.7.83.42: ERROR: Timeout
m.root-servers.net.
	202.12.27.33: OK: 2015112501 (79 ms)
    

Ces délais peuvent sembler courts mais ils ne forment qu'une partie du travail de résolution, il est donc légitime de vouloir les réduire encore.

En outre, ces requêtes à la racine peuvent être observées, que ce soit par les opérateurs de serveurs racine, ou par des tiers sur le projet, ce qui n'est pas forcément souhaitable, question vie privée (cf. RFC 7626).

Donc, l'idée de base de ce RFC est de :

  • Mettre un serveur esclave de la racine sur sa machine, écoutant sur l'adresse locale (loopback),
  • Configurer le résolveur pour interroger d'abord ce serveur.

Cette idée est documentée dans ce RFC mais n'est pas encouragée (c'est un très vieux débat, dont j'avais déjà parlé). En effet, cela ajoute un composant à la résolution (le serveur local faisant autorité pour la racine), composant peu ou pas géré et qui peut défaillir, entrainant ainsi des problèmes graves et difficiles à déboguer. Mais pourquoi documenter une idée qui n'est pas une bonne idée ? Parce que des gens le font déjà et qu'il vaut mieux documenter cette pratique, et en limiter les plus mauvais effets. C'est pour cela, par exemple, que notre RFC demande que le serveur local n'écoute que sur les adresses locales, pour limiter les conséquences d'une éventuelle défaillance à une seule machine.

Dans tous les cas, le RFC recommande que la configuration décrite ici ne soit pas celle par défaut : l'utilisateur doit l'activer explicitement (et en supporter les conséquences).

Pas découragé ? Vous voulez encore le faire ? Alors, les détails pratiques. D'abord (section 2 du RFC), les pré-requis. DNSSEC est indispensable (pour éviter de se faire refiler un faux fichier de zone par de faux serveurs racine). Ensuite (section 3), vous mettez un serveur faisant autorité (par exemple NSD ou Knot) qui écoute sur une des adresses locales (en 127.0.0.0/8, IPv6 est moins pratique car il ne fournit paradoxalement qu'une seule adresse locale à la machine) et qui est esclave des serveurs racine. À noter que votre serveur, n'étant pas connu des serveurs racine, ne recevra pas les notifications (RFC 1996) et sera donc parfois un peu en retard sur la vraie racine (ce qui n'est pas très grave, elle bouge peu).

Il est important de lister plusieurs serveurs maîtres dans sa configuration. En effet, si la mise à jour de la racine dans votre serveur esclave échoue, ce sera catastrophique (signatures DNSSEC expirées, etc) et cette configuration locale, contrairement à la « vraie » racine, n'a aucune redondance. (Une autre raison pour laquelle ce n'est pas une idée géniale.) Quels serveurs maîtres indiquer ? Certains serveurs racine permettent le transfert de zone (RFC 5936) mais ce n'est jamais officiel, ils peuvent cesser à tout moment (l'annexe A du RFC donne une liste et discute de ce choix). Une raison de plus de se méfier.

Il est donc important d'avoir un mécanisme de supervision, pour être prévenu si quelque chose échoue. On peut par exemple interroger le numéro de série dans l'enregistrement SOA de la racine et vérifier qu'il change.

Ensuite, une fois ce serveur faisant autorité configuré, il ne reste qu'à indiquer à un résolveur (comme Unbound) de l'utiliser (section 4 du RFC).

Voici un exemple, pris dans l'annexe B du RFC et testé. J'ai choisi l'exemple avec NSD et Unbound mais il y en a d'autres dans le RFC. D'abord, la configuration de NSD (notez la longue liste de maîtres, pour maximiser les chances que l'un d'eux fonctionne ; notez aussi l'adresse loopback choisie, 127.12.12.12) :

# RFC 7706
server:
       ip-address: 127.12.12.12
zone:
       name: "."
       request-xfr: 192.228.79.201 NOKEY # b.root-servers.net
       request-xfr: 192.33.4.12 NOKEY    # c.root-servers.net
       request-xfr: 192.5.5.241 NOKEY    # f.root-servers.net
       request-xfr: 192.112.36.4 NOKEY   # g.root-servers.net
       request-xfr: 193.0.14.129 NOKEY   # k.root-servers.net
       request-xfr: 192.0.47.132 NOKEY   # xfr.cjr.dns.icann.org
       request-xfr: 192.0.32.132 NOKEY   # xfr.lax.dns.icann.org
       request-xfr: 2001:500:84::b NOKEY # b.root-servers.net
       request-xfr: 2001:500:2f::f NOKEY # f.root-servers.net
       request-xfr: 2001:7fd::1 NOKEY    # k.root-servers.net
       request-xfr: 2620:0:2830:202::132 NOKEY  # xfr.cjr.dns.icann.org
       request-xfr: 2620:0:2d0:202::132 NOKEY  # xfr.lax.dns.icann.org  

Le démarrage de NSD (notez qu'il faut patienter un peu la première fois, le temps que le premier transfert de zone se passe) :

Nov 25 19:50:43 machine-locale nsd[2154]: [2015-11-25 19:50:43.791] nsd[2175]: notice: nsd started (NSD 4.1.2), pid 2154
Nov 25 19:50:56 machine-locale nsd[2154]: zone . serial 0 is updated to 2015112501.
Nov 25 19:50:56 machine-locale nsd[2154]: [2015-11-25 19:50:56.166] nsd[2154]: info: zone . serial 0 is updated to 2015112501.

C'est bon, on a transféré la zone. Testons (notez le bit AA - Authoritative Answer - dans la réponse) :


% dig  @127.12.12.12 SOA . 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61984
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 14, ADDITIONAL: 25
...
;; ANSWER SECTION:
.			86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. (
				2015112501 ; serial
... 

C'est bon.

Maintenant, la configuration d'Unbound (prise dans le RFC) :

server:
    # RFC 7706
    do-not-query-localhost: no
    
# RFC 7706
# Requires a slave auth. running (normally, nsd)
stub-zone:
       name: "."
       stub-prime: no
       stub-addr: 127.12.12.12

Et le test :


% dig www.cnam.fr
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23562
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 3
...
;; ANSWER SECTION:
www.cnam.fr.		0 IN CNAME sarek.cnam.fr.
sarek.cnam.fr.		86400 IN A 163.173.128.52

Ça a marché. Avec tcpdump, on voit le trafic (faible, en raison du cache) vers le serveur racine local :

08:37:24.869569 IP (tos 0x0, ttl 64, id 7734, offset 0, flags [none], proto UDP (17), length 76)
    127.0.0.1.10908 > 127.12.12.12.53: 42633% [1au] A? www.tunisair.com.tn. (48)
08:37:24.869671 IP (tos 0x0, ttl 64, id 12657, offset 0, flags [none], proto UDP (17), length 685)
    127.12.12.12.53 > 127.0.0.1.10908: 42633- 0/8/13 (657)
08:38:04.734565 IP (tos 0x0, ttl 64, id 12887, offset 0, flags [none], proto UDP (17), length 71)
    127.0.0.1.45221 > 127.12.12.12.53: 25787% [1au] A? www.edreams.es. (43)
08:38:04.734645 IP (tos 0x0, ttl 64, id 19270, offset 0, flags [none], proto UDP (17), length 749)
    127.12.12.12.53 > 127.0.0.1.45221: 25787- 0/10/14 (721)
08:38:04.734867 IP (tos 0x0, ttl 64, id 12888, offset 0, flags [none], proto UDP (17), length 70)
    127.0.0.1.40575 > 127.12.12.12.53: 61589% [1au] AAAA? ns-ext.nic.cl. (42)
08:38:04.734932 IP (tos 0x0, ttl 64, id 19271, offset 0, flags [none], proto UDP (17), length 622)
    127.12.12.12.53 > 127.0.0.1.40575: 61589- 0/8/11 (594)
08:44:00.366698 IP (tos 0x0, ttl 64, id 27563, offset 0, flags [none], proto UDP (17), length 62)
    127.0.0.1.22009 > 127.12.12.12.53: 30565% [1au] A? po.st. (34)
08:44:00.389126 IP (tos 0x0, ttl 64, id 34039, offset 0, flags [none], proto UDP (17), length 404)
    127.12.12.12.53 > 127.0.0.1.22009: 30565- 0/6/5 (376)
08:44:01.229635 IP (tos 0x0, ttl 64, id 27693, offset 0, flags [none], proto UDP (17), length 69)
    127.0.0.1.65173 > 127.12.12.12.53: 32911% [1au] AAAA? ns3.perf1.eu. (41)
08:44:01.229705 IP (tos 0x0, ttl 64, id 34207, offset 0, flags [none], proto UDP (17), length 560)
    127.12.12.12.53 > 127.0.0.1.65173: 32911- 0/8/10 (532)
    

À noter qu'il existe un brevet futile (comme tous les brevets...) de Verisign sur cette technique : déclaration #2539 à l'IETF.


Téléchargez le RFC 7706


L'article seul

RFC 7704: An IETF with Much Diversity and Professional Conduct

Date de publication du RFC : Novembre 2015
Auteur(s) du RFC : D. Crocker (Brandenburg InternetWorking), N. Clark (Pavonis Consulting)
Pour information
Première rédaction de cet article le 12 décembre 2015


La question de la diversité dans les organisations qui contribuent d'une manière ou d'une autre au bon fonctionnement de l'Internet a souvent été discutée. Un simple coup d'œil à une réunion IETF permet de voir de nets déséquilibres (peu de femmes, peu de gens originaires d'Afrique ou d'Amérique Latine...). Comme le dit le résumé de ce nouveau RFC : « a small group of well-funded, American, white, male technicians ». Même si ce résumé est exagéré, et si le mécanisme ouvert de l'IETF a largement prouvé son efficacité, il n'est pas interdit de creuser la question « comment accroitre la diversité ? », dans l'espoir d'augmenter encore cette efficacité. (Un tel document suscitera forcément des controverses. Par exemple, personnellement, il me semble que la diversité est plutôt une question de justice - faire sauter les éventuelles discriminations - que d'une supposée meilleure efficacité.)

L'état actuel d'une organisation dépend évidemment de son histoire (section 1 du RFC). L'IETF est née d'un effort commencé à la fin des années 1960, et financé par l'ARPA. Au début, il n'y avait donc que des États-Uniens. La participation s'est ensuite étendue à d'autres milieux aux États-Unis, comme ceux financés par la NSF et non plus l'ARPA. À la création formelle de l'IETF, à la fin des années 1980, le projet a été complètement ouvert. Tout le monde peut participer, sans distinction de genre, de nationalité ou de couleur de peau, au moins en théorie.

L'IETF est à juste titre fière du résultat : le processus ouvert s'est avéré particulièrement efficace, permettant aux protocoles TCP/IP d'être très largement déployés, à la place des protocoles conçus par des SDO traditionnelles et fermées. Mais rien n'est éternel et on ne peut évidemment pas garantir que l'IETF gardera éternellement cette ouverture. Une « vigilance citoyenne » permanente est donc nécessaire.

La culture spécifique de l'IETF est née. Elle se caractérise par une grande franchise dans les discussions, loin de l'hypocrisie de beaucoup d'organisations, où on n'affiche jamais ouvertement les désaccords. Comme toute chose peut être vue de deux façons différentes, le RFC parle non pas de franchise mais de « singularly aggressive behavior, including singularly hostile tone and content ». Il ajoute que ce style n'est pas « professionnel », un terme très curieux, comme si l'aggressivité était le privilège des amateurs... Ce qui est sûr, c'est que ce style, qui allait bien aux participants du début, peut être un problème pour la diversité. Un comportement qui serait considéré « un peu trop direct » aux Pays-Bas peut être vu comme « très impoli » au Japon. (Le RFC parle de « more polite cultures », qui peuvent se sentir mal à l'aise face au style franc et direct de l'IETF.)

La section 2 du RFC décrit ensuite pourquoi le manque de diversité est un problème. D'abord, précisons que tous les attributs sont concernés, le genre, la nationalité, la religion, l'orientation sexuelle, etc. Cette section reprend l'idée que des groupes divers prennent des meilleures décisions (en citant, c'est amusant, uniquement des études états-uniennes, et presque toutes limitées au monde du management capitaliste, comme « Better Decisions Through Diversity: Heterogeneity can boost group performance »).

La question de la diversité étant ancienne, il n'est pas étonnant que le débat sur les solutions le soit aussi, et que de nombreuses techniques aient déjà été proposées, et expérimentées. Par exemple, le RFC note que des mesures purement statistiques, comme des quotas, peuvent être difficile à mettre en œuvre dans des groupes restreints. S'il y a deux Area Directors pour la Routing Area de l'IETF, ils ou elles ne peuvent pas représenter à eux deux toute la diversité souhaitée. En outre, le but est la diversité, pas juste des nombres appliqués aveuglément (avoir X % de membres de tel groupe ne sert à rien si ces X % sont silencieux et ne participent pas).

Quels sont les mécanismes qui peuvent, en pratique, limiter la diversité dans l'IETF (puisque, en théorie, tout le monde peut participer) ? Il y a plein d'exemples :

  • En théorie, la participation à l'IETF peut se faire à distance, par le biais des listes de diffusion et des différents outils de travail en groupe. En pratique, les réunions physiques sont difficiles à ignorer. La participation à ces réunions coûte de l'argent (inscription, voyage, hôtel) et cela limite la diversité en favorisant les riches. La participation à distance ne résout pas tout (par exemple en raison du décalage horaire). Accroitre l'importance des réunions par rapport aux listes de diffusion serait donc un problème pour la diversité.
  • Les participants à l'IETF sont évidemment (et heureusement) des passionnés. Cela peut mener à affirmer un peu trop vigoureusement ses préférences, d'une manière qui peut intimider certains participants, et donc limiter la diversité, en excluant les groupes qui sont traditionnellement exclus de la prise de parole publique.
  • L'IETF travaille sur la technique. Il est parfaitement normal de privilégier l'opinion de ceux et celles qui sont techniquement plus compétents. Mais même une organisation technique comme l'IETF a des activités non techniques (comme le choix des personnes qui assumeront des responsabilités) et, là, il n'y a aucune raison de n'écouter que les gens très forts en technique.
  • D'ailleurs, une partie du travail de l'IETF est de produire des documents (les RFC) qui ne doivent pas seulement être techniquement corrects, mais aussi être lisibles et compréhensibles, et pas seulement par les participants à l'IETF et pas non plus uniquement par des experts. Là encore, les compétences pour ce travail d'éducation ne sont pas forcément les mêmes que pour la technique pure et ne devraient donc pas être sous-estimées.

Mais il y a aussi des comportements anti-diversité plus directs et plus actifs comme le harcèlement ou l'intimidation. Ils peuvent être dirigés contre toutes les personnes appartenant (ou supposées appartenir) à tel ou tel groupe (comme « les femmes » ou « les homosexuels ») ou bien dirigés contre des individus spécifiques (comme l'abominable GamerGate). Aucun cas précis n'a été dénoncé à l'IETF, contrairement à ce qui arrive dans d'autres organisations, mais cela ne veut pas dire que cela n'arrivera jamais, ni même que cela n'est pas déjà arrivé : tous les cas ne sont pas publics, par exemple parce que les victimes peuvent hésiter à se plaindre, en raison du risque de représailles. Un futur RFC décrira la politique de l'IETF au sujet du harcèlement.

Malheureusement, ce RFC 7704 continue à décrire un environnement sans harcèlement comme « professional » comme si des actions aussi graves que celles du GamerGate étaient juste un manque de professionnalisme !

La section 3 du RFC s'occupe plutôt de propositions constructives : comment faire pour que tout le monde se sente bienvenu, de manière à augmenter la diversité ? Par exemple, le RFC recommande aux anglophones (la langue de travail de l'IETF est l'anglais) de parler lentement et clairement, et d'éviter les idiosyncrasies locales, ou les références culturelles trop locales (ah, ces allusions agaçantes à des émissions télé US que les non-États-Uniens n'ont pas vu...) Ainsi, la participation des non-anglophones pourra augmenter. Je note personnellement que, lorsqu'une réunion de l'IETF se tient aux États-Unis, les participants parlent bien plus vite et font moins attention à la diversité linguistique.

On peut aussi :

  • Encourager les timides à participer,
  • Avoir une attitude chaleureuse envers les nouveaux,
  • Ne pas laisser les plus expérimentés monopoliser la parole.

Tout cela n'est pas facile car il faut aussi tenir compte des exigences du travail : le but n'est pas juste d'être gentil mais surtout de créer les nouvelles normes techniques. Un exemple où il est difficile d'atteindre un bon équilibre est celui des réunions physiques des groupes de travail. L'IETF privilégie normalement l'efficacité : on saute directement dans le sujet, on ne passe pas son temps à expliquer, de toute façon, tout le monde est censé avoir travaillé avant, lisant les drafts et les discussions sur la liste de diffusion. Mais cette excellente façon de faire peut décourager les nouveaux, qui n'ont pas compris tous les tenants et aboutissants de la discussion.

Enfin, que faut-il faire contre les gens qui se comportent d'une manière qui peut faire fuir certain·e·s (section 4 du RFC) ? On peut les ignorer si ce n'est pas trop grave mais, au-delà d'un certain niveau de perturbation, il faut faire appel aux autorités (présidents du groupe de travail, ombudsperson, et président de l'IETF si nécessaire).

Quelques ressources supplémentaires sur l'activité de l'IETF à ce sujet :


Téléchargez le RFC 7704


L'article seul

RFC 7700: Preparation, Enforcement, and Comparison of Internationalized Strings Representing Nicknames

Date de publication du RFC : Décembre 2015
Auteur(s) du RFC : P. Saint-Andre (&yet)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF precis
Première rédaction de cet article le 15 décembre 2015


Bien des protocoles Internet manipulent des noms qui doivent être parlants pour les utilisateurs et donc, de nos jours, doivent pouvoir être en Unicode. Les noms purement ASCII appartiennent à un passé révolu. Le groupe de travail PRECIS de l'IETF établit des règles pour ces noms, de manière à éviter que chaque protocole, chaque application, ne soit obligé de définir ses propres règles. Ce nouveau RFC contient les règles pour un sous-ensemble de ces noms : les noms qui visent plutôt à communiquer avec un utilisateur humain (par opposition aux noms qui sont indispensables aux protocoles réseaux, traités dans le RFC 7613). Ce RFC a été depuis remplacé par le RFC 8266.

Ces noms « humains » sont typiquement ceux qui sont présentés aux utilisateurs. Ils doivent donc avant tout être « parlants » et il faut donc qu'ils puissent utiliser la plus grande part du jeu de caractères Unicode, sans restrictions arbitraires (contrairement aux identificateurs formels du RFC 7613, pour lesquels on accepte des limites du genre « pas d'espaces »).

Le terme utilisé par le RFC pour ces noms « humains » est nicknames, terme qui vient du monde de la messagerie instantanée. Il n'y a pas de terme standard pour les désigner, certains protocoles (comme le courrier) parlent de display names (par opposition au login name ou account name), d'autres utilisent encore d'autres termes (l'article « An Introduction to Petname Systems » peut vous intéresser). Par exemple, dans un message électronique, on pourrait voir :

From: Valérie Pécresse <vp@les-républicains.fr>
    

Et, dans cet exemple, vp serait le nom formel (mailbox name dans le courrier, login name pour se connecter), alors que Valérie Pécresse est le nickname, le nom montrable aux humains. (Le concept de display name dans le courrier est normalisé dans la section 3.4.1 du RFC 5322, son exact équivalent XMPP, le nickname, est dans XEP-0172.)

Comme l'illustre l'exemple ci-dessus, on veut évidemment que le nom puisse être en Unicode, sauf pour la petite minorité des habitants de la planète qui utilisent une langue qui peut s'écrire uniquement en ASCII.

Ces noms « parlants », ces nicknames, ne servent pas qu'à désigner des humains, ils peuvent aussi être utilisés pour des machines, des sites Web (dans les signets), etc.

On pourrait penser qu'il n'y a rien à spécifier pour permettre leur internationalisation. On remplace juste ASCII par Unicode comme jeu de caractères autorisé et vas-y, poupoule. Mais Unicode recèle quelques surprises et, pour que les nicknames fonctionnent d'une manière qui paraitra raisonnable à la plupart des utilisateurs, il faut limiter légèrement leur syntaxe.

Ces limites sont exposées dans la section 2 de notre RFC, qui définit un profil de PRECIS. PRECIS, Preparation, Enforcement, and Comparison of Internationalized Strings est le sigle qui désigne le projet « Unicode dans tous les identificateurs » et le groupe de travail IETF qui réalise ce projet. PRECIS définit (RFC 7564) plusieurs classes d'identificateurs et les nicknames sont un cas particulier de la classe FreeformClass, la moins restrictive (celle qui permet le plus de caractères).

Outre les restrictions de FreeformClass (qui n'est pas complètement laxiste : par exemple, cette classe ne permet pas les caractères de contrôle), le profil Nickname :

  • Convertit tous les caractères Unicode de type « espace » (la catégorie Zs) en l'espace ASCII (U+0020),
  • Supprime les espaces en début et en fin du nickname, ce qui fait que " Thérèse" et "Thérèse" sont le même nom,
  • Fusionne toutes les suites d'espaces en un seul espace,
  • Met tout en minuscules (donc les nicknames sont insensibles à la casse),
  • Normalise en NFKC, plus violent que NFC, et réduisant donc les possibilités que deux nicknames identiques visuellement soient considérés comme distincts (cf. section 6, qui prétend à tort que ce serait un problème de sécurité ; comme souvent à l'IETF, le groupe de travail a passé beaucoup de temps sur un faux problème de « confusabilité », cf. UTS#39).

À noter qu'un nickname doit avoir une taille non nulle, après l'application des ces règles (autrement, un nickname de trois espaces serait réduit à... zéro).

Une fois ce filtrage et cette canonicalisation faite, les nicknames sont encodés en UTF-8 et peuvent être comparés par une simple égalité bit à bit.

La section 3 de notre RFC fournit quelques exemples amusants et instructifs de nicknames :

  • "Foo" et "foo" sont acceptables, mais sont le même nom (en application de la régle d'insensibilité à la casse),
  • "Foo Bar" est permis (les espaces sont autorisés, avec les quelques restrictions indiquées plus haut),
  • "Échec au roi ♚" est permis, rien n'interdit les symboles comme cette pièce du jeu d'échecs, le caractère Unicode U+265A,
  • "Henri Ⅳ" est permis (ouvrez l'œil : c'est le chiffre romain à la fin, U+2163) mais la normalisation NFKC (précédée du passage en minuscules) va faire que ce nom est équivalent à "henri iv" (avec, cette fois, deux caractères à la fin).

Comme le rappelle la section 4 de notre RFC, les applications doivent maintenant définir l'utilisation de ces noms parlants, où peut-on les utiliser, etc. L'application peut donc avoir des règles supplémentaires, comme une longueur maximale pour ces nicknames, ou des caractères interdits car ils sont spéciaux pour l'application.

L'application ou le protocole applicatif a également toute latitude pour gérer des cas comme les duplicatas : j'ai écrit plus haut que "Foo Bar" et "foo bar" étaient considérés comme le même nickname mais cela ne veut pas dire que leur coexistence soit interdite : certaines applications permettent à deux utilisateurs distincts d'avoir le même nickname. Même chose avec d'autres règles « métier » comme la possibilité d'interdire certains noms (par exemple parce qu'ils sont grossiers).

Le profil Nickname est désormais ajouté au registre IANA (section 5 du RFC).


Téléchargez le RFC 7700


L'article seul

RFC 7696: Guidelines for Cryptographic Algorithm Agility and Selecting Mandatory-to-Implement Algorithms

Date de publication du RFC : Novembre 2015
Auteur(s) du RFC : R. Housley (Vigil Security)
Première rédaction de cet article le 22 novembre 2015


Bien des protocoles de l'IETF utilisent la cryptographie. Ils s'en servent pour la confidentialité, pour l'authentification, pour la signature. L'utilisation pour la confidentialité a évidemment crû en importance depuis les révélations d'Edward Snowden, malgré la guerre contre le chiffrement que mènent de nombreux gouvernements, qui voudraient pouvoir continuer à espionner tranquillement leurs citoyens. Or, un problème de la cryptographie est que les algorithmes ne sont pas éternels : la cryptanalyse trouve parfois, au bout d'un temps plus ou moins long, des moyens de casser un algorithme, qui doit alors être abandonné. Ce fut le cas, par exemple, de RC4, rejeté dans le RFC 7465. Il est donc indispensable que les protocoles utilisant la cryptographie aient la propriété d'agilité. Cette propriété désigne le fait qu'on puisse changer d'algorithme sans changer le protocole.

Pour des raisons d'interopérabilité, l'IETF désigne toujours un algorithme cryptographique comme obligatoire : ainsi, deux mises en œuvre d'un protocole donné auront toujours au moins un algorithme en commun, l'algorithme obligatoire, et pourront donc interopérer. Mais l'algorithme obligatoire peut lui aussi céder un jour face à la cryptanalyse, et il faut donc également prévoir le moyen de le remplacer.

[Au passage, la plupart des protocoles IETF utilisent non pas un algorithme unique mais une liste d'algorithmes, la cipher suite. Par exemple, pour TLS, cette liste comprend un algorithme de chiffrement asymétrique (comme RSA), un de chiffrement symétrique (comme AES) et un de condensation (comme SHA-2).]

Revenons à la cryptanalyse. Les algorithmes « vieillissent » donc avec le temps, au fur et à mesure que les cryptanalystes découvrent de nouvelles méthodes pour casser l'algorithme. Ce vieillissement n'est pas régulier et n'est pas prévisible. Certains algorithmes sont cassés dans les années qui suivent immédiatement leur publication, d'autres résistent encore (plus ou moins bien) des dizaines d'années après. Ce qui est sûr, c'est que les attaques, au pire stagnent, au mieux se perfectionnent avec le temps : un algorithme ne peut donc pas « rajeunir ». C'est ce vieillissement inéluctable (quoique de durée très variable) qui justifie le principe d'agilité cryptographique.

Le principe est simple et semble excellent. Mais l'expérience de la communauté Internet est qu'il est difficile de changer les vieux algorithmes vulnérables par des nouveaux. Même une fois le nouvel algorithme normalisé par l'IETF, et une fois qu'il est mis en œuvre dans les logiciels les plus répandus, on constate souvent que la mise à jour des logiciels est lente et que, des années après l'abandon officiel d'un algorithme, il est toujours disponible et activé dans des millions de machines (et parfois, il est même le seul disponible). Il est donc difficile de supprimer un vieil algorithme vulnérable (comme MD5, cf. RFC 6151), ne serait-ce que pour des raisons d'interopérabilité : si une machine ne sait condenser qu'avec MD5, les machines équipées d'un logiciel plus récent, qui gère SHA-2 et d'autres, devront bien accepter de parler avec MD5 ou, sinon, plus de communication. Bref, les algorithmes morts continuent à hanter l'Internet pendant très longtemps. Pensons par exemple aux administrateurs système qui hésitent encore à supprimer le protocole SSLv3 (cf. RFC 7568) de leurs serveurs HTTPS, de peur de ne plus pouvoir accepter les clients MSIE 6. Il faut souvent recourir à des méthodes de name and shame comme le test de SSLlabs (qui fait aussi de la gamification, avec ses notes) pour TLS : « cette banque est nulle, leur serveur HTTPS accepte encore 3DES » (ce que le RFC nomme pudiquement « social pressure »).

Passons au concret avec la section 2 de notre RFC. Il s'agit de règles internes à l'IETF qu'il est fortement recommandé de suivre lors du développement de nouveaux protocoles, pour permettre l'agilité cryptographique. D'abord, évidemment, les protocoles IETF ne doivent pas être liés à un algorithme unique, puisque le cassage de celui-ci entrainerait la fin du protocole. Pour permettre le choix d'un algorithme, il faut que chaque algorithme (ou chaque liste d'algorithmes) ait un identificateur, un nombre ou une chaîne de caractères qui désigne un algorithme donné. Ainsi, pour DNSSEC, ces identificateurs (8 pour la liste RSA avec SHA-256, 13 pour la liste ECDSA avec la courbe P-256 et SHA-256, etc) sont stockés dans un registre IANA. TLS, lui, utilise des chaînes de caractères comme TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 qui veut dire « échange de clés Diffie-Hellman avec courbes elliptiques, authentification avec RSA, chiffrement symétrique en AES mode GCM, condensation avec SHA-256 ». Cet identificateur est donc la première étape indispensable vers l'agilité cryptographique.

Faut-il un identificateur par algorithme, identificateurs que l'on combine ensuite pour obtenir la liste utilisée, comme le fait IKE (RFC 7296) ou bien un identificateur par liste, comme c'est le cas pour TLS (RFC 5246) ? La question n'est pas évidente. La première méthode permet d'avoir moins d'enregistrements. Mais toutes les combinaisons possibles n'ont pas forcément un sens donc enregistrer les listes (les combinaisons) peut être préférable. Notre RFC ne tranche pas là-dessus.

Dans tous les cas, pour que nos amis Alice et Bob puissent communiquer, il faut qu'ils aient un jeu d'algorithmes en commun (RFC 3365). D'une manière générale, l'IETF prête une grande attention à cette interopérabilité, d'où la notion d'algorithme obligatoire, ou plutôt « obligatoire à implémenter » (à mettre dans les programmes). Sans ces algorithmes obligatoires, on pourrait avoir deux implémentations parfaitement correctes du protocole, mais qui seraient dans l'impossibilité de dialoguer, puisqu'elles n'auraient aucun algorithme en commun. C'est pour cela que chaque protocole doit avoir un ou plusieurs algorithmes (ou listes, si on enregistre les listes) qui soient obligatoires. Pour DNSSEC, par exemple, c'est RSA-SHA1.

Et comme les algorithmes obligatoires peuvent eux aussi être cassés un jour, il est recommandé, pour faciliter leur changement, que le RFC spécifiant le protocole n'indique pas quels sont les algorithmes obligatoires, mais se réfère à un RFC plus court, sur ce sujet. On pourra ainsi modifier le RFC « Algorithmes » sans toucher au protocole. DNSSEC n'utilise pas cette méthode (l'algorithme obligatoire est défini dans le RFC 4034) mais JOSE (cryptographie pour JSON) le fait (les algorithmes sont définis dans le RFC 7518).

Pour la taille des clés utilisées pour ces algorithmes, notre RFC renvoie au RFC 3766 pour la cryptographie asymétrique et au RFC 7525 pour la symétrique.

En général, la mort d'un algorithme cryptographique n'est pas instantanée. Si, en théorie, il est possible qu'un mathématicien génial fasse une percée théorique inattendue qui rende tout à coup le cassage de tel algorithme trivial, en pratique, cela n'arrive que très rarement : on voit plutôt des attaques de plus en plus perfectionnées, un algorithme de plus en plus déconseillé jusqu'à son abandon officiel. C'est un domaine où il y a peu de « coups de tonnerre dans un ciel bleu ». Le passage de DES à AES s'est ainsi étalé sur des dizaines d'années, et celui de RSA vers les courbes elliptiques prendra sans doute autant de temps.

Pour prévenir les programmeurs des changements qu'on peut sans doute attendre, notre RFC recommande, dans l'esprit du RFC 4307, d'augmenter les termes normatifs définis dans le RFC 2119. Ce RFC définissait l'usage de MUST, SHOULD et MAY (en majuscules) dans les RFC. Notre nouveau RFC recommande d'utiliser également SHOULD+, SHOULD- et MUST-. Un SHOULD+ est la même chose qu'un SHOULD aujourd'hui (« cet algorithme devrait être implémenté, sauf si on a une très bonne raison et qu'on sait ce qu'on fait »). Mais, dans le futur, il est probable qu'il deviendra un MUST (algorithme obligatoire). Un SHOULD- est un SHOULD qui sera probablement dégradé en un simple MAY dans le futur. Quant au MUST-, il indique que l'algorithme est aujourd'hui obligatoire mais ne le restera sans doute pas.

Passer d'un algorithme à l'autre, on l'a vu, n'est pas trivial. Intuitivement, on se dit que l'IETF normalise le nouvel (et meilleur algorithme), que les programmeurs le programment dans les logiciels et que, au bout d'un moment, les nouveaux logiciels sont assez répandus pour qu'on puisse abandonner officiellement l'ancien algorithme.

Cela suppose qu'on sache mesurer l'état du déploiement et, pour beaucoup de protocoles, il n'y a pas de mécanisme de centralisation des statistiques. On ne sait donc pas si on peut « couper le cordon » et abandonner l'ancien algorithme.

C'est pour cela que la tendance est à mettre dans les nouveaux protocoles un mécanisme de signalisation, permettant de voir le déploiement du nouvel algorithme (par exemple le RFC 6975 pour DNSSEC).

Comme le déploiement est toujours trop long, on peut potentiellement se retrouver dans des situations ennuyeuses où l'ancien algorithme, désormais facilement cassé, est encore largement utilisé. Faut-il alors le supprimer des implémentations, remettant ainsi en cause l'interopérabilité, ou bien le laisser alors qu'on sait que cela met en cause la sécurité ? Débat cornélien qui agite régulièrement le monde TLS, par exemple. Il y a quelques années, la tendance était plutôt à laisser les algorithmes mourir tranquillement, de nos jours, elle est plutôt à éliminer rapidement les « canards boiteux », quitte à renoncer à la communication avec les vieux logiciels. C'est ainsi que l'abandon progressif de SHA-1, désormais largement attaqué, a été souvent fait de manière brutale (par exemple Google Chrome décidant soudainement de marquer les certificats utilisant SHA-1 comme étant dangereux).

L'agilité cryptographique n'a pas que des avantages. On a vu qu'elle était indispensable, pour tenir compte des progrès de la cryptanalyse. Mais, si un protocole accepte plusieurs algorithmes, comment s'assurer que les deux pairs qui négocient utilisent bien le plus fort ? Imaginons un protocole de chiffrement où le serveur indique à la connexion les algorithmes qu'il sait gérer et où le client en choisit un dans la liste, a priori le plus solide, et où le chiffrement démarre ensuite, avec l'algorithme choisi. Un attaquant actif, par exemple un Homme du Milieu, peut modifier la liste d'algorithmes pour mettre l'algorithme le plus faible, qu'il pourra ensuite casser. C'est ce qu'on nomme une attaque par repli (downgrade attack) et c'est la plaie des protocoles qui offrent l'agilité cryptographique. Il faut donc trouver un mécanisme de protection et ne pas garder éternellement les algorithmes trop vieux.

Un problème du même ordre se pose avec les protocoles qui permettent, non seulement de négocier les algorithmes de cryptographie, mais également le mécanisme d'échange initial des clés. C'est le cas d'EAP, par exemple (RFC 3748). Les concepteurs de protocole doivent se souvenir que la complexité est souvent la principale ennemie de la sécurité.

Compte tenu des problèmes que peut entrainer l'agilité cryptographique, notamment la complexité accrue du code, certains pourraient être tentés de concevoir des protocoles à un seul algorithme. Le protocole serait plus simple, et n'offrirait pas de possibilités d'attaques par repli. Un exemple de ce choix avait été WEP. Lié à un seul algorithme, ne pouvant pas évoluer, WEP avait été très long et compliqué à remplacer par un nouveau protocole, qu'il avait fallu concevoir, implémenter puis déployer. WEP est donc un bon exemple de l'importance de l'agilité cryptographique.

La section 3 de notre RFC examine sur quels critères choisir les algorithmes et notamment ceux qui seront obligatoires, et qui doivent donc être de haute qualité cryptographique. Évidemment, le choix ne doit pas être laissé à l'utilisateur final, qui n'a pas les éléments pour le faire. Il vaut mieux aussi qu'il ne soit pas laissé à l'administrateur système, qui n'est typiquement pas un expert en cryptographie. (Regardez la difficulté qu'il y a aujourd'hui à gérer un serveur HTTPS, avec tous ces choix pointus à faire en matière d'algorithmes. TLS est probablement un bon exemple du syndrome « trop de choix ».)

D'abord, les algorithmes obligatoires doivent évidemment faire l'objet d'une spécification publique (pendant longtemps, RC4 était secret). Il doivent avoir fait l'objet d'examens attentifs et de tentatives de cassage par des experts. De préférence, ils ne doivent pas faire l'objet de brevets. Ils doivent évidemment aussi répondre à des exigences plus techniques : ils doivent être rapides, implémentables dans un code de taille réduite, résister aux attaques par canal auxiliaire, etc.

Il existe des algorithmes de cryptographie dits « nationaux » parce que normalisés par une organisation de normalisation nationale officielle et parfois rendus obligatoires par une loi locale (si l'organisation de normalisation est le NIST, on ne les appelle pas « nationaux », le terme est réservé à ceux normalisés en dehors des États-Unis). Ils n'ont pas forcément fait l'objet d'une étude sérieuse et leur but est souvent de simple protectionnisme de l'industrie de sécurité nationale. Auquel cas ils ne doivent pas être choisis dans les protocoles IETF et en tout cas pas activés par défaut. (La section 3.4 du RFC fait pas mal de FUD : il existe d'excellents algorithmes « nationaux » comme ceux du GOST.)

Enfin, la section 4 du RFC, qui examine les questions de sécurité restantes, note que la force de l'algorithme n'est pas tout. Des faiblesses peuvent apparaitre, par exemple en raison de l'ordre des opérations de cryptographie (cf. RFC 7366)


Téléchargez le RFC 7696


L'article seul

RFC 7695: Distributed Prefix Assignment Algorithm

Date de publication du RFC : Novembre 2015
Auteur(s) du RFC : P. Pfister, B. Paterson (Cisco Systems), J. Arkko (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF homenet
Première rédaction de cet article le 25 novembre 2015


Le projet Homenet, qui vise à relier en un réseau local autonome tous les objets électroniques de la maison, avance (cf. RFC 7368). Parmi les briques indispensables à l'édification de ce réseau de la maison, il fallait un mécanisme d'allocation des adresses IP. Un réseau Homenet devant fonctionner sans administration système, ce mécanisme devait être entièrement automatique. C'est ce que propose ce RFC.

Contrairement au traditionnel réseau domotique actuel, le réseau Homenet peut être constitué de plusieurs réseaux (au sens IP du terme), avec chacun son préfixe IPv6. Si la maison a un préfixe IPv6 délégué, il faut le découper et affecter les sous-préfixes à chaque réseau de la maison. Normalement, c'est le travail de l'administrateur réseaux, qui centralise l'information puis la distribue. Mais, à la maison, il n'y a personne qui puisse ou veuille faire ce travail, il faut donc l'automatiser. Et ce doit être un algorithme réparti car un réseau Homenet n'a pas de machine « chef ».

Cet algorithme prend en entrée une liste de préfixes (le ou les préfixes délégués à la maison), et répartit les sous-préfixes à chaque lien de façon à ce que chaque lien reçoive au plus un sous-préfixe de chacun des préfixes délégués, qu'il n'y ait pas de recouvrement entre les préfixes, et que le tout soit stable, tant que la topologie du réseau ne change pas (cf. section 3 sur les conditions d'usage de cet algorithme).

Le principe (section 4) est que chaque routeur (je simplifie : ce n'est pas forcément un routeur qui choisit le préfixe) va, pour chaque lien, tirer au hasard (pour minimiser le risque de collision), un préfixe plus spécifique que le préfixe délégué et le transmettre ensuite à tout le réseau, via un algorithme d'inondation. Notez bien que c'est une présentation simplifiée : par exemple, le préfixe initial n'est pas forcément tiré au hasard (cf. section 5).

Cet algorithme dépend donc de l'existence d'un algorithme d'inondation, qui n'est pas spécifié dans ce RFC, plusieurs sont envisageables (comme ceux de OSPF - cf. RFC 7503 - ou de HNCP - Home Networking Control Protocol). Il dépend aussi de l'existence d'un identificateur unique par nœud (rappelez-vous que ce RFC n'est qu'une seule des briques d'Homenet, il n'est pas utilisable seul, par exemple il ne dit pas comment cet identificateur est attribué), et que ces identificateurs ont un ordre. Cela servira au cas où plusieurs routeurs veulent le même préfixe, avec la même priorité (celui qui a l'identificateur le plus grand gagne).

Parmi les nombreuses options de l'algorithme, notez qu'il gère également le cas où le lien a déjà eu un préfixe alloué et souhaite le réutiliser. (Une telle stabilité est souhaitable.)

Enfin, la section 8, sur la sécurité, rappelle que ce protocole n'a pas de protection contre un acteur malveillant. Par exemple, un routeur gourmand qui se prend le préfixe entier pour l'un de ses liens empêche les autres de le réclamer. Un méchant peut aussi annoncer quelque chose tout le temps pour empêcher la convergence, réalisant ainsi une attaque par déni de service. En outre, cet algorithme dépend de la sécurité de l'algorithme d'inondation et de celle du mécanisme de sélection de l'identificateur.

Une mise en œuvre de HNCP en logiciel libre existe, hnetd. Elle contient cet algorithme (cf. fichiers src/pa_core*, « pa » signifiant prefix assignment).


Téléchargez le RFC 7695


L'article seul

RFC 7687: Report from the Strengthening the Internet (STRINT) workshop

Date de publication du RFC : Décembre 2015
Auteur(s) du RFC : S. Farrell (Trinity College, Dublin), R. Wenning, B. Bos (W3C), M. Blanchet (Viagenie), H. Tschofenig (ARM)
Pour information
Première rédaction de cet article le 15 décembre 2015


Depuis les révélations d'Edward Snowden, les initiatives se multiplient pour « durcir l'Internet », c'est-à-dire le rendre plus résistant à la surveillance généralisée, telle que pratiquée par plusieurs pays (par exemple la France, où les politiques profitent cyniquement des attentats islamistes pour faire passer de plus en plus de lois liberticides). Début 2014, à Londres, s'est ainsi tenu l'atelier STRINT, qui a rassemblé une centaine de participants pour réfléchir à la meilleure façon de renforcer l'Internet contre cet espionnage. Ce RFC est le compte-rendu (très tardif) de cet atelier. Il résume les principales interventions, et les suggestions faites à cette occasion.

L'engagement de l'IETF à lutter contre la surveilance généralisée date de sa réunion de Vancouver, et a été formalisé dans le RFC 7258. C'est à la suite de cette réunion canadienne qu'a été tenu l'atelier STRINT, coorganisé par le projet STREWS, l'IAB et le W3C. STRINT signifie « Strengthening the Internet Against Pervasive Monitoring » et l'atelier s'est tenu juste avant la réunion IETF 89 à Londres.

L'atelier a été un succès. Prévu pour un petit nombre de participants (cent maximum : le but était de travailler, pas de faire des discours devant une immense salle), il a été rempli en peu de temps. (Outre les 100 participants physiques, jusqu'à 165 personnes ont suivi l'atelier à distance.) 67 articles avaient été soumis.

La section 2 du RFC résume les conclusions de l'atelier :

  • La cryptographie bien faite est une protection efficace contre la surveillance massive et son usage plus intense est souhaitable.
  • L'analyse de trafic est une menace réelle, et la cryptographie est ici moins efficace. Mais le problème reste insuffisamment connu et mérite d'avantage d'études.
  • La surveillance massive est quelque chose de relativement nouveau et mérite des analyses du modèle de menace plus détaillées (le travail était en cours à l'époque, et cela a mené, entre autres, au RFC 7624).
  • Cette surveillance massive mérite qu'on s'attaque à une mise à jour du RFC 3552.
  • Le terme de « opportunistic security » a été brandi plusieurs fois pendant l'atelier. Il faut savoir que ce terme n'a pas de définition rigoureuse et est utilisé dans le monde de la sécurité pour désigner des tas de choses différentes. Depuis, l'IETF a publié sa définition, dans le RFC 7435.
  • Un effort d'explication auprès des décideurs reste nécessaire, pour expliquer les problèmes techniques que pose la surveillance massive. (Belle naïveté de techniciens honnêtes qui croient que les politiques prennent des mauvaises décisions parce qu'ils ne sont pas bien informés.)
  • La question des interfaces utilisateur est très importante et très difficile. Il existe désormais un net consensus chez les gens de la sécurité que l'utilisateur est un maillon crucial (et souvent fragile) de la chaîne de sécurité. Il reste à tirer des conséquences pratiques de ce consensus de principe. Par exemple, faut-il arrêter de présenter à l'utilisateur des choix dangereux, comme « le certificat n'a pas le bon nom, voulez-vous continuer ? » Si on répond « il ne faut pas proposer de tels choix », une coordination entre les auteurs de logiciels est nécessaire autrement ceux qui respectent le plus la sécurité risquent d'être considérés comme moins bon que ceux de leurs concurrents (comme on l'a déjà vu avec DNSSEC). Globalement, ce problème des interfaces utilisateur reste un champ de recherche ouvert.
  • Développer des exemples de configurations sûres à copier/coller pour mettre dans son logiciel aiderait certainement (regardez par exemple la documentation de l'ANSSI sur HTTPS, section 2.1). Ce n'est pas un travail de normalisation et cela ne concerne donc pas directement l'IETF ou le W3C mais c'est certainement important.
  • Plus directement de la responsabilité de ces SDO : faire un effort pour que les protocoles soient sûrs par défaut (un contre-exemple est SMTP, qui est en clair par défaut.)
  • Apparemment plus anecdotique, mais néanmoins crucial vu leur vaste déploiement, résoudre le problème des portails captifs aiderait : aujourd'hui, ces portails utilisent les mêmes techniques que des attaquants et sont donc indistinguables d'une attaque.

La section 3 de notre RFC revient sur les buts de l'atelier. Une fois qu'on a décidé que la surveillance généralisée était une attaque, et qu'il fallait la combattre (RFC 7258), que faire de plus ?

  • Se mettre d'accord sur des concepts comme celui de « sécurité opportuniste »,
  • Mieux comprendre les compromis à faire (la sécurité n'est pas gratuite),
  • Identifier les « maillons faibles » de la sécurité du Web,
  • Et surtout, identifier les tâches concrètes qui relèvent des organismes de normalisation comme l'IETF ou le W3C et celles qui, sans relever directement de ces organismes, les aideraient dans leur tâche.

Pour atteindre ces buts, l'atelier était structuré pour maximiser les discussions (section 4 du RFC). Les papiers acceptés n'étaient pas présentés (les participants étaient supposés les avoir lus avant).

Quels furent les sujets couverts dans les sessions de l'atelier (section 5 du RFC) ? La session d'ouverture a discuté de questions plutôt « méta » comme la quantité minimale de métadonnées qui est vraiment nécessaire aux protocoles IETF pour faire leur travail, comme la recherche de « fruits à portée de main » (des solutions qui pourraient être déployées très rapidement), ou comme le niveau de sécurité considéré comme « suffisant » (il ne faut pas espérer atteindre une sécurité parfaite, quand l'attaquant a les moyens de la NSA).

La première session portait (section 5.2) sur les menaces. Pas de sécurité sérieuse sans une étude détaillée des menaces. Ce n'est pas la même chose de se protéger contre la DGSE ou le FSB et de se protéger contre le lycéen boutonneux dans son garage. La surveillance généralisée met en cause un modèle traditionnel de menaces, fondé sur une étude coût/bénéfice de la défense (ou de l'attaque d'ailleurs). Dans ce modèle traditionnel, on regardait ce que valait l'objectif à défendre et on calculait les dépenses de sécurité réalistes en fonction de cela. (L'attaquant faisait un calcul similaire, et pouvait migrer vers un autre objectif, si le premier envisagé était trop coûteux.) Mais, avec la surveillance généralisée, il n'y a plus de décisions d'attaquer tel ou tel objectif : on attaque tout le monde. Et l'attaquant étant en général un État, il ne fait pas de calcul de ROI (certaines bureaucraties étatiques sont même contentes quand c'est cher, cela permet de se « construire un empire » en réclamant des budgets toujours plus élevés).

Est-ce que la surveillance généralisée est plus facile s'il y a un petit nombre de silos très protégés (les GAFA, Google, Facebook, etc) ou s'il y a une multitude de petits sites, chacun avec son CozyCloud ou son YunoHost, chacun moins bien protégé que les grosses entreprises professionnelles, mais bénéficiant de la dispersion des données ? Si Facebook est certainement, pour un attaquant, un objectif plus difficile à craquer que le VPS de M. Michu, c'est également un objectif beaucoup plus intéressant : si on le craque, on a les données de centaines de millions de M. Michu. Le RFC suggère donc qu'il vaut mieux ne pas tout mettre chez les GAFA et disperser les objectifs. (Gentiment, il oublie de rappeler que certains attaquants n'ont pas besoin de pirater les GAFA : ils ont PRISM pour cela.)

La session a aussi mis en évidence l'importance d'utiliser un vocabulaire rigoureux quand on parle des menaces et des solutions techniques, surtout quand on s'adresse à un public non-spécialiste. Ainsi, les solutions contre les attaques de l'Homme du Milieu ne « protègent » pas contre ces attaques : elles les rendent simplement visibles. C'est la réaction aux alertes qui déterminera si on est protégé ou pas (pensez au traditionnel avertissement des navigateurs Web : « voulez-vous continuer malgré ce certificat mal fichu ? »).

Une autre session portait sur l'usage des outils de sécurité (section 5.3). Ce n'est pas tout de concevoir des outils géniaux, il faut encore qu'ils soient utilisés. Aujourd'hui, on constate que ce n'est pas assez le cas. Combien de messages circulent en clair quand ils devraient être chiffrés avec PGP ? Combien de SMS envoyés de manière à être lisibles par tous alors qu'il faudrait utiliser Signal (ex-TextSecure) ? Combien de webmestres renoncent à activer HTTPS parce qu'ils ne veulent pas payer une AC et subir ses procédures et son interface Web mal faite ?

Le RFC note que, dans ce dernier cas, ils ont raison, vu la faille fondamentale de ce système des AC : n'importe quelle AC peut émettre un certificat pour n'importe quel domaine. Donc, il suffit qu'une seule des centaines d'AC reconnues par le logiciel soit compromise pour faire s'effondrer tout l'édifice. Des solutions techniques existent (cf. RFC 6962 ou le RFC 6698, curieusement oublié ici).

Un des problèmes à l'usage des outils de sécurité peut être le modèle de confiance utilisé. Dans X.509, c'est « toutes les AC ont raison ». C'est très dangereux pour la sécurité. PGP a un modèle « réseau de confiance » qui a l'inconvénient de ne bien marcher que pour des petites communautés (il n'est pas réellement transitif). Un modèle longtemps méprisé par les experts en sécurité (ceux avec qui, si on les écoute, on ne déploie jamais aucune solution de sécurité, car aucune n'est parfaite) est le TOFU, utilisé par SSH ou Signal. Il a l'avantage d'être beaucoup plus facile pour les utilisateurs, mais l'attaque de l'Homme du Milieu reste possible pour la première connexion. La technique de l'« épinglage des clés » (RFC 7469) est une variante de TOFU.

Et pour SIP ? La constatation de l'atelier était que les fonctions de cryptographie dans SIP, pourtant bien normalisées, étaient peu utilisées. L'argument des opérateurs SIP est que les mises en œuvre de ce protocole sont peu interopérables et que la seule solution pour que ça marche est de modifier les échanges en cours de route, rajoutant ou enlevant des en-têtes SIP pour s'adapter à chaque logiciel. (S'ils ont raison, cela signifie que les RFC sur SIP n'étaient pas clairs, ou bien que les programmeurs ne les ont pas lus.)

Peut-être que WebRTC en tirera les leçons (RFC 8827). Après tout, WebRTC est mis en œuvre par les auteurs de navigateurs et ceux-ci n'ont pas les mêmes intérêts que les opérateurs SIP (les intermédiaires adorent modifier les données et détestent la sécurité de bout en bout).

Et pour XMPP (RFC 6120), pourquoi les techniques de sécurité existantes ne sont-elles pas plus fréquemment utilisées ? XMPP a de l'authentification et du chiffrement du canal, grâce à TLS, et de l'authentification et du chiffrement de bout en bout, grâce à OTR (qui a par contre le gros défaut d'être mal intégré au protocole XMPP). Mais le problème identifié pendant la session est plutôt que XMPP est peu utilisé. Contrairement au courrier électronique, où tout le monde utilise les solutions standard (SMTP et IMF), pour la messagerie instantanée, M. Michu fait une confiance aveugle à des systèmes fermés et privatifs comme Skype, dont la sécurité est inconnue ou inexistante.

Il y avait bien sûr une session consacrée aux questions non techniques (section 5.4) car on sait bien maintenant que « la sécurité n'est pas un produit, c'est un processus ». Installer un outil technique ne suffit pas. Il faut aussi traiter les questions d'éducation des utilisateurs, les questions politiques, les questions juridiques... Ainsi, l'excuse du terrorisme est largement utilisée par les États pour justifier des politiques répressives, tellement répressives qu'elles auraient été largement considérées comme inacceptables il y a seulement quelques années (voir par exemple ce qui se fait en France en ce moment avec l'état d'urgence). Il y aussi, note le RFC, le problème des traités internationaux pro-commerce (comme TTIP) qui contiennent souvent des mesures anti-vie privée.

On note que, d'une façon générale, ces problèmes non techniques étaient traditionnellement peu pris en compte par les organisations comme l'IETF, ou par les informaticiens en général. Cela fait très longtemps que les chercheurs en médecine, par exemple, ont des comités d'éthique qui se penchent sur les conséquences de leur travail. Faudrait-il faire la même chose pour les SDO ? Pour l'instant, les normes qui ont reçu une évaluation extérieure sur les questions de vie privée (comme l'API de géolocalisation) l'ont été ponctuellement, sans démarche systématique.

Cela n'interdit pas d'améliorer les outils et une session était consacrée à cette activité (section 5.5 du RFC). D'abord, l'atelier a discuté de la sécurité opportuniste (au sens de « essayer de chiffrer autant que possible, même sans authentification, ce serait mieux que rien »), en considérant qu'elle n'avait pas été assez utilisée jusqu'à présent. L'une des difficultés de cet opportunisme est de ne pas donner de faux sentiments de sécurité à l'utilisateur. Par exemple, il y avait un consensus dans l'atelier que, si un logiciel tente TLS et y réussit, mais sans authentification, il ne doit pas présenter à l'utilisateur des signes rassurants, genre petit cadenas. Le chiffrement ainsi obtenu est un progrès mais il ne faut pas donner l'impression qu'on s'arrête là.

Un aspect délicat à l'heure actuelle est de l'attitude à avoir lorsqu'on ne peut pas chiffrer : est-ce parce que le pair ne sait effectivement pas ou bien parce qu'un Homme du Milieu a réussi à empêcher le chiffrement ? Pour des sessions qu'on veut sécurisées (https://... vers sa banque), il faut évidemment s'arrêter là. Mais pour les autres, il serait intéressant, plutôt que de se rabattre sur de la communication en clair, ce qui est souvent le choix, de se souvenir des communications précédentes avec ce pair et de décider en fonction du passé si ce problème de chiffrement est normal (une forme de TOFU).

Là aussi, la terminologie est importante. Les descriptions des connexions utilisant le « chiffrement, si possible » (sécurité opportuniste) parlent souvent d'« échec » si la session chiffrée n'a pu être établie alors qu'un tel échec n'est pas pire que si on n'avait même pas essayé. Il faudrait plutôt parler d'« amélioration » quand on a réussi à lancer le chiffrement (et ne rien dire si on n'y est pas arrivé). Là aussi, le fait que les concepteurs de protocoles, les experts en sécurité et les programmeurs ne soient pas des spécialistes de l'interface utilisateur va jouer : il n'est pas évident de communiquer des informations sur le niveau de sécurité à l'utilisateur.

Autre point sur lequel il faudrait améliorer les outils, le fait de chiffrer systématiquement, sans action explicite de l'utilisateur. Sinon, il y a un risque que l'utilisateur ne chiffre que les documents sensibles, ce qui facilite la tâche des espions, en leur indiquant quels sont les documents importants. (C'est un des problèmes de PGP, je trouve.)

Il serait également intéressant d'améliorer TOFU. Un des gros problèmes de ce modèle, tel qu'il est utilisé dans SSH, est qu'il n'existe pas de mécanisme propre pour changer la clé d'un serveur (par exemple parce qu'on a mis à jour le logiciel). Idem si on utilise Signal : si votre correspondant a perdu son téléphone et en a acquis un nouveau, il faut manuellement vérifier la nouvelle identité (TOFU ne peut pas savoir si c'est un changement de clé légitime ou bien une attaque de l'Homme du Milieu).

Un sujet qui fait l'objet de nombreuses discussions dès qu'on parle de vie privée et de surveillance est celui des métadonnées (section 5.6). Chiffrer protège en effet très bien le contenu. Malgré quelques rumeurs, il est peu probable que même les plus puissants attaquants arrivent aujourd'hui à craquer le chiffrement bien fait (attention : bien chiffrer est beaucoup plus dur que ce n'en a l'air). Pour un attaquant rationnel, voler les clés, acheter ou menacer un destinataire légitime, ou encore corrompre le logiciel de chiffrement est bien plus aisé que de casser le chiffrement lui-même (c'est d'ailleurs pour cela que les discussions de détail sur la longueur des clés sont assez ridicules). Mais ce chiffrement n'aide pas si les métadonnées sont, elles accessibles. Pour prendre un exemple classique, imaginons deux personnes qui se téléphonent et chiffrent la communication. Le fait qu'ils se téléphonent est lui-même une information, qui peut être suffisante pour un espion, même s'il n'a pas accès au contenu des communications. C'est encore plus vrai si on a accès à plusieurs communications : si, à chaque fois que A appelle B au téléphone, B, immédiatement après avoir raccroché, appelle C, D et E, on en déduira facilement qu'on a identifié une chaîne de commandement, même si on n'a pas le contenu de leurs conversations. Cet exemple illustre bien le danger des métadonnées. Parfois, même la taille des messages donne des indications (si vingt fichiers de taille différente sont sur un serveur, l'observation du trafic, même chiffré, permet de savoir quel fichier a été récupéré).

Or, ces métadonnées sont partout, soit qu'elle soient absolument indispensables au fonctionnement des protocoles (comme l'adresse IP de destination dans les paquets IP), soit que leur potentiel d'indiscrétion n'ait pas été perçu tout de suite. Les supprimer n'est pas évident : un routeur a bien besoin de l'adresse de destination pour router !

Il y a trois techniques pour lutter contre l'espionnage par les métadonnées : l'agrégation, le détour (contraflow), et la dispersion (multipath). L'agrégation consiste à regrouper des conversations différentes dans un même flux de données. Par exemple, si votre résolution DNS passe par un gros résolveur partagé, les serveurs qu'interroge ce résolveur auront du mal à identifier vos requêtes, toutes passant par le résolveur. Idem en HTTP si on utilise un relais partagé, sauf évidemment si celui-ci laisse passer, ou, pire, ajoute, des informations discriminantes comme le User-Agent:. Même chose côté serveur : si vos pages « sensibles » sont hébergées sur un serveur mutualisé, un observateur aura du mal à dire ce qui était demandé (là encore, tout est dans les détails : par exemple, SNI peut trahir la communication).

Le détour consiste à passer délibérement par des chemins supplémentaires. C'est ce que fait un VPN ou, en encore mieux, Tor. Un espion qui voudrait identifier votre trafic devrait observer l'Internet en de nombreux points, et corréler ce qu'il voit.

Quant à la dispersion, elle consiste à envoyer les données par des moyens différents. Si vous commencez une conversation XMPP via de la 4G et que vous continuez en Wifi, l'attaquant aura davantage de mal que si toute la communication passe par un seul canal.

L'analyse de trafic donne souvent des résultats surprenants d'efficacité, dont les concepteurs de protocole ne se rendent pas compte. (Voir la bibliographie de FreeHaven, par exemple.) Il existe des méthodes pour la contrarier, comme d'ajouter des messages vides (padding, voir par exemple le RFC 7540, sections 6.1 et 10.7) mais elles ont un coût (par exemple en terme de débit) et ne sont pas faciles à utiliser.

Notez que les protections de bas niveau (couche 3) ne sont pas très utiles si les applications elle-même font fuiter des données. Un navigateur Web est particulièrement terrible sur ce point, voir le Panopticlick. C'est pour cela que Tor recommande l'usage du Tor Browser qui ne se contente pas de router les données via Tor, mais qui s'assure aussi que le navigateur ne vous trahit pas, et n'envoie qu'un minimum de données.

Un problème fréquent pour tous les systèmes de sécurité est celui des middleboxes, ces équipements intermédiaires qui se permettent de filtrer les messages, voire de les modifier. Beaucoup de protocoles de sécurité de l'Internet sont conçus pour une connexion de bout en bout : c'est le cas de TLS, par exemple. La middlebox viole cette supposition. On voit, par exemple, des middleboxes qui terminent la session TLS, analysent le trafic, puis re-chiffrent de l'autre côté. Pour passer l'authentification TLS, elles imposent en général de mettre le certificat d'une AC complice sur les ordinateurs clients. À noter que, dans la configuration TLS typique, le client authentifie le serveur mais pas le contraire. Ce qui veut dire qu'un serveur, même ultra-paranoïaque, n'a aucun moyen, contrairement au client, de détecter qu'une middlebox est présente.

Un autre exemple typique de middlebox courante est le portail captif (cf. RFC 6585 mais aussi le RFC 7710, issu des réflexions de cet atelier). Certains systèmes d'exploitation utilisent diverses heuristiques pour détecter la présence d'un portail captif afin, par exemple, de permettre une connexion automatisée. Mais ces heuristiques ne marchent évidemment pas toujours. (D'autant plus qu'il semble que certains points d'accès font tout pour empêcher ces heuristiques de marcher, afin d'empêcher les connexions automatisées.)

Idéalement, il faudrait un protocole nouveau permettant aux portails captifs de se signaler, sans avoir à jouer les Hommes du Milieu. Mais, même si un tel protocole était nnormalisé demain, il faut se rappeler que la plupart des points d'accès ne sont jamais mis à jour... (Un hôtel, par exemple, se moque pas mal de si son portail captif marche bien ou pas.)

L'atelier STRINT a ensuite vu les participants se répartir en petits groupes (break-outs) pour discuter en profondeur certains sujets. Par exemple, l'un de ces groupes s'attaquait à l'analyse des clients. Si certains ignorants ne considèrent que les navigateurs Web, les participants à l'atelier savaient bien, eux, qu'il existe une grande variété de logiciels clients. L'un des problèmes de ces clients est « que faire lorsqu'un certificat pose un problème ? » Certains administrateurs système disent simplement aux utilisateurs « continuez, ne vous inquiétez pas de cet avertissement », conseil qu'il sera difficile de faire désapprendre aux utilisateurs ensuite. Peut-être faudrait-il que les logiciels clients ne fournissent plus d'option pour passer outre un problème de certificat. Mais un tel changement devrait être fait plus ou moins simultanément par tous les auteurs de logiciels de cette catégorie. Autrement, il y a un risque que l'utilisateur croit que les logiciels les plus sûrs sont en tort, en l'empêchant de se connecter à son serveur.

Autre problème d'interaction entre la sécurité informatique et les facteurs humains, le cas des certificats auto-signés. Si un tel certificat est évidemment inacceptable pour une banque ou pour GitHub, pour un site personnel, il peut être tout à fait valable et en tout cas meilleur qu'une communication en clair. Un des aspects délirants de l'usage de HTTPS aujourd'hui est que bien des gérants de serveurs personnels n'activent pas HTTPS car obtenir un certificat est cher et compliqué, et utiliser un certificat auto-signé provoquerait des avertissements de sécurité injustifiés. Résultat : on reste en clair...

Un autre groupe travaillait sur l'activation par défaut des meilleurs choix de sécurité. Quant l'IETF dit que tous les programmes DOIVENT (MUST, cf. RFC 2119) mettre en œuvre tel protocole ou tel algorithme, cela veut dire qu'il doit être présent dans le code (MTI ou Mandatory To Implement, cf. RFC 3365). Mais cela ne signifie pas qu'il sera utilisé, s'il faut une action explicite de l'utilisateur ou de l'administrateur système pour l'activer. La très grande majorité des utilisateurs, et la plupart des administrateurs système, ne changent pas les réglages par défaut. Si on veut vraiment combattre la surveillance généralisée, il ne suffit pas d'avoir 2 ou 3 % des utilisateurs qui sont protégés. Il faut que presque tous le soient, donc passer du MTI au MTU (Mandatory To Use).

Enfin, un autre groupe break-out a planché sur la notion de « sécurité opportuniste » (opportunistic security). Le terme est très utilisé dans les milieux de la sécurité informatique mais n'a pas de définition précise. Plusieurs auteurs ont essayé d'en donner une définition (voir par exemple le RFC 4322) mais ces définitions sont très différentes les unes des autres. Depuis, l'IETF a publié la sienne, dans le RFC 7435.

On l'a dit, ce RFC arrive bien tard après l'atelier. Depuis, du travail a été fait. Juste après l'atelier, la réunion IETF de Londres a logiquement beaucoup couvert ces questions de protection contre l'espionnage. Ce fut par exemple la « DNSE BoF », première réunion physique du projet « DNS et vie privée », qui a depuis débouché sur le RFC 7626.

La totalité des articles présentés est en ligne.


Téléchargez le RFC 7687


L'article seul

RFC 7686: The .onion Special-Use Domain Name

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : J. Appelbaum (The Tor Project,), A. Muffett (Facebook)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 24 octobre 2015


Le TLD .onion est utilisé par Tor pour nommer des serveurs Internet dont la localisation exacte est cachée. Tor est surtout connu pour permettre aux clients de demeurer relativement intraçables pendant leurs activités sur l'Internet, et .onion étend cette possibilité aux serveurs. Ce TLD n'avait aucune forme d'existence officielle avant, il avait juste été choisi comme cela et était reconnu par les logiciels Tor. Désormais, il est stocké dans le registre des noms de domaine spéciaux créé par le RFC 6761.

C'est politiquement une certaine forme de reconnaissance de la part de l'IETF pour ces services cachés de Tor (que TF1 et les ministres nomment le Dark Web). Mais cela ne changera pas grand'chose en pratique, .onion était utilisé depuis des années, illustrant d'ailleurs la déconnexion entre la réalité et certains professionnels de la gouvernance Internet, qui croient que l'ICANN est le « régulateur de l'Internet ».

Techniquement, cet enregistrement de .onion dans le registre des noms de domaine spéciaux mènera peut-être certains logiciels à intégrer une connaissance de ce TLD, pour ne pas faire de requêtes .onion dans le DNS (requêtes involontaires et qui peuvent « trahir » un utilisateur de Tor).

La section 1 de notre RFC rappelle le principe de Tor et des .onion. Tor est spécifié dans « Tor: the second-generation onion router ». Ses services cachés (dont la localisation du serveur est caché : le service lui-même est parfaitement visible, c'est le but) sont identifiés par un nom de domaine en .onion. Par exemple, celui de Facebook, société dont un employé est co-auteur du RFC, est facebookcorewwwi.onion. Comme c'est un nom de domaine, il peut s'utiliser partout où on utilise un nom de domaine, par exemple dans les URI. Ainsi, le blog d'Amaelle Guiton est accessible en http://ozawuyxtechnopol.onion/. Comme ce nom est spécial, on n'utilise pas le DNS pour trouver des données comme l'adresse IP. Un nom en .onion est un identificateur cryptographique (c'est le condensat de la clé publique du serveur). Il est « auto-authentifiant » ce qui veut dire que le client peut s'assurer qu'il parle au bon serveur, via la signature de la communication par la clé du serveur, sans avoir besoin, par exemple, d'un certificat, et ceci que le réseau sous-jacent soit de confiance ou pas. Comme l'identificateur est un condensat cryptographique, il n'est normalement pas compréhensible par un humain (voir la section 4 pour une nuance à cette affirmation, comme dans le cas du nom de Facebook ci-dessus).

Les noms en .onion sont générés localement, sans utiliser une autorité distincte (voir les explications pour mon blog). Aucun registre n'est utilisé (lors de la chaude discussion à l'IETF sur ce RFC, une minorité avait protesté contre le fait que cet enregistrement du TLD privait l'ICANN d'une source de revenus). On n'enregistre pas un nom en .onion, on ne le vend pas, on n'en est « propriétaire » que parce qu'on connait la clé privée correspondante (au passage, comme avec tous les identificateurs cryptographiques, de Namecoin à BitMessage, attention à vos clés privées ! Si elles sont perdues, vous n'avez aucun recours).

On a vu que .onion n'utilise pas le DNS. Pour éviter les collisions entre un nom extérieur au monde du DNS et un nom identique qui serait dans le DNS, le RFC 6761 avait introduit le concept de « noms de domaine spéciaux ». Ces noms ont la syntaxe et une partie de la sémantique des noms utilisés dans le DNS mais ne sont jamais supposés apparaitre dans le DNS. Dans le registre des noms spéciaux, on précise ce que doivent faire les différents composants du DNS (bibliothèques, résolveurs, registres, etc) s'ils rencontrent ces noms. À part les noms du RFC 2606, devenus « spéciaux » par la suite, le premier nom spécial enregistré était le .local d'Apple, via le RFC 6762. Comme pour .local, notre nouveau RFC demande que .onion soit traité spécialement par les logiciels DNS. En pratique, évidemment, cette demande ne sera pas honorée par tous et il y aura donc pendant encore longtemps des « fuites », des requêtes DNS pour .onion qui arrivent aux serveurs racine. Au moment de la publication de notre RFC, .local était le troisième TLD le plus demandé à la racine (derrière les indéboulonnables .com et .net, cf. les statistiques du serveur racine L) et le premier, de très loin, des TLD inexistants. Par comparaison, les fuites pour .onion sont négligeables.

La section 2 du RFC décrit quelles sont ces règles que devraient suivre les logiciels DNS (cette section est obligatoire pour mettre un nom dans le registre des noms spéciaux, cf. RFC 6761, section 5). Donc, voici les différents composants du DNS qui devraient (idéalement) traiter les .onion à part :

  • Les utilisateurs humains doivent savoir que les .onion ont des propriétés de sécurité particulières, et qu'ils ne sont accessibles qu'avec un logiciel spécial (comme le Tor Browser).
  • Les applications comme les navigateurs Web qui mettent en œuvre Tor doivent reconnaitre les noms en .onion et les passer à Tor. Les autres devraient générer une erreur tout de suite et ne pas tenter ces noms dans le DNS.
  • Les bibliothèques qui font de la résolution de noms (comme la glibc) doivent passer ces noms à Tor ou bien générer une erreur « ce nom n'existe pas », sans utiliser le DNS.
  • Les résolveurs DNS doivent renvoyer l'erreur NXDOMAIN (No Such Domain), idéalement sans utiliser le DNS, comme dans les deux catégories précédentes.
  • Les serveurs faisant autorité (a priori, cela ne concerne que ceux de la racine, les autres n'ayant aucune raison d'être interrogés pour ce nom) doivent également répondre NXDOMAIN.
  • D'ailleurs, les opérateurs de serveurs DNS ne doivent pas configurer un serveur pour répondre pour ces noms, qui ne doivent être traités que par Tor.
  • Les registres et BE ne doivent évidemment pas accepter d'enregistrer des noms en .onion...

Le RFC précise explicitement que l'IANA est autorisée à mettre dans la zone racine un mécanisme pour réserver le nom (comme, je suppose, celui du RFC 7535). Et que les opérateurs non-DNS (par exemple les AC, voir la déclaration du CAB sur les .onion) peuvent évidemment stocker des noms en .onion.

Pourquoi ces demandes répétées de ne pas tenter de résoudre les noms dans le DNS ? Car cela ferait connaitre à l'extérieur, en clair, les services Tor cachés auquel vous tentez d'accéder, ce qui annulerait l'effet anonymisant de Tor. Par exemple, ici j'utilise par erreur un logiciel non-Tor pour accéder au blog d'Aeris :

% curl http://blog.aeriszyr4wbpvuo2.onion/
curl: (6) Could not resolve host: blog.aeriszyr4wbpvuo2.onion
   

Et si quelqu'un d'indiscret, sur un serveur racine, regardait le trafic, il a vu (ici, avec tcpdump) :

18:36:10.252749 IP6 2001:db8:8bd9:8bb0:21e:8cff:fe76:29b6.33562 > 2001:1608:10:167:32e::53.53: \
                65162% [1au] A? blog.aeriszyr4wbpvuo2.onion. (56)
18:36:10.284260 IP6 2001:1608:10:167:32e::53.53 > 2001:db8:8bd9:8bb0:21e:8cff:fe76:29b6.33562: \
                65162 NXDomain*- 0/9/1 (1129)

que non seulement je suis un mauvais citoyen qui utilise Tor malgré les injonctions d'un gouvernement bienveillant qui explique qu'il ne faut utiliser que la « cryptographie légale », mais en plus l'indiscret a le nom du site qui m'intéressait (RFC 7626).

En parlant du risque de fuite, la section 4 de notre RFC est consacrée à la sécurité. Outre ce problème de logiciels trop bavards qui en révèlent trop à l'extérieur via les requêtes DNS, elle mentionne le risque de se tromper de nom .onion.

En effet, les noms en .onion sont certes auto-vérifiables, via la cryptographie, mais cela suppose d'utiliser le bon nom. Si un utilisateur se trompe, ou bien fait trop confiance à un nom indiqué sur un canal IRC de numéristes radicalisés, il peut atterrir sur le mauvais site .onion. Le risque est d'autant plus élevé que les noms en .onion sont typiquement illisibles par un humain (des techniques, coûteuses en temps de calcul, permettent de générer des noms plus jolis, comme celui de Facebook cité plus haut).

Les utilisateurs pourraient aussi se faire avoir par ignorance de la syntaxe des noms de domaine. Par exemple, un utilisateur ordinaire pourrait être trompé en croyant que www.onion.example est protégé par Tor ce qui n'est pas du tout le cas.

Il y a aussi des attaques plus techniques. Un nom en .onion est le condensat d'une clé cryptographique. Casser cette clé (trouver la partie privée en n'ayant que la partie publique) nécessite des ressources de calcul colossales mais trouver une clé ayant le même condensat (et donc le même nom .onion) est moins coûteux (tout est relatif : il faudra quand même de la puissance de calcul et du temps), et cela pourrait permettre de créer un faux service caché indistinguable du vrai.

Si vous voulez en savoir plus sur comment fonctionnent ces noms en .onion (je trouve personnellement que la documentation disponible est insuffisante), voyez les guides officiels « Special Hostnames in Tor » et « Tor Rendezvous Specification ».

L'enregistrement de .onion dans les noms de domain spéciaux a été l'occasion d'un long et houleux débat à l'IETF, tournant parfois au psychodrame, comme toujours quand on parle des TLD. En gros, il opposait les « conservateurs », méfiants vis-à-vis de ces nouveaux services pair à pair et soucieux de rester « respectable » aux yeux de l'ICANN, aux « pairàpairistes » qui ne se soucient pas de l'ICANN et ne sont pas satisfaits du système de nommage actuel. Le RFC 6761, qui fournit la base de cet enregistrement, a été très contesté (bien plus que lorsqu'il a servi à enregistrer le TLD d'Apple .local...). L'IETF a finalement pris la décision d'enregistrer .onion mais de fermer la porte juste après aux autres demandes en attente (comme .gnu ou .bit) en attendant une éventuelle révision du RFC 6761. Voici l'article qui annonce cette décision. Ce sera un des points chauds de la prochaine réunion de l'IETF à Yokohama.


Téléchargez le RFC 7686


L'article seul

RFC 7682: IRR & Routing Policy Configuration Considerations

Date de publication du RFC : Décembre 2015
Auteur(s) du RFC : D. McPherson (Verisign), S. Amante (Apple), E. Osterweil (Verisign), L. Blunk (Merit Network), D. Mitchell (Singularity Networks)
Pour information
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 13 décembre 2015


On le sait, il n'y a pas de chef de l'Internet. Personne ne reste dans un bureau toute la journée avec pour mission l'envoi de règles qui seront immédiatement appliquées par tous les acteurs de l'Internet. C'est même le cas des fonctions les plus essentielles de l'Internet comme l'échange des tables de routage. Tout l'Internet ne tient que parce que les opérateurs sont d'accord entre eux pour s'échanger l'information qui se retrouvera dans ces tables « pour joindre le préfixe 2001:db8:fe2::/48, passez par moi, je connais un chemin que j'ai appris des AS 64499 puis 429496613 ». Cet accord de principe se double d'un accord technique sur le protocole à utiliser : BGP, normalisé dans le RFC 4271. Et au-delà, rien, aucun accord : chaque opérateur est libre de sa politique et notament de ce qu'il accepte ou refuse. Un opérateur peut refuser les préfixes plus spécifiques que /32, par exemple. Chacun est maître chez soi. En pratique, bien des opérateurs refusent les préfixes qui ne sont pas dans un IRR. C'est quoi, un IRR ? Qui les gère ? Qui décide de ce qu'on met dans un IRR ?. Ce nouveau RFC explore la question.

Un IRR (Internet Routing Registry) est une base de données stockant des préfixes d'adresses IP et des informations de politique associées comme, par exemple, le ou les AS qui sont autorisés à annoncer ce préfixe en BGP ou bien les communautés BGP (RFC 1997) utilisées. Le RFC 1787, dans sa section 7, décrit l'importance de partager l'information entre les opérateurs. Certes, chacun est maître chez lui, mais tout serait plus simple si chacun partageait avec les autres, pour limiter le risque de décisions malencontreuses.

Mais les IRR ont des problèmes et des limites (introduction en section 3). Première catégorie de problèmes, l'exactitude et l'intégrité des données stockées (section 4). Comme tous les registres utilisés sur l'Internet, les IRR sont plein de données fausses ou dépassées. Les personnes qui mettent ces données dans les registres n'ont guère de motivations pour mettre des données correctes et encore moins pour les mettre à jour. Les données sont donc souvent erronées.

En outre, il n'existe pas de moyen largement déployé de vérifier ces données dès le départ. Si Pakistan Telecom met dans un IRR qu'ils sont autorisés à annoncer le préfixe de YouTube, comment vérifier qu'ils ont le droit de le faire ? Le langage utilisé pour les IRR, RPSL (normalisé dans le RFC 2622) le permet techniquement mais en l'absence d'un mécanisme de signature cryptographique entre le préfixe et l'AS, cela ne permet pas de s'assurer de l'authenticité du contenu de l'IRR. Le RFC note à juste titre que cette absence de mécanisme de signature vient en partie d'un manque d'intérêt de la communauté des opérateurs : tout le monde se plaint des détournements BGP mais personne n'est prêt à faire les considérables efforts qu'il faudrait pour tout certifier.

Bien sûr, certains IRR ont des mesures de sécurité (par exemple, dans la base RIPE, seul le titulaire d'un préfixe peut ajouter des routes pour ce préfixe, cf. RFC 2725 et c'est une obligation contractuelle, cf. ripe-637) mais cela ne s'étend pas aux autres IRR, qui ne peuvent pas vérifier que cette sécurité a été respectée. Difficile donc de savoir quelle politique de sécurité a été utilisée par un IRR donné.

Même quand les données sont correctes, en l'absence de mécanismes de vérification fondés sur la cryptographie, on peut parfois se retrouver avec des données fausses alors qu'elles étaient justes au départ.

Il existe de nombreuses propositions pour créer de tels systèmes de vérification et de certification (TASRS, HotNets-X et bien sûr la RPKI) mais aucune n'a encore un déploiement suffisant.

Comme indiqué plus haut, une partie du problème est le manque de motivation : le titulaire d'une ressource Internet (un préfixe IP, par exemple) peut avoir un intérêt direct à ajouter une information dans un IRR (par exemple parce que son transitaire est strict, et lui impose cet ajout, avant d'accepter l'annonce BGP du titulaire) mais il a rarement de raison objective de le maintenir à jour ou, surtout, de le détruire quand il n'est plus utilisé. Certains acteurs bâtissent leurs filtres d'annonces BGP à partir des IRR, ce qui fait qu'une information manquante se paie d'un manque de visibilité BGP. Mais il n'y a aucune pénalité à avoir de l'information en trop. Si un client, titulaire d'un préfixe IP, passe d'un transitaire strict, qui lui imposait une entrée dans un IRR (par exemple un objet route dans la base RIPE-NCC) vers un transitaire laxiste qui n'impose rien, le client n'a aucune motivation (à part la pureté de l'IRR, qui n'intéresse qu'une poignée de barbus fanatiques utilisant OpenBSD) à changer l'ancienne entrée. Il la laissera probablement telle quelle. Le nouveau transitaire, qui ignore l'IRR, n'en tiendra pas compte.

Une des rares motivations concrètes qui pourrait mener à un nettoyage des IRR est le manque de mémoire dans les routeurs : les filtres pourraient devenir trop gros, si personne ne nettoie jamais. Heureusement pour les utilisateurs des routeurs, mais malheureusement pour la pureté de l'IRR, les routeurs PE modernes ont en général assez de mémoire dans leur module de routage (control plane) pour que cela ne soit plus un problème.

Autre problème avec les IRR, le fait que leur modèle de sécurité soit en général basé sur « le titulaire peut tout, les autres ne peuvent rien ». Si une information est dépassée, un tiers qui s'en aperçoit ne peut rien faire, seul le titulaire est autorisé à la modifier. Pas moyen de nettoyer pour compenser la négligence d'un titulaire. C'est pour cela que le RFC 2725 avait prévu le mécanisme auth-override, qui semble n'avoir jamais été mis en œuvre.

Pour accéder aux données des IRR, on utilise souvent whois. Un exemple (une liste des IRR existe en ligne) :

%  whois -h whois.radb.net 192.134.5.10  
route:          192.134.5.0/24
descr:          NIC-FR-SITE-TH3
origin:         AS2485
mnt-by:         FR-NIC-MNT
mnt-lower:      FR-NIC-MNT
mnt-routes:     FR-NIC-MNT
changed:        jean-philippe.pick@nic.fr 20110214
remarks:        Peering:   peering@nic.fr
remarks:        NOC:       noc@nic.fr
remarks:        Info:      http://www.nic.fr/
source:         RIPE
remarks:        ****************************
remarks:        * THIS OBJECT IS MODIFIED
remarks:        * Please note that all data that is generally regarded as personal
remarks:        * data has been removed from this object.
remarks:        * To view the original object, please query the RIPE Database at:
remarks:        * http://www.ripe.net/whois
remarks:        ****************************
    

On y voit que seul l'AS 2485 est autorisé à être l'origine d'une annonce pour le préfixe 192.134.5.0/24.

Un plaisir des IRR existants est qu'on n'a pas de moyen simple, étant donné une ressource Internet (par exemple un préfixe IP), de savoir quel IRR utiliser. Les clients logiciels existants doivent utiliser diverses heuristiques. Par exemple GNU whois utilise un fichier de configuration local - /etc/whois.conf, des règles incluses dans le client - fichier ip_del_list dans le source, et compte sur le serveur whois de l'ARIN pour le rediriger, pour les ressources inconnues (cette fonction de redirection étant une extension absente du protocole officiel whois, normalisé dans le RFC 3912).

À noter que whois ne fournit aucune confidentialité : le protocole est du simple TCP en clair sur le port 43. (Le protocole RDAP, lui, fournit un mécanisme de chiffrement via TLS.)

La section 5 de notre RFC se penche sur le fonctionnement interne des IRR et notamment sur leur synchronisation. Il est fréquent en effet que les IRR copient les données gérées par d'autres IRR. Cela se fait en général avec le protocole NRTM (protocole ressemblant à whois, et qui est peu ou pas documenté). Ce protocole n'a aucun mécanisme de sécurité (en pratique, la seule protection est la limitation d'accès à certaines adresses IP) et est peu robuste (des erreurs de synchronisation ont déjà eu lieu). Il fonctionne en mode pull et il n'y a pas de mécanisme de notification pour indiquer la présence de données récentes. Une autre façon de synchroniser des IRR est de télécharger un fichier plat, par exemple en FTP, qu'on applique ensuite à la copie locale (ce qui facilite l'application de modifications locales). Ce téléchargement et cette synchronisation sont typiquement faits toutes les 24 heures (une période qui date de l'époque où les réseaux étaient plus lents qu'aujourd'hui, et qui n'a pas toujours été réévaluée depuis), ce qui fait que les données ne sont pas forcément de la première fraicheur. On notera que le logiciel irrd synchronise toutes les dix minutes, par défaut.

Un standard existe pour cette réplication d'IRR, le RFC 2769, mais il ne semble pas avoir jamais eu le moindre succès, peut-être parce qu'il dépend du standard de sécurité RFC 2725, également peu ou pas répandu.

Les filtres effectivement utilisés par les routeurs de l'opérateur sont créés à partir d'un IRR, et cette création implique une autre étape (et les délais associés). Typiquement, l'opérateur utilise un logiciel comme IRRtoolset, qui va traduire les objets trouvés dans l'IRR en règles pour un type de routeur donné. Ce logiciel ne tourne pas en permanence. Conséquence pratique : un changement dans l'IRR a intérêt à ne pas être urgent ! Il n'y a aucun moyen de forcer les opérateurs à télécharger tout de suite les nouvelles données, et à faire tourner la « moulinette » qui va produire les règles pour les routeurs. Si on est un client payant de l'opérateur, on peut parfois les appeler et obtenir que cette opération soit faite de suite, mais ce n'est pas toujours le cas.

Idéalement, lorsqu'une politique change (par exemple un AS annonce un nouveau préfixe), il « suffit » de changer l'IRR, d'attendre les copies dans les autres IRR, puis l'exportation des données depuis les IRR vers les routeurs. Mais le protocole BGP ne permettait pas forcément de changer les caractéristiques d'une session en vol (section 6 de notre RFC) et exigeait une opération de réinitialisation, pour que le routeur accepte les nouvelles routes. Pendant cette opération, tout ou partie du travail normal du routeur était mis en attente... Résultat, cette opération (clear ip bgp neighbor... sur les Cisco...) ne pouvait se faire que pendant les périodes de maintenance. C'est un bon exemple d'un cas où les « bonnes pratiques » (n'accepter que les préfixes décrits dans les IRR) sont irréalisables dans un environnement de production (cf. section 8). Le yakafokon ne marche pas bien dans le monde des réseaux.

Heureusement, ce problème spécifique appartient largement au passé : les extensions à BGP des RFC 2918 et RFC 7313 ont largement supprimé ces obligations.

Il y a aussi les limites inhérentes à certaines mises en œuvre de BGP (section 7 du RFC). Par exemple, au milieu des années 1990, la plupart des routeurs ne permettaient pas de modifier les listes de préfixes acceptés de manière incrémentale : il fallait effacer la liste, puis installer une nouvelle liste, créant ainsi une fenêtre de vulnérabilité pendant laquelle des routes pouvaient fuir. Là aussi, ce problème a largement disparu avec les progrès des routeurs (voir aussi les sections 1 et 8, qui expliquent bien que certains problèmes historiques d'utilisation des IRR sont désormais du passé).

Rien n'est gratuit en informatique : le stockage des listes de préfixes IP acceptés nécessite de la mémoire et, pendant longtemps, les routeurs disposaient de trop peu de mémoire (une NVRAM bien limitée, et très lente en écriture). Les routeurs modernes ont des mémoires flash ou SSD, voire des disques durs et ont donc une bien meilleure capacité. D'un autre côté, les exigences ont crû et la taille de certaines configurations peut toujours poser des défis aux mémoires des routeurs (voir « NTT BGP Configuration Size and Scope »).

Dernier problème, l'envoi aux routeurs des changements. Autrefois, il n'y avait aucun standard en ce sens. Chaque routeur avait son CLI et il fallait générer depuis l'IRR les quelques lignes de commandes qui allaient changer la configuration du routeur, lui faisant accepter de nouveaux préfixes, ou bien refuser ceux qui étaient acceptés. Le routeur recevait ensuite en telnet, puis SSH, l'ordre de charger ces quelques lignes en TFTP ou FTP, puis, plus tard, en SCP. On pouvait alors activer la nouvelle configuration.

De nos jours, il existe une norme pour cela, NETCONF (RFC 6241). On génère toujours des données depuis l'IRR, puis on utilise NETCONF pour les charger. Les données issues de la RPKI peuvent, elles, être envoyées en RTR (RFC 6810) mais cela ne concerne pas tout le reste de la configuration du routeur.

Un petit mot de sécurité pour finir (section 9 du RFC). Le but des IRR étant d'influencer le routage à distance, ces IRR sont donc des ressources sensibles : si quelqu'un peut pirater un IRR et y injecter de fausses données, il peut perturber le routage Internet. Si ce problème est trop fréquent, les opérateurs pourraient en arriver à ne plus utiliser les IRR. Une gestion rigoureuse de leur sécurité est donc cruciale.

Voilà, si vous voulez en savoir davantage sur les IRR, il y a bien sûr l'incontournable site http://www.irr.net/.


Téléchargez le RFC 7682


L'article seul

RFC 7680: A One-Way Loss Metric for IPPM

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : G. Almes (Texas A&M), S. Kalidindi (Ixia), M. Zekauskas (Internet2), A. Morton (AT&T Labs)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 1 février 2016


Une des tristes réalités de l'Internet d'aujourd'hui est que les paquets se perdent. Ils quittent la machine émettrice et ne sont jamais reçus par la machine réceptrice. Il y a de nombreuses causes à cela (abandon du paquet par un routeur surchargé, par exemple), mais ce RFC 7680, comme les autres documents du groupe de travail IPPM se focalise sur la mesure du phénomène, pas sur ses causes. Il définit donc une métrique « perte de paquet » permettant de comparer des mesures entre elles en sachant qu'on parle bien de la même chose. (Ce RFC remplace la première définition, qui était dans le RFC 2680.)

Comme les autres RFC décrivant des métriques, des grandeurs rigoureusement définies et qu'on va mesurer, il s'appuie sur les définitions et le vocabulaire des RFC 2330 et RFC 7312. Par ailleurs, il suit de très près le plan du RFC 2679, qui spécifiait la mesure du délai d'acheminement d'un paquet. Cette fois, ce qui est défini est une mesure binaire (un paquet est perdu ou bien ne l'est pas), Type-P-One-way-Loss, puis une statistique pour le cas où il y a plusieurs paquets, le taux de perte moyen. (Petit rappel : Type-P signifie que le rapport de mesure doit indiquer le type du paquet - protocole de transport, port, etc - car le résultat peut en dépendre. Cf. section 2.8.1.)

Pourquoi cette métrique est-elle utile ? La section 1.1 rappelle l'intérêt de connaître les pertes :

  • Certaines applications, notamment interactives, se comportent mal (ou pas du tout) si le taux de pertes dépasse un certain seuil.
  • Les applications plus ou moins temps-réel aiment encore moins les pertes de paquets que les autres applications.
  • Les protocoles de transport comme TCP compensent les pertes en réémettant les paquets mais un taux de pertes trop élevé les empêchera d'atteindre leur débit maximum.

Mais pourquoi mesurer les pertes sur un chemin aller-simple (one-way) plutôt que aller-retour (two-way) ? La célébrissime commande ping affiche en effet des pertes après un aller-retour (ici 57 %) :

% ping -c 19 198.51.100.80 
PING 198.51.100.80 (198.51.100.80) 1450(1478) bytes of data.
1458 bytes from 198.51.100.80: icmp_seq=1 ttl=46 time=168 ms
1458 bytes from 198.51.100.80: icmp_seq=5 ttl=46 time=167 ms
1458 bytes from 198.51.100.80: icmp_seq=6 ttl=46 time=167 ms
1458 bytes from 198.51.100.80: icmp_seq=9 ttl=46 time=169 ms
1458 bytes from 198.51.100.80: icmp_seq=10 ttl=46 time=167 ms
1458 bytes from 198.51.100.80: icmp_seq=13 ttl=46 time=168 ms
1458 bytes from 198.51.100.80: icmp_seq=15 ttl=46 time=168 ms
1458 bytes from 198.51.100.80: icmp_seq=18 ttl=46 time=167 ms
--- 198.51.100.80 ping statistics ---
19 packets transmitted, 8 received, 57% packet loss, time 18013ms
rtt min/avg/max/mdev = 167.407/168.034/169.066/0.639 ms

Mais les mesures aller-retour ont bien des limites :

  • Si le chemin est asymétrique, on mesure en fait les performances de deux chemins, l'aller et le retour, qui n'ont pas forcément les mêmes caractéristiques. Même si le chemin est symétrique (passage par les mêmes routeurs à l'aller et au retour), rien ne dit que les résultats soient les mêmes dans les deux sens : files d'attente différentes, QoS peut-être réglée différemment, etc.
  • Beaucoup d'applications, par exemple les transferts de fichiers, voient leurs performances dépendre essentiellement d'un seul chemin (pour un transfert de fichiers, celui que suivent les données, pas le chemin inverse par lequel ne transitent que les petits accusés de réception).

Mais les mesures aller-simple sont plus difficiles à effectuer entre autres parce qu'elles ont souvent besoin d'horloges synchronisées (section 1.2). Le principe de la mesure de notre métrique est en effet d'émettre un paquet depuis la machine source à un temps T et de l'attendre à la machine destination jusqu'au temps T + t (où t est le délai qu'on accepte d'attendre). Si les horloges des deux machines ne sont pas synchronisées, leurs mesures de T vont différer, faussant ainsi les résultats. La section 1.2 rappelle donc le vocabulaire à utiliser pour évaluer la synchronisation. Les gourous de l'horlogerie verront qu'il est différent de celui des documents UIT comme le G.810, « Definitions and terminology for synchronization networks ».

  • Synchronisation (synchronization) signifie que deux horloges sont d'accord entre elles sur l'heure qu'il est (time error pour l'UIT).
  • Correction (accuracy) désigne le degré d'accord entre une horloge et la vraie heure UTC (time error from UTC pour l'UIT). Deux horloges peuvent donc être synchronisées et néanmoins incorrectes (ce qui n'est pas un grave problème pour nos métriques aller-simple).
  • Résolution (resolution) est la précision de l'horloge. Certains vieux Unix n'avancent ainsi l'horloge que toutes les dix ms et sa résolution est donc de 10 ms (cela se voyait bien avec la commande ping, qui n'affichait que des RTT multiples de 10). L'UIT dit sampling period.
  • Décalage (skew) est le changement dans la synchronisation ou la correction. Il se produit lorsque l'horloge va plus ou moins vite qu'elle ne le devrait. L'UIT appelle cela time drift.

Une fois ces préliminaires achevés, la section 2 décrit la métrique principale de notre RFC, Type-P-One-way-Packet-Loss. Sa valeur est simplement 0 lorsque le paquet est arrivé et 1 autrement.

Il y a bien sûr davantage de choses à dire sur cette métrique. Par exemple (section 2.5), faut-il distinguer le cas où un paquet a vraiment été perdu et le cas où il est simplement arrivé en retard, après l'expiration du délai ? En théorie, on devrait attendre 255 secondes, la durée de vie maximale d'un paquet IPv4 (RFC 791, section 3.2, notez qu'IPv6 n'a aucune limite, cf. RFC 2460, section 8.2). En pratique, on attendra moins longtemps : après tout, pour beaucoup d'applications, un paquet en retard n'a aucun intérêt, on peut aussi bien le considérer comme perdu. C'est l'approche retenue ici. (Par exemple, l'outil de test DNS dig attend, par défaut, cinq secondes avant de considérer la réponse comme perdue.)

Et si le paquet arrive corrompu, le considère-t-on comme perdu ? Là encore, oui, pas de distinction. En effet, si le paquet est corrompu, on ne peut même pas être sûr qu'il était bien le paquet attendu, puisque les bits qui permettent de le reconnaître sont peut-être ceux qui ont été changés.

Même chose si le paquet est fragmenté et que certains des fragments n'arrivent pas du tout. On ne peut pas reconstituer le paquet, on le considère comme perdu. En revanche, la duplication, elle, n'est pas considérée comme une perte.

Notre RFC 7680 décrit une métrique (une grandeur définie rigoureusement), pas une méthodologie de mesure, encore moins un protocole. Toutefois, la section 2.6 donne des indications sur ce que pourrait être une telle méthodologie. Le mécanisme recommandé est de mettre une estampille temporelle dans le paquet émis, et de regarder à l'arrivée si on détecte le paquet au bout d'un temps « raisonnable ». À noter que cette méthode n'implique pas une stricte synchronisation des horloges entre les deux machines. On est loin d'un protocole complet (je n'ai pas l'impression qu'il ait jamais été mis au point) et, par exemple, on n'indique pas comment la destination sait qu'elle doit s'attendre à voir arriver un paquet.

Toute mesure implique des erreurs et des incertitudes et la section 2.7 les analyse. D'abord, si les horloges ne sont pas synchronisées du tout, un paquet peut être déclaré comme perdu à tort (si l'émetteur a une horloge qui retarde, le paquet arrivera tard et le destinataire aura pu s'impatienter et le considéré perdu). Même problème si le délai d'attente n'est pas raisonnable, si le destinataire renonce trop vite. Ces deux problèmes peuvent être évités en synchronisant à peu près les horloges (il suffit que leur écart soit petit par rapport au délai d'attente) et en choisissant bien le délai (par exemple, sur une liaison utilisant un satellite géostationnaire, la finitude de la vitesse de la lumière impose un délai d'attente minimum de 240 ms - 2 * 35 786 / 300 000).

Une troisième source d'erreur est plus subtile : le paquet peut arriver jusqu'à la machine de destination (donc le réseau fonctionne bien) mais celle-ci le rejeter car ses ressources (par exemple les tampons d'entrée/sortie) sont pleines. Pour éviter de compter à tort des paquets comme perdus, il faut s'assurer que la machine de mesure a des ressources suffisantes pour traiter tous les paquets.

La section 2.8 se penche sur la publication des résultats (voir aussi l'excellent RFC 6703). Par exemple, elle impose de publier le Type-P (comme vu plus haut, le taux de pertes peut être différent en TCP et en UDP, par exemple), le seuil de patience (« le pourcentage de paquets non arrivés au bout de 1 500 ms est de X % »), et recommande de publier, autant que possible, le chemin parcouru (entre deux machines, si le chemin change par suite de modifications de routage, le taux de perte va probablement changer).

La métrique présentée en section 2 était pour un paquet. La section 3 définit une métrique supplémentaire, Type-P-One-way-Packet-Loss-Poisson-Stream pour le cas où on utilise plusieurs paquets. Elle utilise une distribution de Poisson (ce n'est pas la seule possible mais elle est d'usage très fréquent). Et la section 4 s'en sert pour définir une statistique utile. Type-P-One-way-Packet-Loss-Ratio (section 4.1, attention, elle a changé de nom depuis le RFC 2680) est le taux de pertes moyen. Si on envoie cinq paquets et que quatre arrivent, elle vaut 0,2 (c'est ce qu'affiche ping sous l'intitulé % packet loss mais attention, ping fait une mesure aller-retour et pas aller-simple comme notre RFC).

Cette moyenne n'est pas toujours facile à évaluer. Ainsi, sur un lien Internet typique, le taux de pertes est bas (nettement moins de 1 %). Pour obtenir une valeur statistiquement significative, il faut souvent tester avec des centaines de paquets.

Comme le note la section 5, consacrée à la sécurité, un problème courant des mesures actives est qu'elles peuvent perturber le réseau qu'elle observent. Si ces mesures actives ne posent pas trop de problèmes de vie privée (on ne mesure pas le trafic existant, mais seulement celui qu'on a créé), elles peuvent par contre faire mal au réseau. Il faut donc prendre soin de ne pas injecter « trop » de paquets (cf. l'option -f de ping).

Après « les mesures qui font du mal au réseau », il y a un autre risque de sécurité, « le réseau qui fait du mal aux mesures ». Imaginons qu'on mesure les performances d'un opérateur réseau et qu'un concurrent envoie exprès un trafic intense au même moment, les résultats seront mauvais. La publication des résultats devrait donc être accompagnée d'une description des solutions utilisées qui permettent de limiter le risque de ce genre d'attaques. (Cela peut être aussi simple que de ne pas communiquer à l'avance les moments où se font les mesures.)

Le RFC mentionne aussi le risque d'une « mesure Volkswagen » : un opérateur peut reconnaître les paquets de mesure et leur donner un traitement préférentiel. Là encore, il faut indiquer les solutions choisies pour que les paquets de mesure ne soient pas favorisés (par exemple en faisant en sorte qu'ils ressemblent autant que possible à des paquets « normaux »).

La section 6 de notre RFC présente les (très faibles) différences avec la précédente norme, le RFC 2680. Le but principal du nouveau RFC (projet documenté dans le RFC 6576) était de faire avancer cette métrique sur le « chemin des normes » (cf. RFC 2026), de « proposition de norme » à « norme [tout court] ». Les tests du RFC 7290 (voir aussi le rapport sur le RFC 2680) ont montré que les métriques Internet étaient sérieuses et utilisables, justifiant cet avancement sur le chemin des normes.

Les changements dans le texte sont minimes, comme l'introduction des références au RFC sur la publication de mesures, RFC 6703 et à d'autres RFC publiés depuis (comme le RFC 4737 sur le réordonnancement des paquets), la correction de petites erreurs, l'accent plus important sur la protection de la vie privée, etc.


Téléchargez le RFC 7680


L'article seul

RFC 7679: A One-Way Delay Metric for IPPM

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : G. Almes (Texas A&M), S. Kalidindi (Ixia), M. Zekauskas (Internet2), A. Morton (AT&T Labs)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 1 février 2016


Ce RFC définit une métrique, une grandeur à mesurer, en l'occurrence le délai d'acheminement d'un paquet d'un point à un autre du réseau. Cela semble trivial, mais la définition rigoureuse de la métrique, permettant des mesures scientifiques et leur comparaison, prend vingt pages... Elle remplace l'ancienne définition, qui était normalisée dans le RFC 2679.

Comme tous les RFC du groupe de travail ippm, celui-ci s'appuie sur les définitions et le vocabulaire du RFC 2330, notamment la notion de Type-P (paquets IP ayant la même « signature », c'est-à-dire même protocole de couche 4, même numéro de port, etc, car certains équipements réseaux traitent différemment les paquets selon ces variables).

Commençons par le commencement, c'est-à-dire l'introduction, en section 1. Le RFC définit une métrique pour une mesure unique (un singleton) nommé Type-P-One-way-Delay, ainsi qu'un échantillonnage, pour le cas où la mesure est répétée, et enfin diverses statistiques agrégeant les résultats de plusieurs mesures. Pourquoi une telle métrique ? Comme le rappelle la section 1.1, celle-ci est utile dans des cas comme, par exemple :

  • Estimer le débit maximal qu'on obtiendra (avec certains protocoles comme TCP, il est limité par le RTT, cf. le RFC 7323).
  • La valeur minimale de ce délai d'acheminement nous donne une idée du délai dû uniquement à la propagation (qui est limitée par la vitesse de la lumière) et à la transmission. (Voir aussi la section 4.3.)
  • Par contre, son augmentation nous permet de détecter la présence de congestion.

Mais pourquoi un délai d'acheminement « aller-simple » et pas « aller-retour », comme le fait ping, ou bien comme le normalise le RFC 2681 ? Après tout, le délai aller-retour est bien plus simple à mesurer. Mais il a aussi des défauts :

  • Une bonne partie des routes sur l'Internet sont asymétriques. Le délai aller-retour dépend donc de deux délais aller-simple, qui peuvent être très différents.
  • Même si le chemin est symétrique, les politiques de gestion de la file d'attente par les routeurs peuvent être très différentes dans les deux sens.
  • Certains protocoles s'intéressent surtout aux performances dans une direction. C'est le cas du transfert d'un gros fichier, où la direction des données est plus importante que celle des accusés de réception.

Le RFC ne le mentionne apparemment pas, mais on peut aussi dire que la mesure d'un délai aller-retour dépend aussi du temps de réflexion par la machine distante (avec ping, si la machine visée est très chargée, la génération du paquet ICMP de réponse peut prendre un temps non négligeable ; c'est encore pire avec des protocoles applicatifs, où la réflexion n'est pas faite dans le noyau, et est donc sensible à par exemple, le swapping).

Comme avec tout système de mesure, les horloges et leurs imperfections jouent un rôle crucial. La section 2 rappelle des concepts (voir le RFC 2330) comme la synchronisation (le fait que deux horloges indiquent la même valeur) ou le décalage (le fait qu'une horloge aille plus ou moins vite qu'une autre).

Enfin, après tous ces préliminaires, le RFC en arrive à la définition de la métrique, en section 3. Type-P-One-way-Delay est définie comme une fonction de divers paramètres comme les adresses IP des deux parties et l'instant de la mesure. La mesure dépend aussi du Type-P (par exemple parce que certains ports sont favorisés par la QoS ; notez que si la QoS dépend d'une DPI, la définition du Type-P ne suffira pas). Elle est en secondes. Et sa définition (section 3.4) est « Le temps entre l'envoi du premier bit du paquet sur le câble et la réception du dernier bit du paquet depuis le câble ». Si le paquet n'arrive pas, le délai est dit « indéfini » et, en pratique, pris comme étant infini. Les programmeurs noteront donc qu'il n'est pas possible de mesurer cette valeur avec l'API Posix, qui ne donne pas accès à des détails aussi précis.

Ce n'est pas tout de définir une métrique, il faut aussi la mesurer. Dans le monde réel, cela soulève quelques problèmes, couverts par la section 3.5. Le principal étant évidemment la synchronisation des horloges. Si le paquet part à 1247389451,578306110 (en secondes depuis le 1er janvier 1970) et arrive à 1247389453,018393817, le délai a-t-il réellement été de 1,44 secondes ou bien seulement de 1,32 secondes mais les horloges différaient de 0,12 secondes ? Comme des délais peuvent être aussi bas que 100 µs, une synchronisation précise est nécessaire. Le GPS est une bonne solution pour cela, NTP une moins bonne, car sa résolution est plus faible (de l'ordre de plusieurs ms) et il dépend du réseau qu'on veut mesurer.

Il faut aussi tenir compte de problèmes comme les paquets perdus (si le délai de garde est de cinq secondes, un paquet perdu ne doit pas compter pour un délai d'acheminement de cinq secondes, ou bien des agrégats comme la moyenne seront complètement faussés) ou comme la duplication de paquets (dans ce cas, le RFC précise que c'est la première occurrence qui compte). Le délai de garde (délai d'attente maximal avant de considérer un paquet comme perdu) ne doit pas être trop bas, sinon on risque de sur-estimer les performances du réseau, en éliminant les paquets lentement acheminés.

Enfin, pour celui qui voudrait concevoir un protocole de mesure de cette métrique, le RFC suggère une méthodologie, en section 3.6 :

  • S'assurer de la synchronisation des horloges,
  • Former le paquet et y mettre l'instant de départ sur le câble (sur une machine non temps réel, cela peut être délicat de mettre cet instant exact),
  • À la réception, mesurer l'instant et calculer la différence avec ce qui est indiqué dans le paquet,
  • Évaluer l'erreur (il y en aura forcément) et, éventuellement, corriger.

Cette question de l'analyse d'erreur fait l'objet de la section 3.7. Les deux principales sources d'erreur seront liées aux horloges (qui ne sont jamais parfaites) et à la différence entre le temps de départ ou d'arrivée mesuré et le temps réel. Sur un système d'exploitation multi-tâches et non temps réel comme Unix, le temps entre le moment où le paquet arrive dans la carte Ethernet et celui où l'application peut appeler gettimeofday() est souvent significatif (section 3.7.2) et, pire, variable et imprévisible (car on dépend de l'ordonnanceur). Parmi les mécanismes pour déterminer l'erreur, de façon à pouvoir effectuer les corrections, le RFC suggère la calibration (section 3.7.3), en répétant de nombreuses fois la mesure. Cette partie sur l'analyse des erreurs est détaillée et explique en partie la longueur du RFC : la métrologie n'est pas une science simple !

À noter que les deux horloges, à l'arrivée et au départ, ont besoin d'être synchronisées mais n'ont pas forcément besoin d'être correctes. La correction reste quand même utile, car les délais peuvent dépendre de l'heure de la journée et il faut donc indiquer celle-ci dans le rapport final.

Une fois qu'on a bien travaillé et soigneusement fait ses mesures, il est temps de les communiquer à l'utilisateur. C'est l'objet de la section 3.8. Elle insiste sur l'importance d'indiquer le Type-P, les paramètres, la méthode de calibration, etc. Si possible, le chemin suivi par les paquets dans le réseau devrait également être indiqué.

Maintenant, la métrique pour une mesure isolée, un singleton, est définie. On peut donc bâtir sur elle. C'est ce que fait la section 4, qui définit une mesure répétée, effectuée selon une distribution de Poisson, Type-P-One-way-Delay-Poisson-Stream.

Une fois cette métrique définie, on peut créer des fonctions d'agrégation des données, comme en section 5. Par exemple, la section 5.1 définit Type-P-One-way-Delay-Percentile qui définit le délai d'acheminement sous lequel se trouvent X % des mesures (les mesures indéfinies étant comptées comme de délai infini). Ainsi, le 95e percentile indique le délai pour lequel 95 % des délais seront plus courts (donc une sorte de « délai maximum en écartant les cas pathologiques »). La section 5.2 définit Type-P-One-way-Delay-Median qui est la médiane (équivalente au 50e percentile, si le nombre de mesures est impair). La moyenne, moins utile, n'apparait pas dans ce RFC.

Au moins un protocole a été défini sur la base de cette métrique, OWAMP, normalisé dans le RFC 4656 et mis en œuvre notamment dans le programme de même nom.

Le but principal du nouveau RFC (projet documenté dans le RFC 6576) était de faire avancer cette métrique sur le « chemin des normes » (cf. RFC 2026), de « proposition de norme » à « norme [tout court] ». Les tests du RFC 6808 (voir aussi le rapport sur le RFC 2679) ont montré que les métriques Internet étaient sérieuses et utilisables, justifiant cet avancement sur le chemin des normes.

La section 7 décrit les (rares) changements depuis le RFC 2679. Le RFC 6808 notait plusieurs problèmes avec le RFC 2679, problèmes qui ont été traités par ce nouveau RFC 7679. Par exemple, la métrique Type-P-One-way-Delay-Inverse-Percentile, définie dans le RFC 2679 mais jamais mise en œuvre, est abandonnée. D'autre part, une bogue a été corrigée. Les autres changements sont l'introduction des références au RFC sur la publication de mesures, RFC 6703 et à d'autres RFC publiés depuis, ainsi que l'accent plus important sur la protection de la vie privée. Notre nouveau RFC note aussi que le groupe de travail a étudié les conséquences du RFC 6921 (dont vous noterez la date de parution) et conclut que, même avec des délais de propagation négatifs, les métriques décrites ici ne nécessitaient pas de mise à jour.


Téléchargez le RFC 7679


L'article seul

RFC 7676: IPv6 Support for Generic Routing Encapsulation (GRE)

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : C. Pignataro (Cisco Systems), R. Bonica (Juniper Networks), S. Krishnan (Ericsson)
Chemin des normes
Première rédaction de cet article le 23 octobre 2015


Le protocole GRE est le plus simple mécanisme de tunnel normalisé. Il est mis en œuvre sur d'innombrables systèmes, et très largement répandu. Pour reprendre la formule de James Raftery, GRE est « The AK-47 of guerrilla networking. Cheap, simple, gets all sorts of dirty jobs done. ». Il ne fonctionnait traditionnellement qu'avec IPv4 mais bien des mises en œuvre de GRE avaient été adaptées à IPv6 depuis longtemps. Ce RFC décrit cette adaptation.

GRE, spécifié dans les RFC 2784 et RFC 2890, permet de transporter n'importe quoi sur n'importe quoi. On peut faire de l'IPv4 dans IPv4, de l'IPv6 dans l'IPv6, de l'IPv4 dans IPv6 ou le contraire. En termes GRE, IPv6 peut être la charge utile (payload, IPv6 sur autre chose) ou bien le support (delivery, quelque chose sur IPv6).

Le format des en-têtes GRE (RFC 2784, section 2) ne change pas avec ce RFC. Il y a juste la forte recommandation de ne pas utiliser la somme de contrôle GRE. Cela diminue la charge de calcul pour les machines aux extrémités du tunnel GRE, charge qui était peu utile car cette somme de contrôle GRE est largement redondante avec celle que fournissent IP (pour IPv4 seulement), TCP ou UDP. Néanmoins, on a toujours le droit de mettre une somme de contrôle, en cas d'environnement très hostile. (Cf. RFC 6935 à propos des sommes de contrôle et des tunnels.)

D'abord, le cas où IPv6 est la charge utile (section 3 de notre RFC), encapsulé dans... ce qu'on veut, IPv4 ou IPv6. Dans l'en-tête GRE, le champ Protocol Type (RFC 2784, section 2.4) doit être mis à 0x86DD (c'est la même valeur que lorsque IPv6 est porté sur Ethernet, cf. RFC 7042).

Qui dit tunnel dit problèmes de MTU. Pour limiter les dégâts, notre RFC impose que tout tunnel GRE qui transporte de l'IPv6 ait une MTU d'au moins 1 280 octets, ce qui est la valeur minimum requise par IPv6. (Plus précisement, notre RFC demande que le tunnel puisse transporter des paquets de 1 280 octets sans utiliser la fragmentation IP. Cela peut se faire en ayant une MTU >= 1 280 octets ou bien en ayant un système de fragmentation et réassemblage sous IP.) Avec cette règle, on est au moins sûrs que les paquets IPv6 prudents (ceux limités à 1 280 octets) passeront.

En théorie, une mise en œuvre standard de GRE doit tester cette possibilité, avant d'envoyer des paquets IPv6. (Celles d'aujourd'hui ne le font apparemment pas souvent, cf. RFC 7588.)

Et si le point d'entrée du tunnel GRE reçoit un paquet qui est plus grand que la MTU du tunnel ? Rappelez-vous qu'une des principales différences entre IPv4 et IPv6 est que, en IPv6, les routeurs sur le trajet n'ont pas le droit de fragmenter : si c'est nécessaire, cela doit être fait à la source. (Notez aussi que les machines d'entrée et de sortie du tunnel font un travail proche de celui d'un routeur mais que ce ne sont pas exactement des routeurs.) Donc, si le paquet trop gros arrive, le point d'entrée du tunnel doit faire ce que fait un routeur IPv6 : jeter le paquet et envoyer un message ICMP Packet Too Big.

Et le contraire, IPv6 comme réseau sous-jacent, pour transporter n'importe quoi, de l'IPv4 ou de l'IPv6 (section 4 de notre RFC) ? Le paquet IPv6 va comporter l'en-tête IPv6, zéro, un ou davantage en-têtes d'extensions, puis la charge utile, faite d'un en-tête GRE et des données (un paquet IPv4 ou IPv6). S'il n'y a pas d'en-têtes d'extension IPv6, le champ Next Header d'IPv6 vaut 47 (la valeur enregistrée pour GRE). S'il y a un ou plusieurs en-têtes d'extension, le dernier doit avoir, dans son champ Next Header, cette même valeur 47.

Comme l'en-tête IPv6 n'a pas de somme de contrôle, une distribution du paquet à la mauvaise machine est toujours possible. Le comportement normal de cette machine qui reçoit un paquet inattendu est de le jeter silencieusement. Si elle parle GRE elle-même, elle peut faire la décapsulation et faire suivre le paquet (cela me semble très dangereux, permettant de faire relayer les paquets par des machines « ouvertes »).

Enfin, la section 6 de notre RFC se penche sur la sécurité de GRE. Cela va vite car elle est à peu près nulle (cf. RFC 6169). Notamment, contrairement à beaucoup de tunnels modernes, GRE ne chiffre pas. Si on veut de la confidentialité pour les données transportées, il ne faut pas utiliser GRE. GRE reste très utile quand on veut simplement contourner le routage IP normal et établir une forme de routage manuellement contrôlée (j'ai décrit un exemple réel d'un tel cas).

Comme indiqué plus haut, il existe déjà plusieurs mises en œuvre de GRE IPv6. Faisons quelques essais avec des machines Linux. D'abord, IPv6 dans IPv4 (oui, il existe d'autres protocoles que GRE pour tunneler IPv6 dans IPv4, je suis au courant, cf. RFC 7059 pour une comparaison des tunnels), donc en mode « IPv6 payload ».

% sudo ip tunnel add tun0 mode gre remote  10.254.112.180 \
             local 192.168.43.49  ttl 255
% sudo ip link set tun0 up
    

On a ici créé un tunnel GRE entre la machine locale, 192.168.43.49 et l'autre extrémité du tunnel, 10.254.112.180. On attribue maintenant des adresses IPv6 à l'interface tun0 :

% sudo ip -6 addr add fda1:1a36:de6d::2 dev tun0
% sudo ip -6 route add  fda1:1a36:de6d::/48 dev tun0
    

On fait pareil de l'autre côté du tunnel (en inversant évidemment remote et local). On peut maintenant se pinguer en IPv6 même si le FAI ne le fournissait pas (c'est le cas ici, avec un VPS OVH) :

% ping6  fda1:1a36:de6d::2 
PING fda1:1a36:de6d::2(fda1:1a36:de6d::2) 56 data bytes
64 bytes from fda1:1a36:de6d::2: icmp_seq=1 ttl=64 time=1.22 ms
64 bytes from fda1:1a36:de6d::2: icmp_seq=2 ttl=64 time=0.761 ms
64 bytes from fda1:1a36:de6d::2: icmp_seq=3 ttl=64 time=0.689 ms
^C
--- fda1:1a36:de6d::2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.689/0.893/1.229/0.239 ms
    

Plus amusant, tcpdump sait décoder le GRE et affiche donc bien ce qui s'est passé dans le tunnel :

16:46:02.240707 IP 10.254.112.180 > 192.168.43.49: GREv0, length 108: \
    IP6 fda1:1a36:de6d::1 > fda1:1a36:de6d::2: ICMP6, echo request, seq 1, length 64
16:46:02.240957 IP 192.168.43.49 > 10.254.112.180: GREv0, length 108: \
    IP6 fda1:1a36:de6d::2 > fda1:1a36:de6d::1: ICMP6, echo reply, seq 1, length 64
    

tcpdump a décapsulé le GRE, trouvé les paquets ICMP d'IPv6 et les a affichés.

Essayons maintenant l'inverse, « IPv6 delivery », c'est-à-dire de l'IPv4 encapsulé dans IPv6 (cela pourra servir lorsqu'on verra apparaître des FAI uniquement IPv6). Créons le tunnel (notez que le mode est ip6gre et plus gre) :

% sudo  ip -6 tunnel add tun0 mode ip6gre remote 2001:db8:2:245b::42 \
      local 2001:db8:8bd9:8bb0:666:6c7c:9bed:b390  ttl 255
% sudo ip -6 link set tun0 up
    

Donnons des adresses IPv4 :

% sudo ip  addr add 172.17.0.2 dev tun0
% sudo ip route add 172.17.0.0/24 dev tun0
    

Et on peut désormais pinguer en IPv4. tcpdump, là encore, sait décapsuler et afficher ce qui se passe dans le tunnel :

21:19:17.158171 IP6 2001:db8:2:245b::42 > 2001:db8:8bd9:8bb0:666:6c7c:9bed:b390: GREv0, length 88: \
         IP 172.17.0.1 > 172.17.0.2: ICMP echo request, id 32762, seq 1, length 64
21:19:17.238950 IP6 2001:db8:8bd9:8bb0:666:6c7c:9bed:b390 > 2001:db8:2:245b::42: GREv0, length 88: \
         IP 172.17.0.2 > 172.17.0.1: ICMP echo reply, id 32762, seq 1, length 64

Téléchargez le RFC 7676


L'article seul

RFC 7673: Using DNS-Based Authentication of Named Entities (DANE) TLSA Records with SRV Records

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : T. Finch (University of Cambridge), M. Miller (Cisco Systems), P. Saint-Andre (&yet)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dane
Première rédaction de cet article le 15 octobre 2015


Le protocole DANE, normalisé dans le RFC 6698, permet d'associer au nom d'un serveur un certificat qu'on peut comparer avec celui qui est présenté par le serveur lors d'une session TLS, authentifiant ainsi directement ou indirectement le serveur. Cela permet de boucher certaines failles de X.509. Mais DANE ne marche qu'avec un nom de serveur, tel que l'utilise HTTP. La quasi-totalité des protocoles ont, au contraire, une indirection supplémentaire entre nom de service et nom de serveur, typiquement via un enregistrement SRV (RFC 2782). Dans un tel cas, où trouver les enregistrements TLSA, ceux utilisés par DANE ? Le choix est de vérifier le domaine pointé (nom du serveur, celui du prestataire) et pas le pointeur (nom de service, celui de l'utilisateur).

Voici un exemple d'un enregistrement TLSA (au passage, ne cherchez pas à quels mots correspondent les lettres de TLSA : ce n'est officiellement pas un acronyme) classique, pour un serveur HTTP, en l'occurrence pour https://www.freebsd.org :


% dig TLSA _443._tcp.www.freebsd.org 
...
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 4, ADDITIONAL: 13
...
;; ANSWER SECTION:
_443._tcp.www.freebsd.org. 600 IN TLSA 3 0 1 (
				A9F16D689F5AEE122E86A8468A8586DDA4440A7298C6
				4AD4EED1AAE8BEB2A892 )
				...

    

Mais, à part HTTP (dont c'est l'une des principales faiblesses, menant à un mélange entre nom de service et nom de serveur), les protocoles utilisent en général un nom de service (vu par l'utilisateur) et un nom de serveur (récupéré automatiquement dans le DNS via les enregistrements SRV ou, dans le cas du courrier, des enregistrements MX). Il fallait donc étendre la définition originelle de DANE, celle du RFC 6698, pour ces protocoles. Pour SMTP et ses MX, c'est le RFC 7672. Pour les protocoles à SRV, comme XMPP, c'est ce RFC 7673.

Le choix principal qui se posait lors de la rédaction de ce RFC était « l'enregistrement TLSA doit-il être associé au service (l'origine, en partie gauche de l'enregistrement SRV) ou bien au serveur (la cible, en partie droite) ? » Le choix a été fait d'accrocher le TLSA, l'enregistrement DNS contenant le certificat au serveur. Ainsi, si on a cet enregistrement SRV pour XMPP à example.com :

_xmpp-client._tcp.example.com. SRV     1 0 5222 im.example.net.
    

L'enregistrement TLSA sera en im.example.net, pas en example.com. Les raisons de ce choix sont expliquées dans l'annexe B du RFC et résumées plus loin.

Pour la sécurité du lien entre service et serveur, on compte sur DNSSEC, qui signera l'enregistrement SRV (ainsi que, bien sûr, le TLSA). Maintenant, place aux détails concrets.

La section 3 du RFC commence par les tests DNS. Si l'utilisateur veut se connecter à un service foobar dans example.com, il va demander le SRV de _foobar._tcp.example.com. Supposons qu'il existe un alias (enregistrement CNAME) vers foobar.example.net et qu'ensuite on trouve le SRV qui liste un seul serveur, foobar1.example.org. Pour pouvoir utiliser DANE, il faut que toute la chaîne DNS soit sécurisée par DNSSEC. Dans cet exemple, les deux enregistrements qui forment la chaîne (le CNAME puis le SRV) doivent donc tous les deux être signés et validés. Sinon, si l'un de ces enregistrements n'est pas signé, pas question de lancer DANE puisqu'on ne peut pas avoir confiance dans leur contenu.

On n'en a pas fini avec le DNS : il faut maintenant trouver l'adresse IP des serveurs (ici, un seul), ce qui doit être également validé avec DNSSEC. Enfin, on fait les requêtes pour les enregistrements TLSA, en utilisant comme nom (le QNAME ou Query Name) le nom du serveur, préfixé du numéro de port. Si l'application foobar fonctionne sur le port 5634 (il est indiqué dans l'enregistrement SRV), on demandera ici le ou les TLSA de _5634._tcp.foobar1.example.org (et non pas d'example.com). Autre exemple, emprunté au RFC, avec IMAP, le SRV pour example.com valait :

      _imap._tcp.example.com. 86400 IN SRV 10 0 9143 imap.example.net.
    

On demandera donc un enregistrement TLSA pour _9143._tcp.imap.example.net. Évidemment, on vérifie la validité de cet enregistrement avec DNSSEC (ignorer les enregistrements non signés et donc non validés est un principe de base de DANE, cf. RFC 6698, section 4.1).

Le client se connecte en TLS au serveur. Quelles vérifications doit-il faire (section 4) ? S'il n'a trouvé aucun enregistrement TLSA utilisable (par exemple parce qu'il n'y en avait pas, ou bien parce qu'ils n'étaient pas signés avec DNSSEC), il doit faire la validation habituelle d'un certificat X.509 (à partir des AC que le client a dans son magasin), décrite dans le RFC 5280. Il peut être nécessaire d'utiliser quelques règles spécifiques à l'application, cf. RFC 6125. Au passage, notons que la terminologie est variable : ce que notre RFC 7673 nomme service et serveur est appelé dans la RFC 6125 « domaine source » et « domaine dérivé ».

Par contre, s'il y a des enregistrements TLSA et qu'ils sont utilisables (ce qui implique notamment qu'ils soient signés et validés), alors le client doit valider le certificat obtenu dans le dialogue TLS avec DANE (RFC 6698, section 2.1). Notamment, si l'enregistrement TLSA indique un usage « DANE-EE » (DANE End Entity), alors le client ne doit pas faire de vérification X.509 du tout et donc ignorer les RFC 5280 et RFC 6125.

Si vous êtes l'auteur d'un protocole qui utilise des enregistrements SRV, lisez la section 5 de notre RFC : elle écrit les détails auxquels vous devez penser pour votre protocole. Ce sont notamment :

  • Les éventuels mécanismes de repli si le client n'arrive pas à se connecter de manière sûre,
  • Comment les clients doivent-il faire s'ils ne trouvent pas d'enregistrement SRV ou s'ils ne savent pas faire de requêtes SRV (ce qui est un problème fréquent avec le JavaScript exécuté dans un navigateur Web).
  • La méthode générique en TLS pour indiquer le nom de domaine auquel on veut se connecter est l'extension SNI du RFC 6066. Certains protocoles ont une méthode à eux et il faut donc la documenter (par exemple, XMPP utilise l'élément <to> de son flux XML).
  • Utilisation d'éventuels autres mécanismes de découverte, en sus des SRV, comme les NAPTR (RFC 3403) utilisés par SIP.

Si vous êtes opérateur d'un service sécurisé avec TLS, voyez la section 6. Elle rappelle la nécessité de signer les enregistrements DNS SRV et TLSA avec DNSSEC. D'autre part, en créant le certificat qui sera servi en TLS, il faut suivre certaines règles :

  • Si l'enregistrement TLSA prévoit un usage DANE-EE, le ou les noms indiqué(s) dans le certificat n'ont pas d'importance pour DANE (cf. la section 9.2). D'un autre côté, les clients non-DANE ne pourront pas se connecter en TLS si les noms ne correspondent pas à ce qu'ils attendent.
  • Avec d'autres usages que DANE-EE, ou bien si on veut que le certificat marche même avec les clients non-DANE, il faut que le nom dans le certificat soit le nom de serveur et de préférence qu'il y ait aussi le nom de service (les règles exactes, compliquées, sont dans le RFC 6125). Dans un environnement où un fournisseur sert un grand nombre de domaines hébergés (environnement multi-tenant), mettre le nom du service va souvent être difficile.

L'extension SNI du RFC 6066, déjà citée, permet d'envoyer au client le bon certificat, si le serveur en a plusieurs. Un exemple d'un usage de TLSA où il faut vérifier le nom est l'usage DANE-TA où le certificat dans l'enregistrement TLSA autorise l'AC, pas le certificat du serveur. Cet usage empêche les attaques par une autre AC mais pas celles par un autre utilisateur de la même AC. Il faut donc vérifier que le(s) nom(s) dans le certificat est(sont) bien celui attendu (cf. section 9.2).

Après les auteurs de protocoles et les administrateurs système, place aux développeurs (section 7). Pour limiter le temps d'attente pour les utilisateurs, le RFC leur recommande de faire les différentes résolutions aussi en parallèle que possible. Par exemple, une fois obtenu un SRV, on peut faire les résolutions d'adresse (enregistrements A et AAAA) en même temps que le TLSA.

La section 9 du RFC revient sur quelques pièges de sécurité. D'abord, un ensemble d'enregistrements SRV pouvant contenir plusieurs noms de serveurs, il ne faut pas croire que tous auront le même niveau de sécurité, surtout si l'un d'eux est sous-traité à un opérateur ne servant qu'en cas de problème avec les serveurs « principaux ». Par exemple, certains peuvent accepter TLS et d'autres pas. Il sera donc inutile de chercher des enregistrements TLSA pour les seconds. Ce point est d'autant plus important que le traitement des enregistrements SRV ne donne aucune priorité aux serveurs ayant TLS.

L'annexe B de notre RFC est cruciale et doit absolument être lue. Elle revient sur un choix qui a été délicat et très discuté à l'IETF : l'enregistrement TLSA doit-il se situer sur le nom de service (domaine originellement indiqué par l'utilisateur et donc a priori le domaine important qu'on veut vérifier) ou bien sur le nom de serveur (obtenu après une requête SRV et information normalement purement technique) ? Le choix de notre RFC 7673 est clair : le TLSA pertinent est situé sur le nom du serveur, essentiellement parce que c'est la seule méthode réaliste pour les services hébergés chez un gros opérateur qui a des milliers, voire des millions, de client hébergés.

Des raisons diverses viennent à l'appui de ce choix :

  • Le certificat fait partie de la configuration du serveur. Il est donc logique de mettre le TLSA au nom du serveur.
  • Pensez à un changement de certificat : si le TLSA est lié au serveur, il n'y a qu'un seul changement dans le DNS. S'il est lié au client, il y en aura autant que de domaines hébergés (et certains l'oublieront probablement).
  • Si le client n'utilise pas SNI, le certificat servi devra lister tous les domaines de tous les hébergés (comme on le voit sur des gros hébergeurs comme CloudFlare, où https://www.republique-numerique.fr/ partage son certificat avec un site porno chinois, https://renxxx.com/).
  • Avec la méthode choisie, le même certificat marchera pour une connexion via un SRV et aussi pour une connexion directe quand on connait le nom du serveur, ce qui peut être pratique pour le débogage.
  • Certains protocoles applicatifs permettent d'envoyer des messages pour plusieurs domaines en une seule transaction. Cela ne serait plus possible si l'enregistrement TLSA était lié au service. Un exemple d'un tel protocole est SMTP (qui n'utilise pas SRV mais c'est juste un exemple) lors de plusieurs RCPT TO vers des domaines différents.
  • Pour certains protocoles (là encore, c'est le cas de SMTP), un serveur peut jouer plusieurs rôles (par exemple, pour SMTP, cible des enregistrements MX, en réception, mais aussi envoyeur). Il est plus simple de n'avoir qu'un certificat pour tous les cas.

Bien sûr, il y a des cas où le TLSA sur le nom du service (du domaine source) serait préférable. L'IETF avait envisagé de permettre cette possibilité, en plus de la « normale » mais y a renoncé pour garder le protocole simple. Dans certains cas (clients non-DNSSEC, par exemple, qui ne peuvent donc pas valider le SRV et doivent donc vérifier le domaine d'origine), cela compliquera les choses (SNI aidera parfois).

Allez, un exemple réel d'un enregistrement SRV avec DANE au bout :

% dig +nodnssec +short SRV _xmpp-server._tcp.mailbox.org           
0 5 5269 xmpp.mailbox.org.

%  dig +nodnssec +short TLSA _5269._tcp.xmpp.mailbox.org
3 1 1 4758AF6F02DFB5DC8795FA402E77A8A0486AF5E85D2CA60C294476AA DC40B220
    

Et je vous recommande de lire cet excellent article sur la sécurisation de XMPP avec DNSSEC et DANE.


Téléchargez le RFC 7673


L'article seul

RFC 7672: SMTP security via opportunistic DANE TLS

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : V. Dukhovni (Two Sigma), W. Hardaker (Parsons)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dane
Première rédaction de cet article le 18 octobre 2015


L'état actuel de la sécurisation de SMTP par TLS n'est pas très satisfaisant : la grande majorité des certificats est auto-signée (pour éviter les prix et les délais des Autorités de certification) et, souvent, expirée. Conséquence logique, les serveurs SMTP ne vérifient pas les certificats : s'ils le faisaient, ils ne pourraient plus envoyer de courrier, ou bien ils se rabattraient sur du SMTP en clair, sans TLS, ce qui serait pire que d'accepter un certificat pourri. Comment améliorer la situation ? Ce nouveau RFC propose d'utiliser DANE en publiant dans le DNS, sécurisé par DNSSEC, le certificat du serveur. DANE était déjà normalisé pour HTTP, voici comment l'utiliser pour le courrier, où il y a un petit piège supplémentaire : le nom du serveur est indiqué via les enregistrements MX.

Le courrier a des spécificités qui font qu'on ne peut pas appliquer directement DANE de la même façon qu'avec HTTP (section 1 du RFC). Outre l'indirection entre nom du service (ce qui est à droite du @ dans une adresse) et nom de serveur (la partie droite de l'enregistrement MX), il y a le fait que rien n'indique si un service ou un serveur donné a TLS. Résultat, un attaquant actif peut supprimer la requête STARTTLS (RFC 3207), forçant ainsi un repli vers l'envoi de courrier en clair (c'est une des plus grosses vulnérabilités de SMTP-sur-TLS).

Généraliser TLS pour SMTP va prendre du temps (en France, il faut apparemment une charte signée avec le ministre juste pour activer TLS sur son Postfix). La sécurité de SMTP va donc forcément être « opportuniste » (RFC 7435), c'est-à-dire « on chiffre quand on peut » (au passage, attention en lisant les textes sur la sécurité en anglais : « opportunistic security » est un terme flou, qui désigne des choses très différentes selon les auteurs. Ce n'est pas du vocabulaire standardisé de la sécurité).

Notre nouveau RFC 7672 propose de résoudre ce problème avec des enregistrements DANE. Cela permet notamment de résister aux attaques par repli telles que celle où un attaquant actif retire STARTTLS de la liste des extensions SMTP d'un serveur. De même, DANE permet de se protéger contre un Homme du Milieu, en authentifiant le serveur (ce qui est théoriquement possible avec TLS aujourd'hui mais, comme on l'a vu, n'est quasiment jamais fait). À noter qu'un attaquant actif, avec le courrier d'aujourd'hui, n'a même pas besoin de supprimer STARTTLS : s'il n'y a pas de DNSSEC, il peut se contenter d'un empoisonnement DNS pour changer le MX, vers un serveur qui collabore davantage avec lui.

DANE, normalisé dans le RFC 6698, doit sa création à la constatation des faiblesses de X.509. La principale est le nombre excessif d'autorités de certification à qui il faut faire confiance (regardez le magasin de certificats dans votre navigateur Web...) Qu'une seule d'entre elles trahisse ou soit piratée et tout est fichu, même pour les gens qui ne sont pas clients de cette AC.

Bon, mais HTTPS utilise TLS et les AC de X.509 depuis des années et, plus ou moins, ça marche. Pourquoi SMTP serait-il différent ? La section 1.3 de notre RFC explique les différences (lisez bien cette partie si vous voulez comprendre en détail le problème qu'on essaie de résoudre) :

  • Un URL https://... indique clairement la volonté de protéger la session avec TLS. Au contraire, rien dans une adresse de courrier électronique ne permet d'indiquer cette volonté. Cela serait d'ailleurs difficile : SMTP-sur-TLS fonctionne étape par étape alors que l'adresse est de bout en bout. La seule solution est donc d'opportunité : si le serveur SMTP à l'autre bout annonce STARTTLS (RFC 3207) dans sa bannière, tenter sa chance en TLS. Cela permet évidemment des attaques par repli (un attaquant actif peut supprimer le STARTTLS de la bannière), qui sont la plaie de SMTP-sur-TLS.
  • HTTP, hélas, n'utilise pas d'indirection entre le nom de service (par exemple dnsviz.net) et un nom de serveur assurant ce service (par exemple www1.dnsviz.net). Cela a des tas de conséquences négatives pour HTTP (difficulté de faire de la répartition de charge côté client, obligation de « squatter » l'apex du domaine avec des enregistrements A ou AAAA, etc). Si HTTP était à refaire, il faudrait absolument lui faire utiliser les enregistrements SRV. Mais l'indirection, que ce soit par les enregistrements SRV ou bien par la forme simplifiée, les enregistrements MX, qu'utilise SMTP, a un défaut : il faut sécuriser la liaison entre nom de service (la partie gauche du MX, celle qui apparait dans l'adresse de courrier) et nom de serveur (la partie droite du MX). Imaginons un domaine internautique.fr dont le courrier est servi par mail1.provider.example. Même si ce dernier utilise TLS, si l'enregistrement MX n'est pas sécurisé (typiquement via DNSSEC), un attaquant pourrait tout simplement rediriger le courrier vers un autre serveur que mail1.provider.example, plus favorable à ses noirs desseins. Une solution à ce problème serait que le certificat de mail1.provider.example contienne également (subject alternative name ou un truc de ce genre) le nom du service (ici internautique.fr). Ce n'est pas du tout réaliste pour un gros hébergeur ayant des dizaines ou des centaines de milliers de clients.
  • Une solution au problème de l'attaque par repli est de configurer en dur les serveurs SMTP pour exiger de certains destinataires une session TLS ou rien du tout. Cela protège bien contre un attaquant actif mais cela ne passe évidemment pas à l'échelle. Une telle méthode est utilisée dans le système Email Made in Germany, où les gros serveurs SMTP allemands s'engagent à configurer en dur le certificat des autres (peut-être fera-t-on la même chose en France mais cela n'est pas explicite dans les projets actuels). Cela marche au sein d'un cartel de gros, pas pour le courrier en général, où on veut pouvoir écrire à des gens avec qui on n'a pas de relation pré-établie.
  • Une des méthodes les plus utilisées par HTTP pour gérer les problèmes de certificat est de demander à l'utilisateur : « le certificat pour https://www.bortzmeyer.org/ n'est pas signé par une autorité reconnue, voulez-vous continuer ? » D'innombrables études auprès des utilisateurs ont montré que cela ne marchait pas : l'utilisateur ne connait pas assez X.509 et la sécurité pour pouvoir prendre une décision informée. Mais, de toute façon, cette méthode n'a pas de sens pour SMTP, qui n'est pas interactif : le MTA n'a pas d'utilisateur humain à qui demander.

Ça, c'était le problème. Le reste du RFC est consacré à la solution, « DANE pour SMTP ». L'idée est que le MTA émetteur fasse une requête DNS pour le type TLSA (le type utilisé par DANE : ce n'est pas un acronyme, ne cherchez pas sa signification). Une fois les enregistrements TLSA récupérés et validés (par DNSSEC), l'émetteur se connecte au récepteur en SMTP et lance TLS. Il récupère alors le certificat et le compare à ce qu'il a trouvé dans l'enregistrement TLSA. Si c'est bon, il continue, si non il avorte. Un tel système protège contre les attaques par repli : si on trouve un enregistrement TLSA, c'est que le récepteur sait faire du TLS et veut le faire.

Donc, première étape de cette méthode, trouver les TLSA (section 2) du RFC. Si on en trouve, ils indiquent clairement la volonté du pair SMTP de faire du TLS (contrairement à l'indication STARTTLS dans la bannière, qui est parfois envoyée par des serveurs qui ne savent pas faire de TLS). C'est donc l'équivalent du HSTS de HTTP (RFC 6797), une promesse. Administrateurs système, ne mettez pas un TLSA dans le DNS si vous ne savez pas ce que vous faites !

En résultat de la requête DNS pour trouver les TLSA, il y a quatre possibilités :

  • Une réponse validée avec DNSSEC, et avec au moins un enregistrement utilisable. C'est un engagement du destinataire à faire du TLS. On y va et on chiffre. Si la session TLS échoue ou si le certificat obtenu en TLS ne correspond pas, on doit renoncer, plutôt que de livrer du courrier à l'Homme du Milieu.
  • Une réponse validée mais où aucun enregistrement n'est utilisable. Au passage, « utilisable » et « non utilisable » sont définis dans la section 4.1 du RFC 6698, celui qui normalise DANE. Un enregistrement est utilisable s'il est signé, avec signature valide, et si son contenu est accepté par le client (par exemple, le champ « usage du certificat » a une valeur connue). Le client doit alors utiliser TLS mais peut se dispenser d'authentifier, puisqu'il n'a pas d'enregistrement TLSA pour cela.
  • Une réponse non validée par DNSSEC ou bien une réponse validée qu'il n'existe aucun enregistrement TLSA. C'est la situation la plus courante actuellement, et on fait comme si DANE n'avait pas été inventé, en tentant TLS, puis en se rabattant sur du texte en clair si TLS échoue.
  • Une erreur, notamment un échec DNSSEC, par exemple parce que les données ont été modifiées par un attaquant actif. On ne doit pas transmettre le courrier à ce serveur.

En fait, j'ai un peu exagéré, la première étape n'est pas de trouver les enregistrements TLSA mais de trouver les enregistrements MX. Naturellement, on ne doit utiliser DANE que si le MX est signé par DNSSEC. S'il y a plusieurs enregistrements MX, certains peuvent pointer vers des serveurs qui n'ont pas DANE, voire pas TLS. Il est important de se rappeler que l'algorithme de choix parmi ces enregistrements MX (RFC 5321, section 5.1) ne tient pas compte de TLS : le premier serveur peut ne pas avoir TLS alors que les suivants l'ont. DANE ne modifie pas les algorithmes de SMTP et le choix d'un relais de courrier ne dépend donc pas de leur sécurité. Si on veut imposer TLS, il faut donc mettre TLS sur tous ses serveurs annoncés par les enregistrements MX. (Si SMTP avait été conçu plus récemment, il utiliserait les enregistrements SRV et on devrait donc lire le RFC 7673 à la place de celui-ci.)

Ah, et où trouver l'enregistrement TLSA ? Le nom de domaine à utiliser avec DANE est _port._protocole.nom.du.serveur. Pour SMTP, le port est normalement 25. Donc, en général, on cherchera l'enregistrement TLSA en _25._tcp.... Voyons un cas réel avec le domaine sources.org. On cherche d'abord le MX (je fais ici avec dig ce qu'un MTA DANE ferait automatiquement) :

% dig MX sources.org
...
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 5, ADDITIONAL: 1
...
;; ANSWER SECTION:
sources.org.		86400 IN MX 10 uucp.bortzmeyer.org.

On trouve un MX, sécurisé par DNSSEC (le flag AD - Authentic Data - dans la réponse ; notez au passage qu'il faut un résolveur DNSSEC validant pour faire du DANE). Cherchons maintenant le TLSA :

 % dig TLSA _25._tcp.uucp.bortzmeyer.org
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 9, ADDITIONAL: 9
...
;; ANSWER SECTION:
_25._tcp.uucp.bortzmeyer.org. 86400 IN TLSA 2 0 1 (
				FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF
				4A6510890DAD18316B3A )

On a un TLSA utilisable, donc on va faire du TLS et vérifier que le certificat obtenu en TLS correspond bien au contenu de l'enregistrement TLSA.

Et quels enregistrements TLSA suggérer pour les serveurs SMTP, parmi les nombreuses combinaisons possibles ? Notre RFC recommande DANE-EE (usage 3) + SPKI (sélecteur 1) + SHA-256 (méthode de correspondance 1). Pourquoi ces recommandations (vous noterez, sur mon domaine personnel, que je ne les ai pas suivies, utilisant le « second choix » du RFC...) ? DANE-EE (c'est-à-dire qu'on ne fait pas de vérifications X.509 à partir des autorités de certification dans le magasin et que le certificat dans l'enregistrement TLSA est celui du serveur) est recommandé parce que les trois autres possibilités ont des défauts gênants. Avec DANE-TA (usage 2, que j'utilise personnellement), le certificat est celui de l'AC, pas celui du serveur. Comme tous les clients DANE n'ont pas forcément « mon » AC dans leur magasin, il faut envoyer le certificat de l'AC en sus de celui du serveur (ce que je fais sur mon serveur SMTP : cela ne me semble pas si difficile que ça). PKIX-TA et PKIX-EE (où on continue à faire les vérifications X.509 classiques) ont le même problème (la variété des AC présentes dans les différents magasins, qui interdit de compter sur une AC de référence). Mettre ces deux usages est donc dangereux, bien des MTA ne pourront plus vous authentifier.

Pour l'usage DANE-EE, qui est recommandé, le sélecteur suggéré est SPKI (l'enregistrement TLSA contient juste la clé, pas tout le certificat) car les autres informations du certificat (comme la date d'expiration ou le nom du serveur) sont inutiles (toute l'information utile est dans le DNS).

Pour l'usage DANE-TA, en revanche, il est recommandé de mettre un sélecteur CERT, qui indique que le client DANE doit vérifier tout le certificat, pas juste la clé.

Quant aux méthodes de correspondance (le troisième champ de l'enregistrement TLSA), la valeur 0 (on met le certificat entier, au lieu de juste un condensat) est déconseillée, en raison de la difficulté du DNS à faire passer des données de trop grande taille.

Au fait, on a surtout ici parlé de DANE pour sécuriser la communication entre deux serveurs SMTP, deux MTA. Mais entre un MUA et un MTA ? Pour les protocoles comme IMAP (RFC 6186), on utilise DANE+SRV (RFC 7673). Pour SMTP (soumission d'un message par le MUA), qui utilise rarement le RFC 6186 pour l'instant, les configurations statiques traditionnelles marchent encore.

Les administrateurs système seront intéressés par la section 9 du RFC, consacrée aux problèmes opérationnels. Par exemple, un administrateur peut hésiter à activer DANE sur le serveur SMTP dont il a la responsabilité : et si, se dit-il, mon courrier n'est plus transmis, par exemple parce que trop d'informaticiens font des erreurs et publient des configuration DANE cassées ? Cet administrateur prudent peut envisager d'utiliser DANE seulement pour certaines destinations, « pour voir », ou bien utiliser DANE en mode « on regarde et on journalise » mais on ne vérifie pas.

Autre problème opérationnel important, un changement de certificat : il faut bien penser à publier le nouveau TLSA à l'avance, pour que l'ancien ensemble TLSA ait disparu de tous les caches DNS avant que le serveur SMTP n'utilise le nouveau certificat.

Et pour faire du DANE avec SMTP en pratique ? Un MTA qui gère DANE existe, Postfix, depuis la version 2.11 (cf. la documentation officielle). Vous vérifiez bien que votre serveur SMTP utilise un résolveur DNSSEC validant, vous mettez dans la configuration :

smtp_dns_support_level = dnssec

smtp_tls_security_level = dane
   

Et c'est parti. Essayons d'envoyer un message à DENIC qui a annoncé avoir déployé DANE (certificat auto-signé donc normalement pas validable) :

Oct 18 21:58:08 aetius postfix/smtp[26542]: Verified TLS connection established \
      to mx2.denic.de[81.91.161.38]:25: \
      TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)
   

Et voilà, on se connecte en TLS après avoir vérifié que tout allait bien. En effet, DENIC a un enregistrement TLSA :

% dig TLSA _25._tcp.mx1.denic.de
...
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
...
;; ANSWER SECTION:
_25._tcp.mx1.denic.de.	3600 IN	TLSA 3 0 1 (
				17CBD8A164851E86C94A534438D02A4202CC71FCAE6C
				24E1F98214BD586F67A1 )
  

Ça, c'était la configuration en émetteur. Et en réception ? Il faut avoir déjà activé TLS sur son serveur (ce qui a été fait il y a pas mal d'années sur tous les serveurs SMTP sérieux). Il faut avoir une zone (correctement) signée avec DNSSEC. Il faut ensuite publier un enregistrement TLSA. Ici, j'ai choisi, comme expliqué plus haut, de publier le certificat de mon AC, CAcert. J'utilise la commande tlsa dans l'outil hash-slinger :

% tlsa --usage 2 --selector 0 --mtype 1 --output rfc --certificate ~/tmp/cacert.pem \
       --port 25 mail.bortzmeyer.org                                             
_25._tcp.mail.bortzmeyer.org. IN TLSA 2 0 1 ff2a65cff1149c7430101e0f65a07ec19183a3b633ef4a6510890dad18316b3a

Et je mets cet enregistrement dans ma zone DNS :

% dig TLSA _25._tcp.mail.bortzmeyer.org
...
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 8, ADDITIONAL: 7
...
;; ANSWER SECTION:
_25._tcp.mail.bortzmeyer.org. 86400 IN TLSA 2 0 1 (
				FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF
				4A6510890DAD18316B3A )

Pour tester, on peut faire appel aux copains en leur demandant d'envoyer des messages, ou bien on peut se servir de https://www.tlsa.info/, qui teste tout (DNSSEC, DANE et TLS en se connectant au serveur SMTP). Il n'essaie pas uniquement le DNS mais aussi le fait que le certificat corresponde bien à l'enregistrement TLSA. Si je publie un mauvais enregistrement, il proteste :

bortzmeyer.fr

The domain lists the following MX entries:
0 uucp.bortzmeyer.org

All TLSA RRs failed. (See details.)

Usable TLSA Records
2, 0, 1 ff2a65cff1149c74[...]10890dad18316b3b - application verification failure: (50)

Un autre outil de test est https://arp.simson.net/dane_check.cgi.


Téléchargez le RFC 7672


L'article seul

RFC 7671: Updates to and Operational Guidance for the DANE Protocol

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : V. Dukhovni (Unaffiliated), W. Hardaker (Parsons)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dane
Première rédaction de cet article le 21 octobre 2015


Le protocole DANE (RFC 6698) de sécurisation des communications utilisant TLS est encore très peu déployé. Donc, il n'y a pas vraiment de retours d'expériences mais les premiers essais ont quand même permis de se faire des idées, et, pour aider ceux et celles qui vont déployer DANE dans les années à venir, ce nouveau RFC rassemble quelques conseils pratiques.

Donc, DANE permet d'améliorer l'authentification des sessions TLS en publiant dans le DNS, sécurisés par DNSSEC, des enregistrements nommés TLSA (non, ce n'est pas un acronyme, ce nom est à utiliser sans comprendre son étymologie). Ces enregistrements indiquent le certificat utilisé pour la connexion TLS. Ainsi, un gérant d'un serveur TLS n'est plus obligé de dépendre d'une tierce partie, genre AC.

J'ai simplifié car il y en a fait beaucoup de choix : DANE permet de publier des clés brutes, pas seulement des certificats, il permet de publier un certificat d'AC, pas seulement le certificat final, etc. Le RFC 6698 normalise trois champs dans l'enregistrement TLSA (cf. section 2 de notre RFC), « Utilisation du certificat » (quatre valeurs possibles), « Sélecteur » (deux valeurs possibles) et « Méthode de correspondance » (trois valeurs possibles). En tout, il existe vingt-quatre combinaisons, ce qui est probablement trop (combien de clients DANE ont-ils vraiment été testés avec les vingt-quatre combinaisons différentes ?). Notre RFC réduit ce choix par ses conseils.

Voici un exemple d'un enregistrement DANE à peu près conforme aux recommandations du RFC, celui de mon blog :

% dig TLSA _443._tcp.www.bortzmeyer.org

;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 60895
;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 8; ADDITIONAL: 6

;; QUESTION SECTION:
;; _443._tcp.www.bortzmeyer.org.		IN	TLSA

;; ANSWER SECTION:
_443._tcp.www.bortzmeyer.org.	86400	IN	TLSA	2 0 2 EB0AD84F11B4B08BF76C7866EF32842292BBB2862FB6FC49C0A3F807629CA8F5DD28A0DE7B0C04D566020AC4FF2BA44E2F612AA58A1AE4CCACE486D244952FC2
      
    

L'« utilisation du certificat » est DANE-TA (valeur 2, mais le RFC 7218 a introduit de jolis noms pour ces codes), le « sélecteur » est CERT (valeur : 0, on testera tout le certificat, pas juste la clé publique) et la « méthode de correspondance » 2, ce qui veut dire qu'on publie un condensat en SHA-512 de ce certificat.

Notre RFC 7671 ne fait pas qu'ajouter des conseils opérationnels au RFC 6698, il le modifie légèrement sur certains points (section 3 de notre RFC), par exemple en ajoutant qu'un client DANE doit utiliser l'extension TLS nommée SNI (Server Name Indication, cf. RFC 6066).

Que mettre dans le champ « utilisation du certificat » de l'enregistrement TLSA ? La section 4 de notre RFC s'attaque à ce problème. Les quatre valeurs possibles sont PKIX-TA (le certificat utilisé pour TLS doit être vérifié par les mécanismes X.509 classiques et le certificat publié dans le TLSA doit être celui de l'AC), PKIX-EE (le certificat utilisé pour TLS doit être vérifié par les mécanismes X.509 classiques et le certificat publié dans le TLSA doit être celui du serveur TLS), DANE-TA (le certificat publié dans le TLSA est celui d'une AC à partir de laquelle on vérifie le certificat du serveur TLS) et enfin DANE-EE (le certificat publié dans le TLSA est celui du serveur TLS). Pour DANE-TA et DANE-EE, il n'y a pas besoin d'un magasin de certificats pré-existant sur le client TLS.

Il n'y a pas forcément besoin, pour un client DANE, de gérer les quatre utilisations. S'il le fait, un attaquant qui arrive à modifier les enregistrements DNS peut remplacer un PKIK-EE par un DANE-EE et la sécurité supplémentaire de la vérification X.509 qu'impose X.509 est donc assez illusoire. Un client paranoïaque et traditionnaliste qui veut imposer des vérifications X.509 doit donc ignorer purement et simplement les enregistrements avec DANE-EE ou DANE-TA.

Mais notre RFC donne le conseil contraire : ne gérer que DANE-EE et DANE-TA, en raison du manque de confiance qu'on peut avoir dans les centaines d'AC existantes, dont beaucoup ont déjà fait la preuve qu'on ne pouvait pas leur faire confiance. La vérification X.509 de ces AC n'apporte pas grand'chose en sécurité. En outre, il n'existe aucune liste standard d'AC reconnues, ce qui rend PKIX-TA et PKIX-EE très fragiles : le magasin du client doit être un sur-ensemble du magasin de tous les serveurs possibles ce qui mène à des listes d'AC délirantes (regardez celle de votre navigateur Web).

Depuis la publication de DANE, d'autres techniques visant à boucher les trous de X.509 sont apparues, comme les certificats au grand jour du RFC 6962. Comme la liste publique décrite dans ce RFC ne stocke que des certificats émis par des AC connues de la liste, les vérifications du RFC 6962 ne doivent pas être faites pour les utilisations DANE-TA et DANE-EE.

La section 5 rassemble ensuite des conseils spécifiques à chaque usage particulier du certificat publié avec DANE. D'abord, l'usage DANE-EE (valeur : 3). Dans cet usage, le certificat du serveur est publié dans l'enregistrement TLSA et les vérifications X.509 (RFC 5280) ne doivent pas être faites. Le RFC 6698, qui normalisait DANE, ne disait apparemment pas ce qu'il fallait faire des autres informations contenues dans le certificat comme la date d'expiration. Notre RFC 7671 précise (et c'est un des points où il met à jour le RFC 6698, ne se contentant pas d'ajouter des conseils, cf. section 12 pour les autres cas) que les autres informations doivent être ignorées. Si le certificat est dans un enregistrement TLSA, il est bon, quelle que soit la date d'expiration. Idem pour le nom de serveur dans le certificat.

Le sélecteur recommandé, pour cet usage, est SPKI (valeur : 1) qui indique qu'on ne trouve pas dans l'enregistrement TLSA tout le certificat mais juste la clé publique. Raisons de cette recommandation :

  • Cela évite de changer l'enregistrement TLSA quand les métadonnées dans le certificat changent (cas des certificats CAcert, qui ne durent que six mois),
  • C'est compatible avec les clés nues du RFC 7250,
  • C'est cohérent avec l'obligation d'ignorer les données du certificat, à l'exception de la clé publique.

Il n'est pas recommandé d'envoyer le certificat entier (méthode de correspondance Full, valeur 0), notamment en raison des problèmes du DNS avec des enregistrements de grande taille (ce qui est souvent le cas des certificats). Il faut plutôt utiliser un condensat du certificat. En cas de doute, notre RFC recommande donc DANE-EE + SPKI + SHA-256 (notez que l'enregistrement TLSA de mon serveur HTTP, cité plus haut, ne suit pas cette recommandation mais ce que le RFC présente comme un second choix).

Mais ce n'est pas impératif. L'usage DANE-TA, où on publie dans l'enregistrement TLSA le certificat de l'AC et pas celui du serveur, est tout à fait légitime (c'est celui que j'utilise). Attention, il impose d'envoyer toute la chaîne de certificats dans la réponse TLS. (Avec OpenSSL et GnuTLS, il suffit de concaténer tous ces certificats, dans le bon ordre - du plus spécifique au plus général, cf. RFC 5246, section 7.4.2 - dans un seul fichier PEM, qui sera celui indiqué au serveur.) Cette nouvelle obligation a été ajoutée pour le cas où l'AC choisie par le gérant du serveur DANE ne soit pas dans le magasin du client (pour CAcert, c'est fréquent).

Contrairement à l'usage DANE-EE, il est recommandé, avec cet usage DANE-TA, d'utiliser le sélecteur Cert (valeur : 0), car, cette fois, il faut tenir compte du contenu complet du certificat (comme les limites de longueur, par exemple, ou bien les restrictions sur les noms que l'AC peut approuver, cf. RFC 5280, section 4.2.1.10).

Un rappel de sécurité pour finir la section sur DANE-TA : cet usage vous protège contre les autres AC, malhonnêtes ou piratées, mais pas contre les autres utilisateurs de la même AC. Choisissez donc bien votre Autorité de Certification !

Deux autres usages possibles de l'enregistrement TLSA maintiennent des validations X.509 classiques. Ce sont les usages PKIK-EE (valeur : 1) et PKIX-TA (valeur : 0).

Un risque important de l'utilisation de DANE est la désynchronisation entre le ou les certificat(s) envoyés en TLS et ceux publiés dans le DNS, dans l'enregistrement TLSA (section 6 de notre RFC). Il faut absolument maintenir ces informations en cohérence, ce qui est d'autant plus difficile que les outils de supervision actuels n'offrent en général pas grand'chose pour DANE. Ainsi, si on utilise DANE-EE ou PKIX-EE, quand on change de clé publique sur le serveur TLS, il faut penser à mettre à jour l'enregistrement TLSA. Compte-tenu de l'importance de la mise en cache des données dans le DNS, cela nécessite de publier le nouveau certificat dans le DNS à l'avance (cf. section 8.4). Bref, notre RFC fait remarquer à juste titre qu'il est très recommandé que le DNS et le TLS soient gérés par la même organisation, autrement, le risque de cafouillage est trop élevé. (DANE est encore d'utilisation récente et on n'a pas encore vu beaucoup de cas de changement de certificat. Quand ça arrivera, il est à craindre qu'il y ait quelques malheurs, lorsque l'administrateur système oubliera qu'il avait publié un enregistrement TLSA.)

La section 8 met en garde les gérants de serveurs utilisant DANE contre le fait qu'on ne peut pas espérer que tous les clients DANE comprennent tous vos enregistrements TLSA. Ceux-ci peuvent spécifier un algorithme de condensation récent que tout le monde ne gère pas encore. Ou bien ils peuvent utiliser les clés nues du RFC 7250, que tout le monde n'accepte pas, loin de là. Attention donc, surtout lorsque vous décidez des paramètres.

La même section traite du difficile problème du remplacement : en raison des caches du DNS, les changements de clé ou de paramètres ne sont pas vus immédiatement partout. Il faut donc suivre quelques précautions quand on est hébergeur DNS d'un domaine qui utilise DANE :

  • Publier à l'avance les nouveaux enregistrements TLSA (quelle avance ? Le TTL de l'ensemble TLSA.)
  • Une fois le serveur TLS reconfiguré pour la nouvelle clé, virer les anciens enregistrements TLSA.
  • Si on change les paramètres (par exemple on passe d'un sélecteur CERT à un sélecteur SPKI ou bien le contraire), bien vérifier que tous les cas sont couverts pour les anciennes et les nouvelles chaînes de certificat.

À noter que le problème des clients DANE ne gérant pas toutes les valeurs possibles des paramètres est d'autant plus agaçant qu'il n'y a pas forcément de règles précises sur le choix d'un enregistrement TLSA, si plusieurs conviennent. Imaginons que vous ayez deux enregistrements TLSA, identiques sauf la méthode de correspondance qui vaut SHA-256 pour l'un et SHA-512 pour l'autre. Lequel sera utilisé par le client DANE ? Il faudrait évidemment que ce soit le plus fort (SHA-512) mais le RFC 6698 ne dit pas comment. Notre nouveau RFC demande au contraire que tout client DANE ait un classement des algorithmes de condensation, idéalement configurable par l'utilisateur, et qui soit par défaut l'ordre des valeurs (SHA-256 : 1, SHA-512 : 2, etc). Le client DANE, lorsqu'il a le choix, doit prendre le mieux classé (ou la méthode Full - valeur : 0 - qui n'utilise pas d'algorithme de condensation cryptographique, si un enregistrement TLSA l'utilise).

La section 10 de notre RFC rassemble des conseils divers pour la conception de protocoles utilisant DANE. D'abord, la taille des enregistrements, importante car le DNS a souvent des limites de taille. Par exemple, la plupart des serveurs faisant autorité ont une taille maximale de 4 096 octets pour les réponses se faisant en UDP. Même si la réponse est inférieure à cette valeur, une taille plus grande que 1 500 octets a de grandes chances de mener à une fragmentation de la réponse UDP, avec des conséquences négatives sur les performances voire, pire, sur la fiabilité de l'acheminement de la réponse (pas mal de pare-feux bogués bloquent stupidement les fragments). En théorie, on peut alors utiliser TCP pour transmettre les données mais lui aussi est souvent bloqué par des logiciels configurés par des incompétents.

Avec les grands certificats qu'on trouve souvent dans le monde X.509, le risque de paquets trop grands est bien plus élevé qu'avec les données de petite taille qu'on trouve habituellement dans le DNS. D'où les conseils de notre RFC : n'utilisez pas ensemble le sélecteur CERT (valeur : 0, il indique qu'il faut comparer tout le certificat, pas juste la clé publique) et la méthode de correspondance FULL (valeur : 0, elle indique que l'enregistrement TLSA contient les données complètes, pas juste un condensat). En effet, cette combinaison oblige à mettre un certificat entier dans l'enregistrement TLSA, ce qui dépasse en général la taille raisonnable. (D'autant plus qu'en cas de remplacement, il faudra publier simultanément deux enregistrements TLSA.) Avec un sélecteur SPKI (valeur : 1, on ne vérifie que la clé publique), le problème est moins grave, néanmoins autant ne jamais utiliser la méthode de correspondance FULL.

Notre RFC contient aussi des conseils pour le certificat envoyé par TLS. Il y a normalement des règles précises sur le nom (subject, en terminologie X.509) qui doit être mis dans le certificat, afin de permettre l'authentification. Néanmoins, ces règles sont complexes (donc pas toujours bien comprises) et ont changé dans le temps. Il peut être prudent de rajouter des noms « au cas où ». Ainsi, pour un service auquel on accès via un enregistrement SRV, le RFC 7673 prescrit de vérifier le nom en partie droite du SRV. Mais comme on ne peut pas être sûr de ce que feront tous les clients DANE, autant essayer de mettre aussi dans le certificat le nom qui est en partie gauche du SRV.

La section 11 se penche, elle, sur DNSSEC. DANE est complètement dépendant de DNSSEC : sans lui, plus aucun enregistrement TLSA n'est accepté. La sécurité de DNSSEC est donc cruciale pour DANE. Avec X.509, la sécurité de l'AC que vous choisissez a peu d'importance, puisque n'importe quelle AC peut émettre un certificat pour votre serveur. (Les « Name constraints » - section 4.2.1.10 du RFC 5280 - sont très peu utilisées.) Avec DNSSEC, au contraire, vous ne dépendez que d'acteurs que vous choisissez : votre hébergeur DNS, votre BE (souvent le même que l'hébergeur), votre registre...

DNSSEC dépendant du DNS, il va donc falloir sécuriser votre configuration DNS (cf. le bon guide de l'ANSSI). Par exemple, il est recommandé de placer un verrou (registry lock) pour limiter les risques de détournement de votre domaine, ou de modification non autorisée.

Certaines opérations dans le DNS sont délicates à faire lorsqu'un domaine est signé : le passage d'un BE à l'autre lorsque chacun est également l'hébergeur DNS. Une technique parfois recommandée est de dé-signer la zone temporairement. On retire le DS, on attend l'expiration dans les caches, on migre, on met un nouveau DS. Cette méthode est sûre et simple mais elle laisse une fenêtre d'insécurité, où la zone n'est pas signée. Sans DANE, c'est un inconvénient supportable (il faut juste espérer que l'attaquant ne frappe pas à ce moment), avec DANE, c'est impossible car les enregistrements DANE seront ignorés pendant cette période d'insécurité. S'ils sont d'usage PKIK-EE ou PKIK-TA, ce n'est pas trop grave, le certificat sera toujours validé par X.509 mais s'ils sont d'usage DANE-TA ou surtout DANE-EE, on ne pourra plus se connecter au serveur. Voilà pourquoi il faut étudier les conditions de migration du domaine avant de déployer DANE.

DNSSEC n'a pas de notion de révocation (là encore, sauf si on utilise les usages PKIX-EE ou PKIK-TA, où les vérifications de la révocation du certificat peuvent être faites). Attention donc de ne pas mettre des TTL trop longs à vos enregistrements TLSA (section 13 du RFC, au début) et surtout pas des périodes de validité des signatures trop longues pour éviter des attaques par rejeu. Pour ces périodes de validité, le RFC recommande quelques jours pour des clés importantes et quelques semaines pour les autres. Regardez par exemple l'enregistrement TLSA de mon serveur de courrier :

_25._tcp.mail.bortzmeyer.org. 86400 IN TLSA 2 0 1 (
				FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF
				4A6510890DAD18316B3A )
_25._tcp.mail.bortzmeyer.org. 86400 IN RRSIG TLSA 8 5 86400 (
				20151101223339 20151012192513 53605 bortzmeyer.org.
				BEiYRQh4i4Z3RH0h3yZqDjltCmv...
    

Le TTL est d'une journée (ce qui fait qu'un changement d'urgence du certificat pourrait casser la vérification pendant une journée, dans le pire des cas). La durée de validité de la signature est de 20 jours (<Validity><Default>P20D</Default></Validity> dans la configuration OpenDNSSEC). Avec des courtes validités, on ne peut pas se permettre d'avoir un serveur DNS maître en panne très longtemps, et des périodes de quelques jours ne doivent donc être utilisées que si on dispose d'une équipe professionnelle et réactive.

Enfin, il est évidemment crucial de superviser sa configuration DNSSEC.

Enfin, dernier conseil, section 14 (mais on l'a déjà dit plus haut), attention au fait que certains enregistrement TLSA seront considérés comme inutilisables par certains clients DANE. En TLS « opportuniste » (RFC 7435), cela se traduira par une absence de vérification du certificat par le client. Mais en mode plus sécurisé (très rare à l'heure actuelle), cela peut se traduire par une impossibilité de se connecter en TLS.

Terminons avec un peu de ligne de commande Unix. Comment on génère un enregistrement TLSA ? Par exemple, pour le mien, d'usage DANE-TA (valeur : 2), je prends le certificat de mon AC, CAcert (wget https://www.cacert.org/certs/root.crt) et voici deux méthodes possibles, avec OpenSSL, puis avec hash-slinger. D'abord, avec OpenSSL (voir cet article) :

%  openssl x509 -in  root.crt -outform DER | openssl sha256
(stdin)= ff2a65cff1149c7430101e0f65a07ec19183a3b633ef4a6510890dad18316b3a

Et on n'a plus qu'à mettre :

_25._tcp.MXSERVER.DOMAIN.  IN TLSA 2 0 1  ff2a65cff1149c7430101e0f65a07ec19183a3b633ef4a6510890dad18316b3a

dans sa configuration DNS. Avec hash-slinger :

%  tlsa --create --port  25 --certificat root.crt --usage 2 --selector 0 --mtype 1 \
              mail.bortzmeyer.org
_25._tcp.mail.bortzmeyer.org. IN TLSA 2 0 1 ff2a65cff1149c7430101e0f65a07ec19183a3b633ef4a6510890dad18316b3a

Troisième possibilité, le faire en ligne.

Et si je voulais un enregistrement TLSA d'usage DANE-EE (valeur : 3) ? Avec OpenSSL, ce serait :

printf '_25._tcp.%s. IN TLSA 3 1 1 %s\n' \
        $(uname -n) \
        $(openssl x509 -in server.pem -noout -pubkey |
            openssl pkey -pubin -outform DER |
            openssl dgst -sha256 -binary |
            hexdump -ve '/1 "%02x"')
_25._tcp.www.foobar.example. IN TLSA 3 1 1 755b35d2c34c54729d92f97e25d8a8be020235d5b1c6b7751bfefc896b8e5164

Avec hash-slinger, il suffit de modifier les paramètres de la ligne de commande.

Si vous voulez tester vos enregistrements TLSA, ce qui est très recommandé :

Et pour lire davantage, vous pouvez voir le dossier thématique de l'AFNIC sur DANE.


Téléchargez le RFC 7671


L'article seul

RFC 7669: Assigning Digital Object Identifiers to RFCs

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : J. Levine (Taughannock Networks)
Pour information
Première rédaction de cet article le 25 octobre 2015


Depuis mai 2015, tous les RFC ont un DOI. C'est quoi et à quoi ça sert ? C'est ce qu'explique ce RFC avec lequel, je vous préviens, je ne suis pas du tout d'accord.

Les DOI sont un mécanisme d'identification formel de documents numériques. Par exemple, le RFC 7626 a désormais le DOI 10.17487/RFC7626. Les DOI sont désormais attribués à tous les RFC (et c'est rétroactif : le RFC 1 a le DOI 10.17487/RFC0001). Ils étaient prévus à l'origine pour être utilisé avec le système de résolution Handle (RFC 3650). Celui-ci s'étant complètement cassé la figure (et à juste titre), les DOI sont aujourd'hui résolus via un URI (par exemple, pour le RFC 7676, l'URI est https://dx.doi.org/10.17487/rfc7676).

Ce RFC explique que les DOI sont largement utilisés (y compris, désormais, par les RFC) mais oublie de dire que c'est souvent par obligation, par exemple parce que certaines bibliothèques numériques anglo-saxonnes refusent les documents qui n'ont pas de DOI.

Les DOI sont techniquement décrits par une norme ISO, la ISO 26324:2012. Comme presque toutes les normes du dinosaure ISO, elle n'est pas en accès libre. Si vous tenez à la lire, il vous en coûtera 88 francs suisses, et vous n'aurez pas le droit de la distribuer ensuite aux copains. (On note l'incohérence de l'IETF, qui avait signé une grandiose déclaration en faveur des SDO ouvertes.) Les DOI sont ensuite attribués de manière hiérarchique, l'IDF accréditant des agences qui attribuent ensuite des DOI.

Pourquoi des DOI et pas un autre type d'identificateurs ? La section 1 du RFC cite un passage du « Report on best practices for citability of data and on evolving roles in scholarly communication » qui tape sur les URI en montrant une grande incompréhension du sujet. Le document en question reproche aux URI leur manque de permanence, en oubliant la règle numéro 1 de la permanence des identificateurs : la permanence est une fonction de l'organisation, pas de la technique. Autrement dit, un URI peut être stable, s'il est géré par une organisation sérieuse. C'est exactement pareil pour un DOI. Si l'IDF, organisation purement privée, disparait, que deviendront les DOI ?

Notez aussi une particularité des RFC, qui peut être très intéressante pour leur trouver des identificateurs : les RFC sont immuables. Une fois publiés, ils ne sont jamais changés, même pas d'une virgule (le seul moyen de faire un changement est de publier un nouveau RFC). Résultat, on pourrait parfaitement désigner les RFC par un identificateur très stable, leur condensat, comme avec les NI du RFC 6920 (au passage, ce RFC 7669 a le NI ni:///sha256;NAuLJduQ-wP7LBI5nYQw0-Ubxh8DsQdVVaxooj4oYB4).

Un autre argument tout aussi erroné figure dans la section 1 : que les DOI permettent de trouver plus facilement la version gratuite des RFC en ligne. Il est vrai que des gens peu honnêtes ont vendu des versions payantes des RFC (ce qui est légal, les RFC sont libres d'utilisation) sans prévenir leurs acheteurs qu'ils pouvaient les obtenir gratuitement en ligne (ce qui est assez inéthique). Mais croire que les gens ont besoin des DOI pour trouver un RFC en ligne est assez fort de café ! (Cet argument est pourtant repris dans la section 3.)

La section 2 du RFC explique comment sont formés les DOI des RFC. Notez bien qu'un DOI est normalement opaque pour l'utilisateur : contrairement à un URI, il ne faut pas l'analyser pour en chercher des composantes. Néanmoins, si vous aimez savoir comment les choses sont faites, un DOI pour un RFC commence avec le préfixe 10.17487 (les DOI commencent toujours par 10, d'autres utilisations avaient été prévues avec d'autres nombres, mais n'ont jamais décollé), préfixe attribué aux RFC, et est suivi du texte rfc et du numéro du RFC. Le texte est apparemment insensible à la casse (en tout cas, les exemples du RFC sont tantôt en minuscules, tantôt en majuscules) mais, la norme n'étant pas librement accessible, je n'ai pas pu vérifier. Comme le DOI est opaque, il ne faut pas chercher à deviner un DOI pour un RFC donné. Par exemple, le numéro est actuellement formaté avec quatre chiffres mais cela pourra changer après le RFC 9999...

Comme indiqué plus haut, les vendeurs de DOI, après avoir répandu plein de FUD contre les URI, on finalement renoncé à leurs grandioses projets de déploiement de nouveaux protocoles et utilisent le même HTTP que tout le monde, avec les mêmes URI que tout le monde. Pour accéder à un DOI, on le préfixe par https://dx.doi.org/. On accède alors à une page Web fournie par l'entité qui a publié le document (et dont rien ne garantit donc la stabilité...) Cette page peut être le document recherché lui-même, une page de métadonnées avec un accès au document (c'est le cas des RFC) ou bien une page de métadonnées sans le document (cas des documents privés, non accessibles publiquement). Voir à ce sujet le « DOI Handbook »

Le processus d'attribution d'un DOI pour un RFC est décrit dans la section 4. Comme on l'a vu, il existe plusieurs agences d'attribution de DOI, dont plusieurs sont spécialisées dans un secteur très particulier. Le RFC Editor a choisi CrossRef, émanation des éditeurs. (Et qui n'est pas l'unique agence, contrairement à ce que dit le Wikipédia francophone.) Le coût d'adhésion à Crossref est de 660 dollars et chaque DOI attribué à un document coûte un dollar de plus.

Le DOI du RFC est maintenant inclus dans les bases distribuées par le RFC Editor. Tous les RFC qui citent un autre RFC doivent maintenant inclure le DOI (une obligation imposée par l'IDF, cf. la section 4.4 du RFC.) C'est fait automatiquement quand on utilise les outils comme xml2rfc (faut juste penser à vider le cache, en ~/.cache/xml2rfc d'abord, sinon certains RFC auront des DOI et pas d'autres).

L'attribution de DOI aux RFC parus précédemment a nécessité un peu de développement logiciel, utilisant l'API de Crossref pour solliciter les sept mille et quelques DOI des RFC existants.

Notez que tout cela s'est fait sans aucune concertation, ce qui est en contradiction avec les valeurs de l'IETF. Lorsque ce RFC a été soumis, la décision était déjà prise et mise en œuvre (l'annonce officielle date de mai 2015, avant, il fallait prêter attention à des appels d'offre du RFC Editor comme celui-ci).

D'autres solutions auraient pourtant été possibles. D'abord, l'IETF elle-même a plein de mécanismes d'identificateurs, à commencer évidemment par les URI du RFC 3986. Au sein des URI, des plans particulier (comme NI, cité plus haut) étaient possibles. En dehors de l'IETF, des identificateurs plus ouverts comme ARK auraient été un choix mais il semble que les éditeurs scientifiques anglo-saxons ont décidé d'imposer le DOI partout.

Concevoir un système d'identificateurs est moins simple qu'il n'y parait et les DOI ont été conçus par des gens qui n'avaient pas de compétences particulières en ce domaine. Ici, le but était clairement de respectabilité plus que d'améliorer la vie des utilisateurs (comme cela avait été le cas pour l'ISSN).


Téléchargez le RFC 7669


L'article seul

RFC 7665: Service Function Chaining (SFC) Architecture

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : J. Halpern (Ericsson), C. Pignataro (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF sfc
Première rédaction de cet article le 22 octobre 2015


Aujourd'hui, des flots de paquets IP qui voyagent d'un point à un autre de l'Internet ont peu de chances de le faire sans passer par divers traitements, des plus honorables (statistiques, lutte contre une attaque par déni de service) aux moins avouables (étranglement du trafic pour pousser un fournisseur de contenu à payer, censure). Actuellement, ces traitements sont rigidement liés à la topologie du réseau sous-jacent et manquent donc de souplesse. Dès qu'on veut chaîner plusieurs traitements, le résultat de la configuration devient difficile à lire et à maintenir (le problème est décrit plus en détail dans le RFC 7498). L'idée de base du projet SFC (Service Function Chaining) est de spécifier une architecture (ce RFC) et peut-être plus tard des protocoles pour organiser ces traitements de manière plus souple.

Le RFC 7498 avait très bien décrit le problème qu'on essaye de résoudre. Ce nouveau RFC 7665 est plus concret, décrivant l'architecture des SFC mais je trouve personnellement qu'il reste encore très abstrait et qu'il ne fait pas beaucoup avancer la compréhension, par rapport à son prédécesseur.

Donc, l'architecture des SFC (Service Function Chaining). On veut avoir des chaînes ordonnées des traitements appliqués aux flux réseau, et on veut pouvoir les créer, les modifier et les détruire facilement, avec bien plus de souplesse que le système actuel (section 1 du RFC).

Les paquets entrent et sont classés, les traitements étant ensuite appliqués en fonction du classement. Ces traitements sont appliqués dans l'ordre de la chaîne et, attention, il peut y avoir une re-classification dans un des ces traitements, menant à une autre chaîne.

Pour définir l'architecture, on suppose que :

  • Les traitements sont tellement variés qu'il est impossible de les normaliser ou même de les décrire de manière exhaustive. On va donc, dans le projet SFC, s'intéresser uniquement à l'ordonnancement de ces traitements, pas au traitement lui-même. Chaque traitement est une « boîte noire ».
  • La liste des traitements appliqués, les critères d'application, et l'ordre d'application, sont des décisions purement locales. Il n'y aura pas de normalisation des traitements (du genre « il faut commencer par un filtrage IP »).
  • L'application de ces traitements en chaîne dépend évidemment du réseau sous-jacent qui va déplacer les bits d'une machine à l'autre mais ce réseau n'est pas décrit par SFC, chacun peut utiliser ce qu'il veut.

Chaque traitement (on le nomme un SF pour Service Function) est identifié de manière unique dans le domaine (dans les exemples du RFC, l'identificateur est un simple nombre). Une suite de SF est une SFC (Service Function Chain). Une SFC peut être unidirectionnelle (par exemple des paquets qui sont d'abord comptés, puis filtrés, puis modifiés) ou bidirectionnelle.

Un SFF (Service Function Forwarder) est responsable d'acheminer le trafic d'une SF à une autre. Un SFP (Service Function Path) est la réalisation concrète d'une SFC et un RSP (Rendered Service Path) est la suite des SF effectivement visités. Prenons comme exemple une SFC qui dit que le trafic doit passer par deux SF, un pare-feu et un cache. Le SFP, plus concret, va indiquer quelle instance des deux DF, et dans quel centre de données, on va utiliser. Et le RSP indiquera où le trafic est réellement passé (il peut différer du SFP si ce dernier laissait une certaine latitude, ou bien si quelque chose ne s'est pas passé comme prévu).

La section 3 du RFC liste les grands principes, notamment :

  • Indépendance par rapport à la toplogie du réseau : pas besoin de recâbler quand on modifie une SFC.
  • Séparation entre les SFP et la transmission des paquets par les routeurs.
  • Classification des paquets, qui décidera du SFP où on enverra le trafic.
  • Métadonnées accessibles, par exemple le résultat de la classification sera visible par les SF (voir plus loin la notion d'encapsulation).
  • Indépendance des SFC entre elles, et de la SFC par rapport aux SF, nécessaire à la souplesse du dispositif.

La section 4 de notre RFC détaille les composants du système vus plus haut (SF, SFF, etc). Ces composants sont reliés par l'encapsulation SFC, qui définit comment on va encapsuler le trafic pour l'acheminer d'un composant à l'autre. Attention, ce n'est pas un remplaçant d'IP : lorsque les SF sont sur des machines séparées, il faudra toujours un réseau sous-jacent pour transmettre les paquets. Le plan de contrôle (comment trouver où acheminer le trafic) n'est pas décrit, il est hors-sujet pour ce projet, qui reposera sur des protocoles déjà existants.

D'ailleurs, en parlant de réseau, la section 5, qui couvre divers problèmes de réalisation, note entre autres que qui dit encapsulation dit problèmes de MTU, suite aux octets d'en-tête de l'encapsulation. Il n'y a pas de solution idéale pour les futurs protocoles concrets qui instancieront cette vision abstraite des Service Function Chains mais il faut au moins garder ce problème en tête.

Autre problème pratique dans la même section 5, la fiabilité. Si on met des services supplémentaires dans le réseau, cela ne doit pas trop diminuer sa résilience. Par exemple, prenons une SFC qui ne comporte qu'un seul SF, chargé de mesurer le trafic. La panne de l'équipement qui porte ce SF ne doit pas arrêter tout le trafic. Ici, c'est relativement facile car le SF « compteur » n'a pas besoin d'être en série sur le trajet, il peut être placé en dérivation. Mais d'autres SF ont besoin de modifier le trafic et donc doivent être placés en série. Il faut alors prévoir des solutions de secours, par exemple à base de VRRP (RFC 5798).

Le déploiement des SFC peut aussi avoir des conséquences sur la sécurité. On passe d'un réseau assez statique avec peu de fonctions à un réseau très dynamique pouvant assurer plein de fonctions (section 6 de notre RFC).


Téléchargez le RFC 7665


L'article seul

RFC 7663: IAB Workshop on Stack Evolution in a Middlebox Internet (SEMI) Report

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : B. Trammell, M. Kuehlewind (ETH Zurich)
Pour information
Première rédaction de cet article le 22 octobre 2015


Une caractéristique importante de l'Internet d'aujourdhui, et qui le distingue considérablement de l'architecture initialement prévue, est la prévalence de middleboxes un peu partout sur le trajet. Alice et Bob ne peuvent plus, dans la plupart des cas, se parler directement, ils doivent passer par des middleboxes, dont les intérêts ne sont pas ceux des utilisateurs, et qui sont en outre fréquemment boguées et/ou limitées dans leurs fonctions. Un des effets est l'ossification de l'Internet : innover devient de plus en plus difficile, car il y aura toujours une middlebox sur le trajet qui ne sera pas d'accord. Quelles sont les conséquences de cette middleboxation de l'Internet ? Comment peut-on résoudre les problèmes qu'elle posent ? C'est le but du programme IP Stack Evolution de l'IAB que de trouver des réponses à ces questions. C'est dans ce cadre qu'un atelier a été organisé en janvier 2015 à Zurich pour explorer la question. Ce RFC est le compte-rendu de l'atelier SEMI (Stack Evolution in a Middlebox Internet).

On comprend mieux le problème en revenant à l'architecture prévue pour l'Internet (très bien décrite dans le RFC 1958), et qui a assuré son succès, le principe de bout en bout, formalisé dans l'article de J.H. Saltzer, D.P. Reed et David Clark, « End-To-End Arguments in System Design » (ACM TOCS, Vol 2, Number 4, November 1984). Ce principe dit en gros que deux machines connectées à l'Internet doivent décider elles-mêmes de ce qui est bon pour elles, les équipements intermédiaires qui forment le réseau ne sont pas bien placés pour prendre des décisions. Ce principe a pour conséquence un réseau « bête », où les routeurs transmettent les paquets sans chercher à comprendre. Des décisions comme le contrôle de congestion sont faites aux extrémités du réseau, dans les machines terminales. Par exemple, un protocole de transport, dont l'une des fonctions est de réagir en cas de congestion, sera mis en œuvre uniquement dans ces machines. Conséquence de ce principe, l'innovation ne nécessite pas de changement dans l'infrastructure. Si on trouve que le protocole de transport TCP n'est pas terrible, on en invente un autre (comme SCTP) et du jour au lendemain, tout couple de machines Internet peut l'utiliser, sans qu'on ait eu à modifier les routeurs de l'Internet.

Mais l'Internet a bien dégénéré depuis le RFC 1958. D'innombrables équipements supplémentaires, les middleboxes ont été installés et leur but n'est pas de fournir des services aux utilisateurs mais au contraire de les contrôler et de limiter ce qu'ils peuvent faire. C'est ainsi que boitiers NAT, pare-feux, et autres middleboxes se permettent désormais de regarder le trafic et de dire, par exemple « ah, non, SCTP, je ne connais pas, je ne laisse pas passer ». C'est ce qu'on nomme l'ossification : déployer un nouveau protocole de transport, voire un nouveau protocole d'application (« un seul autorisé, HTTP », est un principe fréquent sur les middleboxes), devient de plus en plus difficile. Peut-on encore désossifier l'Internet ? Le problème a été identifié il y a longtemps (cf. l'exposé de S. Deering, « Watching the Waist of the Protocol Hourglass »), il reste à travailler sur les solutions.

L'atelier SEMI avait donc invité les experts à soumettre des articles autour de questions comme « quels chemins dans l'Internet acceptent encore tous les transports ? », « quels chemins sont ouverts à toutes les applications ? », « comment les applications peuvent-elle faire pour contourner les blocages ? », « comment revenir à une situation plus saine ? ». Des tas de pistes étaient possibles :

  • Migrer certaines fonctions de la couche transport vers la couche application (d'une certaine façon, c'est un peu ce que fait HTTP/2, cf. RFC 7540),
  • Développer de meilleurs outils pour que l'application puisse découvrir si un chemin est propre ou pas (et, dans ce cas, quels contournements auront le plus de chances de marcher),
  • Développer des méthodes pour découvrir les middleboxes et leurs caractéristiques,
  • Réfléchir aux questions business : ce n'est pas tout d'avoir des solutions, il faut aussi les déployer et pour cela, avoir des arguments sonnants et trébuchants, pas juste « on va rétablir les principes originels ».

Les articles acceptés sont tous disponibles sur le site Web de l'atelier SEMI. Ce RFC est très court et n'en fait qu'un résumé (et moi, dans cet article, un résumé du résumé).

À l'époque de l'exposé de Deering cité plus haut, le principal type de middlebox repéré était le routeur NAT. Aujourd'hui, les problèmes causés par le NAT, sans avoir été supprimés, sont bien compris et il existe des solutions de contournement (imparfaites, contrairement à ce que laisse entendre l'optimisme du RFC, qui parle d'un problème « largement résolu »). Plusieurs groupes de travail de l'IETF ont travaillé pour cela, notamment BEHAVE. Mais les middleboxes sont devenues plus variées et plus intrusives, au fur et à mesure que leurs possibilités techniques augmentaient (section 2 de notre RFC). Aujourd'hui, le problème qu'elles posent devient d'autant plus intolérable que les préoccupations de sécurité, et notamment de protection de la vie privée, poussent au développement de la cryptographie. Celle-ci permet de préserver l'intégrité des communications de bout en bout et s'oppose donc directement aux middleboxes. (C'était le coeur de l'exposé de Huitema à SEMI.)

Qu'est-ce qui fait que des middleboxes sont déployées ? La section 3 du RFC se penche sur les motivations ; après tout, il y a peu de chances de pouvoir revenir sur ce déploiement si on ne comprend pas pourquoi il a lieu. Parmi les causes, il y a la loi de Moore, qui fait qu'il est de plus en plus réaliste de mettre des traitements importants sur le chemin des communications, malgré la concentration de trafic. Il y a le désir des opérateurs réseau de ne pas être « uniquement un tuyau » (ce que voudraient les utilisateurs) mais d'imposer des traitements (qu'on baptise « valeur ajoutée ») qui justifieront des augmentations de tarif, ou des violations de la neutralité. Il y a des services informatiques qui trouvent qu'il est plus facile de déployer une politique dans le réseau que dans les machines terminales, d'autant plus qu'ils ne contrôlent pas forcément celles-ci (cas du BYOD). Et il y a bien sûr le marketing des vendeurs de middleboxes qui insiste lourdement pour qu'on achète ces boitiers, dotés de vertus miraculeuses (en sécurité ou en performances). C'est vrai qu'acheter est un acte simple, et il est tentant de se procurer un service juste en faisant un chèque. Toutes ces motivations contribuent à l'ossification du réseau.

Les organisateurs de SEMI se placent dans le cadre d'un système capitaliste pur (rebaptisé, car c'est plus joli, « libre marché »), vu comme incontournable. Dans ce cadre, les désaccords ne sont adressables que par le jeu du marché et il faut donc fournir des motivations business pour tout changement. Cela mène à la question « comment vendre les alternatives aux middleboxes ? »

La section 4 explore ce que font exactement les middleboxes. Car il y en a de plein de sortes différentes et, pour résoudre les problèmes qu'elles posent, il faut les étudier et les classer (c'était le papier de Edeline et Donnet).

Cette étude est notamment nécessaire pour savoir si les applications pourront coopérer avec les middleboxes ou bien s'il faudra envisager des mesures plus « ninja » comme de tout tunneler (la contribution de Raiciu et Olteanu).

Et sur les protocoles de transport ? La section 5 discute de comment faire évoluer la couche 4 dans un Internet gelé par les middleboxes. S'inspirant d'un épisode du film « La vie de Brian », le RFC classe les propositions en deux camps :

  • Le « TCP Liberation Front », ceux qui veulent avant tout permettre de reprendre l'évolution de TCP, déployer de nouvelles extensions (qui entrainent actuellement souvent une réaction négative des middleboxes).
  • Le « People's Front of UDP », qui considère que c'est fichu et que tous les services « couche 4 ou à peu près » futurs devront être encapsulés dans l'UDP (c'est par exemple ce que propose le RFC 6951 pour arriver à faire passer SCTP et c'est également pour cette raison que LISP est forcément transporté dans UDP alors qu'il aurait très bien pu être directement sur IP).

Ajoutez la crypto à cela et la solution UDP se traduira peut-être dans le futur par « tout sur DTLS »... Des tas de solutions ont été imaginées par les « transporteurs », les gens de la couche 4. Par exemple, la contribution de Briscoe propose de mettre les options et extensions nouvelles de TCP dans la charge utile et non pas dans l'en-tête TCP, les mettant ainsi à l'abri des middleboxes (jusqu'à ce qu'elles se mettent à faire du DPI lourd...)

À noter que tous les chemins sur l'Internet ne sont pas forcément affligés de middleboxes. Quelles que soient les solutions de contournement adoptées, il serait dommagee qu'elles soient imposées à tous, avec leurs coûts en octets gaspillés et en complexité, alors qu'on peut s'en passer dans beaucoup de cas. Welzl, Fairhurst et Ros avaient ainsi proposé de consacrer des efforts à la détection des middleboxes. On teste le chemin et, s'il est propre, on se dispense des horreurs nécessitées par le contournement des middleboxes. Comme ce test va prendre du temps, il faudra sans doute le faire en parallèle des tentatives de connexion, comme dans le cas du RFC 6555.

Bon, maintenant, place à l'action. Qu'est-ce qui doit être fait pour avancer ? La section 6 de notre RFC liste les points à traiter. D'abord, est-ce qu'on ne pourrait pas envisager de signaler au réseau certaines informations sémantiques (du genre « ce paquet est le début d'un nouveau flot »), dispensant les middleboxes d'essayer de (mal) trouver cette information elles-mêmes ? Cela serait d'autant plus utile que cette information est masquée en cas de chiffrement. Cette idée est à la base du projet SPUD (Substrate Protocol for User Datagrams, « un traité de paix entre machines et réseau »). Ce projet a suscité des controverses lors de sa présentation à l'IETF 92 à Dallas (si on chiffre, ce n'est pas ensuite pour donner des informations à un réseau en qui on n'a pas confiance) et aucun groupe de travail n'a encore été créé. Les objections à SPUD portent notamment sur le fait que la publication des informations devrait être volontaire, et le résultat d'un choix délibéré.

Autre sujet sur lequel il faudrait travailler, la mesure. Cela ne vaudrait pas la peine de développer des hacks d'enfer dans les couches 4 ou 7 pour contourner une perturbation qui est rare. Or, à l'heure actuelle, on manque de données sur les différents types de problèmes causés par les middleboxes. Par exemple, combien de chemins dans l'Internet ne laissent pas passer un protocole de transport inconnu ? (Avant de crier « aucun, tout le monde est derrière un routeur NAT », pensez aux réseaux d'entreprise ou d'organisation, aux réseaux IPv6, etc.) Ces mesures sont le travail de la liste de diffusion hops (How Ossified is the Protocol Stack?) qui discute des meilleurs moyens de collecter cette information, par exemple à partir des journaux des applications qui tentent d'utiliser tel ou tel protocole mais se replient ensuite sur une autre solution. Le pourcentage de repli serait une information utile.

Le RFC n'en parle pas mais un des problèmes posés par les middleboxes est typiquement que leurs programmeurs sont inconnus, et ne participent pas aux forums comme le RIPE ou l'IETF, où se discutent les problèmes de l'Internet. Même si on rédige des bonnes pratiques à suivre pour les auteurs de logiciel de middlebox, il y a peu de chances qu'ils les lisent, ou même apprennent leur existence. (Les middleboxes actuelles ont manifestement été programmées sans lire les RFC ou en tout cas sans lire tous les RFC pertinents, cf. RFC 5625 pour des exemples).

Mais l'IETF est optimiste et croit que l'humanité peut s'améliorer : d'où des documents comme le RFC 3234. Un travail est en cours pour le compléter avec des conseils pratiques.

Bref, la lutte entre les machines terminales, qui veulent un tuyau bête et neutre, et le réseau qui cherche à imposer ses propres vues, n'est pas terminée, loin de là.


Téléchargez le RFC 7663


L'article seul

RFC 7649: The Jabber Scribe Role at IETF Meetings

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : P. Saint-Andre (&yet), D. York (Internet Society)
Pour information
Première rédaction de cet article le 27 septembre 2015


Pendant les réunions physiques de l'IETF, il y a divers moyens de suivre la réunion en n'étant pas présent sur les lieux. Entre autres, il y a une pièce XMPP (protocole autrefois nommé Jabber, ce dernier nom restant très répandu) qui permet de poser des questions et de discuter. Une personne dont le rôle est important est le scribe : il ou elle est sur place et son travail est de relayer les remarques et commentaires dans les deux sens, par exemple en allant au micro lire les questions des participants distants.

Ce RFC décrit le travail de ce scribe, qu'on nomme en général en anglais le « Jabber scribe ». Le protocole XMPP (ex-Jabber) est décrit dans le RFC 6120 et le concept de pièces où peuvent être présents plusieurs utilisateurs est dans le XEP-0045. Le rôle du scribe nécessite surtout des compétences humaines (nul besoin d'être un expert XMPP, d'ailleurs l'IETF pourrait utiliser d'autres technologies de messagerie instantanée, cela ne changerait pas grand'chose à son travail).

Les autres techniques utilisées pour permettre aux participants éloignés de suivre (comme Meetecho) sont en général unidirectionnelles. La pièce XMPP est souvent le seul endroit où ces participants peuvent être actifs et pas seulement regarder et écouter. D'où l'importance du rôle du « scribe Jabber ». Il est présent dans les différentes sessions d'une réunion IETF, notamment lors des réunions des groupes de travail, et c'est une ou un volontaire, personne n'est payé et désigné pour être scribe Jabber. Ce RFC décrit cette activité, les qualités nécessaires et comment faire pour être un bon scribe.

Premièrement, le bon scribe doit connaitre son public, les gens pour qui elle ou il travaille (section 2 du RFC). Il y en a trois catégories :

  • Les participants distants dont j'ai déjà parlé. Ils regardent les planches qui sont montrées dans la salle, ils écoutent le flux audio, mais ils voudraient aussi pouvoir intervenir (au passage, il faut se rappeler que l'IETF est une organisation ouverte, donc permettre à des gens qui n'ont pas eu le temps ou l'argent de venir est important politiquement).
  • Les participants qui sont sur le site mais sont physiquement dans une autre salle. Cela fait partie du folklore IETF de voir quelqu'un dans la salle où se réunit le groupe de travail 1 tout en suivant sur son ordinateur portable les activités des groupes de travail 2 et 3... Comme ils écoutent la salle où ils sont, ils n'ont en général pas branché le flux audio et ont donc besoin d'une pièce XMPP plus bavarde.
  • Les participants qui sont dans la salle physique, mais apprécient le fait que, dans la pièce XMPP, on peut communiquer par écrit (cela peut être plus simple pour les non-anglophones) ou simplement qu'on peut discuter sans déranger les autres (du genre « il a bien dit qu'on pouvait raccourcir un changement de clé à une semaine ? Et la section 2.2 du RFC 5011, alors, il y a pensé ? »)

Cette dernière catégorie peut dans certains cas représenter la totalité des gens présents dans la pièce XMPP. Le scribe peut donc demander s'il y a des participants non physiquement présents. Si ce n'est pas le cas, son travail est simplifié puisque tout le monde peut suivre en direct et parler au micro soi-même.

Dans la pièce XMPP, les gens ont uniquement leur identificateur XMPP qui n'est pas forcément leur nom légal. Le scribe qui doit relayer les questions au micro peut leur demander de préciser quel est le nom à annoncer. Si le participant distant veut rester anonyme, il doit le dire explicitement (les présidents du groupe de travail peuvent refuser qu'il y ait des commentaires anonymes, pour des raisons qui sont entre autres liées aux RFC sur la propriété intellectuelle, cf. RFC 8179).

Le scribe Jabber doit aussi se connaitre lui-même (section 3 du RFC). Tout le monde n'est pas un roi de la dactylographie, tout le monde ne parle pas anglais couramment (et on en entend des accents différents dans les réunions IETF) et on n'exige pas du volontaire qu'il soit un professionnel capable de transcrire en temps réel l'intégralité des débats. Si vous êtes volontaire, ajustez donc votre style de scribe à vos capacités.

Les tâches du scribe sont (section 4 du RFC) avant tout de relayer les messages des participants distants. On n'attend pas du scribe qu'il transcrive toute la session sans erreurs sur le canal XMPP. La plupart des scribes se contentent de donner quelques repères (« Joe en est maintenant à la planche 8, sur les problèmes d'implémentation du protocole », « Daneesh demande comment ont été trouvés les paramètres numériques proposés »). Les tâches importantes sont :

  • Relayer au micro les commentaires des participants distants,
  • Compter les participants distants lors des demandes des présidents de la session du genre « qui a lu le draft ? » ou « qui est volontaire pour faire une revue du document ? » ou « pensez-vous qu'on doive continuer dans cette direction ? » (notez que, dans ce dernier cas, les participants à distance ne bénéficient pas du relatif anonymat de la procédure du hummmmm),

Traditionnellement, le scribe a priorité pour l'accès au micro. C'est notamment utile pour éviter d'aggraver le délai avec lequel les participants distants reçoivent le flux audio et tapent leur contribution.

Il y a aussi d'autres tâches du scribe, moins cruciales (section 5) :

  • Indiquer dans la pièce XMPP les noms des gens qui parlent au micro (en théorie, c'est sur le flux audio, mais c'est souvent marmonné en anglais avec un accent...),
  • Indiquer le numéro de la planche actuellement affichée sur l'écran (« Now slide 13, on the risks of the new protocol »),
  • Superviser via la pièce XMPP la qualité de la retransmission audio (« On n'entend plus rien », « Il y a un écho terrible »),
  • Fournir aux participants distants des liens vers les ressources utilisées (notamment les planches de support des exposés).

Certains scribes vont jusqu'à résumer l'essentiel des exposés et des interventions sur la pièce XMPP mais ce n'est pas obligatoire.

La section 6 fournit un certain nombre de conseils aux scribes potentiels, pour qu'ils puissent s'améliorer. D'abord, évidemment, il faut apprendre XMPP et le service XMPP/Jabber de l'IETF. Il faut ensuite, si ce n'est pas déjà fait, installer un client XMPP (une bonne liste est en ligne) et apprendre à s'en servir. Le serveur XMPP de l'IETF ne permet pas la création de compte : il faut avoir un compte existant chez un des innombrables fournisseurs XMPP (comme celui de la Quadrature du Net mais il en existe plein d'autres, XMPP n'étant pas un système centralisé). Vous pouvez tester la connexion aux pièces IETF, même en dehors des réunions, en se connectant à la pièce de bavardage et de test hallway@jabber.ietf.org.

Une fois prêt, le scribe devrait, avant la session, se coordonner avec les présidents de session, apprendre les dernières nouvelles, s'assurer qu'il y a bien une retransmission etc. Il faut aussi vérifier si ces présidents ont des desiderata particuliers pour le scribe, s'ils sont bien d'accord pour que le scribe ne fasse pas la queue pour s'emparer du micro, etc.

Le scribe doit ensuite s'asseoir près du micro. Même si lui ne s'en sert pas, cela lui permettra de voir les badges des intervenants et donc de lire leur nom (ce qui limiterait les innombrables rappels « state your name, please »). Ensuite, il ou elle doit se connecter en XMPP à NOM-DE-LA-SESSION@jabber.ietf.org. Il est recommandé d'avoir également un navigateur Web ouvert, avec plusieurs onglets, affichant l'agenda de la session, la liste des liens vers les documents présentés en session, la page décrivant la retransmission, etc.

Une fois que la session a démarré, le scribe doit :

  • Bien s'identifier pour que tout le monde soit au courant de son travail (et ne proteste pas quand elle ou il passe devant tout le monde pour accéder au micro),
  • Rappeler aux participants distants qu'il est recommandé de préfixer ses interventions par MIC si on veut les voir relayées au micro,
  • Lorsqu'on parle au micro, dire bien clairement qu'on est un relais, qu'on ne parle pas pour soi-même.

Et, à la fin de la session, le scribe met un message clair dans la pièce, indiquant bien que c'est fini et que cela ne sert plus d'envoyer des commentaires.

Le scribe ultra-pro peut bénéficier des conseils de la section 7, qui donne quelques trucs avancés mais utiles. Par exemple, il est intéressant d'avoir deux clients XMPP, connectés à des comptes sur des services différents, pour faire face à certaines pannes ou délais dans le réseau (expérience vécue par les auteurs du RFC). Si le scribe est fana de métrologie, il peut aussi mesurer le délai en écoutant lui-même le flux audio de retransmission, ou en travaillant avec un participant distant de confiance, de manière à communiquer sur la pièce XMPP une estimation de ce délai.

Tout ça, c'était pour quand tout va bien. Mais, dans le monde réel, il y a parfois des gens qui abusent, surtout dans la chaleur d'une vive discussion (IDN, par exemple...). Comment les gérer (section 8) ? Le scribe n'est pas censé tout relayer. Si un participant distant écrit dans la pièce XMPP « MIC: ce connard ne connait rien à la technique et devrait fermer sa gueule », le scribe n'est nullement obligé de répéter ce commentaire verbatim au micro. La meilleure solution est sans doute de demander à l'excité de refaire son commentaire de manière plus constructive.

Ceci dit, le scribe n'a aucune autorité ou pouvoir particulier. Il ou elle est juste un participant IETF parmi les autres. Cela veut dire qu'il n'est pas obligé de faire la police, c'est le rôle des présidents de session.

Retour aux problèmes techniques dans la section 9, qui rappelle les adresses de courrier électronique à utiliser pour signaler les ennuis (de WiFi, par exemple).

Dans le monde moderne, difficile d'échapper aux problèmes posés par l'appropriation intellectuelle. La section 10, consacrée aux IPR (Intellectual Property Rights) rassure le scribe : il n'est qu'un simple relais et les obligations IETF liées à ces IPR (RFC 5378 et RFC 8179) ne le concernent pas. Ce n'est pas lui le contributeur mais la personne dont il relaie le commentaire.

Enfin, la traditionnelle section sur la sécurité (ici, section 11), clôt ce RFC. À part l'hypothèse, théoriquement possible mais qui semble assez lointaine, d'une attaque DoS contre les serveurs XMPP pour empêcher le scribe de faire son travail, cette section note que l'IETF n'a pas actuellement déployé les mécanismes d'enregistrement des utilisateurs dans ses pièces XMPP et qu'il ne faut donc pas se fier aux noms annoncés. Si quelqu'un se prétend Jari Arkko (l'actuel président de l'IETF), rien ne prouve qu'il dit vrai. « Sur XMPP, personne ne sait que vous êtes un chien. »


Téléchargez le RFC 7649


L'article seul

RFC 7646: Definition and Use of DNSSEC Negative Trust Anchors

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : P. Ebersman (Comcast), C. Griffiths, W. Kumari (Google), J. Livingood (Comcast), R. Weber (Nominum)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 25 septembre 2015


Comme toutes les techniques de sécurité, DNSSEC, qui vise à assurer l'authenticité des réponses DNS, a ses inconvénients. De même qu'une serrure fermée à clé peut avoir pour conséquence de vous empêcher de rentrer chez vous, si vous avez oublié la clé, de même DNSSEC peut empêcher d'accéder à un domaine si le gérant de la zone a commis une erreur technique. Autant le DNS d'avant était très tolérant (il fallait vraiment insister pour « planter » une zone), autant DNSSEC est délicat : les erreurs ne pardonnent pas, puisque le but de DNSSEC est justement d'empêcher l'accès aux données si elles sont suspectes. Mais les outils et les compétences pour gérer DNSSEC ne sont pas encore parfaitement au point et ne sont pas utilisés partout. Il y a donc de temps en temps des plantages, qui ont pour conséquence la panne d'une zone DNS entière. Face à ce problème, les gérants des résolveurs DNS validants aimeraient bien temporairement suspendre les vérifications, après avoir vérifié qu'il s'agissait bien d'un problème et pas d'une attaque. Cette suspension temporaire et limitée se nomme NTA pour Negative Trust Anchor et est décrite dans ce RFC.

DNSSEC est normalisé dans les RFC 4033, RFC 4034 et RFC 4035. Il permet de valider des enregistrements DNS en les signant. Plusieurs points peuvent invalider accidentellement la signature. Par exemple, les signatures ont une durée de validité limitée (pour éviter les attaques par rejeu) : si le dispositif de re-signature périodique a une panne, les signatures expirent et la zone devient invalide. Ce genre de problèmes a été très fréquent au début du déploiement de DNSSEC et n'a pas complètement disparu. Lorsque cela frappe un domaine important, cela se remarque. (Rappel : toutes les techniques de sécurité ont ce genre de problème. Qu'on pense par exemple aux innombrables expirations de certificats X.509.)

Mettez-vous deux secondes à la place du responsable des serveurs DNS récursifs (les résolveurs) d'un gros FAI, ayant beaucoup de clients. Comcast, par exemple, puisque cette entreprise a beaucoup plaidé en faveur de ce nouveau RFC. L'administrateur d'un domaine important, mettons nasa.gov, a cafouillé, la zone est invalide. Mais seuls les résolveurs validants (ceux qui protègent leurs utilisateurs avec DNSSEC) voient cela. Les autres, les anciens résolveurs non sécurisés, ne testent pas DNSSEC et la zone, pour eux, marche normalement. Les utilisateurs des FAI qui n'ont pas déployé DNSSEC pourront donc accéder aux ressources de la zone en panne, mais pas les vôtres. Ils téléphonent au support en masse, et, sur les réseaux sociaux, disent « Comcast a bloqué l'accès à nasa.gov » (oui, c'est un cas réel et qui a été souvent mal présenté dans les forums publics). Le résultat de cette mauvaise interprétation par les utilisateurs risque d'être un recul de DNSSEC : les gérants de résolveurs DNS pourraient se dire « si les mesures de sécurité embêtent les utilisateurs, coupons les mesures de sécurité ».

La « solution » proposée dans ce RFC, la NTA (Negative Trust Anchor, ou « débrayage explicite de la validation ») est une option de configuration du résolveur qui dit « ne valide pas ces domaines, je sais qu'ils sont cassés, ce n'est pas une attaque ». Chaque gérant de résolveur devra donc prendre la décision unilatérale de configurer ou pas ces NTA. Il n'est pas prévu de protocole pour les distribuer. Les NTA sont un comportement, pas un objet sur le réseau. Il n'y a pas, par exemple, d'enregistrement DNS NTA.

Au passage, s'il y a des negative trust anchor, c'est qu'il en existe des positive, non ? Le concept de « point de départ de la confiance » (trust anchor) est décrit dans le RFC 5914. Le résolveur validant vérifie une zone à partir de sa parente, la parente à partir de la grand-parente et... Il faut bien un endroit où ancrer la vérification : c'est la trust anchor, en général la clé de la racine du DNS, qui sert récursivement à valider toutes les autres. Au contraire, la NTA arrête la validation et dit « tout ce qui est en dessous n'est pas vérifié ».

La section 1.2 de notre RFC décrit plus en détail les motivations pour le concept de NTA. En effet, l'idée de base est surprenante : on dépense beaucoup d'efforts et d'argent pour déployer DNSSEC, afin de vérifier les données DNS, puis on fournit un mécanisme qui permet de débrayer la validation. L'idée a en effet suscité beaucoup de remous à l'IETF et de longues discussions. Comme souvent, le débat opposait, non pas tant les pro contre les anti, que ceux qui disaient « cela existe dans la nature, il vaut mieux le documenter » à ceux qui affirmaient « en le documentant, on le légitimise ». Les premiers l'ont finalement emporté, d'où ce RFC 7646. Les raisons sont documentées dans cette section 1.2.

Aujourd'hui, où bien des administrateurs système sont encore débutants en DNSSEC, la majorité des problèmes de validation sont dus à des erreurs de l'administrateur, pas à une vraie attaque (notez que c'est sans doute également le cas en HTTPS...) Bien sûr, les administrateurs en question devraient lire le RFC 6781, et notamment sa section 4.2. Ils éviteraient ainsi bien des malheurs. Mais, en attendant, il est pratique d'avoir un moyen pour ignorer leurs erreurs. C'est l'un des buts des NTA.

Deuxième motivation, le problème de l'utilisateur. Le DNS est une technologie d'infrastructure. Il n'est pas visible à l'utilisateur final et les problèmes au niveau DNS ne peuvent donc pas être analysés par M. Toutlemonde. C'est délibéré : tout le rôle du DNS est justement d'isoler ce M. Toutlemonde de détails pratiques, comme le fait que seenthis.net a changé d'adresse IP. Il est donc cohérent avec ce rôle que l'utilisateur final ne soit pas informé qu'il y a un problème DNSSEC. Il ne peut donc pas savoir ce qui l'empêche d'aller sur son site Web favori et, dans son ignorance, il risque de ne pas attribuer les responsabilités correctement. Comme dans l'exemple plus haut, il pourrait dire « c'est la faute de mon FAI » au lieu de pointer du doigt, à juste titre, l'administrateur de la zone mal signée. Comme dans l'exemple Comcast/NASA cité plus haut, si un domaine important est signé, et fait une erreur déclenchant un problème DNSSEC, on risque de voir vite apparaitre des gazouillis désobligeants contre le FAI, qui n'y est pourtant pour rien. Cela risque de mener la direction du FAI à ordonner qu'on arrête de valider avec DNSSEC. « Le bruit de l'alarme dérange les utilisateurs : coupez l'alarme. » Mettre une NTA pour le domaine critique en question serait certes un recul de la sécurité, mais qui pourrait éviter des reculs encore pires. (C'est compliqué, la politique de sécurité.)

Cette décision stupide pourrait aussi être prise par l'utilisateur, qui passerait d'un résolveur validant à un résolveur non validant. Sur les réseaux sociaux, les conseils idiots se propagent plus vite que les bons, surtout en matière de sécurité « zyva, mets 192.0.2.1 comme résolveur et ça va marcher ». La NTA vise à ralentir cette fuite.

La section 2 de notre RFC décrit la bonne façon d'utiliser les NTA. D'abord, avant d'installer une Negative Trust Anchor, il faut une vérification manuelle, faite par un technicien compétent, de la situation (cf. section 7 sur les tests techniques). Est-ce bien une erreur de la part du gestionnaire de la zone ? On peut s'en assurer en testant la zone depuis différents points (en comptant qu'ils n'ont probablement pas tous été victimes d'une attaque par empoisonnement en même temps) ou tout simplement en prenant connaissance d'une annonce officielle du gestionnaire de la zone, s'il y en a une. Prendre contact avec le gestionnaire de la zone permettra aussi de s'assurer que le problème est bien involontaire (cf. section 6). En tout cas, il ne faut pas installer aveuglément une NTA à chaque fois qu'une validation DNSSEC échoue : cela annulerait complètement l'intérêt de DNSSEC. D'accord, une telle vérification par un humain coûte cher mais il n'y a pas non plus de problème de ce genre tous les mois, ou même tous les trimestres.

Lors de la discussion avec le gérant de la zone, l'administrateur du résolveur qui hésite à installer une NTA peut communiquer à son interlocuteur les enregistrements DNS qu'il voit (obtenus avec dig +cd, pour ignorer la validation), afin de pouvoir s'assurer que ces enregistrements sont bons, qu'il ne s'agit pas d'une attaque. Bien sûr, il faut être pragmatique : si un gros TLD a planté son DNSSEC, rendant ainsi de nombreuses zones invalides, et que ses employés ne répondent pas, il peut être raisonnable de placer unilatéralement la NTA, compte-tenu de l'urgence.

Les NTA sont censées être une mesure sale et temporaire. Il est donc important de faire en sorte qu'elles ne restent pas éternellement, par exemple en indiquant clairement la date dans le fichier de configuration ou dans le journal.

Comme la NTA est une action « anormale » (on ignore une alerte de sécurité), le RFC recommande d'informer clairement les utilisateurs du résolveur comme l'a fait Comcast. C'est d'autant plus important que les utilisateurs n'ont pas d'autre moyen de savoir qu'une NTA est en place (le protocole DNS ne fournit pas de mécanisme pour cela).

Mettre une NTA, c'est facile. Mais il ne faut pas la laisser éternellement, sinon cette zone n'est plus protégée par DNSSEC ! Le RFC demande donc (section 4) que les NTA soient, par défaut, supprimées automatiquement, par exemple au bout d'une semaine (si c'est vraiment une panne, elle ne dure jamais plus longtemps que quelques jours). Idéalement, il faudrait tester régulièrement la validité du domaine, et retirer la NTA s'il redevient valide. À cause de ces recommandations, une gestion entièrement manuelle des NTA, comme dans l'exemple ci-dessous avec la directive domain-insecure: d'Unbound, n'est pas forcément à recommander.

Et, évidemment, une fois la NTA retirée, il faut vider les caches DNS pour la zone.

La NTA revient à prendre une décision sur la gestion d'une zone alors qu'on n'est pas le gérant de la zone. Cela doit donc rester exceptionnel. Le problème, et la solution décrite dans ce RFC, sont très spécifiques à DNSSEC, ou plus exactement à son état actuel. La section 5 de notre RFC dit clairement qu'il ne faut pas envisager de telles solutions pour d'autres problèmes. Si un gérant de zone maladroit a mis le mauvais MX dans la zone, il ne faut pas « corriger » dans les résolveurs. Le principe du DNS doit rester que le gérant de la zone fait autorité sur le contenu de la zone.

Certaines zones, comme servfail.nl cité plus loin dans un exemple, ou comme dnssec-failed.org sont cassées exprès. Leur but est de permettre de tester les outils de diagnostic ou de mesurer le nombre de validateurs. Cette mesure se fait typiquement en incluant dans une page Web un objet (une image, par exemple) accessible via un nom de domaine ainsi invalide. Si le chargement de l'objet se fait, c'est que le navigateur Web n'utilisait pas de résolveur validant.

Il ne faut évidemment pas mettre de NTA sur ces domaines volontairement invalides (section 6 de notre RFC). J'utilise servfail.nl ci-dessous mais c'est juste un exemple.

On a dit plus haut qu'une NTA ne devait être ajouté qu'après qu'un technicien DNS ait évalué l'état de la zone et déterminé que c'était bien un accident. Pour l'aider à faire cette évaluation, il existe plusieurs outils. Par exemple, l'histoire compte : si l'enregistrement de type AAAA de example.net est invalide, mais qu'il vaut 2001:db8:67::ab et qu'il a cette valeur depuis deux ans, on peut être raisonnablement sûr que c'était une erreur DNSSEC et pas une attaque. Comment sait-on que la valeur n'a pas changé depuis deux ans ? On peut utiliser une base de passive DNS comme DNSDB. Un autre outil historique important est DNSviz, qui stocke le résultat des tests DNSSEC précédents (un domaine populaire a forcément été testé plusieurs fois).

Notre RFC liste plusieurs outils de débogage qui permettent d'analyser l'état actuel de la zone :

Les deux premiers sont des logiciels libres et peuvent être installés localement sur votre machine. (Une analyse du cas de nasa.gov a été faite avec ces outils.)

En effet, dans certains cas, le résultat peut dépendre de l'endroit où vous vous trouvez. Par exemple, certaines instances d'un nuage anycast peuvent servir des signatures expirées et d'autres pas. Il est donc utile d'avoir accès à des résolveurs DNSSEC distants. On peut utiliser les sondes Atlas, ou se connecter à des serveurs distants pour y lancer dig. Si tous les résolveurs validants de la planète voient SERVFAIL, il est beaucoup plus probable qu'on soit confronté à une erreur dans la gestion de la zone qu'à une attaque par empoisonnement.

Le RFC liste aussi, dans cette section 7, les causes les plus fréquentes de problème DNSSEC aujourd'hui :

  • Signatures expirées. Les clés DNSSEC n'ont pas de durée de validité mais les signatures, si (elle vaut en général de deux à huit semaines). Avant DNSSEC, une fois qu'une zone DNS était configurée et testée, elle restait correcte plus ou moins éternellement. Depuis DNSSEC, il faut re-signer la zone régulièrement puisque les signatures expirent, même si on n'a pas changé le contenu de la zone. Cette tâche doit évidemment être automatisée (par exemple, OpenDNSSEC ou BIND peuvent le faire sans intervention humaine) mais les logiciels ont des bogues. Si le programme de re-signature ne marche plus, les signatures vont expirer. Au début, c'était quasiment la seule cause de problème DNSSEC, menant au dicton « on peut déboguer DNSSEC avec deux commandes Unix, dig et date ». Aujourd'hui que les outils automatiques sont bien plus fréquents, cette erreur est plus rare.
  • Les autres causes de problème sont toutes liées à la chaîne de confiance, qui part en général de la racine et qui, via des signatures de zone parente en zone fille, permet de valider toute information stockée dans le DNS. Si cette chaîne casse (par exemple un enregistrement DS qui pointe vers une clé inexistante), la zone est invalide. Ici, DNSviz est vraiment l'outil idéal, grâce à la représentation graphique qu'il fait de cette chaîne de confiance. La chaîne de confiance peut être cassée à la suite d'une erreur en transmettant la clé à la zone parente, ou par suite d'un changement ultérieur de clés (key rollover) en oubliant de prévenir la parente.

Enfin, la section 8 de notre RFC couvre plusieurs points de sécurité qui n'étaient pas évidents. Politiquement, la NTA est une prise du pouvoir par le résolveur, qui se permet de contrarier les résultats. C'est un mal nécessaire mais, quand même, il faut être conscient de ce décalage des responsabilités. D'où l'importance d'informer le gérant de la zone signée et de discuter avec lui/elle.

Autre problème, la NTA transforme une zone signée en zone non signée. Cela évite les erreurs de validation mais cela pose un problème pour toutes les applications qui vérifient que le contenu des données est valide (par exemple lorsqu'on lit des clés cryptographiques dans le DNS). Cette vérification se fait typiquement en regardant le bit AD (Authentic Data) dans la réponse DNS. S'il est absent, c'est que la zone n'est pas signée, et les applications risquent alors d'ignorer les informations qu'elles ont trouvées dans le DNS, faute de validation positive. C'est par exemple un problème pour DANE (RFC 6698) : si une NTA est placée, les certificats mis par DANE seront tout à coup ignorés, ce qui pourra couper l'accès à certains serveurs TLS. Le RFC estime que les applications feront de plus en plus leur propre validation, ce qui diminuera le problème, mais ce pronostic me parait très contestable.

L'annexe A du RFC contient plein d'exemples de gestion des NTA sur différents logiciels. Je vais commencer par une méthode non décrite dans le RFC, avec Unbound. Voyons d'abord un domaine invalide avec une requête normale :


% dig A www.servfail.nl

; <<>> DiG 9.9.5-9+deb8u3-Debian <<>> A www.servfail.nl
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 26269
...

On récupère un SERVFAIL (Server Failure) ce qui est normal puisque ce domaine est (délibérement) invalide. Essayons avec l'option +cd (Checking Disabled) qui indique au résolveur de ne pas valider :

  
% dig +cd A www.servfail.nl

; <<>> DiG 9.9.5-9+deb8u3-Debian <<>> +cd A www.servfail.nl
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53947
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;www.servfail.nl.       IN A

;; ANSWER SECTION:
www.servfail.nl.        60 IN CNAME www.forfun.net.
...

Maintenant, modifions la configuration d'Unbound en ajoutant dans le unbound.conf la Negative Trust Anchor :

# Added on 2015-09-22, after confirmation from <foobar@forfun.net>
domain-insecure: "servfail.nl"

Notez l'importance de mettre la date dans le fichier de configuration : les NTA ne doivent pas être permanentes. On recharge la configuration :

% sudo unbound-control reload
ok

Et on réessaie :

    
% dig A www.servfail.nl

; <<>> DiG 9.9.5-9+deb8u3-Debian <<>> A www.servfail.nl
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62157
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 4, ADDITIONAL: 13

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;www.servfail.nl.       IN A

;; ANSWER SECTION:
www.servfail.nl.        60 IN CNAME www.forfun.net.

Notez qu'on a eu la réponse mais que le bit AD (Authentic Data) n'est évidemment pas mis, comme discuté en section 8 du RFC.

Cette méthode a l'inconvénient d'être un peu trop manuelle et de ne pas être automatiquement réversible. À noter que l'annexe A du RFC cite également une méthode qui ne nécessite pas de changer le fichier de configuration, mais utilise l'outil de contrôle à distance d'Unbound (qu'il faut configurer préalablement) :

[Quels NTA sont installées ? ]
% sudo unbound-control list_insecure
%
[Aucun]

[On installe une NTA]
% sudo unbound-control insecure_add servfail.nl
ok
% sudo unbound-control list_insecure           
servfail.nl.

% dig A www.servfail.nl                        
...
www.servfail.nl.        60 IN CNAME www.forfun.net.
...

[On retire la NTA]
% sudo unbound-control insecure_remove servfail.nl
ok
% sudo unbound-control list_insecure              
%

BIND n'a pas d'équivalent de la directive domain-insecure:. C'est une de ses faiblesses. Mais il permet, à partir des récentes versions (non encore publiques, apparemment réservées aux clients payants), d'avoir des NTA plus conformes à ce que demande le RFC, notamment avec retrait automatique au bout d'un temps donné. Je n'ai pas testé donc voici les commandes que donne le RFC :

[Quels NTA sont installées ? ]
% sudo rndc nta -dump

[On installe une NTA pour une heure - la valeur par défaut]
% sudo rndc nta servfail.nl

[On retire explicitement la NTA (sinon, il est retiré automatiquement)]
% sudo rndc nta -remove servfail.nl

Téléchargez le RFC 7646


L'article seul

RFC 7632: Endpoint Security Posture Assessment: Enterprise Use Cases

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : D. Waltermire, D. Harrington
Pour information
Première rédaction de cet article le 25 septembre 2017


La sécurité est évidemment une préoccupation courante quand on gère un réseau (« enterprise network » dit ce document, mais cela s'applique à n'importe quel réseau, capitaliste ou pas). Parmi les problèmes, déterminer l'état de la sécurité de chaque machine du réseau (son logiciel est à jour ? Pas de RAT installé ?) est un des plus importants. Ce RFC décrit des scénarios où on cherche à analyser cet état de la sécurité.

Disons-le tout de suite, une grande partie du RFC est du jargon « process » (quand on remplace l'intelligence par la paperasserie). Si vous n'êtes pas manager chargé d'obtenir une certification ISO 27001, cela ne vous intéressera guère. La seule partie utile est, dans section 2.2 du RFC, quelques scénarios intéressants.

J'ai bien aimé le scénario de la section 2.2.5, où un groupe de chercheurs (ah, justement, ce n'est plus du « enterprise network ») travaille dans la station polaire Zebra (oui, c'est une référence au film) et doit maintenir à jour ses ordinateurs, malgré une liaison Internet intermittente, chère (et la recherche publique n'a jamais d'argent) à faible capacité et énorme latence. Non seulement les conditions sont très dures, mais ils doivent en outre se plier à la « conformité » (compliance), le buzz word à la mode. Une partie du temps de recherche sera donc consommé à suivre les process.


Téléchargez le RFC 7632


L'article seul

RFC 7626: DNS privacy considerations

Date de publication du RFC : Août 2015
Auteur(s) du RFC : S. Bortzmeyer (AFNIC)
Pour information
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 27 août 2015


Les révélations d'Edward Snowden en juin 2013 ont fait comprendre à tous, même aux plus obtus qui s'obstinaient à nier l'ampleur et la gravité de la surveillance généralisée, que les problèmes de vie privée ne sont pas un simple détail. Au contraire, il est maintenant établi que l'Internet, et les technologies numériques en général, sont utilisés comme arme de surveillance massive par le gouvernement des États-Unis et, quasi-certainement, par plusieurs autres, dans la mesure de leurs moyens. Cela a mené l'IETF, qui avait parfois tendance à relativiser l'intensité du problème, à se pencher sérieusement sur la question. Plusieurs travaux ont été lancés. L'un d'eux concerne la protection de la vie privée lors de l'utilisation du DNS et ce nouveau RFC, écrit par votre serviteur, est son premier résultat.

Ce RFC est en fait à la croisée de deux activités. L'une d'elles consiste à documenter les problèmes de vie privée, souvent ignorés jusqu'à présent dans les RFC. Cette activité est symbolisée par le RFC 6973, dont la section 8 contient une excellente analyse de ces problèmes, pour un service particulier (la présence en ligne). L'idée est que, même si on ne peut pas résoudre complètement le problème, on peut au moins le documenter, pour que les utilisateurs soient conscients des risques. Et la seconde activité qui a donné naissance à ce RFC est le projet d'améliorer effectivement la protection de la vie privée des utilisateurs du DNS, en marchant sur deux jambes : minimiser les données envoyées (c'est le sous-projet qname minimization) et les rendre plus résistantes à l'écoute, via le chiffrement. La diminution des données est étudiée dans le groupe de travail IETF dnsop (le principal document est DNS query name minimisation to improve privacy) et le chiffrement dans le groupe de travail IETF dprive (le principal document est TLS for DNS: Initiation and Performance Considerations, qui propose de faire circuler les requêtes DNS sur TLS). Le groupe dprive (le nom, contraction de DNS privacy, suit la tradition des noms de groupes humoristiques, ce qui est fréquent à l'IETF, et est dû à Alexander Mayrhofer) est également l'enceinte où a été développé le RFC 7626, objet principal de cet article.

Donc, pourquoi un RFC sur les questions de vie privée dans le DNS ? Ce dernier est un très ancien protocole, dont l'une des particularités est d'être mal spécifié : aux deux RFC originaux, les RFC 1034 et RFC 1035, il faut ajouter dix ou vingt autres RFC dont la lecture est nécessaire pour tout comprendre du DNS. Et aucun travail de consolidation n'a jamais été fait, contrairement à ce qui a eu lieu pour XMPP, HTTP ou SMTP. Or, le DNS est crucial, car quasiment toutes les transactions Internet mettent en jeu au moins une requête DNS (ne me dites pas des bêtises du genre « moi, je télécharge avec BitTorrent, je n'utilise pas le DNS » : comment allez-vous sur thepiratebay.am ?) Mais, alors que les questions de vie privée liées à HTTP ont fait l'objet d'innombrables articles et études, celles liées au DNS étaient largement ignorées (voir la bibliographie du RFC pour un état de l'art). Pourtant, on peut découvrir bien des choses sur votre activité Internet uniquement en regardant le trafic DNS.

Une des raisons du manque d'intérêt pour le thème « DNS et vie privée » est le peu de compétences concernant le DNS : le protocole est souvent ignoré ou mal compris. C'est pourquoi le RFC doit commencer par un rappel (section 1) du fonctionnement du DNS.

Je ne vais pas reprendre tout le RFC ici. Juste quelques rappels des points essentiels du DNS : il existe deux sortes de serveurs DNS, qui n'ont pratiquement aucun rapport. Il y a les serveurs faisant autorité et les résolveurs. Les premiers sont ceux qui connaissent de première main l'information pour une zone DNS donnée (comme fr ou wikipedia.org). Ils sont gérés par le titulaire de la zone ou bien sous-traités à un hébergeur DNS. Les seconds, les résolveurs, ne connaissent rien (à part l'adresse IP des serveurs de la racine). Ils interrogent donc les serveurs faisant autorité, en partant de la racine. Les résolveurs sont gérés par le FAI ou le service informatique qui s'occupe du réseau local de l'organisation. Ils peuvent aussi être individuels, ou bien au contraire être de gros serveurs publics comme Google Public DNS, gros fournisseur de la NSA. Pour prendre un exemple concret (et en simplifiant un peu), si M. Michu veut visiter le site Web http://thepiratebay.am/, son navigateur va utiliser les services du système d'exploitation sous-jacent pour demander l'adresse IP de thepiratebay.am. Le système d'exploitation va envoyer une requête DNS au résolveur (sur Unix, les adresses IP des résolveurs sont dans /etc/resolv.conf). Celui-ci va demander aux serveurs de la racine s'ils connaissent thepiratebay.am, il se fera rediriger vers les serveurs faisant autorité pour am, puis vers ceux faisant autorité pour thepiratebay.am. Le résolveur aura alors une réponse qu'il pourra transmettre au navigateur de M. Michu.

Principal point où j'ai simplifié : le DNS s'appuie beaucoup sur la mise en cache des données, c'est-à-dire sur leur mémorisation pour gagner du temps la fois suivante. Ainsi, si le même M. Michu, cinq minutes après, veut aller en http://armenpress.am/, son résolveur ne demandera rien aux serveurs de la racine : il sait déjà quels sont les serveurs faisant autorité pour am.

Le trafic DNS est un trafic TCP/IP ordinaire, typiquement porté par UDP. Il peut être écouté, et comme il n'est aujourd'hui pas chiffré, un indiscret peut tout suivre. Voici un exemple pris avec tcpdump sur un serveur racine (pas la racine officielle, mais, techniquement, cela ne change rien) :

15:29:24.409283 IP6 2001:67c:1348:8002::7:107.10127 > \
    2001:4b98:dc2:45:216:3eff:fe4b:8c5b.53: 32715+ [1au] \
    AAAA? www.armenpress.am. (46)

On y voit que le client 2001:67c:1348:8002::7:107 a demandé l'adresse IPv6 de www.armenpress.am.

Pour compléter le tableau, on peut aussi noter que les logiciels génèrent un grand nombre de requêtes DNS, bien supérieur à ce que voit l'utilisateur. Ainsi, lors de la visite d'une page Web, le résolveur va envoyer la requête primaire (le nom du site visité, comme thepiratebay.am), des requêtes secondaires dues aux objets contenus dans la page Web (JavaScript, CSS, divers traqueurs et autres outils de cyberflicage ou de cyberpub) et même des requêtes tertiaires, lorsque le fonctionnement du DNS lui-même nécessitera des requêtes. Par exemple, si abc.xyz est hébergé sur des serveurs dans google.com, une visite de http://abc.xyz/ nécessitera de résoudre les noms comme ns1.google.com, donc de faire des requêtes DNS vers les serveurs de google.com.

Bien sûr, pour un espion qui veut analyser tout cela, le trafic DNS représente beaucoup de données, souvent incomplètes en raison de la mise en cache, et dont l'interprétation peut être difficile (comme dans l'exemple ci-dessus). Mais les organisations qui pratiquent l'espionnage massif, comme la NSA, s'y connaissent en matière de big data et savent trouver les aiguilles dans les bottes de foin.

La section 2 du RFC détaille les risques pour la vie privée dans les différents composants du DNS. Notez que la confidentialité du contenu du DNS n'est pas prise en compte (elle l'est dans les RFC 5936 et RFC 5155). Il est important de noter qu'il y a une énorme différence entre la confidentialité du contenu et la confidentialité des requêtes. L'adresse IP de www.charliehebdo.fr n'est pas un secret : les données DNS sont publiques, dès qu'on connait le nom de domaine, et tout le monde peut faire une requête DNS pour la connaitre. Mais le fait que vous fassiez une requête pour ce nom ne devrait pas être public. Vous n'avez pas forcément envie que tout le monde le sache.

Pour comprendre les risques, il faut aussi revenir un peu au protocole DNS. Les deux informations les plus sensibles dans une requête DNS sont l'adresse IP source et le nom de domaine demandé (qname, pour Query Name, cf. RFC 1034, section 3.7.1). L'adresse IP source est celle de votre machine, lorsque vous parlez au résolveur, et celle du résolveur lorsqu'il parle aux serveurs faisant autorité. Elle peut indiquer d'où vient la demande. Lorsque on utilise un gros résolveur, celui-ci vous masque vis-à-vis des serveurs faisant autorité (par contre, ce gros résolveur va avoir davantage d'informations).

Quant au qname, il peut être très révélateur : il indique les sites Web que vous visitez, voire, dans certains cas, les logiciels utilisés. Au moins un client BitTorrent fait des requêtes DNS pour _bittorrent-tracker._tcp.domain.example, indiquant ainsi à beaucoup de monde que vous utilisez un protocole qui ne plait pas aux ayant-droits. Et si vous utilisez le RFC 4255, pas mal de serveurs verront à quelles machines vous vous connectez en SSH...

Donc où un méchant qui veut écouter votre trafic DNS peut-il se placer ? D'abord, évidemment, il suffit qu'il écoute le trafic réseau. On l'a dit, le trafic DNS aujourd'hui est presque toujours en clair donc tout sniffer peut le décoder. Même si vous utilisez HTTPS pour vous connecter à un site Web, le trafic DNS, lui, ne sera pas chiffré. (Les experts pointus de TLS noteront qu'il existe d'autres faiblesses de confidentialité, comme le SNI du RFC 6066.) À noter une particularité du DNS : le trafic DNS peut passer par un autre endroit que le trafic applicatif. Alice peut naïvement croire que, lorsqu'elle se connecte au serveur de Bob, seul un attaquant situé physiquement entre sa machine et celle de Bob représente une menace. Alors que son trafic DNS peut être propagé très loin, et accessible à d'autres acteurs. Si vous utilisez, par exemple, le résolveur DNS public de FDN, toute la portion de l'Internet entre vous et FDN peut facilement lire votre trafic DNS.

Donc, l'éventuel espion peut être près du câble, à écouter. Mais il peut être aussi dans les serveurs. Bercé par la musique du cloud, on oublie souvent cet aspect de la sécurité : les serveurs DNS voient passer le trafic et peuvent le copier. Pour reprendre les termes du RFC 6973, ces serveurs sont des assistants : ils ne sont pas directement entre Alice et Bob mais ils peuvent néanmoins apprendre des choses à propos de leur conversation. Et l'observation est très instructive. Elle est utilisée à de justes fins dans des systèmes comme DNSDB (section 3 du RFC) mais il n'est pas difficile d'imaginer des usages moins sympathiques comme dans le cas du programme NSA MORECOWBELL.

Les résolveurs voient tout le trafic puisqu'il y a peu de mise en cache en amont de ces serveurs. Il faut donc réfléchir à deux fois avant de choisir d'utiliser tel ou tel résolveur ! Il est déplorable qu'à chaque problème DNS (ou supposé tel), des ignorants bondissent sur les réseaux sociaux pour dire « zyva, mets 8.8.8.8 [Google Public DNS] comme serveur DNS et ça ira plus vite » sans penser à toutes les données qu'ils envoient à la NSA ainsi.

Les serveurs faisant autorité voient passer moins de trafic (à cause des caches des résolveurs) mais, contrairement aux résolveurs, ils n'ont pas été choisis délibérement par l'utilisateur. Celui-ci peut ne pas être conscient que ses requêtes DNS seront envoyées à plusieurs acteurs du monde du DNS, à commencer par la racine. Le problème est d'autant plus sérieux que, comme le montre une étude, la concentration dans l'hébergement DNS est élevée : dix gros hébergeurs hébergent le tiers des domaines des 100 000 sites Web les plus fréquentés (listés par Alexa).

Au passage, le lecteur attentif aura noté qu'un résolveur personnel (sur sa machine ou dans son réseau local) a l'avantage de ne pas envoyer vos requêtes à un résolveur peut-être indiscret mais l'inconvénient de vous démasquer vis-à-vis des serveurs faisant autorité, puisque ceux-ci voient alors votre adresse IP. Une bonne solution (qui serait également la plus économe des ressources de l'Internet) serait d'avoir son résolveur local et de faire suivre les requêtes non résolues au résolveur du FAI. Du point de vue de la vie privée, ce serait sans doute la meilleure solution mais cela ne résout hélas pas un autre problème, celui des DNS menteurs, contre lesquels la seule protection est d'utiliser uniquement un résolveur de confiance.

Enfin, il y a aussi les serveurs DNS « pirates » (installés, par exemple, via un serveur DHCP lui-même pirate) qui détournent le trafic DNS, par exemple à des fins de surveillance. Voir par exemple l'exposé de Karrenberg à JCSA 2012 disponible en ligne (transparents 27 et 28, Unknown et Other qui montrent l'existence de clones pirates du serveur racine K.root-servers.net).

Pour mes lecteurs français férus de droit, une question intéressante : le trafic DNS est-il une « donnée personnelle » au sens de la loi Informatique & Libertés ? Je vous laisse plancher sur la question, qui a été peu étudiée.

Quelques élements d'histoire de ce RFC pour finir, puisque j'ai vécu tout son cycle de vie (c'est mon premier RFC publié). Sa première version a été entièrement écrite, dans un avion de la KLM entre Amsterdam et Vancouver, où j'allais à une réunion IETF en novembre 2013. Long vol sans connexion Internet, donc sans distractions, sièges de la classe affaires et présence de plusieurs collègues qui vous stimulent et avec qui discuter (merci au passage à Olaf Kolkman pour avoir insisté « il faut que tu publies cela »), cela fait d'excellentes conditions de travail.

Le RFC venant d'être publié, on voit qu'il aura fallu moins de deux ans en tout, alors qu'on raconte souvent que l'IETF est lente (sur le fonctionnement de l'IETF, voir mon exposé à JRES). Pour avoir une idée des changements entre le premier « draft KLM » et l'actuel RFC, vous pouvez voir un calcul automatique des différences.

Quelques autres lectures utiles :


Téléchargez le RFC 7626


L'article seul

RFC 7624: Confidentiality in the Face of Pervasive Surveillance: A Threat Model and Problem Statement

Date de publication du RFC : Août 2015
Auteur(s) du RFC : R. Barnes, B. Schneier, C. Jennings, T. Hardie, B. Trammell, C. Huitema, D. Borkmann
Pour information
Première rédaction de cet article le 3 septembre 2015


La publication, grâce à Edward Snowden, d'affreux PowerPoint® de la NSA montrant l'ampleur de la surveillance permanente et généralisée a suscité une prise de conscience chez tous les acteurs de l'Internet. (D'autant plus que d'autres pays en font autant, comme la France, surtout depuis la Loi Renseignement.) Ces PowerPoint® sont souvent d'interprétation difficile et il est donc nécessaire, lorsqu'on travaille aux contre-mesures, d'avoir un modèle clair de la menace contre laquelle on tente de défendre les citoyens internautes. Ce nouveau RFC est l'une des étapes dans ce travail à l'IETF : décrire clairement les risques de la surveillance généralisée.

Ce RFC est écrit par l'IAB, et on note parmi les auteurs Bruce Schneier. Il ne s'agit pas de revenir sur le problème bien connu de l'espionnage des communications (qui est aussi ancien que les réseaux), mais sur les nouveautés qui résultent de la prise de conscience d'un espionnage illimité et indiscriminé (cf. RFC 7258 pour la décision politique de considérer cet espionnage comme une attaque contre l'Internet). Les programmes de la NSA, avec leurs noms rigolos, n'utilisent pas de vulnérabilités inconnues. Aucune science-fiction derrière PRISM, TEMPORA ou BULLRUN. Ces programmes exploitent uniquement des risques connus, mais de manière massive, avec un budget très élevé et une absence totale de scrupules.

Notre nouveau RFC commence donc logiquement par un peu de terminologie (section 2). Il réutilise d'autre part les précédents RFC analogues notamment celui de terminologie de la sécurité (RFC 4949) et celui d'analyse de la protection de la vie privée (RFC 6973). Notons deux choses importantes : d'abord la distinction entre attaques passives et actives. La différence ne vient pas de l'effort de l'attaquant (monter une attaque passive peut être beaucoup de travail) mais du fait que, dans le premier cas, l'attaquant n'écrit rien sur le réseau, n'envoie aucun paquet, ne stoppe aucune communication et ne modifie aucun bit. Il espionne, c'est tout. Au contraire, dans une attaque active comme QUANTUM, le surveillant se permet d'interférer avec les communications, changeant le contenu d'un paquet, envoyant des paquets (pour de l'ARP spoofing par exemple, ou de l'empoisonnement de cache DNS), bloquant certains paquets (par exemple pour faire une attaque par repli contre TLS).

Et la deuxième chose importante est le terme relativement nouveau d'attaque généralisée (pervasive attack), qui désigne les attaques menées, non pas par le lycéen dans son garage, mais par un organisme puissant, pouvant observer (et peut-être intervenir) en de très nombreux points du réseau, avec des capacités big data.

Commençons par décrire l'attaquant, étape indispensable pour élaborer un modèle de menace (section 3). D'abord, un modèle d'un attaquant purement passif (et donc moins puissant que la NSA). S'il est purement passif, cet attaquant « idéal » (idéal du point de vue du modèle, pas du point de vue légal ou moral) a quand même de grandes possibilités, notamment quantitatives. Il voit tout, partout. Le RFC note à juste titre qu'avant les révélations de Snowden (qu'on ne remerciera jamais assez pour ce qu'il a fait), un tel attaquant aurait été considéré comme le produit d'un esprit à la limite de la paranoïa, à part chez les experts en sécurité (qui se doutaient bien, même avant Snowden, de la réalité de la surveillance massive). Cet attaquant peut notamment :

  • Observer tous les paquets, où qu'ils passent,
  • Observer les données stockées dans les différentes machines (comme le permet PRISM),
  • Collaborer avec d'autres attaquants (comme le font les Five Eyes),
  • Mais ne peut pas bloquer, modifier, injecter, il est purement passif.

L'attaquant doit donc se débrouiller avec ce qu'il observe directement, puisqu'il ne peut pas le modifier, et ce qu'il en déduit (inférence, c'est-à-dire dériver des informations de celles qu'on a déjà).

Le chiffrement, même sans authentification, protège largement contre un tel attaquant, en réduisant sérieusement les observations qu'il peut faire. (À condition que ce chiffrement soit bien réalisé, par exemple que les générateurs aléatoires soient de qualité. Cette condition est, en pratique, très difficile à remplir.) Le chiffrement est par contre moins efficace contre l'inférence. Par exemple, les fameuses métadonnées laissées en clair (en-têtes IP et TCP lorsqu'on utilise TLS) peuvent donner plein d'information. Un autre exemple est la taille des paquets (qui permet de savoir si on a envoyé ou reçu un fichier), une information que TLS (ou SSH) ne brouille pas. Même IPsec/ESP, s'il chiffre l'en-tête de couche 4, laisse la couche 3 (IP) en clair.

L'idéal bien sûr pour notre attaquant modèle est quand il n'y a pas de chiffrement. Quand tout est en clair, le contenu des communications est accessible trivialement. Voilà pourquoi le RFC 3365 (en 2002 ! Ça ne nous rajeunit pas.) disait déjà que tout protocole IETF susceptible d'envoyer des données en clair doit avoir une version sécurisée qui chiffre. C'est le cas de presque tous les protocoles aujourd'hui. Le RFC note qu'il y a une exception avec le DNS mais elle est en train d'être comblée par le groupe de travail DPRIVE, (cf. le RFC 7626).

L'inférence peut aussi utiliser des informations qui se trouvent dans des bases de données extérieures à la communication elle-même. Par exemple, comme l'ICANN impose de publier les coordonnées des titulaires des noms de domaine dans les TLD qu'elle contrôle, ces informations peuvent nourrir l'inférence. Même chose avec les bases géoIP ou, encore mieux, avec la quantité d'informations disponibles dans des réseaux sociaux comme Facebook. Ces dernières sources sont très riches, avec de l'information déjà structurée et envoyée « volontairement » par les utilisateurs. Cela met une sérieuse limite à ce que l'IETF peut faire pour améliorer la vie privée sur l'Internet : améliorer les protocoles n'est pas suffisant.

Notre RFC détaille comment inférer à partir des observations directes. Par exemple, pour corréler des adresses IP avec des utilisateurs, on a plusieurs outils : une requête DNS « inverse » (type PTR) suffit parfois. Ces requêtes marchent bien pour les serveurs, peu nombreux et stables (donc une copie locale peut être facilement faite, pour accélerer le processus). Elles sont moins efficaces pour les clients (on obtient parfois des trucs sans trop d'intérêt comme ARouen-655-1-102-140.w90-23.abo.wanadoo.fr). Notez que le RFC étudie les possibilités de surveillance massive. La technique (légale dans de nombreux pays démocratiques) qui consiste pour la police à demander au FAI le nom de l'utilisateur correspond à telle adresse IP ne marche pas ici, elle ne passe pas à l'échelle. C'est un exemple de la différence entre enquêtes ciblées et surveillance généralisée, style Big Brother.

Même si le FAI ne coopère pas dans la mission de surveillance, il existe d'autres moyens de relier une adresse IP à des identités de l'utilisateur. Par exemple, s'il utilise IMAP, on a facilement son identificateur, sauf si la session est chiffrée (ce qui n'est pas encore fait partout). Le problème n'est pas spécifique à IMAP et se trouve aussi dans SIP et dans bien d'autres protocoles. Chiffrer la session n'est donc pas uniquement utile lorsqu'on a « quelque chose à cacher » mais aussi simplement lorsqu'on veut éviter d'être suivi à la trace. Un autre exemple amusant est décrit en section 3.3.4 : l'utilisation des en-têtes Received: du courrier. Même si tout le courrier est chiffré, l'attaquant peut toujours s'abonner à des listes de discussion publiques comme perpass. Il reçoit alors des messages avec ce genre d'en-têtes :

Received: from 192-000-002-044.zone13.example.org (HELO ?192.168.1.100?) (xxx.xxx.xxx.xxx) by lvps192-000-002-219.example.net
   with ESMTPSA (DHE-RSA-AES256-SHA encrypted, authenticated); 27 Oct 2013 21:47:14 +0100
Message-ID: <526D7BD2.7070908@example.org>
Date: Sun, 27 Oct 2013 20:47:14 +0000
From: Some One <some.one@example.org>
    

Collectionner ces en-têtes va lui permettre de compiler une base des émetteurs et des adresses IP qu'ils utilisent. Au bout d'un moment, l'attaquant saura que, si un paquet IP vient de 192.0.2.44, il y a de fortes chances que ce soit l'utilisateur Some One.

Parmi les techniques d'inférence, il y a aussi celles fondées sur les graphes de relations. Si une adresse IP envoie X % de ses paquets à l'IETF, Y % au MIT et Z % à YouPorn, l'observation ultérieure d'une toute autre adresse IP qui a le même graphe de relations peut permettre de conclure que la même personne est derrière les deux adresses.

Il y a aussi les adresses MAC. Celles-ci sont uniques au niveau mondial et sont en général très stables (peu de gens utilisent macchanger). Si le réseau est publiquement accessible (ce qui est typiquement le cas des hotspots WiFi), l'attaquant peut facilement regarder « qui est là » et mettre à jour sa base de données. Notez que certaines techniques, comme les SSID cachés aggravent le risque : la machine de l'utilisateur va diffuser les SSID qu'elle cherche, donnant ainsi davantage d'informations à l'attaquant. Des bases de données des hotspots existent déjà (constituées, par exemple, par les utilisateurs d'Android, dont le smartphone transmet à Google et à la NSA plein d'informations sur les SSID détectés). C'est évidemment encore plus facile pour l'attaquant si le réseau WiFi n'utilise pas WPA ou équivalent (tapez sur votre fournisseur WiFi si ce n'est pas le cas).

Ce très intéressant exposé des techniques d'espionnage existantes est évidemment incomplet : nul doute que la NSA ou la DGSI ont plein d'autres idées. Et il y a certainement des différences entre la théorie de la section 3 et la réalité de la surveillance massive effectuée par ces organisations. Il est bien sûr impossible de savoir exactement ce que la NSA sait faire. Tout au plus peut-on faire quelques suppositions raisonnables (section 4 de notre RFC). D'abord, les révélations Snowden ne laissent pas de doute sur l'existence de cette surveillance généralisée effectuée par la NSA et le GCHQ (notez que notre RFC ne fait pas dans la fausse pudeur, et cite les noms de ces organisations, alors qu'avant on ne parlait que de « certaines agences gouvernementales »). Ensuite, ces mêmes révélations donnent une première idée des méthodes utilisées. Et il n'y a pas que la NSA et ses collaborateurs : nul doute que les services secrets français, chinois, russes ou israéliens espionnent également massivement, dans la mesure de leurs moyens matériels et de leurs compétences. Mais on n'a pas encore les détails, on attend un héros comme Snowden dans ces pays moins imbibés de culture démocratique.

Donc, reality check, à la lumière des révélations Snowden, que fait effectivement la NSA, par rapport à l'attaquant passif idéalisé de la section 3 ? D'abord, cette organisation d'espionnage a effectivement une activité massive de collecte passive :

  • Son système XKEYSCORE surveille l'Internet depuis un très grand nombre de points de mesure, à la recherche d'élements indiquant une cible (comme une adresse de courrier particulière),
  • Le programme TEMPORA du GCHQ espionne les câbles sous-marins (environ 1 500 d'entre eux),
  • Et on peut aussi citer MUSCULAR, qui se branche sur les câbles reliant les différents centres de données de gros acteurs Internet, pour capturer leur trafic interne.

Ce n'est pas tout de capturer, il faut aussi décoder, et une partie du trafic est chiffré. La NSA ne renonce pas devant le chiffrement et, par exemple, son programme BULLRUN met en œuvre divers moyens pour affaiblir la protection qu'offre la cryptographie, par exemple par des modifications du code.

Et, surtout, la NSA ne se contente pas d'attaques passives, comme le faisait l'attaquant modélisé en section 3. Elle a aussi des mécanismes actifs :

Si les révélations Snowden ne portent que sur la NSA et le GCHQ, le RFC rappelle que d'autres États n'hésitent certainement pas à recourir aux mêmes méthodes, et le cas évident de la Chine est cité, avec les techniques de modification de données utilisées par le GFW, techniques qui rappellent fortement le QUANTUM états-unien. Par exemple, le réseau chinois n'hésite pas à modifier les réponses DNS. De l'espionnage actif à l'attaque par déni de service, il n'y a qu'un pas, que le gouvernement chinois a franchi avec le Grand Canon et peut-être avec l'attaque « Poivre du Sichuan ».

La section 5 de notre RFC synthétise la menace à laquelle nous devons désormais faire face. Les attaquants comme la NSA ou la DGSE peuvent :

  • Effectuer passivement des observations (cf. la section 3),
  • Inférer, à partir des observations,
  • Contrairement à l'attaquant passif de la section 3, ces organisations peuvent aussi faire des attaques actives,
  • La cryptographie ne protège pas dans 100 % des cas : entre autres contre-mesures, ces organisations peuvent obtenir des clés privées, soit ponctuellement (piratage d'un ordinateur, fausse manœuvre de l'utilisateur), soit systématiquement (faille de sécurité délibérement introduite dans le logiciel via BULLRUN, piratage d'un fournisseur),
  • Et, enfin, obtenir les données stockées, ce que le chiffrement de la communication n'empêche pas (programme PRISM, où des collaborateurs de la NSA comme Google lui donnent accès à leurs données).

La traditionnelle opposition attaquant passif / attaquant actif des analyses de sécurité est sans doute insuffisante dans le cas de la surveillance systématique. Les trois dernières possibilités citées plus haut (obtention ponctuelle des clés, obtention systématique des clés et accès aux données stockées) étaient ainsi absentes ou très sous-estimées, avant Snowden. En outre, comme ces trois possibilités se situent en dehors des protocoles réseau, l'IETF tendait à les négliger, les considérant comme hors de son domaine.

Autrefois, on considérait que les attaquants actifs étaient forcément situés en bordure du réseau : sur un hotspot WiFi non protégé par WPA, une attaque active est triviale, pour toute personne connectée à ce hotspot. Mais les organisations comme la NSA peuvent également agir au cœur de l'Internet, ce qui augmente sérieusement leurs possibilités. J'avais entendu lors d'une conférence de sécurité un expert affirmer qu'il ne fallait jamais utiliser la WiFi mais toujours la 3G pour des raisons de sécurité. Ce conseil peut avoir un sens face à un attaquant lycéen dans son garage mais certainement pas face à des organisations importantes, pour qui le réseau de l'opérateur 3G est terrain de chasse libre.

La différence quantitative entre le cracker de base dans son garage et une organisation étatique ou para-étatique devient en outre une différence qualitative. Le fait de pouvoir tout observer rend l'inférence beaucoup plus efficace, même en cas de chiffrement. Ainsi, un observateur présent en beaucoup d'endroits peut corréler des flux réseau entre eux, même s'ils sont chiffrés. Un observateur présent en un seul point du réseau n'a pas cette possibilité. Un simple VPN chiffré peut le rendre aveugle, alors que l'observateur présent partout peut trouver les serveurs où on se connecte uniquement en corrélant le trafic du VPN avec le trafic simultané en un autre point de l'Internet (XKEYSCORE fait apparemment cela.)

En prime, les attaquants susceptibles de monter un système de surveillance massive, comme la DGSE, sont également souvent capables de subvertir l'authentification. Chiffrer, en effet, ne sert pas beaucoup si on chiffre, non pas pour le vrai destinataire mais pour l'homme du milieu. La protection habituelle contre ces attaques de l'homme du milieu est l'authentification. Par exemple, on vérifie l'identité du correspondant via un certificat X.509. Mais une organisation puissante peut contraindre les autorités de certification à émettre de vrais/faux certificats. Comme il suffit d'une seule autorité de certification contrainte (ou piratée, ce qui revient au même) pour faire un certificat pour n'importe quel serveur, on voit que la NSA n'a que l'embarras du choix.

Tout cela ne veut pas forcément dire qu'un attaquant puissant comme la NSA ou le FSB a table ouverte. Ces attaques ont des coûts et l'analyse de ces coûts est une branche relativement récente de la sécurité (elle est bien illustrée dans un excellent dessin de XKCD). On ne peut évidemment pas espérer aveugler les agences d'espionnage mais on peut augmenter le prix de leurs activités, jusqu'à les forcer à réduire ces activités. La section 5.2 de notre RFC discute ces coûts.

Tous ne sont pas forcément monétaires. Par exemple, comme les espions, à l'égal des cloportes, n'aiment pas la lumière, le risque d'être pris la main dans le sac, représente un coût. Cela suppose évidemment que l'espion soit détecté et identifié. Si c'est fait, les conséquences peuvent aller de la fermeture d'une voie d'accès aux données, à des poursuites judiciaires, ou à la démission d'un ministre bouc émissaire.

Par exemple, une attaque passive offre à priori moins de chance de se faire attraper puisqu'on ne modifie pas le trafic. Sauf qu'un branchement physique sur des câbles va laisser des traces (les plombiers du Watergate ou du Canard Enchainé en savent quelque chose). Si l'opérateur réseau n'est pas complice de l'attaquant (il semble que, dans le cas de TEMPORA, il l'était), la « bretelle » peut être découverte à l'occasion d'une opération de maintenance, comme ce fut le cas dans l'affaire de Tarnac. Même si l'écoute se faisait de manière purement logicielle, un employé zélé peut la détecter un jour (« mais pourquoi ce port du commutateur est-il en mode miroir ? »). Les techniques sans-fil ne nécessitent pas de branchement physique mais, souvent, la portée utile est faible et l'attaquant doit se rapprocher, ce qui peut mener à sa détection. Bref, la vie d'un espion n'est pas toujours facile. Si l'opérateur collabore, c'est plus facile pour l'espion mais, s'il y a un Snowden parmi les employés de l'opérateur, patatras, la belle opération secrète d'écoute finit en une du Monde ou du New York Times. Si l'attaquant est un État, il peut forcer les employés d'un opérateur national à collaborer mais c'est plus difficile avec les étrangers.

C'est encore pire (du point de vue de l'attaquant) avec les méthodes actives. Elles laissent forcément davantage de traces. Par exemple, un vrai/faux certificat X.509 peut être détecté par des mesures comme les « certificats au grand jour » du RFC 9162.

Les attaques actives représentent aussi souvent un défi technique plus important. Là où les attaques passives nécessitent surtout des gros disques durs, les attaques actives peuvent demander, par exemple, qu'un injecteur de paquets frauduleux gagne la course contre la source légitime afin que ses paquets arrivent avant. À un térabit/s, ce n'est pas évident et cela ne se fait pas avec un PC ordinaire !

Voilà, on a fait un tour partiel des attaquants et de leurs capacités. Les solutions à ces attaques seront développées plus tard (mais cela ne sera pas facile).


Téléchargez le RFC 7624


L'article seul

RFC 7622: Extensible Messaging and Presence Protocol (XMPP): Address Format

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : P. Saint-Andre (&yet)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF xmpp
Première rédaction de cet article le 10 septembre 2015


Ce RFC normalise le format des adresses du protocole de messagerie instantanée XMPP, protocole également connu sous son ancien nom de Jabber. Il remplace l'ancien RFC 6122 avec notamment un changement important sur l'internationalisation de ces adresses, le passage au nouveau système PRECIS (décrit dans le RFC 7564), qui remplace stringprep. Les adresses XMPP peuvent en effet être entièrement en Unicode.

Le protocole XMPP est le standard actuel de messagerie instantanée de l'IETF (il est normalisé dans le RFC 6120). Les utilisateurs sont identifiés par une adresse également connue, pour des raisons historiques, sous le nom de JID (Jabber IDentifier). Ces adresses ont une forme qui ressemble aux adresses de courrier électronique mais elles sont en fait complètement différentes. Ainsi, j'ai personnellement deux adresses XMPP, bortzmeyer@gmail.com (le service de messagerie Google Talk utilise en effet la norme XMPP), qui me sert surtout pour la distraction, et bortzmeyer@dns-oarc.net qui me sert pour le travail (j'utilise aussi le service XMPP de la Quadrature du Net mais plus rarement). Mais rien ne dit qu'un courrier envoyé à ces adresses fonctionnera : adresses XMPP et de courrier vivent dans des mondes différents.

Le format des adresses XMPP était spécifié à l'origine dans le document XEP-0029. Puis il a été normalisé dans la section 3 du RFC 3920. La norme XMPP ayant subi une refonte complète, qui a mené entre autres à un nouveau RFC, le RFC 6120, se posait la question du format d'adresses, dont l'internationalisation, compte tenu de la nouvelle norme IDN, suscitait des débats. Ces débats n'étant pas terminés, la décision a été prise de sortir le format d'adresses du RFC principal, et d'en faire le RFC 6122, jusqu'à ce qu'un consensus apparaisse sur le format « définitif ». Ce format final est celui de notre RFC 7622, qui utilise pour Unicode le cadre PRECIS, normalisé dans le RFC 8264.

Donc, quels sont les points essentiels des adresses XMPP (section 3) ? Une adresse (ou JID) identifie une entité (un humain mais peut-être aussi un programme automatique). Elle comprend trois parties (dont une seule, le domaine, est obligatoire), la partie locale, le domaine et une ressource. Ainsi, dans bortzmeyer@gmail.com/Home, bortzmeyer est la partie locale, gmail.com le domaine et Home la ressource. Le @ et le / servent de séparateurs. Chacune des trois parties peut être composée de caractères Unicode, qui doivent être encodés en UTF-8. La partie locale doit être canonicalisée avec PRECIS et son profil UsernameCaseMapped (voir RFC 8265), le domaine avec les méthodes IDN des RFC 5890 et RFC 5892. Seul le domaine est obligatoire et bot.example.org est donc un JID valide.

Les adresses XMPP (ou JID) sont souvent représentées sous forme d'un IRI, selon le RFC 5122. En gros, un IRI XMPP est un JID préfixé par xmpp:. Mais ces IRI ne sont pas utilisés par le protocole XMPP. Dans les champs to et from des strophes (stanzas) XMPP, on ne trouve que des JID (sans le xmpp: devant). Les IRI ne servent que dans les liens dans les pages Web, comme xmpp:bortzmeyer@gmail.com (attention, ce lien ne marchera pas avec tous les navigateurs).

Le RFC détaille ensuite chaque partie. Le domaine, seule partie obligatoire, est dans la section 3.2. On peut le voir comme une identification du service auquel on se connecte (gmail.com = Google Talk), et la création de comptes et l'authentification se font typiquement en fonction de ce service. En théorie, une adresse IP est acceptable pour cette partie mais, en pratique, c'est toujours un FQDN. Ce nom de domaine peut être un IDN donc instantanée.nœud.example est un nom acceptable pour former un JID. Auquel cas, ce doit être un IDN légal (ce qui veut dire que toute chaîne de caractères Unicode n'est pas forcément un nom légal pour la partie domaine d'un JID). À noter que XMPP n'utilise pas l'encodage en ASCII des IDN (le Punycode).

Et la partie locale, celle avant le @ ? La section 3.3 la couvre. Elle est optionnelle et identifie en général une personne (mais peut aussi indiquer un programme ou bien un salon de conversation à plusieurs). Si elle est en Unicode, elle doit être canonicalisée avec le profil UsernameCaseMapped de PRECIS, profil décrit dans le RFC 8265. Cette partie locale est donc insensible à la casse. Certains caractères normalement autorisés par ce profil sont explicitement interdits en XMPP comme les séparateurs / ou @ mais aussi comme " ou <. (Voir XEP-0106 pour un mécanisme d'échappement permettant de mettre quand même ces caractères.)

Quant à la ressource, troisième partie du JID (après le /), également optionnelle, elle sert à distinguer plusieurs sessions par le même utilisateur (par exemple /Home et /Office). La section 3.4 la décrit en détail. Également en Unicode, elle est canonicalisée par le profil OpaqueString de la classe FreeformClass de PRECIS (RFC 8264, section 4.3). Elle n'a pas de structure officielle. Un / dans une ressource (par exemple example.com/foo/bar) n'implique donc pas une hiérarchie. De même, si on y trouve quelque chose ressemblant à une adresse (par exemple joe@example.net/nic@host), cette ressource nic@host doit être traitée comme un identificateur opaque (et pas être analysée en « nom (at) machine »).

La section 3.5 contient quelques exemples de JID. Si certains sont « ordinaires » (le classique juliet@example.com/foobar, reprenant la tradition XMPP des noms tirés de Roméo et Juliette), d'autres sont plus déroutants à première vue comme juliet@example.com/foo@bar (le domaine est example.com, la ressource foo@bar), foo\20bar@example.com (avec un échappement pour l'espace), π@example.com (partie locale en Unicode), king@example.com/♚ (ressource en Unicode), example.com (juste le nom de domaine)...

Il y a aussi des exemples de JID illégaux, qu'il ne faut pas utiliser, comme "juliet"@example.com (les guillemets), foo bar@example.com (l'espace), henriⅣ@example.com (le caractère Unicode à la fin de la partie locale a un équivalent canonique et n'est donc pas autorisé), ♚@example.com (la partie locale doit obéir aux règles restrictives du RFC 8265, qui n'autorise pas les symboles dans les identificateurs, seulement les lettres et chiffres), juliet@ (domaine absent)...

En parlant d'adresses illégales, qui doit vérifier qu'elles sont légales ? Évidemment, l'émetteur devrait le faire. Mais notre RFC va plus loin en recommandant (section 4) que le récepteur jette les messages XMPP (les strophes, stanzas en anglais) contenant de telles adresses. C'est donc plus strict que le traditionnel principe de robustesse.

Quelles sont les conséquences de sécurité de ces adresses ? Il n'y en a guère mais, bon, il y a toujours des inquiets donc la section 7 examine en détail tous les risques, même très théoriques. Bien sûr, les adresses XMPP héritent des questions de sécurité de PRECIS mais le RFC mentionne surtout les risques de triche sur les adresses. Il y en a de deux sortes, les usurpations et les imitations. Les usurpations (section 7.3.1) sont les cas où un méchant arrive à envoyer un message XMPP en trichant sur l'origine, par exemple si jean@example.net, une fois authentifié auprès de son propre serveur, arrive à transmettre un message prétendant venir de jeanne@jabber.example. Normalement, le protocole XMPP empêche cela, par l'authentification mutuelle des serveurs (sauf attaques un peu sophistiquées, par exemple sur le DNS). Cela dit, cette authentification n'empêche pas un serveur d'annoncer une autre partie locale (jeanne@example.net au lieu jean@example.net).

L'autre risque est celui d'imitation (section 7.3.2). Cette fois, il s'agit d'utiliser des JID légitimes et authentiques mais qui ressemblent à celui de la victime, par exemple fric@paypa1.com au lieu de fric@paypal.com (si vous ne voyez pas la différence, regardez mieux). Cette technique est souvent connue sous le nom de typejacking. Comme le montre l'exemple du RFC ou bien celui cité plus haut, le problème arrive même en se limitant à ASCII. Si vous voulez un joli exemple avec Unicode (mais le résultat dépend de l'environnement avec lequel vous lisez cet article), regardez ᏚᎢᎵᎬᎢᎬᏒ qui ressemble à STPETER mais est écrit en Cherokee. Comme un JID peut contenir à peu près n'importe quel caractère Unicode, il n'y a pas vraiment de prévention technique possible contre ce problème. Il est peu probable que cela ait des conséquences en pratique.

La liste complète des changements par rapport au RFC 6122 figure en annexe A. Rappelons que le RFC 6122 s'appuyait, pour les parties en Unicode, sur des profils Stringprep (RFC 3454) comme Nameprep. Ce Nameprep, décrit dans le RFC 3491, ayant été supprimé à l'occasion de la réforme IDNA bis, le grand changement dans ce nouveau RFC est l'abandon complet de stringprep et l'utilisation de PRECIS pour les identificateurs (comme la partie locale d'un JID) et d'IDN pour le nom de domaine.

Vu les changements entre stringprep et PRECIS, on ne peut pas garantir à 100 % que les JID autrefois valides le seront toujours. Mais, dans la plupart des cas, les anciens JID Unicode resteront légaux et utilisables.


Téléchargez le RFC 7622


L'article seul

RFC 7620: Scenarios with Host Identification Complications

Date de publication du RFC : Août 2015
Auteur(s) du RFC : M. Boucadair, D. Binet, S. Durel, B. Chatras (France Telecom), T. Reddy (Cisco), B. Williams (Akamai), B. Sarikaya, L. Xue (Huawei), R. Wheeldon
Pour information
Première rédaction de cet article le 4 septembre 2015


Un problème intéressant de l'Internet d'aujourd'hui est l'identification d'une machine (Host Identification, ou Host-ID, en anglais). Il s'agit de détecter si une machine A avec qui on communique est la même que la machine B avec qui on échange également. (Rappel : identification n'est pas authentification.) Évidemment, l'adresse IP ne convient plus depuis longtemps : les techniques de partage d'adresses IP, comme le CGN, sont trop répandues. Comment faire, alors ? Ce nouveau RFC ne propose pas de solutions mais il fait le tour d'horizon de ce problème complexe, plus complexe qu'on pouvait croire en lisant les solutions qui avaient été proposées par le RFC 6967.

En effet, TCP/IP n'a pas de notion d'identité d'une machine. Au début, les adresses IP, stables et uniques, pouvaient remplir tant bien que mal ce rôle. Mais c'est fini depuis longtemps, surtout en IPv4. (IPv6 n'est pas forcément la solution : je connais des sites qui font du NAT IPv6 en sortie. Voir la section 3 de notre RFC.) Le RFC 6269 décrit en détail ce partage d'adresses IP et ses conséquences (en général néfastes pour l'identification). Notez que NAT et CGN ne sont pas les seules techniques qui amènent à un tel partage (par exemple, un relais applicatif a les mêmes conséquences : plusieurs machines derrière une seule adresse IP, cf. section 5 du RFC.). Et, en plus du partage d'adresses, les tunnels compliquent également les choses, puisqu'une machine aura une adresse très éloignée de son point d'attachement physique.

Outre les points mentionnés dans le RFC 6269, l'absence d'identification facile rend difficile :

  • D'appliquer une politique spécifique à chaque machine (comme une limitation de trafic),
  • De retrouver une machine interne quand on ne connait que l'adresse vue à l'extérieur,
  • D'appeler un serveur de localisation, qui donne la position physique d'une machine, ce qui serait bien utile pour les appels d'urgence en VoIP (section 9 de notre RFC, et RFC 6443).

Évidemment, le partage d'adresses a aussi des avantages, comme une certaine dissimulation, utile pour la protection de la vie privée (cf. section 12 du RFC). Les solutions d'identification d'une machine peuvent potentiellement annuler certains efforts de protection de la vie privée. Le RFC qui proposait des solutions, le RFC 6967 avait un principe: ne pas transmettre davantage d'informations que celles qui étaient dans le paquet IP original émis par la machine. Notre nouveau RFC se demande (section 2) si ce principe n'est pas trop strict.

La suite du RFC est constituée d'études de cas pour différents environnements. Par exemple, la section 3 étudie le classique CGN (RFC 6888). Certains cas seront résolus par IPv6 (par exemple le NAT IPv4 courant aujourd'hui) mais d'autres vont rester comme la traduction d'adresses IPv6 mentionnée plus haut (RFC 6296). La section 5 regarde les relais applicatifs : comme le CGN, ils « cachent » plusieurs machines derrière une même adresse IP. Comme pour le CGN, cela empêche certains usages comme une identification de l'abonné individuel, ou comme l'attribution d'une attaque, par exemple un commentaire menaçant sur un forum. On peut noter que des solutions spécifiques à tel ou tel protocole applicatif ont été développées et que, si le relais les utilise, le problème disparait. C'est le cas de l'en-tête Received: de SMTP (RFC 5321, sections 3.7.2 et 4.4), largement déployé. Dans le monde HTTP, il y a l'en-tête Forwarded:, du RFC 7239, moins fréquemment rencontré. Ces solutions sont souvent discutées dans le contexte de la protection de la vie privée car leur caractère indiscret est assez évident.

Autre étude de cas, en section 7, les overlays. Ils ont beaucoup d'usages comme par exemple dans certaines architectures pair à pair (RFC 5694). Les manipulations qu'ils utilisent peuvent également aboutir à masquer les adresses IP d'origine. Le RFC contient également des études de cas sur d'autres architectures, le tout étant synthétisé dans la section 11 sous forme d'un joli tableau qui indique notamment, pour chaque architecture, si les problèmes qu'elle pose à l'identification d'une machine disparaitront ou pas avec IPv6.

Terminons en revenant sur la question de la protection de la vie privée car, évidemment, les mécanismes d'identification de la machine visent à envoyer des informations, là où la vie privée exigerait qu'on en envoie le moins possible. La section 12 du RFC expose le problème et renvoie à la section 3 du RFC 6967. Elle note aussi qu'il existe des « solutions » non-standard à la question de l'identification et que ces solutions sont souvent discutables en termes de vie privée (par exemple les en-têtes HTTP non-standards HTTP_MSISDN, HTTP_X_MSISDN, HTTP_X_UP_CALLING_LINE_ID, HTTP_X_NOKIA_MSISDN..) L'IESG a en outre ajouté une note au RFC, rappelant que, si on considère en effet les « problèmes » cités par ce RFC 7620 comme des problèmes à résoudre, les solutions ont de fortes chances de piétiner d'autres RFC et d'être contradictoires avec les principes de confidentialité des RFC 6280 et RFC 7258. Bref, identifier les machines ou protéger la vie privée des utilisateurs, il faudra sans doute choisir.


Téléchargez le RFC 7620


L'article seul

RFC 7617: The 'Basic' HTTP Authentication Scheme

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : J. Reschke (greenbytes)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpauth
Première rédaction de cet article le 5 octobre 2015


Ce court RFC (re-)définit le mécanisme d'authentification « de base » (basic authentication scheme) de HTTP : un mécanisme trivial, où un nom d'utilisateur et un mot de passe sont transmis en Base64 au serveur HTTP. Ce RFC (et ses copains) annule et remplace l'ancien RFC 2617.

Depuis la réécriture générale des RFC sur HTTP, le cadre de l'authentification est décrit dans le RFC 7235. Chaque mécanisme spécifique fait ensuite l'objet de son propre RFC. L'authentification de base est le plus ancien et ce RFC 7617 n'apporte donc rien de bien nouveau, il se contente de toiletter une norme existante.

Le principe est simple : le serveur HTTP gère un ou plusieurs « royaumes » (realm). Dans chaque royaume, il connait une liste d'utilisateurs, identifiés par leur nom, et authentifiés par un mot de passe. Le client, à qui le serveur indique le royaume dont dépend la page Web convoitée, transmet cet identificateur et ce mot de passe, et, si cela correspond à ce qui est dans la base, le serveur lui donne accès. Et lui renvoie une code 403 (accès interdit) autrement.

Voici un exemple de dialogue. Le client a tenté d'accéder à la ressource /rapport.html qui est protégée. Le serveur répond par le code 401 (authentification nécessaire, cf. RFC 7235, section 3.1) et un défi : « essaie de t'authentifier dans le royaume Corporate », dans l'en-tête WWW-Authenticate: (RFC 7235, section 4.1).

HTTP/1.1 401 Unauthorized
Date: Mon, 04 Feb 2014 16:50:53 GMT
WWW-Authenticate: Basic realm="Corporate"  

Le client doit lui répondre avec un nom et un mot de passe. S'il est un navigateur Web, il demandera probablement interactivement à l'utilisateur http-auth.png

Si le client HTTP est un programme autonome, il cherchera dans sa configuration (par exemple, avec curl, ce sera dans le fichier ~/.netrc ou bien dans l'option --user de la ligne de commande). Une fois que le client HTTP aura nom et mot de passe, il les concatène (avec un deux-points comme séparateur) et les encode en Base64 (RFC 4648). Si le nom d'utilisateur est Aladdin et le mot de passe open sesame, voici un moyen simple, avec le shell Unix, de calculer la chaîne de caractères à envoyer :

% echo -n "Aladdin:open sesame" | base64
QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Le client HTTP enverra donc sa requête avec l'en-tête :

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==  

À noter que l'ancienne norme ne spécifiait pas quel encodage utiliser pour représenter nom et mot de passe avant de les passer à Base64. Certains utilisaient Latin-1, d'autres UTF-8. C'est déplorable mais il est trop tard pour changer cela (l'annexe B.3 explique ce choix), donc notre nouveau RFC ne spécifie pas non plus d'encodage, c'est un arrangement privé avec le serveur HTTP, sauf si un encodage a été spécifié dans le défi, avec le paramètre charset. Au passage, signalons que la syntaxe possible pour les noms d'utilisateur est désormais celle du RFC 8265.

Ce paramètre charset (qui aurait dû se nommer plutôt accept-charset car il indique ce que le serveur attend, pas ce qu'il envoie), n'a qu'une seule valeur autorisée, UTF-8. Cette valeur indique que le serveur s'attend à ce qu'identificateur et mot de passe soient normalisés en NFC (règles du RFC 5198), puis encodés en UTF-8.

Prenons un exemple, le nom est test et le mot de passe 123£ (le dernier caractère est U+00A3, qui devient C2 A3 en UTF-8, le terminal utilisé pour l'exemple ci-dessous est en UTF-8, ce qui tombe bien). On encode la chaîne test:123£ en Base64 :

% echo -n test:123£ | base64
dGVzdDoxMjPCow==

Et on a donc la valeur à utiliser dans le champ Authorization:.

Et le royaume, on peut le mettre en Unicode ? Eh bien, ce point est obscur (section 3 de notre RFC) et il faudra attendre une nouvelle mise à jour pour l'éclaircir.

La section 4 de notre RFC parle de sécurité. Elle rappelle que le mot de passe est transmis en clair (Base64 ne protège évidemment pas du tout) et qu'il est donc impératif de transporter la session HTTP dans du TLS (RFC 2818). La solution du RFC 7616 n'a pas ce défaut.

Ce mécanisme « de base » souffre également des faiblesses habituelles des mots de passe. Par exemple, si les utilisateurs peuvent les choisir, ils risquent de prendre des mots faibles (prénom, date de naissance...) ou bien de réutiliser le même mot de passe pour plusieurs services. S'ils ne peuvent pas les choisir, ils auront du mal à les mémoriser et seront donc tentés de les écrire... pas forcément dans un endroit protégé.

Dans tous les cas, que les mots de passe soient choisis par les utilisateurs ou pas, le serveur qui les stocke doit prendre des précautions. Ils ne doivent jamais être stockés en clair sur le serveur, car, si le serveur est piraté, le pirate aurait alors accès à tous les mots de passe, donc beaucoup pourront être utilisables avec d'autres serveurs. Les mots de passe doivent être stockés condensés et salés.

Le mode Basic a été enregistré à l'IANA (section 5 du RFC) dans le registre des mécanismes d'authentification.

Quels sont les changements concrets depuis RFC 2617, section 2, qui normalisait ce mécanisme avant ? L'annexe A les décrit : il y a la compatibilité avec le nouveau cadre d'authentification du RFC 7235, et une meilleure internationalisation avec le nouveau paramètre charset.


Téléchargez le RFC 7617


L'article seul

RFC 7616: HTTP Digest Access Authentication

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : R. Shekh-Yusef (Avaya), D. Ahrens (Independent), S. Bremer (Netzkonform)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpauth
Première rédaction de cet article le 8 octobre 2015


Dans les techniques d'authentification normalisées pour un client HTTP, la plus connue et la plus simple est le mécanisme Basic du RFC 7617. Mais elle a plusieurs failles de sécurité, comme le transmission explicite du mot de passe (et qui se fait en clair si on n'utilise pas HTTPS). D'où cette technique alternative, que je crois peu répandue, car plus complexe (et pas forcément plus sûre) : le mécanisme Digest. Dans ce cas, le serveur HTTP envoie un défi au client, défi auquel le client répondra sans divulguer au serveur aucun secret.

Avec les RFC 7615 et RFC 7617, ce nouveau RFC remplace le très ancien RFC 2617 (qui normalisait tous les mécanismes d'authentification de HTTP). Désormais, l'authentification HTTP comporte un cadre général (le RFC 7235) et un RFC spécifique par mécanisme d'authentification. Celui de notre nouveau RFC, le Digest, a assez peu changé depuis le RFC 2617.

L'essentiel du RFC actuel est dans la section 3. Le client s'authentifie avec un nom et un mot de passe mais le mot de passe n'est pas envoyé tel quel au serveur (quant au nom, ça dépend). Comme son nom l'indique (digest = condensation), les données sont condensées avant d'être envoyées au serveur, empêchant le serveur (ou un indiscret qui écoute) d'accéder à la valeur initiale.

Lorsque le client HTTP tente d'accéder à une ressource protégée, le serveur lui répond avec un code HTTP 401 et un en-tête WWW-Authenticate:, indiquant le mécanisme Digest. Cet en-tête contient le royaume (realm, un identificateur caractérisant le groupe d'utilisateurs attendus, cf. RFC 7235, section 2.2), le domaine (une liste d'URI pour qui cette protection s'applique), un numnique, une chaîne de caractères opaque, que le client renverra telle quelle, une indication de l'algorithme de condensation utilisé et quelques autres détails. Le numnique doit être différent à chaque réponse du serveur et de son mécanisme de génération dépend largement la sécurité de ce mécanisme d'authentification. Un attaquant ne doit pas pouvoir deviner le numnique qui sera utilisé. À part cela, le mécanisme de génération des numniques n'est pas spécifié, c'est une décision locale. Une méthode suggérée par le RFC est que le numnique soit la concaténation d'une estampille temporelle et de la condensation de la concaténation de l'estampille temporelle, de l'ETag de la ressource et d'un secret connu du seul serveur. L'estampille temporelle sert à éviter les attaques par rejeu. Elle est en clair au début du numnique, pour faciliter les comparaisons floues (estampille « pas trop ancienne »). Notez que le RFC ne conseille pas d'inclure l'adresse IP du client dans son calcul, cela défavoriserait trop les clients qui changent d'adresse IP, par exemple parce qu'ils passent par plusieurs relais de sortie possibles. (Alors que la section 5.5 du même RFC donne le conseil opposé...)

Le client HTTP doit répondre à ce défi en envoyant un en-tête Authorization: qui inclut la réponse condensée, le nom de l'utilisateur (qui peut être condensé ou pas, selon la valeur du paramètre userhash, cf. section 3.4.4 pour les détails), un numnique du client, et un compteur du nombre de tentatives d'authentification, qui permet de repérer les rejeux.

La réponse condensée est calculée (section 3.4.1) en condensant la concaténation de plusieurs valeurs, comprenant notamment une condensation de la concaténation du nom de l'utilisateur, de son mot de passe et du royaume, le numnique du serveur et celui du client. Un attaquant ne peut donc pas savoir à l'avance quelle sera la réponse, puisqu'il ne connait pas le numnique.

En recevant cette réponse à son défi, le serveur doit récupérer le mot de passe de l'utilisateur dans sa base de données, et refaire les mêmes opérations de concaténation et de condensation que le client, puis vérifier qu'il trouve le même résultat. (Notez qu'il n'y a pas besoin de stocker le mot de passe en clair, et que c'est même déconseillé, il suffit d'avoir accès à son condensat.) Par exemple, avec Apache, l'outil htdigest gère tout cela.

Le même mécanisme peut s'utiliser pour s'authentifier auprès d'un relais, mais dans ce cas les en-têtes se nomment Proxy-Authenticate: et Proxy-Authorization:.

Bon, c'est bien compliqué tout cela, place aux exemples. Un client veut accéder à http://www.example.org/dir/index.html (section 3.9.1 du RFC). Le royaume est http-auth@example.org, le nom d'utilisateur Mufasa et le mot de passe Circle of Life (n'oubliez pas les deux espaces entre les mots). Le serveur envoie le défi :

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest
       realm="http-auth@example.org",
       qop="auth, auth-int",
       algorithm=SHA-256,
       nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
       opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"      
    

Le serveur demande qu'on condense avec SHA-256. Le client répond au défi :

Authorization: Digest username="Mufasa",
       realm="http-auth@example.org",
       uri="/dir/index.html",
       algorithm=SHA-256,
       nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
       nc=00000001,
       cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ",
       qop=auth,
       response="753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1",
       opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"

Le nom de l'utilisateur était en clair (non condensé). Le numnique et la chaîne opaque sont renvoyés tels quels. La réponse a été calculée en suivant l'algorithme de la section 3.4.1. Si vous voulez toutes les étapes (condensat calculé avec la commande Unix sha256sum) :

  • A1 = Mufasa:http-auth@example.org:Circle of Life
  • H(A1) = 7987c64c30e25f1b74be53f966b49b90f2808aa92faf9a00262392d7b4794232 (avec le nom de l'utilisateur, qui sert de clé d'accès, c'est la seule information à garder sur le serveur, cela évite des mots de passe stockés en clair)
  • A2 = GET:/dir/index.html (la réponse dépend de la partie locale de l'URI, ce qui limite l'ampleur d'un éventuelle attaque par rejeu)
  • H(A2) = 9a3fdae9a622fe8de177c24fa9c070f2b181ec85e15dcbdc32e10c82ad450b04
  • data = 7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v:00000001:f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ:auth:9a3fdae9a622fe8de177c24fa9c070f2b181ec85e15dcbdc32e10c82ad450b04
  • secret:data = 7987c64c30e25f1b74be53f966b49b90f2808aa92faf9a00262392d7b4794232:7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v:00000001:f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ:auth:9a3fdae9a622fe8de177c24fa9c070f2b181ec85e15dcbdc32e10c82ad450b04
  • KD (réponse) = 753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1

Parmi les points qui peuvent compliquer ce mécanisme (qui est ennuyeux mais simple à mettre en œuvre), l'internationalisation (section 4). Si le nom ou le mot de passe ne se limitent pas à ASCII, le serveur a intérêt à utiliser le paramètre charset pour indiquer le jeu de caractères dont le client devra se servir. La seule valeur légale de ce caractère est UTF-8, et les chaînes de caractères doivent être normalisées en NFC (cf. RFC 5198, notamment la section 3). Un exemple se trouve dans la section 3.9.2.

Maintenant que ce mécanisme est décrit, analysons sa sécurité (section 5 du RFC). D'abord, les mots de passe utilisés peuvent être trop faibles. Ce mécanisme Digest permet les attaques par dictionnaire (on essaie tous les mots d'un dictionnaire comme mots de passe) et, si le mot de passe figure dans les dictionnaires habituels (c'est le cas de azertyuipop et de 123456789), il finira par être trouvé. Cette attaque marche quelles que soient les qualités de l'algorithme de condensation employé. Il faut donc essayer de s'assurer qu'on n'utilise que des mots de passe forts. (Si la communication n'utilise pas HTTPS, et qu'un attaquant écoute passivement les défis et les réponses, il peut également les tester contre un dictionnaire, sans avoir besoin de faire des essais qui peuvent donner l'alarme.)

Ces mots de passe doivent être stockés sur le serveur. Bien sûr, on peut stocker uniquement leur forme condensée mais, comme c'est elle qui sert d'entrée à l'algorithme de calcul de la réponse, un attaquant qui met la main sur cette base a un accès complet aux ressources du serveur, sans étape de décryptage (comme cela serait le cas avec un attaquant mettant la main sur un /etc/passwd ou /etc/shadow Unix). Notez que le mécanisme Digest ne permet pas de saler les mots de passe. (À titre personnel, c'est pour cela que je ne trouve pas forcément ce mécanisme forcément plus sûr que Basic, contrairement à ce que dit le RFC en 5.13. Aujourd'hui, les piratages de bases des serveurs sont fréquents. La documentation d'Apache est sceptique aussi, disant « this [Digest authentication] does not lead to a significant security advantage over basic authentication » et « the password storage on the server is much less secure with digest authentication than with basic authentication »). C'est en raison de cette faiblesse que le royaume est inclus dans la condensation qu'on stocke dans la base : au moins l'attaquant ne pourra pas attaquer les autres sites, même si on a le même nom d'utilisateur et mot de passe.

Notez au passage que, comme le mécanisme Basic du RFC 7617, ce Digest permet au serveur d'authentifier le client, mais pas le contraire. Si on veut plus fort, il va falloir utiliser l'authentification permise par TLS (avec des certificats).

Et les attaques par rejeu ? La principale protection est fournie par le numnique. S'il est stupidement généré (par exemple, un simple compteur incrémental, trivial à deviner), les attaques par rejeu deviennent possibles. Avec l'algorithme conseillé, les attaques par rejeu sont plus difficiles mais pas impossibles : comme on peut réutiliser le numnique pendant un certain temps, un attaquant rapide peut faire plusieurs essais. Si c'est intolérable, la seule solution est d'avoir des numniques qui ne sont absolument pas réutilisables (par exemple, des numniques aléatoires, en prenant les précautions du RFC 4086). L'inconvénient est qu'il faut que le serveur les mémorise, au lieu de simplement les recalculer.

Il y a aussi les attaques classiques de l'Homme du Milieu (par exemple dans un relais Web). Un tel attaquant peut, par exemple, remplacer l'algorithme dans le défi par un algorithme plus faible, voir remplacer le défi de Digest par un appel à utiliser un mécanisme plus faible, tel que Basic. Le client HTTP peut prendre quelques mesures (se souvenir de l'authentification utilisée et avertir l'utilisateur si un site qui utilisait Digest passe à Basic) mais aucune n'est parfaite.

Le RFC recommande aussi de n'utiliser l'authentification qu'au-dessus de TLS. Même si le mot de passe n'est pas transmis, l'observation de l'authentification peut donner des informations (et donner accès au contenu des pages Web alors que, si on authentifie, cela peut être parce qu'il est confidentiel). Et TLS avec authentification du serveur protège contre les attaques de l'Homme du Milieu.

Le mécanisme Digest est dans le registre IANA des mécanismes d'authentification. Un nouveau registre est créé pour stocker les algorithmes de condensation.

Les changements depuis le RFC 2617 sont décrits dans l'annexe A. Les principaux ? SHA-256 et SHA-512 sont ajoutés aux algorithmes de condensation. MD5 est conservé, pour des raisons de compatibilité mais très déconseillé (RFC 6151). La possibilité de condenser le nom de l'utilisateur est ajoutée. L'internationalisation est ajoutée.

Si vous utilisez curl pour vous connecter au serveur HTTP, l'option --digest vous permettra d'utiliser le mécanisme de ce RFC (ou bien vous mettez l'option --anyauth et vous laissez curl se débrouiller pour trouver). Côté serveur, pour Apache, c'est bien documenté. Notez la directive Apache AuthDigestDomain pour spécifier le domaine, c'est-à-dire la liste des URI protégés. Pour Nginx, il n'y a apparement pas de solution standard, il faut utiliser un module supplémentaire (ou utiliser le mécanisme Basic + TLS, ce qui est probablement meilleur).

Deux bons textes à lire si vous voulez creuser la question, avec des exemples, un chez Microsoft, et sur le blog perso de Chua Hock-Chuan.


Téléchargez le RFC 7616


L'article seul

RFC 7615: The Hypertext Transfer Protocol (HTTP) Authentication-Info and Proxy-Authentication-Info Response Header Fields

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : 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 5 octobre 2015


Un très court RFC, probablement un des derniers du groupe de travail IETF qui a fait la réécriture de la norme HTTP 1.1. Il normalise l'en-tête HTTP Authentication-Info:, qui était précédemment dans le RFC 2617, et qui, depuis, est dans le RFC 9110.

Cet en-tête, et son équivalent pour les relais, Proxy-Authentication-Info:, sert au serveur HTTP à communiquer des informations après une authentification réussie.

Dans la nouvelle rédaction de la norme HTTP 1.1, l'authentification est décrite par le RFC 7235. L'ancien RFC sur les méthodes d'authentification, le RFC 2617, est désormais abandonné et plusieurs RFC ont repris ses spécifications, comme notre RFC 7615 pour les deux en-têtes d'information Authentication-Info: et Proxy-Authentication-Info:.

La section 3 de notre RFC décrit en détail le premier en-tête. Envoyé par le serveur après une authentification réussie, il contient une liste de paires {nom, valeur}. Les noms possibles dépendent du mécanisme d'authentification utilisé. Par exemple, le mécanisme Digest du RFC 7617 utilise Authentication-Info: pour des informations techniques nécessaires pour la prochaine authentification. Notre RFC 7615 ne normalise donc que la syntaxe, pas la sémantique. Voici un exemple :

Authentication-Info: rspauth="670ff3158cec20b73d7342932f8c40a1",
  cnonce="1672b410efa182c061c2f0a58acaa17d",  nc=00000001, qop=auth
    

L'en-tête Proxy-Authentication-Info:, décrit en section 4, est exactement le même, sauf qu'il est utilisé lors de l'authentification avec un relais intermédiaire et non pas avec le serveur HTTP final.

Les deux en-têtes peuvent être indiscrets, par les informations qu'ils donnent sur l'authentification (ne serait-ce que le simple fait qu'il y a eu authentification). La section 5 de notre RFC, consacrée à la sécurité, recommande donc l'utilisation de HTTPS.

Ces deux en-têtes HTTP sont enregistrés à l'IANA, dans le registre des en-têtes.

Apparemment aucun changement significatif dans ces en-têtes n'est apparu depuis l'ancienne norme, le RFC 2617.


Téléchargez le RFC 7615


L'article seul

RFC 7613: Preparation, Enforcement, and Comparison of Internationalized Strings Representing Usernames and Passwords

Date de publication du RFC : Août 2015
Auteur(s) du RFC : P. Saint-Andre (&yet), A. Melnikov (Isode)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF precis
Première rédaction de cet article le 29 août 2015


Ah, les plaisirs de l'internationalisation du logiciel... Quand l'informatique ne concernait que les États-Unis, tout était simple. Un utilisateur ne pouvait avoir un nom (un login) que composé des lettres de l'alphabet latin (et même chose pour son mot de passe). Mais de nos jours, il n'est pas acceptable de se limiter au RFC 20. Il faut que Пу́тин ou 艾未未 puissent écrire leur nom dans leur écriture et l'informatique doit suivre. La première tentative de normaliser ces noms d'utilisateur en Unicode, dans le RFC 4013 n'avait pas été un immense succès et elle est désormais remplacée par une approche un peu différente, décrite dans ce nouveau RFC, qui a depuis été remplacé par le RFC 8265.

Mais pourquoi faut-il standardiser quelque chose ? Pourquoi ne pas dire simplement « les noms d'utilisateur sont en Unicode » et basta ? Parce que les logiciels qui gèrent noms d'utilisateurs et mots de passe ont besoin de les manipuler, notamment de les comparer. Si ПУ́ТИН essaie de se loguer, et que la base de données contient un utilisateur пу́тин, il faut bien déterminer si c'est le même utilisateur (ici, oui, à part la casse). C'est en général assez simple dans l'alphabet latin (ou dans le cyrillique utilisé pour les exemples) mais il y a d'autres cas plus vicieux qui nécessitent quelques règles supplémentaires.

Le RFC 4013, qui était fondé sur le cadre du RFC 3454 visait à décrire ces règles. Mais l'approche utilisée n'a pas accroché (en partie parce qu'elle était liée à une version d'Unicode particulière) et le défunt stringprep du RFC 3454 a été remplacé par un nouveau cadre, celui du RFC 7564. Notre nouveau RFC 7613 est l'adaptation de ce RFC 7564 au cas spécifique des noms d'utilisateur et des mots de passe.

Ces noms et ces mots de passe (aujourd'hui, il faudrait plutôt dire phrases de passe) sont largement utilisés pour l'authentification, soit directement (SASL PLAIN du RFC 4616, authentification de base de HTTP du RFC 7617), ou bien comme entrée d'une fonction de condensation cryptographique (SASL SCRAM du RFC 5802 ou bien authentification HTTP digest du RFC 7616). L'idée est que les opérations de base sur ces noms (et sur les mots de passe) ne surprennent pas excessivement l'utilisateur, quel que soit son pays, sa langue, sa culture. Un Français ou un Belge ne sera probablement pas trop étonné que Dupont soit accepté comme synonyme de dupont mais il le serait davantage si dupond l'était. Évidemment, la tâche est impossible (les utilisateurs sont tous différents) mais l'idée est de ne pas faire un système parfait mais un système qui marche la plupart du temps.

C'est là qu'intervient le cadre PRECIS (PReparation, Enforcement, and Comparison of Internationalized Strings) du RFC 7564. Il évite que chaque développeur d'un système d'authentification doive lire et comprendre toutes les conséquences d'Unicode, et lui permet de s'appuyer sur une analyse déjà faite. Un exemple de piège d'Unicode (et qui montre pourquoi « on va juste dire que les noms d'utilisateur peuvent être n'importe quel caractère Unicode » est sans doute une mauvaise politique) est le chiffre 1 en exposant, U+00B9 (comme ça : « ¹ » Si vous ne voyez rien, c'est parce que votre logiciel ne sait pas afficher ce caractère. Vous pouvez toujours regarder le source HTML pour comprendre l'exemple.). Doit-on l'autoriser ? Le mettre en correspondance avec le 1 traditionnel de façon à ce que user¹ et user1 soient le même nom ? Imaginez un client XMPP qui vous dise « user¹@example.com veut être votre copain. Je l'autorise ? » et que vous acceptiez en croyant que c'était user1@example.com. Bien sûr, on ne peut pas réellement parler d'« attaque » dans ce cas, une telle erreur permettrait juste de faire quelques farces mais, pour le logiciel qui vérifie une identité, des confusions seraient plus gênantes. Si les « attaques » exploitant la similitude de caractères Unicode sont surtout un fantasme d'informaticien anglophone n'ayant jamais réellement accepté l'internationalisation (plutôt qu'une réalité du terrain), il est quand même plus prudent de supprimer quelques causes de cafouillage le plus tôt possible.

Je l'ai dit plus haut, ce nouveau RFC met fin au profil SASLprep du RFC 4013 mais les protocoles qui l'utilisaient ne sont pas mis à jour automatiquement, ils devront publier une nouvelle version de leur norme (comme le RFC 7622 pour XMPP).

Notre RFC compte deux sections importantes, décrivant le profil PRECIS pour les noms d'utilisateur (section 3) et les mots de passe (section 4). Commençons par les noms d'utilisateur. Un nom est une chaîne de caractères Unicode composée de parties séparées par des espaces. Chaque partie doit être une instance de IdentifierClass et est normalisée en NFC. L'encodage doit être UTF-8. Pourquoi cette notion de « parties séparées par des espaces » ? Parce que la classe IdentifierClass du RFC 7564 ne permet pas les espaces, ce qui est gênant pour certains identificateurs (« Prénom Nom » par exemple, cf. section 3.5). D'où la grammaire de la section 3.1 :

      username   = userpart *(1*SP userpart)
    

qui dit « un nom d'utilisateur est composé d'au moins une partie, les parties étant séparées par un nombre quelconque d'espaces ». Une des conséquences de cette grammaire étant que le nombre d'espaces n'est pas significatif : Jean Dupont et Jean Dupont sont le même identificateur.

Chaque partie étant une instance de l'IdentifierClass du RFC 7564, les caractères interdits par cette classe sont donc interdits pour les noms d'utilisateurs. Une application donnée peut restreindre (mais pas étendre) ce profil. Ces noms d'utilisateurs sont-ils sensibles à la casse ? Ce fut l'un des deux gros débats dans le groupe de travail PRECIS, puisque certains protocoles ont fait un choix et d'autres le choix opposé (l'autre gros débat concernait - bien à tort - un problème subtil et peu important sur les conséquences des changements dans les nouvelles versions d'Unicode). Eh bien, il y a désormais deux sous-profils, un sensible et un insensible. Les protocoles et applications utilisant ce RFC 7613 devront annoncer clairement lequel ils utilisent. Et les bibliothèques logicielles manipulant ces utilisateurs auront probablement une option pour indiquer le sous-profil à utiliser.

Le sous-profil UsernameCaseMapped rajoute donc une règle de préparation des chaînes de caractères : tout passer en minuscules (avant les comparaisons, les condensations cryptographiques, etc), en utilisant l'algorithme Case Folding d'Unicode (oui, changer la casse est bien plus compliqué en Unicode qu'en ASCII). Une fois la préparation faite, on peut comparer octet par octet (rappelez-vous que la chaîne doit être en UTF-8).

L'autre sous-profil, UsernameCasePreserved ne change pas la casse, comme son nom l'indique. ПУ́ТИН et пу́тин y sont donc deux identificateurs différents. C'est la seule différence entre les deux sous-profils. Notre RFC recommande le profil insensible à la casse, UsernameCaseMapped, pour éviter des surprises comme celles décrites dans le RFC 6943 (cf. section 8.2 de notre RFC).

Bon, tout ça est bien nébuleux et vous préféreriez des exemples ? Le RFC nous en fournit. D'abord, des identificateurs peut-être surprenants mais légaux (légaux par rapport à PRECIS : certains protocoles peuvent mettre des restrictions supplémentaires). Attention, pour bien les voir, il vous faut un navigateur Unicode, avec toutes les polices nécessaires :

  • juliet@example.com : le @ est autorisé donc un JID (identificateur XMPP) est légal.
  • fussball : un nom d'utilisateur traditionnel, purement ASCII, qui passera partout, même sur les systèmes les plus antédiluviens.
  • fußball : presque le même mais avec un peu d'Unicode. Bien qu'en allemand, on traite en général ces deux identificateurs comme identiques, pour PRECIS, ils sont différents. Si on veut éviter de la confusion aux germanophones, on peut interdire la création d'un des deux identificateurs si l'autre existe déjà : PRECIS ne donne que des règles miminales, on a toujours droit à sa propre politique derrière.
  • π : entièrement en Unicode, une lettre.
  • Σ : une lettre majuscule.
  • σ : la même en minuscule. Cet identificateur et le précédent seront identiques si on utilise le profil UsernameCaseMapped et différents si on utilise le profil UsernameCasePreserved.
  • ς : la même, lorsqu'elle est en fin de mot. Le cas de ce sigma final est compliqué, PRECIS ne tente pas de le résoudre. Comme pour le eszett plus haut, vous pouvez toujours ajouter des règles locales.

Par contre, ces noms d'utilisateurs ne sont pas valides :

  • Une chaîne de caractères vide.
  • HenriⅣ : le chiffre romain 4 à la fin est illégal (car il a ce qu'Unicode appelle « un équivalent en compatibilité », la chaîne « IV »).
  •  : seules les lettres sont acceptées, pas les symboles (même règle que pour les noms de domaine).

Continuons avec les mots de passe (section 4). Comme les noms, le mot de passe est une chaîne de caractères Unicode. Il doit être une instance de FreeformClass. Cette classe autorise bien plus de caractères que pour les noms d'utilisateur, ce qui est logique : un mot de passe doit avoir beaucoup d'entropie. Peu de caractères sont donc interdits (parmi eux, les caractères de contrôle, voir l'exemple plus bas). Les mots de passe sont sensibles à la casse. L'encodage doit être UTF-8.

Des exemples ? Légaux, d'abord :

  • correct horse battery staple : vous avez reconnu un fameux dessin de XKCD.
  • Correct Horse Battery Staple : les mots de passe sont sensibles à la casse, donc c'est un mot de passe différent du précédent.
  • πßå : un mot de passe en Unicode ne pose pas de problème.
  • Jack of ♦s : et les symboles sont acceptés, contrairement à ce qui se passe pour les noms d'utilisateur.
  • foo bar : le truc qui ressemble à un trait est l'espace de l'Ogham, qui doit normalement être normalisé en un espace ordinaire, donc ce mot de passe est équivalent à foo bar.

Par contre, ce mot de passe n'est pas valide :

Rappelez-vous que ces profils PRECIS ne spécifient que des règles minimales. Un protocole utilisant ce RFC peut ajouter d'autres restrictions (section 5). Par exemple, il peut imposer une longueur minimale à un mot de passe (la grammaire de la section 4.1 n'autorise pas les mots de passe vides mais elle autorise ceux d'un seul caractère, ce qui serait évidemment insuffisant pour la sécurité), une longueur maximale à un nom d'utilisateur, interdire certains caractères qui sont spéciaux pour ce protocole, etc.

Certains profils de PRECIS suggèrent d'être laxiste en acceptant certains caractères ou certaines variantes dans la façon d'écrire un mot (accepter strasse pour straße ? C'est ce qu'on nomme le principe de robustesse.) Mais notre RFC dit que c'est une mauvaise idée pour des mots utilisés dans la sécurité, comme ici (voir RFC 6943).

Comme toutes les fois qu'on change les règles, il faut se préoccuper de la migration depuis l'ancien système (c'est la section 6 du RFC). Si vous aviez déjà des noms d'utilisateur en Unicode en suivant l'ancien système SASLprep, celui du RFC 4013, il va falloir examiner votre base de données et peut-être faire des conversions. Pour les noms, il y a notamment le fait que SASLprep utilisait la normalisation Unicode NFKC alors que PRECIS se sert de NFC. Ce n'est pas forcément si grave que ça car PRECIS interdit les lettres ayant un équivalent de compatibilité, les seules qui sont traitées différemment par NFKC et NFC. Il est donc recommandé d'examiner la base et de repérer des noms ayant un de ces équivalents.

Pour les mots de passe, c'est plus compliqué puisque, si vous êtes sérieux, vous ne les stockez pas en clair, et vous ne pouvez donc pas les examiner. Disons que si un utilisateur qui a utilisé toutes les possibilités rigolotes d'Unicode n'arrive pas à s'authentifier après la migration, il faudra penser à ce problème.

Les profils PRECIS ont été ajoutés au registre IANA (section 7 de notre RFC).

Un petit mot sur la sécurité et on a fini. La section 8 de notre RFC revient sur quelques points difficiles. Notamment, est-ce une bonne idée d'utiliser Unicode pour les mots de passe ? Ça se discute. D'un côté, cela augmente les possibilités (en simplifiant les hypothèses, avec un mot de passe de 8 caractères, on passe de 10^15 à 10^39 possibilités en permettant Unicode et plus seulement ASCII), donc l'entropie. D'un autre, cela rend plus compliqué la saisie du mot de passe, surtout sur un clavier avec lequel l'utilisateur n'est pas familier. Le monde est imparfait et il faut choisir le moindre mal...

Enfin, un résumé des changements depuis l'ancienne technique, celle du RFC 4013, figure dans l'annexe A. Il rappelle que l'ancien stringprep/SASLprep est remplacé par une approche vraiment différente, même si, dans les cas « normaux », le résultat sera le même. Par exemple, stringprep (RFC 3454) autorisait tous les caractères sauf ceux qui étaient interdits alors que PRECIS, comme le fait IDN depuis la nouvelle norme RFC 5891, fait l'inverse (tout ce qui n'est pas autorisé est interdit). Pour résumer les autres principaux changements :

  • Il n'y avait qu'un seul algorithme de préparation et de comparaison dans SASLprep, il y en a désormais trois (noms sensibles à la casse, noms insensibles à la casse, mots de passe).
  • Indépendance vis-à-vis de la version d'Unicode.
  • Normalisation NFC et plus NFKC.

Téléchargez le RFC 7613


L'article seul

RFC 7610: DHCPv6-Shield: Protecting Against Rogue DHCPv6 Servers

Date de publication du RFC : Août 2015
Auteur(s) du RFC : F. Gont (SI6 Networks / UTN-FRH), W. Liu (Huawei Technologies), G. Van de Velde (Alcatel-Lucent)
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 7 septembre 2015


Un peu de sécurité IPv6 sur le réseau local : comment protéger les pauvres machines IPv6 contre un méchant serveur DHCP, qui répond à la place du serveur légitime, et plus rapidement que lui ? Pas de surprise, la solution est la même qu'en IPv4 (DHCP snooping) et est détaillée dans ce RFC : le commutateur bloque les réponses DHCP qui viennent d'un port où aucun serveur DHCP n'est censé être présent.

Le mécanisme porte le doux nom de DHCP Shield. DHCP, normalisé dans le RFC 8415, est très proche en IPv6 et en IPv4 et, dans les deux cas, n'offre quasiment aucune sécurité. Sur un réseau sans serveur DHCP officiel, une machine peut prétendre être serveur DHCP et tout le monde va la croire et accepter ses annonces. C'est une des plaies des réseaux locaux, d'autant plus qu'authentifier le serveur DHCP est très difficile puisqu'on utilise justement DHCP pour ne rien avoir à configurer sur les machines clientes. Sur un réseau avec serveur DHCP légitime, un faux serveur peut parfois se faire écouter, par exemple s'il répond plus vite. Et, même quand il n'y a qu'un seul serveur DHCP, rien ne garantit que les machines utiliseront uniquement les adresses IP qui leur ont été allouées officiellement.

Pour DHCP Shield, le mode de fonctionnement normal est que l'administrateur réseaux configure le commutateur en lui disant sur quels ports du commutateur se trouve le serveur DHCP légitime. Le commutateur examine alors tous les messages et rejette les réponses DHCP qui viendraient d'un autre port. Le problème d'un serveur DHCP pirate est très proche de celui d'un routeur IPv6 pirate qui envoie des Router Advertisement (RFC 4861, section 4.2) trompeurs et la solution est donc très proche (pour les RAcailles, les RA illégitimes, le problème était exposé dans le RFC 6104 et la solution, RA Guard, dans les RFC 6105 et RFC 7113).

Voilà pour le principe, les détails maintenant. Un commutateur ordinaire ne protège pas contre les serveurs DHCP pirates. Il faut un DHCPv6 Shield Device (section 3 du RFC), commutateur « intelligent » capable de mettre en œuvre la technique décrite dans ce RFC. Demandez à votre vendeur avant d'acheter, s'il y a bien les fonctions de DHCP Shield.

Il faut ensuite le configurer explicitement (le commutateur pourrait apprendre seul, en regardant les réponses mais c'est risqué : si le serveur pirate est déjà en service au moment où le commutateur démarre, ce dernier pourrait prendre le pirate pour le serveur légitime). Cette configuration est faite par l'administrateur réseaux, qui désigne le ou les ports du commutateur qui peuvent légitimement voir arriver des réponses DHCPv6, car un serveur légitime se trouve derrière (section 4 du RFC).

Dit comme cela, ça a l'air simple. Mais, dans les réseaux réels, plein de complications peuvent survenir et la section 5 du RFC, sur les problèmes possibles, est beaucoup plus longue que la section 4 qui décrit l'algorithme. Premier gag possible, les en-têtes d'extension IPv6 qui sont très difficiles à analyser. Notre RFC impose donc aux mises en œuvre de DHCP shield d'analyser tout le paquet, de ne pas se limiter arbitrairement aux N premiers octets, car la liste des en-têtes peut être longue. (La section 6 note que cela peut être difficile sur le fast path - mis en oeuvre dans le matériel - des commutateurs et suggère de jeter le paquet si on ne peut pas l'analyser complètement, mais avec une liste de protocoles de transport qui soit configurable, pour éviter de bloquer les nouveaux protocoles apparus après la vente du commutateur.)

Pour aider un peu les pauvres commutateurs, le RFC 7112 impose que, dans un paquet fragmenté, la totalité des en-têtes soit dans le premier fragment (autrement, un serveur DHCPv6 pirate pourrait « tricher » en « cachant » la réponse IPv6 dans le deuxième fragment et en espérant qu'il ne soit pas analysé). Le commutateur doit donc jeter les paquets fragmentés dont le premier fragment ne contient pas toute la chaîne des en-têtes. (Interdire que les réponses DHCP soient fragmentées aurait été encore plus efficace mais pouvait être gênant dans certains cas, où il y a un besoin légitime d'envoyer de grandes réponses.) Cette politique peut sembler violente mais, de toute façon, un paquet fragmenté n'incluant pas la totalité des en-têtes n'a déjà quasiment aucune chance de passer les pare-feux actuels.

Il faut aussi prêter attenion aux fragments qui se recouvrent (RFC 5722). Ils peuvent permettre d'échapper à la détection par le commutateur.

Plus contestable, la décision en cas d'en-têtes dont le champ Next Header est inconnu. Malheureusement, en IPv6, il n'y a pas de moyen garanti de sauter par dessus un tel en-tête (c'est un peu mieux depuis le RFC 6564). Notre RFC 7610 prend donc une décision radicale : par défaut, les paquets IPv6 ayant un tel en-tête doivent être jetés sans merci. Une option du commutateur doit permettre, si l'administrateur le demande, de les accepter (cf. RFC 7045 pour un point de vue plus général sur la question).

Si le paquet est protégé par IPsec/ESP, le commutateur ne peut évidemment pas savoir si c'est du DHCP ou pas, le but d'ESP (RFC 4303) étant bien d'empêcher les intermédiaires d'être indiscrets. Dans ces conditions, le commutateur doit transmettre le paquet. Les machines clientes qui acceptent des réponses DHCP sur IPsec (ça doit être très rare !) doivent donc les authentifier elles-mêmes, ce qui est dans la logique d'IPsec.

Une fois ces précautions prises, le DHCPv6 Shield Device peut déterminer si le paquet est une réponses DHCPv6 et, si oui, et si elle ne vient pas par le bon port, la jeter, protégeant ainsi les clients DHCP innocents.

La section 6 résume certains problèmes de sécurité du DHCP Shield. Elle rappelle que celui-ci ne protège pas contre les attaques non-DHCP (évidemment) ni même contre certaines attaques DHCP (comme les dénis de service).

Elle rappelle également que DHCP Shield devrait être présent sur tous les commutateurs du réseau : autrement, un attaquant relié à un commutateur bête, qui ne filtre pas, verra ses paquets acceptés s'il y a au moins un serveur légitime sur ce commutateur (puisqu'il aura fallu, en aval, autoriser le port où est relié ce commutateur.)

Notez que notre RFC ne propose pas de solution à l'usurpation d'adresses IP (une machine utilisant une adresse qui ne lui a pas été allouée en DHCP, cas mentionné au début de mon article) mais que ces solutions sont dans le RFC 7513.

À l'heure actuelle, au moins certains commutateurs Cisco ont cette fonction de DHCP Shield.


Téléchargez le RFC 7610


L'article seul

RFC 7608: IPv6 Prefix Length Recommendation for Forwarding

Date de publication du RFC : Juillet 2015
Auteur(s) du RFC : M. Boucadair (France Telecom), A. Petrescu (CEA, LIST), F. Baker (Cisco Systems)
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 23 juillet 2015


Comme IPv4, IPv6 route les paquets en fonction d'un préfixe d'adresses, préfixe qui a une longueur comprise entre 0 (tout l'Internet) et 128 bits (une seule machine). Ce très court RFC a juste pour but de rappeler cette règle : la longueur d'un préfixe est quelconque, les mises en œuvres de IPv6, logicielles ou matérielles, ne doivent pas imposer ou favoriser une longueur de préfixe particulière (même pas 64, souvent considéré, à tort, comme spécial). Le routage se fait exclusivement sur le plus long préfixe, quelle que soit sa longueur.

Il est normal qu'IPv6 et IPv4 fassent pareil, ce sont après tout deux versions du même protocole. IPv4 utilisait autrefois un système différent mais, depuis CIDR, il suit les mêmes règles qu'IPv6 : le routage se fait sur la base d'un préfixe d'adresses de longueur quelconque. C'est le préfixe le plus long qui est choisi. Ainsi, pour prendre un exemple IPv4, si la destination est 203.0.113.51 et qu'il existe deux routes possibles, une vers le préfixe 203.0.113.0/26 (longueur 26 bits) et l'autre vers le préfixe 203.0.0.0/18, c'est la première, la plus spécifique (le préfixe le plus long) qui gagne. En IPv6, si on veut envoyer un paquet à 2001:db8:440:fe::25a:9ff et qu'il existe deux routes possibles, 2001:db8:440:fe::/80 (longueur 80 bits) et 2001:db8:440::/48, c'est la première qui est choisie. Le routage sur la base du préfixe le plus long, un concept fondamental d'IP, c'est juste ça. (Le terme de CIDR, introduit par le RFC 1380 et décrit dans le RFC 4632, terme très spécifique à IPv4 et aujourd'hui dépassé techniquement depuis l'abandon de l'ancien système des classes, n'est pas utilisé pour IPv6.)

Mais pas mal de gens qui ne connaissent pas bien IPv6 ont des idées fausses à ce sujet et croient, par exemple, que les préfixes de longueur 64 bits ont un rôle particulier pour le routage, voire que les préfixes comme le /80 donné en exemple plus haut sont illégaux. Le RFC 4291, qui normalise l'adressage IPv6, dit bien (dans sa section 2.5) que n'importe quelle longueur de préfixe (« arbitrary bit-length ») est possible. Mais c'est vrai que la confusion peut venir du rôle particulier de certaines longueurs, notamment 64, dans d'autres utilisations que le routage. Ainsi, le RFC 7421 note que les préfixes plus longs que 64 bits ont des problèmes pour certaines utilisations, comme le SLAAC. Mais il s'agit là de questions liées à l'adressage : cela ne devrait pas affecter le routage, si on veut que les changements futurs de l'adressage n'empêchent pas les routeurs de fonctionner (deux exemples de changement d'adressage : au début d'IPv6, il était envisagé que ce soit /80 plutôt que /64 qui soit la longueur de préfixe « de référence » et, autre exemple, la recommandation pour les liens point à point a varié de /64 à /127, cf. RFC 6164).

Donc, pour résumer, l'adressage est une chose (et les recommandations du RFC 7421, indiquant les avantages à utiliser du /64 pour un lien local, continuent à s'appliquer), le routage en est une autre : le routage IPv6 doit suivre l'algorithme du préfixe le plus long, et ne doit pas avoir de longueurs de préfixes privilégiées ou spéciales.

Cette exigence est formalisée dans la section 2 de notre RFC :

  • Les routeurs IPv6 doivent suivre les règles de la section 5.1 du RFC 4632.
  • La transmission d'un paquet doit se faire sur la base du préfixe le plus long et toutes les longueurs sont également acceptables, même 128, même des valeurs qui ne sont pas un multiple de 8.

Ces règles s'appliquent au code des routeurs : l'administrateur d'un routeur donné peut toujours avoir sa propre politique (par exemple, en BGP, ne pas accepter de préfixes plus longs que 48 bits) mais cela ne doit pas se retrouver dans le logiciel, autrement, les futures évolutions seraient sérieusement compliquées.


Téléchargez le RFC 7608


L'article seul

RFC 7607: Codification of AS 0 processing

Date de publication du RFC : Août 2015
Auteur(s) du RFC : W. Kumari (Google), R. Bush (Internet Initiative Japan), H. Schiller (Verizon), K. Patel (Cisco)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 28 août 2015


Petit quizz BGP : sans relire le RFC 4271, pouvez-vous dire si 0 est acceptable comme numéro de système autonome dans un message BGP ? Si vous ne pouvez pas, ce n'est pas grave, vous n'êtes pas le seul, ce point n'avait jamais été clairement précisé. Ce très court RFC règle le problème : 0 est désormais officiellement interdit.

Pourtant, cela fait longtemps que l'AS 0 (zéro, pas O) est spécial : il est indiqué dans le registre IANA comme non routable. En outre, les ROA (Route Origin Authorizations) IANA du RFC 6491 utilisent l'AS 0 pour indiquer qu'un préfixe IP ne peut pas être annoncé sur l'Internet. Mais cela veut-il dire qu'un message BGP, par exemple une annonce de route, n'a pas le droit de contenir l'AS 0 dans son chemin d'AS (AS_PATH) ? La plupart des mises en œuvre de BGP avaient choisi cette voie et rejetaient ces annonces. Ce comportement est désormais officiel.

Donc, en deux mots, la nouvelle règle : il est défendu d'utiliser l'AS 0 dans les attributs BGP AS_PATH, AS4_PATH, AGGREGATOR et AS4_AGGREGATOR qu'on émet. Si un pair BGP le fait, et vous envoie de tels attributs, ses messages doivent être considérés comme malformés et rejetés selon les procédures du RFC 7606.

Si jamais un pair ouvre une session en indiquant que son AS est zéro, on doit avorter ladite session avec le message d'erreur n° 2, Bad peer AS (RFC 4271, section 6.2).


Téléchargez le RFC 7607


L'article seul

RFC 7606: Revised Error Handling for BGP UPDATE Messages

Date de publication du RFC : Août 2015
Auteur(s) du RFC : E. Chen (Cisco Systems), J. Scudder (Juniper Networks), P. Mohapatra (Sproute Networks), K. Patel (Cisco Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 28 août 2015


Que doit faire un routeur BGP lorsqu'il reçoit un message de type UPDATE avec un attribut incorrect ? La norme était claire : le routeur doit fermer la session BGP en cours (et donc perdre toutes les routes associées). Cela partait du bon sens (si l'attribut est corrompu, on ne peut pas se fier au routeur qui l'a envoyé) mais cela avait des conséquences sérieuses : on supprimait toutes les routes, pas seulement celle dans l'annonce UPDATE. Ce court RFC modifie donc BGP sur un point : on ne coupe plus forcément toute la session, on retire uniquement la route qui figurait dans l'annonce incorrecte.

L'ancienne norme figurait dans le RFC 4271, section 6 : « When any of the conditions described here are detected, a NOTIFICATION message, with the indicated Error Code, Error Subcode, and Data fields, is sent, and the BGP connection is closed ». En pratique, cela voulait dire que les routeurs coupaient des sessions simplement à cause d'un attribut mal formé. Cela pose un problème de sécurité : comme certains routeurs ne vérifient pas les attributs des annonces, l'annonce avec l'attribut invalide peut être propagée et planter des sessions situées bien après l'origine de l'annonce, rendant le débogage et l'attribution des responsabilités très difficiles. En outre, l'annonce a pu être dupliquée par ces routeurs qui ne vérifient pas, et une seule annonce peut donc planter plusieurs sessions. Cela s'était produit, par exemple, dans le cas du fameux attribut 99.

Que peut faire un routeur BGP lorsque il reçoit une annonce invalide ? La section 2 du RFC liste les possibilités, de la plus violente à la plus modérée :

  • Réinitialiser la session (« dans le doute, reboote »). C'était l'approche officielle avant ce RFC.
  • Ne réinitialiser qu'une seule famille d'adresses (AFI, Address Family Identifier, comme seulement IPv4 ou seulement IPv6), comme documenté dans le RFC 4760.
  • Considérer que l'annonce invalide est équivalente à un retrait des routes qu'elle contient (treat-as-withdraw). C'est une nouveauté de ce RFC, qui n'existait pas dans BGP avant. Cela évite de perdre toutes les routes de la session, comme c'était le cas avec la première approche.
  • Ignorer l'attribut invalide mais garder l'annonce, ce que notre RFC déconseille formellement (sauf si l'attribut n'avait aucune conséquence sur la sélection et l'installation des routes).

L'approche « ignorer l'annonce invalide » n'est pas citée : dans un protocole où les mises à jour sont incrémentales, comme BGP (qui n'envoie pas la table de routage complète, seulement les changements), elle pourrait mener à des routes impossibles à détruire (cf. section 6).

C'est la section 3 qui contient les nouvelles règles exactes, après moultes discussions à l'IETF. Pour résumer : c'est la troisième option (treat-as-withdraw) qui est désormais recommandée dans la plupart des cas.

Le reste du RFC est consacré à des détails pratiques. Par exemple, en section 5, on trouve des règles d'encodage qui permettront d'accéder aux routes annoncées (NLRI, Network Layer Reachability Information) malgré la présence d'attributs mal formés. En effet, c'est très joli de dire qu'on doit traiter une annonce invalide comme un retrait mais il faut pour cela savoir quelles routes retirer (réinitialiser toute la session est bien plus simple à mettre en œuvre). Quand l'annonce est invalide, l'analyser n'est pas trivial. Notre RFC demande donc de faciliter la tâche du routeur de réception de l'annonce, par exemple en encodant les attributs MP_REACH_NLRI et MP_UNREACH_NLRI au tout début de la liste des attributs (pour pouvoir les comprendre même si l'annonce est invalide). Évidemment, les routeurs anciens ne suivent pas forcément ces règles et les récepteurs doivent donc rester prêts à tout.

Bien sûr, rien n'est parfait. L'ancienne règle de couper toute la session n'était pas due au désir des auteurs de BGP de perturber le plus possible l'Internet. Il y avait de bonnes raisons à cette décision, notamment de garantir la cohérence du routage. Avec la nouvelle règle, ce n'est plus aussi simple et on risque donc des tables de routage incohérentes (un routeur ayant accepté l'annonce et un autre l'ayant traité comme un retrait...), avec leurs conséquences, comme des boucles de routage. Cela explique la très longue gestation de ce RFC, due à de nombreuses discussions à l'IETF. Il faut dire que toucher à BGP est toujours délicat : une erreur peut potentiellement planter tout l'Internet.

La section 7 du RFC décrit en détail ce que veut dire « malformé » pour un attribut BGP. Par exemple, l'attribut ORIGIN (RFC 4271, section 4.3, et qui indique la source de l'information contenue dans l'annonce) a normalement une longueur de 1 (les attributs BGP sont encodés en TLV) et toute autre longueur indique un attribut ORIGIN mal formé : autrefois, cela aurait coupé la session, depuis notre RFC, cela doit entrainer un retrait de la route contenue dans l'annonce. Pour l'attribut ORIGIN, même chose si la valeur de l'attribut n'est pas une des valeurs spécifiées (IGP, EGP ou INCOMPLETE).

Autre exemple, l'attribut COMMUNITIES (RFC 1997) doit avoir une longueur qui est un multiple de 4. Si ce n'est pas le cas => attribut mal formé => annonce traitée comme étant un retrait de routes.

Conséquence de ce nouveau RFC : tout nouvel attribut spécifié doit indiquer le traitement à appliquer en cas de malformation (section 8). Ce sera en général treat-as-withdraw mais cela doit être marqué explicitement dans la norme décrivant le nouvel attribut.

Un avantage du long délai avant la sortie de ce RFC, est que ce nouveau comportement a déjà été mis en œuvre dans la plupart des routeurs (Alcatel-Lucent SR OS, Cisco IOS, Cisco IOS XR, Juniper JUNOS, Quagga).


Téléchargez le RFC 7606


L'article seul

RFC 7605: Recommendations on Using Assigned Transport Port Numbers

Date de publication du RFC : Août 2015
Auteur(s) du RFC : J. Touch (USC/ISI)
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 8 août 2015


Vous développez une application Internet et vous utilisez des ports enregistrés à l'IANA ? Ou bien aucun port ne convient et vous voulez en enregistrer un nouveau ? Ce RFC est fait pour vous en expliquant, du point de vue du créateur de nouveaux services Internet, comment utiliser les ports ou bien en demander un nouveau.

La procédure complète figure dans le RFC 6335. Ce nouveau RFC 7605 ne le remplace pas mais fournit une vision moins bureaucratique du processus, plus orientée vers le développeur, avec des recommandations concrètes.

Donc, c'est quoi, un port ? C'est un entier de 16 bits qui :

  • Sert à démultiplexer les paquets entrants dans une machine (à les délivrer au bon processus),
  • Sert à identifier un service (25 = SMTP).

Seule la deuxième utilisation nécessite un registre central.

Pour se connecter à une autre machine, il faut connaître le port de destination. Le cas le plus connu est celui des URL. Si l'URL n'indique pas de numéro de port, le port par défaut est 80 (RFC 7230, section 2.7.1). Donc, avec http://www.example.com/, le client HTTP se connectera au port 80 de la machine www.example.com. Mais on peut indiquer un port dans un URL (RFC 3986, section 3.2.3). Si l'URL est http://www.example.com:9081/, le client HTTP se connectera au port 9 081 de la machine www.example.com.

Bien sûr, rien n'oblige à faire tourner un service sur le port officiellement affecté. On peut mettre un serveur DNS sur le port 80 ou au contraire un serveur HTTP sur le port 53, normalement prévu pour le DNS. C'est ainsi que bien des serveurs SSH écoutent sur le port 443, de manière à ce qu'on puisse se connecter même depuis les points d'accès WiFi les plus pourris qui filtrent tous les ports que leur concepteur ne connait pas. Attention toutefois, si des équipements situés sur le trajet font du DPI, cela peut ne pas leur plaire de voir du trafic non-DNS sur le port 53 et cela peut les amener à couper la communication. Comme le note notre section 5, supposer que le trafic sur le port 53 est forcément du DNS est une erreur : l'interprétation des numéros de ports doit être laissé aux deux machines qui communiquent. Le registre des ports est juste là pour leur faciliter la tâche, pas pour ajouter des contraintes inutiles.

Bien sûr, ce principe n'est pas forcément suivi et des tas de logiciels utilisent le registre des ports en supposant que les services correspondent aux numéros de ports (cf. aussi la section 6.2). C'est fréquent sur les pare-feux, par exemple. On veut couper le DNS, pour forcer l'usage des DNS menteurs, on bloque le port 53, ce qui sera contourné en envoyant le trafic DNS sur un autre port et ainsi de suite. Autre cas où un logiciel utilise le registre des ports pour se faciliter la vie, mais parfois à tort, celui des logiciels d'analyse du trafic réseau, comme tcpdump. Le trafic est avec le port 53, tcpdump l'analyse comme si c'était du DNS. Cela peut mener à des résultats amusants. Ici, tcpdump décode du trafic HTTP en croyant que c'est du DNS :

18:34:03.263985 IP 127.0.0.1.46680 > 127.0.0.1.53: \
        Flags [P.], seq 1:111, ack 1, win 342, \
        options [nop,nop,TS val 240543975 ecr 240543975], \
        length 11021536 update+ [b2&3=0x2f20] \
           [21584a] [18516q] [12081n] [11825au][|domain]

Ce qui le mène à des résultats absurdes comme de croire que la section « Question » du message DNS comprend 18 516 questions... À noter que Wireshark, lui, permet de choisir le décodeur, pour ne pas utiliser celui par défaut d'un port donné (menu Analyze/Analyser, puis Decode as/Decoder[sic]).

Aujourd'hui, au moment de la publication de notre RFC 7605, quelle est l'utilisation de l'espace des ports ? Cet espace est divisé (cf. RFC 6335) en trois catégories, « Système » (sur une machine Unix, il faut être root pour écouter sur ces ports), de 0 à 1 023, « Utilisateur », de 1 024 à 49 151, et « Dynamique » (aussi appelé « Privé », les ports locaux, non enregistrés à l'IANA, contrairement aux deux premières catégories), de 49 152 à 65 535.

Donc, un problème à garder en tête avant de réclamer son port, la nécessite de préserver une ressource finie. L'espace des numéros de ports est partagé par tous les utilisateurs de l'Internet et cet espace est petit, moins de 2^16. Sur les 49 151 numéros ouverts à l'enregistrement (à l'exception, donc, de la catégorie « Dynamique »), 5 850 ont été enregistrés pour TCP. Les enregistrements sont en théorie annulables (RFC 6335, section 8.4) mais permanents en pratique (la procédure du RFC 6335 semble parfaitement irréaliste, cf. aussi la section 7.9 de notre RFC). Il faut donc y aller mollo (cette question du conservatisme dans l'allocation a été une des plus disputées au sein du groupe de travail IETF). Par exemple, chaque service ne devrait avoir qu'un seul numéro de port (outre l'économie des numéros de port, cela évite des problèmes de débogages pénibles au cas où certains ports soient bloqués par un pare-feu et pas d'autres). La section 7.2 détaille cette question des ports multiples.

Donc, plutôt que de demander plusieurs ports pour votre service :

  • Prenez un seul port bien connu et indiquez les éventuels autres ports dynamiquement, comme le passive FTP (RFC 959),
  • Utilisez un service externe pour indiquer un port dynamique, comme le permet le portmapper (RFC 1833),
  • Utilisez une fonction de signalisation du protocole, comme le champ Host: de HTTP, qui évite d'avoir un port (ou une adresse IP) par site Web.

Les ports sont censés permettre de séparer des services différents, pas juste des variations d'un même service.

La section 7 du RFC couvre toutes les questions qu'il faut se poser avant l'enregistrement d'un nouveau port. D'abord, est-il vraiment nécessaire, compte tenu des exigences de conservation indiquées plus haut ?

  • Est-ce vraiment un nouveau service ? Si c'est une variante d'un service existant, il peut réutiliser le port de ce service. Notamment, le port ne devrait pas indiquer la version du service, cette version doit être marquée dans le protocole (notez que POP est une exception à cette règle).
  • Si ce service est expérimental (RFC 3692), pourquoi ne pas utiliser les ports réservés à ces usages expérimentaux (RFC 2780) ?
  • A-t-il vraiment besoin d'un port bien connu, statique ? Ne pourrait-il pas utiliser un port dynamique, indiqué dans la configuration, ou dans le DNS (par exemple avec les SRV) ou dans l'identificateur (comme avec les URL cités plus haut), ou échangé via le protocole (comme fait SIP), ou avec un protocole dédié comme le portmapper cité plus haut ?

OK, on a déterminé qu'on avait vraiment besoin d'un numéro de port, on s'apprête à la demander à l'IANA. Mais quel numéro choisir ? Ce n'est pas une obligation. On peut ne pas indiquer de numéro particulier, et laisser l'IANA en choisir un. En revanche, il faut indiquer si le port doit être dans la plage Système ou dans la plage Utilisateur. La distinction est nettement moins importante aujourd'hui. Autrefois, quand l'Internet ne connectait que des grosses machines gérées professionnellement, la distinction servait à isoler les services critiques des autres. Sur ces grosses machines, l'utilisateur ordinaire ne pouvait pas écouter sur les ports de numéro inférieurs à 1 024 (par exemple, sur Unix, il faut être root pour cela) et cela garantissait que le service sur ces ports était « sérieux ». Aujourd'hui où certains systèmes ne font plus la différence et où, de toute façon, tout le monde est super-utilisateur de son Raspberry Pi, la différence a beaucoup moins de sens. Et cette distinction ne doit pas être utilisé pour la sécurité (cf. section 7.4) comme le faisait malheureusement rlogin. Néanmoins, la différence demeure, au moins comme un marqueur de la criticité du service. La plage Système étant petite et très demandée, les chances d'y obtenir un numéro de port sont plus faibles (il faut un examen par l'IETF ou bien une approbation par l'IESG, RFC 6335, section 8.1, et aussi le RFC 5226, sur la définition des politiques d'enregistrement).

Comme toute ressource limitée dans un espace commun, les numéros de port peuvent susciter des frictions. Une fois le logiciel déployé, il peut être difficile de changer le numéro de port de manière coordonné. D'où les deux règles :

  • Ne pas déployer de code avec un numéro de port statique tant que celui-ci n'a pas été enregistré par l'IANA, afin d'éviter le squat (cf. plus loin),
  • Si on utilise les ports expérimentaux du RFC 4727 (1 021 et 1 022), il ne faut le faire que dans un environnement qu'on contrôle bien, pour garantir qu'on pourra migrer ensuite vers le port final, sans bloquer éternellement ces numéros de port expérimentaux.

Et c'est quoi, ce risque de squat ? C'est l'utilisation d'un port statique sans l'avoir obtenu par les procédures normales. Cela peut être dû à un développeur pressé ou négligent qui écrit son code sans tenir compte des procédures, et le publie. Cela peut être aussi délibéré de la part de gens qui s'estiment au-dessus des règles et qui se réservent sans vergogne une part de la ressource commune. Dans les deux cas, c'est très gênant car, une fois le code largement déployé sur l'Internet, il sera vraiment difficile de le changer, ou même de savoir si le port est encore utilisé (voir aussi la section 7.9). Le squat est donc nettement condamné. Un exemple fameux de squat est l'enregistrement de CARP.

La section 8 de notre RFC couvre les questions de sécurité liées aux ports. D'abord, il ne faut pas se fier au numéro de port. Rien ne garantit que ce qui circule sur le port 53 soit du DNS, et encore moins que ce soit du DNS correct (voir l'exemple plus haut avec tcpdump). Rien ne garantit qu'un paquet où le port source est inférieur à 1 024 a vraiment été émis par une personne de confiance, et ainsi de suite. Les mesures classique d'authentification sont donc nécessaires si on veut vraiment se protéger.

Ensuite, un mot sur la vie privée. Le système des ports bien connus est l'antithèse de la vie privée puisqu'un simple coup d'œil à l'en-tête de couche 4, sans aller examiner le contenu applicatif, indique quel service on utilise. Bien sûr, ce n'est pas une garantie (paragraphe précédent...) mais cela donne déjà une indication. Autre indiscrétion liée aux ports : en envoyant des demandes de connexion TCP à une machine, vers les différents ports (comme ce que fait nmap), on peut savoir quels services elle offre, sans avoir besoin d'analyser les applications. C'est un problème, mais qui est fondamentalement lié à l'architecture de TCP/IP et qui est difficile à corriger (on peut toujours recourir à des trucs comme le port knocking).

Moins directement utile mais passionnante, l'histoire des ports était présentée dans la section 3. Le terme est apparu pour la première fois dans le RFC 33, en 1970 (« We assume here that a process has several input-output paths which we will call ports. »). À l'époque, les couches 3 et 4 étaient encore mêlées, dans le protocole NCP. L'adresse désignant une machine, le port devait désigner une voie de communication d'un processus sur cette machine. (Notez qu'avec des adresses IP suffisamment longues et abondantes, comme ce que fournit IPv6 aujourd'hui, on pourrait se débarrasser complètement de la distinction adresse/port, un préfixe IP pourrait désigner une machine et chaque adresse une prise ou un processus. La séparation adresse/port est le souvenir d'une époque révolue.) Le RFC 37 et le RFC 38 ont ensuite précisé et modifié l'idée (« The destintation [sic] socket must be added to the header of each message on the data link. Presumably this would consist of 32 bits [ce sera finalement 16 bits] immediately after the header and before the marking. »). Puis le RFC 48, toujours en 1970, introduit l'idée d'« écoute » sur un port, lorsqu'un processus est en attente d'une requête. Et le RFC 61 est le premier à se demander comment on est censé connaître le port de destination d'un message, et à introduire le concept de « port bien connu » (well-known port) comme le futur port 80 pour HTTP. Le RFC 76 s'attaque à la question posée, mais non résolue, par le RFC 61 et propose un annuaire permettant d'associer des noms de services à des numéros de port (le /etc/services de votre machine Unix en est le lointain descendant). « most permanently assigned devices and/or processes are known by standard mnemonic labels such as DSK (disk), LP (line printer), CR (card reader), TECO (PDP-10 text editor), etc. »

Une importante étape est ensuite franchie avec le RFC 333 en 1972, qui est le premier à suggérer que les ports de source et de destination servent (avec les adresses IP) à identifier une connexion, ce qui sera le choix final de TCP (RFC 793, en 1981, mais décrit deux ans avant avant dans le document IEN 112). Le RFC 717 est le premier à indiquer des numéros de port officiellement affectés mais c'est le RFC 739, en 1977, qui avait généralisé l'idée (sous le nom de socket number). Dans ce RFC, telnet avait déjà le port 23, qu'il a gardé jusqu'à aujourd'hui, comme bien des protocoles depuis oubliés. Les procédures de l'époque étaient plus simples qu'aujourd'hui (« please contact Jon [Postel] to receive a number assignment »).

Quant au RFC 758, il était le premier à étendre le concept de port à TCP (les RFC précédents ne parlaient que de NCP). Certaines plages de numéros de ports étaient réservées à des usages spécifiques, mais son successeur, le RFC 820, n'a pas retenu cette distinction (en prime, le RFC 820 a étendu l'usage des ports à UDP). Avec le RFC 900 disparait la notation octale, avec le RFC 1340 (en 1992), la liste des « ports bien connus » va désormais de 0 à 1 023 et plus seulement jusq'à 255 (on y note l'apparition de 80, pour HTTP). Cette liste sera encore révisée dans le RFC 1700 puis remplacée en 2002 par un registre en ligne à l'IANA, registre décrit par le RFC 3232. (Le RFC listant les ports était toujours en retard sur l'allocation réelle.)


Téléchargez le RFC 7605


L'article seul

RFC 7603: Energy Management (EMAN) Applicability Statement

Date de publication du RFC : Août 2015
Auteur(s) du RFC : Brad Schoening (Independent Consultant), Mouli Chandramouli (Cisco Systems), Bruce Nordman (Lawrence Berkeley National Laboratory)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF eman
Première rédaction de cet article le 4 septembre 2015


Le but du projet EMAN (Energy MANagement) à l'IETF est de développer un ensemble de normes techniques sur la gestion de l'énergie par les équipements informatiques en réseau. Ce RFC explique le projet et décrit des scénarios d'utilisation. C'est un pas de plus (très modeste encore) vers un Internet plus « vert ».

Le cadre général pour la gestion de l'énergie des équipements Internet figure dans le RFC 7326 (et le cahier des charges dans le RFC 6988). L'idée est de d'abord de pouvoir superviser à distance tout engin connecté à l'Internet, et de connaitre par ce moyen sa consommation d'énergie (le préalable à toute action). Puis, le cadre EMAN (défini par le groupe de travail du même nom) doit permettre l'action sur ces engins, par exemple ralentir le processeur pour diminuer la consommation, ou carrément arrêter certaines machines pour économiser l'énergie. Il existe bien sûr déjà des méthodes pour cela mais elles ne sont pas encore normalisées ou bien utilisent des protocoles pré-Internet. EMAN doit permettre la supervision et l'action sur des engins très différents, et ne sortant pas de chez le même fournisseur. Le but n'est pas seulement d'économiser l'argent (l'électricité coûte cher) mais aussi de tenir compte de la finitude des ressources de la planète (c'est, à ma connaissance, la première fois que ce point est mentionné dans un RFC : bien des acteurs de l'Internet vivaient jusqu'à présent dans l'illusion qu'on trouverait toujours « une autre ressource énergétique »).

Bref, deux tâches pour EMAN, la supervision (mesurer la consommation) et l'action (éteindre si nécessaire). Pour permettre cette supervision et cette action, EMAN (RFC 7326) a défini un modèle de données, et utilisera le protocole SNMP, et des MIB dont certaines sont déjà développées (voir par exemple les RFC 7460 sur la MIB générale, RFC 7461 et le RFC 7577 sur la MIB de gestion des batteries). EMAN n'est donc pas une nouvelle pile protocolaire complète (cf. section 5), il s'appuie sur TCP/IP et sur les protocoles de gestion de réseaux standard (cf. RFC 6632).

Et les scénarios d'usage promis ? Ils figurent en section 2 de notre RFC. Je ne vais pas tous les reprendre ici mais certains sont rigolos. On trouve des routeurs dont on veut mesurer la consommation, des commutateurs qui sont eux-même distributeurs d'énergie (PSE Power Sourcing Equipment, par exemple via PoE, cf. RFC 3621), etc. Dans ce dernier cas, celui où des machines sont alimentées via un équipement réseau, il y a deux sous-cas : soit la machine est elle-même capable de faire du EMAN, donc d'informer sur sa consommation électrique elle-même (elle est un « Energy Object »), soit elle ne l'est pas et le PSE va alors devoir le faire pour elle. Et si la machine tire du courant d'une prise au mur ? Là encore, deux sous-cas, l'alimentation électrique peut être un PDU (Power Distribution Unit) « intelligent », capable de transmettre les informations lui-même, soit ce n'est pas le cas et il faudra alors que la machine alimentée soit capable de transmettre les informations à la gestion de réseau (un PC n'aura pas de mal, un objet plus simple si). Voir aussi la section 2.5 sur cette notion d'intermédiaire de mesure, le Mid-level Manager.

Il y a déjà partout des compteurs électriques, soit intégrés aux PDU, soit autonomes, et qui mesurent la consommation. Un des enjeux d'EMAN est de les rendre interrogeables à distance (section 2.4).

Prenons maintenant le cas d'un immeuble de bureaux ou d'une usine, doté d'une grosse alimentation électrique, gérée par des professionnels. De tels systèmes (BMS, Building Management System) sont évidemment gérés centralement depuis longtemps, bien avant EMAN, mais en général par des mécanismes non-standards. La liaison physique avec les équipements se fait souvent en RS-232 ou RS-485, les protocoles sont BACnet, Modbus ou ZigBee.

Plus modeste, la supervision de la consommation électrique à la maison. On peut vouloir savoir combien son frigo consomme (le fameux frigo connecté, de préférence en IPv6, un grand classique du discours marketing sur l'Internet des Objets). Beaucoup des équipements à superviser seront sans doute bon marché, et n'ayant donc pas toutes les capacités EMAN, et devront donc être interrogés via un relais (le mid-level manager dont j'ai parlé plus haut).

Au contraire, dans un centre de données, on a à la fois un enjeu bien plus important (la facture d'électricité de ces centres est énorme) et davantage de moyens (plein de machines connectés qui ne demandent pas mieux que d'être gérées à distance depuis un gestionnaire central). On veut en général une granularité de mesure très fine (pas juste « ce que consomme cette armoire » mais « ce que consomme ce serveur ») donc on va gérer d'importantes quantités de données.

Il ne faut pas oublier les équipements de stockage de l'énergie eux-mêmes, de la batterie traditionnelle à la pile à hydrogène. Ces équipements sont souvent distants (une batterie dans une tour de télécommunications ou en haut d'un château d'eau).

Et pour terminer cette liste très variée, n'oublions pas les humbles imprimantes. En raison de leur consommation électrique élevée, les imprimantes ont souvent des dispositifs d'économie d'énergie (mode « veille »). La consommation varie donc énormément (pensez au chauffage des éléments thermo-mécaniques comme le cylindre lorsque l'imprimante démarre) et des interrogations périodiques risquent donc de rater les moments de haute consommation. Les imprimantes haut de gamme connaissent déjà la gestion à distance et ont souvent SNMP.

Je l'ai indiqué plus haut, EMAN n'arrive pas dans un vide complet. Il y a de nombreuses années que la consommation électrique des équipements informatiques est mesurée et que les machines sont éteintes à distance pour économiser des joules. La section 4 de notre RFC couvre les normes et spécifications techniques existantes (je ne les reprends pas toutes ici, il y en a beaucoup). Ainsi, la CEI a toute une série de normes sur la gestion de l'électricité, avec notamment un modèle décrit dans IEC 61850. C'est un modèle qui embrasse largement, avec une centaine de classes. La norme IEC 62053 est également importante et ces normes ont déjà été utilisées dans EMAN. Proche de IEC 62053, l'ANSI a sa norme C12 sur les compteurs électriques. DMTF a aussi son modèle, DMTF DSP1027.

Il existe aussi des normes plus spécifiques, par exemple le PWG a des normes pour les imprimantes. À noter que la MIB « imprimante », dans le RFC 3805, ne couvre pas la gestion d'énergie. Il y a onze ans, c'était jugé moins important et peu de travail avait été fait en ce sens à l'IETF.

Parmi les autres spécifications existantes, on peut aussi citer ZigBee, élaboré par une organisation privée et pas une SDO ouverte.

Et, bien sûr, il y a Smart grid (section 4.3.3), le projet coordonné par le NIST. Smart grid est plus vaste qu'EMAN (il inclut la distribution de l'énergie) mais moins normatif car c'est plus un projet de coordination que de normalisation.

Un projet important car souvent vu par le consommateur final est Energy Star, lancé par le gouvernement états-unien. Il ne s'agit pas d'une norme technique ou d'un protocole de communication mais d'un ensemble de bonnes pratiques que devraient suivre les équipements électriques, notamment en terme d'efficacité énergétique. Aujourd'hui, EMAN et EnergyStar sont deux efforts séparés mais, dans le futur, EnergyStar pourrait référencer EMAN pour inciter les fabricants à doter leurs systèmes de capacité de mesure.

La section 5 de notre RFC rappelle quelques limites volontaires d'EMAN : EMAN ne cherche pas à résoudre tous les problèmes de l'électricité. Par exemple, EMAN ne couvre pas la production et le transport de l'électricité, seulement sa consommation chez les utilisateurs finaux.

Enfin, pour terminer ce RFC, n'oublions évidemment pas la sécurité, avec la section 6, qui rappelle notamment que la mesure de la consommation électrique peut poser de sérieux problèmes de protection de la vie privée. (On pourra déterminer à distance vos habitudes à la maison, par exemple. La NSA saura quand vous avez des insomnies et allumez la lumière en pleine nuit.) Le RFC 7460, dans sa section 10, détaille ce risque.


Téléchargez le RFC 7603


L'article seul

RFC 7601: Message Header Field for Indicating Message Authentication Status

Date de publication du RFC : Août 2015
Auteur(s) du RFC : M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 5 septembre 2015


Il existe désormais plusieurs techniques pour authentifier les courriers électroniques. Certaines peuvent nécessiter des calculs un peu compliqués et on voudrait souvent les centraliser sur une machine de puissance raisonnable, dotée de tous les logiciels nécessaires. Dans cette hypothèse, le MUA ne recevra qu'une synthèse (« Ce message vient bien de example.com ») et pourra alors prendre une décision, basée sur cette synthèse. C'est le but de l'en-tête Authentication-Results:, normalisé originellement dans le RFC 5451 six ans plus tôt, auquel a succédé le RFC 7001, que ce nouveau RFC met légèrement à jour (il y a peu de changements, le principal étant la correction de l'erreur #4201). Depuis, notre RFC a lui-même été remplacé par le RFC 8601.

Avec des techniques d'authentification comme DKIM (RFC 6376) ou SPF (RFC 7208), les calculs à faire pour déterminer si un message est authentique peuvent être complexes (DKIM utilise la cryptographie) et nécessiter la présence de bibliothèques non-standard. Les installer et les maintenir à jour sur chaque machine, surtout en présence d'éventuelles failles de sécurité qu'il faudra boucher en urgence, peut être trop pénible pour l'administrateur système. L'idée de ce RFC est donc de séparer l'opération en deux : l'authentification est faite sur un serveur, typiquement le premier MTA du site (cf. annexe C pour une discussion de ce choix), celui-ci ajoute au message un en-tête indiquant le résultat de ladite authentification et le MUA (ou bien le MDA, voir la section 1.5.3 pour un bon rappel sur ces concepts) peut ensuite, par exemple par un langage de filtrage comme procmail ou Sieve, agir sur la base de ce résultat. L'idée n'est donc pas de montrer la valeur de cet en-tête à M. Michu (voir la section 4.1 pour quelques risques que cela poserait), mais d'en faire une donnée pour un programme. Cet en-tête marche pour tous les protocoles d'authentification et surpasse donc les en-têtes spécifiques comme le Received-SPF: de SPF (section 1 du RFC). Le filtrage des messages non authentifiés n'est pas obligatoire (section 1.4) : agir - ou pas - sur la base de l'en-tête Authentication-Results: est une décision politique locale.

J'ai utilisé le terme de « site » pour désigner un ensemble de machines gérées par la même organisation mais le RFC a un terme plus rigoureux, ADMD (ADministrative Management Domain). La frontière d'un ADMD est la « frontière de confiance » (trust boundary), définie en section 1.2. Un domaine administratif de gestion est un groupe de machines entre lesquelles il existe une relation de confiance, notamment du fait que, à l'intérieur de l'ADMD, l'en-tête Authentication-Results: ne sera pas modifié ou ajouté à tort (section 1.6 : l'en-tête n'est pas protégé, notamment il n'est pas signé). Il existe de nombreuses variantes organisationnelles du concept d'ADMD. Un ADMD inclus typiquement une organisation (ou un département de celle-ci) et d'éventuels sous-traitants. Il a un nom, l'authserv-id, défini en section 2.2.

L'en-tête Authentication-Results: lui-même est formellement défini en section 2. Il appartient à la catégorie des en-têtes de « trace » (RFC 5322, section 3.6.7 et RFC 5321, section 4.4) comme Received: qui doivent être ajoutés en haut des en-têtes et jamais modifiés. La syntaxe de Authentication-Results: est en section 2.2. L'en-tête est composé du authserv-id, le nom de l'ADMD et d'une série de doublets (méthode, résultat), chacun indiquant une méthode d'authentification et le résultat obtenu. L'annexe B fournit une série d'exemples. Elle commence (annexe B.1) par un message sans Authentication-Results: (eh oui, il n'est pas obligatoire). Puis (tiré de l'annexe B.3), une authentification SPF réussie, au sein de l'ADMD example.com, donnera :

        Authentication-Results: example.com;
                  spf=pass smtp.mailfrom=example.net
        Received: from dialup-1-2-3-4.example.net
                      (dialup-1-2-3-4.example.net [192.0.2.200])
                  by mail-router.example.com (8.11.6/8.11.6)
                      with ESMTP id g1G0r1kA003489;
                  Wed, Mar 14 2009 17:19:07 -0800
        From: sender@example.net
        Date: Wed, Mar 14 2009 16:54:30 -0800
        To: receiver@example.com

Rappelez-vous qu'il peut y avoir plusieurs authentifications. Voici un cas (annexe B.4) avec SPF et l'authentification SMTP du RFC 4954 :

       Authentication-Results: example.com;
                  auth=pass (cram-md5) smtp.auth=sender@example.net;
                  spf=pass smtp.mailfrom=example.net
        Received: from dialup-1-2-3-4.example.net (8.11.6/8.11.6)
                      (dialup-1-2-3-4.example.net [192.0.2.200])
                  by mail-router.example.com (8.11.6/8.11.6)
                      with ESMTP id g1G0r1kA003489;
                  Fri, Feb 15 2002 17:19:07 -0800
        Date: Fri, Feb 15 2002 16:54:30 -0800
        To: receiver@example.com
        From: sender@example.net

L'une des authentifications peut réussir et l'autre échouer. Un exemple (annexe B.6) avec deux signatures DKIM, une bonne et une qui était correcte au départ (regardez le premier Authentication-Results:) mais plus à l'arrivée, peut-être parce qu'un gestionnaire de liste de diffusion a modifié le message :

       Authentication-Results: example.com;
              dkim=pass reason="good signature"
                header.i=@mail-router.example.net;
              dkim=fail reason="bad signature"
                header.i=@newyork.example.com
        Received: from mail-router.example.net
                  (mail-router.example.net [192.0.2.250])
              by chicago.example.com (8.11.6/8.11.6)
                  for <recipient@chicago.example.com>
                  with ESMTP id i7PK0sH7021929;
              Fri, Feb 15 2002 17:19:22 -0800
        DKIM-Signature: v=1; a=rsa-sha256; s=furble;
              d=mail-router.example.net; t=1188964198; c=relaxed/simple;
              h=From:Date:To:Message-Id:Subject:Authentication-Results;
              bh=ftA9J6GtX8OpwUECzHnCkRzKw1uk6FNiLfJl5Nmv49E=;
              b=oINEO8hgn/gnunsg ... 9n9ODSNFSDij3=
        Authentication-Results: example.net;
              dkim=pass (good signature) header.i=@newyork.example.com
        Received: from smtp.newyork.example.com
                  (smtp.newyork.example.com [192.0.2.220])
              by mail-router.example.net (8.11.6/8.11.6)
                  with ESMTP id g1G0r1kA003489;
              Fri, Feb 15 2002 17:19:07 -0800
        DKIM-Signature: v=1; a=rsa-sha256; s=gatsby;
              d=newyork.example.com;
              t=1188964191; c=simple/simple;
              h=From:Date:To:Message-Id:Subject;
              bh=sEu28nfs9fuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m7=;
              b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM=
        From: sender@newyork.example.com
        Date: Fri, Feb 15 2002 16:54:30 -0800
        To: meetings@example.net

La liste complète des méthodes figure dans un registre IANA (section 6). De nouvelles méthodes peuvent être enregistrées en utilisant la procédure « Examen par un expert » du RFC 5226.

La section 2.3 détaille l'authserv-id. C'est un texte qui identifie le domaine, l'ADMD. Il doit donc être unique dans tout l'Internet. En général, c'est un nom de domaine comme laposte.net. (Il est possible d'être plus spécifique et d'indiquer le nom d'une machine particulière mais cette même section du RFC explique pourquoi c'est en général une mauvaise idée : comme les MUA du domaine n'agissent que sur les Authentication-Results: dont ils reconnaissent l'authserv-id, avoir un tel identificateur qui soit lié au nom d'une machine, et qui change donc trop souvent, complique l'administration système.)

La section 2.7 explique les résultats possibles pour les méthodes d'authentification (en rappelant que la liste à jour des méthodes et des résultats est dans le registre IANA). Ainsi, DKIM (section 2.7.1) permet des résultats comme pass (authentification réussie) ou temperror (erreur temporaire au cours de l'authentification, par exemple liée au DNS). Des résultats similaires sont possibles pour SPF (section 2.7.3).

Notons la normalisation d'une méthode traditionnelle d'authentification faible, le test DNS du chemin « adresse IP du serveur -> nom » et retour. Baptisée iprev, cette méthode, bien que bâtie sur la pure superstition (cf. section 7.11) est utilisée couramment. Très injuste (car les arbres des résolutions inverses du DNS, in-addr.arpa et ip6.arpa, ne sont pas sous le contrôle du domaine qui envoie le courrier), cette méthode discrimine les petits FAI, ce qui est sans doute un avantage pour les gros, comme AOL qui l'utilisent. Attention aux implémenteurs : aussi bien la résolution inverse d'adresse IP en nom que la résolution droite de nom en adresse IP peuvent renvoyer plusieurs résultats et il faut donc comparer des ensembles. (Cette méthode qui, contrairement aux autres, n'avait jamais été exposée dans un RFC avant le RFC 5451, est décrite en détail dans la section 3, avec ses sérieuses limites.)

Autre méthode mentionnée, auth (section 2.7.4) qui repose sur l'authentification SMTP du RFC 4954. Si un MTA (ou plutôt MSA) a authentifié un utilisateur, il peut le noter ici.

Une fois le code d'authentification exécuté, où mettre le Authentication-Results: ? La section 4 fournit tous les détails, indiquant notamment que le MTA doit placer l'en-tête en haut du message, ce qui facilite le repérage des Authentication-Results: à qui on peut faire confiance (en examinant les en-têtes Received: ; en l'absence de signature, un Authentication-Results: très ancien, situé au début du trajet, donc en bas des en-têtes, ne signifie pas grand'chose). On se fie a priori aux en-têtes mis par les MTA de l'ADMD, du domaine de confiance. L'ordre est donc important. (La section 7 revient en détail sur les en-têtes Authentication-Results: usurpés.)

Ce n'est pas tout de mettre un Authentication-Results:, encore faut-il l'utiliser. La section 4.1 s'attaque à ce problème. Principe essentiel pour le MUA : ne pas agir sur la base d'un Authentication-Results:, même si ce n'est que pour l'afficher, sans l'avoir validé un minimum. Comme le Authentication-Results: n'est pas signé, n'importe qui a pu en insérer un sur le trajet. Le RFC précise donc que les MUA doivent, par défaut, ne rien faire. Et qu'ils doivent ne regarder les Authentication-Results: qu'après que cela ait été activé par l'administrateur de la machine, qui indiquera quel authserv-id est acceptable.

Naturellement, le MTA d'entrée du domaine devrait supprimer les Authentication-Results: portant son propre authserv-id qu'il trouve dans les messages entrants : ils sont forcément frauduleux (section 5). (Le RFC accepte aussi une solution plus simpliste, qui est de supprimer tous les Authentication-Results: des messages entrants, quel que soit leur authserv-id.)

Arrivé à ce stade de cet article, le lecteur doit normalement se poser bien des questions sur la valeur du Authentication-Results:. Quel poids lui accorder alors que n'importe quel méchant sur le trajet a pu ajouter des Authentication-Results: bidons ? La section 7, consacrée à l'analyse générale de la sécurité, répond à ces inquiétudes. 7.1 détaille le cas des en-têtes usurpés. Les principales lignes de défense ici sont le fait que le MUA ne doit faire confiance aux Authentication-Results: que s'ils portent le authserv-id de son ADMD et le fait que le MTA entrant doit filtrer les Authentication-Results: avec son authserv-id. Comme l'intérieur de l'ADMD, par définition, est sûr, cela garantit en théorie contre les Authentication-Results: usurpés. Le RFC liste néanmoins d'autres méthodes possibles comme le fait de ne faire confiance qu'au premier Authentication-Results: (le plus récent), si on sait que le MTA en ajoute systématiquement un (les éventuels Authentication-Results: usurpés apparaîtront après ; mais certains serveurs les réordonnent, cf. section 7.3). Pour l'instant, il n'y a pas de méthode unique et universelle de vérification du Authentication-Results:, le RFC propose des pistes mais ne tranche pas.

Comme toujours en sécurité, il faut bien faire la différence entre authentification et autorisation. Un spammeur a pu insérer un Authentication-Results: légitime pour son authserv-id. Même authentifié, il ne doit pas être considéré comme une autorisation (section 7.2).

Plusieurs mises en œuvre de ce système existent déjà comme dans MDaemon, sendmail (via sid-milter), Courier, OpenDKIM, etc. Si on veut analyser les en-têtes Authentication-Results: en Python, on a le module authres. Parmi les grosses usines à courrier centralisées, Gmail met systématiquement cet en-tête, par exemple :

Authentication-Results: mx.google.com; spf=pass \
           (google.com: domain of stephane@sources.org designates 217.70.190.232 \
               as permitted sender) smtp.mail=stephane@sources.org

Outre Gmail, à la date de publication du RFC, Yahoo et Hotmail ajoutaient cet en-tête.

Les changements depuis le RFC 7001 sont peu nombreux (annexe D pour une liste complète). Le RFC 7410, qui créait le registre des types d'information possibles sur l'authentification a été intégré et est donc remplacé par notre nouveau RFC. Autrement, l'un des principaux changements concerne la bogue #4201. Le texte du précédent RFC disait que la source de l'authentification devait être un en-tête du message alors que cela peut être un champ particulier d'un en-tête (le cas du champ i dans les signatures DKIM d'exemple dans cet article, cf. 2.3 et 2.7.1). Autrement, les changements par rapport au RFC 7001 sont surtout des détails et les mises en œuvre actuelles devraient continuer sans trop d'histoires. Je rappelle que ce RFC 7601 n'est plus d'actualité, ayant été remplacé par le RFC 8601.


Téléchargez le RFC 7601


L'article seul

RFC 7595: Guidelines and Registration Procedures for URI Schemes

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : D. Thaler (Microsoft), T. Hansen (AT&T Laboratories), T. Hardie (Google), L. Masinter (Adobe)
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 24 juin 2015


Ce n'est pas tous les jours qu'on enregistre un plan d'URI (le plan - scheme en anglais - est le premier composant d'un URI, la partie avant le premier deux-points). Ils sont peu nombreux et on voit rarement autre chose que le fameux http:. Mais, si jamais vous voulez ajouter un plan à la liste existante, ce RFC vous explique les règles d'enregistrement. Il remplace le RFC 4395.

Les plans d'URI sont normalisés dans le RFC 3986, section 3.1. Le plan est souvent appelé à tort « protocole » alors que, dans la grande majorité des cas, il n'a aucun rapport avec un protocole (voir la section 3.8 de notre RFC), et, même quand le nom du plan est celui d'un protocole (comme http:), il n'implique pas l'utilisation de ce protocole (un URI ne sert pas forcément à accéder à une ressource). Il existe de nombreux plans, du très connu http: au moins fréquent tag: (RFC 4151) en passant par bien d'autres, souvent assez confidentiels comme le acct: du RFC 7565 ou le dict: du RFC 2229. La liste des plans enregistrés se trouve à l'IANA. Le RFC 3986 décrit seulement la syntaxe générique des URI, celle commune à tous les URI et qui se limite largement à « un plan, deux points, puis du texte » (par exemple, http://www.bortzmeyer.org/608.html ou tag:bortzmeyer.org,2006-02:Blog/608). La grande majorité du contenu de l'URI a une syntaxe et une signification qui dépendent du plan et un logiciel d'usage très général doit donc connaître ces plans et leurs particularités.

Il existe un registre des plans, qui permet aux développeurs de ces applications de trouver tous les plans en un endroit, et de limiter le risque de collision. La politique d'enregistrement est déliberement assez libérale pour éviter la prolifération de plans non-enregistrés.

Petite note d'internationalisation au passage : les plans sont les mêmes pour les URI (qui doivent s'écrire uniquement en ASCII) et les IRI du RFC 3987, qui peuvent utiliser Unicode (ce n'était pas clair dans le RFC précédent, le RFC 4395).

En section 3 de notre RFC, les règles à suivre. D'abord, la syntaxe générale des URI doit être respectée (ce qui est facile, elle est très générale). Par exemple, l'identificateur de fragment (ce qui suit le croisillon, cf. RFC 3986, section 3.5), garde la même sémantique (notamment le fait qu'il n'est utilisé que par le client, pas par le serveur Web), un nouveau plan d'URI ne peut pas utiliser cette syntaxe pour exprimer autre chose.

Est-ce que le nouveau plan d'URI est une bonne idée ? Pour que son enregistrement soit accepté, le plan doit présenter une utilité à long terme, répond la section 3.1. Cette restriction est justifiée par le fait que tout nouveau plan peut nécessiter une modification de tous les logiciels qui traitent des URI et agissent différemment selon le plan. Et le Web contient autre chose que des clients et serveurs, il y a les relais, les caches, etc. (Le RFC note également que, bien que l'espace de nommage des plans soit infini, en pratique, il pourrait y avoir une concurrence trop forte pour les noms courts et facilement mémorisables et que cela justifie donc de ne pas accepter toutes les candidatures.)

Il y a aussi des contraintes plus techniques. La définition d'un nouveau plan doit décrire la syntaxe de l'URI (rappelez-vous que la syntaxe générale des URI ne couvre qu'une petite partie des règles). La section 3.2 impose que le nouveau plan respecte les règles syntaxiques existantes. Par exemple le // a une signification bien précise dans un URI, il précède le nom de la machine qui sert d'autorité de nommage, pour attribuer le reste de l'URI (section 3.2 du RFC 3986). En l'absence d'une telle machine de référence, le // ne doit donc pas être utilisé. (c'est pour cela que dict://dict.example.org/d:chocolate: a un //, car il contient le nom d'un serveur, ici dict.example.org alors que mailto:echo@generic-nic.net n'en a pas, car les adresses de courrier sont globales, elles ne dépendent pas d'un serveur particulier). D'une manière générale, notre RFC déconseille l'utilisation de la barre oblique, sauf si on accepte des URI relatifs, pour éviter qu'un logiciel trop zélé n'ajoute en prime un traitement spécial pour . ou .. (souvent interprétés pour dire « ce niveau » ou « le niveau supérieur »).

Il faut bien sûr que le plan soit correctement et complètement défini (sections 3.3 à 3.5). Par exemple, si l'URI est résolvable, sa description doit expliquer comment. Autre exemple, la description doit expliquer ce qu'on peut faire de l'URI. Accéder (et parfois modifier) à une ressource (cas du http:) ? À une machine (cas de telnet:, où le modèle « accès à une ressource » ne s'applique pas) ? S'il existe une opération par défaut (« je lance mon navigateur Web sur example:foo-bar-42, que fait-il ? », elle doit être sûre, au sens où elle ne doit pas avoir d'effets de bord. Enfin, le cas des URI qui servent juste à faire correspondre à un identificateur non-URI est normalement plus simple, avec une définition assez évidente. C'est le cas par exemple des mid: du RFC 2392, qui transforment un Message-ID: du courrier électronique en URI.

On a parlé plus haut des IRI. La section 3.6 nous rappelle les principes d'internationalisation des URI, et donne des bons conseils (faire bien attention à ne pas autoriser plusieurs représentations d'un même caractère, cf. RFC 3986, section 2.5). Le RFC donne aussi de mauvais conseils comme de prétendre (sans donner un seul exemple) qu'il faut restreindre le plus possible le jeu de caractères autorisé, certains caractères étant « dangereux ».

Pendant qu'on parle de danger, la section 3.7 rappelle la nécessité de bien documenter les questions de sécurité et de vie privée liées au nouveau plan. C'est une des nouveautés par rapport à l'ancien RFC 4395 que cette mention de la vie privée. Cela reflète l'importance croissante accordée à ce problème à l'IETF : de nombreux RFC mentionnent désormais la vie privée et pas seulement la sécurité informatique traditionnelle.

Enfin, le plan doit recevoir un nom (section 3.8), qui soit à la fois assez court pour être pratique et assez long pour être descriptif (et ce nom doit suivre la syntaxe de la section 3.1 du RFC 3986 qui limite notamment à ASCII, même pour des IRI). Pire, comme ces plans sont visibles (des URI sont souvent affichés dans les publications, sur les cartes de visite, sur les publicités), le nom du plan ne doit pas interférer avec des marques déposées défendues par des bataillons d'avocats. Il vaut donc mieux ne pas essayer de normaliser le plan coca-cola: (qui permettrait d'écrire des choses utiles comme coca-cola:light)... Le RFC recommande aussi d'éviter des noms trop marketing comme tout ce qui contient « universal » ou « standard ».

Pour les plans privés, spécifiques à une organisation et non enregistrés, notre RFC recommande d'utiliser un nom de domaine inversé comme préfixe, afin de limiter les risques de collisions (sections 3.8 et 6). Si la société Example, titulaire du domaine example.com, veut un plan pour son système Foobar, elle utilisera donc com.example.foobar: comme plan d'URI. Cela évite toute collision avec une autre société qui aurait un Foobar. (Le RFC 4395 recommandait un tiret au lieu d'un point dans ce nom inversé.)

Ces règles de la section 3 sont obligatoires pour les plans enregistrés de manière permanente. Mais le registre contient aussi des plans enregistrés à titre provisoire et les règles en question ne sont qu'indicatives pour eux (section 4). Les enregistrements provisoires sont soumis à une politique plus libérale, « premier arrivé, premier servi ». Cela permet de demander que les plans privés soient, s'ils ne sont pas fabriqués à partir d'un nom de domaine comme l'exemple précédent, enregistrés de manière provisoire. Parmi les plans provisoires, au moment de cet article, bitcoin:, dtn: (cf. RFC 5050), etc.

Notez que, dans le registre des plans d'URI, outre les caractéristiques « permanent » et « provisoire », il y a aussi « historique » qui désigne les plans abandonnés (comme le fax: du RFC 2806).

Bref, une fois qu'on a bien lu toutes ces considérations, on peut passer à l'enregistrement proprement dit. Pour cela, il faut suivre la procédure exposée en section 7 (qui utilise les termes du RFC 5226 comme « examen par un expert » ou « premier arrivé, premier servi »). On remplit un formulaire (section 7.4 pour un formulaire vierge), il est examiné (dans la plupart des cas) sur une liste de diffusion comme uri-review@ietf.org, puis par un expert (section 7.2).

Une éventuelle mise à jour d'un enregistrement se fait par le même mécanisme (section 7.3).

Une des nouveautés de notre RFC, par rapport à son prédécesseur RFC 4395, est la création d'un plan d'URI qui sert à la documentation (dans l'esprit du RFC 5398 pour les numéros d'AS et RFC 2606 pour les noms de domaine). Si vous voyez un URI qui commence par example:, c'est... un exemple. Imaginons une base de données qui stocke des URI et qu'on montre un exemple d'export de cette base en JSON, on est sûr de ne pas entrer en conflit avec un vrai URI, et on n'a pas trop à se soucier de la syntaxe (le plan example: autorise tout), en utilisant ce plan :

{"uris":
   {"date": "2014-09-02 09:58:23+00:00",
    "uri": "example:do-some-thing#test"},
   {"date": "2015-06-24 16:11:09+00:00",
    "uri": "example:foo.bar"},
   ...
}

Le formulaire d'enregistrement de ce plan figure dans la section 8 de notre RFC, si vous envisagez d'enregistrer un plan et que vous voulez un exemple. Si vous voulez un vrai exemple récent, vous pouvez regarder la section 7 du RFC 7565, qui enregistrait acct:. (Pour les enregistrements provisoires, la demande est indiquée à partir du registre IANA.)

L'annexe A de notre RFC liste les changements qui se sont produits depuis le RFC 4395. Les plus importants, à mon avis, sont :

  • Fusion des registres permanent et provisoire en un seul registre, avec une colonne Status,
  • Libéralisation de l'enregistrement des plans provisoires (cf. RFC 5226), de « Examen par un expert » à « Premier arrivé, premier servi » (les plans permanents restent à « Examen par un expert »),
  • Ajout du plan example:,
  • Changement des conventions pour les préfixes des plans privés non enregistrés (point au lieu du tiret entre les composants du nom de domaine),
  • Diverses clarifications, par exemple sur le fait que tout plan d'URI s'aapplique aux IRI aussi bien qu'aux URI,
  • Ajout de la vie privée aux considérations sur la sécurité.

Il y avait eu d'autres idées pendant le développement de ce RFC, mais toutes n'ont pas été retenues. Par exemple, à l'IETF 90, nous avions discuté de faire des plans avec préfixes (coap+ws:, coap+sms:, etc, au lieu du simple coap: du RFC 7252), par analogie avec les types MIME structurés du RFC 6839.


Téléchargez le RFC 7595


L'article seul

RFC 7594: A framework for Large-Scale Measurement of Broadband Performance (LMAP)

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : P. Eardley (BT), A. Morton (AT&T Labs), M. Bagnulo (UC3M), T. Burbridge (BT), P. Aitken (Brocade), A. Akhter (Consultant)
Pour information
Réalisé dans le cadre du groupe de travail IETF lmap
Première rédaction de cet article le 21 septembre 2015


Le groupe de travail LMAP de l'IETF travaille sur les mesures des performances des accès Internet « haut débit ». Des mesures comme celles que fait l'ARCEP en France. Ce RFC définit le cadre conceptuel de ces mesures et leur terminologie.

Donc, d'abord, les généralités (section 1 du RFC). On veut mesurer la qualité du réseau depuis un grand nombre de points de mesure. Sur chacun de ces points se trouve un MA (Measurement Agent, au passage, le vocabulaire spécifique de LMAP est en section 3 du RFC) qui peut être matériel (sondes de l'ARCEP, sondes RIPE Atlas, sondes Sam Knows, etc) ou logiciel (Grenouille, etc). Le matériel peut être un boîtier séparé ou bien être un composant dans un engin comme la box. Le but de LMAP est de travailler sur des mesures à grande échelle, avec des milliers, voire des millions de MA. À qui cela va-t-il servir ?

  • Aux opérateurs de réseau pour planifier les investissements et détecter des problèmes,
  • Aux régulateurs des télécommunications (comme l'ARCEP déjà citée) pour comparer les opérateurs et détecter des points où de la régulation pourrait être nécessaire (par exemple en cas de violation de la neutralité du réseau).

Ces buts sont décrits plus en détail dans le RFC 7536.

Outre les MA (Measurement Agents, installés chez M. Michu ou dans un point de mesure dédié, et qui exécutent les mesures), le système comprend les contrôleurs et les collecteurs. Le contrôleur est celui qui dit aux MA quelles mesures faire. Dans le cas de RIPE Atlas, le contrôleur est une machine au RIPE-NCC qui reçoit les demandes de mesures faites, par exemple, via l'API, et les transmet aux Atlas « pingue donc 192.0.2.34 avec un paquet ICMP ECHO par minute pendant dix minutes ». Le collecteur reçoit les résultats de ces mesures (« premier essai, RTT de 18 ms, deuxième essai time out, troisième essai, RTT de 23 ms... ») et les analyse et/ou les rend disponibles. Le collecteur doit donc gérer une belle base de donnéees (big data) avec un mécanisme d'accès aux données, comme SQL. Le protocole de communication entre le contrôleur et les MA se nomme le protocole de contrôle et celui entre les MA et le collecteur le protocole de collecte (report protocol). Certains systèmes (c'est le cas des Atlas) ne font pas de différence entre contrôleur et collecteur (et donc n'utilisent qu'un seul protocole pour le contrôle et la collecte).

On souhaite évidemment que l'ensemble du système :

  • Soit normalisé, afin qu'on puisse choisir indépendamment ses différents composants. Il ne s'agit pas seulement de normaliser les protocoles mais aussi le modèle de données et le format de celles-ci (description des tâches de mesure, et des données récoltées). Normaliser tout cela est le principal travail du groupe de travail LMAP. (Le modèle de données a été normalisé dans le RFC 8193.)
  • Passe à l'échelle comme indiqué plus haut (« des millions de MA »). Un contrôleur unique et centralisé, par exemple, pourrait avoir du mal à effectuer son travail, à devoir coordonner un million de MA bavards (cf. RFC 7398).
  • Accepte la diversité des réseaux (MA connectés à des capacités très variables, réseaux IPv4 et IPv6, tests par plusieurs moyens, par exemple traceroute avec ICMP ou UDP, de façon à maximiser les chances de passer outre les pare-feux).
  • Respecter la vie privée. Certaines informations récoltées peuvent être délicates.

La section 2 du RFC décrit à gros grains à quoi pourrait ressembler le système idéal. Le MA doit faire des mesures. Celles-ci peuvent être passives (le MA observe le trafic existant, sans interférer) ou actives (le MA envoie des paquets et observe leur effet). Notez que la plupart des systèmes existants sont purement actifs (une collecte passive soulève d'intéressants problèmes de vie privée...) mais que LMAP traite les deux cas.

Pour que les mesures soient anaysables et comparables, il vaut mieux qu'elles se réfèrent à des métriques standards et documentées (ce qui est rare, par exemple les mesures de l'ARCEP ne s'appuient pas sur les normes existantes, réinventant ainsi la roue).

Les canaux de communication (entre le MA et le contrôleur, ainsi qu'entre le MA et le collecteur) doivent évidemment être sécurisés, pour se prémunir contre des attaques comme celle d'un faux contrôleur qui essaierait d'utiliser les MA à son profit.

À noter que la configuration initiale du MA (par exemple, le nom de domaine pour contacter le contrôleur) n'est pas normalisée. Le MA peut arriver pré-configuré (c'est le cas des sondes RIPE Atlas) ou bien être configuré par un des protocoles existants comme NETCONF ou CWMP.

La section 4 de notre RFC est consacrée aux limites de LMAP. Le projet est assez ambitieux comme cela, il va donc se donner quelques restrictions (d'autres sont données en section 5.6) :

  • Une seule organisation gère les MA, le contrôleur et le collecteur. LMAP ne va pas essayer de traiter le cas très difficile de mesures complètement pair-à-pair. Un tel système sans chef bien identifié serait sans doute très dangereux (risque de détournement pour faire des attaques par déni de service, risque de manipulation des données, ou de fuite de données privées).
  • Chaque MA n'a qu'un seul contrôleur. Pour la résilience, il serait sans doute intéressant de pouvoir avoir plusieurs contrôleurs mais cela soulèverait le problème de quoi faire si un MA reçoit des instructions contradictoires.
  • Les MA ne se coordonnent pas entre eux, on est purement top->down.
  • La relation entre le contrôleur et le collecteur n'est pas au programme. Ils vont bien sûr coopérer mais ce sera d'une manière non définie dans LMAP.
  • Chaque système de mesures est indépendant des autres (pour éviter d'avoir à gérer des problèmes de coordination). Si un régulateur et un FAI ont chacun leur système LMAP, et que M. Michu a deux MA (Measurement Agent) chez lui, les deux MA s'ignorent et chacun considère le trafic de l'autre comme du trafic utilisateur ordinaire.
  • Il ne gère pas le problème de la triche. Si un régulateur fait des mesures, on peut imaginer que certains FAI chercheront à identifier les lignes où se fait la mesure, ce qui est facile, puis à favoriser ces lignes, pour obtenir un meilleur score. Le problème n'a pas de solution technique et n'est donc pas traité par LMAP. (Voir aussi la fin de la section 7.)

La section 5 du RFC décrit de manière abstraite le modèle des protocoles à élaborer. On y trouve notamment la liste des fonctions à mettre en œuvre comme par exemple un mécanisme de suppression des données si on découvre que certaines mesures étaient erronées (par exemple parce que l'amer visé n'était pas joignable à ce moment).

Mais les informaticiens préféreront peut-être lire la section 6, plus concrète, qui décrit les questions pratiques de mise en œuvre et de déploiement. Par exemple, que doit faire un MA qui redémarre après un long arrêt ? Les instructions du contrôleur qu'il avait reçues et stockées peuvent être dépassées. Il doit donc tenter de re-contacter le contrôleur avant de se lancer dans les mesures.

Autre exemple de discussion pratique, la section 6.2 étudie les différentes formes de MA, et l'endroit où les placer, chaque forme et chaque endroit ayant ses avantages et ses inconvénients. Ainsi, un MA embarqué dans la box du FAI aurait des avantages (il voit tout le trafic, donc les mesures passives sont triviales à effectuer et toujours exactes, et les mesures actives peuvent être faites uniquement lorsque le trafic utilisateur est faible, alors qu'une sonde séparée risque de faire ses mesures au moment où on utilise la ligne à fond) et des inconvénients (dans le modèle classique des box imposées, les fonctions de la box ne sont accessibles qu'au FAI, pas au régulateur ou à l'utilisateur).

Et si le MA est (malheureusement pour lui) coincé derrière un NAT ? La principale conséquence est que le contrôleur ne pourra pas le joindre à volonté, ce sera au MA de le contacter. Une autre solution est de mettre un client PCP (RFC 6887) dans le MA.

Autre cas intéressant à considérer, celui où le MA se trouve en plein dans le réseau du FAI, et non plus chez M. Michu. (Le cas est cité dans le RFC 7398.) Cela permet au MA d'être indépendant des lubies du réseau local et de son accès et de faire des mesures dans un environnement plus contrôlé, donc plus scientifiques. Évidemment, ces mesures seront alors moins représentatives du vécu de l'utilisateur.

La section 6 discute aussi le cas où on a besoin d'une aide sur le réseau. Par exemple, si on pingue un amer situé sur l'Internet, cet amer ne peut pas être purement passif. Ce doit être une machine allumée et qui répond aux paquets ICMP ECHO. Une telle aide est nommée MP pour Measurement Peer. Ce rôle n'est pas évident. Par exemple, un amer peut tout à coup se mettre à limiter le trafic ICMP car il en a assez d'être pingué en permanence, faussant alors toutes les mesures. C'est encore plus vrai si on fait des tests lourds, comme de charger en HTTP un fichier de grande taille. Si on fait cela sur une machine qui n'était pas au courant de son rôle de MP, on peut se retrouver dans les ACL rapidement. S'il y a un protocole de contrôle explicite avec le MP (comme ceux des RFC 4656 ou RFC 5357), tout est plus simple, le MA négocie avec le MP le bon déroulement de la mesure. Sinon, il faut s'assurer d'abord que le MP est d'accord pour être utilisé. Heureusement, il existe des machines qui sont dédiées à ce rôle de MP, comme les Ancres.

La section 6.4 décrit un certain nombre de déploiements typiques. Ça peut aller de cas simples (le MA fait du HTTP avec un MP qui est juste un serveur HTTP ordinaire), à des choses plus complexes, où le MP déploie un logiciel spécifique comme iperf.

Un peu de sécurité maintenant (section 7 du RFC). La sécurité de LMAP doit protéger aussi bien le système de mesures, que le réseau mesuré (des mesures actives trop agressives pourraient sérieusement ralentir ce réseau, par exemple, voir la section 6 du RFC 4656). Plusieurs points sont donc à sécuriser. Par exemple, la mise à jour du logiciel du MA doit se faire de manière sécurisée. Imaginez des sondes dont le firmware serait mis à jour en HTTP (pas HTTPS avec vérification du certificat) : un méchant pourrait se glisser sur le trajet, leur envoyer du logiciel malveillant et se constituer ainsi un botnet. Par exemple, si les MA peuvent faire des mesures passives, un tel botnet pourrait servir à faire de la surveillance massive (RFC 7258).

De la même façon, le MA ne doit pas obéir aveuglément à toute machine qui prétend être le contrôleur : il doit l'authentifier, tester l'intégrité des requêtes du contrôleur et empêcher les rejeux, qui pourraient facilement être utilisés pour des attaques par déni de service. La communication entre MA et contrôleur doit également être chiffrée : elle peut révéler des choses à un attaquant. Idem pour la communication du MA avec le collecteur : elle doit être authentifiée (imaginez un faux MA envoyant des mesures mensongères pour fausser une étude comparée sur les différents FAI) et confidentielle (les MA peuvent faire des mesures privées). À noter que, lorsque le MA est situé chez un utilisateur, on ne peut jamais être totalement sûr de son intégrité : il a pu être ouvert et modifié par l'utilisateur. (C'est encore plus vrai pour un MA logiciel.)

LMAP est prévu pour des grands systèmes de mesure. En outre, des malveillants pourraient tenter des attaques par déni de service contre le système de mesure. Notre RFC précise donc également que le collecteur doit se protéger en limitant le nombre de MA qui se connectent à lui simultanément, en limitant le débit d'envoi des données, et la taille totale des données.

Reste la question de la vie privée (section 8), qui fut le gros sujet de discussion au sein du groupe de travail à l'IETF. La vie privée de qui ? Eh bien, on cherche à protéger aussi bien les utilisateurs, que les FAI et les régulateurs. En cas de mesures passives, l'information sur le trafic Internet des utilisateurs est certainement très sensible et on ne veut pas qu'elle soit diffusée partout. Tout MA qui observe le trafic va donc accéder à ces informations qui peuvent menacer la vie privée. (Le RFC note qu'IPFIX a le même problème, cf. section 11.8 du RFC 7011.) Ainsi, même si la sonde Sam Knows ne fait que des mesures actives, a priori moins sensibles, sa documentation recommande de brancher la sonde en coupure du réseau local, de manière à voir passer tout le trafic de l'utilisateur. C'est pour pouvoir ne déclencher les mesures actives que lorsque le trafic utilisateur est faible ou nul. Mais brancher un engin dont on n'a pas le source de manière à ce qu'il puisse voir tout le trafic est assez dérangeant. En outre, quelqu'un qui observerait les communications de la Sam Knows avec son contrôleur, même sans les comprendre, pourrait savoir quand l'utilisateur est en train d'utiliser son réseau : le MA n'a rien à communiquer dans ce cas (section 8.5.1 de notre RFC).

Même en l'absence de mesures passives du trafic, les MA peuvent avoir accès à des informations confidentielles : SSID du WiFi local, adresses MAC repérées lors des requêtes ARP, etc. Certaines informations sont rentrées explicitement par l'utilisateur et peuvent être sensibles : le contrôleur des sondes Atlas connait ainsi la longitude et latitude de la sonde donc la position de la maison (la précision est volontairement réduite lors de la saisie, précisément pour cette raison).

Quand aux données du FAI, qui peuvent être révélées indirectement via les systèmes de mesure, elles sont nombreuses : topologie exacte du réseau, trafic effectif dans les tuyaux, informations commerciales (type d'abonnements souscrits), etc.

Et le régulateur ? Oui, lui aussi a de la vie privée à défendre car il possède des infos confidentielles aussi bien sur les utilisateurs que sur les FAI, et n'a typiquement pas le droit de les diffuser.

Parmi les méchants qui seraient intéressés par cette information, on peut trouver les concurrents (le chiffrement est alors la protection minimale), l'organisation qui fait tourner les mesures (il est donc souhaitable de réduire la confiance qu'il faut lui faire, par exemple en mettant le MA derrière le port d'un commutateur, ce qui le rend difficilement capable de faire des mesures passives), ou bien sûr les organes de surveillance (RFC 6973, notamment section 5.1.1).

Outre le chiffrement des communications entre le MA et ses contrôleurs et collecteurs, solution déjà citée, il va être préférable de minimiser les données récoltées et transmises. Le chiffrement n'est pas une solution parfaite (notamment, il ne protège pas contre l'organisation qui fait fonctionner le collecteur), et il doit être complété par la minimisation, composante cruciale de tout projet de protection de la vie privée (RFC 6973, section 6.1, et notre RFC 7594, section 8.6.1). Les données doivent être agrégées, résumées, réduites à ce qui est strictement nécessaire pour la tâche en cours.

Les organisations qui collectent et traitent des grandes quantités de données essaient souvent de rassurer les utilisateurs en promettant que les données sont « anonymisées ». La section 8.6.2 de notre RFC rappelle que l'anonymisation est très difficile à faire correctement et que les techniques modernes d'analyse de données peuvent souvent dé-anonymiser et donc retrouver les individus dans la masse des données (cf. RFC 6235 et l'étude de Burkhart, M., Schatzmann, D., Trammell, B., et E. Boschi, « The Role of Network Trace anonymisation Under Attack » en 2010).

L'anonymat ne doit pas être réduit au simple pseudonymat, (section 6.1.2 du RFC 6973) où il y a un identificateur stable des activités, même s'il n'est pas relié à une identité du monde extérieur. Dans le vrai anonymat (très difficile à obtenir, malgré les promesses des commerciaux du big data), il n'y a pas de traçabilité.

D'ou la conclusion de cette section, qu'un accord explicite d'un utilisateur informé et conscient est nécessaire, si on fait des mesures chez lui. (Cela peut d'ailleurs être un argument pour des points de mesures créés spécialement pour la mesure, comme dans les tests ARCEP. Il n'y a alors pas de problème de vie privée.)


Téléchargez le RFC 7594


L'article seul

RFC 7593: The eduroam architecture for network roaming

Date de publication du RFC : Septembre 2015
Auteur(s) du RFC : K. Wierenga (Cisco Systems), S. Winter (RESTENA), T. Wolniewicz (Nicolaus Copernicus University)
Pour information
Première rédaction de cet article le 6 octobre 2015


Le service eduroam permet aux étudiants et employés des universités et centres de recherche européens de se connecter en Wi-Fi même quand ils ne sont pas dans leur université habituelle. Ce RFC décrit le fonctionnement d'eduroam et les choix effectués lors de sa conception (notamment l'absence de ces abominables portails captifs). La taille d'eduroam et ses années de fonctionnement indiquent que ces choix étaient bons et qu'eduroam peut être un modèle pour bien d'autres déploiements de Wi-Fi.

Le projet d'un accès pour le monde académique européen a démarré en 2002 (cf. la proposition initiale, par un des auteurs du RFC). Aujourd'hui, eduroam couvre 10 000 sites (dont un en Papouasie Nouvelle-Guinée) et des millions d'utilisateurs.

Les buts d'eduroam étaient (section 1 du RFC) :

  • Identification unique des utilisateurs, gérée par leur établissement d'origine. Si un chercheur de l'Université Copernic visite l'Université de Pise, pas question que les Italiens soient obligés de lui créer un compte, de lui attribuer encore un nouveau mot de passe, etc. (Point de terminologie au passage : dans ce scénario, l'université d'origine du visiteur est l'IdP - Identity Provider - et celle qu'il visite est le SP - Service Provider, qui fournit l'accès.)
  • Accès au réseau de l'établissement visité et par là à tout l'Internet. (Ce qui n'interdit pas de mettre les visiteurs dans un VLAN à part, ce qui se fait souvent.)
  • Minimum de procédures administratives. Il faut éviter, par exemple, que chacun des 10 000 établissements membres ait à faire quelque chose (signer un contrat, échanger des certificats) avec chacun des 9 999 autres. Cela ne passerait pas à l'échelle.
  • Facile à configurer et utiliser : tous les académiques ne sont pas des experts en informatique.
  • Sûr. Pas question que n'importe quel craqueur de passage puisse avoir un accès gratuit et irresponsable via une université.
  • Raisonnablement respectueux de la vie privée. Par exemple, le SP, l'établissement d'accueil, ne devrait pas être en mesure de tout savoir de ses visiteurs.
  • Évidemment fondé sur des normes ouvertes, de manière à ne pas imposer l'utilisation d'un vendeur particulier.

Avec un tel cahier des charges (section 1), plutôt ambitieux, les solutions qui avaient été envisagées et testées étaient :

  • Utilisation de VPN. Sûre mais ne passant pas du tout à l'échelle.
  • Portail captif. Sécurité bien trop mauvaise (et, je rajoute, très pénible pour les utilisateurs). Les portails captifs ont tous les défauts (cf. l'excellente FAQ d'eduroam) : reposant sur un détournement du trafic, ils sont indistinguables d'une attaque de l'Homme du Milieu et ils contribuent donc à mal éduquer les utilisateurs (par exemple à ignorer les avertissements HTTPS), reposant sur du trafic Wi-Fi en clair, ils permettent tout un tas d'attaques comme la surveillance des communications du voisin, nécessitant une action manuelle d'interaction avec un site Web, ils ne fonctionnent pas avec des programmes automatiques comme Windows Update, ils ne font pas d'authentification de bout en bout (il faut donner son mot de passe au SP), etc. (Note personnelle : il est anormal qu'ils existent encore en 2015.)
  • 802.1X, la solution finalement choisie.

Désormais, eduroam repose sur trois piliers :

  • 802.1X pour l'authentification locale, avec le point d'accès Wi-Fi,
  • EAP (RFC 3748) pour transporter l'authentification, de manière sûre et confidentielle,
  • RADIUS (RFC 2865), pour le routage des requêtes, jusqu'à l'établissement d'origine (l'IdP).

L'utilisation d'EAP dans RADIUS est décrite dans le RFC 3579.

L'architecture d'eduroam est décrite en section 2 de notre RFC. Qui dit authentification dit confiance : d'où vient la confiance dans eduroam ? Il y a une relation de confiance entre l'utilisateur et l'IdP, son établissement d'origine, vérifiée par une authentification mutuelle. Et il y a une relation de confiance entre l'IdP et le SP (l'établissement d'accueil), fondée sur RADIUS.

Si une université, ou établissement analogue, participe au service eduroam, ses bornes Wi-Fi vont publier le SSID eduroam. C'est celui que choisit l'utilisateur la première fois, la connexion sera typiquement faite automatiquement les fois suivantes. Notez qu'il est toujours possible qu'un point d'accès méchant diffuse un faux eduroam : l'utilisateur ne doit pas considérer que tout SSID eduroam est sûr ! Notez aussi, mais c'est moins grave, qu'un utilisateur qui est dans son université habituelle peut se connecter via eduroam, avec les éventuelles limitations que cela implique, plutôt qu'au réseau local de son université. Pour s'accrocher au point d'accès Wi-Fi du SP, la machine de l'utilisateur utilise, on l'a vu, 802.1X. Les transmissions radio sont sécurisées par WPA2 avec AES. Il n'y a pas d'accès anonyme à eduroam, tout utilisateur doit avoir un compte sur un des IdP.

Et EAP, il sert à quoi ? Il permet une protection de bout en bout des informations d'authentification. Même si l'utilisateur s'est connecté à un faux réseau prétendant être eduroam, celui-ci ne pourra pas intercepter, par exemple les mots de passe. Seul l'IdP, l'institution d'origine de l'utilisateur, verra son mot de passe. EAP n'est pas directement un mécanisme d'authentification mais un protocole qui permet de négocier et transporter plusieurs mécanismes d'authentification (du « simple » mot de passe - RFC 4746 - aux certificats - RFC 5216). EAP est de bout en bout, entre l'utilisateur et son IdP, son fournisseur d'identité. Si l'université de rattachement de l'utilisateur déploie une technique d'authentification nouvelle et très rare, pas de problème : les SP, et les serveurs RADIUS n'ont pas à la gérer, seul EAP sera au courant. L'utilisateur s'identifie avec un NAI (RFC 7542), comportant un nom local à l'IdP, un @ et un domaine (ou royaume, realm) unique. Pour des raisons de protection de la vie privée, on peut utiliser un NAI ne comportant que le domaine (par exemple @ma-fac.example), le NAI complet n'étant transporté que dans EAP (pensez à un tunnel), et donc chiffré et inaccessible aux intermédiaires.

Le point d'accès Wi-Fi va ensuite être un client RADIUS pour transmettre les informations permettant l'authentification. (Du point de vue sécurité, notez que cette communication entre le client RADIUS et le premier serveur RADIUS est entièrement chez le SP, et sécurisée par lui, typiquement via les secrets partagés de RADIUS.)

Une fois qu'on est arrivé au serveur RADIUS du SP, que se passe-t-il ? Il faut relayer jusqu'au serveur RADIUS de l'IdP. Les serveurs RADIUS de eduroam sont organisés de manière arborescente, en suivant à peu près l'arbre du DNS. Si un professeur à soton.ac.uk visite l'Université de l'Utah, sa requête va d'abord passer par le serveur RADIUS de cette université. Ce serveur de l'université utah.edu ne connait que le serveur RADIUS et edu. Il lui transmet donc la requête, le serveur de edu passe à la racine (notez que, contrairement au DNS, on ne part pas de la racine) et la requête redescend ensuite vers le serveur de l'IdP (serveurs de ac.uk puis de soton.ac.uk).

Donc, pour détailler le processus, les étapes étaient :

  • Le professeur (enfin, son logiciel, ce qui se nomme dans WPA le supplicant) envoie une requête EAP au point d'accès Wi-Fi de l'Utah, avec une identité anonymous@soton.ac.uk,
  • Le point d'accès états-unien fait suivre au serveur RADIUS de l'Université de l'Utah,
  • Ce serveur voit que la requête n'est pas pour lui (le domaine soton.ac.uk n'est pas le sien), il fait suivre au serveur RADIUS de .edu,
  • Ce serveur voit que ce n'est pas pour lui (ce n'est pas un .edu), il transmet donc à la racine (au passage, notez que la racine est évidemment composée de plusieurs serveurs, pour des raisons de redondance),
  • La racine peut donc transmettre au serveur RADIUS de ac.uk (notez que la racine est généralement configurée avec des TLD mais ac.uk est une exception),
  • Et ce serveur va transmettre à l'université, puisqu'il connait soton.ac.uk,
  • Le serveur RADIUS de l'université britannique va alors décapsuler, trouver la requête EAP et la traiter (c'est-à-dire authentifier l'utilisateur),
  • La réponse (message RADIUS Access-Accept ou Access-Reject) est renvoyée dans l'Utah en suivant la hiérarchie RADIUS d'eduroam en sens inverse,
  • Le serveur RADIUS de l'Université de l'Utah peut alors informer le point d'accès Wi-Fi qu'il doit laisser passer (ou pas) l'utilisateur.

On voit qu'il faut en faire bouger des électrons, et très vite et de manière très fiable. eduroam a logiquement connu quelques malheurs (section 3 du RFC). Par exemple, les serveurs RADIUS à utiliser pour router la requête sont statiquement configurés (une grosse différence avec le DNS). Le RFC 2865 ne dit pas ce qu'il faut faire en cas de panne. RADIUS fonctionne sur UDP et la panne n'est donc pas indiquée explicitement, on a juste une absence de réponse. Pour l'utilisateur final, cela peut se traduire par un long délai, suivi d'un refus d'accès inexplicable. En prime, comme il y a plusieurs relais RADIUS successifs, l'administrateur d'une université, en cas de non-réponse, ne sait pas quel relais a défailli. Son RADIUS ne peut pas distinguer une panne du premier relais d'une panne de la racine, sauf en constatant que les éventuelles requêtes pour des domaines du même TLD marchent. Un processus de débogage pénible (cf. l'article « Dead-realm marking feature for Radiator RADIUS servers »). Et il n'y avait pas non plus dans RADIUS de message de retour indiquant la fin de la panne (ce point a toutefois été résolu avec le RFC 5997).

RADIUS est nettement faiblard en terme de signalisation des erreurs mais le protocole 802.1X ne permet pas non plus de transmettre à l'utilisateur final un message très détaillé. Un serveur RADIUS qui dépend d'un serveur dorsal extérieur (LDAP ou SGBD par exemple) a donc un choix cornélien si ce serveur extérieur est défaillant : le serveur RADIUS peut ne pas répondre du tout, mais cela va être interprété comme une panne par les relais RADIUS, qui risquent de ne plus envoyer de requêtes. Et le logiciel de l'utilisateur ne va pas transmettre de message utile, voire il donnera des avis erronés (« vérifiez votre mot de passe »), en raison du manque d'informations. Soit, autre solution, le serveur RADIUS répond par un refus (RFC 2865, section 4.3), ce qui serait mieux pour les autres relais RADIUS (ils verront que leur camarade répond toujours) mais très déroutant pour l'utilisateur final, qui verra des messages trompeurs et effrayants, par exemple « votre mot de passe est incorrect ou votre compte est fermé ». Ainsi, Windows, dans un tel cas, efface les informations d'authentification qui étaient enregistrées et oblige l'utilisateur à tout recommencer. Ce problème a suscité de nombreux appels à l'assistance utilisateur, car les gens avaient évidemment oublié le mot de passe qu'ils avaient configuré des semaines ou des mois auparavant...

Les innombrables discussions dans la communauté eduroam ou dans le groupe de travail RADEXT de l'IETF n'ont pas permis d'arriver à un consensus. Si RADIUS sur TCP, introduit depuis, résout une partie des problèmes, il ne solutionne pas celui du dorsal (LDAP ou SGBP) planté. Il faudrait un mécanisme analogue au code d'erreur 500 de HTTP mais RADIUS n'en a pas.

Autre problème, la complexité du routage entre les relais RADIUS. Le faire sur la base du TLD marche bien pour les ccTLD (le serveur RADIUS national est administré par l'association eduroam du pays) mais pas du tout pour .com. Il a fallu mettre des exceptions manuelles comme kit.edu routé vers le serveur allemand car le KIT est en Allemagne, ce qui n'était pas évident vu son TLD... Cela pose un problème de passage à l'échelle : s'il n'y a qu'environ 200 ccTLD (dont 50 sont aujourd'hui dans eduroam), il peut y avoir potentiellement des milliers d'établissements dans les gTLD, chacun avec son exception à mettre dans les tables de routage, et à propager vers tous les serveurs (pour des raisons de fiabilité, il y a plusieurs serveurs racines).

Je l'ai dit, RADIUS fonctionne sur UDP. Ce choix était raisonnable dans les configurations simples du début (un client RADIUS, le point d'accès, et un serveur RADIUS, sans relais), mais il a des conséquences désagréables pour la configuration bien plus complexe d'eduroam. EAP est un protocole bavard et il n'est pas rare d'avoir 8 à 10 aller-retours entre le serveur RADIUS du SP et celui de l'IdP. La perte d'un seul paquet nécessitera de tout recommencer, UDP n'ayant pas de retransmission. Dans certains cas, les données EAP sont de taille importante (c'est surtout le cas avec EAP-TLS, où il faut transmettre de gros certificats) et on peut voir des paquets RADIUS dépasser la MTU et être fragmentés. Si, en théorie, la fragmentation n'est pas un problème, en pratique, on sait qu'elle marche mal sur l'Internet, notamment en raison des nombreux pare-feux bogués ou mal configurés. Ces problèmes sont très difficiles à déboguer car, si Alice et Bob constatent que les paquets entre eux ne passent pas, la cause peut être un réseau tiers, situé sur le chemin, et qu'ils ne contrôlent pas. (RADIUS sur TCP, RFC 6613, résout ce problème. Le RFC 6613 discute plus en détail ce problème.)

Autre limite de RADIUS tel qu'il était au début d'eduroam : la protection de la vie privée. Le protocole permettait de chiffrer les mots de passe mais pas le reste du trafic. C'est donc à EAP de contourner ce problème, par exemple avec son authentification TLS. Mais cela ne suffit pas car il y a toujours des attributs « privés » transmis en clair par RADIUS comme Calling-Station-ID qui peut permettre de trouver le terminal de l'utilisateur, ou comme NAS-IP-Address qui permet de trouver le point d'accès. (Le problème se pose aussi dans la réponse : si le message d'acceptation est trop bavard, par exemple en indiquant le département de l'utilisateur à l'université, cela laisse fuiter des informations en clair.) Cela permet donc à un attaquant puissant, en surveillant tous les flux RADIUS (ce qui est largement dans les moyens de la NSA), de suivre à la trace bien des gens. À noter que une telle récolte d'informations n'a pas encore été documentée (on ne trouve pas RADIUS ou eduroam dans les documents Snowden) mais cela ne veut pas dire qu'elle n'a pas eu lieu. La seule solution est de chiffrer toute la session RADIUS, ce qui n'était pas possible dans le RADIUS original (mais le devient avec le RFC 6614).

EAP protège également en permettant l'utilisation d'identificateurs « anonymes », le vrai identificateur n'étant transmis que dans la session EAP chiffrée. Encore faut-il que l'utilisateur configure son logiciel pour cela, et tous les logiciels ne le permettent pas.

Ces sécurités fournies par EAP ne marchent que si on se connecte au bon serveur EAP. Si on se connecte à la place au terrible Homme du Milieu, plus aucune sécurité ne joue. Est-ce que les utilisateurs ont tous configuré leur logiciel pour tester la validité du certificat du serveur EAP, et la tester contre une liste d'AC sérieuses ? On peut en douter et il est donc sans doute possible de capturer des sessions Wi-Fi en présentant un faux serveur EAP.

Ces problèmes de configuration d'EAP sont d'autant plus pénibles que beaucoup des mises en œuvres d'EAP ne permettent pas aux administrateurs système de diffuser facilement des configurations pré-remplies (et, lorsqu'il y en a, elles sont spécifiques à un vendeur), où tous les paramètres de sécurité ont été fixés aux bonnes valeurs, et où l'utilisateur n'a plus qu'à taper nom et mot de passe (ou bien indiquer le certificat client).

Les difficultés pratiques rencontrées avec l'architecture d'eduroam ont mené à certains changements, décrits dans la section 4 du RFC. Certains changements ont nécessité une action normalisatrice à l'IETF. Ces changements peuvent cohabiter avec l'infrastructure actuelle (pas question de tout raser pour recommencer de zéro) et sont donc déployés progressivement. Les deux grands changements sont le remplacement progressif d'UDP par TCP, et l'utilisation de TLS pour sécuriser la session RADIUS (l'ancien système était un secret partagé entre les deux pairs RADIUS).

Au passage, pourquoi ne pas avoir remplacé RADIUS par Diameter (RFC 6733) ? Cela avait été envisagé puisque, sur le papier, le protocole Diameter, bien plus complexe et « enterprise-grade » (c'est-à-dire apprécié des DSI, et n'ayant pas de mise en œuvre en logiciel libre), disposait déjà des services voulus. Mais l'examen de l'offre Diameter existante, par rapport aux exigences d'eduroam (logiciels gratuits ou bon marché, gestion des authentifications EAP les plus courantes, accès à des dorsaux courants comme MySQL, etc) a été décevante. En prime, les points d'accès Wi-Fi existants n'avaient pas de client Diameter (et n'en ont toujours pas).

D'où le choix de travailler à l'IETF pour développer les nouveaux services (RFC 6613, RFC 6614), et avec les développeurs de logiciel libre pour les mettre en œuvre.

Déployer TCP et TLS dans l'infrastructure de serveurs RADIUS a permis de détecter les serveurs en panne (avec les keepalive de TCP, cf. RFC 6613, section 2.6) et de protéger le contenu échangé contre les écoutes. Les certificats X.509 d'eduroam, qui servent à authentifier les pairs RADIUS, sont fournis par un ensemble d'AC accréditées.

TCP et TLS laissent un problème, celui du routage statique des requêtes, dans la hiérarchie des serveurs eduroam. La solution se nomme « découverte dynamique ». Il y a deux problèmes à résoudre : trouver le serveur RADIUS responsable d'un domaine donné, et s'assurer de son authenticité. Pour le premier problème, eduroam utilise des enregistrements S-NAPTR (RFC 3958) avec le service privé x-eduroam:radius.tls, donnant accès à des enregistrements SRV indiquant le serveur à contacter. Par exemple, un cas réel chez RESTENA :

%  dig NAPTR restena.lu
...
restena.lu.  21600 IN NAPTR 100 10 "s" "x-eduroam:radius.tls" "" _radsec._tcp.eduroam.lu.
...

% dig SRV _radsec._tcp.eduroam.lu
...
_radsec._tcp.eduroam.lu. 43198 IN SRV 0 0 2083 tld1.eduroam.lu.
_radsec._tcp.eduroam.lu. 43198 IN SRV 10 0 2083 tld2.eduroam.lu.
    

Ces deux enregistrements nous disent que le domaine restena.lu a un serveur RADIUS joignable via le nom _radsec._tcp.eduroam.lu et que ce nom correspond à deux serveurs, tld1.eduroam.lu et tld2.eduroam.lu, tous les deux opérant sur le port 2083. (Ce système est décrit dans le RFC 7585.) Le RFC note aussi que le nouveau système de découverte dynamique rendra le système plus souple mais peut-être aussi plus fragile, par suite de la complexité ajoutée.

Le second problème est la vérification de l'authenticité d'un serveur. Après tout, n'importe qui peut mettre des enregistrements NAPTR et SRV dans son domaine et prétendre avoir un serveur RADIUS d'eduroam. La solution a été de réutiliser les AC qui émettent les certificats nécessaires pour RADIUS-sur-TLS. Le serveur RADIUS doit donc vérifier que le pair en face :

  • A un certificat émis par une des AC de la PKI d'eduroam (comme eduPKI, le nom dans le certificat étant alors /DC=org/DC=edupki/CN=eduPKI),
  • Que ce certificat contient un OID désignant la politique eduroam eduroam (cf. « Delivery of Advanced Network Technology to Europe, "eduPKI" »). Par exemple, aujourd'hui, un openssl s_client -connect $RADIUS_SERVER:$RADIUS_PORT |openssl x509 -text sur le serveur RADIUS doit montrer « Policy: 1.3.6.1.4.1.27262.1.13.1.1.1.3 » (je trouve des serveurs qui ont plutôt une vieille version de la politique, comme 1.3.6.1.4.1.27262.1.13.1.1.1.0).

Une dizaine de pays et une centaine de domaines utilisent ce nouveau système de découverte dynamique. Les principaux problèmes sont les problèmes classiques de X.509, gestion des CRL, par exemple.

Le progrès ne va évidemment pas s'arrêter là. eduroam considère aussi deux alternatives :

  • DANE (RFC 6698), qui a le gros avantage de permettre de se dispenser complètement de la PKI, en mettant les certificats dans le DNS. La principale limite de DANE, pour le cas d'eduroam, est que DANE permet au client d'authentifier le serveur mais pas (encore) le contraire, alors qu'eduroam a besoin de deux.
  • ABFAB (décrit dans l'Internet-Draft draft-ietf-abfab-arch), prometteur mais encore loin d'être complètement spécifié.

Vu le très grand nombre d'utilisateurs d'eduroam, il ne faut pas s'étonner qu'il y ait des incidents, des abus, etc. La section 5 du RFC décrit les mécanismes techniques permettant de gérer ces contrariétés. D'abord, la comptabilité : dans eduroam, c'est une affaire à gérer localement dans le SP (l'université d'accueil). L'IdP (l'université d'origine) n'est pas informée (cf. le « eduroam Compliance Statement »). Mesurer l'activité d'un utilisateur est un pré-requis pour la lutte contre certains abus. D'un autre côté, le SP ne voit pas forcément l'identité du visiteur, juste son domaine (si le visiteur a configuré les identificateurs « anonymes ») ce qui rend difficile la comptabilité. Le RFC 4372 fournit un mécanisme de comptabilité par utilisateur, chargeable user identity (qui envoie un pseudonyme, pas le « vrai » nom), mais il est très peu implémenté.

En dix ans de fonctionnement, eduroam n'a pas eu d'incident de sécurité sérieux. Cela peut indiquer que l'architecture de sécurité est bonne : il n'y a pas d'accès anonyme, chaque utilisateur est identifié, ce qui peut expliquer leur retenue. Le RFC note que cela veut peut-être dire plutôt que les réseaux utilisés par eduroam ne sont pas assez supervisés et que certains abus passent peut-être inaperçus.

Quoiqu'il en soit, la partie politique de la sécurité est traitée dans « eduroam Policy Service Definition », notre RFC ne décrivant que les moyens techniques. D'abord, le SP est évidemment libre de bloquer un utilisateur qui abuse. Comment ? Si l'utilisateur a activé les identifiants « anonymes », le SP ne possède que le nom de domaine et l'adresse MAC (sauf coopération avec l'IdP, forcément lente et complexe et donc pas utilisable en urgence). Le SP peut donc, si ses équipements le permettent, bloquer la requête EAP sur la base de ces deux éléments. Mais changer l'adresse MAC est trop facile, et un attaquant déterminé peut donc contourner cette protection. Autre solution, le SP peut attendre la réponse du serveur RADIUS de l'IdP et regarder si elle contient l'attribut Chargeable-User-Identity du RFC 4372, qui contient un identifiant unique de l'utilisateur (unique par SP : le SP envoie son Operator-NameRFC 5580, et l'IdP calcule un identifiant qui dépend du SP, pour les raisons décrites en section 6.1). C'est la meilleure solution car le SP peut alors bloquer cet utilisateur, et uniquement lui, soit en ne répondant pas à ses requêtes, soit en fabriquant des Access-Reject RADIUS. S'il n'y a pas de Chargeable-User-Identity dans la réponse ? La seule solution restant, et elle est violente, est de bloquer le domaine entier, ce qui aura l'effet de bord de bloquer les visiteurs qui ont le malheur d'avoir un compte au même endroit que l'abuseur.

Et bloquer au niveau de l'IdP, alors ? Lui peut facilement fermer un compte, empêchant ainsi l'utilisateur d'accèder à tout site eduroam. Si le SP envoie son nom dans la requête (avec l'attribut RADIUS Operator-Name du RFC 5580), on peut même ne bloquer un compte que pour certains SP, par exemple ceux qui se sont plaints de cet utilisateur. Cela permet des politiques plus fines. Par exemple, imaginons un SP qui interdise le partage d'œuvres culturelles. Un visiteur utilise BitTorrent et le SP demande à l'IdP de le bloquer, alors même que l'utilisation de BitTorrent n'est pas interdite sur le réseau de l'IdP. Bloquer l'utilisateur seulement s'il est sur le réseau du SP râleur permet de satisfaire les politiques du SP et de l'IdP. Sans cette finesse, que permet l'attribut Operator-Name, l'IdP risquerait de bloquer complètement un utilisateur, qui n'était peut-être même pas au courant des politiques restrictives du SP.

Passons maintenant à la protection de la vie privée, un des gros morceaux d'eduroam (section 6 du RFC). Si eduroam avait été conçu par Cazeneuve ou Facebook, tout aurait été enregistré tout le temps mais eduroam a au contraire été prévu avec des fortes préoccupations de vie privée. D'abord, on l'a vu, la possibilité de NAI « anonymes » n'indiquant que le domaine (outer identities). Ce système empêche, par exemple, deux SP de déterminer si deux visiteurs de leurs campus, ayant le même IdP, sont une seule et même personne. Excellent pour la vie privée, mais cela rend compliqué l'attribution d'une éventuelle mauvaise action. D'où l'ajout de l'attribut Chargeable-User-Identity dans eduroam. Étant calculé par l'IdP et différent pour chaque SP, il empêche les collusions de SP entre eux, mais permet de remonter les traces d'un éventuel abuseur.

À noter que le domaine, lui, est visible du SP, des différents serveurs RADIUS qui relaient (ils en ont besoin pour le routage) et, si on n'utilise pas TLS, de tous les indiscrets sur le trajet. Si l'IdP est une très grosse université, cela peut frustrer l'observateur mais, dans le cas de petits établissements, cela peut l'aider. Il serait difficile de résoudre ce problème sans refaire tout eduroam.

Par défaut, l'IdP ne sait pas où se trouvent ses utilisateurs, puisque son serveur RADIUS ne voit que les requêtes du serveur RADIUS supérieur (typiquement, celui du pays). Cet enchaînement de serveurs RADIUS, peut sembler lourd, et difficile à déboguer (le point discuté en section 3). Mais il est avantageux, question vie privée.

Par contre, cette protection de l'utilisateur contre son propre IdP peut être affaiblie si on utilise la découverte dynamique (l'IdP voit les requêtes DNS, cf. RFC 7626), et évidemment si le SP envoie son nom dans la requête RADIUS (attribut Operator-Name).

Et la sécurité, à part cette question de vie privée ? Il faut bien sûr relire les sections Sécurité des normes RADIUS, EAP et 802.1X, plus la section 7 de notre RFC, qui discute les problèmes plus spécifiques à eduroam. D'abord, la sécurité de bout en bout repose complètement sur EAP. Si un Homme du Milieu réussit à se faire passer pour le serveur EAP de l'IdP, il a table ouverte. Le client EAP doit donc exiger une authentification du serveur, et le serveur doit faire ce qu'il faut pour être authentifié (par exemple, publier le nom qui doit apparaitre dans le certificat).

En théorie, cette authentification du serveur résout complètement le problème. En pratique, il reste des pièges. Par exemple, certains clients EAP ne permettent de vérifier que l'AC, pas le nom (le sujet du certificat). Tout attaquant qui peut obtenir un certificat quelconque de la même AC peut donc se faire passer pour le serveur EAP. Il vaut donc mieux ne se fier qu'à des AC spécifiques à eduroam. D'autres clients EAP pratiquent le TOFU : ils se fient au premier certificat et le mémorisent pour la suite. Si un utilisateur était chez un point d'accès pirate la première fois, c'est le certificat de l'attaquant qui sera cru. Les utilisateurs doivent donc veiller à configurer leurs clients eduroam proprement (un outil existe pour cela). Pire, certains logiciels permettent à l'utilisateur de complètement sauter la vérification (« No CA certificate is required » sur NetworkManager, par exemple). L'utilisateur qui sélectionnerait cette option pour se faciliter la vie se rendrait très vulnérable aux attaques de l'Homme du Milieu. Dernier piège d'authentification : en utilisant les identités « anonymes » (NAI ne comportant que le nom du domaine), rien n'empêche un utilisateur malveillant de placer dans la session EAP un NAI indiquant un autre domaine. Si le serveur RADIUS de l'IdP indiqué dans le NAI « anonyme » accepte de relayer les requêtes, l'utilisateur pourra se faire authentifier, et le SP ne connaitra alors pas le vrai domaine d'origine. Cela diminue sérieusement la responsabilité de l'utilisateur et lui permet de brouiller ses traces. Voilà pourquoi les serveurs RADIUS d'eduroam ne doivent pas relayer ces requêtes.

Comme tout service sur l'Internet, eduroam est évidemment susceptible de recevoir des attaques par déni de service. Sur les points d'accès Wi-Fi, on peut voir des serveurs DHCP pirates (cf. RFC 7610), des émetteurs de RAcailles (cf. RFC 6105), etc. eduroam est moins vulnérable que le point d'accès Wi-Fi typique avec portail captif, car l'authentification préalable est nécessaire (ce qui limite les attaques par un client tentant d'épuiser la réserve d'adresses IP en faisant des requêtes DHCP répétées) et le Wi-Fi est chiffré (par WPA2), ce qui limite l'usurpation ARP.

Certaines attaques par déni de service spécifiques à eduroam existent. Par exemple, un attaquant situé physiquement à portée d'un point d'accès Wi-Fi eduroam peut envoyer de manière répétée des demandes d'accès en indiquant un domaine situé dans un TLD différent : cela obligera plusieurs serveurs RADIUS, y compris ceux de la racine, à traiter sa demande, et une négociation EAP à se lancer. Heureusement pour eduroam, EAP est synchrone, donc un attaquant donné ne peut lancer qu'une requête à la fois, pour un domaine donné. eduroam reçoit aujourd'hui des centaines de milliers de requêtes d'authentification réussies par jour (et bien plus qui échouent) et un attaquant qui voudrait tuer eduroam avec un afflux de requêtes devrait donc y consacrer de gros moyens. En tout cas, de telles attaques n'ont pas encore été vues.

À noter qu'il existe aussi des attaques involontaires. La plupart des demandes d'authentification qui échouent concernent des comptes qui étaient valides mais ne le sont plus (étudiant qui a terminé ses études, par exemple). Il est donc probable que les gens dont les comptes sont expirés aient oublié de déconfigurer leur logiciel et que celui-ci envoie toujours des demandes dès qu'il passe près d'un point d'accès eduroam. Il y a donc un « botnet de fait » composé de toutes ces machines d'ex-utilisateurs. Le changement de machine par l'utilisateur, lorsque l'ancienne est trop vieille, ne résout pas le problème : aujourd'hui, surtout sur les ordiphones, les données d'authentification sont sauvegardées dans le cloud (pour que Google et la NSA y aient plus facilement accès) et sont remises sur le nouveau jouet lorsque l'ancien est remplacé. Le botnet des anciens d'eduroam ne fait donc que grossir. Il n'y a pas encore de solution propre à ce problème, peut-être améliorer les logiciels client pour qu'ils arrêtent d'envoyer automatiquement des requêtes après N échecs sur une période de X jours.

Un point sur lequel le RFC passe assez rapidement est le problème d'interopérabilité qui peut se poser quand deux auteurs de logiciel n'ont pas compris de la même façon ces normes complexes qu'il faut programmer correctement. Un exemple d'alerte est « RADIUS Attribute Issues regarding RFC5580 (Operator-Name and others) with several RADIUS servers (including Microsoft IAS and NPS) », un amusant problème de normalisation avec le RFC 5580, RFC qui a été souvent cité précédemment.

Si vous êtes intéressé par ce système, je vous recommande la lecture du site Web d'eduroam.


Téléchargez le RFC 7593


L'article seul

RFC 7590: Use of Transport Layer Security (TLS) in the Extensible Messaging and Presence Protocol (XMPP)

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : P. Saint-Andre (&yet), T. Alkemade
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF uta
Première rédaction de cet article le 25 juin 2015


Le groupe de travail UTA de l'IETF produit des recommandations pour un usage correct de TLS par les applications. En effet, indépendamment des forces et faiblesses propres de TLS, plusieurs problèmes de sécurité sont survenues en raison d'une mauvaise utilisation. Ce nouveau RFC traite le cas spécifique de l'utilisation de TLS par le protocole XMPP.

Les problèmes généraux identifiés par le groupe UTA avaient été documentés dans le RFC 7457 et les solutions généralistes, applicables à toutes les applications, dans le RFC 7525. Et pour le protocole XMPP, normalisé dans le RFC 6120 ? XMPP utilise TLS depuis au moins 1999. Les sections 5, 9 et 13 du RFC 6120 expliquent déjà comment faire du TLS avec XMPP. Mais notre nouveau RFC va plus loin et, dans l'esprit du manifeste XMPP/TLS , décide que XMPP doit suivre les recommandations plus strictes du RFC 7525, notamment concernant le choix des algorithmes de chiffrement.

La section 3 du RFC répète les recommandations du RFC 7525, que doivent désormais suivre les mises en œuvre de XMPP, notamment :

  • Toute mise en œuvre de XMPP doit avoir l'option <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> qui indique qu'elle est prête à démarrer TLS (RFC 6120, section 5.4.1 et quelques autres). Mais, comme cette option n'est pas elle-même protégée par TLS, elle peut être supprimée par un homme du milieu (attaque dite de stripping, RFC 7457, section 2.1). XMPP doit donc tenter de faire du TLS avec son partenaire, que cette option soit présente ou pas (le manifeste cité plus haut impose TLS, de toute façon).
  • La compression TLS étant désormais rejetée (RFC 7525, section 3.3), XMPP peut se rabattre sur la compression XMPP du XEP-0138.
  • XMPP a un mécanisme de reprise rapide des sessions (XEP-0198), on peut encore l'améliorer en le couplant avec la reprise de sessions de TLS.
  • En théorie (RFC 6125), un client XMPP devrait authentifier le serveur (et, de préférence, le serveur authentifier les autres serveurs). En pratique, ce n'est pas toujours le cas (avec Pidgin, un certificat à problèmes est signalé mais un seul clic suffit à l'accepter). Une des raisons pour lesquelles on ne peut pas imposer immédiatement une authentification généralisée est que les serveurs XMPP sont souvent hébergés dans un environnement multi-clients, chaque client hébergé ayant son propre nom de domaine et qu'un tel serveur devrait donc avoir un certificat pour chaque client, ou un certificat couvrant tous les clients. DANE résoudra peut-être le problème. En attendant, le RFC recommande fortement de préférer une connexion chiffrée et non authentifiée à une connexion en clair (se replier sur du trafic en clair parce que le certificat est invalide est absurde, mais courant). C'est par exemple ce que recommande le RFC 5386 pour le cas d'IPsec. Bref, « TLS tout le temps, authentification si possible » est le principe.
  • SNI (Server Name Indication, RFC 6066, section 3) est inutile en XMPP, l'attribut to suffit à indiquer le domaine concerné (l'attribut to envoyé avant TLS n'indique que le domaine, pas le destinataire).
  • En sécurité, il est bien connu que le point faible est l'utilisateur humain. La section 3.6 fait donc des recommandations pour les développeurs d'interface utilisateur : indiquer si la connexion avec le serveur est chiffrée par TLS, indiquer si l'authentification a réussi et, si oui, comment, permettre d'afficher l'algorithme de chiffrement utilisé et le certificat présenté, être averti si un certificat change (ce qu'on nomme parfois l'épinglage - pinning). Je viens de tester avec un Pidgin 2.10.10 et la seule de ces recommandations qui semble mise en œuvre est la possibilité d'afficher les certificats (menu Tools -> Certificates).

La section 5 rappelle que XMPP sur TLS chiffre aussi les informations de routage (contrairement à SMTP) et limite donc les fuites de métadonnées. Elle revient aussi sur quelques limites de TLS : XMPP passe par plusieurs serveurs et, si ceux-ci sont piratés ou indiscrets, le chiffrement TLS, qui n'est pas de bout en bout, ne protège pas contre ceux qui ont le contrôle des serveurs. En termes moins gentils, si vous utilisez Google Talk, le chiffrement TLS avec Google Talk (qui marche bien) ne vous protège pas de PRISM. (À noter que notre RFC ne cite pas la solution de bout-en-bout OTR, qui existe mais est mal intégrée à XMPP.)

Je n'ai pas trouvé de liste de toutes les implémentations XMPP, avec leur degré de conformité à ce RFC.


Téléchargez le RFC 7590


L'article seul

RFC 7586: Scaling the Address Resolution Protocol for Large Data Centers (SARP)

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : Youval Nachum (Ixia), Linda Dunbar (Huawei), Ilan Yerushalmi, Tal Mizrahi (Marvell)
Expérimental
Première rédaction de cet article le 28 juin 2015


Le problème de passage à l'échelle de protocoles de recherche d'adresse MAC des voisins, les protocoles comme ARP, sont connus depuis un certain temps, et documentés dans le RFC 6820. Résumé en deux mots, dans un grand centre de données non partitionné en sous-réseaux IP, le trafic ARP peut représenter une partie significative du travail à effectuer par les machines. Ce nouveau RFC expose une des solutions pour faire face à ce problème : SARP (Scaling the Address Resolution Protocol) fait appel à des relais ARP qui peuvent générer localement la plupart des réponses.

Si le centre de données est rigoureusement découpé en sous-réseaux IP (par exemple un sous-réseau, et donc un routeur par baie), il n'y a pas de problème ARP : le trafic ARP reste local. Mais si on veut profiter de la souplesse que permet la virtualisation, par exemple en déplaçant des machines virtuelles d'un bout à l'autre du centre de données en gardant leur adresse IP, on doit alors propager les requêtes ARP sur une bien plus grande distance et les problèmes de passage à l'échelle apparaissent (RFC 6820). La mémoire consommée par la FDB (Filtering Data Base, la table des adresses MAC connues) augmente, ainsi que le temps de traitement de tous ces paquets ARP diffusés.

Les premières versions des brouillons ayant mené à ce RFC ne mentionnaient qu'ARP (RFC 826), protocole de résolution IP->MAC pour IPv4. Mais la version finale considère que le protocole marche aussi bien pour ND (RFC 4861), son équivalent pour IPv6. Seul le nom de la solution garde trace de cette préférence pour ARP. Dans le reste de cet article, je parlerais de ARP/ND.

L'idée de base de SARP est que chaque domaine d'accès (un groupe de machines proches, par exemple dans la même baie ou dans la même rangée) ait un relais (SARP proxy) qui connaisse les adresses MAC de tout le domaine, et réponde aux requêtes ARP/ND pour les autres domaines avec sa propre adresse MAC. Ainsi, la taille de la table ARP des machines du domaine reste proportionnelle à la taille du domaine d'accès, pas au nombre total de machines (comme ce serait le cas avec un réseau « plat » classique, entièrement en couche 2, et sans SARP).

Le relais SARP peut être l'hyperviseur d'un groupe de machines virtuelles (commutateur virtuel) ou bien il peut être dans un commutateur physique, ToR (Top of Rack) ou bien EoR (End of Row). En gros, le relais SARP est là où un domaine d'accès se connecte au cœur du réseau interne du centre de données. Ce doit être une grosse machine car elle va devoir stocker les adresses MAC de toutes les machines qui communiquent avec une machine d'un autre domaine d'accès. Et il peut aussi faire l'objet d'attaques délibérées (cf. section 4).

La section 3 de notre RFC décrit plus en détail le fonctionnement de SARP. Si la machine source et la destination sont dans le même domaine d'accès (même baie, ou même rangée, selon l'endroit où se trouve le commutateur), ARP/ND fonctionne comme d'habitude et SARP n'intervient pas. Si la machine de destination est dans un autre sous-réseau IP, on passe alors par le routeur, selon le mécanisme normal de la couche 3. Mais si la destination est dans le même sous-réseau IP, mais dans un domaine d'accès différent ? Le relais SARP voit alors passer la requête ARP/ND. Si la réponse est dans son cache (qui associe des adresses IP à des adresses MAC), il répond avec sa propre adresse MAC (ainsi, les machines du domaine d'accès local ne sont pas noyées par des milliers d'adresses MAC de tout le centre de données). Sinon, il transmet à tous les domaines d'accès qui peuvent avoir cette adresse IP puis relaie la réponse. Seuls les relais SARP ont un cache qui contient des adresses MAC de tout le centre de données. Les machines ordinaires n'ont que les adresses MAC de leur propre domaine d'accès.

Et pour transmettre un paquet de données ? La machine source, ayant reçu l'adresse MAC du relais SARP en réponse à sa requête ARP/ND va donc mettre sur le câble un paquet ayant pour adresse Ethernet de destination le relais SARP. Le relais SARP, utilisant son propre cache (qui, lui, est complet), remplace l'adresse MAC de destination par la « vraie », et l'adresse MAC source par la sienne (pour qu'une réponse puisse revenir), et remet le paquet sur le câble.

Un tel mécanisme fait que des opérations comme la migration d'une VM d'un bout à l'autre du centre de données sont complètement invisibles. Les mécanismes normaux de résolution feront tout le travail. Cela suppose toutefois que la machine qui se déplace (ou plutôt son hyperviseur qui, contrairement à la VM, est conscient du déplacement) émette tout de suite un paquet ARP gratuit ou un paquet ND non sollicité, pour que les caches soient mis à jour (autrement, la machine migrée restera injoignable le temps que l'entrée dans le cache expire).

Une conséquence de cette technique est que le relais SARP est absolument vital : s'il est en panne, plus rien ne marche, à part les communications locales à un domaine d'accès. Il vaut donc mieux en avoir plusieurs, pour chaque domaine d'accès.

Ce RFC n'a que le statut « Expérimental » car l'IESG n'est pas convaincue que ce soit la seule méthode. Le RFC 7342 liste un certain nombre d'autres techniques (pas forcément directement comparables à SARP). À noter que les approches de type overlay (RFC 7364) résolvent une partie du problème mais pas la question de la taille de la table des adresses MAC. Mais il y a les RFC 4664, RFC 925, RFC 4389 (ces deux derniers sont, à mon avis, proches de SARP), RFC 4541 et RFC 6575...


Téléchargez le RFC 7586


L'article seul

RFC 7583: DNSSEC Key Rollover Timing Considerations

Date de publication du RFC : Octobre 2015
Auteur(s) du RFC : S. Morris (ISC), J. Ihren (Netnod), J. Dickinson (Sinodun), W. Mekking (NLnet Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 22 octobre 2015


Contrairement au DNS classique, le système de sécurité DNSSEC est très dynamique : il faut changer les signatures régulièrement et il est souvent recommandé de remplacer (changer) les clés. Compte-tenu du fait que le DNS n'est pas synchrone (les changements n'apparaissent pas instantanément partout dans l'Internet), ce changement, ce remplacement (rollover, dans la langue d'Alan Turing) est une opération délicate et qui nécessite le strict respect d'un certain nombre de durées. Ce RFC donne des conseils sur la temporalité des opérations DNSSEC.

Pourquoi faut-il changer les clés cryptographiques utilisées ? Il y a plusieurs écoles à ce sujet. Les minimalistes considèrent qu'on ne change les clés que quand c'est nécessaire, par exemple pour passer à des clés plus longues et donc moins vulnérables à la cryptanalyse, ou évidemment quand les clés privées ont été copiées par un méchant. Les maximalistes estiment qu'il faut changer de clé régulièrement, pour être mieux préparé en cas de changement d'urgence, ou pour priver un méchant discret qui aurait réussi à copier une clé privée sans qu'on s'en aperçoive du fruit de son forfait, ou tout simplement parce que l'utilisation d'une clé fournit du matériau, qui peut être utile à un éventuel cryptanalyste. Changer de clé est une opération délicate et, à mon avis, devrait être automatisé : autrement, le risque d'erreur est trop important, comme l'avait montré mon article à la conférence SATIN.

En effet, les facteurs qui rendent l'opération compliquée sont :

  • Les enregistrements DNSSEC, comme les clés (DNSKEY), les signatures (RRSIG) et les pointeurs vers les clés (DS) ne sont pas seulement dans les serveurs faisant autorité mais sont également mémorisés (« cachés ») dans les résolveurs. Si le TTL d'un DNSKEY est de 24 h, il faudra continuer, pendant une journée entière, à permettre la validation avec l'ancienne clé.
  • Il n'y a pas que le remplacement des clés dans les zones déjà signées, il y a aussi la première introduction de la signature dans les zones existantes.
  • Tous les remplacements de clés ne vont pas se faire de manière planifiée : il risque d'y avoir des remplacements d'urgence et ils peuvent nécessiter une préparation spécifique, avec des clés de secours pré-publiées, par exemple.
  • Tout serait plus simple si on pouvait publier toutes les clés possibles, y compris celles non utilisées depuis longtemps. Mais les requêtes DNS pour des enregistrements DNSKEY renvoient toutes les clés et cela peut dépasser la taille qu'on accepte pour des réponses DNS (typiquement 1480 ou bien 4096 octets). Il faut donc supprimer les anciennes clés, et cela ne doit pas se faire trop tôt : il faut être sûr que plus aucun résolveur n'ait ces clés dans son cache.

Une description de ce processus de remplacement de clés (key rollover) figure dans le RFC 6781. Un exemple avec OpenDNSSEC est raconté dans un de mes articles. Notre nouveau RFC détaille la description du RFC 6781, notamment sur les aspects temporels. Deux points à garder en tête avant de le lire :

  • Il est très courant d'avoir deux types de clés, les KSK (Key-Signing Key) qui servent à signer les clés, et qui sont pointées depuis la zone parente, et les ZSK (Zone-Signing Key) qui signent tout le reste. Comme la KSK, elle, est pointée depuis une zone gérée par une organisation différente (la zone parente), elle pose des problèmes particuliers et les deux types de clés sont donc traités séparement dans ce RFC. Le cas moins courant où on n'utilise qu'un seul type de clé n'est pas couvert.
  • Le RFC ne traite pas le cas (très délicat et surtout très peu testé dans le monde réel) des remplacements d'algorithmes (comme le passage de clés RSA à des clés ECDSA, cf. RFC 6605). On trouvera sans doute bien des bogues quand on essaiera cela en vrai ! (Cf. section 5)

Rappelez-vous en outre qu'une requête DNS d'un type donné (par exemple, A, NS, DNSKEY) récupère toujours tous les enregistrements de ce type. Si l'ensemble des enregistrements (RRset pour Resource Record Set) a changé entre temps, mais qu'un ensemble plus ancien est dans le cache, il y restera jusqu'à l'expiration du TTL.

Après ces rappels, les méthodes pour faire un remplacement de clé (section 2 de notre RFC). D'abord, les ZSK (Zone-Signing Keys). Il faut que tout résolveur validant qui a accès à une signature ait également accès à la ZSK correspondante, et ce à tout moment, que l'information soit dans le cache ou pas. Pas question donc de se contenter de publier la nouvelle ZSK et de l'utiliser immédiatement pour signer (les résolveurs ayant l'ancien enregistrement DNSKEY dans leur cache ne pourraient pas valider les nouvelles signatures, et idem si c'est la signature qui est dans le cache mais pas la clé). Il y a trois techniques pour un remplacement qui marche :

  • La pré-publication, décrite dans le RFC 6781. On met la nouvelle ZSK dans l'enregistrement DNSKEY (en laissant les anciennes), et on attend le TTL du DNSKEY, pour être sûr que tous les caches qui ont le DNSKEY ont le nouveau. On peut alors signer avec la nouvelle clé. Puis on attend le TTL des RRSIG, et on est alors certain qu'il ne reste plus de signatures faites avec l'ancienne clé dans les caches. On peut alors supprimer l'ancienne clé du DNSKEY. C'est la technique utilisée par OpenDNSSEC. zsk-prepub
  • La double-signature (un nom pas très rigoureux, car cette technique repose aussi sur une double clé, pas uniquement une double signature), également dans le RFC 6781. On introduit la nouvelle clé dans le DNSKEY et on l'utilise tout de suite pour faire des signatures mais en gardant les anciennes signatures (d'où le nom de double-signature). Une fois le maximum des TTL de DNSKEY et de RRSIG passé, on peut retirer l'ancienne clé et les anciennes signatures. zsk-doublesig
  • La double-RRSIG qui est une vraie « double signature ». On signe avec la nouvelle clé (en gardant les anciennes signatures) mais sans la publier. Une fois le TTL de RRSIG expiré, on change la ZSK. Puis, une fois le TTL de DNSKEY passé, on peut retirer les anciennes signatures.

La double-signature est probablement la plus facile à comprendre : à tout moment, durant la transition, on aura à la fois l'ancienne et la nouvelle clé, les anciennes et les nouvelles signatures. Elle n'a que deux étapes (introduire la nouvelle clé et les nouvelles signatures, puis retirer l'ancienne clé et les anciennes signatures). Son principal inconvénient est d'augmenter la taille des réponses puisqu'il faut transmettre deux fois plus de signatures. La pré-publication est plus compliquée (trois étapes) mais maintient la taille des réponses au minimum nécessaire. Notez que « plus compliqué » est surtout un problème si vous voulez tout comprendre, ou bien si vous êtes le programmeur qui va devoir automatiser l'opération. Mais, si vous utilisez un logiciel déjà fait, comme OpenDNSSEC, vous ne verrez pas cette complexité. La double-RRSIG a les inconvénients des deux autres techniques sans leurs avantages. C'est pour cela qu'elle ne figure pas dans le RFC 6781 et qu'elle n'est pas davantage mentionnée ici.

Et pour un remplacement de KSK ? Le problème est plus simple car la KSK n'est utilisée que pour signer le DNSKEY et clé et signatures voyagent donc ensemble (mais n'ont pas forcément le même TTL, ce que le RFC oublie de dire, donc l'une peut expirer du cache avant l'autre). Mais il est aussi plus compliqué car la KSK est pointée par un lien de confiance (trust anchor), typiquement un enregistrement DS dans la zone parente. Il faut donc coordonner le remplacement de KSK avec celui de ces liens. Et, comme le sait tout administrateur réseau, tout est plus compliqué quand on doit se coordonner avec le monde extérieur. Contrairement au remplacement d'une ZSK, où tout peut être automatisé car le passage d'une phase à l'autre ne dépend que de l'écoulement du temps, le remplacement d'une KSK nécessite une observation manuelle du parent, dont le délai de réaction est imprévisible.

Si le lien de confiance est un enregistrement DS (cas le plus fréquent), il faudra une interaction avec le gestionnaire de la zone parente. Si ce lien a été configuré manuellement (c'est rare, sauf pour la zone racine, qui n'a pas de parente), il faudra faire le changement dans tous les résolveurs qui ont configuré ce lien (une tâche difficile), ou bien utiliser le RFC 5011 (cf. section 3.3.4). C'est en raison des incertitudes à ce sujet qu'il n'y a jamais eu de remplacement de la KSK de la racine.

Comme pour le changement de ZSK, il y a trois techniques :

  • La double-KSK. On met la nouvelle KSK dans l'ensemble DNSKEY. On attend le TTL de la DNSKEY (on est alors sûr que les caches contiennent la nouvelle clé). On change le DS. Une fois celui-ci changé par le parent, on attend le TTL du DS, puis on supprime l'ancienne KSK. C'est la technique utilisée par OpenDNSSEC. ksk-doubleksk
  • Le double-DS. On publie un DS pour la nouvelle KSK. Après que le TTL du DS se soit écoulé, on change la clé. Après que le TTL de la DNSKEY se soit écoulé, on supprime l'ancien DS. ksk-doubleds
  • Le double-RRset. On publie la nouvelle clé, on signe le DNSKEY avec l'ancienne et la nouvelle clé et on publie le nouveau DS. Une fois le maximum du TTL du DS et du TTL de la DNSKEY sont passés, on supprime l'ancien DS et l'ancienne DNSKEY. ksk-doublerrset

Le double-KSK est le plus simple à comprendre, mais cette technique augmente la taille de l'ensemble DNSKEY. Le double-DS n'a pas ce défaut mais nécessite deux interactions avec le parent (certaines zones parentes, comme la racine, sont très lentes à réagir). Le double-RRset a les inconvénients des deux autres techniques mais est aussi la technique qui minimise le temps total de remplacement.

La section 3 du RFC présente les frises chronologiques (timeline) détaillées. Elle s'appuie sur une liste d'états des clés (états qu'affiche un logiciel comme OpenDNSSEC) :

  • Generated : clé créée mais pas encore utilisée. (Les clés peuvent être créées à l'avance.)
  • Published : la clé est publiée dans le DNS.
  • Ready : la clé est publiée depuis suffisamment longtemps pour qu'on soit sûr que, si le DNSKEY est dans un cache, il inclut cette clé.
  • Active : la clé est utilisée pour signer (si c'est une ZSK) ou bien elle permet de valider le DNSKEY (si c'est une KSK).
  • Retired : la clé n'est plus utilisée pour signer mais est encore publiée (certains caches peuvent avoir des vieilles signatures qui nécessitent cette clé).
  • Dead : les caches ont tous la nouvelle clé, elle ne sert plus à rien.
  • Removed : la clé n'est plus publiée.
  • Revoked : cet état n'existe que si on utilise le RFC 5011. Il indique que la clé va être retirée et que les résolveurs qui l'utilisent comme lien de confiance doivent se préparer à ne plus l'utiliser.

Les sections 3.2 et 3.3 présentent les frises chronologiques (timelines) des différentes techniques de remplacement d'une ZSK et d'une KSK (en art ASCII...) Les frises sont un peu complexes car, à chaque fois, on voit deux introductions d'une nouvelle clé, la N et la N+1. L'annexe A détaille les abréviations utilisées. Je n'ai pas reproduit ici les frises du RFC mais juste une version très simplifiée. Quelques points sont dignes d'être notés. D'abord, il peut être prudent, lorsqu'on met en œuvre ces frises, d'ajouter une marge à chaque opération (les éléments <PublishSafety> et <RetireSafety> dans la configuration d'OpenDNSSEC). Si une clé est publiée à l'instant T, et que le TTL est de N secondes, on peut compter que cette clé soit accessible à tous les caches à T + N mais il est plus prudent d'utiliser T + N + M où M est une marge qui permet de faire face à certains imprévus (un retard dans la mise à jour de certains serveurs faisant autorité, par exemple).

On peut améliorer la technique de pré-publication en introduisant des clés en attente (standby keys, section 4). Ces clés sont pré-publiées mais ne sont pas utilisées même lorsque le TTL de DNSKEY est passé. Elles attendent simplement. En général, elles sont là pour des cas d'urgence. Un exemple est celui d'une clé normale, stockée sur la machine qui fait les signatures DNSSEC, et une clé en attente, stockée sur une clé USB dans un coffre-fort. On pré-publie la clé en attente. Si, un matin, on découvre que la machine de signature a été piratée, on peut basculer tout de suite vers la clé en attente, puisqu'elle est dans les caches (la clé en attente est en permanence dans l'état Ready). À noter que, pour une KSK et pour la technique du Double-DS, ce n'est pas la clé qu'on publie mais le DS correspondant. On a donc un standby DS (c'est le cas aujourd'hui sur .fr, si vous regardez). Notez aussi un point de sécurité : une clé en attente n'a de sens que si elle se trouve stockée dans un endroit différent des autres clés. Autrement, elle sera piratée avec les autres.

Donc, en résumé (section 6) :

  • Pour les ZSK, la pré-publication est sans doute la technique la plus raisonnable.
  • Pour les KSK, le double-RRset est sans doute la meilleure technique, en raison du temps total qu'elle prend, plus court que pour les deux autres techniques.

Téléchargez le RFC 7583


L'article seul

RFC 7578: Returning Values from Forms: multipart/form-data

Date de publication du RFC : Juillet 2015
Auteur(s) du RFC : L. Masinter (Adobe)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 15 juillet 2015


Voici la nouvelle définition du type de données Internet multipart/form-data, qui est notamment envoyé par les navigateurs Web une fois qu'on a rempli un formulaire. Elle remplace la définition du RFC 2388.

Il y a plusieurs façons de représenter les données d'un formulaire rempli (cf. annexe B de notre RFC). (Et il faut aussi se rappeler qu'il n'y a pas que les formulaires en HTML : le format décrit dans ce RFC peut servir à d'autres types de formulaires.) Les deux plus fréquentes sont le format par défaut des formulaires Web, application/x-www-form-urlencoded, et le multipart/form-data qui fait l'objet de notre RFC. La sagesse générale des développeurs Web (citée par exemple dans la norme HTML 4) est d'utiliser application/x-www-form-urlencoded sauf s'il faut transmettre des fichiers ou des données binaires, auquel cas on préfère multipart/form-data. En HTML, cela se choisit par l'attribut enctype. Voici un exemple de formulaire HTML pour envoyer un fichier :

  
<form action="http://www.example.com/register"
       enctype="multipart/form-data"
       method="post">
   <p>
   What is your name? <input type="text" name="submit-name"/>
   What files are you sending? <input type="file" name="thefile"/>
   <input type="submit" value="Send"/> 
 </form>
  

Si l'utilisateur « Larry » envoie ainsi le fichier fi1e1.txt, le navigateur encodera les données du formulaire ainsi :

Content-Type: multipart/form-data; boundary=---------------------------14768918103265920051546586892
Content-Length: 359

-----------------------------14768918103265920051546586892
Content-Disposition: form-data; name="submit-name"

Larry
-----------------------------14768918103265920051546586892
Content-Disposition: form-data; name="thefile"; filename="file1.txt"
Content-Type: text/plain

   ... contents of file1.txt ...

-----------------------------14768918103265920051546586892--

Alors que l'encodage pour du application/x-www-form-urlencoded aurait été submit-name=Larry&thefile=file1.txt (ce qui ne convient pas pour le fichier). Cette différence entre les formats des données des formulaires est bien expliquée dans cette réponse sur StackOverflow. Et si vous voulez expérimenter vous-même avec netcat, voyez cette autre réponse.

Vu de l'utilisateur, les choses se passent comme cela (section 1 de notre RFC) : on présente à l'utilisateur un formulaire theform.png L'utilisateur le remplit, il sélectionne (par exemple en cliquant) le contrôle qui sert à dire « j'ai fini, traite-moi ce formulaire ». Le contenu est envoyé à une application sur le serveur. (Petit souvenir personnel : les formulaires sont apparus avec la version 2 de Mosaic et, pendant un certain temps, il était difficile de compter dessus car tout le monde n'avait pas encore mis à jour. Mais ça semblait formidable d'avoir un formulaire en Motif développé avec juste trois lignes d'HTML.)

Quel est le format de ce contenu qu'on envoie ? Il faut se rappeler que les formulaires ne sont pas spécifiques au Web, à HTML et à HTTP : le format peut être utilisé dans toute application qui a une notion de formulaire. Notre RFC ne spécifie pas le formulaire, ni le traitement sur le serveur de réception, mais uniquement le format de transport du formulaire rempli.

Il travaille donc sur une vision abstraite d'un formulaire, composé d'une séquence de champs, chaque champ ayant une valeur, fournie par l'utilisateur (certains champs peuvent avoir une valeur par défaut). Les champs ont un nom, qui est une chaîne de caractères Unicode (mais il est conseillé de se limiter à ASCII si on veut maximiser les chances d'interopérabilité). Il est également conseillé que les noms des champs soient uniques.

La section 4 de notre RFC détaille le format complet. Un message multipart/form-data suit de près le format des autres multipart/ MIME (RFC 2046, section 5.1). Comme son nom l'indique, il est composé de plusieurs parties séparées par une frontière, une ligne commençant par deux tirets. La valeur complète de cette ligne-frontière est donnée dans le champ Content-Type:. Il ne faut évidemment pas que cette ligne apparaisse dans les données envoyées.

Pour chaque partie, il est obligatoire d'avoir un champ Content-Disposition: (RFC 2183) avec un paramètre name qui indique le nom original du champ. Si la partie concerne un fichier qui a été envoyé, le RFC recommande que le champ Content-Disposition: contienne un paramètre filename, suggérant au serveur un nom pour le fichier. (« Suggérant » car, pour des raisons de sécurité, le serveur ne doit pas utiliser ce nom aveuglément, cf. aussi la section 7.)

Problème toujours intéressant, le jeu de caractères utilisé, et son encodage. On peut mettre un paramètre charset au Content-Type: de chaque partie MIME. Mais il est plus fréquent d'avoir un tel paramètre qui soit global. En HTML, la convention est qu'un champ caché du formulaire, nommé _charset_, fixe l'encodage par défaut. (Rappelez-vous que, dans les protocoles IETF et W3C, charset est mal nommé : c'est un encodage, plus qu'un jeu de caractères.) D'autre part, lorsque le transport du multipart/form-data est « 8-bit clean », ce qui est le cas de HTTP, l'utilisation du Content-Transfer-Encoding: est déconseillée.

La section 5 rassemble un ensemble de conseils pratiques pour la bonne transmission et interprétation des données des formulaires. D'abord, il est fortement déconseillé (même si, légalement parlant, ce n'est pas systématiquement interdit) d'éviter les caractères autres que ceux d'ASCII pour les noms des champs dans un formulaire. Ce n'est pas grave en pratique puisque ces noms, contrairement aux étiquettes affichées dans le formulaire, ne sont pas visibles à l'utilisateur. Voici un exemple en HTML :


<p>Envoyez une copie de votre carte d'identité 
<input type="file" name="idscan"/></p>

Le texte d'accompagnement comprend des caractères non-ASCII mais pas le paramètre name.

Toujours d'un point de vue pratique, quelques conseils de sécurité en section 7 :

  • Les données envoyées peuvent être des données personnelles, voire sensibles. C'est d'autant plus vrai que certains navigateurs Web ont une fonction d'auto-remplissage qui met automatiquement des informations personnelles dans les formulaires, ce qui fait qu'un utilisateur distrait peut envoyer davantage d'informations qu'il ne le voulait. L'auteur du formulaire et de son traitement doit donc faire attention à ces données.
  • Le contenu du fichier peut être dangereux (malware).

Le type multipart/form-data est, comme les autres types MIME, enregistré à l'IANA.

Quels sont les changements depuis le RFC 2388 ? Le format a été spécifié à l'origine dans le RFC 1867 puis dans la norme HTML 3.2. L'annexe A de notre RFC détaille les changements, parmi lesquels :

  • Les noms des champs non-ASCII doivent désormais être en UTF-8 et non plus encodés selon la méthode du RFC 2047 (mais, de toute façon, il est recommandé de les éviter). Cf. la section 5.1
  • Lorsque plusieurs fichiers sont envoyés (pour un même champ du formulaire), l'ancienne recommandation (RFC 2388) était d'utiliser un multipart/mixed, la nouvelle est de mettre chaque fichier dans une partie MIME spécifique (en utilisant le même nom de champ).
  • La convention du champ _charset_ (encodage par défaut) est désormais documentée.

Téléchargez le RFC 7578


L'article seul

RFC 7575: Autonomic Networking - Definitions and Design Goals

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : M. Behringer, M. Pritikin, S. Bjarnason, A. Clemm (Cisco Systems), B. Carpenter (Univ. of Auckland), S. Jiang (Huawei Technologies), L. Ciavaglia (Alcatel Lucent)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF nmrg
Première rédaction de cet article le 19 juin 2015


Ce nouveau RFC, issu de l'IRTF et donc assez futuriste, se penche sur les « réseaux autonomes » (autonomic networking), c'est-à-dire sur les réseaux qui se débrouillent tout seuls, sans administrateur réseaux, sans DSI, sans ICANN, etc. Un réseau autonome doit se configurer, s'optimiser, guérir des pannes et se protéger des attaques sans intervention humaine. Ce RFC n'explique pas comment les réaliser (c'est le début d'un programme de recherche) mais définit la terminologie et les buts à atteindre. Il a été publié en même temps que le RFC 7576, qui analysait les techniques existantes et leurs limites. (Le groupe de travail IETF ANIMA travaille sur les aspects plus concrets de ce sujet.)

La première description de tels réseaux autonomes date de 2001 (l'article de Kephart et Chess). L'idée est que toutes les boucles de régulation du système doivent être fermées, sans interaction avec l'extérieur (d'où l'adjectif « autonome »). IP lui-même a éte partiellement conçu pour fonctionner ainsi (la fameuse demi-légende de l'Internet prévu pour résister à une attaque nucléaire). Un protocole comme OSPF est autonome dans la mesure où il s'adapte tout seul aux changements de topologie. Toutefois, IP n'a jamais été complètement autonome et les évolutions qu'il a subi allaient plutôt dans le sens de mettre plus d'intelligence dans la configuration externe que dans le réseau lui-même. Est-ce grave ? Pour un grand réseau d'un Tier 1, on peut penser que son propriétaire préfère que le réseau n'ait pas trop d'autonomie (Skynet ?) et suive plutôt la politique configurée. Mais les réseaux autonomes sont tentants pour l'Internet des objets, quand on a un grand nombre de petites machines très simples, ensemble qui serait très difficile ou impossible à configurer avec les outils existants. Notre RFC estime que les deux approches (configuration extérieure centralisée, et fonctionnement réparti autonome) ont leurs avantages et inconvénients, et que pas mal de réseaux utiliseront une de ces deux approches pour certaines fonctions et la seconde pour les autres fonctions. Ne cherchez donc pas de réseau complètement autonome tout de suite.

De toute façon, l'approche autonome ne peut pas tout faire. Elle nécessite de découvrir tout seul un certain nombre de choses et la politique de gestion du réseau (qui peut s'en servir, pour quoi...) est un bon exemple de quelque chose qui ne peut pas être découvert, qui doit être configuré explicitement.

Les réseaux autonomes ont fait l'objet d'un très grand nombre d'études scientifiques et de publications (la section 7 du RFC contient des lectures, pour les gourmands, notamment trois synthèses de l'existant). Attention, on dit « autonome » et pas « automatique ». Il faut se gérer seul, pas juste dérouler automatiquement un script pré-établi par un humain (voir la section 2 sur les définitions). Par exemple, un système automatique doit être reprogrammé lorsque l'environnement change alors qu'on attend d'un réseau autonome qu'il s'adapte seul.

Donc, que veut-on d'un réseau autonome ? La section 3 décrit les buts. Le réseau doit être auto-géré ce qui se décline en :

  • Se configure tout seul. Les machines démarrent, se découvrent, trouvent les liens qui les relient et se mettent à les utiliser. Pas d'admin' pour avoir tapé des default_router=fe80::1.
  • Se guérit tout seul. Une pelleteuse arrache un câble ? Le réseau contourne le problème automatiquement (ceci marche dans l'Internet actuel : rappelez-vous qu'on a déjà certaines fonctions qui peuvent marcher de manière autonome).
  • S'optimise tout seul en trouvant la meilleure façon d'accomplir les tâches définies.
  • Se protège tout seul car le monde est hostile et cruel et des hackers chinois islamistes à cagoule vont attaquer le réseau.

Évidemment, en trichant, on peut définir tout réseau comme « autonome » si on élargit la définition pour inclure, par exemple, un contrôleur central (comme avec le SDN). Le RFC est donc plus spécifique : « tout seul » veut dire « en n'utilisant que des fonctions qui sont sur les machines terminales ». Comme dit l'Internationale, le réseau autonome n'a « ni Dieu, ni César, ni tribun[, ni contrôleur SDN] ».

Comme on ne peut pas envisager un Internet complètement autonome, ces réseaux autonomes vont devoir coexister avec les méthodes de gestion traditionnelles (comme Netconf). Cela peut nécessiter un mécanisme d'arbitrage si les deux méthodes sont en désaccord. Le RFC utilise un exemple tiré de l'aviation : un avion où le pilote automatique se coupe automatiquement si le vol sort d'une certaine plage de paramètres (par exemple si l'angle d'incidence est trop élevé). Toutefois, on peut aussi se dire qu'une crise n'est pas le meilleur moment pour passer brutalement le contrôle au pilote stressé et le RFC demande donc que les mécanismes autonomes ne se coupent pas tout seuls, même dans des situations non prévues.

Autre but de nos réseaux autonomes : qu'ils soient sûrs. On doit pouvoir, par exemple, empêcher un intrus de rejoindre le réseau, ce qui implique un certain mécanisme d'authentification, qui ne sera pas forcément totalement autonome (par exemple un certificat émis par une AC, une base d'utilisateurs centralisée, etc). Bref, il faudra sans doute de la cryptographie.

« Autonome » ne veut pas dire « isolé et sourd-muet » (sinon, ce ne serait pas un réseau). La machine doit communiquer avec des pairs mais aussi avec des autorités, comme cela qui lui communique le travail à faire, à qui la machine terminale transmet des rapports, des statistiques, etc. C'est ce qu'on nomme l'interface Nord (car placée en haut sur les schémas et tant pis pour l'Australie).

On a vu que le réseau n'est pas créé pour satisfaire les machines mais pour accomplir un certain travail. Il faudra donc un mécanisme pour informer les machines de ce travail, et des changements dans les définitions de ce travail. Ce mécanisme doit être de haut niveau, sinon, ce ne sera plus un réseau autonome, on retournerait à la configuration centralisée traditionnelle. Par exemple, le RFC demande que ce mécanisme n'expose pas la version d'IP utilisée (IPv4 ou IPv6) : cela doit rester un détail technique interne au réseau.

J'ai parlé plus haut de transmettre des rapports à l'autorité centrale. Il est évidemment nécessaire de prévenir les humains qui ont acheté et déployé ces machines de l'efficacité de celles-ci : le travail a-t-il été fait ? Mais, pour respecter le principe d'un réseau autonome, les rapports ne doivent pas porter sur des détails d'implémentation que le réseau doit résoudre lui-même (comme « le lien entre la machine X et la machine Y ne marche plus »). Il faut au contraire un mécanisme de communication abstraite, synthétisant l'information, pour ne pas écrouler l'autorité centrale sous les détails. Imaginons que l'autorité ait envoyé le but de haut niveau « économise l'énergie », le rapport devrait être du genre « 30 % de réduction de la consommation, obtenu en éteignant 40 % des ports réseau ». Pour résumer : les rapports devraient décrire le réseau globalement, pas machine par machine ou lien par lien.

Le RFC 7576 montre qu'il existe déjà un certain nombre de protocoles et de fonctions autonomes dans la famille IP. Mais le but du projet « réseaux autonomes » n'est pas uniquement d'empiler des solutions mais de les intégrer dans un cadre commun, qui reste à développer.

Enfin, « autonome » est un adjectif qu'on peut appliquer à toutes les couches. Par exemple, les commutateurs typiques aujourd'hui sont autonomes au niveau 2 (on les branche n'importe comment et ils font une topologie qui marche). Les routeurs peuvent en faire autant au niveau 3, comme vu avec l'exemple OSPF.

Un bon cahier des charges doit aussi avoir des non-buts : ce qu'on ne cherche pas à atteindre. C'est le rôle de la section 4 du RFC. Les non-buts sont :

  • Supprimer complètement tout opérateur humain (Skynet, encore). Les humains vont rester, mais en se concentrant sur des fonctions de haut niveau, comme la définition et la vérification des politiques.
  • Résoudre tous les problèmes. De temps en temps, il se produira un évènement dont le réseau ne saura pas se dépêtrer seul. Là encore, des humains devront intervenir. Ce sera au moins le cas pour les pannes matérielles, tant que les ordinateurs n'auront pas de périphériques leur permettant d'aller à la casse eux-même...
  • Supprimer tout contrôle central. Comme le note le RFC, la Direction Générale ne serait sans doute pas d'accord.

Enfin, notre RFC se termine par une description, en section 5, d'un modèle de référence des réseaux autonomes, reprenant les points vus précédemment.


Téléchargez le RFC 7575


L'article seul

RFC 7574: Peer-to-Peer Streaming Peer Protocol (PPSPP)

Date de publication du RFC : Juillet 2015
Auteur(s) du RFC : A. Bakker (Vrije Universiteit Amsterdam), R. Petrocco, V. Grishchenko (Technische Universiteit Delft)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ppsp
Première rédaction de cet article le 14 juillet 2015


Le pair-à-pair est un succès énorme de l'Internet et du contenu en quantités impressionnantes est échangé tous les jours avec des techniques fondées sur ce principe. Toutefois, il s'agit surtout de téléchargement (obtenir un contenu statique) alors qu'on voudrait pouvoir utiliser le même concept, le pair-à-pair, pour du ruissellement (streaming), afin de distribuer du contenu dynamique, comme un évenement en train de se produire et qu'on filme. C'est ce que permet le nouveau protocole PPSPP (Peer-to-Peer Streaming Peer Protocol), que normalise ce RFC. Son but est de fournir l'équivalent de BitTorrent pour du contenu dynamique, et beaucoup de concepts de PPSPP sont très proches de BitTorrent (cf. son cahier des charges, dans le RFC 6972).

Dans PPSPP, le contenu est « auto-certifié ». L'identificateur d'un contenu permet sa vérification. Contrairement au contenu statique, on ne peut pas utiliser un simple condensat cryptographique (méthode de BitTorrent) puisqu'on ne connait pas tous les octets à l'avance. PPSPP se sert donc d'un arbre de Merkle calculé récursivement au fur et à mesure que le contenu est disponible (comme cela avait été proposé pour BitTorrent, voir aussi la section 5.5). L'identificateur du contenu est le condensat cryptographique de la racine de cet arbre de Merkle. Grâce à cette auto-certification, un pair malveillant ne pourra pas modifier le contenu (il reste à s'assurer de l'authenticité de l'identificateur mais c'est une autre histoire... BitTorrent a le même problème.)

PPSPP est un protocole applicatif qui peut tourner sur plusieurs protocoles de transport. À l'heure actuelle, le seul normalisé est LEDBAT (RFC 6817), le protocole « durable », qui n'envoie des octets que lorsque le tuyau est libre. Ainsi, l'usage de PPSPP ne va pas perturber les autres applications. (La section 8 détaille l'usage de LEDBAT sur UDP.)

PPSPP peut découvrir la liste des pairs de plusieurs façons : via un tracker centralisé, ou via une DHT. Ce nouveau RFC suppose la liste des pairs déjà connue et ne décrit que le protocole pour récupérer le contenu. L'obtention de la liste fera l'objet d'autres travaux.

La section 2 de notre RFC présente le protocole, à travers trois exemples. D'abord, un pair qui rejoint un essaim (swarm). Un utilisateur humain regarde une page Web contenant un élément <video>. Son navigateur Web lui a présenté une image avec les contrôles habituels comme un bouton Play. L'utilisateur clique sur ce bouton. L'URL derrière la vidéo indique du PPSPP. Le navigateur va alors récupérer la liste des pairs (rappelez-vous que ce point n'est pas couvert dans ce RFC). Supposons qu'on utilise un tracker centralisé. Le logiciel PPSPP va s'enregistrer auprès de ce tracker. Il a une liste de pairs, il peut commencer à parler le protocole PPSPP avec eux. D'abord, le message HANDSHAKE (section 3.1 de notre RFC). Ensuite, il recevra des messages HAVE (section 3.2) indiquant quels sont les parties du flux de données que ses pairs connaissent déjà et peuvent donc fournir à leurs pairs. Il est maintenant un membre de l'essaim.

Deuxième exemple, on veut échanger des données. Notre logiciel PPSPP va envoyer des messages REQUEST (section 3.7) indiquant ce qui l'intéresse, en tenant compte des HAVE reçus. Les pairs envoient des messages DATA (section 3.3) contenant les octets de la vidéo, ainsi que des messages INTEGRITY (section 3.5) contenant les éléments de l'arbre de Merkle et permettant de vérifier que des intermédiaires n'ont pas modifié la vidéo (les détails sur cette vérification sont dans la section 5).

Une fois que notre logiciel a des données, il peut téléverser (to upload). Il va à son tour envoyer des messages HAVE aux pairs, et répondre à des requêtes REQUEST.

Le départ « propre » de l'essaim se fait en envoyant un message HANDSHAKE (et en se désincrivant du tracker, s'il y en a un). Mais, évidemment, dans un réseau pair-à-pair, il est fréquent que des machines ne partent pas proprement : coupure du réseau, plantage de la machine ou du logiciel, etc. Les pairs doivent donc être prêts à gérer le cas de pairs qui ne répondent plus.

La section 3 de notre RFC présente tous les messages qui peuvent être échangés (rassurez-vous : je n'en couvre qu'une partie mais ils ne sont pas si nombreux, seulement douze types). Les messages ne demandent pas de réponse : une absence de nouvelles de la part du pair indique qu'il y a un problème. Par exemple, si on envoie un message HANDSHAKE à des pairs qui ne veulent pas de nous, ils ne répondront pas avec un message d'erreur, ils s'abstiendront simplement de répondre. Il y a donc deux sortes de pairs : ceux qui répondent vite et bien et ceux qui répondent peu ou pas, et qu'on va donc petit à petit décider d'ignorer. On n'insiste pas avec les pairs non répondants.

À noter que PPSPP ignore le format des données envoyées : il transmet des octets, sans savoir si c'est du MPEG nu, ou bien un container rassemblant plusieurs fichiers, comme le permettent des formats comme AVI. PPSPP est un protocole de transfert de données, pas une solution complète de télé-diffusion.

Parmi les points à noter dans les messages : chaque essaim transmet un flot d'octets et un seul (cf. l'avertissement ci-dessus sur les containers). Un essaim a un identificateur (swarm ID), échangé dans les messages HANDSHAKE. Ces messages contiennent également d'autres paramètres (cf. section 7) comme la taille des morceaux (chunks) ou comme la fonction exacte utilisée pour l'arbre de Merkle. Le flot d'octets est en effet découpé en morceaux, chacun ayant un identificateur (chunk ID). Cet identificateur est un paramètre des messages HAVE, REQUEST et DATA. Ainsi, un message DATA contient un morceau, et l'identificateur de ce morceau. Cela permet au pair de savoir où il en est et s'il lui manque quelque chose.

J'ai parlé plus haut du message INTEGRITY qui contient un condensat cryptographique d'un sous-arbre de l'arbre de Merkle correspondant au contenu transmis. Les messages INTEGRITY ne sont pas signés donc ils ne protègent que contre les accidents, pas contre un pair malveillant. Il existe des messages SIGNED_INTEGRITY qui, eux, sont signés (cf. sections 5 et 6.1). À noter que, dans ce cas, la clé publique est dans l'identificateur de l'essaim, encodée en suivant le format des DNSKEY de DNSSEC.

Les messages REQUEST, mentionnés plus haut, servent à demander une partie du flot de données. Contrairement à BitTorrent, ils ne sont pas indispensables : un pair peut vous envoyer des morceaux que vous n'avez pas explicitement demandé. C'est logique pour PPSPP, qui est prévu pour le ruissellement : PPSPP est plus push que pull.

La section 4 explique le mécanisme d'adressage des morceaux. On n'est en effet pas obligé de les désigner un par un. On peut utiliser des intervalles (« du morceau N1 au morceau N2 »), des octets (« tous les morceaux qui composent le premier million d'octets ») ou bien des bin numbers. Un bin number est un mécanisme très astucieux permettant de désigner un intervalle d'octets presque quelconque avec un seul nombre. Je vous laisse lire la section 4.2 du RFC pour une explication complète. (Si quelqu'un de courageux peut ensuite en faire un article sur les bin numbers pour Wikipédia... Actuellement, il n'y en a pas.)

La section 12 de notre RFC intéressera tout particulièrement les administrateurs système et réseau. Elle couvre les problèmes opérationnels avec PPSPP. Par exemple, comme avec tout protocole pair-à-pair, un pair PPSPP a intérêt à choisir des pairs « proches » (entre guillemets car il n'est pas évident de définir « proche »). Le protocole ALTO du RFC 7285 peut aider à mieux choisir ses pairs. Mais il faut bien dire que, l'expérience concrète avec PPSPP manquant encore, on est un peu ici dans des zones inexplorées.

La section 13 du RFC, elle, se consacre aux questions de sécurité. D'abord, la vie privée : comme BitTorrent, PPSPP expose à chaque pair l'adresse IP des autres pairs (sauf si on utilise Tor, ce qui ne sera pas forcément simple) et on ne peut donc pas tellement cacher à ses pairs son intérêt pour tel ou tel contenu. À noter que PPSPP ne fournit pas de mécanisme pour protéger la confidentialité du contenu. Si on veut distribuer du contenu à accès restreint, on le chiffre avant, ou bien on utilise IPsec ou DTLS.

Ensuite, le risque d'attaques par réflexion, puisque PPSPP tournera typiquement sur UDP. Si un attaquant ment sur son adresse IP, peut-il déclencher l'envoi de données massives vers un innocent ? A priori, non, en raison de l'usage d'un mécanisme analogue aux ISN (Initial Sequence Number) de TCP. La communication nécessite la connaissance de nombres nommés channel ID et ils sont choisis aléatoirement (RFC 4960). Un attaquant ne peut donc pas les connaitre (cf. section 5.1.3) s'il a triché sur son adresse IP (puisqu'il ne recevra pas le message lui communiquant le channel ID à utiliser : en d'autres termes, PPSPP teste la « routabilité »).

Une version, apparemment assez expérimentale, de ce protocole a été mise en œuvre en logiciel libre, dans libswift. Une autre, écrite en Erlang est le projet Swirl.


Téléchargez le RFC 7574


L'article seul

RFC 7572: Interworking between the Session Initiation Protocol (SIP) and the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : P. Saint-Andre (&yet), A. Houri (IBM), J. Hildebrand (Cisco Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF stox
Première rédaction de cet article le 17 juin 2015


Ce court RFC décrit une correspondance entre deux protocoles standards de messagerie instantanée, SIP et XMPP. Cela permet de développer proprement des passerelles connectant ces deux mondes, autorisant ainsi Juliette, utilisatrice de XMPP, à parler avec son Roméo, qui utilise SIP. C'est aussi un exercice intellectuel rigolo, mais parfois difficile, comment faire se parler deux protocoles différents, qui n'ont pas exactement les mêmes sémantiques.

C'est vrai qu'on ne sait pas forcément que SIP (RFC 3261) est aussi un protocole de messagerie instantanée. On le voit plutôt uniquement comme un protocole de signalisation pour la téléphonie sur IP. Mais SIP sait bel et bien échanger de courts messages textes, grâce à l'extension MESSAGE du RFC 3428. Quant à XMPP (RFC 6120), ses capacités de messagerie instantanée sont spécifiées dans le RFC 6121. C'est pour des raisons historiques variées que l'IETF a deux protocoles standard de messagerie instantanée, sans compter l'ancêtre IRC.

Le concept de messagerie instantanée, à l'IETF, est décrit dans le RFC 2779. Le but est de communiquer, donc il serait ennuyeux que Roméo et Juliette ne puissent pas échanger simplement parce qu'ils ont fait des choix technologiques différents. Spécifier un mécanisme de passerelle entre ces deux protocoles peut se faire en développant une sémantique abstraite (elle existe déjà, dans le RFC 3860), puis en définissant une correspondance entre cette abstraction et chaque protocole (ce qui a été fait pour XMPP : RFC 3922). En pratique, c'est bien compliqué et notre nouveau RFC 7572 choisit une autre approche, définir une correspondance entre SIP et XMPP, sans intermédiaire. L'inconvénient est que cela ne se généralise pas à davantage de protocoles, l'avantage est que c'est simple à comprendre et à programmer. En pratique, cette approche est donc bien plus répandue.

Notre RFC repose sur un modèle simple, l'envoi de courts textes, les messages, de manière synchrone, entre deux entités (Roméo et Juliette dans les exemples du RFC), ce qui se nomme page mode. Il existe d'autres modèles comme celui de conversations stables sur une certaine durée (session mode) ou comme celui de communications à plus de deux participants. Le groupe de travail STOX de l'IETF est penché dessus et produira d'autres RFC sur ces modèles, comme le RFC 7573 sur les sessions. Notre RFC s'appuie sur le RFC 7247, qui définissait une architecture pour l'interconnexion de SIP et XMPP.

Donc, commençons par XMPP vers SIP (section 4). Un message XMPP est une strophe (stanza) XML <message/> de type normal (le type par défaut). Voici l'exemple envoyé par Juliette :


<message from='juliet@example.com/yn0cl4bnw0yr3vym'
         to='romeo@example.net'>
   <body>Art thou not Romeo, and a Montague?</body>
</message>

Si le domaine dans l'attribut to est un domaine SIP (section 5 du RFC 7247), le serveur XMPP que Juliette utilise va transmettre le message à une passerelle XMPP->SIP qui va traduire en SIP :


MESSAGE sip:romeo@example.net SIP/2.0
Via: SIP/2.0/TCP x2s.example.com;branch=z9hG4bK776sgdkse
Max-Forwards: 70
To: sip:romeo@example.net
From: <sip:juliet@example.com;gr=yn0cl4bnw0yr3vym>;tag=12345
Call-ID: D9AA95FD-2BD5-46E2-AF0F-6CFAA96BDDFA
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 35

Art thou not Romeo, and a Montague?

Notez que l'identificateur de ressource dans le JID (le JID nu est juliet@example.com, la ressource est yn0cl4bnw0yr3vym, cf. RFC 6120, section 1.4) a été traduit en GRUU (Globally Routable User Agent URIs, cf. RFC 5627) SIP.

Le serveur SIP de Roméo répondra automatiquement avec le code 200 (tout va bien) :

SIP/2.0 200 OK
Via: SIP/2.0/TCP x2s.example.com;branch=z9hG4bK776sgdkse
From: sip:juliet@example.com;tag=12345
To: sip:romeo@example.net;tag=vwxyz
Call-ID: D9AA95FD-2BD5-46E2-AF0F-6CFAA96BDDFA
CSeq: 1 MESSAGE
Content-Length: 0

La correspondance entre les termes utilisés figure dans le tableau 1 dans cette section 4. Ainsi, le <body/> de XMPP est transformé en corps du message SIP, l'attribut to de XMPP qui indique le destinataire devient le champ To: de SIP, l'attribut xml:lang de XMPP (absent dans cet exemple) devient un champ Content-Language:, etc. Certaines valeurs n'ont pas de correspondance (comme l'attribut type de XMPP, inutilisé dans l'exemple).

En sens inverse, lorsque Roméo répond, il va utiliser SIP (avec l'extension du RFC 3428) et il va donc falloir traduire le SIP en XMPP. Sa réponse était (section 5 de notre RFC) :


MESSAGE sip:juliet@example.com SIP/2.0
Via: SIP/2.0/TCP s2x.example.net;branch=z9hG4bKeskdgs677
Max-Forwards: 70
To: sip:juliet@example.com
From: sip:romeo@example.net;tag=vwxyz
Call-ID: 9E97FB43-85F4-4A00-8751-1124FD4C7B2E
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 44

Neither, fair saint, if either thee dislike.

Et la passerelle SIP->XMPP qu'utilisera le serveur SIP de Roméo traduira en :


<message from='romeo@example.net/dr4hcr0st3lup4c'
         to='juliet@example.com'>
  <body>Neither, fair saint, if either thee dislike.</body>
</message>

La correspondance entre les termes (tableau 2) est la même, mais inversée. Le champ To: est traduit en attribut to, le corps du message devient un élément XMPP <body>, etc. Notez que la passerelle connaissait le GRUU SIP (par un moyen non spécifié, peut-être parce qu'elle fait partie du serveur SIP) et l'a utilisé pour générer un JID complet avec identificateur de ressource (romeo@example.net/dr4hcr0st3lup4c).

Faire des passerelles entre deux protocoles indépendants, conçus de manière différente et sans coordination a toujours été délicat. Par exemple, la section 6 fait remarquer qu'il y a un problème... de taille. SIP met une limite de 1 300 octets aux messages (RFC 3428, section 8) alors que les RFC sur XMPP ne spécifient pas de limite. En pratique, les messages XMPP dépassent rarement cette taille et, de toute façon, les mises en œuvre effectives de XMPP ont souvent une limite (RFC 6120, section 13.12), mais plus élevée (au moins 10 000 octets doivent être acceptés, dit le RFC 6120). Si Juliette, qui utilise XMPP, essaie d'envoyer un message de 1 500 octets à son Roméo, la passerelle XMPP->SIP n'aura pas d'autre choix que de le rejeter, avec une erreur <policy-violation/>. (Des solutions plus sophistiquées existent, comme de passer en session mode mais notre RFC ne les spécifie pas.)

Autre cause d'incompatibilités possibles, mais en sens inverse, cette fois, les questions de format des données (section 7). Un message SIP peut contenir des données de n'importe quel type (dans les exemples ci-dessus, c'était toujours du text/plain mais ce n'est pas obligatoire). XMPP traitant le contenu de manière très différente, notre RFC impose aux passerelles SIP->XMPP de :

  • Accepter le contenu text/plain, comme dans les exemples ci-dessus, en le mettant dans le <body/> XMPP,
  • Accepter le contenu text/html en le transformant en XHTML qu'on met dans le <body/> XMPP (comme décrit dans le XEP-0071),
  • Faire ce qu'elle veut avec les autres types, aucune règle n'est spécifiée pour eux.

Et si on veut le dire autrement qu'en anglais ? Pas de problème, les deux protocoles permettent d'étiqueter le message avec la langue utilisée, et tous les deux permettent de transporter des caractères Unicode (en général en UTF-8). Si Roméo décide de parler tchèque :


MESSAGE sip:juliet@example.com SIP/2.0
Via: SIP/2.0/TCP s2x.example.net;branch=z9hG4bKeskdgs677
Max-Forwards: 70
To: sip:juliet@example.com
From: sip:romeo@example.net;tag=vwxyz
Call-ID: 5A37A65D-304B-470A-B718-3F3E6770ACAF
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 45
Content-Language: cs

Nic z obého, má děvo spanilá, nenávidíš-li jedno nebo druhé. 

La passerelle le traduira sans problème (j'ai utilisé ici les notations commençant par &#x mais ce n'est pas obligatoire, XMPP utilise XML et peut donc se servir d'UTF-8) :


<message from='romeo@example.net'
         to='juliet@example.com'
         xml:lang='cs'>
	 <body>
           Nic z ob&#x00E9;ho, m&#x00E1; d&#x011B;vo spanil&#x00E1;, nen&#x00E1;vid&#x00ED;&#x0161;-li jedno nebo druh&#x00E9;.
       </body>
</message>

Un mot sur la sécurité pour finir. L'introduction de la passerelle entre les deux protocoles ajoute évidemment quelques risques. Notamment, il est plus difficile de garantir une sécurité de bout en bout. Il existe des solutions standard peu déployées (RFC 3862 et RFC 3923) ou une solution non standard, OTR.

Parmi les serveurs qui mettent déjà en œuvre cette passerelle, on peut apparemment citer Cisco, Kamailio, ou AG Projects (dans Silk Server).


Téléchargez le RFC 7572


L'article seul

RFC 7568: Deprecating Secure Sockets Layer Version 3.0

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : R. Barnes, M. Thomson (Mozilla), A. Pironti (INRIA), A. Langley (Google)
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 26 juin 2015


Ce nouveau RFC formalise un point déjà bien connu des experts en sécurité : le dernier survivant de la famille SSL, SSL version 3, a de graves failles et ne doit pas être utilisé.

Il y a bien longtemps que SSL est dépassé, remplacé par TLS (même si des ignorants continuent de parler de SSL dès qu'ils voient un petit cadenas sur leur navigateur Web). Mais les vieux protocoles ne meurent pas facilement sur l'Internet. Manque de ressources humaines qualifiées, absence d'intérêt pour la sécurité, blocage par la direction financière qui demande quel est le ROI, des tas de raisons font que pas mal de serveurs acceptent encore le SSL v3. Celui-ci, décrit dans le RFC 6101 (mais qui avait été défini et déployé bien avant, en 1996, le RFC 6101 ne faisant que documenter longtemps après), devrait pourtant être abandonné définitivement, ne laissant que TLS (dont la version actuelle est la 1.2, en RFC 5246).

La première fin de SSL v3 était en 1999, avec la sortie de TLS, dans le RFC 2246. Le fait que SSL v3 soit toujours bien vivant aujourd'hui, plus de quinze ans après, donne une idée de l'ossification de l'Internet et du manque de réactivité des techniciens.

La section 3 de notre RFC résume la bonne pratique actuelle : NE PAS UTILISER SSL v3. Les clients ne doivent pas le proposer dans le ClientHello, ni les serveurs dans leur ServerHello.

Bien plus longue, la section 4 décrit pourquoi SSL v3 est cassé sans espoir de réparation. Première raison, qui a permis la faille POODLE (cf. un bon article d'explication pour tous), c'est que le remplissage en mode CBC n'est pas spécifié (et donc pas vérifiable par le pair). Autre faille, SSL v3 fait forcément du MAC-then-encrypt, ce qui est aujourd'hui considéré comme dangereux. TLS fait aussi du MAC-then-encrypt par défaut mais on peut le changer (RFC 7366) grâce aux extensions. Or, SSL v3 n'a pas la notion d'extensions.

Les algorithmes de chiffrement stream de SSL v3 ont tous des défauts sérieux, par exemple RC4 est désormais officiellement abandonné (RFC 7465). Question condensation, ce n'est pas mieux, certaines opérations de SSL v3 imposant MD5 (RFC 1321, abandonné par le RFC 6151).

L'échange de clés dans SSL v3 a aussi des failles permettant à un homme du milieu de se placer. Corrigées dans TLS par des extensions, elles ne sont pas corrigeables en SSL v3.

Toujours en raison de son manque d'extensibilité, SSL v3 ne peut pas avoir certaines des nouvelles fonctions développées depuis sa naissance. Pas d'algorithmes dans les modes AEAD (RFC 5246, section 6), pas de courbes elliptiques (RFC 8422), pas de reprise d'une session existante sans état sur le serveur (RFC 5077), pas de mode datagramme pour UDP (RFC 6347), pas de négociation de l'application utilisée (RFC 7301).

Comme le notait le texte d'accompagnement à l'IESG, où on doit indiquer les mises en œuvre du protocole, « Are there existing implementations of the protocol? Yes, and that's the problem;-) ». Ceci dit, une bonne partie des déploiements de TLS ont commencé à supprimer SSL v3. Logiquement, il devrait être retiré du code des bibliothèques TLS (alors que, encore aujourd'hui, la page d'accueil de GnuTLS se vante de gérer SSL v3). Espérons que ce RFC, qui n'apporte aucune information technique nouvelle, par son côté « officiel », contribue à faire bouger les choses.

Pour déterminer si un serveur accepte SSL v3, on peut utiliser le client d'OpenSSL :

% openssl s_client -connect www.bortzmeyer.org:443 -ssl3 
CONNECTED(00000003)
depth=0 CN = www.bortzmeyer.org
...
SSL handshake has read 2276 bytes and written 470 bytes
...
SSL-Session:
    Protocol  : SSLv3
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: 8B815B79611AB6FB105E84AA3159A0E57D50BA61BEE33478BB5DFEAFD5E4979B

Ici, le serveur a accepté SSL v3 (handshake terminé, algorithme de chiffrement - DHE-RSA-AES256-SHA - sélectionné alors qu'on a forcé SSL v3). Si vous voulez savoir pourquoi ce serveur particulier accepte malheureusement SSL v3, voir à la fin de cet article.

Avec un qui n'a pas SSL v3, on voit :

% openssl s_client -connect www.example.net:443 -ssl3
CONNECTED(00000003)
3073382076:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:s3_pkt.c:348:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 7 bytes
---
...
SSL-Session:
    Protocol  : SSLv3
    Cipher    : 0000
    Session-ID: 

Les messages d'OpenSSL, comme toujours, sont peu clairs, mais on peut voir que le handshake n'a pas abouti (très peu de données transmises), qu'aucun algorithme de chiffrement n'a été choisi et qu'aucune session n'a commencé (ID vide). Ce serveur est donc correct.

Notez que l'administrateur système est dépendant des logiciels utilisés et qu'il ne peut pas tout reprogrammer lui-même. Ainsi, GnuTLS a un module Apache, mod_gnutls, qui a une très sérieuse bogue (ancienne et jamais réparée) qui fait que SSLv3 n'est pas interdit, même quand la configuration le demande. Personnellement, je vais arrêter d'utiliser GnuTLS sur mes sites Web, pas à cause de la bibliothèque elle-même, qui est excellente, mais à cause de ce module Apache pas maintenu.


Téléchargez le RFC 7568


L'article seul

RFC 7567: IETF Recommendations Regarding Active Queue Management

Date de publication du RFC : Juillet 2015
Auteur(s) du RFC : F. Baker (Cisco Systems), G. Fairhurst (University of Aberdeen)
Réalisé dans le cadre du groupe de travail IETF aqm
Première rédaction de cet article le 12 juillet 2015


L'AQM (Active Queue Management) désigne l'ensemble des techniques utilisées par un routeur pour gérer les files d'attente de paquets attendant de partir. La technique triviale est de faire passer les paquets en FIFO et de refuser de nouveaux paquets quand la file d'attente est pleine. Mais il existe plein d'autres techniques possibles, qui forment l'AQM. Ce nouveau RFC résume les recommandations de l'IETF sur l'AQM. Notamment, il n'y a plus de méthode privilégiée, comme l'était RED précédemment (dans l'ancien RFC 2309).

Petit rappel sur IP d'abord (section 1 du RFC) : IP (RFC 791 ou RFC 2460) est un protocole sans état (chaque paquet est routé indépendamment des autres) et donc sans connexion. Cela rend les routeurs bien plus efficaces (ils n'ont pas besoin d'avoir de mémoire), cela permet de changer de route facilement, cela permet de survivre à la perte ou au redémarrage d'un routeur. L'extrême robustesse de l'Internet le montre tous les jours. En revanche, une des faiblesses de ce mécanisme sans connexion est sa sensibilité aux fortes charges : si un routeur congestionné commence à perdre des paquets car ses liens de sortie sont saturés, les machines vont réémettre, envoyant davantage de paquets, aggravant la situation et ainsi de suite jusqu'à la fusion du réseau (le fameux Internet meltdown, cf. RFC 896 et RFC 970). Ce phénomène a été plusieurs fois observés dans les années 1980 sur le cœur de l'Internet. Il est depuis confiné aux marges de l'Internet, par l'applications de meilleures techniques dans les routeurs, mais il menace en permanence de réapparaitre.

Le RFC 2309, publié en 1998, est le dernier qui fasse le point sur le problème de la congestion et ses conséquences. Sa principale recommandation concrète était de déployer massivement une technique de gestion des files d'attente, RED (« Internet routers should implement some active queue management [...] The default mechanism for managing queue lengths to meet these goals in FIFO queues is Random Early Detection (RED). Unless a developer has reasons to provide another equivalent mechanism, we recommend that RED be used. ») Mais, depuis 1998, l'Internet a évolué, notamment par la demande plus forte de limitation de la latence. La recommandation du RFC 2309 ne semble plus aussi opportune. (Et RED s'est avéré difficile à configurer en pratique.)

Tout le travail n'est pas à faire du côté des routeurs. Le problème de la congestion et le risque de fusion sont tellement sérieux, surtout depuis les grandes pannes des années 1980, que beaucoup d'efforts ont été dépensés pour les traiter. C'est ainsi que Van Jacobson a développé les règles (« Congestion Avoidance and Control » dans le SIGCOMM Symposium proceedings on Communications architectures and protocols en 1988) que doit suivre TCP pour éviter que ce dernier n'aggrave la congestion : en cas de perte de paquets, TCP ne doit pas réémettre bêtement comme un porc mais au contraire se calmer, arrêter d'envoyer des paquets à la vitesse maximale, pour donner une chance aux files d'attente des routeurs de se vider. Ces règles sont aujourd'hui documentées dans le RFC 5681. Elles s'appliquent aux machines terminales de l'Internet, alors que notre RFC 7567 concerne les routeurs, qui ont aussi leur rôle à jouer. Les machines terminales ne peuvent pas tout, d'autant plus que toutes ne sont pas bien élevées : il y a des programmes mal écrits ou malveillants qui sont connectés au réseau, cf. la section 5. Des travaux sont en cours pour gérer le cas de machines qui ne réagissent pas à la congestion et continuent à émettre au maximum (cf. RFC 6789).

Mais le risque d'écroulement du réseau sous l'effet de la congestion n'est pas le seul. Il faut aussi penser à la latence. Si on augmente la taille des files d'attente dans les routeurs, pour diminuer le risque d'avoir à jeter des paquets, on augmente aussi la latence, car vider ces files prendra du temps. (L'augmentation excessive de la taille des files d'attentes est connue sous le nom de bufferbloat, voir aussi la section 2.3, et le RFC 8033.)

La section 2 décrit en détail le problème de la gestion des files d'attente dans un routeur de l'Internet. La méthode traditionnelle, la plus simple, est connue sous le nom de tail drop : la queue a une taille finie, lorsqu'elle est pleine, on arrête d'accepter des paquets, point. Cela veut dire que les premiers paquets jetés sont les derniers arrivés. Cette méthode est simple à programmer mais elle a plusieurs inconvénients :

  • Tail drop ne signale la congestion aux machines terminales (en jetant les paquets) que lorsque la file d'attente est pleine. Si la file reste en permanence à 50-80 % pleine, aucun paquet ne sera jeté, les machines terminales continueront à émettre au même rythme, alors que le fait que la file soit plus qu'à moité pleine aura un effet négatif sur la latence.
  • Cette technique ne garantit pas l'égalité des différents flots de communication : dans certains cas, un seul flot peut monopoliser la queue.
  • Elle a aussi la propriété qu'elle tend à synchroniser les différentes machines qui partagent le même goulet d'étranglement (Floyd, S. et V. Jacobsen, « The Synchronization of Periodic Routing Messages »).

On pourrait réduire certains de ces problèmes (notamment le premier) en réduisant la taille de la file d'attente. Mais celle-ci est indispensable dans le cas d'augmentation brusque de trafic : le rythme d'arrivée des paquets n'est pas constant, il y a des moments où tout le monde parle en même temps (Leland, W., Taqqu, M., Willinger, W., et D. Wilson, « On the Self-Similar Nature of Ethernet Traffic (Extended Version) », IEEE/ACM Transactions on Networking), et les files d'attente sont là pour lisser ces soubresauts. Idéalement, on voudrait une queue vide en temps normal, qui ne se remplisse que pendant les pics de trafic. L'algorithme tail drop a l'inconvénient de créer souvent des queues pleines en permanence, au détriment de la latence.

Mais il y a d'autres algorithmes. Le random drop on full jette, lorsque la file est pleine, non pas le dernier paquet mais un paquet au hasard. Cela évite la monopolisation de la file par un seul flot de données mais cela ne résout pas le problème des files toujours pleines. Même chose pour le head drop qui consiste à jeter le premier paquet et non pas le dernier. La bonne solution est donc de ne pas attendre que la file soit pleine pour agir. C'est cette idée qui est à la base de l'AQM. En jetant des paquets avant que la file ne soit remplie (ou bien en les marquant avec ECN, cf. RFC 3168), on va dire indirectement aux machines terminales de ralentir, et on évitera ainsi les files complètement pleines, sauf en cas de brusque pic de trafic.

AQM est donc un concept proactif. Il permet de :

  • Jeter moins de paquets,
  • Réduire l'occupation des files d'attente, et donc la latence, pour le plus grand plaisir des applications interactives,
  • Éviter la monopolisation par un seul flot,
  • Réduire la synchronisation (par l'usage de choix aléatoires).

Tout cela est très bien si les applications utilisent toutes TCP, protocole habitué à réagir à la congestion (en diminuant son débit), et qui protège l'Internet contre les abus. Tant qu'il n'y a que TCP, avec des algorithmes conformes aux recommandations du RFC 5681, tout le monde partage le réseau en bonne intelligence et sans catastrophe, et chacun obtient une part égale de la capacité.

Mais il n'y a pas que TCP dans l'Internet, certains applications utilisent, par exemple, UDP (conseil personnel au passage : le programmeur débutant qui ne connait pas bien les problèmes de congestion devrait n'utiliser que TCP ou un équivalent comme SCTP, afin d'éviter d'écrouler le réseau). On peut classer les flots de données non-TCP en trois catégories :

  • Flots amicaux avec TCP : ce sont ceux qui utilisent des algorithmes de contrôle de la congestion qui, en pratique, leur donnent un débit proche de celui d'un flot TCP (RFC 5348). Par exemple, ce sont des flots UDP envoyés par des applications dont les auteurs ont lu et appliqué le RFC 8085.
  • Flots qui ne réagissent pas à la congestion : ce sont ceux qui continuent à envoyer des paquets sans tenir compte des pertes ou des signalements ECN. Ce sont les « méchants ». Certaines applications de transport de la voix ou de la vidéo sont dans cette catégorie. Jusqu'à présent, la solution anti-congestion à l'IETF avait toujours été d'améliorer les applications. Comme on ne peut pas espérer que 100 % des applications soient bien élevées, il faudra un jour développer des solutions pour gérer ceux qui abusent.
  • Flots qui réagissent, mais pas aussi bien que TCP : ils ont un mécanisme de réaction à la congestion mais ce mécanisme est trop peu réactif, et ces flots prennent donc une part disproportionnée du trafic. Cela peut être le résultat d'une maladresse du programmeur (voir mon conseil plus haut : utilisez TCP, sauf si vous êtes vraiment très fort en contrôle de congestion). Mais cela peut être aussi délibéré, pour s'assurer une plus grosse part du gâteau. Par exemple, certaines mises en œuvre de TCP étaient plus agressives que la normale, peut-être pour que le vendeur puisse proclamer que son TCP était « plus rapide ». On est dans une problématique très proche de celle de nombreux problèmes écologiques : si peu de gens trichent, les tricheurs et les égoïstes ont un gros avantage. Mais s'ils entrainent les autres, une spirale de la triche se développe, jusqu'au point où c'est l'enfer pour tout le monde. Pour l'Internet, une telle spirale pourrait aller jusqu'au cas où il n'y aurait plus de réaction à la congestion du tout, chacun poussant ses octets au maximum, sans tenir compte de l'intérêt collectif.

La section 4 de notre RFC résume les recommandations actuelles :

  • Il faut faire de l'AQM,
  • Ce serait bien de ne pas seulement jeter les paquets mais aussi de pouvoir faire de l'ECN,
  • L'administrateur système ou réseaux ne devrait pas avoir à faire de réglages manuels (tuning), tout devrait s'ajuster automatiquement,
  • L'AQM doit répondre à la congestion effective, pas à ce que le routeur croit savoir sur l'application ou sur le protocole de transport (c'est également impératif pour la neutralité de l'Internet),
  • Le problème des flots délibérement égoïstes est très important, et nécessite davantage de recherche.

Le reste de la section 4 détaille chacune de ces recommandations.

Par exemple, la seconde vient du fait qu'il n'y avait au début qu'un seul moyen pour un routeur de signaler la congestion : jeter des paquets (ce qui était de toute façon nécessaire : quand il n'y a plus de place, il n'y a plus de place). L'ajout d'ECN, dans le RFC 3168, et les spécifications de son usage (voir par exemple le RFC 6679) ont ajouté un deuxième moyen, qui permet de réagir avant qu'on perde des paquets. (Le RFC note que retarder les paquets, ce que fait la file d'attente, peut aussi être vu comme un signal : l'augmentation du RTT va mener TCP à ajuster son débit.)

La recommandation comme quoi le tuning (par le biais de paramètres numériques qu'il faudrait ajuster pour obtenir l'effet idéal) ne doit pas être obligatoire est discutée en section 4.3. Elle vient de l'expérience ce certaines mises en œuvre d'AQM où le pauvre administrateur du routeur devait absolument fixer certains paramètres, alors qu'il manque de temps et qu'il n'est pas forcément expert en congestion. En environnement de production, il n'est pas réaliste d'espérer que le dit administrateur passe ses nuits à faire du tuning ; l'algorithme doit avoir des paramètres par défaut raisonnables et, pour le reste, doit s'ajuster tout seul, en tenant compte d'informations comme la capacité des interfaces du routeur, et de variables mesurées en cours de route comme la durée moyenne de séjour des paquets dans la file d'attente ou le pourcentage de paquets jetés. (Un des problèmes de RED est justement la difficulté à s'ajuster automatiquement.)

Cela n'interdit pas au programmeur de fournir des mécanismes permettant le tuning manuel (ainsi que des outils pour aider l'administrateur à prendre ses décisions) mais ces mécanismes ne doivent pas être indispensables.

Pour la recommandation d'objectivité (décider en fonction de ce qu'on observe, pas de ce qu'on suppose), il est utile de relire le RFC 7141. Par exemple, il ne faut pas tenir compte de la taille des paquets. De même, il ne faut pas supposer que toutes les applications utilisent TCP.

Enfin, sur la recommendation de continuer les recherches, la section 4.7 fournit un programme aux chercheurs qui se demandent sur quel sujet travailler : il reste encore beaucoup de travail.

La section 1.4 de notre RFC décrit les changements depuis le RFC 2309. Les deux plus importants sont :

  • La taille d'une file d'attente n'est plus forcément évaluée uniquement en octets. Elle peut l'être en temps passé par le paquet dans la queue.
  • L'algorithme RED n'est plus le seul recommandé pour gérer les files d'attente.

Téléchargez le RFC 7567


L'article seul

RFC 7565: The 'acct' URI Scheme

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : P. Saint-Andre (Cisco System)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 23 mai 2015


Hop, encore un nouveau plan d'URI, le plan acct: (pour account) qui permet de désigner les informations qu'on peut récupérer sur un compte utilisateur. Désormais, acct:stephane@seenthis.net désignera donc mon compte à SeenThis.

Ne vous fiez pas à la ressemblance syntaxique avec les adresses de courrier : la syntaxe est la même (nom-du-compte@nom-du-service) mais les URI acct: sont indépendants du protocole d'accès. Dans l'exemple plus haut, SeenThis ne fournit pas de service de courrier, mais cela ne change rien à l'URI.

Le premier (et pour l'instant quasi-unique) demandeur de ces URI est le protocole WebFinger (RFC 7033). WebFinger permet d'accéder à des informations, via un protocole REST, en utilisant comme identificateur un URI qui, en pratique, est souvent un URI acct:. La version initiale de WebFinger utilisait uniquement des adresses de courrier électronique. Avant le plan acct:, les plans les plus proches identifiaient toujours un protocole particulier : le courrier pour les URI mailto: (RFC 6068) ou XMPP pour les xmpp:... du RFC 5122. Après moultes discussions au sein du groupe de travail sur WebFinger entre les partisans de l'ancien système (adresses de courrier seulement) et ceux d'un nouveau, fondé sur les URI (eux-même divisés entre amateurs de mailto: et fanas de http:), le choix a été fait de créer ce nouveau plan. Comme indiqué, il a l'avantage de ne pas supposer l'existence d'un protocole particulier. Ainsi, mon compte Twitter est désormais acct:bortzmeyer@twitter.com et il n'implique pas que Twitter fournisse du courrier ou de la messagerie instantanée ou quoi que ce soit d'autre.

À noter qu'un URI acct: identifie un compte, que son titulaire soit un humain ou une organisation ou un bot.

La section 4 fournit la définition rigoureuse de ces nouveaux URI (la syntaxe formelle étant repoussée en section 7). Elle rappelle qu'ils servent à l'identification et pas à l'interaction (RFC 3986, section 1.2.2). La partie gauche (à gauche du @) est le nom du compte auprès d'un fournisseur quelconque et la partie droite est un nom de domaine de ce fournisseur. Donc, acct:foobar@status.example.net, acct:user@example.com ou acct:hamlet@dk sont tous des URI valides. Si un client WebFinger cherche de l'information sur le premier de ces URI, il fera une requête HTTP à status.example.net :

GET /.well-known/webfinger?resource=acct%3Afoobar%40status.example.net HTTP/1.1

Si le nom du compte est une adresse de courrier (ce qui est fréquent sur le Web d'aujourd'hui), il faudra convertir le @ en caractères pour-cent. Par exemple, si le compte juliet@capulet.example existe chez le fournisseur shoppingsite.example, l'URI sera acct:juliet%40capulet.example@shoppingsite.example. Et si on prend mon compte au RIPE-NCC, bortzmeyer+ripe@nic.fr, l'URI sera acct:bortzmeyer%2Bripe%40nic.fr@ripe.net. C'est cet URI qui sera mis, par exemple, dans les requêtes WebFinger.

La section 5 du RFC traite des problèmes de sécurité. On ne met évidemment dans une réponse WebFinger que ce qu'on veut bien indiquer, surtout si le client HTTP n'est pas authentifié. Mais il existe un risque plus subtil : même si le client n'arrive pas à accéder aux informations derrière l'URI acct:, la seule existence de cet URI peut indiquer que le compte existe et cela peut donc être utile aux spammeurs et autres nuisibles. Bref, même si les acct: ne sont que des URI, que des identificateurs, ils peuvent en dire trop.

La section 6, elle, se penche sur l'internationalisation. Les URI acct: sont des URI comme les autres (RFC 3986) et peuvent donc contenir n'importe quel caractère Unicode. Il faut simplement qu'ils soient encodés en UTF-8 puis surencodés en pour-cent. Ainsi, un compte stéphane sur le service example.com pourra être représenté par acct:st%C3%A9phane@example.com. Quelques restrictions toutefois :

  • Le nom de compte est limité aux caractères autorisés par le RFC 8264, dans la classe IdentifierClass.
  • Le nom de domaine après le @ est limité aux caractères IDN autorisés dans le RFC 5892, et encodé en Punycode. Ainsi, le compte stéphane sur le service académie-française.fr sera acct:st%C3%A9phane@xn--acadmie-franaise-npb1a.fr.

La section 7 de notre RFC contient le formulaire d'enregistrement du nouveau plan (selon la procédure du RFC 4395), qui inclut la syntaxe formelle de ces URI, en ABNF. acct: est donc désormais dans le registre officiel des URI.

Si vous voulez voir des exemples réels, le mieux est de regarder le monde WebFinger, par exemple les exemples dans mon article sur le RFC 7033.

L'importance de ce plan d'URL acct: avait été décrite dans un article d'Eran Hammer de 2009 (c'est long, la normalisation).


Téléchargez le RFC 7565


L'article seul

RFC 7564: PRECIS Framework: Preparation, Enforcement, and Comparison of Internationalized Strings in Application Protocols

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : P. Saint-Andre (&yet), M. Blanchet (Viagenie)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF precis
Première rédaction de cet article le 7 juin 2015


Dans la longue marche vers une plus grande internationalisation de l'Internet, la question des identificateurs (comme par exemple les noms de domaine) a toujours été délicate. Ce sont en effet à la fois des éléments techniques, traités automatiquement par les programmes, et des marqueurs d'identité, vus par les humains (par exemple sur des cartes de visite) et manipulés par eux. Jusqu'à présent, chaque protocole internationalisait ses identificateurs comme il le souhaitait. Ce RFC du groupe de travail PRECIS tente une approche unificatrice, en élaborant des règles qui peuvent servir à de larges classes d'identificateurs, pour de nombreux protocoles différents. (Il a depuis été remplacé par le RFC 8264.)

Cette opposition entre « éléments techniques » et « textes prévus pour l'utilisateur » est au cœur du RFC 2277 qui pose comme principe politique qu'on internationalise les seconds, mais pas les premiers. Cet excellent principe achoppe souvent sur la question des identificateurs, qui sont les deux à la fois. D'un côté, les programmes doivent les traiter (les identificateurs doivent donc être clairement définis, sans ambiguité), de l'autre les humains les voient, les communiquent, les échangent (les identificateurs doivent donc permettre, sinon toutes les constructions du langage humain, en tout cas un sous-ensemble d'Unicode qui parait raisonnable aux humains ordinaires : pas question d'imposer stephane comme nom de login à un utilisateur nommé Stéphane, avec un accent sur le E). C'est cette double nature des identificateurs (ainsi, il est vrai, que l'énorme couche de bureaucratie qui gère les noms de domaine) qui explique la durée et la vivacité des discussions sur les IDN.

Maintenant que ces IDN existent (depuis plus de douze ans, RFC 3490), que faire avec les autres identificateurs ? Une possibilité aurait été que chaque protocole se débrouille avec ses propres identificateurs, comme l'a fait le DNS avec les noms de domaine. Mais cela menait à une duplication du travail (et tous les auteurs de protocole ne sont pas des experts Unicode) et surtout à un risque de choix très différents : certains protocoles autoriseraient tel caractère Unicode et d'autres pas, sans que l'utilisateur ordinaire puisse comprendre clairement les raisons de cette différence. L'idée de base du groupe PRECIS est donc d'essayer de faire des règles qui s'appliqueraient à beaucoup de protocoles, épargnant aux concepteurs de ces protocoles de les concevoir eux-mêmes, et offrant à l'utilisateur une certaine homogénéité. Le premier RFC de PRECIS était la description du problème, dans le RFC 6885. Le second est la normalisation du cadre de définition des identificateurs internationalisés, dans ce RFC 7564. Ce cadre permet la manipulation d'identificateurs internationalisés (par exemple leur comparaison, comme lorsqu'un utilisateur tape son nom et son mot de passe, et qu'il faut les vérifier). Il remplace complètement l'ancien système stringprep du RFC 3454.

Le nom du groupe de travail PRECIS reflète les trois fonctions essentielles que vont faire les programmes qui manipulent les identificateurs internationalisés :

  • PRE pour la préparation des identificateurs, les opérations préliminaires comme la conversion depuis un jeu de caractères local non-Unicode,
  • E pour la vérification (enforcement) des règles, afin de déterminer si une chaîne de caractères Unicode est légale ou pas pour un usage donné,
  • C pour la comparaison entre les identificateurs, afin de déterminer leur égalité (« cette ressource n'est accessible qu'à l'utilisateur Thérèse or elle est connectée avec le nom therese »),
  • Le IS final étant pour Internationalized Strings.

A priori, les serveurs Internet seront responsables de la vérification, les clients n'ayant à faire qu'une préparation. Ayant souvent moins de ressources, les clients pourraient en effet avoir du mal à faire certaines opérations Unicode complexes (section 3).

Stringprep (RFC 3454) avait été développé pour le système IDN (RFC 3490) mais était conçu pour être généraliste, et certaines applications n'ayant rien à voir avec les noms de domaine avaient utilisé stringprep. Ce dernier avait des limites, certaines font l'objet d'un consensus, comme le fait que stringprep était lié à une version particulière d'Unicode, ce qui l'empêchait d'évoluer automatiquement lorsque le consortium Unicode publiait une nouvelle version (la version actuelle est la version 7, la plus récente est toujours à l'URL http://www.unicode.org/versions/latest/). D'autres limites étaient plus contestées (RFC 4690). IDN n'utilise plus stringprep depuis le RFC 5890.

Les principes du travail de PRECIS sont :

  • Définir un petit nombre (deux, actuellement) de classes spécifiant un jeu de caractères autorisés, classes applicables à un grand nombre d'usages.
  • Définir le contenu de ces classes en fonction d'un algorithme, reposant sur les propriétés Unicode (contrairement à stringprep où le contenu des classes était énuméré dans le RFC). Ainsi, lorsqu'une nouvelle version d'Unicode sort, il suffit de refaire tourner l'algorithme et on obtient le contenu à jour de la classe.
  • Spécifier les classes par une inclusion : tout caractère non explicitement listé comme membre de la classe est automatiquement exclu.
  • Permettre aux protocoles applicatifs de définir un profil d'une classe, à savoir une restriction de ses membres, ou bien d'autres précisions sur des sujets comme la normalisation Unicode. Il y aura ainsi probablement un profil pour les noms d'utilisateurs, un profil pour les mots de passe, etc. Notez qu'il est prévu que le nombre de profils reste limité, pour ne pas réintroduire l'excessive variété que voulait justement éviter PRECIS.

Si tout va bien, ces principes permettront l'indépendance vis-à-vis des versions d'Unicode (ou, plus exactement, la possibilité de passer à une nouvelle version d'Unicode sans faire une nouvelle norme incompatible), le partage des tables et du logiciel entre applications (par exemple par le biais de bibliothèques communes, utilisables si toutes les applications reposent sur PRECIS), et moins de surprises pour les utilisateurs, qui auraient été bien embêtés si chaque protocole Internet avait eu une manière complètement différente de prévoir l'internationalisation.

Bien, quelles sont donc les classes prévues par PRECIS (section 4) ? L'idée est de faire un compromis entre expressivité et sécurité. Qu'est-ce que la sécurité vient faire là dedans ? Personne ne le sait trop (le RFC utilise plusieurs fois safe et safety sans expliquer face à quels risques) mais Unicode fait souvent peur aux informaticiens anglo-saxons et il est donc courant d'estimer qu'il existe des caractères dangereux.

Il y a donc deux classes en tout et pour tout dans PRECIS : IdentifierClass et FreeformClass. La première classe servira à identifier utilisateurs, machines, pièces de discussions en messagerie instantanée, fichiers, etc, et ne permettra que les lettres, les nombres et quelques symboles (comme le ! ou le +). C'est contraignant mais l'idée est qu'on veut des désignations simples et sans ambiguïté, pas écrire des romans. La seconde classe servira à tout le reste (mots de passe, textes affichés comme la description d'une pièce XMPP, nom complet d'une machine, etc). Par exemple, une imprimante sera imprimante-jean-et-thérèse pour les protocoles qui demandent un nom de la classe IdentifierClass et Imprimante de Jean & Thérèse lorsqu'on pourra utiliser un nom FreeformClass.

Les classes sont définies par les caractères inclus et exclus. Plus précisément, un caractère peut être, pour une classe donnée (voir aussi la section 8) :

  • Valide (ou PVALID pour Protocol Valid),
  • Interdit,
  • Autorisé dans certains contextes seulement, c'est-à-dire que l'autorisation dépendra des caractères voisins (pas facile de trouver un exemple dans l'alphabet latin, cela sert surtout à d'autres écritures),
  • Pas encore affecté dans Unicode.

La classe IdentifierClass se définit donc par :

  • Caractères valides : les lettres et chiffres (rappelons qu'on définit des identificateurs internationalisés : on ne se limite donc pas aux lettres et chiffres latins), et les symboles traditionnels, ceux d'ASCII (comme le tiret ou le tilde).
  • Caractères valides dans certains contextes : ceux de la rare catégorie JoinControl du RFC 5892, section 2.8.
  • Caractères interdits : tout le reste (espaces, ponctuation, la plupart des symboles...).
  • Les caractères non encore affectés sont également interdits.

La classe Freeform Class se définit, elle, par :

  • Caractères valides : les lettres et chiffres (rappelons qu'on définit des identificateurs internationalisés : on ne se limite donc pas aux lettres et chiffres latins), les espaces, la ponctuation, les symboles.
  • Caractères valides dans certains contextes : ceux de la catégorie JoinControl plus quelques exceptions.
  • Caractères interdits : tout le reste, ce qui fait surtout les caractères de contrôle comme U+0007 (celui qui fait sonner votre ordinateur).
  • Les caractères non encore affectés sont également interdits.

Ces listes de caractères autorisés ou interdits ne sont pas suffisantes. Il y a d'autres points à régler (section 5), ce qui se fait typiquement dans les profils. Ainsi, un profil doit définir :

  • Normalisation Unicode à utiliser. NFC est recommandé.
  • La correspondance entre les caractères et leur version large (width mapping). Est-ce que FULLWIDTH DIGIT ZERO (U+FF10) doit être considéré comme équivalent au zéro traditionnel, de largeur « normale », U+0030 ? Notez que certaines normalisations (mais qui ne sont pas celle recommandée), comme NFKC, règlent le problème. Autrement, la recommandation du RFC est « oui, il faut rendre ces caractères équivalents » car l'utilisateur serait certainement surpris que target0 et target0 soient considérés différents (le fameux POLA).
  • D'autres correspondances peuvent être spécifiées par le profil (comme de transformer tous les espaces Unicode en l'espace traditionnel ASCII U+0020).
  • Changement de la casse des caractères, par exemple pour tout mettre en minuscules. Si c'est décidé pour un profil, le RFC recommande que cela soit fait avec la méthode Unicode standard, « Default case folding » (section 3 de la norme Unicode). Attention, cette méthode Unicode ne gère pas des cas qui dépendent de la langue, dont le plus fameux est le i sans point du turc (U+0131 c'est-à-dire ı). Le changement de casse est évidemment déconseillé pour les mots de passe (puisqu'il diminue l'entropie).
  • Interdiction de certains mélanges de caractères de directionnalité différentes. Il y a des écritures qui vont de gauche à droite et d'autres de droite à gauche, et leur combinaison peut entrainer des surprises à l'affichage. Dans certains cas, un profil peut vouloir limiter ce mélange de directionnalités.

Un profil peut également interdire certains caractères normalement autorisés (mais pas l'inverse).

Au passage, pour la comparaison, le RFC (section 7) impose un ordre à ces opérations. Par exemple, la mise en correspondance de la version large sur la version normale doit se faire avant l'éventuel changement de casse. C'est important car ces opérations ne sont pas commutatives entre elles.

Les profils sont enregistrés à l'IANA. Le RFC met bien en garde contre leur multiplication : toute l'idée de PRECIS est d'éviter que chaque protocole ne gère l'internationalisation des identificateurs de manière différente, ce qui empêcherait la réutilisation de code, et perturberait les utilisateurs. Si on avait un cadre commun mais des dizaines de profils différents, on ne pourrait pas dire qu'on a atteint cet objectif. Par exemple, en matière d'interface utilisateur, PRECIS essaie de s'en tenir au POLA (Principle of Least Astonishment) et ce principe serait certainement violé si chaque application trouvait rigolo d'interdire un caractère ou l'autre, sans raison apparente. Le RFC estime d'ailleurs (section 5.1) qu'il ne devrait y avoir idéalement que deux ou trois profils. Mais ce n'est pas possible puisque les protocoles existent déjà, avec leurs propres règles, et qu'on ne peut pas faire table rase de l'existant (tous les protocoles qui ont déjà définis des caractères interdits, comme IRC, NFS, SMTP, XMPP, iSCSI, etc).

Un petit point en passant, avant de continuer avec les applications : vous avez noté que la classe IdentifierClass interdit les espaces (tous les espaces Unicode, pas seulement le U+0020 d'ASCII), alors que certaines applications acceptent les espaces dans les identificateurs (par exemple, Unix les accepte sans problèmes dans les noms de fichier, Apple permet depuis longtemps de les utiliser pour nommer Macintoshes et imprimantes, etc). La section 5.3 explique pourquoi :

  • Il est très difficile de distinguer tous ces espaces entre eux,
  • Certains interfaces utilisateurs risquent de ne pas les afficher, menant à confondre françoise durand avec françoisedurand.

C'est embêtant (toute contrainte est embêtante) mais le compromis a semblé raisonnable au groupe PRECIS.

Passons maintenant aux questions des développeurs d'applications (section 6 du RFC). Que doivent-ils savoir pour utiliser PRECIS correctement ? Idéalement, il suffirait de lier son code aux bonnes bibliothèques bien internationalisées et tout se ferait automatiquement. En pratique, cela ne se passera pas comme ça : sans être obligé de lire et de comprendre tout le RFC, le développeur d'applications devra quand même réflechir un peu à l'internationalisation de son programme :

  • Il est très déconseillé de créer son propre profil. Non seulement c'est plus compliqué que ça n'en a l'air, mais ça risque de dérouter les utilisateurs, si votre application a des règles légèrement différentes des règles des autres applications analogues.
  • Précisez bien quel partie de l'application va être responsable pour la préparation, la vérification et la comparaison. Par exemple, le travail de vérification sera-t-il fait par le client ou par le serveur ? Demandez-vous aussi à quel stade les applications devront avoir fait ce travail (par exemple, en cas de login, avant de donner un accès).
  • Définissez bien, pour chaque utilisation d'un identificateur (chaque slot, dit le RFC), quel profil doit être utilisé. Par exemple, « le nom du compte doit être conforme au profil UsernameCaseMapped de la classe IdentifierClass ».
  • Dressez la liste des caractères interdits (en plus de ceux déjà interdits par le profil) en fonction des spécificités de votre application. Par exemple, un @ est interdit dans la partie gauche d'une adresse de courrier électronique.

Sur ce dernier point, il faut noter que la frontière est mince entre « interdire plusieurs caractères normalement autorisés par le profil » et « définir un nouveau profil ». La possibilité d'interdire des caractères supplémentaires est surtout là pour s'accomoder des protocoles existants (comme dans l'exemple du courrier ci-dessus), et pour éviter d'avoir un profil par application existante.

Votre application pourra avoir besoin de constructions au dessus des classes existantes. Par exemple, si un nom d'utilisateur, dans votre programme, peut s'écrire « Prénom Nom », il ne peut pas être une instance de la classe IdentifierClass, qui n'accepte pas les espaces pour la raison indiquée plus haut. Il faudra alors définir un concept « nom d'utilisateur », par exemple en le spécifiant comme composé d'une ou plusieurs instances de IdentifierClass, séparées par des espaces. En ABNF :

username   = userpart *(1*SP userpart)
userpart   = ... ; Instance d'IdentifierClass

La même technique peut être utilisée pour spécifier des identificateurs qui ne seraient normalement pas autorisés par IdentifierClass comme stéphane@maçonnerie-générale.fr ou /politique/séries/Game-of-Thrones/saison05épisode08.mkv.

On a vu plus haut qu'un des principes de PRECIS était de définir les caractères autorisés de manière algorithmique, à partir de leur propriétés Unicode, et non pas sous la forme d'une liste figée (qu'il faudrait réviser à chaque nouvelle version d'Unicode). Les catégories de caractères utilisées par cet algorithme sont décrites en section 9. Par exemple, on y trouve :

  • LettersDigits qui rassemble les chiffres et les lettres. (Rappelez-vous qu'on utilise Unicode : ce ne sont pas uniquement les lettres et les chiffres d'ASCII.)
  • ASCII7, les caractères d'ASCII, à l'exception des caractères de contrôle,
  • Spaces, tous les espaces possibles (comme le U+200A, HAIR SPACE, ainsi appelé en raison de sa minceur),
  • Symbols, les symboles, comme U+20A3 (FRENCH FRANC SIGN, ₣) ou U+02DB (OGONEK, ˛),
  • Etc.

Plusieurs registres IANA sont nécessaires pour stocker toutes les données nécessaires à PRECIS. La section 11 les recense tous. Le plus important est le PRECIS Derived Property Value, qui est recalculé à chaque version d'Unicode. Il indique pour chaque caractère s'il est autorisé ou interdit dans un identificateur PRECIS. Voici sa version pour Unicode 6.3. (La version 7 est retardée par une tempête dans un verre d'eau.)

Les deux autres registres stockent les classes et les profils (pour l'instant, aucun). Les règles d'enregistrement dans le premier sont strictes (un RFC est nécessaire) et celles dans le second bien plus ouvertes (un examen par un expert est nécessaire).

La section 12 est consacrée aux problèmes de sécurité qui, comme toujours lorsqu'il s'agit d'Unicode, sont plus imaginaires que réels. Un des problèmes envisagés est celui du risque de confusion entre deux caractères qui sont visuellement proches. Le problème existe déjà avec le seul alphabet latin (vous voyez du premier coup la différence entre google.com et goog1e.com ?) mais est souvent utilisé comme prétexte pour retarder le déploiement d'Unicode. PRECIS se voulant fidèle au principe POLA, le risque de confusion est considéré comme important. Notez que le risque réel dépend de la police utilisée. Unicode normalisant des caractères et non pas des glyphes, il n'y a pas de solution générale à ce problème dans Unicode (les écritures humaines sont compliquées : c'est ainsi). Si le texte ᏚᎢᎵᎬᎢᎬᏒ ressemble à STPETER, c'est que vous utilisez une police qui ne distingue pas tellement l'alphabet cherokee de l'alphabet latin. Est-ce que ça a des conséquences pratiques ? Le RFC cite le risque accru de hameçonnage, sans citer les nombreuses études qui montrent le contraire (cf. le Unicode Technical Report 36, section 2, « the use of visually confusable characters in spoofing is often overstated », et la FAQ de sécurité d'Unicode).

Quelques conseils aux développeurs concluent cette partie : limiter le nombre de caractères ou d'écritures qu'on accepte, interdire le mélange des écritures (conseil inapplicable : dans la plupart des alphabets non-latins, on utilise des mots entiers en alphabet latin)... Le RFC conseille aussi de marquer visuellement les identificateurs qui utilisent plusieurs écritures (par exemple en utilisant des couleurs différentes), pour avertir l'utilisateur.

C'est au nom de ce principe POLA que la classe IdentifierClass est restreinte à un ensemble « sûr » de caractères (notez que ce terme « sûr » n'est jamais expliqué ou défini dans ce RFC). Comme son nom l'indique, FreeformClass est bien plus large et peut donc susciter davantage de surprises.

PRECIS gère aussi le cas des mots de passe en Unicode. Un bon mot de passe doit être difficile à deviner ou à trouver par force brute (il doit avoir beaucoup d'entropie). Et il faut minimiser les risques de faux positifs (un mot de passe accepté alors qu'il ne devrait pas : par exemple, des mots de passe insensibles à la casse seraient agréables pour les utilisateurs mais augmenteraient le risque de faux positifs). L'argument de l'entropie fait que le RFC déconseille de créer des profils restreints de FreeformClass, par exemple en excluant des catégories comme la ponctuation. Unicode permet des mots de passe vraiment résistants à la force brute, comme « 𝃍🐬ꢞĚΥਟዶᚦ⬧ »... D'un autre côté, comme le montre l'exemple hypothétique de mots de passe insensibles à la casse, il y a toujours une tension entre la sécurité et l'utilisabilité. Laisser les utilisateurs choisir des mots de passe comportant des caractères « exotiques » peut poser bien des problèmes par la suite lorsqu'utilisateur tentera de les taper sur un clavier peu familier. Il faut noter aussi que les mots de passe passent parfois par des protocoles intermédiaires (comme SASL, RFC 4422, ou comme RADIUS, RFC 2865) et qu'il vaut donc mieux que tout le monde utilise les mêmes règles pour éviter des surprises (comme un mot de passe refusé par un protocole intermédiaire).

Enfin, la section 13 de notre RFC se penche sur l'interopérabilité. Elle rappele qu'UTF-8 est l'encodage recommandé (mais PRECIS est un cadre, pas un protocole complet, et un protocole conforme à PRECIS peut utiliser un autre encodage). Elle rappelle aussi qu'il faut être prudent si on doit faire circuler ses identificateurs vers d'autres protocoles : tous ne savent pas gérer Unicode, hélas.

Il existe une mise en œuvre de PRECIS en Go : https://godoc.org/golang.org/x/text/secure/precis.


Téléchargez le RFC 7564


L'article seul

RFC 7562: Transport Layer Security (TLS) Authorization Using DTCP Certificate

Date de publication du RFC : Juillet 2015
Auteur(s) du RFC : D. Thakore (CableLabs)
Pour information
Première rédaction de cet article le 10 juillet 2015


Le protocole de sécurité TLS permet différents types d'autorisation et ce RFC en ajoute un nouveau, par la présentation d'un certificat DTCP. DTCP est un mécanisme de menottes numériques, et cette extension à TLS permet désormais « TLS pour les ayant-droits ».

DTCP, également connu sous le nom de 5C, est un système fermé. À l'heure actuelle, une version apparemment à jour de la spécification est disponible. Ce système DTCP est assez répandu dans des télévisions, des tablettes, des consoles de jeu... Les certificats DTCP (qui ne sont pas des certificats X.509) sont émis par DTLA (section 2.1 du RFC).

Le RFC 5878 spécifie l'extension de TLS à d'autres mécanismes d'autorisation. Et le RFC 4680 décrit l'ajout de données supplémentaires (le certificat) dans le message Handshake de TLS.

Le type d'autorisation IANA dtcp_authorization est désormais enregistré à l'IANA.


Téléchargez le RFC 7562


L'article seul

RFC 7558: Requirements for Scalable DNS-SD/mDNS Extensions

Date de publication du RFC : Juillet 2015
Auteur(s) du RFC : K. Lynn (Verizon), S. Cheshire (Apple), M. Blanchet (Viagenie), D. Migault (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnssd
Première rédaction de cet article le 17 juillet 2015


Pour résoudre des noms de domaine en informations (comme l'adresse IP) sur le réseau local, sans configurer de serveur DNS, nous avons mDNS (RFC 6762). Pour découvrir des services (par exemples les imprimantes) avec ce mDNS, nous avons DNS-SD (RFC 6763). Mais ces deux techniques, mDNS et DNS-SD, ne fonctionnent que sur un seul segment du réseau, à l'intérieur d'un domaine de diffusion. Il serait bien pratique de pouvoir les utiliser dans un réseau étendu (comme l'Internet...). Ce RFC décrit le problème, les souhaits et établit une liste d'exigences pour cette extension de mDNS et DNS-SD « au-delà du lien local ». (À l'heure actuelle, on n'a pas encore de solution satisfaisant ces exigences.)

C'est par conception que mDNS (RFC 6762) ne passe pas les routeurs IP. Ce protocole marche par diffusion. On crie à la cantonade « qui connait iPhone-de-Jean-Bernard ? » et la machine qui se reconnait répond. mDNS s'appuie donc sur un service de couche 2, la diffusion, et ne fonctionne donc pas sur un réseau composé de plusieurs segments L2 reliés par des routeurs.

Or, il y a évidemment des cas où on voudrait des services comme ceux fournis par mDNS et DNS-SD au-delà du lien local. Parce que le campus ou l'entreprise où on travaille a plusieurs segments L2 (par exemple un pour le filaire et un pour le WiFi), ou bien parce qu'on travaille avec une association située à des centaines de kilomètres, mais joignable par l'Internet. Il n'existe pas actuellement de solutions standard pour cela. Et pas encore de consensus sur la façon la plus propre de le faire.

Autre cas où on se retrouve facilement coincé, celui de réseaux ad hoc comme les 6LowPAN (RFC 6568) où chaque machine ou presque peut devenir routeur (RFC 4903).

D'ailleurs, même en l'absence de ce problème multi-segments, la technique de mDNS, la diffusion (globale, ou bien restreinte) n'est pas idéale dans tous les cas. Sur de l'Ethernet filaire, la diffusion consomme relativement peu de ressources. Mais, sur certains segments, la diffusion coûte cher. En WiFi, elle peut vite mener à consommer une bonne partie de la capacité, d'autant plus qu'il faut ralentir au niveau du récepteur le plus lent (cf. section 2.2). Au passage, autre problème de 802.11 : il n'y a pas d'accusé de réception des trames diffusées et donc des pertes peuvent se produire.

La section 2 de notre RFC décrit le problème qu'on veut résoudre. D'abord, on voudrait pouvoir découvrir des ressources distantes (comme des imprimantes ou des serveurs de fichier) même si elles ne sont pas sur le même segment L2. Actuellement, la seule solution standard est le DNS classique. Cela nécessite soit une configuration manuelle par l'administrateur système, ce qui fait du travail, surtout en cas de changement (on modifie l'adresse IP de l'imprimante mais on oublie de changer la base DNS : tous les sites n'ont pas forcément un IPAM intégré qui prend en charge tout cela et tous les réseaux ne sont pas centralement gérés). Autre solution avec le DNS classique, autoriser les mises à jour dynamiques du DNS, ce qui implique qu'on configure les imprimantes pour faire ces mises à jour.

Et la solution à ce problème doit marcher pour des cas où on a des centaines ou des milliers de machines, et à un coût raisonnable (y compris le coût pour le réseau en terme de trafic).

Les réseaux contraints (LLN pour Low power and Lossy Networks, cf. RFC 7102) posent des défis particuliers. Ils sont souvent multi-segments, avec des nœuds devenant routeurs pour prolonger la portée des ondes radio, et ne peuvent donc pas se contenter des actuels mDNS et DNS-SD. Mais ils connectent souvent des machines peu dotées en ressources. Celles-ci sont parfois injoignables (hibernation ou déconnexion) et on ne peut donc pas compter sur leur présence permanente. Ainsi, mDNS assure l'unicité des noms par la vérification, par une nouvelle machine, que le nom n'était pas déjà présent sur le réseau. Si le possesseur de ce nom hiberne, il ne pourra pas « défendre » son nom.

La section 3 du RFC présente ensuite quelques scénarios d'usage concrets, pour qu'on se fasse une meilleure idée de cas où mDNS et DNS-SD ne suffisent pas. D'abord, un cas de base, le PAN (Personal Area Network, qui regroupe les machines d'un seul utilisateur, par exemple, dans un cas trivial, son PC portable et son imprimante). Pas de routeur présent, mDNS et DNS-SD suffisent bien et résolvent tous les problèmes. On passe ensuite à un cas un peu plus riche : une maison, avec un routeur qui connecte à un FAI et un réseau local d'un seul segment (il peut y avor plusieurs segments physiques, par exemple filaire et WiFi, mais le routeur, qui fait également point d'accès WiFi, les présente comme un seul réseau L2. C'est le réseau de M. Michu aujourd'hui et, là encore, mDNS et DNS-SD marchent bien.

On passe ensuite au réseau SOHO ou bien à la maison « avancée ». Cette fois, on introduit plusieurs routeurs (RFC 7368). Un tel réseau peut s'auto-organiser (il n'y a typiquement pas d'administrateur réseaux professionnel) mais la résolution de noms devient difficile, mDNS ne fonctionnant plus (il ne passe pas les routeurs).

Ensuite viennent les réseaux d'« entreprise » (en fait, de n'importe quelle grande organisation, entreprise à but lucratif ou pas). Plusieurs routeurs, des réseaux compliqués mais, cette fois, on a des administrateurs réseaux professionnels pour s'en occuper. À noter que les grands réseaux des conférences (comme le réseau WiFi des réunions IETF) rentrent dans cette catégorie. mDNS ne marche plus mais on peut désormais avoir des serveurs DNS administrés sérieusement.

Le RFC cite un cas encore plus élaboré, avec les NREN, qui mèlent administration centrale du réseau national, avec des équipes qui gèrent des réseaux régionaux ou de campus.

Et les réseaux « mesh » ? Ils sont multi-segments mais en général pas administrés, ils posent donc le plus de problèmes.

Bon, assez de préliminaires, les exigences maintenant, le vrai cahier des charges. Il figure en section 4. Les exigences sont notées REQn où N est un numéro de 1 à 15. REQ1, par exemple, dit qu'il faut un mode d'auto-configuration permettant à la future solution de marcher toute seule, pour le cas des réseaux non administrés. Mais attention, le RFC précise aussi que les objectifs de sécurité, de passage à l'échelle, de facilité et de déployabilité sont souvent contradictoires et qu'il ne faut pas prendre les exigences isolément mais en groupe (il faudra parfois en sacrifier une pour atteindre l'autre).

REQ2, complémentaire de REQ1, dit que pour les réseaux administrés, il faut pouvoir configurer le mécanisme de manière à partitionner le réseau, pour éviter qu'une requête ne voyage partout (voir aussi REQ15). REQ3 demande que cette possibilité de partition ne se fasse pas sur des critères topologiques (si on a deux segments dans un même bâtiment et un troisième dans un autre bâtiment, il faut pouvoir faire une partition regroupant un des segments du bâtiment et le segment de l'autre bâtiment, voir aussi REQ7).

Parmi les autres exigences, le fait (REQ5) de réutiliser les protocoles existants, notamment mDNS (RFC 6762) et DNS-SD (RFC 6763), l'obligation de fonctionner sur des réseaux où la consommation électrique est un facteur crucial (REQ10, qui dit en gros que le protocole ne doit pas réveiller toutes les machines toutes les cinq minutes), la nécessité de marcher correctement sur des réseaux de plusieurs milliers de machines (REQ11), l'importance de fournir aux utilisateurs un vécu identique que les ressources qu'ils cherchent soient locales au lien ou au contraire distantes (REQ12), le souhait que l'information présentée audit utilisateur ne soit pas dépassée (pas question de lui montrer les services tels qu'ils étaient il y a deux heures, ou même simplement deux minutes, REQ13), etc.

Après cette liste d'exigences, la section 5 de notre RFC se penche sur un problème délicat, la coexistence de plusieurs espaces de noms. En effet, si on utilise le DNS « normal », les noms sont uniques, et c'est une des propriétés les plus essentielles du DNS (RFC 2826). Mais si on utilise mDNS, chaque segment réseau a ses propres noms, sous le TLD .local. On peut parfaitement avoir une Imprimante-Couleur.local dans un bâtiment et voir une toute autre imprimante sous le même nom dans un autre bâtiment. Les noms ne sont plus mondialement uniques. Comme beaucoup d'engins seront livrés avec des noms par défaut identiques, ces « collisions » seront fréquentes. Le problème reste ouvert (voir aussi la section 6.2).

Enfin, la section 6 du RFC se préoccupe de la sécurité. Bien sûr, l'exigence d'un service automatique et efficace ne va pas forcément dans le sens de la sécurité (difficile d'authentifier sans ennuyer les utilisateurs, par exemple). Mais il y a aussi d'autres pièges. Par exemple, avec le mDNS traditionnel, les requêtes et les réponses ont une portée limitée (au seul segment de réseau local). Si on donne un nom à sa machine, le nom ne sera vu que localement et l'utilisateur peut donc donner un nom ridicule ou grossier sans trop de risques. Avec le projet d'étendre cette résolution de noms plus loin que le réseau local, le nom donné aura davantage de conséquences. Sans même parler du cas de noms à problèmes, une extension de la découverte de services peut faciliter la tâche d'un attaquant (imaginez ce que Shodan ferait d'un tel service) et/ou permettre/faciliter l'accès à des ressources qu'on pensait privées (une imprimante, par exemple). Bien sûr, la découverte d'un service n'implique pas son accessibilité mais le risque est quand même là.

Autre problème, la vie privée. Déjà, aujourd'hui, une technologie comme Bonjour est très bavarde. Un Mac ou un iPhone diffusent à tout le réseau local en donnant le nom de l'utilisateur ("l'iPhone de Jean Durand"). Mais le problème ne peut que s'aggraver si on va plus loin que le réseau local. Ce n'est sans doute pas une bonne idée qu'une machine arrivant dans un réseau inconnu annonce le nom de son propriétaire immédiatement. À noter que, en juillet 2015, une expérience de collecte du trafic diffusé à la réunion IETF de Prague a suscité de nombreuses discussions.


Téléchargez le RFC 7558


L'article seul

RFC 7557: Extension Mechanism for the Babel Routing Protocol

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : J. Chroboczek (PPS, University of Paris-Diderot)
Expérimental
Première rédaction de cet article le 11 juin 2015


Le protocole de routage Babel, spécifié dans le RFC 6126, est désormais doté d'un mécanisme d'extension documenté. Il a depuis été intégré dans la norme Babel, dans le RFC 8966.

Un paquet Babel comprend un en-tête fixe, suivi d'une série de TLV. Babel prévoyait des mécanismes d'extension en réservant certaines valeurs et en précisant le comportement d'un routeur Babel lors de la réception de valeurs inconnues. Ainsi :

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

Bien sûr, ces règles ne garantissent pas à elles seules que les extensions cohabiteront bien. D'où ce nouveau RFC, qui décrit comment utiliser ces possibilités, sans conflit entre deux extensions différentes.

La section 2 décrit toutes les possibilités d'extensions propres. Cela commence par une nouvelle version du protocole (l'actuelle version est la 2), qui utiliserait des numéros 3, puis 4...

Moins radicale, une extension de la version 2 peut introduire de nouveaux TLV (qui seront ignorés par les mises en œuvre anciennes de la version 2). Ces nouveaux TLV doivent suivre le format de la section 4.3 du RFC 6126.

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

Babel a aussi six bits libres dans les TLV de type Update (champ Flags, RFC 6126, section 4.4.9). Notre RFC déconseille de les utiliser, pour l'instant.

Enfin, après le dernier TLV (Babel est transporté sur UDP, qui indique une longueur explicite), on peut encore ajouter des données. L'idée était d'y mettre une signature cryptographique mais le système d'authentification de Babel, spécifié dans le RFC 8967, se sert plutôt de nouveaux TLV. Cet espace potentiel est donc inutilisé pour l'instant.

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

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

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


Téléchargez le RFC 7557


L'article seul

RFC 7556: Multiple Provisioning Domain Architecture

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : D. Anipko
Pour information
Réalisé dans le cadre du groupe de travail IETF mif
Première rédaction de cet article le 16 juin 2015


Ce RFC décrit une architecture nouvelle permettant de mieux gérer les machines ayant plusieurs connexions à l'Internet. On ne parle pas ici de gros routeurs ou serveurs connectés à plusieurs réseaux, non, un simple smartphone qui a à la fois le WiFi et la 4G est un exemple d'une machine qui a plusieurs interfaces. Et cela pose des sérieux problèmes avec l'Internet d'aujourd'hui, car, parfois, chaque interface va nécessiter des réglages différents. Notre nouvelle architecture aborde ce problème en définissant le PvD (ProVisioning Domain ou domaine d'avitaillement), un ensemble cohérent de réglages, qui sera attaché à chaque interface.

Pourquoi est-ce un problème d'avoir plusieurs interfaces actives ? Car certains réglages ne sont valables que pour une seule interface, alors que TCP/IP considérait au début que toutes les interfaces se valaient et pouvaient être utilisées. Par exemple, l'adresse IP obtenue sur une interface ne doit pas être utilisée comme adresse IP source sur une autre interface, de peur de se faire mordre par le RFC 2827. Le résolveur DNS obtenu sur une interface ne doit pas être utilisé pour une autre car il refusera probablement de répondre (RFC 5358). Et, même si les résolveurs DNS acceptaient tous les clients, il arrive qu'ils renvoient des données qui ne sont pas les mêmes pour tout le monde (par exemple pour un serveur qui n'est accessible que depuis un certain réseau). Le RFC 6418 décrit plus en détail le problème des interfaces multiples, et le RFC 6419 proposait déjà quelques solutions, chacune spécifique à une plate-forme donnée. Pour résumer (à l'extrême) le RFC 6418, les risques sont :

  • Incohérence entre les informations obtenues depuis les différentes interfaces (comme dans l'exemple DNS ci-dessus),
  • Risque de mélanger les informations obtenues sur différentes interfaces (tenter de résoudre le nom d'un relais avec le serveur DNS d'un autre opérateur...),
  • Usage non conforme à la politique d'un des réseaux (par exemple, téléchargement d'un jeu via le VPN de l'entreprise...)

Donc, pour résoudre ce genre de problème, on introduit le concept de PvD. Mais c'est quoi, un PvD (section 2) ? Un ProVisioning Domain est simplement un ensemble cohérent d'informations de configuration d'un réseau, pour une interface donnée. Cela comprend par exemple l'adresse IP à utiliser (ou le préfixe IP), les adresses IP des résolveurs DNS, le routeur par défaut, le proxy Web à utiliser, etc. Une machine PvD-aware sait gérer cette information (notamment en l'association à une interface et en gardant en mémoire que, par exemple, ce résolveur DNS est fait pour cette interface). Une application PvD-aware a du code pour gérer la coexistence de différents PvD.

Aujourd'hui, les PvD sont implicites. La machine connectée reçoit de l'information de configuration sur chaque interface, via des processus divers (DHCP, mais pas seulement), et cette information n'est pas groupée, sous l'étiquette d'un PvD donné. C'est à la machine PvD-aware de gérer une table de PvD en les nommant et en les associant à chaque interface. Par défaut, avec les PvD implicites, une interface = un PvD.

Mais il y aura plus tard des PvD explicites. Cette distinction entre PvD implicites et explicites est essentielle. L'idée est de développer via l'IETF des mécanismes (comme celui du RFC 8801) pour communiquer à la machine des PvD explicites, regroupant sous un nom donné un jeu d'informations de configuration cohérentes. Par exemple, on peut imaginer une option DHCP qui indique le nom du PvD correspondant aux options de configuration contenues dans cette réponse DHCP (ce n'est qu'une hypothèse : le RFC liste d'autres possibilités, cf. section 3). Avec les PvD explicites, il n'y aura plus forcément une interface = un PvD. On pourra avoir plusieurs interfaces utilisant le même PvD (si elles sont gérées par la même organisation).

Cela impliquera un système (non encore défini) de nommage des PvD. Le « PvD ID » devra être unique (puisque le but est de différencier les informations de configuration de réseaux différents), par exemple en le tirant au hasard dans un espace de grande taille. Le PvD ID ne sera donc pas forcément lisible par un humain ; si on veut une telle lisibilité, il faudra développer une solution, par exemple de métadonnées associées au PvD.

Un PvD peut être commun à plusieurs familles IP (par exemple IPv4 et IPv6) et comporter donc plusieurs adresses. C'est utile si certaines options ont un sens pour plusieurs familles (c'est le cas de la politique de sélection de l'adresse du RFC 7078). Pour les PvD implicites, utiliser un seul PvD pour toutes les familles présentes sur l'interface est la politique recommandée.

La section 3 examine quelques protocoles existants pour voir comment ils pourraient être modifiés pour transporter de l'information explicite sur les PvD. Aujourd'hui, la configuration des machines terminales est faite en général par DHCP (RFC 8415) ou RA (RFC 3971). Notons qu'elles ne sont pas sécurisées par défaut. Des solutions existent pour authentifier la machine qui émet la réponse DHCP ou RA mais authentification n'est pas autorisation : elle ne nous dit pas si cette machine est autorisée à annoncer explicitement tel PvD. Pour cela, il faudrait un moyen de signer les PvD.

Évidemment, si on ajoute des mécanismes de PvD à ces protocoles, cela devra être fait d'une manière compatible avec les machines existantes, qui ne sont pas PvD-aware. Pendant la phase de coexistence, il faudra peut-être dupliquer de l'information dans les réponses DHCP ou RA, pour satisfaire tout le monde.

La section 4 du RFC présente trois études de cas concrètes. La première est celle d'une machine mobile, un smartphone, par exemple. Il a une interface avec un réseau mobile, mettons 3G, et une interface WiFi. S'il est dehors, loin de tout hotspot, il n'aura qu'une interface active et donc un seul PvD : pas de difficultés. S'il s'approche d'un point d'accès WiFi et s'y connecte, le dilemme commence : quelle interface utiliser ? Android, par exemple, ne peut en utiliser qu'une à la fois et va donc cesser d'utiliser la 3G. Cela simplifie le modèle de connexion pour les développeurs mais n'est pas satisfaisant pour l'utilisateur. Il serait plus satisfaisant de pouvoir utiliser les deux, mais en respectant à chaque fois le PvD (qui peut être différent) de chaque interface.

Autre étude de cas, un VPN, qui peut être considéré comme une interface supplémentaire, quoique virtuelle, et un réseau à la maison, connecté à la fois à un FAI généraliste classique et à un service de VoD, avec une interface séparée qu'on n'utilise que pour la vidéo, et qui est donc décrite par un PvD différent.

La section 5 de notre RFC étudie plus en détail certains points spécifiques qui doivent être traités par un nœud PvD-aware. Par exemple, la résolution de noms, déjà citée plus haut, qui dépend fortement du PvD : un résolveur DNS n'est typiquement utilisable que par certains clients, et pas par le monde entier. En outre, les résultats d'une résolution de noms peuvent varier selon le résolveur interrogé (cas d'un service spécifique à un FAI, par exemple le MMS). La machine doit donc savoir quel PvD utiliser pour chaque nom, avec des règles du genre « pour tous les noms se terminant en ma-boîte.example, se servir du résolveur DNS du PvD du VPN de ma boîte ». Si plusieurs PvD correspondent à des FAI généralistes, pouvant servir pour tout accès à un serveur public, la machine PvD-aware peut faire les résolutions de noms en parallèle, et prendre le plus rapide, selon un approche identique à celle des globes oculaires heureux du RFC 6555.

Et puisqu'on parle de sélectionner le « meilleur » PvD, il faut rappeler que la connectivité au réseau local, tel qu'elle s'obtient lorsqu'une requête DHCP ou RA a réussi, ne garantit pas un bon accès à tout l'Internet. Le signal local peut être fort, le serveur DHCP très réactif... et la connexion ultérieure échouer. Il est donc prudent de tester les connexions obtenues, par exemple en essayant de se connecter à un amer bien connu.

On a vu qu'une application pouvait être PvD-aware si elle sait utiliser l'information sur les PvD pour prendre des décisions. La section 6 décrit les propriétés attendues de l'API qui permettra de développer ces applications. Dans le cas le plus simple, une application PvD-aware peut se limiter à n'utiliser qu'un seul PvD. C'est le cas d'une application MMS qui dépend d'un opérateur particulier et qui devra donc passer par l'interface correspondante. Un peu plus complexe serait une application qui exprime des exigences et des préférences, du genre « il me faut IPv6 » ou « je fais de la vidéo-conférence, je veux une faible latence » ou bien « je suis paranoïaque, je ne veux passer que par un PvD cité dans telle liste » ou encore « je ne suis pas pressé, il vaut mieux utiliser la connexion la moins chère ». Le système pourrait alors choisir, en regardant les informations obtenues pour chaque PvD, quel PvD utiliser. Dans le dernier cas (une application qui télécharge beaucoup, comme la mise à jour du système d'exploitation, ou comme une application pair-à-pair d'accès à la culture), un mécanisme de sélection automatique via le PvD simplifierait nettement la tâche de l'utilisateur en le dispensant d'options comme la « n'utiliser qu'avec la WiFi » qu'on trouve souvent sur les applications Android, qui veulent éviter de faire exploser le forfait de téléphonie mobile.

Enfin, les applications les plus avancées pourraient simplement obtenir la liste des PvD et leurs caractéristiques et faire leurs choix elles-mêmes. Ces choix ne seront pas forcément respectés par le système, qui peut avoir ses propres exigences (par exemple forcer la passage par le VPN de l'entreprise pour les connexions aux services de la dite entreprise).

Puisqu'on a parlé de sécurité (« je suis paranoïaque, je ne veux passer que par un PvD cité dans telle liste »), un mot sur les PvD de confiance ou pas (section 7). Par défaut, un PvD n'est pas « de confiance ». Si je me promène dans la rue et que je me connecte à un hotspot inconnu, le PvD associé ne sera pas considéré comme de confiance. Certains systèmes ou applications ne voudront se connecter à tel service que via un PvD de confiance. Mais attention : supposons qu'on ait une telle liste (le PvD du VPN de la boîte, le PvD d'un opérateur à qui on fait confiance, le réseau local à la maison...), il ne faut pas pour autant considérer que le PvD est ce qu'il annonce. Si le PvD de l'entreprise est 6a97f31e-34ec-4ef9-ba75-b1e3addd8222 (ce n'est pas la vraie syntaxe des PvD ID, qui n'est pas encore décidée), et que le serveur DHCP du hotspot annonce ce PvD ID, il ne faut pas pour autant lui faire confiance (voir aussi la section 8). Un PvD de confiance nécessite deux choses : une relation de confiance avec son opérateur, et un moyen de vérifier qu'il s'agit bien du PvD attendu. Ce moyen d'authentification peut passer par une signature du PvD ID, ou bien simplement par le mécanisme d'attachement au réseau : on peut décider que, si on est connecté à un réseau physique stable et sûr, l'annonce du PvD ID sur ce réseau peut être crue. À noter que le RFC fournit un autre exemple, où on fait confiance au réseau d'un opérateur mobile, ce qui ignore le risque des IMSI-catchers.

La section 8 revient d'ailleurs sur les problèmes de sécurité. Par exemple, même si le serveur DHCP ou RA est sûr, un attaquant a pu modifier les données en cours de route. On peut utiliser les techniques (très peu déployées en pratique) de l'option AUTH du RFC 3315 (abandonnée depuis, dans le RFC 8415), section 22.11, ou le SEND du RFC 3971.


Téléchargez le RFC 7556


L'article seul

RFC 7553: The Uniform Resource Identifier (URI) DNS Resource Record

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : P. Faltstrom (Netnod), O. Kolkman (ISOC)
Pour information
Première rédaction de cet article le 14 juin 2015


Ce RFC est la documentation d'un nouveau type d'enregistrement DNS, le type URI qui permet de publier des URI et donc d'avoir un mécanisme pour faire correspondre un nom de domaine à un URI.

Petit rappel, les URI sont normalisés dans le RFC 3986 et permettent sous une forme simple et compacte d'identifier une ressource sur le Web et, très fréquemment, fournissent les moyens d'y accéder. Traditionnellement, quand on voulait mettre des URI dans le DNS et permettre de les retrouver, on utilisait les NAPTR des RFC 3401 et RFC 3404. Notre nouveau RFC critique cette solution en notant qu'une requête NAPTR récupère tous les NAPTR qu'il faut trier ensuite, pas uniquement ceux liés à un seul service (le triage est d'autant plus compliqué qu'il n'existe toujours aucune bibliothèque en logiciel libre pour manipuler des NAPTR). En effet, le nom du service fait partie des données du NAPTR, pas du nom de domaine (le seul critère de sélection dans une requête DNS, avec le type). La solution de notre RFC 7553 permet cette sélection en mettant le type de service souhaité dans le nom de domaine. En outre, l'URI est trivial à extraire, il est le dernier composant des données de l'enregistrement, et ne nécessite pas de traitement ultérieur (on est loin de la complexité des NAPTR, même si les S-NAPTR du RFC 3958 l'ont un tout petit peu simplifiée).

Donc, dès que vous avez besoin d'une correspondance simple entre un nom de domaine et un URL, allez-y, ce type d'enregistrement est fait pour vous. À quoi ressemble-t-il (section 4 du RFC) ? Le format de présentation en texte met dans les données (la partie droite de l'enregistrement) une priorité, suivie d'un poids et de l'URI (nommé Target). Cela donne comme exemple :

_ftp._tcp.example.net.    IN URI 10 1 "ftp://ftp1.example.com/public"

Priorité et poids ont la même sémantique que dans le RFC 2782 (voir plus loin).

Le nom de domaine suit certaines conventions (section 4.1), notamment d'indiquer le service demandé (pris dans le registre IANA qu'avait créé le RFC 6335) et le protocole utilisé, précédés d'un tiret bas.

L'enregistrement URI a le type 256 et figure à ce titre dans le registre IANA des types DNS.

On peut avoir plusieurs URI pour un même nom de domaine (donc un même service). La sélection se fait en examinant d'abord la priorité, puis le poids. La priorité est absolue. On contacte d'abord les URI ayant la priorité la meilleure (c'est le chiffre le plus bas, attention), et, seulement si cela échoue, on tente les autres. Par contre, à priorité équivalente, la sélection selon le poids est probabiliste. Cela permet de faire de la répartition de charge dans le DNS. Si j'écris deux URI avec la même priorité mais des poids différents :

_ftp._tcp.example.net.    IN URI 10 2 "ftp://ftp1.example.net/public"
                          IN URI 10 1 "ftp://ftp4.example.com/mirrors/example.net/"

Alors, l'URI ftp://ftp1.example.net/public a deux fois plus de chances d'être sélectionné, il recevra donc les deux tiers des requêtes. Si j'avais mis des priorités différentes :

_ftp._tcp.example.net.    IN URI 10 1 "ftp://ftp1.example.net/public"
                          IN URI 20 1 "ftp://ftp4.example.com/mirrors/example.net/"

Alors, ftp://ftp4.example.com/mirrors/example.net/ ne sera sélectionné que s'il n'y a pas le choix, uniquement si ftp1.example.net est en panne.

Et sur le réseau, comment est encodé ce nouveau type (section 4.5) ? C'est simple, deux octets pour la priorité, deux pour le poids et l'URI lui-même, sous forme de texte.

Les enregistrements URI permettent d'indiquer la même chose qu'un SRV (RFC 2782), à savoir un nom de serveur et un port, mais ils permettent en outre d'exprimer d'autres choses (comme le répertoire dans les exemples FTP plus haut). En contre partie, il faut pouvoir traiter les URI, les analyser, mais c'est aujourd'hui une tâche bien connue, pour laquelle on a déjà du code. Ainsi, ces deux informations sont presque équivalentes (si on sait que le protocole à utiliser est HTTP) :

_http._tcp    IN  SRV   0  1 8081  www.example.net.
_http._tcp    IN  URI   0  1 "http://www.example.net:8081"

Mais les enregistrements URI sont plus puissants, ceci ne pourrait pas être exprimé en SRV :

_http._tcp    IN  URI   0  1 "http://www.example.net:8081/actu/2015"

Les futurs protocoles pourraient donc n'utiliser que URI, et plus du tout SRV. (À l'heure actuelle, certains protocoles utilisent une combinaison de SRV + un enregistrement TXT, pour résoudre ce problème : l'enregistrement URI est plus élégant.)

Je ne peux pas m'empêcher de noter que bien des problèmes du Web auraient été évités si, dès le début, Tim Berners-Lee avait pensé à découpler le nom de domaine et le serveur, en utilisant les SRV. Actuellement, le nom dans l'URL doit être un nom de machine (il doit obéir aux règles syntaxiques restrictives sur les noms de machine, et il doit avoir une adresse IP). Cela oblige à mettre une adresse à l'apex (le sommet) de la zone DNS (si on veut que http://example.com/ marche, il faut une adresse IP mise au nom example.com, ce qui est compliqué à réaliser proprement). Si le Web utilisait les SRV ou, aujourd'hui, les enregistrements URI, on ne serait pas obligé de polluer l'apex de la zone avec des adresses IP, on aurait séparé le nom court (example.com), dans l'URL, et celui du serveur (qui ne serait pas visible à l'utilisateur ordinaire).

Bien que ce type d'enregistrement ait déjà plusieurs années (le RFC 6895 permet d'enregistrer un type d'enregistrement DNS sans avoir de RFC), certains logiciels ne le gèrent pas encore. Voici une version un peu ancienne d'OpenDNSSEC (je n'ai pas testé avec les versions plus récentes) :

ods-signerd: [adapter] error parsing RR at line 28 (Syntax error, could not parse the RR's rdata):   IN URI 0 1 "http://www.bortzmeyer.org/"

Aïe. Et pareil avec le signeur DNSSEC d'une version un peu vieille de BIND :

dnssec-signzone: warning: sources.org:23: unknown RR type 'URI'
dnssec-signzone: fatal: failed loading zone from 'sources.org': unknown class/type

Idem pour les formulaires Web qui permettent de créer des enregistrements DNS dans une zone gérée par son hébergeur DNS. Tous n'ont pas encore ce type, loin de là.

Pour une vision optimiste, voici le commit qui a ajouté le type URI à PowerDNS.

Un exemple d'utilisation des enregistrements URI est le service des codes postaux dans le DNS, où un URI pointe vers OpenStreetMap. Ici, la commune de Luchon :

% dig +short +nodnssec URI 31110.cp.bortzmeyer.fr
10 1 "http://www.openstreetmap.org/?mlat=42.781913&mlon=0.564010&zoom=12"

Téléchargez le RFC 7553


L'article seul

RFC 7545: Protocol to Access White-Space (PAWS) Databases

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : V. Chen (Google), S. Das (Applied Communication Sciences), L. Zhu (Huawei), J. Malyar (iconectiv), P. McCann (Huawei)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF paws
Première rédaction de cet article le 28 mai 2015


Ah, les espaces blancs (ou fréquences blanches, ou canaux non-utilisés), un nom qui fait rêver, et penser à des mystérieuses zones inconnues sur une carte, qui attendent leurs courageux explorateurs, qui vont s'installer, virer des indigènes inutiles, et faire pousser bananes et café dans ce qui n'était qu'une jungle. Dans le monde des ondes radios, les espaces blancs sont les fréquences qui ont été réservées à un moment mais qui ne sont pas utilisées en pratique, et sont donc susceptibles d'être affectées à un autre usage. Encore faut-il savoir pour cela quelles sont les fréquences libres dans une région donnée, et c'est le rôle du protocole décrit dans ce RFC.

La traduction de « white space » par « espace blanc » figure par exemple dans ce rapport de l'ANFR. On parle aussi de « canaux non utilisés » pour les fréquences libres, et de « réutilisation du spectre » pour le concept, qui agite pas mal de régulateurs des télécommunications et d'industriels. L'idée de base du groupe de travail PAWS de l'IETF (c'est son deuxième RFC après le RFC 6953) est de concevoir un protocole qui permette à une machine en promenade de trouver facilement quelles sont les fréquences libres dans sa zone géographique. En effet, « L’une des difficultés de l’utilisation de ces fréquences blanche [sic] est qu’elles forment un véritable "gruyère" parce que ce sont des petites bandes de fréquence qui se trouvent entre des canaux de TV affectés à des endroits différents selon les régions. La technologie doit donc déterminer avec précision les canaux pré-existants et éviter les interférences locales. » La machine en promenade ne peut donc pas utiliser une bande de fréquence pré-réglée, il faut qu'elle s'adapte aux conditions locales. L'idée est que toutes les fréquences du « gruyère » soient enregistrées dans des bases publiques, et que la machine nomade puisse interroger ces bases, avec ce nouveau protocole PAWS (Protocol to Access White-Space database).

Le RFC 6953 résumait le problème des espaces blancs et les scénario d'usage de ces espaces. L'idée centrale est d'avoir une base de données des espaces blancs (donc des fréquences utilisables) et de la rendre accessible aux engins en déplacement (ordinateurs, smartphones, etc). En effet, vu la complexité de ces espaces, et leur caractère partagé, ce qui a nécessité de nombreuses règles quand à leur usage (telle que la puissance maximale d'émission), et les changements permanents dans ce domaine, essayer de mettre l'information sur chaque appareil est une tâche sans espoir. On la met donc uniquement dans un petit nombre de bases de données. Ce choix impose donc un protocole standard d'accès à ces bases et ce protocole, sans surprise, est conçu au dessus de HTTPS, avec un encodage en JSON.

Donc, PAWS est client/serveur, le client (Master Device, dans le RFC) est l'appareil en mouvement, et qui voudrait bien émettre dans les espaces blancs, et le serveur est la base de données officielle (sections 2 et 3 du RFC). Le client doit d'abord obtenir l'URI du serveur, envoyer des requêtes HTTP pour savoir ce que la base de données peut lui dire (ce qu'on nomme l'initialisation), puis demander quels sont les espaces blancs utilisables dans la région où se trouve le client, et à quelles conditions. Le serveur va alors lui envoyer l'information. (La base de données n'est pas forcément publique, elle peut imposer à ses clients d'être préalablement enregistrés.)

La section 4 du RFC détaille chacune de ces étapes. Pour découvrir le serveur, le client a une liste d'URI en dur dans sa configuration. Ces URI peuvent désigner une base de données, ou bien un service « méta » (géré, par exemple, par le régulateur des télécommunications du pays) qui indiquent plusieurs bases possibles (cf. l'annexe A du RFC). Rien de très souple ici, surtout quand on change de pays.

Certaines bases vont demander que le client s'enregistre. Par exemple, aux États-Unis, la FCC l'impose pour les clients fixes. Il existe donc des messages d'enregistrement dans PAWS. Une fois l'initialisation et l'éventuel enregistrement fait, passons à l'essentiel, la requête demandant les fréquences disponibles. Le client indique sa localisation et certaines autres caractéristiques, comme les fréquences qu'il est techniquement capable d'utiliser, le serveur lui répond avec une liste de fréquences, avec les puissances d'émission maximale dans chaque plage, et les heures où on peut émettre (au format du RFC 3339). Le client peut alors choisir une fréquence, en fonction de ses critères.

La section 5 contient quelques détails sur les requêtes et réponses. Par exemple, la position du client est indiquée par un simple point, ou sous forme d'une région, selon les règles de la section 5 du RFC 5491 (pour les amateurs de géométrie). Le client indique les caractéristiques de son antenne (car elles peuvent influer la réponse) comme sa hauteur. D'autres caractéristiques (comme la direction dans laquelle pointe l'antenne) peuvent être indiquées, et, si elles ne sont pas dans ce RFC 7545, elles seront peut-être enregistrées dans le registre des paramètres PAWS. La requête, décidément très bavarde, peut inclure des informations sur le propriétaire de la machine cliente et, dans ce cas, elles doivent être au format jCard (RFC 7095, un exemple figure dans la section 6.4 de notre RFC).

Bien sûr, la requête peut échouer et, dans ce cas, un objet Error est renvoyé, contenant un code numérique et un message texte. Les codes numériques peuvent être négatifs, comme le -104 de l'exemple ci-dessous, qui signifie que la base de données n'a pas d'information sur la région demandée. (L'ensemble des codes d'erreur est dans un registre IANA.)

Tous ces messages sont encodés en JSON-RPC, avec du contenu en JSON (RFC 8259). La requête est un objet JSON dont un des membres est method, qui indique la méthode (le type de requête). La réponse est un objet JSON dont un des membres est result (ou error), qui contient le résultat demandé. Parmi les méthodes possibles, la plus importante est certainement spectrum.paws.getSpectrum qui est la demande des plages de fréquences blanches.

Il semble qu'il existe plusieurs mises en œuvres de PAWS, en tout cas c'est ce qui s'est dit dans des réunions IETF. Mais la seule que je connais est celle de Google (il y a une bonne documentation de la base utilisée). On peut avoir un accès limité sans engagement (à part un compte Google et une clé d'API), il faut signer un contrat si on veut un accès moins limité. Cette base ne couvre que les USA. Attention, les objets JSON utilisés sont ceux d'une version antérieure de la norme, pas tout à fait les mêmes que dans le RFC. Voici un exemple de script shell pour faire une requête, via curl :

#/bin/sh

# Replace with your own key, see https://developers.google.com/spectrum/paws/gettingstarted
API_KEY=XXXXXX

if [ -z "$2" ]; then
    echo "Usage: $0 longitude latitude" 
    exit 1
fi
lon=$1
lat=$2

curl -XPOST https://www.googleapis.com/rpc -H "Content-Type: application/json" --data "{
  \"jsonrpc\": \"2.0\",
  \"method\": \"spectrum.paws.getSpectrum\",
  \"apiVersion\": \"v1explorer\",
  \"params\": {
    \"type\": \"AVAIL_SPECTRUM_REQ\",
    \"version\": \"1.0\",
    \"deviceDesc\": { \"serialNumber\": \"your_serial_number\", \"fccId\": \"TEST\", \"fccTvbdDeviceType\": \"MODE_1\" },
    \"location\": { \"point\": { \"center\": {\"latitude\": $lon, \"longitude\": $lat} } },
    \"antenna\": { \"height\": 30.0, \"heightType\": \"AGL\" },
    \"owner\": { \"owner\": { } },
    \"capabilities\": { \"frequencyRanges\": [{ \"startHz\": 100000000, \"stopHz\": 950000000 }] },
    \"key\": \"$API_KEY\"
  },
  \"id\": \"Test PAWS\"
}"

Et son résultat, pour la ville de Denver :

% sh test-paws.sh 39.739167 -104.984722 
{
 "jsonrpc": "2.0",
 "id": "Test PAWS",
 "result": {
  "kind": "spectrum#pawsGetSpectrumResponse",
  "type": "AVAIL_SPECTRUM_RESP",
  "version": "1.0",
  "timestamp": "2015-05-24T16:20:35Z",
  "deviceDesc": {
   "serialNumber": "your_serial_number",
   "fccId": "TEST",
   "fccTvbdDeviceType": "MODE_1"
  },
  "spectrumSchedules": [
   {
    "eventTime": {
     "startTime": "2015-05-24T16:20:35Z",
     "stopTime": "2015-05-26T16:20:35Z"
    },
    "spectra": [
     {
      "bandwidth": 6000000.0,
      "frequencyRanges": [
       {
        "startHz": 5.4E7,
        "stopHz": 5.12E8,
        "maxPowerDBm": -56.799999947335436
       },
       {
        "startHz": 5.12E8,
        "stopHz": 5.24E8,
        "maxPowerDBm": 15.99999928972511
       },
       {
        "startHz": 5.24E8,
        "stopHz": 5.36E8,
        "maxPowerDBm": -56.799999947335436
       },
       {
        "startHz": 5.36E8,
        "stopHz": 5.42E8,
        "maxPowerDBm": 15.99999928972511
       },
       {
        "startHz": 5.42E8,
        "stopHz": 5.48E8,
        "maxPowerDBm": -56.799999947335436
       },
       {
        "startHz": 5.48E8,
        "stopHz": 5.54E8,
        "maxPowerDBm": 15.99999928972511
       },
       {
        "startHz": 5.54E8,
        "stopHz": 6.5E8,
        "maxPowerDBm": -56.799999947335436
       },
       {
        "startHz": 6.5E8,
        "stopHz": 6.56E8,
        "maxPowerDBm": 15.99999928972511
       },
       {
        "startHz": 6.56E8,
        "stopHz": 6.68E8,
        "maxPowerDBm": -56.799999947335436
       },
       {
        "startHz": 6.68E8,
        "stopHz": 6.74E8,
        "maxPowerDBm": 15.99999928972511
       },
       {
        "startHz": 6.74E8,
        "stopHz": 6.86E8,
        "maxPowerDBm": -56.799999947335436
       },
       {
        "startHz": 6.86E8,
        "stopHz": 6.98E8,
        "maxPowerDBm": 15.99999928972511
       }
      ]
     }
    ]
   }
  ],
  "needsSpectrumReport": false,
  "rulesetInfo": {
   "authority": "US",
   "maxLocationChange": 100.0,
   "maxPollingSecs": 86400,
   "rulesetIds": [
    "FccTvBandWhiteSpace-2010"
   ]
  }
 }
}

Si on tente un lieu situé en dehors des USA :

{
 "error": {
  "code": -104,
  "message": "Requested location is outside the supported coverage zone",
  "data": [
   {
    "domain": "global",
    "reason": "invalidParameter",
    "message": "Requested location is outside the supported coverage zone"
   }
  ]
 },
 "jsonrpc": "2.0",
 "id": "Test PAWS"
}

Le monde de la gestion des fréquences radio est évidemment lourdement régulé, puisqu'il s'agit d'un espace partagé. Dans l'exemple ci-dessus, on voit la mention que les règles de la FCC s'appliquent ("rulesetIds": ["FccTvBandWhiteSpace-2010"]). D'autres organismes de régulation peuvent intervenir, par exemple l'identifiant de règles (rulesetIds) de l'ETSI serait ETSI-EN-301-598-1.1.1.

Un peu de sécurité, pour finir (section 10). D'abord, PAWS ne permet pas de vérifier que le client utilisera correctement les informations fournies. PAWS envoie des données, c'est au client de les appliquer. Si ce dernier décide d'émettre dans d'autres bandes de fréquences que celles indiquées, ou bien d'utiliser les bandes indiquées, mais avec une puissance supérieure à ce qui est autorisé, PAWS n'offre aucun mécanisme pour l'en empêcher.

On peut imaginer d'autres risques, comme un client redirigé vers un faux serveur PAWS. L'utilisation de HTTPS protège normalement contre cela, le nom du serveur de la base devant être dans le certificat. Enfin, PAWS peut poser des problèmes de vie privée : le client fournit des données de localisation, ce qui permet au serveur de suivre le client.

Quelques lectures pour finir :


Téléchargez le RFC 7545


L'article seul

RFC 7542: The Network Access Identifier

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : DeKok, Alan (FreeRADIUS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 2 mai 2015


Ce nouveau RFC normalise le concept d'identificateur pour l'accès au réseau (NAI pour Network Access Identifier). Cet identificateur est traditionnellement utilisé lors d'un accès authentifié au réseau, pour indiquer la personne ou l'entité qui veut se connecter (avec un mot de passe, ou autre information de créance, pour s'authentifier). Le NAI a une forme qui ressemble aux adresses de courrier ou XMPP. Par exemple, un NAI peut être marie@example.com ou jean_dupont@labs.potamochère.fr. Contrairement au traditionnel login ou nom d'utilisateur, le NAI inclut l'indication d'un domaine (ou plutôt royaume) d'origine, permettant au point d'accès d'accepter des utilisateurs issus d'un autre domaine. Le NAI permet donc des accès fédérés. Ce concept, en dépit de ce nom, est désormais utilisé pour bien d'autres choses que l'accès au réseau. Notre RFC remplace la norme précédente, le RFC 4282, notamment en développant bien plus l'internationalisation (un NAI n'est pas forcément en ASCII). Bienvenue dans le monde merveilleux (et très bordélique) du AAA.

Initialement, la principale motivation pour le NAI (Network Access Identifier) était le roaming : un utilisateur abonné au FAI X se déplace dans une zone où X ne fournit pas d'accès mais a un accord avec le FAI Y qui, lui, est présent. Pour éviter de recopier la base d'utilisateurs de X dans celle de Y, l'utilisateur présente un NAI qui indique son rattachement à X (son home domain). Le point d'accès de Y sait alors qu'il doit demander l'authentification à X. Une fois que c'est fait, on peut donner l'accès via Y (le visited domain). C'est par exemple ainsi que fonctionne la fédération Eduroam. (L'auteur du RFC est d'ailleurs l'auteur et le mainteneur de FreeRADIUS, un des logiciels les plus utilisés pour cette tâche. Le protocole RADIUS est normalisé dans le RFC 2865.)

Le NAI permet donc à des FAI purement régionaux d'accueillir des clients d'autres régions du pays, à des FAI nationaux d'accueillir des clients d'autres pays, à des hotspots WiFi de servir plusieurs FAI avec la même infrastructure, etc. Une description de l'usage des NAI dans des situations de roaming est donné dans le RFC 2194.

On l'a vu, le NAI peut servir à bien d'autres choses que l'accès au réseau. Sa définition est donc indépendante du protocole qui va l'utiliser (le NAI n'est pas spécifique à RADIUS.) Par contre, son encodage effectif dépendra du protocole (par exemple, il faudra assurer l'échappement de certains caractères, le NAI sophie@internautique.fr deviendra sophie@internautique%2Efr dans un URL). À noter que le NAI, quoique répandu, n'est pas le format unique d'identificateur sur le réseau. Certains protocoles existants ont un autre format, et certains permettent le NAI et d'autres formats. Pour les protocoles futurs, notre RFC recommande qu'ils adoptent le NAI, pour uniformiser les identificateurs. C'est déjà le cas de 3GPP dont la norme « TS 23.003 Numbering, addressing, and Identification (Release 12) » précise que l'identificateur est un NAI comme 234150999999999@ims.mnc015.mcc234.3gppnetwork.org.

Attention, le but est d'uniformiser le format, pas les identificateurs. Le NAI n'implique pas que chaque utilisateur ait un identificateur et un seul ! Cela poserait, entre autres, de sérieux problèmes liés à la vie privée. Le RFC recommande d'ailleurs de permettre des identificateurs anonymes (pseudonymes, plutôt) dès qu'ils sont visibles publiquement.

Un peu de terminologie nécessaire pour comprendre le NAI figure en section 1.1. Notez le NAS (Network Access Server) qui est la première machine à laquelle les utilisateurs se connectent pour avoir un accès à l'Internet. Pour les technologies PPTP et L2TP, ce sera le concentrateur d'accès. En WiFi, ce sera le point d'accès (hotspot). Lorsque l'utilisateur envoie son NAI, c'est le NAS qui extrait le domaine de l'utilisateur et relaie (par exemple en RADIUS) la demande d'authentification à ce domaine.

Une bonne partie des changements depuis le RFC 4282 avait été motivé par l'expérience d'Eduroam. Par exemple, la section 2.1 du RFC 4282 demandait que le nom de domaine soit uniquement composé de lettres ASCII, de chiffres et de tirets. Pour les IDN, l'idée était d'utiliser la forme Punycode. Celle-ci est peu pratique, et souvent inutile puisque plusieurs protocoles utilisant les NAI (comme RADIUS ou comme l'EAP du RFC 3748) ne sont pas limités à l'ASCII et recommandent UTF-8 comme encodage des chaînes de caractères (cf. section 3.2). Le RFC 4282 avait d'autres problèmes d'internationalisation comme d'exiger une normalisation des chaînes (qui peut rentrer en conflit avec des exigences locales) ou comme d'exiger des opérations qui soient dépendantes de la langue (que le NAS et autres équipements intermédiaires ne connaissent pas forcément, et ne savent pas toujours gérer). D'autre part, le RFC 4282 interdisait l'utilisation de points de code Unicode non affectés. Cela empêchait le déploiement de toute nouvelle écriture puisque, au début, tous les équipements réseau auraient considéré ces nouveaux caractères comme non affectés ! En pratique, d'ailleurs, aucun équipement réseau n'a mis en œuvre les recommandations d'internationalisation du RFC 4282. Le roaming international se développant, il était temps de changer ces recommandations irréalistes.

La section 2 de notre RFC présente la définition formelle du NAI. Il est en UTF-8, normalisé NFC. Il est divisé en deux parties, le nom d'utilisateur, et le royaume (realm). Ces deux parties sont séparées par un @. Le nom d'utilisateur peut être composée de lettres (Unicode, pas uniquement ASCII), de chiffres et de quelques symboles. fred=?#$&*+-/^smith est donc un nom d'utilisateur valable. Le royaume ressemble à un nom de domaine, avec ses composants séparés par des points mais n'en est pas forcément un. Un exemple de NAI est donc eng%geneviève@example.neteng%geneviève est le nom d'utilisateur et le domaine (royaume) est example.net. (La grammaire formelle est en section 2.2.) Un nom de royaume ne doit pas être réduit à un seul composant donc maire@paris n'est pas un NAI même si le TLD .paris existe. En effet, certains équipements considèrent qu'un royaume d'un seul composant est un sous-royaume du royaume local (donc, chez le FAI example.net, le NAI maire@paris serait interprété maire@paris.example.net).

Le royaume peut être en Unicode, bien des protocoles AAA autorisent à la transporter nativement et il est donc désormais déconseillé d'encoder en Punycode (RFC 3492). Ainsi, le NAI faïza@café.example s'écrit bien ainsi, et pas faïza@xn--caf-dma.example. (Il semble bien que c'est ce que faisaient déjà tous les équipements qui géraient des noms de royaumes en Unicode, malgré ce que disait le RFC 4282.)

Il n'y a pas de limite de taille aux NAI, juste la recommandation de pouvoir gérer au moins 72 octets et, de préférence, 253. (Attention, en UTF-8, un caractère ne fait pas forcément un octet.) Les NAI étant utilisés dans des protocoles très différents, on a parfois des surprises. Ainsi, l'attribut User-Name de RADIUS exige d'accepter jusqu'à 63 octets mais ne dit rien au delà (RFC 2865, section 5.1). En revanche, le protocole concurrent Diameter (RFC 6733) impose à ses mises en œuvre des noms d'utilisateur jusqu'à 16 777 207 octets. Si on est sûr de toujours passer par Diameter (ce qui est très peu probable), on peut utiliser des NAI très longs.

Le nom d'utilisateur est opaque aux autres royaumes (comme pour le courrier électronique même si beaucoup d'ignorants violent cette règle). Par exemple, dans le eng%geneviève@example.net donné plus haut, on peut soupçonner que le nom d'utilisateur indique un routage interne (vers le service d'ingéniérie puis vers l'utilisatrice Geneviève) mais on ne peut pas en être sûr, chaque royaume a ses propres règles. On doit donc traiter le nom d'utilisateur comme un tout, sauf si on est le home domain. Parfois, des protocoles transmettent juste le nom de royaume, faisant passer le nom d'utilisateur dans un canal plus sûr, afin de préserver la vie privée (cf. le TTLS du RFC 5281). L'habitude dans ce cas est de remplacer le nom d'utilisateur par anonymous mais c'est désormais déconseillé, il vaut mieux un nom vide (@internautique.fr est donc un NAI valide). Avec les autres protocoles, notre RFC recommande d'utiliser des noms d'utilisateurs éphémères, pour la vie privée, mais c'est très rarement le cas aujourd'hui.

On a vu qu'on pouvait utiliser des caractères Unicode aussi bien pour le nom de royaume que pour celui de l'utilisateur. Pour les noms d'utilisateur, les règles se basent sur celles du RFC 6532. Pour le nom de royaume, on est restreint aux caractères utilisables dans un nom de domaine (RFC 5891). L'éventuelle traduction en UTF-8 (au cas où l'utilisateur ait rentré des caractères dans un autre encodage) et la normalisation en NFC doivent être faites au tout début, lorsqu'on est encore proche de l'utilisateur et qu'on sait ce qu'il veut (on connait sa langue, par exemple, ce qui n'est pas le cas des équipements réseau intermédiaires ; ces équipements intermédiaires ont tout intérêt à ne pas tripoter les NAI). Ceci dit, cette situation idéale (les terminaux normalisent, les intermédiaires ne changent rien) n'est pas respectée aujourd'hui. Il existe des terminaux qui ne normalisent pas, injectant ainsi des chaînes non-UTF8 dans le système d'authentification. Le RFC note donc que le principe « les terminaux normalisent, les intermédiaires ne changent rien » doit parfois être violé. « The suggestion in the above sentence contradicts the suggestion in the previous section. This is the reality of imperfect protocols. » Ce point a été l'un des plus disputés lors de l'écriture de ce RFC.

Une fois le NAI défini, notre RFC s'attaque au routage des requêtes (section 3). Typiquement, le système d'authentification et autorisation (AAA) extrait le royaume du NAI et s'en sert comme clé pour une table où sont stockés les royaumes qu'on connait et avec qui on a une relation d'acceptation de leurs utilisateurs. Si le royaume n'est pas trouvé dans la table, on refuse l'utilisateur. S'il est trouvé, le contenu de la table nous dira le serveur à interroger pour ce royaume (ainsi que des informations comme le secret partagé RADIUS, le port, etc). Attention, la sémantique des noms de royaume n'est pas forcément connue et, par exemple, les équipements réseau ne savent pas si on peut les consulter de manière insensible à la casse. Parfois, ça marche (rappelez-vous le paragraphe précédent : le monde de l'AAA est imparfait...) Si on ne trouve pas un nom de royaume dans la table, on peut router sur une partie du royaume, par exemple utiliser example.net si le royaume france.example.net n'a pas été trouvé. Attention, ce n'est valable que si le nom raccourci reste un nom valide (net ne le serait pas, vu la prohibition des noms d'un seul composant).

Les NAI ressemblent aux adresses de courrier électronique et certaines normes sont communes aux deux (comme le RFC 6532) mais attention, les règles ne sont pas exactement les mêmes. Toute adresse de courrier n'est donc pas forcément un NAI valide. En pratique, les deux se ressemblent suffisamment pour que beaucoup de FAI utilisent l'adresse de courrier du client comme son NAI.

On a vu que l'AAA était un monde très riche, ancien, et qui contient donc plein de choses surprenantes et de traditions historiques. La section 3.3.1 contient quelques exemples rigolos, avec les recommandations actuelles. Par exemple, les utilisateurs de RADIUS ont longtemps utilisé du routage explicite, où une partie du NAI contenait d'autres instructions de routage (chezmoi.example!utilisateur@fai.example...). Cette méthode (citée par le RFC 4282, section 2.7) s'est avérée très fragile, cassant dès qu'on change le réseau. RADIUS n'ayant pas de protocole de routage (qui diffuserait automatiquement les informations de routage), il fallait informer beaucoup de systèmes en cas de changement. (Diameter - RFC 5729 - ou 3G sont des cas différents car ils utilisent un protocole de routage.)

Le NAI étant en général utilisé dans un contexte de sécurité (point d'entrée pour une authentification), notre RFC consacre une section, la 4, à ces problèmes. Par exemple, si le protocole transporte le nom d'utilisateur en clair (c'est le cas de RADIUS), un écoutant sur le trajet peut apprendre des noms d'utilisateurs existants. Pour empêcher cela, il faut protéger (RADIUS avec IPsec, RFC 3579, Diameter avec TLS, RFC 6733). Si on utilise plusieurs protocoles qui tous se servent de NAI, et que l'utilisateur n'a qu'un seul NAI, un observateur pourra relier entre elles ces différentes utilisations. D'où l'intérêt de ne pas transporter les NAI en clair. Dans le futur, il serait encore mieux d'avoir des NAI éphémères, changés de temps en temps.

Le monde de l'accès réseau étant compliqué, il y a également des risques liés au fait qu'un identificateur peut être interprété d'une façon par un protocole et d'une autre façon par un autre protocole.

Dernier problème des NAI à régler, celui de l'avitaillement (création, maintenance, suppression) des identificateurs. Les noms de royaumes ressemblent à des noms de domaine pour éviter d'avoir à créer une nouvelle infrastructure d'avitaillement. Ainsi, si on est déjà titulaire du domaine lesrépublicains.fr, on n'a pas besoin d'autre chose pour créer des NAI comme nicolas@lesrépublicains.fr, tout en étant sûr de leur unicité, sur laquelle repose le routage. Bien qu'on puisse toujours, techniquement parlant, prendre un nom, sans l'enregistrer comme nom de domaine, pour faire des NAI, cette pratique est interdite. Par contre, l'usage du DNS n'est pas obligatoire et ces noms n'ont donc pas besoin d'être publiés. Si Diameter permet d'utiliser le DNS pour localiser un serveur d'authentification, les autres protocoles n'ont pas forcément cette possibilité : RADIUS repose sur des configurations statiques.

L'annexe A résume les (importants) changements depuis le RFC 4282, notamment :

  • UTF-8 autorisé dans le nom de royaume,
  • Abandon de Punycode.

Ces deux changements sont déjà largement déployés dans les équipements qui gèrent des NAI en Unicode.


Téléchargez le RFC 7542


L'article seul

RFC 7541: HPACK - Header Compression for HTTP/2

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : R. Peon (Google), H. Ruellan (Canon CRF)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 16 mai 2015


Une des nouveautés de la version 2 de HTTP, désormais normalisée dans le RFC 7540, est de représenter les en-têtes des requêtes et des réponses, non plus sous une forme texte, mais sous une forme binaire, avec compression. Ce RFC normalise le mécanisme de compression, nommé HPACK.

Fini, donc, de taper des en-têtes HTTP à la main dans une session telnet, ou bien d'écrire un serveur HTTP qui envoie simplement ses réponses avec un fprintf. Désormais, tout se fait en binaire et sera comprimé, pour gagner quelques octets. L'encodage peu efficace des en-têtes de HTTP version 1 faisait perdre de l'espace, donc du temps, d'autant plus qu'ils sont répétés à chaque requête. Il fallait donc comprimer. Mais un algorithme de compression général, comme le DEFLATE (RFC 1951) qu'utilisait le premier prototype de HTTP 2, le protocole SPDY, avait des conséquences néfastes en terme de sécurité, lorsqu'il était combiné au chiffrement. D'où l'idée d'un algorithme spécifique à HTTP et n'ayant pas ces défauts, l'actuel HPACK. HPACK se veut simple (le RFC fait quand même 58 pages, celui de DEFLATE n'en faisait que 17), et inflexible (pas d'options à négocier).

HPACK est prévu (section 1.1 du RFC) pour comprimer des en-têtes HTTP, c'est-à-dire une suite ordonnée de doublets {nom, valeur}. La duplication des noms est autorisée.

La spécification de HPACK n'impose pas un algorithme spécifique pour le compresseur, elle décrit juste ce à quoi doivent ressembler les données comprimées, pour que le décompresseur arrive à les reconstituer.

Les données comprimées vont contenir des index, qui référencent une table, et des valeurs littérales. HPACK utilise deux tables, qui permettent d'associer un index à un en-tête. La première table est statique : définie dans ce RFC, dans l'annexe A, elle comporte les en-têtes les plus courants. Ainsi, Accept-encoding: gzip,deflate (RFC 7231, section 5.3.4), présent chez presque tous les navigateurs Web, sera représenté par l'index 16. Cette table statique a surtout des entrées qui sont des pseudo-en-têtes, c'est-à-dire des valeurs dans les requêtes ou les réponses qui n'étaient pas définies comme des en-têtes en HTTP 1 mais qui sont assimilés à des en-têtes en HTTP 2 (on les reconnait à leur nom qui commence par deux-points). Ainsi, le classique GET (:method GET pour HTTP 2) sera l'index 2 et /index.html (:path /index.html en HTTP 2) sera l'index 5.

La seconde table est dynamique : vide au début, elle se remplit au fur et à mesure de la compression ou de la décompression. Ses index commencent là où la table statique se termine (à l'index 61).

Un en-tête pourra donc être représenté par un index (cas du Accept-encoding: gzip,deflate plus haut) ou bien par une combinaison d'un nom d'en-tête et d'une valeur. Le nom d'en-tête pourra être un index (Content-type:, index 31, est un exemple dans la table statique) ou bien indiqué littéralement.

Quelles données peut-on mettre dans un flot de données HPACK ? La section 5 expose comment sont représentés entiers et chaînes de caractères. Rappelez-vous que le but est de gagner de la place et les entiers peuvent donc avoir une représentation un peu baroque, un entier pouvant commencer au beau milieu d'un octet (des exemples figurent en annexe C.1). Les chaînes de caractères peuvent être représentées telles quelles mais aussi être comprimées avec Huffman (le code Huffman utilisé est dans l'annexe B).

La section 6 décrit la représentation complète en binaire. Bon, et la table dynamique, elle est gérée comment ? Sa taille peut changer dynamiquement mais la taille maximale est déterminée par le paramètre SETTINGS_HEADER_TABLE_SIZE. Certains éléments dans les données ne changent pas la table mais d'autres ajoutent une entrée à la table dynamique. Selon les bits placés au début d'un élément (section 6), le décodeur sait si la donnée est indexée ou littérale et, si elle est littérale, s'il faut l'ajouter à la table dynamique. De nombreux exemples en annexe C permettent de se faire une meilleure idée de l'encodage.

Enfin, la section 7 se penche sur quelques problèmes de sécurité. Contrairement à DEFLATE (RFC 1951) qui permettait de deviner un préfixe du terme comprimé (ce qui, combiné avec le fait que TLS ne masque pas la longueur des données, seulement leur contenu, menait à l'attaque CRIME), HPACK oblige l'attaquant actif à tester un terme entier. Une attaque par force brute pour essayer de deviner le contenu en se basant sur la longueur observée reste donc possible, bien que nettement plus coûteuse qu'avec DEFLATE. Pour rendre plus difficile cette attaque, on peut avoir intérêt à ne pas comprimer les en-têtes les plus sensibles (comme les cookies). D'autres méthodes dépendent de l'application : par exemple, un navigateur Web ne devrait pas permettre l'utilisation de la même connexion HTTP 2 (donc du même contexte de compression/décompression) par du code issu de deux origines (RFC 6454) différentes.

Attention enfin à la consommation mémoire : compression et décompression peuvent en nécessiter beaucoup. La limite à la taille de la table dynamique est là pour empêcher les excès.

Toutes les mises en œuvre de HTTP 2 ont également HPACK, et en voici une liste.


Téléchargez le RFC 7541


L'article seul

RFC 7540: Hypertext Transfer Protocol version 2

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Belshe (Twist), R. Peon (Google), M. Thomson (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 16 mai 2015
Dernière mise à jour le 10 octobre 2021


Le protocole HTTP, à la base des échanges sur le Web, a connu plusieurs versions successives, la première était 0.9, la suivante 1.0 et la plus courante aujourd'hui est la 1.1. L'évolution entre ces versions était progressive. Mais HTTP/2, dont la norme vient de sortir, marque un saut plus important : s'il garde la sémantique de HTTP (ses en-têtes, ses codes de retour, etc), il a désormais un encodage binaire et un transport spécifique (binaire, multiplexé, avec possibilité de push). Fini de déboguer des serveurs HTTP avec telnet. En échange, le nouveau protocole promet d'être plus rapide, notamment en diminuant la latence lors des échanges. La norme de cette version a depuis été mise à jour dans le RFC 9113 . Oubliez donc le RFC 7540.

C'est un groupe de travail IETF, nommé httpbis, qui a mis au point cette nouvelle version (voir son site Web). Ce groupe httpbis travaillait sur deux projets parallèles : d'abord réorganiser les normes sur HTTP 1.1 pour corriger les innombrables bogues, et mieux organiser la norme, sans changer le protocole (projet conclus en juin 2014). Et un deuxième projet, HTTP version 2, connu aussi sous le nom de code de SPDY (initialement lancé par Google). Si SPDY a changé de nom, on peut toutefois prévoir que cet acronyme apparaitra pendant encore un certain temps, dans les API, codes source, messages d'erreur...

La section 1 de notre nouveau RFC résume les griefs qu'il y avait contre HTTP 1.1, normalisé dans le RFC 7230 :

  • Une seule requête au plus en attente sur une connexion TCP donnée. Cela veut dire que, si on a deux requêtes à envoyer au même serveur, et que l'une est lente et l'autre rapide, il faudra faire deux connexions TCP (la solution la plus courante), ou bien se résigner au risque que la lente bloque la rapide. (La section 6.3.2 du RFC 7230 permettait d'envoyer la seconde requête tout de suite mais les réponses devaient être dans l'ordre des requêtes, donc pas moyen pour une requête rapide de doubler une lente.)
  • Un encodage des en-têtes inefficace, trop bavard et trop redondant.

Au contraire, HTTP/2 n'utilisera toujours qu'une seule connexion TCP, de longue durée (ce qui sera plus sympa pour le réseau). L'encodage étant entièrement binaire, le traitement par le récepteur sera plus rapide.

La section 2 de notre RFC résume l'essentiel de ce qu'il faut savoir sur HTTP/2. Il garde la sémantique de HTTP 1 (donc, par exemple, un GET de /cetteressourcenexistepas qui faisait un 404 avant le fera toujours après) mais avec une représentation sur le réseau très différente. On peut résumer en disant que HTTP/2 ne change que le transport des messages, pas les messages ou leurs réponses.

Avec HTTP/2, l'unité de base de la communication est la trame (frame, et, dans HTTP 2, vous pouvez oublier la définition traditionnelle qui en fait l'équivalent du paquet, mais pour la couche 2). Chaque trame a un type et, par exemple, les échanges HTTP traditionnels se feront avec simplement une trame HEADERS en requête et une DATA en réponse. Certains types sont spécifiques aux nouvelles fonctions de HTTP/2, comme SETTINGS ou PUSH_PROMISE.

Les trames voyagent ensuite dans des ruisseaux (streams), chaque ruisseau hébergeant un et un seul échange requête/réponse. On crée donc un ruisseau à chaque fois qu'on a un nouveau GET ou POST à faire. Les petits ruisseaux sont ensuite multiplexés dans une grande rivière, l'unique connexion TCP entre un client HTTP et un serveur. Les ruisseaux ont des mécanismes de contrôle du trafic et de prioritisation entre eux.

Les en-têtes sont comprimés, en favorisant le cas le plus courant, de manière à s'assurer, par exemple, que la plupart des requêtes HTTP tiennent dans un seul paquet de la taille des paquets Ethernet.

Bon, maintenant, les détails pratiques (le RFC fait 92 pages). D'abord, l'établissement de la connexion. HTTP/2 tourne au-dessus de TCP. Comment on fait pour commencer du HTTP/2 ? On utilise un nouveau port, succédant au 80 de HTTP ? (Non. Les ports sont les mêmes, 80 et 443.) On regarde dans le DNS ou ailleurs si le serveur sait faire du HTTP/2 ? (Non plus.) Il y a deux méthodes utilisées par les clients HTTP/2. Tout dépend de si on fait du TLS ou pas. Si on fait du TLS, on va utiliser ALPN (RFC 7301), en indiquant l'identificateur h2 (HTTP/2 sur TLS). Le serveur, recevant l'extension ALPN avec h2, saura ainsi qu'on fait du HTTP/2 et on pourra tout de suite commencer l'échange de trames HTTP/2. (h2 est désormais dans le registre IANA.) Si on ne fait pas de TLS (identificateur h2c pour « HTTP/2 in clear » mais il est juste réservé pour information puisqu'on ne peut pas utiliser ALPN si on n'utilise pas TLS), on va passer par l'en-tête HTTP Upgrade: (section 6.7 du RFC 7230) :

GET / HTTP/1.1
Host: www.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: [base64url encoding of HTTP/2 SETTINGS payload]

Si le serveur est un vieux serveur qui ne gère pas HTTP/2, il ignorera le Upgrade: :

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html

Si le serveur est d'accord pour faire de l'HTTP/2, il répondra 101 (Switching Protocols) :

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

[Tout ce qui suit est en HTTP/2]

Dans ce dernier cas, la première trame envoyée par le serveur sera de type SETTINGS. Rappelez-vous que chaque couple requête/réponse HTTP aura lieu dans un ruisseau séparé. Ici, le ruisseau numéro 1 aura été créé implicitement, et servira à la requête Upgrade:.

Une fois qu'un client aura réussi à établir une connexion avec un serveur en HTTP/2, il sait que le serveur gère ce protocole. Il peut s'en souvenir, pour les futures connexions (mais attention, ce n'est pas une indication parfaite : un serveur peut abandonner HTTP/2, par exemple).

Maintenant, c'est parti, on s'envoie des trames. À quoi ressemblent-elles (section 4) ? Elles commencent par un en-tête indiquant leur longueur, leur type (comme SETTINGS, HEADERS, DATA... cf. section 6), des options (comme ACK qui sert aux trames de type PING à distinguer requête et réponse) et l'identificateur du ruisseau auquel la trame appartient (un nombre sur 31 bits). Le format complet est en section 4.1.

Les en-têtes HTTP sont comprimés selon la méthode normalisée dans le RFC 7541.

Les ruisseaux (streams), maintenant. Ce sont donc des suites ordonnées de trames, bi-directionnelles, à l'intérieur d'une connexion HTTP/2. Une connexion peut comporter plusieurs ruisseaux, chacun identifié par un stream ID (un entier de quatre octets, pair si le ruisseau a été créé par le serveur et impair autrement). Les ruisseaux sont ouverts et fermés dynamiquement et leur durée de vie n'est donc pas celle de la connexion HTTP 2. Contrairement à TCP, il n'y a pas de « triple poignée de mains » : l'ouverture d'un ruisseau est unilatérale et peut donc se faire très vite (rappelez-vous que chaque échange HTTP requête/réponse nécessite un ruisseau qui lui est propre ; pour vraiment diminuer la latence, il faut que leur création soit rapide).

Un mécanisme de contrôle du flot s'assure que les ruisseaux se partagent pacifiquement la connexion. C'est donc une sorte de TCP dans le TCP, réinventé pour les besoins de HTTP/2 (section 5.2 et relire aussi le RFC 1323). Le récepteur indique (dans une trame WINDOWS_UPDATE) combien d'octets il est prêt à recevoir (64 Kio par défaut) et l'émetteur s'arrête dès qu'il a rempli cette fenêtre d'envoi. (Plus exactement, s'arrête d'envoyer des trames DATA : les autres, les trames de contrôle, ne sont pas soumises au contrôle du flot).

Comme si ce système des connexions dans les connexions n'était pas assez compliqué comme cela, il y a aussi des dépendances entre ruisseaux. Un ruisseau peut indiquer qu'il dépend d'un autre et, dans ce cas, les ressources seront allouées d'abord au ruisseau dont on dépend. Par exemple, le code JavaScript ne peut en général commencer à s'exécuter que quand toute la page est chargée, et on peut donc le demander dans un ruisseau dépendant de celle qui sert à charger la page. On peut dépendre d'un ruisseau dépendant, formant ainsi un arbre de dépendances.

Il peut bien sûr y avoir des erreurs dans la communication. Certaines affectent toute la connexion, qui devra être abandonnée, mais d'autres ne concernent qu'un seul ruisseau. Dans le premier cas, celui qui détecte l'erreur envoie une trame GOAWAY (dont on ne peut pas garantir qu'elle sera reçue, puisqu'il y a une erreur) puis coupe la connexion TCP. Dans le second cas, si le problème ne concerne qu'un seul ruisseau, on envoie la trame RST_STREAM qui arrête le traitement du ruisseau.

Notre section 5 se termine avec des règles qui indiquent comment gérer des choses inconnues dans le dialogue. Ces règles permettent d'étendre HTTP/2, en s'assurant que les vieilles mises en œuvre ne pousseront pas des hurlements devant les nouveaux éléments qui circulent. Par exemple, les trames d'un type inconnu doivent être ignorées et mises à la poubelle directement, sans protestation.

On a déjà parlé plusieurs fois des trames, la section 6 du RFC détaille leur définition. Ce sont aux ruisseaux ce que les paquets sont à IP et les segments à TCP. Les trames ont un type (un entier d'un octet). Les types possibles sont enregistrés à l'IANA. Les principaux types actuels sont :

  • DATA (type 0), les trames les plus nombreuses, celles qui portent les données, comme les pages HTML,
  • HEADERS (type 1), qui portent les en-têtes HTTP, dûment comprimés selon le RFC 7541,
  • PRIORITY (type 2) indique la priorité que l'émetteur donne au ruisseau qui porte cette trame,
  • RST_STREAM (type 3), dont j'ai parlé plus haut à propos des erreurs, permet de terminer un ruisseau (filant la métaphore, on pourrait dire que cela assèche le ruisseau ?),
  • SETTINGS (type 4), permet d'envoyer des paramètres, comme SETTINGS_HEADER_TABLE_SIZE, la taille de la table utilisée pour la compression des en-têtes, SETTINGS_MAX_CONCURRENT_STREAMS pour indiquer combien de ruisseaux est-on prêt à gérer, etc (la liste des paramètres est dans un registre IANA),
  • PUSH_PROMISE (type 5) qui indique qu'on va transmettre des données non sollicitées (push), du moins si le paramètre SETTINGS_ENABLE_PUSH est à 1,
  • PING (type 6) qui permet de tester le ruisseau (le partenaire va répondre avec une autre trame PING, ayant l'option ACK à 1),
  • GOAWAY (type 7) que nous avons déjà vu plus haut, sert à mettre fin proprement (le pair est informé de ce qui va se passer) à une connexion,
  • WINDOW_UPDATE (type 8) sert à faire varier la taille de la fenêtre (le nombre d'octets qu'on peut encore accepter, cf. section 6.9.1),
  • CONTINUATION (type 9), indique la suite d'une trame précédente. Cela n'a de sens que pour certains types comme HEADERS (ils peuvent ne pas tenir dans une seule trame) ou CONTINUATION lui-même. Mais une trame CONTINUATION ne peut pas être précédée de DATA ou de PING, par exemple.

Dans le cas vu plus haut d'erreur entrainant la fin d'un ruisseau ou d'une connexion entière, il est nécessaire d'indiquer à son partenaire en quoi consistait l'erreur en question. C'est le rôle des codes d'erreur de la section 7. Stockés sur quatre octets (et enregistrés dans un registre IANA), ils sont transportés par les trames RST_STREAM ou GOAWAY qui terminent, respectivement, ruisseaux et connexions. Parmi ces codes :

  • NO_ERROR (code 0), pour les cas de terminaison normale,
  • PROTOCOL_ERROR (code 1) pour ceux où le pair a violé une des règles de HTTP/2, par exemple en envoyant une trame CONTINUATION qui n'était pas précédée de HEADERS, PUSH_PROMISE ou CONTINUATION,
  • INTERNAL_ERROR (code 2), un malheur est arrivé,
  • ENHANCE_YOUR_CALM (code 11), qui ravira les amateurs de spam et de Viagra, demande au partenaire en face de se calmer un peu, et d'envoyer moins de requêtes.

Toute cette histoire de ruisseaux, de trames, d'en-têtes comprimés et autres choses qui n'existaient pas en HTTP 1 est bien jolie mais HTTP/2 n'a pas été conçu comme un remplacement de TCP, mais comme un moyen de faire passer des dialogues HTTP. Comment met-on les traditionnelles requêtes/réponses HTTP sur une connexion HTTP/2 ? La section 8 répond à cette question. D'abord, il faut se rappeler que HTTP/2 reste du HTTP. L'essentiel des RFC « sémantiques » HTTP, à savoir les RFC 7231, RFC 7232 et les suivants s'applique toujours. Le RFC 7230 reste partiellement applicable : la sémantique est la même mais son expression change. Certains en-têtes disparaissent comme Connection: qui n'est plus utile en HTTP/2.

HTTP reste requête/réponse. Pour envoyer une requête, on utilise un nouveau ruisseau (envoi d'une trame avec un numéro de ruisseau non utilisé), sur laquelle on lira la réponse (les ruisseaux ne sont pas persistents). Dans le cas le plus fréquent, la requête sera composée d'une trame HEADERS contenant les en-têtes (comme User-Agent: ou Host:, cf. RFC 7230, section 3.2) et les « pseudo-en-têtes » comme la méthode (GET, POST, etc), avec parfois des trames DATA (cas d'un POST). La réponse comprendra une trame HEADERS avec les en-têtes (comme Content-Length:) et les pseudo-en-têtes comme le code de retour HTTP (200, 403, 500, etc) suivie de plusieurs trames DATA contenant les données (HTML, CSS, images, etc). Des variantes sont possibles (par exemple, les trames HEADERS peuvent être suivies de trames CONTINUATION). Les en-têtes ne sont pas transportés sous forme texte (ce qui était le cas en HTTP 1, où on pouvait utiliser telnet comme client HTTP) mais encodés selon le RFC 7541. À noter que cet encodage implique une mise du nom de l'en-tête en minuscules.

J'ai parlé plus haut des pseudo-en-têtes : c'est le mécanisme HTTP 2 pour traiter des informations qui ne sont pas des en-têtes HTTP 1. Ces informations sont mises dans les HEADERS HTTP/2, précédés d'un deux-points. C'est le cas de la méthode (RFC 7231, section 4), donc GET sera encodé :method get. L'URL sera éclaté dans les pseudo-en-têtes :scheme, :path, etc. Idem pour la réponse HTTP, le fameux code à trois lettres est désormais un pseudo-en-tête, :status.

Voici un exemple (mais vous ne le verrez pas ainsi si vous espionnez le réseau, en raison de la compression du RFC 7541) :

### HTTP 1, pas de corps dans la requête ###
GET /resource HTTP/1.1          
Host: example.org         
Accept: image/jpeg          

### HTTP/2 (une trame HEADERS)
:method = GET
:scheme = https
:path = /resource
host = example.org
accept = image/jpeg

Puis une réponse qui n'a pas de corps :

### HTTP 1 ###
HTTP/1.1 304 Not Modified      
ETag: "xyzzy"              
Expires: Thu, 23 Jan ... 

### HTTP/2, une trame HEADERS ###
:status = 304
etag = "xyzzy"
expires = Thu, 23 Jan ...

Une réponse plus traditionnelle, qui inclut un corps :

### HTTP 1 ###
HTTP/1.1 200 OK 
Content-Type: image/jpeg   
Content-Length: 123        

{binary data} 

### HTTP/2 ###
# trame HEADERS
:status = 200
content-type = image/jpeg
content-length = 123

# trame DATA
{binary data}

Plus compliqué, un cas où les en-têtes de la requête ont été mis dans deux trames, et où il y avait un corps dans la requête :

### HTTP 1 ###
POST /resource HTTP/1.1    
Host: example.org     
Content-Type: image/jpeg
Content-Length: 123     

{binary data}           

### HTTP/2 ###
# trame HEADERS
:method = POST
:path = /resource
:scheme = https

# trame CONTINUATION
content-type = image/jpeg
host = example.org
content-length = 123

# trame DATA
{binary data}

Nouveauté de HTTP/2, la possibilité pour le serveur de pousser (push, section 8.2 de notre RFC) du contenu non sollicité vers le client (sauf si cette possibilité a été coupée par le paramètre SETTINGS_ENABLE_PUSH). Pour cela, le serveur (et lui seul) envoie une trame de type PUSH_PROMISE au client, en utilisant le ruisseau où le client avait fait une demande originale (donc, la sémantique de PUSH_PROMISE est « je te promets que lorsque le moment sera venu, je répondrai plus longuement à ta question »). Cette trame contient une requête HTTP. Plus tard, lorsque le temps sera venu, le serveur tiendra sa promesse en envoyant la « réponse » de cette « requête » sur le ruisseau qu'il avait indiqué dans le PUSH_PROMISE.

Et enfin, à propos des méthodes HTTP 1 et de leur équivalent en HTTP/2, est-ce que CONNECT (RFC 7231, section 4.3.6) fonctionne toujours ? Oui, on peut l'utiliser pour un tunnel sur un ruisseau. (Un tunnel sur un ruisseau... Beau défi pour le génie civil.)

La section 9 de notre RFC rassemble quelques points divers. Elle rappelle que, contrairement à HTTP 1, toutes les connexions sont persistentes et que le client n'est pas censé les fermer avant d'être certain qu'il n'en a plus besoin. Tout doit passer à travers une connexion vers le serveur et les clients ne doivent plus utiliser le truc d'ouvrir plusieurs connexions HTTP avec le serveur. De même, le serveur laisse les connexions ouvertes le plus longtemps possible, mais a le droit de les fermer s'il doit économiser des ressources.

À noter qu'on peut utiliser une connexion prévue pour un autre nom, du moment que cela arrive au même serveur (même adresse IP). Le pseudo-en-tête :authority sert à départager les requêtes allant à chacun des serveurs. Mais attention si la session utilise TLS ! L'utilisation d'une connexion avec un autre :authority (host + port) n'est possible que si le certificat serveur qui a été utilisé est valable pour tous (par le biais des subjectAltName, ou bien d'un joker).

À propos de TLS (certainement un des points les plus chaudement disputés à l'IETF dans les discussions sur HTTP/2), la section 9.2 prévoit quelques règles qui n'existaient pas en HTTP 1 (et dont la violation peut entrainer la coupure de la connexion avec l'erreur INADEQUATE_SECURITY) :

  • TLS 1.2 (RFC 5246), minimum,
  • Gestion de SNI (RFC 6066) obligatoire,
  • Compression coupée (RFC 3749), comme indiqué dans le RFC 7525 (permettre la compression de données qui mêlent informations d'authentification comme les cookies, et données contrôlées par l'attaquant, permet certaines attaques comme BREACH) ce qui n'est pas grave puisque HTTP a de meilleures capacités de compression (voir aussi la section 10.6),
  • Renégociation coupée, ce qui empêche de faire une renégociation en réponse à une certaine requête (pas de solution dans ce cas) et peut conduire à couper une connexion si le mécanisme de chiffrement sous-jacent ne permet pas d'encoder plus de N octets sans commencer à faire fuiter de l'information.
  • Très sérieuse limitation du nombre d'algorithmes de chiffrement acceptés (voir l'annexe A pour une liste complète), en éliminant les algorithmes trop faibles cryptographiquement (comme les algorithmes « d'exportation » utilisés dans la faille FREAK). Peu d'algorithmes restent utilisables après avoir retiré cette liste !

TLS avait été au cœur d'un vigoureux débat : faut-il essayer systématiquement TLS, même sans authentification, même si l'URL est de plan http: et pas https: ? Ce « chiffrement opportuniste » avait été proposé à l'IETF, pour diminuer l'efficacité de la surveillance massive (RFC 7258). C'était le ticket #314 du groupe de travail, et ce fut un des plus disputés. Quelques articles sur ce sujet du « tentons TLS à tout hasard » : http://bitsup.blogspot.fr/2013/08/ssl-everywhere-for-http2-new-hope.html, http://it.slashdot.org/story/13/11/13/1938207/http-20-may-be-ssl-only, http://www.pcworld.com/article/2061189/next-gen-http-2-0-protocol-will-require-https-encryption-most-of-the-time-.html, https://www.tbray.org/ongoing/When/201x/2013/11/05/IETF-88-HTTP-Security, http://www.mnot.net/blog/2014/01/04/strengthening_http_a_personal_view ou http://lists.w3.org/Archives/Public/ietf-http-wg/2013OctDec/0625.html. Il faut préciser que l'IETF n'a pas de pouvoirs de police : même si le RFC sur HTTP/2 avait écrit en gros « le chiffrement est obligatoire », rien ne garantit que cela aurait été effectif. Finalement, la décision a été de ne pas imposer ce passage en TLS, mais la question reste en discussion à l'IETF pour le plus grand déplaisir de ceux qui voudraient espionner le trafic plus facilement.

Puisqu'on parle de sécurité, la section 10 traite un certain nombre de problèmes de sécurité de HTTP/2. Parmi ceux qui sont spécifiques à HTTP/2, on note que ce protocole demande plus de ressources que HTTP 1, ne serait-ce que parce qu'il faut maintenir un état pour la compression. Il y a donc potentiellement un risque d'attaque par déni de service. Une mise en œuvre prudente veillera donc à limiter les ressources allouées à chaque connexion.

Enfin, il y a la question de la vie privée, un sujet chaud dans le monde HTTP depuis longtemps. Les options spécifiques à HTTP/2 (changement de paramètres, gestion du contrôle de flot, traitement des innombrables variantes du protocole) peuvent permettre d'identifier une machine donnée par son comportement. HTTP/2 facilite donc le fingerprinting.

En outre, comme une seule connexion TCP est utilisée pour toute une visite sur un site donné, cela peut rendre explicite une information comme « le temps passé sur un site », information qui était implicite en HTTP 1, et qui devait être reconstruite.

Question mises en œuvre de la nouvelle version de HTTP, un bon point de départ est la liste du groupe de travail. nginx avait décrit ses plans et a désormais une mise en œuvre de HTTP/2. Pour le cas particulier des navigateurs Web, il y a un joli tableau.

curl a désormais HTTP/2 :


% curl -v --http2 https://www.ietf.org/
* Connected to www.ietf.org (2400:cb00:2048:1::6814:55) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* ALPN, server accepted to use http/1.1
> GET / HTTP/1.1
> Host: www.ietf.org
> User-Agent: curl/7.52.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Tue, 16 May 2017 14:25:47 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: __cfduid=d980f0f518518e9abb9e786531b1cf7ed1494944747; expires=Wed, 16-May-18 14:25:47 GMT; path=/; domain=.ietf.org; HttpOnly
< Last-Modified: Tue, 02 May 2017 20:16:22 GMT

Désolé de ne pas vous montrer un joli pcap de HTTP/2 mais la plupart des sites accessibles en HTTP/2 (et parfois des clients, « Firefox will only be implementing HTTP/2 over TLS ») imposent TLS, ce qui rend un peu plus compliquée l'analyse. Je n'ai pas encore trouvé de pcap HTTP/2 sur pcapr non plus, mais il y en a à la fin de la page http://daniel.haxx.se/http2/.

Et, sinon, si vous voulez activer HTTP/2 sur un serveur Apache, c'est aussi simple que de charger le module http2 et de configurer :

Protocols h2 h2c http/1.1

Sur Debian, la commande a2enmod http2 fait tout cela automatiquement. Pour vérifier que cela a bien été fait, vous pouvez utiliser curl -v comme vu plus haut, ou bien un site de test (comme KeyCDN) ou encore la fonction Inspect element (clic droit sur la page, puis onglet Network puis sélectionner une des ressources chargées) de Firefox : http2-test.png

Quelques articles pertinents :


Téléchargez le RFC 7540


L'article seul

RFC 7539: ChaCha20 and Poly1305 for IETF protocols

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : Y. Nir (Check Point), A. Langley (Google)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF cfrg
Première rédaction de cet article le 15 mai 2015


Les algorithmes de cryptographie ChaCha20 et Poly1305 n'avaient jamais fait l'objet d'une spécification stable, permettant leur référencement pour les protocoles IETF. C'est désormais fait avec ce RFC (depuis remplacé par le RFC 8439), qui normalise aussi bien leur utilisation isolée (ChaCha20 seul ou Poly1305 seul) que leur combinaison, qui fournit du chiffrement intègre (AEAD).

Aujourd'hui, la référence en matière de chiffrement symétrique est AES, entre autres en raison de ses performances très élevées sur du matériel dédié. AES est quatre à dix fois plus rapide que 3DES, qui était la précédente référence. Il est donc logique que AES soit utilisé partout, et notamment qu'il chiffre la quasi-totalité des sessions TLS. Le problème alors est qu'on dépend trop d'AES : si une faille est découverte par la cryptanalyse, on est fichu (AES est par exemple vulnérable dans certains cas). Il serait plus rassurant d'avoir des alternatives sérieuses à AES (n'obligeant pas à revenir à 3DES), pour que d'éventuelles percées en cryptanalyse ne cassent pas toute la crypto d'un coup. D'autant plus qu'AES a un défaut : rapide sur du matériel spécialisé, il l'est moins sur du matériel généraliste.

D'où les algorithmes décrits formellement dans ce RFC. Inventés par Bernstein, ils ont déjà fait l'objet d'un certain nombre d'analyses de sécurité (« New Features of Latin Dances: Analysis of Salsa, ChaCha, and Rumba » et « Latin Dances Revisited: New Analytic Results of Salsa20 and ChaCha »). ChaCha20 est un algorithme de chiffrement symétrique, plus rapide qu'AES sur un matériel générique (mise en œuvre purement en logiciel), Poly1305 est un MAC, et les deux peuvent être combinés pour faire du chiffrement intègre (et cela figure désormais dans le registre sur AEAD).

La section 2 du RFC décrit les algorithmes (je ne la reprends pas ici, la crypto, c'est trop fort pour moi), et ajoute du pseudo-code, des exemples et des vecteurs de test (il y en a d'autres dans l'annexe A). À l'origine, Poly1305 était décrit comme lié à AES, pour obtenir, par chiffrement du numnique, une chaîne de bits unique et secrète. Mais, en fait, n'importe quelle fonction de chiffrement convient, pas uniquement AES. (L'article du Wikipédia anglophone sur Poly1305 continue à colporter cette erreur.)

En cryptographie, ce sont plus souvent les mises en œuvre que les algorithmes qui ont une faille. La section 3 est donc consacrée aux avis aux programmeurs, pour éviter qu'une erreur de leur part n'affaiblisse ces beaux algorithmes. Poly1305 nécessite de travailler avec des grands nombres et le RFC déconseille d'utiliser la plupart des bibliothèques existantes de gestion des grands nombres comme celle d'OpenSSL. Celles-ci sont trop souvent vulnérables à des attaques par mesure du temps écoulé et le RFC conseille d'utiliser uniquement des bibliothèques qui font leur travail en un temps constant, comme NaCl. Un exemple de mise en œuvre de Poly1305 est poly1305-donna.

La section 4, sur la sécurité, détaille les points importants à suivre pour ne pas se faire casser sa jolie crypto. Pour ChaCha20, avant tout, il faut utiliser un numnique (numnique ?) vraiment unique. On peut utiliser un compteur, on peut utiliser un LFSR, mais il doit être unique.

ChaCha20 et Poly1305 n'utilisent que des opérations simples, normalement faciles à implémenter en un temps constant, qui ne permettra pas à l'attaquant de déduire quoi que ce soit de la mesure des temps de réponse. Attention, programmeurs, certaines fonctions comme la classique memcmp() ne s'exécutent pas en un temps constant, et, si elles sont utilisées, permettent certaines attaques.

À noter que ces algorithmes ne sont pas encore dans le registre IANA des algorithmes TLS. Leur mise en œuvre dans Chrome et chez CloudFlare utilise une valeur non-standard et non interopérable pour identifier l'algorithme. Les discussions se poursuivent pour intégrer ChaCha20 à Firefox. Notez aussi un bon article d'explication de CloudFlare.

La norme pour ces algorithmes est, depuis mai 2018, le RFC 8439.


Téléchargez le RFC 7539


L'article seul

RFC 7538: The Hypertext Transfer Protocol (HTTP) Status Code 308 (Permanent Redirect)

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : J. Reschke (greenbyte)
Chemin des normes
Première rédaction de cet article le 10 avril 2015


Le protocole HTTP définit plusieurs codes de retour pour une redirection (« la ressource que tu cherches n'est pas ici, va voir là »). La section 6.4 du RFC 7231 classe ces trois codes de retour en notant que deux désignent des redirections temporaires (302 et 307) et qu'un désigne une redirection permanente (301). Deux codes permettent au client HTTP de remplacer, pour la nouvelle requête, la méthode POST par un GET (301 et 302), un autre ne le permet pas (307). Si vous avez suivi, vous avez noté qu'il manquait un code voulant dire « redirection permanente mais sans changer la méthode HTTP ». C'est l'objet du nouveau code décrit à l'origine dans le RFC 7238, et normalisé pour la première fois dans ce RFC, le code 308. Depuis, le RFC 9110 a intégré ce code, qui n'a donc plus de RFC séparé.

Donc, 308 veut dire (section 3 de notre RFC) que la ressource Web convoitée a changé de place, que c'est permanent et que le client HTTP devrait donc aller chercher la ressource au nouvel endroit et, s'il le peut, modifier sa base de données (dans le cas d'un crawler, par exemple, ou dans celui d'un navigateur qui modifie les marque-pages). Où est indiqué « le nouvel endroit » ? Par l'en-tête Location: de la réponse HTTP (cf. section 7.1.2 du RFC 7231). Il est recommandé d'inclure un petit texte en HTML fournissant un autre moyen de suivre la redirection, si le client HTTP n'a pas compris le 308. Bref, le 308 est très proche du 301, à la seule exception près qu'un client n'a pas le droit de changer la méthode HTTP (POST, GET, etc) utilisée. Le nouveau code est désormais dans le registre IANA.

Est-ce que l'information comme quoi il y a redirection peut être mémorisée dans les caches ? Il n'y a pas de mécanisme parfait pour cela mais lesdits caches sont invités à regarder le RFC 7234.

Ajouter un nouveau code HTTP peut provoquer des problèmes de déploiement (section 4). En effet, la section 6 du RFC 7231 dit que les codes inconnus commençant par 3 doivent être traités comme le code 300 (qui annonce des choix multiples, en cas de négociation de contenu). Au début, 308 va être inconnu de tous les clients HTTP et sera donc mal interprété. (Vous pouvez tester votre navigateur ici.) Il n'y aura pas de redirection automatique. En attendant que tous les clients soient mis à jour, le webmestre prudent n'utilisera 308 que s'il connait les clients utilisés, ou s'il sait que l'absence de redirection automatique n'est pas trop grave. Le RFC déconseille formellement de faire varier la réponse selon le client (ou selon ce qu'on croit être le client, rappelez-vous que le champ User-Agent: peut être trompeur), cela rend le Web trop difficile à déboguer.

Une façon de s'en tirer pourrait être via le code HTML suggéré plus haut. Par exemple :


HTTP/1.1 308 Permanent Redirect
Content-Type: text/html; charset=UTF-8
Location: http://example.com/new
Content-Length: 454

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
                      "http://www.w3.org/TR/html4/strict.dtd">
<html>
   <head>
      <title>Permanent Redirect</title>
      <meta http-equiv="refresh"
                 content="0; url=http://example.com/new">
   </head>
   <body>
      <p>
         The document has been moved to
         <a href="http://example.com/new">
         http://example.com/new</a>.
      </p>
   </body>
</html>

Ainsi, un navigateur Web qui ne comprend pas le 308 sera redirigé, via le <meta http-equiv="refresh" ....

Où en sont les mises en œuvre ? Vous pouvez tester sur le test de libcurl. Pour les navigateurs et autres clients :

Enfin, je signale deux bons articles sur le 308, un en français et un en anglais. Et, plus technique, la liste des tests qui ont montré que les déploiements du code 308 étaient suffisants pour que l'ancien RFC, expérimental, le RFC 7238, soit remplacé par ce nouveau RFC, qui est, lui, sur le chemin des normes. Aucun changement technique n'a été apporté, juste ce changement de statut.


Téléchargez le RFC 7538


L'article seul

RFC 7536: Large-Scale Broadband Measurement Use Cases

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : Marc Linsner (Cisco Systems), Philip Eardley, Trevor Burbridge (BT), Frode Sorensen (Nkom)
Pour information
Réalisé dans le cadre du groupe de travail IETF lmap
Première rédaction de cet article le 8 mai 2015


Mesurer les performances d'un réseau, c'est crucial. Cela permet de savoir si le réseau a bien les caractéristiques promises et cela permet de comparer les réseaux entre eux. D'où l'existence du groupe de travail LMAP de l'IETF, dont voici le premier RFC. Il décrit deux études de cas où la mesure est nécessaire : un opérateur qui veut s'assurer de la qualité du service qu'il fournit, et un régulateur des télécommunications qui veut vérifier que les opérateurs livrent bien ce qu'ils promettent, et ne discriminent pas certaines utilisations. Il y a bien sûr d'autres cas possibles (l'utilisateur final qui veut mesurer les performances de sa connexion...)

Ce RFC concerne aussi bien les mesures de l'accès fixe (ADSL, par exemple) que de l'accès par un mobile. Il n'y a aucune différence dans les problèmatiques métrologiques entre ces deux accès.

La section 2 de notre RFC décrit les deux scénarios d'usage, repris ensuite en détail dans la section 3 pour le cas du FAI et dans la section 4 pour le cas du régulateur. Commençons par le FAI. La mesure de son réseau l'aide à :

  • Identifier et isoler des problèmes (par exemple un lien saturé),
  • Vérifier que des SLA sont respectés,
  • Concevoir les extensions à son réseau (où faut-il déployer le nouveau matériel et les nouvelles fibres, en priorité),
  • Comprendre le vécu des clients (ce qu'on nomme parfois la QoE - Quality of Experience, qui ne dépend pas seulement de données brutes, comme la capacité des câbles, mais aussi de services comme les résolveurs DNS ou comme les CDN),
  • Comprendre (voire prédire) l'impact de nouvelles technologies déployées dans le réseau. (Le RFC prend l'exemple d'IPv6, pour les opérateurs attardés qui ne l'ont pas encore déployé.) Cela peut aussi concerner des problèmes bien plus triviaux comme la mise à jour du firmware d'une machine qui entraine tout à coup une chute des performances.

Il y a plein de détails techniques à prendre en compte pour ce genre de mesures et le problème est bien plus complexe que ne le croit l'amateur qui débarque dans le domaine. Par exemple, le RFC note que la mesure du vécu de l'utilisateur nécessite des mesures de bout en bout, jusqu'à la machine de M. Michu, mais que le réseau de ce dernier, dans sa maison, n'est pas sous le contrôle du FAI (le Wi-Fi peut être peu efficace en raison de problèmes radio). Le FAI tend donc plutôt à mesurer jusqu'au CPE, ce qui est plus fiable mais moins représentatif.

La meilleure façon de mesurer les caractéristiques du réseau est de faire des mesures actives, avec une machine qui envoie des requêtes et mesure le résultat. Pour ne pas interférer avec le trafic normal de l'utilisateur, il vaut mieux faire ces mesures actives lorsque l'utilisateur ne fait rien. Cela implique que le dispositif de mesure puisse savoir quand l'utilisateur est inactif (la documentation de SamKnows demande que l'engin soit placé en coupure sur le réseau local, lui permettant ainsi d'observer tout le trafic).

Des mesures actives lancées à la demande peuvent même être utilisées en réponse à une plainte d'un utilisateur. Il appelle le support en disant « Ça rame », l'employé au support clique sur un bouton sur son interface Web et cela lance des tests de performance depuis la box de cet abonné et, quelques secondes plus tard, leurs résultats s'affichent sur l'écran du support.

Une autre solution est de faire uniquement des mesures passives mais elles ne permettent d'observer que le débit, pas la capacité (qui est le débit maximum possible). Si on mesure 2 Mb/s de trafic, est-ce parce que le réseau ne permet pas plus ou bien simplement parce que c'est ce que fait l'utilisateur en ce moment ? En outre, les mesures passives soulèvent des problèmes liés à la protection de la vie privée.

Le régulateur, lui, veut évaluer les performances de plusieurs opérateurs et, typiquement, les publier (ce qui nécessite de la rigueur dans les faits et de la pédagogie dans les explications). Cela peut servir par exemple à mesurer le déploiement de l'accès Internet à « haut débit », ou bien à mesurer les pratiques de « gestion du trafic » (terme qui, dans le code des FAI, désigne les discriminations contre tel ou tel type de trafic). Dans tous les cas, vu les conséquences de la publication de ces mesures, le régulateur va devoir s'assurer qu'elles sont précises, significatives et reproductibles.

Il existe plusieurs façons de faire ces mesures : on peut utiliser par exemple un panel d'utilisateurs supposés représentatifs, et installer chez eux un équipement de mesure active, qui signale ce qu'il a obtenu à un serveur central. C'est ainsi que fonctionne SamKnows (ou bien un autre système, non utilisé par le régulateur, les sondes Atlas). Une autre solution, non mentionnée par notre RFC, est de mettre les sondes de mesure, non pas chez les utilisateurs (où il est très difficile de s'assurer qu'elles sont branchées correctement, et où elles peuvent rentrer en concurrence avec le trafic normal de l'utilisateur) mais dans des locaux spécialisés, loués à cette fin. C'est ce que fait l'ARCEP pour ses mesures de l'accès à l'Internet en France.

Une des motivations, pour le régulateur, est de déterminer les violations de la neutralité de l'Internet, afin de savoir s'il est utile de prendre des mesures légales ou autres, pour rétablir cette neutralité. Déterminer, par des mesures actives, si certains services réseau ou certaines destinations sont favorisés ou au contraire défavorisés n'est pas facile (cf. le projet Glasnost et sa publication « Enabling End Users to Detect Traffic Differentiation »). À l'inverse, détecter un blocage complet (par exemple la fermeture du port 25) est plus simple. Le sujet de la neutralité du réseau est, à juste titre, très chaud, et cette demande d'une mesure du phénomène restera sans doute élevée (cf. les règles du BEREC).

La section 5 de notre RFC se penche ensuite sur des détails pratiques dans la mise en œuvre de ces mesures. On va donc avoir N sondes qui font faire des mesures et un serveur central qui collectera les mesures (ce qui nécessitera un protocole de communication, de préférence sécurisé, entre les sondes et ce serveur). Les mesures seront répétées automatiquement et/ou pourront être activées à la demande (par exemple pour déboguer un problème précis). Une fois téléversés dans le serveur, les résultats des mesure devront être analysés (et ce sont parfois d'assez gros fichiers). L'analyse, quoique non couverte dans ce RFC, est également une source de risques. Comme dit l'adage « les chiffres, on leur fait dire ce qu'on veut ». Par exemple, le comité technique de l'ARCEP qui était chargé de superviser les décisions techniques pour le programme de mesure a eu à étudier des questions délicates comme la suppression de mesures aberrantes.

De nombreux choix pratiques vont ensuite se poser. Par exemple, la sonde active doit-elle être faite avec du matériel spécialisé (c'est le cas de SamKnows, de la mesure ARCEP, ou des RIPE Atlas) ou bien avec du logiciel que les utilisateurs téléchargeront (comme Grenouille ou Netalyzr). Ces sondes spécialisées sont plus coûteuses, compliquées à déployer (on ne peut pas en mettre partout, il faut des critères de sélection, etc) mais plus fiables que la machine de M. Michu, probablement bourrée de virus qui la ralentissent, et qui n'est pas forcément allumée en permanence. (Une autre différence vient du fait que la sonde spécialisée peut être branchée immédiatement après le routeur, s'épargnant ainsi d'utiliser un LAN peu fiable et irrégulier.) Dans les deux cas, il faudra se demander si l'échantillon est vraiment représentatif ou si l'auto-sélection plus ou moins grande des utilisateurs a trop biaisé les résultats.

Enfin, la section 7 de notre RFC se penche sur les problèmes de sécurité, notamment de protection de la vie privée (RFC 6973). Parmi les risques, si on crée une infrastructure de mesures actives, on a fabriqué un gentil botnet. Si un méchant peut en prendre le contrôle, il peut l'utiliser pour des attaques par déni de service réparties. (C'est une des raisons pour lesquelles l'exécution de mesures par les sondes Atlas, ouverte au public, est soumise à la dépense d'un certain nombre de crédits.) Toujours en cas de mesures actives, les sondes peuvent potentiellement balayer des réseaux internes qui ne seraient normalement pas accessibles de l'Internet (c'est pour cela que les Atlas ne peuvent pas tester les adresses du RFC 1918, car elles pourraient alors être utilisées pour la reconnaissance du réseau local où elles sont situées). Si les sondes ont des capacités de collecte passive, un méchant peut les utiliser comme « boîtes noires » d'espionnage des réseaux sur lesquels elles sont connectées. Il est donc nécessaire de ne pas fournir un accès illimité à ces sondes. Elle doivent n'être accessibles qu'à leur contrôleur, après authentification forte, et, si elle peuvent exécuter des mesures choisies par les utilisateurs (cas des sondes Atlas), ces mesures doivent être limitées (ainsi, les 1es Atlas ne peuvent pas lancer de téléchargement HTTP depuis un URL quelconque).

Dans le cas de mesures comparatives (« le FAI X est 20 % plus rapide que le FAI Y »), un autre risque de sécurité est celui de triche. Un attaquant qui contrôlerait, au moins partiellement, le système, risquerait de pouvoir fausser les résultats et favoriser un FAI par rapport aux autres. Là encore, de bonnes pratiques de sécurité sont nécessaires. Il y a enfin des attaques plus subtiles, comme d'identifier les lignes où des mesures sont faites, et les favoriser, obtenant ainsi de meilleurs résultats.


Téléchargez le RFC 7536


L'article seul

RFC 7535: AS112 Redirection using DNAME

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : J. Abley (Dyn), B. Dickson (Twitter), W. Kumari (Google), G. Michaelson (APNIC)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 15 mai 2015


Les serveurs DNS, notamment ceux de la racine, sont en permanence bombardés par un trafic « inutile », des demandes de résolution DNS d'origine locale, et qui n'auraient jamais dû sortir. Par exemple, dans les réseaux qui utilisent les adresses IP privées du RFC 1918, les demandes de « résolution inverse » (« quel est le nom correspondant à 192.168.24.66 ? ») devraient toujours être résolues localement (après tout, il s'agit d'adresses privées) mais souvent les gestionnaires de ces réseaux ne configurent pas correctement leurs résolveurs et paf, la requête 66.24.168.192.in-addr.arpa arrive à la racine, qui ne peut pas en faire grand'chose. Idem si un réseau local utilise (bien à tort) un TLD local comme .home ou .corp. Les requêtes pour des TLD inexistants font plus de 25 % du trafic atteignant la racine. Pour les noms correspondants aux adresses du RFC 1918, le problème a été réglé par la création d'un « puits DNS », l'AS112 (RFC 7534). Les serveurs de l'AS112 sont des machines sacrifiées, à qui on envoie toutes les requêtes pour les noms en in-addr.arpa correspondant au RFC 1918. Cela marche très bien depuis de nombreuses années. Tellement bien qu'on se dit qu'on pourrait jeter dans ce puits bien d'autres choses comme les équivalents IPv6 du RFC 1918 (d.f.ip6.arpa, par exemple, cf. RFC 4193), ou comme les TLD tel que .home. Seulement, voilà, l'AS112 n'a pas été prévu pour cela et, avec leur configuration actuelle, ses serveurs ne répondraient pas correctement à ces requêtes. Il suffit de changer cette configuration ? Plus facile à dire qu'à faire, car l'AS112 est composé de nombreux serveurs plus ou moins coordonnés. Il est probablement impossible de les reconfigurer tous. D'où la nouvelle technique, utiliser (pour la première fois en grand) les enregistrements DNAME.

La nature même de l'AS112, système très décentralisé, sans direction claire, fait qu'il est impossible de changer la configuration de tous les nœuds. Même si l'IETF, l'ARCEP, l'ICANN, la NSA, le CSA et Jean-Kevin étaient tous d'accord, on ne pourrait pas garantir qu'il ne traine pas des nœuds AS112 ayant l'ancienne liste. Et puis on ne veut pas faire juste un changement une fois. On voudrait davantage de souplesse, permettant d'ajouter (ou de retirer) des noms à l'AS112 facilement, sans passer à chaque fois des mois, voire des années, à rappeler aux gérants des serveurs AS112 qu'ils doivent changer leur configuration.

Comme toujours avec l'AS112, l'idéal serait que les administrateurs DNS fassent tous correctement leur travail et suivent le RFC 6303, qui leur impose de servir des zones comme *.168.192.in-addr.arpa localement. Mais, dans le monde réel, ça n'arrive pas et l'AS112 (nommé, j'ai oublié de le dire, d'après le numéro de système autonome qui lui a été attribué) reste indispensable.

On a vu plus haut que l'AS112 n'était que faiblement coordonné. Ses serveurs sont anycastés (RFC 4786) et composés de nombreuses machines, administrées par des personnes différentes. Si on décidait de déléguer, mettons, .home, aux serveurs de l'AS112, blackhole-1.iana.org et blackhole-2.iana.org, certaines des instances de ces deux serveurs seront correctement configurées et répondront, à juste titre, NXDOMAIN (ce domaine n'existe pas : c'est la réponse unique de l'AS112). Mais d'autres instances, administrées avec retard, ou gérées par des gens surmenés qui ont raté l'annonce faite sur la liste des gérants AS112, ne sauront pas qu'elles doivent répondre aux requêtes pour *.home. Elles seront en lame delegation, avec des résultats plus ou moins bons (selon le logiciel utilisé) tels qu'une réponse REFUSED (qui poussera les résolveurs à essayer un autre serveur de la zone, alors que l'objectif était au contraire de diminuer le trafic).

L'IETF a donc choisi une voie différente pour l'évolution de l'AS112 : créer un nouveau préfixe, qui recevra les délégations des nouveaux in-addr.arpa, ip6.arpa, TLD, etc. Les nœuds utilisant ce nouveau préfixe utiliseront une nouvelle technique, à base de DNAME (RFC 6672), pour ne pas avoir à être configuré avec la liste des domaines à servir. Cela permettra de faire évoluer cette liste, ce qui est organisationnellement impossible avec les préfixes actuels de l'AS112.

Un enregistrement DNAME dit qu'une zone est un alias d'une autre. Ainsi :

example.com.     DNAME    example.net.

va faire que tous les noms sous example.com (mais pas example.com lui-même, attention), sont les alias des noms correspondants en example.net. Si on veut trouver l'adresse IPv6 associée à foobar.example.com, le résolveur DNS, en trouvant le DNAME, fera une requête pour foobar.example.net et en transmettra le résultat à l'utilisateur.

La nouvelle zone de l'AS112 se nomme empty.as112.arpa et elle est déléguée à un seul serveur (anycasté), blackhole.as112.arpa (192.31.196.1 / 2001:4:112::1). Ce serveur n'a pas les mêmes adresses que les serveurs traditionnels de l'AS112, il y aura deux jeux de serveurs complètement différents, puisqu'ils auront une configuration distincte (une liste fixée de domaines pour les anciens serveurs, cf. RFC 6304, et une seule zone, la cible des DNAME, pour les nouveaux serveurs). Certains serveurs pourront faire partie des deux jeux à la fois (par exemple des anciens serveurs qui seraient modifiés pour gérer les nouvelles adresses en même temps que les anciennes). L'ancien AS112 continue à fonctionner comme avant. Les nouveaux préfixes anycast correspondants sont 192.31.196.0/24 et 2001:4:112::/48, qui ne servent qu'à l'AS112. (Vous pouvez les chercher dans le looking glass de votre choix. L'AS d'origine sera le 112. L'AS112 est désormais à l'origine de quatre préfixes.) Ces adresses IP du serveur du nouvel AS112 ont été enregistrées dans le registre des adresses spéciales créé par le RFC 6890.

Donc, si vous voulez rediriger une zone DNS vers le puits du nouvel AS112, il suffit d'en faire un DNAME de empty.as112.arpa. Oui, aucun besoin de prévenir qui que ce soit, ou de demander une autorisation, vous n'avez qu'à ajouter cet enregistrement.

Un petit mot pour les fanas de gouvernance : le RFC 3172 confie la gestion politique de .arpa à l'IAB et c'est donc celle-ci qui a eu à approuver, sinon ce RFC, du moins le domaine dont il avait besoin, as112.arpa.

À l'heure actuelle, je n'ai pas l'impression qu'il y ait déjà des redirections vers empty.as112.arpa (en tout cas, DNSDB n'en trouve pas). Il faut dire qu'il y a encore peu de serveurs dans le nouvel AS112. Une fois qu'il sera peuplé, et pourra donc gérer le trafic, on pourra mettre des redirections. Rappelez-vous que l'installation d'une redirection ne nécessite aucun changement dans les serveurs du nouvel AS112. Pour tester, vous pouvez utiliser ma zone sink.bortzmeyer.fr. Normalement, nimportequoi.sink.bortzmeyer.fr doit vous obtenir un NXDOMAIN de la part du serveur AS112 « le plus proche ». Voici, vu par les sondes Atlas les différentes réponses possibles pour le nouvel AS112, ce qui semble indiquer qu'il n'a que quatre serveurs :

%  python resolve-name.py -t SOA empty.as112.arpa
Measurement #2004698 for empty.as112.arpa/SOA uses 497 probes
[] : 11 occurrences
[as112.ottix.net. dns.ottix.net. 1 604800 60 604800 604800] : 2 occurrences
[blackhole.as112.arpa. dns.ripe.net. 1 604800 60 604800 604800] : 226 occurrences
[as112.hivane.net. info.hivane.net. 1 604800 60 604800 604800] : 184 occurrences
[blackhole.as112.arpa. noc.dns.icann.org. 1 604800 60 604800 604800] : 60 occurrences
Test done at 2015-05-14T10:59:36Z

Et l'ancien AS112 ? Il continue à fonctionner comme avant. Si le nouvel AS112 marche bien, s'il est largement peuplé, on pourra changer les actuelles délégations des zones RFC 1918 comme 10.in-addr.arpa et les remplacer par une redirection DNAME vers empty.as112.arpa, le nouvel AS112. Une fois que cela sera fait, l'ancien AS112 et ses serveurs blackhole-1.iana.org et blackhole-2.iana.org pourront être supprimés. Il n'y a toutefois pas de plan précis pour cela : il faut d'abord que le nouvel AS112 fasse ses preuves.

Quelles zones seront mises dans le nouvel AS112 ? Comme indiqué plus haut, n'importe quelle zone peut être déléguée au nouvel AS112 de manière unilatérale. Mais ce service est surtout utile pour les zones à fort trafic, comme celles listées dans le RFC 6303 (qui ne sont pas toutes dans l'ancien AS112, par exemple aucune zone en ip6.arpa n'y est) ou comme certains TLD (les plus importants à l'heure actuelle sont, dans l'ordre, .local, .home, .html, .localdomain et .internal). Dans le cas des TLD, toutefois, il est probable que l'incroyable bureaucratie ICANN et la mainmise du gouvernement états-unien sur le contenu de la racine ne retardent considérablement le projet.

Le choix d'utiliser DNAME n'a pas été sans mal. En effet, DNAME ne fait pas partie du DNS original, et ce n'est pas un simple type d'enregistrement pour des données passives, il nécessite un traitement spécifique dans les résolveurs (et, dans une certaine mesure, dans les serveurs faisant autorité). On ne peut donc pas compter sur 100 % de serveurs DNS gérant DNAME. Est-ce un problème ? Le RFC 6672 prévoit un mécanisme de secours, où l'enregistrement DNAME est accompagné d'un CNAME (les alias classiques) synthétisé à la demande par le serveur. En théorie, tout doit donc bien se passer, même dans un monde imparfait où tous les serveurs ne gèrent pas DNAME. Et en pratique ? L'annexe A décrit les expérimentations qui avaient été faites avant de choisir la solution DNAME (quelques autres avaient été proposées). Le test avait consisté en quatre images sur une page Web que devait charger les navigateurs. La page était distribuée sous forme d'une publicité payante, envoyée par la régie publicitaire à de nombreux navigateurs. Le premier URL, http://a.UNIQUE_STRING.dname.example.com/1x1.png?a.UNIQUE_STRING.dname utilise un domaine qui a un DNAME vers un autre domaine. Si tout l'Internet peut travailler avec des DNAME sans problème, l'image correspondante sera chargée dans 100 % des cas. (La chaîne de caractères UNIQUE_STRING est la même pour toutes les images mais varie à chaque chargement de la page. C'est donc l'identificateur d'un test donné.) Le second URL, http://b.dname.example.com/1x1.png?b.UNIQUE_STRING.dname, qui, contrairement au premier, utilise un nom de domaine qui a un DNAME, et qui n'a pas de partie unique et est donc fréquemment mis en cache. Le troisième URL, http://c.UNIQUE_STRING.target.example.net/1x1.png?c.UNIQUE_STRING.target, ressemble beaucoup au premier mais n'utilise pas du tout de DNAME. C'est du DNS on ne peut plus traditionnel, et il sert donc de contrôle : si le score est de moins de 100 % sur cette troisième image, c'est que le navigateur, la machine sur laquelle il tourne, ou bien le réseau qui l'héberge, ont d'autres problèmes que les DNAME. Un script en Flash dans la page mesure le résultat et le temps nécessaire pour l'obtenir. Enfin, une quatrième image, http://results.recorder.example.net/1x1.png? results.UNIQUE_STRING?za=FIRST_RESULT&zb=SECOND_RESULT&zc=THIRD_RESULT, sert juste à transmettre les résultats. Le journal du serveur HTTP ressemblera à :

GET /1x1.png?results.UNIQUE_STRING?za=1822&zb=1674&zc=1582

(Les chiffres sont les temps de chargement en millisecondes.)

Les résultats ? 98,1 % des tests ont permis le chargement de la première ou de la seconde image, celles qui utilisaient les DNAME. Il y a donc 1,9 % de clients qui ne peuvent pas utiliser les DNAME ? Non, car 2,8 % des tests de chargement de la troisième image (qui n'utilise pas de DNAME, que du DNS d'avant-guerre) ont également échoué. Ce qui montre que ce chiffre de 1,9 % est inférieur au pourcentage d'erreur (soubresauts du réseau, etc). Bref, les DNAME marchent très bien.

À noter que les serveurs du nouvel AS112, eux, n'ont aucun besoin de savoir gérer les DNAME. Seuls les résolveurs, et les serveurs faisant autorité pour les zones redirigées doivent le faire.

Le as112.arpa a été délégué début février 2015 :

% check-soa -i as112.arpa
a.iana-servers.net.
	199.43.132.53: OK: 2014122469 (2 ms)
	2001:500:8c::53: OK: 2014122469 (14 ms)
b.iana-servers.net.
	199.43.133.53: OK: 2014122469 (149 ms)
	2001:500:8d::53: OK: 2014122469 (156 ms)
c.iana-servers.net.
	2001:500:8e::53: OK: 2014122469 (13 ms)
	199.43.134.53: OK: 2014122469 (15 ms)

Et son fils :

% check-soa -i empty.as112.arpa
blackhole.as112.arpa.
        2001:4:112::1: OK: 1 (31 ms)
        192.31.196.1: OK: 1 (23 ms)

Voici une réponse actuelle pour le nouveau domaine :


% dig ANY empty.as112.arpa

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> ANY empty.as112.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30414
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 1, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;empty.as112.arpa.	IN ANY

;; ANSWER SECTION:
empty.as112.arpa.	604800 IN SOA blackhole.as112.arpa. dns.ripe.net. (
				1          ; serial
				604800     ; refresh (1 week)
				60         ; retry (1 minute)
				604800     ; expire (1 week)
				604800     ; minimum (1 week)
				)
empty.as112.arpa.	3599 IN	RRSIG NSEC 8 3 3600 20150515204633 (
				20150508164936 52494 as112.arpa.
				lZf9d6oYISRAq8i6gLXXCwUoQP+qmOfAEIiY3hNr6PvD
				DE1kSeGGR3lo3fK6P/CajYv/8twZm/CNQvpAxlRLUyrY
				Hc2WHhgxCtiQx01pLrY9d/QRhiL1WqYZaMSrfNZX0H0S
				GUD1BOcVNzT/lYPz0EdZZKzEXle98ZGWwkIvewE= )
empty.as112.arpa.	3599 IN	NSEC hostname.as112.arpa. NS RRSIG NSEC
empty.as112.arpa.	3599 IN	NS blackhole.as112.arpa.

;; AUTHORITY SECTION:
empty.as112.arpa.	3599 IN	NS blackhole.as112.arpa.

;; ADDITIONAL SECTION:
blackhole.as112.arpa.	3599 IN	A 192.31.196.1
blackhole.as112.arpa.	3599 IN	AAAA 2001:4:112::1
blackhole.as112.arpa.	3599 IN	RRSIG A 8 3 3600 20150516053029 (
				20150508164936 52494 as112.arpa.
				B4eU9u5ZQVGf+Haro2CeCanWwFLeK3hvil8dIlpz1fMm
				xR8K1No4rWTV5hWME1GhFatZVgpATfat9A3rghGWB9Xm
				hcmsaE5uHTOB+56DNhiokWsVtj+WT828naDMlfvGWiP4
				cXIxF/tLcR10XYviczlKYYR/SgAVxgmwjFkBHXg= )
blackhole.as112.arpa.	3599 IN	RRSIG AAAA 8 3 3600 20150515212644 (
				20150508164936 52494 as112.arpa.
				Yk2l+kWkYbYruCNHIKZwGg8GZPDp9y5Qezqk+Ogq5rGF
				/3+R/UjPPw240zdnLi4D2DeBFwlvM8rDq0xt3sreEmdk
				jMdxGcAc8eEfM6O1heP7lgRJW4eCzwOdNX6f1IXEIerg
				XwYWu+3VjI6y4NsrYoczfo+ORAHsdUvz9rdYumk= )

;; Query time: 854 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Fri May  8 20:43:04 2015
;; MSG SIZE  rcvd: 726


Téléchargez le RFC 7535


L'article seul

RFC 7534: AS112 Nameserver Operations

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : J. Abley (Dyn), W. Sotomayor (OttIX)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 15 mai 2015


Le système AS112, décrit dans ce RFC, est à la fois un utile composant du DNS, améliorant les performances et reduisant la charge du réseau, un banc d'essai pour des nouvelles techniques comme l'anycast, et une expérimentation sociale, celle d'un service 100 % acentré.

Un certain nombre de sites connectés à l'Internet utilisent des adresses IP privées, tirées du RFC 1918. Bien des logiciels, lorsqu'ils voient passer un nouveau client, font une résolution DNS pour obtenir le nom du client en fonction de son adresse IP (résolution dite PTR). C'est par exemple le cas du serveur de courrier Postfix, chez qui ce comportement n'est pas débrayable. Lorsque l'adresse IP est privée, il ne sert à rien de poser la question au DNS public. Par définition, celui-ci ne peut pas savoir que MaPetiteEntreprise utilise 192.168.1.0/24 et a attribué 192.168.1.33 à posteclientX.mapetiteentreprise.example. La bonne pratique est donc que l'administrateur réseaux d'un site qui utilise ces adresses privées doit configurer des serveurs DNS pour répondre aux requêtes PTR (cf. RFC 6303). Pour voir cela, on peut utiliser l'option -x de dig, qui permet de faire automatiquement une résolution d'adresse en nom. Le domaine in-addr.arpa (RFC 5855) accueille la forme inversée des adresses (192.168.1.33 devient 33.1.168.192.in-addr.arpa). Testons ici une adresse publique :

% dig -x 192.134.4.20
...
;; ANSWER SECTION:
20.4.134.192.in-addr.arpa. 172800 IN    PTR     rigolo.nic.fr.

Mais beaucoup d'administrateurs réseaux sont négligents, surchargés de travail, incompétents ou les trois à la fois. Ils ne configurent pas ces serveurs DNS et, résultat, la requête PTR sort de leur réseau et va taper sur les serveurs DNS de la racine puis à ceux de in-addr.arpa. (Une bonne partie du trafic semble ainsi venir des réseaux 3G, où le smartphone ne reçoit qu'une adresse privée et où le résolveur DNS qui lui est indiqué ne connait pas les zones correspondantes.) Ceux-ci ont normalement autre chose à faire que de répondre à des requêtes qui sont, dès le départ, des erreurs. Ils délèguent donc à l'AS112, un ensemble de serveurs de noms qui est chargé de répondre « ce nom n'existe pas » à toutes ces requêtes parasites. L'AS112 est donc un puits où finissent les erreurs. Initialement normalisé dans le RFC 6304, il est désormais décrit par ce nouveau RFC. Le nouvel AS112 introduit une importante nouveauté, un mécanisme de délégation utilisant les enregistrements DNAME (RFC 6672) et qui permet de désigner plus facilement des zones à diriger vers le puits. Il y a donc désormais l'ancien AS112 (qui continue à fonctionner et à servir les zones du RFC 1918) et le nouvel AS112, qui servira les futures zones comme les ULA IPv6 du RFC 4193, ou comme des TLD tels que .local ou .home.

On peut voir la délégation de l'ancien AS112 (ancien mais toujours utilisé) avec dig (sauf si votre résolveur suit les recommandations du RFC 6303) :


% dig NS 168.192.in-addr.arpa

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> NS 168.192.in-addr.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56121
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;168.192.in-addr.arpa.  IN NS

;; ANSWER SECTION:
168.192.in-addr.arpa.   8726 IN NS blackhole-2.iana.org.
168.192.in-addr.arpa.   8726 IN NS blackhole-1.iana.org.

;; ADDITIONAL SECTION:
blackhole-1.iana.org.   604 IN A 192.175.48.6
blackhole-1.iana.org.   603 IN AAAA 2620:4f:8000::6
blackhole-2.iana.org.   603 IN A 192.175.48.42
blackhole-2.iana.org.   603 IN AAAA 2620:4f:8000::42

;; Query time: 2 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Fri May 15 10:28:38 2015
;; MSG SIZE  rcvd: 197

La délégation va être conservée dans les mémoires caches des résolveurs DNS et la racine ou in-addr.arpa ne seront donc plus embêtés, après la première requête.

Pour le nouvel AS112, utilisant la technique du RFC 7535, la délégation est :


% dig NS empty.as112.arpa

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> NS empty.as112.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25550
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;empty.as112.arpa.      IN NS

;; ANSWER SECTION:
empty.as112.arpa.       3595 IN NS blackhole.as112.arpa.

;; ADDITIONAL SECTION:
blackhole.as112.arpa.   3595 IN A 192.31.196.1
blackhole.as112.arpa.   3595 IN AAAA 2001:4:112::1

;; Query time: 2 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Fri May 15 10:29:25 2015
;; MSG SIZE  rcvd: 113

Mais qui sont ces machines 192.175.48.6, 192.175.48.42 et 192.31.196.1 ? Des très gros serveurs payés par un mécène et installés à un endroit bien connecté ? Pas du tout. C'est ici que rentre en jeu l'AS112. Ce dernier est composé d'un réseau informel de dizaines de machines un peu partout dans le monde et qui annoncent toutes être 192.175.48.6 et 192.175.48.42 (pour l'ancien préfixe) et 192.31.196.1 (pour le nouveau). Chacune de ces machines encaisse une partie de la charge. L'AS112 n'a pas de chef, juste un site Web et un RFC, ce RFC 7534.

L'AS112 doit son nom au numéro de système autonome qui lui a été attribué (et qui est désormais dans le registre des AS spéciaux, créé par le RFC 7249). Ses serveurs utilisent l'anycast (RFC 4786) pour distribuer la charge entre eux. Avant Global Anycast, c'était donc le premier projet d'anycast entre serveurs faiblement coordonnés. Une histoire complète de l'AS112 figure en annexe A de notre RFC.

Les détails pratiques, maintenant. La liste des zones servies par l'ancien AS112 (Direct Delegation) figure en section 3.2. (Le nouvel AS112 suit un système de délégation dynamique décrit dans le RFC 7535.) Elle comprend 10.in-addr.arpa pour le réseau 10.0.0.0/8, de 16.172.in-addr.arpa à 31.172.in-addr.arpa pour le 172.16.0.0/12, et 168.192.in-addr.arpa pour le 192.168.0.0/16, les préfixes du RFC 1918. Elle inclus aussi 254.169.in-addr.arpa pour le préfixe « local au lien » du RFC 5735. Pour aider à l'identification du nœud qui répond, les serveurs de l'AS112 servent également la zone hostname.as112.net, ici à Paris :


% dig +nsid TXT hostname.as112.net

; <<>> DiG 9.7.3 <<>> +nsid TXT hostname.as112.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1078
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 2, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hostname.as112.net.            IN      TXT

;; ANSWER SECTION:
hostname.as112.net.     267     IN      TXT     "Unicast IP: 193.17.192.194"
hostname.as112.net.     267     IN      TXT     "See http://as112.net/ for more information."
hostname.as112.net.     267     IN      TXT     "See http://noc.hivane.net/cgi-bin/dsc-grapher.pl for local information."
hostname.as112.net.     267     IN      TXT     "Paris, FR"
hostname.as112.net.     267     IN      TXT     "Hivane Networks"

;; AUTHORITY SECTION:
hostname.as112.net.     267     IN      NS      blackhole-2.iana.org.
hostname.as112.net.     267     IN      NS      blackhole-1.iana.org.

;; ADDITIONAL SECTION:
blackhole-1.iana.org.   241     IN      A       192.175.48.6
blackhole-2.iana.org.   241     IN      A       192.175.48.42

;; Query time: 1 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Wed Jul  6 12:36:14 2011
;; MSG SIZE  rcvd: 348

On note que les préfixes IPv6 n'y figurent pas. Pour le nouvel AS112, voici le même test :


% dig +nsid TXT hostname.as112.arpa

; <<>> DiG 9.9.2-P2 <<>> +nsid TXT hostname.as112.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22893
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;hostname.as112.arpa.   IN TXT

;; ANSWER SECTION:
hostname.as112.arpa.    604318 IN TXT "RIPE NCC" "Amsterdam, The Netherlands"
hostname.as112.arpa.    604318 IN TXT "See http://www.as112.net/ for more information."

;; AUTHORITY SECTION:
hostname.as112.arpa.    604317 IN NS blackhole.as112.arpa.

;; Query time: 16 msec
;; SERVER: 192.168.2.254#53(192.168.2.254)
;; WHEN: Fri May 15 10:34:06 2015
;; MSG SIZE  rcvd: 180

(On peut avoir une liste des serveurs, à jour, sur le site officiel).

La section 3.3 décrit les serveurs de noms qui reçoivent la délégation, joliment (mais incorrectement, puisqu'ils répondent) nommés blackhole-1.iana.org et blackhole-2.iana.org, et blackhole.as112.arpa pour le nouvel AS (en dépit de leurs noms, les serveurs de l'AS112 ne sont pas gérés par l'IANA, cf. section 7). Dans le champ MNAME du SOA de la zone déléguée, on trouve également (pour l'ancien AS112) prisoner.iana.org dont la tâche principale est de répondre aux mises à jour dynamiques (RFC 2136) que certaines machines envoient audit MNAME. Du temps du RFC 6304, ces serveurs n'étaient accessibles qu'en IPv4 mais ils ont désormais également des adresses IPv6.

Ce RFC 7534 n'est pas seulement la description d'une technique mais également un HOWTO sur la configuration d'un serveur de l'AS112. De tels textes, prévus pour les administrateurs système, sont rares dans les RFC. La section 4 décrit ainsi tout ce que doit savoir le volontaire qui va créer un nouveau nœud. Il doit connaître BGP (RFC 4271), nécessaire pour l'anycast (RFC 4786) et la gestion d'un serveur DNS faisant autorité. Les serveurs de l'AS112 peuvent être situés n'importe où mais ils sont surtout utiles dans les endroits bien connectés, notamment les points d'échange. Ils peuvent être locaux (annonçant les routes avec la communauté BGP no-export, 0xFFFFFF01, cf. RFC 1997), ou globaux (servant le monde entier). Et naturellement, ils doivent se coordonner (via une liste de diffusion) avec les autres serveurs de l'AS112.

L'AS112 n'impose pas de système d'exploitation particulier (section 4.3) mais tous les serveurs existants semblent utiliser Unix et un grand nombre (c'est difficile à dire, puisque l'AS112 ne contrôle pas tout ce qui se passe sur les serveurs) se servent de BIND. Il est recommandé que la machine AS112 soit dédiée à cette tâche : ces serveurs reçoivent parfois un trafic intense qui pourrait perturber leurs autres activités.

Le serveur signale son existence et sa disponibilité en BGP. Il faut donc coupler le serveur de noms au serveur BGP, pour que l'arrêt du serveur DNS entraîne l'arrêt de l'annonce (le RFC ne fournit pas de script pour cela). Un exemple de comment cela peut se réaliser sur Linux, avec les adresses de l'AS112 attachées à une interface dummy, est (code utilisé sur un serveur anycast réel, quoique pas de l'AS112) :

# Load the variables (the machine is a RedHat)
. /etc/sysconfig/network-scripts/ifcfg-eth0

# Test if the name server actually works. Do not use ps: the server
may be there but unresponsive
TMP=(`dig +short +time=1 +tries=1 @${IPADDR} SOA example.`)
MASTER=${TMP[0]:=somethingwaswrong}

# Normal reply or not?
if test ${MASTER} != "nsmaster.nic.example."
then
    # Disable the interface: Quagga will stop announcing the route
    ifdown dummy0
    # Raise an alarm, send SMS, etc
fi

Le serveur BGP annonce les préfixes de l'ancien AS112, 192.175.48.0/24 et 2620:4f:8000::/48, qui couvrent les adresses de tous les serveurs et l'origine est évidemment 112 (les préfixes IP sont dans le registre des préfixes spéciaux créé par le RFC 6890). Si le serveur gère la zone du nouvel AS112, il annonce en BGP 192.31.196.0/24 et 2001:4:112::/48.

Les exemples du RFC supposent que le serveur BGP est Quagga mais cela peut évidemment marcher avec d'autres. Dans l'exemple ci-dessous, tiré du RFC (section 4.4), le router ID est 203.0.113.1 et le serveur BGP a deux pairs, 192.0.2.1 et 192.0.2.2. Voici un extrait du bgpd.conf (la version intégrale est dans le RFC) :

   hostname my-router
...
   router bgp 112
    bgp router-id 203.0.113.1
    network 192.175.48.0/24
    neighbor 192.0.2.1 remote-as 64496
    neighbor 192.0.2.1 next-hop-self
    neighbor 192.0.2.2 remote-as 64497
    neighbor 192.0.2.2 next-hop-self

En farfouillant sur le site officiel (pas très bien organisé, je trouve), on peut trouver d'autres exemples.

Le serveur AS112 a ensuite besoin d'un serveur DNS faisant autorité (section 4.5), évidemment compatible avec toutes les règles du DNS (RFC 1034). Les exemples de configuration du RFC sont fondés sur BIND. Voici un extrait du named.conf (la version intégrale est dans le RFC) :

   options {
     listen-on {
        ...
        // the following addresses correspond to AS112 addresses, and
        // are the same for all AS112 nodes
        192.175.48.1;      // prisoner.iana.org (anycast)
        192.175.48.6;      // blackhole-1.iana.org (anycast)
        192.175.48.42;     // blackhole-2.iana.org (anycast)

	// The following address is used to support DNAME redirection
        // AS112 service and is the same for all AS112 nodes.
	192.31.196.1;      // blackhole.as112.arpa (anycast)
	};

      listen-on-v6 {
       ...
       // The following addresses are used to support Direct Delegation
       // AS112 service and are the same for all AS112 nodes.
       2620:4f:8000::1;   // prisoner.iana.org (anycast)
       2620:4f:8000::6;   // blackhole-1.iana.org (anycast)
       2620:4f:8000::42;  // blackhole-2.iana.org (anycast)

       // The following address is used to support DNAME redirection
       // AS112 service and is the same for all AS112 nodes.
       2001:4:112::1;    // blackhole.as112.arpa (anycast)
       };
       
     recursion no;        // authoritative-only server
   };

   // RFC 1918
   zone "10.in-addr.arpa" { type master; file "db.empty"; };
   ...

   // RFC 5735
   zone "254.169.in-addr.arpa" { type master; file "db.empty"; };

   // DNAME redirection AS112 Service
   zone "empty.as112.arpa" { type master; file "db.dr-empty"; };

   // also answer authoritatively for the HOSTNAME.AS112.NET zone,
   // which contains data of operational relevance
   zone "hostname.as112.net" {
     type master;
     file "db.hostname.as112.net";
   };

   zone "hostname.as112.arpa" {
     type master;
     file "db.hostname.as112.arpa";
   };
   

Un exemple équivalent pour NSD (utilisé sur le nœud AS112 de Paris) est disponible en as112-nsd.conf (ancien AS112 seulement). Pour simplifier son écriture, il a été produit à partir d'un source en M4, as112-nsd.conf.m4.

Que contiennent les fichiers de zone db.empty, db-fr.empty, db.hostname.as112.net et db.hostname.as112.arpa ? Conformes à la syntaxe de la section 5 du RFC 1035, ils sont communs à BIND et NSD. Les deux premiers, comme leur nom l'indique, sont des fichiers de zone vide, puisque le serveur AS112 ne connait évidemment rien : il ne peut que répondre NXDOMAIN (ce nom n'existe pas) à toutes les requêtes. Ils ne contiennent donc que les informations obligatoires à toute zone (SOA, avec une adresse de contact appropriée) et NS. Les deux autres zones servent au débogage de l'AS112, lorsqu'on veut obtenir des informations sur le serveur AS112 courant. Un contenu typique est juste composé d'enregistrements TXT :

           TXT     "Human AS112 server" "Minas Tirith, Gondor"
           TXT     "Forbidden to orcs and nazguls."
           TXT     "See http://www.as112.net/ for more information."

et parfois d'une localisation (cf. RFC 1876). Le résultat sur un site réel étant :


% dig ANY hostname.as112.net.

; <<>> DiG 9.7.3 <<>> ANY hostname.as112.net.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41528
;; flags: qr rd ra; QUERY: 1, ANSWER: 7, AUTHORITY: 2, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hostname.as112.net.            IN      ANY

;; ANSWER SECTION:
hostname.as112.net.     604796  IN      LOC     37 58 22.590 N 23 44 43.890 E 100.00m 100m 10m 10m
hostname.as112.net.     604796  IN      TXT     "See http://as112.net/ for more information."
hostname.as112.net.     604796  IN      TXT     "Unicast IP: as112.grnet.gr"
hostname.as112.net.     604796  IN      TXT     "Greek Research & Technology Network" "Athens, Greece"
hostname.as112.net.     604796  IN      SOA     flo.gigafed.net. dns.ryouko.imsb.nrc.ca. 1 604800 60 604800 604800
hostname.as112.net.     604796  IN      NS      blackhole-2.iana.org.
hostname.as112.net.     604796  IN      NS      blackhole-1.iana.org.

;; AUTHORITY SECTION:
hostname.as112.net.     604796  IN      NS      blackhole-1.iana.org.
hostname.as112.net.     604796  IN      NS      blackhole-2.iana.org.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Jul  6 12:51:53 2011
;; MSG SIZE  rcvd: 391

(La version intégrale des quatre fichiers de zone figure dans le RFC.)

Une fois le nœud installé, il faut évidemment le tester (avec dig, par exemple). Si les réponses aux requêtes PTR sont correctes, mais pas celles aux requêtes pour le nom hostname.as112.{net,arpa}, c'est sans doute un problème de routage (on est envoyés sur un autre nœud de l'AS112) et il faut alors sortir traceroute et les looking glasses (section 4.6). Des tests dignes de ce nom doivent être faits depuis plusieurs FAI, et doivent tester les trois (ou quatre pour les nouveaux nœuds) adresses IPv4 de l'AS112, plus ses adresses IPv6.

Le bon fonctionnement de l'AS112 ne dépend pas uniquement de sa configuration initiale mais aussi de sa gestion et surveillance quotidiennes. La section 5 est consacrée aux questions opérationnelles. Le nœud doit être surveillé automatiquement, pour s'assurer qu'il répond toujours. S'il doit être arrêté (par exemple pour une maintenance prévue), il faut s'assurer que l'annonce BGP stoppe (autrement, BGP annonce un trou noir, d'où aucune réponse ne reviendra). Autre point important de la gestion opérationnelle d'un serveur de l'AS112, des statistiques, obtenues à partir d'outils comme DSC ou dnstop. Quelle est l'utilisation réelle de l'AS112 ? Ces statistiques n'étant pas consolidées globalement, c'est difficile à dire. Certains opérateurs publient leurs chiffres mais pas tous. Par exemple, le serveur d'Ottawa voit mille requêtes par seconde (cf. « AS112 Intro » par l'un des auteurs du RFC), celui géré par le RIPE-NCC dans les mille cinq cents, et celui à Paris deux fois plus (voir les graphiques), ce qui fait quand même quelques mégabits par seconde. La majorité des types demandés est évidemment du PTR mais il y a aussi un flux important de TXT, apparemment dus à la technologie SD (Service Discovery) d'Apple (voir des statistiques plus détaillées à la fin).

Le nouveau serveur peut alors être annoncé sur les listes appropriées (par exemple, chaque point d'échange a en général la sienne). Enfin, bien que chaque serveur de l'AS112 puisse fonctionner indépendemment des autres, il est évidemment préférable de se coordonner avec les petits camarades (section 6) en écrivant à la liste officielle.

Et dans le futur ? La section 7 explore l'avenir possible de l'AS112. Idéalement, il devrait disparaître petit à petit au fur et à mesure que les administrateurs réseaux prennent soin de ne pas laisser fuir les requêtes PTR pour les réseaux privés, comme recommandé dans le RFC 6303. Le déploiement de logiciels respectant ce principe dès le début pourrait aider. Toutefois, aujourd'hui, les opérateurs de l'AS112 n'observent pas de tendance à la baisse du trafic. Même des années après le déploiement de serveurs mettant en œuvre le RFC 6303, il est probable que le trafic de l'AS112 ne tombera pas à zéro et que ce service restera donc nécessaire.

Enfin, qu'en est-il de la sécurité ? Comme le rappelle la section 9, les requêtes DNS auxquelles répond l'AS112 ne devraient jamais y arriver, normalement. Elles auraient dû rester sur le réseau local. En sortant, elles exposent de l'information interne, qui était peut-être privée (qu'il y ait un serveur AS112 qui y réponde ou pas ne change guère ce risque).

Plus rigolo, comme ces requêtes sont en général involontaires (comme indiqué, elles auraient dû rester privées), les réponses sont inattendues. Plus d'un IDS a donc crié que l'AS112 essayait d'attaquer le réseau. Le RFC 6305 a été écrit pour fournir une réponse toute faite aux administrateurs incompétents qui accusaient l'IANA ou l'AS112.

Comme l'AS112 n'a pas de chef et que l'anycast ne permet pas de limiter le nombre de participants, il est tout à fait possible de fantasmer sur l'hypothèse d'un nœud AS112 voyou, qui donnerait exprès de mauvaise réponses. Ce problème (purement théorique) n'a pas vraiment de solution. Signer les zones avec DNSSEC semble franchement excessif, et difficile à réaliser de manière sûre puisqu'il faudrait distribuer la clé privée à tous les opérateurs de l'AS112.

L'annexe A du RFC expose la longue histoire de l'AS112, de ses débuts en 2002 (les adresses IP privées datent de 1996) à son état actuel, après la redélégation en 2011 de in-addr.arpa, autrefois sur les serveurs de la racine (RFC 5855). L'AS112 a été le premier déploiement massif de l'anycast et a donc joué un rôle primordial dans l'évaluation de cette technologie.

À noter que, d'après la liste officielle des sites, il existe au moins un serveur AS112 en France, chez Hivane, désormais (novembre 2011) connecté au France-IX. Malgré cela, les requêtes françaises pour les serveurs de l'AS112 voyagent souvent loin. C'est un problème banal comme le montrait l'excellente présentation « Investigating AS112 Routing and New Server Discovery ».

Voici quelques analyses sur le trafic de ce serveur français, faites avec DNSmezzo. Le fichier pcap fait 6,8 Go. Il y a 43 701 087 paquets DNS dont 21 858 845 sont des requêtes. Les données ont été prises un vendredi, de 13h40 à 15h30 (heure locale). Regardons d'abord les types de données demandés :

dnsmezzo=> SELECT (CASE WHEN type IS NULL THEN qtype::TEXT ELSE type END),
       meaning,                                                           
       count(results.id)*100/(SELECT count(id) FROM DNS_packets WHERE query) AS requests_percent FROM
             (SELECT id, qtype FROM dns_packets
                 WHERE query)  AS Results
          LEFT OUTER JOIN DNS_types ON qtype = value
              GROUP BY qtype, type, meaning ORDER BY requests_percent desc;


 type  |                meaning                 | requests_percent 
-------+----------------------------------------+------------------
 PTR   | a domain name pointer                  |               57
 TXT   | text strings                           |               35
 SOA   | marks the start of a zone of authority |                6
 CNAME | the canonical name for an alias        |                0
 MX    | mail exchange                          |                0
 AAAA  | IP6 Address                            |                0
 40    |                                        |                0
 DS    | Delegation Signer                      |                0
 ...

La première place des PTR est normale. Celle des TXT est plus surprenante. En regardant les noms utilisés (cf._dns-sd._udp.Y.X.243.10.in-addr.arpa...), on voit qu'ils sont dus à la technique Service Discovery d'Apple, un système normalement confiné au réseau local mais qui bave beaucoup à l'extérieur.

Et quels sont les domaines les plus populaires ?

dnsmezzo=> SELECT substr(registered_domain,1,46) AS domain, 
          count(id)*100/(SELECT count(id) FROM DNS_packets WHERE query) AS requests_percent  
       FROM dns_packets WHERE query GROUP BY registered_domain ORDER BY requests_percent DESC LIMIT 30;
      domain      | requests_percent 
------------------+------------------
 10.in-addr.arpa  |               78
 192.in-addr.arpa |               12
 172.in-addr.arpa |                7
 169.in-addr.arpa |                1
 151.in-addr.arpa |                0
 i~-addr.arpa     |                0
 83.in-addr.arpa  |                0
                  |                0
 gfi.private      |                0
 local.de         |                0
 grupofdez.com    |                0
....

On voit que le réseau 10.0.0.0/8 est nettement le plus populaire. On notera les trois derniers, sans doute des erreurs de configuration.

Et quels sont les résolveurs les plus actifs ? En agrégeant les préfixes IPv4 en /28 :

dnsmezzo=>  SELECT set_masklen(src_address::cidr, 28) AS client, count(id)*100/(SELECT count(id) FROM DNS_packets WHERE query) AS requests_percent                                                                  
     FROM dns_packets WHERE query GROUP BY set_masklen(src_address::cidr, 28)
           ORDER by requests_percent DESC LIMIT 30;
       client       | requests_percent 
--------------------+------------------
 CENSURE.160/28     |               29
 CENSURE.0/28       |               10
 CENSURE.16/28      |                8
 CENSURE.96/28      |                6
...

Oui, j'ai préféré ne pas donner les adresses. Je dirai simplement que ces quatre plus gros sont des opérateurs de téléphonie mobile, deux français et deux extrême-orientaux (les mystères du routage...).

Merci à Clément Cavadore, administrateur du plus gros (en nombre de requêtes) serveur AS112 du monde, pour les données et pour sa relecture.

Les principaux changements depuis le RFC 6304 :

  • Adresses IPv6 pour les serveurs de l'AS112,
  • « Nouvel AS112 », servant la zone empty.as112.arpa, vers laquelle les zones à gérer seront redirigées par un DNAME,
  • Enregistrement des préfixes à l'IANA.

Téléchargez le RFC 7534


L'article seul

RFC 7530: Network File System (NFS) Version 4 Protocol

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : T. Haynes (Primary Data), D. Noveck (Dell)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF nfsv4
Première rédaction de cet article le 7 avril 2015


Le protocole d'accès aux fichiers NFS est très ancien. Sa version 2 est décrite dans le RFC 1094, sa version 3 dans le RFC 1813 et la version 4 faisait l'objet du RFC 3530, qui vient d'être remplacé par ce nouveau RFC. Rien de spectaculaire, juste des clarifications. Notez que, malgré son ancienneté, NFSv3 reste encore très utilisé.

NFS est un gros protocole compliqué (ce RFC fait 300 pages tout rond, et la section 1.1 affirme sans rire qu'une des caractéristiques de NFS est sa simplicité) et n'est pas ma spécialité donc je vais passer rapidement et me contenter des grandes lignes du protocole. NFS permet donc l'accès distant à des fichiers. Les versions anciennes utilisaient au moins deux protocoles distincts, NFS lui-même et « mount » mais NFSv4 n'en a plus qu'un. De même, les éventuels protocoles supplémentaires pour avoir des fonctions de verrouillage des fichiers ont disparu, tout étant désormais intégré dans NFS. Autres caractéristiques importantes de la version 4 (qui fêtera ses quinze ans à la fin de l'année), une meilleure prise en compte de la sécurité (avec négociation de la sécurité), de l'internationalisation, des possibilités de cache chez le client, et un meilleur fonctionnement au dessus de l'Internet (les versions précédentes marchaient surtout en réseau local). NFSv4 essaie aussi d'être plus agnostique par rapport au système d'exploitation sous-jacent, les précédentes versions étant très orientées Unix.

À noter que les RFC sur les versions 2 et 3 de NFS étaient de simples documentations d'un protocole développé de manière fermée par Sun, alors que NFSv4 est entièrement développé à l'IETF.

NFS repose sur la représentation XDR, RFC 7531 et sur le mécanisme RPC (RFC 4506 et RFC 5531, étendu, pour la sécurité, par le RFC 5403).

NFS est un service d'accès aux fichiers : son modèle est celui d'un système de fichiers hiérarchique (avec des répertoires qui peuvent contenir des fichiers et d'autres répertoires). Les noms des fichiers et répertoires sont forcément en UTF-8, pour l'internationalisation. Le contenu des fichiers n'est pas interprété par NFS, c'est juste une suite d'octets. Quand un client NFS ouvre un fichier, il reçoit un filehandle, un identificateur qu'il utilisera dans les requêtes d'entrée/sortie suivantes. Avec les précédentes versions de NFS, on obtenait ce filehandle via le protocole « mount » mais ce protocole a désormais disparu (entre autres en raison de sa faible sécurité, et car il ne permettait pas facilement de passer les pare-feux). Désormais (idée qui remonte aux RFC 2054 et RFC 2055), les filehandles s'obtiennent directement avec le protocole NFS. Les filehandles peuvent être permanents ou temporaires (une nouveauté de NFSv4). Chaque fichier peut avoir toute une collection d'attributs, comme le type du fichier (fichier ordinaire ou répertoire) ou comme des ACL.

Autre changement par rapport à NFSv3, les opérations d'ouverture et de fermeture du fichier sont désormais explicites. La fermeture permet au serveur de libérer tout état associé au fichier, ce qui était impossible dans les vieilles versions de NFS.

Autre propriété importante de NFSv4 : le serveur peut déléguer à un client certaines responsabilités. Si un client a une délégation de lecture, il est sûr qu'aucun autre client ne pourra écrire dans le fichier pendant ce temps. S'il a une délégation d'écriture, personne n'aura aucun accès au fichier tant que la délégation durera.

NFSv2 et NFSv3 utilisaient un port fixe, 2049 (tout en dépendant de portmap pour des raisons que je n'ai jamais comprises). NFSv4 permet d'utiliser plusieurs transports, comme TCP ou SCTP, et n'est pas forcément sur le port 2049.

La section 1.5 de notre RFC résume les changements qu'a connus NFSv4 depuis le RFC 3530. Le protocole est le même, ce sont surtout des différences de rédaction comme :

  • XDR a été déplacé vers un RFC distinct, le RFC 7531.
  • Les références à des noms de domaine, par exemple pour les noms de propriétaires des fichiers, suivent désormais la nouvelle norme IDN, le RFC 5891.

Il existe aujourd'hui des mises en œuvre de NFS pour tous les systèmes. Certaines font au choix du NFSv3 ou du NFSv4, certaines sont encore purement NFSv3.


Téléchargez le RFC 7530


L'article seul

RFC 7526: Deprecating Anycast Prefix for 6to4 Relay Routers

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : O. Troan (Cisco), B. Carpenter (Univ. of Auckland)
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 4 juin 2015


6to4 en anycast, c'est fini ! Cette technique de transition entre IPv4 et IPv6, reposant sur des tunnels établis automatiquement, a pu être utile à un moment pour faciliter l'accès à IPv6 depuis les opérateurs qui étaient en retard pour le déploiement. Mais elle a plein de défauts techniques, qui ont contribué à donner une mauvaise image d'IPv6. Elle est donc marquée par ce RFC comme officiellement abandonnée.

C'est dans le RFC 3068 que 6to4+anycast était normalisé (il existe plein d'autres techniques de transition). Le principe était d'avoir des relais anycast qui recevaient les paquets IPv6 encapsulés dans de l'IPv4, tunnelant ainsi le trafic IPv6 au-dessus d'opérateurs restés en IPv4. Pour éviter d'avoir à configurer manuellement ces relais, une correspondance existait entre les adresses IPv4 des machines, et des adresses IPv6 attribuées dans un préfixe spécifique à 6to4, le 2002::/16 (le réseau IPv6 associé à une adresse IPv4 était 2002:adresse-IPv4::/48). Des outils comme whois connaissaient ce préfixe et savaient donc faire une recherche « intelligente » (ici, d9ae:c921 = 217.174.201.33) :

% whois 2002:d9ae:c921::1

Querying for the IPv4 endpoint 217.174.201.33 of a 6to4 IPv6 address.
...
[affichage des informations au sujet de 217.174.201.33]

Un autre préfixe, en IPv4, était attribué aux relais, pour que les mécanismes de l'anycast trouvent ensuite le relais le plus proche. C'est ce second préfixe, 192.88.99.0/24, qui est retiré du service par ce RFC. En outre, le RFC 3068 est désormais marqué comme « intérêt historique seulement ».

La première version de ces tunnels automatiques, spécifiée dans le RFC 3056, utilisait un adressage unicast. C'est avec le RFC 3068 que 6to4 est passé à l'anycast. Les relais étaient gérés par des tas de volontaires situés sur la planète mais, en pratique, beaucoup marchaient mal ou pas du tout et l'anycast ne permettait pas de garantir qu'on tombe sur un relais valide, encore moins sur un relais proche et rapide. L'étude « Flailing IPv6 » a montré la quantité de problèmes que posait 6to4. Un test avec les sondes RIPE Atlas montre 23 % de timeout sur un serveur 6to4, 2002:d9ae:c921::1, contre 10 % pour une adresse IPv6 native. En test DNS, 343 sondes Atlas sur 470 répondent pour l'adresse 2002:d9ae:c921::1, contre 490 sur 500 pour l'adresse IPv4 du même serveur, 217.174.201.33.

Un résultat tragique de cette mauvaise qualité a été de ralentir le déploiement d'IPv6, bien des utilisateurs coupant IPv6 lorsqu'ils découvraient la lenteur et les pannes de 6to4, bien des gérants de serveurs ne fournissant pas IPv6 de peur que cela entraine une dégradation de la qualité de service.

Le RFC 6343 analysait le problème et faisait des recommandations pour améliorer 6to4. Il recommandait que 6to4 soit coupé par défaut (un scénario commun, avant, était que 6to4 était activé sans demande explicite, le trafic IPv6 passait par un relais lointain, et l'utilisateur en concluait qu'IPv6 était lent) : « it should always be a conscious decision by a user to enable 6to4 ». Le RFC 6343 recommandait aussi de suivre l'algorithme des « globes oculaires heureux » du RFC 6555, afin de masquer les défaillances éventuelles d'une des familles, IPv4 ou IPv6.

Mais ces conseils, quoique assez largement mis en œuvre, ne suffisent pas, et les serveurs accessibles en IPv6 voient toujours du trafic 6to4.

À noter que la technologie 6rd, normalisée dans le RFC 5969, est très proche de 6to4 mais s'en distingue par l'utilisation d'un préfixe IPv6 lié au fournisseur d'accès. Les relais, au lieu d'être gérés un peu partout par des volontaires inconnus, sont donc forcément sous la houlette du FAI qui utilise 6rd, et il peut donc garantir une voie de retour. 6rd n'est donc pas concerné par les critiques de notre RFC.

La section 3 revient en détail sur les problèmes rencontrés avec 6to4. Elle rappelle que les routes peuvent être asymétriques (un relais différent à l'aller et au retour). Si le choix du relais aller peut être contrôlé (par exemple par des préférences BGP pour telle ou telle annonce du préfixe 192.88.99.0/24), le chemin de retour échappe complètement au nœud 6to4, qui ne peut pas être sûr que ses pairs utiliseront un « bon » relais. C'est le cœur du problème de 6to4. (Notez bien que cela ne concerne que le mode anycast, avec le prefixe standard. Des variantes de 6to4, avec un préfixe contrôlé par le FAI, ou avec de l'unicast vers des relais connus, ne sont pas concernées par ce RFC. C'est par exemple le cas de 6rd, cité plus haut)

La section 4 du RFC contient les décisions formellement prises :

  • Le mécanisme d'anycast de 6to4 du RFC 3068 est abandonné,
  • Le préfixe 192.88.99.0/24 est marqué comme abandonné (dans le registre IANA),
  • Le 6to4 en unicast du RFC 3056 reste utilisable, tout comme le préfixe 2002::/16, c'est uniquement son annonce en anycast qui est abandonnée,
  • Les règles de sélection de l'adresse source du RFC 6724 ne sont pas modifiées (elles donnent la priorité à IPv4 sur 6to4, contrairement aux règles de son prédécesseur, le RFC 3484).

Comme indiqué dans la section 5, il est déconseillé d'inclure 6to4+anycast dans les mises en œuvre d'IPv6 et, si on le fait, il faut qu'il soit désactivé par défaut. (Bien des CPE IPv6 avaient imprudemment activé ce mécanisme par défaut, pour fournir une connectivité IPv6 dans tous les cas, même au-dessus d'un opérateur resté uniquement à IPv4.)

En revanche, contrairement à ce qui avait parfois été proposé, notre RFC ne formule pas de recommandations sur le filtrage des annonces de route 6to4 (un tel filtrage bloquerait 6to4 chez l'opérateur qui le ferait). Il conseille par contre aux actuels opérateurs de relais 6to4 de se poser sérieusement la question « est-ce que c'est vraiment la peine de continuer ? » Ces recommandations (ou absence de recommandations) avaient fait l'objet des plus vigoureuses discussions au sein du groupe de travail à l'IETF.


Téléchargez le RFC 7526


L'article seul

RFC 7525: Recommendations for Secure Use of TLS and DTLS

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : Y. Sheffer (Intuit), R. Holz (TUM), P. Saint-Andre (&yet)
Première rédaction de cet article le 6 mai 2015


Le protocole de sécurité TLS sécurise aujourd'hui, par la cryptographie, un grand nombre de communications par l'Internet. Le protocole et ses mises en œuvre dans des bibliothèques comme OpenSSL ont eu plusieurs failles, réparées au fur et à mesure. Mais les plus grosses failles restent dans l'utilisation pratique de TLS : programmeurs et administrateurs systèmes font des erreurs qui affaiblissent la sécurité de TLS. Ce RFC, le deuxième du groupe UTA (utilisation de TLS par les applications) résume les bonnes pratiques qui devraient être suivies en matière de sécurité pour que TLS atteigne complètement ses objectifs. (Il a depuis été remplacé par le RFC 9325.)

TLS est normalisé dans le RFC 5246. Ce RFC documente la version 1.2 et la 1.3 est en cours de normalisation. Il est surtout connu pour sa sécurisation de HTTP, nommée HTTPS. Mais il sert aussi pour sécuriser SMTP, XMPP, IMAP, etc. TLS lui-même ne marche que sur TCP mais il a un équivalent pour UDP, nommé DTLS, et normalisé dans le RFC 6347. Si un attaquant veut casser la protection qu'offre TLS (par exemple pour accéder au contenu en clair d'une communication normalement chiffrée), il peut viser (le RFC 7457 donne une bonne liste)  :

  • Le protocole lui-même. Ainsi, SSL v3, un précurseur de TLS, avait une faille de conception qui permettait l'attaque Poodle. Les failles du protocole, par définition, sont indépendantes d'une mise en œuvre particulière de TLS.
  • Les algorithmes cryptographiques utilisés. TLS a la propriété d'« agilité cryptographique » qui fait qu'il n'est pas lié à un algorithme particulier mais offre un choix. Cela permet, au fur et à mesure des progrès de la cryptanalyse, de changer d'algorithme. Par exemple, les algorithmes AES-CBC (RFC 3602) et RC4 (RFC 7465) ont tous les deux montré des faiblesses sérieuses, ce qui fait que leur utilisation dans TLS est découragée. La liste des algorithmes possibles dépend de la bibliothèque TLS utilisée mais aussi de la configuration du client et du serveur TLS. Pour retirer un algorithme désormais trop faible, comme RC4, on peut donc agir dans le logiciel (en retirant le code correspondant) ou dans la configuration, en supprimant l'algorithme de la liste acceptée.
  • TLS est mis en œuvre dans des bibliothèques logicielles qui, comme tous les logiciels, ont des bogues. Cette fois-ci la faille est spécifique à une mise en œuvre donnée et la correction est de mettre à jour le logiciel, une fois la version corrigée sortie. Ce fut le cas pour la faille Heartbleed, spécifique à OpenSSL, ou de la faille goto fail, spécifique à Apple.
  • Même si le protocole est parfait, n'utilisant que des algorithmes cryptographiques incassés, et programmé sans une bogue, des failles de sécurité peuvent quand même surgir si TLS est utilisé imprudemment. Par exemple, si une application utilise TLS en ayant débrayé (ou pas activé) la vérification du certificat, TLS peut être contourné via une attaque de l'Homme du Milieu. L'article « The most dangerous code in the world: validating SSL certificates in non-browser software » en donne plusieurs exemples.

Bref, l'analyse de sécurité de TLS est complexe et on voit pourquoi il faut se méfier comme de la peste des résumés journalistiques qui annoncent une faille TLS alors qu'il ne s'agissait que d'une bogue dans une bibliothèque.

Le RFC 7457 décrivait déjà les failles, avec plein d'exemples. Notre nouveau RFC se concentre sur les recommandations. Il définit un plancher de sécurité (pas un plafond : on peut toujours être plus strict que ce que définit le RFC). D'autre part, le RFC prévient évidemment que ces recommandations évolueront avec le temps.

Le cœur de notre RFC n'est donc pas l'analyse des risques, mais les recommandations pratiques (sections 3 et suivantes). D'abord, sur la version du protocole :

  • Ne jamais utiliser SSL, que ce soit la v2 (RFC 6176) ou la v3. Décrite dans le RFC 6101, cette dernière a encore bien trop de trous (comme celui qui permet POODLE) et ne gère pas des extensions essentielles à la sécurité comme celle du RFC 5746.
  • N'utiliser TLS 1.0 (RFC 2246) que si on n'a pas le choix. Publié il y a seize ans (!), il n'accepte pas certains algorithmes de cryptographie moderne et il a d'autres faiblesses.
  • TLS 1.2 doit être privilégié. Notons que les algorithmes cryptographiques recommandés dans notre RFC ne sont disponibles qu'avec cette version 1.2.

Si un client TLS a un mécanisme de repli (on tente de se connecter avec la version N, ça échoue, on ré-essaie avec N-1, ce qui se nomme la downgrade dance), on ne doit jamais se replier vers SSL. Autrement, un Homme du Milieu aurait juste à faire échouer la connexion initiale, pour garantir l'utilisation d'un protocole faible (notez que le RFC 7507 fournit une solution contre ce repli). Aux dernières nouvelles, seuls 3 % des serveurs Web TLS/SSL de l'Internet étaient SSL-seulement.

Lorsque client et serveur essaient de se connecter avec TLS mais acceptent des connexions sans TLS, des attaques actives peuvent forcer un repli vers la connexion sans TLS, en clair et pas sécurisée du tout (la négociation de TLS n'est pas elle-même protégée par TLS). Pour éviter cela, client et serveur devraient insister sur l'utilisation de TLS et utiliser des techniques comme HSTS (RFC 6797) pour signaler qu'on sait faire du TLS et qu'il ne faut pas essayer en clair.

Plusieurs attaques sont facilitées par l'utilisation de la compression (RFC 5246, section 6.2.2), comme CRIME. Il est recommandé de la couper, sauf si on est sûr que le protocole applicatif qui utilise TLS n'est pas vulnérable à ces attaques.

L'établissement d'une session TLS nécessite d'échanger plusieurs paquets, ce qui prend du temps. Pour limiter ce problème, TLS dispose d'un mécanisme de reprise de session (RFC 5246). Ce mécanisme doit être autant protégé que le serait une session normale. Par exemple, dans le cas du RFC 5077, si on chiffrait le ticket utilisé pour la reprise de session avec un algorithme bien plus faible que celui utilisé dans la session elle-même, un attaquant pourrait choisir de tenter une « reprise » d'une session inexistante, court-circuitant ainsi l'authentification. À noter aussi que ce mécanisme de reprise de session peut annuler l'effet de la forward secrecy : si l'attaquant met la main sur les tickets, il peut déchiffrer les sessions qu'il a enregistré (cf. section 3.4 de notre RFC). Il faut donc changer les clés des tickets de temps en temps.

L'extension de renégociation sécurisée du RFC 5746 doit être disponible (ou, sinon, il faut couper la renégociation).

Une dernière recommandation générale porte sur SNI (RFC 6066, section 3). Bien que cela n'affecte pas directement la sécurité, cette extension est recommandée, pour des protocoles comme HTTPS, car elle permet des politiques de sécurité plus souples et donc plus implémentables (comme d'avoir un certificat par site Web).

La section 3 de notre RFC portait sur des recommandations générales. La section 4 s'attaque aux algorithmes de cryptographie (cipher suites). Ceux-ci s'usent avec le temps, quand les progrès de la cryptanalyse exposent leurs failles. Cette usure se fait à un rythme très variable : certains algorithmes durent depuis longtemps, d'autres ont été éliminés rapidement. Mais aucun algorithme n'est éternel et voilà pourquoi il est nécessaire de séparer le protocole des algorithmes, ce qu'on nomme l'« agilité cryptographique ». Notre RFC recommande donc de ne pas utiliser l'algorithme NULL, qui ne chiffre pas du tout (pas besoin de cryptanalyse pour le casser...) et n'a d'intérêt que pour les tests et le débogage. Plus récemment, les progrès de la cryptanalyse, documentés dans le RFC 7465, ont montré que RC4 ne devait pas être utilisé non plus. Le problème des algorithmes trop faibles est aggravé par l'action des États qui veulent pouvoir espionner les communications et qui imposent, dans certains cas, l'utilisation d'algorithmes dont les faiblesses sont connues. C'est le cas aux États-Unis des algorithmes dit export (car ils étaient les seuls légalement exportables à une époque). Si ces algorithmes sont présents, l'attaque FREAK permettra à un attaquant actif de les sélectionner, flanquant en l'air toute la sécurité de TLS.

Les révélations de Snowden ont montré que la NSA (et peut-être d'autres organisations) enregistre de nombreuses communications chiffrées qu'elle ne sait pas décrypter. L'idée est que si, un jour, on met la main sur la clé privée (par perquisition physique, piratage de l'ordinateur à distance ou tout autre méthode), on pourra alors déchiffrer et certaines de ces communications seront encore intéressantes. Pour éviter cela, notre RFC conseille de privilégier les algorithmes qui mettent en œuvre la forward secrecy comme la famille DHE.

Quels algorithmes restent-ils après ces nombreuses éliminations ? Notre RFC en mentionne quatre (après une discussion longue et acharnée à l'IETF) : TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 et TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384. Ils utilisent DHE ou ECDHE, avec RSA, AES en mode GCM (voir RFC 5288 section 6, sur la sécurité de ce mode) et SHA-2. Ils font tous du chiffrement intègre (authenticated encryption, RFC 5116). Tout logiciel TLS devrait être configuré pour préferer ces algorithmes (cf. « Applied Crypto Hardening »).

Attention, notre RFC parle uniquement de préférer ces algorithmes, pas de les imposer. Pour permettre l'interopérabilité, TLS a en effet des algorithmes obligatoires, qui doivent être mis en œuvre dans chaque bibliothèque TLS. C'est le cas de TLS_RSA_WITH_AES_128_CBC_SHA, obligatoire mais pas le plus fort, loin de là. Mais on peut compter sur lui puisqu'il est obligatoire, contrairement aux quatre algorithmes cités plus haut, qui peuvent ne pas être présents. Il peut donc être nécessaire d'arbitrer entre interopérabilité et sécurité...

Ce RFC a également des recommandations sur les clés publiques utilisées dans les certificats : 2 048 bits au moins en RSA (ce qui est imposé par la plupart des AC depuis un certain temps, c'est le cas de CAcert, par exemple), et SHA-256 pour condenser la clé (et plus SHA-1).

Un petit mot en passant sur un point abordé dans la section 5. Celle-ci concerne l'« applicabilité » des recommandations faites ici. Cette applicabilité est très large, quasiment tous les usages de TLS sont concernés. Il existe un usage fréquent de TLS, parfois appelé « chiffrement opportuniste » (RFC 7435) où une des parties qui communiquent va essayer de faire du TLS mais, si cela ne marche pas (par exemple parce que l'autre partie ne gère pas le chiffrement), on se rabat sur une communication en clair. Dans ce contexte, certaines des recommandations du RFC peuvent être trop strictes. Par exemple, on a vu qu'il ne fallait pas utiliser RC4, trop faible cryptographiquement. Si on prend au pied de la lettre cette recommandation, qu'une des deux parties ne connait que RC4 et qu'on est dans un contexte de chiffrement opportuniste, on pourrait arriver à ce résultat paradoxal que, RC4 étant refusé, on communique en clair, ce qui est certainement bien pire que le plus mauvais des algorithmes de cryptographie. Il peut donc être nécessaire de dévier des recommandations de notre RFC 7525.

Enfin, pour terminer ce RFC déjà riche, une section 6 consacrée à divers problèmes de sécurité qui n'avaient pas été traités avant. D'abord, la nécessité, lorsqu'on vérifie un certificat, de vérifier également que le nom du serveur, dans le certificat, corespond au nom auquel on voulait se connecter. Cela parait évident mais ce n'est pas toujours fait par la bibliothèque qu'on utilise (cf. mon exposé à Devoxx - et ses transparents - pour des exemples.) Il peut donc être utile que l'application fasse la validation elle-même, sans quoi un attaquant actif peut détourner le trafic chiffré, de manière triviale. La section 3 du RFC 2818 et le RFC 6125 détaillent ce qu'il faut exactement valider. Bien sûr, pour que cette validation ait un sens, il faut que le nom du serveur ait lui-même été obtenu de manière sûre. Si on a cliqué sur un lien https://... dans un message de hameçonnage, vérifier que le nom est correct n'aide pas tellement (« oui, c'est bien secure-serious-bank.ab451e239f.ru »). Idem si le nom vient d'une requête DNS (par exemple de type MX) non sécurisée par DNSSEC.

J'ai déjà parlé plus haut de la forward secrecy, une propriété qui fait que le vol des clés privées a posteriori est inutile, même pour un attaquant qui avait enregistré les communications chiffrées. Dans la vie, ce vol peut arriver pour des tas de raisons, machines jetées à la poubelle sans les avoir effacées, et récupérées par un indiscret, clés trop faibles face à la force brute (cf. « Mining Your Ps and Qs: Detection of Widespread Weak Keys in Network Devices »), clé générée par un tiers (dans le « cloud ») et ensuite obtenue par piratage, attaque violente et/ou légale contre les administrateurs système pour obtenir la clé, et toutes les autres méthodes d'accès aux clés privées qui peuvent exister. La forward secrecy n'empêche pas ces attaques mais elle empêche l'attaquant d'exploiter son succès. Elle s'obtient en général en faisant un échange Diffie-Hellman. Dans le contexte de la sécurité de TLS, le principal problème est que beaucoup d'algorithmes utilisés ne permettent pas le forward secrecy, et que les autres, les bons, ne sont pas sélectionnés en priorité.

L'authentification du serveur TLS (on peut aussi authentifier le client mais c'est plus rare) repose presque toujours sur un certificat X.509. Si la clé privée associée au certificat est volée, le mécanisme de sécurité de X.509 est la révocation (RFC 5280, section 3.3). On sait que ce mécanisme nécessite une bonne connexion Internet, et est peu fiable : les listes de certificats révoqués, à distribuer partout, ne passent pas à l'échelle, le protocole OCSP (RFC 6960) est souvent bloqué (et il pose de toute façon des problèmes de passage à l'échelle et de vie privée), menant les clients à ignorer les échecs OCSP, etc. Il existe des solutions partielles (section 8 du RFC 6066, RFC 6961, RFC 6698) mais pas assez déployées.

Si vous voulez lire des recommandations en français sur la configuration de TLS, il y a deux guides ANSSI qui sont en rapport avec ce RFC, le RGS pour les algorithmes de cryptographie, et le guide pour la sécurité des sites Web, avec des recommandations précises pour OpenSSL (SSLCipherSuites Apache).

Et pour terminer sur une note personnelle, si vous regardez la configuration HTTPS de mon blog, elle est actuellement perturbée par deux sérieuses bogues du module GnuTLS d'Apache : #754960 et #642357.

Merci à Manuel Pégourié-Gonnard pour une relecture attentive qui a permis de trouver plusieurs erreurs. D'autres bonnes lectures :


Téléchargez le RFC 7525


L'article seul

RFC 7520: Examples of Protecting Content using JavaScript Object Signing and Encryption (JOSE)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Miller (Cisco Systems)
Pour information
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 20 mai 2015


Ce RFC fait partie de l'l'ensemble des normes sur le système JOSE (JavaScript Object Signing and Encryption, opérations cryptographiques sur les textes JSON). Il présente des exemples d'utilisation de JOSE, permettant aux développeurs de voir s'ils ont bien compris les normes présentées dans les RFC 7515 et RFC 7516.

Composé essentiellement de textes JSON et de binaire, ce RFC est long : 117 pages. Je n'en décris ici qu'une toute petite partie. Il vaux mieux lire avant les autres RFC sur JOSE pour comprendre les exemples. JOSE est très riche et il existe plein d'options. Il n'est donc pas possible, malgré l'épaisseur de ce RFC, de couvrir tous les cas. Le but est d'avoir au moins un échantillon représentatif des cas les plus courants. JOSE fonctionne en deux temps : calcul des résultats cryptographiques puis sérialisation, qui est la représentation sous forme texte, de ces résultats. JOSE a trois sérialisations possibles : compacte (le résultat est une série de caractères, pas un texte JSON), générale (le résultat est lui-même du JSON) et aplatie (également du JSON). Si vous voulez vérifier les exemples vous-même, ils sont tous disponibles sur GitHub.

Normalement, le contenu du RFC suffit à reproduire l'exemple exactement : en le donnant à une mise en œuvre de JOSE, on doit trouver le même résultat. La principale exception concerne le cas des algorithmes qui utilisent en entrée des données aléatoires (comme DSA). Dans ce cas, il n'est pas possible de retrouver exactement les mêmes valeurs. En outre, pour la présentation dans le RFC, des espaces ont parfois été ajoutés, là où il n'affectait pas la sémantique des opérations cryptographiques.

Commençons par les premiers exemples (section 3), la représentation de clés en JOSE (RFC 7517). D'abord, une clé publique, sur une courbe elliptique, la P-521 :

{
     "kty": "EC",
     "kid": "bilbo.baggins@hobbiton.example",
     "use": "sig",
     "crv": "P-521",
     "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
     "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
   }

Ici, x et y sont des paramètres spécifiques des courbes elliptiques, encodés en Base64 (JSON n'a pas de moyen plus pratique de stocker du binaire). Si c'était une clé privée, on aurait également un paramètre d. kid est l'identificateur de la clé. Plus banale que les courbes elliptiques, une clé publique RSA :

   {
     "kty": "RSA",
     "kid": "bilbo.baggins@hobbiton.example",
     "use": "sig",
     "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw",
     "e": "AQAB"
   }

Ici, n et e sont des paramètres spécifiques de RSA (le module et l'exposant). Une clé privée RSA nécessiterait davantage d'informations :

   {
     "kty": "RSA",
     "kid": "bilbo.baggins@hobbiton.example",
     "use": "sig",
     "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw",
     "e": "AQAB",
     "d": "bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ",
     "p": "3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k",
     "q": "uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc",
     "dp": "B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik",
     "dq": "CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8",
     "qi": "3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4"
   }

À noter que la seule indication qu'il s'agisse d'une clé privée est la présence des membres supplémentaires p, q, dp, dq et qi.

Passons maintenant à la cryptographie symétrique. Cette fois, il n'y a qu'une seule clé, stockée dans le membre k :

{
     "kty": "oct",
     "kid": "018c0ae5-4d9b-471b-bfd6-eef314bc7037",
     "use": "sig",
     "alg": "HS256",
     "k": "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg"
   }

Elle sera utilisée pour les signatures : on concatène la valeur de la clé au contenu et on SHA-256 le tout (non, en fait, c'est plus compliqué, voir RFC 2104). Le vérificateur fait la même opération et doit trouver le même condensat SHA-256.

Voici pour les clés. Passons aux signatures, en section 4. Un texte JSON signé est un JWS (JSON Web Signature). Le texte signé de tous les exemples est un extrait du Seigneur des anneaux, « It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to. ». Attention si vous recalculez les signatures vous-même, le caractère qui ressemble à une apostrophe est en fait le caractère Unicode U+2019, « RIGHT SINGLE QUOTATION MARK » (et, dans le RFC, il y a en plus remplacement de certains espaces par des sauts de ligne). Si vous voulez être sûr, l'encodage en Base64 (RFC 4648) de cette charge utile est SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4=.

Voici d'abord une bête signature RSA. L'en-tête protégé (cf. RFC 7515, sections 2 et 4) est :

{
     "alg": "RS256",
     "kid": "bilbo.baggins@hobbiton.example"
}

On signe la concaténation du Base64 de cet en-tête et du Base64 de la charge utile. Cela donne MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg. Il reste à sérialiser le résultat, c'est-à-dire à le présenter sous une forme concrète. Le RFC 7515 prévoit plusieurs sérialisations possibles. La compacte, utilisable dans les URL, serait eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg (vous reconnaissez la charge utile, la phrase de Tolkien, et la signature, séparées par des points). Avec la sérialisation aplatie, qui donne un texte JSON, ce serait :

{
     "payload": "SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4",
     "protected": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9",
     "signature": "MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg"
   }

C'est un peu compliqué avec une signature ECDSA. En effet, cet algorithme exige des données imprévisibles (le RFC dit « aléatoires » mais il exagère, cf. RFC 6979) et donc chaque signature donnera un résultat différent. Ne vous étonnez donc pas si vous recalculez et que vous trouvez une valeur différente de celle du RFC. Ici, on réutilise la clé présentée plus haut (sur la courbe P-521), et, en sérialisation générale (qui est très proche de la sérialisation aplatie, elle donne aussi un texte JSON, mais elle a un tableau de signatures et pas une signature unique, voir la section 4.8 pour des exemples) :

{
     "payload": "SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4",
     "signatures": [
       {
          "protected": "eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9",
          "signature": "AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2"
       }
     ]
   }

On peut aussi avoir des signatures « détachées », où le texte signé n'apparait pas. Le vérificateur devra récupérer le texte JSON signé, et récupérer la signature détachée, avant de vérifier. Ici, on utilise la clé symétrique montrée plus haut. L'en-tête sera donc :

{
     "alg": "HS256",
     "kid": "018c0ae5-4d9b-471b-bfd6-eef314bc7037"
   }

Et le résultat, en sérialisation aplatie :

{
     "protected": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9",
     "signature": "s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0"
}

Passons maintenant au chiffrement (section 5). Le texte utilisé pour les exemples change. Il est également tiré de « La communauté de l'anneau » et est « You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo. » Le tiret est un U+2013, « EN DASH ».

Premier exemple, avec RSA pour le chiffrement asymétrique de la clé (de la CEK, Content Encryption Key), AES (en mode CBC) pour le chiffrement symétrique, et SHA-256 lorsqu'il faut condenser. Voici la clé publique :

 {
     "kty": "RSA",
     "kid": "frodo.baggins@hobbiton.example",
     "use": "enc",
     "n": "maxhbsmBtdQ3CNrKvprUE6n9lYcregDMLYNeTAWcLj8NnPU9XIYegTHVHQjxKDSHP2l-F5jS7sppG1wgdAqZyhnWvXhYNvcM7RfgKxqNx_xAHx6f3yy7s-M9PSNCwPC2lh6UAkR4I00EhV9lrypM9Pi4lBUop9t5fS9W5UNwaAllhrd-osQGPjIeI1deHTwx-ZTHu3C60Pu_LJIl6hKn9wbwaUmA4cR5Bd2pgbaY7ASgsjCUbtYJaNIHSoHXprUdJZKUMAzV0WOKPfA6OPI4oypBadjvMZ4ZAj3BnXaSYsEZhaueTXvZB4eZOAjIyh2e_VOIKVMsnDrJYAVotGlvMQ",
     "e": "AQAB"
}

L'en-tête protégé est :

{
     "alg": "RSA1_5",
     "kid": "frodo.baggins@hobbiton.example",
     "enc": "A128CBC-HS256"
}

Et on se retrouve avec, en sérialisation générale :

{
     "recipients": [
       {
         "encrypted_key": "laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw"
       }
     ],
     "protected": "eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
     "iv": "bbd5sTkYwhAIqfHsx8DayA",
     "ciphertext": "0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m",
     "tag": "kvKuFBXHe5mQr4lqgobAUg"
}

Le contenu chiffré, et donc désormais confidentiel, est dans le membre ciphertext. Attention si vous essayez de reproduire cet exemple, le résultat exact dépend du vecteur d'initialisation iv. En sérialisation compacte, on aurait :

eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw.bbd5sTkYwhAIqfHsx8DayA.0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m.kvKuFBXHe5mQr4lqgobAUg

On peut aussi chiffrer et signer (section 6).

Attention, les exemples dans ce RFC sont juste... des exemples. Ils visent à permettre aux développeurs de comprendre la norme, et de tester leurs programmes (section 7). L'accent est donc mis, autant que possible, sur la reproductibilité et pas sur la sécurité. Ainsi, en violation des bonnes pratiques, tous les exemples utilisent la même clé symétrique de chiffrement (CEK, Content Encryption Key) et le même vecteur d'initialisation. Cette clé et ce vecteur doivent normalement changer à chaque opération de signature ou de chiffrement.

N'oubliez pas, si vous voulez reproduire les exemples de ce RFC, tous les résultats, sous un format lisible par vos programmes, sont dans un dépôt Github.


Téléchargez le RFC 7520


L'article seul

RFC 7518: JSON Web Algorithms (JWA)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 22 mai 2015


Ce nouveau RFC fait partie de la série des RFC JOSE (cryptographie pour JSON). Il normalise les algorithmes cryptographiques utilisables pour signer ou chiffrer des textes JSON et crée des registres IANA pour les conserver.

Comme le fait en général l'IETF en matière de cryptographie, les algorithmes cryptographiques ne sont pas inscrits « en dur » dans les RFC (rappelez-vous qu'un RFC, une fois publié, n'est jamais modifié) mais mis dans un registre IANA. En effet, la cryptanalyse progresse régulièrement et des algorithmes qui semblaient sûrs à un moment ne le sont plus par la suite. Il est plus facile et plus rapide de modifier un registre IANA que de créer un nouveau RFC.

Pour chaque registre, les algorithmes cités sont marqués Obligatoire, Recommandé ou Facultatif (cf. RFC 2119). En n'utilisant que des algorithmes marqués Obligatoire, on augmente l'interopérabilité.

Commençons par les algorithmes utilisés pour les signatures et MAC (section 3). C'est le membre alg de JWS (JSON Web Signature, cf. RFC 7515). La table complète est dans son registre IANA. Comme JOSE privilégie la concision, les termes utilisés sont plus courts que, par exemple, dans les registres prévus pour TLS. Ainsi, HS512 veut dire « HMAC avec SHA-512 ». (Pour l'algorithme HMAC, voir le RFC 2104.) Et ES256 désignera un algorithme de signature couplant ECDSA avec une courbe P-256 et SHA-256 (on peut aussi signer avec RSA mais les signatures sont plus courtes avec les courbes elliptiques).

Il y a même un algorithme none dans le registre, dont le nom indique clairement que le texte JSON n'est pas authentifié, ni protégé en intégrité. A priori, les applications qui veulent vérifier le JSON reçu vont rejeter des textes ainsi marqués (sections 3.6 et aussi 8.5), sauf cas très spécifiques, par exemple si on est absolument certain que le texte JSON est arrivé sur une connexion sécurisée (mais relire la section 8.5, sur les pièges que cela pose).

Maintenant, le chiffrement. Il faut pouvoir indiquer comment ont été chiffrées les clés ayant servi à chiffrer le contenu. La section 4 décrit les algorithmes prévus pour cela (qui sont aussi dans le même registre IANA), et qu'on met dans le membre alg d'un JWE (JSON Web Encryption, cf. RFC 7516).

Ainsi, un cas simple est celui où les deux parties chiffrent avec une clé statique symétrique, pré-échangée entre eux. On met alors dir (pour direct use of a key) comme algorithme. Si au contraire on chiffre la clé de chiffrement avec RSA, on mettra par exemple l'algorithme RSA1_5 qui veut dire « RSA avec PKCS#1 ». (On a droit aussi, bien sûr, aux échanges de clés Diffie-Hellman.)

Et le contenu lui-même, on le chiffre avec quoi ? La section 5 décrit les algorithmes de chiffrement symétriques utilisés (encore le même registre IANA). Ils se mettent dans le membre enc du JWE. Par exemple, A128CBC-HS256 est AES en mode CBC avec un HMAC sur SHA-256, alors que A256GCM est AES mais en mode GCM (qui, fournissant du chiffrement intègre, dispense d'utiliser HMAC).

À noter que le petit nouveau à l'IETF, le ChaCha20 du RFC 8439, n'est pas encore arrivé dans JOSE et ne figure pas dans ce registre, qui ne compte qu'AES.

Passons maintenant aux clés (section 6), représentés par un JWK (JSON Web Key, RFC 7517. Dans le membre kty (Key TYpe) d'un JWK, on peut trouver RSA, EC (Elliptic Curve) ou oct (octet), ce dernier désignant une clé symétrique. Les paramètres dépendent ensuite du type de clés. Par exemple, pour les courbes elliptiques, crv désigne la courbe utilisée (P-256, P-384, etc, les valeurs possibles ayant leur propre registre), pour RSA, n sera le modulo et e l'exposant. Les valeurs possibles pour ces paramètres de clés sont dans un registre IANA.

Je l'ai dit au début, les progrès de la cryptanalyse nécessitent de changer les algorithmes de temps en temps (section 8.1 sur l'« agilité cryptographique »). La section 7 fixe les règles de modification des registres. En gros, il faut avoir une spécification écrite (pas forcément un RFC) pour voir son algorithme entrer dans le registre (Specification Required, RFC 5226, section 4.1).


Téléchargez le RFC 7518


L'article seul

RFC 7517: JSON Web Key (JWK)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 20 mai 2015


Le sigle JOSE (JavaScript Object Signing and Encryption) désigne l'utilisation de moyens cryptographiques pour sécuriser des textes JSON. JOSE permet notamment de signer (RFC 7515) et chiffrer (RFC 7516) des textes JSON. Pour cela, il faut des clés cryptographiques et ce RFC 7517 normalise la représentation de ces clés en JSON.

Une JWK (JSON Web Key) est donc une clé représentée par un objet JSON. Que les amateurs de X.509 se rassurent, il n'est pas prévu de remplacer ce format par JSON :-) Le but essentiel est de pouvoir manipuler des clés dans le contexte de JSON (transmettre la clé en même temps qu'une signature, chiffrer une clé privée pour la transporter de manière sûre, etc). Outre la JWK, notre RFC définit aussi le JWK set, un ensemble de JWK.

Commençons par un exemple simple, une clé sur une courbe elliptique :

     {"kty":"EC",
      "crv":"P-256",
      "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
      "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
      "kid":"Public key used in JWS A.3 example"
     }

Ici, le membre kty identifie la clé comme utilisant les courbes elliptiques, crv indique l'usage de la courbe NIST P-256, x et y sont les coordonnées de la clé sur cette courbe. kid est un identificateur de clé, dont le format est libre.

La section 4 décrit en détail tous les membres possibles de l'objet clé. Parmi les principaux :

  • kty vaut EC (courbes elliptiques) ou RSA (l'algorithme du même nom). D'autres valeurs sont possibles (cf. RFC 7518, et le registre IANA).
  • use (inutilisé dans l'exemple plus haut) indique l'utilisation prévue de la clé (sig pour signer, enc pour chiffrer...). Là encore, le RFC 7518 prévoit un registre des valeurs possibles.
  • alg désigne l'algorithme à utiliser avec cette clé, parmi ceux enregistrés à l'IANA.
  • kid (Key IDentification) sert à identifier la clé. Par exemple, lorsqu'on doit désigner une clé particulière au sein d'un ensemble de clés disponibles. Notez que son format n'est pas spécifié par notre RFC.
  • x5c est un certificat X.509 (RFC 5280), ou une chaîne de certificats. Les certificats sont une valeur en DER encodée en Base64.
  • x5u est un URL pointant vers un certificat X.509.

JWK peut servir pour la cryptographie asymétrique ou pour la symétrique. Voici un exemple de clé symétrique (le type oct signifie « suite d'octets », la clé elle-même est dans le membre k) :

{
   "kty":"oct",
   "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
   "kid":"HMAC key used in JWS A.1 example"
}

Si on veut manipuler plusieurs clés ensemble (section 5), on peut utiliser un objet JSON comportant un membre keys dont la valeur est un tableau de JWK. Ici, une clé sur une courbe elliptique et une clé RSA :

     {"keys":
       [
         {"kty":"EC",
          "crv":"P-256",
          "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
          "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
          "use":"enc",
          "kid":"1"},

         {"kty":"RSA",
          "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
          "e":"AQAB",
          "alg":"RS256",
          "kid":"2011-04-29"}
       ]
     }

Le format JWK permet de représenter des clés privées, que ce soit la partie privée d'une clé asymétrique, ou bien une clé symétrique. Si on échange ces clés, il est évidemment recommandé de les chiffrer, ce qui peut se faire avec JOSE (RFC 7516). Une JWK chiffrée est alors un JWE (contenu chiffré en JOSE) comme les autres.

Comme tous les RFC JOSE, cette norme fait une forte consommation de registres IANA. La section 8 leur est consacrée. La politique d'enregistrement dans ces registres est « description nécessaire » (cf. RFC 5226), ce qui veut dire qu'un texte stable décrivant la valeur enregistrée est nécessaire. Par exemple, si on veut enregistrer un nouvel algorithme cryptographique pour les clés, on doit indiquer un texte décrivant précisément cet algorithme. Les registres sont notamment :

  • Les paramètres des clés (comme use pour l'usage prévu, ou kid pour l'identificateur). Comme toujours dans le monde JSON, les membres inconnus d'un objet sont ignorés. Ainsi, un nouveau membre enregistré ici pourra être utilisé sans risque puisque les mises en œuvre de JOSE plus anciennes ignoreront ce nouveau membre.
  • Les utilisations des clés comme sig pour la signature ou bien enc pour le chiffrement.

Outre ces nouveaux registres, ce RFC ajoute au registre des types de média le type application/jwk+json qui identifie une clé encodée en JSON et application/jwk-set+json qui identifie un ensemble de clés.

La section 9 de notre RFC se penche sur la sécurité, évidemment un sujet important quand on manipule des clés. Les règles à suivre sont les règles classiques de la cryptographie. Par exemple, les clés privées doivent être gardées à l'abri des regards indiscrets, comme rappelé dans les RFC 3447 et RFC 6030.

Autre piège, risquer de croire que, parce qu'un texte est signé, il a davantage de valeur. Cela n'est vrai que si on peut s'assurer de l'origine de la clé. Autrement, cela ne signifie rien, n'importe qui ayant pu se créer une clé. Un des moyens de vérifier cette origine est de valider le certificat PKIX dans le membre x5c. Au passage, les exemples de certificats dans le RFC sont, comme le veut le format JWK de JOSE, du DER encodé en Base64. Pour les lire, on peut par exemple, mettre le contenu en Base64 (après avoir retiré les espaces et sauts de ligne qui se trouvent dans le RFC) dans un fichier, le décoder avec base64 puis le lire avec OpenSSL :

% base64 -d < rfc.b64 > rfc.der              
% openssl x509 -text -inform der -in rfc.der
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:3c:ff:16:e2:e2
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, ST=CO, L=Denver, O=Ping Identity Corp., CN=Brian Campbell
        Validity
            Not Before: Feb 21 23:29:15 2013 GMT
            Not After : Aug 14 22:29:15 2018 GMT
        Subject: C=US, ST=CO, L=Denver, O=Ping Identity Corp., CN=Brian Campbell
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
...

Téléchargez le RFC 7517


L'article seul

RFC 7516: JSON Web Encryption (JWE)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft), J. Hildebrand (Cisco)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 3 juin 2015


L'ensemble de normes de cryptographie JOSE, qui permet de sécuriser des textes JSON comprend plusieurs RFC, dont ce RFC 7516, qui normalise le chiffrement, permettant d'assurer la confidentialité des documents JSON.

Un document chiffré est baptisé JWE (pour JSON Web Encryption). Il peut exister sous deux formes (deux sérialisations), une compacte (en Base64, cf. section 3.1), qui peut notamment être utilisée dans les URL, et une en JSON, qui permet de passer par les programmes de traitement du JSON (sections 3.2 et 7.2.1). Elles utilisent les mêmes mécanismes cryptographiques sous-jacents. Les algorithmes utilisables sont normalisés dans le RFC 7518. Il est recommandé de lire également le RFC sur les signatures JOSE (RFC 7515) car beaucoup de règles applicables à la fois à la signature et au chiffrement ne sont décrites que dans ce RFC 7515 (comme la comparaison des chaînes de caractères de la section 5.3).

Les principes de base de JWE sont exposés dans la section 3 du RFC (en s'appuyant que la terminologie de la section 2). Quelle que soit la sérialisation choisie, un JWE peut comprendre :

  • L'en-tête JOSE, lui-même composé d'une partie protégée et d'une ou plusieurs parties non protégées,
  • La clé cryptographique, chiffrée,
  • Le vecteur d'initialisation,
  • L'AAD (Additional Authenticated Data), protégée en intégrité mais pas chiffrée, qui sert lorsqu'on fait de l'AEAD,
  • Le texte chiffré (et donc illisible par un indiscret),
  • L'authentication tag.

Dans la sérialisation en JSON, les composants binaires (comme le texte chiffré) sont encodés en Base64, JSON n'ayant pas de mécanisme pour les données binaires.

Un JWE en sérialisation compacte est la concaténation des différents composants cités ci-dessus, chacun encodé en Base64 (un exemple figure en section 3.3). Un JWE en sérialisation JSON est un objet JSON comportant un membre par composant, par exemple iv pour le vecteur d'initialisation, ciphertext pour le texte chiffré, recipients pour des informations sur les destinataires (optionnel : s'il n'y a qu'un seul destinataire, on peut mettre ces informations dans l'objet JWE, cf. section 7.2.2).

L'en-tête JOSE est détaillé dans la section 4. Il inclut la plupart des paramètres cryptographiques. On le représente par un objet JSON (qui sera ensuite encodé en Base64). Cet objet a des membres comme alg (l'algorithme de chiffrement utilisé pour la clé, en général un algorithme de chiffrement asymétrique) ou enc (l'algorithme de chiffrement utilisé pour le contenu, en général un algorithme de chiffrement symétrique), etc. Les algorithmes possibles sont décrits dans le RFC 7518. De nombreux autres membres sont possibles comme zip pour indiquer l'éventuel algorithme de compression utilisé (par exemple celui du RFC 1951).

Le mécanisme complet de chiffrement et de déchiffrement (ce dernier est l'inverse du chiffrement) est décrit dans la section 5. Voici un exemple, tiré de l'annexe A.4 : il y a deux destinataires, le premier utilisera RSA et le second AES pour chiffrer la clé :

"recipients":[
       {"header":
         {"alg":"RSA1_5","kid":"2011-04-29"},
       {"header":
         {"alg":"A128KW","kid":"7"},
	 ...

Le texte sera chiffré avec AES en mode CBC avec du HMAC sur SHA-256 pour produire l'authentication tag :

  {"enc":"A128CBC-HS256"}

(Cet objet formera l'en-tête protégé.) En utilisant cette valeur pour le vecteur d'initialisation :

  "iv":       "AxY8DCtDaGlsbGljb3RoZQ",

et cette clé de chiffrement :

  {"kty":"oct",
      "k":"GawgguFyGrWKav7AX4VKUg"
      }

Et le message en clair « Live long and prosper. », on arrive à ce JWE complet :

  {
      "protected":
       "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
      "unprotected":
       {"jku":"https://server.example.com/keys.jwks"},
      "recipients":[
       {"header":
         {"alg":"RSA1_5","kid":"2011-04-29"},
        "encrypted_key":
         "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-
          kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKx
          GHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3
          YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPh
          cCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPg
          wCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A"},
       {"header":
         {"alg":"A128KW","kid":"7"},
        "encrypted_key":
         "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ"}],
      "iv":
       "AxY8DCtDaGlsbGljb3RoZQ",
      "ciphertext":
       "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
      "tag":
       "Mz-VPPyU4RlcuYv1IwIvzw"
       }

Pour du code qui met en œuvre le chiffrement JOSE, voir mon article général.


Téléchargez le RFC 7516


L'article seul

RFC 7515: JSON Web Signature (JWS)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft), J. Bradley (Ping Identity), N. Sakimura (NRI)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 20 mai 2015


Dans la série des RFC JOSE, qui décrivent les possibilités de protéger des textes JSON avec la cryptographie, ce RFC 7515 normalise les signatures, qui permettent de garantir l'authenticité et l'intégrité des textes JSON.

Le format JSON, normalisé dans le RFC 8259, ne bénéficiait pas jusqu'alors d'un moyen standard pour permettre la vérification de son authenticité. Certes, on pouvait transport le JSON via un transport sécurisé comme HTTPS mais cela ne fournissait qu'une protection du canal, pas un contrôle d'intégrité de bout en bout.

Le principe de ce RFC est le suivant (section 3) : un texte JSON protégé par une signature, un JWS (JSON Web Signature), est composé de trois parties : l'en-tête JOSE (JavaScript Object Signing and Encryption), qui indique les paramètres cryptographiques, la charge utile JWS (le message d'origine), et la signature JWS. L'en-tête JOSE se sépare en un en-tête protégé (par la signature) et un en-tête non protégé. Le document rassemblant ces trois parties est ensuite sérialisé en une suite d'octets. Il y a deux sérialisations possibles. La sérialisation compacte est simplement la concaténation de l'encodage en Base64 de l'en-tête protégé, d'un point, de l'encodage en Base64 de la charge utile, un autre point et enfin l'encodage en Base64 de la signature. Un JWS ainsi sérialisé peut être utilisé dans un URL. Voici un exemple :

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Pas très lisible, évidemment. La deuxième sérialisation possible est dite sérialisation JSON car son résultat est un texte JSON. C'est un objet JSON comportant quatre membres (pas forcément obligatoires), payload, la charge utile, protected, l'en-tête JOSE protégé, header, l'en-tête JOSE non protégé, et signature, la signature. Les trois derniers peuvent se retrouver regroupés dans un sous-objet nommé signatures. En voici un exemple :

{
      "payload":
       "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
      "signatures":[
       {"protected":"eyJhbGciOiJSUzI1NiJ9",
        "header":
         {"kid":"2010-12-29"},
        "signature":
         "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"},
       {"protected":"eyJhbGciOiJFUzI1NiJ9",
        "header":
         {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
        "signature":
         "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"}]
}

Si vous n'avez pas de décodeur Base64 sous la main, notez que la charge utile (le texte JSON qu'on veut protéger) était :

{"iss":"joe",
 "exp":1300819380,
 "http://example.com/is_root":true}

Après cette vision générale, les détails. D'abord, l'en-tête JOSE (section 4). On a vu qu'il indiquait les paramètres algorithmiques de la signature. Les plus importants de ces paramètres :

  • alg indique l'algorithme cryptographique utilisé. Les valeurs possibles dans le registre IANA défini par le RFC 7518. Par exemple {"alg":"ES256"} identifiera l'algorithme ECDSA avec la courbe P-256 et la condensation en SHA-256.
  • jwk est la clé de signature, formatée selon le RFC 7517.
  • jku est un URL au bout duquel on trouvera un ensemble de clés, formatées également selon le RFC 7517. La clé de signature fait partie de cet ensemble. Évidemment, il faut utiliser un transport sécurisé (comme HTTPS, avec validation de l'identité du serveur, cf. RFC 6125) pour récupérer ces clés (section 8, sur les exigences TLS).
  • kid, que vous avez vu dans l'exemple plus haut, est un identificateur de la clé de signature (cf. section 6).
  • x5c est un certificat X.509 (RFC 5280) correspondant à la clé de signature.
  • x5u est un URL pointant vers un certificat X.509 correspondant à la clé de signature.

Les étapes pour créer un JWS sont décrites en section 5 :

  • Encoder la charge utile en Base64 (RFC 4648). Notez qu'il n'existe pas de mécanisme de canonicalisation standard d'un texte JSON et qu'on n'applique donc pas une telle canonicalisation.
  • Fabriquer l'en-tête JOSE avec les paramètres cryptographiques qu'on va utiliser, puis l'encoder en Base64.
  • Signer (les détails dépendent évidemment de l'algorithme de signature utilisé), et encoder la signature en Base64.
  • Sérialiser (en JSON ou en compact).

Pour valider une signature, on fait l'inverse. Si une étape échoue, la signature est rejetée.

  • Analyser la forme sérialisée pour en extraire les différents composants (en-tête, charge utile, signature).
  • Décoder (depuis le Base64) l'en-tête protégé et vérifier qu'on obtient bien du JSON correct.
  • Vérifier qu'on comprend tous les paramètres, par exemple l'algorithme de signature utilisé.
  • Décoder (depuis le Base64) la signature et la charge utile.
  • Valider la (ou les) signature(s).

S'il y a plusieurs signatures, ce que permet JWS, doivent-elles être toutes valides ou bien une seule suffit-elle ? Ce n'est pas défini par la norme JOSE : chaque application utilisant JOSE peut décider comme elle veut. Dans tous les cas, pour que le document soit considéré comme correctement signé, il faut qu'au moins une signature soit valide. Une autre décision est du ressort de l'application : quels sont les algorithmes de signature acceptables. Par exemple, une application peut décider de rejeter une signature car l'algorithme, trop faible cryptographiquement parlant, n'est pas accepté.

Notez que pas mal d'étapes de JOSE nécessitent de comparer des chaînes de caractères. Cela soulève immédiatement les problèmes de canonicalisation. Les règles JSON de comparaison pour les noms des membres d'un objet sont dans la section 8.3 du RFC 8259. Pour les valeurs, c'est plus compliqué et cela dépend de l'application. Ainsi, si une application a décidé que le membre kid (identificateur de la clé) contient un nom de domaine, elle peut faire des comparaisons insensibles à la casse.

La section 7 de notre RFC couvre les sérialisations. Comme on l'a vu plus haut, il y a deux sérialisations, la compacte et celle en JSON. Chaque application de JOSE va décider quelles sérialisations sont acceptables, la compacte, la JSON ou les deux. La sérialisation en JSON a une forme générale, où les signatures sont un tableau (éventuellement de taille 1) et une légère variante, la sérialisation en JSON aplati, où une seule signature est possible. Voici les deux cas, d'abord la forme générale, avec deux signatures :

{
      "payload":"...",
      "signatures":[
       {"protected":"...",
        "signature":"..."},
       ...
       {"protected":"...",
        "signature":"..."}]
     }

Puis la forme aplatie :

{
      "payload":"...",
      "protected":"...",
      "signature":"..."
     }

La sérialisation compacte, lorsqu'elle est envoyée via l'Internet, est étiquetée avec le type MIME application/jose. La sérialisation en JSON est application/jose+json. Ces deux types sont utilisables pour les JWS de ce RFC ou pour les JWE du RFC 7516.

La section 10 de notre RFC revient sur les exigences de sécurité, qui accompagnent tout protocole cryptographique. La plupart ne sont pas spécifiques à JOSE. Par exemple, si on laisse trainer sa clé privée n'importe où, des tas de gens pourront faire des fausses signatures. Autre cas bien connu, le générateur aléatoire utilisé pour générer les clés (et autres valeurs qui doivent être imprévisibles) doit être fiable (des tas de failles de sécurité ont été créées par des générateurs insuffisants). Mais certains problèmes sont un peu plus subtils. Par exemple, supposons qu'on valide la signature et que, cryptographiquement, tout soit au point. Mais qu'est-ce que ça nous prouve ? Ça nous prouve que le document a bien été signé par le titulaire de la clé privée utilisée. Mais, en général, on veut plus que cela. On veut que le document soit bien signé par Mme A ou par la société B. Il y a donc une étape entre la clé et l'entité à qui on fait confiance (Key Origin Authentication) qui n'est pas triviale.

Autre point qui n'est pas forcément maitrisé de tous, la différence entre signature et MAC. La section 10.5 l'explique bien : la clé utilisée pour MAC est entre les mains de plusieurs entités et l'authentification garantie par MAC est donc plus faible.

Il peut y avoir aussi des failles de sécurité dans JSON et pas dans JOSE, notamment en raison du flou de cette norme, et du laxisme de certaines mises en œuvre qui acceptent du JSON mal formé. Ainsi, le RFC 8259 n'impose pas que les membres d'un objet soient uniques. Un objet JSON :

{
  "voter": "Smith",
  "vote": "YES",
  "vote": "NO"
}

est légal (quoique très déconseillé). Si on sait qu'un utilisateur de cet objet a un analyseur qui ne garde que le dernier membre dupliqué, et qu'un autre a un analyseur qui ne garde que le premier membre dupliqué, on peut signer cet objet et faire croire au premier utilisateur que Smith a voté non, et au second que le même Smith a voté oui. Pour éviter cela, la norme JOSE durcit le RFC 8259 en interdisant les membres dupliqués (une meilleure solution aurait été d'imposer l'utilisation du sous-ensemble JSON du RFC 7493, je trouve, mais l'IETF a choisi une autre voie). Une conséquence de ce durcissement est qu'on ne peut pas signer tous les objets JSON. Les cas pathologiques sont exclus. (Ce point a été l'un des plus « chauds » dans la mise au point de JOSE à l'IETF.)

Plein d'examples de signatures se trouvent dans l'annexe A de notre RFC (mais qu'on avait aussi dans le RFC 7520).


Téléchargez le RFC 7515


L'article seul

RFC 7513: SAVI Solution for DHCP

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : J. Bi, J. Wu, G. Yao (Tsinghua Univ.), F. Baker (Cisco)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF savi
Première rédaction de cet article le 11 juin 2015


Le cadre SAVI (Source Address Validation Improvement), décrit dans le RFC 7039, vise à rendre plus difficile l'usurpation d'adresses IP. SAVI fournit un cadre général et plusieurs solutions techniques concrètes sont ensuite développées selon le type de réseau et selon le niveau de sécurité qu'on désire et qu'on est prêt à « payer ». Ainsi, le RFC 6620 décrivait un mécanisme où le réseau d'accès assurait que le premier titulaire d'une adresse IP puisse la garder. Ce nouveau RFC décrit un autre mécanisme, où c'est via l'utilisation de DHCP qu'on contrôle les adresses : le réseau d'accès va empêcher l'utilisation d'adresses qui n'ont pas été allouées par le serveur DHCP. (Ce mécanisme est largement déployé depuis des années, sous divers noms, comme « DHCP snooping », mais n'avait pas été formellement décrit dans un RFC.)

L'usurpation d'adresse IP est à la base de nombreuses attaques sur l'Internet, comme les attaques par réflexion. Il existe depuis longtemps des techniques pour limiter l'usurpation d'adresses IP (le RFC 2827 est un exemple classique, qui permet de protéger un réseau contre l'usurpation par un autre). Celles de SAVI visent surtout le réseau local (réseau d'accès pour un FAI) en limitant le risque d'usurpation interne (qu'un utilisateur du réseau local usurpe l'adresse d'un autre). Ici, dans ce RFC 7513, l'allocation d'une adresse IP via DHCP va créer un lien (binding) entre cette adresse et des informations qui permettront au réseau de filtrer les usurpateurs. Par exemple, en retenant le port physique du commutateur comme lien, le commutateur peut bloquer les paquets dont l'adresse IP source n'est pas celle qui a été allouée à la machine connectée à ce port. Un tel mécanisme est souvent présent dans les commutateurs existants, souvent sous le nom de DHCP snooping mais attention : parfois, ce DHCP snooping se limite à bloquer les réponses DHCP arrivant sur un port inattendu, et n'intégre pas forcément la protection contre l'usurpation d'adresses IP, le but principal de ce RFC. Vérifiez avec votre commutateur !

Ce mécanisme de lien (binding anchor) est décrit en section 3 du RFC 7039 et rappelé en section 3 de notre RFC. Un lien doit être un attribut caractéristique, et difficile à changer (un contre-exemple est l'adresse MAC, facile à changer sur beaucoup de systèmes, et pourtant citée par notre RFC). C'est le cas du port physique du commutateur Ethernet cité plus haut, ou bien d'une association de sécurité WiFi (la section 3.2 du RFC 7039 donne d'autres exemples).

SAVI-DHCP va donc surveiller le trafic DHCP, notant les requêtes et réponses DHCP et les associant aux liens. Notez que cela marche avec le DHCP avec état (RFC 2131 pour IPv4 et RFC 8415 pour IPv6), pas avec le DHCP sans état du RFC 8415, qui ne s'occupe pas d'allocation d'adresses IP. De même, SAVI-DHCP ne gère évidemment pas le cas des réseaux où les adresses IP sont obtenues par un autre moyen que DHCP, par exemple le SLAAC du RFC 4862. Idem pour les adresses locales au lien (RFC 4291, section 2.5.6). Dans ces deux derniers cas, il faut utiliser une autre technique SAVI, le FCFS du RFC 6620.

Bon, maintenant, les détails. La section 4 précise quels acteurs sont considérés : un serveur DHCP évidemment, des clients DHCP, et les machines SAVI, typiquement des commutateurs, qui vont faire respecter les règles SAVI (il y a aussi quelques commutateurs non-SAVI dans le réseau d'exemple, pour mieux refléter la réalité). La machine SAVI va avoir besoin d'une certaine configuration. Par exemple, si le réseau contient un serveur DHCP menteur, la machine SAVI ne peut pas le deviner, et il faut lui dire sur quel port est attaché le vrai serveur DHCP (attribut SAVI DHCP-trust, cf. par exemple cette documentation Cisco, la commande ip dhcp snooping trust indiquera qu'un serveur DHCP légitime opère sur cette interface). De même, certains ports physiques ne doivent pas valider les adresses IP (attribut SAVI Trust, par exemple un port attaché au routeur de sortie, port sur lequel on verra passer, et c'est normal, plusieurs adresses IP) et il faudra donc indiquer à la machine SAVI sur quels ports elle doit surveiller (ceux où ne se trouve normalement qu'une ou plusieurs machines obtenant des adresses par DHCP).

SAVI sépare le réseau en deux, la partie de confiance et le reste. Dans la partie de confiance, on peut être raisonnablement sûr que les adresses IP source sont authentiques : tous les commutateurs valident. SAVI ne prétend pas sécuriser tout l'Internet. Et, même dans le réseau local, une partie du réseau peut être non-SAVI et ne sera donc pas de confiance. Cette notion de périmètre (séparant la partie de confiance et le reste) est essentielle pour configurer SAVI, et pour savoir ce qu'on peut attendre de cette technique. Par exemple, des réponses DHCP venues d'un serveur situé en dehors du périmètre ne seront pas utilisées par SAVI : puisque cette zone n'est pas de confiance, il peut parfaitement s'agir d'un serveur pirate (section 4.3.3 du RFC, un bon exemple de l'utilisation de la notion de périmètre, avec un schéma d'exemple).

La sécurité de SAVI-DHCP dépend évidemment de la sécurité des liens. Il faut notamment s'assurer que les attributs utilisés pour construire le lien sont difficiles à usurper. Un port physique du commutateur est un bon exemple. A contrario, une adresse MAC est un mauvais attribut (trop facile à changer) et même un attribut fort peut être affaibli par certains usages. Par exemple, si on utilise le port physique du commutateur Ethernet comme binding anchor, mais que ce dernier est connecté à des commutateurs non-SAVI en cascade, les nombreuses machines qui partagent ce port physique peuvent encore usurper leurs adresses IP entre elles.

Ces liens et les adresses IP associées doivent être stockées dans la mémoire de la machine SAVI, dans un structure de données dite BST (Binding State Table, section 5). Chaque ligne de cette table stocke également la durée de vie du lien et l'état du lien (établi, en cours d'établissement, inconnu).

La BST se remplit en « espionnant » (snooping) le trafic DHCP (section 6). En résumant (beaucoup) : la machine SAVI voit passer une requête DHCP et la réponse arrive depuis un port marqué comme DHCP-trust. On stocke alors dans la BST le port d'où est venu la requête (le lien, le binding anchor), l'adresse IP dans la réponse, le fait que le lien est établi, et sa durée de vie (typiquement la durée du bail DHCP). Désormais, si on voit un paquet IP arriver par le port d'où venait la requête DHCP, on pourra regarder son adresse IP source, et jeter le paquet si elle ne correspond pas à ce qui est dans la BST (ce filtrage est décrit en section 8). Sur un Juniper, on peut afficher cette BST avec show dhcp snooping binding. Cet exemple est tiré d'une documentation Juniper :

user@switch> show dhcp snooping binding
DHCP Snooping Information:
MAC Address             IP Address Lease   Type     VLAN    Interface
-----------------       ---------- -----   -------  ----    ---------
00:00:01:00:00:03       192.0.2.0  640     dynamic  guest    ge-0/0/12.0
00:00:01:00:00:04       192.0.2.1  720     dynamic  guest    ge-0/0/12.0
00:00:01:00:00:05       192.0.2.5  800     dynamic  guest    ge-0/0/13.0

Attention, il y a quelques pièges. Par exemple, s'il existe plusieurs chemins entre le client et le serveur DHCP, et que la machine SAVI n'est que sur un seul de ces chemins, elle risque de rater le dialogue DHCP. Autre cas problématique si une machine se déplace d'un port à un autre sans refaire une requête DHCP.

La section 7 propose des solutions à ces problèmes de faux positifs. L'idée est de noter le trafic rejeté par SAVI-DHCP et de vérifier activement si le paquet a été rejeté à tort (le mal nommé « Data Snooping Process »). Par exemple, en IPv4, on peut envoyer des requêtes ARP (RFC 826 et RFC 5227) pour déterminer si deux machines (la vraie et l'usurpatrice) utilisent la même adresse IP (s'il n'y a qu'une machine, la vraie, on ne recevra qu'une réponse). En IPv6, on peut utiliser un message DAD (Duplicate Address Detection, cf. RFC 4862, section 5.4) pour faire le même test.

On peut aussi, si on a raté ou qu'on pense avoir raté le dialogue DHCP, demander directement au serveur DHCP, avec un message DHCPLEASEQUERY (RFC 4388) en IPv4 et LEASEQUERY (RFC 5007) en IPv6.

Bref, comme toujours en sécurité, on n'a pas de repas gratuit : SAVI-DHCP protège contre bien des usurpations mais, comme toute technique de filtrage, il peut mener au rejet de messages légitimes.

Le mécanisme de SAVI-DHCP nécessite de mémoriser un état, la BST (Binding State Table, décrite en section 5). Si elle est gardée en RAM et qu'on redémarre, la liste des liens est perdue et tous les paquets seront rejetés (c'est pourquoi, en général, IP déconseille de garder de l'état dans le réseau). La section 9 rappelle ce problème et demande donc que la BST soit stockée dans une mémoire qui survit aux redémarrages. (On pourrait récupérer un bon bout de la BST par les méthodes de la section 7 mais ça prendrait un temps fou.) À noter que, sur un Juniper, ce n'est pas fait par défaut (il faut la directive dhcp-snooping-file pour stocker la BST).

Terminons ce résumé du RFC avec la section 11, consacrée aux questions de sécurité. D'abord, les risques que crée le Data Snooping process de la section 7. Comme ce processus est coûteux en nombre de paquets envoyés, un attaquant pourrait être tenté de le déclencher afin de réaliser une attaque par déni de service. Pour cela, il aurait juste à envoyer quelques paquets usurpés. Le processus doit donc avoir une limitation de trafic.

Plusieurs autres attaques sont possibles contre ce mécanisme de sécurité complexe qu'est SAVI-DHCP (réutiliser l'adresse d'un client qui est parti et ne peut donc plus se défendre en cas de détection d'adresse dupliquée, créer de nombreux liens pour remplir la BST et faire une attaque par déni de service, etc). Il y a aussi un risque sur la vie privée, puisque la BST stocke de nombreuses informations sur l'arrivée et le départ des machines des utilisateurs. Elle ne doit donc pas être archivée. L'idée est qu'aucune information ne devrait être gardée sur les machines qui n'usurpent jamais d'adresse IP (ne pas fliquer les gens honnêtes).

À noter que Cisco prétend avoir inventé la technique et a un brevet sur l'idée, mais propose une licence (avec clause de représailles).

Merci à Cécile Grange pour des indications sur les solutions Juniper.


Téléchargez le RFC 7513


L'article seul

RFC 7512: The PKCS#11 URI Scheme

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : J. Pechanec, D. Moffat (Oracle Corporation)
Chemin des normes
Première rédaction de cet article le 23 avril 2015


La norme technique PKCS#11 décrit une interface d'accès à des fonctions cryptographiques. Par exemple, elle permet à un logiciel de signature de signer en utilisant une clé privée stockée dans une base de données, un HSM, une carte à puce (smart card) ou autres dépôts. Jusqu'à présent, la désignation des objets auxquels on pouvait accéder par PKCS#11 n'était pas normalisée et chaque logiciel avait sa méthode. Désormais, il existe un plan d'URI standard pour cela, spécifié dans ce RFC. Bienvenue à pkcs11:object=cle-de-machin;type=public;id=%69%95%3E%5C%F4%BD%EC%91 et à ses copains.

Prenons l'exemple de l'outil de manipulation de certificats certtool, de GnuTLS. Son option load-ca-certificate permet de charger le certificat d'une AC. La valeur de cette option peut être le nom d'un fichier local mais cela peut aussi être un URI PKCS#11, autorisant ainsi l'accès à tous les mécanismes de stockage ayant une interface PKCS#11. Le principe de ces URI PKCS#11 est de permettre l'accès à des objets (comme les certificats, les clés publiques, les clés privées, etc), en donnant une série d'attributs qui identifient l'objet (dans mon exemple au premier paragraphe, les attributs étaient object, type et id). Le but de ces URI est limité à la récupération d'objets existants, on ne s'en sert pas pour créer de nouveaux objets.

Donc, la définition formelle de ce plan d'URI (section 3 de notre RFC) : le plan est pkcs11 (et les URI commencent donc par pkcs11: et ce plan a été réservé dans le registre IANA), et l'URI est ensuite composé de paires attribut-valeur, séparées par des points-virgules. L'attribut id a une valeur binaire (et qui est donc pourcent-encodée dans l'exemple au premier paragraphe), tous les autres sont du texte en UTF-8. Voici les principaux attributs, avec leur nom dans les URI et l'équivalent dans l'API PKCS#11 :

  • id (CKA_ID) est l'identificateur d'un objet. C'est, comme on l'a vu, une valeur binaire opaque.
  • object (CKA_LABEL) est le nom d'un objet. Contrairement à l'id, c'est du texte.
  • serial (serialNumber dans CK_TOKEN_INFO) est le numéro de série du token, le dispositif de stockage des objets (un HSM, par exemple).
  • token (label dans le CK_TOKEN_INFO), le nom du dispositif de stockage.
  • type (CKA_CLASS), désigne le type d'objet stocké qu'on veut récupérer. Cela peut être cert (un certificat), public (une clé publique), private (une clé privée en cryptographie asymétrique), secret-key (une clé secrète en cryptographie symétrique).

Il est également possible d'ajouter des requêtes dans l'URI, après le point d'interrogation. Par exemple, si le dispositif de stockage réclame un PIN, on peut mettre quelque chose comme ?pin-source=file:/etc/dnssec/token_pin dans l'URI (ici, cela dit que le PIN se trouve dans le fichier /etc/dnssec/token_pin).

La section 4 contient plusieurs exemples d'URI PKCS#11, désignant :

  • Une clé publique, identifiée uniquement par son nom : pkcs11:object=my-pubkey;type=public.
  • Un certificat, en indiquant le nom du dépôt matériel (token) utilisé, et l'id du certificat : pkcs11:token=The%20Software%20PKCS%2311%20Softtoken;manufacturer=Snake%20Oil,%20Inc.;model=1.0;object=my-certificate;type=cert;id=%69%95%3E%5C%F4%BD%EC%91. Notez les attributs manufacturer et model, que je n'avais pas cité dans la liste des attributs les plus utilisés.
  • Une clé privée, en utilisant une nouvelle requête, module-name, qui permet d'indiquer la bibliothèque dynamique à charger pour parler au dépôt des clés (PKCS#11 est une API, pas un protocole, et il faut donc une bibliothèque différente par type de HSM ou smart card) : pkcs11:object=my-sign-key;type=private?module-name=snakeoil-pkcs11. Ici, sur une machine Unix, l'application PKCS#11 va donc tenter de charger la bibliothèque snakeoil-pkcs11.so.

Il existe plusieurs implémentations des URI PKCS#11, le document était en développement depuis longtemps. Ainsi, OpenConnect documente « Objects from PKCS#11 tokens are specified by a PKCS#11 URI. ». Le projet Fedora tente de standardiser tous ses logiciels qui font de la cryptographie autour de ces URI « Currently, there are many different ways to tell each application how to find the certificate. [...] where PKCS#11 objects are specified in a textual form which is visible to the user (e.g. on the command line or in a config file), objects SHOULD be specified in the form of a PKCS#11 URI as as described ». Pour un programme développé avec GnuTLS :

/* In addition the following functions can be used to load PKCS #11
key and certificates by specifying a PKCS #11 URL instead of a
filename. */
int gnutls_certificate_set_x509_trust_file (gnutls_certificate_credentials_t cred, const char * cafile, gnutls_x509_crt_fmt_t type)
...

Téléchargez le RFC 7512


L'article seul

RFC 7507: TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : B. Moeller, A. Langley (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 25 avril 2015


Le protocole TLS offre un grand nombre de choix : choix de la version, choix des algorithmes cryptographiques, plein d'options... Tous ces choix ne sont pas équivalents en terme de sécurité : les versions anciennes de TLS ont des vulnérabilités absentes des plus récentes, par exemple. Dès qu'un protocole cryptographique a des choix, il y a un risque de sécurité : que l'attaquant tente de perturber la négociation initiale entre les deux parties, pour les amener à choisir les variantes les moins sécurisées, en faisant croire à chacun que son partenaire ne peut pas gérer les meilleures variantes. C'est ce qu'on nomme une attaque par repli (downgrade attack) et c'est une plaie classique des protocoles cryptographiques (sauf de ceux qui n'offrent aucun choix, mais qui ont d'autres problèmes, notamment l'impossibilité d'évoluer). Ce RFC présentait une technique TLS pour empêcher certaines attaques par repli : annoncer un algorithme cryptographique qui n'est pas un vrai algorithme mais qui signale qu'on a effectué un repli, permettant au partenaire de détecter que quelqu'un a interféré avec la communication. Cette technique se nomme SCSV, pour Signaling Cipher Suite Value. Elle a été abandonnée par le RFC 8996, qui retirait du service les versions de TLS vulnérables.

Normalement, un tel signalement n'est pas nécessaire (c'est très bien expliqué dans cet article sur StackExchange), les règles de négociation de TLS se chargent de tout (RFC 5246, sections 7.3 et 7.4). Mais il y a des serveurs TLS bogués qui réagissent mal avec certaines variantes. Au lieu d'indiquer proprement qu'ils ne gèrent pas ces variantes, ils coupent la communication. Un client TLS qui veut donc maximiser ses chances de se connecter va donc réessayer, en ne proposant pas les choix qui ont pu mener au précédent échec. C'est sympa du point de vue de l'interopérabilité mais cette downgrade dance est dangereuse du point de vue de la sécurité : le serveur, lors de la deuxième tentative, ne sait pas qu'il s'agit d'un repli. Prenons l'exemple d'un attaquant qui a trouvé une faille dans TLS 1.0 mais qui n'existe plus dans TLS 1.2 (celui du RFC 5246). Si Alice et Bob savent tous les deux parler 1.2, c'est cette version qu'ils choisiront, par défaut. Il faut donc les convaincre de se replier en 1.0. Un attaquant actif peut perturber la négotiation TLS (par exemple en ne transmettant pas le ServerHello, donnant au client l'impression que le serveur a ignoré son ClientHello). Certains clients vont alors se dire « zut, demander 1.2 perturbe le serveur, je vais réessayer directement en 1.0 ». Et l'attaquant aura atteint son but. Le serveur, qui sait faire du TLS 1.2, verra une demande en 1.0 et se dire juste « tiens, un vieux client qui ne sait pas faire de 1.2 ». Jusqu'à ce nouveau RFC, la seule protection contre ces attaques était de configurer le serveur pour refuser certains choix vraiment trop mauvais, question sécurité. Cette solution était trop rigide (pour reprendre l'exemple précédent, TLS 1.0 n'est pas catastrophique : il est raisonnable d'autoriser les vieux clients à se connecter en 1.0, mais on veut empêcher que les clients récents ne soient amenés à se limiter à 1.0). Au passage, un exemple d'une telle démarche est discutée dans l'article présentant la configuration TLS de mon blog (la ligne GnuTLSPriorities SECURE:-VERS-SSL3.0:-ARCFOUR-128:-ARCFOUR-40).

L'idéal serait bien sûr qu'il n'y ait pas de serveurs bogués, que la négociation TLS normale suffise, et que les clients n'aient jamais à faire de downgrade dance. Mais, dans le monde cruel où nous vivons, cela n'arrivera pas, les programmeurs ne lisent pas les normes et ne testent pas leur travail. À noter que, même en l'absence d'un attaquant actif, on voit parfois des replis malencontreux : un problème temporaire de réseau peut mener le client TLS à se dire « tiens, pas de réponse, je vais réessayer en TLS 1.0 et sans les extensions, pour voir ».

Donc, pour permettre au serveur de détecter que le client a fait un repli à tort, notre RFC introduit un nouveau pseudo-algorithme de chiffrement, TLS_FALLBACK_SCSV, valeur 0x56,0x00 (désormais dans le registre IANA). Il sera envoyé uniquement par le client, jamais par le serveur. Ce n'est pas un vrai algorithme, juste un signalement par le client qu'une première connexion a échoué et que le client tente un repli (section 4 du RFC). Si le client envoie le pseudo-algorithme TLS_FALLBACK_SCSV dans son ClientHello, et indique un protocole de version inférieure à ce que le serveur peut gérer, le serveur peut alors se rendre compte que le client a effectué un repli à tort (cf. section 3). Il peut alors répondre avec un nouveau message d'erreur, l'alerte TLS inappropriate_fallback (valeur 86). Voici ce que ça donne avec Firefox : inappropriate-fallback.png

Le signalement par le client qu'il s'est replié est un (pseudo-)algorithme de chiffrement, pas une extension TLS, car le but est qu'il ne pose de problème avec aucun serveur, même le plus ancien et le plus bogué. Le mécanisme d'indication des algorithmes de chiffrement date des débuts de SSL et on peut donc certainement compter dessus. Au passage, la technique de notre nouveau RFC est la deuxième utilisation de ce principe du SCSV, après la TLS_EMPTY_RENEGOTIATION_INFO_SCSV de la section 3.3 du RFC 5746.

La section 6 de notre RFC explore les cas où le client a intérêt à envoyer un TLS_FALLBACK_SCSV ou pas. Si le client n'a pas pu se connecter en TLS v1 ou supérieur, et se replie sur SSL v3, alors, le TLS_FALLBACK_SCSV est vraiment nécessaire car SSL v3 a de nombreuses faiblesses (la faille Poodle par exemple). Par contre, quand un client a une toute nouvelle version de TLS (à l'heure de la publication de ce RFC, la version 1.3 est en cours de développement), des difficultés avec les vieux serveurs sont à prévoir et il peut être préférable de ne pas envoyer TLS_FALLBACK_SCSV, et d'accepter le repli.

Des mesures faites en novembre 2014 indiquaient que 14 % des serveurs TLS sur l'Internet géraient déjà ce pseudo-algorithme TLS_FALLBACK_SCSV. Si vous voulez tester vous-même, vous pouvez par exemple vous servir d'OpenSSL en ligne de commande :

% openssl s_client -connect google.com:443 -state -fallback_scsv -tls1_1
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv3 write client hello A
SSL3 alert read:fatal:unknown
SSL_connect:failed in SSLv3 read server hello A
1077786776:error:1409443E:SSL routines:SSL3_READ_BYTES:tlsv1 alert inappropriate fallback:s3_pkt.c:1260:SSL alert number 86
1077786776:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:598:

Ici, on a tenté de se connecter à Google en envoyant le SCSV (option -fallback_scsv) et en indiquant comme numéro de version TLS 1.1 (alors que Google et OpenSSL savent tous les deux faire du 1.2). Google a donc envoyé l'alarme (le message alert inappropriate fallback). Avec un serveur qui ne gère pas SCSV, on aurait au contraire eu une connexion sans alerte. Si, au lieu du programme openssl, on veut le faire depuis une application qu'on écrit, il y a instructions et code sur le Wiki d'OpenSSL. Notez que le test des SSL Labs regarde aussi SCSV (message « This server supports TLS_FALLBACK_SCSV to prevent protocol downgrade attacks » ou bien aucune indication dans le cas contraire). Vu avec tshark, le test avec openssl montrera :

client -> serveur:

        Handshake Protocol: Client Hello
            Version: TLS 1.1 (0x0302)
                Cipher Suite: Unknown (0x5600) [version trop ancienne
		de Wireshark, qui n'affiche pas le nom de la SCSV]

serveur -> client:

    TLSv1.1 Record Layer: Encrypted Alert                                                                     
        Content Type: Alert (21)                                                                              
        Version: TLS 1.1 (0x0302)                                                                             
        Length: 2                                                                                             
        Alert Message: Encrypted Alert         

(L'alerte est chiffrée et donc pas décodée par défaut par Wireshark.)

Côté navigateurs Web, Firefox et Chrome gèrent cette technique SCSV mais il semble qu'Internet Explorer ne le fera pas.

Et, pour finir, une bonne explication de SCSV, avec des exemples Wireshark. Et merci à Florian Maury pour sa relecture.


Téléchargez le RFC 7507


L'article seul

RFC 7505: A "Null MX" No Service Resource Record for Domains that Accept No Mail

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : J. Levine (Taughannock Networks), M. Delany (Apple)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 1 juillet 2015


Comment indiquer qu'un domaine ne reçoit jamais de courrier ? Jusqu'à présent, il n'existait pas de mécanisme standard, permettant d'indiquer aux clients de ne pas perdre de temps à essayer d'écrire. Ce nouveau RFC indique une méthode, le « MX nul » qui consiste à mettre un point en partie droite de l'enregistrement MX.

Normalement, un logiciel de messagerie qui veut envoyer du courrier à bob@example.net va chercher dans le DNS l'enregistrement MX du domaine example.net. (Le processus exact est décrit dans le RFC 5321, section 5.1.) A priori, si on ne veut pas recevoir de courrier, il suffit de ne pas mettre d'enregistrement MX, non ? Malheureusement, ce n'est pas le cas : le RFC 5321 précise que, s'il n'y aucun MX, on essaie alors les adresses IP associées au nom (règle dite du « MX implicite »).

Or, il existe des domaines qui ne reçoivent pas de courrier, parce qu'ils sont seulement réservés sans intention d'être utilisés, ou bien parce qu'ils ne servent que pour le Web ou bien encore pour toute autre raison. Si un message tente de parvenir à ces domaines, la machine émettrice va perdre du temps à essayer des MX délibérement invalides (avant la norme de notre RFC 7505, des gens mettaient un MX pointant vers localhost) ou bien des adresses où aucun serveur SMTP n'écoute. Ce n'est pas joli. Et cela peut prendre du temps (lorsque la délivrance échoue, l'émetteur met en attente et réessaie) donc l'utilisateur qui s'est trompé de domaine ne sera prévenu que plusieurs jours plus tard, lorsque le serveur émetteur renoncera enfin.

Au contraire, avec le nouveau « MX nul », dit officiellement No Service MX, le rejet sera immédiat et l'utilisateur, notifié tout de suite, pourra corriger son erreur.

La syntaxe exacte du MX nul figure en section 3. On utilise l'enregistrement MX (RFC 1035, section 3.3.9), avec une partie droite comprenant une préférence égale à zéro et un nom de domaine (exchange, dans la terminologie du RFC 1035) vide (de longueur nulle), ce qui se note, en représentation texte, par un simple point. Voici un exemple :

% dig +short MX  internautique.fr 
0 .

Ce nom ne pouvait pas être un nom de machine légal, il n'y a pas de risque de confusion avec les MX actuels. (Les enregistrements SRV du RFC 2782 utilisent le même truc pour dire qu'il n'y a pas de service disponible à ce nom : « A Target of "." means that the service is decidedly not available at this domain. ».)

La section 4 liste les effets de l'utilisation du MX nul. Comme indiqué plus haut, il permet une réponse immédiate à l'utilisateur, lorsque celui-ci s'est trompé d'adresse (bob@example.net alors qu'il voulait écrire à bob@example.com). L'erreur SMTP à utiliser dans ce cas est 556 (Server does not accept mail, RFC 7504) avec comme code amélioré (codes définis dans le RFC 3643) le nouveau 5.1.10 Domain has null MX.

Le MX nul sert aussi si, par erreur ou par usurpation, un serveur tente d'envoyer du courrier avec une adresse d'émission qui est un domaine à MX nul : le récepteur peut rejeter tout de suite ce message, pour la raison qu'il ne pourrait de toute façon pas lui répondre (ou pas lui envoyer de DSN). C'est ainsi que procèdent beaucoup de serveurs de messagerie avec les adresse d'émission dont le domaine n'existe pas. Dans ce cas, les codes d'erreurs à utiliser sont 550 (mailbox unavailable) avec le code étendu 5.7.27 (Sender address has null MX). (Les nouveaux codes sont dans le registre IANA.) Par exemple, Postfix signale, pour le domaine example.com, une erreur 5.1.0 et le message « <foobar@example.com>: Domain example.com does not accept mail (nullMX) ».

Notez enfin que ce RFC concerne le cas où on ne reçoit pas de courrier. Si on veut dire qu'on n'en envoie pas, le plus simple est un enregistrement SPF -all.

Tous les hébergeurs DNS ne permettent pas encore de mettre un MX nul. Par exemple, l'un d'eux m'envoie promener « La valeur et/ou la priorité MX est incorrecte ».


Téléchargez le RFC 7505


L'article seul

RFC 7504: SMTP 521 and 556 Reply Codes

Date de publication du RFC : Juin 2015
Auteur(s) du RFC : J. Klensin
Chemin des normes
Première rédaction de cet article le 1 juillet 2015


Ce RFC enregistre officiellement deux nouveaux codes de retour SMTP (qui étaient déjà largement utilisés), 521 (« I do not accept mail ») et 556 (« The remote domain does not accept mail »). Tous les deux sont prévus pour le cas où un serveur ou un domaine n'acceptent jamais de courrier, en aucune circonstance (par opposition aux codes de rejet plus généraux comme 554).

Petit rappel au passage : les codes de retour SMTP, spécifiés dans la section 4.2 du RFC 5321, ont un premier chiffre qui indique notamment si l'erreur est temporaire (si le premier chiffre est un 4) ou permanente (si le premier chiffre est un 5). Dans le second cas, pas la peine de réessayer plus tard. Ici, le 521 dit bien « ne t'embête pas à revenir, demain, ce sera comme aujourd'hui, je n'accepterai jamais ton message »).

SMTP avait été prévu au début dans un monde où tout le monde acceptait du courrier. Dans les années 1980, toute station de travail Unix venait avec un sendmail activé qui pouvait recevoir des messages. Le paysage aujourd'hui est très différent (section 2 de notre RFC) avec un grand nombre de machines qui ne reçoivent pas de courrier. De même, certains domaines ne sont pas utilisés pour le courrier et il serait pratique de pouvoir indiquer cela à l'avance (RFC 7505).

Dans le premier cas (machine qui ne veut pas recevoir de courrier), le plus simple semble être de ne pas avoir de serveur SMTP du tout. Mais l'impossibilité de se connecter (réponse TCP RST, ou bien timeout, si le pare-feu jette les requêtes TCP) va être interprétée par le client SMTP comme temporaire, et celui-ci va alors réessayer pendant des jours. Si, par la suite d'une erreur de configuration, un client SMTP tente de se connecter à une machine sans serveur, il faudra donc attendre avant de détecter le problème. Avoir un simple serveur SMTP qui ne fait rien d'autre que dire tout de suite « arrête d'insister, ça ne sert à rien » pourrait être plus efficace.

Pour le second cas, le domaine qui n'a pas du tout de service de courrier, le RFC 7505 fournit un moyen simple de l'indiquer dans le DNS, avec le « MX nul ». Il ne manquait qu'un code de retour adapté, pour que le premier relais SMTP de l'utilisateur puisse dire « je ne peux pas envoyer de courrier à ce domaine, ils ne veulent pas ».

Le code 521 est décrit dans la section 3 du RFC. Il est renvoyé au début de la connexion puisqu'il décrit un refus général (pas d'exceptions). Si le refus du courrier est dû à certaines caractéristiques du courrier (par exemple l'emploi de tel émetteur), il ne faut pas utiliser 521 mais plutôt 554. Voici à quoi pourrait ressembler l'accueil d'un serveur SMTP simple, qui ne fait que rejeter imédiatement :

% telnet mail.example.net smtp
Trying 2001:db8:666::1...
Connected to mail.example.net.
Escape character is '^]'.
521 I hate everybody, do not come back
[Connexion fermée]

Le serveur peut clore la connexion immédiatement, ou bien la laisser ouverte et renvoyer des 521 systématiquement. Un message moins pittoresque pourrait être « Server does not accept mail ».

À noter que le code 521 avait déjà été décrit dans le RFC 1846 mais pas normalisé.

La section 4 décrit l'autre code, 556. Le premier code était prévu pour un serveur qui refusait le courrier, le second pour un relais qui essaie d'envoyer au serveur suivant mais découvre que le domaine de destination n'a pas l'intention d'accepter du courrier. Cette découverte se fait typiquement en voyant le « MX nul » du domaine en question (RFC 7505). En faisant une requête MX pour connaître le serveur suivant, le relais peut découvrir que le domaine n'accepte pas de courrier, et il renvoie alors un 556 à son client.

Les deux codes sont désormais enregistrés à l'IANA.


Téléchargez le RFC 7504


L'article seul

RFC 7503: OSPFv3 Auto-Configuration

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : A. Lindem (Cisco Systems), J. Arkko (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ospf
Première rédaction de cet article le 10 avril 2015


Le protocole de routage OSPF est traditionnellement configuré statiquement, et à la main par l'administrateur réseaux. Certains réseaux, comme par exemple des réseaux un peu complexes à la maison, ont besoin d'un protocole de routage, mais sans avoir d'administrateur réseaux disponible. Il faudrait un OSPF qui se configure tout seul, « plug and play ». Ce court RFC montre que c'est possible, avec très peu de modifications des mises en œuvre d'OSPF.

Ce RFC concerne OSPF v3, normalisé dans le RFC 5340. Les changements du protocole par rapport à cette norme sont minimes. Par exemple, deux routeurs OSPF sont désormais autorisés à devenir adjacents (à établir une sorte de session entre eux), même si leurs valeurs des paramètres annoncés dans le paquet Hello, comme HelloInterval, diffèrent (dans un réseau auto-configuré, on ne peut pas espérer que tous les routeurs aient la même valeur, malgré ce que demandait l'annexe A.3.2 du RFC 5340). Autre exemple, une hystérésis a été ajouté lors de l'envoi de certains LSA (Link State Advertisement, les messages d'OSPF). Un routeur ayant les modifications permettant l'auto-configuration peut participer à un réseau avec des routeurs n'ayant pas ces modifications (l'inverse n'est pas vrai : un routeur OSPF classique aura du mal à s'insérer dans un réseau auto-configuré). Ces changements sont nécessaires pour s'adapter aux réseaux qui, tout en étant non-gérés, sont composés de plusieurs liens et plusieurs routeurs, commme ceux envisagés par le projet Homenet (RFC 7368).

La section 2 de notre RFC liste les paramètres que doivent adopter les routeurs auto-configurés :

  • La zone (area) doit être 0.
  • OSPF doit être activé sur toutes les interfaces IPv6 du routeur, sauf si on est sûr d'avoir une très bonne raison de ne pas le faire. Par exemple, pour un routeur CPE, genre box, le RFC 7084 demande évidemment qu'on ne fasse pas tourner de protocole de routage dynamique sur l'interface qui mène au FAI.
  • Le type de réseau OSPF (broadcast network ou point-à-point) doit être configuré en fonction du type de réseau physique (Ethernet et Wi-Fi seront tous les deux broadcast network, cf. RFC 2328, section 1.2).
  • Chaque routeur a le choix de paramètres comme HelloInterval (voir la section 3 du RFC pour les détails).
  • Le choix de l'Instance ID (RFC 5838) doit être 0 pour IPv6 et 64 pour IPv4.

A priori, les réseaux auto-configurés n'auront aucune forme d'authentification, celle-ci nécessitant une certaine action de l'administrateur, par exemple entrer les mots de passe (section 4 de notre RFC). Si, toutefois, on veut authentifier, il est recommandé d'utiliser l'option du RFC 7166.

Dans OSPF, chaque routeur a un router ID (RFC 2328, section 1.2), qui fait 32 bits mais n'est pas une adresse IPv4. Il doit être unique dans la zone donc il faut que tous les routeurs auto-configurés se débrouillent pour ne pas prendre le même (autrefois, c'était une adresse IPv4, et celle du routeur - RFC 5340, annexe C.1, donc l'unicité était facilement garantie). Il faut donc désormais la générer aléatoirement, en utilisant comme graine du générateur aléatoire une information unique, comme le router hardware fingerprint décrit en section 7.2.2.

Même dans ce cas, des collisions de router ID sont possibles. Il faut donc une procédure de détection des duplicatas (section 7) qui consiste, pour les voisins immédiats, à se rendre compte qu'un LSA porte le même router ID que vous, avec une adresse IPv6 différente. Il faudra alors changer : c'est le routeur avec la plus petite adresse IP qui doit changer son router ID. Cette procédure de détection et de correction a été le plus gros sujet de discussion au sein du groupe de travail à l'IETF.

Pour les routeurs non-voisins, on utilise un nouveau TLV placé dans le LSA d'auto-configuration, Router-Hardware-Fingerprint, déjà mentionné au paragraphe précédent (au passage, ce nouveau LSA, prévu pour l'auto-configuration, est le numéro 15 et les valeurs qu'il contient font l'objet d'un nouveau registre). Sa valeur est un nombre qui a de très fortes chances d'être unique. Il est recommandé de le fabriquer en concaténant des valeurs probablement uniques, mais stables, comme l'adresse MAC, et numéro de série du routeur.

Comme vu plus haut au sujet de l'authentification, la sécurité ne s'entend pas bien avec l'auto-configuration (section 8 du RFC). L'auto-configuration fait que n'importe quelle nouvelle machine va être « adoptée » par le réseau et pourra y participer immédiatement. Une aubaine pour un attaquant. Si on n'est pas prêt à accepter cela, il faut recourir aux mécanismes d'authentification décrits dans la section 4 (RFC 7166 ou RFC 4552).

Tout le monde n'a pas forcément envie d'utiliser l'auto-configuration, surtout étant donné ses conséquences en termes de sécurité. Il faut donc un moyen de débrayer cette possibilité (section 9 de notre RFC). (Bien sûr, il faut aussi des moyens de configurer des paramètres comme le HelloInterval ou comme le mot de passe, si on veut faire de l'auto-configuration mais en choisissant certains paramètres.)

Voilà, il ne reste plus qu'à déployer ces nouveaux réseaux : d'après les auteurs, il y a déjà deux ou trois mises en œuvre d'OSPF qui incorporent les règles de ce RFC.


Téléchargez le RFC 7503


L'article seul

RFC 7500: Principles for Operation of Internet Assigned Numbers Authority (IANA) Registries

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : R. Housley (Vigil Security), O. Kolkman (Internet Society)
Pour information
Première rédaction de cet article le 14 avril 2015


Traditionnellement, le fonctionnement de la normalisation dans l'Internet sépare deux fonctions : l'IETF développe les normes techniques (qui sont publiées dans les RFC, documents immuables) et l'IANA gère les nombreux registres qui stockent les paramètres des protocoles de l'IETF. Au contraire des RFC, ces registres changent tout le temps. Ce nouveau RFC décrit les principes de haut niveau sur lesquels repose le fonctionnement de l'IANA. (Il a depuis été remplacé par le RFC 8720.)

Pendant longtemps, la gestion des registres et la publication des RFC étaient assurés par le même homme, Jon Postel à l'ISI. Aujourd'hui, les deux opérations sont complètement séparées, https://www.iana.org/ et https://www.rfc-editor.org/.

Ces registres sont cruciaux pour le bon fonctionnement de l'Internet. Presque tous les protocoles Internet dépendent d'un ou de plusieurs registres. Aujourd'hui, il existe plus de 2 000 registres à l'IANA (la liste complète est en https://www.iana.org/protocols). Les valeurs stockées peuvent être des nombres, des chaînes de caractères, des adresses, etc. Leur allocation peut être centralisée (tout est à l'IANA) ou décentralisée, avec l'IANA déléguant à des registres qui à leur tour délèguent, comme c'est le cas pour les noms de domaine et pour les adresses IP.

L'IANA n'a pas de pouvoirs de police : le respect des registres IANA dépend uniquement de la bonne volonté générale. Évidemment, la pression est forte pour respecter ces registres, puisque le bon fonctionnement de l'Internet en dépend. Ce RFC présente les principes sur lesquels ces registres reposent (sections 2 et 3 du RFC) :

  • Unicité des identificateurs. C'est l'un des principaux buts des registres, s'assurer que qu'il n'y a qu'un seul .fr ou .org, ou que l'algorithme 13 de DNSSEC désigne bien ECDSA pour tout le monde.
  • Stabilité. Les registres doivent tenir plus longtemps que la page Web corporate moyenne. Leur contenu existant ne doit pas changer sauf s'il y a une très bonne raison.
  • Prédictabilité. Le processus d'enregistrement doit être prévisible et ne pas comporter de soudaines surprises (« finalement, il faut tel papier en plus »). Parfois, un jugement humain est nécessaire donc le processus n'a pas à être algorithmique, ni à être limité dans le temps, mais il ne doit pas soudainement ajouter des étapes non prévues.
  • Publicité. Les registres doivent être publics (en pratique, le principal mode de distribution est via le Web). Ce n'est pas si évident que cela, les dinosaures attardés de la normalisation, comme l'AFNOR, l'ISO ou l'IEEE ne le font pas.
  • Ouverture. Le processus qui détermine les politiques d'enregistrement doit être ouvert à tous ceux qui désirent participer. Dans presque tous les cas, c'est l'IETF qui détermine cette politique (les exceptions sont importantes comme la gestion de la racine des noms de domaine), via un RFC développé en effet dans un processus ouvert. Le RFC 5226 détaille les politiques IANA possibles. (Parmi elles, certaines nécessitent un examen par un expert, le jugement humain mentionné plus haut.)
  • Transparence. La gestion des registres ne doit pas être opaque. On peut écrire à l'IANA, ou bien passer les voir Away From Keyboard pendant les réunions IETF, où l'IANA a toujours un stand.
  • Redevabilité. L'IANA doit rendre compte de sa gestion. Selon le RFC 6220, la supervision de la fonction IANA incombe à l'IAB (RFC 2850). En outre, l'IAOC (RFC 4071) a un SLA avec l'actuel opérateur de la fonction IANA, l'ICANN. L'IAB et l'IAOC sont eux-même redevables devant une communauté plus large, via le processus NomCom (RFC 3777). Pour les adresses IP et les ressources associées, le RFC 7249 fait gérer la redevabilité par les RIR (RFC 7020). Ceux-ci sont des organisations ouvertes et eux-même redevables devant leurs membres. (Avez-vous noté quel registre n'était pas mentionné comme bon exemple par le RFC ?)

Téléchargez le RFC 7500


L'article seul

RFC 7498: Service Function Chaining Problem Statement

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : P. Quinn (Cisco Systems), T. Nadeau (Brocade)
Pour information
Réalisé dans le cadre du groupe de travail IETF sfc
Première rédaction de cet article le 15 avril 2015


Le projet SFC à l'IETF, dont voici le premier RFC, vise à mettre de l'ordre dans les innombrables traitements que suivent les flux IP dans l'Internet. Pare-feux, répartiteurs de charge, dispositifs de censure et d'espionnage, et leurs copains veulent tous appliquer des traitements aux communications et, actuellement, il n'existe pas de cadre unificateur pour ordonnancer proprement ces traitements, encore moins de normes techniques. Ce premier RFC expose le problème qu'on tente de résoudre.

Certains des traitements souhaités sont plutôt dans la couche 3, d'autres peuvent concerner les applications. La liste des traitements potentiellement effectués est très vaste, elle comprend les services de surveillance utilisant la DPI (comme les boîtes noires de Cazeneuve), le NAT, les caches, les divers optimiseurs (TCP, TLS) qui assurent certaines fonctions à la place de la machine terminale, etc. Le RFC n'en parle pas mais des fonctions de censure comme les mensonges DNS du réseau chinois rentrent également dans cette liste.

Certains traitements peuvent concerner une seule machine et d'autres la totalité des communications. Actuellement, ces traitements sont très couplés à la topologie du réseau. Par exemple, pour filtrer le trafic indésirable, on met un pare-feu en coupure du réseau, forçant tout le trafic à passer par le pare-feu. Si on veut effectuer un autre traitement, il faut mettre une seconde machine. Le tout devient vite très rigide, difficile à changer, et difficile à analyser dans ses effets combinés. C'est surtout dommage dans les environnements « à la demande » où on crée et détruit très vite des machines virtuelles et même des réseaux entiers.

Le terme de SFC (Service Function Chain) a été créé pour désigner une nouvelle façon de concevoir ces services : on définit des fonctions abstraites (comme celle de pare-feu) et on a une liste ordonnée de telles fonctions, que le réseau peut appliquer, indépendamment de sa topologie. Le concept est développé plus longuement en section 3 du RFC.

Mais, d'abord, en section 2, l'exposé plus détaillé du problème. Cette section est le gros morceau de ce RFC. On l'a vu brièvement plus haut, aujourd'hui, pour assurer une fonction sur les flux réseau, il faut une topologie particulière. Par exemple, le pare-feu doit être sur le chemin et avoir deux « pattes », introduire un pare-feu là où il n'y en avait pas nécessite donc souvent de ré-architecturer son réseau, ajoutant des sous-réseaux IP qui n'étaient pas nécessaires. Ça manque sérieusement de souplesse. Idéalement, on voudrait que le réseau soit architecturé uniquement autour de la délivrance des paquets, et que les services en plus soient déployables en appuyant sur un bouton, sans refaire le réseau à chaque nouveau service.

Un autre exemple de rigidité concerne les répartiteurs de charge, si communs devant les serveurs Web. Il faut souvent configurer le répartiteur comme étant le routeur par défaut des serveurs HTTP, si bien que même le trafic non-Web (par exemple les communications de gestion en SNMP ou SSH) passe par le répartiteur, sans nécessité.

Autre conséquence de cette dépendance vis-à-vis de la topologie, cela rend difficile le changement du service de transport sous-jacent. Si on passe de MPLS à GRE, on risque de devoir changer pas mal de services, alors que, a priori, ils étaient indépendants des couches basses.

Tout cela fait que les réseaux sont plus complexes qu'ils ne le devraient. Changer un paramètre aussi simple que l'ordre dans lequel sont appliqués des services (filtrer d'abord, puis répartir le trafic après, ou bien le contraire) nécessite de changer la topologie. Résultat, les réseaux tendent à rester plutôt statiques, et à ne pas profiter à fond de la souplesse que permettrait la virtualisation (section 2.7). Et assurer la haute disponibilité devient très compliqué, puisque les services de secours doivent conserver la même topologie que le service principal (afin de recevoir les mêmes traitements).

Un autre problème lié au couplage trop fort entre les services et la topologie du réseau est celui de la sélection du trafic (section 2.8). Souvent, on ne veut appliquer les services qu'à une partie du trafic. Or, dans les architectures actuelles, cela va souvent obliger à faire passer tout le trafic par la machine qui met en œuvre le service. Ou, sinon, à mettre en œuvre des mécanismes de redirection peu pratiques. Prenons un exemple : on veut censurer certaines pages de Wikipédia mais pas toutes. Faire passer la totalité du trafic par le système de DPI qui déterminera quelles pages sont demandées serait lent, nécessiterait de grosses machines pouvant faire de la DPI à ce rythme et pourrait être considéré comme abusif par rapport au but à atteindre. Actuellement, les censeurs déploient donc souvent des architectures mixtes (proxy HTTP transparent, puis redirection du trafic des serveurs Wikipédia - et de seulement ceux-ci - vers le système de DPI, qui n'aura donc à traiter qu'une partie du trafic). C'est quand même peu élégant, et il serait donc souhaitable de découpler sélection du trafic et application du service.

Et, bien sûr, dans l'état actuel des choses, comme il n'y a aucun standardisation des services réseaux et de la manière dont ils s'insèrent, faire coexister des services réseau de plusieurs vendeurs différents est très difficile. Une standardisation, même partielle, simplifierait la vie des administrateurs réseau (le but de ce RFC n'est pas de réaliser cette standardisation, ce qui serait très prématuré, mais d'explorer le problème).

La section 3 de notre RFC, elle, décrit de manière positive ce qu'on attend du service chaining, de la composition des services. Pour découpler le service de la topologie, il faudra un overlay par service. Changer la liste, ou l'ordre de la liste des services appliqués, ne nécessitera donc que de changer la connexion entre ces overlays.

Le mécanisme devra fournir un moyen de classer le trafic, en fonction de critères de sélection. En pratique, les possibilités exactes du système de classification dépendront du matériel et logiciel sous-jacents, et la classification sera donc plus ou moins grossière.

Souvent, les services réseau n'ont besoin que des métadonnées pour agir, et il n'est donc pas forcément nécessaire d'envoyer aux services la totalité des flux.

Voilà, c'est très vague, comme description, je sais, mais c'est l'état actuel de la réflexion sur la composition de services (et cette section 3 a déjà suscité beaucoup de discussion dans le groupe de travail). D'autres RFC sont en préparation, plus concrets, comme le document d'architecture de SFC, le RFC 7665.

Un tel système de composition de services soulève évidemment d'amusantes questions de sécurité (section 4). Certaines sont traitées par des protocoles existants (par exemple la création et la maintenance des overlays, qui n'est pas un problème nouveau).

Le RFC note que certains services peuvent nécessiter des connaissances détaillées sur les données transmises, et que des techniques comme le chiffrement peuvent donc limiter ces services. En pratique, on aura moins d'informations, mais on pourra souvent se débrouiller avec. (Il reste des métadonnées non chiffrées.) D'ailleurs, à propos de chifffrement, le RFC note qu'il faudra aussi protéger le trafic SFC : les machines qui effectuent un certain service peuvent être loin de celles qui se « contentent » de faire passer les paquets et il ne faudrait pas que le trafic entre les deux soit espionné ou, pire, modifié, par un tiers (la protection est parfois assurée par le protocole d'overlay). C'est particulièrement important dans un contexte multi-clients (un grand réseau partagé par de nombreux utilisateurs).

À noter qu'Ericsson prétend avoir un brevet même sur la simple description du problème !


Téléchargez le RFC 7498


L'article seul

RFC 7497: Rate Measurement Test Protocol Problem Statement and Requirements

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : A. Morton (AT&T Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 13 avril 2015


La capacité d'un accès Internet est un critère de choix important pour l'utilisateur et c'est même en général le seul qui est mis en avant dans la publicité (« choisissez la fibre qui fonce à 100 Mb/s »). Peut-on la mesurer sérieusement et objectivement ? Ce RFC explore la question, sans donner encore de réponse définitive.

La capacité est définie dans le RFC 5136. Notre nouveau RFC parle de rate et pas de capacity mais la différence est subtile (je vous laisse la découvrir dans le RFC si vous êtes intéressé). En revanche, il faut se méfier de termes flous et souvent utilisés de manière erronée comme « bande passante » ou « débit ». Ce qui intéresse M. Michu (ou, plus exactement, sa fille qui veut télécharger les quatre premiers épisodes de la saison 5 le plus vite possible), c'est bien la capacité de son accès Internet (cf. RFC 6703). Comme c'est un argument commercial essentiel, bien des gens souhaiteraient la mesurer, qu'ils soient simples citoyens, associations de défense des consommateurs ou bien régulateurs des télécoms. C'est ainsi que l'ARCEP a un tel programme de mesure et que l'Union européenne en a lancé un à travers les sondes SamKnows, qui a donné lieu à un excellent rapport, montrant bien les différences entre les proclamations commerciales et la réalité.

Le groupe de travail IPPM de l'IETF travaille depuis longtemps à normaliser les mesures de performance (qui sont souvent floues et approximatives, permettant ainsi toutes les manipulations). Avec la normalisation de la mesure, on pourrait envisager des comparaisons sérieuses entre les offres des FAI. Ce RFC 7497 ne propose pas encore une telle normalisation mais essaie simplement de décrire rapidement le problème. Il se focalise sur l'accès à l'Internet, pas sur les mesures au sein du cœur du réseau (où les capacités sont beaucoup plus élevées). La plupart du temps, le goulet d'étranglement du chemin suivi par les paquets IP sera le lien entre l'utilisateur et le FAI. Ce choix de mesurer l'accès à l'Internet met quelques limites à l'efficacité de la mesure (dans le cœur, on peut utiliser des engins de mesure perfectionnés et coûteux ; chez l'utilisateur, on devra souvent se contenter de dispositifs moins sophistiqués, par exemple ayant une horloge moins précise). Combien de bits/seconde va pouvoir faire passer M. Michu ? Notez que tout dépend d'où on part. De la box ? D'un PC connecté en Wi-Fi ? Le RFC 7398 mettait déjà en avant l'importance de décrire le chemin emprunté par la mesure (le réseau Wi-Fi de M. Michu peut être très chargé, donnant l'impression d'une capacité plus faible qu'elle ne l'est réellement). Autre piège, les FAI imposent souvent aux abonnés des capacités asymétriques : la capacité descendante (dans la terminologie des FAI, qui se voient au-dessus des utilisateurs) est supérieure à la capacité montante.

Une des nombreuses difficultés de la mesure est que les paquets peuvent être traités différemment selon leurs caractéristiques (RFC 2330, section 13) : paquets longs vs. paquets courts, TCP vs. UDP, différence selon le port de destination, etc. Idéalement, le trafic de test, que l'on injectera pour mesurer combien de bits/seconde passeront, devra être une imitation aussi proche que possible du trafic réel de M. Michu. Ce n'est qu'un des très nombreux pièges qui se présentent lorsqu'on veut faire des mesures sur l'Internet. Au moment de la sortie du rapport ARCEP, on avait ainsi vu pas mal de gens peu informés et n'ayant manifestement jamais réfléchi à la question s'exprimer très fort sur divers forums. Ils affirmaient bien haut leurs certitudes (« LOL mais non, c'est idiot, il ne faut pas faire comme cela ») sans que rien n'indique qu'ils avaient compris la complexité du problème.

Dernier piège cité en section 2 de notre RFC, le moment où faire les mesures actives qui sont indispensables à la détermination de la capacité. Si on les fait aux moments pré-définis, on aura des résultats différents selon qu'à ces moment l'utilisateur télécharge en HD ou pas. Il serait préférable d'attendre un moment calme. Mais cela soulève d'intéressants problèmes de protection de la vie privée (par exemple, la documentation de la SamKnows précise qu'il faut l'installer en coupure, de manière à ce qu'elle puisse voir passer tout le trafic).

La section 3 du RFC décrit plus précisément ces mesures actives. Il faut évidemment un protocole de contrôle permettant la coordination entre la sonde de mesure et l'amer (genre RFC 5357 et RFC 4656). Il faut d'autre part que le trafic généré pour le test soit réduit à ce qui est strictement nécessaire pour mesurer la capacité (l'un des problèmes essentiels des mesures actives est qu'elles perturbent le réseau, cf. section 5 du RFC 7680 et section 4 du RFC 3148, et les sections 6 et 7 de notre RFC, qui insistent sur l'importance du consentement). Comme le lien d'accès typique a des capacités asymétriques, l'idéal serait de pouvoir faire des mesures dans une seule direction. Mais c'est en général irréaliste (il faut des équipements de mesure bien synchronisés, notamment du point de vue temporel, et qui soient des boîtes spécialisées, sachant faire ce que ne peut pas faire une machine Unix ordinaire). Donc, la plupart des mesures seront une mesure de l'aller-retour, dont il faudra extraire ensuite les capacités dans chaque direction.

Au bout du compte, ces mesures actives nécessiteront trois composants :

  • L'émetteur, qui est capable d'envoyer des paquets ayant les caractéristiques souhaitées,
  • Le receveur,
  • Et le rapporteur, qui mesure et envoie les résultats dans le format demandé.

Parmi les caractéristiques demandées pour les paquets (section 4), il faut pouvoir choisir la longueur, le contenu (certains équipements réseaux, par exemple ceux qui effectuent de la compression, donnent des résultats différents selon le contenu), les différents champs de l'en-tête IP (comme ceux du RFC 2474), le protocole (TCP ou UDP), les ports, etc. Ces paquets doivent pouvoir être transmis à un rythme choisi. Bien que le RFC passe très rapidement sur ce point, il faut aussi pouvoir, si on utilise TCP, contrôler l'algorithme d'évitement de la congestion.


Téléchargez le RFC 7497


L'article seul

RFC 7493: The I-JSON Message Format

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : T. Bray (Textuality Services)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF json
Première rédaction de cet article le 1 avril 2015


Le format JSON, normalisé dans le RFC 8259, est aujourd'hui très répandu dans l'Internet et largement utilisé. Il a pourtant des faiblesses, notamment une définition un peu floue sur certains points, qui laisse planer un doute sur l'interopérabilité : si j'envoie dans le fichier un objet JSON où deux membres portent le même nom, le destinataire pourra-t-il le traiter ? Ce nouveau RFC résout le problème en créant un profil, une restriction de JSON, nommée I-JSON, qui n'a pas ces flous et garantit donc normalement l'interopérabilité.

On peut penser qu'il aurait mieux valu préciser la norme JSON (aujourd'hui dans le RFC 8259) pour éliminer les ambiguités. Mais cela n'est pas possible sans casser la compatibilité. Si, par exemple, on interdisait dans la norme les objets dont deux membres ont le même nom, on rendrait illégaux des textes JSON existants, qui profitaient du flou de la norme. Cela a été jugé inacceptable, d'où ce choix d'un profil de JSON. Ceux qui veulent continuer à profiter du vague de la norme restent au JSON traditionnel, ceux qui veulent le maximum d'interopérabilité envoient désormais uniquement du I-JSON (ce qui veut dire « Internet JSON » et qui, curieusement, n'a pas de type MIME à lui, on continue à utiliser application/json). Ne pas casser l'existant était d'autant plus nécessaire que bien des analyseurs JSON mettent directement en correspondance les objets JSON avec des structures de données équivalentes dans leur langage de programmation, et qu'il ne fallait donc pas leur imposer une vérification préalable.

Donc, définition du format (section 2). Un texte I-JSON est un texte JSON, puisque I-JSON est un profil, un sous-ensemble de JSON. Il est forcément encodé en UTF-8 et ne doit pas utiliser les surrogates (seizets d'indirection) d'Unicode, ni des points de code qui sont des non-caractères.

Il y a deux grands problèmes d'interopérabilité avec JSON : la représentation des nombres (voir la section 6 du RFC 8259), et les noms de membres dupliqués dans les objets (cf. la section 4 du RFC 8259). La section 2.2 traite les nombres : un texte I-JSON ne devrait pas (sauf raison vitale) utiliser des nombres flottants qui ne sont pas représentables en IEEE 754-2008 binary64, soit en raison de leur taille (1E400...), soit à cause de leur précision (3.141592653589793238462643383279). Pour les entiers, il ne faut pas espérer que les nombres en dehors de l'intervalle [ -(2**53)+1 , (2**53)-1 ] soient acceptés.

Pour les noms de membres, la section 2.3 est claire : les noms dupliqués sont interdits. Donc, cet objet est du JSON légal, quoique dangereux, alors qu'il n'est pas du I-JSON, en raison du Title dupliqué :

"Image": {
            "Width":  800,
            "Height": 600,
            "Title": "View from 15th Floor",
            "Title": "Nice view"
}

D'autre part, I-JSON dit clairement que l'ordre des membres d'un objet ne compte pas. Ces deux objets sont identiques :

"Image": {
            "Width":  800,
            "Height": 600}

"Image": {
            "Height": 600, 
            "Width":  800}

La section 3 de notre RFC précise bien qu'une mise en œuvre de I-JSON est tout à fait autorisée à rejeter ou ignorer un texte JSON qui n'est pas du bel I-JSON bien propre. Les protocoles Internet qui utilisent I-JSON sont invités à prévoir un moyen de signaler ce genre d'erreurs à l'envoyeur.

La section 4 du RFC couvre quelques choix supplémentaires. D'abord, comme dans l'ancien RFC 4627, et de manière différente de ce que permet le RFC 8259, un texte I-JSON doit avoir un objet ou un tableau au niveau supérieur. Ce texte est du JSON valable (depuis le RFC 7159) mais pas du I-JSON :

"Ma belle chaîne n'est pas acceptée car elle n'est pas objet ou tableau"

Il est recommandé que les protocoles qui utilisent I-JSON précisent que le type de plus haut niveau d'un texte soit un objet et que les membres inconnus de cet objet soient ignorés. Il existe en effet deux politiques dans les protocoles pour traiter les éléments inconnus : Must-Ignore et Must-Understand. La première indique que le receveur d'un message doit en ignorer les membres qu'il ne connait pas et continuer comme s'ils étaient absents. La deuxième indique qu'il faut connaitre tous les membres présents, et donc rejeter un message comportant des membres inconnus. La politique Must-Ignore permet l'extensibilité du protocole : une nouvelle version permet d'ajouter des membres à un objet, sans craindre que les anciens récepteurs ne plantent.

I-JSON ajoute aussi des contraintes aux types de données de base. Ainsi, il impose que les dates et heures soient au format du RFC 3339, avec en outre uniquement des lettres en majuscules et des secondes indiquées explicitement :

"creation": "2015-03-23T09:13:00Z"

Et une dernière contrainte sur les données, le binaire devra être encodé en base64url (section 5 du RFC 4648). Ce point fut l'un des plus chaudement disputés dans le groupe de travail.

Je n'ai pas trouvé d'outil qui testerait qu'un texte JSON est conforme à cette nouvelle norme I-JSON. Si quelqu'un connait...

I-JSON est expliqué par l'auteur du RFC sur son blog.


Téléchargez le RFC 7493


L'article seul

RFC 7488: PCP Server Selection

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : M. Boucadair (France Telecom), R. Penno, D. Wing, P. Patil, T. Reddy (Cisco)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pcp
Première rédaction de cet article le 13 mars 2015


Le protocole PCP décrit un mécanisme (ayant vocation à remplacer UPnP) pour configurer automatiquement son routeur/pare-feu, notamment pour autoriser les connexions entrantes. Que doit faire un client PCP s'il reçoit plusieurs adresses IP de serveurs PCP ?

Dans quels cas a-t-on plusieurs serveurs PCP (donc, a priori, plusieurs routeurs à sa disposition) ? Un exemple typique est le multi-homing, si une machine est connectée en filaire et en radio en même temps, par exemple (l'annexe A du RFC décrit en détail un cas de multi-homing). Le RFC 6887, qui normalise PCP, en parlait un peu (dans sa section 8.1, qui explique en outre comment on trouve le ou les serveurs PCP, par exemple en suivant le RFC 7291), mais ne normalisait que le cas à un seul serveur, reportant à plus tard le cas à plusieurs serveurs. C'est donc désormais fait, deux ans après. Que doit donc faire le client qui a à sa disposition les adresses de plusieurs serveurs PCP ? D'autant plus que ceux-ci n'ont pas forcément les mêmes capacités, et ne sont typiquement pas coordonnés entre eux. Notez que les règles données dans ce nouveau RFC exigent que le client puisse déterminer si deux adresses IP pointent vers le même serveur PCP ou bien deux serveurs différents.

La section 3 décrit le cas où il y a plusieurs adresses mais un seul serveur : le client doit alors choisir l'adresse IP source de sa requête PCP, en suivant les règles habituelles (section 4 du RFC 6724) et les contraintes spécifiques à PCP du RFC 6887. Un exemple de ces contraintes est que, si on veut configurer une connexion existante, il faut utiliser comme adresse IP source celle utilisée par ladite connexion. Une fois ce choix fait, le client crée une liste d'adresses IP possibles pour le serveur (section 6 du RFC 6724) et les essaie successivement (rappelez-vous que PCP fonctionne sur UDP). Une fois qu'on en a trouvé une qui marche, on la mémorise pour les futures requêtes.

Si les différentes adresses IP obtenues concernent plusieurs serveurs PCP, c'est plus compliqué (section 4). Il faut alors que le client mémorise plusieurs serveurs et, si nécessaire, les synchronise lui-même (rappelez-vous que les différents serveurs PCP ne se coordonnent pas entre eux). Par exemple, si on veut configurer le pare-feu, c'est de la responsabilité du client d'envoyer la même configuration à tous les serveurs PCP. En revanche, si on veut configurer le NAT, le client ne s'adresse typiquement qu'à un seul serveur PCP, celui correspondant à l'adresse IP externe qu'on veut utiliser. (Il faut donc que le client PCP, lorsqu'il reçoit l'information sur l'existence d'un serveur PCP, se souvienne de l'interface et des adresses IP correspondantes.)

La section 5 fournit plusieurs exemples concrets de ces procédures. Par contre, aucune idée de combien d'implémentations de PCP suivent ce RFC (on ne peut pas dire que PCP soit largement déployé...)


Téléchargez le RFC 7488


L'article seul

RFC 7485: Inventory and Analysis of WHOIS Registration Objects

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : L. Zhou, N. Kong, S. Shen (CNNIC), S. Sheng (ICANN), A. Servin (LACNIC)
Pour information
Réalisé dans le cadre du groupe de travail IETF weirds
Première rédaction de cet article le 9 avril 2015


Dans le cadre de la mise au point du protocole RDAP d'accès aux informations sur des objets enregistrés, le groupe de travail à l'IETF s'était livré à une intéressante étude sur les objets enregistrés et accessibles via l'ancien protocole whois. Cette étude a servi à mieux définir ce qu'il fallait comme services dans RDAP, et à spécifier le format de sortie de RDAP, normalisé dans le RFC 7483. Elle a montré, sans surprises, une grande variabilité : si beaucoup d'éléments d'information sont communs à un grand nombre de registres, c'est souvent sous des noms différents. Cette variabilité est, selon les goûts, un des charmes ou un des principaux défauts des registres de l'Internet.

L'étude qui a servi de base à ce RFC date de 2012 (section 3 de notre RFC, pour la méthodologie). Les données ont été récoltées via whois mais aussi via les interfaces Web d'interrogation des registres (à la fois registres de noms de domaine et registres d'adresses IP). Pour les TLD, le nom nic.$TLD a été utilisé, 106 ccTLD ont permis de récupérer de l'information sur ce nom, ainsi que 18 gTLD. Parfois, l'information a été vérifiée en essayant d'autres noms que nic.$TLD. Les capacités des serveurs whois interrogés étaient très variées (cf. section 5.1). Par exemple, si tous permettent évidemment des requêtes au sujet d'un domaine donné, certains permettent aussi des requêtes pour un contact précis ou pour un BE particulier. Pour les registres d'adresses IP, les cinq RIR ont été interrogés.

La section 4 présente les résultats pour les RIR. On y voit déjà la variété des étiquettes qui fait la beauté de whois. Ainsi, le nom de l'organisation titulaire d'un préfixe IP est étiqueté organisation à AfriNIC, Owner à LACNIC et org-name au RIPE-NCC. La date d'enregistrement d'un contact est changed à AfriNIC, RegDate à ARIN et created à LACNIC. Un préfixe IP se nomme inetnum à l'APNIC ou au RIPE-NCC, mais NetRange ou CIDR à l'ARIN (selon qu'il est IPv4 ou IPv6 !) Voici un exemple à l'APNIC :

inetnum:        1.2.2.0 - 1.2.2.255
netname:        KNET
descr:          KNET Techonlogy (BeiJing) Co.,Ltd.
descr:          4,South 4th treet, Zhongguancun,Haidian District,Beijing
admin-c:        ZX2975-AP
tech-c:         WL1818-AP
country:        CN
mnt-by:         MAINT-CNNIC-AP
mnt-irt:        IRT-CNNIC-CN
mnt-routes:     MAINT-CNNIC-AP
status:         ALLOCATED PORTABLE
changed:        ipas@cnnic.cn 20150107  

Certains éléments ne sont pas présents dans tous les RIR et ceux qui le sont reçoivent, comme on vient de le voir, des noms différents.

Et pour les registres de noms de domaine ? C'est évidemment encore plus varié (au fait, les résultats bruts de la collecte faite pendant l'étude sont disponibles en ligne). Au total, 68 éléments différents ont été identifiés, sous 550 étiquettes distinctes. Les auteurs du RFC les ont classé en éléments publics et autres éléments. Les éléments publics sont ceux qui sont mentionnés dans le document ICANN, « gTLD Applicant Guidebook » de 2012, ou bien dans les RFC sur EPP, RFC 5730, RFC 5731, RFC 5732 ou RFC 5733 (un choix très contestable qui donne une sorte de privilège aux règles des TLD régulés par le gouvernement états-unien).

Parmi les exemples d'éléments publics, on peut trouver évidemment le nom de domaine (l'étiquette la plus fréquente étant domain name mais cinq autres ont été trouvées) suivi de la date de création (en général created mais vingt-trois autres étiquettes sont possible, la deuxième plus grande variété de vocabulaire). 95 % des registres ont donc un élément « nom de domaine » (on peut se demander comment font les 5 % restants...), 85 % une date de création, 77 % un statut du domaine, etc. Par contre, « dernier transfert », le moins fréquent, n'est présent que chez 3 % des registres.

On retrouve la même variété pour les titulaires et les contacts. Aucun élément n'est présent dans la majorité des registres (même pas l'adresse de courrier électronique). Ceux qui le sont ont des noms très variés. Ainsi, pour le contact technique, le téléphone dudit contact est décrit par pas moins de dix étiquettes différentes.

Le cas des serveurs de noms est plus compliqué car, contrairement aux contacts, le serveur de noms n'est pas forcément un objet de première classe dans le modèle de données du registre : il peut être un simple attribut du domaine. C'est pour cela que, dans le monde EPP, le RFC 5732 n'est pas mis en œuvre partout. Ainsi, alors que 92 % des registres indiquent les serveurs de noms dans les réponses (sous 63 étiquettes distinctes, un record, en partie dû à des mécanismes de nommage comme nameserver N avec N indiquant le rang du serveur), tous ne permettent pas des requêtes whois directes sur un serveur de noms.

Enfin, il y a les éléments « divers », ceux qui ne sont pas spécifiés dans les règles ICANN ou dans les RFC sur EPP et qui incluent, par exemple, l'URL d'un site Web associé au domaine, un champ de commentaires (remarks), une date d'anniversaire (six TLD sont dans ce cas, probablement tous à l'AFNIC), un identificateur de marque déposée, etc. La section 6 de notre RFC suggère que des extensions au modèle de données de RDAP pourraient s'inspirer de ces éléments divers, par exemple le point de contact du NOC (pourquoi diable ne pas se contenter du contact technique ?), le fait que l'identité du titulaire soit masquée (ce qui est parfois noté, bien à tort, anonymous), etc.

Il n'y a pas que le modèle de données (et la terminologie associée) qui varie beaucoup d'un registre à l'autre, il y a aussi le format de présentation. Les deux les plus populaires sont clé:valeur et en bloc. Un exemple en clé:valeur est donné par .org :

Domain Name:TV5.ORG
Creation Date: 1995-09-29T04:00:00Z
Updated Date: 2013-09-30T14:24:25Z
Sponsoring Registrar:Gandi SAS (R42-LROR)
...
Registrant Name:Thomas Derobe
Registrant Organization:TV5 Monde
Registrant Street: 131 avenue de Wagram

Un exemple de bloc par le registre de .za :

    Domain Name:
        sab.co.za

    Registrant:
        The South African Breweries Limited
        
        Email: domains@sabmiller.com
        Tel: +27.118818414
        Fax: +27.118818136

    Registrant's Address:
        P.O.Box 782178
        2196 Sandton Sandown
        ZA

    Registrar:
        Ascio

    Relevant Dates:
        Registration Date: 1997-05-06
        Renewal Date:      2015-05-06

    Domain Status:
        Registered until renewal date

Mais il faut remarquer qu'on trouve de tout. Comment classer le résultat du whois de .jp ?

Domain Information:
a. [Domain Name]                YAMAHA.CO.JP
g. [Organization]               YAMAHA Corporation
l. [Organization Type]          Corporation
m. [Administrative Contact]     HN050JP
n. [Technical Contact]          TT9781JP
p. [Name Server]                ns1.dhs.jtidc.jp
p. [Name Server]                ns2.dhs.jtidc.jp
s. [Signing Key]                
[State]                         Connected (2016/03/31)
[Registered Date]                
[Connected Date]                2010/08/02
[Last Update]                   2015/04/01 01:12:19 (JST)

À noter également que onze registres envoient l'information autrement qu'en anglais dans l'alphabet latin (le RFC, comme beaucoup de documents écrits dans le milieu ICANN, confond langue et écriture et écrit « 11 registries give local script responses. The WHOIS information of other registries are all represented in English. »).

Bref, ce RFC illustre bien une des motivations principales du projet RDAP : normaliser la sortie du serveur, de façon à faciliter les traitements automatiques.


Téléchargez le RFC 7485


L'article seul

RFC 7484: Finding the Authoritative Registration Data (RDAP) Service

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : M. Blanchet (Viagenie)
Chemin des normes
Première rédaction de cet article le 1 avril 2015


Le nouveau protocole RDAP d'accès à l'information sur les objets (noms de domaines, adresses IP, etc) stockés dans un registre fonctionne en interrogeant le serveur en HTTP. Encore faut-il trouver le serveur. Comment le client RDAP qui veut des informations sur 2001:67c:288::2 sait-il à quel serveur demander ? Ce fut une des plus chaudes discussions au sein du groupe de travail IETF qui a mis au point RDAP. Ce RFC décrit le mécanisme choisi. En gros, l'IANA gère des « méta-services » qui donnent la liste de serveurs RDAP, mais il peut aussi y avoir redirection d'un serveur RDAP vers un autre. (Depuis, ce RFC a été remplacé par le RFC 9224, mais il y a peu de changements.)

Le protocole RDAP est décrit entre autres dans le RFC 7480 qui précise comment utiliser HTTP pour transporter les requêtes et réponses RDAP. Comme indiqué plus haut, il ne précise pas comment trouver le serveur RDAP responsable d'un objet donné. Avant d'exposer la solution utilisée, la section 1 de notre RFC rappelle comment ces objets (noms de domaine, adresses IP, numéros d'AS, etc) sont alloués et délégués. L'IANA délégue les TLD aux registres de noms de domaines, des grands préfixes IP et les blocs de numéros d'AS aux RIR. Il est donc logique que RDAP suive le même chemin : pour trouver le serveur responsable, on commence par demander à l'IANA, qui a déjà les processus pour cela, et maintient les registres correspondants (adresses IPv4, adresses IPv6, numéros d'AS et domaines).

Pour permettre à RDAP de fonctionner, ce RFC demande donc à l'IANA quelques fichiers supplémentaires, au format JSON (RFC 8259), dont le contenu dérive des registres cités plus haut. (À noter que c'est le premier registre IANA au format JSON.) Et l'IANA doit aussi prévoir des serveurs adaptés à servir ces fichiers, nommés RDAP Bootstrap Service, à de nombreux clients RDAP.

Le format de ces fichiers JSON est décrit dans la section 3 de notre RFC. Chaque bootstrap service contient des métadonnées comme un numéro de version et une date de publication, et il contient un membre nommé services qui indique les URL où aller chercher l'information (la syntaxe formelle figure en section 10). Actuellement, ces services sont encore vides :

 
% curl http://data.iana.org/rdap/ipv4.json
{
  "description": "RDAP bootstrap file for IPv4 address allocations",
  "publication": "2015-03-20T20:39:57Z",
  "services": [],
  "version": "1.0"
}

Mais dans le futur, ce sera un tableau donnant, pour des objets donnés, les URL des serveurs RDAP à contacter pour ces objets indiqués, par exemple :

 {
       "version": "1.0",
       "publication": "2024-01-07T10:11:12Z",
       "description": "RDAP Bootstrap file for example registries.",
       "services": [
         [
           ["1.0.0.0/8", "192.0.0.0/8"],
           [
             "https://rir1.example.com/myrdap/"
           ]
         ],
...

Le membre publication indique la date de parution au format du RFC 3339. Les URL indiqués se terminent par une barre oblique, le client RDAP a juste à leur ajouter une requête formulée selon la syntaxe du RFC 7482. Ainsi, cherchant des informations sur 192.0.2.24, on ajoutera ip/192.0.2.24 à l'URL de base ce qui, avec le bootstrap service précédent, donnerait https://rir1.example.com/myrdap/ip/192.0.2.24.

Pour les adresses IP (section 5), les entrées sont des préfixes, comme dans le premier exemple montré plus haut et la correspondance se fait avec le préfixe le plus spécifique (comme pour le routage IP). Les préfixes IPv4 suivent la syntaxe du RFC 4632 et les IPv6 celle du RFC 4291. Voici un exemple IPv6 :

       "services": [
         [
           ["2001:200::/23", "2001:db8::/32"],
           [
             "https://rir2.example.com/myrdap/"
           ]
         ],
         [
           ["2600::/16", "2100:ffff::/32"],
           [
             "http://example.org/"
           ]
         ],
         [
           ["2001:200:1000::/36"],
           [
             "https://example.net/rdaprir2/",
             "http://example.net/rdaprir2/"
           ]
          ]
       ]

Si on cherche de l'information sur le préfixe 2001:200:1000::/48, il correspond à deux entrées dans le tableau des services (2001:200::/23 et 2001:200:1000::/36) mais la règle du préfixe le plus long (le plus spécifique) fait qu'on va utiliser 2001:200:1000::/36, et la requête finale sera donc https://example.net/rdaprir2/ip/2001:200:1000::/48. (Si elle échoue, on peut passer au deuxième URL du tableau, celui sans HTTPS.)

Pour les domaines (section 4), les entrées des services sont des noms de domaine :

...
       "services": [
         [
           ["net", "com", "org"],
           [
             "https://registry.example.com/myrdap/"
           ]
         ],
         [
           ["foobar.org", "mytld"],
           [
             "http://example.org/"
           ]
         ],
...

L'entrée sélectionnée est la plus longue (en nombre de composants du nom, pas en nombre de caractères) qui correspond. Dans l'exemple ci-dessus, si on cherche des informations sur foobar.org, on ira voir le serveur RDAP en http://example.org/, si on en cherche sur toto.org, on ira en https://registry.example.com/myrdap/.

Pour les numéros d'AS (section 5.3), on se sert d'intervalles de numéros :

"services": [
         [
           ["2045-2045"],
           [
             "https://rir3.example.com/myrdap/"
           ]
         ],
         [
           ["10000-12000", "300000-400000"],
           [
             "http://example.org/"
           ]
         ],
...

Les entités (section 6 de notre RFC) posent un problème particulier, elles ne se situent pas dans un espace arborescent, contrairement aux autres objets utilisable avec RDAP. (Rappel : les entités sont les contacts, les titulaires, les BE...) Il n'existe donc pas de bootstrap service pour les entités (ni, d'ailleurs, pour les serveurs de noms, cf. section 9). En pratique, si une requête RDAP renvoie une réponse incluant un handle pour une entité, il n'est pas idiot d'envoyer les requêtes d'information sur cette entité au même serveur RDAP.

Notez (section 7) que le tableau services ne sera pas forcément complet et que certains objets peuvent ne pas s'y trouver. Par exemple, dans un tableau pour les TLD, les registres n'ayant pas encore de serveur RDAP ne seront logiquement pas cités. On peut toujours tenter un autre serveur, en espérant qu'il utilisera les redirections HTTP. Par exemple, ici, on demande au serveur RDAP de l'APNIC pour une adresse RIPE. On est bien redirigé avec un code 301 (RFC 7231, section 6.4.2) :


%  curl -v http://rdap.apnic.net/ip/2001:67c:288::2
...
> GET /ip/2001:67c:288::2 HTTP/1.1
> User-Agent: curl/7.38.0
> Host: rdap.apnic.net
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< Date: Wed, 01 Apr 2015 13:07:00 GMT
< Location: http://rdap.db.ripe.net/ip/2001:67c:288::2
< Content-Type: application/rdap+json
...

La section 8 couvre quelques détails liés au déploiement de ce service, qui a pris du temps et n'a été effectif que le 25 mars 2015, en pleine réunion IETF à Dallas. C'est que le Bootstrap Service est différent des autres registres IANA. Ces autres registres ne sont consultés que rarement (par exemple, lors de l'écriture d'un logiciel) et jamais en temps réel. Si le serveur HTTP de l'IANA plante, ce n'est donc pas trop grave. Au contraire, le Bootstrap Service doit marcher en permanence, car un client RDAP en a besoin. Pour limiter la pression sur les serveurs de l'IANA, notre RFC recommande que les clients RDAP ne consultent pas ce service à chaque requête RDAP, mais qu'au contraire ils mémorisent le JSON récupéré, en utilisant le champ Expires: de HTTP (RFC 7234) pour déterminer combien de temps doit durer cette mémorisation. Néanmoins, l'IANA a dû ajuster ses serveurs HTTP et louer les services d'un CDN pour assurer ce rôle relativement nouveau.

Le client RDAP doit d'autre part être conscient que le registre n'est pas mis à jour instantanément. Par exemple, si un nouveau TLD est ajouté par le gouvernement états-unien, via Verisign, TLD dont le registre a un serveur RDAP, cette information ne sera pas disponible immédiatement pour tous les clients RDAP.

Comme son ancêtre whois, RDAP soulève plein de questions de sécurité intéressantes, détaillées plus précisement dans le RFC 7481.

La section 12 de notre RFC détaille les processus IANA à l'œuvre. En effet, et c'est une autre différence avec les registres IANA habituels, il n'y a pas de mise à jour explicite des registres du bootstrap service, ils sont mis à jour implicitement comme effet de bord des allocations et modifications d'allocation dans les registres d'adresses IPv4, adresses IPv6, numéros d'AS et domaines. Il faudra juste modifier les procédures de gestion de ces registres existants, pour permettre d'indiquer le serveur RDAP (une information qui n'est pas récoltée aujourd'hui, ce qui explique pourquoi le bootstrap service est vide). Ainsi, le formulaire de gestion d'un TLD par son responsable devra être modifié pour ajouter un champ "serveur RDAP" comme il y a aujourd'hui un champ "serveur Whois".

Aujourd'hui, les fichiers de ce service sont :

  • http://data.iana.org/rdap/dns.json
  • http://data.iana.org/rdap/ipv4.json
  • http://data.iana.org/rdap/ipv6.json
  • http://data.iana.org/rdap/asn.json

Voici, par exemple, celui d'IPv6 (encore vide) :


% curl -v http://data.iana.org/rdap/ipv6.json
...
> GET /rdap/ipv6.json HTTP/1.1
> User-Agent: curl/7.38.0
> Host: data.iana.org
> Accept: */*
> 
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Type: text/plain; charset=UTF-8
< Date: Wed, 01 Apr 2015 13:47:28 GMT
< Etag: "63ea7-96-511be51c6e140"
< Last-Modified: Fri, 20 Mar 2015 20:39:57 GMT
< Server: ECAcc (ewr/14C3)
< X-Cache: HIT
< Content-Length: 150
< 
{
  "description": "RDAP bootstrap file for IPv6 address allocations",
  "publication": "2015-03-20T20:39:57Z",
  "services": [],
  "version": "1.0"
}

Et celui des TLD, qui nous montre les deux pionniers, la république tchèque et l'Argentine :


% curl -v http://data.iana.org/rdap/dns.json
{
  "description": "RDAP bootstrap file for Domain Name System registrations",
  "publication": "2016-12-09T04:10:13Z",
  "services": [
    [
      [
        "ar"
      ],
      [
        "https://rdap.nic.ar"
      ]
    ],
    [
      [
        "cz"
      ],
      [
        "https://rdap.nic.cz"
      ]
    ]
  ],
  "version": "1.0"
}

Testons si cela marche vraiment :

% curl -v https://rdap.nic.ar/domain/edu.ar
...
   "nameservers": [
      {
        "objectClassName": "nameserver",
        "handle": "noc.uncu.edu.ar",
        "links": [
          {
            "href": "https://rdap.nic.ar/nameserver/noc.uncu.edu.ar",
            "type": "application/rdap+json",
            "rel": "self",
            "value": "https://rdap.nic.ar/nameserver/noc.uncu.edu.ar"
          }
        ],
        "ldhName": "noc.uncu.edu.ar"
      },
      {
        "objectClassName": "nameserver",
        "handle": "ns1.mrecic.gov.ar",
        "links": [
          {
            "href": "https://rdap.nic.ar/nameserver/ns1.mrecic.gov.ar",
            "type": "application/rdap+json",
            "rel": "self",
            "value": "https://rdap.nic.ar/nameserver/ns1.mrecic.gov.ar"
          }
        ],
        "ldhName": "ns1.mrecic.gov.ar"
      },
      ...

Parfait, tout marche.

Question lecture, John Levine, dans son article sur RDAP, parlait de ce problème de bootstrap : « The biggest delay in getting RDAP done turned out to be the bootstrap, figuring out where the server is for each top level domain, IP range, or ASN range. A lot of proposals that seemed reasonable, like a fixed name (http://rdap.domain) or a DNS approach like SRV records turned out either to have administrative issues, or to be hard to implement (you can't do SRV lookups from Javascript.) There were also issues that were arguably technical or political (depending which side you're on) about specifying the URL syntax of the queries. » Notez qu'on parle parfois de bootstrap service pour désigner, non pas un ensemble de fichiers dirigeant vers le bon serveur RDAP, comme décrit dans ce RFC, mais un serveur qui ne fait que des redirections, comme celui (expérimental) en rdap.org qui, ici, redirige à juste titre vers Afilias :

  
% curl -v http://rdap.org/domain/rmll.info
...
> GET /domain/rmll.info HTTP/1.1
> User-Agent: curl/7.35.0
> Host: rdap.org
> Accept: */*
> 
< HTTP/1.0 301 Moved Permanently
< Date: Thu, 26 Mar 2015 13:57:20 GMT
< Server: Apache
< X-Powered-By: PHP/5.3.3
< Content-Language: en
< Status: 301
< Location: http://rdg.afilias.info/.well-known/rdap/domain/rmll.info
< Content-Length: 0
< Content-Type: application/rdap+json; charset=UTF-8

D'ailleurs, si vous cherchez une mise en œuvre d'un tel redirecteur, il y a rdapbootstrap (en Java).


Téléchargez le RFC 7484


L'article seul

RFC 7483: JSON Responses for the Registration Data Access Protocol (RDAP)

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : A. Newton (ARIN), S. Hollenbeck (Verisign Labs)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF weirds
Première rédaction de cet article le 26 mars 2015


Dans l'ensemble des normes sur le protocole RDAP, ce RFC est destiné à décrire le format de sortie, celui des réponses envoyées par le serveur d'information RDAP. Ce format est basé sur JSON et, pour utiliser RDAP en remplacement de whois, il faudra donc se munir de quelques outils pour traiter le JSON. (Depuis, le RFC 9083 a remplacé ce RFC. Les quelques changements vont surtout dans le sens d'un durcissement des obligations, avec moins de choix laissés à l'initiative du serveur.)

JSON est normalisé dans le RFC 8259 et représente aujourd'hui le format de choix pour les données structurées c'est-à-dire analysables par un programme. (L'annexe E de notre RFC explique en détail le pourquoi du choix de JSON.) Une des caractéristiques importantes de whois est en effet que son format de sortie n'a aucune structure, c'est du texte libre, ce qui est pénible pour les programmeurs qui essaient de le traiter (mais, d'un autre côté, cela ralentit certains usages déplorables, comme la récolte d'adresses de courrier à des fins de spam, jouant ainsi un rôle de semantic firewall). L'utilisation typique de RDAP est en HTTP (RFC 7480) avec les requêtes exprimées dans la syntaxe des URL du RFC 7482. Voici tout de suite un exemple réel, avec la réponse JSON :

% curl http://rdg.afilias.info/rdap/domain/kornog-computing.info
...
{
   "entities": [
...
         "objectClassName": "entity", 
         "roles": [
            "technical", 
            "billing", 
            "administrative"
         ], 
         "vcardArray": [
            "vcard", 
            [
               [
                  "version", 
                  {}, 
                  "text", 
                  "4.0"
               ], 
               [
                  "fn", 
                  {}, 
                  "text", 
                  "Simon TOSSER"
               ], 
               [
                  "fn", 
                  {}, 
                  "text", 
                  "KORNOG computing"
               ], 
               [
                  "adr", 
                  {}, 
                  "text", 
                  [
                     "", 
                     "", 
                     "26b rue d'Aiguillon", 
                     "MORLAIX", 
                     "", 
                     "29600", 
                     "FR"
                  ]
               ], 
...
   "events": [
      {
         "eventAction": "registration", 
         "eventDate": "2007-08-14T17:02:33Z"
      }, 
      {
         "eventAction": "last changed", 
         "eventDate": "2014-08-14T01:54:07Z"
      }, 
      {
         "eventAction": "expiration", 
         "eventDate": "2015-08-14T17:02:33Z"
      }
   ], 
   "handle": "D19378523-LRMS", 
   "lang": "en", 
   "ldhName": "kornog-computing.info", 
...
   "nameservers": [
      {
         "ldhName": "ns1.kornog-computing.net", 
         "objectClassName": "nameserver", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
         ]
      }, 
      {
         "ldhName": "ns2.kornog-computing.net", 
         "objectClassName": "nameserver", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
         ]
      }
   ], 
   "notices": [
      {
         "description": [
            "Access to AFILIAS WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the Afilias registry database. The data in this record is provided by Afilias Limited for informational purposes only, and Afilias does not guarantee its accuracy. [...]"
         ], 
         "title": "TERMS OF USE"
      }
   ], 
   "objectClassName": "domain", 
...
   "rdapConformance": [
      "rdap_level_0"
   ], 
   "secureDNS": {
      "zoneSigned": false
   }, 
   "status": [
      "clientDeleteProhibited -- http://www.icann.org/epp#clientDeleteProhibited", 
      "clientTransferProhibited -- http://www.icann.org/epp#clientTransferProhibited"
   ]
}

La section 1.2 présente le modèle de données de RDAP. Dans les réponses, on trouve des types simples (comme des chaînes de caractères), des tableaux JSON, et des objets JSON qui décrivent les trucs sur lesquels on veut de l'information (noms de domaine, adresses IP, etc). Ces objets peuvent comporter des tableaux ou d'autres objets et, lorsqu'une réponse renvoie plusieurs objets (cas des recherches ouvertes, cf. RFC 7482, section 3.2), peuvent eux-même être regroupés en tableaux. Il existe plusieurs classes de ces objets. D'abord, les classes communes aux registres de noms de domaine et aux RIR :

  • Domaines (oui, même pour les RIR, pensez à in-addr.arpa et ip6.arpa),
  • Serveurs de noms,
  • Entités diverses, comme les handles des contacts.

Deux classes sont spécifiques aux RIR :

On verra peut-être apparaître d'autres classes avec le temps, si l'usage de RDAP se répand.

La section 2 de notre RFC décrit comment JSON est utilisé. Le type MIME renvoyé est application/rdap+json. La section 2 commence par un rappel que le client RDAP doit ignorer les membres inconnus dans les objets JSON, afin de préserver la future extensibilité. (Cette règle ne s'applique pas au jCard - cf. RFC 7095 - embarqué.) Si un serveur veut ajouter des membres qui lui sont spécifiques, il est recommandé qu'il préfixe leur nom avec un identificateur court suivi d'un tiret bas. Ainsi, cet objet RDAP standard :

{
     "handle" : "ABC123",
     "remarks" :
     [
       {
         "description" :
         [
           "She sells sea shells down by the sea shore.",
           "Originally written by Terry Sullivan."
         ]
       }
     ]
   }

S'il est servi par le « registre de la Lune » (registre imaginaire qui fournit les exemples de ce RFC), celui-ci, lorsqu'il voudra ajouter des membres, les précédera de lunarNIC_ :

{
     "handle" : "ABC123",
     "lunarNic_beforeOneSmallStep" : "TRUE THAT!",
     "remarks" :
     [
       {
         "description" :
         [
           "She sells sea shells down by the sea shore.",
           "Originally written by Terry Sullivan."
         ]
       }
     ],
     "lunarNic_harshMistressNotes" :
     [
       "In space,",
       "nobody can hear you scream."
     ]
   }

(Je vous laisse décoder les références geeks dans l'exemple.)

La section 3 s'occupe des types de données de base. On utilise du JSON normal, tel que spécifié dans le RFC 8259, avec ses chaînes de caractères, ses booléens, son null... Un handle (l'identifiant unique - par registre - d'un contact, parfois nommé NIC handle ou registry ID) est une chaîne. Les adresses IP se représentent également par une chaîne de caractères (ne pas oublier le RFC 5952 pour IPv6). Les pays sont identifiés par le code à deux lettres de ISO 3166. Les noms de domaines peuvent être sous une forme ASCII ou bien en Unicode. Les dates et heures suivent le RFC 3339, et les URI le RFC 3986.

Les informations plus complexes (comme les détails sur un contact) utilisent jCard, normalisé dans le RFC 7095.

Que trouve-t-on dans les objets JSON renvoyés par un serveur RDAP ? Une indication de la version de la norme :

"rdapConformance" :
   [
     "rdap_level_0"
   ]

Et des liens vers des ressources situées ailleurs, suivant le cadre du RFC 8288 :

         "links": [
            {
               "href": "http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5", 
               "rel": "self", 
               "type": "application/rdap+json", 
               "value": "http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5"
            }

On peut aussi avoir du texte libre, comme dans l'exemple plus haut avec le membre remarks. Ce membre sert aux textes décrivant la classe, alors que notices est utilisé pour le service RDAP. Un exemple :

   "notices": [
      {
         "description": [
            "Access to AFILIAS WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the Afilias registry database. The data in this record is provided by Afilias Limited for informational purposes only, and Afilias does not guarantee its accuracy. [...]"
         ], 
         "title": "TERMS OF USE"
      }
   ], 

Contrairement à whois, RDAP permet l'internationalisation sous tous ses aspects. Par exemple, on peut indiquer la langue des textes avec une étiquette de langue (RFC 5646) :

   "lang": "en", 

Enfin, la classe (le type) de l'objet renvoyé par RDAP est indiqué par un membre objectClassName :

   "objectClassName": "domain", 

Ces classes, justement. La section 5 les décrit. Il y a d'abord la classe Entity qui correspond aux requêtes /entity du RFC 7482. Elle sert à décrire les personnes et les organisations. Parmi les membres importants pour les objets de cette classe, handle qui est un identificateur de l'instance de la classe, et roles qui indique la relation de cette instance avec l'objet qui la contient (par exemple "roles": ["technical"] indiquera que cette Entity est le contact technique de l'objet). L'information de contact sur une Entity se fait avec le format jCard du RFC 7095, dans un membre vcardArray. Voici un exemple :

% curl http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5
...
         "objectClassName": "entity", 
         "roles": [
            "technical", 
            "billing", 
            "administrative"
         ], 
         "vcardArray": [
            "vcard", 
            [
               [
                  "version", 
                  {}, 
                  "text", 
                  "4.0"
               ], 
               [
                  "fn", 
                  {}, 
                  "text", 
                  "Simon TOSSER"
               ], 
               [
                  "fn", 
                  {}, 
                  "text", 
                  "KORNOG computing"
               ], 
               [
                  "adr", 
                  {}, 
                  "text", 
                  [
                     "", 
                     "", 
                     "26b rue d'Aiguillon", 
                     "MORLAIX", 
                     "", 
                     "29600", 
                     "FR"
                  ]
               ], 
               [
                  "email", 
                  {}, 
                  "text", 
                  "simon.tosser@gmail.com"
               ], 
               [
                  "tel", 
                  {
                     "type": "work"
                  }, 
                  "uri", 
                  "tel:+33.661463099"
               ], 
            ]
         ]

La classe Nameserver correspond aux requêtes /nameserver du RFC 7482. Notez qu'un registre peut gérer les serveurs de noms de deux façons : ils peuvent être vus comme des objets autonomes, enregistrés tels quel dans le registre (par exemple via le RFC 5732), ayant des attributs par exemple des contacts, et interrogeables directement par whois ou RDAP (c'est le modèle de .com, on dit alors que les serveurs de noms sont des « objets de première classe »). Ou bien ils peuvent être simplement des attributs des domaines, accessibles via le domaine (c'est le modèle de .fr : regardez ssi.gouv.fr, bien que les serveurs de noms soient dans la zone, vous ne pouvez pas demander directement des informations sur ces serveurs via whois). Le principal attribut d'un objet Nameserver est son adresse IP, pour pouvoir générer des colles dans le DNS (enregistrement DNS d'une adresse IP, pour le cas où le serveur de noms est lui-même dans la zone qu'il sert). Voici un exemple avec un des serveurs de noms de la zone afilias-nst.info :

% curl http://rdg.afilias.info/rdap/nameserver/b0.dig.afilias-nst.info 
...
   "ipAddresses": {
      "v4": [
         "65.22.7.1"
      ], 
      "v6": [
         "2a01:8840:7::1"
      ]
   }, 
...

Notez que l'adresse IP est un tableau, un serveur pouvant avoir plusieurs adresses.

La classe Domain correspond aux requêtes /domain du RFC 7482. Un objet de cette classe a des membres indiquant les serveurs de noms, si la zone est signée avec DNSSEC ou pas, l'enregistrement DS si elle est signée, le statut (actif ou non, bloqué ou non), les contacts, etc. Voici un exemple :

% curl http://rdg.afilias.info/rdap/domain/afilias-nst.info  
...
   "nameservers": [
      {
         "ldhName": "a0.dig.afilias-nst.info", 
...
   "secureDNS": {
      "zoneSigned": false
   }, 
   "status": [
      "clientTransferProhibited -- http://www.icann.org/epp#clientTransferProhibited", 
      "serverDeleteProhibited -- http://www.icann.org/epp#serverDeleteProhibited"
   ]
...

La classe IP network rassemble les objets qu'on trouve dans les réponses aux requêtes /ip du RFC 7482. Un objet de cette classe ne désigne en général pas une seule adresse IP mais un préfixe, dont on indique la première (startAddress) et la dernière adresse (endAddress). Personnellement, je trouve cela très laid et j'aurai préféré qu'on utilise une notation préfixe/longueur. Voici un exemple :

% curl http://rdap.db.ripe.net/ip/131.111.150.25    
...
{
  "handle" : "131.111.0.0 - 131.111.255.255",
  "startAddress" : "131.111.0.0/32",
  "endAddress" : "131.111.255.255/32",
  "ipVersion" : "v4",
  "name" : "CAM-AC-UK",
  "type" : "LEGACY",
  "country" : "GB",
...

La dernière classe normalisée à ce stade est autnum (les AS), en réponse aux requêtes /autnum du RFC 7482. Elle indique notamment les contacts de l'AS. Pour l'instant, il n'y a pas de format pour indiquer la politique de routage (RFC 4012). Un exemple d'un objet de cette classe :

% curl  http://rdap.db.ripe.net/autnum/20766 
{
  "handle" : "AS20766",
  "name" : "GITOYEN-MAIN-AS",
  "type" : "DIRECT ALLOCATION",
...
    "handle" : "GI1036-RIPE",
    "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "NOC Gitoyen" ], [ "kind", { }, "text", "group" ], [ "adr", {
      "label" : "Gitoyen\n21 ter rue Voltaire\n75011 Paris\nFrance"
    }, "text", null ], [ "email", { }, "text", "noc@gitoyen.net" ] ] ],
...

Comme, dans la vie, il y a parfois des problèmes, une section de notre RFC, la section 6, est dédiée aux formats des erreurs que peuvent indiquer les serveurs RDAP. Le code de retour HTTP fournit déjà des indications (404 = cet objet n'existe pas ici, 403 = vous n'avez pas le droit de le savoir, etc) mais on peut aussi ajouter un objet JSON pour en indiquer davantage, objet ayant un membre errorCode (qui reprend le code HTTP), un membre title et un membre description. Voici un exemple sur le serveur RDAP expérimental de l'ARIN :

% curl -v http://rdappilot.arin.net/restfulwhois/rdap/autnum/99999 
< HTTP/1.0 404 Not Found
< Date: Thu, 26 Mar 2015 16:02:07 GMT
< Server: Apache/2.2.3 (CentOS)
...
{
...
  "errorCode" : 404,
  "title" : "AUTNUM NOT FOUND",
  "description" : [ "The autnum you are seeking as '99999' is/are not here." ]

Plus positive, la possibilité de demander de l'aide à un serveur RDAP, en se renseignant sur ses capacités, avec la requête /help. Son résultat est décrit dans la section 7 mais les serveurs RDAP actuels ne semblent pas encore utiliser cette possibilité. L'exemple qui suit est donc purement théorique :

{
     "rdapConformance" :
     [
       "rdap_level_0"
     ],
     "notices" :
     [
       {
         "title" : "Authentication Policy",
         "description" :
         [
           "Access to sensitive data for users with proper credentials."
         ],
         "links" :
         [
           {
             "value" : "http://example.net/help",
             "rel" : "alternate",
             "type" : "text/html",
             "href" : "http://www.example.com/auth_policy.html"
           }
         ]
       }
     ]
   }

Et les résultats des recherches ouvertes (section 3.2 du RFC 7482), qui peuvent renvoyer plusieurs objets ? Ce sont des tableaux JSON, dans des membres dont le nom se termine par Results. Par exemple, en cherchant les noms de domaines commençant par ra :

% curl http://rdg.afilias.info/rdap/domains\?name=ra\*|more           
   "domainSearchResults": [
      {
         "ldhName": "RAINSTRAGE.INFO", 
         ...
         "objectClassName": "domain", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
...
         "ldhName": "RADONREMOVAL.INFO", 
...
         "ldhName": "RANCONDI.INFO", 
...

Vous avez peut-être noté dans le tout premier exemple le membre events (section 4.5 du RFC). Ces événements comme created ou last-changed donnent accès à l'histoire d'un objet enregistré. Ici, nous apprenons que le domaine kornog-computing.info a été enregistré en 2007.

Certaines valeurs qui apparaissent dans les résultats sont des chaînes de caractères fixes, stockées dans un nouveau registre IANA. Elles sont conçues pour être utilisées dans les notices, remarks, status, roles et quelques autres. Parmi les remarques, on trouvera le cas où une réponse a été tronquée (section 9 du RFC), comme dans l'exemple ci-dessus avec la mention Incomplete Data. Parmi les statuts, on trouvera, par exemple validated (pour un objet vérifié, par exemple un nom de domaine dont on a vérifié les coordonnées du titulaire), locked (pour un objet verrouillé), obscured (qui n'est pas un statut dans le base du données du registre mais simplement la mention du fait que le serveur RDAP a délibérement modifié certaines informations qu'il affiche, par exemple pour protéger la vie privée), etc. Pour les rôles, on trouvera registrant (titulaire), technical (contact technique), etc.

Pour ceux qu'intéressent les questions d'internationalisation, la section 12 contient d'utiles mentions. L'encodage des données JSON doit être de l'UTF-8. Et, comme indiqué plus haut, les IDN peuvent être sous la forme Punycode ou bien directement en UTF-8.

Et la vie privée, un problème permanent avec whois, où il faut toujours choisir entre la distribution de données utiles pour contacter quelqu'un et les risques pour sa vie privée ? La section 13 revient sur cette question. Un point important : RDAP est un protocole, pas une politique. Il ne définit pas quelles règles suivre (c'est de la responsabilité des divers registres) mais il fournit les outils pour mettre en œuvre ces règles. Notamment, RDAP permet de marquer des parties de la réponse comme étant connues du registre, mais n'ayant délibérement pas été envoyées (avec les codes private et removed) ou bien comme ayant été volontairement rendues peu ou pas lisibles (code obscured).

Vous avez vu dans les exemples précédents que les réponses d'un serveur RDAP sont souvent longues et, a priori, moins lisibles que celles d'un serveur whois. Il faudra souvent les traiter avec un logiciel qui comprend le JSON. Un exemple très simple et que j'apprécie est jq. Il peut servir à présenter le résultat de manière plus jolie :

% curl  https://rdap.centralnic.com/domain/centralnic.pw  | jq "" 
{
  "cnic_recordGenerated": "2015-03-26T16:11:20.0Z",
  "lang": "en",
  "notices": [
    {
      "links": [
        {
          "type": "application/json",
          "media": "screen",
          "rel": "item",
          "href": "https://www.centralnic.com/registry/labs/rdap#service-level",
          "value": "https://www.centralnic.com/registry/labs/rdap#service-level",
          "title": "Service Level"
        }
      ],
      "description": [
        "The RDAP service is currently an alpha quality product. CentralNic makes no warranty of it
s correctness, usefulness or reliability. CentralNic reserves the right to change or remove part or
 all of the service at any time with no prior warning. No service level is offered."
      ],
      "title": "Service Level"
    },
    {
      "links": [
        {
...

(Essayez ce même serveur RDAP sans jq !)

Mais on peut aussi se servir de jq pour extraire un champ particulier, ici le pays :

% curl -s  http://rdap.db.ripe.net/ip/131.111.150.25 | jq ".country"
"GB"

% curl -s  http://rdap.db.ripe.net/ip/192.134.1.1 | jq ".country"
"FR"

Il y a évidemment d'autres logiciels que jq sur ce créneau, comme JSONpath, jpath ou, pour les programmeurs Python, python -m json.tool.

Un dernier mot, sur le choix de JSON pour le format de sortie, alors que le protocole standard d'avitaillement des objets dans les bases Internet, EPP (RFC 5730) est en XML. L'annexe E de notre RFC, qui discute ce choix, donne comme principaux arguments que JSON est désormais plus répandu que XML (cf. l'article « The Stealthy Ascendancy of JSON ») et que c'est surtout vrai chez les utilisateurs (EPP étant utilisé par une population de professionnels bien plus réduite).


Téléchargez le RFC 7483


L'article seul

RFC 7482: Registration Data Access Protocol Query Format

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : A. Newton (ARIN), S. Hollenbeck (Verisign Labs)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF weirds
Première rédaction de cet article le 26 mars 2015


Le nouveau protocole d'information RDAP, qui vise à remplacer whois, est décrit dans un ensemble de RFC. Celui présenté ici normalise la façon de former les requêtes RDAP. Celles-ci ont la forme d'une URL, puisque RDAP repose sur l'architecture REST. (Depuis, ce RFC a été légèrement mis à jour par son remplaçant, le RFC 9082.)

Vous pouvez voir les autres RFC sur RDAP dans mon autre article. Je rappelle juste que le seul transport actuellement normalisé pour RDAP (dans le RFC 7480) est HTTP. RDAP peut être utilisé pour beaucoup de sortes d'entités différentes mais ce RFC ne couvre que ce qui correspond aux usages actuels de whois, les préfixes d'adresses IP, les AS, les noms de domaine, etc. Bien sûr, un serveur RDAP donné ne gère pas forcément tous ces types d'entités, et il renvoie le code HTTP 501 (Not implemented) s'il ne sait pas gérer une demande donnée. Ce RFC ne spécifie que l'URL de la requête, le format de la réponse est variable (JSON, XML...) et le seul actuellement normalisé, au-dessus de JSON, est décrit dans le RFC 7483. D'autre part, ces RFC RDAP ne décrivent que le protocole entre le client RDAP et le serveur, pas « l'arrière-cuisine », c'est-à-dire l'avitaillement (création, modification et suppression) des entités enregistrées. RDAP est en lecture seule et ne modifie pas le contenu des bases de données qu'il interroge.

Passons aux choses concrètes. Une requête RDAP est un URL RFC 3986. Celui-ci est obtenu en ajoutant un chemin spécifique à une base. La base (par exemple https://rdap.example.net/) va être obtenue par des mécanismes divers, comme celui du RFC 7484. On met ensuite un chemin qui dépend du type d'entité sur laquelle on veut se renseigner, et qui indique l'identificateur de l'entité. Par exemple, avec la base ci-dessus, et une recherche du nom de domaine internautique.fr, on construirait un URL complet https://rdap.example.net/domain/internautique.fr. Il y a cinq types d'entités possibles :

  • ip : les préfixes IP (notez qu'on peut chercher un préfixe en donnant juste une des adresses IP couvertes par ce préfixe),
  • autnum : les numéros de systèmes autonomes,
  • domain : un nom de domaine (notez que cela peut être un domaine dans in-addr.arpa ou ipv6.arpa),
  • nameserver : un serveur de noms,
  • entity : une entité quelconque, comme un bureau d'enregistrement, ou un contact identifié par un handle.

Pour ip, le chemin dans l'URL est /ip/XXXXXX peut être une adresse IPv4 ou IPv6 sous forme texte. Il peut aussi y avoir une longueur de préfixe à la fin donc /ip/2001:db8:1:a::/64 est un chemin valable. Ainsi, sur le service RDAP expérimental du RIPE-NCC, http://rdap.db.ripe.net/ip/2001:4b98:dc0:41:: est un URL possible. Testons-le :

% curl  http://rdap.db.ripe.net/ip/2001:4b98:dc0:41:: 
{
  "handle" : "2001:4b98:dc0::/48",
  "startAddress" : "2001:4b98:dc0::/128",
  "endAddress" : "2001:4b98:dc0:ffff:ffff:ffff:ffff:ffff/128",
  "ipVersion" : "v6",
  "name" : "GANDI-HOSTING-DC0",
  "type" : "ASSIGNED",
  "country" : "FR",
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "GAD42-RIPE",
    "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "Gandi Abuse Department" ], [ "kind", { }, "text", "group" ], [ "adr", {
      "label" : "63-65 Boulevard Massena\n75013 Paris\nFrance"
...

Pour autnum, on met le numéro de l'AS après /autnum/. Toujours dans l'exemple RIPE-NCC, http://rdap.db.ripe.net/autnum/29169 permet de chercher de l'information sur l'AS 29169 :

% curl   http://rdap.db.ripe.net/autnum/29169 
{
  "handle" : "AS29169",
  "name" : "GANDI-AS",
  "type" : "DIRECT ALLOCATION",
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "GANDI-NOC",
    "roles" : [ "registrant" ]
  }, {
...

Pour les noms de domaines, on met le nom après /domain/. Ainsi, sur le serveur RDAP expérimental d'Afilias, http://rdg.afilias.info/rdap/domain/rmll.info nous donnera de l'information sur le domaine rmll.info. On peut mettre un nom en Unicode donc https://rdap.example.net/domain/potamochère.fr est valable, mais il devra être encodé comme l'explique la section 6.1, plus loin. Si on ne veut pas lire cette information sur l'encodage, on peut aussi utiliser la forme Punycode, donc chercher avec https://rdap.example.net/domain/xn--potamochre-66a.fr.

On peut aussi se servir de RDAP pour les noms de domaines qui servent à traduire une adresse IP en nom :

% curl http://rdap.db.ripe.net/domain/1.8.a.4.1.0.0.0.0.d.1.4.1.0.0.2.ip6.arpa
{
  "handle" : "0.d.1.4.1.0.0.2.ip6.arpa",
  "ldhName" : "0.d.1.4.1.0.0.2.ip6.arpa",
  "nameServers" : [ {
    "ldhName" : "dns15.ovh.net"
  }, {
    "ldhName" : "ns15.ovh.net"
  } ],
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "OK217-RIPE",
    "roles" : [ "administrative" ]
  }, {
    "handle" : "OTC2-RIPE",
    "roles" : [ "zone", "technical" ]
  }, {
    "handle" : "OVH-MNT",
    "roles" : [ "registrant" ]
  } ],
  "remarks" : [ {
    "description" : [ "OVH IPv6 reverse delegation" ]
  } ],
...

Pour un serveur de noms, on met son nom après /nameserver donc, chez Afilias :

% curl  http://rdg.afilias.info/rdap/nameserver/rmll1.rmll.info 
{
...
   "ipAddresses": {
      "v4": [
         "80.67.169.65"
      ]
   }, 
   "lang": "en", 
   "ldhName": "rmll1.rmll.info", 
...

Pour entity, on indique juste un identificateur. Voici un exemple :

% curl  http://rdg.afilias.info/rdap/entity/R-R191-LRMS   
{
   "handle": "R-R191-LRMS", 
   "lang": "en", 
...
   "roles": [
      "registrar"
   ], 
   "vcardArray": [
      "vcard", 
      [
         [
            "version", 
            {}, 
            "text", 
            "4.0"
         ], 
         [
            "fn", 
            {}, 
            "text", 
            "Gandi SAS"
         ], 
         [
            "adr", 
            {}, 
            "text", 
            [
               "", 
               "", 
               "63-65 boulevard Massena", 
               "Paris", 
               "", 
               "F-75013", 
               "FR"
            ]
...

Dernière possibilité, un chemin spécial indique qu'on veut récupérer de l'aide sur ce serveur RDAP particulier. En envoyant help (par exemple https://rdap.example.net/help, on obtient un document décrivant les capacités de ce serveur, ses conditions d'utilisation, sa politique vis-à-vis de la vie privée, ses possibilités d'authentification, l'adresse où contacter les responsables, etc. C'est l'équivalent de la fonction d'aide qu'offrent certains serveurs whois, ici celui de l'AFNIC :

% whois -h whois.nic.fr  -- -h
...
%% Option   Function
%% -------  -------------------------------------
%% -r       turn off recursive lookups
%% -n       AFNIC output format
%% -o       old fashioned output format (Default)
%% -7       force 7bits ASCII output format
%% -v       verbose mode for templates and help options
%%          (may be use for reverse query)
%% -T type  return only objects of specified type
%% -P       don't return individual objects in case of contact search
%% -h       informations about server features
%% -l lang  choice of a language for informations (you can specify US|EN|UK for
%%          english or FR for french)
%%
...

Pour RDAP, voyez par exemple http://rdg.afilias.info/rdap/help ou, dans un genre très différent, http://rdap.apnic.net/help.

Toutes les recherches jusque-là ont été des recherches exactes (pas complètement pour les adresses IP, où on pouvait chercher un réseau par une seule des adresses contenues dans le réseau). Mais on peut aussi faire des recherches plus ouvertes, sur une partie de l'identificateur. Cela se fait en ajoutant une requête (la partie après le point d'interrogation) dans l'URL et en ajoutant un astérisque (cf. section 4.1). Ainsi, https://rdap.example.net/domains?name=foo* cherchera tous les domaines dont le nom comporte la chaîne de caractères foo. (Vous avez noté que c'est /domains, au pluriel, et non plus /domain ?) Voici un exemple d'utilisation :

% curl  http://rdg.afilias.info/rdap/domains\?name=rm\*|more
   "domainSearchResults": [
      {
         "handle": "D10775367-LRMS", 
         "ldhName": "RMLL.INFO", 
...
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
...
         "ldhName": "RMLL2015.INFO", 
...
         "ldhName": "RMLLOCKSMITHS.INFO", 
... 
      {
         "description": [
            "Search results are limited to 50 per query."
         ], 
         "title": "Search Policy", 
         "type": "result set truncated due to unexplainable reasons"
      }

On peut aussi chercher un domaine d'après ses serveurs de noms, par exemple https://rdap.example.net/domains?nsLdhName=ns1.example.com chercherait tous les domaines délégués au serveur DNS ns1.example.com. Une telle fonction peut être jugée très indiscrète et le serveur RDAP est toujours libre de répondre ou pas :

% curl http://rdg.afilias.info/rdap/domains\?nsLdhName=ns0.abul.org
...
{
   "description": [
      "Domain name search by nameserver is not supported."
   ], 
   "errorCode": 501, 
...

Deux autres types permettent ces recherches ouvertes, /nameservers (comme dans https://rdap.example.net/nameservers?ip=2001:db8:42::1:53, mais notez qu'on peut aussi chercher un serveur par son nom) et /entities (comme dans https://rdap.example.net/entities?fn=Jean%20Dupon*) :

% curl  http://rdg.afilias.info/rdap/entities\?fn=go\*     
{
   "entitySearchResults": [
      {
         "fn": "Go China Domains, Inc.", 
...
         "fn": "Gotnames.ca Inc.", 
...

Notez que ce type de recherche peut représenter un sérieux danger pour la vie privée (comme noté dans le RFC, par exemple en section 4.2) puisqu'elle permettrait, par exemple de trouver tous les titulaires prénommés Jean. Il faut donc espérer qu'elle ne sera accessible qu'à des clients authentifiés, et de confiance.

La section 4 détaille le traitement des requêtes. N'oubliez pas qu'on travaille ici sur HTTP et que, par défaut, les codes de retour RDAP suivent la sémantique HTTP (404 pour un objet non trouvé, par exemple). Il y a aussi quelques cas où le code à retourner est moins évident. Ainsi, si un serveur ne veut pas faire une recherche ouverte, il va répondre 422 (Unprocessable Entity).

Vous avez noté plus haut, mais la section 6 le rappelle aux distraits, que le nom de domaine peut être exprimé en Unicode ou en ASCII. Donc, https://rdap.example.net/domain/potamochère.fr et https://rdap.example.net/domain/xn--potamochre-66a sont deux requêtes acceptables.

Enfin, la section 8 rappelle quelques règles de sécurité comme :

  • Les requêtes ouvertes peuvent mener à une forte consommation de ressources sur le serveur. Le serveur qui ne vaut pas se faire DoSer doit donc faire attention avant de les accepter.
  • Les requêtes RDAP, et surtout les requêtes ouvertes, peuvent soulever des questions liées à la vie privée. Les serveurs RDAP doivent donc réfléchir avant de renvoyer de l'information. Rappelez-vous que RDAP, contrairement à whois, peut avoir un mécanisme d'authentification, donc peut envoyer des réponses différentes selon le client.
  • Et, corollaire du précédent point, les gérants de serveurs RDAP doivent définir une politique d'autorisation : qu'est-ce que je renvoie, et à qui ?

Téléchargez le RFC 7482


L'article seul

RFC 7481: Security Services for the Registration Data Access Protocol

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs), N. Kong (CNNIC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF weirds
Première rédaction de cet article le 4 avril 2015


Une des faiblesses les plus souvent citées de l'ancien protocole whois est son manque de sécurité : pas d'authentification du client (et donc pas de moyen simple de servir des contenus plus ou moins complets selon le client), et pas de confidentialité. Le candidat à sa succession, RDAP, va-t-il faire mieux ? En tout cas, il propose de nombreux services de sécurité, détaillés dans ce RFC. Comment et au profit de qui les utiliser, voici qui va sans doute déclencher de nouvelles disputes de gouvernance.

Le nouveau protocole RDAP est normalisé dans plusieurs RFC comme le RFC 7480 qui décrit comment faire tourner RDAP sur HTTP avec une architecture REST. La grande majorité des fonctions de sécurité de RDAP découlent de cette utilisation de HTTP. Ces fonctions étaient réclamés dès le cahier des charges pour un successeur de whois, le RFC 3707.

La section 3 de notre RFC liste les services de sécurité attendus, et la manière dont RDAP les fournit, en général en s'appuyant sur les services équivalents fournis par HTTP et HTTPS. Ainsi, la premier service demandé est le contrôle d'accès et la section 10.2.2 du RFC 7483, RFC consacré au format des réponses RDAP (en JSON) prévoit un mécanisme standard pour indiquer qu'une partie de la réponse a été délibérement tronquée ou omise.

Ensuite, l'authentification (section 3.1.4.2 du RFC 3707). Pas d'autorisation fine sans authentification préalable. Avec whois, on doit servir les mêmes données à tout le monde, car il n'y a pas d'authentification disponible (parfois, une authentification sommaire est faite via l'adresse IP du client, un registre peut servir davantage d'informations à ses employés, en vérifiant que l'adresse IP source est celle du réseau local du registre). Quand RDAP tourne sur HTTP, il doit donc utiliser les mécanismes d'authentification de HTTP, décrits dans le RFC 7235. Si on utilise le mécanisme basic, qui envoie en clair le mot de passe, il faut en plus utiliser TLS (RFC 2818). On peut aussi tout faire avec TLS, en authentifiant le client par un certificat (section 7.4.6 du RFC 5246) mais c'est optionnel dans RDAP, contrairement aux mécanismes du RFC 7235, qui doivent être présents. Ces mécanismes ne permettent pas d'authentifier le serveur, mais on peut, là encore, se servir de TLS pour cela (en vérifiant le certificat du serveur).

Les mécanismes classiques d'authentification via HTTP nécessitent que le client gère des informations de créance pour tous les serveurs. Or, un même client RDAP peut parler à de nombreux serveurs. Il est donc intéressant de regarder du côté des mécanismes d'authentification fédérés, qui peuvent permettre de n'avoir qu'une seule information de créance, utilisée pour tous les serveurs. Il existe pour cela plusieurs techniques utilisable en HTTP, OAuth (RFC 6749), OpenID, des assertions SAML, ou bien des certificats client avec des AC reconnues par tous les serveurs. À noter que RDAP ne dispose pas (pas encore ?) d'une solution pour découvrir quel mécanisme d'authentification est utilisé par quel serveur.

Une fois qu'on a l'authentification, on peut bâtir l'autorisation et donner des accès aux clients en fonction de leur identité (section 3.1.4.2 du RFC 3707). On peut par exemple :

  • Permettre un accès à tout client (mode « anonyme » comme avec le whois actuel) mais en ne donnant accès qu'à peu d'informations,
  • Ne donner un accès complet qu'aux informations ayant un rapport avec le client (par exemple permettre à un titulaire de tout voir sur ses propres noms),
  • Donner un accès complet aux clients authentifiés comme travaillant pour la NSA.

Au bout du compte, il s'agit de décisions politiques, à prendre dans chaque registre, et ce RFC n'indique donc pas de politique, il indique juste les bases sur lesquelles mettre en œuvre une telle politique.

Parmi les services de sécurité, il y a bien sûr la disponibilité : un serveur RDAP super-protégé mais qui serait tout le temps en panne n'aurait guère d'utilité. Notre RFC rappelle donc qu'il existe un RFC sur les attaques par déni de service (le RFC 4732). Un serveur RDAP est autorisé à se prémunir contre les attaques et les excès, par exemple en limitant d'autorité le trafic. Si un client est refusé en raison de cette limitation, le code de retour HTTP recommandé est le 429 (RFC 6585). Si le client est simplement trop enthousiaste, il ralentira alors ses accès. Évidemment, si c'est un attaquant, il continuera.

Autre service de sécurité essentiel, la confidentialité. Whois n'avait aucun mécanisme de protection contre un tiers qui écoute le réseau (d'un autre côté, comme tout était public...) RDAP permet d'utiliser HTTP sur TLS (RFC 2818), permettant ainsi au chiffrement de protéger la confidentialité des données. (On note que les serveurs RDAP expérimentaux actuellement existants sont loin de tous permettre un accès en HTTPS.) À noter que TLS protège le canal, pas les données : il n'y a pas de chiffrement de bout en bout dans RDAP, pour l'instant.

Et le dernier service de sécurité dont on veut disposer est l'intégrité, la garantie que les données ne soient pas modifiées en route. Il n'existe pas non plus de mécanisme de signature des données dans RDAP, mécanisme qui assurerait une protection de bout en bout. Il faut donc utiliser TLS, dont les paquets comportent un MAC qui permet de détecter les modifications.

On a parlé de confidentialité mais la section 4 de notre RFC pose le problème dans une perspective plus générale, celle de la protection de la vie privée. Ce problème est la plaie de whois (« notre conflit du Moyen-Orient », disait Fadi Chehadé en faisant allusion à la durée du problème et à l'absence de perspectives de solution) et a fait l'objet d'innombrables débats, à l'ICANN ou ailleurs. Comme whois ne fournit aucun accès différencié (tout est public ou pas distribué du tout), les données stockées dans les registres, qui sont souvent sensibles, sont envoyées à tous. Résultat, la seule protection est souvent de mentir, dissimulant ses données personnelles. Parfois, il existe des services intermédiaires qui masquent les données, relaient le courrier, etc. RDAP ne change pas la question des données récoltées et stockées par le registre (si le registre se fait pirater, ou bien s'il donne toutes ses données à des services de surveillance étatiques ou non, la vie privée sera compromise, RDAP ou pas RDAP). En revanche, il permet de ne pas envoyer les données à tout le monde, réservant par exemple les données personnelles à certains clients. RDAP permet par exemple de transmettre davantage de données à des membres des forces de l'ordre, dûment authentifiés. Notez donc que RDAP va soulever des problèmes à lui, que n'avait pas whois. Whois ne permettait techniquement pas de donner plus d'informations aux forces de l'ordre, ou aux ayant-droits, ou à d'autres catégories. RDAP le permet techniquement et certains acteurs le demanderont sans aucun doute.

Comme toujours en protection des données personnelles, le mieux, pour éviter les ennuis, est de ne pas récolter les données du tout. Cette solution simple est la plus efficace, protégeant aussi bien du piratage que d'un opérateur indélicat. Ainsi, les réponses RDAP utilisent jCard (RFC 7095) pour les données personnelles. jCard a énormément de champs possibles et tous ne sont pas pertinents pour le registre. Il est donc possible de ne pas les collecter (et donc de ne pas les envoyer).

À noter qu'il existe aussi un risque lié à la vie privée pour le client : les requêtes qu'il fait peuvent donner des informations sur son activité. Le chiffrement protège contre l'accès d'un tiers à ces informations, mais pas contre le registre lui-même, qui doit donc rester discret sur les requêtes qu'il reçoit.

La section 5 du RFC couvre quelques risques de sécurité résiduels. Par exemple, on voit souvent dans les réponses whois des tentatives d'injection, notamment de code HTML. Notre RFC rappelle donc que les données renvoyées par RDAP ne sont pas forcément sûres et qu'un client RDAP ne doit pas les afficher aveuglément, ni les mettre dans une base de données sans faire attention.

Et, enfin, la section 5 de notre RFC rappelle aussi que le protocole peut assurer des choses comme l'intégrité des données (ce qui a été reçu par le client est bien ce qui avait été envoyé par le serveur) mais que cela ne garantit pas l'exactitude des données : celles-ci étaient peut-être fausses dès le début, soit par négligence de la part de celui qui les a déclarées, soit parce que mentir est, à l'heure actuelle, souvent le seul moyen de protéger ses données personnelles.


Téléchargez le RFC 7481


L'article seul

RFC 7480: HTTP usage in the Registration Data Access Protocol (RDAP)

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : A. Newton (ARIN), B. Ellacott (APNIC), N. Kong (CNNIC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF weirds
Première rédaction de cet article le 26 mars 2015


Le protocole d'accès aux informations des registres RDAP (Registration Data Access Protocol), qui se veut successeur de whois, peut utiliser plusieurs protocoles de transport différents. Pour l'instant, le seul normalisé est HTTP, dans ce RFC.

HTTP est normalisé dans le RFC 7230. Mais, à part cela, il n'y a évidemment pas besoin de le présenter. Son choix comme protocole de transport va de soi dans l'Internet aujourd'hui, et permet de doter RDAP d'une jolie sémantique REST. Toute la complexité est dans le serveur, un des objectifs de ce RFC est que « on puisse utiliser comme client RDAP des outils généralistes comme bash ou wget ». Le mode d'emploi est à peu près :

  • Trouver le bon serveur, par exemple en utilisant la technique du RFC 7484,
  • Fabriquer une jolie requête HTTP de type GET (RFC 7231), en suivant le RFC 7482, par exemple, pour trouver de l'information sur le réseau 192.0.2.0, ce sera http://example.net/rdap/ip/192.0.2.0,
  • Envoyer la requête et lire la réponse en JSON (RFC 7483),
  • La réponse était peut-être sur un autre serveur et, dans ce cas, on a reçu non pas le code JSON, avec le statut 200, mais une redirection (statut HTTP 3xx) ; dans ce cas, on réessaie avec l'URL indiqué dans la redirection.

D'autres réponses étaient possibles, comme le fameux 404 si on demande des informations sur un objet qui n'existe pas. RDAP utilise HTTP et on a donc toutes les subtilités de HTTP à sa disposition.

La section 3 de notre RFC résume les principes de RDAP-sur-HTTP :

  • Une seule requête HTTP pour avoir l'information,
  • Plusieurs formats de sortie possible en théorie même si, pour l'instant, seul le JSON du RFC 7483 est spécifié,
  • Possibilité d'utiliser tout ce que permet HTTP, afin d'éviter de réinventer la roue. Ainsi, si on veut de la compression, on ne la réinvente pas dans RDAP, on utilise celle de HTTP (RFC 7231, section 3.1.2). Même chose pour les mécanismes d'authentification, où on suivra le RFC 7235 ou bien le cache, selon le RFC 9111. Ainsi, on pourra récupérer tous les logiciels et l'expertise de HTTP.

La section 4 détaille la formation des requêtes RDAP sur HTTP. Ce sont des requêtes GET ou HEAD (puisqu'elles ne modifient pas les données, RDAP étant un protocole en lecture seule), qui fonctionnent sur HTTP ou HTTPS (qui est obligatoire pour les logiciels RDAP). Le client doit penser à mettre un en-tête Accept: qui indique un type de données qui existe pour RDAP, comme le application/rdap+json du RFC 7483 (notez la syntaxe avec un +, issue du RFC 6839). S'il l'oublie, le serveur est libre de faire ce qu'il veut, le RFC suggérant d'envoyer une réponse acceptable par un navigateur Web ordinaire (comme text/html), car c'est sans doute cela qui provoquera le moins de surprise (les serveurs RDAP existants - voir par exemple http://rdg.afilias.info/rdap/domain/reflets.info - ne suivent pas cette recommandation).

La requête peut contenir des paramètres (après le ? dans l'URL).

La section 5 de notre RFC détaille les réponses possibles. Comme on utilise HTTP comme transport, tous les codes de réponse HTTP (RFC 7231, section 6) sont admissibles. Néanmoins, certains seront sans doute plus courants :

  • 200 : réponse positive, tout va bien,
  • 301 (redirection permanente, permettant de changer la méthode HTTP), 302 (redirection temporaire, permettant de changer la méthode), 307 (redirection temporaire, ne permettant pas de changer la méthode), 308 (redirection permanente, ne permettant pas de changer la méthode) : les divers codes de redirection, permettant à un « méta-serveur » d'indiquer le bon serveur RDAP dans l'en-tête Location: de la réponse (par exemple, en théorie, l'IANA pourrait avoir un serveur RDAP qui redirige vers les serveurs RDAP des TLD),
  • 404 : ce truc n'a pas été trouvé, par exemple parce que je cherche un nom de domaine qui n'existe pas,
  • 400 : requête mal formée, parce que le client RDAP est bogué ou bien parce qu'on a fabriqué une requête RDAP à la main, en se trompant,
  • 429 : on envoie trop de requêtes (ce code a été normalisé dans le RFC 6585). Aujourd'hui, les serveurs whois ont souvent ce problème de requêtes répétées, cela peut être une attaque DoS mais aussi un domaineur qui veut récolter de l'information, ou un autre type de malhonnête qui veut se constituer une base de données. Un serveur RDAP aura donc probablement une fonction de limitation du trafic, et répondra 429 si le client exagère. Les clients honnêtes ralentiront alors.

Voici quelques exemples réels avec le serveur RDAP expérimental d'APNIC et le client HTTP curl. D'abord, un cas où tout se passe bien :


% curl -v http://rdap.apnic.net/ip/2001:dc0:2001:11::194 
> GET /ip/2001:dc0:2001:11::194 HTTP/1.1
> User-Agent: curl/7.26.0
> Host: rdap.apnic.net
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Thu, 05 Mar 2015 16:08:37 GMT
< Content-Type: application/rdap+json
< Access-Control-Allow-Origin: *
< Transfer-Encoding: chunked
< Server: Jetty(9.2.z-SNAPSHOT)

Un cas où l'objet demandé n'existe pas et où le serveur renvoie le fameux code HTTP 404 :


% curl -v http://rdap.apnic.net/ip/4001:dc0:2001:11::194 
> GET /ip/4001:dc0:2001:11::194 HTTP/1.1
> User-Agent: curl/7.26.0
> Host: rdap.apnic.net
> Accept: */*
> 
< HTTP/1.1 404 Not Found

Et enfin un cas où l'objet existe chez un autre RIR et on est donc renvoyé au RIPE-NCC, avec le code normal de redirection HTTP :


% curl -v http://rdap.apnic.net/ip/2001:4b98:dc0:41:: 
> GET /ip/2001:4b98:dc0:41:: HTTP/1.1
> User-Agent: curl/7.26.0
> Host: rdap.apnic.net
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< Date: Thu, 05 Mar 2015 16:11:16 GMT
< Location: http://rdap.db.ripe.net/ip/2001:4b98:dc0:41::


Téléchargez le RFC 7480


L'article seul

RFC 7479: Using Ed25519 in SSHFP Resource Records

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : S. Moonesamy
Pour information
Première rédaction de cet article le 12 mars 2015


L'algorithme de signature Ed25519 ayant été mis en œuvre dans OpenSSH, ce nouveau RFC permet d'utiliser cet algorithme dans les enregistrements DNS SSHFP (SSH fingerprint).

Ces enregistrements SSHFP, qui permettent de trouver la clé publique d'un serveur SSH dans le DNS, sont normalisés dans le RFC 4255. Les valeurs possibles sont stockées dans un registre IANA. Ce registre est donc mis à jour pour inclure Ed25519, la valeur étant 4 (RSA était 1 et DSA 2).

Voici un exemple d'un tel enregistrement, pour la clé publique 

ssh-ed25519 
    AAAAC3NzaC1lZDI1NTE5AAAAIGPKSUTyz1HwHReFVvD5obVsALAgJRNarH4TRpNePnAS

Le condensat a été fait en SHA-256 :

ssh.example.com. IN SSHFP 4 2 ( a87f1b687ac0e57d2a081a2f2826723
                                         34d90ed316d2b818ca9580ea384d924
                                         01 )

(L'exemple est tiré du RFC mais celui-ci contient une légère bogue, je vous laisse la trouver.)

Question mises en œuvre, Ed25519 est dans OpenSSH depuis la version 6.5. D'autres logiciels utilisent cet algorithme, comme TeraTerm. Wireshark sait désormais le décoder.


Téléchargez le RFC 7479


L'article seul

RFC 7478: Web Real-Time Communication Use-cases and Requirements

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : C. Holmberg, S. Hakansson, G. Eriksson (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 30 mars 2015


Le système WebRTC permet une communication interactive et multimédia entre deux applications tournant dans un navigateur Web (d'où le nom de WebRTC). La vision est qu'Alice et Bob lanceront leur navigateur, iront sur une page qui chargera le code du logiciel (typiquement du JavaScript) et qu'ils communiqueront ensuite. Contrairement à Skype, WebRTC ne nécessitera pas l'installation d'un logiciel, et, surtout, il s'agira d'un protocole ouvert. Ce RFC, le premier du groupe de travail rtcweb, décrit certains scénarios d'usage de WebRTC, pour aider à comprendre quel rôle il joue exactement. Il ne prétend pas être un cahier des charges pour WebRTC et, bien que publié tardivement, il représente plutôt l'état d'esprit au début du projet. (WebRTC a finalement été décrit dans le RFC 8825.)

WebRTC peut permettre la communication avec des systèmes extérieurs et au moins un des scénarios décrits envisage une communication avec un téléphone SIP. Les demandes mises par ce document sur le (à cette époque) futur protocole WebRTC sont marquées Fn (où n est un entier) mais, on l'a vu, ce document ne prétend pas être un cahier des charges et WebRTC ne suivra pas forcément rigoureusement ces demandes. Les demandes marquées An concernent uniquement l'API de WebRTC (le protocole est développé par l'IETF, l'API par le W3C, oui, c'est un peu compliqué). L'annexe A contient ces exigences concernant l'API mais il faut voir le W3C pour avoir l'information fiable.

Les clients WebRTC peuvent être connectés en IPv4, en IPv6, les deux, avoir des capacités réseau très différentes, être sur des réseaux dont la capacité effective varie (liens radio, liens congestionnés), être derrière des pare-feux fascistes, et, bien sûr, être coincés derrière des NAT, des NAT de toutes les sortes (RFC 4787).

Attaquons maintenant les scénarios en commençant par le plus simple : ces chers Alice et Bob veulent discuter par vidéo. Ils ont le même opérateur WebRTC, sont informés en temps réel de la disponibilité de l'autre par une notification au navigateur, et, en cliquant sur le nom du correspondant, peuvent lui parler, l'écouter, le voir et se montrer. On a bien sûr les fonctions classiques, une petite vignette avec un retour de sa propre caméra, la capacité de couper le son pour crier une remarque à son conjoint sans que le correspondant l'entende, etc. Chaque partie peut raccrocher quand elle le veut. Évidemment, Bob et Alice ont des navigateurs de modèles différents, tournant sur des systèmes d'exploitation différents. Bien sûr, on veut de la sécurité, tout le trafic audio et vidéo doit évidemment être chiffré, authentifié et protégé contre toute modification.

De ce premier scénario d'usage, le cas le plus simple et le plus courant, on en déduit les exigences de base. Je ne vais pas toutes les citer mais en voici un échantillon, avec leur identificateur Fn :

  • F1 : le navigateur doit avoir accès au micro et à la caméra,
  • F2 : le navigateur doit pouvoir envoyer des données, même en présence de NAT (la bonne solution serait bien sûr de déployer IPv6 mais l'opposition des opérateurs rend les choses difficiles),
  • Diverses exigences sur la qualité des flux multimédia (F3, réagir à la congestion, F6, détecter que le pair ne reçoit plus rien, F8, pouvoir synchroniser audio et vidéo),
  • F11 : Protection contre les écoutes et autres « interceptions de sécurité » (RFC 2804 et RFC 7258),
  • F13 : authentification et intégrité,
  • F14 : vie privée, il doit exister un mode où Alice communique avec Bob sans lui révéler son adresse IP (possibilité de passer par un serveur pour se protéger).

Les autres exigences apparaissent au fur et à mesure des autres scénarios, qui présentent des cas de plus en plus complexes. Par exemple, Alice ou Bob est derrière un réseau fasciste ou mal configuré qui bloque complètement UDP. On en déduit l'exigence F18, pouvoir passer même quand UDP est bloqué. Variante : un réseau encore plus fasciste ou mal conçu qui n'autorise que HTTP, et via un relais. L'exigence F21 traite cas cas.

Réussir à faire passer une communication malgré les middleboxes, les pare-feux et le NAT est le grand défi des applications réseau modernes. Les solutions nécessitent en général d'utiliser STUN (RFC 8489) et TURN (RFC 8656, le tout avec ICE (RFC 8445). L'exigence F19 impose de pouvoir utiliser ces services, y compris dans le cas où il y a plusieurs serveurs STUN et TURN disponibles. F20 impose de permettre l'utilisation de serveurs STUN et TURN qui ne sont pas ceux du fournisseur WebRTC (par exemple, au sein d'une organisation qui a son propre serveur STUN).

Lorsqu'on utilise des équipements mobiles, le problème peut se compliquer par un changement de réseau en cours de communication, menant presque toujours à un changement d'adresse IP (un smartphone qui était connecté en 4G et qui rentre au bercail où il bascule vers la WiFi). F17 demande que WebRTC puisse continuer à fonctionner dans ce cas, pour éviter le « Allo, Alice, je vais passer en WiFi, je te rappelle ».

Satisfaits de ces services, Alice et Bob multiplient leur exigence. Voilà tout à coup qu'apparait dans le RFC leur désir de partager l'écran, pendant la communication, avec un tiers, que ce dernier puisse suivre ce qu'il se passe (exigence F36).

Laissons maintenant Alice et Bob tranquilles, ils ont peut-être enfin réussi à communiquer. Le RFC passe ensuite à des scénarios plus collectifs, autour du hockey. Un chercheur de talents est à un match avec son téléphone portable (qui a deux caméras, une devant et une derrière), il filme les joueurs qui lui semblent les plus prometteurs et il veut en discuter en télé-conférence avec le patron du club, à distance, et qui regarde le match transmis par le chercheur de talents. WebRTC doit donc pouvoir gérer de nombreux flux multimédias (exigence F25).

Ce genre de demandes s'étend à tout système de conférence à plusieurs, loin du cas simple des seuls Alice et Bob. WebRTC doit jongler avec les flux et de nombreux pairs qui veulent les recevoir (exigences F23 à F29).

C'est bien joli de communiquer avec les autres utilisateurs de WebRTC mais, souvent, on voudrait communiquer avec des gens qui n'ont pas WebRTC, en passant par une passerelle vers leur système, par exemple vers la téléphonie classique. Un premier exemple est celui d'un opérateur qui permet à ses abonnés de passer un appel téléphonique depuis un navigateur Web. L'utilisateur se connecte au site de l'opérateur, s'authentifie, puis appelle qui il veut, comme s'il utilisait un téléphone traditionnel. WebRTC doit donc gérer les codecs traditionnels de la téléphonie (exigence F31).

Si le service qu'on appelle a des commandes comme « pour signaler un problème, appuyez sur la touche 1 », il faut évidemment un moyen de le faire (exigence F32).

Voilà, je n'ai pas tout indiqué mais cela vous donne déjà une bonne idée de ce que WebRTC doit permettre. La section 3 de notre RFC résume toutes ces exigences de manière synthétique, si vous ne voulez pas lire tout le RFC.

Notez que, comme avec tout système qui apporte de nouvelles possibilités, il y a aussi de nouveaux risques. La section 4 liste les risques connus de WebRTC. Notamment, il faut obtenir le consentement éclairé de l'utilisateur avant de permettre l'utilisation du micro et de la caméra (songez aux facilités d'espionnage qu'on aurait si un script WebRTC sur un site Web pouvait allumer la caméra...) et il faut prévenir clairement l'utilisateur que micro et caméras sont allumés.


Téléchargez le RFC 7478


L'article seul

RFC 7477: Child To Parent Synchronization in DNS

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : W. Hardaker (Parsons)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 14 mars 2015


Le DNS est un système décentralisé, mais arborescent : toute zone (à part la racine) dépend d'une zone parente, qui doit notamment indiquer les serveurs de noms de ses zones filles. En théorie, l'information dans la zone parente et celle dans la zone fille doivent parfaitement coïncider mais, en pratique, des différences apparaissent souvent, et elles ont parfois des conséquences ennuyeuses, pouvant aller jusqu'à mettre en danger le bon fonctionnement de la zone. La principale raison de cette « désynchronisation » est qu'il n'existait aucun mécanisme standard par lequel le gestionnaire d'une zone fille pouvait transmettre à la zone parente les données à distribuer. C'est ce manque que comble notre tout nouveau RFC, avec l'introduction des enregistrements DNS de type CSYNC (Child SYNChronization).

Les deux types principaux d'enregistrement à copier de la zone fille vers la zone parente sont la liste des serveurs de noms de la zone (enregistrements NS) et les adresses IP de ces serveurs, si et seulement si leur nom est lui-même dans la zone servie, et qu'on ne peut donc pas compter sur la résolution DNS normale pour trouver les adresses. Ces adresses servies par la zone parente sont nommées colles (glue) et sont des enregistrements de type A et de type AAAA.

La résolution DNS dépend de cette information. En effet, le résolveur DNS part de la racine, et descend, de zone parente en zone fille, jusqu'à trouver l'information qu'il veut. S'il cherche www.hacklab-esgi.fr, il passera par les serveurs de la racine (qui connaissent la liste des serveurs de noms de .fr) puis par ceux de .fr (qui connaissent la liste des serveurs de hacklab-esgi.fr). Voici, reproduite avec dig, la requête qui sera envoyée à un serveur de .fr :


% dig +norecurse @d.nic.fr A www.hacklab-esgi.fr
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30993
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0

;; QUESTION SECTION:
;www.hacklab-esgi.fr.	IN A

;; AUTHORITY SECTION:
hacklab-esgi.fr.	172800 IN NS ns0.online.net.
hacklab-esgi.fr.	172800 IN NS ns1.online.net.

On y voit qu'une réponse correcte nécessite que les serveurs de l'AFNIC (ici d.nic.fr) connaissent les serveurs de hacklab-esgi.fr. Mais la liste de ces serveurs est également dans la zone :


% dig +norecurse @ns0.online.net. NS hacklab-esgi.fr 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59586
;; flags: qr aa; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;hacklab-esgi.fr.	IN NS

;; ANSWER SECTION:
hacklab-esgi.fr.	14400 IN NS ns0.online.net.
hacklab-esgi.fr.	14400 IN NS ns1.online.net.

Ce sont ces deux listes qui devraient idéalement rester synchrones. (On note au passage que la liste dans les serveurs de hacklab-esgi.fr fait autorité : on a le bit aaAuthoritative Answer - dans la réponse, alors que la copie dans les serveurs de .fr ne fait pas autorité.)

Le processus typique actuel d'avitaillement, c'est-à-dire d'enregistrement des informations nécessaires à la délégation, se fait de diverses manières. Rappelez-vous qu'il n'y avait pas de standard pour cela. Prenons deux cas dans le TLD imaginaire .example, Jeanne Michu qui gère sa zone jeanne.example sur ses propres serveurs de noms, et utilise la société Foo comme BE, et Paul Michu, moins geek, qui utilise la société Bar à la fois comme BE et comme hébergeur DNS, pour sa zone paul.example. Jeanne utilise emacs pour modifier le fichier de zone et y mettre :

jeanne.example.	IN	NS	ns1.jeanne.example.
        	IN	NS	ns2.hosted-by-a-friend.example.
ns1             IN      AAAA    2001:db8:f54::2:53

On note que Jeanne n'indique pas l'adresse IP de ns2.hosted-by-a-friend.example, qui est dans une autre zone. Elle recharge ensuite son serveur de noms pour prendre en compte les informations (nsd-control reconfig si elle utilise nsd4) et elle lance un programme qu'elle a écrit qui, utilisant l'API que le BE Foo met à la disposition de ses utilisateurs, envoie les données au BE qui les transmettra au registre, typiquement en EPP. Paul, lui, ne fait rien, il a enregistré le domaine auprès de la société Bar et celle-ci se charge de mettre l'information dans ses propres serveurs de noms, et de prévenir le registre (puisque cette société est BE). Le résultat sera le même pour les deux zones, une fois les serveurs de la zone parente mis à jour, tout sera synchrone. (Rappelez-vous que ce ne sont que deux exemples, il peut y avoir beaucoup d'autres configurations possibles.)

Là où il peut y avoir des problèmes, c'est si la communication se passe mal. Par exemple, si Jeanne se plante dans une manipulation compliquée, ou oublie. Elle modifie l'ensemble NS dans sa zone mais ne pense pas ensuite de signaler le changement au parent. Ou bien elle lance le programme qui va modifier les données chez le parent mais les informations sont rejetées par la zone parente, sauf que ce refus n'est pas transmis à la titulaire du nom de domaine. Il existe des tas de raisons qui peuvent entrainer une désynchronisation de la zone fille et de la parente. C'est ce genre de problème que veut traiter notre nouveau RFC.

La solution proposée est de créer un nouveau type d'enregistrement DNS, nommé CSYNC, que le gérant technique de la zone DNS fille mettra dans la zone, et qui indiquera quelles données de la zone doivent être recopiées dans la zone parente. Qui fera cette copie ? Ce rôle reviendra au parental agent (terme récent et pas encore traduit), qui peut être un BE (charge à lui de transmettre au registre, sans doute en EPP) ou directement le registre.

À première vue, on pourrait penser que cette technique conviendrait très bien également pour DNSSEC (et cela avait été sérieusement envisagé dans le groupe de travail), afin de permettre la synchronisation des enregistrements DS de la zone parente avec les clés (enregistrements DNSKEY) de la zone fille. Mais le cas de DNSSEC est différent (notamment parce que la zone parente fait autorité pour les DS, contrairement aux NS et colles). Un mécanisme différent est donc utilisé, normalisé dans le RFC 7344.

Un autre point que ne traite pas notre nouveau RFC est celui de la configuration initiale. La zone fille doit évidemment être sécurisée avec DNSSEC pour que la parente puisse être sûre d'avoir récupéré le bon CSYNC. La configuration initiale de DNSSEC, ainsi que celle du parental agent pour le commencement des opérations, ne font pas l'objet d'une standardisation. Les CSYNC permettent de maintenir la synchronisation, pas de la créer au début.

La section 2 de notre RFC décrit l'enregistrement CSYNC. Il est placé à l'apex (au sommet) de la zone fille. Il doit être unique. Son numéro, enregistré à l'IANA, est le 62. Ses données comportent trois champs :

  • Un numéro de série (identique à celui qu'on trouve dans le SOA de la zone),
  • Des options (décrites plus loin),
  • Une liste de types d'enregistrement à recopier dans la zone parente (en général, NS, A et AAAA). Elle est encodée selon le mécanisme un peu compliqué du RFC 4034, section 4.1.2.

Cette dernière liste est à respecter totalement ou pas du tout. Si elle compte un type que le parental agent ne connait pas, il ne doit faire aucun changement. D'une manière générale, les opérations liées à un CSYNC sont atomiques.

Voici un exemple d'enregistrement CSYNC, avec le format texte standard, pour la zone de Jeanne Michu :

jeanne.example. 3600 IN CSYNC 2015031401 1 NS AAAA

Il se lit ainsi :

  • Le numéro de série est 2015031401,
  • Les options se limitent à celle du premier bit, immediate,
  • Il faut recopier les enregistrements NS et AAAA (il n'y a pas de colle de type A dans la zone). Si vous voyez un TYPEnnn dans un enregistrement CSYNC, c'est que le type était inconnu de votre client DNS (RFC 3597, section 5).

Le numéro de série doit être une copie de celui du SOA de la zone fille, ou bien avoir une valeur supérieure (si on ne change pas les informations de délégation, on n'est pas obligé de mettre à jour le numéro de série dans le CSYNC). Voir le RFC 1982 pour une définition rigoureuse de « avoir une valeur supérieure ».

L'utilisation de ce numéro de série dépend des options (le deuxième champ). Ces options consistent en seize bits dont seulement deux sont définis aujourd'hui (tout cela est stocké dans un registre IANA, tout ajout nécessitant la rédaction d'une norme). Les deux options définies sont immediate et soaminimum.

La section 3 du RFC décrit les détails du traitement d'un enregistrement CSYNC par le parental agent. Cet agent ne doit agir automatiquement que si l'option immediate est mise (c'est le cas dans l'enregistrement d'exemple ci-dessus). Autrement, il doit attendre une validation, par exemple via une action dans une interface Web (« cette modification de vos serveurs de noms attend votre confirmation »). Quant à l'autre option normalisée, soaminimum, elle indique au parental agent qu'il ne doit copier les données indiquées que si le numéro de série de la zone (indiqué dans l'enregistrement SOA) est supérieur au numéro de série de l'enregistrement CSYNC. (Dans l'exemple plus haut, l'option soaminimum n'était pas activé et le numéro de série dans le CSYNC est donc ignoré.)

J'ai dit plus haut que la copie des données de la zone fille vers la parente devait être atomique (tout copier, ou ne rien changer). Cela ne concerne pas les TTL que la zone parente peut modifier lors de la copie.

D'autre part, la zone parente n'est pas obligée de copier les données quelles qu'elles soient. En effet, la zone parente a sa propre politique (des trucs du genre « deux serveurs de noms minimum » ou bien « je ne tiens compte de la colle que si elle concerne des serveurs qui sont dans la zone qu'ils servent », cf. section 4.3) et peut donc décider de ne pas utiliser les données fournies, rejetant ainsi la mise à jour demandée.

Voyons maintenant (en section 4) quelques problèmes concrets liés à l'utilisation de cette technique. Premier point à garder en tête, il n'y a aucun mécanisme pour remonter une erreur ou un refus (comme celui cité dans le paragraphe précédent) depuis la zone parente vers le gestionnaire de la zone fille. L'information doit donc passer par une autre voie (un message envoyé automatiquement, par exemple). Le gestionnaire de la zone fille ne doit donc pas tenir pour acquis que les données de la zone parente seront modifiées : il doit vérifier.

Le mécanisme des CSYNC nécessite une requête DNS depuis le parental agent. Si celui-ci a peu de zones à surveiller, il peut simplement faire de la scrutation répétée. Mais cela ne passe pas forcément à l'échelle. Les parental agents avec beaucoup de zones à surveiller préféreront peut-être attendre un signal explicite de la part du gérant de la zone (un bouton sur une interface Web du BE, par exemple et/ou une fonction dans l'API).

Pour faciliter la vie des gérants de zones DNS, il faudrait de toute façon que le parental agent documente ses capacités : s'il traite les CSYNC, quels types d'enregistrements accepte-t-il (à part les évidents NS, A et AAAA), le mécanisme de scrutation (à quel intervalle ?), la notification des erreurs...

Une fois que la zone parente a été modifiée, la zone fille peut-elle retirer le CSYNC ? Oui, le changement n'est fait qu'une fois, et la zone parente ne va pas l'annuler même si le CSYNC disparait après.

Le parental agent ne doit agir que si les données ont été validées par DNSSEC (section 5, sur la sécurité du mécanisme). Si votre zone n'est pas encore signée (n'avez-vous pas honte de ce retard ?), vous ne pourrez pas bénéficier des nouveaux services comme CSYNC.

Il n'y a pas encore de mise en œuvre de cette technique (mais Wireshark sait décoder ces paquets). Je serais curieux de voir une liste des parental agents potentiels qui la déploient mais, début 2015, c'est encore trop tôt.


Téléchargez le RFC 7477


L'article seul

RFC 7476: Information-centric Networking: Baseline Scenarios

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : K. Pentikousis (EICT), B. Ohlman (Ericsson), D. Corujo (Universidade de Aveiro), G. Boggia (Politecnico di Bari), G. Tyson (Queen Mary, University of London), E. Davies (Trinity College Dublin), A. Molinaro (UNIRC), S. Eum (NICT)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF icnrg
Première rédaction de cet article le 27 mars 2015


Le concept d'ICN (Information-Centric Networking) est assez à la mode en ce moment. Il désigne une conception du réseau où le composant essentiel n'est pas une machine mais une information, ayant un identificateur, et dont la récupération par l'utilisateur est le but principal de la connectivité. Ce modèle très minitélien colle bien à certains usages du réseau (comme le Web traditionnel, avant les applications Web, ou comme l'accès aux œuvres culturelles en pair à pair), ce qui explique son succès actuel. Ce RFC est le premier publié qui se penche sur ce paradigme : il décrit un certain nombre de scénarios où l'ICN a un sens.

N'attendez pas la description d'un protocole précis, c'est bien trop tôt. Ce RFC sort de l'IRTF, pas de l'IETF et est donc dans une démarche plus recherche qu'ingéniérie. Il liste des cas, étudie une bibliographie mais ne donne pas encore de solutions.

Donc, d'abord, une introduction à l'ICN (section 1 du RFC). Ses promoteurs aiment expliquer que l'Internet actuel est host-centric, c'est-à-dire construit autour de l'host, l'ordinateur ou le routeur connecté à l'Internet et identifié par une ou plusieurs adresses IP. Ces machines, ordinateurs et routeurs, sont connectées plus ou moins en permanence et, dans le modèle original, ont une connectivité de bout en bout (tout le monde peut parler à tout le monde). Le modèle ICN repose sur un changement important de paradigme : ce qui compte, c'est l'information, c'est elle qui a un identificateur, les machines ne sont pas forcément connectées tout le temps, ce qui compte, c'est qu'on puisse récupérer l'information, et peu importe si elle vient d'un serveur précis, ou d'un cache ou d'autres équipements dans le réseau. Le réseau ne transporte donc pas seulement des bits, il peut aussi servir de mécanisme de distribution. Les partisans de l'ICN utilisent souvent le terme de location independance.

Naturellement, cela change la vision qu'on a de la sécurité. Aujourd'hui, si je télécharge le rapport ANSSI « Comprendre et anticiper les attaques DDoS », ma confiance dans l'intégrité et l'authenticité de ce document vient du serveur où je l'ai récupéré (ici, un serveur de l'ANSSI) et des mécanismes techniques qui empêchent une modification en cours (comme HTTPS). En ICN, le serveur n'a plus d'importance, il faut donc bâtir la confiance sur autre chose, qui doit voyager avec l'information elle-même, comme par exemple des signatures. (Vous noterez que, contrairement à ce que prétendent les promoteurs de l'ICN, qui ne connaissent en général que HTTP, il existe plusieurs protocoles Internet qui fonctionnent ainsi depuis longtemps. Ainsi, pour le DNS, il est rare qu'on récupère l'information depuis le serveur original - qui peut être non-joignable, on passe par une série de caches, et la sécurité demande donc un mécanisme de signature, DNSSEC.)

Il existe plusieurs travaux de recherche autour de cette idée. C'est le cas de NetInf, CCN (sur lequel j'ai déjà écrit), NDN et bien d'autres. Comme le note notre RFC, c'est l'équivalent du bouillonnement que connaissait le réseau de la fin des années 70 à la fin des années 80 quand DECnet, IPX et quelques autres concurrençaient sérieusement IP, avant que ce dernier ne s'impose.

Un travail est en cours, au sein du groupe de recherche ICN, pour évaluer les différentes façons de faire de l'ICN qui existent. (Voir le RFC 8569.)

Donc, en section 2, le cœur du RFC, les scénarios envisagés. Logiquement, on commence par les usages à la mode avec les réseaux sociaux. Un gros réseau social comme Facebook doit distribuer énormément d'informations à beaucoup de gens, situés dans des endroits très divers. Le service est donc une combinaison de multicast et de cache. Le contenu est disséminé sur plein de serveurs différents et le modèle ICN convient donc particulièrement bien puisque le client veut récupérer « les photos de Mère-Grand » et pas se connecter à telle ou telle machine (cf. Mathieu, B. et al., « Information-centric networking: a natural design for social network applications » en 2012). Dans le monde merveilleux de l'ICN, un réseau social comme Twitter pourrait être bâti très simplement : un utilisateur publie son tweet, certains utilisateurs le recevront tout de suite (ceux qui sont connectés), les autres le récupéreront à partir d'un cache dans le réseau dès qu'ils seront connectés. L'article de Kim, J. et al. « Content Centric Network-based Virtual Private Community » de 2011 décrit plus en détail cette vision, que le RFC qualifie, de manière franchement baratineuse, de serverless (il y a bien des serveurs, même s'ils ne sont pas explicitement nommés).

Autre scénario d'usage possible, la communication en temps-réel, avec multimédia, par exemple des services comme Skype. Cela inclut des communications entre deux personnes, des conférences d'un groupe de personnes, des ressources partagées comme un tableau virtuel où tout le monde peut écrire, etc. Le tout est soumis à des contraintes de performance assez strictes. Contrairement au scénario précédent, celui-ci semble aux antipodes de l'ICN, puisqu'il s'agit d'échanger et non plus d'« accéder à du contenu ». Et, pourtant, il y a déjà eu des recherches à ce sujet (j'en ai mentionné une dans mon article sur le CCN).

Le RFC cite également un exemple de MMORPG fait en ICN, par Chen, J. et al., « G-COPSS: A Content Centric Communication Infrastructure for Gaming Applications » en 2012.

Peut-on utiliser l'ICN pour le partage d'infrastructures, comme la capacité disque ou réseau ? Le RFC dit que oui, en se basant sur le fait que l'ICN sécurise des objets et pas des canaux de communication et permet donc le partage de ressources. Par exemple, toute machine avec suffisamment de place disque peut devenir un cache. Nul besoin de lui faire confiance, puisque les objets seront sécurisés (par exemple par le biais d'une signature qui leur sera attachée). Cette possibilité est creusée dans l'article de Jacobson, V. et al, « Custodian-Based Information Sharing » en 2012 mais aussi dans le cas de trafic HTTP classique (Psaras, I. et al., « Modelling and Evaluation of CCN- Caching Trees », 2011) ou de trafic BitTorrent (Tyson, G. et al., « A Trace-Driven Analysis of Caching in Content-Centric Networks », 2012). Les CDN actuels font déjà un travail analogue, mais au prix d'une configuration manuelle plus importante.

Si, arrivé à ce stade, vous pensez qu'il y a beaucoup de promesses et peu de réalisations concrètes, je dirais que vous avez tout à fait raison. L'ICN, c'est beaucoup de marketing, faisant miroiter d'extraordinaires changements positifs et se souciant peu des vulgaires problèmes pratiques. Il y a toutefois des applications plus raisonnables comme la distribution de contenu, certes le scénario le plus réaliste puisque l'ICN voit tout comme du contenu. Il est donc logique que ce soit le domaine où l'ICN ait été le plus étudié, voyez le RFC (section 2.5) pour une bonne bibliographie.

Autre exemple marketing et spectaculaire, les réseaux dans les véhicules en mouvement (les VANET). Aussi bien la communication entre véhicules, que celle entre le véhicule et des stations fixes, posent des problèmes très difficiles, et sont un vrai défi pour les concepteurs de réseaux. La topologie change très vite (à la vitesse du véhicule), et la connectivité n'est pas permanente. On est dans un cas adapté à l'ICN où on se soucie moins de qui a envoyé l'information, que de l'information elle-même. Les caches et la réplication de l'information seront certainement utiles ici.

Vous trouvez ce scénario trop terrestre ? Plus en altitude, il y a les réseaux spatiaux, voire interplanétaires. Le concept de DTN (Delay-Tolerant Networking) était né autour des voyages dans l'espace mais peut s'appliquer à d'autres secteurs (comme les sous-marins ou comme des réseaux très perturbés, par exemple suite à une catastrophe naturelle). Comme son nom l'indique, le DTN est conçu pour des cas où le délai d'acheminement d'un bit d'une machine à une autre est tel que les protocoles de transport traditionnels comme TCP ne fonctionneront jamais. (On ne pourra jamais terminer une « triple poignée de mains » dans les temps, par exemple.) En plus du délai d'acheminement, le monde du DTN se caractérise par le fait que la connectivité est l'exception, plutôt que la règle. Pour travailler dans ces conditions, les systèmes DTN (RFC 4838) retrouvent l'architecture « store and forward » des anciens protocoles comme UUCP. Tout routeur est également un serveur de stockage et un cache, et garde l'information au moins jusqu'à ce qu'il ait pu la transmettre à quelqu'un d'autre. Le stockage se fait donc en partie dans le réseau. Ce paradigme peut même s'étendre au cas où certaines des communications se font par un mécanisme de « mule de données », de transport d'un mécanisme de stockage physique (une clé USB, par exemple). Le DTN et ICN ont en commun qu'il n'imposent pas une connectivité permanente et ils pourraient donc, en théorie, bien s'entendre ensemble (Tyson, G., Bigham, J. et E. Bodanese, « Towards an Information-Centric Delay-Tolerant Network », 2013). De plus, les deux paradigmes reposent sur le traitement de l'information comme étant un objet en soi (que le DTN nomme un bundle), à longue durée de vie.

Une variante de ce scénario où le contenu est distribué entre des machines à la connectivité intermittente est celle du « partage de données selon l'occasion » où des informations sont disponibles et seront récupérées si on passe à côté. L'exemple typique (mais non cité par le RFC...) est celui de la PirateBox, qui attend tranquillement d'éventuels visiteurs. Le RFC préfère un cas où les deux parties sont mobiles, et où on distribue des tweets (Hossmann, T., et al. « Twitter in disaster mode: smart probing for opportunistic peers », 2012).

Seconde variante, celle où on distribue de l'information pendant une crise majeure, ayant mené à une importante perturbation des réseaux, perturbation d'autant plus sérieuse que l'énergie manque elle aussi, stoppant ainsi les équipements réseau qui n'avaient pas été mis hors de service pendant la crise. Les DTN peuvent se montrer très utiles dans ce cas, par exemple pour distribuer efficacement l'information utile (comme les alertes, ou l'emplacement des camps de réfugiés). Comme avec tous les réseaux pair-à-pair se posera le problème de la motivation à participer : si le tremblement de terre a frappé et que je me retrouve à la rue avec un smartphone qui n'a plus qu'une heure de batterie, sans espoir de recharge proche, pourquoi est-ce que je consacrerai ces précieux watt-heures à router des messages pour les autres ? Peut-être faudra-t-il compter uniquement sur les équipements apportés par les premiers secours ?

On l'a vu, l'ICN repose sur beaucoup de buzzwords et de promesses aussi floues que mirobolantes. Il était donc inévitable que le super-buzzword Internet des objets soit mentionné dans ce RFC. On sait que les progrès du matériel font que de nombreux objets qui n'étaient pas vus comme des ordinateurs sont désormais connectés à un réseau et même parfois à l'Internet. Prenons les capteurs, par exemple : on peut envisager plein de capteurs dispersés un peu partout, récoltant plein d'informations utiles, auxquelles il faut ensuite accéder. Les idées de l'ICN comme le cache réparti peuvent être utiles ici (cf. l'Internet-Draft de Kutscher, D. et S. Farrell, « Towards an Information-Centric Internet with more Things », présenté à l'atelier Interconnecting Smart Objects with the Internet de l'IAB, en 2011, atelier décrit dans le RFC 6574, ou bien les très nombreuses références citées dans la section 2.8).

Un des points difficiles de tout réseau informatique est le nommage, et le RFC cite ici les possibilités de nommer directement le contenu, ce que permettent par exemple les URI ni: du RFC 6920 (un exemple concret et utile). Par contre, le RFC ne cite pas les magnets mais il est vrai qu'ils n'ont jamais fait l'objet d'une standardisation rigoureuse.

Autre buzzword à ne pas manquer, la smart city. Le RFC tourne ici franchement au discours marketing, avec des envolées sur l'interaction des smart people avec la smart city, le tout sous l'égide d'une bienveillante smart governance.

Assez de scénarios d'usage, la section 3 du RFC passe ensuite aux questions transversales, communes à plusieurs scénarios. Cette fois, il y a davantage de concret. Premier problème, évidemment, le fric. La section 3.1 se penche sur l'économie de la connectivité. Par exemple, les engins connectés auront de plus en plus souvent le choix entre plusieurs connexions (pensez aux smartphones actuels, avec leur choix entre WiFi et 3G) et intégreront probablement des considérations financières dans leur choix. L'accès aux données indépendamment d'un serveur précis est ici utile, pour laisser davantage de liberté de choix aux engins connectés. À condition, comme toujours en économie, que les acteurs rationnels et égoïstes d'Adam Smith soient parfaitement informés des conséquences de leur choix. Le RFC note donc qu'il faudra un travail en ce sens, avec des offres simples et claires, et distribuées automatiquement aux engins qui auront à faire des choix de connectivité.

Ces questions de sous dans les réseaux ne concernent évidemment pas que la machine terminale mais également les opérateurs. L'ICN leur offre de nouvelles possibilités (le déploiement de caches dans leur réseau, automatiquement utilisés par les clients, permet de diminuer les coûts liés à la connectivité externe). Là encore, le RFC cite énormément de références vers des travaux existants.

Autre sujet transversal qui a une grande importance (tout à fait justifiée) aujourd'hui, la consommation énergétique. Le problème est bien réel (les factures d'électricité augmentent, la pollution et les autres conséquences pour l'environnment aussi, les petits objets n'ayant qu'une batterie à capacité limitée souhaitent faire des économies d'électricité) mais son traitement dans le RFC est très décevant : ce ne sont que des vagues promesses comme quoi l'ICN permettrait de diminuer la consommation électrique. L'idée est que l'utilisation massive de caches, le traitement des données dans le réseau lui-même et pas dans les extrémités, et enfin la non-obligation d'être connecté en permanence seraient plus efficace énergétiquement. Le RFC cite plusieurs études dont j'ai l'impression qu'elles sont purement théoriques, sans mesures effectives.

Autre question qui s'applique à plusieurs scénarios d'usage de l'ICN, le cas où des réseaux de différents types, n'utilisant pas tous IP, sont disponibles. Dans le modèle original, dit du sablier, IP formait la ceinture, le point de passage obligé (aujourd'hui, dans la réalité, c'est plutôt HTTP qui joue ce rôle). Dans un monde qui utilise massivement l'ICN, ce pourrait être ICN qui serait la ceinture, l'unificateur de toutes les interactions (Trossen, D. et al., « Arguments for an information centric internetworking architecture », 2010). Les auteurs du RFC sont évidemment conscients du caractère très spéculatif de ce projet, et notent que bien des points restent à résoudre pour avancer dans ce sens, comme la sécurité (traitée plus en détail, par la suite, dans le RFC 7927).


Téléchargez le RFC 7476


L'article seul

RFC 7475: Increasing the Number of Area Directors in an IETF Area

Date de publication du RFC : Mars 2015
Auteur(s) du RFC : S. Dawkins (Huawei)
Première rédaction de cet article le 11 mars 2015


Un court RFC bureaucratique pour faire passer de deux à « plus de deux » le nombre maximum de directeurs de chaque zone d'activité de l'IETF.

L'IETF a en effet ses activités divisées en plusieurs zones (areas), chacune sous la responsabilité de directeurs (Area Directors qui, ensemble, forment l'IESG). Le RFC 2026 fixait (section 14) ce nombre de directeurs à « un ou deux » (même chose en section 1 du RFC 2418). Aujourd'hui, c'est presque toujours deux, mais ce chiffre a varié dans le temps (voir le RFC 1396 pour un passé lointain). Ce nouveau RFC 7475 fait sauter cette limite. Cela ne devrait pas trop changer la taille de l'IESG, l'idée est que cette possibilité ne soit utilisée que rarement.

L'IESG a une grande latitude en ce qui concerne la répartition de l'IETF en zones : le nombre de zones ou leur ampleur n'est pas contrainte par aucun document. On pourrait donc imaginer moins de zones mais de plus grande ampleur, et deux directeurs risqueraient alors de ne pas suffire.

Donc, le texte des RFC 2026 et RFC 2418 est modifié pour remplacer « un ou deux [directeurs] » par « un ou plus ».


Téléchargez le RFC 7475


L'article seul

RFC 7469: Public Key Pinning Extension for HTTP

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : C. Evans, C. Palmer, R. Sleevi (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF websec
Première rédaction de cet article le 18 avril 2015
Dernière mise à jour le 19 novembre 2019


Depuis que les piratages de Comodo et DigiNotar ont fait prendre conscience du peu de sécurité qu'apportent les certificats X.509, plusieurs solutions ont été proposées pour combler les failles des autorités de certification. La proposition de ce RFC, HPKP (HTTP Public Key Pinning), consistait à permettre à un client d'épingler (to pin) les clés cryptographiques d'un serveur HTTP utilisant TLS, c'est-à-dire à s'en souvenir pendant une durée spécifiée par le serveur. Ainsi, même si un faux certificat est émis par une AC, il ne serait pas accepté. En pratique, HPKP a été peu adopté et semble aujourd'hui en voie d'abandon.

Un exemple plus récent d'un « vrai / faux certificat » (certificat vrai car émis par une AC reconnue, mais faux car émis sans l'autorisation du titulaire du nom de domaine, et dans l'intention de tromper les utilisateurs) est celui du ministère des finances français. Comme souvent avec les certificats mensongers, celui-ci visait Google (je soupçonne fort que le but était de lire le courrier Gmail des employés, mais, à Bercy, on dément, et on affirme que les buts étaient de pouvoir effectuer un filtrage du contenu sur le Web externe, et de passer les flux à l'antivirus) et c'est ce qui explique que cette compagnie soit très présente dans les forums comme l'IETF où on cherche des solutions aux sérieuses faiblesses de X.509. Parmi les solutions élaborées, il y a DANE, qui s'appuie sur le DNS (RFC 6698), mais Google préfère les certificats à la lumière du jour du RFC 6962 et l'épinglage (pinning) des clés, dans ce tout nouveau RFC 7469.

À noter qu'il existe déjà des en-têtes HTTP permettant au serveur de spécifier au client son comportement, comme le HSTS du RFC 6797. Mais l'épinglage de clés est indépendant de HSTS.

L'épinglage fait partie des techniques TOFU (Trust On First Use) : la première fois qu'un client se connecte au serveur, il ne peut pas savoir si la clé est bonne (il doit se fier à la validation X.509, avec ses limites). À la première connexion, le client HTTP (par exemple un navigateur Web) doit espérer qu'il n'y a pas d'homme du milieu ayant réussi à obtenir un faux certificat (pour cette raison, une attaque persistente, comme celle du ministère des finances, citée plus haut, ne serait pas empêchée par l'épinglage). Aux connexions suivantes, le client HTTP pourra par contre vérifier l'identité du serveur, grâce à la clé épinglée, c'est-à-dire gardée en mémoire. Ce n'est pas idéal (imaginez un homme du milieu ayant un faux certificat pour la première connexion et épinglant ses propres clés, empêchant ainsi toute correction ultérieure !) mais c'est un progrès sur la situation actuelle (valider les clés est un problème difficile en cryptographie). À part des clés partagées à l'avance directement entre les correspondants (ce qui ne passerait évidemment pas à l'échelle pour le Web entier), il n'y a pas de solution parfaitement sûre pour la validation des clés.

La section 2 décrit les détails pratiques. Elle définit un nouvel en-tête HTTP, Public-Key-Pins:. Présent dans une réponse HTTPS, cet en-tête indique au client HTTP que ce serait souhaitable qu'il épingle, qu'il mémorise, la clé publique. Le contenu de l'en-tête Public-Key-Pins: est le condensat de la clé publique utilisée pour TLS, condensat encodé en Base64 (RFC 4648). L'algorithme de condensation est indiqué dans la valeur de l'en-tête. Aujourd'hui, c'est forcément SHA-256 (RFC 6234). La clé est l'encodage DER du champ subjectPublicKeyInfo du certificat X.509 (à noter que les cas des clés brutes du RFC 7250 ou des clés PGP du RFC 6091 ne semblent pas traités, car elles n'ont pas les problèmes des certificats X.509). Une directive max-age est obligatoire dans l'en-tête HTTP, pour indiquer le nombre de secondes que doit durer l'épinglage (après quoi le client HTTP « oublie » la clé). Voici un exemple :

Public-Key-Pins: max-age=604800;
       pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="

Il existe aussi deux directives facultatives. includeSubDomains indique que l'épinglage s'applique aussi aux serveurs dont le nom est un sous-domaine de celui-ci. Si le client se connecte en HTTPS à bar.example.com et reçoit un Public-Key-Pins: avec includeSubDomains, et qu'il se connecte plus tard à foo.bar.example.com, il exigera de trouver la clé épinglée (voir la section 4.2 pour quelques pièges de cette directive). Autre directive facultative, report-uri indique à quel URI le client doit signaler les erreurs résultant de l'épinglage. En effet, on peut prévoir que, comme avec toute technique de sécurité, il y aura des problèmes. Par exemple, des webmestres changeront de clé et oublieront de modifier le Public-Key-Pins:. Il est donc important que ces problèmes soient détectés rapidement. Ce signalement se fera selon la technique décrite plus loin en section 3. Attention aux conséquences pour la vie privée ! La très détaillée section 5 couvre ce risque d'intrusivité. Voici un exemple avec ces deux directives, et l'utilisation de plusieurs clés (par exemple parce qu'un remplacement est en cours) :

Public-Key-Pins: max-age=2592000;
       pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
       pin-sha256="LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=";
       includeSubDomains;
       report-uri="https://other.example.net/pkp-report"

À noter qu'un deuxième en-tête est défini, Public-Key-Pins-Report-Only:, qui a exactement la même syntaxe, mais une sémantique différente : le client HTTP teste la clé épinglée et, si elle est fausse, le signale à l'URI indiqué par report-uri (qui devient donc obligatoire), mais n'empêche pas l'accès au serveur. C'est utile pour tester avant le vrai déploiement. Les deux en-têtes sont désormais dans le registre des en-têtes.

Comme indiqué plus haut, la section 3 décrit la façon dont un client HTTP peut signaler une erreur de validation. Pour cela, le client HTTP doit fabriquer un message en JSON (RFC 8259) et l'envoyer avec la méthode POST de HTTP à l'URI indiqué dans la directive report-uri. Voici un exemple d'un tel message (la date est au format du RFC 3339) :

 {
    "date-time": "2014-04-06T13:00:50Z",
    "hostname": "www.example.com",
    "port": 443,
    "effective-expiration-date": "2014-05-01T12:40:50Z"
    "served-certificate-chain": [
      "-----BEGIN CERTIFICATE-----\n
      MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n
      ...
    ],
    "validated-certificate-chain": [
      "-----BEGIN CERTIFICATE-----\n
      MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n
      ...
    ],
    "known-pins": [
      'pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="',
      "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""
    ]
  }

Comme souvent en sécurité, le diable est dans les détails, et c'est ce qui explique que la section 4, l'obligatoire « Security Considerations » soit particulièrement longue. Par exemple, l'épinglage peut avoir des conséquences néfastes si on s'est fait voler sa clé privée : normalement, on génère une nouvelle clé, un nouveau certificat et on demande à l'AC de re-signer. Mais on ne pourra pas l'utiliser car la clé publique correspondant à la clé volée est toujours épinglée dans des tas de navigateurs. On peut réduire ce problème en diminuant la durée d'épinglage. Mais, alors, on réduit aussi la durée de la protection dans le cas où une AC génère un certificat mensonger. Un compromis est donc nécessaire. Une approche possible est d'épingler, non pas la clé du serveur mais une clé intermédiaire dans la chaîne des certificats. Supposons que la société Example, qui gère example.com soit cliente de l'AC SmallAC qui a elle-même son certificat signé par une AC très largement reconnue, BigAC. En épinglant la clé de SmallAC, on se protège contre un vol de la clé privée d'example.com, et contre un faux certificat, même émis par BigAC. La société Example reste vulnérable à un faux certificat produit par SmallAC mais cela diminue sérieusement le nombre d'acteurs qui peuvent attaquer Example. (Notez que DANE a les mêmes possibilités : on peut publier dans le DNS sa propre clé, ou bien celle d'une AC.)

On a vu plus haut qu'on pouvait avoir plusieurs clés dans l'en-tête Public-Key-Pins:. Une des utilisations de cette possibilité est le cas où on a une clé de réserve (backup pin), non utilisée mais gardée en un endroit différent de la clé du certificat actuel. Ainsi, si, pour une raison ou pour une autre, la clé est inutilisable, la clé de réserve peut prendre le relais immédiatement puisqu'elle est déjà épinglée.

Autre cas où l'épinglage peut avoir un effet néfaste, celui de l'épinglage hostile. Imaginons un méchant qui obtienne un faux certificat. Il détourne le trafic (par exemple par un empoisonnement DNS) et envoie les gens vers son serveur HTTPS, qui semblera légitime, en raison du faux certificat. Avec l'épinglage, il peut même prolonger son attaque en épinglant sa clé. Si le site légitime n'avait pas été visité avant, ou s'il ne faisait pas d'épinglage, l'attaque peut réussir, bloquant le client HTTPS sur la clé de l'agresseur pour la durée max-age spécifiée par ledit agresseur. Il n'y a pas de solution miracle pour ce problème. Une possibilité est de précharger les clés de sites connus dans le navigateur. Une autre est d'utiliser les certificats au grand jour du RFC 6962. (Et, bien sûr, il y a DANE, RFC 6698, que Google prend toujours soin de ne pas mentionner.)

Autres risques, ceux pour la vie privée (section 5). Un serveur peu sympathique peut utiliser l'épinglage comme une sorte de cookie discret. Par exemple, il peut mettre une petite image dans un sous-domaine, épingler des fausses clés pour ce sous-domaine (une différente par visiteur) et attendre les signalements à report-uri pour identifier un client HTTPS unique. Des sites différents peuvent même coopérer pour avoir le même report-uri, pour suivre un client à travers plusieurs sites.

À noter aussi que les signalements d'un problème de validation contiennent la chaîne de certificats utilisée. Cela peut permettre d'identifier l'utilisation de faux certificats par telle ou telle organisation. C'est plutôt une bonne chose pour détecter des attaques comme celle effectuée au ministère des finances mais cela ne sera évidemment pas apprécié de ceux qui veulent faire du détournement de trafic.

Comme toujours en sécurité, l'utilisabilité est cruciale (section 7). Lorsqu'un épinglage a eu lieu, et que le trafic est ensuite détourné vers un faux serveur, le client HTTPS (par exemple le navigateur Web) va refuser l'accès à ce faux serveur ce qui, du point de vue de M. Toutlemonde devant son navigateur, est un déni de service. Il va donc falloir bien expliquer à M. Toutlemonde ce qui se passe, pour éviter qu'il n'accuse le site légitime.

Le RFC recommande aussi que l'utilisateur puisse accéder facilement à la liste des clés épinglées et aussi, ce qui me semble plus contestable, qu'il puisse la modifier, par exemple en désépinglant les clés. Cela me semble dangereux car cela peut ouvrir une voie à l'ingénierie sociale (« il y a un petit problème technique, si l'accès vous est refusé, cliquez sur Clear all pinned keys »).

L'annexe A contient un exemple, utilisant OpenSSL en ligne de commande, pour générer le Public-Key-Pins:. J'en ai fait un petit script qui s'utilise ainsi :

% make-pin.sh www.ietf.org
...
DHKscLdFrBmZiBGxMdZiyaxp29vnyyPltRS1ZmTF09Y=

Et hop, on n'a plus qu'à mettre Public-Key-Pins: max-age=604800; pin-sha256="DHKscLdFrBmZiBGxMdZiyaxp29vnyyPltRS1ZmTF09Y=" dans la réponse du serveur HTTP. (Tom me fait remarquer à juste titre qu'une clé de secours est obligatoire - section 4.3 - et que donc il faut toujours au moins deux pin-sha256. J'ai simplifié.) Les premières versions de l'Internet-Draft qui a mené à ce RFC utilisaient un programme en Go, make-pin.go :

% openssl s_client -servername www.ietf.org -connect www.ietf.org:443 > ietf.pem
...
% ./make-pin ietf.pem 
Hex: 0c72ac70b745ac19998811b131d662c9ac69dbdbe7cb23e5b514b56664c5d3d6
Base64: DHKscLdFrBmZiBGxMdZiyaxp29vnyyPltRS1ZmTF09Y=

À noter que l'annexe B contient quelques conseils pratiques à l'usage des gérants de serveurs HTTPS, sur le bon déploiement de l'épinglage. Par exemple, il est recommandé de commencer doucement, en mode report-only avant de se jeter dans le grand bain et de risquer de bloquer ses clients. Comme avec n'importe quelle technique de sécurité, on risque de se planter soi-même si on ne fait pas attention : n'épinglez pas bêtement !

Question mises en œuvre, Chrome et Firefox avaient déjà de l'épinglage, avec une série de clés mise en dur dans le logiciel (voir la description de Mozilla et leur annonce). Vous pouvez tester ici si votre navigateur gère l'épinglage. Une description de l'épinglage des clés dans Chrome avait été faite par Adam Langley et sa lecture est recommandée (par exemple pour comprendre pourquoi on épingle juste des clés et pas des certificats entiers). Pour le monde Microsoft, voir leur article. Il y aussi un article détaillé sur le concept, chez OWASP, et l'article de Robert Love avec des détails pratiques. Le peu de succès de HPKP fait que Firefox, par exemple, a annoncé son intention de l'abandonner (cf. ticket #1412438.)

Merci à Florian Maury et Kim Minh Kaplan pour leur relecture.


Téléchargez le RFC 7469


L'article seul

RFC 7465: Prohibiting RC4 Cipher Suites

Date de publication du RFC : Février 2015
Auteur(s) du RFC : A. Popov (Microsoft)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 19 février 2015


Fini, RC4, au moins dans TLS ! Cet algorithme de cryptographie, qui était secret à l'origine et prétendait être ainsi plus sûr, a fait l'objet de tellement d'attaques cryptanalytiques réussies qu'il ne doit plus être utilisé dans le protocole TLS.

Normalisé dans le RFC 5246, TLS sécurise un grand nombre de protocoles TCP/IP, le plus connu étant HTTP. Comme tous les protocoles IETF utilisant la cryptographie, il n'est pas lié à un algorithme de cryptographie particulier. En effet, les progrès de la cryptanalyse font que les algorithmes qui semblaient sûrs à une époque ne durent pas forcément éternellement. Il est donc crucial de permettre l'arrivée de nouveaux algorithmes, et le retrait des vieux (comme cela a été fait pour MD5, cf. RFC 6151). C'est ce qu'on nomme l'agilité cryptographique. Dans TLS, la liste des algorithmes acceptés est enregistrée à l'IANA et ceux acceptés par le client TLS sont transmis au début de la négociation, dans le message ClientHello (RFC 5246, section 7.4.1.2). Parmi ceux proposés, le serveur en choisira un et l'indiquera dans le message ServerHello (RFC 5246, section 7.4.1.3). (En fait, c'est un peu plus compliqué, le client transmet des suites, chaque suite contenant plusieurs algorithmes, notamment un asymétrique, et un symétrique comme l'est RC4. Par exemple, TLS_ECDH_ECDSA_WITH_RC4_128_SHA est l'algorithme asymétrique ECDSA avec RC4) Depuis ce RFC 7465, les suites cryptographiques utilisant RC4 ne doivent plus apparaître dans ces messages.

RC4 n'a pas été normalisé (il était secret au début, un exemple illustrant bien la vanité de la sécurité par l'obscurité) mais a été documenté dans le livre de Schneier, « Applied Cryptography » (à partir de la deuxième édition). Parmi les attaques réussies contre RC4 :

Toutes ces attaques ne sont pas forcément exploitables de manière réaliste. Mais la cryptanalyse progresse tous les jours. Si l'attaque est un peu trop dure aujourd'hui, elle sera possible demain et triviale après-demain (sans compter le fait qu'en cryptanalyse, tout n'est pas publié, certaines organisations ne disent pas ce qu'elles font). Notre RFC estime qu'aujourd'hui, ces attaques sont presque utilisables en pratique. Il est donc temps de virer RC4.

La section 2 est donc simple et courte : le client TLS ne doit plus indiquer de suite cryptographique utilisant RC4 et, s'il le fait, le serveur ne doit plus les sélectionner. Si la totalité des suites proposées par le client utilise RC4, le serveur doit rejeter la connexion, en utilisant l'alerte insufficient_security(71) (cf. RFC 5246, section 7.2). Ce dernier point avait fait l'objet d'un débat dans le groupe de travail, car il revient à rejeter complètement certaines mises en œuvre de TLS (rappelons que certains sont toujours incapables de parler les versions 1.1 et 1.2 de TLS, malgré les failles de sécurité que cela cause). Toutefois, ce cas de logiciels ne gérant que RC4 semble rare dans la nature.

Par contre, le registre IANA ne dispose pas d'un moyen pour indiquer cette obsolescence de RC4 donc des programmeurs / administrateurs système distraits ne feront peut-être pas attention à ce RFC. Diffusez-le largement !

Un exemple de faille de sécurité récente (publiée un mois après le RFC) concernant RC4 : la faille Invariance Weakness. Un autre exemple est présenté sur Numerous Occurrence MOnitoring & Recovery Exploit.


Téléchargez le RFC 7465


L'article seul

RFC 7464: JavaScript Object Notation (JSON) Text Sequences

Date de publication du RFC : Février 2015
Auteur(s) du RFC : N. Williams (Cryptonector)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF json
Première rédaction de cet article le 26 février 2015


Un document JSON est normalement formé d'un texte JSON tel qu'un tableau ou un objet. Mais certains usages de JSON auraient besoin d'un autre genre de documents, une suite de textes JSON, séparés par un caractère de séparation bien défini. C'est ce que normalise ce RFC. Le nouveau type de document, application/json-seq, est formé d'une suite de textes JSON, séparés par les caractères ASCII U+001E, alias RS (record separator) et U+000A, alias LF (line feed).

JSON est normalisé dans le RFC 8259. Il est très utilisé dans un grand nombre de contextes. Du fait qu'un document JSON est un texte JSON (par exemple un objet ou un tableau), une grande partie des analyseurs JSON lisent tout et mettent tout en mémoire avant de le passer à l'application. Ce n'est pas bien adapté au cas où on écrit du JSON dans un journal, par exemple, et où on ne connait pas à l'avance la fin du document. Souvent, il n'y a pas à proprement parler de fin, et on ne peut donc pas utiliser un tableau car on ne saurait pas où mettre le ] final. Pire, imaginons une séquence d'un million d'entrées, chacune faisant un kilo-octet. Avec un analyseur ordinaire, cela ferait un giga-octet à mettre en mémoire, une quantité non triviale. Certes, il existe des analyseurs en flux (streaming), mais ils ne sont pas très répandus, et notre RFC les trouve difficiles d'utilisation.

D'où l'idée de ce RFC : une séquence de textes JSON, qui n'est pas elle-même un texte JSON, et qui peut être produite et consommée de manière incrémentale.

La définition rigoureuse figure en section 2. À noter que deux grammaires ABNF sont données, une pour les générateurs de séquences JSON et une pour les analyseurs. En application du principe de robustesse, la grammaire est plus tolérante pour les seconds : elle permet que les membres d'une séquence ne soient pas des textes JSON valides, afin que l'analyseur puisse continuer à traiter la séquence (cf. section 2.3). En revanche, le générateur doit produire une séquence composée uniquement de textes JSON valides. La grammaire stricte, pour les générateurs, est donc :


JSON-sequence = *(RS JSON-text LF)
     
RS = %x1E
LF = %x0A

JSON-text = <given by RFC7159, using UTF-8 encoding>

RS et LF sont définis dans le RFC 20. À noter que RS, caractère ASCII très peu utilisé, se nomme Record Separator en ASCII mais INFORMATION SEPARATOR TWO dans Unicode. Le choix de ce séparateur a suscité d'intenses débats dans le groupe de travail, avant que le consensus se fasse sur RS. En langue naturelle, cette grammaire se résume en « une séquence JSON est composée d'un nombre quelconque de textes JSON, chacun précédé d'un RS et suivi d'un LF ». Ils sont forcément encodés en UTF-8 (RFC 3629). Comme RS est un caractère de contrôle, il ne peut pas apparaitre directement dans un texte JSON (RFC 8259, section 7) et il n'y a donc pas de risque de collision avec un vrai RS. Je laisse mes lecteurs aventureux chercher comment on entre un caractère RS dans un fichier, avec leur éditeur favori...

Autre grammaire, plus laxiste, pour les analyseurs. Elle est :


JSON-sequence = *(1*RS possible-JSON)
...
possible-JSON = 1*(not-RS)
not-RS = %x00-1d / %x1f-ff; any octets other than RS

Elle est bien plus tolérante que la grammaire du générateur. L'idée est que, si l'analyse d'un texte « possiblement JSON » échoue, l'analyseur pourra sauter au suivant (éventuellement en signalant à l'application qu'il y a eu un problème) et traiter le reste de la séquence. Comme le décrit bien la section 2.3, une erreur n'est pas forcément fatale. Si l'analyseur était trop puriste, il ne pourrait pas traiter un journal où certaines entrées ont été tronquées (et ne sont donc plus des textes JSON valides) suite à, par exemple, un disque plein.

Ce principe de robustesse ne pose pas de problèmes si les textes JSON sont des tableaux ou des objets : une éventuelle troncation se détecte sans ambiguité. Ainsi, [116, 943, 234, 3879 a clairement été tronqué (il manque le crochet final). Il y a davantage de problèmes dans les cas où les textes JSON sont des entiers ou des littéraux comme true. Si on trouve 3879, était-ce bien 3879 ou bien la troncation d'un entier plus long ? C'est là que le LF (U+000A) à la fin de chaque texte JSON est utile, comme canari pour détecter une troncation. Un analyseur doit donc vérifier sa présence (le RFC est plus tolérant, en acceptant n'importe quel ws - RFC 8259, section 2) si le texte JSON n'était pas auto-délimité (les tableaux, objets et chaînes sont auto-délimités, mais pas les nombres ou certains littéraux comme null).

Au passage, un mot sur la sécurité (section 3) : les analyseurs de séquences JSON, comme tous les analyseurs de JSON, seront souvent utilisés sur des documents venus de l'extérieur, pas forcément validés. Ils doivent donc être robustes et ne pas faire de buffer overflow sous prétexte qu'ils rencontrent du JSON bizarre. Et, si vous voulez signer vos séquences JSON, n'oubliez pas que JSON n'a pas de forme canonique, et les séquences encore moins (comme l'analyseur est plus laxiste que le générateur, lire et écrire une séquence peut la changer, par exemple en ajoutant des LF à la fin des textes). Toute opération peut donc potentiellement invalider une signature.

Question mises en œuvre, il semble (je n'ai pas encore testé) que le couteau suisse de JSON, jq, gère ce nouveau format.

Notez un format proche (mais différent : ce serait trop simple autrement), JSON Lines.


Téléchargez le RFC 7464


L'article seul

RFC 7459: Representation of Uncertainty and Confidence in PIDF-LO

Date de publication du RFC : Février 2015
Auteur(s) du RFC : M. Thomson (Mozilla), J. Winterbottom (Unaffiliated)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF geopriv
Première rédaction de cet article le 27 février 2015


Le format PIDF-LO (Presence Information Data Format - Location Object, RFC 4119) permet de représenter la position présente d'un objet mobile. Ce nouveau RFC est consacré à la représentation de l'incertitude sur la position de cet objet, et ajoute un moyen d'indiquer la confiance qu'on a sur la position de cet objet. Ce RFC fournit également des indications sur le comportement à avoir lorsqu'on reçoit de l'information imprécise ou incertaine.

Le cadre général sur le service de localisation est présenté dans le RFC 6280. Idéalement, la localisation de la cible (oui, le RFC utilise le terme de target, ce qui est un peu effrayant) est connue parfaitement. Dans la réalité, on n'a pas une précision infinie, et on a même des doutes sur l'exactitude de la localisation. Il faut donc pouvoir représenter ce manque de précision et ces doutes, à la fois par un vocabulaire commun et par un format standard (une extension du PIDF-LO, Presence Information Data Format - Location Object du RFC 4119). Notez que l'IETF, dans ses RFC, ne normalise pas comment on arrive à déterminer une localisation. Il existe de nombreuses méthodes (triangulation entre les relais de téléphonie mobile, déclaration par la cible elle-même, lorsqu'elle est munie d'un GPS ou équivalent, etc) mais l'IETF ne se préoccupe que du format et de la distribution de cette information, pas de comment elle a été obtenue.

D'abord, revenons sur la notion d'incertitude, si importante en métrologie. La section 2 de notre RFC donne la définition suivante : « l'incertitude exprime de manière quantitative ce que l'on sait à propos d'une grandeur mesurée ». Par exemple, on sait que les instruments de mesure ont une précision limitée et on intègre cette imprécision dans l'incertitude. Ou bien on sait que la grandeur varie très vite et cette variation devient une partie de l'incertitude. Techniquement, l'incertitude est en général représentée par une distribution de probabilité. Celle-ci peut être trop complexe pour être manipulée simplement donc on adopte en général un modèle simple : toute grandeur est accompagnée d'un intervalle et d'un degré de confiance. Par exemple, si je mesure une longueur, je vais l'indiquer « L = 1,00742 +/- 0,0043 m à 95 % de confiance » ce qui veut dire qu'il y a 95 chances sur 100 que L soit entre 1,00312 et 1,01172 mètres. (On note que, si la « vraie » mesure a une dimension - c'est un point, la mesure avec l'incertitude a deux ou trois dimensions, dessinant une région d'incertitude. Les formes de cette région peuvent être variées, cf. RFC 5491.) Si vous voulez en savoir plus sur l'incertitude, vous pouvez lire le « Guide to the expression of uncertainty in measurement (GUM) 98:1995 » de l'ISO ou la Technical Note 1297, « Guidelines for Evaluating and Expressing the Uncertainty of NIST Measurement Result » du NIST.

On a dit plus haut que l'incertitude pouvait être exprimée par une distribution de probabilité. Celle-ci est représentée par une fonction, la PDF (probability density function) qui indique la probabilité, en chaque point, que la « vraie » valeur figure en ce point. Deux PDF sont très répandues, la gaussienne, aussi appelée distribution normale, qui provient en général de la combinaison de beaucoup de petites erreurs aléatoires, et la PDF rectangulaire, qui représente en général une mesure avec une source d'erreurs principale. La PDF est centrée sur la moyenne des mesures, la PDF gaussienne est caractérisée par l'écart-type, la rectangulaire par sa largeur (le RFC utilise la demi-largeur).

L'ancien RFC 3693 utilisait également les termes de précision et de résolution, qui sont désormais abandonnés, l'expérience ayant montré que leur définition ne suffisait pas en pratique. Par contre, comme alternative aux termes quantitatifs comme les caractéristiques de la PDF, notre nouveau RFC 7459 utilise le concept qualitatif d'exactitude (accuracy). L'exactitude d'une mesure indique qualitativement le degré de proximité avec la réalité. On dira ainsi qu'une mesure est « plus exacte » qu'une autre.

Après ces considérations générales sur l'incertitude, les sections 3 et 4 du RFC décrivent précisement comment celle-ci est représentée dans le format PIDF-LO (format fondé sur XML). La section 3 précise le modèle utilisé : la cible qui nous intéresse est considérée comme un point. (Ce n'est pas vrai si la cible est de grande taille, par exemple un aéroport, ou si elle est quantique, mais le modèle adopté par l'IETF est délibérement simplifié.) Le format PIDF-LO du RFC 4119 permet de décrire les incertitudes, et d'indiquer la forme de la région d'incertitude, en utilisant les formes géométriques standard de la norme « GML 3.1.1 PIDF-LO Shape Application Schema for use by the Internet Engineering Task Force (IETF) - Candidate OpenGIS Implementation Specification 06-142r1 ». Par contre, le format PIDF-LO original ne permet pas d'indiquer la confiance, le RFC 5491 se contentant d'une valeur fixe de 95 %. À noter que l'absence d'incertitude dans le fichier PIDF-LO ne signifie pas que la mesure était parfaite : il se peut qu'on n'ait pas cherché à évaluer l'incertitude, ou bien qu'on la connaisse mais qu'on la cache délibérement, par exemple pour des raisons de protection de la vie privée. Notez enfin que le problème de l'incertitude existe aussi pour les localisations civiles (comme « 8, rue de la Pompe, 12345 Villeneuve ») du RFC 5139.

La section 4 de notre RFC étend l'élement <location-info> de PIDF-LO (format normalisé dans le RFC 4119) en ajoutant un élément <confidence>. La confiance est exprimée sous forme d'un pourcentage (comme le « 95 % » indiqué plus haut) ou de la valeur spéciale unknown. Les anciens logiciels ignoreront cet élément (qui n'existait pas au début de PIDF-LO) mais les nouveaux pourront s'en servir pour améliorer les traitements et les messages aux utilisateurs. Un attribut pdf indique l'apparence de la fonction PDF : inconnue, normale (gaussienne) ou rectangulaire. Voici un exemple :


<pidf:presence
         xmlns:pidf="urn:ietf:params:xml:ns:pidf"
         xmlns:con="urn:ietf:params:xml:ns:pidf:geopriv:conf"
         ... >
       <dm:device id="sg89ab">
         <pidf:status>
           <gp:geopriv>
             <gp:location-info>
               <gs:Circle srsName="urn:ogc:def:crs:EPSG::4326">
                 <gml:pos>42.5463 -73.2512</gml:pos>
                 <gs:radius uom="urn:ogc:def:uom:EPSG::9001">
                   850.24
                 </gs:radius>
               </gs:Circle>
<!-- NOUVEAU -->  <con:confidence pdf="normal">67</con:confidence>
             </gp:location-info>
           </gp:geopriv>
         </pidf:status>
       </dm:device>
</pidf:presence>

Le schéma XML complet de ces extensions à PIDF-LO figure dans la section 7. L'espace de noms nécessaire, urn:ietf:params:xml:ns:pidf:geopriv:conf est désormais enregistré à l'IANA.

Avoir l'information ne suffit pas. Il faudra l'utiliser et on peut se demander, par exemple (section 4.3 du RFC) comment présenter une confiance à l'utilisateur, de manière à la fois techniquement correcte et compréhensible pour le non-spécialiste. Par exemple, si la confiance est indiquée de manière trop subtile, avec une légère variation de couleur, l'utilisateur pourrait croire que deux positions sont équivalentes alors que l'une d'elles est plus exacte.

La section 5 du RFC se penche ensuite sur les calculs effectués à partir de localisations comportant une incertitude. Elle est bien plus riche en mathématiques et sa lecture est plutôt pour celles et ceux qui sont à l'aise avec les centroïdes, la forme de la Terre, le calcul matriciel, et la géométrie en général. Ces calculs sont d'autant plus complexes que les opérations sur des données comportant une incertitude ne sont pas intuitives. Par exemple, l'incertitude sur la différence entre deux positions est la somme des incertitudes, pas l'incertitude maximale, encore moins la différence des incertitudes comme un calcul naïf risquerait de le faire. Les fanas de maths peuvent aussi lire les annexes A et B, qui contiennent des formules utiles.

Un petit mot sur la sécurité, pour finir (section 9 du RFC). Indiquer l'incertitude peut donner des indications sur le mécanisme de localisation utilisé, ce qui peut être vu comme excessivement bavard. Ceci dit, la section 13.5 du RFC 6772 rappelle que les services de localisation distribuent de l'information et qu'il est très difficile de diminuer les fuites (sans rendre le service inutilisable).


Téléchargez le RFC 7459


L'article seul

RFC 7457: Summarizing Known Attacks on TLS and DTLS

Date de publication du RFC : Février 2015
Auteur(s) du RFC : Y. Sheffer (Porticor), R. Holz (TUM), P. Saint-Andre (&yet)
Pour information
Réalisé dans le cadre du groupe de travail IETF uta
Première rédaction de cet article le 10 février 2015


Depuis quelques années, on entend souvent parler de failles dans TLS ou dans les mises en œuvre de TLS, comme OpenSSL. Un groupe de travail a été créé à l'IETF pour essayer de durcir la sécurité de TLS, le groupe UTA (Using TLS in Applications). Son premier RFC est un rappel de ces récentes failles. C'est l'occasion de réviser BEAST, CRIME ou Heartbleed.

Le protocole de cryptographie TLS (autrefois nommé SSL) est normalisé dans le RFC 5246. Les attaques récentes contre TLS sont très variées : mauvaise utilisation de TLS par les applications (la principale motivation pour la création du groupe UTA, et son centre d'intérêt principal), bogues dans un programme mettant en œuvre TLS, erreurs dans le protocole, erreurs dans un des algorithmes cryptographiques qu'il utilise... Ce RFC dresse une liste des problèmes de sécurité de ces dernières années, mais on peut être sûr que la liste va s'allonger. Comme le dit la NSA, « Attacks always get better; they never get worse » (cf. RFC 4270).

Le gros morceau du RFC est sa section 2, qui liste les problèmes. Par exemple, la plus évidente est d'empêcher complètement l'usage de TLS (ce qu'on nomme parfois SSL stripping). Par exemple, si un client HTTP se connecte en HTTP et compte sur le serveur pour le rediriger en HTTPS, un attaquant actif peut modifier la redirection, empêchant ainsi TLS de démarrer. Le SSL stripping est donc un cas particulier des attaques par repli (downgrade attacks). Normalement, HSTS (RFC 6797) est la bonne solution contre cette attaque.

Pour HTTP, il est habituel de démarrer directement en TLS. Pour les protocoles où on démarre sans TLS et où on utilise ensuite une commande STARTTLS pour commencer à chiffrer (comme SMTP), une attaque par repli analogue est possible en supprimant la commande STARTTLS. La seule protection possible serait un équivalent de HSTS (le RFC oublie de mentionner DANE, qui pourrait être utilisé à des fins de signalisation). Autre problème avec STARTTLS, les attaques où le tampon d'entrée n'est pas vidé après le passage à TLS, ce qui fait que les commandes injectées avant que TLS ne sécurise la connexion sont exécutées après, en les croyant sûres (CVE-2011-0411). Ce n'est pas une faille du protocole mais de l'application.

Autre attaque, avec un nom rigolo, cette fois, BEAST (CVE-2011-3389). Elle ne touchait que TLS 1.0 (version dépassée depuis longtemps) et seulement le mode CBC.

Plusieurs attaques sont du type padding oracle. C'est le cas de Lucky Thirteen (CVE-2013-0169). Elle peut être combattue en utilisant un mode de chiffrement intègre, ou bien en faisant le chiffrement avant de calculer le MAC (mécanisme dit « encrypt-then-MAC » et recommandé pour TLS par le RFC 7366). Une autre attaque padding oracle, Poodle (CVE-2014-3566 ou bien l'article d'Andréa Fradin), qui ne touche que des versions encore plus anciennes (avant que cela ne s'appelle TLS) et n'a pas de solution connue (à part arrêter d'utiliser des versions archaïques de SSL).

Le protocole TLS est complexe et plein de failles se cachent dans des détails subtils. Par exemple, l'attaque triple handshake (CVE-2014-1295) permet de faire en sorte que deux sessions TLS utilisent les mêmes clés, autorisant ainsi plusieurs autres attaques.

Passons à des attaques plus cryptographiques, celles portant sur l'algorithme RC4. RC4 est utilisé depuis longtemps, a des faiblesses connues depuis longtemps (voir le RFC pour une bibliographie comportant plusieurs articles), et ces faiblesses commencent à devenir exploitables en pratique (aujourd'hui, elles requièrent encore trop de calculs). Il ne faut donc plus utiliser RC4 (RFC 7465).

La compression des données dans TLS apporte ses propres attaques comme CRIME (CVE-2012-4929). Pour les empêcher, on peut couper la compression ou, pour certaines attaques, choisir des solutions au niveau de l'application.

Autre propriété de TLS qui semblait pratique quand elle a été définie, mais qui s'est avérée dangereuse, la renégociation (CVE-2009-3555). La solution a été fournie par le RFC 5746.

TLS utilisant presque toujours des X.509 pour authentifier le serveur (et parfois le client), il n'est pas étonnant que les failles de X.509, ou d'un des algorithmes utilisés dans les certificats, se retrouvent dans la liste des problèmes de sécurité avec TLS. C'est le cas par exemple de l'attaque RSA de Klima, V., Pokorny, O., and T. Rosa, « Attacking RSA-based sessions in SSL/TLS ». ou de celle de Brubaker, C., Jana, S., Ray, B., Khurshid, S., et V. Shmatikov, « Using frankencerts for automated adversarial testing of certificate validation in SSL/TLS implementations ».

Une autre attaque possible est lorsque l'attaquant met la main sur la clé privée a posteriori, et qu'il a enregistré le trafic chiffré. Avec la plupart des algorithmes utilisés par TLS, la connaissance de la clé privée permet de déchiffrer le trafic passé, qui peut être encore intéressant. Cela permet, par exemple, l'utilisation de Wireshark pour analyser un trafic HTTPS. Mais c'est dangereux pour la vie privée : un attaquant patient et ayant beaucoup de place sur ses disques durs pourrait enregistrer tout le trafic chiffré, attendant le moment où il entre en possession des clés privées (ce que fait la NSA, cf. RFC 7258). On peut se protéger contre ces attaques en sécurisant mieux ses clés privées (un HSM ?) mais le mieux est sans doute de passer aux algorithmes qui fournissent la perfect forward secrecy.

Même lorsque le protocole est parfait, des failles peuvent apparaitre en raison de bogues dans les programmes qui mettent en œuvre TLS. On peut même dire qu'il y a bien plus de bogues d'implémentation que de protocole, et elles sont en général plus facilement exploitables, et avec des conséquences plus graves. Ces failles peuvent être dans les bibliothèques TLS (comme OpenSSL, qui en a connu beaucoup, dont la fameuse Heartbleed, CVE-2014-0160, cf. RFC 6250 ou bien l'article de Fradin) ou dans les programmes qui utilisent ces bibliothèques (une excellente étude à ce sujet est celle de Georgiev, M., Iyengar, S., Jana, S., Anubhai, R., Boneh, D., et V. Shmatikov, « The most dangerous code in the world: validating SSL certificates in non-browser software »). Une liste non-exhaustive de ces bogues dans les applications :

  • Absence de vérification du certificat, comme l'ont fait pendant longtemps les bibliothèques Python (voir le CVE-2013-2191). Ce n'est pas une faille du protocole mais de l'application ou des bibliothèques.
  • Si on vérifie le certificat, absence du test du nom du serveur dans le certificat. La faille « goto fail » était de cette catégorie. Voir mon exposé à Devoxx (et ses transparents).

Il n'y a pas que des attaques dues aux bogues du protocole ou des implémentations. Un méchant peut aussi utiliser les simples attaques par déni de service. TLS impose davantage de calculs aux machines qui communiquent et cela peut être utilisé pour le déni de service. Si les processeurs ont progressé (rendant réaliste l'idée d'activer systématiquement TLS pour toutes les connexions), un attaquant disposant d'un grand botnet peut toujours épuiser les capacités de sa victime, en lui imposant des calculs cryptographiques complexes.

De même que les programmeurs d'application peuvent se tromper, mal interpréter les complexes API des bibliothèques TLS, et introduire ainsi des failles de sécurité, les utilisateurs finaux peuvent également prendre des décisions qui annulent la sécurité de TLS, quelle que soit la qualité des protocoles et des logiciels. L'utilisabilité est un élément de la sécurité, si on ne veut pas que M. Michu fasse des erreurs. Par exemple, les logiciels permettent d'accepter un mauvais certificat et les utilisateurs disent presque toujours Oui (et souvent pour des raisons rationnelles). Ici, un exemple avec le logiciel de messagerie instantanée Pidgin : cert-xmpp.png

Lutter contre ce problème nécessitera à la fois HSTS (pour priver de choix l'utilisateur), de l'épinglage des clés, et de meilleurs interfaces utilisateur, une tâche très complexe.

Si vous voulez vous documenter sur ces problèmes TLS, le RFC recommande l'article de Sarkar, P. et S. Fitzgerald, « Attacks on SSL, a comprehensive study of BEAST, CRIME, TIME, BREACH, Lucky13 and RC4 biases ».

Un autre mécanisme TLS contre les attaques par repli est celui décrit dans le RFC 7507.


Téléchargez le RFC 7457


L'article seul

RFC 7454: BGP operations and security

Date de publication du RFC : Février 2015
Auteur(s) du RFC : J. Durand (CISCO), I. Pepelnjak (NIL), G. Doering (SpaceNet)
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 19 février 2015


Tout l'Internet repose sur le protocole BGP, qui permet l'échange de routes entre opérateurs Internet. (BGP est normalisé dans le RFC 4271.) La sécurité de BGP est donc cruciale pour l'Internet, et elle a fait l'objet de nombreux travaux. Ce nouveau RFC résume l'état actuel des bonnes pratiques en matière de sécurité BGP. Du classique, aucune révélation, juste la compilation de l'état de l'art. Ce RFC porte aussi bien sur la protection du routeur, que sur le filtrage de l'information (les routes) reçues et transmises.

Ce genre de compilation aurait plutôt due être faite dans le cadre du project BCOP mais celui-ci semble mort.

La section 2 de ce RFC rappelle qu'il n'a pas de caractère obligatoire : il expose des pratiques de sécurité générales, et il est toujours permis de faire des exceptions, en fonction des caractéristiques spécifiques du réseau qu'on gère.

Donc, au début (sections 4 et 5 du RFC), la protection de la discussion entre deux routeurs, deux pairs BGP qui communiquent (sécurité du canal). Ensuite (sections 6 à 11), la protection des informations de routage échangées, le contrôle de ce qui est distribué (sécurité des données).

Commençons par sécuriser le routeur (section 4). Il devrait idéalement être protégé par des ACL qui interdisent les connexions vers le port 179, celui de BGP, sauf depuis les pairs connus. Les protections de TCP ne suffisent pas forcément, la mise en œuvre de TCP dans les routeurs est parfois faite de telle façon qu'on peut planter le routeur juste en envoyant plein de demandes de connexion. Il faut donc les jeter avant même que TCP ne les voit. De telles ACL sont parfois mise en place automatiquement par le logiciel du routeur, mais dans d'autres cas elles doivent être installées manuellement.

Rappelez-vous qu'un router a à la fois des fonctions de contrôle (control plane, ce qui inclut BGP) et de transmission (data plane). Idéalement, les ACL pour protéger le contrôle devraient être spécifiques à cette fonction et ne pas affecter la transmission des paquets (mais le matériel et le logiciel ne permettent pas toujours cette séparation). Certains routeurs permettent également de mettre en place un limiteur de trafic, pour éviter du trafic excessif, même en provenance de pairs connus. Le RFC 6192 décrit avec plus de détails la protection des fonctions de contrôle d'un routeur.

Ensuite (section 5 du RFC), la protection des sessions BGP avec les pairs légitimes (cf. RFC 6952). Si les deux routeurs ne prennent aucune précaution, un attaquant pourrait, par exemple, couper leur session BGP en envoyant de faux paquets TCP de type RST (cf. RFC 5961). Pire, il pourrait, avec des techniques comme l'usurpation ARP, injecter de faux paquets dans une session BGP existante. Pour se protéger contre les attaques TCP, il faut utiliser une authentification TCP, comme la traditionnelle (et bien dépassée) TCP-MD5 du RFC 2385. Beaucoup d'opérateurs exigent une telle authentification lorsqu'on fait du BGP avec eux (particulièrement sur un point d'échange, où des inconnus peuvent facilement fabriquer de faux paquets). Mais on ne peut pas dire que 100 % des sessions BGP dans le monde sont protégées, en raison du surcoût d'administration qui en résulte (choisir les mots de passe, les distribuer, les changer, etc). En outre, MD5 étant désormais bien affaibli (RFC 6151), il faudrait désormais utiliser le mécanisme AO du RFC 5925. Le RFC note que, malgré le caractère antédiluvien de TCP-MD5, c'est toujours la solution la plus utilisée par les opérateurs. Mes lecteurs qui configurent tous les jours des appairages BGP connaissent-ils des gens qui utilisent AO ?

Une autre solution serait de se servir d'IPsec entre les routeurs mais personne ne le fait.

Autre précaution, filtrer les paquets IP en entrée du réseau de l'opérateur pour interdire les paquets prétendant avoir une adresse IP source située dans le réseau de l'opérateur. Sans cette précaution, même les sessions iBGP pourraient être attaquées.

Dernière protection des sessions BGP, GTSM (RFC 5082) qui consiste à tester que le TTL des paquets entrants est à la valeur maximale (255), et que le paquet vient donc bien du réseau local (s'il était passé par, ne serait-ce qu'un seul routeur, le TTL aurait été décrémenté).

Après avoir protégé les routeurs, et la session BGP sur TCP qui les relie, voyons les données. Sécuriser la session ne sert à rien si le pair légitime et authentifié nous envoie des informations fausses. La section 6 de notre RFC se consacre donc au filtrage des préfixes annoncés. D'abord, les préfixes non routables (ceux marqués Global: false dans le registre des adresses spéciales IPv4 ou son équivalent IPv6) devraient évidemment être rejetés. Mais il est également recommandé de ne pas accepter les préfixes non alloués (par le système d'allocation d'adresses IP IANA->RIR->LIR). Comme la liste de ces préfixes change tout le temps, les filtres doivent être mis à jour automatiquement, à partir de la liste à l'IANA. Comme il y a un délai entre l'allocation d'un préfixe à un RIR et son utilisation réelle sur ce terrain, il n'est pas nécessaire de tester tous les jours (le RFC recommande de tester au moins une fois par mois). Si, pour une raison ou pour une autre, on ne peut pas vérifier la liste en ligne, il vaut mieux ne pas filtrer les préfixes, plutôt que de le faire sur la base d'une liste dépassée : une des plaies de l'Internet est la nécessité de dé-bogoniser (faire retirer des listes de bogons ces listes d'adresses IP non allouées) tout nouveau préfixe, processus qui peut être lent et nécessite pas mal de tests sur les looking glasses. En IPv4, il ne reste plus de préfixes non alloués et ce test régulier n'est donc plus nécessaire.

Tester auprès de l'IANA ne permet que des filtres grossiers, éliminant les annonces de préfixes non alloués à un RIR, ce qui ne sert que pour IPv6, ne vérifie pas les préfixes plus spécifiques que ce que l'IANA alloue, et n'empêche pas un malveillant ou un maladroit d'annoncer les préfixes d'un autre AS. Il peut donc être intéressant de filtrer de manière plus précise, en regardant les IRR. Un IRR est une base de données publiquement accessible, stockant les préfixes et l'AS autorisé à les annoncer (en langage RPSL, cf. RFC 4012). Ces IRR sont gérés par certains opérateurs, ou par les RIR. Par exemple, la base de données du RIPE-NCC contient cette information :

route:          217.70.176.0/20
descr:          GANDI is an ICANN accredited registrar
descr:          for more information:
descr:          Web:   http://www.gandi.net
origin:         AS29169
mnt-by:         GANDI-NOC

On voit ici que seul l'AS 29169 (Gandi) est autorisé à annoncer le préfixe 217.70.176.0/20. En opérant récursivement (car un AS peut être un fournisseur d'un autre AS situé derrière lui et il faudra donc suivre les informations sur les AS relayés), on peut établir une liste de tous les préfixes qu'un pair peut annoncer, et ne pas accepter les autres. Des outils existent pour produire automatiquement des filtres sur le routeur à partir du RPSL (comme IRRToolSet). Malheureusement, aucun IRR n'est parfait (et certains sont vraiment imparfaits) : préfixes absents (surtout les plus spécifiques, en cas de dés-agrégation des annonces), information dépassée, etc. Les IRR des RIR sont proches des opérateurs et donc a priori ont une information fiable mais ce n'est que théorique (les préfixes IP « du marais », alloués avant l'existence des RIR, sont une source particulièrement importante de problèmes). En outre, l'IRR d'un RIR ne couvre que la région de ce RIR, et on peut donc avoir besoin d'en consulter plusieurs (on a un pair états-unien, on regarde la base de l'ARIN, mais ce pair a des clients sud-américains et on doit donc aussi regarder la base de LACNIC...), ce qui justifie les IRR privés, comme RADB, qui essaient de consolider l'information des RIR.

Si vous trouvez que cette imperfection des IRR est bien ennuyeuse, le RFC recommande que vous agissiez de votre côté : vérifiez que vos préfixes sont correctement publiés dans les IRR.

Actuellement, la sécurité des données BGP repose essentiellement sur ce filtrage à partir des IRR et sur la réactivité des administrateurs réseau. Dans le futur, il est possible qu'un système plus fiable soit adopté et déployé, le couple RPKI+ROA, alias SIDR pour Secure Inter-Domain Routing. SIDR repose sur une infrastructure de certification, la RPKI (RFC 6480), et sur des objets signés, les ROA (RFC 6482), annonçant quel AS peut annoncer tel préfixe. SIDR fournit deux services, dont seul le premier est un peu déployé aujourd'hui :

  • La validation de l'origine de l'annonce (le premier AS sur le chemin). Décrite dans le RFC 6811, elle est aujourd'hui disponible dans la plupart des routeurs, et des ROA sont effectivement publiés.
  • La validation du chemin d'AS complet. Surnommé « BGPsec » (RFC 7353 et RFC 7132), la normalisation technique de ce service est loin d'être complétée et il n'existe donc pas de mise en œuvre disponible.

Ces mécanismes SIDR devraient, une fois largement déployés, résoudre la plupart des problèmes décrits dans cette section 6 de notre RFC 7454. Mais cela prendra de nombreuses années et il est donc nécessaire de ne pas abandonner les méthodes actuelles comme les systèmes d'alarme.

Pour la validation de l'origine de l'annonce, notre RFC recommande que la politique de filtrage des annonces (qui est une décision locale de chaque routeur) suive les règles du RFC 7115. Pour les résumer, lorsqu'une annonce BGP est comparée au contenu de la RPKI :

  • S'il existe un ROA et que l'annonce est valide selon ce ROA, on accepte l'annonce,
  • S'il existe un ROA mais que l'annonce n'est pas valide, on rejette l'annonce (attention, rappelez-vous qu'au début de toute nouvelle technique de sécurité, il y a pas mal de faux positifs),
  • S'il n'existe pas de ROA, on accepte l'annonce, avec une préférence plus faible.

Le système RPKI+ROA pose de nouveaux et intéressants problèmes et il est donc recommandé de lire « On the Risk of Misbehaving RPKI Authorities » d'abord.

D'autres filtrages sont possibles en entrée. Par exemple, les opérateurs filtrent les annonces trop spécifiques, afin notamment d'éviter la croissance indéfinie de leurs bases de données et tables de routage. Chacun choisit les valeurs quantitatives précises et il n'y a pas de consensus documenté sur ce point (on peut consulter les documents RIPE-399 et RIPE-532) mais on peut observer qu'un préfixe plus long que /24 en IPv4 et /48 en IPv6 a très peu de chances d'être accepté dans l'Internet. Voici un exemple de filtrage IPv4 sur JunOS :

policy-statement no-small-and-big-prefixes {
        from {
            route-filter 0.0.0.0/0 prefix-length-range /25-/32 reject;
            route-filter 0.0.0.0/0 prefix-length-range /0-/7 reject;
        }
}
protocols {
            bgp {
               ...
               import no-small-and-big-prefixes;

Typiquement, on filtre aussi en entrée les annonces portant sur les préfixes internes. Normalement, ce n'est pas à nos voisins d'annoncer nos routes !

Autres préfixes souvent filtrés, les routes par défaut, 0.0.0.0/0 en IPv4 et ::0/0 en IPv6.

Naturellement, les recommandations de filtrage dépendent du type d'appairage BGP : on ne filtre pas pareil selon qu'on parle à un pair, à un client ou à un transitaire (voir la section 6 du RFC pour tous les détails). Ainsi, pour reprendre le paragraphe précédent, sur la route par défaut, certains clients d'un opérateur demandent à recevoir une telle route et c'est tout à fait acceptable.

La section 7 est consacrée à une pratique très utilisée et très discutée, l'amortissement (damping). Lorsqu'une route vers un préfixe IP donné passe son temps à être annoncée et retirée, on finit par l'ignorer, pour éviter que le routeur ne passe son temps à recalculer ses bases de données. Pour réaliser cela, à chaque changement d'une route, on lui inflige une pénalité, et au bout d'un certain nombre de pénalités, on retire la route. Malheureusement, cette technique mène parfois à supprimer des routes et à couper un accès (voir RIPE-378). Avec de meilleurs paramètres numériques, comme recommandé par le RFC 7196 et RIPE-580, l'amortissement redevient utilisable et recommandable. (En 2021, les paramètres recommandés étaient toujours valables.)

Autre technique de filtrage des erreurs, décrite en section 8, l'imposition d'un nombre maximum de préfixes annoncés par un pair BGP. S'il en annonce davantage, on coupe la session BGP. Un dépassement du nombre maximal est en effet en général le résultat d'une fuite, où, suite à une erreur de configuration, le routeur ré-annonce des routes reçues d'un autre. Parfois, c'est toute la DFZ qui est ainsi annoncée par accident aux pairs ! Notre RFC demande donc instamment qu'on limite le nombre de préfixes accepté pour une session BGP. Pour un pair sur un point d'échange, le seuil devrait être inférieur au nombre de routes de la DFZ (dans les 530 000 en IPv4 aujourd'hui, et 21 000 en IPv6), pour détecter les annonces accidentelles de toute la DFZ. On peut aussi avoir des seuils par pair, fondés sur le nombre de routes qu'ils sont censés annoncer. Pour un transitaire, par contre, le seuil doit être plus élevé que le nombre de routes dans la DFZ, puisqu'on s'attend à tout recevoir d'eux (mais une valeur maximale est quand même utile en cas de désagrégation intensive). Comme l'Internet change tout le temps, il faut réviser ces limites, et suivre les alertes (sur certains routeurs, on peut configurer deux seuils, un pour déclencher une alerte, et un autre, supérieur, pour réellement couper la session). Voici un exemple sur JunOS :

group Route-Server-LINX-V4 {
    family inet {
        unicast {
            prefix-limit {
               maximum 100000;
            }
	}
}

Après le filtrage par préfixe, il peut aussi y avoir du filtrage par chemin d'AS (section 9 de notre RFC) et par routeur suivant (next hop, section 10). Voyons d'abord le filtrage par chemin d'AS. Par exemple, un client d'un opérateur ne devrait pas annoncer des routes avec n'importe quels AS mais seulement avec un chemin comportant uniquement son propre AS (et, si le client a lui-même des clients, avec l'AS de ces clients secondaires). Si l'opérateur n'arrive pas à avoir une liste complète des AS qui peuvent se retrouver dans les chemins de ses clients, au moins peut-il limiter la longueur de ces chemins, pour éviter la ré-annonce accidentelle de routes. D'autre part, on n'accepte pas, dans le cas normal, de routes où un AS privé (64512 à 65534 et 4200000000 à 4294967294, voir RFC 6996) apparait dans le chemin. Conséquence logique, on n'annonce pas à ses voisins de routes avec des chemins d'AS qui incluent un AS privé, sauf arrangement spécifique. Et le chemin d'AS dans une annonce BGP doit toujours commencer par l'AS du voisin (sauf si on parle à un serveur de routes). Enfin, un routeur BGP n'acceptera pas d'annonces où il voit son propre AS dans le chemin, et ce comportement par défaut ne devrait pas être débrayé.

Quant au filtrage sur le routeur suivant (section 10 du RFC), il consiste à refuser une route si l'attribut BGP NEXT_HOP (RFC 4271, section 5.1.3) n'est pas l'adresse du voisin. Attention, ce test doit être débrayé si on parle à un serveur de routes, celui-ci ne souhaitant pas traiter les paquets IP. Idem (débrayage du test) si on fait du RTBH (RFC 6666).

Pour finir, je recommande trois lectures,


Téléchargez le RFC 7454


L'article seul

RFC 7451: Extension Registry for the Extensible Provisioning Protocol

Date de publication du RFC : Février 2015
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF eppext
Première rédaction de cet article le 4 février 2015


Le protocole d'avitaillement EPP, normalisé dans le RFC 5730, est extensible : on peut rajouter des éléments afin de gérer des politiques locales. Jusqu'à présent, ces extensions n'étaient pas collectées en un endroit unique, ce qui pouvait mener à des duplications d'efforts inutiles. Ce nouveau RFC crée un registre d'extensions EPP, géré souplement (y mettre une extension est simple et ne nécessite pas d'accord formel de l'IETF) et qui permettra aux développeurs d'extensions de vérifier facilement si quelqu'un a déjà fait un travail analogue.

EPP est surtout connu pour son utilisation par les registres de noms de domaine. C'est ce protocole qui est utilisé par le titulaire du nom, ou par son bureau d'enregistrement, pour créer un nom, le modifier ou le supprimer. Chaque registre ayant sa propre politique d'enregistrement, le schéma EPP standard ne peut donc pas convenir à tout le monde (« one size does not fit all »). Voilà pourquoi beaucoup de registres ont créé des extensions. Le RFC 3735 les guide dans cette tâche, mais n'indique guère comment publier ces extensions (cf. la section 2.1 du RFC 3735). On a vu ainsi plusieurs registres développer des extensions différentes, et incompatibles, pour le même problème (comme d'indiquer les informations à propos de la TVA sur les objets créés en EPP).

Notre RFC crée donc un registre IANA des extensions EPP. La section 2 du RFC spécifie les détails de ce registre, et des mécanismes d'enregistrement d'une extension. La politique est « norme nécessaire » (cf. RFC 5226, section 4.1), ce qui impose qu'une spécification publique de l'extension soit disponible, et qu'elle soit évaluée par un expert nommé par l'IANA.

Les éventuelles discussions sur la nouvelle extension, ou la qualité de sa documentation, se feront sur la liste de l'actuel groupe de travail IETF EPPEXT, eppext@ietf.org. Même lorsque le groupe de travail sera dissous, la liste continuera donc.

Parmi les critères d'évaluation, outre ceux du RFC 3735, notre RFC rappelle l'importance d'évaluer les conséquences de l'extension pour la vie privée. Une préoccupation qui était absente du RFC 3735 mais qui a bien plus d'importance aujourd'hui. Autrement, notre RFC recommande aux experts évaluateurs d'être souples : si l'extension à EPP a été documentée et est effectivement déployée, elle mérite d'être enregistrée, même si l'expert a des objections techniques. Ainsi, ce n'est pas un problème si plusieurs extensions proches sont enregistrées : cela reflète la réalité. Si quelqu'un veut déposer une extension très proche d'une extension existante, on lui fera remarquer (et il pourra alors choisir d'utiliser plutôt l'extension existante) mais on ne le bloquera pas. (Ce point est celui qui avait fait l'objet des plus chaudes discussions dans le groupe de travail EPPEXT : certains auraient préféré une politique d'enregistremet plus stricte, limitant les doublons.)

Et comment fait-on pour enregistrer ? On envoie à l'IANA un formulaire (un gabarit se trouve dans la section 2.2.2 et des exemples réels dans la section 3) informant du nom de l'extension, de l'endroit où se trouve sa spécification (un URL suffit), des coordonnées de la personne ou de l'organisation qui enregistre, du TLD auquel elle s'applique (ou « N'importe lequel » si elle est d'usage général), ainsi que d'informations sur les éventuels boulets juridiques, par exemple un brevet sur ladite extension (cf. RFC 8179). Voici un exemple de formulaire d'enregistrement rempli (IPR = Intellectual Property Rights) :

   -----BEGIN FORM-----
   Name of Extension:
   "An Example Extension for the .example Top-Level Domain"

   Document Status:
   Informational

   Reference:
   http://www.example.com/html/example-epp-ext.txt

   Registrant Name and Email Address:
   John Doe, jdoe@example.com

   TLDs: .example

   IPR Disclosure:
   http://www.example.com/ipr/example-epp-ext-ipr.html

   Status: Active

   Notes: None
   -----END FORM-----

Et un exemple réel, l'enregistrement de l'extension « période de rédemption » du RFC 3915. La spécification étant un RFC, le contact est l'IESG :


      -----BEGIN FORM-----
      Name of Extension:
      "Domain Registry Grace Period Mapping for the
      Extensible Provisioning Protocol (EPP)"

      Document Status:
      Standards Track

      Reference:
      http://tools.ietf.org/html/rfc3915

      Registrant Name and Email Address:
      IESG, <iesg@ietf.org>

      TLDs: Any

      IPR Disclosure: None

      Status: Active

      Notes: None
      -----END FORM-----

Cette extension est une des quatre premières du registre IANA.


Téléchargez le RFC 7451


L'article seul

RFC 7444: Security Labels in Internet Email

Date de publication du RFC : Février 2015
Auteur(s) du RFC : K. Zeilenga, A. Melnikov (Isode)
Pour information
Première rédaction de cet article le 19 février 2015


On a souvent besoin, lorsqu'on transmet un document, d'indiquer le niveau de sensibilité ou de confidentialité du document. Quelque chose du genre SECRET ou CONFIDENTIEL. Cela peut être fait de manière non structurée, par du texte (par exemple dans l'objet du message) mais cela ne permet pas aux logiciels d'agir automatiquement sur la base de ce texte. D'où l'idée d'un nouveau champ dans l'en-tête du message, SIO-Label:, pour indiquer de manière structurée la sécurité souhaitée pour ce message.

Dans beaucoup d'organisations (l'armée étant un exemple typique), la présence d'une telle indication a des conséquences pratiques comme « les documents marqués CONFIDENTIEL ou supérieur doivent être enfermés dans un coffre quand on sort du bureau » ou bien « on ne doit envoyer les documents marqués SECRET qu'aux gens disposant de telle habilitation ». D'où l'importance de pouvoir indiquer ces niveaux de sécurité. À noter qu'ils sont présentés et discutés dans la norme UIT X.841, Security information objects for access control.

Le protocole XMPP avait déjà une norme pour les niveaux de sécurité, XEP-0258. Ce nouveau RFC part des mêmes concepts et les applique au courrier électronique (RFC 5322).

La section 1.1 de notre RFC rappelle les anciennes méthodes. Typiquement, on met en avant un texte qui indique le niveau de sécurité. Par exemple :


To: author <author@example.com>
From: Some One <someone@example.net>
Subject: [SECRET] the subject 

SECRET

Text of the message.

SECRET

Dans ce message à la syntaxe RFC 5322, le niveau de sécurité (SECRET) a été mis dans le champ Subject: (encadré entre crochets pour être clairement séparé de l'objet normal), et répété au début (marquage FLOT First Line Of Text) et à la fin (LLOT Last Line Of Text) du message. De telles conventions sont fréquentes dans une communauté donnée (par exemple dans la même organisation, ou bien dans un groupe de gens travaillant sur le même projet). Elles vont sans doute continuer à être utilisées pendant longtemps, le nouveau système venant juste d'être spécifié. Pour un humain, même distrait, ces marques indiquent clairement le caractère secret du message. Mais, comme indiqué plus haut, ce n'est pas exploitable par un logiciel.

On notera que le RFC 2634 proposait déjà un mécanisme pour ces niveaux de sécurité, lié à l'utilisation de S/MIME. Notre nouveau RFC spécifie une solution alternative (S/MIME n'a pas été un grand succès...), plus légère. La solution du RFC 2634 était très perfectionnée (avec signature pour éviter qu'un tiers malveillant ne modifie les marques). Ici, on fait plus simple et on suppose qu'il existe un autre mécanisme pour assurer l'intégrité.

Donc, la solution nouvelle est de mettre un champ SIO-Label: dans le message. On suppose que le MUA proposera à l'utilisateur une liste de choix possibles et, une fois le choix fait, le logiciel le traduira dans le format standard. Les MTA et MDA pourront utiliser ce champ pour prendre des décisions. Par exemple, si un MTA a été configuré pour faire suivre automatiquement le courrier de jean@example.com à marie@internautique.fr, il pourra refuser de faire suivre un message marqué SECRET, ne sachant pas si la destinataire a l'habilitation nécessaire. Autre utilisation, le MUA du destinataire pourra afficher clairement le niveau de sécurité. On peut imaginer bien d'autres usages, comme le tri automatique des messages dans des dossiers différents selon le niveau de sécurité.

Les intermédiaires comme les MTA sont autorisés à modifier le champ SIO-Label: (ou l'ajouter s'il n'est pas présent) et, dans ce cas, il doivent indiquer les anciennes valeurs dans le champ SIO-Label-History: qui, comme son nom l'indique, garde trace des changements effectués.

La section 4 décrit formellement la grammaire des nouveaux en-têtes. SIO-Label: comprend une série de paramètres, chacun formé d'une clé et d'une valeur. Le paramètre principal est sans doute label qui indique le niveau de sécurité. Quelles valeurs peut-il prendre ? Plutôt que d'essayer de normaliser une liste de valeurs (ce qui ne marchera jamais, chaque organisation ayant déjà sa liste), notre RFC délègue à d'autres normes, indiquées par le paramètre type. Ainsi, type=":ess"; label="MQYGASkCAQM="; indique que le type est ESS (Enhanced Security Services for S/MIME, RFC 2634, déjà cité) et le label est alors un encodage en BER d'une étiquette ESS. Un type :x411 va indiquer un encodage BER d'une étiquette de sécurité X.411. Enfin, un type :xml indique que le label est l'encodage en Base64 d'un élément XML qui, on le suppose, fera référence à une norme de niveaux de sécurité (si label est trop long, il peut être écrit en plusieurs fois, avec un astérisque et un numéro d'ordre derrière label). Dans cet exemple, la norme est http://example.com/sec-label/0 (un exemple imaginaire) :


       type=":xml";
       label*0="PFNlY0xhYmVsIHhtbG5zPSJodHRwOi8vZXhhbX";
       label*1="BsZS5jb20vc2VjLWxhYmVsLzAiPjxQb2xpY3lJ";
       label*2="ZGVudGlmaWVyIFVSST0idXJuOm9pZDoxLjEiLz";
       label*3="48Q2xhc3NpZmljYXRpb24+MzwvQ2xhc3NpZmlj";
       label*4="YXRpb24+PC9TZWNMYWJlbD4=";

Ce qui se traduit, une fois le Base64 décodé, par :


<SecLabel xmlns="http://example.com/sec-label/0">
       <PolicyIdentifier URI="urn:oid:1.1"/>
       <Classification>3</Classification>
</SecLabel>

Un autre paramètre fréquent est marking qui indique le texte à afficher à l'utilisateur (marking="FOR YOUR EYES ONLY";). Si vous êtes un vrai paranoïaque, vous avez déjà noté que rien ne garantit que ce texte soit cohérent avec le vrai niveau de sécurité, label (cf. section 7). Plus rigolos, fgcolor et bgcolor permettent de suggérer des couleurs à utiliser pour l'affichage, couleurs indiquées par un code hexadécimal ou un nom (cela me semble une mauvaise idée : l'intérêt des niveaux de sécurité écrits sous une forme structurée est justement que le logiciel qui les affichera aura toute l'information pour choisir une couleur adaptée à son utilisateur). En combinant ces paramètres, un en-tête complet pourrait être :

SIO-Label: marking="TOP SECRET";
       fgcolor= #000011; bgcolor=fuschia;
       type=":x411"; label="MQYGASkCAQM="

On a vu qu'un logiciel de courrier était autorisé à modifier les niveaux de sécurité. Dans ce cas, pour permettre l'analyse de ce qui s'est passé, il devrait enregistrer le niveau précédent dans l'en-tête SIO-Label-History:, normalisé dans la section 5 de notre RFC. Cet en-tête de traçabilité (comme Received:) indique si le SIO-Label: a été ajouté par le logiciel, supprimé ou modifié. Voici un exemple où le message a été modifié deux fois, par l'ajout d'un niveau, puis par sa suppression :

SIO-Label-History: marking="EXAMPLE CONFIDENTIAL";
       type=":ess"; label="MQYGASkCAQM=";
       change=delete;
       changed-by="smtp.example.com";
       changed-at="18 Feb 2013 9:24 PDT";
       changed-comment="Pas confiance dans celui-là, je supprime"
SIO-Label-History: new-marking="EXAMPLE CONFIDENTIAL";
       new-type=":ess"; new-label="MQYGASkCAQM=";
       change=add;
       changed-by="smtp.example.net";
       changed-at="18 Feb 2013 7:24 PDT";
       changed-comment="Pas de niveau indiqué, j'en mets un"

Les deux en-têtes SIO-Label: et SIO-Label-History: sont désormais dans le registre des en-têtes.

La bonne utilisation de ces niveaux de sécurité nécessite quelques précautions (section 7 du RFC). Par défaut, le message, y compris ses en-têtes et donc y compris SIO-Label:, n'est pas protégé et un méchant peut donc mettre un faux niveau ou modifier un niveau existant. Ce RFC ne fournit pas à lui seul de services de sécurité et ne dispense donc pas de mettre des protections adaptées, comme PGP pour assurer la confidentialité du message ou TLS pour qu'il soit transporté sans modification.

À noter également un paradoxe des niveaux de sécurité : leur seule présence donne déjà une indication à un éventuel espion. Si OSS 117 est dans un bureau du KGB et n'a que quelques secondes pour choisir les documents à emporter, le fait que les documents les plus intéressants soient marqués en gros « ultra-secret » va l'aider. C'est encore plus vrai si les niveaux de sécurité sont trop parlants, du genre « Project Roswell/Area51 Secret ».

Je ne connais pas de mise en œuvre de ce RFC. Certains clients de messagerie ont déjà des niveaux de sécurité, utilisant d'autres normes. Voir par exemple TrustedBird, présenté aux JRES en 2009. Si vous êtes intéressés par ces questions, vous pouvez aussi regarder la spécification de XIMF.


Téléchargez le RFC 7444


L'article seul

RFC 7443: Application Layer Protocol Negotiation (ALPN) Labels for Session Traversal Utilities for NAT (STUN) Usages

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : P. Patil, T. Reddy, G. Salgueiro (Cisco), M. Petit-Huguenin (Impedance Mismatch)
Pour information
Réalisé dans le cadre du groupe de travail IETF tram
Première rédaction de cet article le 29 janvier 2015


ALPN, normalisé dans le RFC 7301, est une option du protocole de sécurité TLS pour permettre à un client TLS d'indiquer au serveur TLS quelle application il veut utiliser (car il n'y a pas que HTTPS qui utilise TLS...) Cela permet, notamment, d'utiliser un seul port (le seul qui passera depuis tous les réseaux, 443) pour plusieurs applications. Ce nouveau RFC 7443 utilise ALPN pour permettre à un client STUN de signaler au serveur TLS qu'il veut faire du STUN, et lui permet également de spécifier quel usage de STUN (par exemple le relayage des sessions TCP nommé TURN).

STUN sert normalement aux clients tristement coincés derrière un stupide boitier, genre routeur NAT, pour communiquer avec d'autres malheureux dans le même cas (et qui ne peuvent donc pas être appelés directement). Il est surtout utilisé pour le pair-à-pair et pour la communication multimédia (téléphonie sur IP par exemple). STUN peut fonctionner sur TLS, pour plus de sécurité (RFC 8489, section 6.2.2, et RFC 7350 si on utilise UDP). Notre nouveau RFC permet à STUN-sur-TLS d'utiliser l'extension TLS ALPN en indiquant comme application un de ces deux choix :

  • stun.turn : utilisation de STUN et de TURN (RFC 8656),
  • stun.nat-discovery : utilisation de STUN pour découvrir les caractéristiques d'un routage NAT.
  • Après une sérieuse discussion à l'IETF, il a été décidé qu'il n'y aurait pas d'application « STUN générique » (par exemple pour des usages futurs encore inconnus).

Ces deux noms sont désormais enregistrés dans la liste des protocoles applicatifs ALPN.

À l'heure actuelle, il ne semble pas qu'il y ait encore de mise en œuvre de ce système mais les clients WebRTC devraient logiquement être dans les premiers à s'y mettre.


Téléchargez le RFC 7443


L'article seul

RFC 7440: TFTP Windowsize Option

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : Patrick Masotta (Serva)
Chemin des normes
Première rédaction de cet article le 29 janvier 2015


TFTP est un très vieux protocole de transfert de fichiers, surtout utilisé pour le démarrage de machines n'ayant pas les fichiers nécessaires en local, et devant les acquérir sur le réseau (par exemple via PXE). Reposant sur UDP et pas TCP comme tous les autres protocoles de transfert de fichiers, il peut être mis en œuvre dans un code de taille minimal, qui tient dans la mémoire morte. Par défaut, TFTP n'a pas de fenêtre d'envoi : chaque paquet doit faire l'objet d'un accusé de réception avant qu'on puisse envoyer le suivant. Ce RFC ajoute une option à TFTP qui permet d'avoir une fenêtre d'envoi, accélérant ainsi les transferts de fichier.

C'est le RFC 1350 qui est l'actuelle norme TFTP. Ce vieil RFC décrit le fonctionnement de base de TFTP en notant que « [each data packet] must be acknowledged by an acknowledgment packet before the next packet can be sent », ce qu'on nomme le lock-step. Dit autrement, TFTP a une fenêtre de taille 1. Vu par le dissecteur de paquets de pcapr, cela donne une stricte alternance des données et des accusés de réception :

1.		192.168.0.1	»	192.168.0.13	tftp	Write Request, File: rfc1350.txt\000, Transfer type: octet\000
2.		192.168.0.13	»	192.168.0.1	tftp	Acknowledgement, Block: 0
3.		192.168.0.1	»	192.168.0.13	tftp	Data Packet, Block: 1
4.		192.168.0.13	»	192.168.0.1	tftp	Acknowledgement, Block: 1
5.		192.168.0.1	»	192.168.0.13	tftp	Data Packet, Block: 2
6.		192.168.0.13	»	192.168.0.1	tftp	Acknowledgement, Block: 2
7.		192.168.0.1	»	192.168.0.13	tftp	Data Packet, Block: 3
8.		192.168.0.13	»	192.168.0.1	tftp	Acknowledgement, Block: 3

À l'époque du RFC 1350, il n'y avait aucun moyen de changer cela, TFTP n'ayant pas de mécanisme d'options. Mais le RFC 1782, remplacé depuis par le RFC 2347, lui en a donné un.

L'absence d'un mécanisme de fenêtre (ou, ce qui revient au même, le fait que la fenêtre soit de taille 1) serait dramatique pour des transferts sur l'Internet, où la latence est souvent élevée. Mais TFTP n'est quasiment utilisé que sur des LAN, où la latence est faible et les pertes de paquet rares. L'option Blocksize du RFC 2348, permettant des paquets plus grands que les 512 octets originaux, avait jusqu'à présent suffi à calmer les désirs de performance meilleure. Mais TFTP reste lent, et cette lenteur pose un problème lorsqu'on veut transférer de gros fichiers, comme une image Linux ou comme les PE de Microsoft utilisés par WDS/MDT/SCCM lorsqu'on démarre en PXE. Contrairement à ce que croient beaucoup de gens, TFTP est très loin d'être en voie d'extinction et il est donc justifié de chercher à l'améliorer. Le RFC se vante qu'avec cette option, TFTP peut aller aussi vite que les autres protocoles de transfert de fichier.

L'option elle-même est décrite dans la section 3. Le mécanisme d'option du RFC 2347 consiste en l'ajout de l'option à la fin du paquet Read Request ou Write Request. L'option comporte un nom (windowsize dans notre cas), et une valeur, qui est le nombre de blocs dans une fenêtre (rappelez-vous que, grâce à une autre option, celle du RFC 2348, un bloc ne fait pas forcément 512 octets). On peut envoyer autant de blocs qu'indiqué dans cette option, avant d'exiger un accusé de réception (la section 4 montre un schéma détaillé d'un transfert de données, avec une fenêtre de taille 4). Le récepteur des données accuse réception du dernier bloc (cela accuse implicitement réception des blocs précédents). Les accusés de réception TFTP indiquent en effet le numéro de bloc reçu (RFC 1350, dessin 5.3). Si un bloc se perd, l'émetteur des données s'en rendra compte en ne recevant d'accusé de réception que pour le bloc précédant le perdu, il pourra alors réémettre.

L'option windowsize aura dû être préalablement acceptée par le pair, via un OACK (Option Acknowledgment, RFC 2347).

Pour choisir des bonnes valeurs de fenêtre, une expérience a été faite (section 5), transférant un fichier de 180 Mo, avec des blocs de taille 1 456 sur un Ethernet gigabit, entre deux PC. Avec la fenêtre de 1 (la valeur obligatoire, avant notre RFC), le transfert prend 257 secondes. Il baisse ensuite lorsque la taille de la fenêtre augmente (76 secondes pour une fenêtre de 4, 42 secondes pour une fenêtre de 16) puis plafonne, aux alentours de 35 secondes, d'une fenêtre de taille 64 (pour les grandes fenêtres, le risque accru qu'un paquet dans la fenêtre soit perdu compense l'avantage qu'il y a à ne pas attendre les accusés de réception, il ne sert donc à rien d'augmenter indéfiniment la taille de la fenêtre). Un transfert avec un protocole classique (SMB/CIFS) prend 23 secondes. On voit donc que TFTP peut presque atteindre la même valeur.

Cela ne veut pas dire qu'il faut forcément choisir aveuglément une fenêtre de 64 blocs dans tous les cas : la valeur optimale dépend du réseau entre les deux machines. Le RFC recommande donc de tester avant de choisir.

TFTP utilise UDP, qui n'a pas de mécanisme de contrôle de la congestion. Un émetteur de données TFTP doit donc suivre les règles de prudence du RFC 8085 (notamment sa section 3.1) pour ne pas surcharger le réseau (section 6 de notre RFC). Contrairement à TCP, TFTP n'offre pas de mécanisme permettant de réduire la taille de la fenêtre en cours de route. En cas de gros problème de perte de paquets, la seule solution est d'avorter le transfert (ce qu'on nomme un circuit breaker) et de réessayer avec d'autres paramètres.

On trouve plein de traces TFTP sur pcapr mais aucune avec cette option. Parmi les mises en œuvres de TFTP, si le mécanisme d'options du RFC 2347 est souvent présent, ainsi que l'option de taille de bloc du RFC 2348, en revanche notre nouvelle option de taille des fenêtres ne semble pas encore souvent là. Parmi les programmes qui gèrent cette option : Serva (cité au paragraphe suivant), Node-tftp...

Un bon article de l'auteur du RFC explique cette option, les options précédentes, et leur implémentation dans Serva : « Advanced Topics on TFTP ».


Téléchargez le RFC 7440


L'article seul

RFC 7437: IAB, IESG, and IAOC Selection, Confirmation, and Recall Process: Operation of the Nominating and Recall Committees

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : M. Kucherawy
Première rédaction de cet article le 9 janvier 2015


Voici un nouveau RFC « bureaucratique » autour des processus menant au choix et à la désignation des membres d'un certain nombre d'organismes de la galaxie IETF, comme l'IAB ou l'IESG. Les amateurs de droit constitutionnel seront ravis... (Ce RFC n'est plus d'actualité, ayant été remplacé par le RFC 8713.)

Il n'y a pas de grands changements depuis le RFC 3777 qui, depuis plus de dix ans, était la référence sur ces amusants sujets. Ce nouveau RFC 7437 est surtout la consolidation, dans un document unique, des modifications éparpillées qui avaient été apportées au RFC 3777, comme par exemple celle du RFC 6859, qui ajoutait l'IAOC à la liste des comités dont les membres n'était pas éligibles à un poste au NomCom, le comité de nomination. Ce RFC 7437 ne marque donc pas une réforme significative du fonctionnement de l'IETF mais il permet d'avoir un document à jour. L'annexe A du RFC contient la liste complète des changements depuis le RFC 3777.

Ce RFC concerne la désignation des membres de l'IAB, de l'IESG et de certains membres de l'IAOC (voir la section 4 du RFC 4071 sur le sens de ce « certains »). Il ne concerne pas l'IRTF et ses comités propres. Il ne concerne pas non plus le fonctionnement quotidien de ces comités, juste la désignation de leurs membres.

Le processus tourne autour d'un comité nommé NomCom (pour Nominating Committee, comité de nomination).Comme expliqué en section 2, il faut bien différencier les nommés (nominee), les gens dont les noms ont été soumis au NomCom pour occuper un poste à l'IAB, l'IESG ou l'IAOC, des candidats (candidate) qui sont les gens retenus par le NomCom. Le NomCom, comme son nom l'indique, n'a pas de pouvoir de désignation lui-même, celle-ci est décidée (on dit officiellement « confirmée ») par un organisme différent pour chaque comité (l'IAB pour l'IESG, l'ISOC pour l'IAB, etc). Une fois confirmé, le candidat devient... candidat confirmé (confirmed candidate).

La section 3 de notre RFC explique le processus général : il faut désigner le NomCom, le NomCom doit choisir les candidats, et ceux-ci doivent ensuite être confirmés. Cela peut sembler compliqué, mais le but est d'éviter qu'une seule personne ou une seule organisation puisse mettre la main sur l'IETF. Le processus oblige à travailler ensemble.

À première vue, on pourrait penser que le NomCom a un vaste pouvoir mais, en fait, au début du processus, il ne peut pas décider des postes vacants, et, à sa fin, il n'a pas le pouvoir de confirmation.

Un point important et souvent oublié est celui de la confidentialité (section 3.6 du RFC). En effet, l'IETF se vante souvent de sa transparence, tout doit être public afin que chacun puisse vérifier que tout le processus se déroule comme prévu. Mais le travail du NomCom fait exception. Toutes ses délibérations, toutes les informations qu'il manipule, sont confidentielles. Autrement, il serait difficile de demander aux personnes nommées de fournir des informations personnelles, et les personnes extérieures au NomCom qui sont interrogées hésiteraient à s'exprimer franchement sur tel ou tel candidat. Et la publicité des débats risquerait d'encourager des campagnes de soutien extérieures au NomCom, et du lobbying, toutes choses qui sont formellement interdites. La section 8, sur la sécurité, revient sur cette importance de la confidentialité : puisque le NomCom enquête littéralement sur les nommés, il peut récolter des informations sensibles et il doit donc faire attention à les garder pour lui.

Voici, par exemple, l'annonce de la sélection des membres de l'IESG, début 2014.

Et le NomCom lui-même, comment est-il choisi (section 4) ? De ses quinze membres, seuls dix ont le droit de vote. D'abord, les dix membres du NomCom votants doivent répondre à un certain nombre de critères (section 4.14) : ils doivent avoir été physiquement présents à trois des cinq précédentes réunions de l'IETF (c'est une des exceptions au principe comme quoi la participation à l'IETF n'impose pas de venir aux réunions physiques), et c'est vérifié par le secrétariat de l'IETF. Et ils doivent (évidemment), être très familiers avec les processus internes de l'IETF. Une fois qu'on a un ensemble (pool) de volontaires qui acceptent de participer au NomCom (voyez un appel à volontaires typique), comment choisit-on les dix membres de plein exercice ? Eh bien, c'est là que c'est amusant, ils sont choisis au hasard... Il n'existe en effet pas de critères consensuels sur la meilleure méthode de choix des membres du NomCom (rappelez-vous qu'à l'IETF, on ne peut pas voter, puisqu'il n'y a pas de notion de « membre » et donc pas de corps électoral rigoureusement défini). Le tirage au sort se fait selon la méthode, ouverte et publiquement vérifiable, spécifiée par le RFC 3797.

Le président du NomCom, lui, est désigné par l'ISOC. La liste des membres du NomCom est en ligne.

Une fois sélectionnés, les membres du NomCom se mettent au travail (section 5 du RFC). Ils ne sont bien sûr pas éligibles pour les postes qu'il vont devoir pourvoir. Lorsqu'ils doivent prendre une décision, le NomCom vote (une procédure rare à l'IETF). Les nominations peuvent être faites par n'importe quel participant à l'IETF, y compris le nommé lui-même. La décision de retenir tel ou tel nommé comme candidat doit s'appuyer sur sa connaissance de l'IETF et ses qualifications pour le poste (qui ne sont pas forcément les mêmes pour tous les comités : par exemple, l'IAOC nécessite des compétences administratives qui sont moins importantes à l'IAB). L'IETF étant une organisation de grande taille, le NomCom ne connait pas forcément tout le monde, et peut donc aller à la « pêche aux informations » en consultant des gens extérieurs sur tel ou tel nommé.

Les informations récoltées par le NomCom, et ses discussions sont archivées (mais non publiques : voir plus haut au sujet de la confidentialité). Ces archives sont directement utiles s'il faut, par exemple, remplir un poste et qu'on ne veut pas recommencer le processus de zéro pour certains nommés.

Les humains étant ce qu'ils sont, il y aura des désaccords en interne. Comment le NomCom gère-t-il les contestations (section 6) ? Idéalement, le NomCom doit essayer de les régler tout seul (ne serait-ce que pour préserver la confidentialité déjà mentionnée). Si cela ne marche pas, le problème est transmis à l'ISOC, qui nomme un arbitre, dont les décisions sont définitives (pas d'appel).

J'ai parlé ici surtout de pourvoir des postes, mais il peut aussi y avoir révocation (recall, section 7) d'un membre d'un des comités concernés. Cette révocation peut être demandé par au moins vingt participants à l'IETF, qui doivent être éligibles au NomCom, à l'ISOC. Un Recall Committee est alors créé, et peut décider à la majorité des trois quarts d'une révocation, sur la base des griefs présentés par les signataires de la demande de révocation.

Bien des choses au sujet du NomCom ne sont pas écrites, et la tradition orale joue un rôle important dans son fonctionnement. L'annexe B rassemble plusieurs grains de sagesse issus de cette tradition. Par exemple, avoir été président d'un groupe de travail IETF est considéré comme une bonne préparation à l'IESG. Il y a aussi des considérations sur l'équilibre global entre les membres d'un comité. Il ne s'agit pas seulement que chaque membre soit individuellement bon, il faut aussi que le comité rassemble des gens de perspectives différentes (âge, expérience, région d'origine, monde académique vs. entreprises à but lucratif, etc). La tradition orale recommande aussi d'éviter qu'une même organisation n'occupe trop de postes dans un comité. Même si les gens de cette organisation ne forment pas un bloc, l'impression donnée serait mauvaise pour l'IETF. (Lors de l'annonce IESG de début 2014, citée plus haut, notez le dernier paragraphe : les deux directeurs de la zone routage à l'IETF travaillent pour Juniper.)


Téléchargez le RFC 7437


L'article seul

RFC 7435: Opportunistic Security: Some Protection Most of the Time

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : V. Dukhovni (Two Sigma)
Pour information
Première rédaction de cet article le 3 janvier 2015


Les révélations de Snowden ont sérieusement relancé l'intérêt pour la sécurité informatique, et notamment sur les risques d'espionnage. Mais, en sécurité, le mieux est parfois l'ennemi du bien. Certaines exigences de sécurité peuvent mener à des solutions techniquement parfaites mais tellement compliquées à utiliser qu'elles ne seront que peu ou pas déployées. C'est par exemple le cas de l'authentification pour utiliser le chiffrement. Si on impose l'authentification forte du pair avant de chiffrer, on risque de ne pas pouvoir chiffrer, dans des cas où ce serait pourtant bien utile. Ce nouveau RFC, par le mainteneur de Postfix, définit un concept utile, cela de sécurité opportuniste (opportunistic security) : on chiffre quand on peut, même sans authentification, et on authentifie si c'est possible. L'idée est d'augmenter sérieusement la part de trafic chiffré dans l'Internet.

Un petit détour technique, avant de commencer le RFC. Pourquoi chiffrer sans authentifier est-il dangereux ? Si on ne veut que la confidentialité, mais qu'on se moque de l'identité du pair avec qui on communique, pourquoi s'embêter à authentifier, surtout lorsqu'on sait que chiffrer est si simple et authentifier si compliqué ? C'est parce que chiffrer sans authentifier vous rend vulnérable à l'Homme du Milieu. Celui-ci, tapi dans le réseau, entre Alice et Bob, va recevoir les messages d'Alice et les transmettre à Bob (et réciproquement) et cela, évidemment, après lecture. Chiffrer ne sert à rien s'il y a un homme du milieu : Alice croit chiffrer pour Bob alors qu'elle chiffre en fait pour l'espion qui pourra donc lire le texte en clair avant de le chiffrer et de le passer à Bob.

À noter que l'homme du milieu est forcément actif : il doit maintenir un canal de communication avec Alice et un avec Bob. Parfois, pour des raisons pratiques ou bien juridiques (un attaquant actif peut relever de lois pénales plus sévères), l'attaquant reste passif et, dans ce cas, le chiffrement seul, sans authentification, protège parfaitement. Attention, toutefois : pas mal de personnes semblent croire que seul le FAI ou bien la NSA peuvent faire des attaques actives : or, celles-ci sont plus faciles que ne le croit M. Toutlemonde (usurpation ARP par exemple).

La solution correcte aux attaques de l'homme du milieu est l'authentification : si Alice vérifie qu'elle parle bien à Bob, et uniquement à lui, alors, elle pourra détecter quand un homme du milieu sera présent, et éviter ainsi de lui passer ses secrets. C'est le mode « tout ou rien » (soit on authentifie, soit on avorte la communication) qui était traditionnel dans les protocoles IETF (à part quelques exceptions comme la sécurité « mieux que rien » du RFC 5386). Mais l'authentification n'est pas facile. Prenons un exemple, celui de HTTPS, qui utilise la plupart du temps des certificats X.509 pour l'authentification. Des tas de choses peuvent aller mal : certificats expirés, signés par une autorité inconnue de ce navigateur, auto-signés pour éviter de payer des AC à l'utilité douteuse, et tous les autres malheurs qui ponctuent la vie de l'internaute qui essaie de se connecter en HTTPS. L'utilisateur se rabat donc souvent sur du simple HTTP non chiffré. De peur de l'homme du milieu, il fait tout passer en clair ! Cet état de chose est évidemment absurde. Lorsqu'on a un des fameux avertissements de sécurité « ce certificat a un problème incompréhensible pour vous, qu'est-ce que vous décidez ? », c'est dans la grande majorité des cas une erreur du serveur et pas une attaque de l'homme du milieu. Il vaudrait donc mieux, lorsque le site est également accessible en HTTP ordinaire, chiffrer sans authentification : cela ne peut jamais être pire que de ne pas chiffrer du tout. (Les sites HTTPS à plus haut niveau de sécurité, comme une place de marché Bitcoin, imposent HTTPS, et, en cas d'erreur, il n'y a qu'à pleurer en attendant la réparation.)

Ce débat sur l'authentification obligatoire est aussi ancien que la cryptographie. Je me souviens des vieux dinosaures de la sécurité regardant SSH avec méfiance, lors de son introduction, car l'authentification n'était pas obligatoire. Mais les solutions que prônaient ces sympathiques tétrapodes étaient tellement complexes à déployer que les gens ne chiffraient pas, et utilisaient telnet. Il est donc clair que SSH, même avec son modèle TOFU (Trust On First Use) d'authentification plutôt faible, a amélioré la sécurité de l'Internet. Le TOFU n'est pas parfait (il est vulnérable si l'homme du milieu est présent dès la première connexion, et il ne permet pas de savoir si un changement de clé est normal ou pas) mais il a permis de remplacer massivement l'ancien telnet par un protocole chiffré.

Outre HTTPS et SSH, plusieurs protocoles utilisent du chiffrement, et ont des solutions plus ou moins bonnes pour l'authentification. Des solutions comme DANE (RFC 6698) ont été proposées pour résoudre une partie des problèmes d'authentification mais, à l'heure actuelle, il est clair que l'Internet n'a pas de solution d'authentification généraliste techniquement correcte, politiquement sûre, et effectivement déployée.

Ce débat a mené au terme de sécurité opportuniste (opportunistic security), qui date de bien avant le RFC. Mais il n'était pas défini rigoureusement. Parfois, il désignait le fait de faire de la crypto sans que l'utilisateur l'ait explicitement demandé (ce que fait HTTPS Everywhere en transformant d'autorité des sessions HTTP en HTTPS), parfois il désignait le chiffrement sans authentification (c'est le sens qu'il a dans le RFC 5386), parfois la capacité de basculer automatiquement en mode non-chiffré (la définition du Wikipédia anglophone) et parfois enfin du chiffrement avec authentification mais sans avoir de configuration spécifique par pair (c'est ainsi que le RFC 4322 utilise le terme). Notre RFC lui donne une définition stable, qui sera utilisée dans les documents ultérieurs de l'IETF, comme le futur HTTP 2 ou comme DANE pour SMTP.

Bref, on change de perspective : d'un modèle où on authentifie systématiquement, protégeant contre les attaques passive et actives (et où l'absence d'authentification n'est citée que comme « mode dégradé », voire coupe la communication complètement), on passe à un modèle plus réaliste où l'état de base est l'absence de toute protection (la réalité de l'Internet d'aujourd'hui) et où tout gain en sécurité, même imparfait, est une amélioration par rapport à cet état de base. Avec la sécurité opportuniste, on chiffre quand c'est possible et on authentifie quand on peut. « Opportuniste » est donc un terme positif dans ce RFC. Il repose sur l'idée d'un « plancher de sécurité » en dessous duquel on ne descendra pas, et du « au moins aussi sûr » où on déploie tout système (comme le chiffrement) qui va améliorer les choses, ou en tout cas ne jamais les dégrader. Ce nouveau modèle ne change rien au cas où l'on imposait une sécurité minimale (par exemple avec HSTS, RFC 6797), il concerne les communications qui se font actuellement en clair.

La section 3 de notre RFC définit ce qu'est la sécurité opportuniste. Elle a (en simplifiant) trois niveaux, le niveau de base, où tout est en clair (c'est la majorité du trafic Internet aujourd'hui), le niveau où on chiffre, mais sans authentifier, et le niveau le plus sûr, où on chiffre après authentification. Ce dernier niveau est le meilleur mais la devise de la sécurité opportuniste est « mieux vaut le deuxième niveau que de rester bêtement sans sécurité du tout ». (Ce modèle est simplifié car il peut y avoir plusieurs niveaux de chiffrement ; par exemple, on va essayer de chiffrer en mode PFS mais, si cela échoue, on chiffre quand même, dans un mode moins sûr.) Ce modèle de sécurité opportuniste repose sur quatre principes :

  • Les politiques de sécurité existantes continuent comme avant. Si vous avez mis StrictHostKeyChecking yes dans la configuration d'OpenSSH, la sécurité opportuniste ne vous concerne pas, OpenSSH imposera une authentification de toutes les machines, même la première fois que vous vous connectez.
  • Priorité à la communication. En cas de problème d'authentification, on considère qu'il vaut mieux continuer de manière non sûre plutôt que de renoncer (c'est de fait la politique de nombreux utilisateurs).
  • S'adapter au pair et donc utiliser, pour chaque couple de machines qui communiquent, la sécurité maximale possible pour ce couple. Si un pair ne parle que DES, c'est nul, mais on l'utilise quand même, sans pour autant descendre le niveau de sécurité de la communication avec les autres pairs. (Il existe plusieurs méthodes pour déterminer les capacités du pair, certaines dans la session elle-même, comme la négociation des algorithmes de chiffrement dans TLS, d'autres externes, comme DANE.)
  • Franchise. Dans les messages aux utilisateurs, ou dans les journaux, on ne prétend pas qu'on a obtenu un niveau de sécurité qui ne correspond pas à la réalité. Si on n'a pas pu authentifier, on le dit (cela va poser d'intéressants problèmes d'interface utilisateur...)

La section 4 du RFC illustre le concept de sécurité opportuniste avec SMTP (domaine de compétence principal de l'auteur). Une extension à SMTP, STARTTLS, normalisée dans le RFC 3207, permet d'utiliser TLS pour chiffrer la session. Elle est aujourd'hui largement déployée, par exemple par Facebook ou par Google. À noter que cette extension n'est pas protégée cryptographiquement, et donc vulnérable aux attaques par repli (downgrade attacks) où l'attaquant actif va essayer de faire croire qu'un des pairs ne gère pas la sécurité maximale, menant à l'emploi de solutions de sécurité inférieures (ces attaques, un des points faibles de la sécurité opportuniste, sont traitées également dans la section 6). STARTTLS ne protège donc guère contre un attaquant actif. Donc, utiliser le texte en clair lorsqu'il y a un problème TLS (mauvais certificat, par exemple, ce qui est très fréquent avec SMTP sur TLS) n'a guère de sens : de toute manière, un attaquant actif pourrait supprimer le STARTTLS. Bref, SMTP ne devrait pas se rabattre sur le texte en clair alors que du chiffrement sans authentification est possible.

Ne manquez pas également de lire la section 6, qui résume le problème de sécurité, et qui note que la sécurité opportuniste peut aussi aider contre des attaquants ayant de grands moyens, genre NSA (RFC 7258), en les obligeant à utiliser des attaques actives (comme les attaques QUANTUM).


Téléchargez le RFC 7435


L'article seul

RFC 7426: SDN Layers and Architecture Terminology

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : E. Haleplidis (University of Patras), K. Pentikousis (EICT), S. Denazis (University of Patras), J. Hadi Salim (Mojatatu Networks), D. Meyer (Brocade), O. Koufopavlou (University of Patras)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF sdnrg
Première rédaction de cet article le 9 janvier 2015


S'il y a un buzzword populaire en ce moment, dans les technologies de réseau, c'est bien SDN. Ce sigle désigne une approche de contrôle centralisé d'un réseau, par le biais d'ordres envoyés depuis la machine d'administration, vers tous les éléments actifs du réseau (les routeurs, par exemple). Comme tous les buzzwords, son utilisation massive pour désigner tout et n'importe quoi entraîne pas mal de confusion, et ce RFC de l'IRTF essaie de clarifier un peu en précisant la terminologie du SDN (Software-Defined Networking), et en explorant les protocoles actuels qui participent au système SDN.

Le problème est d'autant plus difficile que tout le monde veut être SDN aujourd'hui. Si, comme la plupart des administrateurs réseaux professionnels, j'utilise un script qui utilise SSH pour se connecter sur tous mes routeurs afin de changer leur configuration, je fais du SDN ? (Réponse : oui, selon la plupart des définitions de SDN qu'on peut trouver, non selon les marketeux, car cette solution ne permet pas de nouvelles ventes.)

La définition que donne le RFC est « le SDN, c'est une approche du réseau fondée sur la programmabilité, qui sépare le plan du contrôle de celui de la transmission, et qui utilise des interfaces standardisées ». Une interface est là où deux entités interagissent. Ce peut être fait avec un protocole réseau, ou une API locale. Le maître d'un réseau SDN (le contrôleur) va configurer des éléments du réseau (network device), les engins qui assurent les fonctions comme la transmission des paquets. Le logiciel utilisé se divise entre applications (qui sont un but en elles-mêmes) et services (qui n'existent que pour fournir des fonctions aux applications, via une jolie API).

Et ces histoires de plan dont j'ai parlé plus haut ? Un plan est une collection de ressources (matériel et logiciel) qui sont responsables d'une activité donnée. Le RFC distingue cinq plans :

  • Plan de transmission (forwarding plane) : faire suivre les paquets d'une interface à l'autre,
  • Plan de contrôle (control plane) : détermine les règles que va suivre le plan de transmission. Par exemple, sur un routeur haut de gamme, le plan de contrôle, qui tourne sur du matériel généraliste, fait tourner les protocoles comme BGP ou OSPF, déterminant la table de routage, tandis que le plan de transmission, composé d'ASIC spécialisés, utilise cette table de routage pour transmettre les paquets à la bonne interface.
  • Ces deux premiers plans sont classiques et souvent utilisés dans les discussions réseau. Le RFC en ajoute trois autres : d'abord, plan des opérations (operations plane, la gestion globale de la machine), et plan de gestion (management plane, la supervision et la configuration de la machine).
  • Et enfin, le plan des applications (application plane), qui comprend les services et les applications proprement dites.

Le RFC introduit aussi le concept de couche d'abstraction (AL, Abstraction Layer), qui est la vision qu'une ressource va présenter au monde extérieur. Ainsi, le DAL (Device Abstraction Layer, aussi appelé HAL pour Hardware Abstraction Layer), est la vision externe d'un engin, ce que connaitra le reste du monde. Il y a de la même façon un CAL (Control Abstraction Layer), un MAL (Management Abstraction Layer) et un NSAL (Network Services Abstraction Layer). Oui, moi aussi, je trouve cela bien abstrait.

La section 3 détaille certains de ces concepts. On a, de bas en haut (en mettant en bas ce qui est concret et en haut ce qui est utile) :

  • L'élément du réseau, par exemple un commutateur, qui contient le plan de transmission et celui des opérations, et qui montre à l'extérieur le DAL. Il est décrit plus en détail en section 3.2.
  • Côte-à-côte, les plans de contrôle (faisant appel au CAL) et de gestion (faisant appel au MAL). Sur un engin ancien, ils sont intégrés aux précédents mais le SDN prône leur séparation (qui était réalisée depuis longtemps dans les routeurs), pouvant aller jusqu'à les mettre dans des machines différentes. La distinction entre ces deux plans est subtile, l'intéressante section 3.5 la traite plus en détail. En gros, le plan de contrôle s'occupe plutôt de réactions rapides (genre moins d'une seconde), et a des états de courte durée (genre une minute). Le plan de gestion prend en charge des phénomènes moins rapides.
  • Les services et applications, parlant au NSAL.

Le RFC 7276 avait déjà un schéma de ce genre. Comme on représente les composants avec le matériel en bas et les applications et services en haut, les interfaces sont souvent étiquetées « Nord » et « Sud » selon qu'elles connectent à un composant situé plus haut ou plus bas (et tant pis pour les Australiens qui mettent le Nord en bas). Ainsi, l'interface du plan de gestion avec le plan des opérations (via le DAL) est, pour le plan de gestion, une Southbound interface (MPSI : Management Plane Southbound Interface).

Le RFC note que, pour le plan de gestion, la facilité d'usage doit être un critère plus important que les performances (cf. RFC 3535) ce qui implique entre autres des fichiers de configuration sous forme texte, en UTF-8 (cf. RFC 6632). Il existe déjà plusieurs protocoles pour la communication Sud du plan de gestion, par exemple NETCONF (RFC 6241), ForCES (RFC 5810), et même les bons vieux syslog (RFC 5424) et SNMP (RFC 3411).

La section 4 met tout cela en perspective dans le cas du SDN, notamment en regardant où les protocoles existants se situent. En gros, les contrôleurs SDN existants sont plutôt dans le plan de contrôle et utilisent son interface Sud (CPSI, Control Plane Southbound Interface) pour parler au matériel. Le protocole utilisé pour cela est typiquement OpenFlow. Leur interface Nord (le NSAL) n'est pas normalisée.

Pour les protocoles IETF existants, quelle est leur place dans ce schéma ? Commençons par ForCES (RFC 3746). L'idée de base est de normaliser le protocole de communication entre le plan de contrôle et celui de transmission, afin de pouvoir réaliser un routeur en combinant un control/routing engine et un forwarding engine de fournisseurs différents, ce qui est impossible aujourd'hui. Si ForCES vise surtout la communication entre plan de contrôle et plan de transmission, il est assez souple (définition des éléments gérés indépendante du protocole) pour pouvoir peut-être s'utiliser pour des communications avec le plan de gestion et le plan des opérations.

Le protocole NETCONF (RFC 6241) est, lui, un protocole de gestion à distance d'équipement réseau (qui pourrait remplacer le traditionnel script qui se connecte en SSH sur tous les équipements avant de configurer avec la CLI). Il est donc partiellement concurrent de SNMP, notamment pour les opérations de modification (set en SNMP). Et NETCONF, dans le monde SDN, peut servir de MPSI (Management Plane Southbound Interface). Son langage de modélisation, YANG (RFC 6020), semble très populaire en ce moment à l'IETF.

Au contraire de ForCES et de NETCONF, issus directement de l'IETF, OpenFlow vient du privé (université Stanford) et est géré aujourd'hui par une organisation ad hoc, Open Networking Foundation. Son but est de contrôler de manière centralisée un ensemble de commutateurs réseau. C'est entre autres un DAL (Device Abstraction Layer) pour le CPSI (Control Plane Southbound Interface).

Dans un routeur classique, la base d'informations (RIB, Routing Information Base) est gérée par les protocoles dynamiques comme OSPF et a peu d'interfaces vers l'extérieur. On peut définir des routes statiques, on peut obtenir quelques statistiques et de la journalisation mais on n'a pas d'interface standard avec le système de routage, permettant de manipuler davantage celui-ci. Le but du projet I2RS (Interface to the Routing System) à l'IETF est justement de spécifier cette interface, en utilisant YANG et en réutilisant autant que possible des systèmes existants. Le projet en est actuellement à ses débuts.

Tous ces protocoles nouveaux et qui brillent ne doivent pas faire oublier les traditionnels, comme SNMP. Après tout, le terme « SDN » est en grande partie du marketing, le contrôle des éléments réseau via des protocoles se pratiquait longtemps avant que le sigle SDN soit inventé. Donc, SNMP (RFC 3417, RFC 3412, RFC 3414) est un protocole de gestion de réseaux, actuellement dans sa version 3. Les objets définis dans une MIB peuvent être interrogés (get) et modifiés (set mais, en pratique, c'est bien plus rare qu'on utilise SNMP pour cela). Comme NETCONF, il peut servir de MPSI.

Deux autres protocoles sont moins souvent cités lorsqu'on parle de faire du SDN avec les protocoles IETF existants mais ils méritent quand même une mention. D'abord, PCE (RFC 4655), qui vise à réaliser le calcul de chemins dans le réseau en un endroit différent de celui qui fera la transmission. Par exemple, une machine spécialisée, le PCE (Path Computation Element) va calculer des routes et les transmettre au routeur, le PCC (Path Computation Client), via le protocole PCEP (PCE communication Protocol, RFC 5440). Au contraire de la plupart des protocoles vus ici, qui sont Nord-Sud (communication entre des entités de niveau différent), PCEP est Est-Ouest (on peut dire aussi « horizontal », mais le terme n'est pas dans le RFC) faisant communiquer des machines situées au même niveau conceptuel.

Et enfin le protocole BFD (RFC 5880), un protocole de détection de pannes dans les routeurs, prévu pour être très rapide, afin de détecter les problèmes plus tôt que par les techniques de gestion classiques. C'est conceptuellement un service du plan de contrôle.

Pour résumer ? Lire la section 5 et bien se rappeler que 1) SDN ne se limite pas à utiliser OpenFlow 2) Il y a beaucoup de marketing et beaucoup moins de substance.

Quelques lectures classiques citées par notre RFC (la bibliographie de ce RFC est particulièrement longue, reflet de la complexité, de la richesse, et de la confusion du sujet). D'abord, les articles historiques :


Téléchargez le RFC 7426


L'article seul

RFC 7422: Deterministic Address Mapping to Reduce Logging in Carrier Grade NAT Deployments

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : C. Donley (CableLabs), C. Grundemann (Internet Society), V. Sarawat, K. Sundaresan (CableLabs), O. Vautrin (Juniper Networks)
Pour information
Première rédaction de cet article le 26 décembre 2014


Un nouveau RFC pour Big Brother : quand un FAI veut savoir quel abonné utilisait telle adresse IP à tel moment, c'est simple, non, il lui suffit de regarder les journaux du système d'allocation d'adresses ? En fait, non, c'est simple en théorie, mais cela a beaucoup été compliqué par le développement du partage d'adresses, dont l'exemple le plus connu est le CGN. Si la police ou les ayants-droit disent à un FAI « on voudrait savoir qui utilisait 192.0.2.199 le mercredi 24 décembre à 08:20 », le FAI va se rendre compte que des dizaines d'abonnés utilisaient cette adresse IP à ce moment. Trouver l'abonné exact va nécessiter d'examiner d'énormes journaux. Ce RFC propose donc une méthode pour réduire la taille de ces journaux, en attribuant les ports du CGN de manière partiellement déterministe. L'examen des journaux pourra donc être plus efficace et on trouvera plus vite le méchant abonné qui a osé commettre des délits impardonnables, comme de partager des œuvres culturelles.

Le problème de l'identification d'un abonné précis, en présence de partage d'adresses IP est difficile. (Cela concerne IPv4 seulement car IPv6 n'a pas ce problème et son déploiement natif complet résoudrait le problème pour moins cher - cf. RFC 7021 ; mais, comme disaient les Shadoks, « pourquoi faire simple quand on peut faire compliqué ? ») Je recommande fortement la lecture du RFC 6269 pour en saisir tous les aspects. Notez déjà un point important : si on n'a pas noté, au moment de l'observation du comportement illégal, non seulement l'adresse IP source, mais également le port source, on n'a guère de chance de remonter jusqu'à un abonné individuel, dès qu'il y a utilisation du CGN. Un premier pré-requis est donc que les serveurs journalisent le port source (comme demandé par le RFC 6302) et que les systèmes d'observation du réseau enregistrent ce port. Ensuite, muni de l'adresse IP source, du port source, et d'une heure exacte (ce qui suppose que tout le monde utilise NTP ou équivalent, cf. RFC 6269, section 12), on peut aller voir le FAI et lui poser la question « on voudrait savoir qui utilisait 192.0.2.199:5347 le mercredi 24 décembre à 08:20 » (notez la nouveauté, la mention du port, ici 5347). Si le FAI alloue dynamiquement adresses et ports en sortie, et journalise ces allocations, il lui « suffira » de faire un grep dans les journaux pour donner la réponse. Mais, et ce mais est à l'origine de notre nouveau RFC, ces journaux peuvent être de très grande taille.

Le partage massif d'adresses, tel que pratiqué dans les CGN, est motivé par l'épuisement des stocks d'adresses IPv4. Plusieurs RFC décrivent des variantes du concept de CGN (RFC 6264, RFC 6333...) mais tous ont un point commun : une adresse IP est partagée, non pas seulement entre les membres d'un même foyer, mais entre des abonnés d'un même FAI, abonnés qui ne se connaissent pas, et ne forment pas légalement une entité unique. Pas question donc, dans un état de droit, de punir tous les utilisateurs de 192.0.2.199 parce que l'un d'entre eux a fait quelque chose d'illégal, comme de distribuer des fichiers pris dans l'entreprise qui pirate les ordinateurs de ses clients.

A priori, l'information sur qui utilisait quel couple {adresse, port} à un moment donné est connue du CGN. Il l'enregistre, quelque chose du genre (syntaxe imaginaire) :

2014-12-24T08:20:00 Outgoing connection from 10.4.8.2:6234, allocate 192.0.2.199:5347
2014-12-24T08:21:15 192.0.2.199:5347 is now free (used for 10.4.8.2:6234)

Le FAI sait donc que l'adresse interne correspondant à 192.0.2.199:5347 était 10.4.8.2 et il peut alors consulter son plan d'adressage interne pour savoir de quel abonné il s'agit (ou bien consulter un autre journal si ces adresses internes sont elle-mêmes dynamiques). Au fait, si vous voulez un exemple réel des journaux d'un routeur CGN, voici un extrait de la documentation de Juniper :

Jun 28 15:29:20 cypher (FPC Slot 5, PIC Slot 0) {sset2}[FWNAT]: ASP_SFW_CREATE_ACCEPT_FLOW: proto 6 (TCP) application: any, ge-1/3/5.0:10.0.0.1:8856 -> 128.0.0.2:80, creating forward or watch flow ; source address and port translate to 129.0.0.1:1028 
Jun 28 15:29:23 cypher (FPC Slot 5, PIC Slot 0) {sset2}[FWNAT]:ASP_NAT_POOL_RELEASE: natpool release 129.0.0.1:1028[1] 

Comme dans mon exemple imaginaire, on y voit que deux entrées sont enregistrées, pour l'allocation du port et pour sa libération (sur les routeurs A10, on peut configurer séparement les formats de journalisation pour ces deux événements, avec les mots-clés fixed-nat-allocated et fixed-nat-freed).

Mais quelle est la taille de ces journaux de ces CGN ? L'expérience montre des tailles de 150 à 175 octets par entrée, ce qui est la taille de mon exemple imaginaire ci-dessus, qui journalise en mode texte (cela peut bien sûr se faire de manière structurée dans une base de données, ou bien cela peut se comprimer, les journaux texte se réduisent facilement d'un facteur 2 ou 3 à la compression). Mais à quelle rythme les entrées sont-elles créées ? Il ne semble pas y avoir beaucoup d'études précises sur ce sujet mais des observations chez des FAI états-uniens indiquent des moyennes par abonné autour de 33 000 connexions par jour. Cela ferait plus de 5 mégaoctets par jour et par abonné. Avec un million d'abonnés, le FAI devrait stocker 150 téraoctets par mois. Et il faut la capacité d'acheminer ces journaux : avec seulement 50 000 abonnés, il faut dédier 23 Mb/s entre le routeur CGN et le serveur de journalisation.

Et, une fois stockées les données, il reste à les fouiller. Il faut trouver deux évenements (le début de l'allocation et sa fin) au milieu de ces énormes fichiers, ce qui va prendre du temps.

Une solution élégante, préconisée par notre RFC, est d'avoir un mécanisme déterministe d'allocation des ports en sortie, de manière à ne pas avoir à journaliser l'allocation. Il suffira alors de faire tourner l'algorithme à l'envers pour savoir qui avait tel couple {adresse IP publique, port}.

Quelle est la dynamique d'allocation des ports ? Même si un abonné utilise des milliers de connexions par jour, à un instant donné, sa consommation est bien plus faible. Si le rapport entre le nombre d'abonnés et le nombre d'adresses IP publiques est faible (mettons de l'ordre de 10), chaque abonné pourra utiliser des milliers de ports sans gêner les autres. On peut donc allouer des intervalles entiers de ports, sans avoir besoin de journaliser chaque allocation d'un port donné. Il « suffit » donc d'avoir une fonction déterministe, qui associe à chaque adresse IP interne une adresse IP externe et un intervalle de ports externes. Un exemple trivial d'une telle fonction serait l'allocation de l'intervalle 1024-2999 au premier (dans l'ordre des adresses IP internes) abonné, de 3000-4999 au deuxième, etc. Lorsqu'on a épuisé les numéros de port, on passe à la deuxième adresse IP publique et on recommence. En sens inverse, lorsqu'on recevra la requête « qui utiisait 192.0.2.1:4219 le mercredi 24 décembre à 08:20 ? », on saura, sans consulter le journal, que c'était le deuxième de nos abonnés (deuxième intervalle de ports de la première adresse publique). Cette fonction n'est qu'un exemple, la décision d'utiliser telle ou telle méthode est une décision purement locale. (Attention à ne pas allouer les ports séquentiellement dans l'intervalle donné, afin de limiter les risques pour la vie privée de l'abonné. La section 5 du RFC détaille ce risque pour la vie privée, et suggère des mesures.)

Pour cela, le routeur CGN a besoin de connaitre la liste des adresses internes (avec certains CGN comme DS-Lite, technique de coexistence temporaire IPv4/IPv6, ce seront des adresses IPv6, cf. la section 4 de notre RFC), celles des adresses externes disponibles pour sa fonction de CGN, le nombre total d'abonnés (pour calculer le rapport avec le nombre d'adresses publiques), le nombre de ports par utilisateur, la liste des ports à ne pas utiliser, et, bien sûr, la fonction déterministe de correspondance entre une adresse interne et un couple {adresse externe, port externe}. Parmi les fonctions possibles :

  • Allocation séquentielle (comme dans l'exemple proposée plus haut, ou dans l'exemple plus détaillé de la section 2.3 du RFC),
  • Entrelacement : si on a un facteur de 10 entre le nombre d'abonnés et le nombre d'adresses publiques, on alloue à chaque abonné un port sur dix. Le premier abonné a les ports 1024, 1034, 1044, etc,le deuxième 1025, 1035, etc,
  • Alternance sur l'adresse : un abonné utilise toujours le même port externe mais avec une adresse IP publique différente par connexion. Cela ne marche que si on a autant d'adresses IP publiques que de connexions par abonné mais cela simplifie beaucoup la recherche,
  • Méthode cryptographique, inspirée de la section 2.2 du RFC 6431 : on chiffre une concaténation d'une clé et d'autres informations et le résultat chiffré nous donne le port externe à utiliser. Attention, il faudra la clé pour inverser la fonction et donc retrouver l'abonné, il ne faut pas la jeter si on veut pouvoir répondre à des demandes concernant un passé un peu lointain, alors que les clés ont été changées.

Outre les ports « système » (RFC 6335), exclus de l'allocation, il est prudent de garder en réserve un intervalle de ports pour des allocations dynamiques traditionnelles, avec journalisation de l'allocation. Cela permet, par exemple, de gérer les utilisateurs avancés qui utilisent tellement de connexions sortantes qu'ils épuisent l'intervalle des ports. Avec cette réserve, on pourra toujours les satisfaire. Il faudra certes enregistrer ces allocations mais on aura quand même gagné en taille, en ne journalisant que moins d'information.

Comme on n'a rien sans rien, la plupart des méthodes d'allocation déterministe sont moins « efficaces » qu'une allocation purement dynamique, au sens où elles sous-utilisent les ports (pour les utilisateurs peu gourmands). En outre, elles imposent davantage de travail aux équipes opérationnelles (choix d'un algorithme, réglage de ses paramètres...). D'autre part, il ne faut pas s'imaginer qu'un CGN dissimule sérieusement l'abonné final, l'algorithme d'allocation des ports peut toujours être rétroingénierié (cf. section 6, sur la sécurité).

À noter qu'il faut aussi, pour que tout se passe bien, noter la configuration du CGN et ses éventuels changements. Pas question d'appliquer l'algorithme d'aujourd'hui à une requête judiciaire qui concernerait le mois précédent, si l'algorithme ou ses paramètres ont changé. Il faut donc que le routeur CGN journalise également les changements de paramètres (comme le nombre de ports par abonné).


Téléchargez le RFC 7422


L'article seul

RFC 7421: Analysis of the 64-bit Boundary in IPv6 Addressing

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : B. Carpenter (Univ. of Auckland), T. Chown (Univ. of Southampton), F. Gont (SI6 Networks / UTN-FRH), S. Jiang (Huawei Technologies, A. Petrescu (CEA, LIST), A. Yourtchenko (cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 23 janvier 2015


C'est vrai, ça, pourquoi 64 ? Les adresses du protocole IPv6 ont deux parties, une qui identifie le réseau et l'autre qui identifie la machine. Cette dernière est souvent considérée comme faisant forcément 64 bits. Est-ce vraiment une taille impérative ? Et, si oui, pourquoi ? (Si vous êtes pressé, les réponses du RFC sont « non, mais quand même oui » et « essentiellement en raison de la base installée ».)

Pendant la phase de conception d'IPv6, il y avait eu toute une discussion à l'IETF sur la taille idéale des adresses. La plupart des propositions initiales suggéraient 64 en tout, ce qui était déjà beaucoup pour les processeurs de l'époque (de même que, quand IPv4 avait été conçu, peu de processeurs pouvaient traiter 32 bits comme une donnée de base). Mais c'est finalement 128 bits qui a été choisi. 64 bits permettaient déjà d'adresser plus de machines qu'on ne pouvait en rêver. Mais 128 bits permettait plus de souplesse, et autorisait le développement de mécanismes d'adresse rigolos, par exemple d'utiliser des clés crytographiques comme adresses (RFC 7343).

Une fois ce choix fait, le RFC sur l'adressage IPv6, le RFC 4291, introduisait la notion d'identificateur d'interface (interface identifier ou IID). L'adresse comprend alors deux parties, n bits pour identifier le réseau et 128-n bits pour l'identificateur d'interface. Comme précisé par le RFC 7136, ces identificateurs d'interface n'ont pas de signification en dehors de la machine qui les a alloués et doivent donc être traités comme des valeurs opaques.

Le routage se fait sur la base du préfixe réseau, dont la longueur peut être quelconque, jusqu'à 128 bits. Tous les protocoles de routage gèrent des longueurs de préfixe variables, sans supposition a priori.

Bon, donc, le routage n'impose pas de préfixe de longueur 64, et se moque de la longueur du préfixe. Mais l'autoconfiguration d'adresse sans état (SLAAC), du RFC 4862, elle, considère la longueur 64 comme spéciale ? Non plus. Ce chiffre 64 n'apparait pas dans le RFC 4862 car la longueur de l'identificateur d'interface dépend du type de réseau sous-jacent et est donc spécifiée dans un autre RFC, spécifique à chaque technologie. Pour Ethernet, c'est le RFC 2464, et la longueur spécifiée est bien 64. Donc, pour Ethernet, si on veut de l'auto-configuration sans état, on ne peut pas avoir de réseau ayant un préfixe plus long que 64 bits. DHCP (RFC 8415) suit la même règle et n'a donc pas de chiffre « 64 » magique.

Si l'identifiant d'interface à 64 bits est aujourd'hui largement répandu, c'est en partie à cause de la part de marché d'Ethernet. Il était plutôt prévu de le mettre à 48 bits au début avant que les identifiants EUI-64 ne remplacent les EUI-48. Résultat, le RFC 4291 a sérieusement réduit la souplesse d'IPv6 en parlant d'identificateurs d'interface de 64 bits et en laissant entendre qu'ils étaient forcément dérivés d'une adresse MAC (le RFC 7136 a partiellement corrigé cette erreur mais trop tard, beaucoup de gens sont aujourd'hui persuadés que les 64 derniers bits d'une adresse IPv6 sont forcément une adresse Ethernet). Quant à l'autre choix, de fixer les identificateurs d'interface à 64 bits, il n'a pas empêché le RFC 6164 de recommander 1 seul bit pour cet identificateur, dans le cas de liaisons point-à-point.

Malheureusement, un certain nombre de logiciels et de matériels ont peut-être été bâtis en supposant un identificateur d'interface de 64 bits et, hélas, une autre longueur, bien que techniquement correcte, posera des problèmes si on s'approche de ces logiciels et matériels. Pourquoi diable le RFC 4291 a-t-il sanctifié cette valeur de 64 bits ? Et peut-on encore la changer ?

D'abord (section 2 du RFC), les avantages qu'il y a à avoir une frontière fixe entre le réseau et l'identificateur d'interface. Pour l'auto-configuration sans état (SLAAC pour StateLess Address AutoConfiguration), il faut que la longueur du préfixe, pour un type de réseau physique donnée, soit identique pour toutes les machines du réseau local, et connue à l'avance, donc fixe. Bien sûr, elle n'est pas forcément de 64 bits. Mais le poids d'Ethernet, où cette longueur est de 64 bits, et le désir de simplifier les choses (cf. RFC 5505) poussent à l'uniformisation.

Le RFC 4291 (section 2.5.1), on l'a vu, cite déjà cette limite fixe de 64 bits. Le préfixe du réseau local a donc forcément 64 bits de long, quelle que soit la taille du préfixe qui nous a été alloué (au moins un /56, si on suit le RFC 6177). Cela simplifie la conception des réseaux (préfixe de longueur identique sur tous les liens réseaux d'un campus, par exemple, un très gros avantage par rapport à IPv4, où le manque d'adresses oblige à calculer au plus juste chaque longueur de préfixe), la gestion des préfixes (pas besoin de faire un calcul à chaque allocation, un nouveau lien, paf, je lui donne un /64), la configuration des routeurs et la documentation du réseau de l'organisation sont plus simples.

Garantir une certaine taille pour l'identificateur d'interface permet de choisir le mécanisme qu'on veut pour leur allocation. Des préfixes longs risqueraient de réduire la taille de l'espace des identificateurs d'interface, au point de contraindre l'administrateur réseaux dans sa politique d'allocation.

Les sections suivantes du RFC examinent les arguments contre cette taille fixe de 64 bits mais je vous révèle la fin du RFC tout de suite : l'IETF estime que les avantages d'une longueur d'identificateur d'interface plus ou moins fixée à 64 bits l'emportent sur les inconvénients.

Bon, maintenant, pour la culture de mes lecteurs, quels auraient été les raisons de ne pas imposer une taille spéciale aux identificateurs d'interface ? D'abord, le /64 partout peut mener à du gaspillage. J'ai un réseau avec une demi-douzaine de serveurs statiquement configurés, ou bien utilisant DHCP (donc pas de SLAAC), même si chacun d'eux a plusieurs adresses IP, pourquoi ne pourrais-je pas utiliser un /96 ou similaire, pour économiser des adresses ? Bien sûr, l'espace d'adressage d'IPv6 est très grand mais un utilisateur donné peut n'avoir reçu qu'un seul /64, et comment fait-il alors s'il veut mettre plusieurs réseaux physiques derrière ?

Le RFC 7368, portant sur les réseaux à la maison, écarte la solution des préfixes plus longs (cf. sa section 3.4.1) et préfère mettre la pression sur les FAI pour qu'ils distribuent plus d'un préfixe /64. Il n'y a en effet aucune raison de faire des économies : l'espace IPv6 actuellement utilisé (le 2000::/3, qui ne représente que 13 % de l'espace d'adressage possible) permet 35 billions de /48 donc en donner un à chaque utilisateur humain ne pose aucun problème. Même avec un très mauvais « ratio HD », 0,89, on pourrait encore allouer un trillion de préfixes /48 (voir le RFC 4692, sur ces calculs et sur la notion de ratio HD).

Un autre argument a parfois été présenté pour justifier des préfixes plus longs que 64 bits : cela permet d'avoir davantage de réseaux locaux lorsqu'on a reçu une allocation trop petite. Ceci dit, avec un /48, on a 65 536 réseaux, ce qui est déjà énorme. Il a aussi été dit que des préfixes plus longs que 64 bits permettraient, sinon davantage de réseaux, en tout cas une meilleure agrégation des préfixes mais cet argument ne semble pas tenir non plus : même dans le pire cas (routage complètement à plat, zéro agrégation), router des milliers de préfixes ne pose aucun problème.

Une autre raison pour souhaiter des préfixes plus spécifiques que 64 bits vient des exigences de traçabilité. Moins de bits pour l'identifiant d'interface voudrait dire moins de possibilités qu'une machine prenne l'adresse qu'elle veut, ce qui faciliterait la tâche de l'administrateur réseaux. Comme le précédent, cet argument semble très faible : il existe d'autres méthodes pour surveiller ses machines (par exemple ndpmon).

Beaucoup plus sérieux est le risque d'attaque sur le protocole NDP par épuisement du cache (voir les supports d'exposé de Jeff Wheeler). L'idée de l'attaquant est d'envoyer des paquets à des tas de machines non existantes. Le routeur menant au lien de ces machines va devoir faire une résolution d'adresse IP en adresse MAC, avec NDP et, la machine n'existant pas et ne répondant donc pas, le routeur va devoir mettre une demande en attente, dans une mémoire qui a une taille fixe et qui peut donc être vite remplie (le RFC 3756 détaille cette attaque). Avec un /120 (ou bien avec les préfixes typiques d'IPv4, pour qui cette attaque est également possible), l'attaquant ne pourra occuper que 256 entrées dans la mémoire. Avec un /64, il aura beau jeu pour la remplir complètement (même un /96 serait largement suffisant pour l'attaquant). C'est d'ailleurs un argument du RFC 6164 (section 5.2) pour justifier sa recommandation d'un /127.

Notre nouveau RFC estime que ce risque, quoique réel, n'est pas suffisant pour justifier des préfixes ultra-longs (genre /120) et qu'il vaut mieux déployer les recommandations du RFC 6583.

La section 3 parlait des arguments en faveur d'un préfixe plus long que 64 bits. Mais il y a aussi un autre débat, qui est celui sur les préfixes de longueur variable. Un argument en faveur de « tout le monde en /64 » était que cela fournissait une longueur de préfixe constante. Que se passe-t-il si elle ne l'est pas ? La section 4 du RFC se penche là-dessus. D'abord, par rapport aux normes. Malheureusement, la situation est confuse. Si les RFC 4291, RFC 6177, RFC 5453, RFC 6741 et RFC 7084 font tous référence à une longueur magique de 64 bits, ils ne sont pas forcément très clairs et précis sur le statut de cette référence : simple exemple, constatation de l'existant ou réelle normalisation ? Le RFC 5942 dit au contraire que les mises en œuvre d'IPv6 ne doivent pas supposer une longueur de préfixe fixe.

Les RFC décrivant le cas particulier d'une technologie de couche 2 donnée sont en général plus clairs, et beaucoup imposent un identificateur d'interface de 64 bits (et donc un préfixe de 64 bits) pour l'autoconfiguration sans état. C'est le cas des RFC 2464 (Ethernet, déjà cité), RFC 2467 (FDDI), RFC 4338 (Fibre Channel), RFC 5072 (PPP), etc.

D'autres RFC semblent (mais c'est souvent vague) supposer qu'un identifiant d'interface fait forcément 64 bits. C'est le cas du RFC 4862 pour les adresses locales au lien, du RFC 4429 pour la détection d'adresses dupliquées, du RFC 5969 sur 6rd, du RFC 6437 au sujet du flow label, etc. Dans certains cas, la dépendance vis-à-vis de la longueur du préfixe est plus nette, comme une technique pour étendre un préfixe IPv6 reçu en 3G sur une interface WiFi (RFC 7278), dans les CGA du RFC 3972 ou dans les adresses protégeant la vie privée du RFC 8981.

Et si on est courageux, et qu'on essaie quand même de mettre des identificateurs d'interface dont la longueur est différente de 64 ? Que risque-t-on ? D'abord, certains routeurs peuvent avoir mal lu les spécifications et penser que des identificateurs d'interface entre 65 (RFC 7136) et 126 (RFC 6164) sont invalides, refusant de configurer ainsi une interface ou, pire, refusant ensuite de transmettre des paquets. (Je n'ai pas connaissance d'un étude systématique de routeurs à ce sujet, ni de récit détaillé d'un problème avec un routeur.) CGA, on l'a vu, ne marcherait pas du tout. On peut changer sa spécification mais attention, diminuer la taille de l'identificateur d'interface diminuerait la sécurité de CGA (même chose pour les techniques qui visent à protéger la vie privée par des identificateurs d'interface choisis aléatoirement, cf. section 4.5). Par contre, NAT64 (RFC 6146) marcherait sans doute, jusqu'à 96 bits de préfixe réseau (car il faut garder au moins 32 bits pour l'adresse IPv4 de destination). En revanche, NPT (Network Prefix Translation, RFC 6296) est lié aux 64 bits. Même chose pour ILNP (RFC 6741).

Le mécanisme DAD (Duplicate Address Detection, RFC 4862, section 5.4) pourrait avoir des problèmes si on réduisait trop la taille des identificateurs d'interface. Par exemple, avec un /120, et les adresses du RFC 7217, il n'y aurait que 256 identificateurs d'interface possible et donc des risques de collision élevés. Enfin, les adresses locales au lien, bien que prises dans un espace très large (fe80::/10) sont en fait quasiment toujours formées pour un préfixe de longueur 64 (et l'espace réel est donc fe80::/64) et il n'y a pas de moyen simple de le changer (ce n'est que rarement une option de configuration de la machine).

La section 4.3 contient les résultats d'essais systématiques d'essais de préfixes différents de /64, essais faits avec plusieurs systèmes d'exploitation. Avec des préfixes plus longs ou plus courts que 64 bits, et un routeur qui annonce, via les RA (Router Advertisement), un tel préfixe dans le champ Prefix Information Option, tout marche bien sur tous les Unix et sur Windows (l'essai a également été fait sans le bit L dans l'option, bit qui indique que le préfixe pour être utilisé pour déterminer si le préfixe est sur le lien local et, dans ce cas, les machines ignorent à juste titre le préfixe). Par contre, l'option Route Information Option du RFC 4191 marche nettement moins bien sur les Unix, mais c'est le cas même avec une longueur de 64 bits.

D'autre part, les informations recueillies par les participants à l'IETF sur divers réseaux indiquent que les routeurs routent bien sur des préfixes de longueur quelconque (la recherche d'une route du préfixe le plus long est un algorithme de base d'IP, il est plus ancien qu'IPv6). Et, dans les expériences pratiques, DHCP ne semble pas avoir de problème non plus (un déploiement réel utilise des /120...)

Certains routeurs ont des problèmes de performance car ils traitent à part les préfixes plus longs que 64 bits. Cela fonctionne mais pas aussi vite.

Au moins un équipement réseau à une TCAM limitée à 144 bits ce qui fait que les ACL ne peuvent pas être définies pour un préfixe quelconque, puisqu'elles permettent également de mettre deux ports de 16 bits chacun. Avec un tel équipement, on ne peut pas utiliser d'ACL avec un préfixe plus long que 112 bits.

Bref, la situation des mises en œuvre d'IPv6 ne semble pas trop mauvaise. Contrairement à ce que l'on aurait pu craindre, peu ou pas de programmeurs ont, en lisant trop vite les spécifications, considéré qu'un identificateur d'interface était toujours de 64 bits et, donc, peu de programmes ont cette taille « câblée en dur ». Évidemment, on ne peut pas être sûr tant qu'on n'a pas testé toutes les implémentations, une tâche impossible.

Il n'y a pas que le code IPv6 proprement dit : il y a aussi les outils auxiliaires comme les IPAM. Ont-ils également une taille de préfixe magique fixée dans leur code ? Apparemment, cela n'a pas été testé.

Il y a aussi les craintes liées aux humains : si on décidait de mettre des identificateurs d'interface d'une longueur différente de 64 bits, ne risque-t-on pas d'avoir à reprendre la formation de certains, qui ont mal compris leur cours IPv6 et croient que 64 bits a une signification spéciale ?

Un éventuel changement de la longueur des identificateurs d'interface a aussi des conséquences pour la sécurité. D'abord, la vie privée (section 4.5) : si on tire au sort un identificateur d'interface, pour le rendre difficile à deviner par un observateur indiscret, l'identificateur ne doit évidemment pas être trop petit, sans cela l'observateur pourrait essayer la force brute pour le deviner. Il est difficile de donner un chiffre précis mais notre RFC estime qu'un préfixe de plus de 80 bits, laissant moins de 28 bits pour l'identificateur d'interface, serait trop prévisible.

La longueur de l'identificateur d'interface a également des conséquences pour le balayage (RFC 7707) : il est beaucoup plus difficile de balayer systématiquement un réseau IPv6 qu'un réseau IPv4, en raison du nombre d'adresses possibles. Si on a un long préfixe, le balayage devient réaliste : un /120 IPv6 prendrait autant de temps à balayer qu'un /24 IPv4, c'est-à-dire très peu de temps. (Le problème est proche de celui des CGA, et de celui de la vie privée, déjà cité : beaucoup de techniques de sécurité dépendent de la taille de l'espace possible, en la réduisant, on facilite les attaques.)

En conclusion, si certains points d'IPv6 ne devraient absolument pas dépendre de la longueur du préfixe, qui est un simple paramètre (le routage, par exemple), d'autres sont bien plus liés au nombre magique de 64. Sans compter le risque qu'une partie de la base installée (et pas seulement logicielle, aussi les humains) ait attribué à ce nombre 64 encore plus d'importance que ce que les normes IPv6 prévoient. Le RFC décide donc d'entériner cet usage et de recommander qu'on ne s'éloigne pas de 64 sans de très bonnes raisons.


Téléchargez le RFC 7421


L'article seul

RFC 7418: An IRTF Primer for IETF Participants

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : S. Dawkins (Huawei)
Pour information
Première rédaction de cet article le 13 décembre 2014


Ce court RFC est une introduction à une entité peu connue du monde de l'Internet, l'IRTF, Internet Research Task Force. Tellement peu connue qu'elle n'a même pas de page dans le Wikipédia francophone, c'est dire. L'IRTF est censée travailler sur des projets à long terme (proches de la recherche), pendant que l'IETF travaille sur des sujets bien maîtrisés techniquement, et qu'on peut normaliser relativement rapidement. Cette introduction vise essentiellement les gens qui participent déjà à l'IETF et se demandent si leur prochain projet ne serait pas plus adapté à l'IRTF.

Disons-le franchement tout de suite, l'IRTF n'est pas toujours le truc le plus intéressant dans la vaste galaxie des entités dont le nom commence par un I. La plus grande partie de la recherche concernant l'Internet n'est pas faite là. L'IRTF, très peu connue, et vivant dans l'ombre de l'IETF, n'a pas une activité débordante.

Un des problèmes de l'IRTF, et auquel ce RFC voudrait remédier, est que beaucoup de participants potentiels à l'IRTF croient acquis que ses pratiques sont les mêmes qu'à l'IETF. Ils présentent leurs idées d'une manière qui serait appropriée à l'IETF mais qui ne marche pas pour l'IRTF. D'abord, il faut comprendre la différence entre recherche et ingéniérie. Deux citations l'illustrent, une de Fred Baker qui estime que « le résultat de la recherche, c'est la compréhension, le résultat de l'ingéniérie, c'est un produit ». Et la seconde, de Dave Clark, affirme que « si ça doit marcher à la fin du projet, ce n'est pas de la recherche, c'est de l'ingéniérie ». Le RFC résume en disant que « la recherche, c'est un voyage, l'ingéniérie, c'est une destination ». Un chercheur qui ouvre plus de questions qu'il n'en a fermé dans sa recherche peut être satisfait. Un ingénieur qui ne termine pas ne l'est pas.

Cela entraine des différences entre l'organisation de l'IETF et celle de l'IRTF (section 2 du RFC). Par exemple, les unités de base de l'IETF, les groupes de travail, sont très focalisés, avec une charte précise, des buts à atteindre, et un calendrier. Les unités de base de l'IRTF, les groupes de recherche, sont au contraire larges, traitant plusieurs sujets assez différents en même temps, et avec une charte bien plus large.

De même, les délais ne sont pas les mêmes. L'IRTF, travaillant sur des problèmes difficiles, voit typiquement à trois ou cinq ans, alors que les calendriers (très théoriques...) des groupes de travail IETF visent des échéances plus courtes.

Autre différence, alors que l'IETF est supposé arriver à un consensus (approximatif) entre les membres du groupe de travail (RFC 7282), l'IRTF n'a pas de telles obligations et peut parfaitement, par exemple, suivre plusieurs lièvres à la fois.

L'IRTF n'est pas non plus obligée de suivre les politiques de l'IETF relatives aux brevets (RFC 8179).

Et sur le résultat du groupe de recherche ? En quoi doit-il consister ? Un groupe de travail IETF produit des RFC, c'est son but. Mais un groupe de recherche IRTF ne le fait pas forcément. Il peut aussi publier par d'autres moyens (rapports, articles académiques...), voire se contenter d'Internet-Drafts qui ne deviendront pas de RFC. Le critère du succès, pour un groupe IRTF, c'est de faire avancer la science, pas de faire des RFC.

Maintenant que la section 2 a surtout expliqué ce que l'IRTF n'est pas, la section 3 donne des conseils sur ce qu'il faut faire quand on veut travailler à l'IRTF. L'actuel président de l'IRTF, Lars Eggert, le résume en disant « comportez-vous comme un groupe de recherche IRTF pendant un an, et on verra bien si vous en êtes un ». Et comment est un groupe de recherches IRTF ? Le RFC 4440 donne quelques pistes, purement indicatives :

  • Rassemblez des chercheurs, en nombre suffisant, qui veulent travailler sur ce sujet,
  • Analysez bien ce qui se fait ailleurs, en vous demandant ce que le futur groupe de recherche IRTF apporterait, par rapport à ces activités externes,
  • Organisez un premier atelier pour voir ce que cela donne,
  • Si vous estimez que cette recherche peut déboucher sur des techniques normalisables, trouvez quelques ingénieurs pour jeter un coup d'œil et voir si c'est faisable.

Si vous vous intéressez plutôt aux règles et procédures de fonctionnement de l'IRTF, plutôt qu'à la vision « haut niveau » exposée ici, voyez le RFC 2014. Si vous voulez lire mes articles sur des RFC issus de l'IRTF, demandez au moteur de recherche.


Téléchargez le RFC 7418


L'article seul

RFC 7416: A Security Threat Analysis for Routing Protocol for Low-power and lossy networks (RPL)

Date de publication du RFC : Janvier 2015
Auteur(s) du RFC : T. Tsao, R. Alexander (Cooper Power Systems), M. Dohler (CTTC), V. Daza, A. Lozano (Universitat Pompeu Fabra), M. Richardson (Sandelman Software Works)
Pour information
Réalisé dans le cadre du groupe de travail IETF roll
Première rédaction de cet article le 6 janvier 2015


Le protocole de routage RPL (Routing Protocol for Low power and lossy networks) est conçu pour des objets connectés, nombreux, mais pas gérés, et qui doivent s'organiser tout seuls pour trouver un chemin dans le réseau. Ces objets peu intelligents soulèvent souvent des problèmes de sécurité spécifiques : ils ne sont pas gérés par un administrateur système compétent, ils ont des capacités de calcul limitées, ce qui réduit le recours à la cryptographie, ils ont une interface utilisateur réduite au minimum, ce qui fait qu'entrer une clé WPA est très pénible, etc. Ce nouveau RFC documente les problèmes de sécurité de RPL.

C'est que l'Internet des Objets est à la mode. On voudrait que chaque brosse à dents soit connectée à l'Internet, et qu'elle discute avec le tube de dentifrice et le frigo sans qu'un humain n'ait besoin de configurer manuellement le routage. On a des solutions techniques pour cela, celle qui est au cœur de ce RFC étant le protocole de routage RPL, normalisé dans le RFC 6550. Mais si ces solutions permettent au LLN (Low-power and Lossy Network, réseau limité en capacité et en énergie, cf. RFC 7102) de fonctionner, elles ne garantissent pas sa sécurité. Or, ces réseaux d'objets ont souvent des exigences sérieuses en sécurité (pensez à la distribution d'électricité, par exemple). Les RFC 6574 et RFC 7397 avaient déjà abordé ce problème. Ici, on n'examinera pas l'ensemble des problèmes de sécurité des LLN, on se concentrera sur le routage.

Pour une introduction générale aux problèmes de sécurité du routage, on peut aussi consulter le RFC 4593 (qui détaille notamment les types d'attaquants) et l'article de C. Karlof et D. Wagner, « Secure routing in wireless sensor networks: attacks and countermeasures ». La section 4.3 de notre RFC se focalise sur les problèmes spécifiques aux LLN (déjà abordés dans les RFC 5548, RFC 5673, RFC 5826 et RFC 5867) :

  • Les machines connectés au LLN (les objets) ont des ressources limitées en énergie (batterie de capacité limitée), mémoire et CPU. Comme toujours, la sécurité sera un compromis et, dans le cas d'un LLN, un compromis difficile : il va falloir faire de sérieux sacrifices.
  • Les LLN sont a priori de grande taille. Il ne s'agit pas de quelques ordinateurs qu'on a configurés manuellement mais de centaines ou de milliers d'objets dispersés sur le site. Toute solution de sécurité qui nécessiterait une action compliquée de configuration sur chaque objet est vouée à l'échec.
  • Les objets sont censés fonctionner de manière autonome, et se débrouiller seuls, dans un réseau qui n'est pas géré et évolue sans cesse.
  • La sécurité physique est très minimale. Les objets sont placés à des endroits divers, parfois éloignés, sans qu'on puisse forcément les enfermer dans une cage.
  • Certains objets s'endorment de temps en temps, pour économiser l'énergie. Cela complique sérieusement le déploiement de certaines solutions de sécurité. Par exemple, si on distribue de nouvelles clés cryptographiques, les nœuds endormis ne les auront pas eues.

Malgré ces conditions difficiles, on voudrait que RPL obtienne :

  • Des données de routage quand il en a besoin (disponibilité),
  • Des données de routage non modifiées en route (intégrité),
  • Des données de routage qui viennent bien des machines autorisées (authenticité),
  • Et, même si c'est nettement moins important, des données de routage qui ne sont pas publiées à tous les vents (confidentialité).

La section 6 de notre RFC énumère les attaques possibles, en insistant sur celles spécifiques aux LLN (ou qui sont plus graves pour un LLN). D'abord, il y a le risque d'usurpation d'un nœud existant. Une machine méchante peut arriver, se glisser dans le réseau, et communiquer en prétendant être un des nœuds légitimes. Rappelez-vous que, dans RPL, n'importe quel nœud peut être routeur et donc annoncer des routes. Un usurpateur peut ainsi détourner le trafic destiné à un autre nœud. Ce détournement peut avoir de sérieuses conséquences, même si on a déployé une sécurité applicative (par exemple en utilisant TLS systématiquement) : le méchant peut retarder des messages, les re-jouer, etc. Même si les techniques de sécurité utilisées empêchent ce méchant d'usurper l'identité d'une machine existante, on peut quand même avoir des attaques où le méchant usurpe une identité, n'importe laquelle, non plus dans le but de se faire passer pour tel ou tel nœud mais simplement pour exploiter les droits d'un membre du LLN. Là encore, il peut annoncer des routes (détournant par exemple tout le trafic vers lui). Enfin, si le réseau est très ouvert (n'importe qui peut s'y joindre, identité ou pas), des attaques par épuisement des ressources peuvent avoir lieu. Rappelez-vous que, dans un LLN, certaines ressources sont sévèrement limitées, comme la capacité des batteries. En envoyant beaucoup de messages sans intérêt (spam), un attaquant pourrait priver pas mal de membres du LLN d'énergie.

Si on réussit à authentifier correctement tous les nœuds du LLN, et donc à empêcher les attaques du paragraphe précédent, un méchant a encore la possibilité de modifier les informations de routage, et donc, au final, de contrôler les routes utilisées. Un nœud authentifié peut encore mentir (annoncer des routes qu'il n'a pas ou bien le contraire, c'est un exemple de comportement byzantin), mais on peut aussi imaginer une modification de l'information entre les nœuds (WiFi pas protégé, par exemple).

Enfin, si on réussit à empêcher mensonges et modifications, l'attaquant peut quand même dans certains cas lancer des attaques contre le réseau en l'empêchant tout simplement de fonctionner (attaque par déni de service). Certaines solutions aux problèmes précédents peuvent aggraver ce risque. Ainsi, si on met de la cryptographie partout, un attaquant peut envoyer des messages, certes faux et détectables, mais qu'il faudra tenter de déchiffrer, ce qui consommera des ressources.

La section 7 de notre RFC couvre les contre-mesures générales, qui peuvent être utilisées dans beaucoup de cas (la section 8 parlera des contre-mesures effectivement existantes dans RPL).

Par exemple, contre les écoutes purement passives, la solution est évidemment le chiffrement des messages de routage. Le mécanisme obligatoire en RPL est AES en mode CCM (RFC 3610). Par contre, ZigBee n'a pas de protection à ce niveau et compte sur celles du niveau 2.

Pour les attaques actives, c'est évidemment plus difficile. Une méthode d'attaque courante dans les réseaux ouverts, comme le sont souvent les LLN, est d'envoyer un grand nombre de machines joindre le réseau, pour ensuite le contrôler par la simple majorité (attaque Sybil). La solution est d'authentifier les machines, via une clé publique. Cela ne protège pas contre les byzantins. Un protocole comme OSPF, où tout le monde reçoit toute l'information, peut se défendre contre les byzantins en comparant ce que reçoivent les différents nœuds. RPL n'a pas cette possibilité et il faut donc chercher des nœuds de confiance, qui fourniront une information qu'on pourra comparer avec celle reçue des pairs (BGP a le même problème et utilise ce genre de solutions). On peut aussi utiliser des canaris, des machines qui doivent être joignables en permanence : si elles cessent de l'être après une nouvelle annonce de route, cela peut signifier une attaque. Si un nœud tente une attaque « évier » (attirer tout le trafic par des annonces de routage mensongères, pour ensuite le jeter), il faudra également le détecter et le noirlister (ne plus tenir compte de ses annonces). On pourra aussi utiliser des indications géographiques (un capteur situé dans le bâtiment A.2 pourra trouver suspect que la meilleure route vers un collecteur du même bâtiment passe par un autre bâtiment).

Et les attaques contre les batteries, surchargeant le réseau de messages à traiter pour vider les accus ? Il faudra sans doute des limiteurs de trafic (voire des quotas de trafic), des mécanismes de détection des nœuds trop bavards, etc.

Enfin, la section 8 de notre RFC décrit les méthodes déployées dans RPL. Comme vu plus haut, RPL a un mécanisme de chiffrement, pour assurer la confidentialité (section 10.9 du RFC 6550) mais qu'il n'est pas obligatoire d'activer car RPL peut se reposer sur la sécurité de la couche 2 (WPA en WiFi par exemple). C'est un peu la même chose pour l'intégrité des messages (à mon avis bien plus importante que la confidentialité, pour un protocole de routage) : si RPL peut compter sur une couche 2 sécurisée, c'est bon, sinon, RPL a son propre mécanisme d'intégrité, avec un MAC calculé, par exemple, avec AES.

Pour la disponibilité du réseau, RPL prévoit les mécanismes suivants dans ses routeurs :

  • Ils peuvent limiter la cardinalité des voisins,
  • Garder en mémoire plusieurs chemins pour une destination donnée (avec choix aléatoire),
  • Avoir des quotas de transmission et de réception,
  • Utiliser des informations extérieures à RPL pour évaluer la fiabilité d'une information RPL (comme l'utilisation de la géographie connue dans l'exemple précédent).

À noter que RPL n'a pas de mécanisme de gestion des clés cryptographiques. Celles-ci doivent être fournies et renouvelées en dehors de RPL.

Pour résumer, on peut dire que les exigences de ces réseaux d'objets (autoconfiguration, non-gestion) ne vont pas dans le sens de la sécurité et on peut donc s'attendre à pas mal de problèmes dans les années à venir.


Téléchargez le RFC 7416


L'article seul

RFC 7414: A Roadmap for Transmission Control Protocol (TCP) Specification Documents

Date de publication du RFC : Février 2015
Auteur(s) du RFC : M. Duke (F5), R. Braden (ISI), W. Eddy (MTI Systems), E. Blanton, A. Zimmermann (NetApp)
Pour information
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 3 février 2015


C'est un RFC récapitulatif. Il ne normalise rien de nouveau mais dresse une liste commentée des RFC dont la connaissance est indispensable, ou simplement utile, au programmeur qui met en œuvre TCP.

Depuis sa normalisation, il y a plus de trente ans (dans le RFC 793), TCP a complètement remplacé NCP. TCP est un des grands succès de l'Internet : quasiment toutes les applications Internet s'appuient sur ce protocole.

Mais le RFC normatif, le RFC 793, quoique toujours valable à l'époque, était bien vieux car beaucoup de choses avaient été ajoutées ou retirées à TCP depuis. (Mais, depuis la publication de ce RFC 7414, la norme TCP a été enfin remplacée, par le RFC 9293.) Comme pour beaucoup d'autres protocoles Internet (par exemple le DNS), TCP met donc le programmeur en face d'une rude tâche : avant de commencer à coder, il doit d'abord dresser la liste de tous les RFC dont il aura besoin. Et il faudra qu'il pense à chaque fois à regarder si des errata ont été publiés. C'est cette tâche d'établissement de liste que lui épargne notre RFC en dressant cette liste, et en la rangeant en trois sections, ce qui est impératif pour un TCP moderne (section 2 de notre RFC), ce qui est fortement souhaité (section 3), et ce qu'on peut ajouter si on veut (section 4). Ce « méta-RFC » a donc une bibliographie particulièrement longue, comportant 135 autres RFC. Le groupe de travail avait discuté de l'utilisation d'une autre méthode qu'un RFC, par exemple un Wiki, qui pourrait être plus facilement maintenu à jour, mais sans arriver à se décider pour une autre solution. (Notre nouveau RFC succède au RFC 4614, actualisant ses recommandations.)

Par exemple, le document original sur TCP ne contient rien sur le contrôle de congestion, qui ne sera décrit que dans le RFC 2001. Ce RFC 2001 (ou plus exactement son successeur, le RFC 5681) fait désormais partie de ceux qu'il faut lire. Notez que cette importance n'est pas forcément liée au statut officiel du RFC : le RFC 5681 n'est que projet de norme, alors qu'il est considéré essentiel. On trouve aussi dans cette section le RFC 6298, sur le calcul du délai avant retransmission, ou le RFC 6691 sur le calcul de la MSS.

Dans la section de ce qui est fortement recommandé (section 3), on trouve par exemple le RFC 7323 qui décrit plusieurs extensions nécessaires pour tirer des performances élevées, ou bien le RFC 3168 qui normalise ECN, ou encore le RFC 6582, sur l'algorithme NewReno.

Cette section compte également des RFC décrivant l'abandon d'options ou d'extensions inutiles, voire néfastes. C'est le cas du RFC 6633 qui supprime le mécanisme de répression de l'émetteur.

La sécurité ayant bien plus d'importance aujourd'hui, d'autres RFC décrivent comment se défendre contre certaines vulnérabilités par exemple la lecture du RFC 5961 va apprendre aux programmeurs de TCP comment résister aux attaques en aveugle, et celle du RFC 6528 est indispensable pour empêcher un attaquant d'insérer des paquets dans une session TCP existante.

D'autres extensions sont moins consensuelles et restent plutôt expérimentales à ce jour (section 4) comme l'algorithme Eifel du RFC 3522. Certaines de ces extensions non consensuelles sont encore récentes et s'imposeront peut-être, comme l'extension de la fenêtre initiale (RFC 6928) ou comme l'algorithme de réduction proportionnelle (RFC 6937).

Enfin certaines extensions ont été abandonnées, l'expérience ayant montré leur inutilité ou leur nocivité (section 6 du RFC). C'est ainsi que la proposition du RFC 1146 de tenter de nouveaux moyens de calcul de la somme de contrôle n'a pas pris.

Le protocole T/TCP, normalisé dans le RFC 1644, aurait permis de diminuer nettement la durée des connexions courtes, celles où on échange peu de données (beaucoup de connexions HTTP sont dans ce cas). Promu par des experts comme Stevens, implémenté dans des systèmes comme FreeBSD (option MSG_EOF de sendto), il a été remisé au grenier après que des analyses plus poussées aient montré ses failles de sécurité (il facilite l'utilisation de TCP avec usurpation d'adresses IP). Même sort pour le plus récent RFC 6013 qui décrivait un TCP Cookie Transaction mais qui n'a finalement pas suscité beaucoup d'intérêt. En revanche, TCP Fast Open (RFC 7413) est actuellement la méthode à la mode pour diminuer la latence.

Les RFC de ces extensions abandonnées ont été reclassifiés comme « intérêt historique seulement » dans le RFC 6247.

Notre RFC décrit ensuite les RFC d'architecture ou de concepts, puis les RFC qui s'appliquent à certains environnements difficiles comme les liaisons satellite qui font l'objet des RFC 2757 et RFC 2760 ou les liaisons fortement asymétriques, comme le sont les lignes ADSL (traitées dans le RFC 3449).

De nombreux autres cas sont ensuite traitées dans notre RFC. Notre implémenteur n'a pas fini de tout lire !

La section 8 couvre enfin un cas délicat : les extensions à TCP qui, bien que largement utilisées, n'ont jamais fait l'objet d'un RFC ni même, souvent, d'une description formelle. C'est par exemple le cas de la prédiction d'en-tête, une méthode développée par Van Jacobson et Mike Karels à la fin des années 1980 pour accélérer le traitement des paquets TCP en essayant de prédire ce qu'allaient contenir leurs en-têtes. On programme un chemin rapide pour les paquets qui sont conformes aux prévisions et un chemin plus lent pour les paquets (minoritaires) qui surprennent. Van Vacobson avait décrit cette astuce dans un célèbre message de 1988 « The idea is that if you're in the middle of a bulk data transfer and have just seen a packet, you know what the next packet is going to look like ».

C'était aussi le cas des syncookies, option indispensable sans laquelle un serveur Internet peut être mis à genoux très vite par une attaque SYN flood pour laquelle il n'y a même pas besoin de développements spécifiques, l'outil hping suffisant à l'attaquant. Ces petits gâteaux ont finalement été décrits dans le RFC 4987.


Téléchargez le RFC 7414


L'article seul

RFC 7413: TCP Fast Open

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : Y. Cheng, J. Chu, S. Radhakrishnan, A. Jain (Google)
Expérimental
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 19 décembre 2014


Quand on parle de performances sur l'Internet, on se focalise souvent exclusivement sur la capacité du réseau. C'est, par exemple, l'argument quasi-exclusif des FAI : « Avec la fibre Machin, passez à la vitesse supérieure, XXX Mb/s ». Mais un autre facteur de la qualité de l'expérience utilisateur est la latence, à savoir le temps qu'il faut attendre pour recevoir une réponse. Par exemple, pour accéder à une page Web, avant même d'envoyer le premier octet « utile », il faut réaliser une « triple poignée de mains » (RFC 793, section 3.4) avec le serveur, pour établir la connexion, et cette poignée de mains nécessite pas moins de trois paquets, donc il faudra attendre trois fois le temps d'un aller simple, avant de pouvoir foncer et envoyer les images de chats (ou de loutres). Ce nouveau RFC, encore officiellement expérimental, mais déjà largement déployé, vise à raccourcir ce délai d'ouverture d'une connexion avec le serveur.

L'idée est ancienne (on la trouve par exemple dans le système T/TCP du RFC 1644, et dans les autres systèmes résumés en section 8) mais le problème est plus difficile à résoudre qu'il n'en a l'air, notamment si on veut garder un bon niveau de sécurité (le problème qui a tué T/TCP). L'idée est ancienne, car devoir attendre trois voyages avant de pouvoir envoyer les données contribue sérieusement à la latence d'applications comme le Web. Si le serveur est à 100 ms de distance, on attendra au moins 300 ms avant que des données ne commencent le voyage. Et, contrairement à la capacité, la latence ne s'améliore pas avec le temps et les progrès de l'électronique. Des mesures faites sur Chrome montre que la triple poignée de mains de TCP est responsable de 25 % de la latence moyenne des requêtes HTTP. Il existe des solutions pour certaines applications. Par exemple, pour HTTP, on peut utiliser les connexions persistantes (RFC 7230, section 6.3). L'établissement de ces connexions prendra autant de temps qu'avant mais ce « coût » ne sera payé qu'une fois : les requêtes/réponses ultérieures avec le même serveur HTTP réutiliseront la connexion TCP existante (et, si elles ne viennent pas, la connexion finit par être coupée, par exemple au bout de cinq minutes pour Chrome). Le problème est que ces connexions persistantes ne sont pas assez répandues. Les mesures des auteurs du RFC (Radhakrishnan, S., Cheng, Y., Chu, J., Jain, A., Raghavan, B., « TCP Fast Open », Proceedings of 7th ACM CoNEXT Conference, 2011) montrent que 35 % des requêtes nécessitent la création d'une nouvelle connexion TCP. Il serait agréable de pouvoir accélérer ces créations. La triple poignée de mains prend trois paquets, SYN (du client vers le serveur), SYN + ACK (du serveur vers le client) et ACK (du client vers le serveur). Les données ne voyagent qu'après. L'idée de base de TCP Fast Open (TFO), technique venant de chez Google, est de mettre les données dès le premier paquet SYN du client.

Le plus drôle est que le TCP original n'interdit pas de mettre des données dans le paquet SYN (section 2 de notre RFC). Bien au contraire, c'est explicitement autorisé par la section 3.4 du RFC 793 (« Although these examples do not show connection synchronization using data-carrying segments, this is perfectly legitimate [...] »). Mais avec une grosse restriction, que les données ne soient délivrées au serveur d'applications qu'une fois la triple poignée de mains terminée, ce qui en supprime l'intérêt. Cette règle a pour but d'éviter que des données soient envoyées deux fois (le paquet SYN peut être perdu et retransmis). Les variantes de TCP qui ont essayé d'optimiser le temps d'ouverture de connexion ont en général choisi de sacrifier de la sécurité, afin de maintenir la sémantique de TCP, ce qui n'est en général pas considéré comme acceptable de nos jours (RFC 7414). TCP Fast Open sacrifie, lui, la non-duplication des données : un serveur Fast Open peut, dans certains cas (par exemple si le serveur a redémarré entre les deux SYN), recevoir deux fois les mêmes données envoyées dans un paquet SYN. Ce n'est pas toujours si dramatique que ça en a l'air. Pour HTTP, le premier paquet de données du client sera sans doute un GET /something HTTP/1.1 et cette requête peut être effectuée deux fois sans conséquences graves. Première chose à retenir, donc, sur Fast Open : il ne convient pas à toutes les applications. TCP Fast Open est juste un compromis. Les systèmes ne doivent donc pas l'activer par défaut (les exemples plus loin montrent comment un programme Unix peut activer explicitement Fast Open). La section 4.2 insistera sur ce point.

Et la sécurité ? Le TCP normal présente une vulnérabilité : les paquets SYN n'ayant aucune forme d'authentification, un attaquant peut, en trichant sur son adresse IP, envoyer des paquets SYN sans révéler son identité et ces paquets, s'ils sont assez abondants, peuvent remplir la file d'attente du serveur (attaque dite « SYN flood »). C'est encore pire avec Fast Open puisque ces requêtes en attente comprennent des données, et peuvent déclencher l'exécution de commandes complexes (GET /horrible-page-dont-la-génération-nécessite-10000-lignes-de-Java-ou-de-PHP HTTP/1.1...) Les techniques du RFC 4987 ne sont en général pas appliquables à Fast Open. C'est pour cela que Fast Open ajoute un composant essentiel : un petit gâteau (cookie) généré par le serveur et que le client devra transmettre pour bénéficier du Fast Open.

La section 3 décrit en termes généraux le protocole. À la première connexion Fast Open d'une machine vers une autre, le client envoie l'option TCP (pour les options TCP, voir la section 3.1 du RFC 793) 34 TCP Fast Open Cookie (désormais dans le registre IANA mais attention, les mises en œuvre actuelles utilisent souvent la valeur expérimentale précédente) avec un contenu vide. Si le serveur gère Fast Open, il répondra (dans le SYN + ACK) avec un gâteau (cookie), généré par lui et imprévisible. Dans les connexions TCP ultérieures, le client renverra l'option Fast Open Cookie avec le même gâteau. Le serveur le reconnaitra alors. Les requêtes SYN comportant ce gâteau pourront inclure des données, elles seront transmises tout de suite aux applications qui le demandent (et on aura alors du beau TCP Fast Open) et le premier paquet de réponse pourra inclure des données (dans les limites données par le RFC 5681). On voit donc que la première connexion entre deux machines ne bénéficiera pas de Fast Open. Mais toutes les suivantes, oui (sur Linux, le noyau se souviendra du gâteau). Si le serveur ne gère pas cette option, il répond par un SYN + ACK sans l'option, informant ainsi le client qu'il ne doit pas compter sur Fast Open.

Voici, vu avec tcpdump, un exemple d'une session TCP Fast Open d'une machine Debian/Linux (version jessie) vers Google. Le gâteau (32a8b7612cb5ea57) est en mémoire chez le client (les options TCP sont affichées entre crochets, la « nôtre » est exp-tfo) :

20:10:39.920892 IP (tos 0x0, ttl 64, id 6594, offset 0, flags [DF], proto TCP (6), length 158)
    106.186.29.14.53598 > 173.194.38.98.80: Flags [S], cksum 0x5c7d (incorrect -> 0x9bd5), seq 1779163941:1779164027, win 29200, options [mss 1460,sackOK,TS val 114031335 ecr 0,nop,wscale 7,exp-tfo cookie 32a8b7612cb5ea57], length 86
20:10:39.923005 IP (tos 0x0, ttl 57, id 3023, offset 0, flags [none], proto TCP (6), length 52)
    173.194.38.98.80 > 106.186.29.14.53598: Flags [S.], cksum 0xae4c (correct), seq 1775907905, ack 1779164028, win 42900, options [mss 1430,nop,nop,sackOK,nop,wscale 6], length 0
20:10:39.923034 IP (tos 0x0, ttl 64, id 6595, offset 0, flags [DF], proto TCP (6), length 40)
    106.186.29.14.53598 > 173.194.38.98.80: Flags [.], cksum 0x5c07 (incorrect -> 0x95af), ack 1, win 229, length 0
20:10:39.923462 IP (tos 0x0, ttl 57, id 3024, offset 0, flags [none], proto TCP (6), length 589)
    173.194.38.98.80 > 106.186.29.14.53598: Flags [P.], cksum 0xcdd1 (correct), seq 1:550, ack 1, win 670, length 549
20:10:39.923475 IP (tos 0x0, ttl 57, id 3025, offset 0, flags [none], proto TCP (6), length 40)
    173.194.38.98.80 > 106.186.29.14.53598: Flags [F.], cksum 0x91d0 (correct), seq 550, ack 1, win 670, length 0
20:10:39.923492 IP (tos 0x0, ttl 64, id 6596, offset 0, flags [DF], proto TCP (6), length 40)
    106.186.29.14.53598 > 173.194.38.98.80: Flags [.], cksum 0x5c07 (incorrect -> 0x9382), ack 550, win 237, length 0
20:10:39.923690 IP (tos 0x0, ttl 64, id 6597, offset 0, flags [DF], proto TCP (6), length 40)
    106.186.29.14.53598 > 173.194.38.98.80: Flags [R.], cksum 0x5c07 (incorrect -> 0x937d), seq 1, ack 551, win 237, length 

Notez la longueur du premier paquet, 86 octets (une requête HTTP), alors qu'elle est normalement nulle, sans Fast Open.

Il y a en tout sept paquets. Sans Fast Open, la même requête HTTP aurait pris deux paquets de plus :

20:11:13.403762 IP (tos 0x0, ttl 64, id 55763, offset 0, flags [DF], proto TCP (6), length 60)
    106.186.29.14.42067 > 173.194.38.96.80: Flags [S], cksum 0x5c19 (incorrect -> 0x858c), seq 720239607, win 29200, options [mss 1460,sackOK,TS val 114041380 ecr 0,nop,wscale 7], length 0
20:11:13.405827 IP (tos 0x0, ttl 57, id 7042, offset 0, flags [none], proto TCP (6), length 52)
    173.194.38.96.80 > 106.186.29.14.42067: Flags [S.], cksum 0x5792 (correct), seq 687808390, ack 720239608, win 42900, options [mss 1430,nop,nop,sackOK,nop,wscale 6], length 0
20:11:13.405857 IP (tos 0x0, ttl 64, id 55764, offset 0, flags [DF], proto TCP (6), length 40)
    106.186.29.14.42067 > 173.194.38.96.80: Flags [.], cksum 0x5c05 (incorrect -> 0x3ef5), ack 1, win 229, length 0
20:11:13.405915 IP (tos 0x0, ttl 64, id 55765, offset 0, flags [DF], proto TCP (6), length 126)
    106.186.29.14.42067 > 173.194.38.96.80: Flags [P.], cksum 0x5c5b (incorrect -> 0xaa0c), seq 1:87, ack 1, win 229, length 86
20:11:13.407979 IP (tos 0x0, ttl 57, id 7043, offset 0, flags [none], proto TCP (6), length 40)
    173.194.38.96.80 > 106.186.29.14.42067: Flags [.], cksum 0x3ce6 (correct), ack 87, win 670, length 0
20:11:13.408456 IP (tos 0x0, ttl 57, id 7044, offset 0, flags [none], proto TCP (6), length 589)
    173.194.38.96.80 > 106.186.29.14.42067: Flags [P.], cksum 0x9cce (correct), seq 1:550, ack 87, win 670, length 549
20:11:13.408469 IP (tos 0x0, ttl 57, id 7045, offset 0, flags [none], proto TCP (6), length 40)
    173.194.38.96.80 > 106.186.29.14.42067: Flags [F.], cksum 0x3ac0 (correct), seq 550, ack 87, win 670, length 0
20:11:13.408498 IP (tos 0x0, ttl 64, id 55766, offset 0, flags [DF], proto TCP (6), length 40)
    106.186.29.14.42067 > 173.194.38.96.80: Flags [.], cksum 0x5c05 (incorrect -> 0x3c72), ack 550, win 237, length 0
20:11:13.408720 IP (tos 0x0, ttl 64, id 55767, offset 0, flags [DF], proto TCP (6), length 40)
    106.186.29.14.42067 > 173.194.38.96.80: Flags [R.], cksum 0x5c05 (incorrect -> 0x3c6d), seq 87, ack 551, win 237, length ...

Dans cet exemple, le gâteau envoyé par Google était en mémoire. Si ce n'est pas le cas (la machine vient de redémarrer, par exemple), la première requête Fast Open va être une triple poignée de mains classique, les bénéfices de Fast Open ne venant qu'après :

16:53:26.120293 IP (tos 0x0, ttl 64, id 55402, offset 0, flags [DF], proto TCP (6), length 64)
    106.186.29.14.57657 > 74.125.226.86.80: Flags [S], cksum 0x07de (incorrect -> 0xc67b), seq 3854071484, win 29200, options [mss 1460,sackOK,TS val 325168854 ecr 0,nop,wscale 6,exp-tfo cookiereq], length 0
16:53:26.121734 IP (tos 0x0, ttl 57, id 16732, offset 0, flags [none], proto TCP (6), length 72)
    74.125.226.86.80 > 106.186.29.14.57657: Flags [S.], cksum 0xb913 (correct), seq 2213928284, ack 3854071485, win 42540, options [mss 1430,sackOK,TS val 2264123457 ecr 325168854,nop,wscale 7,exp-tfo cookie 234720af40598470], length 0

Ici, le client, n'ayant pas de gâteau pour 74.125.226.86, a dû envoyer une option Fast Open vide (et donc pas de données : la longueur de son paquet SYN est nulle). À la deuxième connexion, on a un gâteau, on s'en sert :

16:54:30.200055 IP (tos 0x0, ttl 64, id 351, offset 0, flags [DF], proto TCP (6), length 161)
    106.186.29.14.57659 > 74.125.226.86.80: Flags [S], cksum 0x083f (incorrect -> 0x651d), seq 1662839861:1662839950, win 29200, options [mss 1460,sackOK,TS val 325184874 ecr 0,nop,wscale 6,exp-tfo cookie 234720af40598470], length 89
16:54:30.201529 IP (tos 0x0, ttl 57, id 52873, offset 0, flags [none], proto TCP (6), length 60)
    74.125.226.86.80 > 106.186.29.14.57659: Flags [S.], cksum 0x67e3 (correct), seq 2010131453, ack 1662839951, win 42540, options [mss 1430,sackOK,TS val 2264192396 ecr 325184874,nop,wscale 7], length 0

La section 4 de notre RFC plonge ensuite dans les détails compliqués de TCP Fast Open. Le gâteau est un MAC généré par le serveur et est donc opaque au client. Ce dernier ne fait que le stocker et le renvoyer. L'option Fast Open est simple : juste le code 34, une longueur (qui peut être nulle, par exemple pour un client qui ne s'est pas encore connecté à ce serveur, et qui demande donc un gâteau), et éventuellement le gâteau. Le serveur, lors de la génération du gâteau, va typiquement devoir suivre ces règles :

  • Lier le gâteau à l'adresse IP source (pour éviter qu'un attaquant ayant espionné le réseau n'utilise le gâteau d'un autre),
  • Utiliser un algorithme de génération imprévisible de l'extérieur (par exemple un générateur aléatoire),
  • Aller vite (le but de Fast Open est de diminuer la latence : pas question de faire des heures de calcul cryptographiques compliqués),
  • Imposer une date d'expiration au gâteau (soit en changer la clé privée utilisée lors de la génération, soit en incluant une estampille temporelle dans les données qui servent à générer le gâteau).

Un exemple d'algorithme valable (mais rappelez-vous que le gâteau est opaque, le serveur peut donc utiliser l'algorithme qu'il veut) est de chiffrer avec AES l'adresse IP et de changer la clé AES de temps en temps (invalidant ainsi automatiquement les vieux gâteaux). AES étant très rapide, cet algorithme a toutes les propriétés listées plus haut. Pour vérifier un gâteau entrant, le serveur a tout simplement à refaire tourner l'algorithme et voir s'il obtient le même résultat.

Et côté client ? Comme indiqué plus haut, le client doit stocker les gâteaux reçus (sans les comprendre : ils sont opaques pour lui) et les renvoyer lors des connexions suivantes vers le même serveur. Puisqu'on mémorise le gâteau de chaque serveur, on peut en profiter pour mémoriser également le MSS, ce qui indiquera la taille des données qu'on pourra envoyer dans le prochain paquet SYN. (Rappelez-vous que le serveur indique normalement sa MSS dans le SYN + ACK, donc trop tard pour Fast Open.) Mais attention : même si le MSS ainsi mémorisé est grand (supérieur à la MTU, par exemple), ce n'est pas forcément une bonne idée d'envoyer autant de données dans le paquet SYN. Des problèmes comme la fragmentation ou comme les middleboxes ne s'attendant pas à des SYN s'étalant sur plusieurs paquets IP, risquent de diminuer les performances, voire d'empêcher TCP de marcher. Ah, et si on ne connait pas le MSS, on doit se limiter à 536 octets en IPv4 et 1240 en IPv6.

Comme toujours sur l'Internet, lorsqu'on déploie une nouvelle technique, il faut aussi tenir compte des trucs bogués. Si le serveur ne répond pas aux SYN comportant l'option Fast Open, cela peut être parce qu'une stupide middlebox a décidé de jeter ces paquets, qui passeraient sans l'option. Même chose au cas où le serveur n'accuse pas réception des données qui étaient dans le SYN : le client Fast Open doit être prêt à réessayer sans cette option, et à mémoriser que le serveur ne doit pas être utilisé avec Fast Open. (Notez, car le RFC ne le fait pas, que ces incompatibilités, étant typiquement causées par une middlebox et pas par le serveur lui-même, peuvent changer dans le temps, si le routage fait soudain passer par un autre chemin.)

Autre point important lorsqu'on met en œuvre Fast Open : le serveur doit garder une trace en mémoire du nombre de connexions qui ont demandé Fast Open mais n'ont pas encore terminé la triple poignée de mains. Et, au delà d'une certaine limite, le serveur doit refuser de nouvelles connexions Fast Open (en ne renvoyant pas d'option Fast Open dans le SYN + ACK), n'acceptant que le TCP traditionnel. Cette précaution permet de résister à certaines attaques par déni de service.

En parlant d'attaques, la section 5 du RFC se concentre sur la sécurité. L'obligation d'envoyer un gâteau authentique arrête certaines attaques triviales (envoyer paquets SYN avec des données qui vont faire travailler le serveur). Mais d'autres attaques restent possibles. Accrochez-vous, nous allons étudier ce qu'un méchant peut faire contre des serveurs TCP Fast Open.

D'abord, il peut tenter d'épuiser les ressources du serveur en utilisant des gâteaux valides. Où les obtient-il ? Cela peut être en utilisant plein de machines (un botnet). Bien sûr, vous allez me dire, on peut faire des tas d'attaques par déni de service avec un botnet mais, avec Fast Open, les zombies peuvent faire plus de dégâts pour moins cher (ils ne sont pas obligés d'écouter les réponses ni même de les attendre). D'où l'importance de la variable « nombre de connexions Fast Open pas complètement ouvertes » citée plus haut.

On ne peut pas normalement voler des gâteaux à une machine et les utiliser ensuite soi-même puisque le gâteau est (si le serveur a bien fait son boulot) lié à l'adresse IP. Mais ce vol reste possible si plusieurs machines partagent une adresse IP publique (cas du CGN par exemple). Une solution possible serait d'inclure dans le calcul du gâteau, non seulement l'adresse IP mais aussi la valeur d'une option TCP Timestamp.

Fast Open peut aussi en théorie être utilisé dans des attaques par réflexion. Par exemple (mais le RFC indique aussi d'autres méthodes), si l'attaquant contrôle une machine dans le réseau de sa victime, il peut obtenir des gâteaux valables et ensuite, lancer depuis un botnet des tas de connexions Fast Open en usurpant l'adresse IP source de sa victime. Les serveurs Fast Open vont alors renvoyer des données (potentiellement plus grosses que les requêtes, donc fournissant une amplification, chose bien utile pour une attaque par déni de service) à la victime. C'est idiot de la part de l'attaquant de s'en prendre à une machine qu'il contrôle déjà ? Non, car sa vraie victime peut être le réseau qui héberge la machine compromise. Les réponses des serveurs Fast Open arriveront peut-être à saturer la liaison utilisée par ce réseau, et cela en contrôlant juste une machine (soit par piratage, soit par location normale d'une machine chez l'hébergeur qu'on veut attaquer). La seule protection envisagée pour l'instant est de décourager les serveurs d'envoyer les réponses au-delà d'une certaine taille, tant que la triple poignée de mains n'a pas été terminée. Mais cela diminue une partie de l'intérêt de TCP Fast Open.

Bon, fini avec ces tristes questions de sécurité, revenons à la question de l'applicabilité de Fast Open. On a bien dit que Fast Open ne convient pas à tous les cas. Si je suis développeur, dans quels cas mon application a-t-elle raison d'utiliser Fast Open ? D'abord, on a vu que Fast Open fait courir le risque d'une duplication du SYN si le paquet est dupliqué et que le second arrive après que le serveur ait détruit le début de connexion. En pratique, la probabilité d'une telle malchance semble faible. Le RFC ne fournit pas de chiffres précis (voir Jaiswal, S., Iannaccone, G., Diot, C., Kurose, J., Towsley, D., « Measurement and classification of out-of-sequence packets in a tier-1 IP backbone » dans IEEE/ACM Transactions on Networking (TON)). Dans le doute, une application qui ne pourrait pas gérer le cas de données dupliquées ne doit donc pas activer Fast Open (rappelez-vous qu'il ne doit pas non plus l'être par défaut). Comme indiqué plus haut, pour HTTP, un GET ne pose pas de problèmes (les navigateurs Web impatients causent déjà souvent des GET dupliqués, qu'on retrouve dans ses journaux) mais un POST non protégé (par exemple par les requêtes conditionnelles du RFC 7232) a davantage de chances de créer des histoires.

Autre cas où il n'y a pas de problèmes à attendre, celui de TLS. Si le client met le TLS_CLIENT_HELLO dès le SYN, cela n'entraine pas de conséquences fâcheuses si le SYN est dupliqué, et cela fait gagner un RTT sur la poignée de mains de TLS.

Ensuite, même s'il n'a pas de conséquences néfastes, TCP Fast Open n'a pas non plus d'avantages si le temps d'établissement de la connexion est négligeable devant la durée totale de la connexion. Une requête HTTP pour un fichier de petite taille peut sans doute profiter de Fast Open, mais pas le transfert d'une énorme vidéo.

On a parlé plus haut des connexions HTTP persistantes (RFC 7230). TCP Fast Open est-il utile lorsqu'on a ces connexions persistantes ? Oui, répond notre RFC. L'étude de Radhakrishnan, S., Cheng, Y., Chu, J., Jain, A. et Raghavan, B. citée plus haut, ainsi que celle d'Al-Fares, M., Elmeleegy, K., Reed, B. et Gashinsky, I., « Overclocking the Yahoo! CDN for Faster Web Page Loads » (dans Proceedings of Internet Measurement Conference , novembre 2011), montrent que le nombre moyen de transactions HTTP par connexion TCP n'est que de 2 à 4, alors même que ces connexions restent ouvertes plusieurs minutes, ce qui dépasse normalement le temps de réflexion d'un être humain. Les mesures effectuées sur Chrome (qui garde les connexions de 5 à 10 minutes) ne voyaient que 3,3 requêtes HTTP par connexion. Faudrait-il allonger cette durée pendant laquelle les connexions persistent ? Cela entrainerait d'autres problèmes, par exemple avec les routeurs NAT qui, en violation du RFC 5382, coupent automatiquement les connexions bien avant la limite de deux heures demandée par le RFC (voir les études de Haetoenen, S., Nyrhinen, A., Eggert, L., Strowes, S., Sarolahti, P. et Kojo., M., « An Experimental Study of Home Gateway Characteristics » dans les Proceedings of Internet Measurement Conference, octobre 2010 ainsi que de Wang, Z., Qian, Z., Xu, Q., Mao, Z. et Zhang, M., « An Untold Story of Middleboxes in Cellular Networks » dans Proceedings of SIGCOMM, août 2011). Envoyer des keepalives TCP résoudrait ce problème mais serait une sérieuse source de consommation électrique pour les machines fonctionnant sur batteries. On voit même le phénomène inverse, les navigateurs Web conçus pour les équipements mobiles qui se mettent à couper les connexions HTTP persistantes plus tôt (Souders, S., « Making A Mobile Connection »).

Ce RFC sur TCP Fast Open a le statut « expérimental ». Qu'est-ce qu'on doit encore étudier et mesurer pour être sûr que Fast Open marche bien ? D'abord, quel est le pourcentage exact de chemins sur l'Internet où les paquets TCP ayant des options inconnues sont jetés ? Pas mal de middleboxes stoppent stupidement tout ce qu'elles ne comprennent pas (Medina, A., Allman, M., and S. Floyd, « Measuring Interactions Between Transport Protocols and Middleboxes » dans Proceedings of Internet Measurement Conference en octobre 2004). Une option nouvelle, comme Fast Open, pourrait donc avoir du mal à percer. Des mesures semblent indiquer que 6 % des chemins Internet seraient dans ce cas (Langley, A, « Probing the viability of TCP extensions » ou bien Honda, M., Nishida, Y., Raiciu, C., Greenhalgh, A., Handley, M. et Tokuda, H., « Is it Still Possible to Extend TCP? » dans Proceedings of Internet Measurement Conference en novembre 2011). TCP Fast Open réagit à ce problème en réessayant sans l'option (comme le font les résolveurs DNS quand ils n'obtiennent pas de réponse lorsque les requêtes sont envoyées avec EDNS).

Autre sujet de recherche intéressant, les liens avec la congestion. Normalement, Fast Open ne modifie pas les algorithmes qui tentent d'éviter la congestion mais il peut y avoir des cas subtils où Fast Open ne peut pas suivre ces algorithmes (données déjà envoyées avant que les pertes ne soient détectées).

TCP Fast Open impose actuellement l'usage d'un gâteau pour détecter les méchants qui tricheraient sur leur adresse IP source. Mais pour certains serveurs qui n'assurent que des tâches simples et idempotentes (le RFC prend l'exemple d'un serveur HTTP qui ne ferait que des redirections), la protection fournie par le gâteau est peut-être inutile et on pourrait faire des économies en s'en passant (l'expérience du DNS, qui est aussi requête/réponse, me rend personnellement sceptique sur ce point). Ou bien le serveur pourrait s'en passer par défaut, et basculer en Fast Open avec gâteau s'il détecte une attaque par déni de service en cours ? Bref, il y a encore des sujets ouverts.

La section 8 rappelle les travaux qui avaient précédé Fast Open. Il y a bien sûr T/TCP, déjà cité, qui avait trébuché sur les problèmes de sécurité. Une autre solution pour TCP est le TCPCT du RFC 6013 (désormais abandonné, cf. RFC 7805). Mais il y a aussi les solutions dans les applications comme « preconnect ».

Sinon, si vous voulez de la lecture sur Fast Open, il y a une bonne explication dans Linux Weekly News, avec des détails sur son utilisation dans les programmes.

À propos de programmes, et les mises en œuvre ? TCP Fast Open existe dans le navigateur Chrome, ainsi que dans le noyau Linux, depuis la version 3.7 (3.16 seulement pour IPv6). Une Debian en version « jessie » permet donc de tester. Une API possible figure en annexe A du RFC. Du côté serveur, il faut, après avoir créé une socket : setsockopt(sfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)); C'est plus compliqué sur le client (il faudrait envoyer des données dans le connect() ou bien utiliser sendto() ou encore une option de la socket). Le programme client-http-tcp-fastopen.c montre un simple client HTTP utilisant Fast Open. C'est avec lui qu'ont été obtenues les traces montrées plus haut (le pcap complet est sur pcapr ; il utilise une valeur expérimentale pour l'option et pas la valeur standard de 34).

Une lecture pour finir : la présentation « Network Support for TCP Fast Open (NANOG 67) ».

Merci à Alexis La Goutte pour ses remarques.


Téléchargez le RFC 7413


L'article seul

RFC 7410: A Property Types Registry for the Authentication-Results Header Field

Date de publication du RFC : Novembre 2014
Auteur(s) du RFC : M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 5 décembre 2014


Le RFC 7001 avait créé l'en-tête de courrier Authentication-Results: qui permettait de signaler à un logiciel de courrier les résultats de tests d'authenticité faits par un serveur. Cet en-tête pouvait inclure un type de propriété (property type ou ptype) qui indiquait d'où venait la propriété testée : la session SMTP, l'en-tête du message, son corps, ou bien une politique locale. Le jeu de valeurs pour les types possibles était fixe et, depuis, certains ont trouvé ce jeu trop restreint. Ce nouveau et très court RFC remplace donc la liste fixe du RFC 7001 par un registre en ligne à l'IANA. (Depuis, le RFC 7601, a remplacé ces deux RFC.)

Le principe de base du RFC 7001 est de séparer l'exécution des tests d'authenticité de l'utilisation de leurs résultats. Par exemple, les tests sont effectués sur un serveur de messagerie de l'organisation, et leur utilisation est décidée sur le poste de travail de l'utilisateur. Voici un exemple de résultat transmis au logiciel, utilisant les types de propriétés :

Authentication-Results: example.com;
                  spf=pass smtp.mailfrom=example.net
                           ^^^^^^^^^^^^^
                           Type et propriété

Ici, le test SPF a été fait lors de la session SMTP (le type est smtp et il est suivi d'un point et de la commande SMTP - la propriété - testée). Autre exemple :

Authentication-Results: example.com;
              dkim=fail reason="bad signature"
                header.i=@newyork.example.com
                ^^^^^^^^
                Type et propriété

Ici, le test était du DKIM, le type était l'en-tête du message (header) et la propriété le champ i de la signature DKIM (notez que le RFC 7001 dit que la propriété après header doit être un en-tête du message, ce qui n'est pas le cas ici, mais c'est un exemple officiel, je n'y peux rien, voir la bogue du RFC 7001).

Dans ces deux exemples, on a vu les types de propriétés smtp et header. Deux autres sont définis par le RFC 7001, section 2.2, body et policy. Cette liste était fixe et c'est ce point que change notre nouveau RFC.

Désormais, le type de propriété peut être n'importe quel mot-clé enregistré à l'IANA. Ce registre démarre avec les quatre types du RFC 7001. L'enregistrement d'une nouvelle valeur se fait selon la procédure « Examen par un expert » du RFC 5226.

Il est recommandé d'ignorer les types de propriété inconnus (ceux qui viennent d'être enregistrés et ne sont pas encore connus du logiciel). Autrement, déployer un nouveau type serait quasi-impossible.

Comme indiqué plus haut, ce RFC a été fusionné avec le RFC 7001 pour donner le texte qu'il faut consulter aujourd'hui, le RFC 7601.


Téléchargez le RFC 7410


L'article seul

RFC 7405: Case-Sensitive String Support in ABNF

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : P. Kyzivat
Chemin des normes
Première rédaction de cet article le 24 décembre 2014


La plupart des RFC contenant une grammaire formelle pour un format ou un protocole, utilisent le langage ABNF, normalisé dans le RFC 5234. Une des particularités d'ABNF, qui agace beaucoup de monde depuis le début, est le fait que les chaînes de caractères sont forcément insensibles à la casse. Si on veut les rendre sensibles à la casse, ce qui est une demande assez fréquente, il faut utiliser des trucs plus ou moins propres. D'où ce nouveau RFC qui fait sauter l'obstacle en permettant enfin d'indiquer qu'une chaîne de caractères est sensible à la casse.

Voici un exemple tiré du RFC 7208, qui décrit SPF :

mx  = "mx"     [ ":" domain-spec ] [ dual-cidr-length ]

Du fait de l'insensibilité à la casse, un enregistrement SPF peut inclure mx:example.net/26 mais aussi mX:example.net/26, MX:example.net/26 ou Mx:example.net/26. Ce comportement est souvent raisonnable mais, dans certains cas, il ne convient pas et on ne peut plus alors utiliser des chaînes de caractères, il faut (RFC 5234, section 2.3), indiquer explicitement les valeurs numériques de chaque caractère. Par exemple, dans le RFC 4997, les identificateurs sont forcément en majuscule et le littéral THIS doit donc être défini par :

   THIS         = %d84.72.73.83

Si on l'avait défini :

   THIS         = "THIS"

alors, il aurait pu être écrit en minuscules ou en mixte.

Donc, désormais, la règle est que les chaînes de caractères en ABNF peuvent être précédées de %i pour indiquer qu'elles sont insensibles à la casse ou %s pour dire qu'elles ne le sont pas. Comme %i est la valeur par défaut (pour préserver la compatibilité), elle sera souvent omise. La définition du RFC 4997 plus haut aurait donc pu être :

   THIS         = %s"THIS"

À ma connaissance, les différents outils ABNF en http://tools.ietf.org/ n'ont pas encore fait l'objet d'un examen systématique pour déterminer s'ils intégraient la nouvelle norme.


Téléchargez le RFC 7405


L'article seul

RFC 7404: Using Only Link-Local Addressing Inside an IPv6 Network

Date de publication du RFC : Novembre 2014
Auteur(s) du RFC : M. Behringer, E. Vyncke (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 19 novembre 2014


L'utilisation du protocole IPv6 fait que chaque machine a une adresse dite « locale au lien » (link-local) qui n'est pas unique mondialement mais seulement unique sur le lien. Est-ce qu'on peut se contenter de ces adresses, et, par exemple, configurer ses routeurs pour les utiliser ? Ce RFC discute les avantages et les inconvénients. (Attention, le sujet est brûlant à l'IETF.)

Imaginons deux routeurs connectés et qui échangent des routes, via un protocole de routage. On les a configurés avec l'adresse du voisin. Cette adresse peut être une adresse « normale », mondialement unique. Mais elle peut aussi être locale au lien et cela présente quelques avantages. Par exemple, les adresses des routeurs ne sont pas présentes dans la table de routage (car elles n'ont de signification que locale), rendant ces tables plus petites. Et le routeur est plus dur à attaquer, puisqu'il faut être sur le lien pour lui parler. Par contre, cela peut rendre des outils de tests habituels comme ping ou traceroute difficiles ou impossibles à utiliser.

L'un dans l'autre, l'IETF ne tranche pas : cette possibilité marche, elle est documentée dans ce RFC mais chacun doit ensuite décider s'il va l'utiliser ou pas. Comme le dit le RFC avec un sens aigu du lavage de mains « The deployment of this technique is appropriate where it is found to be necessary ».

La section 2 forme le gros de ce RFC : exposer l'approche, ses avantages, et ses risques. Les adresses locales au lien sont désignées par le sigle LLA (link-local addresses). Voici un exemple sur une machine Linux (les LLA sont dans le préfixe fe80::/10) :


% ip -6 addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 fe80::ba27:ebff:feba:9094/64 scope link 
       valid_lft forever preferred_lft forever

Le principe de base de leur utilisation est que, lorsqu'une machine n'a pas besoin de parler au monde extérieur sur cette adresse (ce qui est typiquement le cas d'un routeur), on peut ne mettre qu'une LLA sur une interface.

Attention, ce n'est vrai que pour une interface. Pas question de n'avoir que des LLA sur l'ensemble du routeur car celui-ci doit pouvoir émettre des paquets ICMP du genre Message too big ou bien Time exceeded. Il faut donc qu'au moins une interface du routeur ait une adresse globale, qui sera utilisée comme adresse source lors de l'émission de ces paquets ICMP (cf. RFC 6724). Cette adresse devra être routée, pour éviter tout filtrage en raison du RFC 3704. Dans le monde des routeurs, on appelle cela en général une loopback interface mais attention, c'est un sens différent de celui du mot loopback sur les machines Unix ordinaires. (Au fait, si quelqu'un sait comment modifier l’interface source des erreurs ICMP sur IOS... Ça existe en NX-OS, mais c'est introuvable en IOS et IOS-XE.)

Les protocoles de routage (OSPF, BGP, RIPng) fonctionnent déjà avec des LLA naturellement, ou peuvent être configurés pour le faire (pour BGP, Francis Dupont me souffle qu'il faut faire attention au RFC 2545, qui n'est pas cité). La découverte des voisins par NDP se fait toujours avec des LLA donc n'est pas affectée. Pour les protocoles de gestion du routeur, comme SSH ou SNMP (le RFC s'amuse aussi à citer Telnet...) devront, eux, utiliser l'adresse globale mentionnée plus haut.

Ah, et, évidemment, le gros du trafic du routeur, ce ne sont pas les protocoles de routage ou de gestion du routeur, c'est le trafic des autres, qu'il transmet. Ce dernier a des adresses source et destination qui ne sont pas celles du routeur et, donc, l'utilisation par ce dernier de LLA ou pas ne change rien. Bref, ça devrait marcher. Mais quels sont les avantages à une configuration uniquement avec des LLA ?

D'abord, comme indiqué plus haut, les tables de routage sont plus petites, puisqu'on n'y met pas les LLA, seulement les adresses globales, moins nombreuses (une seule par routeur, dans le cas le plus économe). Ensuite, on simplifie le plan d'adressage : pas besoin d'attribuer des préfixes aux liens entre routeurs. On a également moins de complexité dans la configuration, les LLA étant attribuées automatiquement. Et on a moins de configuration DNS à maintenir, puisqu'on ne met pas les LLA dans le DNS (évidemment, on n'est pas forcé d'y mettre les adresses globales non plus).

Surtout, on réduit les possibilités d'attaque puisque l'envoi de paquets au routeur, depuis l'extérieur du lien, ne pourra se faire que via l'adresse globale (par exemple pour les attaques du RFC 4987). Il n'y aura donc que celle-ci à protéger (par exemple via des ACL).

Le monde où nous vivons n'étant pas un monde idéal, depuis l'expulsion hors du jardin d'Éden, il y a aussi des problèmes associés aux LLA. On peut encore pinguer une interface spécifique depuis le lien (ping $lla%$if-name) mais plus depuis un autre réseau. Le débogage peut donc devenir plus difficile. (Notez que, contrairement à ce qu'on lit souvent dans les articles sur TCP/IP, lorsqu'on pingue une adresse IP associée à une interface, une réponse positive ne garantit pas du tout qu'on est passé par cette interface.) Bien sûr, on peut toujours pinguer l'adresse globale du routeur depuis n'importe où, mais cela fournit moins d'informations. Pour déterminer si une interface marche ou pas, il faudra donc utiliser d'autres méthodes par exemple en se loguant sur le routeur et en examinant l'état des interfaces. (Notez que, là encore, en dépit des légendes, avec certains systèmes d'exploitation, on peut pinguer avec succès une adresse IP associée à cette interface même lorsque cette interface est débranchée.) Le RFC 5837, lorsqu'il est mis en œuvre, peut aider au débogage, en mettant de l'information sur l'interface dans la réponse ICMP.

Même problème, évidemment, avec traceroute. Non seulement on ne peut pas tracerouter vers une interface spécifique, mais le paquet ICMP de réponse viendra de l'adresse IP globale et ne nous renseignera donc pas sur l'interface précise qui l'a émis (sauf si le routeur utilise le RFC 5837 et si le traceroute utilisé exploite cette option). Notez que cela peut être vu comme un avantage : tous les traceroutes passant par ce routeur verront la même adresse de réponse, aidant à repérer le routeur (alors que, autrement, il aurait fallu corréler les différentes adresses, par exemple via les enregistrements PTR associés, ce qui dépend d'heuristiques peu fiables).

Et, bien sûr, cela concerne aussi les systèmes de gestion de réseau : si un gérant SNMP, par exemple, veut parler à un routeur, il devra probablement utiliser son adresse globale.

Autre problème, les adresses LLA automatiquement attribuées vont dépendre du matériel, puisqu'elles seront en général dérivées de l'adresse MAC (via EUI-64). Si on change une carte Ethernet du routeur, on change de LLA, ce qui peut nécessiter une reconfiguration manuelle si ces LLA étaient utilisées statiquement, par exemple dans une configuration BGP. (Matthieu Herrb me fait remarquer qu'on peut parfaitement créer des LLA statiques, genre fe80::31, ce que mentionne d'ailleurs le RFC.) Pendant qu'on est aux configurations statiques, il faut aussi rappeler que les LLA sont moins pratiques à manier puisqu'elles n'ont pas de signification globale. Il faut donc toujours indiquer le lien utilisé. Par exemple, une configuration BGP sera bgp neighbor fe80::21e:8cff:fe76:29b6%eth2 (le %eth2 indiquant l'interface réseau, cf. RFC 4007).

Un cas particulier est celui des points d'échange. Ils connectent beaucoup de monde et représentent une part significative du trafic Internet. Une attaque ou une panne peut sérieusement perturber le trafic. Le préfixe d'adresses IP qui est utilisé pour numéroter les routeurs sur le LAN du point d'échange est donc sensible. Pour réduire les risques, on peut soit ne pas le publier dans la table de routage globale, soit filtrer le trafic entrant vers ce préfixe. Dans le premier cas, les paquets émis depuis l'interface du routeur avec le point d'échange, ayant une adresse source non routée, seront jetés par les réseaux qui font des tests uRPF. Cela perturbe traceroute, mais, surtout la découverte de la MTU du chemin, ce qui est inacceptable. La deuxième méthode ne marche que si tous les opérateurs connectés au point d'échange la mettent en œuvre, ce qui est peu vraisemblable.

Une meilleure solution serait donc de numéroter les routeurs au point d'échange avec des LLA. Chaque routeur aurait toujours son adresse globale, prise dans l'espace d'adressage de l'opérateur propriétaire, mais une attaque globale contre tout le point d'échange serait plus difficile. Par contre, cela pourrait poser des problèmes avec certaines méthodes d'ingénierie du trafic, si l'opérateur veut transporter le préfixe du point d'échange dans son IGP. Ces opérateurs devront trouver une autre méthode.

En synthèse, la conclusion de notre RFC est que l'utilisation des LLA a des avantages et des inconvénients, et que chaque acteur doit faire son évaluation, le RFC ne recommandant spécialement aucune des deux méthodes. Cette conclusion a été chaudement discutée à l'IETF, ceux qui pensaient que les LLA étaient une mauvaise idée n'ayant pas envie que cette utilisation soit documentée, craignant que cela n'apparaisse comme une approbation.


Téléchargez le RFC 7404


L'article seul

RFC 7403: A Media-based Traceroute Function for the Session Initiation Protocol (SIP)

Date de publication du RFC : Novembre 2014
Auteur(s) du RFC : H. Kaplan (Oracle)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF straw
Première rédaction de cet article le 11 novembre 2014


Le protocole de téléphonie sur IP SIP est séparé en deux parties, la signalisation (appeler, raccrocher, etc) qui se fait avec SIP lui-même, et les données qui sont envoyées par un autre mécanisme, mais contrôlé par SIP. Pour la signalisation, SIP avait déjà une fonction de genre traceroute, permettant de visualiser le chemin suivi par les messages SIP. Mais il n'y avait pas l'équivalent pour les données, ce qui est fait désormais.

SIP est normalisé dans le RFC 3261, dont la section 20.22 décrit l'utilisation de l'en-tête Max-Forwards: pour tracer la route entre l'appelant et l'appelé. C'est que les appels SIP ne voyagent que très rarement directement d'un appelant (par exemple un softphone) vers un appelé (entre autres parce que l'appelé n'est pas forcément joignable directement, coincé qu'il est derrière le NAT). Il est courant que l'appel passe par au moins deux intermédiaires (le relais du fournisseur SIP de l'appelant et celui de l'appelé), d'où l'importance de pouvoir faire des « traceroute ». Un traceroute SIP fonctionne donc en envoyant des requêtes avec un Max-Forwards: à 0, puis à 1, et ainsi de suite (comme le traceroute IP utilise le champ TTL), en recevant les messages de code 483 (Too many hops), on identifie les intermédiaires.

Même problème pour les données, elles ne vont pas forcément directement d'un client SIP à un autre, elles peuvent passer par des intermédiaires qui ajoutent des fonctions comme la musique d'attente (RFC 7088), la traversée des NAT, le réencodage du flux audio dans un autre format, etc. Bref, pour les données aussi, on a besoin d'un équivalent de traceroute, afin de pouvoir déboguer tout problème qui surgirait.

Justement, le RFC 6849 fournit un mécanisme, dit media loopback, sur lequel bâtir ce traceroute. Le service de « bouclage » du RFC 6849 permet de renvoyer le flux de données vers l'émetteur, afin que celui-ci puisse contrôler en quel état est ce flux à une étape donnée. Mettons que notre sympathique Alice veuille appeler Bob. Bob n'entend rien à ce que raconte Alice. Il va falloir déboguer. Alice va donc devoir demander à chaque intermédiaire (les B2BUA, back-to-back user agent) de lui envoyer une copie du flux de données, suivant le RFC 6849. Mais Alice ne les connait pas, ces intermédiaires, et n'a pas de moyen de leur parler directement. D'où notre nouveau RFC.

Le principe est d'envoyer une requête SIP INVITE vers Bob, avec des Max-Forwards: partant de zéro et croissant, et d'y joindre un SDP qui demande le bouclage des données (suivant la syntaxe du RFC 6849). Un intermédiaire SIP classique va rejeter l'appel avec le code 483 mais, s'il suit ce nouveau RFC (et le RFC 7332, qui le complète), il va accepter l'appel et renvoyer les données à Alice. Sa réponse sera une réponse positive au INVITE, donc avec le code 200, et, pour indiquer que ce n'est pas la « vraie » réponse de Bob, il indiquera une raison (RFC 3326) Traceroute response.

Attention à la sécurité, ce mécanisme peut finir par envoyer pas mal de données à Alice et imposer du travail aux intermédiaires. Ceux-ci doivent donc avoir un mécanisme pour activer/désactiver ce service, ainsi qu'une limitation automatique du nombre de réponses envoyées (comme les routeurs IP ont une telle limitation pour le traceroute classique).


Téléchargez le RFC 7403


L'article seul

RFC 7401: Host Identity Protocol Version 2 (HIPv2)

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : R. Moskowitz (Verizon), T. Heer (Hirschmann Automation and Control), P. Jokela (Ericsson Research NomadicLab), T. Henderson (University of Washington)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF hip
Première rédaction de cet article le 10 avril 2015


HIP, décrit dans ce RFC, est un protocole très ambitieux, puisqu'il vise à compléter IP en fournissant une séparation de l'identificateur et du localisateur, permettant d'améliorer la sécurité (notamment la résistance aux DoS) et de mieux gérer la mobilité et le multi-homing. Ce RFC décrit la version 2 de HIP, désormais norme officielle (au lieu de protocole expérimental, ce qu'était HIP v1).

L'architecture générale de HIP est décrite dans le RFC 9063 (vous pouvez lire mon article de résumé de HIP). Notre RFC normalise, lui, le protocole concret. HIP repose d'abord sur la séparation entre un nouvel identificateur, le HI (Host Identity) et un localisateur, plus concret, qui sera simplement l'adresse IP, réduite à un rôle moins visible, sans exigence de stabilité. Par exemple, HIP permettra le changement de localisateur (d'adresse IP) en cours de connexion, sans rompre celle-ci, ce qui sera précieux pour la mobilité.

HIP est donc déployable uniquement en modifiant les machines terminales du réseau (si les coupe-feux le laissent passer), sans toucher aux routeurs. Il en existe des mises en œuvres pour FreeBSD et Linux. Le projet OpenHIP adapte également des logiciels comme Wireshark pour qu'ils aient un support HIP. InfraHIP travaille également à l'infrastructure HIP.

Si on ne veut pas lire le RFC 9063, on peut néanmoins avoir une bonne introduction à HIP en lisant les sections 1 et 2 de notre RFC (ou, si on est très pressé, mon article). Elles expliquent le vocabulaire (par exemple, HIP, étant un protocole situé en haut de la couche 3 n'utilise pas le terme de connexion mais celui d'association), le nouvel espace de nommage et les principes du protocole.

L'espace de nommage fait l'objet de la section 3. On distingue les HI (Host Identity), qui sont des clés publiques d'un couple clé privée / clé publique et qui sont de taille variable, et les HIT (Host Identity Tag, décrits dans la section 3.1), qui sont un résumé cryptographique des HI. Ils sont de taille fixe (donc plus faciles à traiter), 128 bits, la taille d'une adresse IPv6. Un préfixe ORCHID (RFC 7343), le 2001:20::/28, sert à éviter toute collision avec les « vraies » adresses IPv6. Avec OpenHIP, la clé peut être générée par le programme hitgen qui fabrique un fichier XML ressemblant à ceci :


<?xml version="1.0" encoding="UTF-8"?>
<my_host_identities>
  <host_identity alg="RSA" alg_id="5" length="128" anon="no" incoming="yes" r1count="10">
    <name>horcrux-1024</name>
    <N>C6EBA2894C33A1312B38853A8ECC0D7967496237A65529807EDF23C4DA753EE88F8FBF71BE38B6910181D5B75DB075B9962326D9BB50C65121DBFD712F1B7F4E2B035953AD650EB5C96B56295FE2731B3B36E8AFED7FB5CD48B73C31A224D4CE4F097D84888EC2E3CA8F3A78939D89B7BCFC5E6DEEAF670695349BFFFE8445F1</N>
    <E>010001</E>
    <D>383A51165838DBDE872611DACC94775692D09677BE87A214954843D7181D3E2C04B0905FF9721481069909AD2C497DED78B7F4FA64CD5F517DADAE8538D89FF21B0498A72F1132545328ABD371B1BAC8ED46441D900921523B78BA55F3FC227F432F2061C92CE9665CB99C1CF425AA90CFC6345FA4E7DA43E477EAF69F86A801</D>
    <P>FF03F93454C9C2D8EC47FE8C9DBF0D82F05E13905F304A5ACA42C45E579F917B4C8CEFEF6B06AAB9BCB7A911D5514B7AEE685DA91E7CC60DDC4C37BA94A22E71</P>
    <Q>C7B0394EB5506B2B75E19E5654262E843659BB76A465C2A7AC47A430749944378E3161FF805B4C6CB037B5CB111F0EF49FF03047FB1CFC51DC0D72DEDAD64F81</Q>
    <dmp1>7426C128DEBD8EEBF2A2D004080D6F0006AF32C5FD352788B6BB3669AA0B59DE08FDE082F202755C67E25735722DB6ED650D502BA961376C34BCDA5D3739AF61</dmp1>
    <dmq1>1B97DE5361FA9AD4869586ABA7351F78658A40BD443A4B8B9FE2C66D6BAF421DEB2827C2869A17156DC444FAAA83002E0D6BC3402F12F24ADD7D7E420D3B5001</dmq1>
    <iqmp>7499A27F59CA1746F1A6E5DE832592F8ACF80B814DD511C490614C44DC92B5CD1650AC944ED5751F28846487C221E8C17E68264DFEF748B86E38EB1F238D94A9</iqmp>
    <HIT>2001:1f:cd4:7125:2427:f77c:d1b6:e15f</HIT>
    <LSI>1.182.225.95</LSI>
  </host_identity>
</my_host_identities>

Notez bien que le fait d'utiliser XML est un choix de OpenHIP, qui n'est utilisé qu'en local. Il n'est pas imposé par la norme qui, sur le câble, n'utilise que du binaire. Les éléments comme P, Q ou iqmp sont les éléments d'une clé RSA (HIP peut utiliser d'autres algorithmes que RSA, comme ECDSA). Le HIT est représenté en utilisant la syntaxe des adresses IPv6, puisqu'il a la même taille et a été conçu pour être stocké comme une adresse par les applications.

La section 3.2 explique comment générer un HIT à partir du HI. Étant un résumé cryptographique (fait avec SHA-256 ou un équivalent), il est sûr, on ne peut pas fabriquer facilement un HI qui aurait le même HIT (cf. annexe E).

Pour signer les paquets, les deux machines utiliseront au début un échange de Diffie-Hellman.

La section 4 donne une vision générale du protocole, qui sera ensuite détaillée dans les sections ultérieures. HIP a reçu le numéro de protocole 139 (il n'a pas changé avec la version 2 de HIP).

La section 4.1 décrit comment former une association entre deux machines HIP. Celle qui demande l'association est nommée l'initiateur, celle qui l'accepte le répondeur. Le protocole d'association nécessite quatre paquets. En effet, avec seulement trois paquets, comme le fait TCP (RFC 793) lors de l'établissement d'une connexion (three-way handshake), on ne peut pas à la fois se protéger contre les DoS et permettre des options par connexion. Se protéger contre les DoS nécessite de ne pas garder d'état tant que le pair n'est pas authentifié, même faiblement. Les techniques qui permettent à TCP de ne pas garder d'état sur le « répondeur », telles que les SYN cookies du RFC 4987 sont incompatibles avec les options TCP.

Voici pourquoi les protocoles plus récents comme SCTP (RFC 3286) ou comme HIP nécessitent quatre paquets.

Dans HIP, ils sont nommés I1, R1, I2 et R2. Les paquets I sont envoyés par l'initiateur et les paquets R par le répondeur.

L'établissement d'une association se passe donc comme ceci :

  • L'initiateur envoie I1 au répondeur. Le paquet contient l'identificateur (le HIT) de l'initiateur et (optionnellement) celui du répondeur. Il contient également les paramètres de la session Diffie-Hellman (attention, c'est un changement par rapport à HIP v1). Aucun état n'est créé chez le répondeur.
  • Le répondeur envoie R1. Ce paquet contient un « puzzle » cryptographique que l'initiateur devra résoudre. Et ce paquet est signé. (Si l'initiateur ne connaissait pas le HI du répondeur, ce qu'on nomme le « mode opportuniste », il ne peut évidemment pas vérifier cette signature, et le mode opportuniste est donc vulnérable aux attaques de l'homme du milieu lors de l'établissement de la connexion, mais pas après. Même ce mode fournit donc au moins autant de sécurité que l'IP actuel.)
  • L'initiateur envoie I2, qui contient la solution du puzzle et les paramètres Diffie-Hellman pour le répondeur. Ce paquet est signé. Tant que cet I2 n'a pas été reçu, le répondeur ne garde aucun état chez lui, ce qui le protège de la plupart des attaques par déni de service.
  • Le répondeur envoie R2 pour accepter l'association. Ce paquet est signé.

Le puzzle, détaillé en section 4.1.1, est un petit problème de calcul que l'initiateur doit résoudre pour montrer qu'il est prêt à « payer », à faire un effort pour que l'association soit acceptée. La difficulté du puzzle peut être réglée par le répondeur, par exemple en étant plus difficile lorsqu'une attaque dDoS est en cours. D'une manière analogue au « minage » Bitcoin, le puzzle consiste simplement à trouver un nombre J tel que, concaténé avec le nombre I envoyé par le répondeur (et imprévisible, pour empêcher les pré-calculs par un attaquant), et avec les HIT des deux pairs, le condensat comprenne un certain nombre K de zéros initiaux (voir l'annexe A pour les détails). Ce K est donc la difficulté du puzzle. À noter qu'il n'y a pas d'estampille temporelle dans les paramètres de la demande de connexion, et que les attaques par rejeu sont donc possibles (mais cela dispense d'une synchronisation d'horloges globale, cf. section 4.1.4).

En pratique, il est très difficile d'imaginer un puzzle qui soit dissuasif contre des attaquants disposant d'un botnet entier, tout en étant soluble par des appareils simples, genre téléphone portable, ne possédant guère de puissance de calcul. (La section 4.1.1 détaille ce problème et les solutions possibles.)

La section 4.1.3 détaille l'utilisation du Diffie-Hellman.

Une des nouveautés de HIP v2 est l'agilité cryptographique, c'est-à-dire le fait que les algorithmes cryptographiques utilisés sont des paramètres du protocole, pas des décisions définitives. On peut donc ainsi changer d'algorithme suivant les progrès de la cryptanalyse. Mais l'agilité a aussi des inconvénients comme le risque d'attaques par repli où, lors de la négociation entre les deux pairs, un homme du milieu réussit à faire croire à Alice que Bob ne gère pas tel algorithme, forçant ainsi Alice à se replier sur un algorithme plus faible. Une nouveauté de ce RFC 7401 est donc la section 4.1.7 sur les protections contre le repli. Contrairement à d'autres protocoles cryptographiques, HIP signe presque tous les paquets relatifs à la négociation d'algorithmes. Ils ne peuvent donc pas être modifiés. Une attaque par rejeu reste possible : Bob met à jour son logiciel, accepte désormais de meilleurs algorithmes mais Mallory a enregistré ses anciens paquets et les envoie à Alice, qui croira alors (même après la vérification de la signature) que Bob continue à ne gérer que de vieux algorithmes. HIP dispose donc d'autres protections comme le fait que les paramètres Diffie-Hellman sont aussi dans ces paquets de négociation et qu'un vieux paquet mènera donc à un échec de la négociation Diffie-Hellman.

Une des grandes forces de HIP est la possibilité de mettre à jour une association existante (section 4.2). À tout moment, pendant la session, un paquet de type UPDATE peut être envoyé pour changer certains paramètres de la session, comme les localisateurs (les adresses IP) utilisées. La signature des paquets permet de s'assurer que le paquet UPDATE est authentique.

Une fois l'association établie, les machines peuvent échanger des données. Si elles utilisent des protocoles comme ESP (RFC 7402), ces données sont protégées contre l'écoute et la modification (HIP lui-même ne chiffre pas).

La section 5 est longue car elle détaille le format, bit par bit, de tous les paquets échangés. Il y a huit types de paquets (section 5.3) comme I1, R1, I2, R2 ou comme UPDATE, présenté plus haut. Dans l'en-tête fixe, commun à tous les paquets, se trouve une liste de paramètres HIP, encodés en TLV, qui permettent de transporter des informations comme les caractéristiques du puzzle (dans les paquets R1), la liste des algorithmes cryptographiques, etc). La liste de tous les paramètres se trouve dans un registre IANA.

Enfin, la section 6 détaille le traitement des paquets, ce qu'il faut faire en les recevant, les erreurs et la façon de les gérer (règle simple : ne pas renvoyer de paquets HIP en cas d'anomalie, seulement des ICMP, et avec un débit limité, car on ne peut pas être sûr du pair s'il y a une erreur), etc.

Notez aussi la section 7 de notre RFC, qui est consacrée à la politique de gestion des identificateurs. Elle recommande fortement que toute mise en œuvre de HIP permette de gérer au moins deux HI différents par machine. Un sera publié et servira à être contacté et au moins un autre sera « anonyme » (terme inexact mais c'est celui du RFC), non publié, utilisé uniquement pour initier des connexions et sera donc plus difficilement traçable. Un inconvénient de l'authentification forte des machines est en effet que cela risque de faire perdre de la vie privée. D'où cette idée d'identificateurs non reliables à une autre identité (si on est très prudent, on utilise un HI différent pour chaque répondeur auquel on se connecte).

La section 8 de notre RFC se penche sur les problèmes de sécurité, une plaie récurrente sur l'Internet d'aujourd'hui, et qui frappera certainement également HIP, s'il est massivement déployé. D'abord, les attaques par déni de service. Celles-ci prennent en général leur source dans une asymétrie, par exemple dans le fait que les coûts soient plus élevés pour l'une des parties. Voici pourquoi il faut quatre paquets pour établir une association : le premier envoyé par le répondeur, R1, peut être un paquet général, envoyé pour toutes les demandes d'association. Le répondeur ne stocke aucun état tant que l'initiateur n'a pas pu prouver son identité.

Comme le R1 est bien plus gros que le I1, HIP pourrait être utilisé pour une attaque par amplification (une attaque où la réponse est plus grosse que la question), en usurpant l'adresse IP source de sa victime. Comme avec le DNS et son RRL, un bon répondeur devrait limiter le rythme d'envoi des R1 par adresse IP.

Enfin, le plus dur, quand on compte sur la cryptographie pour se protéger, c'est de combattre les Hommes du Milieu. Rien ne sert de chiffrer avec les meilleurs algorithmes de cryptographie si, en croyant parler à son correspondant, on parle en fait à un homme du milieu qui s'est fait passer pour le correspondant. HIP a donc ce problème. Certes, les paquets sont signés mais comment être sûr que le HI du correspondant, qui sert à vérifier ces signatures, est le bon ? La seule solution fiable est de valider le HI du correspondant via un tiers. Par exemple, on a trouvé ce HI dans le DNS, dans une zone sécurisée par DNSSEC. Ou bien le HI était dans un certificat X.509 qu'on a validé.

On l'a vu, ce RFC 7401 normalise la version 2 de HIP. Quels sont les principaux changements par rapport à la version 1, normalisée dans le RFC 5201 ? La section 11 répond à cette question. D'abord, on utilise pour représenter les HIT la version 2 d'ORCHID, normalisée dans le RFC 7343 et non plus la v1 du RFC 4843, qui ne permettait l'agilité cryptographique. Résultat, les HIT commenceront désormais par 2001:20... et non plus 2001:10.... Ensuite, les HI peuvent désormais utiliser les courbes elliptiques, via ECDSA. Le protocole d'établissement de l'association a sérieusement changé, avec les paramètres Diffie-Hellman mis plus tôt. Et il y a également d'innombrables changements moins importants, mais qui font que le protocole est différent et incompatible avec la v1. La base installée de HIP étant très faible pour l'instant, cela n'est pas trop gênant. Ces modifications viennent de l'expérience avec HIP v1, obtenue par de nombreux essais avec les différentes mises en œuvre du protocole. Cette expérience a permis de faire passer HIP du statut « Expérimental », celui du RFC 5201, à celui de « Chemin des normes ».

Il existe plusieurs mises en œuvre de HIP v1 (cf. RFC 6538) et HIP for Linux ainsi que OpenHIP ont annoncé leur intention de les adapter à HIP v2.


Téléchargez le RFC 7401


L'article seul

RFC 7398: A Reference Path and Measurement Points for Large-Scale Measurement of Broadband Performance

Date de publication du RFC : Février 2015
Auteur(s) du RFC : M. Bagnulo (UC3M), T. Burbridge (BT), S. Crawford (SamKnows), P. Eardley (BT), A. Morton (AT&T Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 19 février 2015


Ce nouveau RFC est situé à l'intersection du groupe de travail IETF ippm et du plus récent groupe lmap. Ce dernier travaille pour les Large-Scale Measurements of Broadband Performance, c'est-à-dire pour les mesures objectives des performances des différents FAI, telles qu'elles sont menées par des associations de consommateur, ou l'État, ou un régulateur (comme ce que fait l'ARCEP avec son Observatoire sur la qualité du service fixe d'accès à l'Internet). Ces mesures peuvent être faites à des fins de comparaison, mais aussi de diagnostic. La référence normalisée en matière de métrologie est évidemment composée des RFC du groupe ippm (hélas non cités dans le rapport ARCEP mentionné plus haut). Ces RFC définissent les métriques essentielles comme le temps d'acheminement d'un paquet (RFC 7679) ou comme la capacité (RFC 5136). Comme la valeur de ces métriques dépend du point où se fait la mesure, il fallait pouvoir exprimer cette information. C'est le but de ce RFC, exprimer rigoureusement la mesure a été faite.

Prenons l'exemple d'une sonde Atlas « pinguant » un amer situé sur un autre continent, par exemple une ancre Atlas. Le résultat peut être très différent selon que la sonde soit située chez M. Michu et connectée avec du WiFi, ou bien qu'elle soit dans un data center, toute proche d'un gros point d'échange. Comment exprimer cette information sur la localisation de la sonde ? La terminologie utilisée aujourd'hui est souvent floue. Par exemple, on va dire que la sonde est « située chez l'utilisateur ». Mais ce n'est pas assez précis. Est-elle directement sur la box ou bien derrière, connectée par un réseau WiFi bien surchargé ?

On définit donc un chemin de référence (reference path) qui est le chemin suivi par les paquets IP de la mesure. Sur ce chemin se trouvent des points de mesure (measurement points) où peuvent être installés les appareils de mesure. Ces termes viennent de la norme UIT Y.1541, de la section 5.1 du RFC 3432 et de la section 4 du RFC 5835.

Donc, d'abord (section 3 du RFC), la terminologie essentielle :

  • Le chemin de référence (reference path) est une suite d'équipements (routeurs, commutateurs, bornes WiFi...) et de liens qui sont traversés par les paquets.
  • Un abonné (subscriber) est la personne ou l'organisation qui a loué les services d'un prestataire, peut-être avec des restrictions sur ce qu'il peut faire (cf. la norme UIT Q.1741).
  • Un composant dédié (dedicated component) est une ressource (matérielle ou virtuelle) du chemin de référence qui est entièrement dédiée à un abonné. Un composant partagé est, lui, partagé entre les abonnés.
  • Une démarcation (service demarcation point) est la frontière où les responsabilités du prestataire s'arrêtent. Par exemple, dans le cas d'un accès ADSL typique, la démarcation est juste avant la box (côté utilisateur), le FAI n'étant pas responsable du réseau local à la maison. Pour un McDo avec WiFi, la démarcation est les murs du restaurant (les ondes peuvent sortir mais McDo ne s'engage nullement à ce que le WiFi fonctionne dehors).
  • Les segments du chemin de référence peuvent être gérés ou non-gérés (managed paths and unmanaged paths). Attention, le terme est très chargé, car souvent utilisé de manière propagandiste dans les discussions sur la neutralité du réseau. Ici, la définition se place du point de vue du prestataire, par exemple du FAI : est géré ce dont il est responsable, le reste étant considéré comme non-géré (il faudrait plutôt dire « géré par quelqu'un d'autre »).

La section 4 donne un exemple typique de chemin de référence : la machine de l'utilisateur, le réseau local privé de l'utilisateur, une démarcation avant d'arriver dans le réseau du FAI, l'interconnexion entre le FAI et son transitaire, éventuellement plusieurs transitaires, encore une interconnexion avec le FAI du destinataire, une nouvelle démarcation, qui mène au réseau local privé du destinataire, puis la machine de destination. Dommage que traceroute ne montre pas les chemins comme cela :-) Ces démarcations et interconnexions ne se voient en effet pas facilement dans les paquets IP et doivent donc être documentées explicitement lorsqu'on fait des mesures.

La section 5 est ensuite consacrée aux points de mesure. Chacun doit recevoir un numéro unique, pour permettre de décrire précisement la mesure, et le RFC propose un schéma de numérotation : mpXNN où X est le numéro du réseau (0 chez l'utilisateur, 9 chez le destinataire, et obligation de changer de numéro quand on change d'acteur) et NN une machine ou un lien sur le réseau, avec des numéros croissants quand on s'éloigne de l'utilisateur. Ainsi, on aura, par exemple mp000 pour la machine de départ chez l'utilisateur (la sonde Atlas dans mon exemple plus haut), mp120 pour une mesure faite sur le DSLAM du FAI, mp200 pour le premier routeur du transitaire, etc. À noter que les contraintes pratiques fait que les points de mesure ne sont pas forcément placés idéalement. Par exemple, on voudrait mesurer dans la box mais elle ne le permet pas et on place alors un point de mesure dans un appareil externe. Ce n'est pas idéal, par exemple du fait que la connexion entre la box et cet appareil peut introduire des problèmes.


Téléchargez le RFC 7398


L'article seul

RFC 7397: Report from the Smart Object Security Workshop

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : J. Gilger, H. Tschofenig
Pour information
Première rédaction de cet article le 13 décembre 2014


Le 23 mars 2012, à Paris, a eu lieu un atelier sur la sécurité des objets « intelligents ». Ce RFC résume (bien après...) ce qui s'est dit pendant cet atelier.

Cela fait plusieurs années que les organisations de la galaxie IETF travaillent sur la question de l'« Internet des Objets », son architecture, sa sécurité, etc. Ainsi, en 2011, l'IAB avait fait un atelier à Prague sur ce sujet, dont le RFC 6574 avait donné un compte-rendu. Plusieurs groupes de travail de l'IETF se sont attelés à des tâches liées à l'Internet des Objets, c'est le cas par exemple de LWIG (qui a produit le RFC 7228). L'atelier du 23 mars 2012 à Paris était plus ciblé, ne concernant que la sécurité. (« Smart Object Security » fait « SOS », au fait...)

Trente-six articles avaient été acceptés pour cet atelier, répartis en quatre catégories, « Exigences de sécurité et scénarios », « Expériences de mise en œuvre », « Autorisation » et « Fourniture des informations de créance ».

La première catégorie, « Exigences de sécurité et scénarios », découle de l'obligation de mettre, dans les RFC, une section « Security considerations » (RFC 3552 et RFC 4101), analysant les problèmes éventuels de sécurité de la technologie décrite. Mais l'idée est de généraliser cette préoccupation à un écosystème plus large, au lieu d'avoir le nez sur chaque protocole indépendamment. Quelques exemples de questions posées dans cette catégorie :

  • Quels sont les acteurs impliqués ? Dans le cas des compteurs intelligents, par exemple, cela fait beaucoup de monde, c'est un écosystème complexe (cf. RFC 6272).
  • Qui fait l'avitaillement en informations de créance (credentials) ? Le fabricant des objets ? L'utilisateur ?
  • À ce sujet, justement, qu'attend-on de l'utilisateur final ? Entrer un PIN à la première utilisation ? Appuyer sur deux boutons simultanément pour appairer deux objets ? Se connecter à l'objet via un navigateur Web pour le configurer ? Le problème est d'autant plus aigu que la sécurité trébuche en général sur les problèmes liés aux utilisateurs.

Ainsi, à l'atelier, Paul Chilton avait (cf. son article) parlé de l'éclairage : les coûts d'une ampoule sont réduits et on ne peut pas doter chaque interrupteur d'un processeur 32 bits avec puce crypto ! À bien des égards, l'éclairage représente le cas idéal pour évaluer les solutions de sécurité : si une solution est réaliste dans le cas de l'éclairage, elle le sera pour beaucoup de cas d'objets connectés. (Et cela permettra de faire des blagues sur le thème « Combien d'experts en sécurité faut-il pour changer une ampoule ? »)

Rudolf van der Berg avait, lui, parlé d'objets plus complexes, capables d'utiliser une SIM et donc d'être authentifiés par ce biais. Pour le cas où on n'utilise pas un réseau d'opéateur mobile mais, par exemple, le WiFi, on peut utiliser l'EAP-SIM du RFC 4186.

Un problème récurrent des réseaux d'objets « intelligents » est celui de l'interface utilisateur. Où va t-on taper le mot de passe, dans une ampoule ou un interrupteur ? Pour l'authentification via une SIM, on peut tout sous-traiter à l'opérateur mais, si on change d'opérateur, comment reconfigurer les SIM ?

Pour le marché grand public, on sacrifiera probablement la sécurité, pour éviter de compliquer la tâche de l'utilisateur. On n'a donc pas fini de voir des photos nues des utilisateurs, prises par leur réfrigérateur et volées ensuite par un pirate. (Après tout, tout le monde se fiche de la sécurité de M. Michu, surtout si elle diminue les ventes d'objets jugés trop complexes par le consommateur. Quelques affirmations fortes « nos objets sont sécurisés et cryptés », sous la plume du service Communication, suffiront.) Pour les déploiements d'objets en entreprise, par exemple dans une usine ou un entrepôt, les exigences de sécurité seront sans doute plus fortes, ainsi que la possibilité d'avoir du personnel formé.

Actuellement, on l'a vu, la sécurité de ces objets est faible. Il est très fréquent que, lorsqu'ils sont protégés par un mot de passe, ce mot de passe soit défini en usine, et identique pour tous les objets d'un même modèle. La grande majorité des utilisateurs ne changeant pas les mots de passe (d'autant plus que cela peut être difficile à faire), le pirate n'aura qu'à essayer le mot de passe usine pour craquer la majorité des objets. (Souvenir personnel : en 1986, les VAX/VMS de Digital, engins horriblement coûteux, étaient vendus avec un mot de passe du compte d'administration, SYSTEM, identique pour tous les systèmes - c'était manager. Mais ils étaient gérés par des professionnels qui, en général, savaient qu'il fallait changer immédiatement les mots de passe. Ce qui ne veut pas dire que tout le monde le faisait... Le RFC note que beaucoup d'images logicielles pour les Raspberry Pi ont la même faiblesse. Bien des Pi sont sans doute vulnérables...) Globalement, la sécurité des objets est restée à un stade pré-Internet. Tant qu'on ne les connecte pas, ça va à peu près.

Enfin, en analysant la sécurité des objets connectés, il ne faut pas prendre en compte seulement la sécurité d'une maison ou d'une usine mais aussi les risques plus globaux. Si tout le monde a des compteurs électriques intelligents vulnérables, un attaquant peut couper le courant chez M. Michu et M. Michu, réduit à la bougie, est alors bien embêté. Mais, si l'exploitation de la faille peut être automatisée et faite depuis l'Internet, on peut envisager des scénarios où l'attaquant couperait une ville entière (style Watch Dogs).

Les solutions ne manquent pas, bien sûr, mais elles se heurtent souvent à des problèmes concrets. Si on trouve une faille logicielle dans tous les compteurs intelligents, peut-on les mettre à jour automatiquement et à distance (cf. section 4 du RFC pour les recommandations sur ce point) ? Et cette possibilité de mise à jour ne peut-elle pas être elle-même un vecteur d'attaque ? Un objet non intelligent peut être vendu ou donné à un nouveau propriétaire. Est-ce que ce sera toujours le cas s'il est sécurisé (mot de passe changé, oublié et non resettable) ? La solution de sécurité sera-t-elle ouverte ou bien verrouillera-t-elle l'utilisateur auprès d'un fournisseur unique ? Outre les coûts du matériel pour mettre en œuvre la solution de sécurité, y aura-t-il des coûts de licence, par exemple à cause de brevets ? La sécurité ne travaille pas en isolation, elle doit tenir compte de ce genre de questions.

La deuxième catégorie, trois retours d'expérience, portait sur des points comme les résultats de la mise en œuvre de CoAP. À chaque fois, la conclusion était que le déploiement de solutions de sécurité dans des objets très contraints en ressources était faisable. Souvent, cela nécessitait une adaptation, en laissant tomber des options qui auraient été trop coûteuses. La plupart des protocoles IETF permettent cette adaptation (par exemple, pour TLS, il n'est pas nécessaire de gérer tous les algorithmes de cryptographie du monde). Les développeurs ne signalent pas de cas de protocoles IETF impossibles à ajuster aux exigences des objets connectés. L'idée de concevoir des protocoles de sécurité spécialement faits pour les objets connectés n'a pas eu beaucoup de succès : il n'y a pas de raison de croire que ces protocoles, une fois toutes les fonctions souhaitées mises en œuvre, soient moins gourmands. Mohit Sethi a remarqué que, par exemple, les opérations cryptographiques nécessaires sont à la portée d'un Arduino UNO. En fait, si on veut faire des économies, ce n'est pas la cryptographie, même asymétrique, qu'il faut viser en premier mais plutôt la transmission de données : émettre des ondes radio vide la batterie très vite.

Est-ce que la loi de Moore va aider ? Non. Comme déjà noté dans le RFC 6574, les développeurs sont d'avis que cette loi sera utilisée pour baisser les prix, pas pour augmenter les capacités des objets.

Troisième catégorie, les histoires d'autorisation. Richard Barnes a expliqué que le modèle de sécurité dominant, authentifier une entité puis lui donner tous les droits, était particulièrement peu adapté aux objets communiquants, et il propose d'utiliser plutôt des capacités, comme le permet OAuth (RFC 6749). Cela donne une meilleure granularité aux autorisations.

Enfin, la quatrième et dernière catégorie est celle de la création et de la distribution aux objets des informations de créance. Prenons un nouvel objet qui arrive dans un réseau. Il va falloir qu'il connaisse l'information par laquelle il va être accepté par les autres membres du réseau. Faut-il la mettre dans l'objet à sa fabrication ? En tout cas, la faire rentrer par l'utilisateur de l'objet n'est pas une perspective bien tentante : ces objets ont des interfaces utilisateur très limitées, vraiment pas idéales pour, par exemple, rentrer une longue phrase de passe.

Johannes Gilger (cf. son article) a fait le tour des solutions d'appairage, qui permettent d'introduire deux objets l'un à l'autre, de manière à ce qu'ils ne communiquent qu'entre eux après. Par exemple, un humain se tient à côté des deux objets, qui affichent tous les deux un code numérique, et l'humain vérifie que ces codes coïncident.

Cullen Jennings proposait de faire appel à un tiers : l'objet contacte un serveur qui va faire l'enrôlement dans le réseau (mais le RFC oublie de mentionner les graves problèmes de vie privée que cela pose).

La fin de la section 4 de notre RFC résume quelques groupes de travail IETF qui sont impliqués dans la solution des problèmes qui avaient été identifiés dans cet atelier : LWIG (conseil aux implémenteurs de TCP/IP sur des objets limités), DICE (adapter DTLS à ces objets limités), ACE (authentification et autorisation chez les objets connectés), etc.

Une liste complète des papiers présentés figure dans l'annexe C du RFC. Comme l'indique l'annexe B du RFC, les articles présentés pour l'atelier sont tous en ligne (avec une copie ici). Pour la minorité des orateurs qui ont utilisé des supports de présentation, ceux-ci sont également en ligne.


Téléchargez le RFC 7397


L'article seul

RFC 7396: JSON Merge Patch

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : P. Hoffman (VPN Consortium), J. Snell
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 1 novembre 2014


La commande HTTP PATCH permet d'envoyer à un serveur HTTP un document représentant les différences entre l'état d'une ressource sur le serveur et l'état souhaité par le client HTTP. Cette liste de différences peut prendre plusieurs formats et ce RFC en spécifie un nouveau, JSON merge patch, un format de patch conçu pour JSON.

À noter que ce RFC remplace le RFC 7386, publié deux semaines avant, mais qui comportait une erreur technique.

Le format normalisé par ce RFC n'est en fait pas spécifique à HTTP et pourra même servir avec d'autres protocoles. Mais la commande PATCH du RFC 5789 sera sans doute sa principale utilisation. Une ressource au format JSON merge patch est un objet JSON elle-même. Pour chaque clé, si la ressource cible a également cette clé, la valeur est remplacée par celle du patch. Si elle ne l'a pas, on ajoute le couple clé/valeur. Et si la valeur dans le patch est null, on supprime le couple clé/valeur de la ressource cible. Ainsi, si on a ce document JSON sur le serveur :

{
       "a": "b",
       "c": {
         "d": "e",
         "f": "g"
       }
}

et qu'on envoie le patch suivant en HTTP (notez le type MIME de notre nouveau format) :

PATCH /target HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json

{
       "a":"z",
       "c": {
         "f": null
       }
}

On obtiendra :

{
       "a": "z",
       "c": {
         "d": "e"
       }
}

(La valeur de a a été changée, et le couple indexé par c / f a été supprimé.)

Ce format, centré sur le résultat plutôt que sur les opérations, suit donc des principes assez différents de son homologue XML du RFC 5261.

On notera donc que tous les contenus JSON ne sont pas patchables ou, en tout cas, pas de manière propre et facile, avec ce format. Par exemple, si des null sont effectivement utilisés, ou bien si la structure du texte JSON n'est pas celle d'un objet. Mais, bon, ce format est très simple, est lui-même en JSON, et le RFC est très court et facile à comprendre (ce qui n'aurait pas été le cas si on avait voulu tout prévoir), on ne peut pas tout avoir.

La section 2 du RFC précise les règles à suivre lors du traitement des patches. Elle est rédigée en pseudo-code (c'est une erreur dans l'indentation de ce pseudo-code qui avait rendu nécessaire le remplacement du RFC 7386 par notre RFC) et est assez simple pour être citée ici :

   define MergePatch(Target, Patch):
     if Patch is an Object:
       if Target is not an Object:
         Target = {} # Ignore the contents and set it to an empty Object
       for each Name/Value pair in Patch:
         if Value is null:
           if Name exists in Target:
             remove the Name/Value pair from Target
         else:
           Target[Name] = MergePatch(Target[Name], Value)
       return Target
     else:
       return Patch

Parmi les points à noter, le fait qu'un patch qui n'est pas un objet JSON (par exemple un tableau) va toujours remplacer l'intégralité de la ressource cible, ou le fait qu'on ne peut pas modifier une partie d'une ressource cible qui n'est pas elle-même un objet (il faut la changer complètement).

Le patch va agir sur les valeurs, pas sur leur représentation. Ainsi, on n'a aucune garantie qu'il préservera l'indentation du texte JSON ou la précision des nombres. De même, si la ressource cible tire profit des faiblesses de la norme JSON, elle peut ne pas sortir intacte : par exemple, si la ressource cible a plusieurs membres qui ont la même clé (ce qui n'est pas formellement interdit en JSON mais donne des résultats imprévisibles).

Un exemple plus détaillé de patch JSON se trouve en section 3. On part de ce document :

{
       "title": "Goodbye!",
       "author" : {
         "givenName" : "John",
         "familyName" : "Doe"
       },
       "tags":[ "example", "sample" ],
       "content": "This will be unchanged"
}

Et on veut changer le titre, ajouter un numéro de téléphone, retirer le nom de famille de l'auteur, et retirer l'élément sample du tableau tags. On envoie cette requête :

PATCH /my/resource HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json

{
       "title": "Hello!",
       "phoneNumber": "+01-123-456-7890",
       "author": {
         "familyName": null
       },
       "tags": [ "example" ]
}

Et on obtient ce document :

{
       "title": "Hello!",
       "author" : {
         "givenName" : "John"
       },
       "tags": [ "example" ],
       "content": "This will be unchanged",
       "phoneNumber": "+01-123-456-7890"
}

Notez qu'il a fallu remplacer complètement le tableau tags : il n'y a pas de mécanisme pour retirer juste un élément du tableau (comme expliqué au début). Des tas d'exemples figurent dans l'annexe A, si vous voulez écrire une suite de tests.

Le type MIME application/merge-patch+json figure désormais dans le registre IANA (cf. section 4 du RFC), aux côtés de l'équivalent XML décrit dans le RFC 7351, application/xml-patch+xml.


Téléchargez le RFC 7396


L'article seul

RFC 7395: An XMPP Sub-protocol for WebSocket

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : L. Stout (&yet), J. Moffitt (Mozilla), E. Cestari (cstar industries)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF xmpp
Première rédaction de cet article le 1 novembre 2014


Le protocole XMPP (surtout connu par son utilisation dans la messagerie instantanée) peut fonctionner directement au-dessus de TCP. Mais pas mal de middleboxes se permettent de bloquer les protocoles inconnus et leur liste de protocoles connus est bien courte. XMPP a donc une adaptation à HTTP, lui permettant de tourner sur ce protocole. Mais la sémantique de HTTP, requête/réponse, ne convient guère à XMPP et les performances ne sont donc pas géniales. D'où ce nouveau RFC, qui adapte XMPP à WebSocket, lui permettant de tourner sur un protocole peu filtré, avec des meilleurs résultats que HTTP. La technique date de plusieurs années mais elle est maintenant normalisée.

XMPP est normalisé dans les RFC 6120 et RFC 6121. L'adaptation à HTTP, connue sous le nom de BOSH (Bidirectional-streams Over Synchronous HTTP) est décrite dans XEP-0124 et XEP-0206. Cette approche a fait l'objet de critiques (RFC 6202) notamment pour ses performances, comparées au XMPP natif (directement sur TCP).

Outre le problème des innombrables boîtiers situés sur le chemin et qui se permettent de bloquer certains protocoles, une limite de ce XMPP natif est liée au modèle « tout dans le navigateur Web ». Ces navigateurs peuvent exécuter du code récupéré sur le Web (code typiquement écrit en JavaScript) mais ce code a des tas de restrictions, notamment pour l'utilisation directe de TCP. Un client de messagerie instantanée écrit en JavaScript a donc du mal à faire du XMPP « normal ». D'où l'utilisation, peu satisfaisante, de HTTP. Mais, plutôt que d'utiliser le HTTP habituel, comme le faisait BOSH, on va utiliser WebSocket (RFC 6455). WebSocket fournit un service simple d'acheminement de messages, bi-directionnel, pour toutes les applications tournant dans un navigateur Web. Ce service est donc proche de celui de TCP (à part qu'il est orienté messages, au lieu d'acheminer un flux d'octets continu). XMPP sur WebSocket sera du XMPP normal, ayant les mêmes capacités que du XMPP sur TCP.

Attention à la terminologie : le mot anglais message n'a pas le même sens en WebSocket (où il désigne les unités de base de la transmission, équivalent des segments TCP) et en XMPP (où il désigne un type particulier de strophe, celles qui commencent par <message>). Dans ce RFC, « message » a le sens WebSocket.

WebSocket permet de définir des sous-protocoles (qui devraient plutôt être nommés sur-protocoles puisqu'ils fonctionnent au-dessus de WebSocket) pour chaque application. La définition formelle du sous-protocole XMPP est dans la section 3 de notre RFC. Le client doit inclure xmpp dans l'en-tête Sec-WebSocket-Protocol: lors du passage du HTTP ordinaire à WebSocket. Si le serveur renvoit xmpp dans sa réponse, c'est bon (ce xmpp est désormais dans le registre IANA des sous-protocoles WebSocket). Voici un exemple où tout va bien, le serveur est d'accord, le client fait donc du XMPP juste après :


Client:
GET /xmpp-websocket HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: xmpp
Sec-WebSocket-Version: 13

Server:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: xmpp

Client:
<open xmlns="urn:ietf:params:xml:ns:xmpp-framing"
             to="example.com"
             version="1.0" />

Server:
<open xmlns="urn:ietf:params:xml:ns:xmpp-framing"
             from="example.com"
             id="++TR84Sm6A3hnt3Q065SnAbbk3Y="
             xml:lang="en"
             version="1.0" />

Chaque message WebSocket doit contenir un et un seul document XML complet (pas question de le répartir sur plusieurs messages), par exemple :


<message xmlns="jabber:client" xml:lang="en">
     <body>Every WebSocket message is parsable by itself.</body>
</message>

Ce point était un de ceux qui avaient fait l'objet du plus grand nombre de discussions à l'IETF. L'avantage de cette exigence est qu'elle simplifie le travail des programmeurs. Autrement, c'est très proche de ce que fait XMPP sur TCP, à quelques détails près, dans le reste de la section 3.

Du fait de la règle « uniquement des documents XML complets et bien formés », les clients XMPP sur WebSocket ne peuvent plus utiliser le truc traditionnel qui consistait à envoyer des espaces entre les strophes pour garder la connexion ouverte (section 4.6.1 du RFC 6120). À la place, ils doivent utiliser un mécanisme comme le ping XMPP de XEP 0199 ou la gestion de flots du XEP 0198. Pourquoi ne pas utiliser les services de ping de WebSocket lui-même (section 5.5.2 du RFC 6455) ? On en a le droit mais ce n'est pas obligatoire, en reconnaissance du fait que les navigateurs Web ne donnent en général pas accès à ce service aux programmes JavaScript.

Autre conséquence de cette règle « uniquement des documents XML complets et bien formés », on ne peut pas utiliser du XMPP chiffré avec TLS (cela serait vu comme du binaire, pas comme du XML bien formé). Si on veut sécuriser XMPP sur WebSocket, il faut lancer TLS avant, dans la session WebSocket (URI wss:, section 10.6 du RFC 6455).

Mais, au fait, comment un client sait-il qu'un service XMPP donné, mettons jabber.lqdn.fr, fournit du XMPP sur WebSocket ou pas ? Cette question fait l'objet de la section 4. L'idéal serait d'avoir l'information dans le DNS, de la même façon que le client XMPP classique découvre, dans le DNS, que pour communiquer avec bortzmeyer@jabber.lqdn.fr, il faut passer par le serveur iota.lqdn.fr :

% dig SRV _xmpp-server._tcp.jabber.lqdn.fr
...
;; ANSWER SECTION:
_xmpp-server._tcp.jabber.lqdn.fr. 3600 IN SRV 0 5 5269 iota.lqdn.fr.

Mais les pauvres scripts tournant dans les navigateurs n'ont hélas pas le droit de faire directement des requêtes DNS. Il faut donc une autre méthode d'indirection. La méthode officielle est d'utiliser les métadonnées du RFC 6415, avec les liens du RFC 8288. La relation à utiliser se nomme urn:xmpp:alt-connections:websocket et elle est décrite dans le XEP 0156. Pour l'adresse XMPP bortzmeyer@jabber.lqdn.fr, on va 1) envoyer une requête HTTP http://jabber.lqdn.fr/.well-known/host-meta 2) chercher dans le document récupéré un lien pour urn:xmpp:alt-connections:websocket. Si on trouve (c'est un exemple imaginaire) :


<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
         <Link rel="urn:xmpp:alt-connections:websocket"
               href="wss://im.example.org:443/ws" />
</XRD>

C'est qu'il faut se connecter en WebSocket (avec TLS) à im.example.org.

Quelques petits mots sur la sécurité : la méthode de découverte repose sur le DNS, comme pour la méthode originale de XMPP, puisqu'on doit se connecter en HTTP donc faire une requête DNS pour le nom du service XMPP. On peut (et on devrait) sécuriser le tout avec TLS. Mais attention, les applications qui tournent dans un navigateur Web n'ont pas toujours les moyens de faire leur vérification du certificat et notamment la correspondance entre le sujet du certificat et le nom de service souhaité. Si le nom est le même pour WebSocket et XMPP (ce qui n'est pas le cas de l'exemple de découverte cité plus haut, et ne sera pas le cas si on sous-traite son service XMPP), le navigateur a déjà fait la vérification lors de la connexion TLS WebSocket et il faut lui faire confiance. Sinon, il faut faire confiance à la délégation citée plus haut (le XRD).

Pour le reste, c'est toujours du XMPP et les mécanismes de sécurité classiques de XMPP, comme l'authentification des utilisateurs avec SASL, suivent les mêmes règles.

Il existe déjà plusieurs mises en œuvre de XMPP sur WebSocket (reflétant la relative ancienneté du protocole). Côté serveur, elles peuvent être dans le serveur lui-même (Node-XMPP-Bosh qui, en dépit de son nom, fait aussi des WebSockets, un module pour ejabberd ou un autre pour Openfire) ou bien sous forme d'une passerelle qui reçoit le XMPP sur WebSocket et le transmet au-dessus de TCP vers le vrai serveur (comme celle de Kaazing ou wxg). Côté client, il y a les bibliothèques JavaScript Strophe, Stanza.io et JSJaC. Question documentation, il y a un livre que je n'ai pas lu.


Téléchargez le RFC 7395


L'article seul

RFC 7393: Using Port Control Protocol (PCP) to update dynamic DNS

Date de publication du RFC : Novembre 2014
Auteur(s) du RFC : X. Deng, M. Boucadair (France Telecom), Q. Zhao (Beijing University of Posts and Telecommunications), J. Huang, C. Zhou (Huawei Technologies)
Pour information
Première rédaction de cet article le 8 novembre 2014


Lorsqu'on a une machine avec une adresse IP variable, et qu'on veut la joindre depuis l'extérieur (pour se connecter à sa webcam, ou bien à un serveur HTTP qu'elle héberge ou bien pour tout autre raison), il est courant d'utiliser une mise à jour dynamique du DNS. Après tout, c'est bien le but principal du DNS, fournir un identificateur stable, le nom de domaine. Ce RFC explique les pièges et les problèmes lorsqu'on est connecté via un système à fort partage d'adresses IP (comme DS-Lite), et comment on peut utiliser PCP dans ce contexte.

Il existe plusieurs fournisseurs qui hébergent votre nom de domaine et acceptent des requêtes de mise à jour dynamiques, via un formulaire Web ou bien via une API. On peut avoir une idée du nombre de tels fournisseurs en regardant la liste de DNSlookup. Il n'y a pas à proprement parler de norme pour cette demande de mise à jour, à part le RFC 2136 qui ne semble guère utilisé par ces fournisseurs (comme le note à juste titre le Wikipédia anglophone, « DNS dynamique » désigne en fait deux choses différentes, la mise à jour par le RFC 2136 et le fait de mettre à jour la base sans édition manuelle). Le fournisseur doit avoir une interface qui assure en outre un minimum de sécurité (cf. la section 4 de notre RFC) par exemple en utilisant HTTPS + une authentification du client. Une utilisation courante est que le routeur ou l'ordinateur de l'utilisateur détecte une nouvelle adresse IP, et il notifie l'hébergeur de cette nouvelle adresse. Ce dernier met alors à jour le DNS (via le RFC 2136 ou via toute autre méthode).

Mais, aujourd'hui, de plus en plus d'utilisateurs sont coincés derrière un système à partage d'adresses massif (cf. RFC 6888), où on n'a plus une seule adresse IP publique à la maison. Pour être joint de l'extérieur, il faut communiquer non seulement son adresse IP mais également un port. Plus question de faire tourner son serveur Web sur le port 80, celui-ci ne peut pas être partagé. En outre, il faudra évidemment indiquer au réseau que le port en question devra être connecté au port sur lequel écoute le serveur de l'utilisateur (ce qui se fait en UPnP ou, plus récemment, en PCP, ce dernier étant normalisé dans le RFC 6887).

Les nombreux problèmes posés par le partage d'adresses sont bien connus (RFC 6269). Parmi eux :

  • On ne peut plus compter sur les ports « bien connus » (comme 80 pour HTTP), il faut pouvoir indiquer aux clients un port explicite,
  • Il faut un mécanisme pour configurer les connexions entrantes (justement ce que fait PCP),
  • Il faut pouvoir détecter des changements d'adresses IP qui se passent très loin de l'utilisateur, dans l'AFTR de DS-Lite (RFC 6333) ou dans le routeur CGN pour NAT444.

À noter que, pour prévenir le monde extérieur du couple {adresse, port} à contacter (problème connu sous le nom de « problème du rendez-vous »), on utilise souvent aujourd'hui des techniques non-standard, spécifiques à une application particulière (cela se fait souvent dans le monde du jeu en ligne) ou spécifiques à un protocole donné (SIP va utiliser un SIP proxy, section 16 du RFC 3261).

Voyons donc les trois problèmes à résoudre et les solutions possibles (section 2 du RFC) :

  • Pour indiquer le port, deux méthodes, utiliser des URI qui permettent d'inclure le port, comme le permet HTTP (http://www.example.net:5318/foo/bar), ou utiliser des enregistrement DNS SRV (RFC 2782). La seconde méthode est plus propre, car invisible à l'utilisateur (et elle offre d'autres possibilités), et elle n'oblige pas les applications à utiliser des URI. Malheureusement, elle est anormalement peu déployée dans les applications (par exemple les navigateurs Web).
  • Pour configurer les connexions entrantes, on se sert de PCP (RFC 6887), dont c'est justement le but principal.
  • Pour détecter les changements d'adresses, on va encore se servir de PCP. Une des solutions est de faire des requêtes PCP de type MAP régulièrement, demandant une correspondance {adresse externe -> adresse interne} de courte durée et de voir quelle est l'adresse IP retournée. Une autre solution, moins bavarde, est de juste vérifier la table locale du client PCP, notant les changements d'adresses, et de ne faire une requête MAP que s'il n'y a pas de correspondance dans la table locale. Dans les deux cas, lorsqu'on détecte un changement d'adresse, on met à jour le DNS par les moyens classiques (le client PCP, routeur ou ordinateur, est également client du service de DNS dynamique).

La section 3 couvre quelques détails pratiques de déploiement. Par exemple, le RFC couvre le cas où le service de « DNS dynamique » ne fait pas de DNS du tout mais publie sa propre adresse dans le DNS, redirigeant ensuite les clients vers le bon serveur (via une réponse 301 en HTTP, ce qui se nomme parfois URL forwarding). Ces serveurs devront modifier leur API pour que le client puisse indiquer le port en plus de l'adresse IP (aujourd'hui, ils ont souvent 80 câblé en dur). Dans un contexte différent (protocole ne permettant pas les redirections), on peut envisager d'utiliser la technique de découverte du RFC 6763.

Pour résumer par des remarques personnelles, tout cela est plutôt embrouillé, et on n'est pas tiré d'affaire, d'autant plus que PCP n'est pas tellement déployé aujourd'hui.


Téléchargez le RFC 7393


L'article seul

RFC 7386: JSON Merge Patch

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : P. Hoffman (VPN Consortium), J. Snell
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 15 octobre 2014


La commande HTTP PATCH permet d'envoyer à un serveur HTTP un document représentant les différences entre l'état d'une ressource sur le serveur et l'état souhaité par le client HTTP. Cette liste de différences peut prendre plusieurs formats et ce RFC en spécifie un nouveau, JSON merge patch, un format de patch conçu pour JSON. Suite à une grosse erreur technique, ce RFC a été remplacé très peu de temps après par le RFC 7396.

En fait, le format normalisé par ce RFC n'est pas spécifique à HTTP et pourra même servir avec d'autres protocoles. Mais la commande PATCH du RFC 5789 sera sans doute sa principale utilisation. Une ressource au format JSON merge patch est un objet JSON elle-même. Pour chaque clé, si la ressource cible a également cette clé, la valeur est remplacée par celle du patch. Si elle ne l'a pas, on ajoute le couple clé/valeur. Et si la valeur dans le patch est null, on supprime le couple clé/valeur de la ressource cible. Ainsi, si on a ce document JSON sur le serveur :

{
       "a": "b",
       "c": {
         "d": "e",
         "f": "g"
       }
}

et qu'on envoie le patch suivant en HTTP (notez le type MIME de notre nouveau format) :

PATCH /target HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json

{
       "a":"z",
       "c": {
         "f": null
       }
}

On obtiendra :

{
       "a": "z",
       "c": {
         "d": "e"
       }
}

(La valeur de a a été changée, et le couple indexé par c / f a été supprimé.)

Ce format, centré sur le résultat plutôt que sur les opérations, suit donc des principes assez différents de son homologue XML du RFC 5261.

On notera donc que tous les contenus JSON ne sont pas patchables ou, en tout cas, pas de manière propre et facile, avec ce format. Par exemple, si des null sont effectivement utilisés, ou bien si la structure du texte JSON n'est pas celle d'un objet. Mais, bon, ce format est très simple, est lui-même en JSON, et le RFC est très court et facile à comprendre (ce qui n'aurait pas été le cas si on avait voulu tout prévoir), on ne peut pas tout avoir.

La section 2 du RFC précise les règles à suivre lors du traitement des patches. Elle est rédigée en pseudo-code (attention, l'indentation dans le RFC est complètement ratée, cf. l'errata #4132, et c'est à cause de cela qu'il a fallu publier le RFC 7396) et est assez simple pour être citée ici :

   define MergePatch(Target, Patch):
     if Patch is an Object:
       if Target is not an Object:
         Target = {} # Ignore the contents and set it to an empty Object
       for each Name/Value pair in Patch:
         if Value is null:
           if Name exists in Target:
             remove the Name/Value pair from Target
         else:
           Target[Name] = MergePatch(Target[Name], Value)
       return Target
     else:
       return Patch

Parmi les points à noter, le fait qu'un patch qui n'est pas un objet JSON (par exemple un tableau) va toujours remplacer l'intégralité de la ressource cible, ou le fait qu'on ne peut pas modifier une partie d'une ressource cible qui n'est pas elle-même un objet (il faut la changer complètement).

Le patch va agir sur les valeurs, pas sur leur représentation. Ainsi, on n'a aucune garantie qu'il préservera l'indentation du texte JSON ou la précision des nombres. De même, si la ressource cible tire profit des faiblesses de la norme JSON, elle peut ne pas sortir intacte : par exemple, si la ressource cible a plusieurs membres qui ont la même clé (ce qui n'est pas formellement interdit en JSON mais donne des résultats imprévisibles).

Un exemple plus détaillé de patch JSON se trouve en section 3. On part de ce document :

{
       "title": "Goodbye!",
       "author" : {
         "givenName" : "John",
         "familyName" : "Doe"
       },
       "tags":[ "example", "sample" ],
       "content": "This will be unchanged"
}

Et on veut changer le titre, ajouter un numéro de téléphone, retirer le nom de famille de l'auteur, et retirer l'élément sample du tableau tags. On envoie cette requête :

PATCH /my/resource HTTP/1.1
Host: example.org
Content-Type: application/merge-patch+json

{
       "title": "Hello!",
       "phoneNumber": "+01-123-456-7890",
       "author": {
         "familyName": null
       },
       "tags": [ "example" ]
}

Et on obtient ce document :

{
       "title": "Hello!",
       "author" : {
         "givenName" : "John"
       },
       "tags": [ "example" ],
       "content": "This will be unchanged",
       "phoneNumber": "+01-123-456-7890"
}

Notez qu'il a fallu remplacer complètement le tableau tags : il n'y a pas de mécanisme pour retirer juste un élément du tableau (comme expliqué au début). Des tas d'exemples figurent dans l'annexe A, si vous voulez écrire une suite de tests.

Le type MIME application/merge-patch+json figure désormais dans le registre IANA (cf. section 4 du RFC), aux côtés de l'équivalent XML décrit dans le RFC 7351, application/xml-patch+xml.


Téléchargez le RFC 7386


L'article seul

RFC 7384: Security Requirements of Time Protocols in Packet Switched Networks

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : T. Mizrahi (Marvell)
Pour information
Réalisé dans le cadre du groupe de travail IETF tictoc
Première rédaction de cet article le 30 octobre 2014


De plus en plus de protocoles sur l'Internet dépendent d'une horloge correcte. L'époque où les machines étaient vaguement mises à une heure approximative, de façon purement manuelle, est révolue. Aujourd'hui, il est essentiel de connaître l'heure exacte, et cela implique des dispositifs automatiques comme NTP. C'est encore plus essentiel quand il s'agit de protocoles de sécurité, comme DNSSEC (pour déterminer si une signature a expiré) ou X.509 (pour savoir si un certificat est encore valable). Mais cette utilisation du temps comme donnée dans un protocole de sécurité pose elle-même des problèmes de sécurité : si un attaquant perturbe NTP, ne risque-t-il pas d'imposer une fausse heure, et donc de subvertir des protocoles de sécurité ? D'où le groupe de travail TICTOC de l'IETF, dont voici le premier RFC : le cahier des charges des solutions de sécurité pour les protocoles de synchronisation d'horloges, comme NTP. (Une solution pour NTP a ensuite été normalisée dans le RFC 8915.)

Deux de ces protocoles sont largement déployés aujourd'hui : un protocole IETF, NTP (RFC 5905) et PTP, alias IEEE 1588 (pas disponible en ligne, comme toutes les normes du dinosaure IEEE). NTP inclut des mécanismes de sécurité, une authentification par secret partagé (RFC 5905, notamment section 7.3) et une autre par clé publique (Autokey, RFC 5906). Par contre, si PTP a un mécanisme d'authentification expérimental (annexe K de la norme), celui-ci ne semble pas avoir été formalisé complètement. Les déploiements de PTP sont donc non sécurisés.

On ne part donc pas de zéro, en tout cas pour NTP, qui a déjà une bonne partie des mécanismes demandés par ce cahier des charges. Ce RFC vise (section 1) un public composé des auteurs de logiciels de synchronisation (pour s'assurer qu'ils mettent en œuvre correctement les mécanismes de sécurité normalisés) et des auteurs de normes (qui vont devoir ajouter des mécanismes de sécurité là où ils manquent). Il peut aussi être utile aux opérationnels, lorsqu'ils révisent ou auditent la sécurité de leur système de synchronisation d'horloges. À partir de questions simples, « quelles sont les menaces ? », « quels sont les coûts de la sécurité ? », « quelles sont les dépendances croisées (par exemple une authentification des serveurs de temps via un certificat dont l'usage dépend d'une horloge correcte) ? », le RFC va poser une liste d'exigences pour les solutions de sécurité.

Un petit mot sur la terminologie au passage : PTP et NTP n'ont pas le même vocabulaire mais l'analyse de notre RFC traite ensemble les deux protocoles et utilise donc un vocabulaire commun. Ainsi, les termes « maître » (master) et « esclave » (slave) servent pour PTP et NTP (bien qu'en NTP, on dise plutôt « serveur » et « client »). Un « grand-maître » (grandmaster) est une machine qui a un accès direct à une horloge, sans passer par le protocole réseau.

Donc, commençons par l'analyse des menaces (section 3). On se base surtout sur l'article de l'auteur du RFC, T. Mizrahi, « Time synchronization security using IPsec and MACsec » (ISPCS 2011). Mais le RFC contient d'autres références à lire.

D'abord, une distinction entre attaquants internes et externes. Les externes sont juste connectés au même Internet que leurs victimes, ils n'ont aucun privilège particulier. Les internes, par contre, soit ont accès à une partie des clés cryptographiques utilisées, soit ont un accès au réseau sur lequel se trouvent leurs victimes et peuvent donc mener certaines attaques. Ils peuvent par exemple générer du faux trafic qui a plus de chances se sembler authentique. Se défendre contre ces Byzantins sera donc plus difficile. Si aucun mécanisme de sécurité n'est déployé, les attaquants internes et externes ont les mêmes possibilités.

Autre distinction importante entre les attaquants, ceux capables d'être Homme du Milieu et les autres. Un homme du milieu est placé de telle façon qu'il peut intercepter les paquets et les modifier. Les autres peuvent injecter des paquets (y compris en rejouant des paquets qu'ils ont lu) mais pas modifier le trafic existant.

Maintenant, quelles sont les attaques possibles ? La section 3.2 en fournit une longue liste. Rappelez-vous que ce sont des attaques théoriques : beaucoup sont déjà empêchées par les techniques de sécurité existant dans NTP (si elles sont activées...) Un homme du milieu peut modifier les paquets, en changeant les informations sur le temps, donnant ainsi de fausses informations. Tout va sembler OK mais les ordinateurs vont s'éloigner de l'heure réelle. Un attaquant actif peut aussi fabriquer, en partant de zéro, un faux paquet, contenant ces fausses informations. Il peut se faire passer pour le maître, trompant ainsi les esclaves, ou pour un esclave, donnant des informations au maître qui vont lui faire envoyer une réponse erronée au vrai esclave. Là aussi, tout semblera marcher, les horloges seront synchronisées, mais l'information sera fausse. Si l'attaquant a du mal à modifier des paquets ou à les générer (par exemple en raison d'une mesure de sécurité), il peut aussi tenter de rejouer des paquets du passé qu'il aura copiés. Cela permet potentiellement de faire reculer les horloges des victimes.

Un autre moyen de se faire accepter comme le maître, au lieu d'usurper l'identité du vrai maître, est de tricher dans le processus de choix du maître. Par exemple, en PTP, le maître est choisi par un algorithme nommé BMCA (Best Master Clock Algorithm) et le tricheur peut donc arriver à se faire désigner comme maître (rappelez-vous que PTP n'a guère de sécurité).

Un attaquant homme du milieu peut aussi jeter les paquets (faisant croire qu'un maître n'est pas joignable) ou les retarder délibérement : ce retard peut permettre de modifier l'horloge, puisque les participants au protocole NTP utilisent le temps d'aller-retour pour calculer l'heure chez le pair. Certaines protections anti-rejeu (comme le fait de vérifier qu'on ne reçoit pas de copie d'un paquet déjà reçu) ne marchent pas contre cette attaque.

Certaines de ces attaques peuvent se faire par des moyens très divers, situés dans la couche 2 ou dans la couche 3 : ARP spoofing, par exemple.

Une solution évidente à bien des problèmes de sécurité est la cryptographie. Mais attention, elle ouvre la voie à de nouvelles attaques comme l'envoi de paquets mal formés qui mènent à des calculs cryptographiques très longs, réalisant ainsi une attaque par déni de service. Une autre attaque par déni de service moins sophistiquée serait de noyer la machine sous un volume énorme de paquets NTP ou PTP.

L'attaquant peut aussi viser le grand-maître : si ce dernier utilise le GPS, un attaquant qui peut envoyer des faux signaux GPS peut tromper le grand-maître, trompant en cascade tous les autres participants. Aucune défense située dans le protocole de synchronisation ne sera alors effective, puisque l'attaque a lieu en dehors de ce protocole. Elle échappe donc au groupe de travail TICTOC.

Bien sûr, il y a aussi des menaces exploitant une faille des programmes qui mettent en œuvre les protocoles, plutôt que des protocoles eux-mêmes, par exemple les attaques par réflexion utilisant NTP, lorsque le serveur accepte trop facilement des requêtes normalement utiles uniquement pour le débogage.

Plus sophistiquées (peut-être trop pour être utilisées en vrai), les reconnaissances d'un réseau conduites grâce aux protocoles de synchronisation d'horloge. Un attaquant, pour préparer de futures attaques, commence par reconnaître sa cible, chercher les machines, etc. Avec la synchronisation d'horloges, il peut, passivement, collecter des informations qui, par leur fréquence et leur contenu, permettent, entre autres, de fingerprinter des machines spécifiques.

Les attaques possibles sont résumées en section 3.3, avec un tableau qui indique pour chaque attaque l'impact (horloges complètement faussées, précision diminuée - mais l'horloge reste proche du temps réel, ou déni de service) et le type d'attaquant qui peut les effectuer (interne ou externe, devant être homme du milieu ou pas).

De cette liste d'attaques et de leurs caractéristiques, notre RFC va tirer un certain nombre d'exigences auxquelles devront se conformer les solutions de sécurité. Chacune de ces exigences aura un niveau d'impérativité (les MUST et SHOULD du RFC 2119) selon l'impact et selon le type d'attaquant. Par exemple, les attaques qui peuvent être faites par un attaquant externe sont plus graves (le nombre d'attaquants potentiels est plus élevé) et ont donc plus souvent un MUST (section 4 pour la discussion sur les niveaux). Notez que la solution n'est pas forcément interne au protocole de synchronisation d'horloges : utiliser IPsec ou IEEE 802.1AE est souvent une bonne solution.

La section 5 donne la liste des exigences elle-mêmes. La première est l'authentification : il FAUT un mécanisme d'authentification (vérifier que la machine est bien ce qu'elle prétend être) et d'autorisation (vérifier que la machine qui annonce être un maître en a le droit). Notamment, les esclaves doivent pouvoir vérifier les maîtres. Ces mécanismes doivent être récursifs, car les protocoles de synchronisation d'horloges passent souvent par des relais intermédiaires (en NTP, une machine de strate 3 ne reçoit pas directement l'horloge, mais le fait via la machine de strate 2 - le RFC 5906 avait inventé le terme de proventication, contraction de provenance et authentication pour décrire cette question). Cette authentification permet de répondre aux attaques par usurpation d'identité. Sans cela, des attaques triviales sont possibles.

Par contre, l'authentification des esclaves par les maîtres est facultative (MAY) car un esclave malveillant ne peut pas tellement faire de mal à un maître (à part peut-être le déni de service par l'afflux d'esclaves non autorisés) et qu'un esclave a peu de maîtres alors qu'un maître a beaucoup d'esclaves, dont l'authentification pourrait nécessiter trop de travail.

Le RFC impose aussi l'existence d'un mode « fermé » où seuls des pairs authentifiés peuvent participer (il existe sur l'Internet beaucoup de serveurs NTP publics, acceptant des connexions de la part d'inconnus).

Le RFC exige un mécanisme de protection contre les attaques d'un homme du milieu essayant de diminuer la qualité des données, par exemple en retardant délibérement des paquets. En NTP, c'est par exemple le fait d'avoir plusieurs maîtres.

Après l'authentification (et l'autorisation), l'intégrité des paquets : notre RFC exige un mécanisme d'intégrité, permettant de s'assurer qu'un méchant n'a pas modifié les paquets en cours de route. Cela se fait typiquement par un ICV (Integrity Check Value). La vérification de l'intégrité peut se faire à chaque relais (ce qui est plus simple), ou bien de bout en bout (ce qui protège si un des relais est un vilain Byzantin).

L'usurpation d'identité est ensuite couverte : le RFC exige (MUST) un mécanisme permettant d'empêcher un attaquant de se faire passer pour le maître. Comme son nom l'indique, le maître peut modifier les horloges des autres machines à volonté et empêcher une usurpation est donc critique. Le RFC impose en outre un mécanisme contre le rejeu (car ce sont des attaques triviales à monter) et un moyen de changer les clés cryptographiques utilisées (cela a l'air évident mais certains protocoles - comme OSPF, cf. RFC 6039 - sont très pénibles pour cela, et en pratique les clés ne sont pas changées).

Les demandes suivantes sont moins fortes, car concernant des attaques moins graves ou plus difficiles à faire. Par exemple, il faudrait, si possible (SHOULD), fournir des mécanismes contre les attaques par déni de service.

Enfin viennent les simples suggestions, comme de prévoir un mécanisme assurant la confidentialité des paquets. Comme aucune information vraiment secrète ne circule dans les messages de synchronisation d'horloges, cette suggestion est un simple MAY.

Ces exigences sont résumées dans la section 6, sous la forme d'un tableau synthétique.

La section 7 rassemble un ensemble de questions diverses sur la sécurité des protocoles de synchronisation d'horloge. Par exemple, la section 7.4 se penche sur les interactions entre cette synchronisation et des protocoles extérieurs de sécurité comme IPsec. La 7.5 expose un cas plus embêtant, le problème d'œuf et de poule entre la synchronisation d'horloges et des protocoles qui utilisent l'heure dans leurs mécanismes de sécurité. Par exemple, si on utilise TLS avec authentification X.509 à un moment quelconque pour se connecter, une horloge correcte est nécessaire (vérification de la non-expiration du certificat), alors que NTP n'est pas forcément déjà disponible. Il faut donc une horloge stable, pour ne pas trop dériver en attendant que NTP prenne le relais.

Enfin, la section 8 rappelle que le problème difficile de la distribution des clés n'est pas encore traité, que ce soit dans ce RFC ou dans les protocoles.

Voici un court exemple de sécurisation avec NTP. Je n'ai pas utilisé la technique Autokey du RFC 5906 mais la plus ancienne (voire archaïque), qui utilise des clés privées. L'un des avantages est la portabilité, on sait que cela va marcher sur tous les clients et serveurs NTP. Sur le serveur, je crée les clés :

% sudo ntp-keygen  -M     
Built against OpenSSL OpenSSL 1.0.1i 6 Aug 2014, using version OpenSSL 1.0.1j 15 Oct 2014
Generating new md5 file and link
ntpkey_md5_alarmpi->ntpkey_MD5key_alarmpi.3623647899

% sudo ln -s ntpkey_md5_alarmpi ntp.keys

% cat ntp.keys
...
11 SHA1 2db9278081f6b410cfb826317b87cf95d5b90689  # SHA1 key
12 SHA1 cc52f97bc43b6c43a4cbe446813f0c6c3bd54f7c  # SHA1 key

Et j'indique dans la configuration que je n'autorise (notrust) que les clients du réseau local, et s'ils s'authentifient avec la clé n° 11 :

keys /etc/ntp/ntp.keys
trustedkey 11
...
restrict default noquery nopeer nomodify notrap
...
restrict 2a01:e35:8bd9:8bb0:: mask ffff:ffff:ffff:ffff:: notrust

Avec une telle restriction, les clients qui ne s'authentifient pas ne reçoivent pas de réponse (même pas une réponse négative), ce qui rend les problèmes d'authentification difficiles à déboguer, d'autant plus que Wireshark n'indique apparemment nulle part si les paquets sont authentifiés ou pas. Côté client, il faut donc montrer patte blanche, d'abord copier les clés puis :

keys /etc/ntp/ntp.keys
trustedkey 11

server my-favorite-server key 11

Et, cette fois, le serveur répond et tout se passe bien.

Si vous voulez faire de l'Autokey (cryptographie à clé publique), vous pouvez consulter la documentation officielle ou bien, en français, l'article de Laurent Archambault (ou, en général, son cours NTP). Si, au lieu d'être sur Unix avec la mise en œuvre de référence ntpd, vous gérez un routeur Cisco, voyez en français cet article. Si vous utilisez le programme des gens d'OpenBSD, OpenNTPD, tant pis pour vous, il n'a aucun mécanisme de sécurité. Je n'ai pas trouvé de documents ANSSI sur la sécurisation des protocoles de synchronisation d'horloge. Le NIST a un service NTP authentifié (notez la complexité des procédures d'inscription !). Pendant longtemps, la référence en français était l'excellent article d'Alain Thivillon mais il est trop ancien aujourd'hui.


Téléchargez le RFC 7384


L'article seul

RFC 7381: Enterprise IPv6 Deployment Guidelines

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : K. Chittimaneni (Dropbox), T. Chown (University of Southampton), L. Howard (Time Warner Cable), V. Kuarsingh (Dyn), Y. Pouffary (Hewlett Packard), E. Vyncke (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 26 octobre 2014


Le déploiement d'IPv6 continue, trop lentement, mais il continue et de plus en plus d'organisations font désormais fonctionner ce protocole. Ce document est une série de conseils sur le passage à IPv6 au sein d'une organisation (le RFC dit « enterprise » mais je ne vois pas de raison de traduire par « entreprise », ce qui limiterait arbitrairement aux organisations privées prévues pour faire gagner de l'argent à leurs actionnaires). Les précédents RFC de conseils sur le déploiement d'IPv6 ciblaient des organisations spécifiques (comme les opérateurs réseaux dans le RFC 6036), celui-ci s'adresse à toute organisation qui dispose d'un réseau et d'administrateurs pour s'en occuper (les particuliers, ou toutes petites organisations sans administrateurs réseaux, ne sont pas traités).

Bref, vous êtes l'heureux titulaire du titre d'administrateur réseaux dans une organisation qui est pour l'instant encore attardée et qui n'utilise que le protocole du siècle dernier, IPv4. Votre mission, que vous l'acceptiez ou pas, est de passer à IPv6, sachant en outre que vous n'avez probablement pas le droit d'abandonner complètement IPv4. Que faire ? Le RFC 4057 décrivait ces réseaux d'organisation, qui se distinguent du réseau SOHO par la présence d'administrateurs réseaux compétents et dévoués. Il s'agit donc de réseaux gérés, contrairement au réseau de la maison de M. Toutlemonde. Le, la ou les administrateurs réseau doivent gérer un réseau interne, comprenant des serveurs, des postes de travail, des imprimantes, et parfois des routeurs internes. Ce réseau est connecté à l'Internet via au moins un routeur. Plusieurs serveurs sont prévus pour être accessibles de l'extérieur, par exemple le serveur de courrier. Donc, pour résumer le cahier des charges :

  • Déployer IPv6 sans casser IPv4, qui doit continuer à fonctionner,
  • Perturber le moins possible le service. L'utilisateur professionnel veut que ça continue à marcher, les changements techniques indispensables (comme le passage à IPv6) doivent pouvoir être ignorés dans le cadre de son travail.

La pénurie d'adresses IPv4 a des conséquences même sur ceux qui s'obstinent à ne pas déployer IPv6. Par exemple, comme le note le RFC 6302, les serveurs Internet, face au déploiement de techniques comme le CGN, ne peuvent plus se contenter de journaliser l'adresse IP source de leurs clients, ils doivent aussi noter le port source. D'autre part, même si on croit pouvoir se passer d'IPv6, certains réseaux ont déjà de l'IPv6 sans le savoir (parce qu'il est activé par défaut sur beaucoup de systèmes) et cela a des conséquences de sécurité (cf. RFC 6104 pour un exemple et le RFC 7123 pour une vision plus générale de ce problème).

Notre RFC propose trois phases pour l'opération de déploiement :

  • Préparation et détermination,
  • Phase interne,
  • Phase externe.

Les deux dernières ne sont pas forcément exécutées dans cet ordre. Par exemple, si on gère un site Web et que beaucoup de clients potentiels ont déjà IPv6, il est logique de commencer par la phase externe, doter ce site d'une connectivité IPv6. En outre, bien des applications de gestion, comme celles de comptabilité sont affreusement archaïques et n'auront pas IPv6 de si tôt, ce qui relativise l'urgence de la phase interne. D'un autre côté, bien des systèmes d'exploitation ont IPv6 par défaut, et le RFC 7123 note que cela pose des problèmes de sécurité qui mériteraient peut-être une attention immédiate, et donc une priorité à la phase interne. Autre cas où la phase interne doit sans doute passer en premier : si l'espace d'adressage du RFC 1918 commence à ne plus suffire ou bien si une fusion/acquisition a mené à assembler deux réseaux qui utilisaient les mêmes préfixes, entraînant un grand désordre et l'envie, chez l'administrateur réseaux, de se reconvertir comme affineur de fromage dans l'Hérault, ou de déployer IPv6. Comme le notait le RFC 6879, la fusion/acquisition de deux organisations est souvent une bonne occasion pour passer à IPv6, car fusionner deux réseaux IPv4 en adressage privé est toujours long et compliqué. Bref, chaque organisation va devoir déterminer ses priorités et décider de commencer, après la première phase de préparation, par la phase interne ou par l'externe. Autrefois, il y avait aussi la catégorie « c'est bien compliqué tout cela, est-ce que ça en vaut la peine ? » mais sa taille diminue. Certaines objections techniques qui étaient valables à une époque (RFC 1687) ont depuis été traitées.

Donc, maintenant, au travail, avec la première phase, Préparation & Détermination (section 2 du RFC). Le RFC recommande de nommer un « chef de projet professionnel ». Ce qui est sûr est qu'il faut gérer le projet sérieusement, car c'est après tout un changement important dans l'infrastructure, avec plein d'interdépendances. La phase de Préparation & Détermination va, entre autres, servir à décider si on priorise la Phase Interne ou la Phase Externe. La première phase découvrira sans doute des problèmes inattendus et elle se fera donc en plusieurs itérations (« zut, ce plan ne marchera pas, il faut en trouver un autre »).

D'abord, l'inventaire de l'existant. Il faut faire la liste des matériels en déterminant pour chacun s'il est prêt pour IPv6. Il y aura du matériel déjà prêt (au sens où il fait déjà tourner un système capable d'IPv6), du matériel qui pourra recevoir une mise à jour logicielle, et du matériel qu'il faudra remplacer car aucun système avec IPv6 n'existe pour ce matériel. Par exemple, les routeurs (sauf le bas de gamme) sont probablement prêts, mais les objets connectés (genre caméras ou imprimantes) ne le sont souvent pas.

Après le matériel, le logiciel. Il faut faire le tour des applications pour déterminer lesquelles passeront en IPv6 sans problèmes. Si certains logiciels ne sont pas prêts, il faut demander au vendeur. Je suis toujours surpris que les vendeurs expliquent leur manque d'IPv6 par l'argument « aucun client ne l'a demandé ». Parfois, bien sûr, le vendeur ment mais, parfois, les clients semblent effectivement d'une timidité maladive et n'osent pas dire aux vendeurs, même gentiment « excusez-nous de vous demander pardon, mais pourrions-nous avoir de l'IPv6 un jour, s'il vous plait ? »

Lorsque l'application est développée/maintenue en interne, c'est l'occasion de se pencher sur les pratiques de codage. Est-ce que les applications ne sont pas d'un trop bas niveau, intégrant des détails non pertinents comme la taille de l'adresse IP ? Parmi les RFC dont la lecture peut être utile aux programmeurs à ce stade, citons le RFC 4038 sur le rapport entre les applications et IPv6, le RFC 6724 sur la sélection de l'adresse IP source, et le RFC 6555, sur l'algorithme des globes oculaires heureux, si utile lorsqu'on a à la fois IPv4 et IPv6. Un autre point important, mais non mentionné par ce RFC, est que le cycle de vie d'un logiciel développé en interne est long : ce qui est programmé aujourd'hui sera toujours en service dans de nombreuses années. Il faut donc adopter des bonnes pratiques de programmation (programmation réseau de haut niveau, valable aussi bien pour IPv4 que pour IPv6) aujourd'hui, même si la migration vers IPv6 semble lointaine.

C'est l'occasion d'aborder la question cruciale de la formation. Aujourd'hui, il existe encore des écoles ou universités qui enseignent IP sans parler d'IPv6, ou en le réduisant à deux heures de cours à la fin de l'année, dans un fourre-tout « divers sujets ». C'est consternant et cela veut dire que la formation à IPv6 dépendra surtout du technicien lui-même, ou bien de son employeur (section 2.3 du RFC).

Autre gros morceau dans la phase de préparation et détermination, la question de la sécurité. Évidemment, on veut que le réseau soit aussi sûr en IPv6 qu'en IPv4. Au passage, j'ai fait un long exposé à ce sujet. Je ne suis pas d'accord avec l'approche du RFC. Le RFC note qu'IPv6 n'est pas intrinsèquement plus sûr qu'IPv4 juste parce qu'il est plus récent, ce qui est du bon sens. Mais il prend ensuite une approche unilatérale, en notant qu'il existe beaucoup de failles de sécurité dans le code IPv6 car il n'a guère été testé au feu. C'est exact mais le RFC oublie de dire que c'est la même chose pour les attaquants : leurs programmes sont rarement adaptés à IPv6. Mon expérience est que les attaquants et les défenseurs sont aussi peu préparés à IPv6 et que, en pratique, la sécurité des deux protocoles est à peu près équivalente. Le RFC, comme le font souvent les professionnels de la sécurité, pessimistes par profession, ne voit que les faiblesses de la défense. En tout cas, tout le monde est d'accord pour dire que la formation (paragraphe précédent...) est essentielle.

Le RFC tord le cou à quelques mythes comme quoi la sécurité d'IPv6 serait meilleure (il oublie les mythes inverses, tout aussi répandus). Par exemple, IPv6 ne rend pas impossible le balayage d'un réseau, juste parce qu'il a davantage d'adresses. Le RFC 7707 décrit plusieurs techniques de balayage qui sont faisables avec IPv6 (et qui sont effectivement mises en œuvre dans des outils existants). Mais s'il est vrai qu'IPv6 n'empêche pas le balayage, ce nouveau RFC, dans son analyse trop rapide, oublie de dire que le balayage est bien plus facile et rapide en IPv4, comme le montre la disponibilité d'outils (comme massscan) qui balaient tout l'Internet IPv4 en quelques heures ! De même, notre nouveau RFC rappelle qu'IPv6 n'a pas de sécurité cryptographique par défaut (contrairement à une légende répandue par des zélotes d'IPv6 au début, cf. RFC 6434 pour l'enterrement de cette légende). Pire (et, là, ce RFC 7381 est gravement en tort) : la section 2.4.1 explique que c'est une bonne chose pour la sécurité qu'il n'y ait pas de chiffrement car il faut pouvoir espionner le trafic de ses utilisateurs, un argument vraiment incroyable à l'ère post-Snowden.

Le RFC est plus raisonnable par la suite en notant que certaines pratiques de sécurité relèvent plus de la magie que de la raison. Par exemple, les ULA en IPv6 (RFC 4193) ou les adresses privées en IPv4 (RFC 1918) n'apportent aucune sécurité en elles-même, contrairement à ce que croient naïvement certains administrateurs réseau.

Notre RFC fait le point sur les failles de sécurité qui sont spécifiques à IPv6 :

  • Les adresses de protection de la vie privée (RFC 8981) ne la protègent que partiellement mais, surtout, compliquent la vie de l'administrateur réseaux, en limitant la traçabilité des machines. Si un journal montre que 2001:db8:1:1:c144:67bd:5559:be9f s'est connecté au serveur LDAP, comment savoir quelle machine était 2001:db8:1:1:c144:67bd:5559:be9f puisque, s'il utilisait le RFC 8981, il a pu changer d'adresse souvent, sans que cela soit enregistré quelque part ? Une solution possible est d'utiliser un logiciel qui écoute le réseau et stocke dans une base de données les correspondances entre adresses MAC et adresses IPv6 (un logiciel comme ndpmon, donc). Si on contrôle complètement les machines terminales, on peut aussi interdire les extensions « vie privée ». On peut enfin forcer l'usage de DHCP en demandant au routeur d'envoyer toutes les annonces avec le bit M (qui indique que DHCP est disponible, RFC 4861, section 4.2) et qu'aucun préfixe ne comporte le bit A (ce qui interdira l'auto-configuration sans état, RFC 4861, section 4.6.2). Cela suppose que toutes les machines ont un client DHCP v6, ce qui n'est pas gagné aujourd'hui. Pire : on sait qu'aujourd'hui le comportement des différents système en présence des bits M et A varie énormément.
  • Et les en-têtes d'extension ? Leur analyse est difficile et, résultat, certains systèmes de sécurité ne savent pas les traiter, permettant ainsi au méchant d'échapper à la détection ou au filtrage, simplement en ajoutant des en-têtes au paquet IPv6 (RFC 7113 pour un exemple).
  • La fragmentation est une source classique de casse-tête. Elle existe aussi en IPv4 mais IPv6 la restreint à la source, les routeurs intermédiaires ne peuvent pas fragmenter. Du point de vue sécurité, la principale question liée à la fragmentation est le fait que, au nom d'une sécurité mal comprise, certains réseaux bloquent le protocole ICMP, malgré le RFC 4890, gênant ainsi la détection de MTU et empêchant donc de facto la fragmentation. Autres problèmes liés à la fragmentation, mais qui ne sont pas spécifiques à IPv6, le risque d'utilisation de fragments pour échapper à la détection (RFC 6105 pour un exemple), et le réassemblage de fragments qui se recouvrent (RFC 5722).
  • Pour la résolution d'adresses IP en adresses MAC, IPv6 utilise NDP et plus ARP. Le RFC classe cela comme « une importante différence » mais, en fait, du point de vue de la sécurité, les deux protocoles sont très proches. Ils fonctionnent en diffusant à tous l'adresse convoitée, et ils font une confiance absolue à la première réponse reçue. Aucune authentification n'existe (IPv6 a des solutions, mais très peu déployées, cf. RFC 3971 et RFC 3972).
  • Enfin, dernier problème qu'on n'avait pas avec de l'IPv4 pur, un réseau double-pile, IPv4 et IPv6, augmente la surface d'attaque en offrant davantage de possibilités au méchant. Au minimum, il faut faire attention à ce que les politiques de sécurité soient les mêmes en IPv4 et en IPv6 afin d'éviter (je l'ai déjà vu), un pare-feu strict en IPv4 mais très laxiste en IPv6.

Maintenant, le routage. Un grand réseau interne va probablement utiliser un IGP. Lequel ? Plusieurs protocoles gèrent IPv6 (RIPng, IS-IS, OSPF). A priori, pour faciliter la vie des techniciens, il est logique d'utiliser le même protocole de routage en IPv4 et en IPv6. Petit piège dans le cas d'OSPF : OSPF v2 (pour IPv4) et OSPF v3 (pour IPv6) sont proches mais ne sont pas exactement le même protocole (le RFC oublie qu'OPSF v3 peut désormais gérer IPv4, cf. RFC 5838, mais il est vrai que c'est très peu fréquent).

Et l'adressage (section 2.6) ? Il est évidemment radicalement différent en IPv4 et en IPv6. En IPv4, l'essentiel du travail sur l'adressage a pour but d'économiser les quelques adresses qu'on détient, pour tout faire fonctionner malgré la pénurie. En IPv6, ce problème disparait et on peut donc se concentrer sur un plan d'adressage propre. Le document à lire pour faire de jolis plans d'adressage en IPv6 est le RFC 5375.

L'une des décisions à prendre sera d'utiliser des adresses PA ou PI. Les premières sont attribuées par l'opérateur réseau qui nous connecte à l'Internet. Pas de formalités particulières à remplir, elles sont typiquement allouées en même temps que la connectivité est mise en place. Leur inconvénient est qu'on dépend de l'opérateur : le multi-homing va être plus difficile, et, si on change d'opérateur, on est parti pour une pénible renumérotation (RFC 5887). En outre, il peut être difficile d'obtenir la taille de préfixe souhaitée, malgré le RFC 6177 : certains opérateurs ne fileront qu'un /56, voire un /60. Les secondes adresses, les adresses PI, résolvent ces problèmes mais les obtenir nécessite d'affronter la bureaucratie des RIR. Pour les réseaux internes, notre RFC recommande un /64 pour les réseaux des utilisateurs, et un /127 pour les interconnexions point-à-point, comme dit dans le RFC 6164. IPv6 ne nécessite pas les masques de longueur variable, très communs en IPv4 pour essayer de grappigner quelques malheureuses adresses. Utiliser, par exemple, un /80 pour un Ethernet de plusieurs machines utilisateur empêcherait d'utiliser l'auto-configuration (RFC 4862) sans gain utile, et au risque de perturber les futures réorganisations du réseau.

Une fois le plan d'adressage fini, il reste à distribuer les adresses aux machines. Autrefois, on n'utiliisait que SLAAC, parce que c'était la seule possibilité. Le RFC note, avec un très grand optimisme, que DHCP est désormais une alternative mûre (en fait, bien des machines clientes n'ont pas encore de client DHCP, voilà pourquoi je trouve le RFC trop optimiste). Pour le réseau fermement administré, DHCP a l'avantage de garder trace de la correspondance entre adresse MAC et adresse IP, en un point central. Pour faire l'équivalent avec SLAAC, il faudrait un logiciel de supervision comme ndpmon cité plus haut. Autre avantage de DHCP, le serveur DHCP est l'endroit logique où faire des mises à jour dynamiques du DNS pour refléter les changements d'adresses IP. Dernier mot sur le DNS : il est déconseillé de mettre des données pour les ULA dans le DNS mondial.

La phase de Préparation et de Détermination se termine avec une analyse des outils disponibles pour l'administrateur réseaux. Il arrive en effet trop souvent que l'outil utilisé, par exemple, pour le déploiement de nouvelles versions de logiciels, ne soit finalement pas compatible IPv6. S'il a été écrit dans les dix dernières années, cela montre une grande incompétence de la part de son auteur mais ça arrive. Parmi les erreurs faites par les programmeurs, le manque de place pour la représentation des adresses, que ce soit en forme texte (RFC 5952) ou sous leur forme binaire. Ceci dit, tant que le réseau est en double-pile, certaines fonctions (par exemple l'interrogation des agents SNMP) peuvent continuer à se faire en IPv4.

S'il est logique de commencer par la phase Préparation & Détermination, le choix de la phase suivante dépend, comme on l'a vu, des caractéristiques propres à l'organisation dont on gère le réseau. Le RFC commence par la phase externe (section 3) mais ce n'est que l'ordre de présentation, pas forcément l'ordre recommandé.

Donc, la phase externe : il s'agit de migrer en IPv6 les composants du réseau visibles de l'extérieur. Il va évidemment falloir obtenir une connectivité IPv6 d'un opérateur réseau. Il est fortement recommandé d'utiliser de l'IPv6 natif, plus simple à déboguer et évitant les problèmes comme la taille de MTU. Mais, si cela n'est pas possible (dans certaines régions du monde, il est très difficile de trouver un opérateur qui sache faire de l'IPv6), il faudra se résigner à utiliser un tunnel, par exemple vers Hurricane Electric, qui fournit un service stable et pro. Si les adresses utilisées sont des adresses PA, ledit opérateur s'occupera du routage externe. Si ce sont des PI, l'opérateur pourra parfois les router pour le compte du client, et le client devra parfois faire du BGP lui-même. Évidemment, l'obtention d'un préfixe PI va dépendre des règles du RIR local. Par exemple, en Europe, le RIPE-NCC n'impose plus d'être multihomé pour avoir un préfixe PI.

Notre RFC ne traite pas des problèmes spécifiques à chaque service. Par exemple, cela aurait pu être l'occasion d'expliquer que, si annoncer une adresse IPv6 pour un serveur HTTP peut présenter un risque (pour les clients qui croient avoir une connectivité IPv6 alors qu'elle est imparfaite, cf. RFC 6556), en revanche, mettre des adresses IPv6 à ses serveurs DNS n'en présente aucun, puisque les clients DNS mettent en œuvre depuis longtemps un algorithme de test et de sélection des différents serveurs d'une zone. Cela explique sans doute que, selon le rapport ODRIF, il y ait beaucoup plus de zone sous .fr avec du DNS IPv6 que de zones avec un serveur Web IPv6. (Notez que Google fait, curieusement, le contraire : leurs sites Web sont IPv6 depuis longtemps mais leurs zones DNS non.)

Il faudra évidemment penser à la sécurité. Le RFC rappelle que, si on filtre, il ne faut surtout pas bloquer stupidement tout ICMP, indispensable à certaines fonctions d'IPv6 (voir le RFC 4890 pour une discussion détaillée, que notre RFC résume en donnant la liste minimale des types de messages ICMP qui doivent être autorisés).

Il y a des règles de sécurité générales, qui s'appliquent à IPv6 aussi bien qu'à IPv4 : attention aux applications (pensez à mettre bash à jour, par exemple...), mettez en place des mécanismes contre l'usurpation d'adresses (RFC 2827), protégez les routeurs (RFC 6192), etc. Et il y a quelques règles spécifiques d'IPv6 comme les attaques contre le cache NDP (RFC 6583) : il est recommandé de limiter le rythme des requêtes NDP et de bloquer le trafic entrant sauf vers les adresses publiques.

La supervision doit aussi faire l'objet d'une grande attention. Notre RFC recommande de surveiller séparément IPv4 et IPv6, pour être averti si un des deux protocoles défaille. Prenons l'exemple d'un serveur HTTP. Si vous testez son bon fonctionnement avec curl ou wget, vous ne serez pas prévenu si IPv4 ou IPv6 est en panne. En effet, ces deux programmes passent automatiquement aux adresses IP suivantes si l'une d'elles ne fonctionne pas. Il faut donc un test explicitement limité à IPv4 et un limité explicitement à IPv6. Avec Icinga et le check_http des monitoring plugins, cela peut être :

define service{
        use                             generic-service        
        hostgroup_name                  WebServers
        service_description             HTTP4
        check_command                   check_http!-4
        }

define service{
        use                             generic-service        
        hostgroup_name                  WebServers
        service_description             HTTP6
        check_command                   check_http!-6
        }

Il reste la phase interne (section 4) qui, rappelez-vous, peut être faite avant, après ou en même temps que la phase externe, selon les caractéristiques de votre réseau et vos choix. Il s'agit cette fois de migrer en IPv6 le réseau interne, ses applications métier, ses commutateurs, ses postes de travail... A priori, comme il y a peu de chances que toutes les applications et systèmes IPv4 soient prêts demain à migrer, le réseau interne va rester mixte pendant longtemps. Pour la connectivité, la règle habituelle s'applique : « double-pile quand on peut, tunnel quand on n'a pas le choix ». La double-pile (IPv4 et IPv6 sur tous les équipements) est la solution la plus simple pour la gestion du réseau. Le tunnel, fragile et faisant dépendre IPv6 d'IPv4, sert pour les cas où on est coincé à n'utiliser que des systèmes antédiluviens.

En interne également, on va se poser la question de la sécurité. Les gestionnaires de réseaux d'organisations sont souvent peu satisfaits des adresses IP « vie privée » du RFC 8981, car elles rendent difficile la traçabilité (« 2001:db8:1:1:c144:67bd:5559:be9f a fait des accès répétés au serveur LDAP, c'est qui, déjà, 2001:db8:1:1:c144:67bd:5559:be9f ? ») Ou bien on force l'utilisation de DHCP, ou bien on utilise un outil comme ndpmon qui garde trace des correspondances entre adresses MAC et adresses IP.

Comme pour les ARP et DHCP d'IPv4, les techniques de base du réseau IPv6 (les RA de NDP, et DHCP) n'offrent aucune sécurité et il est trivial, par exemple, d'envoyer des « RAcailles », des faux RA (RFC 6104). Il est donc très recommandé de déployer des techniques comme celles du RFC 6105. Vérifiez auprès de votre fournisseur de commutateurs qu'elles sont disponibles ! Dans le futur, les techniques issues du projet SAVI (Source Address Validation Improvement, cf. RFC 6959) aideront peut-être.

Pour assurer le bon fonctionnement du réseau interne, une des questions qui perturbent le plus les administrateurs d'un réseau IPv6 est le choix du mécanisme principal de configuration des machines terminales. SLAAC (RFC 4862) ou DHCP (RFC 8415) ? Il n'y a pas de réponse simple, chacune des deux solutions ayant ses avantages et ses inconvénients. SLAAC est certainement plus simple et plus rapide à déployer mais DHCP permet davantage de contrôle, ce qui est en général apprécié dans les réseaux d'organisations. En pratique, malheureusement, il faudra sans doute les deux car aucun des deux mécanismes ne permet de tout faire. Par exemple, DHCP n'a pas d'option pour indiquer les routeurs à utiliser (il faudra donc compter sur les RA de SLAAC, ou sur une configuration statique). Et SLAAC ne permet pas d'indiquer les serveurs NTP. Si les deux protocoles, DHCP et SLAAC, permettent désormais d'indiquer les résolveurs DNS, aucun des deux n'est encore suffisant pour tous les usages et, en pratique, il est difficile de choisir.

Autre question essentielle, la résilience face aux pannes. Cela passe par la redondance des équipements comme les routeurs. NDP permet aux machines de maintenir une liste de routeurs disponibles et de passer à un autre en cas de panne (RFC 4861, section 7.3). Par défaut, la bascule se fait en 38 secondes (RFC 4861, section 10), ce qui est bien trop long dans beaucoup de cas. Il est donc souvent préférable d'utiliser des techniques comme VRRP (RFC 5798).

Autre problème à regarder de près pendant la phase Interne, les machines terminales, de l'ordinateur de bureau à la machine à café connectée, en passant par l'imprimante et la caméra de vidéo-surveillance. Les ordinateurs ont quasiment tous IPv6 aujourd'hui (mais pas forcément activé par défaut). Mais certaines fonctions peuvent manquer (adresses privées du RFC 8981, client DHCPv6, client RA qui comprend les résolveurs DNS du RFC 8106...) Il est également possible que des algorithmes comme la bonne sélection de l'adresse source (RFC 6724) ou les globes oculaires heureux (RFC 6555) soient manquants ou désactivés. Or, sans eux, l'utilisation d'un système double-pile (IPv4 et IPv6) est bien plus pénible. Il faut donc s'assurer de bien connaître le comportement par défaut des systèmes qu'on utilise sur les réseaux locaux.

Quant aux autres engins, non considérés comme des ordinateurs, il est malheureusement fréquent, en 2014, qu'ils n'aient toujours pas IPv6 (alors même qu'ils sont souvent bâtis sur des systèmes, comme Linux, qui ont IPv6 depuis longtemps). Enfin, le dernier gros problème de la phase interne sera les systèmes utilisés dans l'infrastructure de l'organisation (le système de téléphonie, par exemple) qui ne sont pas toujours prêts pour IPv6. Là encore, il est essentiel que les clients se fassent entendre et tapent sérieusement sur les vendeurs les plus attardés.

On a parlé à plusieurs reprises de réseaux double-pile car c'est l'approche la plus réaliste aujourd'hui. Pourra-t-on un jour simplifier sérieusement le réseau en supprimant enfin le bon vieil IPv4 et en ayant à nouveau un réseau mono-protocole, entièrement IPv6 ? C'est bien le but à long terme, dit avec optimisme la section 5 de notre RFC. Atteindre ce but ne nécessite même pas que tout l'Internet soit entièrement passé en IPv6. Il existe des techniques permettant aux machines d'un réseau purement IPv6 de parler avec les derniers survivants de l'ère IPv4 (cf. par exemple RFC 6144). Au début, une bonne partie du trafic devra passer par ces relais ou des traducteurs NAT64. Mais au fur et à mesure que le reste de l'Internet devient accessible en IPv6 (RFC 6883), ces techniques deviennent naturellement de moins en moins utilisées.

Tous les conseils ci-dessus étaient génériques, s'appliquant à toutes sortes d'organisations. La section 6 traite maintenant des cas particuliers de certaines organisations. Par exemple, les gens dont le métier est de distribuer du contenu sur l'Internet (par exemple via un CDN) ont intérêt à lire les RFC 6883 et RFC 6589.

Un autre cas particulier, qui permettra de finir sur une note optimiste, est celui des campus universitaires. Ils sont aujourd'hui très souvent passés à IPv6. Les NREN ont en général IPv6 depuis le début des années 2000. L'intérêt pour les techniques nouvelles, et la mission de recherche et d'éducation, faisait des universités l'endroit logique pour les premiers déploiements. C'est évidemment souvent le département d'Informatique qui était le premier à migrer ses machines et ses services vers IPv6. Le réseau Eduroam est également accessible avec IPv6 puisqu'il repose sur 802.1x (qui est indifférent à la version du protocole IP utilisée) et non pas sur ces horribles portails captifs (dont un des inconvénients est d'être limité à un protocole).

La grande majorité des universités qui ont déployé IPv6 n'utilise pas d'ULA, ni traduction d'adresses. Presque toujours, elles utilisent des adresses PA fournies par le NREN.


Téléchargez le RFC 7381


L'article seul

RFC 7378: Trustworthy Location

Date de publication du RFC : Décembre 2014
Auteur(s) du RFC : H. Tschofenig (Independent), H. Schulzrinne (Columbia University), B. Aboba (Microsoft )
Pour information
Réalisé dans le cadre du groupe de travail IETF ecrit
Première rédaction de cet article le 18 décembre 2014


Il existe des applications de communication (de téléphonie, par exemple), qui indiquent la localisation de l'appelant, et cette localisation est cruciale lorsque il s'agit d'appels d'urgence, par exemple aux pompiers ou à la police, ou, moins dramatique, d'assistance routière (« ma voiture est en panne et je ne sais pas exactement où je suis », comme cela m'est arrivé sur la N 1 ce mois d'août). Ce nouveau RFC décrit le problème de la sécurité et de la fiabilité de la localisation, ainsi que des solutions pour améliorer cette sécurité et cette fiabilité.

Pour envoyer sa localisation à son correspondant, il y a deux sous-problèmes : 1) déterminer la localisation 2) la transmettre de manière sûre. Pour la téléphonie traditionnelle, la localisation est déterminée par le récepteur à partir du numéro de téléphone présenté. Cela veut dire notamment qu'un faux numéro peut entraîner une mauvaise localisation (cf. RFC 7340 et les autres documents du groupe STIR). Il y a plusieurs mécanismes pour s'assurer du numéro de téléphone comme le rappel (qui permet aussi de confirmer l'urgence, cf. RFC 7090). Mais quand l'appelant est mobile, même lorsqu'on est sûr du numéro de téléphone présenté, le problème n'est pas résolu. Ce RFC se focalise sur les cas où le numéro de téléphone de l'appelant est raisonnablement authentifié mais où il reste des doutes sur la localisation physique de la cible (oui, c'est comme cela qu'on désigne la personne ou l'objet dont on cherche à connaître la localisation). Le mode normal d'obtention de la localisation est de faire appel à un LIS (Location Information Server) qui, connaissant les caractéristiques du réseau utilisé, va l'indiquer à son client. Un malveillant peut faire en sorte qu'une mauvaise localisation soit indiquée de trois façons :

  • Changement d'endroit (place shifting), lorsque l'attaquant arrive à placer un faux objet PIDF-LO ( Presence Information Data Format Location Object, voir le RFC 4119). Dans certains cas, il y a une limite à la triche, par exemple l'attaquant peut indiquer une fausse position mais qui doit rester dans la zone couverte par un relais donné.
  • Changement de moment (time shifting), où l'attaquant réussit à ré-utiliser une information de localisation qui était vraie dans le passé, mais ne l'est plus.
  • Vol de localisation (location theft), lorsque on présente un objet de localisation qui est correct et valide mais concerne une autre personne.

La première façon est la plus puissante, mais n'est pas toujours accessible aux attaquants.

Pour comprendre complètement le problème, il faut aussi connaître l'architecture des services d'urgence (section 1.2) sur l'Internet. Son cadre général figure dans le RFC 6443. Les bonnes pratiques à suivre pour faire un service d'urgence qui marche sont dans le RFC 6881. Ces services d'urgence nécessitent des informations sur l'appelant (comme sa localisation, qu'il n'a pas toujours le temps ou la possibilité de donner, lorsqu'il est en situation d'urgence). Lorsqu'un service d'urgence reçoit l'appel, il doit donc déterminer la localisation, en déduire à qui transmettre l'appel (ce qu'on nomme un PSAP pour Public Safety Answering Point) et router l'appel (en SIP, transmettre un INVITE, contenant la localisation, cf. RFC 6442).

Le problème de tout service d'urgence, ce sont les faux appels. Ils existent depuis bien avant l'Internet. Comme ils détournent les services d'urgence des vrais appels, ils peuvent littéralement tuer, si quelqu'un qui avait besoin d'un secours urgent ne l'obtient pas car tous les services sont occupés à traiter des canulars. (Il est recommandé de consulter le document EENA sur les faux appels.) Parmi les faux appels, l'un est particulièrement dangereux, le swatting. Il doit son nom au SWAT états-unien et consiste à appeler les services de police en prétendant qu'il y a une situation d'extrême danger nécessitant de faire appel à la force (prise d'otages, par exemple). Cet appel amènera à un déploiement policier intense, style cow-boys, chez la victime. Le FBI a documenté ce phénomène. De telles actions étant sévèrement punies, les attaquants vont toujours essayer de cacher leur identité, par exemple en indiquant un faux numéro de téléphone, si leur fournisseur de services téléphoniques le permet. Plusieurs études ont montré que les faux appels étaient particulièrement nombreux si on ne pouvait pas authentifier l'appelant (cf. « Emergency services seek SIM-less calls block » ou « Rapper makes thousands of prank 999 emergency calls to UK police »).

Place maintenant aux menaces sur la localisation. Le RFC 6280 décrit une architecture pour des services de localisation intégrant la notion de vie privée. D'autres RFC décrivent les exigences de tout service de localisation (RFC 3693), les menaces contre eux (RFC 3694), le cas particulier des services d'urgence (RFC 5069), et l'usurpation des numéros de téléphone (RFC 7375).

Notre RFC s'attaque aux menaces en distinguant d'abord trois classes d'attaquants :

  • Les attaquants externes, ne disposant d'aucun privilège particulier,
  • Les attaquants situés dans l'infrastructure de téléphonie, et qui en contrôlent une partie, par exemple le LIS (Location Information Server),
  • Les attaquants situés sur la machine de l'utilisateur.

Évidemment, les deux dernières classes peuvent faire des dégats plus facilement.

Outre la tricherie sur son numéro de téléphone, un attaquant peut aussi tricher sur sa localisation, soit en en inventant une de toutes pièces, soit en « rejouant » une localisation authentique, mais dans le passé ou encore en « volant » une localisation authentique mais d'un autre utilisateur. Ce RFC se focalise sur ces risques liés à la localisation mais la tricherie sur l'identité n'est pas à oublier. En effet, l'auteur des faux appels cherche en général à éviter les représailles, et donc à dissimuler son identité, par exemple en appelant d'une cabine téléphonique.

Maintenant, que peut-on faire pour limiter les risques (section 3) ? Il y a trois mécanismes principaux :

  • Signer les informations de localisation (les fichiers PIDF-LO décrits dans le RFC 4119) au départ de l'appel. Aucune norme n'existe pour cela.
  • Obtention de la localisation, non pas via l'émetteur mais depuis le récepteur, via le RFC 6753, en utilisant le protocole HELD (HTTP-Enabled Location Delivery) RFC 5985. Dans ce cas, le destinataire de l'appel, le PSAP (le service d'urgence), contacte le serveur de localisation, le LIS.
  • Obtention de la localisation, non pas via l'émetteur mais via le réseau (plus exactement un mandataire dans le réseau), en utilisant le RFC 6442. Cette dernière technique, elle, impose la participation du FAI (qui connait la localisation physique de ses abonnés, même si c'est avec une précision limitée, surtout pour les mobiles).

Une fois obtenue la localisation, encore faut-il en évaluer la fiabilité. Ce niveau de fiabilité est une information cruciale pour le processus de décision. Par exemple, un appel d'urgence où la localisation est marquée comme « absolument sûre » peut être traité instantanément, alors qu'on passera un peu plus de temps à vérifier un appel depuis une localisation douteuse (section 4). La localisation dépend d'un certain nombre de partenaires, et cette fiabilité va donc varier selon la confiance qu'on accorde à ces partenaires. Par exemple, dans le deuxième mécanisme cité plus haut (le PSAP interroge le LIS), si le LIS est connu, de confiance, et qu'on l'utilise depuis longtemps avec succès, on se fiera facilement à lui. À l'inverse, dans le cas du troisième mécanisme (interrogation d'un mandataire géré par le FAI), s'il y a eu peu d'appels d'urgence depuis ce FAI et qu'on n'a jamais pu vérifier la fiabilité de ses informations, la localisation sera marquée comme douteuse.

Pour déterminer la validité des informations de localisation, on peut aussi faire des vérifications croisées. Lors d'un appel SIP, une fois qu'on a reçu une localisation physique de l'émetteur, on peut comparer avec la localisation qu'indique l'adresse IP dans les champs Via: ou Contact:, ou celle dans les paquets de données. Si les deux localisations coïncident, on est rassuré. Sinon, on note la localisation comme étant douteuse.

La section 5 résume tous les problèmes de sécurité liés à la localisation fiable. Il faut notamment se rappeler que cette fiabilité peut être en opposition avec d'autres critères de sécurité, comme la protection de la vie privée (la section 6 détaille ce problème). D'autre part, toutes les mesures envisagées ne sont guère efficaces face au problème spécifique de l'attaque par déni de service : un attaquant qui effectuerait un très grand nombre d'appels pourrait toujours perturber le PSAP (le service d'urgence), ne serait-ce que via les vérifications faites. Effectuer un tel nombre d'appels est évidemment plus facile avec la téléphonie sur IP qu'avec le téléphone traditionnel. Et cela permet plus facilement de franchir les frontières, pour attaquer les services d'urgence d'un autre pays.

Ces appels en masse peuvent être faits par des zombies mais aussi par du code non sécurisé, par exemple un malware JavaScript, chargé automatiquement par le navigateur Web, et qui ferait des appels via WebRTC (RFC 8825). Il peut donc être prudent d'empêcher ce genre de code non sécurisé d'appeler les services d'urgence.

Pour analyser la résistance d'un service d'urgence aux attaques par déni de service, il faut séparer les cas des trois ressources finies dont disposent ces services : l'infrastructure informatique (réseaux et serveurs), les humains qui répondent à l'appel, et les services de secours eux-mêmes (police, pompiers, etc). Par exemple, si le réseau marche bien et que les preneurs d'appel répondent bien, mais qu'il n'y a plus aucun pompier disponible car tous sont partis combattre des incendies imaginaires, l'attaque par déni de service a malheureusement réussi. Les contre-mesures doivent donc veiller à traiter les cas d'abus de ces trois ressources. Par exemple, faire des vérifications automatiques poussées sur la vraisemblance de l'information de localisation va stresser la première ressource (l'infrastructure informatique) mais cela préservera les deux autres (qui sont souvent limitées : on n'a pas des ressources humaines abondantes et qualifiées).

Apparemment, il n'existe pas encore de mise en œuvre de ce système.


Téléchargez le RFC 7378


L'article seul

RFC 7377: IMAP4 Multimailbox SEARCH Extension

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : B. Leiba (Huawei Technologies), A. Melnikov (Isode)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 14 octobre 2014


Nouvelle extension IMAP normalisée, pour effectuer une recherche dans plusieurs boîtes aux lettres simultanément, avec la nouvelle commande ESEARCH. Proposée initialement par le RFC 6237, à titre expérimental, cette extension accède désormais au statut de norme.

Par défaut, une recherche IMAP (commande SEARCH, RFC 3501, sections 6.4.4 et 7.2.5, puis étendue par les RFC 4466 et RFC 4731) ne cherche que dans la boîte aux lettres courante. Si on n'est pas sûr de la boîte où se trouve le ou les messages intéressants, et qu'on veut chercher dans plusieurs boîtes, la seule solution est de faire une boucle, effectuant séquentiellement des SELECT pour changer de boîte et un SEARCH à chaque fois. Ces commandes ne peuvent pas être exécutées en parallèle car il n'y a pas de moyen de distinguer leurs résultats (les réponses SEARCH n'indiquent pas quelle était la boîte). La nouvelle commande permet au serveur de faire les recherches en parallèle, s'il le peut, et évite des allers-retours entre client et serveur.

Donc, la nouvelle commande ESEARCH (à ne pas confondre avec la capacité ESEARCH du RFC 4731, même si les deux RFC ont des points communs, comme le format des réponses), présentée en section 2. Sa disponibilité est annoncée par la capacité MULTISEARCH dans la bannière du serveur IMAP. (Cette capacité figure dans le registre IANA.) Voici un exemple où on cherche des messages parlant du Tchad dans les boîtes folder1 et celles sous folder2 (C = client, et S serveur IMAP) :

C: mytag ESEARCH IN (mailboxes "folder1" subtree-one "folder2") subject "chad"
S: * ESEARCH (TAG "mytag" MAILBOX "folder1" UIDVALIDITY 1) UID ALL 3001:3004,3788
S: * ESEARCH (TAG "mytag" MAILBOX "folder2/salmon" UIDVALIDITY 1111111) UID ALL 50003,50006,50009,50012
S: mytag OK done

La syntaxe pour indiquer les boîtes aux lettres où on cherche est celle de la section 6 du RFC 5465, avec l'ajout de subtree-one (utilisé ci-dessus pour folder2) qui, contrairement à subtree, s'arrête au premier niveau (donc la boîte folder2/tuna/red ne serait pas cherchée). Avertissement du RFC au programmeur : subtree peut aller très loin (pensez à une hiérarchie de boîte aux lettres mise en œuvre avec un système de fichiers hiérarchiques, et des liens symboliques qui vont se promener ailleurs) et il faut donc prêter attention au risque d'écroulement du serveur. Voir aussi la section 2.4, qui autorise le serveur à refuser les recherches trop gourmandes, avec le code LIMIT du RFC 5530, et la section 5, sur la sécurité, qui note que cette extension multi-boîtes peut être dangereuse pour le serveur. Un client méchant ou maladroit peut demander un gros travail au serveur, avec juste une commande.

Le RFC note que le mot-clé personal est le moyen le plus pratique de fouiller dans toutes les boîtes de l'utilisateur. Si celui-ci désigne au contraire des boîtes par leur nom, et que le serveur gère les ACL du RFC 4314, il faut avoir le droit de lecture sur ces boîtes (et celui de découverte, si les boîtes ne sont pas explicitement nommées, par exemple si on utilise subtree). Pas question de retourner des résultats pour des boîtes que l'utilisateur n'est pas censé lire.

À noter qu'un serveur qui accepte les recherches floues du RFC 6203 peut les accepter également pour les recherches dans des boîtes multiples.

La réponse est décrite dans la section 2.1 : elle consiste en lignes ESEARCH (cf. RFC 4731). Les messages doivent être identifiés par leur UID (RFC 3501, section 2.3.1.1) comme ci-dessus, pas par leurs numéros (qui n'ont de sens que pour une boîte sélectionnée). Le ALL (RFC 4731, section 3.1), indique qu'on retourne la totalité des messages qui correspondent au critère de recherche. Pour le premier dossier, le folder1, ces messages sont ceux d'UID 3001 à 3004 (une séquence, définie dans la section 9 du RFC 3501) et le message d'UID 3788.

La section 3 du RFC donne un exemple plus complexe, avec deux recherches multi-boîtes en parallèle, chacune identifiée par une étiquette différente :

C: tag1 ESEARCH IN (mailboxes "folder1" subtree "folder2") unseen
C: tag2 ESEARCH IN (mailboxes "folder1" subtree-one "folder2") subject "chad"
S: * ESEARCH (TAG "tag1" MAILBOX "folder1" UIDVALIDITY 1) UID ALL 4001,4003,4005,4007,4009
S: * ESEARCH (TAG "tag2" MAILBOX "folder1" UIDVALIDITY 1) UID ALL 3001:3004,3788
S: * ESEARCH (TAG "tag1" MAILBOX "folder2/banana" UIDVALIDITY 503) UID ALL 3002,4004
S: * ESEARCH (TAG "tag1" MAILBOX "folder2/peach" UIDVALIDITY 3) UID ALL 921691
S: tag1 OK done
S: * ESEARCH (TAG "tag2" MAILBOX "folder2/salmon" UIDVALIDITY 1111111) UID ALL 50003,50006,50009,50012
S: tag2 OK done

Des implémentations de cette norme ? Il y en a apparemment une, en logiciel non-libre, chez Oracle. Cette extension semble rare (et cela a été noté dans les débats à l'IETF : méritait-elle vraiment d'avancer sur le chemin des normes ?). J'ai testé quelques serveurs et je n'ai pas vu la capacité MULTISEARCH dans un Zimbra récent, ou dans la version de Courier actuellement chez Debian. Rien non plus dans des services en ligne comme laposte.net ou Gmail.

Depuis le RFC 6237, qui décrivait cette extension pour la première fois, peu de changements, les principaux sont (section 7) :

  • Passage au statut de norme,
  • Recherches floues,
  • Et quelques autres détails.

Téléchargez le RFC 7377


L'article seul

RFC 7375: Secure Telephone Identity Threat Model

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : J. Peterson (NeuStar)
Pour information
Réalisé dans le cadre du groupe de travail IETF stir
Première rédaction de cet article le 26 octobre 2014


Elle est loin, l'époque où l'Internet et le téléphone étaient deux mondes complètement séparés. Aujourd'hui, le téléphone n'est qu'une application parmi toutes celles tournant sur l'Internet. et les problèmes de sécurité du téléphone sont donc des problèmes Internet. D'où ce RFC qui décrit les menaces d'usurpation d'identité qui planent sur la téléphonie sur IP (cf. SIP, RFC 3261).

La plupart des attaques utilisant le téléphone commencent en effet par un mensonge sur le numéro d'appel : l'attaquant va se débrouiller pour présenter un numéro d'appel qui n'est pas le sien. Souvent, en effet, le numéro de l'appelant est utilisé pour mettre en œuvre une politique de sécurité : on décroche parce qu'on connait le numéro, ou bien on prend au sérieux un appel d'urgence parce qu'on sait qu'on pourra retrouver l'éventuel mauvais plaisant via son numéro ou encore on donne accès à un répondeur en n'utilisant pour toute authentification que le numéro d'appel. Bien sûr, quelqu'un qui ne veut pas révéler son numéro peut toujours ne pas le présenter. Mais beaucoup de correspondants ne décrocheront pas s'ils reçoivent un appel sans numéro. C'est pour cela que les spammeurs du téléphone préfèrent présenter un numéro, n'importe lequel. D'où la création du groupe de travail STIR de l'IETF, groupe qui est chargé de travailler sur ce problème (une description du problème figure dans le RFC 7340). Le but de STIR est de faire en sorte que, quand on voit un numéro entrant s'afficher, on soit raisonnablement sûr que ce soit bien un numéro que l'appelant est autorisé à utiliser.

On ne peut pas traiter le problème à la source : l'attaquant contrôle son téléphone et peut lui faire faire ce qu'il veut. Il faut donc traiter le problème dans le réseau téléphonique, ou bien à l'arrivée, et pouvoir distinguer les numéros autorisés des autres. Une fois qu'on aura cette distinction, on pourra appliquer les politiques de sécurité de son choix (par exemple ne pas décrocher si le numéro présenté n'est pas vu comme sérieusement authentifié).

Ce RFC se focalise sur la triche lors de l'appel. Une fois la connexion établie, d'autres attaques sont possibles (écouter le trafic en cours de route, rediriger les paquets IP vers une autre destination ou, tout simplement utiliser les nombreuses possibilités de SIP pour transférer un appel) mais elles nécessitent typiquement plus de moyens que l'usurpation de numéro, qui peut souvent être faite en n'ayant pas d'autres outils que son téléphone.

Autre piège qui n'est pas traité par le groupe STIR : des téléphones ont des fonctions de carnet d'adresses ou d'annuaire et peuvent donc afficher, à la place du numéro d'appel, le nom de la personne appelante. Cela permet d'autres attaques : par exemple, si l'annuaire n'est pas bien sécurisé, on peut imaginer que l'attaquant glisse un nom d'apparence légitime pour son numéro d'appel, et que le destinataire sera alors trompé, sans qu'il y ait eu usurpation de numéro. C'est une vraie possibilité mais elle nécessite des solutions très différentes (sécurisation des carnets d'adresse et des annuaires).

La section 2 de notre RFC décrit les différents acteurs. Il y a les utilisateurs, aux extrémités, avec leurs téléphones, simples engins sans trop de complications ou au contraire smartphones très riches. Il y a les intermédiaires, par exemple les relais SIP (on ne fait pas de la téléphonie en direct, en général, ne serait-ce que parce que le destinataire n'est pas forcément joignable en ce moment), et il y a les attaquants. Les intermédiaires peuvent modifier les caractéristiques de l'appel en cours de route, par exemple en jetant le numéro d'appel ou en substituant un autre. Ainsi, une passerelle entre la téléphonie IP et le PSTN pourra substituer au numéro indiqué dans un paquet IP son propre numéro, pour une meilleure traçabilité. Quant aux attaquants, on suppose qu'ils ont un téléphone (!) et peuvent passer un appel depuis le lieu de leur choix. Comme indiqué plus haut, ils peuvent indiquer un faux numéro (les téléphones traditionnels ne permettaient pas cela mais c'est possible avec les engins modernes). Pire, ayant accès à l'Internet, on suppose qu'ils peuvent envoyer des paquets IP quelconques, sans passer par un téléphone ou un softphone. Enfin, notre RFC ne prend délibérement pas en compte le risque d'une trahison ou d'un piratage des intermédiaires. Certes, l'attaquant qui contrôlerait les serveurs intermédiaires pourrait faire beaucoup de dégâts mais ce n'est pas ce qui se fait aujourd'hui, dans la grande majorité des cas d'usurpation de numéro.

Après les acteurs, place aux attaques (section 3). L'attaquant peut chercher à usurper un numéro de téléphone donné (par exemple pour se faire passer pour une personne précise) ou bien il peut juste chercher à usurper n'importe quel numéro de téléphone valide (pour ne pas exposer le sien, qui permettrait de remonter jusqu'à lui). Un exemple du premier cas est celui de l'accès à une boîte vocale, lorsque l'authentification se fait uniquement sur la base du numéro présenté. Certes, il serait sans doute préférable d'utiliser (en plus, ou à la place du numéro présenté) une authentification plus forte mais, en pratique, un certain nombre de systèmes n'authentifient qu'avec le numéro appelant, surtout les services commerciaux comme la vidéoconférence où on ne souhaite pas trop embêter le client. Ajouter une authentification par, par exemple, un code numérique à taper, compliquerait les choses pour l'utilisateur. Si le système appelé pouvait savoir si le numéro de téléphone a été correctement authentifié, il pourrait, par exemple, n'imposer la frappe du code numérique que dans le cas où le numéro n'est pas fiable. Comme ces services sont souvent appelés de manière répétitive, on peut aussi compter sur l'historique, par exemple savoir s'il est normal ou pas que tel numéro entrant soit authentifié.

Et le spam, plaie du téléphone comme il l'est du courrier électronique ? Comment empêcher les appels automatiques (robocallers) ? Pour éviter les plaintes, et qu'on remonte jusqu'à eux, les spammeurs ne veulent pas présenter leur vrai numéro. Par exemple, Bouygues Telecom m'appele toujours depuis une ligne qui ne présente pas le numéro d'appelant. Résultat, je ne décroche plus pour de tels appels. Les spammeurs ont donc intérêt à présenter un numéro, mais qui ne soit pas le leur. Leur tâche est donc plus facile que dans le cas précédent, où ils devaient usurper un numéro précis. Par contre, cette fois, l'appelé ne peut pas compter sur l'historique pour évaluer l'appel.

Un des problèmes de l'authentification des appels entrants est le manque de temps. Si c'est une machine qui est appelée (comme dans le cas précédent, celui du répondeur), on peut la faire patienter, le temps qu'on vérifie. Si c'est un humain qu'il faut contacter, c'est plus délicat. Faut-il lui signaler un appel qu'on n'a pas encore eu le temps d'authentifier ? Cette nécessité d'agir en temps réel peut rendre certaines techniques (par exemple de longs calculs cryptographiques) difficiles à faire accepter. Les SMS n'ont pas ce problème : on peut retarder leur distribution sans conséquences sérieuses.

La téléphone connait aussi des attaques par déni de service. Un attaquant peut appeler simplement pour épuiser des ressources limitées, et déguiser alors son numéro pour éviter des représailles (ou tout simplement pour éviter d'être mis en liste noire). Il peut être capable d'utiliser plusieurs fournisseurs et plusieurs téléphones, pour faire une dDoS. Comme le robocaller, l'attaquant qui vise un déni de service n'a pas besoin d'usurper un numéro de téléphone particulier. Tout numéro qui n'est pas le sien conviendra (il voudra probablement le faire varier rapidement, pour éviter les contre-mesures fondées sur des listes noires). Une exception est le cas de l'attaque par réflexion, où l'attaquant veut faire croire à la culpabilité d'un tiers, et usurpe donc le numéro de ce tiers.

Les contre-mesures sont donc les mêmes que pour les appels automatiques des spammeurs : vérifier que les numéros présentés sont des numéros possibles (cela bloque les attaques les moins sophistiquées, celles où l'attaquant met n'importe quoi au hasard), et traiter différemment les appels où on peut être sûr que les numéros sont légitimes (dans le cas d'une attaque, jeter systématiquement les numéros non garantis, par exemple). Un tel traitement différencié n'est toutefois pas acceptable pour les appels d'urgence, qui ont l'obligation de répondre à tout.

Et, pour finir le RFC, les scénarios d'attaque possibles (section 4). Si l'attaquant et sa victime (l'appelant et l'appelé) sont tous les deux en SIP, l'attaquant n'a qu'à mettre le numéro qu'il veut dans le champ From: de la requête SIP INVITE. Si les deux sont au contraires connectés au PSTN (la téléphonie traditionnelle), l'attaquant doit avoir le contrôle du PABX qu'utilise son téléphone. Le PABX envoie une requête Q.931 SETUP avec le numéro de son choix qui va se retrouver dans l'appel SS7, champ Calling Party Number. Et si l'attaquant est en IP et la victime sur le PSTN ? Comme dans le premier cas, il met le numéro qu'il veut dans le message SIP et la passerelle IP<->PSTN va le transmettre à l'appelé. Arrivé là, vous vous demandez sans doute quelles sont les solutions possibles à ces attaques, qui semblent si simples à faire ? Mais ce RFC ne fait que l'analyse des menaces, les solutions seront dans des RFC futurs.


Téléchargez le RFC 7375


L'article seul

RFC 7372: Email Authentication Status Codes

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 17 septembre 2014


Il existe désormais plusieurs techniques d'authentification du courrier électronique, comme SPF ou DKIM. Elles permettent à un serveur de messagerie, s'il le désire, d'accepter ou de rejeter le courrier entrant s'il échoue à ces tests d'authentification. Mais il n'existait pas jusqu'à présent de moyen standard de prévenir l'expéditeur, lors de la session SMTP, de la raison de ce rejet. C'est désormais fait, avec ce nouveau RFC, qui permet de renvoyer des codes de retour SMTP explicites, si on veut.

J'ai bien dit « si on veut » car tous les administrateurs de serveurs ne sont pas d'accord pour indiquer à l'expéditeur les raisons exactes du rejet. Après tout, si l'authentification échoue, c'est peut-être que l'expéditeur était un méchant, un spammeur, par exemple, et, dans ce cas, on ne souhaite pas lui donner de l'information. L'utilisation de ces nouveaux codes de retour est donc optionnelle.

Ces codes sont de type « codes étendus », normalisés par le RFC 3463 et dotés d'un registre IANA depuis le RFC 5248. Les codes « améliorés » du RFC 3463 comportent trois nombres, la classe (2 : tout va bien, 4 : erreur temporaire, 5 : erreur définitive, etc), le second le sujet (6 : problème avec le contenu du message, 7 : problème avec la politique de sécurité, etc) et le troisième le détail. Ils s'écrivent avec un point comme séparateur, contrairement aux codes de retour traditionnels, eux aussi à trois chiffres, mais sans séparateur.

La section 3 du RFC liste ces nouveaux codes. Ils figurent tous dans le registre IANA. Dans quasiment tous les cas, le code de base (non étendu) associé sera 550, le code étendu donnant les détails.

D'abord, pour DKIM (RFC 6376). Il y a deux cas de succès, passing, où la signature DKIM est valide et acceptable, où non seulement la signature est valide mais où elle correspond aux règles locales du serveur récepteur (qui, par exemple, impose que tel ou tel en-tête soit couvert par la signature). Un cas particulier de acceptable (qui a son code spécifique) est celui où le serveur de réception impose que l'auteur du message (dans le champ From:) corresponde à une des identités DKIM utilisées pour signer le message. C'est donc la vérification la plus stricte.

Les codes sont respectivement :

  • X.7.20 (où X indique la classe, qui sera 5 Permanent Failure dans la plupart des cas) : aucune signature DKIM passing.
  • X.7.21 : aucune signature DKIM acceptable. Au moins une signature est valide (passing), autrement on utiliserait X.7.20 mais elle ne correspond pas aux exigences locales (rappelez-vous que la norme DKIM laisse une grande latitude à l'émetteur sur ce qu'il signe et notamment sur l'identité utilisée, voir entre autres la section 1.2 du RFC 6376).
  • X.7.22 : il y a au moins une signature DKIM passing mais elle n'est pas acceptable car l'identité utilisée n'est pas celle contenue dans le champ From: (un cas particulier de X.7.21, donc).

Notez que DKIM permet d'avoir des signatures valides et des invalides sur le même message. En effet, certains logiciels modifient le message en route, invalidant les signatures. Le principe de DKIM est donc qu'on ignore les signatures invalides. On n'envoie les codes de retour indiquant un rejet que lorsqu'on n'a aucune signature valable. À noter aussi que tous ces codes indiquent que le serveur SMTP de réception s'est assis sur l'avis de la section 6.3 (et non pas 6.1 contrairement à ce que dit le nouveau RFC) du RFC 6376. Cet avis dit en effet « In general, modules that consume DKIM verification output SHOULD NOT determine message acceptability based solely on a lack of any signature or on an unverifiable signature; such rejection would cause severe interoperability problems. » Le but est d'augmenter la robustesse de DKIM face à des intermédiaires qui massacreraient des signatures. Mais, bon, il y a des gens qui rejettent les messages juste pour une absence de signature valide, donc, autant leur fournir un code de retour adapté. (Voir aussi la section 4 qui discute ce point et insiste bien sur le fait que cela ne signifie pas une approbation de ce rejet violent par les auteurs du RFC. Cette question a été une des plus chaudement discutées dans le groupe de travail IETF.)

Ensuite, il y a des codes pour SPF (RFC 7208) :

  • X.7.23 : message invalide selon SPF,
  • X.7.24 : pas forcément invalide mais l'évaluation de SPF a entraîné une erreur (problème DNS, par exemple).

Voici à quoi pourrait ressembler une session SMTP avec rejet SPF :

% telnet mail.example.com smtp
220 myserver.example.com ESMTP Postfix (LibreBSD)
...
MAIL FROM:<me@foobar.fr>
550 5.7.23 Your server is not authorized to send mail from foobar.fr

Enfin, il y a un code pour le test dit reverse DNS décrit dans la section 3 du RFC 8601, qui consiste à traduire l'adresse IP de l'émetteur SMTP en nom(s) puis ce(s) nom(s) en adresses IP pour voir si l'adresse originale se trouve dans cet ensemble d'adresses. Il peut conduire au code SMTP X.7.25 en cas d'échec.

La section 4 de notre RFC mentionne un certain nombre de considérations générales sur ces codes de retour. Par exemple, les autres techniques d'authentification développées ultérieurement devront ajouter leur propre code SMTP étendu, sur le modèle de ceux-ci.

Autre point, SMTP ne permet de renvoyer qu'un seul code de retour étendu. Si on a plusieurs techniques d'authentification qui ont échoué, on peut toujours utiliser le code général X.7.26 qui indique que plusieurs tests ont échoué. Mais si on a une erreur d'authentification et une erreur d'un autre type, il n'y a pas de solution propre : il faut choisir une des causes de rejet et renvoyer le code correspondant.

Et la section 5, sur la sécurité, rappelle que l'utilisation de ces codes de retour étendus est facultative. Si vous ne voulez pas révéler à vos correspondants pourquoi vous rejetez leurs messages, vous êtes libre.


Téléchargez le RFC 7372


L'article seul

RFC 7368: IPv6 Home Networking Architecture Principles

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : T. Chown (University of Southampton), J. Arkko (Ericsson), A. Brandt (Sigma Designs), O. Troan (Cisco Systems), J. Weil (Time Warner Cable)
Pour information
Réalisé dans le cadre du groupe de travail IETF homenet
Première rédaction de cet article le 1 novembre 2014


Le projet Homenet de l'IETF est très ambitieux. Il s'agit de définir une architecture et des protocoles pour des réseaux IPv6 à la maison. Non seulement tout doit marcher « tout seul » (on ne peut pas demander à M. Michu de lire le RFC, ou même la documentation) mais en outre le groupe de travail Homenet prévoit deux innovations principales par rapport aux réseaux IPv4 des maisons actuelles : un inter-réseau à la maison (plusieurs réseaux séparés par des routeurs) et pas de NAT, la plaie des communications actuelles. Ce premier RFC du groupe de travail Homenet décrit l'architecture générale envisagée.

La tendance générale dans les maisons modernes est à la prolifération des équipements électroniques. Si toutes les maisons ne connaissent pas encore la situation de la célèbre Maison qui tweete, il n'y a pas de doute que les vingt dernières années ont vu un changement de modèle avec le passage de « à la maison, un ordinateur et un seul, connecté au réseau » à « deux ou trois dizaines d'équipements électroniques dont beaucoup sont connectés au réseau, au moins de temps en temps ». Entre les smartphones, les compteurs intelligents, l'Arduino qui arrose les plantes, la box, le PC du joueur de jeu vidéo, les tablettes de tout le monde, et la télé connectée, on atteint vite un nombre de machines connectées bien supérieur à la totalité de l'Arpanet du début. Il y a bien longtemps qu'il n'y a plus assez d'adresses IPv4 pour tout ce monde. L'architecture typique aujourd'hui (pas réellement documentée, car jamais vraiment réfléchie et étudiée) est d'un réseau à plat (pas de séparation des machines, tout le monde est sur la même couche 2), avec numérotation des équipements avec les adresses IPv4 privées du RFC 1918 et connexion à l'Internet via un unique FAI. Homenet vise au contraire des réseaux IPv6 (IPv4 peut continuer à tourner sur un réseau Homenet mais à côté, car Homenet ne prévoit rien de particulier pour lui), non gérés (M. Michu...) et connectés à plusieurs FAI, pour la résilience, pour compenser les faiblesses ou manques d'un FAI par un autre (bridage de YouTube, par exemple...) ou tout simplement parce que des tas d'offres de connectivité sont disponibles (pensez au smartphone qui a le choix entre la 3G et le WiFi).

Homenet ne sera pas un protocole unique. L'idée du projet est d'analyser ce qui existe, de réutiliser autant que possible les protocoles existants et testés, et d'identifier ce qui manque, pour pouvoir ensuite l'ajouter. Homenet se focalise sur la couche 3 et quelques services indispensables, comme la résolution de noms. Les protocoles physiques sous-jacents sont tous acceptés, du moment qu'IPv6 peut tourner dessus.

L'explosion du nombre d'équipements connectés est déjà largement une réalité (donnant naissance à des slogans plus ou moins pipeau comme « Internet des objets »). Le routage interne (plusieurs réseaux à la maison, séparés par des routeurs) est par contre encore embryonnaire. Mais Homenet vise le futur (ce qui explique aussi pourquoi les questions liées à IPv4 ne sont pas abordées, cf. section 3.2.3). À noter qu'il existe déjà une description du routeur IPv6 idéal pour la maison, dans le RFC 7084.

Comme tout document d'architecture, le RFC Homenet commence avec de la terminologie (section 1.1). Ainsi, la frontière (border) est l'endroit où on change de domaine administratif et où on applique donc les règles de sécurité (filtrage, par exemple). Chaque réseau derrière une frontière se nomme un royaume (realm). Le CER (Customer Edge Router) est le routeur qui est à la frontière. Il peut y en avoir plusieurs (un point important de Homenet, qui avait été chaudement discuté, est que Homenet doit gérer le cas où il y a plusieurs FAI). Homenet prévoit plusieurs routeurs à la maison et le réseau des invités (guest network) est un réseau interne conçu pour les visiteurs et n'ayant pas forcément accès à tous les services du réseau de la maison (pour pouvoir fournir un accès WiFi à vos invités sans qu'ils puissent fureter dans votre collection de sex tapes sur le NAS). Si FQDN est bien connu, Homenet utilise aussi le sigle LQDN (Locally Qualified Domain Name, un nom qui n'a de signification que local).

Attaquons maintenant le problème de créer des homenets. La section 2 fait le point des différences entre IPv4 et IPv6 qui vont avoir un impact sur le réseau à la maison (ou dans le petit bureau d'une petite organisation). Premièrement (section 2.1), IPv6 permet d'avoir plusieurs réseaux à la maison. C'est possible également en IPv4, mais uniquement avec des adresses privées, on a rarement des préfixes IPv4 assez grands pour les découper finement. En revanche, IPv6 permettrait de faire plus facilement des réseaux multiples, par exemple pour séparer le réseau des invités, ou bien pour avoir un réseau de l'employeur, étendu à la maison via un VPN, mais séparé du réseau personnel. Une autre raison pour le multi-réseaux est que les technologies de couche 1 et de couche 2 deviennent de plus en plus hétérogènes, notamment en raison de l'apparition de techniques dédiées aux objets limités (peu de puissance électrique, peu de capacités de calcul, etc). Des écarts de trois ordres de grandeur (de 1 Mb/s à 1 Gb/s) sont courants aujourd'hui et tendent à s'élargir. Pour éviter d'aligner Ethernet sur le plus grand dénominateur commun de ces réseaux limités (RFC 7102), il faut bien partitionner en plusieurs réseaux IP et router entre eux.

Cela implique d'avoir un préfixe IPv6 plus général qu'un /64. Le /64 permet un nombre colossal d'adresses mais ne permet qu'un seul préfixe, donc qu'un seul réseau, en tout cas tant qu'on garde l'auto-configuration sans état du RFC 4862. C'est pour cela que le RFC 6177 recommande d'allouer à M. Michu des préfixes suffisants pour tous ses usages, y compris futurs.

Donc, avoir plusieurs réseaux IP à la maison serait très bien. Mais ce n'est pas trivial. Il faut allouer ces préfixes (rappelons que le réseau à la maison n'est pas géré, M. Toutlemonde ne va pas installer un logiciel d'IPAM et concevoir un plan d'adressage). Et les mécanismes existants pour le réseau sans configuration (comme le mDNS du RFC 6762) ne fonctionnent pas en multi-réseaux (ils dépendent de la diffusion, qui s'arrête au premier routeur rencontré).

Deuxième propriété importante d'IPv6, la possibilité d'avoir des adresses uniques au niveau mondial et donc l'élimination du NAT (section 2.2). C'est à la fois une chance formidable de retrouver la communication directe de bout en bout qui a fait le succès de l'Internet, et aussi un risque car tout trafic sur l'Internet n'est pas souhaitable, et beaucoup d'engins connectés ont une sécurité... abyssale (imprimantes ou caméras avec des mots de passe par défaut, et jamais changés). Une connectivité de bout en bout nécessite une meilleure sécurité des machines, ou alors des pare-feux IPv6 protégeant le réseau. S'agissant de ces pare-feux, notre RFC Homenet note qu'il faut distinguer adressabilité et joignabilité. IPv6 fournit l'adressabilité (toute machine, si humble soit-elle, a une adresse IP unique) mais on ne souhaite pas forcément la joignabilité (je ne veux pas que le voisin se connecte à ma caméra IP).

À noter qu'il existe un débat très chaud à l'IETF concernant les recommandations à faire pour la politique de sécurité par défaut d'un pare-feu à la maison. Les RFC 4864 et RFC 6092 discutent des mérites comparés des politiques « bloquer tout par défaut, sauf quelques exceptions » et « autoriser tout par défaut, avec quelques exceptions ».

Bien sûr, une des nouveautés les plus spectaculaires d'IPv6 est la disponibilité d'un grand nombre d'adresses. Mais on oublie souvent une autre nouveauté, le fait qu'avoir plusieurs adresses IP n'est plus un bricolage spécial, mais devient la norme (section 2.3). Cela entraine des questions nouvelles comme « quelle adresse IP source choisir pour les connexions sortantes ? » (RFC 6724).

IPv6 permet de disposer d'adresses purement locales (section 2.4 de notre RFC), attribuées sans référence à un registre central, les ULA (Unique Local Addresses, RFC 4193 et RFC 7084 pour leur usage dans les CER). Comme M. Michu n'a typiquement pas d'adresses IP à lui, les adresses externes de sa maison ou de sa petite association seront sans doute des adresses attribuées par le FAI. Pour la stabilité, il est donc recommandé d'y ajouter des ULA, qui permettront aux machines locales de se parler en utilisant toujours les mêmes adresses, même en cas de changement de FAI. Comme toutes les adresses privées, les ULA isolent des changements extérieurs. Par contre, elles n'impliquent pas de faire du NAT, même pas du NAT IPv6 (RFC 6296). La machine est censée utiliser son ULA lorsqu'elle communique avec le réseau local et une adresse publique lorsqu'elle communique avec l'extérieur (c'est le comportement par défaut si le RFC 6724 a été implémenté correctement sur la machine). Homenet déconseille donc toute forme de NAT IPv6, même celle du RFC 6296 (pourtant bien meilleure techniquement que le NAT d'IPv4).

Un autre avantage des ULA est que les machines qui n'ont pas besoin de communiquer avec l'extérieur (une imprimante, par exemple), n'ont pas besoin d'adresse publique et peuvent donc se contenter de l'ULA.

Dans les réseaux IPv4, on voit parfois des équipements exposer leur adresse IPv4 à l'utilisateur, par exemple pour pouvoir la changer manuellement. Les adresses IPv6 étant plus longues, plus difficiles à mémoriser et plus aléatoires d'apparence, cette pratique est déconseillée pour Homenet (section 2.5). Pas touche aux adresses !

Enfin, dernier point spécifique à IPv6, le fait que certains réseaux seront peut-être seulement en IPv6. Si on part de zéro aujourd'hui (déploiement greenfield en anglais), il n'y a guère de raison de mettre de l'IPv4. Ne faire que de l'IPv6 simplifie le réseau et sa gestion, par contre cela implique que chaque machine sache tout faire en IPv6 (par exemple, il existe des systèmes qui ont une gestion d'IPv6 complète, sauf pour les résolveurs DNS qui doivent être accessibles en IPv4). Évidemment, même si le réseau local peut être entièrement IPv6, il faudra encore, pendant un certain temps, communiquer avec des machines purement IPv4 et donc déployer des solutions de coexistence comme celle du RFC 6144.

Sur ce, la section 2 du RFC Homenet est terminée. Vous savez désormais ce qu'il faut savoir d'important sur IPv6, place aux principes d'architecture de Homenet en section 3. Comment construire des réseaux IPv6 à la maison avec les techniques IPv6 ? Et ce avec des engins variés, connectés en une topologie quelconque, sans configuration manuelle ou, en tout cas, sans qu'elle soit obligatoire ? La section 3.1 pose les principes de base :

  • Autant que possible, réutiliser des protocoles existants. Homenet est ambitieux mais conservateur.
  • Imposer le moins de changements possibles aux machines, routeurs ou machines terminales.

Les topologies (façons dont les réseaux qui forment le homenet sont connectés) doivent pouvoir être quelconques (section 3.2). Les utilisateurs vont sans doute connecter sans réfléchir et on ne veut pas leur imposer des règles comme « ne pas faire de boucles » ou « le réseau doit avoir une topologie strictement arborescente ». Le réseau doit continuer à fonctionner tant qu'il n'est pas physiquement partitionné. Par exemple, si deux commutateurs sont connectés en une boucle, le commutateur doit le détecter (en voyant son adresse MAC à l'extérieur) et réparer tout seul. Le réseau doit pouvoir être dynamique : il doit accepter non seulement l'ajout ou le retrait de machines mais également les changements dans la connectivité. Le RFC 7084 donne des idées de configurations qui doivent fonctionner. Parmi les propriétés d'un réseau qui ont une particulière importance :

  • La présence ou non de routeurs internes (très rare à l'heure actuelle),
  • Présence de plusieurs réseaux physiques interconnectés uniquement via l'Internet,
  • Gestion du CER (Customer Edge Router) par l'utilisateur ou par le FAI (le RFC ne mentionne pas le cas plus compliqué où l'utilisateur doit utiliser le CER du FAI mais peut configurer certains aspects),
  • Nombre de FAI (presque toujours un seul aujourd'hui mais cela pourrait changer, notamment pour avoir davantage de résilience),
  • Et nombre de CER (il n'y en a pas forcément qu'un seul par FAI).

Le cas le plus commun aujourd'hui est un seul FAI, un seul CER, pas de routeurs internes. Le cas le plus simple dans le RFC est celui de la section 3.2.2.1 : un seul FAI, un seul CER mais des routeurs internes. (Les sections suivantes présentent des cas plus compliqués.)

Le multi-homing présente des défis spécifiques. Une partie du groupe de travail Homenet aurait préféré travailler sur des réseaux ayant un seul FAI, où la plus grande partie des services permettant de faire fonctionner le homenet aurait été fournie par le FAI. Cela simplifiait nettement le problème mais au prix d'une grosse perte d'indépendance pour l'utilisateur. Sans surprise, cette position était surtout défendue par les gens qui travaillent pour les FAI, ceux qui travaillent pour les fabriquants de routeurs préférant du multi-homing, avec plein de routeurs partout. Le multi-homing reste relativement simple s'il n'y a qu'un seul CER, connecté aux différents FAI. Des fonctions comme la sélection d'un FAI en fonction de l'adresse IP source peuvent être entièrement gérées dans le CER. S'il y a plusieurs CER, il faut que chaque machine choisisse le bon CER de sortie. « Bon » au sens qu'il doit être cohérent avec l'adresse IP source (utilisation des adresses du préfixe du FAI) pour éviter le filtrage par les techniques anti-usurpation dites BCP 38 (RFC 2827 et RFC 3704). La question du multi-homing est récurrente à l'IETF et mène souvent à des solutions assez complexes, peut-être trop pour le homenet. Par exemple, une solution possible serait de faire tourner les protocoles de routage sur toutes les machines, de façon à ce que même les machines terminales apprennent les routes et sachent quel routeur contrôle quel réseau. Le RFC 7157 décrit une solution plus simple (qui évite la traduction d'adresses du RFC 6296, déconseillée pour le projet Homenet). Il y a aussi d'utiles techniques qui sont entièrement dans les machines terminales, sans mettre en jeu le réseau, comme SHIM6 (RFC 5553), MPTCP (RFC 6824) ou les globes oculaires heureux du RFC 6555.

Parmi les pièges du multi-homing, le RFC note que certains des FAI peuvent ne pas fournir une connectivité complète. Un exemple est celui du télé-travailleur où le réseau local est multihomé vers l'Internet et vers le réseau de l'employeur, via un VPN, et où le réseau de l'employeur ne donne pas accès à tout l'Internet. Homenet ne fournit pas de solutions à ce sous-problème. (Un autre cas où il se pose, plus polémique et non cité par le RFC, est celui où l'un des FAI bride, filtre ou censure, en violation de la neutralité.)

Le réseau à la maison doit évidemment être entièrement auto-configuré, puisqu'on ne souhaite pas que M. Toutlemonde soit obligé de devenir administrateur réseaux (section 3.3). C'est plus facile à dire qu'à faire. Par exemple, il faut éviter que n'importe quelle machine qui se trouve passer dans les environs puisse rejoindre le réseau alors que sa présence n'est pas souhaitée. L'utilisateur doit donc avoir un moyen simple de tenir à distance les importuns et donc de dire « cette machine est bienvenue ». Il y a d'intéressants problèmes d'interface utilisateur ici... Un exemple d'un moyen simple est la pression quasi-simultanée de deux boutons, un sur la nouvelle machine qui arrive et un sur le routeur.

En parlant de sécurité et de « eux » et « nous », il faudra bien que le homenet soit conscient de l'étendue de son royaume afin, par exemple, d'appliquer des politiques de sécurité différentes entre les communications internes et externes. Sans compter les frontières à l'intérieur même de la maison, comme entre le réseau des enfants et l'extension virtuelle du réseau de l'entreprise de Maman. Comme souvent, le RFC demande que cela soit automatique, mais avec possibilité de changement manuel si on a une configuration très spéciale.

Et l'adressage (section 3.4) ? Ah, c'est une question compliquée. D'abord, le homenet sera dépendant de ce que lui aura alloué le ou les FAI. Espérons qu'ils suivent les politiques du RFC 6177 et lui donnent donc assez d'adresses et en tout cas plus que le pauvre /64 que certains FAI distribuent aujourd'hui à leurs abonnés, et qui ne leur permet pas d'avoir facilement plusieurs réseaux à la maison. Le RFC 6177 n'imposant plus une longueur unique aux allocations, le homenet récupérera peut-être un /60, un /56 ou un /48 (notre RFC recommande un /56 ou plus général). Le protocole de récupération du préfixe sera sans doute celui du RFC 3633. Il permet au homenet de solliciter une certaine longueur de préfixe, mais sans garantie que le FAI ne lui enverra pas un préfixe plus spécifique. Là encore, la délégation de préfixe peut échouer (si la liaison avec le FAI est coupée) et le homenet doit donc pouvoir fonctionner seul, y compris pour son adressage. Une nouvelle raison d'utiliser les ULA. Rappelez-vous que ce RFC est juste une architecture, il ne définit pas en détail les protocoles utilisés, mais il note ici qu'il faudra sans doute une et une seule méthode de délégation de préfixe, pour que tous les routeurs du réseau local soient d'accord sur les adresses à utiliser.

Il est préférable que les préfixes utilisés en interne soient stables, et notamment survivent au redémarrage des routeurs. Cela implique un mécanisme de stockage permanent des données sur les routeurs, ainsi que, de préférence, un moyen de tout remettre à zéro s'il y a une reconfiguration significative.

À propos de stabilité, il faut noter que, bien qu'elle facilite nettement le fonctionnement du réseau, elle a aussi des inconvénients en terme de vie privée. Si le préfixe alloué à un client du FAI reste stable, il aura à peu près le même effet qu'une adresse IPv4 fixe : les machines avec qui communique le client pourront voir que plusieurs requêtes viennent de la même maison. Le NAT (en IPv4) ou les extensions de vie privée (en IPv6, cf. RFC 8981) n'aident pas contre cette indiscrétion.

La section 3.5 discute ensuite de la question du routage interne. En effet, une des nouveautés du projet Homenet est de considérer qu'il y aura des routeurs internes et donc du routage à faire entre les différents réseaux de la maison. Là encore, tout doit se configurer tout seul donc il faudra problablement choisir un protocole de routage dynamique, de préférence un protocole existant et déjà testé, mais qui tient compte des exigences particulières de Homenet (par exemple le peu de ressources matérielles des routeurs internes).

Que des gros problèmes compliqués, non ? Chacun d'entre eux a déjà de quoi distraire une équipe d'ingénieurs pendant un certain temps. Mais ce n'est pas fini. La section 3.6 s'attaque à la sécurité. Le problème est difficile car on ne veut évidemment pas que les voisins récupèrent les selfies qu'on a laissés sur l'appareil photo connecté, mais on veut également une grande simplicité de configuration (voire zéro configuration), ce qui va généralement mal avec la sécurité. La disparition souhaitée du NAT ajoute en outre une nouvelle composante au problème. Il sera difficile d'éviter une réflexion sur la sécurité des machines (abyssalement basse, aujourd'hui), la protection offerte par le réseau ayant ses limites (surtout si on veut que chaque brosse à dents puisse communiquer sur l'Internet). L'un des buts d'Homenet est de rétablir le principe des communications de bout en bout (RFC 2775). Mais cela ne signifie pas open bar pour tout le trafic et notre RFC distingue donc bien le fait d'être mondialement adressable (adresse IPv6 unique) et celui d'être mondialement joignable (n'importe quel script kiddie peut tenter une attaque sur la brosse à dents IP). Le RFC 4864 proposait un modèle de sécurité fondé sur un pare-feu protégeant le périmètre, considérant qu'on ne pouvait pas espérer que toutes les machines soient sécurisées. La polémique se concentre évidemment sur la politique par défaut de ce pare-feu. On sait bien que très peu de gens changeront cette politique donc elle a une importance cruciale. Un blocage par défaut (default deny) ferait retomber dans les problèmes du NAT où des tas d'applications (serveur auto-hébergé, pair-à-pair) sont interdites, sauf à déployer des techniques d'ouverture de pare-feu comme UPnP ou le PCP du RFC 6887. Le RFC 6092 ne suivait donc pas cette approche du « interdit par défaut », et recommandait que, même si elle était choisie, il soit facile de revenir à un mode d'autorisation par défaut, celui qui permet l'innovation et le déploiement de nouveaux services. La question continue à susciter d'innombrables discussions à l'IETF et il est clair qu'il n'existe pas de consensus entre les partisans du « interdit par défaut » et ceux du « autorisé par défaut ».

Par contre, il est certain que, comme indiqué plus haut, tout trafic n'est pas souhaitable. Le principe fondateur de connectivité de bout en bout, c'est « deux machines qui le souhaitent doivent pouvoir communiquer directement », pas « je dois supporter n'importe quel trafic qu'un crétin quelconque veut m'envoyer ». Par exemple, comme indiqué plus haut, on peut souhaiter isoler le trafic du réseau des invités. Filtrer à la frontière sera donc toujours nécessaire.

Est-ce que le NAT ou les pare-feux actuels assurent cette fonction de manière satisfaisante ? Pour le NAT, clairement non. Pour les pare-feux, la religion actuelle des pare-feux (auditeurs ignorants qui vous reprochent de ne pas avoir de pare-feu devant un serveur Internet public, managers qui croient qu'ils ont traité les problèmes de sécurité en installant une boîte noire très chère marquée en gros Firewall...) ne peut pas masquer les innombrables problèmes de sécurité qui affectent les utilisateurs pourtant situés derrière un pare-feu (distribution de malware par le courrier, par exemple). Une des plus grosses faiblesses de la religion du pare-feu est qu'elle suppose que les méchants sont uniquement à l'extérieur : résultat, la compromission d'une seule machine à l'intérieur suffit à annuler l'effet du pare-feu. Donc, la situation actuelle n'est pas satisfaisante. Néanmoins, pour un réseau typique, on peut difficilement se passer aujourd'hui du pare-feu. Autant on peut sécuriser un serveur Internet sérieux, géré par des professionnels, autant on ne peut pas compter sur les innombrables objets connectés : la plupart d'entre eux ont zéro sécurité (serveur Web d'administration activé par défaut, avec un mot de passe identique pour toutes les machines et jamais changé, et un CGI écrit en bash pour faire bonne mesure). Il est donc nécessaire que la sécurité soit assurée en dehors de ces machines, par un pare-feu. Donc, avoir cette fonction de protection, ainsi que la politique « tout interdit sauf ce qui est autorisé » (même si elle n'est pas activée par défaut) est utile, comme demandé par le RFC 7084. Cela ne doit pas faire oublier qu'il faut aussi pouvoir permettre aux machines du réseau de communiquer, lorsqu'elles en ont besoin.

Autre grande question des systèmes répartis, le nommage (section 3.7). Il ne fait pas de doute que Jean-Michu Toutlemonde préférera des noms parlants et surtout stables, aux adresses IPv6. À chaque changement de FAI, le préfixe IPv6, et donc les adresses, changera, alors que les noms resteront. Il faut donc des noms et, comme toujours dans le projet Homenet, que ces noms puissent être attribués sans administration explicite (à part éventuellement la saisie du nom dans une interface simple ; les autres machines devront s'attribuer un nom unique automatiquement). D'autre part, il faudra pouvoir découvrir des services (par exemple, une imprimante, ou bien un NAS), typiquement via une interface graphique qui affichera tous les services trouvés dans le réseau. Les protocoles existants à cette fin (comme celui du RFC 6763) sont typiquement mono-réseau et fonctionnent en criant à la cantonade « Y a-t-il une imprimante dans la salle ? » Avec les homenets composés de plusieurs réseaux, il faudra une autre approche.

En parlant de découverte de service, il est important de faire une distinction entre résolution (lookup) et découverte (discovery). La première consiste à trouver les informations (comme l'adresse IP) à partir d'un nom connu et existant. La seconde à trouver des noms (s'il y en a) correspondant à un certain critère. Homenet va avoir besoin d'un service de noms fournissant ces deux fonctions. Il est évidemment souhaitable, en application du principe qu'Homenet doit réutiliser autant que possible les protocoles existants, que cela soit le DNS (ou une variante comme celle du RFC 6762). Notre RFC voudrait même en plus qu'on puisse utiliser DNSSEC (RFC 4033) ce qui est très souhaitable pour la sécurité, mais tout en gardant cette absence de configuration, ce qui va être difficile.

D'autre part, on voudrait pouvoir utiliser un espace de nommage public, celui des noms de domaine, mais tout en gardant l'aspect « zéro configuration ». La question « un espace de noms ou plusieurs » n'est pas tranchée par ce RFC. Si on veut accéder aux engins de la maison depuis l'extérieur, il faudra bien utiliser l'espace public et unique (celui d'aujourd'hui, là où se trouvent les noms comme www.potamochère.fr, qui marchent sur toute la planète). Si les noms dans cet espace public dépendent du FAI (par exemple jean-jacques.michu.free.fr), l'utilisateur dépendra de son FAI. Le RFC souhaite donc qu'Homenet fonctionne avec des noms de domaine personnels, qui assurent à l'utilisateur son indépendance. Même dans le cas où on a des noms mondiaux, le RFC demande qu'on puisse avoir en plus un espace de noms purement local, qui ne fonctionne que sur le homenet (de la même façon qu'il recommande des adresses IPv6 publiques et des ULA). Le TLD .local ne convient pas forcément à cet usage car il est lié à un protocole particulier (le mDNS du RFC 6762). Il faudra donc un nouveau TLD pour les homenets multi-réseaux (ou bien attendre une éventuelle extension de mDNS, dont le RFC ne parle pas). Une fois le nouveau TLD défini (.sitelocal ? .home ?), les noms dans ce TLD seront des ALQDN (Ambiguous Local Qualified Domain Name), des noms ambigus car plusieurs réseaux pourront utiliser le même (par exemple Jean-Jacques Michu et Jennifer Michu auront tous les deux un michu.sitelocal). Ces noms sont casse-gueule car on ne peut jamais exclure qu'un utiliseur ne mémorise un tel nom lorsqu'il est sur un des réseaux et l'utilise après sur un autre réseau où cela ne marchera pas ou, pire, où cela l'entrainera sur un autre service que celui attendu. Une façon de résoudre le problème est d'avoir des ULQDN (Unique Locally Qualified Domain Name) où le deuxième composant du nom (avant .sitelocal) serait une chaîne de caractères unique, par exemple en condensant l'ULA. Cela peut être généré automatiquement, et survivre aux redémarrages. Ainsi, on peut obtenir un nom unique, avec quasiment aucun risque de collisions, sans faire appel à un registre central. Cela résoudrait le problème de l'accès depuis l'extérieur. Mais le RFC oublie de dire que ces noms ne seront pas très conviviaux... (04619d3973addefca2be3.sitelocal ?). Et si on ne faisait pas appel à un TLD comme .sitelocal mais qu'on utilisait simplement des noms courts comme pc-jean-jacques ou printer ? Le problème de ces noms est le risque de collision avec, par exemple, un TLD délégué (que se passe-t-il si l'ICANN délègue .printer ?)

Enfin, parmi les autres innombrables détails qui compliquent le déploiement d'un joli système de nommage pour le homenet, le RFC note que ce système doit continuer à fonctionner même si le réseau est déconnecté de l'Internet (et ne peut donc pas joindre les serveurs racine du DNS). Cela va à l'opposé de l'approche de la plupart des « objets intelligents » qu'on vend au gogo aujourd'hui et qui sont presque tous dépendants d'un cloud lointain à qui ils envoient systématiquement toutes les données. Et il y a le problème des engins mobiles qui peuvent être connectés à un homenet puis se déplacer pour un autre. On voudrait évidemment qu'ils gardent le même nom, mais ce n'est pas évident (DNS dynamique du RFC 2136 ?).

Pour terminer cette longue liste de problèmes à résoudre, la section 3.8 du RFC traite des problèmes divers. Par exemple, la gestion opérationnelle du réseau. Comme on veut un réseau sans administrateur et qui s'organise tout seul, cette activité de gestion doit être facultative. Mais il peut y avoir des tâches optionnelles, par exemple pour l'utilisateur avancé, ou pour celui qui a des exigences de sécurité fortes et veut donc durcir la configuration par défaut. Au minimum, même si l'utilisateur ne change rien, il aura peut-être envie de regarder (en mode « lecture seule ») son réseau, voir les machines connectées, le trafic (un seul ado abonné à Netflix à la maison peut sérieusement stresser le réseau, croyez-moi), les pannes, l'état de certains services (« NAS plein à 98 % », merci BitTorrent).

Enfin, pour clore le RFC, la section 3.9 revient sur les problèmes qui sont déjà résolus par IPv6 et sur ceux qu'il faudra résoudre. Le principe d'Homenet est de réutiliser, autant que possible, les protocoles existants de la famille IPv6. Mais il faudra bien développer de nouveaux protocoles pour les cas qui sortent du possible actuel. Le routage de base est, selon le RFC, bien traité à l'heure actuelle (bientôt OSPF à la maison...) Le cas du multi-homing avec plusieurs routeurs de sortie est plus compliqué, et nécessitera sans doute des extensions aux protocoles de routage.

À noter que Homenet a un futur protocole de distribution d'information, HNCP (Home Networking Control Protocol, pas encore de RFC publié), qui pourra servir de base à des mécanismes de distribution des routes.

Autre problème pas vraiment résolu, les protocoles de résolution (RFC 6762) et de découverte de services (RFC 6763) ne fonctionnent que sur un réseau où la diffusion à tous est possible. Dans un environnement multi-réseaux comme Homenet, il faudra utiliser leurs extensions, actuellement en cours de développement.

Dernier problème ouvert, pour les ambitieux qui ont des idées : découvrir automatiquement les frontières du réseau, où se termine la maison et où commence le monde extérieur. On l'a dit, Homenet est un projet très ambitieux, régulièrement critiqué comme trop ambitieux et traitant trop de choses à la fois.

Quelques bons articles à lire :

  • Sur l'automatisation de la maison, les excellents et très concrets exposés de Nathalie Trenaman comme IPv6 at Home.
  • Un article généraliste sur la maison qui tweete et l'exposé de son architecte à la Journée du Conseil Scientifique de l'AFNIC.
  • Un article de synthèse très bien fait et très rigolo.
  • Un très bon interview stratégique de Mark Townsley, président du groupe de travail Homenet. « The homenet working group focuses on home networks with IPv6. The task of the working group includes producing an architecture document that outlines how to construct home networks involving multiple routers and subnets, i.e. multi-homing with IPv6. » Il insiste sur les oppositions à Homenet et sur les contestations dans le groupe de travail, entre ceux qui voulaient que le réseau à la maison soit une simple extension de celui du FAI et ceux qui voulaient un réseau autonome « The limit from the operator’s perspective seems to be that the user can have one two or maybe three routers with one ISP connection and a backup or VPN connection, and thats about it. [...] There has always been this tug-of-war between what the operator will provide as a supported configuration and what the users will make happen on their own if the ISP doesn’t provide it. We’re seeing a bit of that in the Working Group now. ».
  • Une excellente présentation générale, du même auteur.

Et, côté mise en œuvre, le projet Hnet.


Téléchargez le RFC 7368


L'article seul

RFC 7366: Encrypt-then-MAC for TLS and DTLS

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : P. Gutmann (University of Auckland)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 16 septembre 2014
Dernière mise à jour le 22 février 2015


Depuis ses débuts, le protocole de cryptographie TLS (héritier de SSL) protège l'intégrité des paquets transmis en calculant un MAC, qui est inclus dans les données avant le chiffrement, une technique qu'on nomme MAC-then-encrypt. Plusieurs failles de sécurité ont été depuis identifiées dans cette technique et ce nouveau RFC normalise une extension à TLS qui permet de faire l'inverse, chiffrer avant de calculer le MAC, ce qui est aujourd'hui considéré comme plus sûr. On nomme cette méthode, logiquement, encrypt-then-MAC. (Notez qu'il existe une méthode encore plus sûre, le chiffrement intègre, systématisé à partir de TLS 1.3.)

Lorsque le protocole SSL, ancêtre de TLS, avait été normalisé, au milieu des années 1990, le MAC-then-encrypt semblait tout à fait sûr. C'est ainsi que l'actuelle norme TLS, le RFC 5246 (section 6.2.3.1), continue à utiliser MAC-then-encrypt. Des études comme celle de M. Bellare et C. Namprempre, « Authenticated Encryption: Relations among notions and analysis of the generic composition paradigm » ou celle de H. Krawczyk, « The Order of Encryption and Authentication for Protecting Communications (or: How Secure Is SSL?) » ont depuis montré que MAC-then-encrypt est vulnérable à un certain nombre d'attaques cryptanalytiques, dans certaines conditions d'utilisation (je simplifie : la question de la vulnérabilité exacte de MAC-then-encrypt est plus compliquée que cela). Il est désormais recommandé d'utiliser plutôt encrypt-then-MAC (je simplifie encore : le RFC note par exemple que les algorithmes qui ne séparent pas chiffrement et calcul du MAC n'ont pas besoin de cette méthode).

Pour sélectionner la méthode recommandée, le groupe de travail TLS de l'IETF a choisi (section 2 de notre RFC) d'utiliser une extension à TLS (RFC 5246, section 7.4.1.4). Le client ajoute dans son message de bienvenue (client_hello) l'extension encrypt_then_mac (le extension_type de encrypt_then_mac vaut 22 et est désormais dans le registre IANA). Si le serveur TLS est d'accord, il mettra cette extension dans son server_hello.

Une autre solution (que d'utiliser le mécanisme d'extensions) aurait été de définir de nouveaux algorithmes de chiffrement et elle a fait l'objet de nombreux débats au sein du groupe de travail. Mais cela menait à une explosion du nombre d'algorithmes (ciphers), il aurait fallu presque doubler le nombre d'algorithmes concernés, pour avoir une version MAC-then-encrypt (l'actuelle) et une version encrypt-then-MAC. Encore une autre solution aurait été de créer une nouvelle version de TLS, la 1.3, où encrypt-then-MAC aurait été le comportement standard. Quand on sait que la version actuelle de TLS, la 1.2, est toujours minoritaire dans la nature, on voit qu'une telle solution aurait sérieusement retardé le déploiement. Au contraire, avec la solution choisie, il « suffira » de changer quelques dizaines de lignes de code dans les bibliothèques TLS actuelles. Un tel changement a des chances de se retrouver plus rapidement sur le terrain.

Comme le mécanisme d'extension est apparu avec TLS (il n'existait pas dans SSL, même dans sa dernière version, la 3), encrypt-then-MAC ne sera pas utilisable pour les logiciels qui utilisent encore SSL v3 (le cas principal semblant être la version 6 d'Internet Explorer). Comme SSL est abandonné depuis quinze ans, des logiciels aussi vieux ont probablement des tas d'autres failles de sécurité plus graves que l'utilisation de MAC-then-encrypt. (Au passage, c'est une des raisons pour lesquelles ce modeste blog n'accepte pas SSLv3.)

Arrêtons la discussion sur les alternatives qui auraient été possibles et revenons à la nouvelle extension (section 3 de notre RFC). Une fois qu'elle est acceptée par le client et le serveur, le traitement des paquets par TLS passera de l'ancien comportement encrypt (data || MAC || pad) (où || désigne la concaténation) au nouveau encrypt (data || pad) || MAC. Le MAC est calculé comme avant, sauf qu'il part du texte chiffré (TLSCiphertext) et plus du texte en clair (TLSCompressedtext, cf. RFC 5246, section 6.2.3.1). La structure de données TLS qui était (RFC 5246, section 6.2.3) :

struct {
          ContentType type;
          ProtocolVersion version;
          uint16 length;
          GenericBlockCipher fragment; /* Après moultes discussions,
	  le groupe de travail a décidé de n'appliquer
	  encrypt-then-MAC qu'aux "block ciphers". */
      } TLSCiphertext;

va devenir :

struct {
          ContentType type;
          ProtocolVersion version;
          uint16 length;
          GenericBlockCipher fragment;
          opaque MAC;  /* Ce champ supplémentaire est la seule
	  nouveauté */
      } TLSCiphertext;

Pour le déchiffrement, on fait les opérations en sens inverse, on vérifie le MAC d'abord, on jette immédiatement le paquet si le MAC est incorrect (en renvoyant un message bad_record_mac), sinon on déchiffre. Ainsi, un attaquant qui modifie les données en vol ne peut rien apprendre sur les clés cryptographiques utilisées : toute modification invalidera le MAC et tous les calculs d'un MAC incorrect prendront le même temps, ne permettant pas d'attaque par mesure du temps.

À noter que TLS permet d'utiliser un MAC raccourci (RFC 6066) et cela reste possible avec encrypt-then-MAC, dans les mêmes conditions.

Comme avec toute extension qui améliore la sécurité, il y a un risque qu'un attaquant actif perturbe la négociation (section 4 du RFC) pour amener les deux parties à ne pas choisir la nouvelle extension (attaque par repli), par exemple en forçant une utilisation de vieilles versions du protocole, n'ayant pas d'extensions (et donc pas de encrypt-then-MAC). La seule protection est de refuser le repli, ce qui peut provoquer des problèmes d'interopérabilité avec certains vieux logiciels (voir par exemple le ticket #1084025 chez Mozilla).

Il y a un serveur TLS public qui gère cette extension, si vous voulez tester votre code client : https://eid.vx4.net. Au 14 septembre 2014, la gestion de cette extension ne figure pas encore dans la version publiée d'OpenSSL, la 1.0.1i mais est dans la version de développement (voir le commit). Par contre, encore rien dans GnuTLS (la version publiée est la 3.3.7).

Merci à Florian Maury pour sa relecture et à Manuel Pégourié-Gonnard pour avoir corrigé une faute sur l'attaque par repli..

Une bonne explication technique de ces problèmes est celle de Moxie Marlinspike.


Téléchargez le RFC 7366


L'article seul

RFC 7365: Framework for Data Center (DC) Network Virtualization

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : Marc Lasserre, Florin Balus (Alcatel-Lucent), Thomas Morin (France Telecom Orange), Nabil Bitar (Verizon), Yakov Rekhter (Juniper)
Pour information
Réalisé dans le cadre du groupe de travail IETF nvo3
Première rédaction de cet article le 11 octobre 2014


Ce nouveau RFC décrit le cadre général de la virtualisation de réseaux en utilisant IP comme substrat. Il est issu du projet NVO3 de l'IETF, qui a produit une description du problème (dans le RFC 7364) et ce document. À ce stade, ce n'est pas encore un protocole concret, même s'il existe déjà des solutions techniques partielles pour ce problème.

La cible est constituée des grands centres de données, hébergeant des centaines de milliers de machines virtuelles, et qu'on souhaite pouvoir gérer de manière souple (par exemple en déplaçant facilement une machine virtuelle d'une machine physique à une autre, sans l'éteindre et sans la changer d'adresse IP). Le RFC 7364 décrit plus en détail le problème à résoudre (et il est donc recommandé de le lire d'abord), ce RFC 7365 étant le cadre de(s) la(les) solution(s). Comme on envisage des grands ensembles de machines, et qu'on cherche à être très dynamique (reconfigurations fréquentes), il faudra beaucoup d'automatisation (pas question de modifier des tables à la main parce qu'une machine s'est déplacée).

Il définit donc un vocabulaire et un modèle pour ces réseaux virtuels. Donc, on parle de réseaux NVO3 (NVO3 networks). Il s'agit de créer des réseaux virtuels (VN pour virtual networks, ou bien overlays) fonctionnant au-dessus d'un protocole de couche 3, IP. Ces réseaux virtuels fournissent aux clients (qui peuvent appartenir à des organisations distinctes, voire concurrentes) soit un service de couche 3, soit un service de couche 2 . Les réseaux virtuels sont créés au-dessus d'un substrat, l'underlay, qui est le « vrai » réseau sous-jacent. Le substrat est toujours de couche 3, comme le nom du projet NVO3 l'indique. Chaque VN aura un contexte, un identificateur qui figurera dans les paquets encapsulés et qui permettra à l'arrivée de distribuer le paquet au bon VN. Le réseau NVO3 utilisera des NVE (Network Virtualization Edge) qui seront les entités qui mettent en œuvre ce qui est nécessaire pour la virtualisation. Un NVE a au moins une patte vers le client (qui envoie des paquets sans savoir qu'il y a virtualisation) et une autre vers le réseau IP qui transporte le trafic entre les NVE. Un NVE n'est pas forcément un équipement physique, cela peut être, par exemple, le commutateur virtuel d'un hyperviseur.

Les sections 2 et 3 présentent le modèle de référence utilisant ce vocabulaire, et ses composants. Les systèmes des clients (tenant systems) sont connectés aux NVE, via un VAP (virtual access point, qui peut être une prise physique ou bien virtuelle, par exemple un VLAN ID). Un même NVE peut présenter aux clients plusieurs VNI (virtual network instance, une instance particulière de réseau virtuel). NVE et système du client peuvent être physiquement dans la même boîte, ou bien il peut s'agir de systèmes distants (le schéma 2 du RFC n'est pas une représentation physique, mais logique). Dans le premier cas, la communication de l'information peut se faire par une API locale, dans le second, par un protocole réseau. Les NVE échangent l'information entre eux (comme des routeurs avec un IGP) ou bien ils sont connectés à une NVA (Network Virtualization Authority) qui leur fournit les informations sur l'état du réseau (qui est membre, comment joindre les membres, etc). Il y aura donc un protocole entre NVE, ou bien entre NVE et NVA. Le NVA n'est évidemment pas forcément un serveur unique, cela peut être une grappe, pour la redondance. Les machines qui forment l'underlay font du routage IP normal et ne connaissent pas, a priori, les systèmes des clients. La gestion de ce réseau underlay se fait avec les mêmes outils OAM que n'importe quel réseau IP.

Le réseau virtuel (l'overlay) devra donc utiliser une forme ou l'autre d'encapsulation pour faire passer ses paquets sur l'underlay. Cela pourra être GRE, IPsec, L2TP, etc. Ce n'est pas tout de tunneler, il faut aussi un mécanisme de contrôle, rassemblant et distribuant l'information dans le réseau. Un tel mécanisme peut être centralisé (comme dans le cas de SDN) ou réparti (comme l'est traditionnellement le routage dans l'Internet).

Quant un NVE fournit un service de couche 2, les systèmes des clients ont l'impression de se connecter à un Ethernet normal (comme avec le RFC 4761 ou le RFC 4762). S'il fournit un service de couche 3, les systèmes des clients voient un réseau IP, comme avec le RFC 4364.

Autre service important, la possibilité de déplacer des VM à l'intérieur du centre de données. Permettre des déplacements à chaud, sans arrêter la VM, est évidemment très souhaitable, mais cela aura des conséquences sur des points comme les caches ARP (qu'il faut mettre à jour si une VM se déplace, alors qu'elle pense rester dans le même réseau de niveau 2).

La section 4 du RFC décrit quelques aspects essentiels dans les discussions sur les réseaux virtuels. D'abord, les avantages et inconvénients des réseaux virtuels. Sur le papier, ils offrent des tas d'avantages : les systèmes des clients n'ont à s'occuper de rien, ils bénéficient d'un réseau certes virtuel mais qui a les mêmes propriétés qu'un vrai, tout en étant plus souple, avec des changements plus rapides. Même les adresses (MAC et IP) sont séparées de celles de l'underlay donc les clients sont isolés les uns des autres. Malheureusement, il y a quelques problèmes en pratique : pas de contrôle sur le réseau sous-jacent et même pas d'information sur lui, par exemple sur son utilisation, ou sur des caractéristiques comme le taux de perte de paquets (RFC 7680). Il y a donc un risque de mauvaise utilisation des ressources réseaux. Et si plusieurs overlays partagent le même underlay, l'absence de coordination entre les réseaux virtuels, chacun ayant l'impression qu'il est tout seul (« each overlay is selfish by nature »), peut encore aggraver les choses. Mais, bon, des réseaux virtuels existent depuis de nombreuses années, et marchent.

Autre exemple, parmi ceux cités par le RFC, des difficultés à réaliser proprement ce projet, le cas de la diffusion. On veut pouvoir fournir des services qui existent sur les réseaux physiques, comme la capacité à diffuser à tous les membres du réseau, avec un seul paquet. Comment fournir le même service avec des réseaux virtuels ? Il va falloir automatiquement répliquer le paquet pour le transmettre ensuite à tous les réseaux physiques qui contribuent au réseau virtuel. Cela peut se faire de manière violente (dupliquer le paquet en autant d'exemplaires qu'il y a de machines et le transmettre à chacune en unicast) ou bien de manière plus subtile mais plus complexe avec le multicast. La première solution minimise l'état à conserver dans les routeurs, la seconde minimise la capacité réseau consommée.

La mise en œuvre concrète de la virtualisation va nécessiter des tunnels, connectant les différents réseaux physiques. Qui dit tunnel dit problèmes de MTU, en raison des octets consommés par les en-têtes du format de tunnel utilisé. Ces quelques octets en plus diminuent la MTU du réseau virtuel. En théorie, la fragmentation résout le problème mais elle a un prix élevé en performances (idem si fragmentation et réassemblage étaient faits dans le système de virtualisation et non pas, comme la fragmentation IP habituelle, par les machines terminales et - en IPv4 - les routeurs). La découverte de la MTU du chemin (RFC 1981 et RFC 4821) permet de se passer de fragmentation mais, en pratique, elle marche souvent mal. Il semble que la meilleure solution soit de faire en sorte que le réseau virtuel présente une MTU « habituelle » (1 500 octets, la MTU d'Ethernet) et, pour réaliser cela, que la MTU de l'underlay soit assez grande pour que les octets de l'encapsulation puissent être ajoutés sans problèmes (utilisation de jumbogrammes).

Enfin, les réseaux virtuels posent des problèmes de sécurité spécifiques (section 5). Un système client ne doit pas pouvoir attaquer le réseau sous-jacent (il ne doit même pas le voir), et un système client ne doit pas pouvoir attaquer un autre système client (par exemple, s'ils sont dans des réseaux virtuels séparés, il ne doit pas pouvoir lui envoyer directement de paquet, même si les deux systèmes clients se trouvent être sur la même machine physique).

Du point de vue du client, le critère est la capacité du réseau NVO3 à distribuer son trafic au bon endroit, et à séparer les trafics. Un tcpdump chez un client ne doit pas montrer les paquets d'un réseau virtuel d'un autre client (ce qui ne dispense évidemment pas d'utiliser le chiffrement, pour les attaques effectuées par le réseau sous-jacent). Et les machines doivent pouvoir faire confiance au VNI (identificateur du réseau virtuel) indiqué dans un paquet. Comme avec le RFC 2827, une machine client ne doit pas pouvoir injecter des paquets mentant sur le réseau virtuel auquel elle appartient.

Des futurs protocoles conformes à ce schéma sont en cours d'examen dans le groupe de travail, mais qui seront en concurrence avec des protocoles déjà existants qui ont les mêmes objectifs, comme celui du RFC 4364.

Merci à Thomas Morin et Marc Lasserre pour leur relecture.


Téléchargez le RFC 7365


L'article seul

RFC 7364: Problem Statement: Overlays for Network Virtualization

Date de publication du RFC : Octobre 2014
Auteur(s) du RFC : T. Narten (IBM), E. Gray (Ericsson), D. Black (EMC), L. Fang, L. Kreeger (Cisco), M. Napierala (AT&T)
Pour information
Réalisé dans le cadre du groupe de travail IETF nvo3
Première rédaction de cet article le 11 octobre 2014


En informatique, depuis les débuts des temps, on a de plus en plus virtualisé. Le processeur, puis la mémoire, puis des machines entières. Désormais, il est donc logique qu'on cherche à virtualiser le réseau. Par exemple, est-il possible de fournir, dans un centre d'hébergement de données, plusieurs centres de données virtuels, chacun complètement isolé des autres, et permettant de déployer, non pas une seule machine mais tout un réseau ? Il n'y a pas encore de solution technique complète pour ce problème mais ce RFC fournit au moins une description détaillée du problème.

Les organisations qui géreront ces centres de données virtuels seront distinctes, peut-être concurrentes. Il est donc essentiel que les différents réseaux soient parfaitement isolés les uns des autres, avec des espaces d'adressage distincts et des communications uniquement faites de manière explicite (comme s'ils étaient deux réseaux physiques connectés par un routeur). Pas question, par exemple, qu'une de ces organisations puisse sniffer le trafic d'une autre.

Le but est de gagner en souplesse d'administration. Installer un « data center » coûte cher, prend du temps, et l'infrastructure physique ne peut pas être facilement modifiée ensuite. En virtualisant tout, on pourrait imaginer que le gérant du centre de données physique loue des centres de données virtuels à différents acteurs, qui à leur tour loueront des services hébergés dans ces centres virtuels. On aura ainsi du virtuel sur du virtuel sur...

Si la virtualisation est bien faite, le locataire n'aura même pas besoin de savoir quelle est la technique sous-jacente utilisée.

Bon, c'est très joli, comme projet, mais est-ce réaliste ? Notre RFC se concentre sur la première étape, cerner le problème et poser les questions auxquelles il va falloir répondre. C'est le rôle du groupe de travail IETF nommé NVO3, et ce RFC, avec le RFC 7365, est sa première publication. Le chiffre 3 dans le nom fait référence au fait que le groupe se concentre sur les solutions de virtualisation mises en œuvre dans la couche 3 (que ces solutions fournissent un service de couche 3 ou de couche 2). Un autre document, le RFC 7365, spécifie notamment le vocabulaire utilisé. Notre RFC y ajoute le concept de réseau supérieur (overlay network), qui désigne le réseau virtuel bâti au-dessus du réseau physique. Un exemple réalisé dans la couche 2 est 802.1Q qui fait de l'encapsulation de trames de niveau 2 dans d'autres trames.

Donc, quels sont les problèmes à résoudre, se demande la section 3 de notre RFC ? On s'attend à pouvoir déplacer les machines virtuelles d'un serveur à l'autre. En cas de virtualisation du réseau lui-même, cette mobilité doit être possible sans tenir compte de la position physique des serveurs. La machine virtuelle doit pouvoir garder son adresse IP (sinon, cela casserait les sessions TCP en cours, sans parler de la nécessité de mettre à jour le DNS, et autres informations), mais aussi son adresse MAC. En effet, des licences logicielles peuvent être liées à cette adresse MAC. En outre, d'autres perturbations pourraient surgir (système d'exploitation qui ne gère pas correctement un changement d'adresse MAC qu'il n'a pas décidé lui-même).

Dans le centre de données classique, l'adresse IP d'un serveur dépend de sa position. Par exemple, si on a un sous-réseau (et donc un routeur) pour une rangée d'armoires, préserver l'adresse IP impose de ne pas changer de rangée. Ce n'est pas une contrainte trop grave pour un serveur physique, qu'on déplace rarement. Mais ce serait très pénible pour des machines virtuelles, dont l'intérêt est justement la souplesse de placement.

Pour permettre un placement des machines à n'importe quel endroit, il est tentant d'avoir un réseau complètement plat, sans routeurs intermédiaires, ou bien en annonçant des routes spécifiques à une machine (/32 en IPv4) dans l'IGP. Mais cette absence de partitionnement, jointe à l'augmentation du nombre de machines que permet la virtualisation, met une sacrée contrainte sur les tables qu'utilisent les machines pour stocker les coordonnées de leurs voisins (ARP ou NDP en couche 2, l'IGP en couche 3). En couche 2, au lieu de stocker les adresses MAC de ses quelques voisines physiques, une machine devra stocker les milliers d'adresses MAC des machines virtuelles « voisines ». Sans compter le trafic ARP que cela représentera (cd. RFC 6820 ; un million de machines généreront plus de 468 240 ARP par seconde soit l'équivalent de 239 Mb/s).

L'exigence de souplesse et d'agilité, afin de permettre l'utilisation optimale du matériel, nécessite de séparer la configuration du réseau physique et celle du réseau logique. Le RFC donne l'exemple d'un centre de données virtuel qui serait mis en œuvre sur un petit groupe de machines physiques proches. Puis le client veut agrandir son centre et il n'y a pas de place aux alentours, on doit donc lui allouer des machines physiques situées relativement loin dans le centre physique. Cela doit pouvoir marcher, indépendamment du fait que le centre de données du client est désormais réparti en deux endroits.

Autre exigence, que les adresses utilisées sur un centre de données virtuel ne dépendent pas de celles utilisées sur un autre centre virtuel présent sur la même infrastructure physique. Dit autrement, deux clients doivent pouvoir numéroter leurs centres comme ils veulent, sans se coordonner entre eux, et sans tenir compte du plan d'adressage du réseau physique sous-jacent.

Ces exigences sont fort ambitieuses, surtout si on les combine avec la demande que la transmission des paquets suive un chemin optimal. Car la virtualisation, celle du réseau comme celle d'autres ressources, a toujours un coût en termes de performance. Par exemple, lorsqu'une machine virtuelle change de place, le meilleur routeur par défaut peut être différent, alors que cette machine n'est pas consciente de son déplacement et de la nécessité de changer. Autant que possible, l'infrastructure sous-jacente devrait faire cela pour elle. Et encore, un routeur IP classique ne garde pas d'état. Mais s'il y avait des middleboxes à état sur le trajet, comme des pare-feux ?

Pour résumer les services attendus du système de virtualisation : fournir un espace d'adressage isolé, et séparer les paquets de ceux des autres clients (on ne veut pas qu'un tcpdump sur une machine virtuelle montre les paquets d'un autre client). La section 4 décrit la classe de solutions envisagée, celle des réseaux virtuels bâtis au-dessus (d'où le terme d'overlay) des réseaux physiques. Chaque réseau virtuel (pour le centre de données virtuel d'un client) serait un réseau supérieur. Lorsqu'un paquet doit être transmis, il sera encapsulé et voyagera dans un tunnel à l'extrémité duquel il sera décapsulé (technique dit map and encap). Le point d'entrée du tunnel devra faire l'opération de recherche de correspondance (map), indiquant, pour une adresse de destination donnée, quel sera le point de sortie du tunnel. Ce point d'entrée encapsulera ensuite (encap) en mettant en adresse de destination de l'en-tête externe, l'adresse du point de sortie du tunnel. Comme le groupe de travail NVO3 ne considère que les réseaux virtuels mis en œuvre sur la couche 3, les adresses externes (celles de l'en-tête externe du paquet) seront forcément des adresses IP. Les adresses internes (celles du paquet avant encapsulation, ou après décapsulation) peuvent être de couche 2 ou de couche 3.

Il faudra aussi, dans bien des cas, connecter le réseau virtuel à l'extérieur (notamment à l'Internet). Cela nécessitera un routeur connecté à l'extérieur qui, après la décapsulation, transmettra le paquet par les procédés habituels (transmission IP normale, dans le cas d'une connexion à l'Internet). Même chose pour connecter deux réseaux virtuels entre eux. Si ces réseaux fournissent un service de couche 3, c'est de l'interconnexion IP classique, via un routeur.

D'un point de vue plus quantitatif, le RFC note (section 4.4) que ce système de réseaux virtuels devra fonctionner dans un environnement de grande taille (des milliers de commutateurs et des dizaines, voire des centaines de milliers de machines virtuelles) et devra donc bien passer à l'échelle. De plus, le réseau virtuel pourra être très dispersé au sein du réseau physique, avec ses fonctions mises en œuvre sur des tas de machines physiques relativement éloignées, qui travailleront aussi pour beaucoup d'autres réseaux virtuels. Le tout sera sans doute très mouvant (un des buts de la virtualisation est la souplesse, la capacité à changer souvent).

Dans le futur, on construira peut-être des centres de données physiques prévus depuis le début uniquement pour héberger des réseaux virtuels et conçus donc à cet effet. Mais, pour l'instant, ce n'est pas le cas et le RFC demande donc aussi que les solutions de virtualisation soient déployables de manière incrémentale, sans exiger une refonte complète de tout le réseau. Ainsi, les routeurs IP qui sont sur le trajet d'un tunnel ne devraient pas avoir à en être conscients. Pour eux, les paquets du tunnel sont des paquets IP comme les autres. De même, le multicast ne devrait pas être obligatoire (car il est peu déployé).

Le cahier des charges est donc gratiné. Heureusement, il n'est pas prévu que le réseau physique sous-jacent s'étende à tout l'Internet. On parle ici de virtualiser un centre de données, placé sous une administration unique.

Néanmoins, la réalisation de cette vision grandiose va nécessiter du travail. Le RFC envisage deux secteurs de travail : celui du contrôle et celui des données. Pour le contrôle, il faudra trouver des mécanismes efficaces pour créer, gérer et distribuer les tables de correspondance (celles qui permettent au point d'entrée de tunnel de trouver le point de sortie). Cela fera peut-être l'objet d'un tout nouveau protocole. Ce mécanisme devra permettre l'arrivée et le départ d'une machine virtuelle dans le réseau supérieur en mettant à jour ces tables rapidement et efficacement.

Pour les données, il existe déjà pas mal de formats d'encapsulation et, ici, il serait sans doute mieux de les réutiliser. Le RFC décourage donc ceux qui voudraient inventer encore un nouveau format.

La section 5 est justement consacrée aux systèmes existants et qui pourraient fournir des idées, voire des réalisations déjà opérationnelles. D'abord, on peut se servir de BGP et MPLS pour faire des réseaux virtuels IP, le RFC 4364 décrit comment. Cette solution est déjà déployée en production. Sa principale limite, selon notre RFC, est le manque de compétences BGP disponibles, alors que cette solution nécessite du BGP partout. Les mêmes protocoles permettent de faire des réseaux virtuels Ethernet (RFC en cours d'écriture).

Bon, alors, autre solution, utiliser les VLAN de 802.1. Ils fournissent une virtualisation en couche 2 en présentant plusieurs réseaux Ethernet virtuels sur un seul réseau physique. Mais ils ne reposent pas sur IP donc ne sont pas utilisables si on a, par exemple, un équipement comme un routeur sur le trajet. À l'origine, on était limité à 4 096 réseaux différents sur un seul réseau physique, mais cette limite est passée à 16 millions depuis IEEE 802.1aq.

Cette dernière technique, également nommée SPB, utilise IS-IS pour construire ses réseaux virtuels.

Et TRILL ? Il utilise lui aussi IS-IS pour fournir des réseaux de couche 2 différents. En France, cette technique est par exemple déployée chez Gandi.

Plus exotique est le cas de LISP (RFC 9300). Son but principal n'est pas de virtualiser le data center mais il pourrait contribuer, puisqu'il fournit des réseaux virtuels IP au-dessus d'IP (donc, service de couche 3, mis en œuvre avec la couche 3).

Enfin, bien que non cité par le RFC, il faudrait peut-être mentionner VXLAN, bien décrit en français par Vincent Bernat et en anglais par le Network Plumber.

À noter qu'un groupe de travail de l'IETF, ARMD, avait travaillé sur un problème proche, celui posé par la résolution d'adresses IP en adresses MAC (avec ARP ou NDP) dans les très grands centres de données où tout le monde était sur le même réseau de couche 2. Le résultat de leurs travaux avait été documenté dans le RFC 6820.

En résumé, notre RFC conclut (section 6) que le problème est complexe et va nécessiter encore du travail...

Merci à Nicolas Chipaux et Ahmed Amamou pour leur relecture.


Téléchargez le RFC 7364


L'article seul

RFC 7363: Self-tuning Distributed Hash Table (DHT) for REsource LOcation And Discovery (RELOAD)

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : J. Maenpaa, G. Camarillo (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF p2psip
Première rédaction de cet article le 7 septembre 2014


Le mécanisme RELOAD est un mécanisme pair-à-pair pour créer un réseau virtuel au-dessus des réseaux existants, notamment aux fins de téléphonie, messagerie instantanée et diffusion multimédia. Ce RFC étend le protocole Chord tel qu'utilisé par RELOAD de manière à permettre l'ajustement automatique de la DHT à des conditions changeantes (par exemple une augmentation ou diminution du taux de changement des pairs, le churn).

C'est le RFC 6940 qui normalise RELOAD. RELOAD offre le choix de plusieurs algorithmes de gestion du réseau virtuel mais, afin de permettre l'interopérabilité de toutes les machines RELOAD, il existe un algorithme obligatoire, que toute mise en œuvre de RELOAD doit connaître. Les autres algorithmes ne pourront être utilisées que si toutes les machines du réseau sont d'accord. Cet algorithme obligatoire se nomme CHORD-RELOAD et repose sur la DHT Chord. Comme toutes les DHT, Chord s'organise tout seul (pas besoin de chef pour créer le réseau virtuel), passe bien à l'échelle et est très résilient. Pour maintenir la DHT, les machines échangent des informations sur leur état et reconfigurent le réseau virtuel si nécessaire. Pour être le plus optimisé possible, afin de limiter le trafic réseau de gestion, ce travail dépend de paramètres comme le taux de changement des pairs (le churn), ou la taille du réseau. Souvent, ces paramètres sont fixés à l'avance lors de l'initialisation de la DHT. Ce n'est évidemment pas satisfaisant car ils peuvent varier dans le temps. Ils servent à calculer des caractéristiques de la DHT comme la taille de la liste des successeurs, ou comme la taille de la table de routage. Ces caractéristiques devraient pouvoir changer dans le temps, elles aussi. (Voir l'article de Mahajan, R., Castro, M., et A. Rowstron, « Controlling the Cost of Reliability in Peer-to-Peer Overlays ».)

Ces mécanismes de stabilisation qui tournent pour maintenir la DHT sont de deux types, périodique ou bien réactif. Dans l'approche périodique, les informations sont régulièrement échangés entre pairs, qu'il y ait eu des changements ou pas. La DHT est ajustée s'il y a du changement. Dans l'approche réactive, les pairs transmettent la nouvelle information lorsqu'il y a un changement et la DHT s'ajuste alors. On voit que l'approche réactive permet des ajustements plus rapides mais qu'elle écroule vite le réseau si le nombre de changements est trop important, notamment parce qu'elle peut entraîner une boucle de rétroaction. (Voir l'article de Rhea, S., Geels, D., Roscoe, T., et J. Kubiatowicz, « Handling Churn in a DHT ».) Le Chord de RELOAD permet d'utiliser les deux approches, alors que la plupart des mises en œuvre d'une DHT n'utilisent que la stabilisation périodique. La période de diffusion des informations fait partie de ces paramètres qu'on voudrait voir évoluer dynamiquement.

La section 4 de notre RFC résume ce qu'il faut savoir de Chord pour comprendre les changements introduits (je ne la répète pas ici). Les sections 5 et 6 décrivent ces changements, qu'est-ce qui peut être modifié dynamiquement et quand.

Ces changements se traduisent par des nouveaux enregistrements dans les registres IANA RELOAD : nouvel algorithme de gestion du réseau virtuel CHORD-SELF-TUNING, nouvelle extension self_tuning_data, etc.


Téléchargez le RFC 7363


L'article seul

RFC 7353: Security Requirements for BGP Path Validation

Date de publication du RFC : Août 2014
Auteur(s) du RFC : S. Bellovin (Columbia University), R. Bush (Internet Initiative Japan), D. Ward (Cisco Systems)
Pour information
Réalisé dans le cadre du groupe de travail IETF sidr
Première rédaction de cet article le 2 septembre 2014


La sécurité du routage BGP est un sujet de préoccupation sur l'Internet depuis de nombreuses années. Ce protocole ne dispose en effet par défaut d'aucune sécurité, n'importe quel opérateur (ou personne extérieure ayant piraté les routeurs d'un opérateur) pouvant annoncer une route vers n'importe quel préfixe, détournant, par exemple le trafic d'un service vital. Ce manque de sécurité ne vient pas d'une confiance naïve dans la nature humaine, mais plutôt de la nature même de l'Internet : il n'y a pas (heureusement !) de Haute Autorité Supérieure de l'Internet qui connaitrait tous les opérateurs et pourrait les autoriser et les surveiller. Un opérateur ne connait (et encore, pas toujours très bien) que ses voisins immédiats, et ne sait pas quelle confiance accorder aux autres. Dans ces conditions, la sécurisation de BGP est forcément un projet à long terme. La première grande étape avait été la normalisation et le déploiement de RPKI et ROA. L'étape suivante est la sécurisation du chemin entier (et pas uniquement de l'origine), dont ce nouveau RFC est le cahier des charges. En route donc vers BGPsec ! (Le nom PATHsec ne semble plus utilisé.)

Rappelons en effet qu'une annonce BGP (RFC 4271) comprend un chemin, la liste des AS par lesquels l'annonce est passée (et, dans la plupart des cas, celle, en sens inverse, dans lequel un paquet IP émis par le récepteur de l'annonce voyagera s'il veut atteindre l'AS d'origine). Voici un telle annonce, extraite du service de looking glass d'Hurricane Electric :

Prefix: 2001:678:c::/48,  Status: E,  Age: 31d9h14m31s
         NEXT_HOP: 2001:7fa:0:1::ca28:a116, Metric: 0,  Learned from Peer: 2001:7fa:0:1::ca28:a116 (1273)
          LOCAL_PREF: 100,  MED: 1,  ORIGIN: igp,  Weight: 0
         AS_PATH: 1273 2200 2484

Le chemin comprend trois AS, et l'origine, l'AS émetteur de l'annonce, est 2484 (oui, tout à droite : un chemin d'AS se lit de droite à gauche).

Avec les certificats de la RPKI (RFC 6480) et avec le système des ROA (Route Origin Authorization, RFC 6482), on peut désormais (RFC 6811) valider l'origine d'une annonce. Cela protège contre les détournements accidentels (comme celui de YouTube par Pakistan Telecom cité plus tôt), où l'AS d'origine est en général celle du détourneur. Mais lors d'une attaque délibérée, l'attaquant peut tricher sur le chemin et envoyer une annonce avec un chemin d'AS qui semble correct, avec la bonne origine. RPKI+ROA ne protègent pas contre cet attaquant compétent. (Les RFC 4593 et RFC 7132 décrivent en détail les vulnérabilités de BGP.)

Maintenant, place aux exigences que devra satisfaire la nouvelle solution de sécurisation. La section 3 du RFC liste les exigences générales et la section 4 celles spécifiques au traitement effectué lors de la réception d'une annonce BGP. Les exigences générales d'abord, numérotées de 3.1 à... 3.23 (oui, une longue liste). D'abord, 3.1 et 3.2, qui résument le projet complet : le routeur BGP qui reçoit une annonce doit pouvoir déterminer, avec un bon niveau de confiance, que l'origine dans l'annonce (exigence 3.1), et le chemin des AS (AS Path) dans l'annonce (exigence 3.2) sont authentiques. On veut être sûr que l'AS d'origine avait bien le droit d'annoncer ce préfixe, et que le chemin d'AS dans l'annonce reflète bien le chemin suivi par l'annonce (dans l'exemple ci-dessus, que 2484 avait bien le droit d'annoncer le préfixe 2001:678:c::/48, et qu'il a bien transmis l'annonce à 2200, qui l'a lui-même bien transmis à 1273). Attention, il ne s'agit pas uniquement de montrer que le chemin d'AS est possible (ces AS sont bien des pairs...) mais que c'est bien celui qui a effectivement été utilisé. Les autres attributs de l'annonce (comme le MED dans l'exemple ci-dessus) ne sont pas protégés (exigence 3.3) car ils ne sont utilisés que dans un AS ou ses voisins immédiats. (Voir aussi l'exigence 3.10.)

Comme toute technologie nouvelle, BGPsec aura des difficultés de déploiement, dans un Internet très ossifié, et la nouvelle solution devra donc être déployable de manière incrémentale (exigences 3.4 et 3.5) : les routeurs BGPsec devront pouvoir travailler avec les routeurs actuels (exigence 3.13 ; la section 5 reconnait que cette exigence ouvre la voie aux attaques par repli, où un attaquant réussit à faire croire qu'un pair ne gère pas BGPsec et qu'il faut donc se replier sur un protocole non sécurisé). Au début, les routeurs BGPsec auront sans doute des pairs BGPsec et d'autres en BGP non sécurisé et BGPsec doit donc pouvoir être configuré pair par pair (exigence 3.12). La cryptographie peut coûter cher en ressources matérielles et un routeur BGP typique a un CPU moins puissant que celui d'une console de jeu de salon. L'exigence 3.6 autorise donc BGPsec à réclamer du matériel nouveau (par exemple des processeurs cryptographiques spécialisés). La compatibilité avec le matériel existant n'est donc pas exigée.

L'attaquant n'est pas forcément situé dans un garage à des milliers de kilomètres, comme dans le cas des détournements BGP spectaculaires connus. Il peut aussi être mieux placé, par exemple sur le lien entre deux routeurs (l'attaquant peut être sur le même point d'échange que ses victimes...) L'exigence 3.8 impose donc une solution qui marche même en cas d'ennemi sur le lien Ethernet (le RFC note que AO - RFC 5925 - ou TLS - RFC 5246 suffisent).

La cryptographie ne sert pas à grand'chose si on n'a pas de moyen de vérifier l'authenticité des clés utilisés. C'est bien joli de tester l'intégrité d'une signature mais il faut aussi que la clé de signature soit reliée aux ressources qu'on veut protéger (ici, les préfixes d'adresses IP et les numéros d'AS). L'exigence 3.9 dit donc que la solution technique a le droit de s'appuyer sur une infrastructure existante établissant ce lien, comme la RPKI (et qu'évidemment cette infrastructure doit être fiable, cf. section 5). 3.17 ajoute que cette infrastructure doit permettre le choix, par l'opérateur, des entités à qui faire confiance (toutes les mises en œuvre actuelles de la RPKI permettent cela, en éditant la liste des trust anchors).

L'exigence 3.14 concerne une question de gouvernance. Il a souvent été reproché aux projets de sécurisation de BGP de faire un déplacement de pouvoir, des opérateurs BGP aux RIR qui gèrent les points de départ de la RPKI. Avec le BGP traditionnel, le RIR a un pur rôle de registre, il ne prend aucune décision opérationnelle concernant le routage. Avec un BGP sécurisé, ce n'est plus le cas. Pour rassurer les opérateurs, 3.14 rappelle que, signature correcte ou pas, la décision d'accepter, de refuser, de prioriser ou de déprioriser une annonce doit rester locale au routeur et à son opérateur. La question « que doit faire un routeur BGPsec en recevant une annonce invalide ? » n'a donc pas de sens et les futurs RFC n'y répondront pas. BGPsec permettra de dire « cette annonce est invalide », il ne dira pas quelle politique adopter vis-à-vis de ces annonces.

Pas question de sacrifier le secret des affaires à la sécurité BGP : l'exigence 3.18 dit que BGPsec ne doit pas révéler au monde plus que ce que BGP diffuse déjà. On ne pourra donc pas exiger, par exemple, qu'un opérateur publie la liste de ses pairs privés ou de ses clients.

Bien sûr, la solution adoptée devra permettre (exigence 3.19) la journalisation des événements pertinents, notamment en matière de sécurité (c'est plus une exigence pour les mises en œuvre que pour les futurs RFC).

Rien n'étant éternel dans l'Internet, le BGP sécurisé devra ré-authentifier les informations de temps en temps, par exemple suite aux mises à jour de la RPKI (exigence 3.20), même s'il n'y a pas eu de changement BGP (ce protocole n'annonce en effet que les changements : une route qui n'a pas changé ne sera pas ré-annoncée périodiquement, et les sessions BGP peuvent durer des mois, l'annonce montrée au début de cet article était vieille de 31 jours).

Enfin, pour en finir avec les exigences générales, la 3.21 impose que la solution BGPsec permette de changer les algorithmes cryptographiques utilisés, pour faire face aux progrès de la cryptanalyse.

La section 4 décrit les exigences spécifiques au traitement des messages BGP UPDATE qui annoncent une nouvelle route ou bien en retirent une ancienne. C'est le moment où il faut valider (exigences 4.1 et 4.2). L'exigence 4.3 dispense BGPsec d'une protection générale contre les attaques par rejeu, qui resteront donc possibles (retransmission d'une annonce BGP qui était valide mais ne l'est plus, vu les changements dans le graphe BGP). Plus difficile, 4.4 demande qu'on puisse se protéger, au moins partiellement, contre le retrait par l'attaquant d'un message BGP.

Pour terminer, la section 5, sur les problèmes généraux de sécurité, rappelle plusieurs choses importantes notamment le fait que la sécurité du routage ne garantit pas celle des paquets IP (« The data plane may not follow the control plane ») et le fait qu'une sécurité de bout en bout, assurée par les deux machines qui communiquent, reste nécessaire. (Il existe d'autres moyens de détourner le trafic que les attaques BGP.)

Le protocole n'est pas encore terminé (ce RFC n'est qu'un cahier des charges) et il n'existe donc pas encore de mise en œuvre de BGPsec dans du code livré aux opérateurs.

Merci à Bruno Decraene pour les corrections.


Téléchargez le RFC 7353


L'article seul

RFC 7352: Sieve Email Filtering: Detecting Duplicate Deliveries

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : S. Bosch
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 16 septembre 2014


Voici un nouveau test pour le langage de filtrage du courrier Sieve : duplicate permet de tester si un message reçu est un double d'un message déjà arrivé (en général en se fiant au Message-Id:) et, par exemple, d'ignorer le doublon.

Tout le monde a déjà rencontré ce problème : on est inscrit à une liste de diffusion et quelqu'un écrit à la liste en vous mettant en copie. Résultat, on reçoit deux fois le même message. La consommation de ressources réseau et système est négligeable, mais c'est gênant pour le lecteur, qui se retrouve avec deux messages à traiter au lieu d'un. Il serait bien plus pratique de détecter automatiquement le duplicata et de le résorber. Même chose si on est abonné à deux listes de diffusion (encore que, dans ce cas, des informations spécifiques à la liste et ajoutées dans les messages, comme le Archived-At: du RFC 5064, peuvent être utiles).

Beaucoup de gens traitent automatiquement leur courrier, avec des techniques comme Sieve ou procmail et la solution décrite dans ce RFC concerne Sieve (qui est normalisé dans le RFC 5228).

La section 3 de notre RFC décrit le nouveau test duplicate. Il s'utilise ainsi :

require ["duplicate", "fileinto", "mailbox"];

if duplicate {
     fileinto :create "Trash/Duplicate";
}

Ici, si le message est un doublon d'un message existant, il est mis dans le dossier Trash/Duplicate. Mais comment le test duplicate sait-il que le message est un doublon ? Il fonctionne en déterminant, pour chaque message, un identificateur unique. Lors du test, on regarde si l'identificateur est présent dans une base de données et, si ce n'est pas le cas, on l'y stocke. Contrairement à bien des extensions à Sieve, celle-ci va donc nécessiter un mécanisme de mémoire, permettant de garder trace des identificateurs de messages déjà vus.

Notez bien que la base est mise à jour lors du test duplicate, pas à la réception de chaque message (le test duplicate peut ne pas être exécuté dans tous les cas, par exemple s'il dépend d'un autre test). De même, l'ajout de l'identificateur unique dans la base ne doit être fait que si le script Sieve se termine normalement, pour éviter de considérer les messages suivants comme des doublons si le premier n'a pas pu être stocké correctement (disque plein ou autre erreur). Dans certains cas (livraison en parallèle), cela mènera à la distribution de deux copies mais le RFC considère qu'il faut éviter à tout prix la perte accidentelle d'un message donc qu'il vaut mieux quelques doublons en trop plutôt que le classement erroné d'un message comme étant un doublon.

Mais comment est déterminé l'identificateur unique indispensable au classement ? Il existe un en-tête prévu pour cela, Message-ID:, dont la section 3.6.4 du RFC 5322 dit bien qu'il doit être unique (il est en général formé d'une concaténation d'un grand nombre tiré au hasard et du nom de domaine du serveur, par exemple 5400B19D.70904@hackersrepublic.org). Mais, en pratique, on voit parfois des Message-ID: dupliqués et il faut donc prévoir des solutions de secours.

C'est ce que contient la section 3.1 de notre RFC, avec les arguments :header et :uniqueid. Par défaut, l'identificateur unique utilisé par le test duplicate est le Message-ID:. Si on utilise le paramètre :header, c'est le contenu de cet en-tête qui est utilisé comme identificateur unique. Par exemple :

if duplicate :header "X-Event-ID" {
     discard;
   }

va jeter tous les messages dont l'en-tête (non standard) X-Event-ID: a une valeur déjà vue (cas d'un système de supervision envoyant ses informations par courrier).

Si on utilise le paramètre :uniqueid, c'est la valeur indiquée par le paramètre qui est l'identificateur unique. Cela n'a d'intérêt, je crois, qu'en combinaison avec les variables Sieve du RFC 5229 (l'exemple suivant utilise aussi les statuts IMAP du RFC 5232) :

require ["duplicate", "variables", "imap4flags"]
if header :matches "subject" "ALERT: *" {
     if duplicate :uniqueid "${1}" {
       setflag "\\seen";
     }

Ici, la valeur du paramètre :uniqueid vaut la variable ${1}, c'est-à-dire le contenu du sujet du message, après l'étiquette « ALERT: ».

Bien sûr, on utilise :header ou :uniqueid mais jamais les deux en même temps.

Le test duplicate met tous les identificateurs uniques dans une seule base. Si on souhaite avoir plusieurs bases, on utilise le paramètre :handle (section 3.2) :

if duplicate :header "X-Event-ID" :handle "notifier" {
     discard;
   }
if duplicate :header "X-Ticket-ID" :handle "support" {
     # Utilisation d'une base différente: un X-Ticket-ID peut être
     # dans la base notifier mais pas dans la base support.
}

Pour mettre en œuvre le test duplicate, une façon simple de ne pas se compliquer la vie avec plusieurs fichiers est de garder dans un fichier unique un condensat de la concaténation de :handle avec l'identificateur unique.

On souhaite parfois que la mémorisation d'un identificateur unique ne soit que provisoire : si un message arrive un mois après, même s'il a un identificateur déjà vu, c'est probablement un nouveau message qui, par erreur ou par bogue, a un identificateur déjà existant. Il est peu probable que le même message, transmis par deux listes de diffusion différentes, traine autant... Le RFC conseille de ne mémoriser l'identificateur que pendant une semaine et fournit un paramètre :seconds (section 3.3) pour contrôler cette durée :

if not duplicate :seconds 1800 {
    notify :message "[SIEVE] New interesting message"
       "xmpp:user@im.example.com";

La durée est en secondes : ici, on indique une expiration au bout de seulement une demi-heure, peut-être parce qu'on ne veut absolument pas perdre de messages et qu'on craint que les identificateurs ne soient réutilisés trop fréquemment. (L'extension pour une notification par XMPP est dans le RFC 5437.)

La durée indiquée par le paramètre :seconds se compte à partir du premier message vu. Les messages ultérieurs portant le même identificateur ne remettent pas le compteur à zéro. Si on utilise le paramètre :last, par contre, la durée est comptée à partir du dernier message vu : tant que des messages arrivent avec cet identificateur, il n'y a pas d'expiration.

Comme toutes les extensions de Sieve, duplicate doit être annoncée au début du script Sieve (RFC 5228, section 6) :

require ["duplicate"]

Et la sécurité (section 6) ? Pour éviter de se faire DoSer, il faut imposer une limite à la taille de la base (en supprimant les identificateurs les plus anciens). Autrement, un flot important de messages avec chacun un identificateur unique pourrait faire exploser le disque dur.

Un autre problème de sécurité est le risque de faux positif : typiquement, on jette les messages dupliqués. Or des identificateurs censés être uniques, comme le Message-ID: ne le sont pas toujours. On risque donc, avec le test duplicate, de jeter à tort des messages. Il est donc prudent de ne pas détruire les messages dupliqués (action discard de Sieve) mais plutôt de les stocker dans une boîte spéciale (avec fileinto).

Il peut y avoir aussi de légères conséquences pour la vie privée : un utilisateur qui a détruit un message sur le serveur sera peut-être surpris que la base des identificateurs uniques continue à stocker le Message-ID: de ce message, qui peut être assez révélateur. Ceci dit, ce n'est pas pire que les actuels journaux (genre /var/log/mail.log, qui contient aussi ce genre d'informations).

Il y a apparemment deux mises en œuvre de Sieve qui gèrent cette extension.

Sinon, en dehors du monde Sieve, voici la solution traditionnelle avec procmail pour obtenir le même résultat :


:0:/var/tmp/.duplicate.lock
* ? formail -D 8192 $HOME/.duplicate.procmail-cache
$HOME/.mail-duplicates

Qui se lit : si le Message-ID: est déjà dans le fichier $HOME/.duplicate.procmail-cache (qui garde les 8 192 dernières entrées), on ne le distribue pas dans la boîte normale, mais dans $HOME/.mail-duplicates.


Téléchargez le RFC 7352


L'article seul

RFC 7351: A Media Type for XML Patch Operations

Date de publication du RFC : Août 2014
Auteur(s) du RFC : E. Wilde (UC Berkeley)
Pour information
Première rédaction de cet article le 31 août 2014


Vous voulez patcher des documents XML, c'est-à-dire envoyer juste la différence entre deux documents à un serveur pour qu'il applique les opérations de transformation qui vont rendre les deux documents identiques ? Le RFC 5261 fournissait un format de description de ces patches. Il manquait toutefois un type MIME décrivant ce format. C'est désormais fait, avec la normalisation dans ce RFC du type de média application/xml-patch+xml.

Outre le RFC 5261, qui décrivait un format pour les patches XML, l'un des protocoles qui utilisent le plus XML, HTTP, a une opération PATCH qui permet de mettre à jour une ressource Web distante (RFC 5789). HTTP, comme d'autres protocoles de l'Internet, étiquette les ressources envoyées ou récupérées avec un type de média (dit aussi « type MIME », cf. RFC 6838), et pour utiliser le format du RFC 5261 avec l'opération PATCH du RFC 5789, il fallait un tel type, désormais application/xml-patch+xml. (Pour l'opération PATCH, les serveurs HTTP choisissent librement les formats de patch qu'ils gèrent, il n'existe pas de format obligatoire. Ils peuvent accepter diff, ce nouvel application/xml-patch+xml et/ou bien d'autres.)

Notez que le RFC 5261 définissait un type MIME mais uniquement pour les messages d'erreur, application/patch-ops-error+xml.

Outre l'enregistrement du type MIME application/xml-patch+xml, ce nouveau RFC corrige également les erreurs du RFC 5261, liées à la complexité de la combinaison entre XPath et les namespaces XML.

Une des raisons pour lesquelles le RFC 5261 ne définissait pas de type MIME est qu'il ne définissait pas un format complet mais juste les éléments XML indiquant l'ajout, la suppression ou la modification d'éléments XML dans le document cible. Notre nouveau RFC, lui, définit un format complet, où les éléments de patch sont inclus dans un document dont l'élément racine est <patch> (et qui sera donc servi avec le type MIME application/xml-patch+xml). Voici un exemple d'un tel document :


<p:patch xmlns:p="urn:ietf:rfc:7351">
     <p:add sel="/section"><para>Nouveau paragraphe, lorem, ipsum, dolor, etc</p:add>
</p:patch>

Notez que l'élément à la racine, <patch> et les éléments du RFC 5261 comme <add> sont dans le même espace de noms urn:ietf:rfc:7351. À part ça, on peut reprendre les exemples du RFC 5261 tels quels (voir la section 2.2 de notre nouveau RFC).

L'annexe A contient un certain nombre de détails techniques. D'abord, une discussion détaillée du problème de la correspondance de deux espaces de noms en XML, problème difficile et où le RFC 5261 s'était planté. Ensuite, le problème des espaces de noms dans le document résultat, où les règles ne sont pas les mêmes en XML et en XPath.

Pour comprendre ce dernier problème, regardez ce document XML :


<x xmlns:a="tag:42">
       <y/>
</x>

L'espace de noms est le même pour les deux éléments XML (URI tag:42, qui utilise de manière inhabituelle le RFC 4151). Mais dans ce document XML quasi-identique :


<x xmlns:a="tag:42">
       <y xmlns:a="tag:42"/>
</x>

Chaque élément a sa propre déclaration d'espace et de noms et, si le patch veut modifier /x/namespace::a, ce sélecteur XPath ne désigne que le nœud <x>, et <y> ne doit pas, lui, être modifié. Or, XPath ne fournit pas assez d'informations pour cela, un logiciel de patch XML doit donc trouver une autre façon de déterminer où stopper sa récursion (par exemple en utilisant DOM). Une mise en œuvre naïve du RFC 5261 qui ne s'appuyerait que sur XPath échouerait dans des cas comme celui indiqué dans ce paragraphe.

Enfin, l'annexe B contient une grammaire ABNF des expressions autorisées par le sous-ensemble de XPath du RFC 5261, pour ceux qui n'aiment pas le W3C Schema qu'utilisait le premier RFC.

Des mises en œuvre complètes de XML Patch+ ce nouveau RFC ? Il y en a apparemment une dans le xDB d'EMC.


Téléchargez le RFC 7351


L'article seul

RFC 7344: Automating DNSSEC Delegation Trust Maintenance

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : W. Kumari (Google), O. Gudmundsson (Shinkuro), G. Barwood
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 4 septembre 2014
Dernière mise à jour le 12 septembre 2014


Un des obstacles à un plus large déploiement de DNSSEC est la nécessité de faire mettre, par le gestionnaire de la zone parente, un enregistrement faisant le lien avec la clé de signature de la zone fille. Cet enregistrement, nommé DS (pour Delegation Signer) est indispensable pour établir la chaîne de confiance qui va de la racine du DNS à la zone qu'on veut sécuriser. Mais, autant signer sa zone ne nécessite que des actions locales, qu'on peut faire tout seul, mettre cet enregistrement DS dans la zone parente nécessite une interaction avec une autre organisation et d'autres personnes, ce qui est souvent compliqué et réalisé d'une manière non standardisée. Ce nouveau RFC propose une méthode complètement automatique, où la zone fille publie les enregistrements de clé localement, et où la zone parente va les chercher (via le DNS) et les recopier.

Faire passer de l'information de la zone fille à la zone parente se fait actuellement avec des mécanismes ad hoc, par exemple via un formulaire Web ou une API chez le BE (cf. section 2.2 du RFC). Un exemple de l'opération est décrit dans mon article sur le remplacement d'une clé. Il faut transmettre les clés (ou leur condensat, le futur enregistrement DS, cf. RFC 4034) à la zone parente pour que la zone soit vérifiable avec DNSSEC. Et il faut le refaire lorsqu'on change la clé. Comme pour tout processus qui franchit les frontières entre deux organisations humaines, bien des choses peuvent aller de travers, surtout lorsqu'il est partiellement effectué manuellement. Et l'absence de techniques normalisées rend difficile le changement de prestataire.

Notre nouveau RFC propose donc une autre méthode : le gestionnaire de la zone signée publie ses clés uniquement dans sa zone, et la zone parente l'interroge à la recherche de nouvelles clés à publier. La sécurité du processus est assurée par les signatures DNSSEC. Ce mécanisme ne marche donc que pour les mises à jour, pas pour la configuration initiale (puisque celle-ci ne peut pas être vérifiée par DNSSEC). Depuis, le RFC 8078 a présenté un moyen de faire la configuration initiale.

En attendant le déploiement du RFC 8078, ce mécanisme supprimera néanmoins une opération pénible et qui est apparemment mal maitrisée par bien des gérants de zones DNS. Naturellement, les anciennes solutions resteront disponibles pour ceux qui préfèrent, et pour le premier envoi des clés, lorsque la zone devient signée. À noter que cette solution est spécifique aux informations DNSSEC (clés de signature). Il y a d'autres informations qu'on pourrait vouloir transmettre automatiquement au parent (serveurs de noms, colle) mais cela dépendra d'autres RFC.

Un petit mot de terminologie : il existe plusieurs mécanismes de gestion (au sens organisationnel) de la relation entre une zone DNS parente et une zone fille. Cette relation peut être directe (par exemple, dans une université, entre l'administrateur de la zone du département de mathématiques et l'administrateur de la zone de l'université), indirecte (passage par un intermédiaire, le BE, imposé, celui-ci communiquant ensuite avec le registre, souvent via EPP) ou complexe (gestion de la racine où le gérant d'un TLD passe par l'ICANN pour un changement qui est fait par le NTIA et Verisign). Pour traiter tous ces cas, le RFC utilise le terme d'« agent du parent » (parental agent) pour désigner l'entité avec lequel le gestionnaire de la zone fille communique, que cette entité soit le gestionnaire de la zone parente ou pas. L'agent du parent est donc l'administrateur de la zone de l'université dans le premier cas, le BE dans le second et l'ICANN dans le troisième. L'annexe A de notre RFC revient en détail sur ces différents modèles et leurs conséquences.

À noter d'ailleurs une complication supplémentaire : le titulaire de la zone fille ne gère pas forcément ses serveurs DNS lui-même (section 2.2.1 du RFC). Il a pu les déléguer à un tiers, l'hébergeur DNS, ou à son agent du parent (il est fréquent que les gens qui louent un nom de domaine à un BE lui confient également l'hébergement DNS). Dans ce dernier cas, tout est simple, l'utilisateur active la signature DNSSEC (ça peut même être fait par défaut, pour épargner ce choix technique à l'utilisateur) et l'hébergeur DNS s'occupe de tout.

Autre point à garder en tête : on peut transmettre à la zone parente un enregistrement DS (le condensat d'une clé) ou bien DNSKEY. Certains gérants de zones demandent un DS, d'autres un DNSKEY, d'autres acceptent les deux. La solution technique de ce RFC marche dans tous les cas.

Voyons maintenant la solution technique choisie. Elle est décrite en section 3. Deux nouveaux enregistrements DNS sont créés, CDS et CDNSKEY, correspondant respectivement aux DS et DNSKEY. Ils sont publiés dans la zone fille (le C initial veut dire Child) et indiquent à la zone parente les informations que la zone fille veut lui transmettre. Le CDS, type 59, a le même format que le DS (RFC 4034, section 5) et le CDNSKEY, type 60, le même format que le DNSKEY (RFC 4034, section 2). Comme on l'a vu plus haut, certains parents demandent un DS, d'autre un DNSKEY. La fille peut publier juste le CDS ou juste le CDNSKEY, selon la parente, ou bien les deux.

L'utilisation de CDS et de CDNSKEY (section 4) est facultative. S'ils sont absents, tout continue comme aujourd'hui. S'ils sont présents, la zone parente qui les détecte peut les publier sous forme d'enregistrement DS (en copiant le CDS ou bien en calculant un DS à partir du CDNSKEY). CDS et CDNSKEY doivent évidemment être signés avec DNSSEC (autrement, on pourrait empoisonner la zone parente) et doivent correspondre à ce qui est réellement dans la zone fille (par exemple, le CDS doit correspondre à une DNSKEY réellement existante). Le mécanisme marche aussi pour les suppressions, la zone parente pouvant retirer les DS qui n'ont plus de CDS mais avec des précautions (section 4.1) : pas question de « dé-sécuriser » la zone en retirant tous les DS valides, par exemple (la possibilité de retrait de DS de la zone parente est, à mon avis, pas très clairement expliquée dans le RFC, mais le RFC 8078 a présenté une solution). La parente peut ensuite prévenir la fille que les nouveaux DS ont été pris en compte et les anciens retirés (par exemple par courrier). Une fois que c'est fait, la zone fille peut supprimer CDS et CDNSKEY. (Attention à bien les supprimer tous : si on en supprime certains, la zone parente va retirer les DS correspondants. Aucun CDS/CDNSKEY ne veut pas dire « supprimer tous les DS » mais « ne faire aucun changement .)

(Au passage, pourquoi avoir un CDNSKEY, pourquoi la zone parente ne regarde pas directement le DNSKEY ? Il y a deux raisons : la première est qu'en général, on ne veut pas publier le DS tout de suite, on souhaite d'abord tester la configuration DNSSEC pendant plus ou moins longtemps. La zone va donc rester signée mais pas rattachée de manière sécurisée à sa parente. Ce rattachement doit être volontaire et explicite car, à partir du moment où il est fait, les erreurs DNSSEC ne pardonnent plus. La deuxième raison est qu'il peut y avoir plusieurs clés dans la zone fille, dont certaines sont, par exemple, en cours de retrait et ne doivent pas être utilisées pour faire un DS.)

Comment l'agent du parent sait-il qu'une zone fille a publié de nouveaux CDS ou CDNSKEY ? Une possibilité est l'interrogation régulière des zones. C'est simple à faire et automatique pour le gérant de la zone fille mais cela peut poser des problèmes de performance pour, par exemple, un gros BE qui gérerait des centaines de milliers de zones (section 6.1). Une autre est de fournir aux clients un bouton à pousser sur un formulaire Web quelconque, indiquant qu'il y a du nouveau dans la zone. Cette deuxième possibilité peut aussi permettre, si le formulaire Web est authentifié et qu'on présente à l'utilisateur le DS pour vérification, de faire l'ajout initial du DS (cela suppose que l'utilisateur fasse une vérification sérieuse… voir à ce sujet le RFC 8078). On peut aussi envisager une API simple pour cela, mais rien n'est encore normalisé. (C'était l'une des plus grosses controverses lors du développement de ce RFC : la méthode décrite ici doit-elle être la méthode officielle ou bien juste une méthode parmi d'autres ? Pour l'instant, c'est la seule normalisée mais elle n'est nullement obligatoire.)

La section 9 du RFC est l'analyse de sécurité de ce système. En automatisant le plus possible la transmission des clés de la fille à la parente, on espère augmenter la sécurité, en diminuant les risques d'erreurs humaines (copier/coller maladroit d'une DS dans un formulaire Web, par exemple). Cette décroissance des incidents aiderait au déploiement de DNSSEC. Mais il n'y a pas de miracle : le gérant de la zone fille pourra toujours faire des bêtises comme de supprimer de sa zone toutes les DNSKEY correspondant aux DS dans la zone parente.

Si le système d'avitaillement de la zone fille est piraté, le pirate pourra évidemment créer des CDS et CDNSKEY signés. Bien sûr, aujourd'hui, il peut déjà créer des enregistrements mais, dans ce cas, cela permettra peut-être d'étendre la durée de l'attaque (il faudra republier les bons CDS/CDNSKEY et attendre la mise à jour de la parente).

Dans le cas où la la gestion de la zone fille est sous-traitée à un hébergeur DNS, cette nouvelle technique a l'avantage que l'hébergeur DNS peut publier les CDS/CDNSKEY lui-même et donc mettre à jour la zone parente sans qu'on ait besoin de lui confier le mot de passe du compte chez le BE.

On peut mettre facilement des CDS et des CDNSKEY dans BIND depuis la version 9.10.1. Sinon, quels « agents de parent » mettent en œuvre ce RFC ? Pour l'instant, le serveur FRED, et ça marche dans .cz. Et, sinon, il existe un logiciel public qui fait ce travail de récupération et validation des CDS et CDNSKEY, cds-monitor. Jan-Piet Mens a fait un récit de son utilisation avec PowerDNS et BIND et l'outil dnssec-cds.


Téléchargez le RFC 7344


L'article seul

RFC 7343: An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers Version 2 (ORCHIDv2)

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : J. Laganier (Luminate Wireless), F. Dupont (Internet Systems Consortium)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF hip
Première rédaction de cet article le 21 septembre 2014


Une nouvelle pierre dans la construction d'une éventuelle future architecture Internet séparant identificateur et localisateur, les ORCHID sont des identificateurs dont la forme est celle d'une adresse IPv6 (afin de pouvoir être utilisés dans les API qui attendent des adresses IP). Ils sont typiquement utilisés dans le cadre de protocoles comme HIP (RFC 9063). Pour les distinguer, notre RFC réserve le préfixe 2001:20::/28. Si vous voyez une telle « adresse IP », ne vous attendez pas à pouvoir forcément la « pinguer », elle n'a pas vocation à être routable, c'est un pur identificateur.

ORCHID signifie Overlay Routable Cryptographic Hash Identifiers. L'adresse IP traditionnelle joue un rôle double, localisateur d'une machine dans le réseau et identificateur d'une machine. ORCHID est prévu pour les protocoles qui séparent identificateur et localisateur (comme HIP) et sert d'identificateur. Leur forme physique est celle d'une adresse IPv6, afin de ne pas changer les API et les applications qui les utilisent (on peut publier des ORCHID dans le DNS, faire un ssh 2001:20::1:42 si on est sur une machine HIP, etc). Bien sûr, il serait plus propre de tout refaire de zéro, avec de nouvelles API, plus adaptées à cette séparation identificateur/localisateur, mais c'est irréaliste. (Dommage, cela aurait permis d'utiliser tout le ::/0 pour ORCHID au lieu de les limiter à un préfixe. Voir la section 4 à ce sujet.)

Voilà pourquoi vous ne trouverez pas des adresses de ce préfixe dans les paquets IPv6 ordinaires (l'identificateur est traduit en localisateur par HIP avant que le paquet soit mis sur le câble). Les paquets ayant ces adresses sont routables dans le réseau virtuel HIP, pas dans l'Internet actuel. Les ORCHID sont donc utilisés « entre machines consentantes », dit le RFC. Un préfixe spécial, le 2001:20::/28, est réservé par l'IANA pour éviter les confusions avec les « vraies » adresses IP. Il figure dans le registre des adresses spéciales (RFC 6890). Cela permet aussi des choses comme une mise en œuvre de HIP sous forme d'un programme extérieur au noyau du système, utilisant le préfixe pour distinguer facilement les ORCHID, et permettre au noyau de transmettre les paquets utilisant des ORCHID à ce programme extérieur. Dans tous les cas, l'utilisation des ORCHID nécessitera un programme (dans le noyau ou extérieur) qui fera la correspondance entre les identificateurs maniés par les applications (les ORCHID) et les localisateurs mis dans l'en-tête des paquets IPv6 envoyés sur le réseau.

Les ORCHID ont été normalisés pour la première fois dans le RFC 4843. Ce nouveau RFC est la version 2, très différente (nouveau préfixe, nouvel algorithme de construction, voir l'annexe B pour toutes les différences entre ORCHID v1 et ORCHID v2).

Les ORCHID ont les propriétés suivantes :

  • Quasi-unicité (sauf malchance, voir l'annexe A),
  • Sécurité, via une chaîne de bits utilisée pour leur construction (la plupart du temps, une clé cryptographique, qui servira à authentifier l'ORCHID),
  • Limitation au préfixe 2001:20::/28,
  • Routabilité dans l'overlay, pas dans le réseau sous-jacent (l'Internet d'aujourd'hui).

Comme les adresses CGA (RFC 3972), les ORCHID sont en général utilisés avec de la cryptographie, la section 2 de notre RFC détaillant le mécanisme de construction d'un ORCHID. On part d'un certain nombre de paramètres, un OGA ID (ORCHID Generation Algorithm IDentifier) qui identifie la fonction de hachage utilisée, un contexte qui identifie le protocole qui utilise ORCHID (la liste possible est à l'IANA), une chaîne de bits et quelques autres. La chaîne de bits est censée être unique. En pratique, ce sera souvent une clé publique. Il y aura un contexte pour HIP, et un pour les futurs autres protocoles qui utiliseront ORCHID. On concatène chaîne de bits et contexte, on les condense et on a un identificateur de 96 bits de long. Il n'y a plus ensuite qu'à ajouter le préfixe 2001:20::/28 et l'identificateur OGA (4 bits) pour avoir l'ORCHID complet de 128 bits.

Maintenant qu'on a construit des ORCHID, comment s'en sert-on ? La section 3 décrit les questions de routage et de transmission. Les routeurs ne doivent pas traiter les ORCHID différemment des autres adresses IP par défaut (afin d'éviter de gêner le déploiement ultérieur de nouveaux usages des ORCHID). Par contre, ils peuvent être configurés pour les rejeter (on peut changer la configuration plus tard, mais c'est plus difficile pour le code), par exemple par une ACL.

La section 4 revient sur les décisions qui ont été prises pour la conception des ORCHID. La principale était la longueur du préfixe. Un préfixe plus court aurait laissé davantage de place pour le résultat de la fonction de condensation, résultat qu'on doit tronquer à 96 bits, au détriment de la sécurité. Mais cela aurait avalé une plus grande partie de l'espace d'adressage d'IPv6. Pour gagner des bits, le contexte (le protocole utilisé) n'est pas dans l'ORCHID lui-même mais dans les paramètres d'entrée qui seront condensés. On ne peut donc pas, en regardant un ORCHID, connaître le contexte (on peut connaitre la fonction de hachage utilisée, via l'OGA ID qui, lui, est dans l'ORCHID final). On ne peut que vérifier a posteriori que le contexte supposé était le bon. Cela comble un des principaux défauts d'ORCHID v1 (dans le RFC 4843), l'absence d'agilité cryptographique (la possibilité de changer d'algorithme suite aux progrès de la cryptanalyse). Par exemple, dans l'ancienne norme ORCHID, HIP était restreint à utiliser SHA-1.

Si vous vous lancez dans l'analyse sécurité d'ORCHID, regardez aussi la section 5. ORCHID dépend de la sécurité des fonctions de condensation (RFC 4270) pour garantir la liaison sécurisée entre une clé publique et l'ORCHID. La nécessité de tronquer leur résultat, pour tenir dans les 128 bits d'une adresse IPv6 (moins le préfixe et le OGA ID) a affaibli ces fonctions (le RFC 6920, quoique parlant d'un sujet très différent, discutait déjà des conséquences de cette troncation).

L'annexe A du RFC, elle, se penche sur les risques de collision. Après tout, chaque ORCHID est censé être unique. Or, il n'y a pas de registre central des ORCHID : chacun les génère de son côté. Il n'y a donc qu'une unicité statistique : il est très improbable que deux machines génèrent le même ORCHID.

Et l'annexe B résume les différences entre les ORCHID v1 du RFC 4843 et les v2 de ce RFC 7343 :

  • Mécanisme d'agilité cryptographique en mettant l'identificateur de l'algorithme (OGA ID) dans l'ORCHID,
  • Suppression de plusieurs discussions intéressantes mais pas indispensables pour créer des ORCHID (voir le RFC 4843 si vous êtes curieux),
  • Nouveau préfixe IPv6, 2001:20::/28, remplaçant l'ancien 2001:10::/28, désormais restitué à l'IANA et à nouveau libre. Les ORCHID v2 sont donc totalement incompatibles avec les v1.

Les programmeurs de HIP for Linux et OpenHIP ont déjà promis de modifier leur code pour s'adapter à ces nouveaux ORCHID (qui sont désrmais dans la v2 de la norme HIP, RFC 7401).

Merci aux deux auteurs du RFC pour leur relecture de cet article.


Téléchargez le RFC 7343


L'article seul

RFC 7342: Practices for Scaling ARP and Neighbor Discovery (ND) in Large Data Centers

Date de publication du RFC : Août 2014
Auteur(s) du RFC : L. Dunbar (Huawei), W. Kumari (Google), I. Gashinsky (Yahoo)
Pour information
Première rédaction de cet article le 28 août 2014


Les protocoles de résolution d'adresse IP en adresse MAC sur un réseau local, ARP pour IPv4 et ND pour IPv6, fonctionnent par diffusion. Le client crie à tout le monde « qui connaît 2001:db8:376:ab::23:c0f ? » et la machine qui se reconnaît répond. L'inconvénient de ce mécanisme est qu'il passe mal à l'échelle : lorsque des centaines de milliers de machines virtuelles sont sur le même réseau local dans un grand data center, et crient toutes en même temps, le réseau va souffrir. Ce nouveau RFC ne propose pas de solution mais décrit les pratiques qui sont actuellement utilisées pour limiter les dégâts.

Le problème des protocoles ARP (RFC 826) et ND (RFC 4861) dans les grands data centers a été décrit en détail dans le RFC 6820. Le problème a toujours existé mais est devenu bien plus sérieux depuis qu'on pratique massivement la virtualisation et que le nombre de machines qui font de l'ARP ou du ND a explosé. Le désir de souplesse dans la gestion de ces machines fait qu'il est difficile d'architecturer le réseau en fonction de ce problème. Par exemple, faire de chaque machine physique un réseau limiterait la diffusion des requêtes ARP ou ND mais obligerait à changer l'adresse IP des machines virtuelles lorsqu'elles passent d'une machine physique à une autre, annulant ainsi cette souplesse que fournit la virtualisation.

Les trois principales conséquences de cette augmentation du trafic ARP/ND :

  • Consommation de capacité réseau au détriment du trafic « utile » (bien sûr, avec les liens modernes à 10 Gb/s, c'est moins grave qu'avant),
  • Augmentation de la charge de travail des routeurs, sans doute la conséquence la plus gênante aujourd'hui (cf. une étude de Merit),
  • En IPv4, augmentation de la charge de toutes les machines car la diffusion est totale (IPv6 utilise le multicast). Là encore, l'augmentation des ressources de calcul des équipements réseau peut aider : un test en laboratoire indique que 2 000 messages ARP par seconde consomment 2 % du CPU d'un serveur.

Comme expliqué dans la section 3, le réseau interne d'un grand data center a en général une de ces trois architectures :

  • Connectivité au niveau 3 (L3), c'est-à-dire qu'on fait du routage IP dans le data center,
  • Tout en niveau 2, le data center est un grand réseau L2,
  • Virtualisation du réseau (overlay).

Pour chacune de ces architectures, une section de notre RFC décrit les pratiques actuelles pour limiter l'effet des protocoles de résolution.

Dans le premier cas (réseau L3), c'est la section 4. Les réseaux utilisant le routage mettent un routeur IP dans chaque baie, voire un pour chaque machine physique. Gros avantage : la diffusion des messages ARP ou ND, qui ne va pas au-delà du premier routeur, est très limitée. Le problème décrit dans le RFC 6820 disparaît donc complètement. Inconvénient : on n'a plus aucune souplesse. Changer une VM de baie, voire de serveur physique dans la même baie, oblige à la changer d'adresse IP, ce qui va casser les sessions en cours, nécessiter une reconfiguration, etc. Cette architecture ne convient donc que lorsque le data center est assez statique, ou bien lorsque les services qui y tournent peuvent supporter ces changements d'adresses IP.

Variante sur cette architecture (non mentionnée dans le RFC mais que j'emprunte à Vincent Bernat), annoncer dans le protocole de routage interne une route par machine (un préfixe /32 en IPv4 et /128 en IPv6). Cela résout ce problème et permet de tout faire en L3, mais, si on a des centaines de milliers de machines, le protocole de routage va souffrir.

Deuxième architecture possible (section 5), le grand réseau L2 où toute diffusion va frapper toutes les machines. Cette fois, le problème des messages de diffusion ARP ou ND va se poser en grand. Les routeurs qui vont faire communiquer ce réseau L2 avec l'extérieur vont souffrir. Comment diminuer cette souffrance ? D'abord, pour le cas où une machine cherche à communiquer avec une machine externe et doit donc résoudre l'adresse IP du routeur en adresse MAC. Si cette adresse MAC n'est pas dans le cache de la machine, elle envoie une requête, et le routeur doit la traiter, ce qui se fait en général via le CPU généraliste du routeur, pas dans les circuits spécialisés.

Première solution : pré-charger l'adresse MAC du routeur dans toutes les machines (options -s et -f de la commande arp sur Unix). Deuxième solution, plus souple : que le routeur envoie des réponses ARP ou ND spontanément, sans attendre les requêtes (cf. RFC 5227). Ainsi, son adresse MAC sera quasiment toujours dans les caches. Cela marche très bien pour IPv4. Mais cela ne résout pas complètement le problème pour IPv6 : ce protocole impose l'envoi de requêtes au routeur, pour valider que la liaison avec celui-ci fonctionne (RFC 4861, section 7.3, notamment « Receipt of other Neighbor Discovery messages, such as Router Advertisements and Neighbor Advertisement with the Solicited flag set to zero, MUST NOT be treated as a reachability confirmation. Receipt of unsolicited messages only confirms the one-way path from the sender to the recipient node. In contrast, Neighbor Unreachability Detection requires that a node keep track of the reachability of the forward path to a neighbor from its perspective, not the neighbor's perspective. »). Malgré cela, notre RFC recommande que cette pratique soit utilisée pour les réseaux IPv4 et que l'on travaille à améliorer la situation pour IPv6, dans la ligne du RFC 7048.

Second cas dans ce grand réseau L2, celui du traitement du trafic entrant dans le réseau. Le routeur de bordure reçoit un paquet pour une machine interne. L'adresse MAC de cette dernière n'est pas dans le cache ARP ou ND du routeur. Il faut donc émettre une requête ARP ou ND, ce qui fait du travail pour le CPU et utilise de nombreux tampons d'attente. Première solution : limiter la quantité de requêtes par seconde. Celles en excès seront simplement abandonnées. Deuxième solution : en IPv4, le routeur peut également surveiller le trafic ARP des machines afin d'apprendre leurs adresses MAC et de remplir son cache à l'avance. En IPv6, le trafic ND n'est pas toujours diffusé et donc pas toujours écoutable, et cette solution n'aide donc pas tellement. Notre RFC recommande cette deuxième solution, au moins pour IPv4, en notant que, s'il est possible que beaucoup de paquets soient destinés à des machines éteintes ou injoignables (et qui n'émettent donc jamais), il vaut mieux trouver d'autres solutions.

De même qu'on peut pré-configurer statiquement l'adresse MAC du routeur dans toutes les machines, on peut aussi pré-configurer statiquement les adresses MAC de toutes les machines dans les routeurs. C'est évidemment un cauchemar à gérer (ceci dit, ce n'est pas fait à la main pour chaque VM, mais typiquement à l'intérieur du programme de création des VM) et il n'existe pas de mécanisme standard pour cela. Le RFC suggère que l'IETF regarde si on peut augmenter des protocoles comme NETCONF pour faire ce genre d'opérations.

Autre approche, rendre la résolution ARP hiérarchique (voir RFC 1027 et les travaux ultérieurs comme cette proposition). Au lieu de n'avoir que deux niveaux, le client et le serveur, on pourrait avoir un relais ARP spécialisé qui puisse répondre aux requêtes, garder en cache les résultats, etc. Le RFC 4903 déconseillait cette approche, notamment parce qu'elle peut gêner le déplacement rapide d'une machine (il faut alors invalider les caches) et parce qu'elle est incompatible avec SEND (que personne n'utilise, il est vrai, cf. RFC 3971). Même possibilité, au moins en théorie, avec ND (RFC 4389 décrit un relais mais qui ne réduit pas le nombre de messages). Au bout du compte, notre RFC ne recommande pas cette technique, bien qu'elle ait parfois été déployée.

Troisième architecture possible pour un grand data center, les réseaux virtuels (overlays, section 6). Il existe des normes pour cela (TRILL ou IEEE 802.1ah) et plusieurs projets. L'idée est que seul un petit nombre d'adresses MAC sont visibles dans les paquets qui circulent entre les baies, les paquets étant décapsulés (révélant l'adresse MAC interne) à un endroit très proche des VM. Les équipements qui font l'encapsulation et la décapsulation doivent être suffisamment dimensionnés puisqu'ils se taperont presque tout le trafic ARP et ND. L'intensité du travail peut être diminuée par des correspondances statiques (comme cité pour les autres architectures) ou bien en répartissant astucieusement la charge entre les machines d'encapsulation/décapsulation.

La section 7 du RFC résume les recommandations : pas de solution miracle qui conviendrait à tous les cas, plusieurs solutions mais aucune parfaite. Certaines améliorations nécessiteraient un changement des protocoles et cela fait donc du travail possible pour l'IETF :

  • Atténuer certaines obligations de ND concernant la bidirectionnalité, obligations qui interdisent actuellement de profiter complètement des messages ND spontanés.
  • Spécifier rigoureusement les sémantiques des mises à jour (lorsqu'on reçoit une réponse ARP ou ND alors qu'on a déjà l'information en cache).
  • Développer des normes pour des relais/caches pouvant stocker les réponses ARP ou ND et les redistribuer largement. Le RFC 4389 peut donner des idées.

À l'heure actuelle, il n'y a plus de groupe de travail IETF sur ce sujet et ce développement de nouvelles solutions risque donc de ne pas être immédiat.


Téléchargez le RFC 7342


L'article seul

RFC 7337: Content Distribution Network Interconnection (CDNI) Requirements

Date de publication du RFC : Août 2014
Auteur(s) du RFC : K. Leung (Cisco), Y. Lee (Comcast)
Pour information
Réalisé dans le cadre du groupe de travail IETF cdni
Première rédaction de cet article le 18 août 2014


Le projet IETF CDNI (Content Delivery Network Interconnection) vise à permettre l'interconnexion de CDN, ces réseaux de serveurs répartis dans le monde qui servent à amortir la charge des serveurs Internet les plus populaires. CDNI a été expliqué dans le RFC 6707 et trois études de cas ont fait l'objet du RFC 6770. Ce troisième RFC du projet décrit les exigences formelles, le cahier des charges du projet. (Le cadre général de la solution technique adoptée est dans le RFC 7336.)

Le projet est important car, aujourd'hui, les CDN ne coopèrent pas, en partie en raison du manque d'interfaces standards. Si un CDN très présent en Amérique veut s'associer avec un autre CDN fort en Europe, à la grande joie de leurs clients respectifs, qui auront ainsi un meilleur service dans les deux cas, ils doivent développer un système ad hoc. Le but de CDNI est de développer cette interface standard (RFC 7336), de manière à ce que plusieurs CDN puissent coopérer et apparaître à l'utilisateur comme un seul service. Dans le futur, une fois le projet complété, le CDN d'origine (« CDN amont ») pourra faire en sorte que le CDN qui l'aide (« CDN aval ») ait accès au même contenu et puisse le servir lui-même aux clients.

Les exigences listées par ce cahier des charges sont classées par priorité : « haute » signifie que cette exigence est impérative, même si elle est compliquée à réaliser, « moyenne » que l'exigence est importante, qu'elle doit être satisfaite sauf si, par sa complexité, elle entraîne un retard dans le projet et, enfin, « basse » est utilisé pour les exigences certes utiles mais pas nécessaires au projet.

Les exigences sont rangées selon l'interface à laquelle elles s'appliquent. Une interface (RFC 7336) est un ensemble de fonctions du CDN, qu'on peut appeler en utilisant des mécanismes normalisés, et qui correspondent à un ensemble de services proches. Par exemple, LI (Logging Interface) regroupe les services de journalisation, permettant à un CDN amont d'avoir des informations sur l'activité d'un CDN aval associé.

Je ne vais pas ici recopier les nombreuses exigences, me focalisant sur celles de niveau élevé, donc impératives à satisfaire.

D'abord, en section 3, les exigences générales, indépendantes de l'interface. La solution ne doit évidemment pas nécessiter de changer les clients (exigence GEN-2), par exemple les navigateurs Web. Elle ne doit pas nécessiter que le fournisseur de contenu change son système de publication (GEN-3) : si celui-ci permet de publier dans un CDN, il doit permettre de profiter de l'interconnexion. Elle doit être assez abstraite pour que chaque CDN soit une « boîte noire » pour les autres, sans avoir besoin de publier de l'information interne. Elle doit marcher au moins lorsque la délivrance au client est faite en HTTP (exigence GEN-5, il existe d'autres protocoles - voir GEN-7 - mais moins cruciaux), et elle doit éviter de créer des boucles entre CDN et elle doit fonctionner même quand les références à une tierce partie sont cassées (exigence GEN-12), par exemple à cause du NAT ou du split DNS.

Suivent en section 4 les exigences pour la CI. CI (Control Interface) est l'interface qui contrôle les autres interfaces, par exemple pour les opérations de démarrage (ce sera là qu'on indiquera le serveur de statistiques auquel il faudra indiquer l'ampleur du trafic, par exemple). Elle doit permettre au CDN amont de demander le nettoyage (la destruction de contenu, exigence CI-1), et elle doit fournir un mécanisme de rétroaction par lequel le CDN aval informe le CDN amont de ce qu'il a fait (CI-4).

En section 5, la RI (Request routing indirection Interface) est l'interface vers le système de routage des requêtes. Elle doit fonctionner rapidement quelle que soit la taille du contenu (exigence RI-1) ce qui veut dire qu'il faut un mécanisme de redirection ultra-léger pour les objets de petite taille (ceux où le temps de redirection risque de dépasser le temps de transfert des données), et qu'il faut pouvoir choisir le compromis entre fraîcheur des données et rapidité. Pour les gros objets (exigence RI-2) où le temps de transfert sera long, il faut bien choisir le CDN d'où il sera servi et il faut donc que la solution permette un choix précis, lié aux caractéristiques de la requête. Autrement dit, un mode où on passe du temps à sélectionner la source des données, pour que le transfert aille ensuite plus vite.

Il faut aussi que cette redirection puisse être récursive (exigence RI-3), c'est-à-dire que la cible d'une redirection va elle-même suivre les éventuelles nouvelles redirections, et itérative (RI-4), c'est-à-dire que l'initiateur suive lui même les redirections multiples. Cela implique que le CDN aval reçoive du CDN amont toutes les informations nécessaires (exigence RI-8), comme l'origine géographique de la requête, les en-têtes HTTP, etc, et à l'inverse que le CDN aval transmette la réponse complète dans le cas d'une redirection (l'URI complet en HTTP, exigence RI-10).

En section 6, la FCI (Footprint & Capabilities Interface). Elle permet l'échange d'informations entre CDN, de manière à permettre le routage des requêtes (leur transmission au CDN le plus approprié) par l'interface RI. Si on compare RRI (Request Routing Interface, une méta-interface qui regroupe FCI et RI) à IP, FCI est l'équivalent des protocoles d'échange de routes comme OSPF et RI est l'équivalent du lookup dans une table de routage.

La FCI doit au minimum permettre de communiquer au CDN amont que le CDN aval est prêt (exigence FCI-1). Idéalement (mais ces exigences sont seulement au niveau moyen, donc pas indispensables), il faudrait aussi qu'il puisse communiquer des méta-informations comme les formats et protocoles qu'il gère, son extension géographique, les protocoles de redirection, les capacités de journalisation, etc.

En section 7, l'interface MI (Metadata Interface), qui permet l'échange de métadonnées sur les contenus servis, comme les restrictions géographiques, les durées de vie des contenus, les limitations d'accès (par exemple, aux abonnés)... Pour cette interface, l'exigence de base (MI-1) est de permettre l'envoi d'informations depuis le CDN amont. Parmi ces informations, il y a évidemment l'endroit d'où le CDN aval doit tirer le contenu (exigences MI-5 et MI-6). Il faut pouvoir ajouter des métadonnées dans le CDN aval (exigence MI-7) et en retirer (MI-8). La granularité de ces métadonnées doit être au niveau d'un objet (MI-9) mais il faut aussi pouvoir regrouper les objets, de manière à gérer ces métadonnées plus facilement (MI-10), avec un système d'héritage entre les groupes d'objets (MI-11).

L'industrie du contenu étant ce qu'elle est, il n'est pas étonnant qu'une longue exigence MI-13 décrive toutes les conditions d'accès au contenu, filtrage selon les pays, selon les adresses IP, dans le temps, etc.

Enfin, en section 8, la LI (Logging Interface), qui permet de transmettre les informations sur l'activité du CDN, de manière à avoir des journaux d'activité. Le transports desinformations de journalisation doit être fiable (exigence LI-1, pas question de se contenter de syslog sur UDP), doit être exhaustif (le CDN amont veut connaître tous les téléchargements faits à partir du CDN aval, exigence LI-2), le transferts des journaux doit pouvoir se faire en batch (LI-4), et utiliser un format standard (LI-6) et un transport standard (LI-7).

Il n'y a plus qu'à normaliser la sécurité (section 9). Bien sûr, la première exigence, SEC-1, est que toutes les opérations entre CDN soient sécurisables, même quand elles s'effectuent au-dessus de l'Internet normal, non sécurisé. Il faut donc pouvoir fournir authentification, intégrité, et confidentialité. Mais il faut aussi se défendre contre les attaques par déni de service, dont les CDN sont souvent victimes (SEC-2).


Téléchargez le RFC 7337


L'article seul

RFC 7336: Framework for Content Distribution Network Interconnection (CDNI)

Date de publication du RFC : Août 2014
Auteur(s) du RFC : L. Peterson (Akamai Technologies), B. Davie (VMware), R. van Brandenburg (TNO)
Pour information
Réalisé dans le cadre du groupe de travail IETF cdni
Première rédaction de cet article le 22 août 2014


Ce RFC est le nouveau cadre technique pour les solutions standard d'interconnexion de CDN. Après le document de description du problème (RFC 6707), une liste de scénarios d'usage (RFC 6770) et un cahier des charges formel (RFC 7337), voici une nouvelle étape du travail du groupe CDNI de l'IETF. Il remplace un ancien travail équivalent, qui n'avait pas débouché, dans le RFC 3466.

Personnellement, je trouve qu'il ne va pas très loin par rapport aux RFC 6707 et RFC 7337. Mais, bon, c'est la description officielle de l'architecture des futurs protocoles d'interconnexion de CDN donc, allons-y.

N'attendez pas de ce RFC des protocoles précis : les spécifications viendront plus tard, ce qui est décrit ici est une architecture de haut niveau, très proche de ce qui avait été écrit dans le RFC 6707. (Par contre, terminologie et architecture du vieil RFC 3466 sont abandonnés.) Le principal ajout est que l'interface de routage des requêtes (Request routing interface) est désormais découpée en deux, une interface de redirection (Request routing indirection Interface) et une interface d'échange d'informations (Footprint & Capabilities Interface). Autrement, je vous renvoie à mon article sur le RFC 6707. Outre la terminologie des RFC 6707 et RFC 7337, quelques concepts nouveaux apparaissent :

  • [Rappel] « CDN amont » : celui sollicité par le client qui veut du contenu, mais qui n'a pas le contenu (ou bien, pour une raison ou pour une autre, qui ne peut pas / ne veut pas servir la requête) et doit donc utiliser les mécanismes CDNI pour déléguer ; le RFC écrit aussi uCDN pour upstream CDN,
  • [Rappel] « CDN aval » : celui qui a le contenu et va donc servir le client ; le RFC écrit aussi dCDN pour downstream CDN,,
  • « Domaine CDN » : le nom de domaine dans l'URL qui identifie le CDN. Par exemple, pour le site Web de l'Élysée, qui utilise le CDN de Level 3, c'est actuellement cdn.cdn-tech.com.c.footprint.net.
  • « Redirection Itérative » : lorsque le CDN amont renvoie simplement au CDN aval, sans essayer de traiter la requête lui-même,
  • « Redirection Récursive » : lorsque le CDN amont fait le travail de redirection lui-même, sans que le client qui accédait au contenu en soit même conscient.

La section 3 du RFC est un survol général du fonctionnement de CDN interconnectés. L'opérateur A gère le CDN amont, celui qui a un lien avec le fournisseur de contenu, qui a choisi A pour servir ses ressources. L'opérateur A a un accord avec l'opérateur B, qui gère un possible CDN aval, qui pourra servir des clients intéressés, par exemple sur une base de proximité géographique (mettons que A est en Europe et B aux États-Unis). Avant que le client n'arrive, A et B auront donc échangé des messages (via les interfaces MI et FCI, cf. RFC 7337) pour que B sache quoi servir (interface MI, envoi de métadonnées) et pour que A sache les capacités de B (interface FCI). Lorsque le client final envoie sa requête, elle est d'abord dirigée (par les techniques habituelles des CDN existants) vers A. Via l'interface RI, le client est redirigé vers B (voir plus loin les techniques de redirection). Le client envoie alors ses requêtes à B. Celui-ci doit contacter A pour obtenir le contenu lui-même (cette opération n'utilise pas les protocoles CDNI) et il sert ce contenu au client. Ensuite, il contactera A pour remplir les statistiques de ce dernier (interface LI).

La section 3 détaille ensuite les mécanismes de redirection récursifs et itératifs. La section 2 du RFC avait déjà résumé ces techniques de base utilisées par les CDN pour la redirection des requêtes. Dans le cas le plus simple, un client (par exemple un navigateur Web) va interroger un CDN qui, soit lui répondra, soit le renverra vers le CDN aval. Pour cette redirection, on peut utiliser le DNS ou bien des mécanismes de redirection du protocole applicatif (par exemple, en RTSP, un code de retour 302). D'abord, le DNS. Le principe est d'envoyer des réponses différentes selon le client. Ce dernier est situé en Europe et interroge un CDN amont qui ne sert de contenu qu'en Amérique ? Pas de problème, aux requêtes sur le domaine CDN, on renvoie l'adresse IP d'un CDN aval qui est présent en Europe. Il y a quelques précautions à prendre (se souvenir que les réponses DNS seront gardées en cache et qu'il faut donc choisir intelligemment le TTL, sans compter le fait que certains résolveurs trichent en gardant en cache plus longtemps, prêter attention à DNSSEC si on génère les redirections au vol, cf. section 3.4.1) mais cette méthode est simple et est déjà utilisée par les CDN actuels, non connectés entre eux. L'avantage de la technique DNS est qu'elle est complètement invisible à l'application, qui ne se rend même pas compte qu'elle a été servie par un autre CDN que celui demandé. L'un de ces inconvénients est que le serveur DNS qui fait autorité ne connait pas le client mais son résolveur DNS. Si le client utilise un résolveur DNS public (comme OpenDNS), le client du contenu et le résolveur peuvent être sur des continents différents et la redirection ne se fera pas vers le CDN optimal. Autre inconvénient, on ne pourra tenir compte, dans l'URL original, que du nom de domaine, le reste de l'URL n'étant pas connu du serveur DNS.

À noter qu'il existe une variante, où on ne renvoie pas directement l'adresse IP mais un nom (technique CNAME ou, mieux, DNAME). C'est le cas de l'Élysée citée plus haut :

% dig A www.elysee.fr
...
;; ANSWER SECTION:
www.elysee.fr.		3600 IN	CNAME cdn.cdn-tech.com.c.footprint.net.

Autre possibilité de redirection, la redirection HTTP : cette fois, on se sert des codes de retour 301 ou 302 qui indiquent au client HTTP qu'il doit aller chercher ailleurs ce qu'il voulait. La nouvelle URL est donnée dans la réponse (en-tête Location:). Cette fois, le serveur peut changer tout l'URL, pas juste le nom de domaine, on connait l'adresse IP du client original (le RFC oublie de mentionner qu'il peut être un relais), ce qui peut permettre de mieux choisir le serveur, et enfin on a plein d'autres informations qui peuvent être utiles pour une redirection intelligente, comme la marque du logiciel client utilisé.

Il y a par contre des inconvénients, le changement de domaine fait que les cookies ne suivront pas, et les caches ne gardent pas en mémoire les redirections (le RFC 7234 le permet mais ce n'est pas fréquemment mis en œuvre).

La section 4 du RFC donne quelques détails sur les différentes interfaces du système, interfaces qui avaient été présentées dans les RFC 6707 et RFC 7337. Dans certains cas, l'interconnexion des CDN se fait à l'intérieur du protocole de communication déjà utilisé (in-band). C'est le cas des redirections HTTP. Dans d'autres cas, on utilise un protocole externe (out-of-band). Il faut également noter, pour comprendre la complexe combinaison d'interfaces de CDNI que, bien que les interfaces soient largement indépendantes, elles reposent sur des conventions communes, par exemple pour le nommage des ressources.

Parmi les détails creusés dans ce RFC 7336 sur les interfaces :

  • Une liste des éléments d'information qui peuvent être intéressants pour l'interface de journalisation, LI (Logging Interface). Conceptuellement, cette interface peut être vue simplement comme une copie des fichiers apache/access.log du CDN aval vers l'amont... Attention, le champ indiquant le nom de domaine demandé (VirtualHost dans Apache) peut être différent de l'original, s'il y a eu redirection HTTP.
  • Certains services de l'interface de communication de métadonnées (MI pour Metadata Interface) peuvent être assurés par le mécanisme de redirection. Par exemple, si le fournisseur de contenu veut limiter l'accès aux utilisateurs européens, il suffit que le CDN amont ne redirige pas vers le CDN américain, pour les requêtes de ce contenu à accès limité. (Le RFC note toutefois que cela manque de souplesse : par exemple, il y a peu de chances que le CDN aval ait une couverture géographique qui coïncide parfaitement avec les exigences de géo-limitation du fournisseur de contenu.)

La section 5 du RFC décrit plusieurs scénarios d'usage de CDNI quand il sera terminé. Par exemple, bien que le modèle de référence (et les exemples que j'ai cités) soient unidirectionnels (le CDN A délègue au CDN B et jamais le contraire), on pourra se servir de CDNI pour les CDN maillés, avec des graphes arbitraires entre les différents CDN.

Déléguer ses fonctions soulève évidemment tout un tas de questions, comme toute sous-traitance. Le CDN amont peut-il faire confiance au CDN aval pour servir le contenu correctement ? Les statistiques de trafic qu'il remonte sont-elles correctes ou bien modifiées dans l'intérêt exclusif du CDN aval ? La section 6 explore le problème de la confiance dans un monde de CDN connectés. Notons que le fournisseur de contenu a déjà aujourd'hui le même problème avec son opérateur CDN : dès qu'on sous-traite, la question de la confiance surgit. Mais CDNI rend les choses un peu plus compliquées : un fournisseur de contenu qui a signé avec l'opérateur de CDN amont peut ne pas être conscient que celui-ci a un accord avec l'opérateur CDN aval. Et si un opérateur CDN modifiait les fichiers avant de les envoyer ? Il existe évidemment des solutions techniques, comme la signature cryptographique des fichiers. Mais, fondamentalement, il faut une combinaison de confiance et de quelques vérifications (par exemple des sondages aléatoires faits par divers clients pour vérifier que le contenu est bien là, et bien conforme à ce qui est demandé).

En parlant de confiance et de sécurité, la section 7 se demande quelles sont les conséquences de l'interconnexion de CDN pour la vie privée (l'existence d'une section nommée Privacy considerations est récente dans les RFC et vient du RFC 6973). Un CDN est bien placé pour observer beaucoup de choses dans le comportement de l'utilisateur, par exemple à quels fichiers il accède, de mécanique_quantique_pour_les_nuls.epub à how_to_make_bombs.avi. L'utilisateur qui accède à un site Web ne sait typiquement pas si celui-ci utilise un CDN (cela se trouve relativement facilement mais tout le monde n'a pas les compétences ou le temps nécessaire). Il fait confiance au site Web, mais ne se rend pas compte qu'il fait également confiance à l'opérateur CDN (qui peut avoir une autre éthique, ou être soumis à d'autres lois : lorsqu'on visite http://www.elysee.fr/, on croit faire confiance à un organisme public français, alors qu'il est en fait servi par un CDN états-unien, soumis au Patriot Act).

Certaines fonctions de CDNI sont justement conçues pour faire circuler de l'information sur l'activité des utilisateurs, notamment l'interface de journalisation (LI). Il faudra donc s'assurer qu'elles disposent de protections appropriées.

Et, toujours sur la sécurité, la section 8 note également d'autres points délicats, qui s'ajoute aux questions de sécurité déjà existantes pour les CDN actuels :

  • Certaines exigences des fournisseurs de contenu (distribution limitée géorgraphiquement, ou bien limitée dans le temps) sont plus difficiles à satisfaire lorsqu'il y a interconnexion des CDN,
  • Par contre, les menottes numériques ne sont pas affectées par CDNI puisqu'elles reposent typiquement sur des mécanismes présents dans le contenu lui-même,
  • Les interfaces entre CDN doivent être protégées, contre l'écoute (cas des journaux d'activité dans la section précédente) mais aussi contre les modifications non autorisées (imaginez qu'un méchant modifie les contenus servis lorsqu'ils passent d'un CDN amont au CDN aval), même si l'interconnexion se fait en utilisant l'Internet public, non sécurisé.

Deux fournisseurs de solutions techniques, Cisco et Alcatel-Lucent, ont annoncé qu'ils travaillaient sur des prototypes d'interconnexion de CDN, utilisant le futur protocole qui sera la concrétisation de ce cadre.


Téléchargez le RFC 7336


L'article seul

RFC 7335: IPv4 Service Continuity Prefix

Date de publication du RFC : Août 2014
Auteur(s) du RFC : Cameron Byrne (T-Mobile US)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 7 septembre 2014


Le RFC 6333, qui normalisait le protocole DS-Lite, réservait un préfixe IPv4, 192.0.0.0/29, pour numéroter les entités impliquées dans le fonctionnement des tunnels DS-Lite. Ce nouveau RFC 7335 généralise ce préfixe en le rendant utilisable pour toutes les solutions techniques liées à la migration vers IPv6.

En effet, ces adresses ne doivent jamais apparaître sur l'Internet. Dans DS-Lite, elles sont limitées aux communications entre les extrémités du tunnel DS-Lite. Il n'y a donc pas de risque de collision si on se sert de ces adresses pour une autre utilisation interne. Si un autre système de transition vers IPv6 a besoin d'adresses IPv4 internes, il peut désormais les prendre dans ce préfixe. C'est par exemple le cas (section 3) de 464XLAT (RFC 6877) où la machine de l'utilisateur (CLAT : client side translator) peut faire de la traduction d'adresses mais a besoin d'une adresse IPv4 (qui ne sortira pas de la machine) à présenter aux applications.

Plutôt que de réserver un préfixe IPv4 différent pour DS-Lite, 464XLAT et les zillions d'autres mécanismes de transition, la section 4 de notre RFC pose donc comme principe que toutes les solutions utilisant des adresses IPv4 internes se serviront du même préfixe, 192.0.0.0/29 .Ce préfixe est donc ainsi documenté dans le registre des adresses spéciales.


Téléchargez le RFC 7335


L'article seul

RFC 7328: Writing I-Ds and RFCs using Pandoc and a bit of XML

Date de publication du RFC : Août 2014
Auteur(s) du RFC : R. Gieben (Google)
Pour information
Première rédaction de cet article le 13 août 2014


Vous voulez écrire un RFC ? Il faut commencer par faire un Internet-Draft (I-D) et il existe pour cela deux formats, en XML ou bien en Word. Ce RFC présente une troisième solution, utilisant Markdown, ou plutôt sa variante définie par Pandoc.

Le format d'écriture de RFC le plus répandu est sans doute XML, tel que décrit dans le RFC 7749. Le format Word est dans le RFC 5385. (Il existe aussi le format historique, utilisant nroff mais je ne suis pas sûr qu'il soit encore accepté aujourd'hui.) Certaines personnes trouvent que les tags XML les distraient pendant qu'ils écrivent leur Internet-Draft (I-D) et ils préfèrent donc utiliser un autre format « texte », avec les marquages de Markdown, jugés moins intrusifs. Markdown est très populaire et est utilisé à plein d'endroits différents (par exemple, dans les formulaires du système de suivi de bogues de GitHub). Markdown a plein de dialectes et de variantes et celle utilisée ici est celle du logiciel Pandoc, un sur-ensemble de Markdown. (Par abus de langage, j'écris ensuite « Pandoc » pour désigner ce format.)

(Au passage, vous pouvez regarder la page officielle de Markdown et celle de Pandoc.)

Le document en Pandoc peut ensuite être traduit dans d'autres formats, HTML, EPUB, DocBook, etc, d'où on peut ensuite tirer le futur RFC dans un format de publication officiel (comme le texte seul). L'outil Pandoc2rfc convertit le Pandoc en Docbook, qui est ensuite traduit en XML-RFC7749, puis ensuite dans les différents formats de publication souhaités (on passe donc d'un texte quasi-brut avec instructions de formatage, à XML, pour revenir à du texte brut...) Dans le futur, peut-être existera-t-il un chemin plus rapide, allant directement du Pandoc au RFC final. En attendant, ce chemin impose quelques contraintes, notamment qu'on ne peut pas complètement éviter d'éditer du XML. L'auteur doit éditer quatre documents :

  • Un document Markdown abstract.mkd contenant le résumé,
  • Un document Markdown middle.mkd contenant le gros du RFC,
  • Un document Markdown facultatif back.mkd contenant les annexes,
  • Un document XML template.xml contenant auteurs et références bibliographiques.

Un exemple du gabarit template.xml figure dans la section 2 de notre RFC.

Pour installer l'outil Pandoc2rfc, vous allez avoir besoin du processeur XSLT xsltproc (la transformation du Docbook en XML-RFC7749 est faite avec XSLT) et bien sûr de Pandoc lui-même.

Pandoc2rfc contient un script shell qui fait les transformations nécessaires (voir la section 3 du RFC).

Pour apprendre la syntaxe de Pandoc, il faut regarder le guide. Pandoc2rfc traduit via xml2rfc (l'outil du RFC 7749) et met en correspondance les concepts Markdown avec ceux de XML-RFC7749. Par exemple, une énumération avec * va être traduite en une liste (<list> XML) style="symbols" et une énumération avec des numéros (comme "1.", "2.", etc) va être traduite en style="numbers" (RFC 7749, section 2.22.3). La section 4 de notre RFC donne une liste complète des équivalences Pandoc<->XML, résumées sous forme d'un tableau dans l'annexe B.

Il est d'ailleurs difficile de faire du Pandoc2rfc sans connaître xml2rfc. Par exemple, pour afficher une table des matières, il faut inclure l'invocation xml2rfc <?rfc toc="yes"?>.

La section 5 liste quelques limitations de Pandoc2rfc par rapport à Pandoc : pas de gestion des index, les commentaires doivent être faits avec des commentaires HTML dans le source Pandoc, les citations se font avec les références XML, le système de citation de Pandoc n'est pas utilisé, et enfin les auteurs doivent se résigner à voir apparaître des erreurs de xml2rfc, la traduction Pandoc vers Docbook ne gère pas toutes les erreurs possibles. De mon expérience, il faut pas mal bricoler pour faire marcher le tout. Écrire des RFC en Markdown est sympa mais on n'y arrive pas en cinq minutes.

Si vous voulez un exemple concret, la distribution de Pandoc2rfc contient un répertoire test/ avec un exemple de RFC bidon utilisant toutes les fonctions de Pandoc2rfc. J'ai un peu modifié le Makefile pour faire des versions texte, XML et HTML du RFC :

% make all
pandoc2rfc -t template.xml back.mkd middle.mkd
pandoc2rfc -H -t template.xml back.mkd middle.mkd
pandoc2rfc -X -t template.xml back.mkd middle.mkd

Et cela produit les trois versions, à partir du source Markdown (essentiellement en middle.mkd) et du gabarit template.xml.


Téléchargez le RFC 7328


L'article seul

RFC 7326: Energy Management Framework

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : J. Parello, B. Claise (Cisco Systems), B. Schoening (Independent Consultant), J. Quittek (NEC Europe)
Pour information
Réalisé dans le cadre du groupe de travail IETF eman
Première rédaction de cet article le 6 septembre 2014


Ce nouveau RFC présente un cadre général pour la gestion de l'énergie dans les protocoles IETF. La préoccupation est assez récente. Pendant longtemps, les ordinateurs et routeurs connectés à l'Internet consommaient autant de courant qu'ils voulaient et personne ne regardait la facture. La montée des préoccupations écologiques, le prix de plus en plus élevé de l'électricité dans les centres de données, et le désir d'avoir des machines sans fil à la patte, alimentées uniquement par une batterie, font que la gestion de l'énergie est maintenant devenue une préoccupation à part entière de l'IETF. Ce cadre modélise les consommateurs d'électricité comme des objets énergétiques (energy objects) qui vont pouvoir être supervisés et contrôlés à distance. On pourra, par exemple, par des protocoles normalisés, suivre la consommation électrique d'un serveur, ou bien la quantité d'énergie restante dans une batterie mais aussi faire passer une machine dans un état à consommation énergétique réduite.

La gestion de réseaux informatiques est divisée par la norme X.700 en cinq parties, Panne, Configuration, Comptabilité, Performance et Sécurité. La gestion de l'énergie n'y figure pas. La norme ISO 50001 ajoute cette préoccupation aux textes. L'IETF a créé un groupe de travail sur la gestion de l'énergie, EMAN, qui avait déjà produit un premier RFC, le cahier des charges, le RFC 6988.

Notre nouveau RFC introduit le concept d'interface énergie, en s'inspirant de celui bien connu d'interface réseau. C'est par une interface énergie que la machine fournit ou consomme de l'énergie. Une machine ne sait pas forcément mesurer ce qu'elle consomme et c'est donc parfois en interrogeant le dispositif de fourniture d'énergie qu'on aura cette information. (L'interface énergie de sortie de l'un étant l'interface énergie d'entrée de l'autre.)

Autres termes définis par ce RFC (section 2) :

  • Entrée (power inlet ou simplement inlet) : l'interface énergie par laquelle le courant arrive.
  • Sortie (outlet) : l'interface énergie par laquelle le courant sort.
  • Énergie : le nombre de kWh consommés ou produits, ou bien qu'on peut consommer ou produire.
  • Puissance : énergie divisée par le temps (en watts ou en joules/seconde). Si l'énergie est une distance, la puissance est la vitesse.
  • Demande : puissance moyennée sur un intervalle. Ces trois dernières définitions sont tirées de IEEE 100.
  • Attributs du courant : la tension, la phase, la fréquence, etc.
  • Qualité du courant : ses attributs par rapport à une référence. Comme le précédent, ce terme vient de IEC 60050.

La section 3 du RFC définit la notion de cible (target device). Ce sont tous les engins qui peuvent être supervisés ou contrôlés dans le cadre défini dans ce RFC : ordinateurs de bureau, serveurs, routeurs, imprimantes, commutateurs, points d'accès WiFi, batteries (lorsqu'elles sont autonomes et non pas enfermés dans un ordinateur), générateurs, fournisseurs PoE, compteurs, capteurs divers... Plusieurs de ces engins ne parleront pas IP et devront être interrogés / commandés via un relais.

Le cadre général défini par ce RFC concerne l'énergie, mais il ne couvre pas toutes les applications liées à l'énergie. La section 5 liste ce qui n'est pas l'objet du travail EMAN en cours : les engins non-électriques (si vous avez un routeur steampunk, propulsé par la vapeur, EMAN ne va pas vous aider) et la production électrique (seules sa distribution et sa consommation sont prises en compte).

La section 6 du RFC décrit le modèle utilisé pour la gestion de l'énergie. Il suit une conception objets classique : une classe Energy Object, avec trois sous-classes, Device, Component et Power Interface. La super-classe Energy Object modélise tout ce qui est relié au réseau et qui l'utilise pour superviser ou commander sa gestion de l'énergie. La classe Device modélise les équipements physiques qui consomment, distribuent ou stockent de l'énergie, comme les ordinateurs. Component sert à décrire les parties d'un objet Device, et le nouveau concept, Power Interface représente les interconnexions. French-power-socket.jpg

Tous les objets héritent de Energy Object qui a comme attributs :

  • Un identificateur unique, un UUID (RFC 9562),
  • Un nom (relativement) lisible ; cela pourra être un nom de domaine (pour les ordinateurs et routeurs, c'est déjà le cas), ou d'autres conventions de nommage,
  • Une importance, allant de 1 à 100, et qui sera utilisée pour prendre des décisions comme « les accumulateurs sont presque à plat, qui est-ce que je coupe en premier ? »,
  • Une série d'étiquettes (tags) permettant de trouver et de manipuler facilement tous les objets ayant une caractéristique commune,
  • Un rôle, qui indique le but principal de cet objet (routeur, lampe, réfrigérateur, etc),
  • Et quelques autres attributs que je n'ai pas cité ici.

Les objets de la classe Energy Object ont également des méthodes permettant la mesure de certaines grandeurs : puissance, attributs du courant électrique, énergie et demande.

D'autres méthodes permettent le contrôle de l'objet et et changer son état. Plusieurs normes donnent des listes d'état possibles pour un objet. Par exemple, IEEE 1621 décrit trois états : allumé, éteint et dormant. D'autres normes, comme ACPI, vont avoir une liste différente. DMTF décrit pas moins de quinze états possibles, faisant par exemple la différence entre Sleep Light et Sleep Deep. Le groupe de travail EMAN, auteur de ce RFC, a produit sa propre liste, qui comprend douze états (section 6.5.4 du RFC), chacun numéroté (pour faciliter l'écriture des futures MIB, dont plusieurs sont proches de la publication en RFC). Par exemple, en cas de suspension, une machine est en sleep(3) et high(11) est au contraire l'état d'une machine complètement réveillée et qui ne cherche pas à faire des économies d'électricité. Un tableau en section 6.5.5 donne des équivalences entre ces normes. Par exemple, le sleep(3) d'EMAN correspond à l'état dormant de IEEE 1621, au "G1, S3" d'ACPI, et au Sleep Deep de DMTF. Ces états sont stockés dans un registre IANA (section 12 du RFC) et cette liste pourra être modifiée par la suite.

Une description formelle du modèle, en UML, figure en section 7.

Pour connaître l'état des mises en œuvre de ce cadre de gestion de l'énergie, voir le Wiki du groupe de travail (plusieurs MIB ont déjà été définies selon ce cadre).

Maintenant, la sécurité (section 11). Sérieux sujet dès qu'on touche à un service aussi essentiel que l'alimentation électrique. Va-t-on éteindre toute l'électricité d'une ville avec son téléphone, comme dans Watch Dogs ? Non, c'est plus compliqué que cela. Néanmoins, la gestion d'énergie doit être mise en œuvre prudemment. Si on gère les machines avec SNMP, le RFC 3410 sur la sécurité de SNMP est une lecture indispensable. Les accès en écriture, permettant de modifier l'état d'unee machine, peuvent en effet permettre, s'ils ne sont pas bien sécurisés, d'éteindre un appareil critique à distance. Mais même les accès en lecture seule peuvent être dangereux, car révélant des choses qu'on aurait préféré garder pour soi.

On lire aussi avec intérêt le RFC 7603 qui précise le cadre d'utilisation.


Téléchargez le RFC 7326


L'article seul

RFC 7323: TCP Extensions for High Performance

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : D. Borman (Quantum Corporation), B. Braden (University of Southern California), V. Jacobson (Google), R. Scheffenegger (NetApp)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 21 septembre 2014


L'algorithme originel de TCP rendait ce protocole de transport trop prudent et n'utilisant pas assez les réseaux, notamment ceux à forte latence. Après quelques essais, le RFC 1323, publié en 1992, a permis à TCP de fonctionner correctement sur une bien plus grande variété de réseaux, et jusqu'à aujourd'hui. Il est désormais remplacé par ce nouveau RFC 7323 qui, après une longue genèse, représente l'état de l'art en matière de performances TCP. Ce nouveau RFC est une lecture indispensable pour les fans de TCP ou tout simplement pour ceux qui veulent comprendre en détail ce protocole.

Avant le RFC 1323, TCP (normalisé dans le RFC 793 en 1981) se comportait très bien sur les réseaux locaux, ainsi que sur les réseaux distants à faible débit, comme ce qu'on avait sur un modem. Mais il était beaucoup moins satisfaisant sur les réseaux à forte latence et forte capacité, les réseaux à fort BDP où BDP signifie Bandwitdh-Delay Product. Si la capacité est faible ou la latence faible, pas de problèmes. Si leur produit dépasse une certaine valeur, TCP n'était pas capable de remplir la fenêtre et ses performances restaient en deçà du maximum théorique du réseau.

La section 1 décrit ce problème. TCP avait été conçu (et avec succès) pour tourner sur des réseaux très disparates, et pour s'adapter automatiquement à leurs caractéristiques (taux de perte, latence, taux de duplication...) À l'époque du RFC 1323, TCP tournait en production sur des réseaux dont les capacités allaient de 100 b/s à 10 Mb/s et cette plage s'est nettement élargie depuis. Existe-t-il une limite au débit de TCP, au-delà de laquelle il ne servirait à rien d'accélérer encore les réseaux ? La question n'a pas de réponse simple.

La caractéristique importante du réseau n'est en effet pas la capacité mais le produit de la capacité et de la latence, le BDP cité plus haut. C'est cette caractéristique qui indique la taille du tuyau que TCP doit remplir, la capacité étant le « diamètre » du tuyau et la latence sa « longueur ». Si la capacité croît beaucoup, au rythme des progrès techniques, la latence est bloquée par la finitude de la vitesse de la lumière et la seule façon de l'améliorer est de raccourcir les câbles. Donc, un gros BDP oblige TCP à avoir davantage de données « en transit », envoyées, mais n'ayant pas encore fait l'objet d'un accusé de réception, ce qui implique des tampons d'entrée/sortie de grande taille mais qui implique aussi la possibilité de garder trace de grands nombres (par exemple le nombre d'octets en transit), donc d'avoir des compteurs de taille suffisante. Ces liaisons Internet avec un fort BDP sont parfois surnommées les « éléphants » de l'anglais LFN (Long Fat Network).

Un exemple typique d'éléphant est une liaison satellite, avec sa capacité souvent respectable mais sa latence terrible, due à la nécessite d'un aller-retour avec l'orbite géostationnaire. À l'époque du RFC 1123, le BDP de ces liaisons était d'environ 1 Mbit soit 100 segments TCP de 1 200 octets chacun. Si une mise en œuvre de TCP se limitait à 50 segments envoyés avant de recevoir un accusé de réception, elle n'utiliserait que la moitié de la capacité disponible. Et les liaisons terrestres peuvent être des éléphants aussi. Un lien transcontinental aux États-Unis a une latence de 30 ms, ce qui, à 45 Mb/s, fait également un BDP de 1 Mbit.

Qu'est-ce qui empêchait TCP de tirer profit de ces éléphants ? Trois points :

  • La taille de la fenêtre n'est stockée par défaut que sur 16 bits, ne permettant pas de fenêtre plus grande que 65 535 octets. Ce problème est résolu par le RFC 1323 avec l'introduction du window scaling.
  • La récupération était trop longue en cas de perte de paquets. Les premiers TCP, dès qu'un paquet était perdu, attendaient de vider complètement le pipeline, puis repartaient de zéro, comme pour une connexion TCP neuve. En 1990, l'algorithme de TCP avait été modifié pour permettre un redémarrage plus rapide, tant qu'on ne perdait qu'un seul paquet par fenêtre TCP. Mais, avec des fenêtres plus grandes, cette probabilité de perte augmente. Les accusés de réception de TCP étant cumulatifs, une perte de paquet survenant au début de la fenêtre peut faire tout perdre. La solution a été une option d'accusés de réception sélectifs (SACK pour Selective ACKnowledgment). Ce point n'a pas été traité dans le RFC 1323 mais dans le RFC 2018.

Un autre problème à considérer est la fiabilité. Si on utilise TCP, c'est pour avoir certaines garanties : que tous les octets émis seront reçus, dans le même ordre, etc. Est-ce que le passage à de plus hautes performances menace ces garanties ? Par exemple, avec des fenêtres plus grandes, la probabilité qu'un paquet ancien, appartenant à une précédente connexion, lorsqu'il finit par arriver, tombe dans la fenêtre courante, cette probabilité est plus élevée. Dans ces conditions, les données seraient corrompues. La principale protection de TCP contre cet accident est la notion de MSL (Maximum Segment Lifetime), le temps qu'un segment peut traîner sur l'Internet. Il ne faut pas réutiliser des numéros de séquence avant qu'une durée supérieure ou égale à la MSL se soit écoulée. Ce numéro ne faisant que 32 bits, cela peut être délicat, surtout aux débits élevés (même sans fenêtres agrandies). La MSL est généralement prise à deux minutes et, à seulement 1 Gb/s, les numéros de séquence ne durent que dix-sept secondes. Or, aucun mécanisme sur l'Internet ne garantit le respect de la MSL. Un vieux paquet ne sera pas jeté. D'où l'utilisation par notre RFC 7323 de l'option Timestamps pour détecter les segments trop anciens et se protéger donc contre la réutilisation des numéros de séquence TCP (solution PAWS, en section 5).

À noter que ces mécanismes sont conçus pour les réseaux à fort BDP. Sur des réseaux à faible BDP, il peut être intéressant de les débrayer, manuellement ou automatiquement.

Reste que les solutions proposées dans ce RFC dépendent des options TCP. Pour certains protocoles, par exemple IP, certaines options ont du mal à passer à travers le réseau (section 1.3 de notre RFC). TCP semble mieux placé de ce point de vue (il est mentionné à la fin de mon article sur les options IP). On peut consulter à ce sujet « Measuring Interactions Between Transport Protocols and Middleboxes » et « "Measuring the Evolution of Transport Protocols in the Internet ».

La section 2 de notre RFC présente la première option qui avait été normalisée pour améliorer les performances de TCP sur les liens à fort BDP (Bandwidth-Delay Product), le window scaling. L'idée de base est très simple : 16 bits pour indiquer la taille de la fenêtre, c'est trop peu, on va donc appliquer un facteur (indiqué dans une option TCP) au nombre décrit par ces 16 bits. À noter que, comme les options ne sont envoyées qu'au début de la connexion TCP, le facteur est constant (la fenêtre elle-même étant dynamique).

L'option Window Scale comprend trois champs : Type, Longueur et Valeur. Le type vaut 3 et est enregistré dans le registre des options, la longueur est forcément de 3 (trois octets en tout) et la valeur est un octet qui indique de combien de bits on va décaler la taille de la fenêtre. Une valeur de 0 indique pas de décalage, donc un facteur de 1 (une telle valeur n'est pas inutile car elle sert à indiquer au pair TCP qu'on sait gérer le window scaling). Une valeur de 1 indique qu'on double la taille de la fenêtre pour connaître la vraie valeur, etc. Voici un exemple vu par Wireshark :

Transmission Control Protocol, Src Port: 51336 (51336), Dst Port: 4332 (4332), Seq: 0, Len: 0
...
   Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
...
        Window scale: 5 (multiply by 32)
            Kind: Window Scale (3)
            Length: 3
            Shift count: 5

Et, quelques paquets plus loin, on voit bien le facteur d'échelle appliqué (32, soit 2^5). Le champ indiquant la longueur de la fenêtre vaut 728 octets mais il faut en fait lire 23 296 octets :

    Window size value: 728
    [Calculated window size: 23296]
    [Window size scaling factor: 32]

(À noter que je parlais aussi de cette option à la fin de l'article sur le RFC 793.) Sur Linux, cette option peut s'activer ou se désactiver avec le paramètre sysctl net.ipv4.tcp_window_scaling (c'est parfois nécessaire de la désactiver dans certains réseaux bogués qui bloquent les paquets TCP contenant des options inconnues d'eux).

Autre option normalisée ici, la meilleure mesure du RTT par l'option Timestamps, en section 3. La mesure du RTT est cruciale pour TCP, pour éviter des accidents comme la congestion brutale décrite dans le RFC 896. Si TCP ne mesure qu'un seul paquet par fenêtre, les résultats seront mauvais pour les grandes fenêtres, par simple problème d'échantillonage (critère de Nyquist).

L'option Timestamps a le type 8, une longueur de 10, et deux champs de quatre octets, l'heure qu'il était au moment de l'envoi et l'heure lue dans le paquet pour lequel on accuse réception (cette valeur n'a donc de sens que si le paquet a le bit ACK). L'« heure » n'est pas forcément celle de l'horloge au mur (puisque, de toute façon, on n'utilisera que des différences), l'important est qu'elle avance à peu près au même rythme. En fait, il est même recommandé que l'horloge ne soit pas directement celle de la machine, pour éviter de donner une information (la machine est-elle à l'heure) à un éventuel observateur indiscret. La section 7.1 recommande d'ajouter à l'horloge de la machine un décalage spécifique à chaque connexion, et tiré au hasard au début de la connexion.

Attention, il n'y a aucune raison qu'on ait le même nombre de paquets dans les deux sens. On peut voir un pair TCP envoyer deux paquets et le récepteur ne faire qu'un seul paquet d'accusé de réception. Dans ce cas, ledit récepteur devra renvoyer le temps du paquet le plus ancien. Toujours avec Wireshark, cela donne :

Transmission Control Protocol, Src Port: 4332 (4332), Dst Port: 51336 (51336), Seq: 0, Ack: 1, Len: 0
...
   Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
...
        Timestamps: TSval 2830995292, TSecr 27654541
            Kind: Timestamp (8)
            Length: 10
            Timestamp value: 2830995292
            Timestamp echo reply: 27654541

Et, dans le paquet suivant de la même direction, les compteurs ont augmenté :

        Timestamps: TSval 2830995566, TSecr 27654569
            Kind: Timestamp (8)
            Length: 10
            Timestamp value: 2830995566
            Timestamp echo reply: 27654569

Ici, il s'agissait d'une communication entre deux machines Linux. La génération des estampilles temporelles dans les options TCP est contrôlée par la variable sysctl net.ipv4.tcp_timestamps (documentée, comme les autres, dans le fichier Documentation/networking/ip-sysctl.txt des sources du noyau). Par exemple :

% sysctl net.ipv4.tcp_timestamps
net.ipv4.tcp_timestamps = 1

Cela signifie que cette option est activée sur cette machine (0 = désactivée).

Cette option d'estampillage temporel est utilisée dans PAWS (présenté plus loin) mais aussi dans d'autres systèmes comme ceux du RFC 3522 ou du RFC 4015.

La section 4 décrit l'utilisation des estampilles temporelles pour mesurer le RTT des paquets, ce qui sert à TCP à déterminer le RTO (Retransmission TimeOut), le délai au bout duquel TCP s'impatiente de ne pas avoir eu d'accusé de réception et réémet. Voir à ce sujet le RFC 6298, pour savoir tout de ce calcul du RTO, et aussi le papier « On Estimating End-to-End Network Path Properties ».

La section 5 présente le mécanisme PAWS (Protection Against Wrapped Sequence numbers), qui sert à lutter contre les vieux segments TCP qui arriveraient tard et avec, par malchance, un numéro de séquence qui a été réutilisé depuis et est donc considéré comme valide. Les numéros de séquence étant stockés sur 32 bits seulement, la probabilité d'un tel accident augmente avec la capacité des réseaux. PAWS se sert de la même option Timestamps qui a été présentée plus haut. L'idée est que si un segment TCP arrive avec une estampille temporelle trop ancienne, par rapport à celles reçues récemment, on peut le jeter sans remords. Comme pour tous les usages de l'option Timestamps, il ne nécessite pas de synchronisation d'horloges entre les deux pairs TCP car les comparaisons se font toujours entre les estampilles mises par une même machine.

Quels sont les changements depuis le RFC 1323 (voir l'annexe H) ? D'abord, une partie du texte a été supprimée, celle consacrée à la discussion des mérites des différentes options. Si on veut lire cette discussion, il faut reprendre le RFC 1323.

Ensuite, de nombreux changements importants ont été apportés. Je ne vais pas les lister tous ici mais, par exemple, la section 3.2 a été très enrichie pour mieux préciser l'utilisation des estampilles temporelles (trop floue précédémment), l'algorithme de sélection de l'estampille dans la section 3.4 du RFC 1323 a été corrigé (deux cas n'étaient pas traités), le cas des paquets TCP RST (ReSeT d'une connexion) a été décrit, la discussion sur la MSS a été déplacée dans le RFC 6691, etc.

Nouveauté de ce RFC (le RFC 1323 clamait qu'il ne se préoccupait pas du sujet), la section 7, sur la sécurité. Ouvrir la fenêtre TCP pour augmenter les performances, c'est bien. Mais cela ouvre également la voie à des attaques où un méchant tente de glisser un paquet dans la séquence des paquets TCP. Normalement, un attaquant situé en dehors du chemin des paquets, qui ne peut donc pas les observer, doit, s'il veut réussir cette injection, deviner le numéro de séquence (RFC 5961). Mais plus la fenêtre est grande et plus c'est facile (il n'a pas besoin de deviner le numéro exact, juste de deviner un numéro qui est dans la fenêtre). Il faut donc mettre en rapport le gain de performances avec le risque d'accepter de faux paquets. PAWS protège partiellement contre ces attaques mais en permet de nouvelles (par exemple l'injection d'un paquet ayant une estampille dans le futur permettrait, si ce paquet est accepté, de faire rejeter les vrais paquets comme étant trop anciens).

Les fanas de programmation et de placement des bits dans la mémoire liront avec plaisir l'annexe A, qui recommande un certain arrangement des options dans le paquet TCP : en mettant deux options vides (NOP) avant l'option Timestamp, on obtient le meilleur alignement en mémoire pour une machine 32-bits.


Téléchargez le RFC 7323


L'article seul

RFC 7322: RFC Style Guide

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : H. Flanagan (RFC Editor), S. Ginoza (RFC Editor)
Pour information
Première rédaction de cet article le 27 septembre 2014


Comme pour toute série de documents, il vaut mieux que les RFC soient cohérents dans leur style. Si certains RFC mettent les références entre parenthèses et d'autres entre crochets, la tâche du lecteur qui doit lire plusieurs RFC sera plus pénible. D'où cette série de règles, que le RFC Editor impose aux auteurs de RFC.

Rappelons que les RFC et leur RFC Editor sont décrits dans le RFC 8729, et que l'organisation du travail dudit RFC Editor est décrite dans le RFC 6635. L'actuel éditeur est Heather Flanagan, une des auteures de ce RFC 7322.

Les auteurs de RFC sont typiquement des ingénieurs informaticiens, qui n'ont pas forcément eu une formation en écriture et ignorent souvent les règles de base. La section 1 leur rappelle d'abord que le guide de style n'est pas là pour les embêter, mais pour que les RFC soient clairs et cohérents, à la fois en interne et entre eux. Le premier RFC Editor, Jon Postel, avait défini des règles s'imposant à tous les auteurs. Elles sont, en moyenne, bien plus souples que celles qu'imposent les journaux scientifiques ou les conférences et ne devraient donc pas trop gêner les participants à l'IETF.

Ce RFC 7322 est prévu pour être plutôt stable (une des fonctions du système des RFC est de garder les documents disponibles pendant de nombreuses années) et ne contient donc que des règles très solides, qui ont peu de chances de bouger avant de nombreuses années. Il a un inséparable compagnon en ligne, qui le complète avec les règles tout aussi importantes mais peut-être moins stables ou plus récentes.

Les règles de style des RFC ne sont pas spécialement extraordinaires : elles suivent avant tout le CMOS, le Chicago Manual of Style, la référence largement reconnue chez les auteurs anglophones, notamment dans les domaines scientifiques et techniques (mais très traditionaliste, et pas disponible en ligne). Le guide complète le CMOS, notamment pour les questions que ce dernier traite mal, comme la présence de codes informatiques au milieu du texte en anglais.

Enfin, comme tous les RFC commencent comme Internet-Drafts, la lecture du guide d'écriture des ID est également nécessaire à l'auteur débutant.

Armé de ce guide et des bons principes, le (enfin, actuellement, la) RFC Editor va alors (section 2) relire le document, corriger les erreurs, signaler aux auteurs les problèmes que le RFC Editor ne peut pas corriger seul, réparer les incohérences... Le but est qu'il y ait une forte cohérence à l'intérieur du document, presque aussi forte entre les RFC d'un même cluster et un peu moindre entre tous les RFC. (Les clusters sont des groupes de RFC portant sur une norme technique commune, et publiés en même temps, comme par exemple le cluster HTTP/1.1. On trouve une discussion plus détaillée en ligne.)

Attention, le travail du RFC Editor n'est pas technique (au sens de l'informatique). Les problèmes techniques doivent être traités par les auteurs et l'exactitude technique doit toujours avoir le pas sur le style. En aucun cas, le RFC Editor ne doit changer le sens du texte. (En pratique, toute activité éditoriale implique des frictions entre auteurs et éditeurs. L'un des buts du guide est de les minimiser, en expliquant clairement les règles.)

Après la philosophie, les règles (section 3). La première est la langue : pas le choix, les RFC doivent être en anglais. Mais lequel ? Celui de quel côté de la mare ? Britannique ou états-unien ? Faut-il écrire minimisation ou minimization ? meter ou metre ? Sur ce point, comme sur pas mal d'autres, le guide est ouvert : l'auteur fait comme il veut mais doit être cohérent. S'il ne l'est pas, le RFC Editor passera tout en orthographe états-unienne.

Les règles de ponctuation sont celles du CMOS (deux espaces après le point, la virgule avant le dernier élément d'une énumération, etc).

Les noms de domaine utilisés doivent être ceux du RFC 2606 pour éviter toute collision avec des noms réels. Les URI doivent être entre chevrons, comme le demande l'annexe C du RFC 3986. Notez bien que cette règle sur les URI ne s'applique qu'au texte seul (ce qui est le cas des RFC), et c'est pour cela que je ne l'applique pas sur ce blog (où j'écris https://www.example.org/parici).

La capitalisation n'est pas imposée mais elle doit être cohérente, selon les règles de cohérence du document sur les termes. Les mots importants d'un titre ou d'une section sont tous capitalisés, donc on écrit Extension for Named Searches (RFC 5466) et pas Extension for named searches ou Extension For Named Searches.

Et les citations ? Là encore, contrairement à ce qu'on voit souvent dans les revues scientifiques ou les actes des colloques, pas de règle impérative, à part le fait que la citation est entre crochets. Autrement, on peut citer en indiquant un court identificateur, comme « [TRILL-OAM] » (exemple pris dans le RFC 7276), ou en indiquant un numéro comme « [2] » (ce que fait par exemple le RFC 6410).

Et les abréviations ? Elle doivent être détaillées à leur première occurrence (avec l'abréviation entre parenthèses), par exemple « JavaScript Object Notation (JSON) » (vu dans le RFC 7072). On a évidemment le droit à une exception pour les abréviations que tout participant à l'IETF connaît certainement comme TCP ou HTTP. En cas d'oubli, vous avez une liste d'abréviations en ligne.

Enfin, la section 4 de notre RFC décrit la structure normale d'un RFC. Un RFC comporte un certain nombre d'éléments, pas forcément obligatoires. La première page a un contenu obligatoire, avec les avertissements juridiques (« boilerplates ») normalisés par le RFC 7841 (voir aussi le site de l'IETF trust). Elle indique aussi le ou les auteurs et leur organisation. On répète souvent que les participants à l'IETF ne représentent qu'eux-mêmes et pas leur employeur. Mais c'est largement faux, sauf pour la minorité assez riche pour se payer elle-même le temps de participation (et les voyages aux réunions). D'ailleurs, justement, l'employeur de l'auteur est indiqué dans le RFC. À noter que, si plusieurs auteurs ont le même employeur, on ne mentionne parfois ce dernier qu'une fois. Cela rend le texte ambigu : dans le RFC 6382, D. McPherson et R. Donnelly sont-ils au chômage ou bien sont-ils, comme le troisième auteur F. Scalzo, des employés de Verisign ?

La première page indique aussi le numéro ISSN des RFC, 2070-1721 et quelques autres métadonnées.

Le RFC doit aussi contenir un résumé, pour les lecteurs paresseux ou pressés. Publié seul (par exemple dans les catalogues des RFC), il doit être lisible en lui-même, sans faire appel au RFC (donc, sans citations faisant référence à la bibliographie). Souvent, il est simplement fait avec un copier/coller des premiers paragraphes de l'introduction, ce qui est autorisé mais pas forcément optimum.

Il y a parfois aussi une note, qui n'a pas été écrite par les auteurs, mais ajoutée par une des autorités qui a examiné le RFC. Par exemple, le RFC 4408 avait une note de l'IESG exprimant sa prudence vis-à-vis du problème, alors très controversé, d'authentification du courrier électronique. On peut aussi citer le RFC 4776, qui contient une note du RFC Editor expliquant que ce RFC a été publié uniquement pour corriger une erreur dans la valeur du code d'une option DHCP.

Ensuite, le corps du RFC. Il y a des parties qui dépendent du sujet du RFC. Ainsi, les RFC décrivant une MIB incluent en général le texte standard présentant les MIB (voir par exemple le RFC 4898, section 2). Et il y a des parties qu'on trouve dans tous les RFC. Certains termes ont un sens particulier dans les RFC. Ainsi, le lecteur anglophone mais non habitué aux RFC s'étonnera peut-être des MUST ou SHOULD écrits en majuscules. Ils sont définis dans le RFC 2119, l'écriture en majuscules signifiant un sens plus spécifique que le sens vague qu'ils peuvent avoir en anglais.

Les auteurs envoient parfois au RFC Editor un document pas complètement fini, notamment parce que les affectations de codes spécifiques par l'IANA n'ont pas encore été faites (RFC 5226). Par exemple, l'Internet-Draft sur le protocole Babel, draft-chroboczek-babel-routing-protocol, contenait le texte « IANA has registered the UDP port number TBD, called "babel", for use by the Babel protocol. » Une fois un port réservé officiellement, le « TBD » (To Be Done) a été remplacé et le RFC 6126 dit « IANA has registered the UDP port number 6697, called "babel", for use by the Babel protocol. ».

À la fin du RFC, se trouvent des sections plus ou moins standardisées, comme la fameuse (et obligatoire) « Security Considerations » (RFC 3552), qui doit permettre de s'assurer que les auteurs du RFC ont pensé aux problèmes de sécurité éventuels. Facultative, en revanche, la section sur les questions liées à l'internationalisation du protocole (RFC 2277).

Reste la bibliographie : elle comporte deux parties, une avec les références normatives et une avec le reste. Une des conséquences est que, si une référence normative est un Internet-Draft pas encore publié, la publication du futur RFC devra attendre. Une référence non-normative, elle, peut être un Internet-Draft non publié. Dans ce cas, il est marqué comme « Work in Progress » pour bien indiquer son manque de stabilité. Quand un RFC est cité, c'est parfois via son numéro de norme ou de BCP (Best Current Practice) car une telle référence est plus stable. Les URI sont autorisés dans la bibliographie, à condition qu'ils soient raisonnablement stables. Ainsi, BCP47 désignait au début le RFC 4646 et le RFC 4647 (oui, un BCP peut correspondre à plusieurs RFC) et, lorsque le RFC 4646 a été remplacé par le RFC 5646, le numéro de BCP n'a pas changé, pointant toujours vers la version la plus récente des bonnes pratiques.

Le RFC se termine aussi par des remerciements aux contributeurs. Le guide note qu'il n'y a pas de règles précises concernant qui est noté comme contributeur. C'est à l'initiative des auteurs. Par exemple, je suis cité comme contributeur dans dix-sept RFC mais cela correspond à des niveaux de participation très différents, d'une vraie participation à juste quelques corrections de détail. Et certains auteurs ont choisi de régler le problème des contributeurs avec une formule attrape-tout comme dans le RFC 4408 « The authors would also like to thank the literally hundreds of individuals who have participated in the development of this design. They are far too numerous to name [...] ».

Un dernier détail, les adresses de courrier électronique dans les RFC doivent être intactes (pas de modification comme rfc-editor (at) rfc-editor.org). Le but des adresses est de pouvoir contacter les auteurs et cela implique de ne pas faire de modifications.

Voilà, c'est fini. Ah, que faire en cas de conflit insoluble entre un auteur et le RFC Editor ? Comme rappelé par l'annexe A, on suit les procédures du RFC 6635.


Téléchargez le RFC 7322


L'article seul

RFC 7321: Cryptographic Algorithm Implementation Requirements and Usage Guidance for Encapsulating Security Payload (ESP) and Authentication Header (AH)

Date de publication du RFC : Août 2014
Auteur(s) du RFC : D. McGrew (Cisco Systems), P. Hoffman (VPN Consortium)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ipsecme
Première rédaction de cet article le 19 septembre 2014


Le protocole de cryptographie IPsec vient avec une liste d'obligations concernant les algorithmes cryptographiques qu'il faut inclure. Autrefois dans le RFC 4835, cette liste a été mise à jour dans ce RFC 7321, remplacé depuis par le RFC 8221. Ainsi, les différentes mises en œuvre d'IPsec sont sûres d'avoir un jeu d'algorithmes corrects en commun, assurant ainsi l'interopérabilité.

Plus précisément, ce nouveau RFC concerne les deux services d'IPsec, ESP (Encapsulating Security Payload, RFC 4303) et AH (Authentication Header, RFC 4302). Les RFC normatifs sur IPsec se veulent stables, alors que la cryptographie évolue. D'où le choix de mettre les algorithmes dans un RFC à part. Par exemple, la section 3.2 du RFC 4303 note « The mandatory-to-implement algorithms for use with ESP are described in a separate RFC, to facilitate updating the algorithm requirements independently from the protocol per se » (c'était à l'époque le RFC 4305, remplacé depuis par le RFC 4835, puis par notre RFC 7321, sept ans après son prédécesseur).

Ce RFC « extérieur » à IPsec spécifie les algorithmes obligatoires, ceux sur lesquels on peut toujours compter que le pair IPsec les comprenne, ceux qui ne sont pas encore obligatoires mais qu'il vaut mieux mettre en œuvre car ils vont sans doute le devenir dans le futur, et ceux qui sont au contraire déconseillés, en général suite aux progrès de la cryptanalyse, qui nécessitent de réviser régulièrement ce RFC (voir section 1). Cette subtilité (différence entre « obligatoire aujourd'hui » et « sans doute obligatoire demain ») mène à une légère adaptation des termes officiels du RFC 2119 : MUST- (avec le signe moins à la fin) est utilisé pour un algorithme obligatoire aujourd'hui mais qui ne le sera sans doute plus demain, en raison des avancées cryptanalytiques, et SHOULD+ est pour un algorithme qui n'est pas obligatoire maintenant mais le deviendra sans doute.

La section 2 donne la liste des algorithmes. Je ne la répète pas intégralement ici. Parmi les points à noter :

  • ESP a un mode de chiffrement intègre (authenticated encryption qu'on peut aussi traduire par chiffrement vérifié ou chiffrement authentifié, que je n'aime pas trop parce qu'on peut confondre avec l'authentification, cf. RFC 5116). Ce mode n'a pas d'algorithme obligatoire mais un SHOULD+ qui sera peut-être donc obligatoire dans la prochaine version, AES-GCM (il était MAY dans le RFC 4835).
  • Le mode le plus connu d'ESP, celui de chiffrement, a deux algorithmes obligatoires, AES-CBC (RFC 3602) et le surprenant NULL, c'est-à-dire l'absence de chiffrement (RFC 2410 ; on peut utiliser ESP pour l'authentification seule, d'où cet algorithme). Il y a aussi un algorithme noté MUST NOT, DES-CBC (RFC 2405) qui ne doit pas être mis en œuvre, afin d'être sûr qu'on ne s'en serve pas (il était seulement SHOULD NOT dans le RFC 4835).
  • Le mode d'authentification (enfin, intégrité serait peut-être un meilleur mot mais c'est subtil) d'ESP a un MUST, HMAC-SHA1 (RFC 2404) mais aussi un SHOULD+ qui pourra le rejoindre, AES-GMAC, GMAC étant une variante de GCM (et qui était en MAY dans le vieux RFC).
  • Et AH, lui, a les mêmes algorithmes que ce mode d'authentification d'ESP.

La section 3 donne des conseils sur l'utilisation d'ESP et AH. AH ne fournit que l'authentification, alors qu'ESP peut fournir également le chiffrement. Bien sûr, le chiffrement sans l'authentification ne sert pas à grand'chose, puisqu'on risque alors de parler à l'homme du milieu sans le savoir (voir l'article de Bellovin, S. « Problem areas for the IP security protocols » dans les Proceedings of the Sixth Usenix Unix Security Symposium en 1996). Certaines combinaisons d'algorithmes ne sont pas sûres, par exemple, évidemment, ESP avec les algorithmes de chiffrement et d'authentification tous les deux à NULL (voir par exemple l'article de Paterson, K. et J. Degabriele, « On the (in)security of IPsec in MAC-then-encrypt configurations » à l'ACM Conference on Computer and Communications Security en 2010). Si on veut de l'authentification/intégrité sans chiffrement, le RFC recommande d'utiliser ESP avec le chiffrement NULL, plutôt que AH. En fait, AH est rarement utile, puisque ESP en est presque un sur-ensemble, et il y a même eu des propositions de le supprimer. AH avait été prévu pour une époque où le chiffrement était interdit d'utilisation ou d'exportation dans certains pays et un logiciel n'ayant que AH posait donc moins de problèmes légaux. Aujourd'hui, la seule raison d'utiliser encore AH est si on veut protéger certains champs de l'en-tête IP, qu'ESP ne défend pas.

La section 4 de notre RFC donne quelques explications à certains des choix d'algorithmes effectués. Le chiffrement intègre/authentifié d'un algorithme comme AES-GCM (RFC 5116 et RFC 4106) est la solution recommandée dans la plupart des cas. L'intégration du chiffrement et de la vérification d'intégrité est probablement la meilleure façon d'obtenir une forte sécurité. L'algorithme de chiffrement AES-CTR (auquel on doit ajouter un contrôle d'intégrité) n'a pas de faiblesses cryptographiques, mais il ne fournit aucun avantage par rapport à AES-GCM (ne tapez pas sur le messager : c'est ce que dit le RFC, je sais que tous les cryptographes ne sont pas d'accord, par exemple parce qu'ils trouvent GCM beaucoup plus complexe).

Par contre, Triple DES et DES, eux, ont des défauts connus et ne doivent plus être utilisés. Triple DES a une taille de bloc trop faible et, au-delà d'un gigaoctet de données chiffrées avec la même clé, il laisse fuiter des informations à un écoutant, qui peuvent l'aider dans son travail de décryptage. Comme, en prime, il est plus lent qu'AES, il n'y a vraiment aucune raison de l'utiliser. (DES est encore pire, avec sa clé bien trop courte. Il a été cassé avec du matériel dont les plans sont publics.)

Pour l'authentification/intégrité, on sait que MD5 a des vulnérabilités connues (RFC 6151), question résistance aux collisions. Mais cela ne gêne pas son utilisation dans HMAC-MD5 donc cet algorithme, quoique non listé pour IPsec, n'est pas forcément ridicule aujourd'hui. SHA-1 a des vulnérabilités analogues (quoique beaucoup moins sérieuses) mais qui ne concernent pas non plus son utilisation dans HMAC-SHA1, qui est donc toujours en MUST. Bien que les membres de la famille SHA-2 n'aient pas ces défauts, ils ne sont pas cités dans ce RFC, SHA-1 étant très répandu et largement suffisant.

Dans le précédent RFC, Triple DES était encore noté comme une alternative possible à AES. Ce n'est plus le cas aujourd'hui, où les vulnérabilités de Triple DES sont bien connues (sans compter ses performances bien inférieures). Triple DES est maintenu dans IPsec (il est en MAY) mais uniquement pour des raisons de compatibilité avec la base installée. Le problème est qu'il n'y a donc plus de solution de remplacement si un gros problème est découvert dans AES (section 5, sur la diversité des algorithmes). Il n'y a aucune indication qu'une telle vulnérabilité existe mais, si elle était découverte, l'absence d'alternative rendrait le problème très sérieux.

Voilà, c'est fini, la section 8 sur la sécurité rappelle juste quelques règles bien connues, notamment que la sécurité d'un système cryptographique dépend certes des algorithmes utilisés mais aussi de la qualité des clés, et de tout l'environnement (logiciels, humains).

Ce RFC se conclut en rappelant que, de même qu'il a remplacé ses prédécesseurs comme le RFC 4835, il sera probablement à son tour remplacé par d'autres RFC, au fur et à mesure des progrès de la recherche en cryptographie. (Ce fut fait avec le RFC 8221.)

Si vous voulez comparer avec un autre document sur les algorithmes cryptographiques à choisir, vous pouvez par exemple regarder l'annexe B1 du RGS, disponible en ligne.

Merci à Florian Maury pour sa relecture acharnée. Naturellement, comme c'est moi qui tiens le clavier, les erreurs et horreurs restantes viennent de ma seule décision. De toute façon, vous n'alliez pas vous lancer dans la programmation IPsec sur la base de ce seul article, non ?


Téléchargez le RFC 7321


L'article seul

RFC 7320: URI Design and Ownership

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : M. Nottingham
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 12 juillet 2014


Ah, les URI... Comme ces identificateurs sont très souvent vus et manipulés par un grand nombre d'utilisateurs, ils suscitent forcément des passions et des discussions sans fin. Ce RFC de bonne pratique s'attaque à un problème fréquent : les applications ou extensions qui imposent des contraintes sur l'URI, sans que cela soit justifié par le format de ces URI. Par exemple, on voit des CMS imposer, au moment de l'installation, que le CMS soit accessible par un URI commençant par le nom du logiciel. S'il s'appelle Foobar, on voit parfois des logiciels qui ne marchent que si l'URI commence par http://www.example.org/Foobar/. Pourquoi est-ce une mauvaise idée et que faudrait-il faire à la place ? (Ce RFC a depuis été remplacé par le RFC 8820, moins normatif.)

D'abord, l'argument d'autorité qui tue : la norme des URI, le RFC 3986, dit clairement que la structure d'un URI est déterminé par son plan (scheme en anglais) et que donc l'application n'a pas le droit d'imposer des règles supplémentaires. Les deux seuls « propriétaires » sont la norme décrivant le plan (qui impose une syntaxe, et certains éléments, par exemple le nom du serveur avec le plan http://) et l'organisation qui contrôle cet URI particulier (par exemple, toujours pour http://, l'organisation qui contrôle le domaine dans l'URI). Imposer des règles, pour une application ou une extension, c'est violer ce principe de propriété. (Il est formalisé dans une recommandation du W3C, section 2.2.2.1.)

Un exemple de structure dans les URI est l'interprétation du chemin (path en anglais) comme étant un endroit du système de fichiers. Ainsi, bien des serveurs HTTP, en voyant l'URI http://www.example.org/foo/bar/toto.html, chercheront le fichier en $DOCUMENT_ROOT/foo/bar/toto.html. C'est une particularité de la mise en œuvre de ce serveur, pas une obligation du plan d'URI http://. Un autre exemple est l'utilisation de l'extension du nom de fichier comme moyen de trouver le type de média de la ressource. (« Ça se termine en .png ? On envoie le type image/png. ») Ces deux cas ne violent pas forcément le principe de propriété des URI car l'utilisateur, après tout, choisit son serveur.

Mais, dans certains cas, l'imposition d'une structure (autre que celle déjà imposée par la norme du plan d'URI) a des conséquences néfastes :

  • Risque de collisions entre deux conventions différentes.
  • Risque d'instabilité si on met trop d'informations dans l'URI (voir la section 3.5.1 du document « Architecture of the World Wide Web, Volume One », cité plus haut). Pour reprendre l'exemple de l'extension du fichier, si on change le format de l'image de PNG en JPEG, l'URI changera, ce qui est néfaste.
  • Rigidité accrue. Si un logiciel impose d'être installé en /Foobar comme dans l'exemple au début, il contraint les choix pour l'administrateur système (et si je veux des URI avec un chemin vide, genre http://foobar.example.org/, je fais quoi ?)
  • Risque que le client fasse des suppositions injustifiées. Si une spécification décrit le paramètre sig comme étant forcément une signature cryptographique, il y a une possibilité qu'un logiciel client croit, dès qu'il voit un paramètre de ce nom, que c'est une signature.

Donc, pour toutes ces raisons, notre RFC déconseille fortement de rajouter des règles de structure dans les URI. Ces règles diminuent la liberté du propriétaire de l'URI.

Qui risque de violer ce principe ? Les auteurs d'applications, comme dans l'exemple Foobar plus haut, mais aussi des gens qui font des extensions aux URI, par le biais de nouvelles spécifications (par exemple pour mettre des signatures ou autres métadonnées dans l'URI). En revanche, ce principe ne s'applique pas au propriétaire lui-même, qui a évidemment le droit de définir ses règles pour la gestion de ses URI (exemple : le webmestre qui crée un schéma de nommage des URI de son site Web). Et cela ne s'applique pas non plus au cas où le propriétaire de l'URI reçoit lui-même une délégation pour gérer ce site (par exemple, un RFC qui crée un registre IANA et spécifie la structure des URI sous https://www.iana.org/ est dans son droit, l'IANA agissant sur délégation de l'IETF). Le principe « bas les pattes » de ce RFC n'est pas technique : on n'interdit pas de mettre de la structure dans les URI, on dit juste qui a le droit de le faire.

Notre RFC reconnait que certaines normes IETF (non citées...) violent ce principe, et appelle à profiter de la prochaine révision pour les corriger.

La partie normative de notre RFC est la section 2. Elle explicite le principe « bas les pattes » (« get off my lawn » dans le nom original du document en anglais...) D'abord, éviter de contraindre l'usage d'un plan particulier. Par exemple, imposer http:// peut être trop contraignant, certaines applications ou extensions pourraient marcher avec d'autres plans d'URI comme par exemple file:// (RFC 8089).

D'autre part, si on veut une structure dans les URI d'un plan particulier, cela doit être spécifié dans le document qui définit le plan (RFC 7230 pour http://, RFC 6920 pour ni:, etc) pas dans une extension faite par d'autres (« touche pas à mon plan »).

Les URI comprennent un champ « autorité » juste après le plan. Les extensions ou applications ne doivent pas imposer de contraintes particulières sur ce champ. Ainsi, pour http://, l'autorité est un nom de domaine et notre RFC ne permet pas qu'on lui mette des contraintes (du genre « le premier composant du nom de domaine doit commencer par foobar-, comme dans foobar-www.example.org »).

Même chose pour le champ « chemin », qui vient après l'autorité. Pas question de lui ajouter des contraintes (comme dans l'exemple du CMS qui imposerait /Foobar comme préfixe d'installation). La seule exception est la définition des URI bien connus du RFC 8615. Le RFC 6415 donne un exemple d'URI bien connus, avec une structure imposée.

Autre conséquence du principe « bas les pattes » et qui est, il me semble, plus souvent violée en pratique, le champ « requête » (query). Optionnel, il se trouve après le point d'interrogation dans l'URI. Notre RFC interdit aux applications d'imposer l'usage des requêtes, car cela empêcherait le déploiement de l'application dans d'autres contextes où, par exemple, on veut utiliser des URI sans requête (je dois dire que mes propres applications Web violent souvent ce principe). Quant aux extensions, elles ne doivent pas contraindre le format des requêtes. L'exemple cité plus haut, d'une extension hypothétique, qui fonctionnerait par l'ajout d'un paramètre sig aux requêtes pour indiquer une signature est donc une mauvaise idée. Une telle extension causerait des collisions (applications ou autres extensions qui voudraient un paramètre de requête nommé sig) et des risques de suppositions injustifié (un logiciel qui se dirait « tiens, un paramètre sig, je vais vérifier la signature, ah, elle est invalide, cet URI est erroné »). Au passage, les préfixes n'aident pas. Supposons qu'une extension, voulant limiter le risque de collisions, décide que tous les paramètres qu'elle définit commencent par myapp_ (donc, la signature serait myapp_sig). Cela ne supprime pas le risque de collisions puisque le préfixe lui-même ne serait pas enregistré.

Sauf erreur, Dotclear gère bien cela, en permettant, via les « méthodes de lecture » PATH_INFO ou QUERY_STRING d'avoir les deux types d'URI (sans requête ou bien avec).

Pourtant, HTML lui-même fait cela, dans la norme 4.01, en restreignant la syntaxe lors de la soumission d'un formulaire. Mais c'était une mauvaise idée et les futures normes ne devraient pas l'imiter.

Comme précédemment, les URI bien connus ont, eux, droit à changer la syntaxe ou contraindre les paramètres puisque, d'une certaine façon, l'espace sous .well-known est délégué à l'IETF et n'est plus « propriété » de l'autorité.

Dernier champ de l'URI à étudier, l'identificateur de fragment (ce qui est après le croisillon). Les définitions d'un type de média (RFC 6838) ont le droit de spécifier la syntaxe d'un identificateur de fragment spécifique à ce type de média (comme ceux du texte brut, dans le RFC 5147). Les autres extensions doivent s'en abstenir.

Bon, assez de négativité et d'interdiction. Après les « faites pas ci » et les « faites pas ça », la section 3 de notre RFC expose les alternatives, les bonnes pratiques pour remplacer celles qui sont interdites ici. D'abord, si le but est de faire des liens, il faut se rappeler qu'il existe un cadre complet pour cela, décrit dans le RFC 8288. Une application peut utiliser ce cadre pour donner la sémantique qu'elle veut à des liens. Autre technique rigolote et peu connue, les gabarits du RFC 6570, qui permettent de gérer facilement le cas de données spécifiques à l'application dans un URI.

Et, comme cité plusieurs fois, les URI bien connus du RFC 8615 sont un moyen de déclarer sa propre structure sur des URI. Par contre, ils sont censés avoir un usage limité (accéder à des métadonnées avant de récupérer une ressource) et ne sont pas un moyen générique d'échapper aux règles qui nous dérangent !


Téléchargez le RFC 7320


L'article seul

RFC 7314: Extension Mechanisms for DNS (EDNS) EXPIRE Option

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : M. Andrews (ISC)
Expérimental
Première rédaction de cet article le 18 juillet 2014


L'enregistrement DNS SOA (Start Of Authority) a un champ expire qui indique au bout de combien de temps un serveur esclave qui ne réussit pas à contacter le maître peut arrêter de servir la zone. Si l'esclave a eu les données, non pas directement du maître, mais d'un autre esclave, la durée d'expiration peut ne pas être correcte. C'est ce (rare) problème que règle l'option EDNS EXPIRE.

En effet, il faut se rappeler que la distribution d'une zone DNS depuis un serveur maître (le RFC utilise l'ancien terme de « serveur primaire ») n'est pas forcément directe. On peut avoir un maître qui envoie des données à un esclave, qui à son tour les envoie à un autre esclave. Cela permet notamment davantage de robustesse (si le maître n'est temporairement pas joignable depuis certains esclaves). Notez que l'esclave ne sait même pas si la machine qui lui a envoyé les données était un maître ou pas.

Si la période de validité donnée par le champ expire du SOA (RFC 1035, section 3.3.13) vaut V et que le transfert de l'esclave à un autre esclave prend place S secondes après le transfert depuis le maître (les transferts ne sont pas forcément instantanés, par exemple en cas de coupure réseau), la zone sera servie pendant V + S secondes et pas seulement pendant V secondes. Pire, s'il existe une boucle dans le graphe de distribution, la zone risque de ne jamais expirer, les esclaves se rafraichissant mutuellement.

Personnellement, le problème me semble rare et de peu d'importance. Il y a des tas d'autres choses plus urgentes à régler dans le DNS. Mais, bon, c'est juste une expérience.

La nouvelle option de ce RFC dépend de EDNS (RFC 6891). Elle a le numéro 9. Mise dans une requête (a priori une requête de type SOA, AXFR ou IXFR), elle indique que le client DNS connait cette option et voudrait sa valeur. Un serveur qui ne connait pas l'option EXPIRE ne mettra pas l'option dans sa réponse.

Par contre, un serveur qui connait cette option répondra avec une option EXPIRE dans sa réponse. Elle comporte quatre octets de données (comme pour le champ expire du SOA), indiquant le nombre de secondes de la période de validité. Si le serveur est un maître, il met toujours dans cette option la valeur du champ expire du SOA. S'il est un esclave, il met la valeur actuelle de son compteur d'expiration. Ainsi, si le champ expire du SOA vaut 7 200 secondes (2 heures) et que le serveur secondaire reçoit une demande 30 minutes après le transfert depuis le maître, il mettra 5 400 dans l'option EDNS EXPIRE (120 minutes de validité moins les 30 minutes écoulées). C'est ainsi qu'on évite l'accumulation des périodes de validité en cas de transfert indirect.

Un serveur esclave (le RFC utilise l'ancien terme de « serveur secondaire ») qui utilise l'option, et qui reçoit une réponse lors d'un transfert initial de la zone, devrait utiliser comme durée de validité la valeur de l'option EXPIRE (et pas le champ expire du SOA, sauf si ce champ a une valeur inférieure à celle de l'option EXPIRE). Cette durée de validité est ensuite mise dans un compteur d'expiration qui décroît avec le temps. Pour les rafraichissements ultérieurs, le serveur esclave doit également utiliser comme durée de validité la valeur de l'option, sauf si le compteur actuel a une valeur plus élevée. Par exemple, si le compteur du secondaire dit que la zone est encore valable pour 4 500 secondes, et qu'une réponse IXFR (RFC 1995) contient une option EXPIRE de valeur 9 300 secondes, alors le compteur est mis à 9 300 secondes. Si l'option EXPIRE avait valu 2 400 secondes, le compteur n'aurait pas été modifié.

Une conséquence amusante de cette option est qu'elle permet de savoir quand a eu lieu le dernier transfert de zone réussi, juste en interrogeant un esclave. Cela peut être vu comme indiscret, mais cela peut aussi être un outil de supervision très pratique.

Cette option est utilisable depuis dig, à partir de la version 9.10. Wireshark a récemment été modifié pour reconnaître cette option.


Téléchargez le RFC 7314


L'article seul

RFC 7305: Report from the IAB Workshop on Internet Technology Adoption and Transition (ITAT)

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : E. Lear
Pour information
Première rédaction de cet article le 19 août 2014


En décembre 2013, à Cambridge, l'IAB a tenu un atelier sur l'adoption des nouvelles technologies dans l'Internet. Qu'est-ce qui fait que telle technologie réussit dans le monde réel et que telle autre reste éternellement sur le papier ? Sérieuse question pour l'IETF, qui a a normalisé aussi bien des succès fous que des échecs plus ou moins complets. (Par exemple, le déploiement de la grande œuvre de l'IETF, IPv6, est extrêmement lent.)

Ce RFC résume les contributions à l'atelier. Comme on s'en doute, il n'y a eu aucun consensus, à part sur l'importance d'étudier l'angle de l'économie, et sur la référence à Bitcoin, grande vedette de l'atelier et source de nombreux exemples. Attention, donc, ce RFC n'est pas une prise de position de l'IAB, mais le compte-rendu d'un colloque pluraliste, aussi bien dans ses participants que dans les opinions exprimées. (Le rôle de l'IAB n'est pas de faire des protocoles - c'est la tâche de l'IETF, sous la direction de l'IESG - mais de réfléchir sur le long terme et sur les questions les plus fondamentales.)

On représente souvent l'écosystème de l'Internet sous forme d'un sablier : le protocole standard d'interconnexion est forcément unique et occupe donc la « taille », le tuyau fin du sablier. Au contraire, les protocoles d'application, beaucoup plus nombreux, occupent le bulbe du haut, et les protocoles « physiques », pour lesquels il y a également un grand choix, sont le bulbe du bas. Dans la vision traditionnelle de l'Internet, la taille était IP.

Dans la biologie, c'est l'ATP qui joue ce rôle central, la brique de base sur laquelle tout le reste est bâti (papier de Meyer).

Aujourd'hui, en raison de l'ossification de l'Internet et de la prévalence de stupides middleboxes qui bloquent tout, la taille (ou faut-il l'appeler le cou ?) du sablier est plutôt HTTP... Il devient de plus en plus difficile pour un protocole de s'imposer, surtout s'il ne tourne pas sur HTTP. En prime, le poids de l'existant est bien plus important qu'aux débuts de l'Internet. Aujourd'hui, un nouveau protocole doit lutter contre des concurrents bien installés.

La section 2 de notre RFC résume les motivations de ce travail, et les travaux équivalents déjà réalisés. On constate souvent que des protocoles, développés soigneusement par l'IETF, ont peu ou pas de succès dans le monde réel et, quand ils se répandent, c'est à un rythme bien trop lent. Trois exemples sont cités par le RFC, IPv6 (RFC 2460), SCTP (RFC 4960) et DNSSEC (RFC 4034). Ce retard peut à son tour retarder d'autres déploiements. Ainsi, DNSSEC est indispensable à DANE (RFC 6698) et le déploiement trop lent de DNSSEC, goulet d'étranglement, affecte donc DANE. Par contre, si les protocoles nouveaux ont du mal, les protocoles existants continuent à évoluer (le RFC cite SMTP et IMAP, qui peuvent être vus comme des réfutations de la théorie comme quoi « HTTP est le nouvel IP, la taille du sablier »).

Un excellent RFC avait déjà étudié les causes du succès ou de l'échec des protocoles, le RFC 5218. Une conséquence de ce RFC 5218 est l'importance plus grande désormais donnée aux facteurs de réussite. Faire un bon protocole ne suffit plus. Les groupes de travail de l'IETF doivent désormais aussi réfléchir à la valeur ajoutée de leurs propositions : le nouveau protocole apporte-t-il suffisamment pour surmonter les barrières situées devant l'adoption ?

Ces barrières étant largement financières, il n'est pas étonnant que plusieurs des papiers présentés à l'atelier portaient sur l'économie (section 3). Le RFC en résume quelques uns. D'abord, la théorie de Weber, S., Guerin, R., et J. Oliveira, sur le couplage. Peut-on augmenter les chances de succès d'un protocole en le livrant avec d'autres ? Ou, au contraire, le couplage va-t-il ralentir le succès ? Comme cité précédemment, DANE dépend de DNSSEC. Cela simplifie son développement, permettant de s'appuyer sur les propriétés de sécurité de DNSSEC. Mais, du point de vue économique, cela fait dépendre DANE du succès de DNSSEC. Le couplage peut aider quand une technologie à succès en tire une autre, et ralentir si une technologie dépend d'une autre.

Autre exemple, très discuté à l'atelier (et c'est une nouveauté à l'IETF, puisque ce système a été développé en dehors de celle-ci), le succès de Bitcoin. Dans son papier, R. Boehme suggère que les protocoles Internet s'inspirent de Bitcoin, exemple de grand succès (section 3.2 de notre RFC). Bitcoin n'a pas eu la partie facile : des médias hostiles (parfois au point de la propagande, comme dans le mensonge souvent répété comme quoi Bitcoin était une pyramide de Ponzi), des incertitudes juridiques (est-ce bien légal ?), des failles techniques (immédiatement exploitées par des voleurs), plusieurs tentatives de « monnaies Internet » avaient déjà été des échecs, des attaques par des spéculateurs visant le gain à court terme, même au prix de l'existence même du système. Mais Bitcoin a survécu à ces campagnes de presse et à ces problèmes techniques et de sécurité. Selon l'auteur, les raisons principales sont :

  • Un mécanisme de récompense des premiers qui adoptent le système. Au début de Bitcoin, miner (créer de nouveaux bitcoins) est relativement facile et cela se durcit par la suite. Les plus difficiles à convaincre, les premiers adoptants, sont donc récompensés davantage, ce qui est logique et efficace. (J'ajoute personnellement que c'est juste : il est normal que ceux qui ont pris des risques au début reçoivent plus que ceux qui attendaient passivement.)
  • Bitcoin ne vit pas dans son coin, isolé. Dès le début, des mécanismes de conversion ont été mis en place de et vers les monnaies d'État. Ainsi, adopter Bitcoin ne signifiait pas s'enfermer dans un monde à part. Un autre exemple, cité par le RFC, est le succès du courrier électronique : dès le début, le courrier Internet a eu des passerelles de et vers les autres systèmes de courrier. Autrement, il n'aurait pas été choisi.
  • Les bitcoins ont une valeur pour leurs possesseurs, ce n'est pas juste pour le bien de l'humanité qu'on demande aux utilisateurs d'adopter la nouvelle technologie : ils y trouvent un intérêt. (Une remarque personnelle : les discussions à l'atelier supposaient acquis un point de vue égoïste, où les gens n'agissent qu'en fonction d'un intérêt personnel à court terme. Le problème serait très différent si on se plaçait dans une perspective plus volontariste, où on considère que les humains peuvent changer leur mentalité.)

Bref, Bitcoin fournit des motivations à ses adopteurs. (Un problème bien connu des militants pro-IPv6 : lorsqu'on suggère aux gens de migrer vers IPv6, la question est souvent « qu'est-ce que ça m'apporte, à moi ? », et elle n'a guère de réponse.)

Troisième étude de cas, le déploiement de DNSSEC (section 3.3) via le récit de A. Eklund Lowinder et P. Wallstrom sur le déploiement de cette technique en Suède, à commencer par le TLD .se. Le travail d'IIS pour encourager DNSSEC a pris la forme d'une contribution au financement d'OpenDNSSEC (pour abaisser les barrières techniques), et d'incitations financières (auprès des bureaux d'enregistrement).

Une des conclusions de cette partie de l'atelier était qu'il faut éviter d'accrocher une technologie exclusivement à une autre. Le logiciel privateur Skype a été cité comme exemple : il teste plusieurs transports disponibles et choisit celui qui marche. De même, lier une application à SCTP serait probablement une erreur : si SCTP ne réussit pas à se répandre, cette application serait fichue). Il faudrait plutôt essayer plusieurs transports et garder le premier qui marche, un peu comme le fait l'algorithme des globes oculaires heureux dans le RFC 6555.

Et puisqu'on parlait d'économie, il y a eu évidemment des discussions sur le modèles de prix, comme suite au papier de S. Sen. Par exemple, certains protocoles pourraient bénéficier d'un prix dépendant de l'heure (pour encourager le trafic à se déplacer vers les heures creuses).

Ah, une question qui est dans la section 5 mais qui aurait eu sa place dans celle sur l'économie : celle des brevets. Leurs effets néfastes sont bien connus. Le papier de E. Lear et D. Mohlenhoff décrit leurs relations avec la normalisation. Le plus gros problème identifié est celui des « brevets sous-marins », brevets que l'IETF ne connait pas... jusqu'au moment où il est trop tard.

Mais l'économie ne peut pas tout résoudre. Les choix se font aussi, mais si ce n'est pas la seule motivation, sur la qualité technique. De ce point de vue-là, pour qu'un protocole réussisse, il faut aussi faire en sorte qu'il soit le « meilleur » possible. Par exemple, est-ce que le processus de normalisation de l'Internet est suffisamment bien connecté au monde de la recherche, où s'élaborent les idées du futur ? Normalement, l'IETF ne normalise que des technologies bien maîtrisées. L'interaction avec la recherche se fait via l'IRTF.

Les chercheurs suggèrent parfois que l'architecture actuelle de l'Internet n'est plus adaptée aux défis futurs, et qu'il faudrait la changer, par exemple dans la direction du Lowest Common Denominator Networking, idée qui a apparemment été mal reçue à l'atelier.

Un atelier n'est pas complet sans une rubrique « Divers » (section 6) et deux autres points ont donc été abordés. D'abord, la résilience de l'Internet, et notamment la sécurité du routage. Le papier d'A. Robachevsky l'abordait en partant de l'éculée référence à la tragédie des terres communales. L'Internet est composé d'un grand nombre de réseaux distincts, sans administration centrale (ce qui est une bonne chose). La tentation peut donc être forte de se servir des communs (comme la table de routage globale) sans souci de leur pérennité, sans gestion collective.

Et un deuxième point « Divers » concernait TLS. TLS est très largement adopté et ne souffre pas, a priori, du syndrome du protocole qu'on n'arrive pas à déployer. Mais la très grande majorité des clients et serveurs existants utilisent des vieilles versions du protocole TLS, ayant des vulnérabilités connues (comme Beast). La version la plus récente de TLS, la 1.2, est normalisée dans le RFC 5246. Comment faire en sorte qu'elle soit déployée partout ? Et le problème ne concerne pas que le protocole lui-même mais aussi les algorithmes de cryptographie utilisés. (Au cours de l'atelier, il a été noté qu'une grande partie du trafic est toujours chiffrée avec Triple DES, algorithme aux faiblesses connues.)

Maintenant, les actions (section 7). La conclusion de ce RFC reconnait l'importance de regarder le succès des systèmes comme Bitcoin, mentionné pour la première fois dans un RFC, et un exemple pour tout nouveau système. Autrement, l'idée la plus intéressante me semble être celle de pousser la collaboration avec le monde académique, par exemple en enrôlant des étudiants pour relire et critiquer les documents IETF. Cela fournirait à ces étudiants une excellente occasion d'apprendre, et à l'IETF plein de regards neufs.


Téléchargez le RFC 7305


L'article seul

RFC 7304: A method for mitigating namespace collisions

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : W. Kumari (Google)
Pour information
Première rédaction de cet article le 7 juillet 2014


Il arrive parfois, lors de l'utilisation d'un nom de domaine, qu'il y ait plusieurs noms qui correspondent à l'intention exprimée par l'utilisateur humain (dans les milieux ICANN, c'est souvent appelé une collision, terme brutal conçu pour faire peur). Par exemple, si l'utilisateur dans une entreprise example.com tape « www.foobar » dans son navigateur Web, peut-être comptait-il aller en http://www.foobar.example.com/ en comptant sur le fait que le logiciel complètera (ce qu'on nomme une search list) mais peut-être aussi voulait-il aller en http://www.foobar/ (le TLD .foobar n'existe pas aujourd'hui mais, au rythme où des TLD sont créés, cela pourrait arriver un jour). Dans ces conditions, comment faire pour désambiguer ? Ce très court RFC décrit une méthode... et explique pourquoi elle est fortement déconseillée.

Ce problème n'est pas spécifique aux search lists. On peut aussi l'avoir lorsque plusieurs espaces de nommage sont utilisés, par exemple en cas de « racines alternatives ». Les partisans desdites racines écartent souvent le problème de « collision » entre deux racines en disant « il suffira de demander à l'utilisateur son choix ». Pourquoi est-ce une mauvaise idée (mon intention était d'écrire « une idée idiote » mais le RFC dont je rends compte est plus prudent) ?

La section 2 de notre RFC décrit la méthode et ses défauts : si le nom n'a qu'une signification possible, on y va, sinon on présente à l'utilisateur une liste des possibilités « vouliez-vous aller en http://www.foobar.example.com/ ou en http://www.foobar/ ? » et on lui demande de choisir. On peut mémoriser ce choix, pour éviter de demander trop souvent à l'utilisateur. Mes lecteurs techniques voient sans doute immédiatement pourquoi cela ne peut pas marcher, mais ce RFC est conçu à des fins pédagogiques, pour tordre le cou une bonne fois pour toutes à cette fausse bonne idée, qui resurgit de temps en temps.

Quels sont les problèmes avec cette approche (si vous êtes enseignant en informatique, vous pouvez faire de cette question un sujet d'interrogation, pour voir si les étudiants ont bien compris les réseaux) ?

  • Il n'y a pas toujours un humain disponible devant l'écran. Il y a des serveurs fonctionnant automatiquement, et des applications qui s'exécutent en arrière-plan (comme les mises à jour périodiques).
  • L'humain peut ne pas savoir, notamment si le choix découle d'une tentative de hameçonnage ou autre tentative délibérée de l'induire en erreur.
  • Le délai supplémentaire pendant lequel l'utilisateur réfléchit peut conduire l'application à renoncer.
  • Ces demandes perpétuelles peuvent être pénibles pour l'utilisateur (songez qu'une seule page Web peut comporter des dizaines de noms de domaine).
  • Mémoriser les choix résoudrait partiellement le problème précédent, mais créerait d'autres ennuis, par exemple en cas de déplacement (si l'utilisateur se servait d'un portable et qu'il quitte les locaux de example.com).

Bref, c'est une mauvaise solution et notre RFC la déconseille. Par contre, il ne propose pas d'alternative (il n'y en a pas de sérieuse).

Pous les informaticiens, notez que, question mise en œuvre technique d'une telle solution, on aurait plusieurs possibilités : intercepter les requêtes de résolution de noms dans un shim, une mince couche logicielle entre l'application et la bibliothèque de résolution de noms (c'est ainsi que sont souvent mis en œuvre des TLD « alternatifs » comme .bit ou .onion) ou bien en remplaçant complètement la bibliothèque de résolution de noms. On pourrait encore mettre ce service dans le navigateur Web (ignorant les problèmes des applications non-Web), ou dans un relais sur le trajet.


Téléchargez le RFC 7304


L'article seul

RFC 7303: XML Media Types

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : H. Thompson (University of Edinburgh), C. Lilley (W3C)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 11 juillet 2014


Voici la nouvelle norme décrivant les types MIME XML, comme application/xml. Elle remplace le RFC 3023. Cette norme décrit aussi l'utilisation de +xml comme suffixe pour des formats de données fondés sur XML comme TEI, avec son application/tei+xml.

XML est une norme du W3C et n'est donc pas dans un RFC mais dans un document du W3C. Lorsque des documents sont envoyés sur l'Internet, ils sont souvent étiquetés avec un type de média, dit aussi, pour des raisons historiques, type MIME. Pour XML, il existe cinq types, application/xml, text/xml, application/xml-external-parsed-entity, text/xml-external-parsed-entity et application/xml-dtd. Il existe aussi une convention, formalisée dans le RFC 6838, pour les formats bâtis au-dessus de XML, comme Atom (RFC 4287). On écrit les types de média pour ces formats avec un +xml à la fin, indiquant ainsi qu'un processeur XML généraliste pourra toujours en faire quelque chose, même s'il ne connait pas ce format spécifique. Ainsi, Atom est application/atom+xml. (Ces suffixes sont désormais banals mais, à l'époque du RFC 3023, ils étaient contestés et l'annexe A du RFC 3023 contient une justification détaillée, qui n'a pas été reprise dans ce nouveau RFC 7303.)

Pour normaliser quelque chose à propos de XML, il faut d'abord se pencher sur les problèmes d'encodage de caractères. Le modèle de caractères de XML est forcément Unicode.Les encodages de documents peuvent être très divers, mais la norme Unicode n'en définit que trois, UTF-8, UTF-16 et UTF-32. UTF-8 (RFC 3629) représente les caractères par une suite d'octets de longueur variable. Il n'a qu'une seule sérialisation en octets possible. UTF-16 en a deux, car il représente les caractères (enfin, ceux du PMB) par des seizets. Selon qu'on mette l'octet de poids fort du seizet en premier ou en dernier, on parle d'UTF-16 gros-boutien (utf-16be dans une déclaration XML) ou d'UTF-16 petit-boutien (utf-16le). Quant à UTF-32, qui est le plus simple des encodages, car le plus uniforme (tout caractère Unicode est représenté par quatre octets, codant son point de code), il a quatre sérialisations possibles en théorie mais deux seulement sont définies, UTF-32BE, gros-boutien, et UTF32-LE, petit-boutien. UTF-32 est malheureusement peu déployé (qu'on ne me dise pas que c'est parce qu'il prend plus de place : quatre octets par caractère, à l'époque où on s'échange des vidéos HD, ce n'est rien). Ce RFC déconseille désormais son usage. (Une bonne discussion des problèmes avec UTF-32 est dans ce rapport de bogue chez Mozilla.)

La section 3 du RFC décrit toutes les recommandations actuelles pour l'encodage des documents XML envoyés sur l'Internet. UTF-8 est recommandé (et sans BOM : il faut le retirer si, par exemple, on convertit de l'UTF-16 en UTF-8). Les producteurs/envoyeurs de XML devraient mettre un paramètre charset (pour les protocoles qui ont ce paramètre) et utiliser la déclaration XML (le truc qui commence par <?xml version="1.0" encoding=...) lorsqu'ils utilisent autre chose qu'UTF-8.

Cela suppose qu'ils sachent exactement quel est l'encodage. Si on envoie de l'XML et qu'on ne peut pas déterminer son encodage, il vaut mieux ne rien dire que de raconter n'importe quoi. Le RFC note que c'est particulièrement important pour les serveurs Web : avoir un paramètre global pour tout le site qui indique un encodage est dangereux, à moins qu'on puisse être absolument sûr que tous les documents du site auront cet encodage. Le RFC recommande que cet étiquetage soit configurable par l'utilisateur, pour qu'il puisse l'adapter à ses fichiers (AddDefaultCharset et AddCharset dans Apache.)

Quant aux consommateurs de documents XML, ils doivent considérer le BOM comme faisant autorité, et utiliser le paramètre charset si le BOM est absent. Les consommateurs qui comprennent le XML peuvent, s'il n'y a ni BOM, ni charset, utiliser les techniques purement XML, exposées dans la norme de ce format (en gros, utiliser la déclaration par exemple <?xml version="1.0" encoding="ISO 8859-1"?>. Il y a plein d'exemples en section 8 du RFC. Par exemple, ce cas-ci :


Content-Type: application/xml; charset=utf-8
...
<?xml version="1.0" encoding="utf-8"?>

est trivial : tout le monde est d'accord, le document est en UTF-8 et c'est explicite. En revanche, ce cas :


Content-Type: application/xml; charset=iso-8859-1
...
<?xml version="1.0" encoding="utf-8"?>

est pathologique : le type MIME dans l'en-tête HTTP et la déclaration XML se contredisent. Ici, un logiciel respectueux des normes doit traiter le document comme de l'ISO 8859-1, le type MIME ayant priorité (il n'y a pas de BOM, qui aurait une priorité supérieure). Mais, évidemment, l'envoyeur n'aurait pas dû générer ces informations incohérentes. Il vaut mieux ne pas envoyer de charset que d'envoyer un incorrect (voir aussi annexe C.2). Ainsi, dans ce troisième exemple :


Content-Type: application/xml
...
<?xml version="1.0"?>

il n'y a rien d'explicite : pas de BOM, pas de charset dans le type MIME et pas d'encodage indiqué dans la déclaration XML. Dans ce cas, puisque MIME ne dit rien, on applique la règle XML : l'encodage par défaut en XML est UTF-8.

À noter que le transport le plus utilisé pour XML, HTTP, avait un encodage de caractères par défaut, ISO 8859-1 mais ce n'est plus le cas depuis le RFC 7230. Voir aussi le RFC 6657 pour l'encodage par défaut des types text/*.

Assez fait d'encodage, place aux types MIME, sujet principal de ce RFC. La section 4 donne leur liste :

  • Les documents XML eux-mêmes auront le type application/xml ou text/xml. Le RFC ne tranche pas entre les deux possibilités, alors que ce choix a fait se déplacer beaucoup d'électrons, lors des innombrables discussions sur le « meilleur » type. (Le prédécesseur, le RFC 3023 recommandait text/xml.)
  • Les DTD auront le type application/xml-dtd.
  • Les « entités externes analysées » (external parsed entities), sont de type application/xml-external-parsed-entity ou text/xml-external-parsed-entity. Si elles sont par ailleurs des documents XML bien formés (ce qui n'est pas toujours le cas), elles peuvent avoir les types application/xml ou text/xml.
  • Les paramètres externes (external parameter entities) ont le même type que les DTD, application/xml-dtd.

Ils sont tous mis dans le registre IANA (cf. section 9 du RFC).

Il y a aussi le suffixe +xml (section 4.2), utilisant la notion de suffixe du RFC 6839. Il a vocation à être utilisé pour tous les formats XML. Si les concepteurs de ce format ne veulent pas d'un traitement générique XML (un cas probablement rare), ils doivent choisir un type MIME sans ce suffixe.

À noter que, si on envoie du XML en HTTP, le système de négociation de contenu de HTTP ne prévoit pas de mécanisme pour dire « j'accepte le XML, quel que soit le format ». Pas question de dire Accept: text/*+xml, donc.

La section 5 décrit ensuite le cas des identificateurs de fragment (le texte après le # dans un URI, pour désigner une partie d'un document). Ils sont décrits dans la section 3.5 du RFC 3986. Pour le cas particulier de XML, on se sert de la syntaxe XPointer pour écrire ces identificateurs (pas exemple, http://www.example.org/data.html#xpointer(/foo/bar)).

Le document XML envoyé peut utiliser l'attribut xml:base (section 6) pour spécifier un URI de référence, utilisé pour construire des URI absolus à partir des relatifs qu'on peut trouver dans le document XML (par exemple, lors de l'inclusion d'un autre document XML).

Et les versions de XML (il existe actuellement deux versions normalisées, 1.0 et 1.1) ? Voyez la section 7, qui précise que les types MIME sont exactement les mêmes pour toutes les versions : un analyseur XML doit utiliser les techniques XML (le champ version dans la déclaration) pour identifier les versions, pas les types MIME.

Enfin, si vous vous intéressez à la sécurité, voyez la section 10 qui résume rapidement les grandes questions de sécurité de XML. D'abord, les documents XML étant souvent modulaires (un document déclenche le chargement de paramètres ou d'entités XML externes, ou encore de feuilles de style), la sécurité doit prendre en compte tous les documents extérieurs et leur technique de chargement. Si un document XML est chargé en HTTPS mais qu'il contient une référence HTTP à une feuille de style CSS, la sécurité de HTTPS ne protégera pas cette dernière, alors qu'elle pourrait, par exemple, faire disparaître certains des éléments XML (display: none;...) Ainsi, beaucoup de documents XML se réfèrent à des entités XML qui sont sur les serveurs du W3C, sans se préoccuper d'analyser la sécurité desdits serveurs. Si la définition de l'entité mdash est remplacée par le texte de Winnie l'ourson, de drôles de résultats peuvent survenir.

Il y a aussi des attaques par déni de service : un document XML qui contient une référence à une entité qui contient à son tour de nombreuses autres références, qui contiennent chacune de nombreuses autres références, et ainsi de suite, jusqu'au dépassement de pile. (La forme la plus triviale de l'attaque, où l'entité se référence elle-même, est normalement empêchée par la prohibition de ces auto-références.)

Également d'un grand intérêt pratique, l'annexe C, sur les questions opérationnelles. La situation actuelle, notamment pour trouver l'encodage des caractères d'un document, n'est pas idéale. La nouvelle règle sur les BOM (priorité sur le paramètre charset) casse, en théorie, la compatibilité mais, en pratique, n'aggrave pas la situation et devrait l'améliorer à terme. Si on veut se simplifier la vie lors de l'envoi de XML, on le met en UTF-8 : c'est l'encodage recommandé par défaut, et il se passe de BOM. Si on n'utilise pas UTF-8, alors, il faut mettre un BOM.

Et le consommateur de XML ? Il lui suffit de regarder le BOM sinon le charset sinon la déclaration XML. En suivant ces règles simples, tout le monde devrait être heureux.

Depuis le RFC 3023, la précédente norme, que s'est-il passé ? L'annexe D résume les nombreux et sérieux changements. Les sous-types de text comme text/xml ont vu leur définition alignée avec celle du sous-type d'application. text/xml est donc désormais un simple synonyme de application/xml, ce qui reflète la réalité des mises en œuvre logicielles de XML. Le BOM est désormais prioritaire sur le charset. D'autre part, XPointer est désormais intégré. Et UTF-32 est maintenant officiellement déconseillé, au nom de l'interopérabilité.


Téléchargez le RFC 7303


L'article seul

RFC 7301: Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : S. Friedl (Cisco Systems), A. Popov (Microsoft), A. Langley (Google), E. Stephan (Orange)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 24 juillet 2014


On le sait, désormais, tout l'Internet tourne sur le port 443 (et aussi sur 80 mais de moins en moins, en raison des révélations de Snowden). C'est en effet l'un des rares ports dont on peut être sûr qu'il est à peu près tout le temps ouvert, même sur les réseaux les plus affreux genre hôtel ou aéroport. En prime, les communications sur ce port sont chiffrées avec TLS (RFC 5246). Si seul HTTP se servait de ce port, cela marcherait mais de plus en plus de protocoles applicatifs se bousculent pour l'utiliser. Comment leur permettre de partager le port 443 sans émeutes ? En ajoutant une extension à TLS qui permet d'indiquer le protocole applicatif qui va utiliser ce port, une fois la session TLS démarrée.

Cette extension avait surtout été conçue pour les besoins de HTTP/2 (autrefois nommée SPDY), version qui est loin d'être terminée. ALPN (Application-Layer Protocol Negotiation), objet de notre RFC, sert à indiquer la version de HTTP, et aussi désigner les services qui vont tourner au dessus de HTTP, comme WebRTC (RFC 8833). Mais elle pourra servir à d'autres protocoles. Comme, par exemple, faire coexister IMAP et HTTP sur le même port. Vous allez peut-être me dire « mais pourquoi ne pas faire cela dans une couche entre TLS et l'application, de manière à éviter de complexifier TLS ? » et le RFC vous répond que le but est de performance (éviter les allers-retours entre client et serveur) et de souplesse (choisir un certificat différent selon le protocole d'application).

À noter qu'il s'agit d'une extension TLS : si on veut faire coexister sur un même port des applications TLS comme HTTP et non-TLS comme SSH, il faut une autre solution (par exemple sslh).

Comment fonctionne ALPN (section 3 de notre RFC) ? Le client envoie la liste des applications qu'il gère dans son message TLS ClientHello (section 7.4.1.2 du RFC 5246), le serveur en choisit une et la renvoie dans son ServerHello. Tout se fait donc dans la poignée de mains de TLS, sans imposer d'allers-retours supplémentaires. Si le client ne veut qu'une seule application, il envoie un message avec une liste ne comportant que cette application.

L'extension se nomme application_layer_protocol_negotiation et a le numéro 16 (désormais dans le registre IANA). Elle a un contenu (de type ProtocolNameList) qui contient la liste des protocoles applicatifs, en ordre de préférence décroissante. En termes TLS, cela s'écrit :


enum {
       application_layer_protocol_negotiation(16), (65535)
   } ExtensionType;

opaque ProtocolName<1..2^8-1>;

struct {
       ProtocolName protocol_name_list<2..2^16-1>
   } ProtocolNameList;

Les valeurs possibles pour les protocoles applicatifs sont dans un registre IANA. Des nouveaux protocoles pourront être ajoutés après un examen par un expert (RFC 5226, section 4.1). Pour l'instant, on y trouve le HTTP actuel, 1.1 (RFC 7230) et les variantes de SPDY. HTTP/2 sera placé dans ce registre après sa normalisation.

Cette extension sert aussi bien au client (liste des applications que le client veut utiliser) qu'au serveur (application - au singulier - choisie, après avoir ignoré celles que le serveur ne connait pas). Si le serveur ne met pas cette extension dans sa réponse, c'est ce qu'est un vieux serveur, qui ne la connait pas. S'il répond avec une alerte no_application_protocol, c'est que l'intersection de la liste du client avec celle configurée dans le serveur est hélas vide.

Si vous utilisez une application qui peut attirer l'attention de la NSA, attention : la négociation ALPN est en clair, avant que le chiffrement ne démarre (sections 4 et 5). C'était un des points les plus controversés lors des discussions à l'IETF mais cela a été décidé pour être cohérent avec le modèle d'extension de TLS (un concurrent d'ALPN, NPN, n'avait pas ce défaut). Si vous tenez à cacher le protocole applicatif utilisé, vous devez faire une renégociation une fois le chiffrement commencé.

Des mises en œuvre de cette extension ? C'est apparemment fait pour NSS (voir #996250 et #959664). Et Wireshark va pouvoir le décoder. Pour les autres, voir le tableau synthétique.


Téléchargez le RFC 7301


L'article seul

RFC 7300: Reservation of Last Autonomous System (AS) Numbers

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : J. Haas (Juniper Networks), J. Mitchell (Microsoft Corporation)
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 11 juillet 2014


Ce très court RFC réserve formellement deux numéros d'AS, 65535 et 4294967295, qui ne doivent donc pas être alloués à un opérateur réseau.

Ces deux AS étaient déjà réservés en pratique mais cela n'avait pas été documenté (au sens du RFC 6996). Ils sont les derniers de leur plage (65535 est le dernier des AS traditionnels sur 16 bits et 4294967295 le dernier des AS sur 32 bits du RFC 6793), d'où le titre de ce RFC.

Pourquoi les réserver ? Pour 65535, c'est parce qu'il est déjà utilisé dans des communautés BGP bien connues (RFC 1997 et registre IANA, c'est le cas, par exemple, de NO_EXPORT, alias 65535:65281). Par contre, 4294967295 n'a pas de telles communautés mais il est réservé au cas où on ait besoin d'un AS qui ne soit jamais annoncé en BGP.

Donc, ces deux AS ne doivent pas être utilisés sur l'Internet et ne seront donc jamais (si tout le monde respecte les règles) dans un attribut BGP comme AS_PATH. Mais ils peuvent servir à des usages pas encore définis et les programmes qui mettent en œuvre BGP ne doivent donc pas interdire leur usage. Ils sont désormais dans le registre IANA des AS et dans celui des AS spéciaux.


Téléchargez le RFC 7300


L'article seul

RFC 7291: DHCP Options for the Port Control Protocol (PCP)

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : M. Boucadair (France Telecom), R. Penno, D. Wing (Cisco)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pcp
Première rédaction de cet article le 15 juillet 2014


Le protocole PCP, normalisé dans le RFC 6887 permet à la machine de M. Michu de configurer un routeur/traducteur, par exemple pour lui demander de laisser passer le trafic entrant vers un port donné. La norme PCP ne précisait pas tellement comment le client était censé trouver le serveur PCP. Dans certains cas, c'est trivial, c'est le routeur par défaut. Dans d'autres, il faut d'autres mécanismes et c'est là que notre RFC 7291 est utile : il normalise un moyen de découvrir le serveur PCP grâce à une nouvelle option DHCP.

Le mécanisme est le même pour DHCP IPv6 (RFC 8415) ou DHCP IPv4 (RFC 2131). Pour DHCP IPv6, l'option est décrite en section 3. Elle est nommée OPTION_V6_PCP_SERVER et a le code 86 (mis dans le registre IANA). Suit une liste d'adresses IPv6, qui sont celles d'un serveur PCP. S'il y a plusieurs serveurs PCP, on met plusieurs occurrences de l'option OPTION_V6_PCP_SERVER.

On note que c'est une adresse IP et pas un nom de domaine qui est utilisée pour identifier le ou les serveur(s) PCP. Un nom de domaine aurait permis un niveau d'indirection supplémentaire. Le sujet a donc fait l'objet d'une certaine controverse au sein du groupe de travail PCP à l'IETF avant que le consensus se fasse sur l'adresse IP.

Pour obtenir cette liste d'adresses, le client DHCP doit mettre l'option OPTION_V6_PCP_SERVER dans sa requête et, si le serveur DHCP connait des serveurs PCP, il mettra leur(s) adresse(s) dans sa réponse.

Le mécanisme est quasiment le même en IPv4 (section 4), avec l'option OPTION_V4_PCP_SERVER de code 158 (registre IANA). La principale différence est le mécanisme utilisé pour mettre plusieurs serveurs PCP (pas juste plusieurs adresses IP pour un serveur, mais plusieurs serveurs) : en IPv6, on répétait l'option. En IPv4, on envoie plusieurs listes dans la même réponse.

Donc, attention, aussi bien côté client que côté serveur, ce RFC permet d'avoir plusieurs serveurs PCP, ayant chacun plusieurs adresses IP. Par exemple, côté serveur, le mécanisme de configuration du serveur (mettons son fichier de configuration) doit permettre de distinguer les deux cas, afin de choisir le bon encodage. Si le fichier de configuration permet de mettre un nom de domaine pour le serveur PCP, et que le serveur DHCP, en résolvant ce nom, trouve plusieurs adresses IP, il doit bien les mettre dans une seule option (en IPv6) ou une seule liste (IPv4).

Notez une différence entre IPv6 et IPv4 : un serveur DHCP IPv6 peut retourner des adresses IPv4 (encodées selon la section 2.5.5.2 du RFC 4291) dans sa réponse (cas d'un réseau purement IPv6 mais qui reçoit une connectivité IPv4 via un mécanisme spécifique), l'inverse n'étant pas vrai.

À noter que, dans le cas de multi-homing, on peut recevoir plusieurs serveurs PCP via des réponses DHCP différentes, sur des liens réseau différents (par exemple un lien WiFi et un 3G). Dans ce cas, la machine doit bien faire attention à associer chaque serveur PCP à son réseau, pour ne configurer que le bon serveur PCP correspondant à l'adresse qu'on veut utiliser.

Les praticiens noteront avec plaisir qu'il existe au moins une mise en œuvre documentée (sur Fedora).


Téléchargez le RFC 7291


L'article seul

RFC 7290: Test Plan and Results for Advancing RFC 2680 on the Standards Track

Date de publication du RFC : Juillet 2014
Auteur(s) du RFC : L. Ciavattone (AT&T Labs), R. Geib (Deutsche Telekom), A. Morton (AT&T Labs), M. Wieser (Technical University Darmstadt)
Pour information
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 23 juillet 2014


Le RFC 2680 normalisait une métrique utile à l'analyse des performances des réseaux informatiques, le taux de perte de paquets (mesuré sur un aller simple). Pour faire avancer ce RFC sur le chemin des normes, pour qu'il accède au statut de « norme tout court », il faut une évaluation : la description du RFC est-elle claire et complète ? Les mises en œuvre logicielles sont-elles équivalentes ? C'est ce travail d'évaluation que ce nouveau RFC documente, et qui a mené au RFC 7680.

Évaluer la norme d'une métrique est un peu plus compliqué qu'évaluer un protocole. La méthode traditionnelle à l'IETF pour évaluer un protocole est de regarder si deux mises en œuvre différentes peuvent interopérer. Pour une métrique, ce n'est pas possible et on utilise donc une autre méthode, regarder si deux mises en œuvre différentes d'une métrique, confrontées au même trafic, produisent des résultats compatibles (pas forcément identiques : les mesures ne sont jamais parfaitement précises).

Le groupe de travail IPPM de l'IETF travaille depuis longtemps sur ce problème d'avancement des métriques sur le chemin des normes. Les principes de l'évaluation d'une métrique ont été décrits dans le RFC 6576 et ont déjà été mis en pratique dans le RFC 6808, pour la métrique « délai d'acheminement d'un paquet (en aller simple) ». L'idée de base est que, si deux mesures, par des mises en œuvre différentes, donnent des résultats suffisamment proches, c'est que la métrique était correctement définie, claire et sans ambiguité. Cette évaluation permet aussi de voir quelles options de la métrique n'ont jamais été implémentées, et sont donc candidates à être supprimées dans une future révision de la norme.

En suivant le même plan que le RFC 6808, voici donc l'évaluation du RFC 2680 en pratique. La configuration de test est décrite en section 3 : les deux mises en œuvre testées étaient un NetProbe (ce qu'utilise WIPM), utilisant des paquets UDP avec une distribution périodique (RFC 3432) ou de Poisson (RFC 2330), et un Perfas+ (description en allemand), également avec UDP. Dans les deux cas, on passait par un tunnel L2TP (RFC 3931), pour dissimuler aux équipements intermédiaires les adresses IP et ports des équipements de tests (autrement, le trafic risquerait de passer par des chemins différents pour les deux tests). À l'extrémité du tunnel, le trafic est renvoyé donc cela permet d'avoir l'émetteur et le récepteur au même endroit, tout en faisant une mesure unidirectionnelle sur une longue distance. Pour introduire des phénomènes rigolos comme des pertes de paquet, un émulateur Netem est installé sur une machine Fedora, qui assure la communication entre le tunnel et un VLAN où se trouve l'équipement de test, via un lien FastEthernet. Les équipements testés ont envoyé des flots à 1 et 10 p/s, avec des centaines de paquets, de tailles variables (de 64 à 500 octets). Le type-P (cf. RFC 2680, section 2.8.1) des paquets était « UDP avec DSCP best effort » (de toute façon, l'encapsulation dans le tunnel L2TP fait que ces bits DSCP ont probablement été ignorés).

La section 4 de notre RFC décrit l'étalonnage (vérifier les horloges, par exemple).

On l'a dit, c'est bien joli de comparer deux programmes mais que doit être le résultat de la comparaison ? Une égalité rigoureuse ? Ce n'est pas possible. La section 5 indique les critères de comparaison : on fait de l'ADK avec un facteur de confiance à 0,95 (et de l'adéquation à la loi de distribution).

Enfin, après toutes ces précautions méthodologiques, la section 6 contient les résultats. Par exemple, en périodique, les deux systèmes mesurés donnent des résultats largement compatibles mais, en distribution de Poisson, les résultats sont tout juste acceptables. Les mesures ont bien résisté à des tests comme celui du délai maximal d'attente (avant de déclarer un paquet perdu) ou comme celui du désordonnement des paquets (lorsqu'un paquet est tellement en retard qu'il arrive après un paquet parti après).

Conclusions (section 7) : les deux mises en œuvre sont compatibles, ce qui indique que le RFC 2680 est suffisamment clair et précis. Le processus de test a toutefois noté quelques points où le RFC 2680 pouvait être rendu plus clair (sans compter les erreurs connues du RFC). Cela a été fait dans le RFC 7680.

Pour les fanas, la section 10 rassemble toutes les commandes de configuration des équipements qui ont été utilisées. Par exemple, Netem a été configuré avec tc (ici, pour ajouter un retard variable et en prime 10 % de perte de paquets) :

tc qdisc change dev eth1 root netem delay 2000ms 1000ms loss 10%

Téléchargez le RFC 7290


L'article seul

RFC 7288: Reflections On Host Firewalls

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : D. Thaler (Microsoft)
Pour information
Première rédaction de cet article le 2 juillet 2014


Aujourd'hui, on met des pare-feux partout et leur présence est en général considérée, sans aucune réflexion supplémentaire, comme indispensable. Il existe des pare-feux qui se branchent sur le réseau et protègent ainsi toutes les machines du réseau (network firewall). Et il existe des pare-feux sur les machines terminales, des host firewalls, qui font l'objet de ce RFC. En présence d'un tel pare-feu, on peut avoir une application qui tourne, et donc consomme des ressources, mais ne peut pas communiquer avec l'extérieur puisqu'elle est bloquée par le pare-feu. Le même résultat de sécurité pourrait être atteint en ne faisant pas tourner l'application, ou en la configurant pour limiter ses possibilités. Cette approche ne serait-elle pas meilleure ?

Le RFC 2979 discutait des pare-feux sur l'Internet et des propriétés qu'on attendait d'eux (et les RFC 4949 et RFC 4948 discutaient de la terminologie). Le RFC 2979 pointait notamment le risque de « faux positif », lorsqu'un pare-feu bloque accidentellement une communication légitime. Les vendeurs de pare-feux oublient toujours de mentionner ce risque. Pourtant, nombreux sont les pare-feux qui bloquent stupidement des connexions parfaitement légitimes, par exemple parce que les paquets IP contiennent des options, ou des en-têtes IPv6 (cf. RFC 7045). Le RFC 4924 revient sur cette question des pare-feux en notant qu'ils sont largement responsables de l'ossification de l'Internet, et que de plus en plus d'applications consacrent beaucoup d'effort à contourner ces obstacles. En outre, les pare-feux contribuent souvent à un faux sentiment de sécurité, qui peut mener à baisser sa garde sur les machines supposées « protégées par le pare-feu » (section 6 de notre RFC). Enfin, la section 1.1 du RFC rappelle que le NAT n'est pas un vrai pare-feu.

Le problème des pare-feux est d'autant plus aigu que la réponse classique à la question de l'utilité d'un pare-feu est « bloquer le trafic non souhaité », mais que cette réponse ne dit pas « non souhaité par qui ». Par l'utilisateur final ? Par son employeur ? Par l'administrateur réseau ? Par le développeur ? Leurs intérêts sont souvent en conflit et on ne peut pas espérer un consensus simple entre tous ces acteurs (le RFC reprend l'excellent terme de « tussle »). Pas étonnant qu'on voit souvent des « courses aux armements » entre ceux qui bloquent et ceux qui contournent le blocage.

Le pare-feu typique est souvent configuré par des règles allow/deny où on indique que tel type de trafic est autorisé ou interdit (section 2 du RFC). Voici par exemple des règles Shorewall où tout est interdit par défaut mais où on accepte quelques services :

# SMTP 
ACCEPT               net       fw       tcp      25
ACCEPT               net       fw       tcp      587
# IMAP, IMAPS et POPS
ACCEPT               net        fw      tcp      143
ACCEPT               net        fw      tcp      993
ACCEPT               net        fw      tcp      995
# Nagios Remote Execution (NRPE)
ACCEPT               net:192.0.2.187  fw  TCP     5767
# SNMP
ACCEPT               net:192.0.2.187,203.0.113.170   fw  udp   161

Pour un pare-feu sur une machine terminale, l'utilisateur n'a pas le droit de modifier ces règles sauf dans le cas (fréquent avec les machines personnelles) où l'utilisateur est en même temps administrateur système. Par contre, des applications peuvent configurer le pare-feu, pour les systèmes où celui-ci fournit une API aux applications, ou bien s'il existe un protocole standard de changement de la configuration du pare-feu comme UPnP ou son successeur potentiel PCP (RFC 6887). Ces règles sont classées par notre RFC en deux catégories : réduction de la surface d'attaque (empêcher l'application de faire des choses que le développeur ne voulait pas qu'elle fasse) et politique de sécurité (empêcher l'application de faire des choses que l'administrateur système ne voulait pas qu'elle fasse).

La section 3 décrit la première catégorie, la réduction de la surface d'attaque. On peut se demander si cette catégorie est utile : après tout, si on ne veut pas qu'une application, par exemple, détruise des fichiers en réponse à une requête venue par le réseau, le mieux est de ne pas mettre en œuvre cette fonction. On sera alors bien plus en sécurité. Sauf qu'on n'a pas toujours le luxe d'avoir uniquement des applications bien conçues et bien écrites. Souvent, le développeur a fait des impasses (ou, en termes plus savants, a pris de la dette technique) et réécrire l'application serait trop coûteux. C'est par exemple le cas de beaucoup d'applications Web programmées à la va-vite sans souci de sécurité, en PHP ou VB.NET. Coller un pare-feu devant l'application est en général moins coûteux et plus efficace que de se plonger dans le plat de spaghettis.

Il y a aussi des cas où la dette prise par le développeur (reporter le problème à plus tard...) était justifiée par un manque de support de la part du système. Par exemple, une règle aussi simple et courante que « communication uniquement avec le lien local » est difficile à mettre en œuvre de façon portable, sur Unix, dans tous les langages de programmation. (Notez au passage que n'autoriser que les adresses IP source du même réseau que celui du serveur n'est pas suffisant, en raison de la possibilité d'usurpation d'adresse. Pour UDP, il faudrait aussi tester le TTL, cf. RFC 5082.) Il y a aussi le cas où la machine se déplace d'un réseau sûr à un réseau non-sûr. Le développeur est donc tenté de déléguer la mise en œuvre de cette politique à un pare-feu.

Même chose avec des politiques complexes, comme de ne communiquer que sur les liens les moins coûteux, sachant que l'application n'a pas forcément connaissance des coûts (sur Android, cette politique est en général purement binaire : on considère que la 3G est coûteuse et le Wifi gratuit, ce qui n'est pas toujours vrai.) Avoir une API permettant à l'application d'exprimer ses souhaits, que le système d'exploitation traduirait en règles de pare-feu concrètes, simplifierait beaucoup les choses.

Quelles sont donc les solutions pour l'utilisateur, qui se retrouve avec une application « imparfaite », pleine de failles de sécurité ? D'abord, réparer le logiciel en corrigeant ces failles. Les partisans des pare-feux feront évidemment remarquer qu'il est plus rapide et plus efficace d'utiliser un pare-feu : déboguer un logiciel mal écrit est long et coûteux et on n'est jamais sûr d'avoir bouché tous les trous de sécurité. Il y a d'ailleurs des cas où réparer le logiciel est quasi-impossible : pas les sources pour le faire ou bien pas de mécanisme de mise à jour pour les engins qui font tourner ce logiciel. En général, un changement des règles du pare-feu peut être déployé plus facilement qu'un patch.

Autre idée, ne pas utiliser le logiciel. Solution brutale mais qui résout tout. Notez que l'idée n'est pas si violente qu'elle en a l'air : certains systèmes font tourner par défaut des logiciels qui ne devraient pas tourner. Arrêter ce logiciel inutile est une solution réaliste.

Enfin, il y a le pare-feu, qui va protéger contre le logiciel mal fait. Le logiciel tournera toujours, consommant des ressources (personnellement, je ne trouve pas l'argument très convaincant : si le logiciel est juste en attente d'événements, il ne consomme pas grand'chose). Et, surtout, si un utilisateur tente de se servir du logiciel, il aura des surprises, car beaucoup de programmes ne sont pas conçus de manière robuste : ils réagissent mal quand, par exemple, certains services réseau ne leur sont pas accessibles. Parfois, cela aggrave la consommation de ressources (par exemple, le logiciel, n'ayant pas compris qu'il était bloqué par le pare-feu, réessaie en boucle). Autre problème avec les pare-feux : ils sont souvent surbloquants. Par exemple, ils bloquent tout ce qu'il ne connaissent pas et gênent donc considérablement l'innovation. Certains analysent les paquets de manière très sommaire (oubliant par exemple certaines fonctions avancées du protocole) et prennent donc de mauvaises décisions. C'est ainsi qu'ICMP est souvent bloqué, menant à des problèmes de découverte de la MTU du chemin (RFC 4890 et RFC 2979).

Deuxième catégorie de règles dans un pare-feu, celles qui visent à faire respecter une politique de sécurité. L'administrateur a décidé qu'on ne regarderait pas YouTube, les règles bloquent YouTube. Cette catégorie peut en théorie être mise en œuvre à trois endroits. D'abord, dans les applications elles-mêmes. Ça ne passe évidemment pas à l'échelle : il faudrait ajouter du code à toutes les applications (faites un peu une liste du nombre de clients HTTP sur votre machine, par exemple ; rappelez vous qu'il n'y a pas que les navigateurs Web) et les configurer. En pratique, il y aura toujours une application oubliée. Cette solution n'est donc pas réaliste.

Deuxième endroit possible, le pare-feu. Outre les problèmes discutés plus haut (application qui réagit mal au blocage de certains services), cela mène facilement à une course aux armements : comme les désirs de l'utilisateur final et de l'administrateur du pare-feu ne coïncident pas forcément, les applications, à la demande des utilisateurs, vont évoluer pour contourner le filtrage, qui va devenir de plus en plus intrusif et ainsi de suite jusqu'à ce que tout le monde, pris dans cette course, oublie le but originel de la politique de sécurité. Comme le disait la section 2.1 du RFC 4924, le filtrage sans le consentement (au moins passif) de l'utilisateur est difficile, et va mener à des solutions compliquées, coûteuses et fragiles, violant largement les bons principes d'architecture réseau (par exemple en faisant tout passer au-dessus de HTTP, seul protocole autorisé).

Reste le troisième endroit, qui a plutôt les faveurs du RFC : faire des politiques de sécurité un service auquel s'inscrivent les applications. L'application utilise une bibliothèque (comme les TCP wrappers) ou bien parle un protocole réseau (comme PCP, RFC 6887), décrit ce qu'elle veut, et apprend si c'est autorisé ou pas, de manière propre. Cela nécessite évidemment des standards (comme PCP, qui est pour l'instant très peu déployé, et qui est de toute façon sans doute insuffisant pour gérer toutes les politiques possibles) car on n'imagine pas chaque application ajouter du code pour l'API de chaque marque de pare-feu.

Cette technique est très originale par rapport à l'approche habituelle sur les pare-feux mais c'est celle recommandée par notre RFC. Pour le résumer en une phrase, on fait trop travailler les pare-feux et pas assez les applications.


Téléchargez le RFC 7288


L'article seul

RFC 7286: ALTO Server Discovery

Date de publication du RFC : Novembre 2014
Auteur(s) du RFC : S. Kiesel (University of Stuttgart), M. Stiemerling (NEC Europe), N. Schwan (Stuttgart, Germany), M. Scharf (Alcatel-Lucent Bell Labs), H. Song (Huawei)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF alto
Première rédaction de cet article le 14 novembre 2014


Le protocole ALTO (Application-Layer Traffic Optimization), normalisé dans le RFC 7285, permet à une machine qui communique avec des pairs, de déterminer quel pair utiliser lorsqu'ils fournissent le même service (par exemple, dans un système de partage de fichiers pair-à-pair, lorsque les membres d'un même essaim ont le fichier convoité). La machine, un client ALTO, demande à un serveur ALTO quel est le « meilleur » pair, optimisant ainsi son utilisation du réseau. Oui, mais comment est-ce que le client trouve le serveur à utiliser ?

Le RFC 6708, le cahier des charges d'ALTO, disait dans son exigence AR-32 qu'il fallait un mécanisme pour trouver le serveur. ALTO reposant sur HTTP, trouver un serveur, c'est trouver l'URI qui le désigne. Le protocole de découverte va partir d'un nom de domaine (obtenu, par exemple, via DHCP, ou bien via une configuration manuelle), faire une requête DNS sur ce nom, en demandant le type U-NAPTR (RFC 4848, mais ne paniquez pas, j'explique le U-NAPTR plus loin). La réponse sera l'URI désiré.

Donc, première étape (section 3.1), récupérer le nom de domaine. Pour la machine typique de M. Michu, cela se fait en DHCP, le serveur DHCP donnant, parmi d'autres informations, le nom de domaine de référence du réseau local (options DHCP 213 - OPTION_V4_ACCESS_DOMAIN - et 57 -  OPTION_V6_ACCESS_DOMAIN - de la section 3 du RFC 5986, ou bien, si elle n'est pas présente, et en IPv4 seulement, l'option 15 de la section 3.17 du RFC 2132). Le nom sera alors celui du FAI ou celui de l'organisation où M. Michu se connecte. Mais le RFC demande aussi que les mises en œuvre de la découverte de serveurs ALTO puisse aussi se faire à partir d'un nom de domaine rentré manuellement par l'utilisateur. Cela permet, par exemple, de traiter le cas où un utilisateur n'a pas confiance dans le serveur ALTO de son FAI et souhaite utiliser le serveur ALTO d'une organisation tierce. (Tiens, peut-être verrons-nous apparaître un Google Alto ?)

Une fois qu'on a le nom de domaine, on passe à la deuxième étape de la procédure de découverte du serveur (section 3.2). Pour cela, on va demander un enregistrement de type U-NAPTR. Ce type de données, normalisé dans le RFC 4848, est très complexe. Disons simplement qu'il permet de découvrir des services en utilisant un enregistrement DNS qui comprend une étiquette de service, et une expression rationnelle de remplacement dont le résultat sera l'URI recherché (la procédure de découverte de serveur d'ALTO simplifie les choses en n'utilisant pas la partie gauche de l'expression, seulement le résultat). Les U-NAPTR sont plus riches que les S-NAPTR du RFC 3958 mais moins que les NAPTR originels (RFC 3403). À noter que la différence entre NAPTR, S-NAPTR et U-NAPTR ne se voit pas dans le DNS : tous utilisent le même type, NAPTR. Voici un exemple d'un enregistrement DNS pour la découverte du serveur ALTO de example.net :

example.net. IN NAPTR 100 10 "u" "ALTO:https" "!.*!https://alto1.example.net/ird!"  ""

L'étiquette de service est ALTO:https (désormais enregistrée à l'IANA). En filtrant sur cette étiquette, on pourra récupérer uniquement les enregistrements ALTO. Ici, l'URI de résultat sera https://alto1.example.net/ird.

Il peut y avoir plusieurs NAPTR, pour fournir des serveurs alternatifs, et on pourrait donc avoir :

example.net. IN NAPTR 100 10 "u" "ALTO:https" "!.*!https://alto1.example.net/ird!"  ""
             IN NAPTR 100 20 "u" "ALTO:https" "!.*!https://alto2.example.net/ird!"  ""

Dans ce cas, le champ « Préférence » du second serveur (le second URI, plutôt) étant plus élevé, il ne sera choisi que si le premier ne répond pas (oui, une préférence plus élevée veut dire qu'on sera moins considéré, comme pour les enregistrements MX).

Au fait, pourquoi un U-NAPTR et pas un simple S-NAPTR (puisqu'on ne se sert pas de la partie gauche de l'expression rationnelle) ? Parce que les S-NAPTR ne fournissent comme résultat qu'un couple {serveur, port}, pas un URI comme le protocole ALTO en a besoin.

En pratique, quelles questions posera le déploiement de cette procédure (section 4) ? Elle dépend d'une bonne réception du nom de domaine. Les options du RFC 5986 ne sont pas forcément gérées par tous les serveurs DHCP. Ensuite, dans le cas d'une connexion typique à la maison via un petit routeur CPE, il faudra que le routeur passe fidèlement en DHCP les noms de domaine qu'il a lui-même obtenu. Si, à la place du example.net, il transmet aux clients un nom comme, mettons, .local, la recherche de serveur ALTO échouera.

Cette procédure de découverte du serveur, comme le note la section 6 de notre RFC, n'est pas très sécurisée. Si un méchant arrive à diriger les clients vers un mauvais serveur ALTO, celui-ci pourra donner de l'information fausse, menant les clients à choisir un pair particulièrement lent. Pour cela, le méchant peut s'attaquer à l'échange DHCP. DHCP n'est pas sécurisé du tout mais, bon, si le méchant peut envoyer des fausses réponses DHCP, il pourra faire des choses bien pires que de donner un mauvais serveur ALTO. Donc, cette méthode d'attaque n'est pas très inquiétante. Une autre méthode pour l'attaquant serait de convaincre l'utilisateur de rentrer manuellement un nom de domaine menant au serveur ALTO malveillant, un problème qui ressemble à celui du hameçonnage (et qui, comme lui, n'a pas de solution technique).

Une dernière attaque possible serait de compromettre la résolution DNS. La procédure de découverte du serveur ALTO n'impose pas l'usage de DNSSEC et, sans lui, le DNS n'est pas vraiment sûr. Enfin, l'attaque pourrait porter, après la découverte du serveur correct, sur la communication HTTP avec le serveur (surtout si on n'utilise pas HTTPS). Personnellement, je ne suis pas trop inquiet : on a des problèmes de sécurité bien plus sérieux sur l'Internet.

À noter que d'autres mécanismes de découverte du serveur ALTO ont été proposés à l'IETF et qu'ils feront peut-être l'objet d'une spécification officielle plus tard.


Téléchargez le RFC 7286


L'article seul

RFC 7285: ALTO Protocol

Date de publication du RFC : Septembre 2014
Auteur(s) du RFC : R. Alimi (Google), R. Penno (Cisco Systems), Y. Yang (Yale University)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF alto
Première rédaction de cet article le 5 septembre 2014


Couronnant un travail commencé six ans auparavant, avec un net ralentissement de l'enthousiasme vers la fin, ce nouvel RFC normalise enfin le protocole ALTO (Application-Layer Traffic Optimization). Ce protocole sert notamment dans le cas de transferts de fichiers en pair à pair. Lorsqu'une machine qui veut récupérer un fichier (disons, au hasard, un épisode de Game of Thrones) a le choix entre plusieurs pairs possibles, qui ont chacun les données convoitées, lequel choisir ? ALTO permet d'interroger un oracle, le serveur ALTO, qui va nous donner des informations guidant le choix.

Il existe déjà des tas de façons, pour une application, de mesurer ou de calculer le « meilleur » pair. Par exemple, l'information de routage (annonces BGP, notamment) est publique et une application peut y accéder, par exemple via un looking glass. Mais cela ne donne pas une vue complète et, surtout, cela ne donne pas la vision de l'opérateur réseau, qui pourrait souhaiter, par exemple, qu'on utilise plutôt un pair qui fasse passer par un lien de peering (gratuit), plutôt que par un lien de transit (payant). ALTO est donc avant tout un moyen de faire connaître les préférences du FAI, de manière à ce que l'application puisse faire un choix plus informé. Par exemple, ALTO permet de distribuer des cartes simplifiées du réseau, suffisantes pour que l'application repère les liens intéressants.

Le but est donc bien que les applications changent leur comportement, en utilisant l'information ALTO, afin de mieux utiliser les ressources du réseau (le transfert en pair à pair peut représenter une bonne part du trafic et il est dans l'intérêt de tous de l'optimiser). La même méthode et le même protocole ALTO peut aussi être utilisé pour optimiser l'accès à un CDN et le serveur ALTO peut donc être fourni par d'autres acteurs que le FAI (le protocole lui-même est neutre, au sens où il n'impose pas de critères de choix ; le coût financier, utilisé dans l'exemple précédent peering/transit, n'est qu'une possibilité parmi d'autres).

Le problème que résout ALTO est formellement décrit dans le RFC 5693. Pour le résumer : en raison du modèle en couches, les applications n'ont pas assez d'information sur le réseau sous-jacent et ne peuvent donc pas prendre de décisions « intelligentes ». Il s'agit donc de leur donner cette information. Ainsi, le réseau sera mieux utilisé, on aura moins de gaspillage (avantage collectif) et les applications auront de meilleures performances (temps de téléchargement plus courts, par exemple, un avantage individuel, cette fois).

Techniquement, ALTO est un protocole HTTP/REST, où requêtes et réponses sont en JSON (RFC 8259). Que du classique, donc, et qui utilisera l'infrastructure HTTP existante.

Un petit rappel de terminologie (s'appuyant sur le RFC 5693) est fait en section 2. On y trouve les termes d'extrémités (endpoint), ALTO information base (l'ensemble des informations connues d'un serveur ALTO), etc.

Place maintenant à l'architecture d'ALTO, en section 3. Le cas typique est celui d'un opérateur, ayant un AS et un serveur ALTO pour distribuer l'information sur cet AS (bien sûr, des tas d'autres cas sont possibles). L'ALTO information base de cet AS est composée d'une série de coûts entre extrémités du réseau. Une extrémité est exprimée sous forme d'un préfixe IP (ce n'est donc pas forcément une seule adresse IP). Dans le cas le plus simple, la base peut tout simplement contenir quelque chose du genre « nos préfixes ont un coût fixe et faible, le reste de l'Internet un coût fixe et deux fois plus élevé » ou bien des informations bien plus complexes. La base contient donc les coûts, vus de cet opérateur. Elle va être distribuée par un serveur ALTO, interrogé par des clients ALTO. Plus tard, d'autres moyens de désigner une extrémité existeront, un registre IANA a été créé pour stocker les types d'adresses (section 14.4 de notre RFC).

Et d'où la base vient-elle ? Le protocole ALTO ne spécifie pas de méthode particulière. La base a pu être remplie à la main par les employés de l'opérateur réseau, en fonction de leur politique. Ou générée automatiquement à partir des données de l'opérateur sur la topologie du réseau. Ou elle a pu être assemblée dynamiquement par le biais d'un système de mesure, ou à partir des informations d'un protocole de routage. Ou encore elle peut être l'agrégation de plusieurs sources. La base n'est donc pas statique, mais elle est prévue pour ne pas changer en temps réel, elle ne tient donc typiquement pas compte de la congestion, phénomène très transitoire. On peut aussi imaginer des serveurs ALTO dialoguant entre eux, pour échanger leurs informations, mais il n'existe pas de protocole standard pour cela (notre RFC concerne uniquement le protocole d'interrogation d'un serveur par un client).

L'information ALTO sera peut-être dans le futur également distribuée par d'autres moyens (une DHT ?) mais rien n'est normalisé pour l'instant. Cela nécessiterait sans doute des mécanismes permettant d'indiquer la fraîcheur de l'information (date d'expiration, par exemple) et des mécanismes de sécurité (signatures) qui n'existent pas actuellement. Pour l'instant, ces services sont fournis par le protocole de transport, HTTP.

ALTO distribue l'information sous la forme de tables (map), indiquant les caractéristiques du réseau, et les coûts associés. (Comme indiqué plus haut, ces tables peuvent être de simples fichiers, distribués comme tels.) Une utilisation directe des tables (ce qu'on nomme le Map Service) ferait beaucoup de travail pour le client : télécharger les tables (qui peuvent être très grosses), puis faire des calculs compliqués pour trouver le meilleur pair. ALTO fournit donc en plus des services auxiliaires pour les clients paresseux. Le premier est le service de filtrage (Map Filtering Service) : le client donne des informations supplémentaires et le serveur lui envoie des tables simplifiées, ne correspondant qu'à ce que le client a demandé. Le second service auxiliaire est le service d'information sur une extrémité (Endpoint Property Service) : le client demande des détails sur une extrémité, par exemple son type de connectivité (on préférera un pair connecté en FTTH à un pair ADSL). Enfin, le troisième service auxiliaire, Endpoint Cost Service permet d'obtenir directement les coûts d'une extrémité donnée. Mais, avant de détailler le protocole pour ces trois services, voyons le service de base, le Map Service, d'abord pour les tables, puis pour les coûts.

D'abord, l'accès aux informations sur le réseau, la Network Map (section 5). Elle part d'une observation : il est coûteux de distribuer l'information sur chaque machine connectée et c'est surtout inutile, les machines se groupant selon la topologie du réseau. Une Network Map est donc surtout une série de regroupements. Chaque regroupement est identifié par un PID (Provider-defined IDentifier) qui, comme son nom l'indique, n'a de sens que pour un opérateur donné. Chaque groupe désigné par un PID va comprendre un ou plusieurs préfixes d'adresses IP (d'autres identificateurs des extrémités sont possibles). Un PID peut désigner toute une ville, ou bien tout ce qui est connecté à un POP donné. On verra plus loin que les coûts sont indiqués par PID et pas par préfixe ou par adresse, de manière à diminuer la quantité d'information à manier. Dans le futur, des groupes pourront être identifiés par autre chose qu'un PID, par exemple un pays ou un AS. Un registre IANA a été créé pour stocker ces futurs propriétés des extrémités. À la réunion IETF de Toronto, en 2014, ont été ainsi discutées des propriétés comme « type d'accès » (ADSL ou 3G...), « volume limité » (pour les offres illimitées des opérateurs 3G/4G, etc.

Un exemple d'une table triviale serait :

  • PID1 regroupe 192.0.2.0/24 et 198.51.100.0/25.
  • PID2 regroupe 198.51.100.128/25.
  • PID3 regroupe 0.0.0.0/0 (c'est-à-dire tout le reste de l'Internet).

Ensuite, la table des coûts (Cost Map, section 6). Elle est souvent plus dynamique que la table du réseau (ce qui justifie leur séparation) et indique les coûts vus par l'opérateur. Un « type de coût » comprend une métrique (une définition de comment on mesure un coût) et un mode (comment comparer les coûts, notamment est-ce qu'on peut appliquer des opérations arithmétiques comme l'addition). Les métriques possibles sont enregistrées à l'IANA et l'enregistrement de nouvelles métriques requiert un RFC qui ne soit pas un document individuel.

Au moins une métrique doit être utilisée par le serveur, routingcost, qui doit refléter le coût de routage. Elle n'est pas davantage définie donc cela peut être un nombre de kilomètres à vol d'oiseau, un nombre de sauts IP, un calcul à partir des coûts indiqués par l'IGP, etc. Quant aux modes, deux sont obligatoires, numerical et ordinal. Le premier utilise des nombres en virgule flottante et permet toutes les opérations arithmétiques classiques (comme l'addition de deux coûts), le second utilise des entiers et ne permet que les comparaisons. À la réunion IETF de Toronto, en juillet 2014, on a discuté de futures métriques comme par exemple le taux de perte de paquets, la gigue...

Une table des coûts triviale serait :

  • En partant de PID1, le coût d'aller à PID2 est de 2 et le coût vers tout l'Internet (PID3) est de 5,
  • En partant de PID2, le coût pour aller à PID1 est de 1 (les coûts ne sont pas forcément symétriques) et le coût vers le reste de l'Internet (PID3) de 4.

Pour la plupart des exemples ci-dessous, je vais utiliser un des rares serveurs ALTO publics existants, http://alto.alcatel-lucent.com:8000/. Le plus simple est d'utiliser curl, combiné avec jsonlint pour mieux afficher le JSON :

% curl -s http://alto.alcatel-lucent.com:8000/network/full | jsonlint -f
{ 
  "meta" : { "vtag" : { 
          "resource-id" : "default-network",
          "tag" : "192.11.155.88/f9d21e031e5cf58103d4687d65025cfb"
        } },
  "network-map" : { 
      "defaultpid" : { 
          "ipv4" : [ "0.0.0.0/0" ],
          "ipv6" : [ "::/0" ]
        },
      "mypid1" : { "ipv4" : [ 
              "15.0.0.0/8",
              "10.0.0.0/8"
            ] },
      "mypid2" : { "ipv4" : [ "192.168.0.0/16" ] },
      "mypid3" : { "ipv4" : [ "192.168.10.0/24" ] },
      "peeringpid1" : { "ipv4" : [ "128.0.0.0/16" ] },
      "peeringpid2" : { 
          "ipv4" : [ "130.0.0.0/16" ],
          "ipv6" : [ "2001:DB8::/32" ]
        },
      "transitpid1" : { "ipv4" : [ "132.0.0.0/16" ] },
      "transitpid2" : { "ipv4" : [ "135.0.0.0/16" ] }
    }
}

Et voilà, on a la table complète du réseau d'un FAI (fictif). La table contient des préfixes IP, avec le PID associé (par exemple, 128.0.0.0/16 a le PID peeringpid1).

La section 8 de notre RFC en vient au protocole : ALTO est un protocole REST pour accéder à des ressources (les tables) et à des annuaires de ressources, les IRD (Information Resource Directory). Les ressources sont récupérées en HTTP et ont donc un type de média indiqué (application/alto-networkmap+json pour la table du réseau, et application/alto-costmap+json pour la table des coûts). Ces types MIME ont été enregistrés dans le registre officiel. En général, les requêtes ALTO se font avec la méthode HTTP GET. Comme tous les protocoles s'appuyant sur HTTP, ALTO a à sa disposition toutes les fonctions rigolotes de HTTP, comme la mise en cache (RFC 7234). De même, la sécurité est fournie par les mécanismes HTTP habituels (HTTPS, authentification du RFC 7236, etc). Les codes de réponse habituels de HTTP sont utilisés, comme 200 si tout s'est bien passé, 405 si la méthode utilisée ne plait pas au serveur et 503 si le serveur a un problème temporaire.

Si la requête HTTP s'est bien passée, mais qu'un problème spécifique à ALTO est survenu, le serveur renvoie des données JSON de type application/alto-error+json. Elles comprennent au moins un champ code qui indiquera le type d'erreur par exemple E_SYNTAX pour des paramètres d'entrée incorrects, E_MISSING_FIELD pour l'absence d'un champ obligatoire, etc. Testons avec le serveur public, en envoyant du JSON incorrect (accolade ouvrante sans la fermante) :

% curl -s -d '{' -H "Content-Type: application/alto-networkmapfilter+json" \
   -X POST http://alto.alcatel-lucent.com:8000/network/filtered | jsonlint -f 
{ "meta" : { 
      "code" : "E_SYNTAX",
      "syntax-error" : "Premature EOF in JSON object; expecting key"
    } }

Les erreurs possibles sont dans un registre IANA (section 14.5 de notre RFC).

La section 9 présente l'IRD, l'Information Resource Base, le mécanisme de distribution de méta-information (où trouver la Network Map, où trouver la Cost Map, etc). Elle a aussi la forme de données JSON, servies sous le type application/alto-directory+json. Voici celle du serveur ALTO public indiqué plus haut :

% curl -s http://alto.alcatel-lucent.com:8000/directory | jsonlint -f 
{ 
  "meta" : { 
      "cost-types" : { 
          "hop-num" : { 
              "cost-metric" : "hopcount",
              "cost-mode" : "numerical",
              "description" : "Simple hopcount"
            },
...
      "default-alto-network-map" : "default-network",
      "priv:alu-server-info" : { 
          "Build-Date" : "2014-04-28 13:57:08 EDT",
          "Build-OS" : "Mac OS X 10.9.2",
          "Build-OS-Nodename" : "wdr-i7mbp2.mh.lucent.com",
          "Build-User" : "wdr",
          "Implementation-Title" : "ALTO Server Implementation",
          "Implementation-Vendor" : "Alcatel-Lucent (Bell Labs/Murray Hill)",
          "Implementation-Version" : "(2014-04-28 13:57:08 EDT)",
...
  "resources" : { 
      "costs-end" : { 
          "accepts" : "application/alto-endpointcostparams+json",
          "capabilities" : { 
              "cost-constraints" : true,
              "cost-type-names" : [ 
                  "rtg-num",
                  "rtg-ord",
                  "hop-ord",
                  "hop-num"
                ]
            },
          "media-type" : "application/alto-endpointcost+json",
          "uri" : "http://alto.alcatel-lucent.com:8000/costs/end"
        },
...
      "default-network" : { 
          "media-type" : "application/alto-networkmap+json",
          "uri" : "http://alto.alcatel-lucent.com:8000/network/full"
        },
...
    }
}

On y voit, par exemple, que si je veux obtenir la table complète du réseau, je dois demander http://alto.alcatel-lucent.com:8000/network/full, comme fait plus haut.

Bon, ce n'est pas tout, ça, il faut maintenant des données. La section 10 indique les types de base qui sont utilisés : les PID (identificateurs des réseaux) sont des chaînes de caractères ASCII, les ressources comme les Network Maps ont également un identificateur, le Resource ID (encore une chaîne ASCII), les extrémités sont en général identifiées par une adresse ou un préfixe IP, à la syntaxe traditionnelle, les mode et métriques des coûts sont des chaînes ASCII...

Avec ces types, on peut construire les données. Quand un client ALTO a l'adresse d'un pair potentiel, et cherche dans la table le PID correspondant, il peut y avoir plusieurs préfixes qui correspondent. Dans ce cas, c'est le plus spécifique qui gagne (règle dite du « longest match », cf. RFC 1812). Pour éviter toute ambiguité, la table doit être complète et sans recouvrement. Complète signifie que toutes les adresses doivent être présentes. Dans le cas d'un opérateur ayant une connectivité avec tout l'Internet, cela veut dire qu'il faut représenter toutes les adresses de l'Internet. Une entrée pour le réseau 0.0.0.0/0 en IPv4 et ::0/0 en IPv6 est le moyen le plus simple d'atteindre ce but : cette entrée, attrapera toutes les adresses non couvertes par un des préfixes plus spécifiques. Quant au non-recouvrement, il signifie que la table ne doit pas avoir deux préfixes identiques (il peut y avoir recouvrement mais uniquement entre préfixes de longueurs différentes, la règle du longest match permettra alors de sélectionner).

Par exemple, cette table est complète et sans recouvrement :

   "network-map" : {
     "PID0" : { "ipv6" : [ "::/0" ] },
     "PID1" : { "ipv4" : [ "0.0.0.0/0" ] },
     "PID2" : { "ipv4" : [ "192.0.2.0/24", "198.51.100.0/24" ] },
     "PID3" : { "ipv4" : [ "192.0.2.0/25", "192.0.2.128/25" ] }
   }

Avec cette table du réseau, 192.0.2.1 sera dans PID3 (le préfixe dans PID2 est moins spécifique), 198.51.100.200 sera dans PID2 et 203.0.113.156 sera dans PID1, en raison de la règle attrape-tout qui couvre tout l'Internet IPv4. Notez l'utilisation de la désagrégation : 192.0.2.0/24 a été représenté avec deux préfixes dans PID3 car, autrement, la table aurait eu un recouvrement.

Et la table des coûts ? Voici un exemple :

% curl -s http://alto.alcatel-lucent.com:8000/costs/full/routingcost/num | jsonlint -f
{ 
  "cost-map" : { 
      "defaultpid" : { 
          "defaultpid" : 15.0,
          "mypid1" : 15.0,
          "mypid2" : 15.0,
          "mypid3" : 15.0,
          "peeringpid1" : 15.0,
          "peeringpid2" : 15.0,
          "transitpid1" : 15.0,
          "transitpid2" : 15.0
        },
      "mypid1" : { 
          "defaultpid" : 4.0,
          "mypid1" : 15.0,
          "mypid2" : 15.0,
          "mypid3" : 15.0,
          "peeringpid1" : 15.0,
          "peeringpid2" : 15.0,
          "transitpid1" : 5.0,
          "transitpid2" : 10.0
        },
...
      "peeringpid1" : { 
          "defaultpid" : 15.0,
          "mypid1" : 15.0,
          "mypid2" : 15.0,
          "mypid3" : 15.0,
          "peeringpid1" : 15.0,
          "peeringpid2" : 15.0,
          "transitpid1" : 15.0,
          "transitpid2" : 15.0
        },
...
    },
  "meta" : { 
      "cost-type" : { 
          "cost-metric" : "routingcost",
          "cost-mode" : "numerical"
        },
      "dependent-vtags" : [ { 
            "resource-id" : "default-network",
            "tag" : "192.11.155.88/f9d21e031e5cf58103d4687d65025cfb"
          } ]
    }
}

On y voit, par exemple, que le coût entre

mypid1

et

peeringpid1

est de 15 (en utilisant la métrique routingcost).

On l'a vu, le client ALTO peut ne demander qu'une partie d'une table, pour réduire la consommation de ressources réseau et de temps de calcul. Ici, un client envoie un objet JSON (de type application/alto-networkmapfilter+json) qui indique quel(s) PID l'intéresse(nt) :

POST /networkmap/filtered HTTP/1.1
Host: custom.alto.example.com
Content-Length: 33
Content-Type: application/alto-networkmapfilter+json
Accept: application/alto-networkmap+json,application/alto-error+json

{
     "pids": [ "PID1", "PID2" ]
}

Notez qu'on utilise la méthode HTTP POST au lieu de GET. On peut aussi filtrer les tables de coûts, par exemple en n'acceptant qu'un seul mode.

Et voici une récupération des propriétés d'une extrémité, l'adresse de l'extrémité étant indiquée dans l'objet JSON application/alto-endpointpropparams+json :

POST /endpointprop/lookup HTTP/1.1
Host: alto.example.com
Content-Length: 181
Content-Type: application/alto-endpointpropparams+json
Accept: application/alto-endpointprop+json,application/alto-error+json

{
    "properties" : [ "my-default-networkmap.pid",
                     "priv:ietf-example-prop" ],
    "endpoints"  : [ "ipv4:192.0.2.34",
                     "ipv4:203.0.113.129" ]
}

HTTP/1.1 200 OK
Content-Length: 396
Content-Type: application/alto-endpointprop+json

...
    "endpoint-properties": {
      "ipv4:192.0.2.34"    : { "my-default-network-map.pid": "PID1",
                               "priv:ietf-example-prop": "1" },
      "ipv4:203.0.113.129" : { "my-default-network-map.pid": "PID3" }
    }
  }

Et ici une récupération des coûts associés à une extrémité. Par exemple, on est un client BitTorrent qui hésite entre trois pairs potentiels de l'essaim, 192.0.2.89, 198.51.100.34 et 132.0.113.45. On les envoie au serveur (notez les conséquences pour la vie privée : ce point est développé plus loin) :

# Les données JSON de la requête sont mises dans un fichier
% cat /tmp/select 
{
    "cost-type": {"cost-mode" : "ordinal",
                  "cost-metric" : "routingcost"},
    "endpoints" : {
      "srcs": [ "ipv4:10.0.2.2" ],
      "dsts": [
        "ipv4:192.0.2.89",
        "ipv4:198.51.100.34",
        "ipv4:132.0.113.45"
      ]
    }
  }

# On donne ce fichier à curl comme source des données à envoyer
# (option -d)
% curl -s -d '@/tmp/select' -H "Content-Type: application/alto-endpointcostparams+json" \
   -X POST http://alto.alcatel-lucent.com:8000/costs/end | jsonlint -f

Et le serveur ALTO répond en indiquant des coûts :

{ 
  "endpoint-cost-map" : { "ipv4:10.0.2.2" : { 
          "ipv4:132.0.113.45" : 2,
          "ipv4:192.0.2.89" : 1,
          "ipv4:198.51.100.34" : 1
        } },
  "meta" : { "cost-type" : { 
          "cost-metric" : "routingcost",
          "cost-mode" : "ordinal"
        } }
}

Ici, depuis la source 10.0.2.2, les meilleurs pairs sont 192.0.2.89 et 198.51.100.34, ex-aequo.

Pour rendre les choses plus concrètes, la section 12 du RFC présente un certain nombre de scénarios d'usage. Le premier, et le plus « évident » est celui d'un client ALTO placé dans un tracker pair à pair, un de ces logiciels qui aiguillent les pairs vers un pair qui a le contenu convoité. Chaque tracker gère des essaims (ensemble de pairs qui téléchargent le même fichier et a la tâche délicate de choisir quels pairs sont annoncés à chaque machine connectée au tracker (sauf si l'essaim est petit, auquel cas la tâche est triviale, on envoie tout). Les trackers utilisent déjà un ensemble de mécanismes pour cela et ils peuvent y ajouter ALTO. Comme un tracker pour un contenu populaire (mettons le dernier épisode d'une série télévisée très populaire) peut avoir des dizaines, voire des centaines de milliers de machines connectées, la meilleure solution ALTO est sans doute de télécharger la table du réseau et la table des coûts complètes et de les analyser. Pour chaque membre de l'essaim, le tracker cherchera le PID dans la table du réseau, puis le coût dans la table des coûts. Il enverra les pairs de préférence vers un pair du même PID ou, sinon, vers le pair au coût le plus bas.

Mais, pour diverses raisons, les pairs peuvent souhaiter faire la sélection eux-même. Les trackers sont des cibles évidentes pour la répression du pair à pair (ou, tout simplement, des SPOF...) et on peut vouloir se débrouiller sans eux, utilisant un mécanisme de rendez-vous complètement pair à pair comme une DHT. Dans ce cas, le client ALTO doit forcément être dans le logiciel de partage pair à pair (par exemple rTorrent). La technique la plus coûteuse, mais aussi celle qui préserve le mieux la vie privée de l'utilisateur, est que le logiciel télécharge la table du réseau et la table des coûts, puis fasse les calculs lui-même. Ainsi, il ne donnera presque aucune information au serveur ALTO.

Troisième scénario d'usage proposé par notre RFC, la sous-traitance des calculs et du filtrage au serveur ALTO, en utilisant le Map Filtering Service. Le logiciel pair à pair, cette fois, ne télécharge pas les tables entières, il indique au serveur ALTO une liste de pairs potentiels (trouvée, par exemple, sur la DHT), des critères de choix, et le serveur ALTO choisit le « meilleur » selon ces critères.

Notre RFC comprend ensuite une section 13 de discussion sur divers points du protocole. Premier point : comment un client trouve-t-il le serveur ALTO ? La norme ne définit pas une méthode unique et obligatoire. Le serveur peut être trouvé par une configuration manuelle, ou bien par la technique DNS du RFC 7286 sur la découverte de serveurs ALTO.

Et le cas d'une machine qui a plusieurs adresses IP ? C'est d'autant plus compliqué qu'il y a une interaction entre l'adresse utilisée, le FAI par lequel on passe et l'adresse du pair distant. ALTO ne fournit pas de solution immédiate, uniquement un mécanisme de description des extrémités suffisamment souple pour qu'on puisse y intégrer d'autres identificateurs que les bêtes adresses IP (voir plus haut les registres IANA de types d'adresses).

Reste à régler la question du passage par les routeurs NAT, le cauchemar habituel du pair à pair. En raison de ces obstacles, un protocole devrait éviter de transporter des adresses IP dans ses données, justement ce que fait ALTO. On a vu que, dans certains cas, le client ALTO indique son adresse au serveur, pour lui permettre un bon choix du pair. En raison du NAT, cette méthode ne marche pas forcément et le RFC autorise donc le serveur ALTO à utiliser l'adresse IP source des paquets ALTO entrants (adresse traduite par le routeur NAT) plutôt que celle indiquée dans les données JSON. Si le client ALTO n'est pas satisfait et veut indiquer lui-même son adresse IP dans les données, il doit utiliser un service comme STUN (RFC 8489) pour découvrir son adresse publique.

Et la sécurité dans tout ça ? La section 15 du RFC explore en détail les questions de sécurité d'ALTO. Le RFC cahier des charges, le RFC 6708, reconnaissait le problème et demandait des solutions minimum. D'abord, l'authentification. En effet, un attaquant peut vouloir distribuer de la fausse information ALTO, pour tromper un pair et l'envoyer vers des pairs plus lents. Cela serait une attaque par déni de service sur le réseau pair à pair. ALTO s'appuyant sur HTTP, les solutions de sécurité à utiliser sont celles de HTTP, essentiellement TLS. Pour l'authentification via un certificat, les clients et serveurs ALTO doivent bien suivre le RFC 6125. Attention, cette authentification se fait en fonction du nom présent dans l'URL utilisé par le client ALTO. Si celui-ci utilise un mécanisme de découverte de l'URL qui n'est pas fiable, la protection de TLS arrivera trop tard. Aujourd'hui, il n'y a pas de protection des données ALTO (pas de signature des maps, par exemple), seulement du canal par lequel elles transitent.

C'est bien joli d'authentifier le serveur ALTO mais encore faut-il qu'il soit digne de confiance. Si un méchant serveur ALTO distribue de mauvaise informations, comment peut-on se protéger ? Le RFC 5693 pointait déjà ce risque. Si les serveurs ALTO sont gérés par les FAI, comme beaucoup d'entre eux ont affirmé leur goût pour les violations de la neutralité du réseau, pourquoi les clients leur feraient-ils confiance ? Deux approches sont possibles pour le client ALTO. La première est d'analyser les conséquences de son choix. Si un logiciel pair à pair utilise parfois ALTO et parfois choisit les pairs au hasard, en mesurant les débits obtenus, il peut savoir si l'utilisation d'ALTO est dans son intérêt. (Attention, le but d'ALTO n'est pas uniquement la satisfaction du client : un FAI peut légitimement envoyer les clients vers des pairs qui ne sont pas plus rapides mais qui lui coûtent moins cher, par exemple parce qu'ils sont accessibles par un lien de peering gratuit.) Une seconde approche pour le client est de ne pas utiliser les serveurs ALTO du FAI (qui n'a pas forcément les mêmes intérêts que lui) mais des serveurs ALTO « neutres » fournis par une tierce partie (les exigences AR-20 et AR-21 dans le RFC 6708). Rappelez-vous aussi qu'ALTO n'est qu'une source d'information parmi d'autres, le client l'utilise pour sa prise de décision mais ne lui obéit pas aveuglément.

Et la confidentialité ? Bien sûr, une bonne partie des informations distribuées par ALTO sont publiques ou presque. La network map peut être vue comme confidentielle par le FAI mais, si elle est distribuée à tous ses clients, elle ne peut pas rester trop longtemps secrète. Néanmoins, on ne souhaite pas forcément que n'importe quel espion lise tout le trafic ALTO. Après tout, en combinant la table du réseau et celle des coûts, un attaquant peut récolter plein d'information sur le réseau d'un opérateur, à des fins d'espionnage industriel, ou bien pour préparer une attaque par déni de service. Et les informations données par les clients (liste de pairs potentiels...) sont également très sensibles. Que peut-on faire contre l'espionnage ? D'abord, au moment de créer les tables qui seront utilisées par ALTO, il faut se rappeler qu'ALTO n'impose pas un niveau de détail particulier. Le FAI qui veut avant tout optimiser le trafic fournira un grand niveau de détails, celui qui craint l'espionnage économique donnera des tables plus grossières. Ensuite, pour éviter l'écoute par un tiers, ALTO utilise, comme pour l'authentification, les solutions habituelles de HTTP, en l'occurrence TLS.

Notre RFC se penche aussi sur la vie privée des clients ALTO. D'abord, en raison de l'utilisation de HTTP, certains des risques de vie privée de HTTP affectent ALTO (par exemple l'utilisation de cookies, pas obligatoire dans ALTO mais qui peuvent être activés par défaut par certains clients HTTP). Ensuite, il y a clairement des risques de confidentialité différents pour le client et pour le serveur ALTO. Le client soucieux de vie privée a tout intérêt à télécharger l'intégralité des tables (réseau et coûts) et à faire la sélection soi-même, ne transmettant ainsi aucune information au serveur. En revanche, le serveur soucieux de sa vie privée à lui va vouloir le contraire : ne pas envoyer les tables complètes mais demander au client de lui fournir des critères de filtrage, avec lesquels le serveur fera son choix. On peut donc s'attendre, si ALTO se répand, à des conflits entre utilisateurs et FAI, par exemple si un FAI décide de ne pas fournir le service « tables complètes » et impose l'utilisation des services avec filtrage.

Dernier risque de sécurité pour ALTO, le risque de panne. Si on est habitué à utiliser ALTO, on sera bien embêté si un attaquant trouve le moyen de planter le serveur ALTO. Cela peut servir à aggraver une attaque par déni de service. Ce risque est d'autant plus important qu'un serveur ALTO peut se trouver, si on lui demande de faire des filtrages, dans l'obligation de faire des gros calculs, décidés par son client. Un client malveillant peut ainsi générer facilement une table avec N origines et M destinations, forçant le serveur à calculer N*M chemins. Un serveur ALTO doit donc être prudent sur ce point et prévoir de la limitation de trafic, et sans doute de l'authentification des clients (par exemple, pour un FAI, restreindre l'accès à ses abonnés).

Reste la gestion d'ALTO (section 16). Suivant le RFC 5706, cette section va se pencher sur les problèmes concrets des pauvres ingénieurs système qui vont devoir déployer ALTO et le maintenir en état de marche. ALTO reposant sur HTTP, cela impose l'installation et le maintien d'un serveur HTTP, soit un serveur standard avec un module ALTO, soit un serveur ALTO incluant le protocole HTTP. Mais il y a des problèmes plus sérieux, notamment les choix des services rendus. Par exemple, quel niveau de détail envoie-t-on, quelles requêtes permet-on ? Si on refuse d'envoyer la table du réseau complète, que doit-on faire lorsqu'une requête avec filtrage arrive, avec un filtre vide (un client ALTO astucieux peut utiliser cela pour contourner les restrictions d'accès à la table complète) ? Il faut aussi décider d'un mécanisme pour distriber l'URL où trouver le serveur ALTO. Dans la documentation accessible aux utilisateurs ? Uniquement avec la méthode du futur RFC sur l'utilisation du DNS pour trouver le serveur ? ? (Le RFC n'en parle pas mais le faible nombre de clients ALTO existants n'aide pas à trancher sur ces points.) Heureusement, il n'y a pas encore de question de migration à assurer, puisque ALTO est un nouveau service.

Pour l'opérateur réseau, ALTO va, s'il est utilisé, mener à des déplacements du trafic vers d'autres lignes. C'est bien son but mais cela peut entraîner des surprises : le responsable du serveur ALTO a désormais les moyens d'influencer sur la localisation du trafic, autant que celui qui configurait MPLS ou OSPF.

Pour la journalisation, le RFC recommande que les serveurs ALTO utilisent le standard syslog (RFC 5424), ce que ne font typiquement pas les serveurs HTTP habituels.

ALTO ne fournit pas encore d'interface standard de communication entre serveurs ALTO (par exemple pour agréger de l'information provenant de diverses sources), ni de MIB, ni d'interface standard de configuration, style NETCONF.

Pour les passionnés d'histoire, l'annexe B rappelle tous les ancêtres d'ALTO, notamment P4P (voir « P4P: Provider Portal for (P2P) Applications », présenté à SIGCOMM en 2008.

Et les mises en œuvre existantes ? On a vu le serveur d'Alcatel-Lucent. Il existe aussi celui fait à partir d'un dessin fameux de XKCD. Trois mises en œuvre différentes ont été montrées à la réunion IETF 80 et bien plus ont été testées rigoureusement lors d'un test d'interopérabilité à l'IETF 81. Les résultats sont documentés en ligne. Un autre test a eu lieu à l'IETF 85 et est également documenté.

Merci à Wendy Roome pour le serveur ALTO public utilisé ici, et pour ses patientes explications.


Téléchargez le RFC 7285


L'article seul

RFC 7284: The Profile URI Registry

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : M. Lanthaler
Pour information
Première rédaction de cet article le 1 juillet 2014


Le RFC 6906 définit la notion de profil, une variante (en général restrictive) d'un format. Les profils du RFC 6906 sont identifiés par un URI et ce nouveau RFC crée un registre de ces URI, afin de faciliter la tâche des développeurs.

Les conditions d'inscription dans le registre sont spécifiées dans la section 2 : il faut indiquer l'URI qui sert d'identificateur, un nom court pour le profil, la description et un lien vers une documentation stable du profil, accessible publiquement. Ensuite (section 4), c'est du premier arrivé, premier servi (politique décrite dans la section 4.1 du RFC 5226). La section 3 donne un exemple en utilisant un profil bidon, http://example.com/profiles/example.

Le registre est désormais en ligne et comprend au début cinq profils :

  • urn:example:profile-uri, prévu pour être utilisé dans les exemples, documentations, etc,
  • Dublin Core http://dublincore.org/documents/2008/08/04/dc-html/, un moyen pour mettre les métadonnées en HTML,
  • http://www.w3.org/ns/json-ld#expanded, http://www.w3.org/ns/json-ld#compacted et http://www.w3.org/ns/json-ld#flattened, des profils du monde JSON décrits dans une norme du W3C.

Téléchargez le RFC 7284


L'article seul

RFC 7282: On Consensus and Humming in the IETF

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : P. Resnick (Qualcomm)
Pour information
Première rédaction de cet article le 1 juillet 2014


L'IETF, organisme de normalisation des protocoles de l'Internet, fonctionne normalement par « consensus ». Il n'y a pas de vote formel, pas de majorité qui décide, on discute jusqu'à ce que presque tout le monde soit d'accord. À cause du « presque », on parle de « consensus approximatif » (rough consensus). Ça, c'est la théorie. En pratique, les évolutions récentes font que de plus en plus de décisions sont prises suite à des opérations qui ressemblent pas mal à des votes majoritaires, justement ce que les règles de l'IETF voulaient éviter. D'où ce RFC d'opinion, écrit pour défendre le principe du consensus approximatif, et pour appeler à se méfier de ces dérives.

Ce RFC a le statut « pour information » et représente le point de vue de son auteur : ce n'est pas un document officiel. En outre, il ne définit pas de nouvelles règles, il explique juste le fonctionnement idéal. Pour résumer ce RFC, revenons à la théorie. Le fonctionnement normal de l'IETF a été traduit par une percutante phrase de Dave Clark (dans « A Cloudy Crystal Ball - Visions of the Future »), que tous les participants à l'IETF connaissent par cœur : « We reject kings, presidents and voting. We believe in rough consensus and running code. ». Les décisions à l'IETF ne peuvent pas être prises par un seul individu (roi ou président), mais elles ne doivent pas non plus être prises par un vote, pour les raisons expliquées plus loin. Au contraire, elles doivent s'appuyer sur le consensus approximatif, lui-même nourri d'expérience concrète (le « running code », par opposition à des organisations comme l'ISO qui ont développé des usines à gaz impossibles à programmer). La pratique doit toujours l'emporter : le code qui marche a raison.

Notez que le consensus est approximatif : avoir un consensus tout court (tout le monde est d'accord ou, au moins, se tait) serait l'idéal mais ce n'est pas réaliste. Demander un consensus complet serait donner un droit de veto à n'importe quel individu négatif qui s'oppose à tout (l'IETF, comme toute organisation humaine, a quelques trolls de ce calibre...).

Comme il n'y a pas de vote, l'IETF a développé une autre pratique inhabituelle, le mmmmmmmm (humming). Lorsqu'on veut avoir une idée de l'opinion des gens, lors d'une réunion physique, on demande à chacun de se manifester par ce bruit produit en gardant la bouche fermée (ce qui assure un certain secret, contrairement aux mains levées). En faisant des mmmmmmmmm plus ou moins forts, on peut même avoir un vote non-binaire. Ce rituel est souvent pratiqué pendant les réunions IETF.

Mais tous les participants à l'IETF ne comprennent pas forcément ces subtilités, surtout lorsqu'ils viennent d'arriver. « Pourquoi un mmmmmm et pas un vote normal ? » ou « Il y avait une majorité de mmmmmm en faveur de la proposition B, pourquoi continue-t-on de discuter ? » Même quand le groupe de travail est arrivé à un résultat, bien des participants ne comprennent pas comment il a été obtenu et pensent que le processus a produit un mauvais résultat. Paradoxe : il n'y a pas de consensus à l'IETF sur l'importance du consensus. Ou plutôt, il y en a un en parole (la phrase de Clark est très souvent citée) mais pas dans la réalité du travail.

Donc, premier point expliqué par ce RFC, en section 2, l'important n'est pas que tout le monde soit d'accord, mais qu'il n'y ait pas trop de désaccord. Imaginons un groupe qui doit trancher entre deux formats pour un protocole (mettons JSON et XML, pour prendre un exemple réel...). Il y a des gens pour et des gens contre chacune des deux propositions. Cela veut-il dire qu'il n'y aura jamais de consensus ? Sauf que tout travail d'ingéniérie (et la création d'une norme technique en est un) nécessite des compromis. Si on demande un accord de tous, on ne l'aura jamais (surtout avec le goût des ingénieurs pour les discussions sur la couleur du garage à vélos). En revanche, si on demande qu'il n'y ait pas d'objections bloquantes, on peut arriver à un résultat. Les partisans de XML ne vont pas tout à coup préférer JSON. Par contre, ils peuvent considérer que JSON, sans être leur solution préférée, est acceptable, qu'il n'a pas de défaut qui mettrait vraiment en péril le nouveau protocole. Il ne faut donc pas demander aux participants « êtes-vous heureux avec ce choix ? » (il y aura forcément des râleurs) mais plutôt « ce choix a t-il un défaut rédhibitoire (et, si vous répondez oui, argumentez) ? » Bien sûr, il faut quand même qu'il y ait un certain nombre de gens qui soutiennent activement la proposition. Une solution technique qui ne rencontrerait aucune objection, mais pas non plus de soutien actif ne serait sans doute pas intéressante !

Autre point où il faut entrer dans les nuances, la différence entre compromis et compromission. Le mot « compromis » (en français, comme en anglais avec « compromise ») est utilisé dans deux sens différents. Le compromis est une bonne chose : en ingéniérie, on a rarement des solutions idéales. Il faut en général arbitrer et, par exemple, décider de sacrifier du temps CPU pour consommer moins de ressources réseau ou le contraire, ou bien mettre de la redondance pour assurer l'intégrité alors qu'elle va diminuer les performances, ou encore préférer un format texte qui facilite le débogage à un format binaire plus efficace mais plus dur à traiter par les humains. Ce genre de compromis est un travail normal et essentiel de l'ingénieur, et l'IETF le fait.

En revanche, les compromissions sont néfastes : une compromission est quand on tient compte des opinions et pas des principes d'ingéniérie. Par exemple qu'on accepte telle option, qui semble inutile, voire dangereuse, parce qu'une partie du groupe de travail trépigne et y tient absolument. On ajoute alors l'option pour obtenir leur accord (ou leur non-désaccord), faisant ainsi une compromission (ou un « design by committee », où le résultat n'enthousiasme personne, à force d'avoir intégré plein de demandes contradictoires). Ce genre de compromission (qu'il faudrait plutôt appeler capitulation) n'a pas réglé les problèmes techniques. Pire, on peut voir ce que le RFC désigne sous le nom de « horse trading » (comportement de maquignon ?) « Je ne suis pas d'accord avec ta proposition sur l'algorithme de traitement de la congestion, tu n'es pas d'accord avec ma proposition sur le format des données, mettons-nous d'accord pour chacun soutenir la proposition de l'autre. » Cela permet d'arriver à un accord mais au prix de la qualité : les objections contre les deux propositions ont été ignorées, alors qu'elles étaient peut-être sérieuses techniquement et devaient être traitées comme telles. Ce comportement donne l'apparence du consensus alors qu'il est de la pure magouille.

Deuxième point important, en section 3, le fait qu'il faut traiter toutes les questions mais pas forcément les résoudre. Parfois, une objection technique va être résolue à la satisfaction de tous : celui qui l'a soulevée est convaincu que son objection était erronée, ou bien le groupe de travail a été convaincu qu'elle était sérieuse et a modifié le protocole en cours de discussion. Mais, parfois, le groupe de travail ne change pas de direction et celui qui a soulevé l'objection est frustré. Est-ce un échec du consensus ? Non, car il y a toujours « consensus approximatif ». Celui-ci est une solution de repli : l'idéal est le consensus complet mais, comme le dit le conte « Le meunier, son fils et l'âne », on ne peut pas toujours plaire à tout le monde et, de toute façon, il y a des gens qui ne sont jamais contents. La notion de consensus approximatif est faite pour ces cas-là : l'objection n'a pas été ignorée, elle a été sérieusement étudiée et le groupe de travail a délibérement décidé de continuer dans la voie originale. Compte-tenu de la forte personnalité de pas mal de participants à l'IETF, le consensus seulement approximatif, qui devrait être une exception à la règle du consensus, est souvent la norme.

Notez que ce consensus approximatif vu comme un repli lorsque le consensus idéal n'est pas atteint est une description nouvelle. Le RFC 1603 voyait plutôt le consensus approximatif comme exprimant le « point de vue dominant » du groupe de travail IETF. Cette vision quantitative (exprimée de manière encore plus directe dans son successeur, le RFC 2418) n'est pas partagée par ce nouveau RFC 7282, qui met l'accent sur le fait que les 0,1 % qui sont en désaccord ont peut-être raison (comme le disait un de mes enseignants à la fac, « la science n'est pas une démocratie »).

Et le mmmmmmm ? La section 4 revient sur son rôle. D'abord, pourquoi ne vote-t-on pas, à l'IETF (certainement la première question que posent tous les nouveaux venus) ? D'abord, l'IETF n'a pas de membres : il n'existe aucun processus formel d'adhésion. On s'inscrit à la liste de diffusion d'un groupe de travail et, hop, on est un participant à l'IETF. Impossible donc, de compter le corps électoral. Ensuite, le vote peut être une mauvaise chose : comme indiqué plus haut (même si l'expression n'est pas dans le RFC), la technique n'est pas démocratique. 51 % ou même 99 % d'un groupe de travail peut toujours voter X, c'est peut-être quand même Y qui est justifié techniquement. Le vote pourrait être un moyen de glisser sous le tapis les problèmes gênants, qui doivent au contraire être traités en pleine lumière. Une des raisons de l'utilisation du mmmmmmm est donc, précisément par le caractère folkorique de la procédure, de rappeler qu'on ne vote pas, à l'IETF (par comparaison avec, disons, un vote à main levée).

Le mmmmmmm sert donc à jauger la situation et à ordonner la discussion. Par exemple, s'il y a beaucoup plus de mmmmmmm objectant contre X que contre Y, partir des objections contre Y peut permettre d'optimiser le temps de discussion (sans pour autant considérer que Y a « gagné »).

Malgré cela, un effet pervers s'est développé, avec des gens considérant le mmmmmmm comme une sorte de vote anonyme. Ce n'est pas son but, le mmmmmmm devrait être utilisé au début (pour avoir une idée des points de vue en présence) pas à la fin pour clore le bec aux minoritaires. Le mmmmmmm n'est pas une méthode magique, et, s'il est mal utilisé, il a souvent les mêmes inconvénients que le vote classique (par exemple une extrême sensibilité à la rédaction des questions, ou même simplement à leur ordre).

Donc, le but, c'est le consensus ? Pas du tout. La section 5 insiste sur le fait que le consensus est un moyen et pas une fin. Le consensus approximatif est un moyen d'obtenir la meilleure décision technique possible, en s'assurant qu'aucune objection, aucun problème, n'a été négligé. Au contraire, l'expérience des SDO qui votent a largement montré que cela mène à des mauvaises décisions, notamment suite à des compromissions pour obtenir une majorité, et suite au mépris des remarques parfaitement valides des minoritaires.

Alors, évidemment, la méthode IETF prend du temps et est souvent exaspérante, même pour les plus patients des participants. Et il ne faut donc pas se faire d'illusions : les magouilles politiciennes existent aussi à l'IETF. Simplement, passer à un système plus rapide comme le vote permettrait d'avoir plus vite des normes de moins bonne qualité.

La section 6 revient sur la notion de majorité et sur l'approche quantitative, qu'appuyait le RFC 2418 (« Note that 51% of the working group does not qualify as "rough consensus" and 99% is better than rough. ») S'il y a 100 participants dans un groupe qui trouvent la proposition en cours excellente, et la soutiennent activement, et 5 participants qui sont en désaccord, prédisant, par exemple, « ce protocole va créer de la congestion et n'a aucun mécanisme de réaction en cas de congestion » et que personne ne répond de manière argumentée à ce point, alors, il n'y a pas de consensus, même pas de consensus approximatif. Une objection a été ignorée, pas traitée, et pas rejetée. Le faible nombre d'opposants n'y change rien, on ne peut pas parler d'un consensus, même pas approximatif. (Le RFC note que c'est pareil si la ou les personnes qui ont soulevé l'objection ne sont pas des participants réguliers, et qu'ils n'insistent pas après avoir fait leurs remarques ; les remarques en question doivent quand même être traitées.)

En sens inverse, et même si cela peut sembler anti-intuitif, on peut avoir 5 personnes qui soutiennent un projet et 100 qui sont contre, et qu'il y ait quand même un consensus en faveur du projet (section 7). Comment est-ce possible ? Le RFC décrit une telle situation (et des cas analogues se sont effectivement produits) : un groupe de travail a peu de participants actifs. Ils sont arrivés à un consensus malgré les objections de l'un d'entre eux, objection qui a été étudiée et rejetée. Le « dissident » fait appel à une centaine de personnes, parfois des participants à d'autres groupes de travail mais souvent des employés de la même société que lui, qui ne connaissent rien au sujet mais font ce qu'on leur dit. Ils envoient tous un message sur la liste de diffusion, disant qu'ils soutiennent l'objection. Une bonne façon de traiter ces soutiens vides (sans contenu nouveau) est de leur demander « Nous avons déjà discuté de ce point et abouti à un consensus. Avez-vous des éléments techniques nouveaux qui justifieraient de rouvrir la discussion ? » En général, les commerciaux et marketeux qui avaient été recrutés pour faire masse dans la discussion ne répondent pas... Ils croyaient que l'IETF fonctionnait sur un système de vote et sont surpris de découvrir qu'on leur demande d'argumenter. Bien sûr, ce cas est un peu extrême mais la même méthode peut servir dans des cas moins dramatiques. Le principe du consensus sert à traiter une des plus grosses failles des systèmes de vote : le bourrage des urnes par des ignorants.


Téléchargez le RFC 7282


L'article seul

RFC 7279: An Acceptable Use Policy for New ICMP Types and Codes

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : M. Shore (No Mountain Software), C. Pignataro (Cisco Systems)
Première rédaction de cet article le 13 juin 2014


Voici un court RFC sur un protocole peu connu mais indispensable au bon fonctionnement de l'Internet : ICMP. Plus précisément, ce RFC se penche sur la création de nouveaux types et codes ICMP : quand est-ce une bonne idée ?

ICMP est normalisé dans le RFC 792 pour IPv4 et dans le RFC 4443 pour IPv6. Il sert de protocole de signalisation pour IP, transportant des informations sur l'état du réseau et les éventuels problèmes rencontrés. Les messages ICMP ont un champ nommé Type qui indique la catégorie du message et, lorsque le message nécessite davantage d'analyse, un champ Code. Ainsi, pour IPv6, un paquet ICMP dont le champ Type vaut 1 indique que la destination souhaitée n'est pas joignable, et le Code indique la raison (par exemple, 0 indique que le routeur ne connait pas de route vers cette destination). La liste de ces types et codes n'est pas figée et on pouvait toujours en ajouter des nouveaux (par exemple celui du RFC 6743) ou en retirer (cf. RFC 6633). Un registre IANA donne la liste actuelle (pour IPv4 et pour IPv6).

Il n'existait pas de politique formelle quant à l'enregistrement de nouveaux types et codes. Chaque demande était évaluée sans référence à une règle commune. La section 2 de notre RFC introduit une politique. Deux cas sont estimés acceptables :

  • Le nouveau type sert à indiquer à l'émetteur du paquet qu'un problème dans la transmission est survenu en aval. L'examen du message ICMP doit permettre à l'émetteur de savoir si le paquet a été transmis ou pas. C'est par exemple le cas, pour les types existants, de Destination unreachable (type 3 en IPv4 et 1 en IPv6), de Time exceeded (utilisé par traceroute, type 11 en IPv4 et 3 en IPv6), de Packet too big (type 2 en IPv6, malheureusement trop souvent filtré, ce qui explique les problèmes de Path MTU discovery fréquents avec IPv6).
  • Le nouveau type sert à obtenir ou à transmettre des informations sur un nœud du réseau, obtenir ou transmettre des paramètres du réseau, ou découvrir des machines situées sur le lien. C'est par exemple le cas, pour les types existants, de Echo (request or reply) (dont dépend la commande ping, types 0 et 8 en IPv4, 128 et 129 en IPv6), des messages de sollicitation ou d'annonce du routeur (types 9 et 10 en IPv4, 133 et 134 en IPv6), des messages de résolution d'adresse IP en adresse MAC (types 135 et 136 en IPv6, cf. RFC 4861).

La section 2.1 de notre RFC classe tous les types existants en indiquant de quel cas ils relèvent. Attention, cette classification couvre aussi les types abandonnés et qui ne doivent plus être utilisés (RFC 6918).

Ces cas limitatifs excluent donc l'usage d'ICMP pour faire un protocole de routage complet. D'abord, du point de vue architecture, ICMP n'a pas été prévu pour cela. Ensuite, il n'a aucun mécanisme d'authentification et il permet des usurpations triviales. D'autre part, et malheureusement, il est souvent filtré.

Il existe au moins un protocole de routage mis en œuvre sur ICMP : RPL (RFC 6550). C'est une exception et elle ne devrait pas être généralisée (RPL ne fonctionne pas au niveau de tout l'Internet mais uniquement dans des réseaux locaux).

Certaines applications utilisent ICMP de manière créative, par exemple en provoquant délibérement des conditions d'erreur, pour récolter, via les messages ICMP d'erreur, des informations sur le réseau. C'est notamment le cas de traceroute, qui envoie des paquets avec un TTL délibérement trop bas, pour provoquer l'envoi de messages Time exceeded. Cela ne pose pas de problème philosophique : ces applications utilisent les types ICMP existants, elles ne changent pas le protocole.

Notre RFC note également que, si on veut étendre ICMP parce qu'il est actuellement trop limité, il existe un mécanisme standard pour mettre de l'information structurée dans les messages ICMP, mécanisme décrit dans le RFC 4884. Par exemple, ce mécanisme permet d'indiquer dans les messages ICMP des informations sur les interfaces réseaux utilisées par le paquet d'origine (RFC 5837).

La section 3 résume les choses importantes à savoir sur la place d'ICMP : originellement prévu pour signaler les erreurs, il a été vite étendu pour faire des diagnostics (style ping). Il fait partie intégrante d'IP (ce n'est pas une option : une machine IP doit gérer ICMP). Bien que ses messages soient encapsulés dans IP, il n'est pas considéré comme un protocole au-dessus d'IP mais comme un composant d'IP. Et le RFC rappelle que son nom est trompeur : le « Protocole des Messages de Contrôle de l'Internet » ne contrôle nullement l'Internet, son rôle est plus modeste mais indispensable.


Téléchargez le RFC 7279


L'article seul

RFC 7276: An Overview of Operations, Administration, and Maintenance (OAM) Tools

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : T. Mizrahi (Marvell), N. Sprecher (Nokia Solutions and Networks), E. Bellagamba (Ericsson), Y. Weingarten
Pour information
Réalisé dans le cadre du groupe de travail IETF opsawg
Première rédaction de cet article le 25 juin 2014


Ce RFC est entièrement consacré à la gestion de réseaux. Quels sont les outils existants dans les réseaux TCP/IP, notamment l'Internet ? Ce RFC est destiné aux opérateurs réseau, aux fournisseurs d'équipements et de logiciels réseau, et aux gens de la normalisation, pour s'assurer qu'ils ont une base d'information commune sur les outils existants.

La gestion de réseaux est ici désignée par le sigle OAM qui signifie Operations, Administration, and Maintenance. OAM est défini dans le RFC 6291. Les outils de l'OAM sont tous les dispositifs qui permettent de détecter un problème et de l'isoler, ou bien de mesurer les performances. (Les outils permettant de configurer les équipements réseaux ne sont pas traités ici.) Ce nouveau RFC couvre les outils utilisés dans des contextes très divers, d'IP à MPLS en passant par TRILL mais je ne vais parler que des outils IP, ceux que je connais.

Ce RFC décrit les outils, logiciels mettant en œuvre un protocole particulier. Une liste des protocoles normalisés par l'IETF pour l'OAM est dans le RFC 6632. Par exemple, OWAMP (RFC 4656) est un protocole, le programme distribué par Internet 2 est un outil mettant en œuvre ce protocole.

Tous les réseaux sont bien sûr gérés, et tous ont évidemment des dispositifs d'OAM, plus ou moins perfectionnés. On a donc :

  • O (pour Operations) : tout ce qui contribue à ce que le réseau reste « up & running » en détectant les problèmes (et en les résolvant) avant même que l'utilisateur ne s'en aperçoive.
  • A (pour Administration) : garder à jour la liste des ressources et surveiller leur utilisation.
  • M (pour Maintenance) : permettre les réparations et les évolutions (mise à jour du logiciel du routeur, par exemple).

Parfois, ces dispositifs d'OAM ont été ajoutés après, en utilisant (souvent de manière créative) les fonctions disponibles. De nos jours, on tend à prévoir l'OAM dès le début, comme ce fut le cas pour l'ATM.

Notre RFC commence (section 2) par des rappels de concept et de terminologie (outre le RFC 6291, déjà cité, le RFC 7087 définit les termes spécifiques à MPLS). D'abord, données vs. contrôle : on distingue souvent dans un équipement réseau le sous-système des données (data plane ou user plane) et le sous-système de contrôle (control plane). Le premier désigne toutes les fonctions qui contribuent à transmettre les paquets (et donc les données) à l'équipement suivant. Le second, le sous-système de contrôle, comprend les fonctions qui permettent d'établir dynamiquement les informations dont le sous-système des données va avoir besoin. Par exemple, dans un routeur, le sous-système des données est composé des fonctions qui font passer le paquet d'une interface d'entrée à une interface de sortie (rôle de forwarding), alors que le sous-système de contrôle (rôle de routing) comprend notamment les fonctions de calcul de la table de routage (les mises en œuvre d'OSPF, de BGP, etc), table de routage qu'utilisera le sous-système des données lors de la transmission. Si le routeur est une machine Unix, le sous-système de données est mis en œuvre dans le noyau, alors que celui de contrôle l'est par un démon séparé, genre Quagga ou BIRD. La distinction entre sous-systèmes de contrôle et de données n'est pas seulement conceptuelle, ni limitée au logiciel. Dans un routeur Juniper ou Cisco moyen ou haut de gamme, c'est même du matériel différent (ASIC pour les données, CPU généraliste pour le contrôle). L'OAM, tel qu'utilisé ici, mesure et teste le sous-système de données, mais il peut utiliser des informations fournies par le sous-système de contrôle, et être piloté par lui. (On voit parfois, par exemple dans le RFC 6123, un troisième sous-système, le sous-système de gestion, le management plane. De toute façon, la différence entre ces sous-systèmes n'est pas forcément claire et nette dans tous les cas.)

Encore un peu de terminologie : les outils peuvent être « à la demande » ou bien « proactifs ». Les premiers sont déclenchés lorsqu'il y a un problème (c'est l'administrateur réseaux à qui on dit « le serveur ne marche pas » et qui lance ping tout de suite), les seconds tournent en permanence, par exemple pour détecter et signaler les pannes.

Quelle sont les fonctions précises d'un logiciel d'OAM ? Notre RFC cite le test de la connectivité, la découverte du chemin, la localisation d'un problème, et des mesures liées aux performances comme la mesure du taux de perte de paquets, ou comme la mesure des délais d'acheminement.

On entend parfois parler de « tests de continuité » et de « tests de connectivité ». Ces termes viennent de MPLS (RFC 5860) et désignent, dans le premier cas, un test que les paquets peuvent passer et, dans le second, que deux systèmes sont effectivement connectés, et par le chemin attendu (IP, étant sans connexion, n'a guère besoin de ces tests de connectivité).

En parlant de connexion, le monde TCP/IP comprend des protocoles avec connexion et des protocoles sans. L'OAM concerne ces deux groupes et les outils présentés dans ce RFC couvrent les deux. Un test utilisant un protocole sans connexion (ping est l'exemple archétypal) peut emprunter un autre chemin, d'autres ressources (et donc donner un autre résultat), qu'une utilisation réelle du réseau. Au contraire, en testant un protocole avec connexion (TCP, par exemple), on utilise les mêmes ressources que les vraies données. Notez aussi que des protocoles sans connexion peuvent être testés par des protocoles avec connexion, le RFC donnant l'exemple d'un test d'IP fait avec BFD (RFC 5880).

Enfin, dernier point de terminologie, les mots utilisés pour les problèmes. Il n'existe pas une norme unique et acceptée pour ces mots. Suivant la norme ITU-T G.806, notre RFC fait une différence entre défaillance (fault), qui est l'incapacité à effectuer une tâche, comme de livrer un paquet, interruption (defect), qui est un arrêt temporaire d'un service et panne (failure). Cette dernière, au contraire de l'interruption, n'est pas un accident ponctuel et elle peut durer longtemps.

Bien, après tous ces préliminaires, les outils eux-mêmes, présentés en section 4 du RFC. À tout seigneur, tout honneur, on va évidemment commence par l'outil emblématique de l'OAM, ping. Il envoie un paquet ICMP de type « demande d'écho » et la réception d'un paquet ICMP de réponse indiquera que la connectivité est complète. Il donnera également quelques indicateurs de performance comme le RTT, affiché après time= :

% ping -c 3 www.ietf.org
PING www.ietf.org (4.31.198.44) 56(84) bytes of data.
64 bytes from mail.ietf.org (4.31.198.44): icmp_req=1 ttl=44 time=227 ms
64 bytes from mail.ietf.org (4.31.198.44): icmp_req=2 ttl=44 time=222 ms
64 bytes from mail.ietf.org (4.31.198.44): icmp_req=3 ttl=44 time=223 ms

--- www.ietf.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 222.689/224.685/227.533/2.067 ms

Certaines versions de ping peuvent faire des tests avec UDP plutôt qu'ICMP. ping donne un point de vue unilatéral, celui du côté qui initie la connexion. Si on veut le point de vue du pair, il faut que celui-ci fasse un test de son côté (par exemple, s'il y a un pare-feu à état entre les deux machines, un des tests peut échouer même si l'autre réussit). Malheureusement, il arrive que ces paquets ICMP soient filtrés (par exemple, suite à l'incompétence de l'administrateur qui croit que l'attaque mal nommée ping of death a un rapport avec ping alors qu'elle n'en a pas).

Après ping, l'outil d'OAM le plus connu et le plus utilisé est sans doute traceroute. Comme ping, il n'y a pas de texte sacré de référence le décrivant. À l'époque, on codait d'abord, on documentait ensuite (parfois). Les textes les plus canoniques sur traceroute semblent être les RFC 1470 et RFC 2151.

traceroute sert à découvrir le chemin pris par les paquets entre l'initiateur de la requête et une cible. Il envoie un paquet UDP à destination du port 33434 en mettant dans l'en-tête IP un TTL inhabituel, de 1. Vu avec tcpdump, cela donne (notez le ttl 1) :

22:10:20.369307 IP (tos 0x0, ttl 1, id 19164, offset 0, flags [none], proto UDP (17), length 60)
    192.168.2.1.44024 > 213.154.224.1.33434: UDP, length 32

Le premier routeur rencontré va donc considérer ce paquet comme trop ancien, le jeter, et envoyer un paquet ICMP de type Time exceeded à la source, qui aura ainsi l'adresse IP du premier routeur :

22:17:46.359084 IP (tos 0xc0, ttl 64, id 64893, offset 0, flags [none], proto ICMP (1), length 88)
    192.168.2.254 > 192.168.2.1: ICMP time exceeded in-transit, length 68
	IP (tos 0x0, ttl 1, id 19239, offset 0, flags [none], proto UDP (17), length 60)
    192.168.2.1.34315 > 213.154.224.1.33434: UDP, length 32

Ensuite, traceroute itère : il incrémente le numéro de port et le TTL et trouve ainsi le deuxième routeur. Le jeu s'arrête lorsque traceroute reçoit un paquet ICMP Port unreachable lorsque le paquet UDP atteint sa cible et que celle-ci, n'ayant pas de service sur ce port, répondra négativement :

22:19:20.648790 IP (tos 0x0, ttl 53, id 11453, offset 0, flags [none], proto ICMP (1), length 56)
    213.136.31.102 > 192.168.2.1: ICMP 213.154.224.1 udp port 33445 unreachable, length 36
	IP (tos 0x0, ttl 1, id 19325, offset 0, flags [none], proto UDP (17), length 60)
    192.168.2.1.57471 > 213.154.224.1.33445: UDP, length 32

Utilisant toutes ces informations, traceroute peut alors afficher le chemin :

% traceroute -q 1 www.nlnetlabs.nl
traceroute to www.nlnetlabs.nl (213.154.224.1), 30 hops max, 60 byte packets
 1  freebox (192.168.2.254)  13.646 ms
 2  88.189.152.254 (88.189.152.254)  37.136 ms
 3  78.254.1.62 (78.254.1.62)  37.133 ms
 4  rke75-1-v900.intf.nra.proxad.net (78.254.255.42)  46.845 ms
 5  cev75-1-v902.intf.nra.proxad.net (78.254.255.46)  39.030 ms
 6  p16-6k-1-po12.intf.nra.proxad.net (78.254.255.50)  43.658 ms
 7  bzn-crs16-1-be1024.intf.routers.proxad.net (212.27.56.149)  43.662 ms
 8  bzn-crs16-1-be1106.intf.routers.proxad.net (212.27.59.101)  43.637 ms
 9  londres-6k-1-po101.intf.routers.proxad.net (212.27.51.186)  55.973 ms
10  *
11  amsix-501.xe-0-0-0.jun1.bit-1.network.bit.nl (195.69.144.200)  60.693 ms
12  nlnetlabs-bit-gw.nlnetlabs.nl (213.136.31.102)  62.287 ms

(On note que le routeur n° 10 a refusé de répondre, ce qui arrive, ou que sa réponse s'est perdue, ce qui arrive aussi.)

Sur une machine Unix d'aujourd'hui, il existe souvent plusieurs mises en œuvre différentes de traceroute. traceroute est une idée, pas un programme unique. Par exemple, Paris traceroute fait varier l'en-tête IP pour essayer de découvrir plusieurs chemins lorsqu'il y a de l'ECMP. Des traceroutes ont des options pour utiliser ICMP et pas UDP (c'est le cas des sondes Atlas). Il existe des extensions à ICMP pour rendre traceroute plus utile, comme celles du RFC 4950 ou RFC 5837.

Attention aux limites de traceroute : il ne montre que le chemin aller. Le routage sur l'Internet pouvant être asymétrique, rien ne dit que le chemin de retour sera le même.

Après, le RFC passe à des outils moins connus du grand public. D'abord, les outils BFD. Normalisé dans le RFC 5880, BFD permet de tester la connectivité dans le contexte d'IP (RFC 5881) mais aussi de MPLS (RFC 5884) et de bien d'autres. Il fonctionne en mode connecté : les deux machines établissent une session BFD. Ensuite, elles échangent des paquets BFD, soit périodiquement, soit à la demande. La bonne arrivée de ces paquets indique que la connexion avec le pair fonctionne. Il existe aussi un mode où BFD envoie des paquets « demande d'écho » et attend une réponse.

Il existe ensuite plusieurs outils d'OAM pour le monde MPLS, le plus important étant LSP-Ping, décrit dans le RFC 4379. S'il assure des fonctions analogues à ping, comme son nom l'indique, il en fait aussi qui sont équivalentes à traceroute. Répondre à une demande d'écho est moins trivial en MPLS qu'en IP. Par exemple, un chemin (un LSP, Label Switched Path) peut n'être établi que dans une seule direction, rendant impossible de répondre en MPLS à un LSP-Ping.

Les autres outils MPLS sont décrits en détail dans les sections 4.4 et 4.5 de notre RFC. Sinon, la problématique générale de l'OAM en environnement MPLS est dans les RFC 4377 et RFC 4378. (L'OAM de MPLS a d'ailleurs suscité un affrontement entre l'IETF et l'UIT, le point de vue de l'IETF étant exposé dans le RFC 5704.)

ping sur un réseau IP a plusieurs limites : il mesure un aller-retour (alors que les chemins peuvent être différents, avec des caractéristiques très différentes), et il n'est pas défini avec une grande précision donc la sémantique du RTT, par exemple, n'est pas rigoureuse. L'IETF, via son groupe de travail IPPM, a deux protocoles qui traitent ces limites, OWAMP et TWAMP. Outre des définitions rigoureuses de métriques comme le délai d'acheminement aller-simple (RFC 7679), ou comme la connectivité (RFC 2678), IPPM a produit ces deux protocoles qui établissent une session de contrôle entre deux points, sur TCP, avant de lancer une mesure précise avec UDP. OWAMP (RFC 4656) mesure un aller-simple alors que TWAMP (RFC 5357) mesure un aller-retour (comme ping).

À noter que, pour mesurer les performances, il existe bien d'autres outils comme les outils OAM d'Ethernet.

Enfin, la section 4 se termine par une section sur TRILL (RFC 6325). Trop récent, ce système n'a pas encore beaucoup d'outils OAM. Il existe un cahier des charges pour ces outils, le RFC 6905, qui demande des outils pour tester la connectivité, découvrir le chemin suivant et mesurer des indicateurs comme le temps d'acheminement d'un paquet.

La section 5 du RFC résume tous les outils décrits, sous forme d'un tableau donnant le nom des outils, un résumé de leur fonctionnement, et le protocole auquel ils s'appliquent (IP, MPLS, TRILL, etc). Pratique pour les lecteurs pressés.

Il reste enfin la classique section de sécurité, la section 6. Un système d'OAM soulève évidemment des enjeux de sécurité. Par exemple, un attaquant qui contrôle l'OAM pourrait créer l'illusion de pannes non-existantes, forçant les équipes du réseau à perdre du temps. Ou il pourrait empêcher la détection de pannes réelles, ce qui aggraverait le déni de service.

Certains des outils d'OAM présentés dans ce RFC ont des fonctions de sécurité, empêchant par exemple la modification des données par un tiers. BFD a un mécanisme d'authentification. OWAMP et TWAMP peuvent authentifier (via un HMAC) et/ou chiffrer leurs communications (en AES). Ceci dit, la confidentialité n'est pas en général considérée comme un problème pour l'OAM, seules l'authentification et l'intégrité le sont. D'autres outils n'ont aucune sécurité (traceroute peut facilement être trompé, comme l'avait montré The Pirate Bay).

Les outils d'OAM peuvent aussi être utilisés pour la reconnaissance : par exemple, l'option -g de fping ou la possibilité d'indiquer un préfixe IP (et pas juste une adresse) à nmap, permettent de découvrir les machines existant sur le réseau.

L'annexe A termine le RFC en énumérant une (longue) liste de documents de normalisation sur l'OAM, y compris des documents non-IETF.


Téléchargez le RFC 7276


L'article seul

RFC 7269: NAT64 Deployment Options and Experience

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : G. Chen, Z. Cao (China Mobile), C. Xie (China Telecom), D. Binet (France Telecom-Orange)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 20 juin 2014


L'épuisement des adresses IPv4 étant allé plus vite que le déploiement d'IPv6 (qui est freiné par la passivité de nombreux acteurs), il y a de plus en plus souvent le problème de connecter des réseaux modernes, entièrement en IPv6, à des machines anciennes restées en IPv4. La solution de l'IETF à ce problème est le déploiement de NAT64, normalisé dans le RFC 6144. Ce nouveau RFC documente l'expérience concrète de trois gros opérateurs avec NAT64. Qu'est-ce qui a marché, qu'est-ce qui a raté ?

Ces réseaux entièrement IPv6 ont l'avantage de ne pas avoir de problème de manque d'adresses IP (même les préfixes du RFC 1918 peuvent être insuffisants pour un grand réseau) et de permettre d'utiliser un plan d'adressage propre dès le début (pas de contorsions pour faire durer les adresses) et une architecture unique (un seul protocole à gérer). Pour les réseaux mobiles, par exemple, cela signifie un seul contexte PDP, ce qui simplifie les choses. Mais, comme vu plus haut, leur inconvénient est qu'ils ne peuvent pas accéder aux services qui restent archaïquement en IPv4 seul comme Twitter ou impots.gouv.fr. Et, même si les professionnels sérieux ont compris depuis longtemps l'importance de migrer vers IPv6, les résistances des plus attardés vont sans doute durer longtemps et on peut penser que des réseaux uniquement IPv4 seront encore en fonctionnement pendant de longues années. Au lieu du plan de transition envisagé au début (« tout le monde en IPv4 » -> « double-pile - IPv4 et IPv6 - déployée progressivement » -> « tout le monde en IPv6 »), il faut maintenant travailler dans le cadre d'un nouveau plan, « tout le monde en IPv4 » -> « certains réseaux en v4 seul et certains en v6 seul » -> « tout le monde en IPv6 ». L'étape intermédiaire a été décrite dans les RFC 6145 et RFC 6146 et son composant le plus connu est nommé NAT64. NAT64 effectue une traduction d'adresses de IPv6 vers IPv4 en sortie du réseau moderne vers le réseau archaïque et l'inverse lorsque la réponse arrive.

NAT64 a donc une partie des inconvénients du NAT IPv4 traditionnel (NAT44), comme le montre le compte-rendu d'expérience du RFC 6586 mais il parait incontournable, sauf si le déploiement d'IPv6 s'accélérait subitement dans l'Internet, ce qu'on ne voit pas venir.

30 % des opérateurs, selon un sondage signalé dans le RFC 6036 prévoient de déployer NAT64 ou un système équivalent. NAT64 est également systématiquement présent lors des réunions des organismes de normalisation ou de gestion des ressources réseau, comme l'IETF ou le RIPE. À chaque réunion, un des réseaux WiFi est « IPv6 seulement » et bénéficie d'une passerelle NAT64 vers l'extérieur. De nombreux experts peuvent ainsi tester en vrai les technologies modernes. Bref, NAT64 est désormais une technique importante et il est donc nécessaire d'étudier ses conséquences pratiques. C'est le rôle de ce nouveau RFC, qui ne décrit pas un nouveau protocole mais offre simplement un retour d'expérience.

À noter que NAT64 peut être déployé en deux endroits :

  • Côté FAI, ce qu'on appelle le NAT64-CGN (pour Carrier-Grade NAT), sous forme d'un gros traducteur NAT dans le réseau du FAI,
  • Ou bien côté fournisseur de services/contenus, ce qu'on appelle le NAT64-FE (pour Front End), sous forme d'un traducteur NAT dans le data center, devant les serveurs.

Le premier cas est celui du FAI tout en IPv6 mais qui veut permettre à ses clients d'accéder à des services IPv4. Le second est celui du fournisseur de services ou de contenus dont l'infrastructure est malheureusement entièrement ou partiellement en IPv4 mais qui veut fournir un accès IPv6, en ne gérant qu'un traducteur, au lieu de mettre à jour tous ses systèmes. (Le RFC ne discute pas la question de savoir si c'est une idée intelligente ou pas...)

À noter que le cas d'un NAT64 chez l'utilisateur (le célèbre M. Michu), dans son CPE, n'est pas mentionné. Un NAT64 dans le CPE imposerait un réseau du FAI qui soit en IPv4 jusqu'au client, justement ce qu'on voudrait éviter. Le RFC recommande plutôt de mettre les traducteurs NAT64 près de la sortie du FAI, de façon à permettre à celui-ci de conserver un réseau propre, entièrement IPv6 (section 3.1.3). Certes, cela va concentrer une bonne partie du trafic dans ces traducteurs mais NAT64 est fondé sur l'idée que la proportion de trafic IPv4 va diminuer avec le temps : les traducteurs n'auront pas besoin de grossir. Aujourd'hui, 43 des cent plus gros sites Web (selon Alexa) ont déjà un AAAA et court-circuitent donc complètement le NAT64.

Autre problème avec la centralisation, le risque de SPOF. Si le CPE de M. Michu plante, cela n'affecte que M. Michu. Si un gros traducteur NAT64, gérant des milliers de clients, plante, cela va faire mal. Il faut donc soigner la disponibilité (voir section 4).

Centraliser dans un petit nombre de traducteurs près de la sortie évite également d'avoir plusieurs équipements NAT64, avec les problèmes de traçabilité que cela poserait, par exemple s'ils ont des formats de journaux différents.

NAT64 nécessite un résolveur DNS spécial, utilisant DNS64 (RFC 6147). En effet, les clients, n'ayant qu'IPv6, ne demanderont que des enregistrements AAAA (adresses IPv6) dans le DNS. Le résolveur DNS64 doit donc en synthétiser si le site original (par exemple twitter.com) n'en a pas. Dans certains cas, par exemple une page Web où les liens contiennent des adresses IPv4 littérales (comme <a href="http://192.0.2.80/">), la solution 464xlat du RFC 6877 permet de se passer de DNS64. Mais, dans la plupart des déploiements NAT64, DNS64 sera indispensable.

NAT64 va probablement coexister avec NAT44 (le NAT majoritaire aujourd'hui), les réseaux locaux chez l'utilisateur gardant un certain nombre de machines IPv4. Si le RFC 6724 donne par défaut la priorité à IPv6, quelque soit le type de connectivité IPv6, les algorithmes comme celui des globes oculaires heureux (RFC 6555) peuvent mener à préférer IPv6 ou IPv4 et même à en changer d'un moment à l'autre, en fonction de leurs performances respectives. Ces changements ne seront pas forcément bons pour l'expérience utilisateur.

Pour le NAT64-FE (juste en face des serveurs), le RFC 6883 donnait quelques indications, qui peuvent s'appliquer à NAT64. Ici, DNS64 n'est pas forcément nécessaire, les adresses IPv6 servant à adresser les serveurs sont en nombre limité et peuvent être mises dans le DNS normal.

La section 4 de notre RFC revient sur l'exigence de haute disponibilité, essentielle si on veut que le passage de IPv4+IPv6 à IPv6+NAT64 ne diminue pas la fiabilité du service. Je me souviens d'une réunion RIPE où il n'y avait qu'un seul résolveur DNS64 et, un matin, il avait décidé de faire grève. DNS64 étant indispensable à NAT64, les clients étaient fort marris. Mais la redondance des résolveurs DNS est un problème connu, et relativement simple puisqu'ils n'ont pas d'état. Le RFC se focalise surtout sur la haute disponibilité des traducteurs NAT64 car eux peuvent avoir un état (comme les traducteurs NAT44 d'aujourd'hui). Il y a trois types de haute disponibilité : le remplaçant froid, qui est un traducteur NAT64 inactif en temps normal, et qui ne se synchronise pas avec le traducteur actif. Il est typiquement activé manuellement quand le traducteur actif tombe en panne. Comme il n'a pas de copie de l'état (la table des sessions en cours, aussi nommée BIB pour Binding Information Base), toutes les connexions casseront et devront être réétablies. Le second type est le remplaçant tiède. Il ne synchronise pas les sessions mais il remplace automatiquement le traducteur NAT64 principal, par exemple grâce à VRRP (RFC 5798). Au cours des tests faits par les auteurs du RFC, il fallait une minute pour que VRRP bascule et que les trente millions de sessions de la BIB soient établies à nouveau. Enfin, il y a le remplaçant chaud, qui synchronise en permanence l'état des sessions. Cette fois, la bascule vers le remplaçant est indétectable par les clients. Pour s'apercevoir rapidement de la panne du traducteur principal, le test a utilisé BFD (RFC 5880) en combinaison avec VRRP. Cette fois, la bascule des trente millions de sessions n'a pris que trente-cinq millisecondes, soit une quasi-continuité de service. Évidemment, cela nécessite du logiciel plus complexe dans les traducteurs, surtout vu l'ampleur de la tâche : avec 200 000 utilisateurs, il faut créer et détruire environ 800 000 sessions par seconde ! Un lien à 10 Gb/s entre les traducteurs n'est pas de trop, pour transporter les données nécessaires pendant les pics de trafic.

Alors, remplaçant froid, tiède ou chaud ? Notre RFC ne tranche pas définitivement, disant que cela dépend des applications. (L'annexe A du RFC contient des tests spécifiques à certaines applications.) Environ 90 % du trafic pendant les tests était dû à HTTP. Ce protocole n'a pas besoin de continuité de service, chaque requête HTTP étant indépendante. Le traducteur chaud n'est donc pas indispensable si HTTP continue à dominer (au passage, c'est pour une raison analogue que la mobilité IP n'a jamais été massivement utilisée). En revanche, le streaming souffrirait davantage en cas de coupure des sessions. (Curieusement, le RFC cite aussi le pair-à-pair comme intolérant aux coupures de session, alors que les clients BitTorrent, par exemple, s'en tirent très bien et réétablissent automatiquement des sessions.)

Le trafic d'un traducteur NAT64-CGN peut être intense et, même en l'absence de pannes, il est raisonnable de prévoir plusieurs traducteurs, afin de répartir la charge. Attention, si on fait du NAT64 avec état (le plus courant), il faut s'assurer que les paquets d'une session donnée arrivent toujours au même traducteur. Une façon de distribuer les requêtes entre les traducteurs, pour le NAT64-CGN, est de demander au serveur DNS64 de synthétiser des préfixes différents selon le client, et d'envoyer les différents préfixes à différents traducteurs, en utilisant le classique routage IP. Pour le NAT64-FE, les techniques classiques des répartiteurs de charge (condensation de certains paramètres puis répartition en fonction du condensat) conviennent.

La section 5 du RFC se penche ensuite sur le problème de l'adresse IP source. À partir du moment où on fait du NAT (quel que soit le NAT utilisé), l'adresse IP source vue par le destinataire n'est pas celle de l'émetteur mais celle du traducteur NAT. Cela entraine tout un tas de problèmes. D'abord, la traçabilité. Un serveur voit un comportement illégal ou asocial (par exemple, pour un serveur HTTP, des requêtes identiques coûteuses répétées, pour réaliser une attaque par déni de service). Son administrateur note l'adresse IP du coupable. Qu'en fait-il ? Pour pouvoir remonter de cette adresse IP au client individuel, il faut garder les journaux du traducteur NAT (et aussi, le RFC l'oublie, que le serveur note l'heure exacte et le port, comme rappelé par le RFC 6302). Les auteurs du RFC ont tenté l'expérience avec 200 000 clients humains pendant 60 jours. Les informations sur les sessions étaient transmises par syslog (RFC 5424) à une station d'archivage. Avec toutes les informations conservées (heure, protocole de transport, adresse IPv6 source originelle - et son port, adresse IPv4 source traduite - et son port), soit 125 octets, les 72 000 sessions par seconde ont produit pas moins de 29 téra-octets de données. La seule activité de journalisation, pour faire plaisir au CSA, nécessite donc une infrastructure dédiée (machines, disques et liens) et coûteuse.

Le système pourrait toutefois être amélioré. Au lieu de noter le port pour chaque session, on pourrait allouer une plage de ports à chaque client et réduire ainsi le volume à journaliser (seule l'allocation de la plage serait notée ; ceci dit, cela compliquera sérieusement le logiciel de recherche, qui aura moins de données à fouiller mais davantage de calculs à faire). On peut même statiquement allouer des plages de port à chaque client, supprimant ainsi une grande partie de la journalisation. Mais attention, ces méthodes d'optimisation ont deux gros défauts : elles diminuent l'efficacité du multiplexage (certains client vont tomber à court de ports alors que d'autres en auront des inutilisés) et elle est contraire aux recommandations de sécurité du RFC 6056, qui prescrit des ports sources difficiles à deviner, pour compliquer la tâche d'un attaquant.

Autre problème lié à la traduction d'adresses, la géolocalisation. Un serveur qui géolocalise en se fondant sur l'adresse IP source trouvera la position du traducteur, pas celle de l'utilisateur. Parfois, cela peut être gênant. Le RFC 6967 cite quelques solutions possibles, mais aucune n'est parfaite : on peut par exemple se servir d'informations applicatives comme l'en-tête Forwarded: de HTTP (RFC 7239), ce qui ne marche évidemment qu'avec ce protocole.

La section 6 revient vers les problèmes de M. Michu, heureux utilisateur, sans le savoir, d'un traducteur NAT64. Quelle va être la qualité de son vécu d'utilisateur ? Ou, dit plus trivialement, est-ce que ça va marcher ou planter ? Certaines applications fonctionnent facilement et simplement à travers n'importe quel NAT, comme HTTP ou SSH. D'autres nécessitent un relais, une ALG. Les traducteurs NAT64 fournissent en général une ALG pour FTP (RFC 6384). Même pour les protocoles qui marchent « tout seuls » à travers NAT64, une ALG peut être utile pour la traçabilité, par exemple insérer des en-têtes Via: dans une requête HTTP ou Received: dans un message transmis en SMTP.

En testant des applications réelles, comme l'avait fait le RFC 6586, les auteurs de ce RFC ont trouvé que plusieurs continuent à planter, ce qui plaiderait pour l'ajout à NAT64 des fonctions 464xlat du RFC 6877. Ainsi, SIP n'a pas réussi à appeler depuis la machine IPv6 pure vers un softphone en IPv4 pur (les adresses IP sont transmises dans la signalisation, et ne sont pas traduites par NAT64). Il faut donc, comme recommandé par le RFC 6157, que les clients SIP utilisent ICE (RFC 8445), qui a l'avantage de traiter également le problème des pare-feux.

Pour IPsec, le bilan est également mitigé : comme prévu, AH n'a pas fonctionné (puisque son but est d'empêcher toute modification des en-têtes, donc des adresses IP source et destination), mais ESP non plus, les paquets du protocole de couche 4 50, le protocole d'ESP, n'étant pas traduits. Utiliser ESP sur UDP, comme décrit dans le RFC 3947, aurait probablement résolu ce problème.

Le tableau de la section 6.1 résume les applications testées et les résultats :

  • Web : pas de problème, sauf les rares cas où un URL inclut une adresse IPv4 littérale,
  • Messagerie instantanée : la plupart des services testés ont échoué (mon expérience personnelle est que XMPP et IRC fonctionnent très bien à travers NAT64, donc je suppose qu'il s'agissait de protocoles fermés et de logiciels privateurs),
  • Jeux : les jeux non-Web ont presque tous échoué,
  • SIP : échec,
  • IPsec : échec (vor ci-dessus),
  • Partage de fichiers en pair-à-pair : échec, par exemple avec eMule,
  • Courrier électronique : pas de problème,
  • FTP : pas de problème.

L'annexe A décrit en outre les délais acceptables pour ces applications, lorsque le traducteur NAT64 tombe en panne et est remplacé. Les jeux interactifs, par exemple, ne supportent pas les longues interruptions.

Comme un traducteur NAT64 gène certains services, il serait utile de fournir aux clients un moyen de contrôler, par exemple, l'ouverture de ports entrants, les ports sortants affectés, etc. Il existe un protocole standard pour cela, PCP (RFC 6887), qui serait un ajout très utile aux traducteurs NAT64 mais, pour l'instant, aucun n'en dispose encore.

La section 7 du RFC se penche ensuite sur les problèmes de MTU. Certes, il n'y a pas de tunnel avec NAT64, mais il peut y avoir des liens IPv4 dont la MTU est inférieure à 1 280 octets, le minimum des liens IPv6. Il n'y a pas de moyen simple, en NAT64-CGN, de gérer ce problème.

Bon, et la sécurité ? La section 9 étudie la question. NAT64 fait du suivi des sessions TCP et est donc normalement à l'abri de pas mal de types d'attaques par déni de service. On peut renforcer sa sécurité en déployant RPF (RFC 3704), pour empêcher les usurpations d'adresses IPv6.

Pour NAT64-FE, une attaque possible serait de remplir la table des sessions en commençant plein de sessions vers les serveurs situés derrière le traducteur NAT64-FE. Celui-ci doit donc avoir un mécanisme de limitation de trafic.

Ah, et puis il faut rappeler qu'un résolveur DNS64, étant un résolveur menteur (pour la bonne cause, certes, mais menteur tout de même), s'entend mal avec DNSSEC. Le RFC 6147 contient de nombreuses notes à ce sujet.

Ce RFC est issu d'un processus qui a commencé par un exposé à l'IETF. Il y a eu quelques objections de principe (un certain nombre de participants à l'IETF estiment que toute traduction est une erreur, NAT64 comme les autres).


Téléchargez le RFC 7269


L'article seul

RFC 7265: jCal: The JSON format for iCalendar

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : P. Kewisch (Mozilla), C. Daboo (Apple), M. Douglass (RPI)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jcardcal
Première rédaction de cet article le 1 juin 2014


Le format iCalendar permet de décrire de manière standard, compréhensible par tous les logiciels de gestion d'agenda, les événements, rendez-vous, tâches à accomplir, etc. Très connu et largement déployé, il est présent à de nombreux endroits. iCalendar est à la fois un modèle de données (décrivant ce qu'on stocke) et une syntaxe particulière. Des syntaxes alternatives sont possibles et ce nouveau RFC en propose une, fondée sur JSON. Elle se nomme donc jCal.

Il y avait déjà une autre syntaxe alternative, fondée sur XML, dans le RFC 6321. Celle-ci s'inscrit dans la mode JSON actuelle (RFC 8259) et promet de rendre le vieux format iCalendar plus accessible pour les applications Web, notamment celles écrites en JavaScript. Notez qu'il existe un autre format en JSON, le jsCalendar du RFC 8984, qui repose sur un modèle de données différent.

iCalendar est normalisé dans le RFC 5545. Il a plusieurs points techniques en commun avec le format vCard de description de « cartes de visite » virtuelles, normalisé dans le RFC 6350 et c'est pour cela que le même groupe de travail à l'IETF a normalisé la version JSON de iCalendar (dans ce RFC 7265) et la version JSON de vCard (RFC 7095). Cette dernière, jCard, a essuyé les plâtres et jCal lui doit beaucoup et lui ressemble énormément.

La section 1 du RFC résume le cahier des charges du projet jCal (identique à celui du RFC 6321 pour xCal) :

  • Possibilité de conversion iCalendar -> jCal et retour, sans perte sémantique,
  • Pas d'impératif de préservation de l'ordre des éléments,
  • Maintien du modèle de données de iCalendar,
  • Les futures extensions de iCalendar devront pouvoir être intégrées naturellement, sans nécessiter un nouveau RFC jCal.

La section 3 est le gros morceau du RFC, indiquant comment convertir les iCalendar actuels en jCal. iCalendar a quelques particularités syntaxiques. Par exemple, les lignes trop longues peuvent être repliées, et certaines valeurs ont besoin d'échappement. Pour passer à jCal, on déplie toutes les lignes et on retire les échappements. Puis on applique les échappements de JSON.

Un document iCalendar est une suite d'objets iCalendar (a iCalendar stream) qu'on transforme en un tableau JSON, dont chaque élément est un objet iCalendar. Ce simple objet iCalendar, qui définit un événement Planning meeting :

BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Example Inc.//Example Calendar//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:20080205T191224Z
DTSTART:20081006
SUMMARY:Planning meeting
UID:4088E990AD89CB3DBB484909
END:VEVENT
END:VCALENDAR

va être traduit ainsi en jCal (exemple tiré de l'annexe B du RFC) :

["vcalendar",
  [
    ["calscale", {}, "text", "GREGORIAN"],
    ["prodid", {}, "text", "-//Example Inc.//Example Calendar//EN"],
    ["version", {}, "text", "2.0"]
  ],
  [
    ["vevent",
      [
        ["dtstamp", {}, "date-time", "2008-02-05T19:12:24Z"],
        ["dtstart", {}, "date", "2008-10-06"],
        ["summary", {}, "text", "Planning meeting"],
        ["uid", {}, "text", "4088E990AD89CB3DBB484909"]
      ],
      []
    ]
  ]
]

La section 4 explique, elle, les détails de l'opération inverse, convertir du jCal en iCalendar.

Ce nouveau format jCal a désormais son propre type MIME, application/calendar+json (et pas jcal+json, attention).

Parmi les mises en œuvre de jCal, on note :


Téléchargez le RFC 7265


L'article seul

RFC 7258: Pervasive Monitoring Is an Attack

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : S. Farrell (Trinity College Dublin), H. Tschofenig (ARM)
Première rédaction de cet article le 13 mai 2014


Assez des RFC qui décrivent un protocole réseau, jusque dans les plus infimes détails, au bit près ? Et des RFC bureaucratiques sur le fonctionnement de l'IETF et de tout son zoo de groupes et de comités ? Voici un RFC 100 % politique, et un excellent, en plus. Ce RFC 7258 résume la politique de l'IETF vis-à-vis de l'espionnage de masse que pratique, entre autres, la NSA : cet espionnage de masse est, techniquement, une attaque, et il est justifié de faire tout ce qu'on peut techniquement pour combattre cette attaque.

Cette affirmation n'allait pas de soi. Rappelez-vous qu'un des mécanismes utilisés par la NSA (et révélé par le héros Snowden) pour faciliter l'espionnage est justement d'affaiblir les systèmes de sécurité, au nom du « il faut bien que nous, qui sommes les gentils, puissions écouter les plans des méchants pédonazis ». (C'est notamment le programme BULLRUN.) Après quelques discussions, l'IETF affirme haut et fort que cet argument ne tient pas : si on affaiblit la sécurité du réseau pour faciliter les écoutes légales, on l'affaiblit face à tous les espions, qu'on les trouve légitimes ou pas.

Avant de faire face à une attaque, il faut la définir. Notre RFC considère (section 1) que l'espionnage de masse (PM pour Pervasive Monitoring) est une attaque d'un nouveau genre. Ce n'est plus simplement le lycéen dans son garage qui écoute un réseau Wi-Fi proche et mal protégé. L'espionnage de masse n'est pas une nouveauté technique (les révélations de Snowden ne contiennent aucune surprise technique, aucune technique ultra-avancée, genre X-Files) mais se distingue des attaques précédentes par son caractère indiscriminé (on écoute tout le monde, innocent ou coupable, avant même tout soupçon), et sa simple taille (la STASI, avec les moyens techniques de l'époque, devait choisir qui elle écoutait ; la NSA peut, grâce aux méthodes de traitement du big data, écouter tout le monde).

L'espionnage de masse est défini comme l'écoute à très grande échelle des communications sur le réseau (qu'on se limite aux métadonnées ou pas), en utilisant des mécanismes passifs (l'écoutant traditionnel des analyses de risque), ou actifs (le programme Tailored Access Operations avec son QUANTUM et son FOXACID).

L'IETF a considéré depuis le début que l'espionnage massif était une attaque contre la vie privée. La question a fait l'objet de beaucoup de débats à la réunion IETF de Vancouver en novembre 2013, débats qui ont donné lieu à plein de bonnes résolutions (cf. les documents de la session plénière). Pour les résumer : l'IETF doit modifier ses protocoles réseau et concevoir les futurs protocoles de manière à rendre l'espionnage plus difficile. Le rendre impossible est sans doute irréaliste (et, certains le pensent, non souhaitable, car ils estiment que la surveillance ciblée, par exemple d'un suspect par la police, doit rester possible). L'idée est donc plutôt de rendre la surveillance de masse si difficile, et donc si coûteuse, que les organisations qui écoutent devront se limiter à une écoute ciblée sur les seules personnes sur lesquels pèsent des soupçons sérieux. « Don't give them anything for free. »

Le mot « attaque » est utilisé par l'IETF dans un sens purement technique (cf. RFC 4949 pour de la terminologie) : il s'agit d'une action délibérée par un tiers pour remettre en cause les attentes des deux parties qui communiquent (ici, leur attente que la communication soit privée), et il n'implique rien quant à la légitimité ou la légalité de telles attaques. Une attaque peut donc être légale, elle pose néanmoins exactement les mêmes problèmes techniques, et nécessite les mêmes solutions. Il serait ridicule de croire qu'on pourrait concevoir des systèmes de sécurité qui empêchent les « méchants » d'écouter mais autoriseraient les « gentils ». Quelle que soit l'opinion qu'on a sur ces « gentils », il est important de garder en tête qu'on ne peut pas se protéger contre les « méchants » sans bloquer ou gêner aussi les écoutes des « gentils ». Toute l'approche de l'IETF est techniquement neutre, dans le sens où on ne se préoccupe pas des motivations des espions : ceux-ci peuvent être une puissante agence gouvernementale, une entreprise commerciale qui veut récolter de l'information sur ses clients (ce qui peut être légal dans certains pays), un gang de délinquants dans leur sous-sol, ils peuvent agir pour le fric, l'idéologie, le goût du pouvoir ou n'importe quelle autre raison : c'est le même problème technique et les solutions seront les mêmes.

Après ces préalables, la section 2 du RFC décrit la position de l'IETF : on va travailler pour limiter l'espionnage de masse. On l'a vu, le rendre complètement impossible est sans doute peu réaliste. L'idée, suivant l'exposé de Schneier à la réunion de Vancouver, est d'augmenter les coûts pour l'attaquant, le forçant à mieux cibler ses opérations, et/ou exposant de l'espionnage qui serait resté caché autrement.

Les protocoles IETF avaient déjà souvent des mécanismes permettant de protéger la vie privée, typiquement du chiffrement afin d'empêcher un tiers d'accéder aux données échangées. Ces mécanismes sont recommandés par le RFC 3552. Mais ils ne prennent pas en compte le changement de catégorie que représente l'espionnage de masse. Le chiffrement, en général, ne protège pas les métadonnées, il ne tient pas compte des risques d'analyse de trafic, et il ne protège pas si les extrémités de la communication trahissent (cas du programme PRISM), ce qui nécessiterait une minimisation des données, pas uniquement leur chiffrement. Il est donc nécessaire d'adapter les normes de la famille TCP/IP, suivant la prise de conscience qui a suivi les révélations d'Edward Snowden.

En pratique, notre RFC demande aux auteurs de protocoles de prendre en considération le risque d'espionnage massif. Cela n'implique pas forcément une section « Pervasive Monitoring Considerations » dans leur RFC (comme il existe une « Security Considerations » obligatoire). Mais cela veut dire que les auteurs doivent regarder la question et être prêt à répondre aux questions à ce sujet. (Ce point était l'un des plus contestés lors de la création de ce RFC : certaines versions étaient plus directives, imposant des contraintes moins vagues.) En matière de lutte contre l'espionnage massif, comme souvent en sécurité, il vaut mieux prévoir les protections dès qu'on conçoit l'architecture, les mettre après est souvent très complexe.

À propos de complexité, une des difficultés de la lutte contre l'espionnage massif est qu'on a toujours besoin de gérer ses réseaux et que certaines activités de gestion sont proches de l'espionnage (surveiller les caractéristiques du trafic à partir de NetFlow, par exemple, ou bien utiliser tcpdump pour déboguer une application). Il serait dommage que les mesures techniques de protection de la vie privée bloquent ces pratiques. En fait, il y a même des mesures de sécurité qui reposent sur la publication, comme la Certificate Transparency du RFC 9162 (ou comme, mais le RFC ne le cite pas, Bitcoin). Il y a donc là un difficile compromis à négocier.

Enfin, la section 2 du RFC rappelle que l'IETF a des pouvoirs limités : c'est une SDO, elle écrit des normes, elle ne fait pas les programmes qui mettent en œuvre ces normes, encore moins les pratiques de déploiement et de sécurité. (Sans même mentionner les activités politiques et juridiques, qui sont encore plus loin de l'IETF.) Or, la sécurité (vie privée ou autre) dépend bien plus des programmes et des pratiques que des normes techniques.

La section 3 du RFC résume ce qui a déjà été fait à l'IETF, et le processus suivi : les RFC 1984 et RFC 2804 étaient déjà des déclarations technico-politiques sur la sécurité, et avaient été faits en commun entre l'IAB et l'IESG. L'IETF ayant changé ses règles bureaucratiques internes depuis, ce RFC 7258 est publié par l'IETF, sans l'IAB. C'était également le cas du RFC le plus complet sur la vie privée, l'excellent RFC 6973, dont la lecture est très recommandée.


Téléchargez le RFC 7258


L'article seul

RFC 7254: A Uniform Resource Name Namespace for the Global System for Mobile communications Association (GSMA) and the International Mobile station Equipment Identity (IMEI)

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : M. Montemurro, A. Allen (Blackberry), D. McDonald (Eircom), P. Gosden (GSM Association)
Pour information
Première rédaction de cet article le 22 mai 2014


Ce RFC normalise un nouvel espace de nommage dans la famille des URN. Cet espace sera géré par l'association des fabriquants de matériel GSM, GSMA. Il permettra notamment d'écrire les IMEI, ces identifiants des téléphones mobiles, sous forme d'un URN, par exemple urn:gsma:imei:35465101-163629-9.

L'utilité de ces URN ne s'arrêtera pas au GSM puisque les mêmes identificateurs sont utilisés pour UMTS ou la 3G. Outre l'IMEI (identifié par la chaîne de caractères imei), ils pourront dans le futur exprimer d'autres identificateurs. Le mécanisme pour définir des espaces de noms dans les URN est spécifié dans le RFC 8141. Un URN est un URI qui commence par urn: suivi d'un espace de noms (ou NID pour Namespace IDentifier), ici gsma. Donc, le début des URN de ce RFC sera toujours urn:gsma:.

Ensuite, l'IMEI. Ce numéro de série unique à chaque téléphone figure en général sur l'appareil, ou son emballage, ou bien peut être lu via le logiciel du téléphone. Ici, sous la batterie d'un téléphone imei-openmoko.jpg

L'usage le plus connu de l'IMEI est en cas de perte ou de vol du téléphone : on indique l'IMEI à la police ou au service des objets trouvés, et ils pourront ainsi savoir si le téléphone récupéré est le bon. L'IMEI comporte 15 chiffres, organisés en trois groupes qu'on sépare parfois par un trait d'union : 8 chiffres pour le TAC (Type Allocation Code), 6 chiffres pour le SNR (Serial NumbeR) et le Spare, un chiffre de contrôle. Le TAC identifie le modèle chez le constructeur et le SNR indique une machine particulière de ce modèle. Tous les deux sont câblés en dur dans le matériel du téléphone. L'IMEISV (SV pour Software Version) inclut en plus un numéro de version du logiciel du téléphone. Si vous voulez plus de détails, il faudra lire le standard TS 23.003.

Les IMEI sont alloués hiérarchiquement (de GSMA au constructeur). GSMA est une association privée d'opérateurs de la téléphonie et ses politiques d'allocation sont documentées sur son site Web.

Donc, place aux nouveaux URN, leur structure est définie en section 3. Ils ne comptent que des caractères ASCII (dans une communication GSM, l'IMEI est transmis en binaire - section 4.2.4 de notre RFC, l'URN est une représentation texte) et, pour l'instant, qu'un seul sous-espace, imei. Après l'IMEI lui-même, il y a des paramètres optionnels. Par exemple, cet URN :

urn:gsma:imei:90420156-025763-0;svn=42

a le paramètre indiquant le numéro de version du logiciel (IMEISV), ici 42. Le NID gsma est désormais dans le registre des NID.

Normalement, les URN ont une obligation de persistence (section 1 du RFC 8141). Ici, elle est garantie par l'engagement de GSMA à maintenir les IMEI.

À noter que les URN ne sont pas, dans le cas général, résolvables automatiquement (pas de service équivalent au DNS) et que rien ne garantit donc qu'on puisse utiliser ces URN gsma: pour autre chose que des comparaisons entre eux. Leur utilité (alors que les IMEI existent et sont utilisés depuis longtemps) est de pouvoir être mis là où un protocole ou un format attend des URI (section 5 du RFC).

La section 8, sur la sécurité, est plus détaillé que ce n'est le cas habituellement pour les URN. Mais c'est parce qu'il y a parfois des erreurs sur la sémantique des IMEI. Comme ils sont souvent écrits sur le téléphone lui-même, ou facilement consultables une fois le téléphone allumé, ils ne sont pas confidentiels. Il ne faut donc pas s'en servir comme capacité (un identifiant dont la seule connaissance fournit un accès à une ressource). Par exemple, certains help desks d'opérateurs utilisent la connaissance de l'IMEI comme une preuve que la personne qui appelle est le titulaire légitime du téléphone. C'est une sérieuse erreur de sécurité.

L'IMEI est un identifiant personnel, puisqu'il est attaché à un téléphone mobile individuel que le propriétaire trimballera partout avec lui. Il soulève donc des problèmes de protection de la vie privée. Les IMEI (et les URN urn:gsma:imei:...) ne doivent donc pas être transmis aveuglément, ce qui risquerait de permettre de suivre l'utilisateur à la trace. Il est recommandé de chiffrer les communications où un IMEI est échangé.

Mais il n'est pas remis à zéro lorsque le téléphone change de propriétaire, et il ne faut donc pas l'utiliser pour router des appels vers une personne, ces appels pourraient en effet être envoyés au mauvais endroit. (L'IMEI est dans le matériel, réinstaller complètement le logiciel ne le change pas.)


Téléchargez le RFC 7254


L'article seul

RFC 7252: Constrained Application Protocol (CoAP)

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : Z. Shelby (Sensinode), K. Hartke, C. Bormann (Universitaet Bremen TZI)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF core
Première rédaction de cet article le 2 juillet 2014


Le protocole CoAP n'est pas destiné aux ordinateurs, ni même aux smartphones mais principalement aux petits engins, aux machines qui n'ont parfois qu'un microcontrôleur 8 bits pour tout processeur, très peu de mémoire (cf. RFC 6574) et qui, en prime, sont connectées par des liens radio lents et peu fiables (les « LowPAN » des RFC 4919 et RFC 4944), allant parfois à seulement quelques dizaines de kb/s. Pour de tels engins, les protocoles comme HTTP et TCP sont trop contraignants. CoAP est un « HTTP-like » (il reprend pas mal de termes et de concepts de HTTP, comme le modèle REST) mais spécialement conçu pour des applications M2M (machine-to-machine) dans des environnements à fortes limitations matérielles.

Le succès de HTTP et notamment de REST a sérieusement influencé les concepteurs de CoAP. Le modèle de CoAP est celui de HTTP : protocole requête/réponse, verbes GET, POST, DELETE, etc, des URI et des types de media comme sur le Web (application/json...) Cette proximité facilitera notamment le développement de passerelles entre le monde des objets CoAP et le Web actuel (section 10). Une des pistes explorées pour l'Internet des Objets (terme essentiellement marketing mais répandu) avait été de prendre de l'HTTP normal et de comprimer pour gagner des ressources réseau mais CoAP suit une autre voie : définir un protocole qui est essentiellement un sous-ensemble de HTTP. Si vous connaissez HTTP, vous ne serez pas trop perdu avec CoAP.

CoAP tournera sur UDP (RFC 768), TCP étant trop consommateur de ressources, et, si on veut de la sécurité, on ajoutera DTLS (RFC 6347). CoAP fonctionne donc de manière asynchrone (on lance la requête et on espère une réponse un jour). On pourrait décrire CoAP comme composé de deux parties, un transport utilisant UDP avec des extensions optionnelles si on veut de la fiabilité (accusés de réception), et un langage des messages (requêtes et réponses en HTTP-like).

Et les messages ? L'en-tête CoAP (section 3 du RFC) a été conçu pour être facile à analyser par des programmes tournant sur de petites machines. Au lieu du texte lisible de HTTP, l'en-tête de CoAP commence par une partie fixe de quatre octets, qui comprend un Message ID de deux octets. Ce Message ID permet de détecter les duplicatas et d'associer un accusé de réception à un message précis. À noter qu'avec ces deux octets, on est limité à environ 250 messages par seconde (en raison du paramètre EXCHANGE_LIFETIME qui est à 247 secondes par défaut). Ce n'est pas une limite bien grave : les ressources (en énergie, en capacité réseau, etc) des machines CoAP ne leur permettront pas d'être trop bavardes, de toute façon.

Le message contient également un champ Token (utilisé pour mettre en correspondance les requêtes et les réponses, à un niveau supérieur à celui des messages, qui sont, eux, identifiés par le Message ID) et un code sur huit bits. Ce code s'écrit sous forme d'un groupe de trois chiffres, le premier indiquant la classe (2 : succès, 4 : erreur du client, 5 : erreur du serveur, etc) et suivi d'un point, et les deux autres chiffres fournissant des détails. Comme vous connaissez HTTP, vous ne serez pas étonné d'apprendre que le code 4.03 indique un problème de permission... Un registre de ces codes existe.

Notez bien que l'encodage, lui, est radicalement différent de celui de HTTP. Il est en binaire et le code 4.03 sera transmis sous forme d'un octet (10000011, avec 100 pour la classe et 11 pour le détail), pas sous forme de la chaîne de caractères qu'utilise HTTP.

Le message contient ensuite des options, qui jouent le rôle des en-têtes de requête de HTTP (leur liste est également dans un registre, on y trouve des trucs connus comme If-Match - section 5.10.8.1, Accept - section 5.10.4 - ou ETag - section 5.10.6). Pour économiser quelques bits, leur encodage est assez spécial. Le numéro de l'option, normalement sur 16 bits, n'est pas transmis tel quel mais sous forme d'une différence avec l'option précédente. Ainsi, si on utilise les options 4 (ETag) et 5 (If-None-Match), la première option indiquera bien 4 mais la seconde indiquera 1... De même, les valeurs de l'option sont violemment comprimées. Si on veut envoyer un entier, on ne doit transmettre que le nombre d'octets nécessaire (rien si l'entier vaut zéro, un seul octet s'il est inférieur à 255, etc).

Le transport utilisé par CoAP, UDP, ne fournit aucune garantie de remise : un paquet UDP peut être perdu, et UDP ne s'en occupera pas, ce sera à l'application de gérer ce cas. CoAP fournit un service pour faciliter la vie aux applications : on peut marquer un message CoAP comme nécessitant un accusé de réception (type CON pour Confirmable). Si ce type est présent dans l'en-tête CoAP, l'expéditeur recevra un accusé de réception (type ACK) portant le Message ID du message reçu. Le RFC fournit l'exemple d'un capteur de température interrogé en CoAP :

Client -> Serveur: CON [0xbc90] "GET /temperature" 
Serveur -> Client: ACK [0xbc90] "2.05 Content" "22.5 °C"

Ici, le second message, la réponse du serveur, contient un accusé de réception pour 0xbc90 (le Message ID). La requête est un GET et la réponse a le code 2.05 (un succès). Notez que, contrairement à HTTP, les codes sont écrits avec un point entre le premier chiffre (la classe) et les deux autres (le détail, cf. section 5.9). Ainsi, 4.04 a la classe 4 (erreur du client) et le détail 04 (ressource non trouvée). Comme indiqué plus haut, les classes sont les mêmes qu'en HTTP : 2 pour un succès, 4 pour une erreur du client (qui devrait changer sa requête avant de réessayer) et 5 pour une erreur du serveur (réessayer à l'identique plus tard peut marcher).

Le Message ID et ces types CON et NON (son contraire, Non-confirmable) permettent de mettre en œuvre des mécanismes simples de retransmission. L'émetteur envoie un message de type CON, s'il ne reçoit pas de message de type ACK à temps, il réessaie, avec croissance exponentielle du délai. Le Message-ID permet aussi de détecter les éventuels duplicatas.

On n'est pas obligé d'utiliser le type CON. Si un message n'a pas besoin de fiabilité (par exemple les lectures périodiques qu'envoie un capteur, que quelqu'un écoute ou pas), il sera du type NON.

Le Message ID doit évidemment être unique, pendant la durée de vie possible des échanges (variable EXCHANGE_LIFETIME, quatre minutes par défaut). Il peut être généré de manière incrémentale (l'émetteur garde un compteur indiquant le dernier Message ID généré) mais, dans ce cas, le RFC recommande (section 4.4) que la valeur initiale soit aléatoire, pour limiter les possibilités d'attaque par un méchant non situé sur le chemin des données (c'est un problème de sécurité analogue à celui des identificateurs de fragments IP - voir l'option --frag-id-policy de l'outil frag6 - ou celui des numéros de séquences initiaux de TCP - voir le RFC 6528).

Autre problème pour l'émetteur CoAP : quelle taille de messages ? Les machines pour qui CoAP est conçu peuvent avoir du mal à gérer parfaitement la fragmentation. Et puis des gros paquets ont davantage de chances d'être corrompus que des petits, sur les liens radios typiques des machines CoAP. Le RFC recommande donc de ne pas dépasser la MTU et, si elle est inconnue, de ne pas dépasser 1 280 octets en IPv6. (C'est plus compliqué pour IPv4 où le RFC recommande 576 octets et le bit DF - Don't Fragment - en notant que, pour les usages typiques de CoAP, le chemin sera simple, avec peu de routeurs et pas de liens à grande distance, donc peu de chances que la fragmentation soit nécessaire.)

Comme CoAP repose sur UDP, il n'y a pas de mécanisme de contrôle de la congestion par défaut. CoAP doit donc s'auto-limiter : réémissions avec croissance exponentielle des délais, et au maximum une requête en attente pour chaque machine avec qui on communique (paramètre NSTART). Ces règles sont pour le client. Si tous les clients les respectent, tout ira bien. Mais un serveur CoAP prudent doit considérer que certains clients seront bogués ou malveillants. Les serveurs ont donc tout intérêt à avoir une forme ou une autre de limitation de trafic.

La sémantique des requêtes et réponses CoAP figure en section 5. On l'a dit, elle ressemble à celle de HTTP, un client qui envoie une requête et un serveur qui transmet une réponse. L'une des plus grosses différences avec HTTP est le caractère asynchrone de l'échange.

Les requêtes sont les classiques (section 5.8) GET, POST, PUT et DELETE, agissant sur une ressource donnée (identifiée par un URI), comportant des données optionnelles (surtout utilisées pour POST et PUT) et utilisant les types de média. CoAP exige que GET, PUT et DELETE soient idempotents (une bonne pratique mais pas toujours respectée sur le Web). Une requête non reconnue et la réponse sera un 4.05. La liste des requêtes possibles est dans un registre IANA.

Du fait du caractère asynchrone de l'échange, mettre en correspondance une requête et une réponse est un peu plus compliqué qu'en HTTP, où toutes les deux empruntaient la même connexion TCP. Ici, la section 5.3.2 résume les règles de correspondance : une réponse correspond à une requête si l'adresse IP source de la réponse était l'adresse IP de destination de la requête et que le Message ID et le Token correspondent.

Comme HTTP, CoAP permet d'utiliser des relais. C'est d'autant plus important que les machines CoAP sont souvent indisponibles (hibernation pour économiser la batterie, par exemple) et un relais pourra donc répondre à la place d'une machine injoignable. Les relais sont traités plus en détail en section 5.7. Comme en HTTP, on pourra avoir des forward proxies sélectionnés par les clients ou des reverse proxies placés devant un serveur.

On l'a vu, CoAP, comme HTTP, utilise des URI, détaillés en section 6. Ils commencent par les plans coap: ou coaps:. On verra ainsi, par exemple, coap://example.com/~sensors/temp.xml ou coaps://[2001:db8::2:1]/measure/temperature/. Attention, tout le monde croit bien connaître les URI car ils sont massivement utilisés pour le Web mais le RFC met en garde les programmeurs : il y a plein de pièges dans le traitement des URI, notamment dans le décodage des valeurs encodées en pour-cent.

Si le port n'est pas indiqué dans l'URI (ce qui est le cas des deux exemples ci-dessus), le port par défaut est 5683 pour coap: et 5684 pour coaps:.

CoAP utilise, comme HTTP, la convention du /.well-known/ (RFC 8615) pour placer des ressources « bien connues », facilitant ainsi leur découverte.

Justement, à propos de découverte, la section 7 détaille comment un client CoAP va pouvoir trouver les URI des ressources intéressantes. CoAP est conçu pour des communications de machine à machine, où aucun humain n'est présent dans la boucle pour deviner, faire une recherche Google, utiliser son intuition, etc. La méthode privilégiée dans CoAP est celle du RFC 6690 : un fichier au format normalisé situé en /.well-known/core.

Les section 9 et 11 sont consacrées à la sécurité de CoAP. Évidemment, vu les ressources très limitées des machines CoAP typiques, il ne faut pas s'attendre à une grande sécurité. Par exemple, une protection par DTLS (RFC 6347) est possible mais pas obligatoire, juste conseillée. En outre, les ressources matérielles limitées des machines CoAP compliquent la tâche du programmeur : des processeurs très lents qui facilitent les attaques par mesure du temps écoulé, et pas de bon générateur aléatoire. En l'absence d'un tel générateur, on ne peut donc pas générer des clés cryptographiques localement, il faut le faire en usine et les enregistrer sur la machine. Et pas question de mettre les mêmes clés à tout le monde : comme les machines CoAP seront souvent dispersées dans des endroits ayant peu de sécurité physique (capteurs placés un peu partout), et n'auront en général pas de protection contre les manipulations physiques, pour des raisons de coût, un attaquant pourra facilement ouvrir une machine et en extraire ses clés.

La complexité est l'une des ennemies principales de la sécurité. Le RFC rappelle que le traitement des URI (bien plus compliqué qu'il n'en a l'air) impose des analyseurs relativements complexes et donc augmente la probabilité de bogues, pouvant mener à des failles de sécurité. Même chose pour le format des liens du RFC 6690.

Question réseau, CoAP souffrira sans doute d'attaques rendues possibles par l'usurpation d'adresses IP. Comme UDP ne nécessite pas d'échange préalable, il est trivial d'envoyer un paquet depuis une adresse usurpée et de le voir accepté. Cela permet des tas d'attaques comme :

  • Envoyer un RST (Reset) aux demandes de connexion vers un serveur, rendant ainsi ce serveur inutilisable (déni de service),
  • Envoyer une fausse réponse à une requête GET.

Pour cette deuxième attaque, il faut pouvoir deviner le Token utilisé. Si l'attaquant est aveugle (parce que situé en dehors du chemin des paquets), sa tâche sera difficile si le Token est bien aléatoire (mais ces machines contraintes en ressources n'ont souvent pas de vrai générateur aléatoire, au sens du RFC 4086).

En pratique, il est probable que les déploiements réels de CoAP aient lieu dans des réseaux fermés, ne contenant que des machines de confiance, et où l'accès à l'extérieur passera par une passerelle qui s'occupera de sécurité. Autrement, un simple ping à destination d'une machine CoAP pourrait suffir à vider sa batterie.

CoAP introduit aussi une autre menace, celle d'attaques par amplification (section 11.3). Comme SNMP et le DNS (tous les deux déjà utilisés pour ces attaques), CoAP a des réponses plus grandes que les questions (permettant l'amplification) et repose sur UDP et non pas TCP (permettant l'usurpation d'adresse IP).

La seule limite à ces attaques semble devoir être les faibles ressources des machines CoAP, qui devraient les rendre relativement peu intéressantes comme amplificateurs contre des serveurs Internet. En revanche, à l'intérieur d'un réseau de machines CoAP, le risque demeure élevé et le RFC ne propose aucune vraie solution.

CoAP est, d'une certaine façon, un vieux protocole (voir l'article « CoAP: An Application Protocol for Billions of Tiny Internet Nodes » de Carsten Bormann, Angelo Paolo Castellani et Zach Shelby publié en 2012 dans dans Internet Computing, IEEE (Volume:16 , Issue: 2) et malheureusement pas disponible en ligne, il faut demander une copie à l'auteur). Il existe déjà plusieurs mise en œuvre, qui ont été souvent testées dans des essais d'interopérabilité formels. Un exemple de mise en œuvre est celle du système Contiki.

Des exemples de requêtes CoAP décrites en détail figurent dans l'annexe A du RFC. Grâce à Renzo Navas, voici quelques traces CoAP au format pcap :

Si tcpdump ne connait pas encore CoAP, Wireshark, par contre, sait bien l'analyser. Ici, une la première requête GET du premier fichier pcap et sa réponse :


Constrained Application Protocol, TID: 27328, Length: 21
    01.. .... = Version: 1
    ..00 .... = Type: Confirmable (0)
    .... 0000 = Option Count: 0
    Code: GET (1)
    Transaction ID: 27328
    Payload Content-Type: text/plain (default), Length: 17, offset: 4
        Line-based text data: text/plain
            \273.well-known\004core

Constrained Application Protocol, TID: 27328, Length: 521
    01.. .... = Version: 1
    ..10 .... = Type: Acknowledgement (2)
    .... 0000 = Option Count: 0
    Code: 2.05 Content (69)
    Transaction ID: 27328
    Payload Content-Type: text/plain (default), Length: 517, offset: 4
        Line-based text data: text/plain
            \301(\261\r
            [truncated] \377</careless>;rt="SepararateResponseTester";title="This resource will ACK anything, but never send a separate response",</helloWorld>;rt="HelloWorldDisplayer";title="GET a friendly greeting!",</image>;ct="21 22 23 24";rt="Ima

Merci à Laurent Toutain pour sa relecture attentive.


Téléchargez le RFC 7252


L'article seul

RFC 7250: Using Raw Public Keys in Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : P. Wouters (Red Hat), H. Tschofenig, J. Gilmore, S. Weiler (SPARTA), T. Kivinen (AuthenTec)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 1 juillet 2014


Le système de sécurité TLS, normalisé dans le RFC 5246 est souvent confondu avec la norme de certificats X.509. On lit souvent des choses comme « le serveur TLS envoie alors un certificat X.509 au client », voire, pire, on appelle ces certificats « certificats TLS » (ou, encore plus inexact, « certificats SSL »). Dans la réalité, les deux systèmes, TLS et X.509, sont indépendants. X.509 peut servir à autre chose qu'à TLS (et c'est pourquoi parler de « certificats SSL » est une grosse erreur), et TLS peut utiliser d'autres techniques d'authentification que X.509. Une de ces techniques était déjà spécifiée dans le RFC 6091, l'utilisation de clés PGP. Une autre vient d'être normalisée dans ce RFC, l'utilisation de « clés brutes » (raw keys), sans certificat autour. Comme une clé seule ne peut pas être authentifiée, ces clés brutes n'ont de sens que combinées avec un mécanisme d'authentification externe, comme DANE.

Rappelons en effet qu'un certificat, c'est une clé publique (champ SubjectPublicKeyInfo dans X.509) plus un certain nombre de métadonnées (comme la date d'expiration) et une signature par une autorité qui certifie la clé. Pour la session TLS, la seule partie indispensable est la clé (dans un certificat « auto-signé », seule la clé a un sens, le reste du certificat ne pouvant pas être vérifié). Mais, en pratique, le chiffrement sans l'authentification est limité : il ne protège que contre un attaquant purement passif. Dès que l'attaquant est actif (pensons par exemple à un hotspot Wifi tentant... mais tenu par l'attaquant), il peut rediriger le client TLS vers un serveur intermédiaire qui va faire croire au client qu'il est le vrai serveur, avant de retransmettre vers le serveur authentique. Pour contrer cette attaque de l'homme du milieu, on authentifie le serveur. Sur l'Internet, la méthode la plus courante est l'utilisation de certificats X.509, ou plus précisement de leur profil PKIX (RFC 5280). Cette méthode est d'une fiabilité très douteuse : des centaines d'organisations dans le monde peuvent émettre un faux certificat pour gmail.com et il ne peut donc pas y avoir de confiance rationnelle dans ce système (cf. « New Tricks for Defeating SSL in Practice »).

Il existe d'autres méthodes d'authentification que X.509, permettant de faire un lien entre le serveur qu'on veut contacter, et l'entité qui nous envoie une clé publique en TLS :

  • Les certificats ou clés publiés dans le DNS et sécurisés par DNSSEC, à savoir la technique DANE du RFC 6698,
  • Les certificats ou clés publiés dans un annuaire LDAP,
  • Les certificats ou clés stockés en dur chez le client. Cela manque de souplesse (il est difficile de les changer) et ce n'est donc pas très recommandé pour l'Internet public mais c'est envisagé pour des déploiements plus fermés comme ceux du protocole CoAP (RFC 7252), où les objets peuvent sécuriser la communication avec DTLS. (Cette troisième méthode est sans doute la seule possible pour l'authentification du client TLS par le serveur, cf. section 4.3.)

La section 6 de notre RFC revient en détail sur l'authentification de ces clés brutes. Sans cette authentification, une session TLS utilisant ces clés est très vulnérable à l'homme du milieu.

La section 3 décrit les détails de format des clés brutes. Il faut deux extensions au protocole TLS, client_certificate_type et server_certificate_type (enregistrées dans le registre des extensions), qui permettent d'indiquer (lors de la négociation TLS) séparément le type de certificat utilisé par le serveur et par le client. Par exemple, pour le serveur, cela s'écrit ainsi :

 
struct {
           select(ClientOrServerExtension) {
               case client:
                 CertificateType server_certificate_types<1..2^8-1>;
               case server:
                 CertificateType server_certificate_type;
           }
   } ServerCertTypeExtension;

Lorsque ces extensions TLS sont utilisées, la structure Certificate est modifiée ainsi :

   

struct {
       select(certificate_type){

           // certificate type defined in this document.
           case RawPublicKey:
             opaque ASN.1_subjectPublicKeyInfo<1..2^24-1>;

           // X.509 certificate defined in RFC 5246
           case X.509:
             ASN.1Cert certificate_list<0..2^24-1>;

           // Additional certificate type based on TLS
           //   Certificate Type Registry 
           //   https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-3
           // for instance PGP keys
       };
   } Certificate;

(On notera que le RFC 6091 utilisait un autre mécanisme, l'extension cert_type, numéro 9, mais qui n'a pas été réutilisée ici, le RFC 6091 n'ayant pas le statut « Chemin des Normes » et le mécanisme cert_type ne permettant pas des types différents pour le client et le serveur.) Le champ subjectPublicKeyInfo contient un encodage DER de la clé et d'un identificateur d'algorithme (un OID comme 1.2.840.10045.2.1 pour ECDSA) :

     SubjectPublicKeyInfo  ::=  SEQUENCE  {
           algorithm               AlgorithmIdentifier,
           subjectPublicKey        BIT STRING  }

L'omission d'une grande partie du certificat permet de se contenter d'un analyseur ASN.1 plus réduit. Mais les clés brutes ne sont malheureusement pas réellement brutes, c'est quand même une structure décrite en ASN.1 et il faut donc un analyseur minimal.

La section 4 décrit les modifications à la négociation initiale de TLS (les autres parties de la communication ne sont pas modifiées par ce RFC). Le client ajoute une ou deux des extensions TLS (la plupart du temps, en TLS, le client ne s'authentifie pas, et on n'aura donc que l'extension server_certificate_type). La ou les extensions indiquent les types de certificat reconnus par le pair TLS (si l'extension est absente, seul X.509 est reconu). Ainsi, un serveur nouveau, intégrant les clés brutes, sait tout de suite si un client pourrait les traiter (si le client n'a pas mis server_certificate_type, ou bien si son server_certificate_type n'inclut pas les clés brutes, ce n'est pas la peine d'en envoyer). Si c'est le client qui est nouveau et le serveur ancien, la réponse du serveur ne contiendra pas les extensions et le client saura donc qu'il ne faut pas s'attendre aux clés brutes. Si le serveur reconnait l'extension, mais aucun des types de certificats indiqués, il termine la session. À noter que ces clés brutes marchent avec tous les algorithmes de cryptographie déjà reconnus.

La section 5 du RFC fournit des exemples de sessions TLS avec cette nouvelle possibilité. Par exemple, ce dialogue montre un client qui gère les clés brutes du serveur (et uniquement celles-ci, ce n'est donc pas un navigateur Web typique) et un serveur qui accepte d'envoyer sa clé ainsi. Le client n'est pas authentifié (il n'envoie pas sa clé ou son certificat et ne se sert donc pas de client_certificate_type) :


client_hello,
server_certificate_type=(RawPublicKey) // [1]
                       ->
                       <- server_hello,
                          server_certificate_type=(RawPublicKey), // [2]
                          certificate, // [3]
                          server_key_exchange,
                          server_hello_done

client_key_exchange,
change_cipher_spec,
finished               ->

                       <- change_cipher_spec,
                          finished

Application Data       <-------> Application Data

Ce cas d'un client ne comprenant que les clés brutes est un cas qui peut se produire pour l'Internet des objets, par exemple avec CoAP. Mais un client différent, par exemple un navigateur Web, va accepter d'autres types de certificats. Le dialogue pourrait ressembler à :


client_hello,
server_certificate_type=(X.509, RawPublicKey)
client_certificate_type=(RawPublicKey) // [1]
                         ->
                         <-  server_hello,
                             server_certificate_type=(X.509)//[2]
                             certificate, // [3]
                             client_certificate_type=(RawPublicKey)//[4]
                             certificate_request, // [5]
                             server_key_exchange,
                             server_hello_done
certificate, // [6]
client_key_exchange,
change_cipher_spec,
finished                  ->

                          <- change_cipher_spec,
                             finished

Application Data        <------->     Application Data

Ici, le serveur reconnait la nouvelle extension mais ne sait envoyer que des certificats X.509 (ce qui est donc fait par la suite). Le client, lui, s'authentifie en envoyant une clé brute (même si ce message est marqué certificate dans le dialogue).

Il existe apparemment déjà plusieurs mises en œuvre de TLS qui utilisent ces extensions, par exemple GnuTLS.


Téléchargez le RFC 7250


L'article seul

RFC 7249: Internet Numbers Registries

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : R. Housley (Vigil Security)
Pour information
Première rédaction de cet article le 20 mai 2014


Le système de registre pour les adresses IP est décrit dans le RFC 7020. Cet ultra-court RFC liste les registres IANA qui font partie de ce système.

Pour distribuer des ressources qui doivent être uniques, comme les adresses IP mais aussi les numéros d'AS, l'IETF fait appel à l'IANA (RFC 2860). Le RFC 7020 décrit en détail ce système. Il faut trois registres IANA pour le mettre en œuvre : celui des numéros d'AS, celui des adresses IPv4 et celui des adresses IPv6.

Le registre des numéros d'AS stocke ensemble les numéros sur 16 bits (l'ancienne norme) et les plus récents numéros sur 32 bits. L'allocation de ces numéros d'AS se fait selon les politiques de chaque RIR. Certains numéros d'AS sont réservés et d'autres le seront peut-être dans le futur, selon la politique IETF review (RFC 5226). Ce registre des AS spéciaux est nouveau, créé par ce RFC 7249, consolidant les numéros réservés par divers RFC (comme 23456 pour le RFC 6793, ou 65536 à 65551 réservés pour la documentation par le RFC 5398.

Même chose pour les adresses IPv4 (passage par les RIR et leurs politiques). Là aussi, il existe un registre des adresses spéciales (même politique IETF review).

Et pour IPv6 ? Pour l'instant, la grande majorité de cet immense espace est réservée (RFC 3513). Le reste est alloué par les RIR selon leurs politiques, comme pour IPv4. Il y a aussi un registre spécial.


Téléchargez le RFC 7249


L'article seul

RFC 7240: Prefer Header for HTTP

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : J. Snell
Chemin des normes
Première rédaction de cet article le 18 juin 2014


Dans certains cas, la norme du protocole HTTP laisse un serveur choisir entre plusieurs comportements, tous légaux. Un client peut avoir une préférence personnelle et ce nouvel en-tête Prefer:, dans la requête HTTP, permet à ce client de la spécifier. Ce n'est pas un ordre, le serveur peut ignorer cette préférence.

Un exemple de cette latitude laissée aux serveurs ? Lorsqu'un client modifie une ressource Web avec la commande PUT (cf. RFC 5023), le serveur peut retourner la nouvelle ressource, complète, ou bien seulement la modification faite. Le client pourrait dire « je ne vais même pas lire ce texte, envoie le minimum » ou bien « je vais tout vérifier soigneusement, envoie la ressource après modification, pour m'éviter un GET ultérieur ». Le peut-il aujourd'hui avec l'en-tête Expect: (section 14.20 du RFC 2616) ? Non, car Expect: est impératif : tout serveur, ou même tout intermédiaire (par exemple un relais) qui ne le comprend pas, ou ne peut lui obéir, doit rejeter la requête. Expect: ne convient donc pas pour le cas où on veut dire « si tu arrives à le faire comme cela, ça m'arrangerait mais ne te casse pas trop la tête ». Comme le dit le RFC, dans un style très Jane Austen, « preferences cannot be used as expectations ». C'est d'autant plus important que certaines préférences peuvent avoir un coût de traitement élevé pour le serveur et que, si celui-ci les acceptait aveuglément, il pourrait se retrouver victime d'un déni de service (cf. section 6).

La section 2 spécifie la syntaxe du nouvel en-tête Prefer:. Sa sémantique, on l'a vu, est qu'il n'est pas impératif. Le serveur qui ne comprend pas un Prefer: ou ne peut pas ou ne veut pas le respecter continue le traitement de la requête en ignorant cet en-tête. Il peut y avoir plusieurs en-têtes Prefer: ou bien un seul avec une liste de préférences séparées par des virgules, comme ici :

GET /coffee HTTP/1.1
Prefer: no-sugar, no-milk, hot

Certaines préférences prennent une valeur, après un signe = :

GET /coffee HTTP/1.1
Prefer: sugar=2

Il peut aussi y avoir des paramètres à certaines préférences, après un ; comme :

GET /coffee HTTP/1.1
Prefer: milk; organic="true"

Vu le caractère optionnel de ce système de préférences, on ne s'étonnera pas que le RFC demande aux serveurs HTTP d'ignorer les préférences inconnues (ce qui est le cas de milk ou sugar, qui ne sont pas dans le registre officiel...)

Que peut-on mettre dans un champ Prefer: ? Uniquement des préférences enregistrées. La section 4 décrit les préférences existant actuellement :

  • respond-async indique que le client n'aime pas attendre et préfère une réponse asynchrone plus tard. Le serveur qui acceptera enverra alors un code de retour 202, accompagné d'un champ Location: pour indiquer où récupérer la réponse lorsqu'elle sera prête. Cette préférence ne prend pas de valeur.
  • Par contre, la préférence wait prend une valeur, le nombre de secondes qu'on est prêt à attendre, ce qui est utile en combinaison avec respond-async. Ainsi, Prefer: respond-async, wait=30 signifiera qu'on est prêt à attendre une demi-minute, puis qu'on préférerait une réponse asynchrone ensuite.
  • return a aussi une valeur, indiquant si le client préfère recevoir la ressource entière ou bien une version allégée. Prefer: return=representation exprime le premier choix et Prefer: return=minimal le second (c'est sans doute ce que demanderont les clients connectés à un réseau très lent).
  • Enfin, handling indique où le client met le curseur entre le libéralisme et la rigidité. handling=lenient signifie que le client préférerait que le serveur soit libéral, où cas où la requête contienne quelques erreurs mineures, handling=strict, que le client demande au serveur de n'accepter que des requêtes parfaites.

Comme le respect de Prefer: est facultatif, attention à ne pas l'utiliser comme substitut de la négociation de contenu. En effet, il peut être ignoré par les caches, qui pourraient mémoriser un contenu correspondant à certaines préférences et le servir à d'autres clients qui auraient d'autres préférences. Si le serveur sert des contenus différents selon les préférences, il doit penser à mettre un Vary: dans la réponse.

Si le serveur HTTP est sympa, il peut inclure dans la réponse un en-tête Preference-Applied: qui indique quelles préférences ont été effectivement appliquées. Un exemple avec la commande PATCH du RFC 5789 et le format du RFC 6902 :

PATCH /my-document HTTP/1.1
Host: example.org
Content-Type: application/json-patch
Prefer: return=representation

[{"op": "add", "path": "/a", "value": 1}]

qui entraîne la réponse :

HTTP/1.1 200 OK
Content-Type: application/json
Preference-Applied: return=representation
Content-Location: /my-document

{"a": 1}

Les détails bureaucratiques sont en section 5, consacrée aux registres IANA. Les en-têtes Prefer: et Preference-Applied: sont ajoutés au registre des en-têtes. Un nouveau registre, pour stocker les préférences, est créé. Les enregistrements se feront selon la politique « Norme nécessaire » du RFC 5226 : chaque préférence devra être décrite dans un document stable, décrivant ses caractéristiques syntaxiques et sémantiques. Le tout sera envoyé à la liste ietf-http-wg@w3.org pour un premier examen, puis approuvé ou rejeté par l'expert nommé par l'IANA.

Début 2013, il semble que cet en-tête Prefer: soit déjà géré par Abdera. Le protocole OData cite aussi cet en-tête. Mais on ne s'attend pas à ce qu'il soit massivement utilisé par les navigateurs : il est plutôt prévu pour des clients automatiques, appelant une API REST.


Téléchargez le RFC 7240


L'article seul

RFC 7239: Forwarded HTTP Extension

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : A. Petersson, M. Nilsson (Opera Software)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 17 juin 2014


Lorsqu'un client HTTP se connecte directement à un serveur HTTP, ce dernier voit l'adresse IP du client et peut la journaliser pour la traçabilité, faire du contrôle d'accès, des statistiques, etc. Mais si le client est passé par un relais (proxy) ? La solution proposée par notre RFC est que le relais ajoute un en-tête, Forwarded:, à la requête, reprenant l'information que le passage par le relais a fait perdre. Il existait déjà des en-têtes non standards pour ce rôle, ce RFC est le premier à normaliser.

Notez que, non seulement les relais sont d'un usage très fréquent dans le Web d'aujourd'hui, mais qu'ils sont souvent inconnus du client, par exemple parce qu'ils s'insèrent automatiquement dans la requête HTTP, sans configuration explicite. Même s'il voulait indiquer son adresse IP, le client ne pourrait pas. Il est donc nécessaire que ce soit le relais qui le fasse. La plupart du temps, la perte d'information due au relais (on n'a plus accès à l'adresse IP du client) n'est pas le but principal du relais, ni même un effet souhaité. Le relais vise par exemple à diminuer l'usage de la liaison Internet en gardant les ressources Web dans son cache. Dans ce cas, la perte d'information est un effet de bord non désiré et on peut souhaiter que le relais répare le problème qu'il a causé.

À noter qu'il existe aussi souvent des relais situés, non pas à proximité du client, mais proche du serveur, par exemple pour lui ajouter une fonction de cache des données souvent accédées (le logiciel le plus connu pour cette tâche est Varnish). Ces relais (parfois appelés « relais inverses ») posent le même problème (de perte d'information) et peuvent utiliser la même solution.

Il existe déjà plusieurs en-têtes pour transporter l'information jusqu'au serveur (comme X-Forwarded-For:) mais aucun n'avait encore été normalisé, ce qui fait que l'interopérabilité ne pouvait être garantie. Forwarded: est désormais dans le registre des en-têtes (section 9).

Parfois, le relais a au contraire pour but de dissimuler les clients (par exemple pour permettre l'accès anonyme au Web) et, dans ce cas, il ne va évidemment pas utiliser la technique de ce RFC : Forwarded: n'est pas obligatoire.

Notez que les mêmes problèmes de perte d'information (parfois souhaitée, parfois non) se produisent avec le NAT : voir le RFC 6269.

L'ancien système non normalisé faisait en général appel à trois en-têtes, X-Forwarded-For:, X-Forwarded-By:, et X-Forwarded-Proto:. Un des gros inconvénients de ce système (et qui explique la décision de n'avoir plus qu'un en-tête, avec plusieurs types d'information) était qu'on ne pouvait pas savoir quels en-têtes étaient liés : rien n'indiquait si un X-Forwarded-For: et un X-Forwarded-By: avaient été mis par le même relais.

La section 4 donne la syntaxe complète de cet en-tête Forwarded:. Il est bien sûr facultatif et doit être débrayé par défaut (en raison des problèmes de protection de la vie privée qu'il pose). Il comporte une liste de couples {paramètre, valeur} qui permettent d'indiquer les changements (par exemple d'adresse IP) au passage du relais. Si plusieurs relais ont été successivement utilisés, certains paramètres peuvent être répétés. Premier exemple, où seule l'adresse IP du « vrai » client est indiquée :

Forwarded: For="[2001:db8:cafe::17]"

Autre exemple, où on met l'adresse IP et le port originels :

Forwarded: For="[2001:db8:cafe::17]:4711"

Bien plus bavard, un en-tête qui indique l'adresse IP du client mais aussi celle du relais, ainsi que le protocole original (un relais peut transformer du HTTP en HTTPS et réciproquement, par exemple si un relais termine les sessions TLS avant de passer au vrai serveur) :

Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43

(Je vous laisse chercher pourquoi seules les adresses IPv6 sont entre guillemets. C'est expliqué plus loin.) Et enfin un exemple où deux relais ont été successivement traversés, ils sont alors séparés par des virgules :

Forwarded: for=192.0.2.43, for="[2001:db8:cafe::17]"

Ces paramètres (dans les exemples ci-dessus, for, by et proto) sont spécifiés en détail en section 5. by identifie le relais (utile, si on en a plusieurs, ou simplement si un relais écoute sur plusieurs adresses IP et veut indiquer laquelle a reçu la requête originale). Ce n'est pas forcément une adresse IP. for identifie le client original. Là encore, ce n'est pas forcément une adresse IP, cela peut être un identificateur arbitraire.

Si ce n'est pas une adresse IP, qu'est-ce que c'est ? La section 6 décrit le concept d'identificateur, utilisé par les paramètres for et by. Pour des raisons de sécurité, mais aussi parce qu'ils peuvent être plus pratiques, un relais peut toujours utiliser des identificateurs à lui pour désigner le client (l'identificateur spécial unknown indique que le relais ne sait pas). On peut donc avoir :

Forwarded: for=unknown;by=203.0.113.43

où le relais s'identifie mais ne veut pas ou ne peut pas dire qui est son client (il pourrait aussi ne pas mettre for du tout mais le unknown indique que c'est une décision délibérée, pas un oubli).

Autre possibilité, utiliser des identificateurs attribués localement (précédés par un trait bas), qui ont un sens pour le relais mais pas forcément pour le serveur. Cela permet la traçabilité, sans trop révéler à l'extérieur. Exemple :

Forwarded: by=_eth1

ou bien :

Forwarded: for=_97470ea54d581fc676f6b781b811296e

Des nouveaux paramètres pourront être ajoutés dans le futur et seront stockés dans le nouveau registre des paramètres.

Enfin, les identificateurs peuvent être des adresses IP, comme dans les précédents exemples. Dans ce cas, les adresses IPv6 doivent être entre guillemets, car le deux-points a une signification particulière dans les en-têtes HTTP.

Petit point à garder en tête, l'en-tête Via:, normalisé dans la section 5.7.1 du RFC 7230 ne donne, lui, d'informations que sur le relais, pas sur le client originel. En général, on ne peut pas espérer retrouver toute l'information en combinant Via: et Forwarded: car certains relais mettront uniquement un Via:, certains uniquement un Forwarded: et d'autres les deux.

La section 8 couvre toutes les questions de sécurité liées à l'en-tête Forwarded:. D'abord, il faut se rappeler qu'il n'est absolument pas authentifié. Un client plaisantin a pu en mettre un bidon au départ. Si la requête n'est pas en HTTPS, quelqu'un sur le trajet a pu ajouter, retirer ou modifier cet en-tête n'importe comment. Il faut donc traiter cette information avec prudence, sauf si on est sûr que le précédent relais était une machine de confiance.

Mais les plus gros problèmes de sécurité posés par ce mécanisme concernent évidemment la fuite d'information. L'en-tête Forwarded: peut révéler la structure interne d'un réseau privé (Forwarded: for=192.168.33.165 et on sait quelle plage du RFC 1918 est utilisée en interne...). Plus drôle, si un serveur renvoie cet en-tête dans la réponse (ce que le RFC interdit), il révèle au client les relais éventuellement non connus de ce dernier (notez qu'il existe des sites Web pour cela).

Mais le risque principal de cette fuite d'information est évidemment celui de compromission de la vie privée : l'en-tête Forwarded: transmet au serveur des informations que le client peut considérer comme privées, notamment une donnée nominative, l'adresse IP. D'où le rappel qu'un relais qui vise l'anonymisation des requêtes ne doit évidemment pas utiliser cet en-tête. (Le RFC 8165 cite d'ailleurs cet en-tête Forwarded: comme un exemple de mauvaise pratique.)

Le RFC demande donc que, par défaut, les identificateurs utilisés dans les paramètres for et by soient opaques, et générés plus ou moins aléatoirement, pour chaque requête. (Mon avis personnel est que, dans ce cas, autant ne pas mettre de Forwarded: du tout...)

Le RFC rappelle aussi que le problème de l'anonymat sur le Web est bien plus vaste que cela : si on n'utilise pas de relais anonymisant, on divulgue déjà son adresse IP, et il existe un million d'autres moyens pour un serveur de suivre à la trace un client, comme le montre le Panopticlick. Les gens qui se plaignent de la menace que Forwarded: (ou ses prédécesseurs comme X-Forwarded-For:) font courir à leur vie privée ne sont pas toujours cohérents avec eux-mêmes (par exemple, il est rare qu'ils débrayent les cookies, bien plus efficaces pour le suivi des visiteurs).

Question mises en œuvre, plusieurs logiciels HTTP géraient déjà les en-têtes non officiels (par exemple, Squid documente comment le configurer, même chose avec Varnish dans sa FAQ). Pour le Forwarded:, il va falloir attendre un peu.


Téléchargez le RFC 7239


L'article seul

RFC 7238: The Hypertext Transfer Protocol (HTTP) Status Code 308 (Permanent Redirect)

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : J. Reschke (greenbyte)
Expérimental
Première rédaction de cet article le 17 juin 2014


Le protocole HTTP définit plusieurs codes de retour pour une redirection (« la ressource que tu cherches n'est pas ici, va voir là »). La section 6.4 du RFC 7231 classe ces trois codes de retour en notant que deux désignent des redirections temporaires (302 et 307) et qu'un désigne une redirection permanente (301). Deux codes permettent au client HTTP de remplacer, pour la nouvelle requête, la méthode POST par un GET (301 et 302), un autre ne le permet pas (307). Si vous avez suivi, vous avez noté qu'il manquait un code voulant dire « redirection permanente mais sans changer la méthode HTTP ». C'est l'objet du nouveau code décrit dans ce RFC, le 308 (depuis normalisé dans le RFC 7538).

Donc, 308 veut dire (section 3 de notre RFC) que la ressource Web convoitée a changé de place, que c'est permanent et que le client HTTP devrait donc aller chercher la ressource au nouvel endroit et, s'il le peut, modifier sa base de données (dans le cas d'un crawler, par exemple, ou dans celui d'un navigateur qui modifie les marque-pages). Où est indiqué « le nouvel endroit » ? Par l'en-tête Location: de la réponse HTTP (cf. section 7.1.2 du RFC 7231). Il est recommandé d'inclure un petit texte en HTML fournissant un autre moyen de suivre la redirection, si le client HTTP n'a pas compris le 308. Bref, le 308 est très proche du 301, à la seule exception près qu'un client n'a pas le droit de changer la méthode HTTP (POST, GET, etc) utilisée. Le nouveau code est désormais dans le registre IANA.

Est-ce que l'information comme quoi il y a redirection peut être mémorisée dans les caches ? Il n'y a pas de mécanisme parfait pour cela mais lesdits caches sont invités à regarder le RFC 7234.

Ajouter un nouveau code HTTP peut provoquer des problèmes de déploiement (section 4). En effet, la section 6 du RFC 7231 dit que les codes inconnus commençant par 3 doivent être traités comme le code 300 (qui annonce des choix multiples, en cas de négociation de contenu). Au début, 308 va être inconnu de tous les clients HTTP et sera donc mal interprété. (Vous pouvez tester votre navigateur ici.) Il n'y aura pas de redirection automatique. En attendant que tous les clients soient mis à jour, le webmestre prudent n'utilisera 308 que s'il connait les clients utilisés, ou s'il sait que l'absence de redirection automatique n'est pas trop grave. Le RFC déconseille formellement de faire varier la réponse selon le client (ou selon ce qu'on croit être le client, rappelez-vous que le champ User-Agent: peut être trompeur), cela rend le Web trop difficile à déboguer.

Une façon de s'en tirer pourrait être via le code HTML suggéré plus haut. Par exemple :


HTTP/1.1 308 Permanent Redirect
Content-Type: text/html; charset=UTF-8
Location: http://example.com/new
Content-Length: 454

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
                      "http://www.w3.org/TR/html4/strict.dtd">
<html>
   <head>
      <title>Permanent Redirect</title>
      <meta http-equiv="refresh"
                 content="0; url=http://example.com/new">
   </head>
   <body>
      <p>
         The document has been moved to
         <a href="http://example.com/new">
         http://example.com/new</a>.
      </p>
   </body>
</html>

Ainsi, un navigateur Web qui ne comprend pas le 308 sera redirigé, via le <meta http-equiv="refresh" ....

Où en sont les mises en œuvre ? Vous pouvez tester sur le test de libcurl. Pour les navigateurs et autres clients :

Enfin, je signale deux bons articles sur le 308, un en français et un en anglais. Ce code était expérimental à l'époque et est désormais normalisé, depuis le RFC 7538.


Téléchargez le RFC 7238


L'article seul

RFC 7237: Initial Hypertext Transfer Protocol (HTTP) Method Registrations

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : J. Reschke (greenbytes)
Pour information
Première rédaction de cet article le 14 juin 2014


Une des nouveautés de la série de RFC sur le protocole HTTP 1.1 est l'introduction d'un registre des méthodes HTTP (GET, POST, etc), permettant de voir du premier coup d'œil les méthodes existantes. Ce registre commence avec les méthodes pré-existantes que ce purement bureaucratique RFC 7237 enregistre formellement.

Les procédures pour spécifier une nouvelle méthode (et donc être publié dans le registre) sont décrites dans la section 8.1 du RFC 7231.

Sont donc ajoutés, dans la version initiale du registre IANA, outre les méthodes du RFC 7231 comme les classiques GET ou PUT pas moins de trente-quatre méthodes, la plupart venues de WebDAV (RFC 4918). Parmi elles, ACL (RFC 3744), LABEL (RFC 3253), SEARCH (RFC 5323), mais aussi certaines sans lien avec WebDAV comme PATCH (RFC 5789).


Téléchargez le RFC 7237


L'article seul

RFC 7236: Initial Hypertext Transfer Protocol (HTTP) Authentication Scheme Registrations

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : J. Reschke (greenbytes)
Pour information
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 16 juin 2014


Une des nouveautés de la série de RFC sur le protocole HTTP 1.1 est l'introduction d'un registre des mécanismes d'authentification (RFC 7235). Ce registre commence avec les mécanismes pré-existants, comme Basic ou Digest, que ce RFC enregistre formellement.

Cinq mécanismes sont donc enregistrés à l'IANA :

  • Basic et Digest, décrits dans les RFC 7616 et RFC 7617,
  • Bearer, du RFC 6750,
  • Negotiate, normalisé dans le RFC 4559, et dont notre RFC note qu'il viole à la fois la syntaxe et la sémantique de HTTP,
  • OAuth, normalisé dans le RFC 5849.

Téléchargez le RFC 7236


L'article seul

RFC 7235: Hypertext Transfer Protocol (HTTP/1.1): Authentication

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), 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 16 juin 2014


Dans la série de RFC sur le protocole HTTP 1.1, ce nouveau document normalisait l'authentification faite en HTTP. Le RFC 9110 l'a remplacé depuis.

Le HTTP originel avait été conçu uniquement pour de l'accès à des documents publics. Toutefois, l'authentification a été assez vite ajoutée, afin de permettre de mettre en ligne des documents dont l'accès est restreint à une certaine catégorie d'utilisateurs. HTTP dispose aujourd'hui de plusieurs mécanismes d'authentification, décrits dans ce RFC. Il faut quand même noter que tous ont des limites et, qu'en pratique, l'authentification des utilisateurs humains se fait presque toujours par des mécanismes non-HTTP, et pas par ceux de ce RFC.

Le principe de base de l'authentification HTTP est le défi/réponse. Un client cherche à accéder à une ressource non-publique : le serveur lui envoie à la place un défi (code de réponse 401 et en-tête WWW-Authenticate:), le client fait une nouvelle demande, avec la réponse au défi (en-tête Authorization:). À noter qu'il n'y a pas que les serveurs d'origine qui peuvent exiger une authentification, les relais peuvent le faire également (la réponse de défi est alors un 407 et la réponse du client est dans un en-tête Proxy-Authorization:). Les codes de retour liés à l'authentification (301 et 307) sont décrits en détail dans la section 3 et stockés dans le registre IANA des codes de retour. Voici un exemple, vu avec curl, d'un site faisant une authentification par mot de passe :


% curl -v https://icinga.example.org/icinga/
...
> GET /icinga/ HTTP/1.1
> Host: icinga.example.org
> 
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Basic realm="Icinga Access"
...

Et, si on indique via curl le mot de passe (si on s'en sert souvent, on peut aussi mettre le mot de passe dans ~/.netrc) :


% curl -u icinga:vachementsecret -v https://icinga.example.org/icinga/
...
> GET /icinga/ HTTP/1.1
> Authorization: Basic aWNpbmdhOnZhY2hlbWVudHNlY3JldA
> Host: icinga.example.org
...
< HTTP/1.1 200 OK

Notez que l'authentification se fait sur le canal HTTP (le mot de passe n'est pas chiffré, juste un peu brouillé) et que celui-ci a donc intérêt à être protégé (par exemple par TLS).

Un navigateur Web, recevant le défi (401), va automatiquement demander à l'utilisateur le mot de passe http-auth.png et le renverra, dans une seconde requête (et, en général, il mémorisera ce mot de passe, pour éviter de le demander à chaque requête HTTP ; HTTP est sans état, c'est le client qui mémorise et donne l'illusion d'une « session »).

Une fois qu'on est authentifié, on n'est pas forcément autorisé : si un client reçoit un 403, c'est qu'il n'est pas autorisé, même si son authenticité ne fait pas de doute.

Un concept important de l'authentification HTTP est celui de « royaume » (realm, section 2.2). Un royaume est un ensemble de ressources sur le serveur qui ont la même base d'utilisateurs. Un serveur peut partitionner ses ressources en plusieurs royaumes, par exemple pour utiliser plusieurs sources d'authentification différentes. Le royaume utilisé est transmis par le serveur dans le défi (en-tête WWW-Authenticate:).

La section 4 décrit en détail les en-têtes liés à l'authentification. Le WWW-Authenticate: contient le défi. Il est composé d'une indication du type d'authentification, avec le royaume utilisé, et d'éventuels paramètres. Par exemple, pour le type le plus simple, Basic, où le défi est vide, et où le client doit simplement envoyer identificateur et mot de passe, l'en-tête ressemblera à (pour le royaume Staff) :

WWW-Authenticate: Basic realm="Staff"

Quant au champ Authorization:, il est envoyé par le client en réponse à un défi (ou préventivement si le client sait que l'accès à la ressource est authentifié). Les informations qu'il contient dépendent du type d'authentification. Avec Basic, ce sont un identificateur et un mot de passe, séparés par un deux-points et encodés en Base64 (c'est normalisé dans le RFC 7617, section 2).

Au fait, la configuration du serveur Apache qui a servi pour les exemples plus haut :

<Directory>
  AuthName "Icinga Access"
  AuthType Basic
  AuthUserFile /etc/icinga/htpasswd.users
  Require valid-user
  ...

Et le fichier /etc/icinga/htpasswd.users est géré avec la commande htpasswd.

L'authentification auprès d'un relais, est identique, avec Proxy-Authenticate: et Proxy-Authorization: au lieu de WWW-Authenticate: et Authorization:.

Les différents mécanismes d'authentification (comme Basic) sont notés dans un registre IANA. Le registre inclut un lien vers la spécification de chaque mécanisme. Ainsi, le traditionnel Basic est dans le RFC 7617 et le récent Bearer dans le RFC 6750. Si vous voulez enregistrer un nouveau mécanisme, lisez aussi le RFC 7236 pour voir des exemples.

Tout nouveau mécanisme doit tenir compte des caractéristiques de HTTP. Par exemple, comme HTTP est sans état, le serveur ne doit pas avoir à se souvenir des requêtes précédentes : toutes les informations pour authentifier un client doivent être dans la requête.

La section 6 résume les problèmes de sécurité liés à l'authentification. Par exemple, le cadre général d'authentification de HTTP, spécifié dans ce RFC 7235, ne précise pas de mécanisme assurant la confidentialité des lettres de créance présentées. Ainsi, dans le cas du mécanisme Basic, le mot de passe est transmis en clair (on ne peut pas considérer Base64 comme un chiffrement...) Il faut donc prendre des précautions supplémentaires (TLS...) Notez qu'il n'y a pas que le mot de passe qui soit une donnée sensible : dans le cas de Basic, l'identificateur de l'utilisateur est également confidentiel.

Le mécanisme HTTP d'authentification, reposant sur un protocole sans état, ne fournit pas de durée de vie de l'authentification. Un client peut garder le mot de passe éternellement alors que le serveur voudrait, par exemple, obliger les clients qui avaient été absents longtemps à se ré-authentifier. Et si c'est le client qui veut annuler l'effet de son authentification, le mécanisme HTTP ne permet pas de fonction de « déconnexion ». C'est une des principales raisons pour lesquelles les applications qui authentifient les utilisateurs ne se servent pas souvent de l'authentification HTTP. Une autre raison est l'impossibilité d'adapter le dialogue de login, par exemple en mettant un lien vers une page de documentation. En pratique, la plupart des applications se servent donc d'un formulaire Web pour demander le mot de passe, puis d'un cookie (RFC 6265) pour chaque requête.

Les changements depuis les RFC 2616 et RFC 2617 ? Ils sont cités dans l'annexe A. Les deux principaux sont la révision de la grammaire des valeurs des en-têtes Authorization: et l'introduction d'une procédure d'enregistrement des nouveaux mécanismes d'authentification (un premier exemple est celui des mécanismes existants, dans le RFC 7236).


Téléchargez le RFC 7235


L'article seul

RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), M. Nottingham (Akamai), 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 juin 2014


Le protocole HTTP 1.1, désormais décrit dans une série de RFC, transporte énormément de données tous les jours et consomme donc à lui seul une bonne partie des ressources de l'Internet. D'où l'importance de l'optimiser. Une des méthodes les plus efficaces pour cela est le cache (terme anglais qui fait très bizarre en français : pour mieux accéder à une ressource, on la cache...). Ce RFC spécifie le modèle de cachage de HTTP et comment les clients et les serveurs peuvent l'utiliser. (Il a depuis été remplacé par le RFC 9111.)

Un cache Web est un espace de stockage local où on peut conserver la représentation d'une ressource qu'on a récupérée. Si la même ressource est à nouveau désirée, on pourra la récupérer depuis le cache, plus proche et donc plus rapide que le serveur d'origine. Outre le temps d'accès, le cachage a l'avantage de diminuer la consommation de capacité réseau. Un cache peut être partagé entre plusieurs utilisateurs, augmentant ainsi les chances qu'une ressource désirée soit présente, ce qui améliore l'efficacité. Comme tous les caches, les caches Web doivent gérer le stockage, l'accès et la place disponible, avec un mécanisme pour gérer le cas du cache plein. Comme tous les caches, les caches Web doivent aussi veiller à ne servir que de l'information fraîche. Cette fraîcheur peut être vérifiée de différentes façons, y compris par la validation (vérification auprès du serveur d'origine). Donc, même si l'information stockée dans le cache n'est pas garantie fraîche, on pourra quand même l'utiliser, si le serveur d'origine confirme qu'elle est toujours utilisable (dans ce cas, on aura quand même un accès réseau distant à faire, mais on évitera de transférer une ressource qui peut être de grande taille).

Le cache est optionnel pour HTTP, mais recommandé, et utiliser un cache devrait être le comportement par défaut, afin d'épargner le réseau, pour lequel HTTP représente une bonne part du trafic.

On peut garder en cache plusieurs sortes de réponses HTTP. Bien sûr, le résultat d'une récupération après un GET (code 200, cf. RFC 7231) est cachable et représente l'utilisation la plus courante. Mais on peut aussi conserver dans le cache le résultat de certaines redirections, ou bien des résultats négatifs (un code 410, indiquant que la ressource est définitivement partie), ou même le résultat de méthodes autres que GET (bien que cela soit plus rare en pratique).

Ici, un exemple où une page a été stockée par un cache Squid, et récupérée ensuite. L'argument de GET est l'URI complet, pas juste le chemin :


% curl -v http://www.w3.org/WAI/
...
> GET http://www.w3.org/WAI/ HTTP/1.1
> User-Agent: curl/7.26.0
> Host: www.w3.org
...
< HTTP/1.0 200 OK
< Last-Modified: Thu, 12 Jun 2014 16:39:11 GMT
< ETag: "496a-4fba6335209c0"
< Cache-Control: max-age=21600
< Expires: Sun, 15 Jun 2014 15:39:30 GMT
< Content-Type: text/html; charset=utf-8
< Age: 118
< X-Cache: HIT from cache.example.org
< X-Cache-Lookup: HIT from cache.example.org:3128
< Via: 1.1 cache.example.org:3128 (squid/2.7.STABLE9)
...
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Le client HTTP curl suit la variable d'environnement http_proxy et contacte donc le relais/cache Squid en cache.example.org en HTTP. À son tour, celui-ci se connectera au serveur d'origine si nécessaire (ce ne l'était pas ici, l'information a été trouvée dans le cache, comme l'indique la mention HIT.)

Les données stockées dans le cache sont identifiées par une clé (section 2 de notre RFC). Pour un cache simple, qui ne gère que GET, la clé principale est l'URI de la ressource convoitée. On verra plus loin que la clé est en fait plus complexe que cela, en raison de certaines fonctions du protocole HTTP, comme la négociation de contenu, qui impose d'utiliser comme clé certains en-têtes de la requête.

La section 3 du RFC normalise les cas où le cache a le droit de stocker une réponse, pour réutilisation ultérieure. Le RFC définit ces cas négativement : le cache ne doit pas stocker une réponse sauf si toutes ces conditions sont vraies :

  • La méthode est cachable (c'est notamment le cas de GET),
  • Le code de retour est compris du cache (200 est le cas évident),
  • Il n'y a pas de directive dans la réponse qui interdise le cachage (en-tête Cache-Control:, voir plus loin),
  • L'accès à la ressource n'était pas soumis à autorisation (cf. RFC 7235), dans le cas d'un cache partagé entre plusieurs utilisateurs,
  • La réponse contient des indications permettant de calculer la durée de vie pendant laquelle elle restera fraîche (comme l'en-tête Expires:).

Un cache peut stocker des réponses partielles, résultat de requêtes avec intervalles (cf. RFC 7233), si lui-même comprend ces requêtes. Il peut concaténer des réponses partielles pour ensuite envoyer une ressource complète.

Une fois la ressource stockée, le cache ne doit pas la renvoyer sauf si (là encore, la norme est formulée de manière négative, ce qui est déroutant) toutes ces conditions sont vraies :

  • Les URI correspondent,
  • Les en-têtes désignés par l'en-tête Vary: correspondent (cela concerne surtout le cas où il y a négociation du contenu),
  • La requête ne contient pas de directive interdisant de la servir avec des données stockées dans le cache,
  • La ressource stockée est encore fraîche, ou bien a été re-validée avec succès.

L'exigence sur la clé secondaire (les en-têtes sur lesquels se fait la négociation de contenu) est là pour s'assurer qu'on ne donnera pas à un client une ressource variable et correspondant aux goûts d'un autre client. Si le client dont la requête a déclenché la mise en cache avait utilisé l'en-tête Accept-Language: fr indiquant qu'il voulait du français, et que le second client du cache demande la même ressource, mais avec Accept-Language: en, il ne faut évidemment pas donner la copie du premier client au second. Si la réponse avait l'en-tête Vary: accept-language indiquant qu'elle dépend effectivement de la langue, le cache ne doit la donner qu'aux clients ayant le même Accept-Language:.

Et la fraîcheur, elle se définit comment (section 4.2, une des plus importantes du RFC) ? Le cas le plus simple est celui où le serveur d'origine envoie un en-tête Expires (ou une directive max-age), par exemple Expires: Mon, 15 Jun 2015 09:33:06 GMT (un an dans le futur). Dans ce cas, la ressource gardée en cache est fraîche jusqu'à la date indiquée. Attention : les formats de date de HTTP sont compliqués et il faut être prudent en les analysant. Si le Expires: indique une date syntaxiquement incorrecte, le cache doit supposer le pire et considérer que la ressource a déjà expiré. En pratique, bien des serveurs HTTP ne fournissent pas cet en-tête Expires: et le cache doit donc compter sur des heuristiques. La plus courante est d'utiliser le champ Last-Modified: et de considérer que, plus le document est ancien, plus il restera frais longtemps (section 4.2.2). (La FAQ de Squid explique bien l'heuristique de ce logiciel de cache.) Le RFC ne normalise pas une heuristique particulière mais met des bornes à l'imagination des programmeurs : ces heuristiques ne doivent être employées que s'il n'y a pas de date d'expiration explicite, et la durée de fraîcheur doit être inférieure à l'âge du document (et le RFC suggère qu'elle ne soit que 10 % de cet âge). Par contre, l'ancienne restriction du RFC 2616 contre le fait de garder en cache des documents dont l'URL comprenait des paramètres (après le point d'interrogation) a été supprimée. Un serveur ne doit donc pas compter que ces documents seront forcément re-demandés. Il doit être explicite quant à la durée de vie de ces documents.

Dans sa réponse, le cache inclut un en-tête Age:, qui peut donner au client une idée de la durée depuis la dernière validation (auprès du serveur d'origine). Par exemple, Age: 118, dans le premier exemple, indiquait que la page était dans le cache depuis presque deux minutes.

Une réponse qui n'est pas fraîche peut quand même être renvoyée au client dans certains cas, notamment lorsqu'il est déconnecté du réseau et ne peut pas donc valider que sa copie est toujours bonne. Le client peut empêcher cela avec Cache-Control: must-revalidate.

Comment se fait cette validation dont on a déjà parlé plusieurs fois ? Lorsque le serveur a une copie d'une ressource, mais que sa date maximum de fraîcheur est dépassée, il peut demander au serveur d'origine. Cela se fait typiquement par une requête conditionnelle (cf. RFC 7232) : si le serveur a une copie plus récente, il l'enverra, autrement, il répondra par un 304, indiquant que la copie du cache est bonne. La requête conditionnelle peut se faire avec un If-Modified-Since: en utilisant comme date celle qui avait été donnée dans le Last-Modified:. Ou bien elle peut se faire avec l'entity tag et un If-None-Match: :


% telnet cache 3128
...
GET http://www.w3.org/WAI/ HTTP/1.1
Host: www.w3.org
If-None-Match: "496a-4fba6335209c0"

HTTP/1.0 304 Not Modified
Date: Sun, 15 Jun 2014 09:39:30 GMT
Content-Type: text/html; charset=utf-8
Expires: Sun, 15 Jun 2014 15:39:30 GMT
Last-Modified: Thu, 12 Jun 2014 16:39:11 GMT
ETag: "496a-4fba6335209c0"
Age: 418
X-Cache: HIT from cache.example.org
X-Cache-Lookup: HIT from cache.example.org:3128
Via: 1.0 cache.example.org:3128 (squid/2.7.STABLE9)
Connection: close

Le cache peut aussi utiliser la méthode HEAD pour tester sa copie locale auprès du serveur d'origine, par exemple pour invalider la copie locale, sans pour autant transférer la ressource.

La section 5 liste tous les en-têtes des requêtes et des réponses qui sont utilisés pour le bon fonctionnement des caches, comme Age:, Expires:, etc. Ils sont enregistrés à l'IANA, dans le registre des en-têtes. Notons parmi eux le peu connu (et peu mis en œuvre, au point que ce RFC supprime plusieurs possibilités avancées de cet en-tête) Warning: qui permet de transférer des informations utiles au cache mais qui ne tiennent pas dans les autres en-têtes. Par exemple, un serveur peut indiquer qu'il ne sera pas joignable (pour revalidation), avec le code d'avertissement 112 (ces codes sont dans un registre spécial) :

HTTP/1.1 200 OK
Date: Sat, 25 Aug 2012 23:34:45 GMT
Warning: 112 - "network down" "Sat, 25 Aug 2012 23:34:45 GMT"

Parmi ces en-têtes, Cache-Control: (autrefois Pragma:) permet de spécifier des directives concernant le cache. Un client d'un cache peut spécifier l'âge maximum qu'il est prêt à accepter (directive max-age), une fraîcheur minimum (directive min-fresh), que la ressource ne doit pas être stockée dans le cache (directive no-store, qui est là pour des raisons de vie privée mais, bien sûr, est loin de suffire pour une véritable confidentialité), ou bien qu'elle peut être stockée mais ne doit pas être servie à un client sans revalidation (directive no-cache), etc. Les directives possibles sont stockées dans un registre IANA.

L'en-tête Cache-Control: peut aussi être utilisé dans des réponses. Un serveur peut lui aussi indiquer no-cache, typiquement parce que ce qu'il envoie change fréquemment et doit donc être revalidé, private s'il veut insister sur le fait que la réponse n'était destinée qu'à un seul utilisateur et ne doit donc pas être transmise à d'autres, etc.

À noter qu'un cache HTTP n'est pas forcément un serveur spécialisé. Tous les navigateurs Web ont des fonctions d'historique (comme le bouton Back). Est-ce que celles-ci nécessitent des précautions analogues à celles des caches, pour éviter que le navigateur ne serve des données dépassées ? Pas forcément, dit le RFC, qui autorise un navigateur à afficher une page peut-être plus à jour lorsqu'on utilise le retour en arrière dans l'historique.

La section 8 détaille les problèmes de sécurité qui peuvent affecter les caches. Un cache, par exemple, peut permettre d'accéder à une information qui n'est plus présente dans le serveur d'origine, et donc de rendre plus difficile la suppression d'une ressource. Un cache doit donc être géré en pensant à ces risques. Plus grave, l'empoisonnement de cache : si un malveillant parvient à stocker une fausse représentation d'une ressource dans un cache (avec une longue durée de fraîcheur), tous les utilisateurs du cache recevront cette information au lieu de la bonne. Un cache peut avoir des conséquences pour la vie privée : en demandant une ressource à un cache partagé, un utilisateur peut savoir, à partir du temps de chargement et d'autres informations envoyées par le cache, si un autre utilisateur avait déjà consulté cette page.

L'annexe A liste les différences depuis le texte précédent, celui du RFC 2616, section 13. Elles sont nombreuses (le texte a été réécrit) mais portent surtout sur des détails, par exemple des précisions sur les conditions exactes dans lesquelles on peut garder une information dans le cache. Depuis, un autre changement a eu lieu avec le remplacement de notre RFC par le RFC 9111.

Notez que le RFC 8246 a ajouté une extension à Cache-Control:, pour indiquer l'immuabilité d'une ressource.


Téléchargez le RFC 7234


L'article seul

RFC 7233: Hypertext Transfer Protocol (HTTP/1.1): Range Requests

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), Y. Lafon (W3C), 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 juin 2014


Parmi les fonctions du protocole HTTP 1.1 qui ont eu droit à un RFC spécifique, les intervalles. C'est la possibilité de récupérer en HTTP, non pas la totalité d'une ressource mais une partie, un intervalle (range) de celle-ci. Ce RFC les décrivait mais a été ensuite supplanté par le RFC 9110.

Cette fonction est utile, par exemple, lorsqu'un transfert est interrompu en cours de route et qu'on voudrait pouvoir reprendre le téléchargement au point où il s'était arrêté, et non pas bêtement depuis le début. C'est possible avec le protocole rsync, comment faire avec HTTP ? Le client lit la partie déjà téléchargée, note sa taille, et demande au serveur le reste, en utilisant les intervalles. D'autres usages sont possibles comme de ne récupérer qu'une partie d'un document quand on n'a pas la possibilité de le traiter en entier. Attention, toutefois, ces intervalles sont optionnels pour les serveurs HTTP et un serveur qui ne les gère pas va vous envoyer toutes les données, même si vous n'aviez demandé qu'une partie.

Voici un exemple d'utilisation de ces intervalles avec le client HTTP curl et son option -r (--range en version longue). Ici, on récupère la fin du fichier, à partir du 20 001 ème octet (on compte en partant de zéro), et jusqu'à la fin :


% curl  -v --range "20000-" http://www.bortzmeyer.org/images/moi.jpg > moi-partiel.jpg

> GET /images/moi.jpg HTTP/1.1
> Range: bytes=20000-

< HTTP/1.1 206 Partial Content
< Accept-Ranges: bytes
< Content-Length: 34907
< Content-Range: bytes 20000-54906/54907
...

Vous avez vu les en-têtes utilisés pour décrire les intervalles. Notez qu'avec curl, on peut aussi mettre directement les en-têtes (par exemple --header "Range: bytes=20000-" au lieu de --range "20000-") mais c'est déconseillé car cela ne corrige pas les erreurs de syntaxe.

Maintenant, comment cela fonctionne t-il sur le câble, lorsqu'on examine le trafic HTTP ? D'abord, un mot sur les unités utilisées. L'en-tête Range: peut indiquer l'intervalle en octets, comme plus haut, ou dans d'autres unités (pour l'instant, aucune n'a été normalisée, lorsque ce sera le cas, elles seront ajoutées dans le registre IANA). L'avantage des octets est qu'ils conviennent à tous les types de ressources, les représentations des ressources étant transférées sous forme d'un flot d'octets. L'inconvénient est qu'ils ne tiennent pas compte de la syntaxe sous-jacente de la ressource. Par exemple, pour un fichier CSV, il serait sans doute plus pratique d'indiquer l'intervalle en nombre de lignes, pour permettre de récupérer un fichier non corrompu, mais cela supposerait un serveur HTTP qui connaisse la syntaxe CSV. Autre exemple d'une limite des octets : pour un fichier texte seul dont le jeu de caractères est Unicode, le nombre de caractères serait certainement une unité plus pertinente que le nombre d'octets (avec des octets, on risque de récupérer un fichier où certains caractères ne soient pas complets). Mais les serveurs HTTP ne savent pas forcément analyser les encodages d'Unicode, comme UTF-8.

Les intervalles peuvent être ouverts ou fermés. Un exemple d'intervalle fermé est bytes=500-999 qui spécifie le deuxième groupe de 500 octets de la ressource, de l'octet 500 (inclus) à l'octet 999 (inclus aussi). Un intervalle ouvert est bytes=-999 qui indique les 999 derniers octets du fichier (notez que le 999 n'a donc pas du tout la même signification selon qu'il y a un chiffre avant le tiret ou pas). On peut indiquer plusieurs intervalles discontinus, par exemple bytes=500-600,601-999. Ces intervalles doivent être dans l'ordre croissant et n'ont pas le droit de se recouvrir. Attention, un client facétieux ou malveillant peut utiliser des chiffres très grands pour un intervalle ou bien des intervalles qui se recoupent, ce qui, dans au moins un cas avec Apache, a mené à une faille de sécurité (voir aussi la section 6.1 sur ce problème de sécurité).

Le serveur peut indiquer quelles unités il accepte pour les intervalles avec l'en-tête Accept-Ranges:, par exemple :

Accept-Ranges: bytes

Le client, pour indiquer qu'il ne demande qu'une partie de la représentation d'une ressource, utilise, on l'a vu dans l'exemple plus haut, l'en-tête Range:. Combiné avec la requête GET, cet en-tête indique que le serveur, s'il est d'accord, s'il gère l'unité indiquée, et si la syntaxe est correcte, peut n'envoyer que la partie demandée. Ces en-têtes spécifiques aux requêtes avec intervalle sont stockés dans le registre IANA des en-têtes.

Un cas un peu plus compliqué est celui où le client a récupéré une partie d'une ressource, la ressource a été modifiée sur le serveur, le client veut récupérer le reste. Les intervalles demandées par le client ne signifient alors plus rien. Un mécanisme peu connu existe pour traiter ce cas : l'en-tête If-Range:, suivi d'un validateur (cf. RFC 7232) dit au serveur « envoie-moi seulement l'intervalle, s'il n'y a pas eu de changement depuis ce validateur, ou bien tout le fichier sinon ».

Quelles sont les réponses spécifiques aux requêtes avec intervalles ? La section 4 en donne la liste (elles ne sont que deux, dans les autres cas, le code de retour est un classique, comme par exemple 200 pour un transfert complet réussi, et sont dans le registre IANA). D'abord, il y a 206 qui signifie un succès (classe = 2) mais qui prévient que, comme demandé, seule une partie du contenu a été envoyé. Le serveur doit inclure un en-tête Content-Range: dans la réponse, indiquant ce qui a été réellement envoyé (regardez l'exemple curl au début). Si plusieurs intervalles étaient spécifiés dans la requête, le résultat est transporté dans une structure MIME de type multipart/byteranges décrite dans l'annexe A. Chaque partie de la réponse aura son propre Content-Range: indiquant où elle se situe dans la ressource originale.

L'autre code de retour possible est 416 qui indique une erreur (classe = 4) car l'intervalle indiqué n'est pas admissible. Par exemple, il y a recouvrement entre les intervalles, ou bien l'octet de départ est situé après la fin du fichier. Attention, rappelez-vous que les intervalles sont optionnels, un serveur peut ignorer l'en-tête Range: et, dans ce cas, répondre systématiquement avec un 200 en envoyant tout le contenu de la ressource.

Les changements depuis le RFC 2616 ? L'annexe B en fait la liste mais elle est courte, notre nouveau RFC est surtout une reformulation, avec peu de changements : insistance sur la liberté du serveur à honorer ou pas les requêtes avec intervalles, précisions sur les validateurs acceptables, création du registre des unités - même s'il ne compte pour l'instant qu'une seule unité, bytes...


Téléchargez le RFC 7233


L'article seul

RFC 7232: Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), 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 14 juin 2014


Dans la longue série des RFC sur le protocole HTTP 1.1, ce document relativement court se consacre aux requêtes HTTP conditionnelles : quand un client dit à un serveur « envoie-moi le contenu de cette ressource mais seulement si telle ou telle condition est vraie ». La principale utilité de ces requêtes conditionnelles est d'économiser la capacité réseau si le client a déjà une copie du contenu. Une autre utilité est de permettre la mise à jour d'un document si et seulement si il n'a pas été modifié depuis que le client a commencé à travailler dessus, évitant ainsi le problème de la « mise à jour perdue ». Il est maintenant dépassé par le RFC 9110.

Pour indiquer ces conditions, le client ajoute un ou plusieurs en-têtes (RFC 7231) à sa requête. Quels sont les éléments dont dispose le client pour indiquer les conditions ? On les nomme les validateurs. Deux validateurs sont très répandus, la date de dernière modification d'une ressource et l'étiquette de ressource (entity tag ou ETag). D'autres peuvent être définis, par exemple par WebDAV (RFC 4918). Un validateur est fort ou faible. Un validateur fort est un validateur dont la valeur change à chaque changement, même trivial, du contenu d'une ressource (les étiquettes sont dans ce cas, comme le sont les identifiants de commits d'un VCS comme git ou Subversion). Avec du contenu Web statique, et s'il n'y a pas de négociation du contenu, une façon simple de générer un validateur fort est de condenser le contenu de la ressource, et d'utiliser le condensat comme étiquette. Les validateurs forts sont idéaux (ils identifient précisement un état d'une ressource) mais souvent difficiles, voire impossibles, à générer. Au contraire, les validateurs faibles sont moins précis (plusieurs états d'une ressource peuvent correspondre à la même valeur du validateur) mais simples à générer. Par exemple, une date de dernière modification est un validateur faible : si sa résolution est d'une seconde, et que deux changements de la ressource sont faits dans la même seconde, le validateur ne changera pas. HTTP permet les deux, chacun ayant son utilité. Mais le développeur qui se sert des validateurs pour son application a fortement intérêt à connaître la différence ! Le RFC donne l'exemple de rapports météorologiques : pour éviter qu'un rapport reste dans un cache Web (RFC 7234) alors qu'une version plus récente existe sur le serveur d'origine, le gérant de cette base de rapports doit veiller à ce que les validateurs changent quand le contenu change. D'une manière générale, les validateurs faibles sont acceptables quand on veut juste optimiser les coûts (cas des caches) mais lorsqu'on veut modifier un contenu et éviter l'effet « perte de mise à jour », il faut utiliser un validateur fort.

Comment un serveur HTTP communique-t-il un validateur au client ? Via les en-têtes de la réponse (section 2.2 du RFC). Il y a deux en-têtes possibles :

  • Last-Modified: qui indique la date de dernière modification de la ressource,
  • ETag: qui indique une étiquette identifiant une version spécifique de la ressource.

Le RFC prescrit à tout serveur HTTP d'envoyer systématiquement un Last-Modified: dès lors qu'il peut déterminer la date de modification (si la ressource est assemblée à partir de plusieurs éléments, c'est le plus récent qui compte). Cela permettra d'utiliser plus souvent les caches et donc de diminuer la consommation de capacité réseau. Un exemple de cet en-tête (la dernière ligne) :


% curl -v http://verite/
> GET / HTTP/1.1
...
< HTTP/1.1 200 OK
< Server: nginx/1.6.0
< Date: Thu, 29 May 2014 19:45:17 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Thu, 24 Apr 2014 14:14:52 GMT

Dans la grande majorité des cas, le Last-Modified: est un validateur faible. (Ne serait-ce que parce que la ressource peut changer deux fois en une seconde, ce qui ne changera pas le Last-Modified:.)

Le ETag:, lui, est un identificateur opaque. Il est en général plus difficile à générer pour le serveur mais bien plus fiable (il évite notamment le problème des « deux changements dans la même seconde »). En général, c'est un validateur fort. Un exemple :


% curl -v http://verite/toto.txt
...
> GET /toto.txt HTTP/1.1
...
< HTTP/1.1 200 OK
< Server: nginx/1.6.0
...
< ETag: "53878f56-5"

Comme c'est un identificateur opaque, seul le serveur sait comment il a été généré. Premier critère avant de choisir une méthode de génération : garantir que deux versions différentes d'une ressource auront deux ETag différents. Deux méthodes courantes pour le générer sont l'utilisation d'un numéro de révision interne (par exemple si les ressources sont stockées dans un VCS) ou bien l'utilisation d'une fonction de condensation. Là encore, le RFC demande que le serveur envoie une étiquette si possible, sauf s'il y a de bonnes raisons, par exemple de performance. Donc, un serveur qui suit le RFC de près enverra les deux validateurs, la date et l'étiquette, en réponse à chaque requête.

Comment le client utilise-t-il ce validateur (section 3) ? Il dispose d'un choix d'en-têtes à mettre dans la requête permettant de dire au serveur « agis sur la ressource si et seulement si telle condition portant sur les validateurs est vraie ». Par exemple, l'en-tête If-Match: indique une condition portant sur l'étiquette :

If-Match: "4149d-88-4b1795d0af140"

La condition ci-dessus, dans une requête GET, POST ou autre, signifie au serveur de n'agir que si la ressource correspond à l'étiquette indiquée. Pour une méthode modifiant l'état de la ressource (comme POST ou PUT), cela permet d'éviter le syndrome de la mise à jour perdue. Voici un exemple, n'utilisant pas les requêtes conditionnelles :

  • Le client récupère avec GET une ressource,
  • Il la modifie localement,
  • Pendant ce temps, la ressource a été modifiée sur le serveur, peut-être par un autre client,
  • Le client veut enregistrer sa version et fait un PUT. Les modifications de l'étape précédente sont donc perdues.

Avec les requêtes conditionnelles, on aurait eu :

  • Le client récupère avec GET une ressource, et obtient un validateur fort, l'étiquette e68bd4cc10e12c79ff830b0ec820ef6b,
  • Il la modifie localement,
  • Pendant ce temps, la ressource a été modifiée sur le serveur, peut-être par un autre client,
  • Le client veut enregistrer sa version et fait un PUT en ajoutant un If-Match: "e68bd4cc10e12c79ff830b0ec820ef6b". Le serveur calcule l'étiquette (ici, c'est un condensat MD5), voit qu'elle ne correspond pas, et refuse le PUT avec un code 412. Les modifications de l'étape précédente ne sont pas perdues.

If-Match: est surtout utile dans les opérations modifiant la ressource comme PUT. Son opposé If-None-Match: sert plutôt pour les GET lorsqu'un cache dit à un serveur « envoie-moi une copie si elle est différente de celle que j'ai déjà ». Notez que If-None-Match: peut prendre comme valeur une liste de ETags.

Il y a aussi des pré-conditions qui portent sur la date de modification et non plus sur l'étiquette. Ce sont If-Modified-Since: et If-Unmodified-Since:. Si on envoie :

If-Modified-Since: Mon, 26 May 2014 19:43:31 GMT

dans une requête GET, on ne recevra le contenu de la ressource que s'il est plus récent que le 26 mai 2014. Autrement, on aura un 304, indiquant que le contenu n'a pas été changé depuis. C'est ainsi qu'un cache peut s'assurer que la copie qu'il détient est toujours valable, sans pour autant consommer de la capacité réseau. C'est également utile pour un crawler, par exemple celui d'un moteur de recherche qui ne veut pas récupérer et indexer un contenu qu'il connait déjà. Le cache qui a reçu un Last-Modified: au dernier GET conserve la valeur de ce Last-Modified: et la renvoie dans un If-Modified-Since: la fois suivante. curl a des options pour cela. Ici, un script de téléchargement qui trouve dans un fichier la date de dernière modification, et ne télécharge que si le fichier est plus récent :

ltr_date=`head -n 1 ${LTR_LOCAL} | cut -d" " -f2`
# Allow time to elapse. The date of the file at IANA is often the day after
# the date written in the LTR. Heuristically, we add one day and a few hours.
current_date=`date +"%Y%m%d %H:%M:%S" --date="${ltr_date} +1 day +4 hour"`
...
curl --time-cond "${current_date}" ...

Ces en-têtes sont enregistrés à l'IANA. Leur usage est facultatif pour le serveur HTTP et, par exemple, nginx ignore ces en-têtes, limite signalée depuis pas mal de temps.

La section 4 liste les deux codes de retour HTTP en rapport avec ces requêtes conditionnelles. 304 indique que le contenu n'a pas été modifié depuis la date donnée et le serveur redirige (d'où le 3xx) le client vers sa copie locale pré-existante. 412 indique qu'une pré-condition nécessaire n'est pas vraie. C'est en général le résultat d'une requête avec If-Match: lorsque l'étiquette ne correspond plus au contenu de la ressource. Ces deux codes sont dans le registre IANA.

Les sections 5 et 6 précisent l'ordre d'évaluation des pré-conditions, entre elles, et par rapport aux autres critères de recherche. Notamment, les pré-conditions ne sont pas utilisées si la ressource n'existe pas ou si son accès est interdit. Si on a un 404 (ressource non trouvée) sans pré-conditions, on aura le même 404 avec pré-conditions, l'existence de la ressource est testée avant les pré-conditions.

Et les pré-conditions entre elles, puisqu'on peut en avoir plusieurs dans une requête ? Le serveur doit évaluer dans cet ordre (en supposant à chaque fois que l'en-tête en question soit présent ; sinon, on saute au test suivant) :

  • D'abord, If-Match:, car il faut avant tout éviter la mise à jour perdue,
  • Ensuite If-Unmodified-Since: (qui passe après car les dates sont moins fiables que les étiquettes),
  • Ensuite If-None-Match: (il sert à la validation des caches, ce qui est moins crucial que d'empêcher la mise à jour perdue),
  • Et enfin If-Modified-Since:.

Et, pour finir, quelques considérations de sécurité, en section 8. D'abord, les validateurs ne sont pas des mécanismes de contrôle d'intégrité, comme peut l'être une signature numérique (le serveur peut mentir, ou un tiers situé sur le trajet a pu modifier les en-têtes en vol). Ensuite, les étiquettes, les ETag peuvent poser des problèmes de protection de la vie privée : un serveur méchant peut générer une étiquette unique pour un client donné ce qui, lorsque le client reviendra et enverra des If-Match: ou If-None-Match: permettra de le reconnaître. Une sorte de cookie caché, donc. Un navigateur Web doit donc les traiter comme tel (oublier les étiquettes lorsque l'utilisateur vide le stock des cookies, par exemple).

L'annexe A dresse une liste des différences par rapport aux sections correspondantes du RFC 2616. Rien de fondamental mais la définition de la force et de la faiblesse des validateurs a été étendue et précisée, et une définition de l'ordre d'évaluation des pré-conditions a été ajoutée.


Téléchargez le RFC 7232


L'article seul

RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), 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 14 juin 2014


Ce RFC est le deuxième plus important de la longue série des nouveaux RFC décrivant le protocole HTTP 1.1. Le premier, le RFC 7230 décrivait les principes généraux, les URI et la syntaxe des messages. Ce second RFC fournit la sémantique desdits messages. Il est donc assez long, mais facile à comprendre car il consiste surtout en une liste détaillée de champs d'en-têtes, de codes de retour, etc. Il a depuis été remplacé par le RFC 9110.

Si on veut comprendre HTTP 1.1 en détail, il faut donc commencer par le RFC 7230. Ensuite, on peut lire ce RFC 7231 mais la plupart des gens l'utiliseront sans doute uniquement comme référence, pour vérifier un point particulier de la norme. Rappelons juste qu'un message HTTP est soit une requête, soit une réponse, et que requête ou réponse sont composées d'une première ligne, puis d'une série de champs (formant l'en-tête de la requête ou de la réponse) et éventuellement d'un corps. La première ligne d'une requête est une méthode (comme GET), qui donne le sens principal de la requête (l'en-tête pouvant légèrement modifier cette sémantique) et ses paramètres, la première ligne d'une réponse est surtout composée d'un code de retour, les fameux trois chiffres.

Les méthodes des requêtes (comme GET ou POST) agissent sur des ressources (section 2 de notre RFC). Les ressources peuvent être n'importe quoi. Au début du Web, c'étaient forcément des fichiers mais cela a évolué par la suite et c'est désormais un concept bien plus abstrait. Une ressource est identifiée par un URI (RFC 3986 et section 2.7 du RFC 7230). Notez donc qu'on spécifie indépendemment méthode et ressource (contrairement à d'autres systèmes hypertextes où c'était l'identificateur qui indiquait l'action souhaitée).

La ressource, vous l'avez vu, est une notion assez abstraite. On ne peut interagir avec elle que via l'étroite interface de HTTP, sans savoir comment le serveur à l'autre bout gère les ressources (fichier ? extraction dynamique d'une base de données ? autre processus ?) Cette abstraction est à la base du principe « REST ». Mais la ressource a une représentation (section 3 de notre RFC), qui est une suite d'octets, quelque chose de concret, donc. Une même ressource peut avoir plusieurs représentations. Un exemple simple est celui où la ressource est une image et où il y a une représentation en JPEG, une en PNG, etc. Les différentes représentations seront des suites d'octets complètement différentes les unes des autres alors qu'elles représenteront « la même » image.

Le choix de la représentation est fait par le mécanisme dit de « négociation du contenu ».

Les représentations sont étiquetées avec un type de média (dit aussi type MIME) à la syntaxe bien connue « type/sous-type » comme image/png. En plus du type et du sous-type, ils peuvent contenir des paramètres comme le charset (terme impropre car c'est en fait un encodage), charsets qui sont enregistrés à l'IANA, suivant le RFC 2978. Le tout est mis dans le champ Content-type: comme, par exemple :

Content-Type: text/html; charset=UTF-8

Malheureusement, les serveurs HTTP ne sont pas toujours correctement configurés et les étiquettes de type/sous-type peuvent être incorrectes. Certains navigateurs Web tentent de résoudre le problème en analysant la représentation (ce qu'on nomme le « content sniffing ») mais cette pratique, peu fiable, est déconseillée par notre RFC, notamment pour des raisons de sécurité (il existe des logiciels malveillants encodés de façon à sembler une image GIF pour certains logiciels et un exécutable Windows pour d'autres).

Outre ce type/sous-type, la représentation a d'autres métadonnées. Par exemple, on peut indiquer une langue, soit dans la requête (la langue qu'on veut), soit dans la réponse (la langue obtenue). La langue est codée par une étiquette de langue (RFC 5646) comme fr, az-Arab ou en-AU. En pratique, demander des langues spécifiques n'a guère d'intérêt car la qualité de la traduction n'est pas prise en compte. Si je préfère le français, mais que je peux lire l'anglais, une demande dans cet ordre me donnera surtout des pages Web mal traduites en français.

Les méthodes de HTTP font l'objet de la section 4 de notre RFC. Certaines méthodes sont sûres, c'est-à-dire qu'elles sont en lecture seule : elles ne modifient pas les ressources sur le serveur. On peut donc les utiliser sans modération. Les méthodes peuvent être idempotentes, c'est-à-dire que leur application répétée produit un résultat identique à une application unique. Toute méthode sûre est idempotente (puisqu'elle ne change pas la ressource) mais l'inverse n'est pas vrai. Enfin, certaines méthodes sont qualifiées de « cachables » (désolé pour l'affreux terme, et qui est faux en plus car il ne s'agit pas de dissimuler quoi que ce soit, c'est une allusion aux caches dans les réseaux). Les réponses peuvent potentiellement être gardées en mémoire pour resservir. Toutes les méthodes sûres sont cachables.

La reine des méthodes, la première définie, la plus courante est évidemment GET. C'est la méthode par défaut de la plupart des clients (par exemple, avec curl, c'est celle qui sera utilisée si on ne met pas l'option -X/--request). Elle demande au serveur d'envoyer une représentation de la ressource indiquée. Dans le cas du serveur HTTP le plus simple, les URI sont traduits en noms de fichiers locaux (et la syntaxe des URI reflète la syntaxe des noms de fichiers Unix) et ces fichiers sont alors simplement envoyés au client. Mais on peut mettre en œuvre GET de bien d'autres façons. GET est sûre et donc idempotente et cachable.

Utilisée surtout pour le débogage, la méthode HEAD ne transfère pas la représentation, mais uniquement le code de retour et les en-têtes de la réponse. Cela permet de tester un serveur sans épuiser la capacité réseau, par exemple dans un programme de vérification de liens. HEAD est sûre et donc idempotente et cachable. (Attention, certaines applications Web boguées renvoient un code de succès alors même qu'elles ont un problème ; pour vérifier le bon fonctionnement d'une telle application, il faut faire un GET et analyser le contenu, comme avec les options -r ou -s du check_http des plugins Nagios.)

Au contraire, POST n'est pas sûre : elle demande qu'on traite le contenu de la requête (avec GET, la requête n'a pas de contenu, juste l'en-tête) dans le cadre d'une ressource donnée. Son utilisation la plus connue est le cas où la ressource visée est un formulaire et où la requête contient les valeurs qui vont être placées dans les champs. Dans certains cas, POST est cachable (mais, en pratique, peu de logiciels de cache en profitent).

Plus radical, PUT remplace la ressource par le contenu de la requête (ou bien crée une ressource si elle n'existait pas déjà). Elle n'est évidemment pas sûre mais elle est idempotente (le résultat, qu'on applique la requête une fois ou N fois, sera toujours une ressource dont la représentation est le contenu de la requête). Le code de retour (voir la section 6 de notre RFC) sera différent selon que la ressource a été créée ou simplement remplacée. Dans le premier cas, le client récupérera un 201, dans le second un 200. PUT et POST sont souvent confondus et on voit souvent des API REST qui utilisent POST (plus courant et plus connu des développeurs) pour ce qui devrait être fait avec PUT. La différence est pourtant claire : avec un PUT, la ressource sur le serveur est remplacée (PUT est donc idempotente), alors qu'avec POST elle est modifiée pour intégrer les données envoyées dans le corps du POST.

Voici un exemple de PUT avec l'option -T de curl (qui indique le fichier à charger) :


% curl -v -T test.txt http://www.example.net/data/test.txt
> PUT /data/test.txt HTTP/1.1
> User-Agent: curl/7.37.0
> Host: www.example.net
> Accept: */*
> Content-Length: 7731
...
< HTTP/1.1 201 Created
< Server: nginx/1.6.0
< Date: Fri, 30 May 2014 20:38:36 GMT
< Content-Length: 0
< Location: http://www.example.net/data/test.txt

(Le serveur nginx était configuré avec dav_methods PUT;.)

La méthode DELETE permet de supprimer une ressource stockée sur le serveur, comme le ferait le rm sur Unix.

La méthode CONNECT est un peu particulière car elle n'agit pas réellement sur une ressource distante : elle dit au serveur de créer un tunnel vers une destination indiquée en paramètre et de relayer ensuite les données vers cette destination. Elle sert lorsqu'on parle à un relais Web et qu'on veut chiffrer le trafic de bout en bout avec TLS. Par exemple :

CONNECT server.example.com:443 HTTP/1.1
Host: server.example.com:443

va se connecter au port 443 de server.example.com.

Restent les méthodes OPTIONS et TRACE qui servent pour l'auto-découverte et le débogage. Rarement mises en œuvre et encore plus rarement activées, vous trouverez peu de serveurs HTTP qui les gèrent.

Une fois les méthodes étudiées, dans la section 4, place aux en-têtes envoyés après la ligne qui contient la méthode. C'est l'objet de la section 5 du RFC. Ces en-têtes permettent au client HTTP d'envoyer plus de détails au serveur, précisant la requête.

D'abord (section 5.1), les en-têtes de contrôle. Ce sont ceux qui permettent de diriger le traitement de la requête par le serveur. Le plus connu est Host:, défini dans le RFC 7230. Mais il y a aussi Expect:, qui permet de réclamer de la part du serveur qu'il mette en œuvre certaines fonctions. Si ce n'est pas le cas, le serveur peut répondre 417 (« I'm sorry, Dave »). La seule valeur actuellement définie pour Expect: est 100-continue qui indique que le client va envoyer de grandes quantités de données et veut recevoir une réponse intérimaire (code de réponse 100).

Les autres en-têtes de contrôle sont définis dans d'autres RFC de la famille. Ceux relatifs aux caches, comme Cache-Control: ou Pragma:, sont dans le RFC 7234. Range:, lui, figure dans le RFC 7233.

Après les en-têtes de contrôle, il y a ceux liés aux requêtes conditionnelles, comme If-Match: ou If-Modified-Since:. Ils sont décrits dans le RFC 7232.

Troisième catégorie d'en-têtes transmis lors des requêtes, ceux liés à la négociation de contenu (section 5.3), comme Accept:. Ils vont permettre d'indiquer le genre de contenu que le client préfère. Comme ces choix ne sont pas binaires (« je gère PNG et JPEG, ex-aequo, et je peux me débrouiller avec GIF s'il n'y a vraiment pas le choix »), les en-têtes de cette catégorie prennent un paramètre indiquant la qualité. Le paramètre se nomme q et sa valeur est le poids attribué à une certaine préférence, exprimée sous forme d'un nombre réel entre 0 et 1. Ainsi, lorsqu'une requête GET vient avec cet en-tête Accept: :

Accept: audio/*; q=0.2, audio/basic

elle indique que le client préfère audio/basic (pas de qualité indiquée donc on prend celle par défaut, 1). Pour l'exemple cité plus haut avec les formats d'image, cela pourrait être :

Accept: image/bmp; q=0.5, image/jpeg, image/gif; q=0.8, image/png

indiquant une préférence pour JPEG et PNG (pas de qualité indiquée, donc 1 pour tous les deux), avec un repli vers GIF et, dans les cas vraiment où il n'y a rien d'autre, BMP (notez que le type image/bmp n'est pas enregistré mais on le rencontre quand même souvent).

Même principe pour sélectionner un encodage des caractères avec Accept-Charset: (rappelez-vous que le terme charset utilisé à l'IETF est incorrect, il désigne plus que le jeu de caractères). Et l'encodage des données ? Il peut se sélectionner avec Accept-Encoding: :

Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0

(identity signifie « aucune transformation ». La qualité zéro indiquée à la fin signifie qu'en aucun cas on n'acceptera cette solution.)

Il existe enfin un en-tête Accept-Language: pour indiquer les langues préférées mais, en pratique, il ne sert pas à grand'chose.

Catégorie suivante d'en-têtes, ceux d'authentification. C'est le cas de Authorization: défini dans le RFC 7235.

Une dernière catégorie d'en-têtes est représentée par les en-têtes de contexte (section 5.5), qui donnent au serveur quelques informations sur son client. Ils sont trois, From: qui contient l'adresse de courrier électronique de l'utilisateur. Il n'est guère utilisé que par les robots, pour indiquer une adresse à laquelle se plaindre si le robot se comporte mal. En effet, son envoi systématique poserait des gros problèmes de protection de la vie privée. Le deuxième en-tête de cette catégorie est Referer: qui indique l'URI où le client a obtenu les coordonnées de la ressource qu'il demande. (À noter que le nom est une coquille ; en anglais, on écrit referrer.) Si je visite l'article de Wikipédia sur le Chaperon Rouge et que j'y trouve un lien vers http://www.example.org/tales/redridinghood.html, lors de la connexion au serveur www.example.org, le navigateur enverra :

Referer: http://fr.wikipedia.org/wiki/Le_Petit_Chaperon_rouge

Cet en-tête pose lui aussi des problèmes de vie privée. Il peut renseigner le serveur sur l'historique de navigation, les requêtes effectuées dans un moteur de recherche, etc. Notamment, le navigateur ne doit pas envoyer cet en-tête si l'URI de départ était local, par exemple de plan file:.

Enfin, User-Agent:, le troisième en-tête de contexte, permet d'indiquer le logiciel du client et son numéro de version. Comme certains sites Web, stupidement, lisent cet en-tête et adaptent leur contenu au navigateur (une violation hérétique des principes du Web), les navigateurs se sont mis à mentir de plus en plus, comme le raconte une jolie histoire. Par exemple, le navigateur que j'utilise en ce moment envoie :

User-Agent: Mozilla/5.0 (X11; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0 Iceweasel/29.0.1

(Au passage, si vous voulez voir tout ce que votre navigateur envoie, vous pouvez essayer ce service.)

Si vous utilisez Apache, et que vous voulez conserver, dans le journal, la valeur de certains en-têtes rigolos, Apache permet de le faire pour n'importe quel en-tête. Ainsi :

LogFormat "[%h]:%{remote}p %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %v" combinedv6

va enregistrer le Referer: et le User-Agent: ce qui donnera :

[2001:db8:22::864:89]:37127 - - [12/Jun/2014:10:09:17 +0200] "GET /greylisting.html HTTP/1.1" 200 3642 "http://fr.wikipedia.org/wiki/Greylisting" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36" www.bortzmeyer.org

J'ai déjà parlé du code de retour HTTP, les fameux trois chiffres qui indiquent si la requête a réussi ou pas. La section 6 le décrit plus en profondeur. Ce code est composé d'une classe, indiquée par le premier chiffre, et d'un code particulier dans les deux chiffres suivants. Des nouveaux codes sont régulièrement créés et un client HTTP doit donc se préparer à rencontrer de temps en temps des codes inconnus. En revanche, le nombre de classes est fixe. Ce sont :

  • 1xx : codes informatifs indiquant que la requête a été reçue mais le travail demandé n'est pas encore terminé (par exemple 100 qui signifie « patientez deux secondes, ça arrive » ou 101 lorsqu'on utilise WebSocket).
  • 2xx : la requête est un succès (le code le plus fréquent est 200 « tout va bien, voici ta réponse » mais il y en a plusieurs autres comme 201 indiquant que la ressource n'existait pas mais a été créée avec succès, par exemple par un PUT).
  • 3xx : codes de redirection, indiquant que le client va devoir aller voir ailleurs pour terminer sa requête (300 pour indiquer qu'il y a plusieurs choix possibles et que le client doit se décider). 301 et 302 permettent désormais de changer la méthode utilisée (POST en GET par exemple) 307 et 308 ne le permettent pas. 301 et 308 sont des redirections permanentes (le navigateur Web peut changer ses signets), les autres sont temporaires. Si vous utilisez Apache, la directive Redirect permet de faire des 301 (Redirect temp) ou des 302 (Redirect permanent), pour les autres, il faut indiquer explicitement le code (cf. la documentation). Attention à bien détecter les boucles (redirection vers un site qui redirige...)
  • 4xx : erreur située du côté du client, qui doit donc changer sa requête avant de réessayer. C'est par exemple le fameux 404, « ressource non trouvée » ou le non moins célèbre 403 « accès interdit ». À noter que, si vous êtes administrateur d'un serveur et que vous savez que la ressource a définitivement disparu, vous pouvez envoyer un 410, qui indique une absence définitive (Redirect gone /PATH dans Apache, au lieu d'un simple Redirect mais ce n'est pas forcément respecté.) Ah, et si vous voyez un 402, sortez vos bitcoins, cela veut dire Payment required.
  • 5xx : erreur située du côté du serveur, le client peut donc essayer une requête identique un peu plus tard (c'est par exemple le 500, « erreur générique dans le serveur » lorsque le programme qui produisait les données s'est planté pour une raison ou l'autre).

La liste complète des codes enregistrés (rappelez-vous qu'elle est parfois allongée) est stockée à l'IANA mais c'est plus rigolo de regarder la fameuse page des codes HTTP représentés par des chats, où les images ont été très bien choisies (ce sont des images de cette collection qui sont affichées par ce blog en cas d'erreur). Il existe aussi une page équivalente avec des chiens.

Derrière la première ligne de la réponse, celle qui contient ce code de retour en trois chiffres, les en-têtes de réponse. La section 7 du RFC les décrit en détail. Là encore, plusieurs catégories. La première est celle du contrôle. C'est le cas de Date: qui indique date et heure du serveur. Le format de cette information est un sous-ensemble de celui du RFC 5322 (et, hélas, pas du RFC 3339, bien plus simple et lisible). À noter qu'on trouve parfois des serveurs utilisant d'autres formats : c'était mal spécifié au début de HTTP. Un exemple avec le format recommandé :


% curl -v http://www.hackersrepublic.org/ 
...
< HTTP/1.0 200 OK
< Server: Apache/2.4.6
< Date: Sat, 14 Jun 2014 12:11:19 GMT

Location: sert en cas de redirection à indiquer le nouvel URI. Par exemple :


% curl -v http://www.bortzmeyer.org/eusthatius-test-grammars.html 
...
> GET http://www.bortzmeyer.org/eusthatius-test-grammars.html HTTP/1.1
...
< HTTP/1.0 301 Moved Permanently
< Date: Sat, 14 Jun 2014 12:13:21 GMT
< Location: http://www.bortzmeyer.org/eustathius-test-grammars.html

(Redirection mise en place suite à une coquille dans le lien depuis un site important.)

Le champ Vary: est plus subtil. Il indique de quels paramètres de la requête dépend le résultat obtenu. C'est indispensable pour les caches : si une réponse varie selon, mettons, la langue demandée, un autre client qui demande une autre langue ne doit pas recevoir le même contenu, même si l'URL est identique. Un cache Web doit donc utiliser comme clé d'une ressource, non pas l'URL seul mais la combinaison de l'URL et du contenu de Vary:. Voici un exemple sur ce blog, où le format d'image peut être négocié :


% curl -v http://www.bortzmeyer.org/images/nat66 
...
> GET /images/nat66 HTTP/1.1
> Accept: */*
...
< HTTP/1.1 200 OK
< Content-Location: nat66.gif
< Vary: negotiate,accept
...

C'est la version GIF qui a été choisie et le Vary: indique bien que cela dépendait de l'en-tête Accept:.

Troisième catégorie de réponses, les validateurs, comme Last-Modified:. Leur utilisation principale est pour des requêtes conditionnelles ultérieures (RFC 7232). Ainsi, une réponse avec un Last-Modified:, indiquant la date de dernier changement, permettra au client de demander plus tard « cette ressource, si elle n'a pas changé depuis telle date », limitant ainsi le débit réseau si la ressource est inchangée. Autre en-tête validateur, Etag:, dont la valeur est une étiquette (entity tag) identifiant de manière unique une version donnée d'une ressource. Ainsi :


% curl -v https://www.laquadrature.net/fr/snowden-terminator-et-nous
...
< HTTP/1.1 200 OK
< ETag: "da6e32e8d35ff7cf11f9c83d814b9328"
...

La ressource snowden-terminator-et-nous de ce serveur est identifiée par l'étiquette da6e32e8d35ff7cf11f9c83d814b9328 (probablement un condensat MD5).

Il y a deux autres catégories pour les en-têtes de réponse, la troisième comprend les en-têtes utilisées pour l'authentification (RFC 7235) comme WWW-Authenticate:. Et la quatrième est composée des en-têtes indiquant le contexte. La plus connue est Server: qui indique le(s) logiciel(s) utilisé(s) par le serveur. Par exemple, dans le cas de ce blog (et changeons un peu, utilisons wget au lieu de curl) :

% wget --server-response --output-document /dev/null http://www.bortzmeyer.org/
...
 HTTP/1.1 200 OK
 Server: Apache/2.2.22 (Debian)
 ...

La section 9.6 rappelle que, contrairement à une idée reçue, les indications sur la version du logiciel que transporte cet en-tête ne posent guère de problèmes de sécurité. Les attaquants ne s'y fient pas (ils savent que cet en-tête peut être modifié par l'administrateur du serveur et que, de toute façon, la vulnérabilité n'est pas liée à une version, certains systèmes patchent le logiciel mais sans changer le numéro de version) et essaient donc toutes les attaques possibles (le serveur HTTP qui héberge ce blog reçoit souvent des tentatives d'attaques exploitant des failles d'IIS, alors que c'est un Apache et qu'il l'annonce).

Toutes ces listes de codes, en-têtes, etc, ne sont pas figées. Régulièrement, de nouveaux RFC les mettent à jour et la version faisant autorité est donc stockée dans un registre à l'IANA. La section 8 rappelle la liste de ces registres :

  • Un nouveau registre pour les méthodes (GET, PUT, etc, le RFC 7237 enregistre formellement les anciennes méthodes). Les éventuelles nouvelles méthodes doivent être génériques, c'est-à-dire s'appliquer à tous les genres de ressources. Lors de l'enregistrement, il faudra bien préciser si la méthode est idempotente, sûre, etc.
  • Un autre registre pour les codes de retour comme 200 ou 404. L'ajout d'un nouveau code nécessite le processus IETF review décrit dans le RFC 5226, section 4.1.
  • Encore un autre pour les en-têtes, qu'ils soient dans les requêtes ou dans les réponses. Ce registre est partagé avec d'autres protocoles qui utilisent un format similaire, notamment le courrier électronique. Les procédures sont celles du RFC 3864. Autrefois, il était fréquent de définir des en-têtes sans les enregistrer, en les préfixant d'un X-. Cette pratique a été abandonnée par le RFC 6648.
  • Et enfin un dernier registre pour le codage du contenu (en fait pas tout à fait le dernier, j'en ai omis certains).

Reste le gros morceau de la sécurité, en section 9. Notre RFC étudie successivement plusieurs points qui peuvent poser problème. D'abord, l'attaque basée sur le nom de fichier. Si un serveur HTTP imprudent transforme directement le chemin dans l'URL en un nom de fichier du système de fichiers local, il peut sans s'en douter donner accès à des endroits non prévus. Par exemple, sur un serveur Unix, lorsque la requête est :

GET /../../../../../../../../etc/passwd HTTP/1.1

un serveur mal programmé donnerait accès au fichier (normalement non distribué /etc/passwd), car .., sur Unix, désigne le répertoire situé un cran au dessus (et le répertoire courant, si c'est la racine, donc l'attaquant a intérêt à mettre beaucoup de .. pour être sûr d'atteindre la racine avant de redescendre vers /etc).

Autre attaque possible, l'injection de commandes ou de code. Le contenu du chemin dans l'URL, ou celui des autres paramètres de la requête, ne mérite aucune confiance : il est complètement sous le contrôle du client, qui peut être un attaquant, et qui peut donc inclure des caractères spéciaux, interprétés par un des logiciels qui manipulent ce contenu. Imaginons par exemple que le contenu de l'en-tête Referer: soit mis dans une base de données relationnelle et que le client ait envoyé un en-tête :

Referer: http://www.google.com/' ; DROP TABLE Statistics; SELECT'

Comme l'apostrophe et le point-virgule sont des caractères spéciaux pour le langage SQL, on pourrait réussir ici une injection SQL : le code SQL situé entre les deux apostrophes (ici, une destruction de table) sera exécuté. Ces attaques par injection sont bien connues, relativement faciles à empêcher (les données issues de l'extérieur ne doivent pas être passées à un autre logiciel avant désinfection), mais encore fréquentes.

L'actualité (les révélations de Snowden) poussent évidemment à se préoccuper des questions de vie privée. Un client HTTP peut envoyer plein d'informations révélatrices (comme la localisation physique de l'utilisateur, son adresse de courrier électronique, des mots de passe...) Le logiciel, qui connait ces informations, doit donc faire attention à ne pas les divulguer inutilement. Certaines personnes utilisent l'URI comme un mot de passe (en y incluant des données secrètes et en comptant que l'URI ne sera pas publié) ce qui est une très mauvaise idée. En effet, les URI sont partagés, par les systèmes de synchronisation de signets, par les navigateurs qui consultent des listes noires d'URI, par des utilisateurs qui n'étaient pas conscients que c'était un secret, par l'en-tête Referer:... Bref, il ne faut pas compter sur le secret de l'URI. Créer un site Web confidentiel et compter sur le fait qu'on n'a envoyé l'URI qu'à un petit groupe restreint de personnes est une très mauvaise stratégie de sécurité. Autre piège pour la vie privée, les informations apparemment purement techniques et non personnelles transmises par le navigateur Web, comme le User-Agent:, les en-têtes de négociation de contenu (comme Accept-Language:), mais aussi la liste des polices ou bien d'autres caractéristiques. Prises ensemble, ces informations permettent le fingerprinting, l'identification d'un navigateur unique au milieu de millions d'autres, grâce à ses caractéristiques uniques. Le fingerprinting marche bien car, en pratique, la combinaison de toutes ces informations techniques est souvent unique. Vous ne me croyez pas ? Regardez le Panopticlick.

Voilà, le gros du RFC est passé, il était long mais c'est parce que HTTP est riche et plus complexe qu'il n'en a l'air. Les annexes de ce RFC fournissent encore quelques informations intéressantes. Ainsi, l'annexe A explique les différences entre HTTP et MIME. HTTP se sert de beaucoup de pièces empruntées au courrier électronique et à MIME et, à première vue, lire le RFC 2045 suffit pour les utiliser. Mais HTTP ayant des caractéristiques différentes de celles du courrier, ce n'est pas tout à fait vrai. Par exemple, l'en-tête MIME-Version: n'est pas obligatoire et les formats de date sont plus stricts. Plus gênant, HTTP n'a pas les limites de longueur de ligne de MIME et ne replie donc pas les lignes trop longues.

La liste des changements entre le précédent RFC, le RFC 2616 et ce RFC figure dans l'annexe B. Rappelez-vous que le protocole est le même, HTTP 1.1 et qu'il n'y a donc pas normalement, sauf bogue dans la spécification, d'incompatibilité entre les deux RFC. Les changements sont normalement uniquement dans la rédaction de la norme. Parmi les changements qui peuvent quand même avoir des conséquences pratiques :

  • Les méthodes possibles sont désormais dans un registre IANA.
  • ISO 8859-1 n'est plus le jeu de caractères par défaut des en-têtes (on trouvait très peu d'en-têtes qui tiraient profit de cette règle : mon blog en avait un et plusieurs personnes m'avaient fait remarquer, bien à tort, que c'était illégal). Même chose pour les contenus de type texte.
  • Les codes de retour de redirection 301 et 302 autorisent explicitement le changement de méthode (de POST en GET, par exemple), alignant la norme avec la réalité du comportement des logiciels.

Téléchargez le RFC 7231


L'article seul

RFC 7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : R. Fielding (Adobe), 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 14 juin 2014


Grande révision de la norme HTTP 1.1, désormais éclatée en huit RFC différents. Celui-ci décrit l'architecture générale du principal protocole du Web, HTTP, le format des URI http: et https:, et la syntaxe générale des messages. (Il a depuis été largement remplacé par les RFC 9110 et RFC 9112.)

HTTP, un des protocoles les plus célèbres de l'Internet, permet à des clients d'accéder à des ressources situées sur des serveurs. (Le terme de « ressource » a été choisi car il est abstrait : les ressources peuvent être des fichiers mais ce n'est pas forcément le cas.) HTTP est sans état, chaque requête est indépendante des autres et un serveur peut répondre à une requête sans forcément connaître la séquence des requêtes précédentes. Comme il est très générique, et ne suppose pas grand'chose sur les clients et les serveurs, HTTP peut être utilisé dans un grand nombre de contextes différents. Son utilisation par les navigateurs Web n'est donc qu'une seule possibilité. HTTP est utilisé, côté client, par des appliances, des programmes non-interactifs (mise à jour du logiciel, par exemple), des applications tournant sur mobile et récupérant des données sans que l'utilisateur le voit, etc. De même, le modèle du serveur HTTP Apache tournant sur un serveur Unix dans un data center n'est qu'un seul modèle de serveur HTTP. On trouve de tels serveurs dans les caméras de vidéo-surveillance, les imprimantes, et bien d'autres systèmes. Il faut notamment se souvenir qu'il n'y a pas forcément un humain dans la boucle. C'est pourquoi certaines propositions d'évolution de HTTP qui nécessitaient une interaction avec un utilisateur humain, par exemple pour désambiguïser des noms de domaine, sont absurdes. Même chose pour les décisions de sécurité.

Il existe de nombreuses passerelles vers d'autres systèmes d'information. Un client HTTP peut donc, via une passerelle, accéder à des sources non-HTTP. D'une manière générale, HTTP étant un protocole, et pas une implémentation, le client ne sait pas comment le serveur a obtenu la ressource et où. Au tout début du Web, le seul mécanisme pour le serveur était de lire un fichier, mais ce n'est plus le cas depuis bien longtemps (d'où l'utilisation du terme « ressource » et pas « fichier » dans la norme). HTTP spécifie donc un comportement extérieur, pas ce qui se passe à l'intérieur de chaque machine.

La section 2 de notre RFC décrit l'architecture du World-Wide Web et notamment de HTTP. Ce dernier, on l'a vu, est un protocole requête/réponse, sans état. Un client interroge un serveur, au-dessus d'un protocole de transport fiable, TCP. Comme dans tout protocole client/serveur, le serveur attend passivement des requêtes et les traite lorsqu'elles arrivent. Les ressources sont identifiées par un URI (normalisés dans le RFC 3986). Le format des messages HTTP est du texte, comme avec bien d'autres protocoles TCP/IP, par exemple SMTP. Cela facilite l'écriture des programmes, et surtout leur débogage (messages tapés à la main, lecture des communications). À noter que la prochaine version de HTTP, HTTP 2, utilisera au contraire un encodage binaire. Ce format texte ressemble à bien des égards à l'IMF du RFC 5322, notamment pour la syntaxe des en-têtes (Name: value). HTTP emprunte aussi à MIME par exemple pour indiquer le type des ressources (texte, image, etc).

Le cas le plus simple en HTTP est la récupération d'une ressource par une requête GET. En voici un exemple, affiché par le client HTTP curl dont l'option -v permet de visualiser les requêtes et les réponses. Le client envoie la ligne GET suivie du chemin de la ressource sur le serveur, le serveur répond par une ligne de statut, commençant par le fameux code à trois chiffres (ici, 200). Client et serveur peuvent et, dans certains cas, doivent, ajouter des en-têtes précisant leur message :


% curl -v http://www.bortzmeyer.org/files/exemple-de-contenu.txt
...
> GET /files/exemple-de-contenu.txt HTTP/1.1
> User-Agent: curl/7.26.0
> Host: www.bortzmeyer.org
> Accept: */*
> 
[Fin de la requête. La réponse suit]

< HTTP/1.1 200 OK
< Date: Thu, 29 May 2014 16:35:44 GMT
< Server: Apache/2.2.22 (Debian)
< Last-Modified: Fri, 11 Nov 2011 18:05:17 GMT
< ETag: "4149d-88-4b1795d0af140"
< Accept-Ranges: bytes
< Content-Length: 136
< Vary: Accept-Encoding
< Link: rel="license"; title="GFDL"; href="http://www.gnu.org/copyleft/fdl.html"
< Content-Type: text/plain; charset=UTF-8

[Fin des en-têtes, le contenu de la ressource suit]

C'est juste un exemple de texte ("contenu"), rien de particulier. Il
est uniquement en ASCII, pour contourner les histoires d'encodage.

Ceci était le cas le plus simple : HTTP permet des choses bien plus compliquées. Ici, pour une page en HTML avec davantage de champs dans la réponse :


% curl -v http://www.hackersrepublic.org/
...
> GET / HTTP/1.1
> User-Agent: curl/7.26.0
> Host: www.hackersrepublic.org
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: Apache/2.4.6
< X-Powered-By: PHP/5.4.4-14+deb7u9
< X-Drupal-Cache: HIT
< Content-Language: french
< X-Generator: Drupal 7 (http://drupal.org)
< Cache-Control: public, max-age=0
< Expires: Sun, 19 Nov 1978 05:00:00 GMT
< Etag: "1401374100-0-gzip"
< Last-Modified: Thu, 29 May 2014 14:35:00 GMT
< Content-Type: text/html; charset=utf-8
< Vary: Cookie,Accept-Encoding
< Transfer-Encoding: chunked
< Date: Thu, 29 May 2014 16:37:15 GMT
< Connection: keep-alive
< Via: 1.1 varnish
< Age: 0
< 
...
<!DOCTYPE html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta charset="utf-8" />
<link rel="apple-touch-icon-precomposed" href="http://www.hackersrepublic.org/sites/all/modules/touch_icons/apple-touch-icon-precomposed.png" type="image/png" />
<link rel="apple-touch-icon" href="http://www.hackersrepublic.org/sites/all/modules/touch_icons/apple-touch-icon.png" type="image/png" />
<meta name="viewport" content="width=device-width" />
<meta name="Generator" content="Drupal 7 (http://drupal.org)" />
...

Une des complications possibles est la présence d'intermédiaires. HTTP permet des relais des passerelles et des tunnels. Le relais (proxy) est du côté du client, souvent choisi par lui, et transmet les requêtes, après avoir appliqué certains traitements, comme le filtrage de la publicité, la censure, ou bien la mise en cache (cf. RFC 7234) des ressources souvent demandées, pour accélérer les requêtes suivantes (c'est par exemple la principale fonction de l'excellent logiciel Squid et c'est un excellent moyen d'économiser de la capacité réseau, particulièrement lorsqu'on est connecté par des lignes lentes). Lorsque le relais n'est pas explicitement choisi par le client, on parle de transparent proxy (RFC 1919 et RFC 3040). Ils servent typiquement à restreindre les services auquel un utilisateur captif peut accéder. La passerelle (gateway, également nommée reverse proxy, et qu'il ne faut pas confondre avec celle décrite plus haut qui fait la conversion entre HTTP et un autre protocole) est, au contraire, proche du serveur, choisie par lui, et fournit des services comme la répartition de charge ou comme la mémorisation des réponses, pour aller plus vite la prochaine fois (c'est par exemple le rôle du logiciel Varnish dont vous avez vu la présence signalée par l'en-tête Via: dans l'exemple précédent). Enfin, le tunnel assure juste une transmission des octets d'un point à un autre. Il est surtout utilisé pour le cas où la communication est chiffrée par TLS mais que le client et le serveur ne peuvent pas se parler directement. Pour tout intermédiaire, il est important de se rappeler que HTTP est sans état : deux requêtes, même venant de la même adresse IP, ne sont pas forcément liées (le RFC 4559 faisait l'erreur de violer cette règle).

Un point important pour les logiciels HTTP : la norme ne met pas de limites quantitatives dans bien des cas. C'est le cas par exemple de la longueur des URI. Il y a donc potentiellement problèmes d'interopérabilité. Au minimum, notre RFC demande qu'une mise en œuvre de HTTP sache lire des éléments aussi longs que ceux qu'elle génère elle-même, ce qui semble du bon sens.

On l'a dit, cette version de HTTP est la même que celle du RFC 2616 (et, avant, celle du RFC 2068), la version 1.1. L'idée est que la syntaxe des messages échangés dépend du numéro majeur (1, ici). C'est pour cela que le passage à un encodage binaire (et non plus texte) des messages va nécessiter un passage à la version majeure numéro 2. Par contre, des nouveaux messages ou des extensions des messages précédents peuvent être ajoutés en incrémentant juste le numéro mineur (1, à l'heure actuelle). En général, clients et serveurs HTTP 1.1 et HTTP 1.0 (normalisé dans le RFC 1945) peuvent ainsi interagir.

Le World-Wide Web repose sur trois piliers, le protocole HTTP, présenté ici, le langage HTML, et les adresses des ressources, les URI, normalisées dans le RFC 3986. HTTP utilise deux plans (scheme) d'URI, http: et https:. http: est spécifique à TCP, bien que HTTP ait juste besoin d'un canal fiable et ne se serve pas des autres fonctions de TCP. Porter HTTP sur, par exemple, SCTP, serait trivial, mais nécessiterait des URI différents (autrement un client bilingue ne saurait pas a priori s'il doit essayer d'établir la connexion en TCP ou en SCTP). Le plan est suivi des deux barres obliques et du champ « nom de machine ». L'adresse IP de la (ou des) machine(s) est typiquement trouvée dans le DNS. Ainsi, ce blog est en http://www.bortzmeyer.org/ ce qui veut dire qu'il faudra faire une requête DNS pour le nom www.bortzmeyer.org (http://www.bortzmeyer.org/ est un URI, www.bortzmeyer.org est un nom de domaine). Le port par défaut est le bien connu 80. Malheureusement, HTTP n'utilise pas de mécanisme d'indirection comme les MX du courrier électronique ou comme les plus modernes SRV du RFC 2782, utilisés par presque tous les autres protocoles Internet. Résultat, il n'est pas trivial de mettre un nom de domaine « court » (juste le nom enregistré, comme example.org, sans préfixe devant) dans un URI. Cela ne peut se faire qu'en mettant directement une adresse IP au nom enregistré, empêchant ainsi d'autres services sur le nom court. Cela rend également très difficile la répartition de charge côté client. C'est un des manques les plus sérieux de HTTP.

Le plan https: est pour les connexions HTTP sécurisées avec TLS (le petit cadenas du navigateur Web...) Le port est alors le 443. TLS est normalisé dans le RFC 5246.

La section 3 de notre RFC décrit le format des messages. Bon, HTTP est bien connu, il faut vraiment que je le répète ? Une ligne de départ, puis une syntaxe inspirée de l'IMF du RFC 5322, avec ses champs « Nom: valeur », puis une ligne vide puis un corps optionnel. Le récepteur va en général lire la ligne de départ, puis lire les en-têtes en les mettant dans un dictionnaire, puis, si l'analyse de ces données montre qu'un corps peut être présent, le récepteur va lire le corps pour la quantité d'octets indiquée, ou bien jusqu'à la coupure de la connexion. La ligne de départ est la seule dont la syntaxe est différente entre les requêtes et les réponses. Pour une requête, on trouve une méthode (la liste des méthodes possibles est dans le RFC 7231), une cible, puis la version HTTP. Pour la réponse, on a la version HTTP, le code de retour (les fameux trois chiffres), et une raison exprimée en langue naturelle. Voici un exemple avec curl, où on récupère une ressource existante, avec la méthode GET et on a le code de retour 200 (succès) :


% curl -v http://www.afnic.fr/
...
> GET / HTTP/1.1
> User-Agent: curl/7.32.0
> Host: www.afnic.fr
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Tue, 22 Apr 2014 16:47:34 GMT
< Server: Apache/2.2.3 (Red Hat) DAV/2 mod_ssl/2.2.3 OpenSSL/0.9.8e-fips-rhel5
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Content-Type: text/html; charset=utf-8
< Set-Cookie: afnic-prod=m3nc4r1oivltbdkd9qbh6emvr5; path=/
< Transfer-Encoding: chunked
< 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1
-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
...

Ici, par contre, on essaie de détruire (méthode DELETE) une ressource qui n'existe pas. On a le code de retour 404 (ressource inexistante) :


% curl -v -X DELETE http://www.afnic.fr/test
...
> DELETE /test HTTP/1.1
> User-Agent: curl/7.32.0
> Host: www.afnic.fr
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Date: Tue, 22 Apr 2014 16:50:16 GMT
< Server: Apache/2.2.3 (Red Hat) DAV/2 mod_ssl/2.2.3 OpenSSL/0.9.8e-fips-rhel5
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
...

Les codes de retour possibles sont décrits en détail dans le RFC 7231. En attendant, vous trouvez des jolies photos de chats illustrant ces codes chez les HTTP status cats et, pour les chiens, voyez par ici.

Il n'y a pas de limite imposée par la norme pour des choses comme la longueur des lignes de début ou comme la longueur d'un champ dans l'en-tête. En pratique, il est recommandé aux logiciels HTTP d'accepter au moins 8 000 octets.

Les en-têtes des requêtes et réponses comprennent un nom de champ (comme User-Agent ou Expires), deux-points et la valeur de l'en-tête. Des nouveaux champs sont introduits régulièrement, HTTP n'impose pas un jeu fixe de noms de champs. Ils sont enregistrés dans un registre IANA qui est le même que pour les champs du courrier électronique (certains en-têtes, comme Date:, sont communs à plusieurs protocoles/formats.)

L'ordre des champs n'est pas significatif. Normalement, les champs sont présents une seule fois au maximum. Mais il y a des exceptions, si le contenu d'un champ est une liste, on peut avoir plusieurs occurrences du champ, la valeur étant alors la concaténation de toutes les valeurs en une liste. Au moins un champ, Set-Cookie: (RFC 6265), n'obéit pas à cette règle, pour des raisons historiques, et doit donc être traité à part.

Important changement par rapport à la norme précédente, le RFC 2616, la grammaire des en-têtes. Il n'y a plus une règle spécifique par champ mais une grammaire générique pour les champs, avec une partie spécifique pour la valeur.

Il n'y a pas d'espace entre le nom de champ et le deux-points et le RFC impose, principe de robustesse ou pas, de rejeter les messages ayant de tels espaces. (Autrement, cela permettrait d'intéressantes attaques.)

Autre changement important depuis le précédent RFC, l'encodage par défaut. La norme autorisait explicitement ISO 8859-1 dans les en-têtes, les autres encodages devaient passer par la technique du RFC 2047. Cette règle est désormais abandonnée, les valeurs des en-têtes devant rester en ASCII, ou bien être traitées comme du binaire, sans être interprété comme du ISO 8859-1.

Au cours de son transfert, la ressource à laquelle on accède en HTTP peut subir des transformations, par exemple pour en réduire la taille. La section 4 de notre RFC décrit ces « codages pendant le transfert » : compression mais aussi transfert en plusieurs morceaux.

Maintenant, en section 5 du RFC, un autre point important de HTTP, le routage des requêtes. Lorsqu'un client HTTP reçoit un URL, qu'en fait-il ? Il va regarder si la ressource correspondant à cet URL est déjà dans sa mémoire et est réutilisable. Si non, il va regarder s'il doit faire appel à un relais (cela dépend de la configuration dudit client). Si oui, il se connecte au relais et fait une requête HTTP où l'identificateur de ressource est l'URL complet (absolute form dans le RFC). Si non, il extrait le nom du serveur HTTP de l'URL, se connecte à ce serveur, et fait une requête HTTP où l'identificateur de ressource est juste la partie « chemin ». Le champ Host: de l'en-tête HTTP vaut le nom du serveur. Le port par défaut (s'il n'est pas indiqué dans l'URL) est, comme chacun le sait, 80 (et 443 pour HTTPS). Le nom de serveur donné dans l'URL est directement utilisé pour une requête de résolution de noms pour avoir l'adresse. Malheureusement, comme indiqué plus haut, HTTP n'utilise pas les SRV du RFC 2782, d'où le fait qu'on voit souvent des adresses IP mises directement à l'apex du domaine enregistré.

À noter que ce RFC ne couvre pas l'autre partie du « routage », le fait, pour le serveur, de trouver, pour une cible donnée, la localisation de la ressource demandée. Les premiers serveurs HTTP avaient un routage très simple : la cible était préfixée par un nom de répertoire configuré dans le serveur, et le tout était interprété comme le chemin d'un fichier sur le serveur. Ainsi, GET /toto.html sur un serveur où le nom de départ était /var/web, servait le fichier /var/web/toto.html. Aujourd'hui, ce mécanisme de routage existe toujours mais il est accompagné de nombreux autres. À noter que, depuis la création du concept de virtual host, le serveur HTTP commence par chercher le virtual host, en utilisant le champ Host: pour le routage.

La section 6 de notre RFC couvre la gestion des connexions. HTTP n'a pas besoin de grand'chose de la part du protocole de transport sous-jacent : juste une connexion fiable, où les octets sont reçus dans l'ordre envoyé. TCP convient à ce cahier des charges et c'est le protocole de transport utilisé lorsque l'URL est de plan http: ou https:. On pourrait parfaitement faire du HTTP sur, par exemple, SCTP (RFC 4960), mais il faudrait un nouveau plan d'URL. HTTP, pour l'instant, utilise forcément TCP, et le client HTTP doit gérer les connexions TCP nécessaires (les créer, les supprimer, etc).

Le modèle le plus simple (et le modèle historique de HTTP mais qui n'est plus celui par défaut) est celui où chaque couple requête/réponse HTTP se fait sur une connexion TCP différente, établie avant l'envoi de la requête, et fermée une fois la réponse reçue. Mais d'autres modèles sont possibles. Pour indiquer ses préferences, le client utilise l'en-tête Connection:. Par défaut, une connexion TCP persiste après la fin de l'échange, et peut servir à envoyer d'autres requêtes. Si le client veut fermer la connexion TCP immédiatement, il envoie :

Connection: close

L'établissement d'une connexion TCP prenant un certain temps (la fameuse triple poignée de mains), il est logique que les connexions soient persistentes et réutilisables.

Un client HTTP peut aussi avoir plusieurs connexions TCP ouvertes simultanément vers le même serveur mais le RFC lui impose de limiter leur nombre. (Ce parallélisme est utile pour éviter qu'une courte requête, par exemple pour une feuille de style soit bloquée par un gros téléchargement.) Les versions précédentes de la norme donnaient des valeurs précises (deux, dans le RFC 2616) mais notre nouveau RFC ne donne plus de chiffre, demandant simplement aux clients d'être raisonnables.

La section 9 est l'obligatoire section de sécurité. D'abord la question de l'autorité que fait (ou pas) la réponse. Les problèmes de sécurité surviennent souvent lorsque l'idée que se fait l'utilisateur ne correspond pas à la réalité : c'est le cas par exemple du hameçonnage où la réponse qui fait autorité, pour HTTP, n'est pas celle que croit l'utilisateur. Le RFC donne quelques conseils comme de permettre aux utilisateurs d'inspecter facilement l'URI (ce que ne font pas les utilisateurs et que les navigateurs Web ne facilitent pas, trop occupés à noyer la barre d'adresses, jugée trop technique, au milieu d'autres fonctions). Mais il peut aussi y avoir des cas où HTTP lui-même est trompé, par exemple si un empoisonnement DNS ou bien une attaque contre le routage IP a envoyé le navigateur vers un autre serveur que celui demandé. HTTPS vise à résoudre ces problèmes mais, avec l'expérience qu'on a maintenant de ce service, on peut voir que ce n'est pas si simple en pratique (attaques contre les AC, bogues dans les mises en œuvre de TLS, etc). Et cela ne résout pas le problème de l'utilisateur qui suit aveuglément un lien dans un courrier reçu... À noter que HTTP n'a aucun mécanisme d'intégrité, pour se protéger contre une modification du message. Il dépend entièrement des services sous-jacents, TLS dans le cas de HTTPS. Ces services protègent le canal de communication mais pas les messages eux-mêmes, pour lesquels il n'y a pas de sécurité de bout en bout, encore une sérieuse limite de HTTPS. Même chose pour la confidentialité (le groupe de travail, après de longues discussions n'a pas réussi à se mettre d'accord sur un texte à inclure au sujet de l'interception des communications HTTP.)

HTTP soulève aussi plein de questions liées à la vie privée. On sait que le journal d'un serveur HTTP peut révéler beaucoup de choses. Un serveur cache d'un réseau local, notamment, voit tout le trafic et peut le relier à des utilisateurs individuels. Bref, il faut traiter les journaux sérieusement : ils sont souvent soumis à des lois de protection de la vie privée (ils contiennent des informations qui sont souvent nominatives comme l'adresse IP du client HTTP), et ils doivent donc être gérés en accord avec les bonnes pratiques de sécurité (par exemple, lisibles seulement par les administrateurs système). Le RFC recommande qu'on ne journalise pas tout ou que, si on le fait, on « nettoie » les journaux au bout d'un moment (par exemple en retirant l'adresse IP du client ou, tout simplement, en supprimant le journal).

La section 8 de notre RFC résume les enregistrements faits à l'IANA pour HTTP :

Le travail de développement de HTTP a mobilisé énormément de monde, ce qui reflète l'extrême importance de ce protocole sur l'Internet. La section 10 liste des centaines de noms de personnes ayant participé à ce protocole (dont votre serviteur). L'annexe A résume la longue histoire de HTTP depuis sa création en 1990. HTTP/0.9 (qui n'avait pas encore de numéro de version officiel, il l'a reçu après) était un protocole ultra-simple (d'où son succès, alors que les gourous de l'hypertexte travaillaient tous sur des choses bien plus complexes, et regardaient de haut ce service trop simple) qui n'avait qu'une méthode, GET. Sa spécification était minimale. Les numéros de versions sont officiellement apparus avec HTTP/1.0, le premier décrit dans un RFC, le RFC 1945. HTTP/1.0 introduisait les en-têtes permettant de varier les requêtes et les réponses, et notamment d'indiquer le type de la ressource récupérée. Son principal manque était l'absence de toute gestion des virtual hosts, puisqu'il n'avait pas l'en-tête Host:. Il fallait donc une adresse IP par site servi...

HTTP/1.1, décrit pour la première fois dans le RFC 2068, introduisait notamment le virtual hosting et les connexions TCP persistantes. Le RFC 2068 a été remplacé ensuite par le RFC 2616, puis par notre RFC 7230 puis encore, mais partiellement, par le RFC 9112, mais sans changement du numéro de version. Si les changements apportés depuis le RFC 2616 sont très nombreux, ils ne changent pas le protocole. Parmi les principaux changements qu'apporte notre RFC 7230 :

  • L'indication du nom de l'utilisateur (et, dans certains cas, du mot de passe !) dans l'URI est abandonnée.
  • Les URI https: sont désormais officiellement définis dans le RFC HTTP et plus dans un RFC à part (le RFC 2818).
  • Les en-têtes s'étendant sur plusieurs lignes sont maintenant découragés.
  • Et plein d'autres détails, indispensables au programmeur d'un client ou d'un serveur HTTP mais qui ennuieraient probablement très vite la plupart des lecteurs.

Téléchargez le RFC 7230


L'article seul

RFC 7228: Terminology for Constrained Node Networks

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : C. Bormann (Universitaet Bremen TZI), M. Ersue (Nokia Siemens Networks), A. Keranen (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF lwig
Première rédaction de cet article le 15 mai 2014


Il existe désormais de nombreux protocoles et donc de nombreux documents (par exemple des RFC) pour les objets limités (en puissance de calcul, en énergie, en capacité réseau...). L'Internet, conçu d'abord pour de gros ordinateurs alimentés en permanence, s'adapte de plus en plus à ces objets limités. D'où l'importance d'une terminologie standard : ce nouveau RFC définit un certain nombre de termes utilisés dans la normalisation de protocoles pour ces petits objets.

Des exemples de tels objets ? Des capteurs mis dans la nature, un actionneur dans une usine, des Arduino au fond d'un placard, et bien d'autres encore. Ils ont en commun de manquer sérieusement d'une ou plusieurs ressources, qui étaient considérées comme virtuellement illimitées : énergie électrique, capacité réseau, capacité de calcul... Tous ensemble, ces objets contribuent à ce qu'on appelle (un terme médiatique sans définition rigoureuse) « l'Internet des Objets ».

Adapter les protocoles Internet à cet Internet des Objets nécessite deux adaptations quantitatives :

  • « scaling up », s'adapter à un réseau comptant beaucoup plus de machines, peut-être des dizaines de milliards. Le modèle dominant, aux débuts de l'Internet, était d'un ordinateur par entreprise. Il est passé à un par département (l'« informatique départementale » des années 70 et 80) puis à un par personne avec la micro-informatique. Aujourd'hui, le modèle est plutôt de plusieurs ordinateurs par personne, même si on ne pense pas forcément à ces objets comme étant des ordinateurs.
  • « scaling down », s'adapter à des machines ayant des capacités considérées aujourd'hui comme très faibles (tout en étant parfois supérieures à celles des machines des débuts de l'Arpanet).

La section 2 de notre RFC définit la terminologie utilisée. Le RFC est en anglais et les traductions sont de moi, donc n'ont pas de caractère normatif, contrairement au texte anglais. Premier terme défini, celui de « nœud contraint » (constrained node). Ce sont nos objets. Ils sont définis négativement, par le fait qu'il n'ont pas certaines caractéristiques que l'on associe d'habitude automatiquement à un ordinateur moderne. Par exemple, certains objets n'ont pas d'alimentation électrique permanente et doivent donc économiser la batterie. Certains objets n'ont pas de MMU et ne peuvent donc pas gérer de mémoire virtuelle, ce qui implique de faire très attention à la consommation mémoire des programmes. Certains objets n'ont aucune interface utilisateur (pas d'écran, même limité), ce qui rend impossible certaines opérations (« pour sécuriser l'Internet des Objets, on va utiliser des mots de passe, qu'il faudra rentrer dans chaque objet »). Les objets ont aussi des contraintes quantitatives, comme une ROM très limitée, qui impose un code de petite taille. Un nœud contraint est donc très différent d'un PC de bureau (où le programmeur de Gnome ou de Windows ne réfléchit, ni à la consommation électrique, ni à la consommation de mémoire...) mais même également d'un smartphone, engin finalement très perfectionné et qui peut faire tourner un Unix peu modifié. On voit avec cet exemple que la définition de nœud contraint n'est pas complètement rigoureuse (après tout, le smartphone est très contraint en énergie électrique).

La section 3 du RFC tente de quantifier cette notion de nœud contraint, en introduisant des classes de nœuds, selon leurs caractéristiques. (Petit rappel : un kibioctet, noté Kio, c'est 1 024 octets.) La classe 0 (aussi notée C0), la plus contrainte, a une mémoire vive bien en dessous de 10 Kio, et une mémoire morte très inférieure à 100 Kio. La classe 1 a des mémoires aux alentours, respectivement, de 10 et 100 Kio. Et la classe 2, la plus riche, a dans les 50 Kio de RAM et 250 de ROM. Ne comptez pas sur la loi de Moore pour tirer ces chiffres vers le haut dans le futur : dans le domaines des objets, les progrès sont utilisés pour baisser les prix et/ou la consommation électrique, et équiper davantage d'objets, pas pour augmenter les capacités. Pour comparer, un Raspberry Pi typique a 512 Mio (oui, je sais, c'est souvent écrit Mo mais c'est une erreur, il faut dire que la situation est compliquée). Il n'est donc pas considéré comme objet contraint. En revanche, un Arduino typique peut n'avoir que 2 à 8 Kio, ce qui les met dans la classe 0.

Les nœuds de la classe 0 ne peuvent pas espérer avoir de vraie communication TCP/IP. Le terme d'« Internet des Objets » est tout à fait impropre pour eux, ils ne peuvent pas se connecter à l'Internet, et surtout pas de manière sécurisée. Typiquement, leur connexion aux réseaux se fera via une passerelle. La classe 1 a plus de chance : ils n'arriveront certes pas à faire tourner HTTP + TLS + XML + XSLT mais ils peuvent utiliser des protocoles TCP/IP spécialement prévus pour eux, comme CoAP. Les nœuds de la classe 2, eux, peuvent faire tourner plus ou moins les mêmes protocoles qu'un serveur ordinaire ou qu'une machine de bureau. Bien sûr, ils restent contraints et toute optimisation est donc bonne à prendre, par exemple pour économiser la batterie. Il n'y a pas de classe 3 ou au delà : les machines ayant de meilleures capacités que la classe 2 n'ont pas de contraintes comparables et il n'y a donc pas besoin que l'IETF développe des normes ou pratiques particulières pour eux.

Deuxième terme important dans la section 2 de notre RFC, « réseau contraint ». Un réseau contraint (constrained network, cf. RFC 7102) est un réseau auquel manquent certaines caractéristiques qu'on a l'habitude de tenir pour acquises sur l'Internet : le débit maximum est fortement limité, le taux de pertes de paquets très élevé, les liens sont souvent très asymétriques (ça marche dans un sens mais pas dans l'autre)... Ces contraintes peuvent venir du coût (on a serré les budgets), du milieu ambiant (pensez à un réseau sous-marin...), des contraintes légales (limitation de la puissance maximale), ou des contraintes techniques (vieilles technologies dont on ne peut pas se débarasser).

Il ne faut pas confondre le réseau contraint avec le « réseau de nœuds contraints » (constrained node network). Ce dernier est un réseau composé en grande partie de nœuds contraints, ce qui réduit ses possibilités, même si le réseau lui-même est parfait.

Plus grave que le réseau contraint, le « réseau limité » (challenged network). C'est un réseau qui a du mal à fournir des services IP de bout en bout : pas de connectivité complète, interruptions fréquentes (voir RFC 4838 pour des exemples rigolos), délais d'acheminement des paquets qui sont supérieurs au MSL (Maximum Segment Lifetime) de TCP, empêchant ainsi d'établir des connexions TCP, même si ping fonctionne (les réseaux RFC 1149 sont un bon exemple)...

Enfin, la section 2 rappelle deux termes fréquemment utilisés dans les RFC et déjà définis. Un LLN (Low-power Lossy Network), défini dans le RFC 7102, est un réseau contraint et formé de nœuds contraints. Cela oblige à des protocoles spécifiques comme RPL (RFC 6550). Et un LowPAN (Low-Power Wireless Personal Area Network, RFC 4919) était le nom d'un groupe de travail IETF et le terme est souvent utilisé comme synonyme de LLN (le Personal dans LowPAN n'ayant plus guère de signification aujourd'hui). Un dérivé, 6LowPAN, désigne le travail fait pour utiliser IPv6 sur ces réseaux LowPAN.

L'une des contraintes les plus fréquentes et les plus pénibles est évidemment la consommation électrique. La section 4 de notre RFC définit des termes pour ce domaine. Deux termes sont importants pour caractériser la consommation d'un nœud contraint : Ps (pour Power sustainable) indique la consommation instantanée de la machine en train de tourner (en watts) et Et est l'énergie totale qui sera consommée avant que la machine ne s'arrête, sa batterie à plat. « Ps » doit être indiqué pour chaque mode du nœud contraint si, comme c'est souvent le cas, il existe plusieurs modes de fonctionnement, consommant plus ou moins de courant. « Et » est infini pour une machine connectée au courant général, et se mesure en joules.

Cela permet de définir des classes selon des critères liés à l'énergie électrique disponible : E0 est la classe des machines dont la disponibilité en électricité à liée à des évenements extérieurs (recharge par une action mécanique externe, par exemple), E1 celle des machines dont la consommation électrique est limitée durant une certaine période (la durée entre deux recharges, ou bien le cycle quotidien du soleil si la recharge se fait par énergie solaire), E2, celle des machines qui ont une durée de vie limitée (une batterie non remplaçable, par exemple, ce qui fait que bien des machines sont à la fois E1 et E2), et E9 la classe des machines illimitées, qui peuvent puiser du courant à volonté.

Du fait de ces limites d'énergie disponibles, les nœuds contraints doivent s'adapter. Souvent, la radio est le principal poste de consommation : il est bien plus coûteux d'envoyer un paquet que de le fabriquer, même si on a utilisé le chiffrement. Les machines peuvent être classées selon leur stratégie de consommation. P0 est la classe des machines qui sont éteintes la plupart du temps et ne sont allumées que pour une tâche spécifique. Cela veut dire que leur attachement au réseau doit recommencer à chaque allumage, une tâche coûteuse en énergie (émission d'une requête DHCP, attente...) et qu'il est intéressant d'optimiser. P1 est une classe de machines qui sont sous tension en permanence, mais dans un mode à consommation réduite, où les réactions ne sont pas forcément très rapides. Elles restent donc attachées au réseau en permanence. Enfin, P9 regroupe les machines qui sont tout le temps complètement réveillées, connectées au réseau en consommation maximale. Ce serait le cas d'un routeur, par exemple. (Le RFC 7102 ne distinguait que deux niveaux, correspondant à nos classes P0 et P9.)


Téléchargez le RFC 7228


L'article seul

RFC 7227: Guidelines for Creating New DHCPv6 Options

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : D. Hankins (Google), T. Mrugalski, M. Siodelski (ISC), S. Jiang (Huawei Technologies), S. Krishnan (Ericsson)
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 11 mai 2014


Le protocole DHCPv6, normalisé dans le RFC 8415, permet de configurer des clients IPv6 depuis un serveur central, qui maintient un état (adresses IP attribuées, par exemple). Des tas d'options aux requêtes et réponses DHCPv6 permettent de fournir toutes sortes d'informations utiles. La liste de ces options n'est pas figée, on peut en définir de nouvelles (sections 21 et 24 du RFC 8415). Ce nouveau RFC guide les concepteurs d'options (et leurs collègues à l'IETF qui examineront les nouvelles demandes d'options) : que faire lorsqu'on crée une nouvelle option DHCPv6 et surtout que faut-il ne pas faire. Il s'adresse donc surtout à un public de normalisateurs et de programmeurs.

Pour les programmeurs, la question (section 2 du RFC) est « qu'est-ce que la nouvelle option va nécessiter comme travail ? Un ajout trivial aux clients et serveurs DHCP ou au contraire de vrais changements ? » Dans le second cas, les chances de déploiement de la nouvelle option sont minces... (Aussi bien en DHCPv4 pour IPv4 qu'en DHCPv6, des tas d'options ont été normalisées mais jamais réellement déployées dans la nature, ou parfois au bout de plusieurs années seulement.) En effet, la nouvelle option ne nécessite pas que des changements dans le message tel qu'il circule sur le réseau : il faut changer toute la chaîne de traitement, par exemple l'interface de configuration du serveur. Si ce dernier est configuré par un fichier de configuration, il faudra modifier l'analyseur pour reconnaître la définition d'une valeur dans cette option. S'il est configuré par un GUI, il faudra ajouter menus et boîtes de dialogues. Ensuite, il faudra que les administrateurs réseaux utilisent cette option, ce qui plaide en faveur d'options simples, ne nécessitant pas de lire des tonnes de documentation pour être configurée.

Donc, l'option qui a le plus de chances d'être adoptée, est celle qui ne nécessite que peu ou pas de changement dans les fichiers de configuration, celle qui ne nécessite pas trop de changement (voire pas du tout, en utilisant les capacités de traitement d'options inconnues) dans le code source, celle qui est proche d'options existantes, et, évidemment, celle qui est utile dans une grande gamme de cas.

La section 3 du RFC rappelle dans quel cas il est intéressant d'utiliser DHCPv6. Contrairement à IPv4 où il n'y a guère le choix (pas de mécanisme d'auto-configuration général), IPv6 a deux méthodes de configuration automatique, SLAAC (RFC 4862) et DHCPv6 (RFC 8415). Tout (« Any knob, dial, slider, or checkbox on the client system », dit le RFC) peut être configuré par DHCP, de l'adresse IP du client, au nom de domaine qu'il utilisera par défaut, en passant par la température à laquelle il doit automatiquement s'arrêter (ce dernier exemple n'est pas normalisé). Comme DHCP est une configuration centralisée, sous le contrôle de l'administrateur réseaux du réseau local où la machine est actuellement attachée, le client n'a pas forcément envie de tout laisser configurer. DHCP est utile pour les paramètres qui dépendent étroitement du réseau actuel (l'adresse IP étant l'exemple typique) mais pas pour les paramètres où le client veut garder le contrôle.

Enfin, la section 3 rappelle que le client a le dernier mot : il peut toujours ignorer les options reçues en DHCP ou les remplacer par les siennes. Par contre, cela peut l'empêcher, notamment dans les réseaux d'entreprise, d'accéder à certains services. Par exemple, si le client DHCP ignore le résolveur DNS indiqué, il pourra rater certains noms qui n'existent que dans une vue DNS locale.

Bon, assez de préliminaires : la section 4 liste les principes généraux qui président à la définition de nouvelles options. Principe n° 1 : la réutilisation. La nouvelle option doit réutiliser autant que possible ce qui existe déjà. Ainsi, si une option prend comme valeur (prenons un exemple irréaliste) un ISBN, il est peu probable que le code pour analyser des ISBN dans le fichier de configuration existe. En revanche, si elle prend comme valeur une adresse IP, le code existe certainement car des tas d'options ont déjà besoin d'une adresse IP.

Il y a deux sortes d'options : les simples qui se contentent de transporter des données du serveur vers le client et qui peuvent donc être gérées par du code générique. Et les compliquées, qui nécessitent un traitement spécifique par le serveur (comme l'option du RFC 4704), avant d'envoyer les données. Inutile de dire que les premières seront plus... simples à déployer.

La réutilisation est surtout importante dans les formats. Si l'option n'utilise que des éléments déjà connus (comme les adresses IP citées plus haut), elles seront bien plus simples à ajouter aux serveurs et aux clients, le code étant déjà là. Bien qu'il puisse être nécessaire de définir des nouveaux formats, notre RFC recommande fortement de construire plutôt à partir des briques existantes. La section 5 détaille ce point. Car, pour le concepteur d'une nouvelle option, fouiller tous les RFC définissant une option DHCPv6, pour voir ce qui serait réutilisable, serait très long. Notre RFC propose donc une liste d'éléments (de briques) courants. Si on a besoin de structures un peu compliquées, on pourra toujours les construire à partir de ces briques.

Premier élément commun et courant, l'adresse IPv6. Des tas d'options en incluent une (liste de serveurs SIPRFC 3319, résolveurs DNSRFC 3646, serveur NTPRFC 5908, etc). Il suffit donc, lorsqu'on définit une option qui distribue (entre autres) des adresses IPv6 de reprendre la définition (l'encodage est résumé dans la section 5.1)... et le code marchera tout seul.

Si on veut un préfixe IPv6 (adresse + longueur du préfixe), cela existe également déjà (quoique ce soit bien plus rare, cela ne se trouve pour l'instant pas encore dans des RFC).

Plus court qu'une adresse IPv6, le booléen. Il existe dans au moins une option (le rapid commit du RFC 8415, section 22.14). Plutôt que de le représenter sous forme d'un octet (un bit pour la valeur et sept pour le remplissage), le RFC recommande plutôt que la seule présence ou absence de l'option indique la valeur. On définit une valeur par défaut et, si l'option est présente, sa valeur sera l'opposé de la valeur par défaut. Cela permet d'encoder uniquement le code et la longueur (forcément zéro mais DHCPv6 impose la présence de ce champ Longueur), sans aucun contenu. Le nom de l'option doit refléter l'effet qu'aura sa présence. Par exemple, s'il existe un booléen FOO et que sa valeur par défaut est Vrai, l'option devra s'appeler DISABLE_FOO puisque sa présence mettra FOO à Faux.

Plus grands que les booléens, les entiers, comme le refresh time du RFC 4242. Si on veut transmettre un entier de 32 bits, on peut réutiliser ce format.

Plus grand encore, et plus compliqué, un URI. Par exemple, le RFC 5970 fournit une option qui permet d'indiquer les coordonnées du code à charger au démarrage d'une machine. Ces coordonnées sont un URI, par exemple ftp://[2001:db8:23a::1]/bootfiles/pi.exe. Sur le câble, cette option est encodée exactement comme du texte libre (exemple suivant) mais le fait de la marquer comme contenant un URI permet au serveur DHCP de tester sa syntaxe avant de charger cette option.

Ah, le texte, justement. Le RFC recommande que toutes les options utilisant du texte libre imposent à celui-ci d'être en Unicode, avec les restrictions du RFC 5198, et encodé en UTF-8. (Rappelez-vous que du texte en pur ASCII remplit ces conditions.) Le RFC 4833, qui définit une option en texte libre pour indiquer le fuseau horaire, sans le dire clairement, se limite au seul ASCII et, donc, si on créait une option prenant du texte libre en Unicode, il faudrait probablement développer du code spécifique, personne ne l'ayant encore fait.

Certaines options prennent comme valeurs des listes et pas de simples scalaires. C'est le cas d'options comme la liste de serveurs SIP déjà vue plus haut.

À part la réutilisation des formats, que conseille notre RFC ? La section 7 recommande d'éviter les alias, ces options qui donnent accès au même paramètre mais via des formats différents. Par exemple, si on veut indiquer un serveur réseau, avoir deux options, une prenant en paramètre une adresse IP et l'autre un nom de domaine, est fortement déconseillé. Cela augmente la quantité de code et laisse dans l'ambiguité la question de savoir quelle option gagne si les deux sont présentes. À la place, il faut une seule option, le type de paramètre dépendant des propriétés que l'on veut (ici, la simplicité pour l'adresse IP, la liaison retardée pour le nom de domaine).

La section 8 brode davantage sur ce thème du choix entre nom de domaine et adresse IP. S'il est fortement conseillé de n'avoir qu'une option, laquelle ? Le RFC évite de faire une recommandation générale, car cela dépend du paramètre. Par exemple, le résolveur DNS doit évidemment être indiqué par une adresse IP. Les paramètres qui sont liés à la topologie du réseau (les paramètres « couche 3 » comme le serveur de mobilité) sont sans doute mieux représentés par des adresses IP. Ceux qui sont plus proches des applications (les paramètres « couche 7 » comme un serveur SIP) ont plutôt intérêt à utiliser des noms de domaines, voire des URI.

Il y a d'autres points à prendre en compte. Par exemple, les applications réagissent en général mieux aux problèmes DNS temporaires qu'aux problèmes réseau. Un nom de domaine sera donc intéressant si on veut éviter qu'une panne plante l'application. Le problème de résolution DNS est attendu et, en pratique, souvent bien géré, ce qui n'est pas le cas si, par exemple, un client DHCP reçoit une adresse IP qui, en pratique, ne marche pas : ce cas n'est pas prévu et le client ne réessaiera pas automatiquement.

L'indirection supplémentaire fournie par le nom de domaine est, la plupart du temps, un avantage. Un exemple où, au contraire, c'est un inconvénient, est celui où on veut fournir un service qui dépend de la localisation. Le DNS est bâti sur le principe qu'une question entrainera la même réponse partout. Il existe des services DNS géo-localisés mais qui, en pratique, ne sont pas très satisfaisants puisqu'ils violent ce principe. Au contraire, le serveur DHCP sait forcément où est connecté le client (sinon, il ne pourrait pas choisir des paramètres comme l'adresse IP) et est donc bien placé pour renvoyer une adresse IP qui dépend de la localisation.

Autre question soulevée par ce choix entre adresse IP et nom de domaine : le temps qu'il faudra pour qu'un changement dans la configuration soit pris en compte. Si le serveur DHCP renvoie une adresse IP, et décide ensuite de la changer, il ne peut pas garantir que les clients la recevront immédiatement. Certes, il existe une option reconfigure dans DHCPv6 (RFC 8415, sections 16.11, 18.2.11 et 18.3.11), permettant au serveur des notifications non sollicitées, mais elle n'est pas obligatoire et il semble que bien des clients ne la gèrent pas. En revanche, si le serveur avait renvoyé un nom de domaine, et si l'application pense à le redemander souvent (un gros Si...), la nouvelle valeur sera effective au bout de N secondes où N est le TTL choisi par le serveur DNS. Le choix dépend donc de pas mal de paramètres (par exemple, est-ce que l'administrateur du serveur DHCP contrôle aussi le serveur DNS et peut choisir le TTL à volonté ?) que le concepteur de l'option ne peut hélas pas connaître à l'avance.

Autre argument de prudence avant d'utiliser des noms de domaine : il crée une dépendance envers le DNS. Il faut donc s'assurer que le serveur envoie bien la liste des résolveurs DNS, et que ceux-ci fonctionnent correctement.

Une caractéristique de DHCPv6 est le fait que les options peuvent être incluses dans d'autres options. Cela permet de faire des options spécifiques à certains cas, du genre une option Y qui n'a de sens que si on a aussi accepté l'option X. On encapsule alors Y dans X. Il y a donc des options top-level et des options encapsulées. Il y a aussi des sous-options, qui n'ont pas de numéro d'option propre mais sont numérotées par rapport au numéro de l'option qui les contient. Les numéros d'options dans DHCPv6 sont codés sur 16 bits (8 bits pour DHCPv4) et il y a donc abondance de numéros disponibles. Le RFC conseille donc de ne pas chercher à les économiser et recommande les options encapsulées plutôt que les sous-options. Plus rigolo, l'encapsulation peut être à plus de deux niveaux : c'est le cas de la délégation de préfixe du RFC 8415, où le préfixe peut contenir une option d'exclusion qui elle-même contient une option préfixe, indiquant le préfixe exclu.

DHCP (v4 ou v6) est un mécanisme à état : le serveur DHCP se souvient de ce qu'il a fait et en tient compte pour les réponses suivantes. L'exemple le plus classique concerne l'allocation d'adresses IP : le serveur doit se souvenir de quelles adresses ont été allouées, pour ne pas allouer deux fois la même. Toutefois, dès qu'il faut maintenir un état supplémentaire, en général pour donner des réponses différentes par client, on augmente la complexité du serveur. Le RFC recommande donc d'éviter de définir de nouvelles options imposant le maintien d'un état. On peut souvent obtenir le même effet en laissant le client générer une valeur unique, à partir de son adresse IP et d'informations générales.

J'ai déjà parlé plus haut du fait que les clients DHCP ne vont pas magiquement chercher des nouveaux paramètres dès que le serveur DHCP a été reconfiguré. Le mécanisme reconfigure ne va pas forcément marcher avec tous les clients et l'administrateur du serveur DHCP doit donc être prêt à voir des clients continuer à utiliser des vieux paramètres. Cela peut être important aussi pour le concepteur d'options, au cas où il espérerait des options dont les valeurs changent souvent (section 11).

Un autre cas rigolo est celui où il y a plusieurs serveurs DHCP sur le même réseau. Cela n'est pas forcément le résultat d'une erreur ou d'un piratage. Par exemple, si un réseau à la maison est connecté par deux FAI, chacun apportant sa box, deux serveurs DHCP répondront aux requêtes des clients. Le protocole DHCP ne fournit pas de mécanisme pour gérer cela, juste quelques conseils dans le RFC 8415, conseils qui ne semblent pas suivis par les implémentations actuelles. En pratique, bien des clients n'écoutent que le premier serveur qui leur a répondu (section 12 de notre RFC). Ils n'essaient pas de fusionner intelligemment les différentes sources. Par exemple, il serait logique d'utiliser le résolveur DNS du FAI 1 lorsqu'on va utiliser les adresses IP, et la ligne, de ce FAI, et le résolveur du FAI 2 dans l'autre cas. Mais ce n'est pas ce qui se passe et, aujourd'hui, le cas de la machine à plusieurs connexions réseau est toujours assez mal géré. C'est un problème général, qui n'est pas soluble dans le cadre d'une option DHCP particulière (voir les RFC du groupe de travail MIF).

En DHCP, la taille compte. C'est ce qu'explique la section 15, qui note que les paquets DHCPv6 ont une taille maximale de 64 ko. Contrairement à DHCPv4, il n'y a pas de trucs utilisés en couche 2, DHCPv6 est purement une application tournant sur UDP sur IPv6, avec des adresses locales au lien. Bon, c'est la théorie. En pratique, si on bourre un paquet d'options de grande taille, peut-on vraiment aller jusqu'à 64 ko ? Le RFC 8415 est plus prudent et dit « The server must be aware of the recommendations on packet sizes and the use of fragmentation as discussed in Section 5 of RFC 8200. ». Il ne semble pas qu'aucune mise en œuvre de DHCPv6 ait câblé en dur des limites de taille inférieures aux 64 ko légaux. Donc, ça devrait marcher mais, dans la réalité, personne n'a encore testé des réponses DHCP supérieures aux 1 280 octets qui sont le miminum qu'IPv6 doit accepter ou aux 1 500 octets qui sont la MTU d'Ethernet. Notre RFC suggère que, si on veut vraiment envoyer des grandes quantités de données, une option DHCP n'est pas la meilleure solution et qu'il vaut mieux envoyer au client un URL indiquant où chercher ces données.

Pas encore épuisé par tous les points qu'il faut garder en tête en définissant une nouvelle option DHCP ? C'est que le RFC n'est pas terminé. Une option peut-elle apparaître plusieurs fois dans une réponse DHCP (section 16) ? Par défaut, non, mais c'est possible si et seulement si c'est indiqué explicitement dans la spécification de l'option. Attention, l'ordre d'apparition n'est pas significatif (section 17). Un client peut mettre les options dans une structure de données qui ne préserve pas l'ordre (un dictionnaire, par exemple).

Autre piège lorsqu'il y a plusieurs options : il faut spécifier la sémantique des données ainsi récupérées. Ainsi, l'option AFTR du RFC 6334 (utilisée pour DS-Lite) est un singleton, une option à apparition unique. Il avait été envisagé de permettre plusieurs occurrences de l'option, permettant d'indiquer plusieurs AFTR (l'extrémité du tunnel DS-Lite auquel on se connecte, cf. RFC 6333). Mais comment le client devait-il choisir parmi eux ? Une répartition de charge entre les AFTR était-elle possible ? Et une bascule automatique d'un AFTR à l'autre en cas de panne ? Spécifier tout cela aurait été trop compliqué et l'option est donc restée un singleton.

Les messages DHCPv6 peuvent être relayés afin d'atteindre des réseaux où il n'y a pas de serveur DHCP. Contrairement à DHCPv4, les options spécifiques aux relais sont des options ordinaires, prises dans le même espace de numérotation que les autres (section 18 de notre RFC).

Au fait, comment un serveur sait-il quelles sont les options acceptées et gérées par le client ? Il existe une option ORO (Option Request Option), normalisé dans le RFC 8415, pour que le client indique ses capacités, à la fois ce qu'il acceptera, et ce qu'il utilisera réellement. Elle n'est pas obligatoire et ne représente donc pas un vrai mécanisme de négociation des options.

Et les innombrables techniques de transition d'IPv4 vers IPv6 ? Elles nécessitent sûrement des options DHCPv6, non (section 20) ? En fait, non. Notre RFC recommande de les transporter via DHCPv4 puisqu'elles deviendront inutiles lorsque IPv4 disparaitra (ah, l'optimisme...) et elles ne doivent donc pas encombrer l'espace des options DHCPv6.

Arrivés à ce point, les auteurs de nouvelles options DHCPv6 doivent se demander s'ils arriveront un jour à compléter le futur RFC décrivant leur option chérie. La section 21 est là pour les aider en fournissant une liste de points à couvrir, avec un exemple de texte pour chacun. Le RFC recommande trois sous-sections, une pour les clients DHCP, une pour les serveurs et une pour les relais (pour ces derniers, la plupart du temps, il n'y aura rien à faire, un relais doit relayer aveuglément les options qu'il ne connait pas). Par exemple, pour les clients, le RFC suggère de commencer par « Clients MAY request option foo, as defined in [RFC3315], sections 17.1.1, 18.1.1, 18.1.3, 18.1.4, 18.1.5 and 22.7. As a convenience to the reader, we mention here that the client includes requested option codes in Option Request Option. »... Plus qu'à copier/coller en mettant le vrai nom de l'option à la place.

Autre question bureaucratique, le RFC décrivant la nouvelle option doit-il indiquer dans ses métadonnées qu'il met à jour les RFC existants comme le RFC 8415 ? Non, répond la section 22. Il y a aujourd'hui environ 80 options définies et si toutes mettaient à jour le RFC 8415, l'implémenteur de DHCPv6 en aurait, des documents à lire ! Donc, la plupart des RFC définissant des options ne changeront pas les RFC existants. Par contre, s'il est nécessaire de remplacer une partie de la norme existante, alors, oui, on doit indiquer cette mise à jour. C'est le cas du RFC 6644 qui est bien décrit ainsi dans l'index des RFC « 6644 Rebind Capability in DHCPv6 Reconfigure Messages. D. Evans, R. Droms, S. Jiang. July 2012. (Format: TXT=19176 bytes) (Updates RFC3315) (Status: PROPOSED STANDARD) ».

Un peu de sécurité et de vie privée pour terminer. La section 23 rappelle aux auteurs d'options l'importance de la sécurité. DHCP est bien connu pour son absence totale d'authentification, qui fait qu'un serveur « pirate » peut facilement se glisser à la place d'un vrai et servir n'importe quoi. Il existe pourtant en théorie un mécanisme d'authentification (section 21 du RFC 3315) mais soyons francs : presque personne ne l'a programmé et quasiment personne ne l'a déployé. Bref, les concepteurs d'options doivent être conscients que les options seront transmises en clair et, pire, qu'un méchant pourra envoyer des fausses valeurs.

Autre problème de sécurité, la longueur des options. Si elle est de taille fixe, le client qui la lit devra vérifier que la longueur réelle est bien la longueur théorique (autrement, il risque un débordement de tampon). Si elle est de taille variable (un URI, par exemple), le lecteur de l'option doit se méfier, l'option peut être très longue... Des valeurs ayant la taille normale peuvent néanmoins donner de drôles de résultats. Par exemple, une option contenant une adresse IP peut indiquer, si le serveur est malveillant ou bien s'il a été doublé par un serveur pirate, une adresse de diffusion, pour pousser le client à arroser tout le réseau...

À noter que le RFC ne rappelle pas une spécificité de DHCPv6 : il est courant qu'un réseau IPv6 n'ait pas de serveur DHCP légitime du tout, l'administrateur réseaux préférant la configuration SLAAC. Dans ce cas, un serveur pirate aurait la partie très facile, n'ayant pas à faire la course avec le serveur légitime.

Enfin, il reste la question de la vie privée (section 24). Les messages DHCP sont transmis quasiment toujours en clair et il ne faut donc pas compter sur leur confidentialité. En théorie, on pourrait utiliser IPsec pour les chiffrer mais personne ne le fait.


Téléchargez le RFC 7227


L'article seul

RFC 7225: Learning NAT64 PREFIX64s using Port Control Protocol (PCP)

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : M. Boucadair (France Telecom)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pcp
Première rédaction de cet article le 19 mai 2014


Lorsqu'on est situé derrière un routeur NAT64, parce qu'on n'a pas d'adresse IPv4 et qu'on dépend de ce routeur pour la communication avec les vieux systèmes qui sont encore uniquement en IPv4, on peut, la plupart du temps, ignorer ce que fait ledit routeur et, notamment, le préfixe qu'il utilise pour synthétiser des adresses IPv6 à partir des adresses IPv4 des systèmes archaïques. C'est la cuisine interne du routeur. Mais, parfois, ce n'est pas possible et on aurait besoin de connaître ce préfixe pour faire la synthèse d'adresses IPv6 soi-même. Ce nouveau RFC décrit une option du protocole PCP permettant d'apprendre le préfixe de synthèse.

Un petit rappel sur NAT64, normalisé dans le RFC 6146. Lorsqu'on a un réseau purement IPv6, mais qu'on veut pouvoir communiquer avec les machines purement IPv4, une des techniques possibles est d'installer un routeur NAT64 qui va faire de la traduction d'adresses d'IPv6 vers IPv4 et retour. Les machines du réseau étant purement IPv6, il faut qu'elles trouvent une adresse IPv6 lorsqu'elles demandent, même si la machine avec qui elles veulent communiquer n'en a pas. NAT64 est donc inséparable de DNS64 (RFC 6147) qui synthétise ces adresses IPv6 en les préfixant avec un préfixe spécial, que le routeur NAT64 reconnaîtra (RFC 6052). Le choix de ce préfixe est une décision locale et les machines du réseau local purement IPv6 ne connaissent pas ce préfixe. La plupart du temps, cela ne les gêne pas. Elles croiront parler en IPv6 avec leur partenaire. Mais, parfois, cela pourrait être utile. Par exemple, dans certains protocoles (par exemple SIP), il y a des références : Alice écrit à Bob en IPv6, le routeur NAT64 transmet à Bob en IPv4 et Bob, voyant une session en IPv4, répond à Alice « envoies les paquets à l'adresse 192.0.34.19 ». Le routeur NAT64 n'analyse pas les paquets SIP et ne peut donc pas traduire cette référence. C'est donc Alice qui doit le faire, ce qui implique de connaître le préfixe à utiliser, pour que le routeur NAT64 sache quoi faire de ces paquets. Le RFC 7051 faisait le tour des possibilités existantes pour découvrir ce préfixe et le RFC 7050 proposait une solution. Notre RFC 7225 en suggère une autre.

PCP (RFC 6887) est un protocole (assez récent et encore très peu déployé) de communication entre une machine sur un réseau local et la box qui relie ce réseau à l'Internet. Son utilité principale est pour l'ouverture de trous dans le NAT, pour permettre, par exemple, les connexions entrantes. Il permet la définition d'options qui ajoutent des possibilités comme celle décrite dans ce RFC, PREFIX64.

La section 3 de notre RFC décrit le cahier des charges. On veut :

  • distinguer les adresses IPv6 natives de celles qui ont été synthétisées par NAT64.
  • pouvoir synthétiser des adresses IPv6 pour NAT64, à partir d'adresses IPv4, même quand DNS64 n'est pas disponible ou utilisable.
  • permettre l'utilisation de DNSSEC.
  • gérer des cas compliqués comme la découverte du préfixe lorsque le préfixe dépend de la destination.
  • fonctionner même s'il y a plusieurs routeurs NAT64 sur le réseau local (avec des préfixes différents, sinon, cela ne serait pas drôle).

La section 4 du RFC 7051 contient des études de cas plus détaillées. Par exemple, on peut souhaiter avoir son propre résolveur DNS, sur sa machine, et donc on doit faire la synthèse des adresses IPv6 soi-même. Cela nécessite de connaître le préfixe utilisé sur ce réseau local. Il existe de nombreuses raisons pour avoir un résolveur local sur sa machine mais le RFC en cite surtout une : pouvoir faire du DNSSEC proprement, c'est-à-dire avec validation locale. Autre cas où un mécanisme pour apprendre le préfixe est nécessaire, celui cité plus haut où une application transmet des références, sous forme d'une adresse IP. Cela ne concerne pas que SIP, cité plus haut (RFC 3261 et RFC 4566) mais aussi WebRTC (RFC 8825), BitTorrent (lorsque le tracker indique les adresses des leechers et seeders), etc.

La section 4 du RFC décrit le format de la nouvelle option, PREFIX64, de numéro 129 (cf. le registre IANA). Le point important est que, pour chaque préfixe IPv6 listé dans le champ Prefix64, il y a une liste (pouvant être de taille nulle) de préfixes IPv4 pour lesquels ce préfixe s'applique.

Que doit faire le serveur PCP avec cette option ? Lorsque le client le demande (en mettant l'option PREFIX64 dans sa requête), le serveur lui répond poliment, avec le préfixe que lui, serveur, utilisera pour les synthèses d'adresses IPv6. Le serveur a le droit d'envoyer cette option PREFIX64 même si on ne lui a rien demandé. Il peut y avoir plusieurs occurrences de l'option si le serveur PCP (le routeur NAT64) utilise plusieurs préfixes.

Et le client ? Il peut demander explicitement le préfixe, en utilisant l'option PREFIX64 avec une valeur spéciale pour le préfixe (::/96). Attention à ne pas paniquer si la réponse contient plusieurs préfixes IPv6, c'est normal. Le client ne doit pas garder en vrac les préfixes mais les laisser associés à un serveur PCP particulier (au cas où il y en ait plusieurs sur le réseau, ce qui est rare, mais permis).

Des exemples d'usage figurent dans la section 5, avec un exemple détaillé pour le (compliqué) cas de SIP : le client SIP (le softphone, qui n'a que IPv6) va envoyer une requête PCP de type MAP avec les options PORT_SET et PREFIX64. Il récupère les ports à utiliser et le préfixe, mettons 2001:db8:122::/48. Avec les informations sur son adresse IPv4 externe, il va construire une offre SDP, qui ne contiendra que de l'IPv4. Ensuite, le logiciel fait une requête SIP INVITE, en IPv6, en utilisant une adresse de destination formée à partir du préfixe et de l'adresse IPv4 du serveur SIP. Le routeur NAT64, voyant ce préfixe, va ensuite faire son travail (conversion en v4, transmission). Pareil pour le message de routeur (l'acceptation de l'appel). Notez que l'« intelligence » était presque entièrement dans le client : le routeur NAT64 n'a pas d'ALG.

À ma connaissance, il n'existe encore aucun client ou serveur PCP avec cette option.


Téléchargez le RFC 7225


L'article seul

RFC 7221: Handling of Internet Drafts by IETF Working Groups

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : A. Farrel (Juniper Networks), D. Crocker (Brandenburg InternetWorking)
Pour information
Première rédaction de cet article le 30 avril 2014


Voici un nouveau RFC procédural, consacré à la gestion des Internet Drafts, ces brouillons de futurs RFC. L'IETF est structurée en groupes de travail (WG, pour Working Groups) et ces groupes doivent, comme leur nom l'indique, travailler. Mais pour produire quoi ? Des documents. L'IETF n'écrit pas de logiciels, ne fabrique pas de matériel, cette organisation de normalisation est entièrement vouée à produire des documents, les fameux RFC. Mais avant d'être un RFC, le document passe par le stade Internet Draft. D'où viennent les Internet Drafts des groupes de travail ? Comment sont-ils créés ?

Quand un groupe de travail développe un Internet Draft, il y a eu plusieurs points de départ possibles. Le groupe a pu partir d'une feuille blanche, le document ayant été rédigé dans le cadre du travail du groupe. Parfois, également, le document existait avant, et a été adopté par le groupe de travail. Des fois, lors de son adoption, le document était très avancé, presque prêt et, des fois, il méritait largement son nom de draft (brouillon). L'IETF se méfie (en théorie) des processus trop formalisés et les groupes de travail ont donc une grande latitude dans les choix. Si la charte du groupe de travail met des limites, ces limites laissent souvent bien des possibilités. (Les chartes des groupes de travail existants sont disponibles en ligne ; notez que beaucoup d'entre elles font référence à des Internet Drafts avec des formules du genre « le groupe partira du document draft-smith-foo-bar ».) Ce RFC n'ajoute pas de nouvelles règles (mon opinion personnelle est qu'il y en a déjà beaucoup, pour une organisation qui aime bien afficher son mépris des règles bureaucratiques) mais décrit les pratiques existantes. « Pragmatics over niceties »

D'abord, un point important (section 1.1), il y a draft et draft. N'importe qui peut publier un draft, et il y a effectivement très peu de formalités pour cela. La plupart des drafts ne sont donc pas des Working Group drafts. Ces drafts des groupes de travail sont des documents sous le contrôle de l'IETF (et pas d'un individu, même pas de leur auteur, ou des présidents du groupe de travail), et leur avancement vers la publication en RFC dépend donc du consensus approximatif (rough consensus) au sein du groupe dans son ensemble. Ce mécanisme de décision est décrit dans le Tao et de manière plus formelle dans la section 3.3 du RFC 2418.

On peut dire que le draft individuel représente la liberté quasi-totale alors que le draft de groupe de travail est une œuvre collective, représentant l'opinion du groupe. Résultat, le processus est parfois laborieux, voire excessivement frustrant, mais c'est nécessaire pour s'assurer que le document représente bien une vue collective et a donc plus de signification qu'un article publié sur un blog personnel. L'auteur du document a un rôle particulier mais, en théorie, pas de pouvoir de décision (bien sûr, être celui qui tient le clavier a quelques avantages lorsqu'il faut traduire en mots le consensus du groupe). Comme le dit le proverbe africain, « si tu veux voyager vite, pars seul, si tu veux voyager loin, pars en groupe ». Les règles précises pour ces drafts sont formalisées dans le RFC 2026 (notamment la section 2.2), la liste des points à vérifier, le RFC 2418 (notamment sa section 7.2) et enfin bien sûr le Tao.

On reconnait un draft de groupe de travail à son nom. Il est nommé draft-ietf-WGNAME-...WGNAME est le nom du groupe. Au contraire, le draft individuel se nomme draft-LASTNAME-...LASTNAME est le nom de l'auteur. Ainsi, au moment où j'écris (avril 2014), le draft draft-ietf-precis-framework est un document du groupe de travail precis (dont le nom apparait comme deuxième composant du nom du document) alors que draft-bortzmeyer-dns-qname-minimisation est, pour l'instant, un document individuel (avec mon nom en deuxième composant). Certains drafts individuels seront adoptés par un groupe de travail et deviendront alors des documents de groupe, en changeant de nom. Par exemple, comme on peut le voir sur le « DataTracker », le draft individuel draft-sheffer-uta-tls-attacks a été adopté par le groupe de travail UTA et est devenu le draft-ietf-uta-tls-attacks.

Maintenant, les détails. La section 2 couvre l'adoption d'un draft individuel par un groupe de travail. Rappelez-vous, il n'y a pas de règles formelles et générales sur les critères d'adoption, le groupe de travail doit prendre ses responsabilités. En pratique, notre RFC note que les critères importants sont :

  • Mention explicite du draft dans la charte du groupe,
  • Document qui coïncide avec le sujet du groupe, et ne demande pas de modification de la charte, ou alors très légère,
  • Document de qualité, suffisamment clair et réaliste pour que, en l'utilisant comme base de travail, le groupe ait des chances d'aboutir à un RFC (l'IETF se méfie des groupes qui s'agitent pendant des années sans rien produire),
  • Risques liés à l'appropriation intellectuelle,
  • Et, bien sûr, soutien du groupe.

Rappelez-vous que les groupes fonctionnent par consensus approximatif. L'unanimité n'est pas nécessaire. D'autre part, le draft est un... brouillon. Il n'est pas exigé qu'il soit paré pour la publication, tout juste vérifie-t-on quelques détails pratiques. Et le groupe peut toujours adopter un document qui sera finalement abandonné : l'adoption ne garantit absolument pas la publication. On voit même parfois des drafts d'un groupe de travail redevenir finalement des documents individuels (cf. section 5.2).

Une fois la décision prise, les présidents (ils sont toujours deux) du groupe de travail doivent ensuite :

  • Vérifier que le groupe est d'accord pour cette adoption (curieusement, ce point n'est pas mis en premier dans le RFC).
  • Bien s'assurer que l'auteur comprend que le contrôle est transféré à l'IETF. Ce n'est plus lui qui décide du contenu du document (il y a eu quelques cas contentieux, par exemple où l'auteur demandait qu'on retire son nom, car il n'était plus d'accord, mais les plus gros problèmes surviennent lorsque le document était issu d'une entreprise privée, et décrivait une technologie que cette entreprise aurait voulu voir l'IETF adopter sans discussion).
  • Vérifier si les requins de l'appropriation intellectuelle ont des brevets possibles sur cette technique (cf. RFC 6302).
  • Respecter quelques règles procédurales comme l'annonce officielle de l'adoption sur la liste de diffusion du groupe, la notification du changement de nom aux gérants du DataTracker pour que les outils IETF gardent l'historique, etc.

La section 3 décrit le rôle des auteurs et rédacteurs (editors). Certaines personnes à l'IETF font la différence entre ces deux concepts (voir « RFC Editorial Guidelines and Procedures -- Author Overload » et la section 6.3 du RFC 2418), l'auteur étant vu comme mettant réellement du sien dans le document, formant de nouvelles idées, et le rédacteur comme étant un simple exécutant, quasiment passif, des volontés du groupe de travail. Mais notre RFC ne fait pas de différence, estimant qu'elle serait trop subjective. Auteurs et/ou rédacteurs sont choisis par les présidents du groupe de travail (rappelez-vous qu'une fois un document adopté, le contrôle passe à l'IETF) et ne sont pas forcément le ou les auteurs originaux. En pratique, toutefois, il est fréquent que l'auteur original continue après l'adoption.

La section 4 couvre la façon de traiter les documents existants. Un groupe de travail n'est pas forcé de prendre ces documents, de corriger deux ou trois fautes d'orthographe, et de les publier comme RFC. Bien au contraire. L'IETF, contrairement à certaines SDO, ne se contente pas de mettre un coup de tampon approbateur sur des documents qui arrivent tout cuits. Les documents existants peuvent être considérés comme :

  • Des idées, dont on peut s'inspirer, mais sans plus,
  • Un mécanisme raisonnable dans son principe mais dont de nombreux points vont devoir être traités, révisés, détaillés,
  • Une description d'un bon système, qui a juste besoin de quelques aménagements,
  • Une technique déjà déployée, et où tout changement doit donc être abordé avec prudence, afin de ne pas remettre en cause la base installée.

Bref, la palette est très large. Tout document extérieur adopté par un groupe de travail ne sera pas traité de la même façon. Certains documents arrivent à l'IETF après des années d'usage de la technologie qu'ils décrivent, d'autres sont des idées purement théoriques, et encore, où l'analyse théorique est souvent sommaire.

Il y a aussi quelques points divers traités dans la section 5. D'abord, entre les drafts purement individuels et ceux d'un groupe de travail, il y a aussi des drafts individuels mais qui sont sous le parapluie d'un groupe de travail (voir le document « Guidance on Area Director Sponsoring of Documents »). On les reconnait à leur nom draft-LASTNAME-WGNAME-.... C'est rare, mais cela arrive. (Notez aussi qu'il n'existe pas de police des drafts, donc certains auteurs choisissent parfois des noms qui violent ces conventions.)

Autre cas spécifique, celui de drafts différents sur le même sujet, par exemple deux protocoles jouant le même rôle, chacun d'entre eux soutenu par une partie du groupe de travail. Un groupe n'est pas obligé de trancher. Les différences entre les deux propositions peuvent refléter des choix fondamentaux, chaque draft ayant ses mérites propres. Le groupe de travail peut suggérer une fusion, mais ce n'est pas obligatoire. Dans le domaine technique, la fusion de deux bons systèmes peut parfaitement donner une horreur, ce que le RFC illustre par l'histoire du sous-marin et de l'hélicoptère : les sous-marins sont utiles et bien adaptés à leur tâche. Les hélicoptères aussi. Mais tenter de concevoir un engin qui aurait les caractéristiques des deux produirait probablement une machine inadaptée aux deux rôles. (L'histoire est originellement due à Marshall Rose.)

Le problème des deux drafts concurrents est d'autant plus sensible si un des deux drafts arrive après l'autre : les auteurs du premier peuvent mal prendre cette « intrusion ». En même temps, l'IETF travaille par écrit et encourage fortement l'expression des idées sous forme d'un draft, pour obliger les concepteurs à raffiner leurs idées, à ne pas se contenter d'un résumé dans un message de deux paragraphes. Donc, ce genre de concurrence continuera à se produire.


Téléchargez le RFC 7221


L'article seul

RFC 7218: Adding acronyms to simplify DANE conversations

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : O. Gudmundsson (Shinkuro)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dane
Première rédaction de cet article le 23 avril 2014


Le système DANE permet de publier des clés cryptographiques ou des certificats dans le DNS, en les authentifiant avec DNSSEC. Ces clés ou certificats sont mis dans un enregistrement de type TLSA et cet enregistrement comprend plusieurs champs portant des valeurs numériques. Jusqu'à ce RFC, il n'existait pas d'acronymes standards pour désigner les valeurs possibles, ce qui rendait difficile la communication entre humains, et le choix des noms de variables dans les programmes. Ce nouveau RFC ne change pas le système DANE mais décrit simplement ces acronymes standards.

Voici un exemple actuel d'enregistrement TLSA (enregistrement DANE) :

_443._tcp.fedoraproject.org. 300 IN TLSA 0 0 1 (
				D4C4C99819F3A5F2C6261C9444C62A8B263B39BC6ACC
				E35CDCABE272D5037FB2 )

Les champs dont les valeurs sont ici 0, 0 et 1 sont les champs dont on souhaite pouvoir parler plus facilement. La norme DANE, le RFC 6698, ne définit pas de noms courts pour les valeurs. Par exemple, le deuxième champ, le Sélecteur, qui vaut 0 ici, peut prendre deux valeurs, que le RFC 6698 nomme Full certificate et SubjectPublicKeyInfo, alors que notre nouveau RFC 7218 propose d'ajouter les acronymes Cert et SPKI. Dans le futur, on peut même imaginer que les logiciels puissent charger directement une zone DNS où les valeurs numériques seraient remplacées par ces acronymes (et dig pourrait les afficher au lieu des valeurs numériques actuelles).

Le registre IANA en https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml est donc modifié pour y inclure ces acronymes. Le champ « Utilisation du certificat » (Certificate usage), sans doute celui où il y a eu le plus de confusions et de discussions, peut prendre les valeurs :

  • 0, contrainte sur l'AC, désormais PKIX-TA,
  • 1, contrainte sur le certificat, désormais PKIX-EE (EE pour End Entity),
  • 2, déclaration de l'AC, désormais DANE-TA,
  • 3, déclaration du certificat, désormais DANE-EE.

Notez le regroupement des acronymes en deux groupes : les acronymes commençant par PKIX sont les utilisations où on fait toujours la validation PKIX classique (RFC 5280) et ceux commençant par DANE sont ceux où on n'utilise plus le modèle de validation de X.509, on est purement dans un monde DANE.

Le champ « Sélecteur » (Selector), lui, peut être :

  • 0, le certificat complet, désormais Cert,
  • 1, la clé seule, désormais SPKI.

Et le champ « Méthode de correspondance » (Matching type, et merci à Romain Tartière pour avoir trouvé une erreur dans mon article original) :

  • 0, valeur brute des données, désormais Full,
  • 1, condensat SHA-256 des données, désormais (logiquement) SHA2-256,
  • 2, condensat SHA-512 des données, désormais SHA2-512.

La section 3 donne des exemples d'enregistrements affichés avec ces acronymes. Pour celui cité plus haut, ce serait :

_443._tcp.fedoraproject.org. 300 IN TLSA PKIX-TA Cert SHA2-256 (
				D4C4C99819F3A5F2C6261C9444C62A8B263B39BC6ACC
				E35CDCABE272D5037FB2 )

Les humains étant particulièrement sensibles aux noms, les discussions ont été longues quant au choix des acronymes. Tout le monde était d'accord qu'il vallait mieux des acronymes que des nombres, simplement, chacun avait les siens comme favoris.

Pour la petite histoire, une bonne partie de la démarche menant à ce RFC vient de l'introduction de DANE dans Postfix. Viktor Dukhovni, en faisant ce travail, a découvert DANE et signalé à l'IETF nombre de problèmes et de limites, et notamment la difficulté à ne manipuler que des valeurs numériques, par exemple dans les documentations.


Téléchargez le RFC 7218


L'article seul

RFC 7217: A Method for Generating Semantically Opaque Interface Identifiers with IPv6 Stateless Address Autoconfiguration (SLAAC)

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : F. Gont (SI6 Networks / UTN-FRH)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 2 mai 2014


Il existe actuellement de nombreuses méthodes (y compris manuelles) de générer les adresses IPv6 mais le mode SLAAC (Stateless Address Autoconfiguration, normalisé dans le RFC 4862) est particulièrement intéressant car il permet aux machines IPv6 de s'auto-configurer, sans qu'il soit nécessaire de mémoriser un état dans un serveur central. SLAAC fonctionne en concaténant à un préfixe, appris en écoutant les annonces des routeurs, un identifiant d'interface spécifique à la machine. Au tout début d'IPv6, il n'existait qu'une seule façon de générer ces identifiants d'interface, via l'adresse MAC de la machine. Puis une deuxième façon a été ajoutée, en tirant au sort l'identifiant d'interface, et en en changeant souvent, pour préserver sa vie privée (RFC 8981). Et une troisième, la plus sûre, où l'identifiant d'interface est dérivé d'une clé cryptographique (RFC 3972, mais ces CGA sont peu utilisés et notre RFC n'en parle guère). Notre nouveau RFC propose une quatrième façon, en condensant un secret, un certain nombre de caractéristiques de la machine et le préfixe, de manière à avoir des identifiants stables (comme ceux de la première façon), mais préservant quand même partiellement la vie privée (comme ceux de la deuxième façon) : l'identifiant d'interface change quand la machine change de réseau, ne permettant plus de la suivre à la trace. Cette méthode permet de choisir l'identifiant d'interface, elle ne modifie pas l'algorithme présenté dans le RFC 4862.

Les identifiants d'interface obtenus par l'adresse MAC simplifient bien des choses, notamment grâce à leur stabilité : on éteint la machine et on la rallume, on est sûr de retrouver la même adresse IPv6. Ainsi, lorsqu'on regarde le journal des connexions, on peut facilement retrouver la machine qu'on a repéré. Et créer des ACL est simple, puisque les adresses ne changent pas. Mais, en échange, ces identifiants ont des inconvénients, notamment pour la vie privée (cf. l'étude de l'IAB). La stabilité permet de suivre à la trace une machine pendant une longue période. Pire, même si la machine change de réseau, l'identifiant d'interface ne change pas, permettant de suivre cette trace même en cas de mobilité. D'autre part, comme l'adresse MAC dépend du constructeur, les adresses IPv6 d'un même parc ont donc souvent pas mal de bits en commun. Cette prévisibilité facilite notamment le balayage des adresses réseau (qui est normalement difficile en IPv6, vu le nombre d'adresses, cf. RFC 7707) et cette utilisation a été mise en œuvre dans des outils de reconnaissance existants (cf. mon article sur les attaques contre IPv6). Enfin, des opérations de maintenance matérielle, comme de changer une carte Ethernet, vont faire changer l'adresse, annulant l'avantage de stabilité.

Le RFC 8981 voulait s'attaquer à ces problèmes avec ses adresses temporaires, où l'identifiant d'interface est choisi aléatoirement et change de temps en temps. L'idée est que la machine aurait une (ou plusieurs) adresses temporaires, une (ou plusieurs) adresses stables et qu'on utiliserait l'adresse temporaire pour les connexions sortantes, et l'autre pour les entrantes. Cela fournit une bonne protection, question vie privée, mais au prix de quelques inconvénients. Comme rien n'est gratuit en ce bas monde, ces adresses compliquent la vie de l'administrateur réseaux : interpréter le trafic qu'on voit passer est moins simple (beaucoup de techniques de protection de la vie privée ont ce défaut). On voit donc des entreprises couper ces adresses temporaires, afin de mieux surveiller leurs employés (cf. le récit de Ron Broersma). Les adresses privées peuvent également poser des problèmes pour les commutateurs réseaux. En outre, pour des engins aux capacités limités (Internet des objets), la mise en œuvre d'une technique supplémentaire de génération des adresses peut être trop coûteuse. Enfin, comme les adresses traditionnelles sont toujours en place, certaines activités, comme le balayage d'adresses en suivant certains motifs, liés aux préfixes des constructeurs, restent possibles. Bref, la situation actuelle n'est pas complètement satisfaisante.

Notre nouveau RFC 7217 ne vise pas à remplacer les adresses temporaires, qui restent la bonne solution pour limiter le suivi d'une machine à la trace. Il veut plutôt remplacer les adresses basées sur l'adresse MAC, en gardant l'importante propriété de stabilité. L'idée est que les machines IPv6, dans le futur, auront uniquement une adresse stable, générée selon ce RFC, ou bien une adresse stable générée selon ce RFC et une adresse temporaire. L'adresse fondée sur l'adresse MAC aurait vocation à disparaître à terme (même si le RFC n'est pas aussi radical, cf. section 4, dernier élément de l'énumération), car elle facilite trop le balayage des réseaux et le suivi d'une machine mobile, sans avoir d'avantages par rapport à la solution de ce RFC.

L'objectif principal est le mécanisme SLAAC d'auto-configuration sans état mais la solution de ce RFC peut aussi s'appliquer à d'autres méthodes comme DHCP (RFC 8415), où le serveur peut utiliser un algorithme identique pour générer les adresses qu'il va distribuer.

La section 4 formalise le cahier des charges de la nouvelle méthode de génération des identifiants d'interface :

  • Identifiant stable dans le temps, tant qu'on est connecté au même réseau (ce qui permet la corrélation entre les différentes activités de la machine dans le temps : si on ne veut pas cela, il faut utiliser les adresses temporaires),
  • Identifiant dépendant du préfixe, de manière non prévisible par un observateur : si un client IPv6 contacte un serveur, puis change de réseau, puis contacte le même serveur, le serveur ne doit pas pouvoir facilement rapprocher les deux adresses (l'un des plus gros inconvénients de la méthode historique de génération d'adresses était cette possibilité de rapprochement),
  • Identifiant non prévisible pour un observateur, même s'il connait des identifiants sur le même réseau,
  • Il serait souhaitable, si possible, que l'identifiant soit indépendant de l'adresse MAC, de manière à ce qu'un changement de carte Ethernet ne se traduise pas par un changement d'adresss IP (les identifiants de la méthode historique sont trop stables pour préserver la vie privée mais changent trop lorsqu'on modifie le matériel).

À noter que l'algorithme exact utilisé pour le choix de l'identifiant d'interface (et donc de l'adresse) est une décision purement locale. Chaque machine fait comme elle veut, cela n'affecte pas l'interopérabilité. Sur un même réseau peuvent donc coexister des machines utilisant des algorithmes différents.

Je crois que j'ai un peu abusé de votre patience avec ces longs préliminaires. Peut-être auriez-vous préféré qu'on commence directement avec l'algorithme, la solution avant la description du problème ? En tout cas, arrivé à la section 5, vous avez cet algorithme. Il est trivial : l'identifiant d'interface est le résultat de l'application d'une fonction de condensation à plusieurs paramètres. Cette fonction doit donner un résultat qui, vu de l'extérieur, sera imprévisible, et elle ne doit pas être inversible. Un exemple d'une telle fonction est la fonction de condensation cryptographique SHA-256, dont on conservera les 64 bits de plus faible poids (par contre, MD5 ne doit pas être utilisé, cf. RFC 6151). Rappelez-vous que la génération de l'identifiant d'interface est un processus purement local et que différentes machines peuvent donc utiliser des fonctions de condensation différentes. Les paramètres de la fonction de condensation comportent au moins :

  • Le préfixe des adresses IP (donc, changer de réseau fait changer d'identifiant d'interface, ce qui est souhaité), tel qu'on l'a appris, par exemple via les RA (Router Advertisement),
  • Le nom de l'interface réseau, par exemple eth0 pour une machine Linux, le but étant que la machine ait des adresses différentes pour chaque réseau, même s'ils utilisent le même préfixe,
  • Un compteur des conflits (duplication d'adresses), qui part de zéro et est incrémenté chaque fois qu'une collision d'adresses (deux adresses identiques sur le même lien) a lieu,
  • Une clé secrète, spécifique à la machine (tous les autres paramètres et, bien sûr, l'algorithme exact utilisé, peuvent être découverts plus ou moins facilement par un observateur : cette clé est donc indispensable si on veut des adresses vraiment imprévisibles),
  • Et, facultativement, un identifiant du réseau, par exemple le SSID ou bien une des idées du RFC 6059.

L'annexe A du RFC fournit plusieurs idées pour le nom de l'interface réseau.On peut se servir de l'index d'interface (RFC 3493), du nom s'il est assez stable (un système d'exploitation où les interfaces réseau portent des noms dépendant du pilote utilisé aura des noms moins stables que Linux, où ce nom est générique, eth1, wlan0, etc), ou de tout autre identificateur fourni par le système (certains ont un UUID par interface réseau).

La clé secrète sera typiquement générée à l'initialisation de la machine, par un processus aléatoire ou pseudo-aléatoire, et stockée de manière à survivre aux redémarrages. Mais le RFC prévoit aussi le cas où elle pourrait être affichée, voire modifiée, par l'administrateur système. Le point important est de se rappeler que toute la sécurité de ce système en dépend donc elle doit être bien choisie.

Cet algorithme est largement inspiré de celui décrit dans le RFC 1948, pour un usage très différent.

Une fois obtenu un identifiant d'interface, il faut vérifier qu'il n'est pas dans les identifiants réservés du RFC 5453. Sinon, tous les bits de l'identifiant d'interface sont opaques (au sens du RFC 7136) et il ne faut donc pas leur chercher de signification particulière. Dernière vérification à faire avant d'utiliser l'adresse construite avec cet identifiant d'interface : tester qu'il n'y a pas de conflits avec une autre machine. En effet, comme chaque machine du réseau tire son identifiant d'interface au hasard, il y a une probabilité non nulle (mais très faible) que deux machines tirent le même identifiant et donc la même adresse IP. Elles doivent donc suivre la procédure de détection de conflits « DAD » du RFC 4862 (section 5.4).

C'est désormais la méthode de ce RFC qui est recommandée lorsqu'on veut des adresses stables (cf. RFC 8064), à la place des anciennes adresses dérivées de l'adresse MAC.

Il existait une mise en œuvre pour Linux, par Hannes Frederic Sowa, mais, apparemment, cela a été intégré dans la distribution officielle peu après la sortie du RFC. (Par contre, à ma connaissance, rien pour Windows ou pour les BSD.)


Téléchargez le RFC 7217


L'article seul

RFC 7216: Location Information Server (LIS) Discovery using IP address and Reverse DNS

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : M. Thomson (Mozilla), R. Bellis (Nominet UK)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF geopriv
Première rédaction de cet article le 30 avril 2014


Normalement, pour trouver le serveur de localisation (LIS) qui lui permettra d'en connaître plus sur sa position physique, et donc d'accéder à des services fondés sur cette position, une machine utilise les techniques du RFC 5986. Mais celles-ci nécessitent une coopération de la part de la box, coopération qui a l'air difficile à obtenir. Ce nouveau RFC propose donc une autre solution, fondée entièrement sur le DNS.

Un LIS est normalement un service du système d'accès à l'Internet (et on en change donc quand on change de réseau). Il connait la topologie du réseau et pourra donc répondre aux requêtes des machines clients lorsqu'elles voudront connaître leur place dans le monde (en utilisant le protocole du RFC 5985). Cette localisation est utilisée, par exemple, dans les services d'urgence (imaginez un appel VoIP au 112 où l'appelant n'a pas le temps de donner sa position : il faut que son logiciel le fasse pour lui.) Reste à trouver ce LIS. Le RFC 5986 proposait une méthode simple, une option DHCP (comme il en existe pour trouver les serveurs DNS ou NTP). Mais cela suppose que le serveur DHCP soit mis à jour pour suivre le RFC 5986 et, apparemment, peu le sont. Déployer une nouvelle option DHCP sur toutes les boxes du monde prend un temps fou (convaincre les développeurs, modifier le code, mettre à jour les millions de boxes existantes ou bien attendre leur remplacement...)

Donc, il vaut mieux une méthode qui ne dépende pas de la box. C'est ce que propose notre RFC. Le principe est de partir de l'adresse IP de la machine, de la transformer en un nom de domaine et d'utiliser ensuite ce nom pour des requêtes DDDS, comme c'était le cas avec le RFC 5986, qui partait d'un nom de domaine reçu en DHCP puis le soumettait à DDDS.

Bon, mais le lecteur attentif a dû noter un piège : la machine typique du réseau local typique du M. Michu typique a une adresse IPv4 privée. Ce n'est pas très utile pour faire des requêtes dans le DNS public. Il va donc falloir que la machine commence par utiliser un protocole comme STUN pour trouver son adresse IP publique. Donc, le principe de notre RFC 7216 est :

  • D'abord, on essaie la requête DHCP du RFC 5986. Si elle réussit, c'est bon, sinon, on continue avec la nouvelle méthode,
  • On cherche la ou les adresses IP publiques de la machine,
  • On les convertit en noms de domaine dans les zones comme in-addr.arpa. Par exemple, 192.0.2.143 devient 143.2.0.192.in-addr.arpa.
  • On passe alors à la découverte DDDS de la section 4 du RFC 5986. En gros, on fait une requête pour le type NAPTR, service LIS:HELD, sur le nom de domaine obtenu à l'étape précedente.
  • Si ça ne donne rien, on raccourcit le nom de domaine (on retire le composant le plus à gauche) et on réessaie la requête NAPTR.

Pour l'étape « trouver l'adresse IP publique de la machine », on a vu que la méthode suggérée est STUN (RFC 8489), avec un message de type Binding Request et une réponse dans le paramètre XOR-MAPPED-ADDRESS. Mais une machine a aussi le droit de se servir de PCP (RFC 6887, sections 10.1 et 11.4, la réponse à un MAP request va contenir l'adresse publique) ou UPnP pour cela. Notez que, parfois, l'adresse ainsi obtenue peut être à son tour une adresse privée (RFC 1918) et que cela n'empêche pas la procédure de découverte du LIS de fonctionner (à condition que le résolveur DNS utilisé sache rediriger les requêtes vers un serveur local qui fait autorité pour les in-addr.arpa correspondants).

Quant au raccourcissement du nom de domaine, il est prévu pour tenir compte du fait qu'il n'y aura pas forcément un enregistrement NAPTR pour tous les noms de domaine correspondant à une adresse publique. Parfois, le LIS servira une population plus large (en IPv4, un /24, voire même un /16) et on n'aura de NAPTR que pour le nom raccourci. Ainsi, avec l'adresse IP publique citée plus haut, si on ne trouve pas de NAPTR pour 143.2.0.192.in-addr.arpa, on essaiera avec 2.0.192.in-addr.arpa puis 0.192.in-addr.arpa. Pour IPv6, notre RFC recommande de raccourcir le nom de domaine pour correspondre successivement à un /64, un /56, un /48 ou un /32.

Comme toujours avec la géolocalisation, il y a des questions de vie privée délicates (section 5, et voir aussi le RFC 6280). Ce RFC décrit un mécanisme pour permettre à une machine de trouver son LIS, et donc finalement sa localisation. Ceci n'est pas un risque pour la vie privée. Par contre, une fois cette information obtenue, il faudra faire attention à qui on l'envoie.

Il y a apparemment plusieurs mises en œuvre de ce mécanisme alternatif de découverte du LIS mais je n'ai pas de liste sous la main.


Téléchargez le RFC 7216


L'article seul

RFC 7215: LISP Network Element Deployment Considerations

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : L. Jakab (Cisco Systems), A. Cabellos-Aparicio, F. Coras, J. Domingo-Pascual (Technical University of Catalonia), D. Lewis (Cisco Systems)
Expérimental
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 23 avril 2014


Le protocole réseau LISP a été normalisé il y a plus d'un an et plusieurs déploiements de taille significative ont déjà eu lieu. La norme LISP n'impose pas un modèle unique de déploiement et laisse bien des choix à la discrétion de l'administrateur réseaux sur le terrain, notamment pour le placement des différents éléments qui composent un réseau LISP. Ce nouveau RFC fait le point sur les différents modèles de déploiement possibles. Il est donc orienté vers les opérationnels, ceux (et celles) qui vont déployer LISP en production.

Petit rappel, LISP vise à résoudre le problème de la croissance de la table de routage globale de l'Internet (problème décrit dans le RFC 4984), par le moyen d'une séparation entre identificateurs, les EID (Endpoint IDentifiers) et les localisateurs, les RLOC (Routing LOCators). LISP est normalisé dans le RFC 6830. À l'heure actuelle, les RFC sur LISP ont le statut « expérimental » (y compris ce RFC 7215), reflétant le caractère assez disruptif de ce protocole. Il n'y a notamment aucune solution aux différents problèmes de sécurité étudiés dans la section 15 du RFC 6830.

Un principe essentiel de LISP est la distinction faite entre les réseaux de bordure, qui ne travaillent qu'avec des EID, et le cœur de l'Internet qui ne travaille qu'avec des RLOC. Mais où placer la frontière, frontière d'autant plus importante que c'est là où vont devoir se situer les routeurs LISP (les routeurs de bordure et du cœur sont, eux, des routeurs IP non modifiés) ? L'idée initiale était que la frontière était aux limites des AS « feuille », ceux qui n'ont pas de trafic de transit. Mais, en fait, LISP permet plusieurs choix. Un « site LISP » peut être un AS feuille mais peut aussi être un simple réseau local.

LISP tunnelise les paquets d'un site LISP à l'autre, à travers le cœur. Le routeur LISP, connecté à la fois à la bordure et au cœur se nomme un ITR (Ingress Tunnel Router) à l'entrée (encapsulation des paquets) et un ETR (Egress Tunnel Router) à la sortie (décapsulation des paquets). Quand on veut parler des deux types en même temps, on dit juste « un xTR ».

Passons maintenant aux scénarios, section 2.1. Premier scénario possible de déploiement, le « Customer Edge ». Le routeur LISP est dans les locaux du client, contrôlé par lui, et sur la frontière entre réseau du client et réseau de l'opérateur. Ce sera a priori le cas le plus fréquent chez les LISPiens et c'est la solution recommandée par notre RFC. A priori, si on déploie LISP, c'est qu'on a un réseau de grande taille, multi-homé, et qu'on souhaite faire de la gestion de trafic (faire entrer le trafic Internet préferentiellement par un des opérateurs, par exemple). Dans le scénario Customer Edge, le client a le complet contrôle des xTR et peut déployer les politiques qu'il veut sans rien demander à personne. L'information de joignabilité des ETR, si importante en LISP, peut être maintenue correctement, tous les routeurs LISP étant sous le contrôle de la même organisation. Les Locator Status Bits mis par l'ITR sont également toujours conformes à la réalité.

Autre avantage, le réseau interne, son plan d'adressage, son protocole de routage et ses régles de filtrage ne changent pas.

Comme toutes les techniques utilisant des tunnels, LISP est très sensible aux problèmes de MTU (RFC 4459), le tunnel consommant quelques octets qui vont diminuer la MTU du lien. Si la connexion entre le client et son opérateur a une MTU supérieure aux traditionnels 1 500 octets d'Ethernet, il n'y a pas de problème. Sinon, ce scénario peut entraîner des problèmes de MTU.

Second scénario possible, le « Provider Edge ». Cette fois, on met les xTR chez l'opérateur, sous son contrôle. Le client n'a pas à mettre à jour ses routeurs, ou à les configurer. Et, avec un seul xTR, l'opérateur peut servir plusieurs clients LISP.

Par contre, cela fait perdre à LISP une de ses principales qualités, la possibilité de contrôler la répartition du trafic entrant (ingress traffic engineering). En effet, les xTR ne sont plus sous le contrôle du client. Et si le client est multi-homé, c'est encore pire, les xTR étant chez des opérateurs concurrents.

Les xTR qui servent un site LISP n'étant plus coordonnés, ils ne vont pas forcément avoir de l'information correcte et à jour sur la joignabilité, et ne pourront donc pas servir cette information.

Par contre, ce scénario peut limiter les risques d'un problème de MTU, les xTR étant directement dans le réseau de l'opérateur, où la MTU disponible est souvent plus grande.

Mais on peut commettre des perversions bien pires avec LISP. Par exemple, on peut mettre les xTR derrière des routeurs NAT, par exemple si on n'a pas assez d'adresses IPv4. Dans ce troisième scénario, l'ITR encapsule les paquets qui sont ensuite NATés. Attention, les paquets LISP Map Requests n'auront alors pas le même en-tête IP que les Map Reply correspondants, qui seront alors jetés par le routeur NAT. Il faudra une configuration explicite (par exemple diriger tous les paquets UDP de port source 4342 vers l'ITR) pour éviter cela.

Ce RFC ne s'arrête pas à ces trois scénarios possibles. Il décrit aussi comment les fonctions LISP peuvent être réparties dans divers équipements. Par exemple, les fonctions d'ITR et d'ETR ne sont pas forcément présentes dans le même boîtier. On a le droit de les placer dans deux routeurs différents, par exemple pour mettre les ITR très près des machines terminales, afin d'encapsuler le plus tôt possible.

Comme toutes les solutions de séparation de l'identificateur et du localisateur, LISP dépend énormément des mécanismes de correspondance (RFC 9301), permettant de trouver un localisateur (RLOC) lorsqu'on connait l'identificateur (EID). Pour résoudre le problème de bootstrap, les serveurs de correspondance doivent être désignés par des RLOC uniquement. Le système de correspondance a deux composants, les Map Servers et les Map Resolvers. Voyons d'abord les premiers (section 3.1).

Les Map Servers apprennent la correspondance EID->RLOC de leurs ETR (message Map Register) et publient ensuite cette information, par exemple via le protocole ALT (RFC 6836) ou via le protocole DDT (RFC 8111). ALT s'inspire plutôt de BGP, DDT plutôt du DNS. Les gérants des Map Servers se nomment les MSP (Mapping Service Provider). Ils peuvent être opérateurs réseaux ou bien des organisations spécialisées dans le service de correspondance, se faisant payer pour publier un préfixe EID (section 5.2). A priori, les bonnes pratiques existantes pour la gestion de BGP s'appliquent à ALT, et celles pour le DNS à DDT. Mais notre RFC ne va pas plus loin : il est encore trop tôt pour graver dans le marbre de strictes politiques pour les gérants de Map Servers.

DDT (RFC 8111) est arborescent et repose donc sur une racine. Cette racine est actuellement gérée par plusieurs organisations volontaires. Comme pour la racine du DNS, elle est servie par plusieurs serveurs, chacun géré par une organisation différente, et désignés par une lettre de l'alphabet grec. Au moins un de ces serveurs est anycasté. La racine doit normalement vérifier que les organisations qui enregistrent un EID sont autorisés à le faire, via un RIR qui leur a attribué le préfixe en question.

Et les Map Resolvers (section 3.2) ? Leur travail (RFC 9301) est de recevoir des requêtes Map Request, typiquement envoyées par un ITR, de trouver une correspondance EID->RLOC dans la base de données distribuée, et de la renvoyer au demandeur. (Les habitués du DNS peuvent se dire qu'un Map Server est un « serveur faisant autorité » et un Map Resolver un « résolveur » ou « serveur récursif ».) Vu leurs « clients », les Map Resolvers ont tout intérêt à être situés près des ITR qu'ils servent.

Les ITR vont devoir être configurés avec les adresses de leurs Map Resolvers. Un préfixe anycast (RFC 4786) commun faciliterait cette tâche, l'ITR trouvant ainsi automatiquement le résolveur le plus proche et donc en général le plus rapide.

Comme toute technologie nouvelle sur le réseau, LISP doit faire face au problème de la coexistence avec les anciens systèmes. Aujourd'hui, il y a peu de sites LISP. Ceux-ci doivent donc se poser la question de la coexistence avec les sites non-LISP. Plusieurs techniques sont envisagées pour cela, comme les P-ITR, Proxy ITR du RFC 6832. Un site LISP qui veut envoyer des paquets à un site non-LISP peut le faire simplement en n'utilisant pas l'encapsulation LISP. Par contre, pour en recevoir, il doit déployer une technique comme le P-ITR.

Et puisqu'on parle de coexistence avec les sites non-LISP, il faut aussi envisager le processus de migration provisoire depuis l'état actuel vers LISP (section 5 et annexe A). Le RFC est ambitieux, partant de l'état initial (peu de sites LISP) en allant vers un état intermédiaire où il y aurait une majorité de sites LISP, pour terminer par un Internet complètement LISPisé.

Au début, un site LISP n'a pas le choix. Sauf à ne communiquer qu'avec les autres sites LISP, il a intérêt à annoncer ses préfixes dans le Map system LISP mais aussi en BGP, pour que les sites non-LISP sachent où le trouver. On notera donc que, dans cette situation, LISP ne contribue guère à la réduction de la table de routage globale, puisque tous les réseaux doivent toujours être publiés dans BGP. Heureusement, au fur et à mesure que le nombre de sites LISP augmente, il y aura de moins en moins besoin d'utiliser les techniques de traffic engineering pour contrôler les flux de données. Comme ces techniques (par exemple la désagrégation des préfixes) sont largement responsables de la croissance de la table de routage globale, LISP aura donc déjà un intérêt concret à ce stade (encore lointain).

On l'a vu, l'inconvénient de cette méthode (annoncer les préfixes en BGP) est qu'on ne diminue pas la taille de la DFZ. Pire, si on est un nouveau réseau sans infrastructure BGP existante, on augmente cette taille. Pour ces réseaux neufs, notre RFC recommande donc plutôt de ne pas déployer BGP du tout et d'utiliser les P-ITR. C'est alors le titulaire d'un préfixe englobant qui annonce le préfixe et le route vers les ETR du client. Ainsi, il n'y a pas de désagrégation des préfixes. Par contre, l'opérateur qui fournit ce service doit router tout le trafic non-LISP du client, ce qui n'est pas forcément raisonnable si c'est un gros client (comparez cela aux tunnels IPv6 que fournissent gratuitement des opérateurs comme Hurricane Electric : cela n'est réaliste que si le trafic est faible). Le problème disparaitra petit à petit si LISP se développe, lorsqu'il n'y aura plus que des reliquats non-LISP (on en est très loin).

L'annexe A du RFC décrit un plan de migration concret pour les responsables opérationnels, sous forme d'une liste d'étapes, avec des points à vérifier à chaque étape :

  • Faire un état des lieux quantitatif du réseau, pour avoir combien de paquets par seconde et de bits par seconde il faudra acheminer.
  • Vérifier les capacités LISP des routeurs existants : peuvent-ils être utilisés ou bien va t-il falloir en acheter d'autres ?
  • Faire bien attention aux questions de MTU, LISP utilisant des tunnels. Si tous les liens externes peuvent accepter une MTU de 1 556 octets, parfait. Dans tous les cas, testez que cela passe et qu'il n'y a pas un pare-feu trop zélé qui bloque les messages ICMP indispensables à la découverte de la MTU du chemin.
  • Vérifiez que vos préfixes IP sont utilisables pour LISP. Si c'est du PI, pas de problème.
  • Configurez les routeurs LISP.
  • Testez la joignabilité des ETR (par exemple avec ping) et l'enregistrement des préfixes avec lig (RFC 6835).
  • etc (la liste est longue...)

Téléchargez le RFC 7215


L'article seul

RFC 7211: Operations Model for Router Keying

Date de publication du RFC : Juin 2014
Auteur(s) du RFC : S. Hartman (Painless Security), D. Zhang (Huawei)
Pour information
Réalisé dans le cadre du groupe de travail IETF karp
Première rédaction de cet article le 19 juin 2014


Il y a un gros travail en cours à l'IETF pour améliorer la sécurité du routage sur l'Internet. L'un des aspects de ce travail concerne la gestion des clés par les routeurs. Bien des solutions de sécurité nécessitent que les routeurs disposent de clés secrètes. Le groupe de travail KARP travaille sur les problèmes de gestion de ces clés (cf. RFC 6518). Ce nouveau RFC du groupe décrit les problèmes opérationnels et les pratiques actuelles de gestion des clés dans les routeurs.

KARP a déjà produit plusieurs RFC. Celui-ci se veut particulièrement terre-à-terre. Il existe des tas de techniques pour sécuriser la communication entre routeurs. Mais comment sont-elles effectivement déployées ? Pour le savoir, il faut disposer d'un modèle décrivant les opérations de gestion de clés. C'est d'autant plus crucial que la sécurisation du routage présente quelques défis spécifiques. Par exemple, comme il faut que le routage fonctionne pour pouvoir contacter d'autres machines du réseau, les solutions fondées sur un serveur d'authentification central ne conviennent pas.

D'abord, le modèle de configuration d'un routeur, en section 3. La configuration consiste à indiquer au routeur les clés qu'il utilisera pour s'authentifier, ainsi que divers paramètres. Cela peut se faire manuellement ou automatiquement. La configuration automatique étant encore un sujet d'étude, notre RFC se concentre sur la configuration manuelle, via une structure abstraite, la table des clés. Ce n'est déjà pas évident car certains protocoles nécessitent une clé commune à tous les routeurs, et d'autres pas. Il faut donc pouvoir configurer les clés par interface réseau et par pair. Prenons l'exemple d'OSPF (RFC 2328) : sur tout lien réseau, tous les routeurs doivent utiliser la même clé. En revanche, d'un lien à l'autre, un même routeur peut se trouver à utiliser plusieurs clés différentes. Mais ce n'est pas obligatoire et, dans certaines organisations, on aura peut-être une clé pour chaque zone (area) OSPF, avec seuls les ABR (Area Border Router) utilisant plusieurs clés. Bien sûr, avec une table de clés OSPF où les clés sont rangées par lien, on peut réaliser la politique « une clé par zone » en mettant la même clé pour tous les liens de la zone. Mais, si ce n'est pas vérifié par le système de gestion de la table de clés, il y a un risque de désynchronisation, par exemple parce qu'on change la clé d'un lien en oubliant les autres liens de la zone. Il serait donc souhaitable d'avoir un mécanisme d'héritage (« la clé du lien dépend de la zone ») permettant d'éviter cette désynchronisation accidentelle.

L'intégrité de la table des clés par rapport aux règles techniques des protocoles de routage est évidemment essentielle. Le routeur doit donc s'assurer que les algorithmes de cryptographie indiqués sont compatibles avec le protocole de routage, que la fonction de dérivation l'est également, etc. La table peut être modifiée via une quantité de méthodes (système de gestion de configuration, interface Web, CLI, etc) du moment que son intégrité est vérifiée.

Afin d'éviter les « clés éternelles », jamais changées (même lorsqu'un employé qui les connait quitte l'organisation), il faut aussi que le table prévoit un système d'expiration, pour pouvoir indiquer « cette clé est valable jusqu'au 15 avril 2014 » et qu'elle soit automatiquement marquée comme expirée après cette date.

Il existe des tas de façons d'utiliser des clés en cryptographie. La plus simple (et sans doute la plus courante aujourd'hui) est que les clés configurées dans le routeur soient partagées, et utilisées telles quelles dans le protocole de routage. Mais on peut aussi passer par une fonction de dérivation, qui va combiner la clé partagée avec des paramètres d'une session particulière, rendant ainsi la tâche plus difficile pour l'attaquant (même s'il a la clé, il ne pourra pas forcément s'insérer dans une session en cours). C'est par exemple ce que fait le protocole AO du RFC 5925 (dans sa section 5.2). Ou bien on peut se servir des clés préconfigurées pour s'authentifier le temps de générer des clés de session, par exemple avec Diffie-Hellman. Les clés sont parfois identifiées par un nombre court, parfois pas identifiées du tout et un routeur peut avoir à en essayer plusieurs avant de tomber sur la bonne.

Enfin, il y a le cas où les routeurs utilisent de la cryptographie asymétrique. La clé privée de chaque routeur ne quittera alors jamais le routeur, ce qui augmente la sécurité. (Ceci dit, cela empêchera de remplacer rapidement un routeur, ce qui est une opération souhaitable, et qui justifie donc une gestion centrale des clés.) L'authentification des autres routeurs pourra se faire via une PKI (ce qui peut être compliqué à mettre en place), ou bien en ajoutant la clé publique de chaque routeur à tous ses pairs (ce qui n'est pas pratique si on ajoute souvent de nouveaux routeurs). Pour identifier les clés, notre RFC recommande de se servir du RFC 4572 (section 5). Ensuite, les autorisations de tel ou tel routeur pair peuvent se faire en indiquant les clés (ce qui a l'inconvénient qu'il faut les refaire si un routeur change de clé) ou en indiquant une identité du routeur (ce qui nécessite, pour cette indirection supplémentaire, un moyen sécurisé de passer de l'identité du routeur à sa ou ses clés). Avec une PKI, le problème ne se posera évidemment pas.

On l'a vu, un problème spécifique à la sécurisation du routage est qu'il faut que le mécanisme marche sans dépendre du réseau puisque, avant que les routeurs soient authentifiés et échangent les routes, on n'aura peut-être pas de réseau. Cela limite sérieusement le rôle que peuvent jouer des serveurs centraux, genre RADIUS (RFC 2865). Pas question par exemple que le seul moyen d'obtenir les clés des pairs soit de demander à un serveur central. Cela ne veut pas dire que ces serveurs centraux soient inutiles. Ils peuvent aider à des opérations comme la diffusion de nouvelles clés en cas de préparation à un remplacement de clés ou comme la distribution de la clé d'un nouveau pair. Simplement, le réseau doit pouvoir démarrer et fonctionner sans eux.

La section 6 de notre RFC est consacrée au rôle de l'administrateur humain dans la gestion des clés. Deux exemples typiques où il est indispensable, l'arrivée d'un nouveau pair (il faut décider si on le laisse entrer ou pas) et la réparation en cas de problème. Si le réseau fonctionne déjà, l'arrivée d'un nouveau pair peut être simplifiée car il peut suffire d'inscrire ce routeur dans une base de données et toutes les informations nécessaires peuvent être propagées aux autres routeurs en utilisant le réseau. Le cas d'un réseau tout nouveau démarrant à froid est évidemment plus compliqué.

Naturellement, le nouveau routeur doit être proprement configuré sur le plan de la sécurité ; il ne servirait à rien de protéger les clés utilisées par les protocoles de routage si on pouvait se connecter en SSH sur le routeur avec login: admin password: admin !

Et les pannes ? C'est que la sécurité apporte ses propres causes de panne. Vouloir sécuriser un réseau peut l'empêcher de fonctionner. Ainsi, l'expiration d'un certificat entraîne son refus par les autres routeurs et le retrait du routeur au certificat trop vieux... Même si le RFC n'en parle pas, une des raisons du faible déploiement des solutions de sécurisation du routage est la crainte d'avoir davantage de pannes. Le déploiement de toute solution de sécurité nécessitera des pratiques plus rigoureuses, par exemple une supervision des dates d'expiration des certificats.

Et une fois qu'on a décidé de déployer une jolie sécurité toute neuve avec une meilleure gestion des lettres de créance des routeurs, comment on fait ? La section 7 fait remarquer que le passage du système actuel au nouveau ne va pas forcément être sans douleur. Si on conçoit un réseau tout neuf, on peut le faire proprement dès le début. Mais si on a un réseau existant et qu'on veut y introduire de nouvelles pratiques ? Et sans tout casser ? Aujourd'hui, si des clés comme celles d'OSPF ou bien celles utilisées entre routeurs BGP sont très rarement changées, c'est souvent par peur que ce changement coupe le routage. Pour deux routeurs BGP appartenant à des organisations différentes, le changement du mot de passe MD5 (RFC 2385) doit être soigneusement coordonné et il faut que le pair respecte rigoureusement la procédure qui a été définie, notamment le moment du changement. Comme on s'en doute, c'est rarement fait.

Prenons l'exemple du nouveau mécanisme AO (RFC 5925) qui remplace l'authentification MD5. Il n'existe pas de mécanisme automatique pour savoir si le pair BGP utilise MD5 ou AO. Il faut donc un changement coordonné (« le 11 mars à 13h37 UTC, on passe à AO »). Si le logiciel utilisé permet de grouper les configurations en traitant tout un ensemble de pairs de la même façon, il faut en prime faire cela pour tous les pairs à la fois. Vu cette difficulté, il n'est pas étonnant que peu de sessions BGP soient aujourd'hui protégées par AO.

Enfin, le rappelle la section 8, beaucoup de mécanismes de sécurité dépendent d'une horloge à l'heure. Il est donc crucial de s'assurer que l'heure sur les routeurs est correctement synchronisée.


Téléchargez le RFC 7211


L'article seul

RFC 7208: Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : S. Kitterman (Kitterman Technical Services)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF spfbis
Première rédaction de cet article le 27 avril 2014


On le sait, le courrier électronique, tel qu'il est spécifié dans les RFC 5321 et RFC 5322, ne fournit aucune authentification, même faible, de l'émetteur. Un expéditeur de courrier peut toujours prétendre être François Hollande <president@elysee.fr> et il n'y a aucun moyen de l'en empêcher. C'est parfois pratique mais c'est aussi un gros obstacle lorsqu'on tente de gérer le problème des courriers non désirés comme le spam. SPF vise à diminuer cette facilité de frauder en permettant à un titulaire de nom de domaine de déclarer quelle(s) adresse(s) IP sont autorisées à envoyer du courrier pour ce domaine. Ce nouveau RFC représente la première norme SPF (le premier RFC, le RFC 4408, était officiellement une expérimentation, sans le statut de norme.)

SPF dépend donc du DNS. Le principe de base est d'ajouter à sa zone DNS, par exemple bortzmeyer.org, un enregistrement de type TXT. Cet enregistrement déclare, dans un langage ad hoc, quelle(s) adresse(s) IP peuvent envoyer du courrier pour ce domaine. Par exemple, bortzmeyer.fr a "v=spf1 mx -all", ce qui veut dire en français que seuls les MX (les serveurs qui reçoivent le courrier) de ce domaine peuvent en émettre, le reste de l'Internet (all) est exclu.

Pour voir ces enregistrements SPF, on peut par exemple utiliser dig :

% dig +short TXT bortzmeyer.org
"v=spf1 mx ?all"

% dig +short TXT freebsd.org 
"v=spf1 ip4:8.8.178.116 ip6:2001:1900:2254:206a::19:2 ~all"
 
dig +short TXT archlinux.org
"v=spf1 ip4:66.211.214.128/28 ip4:78.46.78.247 ip6:2a01:4f8:120:34c2::2 a:aur.archlinux.org ~all"

Le langage en question, très simple dans la plupart des cas (comme ci-dessus) mais permettant des choses très (trop ?) compliquées, est décrit dans la section 5 du RFC. Le premier enregistrement SPF contient mx indiquant que les machines dans l'enregistrement MX du domaine sont autorisées. Les deux autres enregistrements d'exemple listent explicitement les adresses IP. Notez qu'il existe plein d'exemples en annexe A de ce RFC.

Le langage de SPF, on l'a vu, est riche et complexe. D'où l'avertissement en section 11.1 de ce RFC : attention en l'évaluant. Il est prudent de prévoir des limites, par exemple de temps écoulé, du nombre d'inclusions emboîtées, ou de requêtes DNS envoyées, afin de ne pas être victime d'un déni de service (ou de contribuer à en faire un).

Et si on veut annoncer clairement qu'on n'envoie jamais de courrier ? Par exemple, un organisme de paiement a acheté des tas de noms de domaines dans plusieurs TLD mais il envoie toujours du courrier depuis example.com et l'usage de tout autre nom ne peut être qu'une erreur ou une tentative de fraude. On met alors un enregistrement v=spf1 -all. (Notez qu'il n'existait aucun mécanisme avant SPF pour annoncer qu'on n'envoyait pas de courrier. On voit parfois des MX bidons pour cela, par exemple pointant vers 0.0.0.0 mais cela n'est pas standard.)

On note que SPF, comme la plupart de ses concurrents, n'authentifie que le domaine, pas la personne émettrice (ce point, et plusieurs autres, est discuté en détail dans la section 11, « Sécurité », de notre RFC).

Le récepteur du courrier, s'il utilise SPF, va comparer l'adresse IP du client SMTP aux adresses autorisées par l'enregistrement SPF et le résultat pourra être (section 2.6) none (sans opinion, typiquement parce qu'il n'y avait pas d'enregistrement SPF publié), neutral (il y avait bien un enregistrement SPF mais il se terminait par un avis neutre, typiquement avec le qualificateur « ? », pass (cette adresse IP est autorisée pour ce domaine) ou fail (cette adresse IP n'est pas autorisée pour ce domaine). Il y a aussi deux cas d'erreurs, temperror et pererror.

Une fois que le domaine est authentifié, on en fait quoi ? En soi, être authentifié n'est évidemment pas une garantie de bon comportement (c'est toute la différence entre authentification et autorisation). C'est simplement une première étape du processus de sécurité : une fois une identité solidement établie, on peut utiliser les mécanismes de réputation existants (en prime, un nom de domaine est plus stable qu'une adresse IP).

La décision finale est une décision locale. Les gens à qui on explique SPF pour la première fois disent souvent « et que fait le serveur SMTP si l'authentification SPF échoue ? » et la réponse est toujours « ça dépend », car, en effet, cela dépend de la politique de ce serveur SMTP. Certains seront violents, rejettant complètement le message, d'autres se contenteront de noter (peut-être en transmettant l'information avec le RFC 6652), d'autres enfin tiendront compte du résultat de SPF mais comme une indication parmi d'autres. Une fois la décision prise, le message peut être rejeté dès la session SMTP ou bien peut être accepté mais marqué d'une manière ou d'une autre (ce qui pourra lui « enlever des points » pour une évaluation ultérieure). Il existe deux façons de marquer un message, avec l'en-tête Received-SPF: (défini dans ce RFC, section 9.1) ou bien avec un en-tête non spécifique à SPF, Authentication-Results: (RFC 5451). Autre différence entre les deux en-têtes, Received-SPF: donne des informations détaillées, utiles pour le débogage, alors que Authentication-Results: vise surtout à donner un résultat simple sur la base duquel des logiciels ultérieurs (comme le MUA) pourront agir. Voici deux exemples, tirés du RFC :

Authentication-Results: myhost.example.org; spf=pass
     smtp.mailfrom=example.net

Received-SPF: pass (myhost.example.org: domain of
    myname@example.com designates 192.0.2.1 as permitted sender)
       receiver=mybox.example.org; client-ip=192.0.2.1;
       envelope-from="myname@example.com"; helo=foo.example.com;

Il y avait eu des discussions à l'IETF autour de la suppression d'un des deux en-têtes mais cela n'a finalement pas été fait.

Authentifier le courrier électronique est plus compliqué qu'il ne semble au premier abord, en partie parce qu'il existe plusieurs identités possibles :

  • L'expéditeur de l'enveloppe (MAIL FROM de la session SMTP),
  • L'expéditeur indiqué dans les en-têtes, qui lui-même dépend de l'en-tête qu'on choisit (From: ? Sender: ?).

Les partisans de la première approche (celle de SPF) lisent le RFC 5321 et s'appuient sur l'identité MAIL FROM (dite aussi RFC5321.MailFrom, cf. section 1.1.3). Chacune a ses avantages et ses inconvénients. (Notez que SPF utilise également le nom annoncé par la commande HELO de SMTP, cf. section 2.3.)

Attention, un vérificateur SPF doit bien prendre soin de n'utiliser que cette identité, autrement, les résultats peuvent être faux (par exemple, un MLM va changer le MAIL FROM mais pas l'en-tête From:).

Les changements depuis l'ancien RFC 4408 figurent dans l'annexe B. Le principal est le changement de statut : RFC 4408 était expérimental, notre nouveau RFC est sur le chemin des normes. Autrement, des détails, rien de vital, le principal changement technique étant l'abandon du type d'enregistrement DNS SPF pour les raisons expliquées dans l'annexe A du RFC 6686. Parmi les sujets polémiques qu'a rencontré le groupe de travail, et qui ont engendré l'essentiel du trafic sur la liste de diffusion :

  • La décision douloureuse d'abandonner le type d'enregistrement DNS SPF.
  • La revendication récurrente, par certaines personnes, que le RFC impose un traitement particulier (rejeter le message) en cas d'échec SPF. Comme cela n'affecte pas l'interopérabilité, le groupe a logiquement décidé que c'était une décision de politique locale.
  • Il y a régulièrement une discussion dans le milieu SPF pour savoir ce que doit faire un serveur de messagerie lorsqu'il n'y a pas d'enregistrement SPF pour le serveur qu'il veut authentifier. Certains prônent un « enregistrement SPF par défaut » par exemple v=spf1 ~all ou encore v=spf1 mx/24/48 a/24/48 ~all. Une telle valeur est complètement arbitraire et n'a jamais été normalisée.
  • Les discussions sur le forwarding de courrier et sur les listes de diffusion sont également des traditions du monde SPF.
  • Pour des raisons de sécurité (nombreux traitements, et nombreuses requêtes DNS), certains avaient proposé d'abandonner la compatibilité avec les premières versions de SPF et de supprimer du langage quelques mécanismes très gourmands. Ce projet n'a pas été retenu.

SPF est aujourd'hui très répandu, de nombreux domaines l'annoncent et bien des logiciels de courrier peuvent traiter du SPF.


Téléchargez le RFC 7208


L'article seul

RFC 7207: A Uniform Resource Name (URN) Namespace for Eurosystem Messaging

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : M. Ortseifen (Deutsche Bundesbank), G. Dickfeld (Deutsche Bundesbank)
Pour information
Première rédaction de cet article le 18 avril 2014


Une famille d'URN de plus, pour les messages d'Eurosystem, famille gérée par la Bundesbank pour le compte de l'ESCB. Vous ne connaissez pas le secteur bancaire ? L'ESCB est un regroupement de banques centrales européennes (mais n'ayant pas forcément adopté l'euro) comme la Bundesbank. L'Eurosystem, comme son nom l'indique, est commun aux membres de l'ESCB qui ont adopté l'euro (voir la présentation par l'ESCB).

Et pourquoi ont-ils besoin d'URN ? Parce qu'ils échangent des messages par le système TARGET2 (un système à la norme ISO 20022) et qu'un certain nombre d'éléments dans ces messages ont besoin d'être identifiés de manière unique et stable dans le temps (les messages ont toujours besoin d'être lus et compris des années après). Les identifiants doivent être indépendants du protocole d'accès, ce qu'offrent les URN, normalisés dans le RFC 8141. Il est important que l'Eurosystem puisse être un registre d'identificateurs, avec son propre NID, son propre espace de noms pour ses URN (RFC 8141). Cet espace se nomme eurosystem et est enregistré à l'IANA.

Il n'y a pas de structure à l'intérieur de ces URN (donc, après le urn:eurosystem:), juste une suite de caractères. L'exemple donné par le RFC est urn:eurosystem:xsd:reda.012.001.02.


Téléchargez le RFC 7207


L'article seul

RFC 7203: IODEF-extension for structured cybersecurity information

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : T. Takahashi (NICT), K. Landfield (McAfee), T. Millar (USCERT), Y. Kadobayashi (NAIST)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF mile
Première rédaction de cet article le 22 avril 2014


Le format IODEF permet l'échange de données structurées (et donc analysables par un programme) sur des incidents de sécurité. Ce nouvel RFC étend le format IODEF avec des informations utiles pour le monde de la « cybersécurité ».

Le RFC commence par prétendre que le nombre d'incidents de cybersécurité augmente tous les jours (alors qu'on n'en sait rien). Ce qui est sûr, c'est que la quantité d'informations échangées sur ces incidents augmente et qu'il existe une quantité impressionnante de formats structurés et de référentiels (quelques exemples au hasard, pris dans ceux cités par le RFC : CVSS, OVAL, SCAP, XCCDF...). Notre RFC en ajoute donc un, sous forme, non pas d'un format nouveau mais d'une extension de IODEF, un format fondé sur XML et qui avait été normalisé dans le RFC 5070 (remplacé depuis par le RFC 7970). Signe des temps : un des auteurs du RFC travaille au ministère de l'intérieur états-unien...

La section 3 du RFC rappelle ses buts, et l'importance de ne pas repartir de zéro, d'agréger les formats cités plus haut au lieu d'essayer de les remplacer. Les extensions IODEF elles-mêmes figurent en section 4. En gros, il s'agit de permettre d'incorporer dans IODEF des descriptions issues de normes extérieures déjà existantes. Un nouveau registre IANA stocke les spécifications ainsi incorporées. Pour l'instant, le registre n'en compte qu'une seule, urn:ietf:params:xml:ns:mile:mmdef:1.2 qui est fondée sur la norme IEEE MMDEF, qui permet de décrire des logiciels malveillants.

Chacune de ces entrées dans le nouveau registre dérivera d'une classe (notre RFC utilise le vocabulaire de la programmation objet, et le langage UML pour la modélisation) parmi les huit : AttackPattern, Platform, Vulnerability, Scoring, Weakness, EventReport, Verification et Remediation. Ainsi, MMDEF, la première entrée, hérite de AttackPattern. Chacune de ces classes est décrite en détail en section 4.5

Et voici, tiré du RFC, un exemple de rapport IODEF incorporant des éléments MMDEF, décrivant un malware de nom eicar_com.zip (un fichier de test connu) :


<?xml version="1.0" encoding="UTF-8"?>
<IODEF-Document version="1.00" lang="en"
 xmlns="urn:ietf:params:xml:ns:iodef-1.0"
 xmlns:iodef="urn:ietf:params:xml:ns:iodef-1.0"
 xmlns:iodef-sci="urn:ietf:params:xml:ns:iodef-sci-1.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Incident purpose="reporting">
    <IncidentID name="iodef-sci.example.com">189493</IncidentID>
    <ReportTime>2013-06-18T23:19:24+00:00</ReportTime>
    <Description>a candidate security incident</Description>
    <Assessment>
      <Impact completion="failed" type="admin" />
    </Assessment>
    <Method>
      <Description>A candidate attack event</Description>
      <AdditionalData dtype="xml">
        <iodef-sci:AttackPattern
         SpecID="http://xml/metadataSharing.xsd">
          <iodef-sci:RawData dtype="xml">
            <malwareMetaData xmlns="http://xml/metadataSharing.xsd"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xml/metadataSharing.xsd
             file:metadataSharing.xsd" version="1.200000" id="10000">
              <company>N/A</company>
              <author>MMDEF Generation Script</author>
              <comment>Test MMDEF v1.2 file generated using genMMDEF
              </comment>
              <timestamp>2013-03-23T15:12:50.726000</timestamp>
              <objects>
                <file id="6ce6f415d8475545be5ba114f208b0ff">
                  <md5>6ce6f415d8475545be5ba114f208b0ff</md5>
                  <sha1>da39a3ee5e6b4b0d3255bfef95601890afd80709</sha1>
                  <sha256>e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca4
                          95991b7852b855</sha256>
                  <sha512>cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83
                          f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b9
                          31bd47417a81a538327af927da3e</sha512>
                  <size>184</size>
                  <filename>eicar_com.zip</filename>
                  <MIMEType>application/zip</MIMEType>
                </file>
                <file id="44d88612fea8a8f36de82e1278abb02f">
                  <md5>44d88612fea8a8f36de82e1278abb02f</md5>
                  <sha1>3395856ce81f2b7382dee72602f798b642f14140</sha1>
                  <sha256>275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4
                          538aabf651fd0f</sha256>
                  <sha512>cc805d5fab1fd71a4ab352a9c533e65fb2d5b885518f4e565e
                          68847223b8e6b85cb48f3afad842726d99239c9e36505c64b0
                          dc9a061d9e507d833277ada336ab</sha512>
                  <size>68</size>
                  <crc32>1750191932</crc32>
                  <filename>eicar.com</filename>
                  <filenameWithinInstaller>eicar.com
                  </filenameWithinInstaller>
                </file>
              </objects>
            <relationships>
              <relationship type="createdBy" id="1">
                <source>
                  <ref>file[@id="6ce6f415d8475545be5ba114f208b0ff"]</ref>
                </source>
                <target>
                  <ref>file[@id="44d88612fea8a8f36de82e1278abb02f"]</ref>
                </target>
                <timestamp>2013-03-23T15:12:50.744000</timestamp>
                </relationship>
              </relationships>
            </malwareMetaData>
          </iodef-sci:RawData>
        </iodef-sci:AttackPattern>
      </AdditionalData>
    </Method>
    <Contact role="creator" type="organization">
      <ContactName>iodef-sci.example.com</ContactName>
      <RegistryHandle registry="arin">iodef-sci.example-com
      </RegistryHandle>
      <Email>contact@csirt.example.com</Email>
    </Contact>
    <EventData>
      <Flow>
        <System category="source">
          <Node>
            <Address category="ipv4-addr">192.0.2.200</Address>
            <Counter type="event">57</Counter>
          </Node>
        </System>
        <System category="target">
          <Node>
            <Address category="ipv4-net">192.0.2.16/28</Address>
          </Node>
          <Service ip_protocol="4">
            <Port>80</Port>
          </Service>
        </System>
      </Flow>
      <Expectation action="block-host" />
      <Expectation action="other" />
    </EventData>
  </Incident>
</IODEF-Document>

On notera que bien des discussions préalables au RFC portaient sur cette plaie de l'appropriation intellectuelle, plusieurs des schémas référencés ayant des noms qui sont des marques déposées.


Téléchargez le RFC 7203


L'article seul

RFC 7196: Making Route Flap Damping Usable

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : C. Pelsser, R. Bush (Internet Initiative Japan), K. Patel (Cisco Systems), P. Mohapatra (Cumulus Systems), O. Maennel (Loughborough University)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 17 mai 2014


L'amortissement des annonces de routes lorsque ces routes sont instables (annoncées et retirées fréquemment) est une vieille technique pour limiter la charge sur les routeurs. Le principe est d'ignorer (pendant un certain temps) une route s'il y a eu trop de changements dans une période récente, de façon à éviter que le routeur BGP ne passe tout son temps à gérer une route qui part et revient en permanence. Le terme officiel est Route Flap Damping (RFD, on dit aussi dampening). L'idée est bonne mais l'expérience a montré que l'amortissement pénalisait excessivement les sites très richement connectés : plus on a de connexions, plus il y a des changements sur ses préfixes et plus on sera amorti. Résultat, ces dernières années, un certain nombre d'opérateurs ont préféré couper l'amortissement. Ce nouveau RFC propose de le rétablir, mais avec des nouveaux paramètres quantitatifs, qui devraient, cette fois, ne pénaliser réellement que les routes qui déconnent et pas les sites qui sont simplement très connectés.

L'amortissement a été formellement décrit dans ripe-178 puis dans le RFC 2439. Le problème des faux positifs a été décrit en 2002, dans « Route Flap Damping Excacerbates Internet Routing Convergence ». Cela a mené à des révisions des politiques des opérateurs, allant dans le sens de déconseiller l'amortissement, comme raconté dans ripe-378, qui dit que le remède (le RFD, l'amortissement) est pire que le mal et conclut « the application of flap damping in ISP networks is NOT recommended ». Des nouvelles études (comme « Route Flap Damping Made Usable », par les auteurs du RFC) ont mené à une approche intermédiaire : garder l'amortissement, mais avec de nouveaux paramètres, comme déjà recommandé dans ripe-580 (document RIPE très proche de ce RFC), qui annule le ripe-378. Il existe aussi un Internet-Draft contenant le résultat d'une étude faite auprès des opérateurs sur leurs pratiques, le document draft-shishio-grow-isp-rfd-implement-survey.

En effet, un tout petit nombre de préfixes d'adresses IP est responsable de la majorité du travail (le churn) des routeurs BGP, comme indiqué dans « BGP Extreme Routing Noise » ou bien dans l'article Route Flap Damping Made Usable cité plus haut. Cet article a testé des annonces BGP réelles pendant une semaine et note que 3 % des préfixes font 36 % des messages BGP. Ce sont ces préfixes qu'il faut pénaliser par l'amortissement, en épargnant les 97 % restants.

Quels sont les paramètres d'amortissement sur lesquels on peut jouer ? La section 3 les rappelle dans un tableau. Certains sont modifiables par l'administrateur du routeur, d'autres pas. Et le tableau, qui liste les valeurs par défaut existant chez Cisco et chez Juniper, montre qu'il n'y a pas de consensus sur ces valeurs par défaut. Attention, en lisant le tableau. Il n'existe malheureusement pas de vocabulaire unique pour ces paramètres (malgré la section 4.2 du RFC 2439) et le nom varie d'un document à l'autre. Ainsi, le RFC 2439 nomme cutoff threshold ce que ripe-580 et notre RFC nomment suppress threshold. C'est dommage, c'est le paramètre le plus important : c'est le nombre de retraits (WITHDRAW BGP) de routes après lequel on supprime la route (multiplié par un facteur, la pénalité). Il vaut 2 000 par défaut sur IOS et 3 000 sur JunOS, ce qui est trop bas.

La section 4 de notre RFC cite en effet l'article Route Flap Damping Made Usable mentionné plus haut, qui estime qu'un seuil remonté à 6 000 permettrait de réduire le rythme de changement BGP de 19 %, contre 51 % avec un seuil de 2 000, mais en impactant dix fois moins de préfixes, donc en faisant beaucoup moins de victimes collatérales. Monter le seuil à 12 000 supprimerait presque complètement l'amortissement, très peu de préfixes étant à ce point instables.

Notre RFC recommande donc :

  • De ne pas changer les valeurs par défaut dans les systèmes d'exploitation de routeurs, même si elles sont mauvaises, car cela changerait la sémantique de certaines configurations actuelles, qui comptent sur ces valeurs par défaut,
  • Remonter le suppress threshold à 6 000 dans les configurations actives,
  • Si possible, ajouter un mode de test (dry run) aux routeurs où les calculs d'amortissement seraient faits mais pas appliqués aux routes. Cela permettrait aux opérateurs de tester les paramètres qu'ils envisagent.

Ces recommandations, notamment la valeur du seuil de déclenchement de l'amortissement (suppress threshold) permettraient d'utiliser l'amortissement sans gros inconvénients.

Ah, un petit mot sur la sécurité (section 7) : un attaquent peut générer des faux retraits pour déclencher l'amortissement et mener à des dégâts supérieurs à ce qu'il aurait pu faire directement. Les paramètres plus conservateurs de ce nouveau RFC devraient limiter ce risque.

Pour configurer l'amortissement sur IOS, voir la documentation officielle, pour Quagga, c'est très semblable, et pour JunOS, voir leur documentation. Sur un routeur IOS, une route supprimée par l'amortissement sera affichée ainsi (voyez notamment la dernière ligne) :

R2# sh ip bgp
BGP table version is 12, local router ID is 192.168.0.1
Status codes: s suppressed, d damped, h history, * valid, > best, i – internal,
r RIB-failure, S Stale
Origin codes: i – IGP, e – EGP, ? – incomplete

Network                Next Hop  Metric  LocPrf  Weight  Path
d 12.12.12.12/32    192.168.0.2       0               0  2 i
*> 13.13.13.13/32   192.168.0.2       0               0  2 i

R2# sh ip bgp 12.12.12.12
BGP routing table entry for 12.12.12.12/32, version 12
Paths: (1 available, no best path)
Flag: 0x820
Not advertised to any peer
2, (suppressed due to dampening) (history entry)
192.168.0.2 from 192.168.0.2 (13.13.13.13)
Origin IGP, metric 0, localpref 100, external
Dampinfo: penalty 3018, flapped 4 times in 00:04:11, reuse in 00:03:20

Téléchargez le RFC 7196


L'article seul

RFC 7194: Default Port for IRC via TLS/SSL

Date de publication du RFC : Août 2014
Auteur(s) du RFC : Richard Hartmann
Pour information
Première rédaction de cet article le 8 août 2014


Le protocole de messagerie instantanée IRC est toujours très utilisé, malgré la concurrence de XMPP. Il n'existait pas de port « officiel » pour les connexions IRC sécurisées par TLS, ce qui est fait avec ce RFC, qui décrit l'usage, déjà très répandu, du port 6697.

IRC est officiellement standardisé dans les RFC 1459, RFC 2810, RFC 2811, RFC 2812 et RFC 2813 mais il ne faut pas s'y fier : la pratique réelle est loin de ces RFC, qu'il faut plutôt utiliser comme point de départ d'une description du protocole que comme une « Bible » définitive. IRC avait depuis longtemps deux ports standards, 194 pour le trafic en clair et 994 pour le trafic chiffré avec TLS. Ces deux ports sont inférieurs à 1 024 et nécessitent donc que le serveur soit lancé par root sur une machine Unix. Comme ce n'est pas toujours possible, ou souhaitable, en pratique, les serveurs IRC écoutent en général sur 6667 en clair et 6697 en chiffré. Le port 6667 a été documenté pour cet usage mais ce n'était pas encore le cas du 6697. Les clients IRC n'avaient donc pas de moyen standard fiable de découvrir si un serveur gérait les connexions IRC sur TLS.

La section 2 du RFC décrit le fonctionnement d'IRC sur TLS : le client se connecte à un serveur IRC. Une fois la connexion établie, la négociation TLS a lieu. Le serveur est censé présenter un certificat d'une autorité reconnue, dont le nom est le nom du serveur. Le client peut s'authentifier, aussi comme décrit dans la documentation d'OFTC . Une fois la négociation terminée avec succès, les identités vérifiées et tout, le trafic passe alors par cette connexion protégée.

Le nouveau numéro est désormais dans le registre IANA :

ircs-u             6697        tcp    Internet Relay Chat via    TLS/SSL               2014-02-11

À noter que ce mécanisme ne protège que la liaison client<->serveur. IRC a aussi des communications serveur<->serveur (coordination non standardisée entre les différentes machines qui mettent en œuvre un service IRC) qui ne sont pas traitées ici, même si le RFC recommande aux opérateurs IRC de systématiquement chiffrer le trafic entre machines d'un même service. À noter aussi qu'IRC ne fait pas de liaison directe en pair à pair. Quand Alice et Bob se parlent en IRC, cela passe toujours par un serveur et, même si TLS sécurise la connexion avec le serveur, cela ne protège pas Alice et Bob d'un espionnage par le serveur (par exemple si celui-ci participe au programme PRISM), comme le rappelle la section 3 du RFC. Le chiffrement qui n'est pas de bout en bout a des pouvoirs de protection limités ! Seul OTR fournirait une protection de bout en bout (mais nécessite un peu plus d'action de la part d'Alice et Bob alors que TLS est largement invisible).

L'annexe A du RFC rappelle qu'en 2010, une étude avait montré que dix des vingt principaux services IRC géraient TLS.

La plupart des grands serveurs IRC aujourd'hui gèrent TLS. Parmi les exceptions, j'ai trouvé ircnet.nerim.fr mais aussi le serveur IRC du W3C qui n'est hélas accessible en TLS que par les membres du W3C. Avec un serveur qui gère TLS, et avec Pidgin comme client, il faut cocher la case Use SSL [sic] mais aussi changer manuellement le port, pour 6697 : pidgin-irc-tls.png

On verra alors des connexions TLS :

(09:00:20) gandalf.geeknode.org: (notice) *** You are connected to gandalf.geeknode.org with TLSv1-AES256-SHA-256bits

À noter que Geeknode est signé par CAcert comme beaucoup de serveurs IRC. Freenode, par contre, est signé par Gandi :

% openssl s_client -connect chat.freenode.net:6697
CONNECTED(00000003)
depth=1 C = FR, O = GANDI SAS, CN = Gandi Standard SSL CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.freenode.net
   i:/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
 1 s:/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
   i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
---
...

Téléchargez le RFC 7194


L'article seul

RFC 7181: The Optimized Link State Routing Protocol version 2

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : T. Clausen (LIX, Ecole Polytechnique), C. Dearlove (BAE Systems ATC), P. Jacquet (Alcatel-Lucent Bell Labs), U. Herberg (Fujitsu Laboratories of America)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF manet
Première rédaction de cet article le 11 avril 2014


Il existe désormais plusieurs protocoles de routage pour le problème difficile des MANETs, ces réseaux ad hoc (c'est-à-dire non organisés et non gérés) de machines diverses connectées de manière intermittente. On est loin des réseaux structurés classiques, avec leurs routeurs bien administrés qui se parlent en OSPF. Dans un MANET, le réseau doit se configurer tout seul, il n'y aura pas d'administrateur pour cela (le RFC 2501 examine les différents aspects du problème des MANETs). Notre nouveau RFC décrit la version 2 d'un de ces protocoles de routage les plus répandus, OLSR, dont la version 1 était dans le RFC 3626.

OLSR v2 est incompatible avec la v1, c'est un nouveau protocole. Il garde toutefois les mêmes principes de base (qui étaient avant ceux d'HiperLAN), notamment l'utilisation de MPR, des nœuds du réseau choisis comme routeurs (dans un MANET, il n'y a pas de routeur désigné, chaque machine peut se voir affecter cette tâche, cf. section 18). Ainsi, toutes les machines n'ont pas à émettre de l'information sur leurs interfaces, seul un sous-ensemble des nœuds, les MPR, le fait (c'est particulièrement rentable si le réseau est très dense ; s'il ne l'est pas, la plupart des nœuds seront des MPR puisqu'il n'y aura pas le choix). D'autre part, OLSR v2 est un protocole proactif, il calcule les routes en permanence et elles sont toujours prêtes (contrairement à d'autres protocoles qui calculent les routes à la demande). Principales nouveautés dans OLSR v2 : d'autres façons d'évaluer le coût d'une route que le simple nombre de sauts, et davantage de souplesse dans la signalisation. Notez enfin qu'OLSR peut fonctionner sur des liens de couche 2 variés. Ces liens ne sont pas forcément fiables (par exemple, les liens radio perdent souvent des paquets).

Pour comprendre, et surtout si vous voulez mettre en œuvre OLSR v2, il va falloir lire plusieurs RFC. En effet, la structure des normes OLSR v2 est modulaire : il y a un protocole de découverte des voisins (NHDP, dans le RFC 6130), un format de messages décrit dans le RFC 5444, des TLV normalisés dans le RFC 5497, et (mais celui-ci est optionnel) les considérations sur la gigue du RFC 5148 (variations aléatoires ajoutées pour éviter que tous les messages n'arrivent en même temps). Et, naturellement, il faut ensuite lire ce nouveau RFC 7181 (113 pages).

La section 4 résume le fonctionnement du protocole. Comme les MANETs sont loin de mes domaines de compétence, je ne vais pas la reprendre complètement. Quelques points qui me semblent importants. D'abord, le routeur OLSR a plusieurs bases de données (cf. RFC 6130) dans sa mémoire : il y a sa configuration locale (ses adresses IP), sa liste d'interfaces réseau, avec les métriques de chacune (le « coût » d'utilisation), la base des voisins (très dynamique puisque, dans un MANET, les choses changent souvent, le protocole du RFC 6130 permet de découvrir les voisins, voir aussi la section 15 de ce RFC). Cette dernière base contient les volontés d'un voisin (un nœud peut indiquer sa volonté à être routeur, elle va de WILL_NEVER à WILL_ALWAYS). Et il y a bien sûr la base de la topologie, indiquant la vision du réseau de la machine (les routes qu'elle connait).

Ensuite, OLSR v2, contrairement à son prédécesseur, dispose de plusieurs métriques pour mesurer les coûts d'utilisation d'une route. Un coût est unidirectionnel (il n'a pas forcément la même valeur dans les deux directions).

Le protocole dépend d'un certain nombre de paramètres (section 5). Certains sont spécifiés dans le RFC 5498 comme le numéro de port lorsque OLSR tourne sur UDP (269).

Comme souvent avec les réseaux ad hoc, la sécurité est souvent à peu près nulle. La section 23 de notre RFC fait le point sur les risques associés à OLSR v2 et sur l'approche utilisée si on souhaite sécuriser un MANET. Premier principe, chaque routeur doit valider les paquets (pas seulement leur syntaxe mais aussi leur contenu) puisqu'il ne peut a priori pas faire confiance aux autres. Deuxième principe, la sécurité d'OLSR v2 est réglable. On peut aller de « open bar », on fait confiance à tout le monde, à l'authentification des messages par le biais de signatures attachées aux messages (RFC 7182 et RFC 7183).

Cette sécurité, si on choisit de l'activer, nécessite que les routeurs connaissent les clés cryptographiques servant à l'authentification. OLSR v2 n'a pas de protocoles de gestion de clés. Dans le contexte d'un MANET, il n'y aura souvent pas de moyen de configurer une clé avant d'installer les machines. (Rappelez-vous qu'un MANET est censé être « zéro administration »).

Il existe bien des mises en œuvre de cette version 2 de OLSR, un protocole qui avait commencé sa carrière vers 2005. Citons entre autres (attention, elles ne sont pas forcément libres) :


Téléchargez le RFC 7181


L'article seul

RFC 7166: Supporting Authentication Trailer for OSPFv3

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : M. Bhatia (Alcatel-Lucent), V. Manral (Hewlett Packard), A. Lindem (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ospf
Première rédaction de cet article le 13 mars 2014


La version 2 du protocole de routage OSPF avait un mécanisme d'authentification (annexe D du RFC 2328). Lors de la conception de la version 3 (qui permettait notamment d'ajouter IPv6), ce mécanisme avait été abandonné, l'idée étant que l'IETF avait déjà un mécanisme d'authentification plus général, IPsec, et qu'il « suffisait » de l'utiliser. Selon cette analyse, il n'y avait plus besoin de doter chaque protocole de son propre mécanisme d'authentification. C'était très bien sur le papier. Mais, en pratique, le déploiement d'IPsec est très limité, à la fois en raison de sa complexité et du caractère imparfait de ses implémentations. Résultat, les utilisateurs d'OPSFv3 n'ont, la plupart du temps, pas déployé de mécanisme de sécurité du tout. En voulant faire trop propre, on a donc diminué la sécurité du routage. Le RFC 6506 corrigeait le tir en dotant enfin OSPFv3 d'un mécanisme d'authentification léger et réaliste. Ce mécanisme a été expliqué par l'un des auteurs du RFC sur son blog. Ce nouveau RFC remplace le RFC 6506 et le met légèrement à jour.

OSPFv3 est normalisé dans le RFC 5340, dont le titre (« OSPF pour IPv6 ») est trompeur car, depuis le RFC 5838, OSPFv3 peut gérer plusieurs familles d'adresses et peut donc, en théorie, remplacer complètement OSPFv2. En pratique, toutefois, ce n'est pas encore le cas, notamment pour le problème de sécurité qui fait l'objet de ce RFC : contrairement aux autres protocoles de routage internes, OSPFv3 ne disposait d'aucun mécanisme d'authentification. N'importe quel méchant sur le réseau local pouvait se proclamer routeur et envoyer de fausses informations de routage. L'argument répété était « pas besoin de mécanisme spécifique à OSPFv3, utilisez les mécanismes IPsec, comme expliqué dans le RFC 4552 ». Mais on constate que cette possibilité a été très peu utilisée. Le RFC se contente de noter que c'est parce que IPsec est mal adapté à certains environnements comme les MANET mais il ne parle pas des autres environnements, où IPsec est simplement rejeté en raison de la difficulté à trouver une implémentation qui marche, et qu'un administrateur système normal arrive à configurer.

IPsec a également des faiblesses plus fondamentales pour des protocoles de routage comme OSPF. Ainsi, les protocoles d'échange de clés comme IKE ne sont pas utilisables tant que le routage ne fonctionne pas. Pour résoudre le problème d'œuf et de poule, et parce que les communications OSPF sont de type un-vers-plusieurs (et pas un-vers-un comme le suppose IKE), le RFC 4552 prône des clés gérées manuellement, ce qui n'est pas toujours pratique.

Enfin, l'absence de protection contre le rejeu affaiblit la sécurité d'IPsec dans ce contexte, comme le note le RFC 6039.

La solution proposée figure en section 2. L'idée est d'ajouter à la fin du packet OSPF un champ qui contienne un condensat cryptographique du paquet et d'une clé secrète, comme pour OSPFv2 (RFC 5709) (D'autres types d'authentification pourront être utilisés dans le futur, un registre IANA des types a été créé.) Les options binaires du paquet, au début de celui-ci (RFC 5340, section A.2), ont un nouveau bit, en position 13, AT (pour Authentication Trailer, désormais dans le registre IANA), qui indique la présence ou l'absence du champ final d'authentification (tous les paquets n'ont pas ce champ Options, donc le routeur devra se souvenir des valeurs de ce champ pour chaque voisin).

Pour chaque couple de routeurs ainsi protégés, il y aura un certain nombre de paramètres, qui forment ce qu'on nomme un accord de sécurité (security association, section 3) :

  • Un identifiant sur 16 bits, manuellement défini, le Security Association ID. L'émetteur le choisit et le récepteur le lit dans le paquet. Cette indirection va permettre de modifier des paramètres comme les clés cryptographiques (ou même l'algorithme cryptographique), tout en continuant le routage.
  • L'algorithme utilisé, par exemple HMAC-SHA1 ou HMAC-SHA512,
  • La clé,
  • Des paramètres temporels indiquant, par exemple, à partir de quand la clé sera valide.

Une fois qu'on a toutes ces informations, que met-on dans le paquet OSPF envoyé sur le câble ? La section 4 décrit le mécanisme. Le champ final d'authentification (Authentication Trailer) est composé notamment de l'identifiant d'un accord de sécurité (SA ID, décrit au paragraphe précédent, et qui permet au récepteur de trouver dans sa mémoire les paramètres cryptographiques liés à une conversation particulière), d'un numéro de séquence (qui sert de protection contre le rejeu ; il est augmenté à chaque paquet émis et il comprend 64 bits) et du condensat cryptographique du paquet concaténé avec la clé (la section 4.5 décrit l'algorithme en détail et notamment quels champs du paquet sont inclus dans les données condensées).

Le routeur qui reçoit un paquet utilisant l'authentification (il le sait grâce au bit AT qui était notamment présent dans les paquets OSPF Hello) va accéder au champ d'authentification (le champ Longueur du paquet OSPF lui permet de savoir où commence le champ d'authentification, éventuellement en tenant compte du bloc Link-Local Signaling du RFC 5613, un routeur doit donc gérer au moins en partie ce dernier RFC s'il veut authentifier). Le récepteur refait alors le calcul cryptographique et vérifie si le champ final d'authentification est correct. Le calcul est très proche de celui du RFC 5709 à part l'inclusion de l'adresse IPv6 source.

Supposons que nous soyons administrateur réseaux et que nos routeurs gèrent tous ce RFC. Comment déployer l'authentification sans tout casser ? La section 5 recommande de migrer tous les routeurs connectés au même lien simultanément. Autrement, les routeurs qui n'utilisent pas l'authentification ne pourront pas former d'adjacences OSPF avec ceux qui l'utilisent. Le RFC prévoit un mode de transition, où le routeur envoie le champ final d'authentification mais ne le vérifie pas en entrée mais l'implémentation de ce mode n'est pas obligatoire.

La section 6 contient l'analyse de sécurité de cette extension d'OSPF. Elle rappelle qu'elle ne fournit pas de confidentialité (les informations de routage seront donc accessibles à tout espion). Son seul but est de permettre l'authentification des routeurs, résolvant les problèmes notés par le RFC 6039. À noter que cette extension ne permet pas d'authentifier un routeur particulier mais simplement de s'assurer que l'émetteur est autorisé à participer au routage sur ce lien (tous les routeurs ont la même clé). La clé, rappelle cette section 6, devrait être choisie aléatoirement, pour ne pas être trop facile à deviner (cf. RFC 4552).

Des implémentations de cette option dans le logiciel d'un routeur ? Elle existe dans Cisco (voir leur documentation) et Quagga.

Les changements depuis le RFC 6506 ne sont pas très importants (section 1.2) et sont surtout des clarifications et des corrections de quelques erreurs dans l'ancienne spécification. Ainsi, ce nouveau RFC dit clairement que certaines calculs de somme de contrôle, redondants, doivent être omis (cela avait fait l'objet des errata 3567 et 3568). Et il supprime la possibilité d'utiliser des clés expirées lorsqu'il n'existe plus de clé valide (qui était à la fin de la section 3 de l'ancien RFC ; la nouvelle suggestion est de notifier l'opérateur et d'arrêter d'envoyer les paquets OSPF).


Téléchargez le RFC 7166


L'article seul

RFC 7165: Use Cases and Requirements for JSON Object Signing and Encryption (JOSE)

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : R. Barnes (BBN Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 15 avril 2014


Il est traditionnel de classer les mécanismes de sécurité de l'Internet en deux, ceux fondés sur la sécurité du canal et ceux fondés sur la sécurité de l'objet. Pour les premiers, on garantit certaines propriétés de l'objet pendant son transit dans un canal donné. Pour les seconds, l'objet se déplace en permanence dans une armure cryptographique qui le protège, quelle que soit la sécurité du canal où il voyage. Le groupe de travail JOSE de l'IETF cherche à procurer une sécurité de l'objet aux textes encodés en JSON. Son premier RFC est consacré à décrire les cas d'usage et le cahier des charges de cette sécurité.

JSON (RFC 7159) est un format très répandu, notamment sur le Web. Il peut être transporté dans des protocoles qui assurent la sécurité du canal comme HTTPS. Mais, comme toujours avec la sécurité du canal (IPsec, TLS, etc), elle ne garantit pas de sécurité de bout en bout. Par exemple, si le serveur d'origine est piraté, et les textes en JSON modifiés, HTTPS ne protégera plus. Même chose si on utilise certains relais, chose courante sur le Web : HTTPS ne protège pas contre les intermédiaires. Il existe à l'IETF des mécanismes assurant la sécurité du message (de l'objet) comme CMS (RFC 5652) pour l'ASN.1/DER. Mais pour le JSON ? Il y a là un manque à combler. Car la sécurité du message est nécessaire pour permettre la manipulation du messages par des intermédiaires à qui on ne fait pas forcément confiance. Pour le courrier électronique, la sécurité du canal est fournie par SMTP sur TLSRFC 3207, et la sécurité du message par PGPRFC 9580 - ou S/MIME - mais le RFC, curieusement, ne cite pas PGP. Par contre, il n'existe pas encore de solution propre pour JSON transporté sur HTTP. Les gens de XML ont choisi XML Signature et XML Encryption, les gens de JSON travaillent donc activement à leur propre solution.

Ce RFC parle de sécurité et utilise donc largement la terminologie standard du RFC 4949. Il peut être utile aussi de lire le RFC 5652 sur CMS car ce RFC le cite souvent.

Le groupe de travail JOSE (JSON Object Signing and Encryption) est chargé de développer trois formats :

Rappelez-vous que ce RFC 7165 n'est que le premier RFC du groupe, il ne donne pas encore de solutions, il explore le problème et précise les exigences du travail à effectuer (la liste officielle et numérotée de ces exigences figure en section 6).

Le cahier des charges débute en section 3 avec un résumé des exigences « de base » :

  • Le format pour l'objet chiffré doit permettre l'utilisation de la cryptographie symétrique et de la cryptographie asymétrique.
  • Le format pour l'objet signé doit permettre une vérification de l'intégrité par MAC pour le cas où les deux parties partagent une clé (cryptographie symétrique), et par signature avec de la cryptographie asymétrique.
  • Comme les textes JSON protégés ne seront pas forcément traités dans le contexte d'une communication synchrone avec possibité de négociation ou d'échange, il faut (le RFC prévoit des exceptions très encadrées) que tous les paramètres cryptographiques nécessaires (à part les clés) soient inclus dans l'objet. À noter que la liste des paramètres dépend de l'algorithme cryptographique utilisé (qui doit donc être indiqué clairement).
  • Conséquence de l'exigence précédente, les applications qui traitent les textes JSON protégés doivent avoir un moyen simple de déterminer si elles sont en possession de la clé nécessaire, et de produire un message d'erreur clair si ce n'est pas le cas.

La section 4 rappelle que l'application qui utilisera les textes JSON protégés a aussi des responsabilités, par exemple c'est elle qui décidera quels algorithmes sont acceptables, comment seront échangées les clés, etc.

La liste complète des exigences est en section 6 du RFC. Mais, avant cela, la section 5 contient les études de cas. La première est celle des jetons (security tokens), ces petits textes qu'on s'échange pour authentifier ou autoriser un tiers dans une communication (« il a le doit de lire les fichiers, laisse-le y accéder »). C'est par exemple le cas des assertions de SAML, de Persona, et d'OpenID Connect. Certains utilisent XML mais un autre groupe de travail IETF développe un format JSON, JWT (JSON Web token), déjà utilisé dans des systèmes comme Persona. Ce format a besoin des techniques JOSE pour être sécurisé. Le RFC note qu'il faudra aussi que le format final puisse être mis dans un URL, ce qui nécessite qu'il doit très compact. Le fait qu'une permission soit donnée peut être parfois confidentiel et le format de signature peut donc ne pas suffire. Même dans ce cas d'usage, il faudra donc aussi penser à la confidentialité. Autre exemple de jeton, dans OAuth (RFC 6749). Ici, la norme impose un transport par HTTPS donc la confidentialité est normalement assurée, il ne reste que l'authentification.

Ces jetons de sécurité sont également utilisés dans les cas de fédérations d'identité. Ainsi, OpenID Connect, déjà cité, repose sur OAuth et JSON et est un des gros demandeurs des fonctions JOSE.

Autre étude de cas, pour le protocole XMPP (RFC 6120), surtout connu pour la messagerie instantanée. Un instant, vous allez me dire, le X dans XMPP rappelle qu'il a XML comme format. Que vient-il faire dans un RFC parlant de JSON ? C'est parce que la sécurité de XMPP, aujourd'hui, est uniquement une sécurité du canal : les communications entre clients et serveurs, ou bien entre les serveurs, sont protégées par TLS (et de nombreux acteurs du monde XMPP se sont engagés à ce que le chiffrement soit systématisé avant mai 2014). Mais cela ne fournit pas de sécurité de bout en bout, ce qui est d'autant plus gênant que les sessions XMPP sont rarement établies directement entre deux pairs, mais passent par des serveurs qui sont la plupart du temps gérés par une organisation différente. XMPP, tel qu'utilisé aujourd'hui, est donc vulnérable à l'espionnage par le fournisseur. Le problème est identifié depuis longtemps, mais la seule solution standard, décrite dans le RFC 3923, n'a jamais été adoptée (comme la plupart des techniques S/MIME). Actuellement, la solution la plus commune pour résoudre ce problème de sécurité est OTR.

Une autre solution est donc en cours de développement dans la communauté XMPP, fondée sur JSON et JOSE. C'est certes bizarre de transporter des textes JSON dans les flux XML de XMPP et cela complique un peu les choses (il faut être sûr que le texte JSON ne contienne pas de caractères qui sont spéciaux pour XML, ou alors il faut tout mettre dans un bloc CDATA ou encore encoder tout en Base64, au prix d'un accroissement de taille).

Autre système qui aura besoin de JOSE, ALTO (RFC 6708). Ce système permet à un client de s'informer, auprès d'un serveur, sur le pair le plus « proche » pour les cas où plusieurs pairs peuvent rendre le même service. Dans son mode le plus simple, ALTO est simplement un protocole requête/réponse, où les échanges se font en JSON sur HTTP. HTTPS est suffisant pour sécuriser ce mode. Mais les futures versions d'ALTO pourraient avoir des objets d'information relayés entre plusieurs parties, et JOSE deviendrait alors utile pour les sécuriser.

Continuons la riche liste de cas d'école possibles pour JOSE, avec les systèmes d'alerte. Il y a des travaux en cours à l'IETF sur l'utilisation de l'Internet pour diffuser des alertes, par exemple concernant une catastrophe naturelle proche. Une exigence absolument critique de ces systèmes est l'impossibilité de fabriquer une fausse alerte. Si c'était possible, une grave panique pourrait être déclenchée à volonté. Et, sans même parler des effets de la panique, la confiance dans le système disparaitrait rapidement. Or, les alertes doivent être diffusées très vite, à beaucoup de gens, quel que soit le mécanisme par lequel ils sont actuellement connectés. Elles passent donc par des intermédiaires, cherchant à toucher tout le monde. Une protection du canal ne suffit donc pas, une protection du message (du texte JSON) est nécessaire.

Dernier cas que je vais citer, l'API Web Cryptography. Cette API normalisée permet notamment au code JavaScript s'exécutant dans un navigateur de demander au navigateur de réaliser des opérations cryptographiques. L'un des intérêts (par rapport à une mise en œuvre complètement en JavaScript) est la sécurité : les clés peuvent rester dans le navigateur, JavaScript n'y a pas accès. Ceci dit, dans certains cas, la capacité d'exporter une clé (par exemple pour la copier vers un autre appareil) est utile. L'API prévoit donc cette fonction (avec, on l'espère, de stricts contrôles et vérifications) et cela implique donc un format standard pour ces clés (publiques ou privées). Au moins pour les clés privées, la confidentialité de ce format est cruciale. JOSE (son format JWK) va donc être utilisé.

La section 6 du RFC liste les exigences précises du projet JOSE. Chacune, pour faciliter les références ultérieures, porte un identificateur composé d'une lettre et d'un nombre. La lettre est F pour les exigences fonctionnelles, S pour celles de sécurité et D si c'est une simple demande, pas une exigence. Par exemple, F1 est simplement l'exigence de base d'un format standard permettant authentification, intégrité et confidentialité. F2 et F3 couvrent le format des clés (dans le cas de la cryptographie symétrique comme dans celui de l'asymétrique). F4 rappelle que le format doit être du JSON, et F5 qu'il faut une forme compacte, utilisable dans les URL.

Parmi les simples désirs, D1 rappelle l'importance de se coordonner avec le groupe de travail WebCrypto du W3C, D2 souhaite qu'on n'impose pas (contrairement à beaucoup d'autres normes de cryptographie comme XML Signature) de canonicalisation du contenu, D3 voudrait qu'on se focalise sur le format, pas sur les opérations, de manière que les formats JOSE soient utilisables par des applications très différentes, utilisant des protocoles de cryptographie bien distincts.

À noter que la section 7 revient sur la canonicalisation en reconnaissant que, comme il n'existe pas de moyen automatique simple de déterminer si deux textes JSON représentent la même information, cela peut avoir des conséquences sur la sécurité de JOSE.

Merci à Virginie Galindo pour sa relecture.


Téléchargez le RFC 7165


L'article seul

RFC 7164: RTP and Leap Seconds

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : K. Gross (AVA Networks), R. van Brandenburg (TNO)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF avtcore
Première rédaction de cet article le 1 avril 2014


Les secondes intercalaires sont une source de complication et de polémique depuis longtemps. Voilà qu'elles affectent même le protocole de distribution de multimédia RTP : si on regarde un film, ou qu'on a une communication téléphonique, au moment où une seconde intercalaire est ajoutée, RTP va mal le vivre. Ce RFC propose donc un léger changement dans la façon dont RTP tient compte du temps, afin de rester heureux même pendant les secondes intercalaires.

RTP est normalisé dans le RFC 3550. Il est conçu pour l'envoi de flux multimédias (audio ou vidéo) entre un émetteur et un récepteur. Les caractéristiques propres des flux multimédias font que TCP n'est pas très adapté, donc RTP utilise UDP. UDP, par défaut, ne prévoit pas de rétroaction (l'émetteur ne sait pas ce que le récepteur a reçu) donc RTP ajoute des fonctions permettant d'informer son pair de ce qui se passe. Certains flux étant temps réel, ces informations (sender reports et receiver reports, section 6.4 du RFC 3550) incluent des estampilles temporelles. Un des champs de ces informations, NTP timestamp, fait référence à une horloge absolue (l'horloge située sur le mur, synchronisée avec l'échelle UTC). Une horloge qui a des soubresauts, les secondes intercalaires. Or, jouer proprement un flux audio ou vidéo nécessite au contraire une horloge sans à-coups.

La section 3 de notre RFC est un rappel sur les secondes intercalaires. Il y a deux échelles de temps standard. L'une est bien adaptée à l'informatique, à l'Internet et aux activités scientifiques en général, c'est TAI, une échelle fondée sur un phénomène physique (les atomes de césium dans une horloge atomique) et où le temps est strictement croissant et prévisible. Une autre échelle est bien adaptée à l'organisation des pique-niques et autres activités au grand air, c'est UTC. La référence d'UTC est la rotation de la Terre. Comme la Terre, au contraire des atomes de césium, est imparfaite, UTC ne garantit pas que le temps progresse régulièrement, et n'est pas prévisible (je ne peux pas dire aujourd'hui quelle sera l'heure UTC dans cinq cents millions de secondes, alors que c'est trivial en TAI). Depuis 1972, UTC est définie comme étant TAI plus la correction des secondes intercalaires, qui ajoutées de temps en temps, permettent de compenser les variations de la rotation de la Terre. Ces secondes intercalaires sont forcément le dernier jour du mois et, en pratique, ont toujours été fin décembre ou fin juin (cf. texte UIT TF.460). Elles sont annoncées moins d'un an à l'avance dans le bulletin C (rappelez-vous que la rotation de la Terre n'est pas prévisible), par l'IERS.

S'il y a une seconde intercalaire, elle est forcément à la fin de la journée. Elle peut être positive (la dernière seconde de la journée est doublée, et s'affiche « 23 h 59 mn 60 s ») ou négative (la dernière seconde de la journée est omise). Jusqu'à présent, toutes les secondes intercalaires étaient positives, puisque la Terre ralentit (le jour devient plus long). À noter qu'il y a depuis des années une discussion sur la suppression des secondes intercalaires (ce qui serait une mauvaise idée), mais qu'elle n'est pas encore close. Voir mon article sur ce sujet et le document de l'UIT.

La référence de temps la plus commune sur l'Internet, NTP (RFC 5905) est en UTC (ce qui est une mauvaise idée, selon moi, les ordinateurs n'ayant pas besoin de savoir s'il fait jour ou pas). Au moment de la seconde intercalaire positive, l'horloge NTP ralentit (ce qui permet au moins de s'assurer que deux mesures successives donneront un temps strictement croissant) ou s'arrête, ce qui fait que la dernière seconde du jour dure deux secondes. Pour tout processus temps-réel, comme RTP, c'est un gros problème.

Les applications obtiennent en général l'heure via une interface normalisée POSIX. L'échelle de temps de POSIX est UTC, mais sans vraie spécification de la gestion des secondes intercalaires. En pratique, les différentes mises en œuvre de POSIX ont des comportements différents. Par exemple, certaines répètent l'heure, pendant la seconde intercalaire et deux lectures successives du temps à une seconde d'intervalle, peuvent donc donner une heure identique. Pire, l'horloge peut même aller en arrière (ce qu'UTC ne fait pas). D'autres ralentissent l'horloge, permettant une adaptation en douceur (et pas de répétition) mais cela n'est pas idéal non plus pour des applications temps-réel ! (Un bon article sur les problèmes d'utiliser une échelle de temps à secondes intercalaires est donné dans un excellent article de Google.)

Conséquences de ces comportements ? La section 4 note que l'envoyeur et le récepteur RTP peuvent donc avoir une seconde entière de décalage, ce qui est beaucoup pour la plupart des applications RTP. Cela peut mener à l'abandon de paquets RTP bien reçus mais considérés comme trop vieux, ou bien au contraire à la conservation de paquets dans les tampons d'entrée/sortie même lorsqu'ils ne sont plus utiles. Cela peut se traduire par une coupure du son ou de l'image. Certains récepteurs reconnaîtront un problème et se resynchroniseront avec l'émetteur. Les autres devront attendre.

La section 5 liste les recommandations pour éviter ce problème. D'abord, elle note que les récepteurs et émetteurs qui ne sont pas synchronisés avec l'horloge au mur, mais qui se contentent de mesurer le temps écoulé depuis leur démarrage n'auront jamais le problème. Ensuite, la section 5 note aussi que les émetteurs et récepteurs RTP qui utilisent une échelle de temps sans secondes intercalaires (évidemment TAI mais aussi IEEE 1588 ou GPS) n'ont également pas de problèmes. Mais pourquoi diable RTP n'utilise pas systématiquement TAI ? Cette échelle de temps a toutes les propriétés souhaitables pour la communication au sein d'un réseau informatique. Le RFC ne le dit pas, mais c'est probablement parce que TAI est, hélas, trop difficile d'accès sur la majorité des plate-formes. NTP et l'horloge du système fournissent un temps qui convient à beaucoup d'activités humaines, mais ne convient pas aux ordinateurs. Et il n'y a souvent pas de moyen simple d'accéder à TAI ou une autre échelle prédictible. (C'est le cas des fonctions POSIX gettimeoday() et clock_gettime().)

Pour les autres, les mises en œuvre de RTP qui doivent utiliser une échelle de temps qui a des secondes intercalaires, elles sont dans l'obligation de gérer ces secondes intercalaires. Cela implique d'abord un moyen de les connaître à l'avance (par exemple via le champ Leap Indicator de NTP). Ce n'est pas forcément réaliste (bien des machines reçoivent l'heure par des mécanismes qui n'indiquent pas l'approche d'une seconde intercalaire). Une solution un peu crade mais qui marche est alors de prendre les mesures citées plus loin tous les mois, lors de la fin du dernier jour du mois.

Les secondes intercalaires négatives ne posent aucun problème. Mais, on l'a vu, toutes les secondes intercalaires jusqu'à présent ont été positives. Dans ce cas, le RFC recommande que les logiciels RTP n'envoient pas de sender reports pendant les deux secondes où le temps est ambigu, car une seconde intercalaire a été ajoutée. Et les récepteurs doivent ignorer de tels messages. Ce changement aux règles du RFC 3550 est la principale recommandation concrète de ce RFC. Elle ne semble pas encore mise en œuvre dans un seul logiciel RTP. Est-ce que le problème, quoique joli techniquement, est assez grave en pratique pour justifier ce changement ?


Téléchargez le RFC 7164


L'article seul

RFC 7159: The JSON Data Interchange Format

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : T. Bray (Google)
Chemin des normes
Première rédaction de cet article le 3 mars 2014


Il existe une pléthore de langages pour décrire des données structurées. JSON, normalisé dans ce RFC (qui succède au RFC 4627), est actuellement le plus à la mode. JSON se veut plus léger que XML. Comme son concurrent XML, c'est un format textuel, et il permet de représenter des structures de données hiérarchiques. Ce RFC est l'ancienne norme JSON, remplacée depuis par le RFC 8259.

À noter que JSON doit son origine, et son nom complet (JavaScript Object Notation) au langage de programmation JavaScript, dont il est un sous-ensemble. La norme officielle de JavaScript est à l'ECMA actuellement la version 5.1 du document ECMA-262. JSON est dans la section 15.12 de ce document mais est aussi dans ECMA-404, qui lui est réservé. Il était prévu une publication commune ECMA/IETF mais elle n'a finalement pas eu lieu. Contrairement à JavaScript, JSON n'est pas un langage de programmation, seulement un langage de description de données, et il ne peut donc pas servir de véhicule pour du code méchant (sauf si on fait des bêtises comme de soumettre du texte JSON à eval(), cf. section 12 et erratum #3607 qui donne des détails sur cette vulnérabilité).

Voici un exemple, tiré du RFC, d'un objet exprimé en JSON :

  {
      "Image": {
          "Width":  800,
          "Height": 600,
          "Title":  "View from 15th Floor",
          "Thumbnail": {
              "Url":    "http://www.example.com/image/481989943",
              "Height": 125,
              "Width":  "100"
          },
          "IDs": [116, 943, 234, 38793]
        }
   }

Les détails de syntaxe sont dans la section 2 du RFC. Cet objet d'exemple a un seul champ, Image, qui est un autre objet (entre { et }) et qui a plusieurs champs. (Les objets sont appelés dictionnaires ou maps dans d'autres langages.) L'ordre des éléments de l'objet n'est pas significatif (certains analyseurs JSON le conservent, d'autres pas). Un de ces champs, IDs, a pour valeur un tableau (entre [ et ]). Les éléments d'un tableau ne sont pas forcément du même type (section 5, qui précise un point qui n'était pas clair dans le précédent RFC). Autrefois, un texte JSON était forcément un objet ou un tableau. Ce n'est plus le cas aujourd'hui donc, par exemple  :

"Hello world!"

est un texte JSON légal (composé d'une chaîne de caractères en tout et pour tout). Ce point a d'ailleurs suscité de vigoureuses protestations car un lecteur de JSON qui lit au fil de l'eau peut ne pas savoir si le texte est fini ou pas (avant, il suffisait de compter les crochets et accolades).

Et quel encodage utiliser pour les textes JSON (section 8) ? Le RFC 4627 était presque muet à ce sujet. Cette question est désormais plus développée. Le jeu de caractères est toujours Unicode et l'encodage par défaut est UTF-8. UTF-16 et UTF-32 sont permis mais UTF-8 est le seul qui assure l'interopérabilité, bien des mises en œuvre de JSON ne peuvent en lire aucun autre. Les textes JSON ne doivent pas utiliser de BOM et le RFC ne dit pas comment le récepteur sait quel est l'encodage utilisé, on suppose qu'il doit être indiqué par ailleurs (par exemple dans l'en-tête Content-Type: en HTTP).

Notre RFC ne spécifie pas un comportement particulier à adopter lorsqu'une chaîne de caractères n'est pas légale pour l'encodage choisi. Cela peut varier selon l'implémentation.

Autre problème classique d'Unicode, la comparaison de chaînes de caractères. Ces comparaisons doivent se faire selon les caractères Unicode et pas selon les octets (il y a plusieurs façons de représenter la même chaîne de caractères, par exemple foo*bar et foo\u002Abar sont la même chaîne).

JSON est donc un format simple, il n'a même pas la possibilité de commentaires dans le fichier... Voir sur ce sujet une intéressante compilation.

Le premier RFC décrivant JSON était le RFC 4627. Quels changements apporte cette première révision (section 1.3 et annexe A) ? Au début du travail, l'IETF était partagée entre des ultras voulant réparer tous les problèmes de la spécification et les conservateurs voulant changer le moins de choses possible. Finalement, rien de crucial n'a été modifié, quelques bogues ont été corrigées et des points flous du premier RFC ont été précisés (quelques uns ont déjà été présentés plus haut). Cela a quand même posé quelques problèmes philosophiques. Ainsi, le RFC 4627 disait dans sa section 2.2 « The names within an object SHOULD be unique ». Et s'ils ne l'étaient pas, que se passait-il ? Si un producteur de JSON, ignorant l'avertissement, envoie :

{
"name": "Jean Dupont",
"city": "Paris",
"city": "London"
}

Que va faire le récepteur ? Planter ? Prendre la première ville ? La dernière ? Un ensemble de toutes les villes ? Une solution possible aurait été de transformer le SHOULD en MUST (cf. RFC 2119) et donc de déclarer cet objet JSON illégal. Mais cela aurait rendu illégaux des tas d'objets JSON circulant sur l'Internet et qui n'étaient que déconseillés. Le choix a donc été de décréter (section 4) que l'objet respectant la règle « noms uniques » serait interopérable (tous les récepteurs en feront la même interprétation) alors que celui qui viole cette règle (comme l'exemple avec deux city plus haut) aurait un comportement imprévisible. Un programme mettant en œuvre l'analyse de JSON a donc le droit de choisir parmi tous les comportements mentionnés plus haut.

Autres changements, un avertissement (section 6) sur la précision des nombres (on peut écrire 3.141592653589793238462643383279 mais on n'a aucune garantie que le récepteur pourra conserver une telle précision).

Voici un exemple d'un programme Python pour écrire un objet Python en JSON (on notera que la syntaxe de Python et celle de JavaScript sont très proches) :

import json

objekt = {u'Image': {u'Width': 800,
                     u'Title': u'View from Smith\'s, 15th Floor, "Nice"',
                     u'Thumbnail': {u'Url':
                                    u'http://www.example.com/image/481989943',
                                    u'Width': u'100', u'Height': 125},
                     u'IDs': [116, 943, 234, 38793],
                     u'Height': 600}} # Example from RFC 4627, lightly modified

print json.dumps(objekt)

Et un programme pour lire du JSON et le charger dans un objet Python :

import json

# One backslash for Python, one for JSON
objekt = json.loads("""
{
      "Image": {
          "Width":  800,
          "Height": 600,
          "Title":  "View from Smith's, 15th Floor, \\\"Nice\\\"", 
          "Thumbnail": {
              "Url":    "http://www.example.com/image/481989943",
              "Height": 125,
              "Width":  "100"
          },
          "IDs": [116, 943, 234, 38793]
        }
   }
""") # Example from RFC 4267, lightly modified

print objekt
print ""
print objekt["Image"]["Title"]

Le code ci-dessus est très simple car Python (comme Perl ou Ruby ou, bien sûr, JavaScript) a un typage complètement dynamique. Dans les langages où le typage est plus statique, c'est moins facile et on devra souvent utiliser des méthodes dont certains programmeurs se méfient, comme des conversions de types à l'exécution. Si vous voulez le faire en Go, il existe un bon article d'introduction au paquetage standard json.

Pour Java, qui a le même « problème » que Go, il existe une quantité impressionnante de bibliothèques différentes pour faire du JSON (on trouve en ligne plusieurs tentatives de comparaison). J'ai utilisé JSON Simple. Lire un texte JSON ressemble à :

import org.json.simple.*;
...
Object obj=JSONValue.parse(args[0]);
if (obj == null) { // May be use JSONParser instead, it raises an exception when there is a problem
	    System.err.println("Invalid JSON text");
	    System.exit(1);
} else {
	    System.out.println(obj);
}

JSONObject obj2=(JSONObject)obj; // java.lang.ClassCastException if not a JSON object
System.out.println(obj2.get("foo")); // Displays member named "foo"

Et le produire :

JSONObject obj3=new JSONObject();
obj3.put("name","foo");
obj3.put("num",new Integer(100));
obj3.put("balance",new Double(1000.21));
obj3.put("is_vip",new Boolean(true));

JSON dispose d'une page Web officielle, où vous trouverez plein d'informations. Pour tester dynamiquement vos textes JSON, il y a ce service. Il y a aussi des gens critiques, voir par exemple, cette analyse détaillée (avec beaucoup de références au RFC).


Téléchargez le RFC 7159


L'article seul

RFC 7158: The JSON Data Interchange Format

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : T. Bray (Google)
Chemin des normes
Première rédaction de cet article le 2 mars 2014


Suite à une stupide erreur de date, ce RFC a été annulé le lendemain de sa publication et remplacé par le RFC 7159 (les RFC ne sont jamais modifiés, leur contenu est immuable).


Téléchargez le RFC 7158


L'article seul

RFC 7157: IPv6 Multihoming without Network Address Translation

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : O. Troan (Cisco), D. Miles (Alcatel-Lucent), S. Matsushima (Softbank Telecom), T. Okimoto (NTT West), D. Wing (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 22 avril 2014


Pour la petite entreprise ou association, il est très intéressant d'être multi-homé, c'est-à-dire d'avoir plusieurs connexions à l'Internet, afin d'être sûr que l'accès fonctionne toujours. Financièrement, acheter deux connexions Internet grand public, de fiabilité moyenne, est nettement moins cher qu'une seule connexion supposée de grande fiabilité. Il reste à permettre aux machines du réseau local à utiliser les deux connexions. En IPv4, cela se fait traditionnellement en utilisant le NAT, qui est de toute façon nécessaire en raison de la pénurie d'adresses. Et en IPv6 ?

On pourrait utiliser le NAT, comme le mettent en œuvre un certain nombre de boîtiers existants actuellement. Les machines du réseau local utiliseraient un seul préfixe, un ULA et le routeur traduirait vers les préfixes de l'un ou l'autre FAI (peut-être en tenant compte de la charge, du prix, etc). Mais le NAT a de nombreux inconvénients et l'un des buts d'IPv6 était justement de s'en débarrasser (ceci dit, si vous voulez tenter l'aventure, il existe un RFC sur ce sujet, le RFC 6296, cf. section 7.1). Autre solution, faire du beau multi-homing propre avec des adresses PI et BGP. Mais c'est complètement hors de portée de la petite organisation, notamment par les ressources humaines que cela nécessite. (Voir le RFC 3582 pour un cahier des charges d'une solution idéale pour le multi-homing.)

Je vous le dis tout de suite, il n'existe pas encore de solution propre et déployable pour ce problème. À court terme, le RFC 6296 reste la seule solution. Notre RFC explore ce qui pourrait être utilisé pour après, en supposant un réseau multi-homé avec plusieurs préfixes IP (MHMP pour multihomed with multi-prefix). C'est donc plutôt un cahier des charges qu'un catalogue de solutions.

A priori, IPv6 permet parfaitement d'avoir deux préfixes d'adresses (un par FAI, si on est multi-homé à seulement deux FAI) sur le même réseau. Mais cela laisserait les machines face à bien des problèmes :

  • S'il y a deux routeurs (un pour chaque FAI), lequel choisir pour sortir ?
  • Quelle adresse IP source choisir pour les connexions sortantes ? Notez que c'est lié au problème précédent : si le FAI met en œuvre le filtrage du RFC 2827, il faut choisir le préfixe correspondant au FAI de sortie.
  • Et c'est encore pire si le FAI impose l'usage de ses résolveurs DNS car il y met des informations spécifiques à ses clients (comme Orangesmtp.wanadoo.fr et smtp.orange.fr donnent des résultats différents selon le réseau, interne ou externe).

Bref, simplement connecter le réseau local à deux FAI et distribuer leurs adresses sur ledit réseau ne suffit pas.

La section 3 décrit plusieurs scénarios typiques, pour rendre plus concret le problème. Le premier est celui où le réseau a deux routeurs, chacun connecté à un FAI et ignorant de l'autre routeur. C'est le cas par exemple de l'abonnement à deux FAI ADSL avec chaque FAI fournissant sa box. Le deuxième scénario imagine un seul routeur sur le réseau local, connecté à deux FAI. L'unique routeur du réseau local peut publier sur le réseau local tout ou partie des informations (préfixe IP, résolveurs DNS) reçues. Ce scénario peut se trouver, entre autres, si on a un abonnement Internet plus un tunnel vers un fournisseur de VPN. Enfin, dans le troisième scénario, c'est la machine terminale qui a deux connexions et qui doit les gérer. C'est le cas du téléphone drôlement intelligent qui est connecté en WiFi et en 3G.

Quels vont être les principaux problèmes à résoudre avec ces trois scénarios (section 3.3) ?

  • Dans le premier cas, celui à deux routeurs, la sélection, par une machine du réseau local, de son adresse IP source, en cohérence avec le routeur choisi pour la sortie (si elle se trompe, le paquet sera refusé par le FAI s'il met en œuvre le RFC 2827), et la répartition de charge (chaque machine n'enverra du trafic qu'à un seul routeur),
  • Dans le deuxième scénario, avec un seul routeur sur le réseau local, le même problème de sélection d'adresse IP source, si le routeur publie les deux préfixes sur le réseau local, et la sélection du FAI de sortie par le routeur,
  • Pour le troisième exemple, celui de la machine terminale à plusieurs connexions, le manque d'informations (sur la facturation, par exemple) pour décider quel trafic envoyer à quelle interface (curieusement, notre RFC ne cite pas l'excellent RFC 6419, entièrement consacré à cette question des machines terminales multi-homées).

Et, dans les trois scénarios, le problème du résolveur DNS, si les deux résolveurs ne donnent pas les mêmes résultats.

Maintenant, il faut résoudre ces problèmes, en respectant deux principes (section 4) : maintien du principe de bout en bout (donc pas de NAT), puisque c'est l'un des principaux buts d'IPv6, et passage à l'échelle, la solution devant fonctionner même pour des gros déploiements.

Les sections 5 et 6 explore les angles d'attaque possibles. Pour la sélection de l'adresse IP source (sections 5.1 et 6.1), la référence actuelle est le RFC 3484, qui est loin de donner un résultat optimum, puisqu'il utilise uniquement l'adresse IP de destination (dans la scénario 1 ci-dessus, il ne garantit pas qu'on sélectionne une adresse qui correspondra au routeur de sortie). Une approche actuellement étudiée à l'IETF serait de distribuer (par exemple en DHCP), depuis le routeur, des politiques de sélection d'adresse (actuellement, elles sont configurées dans chaque machine, /etc/gai.conf sur la plupart des Linux, par exemple). Pour que ces politiques soient complètes, cela nécessitera la coopération du FAI..

Pour la sélection du routeur (sections 5.2 et 6.2), c'est à peu près la même chose : les machines terminales n'ayant actuellement pas assez d'informations pour prendre une décision intelligente, il faudra leur envoyer (via DHCP), les informations permettant de choisir le routeur. Une telle information ne peut pas facilement être transmise avec les RA (Router Advertisement), qui ne permettent pas d'envoyer des informations différentes selon la machine. (On pourrait envisager d'utiliser les protocoles de routage eux-mêmes mais il y a bien longtemps qu'on a cessé de les faire tourner sur les machines terminales, et pour de bonnes raisons.)

Enfin, pour le dernier gros problème, la sélection du résolveur DNS (sections 5.3 et 6.3), notre RFC rappelle que les machines ont pu connaître le résolveur via DHCP (RFC 3646) ou RA (RFC 8106). Dans le cas du multi-homing, la machine aura typiquement plusieurs résolveurs DNS. Parfois, il faudra utiliser un résolveur spécifique pour un domaine donné (dans l'exemple d'Orange, cité plus haut, il faut utiliser les résolveurs d'Orange pour les noms en wanadoo.fr, car on obtient des résultats différents avec les serveurs publics). Cette pratique, connue sous le nom de split DNS est typiquement très mal vue (entre autres, elle rend le débogage très compliqué) mais elle existe. Notre RFC décide donc, sans l'entériner, de « faire avec ».

Là encore, un travail est en cours à l'IETF pour normaliser une politique de sélection du résolveur, en fonction du domaine à résoudre, et distribuée par DHCP (RFC 6731).

Bien sûr, il existe des tas d'autres techniques qui peuvent aider dans ce cas du multi-homing. Le RFC cite SHIM6 (RFC 5533), SCTP (RFC 4960), HIP (RFC 5206), etc. Mais elles sont aujourd'hui trop peu déployées pour qu'on puisse compter dessus.

Enfin, la section 8 nous rappelle que tout ceci va certainement poser des problèmes de sécurité amusants. Par exemple, si on distribue une politique de sélection (d'adresse IP source, de résolveur DNS, etc) sur le réseau, il y aura toujours des machines qui n'obéiront pas. Contrôle et filtrage resteront donc nécessaires. D'autre part, il existe déjà aujourd'hui des serveurs DHCP pirates, qui répondent à la place du vrai, et le problème sera pire encore lorsque des politiques de sélection (de routeur, de réolveur DNS, etc) seront distribuées via DHCP.


Téléchargez le RFC 7157


L'article seul

RFC 7154: IETF Guidelines for Conduct

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : S. Moonesamy
Première rédaction de cet article le 3 mars 2014


L'IETF, comme toute organisation humaine, a parfois des problèmes avec le comportement de certains de ses membres. Et, même quand il n'y a pas encore eu de problèmes (ce qui semble le cas à l'IETF), cela peut être une bonne idée de les traiter avant qu'ils ne surviennent. C'était le but du RFC 3184 en 2001, RFC que ce nouveau RFC remplace. Voici donc les règles de comportement à l'IETF. Résumées en quelques mots « ne vous comportez pas comme une brute ».

Ce n'est pas forcément une règle triviale à appliquer. En effet, l'IETF rassemble des participants d'origines très diverses. Ils et elles sont de pays différents, de cultures différentes, et ont des avis très distincts sur ce qui constitue un comportement poli et digne. L'idée de base est que chaque participant soit traité avec respect et qu'il n'est pas question de tolérer, par exemple (cet exemple n'est pas dans le RFC, qui évite soigneusement tous les exemples qui auraient l'air féministes) le harcèlement systématiques des participantes qui se fait à DEF CON.

Malheureusement, ce RFC se sent obligé d'ajouter qu'il faut se comporter de manière « professionnelle » comme si les amateurs, eux, étaient des brutes avinées et qu'il n'y a que dans le cadre du travail qu'on peut être civilisé.

Donc, les règles concrètes, en section 2 de ce RFC. D'abord, respect et courtoisie vis-à-vis des collègues, « traitez-les comme vous voudriez être traité » (notez que ce conseil ne tient pas compte, justement, de la diversité... Pas facile de normaliser la politesse.) Le RFC insiste sur le rôle de la langue : l'IETF fait tout en anglais et cette langue n'est pas la langue maternelle de tous les participants. Il est donc crucial que les anglophones en tiennent compte, parlent lentement, en évitant l'argot, et surtout en essayant sincèrement de comprendre le non-anglophone, sans le mépriser parce qu'il ne maîtrise pas la langue de Turing.

Ensuite, le RFC insiste sur le fait qu'on discute d'idées, pas de personnes, et qu'on utilise des arguments rationnels. Les tactiques d'intimidation (« il faut vraiment ne rien connaître à TLS pour proposer une telle modification ») ne sont pas admises. (Ce type de réponse est connu sous l'acronyme SQCFCR, Simple Question, Content-Free Condescending Response. À la place, il faut utiliser le SQPA, Simple Question, Polite Answer.)

Autre règle, qui ne concerne pas directement l'interaction entre les participants, l'obligation de chercher, en conscience, les meilleures solutions pour l'Internet, pas seulement celles qui correspondent aux intérêts d'un groupe particulier. Même si le RFC ne cite pas cet exemple, on peut penser à un participant travaillant pour la NSA qui chercherait à faire adopter une cryptographie de qualité inférieure comme norme IETF, pour faciliter l'espionnage.

Et une dernière règle, l'obligation de ne pas faire perdre son temps aux autres en travaillant sérieusement, en lisant les documents, et en n'oubliant pas de regarder l'historique d'une discussion avant de sauter dedans à pieds joints.

Et en cas de violation de ces règles ? Les témoins, signale l'annexe A du RFC, peuvent les signaler à l'IETF chair ou à l'IESG. L'annexe B décrit les conséquences qui peuvent s'ensuivre, par exemple le refus de laisser la parole à certaines personnes en raison de leur comportement (RFC 2418) ou la mise sur une liste noire des gens dont les messages aux listes de diffusion seront rejetés (RFC 3683 et RFC 3934).

Quels changements depuis le RFC 3184 ? Ils sont documentés dans l'annexe C. Pas de changements de fond, une phrase malheureuse demandant aux débutants de se taire et d'écouter a été retirée, le texte sur l'usage de l'anglais a été changé...

Je recommande la lecture de l'excellent exposé de Radia Perlman à l'IETF 53...


Téléchargez le RFC 7154


L'article seul

RFC 7153: IANA Registries for BGP Extended Communities

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : Eric C. Rosen (Cisco Systems), Yakov Rekhter (Juniper Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 14 mars 2014


Rien de dramatiquement nouveau dans ce RFC sur le protocole de routage BGP. Il s'agit juste d'une réorganisation des registres qui stockent les « communautés étendues », des attributs d'une annonce BGP. Les communautés étendues déjà enregistrées ne sont pas modifiées, les valeurs ne changent pas, le code continue à tourner comme avant, c'est juste la relation entre registres et les règles d'enregistrement qui sont clarifiées.

Ces communautés étendues sont normalisées dans le RFC 4360. Plus grandes que les anciennes communautés du RFC 1997, elles sont structurées en un type, parfois un sous-type et une valeur. (Rappel : il existe en ligne une liste des communautés des principaux opérateurs.) Le type indique entre autres si la communauté est transitive (si elle doit être transmise aux AS voisins) ou pas. S'il n'y a pas de sous-type, on parle de « types normaux » et, s'il y en a un, de « types étendus ». Types et sous-types sont mis dans un registre IANA. Les politiques d'allocation (cf. RFC 5226) varient, une partie de l'espace étant sous une politique restrictive (pour garantir qu'elle ne s'épuisera pas trop vite) et une autre sous une politique plus laxiste (pour faciliter la vie des utilisateurs). Par exemple, une communauté étendue qui commence par 0x0107 indique une propriété spécifique à un préfixe IPv4 (type 0x01), en l'occurence le Route ID / route type (sous-type 0x07) d'OSPF (cf. RFC 4577).

Les anciennes règles étaient spécifiées dans le RFC 4360 mais d'une manière qui s'est avérée trop confuse. D'où la réforme des registres (pas du protocole : les annonces BGP ne changent pas).

Donc, les nouveaux registres, tels que les décrit la section 2 de notre RFC :

Les registres des types doivent découper l'espace de nommage en trois, chaque partie ayant une politique d'allocation différente. De 0x00 à 0x3F, c'est du premier arrivé, premier servi. De 0x80 à 0x8F, réservé à un usage expérimental (depuis, le RFC 9184 a un peu grignoté cette plage). Et de 0x90 à 0xBF, il faut une norme. Pour les registres des sous-types, ce découpage est fait une fois pour toutes : de 0x00 à 0xBF (les sous-types sont codés sur un octet, cf. RFC 4360, section 3), la politique est « premier arrivé, premier servi » (très laxiste, donc, cf. RFC 5226), de 0xC0 à 0xFF, la politique « Examen par l'IETF » (très stricte, au contraire : il faut un RFC, et pas un RFC soumis individuellement). Rappelez-vous que tous les types n'ont pas de sous-types. Le fait d'avoir des sous-types est une propriété définie à la création du type (et indiquée dans le registre).

Un cas particulier est traité dans la section 3, celui des communautés étendues spécifiques pour les adresses IPv6. Créées par le RFC 5701, sur le modèle de communautés étendues spécifiques pour les adresses IPv4, elles n'ont en fait jamais été alignées, malgré la demande du RFC 5701 : les sous-types ne correspondent pas toujours. Notre RFC 7153 en prend donc acte et supprime cette demande d'alignement entre les sous-types IPv6 et les IPv4. Les deux registres pour IPv6 sont disponibles, un pour les transitifs et un pour les non-transitifs.

OK, et si je veux déclarer un type ou un sous-type et qu'il se retrouve dans ces beaux registres qui viennent d'être réorganisés, je fais quoi ? La section 4 décrit les procédures d'enregistrement. D'abord, le demandeur doit se poser la question « faut-il un nouveau type ou bien un sous-type d'un type existant peut-il suffire ? » Ensuite, s'il faut un type, doit-il être transitif ou pas ? (Certains types ont un sens dans les deux cas et doivent donc être ajoutés dans deux registres.) Et le type aura t-il des sous-types ? (Ce n'est pas obligatoire d'en avoir mais cela doit être mentionné dès le début.) Et, si oui, ces sous-types seront-ils dans un registre à part (c'est le cas de tous les types à sous-types aujourd'hui) ou bien réutiliseront-ils un registre de sous-types existant ?

Enfin, la section 5 du RFC contient la valeur actuelle des registres, qui sont désormais en ligne à l'IANA.


Téléchargez le RFC 7153


L'article seul

RFC 7151: File Transfer Protocol HOST Command for Virtual Hosts

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : P. Hethmon (Hethmon Brothers), R. McMurray (Microsoft)
Chemin des normes
Première rédaction de cet article le 12 mars 2014


On ne peut pas dire que le protocole de transfert de fichiers FTP soit encore très utilisé, largement concurrencé qu'il est par HTTP ou BitTorrent. Mais il existe encore de nombreuses ressources accessibles en FTP et de nombreux serveurs FTP donc l'IETF continue à améliorer le protocole. Cette nouvelle extension résout un problème : lorsque plusieurs noms pointent vers la même adresse IP et donc le même serveur FTP, ce serveur ne savait pas sous quel nom il avait été désigné à l'origine, et ne pouvait donc pas ajuster son comportement à ce nom. L'extension HOST résout ce problème en permettant au client FTP d'indiquer le nom original.

Cela se fait depuis longtemps pour HTTP (RFC 2616 qui a créé HTTP 1.1, remplaçant le HTTP 1.0 du RFC 1945) avec l'en-tête Host: envoyé dans la requête, qui permet le mécanisme de virtual hosting (plusieurs serveurs, ayant des comportements différents, sur la même adresse IP). Mais FTP n'avait pas encore l'équivalent. FTP est normalisé dans le RFC 959. Si vous ne connaissez pas ce protocole ou son histoire, je recommande le texte de Jason Scott. Traditionnellement, on n'accédait à un serveur FTP que par un seul nom, et les ressources (fichiers) disponibles ensuite étaient rangés dans des répertoires différents. Si le même serveur FTP anonyme hébergeait un miroir de FreeBSD et un autre de NetBSD, on pouvait créer deux noms, mettons ftp.freebsd.example et ftp.netbsd.example pointant vers la même adresse IP mais, comme la connexion ne se fait qu'avec les adresses IP (après que le logiciel client ait résolu le nom de domaine en adresse IP, grâce au DNS), le logiciel serveur FTP ne pouvait pas savoir le nom utilisé par le client. Résultat, le serveur devait présenter le même contenu, et l'utilisateur, qu'il soit fan de FreeBSD ou de NetBSD voyait à la racine les répertoires de deux systèmes (et probablement de bien d'autres). Un exemple avec l'excellent client ncftp sur un site miroir de FreeBSD :

% ncftp ftp.fr.freebsd.org
NcFTP 3.2.5 (Feb 02, 2011) by Mike Gleason (http://www.NcFTP.com/contact/).
Connecting to 158.255.96.2...                                                                                        
Welcome free.org FTP service
Logging in...                                                                                                        
Login successful.
Logged in to ftp.fr.freebsd.org.                                                                                     
ncftp / > ls
debian@   mirrors/  private/  pub/      stats/    ubuntu@

ncftp / > cd mirrors/
Directory successfully changed.
ncftp /mirrors > ls
archive.ubuntu.com/          ftp.freebsd.org/             releases.ubuntu-fr.org/
cdimage.debian.org/          ftp.ubuntu.com/              releases.ubuntu.com/
ftp.debian.org/              ftp.xubuntu.com/             videolan/

Il aurait quand même été plus pratique d'arriver directement dans mirrors/ftp.freebsd.org ! Le fait que le serveur ne connaisse pas le nom original a d'autres conséquences, comme de ne pas pouvoir utiliser des systèmes d'authentification différents selon le nom (accès FTP anonyme sur certains et pas sur d'autres, par exemple).

La section 3 du RFC décrit cette extension HOST. Elle a la forme d'une commande qui doit être envoyée au serveur avant l'authentification (rappelez-vous qu'un des buts de cette commande est d'avoir la possibilité d'authentifications différentes selon le serveur virtuel). Le serveur doit répondre par un code 220 si tout s'est bien passé. Le RFC recommande que le serveur n'envoie le message de bienvenue qu'après la commande HOST puisque cela lui permettrait d'adapter le message de bienvenue au nom utilisé. Voici un exemple, où « C> » indique un message envoyé par le client FTP et « S> » un message envoyé par le serveur FTP :

C> HOST ftp.example.com
S> 220 Host accepted

Et, en cas d'authentification :

C> HOST ftp.example.com
S> 220 Host accepted
C> USER foo
S> 331 Password required
C> PASS bar
S> 230 User logged in ftp.example.com

La commande HOST prend comme paramètre le nom de domaine qui a été utilisé par le client, après d'éventuelles normalisations comme l'ajout d'un suffixe (par contre, si c'est un alias dans le DNS, on utilise l'alias, pas le nom canonique). Si le nom est un IDN, c'est la forme Punycode qui doit être utilisée dans la commande HOST :

% logiciel-client ftp.café-crème.example
C> HOST ftp.xn--caf-crme-60ag.example
S> 220 Host accepted

Si l'utilisateur humain avait utilisé directement une adresse IP, c'est elle qu'on passe à la commande HOST :

C> HOST [2001:db8::c000:201]
S> 220 Host accepted

Ou bien :

C> HOST 192.0.2.1
S> 220 Host accepted (but you should use IPv6)

Par contre, le client ne doit pas indiquer le numéro de port, même lorsque c'était un port non-standard. En effet, le serveur le connait déjà, puisqu'il a cette information dans les données de connexion.

Que doit faire le serveur en recevant un HOST ? Il doit normalement vérifier que ce nom correspond bien à un des serveurs virtuels déclarés dans sa configuration. Sinon :

C> HOST ftp.example.net
S> 504 Unknown virtual host

(Le serveur peut, à la place, décider d'envoyer le client vers le serveur virtuel par défaut.) En cas de succès, le serveur peut ensuite s'adapter à ce nom : changer de répertoire par défaut, activer un autre méthode d'authentification, etc.

Mais que se passe t-il si l'utilisateur a un vieux client FTP qui n'envoie pas de HOST ? Là aussi, c'est au serveur de décider quoi faire dans ce cas (utiliser un serveur virtuel par défaut, refuser la connexion, etc). Et si c'est le serveur qui est vieux et qui ne connait pas HOST ? C'est alors le cas normal d'une commande inconnue (RFC 959, section 4.2) :

C> HOST ftp.example.com
S> 502 Unimplemented

Un peu plus compliqué, le cas où la session est protégée par TLS. Si le client utilise l'indication TLS du nom, normalisée dans l'extension server_name (RFC 6066), le serveur doit vérifier que le nom donné en paramètre à HOST est le même que celui de la session TLS.

Des questions de sécurité ? Comme indiqué plus haut, l'utilisation de la commande HOST peut faire changer de système d'authentification. Il est donc crucial que le serveur FTP sépare bien les serveurs virtuels pour éviter, par exemple, qu'on puisse se connecter sur un serveur virtuel avec les lettres de créance d'un autre. Idem lorsque le client authentifie le serveur avec les certificats du RFC 4217. Notre RFC rappelle également l'utilité des extensions d'authentification du RFC 2228 et l'intérêt de la (re)lecture du RFC 2577 sur la sécurité des serveurs FTP.

La nouvelle commande HOST est désormais officiellement enregistrée dans le registre IANA.

L'annexe A discute des autres choix qui auraient pu être faits mais qui ont finalement été rejetés. Une solution possible était d'étendre la commande déjà existante CWD (Change Working Directory) en lui donnant comme argument le nom du serveur virtuel. Cela permettrait ainsi d'avoir des sous-répertoires différents par serveur virtuel, comme c'est déjà souvent le cas (regardez l'exemple de ftp.fr.freebsd.org et de son répertoire mirrors/). Mais cela a des limites : CWD n'est accepté qu'après l'authentification et ne permet donc pas d'avoir des mécanismes d'authentification différents selon le serveur virtuel. Et ça manque de souplesse en forçant une certaines organisation des répertoires du serveur (ou bien en modifiant le code du serveur pour traiter cette première commande CWD différemment. Et ce n'est pas terrible du côté sécurité, un visiteur pouvant facilement voir tous les serveurs virtuels.

Une autre solution qui avait été suggérée était la commande ACCT qui permet de choisir un compte particulier, mais après l'authentification. Elle a donc un défaut en commun avec CWD, elle ne permet pas une authentification différente par serveur virtuel. (Ni d'utiliser des certificats différents, lorsqu'on utilise les extensions de sécurité des RFC 2228 et RFC 4217).

Et la commande USER ? Pourquoi ne pas l'étendre en ajoutant le serveur virtuel ?

C> USER foo@example.com
S> 331 Password required
C> PASS bar
S> 230 User logged in

Le problème est que certains environnements ont déjà des comptes utilisateurs comportant un @domaine, cas qu'on ne pourrait pas distinguer de celui où on indique un serveur virtuel. Et les extensions de sécurité de FTP mentionnées plus haut font la négociation de certificats avant le USER donc, là encore, on ne pourrait pas avoir des certificats différents selon le serveur virtuel.

Cette extension à FTP est ancienne (première proposition en 2007, apparemment), même si elle n'avait pas été formellement normalisée. Elle est incluse dans IIS comme documenté par un des auteurs du RFC, dans le serveur ncftpd, dans le serveur proftpd... Mais je n'ai pas testé ce que cela donnait en vrai (il faudrait déjà trouver un client qui le gère).


Téléchargez le RFC 7151


L'article seul

RFC 7149: Software-Defined Networking: A Perspective From Within A Service Provider

Date de publication du RFC : Mars 2014
Auteur(s) du RFC : M. Boucadair (France Telecom), C. Jacquenet (France Telecom)
Pour information
Première rédaction de cet article le 6 mars 2014


Ah, le SDN (Software-Defined Networking)... Un buzz word fort du moment, il est, chez les techniciens, l'équivalent de cloud chez les commerciaux... Le terme est tellement vague et mal défini qu'il peut désigner tout et n'importe quoi. Dans ce RFC, les deux auteurs explorent le concept, tentent une définition, et nous exposent leur analyse (plutôt critique) du SDN.

SDN désigne en général un ensemble de techniques (dont la plus connue est OpenFlow) permettant de gérer centralement un réseau, lorsque ce réseau est sous une autorité unique (contrairement à ce qu'on lit parfois, le SDN n'a donc pas vocation à être déployé sur l'Internet). L'idée est de ne plus confier aux seuls protocoles de routage la capacité de configurer les éléments du réseau, mais de définir une politique, de la configurer dans une machine centrale, et de l'appliquer ensuite aux éléments du réseau. On voit que, dans la définition la plus générale du SDN, si on remplace les employés qui se loguent sur les routeurs et les commutateurs pour les configurer par un logiciel du type de Ansible ou Puppet, on fait du SDN sans le savoir.

Ah, mais justement, quelle est la bonne définition de « SDN » ? Notre RFC 7149 commence par noter qu'il n'existe pas de définition rigoureuse unique (comme avec tous les buzz words). L'approche des auteurs est de partir des services réseaux (d'où le titre du RFC) puis de tenter une introduction à SDN. La section 1 du RFC se penche sur les problèmes du fournisseur de services, à partir de l'exemple du VPN. Fournir un service de VPN à ses clients nécessite l'activation de plein de capacités différentes : adressage et routage, bien sûr, mais aussi création des tunnels, qualité de service, filtrage pour la sécurité, et bien sûr tout ce qui est nécessaire à la supervision. La méthode traditionnelle, qui consiste à configurer manuellement (via la ligne de commandes ou via une interface graphique) un grand nombre de machines différentes (car ce n'est pas une seule machine qui va avoir toutes les capacités citées plus haut) est lente, coûteuse et l'erreur arrive vite. Il est évident qu'il faut automatiser, si on ne veut pas laisser le client attendre son VPN pendant des jours... pour qu'il découvre finalement qu'une des fonctions attendues ne marche pas suite à une légère erreur humaine. Donc, si vous voulez survivre dans le business du VPN, vous allez utiliser un programme pour configurer tout cela.

Bon, mais, d'abord, c'est quoi le SDN ? La section 2 du RFC se penche sur le problème de la définition. C'est évidemment difficile car le sigle a été usé et abusé par les marketeux. Par exemple, on définit parfois le SDN comme la séparation, dans les routeurs entre le système de contrôle (en général fait en logiciel sur un processeur généraliste) et le système de transmission (souvent fait par des circuits électroniques spécialisés donc considéré à tort comme n'étant pas du logiciel). Cette séparation offre plus de souplesse d'un côté et plus de performances de l'autre. Mais notre RFC pointe tout de suite que cette séparation est faite depuis de nombreuses années : si c'est là toute la nouveauté du SDN, cela ne vaut pas la peine. En fait, quand on dit « SDN », on ajoute souvent un point important à cette séparation : que le système de contrôle, au lieu d'être dans chaque routeur, vaguement coordonnés par un protocole de routage comme OSPF, soit centralisé, et standardisé pour que le contrôleur et le contrôlé puissent être achetés à des fournisseurs différents. Dans cette définition du SDN, les routeurs et autres équipements réseaux sont « bêtes », juste capables de transmettre les paquets, et un contrôleur « intelligent » fait tous les calculs avant de transmettre des ordres simples aux routeurs. (On parle de PDP - Policy Decision Point - pour le contrôleur et de PEP - Policy Enforcement Point - pour les équipements réseau.)

L'argument en général donné par les pro-SDN est celui de la flexibilité. Lorsque de nouvelles exigences apparaissent, par exemple pour offrir un nouveau service aux clients, on change juste le logiciel du contrôleur et tout le reste du réseau suit gentiment. À noter que cela va au delà du routage : il faut aussi pouvoir transmettre aux clients des ordres portant sur la réservation de capacité réseau, par exemple. (Les solutions commerciales qui se disent « SDN » se vantent toutes de leur flexibilité, sans toujours préciser qu'est-ce qui est flexible et qu'est-ce qui est fixé.)

À noter que ces calculs dans le contrôleur supposent que celui-ci dispose d'un bon modèle du réseau. Puisque les équipements réseau vont lui obéir aveuglément, il ne faut pas qu'il transmette des ordres qui mènent à, par exemple, une congestion du réseau. Pour cela, il doit donc connaître les détails du réseau, de façon à être capable de prédire les conséquences de ces actions (ou de façon à pouvoir dire à l'administrateur réseaux « désolé, Dave, ce que tu me demandes est impossible »). Cela peut nécessiter le développement de meilleurs émulateurs de réseau, pour pouvoir tester les conséquences d'un ordre avant de l'envoyer.

Armés de ces précautions, les auteurs du RFC définissent donc le SDN comme « l'ensemble des techniques utilisées pour :

  • faciliter l’ingénierie,
  • améliorer le temps de production,
  • simplifier l’exploitation de services réseau d’une manière déterministe, dynamique et capable d’être déployée à grande échelle.

 ». On note qu'ils n'insistent pas sur le côté « logiciel » (le S de SDN), les mécanismes réseau étant par essence à base de logiciels.

Ce beau programme nécessite des techniques pour :

  • Découvrir la topologie du réseau (on ne peut pas commander un réseau qu'on ne connait pas), les capacités des équipements actifs, et comment les configurer,
  • Donner des ordres aux équipements réseau,
  • Avoir un retour sur l'exécution des ordres donnés, et sur leurs résultats.

OK, c'est très joli mais est-ce réaliste ? La section 3 se le demande. Un écosystème comme l'Internet est l'un des objets les plus complexes jamais conçus par l'humanité (et il existe des tas de réseaux qui, sans être aussi gros que l'Internet, sont d'une taille et d'une complexité redoutables). Les exigences des utilisateurs sont innombrables et souvent difficiles à concilier (résilience, y compris face aux attaques délibérées, performances, flexibilité, rapidité de déploiement des changements...) Le RFC suggère donc une certaine modestie. D'abord, se souvenir du passé. On l'a vu, les promesses du SDN étaient souvent plus ancrées dans le verbiage commercial que dans la réalité. Quand elles faisaient référence à quelque chose de concret, c'était parfois quelque chose qui existait depuis longtemps mais qui avait été rebaptisé « SDN » (qui se souvient des vieux slogans commerciaux comme « Active Networks » ou « Programmable Networks » ?) C'est ainsi que les NMS ou le PCE (RFC 4655) ont parfois été enrôlés contre leur gré sous la bannière « SDN ». Pour la séparation du système de contrôle et du système de transmission, on peut aussi citer le routage via le DNS (RFC 1383) ou évidemment ForCES (RFC 5810).

Autre suggestion de modestie, être pragmatique. Le SDN doit être utilisé s'il aide, pas juste pour le plaisir de faire des exposés à NANOG. Par exemple, la centralisation du contrôle ne doit pas conduire à diminuer la résilience du réseau en en faisant un SPOF. Si le contrôleur est en panne ou injoignable, il faut que les équipements réseau puissent au moins continuer à assurer leurs tâches de base (bien sûr, les contrôleurs sont redondés mais cela ne suffit pas dans tous les cas). Autre exemple de pragmatisme, il faut mesurer le réseau et s'assurer qu'on a réellement obtenu le résultat voulu.

D'autant plus que rien n'est gratuit dans ce monde cruel. La souplesse et la réactivité que fournissent les possibilités de configuration des équipements ont un coût, par exemple en rendant plus difficile, si on utilise des interfaces standard, d'optimiser les performances, puisqu'on ne pourra pas forcément toucher aux fonctions les plus spécifiques du matériel.

Lorsqu'on dit « SDN », on pense souvent immédiatement à OpenFlow, la plus connue des techniques vendues sous ce nom. Mais le SDN ne se réduit pas à OpenFlow et bien d'autres protocoles peuvent être utilisés pour de la configuration à distance (de PCEP - RFC 5440 - à NETCONFRFC 6241 en passant par COPS-PRRFC 3084 - ou RPSLRFC 2622). OpenFlow n'est donc qu'un composant possible d'une boîte à outils plus large.

Enfin, lorsqu'on fait une analyse technique d'un mécanisme, il est important de voir quels sont les « non-objectifs », les choses qu'on n'essaiera même pas d'atteindre (dans le discours commercial, il n'y a pas de non-objectifs, la solution proposée est miraculeuse, guérit le cancer systématiquement et fait toujours le café) :

  • La flexibilité rencontrera toujours des limites, ne serait-ce que les capacités du matériel (aucune quantité de SDN ne permettra à un routeur d'aller plus vite que ce que lui permettent ses interfaces réseaux et ses ASIC),
  • La modularité et la programmabilité se heurteront aux limites du logiciel, comme la nécessité de tests (le software est nettement moins soft que ne s'imaginent les décideurs),
  • Le contrôle absolu depuis un point central est très tentant pour certains mais il se heurte aux problèmes de passage à l'échelle et à la nécessité que les équipements aient assez d'autonomie pour gérer les déconnexions temporaires.

La section 4 du RFC discute ensuite plus en détail certains problèmes qu'on rencontre sur la route du SDN. Premier problème cité, toute automatisation d'un processus est vulnérable aux bogues dans le logiciel : c'est par exemple le syndrome du « robot fou » qui, ne se rendant pas compte que ses actions mènent à des catastrophes, les continue aveuglément (deux exemples, un avec Ansible et un avec Flowspec). Autre difficulté qui ne disparaitra pas facilement, l'amorçage du SDN : la première fois qu'on le met en place, les équipements et le contrôleur ne se connaissent pas et doivent apprendre leurs capacités. (Et utiliser le réseau pour configurer le réseau soulève plein de problèmes intéressants...)

Gérer un réseau, ce n'est pas seulement le configurer et faire en sorte qu'il démarre. Il faut aussi assurer le débogage, la maintenance, les statistiques, la détection (et la correction) de problèmes, tout ce qui est désigné sous le sigle OAM (Operations And Management, cf. RFC 6291). Le SDN doit prendre cela en compte.

On l'a vu, un des principes du SDN est la concentration de l'« intelligence » en un point central, le PDP (Policy Decision Point, là où on configure les services attendus). Cela pose des problèmes pour la résilience du réseau ou tout simplement pour son passage à l'échelle. Un mécanisme permettant d'avoir plusieurs PDP synchronisés semble donc nécessaire. En parlant de passage à l'échelle, le RFC signale aussi que certaines promesses du SDN vont être difficiles à tenir. Par exemple, avoir des machines virtuelles ayant des politiques de QoS différentes, et migrant librement d'un data center à l'autre est faisable en laboratoire mais ne va pas passer à l'échelle facilement.

Enfin, il ne faut pas oublier les risques, souvent négligés lors de la présentation d'une belle technologie qui brille. Le contrôleur va devenir le point faible du réseau, par exemple. Et la sécurité du SDN n'a pas encore été tellement mise à l'épreuve (section 6 du RFC).

Merci à Mohamed Boucadair et Christian Jacquenet pour leur relecture.


Téléchargez le RFC 7149


L'article seul

RFC 7143: iSCSI Protocol (Consolidated)

Date de publication du RFC : Avril 2014
Auteur(s) du RFC : Mallikarjun Chadalapaka (Microsoft), Julian Satran (Infinidat), Kalman Meth (IBM), David Black (EMC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF storm
Première rédaction de cet article le 5 avril 2014


Le protocole iSCSI permet à une machine d'accéder à des disques (ou autres dispositifs de stockage) situés en dehors, loin de l'atteinte des bus internes de la machine. iSCSI consiste à faire passer les traditionnelles requêtes SCSI sur IP, autorisant ainsi l'utilisation de tous les équipements réseaux qui font passer de l'IP, et dispensant ainsi d'acheter des équipements spécialisés dans les SAN, comme le très coûteux Fibre Channel. iSCSI était à l'origine normalisé dans plusieurs RFC, que ce nouveau document rassemble en une seule (très) grosse spécification.

Résultat, le RFC faisant autorité pour iSCSI est un document de 344 pages, un record ! Il remplace les anciennes normes, les RFC 3720, RFC 3980, RFC 4850 et RFC 5048.

Si jamais vous envisagez de lire le RFC entier, je vous souhaite bon courage. Si vous voulez juste apprendre deux ou trois choses sur iSCSI, révisez d'abord un peu SCSI (les section 2.1 et 2.2 du RFC détaillent la terminologie, la 4.1 les concepts) : c'est un protocole client/serveur où le client (typiquement un ordinateur) se nomme l'initiateur et le serveur (typiquement un disque) la cible. L'initiateur envoie des commandes à la cible, qui répond. Le transport des commandes et des réponses peut se faire sur bien des supports, entre autres SAS, Parallel SCSI et FireWire. Ces supports traditionnels de SCSI ont généralement des faibles portées. iSCSI, au contraire, met les commandes et les réponses sur TCP, donc IP, et les cibles peuvent être à n'importe quelle distance de l'initiateur (même si, en pratique, initiateurs et cibles seront souvent dans le même réseau local).

SCSI peut aussi être utilisé pour parler à des lecteurs de bande, à des DVD, mais aussi, autrefois, à des imprimantes ou des scanners. Chaque dispositif d'entrée/sortie SCSI se nomme un LU (Logical Unit). Une même cible peut comporter plusieurs LU, chacun ayant un numéro, le LUN (Logical Unit Number).

Les commandes sont regroupées en tâches. Chaque tâche est séquentielle (une commande après l'autre) mais un initiateur et une cible peuvent avoir plusieurs tâches en cours d'exécution parallèle.

Les données peuvent évidemment voyager dans les deux sens : si un ordinateur écrit sur un disque, l'initiateur (l'ordinateur) envoie des données à la cible (le disque). Si l'ordinateur lit un fichier, ce sera le contraire, les données iront de la cible vers l'initiateur. Le sens de voyage des données est toujours exprimé du point de vue de l'initiateur. Donc, du « trafic entrant » désigne des données allant de la cible vers l'initiateur (une lecture sur le disque, par exemple).

iSCSI consiste à envoyer les messages SCSI, baptisés PDU (pour Protocol data unit), sur TCP (port 3260 ou à la rigueur 860). Contrairement à ce qui se passe pour d'autres protocoles (comme SIP), données et commandes voyagent dans les mêmes connexions TCP. Pour diverses raisons, il peut y avoir plusieurs connexions TCP actives entre l'initiateur et la cible. On les appelle collectivement la session (équivalent du nexus en SCSI classique). Chaque session a son propre identificateur et chaque connexion TCP de la session a un identificateur de connexion. Des connexions TCP peuvent être ajoutées ou retirées en cours de session, augmentant ainsi la résilience.

La réponse à une commande donnée doit être envoyée sur la même connexion TCP que celle où la commande avait été reçue (« allégeance à la connexion »). Ainsi, si un initiateur demande une lecture de données, celles-ci arriveront sur la même connexion.

L'ordre des commandes est parfois essentiel en SCSI. Pour cela, elles sont numérotées (Command Sequence Number, et cette numérotation est valable globalement pour toute la session), afin que la cible les exécute dans l'ordre. Il existe aussi d'autres numéros (Status Sequence Number) qui ne servent que dans une connexion TCP donnée et sont plutôt utiliser en cas d'erreurs, pour associer un message d'erreur à une commande précise. (Le RFC 3783 décrit avec bien plus de détails le concept d'ordre dans iSCSI.)

À noter que les réponses aux commandes, en SCSI (et donc en iSCSI), ne respectent typiquement aucun ordre. Si une cible exécute la commande A puis la commande B, la réponse à B pourra arriver à l'initiateur avant la réponse à A (ce qui est logique, les opérations d'entrée/sortie pouvant avoir des durées très variables ; la commande B était peut-être très rapide à exécuter).

Les données, elles, ont un ordre. Si on lit 10 000 octets, on veut évidemment recevoir le premier octet des données en premier. D'où le Data Sequence Number qui se trouve dans les paquets de données et qui indique où se trouvent ces données dans le flux transmis.

Un autre point important : TCP fournit un service de flot d'octets continu. Il n'y a pas de séparation entre les PDU (les messages) iSCSI. Pour que le destinataire puisse donc savoir où se termine le PDU (et où commence le suivant), ceux-ci sont préfixés par leur longueur (comme dans beaucoup d'autres protocoles utilisant TCP, par exemple dans EPP et dans le DNS).

Les données peuvent être sensibles (confidentielles, par exemple) et iSCSI doit donc prévoir des mécanismes d'authentification. Ainsi, au début d'une session, l'initiateur se présente et prouve son identité. La cible doit aussi prouver qu'elle est bien la cible visée (authentification mutuelle). Il existe plusieurs mécanismes pour cela, décrits en détail en sections 6 et 12. La recommandation de ce RFC est de protéger les sessions avec IPsec (cf. section 9, ainsi que le RFC 3723).

Au fait, comme toujours en réseau, il faut des identificateurs pour désigner cibles et initiateurs. En iSCSI, il sont appelés noms. Contrairement au SCSI classique où les identificateurs n'ont besoin d'être uniques qu'à l'interieur d'un domaine très restreint (souvent un seul boîtier, parfois une salle machines), iSCSI permet de faire parler des machines situées sur l'Internet et les noms doivent donc être mondialement uniques. (Pour une vue générale du nommage en iSCSI, voir le RFC 3721.) En outre, ces noms doivent (section 4.2.7.1) être stables sur le long terme, ne pas être dépendant de la localisation physique des machines, ni même du réseau où elles sont connectées, et le système de nommage doit être un système déjà existant : pas question de réinventer la roue ! À noter que ce sont des principes analogues à ceux des URN du RFC 1737. Les noms doivent en outre pouvoir être écrits en Unicode, canonicalisés par le profil stringprep de iSCSI, spécifié dans le RFC 3722, puis encodés en UTF-8, forme normale C.

iSCSI fournit trois formats pour atteindre ces objectifs. Un nom commence par un type indiquant quel format est utilisé, puis comprend le nom proprement dit. Les trois types sont :

  • Nom de domaine, type iqn. Comme ceux-ci ne sont pas forcément stables sur le long terme (pour des raisons juridico-politiques, pas pour des raisons techniques), le format iSCSI ajoute une date indiquant un moment où le titulaire avait effectivement ce nom. C'est le même principe que les URI tag: du RFC 4151. Un nom valide comporte le nom de domaine (écrit à l'envers) et donc, on peut voir, par exemple, iqn.2001-04.com.example:storage:diskarrays-sn-a8675309, attribué par le titulaire de example.com.
  • NAA (Network Address Authority), type naa, un système spécifique au monde Fibre Channel. Un exemple de nom NAA est naa.52004567BA64678D.
  • EUI, type eui. un format de l'IEEE permettant de donner des noms uniques aux machines. Par exemple, un nom iSCSI EUI peut être eui.02004567A425678D.

Il existe également des mécanismes de découverte des noms accessibles, décrits dans les RFC 3721 et RFC 4171. Notre RFC note que, malheureusement, certains de ces mécanismes dépendent de SLP (protocole décrit dans le RFC 2608) qui n'a jamais vraiment été implémenté et déployé.

Attention, ce RFC 7143 ne décrit que le transport de SCSI sur IP (en fait, sur TCP). SCSI, lui, reste décrit par ses normes originales (qui ne semblent plus accessibles en ligne). Pour décrire le modèle, elles se servent d'UML, une technique qu'on trouve rarement dans un RFC, d'autant plus qu'elle repose sur de jolis dessins, qu'on ne peut pas facilement reproduire dans un RFC, avec leurs règles de formatage actuelles. Ce RFC comporte donc des diagrammes UML... en art ASCII (section 3).

iSCSI est décrit par une machine à nombre fini d'états et ladite machine figure en section 8.

Évidemment, les disques durs peuvent tomber en panne ou bien le réseau entre l'initiateur et la cible partir en vacances. Il faut donc prévoir des mécanismes de gestion des erreurs, et ils font l'objet de la section 7. C'est ainsi que, par exemple, une tâche qui échoue sur une connexion TCP peut être reprise sur une autre (qui peut passer par un chemin réseau différent). Notez que cette norme n'impose pas aux acteurs iSCSI de tous mettre en œuvre des techniques sophistiquées de récupération d'erreurs, juste de réagir proprement lorsque les erreurs se produisent. La section 7 est très détaillée : après tout, on ne veut pas perdre ses précieuses données juste parce que l'Internet a eu un hoquet pendant une opération d'écriture en iSCSI.

Mais comment détecte-t-on un problème sur une connexion TCP ? Cela peut être un message ICMP qui coupe la connexion mais aussi une absence prolongée de réponse à une commande, ou bien à un test iSCSI (la commande NOP, équivalente du ping IP) ou TCP (les keep-alives du RFC 1122, section 4.2.3.6).

Les pannes, c'est ennuyeux, mais les piratages, c'est pire. On ne veut pas qu'un méchant situé sur le trajet puisse lire nos données secrètes ou modifier ce qu'on écrit sur le disque. En SCSI traditionnel, une grande partie de la sécurité est physique : initiateur et cible sont dans le même boîtier (celui du serveur) ou à la rigueur dans la même armoire avec juste un SAN entre les deux. En iSCSI, on perd cette sécurité physique. Si l'initiateur et la cible sont connectés par le grand Internet, tout peut arriver sur le chemin. La section 9, « Security Considerations », fait donc le tour des menaces et des contre-mesures. (À quoi il faut ajouter le RFC 3723.)

iSCSI peut être utilisé sans sécurité, comme l'ancien SCSI, si on est parfaitement sûr de la sécurité physique. Mais notre RFC déconseille de courir ce risque. iSCSI fournit deux mécanismes de sécurité et le RFC demande qu'on les utilise. Le premier est interne à iSCSI, c'est l'authentification réciproque des deux parties lors de l'établissement de la session. Le deuxième est externe, et c'est IPsec. Ces deux mécanismes doivent être mis en œuvre (même s'ils ne seront pas forcément activés par l'administrateur système, notamment pour IPsec, complexe et pas forcément utile si tout le monde est dans la même salle machines).

À noter qu'une limite d'IPsec est que les systèmes d'exploitation typiques ne permettent pas à une application de savoir si ses connexions sont protégées ou non par IPsec. Ainsi, une application qui voudrait faire une authentification par mot de passe en clair uniquement si la connexion est chiffrée ne peut pas être sûre et doit donc supposer le pire (une connexion non chiffrée). L'authentification interne ne doit donc jamais utiliser de mot de passe en clair. La méthode recommandée est CHAP (RFC 1994, mais avec quelques ajouts). Dans le futur, un mécanisme comme celui du RFC 5433 ou comme SRPRFC 2945 - sera peut-être utilisé.

Le mécanisme interne n'assure que l'authentification réciproque. Il ne protège pas contre l'écoute, ni même contre la modification des messages en cours de route. Il ne doit donc être utilisé seul que si on est sûr que ces écoutes et ces modifications sont impossibles (par exemple si on a une bonne sécurité physique du réseau). Imaginez les conséquences d'une modification des données avant leur écriture sur le disque !

IPsec dans iSCSI doit suivre le RFC 3723 et le tout récent RFC 7146. Avec IPsec, les sessions iSCSI peuvent garantir la confidentialité et l'intégrité des données. À noter que les numéros de séquence IPsec ne sont par défaut que sur 32 bits. iSCSI verra probablement des débits élevés (par exemple plusieurs Gb/s) et ce numéro sera donc vite arrivé au bout. Le RFC demande donc les numéros de séquence étendus (64 bits) de la section 2.2.1 du RFC 4303.

Les programmeurs tireront profit de la section 10, qui rassemble des conseils utiles pour mettre en œuvre iSCSI sans se planter. Un des enjeux de iSCSI est la performance, vu les grandes quantités de données à traiter... et l'impatience des clients. Le protocole a été soigneusement conçu pour permettre d'éventuelles implémentations directement dans le matériel, et pour permettre le DDP (Direct Data Placement, RFC 5041). Ainsi, on peut mettre iSCSI dans le firmware, permettant le démarrage sur une cible iSCSI.

Parmi les points notés par cette section, la gestion des machines dotées de plusieurs cartes réseau (on peut en utiliser plusieurs pour la même session iSCSI), le délicat choix des délais d'attente maximaux (non normalisés, car dépendant de l'infrastructure, notamment matérielle), et l'ordre des commandes (une commande qui change l'état de la cible, par exemple un vidage - flush - des tampons, ne doit pas être envoyée comme commande immédiate, pour éviter qu'elle ne double d'autres commandes).

La section 11 décrit le format exact des PDU sur le câble. Si vous le désirez, on trouve des traces iSCSI sur pcapr.

Il existe de nombreuses mises en œuvre d'iSCSI et des programmeurs de nombreuses entreprises (Dell, EMC, Microsoft, NetApp, Red Hat, VMware, etc) ont participé à la création de ce RFC. Une liste partielle de mises en œuvre :

À part le gros changement éditorial (consolider plusieurs RFC en un seul), les changements de iSCSI dans ce RFC sont peu nombreux. Par exemple, une stricte prohibition des caractères de ponctuation dans les noms SCSI est devenue une forte mise en garde. La section 2.3 liste toutes les modifications.

Merci à Bertrand Petit pour sa relecture attentive.


Téléchargez le RFC 7143


L'article seul

RFC 7142: Reclassification of RFC 1142 to Historic

Date de publication du RFC : Février 2014
Auteur(s) du RFC : M. Shand, L. Ginsberg (Cisco Systems)
Pour information
Réalisé dans le cadre du groupe de travail IETF isis
Première rédaction de cet article le 26 février 2014


Voilà ce qui arrive lorsqu'un protocole est normalisé par deux organisations à la fois... Il existe depuis longtemps un doute sur le RFC 1142, censé décrire le protocole de routage IS-IS. Est-ce bien la norme de référence ? Non, dit notre nouveau RFC 7142. La norme de référence est à l'ISO et le RFC 1142, plus à jour, ne doit pas être utilisé.

IS-IS est en effet normalisé par l'ISO sous le numéro ISO/IEC 10589:2002. L'ISO, vieux dinosaure bureaucratique, n'a pas encore été informée de l'existence de l'Internet et ne distribue donc la plupart de ses normes que sous forme papier (IS-IS, on le verra, est une exception). Le RFC 1142 avait été prévu à l'origine pour être une reprise de la norme ISO 10589, distribuée librement et donc plus accessible. Mais IS-IS a évolué pendant ce temps, et le RFC 1142 n'a pas bougé, devenant de plus en plus décalé par rapport à la norme ISO officielle. (À noter aussi le RFC 1195, qui adapte IS-IS à IP.) Mettre à jour le RFC 1142 semble impossible pour des raisons de propriété intellectuelle à l'ISO.

Notre RFC 7142 prend donc acte de ce décalage et reclassifie le RFC 1142 comme « d'intérêt historique seulement ». Si vous voulez lire la norme officielle sur IS-IS, il faut aller à l'ISO.

À noter qu'il existe un autre protocole de routage interne, OSPF et que lui est normalisé dans des documents librement accessibles (RFC 2328 pour la v2 ou bien RFC 5340 et RFC 5838 pour la v3, moins déployée aujourd'hui).


Téléchargez le RFC 7142


L'article seul

RFC 7141: Byte and Packet Congestion Notification

Date de publication du RFC : Février 2014
Auteur(s) du RFC : B. Briscoe (BT), J. Manner (Aalto University)
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 27 février 2014


Lorsqu'un routeur de l'Internet doit stocker des paquets en attente d'envoi au routeur suivant, et que la file d'attente est pleine ou menace de l'être, que doit-il faire ? Il y a très longtemps, le routeur attendait le remplissage de la file et jetait les paquets arrivés ensuite (on appelle cette « méthode » le drop-tail). De nos jours, les routeurs ont en général une approche plus « intelligente », souvent nommée AQM (Active Queue Management) qui consiste à utiliser divers algorithmes pour mieux réagir à cette situation, et limiter ainsi les risques de congestion. Il existe de nombreux algorithmes d'AQM comme, par exemple, RED (la section 1.1 en donne une liste : le RFC utilise en général RED comme exemple). Ce nouveau RFC ne décrit pas encore un algorithme de plus mais expose trois bonnes pratiques qui devraient être suivies par tous les algorithmes d'AQM :

  • Les protocoles de transport devraient tenir compte de la taille des paquets, lorsqu'ils réagissent à des signaux indiquant l'arrivée de la congestion,
  • Par contre, les routeurs ne devraient pas tenir compte de cette taille lorsqu'ils décident d'agir parce que les tuyaux se remplissent,
  • Dans le cas spécifique de l'algorithme RED, son mode « octet », qui privilégie les petits paquets en cas de congestion, ne devrait pas être utilisé (contrairement à ce que recommandait le RFC 2309, section 3, RFC depuis remplacé par le RFC 7567).

À noter que les actions prises par les routeurs lorsqu'ils détectent l'approche de la congestion sont variées : autrefois, il n'y en avait qu'une, laisser tomber des paquets mais, aujourd'hui, un routeur peut faire d'autres choix comme de marquer les paquets (ECNRFC 3168 ou PCN - RFC 5670).

Le problème de la prise en compte (ou pas) de la taille des paquets lorsqu'on détecte ou réagit à la congestion a occupé les chercheurs depuis de nombreuses années. Les mécanisme pré-AQM, genre drop-tail (lorque la file d'attente est pleine, on jette les messages qui arrivent, ceux qui auraient normalement été mis à la fin de la file), traitaient tous les paquets pareils. Or, il y a des gros et des petits paquets et, en prime, les ressources réseau peuvent être pleines en nombre d'octets (bit-congestible, maximum de b/s atteinte, la limite importante pour les réseaux lents, genre radio) ou en nombre de paquets (packet-congestible, maximum de paquets/s atteint, un indicateur beaucoup moins cité que le précédent mais souvent crucial, par exemple pour la fonction de recherche d'une route dans un routeur). À l'époque, on ne se posait pas trop de questions. Aujourd'hui, on se demande :

  • Lorsqu'on mesure la congestion, faut-il mesurer la longueur de la file d'attente en octets, en paquets (rappelez-vous qu'il y a des gros et des petits paquets, donc cela ne donnera pas le même résultat que l'indicateur précédent) ou en temps d'attente ? Le consensus actuel est que le mieux est de compter en temps d'attente mais, si cela n'est pas possible, de compter avec l'indicateur pour lequel le réseau est effectivement limité.
  • Lorsqu'un routeur a détecté et signale la congestion (en marquant ou en jetant des paquets), doit-il tenir compte de la taille des paquets, et, par exemple, jeter/marquer préférentiellement les gros ? Il y avait nettement moins de consensus sur cette question, que notre RFC tranche en disant que, non, le routeur devrait ignorer la taille des paquets. Avant ce RFC, les discussions qui avaient mené au RFC 2309 (et qui n'ont pas forcément été documentées dans le RFC 2309, voir ce résumé) recommandaient de marquer/jeter en fonction du nombre d'octets et donc de privilégier les petits paquets. Cela épargnait les importants paquets de contrôle (qui sont en général petits). L'une des raisons du changement de stratégie est que ce n'est pas au routeur de se préoccuper du débit de TCP, ce devrait être à TCP de gérer cela (RFC 2914).
  • Lorsque les protocoles de transport comme TCP agissent lorsqu'ils voient un signal de congestion, doivent-ils tenir compte de la taille des paquets ? Il y avait nettement moins de consensus sur cette question, que notre RFC tranche en disant que, oui, TCP devrait prendre en compte la taille des paquets (contrairement au routeur).

L'algorithme RED, tel que décrit dans le RFC 2309, a deux modes, nommés packet mode et byte mode et le second a un effet pervers, encourager les protocoles des couches supérieures à utiliser des petits paquets, qui ont moins de chances d'être jetés. (Notre RFC note que ce mode ne semble heureusement plus utilisé aujourd'hui.) La section 1.2 contient un tableau qui indique la différence de comportement pour deux flots de 48 Mb/s, un comportant uniquement des paquets de 60 octets (donc 100 kp/s) et un autre des paquets de 1 500 octets (donc 4 kp/s). En mode paquet (probabilité de perte de paquet constante), RED maintient le débit (certes, il dégomme davantage de petits paquets mais ceux-ci transportent moins). En mode octet (probabilité de perte d'un octet constante), le débit diminue davantage pour le flot ayant les gros paquets.

TCP, aujourd'hui, ne tient typiquement pas compte de la taille des paquets lorsqu'il prend des décisions comme de diminuer la taille de la fenêtre. En pratique, cela n'a jamais été un problème car, dans une connexion TCP donnée, tous les paquets dans une direction donnée ont la même taille. Mais, dans le futur, cela pourra changer et il est donc utile de rappeler aux auteurs de mises en œuvre de TCP qu'il est au contraire recommandé de considérer la congestion comme plus sérieuse lorsque des gros paquets sont perdus.

Est-ce que le système est limité en nombre de paquets/s (packet-congestible) ou en nombre de bits/s (bit-congestible) ? Tout réseau comporte des composants des deux types. Par exemple, si une machine a des tampons d'entrée-sortie de taille variable, ces tampons seront une ressource bit-congestible (trop de bits et toute la mémoire sera utilisée). S'ils sont de taille fixe, on sera plutôt packet-congestible. Si tout est bien conçu, les deux limites devraient être approchées à peu près en même temps. En pratique, les ressources Internet sont en général actuellement limitées en bits/s (cf. RFC 6077, section 3.3). Il y a aussi des cas plus complexes par exemple un pare-feux à état qui serait limité en nombre de flots simultanés gérés et serait donc flow-congestible.

La section 2 du RFC reprend les recommandations concrètes résumées plus tôt. (Elles sont à nouveau résumés dans la section 7 donc, si vous êtes pressés, vous pouvez vous contenter de lire cette section 7, qui est la conclusion du RFC.) D'abord, la mesure de la taille de la file d'attente. On l'a vu, l'idéal est lorsque cette mesure se fait en secondes (le temps que passera le paquet dans la file, qui peut être élevé en raison du bufferbloat). Mais on ne peut mesurer de manière exacte ce temps que lorsque le paquet quitte la file d'attente, ce qui est trop tard. Donc, en pratique, on mesure en général la file en octets ou en paquets. La première méthode est meilleure si la file d'attente mène à une ressource bit-congestible, la seconde est meilleure si la ressource en aval est packet-congestible. Ainsi, une file d'attente menant à un lien réseau typique se mesurera en octets, une file d'attente menant au moteur de filtrage d'un pare-feu se mesurera plutôt en paquets. Traduit en vocabulaire RED, cela veut dire de choisir le mode octet pour les mesures. Et le RFC déconseille de rendre ce choix configurable, car le fait d'être bit-congestible ou packet-congestible est une propriété inhérente à la file d'attente, et ne dépend pas des opinions de l'administrateur système.

Ensuite, la notification de la congestion. Qu'elle se fasse par la méthode traditionnelle d'IP (jeter le paquet) ou bien par les méthodes plus douces comme l'ECN, elle ne devrait pas dépendre de la taille du paquet. Traduit en langage RED, cela veut dire d'utiliser le mode paquet pour la notification de la congestion (alors que le RFC recommandait l'autre mode, le mode octet, pour la mesure de la file d'attente, attention à ne pas mélanger les deux). Le but principal est de ne pas encourager les flots à multiplier les petits paquets. L'étude des implémentations publiée dans l'annexe A indique que tout le monde fait déjà comme cela, donc le RFC ne fait que documenter l'existant.

Et il reste le cas de la réaction à la congestion. Des paquets manquent, ou bien arrivent avec un bit ECN. Que doivent faire TCP ou les autres protocoles de transport ? Ils devraient considérer l'« intensité » de la congestion comme étant proportionnelle à la taille des paquets. Comme si l'indication de la congestion portait sur chaque octet du paquet. Notez que le RFC ne dit pas ce que TCP doit faire mais comment il doit aborder le diagnostic. Ensuite, les actions éventuelles doivent être prises par TCP, pas par le réseau. Si, par exemple, on souhaite que deux flots TCP utilisant des paquets de taille différentes doivent tourner au même débit (mesuré en b/s), c'est TCP qui doit s'en occuper, et ne pas compter que le réseau ajustera les pertes de paquets pour cela. Même chose pour les paquets de contrôle (un paquet SYN par exemple).

C'est bon ? Vous avez bien compris ce que le RFC recommandait ? Alors, maintenant, pourquoi ? C'est le rôle de la section 3 que de justifier ces recommandations. D'abord, comme indiquer plus haut, ne pas donner des raisons à une implémentation de privilégier les petits paquets. Comme noté dans le RFC 3426 (ou le papier de Gibbens et Kelly), toujours penser aux effets pervers des bonnes intentions. Favoriser les paquets de petite taille peut sembler raisonnable, mais cela encourage les protocoles de transport à réduire la taille des paquets, donc à augmenter la charge des routeurs. Pire, cela ouvre une voie à certaines attaques par déni de service (en envoyant beaucoup de petits paquets, on peut empêcher les gros de passer).

Ensuite, une des motivations pour l'ancienne recommandation de privilégier les petits paquets venait du fait que les paquets de contrôle (qu'il faut essayer de favoriser) sont en général petits (c'est le cas des paquets TCP SYN et ACK mais aussi des paquets de certaines applications par exemple les requêtes DNS et même les GET HTTP). Mais l'inverse n'est pas vrai, un petit paquet pouvant n'avoir pas de rôle dans le contrôle. Là encore, favoriser aveuglément tous les petits paquets encouragerait les protocoles des couches supérieures à tout découper en petits paquets, ce qui n'est pas le but recherché.

Une autre raison de donner la priorité aux petits paquets était d'égaliser le débit de deux flots TCP qui enverraient les données dans des segments de taille différente (pour deux flots, TCP maintient le même nombre de segments donc on a plus de débit avec des segments plus grands). Mais, même si on estime ce but souhaitable, il ne devrait pas être réalisé dans les routeurs, qui ne connaissent pas forcément le protocole de transport utilisé (même entre deux TCP, les résultats d'un paquet perdu vont dépendre de l'algorithme utilisé, par exemple NewRenoRFC 5681 - vs. Cubic), mais dans les protocoles de transport, qui peuvent toujours ajuster leur politique comme ils veulent.

Il ne faut pas oublier non plus que le déploiement d'AQM est incomplet : certains routeurs font de l'AQM, d'autres pas. Les protocoles de transport doivent donc de toute façon gérer leur propre politique, ils ne peuvent pas être sûrs que le réseau le fera pour eux. C'est une variante de l'argument classique en faveur d'un contrôle de bout en bout (cf. J.H. Saltzer, D.P. Reed et David Clark, « End-To-End Arguments in System Design ») : ne faites pas dans le réseau ce que vous pouvez faire aux extrémités.

Une critique plus détaillée des anciennes recommandations, notamment à propos de RED, figure en section 4. Très intéressante lecture pour les étudiants qui veulent comprendre la congestion et les moyens de la combattre. Le papier originel de RED (Floyd et Van Jacobson, « Random Early Detection (RED) gateways for Congestion Avoidance ») introduisait les deux modes dont j'ai parlé, mode octet et mode paquet. Mais il ne recommandait pas un mode spécifique. Quand RED est devenu la recommandation officielle dans le RFC 2309, cinq ans plus tard, il n'y avait pas encore une recommandation claire (depuis, RED a perdu son statut, cf. RFC 7567). C'est dans les échanges de courrier cités plus haut que s'était forgée petit à petit l'idée qu'il fallait distinguer la mesure de la congestion (en octets ou en paquets) et l'action (même probabilitité d'abandon pour tous les paquets, ou bien une probabilité qui dépend de leur taille).

La mesure de la congestion n'est pas triviale. Par exemple, un routeur peut avoir une file d'attente packet-congestible (par exemple parce que le routeur utilise un tampon de taille fixe par paquet en attente) mais qui donne accès à une ressource bit-congestible. Que choisir dans ce cas ? Notre RFC dit qu'il faut quand même compter en octets : c'est la congestion de la ressource la plus en aval qu'il faut compter. Cette règle simple à l'avantage de marcher aussi si la file d'attente est plus compliquée, se servant de plusieurs jeux de tampons (des petits, des grands...), chaque jeu étant d'une taille donnée (ce que Cisco nomme buffer carving).

Et s'il n'y a pas de file d'attente à proprement parler ? Par exemple, l'alimentation électrique d'un engin qui communique par radio est en général bit-congestible car la consommation électrique dépend du nombre de bits transmis. Mais il n'existe pas de file d'attente des paquets attendant que la batterie se remplisse. En fait, AQM n'impose pas une file d'attente. D'autres moyens que la longueur de cette file permettent de mesurer la congestion, comme expliqué dans « Resource Control for Elastic Traffic in CDMA Networks » dans le cas de l'exemple de l'engin sans fil.

Le problème d'une discrimination envers les grands paquets n'est pas spécifique aux mécanismes « avancés » d'AQM. Le bête et traditionnel tail-drop (jeter les nouveaux paquets entrants quand la file est pleine) tend à rejeter surtout les grands paquets (s'il y a un peu de place, on n'acceptera que les petits paquets : donc, dès que la file d'attente « avance », les petits paquets la rempliront avant qu'elle n'ait eu le temps de se vider assez pour un grand paquet). Même chose lorsqu'on a plusieurs jeux de tampons et qu'on autorise les petits paquets à occuper les grands tampons.

Et du côté des protocoles de transport, qu'est-ce qui a été fait ? Suivant la ligne du RFC 5348, le protocole TFRC-SP, spécifié dans le RFC 4828 vise à favoriser les petits paquets mais au bon endroit, dans le protocole de transport aux extrémités, pas dans les routeurs.

Cela ne résout pas le problème des paquets de contrôle, qui sont en général de petite taille (mais rappelez-vous que l'inverse n'est pas vrai). Une solution possible est de rendre TCP plus solide face à la perte de paquets de contrôle. Cela a été décrit dans les RFC 5562 et RFC 5690. Ces deux RFC disent d'ailleurs qu'il vaudrait peut-être mieux que les routeurs ne laissent pas tomber les petits paquets. Mais notre RFC 7141 dit au contraire qu'il faut résoudre le problème aux extrémités, pas dans les routeurs. D'autres propositions de réforme de TCP ont été proposées, parfois assez rigolotes comme la proposition de Wischik de dupliquer systématiquement les trois premiers paquets de toute connexion TCP, ce qui ajouterait peu de trafic (ces paquets sont petits) mais rendrait TCP bien plus résistant aux pertes des petits paquets, ou encore une proposition similaire qui a été testée sur les serveurs de Google.

La section 5 du RFC est consacrée aux questions non répondues. Notre RFC est clair dans ses recommendations (que le routeur ne tienne pas compte de la taille des paquets mais que le transport le fasse). Mais cela ne répond pas à tout :

  • Comment gérer le cas des routeurs à AQM existants, s'ils mettent en œuvre le mode octet désormais déconseillé ?
  • Comment déployer les nouvelles recommandations dans les protocoles de transport ?

La première question est relativement facile car l'étude documentée dans l'annexe A montre que le mode octet a été peu déployé. On peut donc ignorer le problème. Pour la deuxième, il existe des modifications expérimentales des protocoles de transport (RFC 4828) mais rien de systématique.

Il n'y a donc pas trop de problèmes si l'Internet reste comme il est, essentiellement composés de ressources bit-congestible. Mais s'il se peuplait petit à petit de ressources packet-congestible ? La question avait déjà été posée dans la section 3 du RFC 6077 mais n'a pas encore de réponse.

Ces recommandations ont-elles des conséquences sur la sécurité de l'Internet ? La section 6 de notre RFC dit que oui, dans un sens positif. En effet, l'ancienne recommandation, de jeter en priorité les gros paquets, facilitait certaines attaques par déni de service. Après tout, une des raisons de déployer AQM était d'éviter le biais en faveur des petits paquets qui était un conséquence du tail drop. Le mode octet d'AQM pouvait donc être vu comme une réintroduction d'une vulnérabilité qu'AQM voulait justement éviter.

L'annexe A rend compte de l'étude de 2007 qui montre qu'aucun des vendeurs d'équipement (routeurs, pare-feux, etc) ayant répondu à l'enquête (16 répondants) ne mettait en œuvre le mode octet pour décider de laisser tomber les paquets (donc, ils n'auront rien à faire, ce RFC 7141 rend juste compte de leur pratique actuelle). À noter que la plupart des vendeurs n'ont pas voulu être identifiés (les deux exceptions sont Alcatel-Lucent et Cisco, plus Linux qui a pu être étudié sans le vendeur, puisqu'en logiciel libre). Autre sujet d'amusement, deux vendeurs n'étaient pas sûrs et devaient vérifier. Les justifications données étaient plutôt égoïstes : prendre en compte la taille des paquets avant de décider de les jeter aurait compliqué le code. Maintenant, qu'est-ce qui est déployé dans le vrai Internet ? Bien qu'il n'y ait pas d'étude à ce sujet, les auteurs du RFC pensent que bien des files d'attente sur l'Internet sont encore tail drop, pré-AQM, notamment dans les équipements de bas de gamme. Les équipements qui font de l'AQM mais avec des tampons de taille fixe, comme ceux en tail drop continuent à favoriser (légèrement) les paquets de petite taille mais il est difficile de mesurer l'exacte ampleur de leur déploiement.


Téléchargez le RFC 7141


L'article seul

RFC 7136: Significance of IPv6 Interface Identifiers

Date de publication du RFC : Février 2014
Auteur(s) du RFC : B. Carpenter (Univ. of Auckland), S. Jiang (Huawei Technologies)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 12 février 2014


Les adresses IPv6 sont souvent composées en utilisant un truc nommé « interface identifiers » (identifiant d'interface réseau). Ces identifiants peuvent être formés, par exemple, en utilisant les adresses MAC, en utilisant des bits ayant un sens particulier dans les normes IEEE. Résultat, dans le passé, certains ont attribué à des bits de l'identifiant d'interface une signification qu'ils n'avaient pas. Ce nouveau RFC clarifie la question : les identifiants d'interface doivent être considérés comme opaques et il ne faut pas tirer de conclusion du fait que tel ou tel bit est mis.

Un exemple typique de construction d'adresse IPv6 est donné dans la section 2.5 du RFC 4291. L'adresse IPv6 de 128 bits est formée en concaténant un préfixe avec un interface identifier. Ce dernier est censé être unique sur le lien où la machine est connectée. Cet objectif peut être atteint en prenant l'adresse MAC de la machine et en la transformant en utilisant le format Modified EUI-64. Dans ce format, le bit U (pour universal) est inversé, 1 signifiant que l'identifiant EUI-64 est unique mondialement, 0 qu'il ne l'est pas (ainsi, les adresses fabriquées manuellement comme 2001:db8:33::1 ont un identifiant d'interface où le bit U est à zéro). Un autre bit est spécial, le G, qui indique s'il s'agit d'une adresse de groupe ou de machine individuelle. Ces deux bits perdent leur signification dès qu'ils sont mis dans une adresse IPv6, c'est le point important de ce RFC.

Un exemple ? Si la machine a l'adresse MAC b8:27:eb:ba:90:94, son identifiant d'interface va être ba27:ebff:feba:9094 (suivant le tutoriel sur le format EUI-48, on ajoute ff:fe au milieu, l'adresse Ethernet ne faisant que 48 bits, et on inverse le bit U, transformant le b8 en ba).

Comme indiqué, il y a bien d'autres façons de fabriquer un identifiant d'interface (notre nouveau RFC 7136 utilise le sigle « IID » qui n'apparait pas dans le RFC 4291 original). Si celle utilisant une adresse MAC est la plus souvent présentée dans les tutoriels IPv6, elle n'est pas la seule et on a des identifiants d'interface formés à partir d'un processus cryptographique (RFC 3972 ou RFC 5535), générés aléatoirement et utilisés temporairement, pour protéger la vie privée (RFC 8981), ou fabriqués à partir des adresses IPv4 (RFC 5214). Sans compter la méthode manuelle de choisir l'identifiant d'interface à volonté, en en faisant un nombre significatif (::53 pour un serveur DNS) ou rigolo (::dead:beef). Et de nouvelles méthodes apparaissent de temps en temps. Pour chacune de ces méthodes, la norme stipule la valeur que doivent prendre les bits U et G. Par exemple, le RFC 3972 les met à zéro tous les deux et le RFC 8981 (section 3.3) met U à zéro et ne dit rien pour G. Les identifiants formés à partir de ces méthodes ont donc des valeurs très variables pour ces deux bits. En fait, l'identifiant d'interface ne fait même pas forcément 64 bits, comme illustré par le RFC 6164, qui le réduit à un seul bit pour les liaisons point à point entre deux routeurs !

Bref, l'affirmation du RFC 4291 (section 2.5.1) comme quoi le bit U signifie réellement que l'adresse est unique ou pas n'est plus vraie. Et, même si on n'avait gardé qu'une seule méthode de création des identifiants d'interface, celle fondée sur l'adresse MAC, les exemples n'ont pas manqué de constructeurs livrant plusieurs cartes Ethernet avec la même adresse (et c'est encore plus vrai sur les machines virtuelles). Simon Castaing m'a fourni une bonne liste :

On ne peut donc pas espérer que les identifiants d'interface soient mondialement uniques. On ne peut pas compter sur le bit U.

Même des protocoles qui, au début, voulaient pouvoir compter sur l'unicité de l'identifiant d'interface ont fait marche arrière. Par exemple ILNP (RFC 6741) prévoit que les 64 derniers bits de l'adresse soient uniques pour un localisateur donné. Mais il a quand même un système de détection de duplication, car utiliser EUI-64 pour ces 64 derniers bits ne suffit pas, comme on l'a vu.

Ah, et puis on a beaucoup parlé du bit U et nettement moins du bit G. Les adresses IPv6 formées à partir de l'adresse Ethernet ne devraient pas avoir le bit G à 1 (on n'utilise pas les adresses de groupe) mais cela ne veut pas dire que ce bit ait une signification particulière, dans une adresse IPv6. Comme pour le bit U, une fois l'adresse fabriquée, on ne peut plus l'analyser. Si on sait, par un moyen ou un autre, qu'une adresse IPv6 a été formée à partir d'une adresse MAC, on peut recalculer l'adresse MAC, ce qui peut avoir des avantages opérationnels, lors du débogage d'un réseau. Mais, si on ne le sait pas, il vaut mieux s'abstenir : ce n'est pas parce que l'identifiant d'interface a le bit U à 1 et le bit G à 0 qu'il a forcément été engendré à partir d'une adresse MAC.

Parfois, le mécanisme de génération d'identifiants d'interface par une adresse MAC est présenté comme garantissant l'unicité, sans autre effort. Comme on l'a vu, ce n'est pas le cas, même si tout le monde utilisait ce mécanisme. C'est pour cela qu'IPv6 a un système de détection des duplications d'adresses, le DAD (Duplicate Address Detection, RFC 4862). Comme ce système est obligatoire, on n'a pas besoin de trouver des méthodes de génération d'adresse qui assurent l'unicité : il suffit de laisser le DAD trouver les collisions et, dans ce cas, de réessayer. Par exemple, la section 3.4 du RFC 8981 dit qu'en cas de collision, on refait tourner l'algorithme (de génération aléatoire de l'identifiant) et on obtient donc un nouvel identifiant aléatoire.

Les sections 3 et 5 du RFC sont la partie normative de ce document : les bits U et G peuvent être utilisés librement par les méthodes de génération des identifiants d'interface (et donc des adresses IPv6) et, lorsqu'on lit une adresse IPv6 sans connaître le mécanisme de génération, il ne faut pas croire qu'on peut déduire quelque chose de la valeur de ces deux bits. Dans certains cas (identifiants temporaires aléatoires du RFC 8981), c'est même un facteur de sécurité (donner le moins d'information possible, cf. section 6).

Cela nécessite de modifier le RFC 4291 : la régle comme quoi les identifiants d'interface (à part ceux commençant par trois bits mis à zéro) doivent être formés à partir d'une adresse MAC est officiellement retirée, et l'allusion aux bénéfices du bit U pour détecter un identifiant d'interface mondialement unique également. Comme le note notre RFC, cela ne devrait gêner aucune implémentation, cette réforme alignant simplement la norme sur la pratique constatée.


Téléchargez le RFC 7136


L'article seul

RFC 7133: Information Elements for Data Link Layer Traffic Measurement

Date de publication du RFC : Mai 2014
Auteur(s) du RFC : S. Kashima (NTT), A. Kobayashi (NTT East), P. Aitken (Cisco Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ipfix
Première rédaction de cet article le 22 mai 2014


Le protocole IPFIX permet de transmettre des informations statistiques d'un point de mesure à un dispositif d'analyse. Quelles informations ? Cela dépend des éléments d'information normalisés et utilisés par le dispositif de mesure. La plupart des éléments d'information décrits au début d'IPFIX concernaient la couche 3, mais ce nouveau RFC étend IPFIX vers la couche 2, en permettant de transmettre des informations sur des choses comme le nombre total d'octets transportés par tous les paquets du lien (pas seulement les paquets IP).

C'est que les opérateurs de réseaux à longue distance, pas seulement les administrateurs de LAN, doivent désormais produire des chiffres sur le comportement de la couche « liaison de données ». Si Ethernet et les VLAN n'étaient autrefois utilisés qu'en local, on a désormais plein d'offres de services de couche 2 sur une plus grande distance (IEEE 802.1Q). IPFIX, normalisé dans le RFC 7011, a bien un modèle de données pour l'échantillonnage de paquets (RFC 5477) mais pas directement assez d'éléments d'information pour la couche 2. Les éléments d'information normalisés sont tous rangés dans un registre IANA (cf. RFC 7012, sur le modèle de données d'IPFIX), registre auquel ce nouveau RFC 7133 ajoute les éléments de couche 2.

Parmi les éléments qui existaient déjà (section 3.1), on trouvait dataLinkFrameSize, d'ID 312, qui décrivait la longueur d'une trame. Mais le gros de notre RFC est évidemment fait des nouveaux éléments d'information. En voici quelques-uns.

Il y a dataLinkFrameType (ID 408), qui indique le type d'une trame (0x01 étant l'Ethernet original et 0x02 l'IEEE 802.11). Il y a l2OctetTotalCount (ID 419) qui indique combien d'octets sont passés en tout par le point de mesure. (Comme on mesure la couche 2, ce nombre d'octets inclut l'en-tête Ethernet, et est donc distinct du octetTotalCount du RFC 5102.) On trouve aussi minimumL2TotalLength (ID 422) qui est la taille de la plus petite trame observée depuis le début des mesures.

Bien d'autres éléments sont disponibles, par exemple pour l'observation des VLAN (avec des noms commençant par dot1q). Bonne lecture du RFC !


Téléchargez le RFC 7133


L'article seul

RFC 7132: Threat Model for BGP Path Security

Date de publication du RFC : Février 2014
Auteur(s) du RFC : S. Kent (BBN), A. Chi (UNC-CH)
Pour information
Réalisé dans le cadre du groupe de travail IETF sidr
Première rédaction de cet article le 22 février 2014


Tout le monde le sait, le système de routage de l'Internet, fondé sur le protocole BGP, n'est pas sûr. Il est trop facile d'y injecter des annonces de routes mensongères. Le premier pas vers une sécurité plus forte était de sécuriser la communication entre routeurs (RFC 5925). Un second pas a été réalisé avec le déploiement de la RPKI. Un troisième pas avec la normalisation de la solution RPKI+ROA. Cette dernière protège uniquement l'origine d'une annonce BGP. Cela suffit à arrêter pas mal d'erreurs mais une attaque délibérée gardera probablement l'origine authentique et trichera sur le chemin d'AS présent dans l'annonce BGP. D'où la nécessité de continuer le travail. C'est le projet PATHSEC (Path Security) pour lequel ce nouveau RFC énumère les motivations. (Le terme de BGPSEC avait été utilisé dans le passé mais PATHSEC semble plus fréquent aujourd'hui.)

Le but de PATHSEC est simple : garantir que le chemin d'AS dans une annonce BGP est authentique, et que les NLRI (Network Layer Reachability Information) soient celles originellement annoncées. (Rappelez-vous que les ROA du RFC 6482 ne protègent que le début du chemin, l'origine.) Le chemin d'AS est transporté dans l'annonce BGP par l'attribut AS_PATH (RFC 4271, sections 4.3 et 5.1.2). La stratégie de PATHSEC est de s'appuyer sur la RPKI (RFC 6487), une infrastructure de distribution de certificats et d'objets signés. PATHSEC ne comptera pas sur une instance centrale qui connaitrait toutes les annonces BGP et pourrait tout vérifier. Au contraire, comme BGP lui-même, PATHSEC s'appuiera sur une vue locale, celle des routeurs d'un AS.

Pour concevoir proprement PATHSEC, il faut analyser les menaces, faire une analyse de risque. Que peut faire un méchant, même si tout le monde a déployé la RPKI et émet des ROA ? Il existe déjà des documents d'analyse des faiblesses de la sécurité du routage comme le RFC 4272 ou comme l'article de Kent, Lynn et Seo, « Design and Analysis of the Secure Border Gateway Protocol (S-BGP) » à la conférence IEEE DISCEX en 2000. Ce RFC détaille les faiblesses, notamment en indiquant celles qui resteront même dans un monde futur où tout les acteurs auront déployé PATHSEC. Le cahier des charges formel, lui, a été publié plus tard, dans le RFC 7353.

La section 3 résume les concepts. Une menace est un adversaire motivé et compétent. Il existe plusieurs catégories de menaces. Les opérateurs du réseau en sont une. L'opérateur peut demander à ses routeurs BGP d'émettre des messages visant à perturber le réseau ou à dérouter du trafic, par exemple pour le faire passer par des liens financièrement avantageux pour lui. Le contrôle légitime de routeurs BGP de la DFZ fait de cette catégorie d'attaquants potentiels une menace sérieuse. Si cet opérateur participe à la RPKI, il peut aussi émettre des vrais/faux certificats et ROA. Avec PATHSEC, il pourra donc signer de faux chemins d'AS.

Autre catégorie d'attaquants, les pirates informatiques qui prendraient le contrôle d'un ou plusieurs routeurs. Leurs capacités de nuisance seraient donc à peu près les mêmes que celles d'un opérateur, mais avec des limites (monter une attaque de l'Homme du Milieu serait plus difficile pour eux, le contrôle des routeurs ne donne pas forcément le contrôle de l'AC RPKI, etc). Le pirate est distinct du délinquant, étudié dans le paragraphe suivant, non par ses motivations (elles n'ont pas d'importance pour cette analyse technique du routage et de sa sécurité), mais par le fait que cette catégorie opère en général purement à distance, sans accès physique aux équipements. Le délinquant, lui, a d'autres possibilités. Par menace, chantage ou corruption, il peut même enrôler dans ses activités des employés de l'opérateur réseau. Contrairement au pirate, qui a parfois des motivations politiques, le délinquant est typiquement motivé par l'argent. Par exemple, il peut être payé pour réaliser une attaque par déni de service.

Les RIR sont aussi une menace pour le routage. Attribuant les ressources Internet (notamment les adresses IP), et étant à la racine de la RPKI, ils ont la possibilité de casser le routage. Pour prendre un exemple souvent cité, « l'attaque de la police néerlandaise », une action en justice aux Pays-Bas contre le RIPE-NCC pourrait mener à une perturbation du routage de l'opérateur dont les ressources auraient été reprises par le RIR.

Enfin, les États sont eux-même souvent la principale menace. L'État contrôle, directement ou indirectement, les opérateurs sur son territoire, il a parfois des capacités de surveillance massive, il peut monter des attaques de l'Homme du Milieu (l'Iran l'a fait plusieurs fois et les mollahs ne sont certainement pas les seuls à le faire). Comme expliqué plus haut, l'État peut aussi avoir barre sur le RIR situé sur son territoire. Certaines de ces attaques peuvent se commettre en dehors du territoire de l'État (la NSA ou la DGSE espionnent à l'extérieur).

Après ce tour des (méchants) acteurs, la section 4 de notre RFC décrit les catégories d'attaques. D'abord, les attaques contre la session BGP établie entre deux routeurs. Un attaquant peut perturber une telle session (envoyer des paquets TCP RST) et ainsi fait du déni de service. Il peut aussi faire l'Homme du Milieu : le routeur d'Alice croit qu'il parle au routeur de Bob alors qu'en fait il parle au routeur pirate. Dans tous les cas, si la session BGP n'est pas protégée, l'attaquant peut faire des choses comme modifier les annonces BGP. Le problème est connu depuis longtemps, le RFC 4272 en parle en détail, et décrit les solutions. En gros, on peut considérer ce problème particulier comme étant résolu depuis des années.

Mais l'attaquant peut aussi viser directement le routeur. Que ce soit par piratage ou bien parce que l'attaquant est le gérant légitime du routeur, le résultat est le même. Une fois qu'on contrôle un routeur, on peut effectuer plein d'attaques. Attention, BGP permettant un contrôle détaillé de la politique de routage, toute manipulation BGP n'est pas forcément une attaque. Le RFC cite l'exemple d'une fuite où certaines routes sont propagées au-delà de ce que d'autres opérateurs considèrent comme légitime ; cela peut être une mauvaise idée égoïste, sans être forcément une attaque. (Un autre exemple pourrait être les annonces ultra-larges.) Par contre, ces manipulations seront unanimement considérées commes des attaques :

  • Insérer d'autres numéros d'AS que les siens dans le chemin,
  • Être à l'origine d'une route sans autorisation (les ROA - RFC 6482 - sont justement là pour bloquer cela),
  • Voler (par copie) les clés privées utilisées par le routeur, soit pour l'authentification avec les routeurs voisins (s'ils utilisent l'AO du RFC 5925) soit pour signer les annonces de route avec PATHSEC,
  • Et plusieurs autres (voir le RFC pour les détails).

Autres attaques possibles, moins directes : viser non pas les routeurs mais les machines de gestion du réseau. Si les routeurs sont gérés par un système central, avec Ansible ou Chef ou un logiciel équivalent, prendre le contrôle du système central permet de contrôler tous les routeurs.

La RPKI a ses propres vulnérabilités. L'attaquant peut viser un dépôt d'objets de la RPKI. S'il détruit les objets du dépôt ou bien rend celui-ci inutilisable, il a réalisé une attaque par déni de service contre la RPKI (voir aussi la section 5, sur ce risque). Notons quand même que la RPKI n'a jamais été prévu pour être synchrone. Les validateurs sont censés garder des copies locales et peuvent donc survivre un certain temps à une panne d'un dépôt en utilisant ces copies locales (et les durées typiques de synchronisation sont bien plus longues qu'avec le DNS, donc la mise en cache isolera de l'attaque pendant plus longtemps). Et, les objets étant signés, l'attaquant qui contrôle un dépôt ne peut pas changer les objets. Les manifestes du RFC 6486 protègent également contre certaines manipulations. Par contre, la RPKI reste vulnérable à certaines attaques par rejeu. Les opérateurs de la RPKI doivent donc choisir des dates de validité de leurs objets assez courtes pour les protéger du rejeu mais assez longues pour ne pas entraîner des problèmes opérationnels si, par exemple, le système de signature a un problème. (On note que c'est un problème très proche de celui de la sélection des durées de vie de signatures DNSSEC.)

Bien plus grave serait l'attaque réussie contre l'autorité de certification, et plus seulement contre le dépôt de publication. Parce que, cette fois, l'attaquant serait en mesure de créer des objets signés à sa guise. Il n'y a même pas besoin que l'attaquant réussisse à copier la clé privée de l'AC : il suffit qu'il prenne le contrôle du dispositif de gestion des données, avant la signature (c'est pour cela que les HSM ne protègent pas autant qu'on le croit, même s'ils ont le gros avantage de faciliter la réparation, une fois le problème détecté).

L'expérience de DNSSEC permet de prédire que les problèmes provoqués par la négligence, les bogues ou l'incompétence seront sans doute au moins aussi fréquents que les attaques. Pour reprendre une citation dans Pogo, rappelée par notre RFC, « We Have Met the Enemy, and He is Us ».

Enfin, la section 5 liste les vulnérabilités résiduelles, celles que même un déploiement massif de PATHSEC ne limiterait pas. Par exemple, une AC peut mal se comporter avec ses propres ressources (émettre un ROA pour un de ses préfixes mais avec le mauvais numéro d'AS, suite à une faute de frappe, par exemple). Même avec PATHSEC, quelques risques resteront. On a déjà parlé des fuites (route réannoncée alors qu'elle ne le devrait pas, mais avec un chemin d'AS correct), qu'on peut d'autant moins empêcher qu'il n'existe pas de définition consensuelle de ce qu'est une fuite. Il y a aussi le fait que PATHSEC ne protège pas tous les attributs d'une annonce BGP, alors même que certains sont utilisés pour prendre des décisions de routage. Et puis PATHSEC permet de vérifier une annonce mais pas de vérifier que l'annonce n'a pas été retirée entre temps. Si un lien est coupé, que des routeurs BGP retirent la route, mais qu'un méchant intercepte et détruit ces retraits de route, les anciennes annonces resteront valables un certain temps.


Téléchargez le RFC 7132


L'article seul

RFC 7129: Authenticated Denial of Existence in the DNS

Date de publication du RFC : Février 2014
Auteur(s) du RFC : R. Gieben (Google), W. Mekking (NLnet Labs)
Pour information
Première rédaction de cet article le 13 février 2014


Voilà une expression un peu effrayante, « la négation d'existence authentifiée ». C'est en fait un terme utilisé dans le DNS et notamment dans DNSSEC, pour indiquer qu'un résolveur DNS a pu prouver qu'un nom n'existe pas, ou bien qu'il existe mais qu'il n'a pas de données de tel type. Dans DNSSEC, cela se fait typiquement avec des enregistrements NSEC et NSEC3, dont la définition n'est pas toujours claire pour tout le monde. Ce RFC a donc pour but d'expliquer « tout ce qu'il faut savoir sur la négation d'existence authentifiée ». C'est une lecture indispensable pour les programmeurs qui vont mettre en œuvre DNSSEC, mais aussi pour les étudiants ou ingénieurs qui veulent comprendre DNSSEC y compris dans ses tréfonds les plus obscurs.

C'est que NSEC et, surtout, NSEC3 sont très compliqués, reconnait ce RFC dès sa première section. C'est même une des parties les plus compliquées de DNSSEC, qui n'en manque pourtant pas.

DNSSEC fonctionne en signant cryptographiquement les données retournées. Mais il ne signe pas les messages. Il y a deux codes de retour pour une réponse DNS lorsque le nom n'existe pas ou bien qu'il n'y a pas de données du type demandé. Dans le premier cas, le serveur DNS répond NXDOMAIN (No Such Domain), dans le second NOERROR mais avec un champ Answer Count à zéro, ce qu'on nomme une réponse NODATA. Dans les deux cas, aucun enregistrement n'est renvoyé. Comment signer le vide ? C'est pourtant indispensable, autrement un attaquant pourrait, par exemple, fabriquer une réponse prétendant qu'un enregistrement DS (délégation signée) n'existe pas, débrayant ainsi la sécurité qu'offre DNSSEC (section 6 de notre RFC).

Tous les exemples du RFC sont faits avec une petite zone d'exemple, example.org dont voici le contenu non signé :

example.org.        SOA ( ... )
                    NS  a.example.org.
a.example.org.      A 192.0.2.1
                    TXT "a record"
d.example.org.      A 192.0.2.1
                    TXT "d record"

Chargeons-la dans NSD pour voir et pouvoir reproduire les tests (le serveur va écouter sur le port 9053). D'abord (section 2 du RFC), avec une zone non signée. Premier test, le résolveur demande les enregistrements de type TXT pour a.example.org (le fichier de configuration de dig contient l'option +dnssec et donc impose EDNS) :


% dig @::1 -p 9053 TXT a.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 TXT a.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46585
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;a.example.org.		IN TXT

;; ANSWER SECTION:
a.example.org.		3600 IN	TXT "a record"

;; AUTHORITY SECTION:
example.org.		3600 IN	NS a.example.org.

;; ADDITIONAL SECTION:
a.example.org.		3600 IN	A 192.0.2.1

;; Query time: 1 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Mon Jan 20 18:46:25 CET 2014
;; MSG SIZE  rcvd: 93

On a bien le code de retour NOERROR et un seul enregistrement en réponse. On récupère aussi des informations facultatives dans les sections Authority et Additional. Si on demande par contre b.example.org :


% dig @::1 -p 9053 TXT b.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 TXT b.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 10555
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;b.example.org.		IN TXT

;; AUTHORITY SECTION:
example.org.		3600 IN	SOA a.example.org. root.example.org. (
				2014012000 ; serial
				604800     ; refresh (1 week)
				86400      ; retry (1 day)
				2419200    ; expire (4 weeks)
				86400      ; minimum (1 day)
				)

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Mon Jan 20 18:48:18 CET 2014
;; MSG SIZE  rcvd: 85

On a bien un NXDOMAIN. La section Authority nous donne le SOA de la zone.

Il y a un autre cas où la négation d'existence est nécessaire : lorsque le nom existe mais qu'il n'y a pas de données de ce type. Par exemple, si je demande une adresse IPv6 (qui n'est pas dans la zone) :


%  dig @::1 -p 9053 AAAA a.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 AAAA a.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55053
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;a.example.org.		IN AAAA

;; AUTHORITY SECTION:
example.org.		3600 IN	SOA a.example.org. root.example.org. (
				2014012000 ; serial
				604800     ; refresh (1 week)
				86400      ; retry (1 day)
				2419200    ; expire (4 weeks)
				86400      ; minimum (1 day)
				)

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Thu Jan 23 10:07:06 CET 2014
;; MSG SIZE  rcvd: 83

Ici, a.example.org a bien une adresse IPv4 dans la zone (et donc, le nom existe) mais pas d'adresse IPv6. Le code de retour est NOERROR (pas de problème) mais le compteur de réponses (ANSWER:) indique zéro. C'est ce qu'on appelle une réponse NODATA même si ce code n'apparait jamais dans les normes DNS.

Maintenant, passons en DNSSEC (section 3). D'abord, le rappel de quelques principes :

  • Les signatures DNSSEC peuvent être calculées à la volée (lors d'une requête) ou bien pré-calculées puis mises dans la zone. Les deux modes sont possibles (DNSSEC a été soigneusement conçu pour que les serveurs de noms ne soient pas obligés de faire de la cryptographie en temps réel) mais la plupart des déploiements actuels utilisent le pré-calcul. Pourquoi ne pas avoir imposé la signature dynamique (elle aurait simplifié certaines choses) ? Parce que le matériel de l'époque de la conception de DNSSEC ne permettait pas de signer à ce rythme et, même aujourd'hui, il faut se rappeler que des serveurs travaillent fréquemment à plus de 10 000 requêtes par seconde, avec des pics plus élevés. D'autre part, la signature à la volée nécessite que la clé privée soit distribuée à tous les serveurs faisant autorité, ce qui peut être difficile et est certainement peu sûr.
  • La réponse DNS n'est jamais signée, ce sont les données qui le sont. Ce qui veut dire que tous les en-têtes de la réponse DNS (comme le code de retour NXDOMAIN, ou comme le bit AD - Authentic Data) peuvent être mensongers.
  • Les alias (CNAME) et surtout les jokers (cf. RFC 4592) compliquent sérieusement les choses. Sans eux, le RFC 5155, par exemple, serait bien plus court ! (Une bonne leçon lorsqu'on conçoit des protocoles : des fonctions qui semblent cool et utiles peuvent se payer très cher plus tard, par exemple lorsqu'on tente de sécuriser le protocole.)

En raison du premier principe, il faut pouvoir pré-calculer les réponses négatives alors que la liste des questions menant à une réponse négative est quasi-infinie. Pas question donc de générer une réponse signée pour toutes les questions théoriquement possibles (si on imposait la génération dynamique de réponses à la volée, cela serait possible). On ne peut pas non plus utiliser un enregistrement générique (ne dépendant pas du nom demandé) pour toutes les réponses négatives car il pourrait facilement être utilisé dans une attaque par rejeu (on demande foobar.example.org, on a une réponse négative signée, on l'enregistre et on la sert ensuite à des résolveurs qui demandent a.example.org pour leur faire croire que ce nom n'existe pas).

La solution adoptée par DNSSEC a été de « signer les trous ». Un enregistrement spécial définit un intervalle entre deux noms, signifiant « il n'y a rien entre ces deux noms ». Et cet enregistrement est signé et peut donc être vérifié. Au début, cet enregistrement spécial se nommait le NXT (NeXT name) et était normalisé dans le RFC 2535, abandonné depuis. Il a été remplacé par le NSEC (Next SECure) avec le RFC 3755.

Le NSEC nécessite que la zone soit triée. Pour qu'un enregistrement affirmant « il n'y a rien entre jack.example.com et susie.example.com » soit utilisable, il faut savoir quels noms tomberaient entre ces deux noms. Le choix a été d'utiliser l'ordre alphabétique (RFC 4034, section 6.1). Donc, monica.example.com est entre ces deux noms mais pas bob.example.com. Dans notre zone d'exemple example.org, cela veut dire qu'il y aura trois NSEC : un allant de l'apex (example.org, l'apex est souvent notée @) à a.example.org, un allant de a.example.org à d.example.org et un bouclant la chaîne, en allant de d.example.org à l'apex. Signons la zone pour voir :

[On crée une clé]
% dnssec-keygen -a RSASHA256 -f KSK -b 4096 example.org
Generating key pair..................................................................................................................................................................................................................................++ .............................................++ 
Kexample.org.+008+37300

[On édite le fichier de zone pour mettre "$INCLUDE
Kexample.org.+008+37300.key"]

[On signe]
% dnssec-signzone -z example.org
dnssec-signzone: warning: example.org:3: no TTL specified; using SOA MINTTL instead
Verifying the zone using the following algorithms: RSASHA256.
Zone fully signed:
Algorithm: RSASHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                      ZSKs: 0 active, 0 stand-by, 0 revoked
example.org.signed

Examinons le fichier example.org.signed, il a bien trois NSEC (et ils sont signés) :

% grep NSEC example.org.signed
example.org.	86400 IN NSEC	a.example.org. NS SOA RRSIG NSEC DNSKEY
example.org.	86400 IN RRSIG	NSEC 8 2 86400 20140222083601 20140123083601 37300 example.org. J9kDD...
a.example.org.	86400 IN NSEC	d.example.org. A TXT RRSIG NSEC
a.example.org.	86400 IN RRSIG	NSEC 8 3 86400 20140222083601 20140123083601 37300 example.org. IVc/rrR...
d.example.org.	86400 IN NSEC	example.org. A TXT RRSIG NSEC
d.example.org.	86400 IN RRSIG	NSEC 8 3 86400 20140222083601 20140123083601 37300 example.org. b/DHgE...

(J'ai un peu triché, j'ai mis des noms absolus partout avec named-compilezone -s full.)

Chargeons cette zone signée et interrogeons-la pour un nom inexistant :


% dig @::1 -p 9053 A b.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 A b.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 16186
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;b.example.org.		IN A

;; AUTHORITY SECTION:
a.example.org.		86400 IN NSEC d.example.org. A TXT RRSIG NSEC
a.example.org.		86400 IN RRSIG NSEC 8 3 86400 (
				20140222083601 20140123083601 37300 example.org.
				IVc/rr...
example.org.		86400 IN NSEC a.example.org. NS SOA RRSIG NSEC DNSKEY
example.org.		86400 IN RRSIG NSEC 8 2 86400 (
				20140222083601 20140123083601 37300 example.org.
				J9kDDpefX...
example.org.		86400 IN SOA a.example.org. root.example.org. (
				2014012000 ; serial
				604800     ; refresh (1 week)
				86400      ; retry (1 day)
				2419200    ; expire (4 weeks)
				86400      ; minimum (1 day)
				)
example.org.		86400 IN RRSIG SOA 8 2 86400 (
				20140222083601 20140123083601 37300 example.org.
				QcFJIEpCs...

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Thu Jan 23 10:45:38 CET 2014
;; MSG SIZE  rcvd: 1821

On obtient logiquement un NXDOMAIN et on a en plus le NSEC (signé) affirmant « il n'existe rien entre a.example.org et d.example.org ». Le résolveur a donc la preuve (signée) de la non-existence de b.example.org. Un attaquant qui enregistre cette réponse ne pourra pas l'utiliser contre, disons, k.example.org, puisque celui-ci n'est pas couvert par le NSEC.

Et avec un nom existant mais un type de données qui ne l'est pas :


% dig @::1 -p 9053 AAAA a.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 AAAA a.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15504
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;a.example.org.		IN AAAA

;; AUTHORITY SECTION:
example.org.		86400 IN SOA a.example.org. root.example.org. (
				2014012000 ; serial
				604800     ; refresh (1 week)
				86400      ; retry (1 day)
				2419200    ; expire (4 weeks)
				86400      ; minimum (1 day)
				)
example.org.		86400 IN RRSIG SOA 8 2 86400 (
				20140222083601 20140123083601 37300 example.org.
				QcFJIE...
a.example.org.		86400 IN NSEC d.example.org. A TXT RRSIG NSEC
a.example.org.		86400 IN RRSIG NSEC 8 3 86400 (
				20140222083601 20140123083601 37300 example.org.
				IVc/rrRD5...

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Thu Jan 23 10:56:28 CET 2014
;; MSG SIZE  rcvd: 1228

Ls NSEC contiennent à la fin une liste des types de données présents pour le nom en partie gauche du NSEC. On a un NSEC qui dit « oui, a.example.org existe mais les seules données sont des types A, TXT et évidemment RRSIG et NSEC ». Le résolveur validant peut alors s'assurer que le AAAA n'existe pas.

Bon, tout cela est très joli mais les NSEC ont quand même deux inconvénients (section 3.4). Le premier est qu'ils permettent le zone walking : en testant avec un nom pris au hasard, on récupére le nom existant suivant. On teste alors ce nom avec un type inexistant et on a le nom encore suivant. Et, en itérant, on a toute la zone. À la main (mais cela s'automatise facilement) :

% dig @::1 -p 9053 A $RANDOM.example.org
...
example.org.		86400 IN NSEC a.example.org.
[Donc, le nom suivant est a.example.org. On continue avec un type de
données rare.]

%  dig @::1 -p 9053 NAPTR a.example.org
...
a.example.org.		86400 IN NSEC d.example.org. ...
[On a le nom suivant, d.example.org, plus qu'à continuer]

Ce zone walking permet d'accéder au contenu entier d'une zone, même si le transfert de zones est fermé. Cela n'est pas gênant pour certaines zones (zones très structurées comme celles sous ip6.arpa ou bien petites zones au contenu évident, l'apex et www) mais inacceptable pour d'autres. Il existe des techniques astucieuses pour le limiter (cf. RFC 4470) mais la solution la plus répandue est le NSEC3, présenté plus loin.

Le second inconvénient des NSEC ne concerne que les grandes zones composées essentiellement de délégations, typiquement les TLD. Chaque enregistrement va nécessiter un NSEC et sa signature, augmentant considérablement la taille de la zone, même quand elle ne comporte que peu de délégations sécurisées. Cela pourrait faire hésiter à adopter DNSSEC.

La solution à ces deux inconvénients est NSEC3, normalisé dans le RFC 5155. Mais, avant de voir NSEC3, voyons les autres solutions qui avaient été envisagées puis abandonnées (section 4 du RFC). Il y avait le NO, où la chaîne qui faisait le tour de la zone n'était pas fondée sur les noms, comme dans NSEC mais sur un condensat des noms, ne permettant pas de remonter au nom. (NSEC3 a plus tard repris cette idée.) Sur le moment, le danger du zone walking n'était pas considéré comme très grave, et NO était vite tombé dans l'oubli. Le problème que posait le zone walking a resurgi par la suite, menant à la conception de NSEC2, qui utilisait également des condensats des noms protégés. NSEC2 travaillait main dans la main avec un nouvel enregistrement, EXIST, qui servait à prouver l'existence d'un nom sans avoir besoin d'indiquer des données. C'était utile en cas d'utilisation des jokers (RFC 4592). Prouver que b.example.org n'existe pas est une chose, mais il faut aussi prouver qu'il n'y avait pas de joker qui aurait pu l'engendrer. C'est lors du travail sur NSEC2 qu'on a compris que les jokers étaient très compliqués et très mal compris.

Par contre, NSEC2 n'avait pas de système d'opt-out qui aurait pu résoudre le second inconvénient de NSEC, l'augmentation de la taille de la zone pour un TLD. D'où le développement de DNSNR, un enregistrement expérimental qui avait été le premier à prévoir une option pour ne faire aller la chaîne que d'un nom signé à un autre nom signé (alors que la chaîne NSEC va d'un nom à un nom). DNSNR affaiblit un peu la sécurité (on ne peut plus prouver la non-existence d'un nom qui n'est pas signé) mais d'une manière cohérente avec la philosophie de DNSSEC (où la signature n'est pas obligatoire). Et il permettait de diminuer l'augmentation de taille de la zone, la rendant proprotionnelle au nombre de noms signés, pas au nombre de noms. NSEC3 a donc également repris ce concept.

Il est donc temps de passer à NSEC3 (section 5 de notre RFC). NSEC3 ajoute la condensation des noms et l'opt-out, mais au prix d'une certaine complexité, qui fait qu'encore de nos jours, peu de gens arrivent à déboguer un problème NSEC3. C'est entre autre pour cela que NSEC3 ne remplace pas NSEC : les deux restent définis (par exemple, la racine est signée avec NSEC, le zone walking n'étant pas un problème, puisque les données sont publiques ; la taille n'en est pas un non plus, la majorité des TLD étant signés, l'opt-out ne ferait pas gagner grand'chose).

Donc, le principe de NSEC3 : lorsqu'on signe, on met un enregistrement NSEC3 pour le condensat du nom, pointant vers le condensat suivant. La chaîne qui couvre tous les trous est donc une chaîne de condensats et pas de noms. Lorsqu'une question arrive, et que la réponse est négative, le serveur faisant autorité doit condenser le nom pour savoir quel enregistrement NSEC3 renvoyer (donc, NSEC3 est le seul cas dans DNSSEC où un serveur faisant autorité doit faire de la crypto à chaque requête, mais il est vrai que ce n'est qu'une condensation, opération typiquement très rapide). Pour éviter qu'un attaquant n'utilise des tables pré-calculées, stockant les condensats de noms possibles, on ajoute un sel et on peut faire plus d'une itération si on veut.

Pour tester NSEC3, signons cette fois notre zone avec NSEC3. Il va falloir ajouter deux arguments, -3 pour indiquer le sel et -H pour le nombre d'itérations supplémentaires à faire (-A permettrait d'activer l'opt-out, ce que je ne fais pas ici). Les exemples du RFC utilisent un sel amusant, DEAD. C'est une mauvaise idée que de choisir un sel comme cela, car ces mots amusants sont en nombre limité et des méchants ont peut-être déjà généré des tables de condensats utilisant ces sels. Je prends donc un sel aléatoire (avec $RANDOM et sha256sum ci-dessous). Par contre, je garde les autres options du RFC, 2 pour le nombre d'itérations supplémentaires, pas d'opt-out et SHA-1 comme algorithme :

% dnssec-signzone -3 $(echo $RANDOM$RANDOM | sha256sum | cut -d' ' -f1) -H 2 \
                  -z example.org
dnssec-signzone: warning: example.org:3: no TTL specified; using SOA MINTTL instead
Verifying the zone using the following algorithms: RSASHA256.
Zone fully signed:
Algorithm: RSASHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                      ZSKs: 0 active, 0 stand-by, 0 revoked
example.org.signed

Et, lorsque je charge cette zone et que je demande un nom non-existant, je récupère des NSEC3 au lieu des NSEC :


% dig @::1 -p 9053 A b.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 A b.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 7591
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;b.example.org.		IN A

;; AUTHORITY SECTION:
ui6pc9ajfb1e6ge0grul67qnckig9bck.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				ASPD8T7IP6MGQ09OPQQP3KMH9D7VVODA
				A TXT RRSIG )
ui6pc9ajfb1e6ge0grul67qnckig9bck.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140223065356 20140124065356 37300 example.org.
				PIb9Y8T...
l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK
				NS SOA RRSIG DNSKEY NSEC3PARAM )
l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140223065356 20140124065356 37300 example.org.
				WKf8OkW...
aspd8t7ip6mgq09opqqp3kmh9d7vvoda.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				L6M3OP8QM1VR3T47JNM6DBL6S4QM2BL8
				A TXT RRSIG )
aspd8t7ip6mgq09opqqp3kmh9d7vvoda.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140223065356 20140124065356 37300 example.org.
				YrR7/0vxWT...

[SOA omis...]

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Fri Jan 24 08:57:43 CET 2014
;; MSG SIZE  rcvd: 2639

À quel nom correspondent ces condensats ? On va utiliser le programme nsec3hash livré avec BIND. On prend les paramètres de condensation dans l'enregistrement NSEC3PARAM (cet enregistrement est nécessaire car tous les serveurs faisant autorité pour une zone, pas seulement le ou les maîtres, doivent calculer ces condensats, ce qui implique de disposer de ces informations ; si le DNS avait été prévu avec DNSSEC et NSEC3 dès le début, on les aurait probablement mises dans le SOA) :

% dig +short @::1 -p 9053 NSEC3PARAM example.org
1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9
...

On voit donc le nombre d'itérations à faire et la valeur du sel (ce n'est pas le même sel que dans les exemples du RFC, ne vous étonnez donc pas si les valeurs sont différentes ; celles du RFC sont résumées dans l'annexe C). Testons avec l'apex :

% nsec3hash DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 1 2 example.org
L6M3OP8QM1VR3T47JNM6DBL6S4QM2BL8 (salt=DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9, hash=1, iterations=2)

Et pareil pour les autres noms qu'on connait. On peut donc trouver le NSEC3 correspondant à chacun. Ici, pour l'apex, c'était :

l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK
				NS SOA RRSIG DNSKEY NSEC3PARAM )

Avec à la fin la liste des types qui existent pour ce nom. Et avec dans la valeur le condensat suivant, UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK.

Ici, on n'a pas utilisé l'opt-out. Il n'aurait pas de sens pour cette zone car l'opt-out ne dispense de signatures et de preuves de non-existence que les délégations ou les non-terminaux vides (les domaines qui n'ont pas d'enregistrement et qui n'existent que parce qu'ils ont des sous-domaines). Mais, dans un gros TLD, l'opt-out peut aider à garder la taille des zones à des valeurs raisonnables. Regardons la zone .fr :


% dig A nexistesurementpasmaisquisait.fr
...
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 38993
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
...
9GVSHUTCOU5FH6SKL75VBHIJQ6KLB8HR.fr. 5346 IN NSEC3 1 1 1 BE174A99 9GVTDB9F17RKAOJKIK7GIH3EHS89GGJ6 NS SOA TXT NAPTR RRSIG DNSKEY NSEC3PARAM
...

Le deuxième chiffre, qui est à 1 et plus à 0 comme dans l'exemple précédent, montre que .fr utilise l'opt-out. Les enregistrements NSEC3 ne couvrent donc que les délégations signées (et qui ont donc un enregistrement DS). Bref, ceux qui ne voulaient pas utiliser DNSSEC ne sont pas protégés par DNSSEC, ce qui est finalement plus logique que ce qui arrive avec NSEC.

NSEC3 peut encore peut-être paraître simple comme cela mais la norme est très complexe et on y découvre encore des cas bizarres, pas ou mal prévus comme l'erratum 3441.

Maintenant, le problème difficile, les jokers (section 5.3). Ajoutons dans notre zone d'exemple :

*.example.org.      TXT "wildcard record"

Si un client DNS demande le TXT de z.example.org, il aura une réponse (il aurait eu un NXDOMAIN avec la zone précédente). Revenons aux enregistrements NSEC pour un moment :


% dig -p 9053 @::1 TXT z.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> -p 9053 @::1 TXT z.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49955
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;z.example.org.		IN TXT

;; ANSWER SECTION:
z.example.org.		86400 IN TXT "wildcard record"
z.example.org.		86400 IN RRSIG TXT 8 2 86400 (
				20140227062210 20140128062210 37300 example.org.
				G8THJnlRf...

;; AUTHORITY SECTION:
d.example.org.		86400 IN NSEC example.org. A TXT RRSIG NSEC
d.example.org.		86400 IN RRSIG NSEC 8 3 86400 (
				20140227062210 20140128062210 37300 example.org.
				JoewWY...

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Tue Jan 28 08:23:49 CET 2014
;; MSG SIZE  rcvd: 1215

On reçoit une réponse. Comment savoir qu'elle vient d'un joker ? C'est grâce à un champ discret de la signature, dont je n'ai pas encore parlé, le champ Labels (RFC 4034, section 3.1.3), le troisième du RRSIG. Il vaut 3 pour d.example.org, ce qui est normal car ce nom comporte trois composants. Mais il ne vaut que 2 pour z.example.org qui a aussi trois composants, car cet enregistrement dans la réponse a été dynamiquement généré grâce au joker. Ainsi, le résolveur DNS validant a toutes les informations nécessaires pour vérifier la signature de z.example.org. Comme on peut le vérifier en lisant le fichier de zone, cette signature n'a pas été générée dynamiquement, c'est celle du joker, *.example.org.

L'enregistrement NSEC dans la réponse ci-dessus empêche les attaques où le méchant essaierait de faire croire que, par exemple, a.example.org a aussi l'enregistrement TXT du joker. a.example.org ayant son propre TXT, celui du joker n'est pas utilisé et le NSEC - obligatoire - permettrait de prouver cela. Ici, le NSEC dit qu'il n'y a pas de TXT entre d.example.org et example.org donc rien pour z.example.org, achevant de prouver que la réponse vient d'un joker.

Et avec NSEC3 ? Pareil :


% dig -p 9053 @::1 TXT z.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> -p 9053 @::1 TXT z.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10172
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;z.example.org.		IN TXT

;; ANSWER SECTION:
z.example.org.		86400 IN TXT "wildcard record"
z.example.org.		86400 IN RRSIG TXT 8 2 86400 (
				20140223162550 20140124162550 37300 example.org.
				i69nAYi...
;; AUTHORITY SECTION:
l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK
				NS SOA RRSIG DNSKEY NSEC3PARAM )
l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140223162550 20140124162550 37300 example.org.
				ZbfNK6xD++...

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Tue Jan 28 08:15:15 CET 2014
;; MSG SIZE  rcvd: 1292

L'enregistrement NSEC3 prouve qu'il n'y a pas de TXT pour z.example.org, dont le condensat, TIIAIPBQRUI8LQOQVUOTC1RGS4VR3BA5, tomberait entre L6M3OP8QM1VR3T47JNM6DBL6S4QM2BL8 (l'apex) et UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK (a.example.org).

Je vous épargne (et à moi aussi), la section 5.4 sur les CNAME combinés aux jokers.

Plus utile (mais pas facile) est la section 5.5, sur la notion de « boîte la plus proche » (closest encloser). Une particularité de NSEC3 est qu'on perd l'information sur la profondeur de la zone : les condensats sont dans un espace plat, quel que soit le nombre de composants dans le nom condensé. Il va donc falloir ajouter un enregistrement NSEC3 pour la boîte la plus proche. Cette boîte (closest encloser, défini dans le RFC 4592) est le nœud existant dans la zone qui a le plus de composants correspondant à la requête. Si la requête portait sur x.2.example.org et qu'il n'existe rien se terminant en 2.example.org, la boîte la plus proche est example.org. Autre notion, le « nom plus proche [de la boîte la plus proche] » est le nom (non existant, au contraire de la boîte la plus proche) ayant un composant de plus que la boîte la plus proche. Dans l'exemple précédent, ce serait 2.example.org. Une preuve NSEC3 doit parfois comprendre un enregistrement pour prouver la boîte la plus proche, et un pour prouver que le nom plus proche n'existe pas.


% dig @::1 -p 9053 A x.2.example.org

; <<>> DiG 9.9.3-rpz2+rl.13214.22-P2-Ubuntu-1:9.9.3.dfsg.P2-4ubuntu1.1 <<>> @::1 -p 9053 A x.2.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52476
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;x.2.example.org.	IN A

;; AUTHORITY SECTION:
ui6pc9ajfb1e6ge0grul67qnckig9bck.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				ASPD8T7IP6MGQ09OPQQP3KMH9D7VVODA
				A TXT RRSIG )
ui6pc9ajfb1e6ge0grul67qnckig9bck.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140227063446 20140128063446 37300 example.org.
				eqpl3Vp...
...
l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK
				NS SOA RRSIG DNSKEY NSEC3PARAM )
l6m3op8qm1vr3t47jnm6dbl6s4qm2bl8.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140227063446 20140128063446 37300 example.org.
				GaK0HrQ...
je5k991emd1g7f9p37a3ajr96jrl0fvi.example.org. 86400 IN NSEC3 1 0 2 DD438FBA32EC3FFA4B1849EF2F41F64A83A17D220D22F57BC9903300A861BFE9 (
				L6M3OP8QM1VR3T47JNM6DBL6S4QM2BL8
				TXT RRSIG )
je5k991emd1g7f9p37a3ajr96jrl0fvi.example.org. 86400 IN RRSIG NSEC3 8 3 86400 (
				20140227063446 20140128063446 37300 example.org.
				U5zFverPJT...

;; Query time: 0 msec
;; SERVER: ::1#9053(::1)
;; WHEN: Tue Feb 04 18:10:08 CET 2014
;; MSG SIZE  rcvd: 2641

Si vous voulez suivre les explications qui suivent, vous devez calculer les condensats des noms. Les voici déjà calculés (avec mon sel ; avec le sel du RFC, voir l'annexe C qui résume les valeurs) :

Noms dans la zone :
L6M3OP8QM1VR3T47JNM6DBL6S4QM2BL8 : apex
UI6PC9AJFB1E6GE0GRUL67QNCKIG9BCK : a.example.org
ASPD8T7IP6MGQ09OPQQP3KMH9D7VVODA : d.example.org
JE5K991EMD1G7F9P37A3AJR96JRL0FVI : *.example.org

Noms dans la requête :
C9PVNA4KK7P5CH0L8C5RFDDI377RMJTO : x.2.example.org
4TPLI2PU4PVISAQ3OK4BNE06FL1ESDKJ : 2.example.org
TIIAIPBQRUI8LQOQVUOTC1RGS4VR3BA5 : z.example.org

Ici, il a fallu pas moins de trois NSEC3 pour prouver que le nom n'existait pas. Le premier prouve que 2.example.org n'existe pas (son condensat tombe entre les deux valeurs de l'enregistrement NSEC3) et que donc x.2.example.org n'existe pas non plus, puisqu'il était sous 2.example.org. Le second prouve que la boîte la plus proche, example.org existe (son condensat est la partie gauche du NSEC3). Et le troisième prouve qu'il y a un joker sous la boîte la plus proche (son condensat est la partie gauche du NSEC3) mais seulement pour les TXT. S'il n'y avait pas de joker dans la zone, le troisième NSEC3 servirait à prouver cette absence (section 5.6).

Sinon, si vous aimez lire le code source, le RFC recommande celui d'Unbound, dans validator/val_nsec3.c...

Si votre cerveau n'est pas complètement frit après ce RFC, l'annexe A présente un mécanisme pour utiliser des NSEC en rendant plus difficile l'énumération de la zone, la technique de la « couverture minimale » (RFC 4470). Elle impose par contre une signature en ligne, en réponse à la question posée. En pratique, cette technique ne semble pas déployée. Une technique analogue existe pour NSEC3 avec les « mensonges blancs » rappelés dans l'annexe B. Ils sont mis en œuvre dans le serveur de noms Phreebird.


Téléchargez le RFC 7129


L'article seul

RFC 7128: RPKI Router Implementation Report

Date de publication du RFC : Février 2014
Auteur(s) du RFC : R. Bush (Internet Initiative Japan), R. Austein (Dragon Research Labs), K. Patel (Cisco Systems), H. Gredler (Juniper Networks), M. Waehlisch (FU Berlin)
Pour information
Réalisé dans le cadre du groupe de travail IETF sidr
Première rédaction de cet article le 22 février 2014


Le protocole RTR (RPKI to Router Protocol), normalisé dans le RFC 6810, est utilisé entre un routeur et un cache/validateur qui vérifie les objets signés de la RPKI. Ce nouveau RFC fait le point sur les mises en œuvre effectives de RTR et leur degré de couverture de la norme.

C'est un RFC un peu particulier : ce n'est pas la normalisation d'un protocole (c'est fait dans le RFC 6810) et ce n'est pas une étude indépendante, juste une collecte de réponses à un questionnaire. Les auteurs du RFC n'ont pas vérifié ces réponses, envoyées par les auteurs des différentes mises en œuvre de RTR.

Petit rappel sur la RPKI : les titulaires de ressources Internet (les préfixes d'adresses IP, notamment) émettent des objets cryptographiquement signés attestant notamment de la légitimité d'un AS à annoncer tel préfixe en BGP. La vérification de ces objets nécessite des calculs cryptographiques pour lesquels le routeur moyen n'est pas forcément bien équipé. L'architecture conseillée est donc d'avoir une machine Unix ordinaire, le cache/validateur, qui va faire ces calculs, et le routeur se contentera de charger les résultats depuis un cache/validateur de confiance. Entre les deux, le protocole RTR, où le serveur est le cache/validateur et le client est le routeur.

La section 2 du RFC liste les mises en œuvre interrogées, aussi bien clients que serveur. (J'ai écrit une bibliothèque très minimum pour faire des clients RTR en Go à des fins notamment de statistiques : GoRTR. Très réduite et peu utilisée, elle ne fait pas partie de la liste étudiée par notre RFC.) On trouve donc dans ce RFC :

Le reste du RFC contient les résultats du questionnaire. D'abord, la gestion des différents types de message (section 3). Tout le monde le fait, évidemment, sauf XR et JunOS qui ne gèrent pas encore les messages Error Report. Ensuite, la gestion des échanges entre client et serveur (section 4) : presque complet sauf le programme du RIPE-NCC qui, aux questions Serial Query, envoie toujours un Cache Reset, forçant le client à tout télécharger.

Une des questions chaudes lors de la mise au point de RTR était le mécanisme de transport entre le client et le serveur, notamment pour assurer la sécurité (si le client, le routeur, parce qu'il a été trompé, parle à un serveur pirate, la sécurité fournie par la RPKI disparait, puisque le routeur ne fait pas les vérifications cryptographiques lui-même). Finalement, pour tenir compte des capacités très différentes des routeurs du marché, le RFC 6810 avait laissé les programmeurs choisir leur transport sécurisé librement. L'étude montre (section 5) que le seul protocole commun à toutes les mises en œuvre de RTR est le TCP pur, non sécurisé... Un autre choix, TCP protégé par le vieil RFC 2385, n'a au contraire rencontré aucun adepte. Même chose, hélas, pour TLS, pour le TCP-AO du RFC 5925 (ce dernier était pourtant recommandé par le RFC 6810), et pour IPsec. SSH, par contre, est une solution possible pour la moitié des implémentations. Bref, la sécurité des sessions RTR reste un sujet de préoccupation.

Et la gestion des différents codes d'erreur possible (section 6) ? À part JunOS, qui ignore les erreurs, tous ont répondu positivement.

Pour éviter de télécharger la liste des préfixes autorisés, avec leurs AS d'origine, à chaque changement, RTR a un système de mise à jour incrémentale. Nos programmes le mettent-ils en œuvre (section 7) ? Oui, sauf le serveur du RIPE-NCC et ceux des routeurs Cisco. Pour le concept de Session ID, qui permet d'indiquer que le cache/validateur a redémarré, c'est mieux, seul le validateur du RIPE-NCC ne le gère pas (section 8).

La section 10 termine ce RFC avec des questions sur les tests d'interopérabilité qui ont été faits. On notera avec amusement que les vendeurs de solutions privatrices, comme Cisco ou Juniper, n'ont pas testé leurs produits entre eux, mais l'ont fait uniquement face aux logiciels libres.


Téléchargez le RFC 7128


L'article seul

RFC 7127: Characterization of Proposed Standards

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : O. Kolkman (NLnet Labs), S. Bradner (Harvard University), S. Turner (IECA)
Première rédaction de cet article le 30 janvier 2014


En théorie, il existe à l'IETF une hiérarchie de normes. Un RFC publié sur le chemin des normes peut avoir plusieurs niveaux dans cette hiérarchie. Au nombre de trois à l'origine, ces niveaux ont été ramenés à deux par le RFC 6410. Le premier de ce niveau est « Proposition de Norme » (Proposed Standard), décrit par le RFC 2026. Sauf que la réalité est loin de ce que décrivent les documents officiels.

Le RFC 2026 est toujours le document qui décrit officiellement les normes issues de l'IETF. Sa section 4.1.1 raconte ce qui fait une « Proposition de Norme » mais ce récit est loin de ce qu'on observe en pratique. Ce nouveau RFC 7127 ne change pas le processus de normalisation, il se contente de remplacer la description des Propositions de Norme du RFC 2026 par un texte plus réaliste.

Pour atteindre le niveau Proposition de Norme, le premier niveau du chemin des normes, il faut une décision de l'IESG. Dans la vision originale, les normes allaient ensuite avancer par décisions successives, le long du chemin des normes, jusqu'au statut suprême, celui de « Norme Complète » (Internet Standard). En fait, des tas de protocoles très utilisés et très déployés n'ont jamais suivi cette progression et sont restés Proposition de Norme. Dans la liste des normes, on trouve ainsi, bloqués au niveau Proposition, des tas de protocoles très répandus et indiscutablement réussis, comme les communautés BGP du RFC 1997 ou comme le format OpenPGP du RFC 9580. Il serait donc ridicule et pédant d'écarter une Proposition de Norme en raison de son niveau sur le chemin des normes, alors que beaucoup de normes à ce niveau sont stables, bien testées, mises en œuvre dans beaucoup de programmes...

Donc, la section 3.1 de notre nouveau RFC propose une nouvelle description des Propositions de Norme, description qui remplace la section 4.1.1 du RFC 2026. Une Proposition de Norme est stable, les principaux choix de conception ont été faits et tranchés, elle a fait l'objet d'un examen détaillé par l'IETF, et elle est utile pour les internautes. Si la disponibilité d'une implémentation, et l'expérience opérationnelle de son utilisation, sont très recommandés pour recevoir le statut de Proposition de Norme, cela n'est pas stricto sensu indispensable. Par contre, si le protocole en question touche à une fonction essentielle de l'Internet, l'IESG peut exiger une telle expérience concrète.

Parfois, une norme sera publiée avec le statut de Proposition de Norme alors qu'il reste encore des problèmes non réglés. Dans ce cas, ces problèmes doivent être clairement documentés dans le texte de la norme (section 4 de notre RFC).

La description est plus courte que dans le RFC 2026 et ne contient plus les avertissements et mises en garde de l'ancien RFC.

Notre nouveau RFC ne change pas la description du second niveau, Norme Complète, qui reste présenté par la section 4.1.3 du RFC 2026.


Téléchargez le RFC 7127


L'article seul

RFC 7126: Recommendations on filtering of IPv4 packets containing IPv4 options

Date de publication du RFC : Février 2014
Auteur(s) du RFC : F. Gont (UTN-FRH / SI6 Networks), R. Atkinson (Consultant), C. Pignataro (Cisco)
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 12 février 2014


Le protocole IPv4 permet d'ajouter dans l'en-tête d'un paquet un certain nombre d'options qui peuvent influencer le traitement de ce paquet par les routeurs et les machines terminales. Certaines de ces options ayant eu des conséquences négatives pour la sécurité des réseaux, il est courant que les paquets portant des options soient filtrés par les pare-feux. Est-ce une bonne idée ? Est-ce que le choix dépend de l'option ? Quelles options faut-il filtrer ? Ce RFC rappelle brièvement la fonction de chaque option et donne des conseils sur le filtrage qu'il faudrait (ou pas) lui appliquer. C'est donc un document orienté vers le concret, vers les questions opérationnelles.

Aujourd'hui, note le RFC, une politique fréquente semble de bloquer systématiquement tout paquet IPv4 contenant des options, quelles que soient ces options. Une politique aussi violente a des tas de conséquences négatives sur le fonctionnement de l'Internet (section 6 de notre RFC, qui s'oppose à cette politique), la principale étant d'interdire de facto le déploiement de toute nouvelle option, si utile qu'elle puisse être. Une machine terminale peut toujours accepter ou rejeter les paquets IPv4 contenant des options, ce sont les paquets dont elle est destinataire, c'est son affaire (encore que le réglage par défaut du système d'exploitation soit important puisqu'on sait que beaucoup de gens ne le modifieront pas). Mais pour un intermédiaire comme un routeur ou un pare-feu; c'est plus délicat : s'il jette les paquets contenant des options, il brise le modèle de bout en bout et empêche toutes les machines situées plus loin de tirer profit de ces options. La situation est toutefois plus compliquée que cela puisque certaines options sont prévues pour être lues et traitées par les intermédiaires. Ce n'est donc pas une pure affaire de transparence du réseau.

Pour un engin intermédiaire, il y a trois stratégies possibles, en plus de la méthode paresseuse et violente de jeter tous les paquets ayant des options :

  • Laisser passer les paquets contenant des options,
  • Par défaut, laisser passer les paquets contenant des options mais avoir une liste d'options dangereuses, qu'on ne laissera pas passer,
  • Par défaut, jeter les paquets contenant des options mais avoir une liste des options acceptables, et laisser passer les paquets ne contenant que ces options.

Les études sur ce sujet montrent que les paquets contenant des options ont du mal à passer sur l'Internet, bien des intermédiaires les refusant systématiquement (méthode paresseuse et violente). Sur beaucoup de routeurs ou de pare-feux, le choix est binaire : ou on accepte toutes les options, ou on les jette toutes (notre RFC déconseille fortement cette limitation). On trouve les résultats de ces études dans « Measuring Interactions Between Transport Protocols and Middleboxes » de Medina, A., Allman, M., et S. Floyd, à Usenix / ACM Sigcomm en octobre 2004 ou dans « IP Options are not an option » de Fonseca, R., Porter, G., Katz, R., Shenker, S., et I. Stoica en décembre 2005. Sans compter les études montrant, comme « Spoofing prevention method » de Bremier-Barr, A. et H. Levy (IEEE InfoCom 2005), que bien des routeurs bas de gamme ne savent tout simplement pas gérer les options IPv4.

Avant les recommandations concrètes de ce RFC, un petit rappel des options IPv4, telles que normalisées par le RFC 791 (section 3.1). Physiquement, les options peuvent avoir deux formats (le second étant de très loin le plus commun) :

  • Un octet indiquant le type de l'option, sans arguments,
  • Un triplet {type de l'option, longueur de l'option, arguments de l'option}, les deux premiers champs étant stockés sur un octet.

On voit que ce n'est pas trivial à analyser lorsqu'on traite des centaines de millions de paquets par seconde. (Exercice : essayez d'écrire du code le plus rapide possible pour cela.) Mais IPv4 étant très ancien, le problème est bien connu et semble donc moins angoissant. Pour cette analyse des options, la machine IPv4 doit connaître la liste officielle des options (stockée dans un registre IANA). Le programmeur y verra par exemple les options 0 - fin de la liste d'options - et 1 - neutre. Ces deux options n'ont pas d'argument et donc tout tient dans un seul octet. Les options sont organisées en liste, la liste se terminant par l'option 0. Voici par exemple le code utilisé dans le noyau Linux pour lire les options (fichier net/ipv4/ip_options.c) :

unsigned char *optptr; /* Pointe vers la prochaine option */
...
switch (*optptr) {
    /* Deux cas particuliers au début, les deux options formées d'un
    seul octet */
    case IPOPT_END:
          ...
	goto eol;
    case IPOPT_NOOP:
	l--;
	optptr++;
	continue;
}
/* Le cas général, où la longueur de l'option est indiquée par le
deuxième octet (le premier étant le type) */
optlen = optptr[1];
switch (*optptr) {
/* Un "case" pour chaque option possible */
    case IPOPT_SSRR:
    ...

Le champ qui indique le type de l'option est lui-même subdivisé en trois sous-champs : un booléen qui indique si l'option doit être copiée dans tous les fragments au cas où la machine doive fragmenter le paquet, une classe stockée sur deux bits (deux classes seulement sont définies, option de contrôle et option de débogage et de mesure), et le numéro de l'option à proprement parler. Par exemple, 131 (Loose Source and Record Route) a le premier bit à un et doit donc être copiée en cas de fragmentation.

Si vous aimez fabriquer des paquets avec Scapy, il faut savoir (cf. cet article) qu'il faudra formater les options vous-même, Scapy ne fournit pas de mécanisme pour cela. Vous devez donc indiquer la liste d'octets qui compose la liste d'options. Ici, je ne mets qu'une option (inexistante), de type 42 et de longueur des données nulle (mais il faut compter dans le champ longueur l'octet de type et l'octet de longueur) :

p = IP(dst="127.0.0.1", 
       options=IPOption("\x2A\x02"))/
         UDP(sport=RandShort(),dport=53)/
           DNS(qr=0, rd=1, id=666, qd=DNSQR(qname="www.example"))

Affiché par tcpdump, cela donnera :

15:36:11.243193 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 61, options (unknown 42,EOL))
    127.0.0.1.54932 > 127.0.0.1.53: [udp sum ok] 42+ A? www.example. (29)

La section 3 détaille ce travail d'analyse des options. Pendant longtemps, les routeurs IP utilisaient un processeur généraliste pour traiter les paquets et donc les options. Le processeur gère les paquets mais aussi le routage (OSPF, BGP...) et les protocoles de plus haut niveau comme SNMP ou SSH. Un influx important de paquets IPv4 portant des options peut permettre une attaque par déni de service : occupé à analyser toutes ces options et à agir en fonction de leur contenu, le processeur n'aurait plus le temps de faire les autres tâches. Depuis le milieu des années 1990, de tels routeurs sont souvent remplacés par des routeurs disposant de circuits spécialisés pour traiter les paquets (FPGA, ASIC...). Le routeur a deux catégories de tâches : traiter les paquets entrants et les faire suivre (tâche effectuée à très grande vitesse par le circuit spécialisé) et le reste du travail, du routage à la gestion de l'interface utilisateur (tâche qui reste confiée à un processeur généraliste). Un des avantages de cette architecture est que le traitement des paquets ne rentre plus en concurrence avec les tâches de gestion du routeur (cf. RFC 6192). Mais elle peut compliquer les choses pour les options car ces circuits spécialisés sont rigides et il est difficile d'y mettre du code complexe. Certains routeurs simplifient donc en transmettant aveuglément les paquets, sans tenir compte du fait qu'ils contiennent des options ou pas. D'autres peuvent jeter les paquets contenant certaines options. Et d'autres enfin arrivent même à traiter les options qu'ils sont censés traiter (rappelez-vous que les options d'IPv4 peuvent être destinées à la machine de destination, ou bien à tous les routeurs intermédiaires ; contrairement à IPv6, les deux catégories ne sont pas facilement distinguables, le routeur doit connaître la liste complète des options enregistrées, pour savoir si une option est pour lui). Bref, quand on décide une politique de traitement des options, il faut d'abord se pencher sur ses routeurs et regarder si leurs ASIC sont capables de mettre en œuvre cette politique.

Place maintenant aux recommandations concrètes. La longue section 4 de notre RFC va donner un avis pour chaque option IPv4 enregistrée. À chaque option, notre RFC indique :

  • À quoi elle sert,
  • Les risques de sécurité connus,
  • Les conséquences d'un blocage des paquets portant cette option,
  • Une recommandation sur le blocage.

Commençons par un cas trivial, l'option de type 1 qui indique qu'il n'y a rien à faire :

  • Son utilité principale est d'aligner l'en-tête du paquet sur un multiple de 32 bits,
  • Il n'y a pas de risques connus,
  • Quelles que soient les options utiles, il y a des bonnes chances que le paquet soit complété par des options de type 1. Donc, jeter les paquets contenant cette option revient à interdire les options,
  • Les routeurs, pare-feux et autres intermédiaires ne devraient pas bloquer les paquets ayant l'option de type 1.

C'est évidemment la même chose pour l'option de type 0, qui indique la fin de la liste d'options, et qui est donc souvent présente dans tous les paquets ayant des options (le RFC 791 explique dans quels cas elle peut être omise).

Maintenant, les autres options, plus complexes. Je ne vais pas reprendre dans cet article la liste complète. Si vous voulez tout voir, regardez le RFC. Par exemple, les options de type 131 (LSSR, Loose Source and Record Route) ou 137 (SSSR, Strict Source and Record Route) :

  • Elles permettent à l'émetteur de définir une route qui devra être suivie par les paquets (routage par la source), et/ou d'enregistrer la route suivie dans le paquet, à des fins de débogage,
  • Les risques de sécurité sont énormes (RFC 6274, sections 3.12.2.3 et 3.12.2.4), ces options permettent de contourner les pare-feux, de joindre des machines normalement inaccessibles, d'apprendre le topologie d'un réseau, de faire du déni de service en créant des paquets qui rebondiront éternellement dans le réseau... En outre, sa mise en œuvre est complexe et mène facilement à des failles de sécurité comme celle qui avait frappé OpenBSD en 1998,
  • Si on les bloque, les outils de débogage qui s'en servent (comme traceroute avec l'option -g) ne marcheront plus mais, de toute façon, en pratique, ces options marchent rarement (à cause des fréquents blocages mais aussi à cause de leurs propres limitations, comme la faible taille maximale de l'en-tête IPv4, qui ne permet pas de stocker des longues routes),
  • La recommandation est, par défaut, de jeter les paquets contenant cette option, et d'avoir un réglage permettant de les accepter.

L'option 7, Record Route, ne spécifie pas de route mais demande que les routeurs enregistrent dans le paquet par où on est passé. Voici ce que voit tcpdump en mode bavard (-vvv) lorsqu'on utilise ping avec l'option -R (on n'est pas allé loin, on a juste pingué localhost) :

[Un ping normal, les paquets IP n'ont pas d'option]
08:26:44.040128 IP (tos 0x0, ttl 64, id 17400, offset 0, flags [DF], proto ICMP (1), length 84)
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 7811, seq 1, length 64
08:26:44.040178 IP (tos 0x0, ttl 64, id 17401, offset 0, flags [none], proto ICMP (1), length 84)
    127.0.0.1 > 127.0.0.1: ICMP echo reply, id 7811, seq 1, length 64

[Le ping avec -R. Notez le NOP dans la requête, pour aligner les
options, et le EOL dans la réponse, pour marquer la fin.]
08:26:47.126729 IP (tos 0x0, ttl 64, id 17405, offset 0, flags [DF], proto ICMP (1), length 124, options (NOP,RR 127.0.0.1, 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0))
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 7812, seq 1, length 64
08:26:47.126784 IP (tos 0x0, ttl 64, id 17406, offset 0, flags [none], proto ICMP (1), length 124, options (RR 127.0.0.1, 127.0.0.1, 127.0.0.1, 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0,EOL))
    127.0.0.1 > 127.0.0.1: ICMP echo reply, id 7812, seq 1, length 64

Comme les deux options précédentes, elle marche rarement en pratique (c'est pour cela que je me suis limité à localhost), en raison des nombreux équipements intermédiaires qui bloquent les paquets qui la contiennent. La recommandation est la même, la jeter par défaut. En attendant, dans un réseau où cette option marche, elle fournit une alternative à traceroute :

% ping -R www.free.fr
PING www.free.fr (212.27.48.10) 56(124) bytes of data.
64 bytes from www.free.fr (212.27.48.10): icmp_req=1 ttl=55 time=28.2 ms
RR: 	...
	vau75-1-v900.intf.nra.proxad.net (78.254.255.41)
	rke75-1-v902.intf.nra.proxad.net (78.254.255.45)
	cev75-1-v906.intf.nra.proxad.net (78.254.255.49)
	p16-9k-1-be1000.intf.routers.proxad.net (212.27.56.150)
	bzn-crs16-2-be1000.intf.routers.proxad.net (212.27.59.102)
	bzn-crs16-1-be1501.intf.routers.proxad.net (212.27.51.69)
	bzn-6k-sys.routers.proxad.net (212.27.60.254)

64 bytes from www.free.fr (212.27.48.10): icmp_req=2 ttl=55 time=29.4 ms	(same route)
...

Il existe aussi bien des options IPv4 qui sont dépassées et officiellement abandonnées (cf. RFC 6814). C'est par exemple le cas de l'option 136, Stream Identifier, déjà marquée comme inutile par les RFC 1122 et RFC 1812 ou des options 11 et 12 (Probe MTU et Reply MTU), décrites dans le RFC 1063 et abandonnées depuis le RFC 1191. Même chose pour celles qui avaient été oubliées dans un grenier, puis officiellement abandonnées par le RFC 6814, comme l'option 82 (Traceroute) ou l'option 142 (VISA). La recommandation, pour toutes ces options abandonnées, est de jeter les paquets qui les contiennent. Notez que les trois options de débogage citées plus haut, ne sont pas abandonnées, juste citées comme dangereuses. Si la recommandation par défaut est la même (jeter les paquets), notre RFC demande également un mécanisme pour pouvoir les accepter, chose qu'il ne demande pas pour les options abandonnées.

Continuons avec l'option 68, Timestamp.

  • Elle permet d'enregistrer dans le paquet l'heure à laquelle le paquet a été traité par la machine,
  • Cela peut fournir des informations indiscrètes sur la dite machine, par exemple en utilisant son décalage temporel pour l'identifier (cf. « Remote Physical Device Fingerprinting » de Kohno, T., Broido, A., et kc. Claffy, dans les IEEE Transactions on Dependable and Secure Computing en 2005, qui utilise une technique légèrement différente),
  • Si on bloque cette option, des commandes comme ping -T ne marcheront plus mais, de toute façon, elles ne marchent pas toujours aujourd'hui, cette option étant souvent bloquée (mais on trouve encore des réseaux dont les opérateurs, non seulement ne jettent pas ces paquets, mais traitent l'option, et mettent l'estampille dans le paquet),
  • L'avis de notre RFC est de jeter les paquets avec cette option.

Si on trouve un réseau où cette option passe, notez que ping affiche les délais de manière relative (mais regardez le paquet avec Wireshark, vous verrez les vraies valeurs, qui sont absolues). En cas de non-synchronisation des horloges, comme ici, cela peut donner des temps négatifs (en milli-secondes) :

% ping -c 1 -T tsandaddr  www.example.org
[J'ai déjà vu des réseaux qui acceptaient cette option avec le
paramètre tsonly mais pas avec tsandaddr.]
...
TS: 	fooobar (192.168.2.4)	50202455 absolute
	192.168.2.254	-14
	vau75-1-v900.intf.nra.proxad.net (78.254.255.41)	19
	rke75-1-v902.intf.nra.proxad.net (78.254.255.45)	1
Unrecorded hops: 8

(Notez que huit routeurs ont ignoré cette option, ou tout simplement n'avaient plus de place pour mettre leur estampille, mais ont laissé passer le paquet.)

Et la 148, Router Alert ?

  • Normalisée dans le RFC 2113, elle demande aux routeurs intermédiaires d'examiner le contenu de l'option, qui contient des demandes pour eux (la liste des demandes possibles figure dans un registre IANA créé par le RFC 5350),
  • Obligeant le routeur à examiner en détail le paquet et à effectuer un traitement spécial, c'est évidemment une voie royale pour les attaques par déni de service, comme expliqué dans le RFC 6398,
  • Mais, si on la bloque, on bloque aussi les services qui l'utilisent comme RSVP (RFC 2205),
  • Elle ne devrait être utilisée que dans des environnements fermés et contrôlés. Comme le routeur ne sait pas s'il est dans un tel environnement, il devrait par défaut ignorer cette option (sans bloquer le paquet) et avoir un mécanisme pour demander son traitement ou, au contraire, pour jeter les paquets ayant cette option.

Autre option qui a un sens dans des environnements fermés (tous les réseaux IP ne sont pas connectés à l'Internet), l'option 130, DoD Basic Security Option.

  • Conçue pour les militaires, dans le RFC 1108, elle permet d'indiquer dans le paquet son niveau de sécurité, ce qui permet des politiques comme « ne pas transmettre les paquets Top Secret sur les lignes non chiffrées ». Elle est mise en œuvre dans plusieurs systèmes comme SELinux, Solaris ou Cisco IOS (voyez la documentation pour la configurer). Elle est effectivement utilisée, mais en général dans des réseaux à part, réservés à l'armée. Ces réseaux utilisent du matériel standard (PC / Linux, routeurs Cisco, etc) mais ne sont pas reliés à l'Internet public. Ironie de la normalisation, cette option avait été retirée du chemin des normes par l'IESG alors que son déploiement a plutôt augmenté depuis. Si vous voulez des détails sur ce mécanisme, vous pouvez consulter le RFC 5570, qui décrit une option similaire pour IPv6,
  • Cette option ne crée pas de problème de sécurité,
  • Si elle est bloquée, ce système de sécurité ne fonctionne plus,
  • Certes, elles n'est utilisée que dans des réseaux fermés. Mais comme un routeur ordinaire du marché n'a aucun moyen de savoir s'il est dans un tel réseau, le RFC déconseille fortement de jeter par défaut les paquets contenant cette option.

C'est un peu pareil pour son équivalent civil, l'option 134 (CIPSO, Commercial IP Security Option, pas normalisée dans un RFC mais dans un document FIPS), avec les mêmes recommandations de non-blocage. Elle aussi est mise en œuvre dans SELinux.

Et les options marquées comme expérimentales ? C'est le cas de la 25 (Quick Start).

  • Elle fait partie d'une expérience décrite dans le RFC 4782, d'un mécanisme permettant d'informer la couche transport sur la capacité du tuyau,
  • Elle permet plusieurs attaques par déni de service, aggravant la charge du routeur, ou bien encourageant TCP à avaler toute la capacité réseau avec une seule connexion,
  • Bloquer les paquets empêcherait Quick Start de fonctionner,
  • Notre RFC recommande plutôt d'ignorer cette option par défaut (ne pas bloquer les paquets, les transmettre ou les traiter, mais sans avoir tenu compte de l'option).

Bon, cela faisait une longue liste et encore, je n'ai pas répété toutes les options. Et les options inconnues (comme la numéro 42 que j'ai montré dans l'exemple Scapy), que faut-il faire ? La section 4.23 dit clairement qu'il faut les ignorer, faire comme si elles n'étaient pas là (c'était déjà écrit dans le RFC 1122, section 3.2.1.8, et le RFC 1812, section 4.2.2.6). Autrement, si le comportement par défaut était de jeter les paquets contenant des options inconnues, il serait impossible de déployer une nouvelle option ! Malheureusement, bien des middleboxes ont ce comportement (bloquer ce qu'on ne connait pas), ce qui contribue à l'ossification de l'Internet. Notez d'ailleurs que notre RFC renonce à appliquer les directives des RFC 1122 et RFC 1812 qui disaient qu'il ne fallait pas jeter les paquets portant les options inconnues, en aucun cas. Au contraire, ce nouveau RFC 7126 permet qu'il existe une méthode pour changer la configuration et jeter les paquets portant des options inconnues (chose qui existe déjà largement).


Téléchargez le RFC 7126


L'article seul

RFC 7123: Security Implications of IPv6 on IPv4 Networks

Date de publication du RFC : Février 2014
Auteur(s) du RFC : F. Gont (SI6 Networks/UTN-FRH), W. Liu (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 11 février 2014


La sécurité d'IPv6 a déjà fait couler beaucoup d'encre. Ce RFC se focalise sur un aspect particulier : la sécurité des techniques de transition/coexistence entre IPv4 et IPv6. En effet, l'incroyable retard que mettent beaucoup de FAI à déployer IPv6 fait que, bien, souvent, pour accéder à IPv6, on doit utiliser des techniques plus ou moins propres, qui étaient appelées autrefois, avec optimisme, « techniques de transition » et qu'on nomme souvent aujourd'hui « techniques de coexistence ». Ces techniques, en général conçues pour être un bouche-trou temporaire, n'ont pas forcément une architecture bien propre, et apportent souvent leurs problèmes de sécurité spécifiques.

Normalement, le problème aurait dû disparaitre depuis longtemps. Comme le pose le RFC 6540, de nos jours, IP veut dire IPv6 et tout devrait être en IPv6. Cela dispenserait de ces techniques de transition et de leurs problèmes. Malheureusement, on constate que bien des réseaux sont encore uniquement en IPv4 et que, pour les traverser, on est forcés de contourner le problème en utilisant une des techniques de transition. Ce RFC décrit les problèmes de sécurité qui peuvent en résulter. Il cible les réseaux d'organisations, pas les réseaux domestiques ou ceux des FAI. Quelques exemples de ces problèmes ?

  • Le NIDS peut être aveugle s'il n'analyse qu'IPv4 et que des machines parlent entre elles en IPv6,
  • Un pare-feu peut filtrer certains types de trafic en IPv4 et en être incapable en IPv6,
  • Même si le NIDS ou le pare-feu comprennent IPv6, l'administrateur du réseau peut se tromper et mettre, par accident, des politiques différentes en IPv4 et en IPv6 (peu de pare-feux ont un langage de configuration de haut niveau, permettant d'exprimer des règles communes à IPv4 et IPv6 d'un seul coup),
  • Les mécanismes de transition sont prévus pour échapper aux limitations d'un réseau archaïque, qui n'a encore qu'IPv4. Une conséquence peut donc être qu'ils permettent aussi d'échapper aux politiques de sécurité, en donnant à une machine une connexion à tout l'Internet, qu'elle n'était pas censée avoir (c'est notamment le cas de Teredo, et le NAT ne le bloque pas),
  • Si tout le trafic est censé passer par un VPN sécurisé, le trafic IPv6 est parfois oublié et passe alors en dehors du VPN.

Logiquement, tout cela ne devrait pas arriver : le trafic IPv6 devrait être soumis aux mêmes règles (bonnes ou mauvaises) que le trafic IPv4. Mais, en pratique, on observe que ce n'est pas toujours le cas.

Certains administrateurs réseau naïfs croient que, parce qu'ils ont décrété que le réseau était purement IPv4, ou tout simplement parce qu'ils ne connaissent pas IPv6, ils n'auront pas de trafic IPv6. Mais c'est faux (section 2 de notre RFC). La plupart des systèmes d'exploitation ayant désormais IPv6, et celui-ci étant activé par défaut, les machines peuvent se parler en IPv6. Même si les routeurs ne le laissent pas passer, les machines pourront souvent se parler avec leurs adresses locales au lien. Une politique de l'autruche (« je ne vois pas IPv6 donc il ne me voit pas ») n'est donc pas tenable.

La communication entre machines locales en IPv6 peut survenir par accident, sans que personne ne l'ait délibérement cherché. Mais il y a pire : un attaquant peut activer IPv6 en se faisant passer pour un routeur IPv6 et en envoyant des RA (Router Advertisement), fournissant ainsi aux machines une adresse IPv6 globale et peut-être une connectivité globale. Ces attaques (décrites dans l'article de Waters) sont mises en œuvre dans des logiciels comme la boîte à outils SI6 (décrite dans le cours de Fernando Gont), le méchant n'a donc rien à programmer lui-même.

Pour éviter certaines de ces attaques, on peut envisager de filtrer les paquets IPv6 dans les équipements réseau comme les commutateurs. S'ils permettent cela (il suffit de reconnaître le type 0x86dd dans l'en-tête Ethernet), on bloque ainsi le trafic IPv6, même interne. Mais c'est violent puisqu'on empêche tout trafic IPv6, on ne fait que rendre la future migration encore plus pénible. On peut aussi supprimer IPv6 de toutes les machines qui se connectent au réseau, ce qui nécessite d'avoir accès à toutes les machines, ce qui est difficile en dehors des réseaux à très haute sécurité. Sinon, pour ne bloquer que les attaques SLAAC, on peut utiliser le RA Guard du RFC 6105 (une technique équivalente, pas encore décrite dans un RFC, existe pour DHCP, le DHCP Shield).

Une bonne partie des techniques de transition/coexistence reposent sur des tunnels. Ceux-ci posent des problèmes de sécurité spécifiques (section 3 de notre RFC), qui ne sont d'ailleurs pas spécifiques à IPv6 : un tunnel IPv4-dans-IPv4 est tout aussi dangereux (RFC 6169). Le tunnel n'est pas forcément un danger : tout dépend de comment il est géré. Les mécanismes automatiques, sans gestion du tout, comme Teredo ou 6to4 sont les plus risqués. Le tunnel peut être dangereux par accident, mais aussi parce qu'un utilisateur peut délibérement s'en servir pour contourner les politiques de sécurité.

Si on souhaite empêcher les tunnels IPv6-dans-IPv4, le plus simple est en général de bloquer les paquets IPv4 utilisant le protocole (pas le port, attention) 41, qui désigne l'encapsulation d'IPv6 dans IPv4. Mais il existe des tas de variétés de tunnels, dont certainement pas forcément très bien standardisés (un tunnel IPv6-dans-IPv4 sur IPsec, sur TLS...). L'annexe A du RFC résume, dans un tableau synthétique, toutes les règles à mettre dans son pare-feu selon le type de tunnel qu'on veut bloquer.

Le tunnel le plus basique est 6in4. On met simplement le paquet IPv6 dans un paquet IPv4 de protocole 41, pas d'autres métadonnées, pas de protocole de configuration (c'est typiquement une configuration manuelle). Bloquer le protocole 41 suffit à les arrêter. Par exemple, avec Netfilter, sur Linux, on peut faire :

# iptables --append FORWARD --protocol 41 --jump DROP

Et les paquets du protocole 41 ne seront alors plus transmis par le routeur Linux. (Rappel : c'est bien le protocole - de transport - 41, pas le port 41. grep 41 /etc/protocols)

C'est la même chose, on l'a vu, pour bien des mécanismes de tunnels, par exemple pour le 6rd du RFC 5969.

Cela s'applique aussi à 6to4, décrit par le RFC 3056. Il pose bien des problèmes de sécurité, documentés dans le RFC 3964 et, souvent, on souhaiterait le bloquer mais en laissant passer les autres systèmes qui utilisent le protocole 41. On peut alors :

  • filtrer les paquets IPv4 sortants qui vont vers le préfixe 192.88.99.0/24,
  • ou filtrer les paquets IPv4 entrants qui viennent de 192.88.99.0/24 (RFC 3068),
  • (nécessite des capacités d'inspection du paquet plus avancées) filtrer les paquets IPv4 contenant un paquet IPv6 dont l'adresse source ou destination est dans 2002::/16.

Le RFC cite aussi la possibilité de filtrer spécifiquement les paquets à destination de, ou en provenance des relais 6to4 connus mais ceux-ci sont nombreux et changent tout le temps.

Et Teredo (RFC 4380) ? Il pose encore plus de problèmes de sécurité à l'administrateur, puisqu'il permet à un utilisateur de court-circuiter toutes les sécurités du réseau, parfois sans même le faire exprès. Il marche même derrière le NAT (encore un exemple montrant que le NAT ne fournit guère de sécurité). Teredo est surtout utilisé sur Windows puisqu'il est installé et activé par défaut sur ce système.

Teredo n'utilise pas le protocole 41 mais UDP. Le client Teredo se connecte à un serveur qui écoute sur le port 3544. Filtrer ce port est donc efficace... sauf qu'il existe des serveurs Teredo écoutant sur des ports non-standard. Au moins, cela évite les connexions accidentelles. Si le pare-feu a des capacités d'inspection profonde, il peut :

  • filtrer les paquets sortants qui contiennent de l'UDP et un paquet IPv6 en charge utile UDP, avec une adresse source dans 2001::/32,
  • filtrer les paquets entrants qui contiennent de l'UDP et un paquet IPv6 en charge utile UDP, avec une adresse destination dans 2001::/32.

Ces deux règles ont des faux positifs (charge utile UDP qui ressemble à de l'IPv6...) et les appliquer n'est pas toujours facile (par exemple, si les paquets sont fragmentés, il faut les réassembler). Autre solution pour bloquer Teredo : le client Windows obtient l'adresse du serveur en résolvant teredo.ipv6.microsoft.com. Bloquer ce nom sur les résolveurs DNS (par exemple avec RPZ) peut empêcher les connexions Teredo que ferait Windows par défaut. On peut aussi bloquer les adresses IP vers lesquelles ce nom résout (mais attention, elles changent). Cela ne protège que contre les connexions Teredo faites par défaut, pas contre un utilisateur qui va délibèrement chercher à contourner les règles, par exemple en utilisant des serveurs Teredo non connus.

Un protocole souvent utilisé pour la configuration d'un tunnel est TSP (RFC 5572), où le client se connecte à un intermédiaire, nommé tunnel broker, qui lui indique les paramètres du tunnel (qui utilisera ensuite le protocole 41). La connexion se fait en TCP ou en UDP, vers le port 3653, qu'on peut donc bloquer pour neutraliser TSP.

À noter que la seule raison envisagée jusqu'à présent dans ce RFC pour bloquer les tunnels était la sécurité mais la section 4 rappelle qu'il en existe une autre : empêcher les machines d'établir accidentellement une connexion IPv6 pourrie (par exemple parce qu'elle passe par 6to4), que les applications utiliseraient ensuite, obtenant des performances et une qualité de service très inférieures à ce qu'elles auraient eu avec l'IPv4 natif. C'est en effet un des gros problèmes d'IPv6 : beaucoup de machines croient avoir une connectivité IPv6 alors que celle-ci est incomplète ou de très mauvaise qualité. Bloquer les tentatives de former un tunnel peut donc améliorer l'expérience utilisateur (RFC 6555).

Le RFC envisage une autre solution pour éviter ce problème : laisser les tunnels se faire mais bloquer la résolution de noms pour le type DNS AAAA (adresse IPv6). Si le résolveur ment et supprime les réponses AAAA, les applications n'essaieront pas de se connecter en IPv6. Comme toutes les solutions où le résolveur ment, elle est difficilement compatible avec DNSSEC.


Téléchargez le RFC 7123


L'article seul

RFC 7120: Early IANA Allocation of Standards Track Code Points

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : M. Cotton (ICANN)
Première rédaction de cet article le 25 janvier 2014


Bien des protocoles réseaux nécessitent l'allocation de nombres particuliers, un numéro de protocole, une valeur pour une option, etc (ce que ce RFC nomme des « code points »). Cette allocation est typiquement stockée dans un registre IANA. Lorsque l'allocation nécessite un examen formel par l'IETF ou un de ses groupes et comités, un problème d'œuf et de poule surgit : pour avoir l'allocation du nombre, il faut un document, par exemple un RFC mais pour publier ce document, il faut une allocation du nombre. Pour briser ce cercle vicieux, ce RFC, héritier du RFC 4020, expose les règles selon lesquelles l'IANA peut allouer un nombre avant une publication formelle d'une norme.

Les politiques d'allocation de nombres et autres code points à l'IETF sont exposées dans le RFC 5226. Dans certains cas, le problème ne se pose pas. Par exemple, la politique PAPS « Premier Arrivé, Premier Servi » (First come, first served), où toute requête est acceptable et est faite dans l'ordre d'arrivée, ne nécessite pas de document publié et peut donc se faire sans tambours ni trompettes. Même chose pour « Examen par un expert » (Expert review). Par contre, certaines politiques sont plus restrictives, par exemple parce que l'espace de nommage utilisé est très étroit et qu'il faut l'utiliser prudemment. La politique « Examen par l'IETF » (IETF review) impose par exemple un RFC et pas n'importe lequel. La politique « Action de normalisation » (Standards action) impose en outre que ce RFC soit sur le « chemin des normes ». Dans ces deux cas, on a le problème d'œuf et de poule mentionné plus haut. Parfois, les auteurs d'un protocole résolvent le problème « à la rache » en s'attribuant d'autorité un numéro qui leur semble libre et en l'utilisant dans le futur RFC... et dans des mises en œuvre du protocole qui sont testées sur le réseau. Si l'IANA choisit ensuite d'allouer un autre numéro au moment de la normalisation, des ennuis sans nombre vont surgir. Par exemple, les premières mises en œuvre n'interagiront pas avec celles qui ont été faites après la normalisation.

Faut-il taper sur ces auteurs trop pressés ? Non, car ce n'est pas entièrement de leur faute : le processus de normalisation est long, très long, et on ne peut pas décemment leur reprocher d'avoir voulu essayer leur nouveau jouet à l'avance. En outre, c'est dans l'intérêt général que les nouveaux protocoles soient testés pour de bon, avant la publication officielle de la norme. Cela permet d'éliminer les mauvaises idées au feu de la réalité. Cette importance donné aux « programmes qui marchent » (running code) est justement un des points qui a assuré le succès de l'IETF face à des SDO concurrentes. D'ailleurs, les règles de certains groupes à l'IETF imposent ce déploiement avant la normalisation (voir par exemple le RFC 4794 qui a remplacé le RFC 1264, qui était encore plus radical).

Donc, puisque ces allocations précoces (early allocations) sont une bonne chose, quelles règles doivent-elles suivre ? La section 2 de notre RFC impose que toutes ces conditions soient remplies avant qu'une allocation précoce soit acceptée :

  • La politique d'allocation pour l'espace de nommage considéré doit être « Norme nécessaire » (si cette norme est un RFC), « RFC obligatoire », « Examen par l'IETF », ou « Action de normalisation ». (La liste de ces politiques était bien plus courte dans le RFC 4020.)
  • Un document Internet-Draft doit exister, décrivant le protocole ou le système qui a besoin de cette allocation. Rappelons qu'un Internet-Draft ne nécessite pas d'autorisation et peut être publié sans formalités.
  • La spécification dans cet Internet-Draft doit être stable, le protocole ne doit plus changer de manière incompatible (ce qui nécessiterait d'allouer un nouveau numéro après).
  • Les présidents du groupe de travail et les directeurs de zone d'activité IETF doivent approuver cette allocation, en prenant en compte l'intérêt de la communauté pour ce nouveau protocole.

C'est contraignant, mais le but est d'éviter les abus qui mèneraient à un épuisement rapide d'un des registres IANA (cf. section 5).

Une fois ces prérequis rassemblés, les auteurs de l'Internet-Draft font une requête à l'IANA. Celle-ci alloue le nouveau numéro ou code point, et le marque comme Temporaire, en indiquant la date. En effet, une allocation précoce n'est valable qu'un an. Au bout d'un an, elle doit avoir été transformée en allocation ferme, ou bien renouvelée en répétant tout le processus. Sinon, elle sera marquée comme expirée (pas de réutilisation possible) puis comme abandonnée (réutilisation possible, s'il n'y a pas de mises en œuvre du protocole qui trainent, et si l'espace de nommage est presque épuisé).

Un exemple d'un enregistrement temporaire ? Aujourd'hui, vous trouvez par exemple la valeur 5 dans les modes de réponse du test de connectivité de MPLS : https://www.iana.org/assignments/mpls-lsp-ping-parameters/mpls-lsp-ping-parameters.xml#reply-modes note « 5 - Reply via specified path (TEMPORARY - expires 2012-01-20) [sic] ».

Pas de changements drastiques depuis le RFC 4020, le principal étant l'extension des allocations précoces à d'autres politiques d'allocation. Il y a eu peu de débats sur ce nouveau RFC : après tout, il s'agit de cas spécifiques qui ne concernent pas tous les participants à l'IETF.


Téléchargez le RFC 7120


L'article seul

RFC 7118: The WebSocket Protocol as a Transport for the Session Initiation Protocol (SIP)

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : I. Baz Castillo, J. Millan Villegas (Versatica), V. Pascual (Quobis)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF sipcore
Première rédaction de cet article le 29 janvier 2014


Aujourd'hui, de plus en plus de communications sur l'Internet passent sur le port 80, celui de HTTP, parce que c'est souvent le seul que des réseaux d'accès fermés et mal gérés laissent passer. Le protocole WebSocket a été créé juste pour cela, pour fournir un « nouveau TCP » aux applications, notamment celles tournant dans un navigateur Web. Ce nouveau RFC normalise le transport du protocole de communciation SIP sur WebSocket. Une de ses applications sera le développement de softphones sous forme d'applications JavaScript. « Téléphonie IP over Web », en somme.

Le principe de WebSocket, normalisé dans le RFC 6455, est d'ouvrir une connexion HTTP (donc, sur TCP et, éventuellement, sur TLS) puis de la transformer en un canal permanent et bi-directionnel. Sur ce canal passent des messages (et pas un flot d'octets non structuré comme avec TCP). Tous les gros (très gros) navigateurs récents ont déjà un client WebSocket et en permettent l'accès aux applications JavaScript via l'API officielle. Dans le futur, on pourra voir d'autres clients WebSocket, par exemple sous forme d'une bibliothèque pour les programmeurs de smartphones.

Un concept important de WebSocket est celui de sous-protocole (section 1.9 du RFC 6455), un protocole applicatif au dessus de WebSocket. Indiqué par l'en-tête Sec-WebSocket-Protocol:, ce sous-protocole permet d'indiquer l'application qui va utiliser WebSocket, ici SIP.

Voici donc (section 4 de notre RFC) une demande de transformation d'un canal HTTP ordinaire en WebSocket, pour le sous-protocole SIP :

GET / HTTP/1.1
Host: sip-ws.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://www.example.com
Sec-WebSocket-Protocol: sip
Sec-WebSocket-Version: 13

Si elle est acceptée par le serveur HTTP, cette demande produira un canal WebSocket de sous-protocole sip. Voici une réponse positive du serveur :

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: sip

Le sous-protocole SIP est désormais dans le registre IANA des sous-protocoles WebSocket.

WebSocket peut avoir des messages textes ou binaires. SIP peut utiliser des données textes ou binaires (pas dans les en-têtes mais dans le corps des messages SIP). Donc, clients et serveurs SIP-sur-WebSocket doivent gérer les deux types de messages.

WebSocket fournit un transport fiable (section 5) donc SIP n'a pas besoin de prévoir de retransmission. Chaque message SIP se met dans un et un seul message WebSocket et chaque message WebSocket ne contient qu'un seul message SIP. Comme WebSocket a son propre mécanisme d'indication de la longueur, le champ Content-Length: de SIP (section 20.14 du RFC 3261) est inutile.

Le champ Transport de l'en-tête Via: de SIP (section 20.42 du RFC 3261) vaut WS (ou WSS si TLS est utilisé) lorsque les messages SIP sont transportés sur WebSocket. Le paramètre received de cet en-tête Via:, qui indique normalement l'adresse IP du client, n'a guère de sens pour WebSocket, où le passage par un relais HTTP sera probablement fréquent. Et il est inutile puisque la réponse peut uniquement être transmise sur la connexion WebSocket. Le RFC 3261, section 18.2.1 est donc modifié pour rendre ce received facultatif. Ah, et, sinon, dans un URI SIP, ws: ou wss: (S pour secure) indique l'utilisation de WebSocket. On verra par exemple wss://sip.example.com:8443/ (comme dans la documentation de JSSIP). Pour trouver un serveur SIP WebSocket en utilisant NAPTR (RFC 3263), on met la valeur SIP+D2W dans l'enregistrement NAPTR (valeur désormais notée dans le registre IANA). Mais c'est purement théorique puisque, malheureusement, le code JavaScript ne peut en général pas faire de requête DNS de type NAPTR (c'est hélas pareil pour les SRV).

La section 8 fournit des nombreux exemples de dialogues SIP sur WebSocket. Par exemple, lorsqu'Alice, utilisant son navigateur Web, charge la page avec le code SIP-sur-WebSocket, elle va commencer par s'enregistrer auprès de son serveur SIP, ici codé en dur comme étant proxy.example.com. Elle commence en HTTP :

GET / HTTP/1.1
Host: proxy.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: https://www.example.com
Sec-WebSocket-Protocol: sip
Sec-WebSocket-Version: 13

Et, lorsque la connexion WebSocket est acceptée, elle continue en SIP :


REGISTER sip:proxy.example.com SIP/2.0
Via: SIP/2.0/WSS df7jal23ls0d.invalid;branch=z9hG4bKasudf
From: sip:alice@example.com;tag=65bnmj.34asd
To: sip:alice@example.com
Call-ID: aiuy7k9njasd
CSeq: 1 REGISTER
Max-Forwards: 70
Supported: path, outbound, gruu
Contact: <sip:alice@df7jal23ls0d.invalid;transport=ws>
     ;reg-id=1
     ;+sip.instance="<urn:uuid:f81-7dec-14a06cf1>"

Notez le .invalid dans l'adresse mise en Contact:, parce que le code JavaScript n'a pas de moyen de déterminer l'adresse IP locale. Notez aussi que TLS était utilisé, d'où le WSS dans le Via:.

Ensuite, Alice appelle l'habituel Bob en envoyant le message SIP :


INVITE sip:bob@example.com SIP/2.0
Via: SIP/2.0/WSS df7jal23ls0d.invalid;branch=z9hG4bK56sdasks
From: sip:alice@example.com;tag=asdyka899
To: sip:bob@example.com
Call-ID: asidkj3ss
CSeq: 1 INVITE
Max-Forwards: 70
Supported: path, outbound, gruu
Route: <sip:proxy.example.com:443;transport=ws;lr>
Contact: <sip:alice@example.com
    ;gr=urn:uuid:f81-7dec-14a06cf1;ob>
Content-Type: application/sdp
...

Le relais proxy.example.com va alors router cet appel vers Bob (pas forcément avec WebSocket, dans l'exemple de la section 8 de notre RFC, c'est UDP qui est utilisé) et le relais va dire à Alice que c'est bon :


SIP/2.0 200 OK
Via: SIP/2.0/WSS df7jal23ls0d.invalid;branch=z9hG4bK56sdasks
Record-Route: <sip:proxy.example.com;transport=udp;lr>,
     <sip:h7kjh12s@proxy.example.com:443;transport=ws;lr>
From: sip:alice@example.com;tag=asdyka899
To: sip:bob@example.com;tag=bmqkjhsd
Call-ID: asidkj3ss
CSeq: 1 INVITE
Contact: <sip:bob@203.0.113.22:5060;transport=udp>
Content-Type: application/sdp

Il y a apparemment au moins deux mises en œuvre de ce mécanisme, comme JSSIP, SIP router (c'est documenté) ou encore OverSIP (voir sa documentation WebSocket). L'annexe B du RFC donne des détails pour les programmeurs.


Téléchargez le RFC 7118


L'article seul

RFC 7115: RPKI-Based Origin Validation Operation

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : R. Bush (Internet Initiative Japan)
Réalisé dans le cadre du groupe de travail IETF sidr
Première rédaction de cet article le 15 janvier 2014


Le mécanisme de sécurisation des annonces de route pour BGP, connu sous le nom de RPKI+ROA, est normalisé depuis un an et il existe désormais un peu d'expérience opérationnelle. Que nous enseigne-t-elle ? Peut-on commencer à définir des « bonnes pratiques » de déploiement et de fonctionnement de la RPKI ?

Outre la publication des normes sur RPKI+ROA, comme le RFC 6480, il existe plusieurs logiciels permettant de mettre en œuvre ces normes. On trouve encore peu de comptes-rendus d'expérience concrète avec la RPKI. En français, je vous recommande fortement l'excellent mémoire de master de Guillaume Lucas. Il faut dire qu'on en est encore aux débuts (ce qui explique la faible taille de ce nouveau RFC). Par exemple, il n'existe toujours pas de point de départ (trust anchor) unique pour la validation, chaque RIR ayant son propre certificat, chacun étant une racine pour la validation. Le RFC estime qu'une racine unique finira par apparaître, ce dont je doute fort, en raison des nombreux conflits de gouvernance à ce sujet.

Notre nouveau RFC, ce RFC 7115, a une vision très optimiste : il affirme même que, déployée intelligemment et prudemment, RPKI+ROA entraînera peu de perturbations du système de routage de l'Internet. L'expérience récente de DNSSEC semble pourtant indiquer le contraire, à savoir qu'il n'est pas trivial de déployer de la sécurité cryptographique et qu'on casse parfois quelque chose en le faisant. À moins que les gens de BGP soient bien plus compétents que ceux du DNS ?

Bon, assez de généralités, place aux recommandations concrètes. N'oubliez pas d'abord de lire les RFC RPKI+ROA. Puis, attaquons la section 3, le cœur de ce nouveau RFC. La RPKI est la base de données répartie (RFC 6481) stockant les autorisations de routage (les ROA, RFC 6482), les certificats (RFC 6484), les révocations, les enregistrements Ghostbuster (RFC 6493), etc. Elle a été conçue pour être distribuée de manière hiérarchique, des dépôts mondiaux nourrissant des dépôts plus locaux qui à leur tout nourriraient des dépôts très locaux. En pratique, cela ne semble pas encore très fréquent : l'architecture la plus courante semble être encore à deux étages, le dépôt du RIR et celui de l'opérateur. Notez qu'on peut parfaitement utiliser des dépôts et des caches validateurs situés dans un autre réseau que le sien, par exemple chez son transitaire : si on lui fait confiance pour router les paquets, on peut bien lui faire confiance pour gérer la RPKI, et s'appuyer sur son travail.

Le cache validateur, dans le réseau de l'opérateur, collecte toutes les données de la RPKI (en utilisant rsync) et les valide en utilisant un logiciel comme rcynic ou le validateur du RIPE-NCC. Les routeurs qui font confiance à ce cache iront alors chercher ces informations sur la validité des routes (typiquement en utilisant le protocole RTR du RFC 6810), sans avoir à faire de crypto eux-mêmes. Cela impose que les routeurs soient configurés uniquement avec des adresses de caches validateurs de confiance. Et que la connexion entre le routeur et le cache soit bien sécurisée, par exemple par SSH, particulièrement si le cache validateur est dans un AS différent. Pour des raisons de résilience, le cache doit être joignable sans avoir besoin de ressources extérieures, comme le DNS ou comme la RPKI elle-même (si le routeur devait valider la route vers le cache, on aurait un beau problème de bootstrap). Il vaut sans doute mieux que les routes entre le routeur et le cache validateur ne dépendent pas du tout de BGP. Et, toujours pour la résilience, un routeur devrait utiliser plusieurs caches (comme une machine a plusieurs résolveurs DNS).

La validation dans la RPKI est arborescente : on part d'un certificat d'une autorité de confiance, le TAL (Trust Anchor Locator, cf. RFC 7730 et, oui, je simplifie parce que le TAL est en fait un pointeur vers le certificat), et on valide récursivement les certificats des titulaires de ressources (adresses IP, par exemple) à partir de ces TAL. Si le gérant d'un cache validateur met n'importe quoi comme TAL (des certificats mal ou pas gérés), toute la confiance s'écroule. Il faut donc bien choisir ses TAL ! Voici un contre-exemple, une installation de rcynic où ont été installées toutes les TAL possibles, test et production mêlées :

% ls etc/trust-anchors 
afrinic.tal	 lacnic.tal	    testbed-apnicrpki.tal
apnic.tal	 ripe-ncc-root.tal  testbed-arin.tal
bbn-testbed.tal  testbed-apnic.tal  testbed-ripe.tal
% cat etc/trust-anchors/ripe-ncc-root.tal 
rsync://rpki.ripe.net/ta/ripe-ncc-ta.cer
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0URYSGqUz2m
yBsOzeW1jQ6NsxNvlLMyhWknvnl8NiBCs/T/S2XuNKQNZ+wBZxIgPPV
...

Le RFC insiste ensuite sur un des points les plus faibles de la RPKI : les délais de mise à jour ne sont spécifiés nulle part (voir aussi la section 6 du RFC, qui revient sur ce problème). Un cache validateur pourrait, par exemple, ne charger les données avec rsync que deux fois par semaine et travailler ainsi avec des données relativement anciennes, sans violer aucune norme technique. (La section 6 du RFC prétend que c'est la même chose avec le DNS, qui n'est que « synchrone à terme ». Mais c'est tout à fait faux : dans le DNS, les délais sont parfaitement connus et standards, le principal étant le TTL.) À l'intérieur de son réseau, un opérateur qui a plusieurs caches peut décider de les synchroniser très fréquemment : ce sont ses machines, il décide. Mais, à l'extérieur, même si ce RFC n'en parle pas, il n'est pas du tout sûr que les serveurs rsync des RIR résistent en cas de synchronisation trop agressive.

Après ces questions d'architecture de la validation, la section 3 de notre RFC continue avec la création des ROA (Route Origin Authorizations, les objets signés qui authentifient la prétention d'un AS à être à l'origine de l'annonce BGP d'un préfixe). D'abord, bien se rappeler qu'IP est arborescent : un ROA pour 192.0.2.0/24 peut concerner aussi 192.0.2.128/26. Avant d'émettre un ROA couvrant un gros préfixe, il faut donc être sûr que tous les préfixes inférieurs qui auront besoin d'être routés ont déjà des ROA corrects. Sinon, toutes leurs annonces deviendront subitement invalides.

Les ROA disposent d'un attribut maxLength qui permet d'être un peu laxiste en cas d'annonce d'un sous-préfixe. Si le ROA concerne le préfixe 192.0.2.0/24-26 (avec 24 = longueur du préfixe, et 26 = longueur maximale des annonces), une annonce 192.0.2.128/26 sera acceptée (alors que 192.0.2.128/27 serait refusée). Mais c'est dangereux car une annonce plus spécifique (préfixe plus long) créera une entrée prioritaire dans la table de routage (IP donnant la priorité au préfixe le plus long), facilitant le détournement que RPKI+ROA avait pour mission d'empêcher. Le RFC conseille donc, d'abord que les logiciels de gestion de la RPKI mettent, par défaut, une longueur maximale égale à la longueur du préfixe (aucun sous-préfixe autorisé) et ensuite que maxLength soit utilisé avec précaution. Si on a juste trois sous-préfixes, il vaut sans doute mieux générer trois ROA pour eux, plutôt que d'affaiblir la sécurité en ayant une longueur maximale supérieure à la longueur du préfixe. (Ou un seul ROA contenant trois préfixes s'ils ont tous le même AS d'origine.)

On l'oublie souvent, mais un préfixe peut être « multi-origine », c'est-à-dire être annoncé par plusieurs AS. C'est même recommandé dans certains cas, par le RFC 6382. Dans ce cas, il faut faire autant de ROA qu'il y a d'AS d'origine possibles (un ROA peut contenir plusieurs préfixes mais pas plusieurs AS).

Enfin (il y a aussi plein d'autres recommandations que je n'ai pas reprises ici), le RFC recommande d'utiliser des outils automatiques pour superviser ses objets RPKI et, par exemple, avertir lors de l'expiration proche d'un certificat (comme on devrait le faire pour tous les certificats).

Au fait, à quel endroit du réseau doit-on installer les routeurs qui utiliseront la validation ? La section 4 se penche sur cette question. A priori, seuls les routeurs de bord, ceux situés au contact d'un autre AS, seront dans ce cas. Les autres routeurs font confiance aux routes distribuées en interne. On peut même déployer cette utilisation de la validation de manière incrémentale, un routeur après l'autre. Mais attention à la répartition du trafic : les premiers routeurs qui utiliseront la validation pourront refuser certaines routes, que les autres accepteront, menant à des déplacements de trafic d'un lien vers un autre.

J'ai dit que les routeurs qui utilisent la validation pourraient refuser certaines routes. Justement, que doit faire un routeur qui se connecte à un cache validateur lorsque ledit cache a marqué une route comme invalide (cf. RFC 6811 pour les différents résultats de validation) ? La section 5 du RFC décrit les politiques possibles. Le principe cardinal est « chaque opérateur décide ». Ce n'est pas le RFC qui décide de ce que doit faire le routeur.

L'approche radicale serait évidemment que le routeur rejette les routes invalides. Mais, si on se fie au déploiement d'autres techniques de sécurité comme DNSSEC, au début, il y aura plein d'erreurs par les opérateurs et bien des routes seront marquées à tort comme invalides. Rejeter ces routes dès le début serait sans doute une erreur. Il vaudrait sans doute mieux commencer par une approche moins violente, se contentant d'attribuer une priorité plus basse aux routes invalides.

Le problème est que cela permet des attaques avec des préfixes plus spécifiques, comme dans l'exemple plus haut. Soit un ROA 192.0.2.0/24-24 (le 24-24 indiquant que la longueur du préfixe et la longueur maximale admise sont la même, 24 bits). Un méchant annonce 192.0.2.128/26. Cette annonce sera marquée comme invalide par le système RPKI+ROA. Mais si elle est quand même acceptée, même avec la priorité la plus basse, elle s'installera dans les tables de routage et, étant plus spécifique que 192.0.2.0/24, elle gagnera, et les paquets IP seront envoyés à l'endroit désigné par l'annonce du méchant. Bref, pas de solution idéale à ce dilemme, le RFC suggère néanmoins de ne pas accepter les routes invalides sans une bonne raison.

Et si le résultat de la validation est qu'aucun ROA couvrant cette annonce n'a été trouvé (le cas le plus fréquent aujourd'hui, où seule une minorité de préfixes sont signés) ? Le RFC recommande évidemment d'accepter ces routes. Ce n'est pas demain la veille qu'on pourra dire « quasiment tout le monde a des ROA, arrêtons de router les autres ».

Enfin, la section 6 couvre quelques recommandations diverses : avoir des mécanismes spéciaux pour les préfixes « importants », par exemple ceux des serveurs racine du DNS, afin d'être prévenu si la RPKI veut tout à coup les invalider, gérer les AS sur quatre octets du RFC 6793, et avoir des horloges à l'heure, puisque certificats et ROA peuvent expirer.

Le but de RPKI+ROA est d'améliorer la sécurité du routage Internet, notamment face à des détournements comme celui de YouTube par Pakistan Telecom. Cet objectif est-il atteint ? La section 7 de notre RFC appelle à la prudence : les ROA, comme leur nom l'indique, ne protègent que l'origine d'une annonce (l'AS le plus à droite dans un chemin d'AS). Dans quasiment tous les détournements accidentels (comme celui de Pakistan Telecom cité plus tôt), l'origine est changée et RPKI+ROA le détecterait donc. Mais, si le détournement n'est pas un accident mais une attaque délibérée, on peut penser que le méchant va soigner ses annonces BGP. Il mettra probablement la vraie origine et ne bricolera que la suite du chemin. Pour l'instant, la RPKI n'a pas de mécanisme pour faire face à cela. De même, toute manipulation du chemin faite après l'émission par l'AS d'origine ne sera pas détectée, tant que l'origine est respectée.

Ah, et une autre limite de ce système : BGP ne fait que transmettre des annonces de route, que les routeurs ne respectent pas forcément (« les données ne suivent pas forcément le contrôle »). Donc, même si BGP est parfaitement sécurisé, des routeurs défaillants ou piratés peuvent encore faire échouer la sécurité.

Une bonne lecture concrète en français sur le système RPKI+ROA ? « Sécuriser le routage sur Internet » de Guillaume Lucas. Sinon, il existe une liste de diffusion des opérateurs RPKI mais avec très peu de trafic.

Merci à Guillaume Lucas pour sa relecture très attentive, mais cela ne veut pas dire qu'il est d'accord avec tout.


Téléchargez le RFC 7115


L'article seul

RFC 7113: Implementation Advice for IPv6 Router Advertisement Guard (RA-Guard)

Date de publication du RFC : Février 2014
Auteur(s) du RFC : F. Gont (UK CPNI)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 12 février 2014


La sécurité, ce n'est pas facile et il faut faire attention à beaucoup de choses. Ce RFC est entièrement consacré à un oubli de pas mal de programmeurs lorsqu'ils mettent en œuvre une technique de sécurité pour IPv6, le RA guard : il est en effet courant d'oublier qu'un paquet IPv6 peut avoir plusieurs en-têtes, chaînés, et que chercher un motif dans le paquet, à un nombre d'octets fixes depuis le début du paquet, est une mauvaise stratégie. (Le RFC décrit également un second problème, lié à la fragmentation.)

Le RA guard est une protection contre les RAcailles, ces annonces d'un routeur IPv6 (RA = Router Advertisement) qui ne sont pas émises par un routeur légitime. Les RAcailles sont un phénomène courant, en général provoqué par une erreur de configuration mais elles peuvent aussi être utilisées pour une attaque. Dans ce cas, le méchant s'annonce lui-même comme le routeur du réseau, reçoit donc le trafic et peut alors le jeter, l'espionner, le détourner, ou autres méchancetés. (Le RFC 6104 pose le problème.)

Il n'est pas facile de lutter contre ce phénomène, tout en gardant la simplicité de l'auto-configuration sur le réseau local (si on renonce à la simplicité, il existe une solution, le RFC 3971). Le problème est d'ailleurs le même avec DHCP depuis longtemps (le méchant peut générer de fausses réponses DHCP). Comme le problème est ancien, il y a longtemps que des solutions sont déployées en IPv4. Typiquement, le commutateur examine les paquets (oui, de la DPI), regarde si c'est une réponse DHCP et, si c'est le cas et que le port du commutateur n'est pas censé abriter un serveur DHCP, on jette le paquet. (Il existe plusieurs méthodes pour déterminer si un serveur DHCP légitime est sur ce port, de la confiugration manuelle, jusqu'à l'écoute préalable, pour apprendre automatiquement.)

Cette méthode peut s'étendre facilement aux annonces de routeur d'IPv6, les RA : le RFC 6105 la décrit en détail, sous le nom de RA guard. Mais les premières mises en œuvre ont souvent souffert d'un oubli de la part des programmeurs.

En effet, pour examiner la charge utile du paquet, il faut sauter l'en-tête IP. En IPv4, il est de taille variable et il faut donc lire le champ Longueur, sauter le bon nombre d'octets et on regarde alors la charge utile. En IPv6, l'en-tête étant de taille fixe, cela semble plus facile et c'est ce qui a trompé pas mal d'implémenteurs. Car plusieurs ont fait la même erreur : oublier les en-têtes d'extensions. IPv6 permet en effet d'ajouter plusieurs en-têtes entre l'en-tête principal et la charge utile. Pour contourner le RA Guard, tout ce qu'avait à faire le méchant était d'ajouter un de ces en-têtes, décalant ainsi la charge utile et empêchant sa reconnaissance.

Le problème est bien connu, j'avais même fait un article là-dessus il y a quatre ans mais il y avait de nombreuses autres analyses avant. Mais les programmeurs d'engins réseaux comme les commutateurs ne prennent pas toujours le temps de se renseigner : le marketing dit « nos clients réclament du RA Guard, il faut qu'on puisse l'écrire sur la feuille de spécifications, et ça doit être livré avant-hier », le programmeur programme et cela semble marcher avec des paquets normaux, personne ne fait de tests avec des paquets inhabituels, précisement ceux qu'utilisera l'attaquant.

Ce RFC 7113 rappelle donc qu'un commutateur qui met en œuvre RA Guard doit analyser tous les en-têtes, pas seulement sauter le premier. Sinon, cette protection ne vaut pas grand'chose. À noter que le RFC se focalise sur le cas des RA Guard mais, en fait, des tas de systèmes de sécurité IPv6, des IDS aux limiteurs de trafic ont exactement la même vulnérabilité : en ajoutant un simple en-tête Destination, vous passez outre la plupart des contrôles. (Des logiciels très utiles comme NDPmon, ramond ou rafixd sont apparemment vulnérables.)

Cette première attaque est exposée en section 2.1. On peut noter qu'il n'existe actuellement aucun usage légitime des en-têtes d'extension dans une annonce RA. Mais l'attaque marche car les mises en œuvre de RA guard n'en tiennent pas compte.

Une deuxième attaque, fondée sur la fragmentation, est décrite en section 2.2. L'idée est de fragmenter l'annonce RA en deux paquets IP, les bits qui permettent d'identifier le paquet comme une annonce RA étant dans le deuxième fragment. Si le commutateur ne fait pas de réassemblage des paquets, il ne pourra pas détecter la RAcaille et donc pas le bloquer. Toutes les implémentations testées par l'auteur du RFC sont vulnérables.

Bon, c'est bien joli de décrire les attaques mais comment réparer ? La section 3 décrit les obligations d'un système de RA GUard sérieux :

  • Si le paquet a une adresse source qui n'est pas locale au lien (les adresses locales au lien sont dans le préfixe fe80::/10), le laisser passer. Un RA doit toujours avoir une adresse source locale au lien (puisqu'il est forcément générer par un routeur connecté au lien) donc inutile d'examiner ce paquet, si c'est une RAcaille, il sera refusé de toute façon (RFC 4861, section 6.1.2).
  • Si le nombre de sauts maximum (champ Hop Limit) n'est pas à 255, laisser passer le paquet. Les RA utilisent ce champ comme protection contre une injection de RA par une machine extérieure au réseau local. S'il est à moins de 255, ce qui indique qu'il a traversé au moins un routeur, il sera rejeté par les machines terminales donc, comme dans le cas précédent, pas la peine de se fatiguer à l'examiner.
  • Si le paquet est un fragment et n'est pas le premier fragment d'une série, le laisser passer (en raison de la règle suivante).
  • Le système RA Guard doit analyser tous les en-têtes, pas juste le premier. Cette tâche est complexe mais elle a été rendue plus facile par le RFC 6564. En outre, le RFC 7112 impose que la totalité des en-têtes soient dans le premier fragment, ce qui fait qu'il n'y a pas besoin de réassembler le paquet d'origine pour effectuer cette analyse (on a désormais le droit de jeter les paquets où le premier fragment ne contient pas toute la chaîne d'en-têtes). Par contre, le RFC interdit à RA Guard de se limiter aux N premiers octets : il faut analyser tout le paquet (les en-têtes d'extension peuvent être arbitrairement grands).
  • Ensuite, on peut appliquer l'algorithme RA Guard classique : si le paquet est un RA et que ce n'est pas autorisé sur ce port, le jeter. Autrement, le laisser passer.

À noter que les paquets ESP (RFC 4303) seront toujours acceptés (puisque le RA est après l'en-tête ESP, qui est considéré comme l'en-tête final d'IP). C'est logique : c'est IPsec qui, dans ce cas, assure la sécurité des paquets, RA Guard s'efface alors devant IPsec.

Un dernier détail lié à la fragmentation : IPv6 permettait à l'origine des fragments non-disjoints. Ces fragments arriveraient à passer les règles ci-dessus. Mais ils ont été interdits par le RFC 5722 et l'étude « IPv6 NIDS evasion and improvements in IPv6 fragmentation/reassembly » montrait, qu'en 2012, la plupart des mises en œuvre d'IPv6 faisaient respecter cette interdiction. Plus radical, le RFC 6980 interdit complètement la fragmentation pour les RA mais il ne sera pas déployé immédiatement dans toutes les machines terminales, donc RA Guard ne peut pas encore compter dessus.

Un document équivalent pour DHCP sera publié comme RFC, pour l'instant, c'est l'Internet-Draft draft-ietf-opsec-dhcpv6-shield, qui utilise les mêmes techniques que notre RFC 7113.

Si vous voulez tenter les attaques décrites ici, vous avez la boîte à outils de SI6 ou bien l'ensemble logiciel THC.


Téléchargez le RFC 7113


L'article seul

RFC 7112: Implications of Oversized IPv6 Header Chains

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : F. Gont (SI6 Networks / UTN-FRH), V. Manral (Hewlett-Packard), R. Bonica (Juniper Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 29 janvier 2014


Résumer ce nouveau RFC en deux mots ? Il dit qu'il ne faut pas, lorsque des paquets IPv6 sont fragmentés, que les en-têtes d'extension se retrouvent dans des fragments différents. Tous ces en-têtes doivent être dans le premier fragment, pour des raisons de sécurité.

Ces en-têtes d'extension, une nouveauté d'IPv6, ont causé bien des casse-têtes aux développeurs, par exemple pour suivre la chaîne qu'ils représentent. Normalisés dans la section 4 du RFC 2460, ils n'ont connu à leur début aucune limite : leur nombre pouvait être quelconque (contrairement à ce qui se passe pour IPv4, où la place réservée aux options a une taille maximale, de 40 octets). Rien ne s'opposait donc à ce que la chaîne de ces en-têtes, avant l'en-tête de transport, soit trop grosse pour tenir dans un seul fragment et soit donc coupée, une partie des en-têtes se retrouvant dans les fragments suivants. Je vous rassure tout de suite, de telles chaînes délirantes n'arrivent jamais en vrai mais, comme les logiciels étaient obligés de les gérer, elles auraient pu être créées et exploitées par des attaquants. Par exemple, un attaquant peut fabriquer délibérement une chaîne d'en-têtes très longue, de façon à ce que les informations de la couche transport soient dans le deuxième paquet, que certains IDS ne verront pas.

La liste des en-têtes d'extension possible est, depuis le RFC 7045, dans un registre IANA. Dans un paquet IPv6, ces en-têtes sont organisés en une chaîne, chaque en-tête ayant un champ Next Header qui indique le type de l'en-tête suivant. La chaîne se termine par un en-tête du protocole de transport (typiquement TCP ou UDP), par un nouvel en-tête IPv6 (dans le cas d'une encapsulation IPv6-dans-IPv6), par un en-tête IPsec, ou bien par un en-tête dont le champ Next Header vaut 59, indiquant que rien ne le suit. Analyser cette chaîne est non trivial, mais c'est nécessaire pour le filtrage ou l'observation. Un pare-feu à qui on dit « tu bloques tout sauf les paquets TCP à destination des ports 22 et 80 » a besoin d'analyser la chaîne des en-têtes, puisqu'il doit arriver à l'en-tête TCP pour y trouver les numéros de ports. Et cet en-tête TCP n'est pas à une position fixe par rapport au début du paquet. Certains équipements de sécurité, par exemple des pare-feux, sont sans état : ils analysent chaque paquet indépendamment des autres, et n'essaient pas, par exemple, de reconstituer les datagrammes fragmentés. Si la chaîne des en-têtes est très longue, l'en-tête TCP peut se retrouver dans le deuxième fragment, ce qui va être très embêtant pour le pare-feu sans état (section 4 de notre RFC). Comme le premier fragment ne contient pas assez d'information pour décider, le pare-feu a deux choix : le bloquer, et il va alors filtrer un datagramme qui était peut-être légitime. Ou bien le laisser passer mais, pour accepter ou non les fragments suivants, le pare-feu a besoin de se souvenir de ce premier fragment, ce qui n'est pas possible sans garder un état.

D'où la nouvelle règle édictée par notre RFC, dans sa section 5 : tous les en-têtes doivent être dans le premier fragment. Si ce n'est pas le cas, les machines terminales devraient jeter le paquet en question (on a le droit de mettre une option de configuration pour les laisser passer quand même). Les machines intermédiaires (routeurs et pare-feux) ont le droit d'en faire autant.

Cette destruction du paquet invalide peut être accompagnée de l'émission d'un paquet ICMP, de type 4 (Parameter problem) et de code 3 (ce nouveau code, First- fragment has incomplete IPv6 Header Chain a été ajouté dans le registre IANA).

On notera que la taille maximale d'une chaîne d'en-têtes dépend donc de la MTU. Si l'émetteur ne fait pas de découverte de la MTU du chemin, il doit se limiter à la taille minimale d'IPv6, 1 280 octets.

Ce RFC fait partie des normes qui sont venues après la mise en œuvre : il existe déjà plusieurs pare-feux IPv6 sans état qui jettent sans merci les paquets lorsque la chaîne complète des en-têtes n'est pas entièrement dans le premier fragment.


Téléchargez le RFC 7112


L'article seul

RFC 7111: URI Fragment Identifiers for the text/csv Media Type

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : M. Hausenblas (DERI, NUI Galway), E. Wilde (EMC Corporation), J. Tennison (Open Data Institute)
Pour information
Première rédaction de cet article le 17 janvier 2014


Le classique format CSV est normalisé dans le RFC 4180. Lorsqu'un URI désigne un fichier CSV, comment indiquer une partie spécifique du fichier ? Jusqu'à présent, il n'y avait pas de mécanisme pour cela. Ce nouveau RFC comble ce manque et définit une syntaxe (fragment identifier) pour désigner une ligne particulière, une colonne spécifique, voir une seule cellule d'un fichier CSV. http://www.example.org/data.csv#row=12 fonctionnera désormais, pour indiquer qu'on veut sauter à la douzième ligne du fichier data.csv.

Les ressources au format CSV sont identifiées par le type text/csv. Ce type a deux paramètres, charset qui indique l'encodage et header qui indique si l'en-tête facultatif de CSV est présent ou pas (cet en-tête donne le nom des colonnes). Rappelons que la syntaxe et la sémantique des identificateurs de fragment dans un URI dépendent du type de la ressource. Par exemple, « la cellule en 2ème ligne et 5ème colonne » a un sens en CSV mais pas en texte brut, alors que « le 292ème caractère » a un sens en texte brut (RFC 5147 pour les identificateurs de fragments du texte brut).

Attention, les identificateurs de fragments sont interprétés uniquement par le client Web. Leur bon fonctionnement dépend donc du déploiement du logiciel nécessaire chez les clients, ce qui va prendre du temps (je me demande combien de navigateurs Web gèrent le RFC 5147...). Le serveur n'a même pas un moyen de savoir si le client gère ces identificateurs de fragment. Mais ce n'est pas forcément un problème grave : si le client ne comprend pas la syntaxe des identificateurs de fragments pour CSV, il charge quand même le fichier CSV, il ne peut juste pas aller directement à la partie intéressante. Le repli se fait donc en douceur. Pour l'instant, à ma connaissance, il n'existe pas de logiciel qui gère ces fragments CSV.

Bref, voyons maintenant la sémantique des identificateurs de fragments pour CSV (section 2 du RFC). Le RFC contient un exemple avec des données de température mais je vais plutôt prendre les données BGP de la récente panne de l'Internet à Saint-Pierre-et-Miquelon. Les données originales étaient au format MRT (RFC 6396) mais bgpdump peut les traduire en quasi-CSV, il suffit d'un petit coup de sed ensuite :

% bgpdump -m updates.20140104.1930.bz2 | sed 's/|/,/g' > updates.20140104.1930.csv

Le fichier utilisé pour les exemples est panne-spm.csv (oui, il contient une ligne optionnelle d'en-tête au début, mais ne l'indique pas dans le type MIME, violant ainsi la section 3 du RFC 4180). Chaque ligne comprend notamment l'heure (deuxième colonne, vous pouvez traduire 1388864007 avec date -u --date=@1388864007), le type de message (troisième colonne, avec A = Announce et W = Withdraw), le pair qui a envoyé le message (quatrième colonne), le préfixe d'adresse IP concerné (sixième colonne), etc.

D'abord, on peut sélectionner une ligne particulière, la première étant numérotée 1 (pas zéro, attention, les informaticiens). La ligne d'en-tête, facultative, compte pour une ligne normale si elle est présente. Ainsi, la ligne 5 est BGP4MP,1388864007,W,195.66.224.32,3257,70.36.8.0/22. On peut aussi indiquer un intervalle des lignes. Ainsi, 5-7 est :

BGP4MP,1388864007,W,195.66.224.32,3257,70.36.8.0/22
BGP4MP,1388864007,A,195.66.225.76,251,70.36.8.0/22,251 3257 11260 3695,IGP,195.66.225.76,0,0,3257:4000 3257:8093 3257:50002 3257:50122 3257:51400 3257:51401 65020:10708,NAG,,
BGP4MP,1388864007,W,195.66.236.32,3257,70.36.8.0/22

Le signe * indique « la dernière ligne » donc * désigne :

BGP4MP,1388864142,W,195.66.224.215,31500,70.36.12.0/22

On peut aussi désigner une colonne donnée. Là aussi, on part de 1. La sixième colonne sera :

70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
70.36.8.0/22
...

(Les Unixiens noteront que c'est l'équivalent de cut : cut -d, -f6 panne-spm.csv.) Et les colonnes 2-4 :

1388864007,A,195.66.224.32
1388864007,A,195.66.225.111
1388864007,A,195.66.236.32
1388864007,W,195.66.224.32
1388864007,A,195.66.225.76
1388864007,W,195.66.236.32
1388864007,A,195.66.224.32
...

Le signe * est également utilisable.

Enfin, on peut indiquer une cellule particulière, identifiée par une ligne et une colonne. 4,2 désignera donc 195.66.224.32. La syntaxe des intervalles marche aussi, donc 2-3,4-5 désignera quatre cellules :

1388864007,A
1388864007,W

Les identificateurs de fragments de ressources CSV peuvent aussi être composés de plusieurs sélections disjointes, mais, bon, cela devient un peu compliqué.

La syntaxe précise figure en section 3. Pour indiquer si le numéro désigne une ligne, une colonne, ou une cellule, on le préfixe avec row= (« rangée »), col= ou cell=. Comme montré dans l'exemple ci-dessus, les valeurs d'un intervalle sont séparées par un -, les lignes et colonnes d'une cellule par une ,. Si on a plusieurs sélections disjointes, elles sont séparées par un ;. Et, comme toujours avec les URI, l'identificateur de fragment est séparé du reste de l'URI par un #. Ainsi, l'URL pour récupérer la cellule 3,5 de mon fichier d'exemple sera http://www.bortzmeyer.org/files/panne-spm.csv#cell=3,5. Et, si vous avez un navigateur Web qui gère ce RFC, http://www.bortzmeyer.org/files/panne-spm.csv#row=10 devrait vous pointer directement sur la dixième ligne.

La section 4 donne des détails sur la manière exacte dont un client devrait gérer ces fragments, notamment en cas d'erreurs. S'il y a une erreur de syntaxe (par exemple http://www.bortzmeyer.org/files/panne-spm.csv#line=10, avec line au lieu de row), l'identificateur doit être ignoré (tout se passera donc comme si on était simplement allé en http://www.bortzmeyer.org/files/panne-spm.csv). Même chose si les nombres pointent en dehors du fichier, parce que trop grands.

L'enregistrement du type text/csv a été mis à jour pour inclure cette possibilité supplémentaire.


Téléchargez le RFC 7111


L'article seul

RFC 7108: A Summary of Various Mechanisms Deployed at L-Root for the Identification of Anycast Node

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : J. Abley (Dyn), T. Manderson (ICANN)
Pour information
Première rédaction de cet article le 15 janvier 2014


L'anycast a des tas d'avantages pour les serveurs DNS mais il a au moins un inconvénient : le débogage peut être plus difficile, car deux points de mesure peuvent tomber sur une instance différente du service. Si toutes les instances sont réellement identiques, ce n'est pas un problème. Mais si l'une d'elles a un comportement, ou des données, légèrement différent, de laquelle s'agit-il lorsqu'un utilisateur se plaint que « j'interroge ns2.nic.example et sa réponse n'est pas correcte ? » Ce RFC documente l'ensemble des techniques utilisées par l'un des serveurs racine du DNS, le serveur L géré par l'ICANN.

Le problème se résume donc à « j'interroge l.root-servers.net et je voudrais savoir sur quelle instance je suis tombé, et ceci sans faire appel à des connaissances internes à l'ICANN ». On peut s'intéresser à cette information par curiosité, ou bien pour déboguer un problème (comme dans l'exemple du paragraphe précédent) ou encore pour évaluer la bonne distribution des sites anycast (comme dans mon article aux RIPE labs).

Est-ce une bonne chose que cette information soit disponible à l'extérieur ? Oui, répond clairement l'ICANN, on gère un service qui est public et destiné au public et cette transparence est nécessaire, notamment du point de vue opérationnel. Et puis la localisation de ces serveurs n'est pas vraiment un secret (contrairement à ce qu'on a parfois lu dans des articles de presse sensationnalistes). Félicitons donc l'ICANN pour cet effort de publication (tous les serveurs racine du DNS ne le font pas, loin de là, cf. section 6 pour des éléments à ce sujet) et passons à la technique.

La gestion de services anycast est décrite dans le RFC 4786. Cette technique permet de répartir sur toute la planète les serveurs qui répondent à une adresse (pour L, ce sont actuellement 199.7.83.42 en IPv4 et 2001:500:3::42 en IPv6). Beaucoup d'information est disponible en ligne sur la gestion de la racine, notamment en http://www.root-servers.org/. Une liste des instances de « L-root » (actuellement 143 sites et 273 machines) est également en ligne.

Comment sont nommées ces instances de L (section 3 de notre RFC) ? Chaque copie de L-root a un nom, <IATA Code><NN>.l.root-servers.org<IATA Code> est un code IATA identifiant l'aéroport le plus proche. Cette technique de nommage des équipements réseau est très courante chez les opérateurs Internet. Par exemple, cdg est l'aéroport de Roissy près de Paris. Le nombre <NN> sert à distinguer deux machines proches du même aéroport (par exemple dans le même centre de traitement de données). Si un site est situé à mi-chemin entre deux aéroports, on en choisit arbitrairement un.

Bien, c'est très joli, ces noms mais comment trouve-t-on celui de l'instance de L-root qui nous a répondu ? La section 4 du RFC décrit les différentes méthodes possibles. Commençons par NSID (Name Server Identifier, normalisé dans le RFC 5001). C'est une option du DNS qui permet de demander au serveur, s'il le veut bien, de renvoyer son nom. Testons là avec dig :

% dig +nsid @l.root-servers.net SOA .
...
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; NSID: 6b 62 70 30 31 2e 6c 2e 72 6f 6f 74 2d 73 65 72 76 65 72 73 2e 6f 72 67  \
        (k) (b) (p) (0) (1) (.) (l) (.) (r) (o) (o) (t) (-) (s) (e) (r) (v) (e) (r) (s) (.) (o) (r) (g)

La question posée (le SOA de la racine) ne nous intéresse pas, on voulait juste le nom du serveur, ici kbp01.l.root-servers.org (donc à Kiev). C'est la méthode recommandée et la plus fiable. Si vous voulez signaler à l'ICANN un problème avec L-root, c'est cette technique qu'il faut utiliser pour envoyer un rapport de bogue utile. C'est d'ailleurs vrai pour la majorité des serveurs anycast DNS (par exemple, le serveur d.nic.fr qui fait autorité pour .fr accepte également cette option). Par contre, dans certains cas, cela ne marchera pas car NSID dépend de EDNS (RFC 6891) et certains équipements réseaux bloquent (bêtement) EDNS.

Une autre technique existe, bien plus ancienne que NSID et qui est sans doute plus connue des administrateurs réseaux : interroger le serveur sur les noms hostname.bind ou id.server, avec le type TXT et la classe CH. Par exemple :

% dig @l.root-servers.net CH TXT hostname.bind
...
;; ANSWER SECTION:
hostname.bind.		0 CH TXT "lys01.l.root-servers.org"
...

(C'est près de Lyon.) Notez bien que .bind et .server ne sont pas des vrais TLD. Ils n'ont de signification que locale, sur le serveur en question. Chaque machine répondra de manière différente. Comme son nom l'indique, hostname.bind a été à l'origine introduit par le logiciel BIND mais a depuis été adopté par d'autres (L-root utilise nsd). id.server, qui donne le même résultat, a été créé pour faire moins spécifique à BIND mais n'a jamais été très populaire.

hostname.bind et id.server ne dépendent pas d'EDNS et ne nécessitent pas un client DNS qui comprend l'option NSID. Mais ils ont tous les deux un gros défaut : si on reçoit une réponse surprenante et que, dans la foulée, on fait une requête hostname.bind pour enquêter, rien ne dit que le routage n'aura pas changé entre temps, et qu'on n'aura pas désormais affaire à une autre instance. NSID, où l'option voyage en même temps que la requête, n'a pas cet inconvénient.

Aussi bien NSID que hostname.bind nécessitent un client DNS (comme dig ou drill), ce que tout le monde n'a pas sur sa machine (notamment sur Windows). Et, même si on a un client DNS, taper la ligne de commande correctement peut être un exploit inaccessible à certains utilisateurs. Lorsqu'un problème se pose avec, semble t-il, une instance spécifique de L-root, il vaudrait mieux pouvoir donner des instructions simples à l'utilisateur qui signale le problème. C'est le but de la dernière technique, identity.l.root-servers.org, présentée en section 4.4. Chaque instance de L-root fait autorité pour ce nom mais donne une réponse différente, révélant l'identité de l'instance. Ce nom a un enregistrement TXT mais surtout un enregistrement A (une adresse IPv4) donc, si on peut interroger ce nom avec un client DNS, comme ci-dessus :

% dig identity.l.root-servers.org
...
;; ANSWER SECTION:
identity.l.root-servers.org. 3600 IN A 77.88.206.134

(en profitant du fait que le type A est la valeur par défaut pour dig donc n'a pas besoin d'être spécifiée), on peut aussi demander à l'utilisateur de juste faire :

% ping identity.l.root-servers.org
PING identity.l.root-servers.org (77.88.206.134) 56(84) bytes of data.
64 bytes from hostmaster.kiev.customer.top.net.ua (77.88.206.134): icmp_req=2 ttl=47 time=86.5 ms
64 bytes from hostmaster.kiev.customer.top.net.ua (77.88.206.134): icmp_req=4 ttl=47 time=90.7 ms
...

et d'indiquer la valeur qu'il voit pour l'adresse. Au passage, la traduction d'adresse en nom nous indique qu'on touche bien l'instance de Kiev. ping, lui, est installé partout. C'est le gros intérêt de cette technique, son accessibilité pour des non-techniciens. Elle est spécifique à L-root (alors que les deux précédentes sont « standard » et largement déployées). Notez bien que ping est juste un moyen (simple et toujours disponible) de faire une résolution de nom en adresse IPv4. Rien ne garantit que cette adresse sera routable, c'est juste un identificateur unique permettant de distinguer les différentes instances de L-root.

Si on a un client DNS (ici, drill), on peut aussi demander le TXT, plus riche :

% drill identity.l.root-servers.org TXT
...
;; ANSWER SECTION:
identity.l.root-servers.org.	3600	IN	TXT	"kbp01.l.root-servers.org" "Kiev" "" "Ukraine" "Europe"

On trouve le nom du serveur, suivant le schéma de nommage indiqué plus haut, la ville en clair, le pays et la région (au sens ICANN du terme).

Pour cette dernière technique, celle avec identity.l.root-servers.org, on n'a pas interrogé directement l.root-servers.net mais on est passé par le serveur récursif (le résolveur) utilisé par la machine de l'utilisateur. Le résolveur peut être sur un réseau différent et donc parfois utiliser une instance de L-root différente de celle de son client, lorsque celui-ci fait des requêtes directes. En outre, le cache du résolveur peut compliquer l'interprétation des résultats. Par exemple, les réponses à une requête A et à une TXT peuvent être incohérentes, si elles sont entrées dans le cache à des moments différents et que les routes avaient changé entre temps.

Si vous voulez voir la liste complète des instances de L-root, elle est stockée dans le DNS, sous forme d'un (très gros) enregistrement TXT dans nodes.l.root-servers.org. On l'interroge en TCP car la réponse sera en général trop grande pour le serveur DNS s'il utilise UDP :

% dig +tcp nodes.l.root-servers.org TXT
...
;; ANSWER SECTION:
nodes.l.root-servers.org. 28681	IN TXT "pom01.l.root-servers.org" "Port Moresby" "" "Papua New Guinea" "AsiaPacific"
nodes.l.root-servers.org. 28681	IN TXT "ppt01.l.root-servers.org" "Papeete" "Tahiti" "French Polynesia" "AsiaPacific"
nodes.l.root-servers.org. 28681	IN TXT "ppt02.l.root-servers.org" "Papeete" "Tahiti" "French Polynesia" "AsiaPacific"
nodes.l.root-servers.org. 28681	IN TXT "prg01.l.root-servers.org" "Prague" "" "Czech Republic" "Europe"
...

Si vous aimez les détails techniques sur le fonctionnement de identity.l.root-servers.org, voyez la section 5. identity.l.root-servers.org est une sous-zone de l.root-servers.org, déléguée à un seul serveur de noms, dont l'adresse IP est dans le même préfixe que l.root-servers.net :

% dig NS identity.l.root-servers.org
...
;; ANSWER SECTION:
identity.l.root-servers.org. 3600 IN NS	beacon.l.root-servers.org.
...

Chacun des serveurs sert une zone identity.l.root-servers.org différente, reflétant la localisation du serveur. La zone identity.l.root-servers.org n'est donc pas cohérente et c'est fait exprès. Cela n'empêcherait pas la signature avec DNSSEC mais cela la compliquerait (installer les logiciels et générer des clés sur chaque nœud...) et donc identity.l.root-servers.org n'est pas signé (de toute façon, les zones au-dessus ne le sont pas non plus).


Téléchargez le RFC 7108


L'article seul

RFC 7103: Advice for Safe Handling of Malformed Messages

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : M. Kucherawy, G. Shapiro, N. Freed
Pour information
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 16 janvier 2014


Dans un monde idéal, les messages transmis par le système de courrier électronique de l'Internet seraient tous parfaitement conformes aux normes, comme le RFC 5322. Dans la réalité, l'ancienneté du courrier, et son succès, qui a mené à une explosion du nombre de logiciels, font que beaucoup de messages sont incorrects, « malformed », dit ce nouveau RFC. Que doivent faire les logiciels confrontés à ces messages incorrects ? Voici une série d'avis pour les programmeurs qui veulent essayer de faire le moins mal possible.

Les normes du courrier électronique sont pourtant anciennes, remontant aux années 1970 (le RFC 733 semble avoir été le premier), et on pourrait penser qu'elles sont désormais bien intégrées partout. Mais ce n'est clairement pas le cas en pratique. Une approche « fasciste » de ce problème serait de rejeter ces messages invalides. Mais cela éliminerait une bonne partie de l'intérêt du courrier électronique, la capacité à communiquer avec un grand nombre de gens. La pression du « marché » va donc plutôt vers un certain laxisme. Un logiciel qui rejetterait tous les messages erronés n'auraient pas beaucoup de clients ! Il est en général plutôt conseillé de faire preuve de souplesse et d'accepter ces messages non-standard dans certains cas, dans la logique du principe de robustesse. Cela ne veut pas dire qu'il faut tout tolérer et ce RFC 7103 rassemble des conseils pour les auteurs de logiciels de gestion du courrier. Une interprétation extrémiste du principe de robustesse serait en effet qu'un émetteur peut envoyer n'importe quoi, le récepteur ayant tout à faire tout travail d'interprétation (« mais qu'est-ce qu'il a voulu dire ? »).

Une autre variante du problème de non-conformité aux normes est que certains logiciels, côté réception, ont des bogues qui peuvent pousser les émetteurs à violer la norme... pour ne pas déclencher ces bogues. Bref, ce RFC est confus parce que le problème est confus. Le courrier électronique est un gros b....l.

Le principe de robustesse a plutôt bien marché pour le courrier, estime notre RFC. Faire un message qui sera accepté partout est relativement facile, vu la tolérance des récepteurs face à des erreurs de détail. Mais les temps ont changé : notamment, la montée des préoccupations de sécurité rend difficile de continuer à être tolérant. Par exemple, un méchant peut placer un piège dans un message invalide, piège qui sera détecté par certains logiciels et pas par d'autres. Cette différence d'appréciation, inoffensive pour des messages normaux, peut devenir critique face à des messages portant du logiciel malveillant.

Un autre cas où le problème peut devenir critique est celui du spam. Les logiciels d'envoi de spam sont souvent particulièrement négligents (vite et mal écrits) et pas mal de logiciels antispam mettent des mauvais points aux messages qui ont des erreurs techniques, ce qui peut mener à leur classement comme spam. Le principe de robustesse rencontre donc une autre limite ici.

Il faut se rappeler que le courrier est non-interactif, ce qui rend difficile de faire respecter les règles. Dans une communication interactive, on peut imaginer un récepteur qui rejette les messages invalides, indiquant clairement à l'émetteur qu'il doit recommencer en respectant les règles. Pour le courrier, ce n'est pas possible : le récepteur doit se débrouiller avec ce qu'il a. L'auteur du logiciel de réception préférera donc toujours accepter les messages invalides plutôt que de subir les plaintes de ses utilisateurs, qui ne recevraient pas les messages attendus.

Néanmoins, notre RFC précise (section 1.2) qu'il n'approuve pas ces innombrables erreurs que commettent les émetteurs négligents. Le code en cause devrait être réparé de toute façon, ne serait-ce que pour des raisons de sécurité. Mais les conseils donnés par la suite sont là pour permettre au courrier de fonctionner en attendant cette réparation (fort hypothétique, je dois dire). Cela n'empêche pas de rappeler aux émetteurs de courrier qu'il est dans leur intérêt, et dans celui de tout l'Internet, d'essayer de fabriquer et d'envoyer des messages le plus parfaits possible. Bien relire les RFC 5598, RFC 5322 et RFC 2045 est donc nécessaire si on écrit du logiciel qui traite des messages.

Pour les récepteurs des messages mal formés, notre RFC suggère les principes suivants :

  • Lorsqu'il y a une erreur syntaxique mais que l'intention sémantique est claire (exemple : un excès de < autour d'une adresse), accepter le message.
  • Autrement, ne pas essayer d'accepter le message, sauf si on a de bonnes raisons de penser qu'un rejet aurait de pires conséquences.
  • Et ne pas oublier la sécurité, qui peut imposer des choix qui ne sont pas conformes aux deux principes ci-dessus.

Maintenant, les conseils pratiques. D'abord, en section 4, tout ce qui est lié à la différence entre fond et forme : un message électronique peut avoir plusieurs représentations équivalentes du point de vue du contenu. C'est déjà le cas en transit mais c'est encore plus vrai lorsqu'il est stocké sur un système. Il a pu, par exemple, être mis dans un SGBD. Le principe que pose notre RFC est qu'il faut toujours garder quelque part la forme originale et que c'est elle qui doit être passée aux différents modules qui vont traiter le message. C'est la seule façon de garantir que chaque module ait toute l'information disponible, qu'on ne l'ait pas digérée pour lui. Par exemple, si un module ajoute des en-têtes locaux au message, les modules ultérieurs doivent recevoir le message sans ces en-têtes (si on veut communiquer avec eux, il vaut mieux utiliser des méthodes extérieures au message).

Cet avis est particulièrement important pour les modules voués au traitement de messages abusifs, que l'on souhaite signaler : les modifications faites par les modules précédents, même dans une bonne intention, pourraient empêcher, par exemple, de reconnaître le vrai expéditeur.

Même des changements qui semblent purement syntaxiques (supprimer les espaces non significatifs, par exemple), peuvent affecter d'autres traitements (comme les signatures).

Mais, au fait, quel agent dans l'ensemble de la chaîne de traitement a le plus de responsabilité dans la production de messages corrects ? La section 5 de notre RFC confie ce rôle au MSA : premier jalon en dehors de la machine de l'utilisateur, il est le point recommandé pour le respect des règles. Notamment, il a encore la possibilité de rejeter un message de façon à ce que le vrai émetteur soit prévenu, ce que ne pourront pas toujours faire les MTA situés plus loin sur le trajet (qui peuvent générer un courrier de rejet mais ne sont jamais sûrs qu'il ira à l'émetteur original).

Une cause fréquente de non-conformité des messages est une fin de ligne incorrecte (section 6). La seule fin de ligne standard dans un message est la combinaison CR LF (Carriage Return, 13 en ASCII suivi de Line Feed, 10 en ASCII), sauf si on utilise le RFC 3030. Mais d'autres systèmes ont des conventions différentes, par exemple Unix, où la fin de ligne est le seul LF. En pratique, on voit sur le réseau des messages avec uniquement des LF, et des messages avec un mélange de LF et de CR LF !

Comme il y a très peu de chance qu'un CR ou un LF isolé se retrouvent dans un texte, notre RFC recommande de les traiter comme des CR LF et donc des fins de ligne. (Cet avis ne vaut que pour le texte transporté en SMTP brut, pas pour des parties encodées en MIME.)

Une grosse section du RFC, la 7, est ensuite consacrée à toutes les erreurs qu'on peut trouver dans les en-têtes d'un message. Ce Musée des Horreurs doit son existence en partie à la longévité du courrier électronique, utilisé et maltraité partout depuis de nombreuses années. Ainsi, cet en-tête :


To: <@example.net:fran@example.com>

est marqué comme dépassé par le RFC 5322 (c'était du routage par la source : envoyer d'abord à example.net, pour qu'il transmette à fran@example.com). Mais l'intention est claire et on peut donc l'interpréter sans risques comme :


To: <fran@example.com>

Même chose pour les excès de chevrons déjà cités. Il n'y a pas de mal à traiter :


To: <<<user2@example.org>>>

comme étant en fait :


To: <user2@example.org>

C'est plus gênant quand ces chevrons ne sont pas égaux en ouverture et en fermeture :


To: <another@example.net

peut quand même être lu :


To: <another@example.net>

Et si ce sont les guillemets qui ne sont pas équilibrés ?


To: "Joe <joe@example.com>

Ce cas est plus vicieux car il y a plusieurs interprétatations possibles. Mais le RFC recommande la plus simple :


To: "Joe" <joe@example.com>

Autre bogue qui se voit dans la nature, les lignes dans l'en-tête qui ne sont pas des en-têtes :


From: user@example.com 
To: userpal@example.net 
Subject: This is your reminder
about the football game tonight
Date: Wed, 20 Oct 2010 20:53:35 -0400

Manifestement, le sujet, trop long, a subi un retour chariot anormal : les en-têtes sur plusieurs lignes sont légaux dans le format des messages, mais les lignes de continuation doivent commencer par un espace (section 2.2.3 du RFC 5322). Les conséquences de cette bogue peuvent être graves : certains logiciels vont considérer que les en-têtes s'arrêtent à la première ligne qui n'est pas un en-tête, et donc ne verront pas le champ Date:, repoussé dans le corps du message, d'autres vont corriger en reconnaissant la ligne anormale et d'autres enfin rejetteront complètement le message comme étant invalide (ce qu'il est). Ce genre de différences de comportement peut être exploité par un attaquant : s'il sait que l'antispam a un comportement, et le MUA un autre, il peut glisser des informations qui échapperont à l'antispam mais seront vues par le lecteur. Le RFC suggère donc, mais mezzo voce, de rejeter le message.

Il y a aussi des cas où les normes n'étaient pas claires, menant à des différences de comportement des logiciels. Ce message était parfaitement légal :


From: user@example.com 
To: userpal@example.net 
Subject: This is your reminder
 
 about the football game tonight
Date: Wed, 20 Oct 2010 20:53:35 -0400

Le champ Subject: a été replié en trois lignes, chacune commençant bien par un espace. Donc, ce message n'a normalement qu'une seule interprétation possible (« This is your reminder about the football game tonight »). Mais certains logiciels vont d'abord supprimer les espaces inutiles, la seconde ligne du sujet va alors être vide, devenant un séparateur entre l'en-tête et le corps... Depuis le RFC 5322, ce message est toujours légal mais marqué comme utilisant une syntaxe dépassée. Aujourd'hui, les émetteurs ne devraient plus envoyer de telles lignes.

On voit aussi des en-têtes ayant diverses erreurs de syntaxe :


MIME-Version : 1.0

Ici, il y a un espace anormal, entre le nom du champ et le :. Comme l'interprétation est évidente, le RFC recommande de supprimer les espaces avant le séparateur « : ».

Autre cas rigolo, le nombre d'en-têtes. Certains en-têtes ont une cardinalité imposée (voir le tableau au début de la section 3.6 du RFC 5322). C'est ainsi que From: et Subject:, s'ils sont présents, doivent l'être à un seul exemplaire, alors que Received:, en-tête de trace, peut être répété. Que doit faire un logiciel lorsqu'il rencontre :


From: reminders@example.com
To: jqpublic@example.com
Subject: Automatic Meeting Reminder
Subject: 4pm Today -- Staff Meeting
Date: Wed, 20 Oct 2010 08:00:00 -0700

Reminder of the staff meeting today in the small
auditorium.  Come early!

Certains logiciels ne vont garder que le premier sujet, d'autres que le dernier. Là encore, un attaquant peut se dissimuler à certains logiciels en fabriquant des messages invalides, qui seront interprétés de manière différente par les différents logiciels. Pour le sujet, le RFC recommande tout simplement de concaténer les deux valeurs (« Automatic Meeting Reminder 4pm Today -- Staff Meeting ») en un seul sujet. Même chose pour l'expéditeur (on l'oublie souvent mais un champ From: peut parfaitement contenir plusieurs adresses). Donc,

From: president@example.com
From: vice-president@example.com

devient :

From: president@example.com, vice-president@example.com 

Et si c'est le contraire ? Si des champs obligatoires dans l'en-tête comme From:, Message-ID: ou Date: sont manquants ? Le choix recommandé par notre RFC est de les ajouter, en synthétisant l'information (pour Date:, c'est assez facile, pour From:, une solution est d'extraire l'adresse du MAIL FROM de SMTP, une autre est de fabriquer à partir de l'adresse IP du client, par exemple unknown@[192.0.2.2]). Mais attention : rappelez-vous la régle précédente comme quoi les modules de traitement doivent recevoir le message original. Par exemple, un module antispam peut être intéressé par le fait que Date: manque, cela peut être une signature révelant un problème de spam.

Et les problèmes liés au jeu de caractères et à l'encodage ? Les erreurs d'étiquetage sont fréquentes, par exemple un message marqué :

Content-Type: text/plain; charset=US-ASCII

peut parfaitement contenir des caractères en dehors d'ASCII. Pour détecter l'encodage, notre RFC suggère des heuristiques simples (« si aucun octet n'a le bit de poids fort à zéro, c'est probablement de l'ASCII, sauf si on trouve les séquences d'échappement d'encodages connus comme ISO-2022-JP ; sinon, si le texte est de l'UTF-8 légal, c'est probablement de l'UTF-8 car cela ne peut pas arriver par accident »). Un logiciel de courrier est donc autorisé à utiliser ces heuristiques pour trouver le vrai jeu de caractères et l'encodage utilisé, afin de traiter ce message selon ce jeu et pas selon celui indiqué dans les en-têtes.

Puisqu'on en vient aux jeux de caractères, il faut noter que l'introduction de MIME a suscité de nouvelles occasions de bogues, au point qu'une section entière de notre RFC, la 8, leur est consacrée. Par exemple, Base64 a fait l'objet de plusieurs spécifications (la « bonne » est aujourd'hui celle du RFC 4648) et toutes n'étaient pas d'accord entre elles sur l'attitude à adopter lors de la rencontre de caractères situés en dehors de l'alphabet limité de Base64. Là encore, comme tout ce qui permet deux interprétations, cela peut être utilisé par un attaquant pour produire un message qui sera ignoré par l'IDS ou l'antispam mais accepté par le lecteur.

Enfin, le dernier problème envisagé dans ce RFC est celui des lignes trop longues : la norme (section 2.1.1 du RFC 5322) les limite à 1 000 caractères mais on trouve parfois davantage. Le RFC ne donne pas de conseil explicite (rejeter ? corriger ?) mais met en garde contre les logiciels qui ignorent les caractères supplémentaires : cela fournit encore un autre moyen de dissimulation de contenu.

À noter qu'une des propositions alternatives, lors de la création de ce RFC, était de faire un registre en ligne, contenant les erreurs dans les messages et les actions conseillées. Cela aurait été plus facile à mettre à jour qu'un RFC. Mais documenter dans un registre des erreurs semblait trop étrange...


Téléchargez le RFC 7103


L'article seul

RFC 7102: Terms used in Routing for Low power And Lossy Networks

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : JP. Vasseur (Cisco Systems)
Pour information
Réalisé dans le cadre du groupe de travail IETF roll
Première rédaction de cet article le 25 janvier 2014


Le terme de ROLL (Routing for Low power And Lossy Networks) désigne à l'IETF un travail en cours pour l'adaptation des algorithmes de routage à ce que le marketing appelle l'Internet des Objets, ces petits engins connectés en TCP/IP, mais dotés de faibles capacités et de liaisons physiques très imparfaites. On parle aussi de LLN pour Low power and Lossy Networks. Le groupe de travail du même nom a déjà produit plusieurs RFC et se voit désormais doté, avec ce nouveau document, d'un texte décrivant la terminologie de ROLL.

Les LLN, ces réseaux d'engins aux capacités limitées, sont utilisés dans de nombreux contextes, de la domotique (voir la fameuse maison qui tweete) au contrôle de processus industriel en passant par la surveillance de l'environnement, avec plein de capteurs semés, littéralement, dans la nature. Les machines connectées à un LLN n'ont pas l'équipement d'un ordinateur de bureau. Pas de MMU, pas de processeur 64 bits, pas de disque dur et surtout pas d'alimentation électrique permanente. Il faut donc faire durer la batterie (low power...) Leurs connexions au réseau se font en général sans fil, en 802.15.4 ou WiFi, donc sur des liens où les pertes de paquet ne sont pas rares (d'où le lossy dans le nom).

Les machines visées dans ce RFC sont en général des engins très spécifiques, conçus pour une tâche donnée, dans le contexte d'une application précise. Le vocabulaire des LLN est donc varié, chaque communauté qui utilise des LLN ayant développé le sien. D'où l'intérêt de ce RFC, qui essaie d'unifier le vocabulaire des RFC du groupe ROLL, comme le RFC 5548 (le cahier des charges général), RFC 5673 (le cahier des charges spécifique aux applications industrielles), RFC 5826 (le cahier des charges pour la domotique), RFC 5867 (le cahier des charges pour la surveillance et gestion d'immeubles), etc. À noter qu'un autre RFC de terminologie pour ce monde des Objets est le RFC 7228.

La terminologie est décrite en section 2. Je ne vais pas reprendre ici tous les termes (vous devrez lire le RFC si vous voulez tout savoir) mais seulement certains qui me semblent particulièrement importants, dans l'ordre du RFC (l'ordre alphabétique en anglais).

  • Un actionneur (actuator) est un engin qui peut agir en contrôlant quelque chose d'extérieur. Il peut allumer une chaudière, ou actionner un aiguillage ou ouvrir une vanne.
  • AMI (Advanced Metering Infrastructure) désigne l'utilisation de la « Smart grid » pour la mesure.
  • Un canal (channel) est une bande de fréquences utilisée pour la communication. Sa largeur dépend de la sensibilité des équipements radio.
  • L'outil d'avitaillement (commissioning tool) est un logiciel, ou un matériel dédié avec le logiciel adapté, servant à configurer le réseau. Notez que beaucoup de LLN ne sont pas configurés du tout : on branche et ça doit marcher.
  • Le contrôleur (controller) est l'engin qui reçoit les informations des capteurs et qui, sur la base de ces informations, va décider des actions à entreprendre, actions qui seront demandées aux actionneurs.
  • Un puits de données (data sink) est tout engin qui reçoit des données. Le terme est discutable car on a l'impression que les données sont juste avalées, comme par un trou noir, alors qu'elles sont gardées et/ou analysées.
  • La direction descendante (downstream) est celle qui va du monde extérieur (par exemple l'Internet) vers le LLN. Sur un dessin, il faut donc placer le LLN en bas, pour être cohérent avec cette définition.
  • Un engin de terrain (field device) est n'importe quel engin qui, au lieu d'être installé dans le confort d'une salle machines, est placé près du système qu'il doit surveiller et/ou commander. Cela inclut donc les capteurs et les actionneurs. Les engins de terrain sont souvent, vu les contraintes de coût et d'encombrement, des engins limités en capacité CPU, RAM, et en énergie. Par exemple, un capteur typique d'aujourd'hui peut n'avoir que quelques ko de RAM, quelques dizaines de ko de mémoire flash, un microcontrôleur 8 ou 16 bits, et une capacité réseau parfois de seulement quelques kb/s.
  • FMS (Facility Management System) est un terme qui désigne globalement toutes les fonctions de gestion d'un immeuble, de la sécurité incendie à l'air conditionné.
  • Le standard HART (Highway Addressable Remote Transducer), géré par l'organisation du même nom, couvre la commande et la surveillance de processus industriels.
  • Le sigle HVAC (pour Heating, Ventilation and Air Conditioning, chauffage, ventilation et climatisation en français) désigne l'ensemble des systèmes qui contrôlent le chauffage, la ventilation et le conditionnement d'air dans un bâtiment.
  • L'ISA (International Society of Automation) est une organisation qui établit des standards dans le champ de l'automatisation, notamment industrielle.
  • Un routeur de bord (LBR, c'est-à-dire LLN Border Router) est un routeur qui assure l'interface entre le LLN, le réseau d'objets, et le reste du monde (l'Internet, ou bien un réseau local d'entreprise dont le LLN n'est qu'une partie).
  • Le réseau à petits moyens (LLN, Low power and Lossy Network), déjà présenté, est le centre de l'attention de ce RFC. Quelqu'un a un plus joli terme en français ? Réseau pauvre ? Réseau économe ? Laurent Toutain suggère « réseau contraint », Emmanuel Saint-James « réseau léger » ce qui, je le cite, « conserve le L de l'anglais, ça évoque que c'est pas lourd à mettre en œuvre mais qu'en terme de fiabilité c'est ... léger ».
  • Une machine qui ne dort jamais (machine insomniaque ? en anglais, c'était non-sleepy node) est un engin qui est toujours sous tension, et ne se met jamais en hibernation ou autre mode d'économie d'énergie. Le LBR est probablement une machine qui ne dort jamais, puisque connecté à des réseaux extérieurs qui sont toujours en activité. C'est sans doute la même chose pour le contrôleur.
  • Le contrôle ouvert (open loop control) est un mode de fonctionnement où un opérateur peut prendre des décisions et les faire appliquer par les actionneurs (contrairement à un mode complètement automatique).
  • Le terme point-à-point (ou P2P, point to point) a un sens très particulier dans le contexte de ROLL, qui n'a qu'un lointain rapport avec sa signification dans d'autres domaines. P2P signifie ici qu'on parle du trafic échangé entre deux machines, même indirectement connectées.
  • Au contraire, le point-à-multipoint (P2MP, point to multipoint) est le trafic entre une machine et un groupe d'autres machines. C'est l'équivalent du multicast (RFC 4461 ou RFC 4875).
  • Rappelons que le RFID (Radio Frequency IDentification) est une technique de communication avec des étiquettes fixées à des objets, étiquettes qui sont actives mais n'ont en général pas de source d'énergie propre.
  • Le protocole RPL est un protocole de routage conçu spécialement pour les LLN. Il est normalisé dans le RFC 6550. Un domaine RPL (RPL domain) est un ensemble de routeurs RPL situés sous la même administration.
  • Un capteur (sensor) est un engin qui fait des mesures (par opposition à l'actionneur, qui agit). Il y a plein de choses à mesurer, la température, les caractéristiques d'un courant électrique, l'humidité, le bruit, le pourcentage d'oxyde de carbone dans l'air, etc.
  • Une machine qui dort parfois (sleepy node) est un engin doté d'un mode d'économie d'énergie où il cesse de participer au réseau pendant un moment (mise en sommeil automatique au bout de N secondes d'inactivité, par exemple).
  • La direction montante (upstream) est celle qui va du LLN vers le monde extérieur (par exemple l'Internet).

Téléchargez le RFC 7102


L'article seul

RFC 7101: List of Internet Official Protocol Standards: Replaced by an Online Database

Date de publication du RFC : Décembre 2013
Auteur(s) du RFC : S. Ginoza (AMS)
Pour information
Première rédaction de cet article le 6 décembre 2013


Il fut une époque où le RFC Editor publiait une liste des normes techniques Internet, sous forme d'un RFC. Connue sous le nom de « xx00 », cette liste n'a plus été publiée depuis 2008 et il était donc temps de documenter sa disparition. Elle est désormais remplacée par une page Web.

Le premier RFC à jouer ce rôle était le RFC 1083. À partir du RFC 2200, cette liste était publiée dans des RFC dont le numéro se terminait par 00, ce qui a mené au surnom « xx00 » pour désigner la série. Le dernier a été le RFC 5000. La série étant terminée, des futurs RFC au numéro se terminant par 00 pourront apparaître, sans qu'ils aient de lien avec cette liste de normes.

De nos jours, une liste en ligne, mise à jour en permanence, est évidemment plus logique. Elle existe depuis maintenant dix ans, et, comme noté par le RFC 7100, en raison de cette existence, les RFC « xx00 » (également désignés par l'abréviation « STD 1 ») n'ont plus de sens.


Téléchargez le RFC 7101


L'article seul

RFC 7100: Retirement of the "Internet Official Protocol Standards" Summary Document

Date de publication du RFC : Décembre 2013
Auteur(s) du RFC : P. Resnick (Qualcomm Technologies)
Première rédaction de cet article le 6 décembre 2013


Un peu de rangement dans la bibliothèque des RFC. La section 2.1 du RFC 2026 indiquait qu'un RFC spécial (nommé « STD 1 ») contenait une liste de tous les RFC ayant le statut de norme. Maintenir un tel document était devenu trop coûteux et cette règle est désormais abandonnée. Le dernier de la série aura été le RFC 5000, qui n'aura donc pas de successeur (RFC 7101). Désormais, il ne reste plus que la liste publiée en ligne, maintenant la seule à faire foi. Si vous voulez connaître le statut d'un RFC, c'est là qu'il faut aller.


Téléchargez le RFC 7100


L'article seul

RFC 7098: Using the IPv6 Flow Label for Load Balancing in Server Farms

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : B. Carpenter (Univ. of Auckland), S. Jiang (Huawei Technologies), W. Tarreau (HAProxy)
Pour information
Réalisé dans le cadre du groupe de travail IETF intarea
Première rédaction de cet article le 17 janvier 2014


Le champ « Flow label » dans l'en-tête des paquets IPv6 est un des mystères de l'Internet. Bien qu'il ait désormais un RFC entièrement pour lui, le RFC 6437, et qu'il soit obligatoire, selon le RFC 6434, personne n'a l'air de savoir à quoi il peut vraiment servir en pratique. Lorsqu'on observe des paquets IPv6, ce champ est souvent mis à zéro. Des gens ont déjà réfléchi à des utilisations possibles et ont documenté leurs idées dans le RFC 6294. Notre nouvel RFC, lui propose un usage : faciliter la répartition de charge dans les fermes de serveurs. Comment ? Pas si vite, d'abord un petit rappel sur le flow label.

La section 2 de notre RFC rafraichit la mémoire de ceux qui ont lu les RFC 2460 et RFC 6437 trop vite. Le champ flow label fait 20 bits et doit avoir une valeur fixe pour un flot donné (par exemple pour une connexion TCP donnée). Sa valeur doit être uniformément répartie parmi les valeurs possibles (et, pour des raisons de sécurité, il vaut mieux qu'elle soit imprévisible de l'extérieur, cf. le cours de sécurité de Gont). Si le nœud de départ n'a pas mis une valeur non nulle dans ce champ, un nœud ultérieur (par exemple un routeur) a le droit de le faire. Le flow label est à une position fixe par rapport au début du paquet, ce qui le rend facilement lisible, même à grande vitesse, contrairement à l'en-tête TCP, qui peut se situer à une distance quelconque du début du paquet. Comme IPv6, contrairement à IPv4, n'a pas de champ qui indique la longueur des en-têtes de couche 3 (permettant de les sauter facilement pour arriver à l'en-tête de couche 4), le flow label pourrait être un meilleur moyen d'identifier un flot donné, d'autant plus qu'il est répété dans tous les paquets (alors que, en cas de fragmentation, l'en-tête de couche 4 ne sera que dans un seul paquet). Mais c'est purement théorique : aujourd'hui, il est rare, dans la nature, de rencontrer des paquets IPv6 avec un flow label non nul (1,4 % des paquets HTTP/IPv6 entrant sur mon blog ont un flow label non nul - vu avec tshark). Vingt bits de perdus pour rien.

Avant d'utiliser le flow label pour faire de la répartition de charge, la section 3 de notre RFC résume les techniques qui existent aujourd'hui pour faire cette répartition. (On peut aussi lire à ce sujet une synthèse d'un des auteurs du RFC.) Les exemples sont tous empruntés à HTTP mais la plupart des ces techniques s'appliquent à tous les protocoles. Première méthode, donc, mettre plusieurs adresses IP dans le DNS. Si le serveur faisant autorité, ou le résolveur, renvoient ces adresses dans un ordre aléatoire, cela assurera une répartition égalitaire entre toutes les adresses. (Le RFC ne mentionne pas que l'usage des enregistrement SRV du RFC 2782 résoudrait bien des limites du DNS. Mais cela dépend de clients bien faits et certains gérants de serveurs préfèrent donc contrôler tout le processus de répartition de charge.) Cette méthode était indépendante du protocole applicatif utilisé. Une méthode spécifique à HTTP serait d'avoir un relais inversé (reverse proxy) en face des vrais serveurs, qui redirige vers un des serveurs. Les clients ne verraient alors qu'une seule adresse IP. Bien sûr, le relais inversé sera seul à la tâche (alors que le but était de faire de la répartition de charge) mais relayer une connexion TCP est bien moins de travail que de servir une page Web complexe. Une variante de cette technique est utilisée pour HTTPS où le répartiteur de charge est également la terminaison de la session TLS, relayant ensuite en clair le trafic jusqu'au vrai serveur.

Mais la technique la plus répandue est sans doute d'avoir un répartiteur de charge opérant en couches 3 et 4, indépendamment du protocole de couche 7. Cela peut être un boîtier fermé spécialisé, un PC ordinaire avec, par exemple IPVS, une fonction embarquée sur le routeur, etc. L'adresse IP du répartiteur est publiée dans le DNS et les clients n'ont donc rien à faire. Comme la solution précédente, elle ne dépend donc pas du comportement du client. Certains de ces répartiteurs sont sans état, relayant chaque paquet IP indépendemment, typiquement en utilisant comme clé un condensat d'informations faciles à trouver dans le paquet (comme l'adresse IP source). Et d'autres sont à état, gardant en mémoire les connexions TCP en cours, et envoyant tous les paquets d'une même connexion vers le même serveur.

Au passage, une fois la décision prise de joindre tel ou tel serveur parmi tous ceux présents dans la ferme, comment le répartiteur redirige-t-il les paquets ? Si le répartiteur et les serveurs sont sur le même LAN, changer l'adresse MAC peut être suffisant (« liaison directe »). Les paquets de retour seront alors transmis sans passer par le répartiteur, qui aura moins de travail. Autre solution, mettre chaque serveur derrière un routeur et utiliser de l'anycast (contrairement à ce que croient certains, l'anycast n'est pas spécifique à BGP). Mais le RFC ne détaille pas cette solution (l'anycast ne se marie pas bien avec la nécessité de maintenir les paquets d'une même connexion TCP épinglés au même serveur).

Troisième solution pour la transmission des paquets vers le « vrai » serveur, donner à chaque serveur sa propre adresse IP et faire un tunnel (GRE, par exemple, car c'est le plus simple et le plus facile à déboguer) vers le serveur, encapsulant le paquet destiné à l'adresse IP du service. Là aussi, le paquet de retour n'a pas besoin de passer par le répartiteur. Selon la taille des paquets utilisés pour l'encapsulation, on pourra rencontrer des problèmes de MTU. Enfin, dernier cas, le NAT où le répartiteur fait une traduction d'adresse IP vers celle du serveur. Attention, dans ce cas, il faut bien configurer le serveur pour qu'il renvoie les paquets de retour vers le répartiteur, pour que celui-ci puisse faire la traduction d'adresse dans l'autre sens. Avec cette solution, le répartiteur, et son état, devient un point de défaillance unique.

Sur toutes ces questions de répartition de charge, on peut consulter l'exposé et l'article d'Alexandre Simon aux JRES 2011.

Comme les relais travaillant au niveau 7 doivent de toute façon analyser tous les paquets, l'utilisation du flow label a peu de chances d'améliorer leurs performances. Donc, le reste du RFC se limite aux redirecteurs travaillant aux niveaux 3 et 4.

Qu'est-ce qui est proposé pour ceux-ci (section 4) ? C'est le cœur de ce RFC, la recommandation pour les répartiteurs de charge d'utiliser cette étiquette des flots.

  • Si le flow label est à zéro (la grande majorité aujourd'hui), continuer comme maintenant,
  • Si le flow label a été mis, comme spécifié par le RFC 6437, utiliser le couple {adresse IP source, flow label} pour la répartition de charge : un répartiteur sans état condense ce couple (RFC 6438), on utilise le condensat comme clé, et on envoie tous les paquets ayant la même clé vers le même serveur. Cela marchera même si les paquets IPv6 sont fragmentés alors qu'un redirecteur classique sans état, qui ne peut donc pas réassembler les paquets, ne pourra pas fonctionnner car il ne trouvera pas le port source dans les fragments (sauf le premier). Un répartiteur avec état dirige le premier paquet du flot vers un serveur et mémorise l'association {adresse IP source, flow label} -> serveur. Si les paquets IPv6 comprennent des en-têtes d'extension, l'utilisation du flow label sera nettement plus rapide que de chercher l'en-tête de transport, et cela malgré le test supplémentaire (« est-ce que le flow label est nul ? »).
  • Les redirecteurs qui font du NAT vers le serveur n'ont aucun intérêt à utiliser le flow label puisqu'ils doivent de toute façon atteindre la couche transport afin de trouver les ports.

Certaines configurations pourraient empêcher un bon fonctionnement de cette méthode. Par exemple, s'il y a partage massif d'adresses derrière un CGN, les risques de collision des flow labels augmentent. Comme il n'y a guère de bonnes raisons de faire un tel partage massif en IPv6, on peut espérer que cela ne soit pas un problème. (Un rappel : en IPv6, traduction d'adresses n'implique pas partage d'adresses, cf. RFC 6296.)

Des problèmes de sécurité avec cette approche ? La section 5 note que le flow label n'est pas spécialement sécurisé (à part si on utilise IPsec) mais c'est également le cas de tous les champs utilisés par les répartiteurs de charge. Néanmoins, comme le rappelle le RFC 6437, un répartiteur paranoïaque peut vérifier que, par exemple, les paquets ne sont pas envoyés de manière déséquilibrée vers un seul serveur car un petit malin modifie les flow label en cours de route. En pratique, en raison de l'utilisation de l'adresse IP source dans la clé, d'une fonction de condensation cryptographique comme SHA-1 et, possiblement, d'un secret concaténé au couple {adresse IP source, flow label} avant sa condensation, une telle attaque ne serait pas triviale.

À noter qu'aujourd'hui, il ne semble pas qu'il existe déjà de répartiteur de charge qui mette en œuvre les préconisations de ce document. (Par exemple, apparemment rien dans l'IPVS de Linux en 3.1.7.)

Merci à Alexandre Simon pour sa relecture.


Téléchargez le RFC 7098


L'article seul

RFC 7095: jCard: The JSON format for vCard

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : P. Kewisch (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jcardcal
Première rédaction de cet article le 15 janvier 2014


Le format vCard permet de décrire de manière standard, compréhensible par tous les logiciels de gestion de carnet d'adresses, les informations sur un individu ou une organisation. Très connu et largement déployé, il est présent à de nombreux endroits. vCard est à la fois un modèle de données (décrivant ce qu'on stocke) et une syntaxe particulière. Des syntaxes alternatives sont possibles et ce nouveau RFC en propose une, fondée sur JSON. Elle se nomme donc jCard.

Il y avait déjà une autre syntaxe alternative, fondée sur XML, dans le RFC 6351. Celle-ci s'inscrit dans la mode JSON actuelle et promet de rendre le vieux format vCard plus accessible pour les applications Web, notamment celles écrites en JavaScript.

vCard est actuellement en version 4, normalisée dans le RFC 6350. Il a plusieurs points techniques en commun avec le format iCalendar de gestion d'agendas, normalisé dans le RFC 5545. Le travail portait donc également sur une syntaxe JSON pour iCalendar, normalisée dans le RFC 7265. JSON, lui, est normalisé dans le RFC 8259. La section 1 du RFC résume le cahier des charges du projet jCard :

  • Possibilité de conversion vCard -> jCard et retour, sans perte sémantique,
  • Pas d'impératif de préservation de l'ordre des éléments,
  • Maintien du modèle de données de vCard,
  • Les futures extensions de vCard devront pouvoir être intégrées naturellement, sans nécessiter un nouveau RFC jCard.

La section 3 est le gros morceau du RFC, indiquant comment convertir les vCard actuelles en jCard. Rappelons qu'une vCard comprend plusieurs propriétés (de cardinalité pouvant être différente de 1), chacune ayant une valeur et, parfois, des paramètres, ces derniers ayant un nom et une valeur. Par exemple, dans :

TEL;TYPE=VOICE,TEXT,WORK;VALUE=uri:tel:+1-666-555-1212

La propriété est TEL, il y a deux paramètres, TYPE qui a trois valeurs, et VALUE qui n'en a qu'une. La valeur de la propriété est un numéro de téléphone, ici +1-666-555-1212.

vCard a quelques particularités syntaxiques. Par exemple, les lignes trop longues peuvent être repliées, et certaines valeurs ont besoin d'échappement. Pour passer à jCard, on déplie toutes les lignes et on retire les échappements. Puis on applique les échappements de JSON.

Une vCard est représentée par un tableau JSON de deux éléments, le premier étant juste la chaîne de caractères vcard et le second étant un tableau JSON avec un élément par propriété. Si on veut mettre plusieurs vCard ensemble, on peut faire un tableau JSON dont chaque élément est une vCard représentée en JSON comme ci-dessus.

Chaque élément qui représente une propriété se compose d'un tableau d'au moins quatre éléments, les quatre obligatoires étant le nom de la propriété (forcément en minuscule, alors que cela ne comptait pas en vCard), les paramètres, une chaîne identifiant le type de la valeur, et la valeur. Si la propriété avait plusieurs valeurs, ce qui est permis en vCard, on ajoute des éléments au tableau. Un exemple de jCard est donc :

   ["vcard",
    [
       ["version", {}, "text", "4.0"],
       ["fn", {}, "text", "John Doe"],
       ["gender", {}, "text", "M"],
       ["categories", {}, "text", "computers", "cameras"],
       ...
    ]
   ]

On voit ici une propriété gender (genre, normalisée dans la section 6.2.7 du RFC 6350), et ayant une valeur de type texte. La propriété categories (section 6.7.1 du RFC 6350), elle, a deux valeurs. On notera que, dans cet exemple, aucune propriété n'a de paramètre, ce qui est représenté par l'objet JSON vide {}. On notera aussi qu'un seul type est utilisé, text mais on verra plus loin quelques exemples de la riche liste de types possibles (le type doit être indiqué explicitement en jCard pour permettre à jCard de traiter des futures extensions à vCard, sans avoir besoin de connaître les nouvelles propriétés ; voir la section 5 pour les détails).

Quelques propriétés sont traitées de manière particulière. Ainsi, version (4.0 à l'heure actuelle) doit être la première du tableau. Certaines propriétés, en vCard, sont structurées : l'exemple le plus classique est l'adresse ADR, avec des champs séparés par un point-virgule. En jCard, on les représente par un tableau. Ainsi, la propriété vCard :

ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.

devient en jCard :

["adr", {}, "text",
     [
     "", "", "123 Main Street",
     "Any Town", "CA", "91921-1234", "U.S.A."
     ]
   ]

(Notez les deux champs manquants au début, le numéro de la boîte postale, s'il y en a une, et le numéro de l'appartement.)

Et les paramètres ? C'est un objet JSON (ce qu'on nomme un dictionnaire dans d'autres langages). Chaque membre de l'objet a pour clé un nom de paramètre et pour valeur la valeur du paramètre. Si l'adresse ci-dessus avait eu le paramètre vCard LANGUAGE avec une valeur indiquant une adresse rédigée en anglais, la première ligne du jCard deviendrait :

["adr", {"language": "en"}, "text",
 ...

On a fait les propriétés, les paramètres, restent les valeurs. Il existe de nombreux types possibles pour les valeurs, je ne vais pas les citer tous. Commençons par l'exemple uri. Une valeur de ce type contient... un URI :

["photo", {}, "uri", "http://www.bortzmeyer.org/images/moi.jpg"]

Les dates n'ont pas tout à fait le même format qu'en vCard. En jCard, elles suivent la norme ISO 8601 2004 donc, par exemple :

["bday", {}, "date", "1412-01-06"]

(au lieu du BDAY:14120106 de vCard.)

Autre exemple de type utile, language-tag, pour indiquer que la valeur est une étiquette de langue :

["lang", {}, "language-tag", "de"]

(Petit rappel vCard au passage : language est la langue dans laquelle est écrite un élément d'information, par exemple une adresse. lang est la langue qu'on peut utiliser pour contacter l'entité décrite par une vCard.)

La section 4 explique, elle, les détails de l'opération inverse, convertir du jCard en vCard.

Reste le problème des propriétés ou paramètres inconnus (section 5). Si un nouveau RFC crée des extensions à vCard, par exemple en ajoutant des propriétés, comme le RFC 6474 ajoutait BIRTHPLACE, DEATHPLACE et DEATHDATE, que faire ? La section 5 étudie leur représentation en jCard. Rappelez-vous qu'un des éléments du cahier des charges était la possibilité d'étendre vCard sans avoir besoin de créer un nouveau RFC pour jCard. Lorsqu'un convertisseur vCard -> jCard rencontre une propriété de type inconnu, il peut mettre unknown comme type. Ainsi, FOO:http://www.foo.example/ deviendra :

["foo", {}, "unknown", "http://www.foo.example/"]

alors qu'un convertisseur plus récent, connaissant la propriété (imaginaire, hein, c'est juste un exemple) FOO pourra traduire :

["foo", {}, "uri", "http://www.foo.example/"]

Ce nouveau format jCard a désormais son propre type MIME, application/vcard+json (et pas jcard+json, attention).

Parmi les mises en œuvre de jCard, on note :

  • ICAL.js en JavaScript (mais surtout prévu pour iCalendar en JSON),
  • Py Calendar, en Python, également surtout pour iCalendar,
  • ez-vcard, en Java. Ne compile pas du premier coup (mvn install -> Tests in error: HCardPageTest.create_then_parse:259 NullPointer) mais semble bien conçu, généralement.

Voici ma vCard présentée dans mon article sur le RFC 6350, traduite en jCard (un exemple complet se trouve sinon dans l'annexe B.1 du RFC) :

  ["vcard",
    [
       ["version", {}, "text", "4.0"],
       ["fn", {}, "text", "Stéphane Bortzmeyer"],
       ["n", {}, "text", ["Bortzmeyer", "Stéphane", "", ""]],
       ["uid", {}, "uri", "urn:uuid:a06340f8-9aca-41b8-bf7a-094cbb33d57e"],
       ["gender", {}, "text", "M"],
       ["kind", {}, "text", "individual"],
       ["email", {}, "text", "individual"],
       ["title", {}, "text", "Indigène de l'Internet"],
       ["photo", {}, "uri", "http://www.bortzmeyer.org/images/moi.jpg"],
       ["lang", {"pref": "1"}, "language-tag", "fr"],
       ["lang", {"pref": "2"}, "language-tag", "en"],
       ["impp", {"pref": "1"}, "uri", "xmpp:bortzmeyer@dns-oarc.net"],
       ["impp", {"pref": "2"}, "uri", "xmpp:bortzmeyer@gmail.com"],
       ["url", {}, "uri", "http://www.bortzmeyer.org/"],
       ["key", {}, "uri", "http://www.bortzmeyer.org/files/pgp-key.asc"]
   ]
  ]

Téléchargez le RFC 7095


L'article seul

RFC 7094: Architectural Considerations of IP Anycast

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : D. McPherson (Verisign), D. Oran (Cisco Systems), D. Thaler (Microsoft), E. Osterweil (Verisign)
Pour information
Première rédaction de cet article le 17 janvier 2014


La technologie de l'anycast est maintenant largement déployée dans l'Internet. C'est l'occasion de faire un point architectural : quelles sont les conséquences de l'anycast ? Telle est la question de ce RFC de l'IAB.

Qu'est-ce que l'anycast ? C'est simplement le fait qu'une adresse IP, celle à laquelle répond un service offert sur l'Internet, soit configurée en plusieurs endroits (cf. RFC 4786). Cette technique est surtout connue par son utilisation massive dans le DNS, notamment pour les serveurs racine. Fin 2007, il y avait déjà dix des treize serveurs racine qui utilisaient l'anycast (cf. les minutes de la réunion 29 du RSSAC). Sans compter la quasi-totalité des gros TLD qui reposent, eux aussi, sur cette technique pour tout ou partie de leurs serveurs. À part le DNS, l'utilisation la plus importante de l'anycast est sans doute pour les serveurs NTP (RFC 5905).

L'adresse IP perd donc sa caractéristique « est unique dans tout l'Internet ». La même adresse IP est configurée en plusieurs endroits, et un paquet IP à destination de cette adresse IP de service arrivera dans un seul de ces endroits, le « plus proche » (en termes de métriques de routage, pas forcément en terme de distance géographique ou de RTT).

À noter que rien ne distingue, syntaxiquement, une adresse anycast d'une adresse habituelle. D'ailleurs, déterminer si un service donné est « anycasté » n'est pas toujours facile. (Quelques traceroutes depuis divers points, ainsi qu'une interrogation directe du serveur, par exemple avec le RFC 5001 pour le DNS, peuvent répondre à cette question, mais on n'a pas toujours une certitude.)

Le RFC 4786 discute en détail différentes façons de faire de l'anycast. Notre nouveau RFC 7094 ajoute une nouvelle distinction : « off-link anycast » et « on-link anycast ». Le premier mode est celui de l'anycast actuel, largement déployé comme on l'a vu. Plusieurs sites annoncent la même route et le « plus proche » est choisi. C'est ce mode qui est discuté dans le RFC 4786.

Le second mode, on-link anycast, n'est pas réellement déployé. Il désigne un système où le protocole de résolution d'adresses sur un réseau local peut gérer, sans protocole de routage, l'envoi à une machine parmi celles qui répondent à une adresse IP donnée. Dans le monde IP, il n'est normalisé que pour IPv6 (RFC 4861, notamment la section 7.2.7).

Lorqu'on utilise le premier mode, le off-link anycast, quel AS d'origine doit-on mettre dans l'annonce BGP ? La plupart des sites anycast utilisent le même AS pour chaque site mais le RFC 6382 documente une méthode où un AS différent est utilisé par site (méthode « multi-origines »).

De quand date l'anycast ? La section 2.1 se penche sur l'histoire de ce concept. La première spécification était le RFC 1546 en 1993, ce qui ne nous rajeunit pas. À l'époque, c'était purement théorique mais le RFC 1546 liste bien toutes les questions. La première utilisation documentée était l'année suivante, pour de la distribution de vidéo, et est notée dans l'IMR 9401. Il s'agissait de trouver le serveur de vidéos « le plus proche ». La rumeur de l'Internet dit que des FAI ont utilisé l'anycast pour leurs résolveurs DNS à partir de cette époque mais il n'y a pas de traces écrites. En 1997, l'IAB s'en mêle pour la première fois, avec quelques phrases dans le RFC 2101.

L'anycast a également été mentionné lors de l'atelier sur le routage organisé par l'IAB l'année suivante et documenté dans le RFC 2902. Cette technique est encore présentée comme « à étudier » (« We need to describe the advantages and disadvantages of anycast »). Donc, en 1999, à la 46ème réunion de l'IETF, une BoF sur l'anycast a eu lieu. Les deux principales conclusions étaient que l'usage de l'anycast pour TCP n'était pas forcément une bonne idée, mais que par contre l'application qui serait la plus suceptible d'utiliser l'anycast avec profit était le DNS.

Par la suite, IPv6 est arrivé et a spécifié des adresses anycast dans le RFC 2526 et dans le RFC 3775. Il était aussi prévu d'avoir des relais anycastés pour la coexistence IPv4-IPv6 (RFC 2893) mais cela a été supprimé par la suite, avant que 6to4 ne réintroduise l'idée dans le RFC 3068. L'expérience de 6to4 a d'ailleurs bien servi à mesurer les conséquences de l'utilisation de l'anycast « en vrai » et cela a été documenté dans le RFC 3964.

Mais c'est le DNS qui a popularisé l'anycast, d'abord avec l'AS 112 (décrit dans le RFC 7534) puis avec la racine. En 2002, le RFC 3258 décrit cette utilisation. Il est amusant de constater que ce RFC n'utilise pas le terme anycast, considéré à l'époque comme devant désigner uniquement les techniques reposant sur une infrastructure spécifique (comme le multicast). Le RFC 3258 note aussi qu'aucun changement des mécanismes de routage n'est nécessaire. Et que l'utilisation d'UDP par le DNS suffisait à résoudre le problème du changement des routes en cours de session : le DNS étant requête/réponse, sur un protocole (UDP) sans état, il n'y avait pas de risque de parler à deux instances différentes pendant une session. Le RFC 3258 recommandait d'arrêter le serveur DNS, plutôt que de couper le routage, en cas de panne, arguant du fait que les clients DNS savent se débrouiller avec un serveur en panne. Couper le routage a en effet l'inconvénient de propager des mises à jour BGP dans toute la DFZ, ce qui peut mener à leur rejet (RFC 2439). Cet argument ne vaut que pour les serveurs faisant autorité (se débrouiller avec un résolveur en panne est bien plus lent). Aujourd'hui, on conseille plutôt le contraire, notamment lorsqu'on a des SLA par serveur DNS (ce qui est absurde, puisque le DNS se débrouille très bien avec un serveur en panne, mais cela se voit dans certains contrats). La section 4.5 de notre RFC revient plus en détail sur ce conseil.

Sur la base notamment du déploiement de l'anycast dans le DNS de 2002 à 2006 a été écrit le RFC 4786, sur les aspects pratiques de l'anycast. Il insiste sur la nécessité que le routage soit « stable », c'est-à-dire dure plus longtemps que la transaction typique (ce qui est facile à réaliser avec les protocoles requête/réponse comme le DNS). Il note aussi que l'anycast peut compliquer la gestion des réseaux, en ajoutant de nouvelles causes de perturbation.

Il y a d'autres cas où le vocabulaire a changé. Par exemple, IPv6 venait dès le début avec quelque chose nommé anycast mais qui était uniquement du on-link anycast, pas le off-link anycast qui est massivement utilisé par le DNS. Cela impliquait des restrictions sur l'usage (interdiction de mettre une adresse anycast en source d'un paquet, cf. section 2.5 du RFC 1884) qui ont été supprimées en 2006 par le RFC 4291. L'on-link anycast d'IPv6 existe toujours (section 7.2.7 du RFC 4861) mais semble très peu employé.

La section 3 de notre RFC pose ensuite les principes d'architecture à suivre pour l'anycast. Elle est assez restrictive, limitant l'anycast à quelques protocoles simples comme le DNS. D'abord, le modèle en couches est considéré comme essentiel par sa modularité. Cela veut dire qu'une application (couche 7) ne devrait pas avoir à être modifiée pour s'adapter au système de routage (couche 3). L'application ne devrait pas non plus être concernée par la stabilité des routes, comme elle n'est pas concernée par le taux de perte de paquets, qui est en général traité dans une couche plus basse. Avec les protocoles de transport à états, comme TCP, un changement de routage qui fait arriver à une autre instance et c'est la fin de tout, puisque cette instance n'a pas l'état associé : elle enverra purement et simplement un RST, mettant fin à la connexion. À noter que c'est un des cas où quelque chose peut très bien marcher dans le laboratoire et pas dans le vrai Internet (où les changements de routes sont un événement relativement fréquent).

Donc, si une adresse de destination d'un paquet est anycast, différents paquets à destination de cette adresse pourront être envoyés à des machines distinctes. Ce n'est pas un problème si on respecte les principes posés par ce RFC : une requête qui tient dans un seul paquet, un transport sans état (comme UDP), pas d'état côté serveur entre deux requêtes, et des requêtes idempotentes. Le DNS obéit à tous ces principes.

Et les adresses anycast en source et pas seulement en destination ? Si on fait cela, deux réponses au même paquet pourront arriver à deux machines différentes. Cela marchera quand même s'il n'y a pas de réponses (cas du DNS : le demandeur ne répond pas à la réponse, venant d'un serveur anycast). Ou si elles sont distribuées à la bonne instance par un autre mécanisme, spécifique à l'application. Mais il y a un autre piège avec une adresse anycast en source : si on met en œuvre le filtrage RPF (RFC 4778), le paquet entrant sera peut-être refusé puisque rien ne dit que le paquet d'une instance donnée arrivera par l'interface par lequel une réponse serait sortie. La section 4.4.5 du RFC 4786 donne quelques conseils à ce sujet.

Une solution au problème du changement de routage, amenant à une autre instance, serait de n'utiliser l'anycast que pour la découverte du serveur, pas pour la communication avec ce serveur (section 3.4). Cela ne convient pas au DNS, puisque cela augmente d'un aller-retour le temps total d'interaction mais ce n'est pas grave, le DNS ne craint pas les changements de route. En revanche, pour un protocole utilisant TCP, on pourrait envoyer un paquet UDP à l'adresse anycast de découverte, recevoir en réponse l'adresse unicast du serveur et interagir ensuite en TCP avec cette adresse unicast. Ainsi, on serait à l'abri des changements de route ultérieurs, tout en gardant les avantages de l'anycast, notamment la sélection du serveur le plus proche. Je ne connais pas encore de système qui utilise cette approche, pourtant prometteuse.

Enfin, la section 4 du RFC analyse certains points précis de l'anycast. Par exemple, son passage à l'échelle pour le système de routage. Chaque serveur anycast public sur l'Internet va nécessiter une route dans la DFZ et va donc charger tous les routeurs de la DFZ. Il est donc préférable que l'usage de l'anycast reste limité à quelques services (comme c'est le cas actuellement). Certes, on peut mettre plusieurs serveurs derrière un même préfixe anycast (et donc une seule route) mais cela imposerait qu'à chaque site, on trouve la totalité des serveurs.

On a vu qu'on pouvait avoir le beurre (l'anycast) et l'argent du beurre (la résistance au changement de routes) en commençant les connexions TCP par un échange UDP pour trouver l'adresse du serveur le plus proche. Cela se paie par un aller-retour supplémentaire (celui en UDP). Il existe une façon astucieuse d'éviter ce coût mais elle requiert une modification de TCP. L'idée est la suivante : le premier paquet TCP, le paquet SYN, est envoyé à l'adresse anycast. La réponse, SYN-ACK est émise depuis une adresse source unicast. Le reste de la communication (fin de la triple poignée de mains avec un ACK puis échange de données) se ferait avec l'adresse unicast du serveur, à l'abri des fluctuations du routage. Les mises en œuvre actuelles de TCP rejetteraient le deuxième paquet, le SYN-ACK car l'adresse source ne correspond pas. Mais, si elles étaient modifiées pour accepter n'importe quelle adresse source en réponse à un SYN envoyé à une adresse anycast, cela marcherait (le paquet entrant serait envoyé au processus qui a une prise réseau avec les mêmes ports et un numéro de séquence TCP qui convient.) Modifier TCP est peut-être trop risqué mais la même idée pourrait être appliquée à des protocoles de transport plus récents comme SCTP.

La section 4.4 se penche sur les questions de sécurité. On utilise souvent l'anycast avant tout pour limiter les effets des dDoS, en ayant plusieurs sites pour amortir l'attaque, avec en outre un contingentement géographique (chaque zombie de l'attaquant ne peut taper que sur un seul site). On peut même s'en servir pour faire couler le trafic non désiré au fond de l'évier, dans l'esprit du RFC 3882. Cette méthode a bien marché dans le cas de grosses erreurs de configuration comme la bavure Netgear/NTP documentée dans le RFC 4085.

On a parlé plus haut du conseil de ce RFC de ne pas retirer une route en cas de panne mais de laisser le trafic arriver au serveur en panne. Ce conseil est contesté mais, en cas d'attaque, il n'y a guère de doute qu'il faut laisser la route en place, sinon l'attaque ira simplement vers une autre instance, probablement plus lointaine, en gênant davantage de monde au passage. Une exception est celle où on retire la route pour aider à trouver la vraie source d'une attaque.

Autre question de sécurité, le risque d'un faux serveur. Ce n'est pas un risque purement théorique, loin de là. Ainsi, à la Journée du Conseil Scientifique de l'AFNIC du 4 juillet 2012, Daniel Karrenberg avait expliqué que le RIPE-NCC avait identifié plusieurs copies pirates du serveur DNS racine K.root-servers.net. Bien sûr, annoncer un préfixe qui n'est pas à vous et attirer ainsi le trafic légitime vers le pirate a toujours été possible en BGP. Mais l'anycast rend cette attaque plus facile : si on voit une annonce d'un préfixe d'un ministère français par un opérateur biélorusse, on s'étonnera et on cherchera. Avec l'anycast, il est tout à fait normal de voir des annonces BGP (ou d'un protocole de routage interne) du même préfixe jaillir d'un peu partout, même d'AS différents. Il est donc très recommandé d'avoir un mécanisme d'authentification, permettant de s'assurer qu'on parle à une instance anycast légitime, et pas à un pirate. (Dans le cas de DNS, c'est DNSSEC qui assure ce rôle. Comme DNSSEC protège les données, et pas juste le canal, si la zone DNS est signée, peu importe que le résultat soit obtenu via un serveur légitime ou pas.)

D'autres attaques que l'envoi de réponses mensongères sont possibles en faisant des annonces de routage d'un préfixe utilisé en anycast. Par exemple, on peut empêcher les paquets d'atteindre les serveurs légitimes, leur masquant ainsi le trafic. La section 6.3 du RFC 4786 et l'article de Fan, X., Heidemann, J., et R. Govindan, « Evaluating Anycast in the Domain Name System » fournissent davantage de détails sur ces attaques spécifiques à l'anycast.


Téléchargez le RFC 7094


L'article seul

RFC 7091: GOST R 34.10-2012: Digital Signature Algorithm

Date de publication du RFC : Décembre 2013
Auteur(s) du RFC : V. Dolmatov (Cryptocom), A. Degtyarev (Cryptocom)
Pour information
Première rédaction de cet article le 17 décembre 2013


L'algorithme de signature GOST est une norme russe de cryptographie. Son utilisation est obligatoire en Russie pour les services publics. L'ancienne version de cet algorithme de signature, GOST R 34.10-2001, était dans le RFC 5832, que ce nouveau RFC met à jour.

Le caractère très étatique de GOST est rappelé dès la section 1.1 du RFC qui note que l'algorithme a été développé par la FAGCI (ou FAPSI), la NSA russe. Il remplace l'ancien GOST R 34.10-2001 (mais ce RFC ne contient malheureusement pas de description des changements entre les deux versions). GOST est obligatoire en Russie pour les services nationaux (section 2 du RFC).

GOST R 34.10-2012, décrit dans ce RFC, est donc un algorithme de pure signature, ne pouvant pas servir au chiffrement. Reposant sur la cryptographie asymétrique, il est donc sur le même créneau que DSA. Mais, contrairement à lui, il repose sur les courbes elliptiques.

Je vous laisse découvrir ledit algorithme dans le RFC, personnellement, mes compétences en cryptographie sont bien trop faibles pour y comprendre quelque chose. Et le code source ? Il ne semble pas être dans OpenSSL qui a apparemment toujours (version 1.0.1e) l'ancienne version de GOST R 34.10. Pour DNSSEC, le numéro d'algorithme 12 est explicitement marqué pour l'ancienne version (RFC 5933), c'est son successeur, le RFC 9558 qui a vu le passage à GOST R 34.10-2012, avec le numéro DNSSEC 23.


Téléchargez le RFC 7091


L'article seul

RFC 7088: Session Initiation Protocol Service Example -- Music on Hold

Date de publication du RFC : Février 2014-02-11
Auteur(s) du RFC : D. Worley (Ariadne)
Pour information
Première rédaction de cet article le 11 février 2014


Une des fonctions les plus demandées d'un service de téléphonie, dans les entreprises, est la musique d'attente, cette insupportable ritournelle qu'il faut supporter en attendant un interlocuteur qui ne viendra peut-être jamais. Comment déployer ce service si on utilise SIP pour la téléphonie ? Il existe plusieurs méthodes et ce nouveau RFC en documente une. Il peut être utilisé comme exemple d'un service mis en œuvre au dessus de SIP, sans nécessiter de modification ou d'extension du protocole.

A priori, ce n'est pas évident. Rappelons brièvement comment fonctionne SIP (RFC 3261), lorsqu'Alice veut contacter Bob. Le client SIP de Bob s'est enregistré auprès d'un fournisseur SIP (SIP permet aussi du pair-à-pair, sans ces fournisseurs, mais c'est plus rare). Alice appelle le serveur SIP de Bob, et lui indique (dans un SDP, cf. RFC 4566) où envoyer le flux audio. Le serveur de Bob prévient son client et, si celui-ci accepte, il indique à son tour où envoyer le son. La communication est établie. Le flux audio ne voyage pas dans le même canal que la signalisation. Les machines SIP doivent indiquer où envoyer ce flux car elles sont souvent coincées derrière un routeur NAT et elles doivent d'abord faire un trou dans le NAT, par exemple avec STUN. Maintenant, si le serveur SIP de Bob ne peut pas établir la communication avec Bob tout de suite et qu'il veut envoyer une musique d'attente, genre « Les quatre saisons » de Vivaldi ? L'architecture de SIP fait que ce n'est pas complètement trivial. Plusieurs méthodes avaient été documentées (par exemple en section 2.3 du RFC 5359) mais avaient des effets parfois gênants, par exemple entraînaient des messages inattendus dans l'interface utilisateur du client SIP, ou bien marchant mal en cas d'authentification des partenaires.

D'où la nouvelle méthode décrite dans ce RFC (section 2) : comme dans la section 2.3 du RFC 5359, Bob envoie à son tour un message INVITE à Alice pour la mettre en attente, mais il ne fournit pas de SDP, pas de description des détails techniques de la session audio. Alice va alors en envoyer un à elle. Bob utilise l'option de la section 5.2 du RFC 4235 pour indiquer qu'il ne jouera pas le flux audio. Bob transmet le SDP d'Alice au serveur de musique d'attente, via un nouvel INVITE. Le serveur de musique va alors envoyer la musique en RTP (RFC 3550) à Alice. Cette sorte d'indirection (ici, Bob contactant le serveur de musique mais en lui disant d'envoyer le son à Alice) est très courant dans le monde SIP (et pose d'ailleurs d'amusants problèmes de sécurité).

Pour mettre fin à l'attente, le serveur de Bob ré-envoie un INVITE à Alice, un INVITE habituel, cette fois, avec un SDP de Bob. Et il coupe la session avec le serveur de musique d'attente.

Tiré du RFC (qui contient la session complète, avec tous les détails), voici la requête de Bob (ou plutôt du serveur de Bob) à Alice lorsqu'il la met en attente. Notez l'absence de SDP (de descripteur de session, le corps a une taille nulle) et le +sip.rendering="no" du RFC 4235 pour indiquer que Bob n'écoute pas, pour l'instant :


INVITE sips:a8342043f@atlanta.example.com;gr SIP/2.0
    Via: SIP/2.0/TLS biloxi.example.com:5061
     ;branch=z9hG4bK874bk
    To: Alice <sips:alice@atlanta.example.com>;tag=1234567
    From: Bob <sips:bob@biloxi.example.com>;tag=23431
    Call-ID: 12345600@atlanta.example.com
    CSeq: 712 INVITE
    Contact: <sips:bob@biloxi.example.com>;+sip.rendering="no"
    Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
    Supported: replaces
    Content-Length: 0

Et la sollicitation de Bob auprès du serveur de musique d'attente. Cette fois, un SDP est inclus, contenant l'adresse IP où Alice recevra le flux (192.0.2.69), le port où envoyer ce flux (49170) et le paramètre recvonly indiquant au serveur de musique qu'Alice écoutera mais ne parlera pas au dit serveur :


INVITE sips:music@source.example.com SIP/2.0
    Via: SIP/2.0/TLS biloxi.example.com:5061
     ;branch=z9hG4bKnashds9
    Max-Forwards: 70
    From: Bob <sips:bob@biloxi.example.com>;tag=02134
    To: Music Source <sips:music@source.example.com>
    Call-ID: 4802029847@biloxi.example.com
    CSeq: 1 INVITE
    Contact: <sips:bob@biloxi.example.com>
    Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
    Supported: replaces, gruu
    Content-Type: application/sdp
    Content-Length: [omitted]

    v=0
    o=bob 2890844534 2890844534 IN IP4 atlanta.example.com
    s=
    c=IN IP4 192.0.2.69
    t=0 0
    m=audio 49170 RTP/AVP 0
    a=rtpmap:0 PCMU/8000
    a=recvonly

Les avantages de ce mécanisme (section 3) ? Pas de transfert du dialogue SIP donc les adresses affichées par les logiciels SIP ne changent pas en cours de session. Pas d'utilisation de la commande REFER, introduite dans le RFC 3515 mais peu déployée. Lien direct entre le serveur de musique et l'appelant mis en attente (Alice), ce qui évite le faire passer le flux audio par le répondant (Bob).

Et les pièges (section 4) ? Il y a un petit risque qu'Alice n'indique pas, dans le SDP, tous les formats audio que gère son logiciel, mais seulement ceux qu'elle a utilisé avec Bob. C'est une violation des sections 5.1 et 5.3 du RFC 6337 mais cela peut arriver. Et, dans ce cas, il pourra arriver qu'elle ne reçoive rien parce que le serveur de musique d'attente croit, à tort, qu'elle ne gère pas les formats qu'il possède. Si Alice (enfin, son logiciel SIP), gère les formats X et Y, que B gère les formats X et Z, et que le serveur de musique gère les formats Y et Z, si Alice n'annonce dans son SDP que le format X (le seul qu'elle a en commun avec Bob), le serveur de musique croira qu'il ne peut pas la satisfaire, alors que le format Y aurait convenu.

Quelques mots enfin sur la sécurité (section 5). Le serveur de musique est un tiers qui n'est pas forcément sous la même administration que le serveur de Bob. Il va récupérer quelques informations (l'adresse IP d'Alice) et il faut donc que Bob (enfin, son fournisseur SIP), veille à ce que la sécurité du serveur de musique soit assurée. Le RFC suggère que le plus simple est que le fournisseur de Bob évite la sous-traitance et utilise un serveur de musique d'attente installé chez lui.

Quelles mises en œuvre de SIP ont une fonction de musique d'attente conforme à ce RFC ? Apparemment (mais je n'ai pas vérifié), les téléphones SIP de Polycom, le système OnSIP, les Cisco (ex-Linksys), etc. Vous pouvez trouver un pcap d'un dialogue avec musique d'attente en http://wiki.sipfoundry.org/display/sipXecs/Phone+Certification+Process (cherchez music on hold).


Téléchargez le RFC 7088


L'article seul

RFC 7086: Host Identity Protocol-Based Overlay Networking Environment (HIP BONE) Instance Specification for REsource LOcation And Discovery (RELOAD)

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : A. Keranen, G. Camarillo, J. Maenpaa (Ericsson)
Expérimental
Réalisé dans le cadre du groupe de travail IETF hip
Première rédaction de cet article le 17 janvier 2014


Le protocole pair-à-pair RELOAD, spécifié dans le RFC 6940, définit un certain nombre d'éléments minimum pour créer un réseau pair-à-pair mais pas la totalité. Il doit être complété par des descriptions d'un overlay particulier, un réseau utilisant RELOAD. Ce RFC est la spécification d'un overlay basé sur HIP.

HIP est normalisé dans le RFC 7401 et le cadre pour construire des overlays avec HIP est dans le RFC 6079. Ce RFC 7086 combine donc RELOAD et HIP BONE pour faire des réseaux pair-à-pair. À noter que tout RELOAD n'est pas utilisé : le Forwarding and link management layer de RELOAD (section 6.5 du RFC 6940 est complètement remplacé par HIP (section 3 de notre RFC).

Définir une classe d'instances RELOAD nécessite de spécifier les identificateurs utilisés pour les machines (Node ID dans RELOAD). Dans le cas de HIP, les Node ID peuvent être de deux types (section 4 de notre RFC) :

  • Les identificateurs HIP classiques, les ORCHID (RFC 7343), qui ont l'avantage de pouvoir s'utiliser dans les API existantes, puisqu'ils ont la forme d'une adresse IPv6, dans un préfixe dédié,
  • Des identificateurs RELOAD complets, qui permettent d'avantage de machines (2^128 au lieu de 2^100) mais qui ne sont plus compatibles avec les applications existantes.

Il faut aussi définir la correspondance entre les messages RELOAD et les messages HIP (section 5). Les messages RELOAD sont transportés dans des messages HIP de type DATA (RFC 6078) mais certains services assurés par des parties du message RELOAD sont déplacés vers HIP. Ainsi, le forwarding header de RELOAD (qui sert à contrôler l'envoi vers la destination finale) est remplacé par des fonctions HIP comme les listes Via (RFC 6028) qui permettent de mieux contrôler le routage, et le security block de RELOAD se déplace vers des extensions HIP comme les certificats du RFC 6253.

Normalement, les messages RELOAD sont sécurisés par l'utilisation de TLS (RFC 5246). Mais HIP peut déjà tout chiffrer. Plus besoin de TLS, donc, remplacé par le chiffrement HIP du RFC 6261.

Dans tout système pair-à-pair, le recrutement et l'arrivée de nouveaux pairs sont des points délicats (section 8). Ici, on utilise les mécanismes de RELOAD, avec quelques détails différents. Par exemple, les certificats échangés contiennent des HIT (condensat d'un HI, d'un identificateur HIP) et pas des URI RELOAD. Ces HIT sont placés dans le champ subjectAltName du certificat (RFC 6253).

Il a aussi fallu étendre un peu la définition du document de configuration initial (section 11 du RFC 6940 et section 10 de notre RFC). Récupéré par les pairs, ce document contient les informations nécessaires pour rejoindre l'overlay. L'élément XML <bootstrap-node> contient désormais un HIT.

Ce nouveau type d'overlay est désormais noté dans le registre IANA.

Il existe apparemment au moins une mise en œuvre de ce RFC mais je n'ai pas eu l'occasion de l'essayer.


Téléchargez le RFC 7086


L'article seul

RFC 7085: Top-Level Domains that Are Already Dotless

Date de publication du RFC : Décembre 2013
Auteur(s) du RFC : J. Levine (Taughannock Networks), P. Hoffman (Cybersecurity Association)
Pour information
Première rédaction de cet article le 5 décembre 2013


La question du bon ou mauvais fonctionnement d'un nom de domaine fait d'un seul composant (par exemple com ou dk) a déjà fait l'objet de pas mal d'articles. (Le premier était apparemment le mien, en 2009.) Elle a pris plus d'importance avec la création massive de nouveaux TLD par l'ICANN, les premiers ayant été introduits dans la racine du DNS en 2013. Ce RFC a une approche documentaire : il n'étudie pas le fonctionnement de ces domaines d'un seul composant (dotless domains) mais il regarde quels TLD, aujourd'hui, sont dans ce cas.

Le choix a été fait de considérer comme « permettant de faire des noms d'un seul composant » tout TLD ayant un enregistrement A (adresse IPv4), un AAAA (adresse IPv6) ou un MX (relais de courrier). C'est assez arbitraire (les différents documents sur les dotless domains ne sont pas d'accord sur la définition). Avec cette définition, des domaines d'un seul composant (dotless domains) existent (rappelons que l'ICANN ne régule pas le DNS ; ses règles ne s'appliquent pas à tous les TLD).

Donc, test fait en septembre 2013 : 5 % des TLD avaient un des enregistrements DNS qui les rendent « capables de faire des noms d'un seul composant » et tous étaient des ccTLD. 18 TLD ont un enregistrement MX (dont deux français, .mq et .gp). 17 (pas forcément les mêmes) ont un enregistrement A. Un seul, .dk, a un enregistrement AAAA.

Ce RFC ne formule pas de recommandations. Il ne dit pas si les domaines d'un seul composant sont Bien ou Mal (personnellement, je ne vois pas quels problèmes ils pourraient sérieusement poser).

Pour les informaticiens, le script qui a servi à compter ces résultats est inclus dans le RFC :


#! /bin/sh

# Get the current list of TLDs from IANA
wget -O orig.txt http://data.iana.org/TLD/tlds-alpha-by-domain.txt
# Remove the comment at the top of the file
grep -v '^#' orig.txt > TLDs.txt
# Get all the nameservers
while read tld; do host -t NS $tld; done < TLDs.txt > TLD-servers.txt
# Do queries for each record type, and do them on each nameserver
for rec in A AAAA MX; do
     while read tld ignorea ignoreb ns; do
       host -t $rec $tld. $ns;
     done < TLD-servers.txt;
done > all-out.txt
# Print the results
grep "has address" all-out.txt | sort -uf
grep "has IPv6" all-out.txt | sort -uf
grep "mail is handled" all-out.txt | sort -uf

Notez que ce script a peu de traitement d'erreurs. Comme la racine, dont l'ICANN ne vérifie pas vraiment la qualité, a plusieurs erreurs, vous aurez quelques messages amusants si vous le faites tourner.

Voici une liste non exhaustive des articles et études sur la question des domaines d'un seul composant :


Téléchargez le RFC 7085


L'article seul

RFC 7084: Basic Requirements for IPv6 Customer Edge Routers

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : H. Singh, W. Beebee (Cisco Systems), C. Donley (CableLabs), B. Stark (AT&T)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 23 novembre 2013


Ce RFC du groupe de travail v6ops, qui se consacre aux problèmes pratiques du fonctionnement d'IPv6 (sans modification des protocoles, donc), porte sur les CPE (Customer Premises Equipment), alias CER (Customer Edge Routers), alias home gateway, qui sont les boîtiers installés chez l'utilisateur domestique ou dans la petite entreprise. Par exemple, en France, la Freebox ou la DartyBox sont des CPE. Certains d'entre eux gèrent le protocole IPv6 et ce RFC résume tout ce que doivent savoir les concepteurs de ces « boxes » pour faire de l'IPv6 proprement. Il succède, avec quelques changements, au RFC 6204, qui était le premier de cette série.

Ce RFC se focalise (section 1) sur le cas où IPv6 est natif (pas de traduction d'adresses entre v4 et v6), et sur le cas simple où il n'y a qu'un seul CPE, qui récupère sa configuration sur le WAN, puis la distribue aux machines IPv6 locales, puis route leurs paquets. Le déploiement de l'IPv6 dans le réseau de l'opérateur n'est pas discuté (cf. RFC 4779). Ce RFC concerne uniquement le « foyer, doux foyer ».

Ce RFC utilise un vocabulaire normatif, celui du RFC 2119, mais pas pour spécifier un protocole mais pour indiquer quel est le minimum qu'on peut attendre d'un CPE IPv6 aujourd'hui.

D'abord (section 3), un rappel du fonctionnement d'un CPE IPv4 aujourd'hui. Ce fonctionnement n'est spécifié nulle part, il résulte d'une accumulation de choix par les auteurs anonymes des CPE existants. Ces choix sont souvent erronés. En l'absence de norme formelle, la section 3.1 décrit le CPE « typique » de 2012. Ce CPE typique a une (et une seule) connexion avec l'Internet, une seule adresse IP publique (et encore, parfois, il y a même du NAT dans le réseau de l'opérateur) et il sert de routeur NAT aux machines IPv4 situées sur le réseau local. Par défaut, en raison du NAT, il bloque toutes les connexions entrantes (c'est la seule allusion à cette question qui soit restée dans la version finale du RFC). Ouvrir des ports entrants (port forwarding) se fait par une configuration manuelle du CPE, via une interface Web (cas de la Freebox) ou bien par UPnP. C'est donc un vrai Minitel 2.0. Un avantage de ces adresses privées est toutefois d'assurer la stabilité des adresses internes : elles ne changent pas si on quitte son FAI.

L'architecture ci-dessus est largement déployée et correspond au cas de la plupart des abonnés à l'Internet à la maison. À quoi ressemblera t-elle en IPv6 ? On ne peut évidemment pas encore être sûr, mais la section 3.2, qui la décrit en termes très généraux, suppose qu'elle ne sera pas très différente, à part que la présence de plusieurs réseaux (et donc plusieurs préfixes IP) sera peut-être un cas plus fréquent qu'aujourd'hui. Quelles adresses IP seront utilisées à l'intérieur ? On pense immédiatement au RFC 5902, qui n'est toutefois pas cité. Le RFC 7084 présente la possibilité que des adresse locales, les ULA (RFC 4193) soient utilisées pour le réseau local. Le CPE devra bien alors fournir un mécanisme de traduction. Pour les communications entre machines du réseau interne, il faudra utiliser les mécanismes du RFC 4191.

Alors, maintenant, quelles sont les exigences auxquelles devront se plier les futurs CPE IPv6 ? La section 4 est la liste de ces demandes. Elles sont nombreuses et, pour s'y retrouver, elles portent chacune un identificateur formel, indiquant la catégorie et un numéro. Par exemple, la première, G-1, rappelle qu'un routeur est aussi un nœud du réseau et doit donc suivre le protocole IPv6, tel qu'il s'applique à tous les nœuds IPv6, routeur ou machine terminale (RFC 8504). Parmi les autres exigences (je vous rassure, je ne vais pas les citer toutes), G-4 et G-5 précisent que, si le CPE n'a pas pu obtenir une connectivité IPv6 avec l'extérieur, il ne doit pas publier d'adresses IPv6 sur le réseau local (car beaucoup d'applications réagissent mal lorsque la machine a une adresse IPv6 mais pas de connectivité, cf. RFC 6555). Si le CPE n'a pas de connectivité globale, il doit émettre des annonces RA (Router Advertisement, RFC 4861) avec une durée de vie nulle.

Le CPE se connecte avec le reste de l'Internet en suivant les protocoles standard d'encapsulation pour IPv6 par exemple le RFC 2464 pour Ethernet et le RFC 5072 pour PPP (exigences WLL-1 et WLL-2).

Le CPE doit donc obtenir une adresse et une connectivité depuis l'amont, depuis le FAI. Cela peut se faire avec NDP ou avec DHCP (tous les deux fonctionnent sur tout type de lien, pas seulement sur Ethernet). C'est pour cela que, sur PPP, il n'y a pas de mécanisme en IPv6 pour allouer des adresses globales (RFC 5072). Donc, exigence W-1, le CPE doit utiliser NDP (RFC 4862) ou DHCP (RFC 8415) pour récupérer une adressse IPv6 globale. Avoir une adresse pour le CPE, c'est très joli, mais il faut aussi qu'il ait un préfixe à déléguer aux clients du réseau local, et il doit l'obtenir avec la technique DHCP du RFC 8415 (exigences W-4 et WPD-1).

Nouveauté de ce RFC par rapport au RFC 6204, W-6, le CPE doit aussi inclure un client PCP (Port Control Protocol, RFC 6887) pour son propre usage (il n'est pas obligé de fournir ce service à ces clients du LAN).

À côté d'autre exigences évidentes, portant sur des fonctions de base d'IPv6, le RFC demande aussi que le client DHCP dans le CPE utilise les options du RFC 3646 permettant de récupérer la liste des serveurs de noms (exigences WAA-3 et WAA-4).

Il devrait aussi avoir un serveur NTP (RFC 5905), mais pour son usage, pas forcément pour distribuer l'heure sur le réseau local (exigence WAA-5). La liste des serveurs NTP devrait également être récupérée dynamiquement et de manière standard avec les options DHCP du RFC 5908.

Justement, côté LAN, maintenant, que doit faire le bon CPE IPv6 ? Là encore, on trouve beaucoup d'exigences qui sont juste un rappel des fonctions de base d'IPv6. Mais d'autres sont moins évidentes comme la capacité à gérer des ULA (exigence ULA-1 et RFC 4193) ou le serveur DHCP pour les clients du réseau local (exigence L-8, en pratique, très rare sur les CPE d'aujourd'hui). Ce serveur DHCP peut servir à l'affectation des adresses IP (RFC 8415) ou bien uniquement à distribuer des paramètres statiques, comme le permet le RFC 8415. Aussi bien en DHCP (RFC 3646) qu'en RA (RFC 8106), le CPE doit fournir aux machines du réseau local les adresses des serveurs de noms, ainsi que quelques paramètres DNS.

Également côté LAN, le CPE devra fournir des adresses globales ou des ULA (les adresses locales au lien ne suffisent pas et, de toute façon, pas besoin d'un routeur pour en acquérir). La gestion des ULA (RFC 4193) est désormais obligatoire, et le CPE doit pouvoir mémoriser le préfixe ULA, même en cas de redémarrage, de façon à fournir un préfixe stable (et, idéalement, configurable) au réseau dont il a la charge (exigences ULA-1, ULA-2 et ULA-3).

Une autre nouveauté de ce RFC 7084 par rapport à son prédécesseur, le RFC 6204, est l'exigence que le CPE IPv6 gère certaines des techniques de coexistence et de transition IPv4-IPv6. Ainsi, le RFC recommande fortement 6rd (RFC 5969) et DS-Lite (RFC 6333).

La securité est la dernière sous-section de cette section 4. C'est un sujet très délicat, car il opposait, à l'IETF, ceux qui voulaient interdire par défaut les connexions entrantes, au nom de la sécurité (« Minitel 2.0 ») à ceux qui voulaient profiter du fait qu'IPv6, avec son abondance d'adresses globalement uniques, permettait de rétablit le modèle de bout en bout de l'Internet, qui permet à deux machines consentantes d'échanger les paquets qu'elles veulent. Le compromis entre les deux camps a finalement été que le CPE devait mettre en œuvre, dans son logiciel, cette capacité de bloquage, mais pas forcément l'activer par défaut. Un autre RFC, le RFC 6092, discute plus en détail des fonctions de pare-feu d'un CPE. Dans notre RFC 7084, on a juste la recommandation que, par défaut, le CPE filtre les adresses IP usurpées (RFC 2827) et les paquets clairement invalides (bogons, par exemple).

Quels sont les changements depuis le RFC 6204, qui avait été le premier à s'attaquer à cette difficile question de la spécification d'un CPE idéal ? Ils sont assez importants (surtout que le RFC 6204 est assez récent, vieux de seulement deux ans et demi), et décrits en annexe A. Les principaux :

  • L'ajout des techniques de transition comme 6rd et DS-Lite.
  • La normalisation de PCP dans le RFC 6887, qui permet désormais de l'indiquer comme obligatoire (mais seulement pour le CPE lui-même, pas forcément pour les machines du réseau local).
  • Des obligations en plus, comme les paramètres DNS, qui passent de SHOULD à MUST.
  • Plus de précision dans certaines demandes, par exemple sur le fait que le CPE doive cesser d'annoncer des routes IPv6 si lui-même n'a plus de connectivité vers le FAI.

Les CPE d'aujourd'hui mettent-ils en œuvre ces recommandations ? Difficile à dire, je ne connais pas d'étude systématique ayant été faite sur les capacités de ces engins (un projet est en cours), mais ce serait certainement très instructif.


Téléchargez le RFC 7084


L'article seul

RFC 7083: Modification to Default Values of SOL_MAX_RT and INF_MAX_RT

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : R. Droms (Cisco Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 23 novembre 2013


Choisir les valeurs numériques par défaut des paramètres réseaux est un art difficile. Et, parfois, on se trompe et il faut corriger. Depuis qu'il y a des réseaux IPv6 utilisant DHCP pour leur configuration, suivant la spécification du RFC 3315, on observe parfois des pics de trafic importants qui ont été attribués à la valeur maximale trop basse de deux paramètres, SOL_MAX_RT et INF_MAX_RT. Ce RFC remonte donc ces valeurs. (Ce RFC a été depuis intégré dans le RFC 8415.)

Ces paramètres étaient définis dans le RFC 3315 (remplacé depuis par le RFC 8415, qui a intégré notre RFC 7083). Un client DHCP, en l'absence de réponse, doit réessayer mais en augmentant progressivement son délai d'attente jusqu'à une valeur maximale, à partir de laquelle il réessaiera périodiquement. SOL_MAX_RT est la durée maximale qu'un client DHCP attendra s'il ne reçoit pas de réponses à ses messages de sollicitation (section 17.1.2 du RFC 3315). Et INF_MAX_RT est la durée maximale entre deux demandes d'informations. Si le serveur DHCP choisit de ne pas répondre aux demandes de sollicitation des clients, chaque client retransmettra toutes les deux minutes, la valeur qui était indiquée par le RFC 3315. S'il y a des dizaines de milliers de clients DHCP, c'est trop, le serveur supportera une charge excessive.

La section 3 de notre RFC contient les nouvelles valeurs par défaut : SOL_MAX_RT et INF_MAX_RT passent de 120 secondes à 3 600. La charge d'un serveur, dans le pire des cas, devrait donc être divisée par trente. À noter que rien n'a été observé dans le monde réel pour INF_MAX_RT mais il est également remonté par souci de cohérence avec SOL_MAX_RT.

Attention : les valeurs spécifiées dans la section 3 sont des valeurs par défaut. Un serveur DHCP peut les changer en utilisant les nouvelles options du même nom (SOL_MAX_RT, numéro 82 et INF_MAX_RT, numéro 83) décrites dans les sections 4 et 5 et désormais enregistrées à l'IANA. Ces deux options dans la réponse DHCP permettent de spécifier une autre valeur (entre 60 et 86 400 secondes) pour les paramètres SOL_MAX_RT et INF_MAX_RT.

À noter qu'il n'existe pas encore de mise en œuvre de ces nouvelles options. Un client mis à jour devra obéir à ces options et un serveur mis à jour permettra de les fixer.


Téléchargez le RFC 7083


L'article seul

RFC 7078: Distributing Address Selection Policy using DHCPv6

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : A. Matsumoto, T. Fujisaki (NTT), T. Chown (University of Southampton)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 9 janvier 2014


Lorqu'une machine IPv6 a plusieurs adresses IP, laquelle choisir pour une connexion sortante ? Le RFC 6724 définit une politique par défaut, consistant en règles du genre « préférer les adresses temporaires du RFC 8981, pour des raisons de préservation de la vie privée ». Comme ce sont seulement des règles par défaut, on peut les changer. Un des mécanismes est que le serveur DHCP indique à ses clients d'autres règles et ce RFC décrit une nouvelle option DHCP permettant en effet de changer de politique de sélection d'adresse IP source. L'administrateur qui gère le serveur DHCP pourra alors fixer d'autres règles.

En effet, il y a peu de chances que la politique par défaut définie dans le RFC 6724 convienne à tout le monde. Le RFC 5221 demandait donc qu'on puisse changer de politique et ne pas être tenu éternellement par celle du RFC 6724. À noter que l'obéissance au serveur DHCP, quoique recommandée, n'est pas obligatoire : au bout du compte, l'administrateur de la machine contrôle la politique de sélection d'adresses IP source.

La syntaxe de la nouvelle option DHCP figure en section 2. L'option a le numéro 84 (dans le registre DHCP), et comprend deux booléens, A et P, suivis par une suite d'options de numéro 85 (rappelez-vous que DHCPv6 permet de mettre des options dans d'autres options). Chaque option de cette suite vaut pour une ligne dans la table des politiques (une ligne dans le fichier /etc/gai.conf si vous êtes sur Linux), donc une règle, et comprend :

  • Une étiquette (cf. RFC 6724, section 2.1),
  • Une précédence,
  • La longueur du préfixe,
  • Le préfixe des adresses IP.

Des exemples figurent en annexe A, en utilisant les scénarios du RFC 5220.

Le booléen A signifie « Automatic row addition flag » et veut dire, lorsqu'il est mis à 0, que la règle en question peut poser des problèmes et ne devrait pas être ajoutée automatiquement à la politique. Normalement, il est à 1. Le booléen P signifie « Privacy preference flag » et exprime la préférence donnée aux adresses temporaires (RFC 8981) pour préserver la vie privée. Il est normalement à 1, le choix le plus sûr (on sélectionne de préférence les adresses temporaires comme adresses sources).

En recevant ces options, le client DHCP met à jour sa propre table. C'est le comportement par défaut recommandé, avec une option pour débrayer cette mise à jour, et garder sa propre table originale.

Cette politique de sélection de l'adresse IP source est globale à la machine. Même si elle a plusieurs interfaces réseau, la table est commune à toutes. Une des raisons de ce choix est que l'interface de sortie est souvent choisie après l'adresse IP source et en fonction de celle-ci.

Quelques détails utiles pour le programmeur figurent en section 4 : l'étiquette est représentée dans le protocole par un entier non signé mais, en fait, la seule opération sur les étiquettes est la comparaison, et l'ordre n'a aucune signification. Le client peut donc la convertir dans n'importe quel type.

Il n'y a pas de limite de taille dans ce RFC et on pourrait donc en théorie envisager des tables énormes. En pratique, la taille maximale d'un datagramme UDP met une limite aux alentours de 3 000 règles et, de toute façon, la plupart des implémentations auront des problèmes bien avant (par exemple, parce qu'elles n'accepteront pas le datagramme UDP fragmenté).

Enfin, un peu de sécurité (section 5) : DHCP n'offrant aucune protection, un méchant peut facilement se faire passer pour le serveur DHCP officiel et envoyer des tables délirantes, menant à sélectionner une mauvaise adresse. Notez quand même qu'un tel serveur DHCP méchant peut faire bien d'autre chose que de d'envoyer de mauvaises tables. Les protections posisbles sont l'utilisation de techniques cryptographiques comme IPsec (ce que quasiment personne ne fait) ou bien le contrôle des messages DHCP par le commutateur (DHCP snooping).


Téléchargez le RFC 7078


L'article seul

RFC 7073: A Reputation Response Set for Email Identifiers

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : N. Borenstein (Mimecast), M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF repute
Première rédaction de cet article le 22 novembre 2013


Le cadre général du système de requête sur la réputation a été défini dans le RFC 7070. Il reste à le décliner en diverses applications. L'une des utilisations les plus importantes pour un système de réputation est évidemment la lutte contre le spam et c'est donc à cela qu'est consacré notre RFC : la réputation des identifiants de courrier électronique.

L'application se nomme donc email-id (et est enregistrée dans le registre des applications). Les assertions possibles sur un acteur du courrier sont :

  • abusive : envoie-t-il des messages abusifs, par exemple de harcèlement ou de menaces ?
  • fraud : envoie-t-il des messages frauduleux, par exemple de hameçonnage ? (Voir à ce sujet le RFC 5901.)
  • invalid-recipients : envoie-t-il des messages à des utilisateurs inexistants (ce qui est courant chez les spammeurs, soit parce que leurs listes sont de mauvaise qualité, soit parce qu'ils testent de nouvelles adresses).
  • malware : envoie-t-il du logiciel malveillant ?
  • spam : envoie-t-il du spam ?

Dans le cadre du RFC 7070, ces assertions ne sont pas binaires : une entité a, pour chaque assertion, un classement qui va de 0 (assertion tout à fait fausse) à 1 (assertion vraiment vraie). Ainsi, example.net pourrait avoir un classement de 0,01 à l'assertion malware (il n'envoie quasiment jamais de logiciels malveillants) mais de 0,8 à l'assertion spam (il envoie souvent du spam). Les classements sont linéaires donc une entité qui aurait un classement de 0,4 pour le spam pourrait être décrite par « est deux fois moins spammeur que example.net ».

On note que toutes ces assertions sont « négatives », décrivent un comportement qu'on désapprouve. L'annexe A du RFC rappelle que certains pensent qu'il serait plus intéressant de travailler sur des assertions positives (et donc des bonnes réputations), car on peut échapper à des mauvaises réputations (on achète un nouveau nom de domaine et hop, on repart de zéro). Cela se fera peut-être dans le futur.

En réponse à une requête d'application email-id et comportant une ou plusieurs de ces assertions (celles qui intéressent le client du service de réputation), le serveur de réputation renvoie un reputon, une information structurée en JSON comportant un certain nombre de membres obligatoires (cf. RFC 7071) et, dans le cadre de cette application email-id, deux autres :

  • email-id-identity qui indique comment a été identifié l'émetteur (la réputation ne vaut évidemment pas grand'chose sans authentification mais, parfois, on n'a pas le choix et on a des identités non authentifiées) : DKIM (l'identité doit alors être la valeur de l'étiquette d=), SPF, adresse IP, valeur du champ HELO dans la connexion SMTP, valeur du champ MAIL FROM dans la communication SMTP (ce qu'on nomme le « RFC 5321 from »), valeur de l'en-tête From: du message (ce qu'on nomme le « RFC 5322 from »),
  • sources qui indique le nombre de sources qui ont contribué à l'établissement de cette réputation (le membre standard sample-size est le total de rapports, mais ils peuvent tous provenir d'une seule source).

L'identité (email-id-identity) est cruciale car on dispose de plusieurs identités dans un message (le From: de l'en-tête n'est pas forcément le même que le MAIL FROM de l'enveloppe SMTP), et elles n'ont pas toujours la même force. Par exemple, le From: de l'en-tête n'a subi aucune validation et peut valoir n'importe quoi. Au contraire, une signature DKIM permet de rattacher un message à un domaine responsable. Si le client n'est intéressé que par un seul type d'identité (par exemple SPF), il peut le préciser dans la requête.

Un exemple de reputon ? OpenDKIM a un service de distribution de réputation DKIM (donc, seuls les domaines utilisant DKIM y sont présents) :


% wget -O - 'http://repute.opendkim.org/repute.php?subject=amazon.com&assertion=spam&application=email-id&service=repute.opendkim.org'
...
{
  "application": "email-id",
  "reputons": [
    {
	"rater": "repute.opendkim.org",
	"assertion": "spam",
	"rated": "amazon.com",
	"rating": 0.000229625,
	"identity": "dkim",
	"rate": 1013,
	"sample-size": 181,
	"generated": 1384331169
    }
  ]
}


Téléchargez le RFC 7073


L'article seul

RFC 7072: A Reputation Query Protocol

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : N. Borenstein (Mimecast), M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF repute
Première rédaction de cet article le 22 novembre 2013


Comment obtenir de l'information sur la réputation d'une entité (un nom de domaine, une adresse IP, etc) sur l'Internet ? Il existe actuellement tout un tas de méthodes ad hoc et le but du groupe de travail IETF repute est de fournir une alternative standard. Le RFC 7070 décrit le fonctionnement général de ce système. Ce cadre général autorise plusieurs protocoles concrets de récupération de l'information et ce RFC décrit un de ces protocoles, fondé sur HTTP.

Le mécanisme est assez simple et le RFC très court. Le client qui veut se renseigner auprès d'un serveur de réputation travaille en deux temps :

  • Il récupère un gabarit auprès du serveur de réputation, et l'utilise pour fabriquer un URI,
  • Il récupère ensuite le reputon, exprimé en JSON (cf. RFC 7071), via cet URI.

Ce mécanisme en deux étapes permet de la souplesse : les reputons peuvent se trouver derrière des URI très différents, qui n'ont pas besoin d'être « en dur » dans le client.

Ainsi, le service de réputation d'OpenDKIM, accessible en repute.opendkim.org a le gabarit http://{service}/repute.php{?subject,application,assertion,service,reporter} ce qui s'expanse en http://repute.opendkim.org/repute.php?subject=nom-de-domaine&application=email-id&assertion=spam&service=repute.opendkim.org (reporter est optionnel). Rappel de syntaxe des gabarits : le point d'interrogation ne s'applique pas qu'à la variable suivante mais à toutes les variables entre crochets.

Il n'y a pas de mécanisme de découverte d'un serveur de réputation : typiquement, cela se fait manuellement. En pratique, beaucoup de ces services nécessiteront une inscription ou un abonnement, de toute façon. Notez que le RFC ne spécifie pas de mécanisme d'authentification du client : on se sert par exemple des solutions classiques de HTTP. De même, si on veut de la confidentialité, on doit utiliser les mécanismes de chiffrement habituels, donc HTTPS (voir section 5 de ce RFC).

Le client doit aussi connaître le nom de l'application et le nom de l'assertion à tester. Il récupére ensuite le gabarit, en utilisant un URI « bien connu » (RFC 8615), /.well-known/repute-template (désormais dans le registre IANA des URI bien connus). Ce gabarit suit la syntaxe du RFC 6570. Le client remplace alors les variables. Par exemple, pour le gabarit ci-dessus, la variable application va être remplacée par email-id (le serveur de réputation peut gérer plusieurs applications). Pour reprendre l'exemple du RFC, si le gabarit du service example.com avait été http://{service}/{application}/{subject}/{assertion}, et qu'on cherchait des informations sur la réputation de example.org dans le cadre de l'application email-id (normalisée dans le RFC 7073), sur l'assertion spam, l'expansion du gabarit donnerait http://example.com/email-id/example.org/spam. Quelles sont les variables possibles dans un gabarit ?

  • application est le nom de l'application, pris dans le registre IANA,
  • service est le nom (ou l'adresse IP) du service de réputation demandé (celui d'où on a obtenu le gabarit),
  • subject est l'entité dont on veut connaître la réputation,
  • assertion est l'assertion qui nous intéresse, les valeurs possibles dépendant de l'application,
  • Sans compter des variables spécifiques à l'application.

Si un paramètre est optionnel mais que la syntaxe du gabarit ne permet pas de l'omettre, le client met une chaîne de caractères vide. L'auteur du gabarit doit veiller à ce que cela ne mène pas à des URI incorrects. Ainsi, le gabarit http://{service}/{application}/{subject}/{assertion}/{a}/{b}, si a est facultatif, pourrrait mener à une expansion où on aurait deux barres obliques de suite, ce que bien des serveurs HTTP réduisent à une seule, faussant ainsi la lecture de l'URI. Une bonne solution serait d'utiliser le mécanisme des gabarits du RFC 6570 pour les paramètres optionnels et donc de réécrire le gabarit vers http://{service}/{application}/{subject}/{assertion}/{?a,b}.

La réponse générée par le serveur de réputation sera alors un reputon (RFC 7071), étiqueté application/reputon+json.

Il existe une implémentation (due à Murray S. Kucherawy, un des auteurs du RFC) dans OpenDKIM à partir de la 2.9 (actuellement en version beta), le serveur est écrit en PHP (le serveur produit du JSON avec printf...) et le client en C. Testons-là avec le service public repute.opendkim.org. On récupère le gabarit :

% curl http://repute.opendkim.org/.well-known/repute-template
http://{service}/repute.php{?subject,application,assertion,service,reporter,format}

On fabrique ensuite une requête curl à la main (un vrai client du service de réputation le ferait automatiquement à partir du gabarit) :

% curl 'http://repute.opendkim.org/repute.php?subject=gmail.com&assertion=spam&application=email-id&service=repute.opendkim.org'
Content-Type: application/reputon+json

{
  "application": "email-id",
  "reputons": [
    {
	"rater": "repute.opendkim.org",
	"assertion": "spam",
	"rated": "gmail.com",
	"rating": 0.0113348,
	"identity": "dkim",
	"rate": 1735,
	"sample-size": 181,
	"generated": 1383463475
    }
  ]
}

On voit que Gmail émet apparemment peu de spam (classement à 0,0113348). Ce service est mis en œuvre avec les messages reçus par le domaine opendkim.org et seulement s'ils sont signés par DKIM (donc, n'essayez pas avec un domaine non signé comme laposte.net, vous aurez un No data available).


Téléchargez le RFC 7072


L'article seul

RFC 7071: A Media Type for Reputation Interchange

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : N. Borenstein (Mimecast), M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF repute
Première rédaction de cet article le 22 novembre 2013


Le cadre général d'accès à l'information sur la réputation d'une entité (identifiée par son nom de domaine, son adresse IP ou d'autres identificateurs) a été défini dans le RFC 7070. Cet autre RFC est plus concret et définit le format d'un reputon, une information structurée (en JSON) sur la réputation d'une entité, ainsi que le type de media associé, le nouveau application/reputons+json. Il crée également des registres IANA pour les noms d'applications de réputation et les réponses possibles selon l'application.

Le cadre du RFC 7070 prévoit que l'accès aux informations de réputation peut se faire par plusieurs mécanismes comme par exemple HTTP (RFC 7072). Mais le format transporté est toujours le même, celui d'un reputon. Un reputon est un objet JSON comportant les informations de réputation : identificateur de l'entité jugée, assertions sur cette identité, classement de l'identité selon ces assertions. Une requête va donc renvoyer un ou plusieurs reputons.

La section 3 liste les attributs d'un reputon, notamment :

  • L'identité de l'entité (rater) qui a jugé de la réputation,
  • Celle de l'entité jugée (rated),
  • L'assertion,
  • Le classement (rating) de l'entitée jugée, selon cette assertion, de 0,0 (assertion complètement fausse) à 1,0 (assertion tout à fait vraie).

Les identités dépendent de l'application et peuvent être des noms de domaine, des adresses IP, etc. La section 4 décrit en détail la notion de classement. Il y a aussi des attributs facultatifs dans un reputon :

  • Degré de confiance du juge vis-à-vis de son classement, de 0,0 à 1,0,
  • Classement considéré comme normal, pour pouvoir estimer si l'entité jugée est « dans les clous » ou pas,
  • Taille de l'échantillon sur lequel s'est fondé le jugement,
  • Date et heure où le classement a été établi (generated),
  • Date et heure à partir desquelles le jugement cessera d'être valable (expires).

Ces deux derniers attributs sont représentés par un nombre de secondes depuis le 1er janvier 1970. L'attribut expires permet (mais n'oblige pas) de mettre en place des caches devant le serveur qu'on interroge (section 5). Le RFC recommande de mettre des durées de validité d'autant plus courtes qu'on n'est pas sûr du jugement, par exemple parce qu'on n'a pas encore récolté beaucoup de données.

La section 6 indique la syntaxe concrète des reputons, sous forme d'un objet JSON, dont les membres (couples {clé, valeur}) représentent les attributs présentés plus haut. Les reputons sont mis dans un tableau JSON, puisqu'on peut en avoir plusieurs (s'il existe plusieurs assertions). Les assertions présentes dans un reputon sont typiquement celles qui ont été demandées par le client. Si ce dernier ne précise rien, le serveur peut renvoyer toutes les assertions qu'il connait. Un reputon peut être vide, si le serveur n'a aucune information sur l'entité et l'assertion demandées.

Voici l'exemple de reputon donné par le RFC, emprunté au baseball :

{
       "application": "baseball",
       "reputons": [
         {
           "rater": "RatingsRUs.example.com",
           "assertion": "is-good",
           "rated": "Alex Rodriguez",
           "rating": 0.99,
           "sample-size": 50000
         }
       ]
}

On a un seul reputon, pour l'assertion « est un bon joueur ». Vu le classement (quasiment 1), on peut dire que RatingsRUs.example.com estime qu'Alex Rodriguez est un bon joueur.

L'assertion est ici très générale. Elle pourrait être plus précise, si les concepteurs de l'application baseball le voulaient :

{
       "application": "baseball",
       "reputons:" [
         {
           "rater": "baseball-reference.example.com",
           "assertion": "hits-for-power",
           "rated": "Alex Rodriguez",
           "rating": 0.99,
           "sample-size": 50000
         },
         {
           "rater": "baseball-reference.example.com",
           "assertion": "strong-hitter",
           "rated": "Alex Rodriguez",
           "rating": 0.4,
           "confidence": 0.2,
           "sample-size": 50000
         }
       ]
}

Si vous ne connaissez pas le baseball et que vous vous demandez ce que veut dire hits-for-power (ne frappe pas forcément beaucoup mais fort) ou strong-hitter (frappe souvent des coups sûrs), voyez Wikipédia. On voit que le même Alex Rodriguez a une nettement moins bonne réputation pour strong-hitter que pour hits-for-power. Notez aussi l'indication de la taille de l'échantillon (ici, 50 000 points de mesure), qui permet aux statisticiens de se faire une idée de la validité de ces classements.

Un exemple moins artificiel de service de réputation serait évidemment lié à la lutte contre le spam. Prenons donc cette fois une application réelle, enregistrée dans le registre IANA des applications de réputation, l'application email-id définie dans le RFC 7073. Ce tableau contient deux reputons :

     {
       "application": "email-id",
       "reputons": [
         {
           "rater": "rep.example.net",
           "assertion": "spam",
           "identity": "dkim",
           "rated": "example.com",
           "confidence": 0.95,
           "rating": 0.012,
           "sample-size": 16938213,
           "updated": 1317795852
         },
         {
           "rater": "rep.example.net",
           "assertion": "spam",
           "identity": "spf",
           "rated": "example.com",
           "confidence": 0.98,
           "rating": 0.023,
           "sample-size": 16938213,
           "updated": 1317795852
         }
       ]
     }

Il se lit ainsi : « example.com, authentifié par DKIM (regardez l'attribut identity, spécifique à cette application) envoit du spam 1,2 % du temps. L'échantillon compte près de 17 millions de messages ». À noter que le second reputon, basé sur SPF, indique presque deux fois plus de spam. Cela peut vouloir dire que la liste des serveurs SMTP autorisés par SPF comprend quelques moutons noirs.

Ces reputons seront étiquetés avec le nouveau type application/reputons+json désormais enregistré à l'IANA. Il utilise les suffixes (+json) du RFC 6839. Est également enregistrée à l'IANA la liste des applications. Les nouvelles applications qui voudraient être incluses dans ce registre doivent avoir un examen par l'IETF ou bien une spécification stable (le RFC 5226 contient la liste des règles d'enregistrement à l'IANA).

Vous voulez voir des vrais reputons ? Il n'y a pas encore beaucoup de services disponibles publiquement. Essayons avec celui d'OpenDKIM :


% curl 'http://repute.opendkim.org/repute.php?subject=ietf.org&assertion=spam&application=email-id&service=repute.opendkim.org'
Content-Type: application/reputon+json

{
  "application": "email-id",
  "reputons": [
    {
	"rater": "repute.opendkim.org",
	"assertion": "spam",
	"rated": "ietf.org",
	"rating": 0,
	"identity": "dkim",
	"rate": 4,
	"sample-size": 2,
	"generated": 1338014959
    }
  ]
}

Très bon score pour ietf.org, une spamicité nulle. Mais faites attention à la taille de l'échantillon, seuls deux messages ont été examinés...

Merci à Vincent Levigneron pour ses explications sur le baseball (les erreurs qui restent sont les miennes, je n'ai pas forcément tout compris).


Téléchargez le RFC 7071


L'article seul

RFC 7070: An Architecture for Reputation Reporting

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : N. Borenstein (Mimecast), M. Kucherawy, A. Sullivan (Dyn)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF repute
Première rédaction de cet article le 22 novembre 2013


Il y a des tas de fois dans l'Internet où on souhaite se renseigner automatiquement sur la réputation d'une entité (une adresse IP, un nom de domaine, etc). Aujourd'hui, chaque application qui souhaite le faire développe une technologie spécifique pour l'accès à cette réputation (comme les listes noires DNS du RFC 5782). L'idée du projet repute de l'IETF est de créer des mécanismes communs, utilisables par une variété d'applications. Ce premier RFC est la fondation du projet et décrit l'architecture générale du système de réputation. D'autres RFC vont décrire les détails.

Un des principes fondateurs de l'Internet est qu'on n'a pas besoin de montrer patte blanche avant d'accéder à un service. Par exemple, pour une des applications les plus répandues, le courrier électronique, n'importe qui peut écrire à n'importe qui sans introduction préalable. On entend souvent des gens qui n'ont pas réfléchi à la question dire que cela contribue aux problèmes de sécurité de l'Internet. Mais cela a surtout contribué à son succès ! Comme le note à juste titre le RFC 5218, un système plus rigide, avec mécanismes de sécurités dès le début, avec authentification obligatoire avant d'envoyer un message, plairait certes aux dirigeants chinois ou saoudiens, et permettrait certainement de mieux traiter certains problèmes comme le spam. Mais il aurait aussi certainement à coup sûr tué le courrier électronique avant même qu'il ne décolle (ce n'est pas un avis personnel : c'est une constatation fondée sur l'observation de systèmes concurrents, bien oubliés aujourd'hui).

Donc, la plupart des services de l'Internet n'authentifient pas (l'émetteur d'un courrier peut mettre ce qu'il veut dans le champ From:...) et, même lorsqu'ils le font (en cas d'utilisation de TCP, l'adresse IP est relativement authentifiée), l'authenticité d'un pair ne nous renseigne pas sur son honnêteté et sa sincérité. Cette confusion entre authentification et autorisation est très fréquente, elle a même mené certains spammeurs à être les premiers à déployer certaines techniques (comme DKIM), en espérant jouer sur cette confusion. Si certains administrateurs de serveurs de messagerie étaient assez bêtes pour retirer des points de « spamicité » uniquement parce qu'un message avait une signature DKIM valide, le spammeur pouvait espérer injecter quelques spams en plus.

Résultat, les services de l'Internet, comme le courrier électronique, sont un grand succès mais, suite logique de ce succès, sont affligés de nombreux problèmes de sécurité (« Any real ecosystem has parasites », dirait Cory Doctorow). Comment lutte-t-on contre ces problèmes ? Une méthode courante est d'utiliser la réputation, c'est-à-dire des affirmations par un tiers comme quoi telle ou telle entité est digne de confiance. Son utilisation est particulièrement courante dans le cadre de la lutte contre le spam : on demande à un service de réputation « cette adresse IP est-elle souvent émettrice de spam ? » Si oui, on peut décider de ne pas accepter son message. Cette fois, on ne se limite pas à l'authentification : on bâtit au-dessus d'elle.

Si le monde du courrier électronique fut le premier à utiliser à grande échelle ces systèmes de réputation, d'autres dans l'Internet pourraient y venir. C'est pour les aider qu'a été développé ce modèle, et les protocoles qui l'accompagnent. En effet, les mécanismes actuels (le plus connu étant les DNSBL décrites dans le RFC 5782 mais il y a aussi le système du RFC 5518 pour se porter garant) sont très simplistes, notamment par le fait que leur réponse est binaire. On aurait besoin de nuances, et de la capacité d'apporter des détails (le RFC cite comme exemple la différence entre « approuver un chèque » et une institution très typiquement états-unienne, « faire un credit report complet »). Autre exemple où les systèmes actuels sont insuffisants, le cas où un acteur a une réputation différente selon ses services. Par exemple, un site de commerce en ligne peut avoir une mauvaise réputation pour les délais de livraison, mais un bonne réputation pour la qualité de l'information qu'il donne en cas de problème.

Compte tenu de tous ces points, le groupe de travail a développé un modèle, qui est résumé en section 2 de ce RFC. La réputation se gère à trois. On a un acteur qu'on veut évaluer, désigné par un identificateur. Un client qui est intéressé par la réputation de cet acteur. Et un service de réputation qui va distribuer de l'information sur les acteurs. Le service de réputation peut être public ou accessible seulement à des abonnés. Le client devra être configuré pour accéder à ce service de réputation. Les identificateurs utilisés peuvent être variés : noms de domaine, adresses de courrier électronique, adresses IP, etc.

Descendons un peu plus dans les détails (sections 4 à 6). L'architecture du système est celle d'un simple protocole question/réponse, qui peut utiliser comme transport sous-jacent divers mécanismes comme par exemple HTTP, le DNS... La syntaxe exacte dépend de l'application (rappelez-vous que ce RFC ne décrit qu'un cadre général). Un format possible des informations de réputation est normalisé dans le RFC 7071, un des protocoles d'accès, fondé sur HTTP, est dans le RFC 7072, et les identificateurs utilisés dans le cas du courrier électronique sont dans le RFC 7073.

Prenons l'exemple d'une application, un logiciel qui reçoit le courrier électronique, et qui utilise DKIM (RFC 6376) pour authentifier le domaine expéditeur. Ce nom étant authentifié, elle pourra s'en servir comme base de l'évaluation du message : on authentifie l'envoyeur du courrier avec DKIM, on interroge un serveur de réputation sur la réputation de cet envoyeur, et on décide alors d'accepter le message ou de l'envoyer dans le dossier « Spam ». DKIM apporte l'authentification, le système de notre RFC ajoute la réputation, et les deux ensemble permettent l'autorisation.

Que retourne un serveur de réputation ? Trois choses importantes :

  • Le nom de l'entité qu'il vient d'évaluer (dans l'exemple précédent, ce pourrait être gmail.com, le domaine expéditeur qui signe avec DKIM).
  • Une (ou plusieurs) assertion(s). Une assertion est une affirmation, plus ou moins fausse, sur le comportement de l'entité. Pour un domaine expéditeur, cela pourrait être « envoie du spam ». Pour un site de commerce en ligne, « livre dans les temps ». Pour quelqu'un qui modifie Wikipédia, « vandalise des articles ».
  • Un classement. Contraitrement aux DNSBL, le système de réputation n'est pas binaire. Une assertion peut être plus ou moins fausse et c'est ce qu'exprime le classement. Un classement va de 0 (assertion complètement fausse) à 1 (assertion toujours vraie). Ainsi, un domaine qui envoie rarement du spam pourrait avoir un classement de 0,2 à l'assertion « envoie du spam » alors qu'un domaine plus spammeur aurait un classement de 0,6.

Rappelez-vous que les assertions pertinentes, ainsi que la signification des classements, dépendent de l'application. Chaque application (réception de courrier, jugement des commentaires sur un blog, etc) aura donc sa propre spécification, décrivant les réponses attendues. Les applications ainsi spécifiées sont stockées dans un registre IANA.

La réponse structurée est dans un objet nommé « reputon ». Les détails de sa syntaxe dépendent du transport utilisé et de l'application. Mais si vous voulez voir des exemples de reputons, regardez le RFC 7071.

Pour obtenir un reputon en réponse, le client aura dû envoyer le nom de l'entité qu'il veut évaluer, le nom de l'application (tiré du registre IANA cité plus tôt) et, éventuellement, les assertions qui l'intéressent (le serveur de réputation peut en stocker plusieurs pour une même entité).

Comme le note la section 8, tout ceci peut poser des problèmes de préservation de la vie privée. Les informations de réputation peuvent dans certains cas être considérées sensibles et pas distribuables publiquement. Et il n'y a pas que la réponse qui peut être sensible, la question l'est aussi parce qu'elle révèle un intérêt du client (« le MP3 tina-turner-total-eclipse-of-the-heart.mp3 de condensat SHA-256 5ba214e312254abd22e7aae38af865a92f93cbd01e180051ab5bd443ceeae594, que je m'apprête à télécharger, est-il de bonne qualité ? ») Le RFC insiste donc sur la nécessité de fournir de la confidentialité si les données le justifient. Par exemple, le DNS, qui ne fournit aucune confidentialité, ne doit en aucun cas être utilisé pour des services sensibles. Si on se sert de HTTP comme transport de données de réputation sensibles, il faut utiliser HTTPS et, si on se sert du courrier, PGP ou équivalent.

De même, un accès non autorisé à la base de données d'un serveur de réputation pourrait causer des dommages, si ces données sont privées.

Mais il y a aussi des problèmes de sécurité qui ne sont pas liées à la vie privée (section 9). Par exemple, que se passe t-il si le serveur de réputation ment, distribuant délibérement des informations trop ou pas assez favorables à certaines entités ? Si un client accède à des informations de réputation, c'est probablement pour s'en servir pour prendre des décisions et des informations fausses peuvent donc avoir des conséquences concrètes désagréables. Imaginez un serveur de courrier qui accepterait du spam (ou, au contraire, rejetterait des messages légitimes) parce que le serveur de réputation l'a trompé.

Il n'y a pas de solution miracle à ce problème. Utiliser un serveur de réputation, c'est sous-traiter, c'est faire confiance. Cela implique le risque d'être trompé. Au minimum, le RFC conseille de ne faire confiance qu'à des services de réputation qui publient leurs pratiques de classement, qu'on puisse les analyser (voir le RFC 6471 pour ce problème dans le cas des listes noires de spammeurs dans le DNS).

Les motivations pour le projet de réputation ont été décrites dans les supports de la première présentation à l'IETF.

Pour des exemples d'utilisation et des informations sur les mises en œuvre de ce système, voir mes articles sur le RFC 7071 et sur le RFC 7072. Merci à Murray S. Kucherawy pour son aide.


Téléchargez le RFC 7070


L'article seul

RFC 7069: DECoupled Application Data Enroute (DECADE)

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : R. Alimi (Google), A. Rahman (InterDigital Communications), D. Kutscher (NEC), Y. Yang (Yale University), H. Song (Huawei Technologies), K. Pentikousis (EICT)
Pour information
Première rédaction de cet article le 27 novembre 2013


L'architecture traditionnelle de l'Internet est celle d'un réseau « bête », transportant des paquets sans en comprendre le contenu, avec toute l'« intelligence » concentrée aux extrémités, dans les machines terminales. Un travail avait été commencé à l'IETF, dans le défunt groupe DECADE, pour voir s'il était possible de changer légèrement ce modèle pour certaines catégories d'applications (notamment pair-à-pair), en dotant le réseau de capacité de stockage des données (un peu comme le font, de manière non-standard, les CDN). Le projet a finalement échoué mais a publié quelques RFC, dont ce dernier document, qui décrit l'architecture d'un tel système.

Les deux autres RFC importants de DECADE étaient le RFC 6646, exposé détaillé du problème, et le RFC 6392, qui fait le tour des mécanismes disponibles. (Il est très recommandé de lire au moins le RFC 6646 avant ce RFC 7069.) Finalement, le projet a été abandonné et le groupe DECADE dissous, mais, pour ne pas perdre le travail effectué, il est publié dans ce nouveau RFC, qui décrit, en termes assez généraux, l'architeecture de DECADE. Comme exemple d'usage, prenons une machine connectée en ADSL. Elle a typiquement une capacité réseau « montante » très limitée. Mettre à jour le réseau pour augmenter cette capacité (par exemple pour passer en FTTH) risque d'être coûteux. Disposer dans le réseau des dispositifs de stockage permettant à cette machine de distribuer du contenu sur l'Internet sans tuer sa capacité ADSL limitée serait peut-être plus économique. (Notez aussi que cela soulève d'intéressants problèmes politiques de contrôle sur les données servies.)

Donc, l'idée est d'avoir des serveurs DECADE dans le réseau, qui stockent les données des clients DECADE. Les données pourront être copiées entre serveurs, et récupérées par d'autres clients que ceux qui les ont déposées. Pour cela, il faudra un protocole de gestion des ressources déposées, le DRP (DECADE Resource Protocol) et un protocole d'accès aux ressources, le SDT (Standard Data Transfer protocol). Pour ce dernier, il était prévu dès le début d'utiliser un protocole standard existant comme HTTP.

Les serveurs DECADE seront fournis par des fournisseurs de stockage, qui pourront être les FAI ou bien d'autres acteurs. Ces fournisseurs décideront de l'allocation de ressources (espace de stockage, capacité réseau).

Il n'était pas prévu que les utilisateurs accèdent aux serveurs DECADE directement mais que ceux-ci fournissent un service aux applications, service masqué aux utilisateurs. La section 3 de notre RFC contient un schéma qui illustre ce principe : une application veut envoyer des données à une autre application (les deux applications parlent entre elles avec un protocole pair-à-pair quelconque). Pour cela, elle envoie les données au serveur avec le SDT (rappelez-vous que c'est un protocole standard comme HTTP) et utilise le DRP pour indiquer au serveur les conditions d'accès aux données. L'autre application utilisera SDT pour récupérer les données. Selon le niveau de confidentialité des données, il y aura aussi peut-être une étape de récupération d'un jeton que l'envoyeur transmettra au destinataire (toujours avec leur protocole pair-à-pair à eux, qui ne regarde pas DECADE), et avec lequel le destinataire pourra prouver ses droits au serveur DECADE. Un peu comme les applications « passe-plat » existants comme http://dl.free.fr/ mais masqué à l'utilisateur. Entre parenthèses, ce scénario d'usage avait été réclamé dans un excellent dessin de xkcd.

La section 4 décrit l'architecture du service DECADE (s'il avait été construit ; rappelez-vous que le projet a été abandonné). En gros, DECADE fournira les données (data plane), l'application pair-à-pair la signalisation (control plane). DECADE se voulait indépendant de l'application, fournissant un service général de données. Les applications auraient géré les services comme l'indexation, le moteur de recherche dans les données, etc. Des systèmes de stockage des données séparant données et signalisation existent déjà. Le RFC mentionne Google File System, ou l'extension pNFS de NFS, décrite dans la section 12 du RFC 5661.

Une chose importante avec DECADE est que ce système ne prévoit pas de modifier le contenu déposé dans le stockage en réseau. Les objets écrits sont immuables (section 4.2). Ce principe permet de simplifier considérablement le système, puisqu'il n'y a plus de problème de synchronisation entre les différents serveurs de stockage. Si on veut vraiment modifier une ressource mise en ligne, il faut détruire l'ancienne et en mettre une nouvelle. Ce sera à l'application, pas à DECADE, de changer la correspondance entre le nom de la ressource et le nouvel objet qui, pour DECADE, sera un objet différent, sans lien avec le premier. Chaque application aura en effet son propre système de nommage. On peut comparer cela avec le nommage dans un système de fichiers (comme /home/stephane/Downloads/galaxy.avi) contre celui de plus bas niveau utilisé par le système de fichiers pour parler aux contrôleurs de disque.

Puisqu'on a commencé à parler d'identité (« le même objet ») et donc d'identificateurs, quels sont les identificateurs dans DECADE ? Chaque objet a un identificateur unique. Si un objet est répliqué sur plusieurs serveurs, toutes ces copies sont toujours désignées par le même identificateur. DECADE n'envisageait pas d'imposer un mécanisme unique de nommage mais le RFC suggère d'utiliser des condensats du contenu, comme dans le RFC 6920 (voir aussi la section 6.1). Là encore, l'immuabilité des objets stockés est essentielle pour que ce nommage par le contenu fonctionne.

La section 5 est plus concrète, décrivant certains des composants du système. Par exemple, elle couvre les jetons d'authentification, dont l'utilisation était prévue pour que le déposant d'un fichier puisse distribuer des droits d'accès à des lecteurs (voir aussi la section 6.2.1). Elle parle aussi de l'importance d'avoir un mécanisme de découverte (non spécifié : rappelez-vous que le travail sur DECADE avait été interrompu en route) pour localiser le serveur DECADE approprié.

La section 6, elle, est consacrée aux protocoles DRP (protocole de contrôle) et SDT (protocole de transport des données). Elle est également assez abstraite : l'idée originale est que des protocoles concrets seraient choisis ultérieurement. Ces protocoles ne sont pas utilisés seulement entre un client DECADE et un serveur DECADE mais aussi entre serveurs, notamment pour la réplication. Les données stockées dans DECADE peuvent en effet être automatiquement copiées de serveur à serveur pour augmenter les performances lors de la récupération (section 6.4). Une évaluation des protocoles possibles pour remplir ces rôles figure dans l'annexe A.

HTTP (RFC 7230) est évidemment le premier protocole considéré. C'est un candidat presque idéal pour le rôle de SDT mais il peut aussi servir de DRP. HTTPS fournit des mécanismes de sécurité bien compris et largement déployés. HTTP permet d'assurer les deux fonctions du SDT, en lecture mais aussi en écriture (avec les méthodes PUT et POST). Par contre, il lui manque quelques fonctions, comme des ACL ou comme des mécanismes de transmission de politique d'accès au serveur. Ceci dit, ces manques pourraient être comblés en ajoutant quelques en-têtes dans les requêtes et réponses HTTP. C'est ce que fait Google Storage. Ce dernier utilise OAuth (RFC 6749) pour les délégations d'accès.

Un autre candidat est CDMI. Il est basé sur HTTP mais avec de nombreux enrichissements. Lui dispose d'ACL aussi riches qu'on le veut. Et, question contrôle des données, il permet de spécifier des choses comme le nombre de copies à générer, leur placement géographique, la durée de conservation, etc. CDMI parait donc plus proche des besoins de DECADE.

Et la sécurité d'un système comme DECADE ? La section 8 la décrit en détail, en s'appuyant sur la section 5 du RFC 6646. Il y a évidemment le risque d'attaques par déni de service, par exemple si un client méchant envoie une quantité astronomique de données à stocker.

Pour l'accès aux données, DECADE comptait sur un mécanisme de délégation : on n'autorise pas le client, mais on distribue des jetons dont la possession suffit pour l'accès. Les problèmes de sécurité liés à ces mécanismes de délégation sont traités dans la section 10 du RFC 6749.

Un autre type d'attaque est dirigé contre le client : arriver à lui faire télécharger des données qui ne sont pas celles qu'il espérait. Ce genre d'attaques est courant dans le monde du téléchargement pair-à-pair où un fichier nommé hot-naked-women-at-the-beach.avi peut en fait contenir un discours d'un télévangéliste. S'il est difficile de se prémunir contre un nom trompeur, en revanche, DECADE peut sécuriser la liaison entre un nom et un objet. Ainsi, des adresses basées sur un condensat du contenu sont auto-validantes : après le téléchargement, on recalcule le condensat et on vérifie que le contenu est bien celui demandé. Cela ne règle qu'une partie du problème : la publicité mensongère, par exemple pour tromper un moteur de recherche, reste possible.


Téléchargez le RFC 7069


L'article seul

RFC 7066: IPv6 for 3GPP Cellular Hosts

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : J. Korhonen (Renesas Mobile), J. Arkko (Ericsson), T. Savolainen (Nokia), S. Krishnan (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 5 novembre 2013


Il y a désormais des tas d'engins mobiles connectés à l'Internet, par la 3G ou bientôt par la 4G (mon Dieu, je mets des termes marketroïdo-publicitaires sur mon blog...) Les spécifications de ces protocoles imposent normalement IPv6 mais, en pratique, on ne trouve quasiment jamais d'IPv6 sur ces réseaux mobiles (tiens, le RFC utilise le terme états-unien, cellular). D'ailleurs, ça veut dire quoi « gérer IPv6 » pour ces engins ? Quels sont, parmi les nombreux RFC sur IPv6, ceux qu'il faut absolument mettre en œuvre ? Les caractéristiques du monde mobile (capacité réseau très limitée, par exemple) ont-elles des conséquences particulières pour IPv6 ? Ce RFC fait le point sur « IPv6 sur réseaux mobiles ». Il succède au RFC 3316, qui avait été le premier, en 2003, à se lancer dans ce travail.

Ces technologies de réseaux mobiles permettent à un appareil comme le smartphone d'avoir, lui aussi, une connexion permanente à l'Internet, comme l'ADSL le permet aux machines fixes. Cela a commencé avec le GPRS, puis l'UMTS et quelques autres techniques. Résultat, des centaines de millions d'engins mobiles sont connectés et chacun a besoin d'une adresse IP. IPv4 n'y suffit plus depuis longtemps, et, aujourd'hui, avoir un accès Internet sur son mobile impose quasiment toujours d'être coincé avec une adresse privée (RFC 1918). D'où l'intérêt d'IPv6, qui permettra à chaque machine d'avoir son adresse publique. UMTS a apparemment été le premier réseau mobile où IPv6 était mentionné dans la spécification. Pour les réseaux EPS/LTE, voir le RFC 6459.

Normalement, « avoir IPv6 », pour une machine terminale, est facile à définir. Cela veut dire respecter les règles du RFC 8504, qui rassemble en un document la liste des exigences. D'ailleurs, notre RFC 7066 ne prétend pas remplacer ce RFC 8504 : il le complète, pour préciser les points spécifiques aux réseaux mobiles (« cellulaires », comme si on était en prison). Il vise surtout les programmeurs qui vont mettre ou maintenir IPv6 dans Android, iOS, etc. À noter que le RFC distingue trois types de machines terminales connectées aux réseaux mobiles :

  • Celles complètement fermées, où l'utilisateur ne peut rien changer (un téléphone classique),
  • Celles où l'utilisateur peut ajouter des applications (le smartphone typique),
  • Celles où l'accès 3G est extérieur à la machine, par exemple un ordinateur portable muni d'une clé 3G, où les applications (et même une bonne partie du système) ne savent pas qu'elles utilisent la 3G.

Ce RFC se focalise sur l'IPv6, pas sur les techniques de transition d'IPv4 vers IPv6 ou de coexistence temporaire entre les deux protocoles. Il rappelle que la meilleure technique est la « double-pile » du RFC 4213 : que chaque machine ait deux adresses, une v4 et une v6, le temps de la transition.

Le RFC commence par les exigences de base (Basic IP), celles qui s'appliquent dans tous les cas (section 2). La machine doit évidemment mettre en œuvre la norme IPv6 de base (RFC 2460), ainsi que les mécanismes de découverte du voisin du RFC 4861.

Toutefois, il faut nuancer. Dans les réseaux GPRS, UMTS et EPS, la liaison est point-à-point : une machine n'a qu'un seul voisin, déjà connu car il s'annonce comme routeur (ce routeur est appelé par des sigles pittoresques qui dépendent de la technologie utilisée, comme GGSN ou PGW). Et donc, logiquement, il n'y a pas d'adresse de niveau 2, donc pas besoin d'un protocole pour résoudre les adresses IP en adresses de niveau 2, comme le fait NDP. Même si le routeur répondait aux messages Neighbor Solicitation, sa réponse ne contiendrait pas d'adresses de niveau 2. Le mécanisme NUD (Neighor Unreachability Detection) du RFC 4861, section 7.3, reste nécessaire (des détails dans l'annexe A). Ces messages permettent de s'assurer que le voisin répond bien. Mais il ne faut pas en abuser : les engins connectés à un réseau mobile ont en général une batterie à capacité limitée. Notre RFC recommande donc, pour s'assurer que le voisin est toujours vivant, de compter avant tout sur des indications indirectes, comme le retour des paquets TCP, ou comme les réponses DNS lorsqu'on a utilisé UDP pour les questions. Avec les protocoles de téléphonie comme RTP (RFC 3550) ou SIP (RFC 3261), il faut se servir des mécanismes de rétroaction de ces protocoles, pour confirmer la joignabilité. On ne doit faire du NUD qu'en dernier recours.

Le mobile ainsi connecté doit configurer sa propre adresse IPv6 avec SLAAC (StateLess Address AutoConfiguration, RFC 4862), ce qui veut dire qu'il doit accepter les RA (Router Advertisment) envoyés d'en face. Aucun besoin de faire de la détection d'adresses dupliquées (RFC 4862, section 5.4) puisqu'on est seul sur le lien (avec le routeur). En revanche, DHCP (RFC 8415) n'est pas obligatoire, mais on peut l'utiliser, par exemple pour récupérer les adresses des serveurs SIP (RFC 8415 et RFC 3319) ou pour obtenir la délégation d'un préfixe à utiliser sur le réseau local (RFC 8415, au cas où le mobile serve lui-même de routeur pour un tel réseau, par exemple en WiFi).

Le mécanisme d'adressage est très différent de celui des réseaux fixes. Le préfixe de l'adresse est fourni par le routeur et est unique par connexion 3G. Le suffixe est également choisi par le routeur, en général au hasard, il n'y a pas d'adresse MAC en dur dans l'engin mobile. L'annexe A rappele les particularités de l'adressessage IPv6 en 3G.

Le mobile doit également savoir trouver les adresses des résolveurs DNS avec SLAAC, comme normalisé dans le RFC 8106. Certes, ces adresses sont normalement transmises au mobile en 3G, sans passer par un protocole IP, mais il peut y avoir sur le trajet des intermédiaires qui ont du mal à passer cette option.

À ce sujet, on a parfois du PPP (RFC 1661) entre le mobile et un autre équipement, notamment dans le cas d'ordinateurs avec clé 3G. Dans ce cas, il faut utiliser le protocole de contrôle PPP pour IPv6, IPv6CP, normalisé dans le RFC 5072.

Des problèmes de vie privée ? Forcément, oui. Un mobile étant mobile, pouvoir le suivre à la trace serait très intéressant pour certains, et néfaste pour la vie privée de son propriétaire. Il est donc recommandé de mettre en œuvre les adresses temporaires du RFC 8981 mais lisez plus loin, la question de l'adressage IPv6 sur les réseaux 3G est plus compliquée qu'elle n'en a l'air. Comme le rappelle la section 7, la partie spécifique à la machine (Interface Identifier) de l'adresse IPv6 est donnée par le réseau, elle n'est pas une propriété constante de la machine (comme l'est une adresse Ethernet) et le suivi à la trace via les adresses 3G est donc nettement moins possible. En fait, c'est plutôt le préfixe et pas le suffixe qui identifie une machine, car il reste constant pendant le déplacement.

Et une dernière chose à bien garder en tête : la MTU. Les réseaux mobiles utilisent beaucoup de tunnels et les paquets peuvent donc avoir une taille maximum plus faible que prévue. Il est donc impératif que les mobiles tiennent compte de l'option MTU dans les messages RA (section 4.6.4 du RFC 4861).

Une fois ces questions de base réglées et correctement mises en œuvre dans le mobile, le RFC a encore deux courtes sections. La section 3 concerne la sécurité. Elle rappelle qu'IPsec n'est pas obligatoire (bien que, évidemment, son usage sécuriserait tout le trafic du mobile, avant son envoi sur les ondes radio). Elle note aussi qu'un mobile peut s'attendre à recevoir des paquets fragmentés, que ceux-ci posent des problèmes de sécurité fréquents, et qu'il faut donc suivre les RFC 5722 et RFC 6980. La sécurité est également discutée en section 7.

La dernière section d'exigences, la section 4, concerne la mobilité. Dans le monde 3G, elle est gérée par les couches basses et il n'est donc pas du tout nécessaire de mettre en œuvre les techniques de mobilité IP (par exemple celles du RFC 5555).

L'annexe B résume les changements depuis le RFC 3316. Rien de révolutionnaire, essentiellement des clarifications, l'ajout de technologies récentes comme la découverte des résolveurs DNS par le RFC 6106, beaucoup de points liés à la sécurité, suite au RFC 6583, etc.

Je ne fournis dans cet article aucun exemple concret : c'est parce que les opérateurs qui font de l'IPv6 sur la 3G sont en nombre infime (aucun en France). Par exemple, regardez le dernier point fait par SFR, aucune date n'était annoncée.


Téléchargez le RFC 7066


L'article seul

RFC 7065: Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : M. Petit-Huguenin (Impedance Mismatch), S. Nandakumar, G. Salgueiro, P. Jones (Cisco Systems)
Chemin des normes
Première rédaction de cet article le 23 novembre 2013


Ce court RFC normalise un nouveau plan d'URI, turn:, qui sera utilisé pour la configuration des clients TURN, un protocole de traversée des obstacles comme les routeurs NAT.

C'est le travail sur WebRTC qui a ravivé l'intérêt pour ce nouveau modèle d'URI (envisagé depuis longtemps mais jamais normalisé). WebRTC (RFC 8825) est un mécanisme de communication directe entre navigateurs Web. Souvent, les logiciels WebRTC vont devoir passer à travers des environnements hostiles comme des routeurs NAT. Une des techniques fréquemment utilisées pour aider ce passage est TURN, normalisé dans le RFC 8656, qui permet à un client TURN, en se connectant à un serveur TURN (en général installé par un fournisseur de services, par exemple SIP), de faire relayer ses paquets par le serveur TURN. TURN est une extension de STUN et s'utilise pour les cas désespérés, lorsque la seule solution pour communiquer est de faire relayer tout le trafic.

Mais, pour cela, il faut que le client soit configuré avec les coordonnées d'un serveur TURN. Actuellement, cela se fait d'une manière spécifique à chaque client. D'où l'idée d'avoir un mécanisme simple de désignation du serveur TURN, un URI comme turn:example.net. Il n'y aura plus qu'à le copier/coller à l'endroit indiqué. Cela simplifiera la configuration et la documentation. Combiné avec le mécanisme de résolution du RFC 5928, il n'y aura désormais presque rien à faire pour configurer TURN.

La section 3 fournit la syntaxe exacte. Il y a deux plans d'URI, turn: et turns:, le second servant aux connexions sécurisées avec TLS. Ils sont notés dans le registre IANA des plans. Un numéro de port est possible comme par exemple turns:provider.example:8888. S'il est absent, le port par défaut est 3478 pour turn: et 5349 pour turns:. Rappelez-vous que le nom du serveur, lui, sera déduit du nom de domaine indiqué dans l'URI par une recherche SRV, après passage par le mécanisme de résolution du RFC 5928.

Et les mises en œuvre ? Le logiciel turnuri (distribué en http://debian.implementers.org/stable/source/turnuri.tar.gz) met en œuvre les URI turn: ainsi que le mécanisme de résolution du RFC 5928. C'est également le cas de la bibliothèque libjingle, qu'utilise Chrome pour WebRTC (Firefox a sa propre implémenation).

Ce RFC a eu une histoire très longue et compliquée, remontant à plusieurs années. Ceux qui s'intéressent aux choix effectués (par exemple d'un plan turns: plutôt que d'un paramètre ;proto=tls dans l'URI) peuvent consulter un article de l'auteur sur son blog et la discussion à l'IETF. Parmi les nombreux messages échangés à l'IETF sur ces URI, je vous suggère la soumission originale et la discussion qui a suivi.


Téléchargez le RFC 7065


L'article seul

RFC 7064: URI Scheme for Session Traversal Utilities for NAT (STUN) Protocol

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : S. Nandakumar, G. Salgueiro, P. Jones (Cisco Systems), M. Petit-Huguenin (Impedance Mismatch)
Chemin des normes
Première rédaction de cet article le 23 novembre 2013


Ce court RFC normalise un nouveau plan d'URI, stun:, qui sera utilisé pour la configuration des clients STUN, un protocole de traversée des obstacles comme les routeurs NAT.

C'est le travail sur WebRTC qui a ravivé l'intérêt pour ce nouveau modèle d'URI (envisagé depuis longtemps mais jamais normalisé). WebRTC (RFC 8825) est un mécanisme de communication directe entre navigateurs Web. Souvent, les logiciels WebRTC vont devoir passer à travers des environnements hostiles comme des routeurs NAT. Une des techniques fréquemment utilisées pour aider ce passage est STUN, normalisé dans le RFC 8489, qui permet à un client STUN, en se connectant à un serveur STUN (en général installé par un fournisseur de services, par exemple SIP), d'apprendre son adresse IP extérieure et aussi d'autres caractéristiques utiles du NAT traversé.

Mais, pour cela, il faut que le client soit configuré avec les coordonnées d'un serveur STUN. Actuellement, cela se fait d'une manière spécifique à chaque client. D'où l'idée d'avoir un mécanisme simple de désignation du serveur STUN, un URI comme stun:example.net. Il n'y aura plus qu'à le copier/coller à l'endroit indiqué. Cela simplifiera la configuration et la documentation.

La section 3 fournit la syntaxe exacte. Il y a deux plans d'URI, stun: et stuns:, le second servant aux connexions sécurisées avec TLS. Ils sont notés dans le registre IANA des plans (après une discussion sur la liste d'examen des nouveaux plans). Un numéro de port est possible comme par exemple stuns:provider.example:8888. S'il est absent, le port par défaut est 3478 pour stun: et 5349 pour stuns:. Rappelez-vous que le nom du serveur, lui, sera déduit du nom de domaine indiqué dans l'URI par une recherche SRV (section 9 du RFC 5389).

Aujourd'hui, ces URI stun: sont utilisés dans des normes W3C comme celle de WebRTC. Ils sont acceptés par :


Téléchargez le RFC 7064


L'article seul

RFC 7059: A Comparison of IPv6 over IPv4 Tunnel Mechanisms

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : S. Steffann (S.J.M. Steffann Consultancy), I. van Beijnum (Institute IMDEA Networks), R. van Rein (OpenFortress)
Pour information
Première rédaction de cet article le 27 novembre 2013


Il existe d'innombrables techniques pour faire coexister IPv4 et IPv6 sur l'Internet. Tellement qu'on s'y perd facilement. Ce nouveau RFC se concentre sur une catégorie particulière, les tunnels « IPv6 sur IPv4 » et fait la liste de tous les mécanismes de cette catégorie (des plus répandus aux plus exotiques), avec leurs forces et leurs faiblesses.

Ces tunnels sont dictés par la nécessité. La bonne méthode pour se connecter en IPv6 est clairement d'utiliser une connexion native. Mais on n'a pas toujours le choix. Aujourd'hui, depuis de nombreuses années, et sans doute encore pour un certain temps, il existe de nombreuses îles IPv6, séparées les unes des autres par des réseaux purement IPv4. Par exemple, vous avez loué une machine virtuelle chez un fournisseur qui est resté à l'ancien protocole (comme Numergy) mais vous voulez accéder à l'Internet IPv6. Ou bien vous avez déployé IPv6 sur votre campus mais votre opérateur réseau n'est toujours pas capable de fournir de l'IPv6 ce qui vous désespère. Dans ces deux cas, et dans plusieurs autres, vous serez sans doute obligé d'utiliser un tunnel. Un tunnel fonctionne en encapsulant les paquets d'un protocole dans ceux d'un autre protocole. Ainsi, pour transporter de l'IPv6 sur l'IPv4, le routeur d'entrée de tunnel met le paquet IPv6 à l'intérieur d'un paquet IPv4, celui-ci voyage ensuite par les mécanismes IPv4 habituels, sur un réseau qui ne connait qu'IPv4 et, à l'arrivée sur le routeur de sortie de tunnel, le paquet IPv6 est décapsulé (extrait du paquet IPv4) puis continue son chemin dans le réseau IPv6.

Ce principe est le même pour toutes les techniques de tunnels. Mais les nombreuses techniques existent diffèrent par bien d'autres points, ce qui sème souvent la confusion chez les administrateurs réseau. D'autant plus que ces techniques ne se valent pas : certaines posent des gros problèmes de sécurité ou de fiabilité.

Ce RFC fait le tour de ces techniques. Attention : il ne couvre que le cas « IPv6 tunnelé dans IPv4 ». Il existe plein d'autres techniques de tunnels, pour faire des VPN par exemple. De même, ce RFC 7059 ne parle pas de DS-Lite, qui n'est pas une technologie de IPv6 sur IPv4 mais, au contraire, un moyen de transporter l'IPv4 sur des réseaux purement IPv6.

La section 3 est le gros morceau du RFC, contenant la liste de tous les mécanismes de tunnels étudiés (je ne les ai pas tous repris dans cet article). La plupart des tunnels font une encapsulation directe : pas d'intermédiaire entre l'en-tête IPv4 et le paquet IPv6. L'en-tête IPv4 a un champ « Protocole » qui contient la valeur 41, identifiant IPv6 (cf. section 5.1). L'adresse IPv6 des extrémités du tunnel est parfois automatiquement créée en fonction de l'adresse IPv4 (tunnels automatiques), pour trouver facilement l'extrémité du tunnel (ce point est détaillé en section 5.4). Au contraire, dans les tunnels manuels, il a fallu configurer explicitement les paramètres du tunnel (notamment l'adresse IPv4 de sortie). Un cas intermédiaire est celui où le tunnel est manuel mais la configuration se fait via un protocole auxiliaire de gestion du tunnel, qui dispense l'utilisateur de cette tâche.

D'autres tunnels ne font pas une encapsulation directe : ils mettent l'IPv6 dans de l'UDP qui est ensuite transporté sur IPv4. Cela permet la traversée des NAT et résout le problème de l'ossification de l'Internet v4, où seuls UDP et TCP arrivent à passer, les autres protocoles de couche 4 (comme le 41) étant de facto interdits en beaucoup d'endroits.

Commençons par les tunnels manuels, les plus anciens (ils étaient déjà dans le RFC 1933 en 1996). Leur norme actuelle est le RFC 4213. On les nomme aussi tunnels statiques ou bien 6in4. Le principe est de désigner explicitement, sur chaque point d'entrée, quel est le point de sortie du tunnel. Pour des exemples de configuration de tels tunnels, voir mes articles « Connecter un serveur dédié à IPv6 avec un tunnel manuel » et, plus compliqué « Un tunnel IPv6-in-v4 sur un tunnel GRE... ». Cette configuration manuelle rend cette solution « Michu-hostile » mais elle a des avantages : le réseau est prévisible (on sait exactement où les paquets vont passer) et facile à déboguer. À noter que la configuration peut être simplifiée par l'utilisation d'un courtier (broker). Les performances vont dépendre du choix de l'autre extrémité du tunnel (dans mon exemple au Cameroun, elle était à Londres, nous n'avions rien trouvé de plus proche). Autrefois, il était courant que le tunnel s'étende sur deux continents différents, allongeant sérieusement le RTT. Ces mauvais choix (tunnel trop long) ont souvent donné une mauvaise réputation aux tunnels. À tort : à titre personnel, je trouve qu'un tunnel manuel est une solution simple, fiable et efficace pour se connecter en IPv6 si on n'a pas de fournisseur IPv6 sous la main. Le seul piège est qu'il faut bien choisir son fournisseur de tunnel.

On peut aussi utiliser GRE (RFC 2784), qui est très répandu dans les routeurs (mais pas dans les machines terminales typiques). C'est un protocole d'encapsulation très généraliste (IPv4 sur IPv4, IPv6 sur IPv4, etc).

GRE est ultra-simple, avec son RFC de moins de neuf pages. Trop dans certains cas, alors on peut lui préférer SEAL (dont le RFC n'a pas encore été publié) qui prévoit quelques services supplémentaires dont un protocole de contrôle permettant aux deux extrémités du tunnel de dialoguer. Un autre exemple de « GRE++ » est AYIYA (pas encore de RFC non plus). Notez que SEAL, contrairement à GRE, n'a pas encore connu beaucoup d'utilisations.

Comme la nécessité d'une configuration manuelle refroidit beaucoup de gens et peut sembler un frein au déploiement d'IPv6, il existe des solutions de tunnels automatiques. Par exemple, le RFC 2893 décrivait une solution (supprimée depuis) où les adresses IPv6 étaient des adresses « compatibles IPv4 » (par exemple ::192.0.2.1, alias ::c000:201, équivalent IPv6 de 192.0.2.1). Le gros inconvénient de cette solution est qu'elle ne marchait qu'entre machines ayant cette technologie, et pas avec l'Internet IPv6. Elle n'a donc plus de rôle aujourd'hui.

Au contraire, 6to4 (RFC 3056) est très répandu (on le trouve dans plusieurs routeurs CPE). Il fonctionne automatiquement, en mettant l'adresse IPv4 du tunnel dans une adresse IPv6 préfixée par 2002::/16, et suivie de l'adresse IPv4. 6to4 dépend de relais (en général gérés bénévolement) capables de servir de point d'entrée et de sortie du tunnel. Grâce à l'anycast (RFC 3068) dont 6to4 avait été un des premiers utilisateurs, plusieurs relais sont accessibles pour un préfixe donné. Ils ont tous l'adresse IPv4 publique 192.88.99.1 (2002:c058:6301:: en IPv6). La route vers 2002::/16 est annoncée vers l'Internet IPv6 par tous les relais et le plus « proche » est sélectionné, répartissant ainsi automatiquement le travail. Sans configuration manuelle, 6to4 est bien adapté au petit réseau qui veut se connecter rapidement. Malheureusement, 6to4 est très imprévisible : les relais sont variés dans leur sérieux et la qualité de leur connexion, et on ne sait pas lequel on va utiliser. Le routage est en général asymétrique (on utilise un relais différent à l'aller et au retour) ce qui rend le débogage des problèmes de connectivité difficile. Le RFC 6343 liste les problèmes de 6to4 et ne recommande pas son usage. Le RFC 7526 est allé plus loin en abandonnant officiellement 6to4.

Pour résoudre ces problèmes sérieux de 6to4, certains FAI (comme Free en France) ont déployé 6rd (RFC 5969). 6rd leur permet de déployer IPv6 pour leurs clients, en ne changeant qu'une partie du réseau, sans qu'il soit nécessaire qu'il fonctionne intégralement en IPv6. 6rd ressemble beaucoup à 6to4 mais n'utilise pas le préfixe commun 2002::/16, mais un préfixe spécifique au FAI (ce qui veut dire que, dans le journal d'un serveur, on ne repère pas les clients 6rd, contrairement aux clients 6to4). Ce préfixe doit être envoyé au client, par exemple en DHCP. À noter que, comme les clients 6rd d'un même FAI partagent en général un préfixe IPv4 commun, il n'est pas nécessaire d'encoder tous les 32 bits de l'adresse IPv4 dans l'adresse IPv6, ce qui libère quelques bits (section 4 du RFC 5969). Si, contrairement à 6to4, 6rd ne peut pas être déployé par l'utilisateur seul, il a par contre l'avantage d'être bien plus prévisible et facile à déboguer. La responsabilité de la connectivité est bien plus claire, elle est entièrement chez le FAI, sans avoir besoin d'impliquer des relais extérieurs.

Comme 6to4, 6rd est sans état et les routeurs relais peuvent donc utiliser l'anycast.

6to4 et 6rd utilisent l'encapsulation directe, où le paquet IPv6 est mis directement dans IPv4, ce dernier l'indiquant par le numéro de protocole 41. L'un des inconvénients que cela présente est que cela empêche la traversée des NAT. Un autre protocole de tunnel, Teredo (RFC 4380), résout le problème en ajoutant UDP. On a donc IPv6-dans-UDP-dans-IPv4. Cela permet aussi d'avoir plusieurs clients derrière le même routeur NAT. Teredo étant activé par défaut dans certaines versions de Windows, son usage est répandu. Teredo inclut le port UDP, avec les adresses IPv4 du tunnel, dans l'adresse IPv6, qui est préfixée par 2001:0::/32.

Du point de vue de la fiabilité et des performances, Teredo est pire que 6to4, comme l'illustre l'article « Testing Teredo ».

Une solution de tunnel bien plus exotique et rare est LISP (RFC 9300). LISP n'a pas été spécialement conçu pour mettre de l'IPv6 dans l'IPv4, il est une solution générale de séparation de l'identificateur et du localisateur. Les identificateurs sont nommés EID dans LISP et les localisateurs RLOC. Tous les deux ont la forme d'une adresse IP. On peut avoir un EID IPv6 et un RLOC IPv4, réalisant ainsi un tunnel IPv6-sur-IPv4. Donc, LISP permet de faire nos tunnels mais c'est un protocole riche et complexe et l'utiliser uniquement pour cela semble exagéré.

Parmi les autres tunnels possibles, c'est dans ce RFC que j'ai appris l'existence de 6bed4. Son originalité est de fournir un mécanisme pour débrayer automatiquement le tunnel si le correspondant est joignable en IPv6 natif, par exemple s'il est sur le même réseau local. Cela lui permet d'atteindre des performances plus proches de celles de l'IPv4. Comme Teredo, 6bed4 met dans ses adresses IPv6 les adresses IPv4 et les numéros de ports UDP des routeurs du tunnel.

Les mécanismes de tunnel utilisent souvent des mécanismes auxiliaires, qui ne sont pas des tunnels mais qui aident à leur établissement et à leur gestion. La section 4 fait le tour des principaux. On y trouve par exemple le TSP du RFC 5572, qui permet de configurer automatiquement un tunnel, évitant l'étape « lecture de la doc' et tentative de la recopier ». Ce mécanisme est par exemple utilisé par Freenet6 et des exemples figurent dans mon article sur les serveurs de tunnel.

Un inconvénient des serveurs de tunnel se présente lorsque le client change d'adresse IPv4 (cas d'une adresse dynamique dans certains abonnements). Avant, il fallait arrêter le tunnel et en créer un nouveau. Le protocole SixXS Heartbeat permet d'éviter cela : le client envoie régulièrement des paquets au serveur de tunnel, qui peut ainsi apprendre un changement d'adresses et se reconfigurer. Le serveur de SixXS fait cela, et les clients typiques aussi. À noter qu'AYIYA inclut cette fonction de « battement de cœur ».

Enfin, après TSP, un autre protocole de négociation de paramètres et de création de tunnel est TIC, également utilisé à SixXS. Il a notamment été mis en œuvre dans un petit routeur CPE très populaire en Allemagne et aux Pays-Bas, le Fritz!Box AVM.

La section 5 de notre RFC discute les aspects communs à tous (ou en tout cas à une bonne partie) de ces mécanismes de tunnel. Par exemple, les routeurs NAT (plus exactement NAPT car ils changent le port, pas seulement l'adresse IP, et doivent donc connaître le protocole de couche 4 utilisé) et les pare-feux sont une cause fréquente de problème pour les tunnels, comme ils gênent d'ailleurs bien d'autres services. Ainsi, le protocole de « transport » 41 (encapsulation directe d'IPv6 dans IPv4) est souvent bloqué, ce qui a mené à l'utilisation d'UDP (par exemple par Teredo), pour contourner ce blocage. Puisqu'il n'a pas de port, le protocole 41 ne peut pas passer à travers un routeur NAPT. Il pourrait passer à travers un routeur NAT (rappelez-vous que la plupart des équipements NAT sont en fait du NAPT) dans certaines conditions. Mais, si l'adresse IPv6 est dérivée de l'IPv4, la traduction d'adresses va certainement casser le tunnel. C'est le cas de 6to4 et 6rd (6rd fonctionne en général car il ne traverse pas le routeur NAPT : il démarre sur ce routeur, qui est le point d'entrée du tunnel).

Par contre, GRE et les tunnels manuels peuvent fonctionner à travers un NAT. Il y a parfois des surprises et il peut être préférable d'utiliser un mécanisme prévu dès le début pour traverser le NAT, comme Teredo, AYIYA, ou 6bed4.

Et puis, bien sûr, une plaie récurrente de tous les tunnels est la question de la MTU (section 5.3). En raison de l'encapsulation, tout mécanisme de tunnel diminue la MTU effective de quelques octets. Normalement, la fragmentation et la découverte de la MTU du chemin devraient gérer cela et permettre au trafic de passer à travers le tunnel. En pratique, le nombre de pare-feux mal configurés qui bloquent les paquets ICMP nécessaires à la découverte de la MTU (message ICMP « Packet Too Big ») est tel que les problèmes sont fréquents. Si l'extrémité du tunnel est sur la machine terminale, celle-ci peut encore réussir à communiquer avec TCP, la MSS de ce dernier s'ajustera. Sinon, on aura des problèmes à première vue mystérieux comme le fait qu'un ping ordinaire passe mais pas un ping avec une taille différente. Ou bien on verra les connexions TCP s'établir, le client HTTP envoyer sa requête mais la réponse, plus grande et ne tenant pas dans la MTU, n'arrivera jamais. Ces problèmes liés à la MTU sont une des plaies de l'Internet et l'utilisation des tunnels les rend encore plus fréquents.

On le voit, la liste des solutions techniques pour tunneler IPv6 dans IPv4 est longue (et encore, je n'ai pas cité dans cet article tous ceux que mentionne le RFC). Comment choisir ? La section 6 du RFC est consacrée à l'évaluation de ces solutions (l'annexe A donne la iste des critères utilisés). D'abord, l'usage qu'ils font des adresses IPv4, celles-ci étant désormais très rares. Les tunnels manuels, qui dépendent d'une adresse IPv4 fixe et unique, ainsi que 6to4, ne peuvent pas marcher à travers un CGN, lorsque plusieurs clients se partagent une adresse IPv4. Teredo ou AYIYA, au contraire, ont été explicitement conçus pour bien marcher même à travers les pires NAT.

Deuxième critère d'évaluation, la topologie réseau permise. Certains tunnels (par exemple les tunnels manuels) sont point à point, entre deux machines fixes, les routeurs d'entrée et de sortie du tunnel. Cela facilite le débogage car le cheminement du trafic est parfaitement prévisible. D'autres (comme 6to4) sont plutôt un vaste réseau où plusieurs relais peuvent être utilisés pour fournir un lien virtuel qui est NBMA plutôt que point à point. Cela offre plus de souplesse et ne fait pas des deux routeurs d'extrémité du tunnel des SPOF.

En pratique, la section 6.2 du RFC penche nettement vers la première solution, une liaison point à point, qui colle bien au modèle traditionnel suivi par les liens physiques, et qui établit clairement les responsabilités de chaque acteur. Bien que l'autre topologie soit séduisante sur le papier, elle a en pratique entraîné beaucoup de problèmes de performance et de débogage.

Et à propos de SPOF, quelle est la fiabilité de ces techniques de tunnels lors d'une utilisation quotidienne ? L'expérience montre que les tunnels manuels sont plutôt fiables (une fois configuré, il n'y a guère de raison qu'ils arrêtent de marcher) et, surtout, ils sont simples dans leurs problèmes : soit le tunnel marche, soit rien ne passe. Pinguer l'extrémité du tunnel suffit en général à les superviser. D'où le tableau de la section 6.3, qui classe les techniques de tunnel par ordre de fiabilité décroissante, et qui met les tunnels configurés manuellement en haut, et Teredo et 6to4 tout en bas... (LISP est indiqué comme le plus fiable, à cause de ses mécanismes de réparation automatiques mais, contrairement à 6to4 ou aux tunnels, il n'a pas encore beaucoup été testé en vrai.)

Les problèmes de 6to4 ont été aggravés par le fait que certaines mises en œuvre de ce protocole ne testaient même pas que la machine avait une connectivité avec au moins un relais (RFC 6343 et RFC 7526).

Et les performances ? En raison de l'encapsulation, il y a forcément quelques octets perdus par le tunnel. Dans le cas d'une encapsulation directe, la moins coûteuse, cette perte représente 1,3 % d'un paquet de la taille maximale (1 500 octets). À part cette diminution de la charge utile, la performance dépend surtout des routeurs d'entrée et de sortie du tunnel. S'ils traitent les paquets « normaux » dans leur ASIC, mais l'encapsulation et la décapsulation en logiciel, dans leur relativement lent processeur, alors, oui, le tunnel sera lent. Mais ce n'est pas obligatoire. En fait, historiquement, le principal problème de performance des tunnels avait été le fait que les tunnels étaient souvent établis avec des machines relativement lointaines et c'est cet allongement du trajet qui ralentissait le service. Autrement, les tunnels ne sont pas synonymes de lenteur.

Bon, et la sécurité (section 7) ? Les tunnels (pas seulement ceux de IPv6 sur IPv4) sont souvent mauvais sur ce point. Par exemple, si l'entrée du tunnel ne fait rien pour vérifier les adresses IPv6 source des paquets qu'elle encapsule, le tunnel permettra peut-être de contourner les mécanismes anti-usurpation d'adresses (le cas de l'usurpation d'adresses avec 6to4 est couvert dans le RFC 3964). Il est donc important que le routeur d'entrée du tunnel prenne des précautions pour n'accepter que des paquets de ses clients légitimes. Autre faille possible : le tunnel permet d'établir une connectivité qui ne devrait pas « normalement » exister (dans le cas d'IPv6 sur IPv4, c'est son but explicite) et cela peut permettre de contourner les règles de sécurité qui sont en place (RFC 6169).


Téléchargez le RFC 7059


L'article seul

RFC 7050: Discovery of the IPv6 Prefix Used for IPv6 Address Synthesis

Date de publication du RFC : Novembre 2013
Auteur(s) du RFC : T. Savolainen (Nokia), J. Korhonen (Nokia Siemens Networks), D. Wing (Cisco Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF behave
Première rédaction de cet article le 5 novembre 2013


Lorsqu'on utilise le mécanisme NAT64 du RFC 6146 pour donner accès à l'Internet historique IPv4 depuis des machines IPv6, seul le traducteur NAT64 connait le préfixe IPv6 utilisé pour la traduction. Les machines ordinaires du réseau local ne le savent pas. Ce nouveau RFC fournit un moyen standard de découvrir ce préfixe.

Un tout petit rappel sur NAT64 (RFC 6146) et son copain DNS64 (RFC 6147) : leur but est de fournir une connectivité IPv4 (par exemple pour accéder à des machines qui n'ont toujours pas IPv6) aux réseaux modernes qui seront entièrement en IPv6 (RFC 6144). Pour cela, le serveur DNS64 « ment » en répondant aux requêtes de type AAAA (demande d'une adresse IPv6) par une réponse synthétisée, lorsque le nom demandé n'a qu'un A (adresse IPv4). Cette réponse synthétique utilise un préfixe configuré à la fois dans le serveur DNS64 et dans le traducteur NAT64 qui, voyant une adresse portant ce préfixe dans le champ Destination, va traduire l'IPv6 en IPv4 (et réciproquement au retour).

La plupart du temps, les machines IPv6 situées sur le réseau local n'auront aucun besoin de savoir ce qui se passe. Pour elles, tous les services externes sont accessible en IPv6 et elles ne connaissent pas la magie sous-jacente. Bien sûr, en regardant les adresses IPv6 obtenues, elles pourront s'étonner de voir que tant d'entre elles commencent par le même préfixe, mais qu'elles le fassent ou pas ne change rien. NAT64 est prévu pour fonctionner entièrement dans le routeur d'accès, sans participation (et donc sans mise à jour du logiciel) des machines terminales.

Sauf qu'il y a des cas où il serait utile que ces machines terminales bossent un peu. Par exemple, DNS64 ne sert à rien si l'application n'utilise pas le DNS. Si on a un URL http://192.168.0.33/, qui est légal (quoique déconseillé) et devrait marcher, DNS64 ne sera jamais appelé et NAT64 échouera donc. Pourtant, cet URL pourrait fonctionner à travers NAT64 si seulement la machine terminale faisait le travail de DNS64 en synthétisant l'adresse IPv6 correspondant à 192.168.0.33. Un problème analogue avec DNS64 se pose si la machine terminale fait la validation DNSSEC elle-même (ce qui est souvent une bonne idée). Dans ce cas, les réponses « mensongères » du serveur DNS64 seront refusées. Dans ces deux cas, on souhaite que la machine terminale synthétise une adresse IPv6 elle-même et, pour cela, elle doit connaître le préfixe qui permettra au routeur NAT64 de savoir ce qu'il doit faire.

Ce préfixe « magique » (les adresses utilisant tout autre préfixe seront traitées par le routeur comme de l'IPv6 ordinaire) peut être de deux types :

  • Un préfixe bien connu, réservé à cet usage, le WKP (Well-Known Prefix) qui vaut 64:ff9b::/96. Il est décrit dans le RFC 6052.
  • Ou bien un préfixe décidé localement, un NSP (Network-Specific Prefix), 2001:db8:1:64::/96 dans les exemples suivants.

Dans les deux cas, ce préfixe doit être configuré à l'identique dans le routeur NAT64 et dans le serveur DNS64. Et, si on utilise la synthèse locale (locale à la machine terminale) des adresses IPv6, il ,doit aussi être connu des machines terminales, ce qui est le but de ce RFC. Attention, il peut y avoir non pas un, mais plusieurs préfixes utilisés simultanément.

La technique utilisée dépend entre autres d'un nom bien connu, ipv4only.arpa, qui n'aura jamais que des adresses IPv4, et d'adresses IPv4 bien connues, les WKA (Well-Known Addresses), 192.0.0.170 et 192.0.0.171.


% dig +short A ipv4only.arpa
192.0.0.170
192.0.0.171

% dig +short AAAA ipv4only.arpa

Le principe (section 3 de notre RFC) est de faire une requête DNS de type AAAA (adresse IPv6) pour ce nom ipv4only.arpa. Comme ce nom n'a que des enregistremments A (adresse IPv4), si on obtient des enregistrements AAAA, c'est qu'il y a du DNS64 sur le trajet, qui synthétise ces enregistrements. Sinon, il n'y a pas de service DNS64. (La requête doit se faire avec le bit CD - Checking Disabled - à 0, autrement le serveur DNS64 ne fait pas la synthèse.) À la place d'un serveur DNS64, il peut aussi y avoir un serveur menteur qui répond même en l'absence de données (cela est fréquent sur les portails captifs). Dans ce cas, le client doit aussi faire une requête pour un nom qui n'existe pas (il n'est pas si facile que cela d'en trouver un) et vérifier qu'il récupère bien NXDOMAIN.

Une fois reçue sa réponse, la machine doit examiner tous ces AAAA et en déduire le (ou les) préfixe(s) utilisé(s) pour la synthèse. Si le préfixe est le WKP, c'est facile. Si c'est un NSP, c'est un peu plus dur. C'est là que les WKA sont utilisées : comme la machine connait les adresses IPv4 originales, elle peut les retrouver dans les adresses IPv6. Avec les examples plus haut, la machine fait une requête AAAA pour ipv4only.arpa, obtient comme réponse 2001:db8:1:64::192.0.0.170 (qu'on peut également écrire 2001:db8:1:64::c000:aa) et en déduit que le préfixe utilisé est 2001:db8:1:64::/96. Par exemple, avec BIND, et ce fichier de configuration :

options {
        ...
        dns64 2001:db8:1:64::/96 { // Network-Specific Prefix
              clients { me; };
        };

On obtiendra :

% dig +nodnssec AAAA ipv4only.arpa
...
;; ANSWER SECTION:
ipv4only.arpa.		3485 IN	AAAA 2001:db8:1:64::c000:ab
ipv4only.arpa.		3485 IN	AAAA 2001:db8:1:64::c000:aa

Si cela ne marche pas (par exemple si on ne trouve pas les WKA comme 192.0.0.170 dans la réponse), alors la recherche du préfixe a échoué (format d'adresses inhabituel ou un truc comme ça) et on doit laisser tomber et donc ne pas faire de synthèse d'adresses IPv6 sur la machine cliente. La procédure de ce RFC ne prétend pas marcher dans tous les cas.

Au fait, pourquoi deux adresses WKA, 192.0.0.170 et 192.0.0.171 ? L'annexe B du RFC discute ce choix, dû au désir de limiter les faux positifs (par exemple si la chaîne de bits qui compose une des deux adresses apparait également dans le préfixe NAT64.)

Notons que, si le canal entre le client et le serveur DNS64 n'est pas protégé, un attaquant peut facilement informer le client avec un mauvais préfixe. On peut (sauf pour le WKP) valider l'information avec DNSSEC (je ne détaille pas ici, voir la section 3.1 du RFC).

C'est bien joli d'avoir appris le préfixe mais rappelez-vous que ce RFC propose essentiellement une heuristique : il ne donne pas de garanties. Il faut donc tester le préfixe qu'on vient d'obtenir. Après tout, des tas de choses peuvent déconner. La machine cliente peut faire les tests qu'elle veut (viser des amers publics). Mais le RFC suggère une procédure que le FAI qui a déployé NAT64 peut mettre en place. Le FAI doit configurer une machine de test (qui répond aux paquets ICMP Echo et n'a pas de limitation de trafic) et mettre deux informations dans le DNS. La machine finale fait une requête DNS de type PTR pour une adresse WKA (192.0.0.170 ou 192.0.0.171) représentée en IPv6 et traduite au format ip6.arpa. Puis elle fait une requête de type A sur le nom obtenu et cela donne l'adresse de la machine de test du FAI, si celui-ci a suivi les recommandations de notre RFC. Avec les exemples de préfixes plus haut, on utilisera l'adresse 2001:db8:1:64::192.0.0.170, la requête PTR portera sur a.a.0.0.0.0.0.c.0.0.0.0.0.0.0.0.4.6.0.0.1.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa et, si elle renvoie le nom ping.example.net, la requête A portera sur ce nom. Mettons qu'on obtienne 192.0.2.33, on synthétisera 2001:db8:1:64::192.0.2.33 et on verra bien si ça marche. (L'annexe A du RFC contient un exemple complet de fichier de zone DNS standard utilisant cette technique.)

Par contre, les clients ne doivent pas faire de tests de connectivité avec les adresses obtenues en interrogeant ipv4only.arpa. (Elles ne sont pas censées répondre.)

Notre RFC rappelle aussi que cette technique ne change rien au fait que NAT64 est fondamentalement un bricolage provisoire, que le résultat est « mieux que rien » mais que la bonne solution est évidemment le passage généralisé à IPv6.

Ah, et, pendant qu'on parle de ce que configure localement le FAI, le RFC n'interdit pas des déploiements de NAT64 où les clients utilisent un autre nom que ipv4only.arpa, par exemple si le FAI veut ne dépendre que de ses propres noms (ipv4only.example.net).

Les sections 4 et 5 donnent quelques conseils pratiques pour le déploiement de l'infrastructure nécessaire. Ainsi, le domaine ipv4only.arpa devra avoir un long TTL, au moins une heure, pour bénéficier des caches. Il doit être signé avec DNSSEC.

Comme pour toutes les techniques de transition (ici, d'IPv4 vers IPv6), l'IETF impose une description d'une stratégie de sortie. Comment fera t-on lorsque NAT64 et DNS64 ne seront plus nécessaires ? La section 6 demande que les machines terminales qui ont la possibilité de découvrir le préfixe NAT64, et de synthétiser elles-mêmes les adresses IPv6, aient un mécanisme pour couper cette possibilité, le jour où elle sera abandonnée.

Enfin, un peu de bureaucratie IANA en section 8. Le domaine « spécial » ipv4only.arpa a été enregistré selon les règles des RFC 3172, et RFC 6761, règles qui n'avaient pas vraiment été respectées, ce qui a nécessité une correction dans le RFC 8880. Le domaine a été placé dans le registre des noms spéciaux. Les adresses WKA, elles, ont été enregistrées selon les règles des RFC 5736 (qui gère 192.0.0.0/24) et RFC 6890. Elles sont donc désormais dans le registre des adresses spéciales.

Il existe au moins une mise en œuvre de NAT64 qui inclus la technique de découverte de préfixe de ce RFC.


Téléchargez le RFC 7050


L'article seul

RFC 7049: Concise Binary Object Representation (CBOR)

Date de publication du RFC : Octobre 2013
Auteur(s) du RFC : C. Bormann (Universitaet Bremen TZI), P. Hoffman (VPN Consortium)
Chemin des normes
Première rédaction de cet article le 24 octobre 2013


Il existait un zillion de formats binaires d'échange de données ? Et bien il y en a désormais un zillion plus un. CBOR (Concise Binary Object Representation) est un format qui utilise un modèle de données très proche de celui de JSON, mais est encodé en binaire, avec comme but principal d'être simple à encoder et décoder, même par des machines ayant peu de ressources matérielles. (Il a depuis été remplacé par le RFC 8949.)

Parmi les autres formats binaires courants, on connait ASN.1 (plus exactement BER ou DER, utilisés dans plusieurs protocoles IETF) ou MessagePack mais ils avaient des cahiers des charges assez différents (l'annexe E du RFC contient une comparaison). CBOR se distingue d'abord par sa référence à JSON (RFC 8259), dont le modèle de données sert de point de départ à CBOR, puis par le choix de faciliter le travail des logiciels qui devront créer ou lire du CBOR. CBOR doit pouvoir tourner sur des machines très limitées. Par contre, la taille des données encodées n'est qu'une considération secondaire (section 1.1 du RFC pour une liste prioritisée des objectifs de CBOR). Quant au lien avec JSON, l'idée est d'avoir des modèles de données suffisamment proches pour qu'écrire des convertisseurs CBOR->JSON et JSON->CBOR soit assez facile, et pour que les protocoles qui utilisent actuellement JSON puissent être adaptés à CBOR sans douleur excessive.

La spécification complète de CBOR est en section 2 de ce RFC. Chaque élément contenu dans le flot de données commence par un octet dont les trois premiers bits indiquent le type majeur. Les cinq suivants donnent des détails. Ce mécanisme permet de programmeur un décodeur CBOR avec une table de seulement 256 entrées (l'annexe B fournit cette table et l'annexe C un décodeur en pseudo-code très proche de C). Si la valeur que codent ces cinq bits suivants est inférieure à 24, elle est utilisée telle quelle. Sinon, cela veut dire que les détails sont sur plusieurs octets et qu'il faut lire les suivants (la valeur des cinq bits codant la longueur à lire). Selon le type majeur, les données qui suivent le premier octet sont une valeur (c'est le cas des entiers, par exemple) ou bien un doublet {longueur, valeur} (les chaînes de caractères, par exemple). L'annexe A de notre RFC contient de nombreux exemples de valeurs CBOR avec leur encodage.

Quels sont les types majeurs possibles ? Si les trois premiers bits sont à zéro, le type majeur est un entier non signé. Si les cinq bits suivants sont inférieurs à 24, c'est la valeur de cet entier. S'ils sont égaux à 24, c'est que l'entier se trouve dans l'octet suivant l'octet initial, s'ils sont égaux à 25, que l'entier se trouve dans les deux octets suivants, et ainsi de suite (31 est réservé pour les tailles indéterminées, décrites plus loin). L'entier 10 se représentera donc 00001010, l'entier 42 sera 00011000 00101010, etc. Presque pareil pour un type majeur de 1, sauf que l'entier sera alors signé, et négatif. La valeur sera -1 moins la valeur encodée. Ainsi, -3 sera 00100010. Vous voulez vérifier ? L'excellent terrain de jeu http://cbor.me vous le permet, essayez par exemple http://cbor.me?diag=42.

Le type majeur 2 sera une chaîne d'octets. La longueur est codée d'abord, en suivant la même règle que pour les entiers. Puis viennent les données. Le type 3 indique une chaîne de caractères et non plus d'octets. Ce sont forcément des caractères Unicode, encodés en UTF-8 (RFC 3629). Le champ longueur (codé comme un entier) indique le nombre d'octets de l'encodage UTF-8, pas le nombre de caractères (pour connaître ce dernier, il faut un décodeur UTF-8). Vous voulez des exemples ? Connectez-vous à http://www.cbor.me/?diag=%22lait%22 et vous voyez que la chaîne « lait » est représentée par 646c616974 : 64 = 01100100, type majeur 3 puis une longueur de 4. Les codes ASCII suivent (rappelez-vous qu'ASCII est un sous-ensemble d'UTF-8). Avec des caractères non-ASCII comme http://www.cbor.me/?diag=%22caf%C3%A9%22, on aurait 65636166c3a9 (même type majeur, longueur 5 octets, puis les caractères, avec c3a9 qui code le é en UTF-8).

Le type majeur 4 indique un tableau. Rappelez-vous que CBOR utilise un modèle de données qui est très proche de celui de JSON. Les structures de données possibles sont donc les tableaux et les objets (que CBOR appelle les maps). Un tableau est encodé comme une chaîne d'octets, longueur (suivant les règles des entiers) puis les éléments du tableau, à la queue leu leu. La longueur est cette fois le nombre d'éléments, pas le nombre d'octets. Les éléments d'un tableau ne sont pas forcément tous du même type.

Le type majeur 5 indique une map (ce qu'on appelle objet en JSON et dictionnaire ou hash dans d'autres langages). Chaque élément d'une map est un doublet {clé, valeur}. L'encodage est le même que pour les tableaux, la longueur étant le nombre de doublets. Chaque doublet est encodé en mettant la clé, puis la valeur. Donc, le premier scalaire est la clé de la première entrée de la map, le deuxième la valeur de la première entrée, le troisième la clé de la deuxième entrée, etc.

Les clés doivent être uniques (une question problématique en JSON où les descriptions existantes de ce format ne sont ni claires ni cohérentes sur ce point).

Je passe sur le type majeur 6, voyez plus loin le paragraphe sur les étiquettes. Le type majeur 7 sert à coder les flottants (encodés ensuite en IEEE 754) et aussi d'autres types scalaires et le break code utilisé dans le paragraphe suivant. Les autres types scalaires, nommés « valeurs simples » (simple values) sont des valeurs spéciales comme 20 pour le booléen Faux, 21 pour le Vrai, et 22 pour le néant. Elles sont stockées dans un registre IANA.

Dans la description ci-dessus, les types vectoriels (tableaux, chaînes, maps) commencent par la longueur du vecteur. Pour un encodeur CBOR, cela veut dire qu'il faut connaître cette longueur avant même d'écrire le premier élément. Cela peut être contraignant, par exemple si on encode au fil de l'eau (streaming) des données en cours de production. CBOR permet donc d'avoir des longueurs indéterminées. Pour cela, on met 31 comme « longueur » et cette valeur spéciale indique que la longueur n'est pas encore connue. Le flot des éléments devra donc avoir une fin explicite cette fois, le break code. Celui-ci est représenté par un élément de type majeur 7 et de détails 31, donc tous les bits de l'octet à 1. Par exemple, http://cbor.me/?diag=%28_%20%22lait%22%29 nous montre que la chaîne « lait » ainsi codée (le _ indique qu'on veut un codage en longueur indéterminée) sera 7f646c616974ff. 7f est le type majeur 3, chaîne de caractères, avec la longueur 31, indiquant qu'elle est indéterminée. Puis suit la chaîne elle-même (les chaînes indéterminées en CBOR sont faites par concaténation de châines de longueur déterminée), puis le break code ff.

La même technique peut être utilisée pour les chaînes d'octets et de caractères, afin de ne pas avoir à spécifier leur longueur au début. À noter que cette possibilité de listes de longueur indéterminée n'existait pas dans les premières versions de CBOR. Elle a été ajoutée pour faciliter la vie du streaming.

Revenons au type majeur 6. Il indique une étiquette (tag), qui sert à préciser la sémantique de l'élément qui suit. Un exemple typique est pour indiquer qu'une chaîne de caractères est un fait une donnée structurée, par exemple une date ou un numéro de téléphone. Un décodeur n'a pas besoin de comprendre les étiquettes, il peut parfaitement les ignorer. Les valeurs possibles pour les étiquettes sont stockées dans un registre IANA.

Quelques valeurs d'étiquette intéressantes ? La valeur 0 indique une date au format du RFC 3339 (une chaîne de caractères). La valeur 1 étiquette au contraire un entier, et indique une date comme un nombre de secondes depuis le 1er janvier 1970. Les valeurs 2 et 3 étiquettent une chaîne d'octets et indiquent qu'on recommande de l'interpréter comme un grand entier (dont la valeur n'aurait pas tenu dans les types majeurs 0 ou 1). Les décodeurs qui ne gèrent pas les étiquettes se contenteront de passer à l'application cette chaîne d'octets, les autres passeront un grand entier.

Autre cas rigolos, les nombres décimaux non entiers. Certains ne peuvent pas être représentés de manière exacte sous forme d'un flottant. On peut alors les représenter par un couple [exposant, mantisse]. Par exemple, 273,15 est le couple [-2, 27315] (l'exposant est en base 10). On peut donc l'encoder en CBOR sous forme d'un tableau de deux élements, et ajouter l'étiquette de valeur 4 pour préciser qu'on voulait un nombre unique.

D'autres étiquettes précisent le contenu d'une chaîne de caractères : l'étiquette 32 indique que la chaîne est un URI, la 34 que la chaîne est du Base64 (RFC 4648), la 35 dit qu'on va rencontrer une expression rationnelle et la 36 que cela va être un message MIME (RFC 2045). Comme l'interprétation des étiquettes est optionnelle, un décodeur CBOR qui n'a pas envie de s'embêter peut juste renvoyer à l'application cette chaîne.

Une astuce amusante pour finir les étiquettes, et la spécification du format : l'étiquette 55799 signifie juste que ce qui suit est du CBOR, sans modifier sa sémantique. Encodée, elle sera représentée par 0xd9d9f7 (type majeur 6 sur trois bits, puis détails 25 qui indiquent que le nombre est sur deux octets puis le nombre lui-même, d9f7 en hexa). Ce nombre 0xd9d9f7 peut donc servir de nombre magique. Si on le trouve au début d'un fichier, c'est probablement du CBOR (il ne peut jamais apparaître au début d'un fichier JSON, donc ce nombre est particulièrement utile quand on veut distinguer tout de suite si on a affaire à du CBOR ou à du JSON).

Maintenant que le format est défini rigoureusement, passons à son utilisation. CBOR est conçu pour des environnements où il ne sera souvent pas possible de négocier les détails du format entre les deux parties. Un décodeur CBOR générique peut décoder sans connaître le schéma utilisé en face. Mais, en pratique, lorsqu'un protocole utilise CBOR pour la communication, il est autorisé (section 3 du RFC) à mettre des restrictions, ou des informations supplémentaires, afin de faciliter la mise en œuvre de CBOR dans des environnements très contraints en ressources. Ainsi, on a parfaitement le droit de faire un décodeur CBOR qui ne gérera pas les nombres flottants, si un protocole donné n'en a pas besoin.

Un cas délicat est celui des maps (section 3.7). CBOR ne place guère de restrictions sur le type des clés et un protocole ou format qui utilise CBOR voudra souvent être plus restrictif. Par exemple, si on veut absolument être compatible avec JSON, restreindre les clés à des chaînes en UTF-8 est souhaitable. Si on tient à utiliser d'autres types pour les clés (voire des types différents pour les clés d'une même map !), il faut se demander comment on les traduira lorsqu'on enverra ces maps à une application. Par exemple, en JavaScript, la clé formée de l'entier 1 est indistinguable de celle formée de la chaîne de caractères "1". Une application en JavaScript ne pourra donc pas se servir d'une map qui aurait de telles clés, de types variés.

On a vu que certains élements CBOR pouvaient être encodés de différentes manières, par exemple un tableau peut être représenté par {longueur, valeurs} ou bien par {valeurs, break code}. Cela facilite la tâche des encodeurs mais peut compliquer celle des décodeurs, et cela peut rendre certaines opérations, comme la comparaison de deux fichiers, délicates. Existe t-il une forme canonique de CBOR ? Non, pas en standard, et ce point a suscité de chaudes discussions à l'IETF. Néanmoins, un protocole ou format donné, qui utilise CBOR, peut définir une telle forme canonique. La section 3.9 donne quelques pistes à ce sujet et suggère les règles suivantes :

  • Mettre les entiers sous la forme la plus compacte possible. L'entier 2 peut être représenté par un octet (type majeur 0 puis détails égaux à 2) ou deux (type majeur 0, détails à 24 puis deux octets contenant la valeur 2), voire davantage. La forme canonique recommandée est la première (un seul octet). Même règle pour les longueurs (qui, en CBOR, sont encodées comme les entiers.)
  • Trier les clés d'une map de la plus petite à la plus grande. (Selon leur représentation en octets, pas selon l'ordre alphabétique.)
  • Mettre les tableaux et les chaînes sous la forme {longueur, valeurs}.

Tous les encodeurs CBOR qui suivent ces règles (qui seront peut-être un jour normalisées dans un nouveau RFC définissant le « CBOR canonique ») produiront, pour un même jeu de données, le même encodage.

Autre question pratique importante, le comportement en cas d'erreurs. Que doit faire un décodeur CBOR si deux clés sont identiques dans une map, ce qui est normalement interdit en CBOR ? Ou si un champ longueur indique qu'on va avoir un tableau de 5 éléments mais qu'on n'en rencontre que 4 avant la fin du fichier ? Ou si une chaîne de caractères, derrière son type majeur 3, n'est pas de l'UTF-8 bien formé ? Les sections 3.3, 3.4 et 3.10 décrivent la question. CBOR n'est pas pédant : un décodeur a le droit d'ignorer certaines erreurs, de remplacer les valeurs par ce qui lui semble approprié. CBOR penche nettement du côté « être indulgent avec les données reçues » ; il faut dire qu'une application qui utilise CBOR peut toujours le renforcer en ajoutant l'obligation de rejeter ces données erronées. Un décodeur strict peut donc s'arrêter à la première erreur. Ainsi, un pare-feu qui analyse du CBOR à la recherche de contenu malveillant a tout intérêt à rejeter les données CBOR incorrectes (puisqu'il ne sait pas trop comment elles seront interprétées par la vraie application, la section 8 revient sur ce point). Bref, la norme CBOR ne spécifie pas de traitement d'erreur unique.

Comme CBOR a un modèle de données proche de celui de JSON, on aura souvent envie d'utiliser CBOR comme encodage efficace de JSON. Comment convertir du CBOR en JSON et vice-versa sans trop de surprises ? La section 4 du RFC se penche sur ce problème. Depuis CBOR vers JSON, les traductions suivantes sont suggérées :

  • Les entiers deviennent évidemment des nombres JSON.
  • Les chaînes d'octets sont encodées en base64 et deviennent des chaînes de caractères JSON (JSON n'a pas d'autre moyen de transporter du binaire).
  • Les chaînes de caractères deviennent des chaînes de caractères JSON (ce qui nécessite d'en échapper certains, RFC 8259, section 7).
  • Les tableaux deviennent des tableaux JSON et les maps des objets JSON (ce qui impose de convertir les clés en chaînes UTF-8, si elles ne l'étaient pas déjà).
  • Etc.

En sens inverse, de JSON vers CBOR, c'est plus simple, puisque JSON n'a pas de constructions qui seraient absentes de CBOR.

Pour les amateurs de futurisme, la section 5 discute des éventuelles évolutions de CBOR. Pour les faciliter, CBOR a réservé de la place dans certains espaces. Ainsi, le type majeur 7 permettra d'encoder encore quelques valeurs simples (cela nécessitera un RFC sur le chemin des normes, cf. RFC 5226 et la section 7.1 de notre RFC). Et on peut ajouter d'autres valeurs d'étiquettes (selon des règles qui dépendent de la valeur numérique : les valeurs les plus faibles nécessiteront une procédure plus complexe, cf. section 7.2).

CBOR est un format binaire. Cela veut dire, entre autres, qu'il n'est pas évident de montrer des valeurs CBOR dans, mettons, une documentation, contrairement à JSON. La section 6 décrit donc un format texte (volontairement non spécifié en détail) qui permettra de mettre des valeurs CBOR dans du texte. Nulle grammaire formelle pour ce format : il est prévu pour l'utilisation par un humain, pas par un analyseur syntaxique. Ce format ressemble à JSON avec quelques extensions pour les nouveautés de CBOR. Par exemple, les étiquettes sont représentées par un nombre suivi d'une valeur entre parenthèses. Ainsi, la date (une chaîne de caractères étiquetée par la valeur 0) sera notée :

0("2013-10-12T11:34:00Z")

Une map de deux éléments sera notée comme en JSON :

{"Fun": true, "Amt": -2}  

Même chose pour les tableaux. Ici, avec étiquette sur deux chaînes de caractères :

[32("http://cbor.io/"), 34("SW5zw6lyZXogaWNpIHVuIMWTdWYgZGUgUMOicXVlcw==")]

Lors de l'envoi de données encodées en CBOR, le type MIME à utiliser sera application/cbor. Comme l'idée est d'avoir des formats définis en utilisant la syntaxe CBOR et des règles sémantiques spécifiques, on verra aussi sans doute des types MIME utilisant la notation plus du RFC 6839, par exemple application/monformat+cbor.

Un petit mot sur la sécurité (section 8) : il est bien connu qu'un analyseur mal écrit est un gros risque de sécurité et d'innombrables attaques ont déjà été réalisées en envoyant à la victime un fichier délibérement incorrect, conçu pour déclencher une faille de l'analyseur. Ainsi, en CBOR, un décodeur qui lirait une longueur, puis chercherait le nombre d'éléments indiqué, sans vérifier qu'il est arrivé au bout du fichier, pourrait déclencher un débordement de tampon. Les auteurs de décodeurs CBOR sont donc priés de programmer de manière défensive, voire paranoïaque : ne faites pas confiance au contenu venu de l'extérieur.

Autre problème de sécurité, le risque d'une attaque par déni de service. Un attaquant taquin peut envoyer un fichier CBOR où la longueur d'un tableau est un très grand nombre, dans l'espoir qu'un analyseur naïf va juste faire malloc(length) sans se demander si cela ne consommera pas toute la mémoire.

Enfin, comme indiqué plus haut à propos du traitement d'erreur, comme CBOR ne spécifie pas de règles standard pour la gestion des données erronées, un attaquant peut exploiter cette propriété pour faire passer des données « dangereuses » en les encodant de telle façon que l'IDS n'y voit que du feu. Prenons par exemple cette map :

{"CodeToExecute": "OK",
 "CodeToExecute": "DANGER"}

Imaginons qu'une application lise ensuite la donnée indexée par CodeToExecute. Si, en cas de clés dupliquées, elle lit la dernière valeur, elle exécutera le code dangereux. Si un IDS lit la première valeur, il ne se sera pas inquiété. Voilà une bonne raison de rejeter du CBOR invalide (les clés dupliquées sont interdites) : il peut être interprété de plusieurs façons.

Pour les amateurs d'alternatives, l'annexe E du RFC compare CBOR à des formats analogues. Attention, la comparaison se fait à la lumière du cahier des charges de CBOR, qui n'était pas forcément le cahier des charges de ces formats. Ainsi, ASN.1 (ou plutôt ses sérialisations comme BER ou DER, PER étant nettement moins courant puisqu'il nécessite de connaître le schéma des donnéees) est utilisé par plusieurs protocoles IETF (comme LDAP) mais le décoder est une entreprise compliquée.

MessagePack est beaucoup plus proche de CBOR, dans ses objectifs et ses résultats, et a même été le point de départ du projet CBOR. Mais il souffre de l'absence d'extensibilité propre. Plusieurs propositions d'extensions sont restées bloquées à cause de cela.

BSON (connu surtout via son utilisation dans MongoDB) a le même problème. En outre, il est conçu pour le stockage d'objets JSON dans une base de données, pas pour la transmission sur le réseau (ce qui explique certains de ses choix). UBJSON est un autre encodage binaire de JSON. Contrairement à CBOR, il se tient étroitement au modèle de données de JSON. Enfin, MSDTP, spécifié dans le RFC 713, n'a jamais été réellement utilisé.

Rappelez-vous que CBOR prioritise la simplicité de l'encodeur et du décodeur plutôt que la taille des données encodées. Néanmoins, un tableau en annexe E.6 compare les tailles d'un même objet encodé avec tous ces protocoles : BSON est de loin le plus bavard (BER est le second), MessagePack et CBOR les plus compacts.

Une liste des implémentations est publiée en http://cbor.io/. Au moins quatre existent, en Python, Ruby, JavaScript et Java. J'avais moi-même écrit un décodeur CBOR très limité (pour un besoin ponctuel) en Go. Il est disponible ici et son seul rôle est d'afficher le CBOR sous forme arborescente, pour aider à déboguer un producteur de CBOR. Cela donne quelque chose du genre :

% ./read-cbor test.cbor
Array of 3 items
	String of length 5: C-DNS
	Map of 4 items
		Unsigned integer 0
 => 		Unsigned integer 0
		Unsigned integer 1
 => 		Unsigned integer 5
		Unsigned integer 4
 => 		String of length 70: Experimental dnstap client, IETF 99 hackathon, data from unbound 1.6.4
		Unsigned integer 5
 => 		String of length 5: godin
	Array of indefinite number of items
		Map of 3 items
			Unsigned integer 0
 => 			Map of 1 items
				Unsigned integer 1
 => 				Array of 2 items
					Unsigned integer 1500204267
					Unsigned integer 0
			Unsigned integer 2
 => 			Map of indefinite number of items
				Unsigned integer 0
 => 				Array of 2 items
					Byte string of length 16
					Byte string of length 16
...

Merci à Carsten Bormann pour sa relecture.


Téléchargez le RFC 7049


L'article seul

RFC 7048: Neighbor Unreachability Detection Is Too Impatient

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : E. Nordmark (Arista Networks), I. Gashinsky (Yahoo!)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 8 janvier 2014


Le service de découverte des voisins d'IPv6, normalisé dans le RFC 4861, inclut une fonction de détection de l'injoignabilité du voisin (section 7.3 du RFC 4861). En trois secondes, elle permet de détecter la panne d'un voisin et donc, s'il existe un autre voisin pouvant assurer la même fonction, de basculer vers un voisin qui marche. Seulement, s'il n'existe pas de voisin équivalent, il ne sert à rien de détecter la panne (puisqu'on n'a pas d'alternative) et ce service est, dans ce cas, bien trop impatient, menant à une charge inutile du réseau.

Tout mécanisme de détection de la panne d'un composant réseau fait face à la même nécessité de compromis : si on essaie très souvent, on détectera les pannes rapidement mais on chargera le réseau. Autre problème, on risque de croire à tort qu'il y a une panne alors qu'on avait un problème temporaire dans les couches basses (convergence spanning tree prenant plusieurs secondes, par exemple). Si on essaie rarement, on épargnera le réseau, on risquera moins de détecter de fausses pannes, mais on risque de ne pas voir les vraies pannes aussi vite.

Le RFC 4861 optimise plutôt du côté de la rapidité de la détection. Un cas typique où on peut avoir un voisin équivalent est celui de deux routeurs sur le même réseau local. Il est important de détecter la panne d'un routeur très vite, pour pouvoir passer à l'autre avant que les applications ne s'en aperçoivent. Les délais spécifiés dans la section 10 du RFC 4861 (MAX_UNICAST_SOLICIT, trois transmissions séparées par une seconde) sont donc raisonnables. Mais ce nouveau RFC se focalise sur le cas où il n'y a pas d'alternative et où une détection agressive et repétée de la joignabilité est donc inutile. Il faut donc faire un compromis différent. Le RFC 6583 décrit ce problème, ainsi que d'autres questions opérationnelles liées à la découverte des voisins.

Notez que le protocole équivalent pour IPv4, ARP (RFC 826), n'a pas ce problème car le RFC ne spécifie pas de délais particuliers, les mises en œuvre d'ARP sont donc libres d'optimiser selon leur goût, par exemple vers moins de nervosité dans la détection des pannes.

La section 3 décrit les changements faits dans le protocole. On a désormais le droit d'envoyer plus de MAX_UNICAST_SOLICIT s'il n'existe pas de voisin alternatif. Dans ce cas, on est censé utiliser un repli exponentiel entre deux transmissions. Le modèle de la section 7.3.2 du RFC 4861 est mis à jour pour ajouter un état : UNREACHABLE. On y entre lorsqu'il n'y a plus de réponses aux sollicitations. Lorsqu'un voisin est dans cet état, on continue à lui envoyer des paquets, comme dans l'état PROBE, mais les tests de joignabilité utilisent le multicast, car le voisin a peut-être changé d'adresse MAC. Et, évidemment, on ne choisit plus ce voisin comme routeur par défaut.

Au bout d'un moment (le RFC recommande un maximum de soixante secondes), le voisin est considéré comme définitivement mort et retiré de la table des voisins. Au fait, pour voir cette table, sur Linux, c'est (ici avec trois routeurs possibles) :

% ip -6 neighbour show
fe80::641 dev eth0 lladdr 00:07:b4:02:b2:01 router DELAY
fe80::250:3eff:fe97:7c00 dev eth0 lladdr 00:50:3e:97:7c:00 router STALE
fe80::20e:39ff:fe43:6400 dev eth0 lladdr 00:0e:39:43:64:00 router REACHABLE

Sur une autre machine, avec plusieurs voisins, dont un routeur :

% ip -6 neighbour show
fe80::21e:8cff:fe7f:48fa dev eth0 lladdr 00:1e:8c:7f:48:fa REACHABLE
fe80::a2f3:c1ff:fec4:5b6e dev eth0 lladdr a0:f3:c1:c4:5b:6e REACHABLE
fe80::f6ca:e5ff:fe4d:1f41 dev eth0 lladdr f4:ca:e5:4d:1f:41 router REACHABLE
fe80::f6ec:38ff:fef0:d6f9 dev eth0 lladdr f4:ec:38:f0:d6:f8 REACHABLE

Sur ce même Linux, les paramètres de la détection d'injoignabilité sont réglables avec sysctl, variables net.ipv6.neigh.default.ucast_solicit et net.ipv6.neigh.default.mcast_solicit.

Si vous aimez la programmation, la section 4 de notre RFC contient un algorithme (spécifié en langage naturel) mettant en œuvre les nouvelles possibilités, et donc moins impatient que l'algorithme actuel.


Téléchargez le RFC 7048


L'article seul

RFC 7045: Transmission and Processing of IPv6 Extension Headers

Date de publication du RFC : Décembre 2013
Auteur(s) du RFC : B. Carpenter (Univ. of Auckland), Huawei Technologies
Chemin des normes
Première rédaction de cet article le 6 décembre 2013


Encore un RFC de clarification sur IPv6. Le déploiement effectif de ce protocole a en effet suscité des questions qui n'étaient pas évidentes avant. Ce RFC s'occupe des en-têtes d'extension que peut contenir un datagramme IPv6. Les règles de traitement de ces en-têtes dans la section 4 du RFC 2460 n'étaient en effet pas d'une clarté limpide. Ce RFC précise aussi les règles d'enregistrement de nouveaux en-têtes à l'IANA, puisqu'il n'existait malheureusement pas de liste faisant autorité.

Petit rappel, d'abord (section 1 du RFC) : l'en-tête normal d'un datagramme IPv6 est de taille fixe (40 octets) contrairement à ce qui se passe en IPv4. Mais entre cet en-tête et le contenu du paquet (qui peut être du TCP, de l'ICMP, de l'UDP ou même être vide), peuvent se glisser plusieurs en-têtes d'extension. Il y a donc une chaîne d'en-têtes, reliés par le champ Next header qui identifie le type de l'en-tête d'extension ou du contenu qui suit. Par exemple, un Next header à 60 signifie que cet en-tête est suivi par un en-tête Destination options alors qu'un Next header à 6 indique que l'en-tête est suivi par du contenu TCP.

La norme IPv6, le RFC 2460, spécifiait dans sa section 4 un jeu initial d'en-têtes d'extension, ainsi que la façon de les traiter. À l'exception de l'en-tête Hop-by-Hop Options, les en-têtes d'extension devaient être ignorés par les routeurs intermédiaires, et traités uniquement dans la machine de destination finale. Ainsi, de nouveaux en-têtes pouvaient être introduits sans affecter les routeurs et sans que ceux-ci aient besoin d'être mis à jour.

Ce schéma correspondait à l'architecture originale de l'Internet : le moins de traitements possible dans les nœuds intermédiaires, et toute l'intelligence aux extrémités. Mais ce modèle est désormais menacé par l'invasion de middleboxes plus ou moins invasives. Par exemple, pare-feux et répartiteurs de charge inspectent le paquet et prennent des décisions en fonction d'autres informations que l'en-tête initial (en général, elles regardent au moins l'en-tête TCP). Résultat, on ne peut plus prétendre que le réseau est transparent pour les en-têtes d'extension. Ces middleboxes doivent suivre toute la chaîne des en-têtes et ce travail est plutôt compliqué, car il n'existait pas (jusqu'au RFC 6564) de format uniforme pour les en-têtes. Il est donc difficile de l'accomplir à la vitesse du réseau, lorsque celui-ci est du 100 Gb/s ! Ce problème n'a pas de solution simple (il découle d'un mauvais choix lors de la création d'IPv6) mais on peut au moins spécifier rigoureusement ce qu'on attend de ces middleboxes.

En effet, certaines middleboxes, notamment les pare-feux, ont un comportement anormal. Un pare-feu est, par profession, paranoïaque : il rejette tout ce qu'il ne connait pas. Un en-tête inconnu et, hop, tout le paquet est jeté. Les en-têtes nouveaux ont donc peu de chances de réussir à se frayer un chemin dans l'Internet. Mais il y a pire : bien des pare-feux programmés avec les pieds par des gens qui n'ont jamais lu le RFC 2460 ne reconnaissent même pas la totalité des en-têtes d'extension originels. Ainsi, certaines fonctions d'IPv6, pourtant normalisées dès le début, comme la fragmentation, ont du mal à fonctionner.

Même si le programmeur de la middlebox a lu le RFC 2460, il risque de s'être simplifié la vie en ignorant la possibilité que de nouveaux en-têtes soient définis. L'IETF ne leur facilitait pas la tâche en ne fournissant pas de liste faisant autorité de tous les en-têtes déclarés. En effet, les numéros d'en-tête sont issus du même espace que les protocoles de transport (voir le registre). Et il n'y avait pas de moyen simple de savoir si le numéro N dans cet espace désigne un protocole de transport ou un en-tête d'extension, si l'application ne connait pas ce qui est désigné par ce N. Résultat, les nouveaux en-têtes ont peu de chance d'être déployés (ils se heurteront à toutes les middleboxes). On voit donc peu d'applications qui tentent d'utiliser des nouveaux en-têtes... ce qui ne motive pas les développeurs de middleboxes à réparer leurs engins. Le format uniforme des en-têtes, décrit dans le RFC 6564, arrangera un peu les choses, en permettant de passer un en-tête, même inconnu.

Après ces préliminaires, les exigences (section 2 de notre RFC). D'abord, un rappel, le traitement des en-têtes d'extension n'est pas une cerise sur le gâteau, c'est un composant indispensable d'IPv6 et toute machine qui prétend traiter l'IPv6 doit traiter ces en-têtes et, si elle veut accéder au contenu du paquet, doit être capable de traiter la chaîne complète des en-têtes. Un simple routeur (qui ne regarde pas le contenu des paquets) doit transmettre les paquets qu'ils aient des en-têtes d'extension ou pas (ce routeur n'a que l'en-tête fixe à regarder). Un engin qui a des fonctions supplémentaires (comme un pare-feu) doit examiner toute la chaîne si elle ne comprend que des en-têtes normalisés et notre RFC recommande que cela soit possible même s'il existe des en-têtes inconnus dans la chaîne. Maintenant qu'une liste des en-têtes normalisés est publiée, les programmeurs n'ont plus d'excuse.

Le RFC 2460 demandait que les machines de destination jettent les paquets contenant des en-têtes inconnus. Mais cela ne s'applique qu'aux machines de destination. Les machines intermédiaires, comme les pare-feux, ne doivent pas en faire autant, sinon il ne sera jamais possible de déployer de nouveaux en-têtes (je crains que cette excellente recommandation ne soit largement ignorée, dans un Internet de plus en plus ossifié).

Une machine intermédiaire peut avoir une option configurable pour jeter les paquets contenant des en-têtes normalisés mais cela doit être une option, non activée par défaut. (Pour les en-têtes inconnus, le choix par défaut peut être de les jeter.)

Une mention spéciale pour l'en-tête de routage (section 4.4 du RFC 2460). Il existe en plusieurs variantes, identifiées par un numéro de type. Si les types 0 et 1 ont été officiellement abandonnés pour des raisons de sécurité (RFC 5095), il n'y a aucune bonne raison de jeter les paquets contenant d'autres types, comme le type 2 (RFC 6275) ou le type 3 (RFC 6554).

Une autre mention concerne l'en-tête hop by hop, le seul que tous les routeurs sur le trajet sont censés examiner (c'est pour cela qu'il est obligatoirement en premier). Comme c'est très difficile à faire à pleine vitesse, notre RFC adopte une position réaliste en notant qu'il ne faut pas s'attendre à ce que tous les routeurs le fassent effectivement, et que ceux qui le feront utiliseront sans doute un chemin plus lent à l'intérieur du routeur.

La section 3 revient sur des questions de sécurité générales. Par exemple, elle rappelle que des en-têtes utilisant les valeurs marquées comme expérimentales (253 et 254) auront encore plus de problèmes que les autres à passer (RFC 4727).

Quant à la section 4, elle spécifie les changements à l'IANA visant à faciliter la tâche des programmeurs de code IPv6. D'abord, dans le registre des numéros de protocole, ajouter une colonne pour indiquer s'il s'agit d'un en-tête d'extension IPv6 (la nouvelle colonne « IPv6 Extension Header »). Ensuite, créer un nouveau registre ne contenant que ces numéros. L'enregistrement de nouveaux en-têtes continue à suivre les règles du RFC 2780.


Téléchargez le RFC 7045


L'article seul

RFC 7043: Resource Records for EUI-48 and EUI-64 Addresses in the DNS

Date de publication du RFC : Octobre 2013
Auteur(s) du RFC : J. Abley (TekSavvy Solutions)
Pour information
Première rédaction de cet article le 24 octobre 2013


Tout le monde connait les identifiants EUI-48 et EUI-64 même si ce n'est pas sous ce nom là. Normalisés par l'IEEE, ils servent notamment d'adresses Ethernet. Désormais, on peut les mettre dans le DNS, en utilisant les nouveaux types créés par ce RFC. Attention : pour des raisons liées à la protection de la vie privée, il n'est pas prévu que ces enregistrements DNS EUI48 et EUI64 se retrouvent dans le DNS public, seulement dans des zones locales (un point qui a soulevé des controverses).

Donc, d'abord, le type EUI48 (section 3). Il a le numéro 108 dans le registre IANA. En binaire, c'est simplement un groupe de six octets. Sous la forme texte (par exemple dans un fichier de zone), c'est six groupes (séparés par des tirets) de chacun deux chiffres hexadécimaux, par exemple :

host.example.   86400   IN   EUI48 00-00-5e-00-53-2a

(Notez que l'adresse MAC utilise le préfixe IANA et les valeurs réservées pour les exemples par le RFC 7042.)

C'est quasiment pareil pour le type EUI64. Numéro 109, huit octets à la suite en binaire, huit groupes de chiffres hexa en mode texte :

host.example.   86400   IN   EUI64 00-00-5e-ef-10-00-00-2a

Mais à quoi cela sert, ces adresses Ethernet dans le DNS ? La section 5 répond à la question en décrivant le cas d'usage qui avait motivé ce RFC. Au Canada, les FAI utilisant le câble utilisent DHCP pour fournir des adresses IP aux abonnés. Souvent, cela passe par un revendeur qui ne contrôle pas tout le réseau. Le revendeur connait l'adresse EUI-48 de son client mais pas l'adresse IP allouée. La correspondance entre l'adresse IP et l'adresse MAC, a décidé le régulateur, doit être publiée dans le DNS (document « Implementation of IP Address Tracking in DOCSIS Networks (TIF18) » du CRTC Interconnection Steering Committee Network Working Group, voir leurs documents). Avant ce RFC, les méthodes utilisées étaient variables et pas forcément très jolies (des enregistrements TXT, par exemple).

Cela pose quelques problèmes de sécurité, notamment liés à la protection de la vie privée. Une adresse MAC est en effet (en théorie) unique au niveau mondial et peut donc permettre de suivre une machine. Elle change moins que l'adresse IP attribuée et fournit donc un meilleur moyen de traque, permettant de suivre un utilisateur donné. C'est pour cela que la section 8 du RFC dit clairement que les types EUI48 et EUI64 ne doivent apparaître que dans des zones privées, non accessibles au public. (Cela n'a pas suffit à certains participants à l'IETF qui réclamaient qu'on ne mette jamais ces adresses EUI48 et EUI64 dans le DNS, zones privées ou pas.)

Ces deux nouveaux types d'enregistrement DNS sont mis en œuvre dans NSD en expérimental (ticket #496, il faut compiler avec l'option --enable-draft-rrtypes) et dans Knot, apparemment depuis la version 1.3.0.


Téléchargez le RFC 7043


L'article seul

RFC 7042: IANA Considerations and IETF Protocol and Documentation Usage for IEEE 802 Parameters

Date de publication du RFC : Octobre 2013
Auteur(s) du RFC : Donald Eastlake (Huawei), Joe Abley (ICANN)
Première rédaction de cet article le 24 octobre 2013


Les identificateurs IEEE 802 comme les adresses MAC d'Ethernet ne sont pas gérés par l'IETF et ne sont pas dans un registre IANA. C'est l'IEEE qui les distribue et en garde trace. Toutefois, certains protocoles IETF dépendent de ces identificateurs et ce RFC documente cet usage. Il décrit l'OUI (Organizationally Unique Identifier) attribué à l'IANA, le 00-00-5E, et indique à quoi il peut servir et comment. Ce nouveau RFC remplace l'ancien RFC 5342, avec quelques changements importants. Il a depuis lui-même été remplacé par le RFC 9542.

Parmi les exemples d'utilisation d'identificateurs IEEE 802, on peut citer les adresses d'IPv6 qui, en auto-configuration sans état, sont dérivées de l'adresse MAC. Ou bien les types de paquets Ethernet comme 0x0800 pour IPv4 et 0x86DD pour IPv6. Mais la plus grande partie de ce RFC est consacrée à l'OUI (Organizationally Unique Identifier) de l'IANA, et comment allouer des identificateurs commençant par cet OUI. Ce RFC en écrit certains, comme ceux réservés à la documentation. Fini de choisir des adresses Ethernet au hasard lorsqu'on rédige un cours ou un manuel sur ARP ! Normalement, depuis la publication de notre RFC, on utilise désormais des adresses prévues à cet effet, suivant les recommandations des RFC 2606 et RFC 5737.

On l'a dit, c'est l'IEEE qui tient le registre de ces identificateurs. L'IEEE est l'héritier de la société Xerox qui avait créé le registre. Tout le monde peut obtenir des valeurs dans ce registre mais l'IEEE, organisation très traditionnaliste, fait payer très cher (570 $ pour la norme Ethernet, certaines sont distribuées gratuitement), et ne publie pas la liste intégrale des enregistrements. Toutefois, les autres SDO peuvent obtenir gratuitement certaines valeurs.

Parmi ces paramètres, les OUI, identificateurs uniques d'une organisation (registre à l'IEEE). Ils sont surtout connus car ils servent à préfixer les adresses Ethernet. Dell ayant entre autres l'OUI 18-03-73 (l'IEEE publie une liste partielle, on trouve une liste dans le programme arpwatch, installée en /usr/share/arpwatch/ethercodes.dat et une autre est en ligne), une machine de ce constructeur peut avoir, par exemple, l'adresse 18-03-73-66-e5-68 sur sa carte Ethernet (notre RFC utilise le tiret comme séparateur - cf. section 1.1 - alors qu'on voit souvent le deux-points dans d'autres contextes). L'IANA, on l'a vu, a l'OUI 00-00-5E. L'IEEE ne fournit pas d'OUI pour les documentations, donc l'IANA a réservé des identificateurs sous son OUI à elle, pour cet usage.

Le gros morceau du RFC, la section 2, concerne les adresses MAC de type Ethernet, l'utilisation la plus connue du registre IEEE. Aujourd'hui, elles existent en deux formats, le classique, de 48 bits, nommé EUI-48, un format plus récent sur 64 bits, l'EUI-64, et l'IEEE est actuellement en train d'étudier la possibilité de créer un format EUI-128 sur 128 bits.

Les EUI-48, archi-connus en raison de leur rôle dans l'adressage Ethernet, Wi-Fi, etc, sont mondialement uniques. Si une machine a 38-59-f9-7d-b6-47, elle sera la seule au monde dans ce cas (sauf erreur dans les processus de fabrication des cartes réseaux). Les six octets de ces adresses se divisent en un OUI de trois octets (38-59-f9 dans l'exemple précédent, identifiant la société Foxconn alias Hon Hai) et trois octets attribués par le titulaire de l'OUI (l'IEEE n'enregistre donc pas les adresses individuelles mais seulement les OUI). À noter que, dans les trois octets initiaux, ceux de l'OUI, deux bits ont une signification spéciale. Le Group bit indique si l'adresse MAC est multicast (s'il est à 1) ou unicast. Le Local bit dit si l'adresse MAC est mondialement unique (s'il est à 0) ou si elle est gérée localement sans souci du reste du monde (si le bit est à 1). Dans les OUI attribués par l'IEEE, comme le 00-00-5E de l'IANA, le Local bit est à 0. Ainsi, avec un seul OUI, on peut fabriquer des identificateurs unicast ou multicast. De même, les identificateurs peuvent être globaux ou purement locaux (et, dans ce dernier cas, l'OUI n'a plus d'importance).

Il y a quelques plages d'adresses spéciales sous l'OUI IANA. Ainsi, en unicast, les plages de 00-00-5E-00-00-00 à 00-00-5E-00-00-FF et de 00-00-5E-00-52-00 à 00-00-5E-00-52-FF sont réservées pour de futures allocations par l'IANA, celles de 00-00-5E-00-01-00 à 00-00-5E-00-01-FF et de 00-00-5E-00-02-00 à 00-00-5E-00-02-FF pour le protocole VRRP, du RFC 5798, protocole qui nécessite que la machine change son adresse MAC. Et 00-00-5E-00-53-00 à 00-00-5E-00-53-FF est réservée pour la documentation. Vous pouvez trouver la liste complète dans le registre IANA. Si je regarde les adresses MAC des voisins de ma machine :

% ip -6 neighbor show                                
fe80::10:dbff:feff:4070 dev eth1 lladdr 00:10:db:ff:40:70 router REACHABLE

Je peux trouver le type de machine dans la liste locale des OUI :

% grep 0:10:db /usr/share/arpwatch/ethercodes.dat 
0:10:db	Juniper Networks, Inc.

Et si j'écris une documentation sur le protocole NDP, je vais mettre à la place des jolies adresses réservées pour la documentation :

% ip -6 neighbor show                                
fe80::5eff:feff:4070 dev eth1 lladdr 00:00:5e:ff:40:70 router REACHABLE

Les allocations IANA doivent correspondre à un travail de normalisation d'un protocole (décrit dans un RFC ou bien un Internet-Draft), et ne doivent pas être utilisées comme moyen d'échapper aux règles « normales » de l'IEEE. Dans la plage de 00-00-5E-00-52-00 à 00-00-5E-00-52-FF, la procédure est simplement celle d'un examen par un expert (section 4.1 du RFC 5226), et le RFC recommande un examen léger (l'espace d'adressage est large et il n'est pas nécessaire d'économiser). Dans celle de 00-00-5E-00-00-00 à 00-00-5E-00-00-FF, la procédure est un cas nouveau, non documenté dans le RFC 5226 et nommé « ratification par l'IESG ». Le concept de « ratification par l'IESG » est introduit dans ce RFC 7042 (section 5.1) pour dire « examen par un expert, puis, après son accord, passage devant l'IESG qui peut refuser ». L'annexe A de notre RFC contient les formulaires à remplir pour demander ces enregistrements.

Et pour les EUI-64 ? La section 2.2 rappelle leurs usages, comme la fabrication de la partie droite, l'« Interface Identifier », des adresses IPv6 (section 2.5.1 et annexe A du RFC 4291 et annexe A du RFC 5214), ou comme l'adressage FireWire. Attention, dans les adresses IPv6, le sens du Local bit a été inversé (0 veut dire que l'adresse est locale). En EUI-64 modifié (avec cette inversion du bit local), le préfixe IANA est 02-00-5E.

On y retrouve des plages analogues à celles des EUI-48 comme celle de 02-00-5E-10-00-00-00-00 à 02-00-5E-10-00-00-00-FF pour la documentation, avec des règles identiques.

Outre le préfixe IANA 00-00-5E, il existe deux autres préfixes utilisés dans la normalisation IETF (section 2.3), 33-33, pour du multicast IPv6 (RFC 2464), et CF pour PPP (RFC 2153). Le premier doit sa valeur à l'adresse du PARC, 3333 Coyote Hill Road, Palo Alto, Californie, où a été conçu Ethernet. Le second est officiellement fermé aux nouveaux enregistrements.

Après cette section 2 consacrée aux adresses MAC, la section 3 regroupe tous les autres paramètres IEEE utilisés par l'IETF. On y trouve notamment les types Ethernet qui, placés dans la trame Ethernet après les adresses, indique le type du protocole de niveau supérieur. Ils comportent deux octets, 0x0800 pour IPv4, 0x0806 pour ARP, 0x86DD pour IPv6, 0x22F3 pour TRILL, etc. Ils sont gérés par l'IEEE mais sont mentionnés ici (annexe B pour une liste partielle) pour compléter l'information. Un mécanisme d'extension est prévu pour utiliser des types plus longs que deux octets et c'est ainsi que 00-00-5E-00-42 est un numéro de protocole valable, réservé pour la documentation.

Les OUI sont aussi utilisés comme préfixes pour d'autres choses, par exemple les sélecteurs d'un algorithme de chiffrement dans IEEE 802.11. La section 4 décrit l'allocation de paramètres sous le préfixe IANA pour ces usages. Là encore, cela ne doit être fait que dans le cadre d'un processus de normalisation, avec spécification publiée.

Les changements depuis le RFC 5342 ne sont peut-être pas spectaculaires mais sont importants. Il y a l'ajout des adresses MAC de documentation. Mais il y a surtout la suppression de la règle (section 2.1.2 du RFC 5342) « allocation pour l'unicast et le multicast en même temps » qui devait simplifier le travail de l'IANA mais qui s'est avérée trop difficile à suivre. Désormais, on peut donc réserver séparement pour l'unicast et le multicast.

Autres changements, l'intégration des réflexions actuellement en cours sur la restructuration des registres IEEE, en raison des risques d'épuisement des identificateurs IEEE, et ajout des types d'enregistrement DNS EUI48 et EUI64 pour les adresses MAC (décrits en détail dans le RFC 7043).


Téléchargez le RFC 7042


L'article seul

RFC 7039: Source Address Validation Improvement Framework

Date de publication du RFC : Octobre 2013
Auteur(s) du RFC : Jianping Wu, Jun Bi (Tsinghua University), Marcelo Bagnulo (UC3M), Fred Baker (Cisco), Christian Vogt (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF savi
Première rédaction de cet article le 1 novembre 2013


Une des choses agaçantes sur l'Internet est qu'il est trivial de tricher sur son adresse IP source. Une machine qui a comme adresse 2001:db8:1:2::42 peut parfaitement émettre un paquet où l'adresse IP source est 2001:db8:9fe:43::1 et, là plupart du temps, ce paquet arrivera à destination (le routage ne se fait que sur la destination, pas sur la source), trompant le récepteur sur la vraie source de l'envoi. Cette faiblesse a donc des tas de conséquences pour la sécurité. Il existe des bonnes pratiques documentées pour empêcher l'émission de tels paquets (RFC 2827 et RFC 3704) mais elles sont peu déployées en pratique. Le projet SAVI (Source Address Validation Improvement) vise à propose des mécanismes pour rendre plus difficile l'utilisation d'adresses IP usurpées. Ce document est son cadre général, exposant les principes.

Les attaques possibles sont documentées dans le RFC 6959, qui explique la portée du projet SAVI. Les deux RFC cités plus haut, collectivement connus sous le nom de « BCP 38 » (RFC 2827 et RFC 3704), assurent, lorsqu'ils sont déployés, une validation de la source avec pour granularité celle d'un préfixe IP. Ainsi, un FAI dont les adresses IP sont en 2001:db8:1::/32 peut empêcher un de ses clients de sortir avec l'adresse 2001:db8:9fe:43::1 (qui n'est pas dans le même préfixe) mais BCP 38 ne traite pas le cas où le client 2001:db8:1:2::42 veut usurper 2001:db8:1:2:73:66:e5:68 (même préfixe). Il existe des mécanismes privés pour traiter ce cas (comme le Source Guard de Cisco) mais pas encore de norme. C'est le but de SAVI.

Son principe (section 2) est que tout est fait dans le réseau, pas dans les machines (puisque celles-ci peuvent être sous le contrôle d'un méchant). Il y a trois étapes dans une validation SAVI :

  • Déterminer les adresses IP légitimes pour une machine,
  • Attacher ces adresses IP à une propriété au niveau 2, propriété qui doit être difficile à usurper. Cela peut être par exemple le port physique du commutateur.
  • Tester que les paquets ayant cette adresse source obéissent bien à cette propriété.

C'est vague ? Parce que ce n'est qu'un modèle. D'autres RFC, par exemple le RFC 6620, spécifieront rigoureusement cet attachement entre une adresse IP et une propriété de la couche 2. Le RFC 6620 prévoit que le commutateur note les adresses IP source utilisées et refuse ensuite les paquets ayant cette adresse source (le principe est donc « premier arrivé, premier servi ») sauf si un test montre que l'adresse n'est plus joignable sur l'ancien port.

L'entité qui accomplit les trois étapes ci-dessus est appelée « instance SAVI ». Dans l'exemple donné, c'est le commutateur mais cela peut aussi être un routeur ou un autre équipement. C'est typiquement le commutateur qui est le mieux placé pour vérifier les adresses locales (le routeur a du mal à empêcher une machine d'usurper l'adresse d'une autre machine du même lien). Le principe de base est que SAVI est d'autant mieux mis en œuvre qu'on est proche de la source des paquets. Si on s'éloigne :

  • Il est plus difficile de déterminer les adresses légitimes,
  • On n'a plus de propriétés de niveau 2 à attacher à une adresse,
  • On protège moins puisque la machine menteuse pourra toujours parler aux machines proches.

Toutefois, SAVI prévoit le cas où on ne peut pas utiliser la solution idéale (par exemple parce que le commutateur où sont connectées les machines est pré-SAVI et ne gère pas ce RFC), et où on se contente d'une solution imparfaite. Notez qu'un certain nombre de commutateurs ont déjà des fonctions analogues à SAVI, mais de manière non-standard.

La section 3 couvre ces options de déploiement. Toute solution SAVI concrète va dépendre du mécanisme d'allocation d'adresses (le RFC 7513 couvre le cas de DHCP et le RFC 6620 celui des adresses auto-attribuées, par exemple via le RFC 4862) et des caractéristiques de la couche 2. Pour le mécanisme d'allocation d'adresse, il faut noter que plusieurs mécanismes peuvent coexister sur un même lien (section 6).

Pour l'attachement d'une adresse IP à une propriété de couche 2, on a le choix :

  • Adresse MAC (déconseillé par le RFC car trop facile à usurper),
  • Port physique du commutateur (attention, il peut y avoir plusieurs machines derrière un port),
  • Association de sécurité WPA entre une machine et sa base, pour un lien WiFi,
  • Identifiant d'une session PPP,
  • Identifiant du tunnel, si la machine est connectée via GRE, MPLS, etc.

Chacun de ces cas va nécessiter une incarnation concrète des principes de ce RFC 7039.

Comme souvent en sécurité, le déploiement de la sécurisation va créer de nouveaux problèmes et de nouveaux motifs de panne. La section 5 en expose certains. Par exemple, un commutateur qui mémorise une association adresse<->port et qui redémarre perd ces associations et va alors se mettre à refuser tous les paquets, avant de réapprendre les associations. Ou bien une machine change brusquement de port et, pendant un moment, ne peut plus communiquer. SAVI doit donc prévoir des mécanismes de rattrapage, par exemple, lorsque beaucoup de paquets sont refusés, tester si l'adresse IP est unique sur le lien et, si oui, en déduire que c'était bien la machine légitime qui émettait. (À noter que ces mécanismes sont mis en défaut si la machine légitime était éteinte à ce moment.)

Comme noté par la section 7, une machine SAVI a aussi intéret à connaître le préfixe IP légitime du lien, pour faire un test supplémentaire de validité. Elle peut le faire par configuration explicite, en écoutant les annonces RA (Router Advertisment) du routeur IPv6, en écoutant les messages DHCP de délégation de préfixe, … (RFC 7513)

N'espérez pas de miracle de SAVI. La section 10, qui résume l'analyse de sécurité, note bien que SAVI rend l'usurpation plus difficile mais ne « prouve » pas l'adresse IP source, au sens où une signature cryptographique prouve l'authenticité d'un document, par exemple. Si on veut faire mieux, il faut passer à des protocoles avec authentification cryptographique de la source (comme HIP).

Notez que SAVI a une longue histoire à l'IETF, chaude et contestée. Le projet se nommait auparavant SAVA (Source Address Validation Architecture, cf. RFC 5210) et avait des objectifs bien plus ambitieux, au point de faire peur à beaucoup, d'autant plus que les propositions venaient de Chine. L'ancien SAVA prévoyait un cadre englobant tout l'Internet, avec intégration de « BCP 38 » (RFC 2827 et RFC 3704) et communication entre opérateurs pour garantir la validation de bout en bout. À la réunion IETF de Prague en 2008, SAVA s'était fait chaudement allumer. Personne n'avait osé le dire tout haut pendant la réunion mais la salle bruissait de « on ne va pas changer l'architecture de l'Internet pour faire plaisir aux communistes ». Le seul orateur à mentionner ce problème l'avait fait diplomatiquement en disant que SAVA risquait d'amener dans Internet des préoccupations qui sont traditionnellement celles des telcos (comme la facturation à l'usage). SAVI est donc désormais la version light, plus focalisée du point de vue technique, et avec acceptation du fait que tout le monde n'a pas envie d'être fliqué (SAVI soulève quand même plein de problèmes pour la vie privée, qui ne sont pas traités dans ce RFC).


Téléchargez le RFC 7039


L'article seul

RFC 7033: WebFinger

Date de publication du RFC : Septembre 2013
Auteur(s) du RFC : Paul E. Jones, Gonzalo Salgueiro (Cisco Systems), Michael B. Jones (Microsoft), Joseph Smarr (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 28 septembre 2013
Dernière mise à jour le 2 mai 2017


Ce RFC décrit (même si elle n'est pas présentée ainsi) la deuxième version du protocole WebFinger. La première était informelle et permettait de récupérer de l'information sur une personne ou une organisation à partir de son adresse de courrier. La deuxième version, la première officiellement normalisée, généralise WebFinger : la clé d'entrée dans l'information est un URI, qui peut être une adresse de courrier (mailto:, RFC 6068) mais pas forcément.

WebFinger doit son nom à l'antique protocole Finger, normalisé dans le RFC 1288. Finger permettait de récupérer de l'information sur une personne, identifiée par login@nom-de-machine en se connectant sur le port 79 de la dite machine. On obtenait une réponse non structurée (du texte libre). Au contraire, WebFinger tourne sur le port 80, celui de HTTP, utilise REST, et envoie une réponse structurée, en JSON, qui est donc analysable par un programme. On nomme cette réponse le JRD, JSON Resource Descriptor.

Que contient ce JRD ? Ce qu'on veut. Pas grand'chose si on est soucieux de vie privée et, sinon, une adresse, un numéro de téléphone, une photo, etc. WebFinger peut être utilisé pour des entités non humaines (une imprimante, une machine à café, etc), pour obtenir de l'information sur leurs capacités. Par contre, WebFinger est prévu pour de l'information relativement statique, et pas pour se renseigner sur l'état actuel. Pour une imprimante, il peut servir à apprendre qu'elle sait faire de la couleur, ou seulement du noir & blanc, mais pas à connaître la quantité de feuilles de papier restant dans le bac.

(Pour des raisons historiques, certaines mises en œuvre de WebFinger distribuent un XRD, la même chose mais en XML. D'une manière générale, attention à ce que vous trouvez avec un moteur de recherche, lorsque vous demandez « webfinger » : ce seront souvent des informations complètement dépassées.)

Et quel genre d'URI peut-on utiliser en argument ? Ce qu'on veut mais, en pratique, l'usage le plus courant aujourd'hui est avec les URI acct: (normalisés dans le RFC 7565).

WebFinger reste délibérement ouvert : le RFC spécifie un protocole et un format mais pas une sémantique. Ainsi, le JRD peut avoir un contenu très varié selon les applications. L'idée est que chaque application de WebFinger spécialisera ce protocole et ce format, en indiquant plus précisément le type d'URI attendu et les informations contenues dans le JRD de réponse. À noter que ce point avait fait l'objet de vives controverses à l'IETF, à la fin du processus de normalisation. Tel que spécifié, WebFinger semblait à certains terriblement vague, un framework plutôt qu'un protocole. Selon les mots de Pete Resnick lors de la discussion entre l'IESG et les auteurs, « I suspect that the semantics are so underspecified that there could not possibly be interoperable implementations without lots of out-of-band information ». C'est pour cela que le RFC intègre aujourd'hui ces précisions : la sémantique sera dans d'autres spécifications (la section 8 du RFC détaille ce choix et ses conséquences).

La section 3 donne deux exemples d'utilisation, le premier dans le cas d'OpenID Connect et le second pour récupérer des métadonnées sur une page Web. Dans le premier cas, Carol veut s'authentifier auprès d'un site Web et donne son identificateur OpenID Connect, carol@example.com. Le site qui authentifie va utiliser WebFinger (avec l'URI acct:carol@example.com, avec le plan acct:) pour trouver le fournisseur OpenID de Carol. Dans le second cas, le client WebFinger va interroger le site qui héberge la page Web et demander en utilisant comme URI celui de la page Web.

À noter que les versions préliminaires de ce RFC avaient également plein d'exemples très hypothétiques, jamais utilisés en vrai, et qui ont été ensuite supprimés. On y trouvait par exemple un mécanisme possible pour l'autoconfiguration du client de courrier électronique, qui n'apportait rien par rapport au RFC 6186.

Avant de se plonger dans le protocole lui-même, la section 2 rappelle quelques points de vocabulaire. WebFinger étant, comme son nom l'indique, fondé sur le Web, il fait un grand usage des liens, tels que décrits dans le RFC 8288, pour indiquer une relation. La relation a un type et une information liée. En HTTP, le RFC 8288 utilise ainsi les attributs rel (type de la relation) et href (information liée) dans un en-tête Link:. WebFinger représente le même concept en JSON avec des objets JSON links (un tableau JSON), chacun comportant un membre rel et un membre href. Un exemple, pour une entité qui est un article publié sur le Web (le deuxième cas d'exemple cité plus haut, la recherche de métadonnées), les liens seraient :

"links" : [
    {
         "rel" : "copyright",
         "href" : "http://www.example.com/copyright"
    },
    {
         "rel" : "author",
         "href" : "http://blog.example.com/author/steve",
    }
]

Cet exemple se lit : l'entité interrogée via WebFinger a un copyright (qu'on peut trouver en http://www.example.com/copyright) et un auteur, décrit en http://blog.example.com/author/steve.

La section 4 décrit le protocole complet. C'est du REST, donc au-dessus de HTTP. Le client WebFinger doit spécifier l'URI de l'entité sur laquelle il veut des informations et il peut aussi spécifier un ou plusieurs types de relations qui l'intéressent (par défaut, il va tout recevoir). À noter que WebFinger impose l'usage de HTTPS, ce protocole étant souvent utilisé pour transporter des données sensibles (section 9.1, et c'était un des points de discussion les plus chauds à l'IETF). La requête WebFinger va utiliser un chemin qui utilise le préfixe .well-known du RFC 8615 et le suffixe webfinger (désormais enregistré dans les noms bien connus). Si l'URI de l'entité qui nous intéresse contient un nom de machine, c'est cette machine que contacte le client WebFinger (sinon, il doit se débrouiller, d'une manière non précisée). La méthode HTTP utilisée est toujours GET (section 9.3 du RFC 2616). Prenons un exemple, celui de l'article http://blog.example.com/article/id/314 sur lequel on voudrait plus d'informations. Le client WebFinger va se connecter à blog.example.com en HTTPS et envoyer la requête HTTP :

GET /.well-known/webfinger?resource=http%3A%2F%2Fblog.example.com%2Farticle%2Fid%2F314 HTTP/1.1
Host: blog.example.com

Le composant de requête (section 3.4 du RFC 3986) resource est l'URI (ici pour-cent encodé) de l'entité qui nous intéresse.

Si le serveur WebFinger connait l'entité en question, et accepte de répondre, il répond par le JRD (les données en JSON, étiquetées application/jrd+json, et décrites plus loin, en section 4.4 du RFC). Dans tous les autres cas, il répond par les codes HTTP traditionnels (400 « tu as oublié un truc, peut-être la resource », 403 « pas question que je te réponde à toi », 404 « je ne connais pas cette entité », 500 « j'ai un problème », 429 « trop de travail, je craque », etc).

Et si le client a inclus un ou plusieurs rel dans sa requête, indiquant qu'il n'est pas intéressé par tous les types de données mais seulement par certains ? Cela n'influe que sur le membre links du JRD, qui n'incluera alors que ce qui est demandé. Reprenons l'exemple de notre page Web et ne cherchons que l'auteur :

GET /.well-known/webfinger?resource=http%3A%2F%2Fblog.example.com%2Farticle%2Fid%2F314&rel=author HTTP/1.1
Host: blog.example.com
...
"links" : [
    {
         "rel" : "author",
         "href" : "http://blog.example.com/author/steve",
    }
]

Quel est l'intérêt (après tout, le client pourrait ainsi bien filtrer les types de liens après les avoir tous récupérés) ? Économiser des ressources sur le serveur (certaines informations peuvent nécessiter des requêtes compliquées dans une base de données) et diminuer le débit réseau. Notez toutefois, si vous écrivez un client, que tous les serveurs ne gèrent pas ce paramètre rel dans la requête et que le client risque donc toujours de tout récupérer, et de devoir trier ensuite.

Le format complet du JRD (JSON Resource Descriptor, annexe A du RFC 6415 et dérivé du XRD) figure en section 4.4. C'est un objet JSON (RFC 8259) comprenant les membres subject, aliases, properties et links que nous avons déjà vu. subject, le seul obligatoire, est un identificateur de l'entité sur laquelle on se renseigne (en général le même que le paramètre resource), properties sont les informations sur l'entité (un registre IANA les stocke, en échange d'une spécification écrite, cf. section 10.4.2) et links les liens. links est le plus complexe. Chaque lien est un objet JSON comportant plusieurs membres. rel est le seul obligatoire et sa valeur est, soit un type enregistré à l'IANA selon le RFC 8288, soit un URI (on peut ainsi « créer » ses propres types). Les autres membres possibles sont type (un type MIME), href (pointe vers la valeur du lien), titles (un texte humainement lisible, par exemple pour le présenter à l'utilisateur, marqué par une étiquette de langue) et properties (informations diverses). Voici un exemple complet, tiré du RFC, toujours au sujet de notre page Web intéressante :

{
       "subject" : "http://blog.example.com/article/id/314",
       "aliases" :
       [
         "http://blog.example.com/cool_new_thing",
         "http://blog.example.com/steve/article/7"
       ],
       "properties" :
       {
         "http://blgx.example.net/ns/version" : "1.3",
         "http://blgx.example.net/ns/ext" : null
       },
       "links" :
       [
         {
           "rel" : "copyright",
           "href" : "http://www.example.com/copyright"
         },
         {
           "rel" : "author",
           "href" : "http://blog.example.com/author/steve",
           "titles" :
           {
             "en" : "The Magical World of Steve",
             "fr" : "Le Monde Magique de Steve"
           },
           "properties" :
           {
             "http://example.com/role" : "editor"
           }
         }
      ]
}

La section 7 du RFC couvre un cas délicat, celui de services WebFinger hébergés. Si on souhaite sous-traiter WebFinger à un tiers, comment l'indique-t-on ? La seule solution est de faire une redirection HTTP depuis son site. Par exemple, avec Apache, on mettra dans la configuration :

Redirect /.well-known/webfinger http://wf.example.net/.well-known/webfinger

Et les requêtes WebFinger qu'on recevra seront gérées par le prestataire wf.example.net par le biais d'une redirection HTTP.

La section 8 décrit ce que veut dire « spécifier l'usage de WebFinger pour une application ». On a vu que WebFinger fournissait un protocole et un format très général. Chaque application qui compte se servir de WebFinger doit préciser un certain nombre de choses, notamment le contenu du JRD attendu. Si vous voulez vous servir de WebFinger pour un nouveau service très cool, vous allez devoir lire cette section et rédiger les détails. Première chose, le type d'URI attendu (acct: ? un autre ?) Deuxième chose, comment trouver le serveur à interroger. Si l'URI utilise le plan http:, c'est trivial. Mais pour les acct: ou les mailto: ? L'application doit donc préciser comment on trouve le serveur WebFinger (cela peut être aussi simple que d'avoir un serveur WebFinger central, codé en dur dans les programmes, pour tous les URI de l'application...)

Enfin, l'application doit spécifier le contenu attendu : quelles properties sont obligatoires dans la réponse, par exemple ? Même chose pour les liens : quels types rel peuvent/doivent être utilisés dans les liens ?

Ce n'est pas un peu indiscret, toutes ces informations distribuées à tout vent ? Si, et ce point a fait l'objet de vives discussions à l'IETF, ce qui a fini par donner naissance aux sections 6 et 9.2 de ce RFC. Le principal avantage de WebFinger (un seul endroit où aller pour récupérer toutes les informations sur une entité, et sous une forme structurée, ce qui est très pratique pour les programmes qui vont l'analyser) est aussi son principal risque (comme dit le RFC «  The easy access to user information via WebFinger was a design goal of the protocol, not a limitation »). Le RFC cite l'exemple de données qui permettraient le harcèlement d'une personne. L'article « Abusing social networks for automated user profiling » illustrait bien comment le recoupement d'informations provenant de différents réseaux sociaux permettait de découvrir plein de choses sur les utilisateurs.

Ces sections « vie privée » du RFC rappellent qu'un serveur WebFinger ne distribue que ce qu'il veut. En cas de demande d'information sur une personne, par exemple, la norme technique qu'est ce RFC ne spécifie pas qu'on doive distribuer l'adresse et le numéro de téléphone. C'est un choix des administrateurs du serveur. (Au passage, c'est exactement la même chose pour le protocole whois, RFC 3912, un protocole dont les usages sont proches de ceux de WebFinger. Le RFC spécifie un protocole, pas une politique de distribution des données.)

Ensuite, le serveur n'est pas obligé d'être ouvert à tout le monde. Il peut parfaitement utiliser l'authentification HTTP (ou d'autres mécanismes de contrôle d'accès comme l'adresse IP du client) pour restreindre la distribution d'informations à certains. Un serveur WebFinger est également, cela va de soi, autorisé à fournir des réponses différentes selon le client. Par exemple, on peut imaginer une réponse minimale pour les clients inconnus, et davantage de détails pour ceux qui s'authentifient. Le RFC ne cite pas les questions légales (hors sujet pour une norme technique) mais, par exemple, un serveur WebFinger d'une entreprise qui distribuerait des détails personnels sur ses employés, comme des photos, sans leur autorisation, serait certainement en violation de la directive européenne sur la protection des données personnelles.

La section 9.2 demande donc que, pour tout service WebFinger, il existe une interface permettant aux utilisateurs d'indiquer de manière simple s'ils veulent que des informations à leur sujet soient publiées ou pas, et lesquelles. Par exemple, pour un réseau social typique, on peut imaginer que les utilisateurs choisissent quels éléments d'information sur eux soient publics et, dans ce cas, que seuls les éléments ainsi marqués soient distribués par WebFinger. Le RFC demande aussi que, par défaut, rien ne soit publié (ce qui n'est certainement pas la pratique des gros silos de données comme Facebook).

Les liens fournis en réponse à une requête WebFinger peuvent d'ailleurs eux aussi pointer vers des ressources dont l'accès est contrôlé ou limité. Bref, ce n'est pas de la faute de WebFinger si des informations sensibles circulent, il n'est qu'un outil, à utiliser intelligemment.

Autre problème de sécurité avec WebFinger, le fait que la réponse est différente selon que la ressource existe ou pas (code HTTP 200 dans le premier cas et 404 dans le second). Ainsi, même si la réponse est vide, un client WebFinger peut, par essais répétés, se constituer une liste des ressources existantes. Cela peut permettre d'énumérer les utilisateurs d'un réseau social, ou bien les adresses de courrier valides (information certainement utile pour un spammeur). Le RFC recommande donc que des mesures techniques, comme une limitation du trafic par adresse IP du client, soient déployées.

Autre cas où l'utilisation maladroite de WebFinger peut avoir des conséquences néfastes, les requêtes automatiques. Supposons un MUA qui ferait automatiquement une requête WebFinger sur le champ From: du message lorsque celui-ci est lu. Un spammeur pourrait générer un champ From: différent par destinataire et les requêtes WebFinger entrantes lui diraient quels destinataires ont lu le message... Le RFC recommande donc de ne pas effectuer de requêtes WebFinger automatiquement.

Enfin, le RFC note que rien ne garantit que les valeurs renvoyées par WebFinger soient correctes (là encore, c'est un problème que les utilisateurs de whois connaissent déjà bien). Il y a en effet des choses fausses sur le Web.

Question mises en œuvre, ce n'est pas cela qui manque, y compris en logiciel libre. Il en existe une liste incomplète. Par exemple, GNU Social gère ce protocole.

Voici quelques exemples de requêtes WebFinger réelles, faites avec le client REST curl :

% curl -v 'https://packetizer.com/.well-known/webfinger?resource=acct:paulej@packetizer.com'
HTTP/1.1 200 OK
Server: Apache/2.2.22 (Fedora)
Access-Control-Allow-Origin: *
Content-Type: application/jrd+json; charset=UTF-8
...
{
  "subject" : "acct:paulej@packetizer.com",
  "aliases" :
  [
    "h323:paulej@packetizer.com"
  ],
  "properties" :
  {
    "http://packetizer.com/ns/name" : "Paul E. Jones",
    "http://packetizer.com/ns/name#zh-CN" : "保罗‧琼斯",
    "http://packetizer.com/ns/activated" : "2000-02-17T03:00:00Z"
  },
  "links" :
  [
    {
      "rel" : "test1",
      "href" : "http://example.com/author?q=acct%3Apaulej%40packetizer.com",
      "titles" :
      {
        "en-us" : "Test Link"
      }
    },
    {
      "rel" : "test2",
      "href" : "http://example.org/%E7%A7%81%E3%81%AE%E6%96%87%E6%9B%B8.txt"
    },
    {
      "rel" : "http://webfinger.net/rel/avatar",
      "type" : "image/jpeg",
      "href" : "http://www.packetizer.com/people/paulej/images/paulej.jpg"
    },
    {
      "rel" : "http://specs.openid.net/auth/2.0/provider",
      "href" : "https://openid.packetizer.com/paulej"
    },
    {
      "rel" : "http://packetizer.com/rel/share",
      "type" : "text/html",
      "href" : "http://hive.packetizer.com/users/paulej/"
    },
    {
      "rel" : "http://webfinger.net/rel/profile-page",
      "type" : "text/html",
      "href" : "http://www.packetizer.com/people/paulej/"
    },
    {
      "rel" : "http://packetizer.com/rel/blog",
      "type" : "text/html",
      "href" : "http://www.packetizer.com/people/paulej/blog/",
      "titles" :
      {
        "en-us" : "Paul E. Jones' Blog"
      }
    },
    {
      "rel" : "http://packetizer.com/rel/businesscard",
      "type" : "text/vcard",
      "href" : "http://www.packetizer.com/people/paulej/paulej.vcf"
    },
    {
      "rel" : "http://schemas.google.com/g/2010#updates-from",
      "type" : "application/atom+xml",
      "href" : "http://www.packetizer.com/people/paulej/blog/blog.xml"
    },
    {
      "rel" : "http://microformats.org/profile/hcard",
      "type" : "text/html",
      "href" : "http://www.packetizer.com/people/paulej/"
    },
    {
      "rel" : "http://bitcoin.org/rel/address",
      "href" : "bitcoin:17XoqvUCrf12H7Vc7c7uDxib8FDMXFx2p6"
    }
  ]
}

Autre exemple, pour l'URI acct:javier@seed.gluu.org, avec beaucoup moins d'information distribuée :

% curl -v 'https://seed.gluu.org/.well-known/webfinger?resource=acct:javier@seed.gluu.org'
...
{
    "subject": "acct:javier@seed.gluu.org",
    "links": [{
        "rel": "http://openid.net/specs/connect/1.0/issuer",
        "href": "https://seed.gluu.org"
    }]
}

En théorie, si on était sérieux, on ajouterait à curl l'option --header "Accept: application/jrd+json" pour indiquer au serveur qu'on ne comprend que ce format, le seul actuellement standard pour WebFinger (la syntaxe jrd+json, c'est-à-dire langage + format, est décrite dans le RFC 6839). Mais beaucoup de serveurs n'en tiennent pas compte (certains vous servent du XRD si vous mettez --header "Accept: application/xrd+xml").

WebFinger est également utilisé par Mastodon donc tout serveur Mastodon est également un serveur WebFinger. Essayons avec mon compte Mastodon, bortzmeyer@mastodon.gougere.fr :

% curl 'https://mastodon.gougere.fr/.well-known/webfinger?resource=bortzmeyer@mastodon.gougere.fr'
{"subject":"acct:bortzmeyer@mastodon.gougere.fr","aliases":["https://mastodon.gougere.fr/@bortzmeyer"],"links":[{"rel":"http://webfinger.net/rel/profile-page","type":"text/html","href":"https://mastodon.gougere.fr/@bortzmeyer"},{"rel":"http://schemas.google.com/g/2010#updates-from","type":"application/atom+xml","href":"https://mastodon.gougere.fr/users/bortzmeyer.atom"},{"rel":"salmon","href":"https://mastodon.gougere.fr/api/salmon/369"},{"rel":"magic-public-key","href":"data:application/magic-public-key,RSA._AmUWXDlwOkzKtqUsxUC94_B9yRZct-C8QqrxLWhGzA3zKNZwic0KWKMBuVRuQ7GXOq5lsyhA2pvXBTnh-Sk_8G5uLY6I7C0sjgAQKyiHVCmOBAGwcw67qfxIoN5-l2NrIZ0IygxnMOY_GU1q6fg8v6_1_bepnjCduWRVAdDBoo_HzSn91LYVleAg3E3oK8eXWYb28_DaCq9tJy5hHYLDK92XKTtk7t0Ii9U7znFvSrqgqD-qEc3KQHS5kOFRD1EfK9CI6872og0M_b6FVhNfcITaVjjk3S0uM0mpHiQuqPtfytdkRlEBd4uZUce3dPk0sODQaNcVrAMHf0KFm3w1w==.AQAB"},{"rel":"http://ostatus.org/schema/1.0/subscribe","template":"https://mastodon.gougere.fr/authorize_follow?acct={uri}"}]}  

Enfin, pour terminer cet article, une question que se posent certainement tous mes lecteurs qui connaissent le DNS. Pourquoi diable avoir décidé que le serveur WebFinger était le nom de domaine dans l'URI, ce qui manque de souplesse (si l'URI est acct:twitter.com, cela oblige Twitter à avoir le serveur WebFinger au même endroit que le serveur Web) plutôt que d'avoir une indirection, fournie par les très utiles enregistrements SRV ? Je suis d'accord, cela aurait été la bonne solution et cela aurait résolu bien des problèmes. Hélas, le groupe de travail WebFinger a fait un autre choix, pour les raisons suivantes :

  • Le Web n'utilise malheureusement pas les SRV (HTTP est un des rares protocoles où on n'a pas d'intermédiaire entre le nom de domaine et le nom du serveur, obligeant à mettre des adresses directement dans son nom de domaine).
  • JavaScript dans le navigateur (une des principales utilisations prévues) ne permet pas de faire des requêtes SRV.
  • Beaucoup d'hébergeurs DNS sont tellement mauvais qu'il ne permettent pas l'avitaillement d'enregistrements SRV via l'interface Web fournie au client.

Vous pouvez lire une discussion qui avait eu lieu à l'époque.

Autres lectures sur WebFinger, la synthèse de l'auteur du RFC, et un argumentaire pro-WebFinger de sa part.


Téléchargez le RFC 7033


L'article seul

RFC 7027: Elliptic Curve Cryptography (ECC) Brainpool Curves for Transport Layer Security (TLS)

Date de publication du RFC : Octobre 2013
Auteur(s) du RFC : J. Merkle (secunet Security Networks), M. Lochter (BSI)
Pour information
Première rédaction de cet article le 3 octobre 2013
Dernière mise à jour le 21 mai 2014


Rien d'extraordinaire dans ce très court RFC : juste l'enregistrement de trois nouvelles courbes elliptiques, collectivement nommées Brainpool, pour utilisation dans TLS.

Ces courbes Brainpool avaient été normalisées originellement dans le RFC 5639 (et leur description était dans « ECC Brainpool Standard Curves and Curve Generation - v. 1.0 »). Le protocole TLS permet d'utiliser des courbes elliptiques depuis le RFC 4492. Ces trois courbes Brainpool avaient déjà des OID mais TLS nécessitait en plus l'enregistrement de noms, ce qui est désormais fait.

Les trois courbes sont ainsi nommées, avec la syntaxe de TLS :

enum {
             brainpoolP256r1(26),
             brainpoolP384r1(27),
             brainpoolP512r1(28)
        } NamedCurve;

Et elles figurent désormais dans le registre IANA.

Au fait, pourquoi de nouvelles courbes elliptiques alors qu'il y en a déjà plein, dont certaines normalisées par le NIST ? C'est parce qu'il existe de sérieux soupçons que les courbes NIST aient été délibérement affaiblies sur ordre de la NSA (voir l'exposé « Crypto Won't Save You Either », p. 73).

Pour ceux qui lisent la langue de Konrad Zuse, il existe un site Web sur Brainpool en allemand.


Téléchargez le RFC 7027


L'article seul

RFC 7021: Assessing the Impact of Carrier-Grade NAT on Network Applications

Date de publication du RFC : Septembre 2013
Auteur(s) du RFC : C. Donley (CableLabs), L. Howard (Time Warner Cable), V. Kuarsingh (Rogers Communications), J. Berg (CableLabs), J. Doshi (University of Colorado)
Pour information
Première rédaction de cet article le 20 septembre 2013


Sous le nom générique (et souvent erroné) de NAT se trouve tout un zoo de techniques variées et n'ayant en commun que leur complexité et leur fragilité. Ce nouveau RFC documente les problèmes liés à une technique particulière, nommée « double NAT » ou « NAT 444 » ou encore « CGN ». Lorsqu'un malheureux paquet IP subit deux traductions, qu'est-ce qui va casser ?

L'idée du CGN (un terme marketing, qu'il vaudrait mieux remplacer par NAT 444 pour « deux NAT sur le trajet d'un paquet IPv4 ») est de faire beaucoup d'efforts et de dépenser beaucoup d'argent pour ne pas migrer vers IPv6. Au lieu de déployer IPv6, ce qui simplifierait beaucoup les choses, notamment pour les applications, on déploie de gros routeurs NAT chez le FAI (loin des utilisateurs, d'où le nom de CGN - Carrier-Grade NAT - par opposition au NAT CPE des boxes actuelles). En toute rigueur, on peut avoir du CGN sans avoir du double NAT (c'est par exemple courant dans les offres 3G). Mais ce RFC se focalise sur le cas typique de l'accès Internet à la maison ou au bureau où les paquets IPv4 subiront une double traduction, par une box chez le client puis par le routeur CGN chez le FAI. On aura donc deux NAT à la suite.

Ce RFC n'est pas une analyse théorique. Au contraire, il décrit le résultat de tests effectifs menés par un labo des FAI et deux FAI importants (CableLabs, Time Warner Cable et Rogers), qui ont testé en vrai le NAT 444 et les problèmes qu'il pose. La première campagne de tests a été faite en 2010 et avait montré que des applications comme le streaming vidéo, les jeux en ligne et le partage de fichiers en pair-à-pair avaient des ennuis. Une seconde série de tests a été faite en 2011 par CableLabs seul, en essayant du matériel de plusieurs vendeurs (A10, Juniper, Alcatel-Lucent) pour faire le CGN. D'une manière générale, les tests n'ont été faits qu'avec les applications qui avaient des chances (ou plutôt des malchances) d'avoir des problèmes : un simple accès en lecture seule à une page Web ordinaire ne présente pas de risques et n'a donc pas été testé. La liste des applications testées est longue ;

Ce RFC est essentiellement consacré à rendre compte des résultats de cette seconde campagne de tests.

La section 2 du RFC commence par décrire les architectures utilisés pour les tests. Par exemple, le premier cas (section 2.1.1) est le cas le plus simple : une seule machine terminale (« client »), un seul réseau local, un seul FAI. Le deuxième cas correspond à une maison avec plus d'équipements puisqu'il y a deux machines terminales. Tous les cas avec deux machines chez l'utilisateur permettent de tester des applications pair-à-pair entre ces deux machines. Le troisième cas a deux réseaux locaux mais un seul FAI donc, avec le CGN, possibilité que les machines des deux réseaux se présentent à l'extérieur avec la même adresse publique (voir le cas des Xbox plus loin). Et le quatrième cas a deux machines terminales, chez des FAI différents (donc avec des routeurs CGN différents et des adresses IP différentes).

Divers petits routeurs ont été utilisés comme CPE pendant les tests (Netgear, Linksys, etc). Les machines terminales étaient des ordinateurs Windows ou Mac OS, des consoles Xbox, des tablettes iPad, des lecteurs Blu-Ray connectés, etc.

Résultats ? Les activités les plus traditionnelles comme envoyer et recevoir du courrier, ou comme lire le Web, n'ont pas été affectées par le CGN. Les technologies de transition vers IPv6 comme 6to4 (RFC 3056) avaient été testées lors des essais de 2010 et les résultats étaient très mauvais. Ces tests n'ont pas été refaits en 2011. Autrement, qu'est-ce qui n'a pas marché ?

Plusieurs applications pair-à-pair par exemple de jeu en ligne ou de téléphonie SIP ont échoué dès qu'un CGN était là. Dans le cas de la Xbox, deux utilisateurs situés chez le même FAI n'arrivent pas à se connecter entre eux s'il y a du NAT444. Cela a apparemment été réglé par Microsoft dans une mise à jour de décembre 2011. Dans le cas de PJSIP, les appels passant par un fournisseur SIP marchaient mais pas ceux effectués en pair-à-pair.

μTorrent a fonctionné dans certains cas mais pas dans tous. Il utilise une variété de techniques pour passer à travers les NAT (y compris STUN).

Pourquoi ces échecs, lorsque ça marche avec du NAT « habituel » ? Il existe plusieurs raisons (analysées dans le RFC) mais, pour prendre l'exemple de la Xbox, c'est parce que le serveur des Xbox sait dire à deux consoles qui se connectent depuis la même adresse IPv4 publique : « vous êtes toutes les deux derrière un routeur NAT, communiquez directement sur vos adresses privées ». Cela fonctionne si les deux Xbox sont sur le même réseau local et peuvent en effet se parler sans intermédiaire. Mais s'il y a du CGN, et qu'elles sont sur des réseaux locaux différents, connectés par le même FAI, elles présentent au serveur de Microsoft la même adresse IPv4 publique mais elles ne peuvent pas se joindre avec leurs adresses privées.

Les tests ont été qualitatifs (ça marche ou ça ne marche pas) mais aussi quantitatifs avec mesure de la latence ou de la gigue, pour lesquelles le CGN ne semble pas avoir d'impact négatif.

Soyons optimistes, il y a eu des améliorations entre les tests de 2010 et ceux de 2011, notamment grâce à l'utilisation plus fréquente de STUN ou de relais permettant de contourner les problèmes du NAT. Le RFC ne parle pas de l'aspect économique mais je note que, lorsqu'on évalue le coût des CGN, il faut voir que c'est aux auteurs d'application de payer pour les FAI, en augmentant la complexité de leurs applications pour contourner les obstacles.

Certains problèmes restent et semblent consubstantiels du CGN, comme la difficulté qu'il y a à fournir des informations aux autorités en cas d'enquête sur un comportement anormal : l'adresse IP publique qui est vue par les serveurs distants est partagée entre un grand nombre d'utilisateurs (RFC 6269).

Les résultats bruts des tests de 2010 figurent en section 5 et ceux des tests de 2011 en section 4, sous forme de tableau indiquant ce qui marche et ce qui ne marche pas.

Que recommander après ces résultats ? La section 6 traite de la gestion de ces problèmes liés au double NAT. Elle recommande notamment l'utilisation de PCP (Port Control Protocol, RFC 6887), pour que les applications puissent ouvrir les ports nécessaires dans le routeur CGN.

Un exposé de CableLabs résumant leurs observations est disponible en « Carrier Grade NAT - Observations and Recommendations ».


Téléchargez le RFC 7021


L'article seul

RFC 7020: The Internet Numbers Registry System

Date de publication du RFC : Août 2013
Auteur(s) du RFC : R. Housley (Vigil Security), J. Curran (ARIN), G. Huston (APNIC), D. Conrad (Virtualized, LLC)
Pour information
Première rédaction de cet article le 29 août 2013


Le bon fonctionnement de l'Internet dépend de l'unicité de certains nombres, notamment les adresses IP. Comment ces nombres sont-ils alloués de manière à respecter cette unicité et d'autres propriétés souhaitables ? Ce RFC remplace l'ancien RFC 2050 qui décrivait le système d'allocation des adresses IP en 1996.

Comme son prédécesseur, ce RFC ne propose pas une nouvelle politique : il documente ce qui se fait actuellement. Cette documentation est d'autant plus difficile que la gouvernance des adresses IP est un sujet complexe, à l'intersection de la technique (les limites de taille de l'espace d'adressage, les limites de traitement des routeurs), de la politique et de l'économie. Contrairement à la gouvernance des noms de domaine, celle des adresses IP fait peu de bruit et est surtout traitée dans des cercles fermés. Malgré cela, il n'y a certainement pas de consensus quant à la gestion de ces adresses et ce RFC n'est pas exempt de parti pris. Dans cet article, j'essaie de coller à la description qu'ont choisi les auteurs du RFC mais rappelez-vous que tout le monde ne la trouve pas correcte, loin de là (j'avais un point de vue plus personnel dans mon article sur le RFC 2050).

On notera aussi que le titre du RFC fait référence au système d'allocation des nombres, pas seulement des adresses IP. Il traite en effet également des numéros d'AS, qui étaient absents du RFC 2050.

Donc, commençons par la section 2, les buts. Pourquoi faut-il une gestion des nombres ? On ne peut quand même pas être propriétaire du nombre 3676198671278441090, quand même ? Pourquoi ces organisations et ces règles ? Le premier but de cette gestion est la gestion de la pénurie : les adresses IPv4, notamment, sont en nombre fini et dramatiquement insuffisant. Le bon fonctionnement de l'Internet nécessitant qu'une adresse IP soit unique (ce blog est en 2605:4500:2:245b::42 ; si une autre machine avait cette adresse, à laquelle iraient les paquets ?), il faut un mécanisme pour s'assurer qu'une adresse ne soit allouée qu'une fois. Si l'espace d'adressage était immense, tirer un nombre au hasard dans cet espace assurerait une quasi-unicité (c'est ainsi qu'on fait pour les clés cryptographiques). Mais il ne l'est pas.

Et ce n'est pas le seul but de la gestion des adresses. Le routage dans l'Internet est hiérarchique. Il n'est pas possible qu'un routeur de la DFZ connaisse toutes les adresses du monde, sa mémoire n'y suffirait pas, sans parler du rythme de changement des tables de routage que cela imposerait. On regroupe donc les adresses en préfixes et le routage fonctionne sur ces préfixes, pas sur les adresses individuelles. Mais cela ne marche que si les adresses sont agrégeables, si elles sont suffisamment proches les unes des autres pour être regroupées en préfixes. Si 2001:db8:1:a::/64 est routé par un opérateur et 2001:db8:1:b::/64 par un autre, on ne pourra pas agréger ces annonces en un seul 2001:db8:1::/48. C'est donc le deuxième but de la politique de gestion des adresses IP, permettre l'agrégation. (Par contre, la politique de routage, à savoir ce que les routeurs acceptent en pratique ou pas, est indépendante du système d'enregistrement des nombres. Elle est décidée par chaque opérateur séparément.)

Troisième et dernier but, conserver et publier (typiquement, via whois), des informations fiables sur les titulaires des préfixes, de manière à pouvoir les contacter en cas de problème pratique (par exemple de sécurité, cf. section 7). L'un des rôles des registres est de s'assurer que ces informations soient correctes. En pratique, les données actuellement publiées sont souvent de qualité médiocre (erronées, pas à jour, etc.) D'autre part, rien n'étant parfait en ce monde, on a déjà vu des cas où deux registres avaient alloué le même nombre.

Comme le notait déjà le RFC 2050, ces buts peuvent être contradictoires entre eux. Ainsi, utiliser le mieux possible le nombre limité d'adresses IPv4 nécessiterait des micro-allocations (donner un /29 à celui qui n'a pas besoin de beaucoup d'adresses) alors que le routage demande de l'agrégation et donc d'allouer plutôt les préfixes en grands morceaux. D'autre part, ces trois buts peuvent être en contradiction avec d'autres intérêts. Par exemple, la publication des informations sur les titulaires et responsables techniques des préfixes peut être utilisée par les spammeurs pour collecter des adresses.

La section 3 du RFC décrit les organisations qui mettent en œuvre ce système de registre des nombres, et leurs relations. L'allocation hiérarchique des adresses IP et des numéros d'AS est enracinée à l'IANA qui distribue des ressources aux RIR qui les distribuent à des LIR qui les distribuent à des utilisateurs finaux (en simplifiant un peu). L'IANA est une fonction, pas une organisation (aujourd'hui, la fonction IANA est assurée par l'ICANN, suivant le MoU décrit dans le RFC 2860). Les documents IANA relatifs à ce rôle de registre des nombres sont notamment le ICANN Address Supporting Organization (ASO) MoU, le ICP-2: Criteria for Establishment of New Regional Internet Registries et le Internet Assigned Numbers Authority (IANA) Policy for Allocation of ASN Blocks to Regional Internet Registries. En pratique, les politiques d'allocation sont plutôt du ressort des RIR (décrits à l'origine dans le RFC 1366) et ces politiques doivent plutôt être cherchées sur les sites Web des RIR.

Mais d'autres organisations jouent aussi un rôle comme l'IETF qui édicte les normes techniques (mais, normalement, pas les politiques d'allocation précises, voir le RFC 6177 pour un exemple de débat) et qui réserve certains nombres (RFC 6890). La section 5 revient d'ailleurs sur les rôles respectifs de l'IETF et de l'ICANN.

La section 4 du RFC quitte ces considérations organisationnelles (ou bureaucratiques, si on veut être plus méchant) pour la technique, en notant qu'il est aussi de la responsabilité des registres de nombres de fournir un service de résolution DNS d'adresses IP en noms (via la gestion de domaines en in-addr.arpa et ip6.arpa) et d'assurer un service whois conforme à la norme technique (RFC 3912).

La section 6 décrit les changements depuis le RFC 2050, il y a dix-sept ans (lorsque l'ICANN n'existait même pas). Par exemple, le RFC 2050 décrivait un mécanisme d'appel à l'IANA lorsqu'on était mécontent d'une décision d'un autre acteur. Ce mécanisme a été supprimé (les RIR ont des procédures internes d'appel, par exemple le RIPE-NCC).


Téléchargez le RFC 7020


L'article seul

RFC 7017: IMAP Access to IETF Email List Archives

Date de publication du RFC : Août 2013
Auteur(s) du RFC : R. Sparks (Oracle)
Pour information
Première rédaction de cet article le 3 septembre 2013


Dans son travail, l'IETF utilise énormément les listes de diffusion. Afin de s'assurer que le travail de normalisation soit ouvert et transparent, ces listes sont publiquement accessibles. Mais il n'existe pas de moyen très pratique de naviguer dans les archives de ces listes, alors qu'il serait tentant de pouvoir le faire en utilisant le protocole normalisé d'accès à des boîtes aux lettres, IMAP. Ce court RFC est le cahier des charges du projet « Accès en IMAP aux archives des listes IETF ».

Les principaux accès à ces listes actuellement se font via le Web (qui fait l'objet d'un travail analogue pour améliorer ce service, cf. RFC 6778) ou en travaillant sur des copies locales des boîtes (pas forcément pratique). Bien des membres de l'IETF réclament un accès IMAP (RFC 9051), chaque liste étant représentée par une boîte IMAP. On pourra ainsi utiliser son client IMAP favori (mutt, Thunderbird, etc) pour accéder à ces archives.

Les exigences les plus importantes de ce cahier des charges (section 2) :

  • Même si l'archive est publique (le cas le plus fréquent) et accessible par tous, il faudra que le système permette de se loguer (avec la base d'identité du datatracker), afin de pouvoir marquer les messages (lu, non lu, etc). Il est souhaitable que d'autres annotations soient possibles, comme décrit dans les RFC 5257 et RFC 5464. Pour l'accès « anonyme », le système devra utiliser le mécanisme SASL du RFC 4505, ou bien un compte spécial (login anonymous / mot de passe anonymous...)
  • À part ces marques et ces annotations, il ne faut évidemment pas que les utilisateurs puissent modifier ou supprimer les messages.
  • Il faut que les fonctions de recherche d'IMAP soient mises en œuvre, avec les fonctions décrites dans le RFC 6778, de préférence en utilisant les extensions à IMAP des RFC 5256 (le tri), RFC 6237 (recherche multi-boîtes, depuis remplacé par le RFC 7377) et RFC 6203 (la recherche floue...)

Si vous êtes programmeur et que vous envisagez de se lancer dans ce travail, attention, la section 3 précise que le système devra prévoir une future extension aux adresses de courrier en Unicode.

Des problèmes de sécurité ? La section 4 en voit quelques uns. La fonction de recherche peut être très gourmande en CPU et en E/S. Un client méchant ou simplement avide pourrait mettre à genoux le serveur en multipliant les requêtes. Le système doit donc être capable de limiter la consommation de ressources par utilisateur. Un problème analogue se pose pour les annotations, dont il faut limiter la consommation d'espace disque.

Je n'ai pas trouvé trace d'un appel d'offres formel de l'IETF correspondant à ce RFC. Plus tard, peut-être ?


Téléchargez le RFC 7017


L'article seul

RFC 7012: Information Model for IP Flow Information eXport (IPFIX)

Date de publication du RFC : Unknown month 2013 September
Auteur(s) du RFC : B. Claise (Cisco), B. Trammell (ETH Zurich)
Chemin des normes
Première rédaction de cet article le 16 septembre 2013


Le protocole IPFIX d'envoi par un routeur de résumés statistiques sur le trafic qu'il voit passer (RFC 7011), dépend d'un modèle de données, que décrit notre RFC, qui remplace l'ancien RFC 5102.

Le RFC 7011 qui normalise le protocole IPFIX indique comment transporter les données de l'exporteur (typiquement un routeur) vers le récolteur (typiquement la machine d'administration du réseau) mais n'indique pas quelles données sont transportées. Notre RFC va jouer ce rôle, équivalent à celui du SMI du RFC 2578 pour SNMP.

Notre RFC est assez simple (son prédécesseur, le RFC 5102 était très long, mais c'est parce qu'il intégrait la liste des éléments d'information disponibles, elle est désormais dans un registre IANA). Un élément d'information a un nom (par exemple destinationTransportPort), une description (cet élément indique le port de destination du flot), un type (ici unsigned16, nombre entier sur 16 bits) et d'autres informations utiles comme un ElementID qui identifie de manière unique un élément d'information. Les types sont décrits en détail dans la section 3 mais sont très classiques (entiers de différentes factures, booléens, adresses MAC, chaînes de caractères en Unicode, etc). Plus originaux sont les sémantiques de la section 3.2. Si les éléments ont par défaut la sémantique quantity (ils affichent la valeur actuellement mesurée), d'autres sont différents, par exemple en indiquant un total (sémantique d'odomètre). Ainsi, les éléments ayant une sémantique de totalCounter repartent de zéro lorsqu'ils ont atteint leur valeur maximale. Ceux ayant la sémantique identifier ne sont pas des nombres (même quand leur valeur est numérique, comme les numéros d'AS) et ne doivent donc pas être additionnés.

Voici un exemple complet, tiré du registre. Certains champs sont obligatoires, comme le nom, la description, le type (ici un entier non signé de 64 bits) ou l'ElementID (qui peut être un nombre simple attribué par l'IANA, pour les éléments « officiels » comme le 85 montré ici, ou bien complété par un numéro d'organisation pour les autres). D'autres sont facultatifs comme l'unité (ici, des octets ; une erreur dans les unités a déjà entraîné la perte d'une sonde spatiale). Le nom suit parfois des conventions de nommage (section 2.3). Par exemple, les éléments dont le nom commence par post identifient une mesure faite après un traitement par une middlebox, par exemple une traduction d'adresse. Voici l'élément octetTotalCount :

octetTotalCount
   Description:
      The total number of octets in incoming packets for this Flow at
      the Observation Point since the Metering Process
      (re-)initialization for this Observation Point.  The number of
      octets include IP header(s) and IP payload.
   Abstract Data Type: unsigned64
   Data Type Semantics: totalCounter
   ElementId: 85
   Status: current
   Units: octets

Le vrai format source du registre (regardez https://www.iana.org/assignments/ipfix/ipfix.xml depuis autre chose qu'un navigateur Web) est XML (section 7.3), avec un schéma en Relax NG. La définition ci-dessus est en fait :


<record>
<name>octetTotalCount</name>
<dataType>unsigned64</dataType>
<group>flowCounter</group>
<dataTypeSemantics>totalCounter</dataTypeSemantics>
<elementId>85</elementId>
<applicability>all</applicability>
<status>current</status>
<description>
<paragraph>
The total number of octets in incoming packets
for this Flow at the Observation Point since the Metering
Process (re-)initialization for this Observation Point.  The
number of octets includes IP header(s) and IP payload.
</paragraph>
</description>
<units>octets</units>
<xref type="rfc" data="rfc5102"/>
<revision>0</revision>
<date>2013-02-18</date>
</record>

Les éléments dans le registre IANA sont décrits en XML car cela permet de produire automatiquement du code ou des fichiers de configuration à partir du registre. Mais le protocole IPFIX lui-même n'utilise pas du tout XML.

Les changements depuis le RFC 5102 sont décrits en section 1.1. Le principal est que la liste des éléments d'information, au lieu d'être listée dans le RFC, est désormais dans un registre IANA. D'autre part, le mécanisme pour modifier cette liste a été légèrement changé (section 7.4). Il est décrit en détail dans le RFC 7013. En gros, pour ajouter un nouvel élément d'information, il faut un examen par un expert (le RFC 5226 décrit toutes ces procédures).


Téléchargez le RFC 7012


L'article seul

RFC 7011: Specification of the IP Flow Information eXport (IPFIX) Protocol for the Exchange of Flow Information

Date de publication du RFC : Septembre 2013
Auteur(s) du RFC : B. Claise (Cisco Systems), B. Trammell (ETH Zurich)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF ipfix
Première rédaction de cet article le 16 septembre 2013


Le système IPFIX, successeur désigné de Netflow avait été normalisé dans le RFC 5101, que notre RFC met légèrement à jour. Des routeurs de différentes marques peuvent donc désormais envoyer des informations statistiques à des machines d'administration de différentes origines. L'idée de base, héritée de Netflow, est d'agréger les informations de trafic, pour que le routeur n'ait à envoyer qu'une synthèse, et pas la totalité du trafic. Comme Netflow, IPFIX peut servir à la gestion du réseau, à la supervision mais aussi à l'espionnage.

Un cahier des charges pour IPFIX avait été spécifié dans le RFC 3917. Le système IPFIX lui-même est normalisé depuis le RFC 5101, ce nouveau RFC prenant en charge le protocole d'autres RFC s'occupant du modèle d'informations (RFC 7012 et RFC 5610) ou bien de l'architecture des différents composants d'IPFIX. C'est ainsi qu'IPFIX a des extensions rigolotes comme la technique de compression du RFC 5473, les données complexes du RFC 6313 ou le stockage de donnéees dans des fichiers permanents du RFC 5655.

La terminologie d'IPFIX est en section 2. Il est recommandé de lire le document d'architecture, le RFC 5470. Un point d'observation (Observation Point) est l'endroit du réseau d'où on observe (le port d'un routeur, par exemple). Un domaine d'observation (Observation Domain) est l'ensemble des points d'observation dont les observations vont être agrégées en un seul message IPFIX (un routeur, par exemple). Un flot (flow) est un ensemble de paquets, passant par le même point d'observation, et ayant des caractéristiques communes. la définition est volontairement très ouverte. Un flot ne correspond donc pas forcément à une connexion TCP. Par exemple, un flot peut être défini par :

  • Les en-têtes du paquet : adresses IP de source et de destination, bien sûr, mais aussi les ports, et/ou des champs applicatifs. Donc, « tous les paquets depuis ou vers [2001:db8:1:2]:53 » est un flot, identifiant le trafic DNS de 2001:db8:1:2.
  • Les caractéristiques du traitement du paquet : prochain routeur ou interface de sortie.

Un enregistrement de flot (flow record) est composé de la définition du flot et des valeurs mesurées (nombre total de paquets appartenant à ce flot qui ont été vus, nombre total d'octets). Un gabarit (template) est une structure de données qui décrit ce qui est contenu dans les enregistrements. Un exporteur (exporter), typiquement le routeur, va émettre ces enregistrements, contenant le résultat de ses observations, vers un collecteur (collector) où on fabriquera de jolis graphes.

Notre RFC normalise ensuite le format des paquets (section 3). Comme avec d'autres protocoles, les paquets commencent par un numéro de version, 10 ici (inchangé depuis le RFC 5101), IPFIX marquant sa descendance depuis Netflow, dont la dernière version était la 9. Le RFC décrit aussi l'encodage des données exportées par l'observateur IPFIX (section 6).

Des exemples d'encodage sont fournis dans l'annexe A. Par exemple, A.2.1 utilise des éléments enregistrés à l'IANA (IPFIX permet aussi de définir les siens) :

  • Adresse IP source sourceIPv4Address,
  • Adresse IP destination destinationIPv4Address,
  • Routeur suivant ipNextHopIPv4Address,
  • Nombre de paquets packetDeltaCount,
  • Nombre d'octets octetDeltaCount.

Les trois premiers identifient le flot et les deux derniers sont les mesures par flot. Le gabarit va donc lister ces cinq élements, avec leur taille (quatre octets chacun).

Enfin, notre RFC décrit le mécanisme de transport, au dessus d'UDP, le protocole traditionnel de Netflow, mais aussi de TCP ou bien du protocole recommandé, SCTP. Pour répondre au cahier des charges, qui insistait sur la sécurité, la section 11.1 décrit aussi l'utilisation de TLS. À propos de sécurité, la section 11 se penche aussi sur la confidentialité (IPFIX permet de transporter des informations sur les métadonnées d'une communication, permettant l'analyse de trafic ; même si on n'a pas le contenu des communications, cela peut être très indiscret). Elle attire aussi l'attention du programmeur sur l'importance de s'assurer de l'intégrité des données. IPFIX pouvant être utilisé pour la facturation, un client malhonnête peut avoir une bonne motivation pour modifier ces données.

La section 1.1 décrit les changements depuis le premier RFC, le RFC 5101. Ils sont de peu d'importance et deux logiciels suivant les deux RFC pourront interagir. Il y a eu plusieurs corrections d'erreurs dans la spécification, les définitions d'élements d'information situées dans l'ancien RFC ont toute été sorties, vers le registre IANA, qui fait désormais seul autorité. Une nouvelle section, la 5.2, traite le problème du débordement de certains types temporels, débordement qui se produira en 2032 ou 2038 selon les cas (cela semble loin dans le futur mais les logiciels durent longtemps, rappelez-vous le bogue de l'an 2000).

IPFIX est déjà mis en œuvre dans plusieurs systèmes. Un exemple de mise en œuvre en logiciel libre est Maji. Mais, apparemment Cacti ne sait pas exporter de l'IPFIX, juste du vieux Netflow. Ntop sait faire mais il faut passer à nProbe l'option -V 10 (plein d'exemple dans cet article, merci à Andrew Feren pour les informations). Si vous voulez voir des traces IPFIX, il y en a deux sur pcapr. Wireshark sait analyser de l'IPFIX, il faut lui demander de décoder comme du cflow. Le RFC 5153 donne des conseils aux programmeurs qui veulent créer ou lire de l'IPFIX. Les RFC 5471 et RFC 5472 sont utiles aux administrateurs réseaux qui voudraient déployer IPFIX. Toutefois, aujourd'hui, des années après la sortie du premier RFC, il semble que peu d'opérateurs utilisent IPFIX (v10). La plupart sont restés bloqués sur Netflow (v9). Les « grands » routeurs (Juniper ou Cisco) savent faire de l'IPFIX mais pas forcément les routeurs de bas de gamme.

Deux autres logiciels importants, des collecteurs IPFIX. Il y a bien sûr pmacct mais aussi Vflow. Voici un exemple de fichier de configuration pmacct :

# Les bases de données dans lesquelles on stockera
plugins: memory,sqlite3,pgsql

# La version du schéma de données (7 est la plus récente)
sql_table_version: 7

# Le port UDP où les données IPFIX sont envoyées (cela doit coïncider
# avec la config' du routeur)
nfacctd_port: 2055

# Le ou les critères d'agrégation
aggregate: src_host

Avec une telle configuration, voici ce qui sera enregistré dans la base PostgreSQL :

pmacct=> select ip_src,bytes,packets from acct_v7 ;
    ip_src    | bytes  | packets 
--------------+--------+---------
 10.10.86.133 | 371740 |    2083
 192.0.2.2    | 368576 |    2804
(2 lignes)

Mais, au lieu de PostgreSQL, on aurait pu aussi utiliser le client en ligne de commandes (grâce au plugin memory) :

% pmacct -s
SRC_IP                                         PACKETS               BYTES
192.0.2.2                                      2363                  310176
10.10.86.133                                   1749                  312036

For a total of: 2 entries

Maintenant, si on ajoute au fichier de configuration une agrégation sur d'autres critères :

aggregate: src_host,dst_host,proto,src_port,dst_port

On aura alors bien plus de lignes dans les bases (une par tuple, et le port source du trafic SSH varie à chaque fois) :

% pmacct -s
SRC_IP                                         DST_IP                                         SRC_PORT  DST_PORT  PROTOCOL    PACKETS               BYTES
10.10.86.133                                   192.0.2.2                                      57230     22        tcp         6                     488
10.10.86.133                                   192.0.2.2                                      57250     22        tcp         6                     488
...
192.0.2.2                                      192.0.2.1                                      39802     53        udp         1                     71
192.0.2.2                                      10.10.86.133                                   22        57206     tcp         17                    2539

For a total of: 180 entries

Et idem dans la base PostgreSQL :

pmacct=> select count(*) from acct_v7 ;
 count 
-------
   198
(1 ligne)

On peut utiliser SQL pour faire des sélections, des agrégations... Exemple, tout le trafic depuis une machine, avec la fonction d'agrégation SQL sum et la fonction de sélection SQL where :

pmacct=> select sum(bytes), sum(packets) from acct_v7 where ip_src='192.0.2.2';
  sum   | sum  
--------+------
 326807 | 2492
(1 ligne)

Ou bien tout le trafic UDP :

pmacct=> select sum(bytes), sum(packets) from acct_v7 where ip_proto=17;
  sum   | sum  
--------+------
 111738 | 1574
(1 ligne)

Par défaut, les données sont agrégées, quel que soit leur âge. Si on veut faire des études historiques, il faut demander à garder les données plus anciennes :

aggregate: src_host,dst_host
sql_history: 5m
sql_history_roundoff: m

On voit alors les données « tourner » (notez le order SQL pour classer par ordre rétro-chronologique) :

pmacct=> select ip_src,ip_dst,packets,stamp_inserted,stamp_updated from acct_v7 where ip_dst!='0.0.0.0' order by stamp_updated desc;
    ip_src    |    ip_dst    | packets |   stamp_inserted    |    stamp_updated    
--------------+--------------+---------+---------------------+---------------------
 10.10.86.133 | 192.0.2.2    |    1249 | 2016-05-03 10:25:00 | 2016-05-03 10:28:02
 192.0.2.2    | 10.10.86.133 |    1487 | 2016-05-03 10:25:00 | 2016-05-03 10:28:02
 192.0.2.2    | 192.0.2.1    |     116 | 2016-05-03 10:25:00 | 2016-05-03 10:28:02
 192.0.2.2    | 192.0.2.1    |     252 | 2016-05-03 10:20:00 | 2016-05-03 10:26:02
 192.0.2.2    | 10.10.86.133 |    2906 | 2016-05-03 10:20:00 | 2016-05-03 10:26:02
 10.10.86.133 | 192.0.2.2    |    2354 | 2016-05-03 10:20:00 | 2016-05-03 10:26:02
 10.10.86.133 | 192.0.2.2    |    2364 | 2016-05-03 10:15:00 | 2016-05-03 10:21:02
 192.0.2.2    | 192.0.2.1    |     270 | 2016-05-03 10:15:00 | 2016-05-03 10:21:02
 192.0.2.2    | 10.10.86.133 |    2911 | 2016-05-03 10:15:00 | 2016-05-03 10:21:02
 192.0.2.2    | 10.10.86.133 |    1645 | 2016-05-03 10:10:00 | 2016-05-03 10:16:02
 192.0.2.2    | 192.0.2.1    |     154 | 2016-05-03 10:10:00 | 2016-05-03 10:16:02
 10.10.86.133 | 192.0.2.2    |    1310 | 2016-05-03 10:10:00 | 2016-05-03 10:16:02
(12 lignes)

(Chaque enregistrement dure un peu plus que les cinq minutes configurées car pmacct « bufferise ».)

Voici enfin un exemple de paquet vu par Wireshark. C'est du vrai IPFIX (numéro de version 10).

[Premier paquet, avec les gabarits]

Cisco NetFlow/IPFIX
    Version: 10
    Length: 876
    Timestamp: Jul  8, 2011 21:18:53.000000000 CEST
        ExportTime: 1310152733
    FlowSequence: 0
    Observation Domain Id: 0
    Set 1
        FlowSet Id: Data Template (V10 [IPFIX]) (2)
        FlowSet Length: 248
        Template (Id = 47104, Count = 25)
            Template Id: 47104
            Field Count: 25
            Field (1/25): flowStartMilliseconds
                0... .... .... .... = Pen provided: No
                .000 0000 1001 1000 = Type: flowStartMilliseconds (152)
                Length: 8
            Field (2/25): flowEndMilliseconds
                0... .... .... .... = Pen provided: No
                .000 0000 1001 1001 = Type: flowEndMilliseconds (153)
                Length: 8
            Field (3/25): BYTES_TOTAL
                0... .... .... .... = Pen provided: No
                .000 0000 0101 0101 = Type: BYTES_TOTAL (85)
                Length: 8
            Field (4/25): BYTES_TOTAL [Reverse]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0101 0101 = Type: BYTES_TOTAL (85) [Reverse]
                Length: 8
                PEN: IPFIX Reverse Information Element Private Enterprise (29305)
            Field (5/25): PACKETS_TOTAL
                0... .... .... .... = Pen provided: No
                .000 0000 0101 0110 = Type: PACKETS_TOTAL (86)
                Length: 8
            Field (6/25): PACKETS_TOTAL [Reverse]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0101 0110 = Type: PACKETS_TOTAL (86) [Reverse]
                Length: 8
                PEN: IPFIX Reverse Information Element Private Enterprise (29305)
            Field (7/25): IPV6_SRC_ADDR
                0... .... .... .... = Pen provided: No
                .000 0000 0001 1011 = Type: IPV6_SRC_ADDR (27)
                Length: 16
            Field (8/25): IPV6_DST_ADDR
                0... .... .... .... = Pen provided: No
                .000 0000 0001 1100 = Type: IPV6_DST_ADDR (28)
                Length: 16
            Field (9/25): IP_SRC_ADDR
                0... .... .... .... = Pen provided: No
                .000 0000 0000 1000 = Type: IP_SRC_ADDR (8)
                Length: 4
            Field (10/25): IP_DST_ADDR
                0... .... .... .... = Pen provided: No
                .000 0000 0000 1100 = Type: IP_DST_ADDR (12)
                Length: 4
            Field (11/25): L4_SRC_PORT
                0... .... .... .... = Pen provided: No
                .000 0000 0000 0111 = Type: L4_SRC_PORT (7)
                Length: 2
            Field (12/25): L4_DST_PORT
                0... .... .... .... = Pen provided: No
                .000 0000 0000 1011 = Type: L4_DST_PORT (11)
                Length: 2
            Field (13/25): PROTOCOL
                0... .... .... .... = Pen provided: No
                .000 0000 0000 0100 = Type: PROTOCOL (4)
                Length: 1
            Field (14/25): flowEndReason
                0... .... .... .... = Pen provided: No
                .000 0000 1000 1000 = Type: flowEndReason (136)
                Length: 1
            Field (15/25): paddingOctets
                0... .... .... .... = Pen provided: No
                .000 0000 1101 0010 = Type: paddingOctets (210)
                Length: 6
            Field (16/25):  21 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0001 0101 = Type: 21 [pen: CERT Coordination Center]
                Length: 4
                PEN: CERT Coordination Center (6871)
            Field (17/25): TCP_SEQ_NUM
                0... .... .... .... = Pen provided: No
                .000 0000 1011 1000 = Type: TCP_SEQ_NUM (184)
                Length: 4
            Field (18/25): TCP_SEQ_NUM [Reverse]
                1... .... .... .... = Pen provided: Yes
                .000 0000 1011 1000 = Type: TCP_SEQ_NUM (184) [Reverse]
                Length: 4
                PEN: IPFIX Reverse Information Element Private Enterprise (29305)
            Field (19/25):  14 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0000 1110 = Type: 14 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (20/25):  15 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0000 1111 = Type: 15 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (21/25): 16398 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .100 0000 0000 1110 = Type: 16398 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (22/25): 16399 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .100 0000 0000 1111 = Type: 16399 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (23/25): SRC_VLAN
                0... .... .... .... = Pen provided: No
                .000 0000 0011 1010 = Type: SRC_VLAN (58)
                Length: 2
            Field (24/25): SRC_VLAN [Reverse]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0011 1010 = Type: SRC_VLAN (58) [Reverse]
                Length: 2
                PEN: IPFIX Reverse Information Element Private Enterprise (29305)
            Field (25/25): Unknown(32767)
                0... .... .... .... = Pen provided: No
                .111 1111 1111 1111 = Type: Unknown (32767)
                Length: 65535 [i.e.: "Variable Length"]
        Template (Id = 49155, Count = 3)
            Template Id: 49155
            Field Count: 3
            Field (1/3): TCP_SEQ_NUM
                0... .... .... .... = Pen provided: No
                .000 0000 1011 1000 = Type: TCP_SEQ_NUM (184)
                Length: 4
            Field (2/3):  14 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0000 1110 = Type: 14 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (3/3):  15 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0000 1111 = Type: 15 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
        Template (Id = 49171, Count = 6)
            Template Id: 49171
            Field Count: 6
            Field (1/6): TCP_SEQ_NUM
                0... .... .... .... = Pen provided: No
                .000 0000 1011 1000 = Type: TCP_SEQ_NUM (184)
                Length: 4
            Field (2/6):  14 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0000 1110 = Type: 14 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (3/6):  15 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0000 1111 = Type: 15 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (4/6): 16398 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .100 0000 0000 1110 = Type: 16398 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (5/6): 16399 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .100 0000 0000 1111 = Type: 16399 [pen: CERT Coordination Center]
                Length: 1
                PEN: CERT Coordination Center (6871)
            Field (6/6): TCP_SEQ_NUM [Reverse]
                1... .... .... .... = Pen provided: Yes
                .000 0000 1011 1000 = Type: TCP_SEQ_NUM (184) [Reverse]
                Length: 4
                PEN: IPFIX Reverse Information Element Private Enterprise (29305)
        Template (Id = 49176, Count = 2)
            Template Id: 49176
            Field Count: 2
            Field (1/2):  18 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .000 0000 0001 0010 = Type: 18 [pen: CERT Coordination Center]
                Length: 65535 [i.e.: "Variable Length"]
                PEN: CERT Coordination Center (6871)
            Field (2/2): 16402 [pen: CERT Coordination Center]
                1... .... .... .... = Pen provided: Yes
                .100 0000 0001 0010 = Type: 16402 [pen: CERT Coordination Center]
                Length: 65535 [i.e.: "Variable Length"]
                PEN: CERT Coordination Center (6871)
        Template (Id = 49156, Count = 2)
            Template Id: 49156
            Field Count: 2
            Field (1/2): SRC_MAC
                0... .... .... .... = Pen provided: No
                .000 0000 0011 1000 = Type: SRC_MAC (56)
                Length: 6
            Field (2/2): DESTINATION_MAC
                0... .... .... .... = Pen provided: No
                .000 0000 0101 0000 = Type: DESTINATION_MAC (80)
                Length: 6

[Deuxième paquet, avec les données]

Cisco NetFlow/IPFIX
    Version: 10
    Length: 464
    Timestamp: Jul  8, 2011 21:18:53.000000000 CEST
        ExportTime: 1310152733
    FlowSequence: 0
    Observation Domain Id: 0
    Set 1
        FlowSet Id: (Data) (45840)
        FlowSet Length: 448
        Flow 1
            [Duration: 0.274000000 seconds]
                StartTime: Jun  7, 2011 15:22:38.902000000 CEST
                EndTime: Jun  7, 2011 15:22:39.176000000 CEST
            Permanent Octets: 220
            Permanent Octets: 276 (Reverse Type 85 BYTES_TOTAL)
            Permanent Packets: 4
            Permanent Packets: 4 (Reverse Type 86 PACKETS_TOTAL)
            SrcAddr: 77.250.217.161 (77.250.217.161)
            DstAddr: 192.168.5.219 (192.168.5.219)
            SrcPort: 51413
            DstPort: 52026
            Protocol: 6
            Flow End Reason: End of Flow detected (3)
            Enterprise Private entry: (CERT Coordination Center) Type 21: Value (hex bytes): 00 00 00 00
            Vlan Id: 0
            Vlan Id: 0 (Reverse Type 58 SRC_VLAN)
            [Enterprise Private entry: ((null)) Type 32767: Value (hex bytes): 00 c0 13 00 10 14 8d 68 ed 12 11 18 11 ed 4e 7d ... (Variable Length)]
                String_len_short: 255
                String_len_short: 17
        Flow 2
            [Duration: 0.672000000 seconds]
                StartTime: Jun  7, 2011 15:22:40.813000000 CEST
                EndTime: Jun  7, 2011 15:22:41.485000000 CEST
            Permanent Octets: 336
            Permanent Octets: 164 (Reverse Type 85 BYTES_TOTAL)
            Permanent Packets: 5
            Permanent Packets: 3 (Reverse Type 86 PACKETS_TOTAL)
            SrcAddr: 192.168.5.219 (192.168.5.219)
            DstAddr: 84.97.86.239 (84.97.86.239)
            SrcPort: 52035
            DstPort: 43572
            Protocol: 6
            Flow End Reason: End of Flow detected (3)
            Enterprise Private entry: (CERT Coordination Center) Type 21: Value (hex bytes): 00 00 00 dd
            Vlan Id: 0
            Vlan Id: 0 (Reverse Type 58 SRC_VLAN)
            [Enterprise Private entry: ((null)) Type 32767: Value (hex bytes): 00 c0 13 00 10 a3 c6 5c 68 02 19 12 11 8e be b7 ... (Variable Length)]
                String_len_short: 255
                String_len_short: 17
        Flow 3
            [Duration: 2.046000000 seconds]
                StartTime: Jun  7, 2011 15:22:40.813000000 CEST
                EndTime: Jun  7, 2011 15:22:42.859000000 CEST
            Permanent Octets: 336
            Permanent Octets: 164 (Reverse Type 85 BYTES_TOTAL)
            Permanent Packets: 5
            Permanent Packets: 3 (Reverse Type 86 PACKETS_TOTAL)
            SrcAddr: 192.168.5.219 (192.168.5.219)
            DstAddr: 142.68.133.226 (142.68.133.226)
            SrcPort: 52036
            DstPort: 50006
            Protocol: 6
            Flow End Reason: End of Flow detected (3)
            Enterprise Private entry: (CERT Coordination Center) Type 21: Value (hex bytes): 00 00 03 51
            Vlan Id: 0
            Vlan Id: 0 (Reverse Type 58 SRC_VLAN)
            [Enterprise Private entry: ((null)) Type 32767: Value (hex bytes): 00 c0 13 00 10 54 cc ca 16 02 19 12 11 74 3f 5e ... (Variable Length)]
                String_len_short: 255
                String_len_short: 17
        Flow 4
            [Duration: 0.162000000 seconds]
                StartTime: Jun  7, 2011 15:22:43.806000000 CEST
                EndTime: Jun  7, 2011 15:22:43.968000000 CEST
            Permanent Octets: 60
            Permanent Octets: 40 (Reverse Type 85 BYTES_TOTAL)
            Permanent Packets: 1
            Permanent Packets: 1 (Reverse Type 86 PACKETS_TOTAL)
            SrcAddr: 192.168.5.219 (192.168.5.219)
            DstAddr: 84.221.224.151 (84.221.224.151)
            SrcPort: 52047
            DstPort: 44809
            Protocol: 6
            Flow End Reason: End of Flow detected (3)
            Enterprise Private entry: (CERT Coordination Center) Type 21: Value (hex bytes): 00 00 00 a2
            Vlan Id: 0
            Vlan Id: 0 (Reverse Type 58 SRC_VLAN)
            [Enterprise Private entry: ((null)) Type 32767: Value (hex bytes): 00 c0 13 00 10 60 40 f2 6b 02 00 14 00 00 00 00 ... (Variable Length)]
                String_len_short: 255
                String_len_short: 17
        Flow 5
            [Duration: 0.335000000 seconds]
                StartTime: Jun  7, 2011 15:22:43.804000000 CEST
                EndTime: Jun  7, 2011 15:22:44.139000000 CEST
            Permanent Octets: 60
            Permanent Octets: 40 (Reverse Type 85 BYTES_TOTAL)
            Permanent Packets: 1
            Permanent Packets: 1 (Reverse Type 86 PACKETS_TOTAL)
            SrcAddr: 192.168.5.219 (192.168.5.219)
            DstAddr: 113.160.54.234 (113.160.54.234)
            SrcPort: 52044
            DstPort: 39621
            Protocol: 6
            Flow End Reason: End of Flow detected (3)
            Enterprise Private entry: (CERT Coordination Center) Type 21: Value (hex bytes): 00 00 01 4f
            Vlan Id: 0
            Vlan Id: 0 (Reverse Type 58 SRC_VLAN)
            [Enterprise Private entry: ((null)) Type 32767: Value (hex bytes): 00 c0 13 00 10 a0 86 d6 62 02 00 14 00 00 00 00 ... (Variable Length)]
                String_len_short: 255
                String_len_short: 17
...

Questions lectures, vous pouvez regarder cet exposé à FRnog.


Téléchargez le RFC 7011


L'article seul

RFC 7010: IPv6 Site Renumbering Gap Analysis

Date de publication du RFC : Septembre 2013
Auteur(s) du RFC : B. Liu, S. Jiang (Huawei Technologies), B. Carpenter (University of Auckland), S. Venaas (Cisco Systems), W. George (Time Warner Cable)
Pour information
Réalisé dans le cadre du groupe de travail IETF 6renum
Première rédaction de cet article le 14 septembre 2013


Si on pouvait facilement renuméroter (changer les adresses IP) d'un réseau, beaucoup de problèmes seraient moins graves. Par exemple, il y aurait moins de demande pour des adresses PI. Mais, comme l'explique bien le RFC 5887, renuméroter, en pratique, est difficile, et les administrateurs réseaux, à juste titre, font tout ce qu'ils peuvent pour l'éviter. Pour essayer de résoudre ce problème, l'IETF a un groupe de travail 6renum, dont voici le troisième RFC. 6renum travaille à faciliter la rénumérotation en IPv6. Ce RFC 7010 est consacré à l'analyse des trous : que manque t-il comme protocole IETF pour faciliter la renumérotation ?

C'est un enjeu important pour l'Internet : sans renumérotation facile, les administrateurs réseaux se tourneront encore plus massivement vers les adresses PI, qui exercent une pression sur la table de routage (RFC 4984). Le RFC 6879, plus pratique, décrivait un certain nombre de scénarios de renumérotation et ce nouveau document, le RFC 7010 va bâtir sur ces scénarios en regardant ce qui gêne leur réalisation (et qui nécessitera un travail à l'IETF). Les machines ayant une adresse IP statique, typiquement les serveurs, sont traitées dans un autre document, le RFC 6866. De même, le cas d'une rénumérotation urgente et non planifiée, par exemple suite à la faillite d'un FAI, n'est pas couvert ici.

Donc, d'abord (section 2), qu'appelle t-on une rénumérotation réussie ? Que voudrait-on comme propriétés ? Une rénumérotation part d'un ancien préfixe et arrive à un nouveau. Pour les moyennes et grandes organisations, on a pu recevoir ce nouveau préfixe par des moyens humains (message électronique, par exemple). Pour les petites, on a pu le recevoir par une délégation, genre DHCPv6-PD (Prefix Delegation, RFC 8415). Dans les deux cas, on voudrait plein de choses :

  • Le nouveau préfixe devrait être reçu automatiquement et correctement,
  • Les adresses IP dans ce nouveau préfixe devraient être acquises automatiquement par les machines, sans intervention humaine,
  • Les endroits où se trouvent configurées ces adresses devraient se mettre à jour,
  • Même si ça se passe tout seul, on souhaiterait être notifié de ce changement et pouvoir le superviser,
  • Enfin, on voudrait que la rénumérotation ne casse pas les sessions applicatives en cours (pensez à SSH...) Comme ce RFC ne regarde que les renumérotations contrôlées (pas celles faites en urgence, à l'arrache), cet objectif peut être atteint en ayant une période de transition qui soit plus longue que la durée de vie de ces sessions applicatives.

Comme le savent les lecteurs du RFC 5887, on en est loin...

Et quels sont les protocoles, les outils et les procédures qui peuvent nous aider à s'approcher de ces beaux objectifs (section 3) ? Les protocoles sont les suivants :

  • Les messages RA (Router Advertisment, RFC 4861) permettent d'annoncer les préfixes IPv6 utilisés sur le lien local,
  • SLAAC (StateLess Address AutoConfiguration, RFC 4862) permet aux machines de se configurer une adresse IPv6 après avoir entendu les RA,
  • RA + SLAAC ne sont pas la seule solution, IPv6 a aussi DHCP (RFC 8415 et RFC 8415 pour la délégation de préfixe),
  • Il y eu aussi un système utilisant ICMP spécifiquement pour la rénumérotation, décrit dans le RFC 2894 et qui ne semble pas avoir jamais été déployé.

Il y a aussi des outils :

  • Les moyens et grands réseaux ne se gèrent pas à la main, ils se servent d'IPAM, qui gardent trace des adresses et de leur allocation,
  • Dès que le réseau a une taille non triviale, il est fréquent que les modifications ne soient pas propagées manuellement mais par un outil comme Chef ou Puppet,
  • Cette propagation des configurations peut aussi se faire avec des outils utilisant NETCONF (RFC 4741) ou d'autres protocoles de transport. Pour des détails pratiques, on peut consulter l'article de Leroy et Bonaventure, « Preparing network configurations for IPv6 renumbering »,

Et des procédures :

  • Le RFC 4192 décrit en détail comment renuméroter un réseau IPv6 sans flag day, sans un jour J où le soleil se coucherait sur un réseau complètement migré,
  • Le RFC 6879, déjà cité, étudie des cas de renumérotation et fait des recommandations opérationnelles.

Mais, en pratique, cela ne suffit pas. La section 5 se penche sur le premier problème, la configuration des adresses dans les machines terminales et les routeurs. D'abord, l'interaction entre SLAAC et DHCP, une source de frustration fréquente pour les administrateurs réseaux IPv6. En gros, ces deux protocoles permettent de faire la renumérotation. S'ils sont présents tous les deux sur un réseau, c'est plus compliqué et il faut bien les coordonner. Le plus simple est quand même de n'en avoir qu'un seul (ce qui est, heureusement, le cas le plus courant). Normalement, il existe des indications dans les messages permettant de coordonner les deux protocoles (options M et O du RA, cf. RFC 4861, section 4.2). Mais ils sont traités comme indicatifs seulement. Résultat, les différents systèmes d'exploitation ne les interprètent pas de la même manière. On n'est donc pas sûr, par exemple, qu'on puisse renuméroter avec les RA des machines qui avaient été configurées en DHCP (ManagedFlag passant de 1 à 0). De même, les RFC 4862 et RFC 3315 ne sont pas clairs sur ce que doit faire une machine cliente DHCP lorsqu'elle voit des nouveaux préfixes être annoncés par des RA. Un problème analogue se pose en sens inverse (transition de DHCP vers SLAAC).

Et pour les routeurs ? Logiquement, tout devrait bien se passer sauf que, contrairement aux machines terminales qui acceptent toutes de changer d'adresse IP en vol, certains routeurs doivent être redémarrés lorsque cela leur arrive.

Comme souvent en renumérotation, on s'épargnerait bien des problèmes en utilisant des noms dans les configurations et pas des adresses IP. Mais le RFC note, à juste titre, que ce n'est pas toujours le cas pour les routeurs.

Une fois machines terminales et routeurs renumérotés, il reste à mettre à jour des tas de configurations et de bases de données qui stockent encore les anciennes adresses. C'est l'objet de la section 6. Premier exemple, les zones DNS. La zone peut être maintenue à la main, avec un éditeur et il faudra alors faire un rechercher/remplacer. Ou bien on peut utiliser les mises à jour dynamiques (RFC 3007). Cette fonction existe depuis longtemps, est mise en œuvre dans plusieurs logiciels serveurs mais, pour que chaque machine puisse individuellement faire la mise à jour, il faut un mécanisme d'autorisation, et gérer une clé dans chaque machine n'est pas pratique. Il est plus commun que la mise à jour du DNS soit faite par le serveur DHCP, pour le compte des machines terminales (RFC 4704). Cela marche très bien si la renumérotation est faite par DHCP. Si on a utilisé SLAAC, il n'existe pas de solution évidente (aujourd'hui : des réflexions sont en cours, par exemple dans draft-ietf-dhc-addr-registration).

Il reste à traiter le cas des adresses IP éparpillées un peu partout, notamment dans des ACL. Il n'existe pas de solution générale pour ce problème. Mais notre RFC recommande que, lorsqu'on utilise des adresses IP dans des configurations, on définisse une variable au début et on l'utilise ensuite, pour limiter la douleur de la renumérotation. Un exemple en shell Unix avec Netfilter, pour un routeur Unix qui transmet vers un serveur HTTP :

# Define the variable
WEBSERVER=2001:db8:cafe::1:34a

# By default, block everything
ip6tables --policy FORWARD DROP

# Allow ICMP. We could be more selective.
ip6tables --append FORWARD --protocol icmp --destination ${WEBSERVER} --jump ACCEPT

# Rate limiting
ip6tables --append FORWARD --protocol tcp --destination ${WEBSERVER} --dport 80 --tcp-flags SYN SYN -m hashlimit \
   --hashlimit-name Web --hashlimit-above 3/second --hashlimit-mode srcip \
   --hashlimit-burst 7 --hashlimit-srcmask 28 --jump DROP

# Allow HTTP and HTTPS
ip6tables --append FORWARD --protocol tcp --destination ${WEBSERVER} \
         --dport 80:443 --jump ACCEPT

Ainsi, le script n'utilise qu'une seule fois l'adresse, au début, et est donc bien plus facile à modifier. Un programme comme ack-grep est très pratique pour trouver tous ces cas où une adresse est stockée dans la configuration :

# ack-grep --all 2001:db8:cafe::1:42   
network/interfaces
14:        address 2001:db8:cafe::1:42   

nsd3/nsd.conf
15:        ip-address: 2001:db8:cafe::1:42   
...

Pour simplifier ce problème des adresses IP dispersées un peu partout, notre RFC recommande l'utilisation d'outils de gestion de configuration comme Chef ou Puppet : on change la configuration à un endroit et elle est ensuite poussée vers tous les serveurs. Il existe aussi des outils non-libres, spécifiques à un vendeur particulier, pour assurer cette tâche et le RFC regrette l'absence d'une norme complète (NETCONF ne règle pas tous les cas) et ouverte pour cette question de mise à jour.

Pour que l'opération de migration vers les nouvelles adresses se passe bien, il faut aussi des mécanismes de gestion des événements, notamment de notification (« Un nouveau préfixe est arrivé »). Ces notifications permettraient, par exemple, d'invalider les caches DNS (pour forcer une mise à jour), ou de changer les configurations de filtrage (le RFC 2827 demande qu'on ne laisse pas sortir de son réseau les paquets ayant une adresse IP source autre que celles du réseau ; mettre ce filtrage en œuvre nécessite de connaître le préfixe du réseau local, et d'en changer si nécessaire). Cette notification n'est pas triviale, notamment si on utilise SLAAC (puisque, dans ce cas, aucun serveur central n'est informé du changement d'adresse d'une machine)

Le DNS pose d'ailleurs d'autres questions. En raison du TTL des enregistrements DNS, les nouvelles informations ne peuvent pas être réjuvénées instantanément. Si la rénumérotation du réseau est prévue suffisemment à l'avance, la bonne pratique est d'abaisser ces TTL avant, de faire le changement, puis de remonter les TTL.

Les sections 9 et 10 résument les trous qu'il y a actuellement dans les protocoles TCP/IP, et dont le comblement rendrait la rénumérotation plus facile :

  • Un mécanisme pour informer le routeur qu'il doit se rénuméroter lui-même, et pour choisir une adresse dans le préfixe délégué. Et une meilleure gestion de sa propre renumérotation par le routeur (ne nécessitant pas de redémarrage).
  • Une meilleure spécification des interactions SLAAC<->DHCP, notamment sur la renumérotation en DHCP de machines numérotées par SLAAC et réciproquement.
  • Le problème de la mise à jour du DNS par les machines SLAAC reste entier.
  • L'usage trop important d'adresse IP « codées en dur », non dérivées d'une unique variable facile à changer. Certains systèmes ne permettent même pas une telle dérivation.
  • Un mécanisme de notification « attention, les adresses vont changer / ont changé ».
  • L'interaction avec les TTL DNS reste compliquée.

La section 10 se spécialise dans les trous considérés comme insolubles, et dont le groupe 6renum ne s'occupera donc pas :

  • La mise à jour des zones DNS pour le cas où elles sont extérieures à l'organisation, par exemple chez un hébergeur DNS qui fournit uniquement une interface Web pour les mettre à jour.
  • La synchronisation des entrées AAAA (nom -> adresse) et PTR (adresse -> nom) dans le DNS. Cette synchronisation est d'autant plus insoluble que les zones « directes » et « inverses » (ip6.arpa) peuvent très bien être gérées par des hébergeurs différents.
  • Créer des types d'enregistrement DNS explicitement pour faciliter la renumérotation a déjà été tenté avec le A6 du RFC 2874. Trop complexe, le A6 a été peu déployé et a officiellement été abandonné avec le RFC 6563. L'idée de séparer le préfixe de l'adresse et son suffixe lors de la résolution DNS reste dans l'air mais le groupe 6renum n'a pas l'intention de s'y attaquer.
  • Les protocoles de transport comme TCP lient une connexion aux adresses IP de source et de destination. Cela a des tas d'inconvénients (en cas de renumérotation, les connexions cassent) mais c'est considéré comme un problème de grande ampleur, loin des capacités du groupe 6renum.
  • Un problème analogue se pose dans certaines applications, qui cassent les sessions lorsqu'une adresse IP d'une des parties change.

Voilà, nous avons fait le tour des problèmes, il reste à lire la section 11, spécialisée dans les questions de sécurité. Par exemple, si on a des ACL sur les adresses IP, et qu'elles interdisent à certains méchants de se connecter à l'adresse IP d'un serveur, la rénumérotation ne doit pas invalider cette liste noire : la règle doit être mise à jour pour pointer vers la nouvelle adresse IP du serveur.

Mais on peut aussi noter que la configuration automatique, souhaitée par le RFC, amène aussi ses propres risques, comme illustré par l'accident de Cloudflare ou comme un cas rigolo avec Ansible.


Téléchargez le RFC 7010


L'article seul

RFC 7001: Message Header Field for Indicating Message Authentication Status

Date de publication du RFC : Septembre 2013
Auteur(s) du RFC : M. Kucherawy
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 21 septembre 2013


Il existe désormais plusieurs techniques pour authentifier les courriers électroniques. Certaines peuvent nécessiter des calculs un peu compliqués et on voudrait souvent les centraliser sur une machine de puissance raisonnable, dotée de tous les logiciels nécessaires. Dans cette hypothèse, le MUA ne recevra qu'une synthèse (« Ce message vient bien de example.com ») et pourra alors prendre une décision, basée sur cette synthèse. C'est le but de l'en-tête Authentication-Results:, normalisé originellement dans le RFC 5451 quatre ans plus tôt, RFC que ce nouveau RFC met légèrement à jour (il y a peu de changements). Il a lui-même été remplacé, depuis, par le RFC 7601.

Avec des techniques d'authentification comme DKIM (RFC 6376) ou SPF (RFC 7208), les calculs à faire pour déterminer si un message est authentique peuvent être complexes (DKIM utilise la cryptographie) et nécessiter la présence de bibliothèques non-standard. Les installer et les maintenir à jour sur chaque machine, surtout en présence d'éventuelles failles de sécurité qu'il faudra boucher en urgence, peut être trop pénible pour l'administrateur système. L'idée de ce RFC est donc de séparer l'opération en deux : l'authentification est faite sur un serveur, typiquement le premier MTA du site (cf. annexe D pour une discussion de ce choix), celui-ci ajoute au message un en-tête indiquant le résultat de ladite authentification et le MUA (ou bien le MDA, voir la section 1.5.3 pour un bon rappel sur ces concepts) peut ensuite, par exemple par un langage de filtrage comme procmail ou Sieve, agir sur la base de ce résultat. Cet en-tête marche pour tous les protocoles d'authentification et surpasse donc les en-têtes spécifiques comme le Received-SPF: de SPF (section 1 du RFC). Le filtrage des messages non authentifiés n'est pas obligatoire (section 1.4) : agir - ou pas - sur la base de l'en-tête Authentication-Results: est une décision politique locale.

J'ai utilisé le terme de « site » pour désigner un ensemble de machines gérées par la même organisation mais le RFC a un terme plus rigoureux, ADMD (ADministrative Management Domain). La frontière d'un ADMD est la « frontière de confiance » (trust boundary), définie en section 1.2. Un domaine administratif de gestion est un groupe de machines entre lesquelles il existe une relation de confiance, notamment du fait que, à l'intérieur de l'ADMD, l'en-tête Authentication-Results: ne sera pas modifié ou ajouté à tort (section 1.6 : l'en-tête n'est pas protégé, notamment il n'est pas signé). Il existe de nombreuses variantes organisationnelles du concept d'ADMD. Un ADMD inclus typiquement une organisation (ou un département de celle-ci) et d'éventuels sous-traitants. Il a un nom, l'authserv-id, défini en section 2.2.

L'en-tête Authentication-Results: lui-même est formellement défini en section 2. Il appartient à la catégorie des en-têtes de « trace » (RFC 5322, section 3.6.7 et RFC 5321, section 4.4) comme Received: qui doivent être ajoutés en haut des en-têtes et jamais modifiés. La syntaxe de Authentication-Results: est en section 2.2. L'en-tête est composé du authserv-id, le nom de l'ADMD et d'une série de doublets (méthode, résultat), chacun indiquant une méthode d'authentification et le résultat obtenu. L'annexe C fournit une série d'exemples. Elle commence (annexe C.1) par un message sans Authentication-Results: (eh oui, il n'est pas obligatoire). Puis (tiré de l'annexe C.3), une authentification SPF réussie, au sein de l'ADMD example.com, donnera :

        Authentication-Results: example.com;
                  spf=pass smtp.mailfrom=example.net
        Received: from dialup-1-2-3-4.example.net
                      (dialup-1-2-3-4.example.net [192.0.2.200])
                  by mail-router.example.com (8.11.6/8.11.6)
                      with ESMTP id g1G0r1kA003489;
                  Wed, Mar 14 2009 17:19:07 -0800
        From: sender@example.net
        Date: Wed, Mar 14 2009 16:54:30 -0800
        To: receiver@example.com

Rappelez-vous qu'il peut y avoir plusieurs authentifications. Voici un cas (annexe C.4) avec SPF et l'authentification SMTP du RFC 4954 :

       Authentication-Results: example.com;
                  auth=pass (cram-md5) smtp.auth=sender@example.net;
                  spf=pass smtp.mailfrom=example.net
        Received: from dialup-1-2-3-4.example.net (8.11.6/8.11.6)
                      (dialup-1-2-3-4.example.net [192.0.2.200])
                  by mail-router.example.com (8.11.6/8.11.6)
                      with ESMTP id g1G0r1kA003489;
                  Fri, Feb 15 2002 17:19:07 -0800
        Date: Fri, Feb 15 2002 16:54:30 -0800
        To: receiver@example.com
        From: sender@example.net

L'une des authentifications peut réussir et l'autre échouer. Un exemple (annexe C.6) avec deux signatures DKIM, une bonne et une qui était correcte au départ (regardez le premier Authentication-Results:) mais plus à l'arrivée, peut-être parce qu'un gestionnaire de liste de diffusion a modifié le message :

       Authentication-Results: example.com;
              dkim=pass reason="good signature"
                header.i=@mail-router.example.net;
              dkim=fail reason="bad signature"
                header.i=@newyork.example.com
        Received: from mail-router.example.net
                  (mail-router.example.net [192.0.2.250])
              by chicago.example.com (8.11.6/8.11.6)
                  for <recipient@chicago.example.com>
                  with ESMTP id i7PK0sH7021929;
              Fri, Feb 15 2002 17:19:22 -0800
        DKIM-Signature: v=1; a=rsa-sha256; s=furble;
              d=mail-router.example.net; t=1188964198; c=relaxed/simple;
              h=From:Date:To:Message-Id:Subject:Authentication-Results;
              bh=ftA9J6GtX8OpwUECzHnCkRzKw1uk6FNiLfJl5Nmv49E=;
              b=oINEO8hgn/gnunsg ... 9n9ODSNFSDij3=
        Authentication-Results: example.net;
              dkim=pass (good signature) header.i=@newyork.example.com
        Received: from smtp.newyork.example.com
                  (smtp.newyork.example.com [192.0.2.220])
              by mail-router.example.net (8.11.6/8.11.6)
                  with ESMTP id g1G0r1kA003489;
              Fri, Feb 15 2002 17:19:07 -0800
        DKIM-Signature: v=1; a=rsa-sha256; s=gatsby;
              d=newyork.example.com;
              t=1188964191; c=simple/simple;
              h=From:Date:To:Message-Id:Subject;
              bh=sEu28nfs9fuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m7=;
              b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM=
        From: sender@newyork.example.com
        Date: Fri, Feb 15 2002 16:54:30 -0800
        To: meetings@example.net

La liste complète des méthodes figure dans un registre IANA (section 6). De nouvelles méthodes peuvent être enregistrées en utilisant la procédure « Examen par un expert » du RFC 5226.

La section 2.3 détaille l'authserv-id. C'est un texte qui identifie le domaine, l'ADMD. Il doit donc être unique dans tout l'Internet. En général, c'est un nom de domaine comme laposte.net. (Il est possible d'être plus spécifique et d'indiquer le nom d'une machine particulière mais cette même section du RFC explique pourquoi c'est en général une mauvaise idée : comme les MUA du domaine n'agissent que sur les Authentication-Results: dont ils reconnaissent l'authserv-id, avoir un tel identificateur qui soit lié au nom d'une machine, et qui change donc trop souvent, complique l'administration système.)

La section 2.5 explique les résultats possibles pour les méthodes d'authentification (en rappelant que la liste à jour des méthodes et des résultats est dans le registre IANA). Ainsi, DKIM (section 2.5.1) permet des résultats comme pass (authentification réussie) ou temperror (erreur temporaire au cours de l'authentification, par exemple liée au DNS). Des résultats similaires sont possibles pour SPF (section 2.5.3).

Notons la normalisation d'une méthode traditionnelle d'authentification faible, le test DNS du chemin « adresse IP du serveur -> nom » et retour. Baptisée iprev, cette méthode, bien que bâtie sur la pure superstition (cf. section 7.11) est utilisée couramment. Très injuste (car les arbres des résolutions inverses du DNS, in-addr.arpa et ip6.arpa, ne sont pas sous le contrôle du domaine qui envoie le courrier), cette méthode discrimine les petits FAI, ce qui est sans doute un avantage pour les gros, comme AOL qui l'utilisent. Attention aux implémenteurs : aussi bien la résolution inverse d'adresse IP en nom que la résolution droite de nom en adresse IP peuvent renvoyer plusieurs résultats et il faut donc comparer des ensembles. (Cette méthode qui, contrairement aux autres, n'avait jamais été exposée dans un RFC avant le RFC 5451, est décrite en détail dans la section 3, avec ses sérieuses limites.)

Autre méthode mentionnée, auth (section 2.5.4) qui repose sur l'authentification SMTP du RFC 4954. Si un MTA (ou plutôt MSA) a authentifié un utilisateur, il peut le noter ici.

Une fois le code d'authentification exécuté, où mettre le Authentication-Results: ? La section 4 fournit tous les détails, indiquant notamment que le MTA doit placer l'en-tête en haut du message, ce qui facilite le repérage des Authentication-Results: à qui on peut faire confiance (en examinant les en-têtes Received: ; en l'absence de signature, un Authentication-Results: très ancien, situé au début du trajet, donc en bas des en-têtes, ne signifie pas grand'chose). On se fie a priori aux en-têtes mis par les MTA de l'ADMD, du domaine de confiance. L'ordre est donc important. (La section 7 revient en détail sur les en-têtes Authentication-Results: usurpés.)

Ce n'est pas tout de mettre un Authentication-Results:, encore faut-il l'utiliser. La section 4.1 s'attaque à ce problème. Principe essentiel pour le MUA : ne pas agir sur la base d'un Authentication-Results:, même si ce n'est que pour l'afficher, sans l'avoir validé un minimum. Comme le Authentication-Results: n'est pas signé, n'importe qui a pu en insérer un sur le trajet. Le RFC précise donc que les MUA doivent, par défaut, ne rien faire. Et qu'ils doivent ne regarder les Authentication-Results: qu'après que cela ait été activé par l'administrateur de la machine, qui indiquera quel authserv-id est acceptable.

Naturellement, le MTA d'entrée du domaine devrait supprimer les Authentication-Results: portant son propre authserv-id qu'il trouve dans les messages entrants : ils sont forcément frauduleux (section 5). (Le RFC accepte aussi une solution plus simpliste, qui est de supprimer tous les Authentication-Results: des messages entrants, quel que soit leur authserv-id.)

Arrivé à ce stade de cet article, le lecteur doit normalement se poser bien des questions sur la valeur du Authentication-Results:. Quel poids lui accorder alors que n'importe quel méchant sur le trajet a pu ajouter des Authentication-Results: bidons ? La section 7, consacrée à l'analyse générale de la sécurité, répond à ces inquiétudes. 7.1 détaille le cas des en-têtes usurpés. Les principales lignes de défense ici sont le fait que le MUA ne doit faire confiance aux Authentication-Results: que s'ils portent le authserv-id de son ADMD et le fait que le MTA entrant doit filtrer les Authentication-Results: avec son authserv-id. Comme l'intérieur de l'ADMD, par définition, est sûr, cela garantit en théorie contre les Authentication-Results: usurpés. Le RFC liste néanmoins d'autres méthodes possibles comme le fait de ne faire confiance qu'au premier Authentication-Results: (le plus récent), si on sait que le MTA en ajoute systématiquement un (les éventuels Authentication-Results: usurpés apparaîtront après ; mais certains serveurs les réordonnent, cf. section 7.3). Pour l'instant, il n'y a pas de méthode unique et universelle de vérification du Authentication-Results:, le RFC propose des pistes mais ne tranche pas.

Comme toujours en sécurité, il faut bien faire la différence entre authentification et autorisation. Un spammeur a pu insérer un Authentication-Results: légitime pour son authserv-id. Même authentifié, il ne doit pas être considéré comme une autorisation (section 7.2).

Plusieurs mises en œuvre de ce système existent déjà comme dans MDaemon, sendmail (via sid-milter), Courier, OpenDKIM, etc. Si on veut analyser les en-têtes Authentication-Results: en Python, on a le module authres. Parmi les grosses usines à courrier centralisées, Gmail met systématiquement cet en-tête, par exemple :

Authentication-Results: mx.google.com; spf=pass \
           (google.com: domain of stephane@sources.org designates 217.70.190.232 \
               as permitted sender) smtp.mail=stephane@sources.org

Outre Gmail, à la date de publication du RFC, Yahoo et Hotmail ajoutaient cet en-tête.

Les changements depuis le RFC 5451 sont peu nombreux. Outre la correction d'erreurs, on trouve l'intégration du RFC 6577, une libéralisation des règles d'enregistrement de nouvelles méthodes d'authentification, des nouvelles méthodes (dont je n'ai pas parlé ici) comme le VBR du RFC 6212 et divers changements éditoriaux. Le RFC 7601, qui l'a ensuite remplacé, n'a pas non plus fait de changements énormes.


Téléchargez le RFC 7001


L'article seul

RFC des différentes séries : 0  1000  2000  3000  4000  5000  6000  7000  8000  9000