Ce blog n'a d'autre prétention que de me permettre de mettre à la disposition de tous des petits textes que j'écris. On y parle surtout d'informatique mais d'autres sujets apparaissent parfois.
Première rédaction de cet article le 16 Mai 2013
Aujourd'hui, le site Web de la RATP,
a été en panne de 11h à
16h environ (la reprise a été cahotique, avec de nombreuses rechutes
jusqu'en soirée). Que s'est-il passé ? Comme pour chaque panne d'un service
Internet, c'est l'occasion d'en tirer des leçons pour améliorer la
résilience.http://www.ratp.fr/
Sur les réseaux sociaux, les utilisateurs mécontents ont signalé le problème en disant que « le site Web ne marche pas » ou que « l'appli (pour mobile) ne marche pas ». Mais la vraie cause n'étant pas là. Regardons pendant la panne avec wget :
% wget http://www.ratp.fr/ --2013-05-16 11:52:21-- http://www.ratp.fr/ Resolving www.ratp.fr... failed: Name or service not known. wget: unable to resolve host address `www.ratp.fr'
Le message d'erreur est clair : le client HTTP
wget n'a pas réussi à charger le site car il n'a pas pu résoudre le
nom en adresse IP. C'était donc un problème DNS,
apparemment. Regardons le DNS pendant la panne avec
dig. Quels sont les serveurs de noms de ratp.fr ?
% dig NS ratp.fr ... ;; ANSWER SECTION: ratp.fr. 3600 IN NS indom10.indomco.com. ratp.fr. 3600 IN NS ns1.ratp.fr. ratp.fr. 3600 IN NS indom30.indomco.fr. ratp.fr. 3600 IN NS ns0.ratp.fr. ...
Et demandons à l'un d'eux l'adresse de
www.ratp.fr :
% dig @ns0.ratp.fr. A www.ratp.fr ... ;; AUTHORITY SECTION: www.ratp.fr. 3600 IN NS altns1.ratp.fr. www.ratp.fr. 3600 IN NS altns2.ratp.fr. ;; ADDITIONAL SECTION: altns1.ratp.fr. 3600 IN A 195.200.228.2 altns2.ratp.fr. 3600 IN A 195.200.228.130 ;; Query time: 4 msec ;; SERVER: 193.104.162.15#53(193.104.162.15) ;; WHEN: Thu May 16 11:53:02 2013 ;; MSG SIZE rcvd: 114
Ah, on n'a pas directement l'adresse mais une
délégation. Le DNS repose sur un système
arborescent de délégations depuis la racine
jusqu'à la machine qui connait la réponse. Dans
.fr, il n'y a en général
pas de délégation entre le deuxième et le troisième
composant du nom de domaine mais, ici, c'est le
cas : www.ratp.fr n'est pas dans la même
zone que ratp.fr.
Avant de revenir sur les raisons de cette délégation inhabituelle
(mais parfaitement légale), continuons la recherche de l'adresse IP de
www.ratp.fr :
% dig @altns1.ratp.fr. A www.ratp.fr ; <<>> DiG 9.7.3 <<>> @altns1.ratp.fr. A www.ratp.fr ; (1 server found) ;; global options: +cmd ;; connection timed out; no servers could be reached
Et c'est pareil pour altns2.ratp.fr. La zone n'a
que deux serveurs de noms, ce qui est peu, et les deux sont en panne
en même temps. Pas étonnant que le nom ne puisse pas être résolu.
Pourquoi ces deux serveurs sont en panne simultanément ? La
proximité de leurs adresses IP fait penser qu'ils sont sans doute au
même endroit, et qu'ils ont été victimes de la même panne de courant
ou de réseau ou de la même attaque par déni de service. La RATP n'a pas suivi un principe de base de la
résilience : éloigner les serveurs de noms, pour que la même panne ne
les coupe pas tous en même temps. On note que la zone
ratp.fr suit les bons principes (quatre serveurs,
bien éloignés). Mais www.ratp.fr ne le fait hélas pas.
Mais pourquoi cette délégation relativement inhabituelle du nom
www ? Le plus probable est que le site Web se
trouve derrière un équipement de répartition de charge et que cet équipement prend également en charge le
DNS, changeant les réponses suivant la demande. Une fois le service
réparé, on peut d'ailleurs constater que ces engins envoient des
réponses avec une durée de vie très courte (300 secondes). Ces
équipements conçus pour les gens du Web (qui ne connaissent pas
forcément le DNS) sont souvent bogués jusqu'au trognon. Ainsi, un des
serveurs répond parfois FORMERR (Format
Error) et renvoie une réponse syntaxiquement incorrecte (le Messages has 11 extra bytes at end) :
% dig @altns1.ratp.fr A www.ratp.fr ... ;; ->>HEADER<<- opcode: QUERY, status: FORMERR, id: 12599 ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; WARNING: Messages has 11 extra bytes at end ;; QUESTION SECTION: ;www.ratp.fr. IN A ;; Query time: 37 msec ;; SERVER: 195.200.228.2#53(195.200.228.2) ;; WHEN: Thu May 16 22:17:06 2013 ;; MSG SIZE rcvd: 40
Ce comportement disparait si on coupe EDNS.
Merci à Jean-Baptiste Favre pour le premier signalement.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : H. Flanagan (RFC Series Editor), N. Brownlee (Independent Submissions Editor)
Pour information
Première rédaction de cet article le 15 Mai 2013
Cela fait longtemps que le format des RFC est critiqué, à l'IETF ou ailleurs. Pour d'excellentes raisons (détaillées plus loin), ce format est très ancien et très rigide, sans concessions aux gadgets modernes. Il n'a pas encore été possible de le modifier, à la fois en raison des difficultés de prise de décision au sein de la communauté, et aussi parce que le problème est réellement difficile. Contrairement à ce que prétendent certains yakafokon, trouver un format idéal n'est pas trivial. Ce RFC est la première étape d'une tentative de réforme, commençant par un cahier des charges sur les changements souhaitables. Les règles rigides de formatage (longueur des pages et des lignes) disparaissent, l'Unicode fait son entrée dans les RFC, et la possibilité d'inclure des images apparait.
Une des raisons de la stagnation du projet de changement depuis des années était la réorganisation de la fonction de RFC Editor. Désormais, les nouvelles règles sur cette fonction sont écrites (RFC 6635), une nouvelle RFC Editor a pris ses fonctions, jeune et dynamique (Heather Flanagan, un des auteurs de ce RFC), et il va peut être être enfin possible de faire évoluer le format traditionnel.
Le format actuel est documenté dans le RFC 2223 : texte brut sans enrichissement, en ASCII, pages de 58 lignes, lignes de 72 caractères au maximum, pas de notes de base de page, références croisées par numéro de section et pas de page, etc. PostScript était autorisé et quelques RFC ont été publiés ainsi. Une tentative de mise à jour de ce RFC, avec écriture d'une proposition de nouvelle version, avait eu lieu en 2004 mais avait été abandonné. J'avais déjà écrit un article détaillé expliquant le pourquoi du format traditionnel et les raisons pour lesquelles il est difficile à changer.
La section 1 de ce RFC commence par rappeler la longue histoire des RFC. Ils ont commencé il y a plus de quarante ans, et dans les débuts, certains étaient écrits à la main (!), d'autres tapés à la machine, d'autres encore produits par les outils de formatage invraisemblables qu'on trouvait sur les mainframes de l'époque. Résultat, certains sont devenus illisibles avec le temps, les outils tombant en désuétude. Ce problème de permanence est un des problèmes les plus cruciaux pour les RFC et explique pourquoi le RFC Editor n'a jamais été très chaud à l'idée d'utiliser le logiciel à la mode du moment : l'informatique en a déjà enterré beaucoup.
Au bout d'un moment, un format standard a émergé, fondé sur du texte brut et un encodage en ASCII. À partir de là, la série des RFC a vécu une longue période de calme et de stabilité et cette permanence (songez aux formats à la mode vite disparus comme WordPerfect) a beaucoup contribué à son succès. On peut relire aujourd'hui sans problème un RFC de 1980 comme le RFC 768. Ce n'est pas que le format ait été jugé parfaitement satisfaisant par tout le monde, ni qu'aucune proposition de changement n'ait été faite, bien au contraire. Mais aucun des ces propositions n'a connu de consensus : toutes résolvaient un problème précis... en en créant plusieurs autres.
Avant de regarder les propositions actuellement sur la table, il faut bien comprendre qu'il y a plusieurs endroits dans le cycle de vie d'un RFC où un format standard est nécessaire ou utile. Cette terminologie est très importante car l'incompréhension de ces étapes du cycle de vie est l'une des causes principales de la confusion des débats sur la réforme des RFC :
http://tools.ietf.org par exemple voici ce RFC), du PDF formaté différemment, etc.Évidemment, les choses ont changé depuis (le RFC 2223 date de seize ans...) Quels sont les points qui suscitent le plus de protestations ? D'abord, l'utilisation d'art ASCII et lui seul pour les graphiques. Elle a l'avantage d'encourager les auteurs à écrire des descriptions textuelles claires, plutôt que de passer du temps à faire de jolis dessins. Sans les limitations de l'art ASCII, les diagrammes seraient probablement moins concis. D'un autre côté, des choses comme les automates finis sont vite illisibles en art ASCII et les protocoles où il y a plus de trois acteurs qui interagissent sont difficiles à dessiner. Des graphiques plus élaborés que l'art ASCII permettraient également de représenter des équations mathématiques complexes.
Après les images, le sujet le plus chaud est évidemment l'encodage. ASCII a des tas d'avantages : standard, très répandu, facile à manipuler (outils de recherche, par exemple), plus pratique lorsqu'il faut renumériser un document (oui, le cas s'est déjà produit dans le passé)... Et la langue des RFC étant de toute façon l'anglais, les limites d'ASCII ne sont pas trop graves.
Mais il y a quand même des limites : lorsqu'un RFC parle
d'internationalisation (comme le RFC 5890 ou le
RFC 6530, ou comme de plus en plus de normes), c'est bien dommage de ne pas pouvoir
donner d'exemple lisible dans ce RFC. Devoir écrire
U+00c9 pour parler de É est
pénible... Des exemples comme ceux de XMPP
(RFC 6121, section 5.2.3) bénéficieraient de
l'acceptation d'Unicode dans les RFC.
Et certains auteurs de RFC ont des noms qui ne peuvent pas s'écrire correctement en ASCII et ils regrettent de devoir les modifier.
Autres points sur lesquels des gens ont souvent râlé contre le format actuel : la pagination et l'ajustement du texte. La pagination en unités fixes fait vraiment rétro : elle avait un sens quand les RFC étaient souvent imprimés pour être lus mais à l'ère des tablettes, cela semble bien dépassé. Plus compliqué est le cas de l'ajustement du texte. La largeur de colonne fixe qui est la norme actuelle convenait aux VT100 mais pas aux écrans modernes, avec leurs tailles très variables.
Enfin, ce n'est pas tout de définir des formats, il faut aussi des outils qui rendent la production de RFC conforme à ces formats facile (pour avoir une idée des difficultés, lire le RFC 5385). Ces outils doivent-ils être développés à l'IETF ou bien doit-on utiliser des outils standard ? Les exigences de l'IETF sont-elles tellement spécifiques qu'on ne puisse pas utiliser des outils existants ? D'un autre côté, les outils spécifiques donnent plus de souplesse et de pouvoir et, aujourd'hui, il en existe déjà beaucoup (par exemple, la version 2 de xml2rfc - une réécriture complète, abandonnant TCL pour Python, pour produire des RFC suivant le schéma du RFC 2629, est bien meilleure que la précédente) donc on peut dire que le modèle « faisons tout nous-même » marche bien (il y a beaucoup d'informaticiens à l'IETF).
Enfin, s'il y a des réclamations des lecteurs et des auteurs, il y en a aussi du RFC Editor : il voudrait pouvoir abandonner nroff (65 % des RFC aujourd'hui sont soumis au format XML, qu'il faut traduire en nroff au lieu de l'utiliser directement comme format d'entrée pour les différentes publications).
Après les contraintes et les réclamations, les décisions (section 3). D'abord, ce qui ne change pas :
Ensuite, les nouvelles exigences effectivement retenues, notamment :
Et il y a aussi des exigences qui ont été supprimées :
Voilà, le cahier des charges est posé, il reste à définir le
nouveau format, développer les outils, et déployer le tout... Ce sera
pour le prochain épisode. À la réunion IETF 86 a été annoncé
le choix de s'appuyer sur le format XML comme format canonique, avec
comme formats de publication le texte brut, HTML, PDF et
EPUB (voir la FAQ sur ces décisions.)
Deux Internet-Drafts sont
en cours, un sur le format, draft-rfc-format-flanagan,
et un sur le style, draft-flanagan-style.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : F. Gont (Huawei)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 15 Mai 2013
Une particularité amusante de la gestion de la fragmentation dans IPv6 est qu'un paquet peut très bien avoir un en-tête de fragmentation sans être fragmenté du tout. Cela se nomme un « fragment atomique » (le terme est très malheureux car il n'a rien à voir avec les « datagrammes atomiques » du RFC 6864). Ils n'ont aucun intérêt pratique mais sont engendrés par certains systèmes lorsqu'ils reçoivent un message ICMP Packet too big indiquant une MTU inférieure à 1280 octets (la taille miminale pour une MTU IPv6). Le problème est que ces fragments atomiques sont ensuite traités par bien des systèmes comme des vrais fragments, permettant ainsi certaines attaques subtiles. Ce nouveau RFC demande donc que les fragments atomiques soient gérés à part, compte tenu de leurs particularités.
Si vous voulez réviser les règles de la fragmentation dans IPv6, c'est dans le RFC 2460. Contrairement à IPv4, seuls les machines de départ (pas les routeurs intermédiaires) peuvent fragmenter. Si une machine de départ doit envoyer un paquet qui est trop grand pour la MTU, elle le fragmente en plusieurs morceaux, chaque morceau indiquant son décalage par rapport au début du paquet original. Même si ce n'est pas explicite dans ce RFC, le recouvrement des fragments était autorisé, ce qui complique sérieusement le réassemblage et pouvait permettre d'échapper à certains IDS. Il n'est donc pas étonnant que le RFC 5722 ait finalement interdit ces fragments recouvrants. Bon, et les fragments atomiques, ils sont fabriqués pourquoi ? La section 5 du RFC 2460 ne laisse pas le choix aux mises en œuvre d'IPv6 : normalement, elles doivent fabriquer un fragment atomique (un paquet qui a l'en-tête de fragmentation, sans pour autant être fragmenté) si la taille indiquée par le paquet ICMP est inférieure aux 1280 octets minimaux d'IPv6 (c'est pour aider certains mécanismes de traduction IPv4<->IPv6). Dans un fragment atomique, le décalage (fragment offset) sera de zéro (puisque ce fragment est le premier) et le bit M sera à Zéro (puisque ce fragment est le dernier du datagramme). Comme ces paquets ICMP Packet too big ne sont pas authentifiés, même quand c'est possible (section 5.3 du RFC 4443 et RFC 5927), un attaquant peut donc faire fabriquer des fragments atomiques assez facilement.
Ensuite, comme bien des systèmes traitent ces fragments atomiques en même temps que les fragments normaux, ils peuvent, par exemple, être fusionnés avec d'autres fragments prétendant venir de la même source.
Les problèmes de sécurité liés aux fragments sont bien connus : voir notamment le RFC 5722 mais aussi le RFC 6274 qui décrit ces attaques pour IPv4 (beaucoup sont communes aux deux versions). Ce problème est encore aggravé par le fait que certains systèmes génèrent des identificateurs de fragment trop prévisibles, permettant à l'attaquant de savoir où il devra frapper.
La section 4 décrit ensuite les nouvelles règles, visant à résoudre ce problème. En deux mots, en recevant un fragment atomique (que l'on reconnait à la combinaison décalage=0 et bit M =0), on doit le traiter différemment des autres fragments et il ne peut être réassemblé qu'à partir du fragment unique.
L'annexe A contient un tableau listant un certain nombre de systèmes d'exploitation actuels en indiquant s'ils génèrent des fragments atomiques, et s'ils mettent en œuvre ce RFC (les traitent différemment des autres fragments). La plupart des systèmes génèrent ces fragments atomiques lorsqu'ils reçoivent le faux paquet ICMP Too big (une exception est NetBSD). Et plusieurs d'entre eux (Linux récent, NetBSD, OpenBSD) suivent déjà la recommandation de ce RFC et ne sont donc normalement pas vulnérables aux attaques décrites ici.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : D. Thaler (Microsoft)
Pour information
Première rédaction de cet article le 10 Mai 2013
Utiliser des identificateurs (noms
de domaine, URI, noms
d'utilisateur, adresses de courrier, etc) comme
clés d'accès à des informations de sécurité est courant. Par exemple,
on autorise machin@truc.example et lui seul à
accéder à certains contenus. Cela implique une
comparaison entre l'identificateur présenté et
ceux stockés dans une base. En apparence, rien de plus simple que de
comparer deux chaînes de caractères. En réalité, il existe plein de
pièges, que documente ce RFC de
l'IAB. Si tout le monde n'utilise pas
exactement le même algorithme de comparaison (et certains sont mal
spécifiés ou mal connus et permettent donc des variations), alors on
peut avoir aussi bien des dénis de service (utilisateur légitime
refusé) que des augmentations de privilèges (utilisateur illégitime
accepté).
L'informaticien naïf peut croire que comparer deux identificateurs, c'est simplement faire une comparaison bit à bit de leur représentation mais non, c'est plus compliqué que cela.
Pour comprendre le problème, la section 1 du RFC commence par parler du cycle de vie d'un identificateur. Il est d'abord généré, par exemple par une autorité centrale. Il est ensuite souvent stocké en deux endroits, chez l'utilisateur qui va s'en servir et dans une base des identificateurs enregistrés. Par exemple, si c'est une autorité centrale qui a fabriqué l'identificateur, elle le met dans sa base de données (cas, par exemple, d'un registre de noms de domaine). Naturellement, il y a des tas de possibilités différentes. Par exemple, un identificateur peut être une clé publique cryptographique, générée localement et stockée de même.
L'identificateur est ensuite distribué à ceux et celles qui en auront besoin. Cela peut se faire par des moyens numériques mais aussi par des moyens traditionnels comme une carte de visite ou une communication téléphonique. Pensez à un URL que l'on utilise dans des publicités, dans l'espoir que des gens tapent ensuite cet URL dans la barre d'adresse de leur navigateur. Ce passage par des moyens de communication non numériques est une des sources de problèmes car taper correctement un identificateur lu en vitesse sur le flanc d'un autobus n'est pas trivial.
Enfin, quelqu'un va utiliser cet identificateur. Par exemple, il va
essayer d'envoyer un message à
barack@whitehouse.gov et espère que cela
atteindra la boîte aux lettres de quelqu'un de l'équipe du
Président. Ou bien un utilisateur va récupérer un identificateur et
essayer de le comparer avec celui qu'il connait. C'est le cas d'un
navigateur Web voulant valider un certificat
X.509 (RFC 6125).
À noter qu'il existe plein d'autres complications possibles. Par
exemple, une entité peut être désignée par plusieurs identificateurs
(ce RFC est à la fois http://www.ietf.org/rfc/rfc6943.txt et
http://www.rfc-editor.org/rfc/rfc6943.txt, un être humain
peut être référencé par son numéro de passeport ou bien par son
numéro de Sécu). Notre RFC ne se préoccupe pas
de ce cas, se limitant à celui, déjà assez difficile, de la
comparaison de deux identificateurs pour voir s'ils sont identiques.
Cela peut se faire de trois façons (section 1.1, et voir aussi le RFC 6885 qui avait introduit ces trois cas) :
2001:db8:1::1317 dans une
ACL, il n'y a aucune ambiguité pour déterminer
si l'adresse présentée est égale ou non à celle-ci. (Attention, ce
n'est vrai que pour la forme binaire des adresses IP, pas pour leur
représentation textuelle.)Une technique courante pour faciliter les comparaisons des identificateurs définis est la canonicalisation. On réduit d'abord l'identificateur à une forme canonique et on fait ensuite une comparaison absolue (bit à bit). Pour des noms de domaines, on peut par exemple toujours les passer en minuscules avant de comparer. Dans le cas d'identificateurs Unicode, c'est évidemment plus complexe mais il existe plusieurs algorithmes de canonicalisation Unicode. L'important est que toutes les parties impliquées utilisent le même.
On peut bien sûr comparer sans canonicaliser mais avoir une forme canonique est tellement pratique (par exemple pour l'affichage) que cela vaut toujours la peine d'en définir une. Ce faisant, on définit aussi un algorithme de comparaison.
La section 2 cite des exemples d'utilisation d'identificateurs dans
des contextes de sécurité. Par exemple, trouver une clé en échange
d'un nom (a principal, dit-on en sécurité),
chercher dans une ACL si une entité est
autorisée, compter l'activité d'une entité donnée (et il faut donc
ajouter son activité dans la bonne ligne du tableau). Le point
important est qu'il faut que tout le monde utilise le même
algorithme. Si on stocke l'activité d'adresses de courrier
électronique sans les canonicaliser, et que quelqu'un change son
adresse de jean@durand.example à
jean@Durand.EXAMPLE (pourtant la même adresse),
il pourra apparaître comme vierge, comme n'ayant pas d'activité
précédente.
Les cas réels peuvent être très compliqués. Par exemple, en HTTPS, on compare ce qu'a tapé un utilisateur dans la barre d'adresses du navigateur avec ce que contient le certificat (RFC 6125). Plusieurs protocoles différents sont en jeu (de la définition des URL à celle de X.509) et plusieurs acteurs (des utilisateurs qui tapent plus ou moins bien, sur des systèmes très variés, et tout le monde des AC), chacun de ces acteurs pouvant avoir ses propres règles.
En cas d'algorithmes différents utilisés par des parties
différentes, on peut avoir aussi bien des faux
positifs que des faux négatifs. Les
faux positifs, c'est quand deux identificateurs sont considérés comme
identiques alors qu'ils ne devraient pas. (Je me souviens d'un vieux
système Unix où le nom de
login était silencieusement tronqué à huit
caractères, donc bortzmeyer et
bortzmeye étaient considérés identiques.) Si les
privilèges sont attribués en fonction de cette égalité, on a un gain
en privilèges. Si, par contre, les privilèges sont refusés en fonction
de cette égalité (cas d'une liste noire), on a
un refus d'un service légitime. Le faux négatif, c'est le contraire :
deux identificateurs considérés comme différents alors qu'ils sont
équivalents (cas de jean@durand.example et
jean@Durand.EXAMPLE plus haut, si on oublie que
le nom de domaine est insensible à la casse). Les conséquences sont
opposées : si les
privilèges sont attribués en fonction de cette égalité, on a un refus
de service. Si, par contre, les privilèges sont refusés en fonction
de cette égalité, on a un gain de privilèges, à tort.
Évidemment, le gain de privilèges est plus grave que le refus de service et c'est pour cela qu'on trouve, par exemple, dans la section 6.1 du RFC 3986 « comparison methods are designed to minimize false negatives while strictly avoiding false positives ». (Cet exemple suppose que les privilèges sont accordés en fonction de l'égalité et que les faux positifs sont bien plus graves.)
Le RFC donne un exemple où les identificateurs sont des
URI. La société Foo paie
example.com pour accéder à un service nommé
Stuff. Alice, employée de Foo, a un compte identifié par
http://example.com/Stuff/FooCorp/alice. En
comparant des URI, Foo tient compte du fragment (la partie après le
#, section 3.5 du RFC 3986) ce qu'example.com ne fait pas. Et
Foo permet les # dans les noms de compte. Un autre employé de Foo, le
malhonnête Chuck, se fait créer un compte avec l'identificateur
http://example.com/Stuff/FooCorp/alice#stuff. Foo
ne voit pas le problème puisque cet identificateur n'existe pas. Chuck
va donc pouvoir obtenir des autorisations d'accès de Foo. IL
peut ensuite se connecter auprès d'example.com
comme étant
http://example.com/Stuff/FooCorp/alice,
l'identificateur d'Alice. Certes, l'autorisation de Chuck n'était
valable que pour
http://example.com/Stuff/FooCorp/alice#stuff mais
rappelez-vous qu'example.com compare les URI en
ignorant les fragments... Voici un cas où les différences entre les
mécanismes de comparaison d'identificateurs ont permis un
accroissement illégitime de privilèges.
Après cet exemple, la section 3 fait le tour des identificateurs
les plus courants et de leurs pièges spécifiques. D'abord, les noms de
machines. Ce sont normalement un sous-ensemble des noms de domaines (RFC 6055) mais notre RFC utilise ce terme
dans un sens plus large, pour parler de tous les fois où un
identificateur ou composant d'identificateur est appelé Host. Ils sont souvent utilisés comme
identificateurs, soit directement (par exemple dans le RFC 5280), soit indirectement, comme partie d'un identificateur (le RFC cite
l'exemple des URI et des adresses de courrier). Le RFC note bien que
ce terme de nom de machine (hostname) est
ambigu. Ainsi, dans tyrion.lannister.got, le nom
de machine est-il tyrion ou bien
tyrion.lannister.got (section 3.1 du RFC 1034) ? Cela peut entraîner des
problèmes lorsqu'on veut décider si la machine
tyrion a accès aux privilèges de la machine
tyrion.lannister.got...
Dans le sens large qu'il a ici « nom de machine » peut aussi être
une adresse IP littérale. Cela entraîne
d'autres confusions possibles. Par exemple, si le
TLD .42 existe et qu'un
nom 103.2.1.42 est enregistré, comment le
distinguer de l'adresse IPv4
103.2.1.42 ? Normalement, la section 2.1 du RFC 1123 règle la question : on doit tester l'adresse
IP d'abord et 103.2.1.42 n'est donc jamais un
nom. Mais il n'est pas sûr que tous les programmes appliquent le RFC 1123... Certaines personnes pensent donc qu'il y
a un risque à accepter des TLD numériques, même si le RFC 1123 est clair.
Autre source d'ambiguité : la norme POSIX
1003.1 de l'IEEE admet pour une adresse IPv4
plusieurs formes, pas seulement la forme classique en quatre
composants séparés par des points. Ainsi, 10.0.258,
0xA000201 et 012.0x102 sont
des représentations légales de la même adresse, 10.0.1.2. Certaines normes se
tirent d'affaire en imposant la forme stricte, celle avec les quatre
composants décimaux séparés par des points. C'est le cas des URI, par
exemple (« an IPv4 address in dotted-
decimal form »). Mëme chose avec
inet_pton qui n'accepte que la forme
stricte. Si les différentes formes sont acceptées, on peut avoir un
problème d'ambiguité.
Et avec IPv6 ? Il y a également plusieurs
représentations texte possibles (mais, à mon avis, moins susceptibles
de poser des problèmes en pratique), par exemple
2001:db8::1 et
2001:DB8:0:0:0:0:0:1 pour la même adresse, sans
compter des cas plus tordus comme les identificateurs de zone dans les
URL (RFC 6874). Contrairement à IPv4, il existe
une représentation canonique, normalisée dans le RFC 5952 mais elle n'est pas forcément utilisée par tous.
L'internationalisation (RFC 2277) ajoute
évidemment quelques questions. Par exemple, la section 3.2.2 du RFC 3986 autorise un nom de domaine
Unicode à être écrit en encodage pour-cent
ou en punycode (le second
étant recommandé mais pas imposé). Comment
comparer caf%C3%A9.fr et
xn--caf-dma.fr ? Comme souvent en matière
d'internationalisation (qui n'a jamais été complètement acceptée par
certains), le RFC pinaille même plus loin en imaginant le cas
(purement hypothétique) d'un registre qui accepterait l'enregistrement
de noms commençant par xn--, entrainant ainsi une
confusion avec des IDN.
Autre façon de comparer des noms : les résoudre en adresses IP et comparer les adresses. C'est ce que fait la bibliothèque standard Java par défaut (classe URL). Cette méthode a évidemment toujours été dangereuse, mais c'est encore pire maintenant, avec les adresses IP privées, les trucs du DNS pour avoir une réponse dépendant de la source, les mobiles, etc. Elle était conçue pour lutter contre des failles de sécurité comme le changement DNS mais le jeu en vaut-il la chandelle ? Sans compter qu'il est contestable d'attendre le DNS juste pour comparer deux identificateurs.
Après les noms de machines, les ports. L'URL
http://www.example.com:443/ est-il égal à
http://www.example.com:https,
https ayant été enregistré (RFC 6335) comme équivalent de 443 ? (Cet exemple est facile : la
seconde forme est illégale dans un URL HTTP. Mais, dans d'autres cas,
cela peut être ambigu.)
On a souvent vu les URI dans les deux sections précédentes, consacrées aux noms de machines et aux ports. Le principal problème de la comparaison d'URI est qu'un URI est formé de plusieurs composants, chacun suivant des règles de comparaison différentes. Second problème, il existe plusieurs mécanismes standard de comparaison d'URI (RFC 3986, section 6.2, qui décrit l'échelle des comparaisons, de la plus simple à la plus complète). Le but de cette variété est de permettre aux diverses applications des URI d'optimiser pour les performances ou pour la sécurité. L'inconvénient est que deux comparateurs d'URI peuvent donner des résultats différents sans même qu'on puisse accuser l'un d'eux d'être bogué ou non standard.
Certains composants de l'URI posent des problèmes particuliers :
les plans définissent la syntaxe spécifique d'un type d'URI et il ne
faut donc jamais essayer de comparer deux URI de plans différents
(http et ftp par exemple,
même si, dans ce cas, la syntaxe est la même).
Un autre cas souvent oublié dans les URI est la partie nommée
userinfo avant le @, par
exemple dans
ftp://alice:bob@example.com/bar. Doit-elle être
considérée significative en comparant des URI ? Le RFC ne fournit pas
de règles à ce sujet.
Le chemin après le nom de machine pose un autre problème, celui des
caractères . et
.. qui, normalement, indiquent un chemin relatif.
Mais la section 5.2.4 du RFC 3986 fournit un
algorithme pour les retirer, transformant
http://example.com/a/b/c/./../../g en
http://example.com/a/g. Un nouveau piège pour la
comparaison ?
Continuons vers la fin de l'URI. Après le ?
il y a une requête. Doit-elle être prise en compte dans la
comparaison ? Là encore, pas de réponse simple, c'est à l'application
de décider si
http://www.example.org/foo/bar?ref=323 est
identique à http://www.example.org/foo/bar. Un
exemple où cette question se pose est celle d'un site de référencement
d'URI, avec les nombreux cas où la requête ne stocke en fait qu'une
variable de suivi de la circulation de l'URI (lu sur
Twitter, lu sur
Facebook, etc).
Reste le fragment, la dernière partie d'un URI, après le #. En général, lorsqu'on utilise un URI comme identificateur dans un contexte de sécurité, on ignore le fragment (voir l'exemple plus haut avec Chuck et Alice...) Mais ce n'est pas une règle qui marche dans tous les cas. Là encore, l'important est la cohérence : que toutes les applications qui gèrent cet URI fassent pareil.
Comme pour les noms de machine, dans l'exemple Java plus haut, on pourrait se dire qu'une façon simple de comparer deux URI est de les déréférencer et de voir s'ils pointent vers des contenus identiques. Mais tous les URI ne sont pas déréférençables, on n'a pas forcément envie d'imposer une connexion Internet en état de marche juste pour comparer deux identificateurs et, de toute façon, un tel algorithme serait très fragile (que faire si on trouve le même document XML mais avec des encodages différents ?) En outre, toute démarche active comme celle-ci est dangereuse pour la vie privée (elle informe les gérants des serveurs Web de ce que l'on est en train de faire, comme le font les Web bugs).
Après les URI, place à une catégorie d'identificateurs très souvent
utilisés pour identifier une entité, les adresses de courrier (RFC 5322 pour leur syntaxe, et RFC 6532 pour le cas où elles sont internationalisées). Une
adresse de courrier, comme un URI, a plusieurs parties, qui suivent
des règles différentes pour la comparaison. La partie à droite du
@ est un nom de domaine et ce cas a été traité
plus haut. La partie gauche, dite partie locale, est un identificateur
indéfini : ses règles ne sont pas connues à l'extérieur et on ne peut
donc pas savoir, par exemple, si rms@gnu.org et
RMS@gnu.org sont le même utilisateur, ou si
stephane+ps@bortzmeyer.org est le même que
stephane+ump@bortzmeyer.org. Dans le cas où des
adresses de courrier sont utilisées dans un certificat, on choisit
souvent une comparaison bit à bit... qui peut donner plein de faux négatifs.
Après cette liste à la Prévert de problèmes,
la section 4 de notre RFC tente une synthèse. Elle identifie quatre
problèmes. Le premier est la confusion. Un
identificateur est utilisé sans que son type soit clair. Par exemple,
si je tape telnet 1000, est-ce l'adresse
IPv4 0.0.3.232 ou bien
l'adresse IPv6 ::3:e8 ?
Et si je tape ping 10.1.2.42, est-ce que
10.1.2.42 est un nom ou une adresse (le TLD
.42 peut exister) ?
Résoudre la confusion nécessite un algorithme clair. Dans le
premier exemple ci-dessus, il n'y a pas de
confusion. 100 ne peut pas être une adresse IPv6
légale (la présence ou l'absence d'un : suffit à
les reconnaître). Le second exemple est normalement clair : l'adresse
IP a priorité donc 10.1.2.42 ne peut pas être un
nom même si le TLD .42 existe. Si cette règle de
précédence est respectée par les implémentations, il n'y aura pas de
problèmes (identificateurs définis). Mon avis personnel est que ce RFC
pinaille quand même très fort sur ce point, en s'interrogeant
gravement sur des problèmes théoriquement intéressants mais extrêmement
tordus et donc rares en pratique.
Deuxième problème, l'internationalisation. Un logiciel n'a aucun
problème à comparer google.com et
goog1e.com et à dire qu'ils sont
différents. C'est plus difficile pour un humain (vous aviez repéré le
L qui était en fait un 1 ?) Toutes les fois où un humain est impliqué,
dans la saisie ou la reconnaissance d'un identificateur, ce genre d'erreur peut se produire. Comme le montre cet exemple, cela n'a
d'ailleurs rien de spécifique aux chaînes de caractères Unicode. Mais
ce problème est souvent cité comme argument contre
l'internationalisation. Bref, le point important : la sécurité ne
devrait pas dépendre d'une vérification visuelle faite par un
humain. (Cf. l'article
de Weber et le RFC 6885.)
Problème suivant, la portée. Certains
identificateurs ne sont pas uniques au niveau
mondial. localhost est un bon exemple. C'est
également le cas des adresses du RFC 1918. On
peut aussi citer l'adresse de courrier alice qui,
utilisée depuis une machine d'example.com
arrivera à une Alice et, depuis une machine d'un autre domaine, à une
autre. Dans ce dernier cas, la bonne solution est de toujours utiliser
une adresse unique (par exemple
alice@example.com) même dans un contexte local :
l'expérience prouve que les identificateurs fuient souvent d'un
domaine local vers un autre.
Enfin, dernier problème identifié par cette section 4, la
durée. Certains identificateurs ne sont pas
éternels et peuvent disparaître, ou désigner une autre entité. Par
exemple, bob@example.com peut désigner un Bob
aujourd'hui et, s'il quitte l'entreprise et qu'un autre est embauché,
un Bob complètement différent dans quelques mois. C'est la même chose
pour les adresses IP et des tas d'utilisateurs ont déjà souffert de se
voir attribuer une adresse IP qui avait une mauvaise réputation.
La section 5 résume les conseils les plus importants : se méfier des identifcateurs indéfinis, prévoir une comparaison absolue ou définie pour tous les identificateurs futurs, penser aux mécanismes pour valider les identificateurs (RFC 3696). Le gros risque restera toujours le cas où plus d'un protocole utilise un identificateur donné, car les différents protocoles n'auront pas forcément les mêmes règles de comparaison des identificateurs.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : J. Levine (Taughannock Networks), P. Hoffman (VPN Consortium)
Pour information
Première rédaction de cet article le 7 Mai 2013
Il y a beaucoup d'utilisateurs des noms de domaine qui pensent que deux noms qui,
pour eux, sont « le même », devraient être traitées d'un bloc par le
DNS et/ou par les systèmes d'enregistrement de
noms. Tout le problème est évidemment de définir « le même » : il n'y
a en général pas d'accord entre les utilisateurs sur ce point. Ainsi,
des anglophones peuvent penser que
meter.example et
metre.example sont « le même nom » et devraient
donc se comporter ainsi. D'autres pensent que
pizzeria-napoli.example et
pizzerianapoli.example sont « le même nom ». Et,
évidemment, depuis l'arrivée des IDN, le
potentiel pour des noms « identiques » a encore augmenté. Il a donc
été proposé que ces variantes d'un « même » nom
soient explicitement reconnues. Ce RFC ne
suggère pas de mécanisme en ce genre (je pense personnellement que le
problème est bien trop flou et subjectif pour cela). Il se contente de
regarder les pratiques actuellement déployées par les
registres en matière de « variantes ».
Des exemples de caractères qui sont une « variante » d'un autre ne
manquent pas dans les écritures du monde. Ainsi, la
Chine a connu sous Mao
une réforme orthographique, passant des
sinogrammes
« traditionnels » aux
« simplifiés ». La plupart des sinophones
considèrent que 雲 et 云
sont des variantes du même mot. Dans les langues utilisant
l'alphabet latin avec des
accents, certains considèrent que le mot avec
et sans accent sont des variantes l'un de l'autre. Le RFC note qu'en
français certains omettent les accents sur les majuscules (c'est
incorrect, mais cela se fait parfois) et que donc
INTERNÉ et INTERNE sont
considérés comme « équivalents ». Ce qui est sûr, c'est
qu'historiquement, les difficultés à manier les caractères
non-ASCII dans beaucoup d'environnements
informatiques avaient mené bien des utilisateurs à considérer les
accents comme purement décoratifs, et pouvant être omis.
Est-ce que ce vague sentiment que deux groupes de caractères sont
« la même chose » peut être formalisé dans une définition rigoureuse
des « variantes » ? Il y a eu quelques tentatives comme à
l'ICANN, ou à l'IETF dans le RFC 3743 (non standard). Mais un autre
document de la même ICANN concluait
qu'il n'existait pas de définition utilisable. Ensuite, sur le
comportement attendu de deux noms identiques ne fait pas non plus
l'objet d'un consensus. Par exemple, si on veut, non pas seulement une
réponse identique dans le DNS, mais un vécu de
l'utilisateur identique, par exemple sur le
Web, il n'y a aucune solution purement DNS (en
raison du comportement de HTTP avec le champ
Host:). Si vous voulez lire davantage sur cette
question, je vous renvoie à mon article « Que veut dire synchroniser deux
domaines ? ».
Ce RFC n'essaie donc pas de régler ce problème (très ancien et sans doute insoluble). Il fait un tour d'horizon des pratiques des gTLD (qui sont contractuellement obligés par l'ICANN de rédiger leurs pratiques IDN et de les déposer à l'ICANN, et qui rendent accessibles le contenu de leurs zones, permettant aux chercheurs de l'étudier) et d'un certain nombre de ccTLD. Ces obligations de l'ICANN sont décrites dans « Guidelines for the Implementation of Internationalized Domain Names ». Le RFC note que ces règles ne sont guère respectées, les politiques déposées à l'ICANN étant souvent dépassées et plus à jour (URL cassés, personnes désormais parties, etc). (Mon opinion personnelle est que ces « IDN Guidelines » n'ont aucun sens et sont motivées par des frayeurs bureaucratiques plutôt que par des considérations pratiques.)
Pensez à réviser la terminologie en section 2. Un lot (bundle, on dit aussi IDL package) est un ensemble de noms qui sont tous des variantes les uns des autres (RFC 3743). Un nom est alloué (allocated) ou enregistré s'il est attribué à un titulaire. Il est actif (active) s'il apparait dans le DNS. Il est bloqué (blocked) s'il ne peut pas être alloué du tout et réservé (witheld) s'il ne peut être alloué que dans certaines conditions.
La section 4 décrit les politiques des gTLD (avec vérification dans
les fichiers de zone de la réalité de ces politiques). Certains sont
faciles : .aero,
.coop ou .pro n'ont pas
d'IDN (même chose pour .xxx). D'autres ont un grand intérêt pour les IDN. Ainsi,
.asia a évidemment une
politique
IDN détaillée, avec gestion de lots, via les enregistrements
NS (les variantes ont le même jeu de
NS). .cat a un cas plus
simple que .asia puisqu'il ne reconnait qu'une
seule langue, le catalan. La liste des
caractères autorisés est
publiée et elle comprend des caractères comme le l·l
(considéré comme un caractère en catalan mais représenté par trois
caractères Unicode). Lorsqu'on enregistre un nom IDN, l'ASCII
« équivalent » est aussi enregistré et un DNAME
(RFC 6672) est mis dans le fichier de
zones (il semble que cela soit le seul gTLD à procéder ainsi). Par
exemple :
xn--caball-gva.cat. 43200 IN DNAME caballe.cat.
Le nom IDN caballé.cat pointant vers
l'ASCII caballe.cat (et merci à DNSDB pour permettre l'exploration facile du DNS
à la recherche d'exemples).
Contrairement à .asia et a fortiori à
.cat,
.com doit gérer toutes les
écritures du monde. VeriSign a transmis à
l'ICANN des tables pour des écritures
hiéroglyphiques et pour
l'araméen... Les politiques suivies sont
décrites en détail dans plusieurs documents (voir la liste dans la
bibliographie du RFC). Pour l'écriture
chinoise, et pour elle seule, les variantes d'un nom
alloué sont
bloquées. (.net et
.name suivent la même
politique que .com.)
.org publie une liste des langues gérées (notez que
c'est absurde puisque IDN gère des écritures, pas des langues, mais
cette confusion est fréquente dans les cercles ICANN, où il est
toujours mal admis que des gens osent utiliser d'autres écritures que
celle des États-Unis). Les tables déposées à l'ICANN sont un
sous-ensemble de ces tables publiées par le registre (pas de mise à
jour ?) Les documentations officielles de .org font allusion à une politique
de gestion des variantes mais apparemment sans dire en quoi consiste
cette politique.
.tel a beaucoup d'IDN
et une politique
publique. Les noms avec l'écriture
japonaise utilisent un système de blocage (le premier
arrivé empêche l'allocation des variantes) alors que pour l'écriture
chinoise, les variantes sont publiées (avec des enregistrements NS identiques).
La section 5 passe aux ccTLD. Je ne vais pas tous les citer mais
ils ont souvent des politiques
intéressantes. .cl publie sa
politique, qui ne tient pas compte d'éventuelles variantes.
.cn a évidemment plus
de travail : leur politique est publiée sous forme d'un
RFC, le RFC 4713. Les
variantes sont publiées, avec des enregistrements NS. Par contre,
.ir n'a pas d'IDN. Comme
un certain nombre de registres des pays utilisant
l'écriture arabe (qui va de droite à gauche),
ils considèrent que le mélange d'un nom en écriture arabe avec un
TLD en écriture latine (allant de gauche à droite) n'est pas
souhaitable. (Mais il y a des IDN dans le TLD équivalent en écriture arabe, ایران.)
Bien que TLD d'un pays majoritairement anglophone,
.nz a une politique IDN (qui ne
parle pas des variantes) pour le maori. On
notera que le domaine compte des DNAME par exemple
māori.dns.net.nz qui pointe vers l'équivalent
ASCII :
xn--mori-qsa.dns.net.nz. 86400 IN DNAME maori.dns.net.nz.
Contrairement aux autres ccTLD, il semble que
.ru ne publie pas sa
politique directement, uniquement via la table déposée à l'ICANN.
La politique utilisée par
.fr n'est pas étudiée dans
ce RFC. Elle est disponible
en ligne.
La liste des caractères acceptés figure en section 2 (ce sont les
caractères utilisés pour les langues d'Europe de l'Ouest). S'il y a eu
un système de variantes pendant la période d'ouverture (section 4), il
a ensuite disparu.
Voilà, si vous voulez approfondir la question et voir la politique des autres TLD, consulter ce RFC. J'espère en tout cas avoir donné une bonne idée de la variété des écritures du monde et des solutions pour les gérer dans les noms de domaine.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Rose (NIST)
Réalisé dans le cadre du groupe de travail IETF dnsext
Première rédaction de cet article le 2 Mai 2013
Mais quel algorithme de cryptographie choisir pour mes signatures DNSSEC, se demande l'ingénieur système ? Il y a bien un registre IANA des algorithmes normalisés mais c'est juste une liste non qualifiée, qui mêle des algorithmes de caractéristiques très différentes. Ce nouveau RFC vise à répondre à cette question en disant quels sont les algorithmes recommandés.
La première liste d'algorithmes possibles avait été faite dans le RFC 4034. D'autres algorithmes avaient été ajoutés par la suite. Certains sont devenus populaires. Par exemple, RSA avec SHA-2 est utilisé pour presque tous les TLD importants et est donc difficilement contournable pour un résolveur validant. D'autres ont été peu à peu abandonnés, parfois parce que les progrès de la cryptanalyse les menaçaient trop, parfois simplement parce qu'ils n'avaient pas un bon marketing.
Aujourd'hui, le développeur qui écrit ou modifie un logiciel résolveur validant (comme Unbound ou BIND) doit donc se taper pas mal de RFC mais aussi pas mal de sagesse collective distillée dans plusieurs listes de diffusion pour se faire une bonne idée des algorithmes que son logiciel devrait gérer et de ceux qu'il peut laisser tomber sans trop gêner ses utilisateurs.
Ce RFC 6944 détermine pour chaque algorithme s'il est indispensable (on n'a pas le droit de faire l'impasse), recommandé (ce serait vraiment bien de l'avoir, sauf raison contraire impérieuse), facultatif (si vous n'avez rien d'autre à faire de vos soirées que de programmer) ou tout simplement à éviter (pour le cas de faiblesses cryptographiques graves et avérées). La liste se trouve dans la section 2.3 : RSA avec SHA-1 est le seul indispensable. RSA avec SHA-1 plus NSEC3 (voir plus loin l'explication de ce cas particulier), RSA SHA-256 ou SHA-512 (connus collectivement comme SHA-2), ECDSA avec SHA-256 ou SHA-384 sont recommandés. Tous les autres sont facultatifs (c'est par exemple le cas de GOST dans le RFC 5933) sauf RSA avec MD5 qui est à éviter (RFC 6151).
La section 2.2 justifie ces choix : RSA+SHA-1 est l'algorithme de référence, celui qui assure l'interopérabilité (tout logiciel compatible DNSSEC doit le mettre en œuvre). Normalisé pour DNSSEC avant l'apparition de NSEC3 dans le RFC 5155, il existe en deux variantes, une sans NSEC3 (celle qui est indispensable) et une avec (qui est recommandée car la plupart des TLD utilisent NSEC3). RSA+SHA-2 est recommandé car, comme indiqué plus haut, la racine et la plupart des TLD l'utilisent. Un résolveur qui ne comprendrait pas ces algorithmes ne servirait pas à grand'chose.
Au contraire, ECDSA est très peu utilisé en pratique. Mais les courbes elliptiques suscitent beaucoup d'intérêt, et sont une alternative au cas où il y aurait un gros problème avec RSA. D'où le statut « Recommandé ».
Des nouveaux algorithmes vont certainement apparaître dans le registre (cf. RFC 6014). Ils seront automatiquement considérés comme facultatifs, jusqu'à la sortie d'un nouveau RFC qui remplacerait ce RFC 6944.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Alan DeKok (Network RADIUS), Avi Lior
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 1 Mai 2013
RADIUS, un protocole utilisé pour l'authentification (et la configuration) d'accès à l'Internet, est ancien et marche toujours. Lorsque vous accédez à l'Internet depuis chez vous, sans vous en rendre compte, vous avez probablement indirectement utilisé RADIUS. Il marche toujours très bien mais, rançon du succès, il a été tellement étendu qu'un certain nombre de champs du message RADIUS sont désormais pleins : toutes les options possibles seront allouées très bientôt. Ce nouveau RFC décrit un mécanisme d'extension de RADIUS, permettant de continuer l'enregistrement de nouvelles options, au prix de quelques bricolages.
Il y a peu de gens qui manipulent RADIUS (RFC 2865) explicitement. Ce protocole se trouve en effet caché dans le réseau du FAI, entre la machine qui contrôle l'accès (le NAS) et un serveur RADIUS qui contient les données sur les utilisateurs. RADIUS permet de ne pas avoir à copier les informations d'authentification, ou les paramètres d'un utilisateur donné, directement dans tous les NAS, mais de les centraliser dans un petit nombre de serveurs RADIUS.
La requête, et surtout la réponse RADIUS peuvent contenir un
certain nombre d'attributs (RFC 2865, section 5) comme « nom de l'utilisateur », « mot de
passe », « adresse IP à attribuer », etc. Le champ
« Attribute » est en TLV et
le type (User-Name = 1,
User-Password = 2,
Framed-IP-Address = 8, etc) est encodé sur un
seul octet. La liste (un registre
IANA) est aujourd'hui bien remplie et devrait l'être
complètement en 2014 ou
2015. C'est le principal problème de RADIUS
aujourd'hui (section 1 de notre RFC). Mais il y en a d'autres comme le
fait que la longueur d'un attribut soit codé sur un octet seulement
(donc 253 octets maximum pour la valeur d'un attribut, puisqu'il faut
retirer le type et la longueur).
Notre RFC fait donc les changements suivants :
Voilà, c'est l'essentiel du RFC. Ceux qui étendent le protocole RADIUS vont sans doute migrer vers les nouveaux types, dès aujourd'hui, ou bien lorsque les anciens seront épuisés.
Des exemples d'encodage figurent en section 9. Par exemple, un
attribut utilisant un type étendu (ici, 241.1) et ayant une valeur de type texte
(la chaîne "bob") se représentera f1 06 01 62 6f
62 (f1, le type, 241,
06 la longueur totale, 01 le
sous-type du type étendu, 1 (à la place du premier octet de la
valeur), 62 6f 62 la vraie valeur, la chaîne
de caractères). Plus compliqué, un attribut 241.2 contenant un TLV
dont le type est 1, la longueur 4 et la valeur 23
45, sera représenté f1 07 02 01 04 23
45.
Avec les étendus longs (Long Extended
Type), un attribut 245.1 contenant le même "bob" sera
f5 07 01 00 62 6f 62 (f5 est
le type, la longueur est de sept octets, 01 est
la suite du type, l'octet supplémentaire est à 0 (donc le bit M
aussi : pas d'autres attributs à attendre) et la valeur est la chaîne
"bob" (62 6f 62 en
ASCII). Si un type 245.4 encode plus de 251
octets (ici, 260 octets de valeur), on
aura le premier attribut qui commencera par f5 ff 04
80 (longueur totale à 256 octets, l'octet supplémentaire vaut 80, indiquant que le bit M
est à Un) et un deuxième attribut qui commencera par f5 13
04 00 (octet supplémenaire à 0 donc bit M à Zéro, ce second
attribut est le dernier). La longueur totale est ff +
13 soit 260 octets pour la valeur.
Si vous voulez tester vous-même ces nouveaux types et leur encodage, l'annexe A du RFC contient un programme en C qui permet exactement cela (copie locale du source). Il s'utilise ainsi :
% echo '241.1 "bob"' | ./radius-attr-generator
241.1 "bob" -> f1 06 01 62 6f 62
% echo '243.2 42' | ./radius-attr-generator
243.2 42 -> f3 04 02 42
# Plus drôle, un TLV dans un TLV :
% echo '241.4 { 1 23 45 } { 3 { 1 ab cd } }' | ./radius-attr-generator
241.4 { 1 23 45 } { 3 { 1 ab cd } } -> f1 0d 04 01 04 23 45 03 06 01 04 ab cd
Parmi les autres nouveautés du RFC, il y a la formalisation de la
convention de nommage informel des attributs : mots séparés par des
tirets (par exemple Framed-MTU), attributs
spécifiques à un vendeur préfixés par le nom du vendeur (par exemple
Starbucks-Latte-Size pour un vendeur nommé
Starbucks).
Le changement apporté au protocole n'est pas trivial, mais soigneusement conçu pour maintenir la compatibilité. La section 5 du RFC note toutefois quelques problèmes potentiels. D'abord, certains vendeurs se sont approprié des numéros de types qui étaient marqués comme réservés (et qui sont désormais utilisés pour les types étendus). Comme le notait le RFC 6158, c'est un comportement anti-social. Maintenant que ces numéros réservés sont utilisés, ces attributs spécifiques au vendeur anti-social ne marcheront plus (bien fait).
Autre problème potentiel, il est fréquent que les messages RADIUS soient relayés par un serveur intermédiaire (RFC 2865, section 2.3), notamment en cas d'itinérance. Idéalement, le relais devrait ignorer les attributs qu'il ne comprennent pas. Si, par contre, il rejette les messages contenant ces attributs nouveaux, un client et un serveur conformes au nouveau format ne pourront pas communiquer à travers un tel relais. Notre RFC rappelle bien qu'un relais devrait être transparent et relayer même ce qu'il ne comprend pas.
Les sections 6.6 et 10.3 fournissent les règles d'enregistrement des nouveaux types. Il est recommandé d'y aller mollo : les nouveaux espaces sont plus grands mais pas infinis. Le registre IANA stocke désormais des attributs des nouveaux types.
Devoir ajuster a posteriori un protocole, qui avait été conçu d'une certaine manière, et qui esr assez rigide, est toujours une opération délicate, spécialement lorsqu'il faut maintenir la compatibilité avec l'existant. Des tas de propositions ont été faites depuis des années, pour étendre RADIUS. La section 7 du RFC documente pourquoi celle-ci a été choisie. D'abord, elle est relativement simple, avec peu de modifications du format. Son principal inconvénient est que le format des Long Extended Type est assez baroque.
Quant au mécanisme pour agrandir la taille possible des valeurs, il a d'abord été conçu pour ne pas changer les attributs dont la valeur restait petite. D'après une étude de 2010 (citée en section 7.1) portant sur tous les dictionnaires Radius connus, les entiers représentent près de la moitié des valeurs d'attributs RADIUS publics. En ajoutant les autres types de taille fixe (adresses IP, par exemple), on arrive à plus de la moitié. Il fallait donc éviter de faire payer ces types peu consommateurs en octets.
Plusieurs des mises en œuvre de Radius gèrent déjà ces extensions, par exemple FreeRADIUS. Il faut dire qu'il n'y a guère le choix, vue l'imminence de l'épuisement.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Perreault (Viagenie), I. Yamagata, S. Miyakawa (NTT Communications), A. Nakagawa (Japan Internet Exchange (JPIX)), H. Ashida (IS Consulting G.K.)
Réalisé dans le cadre du groupe de travail IETF behave
Première rédaction de cet article le 1 Mai 2013
Qu'on les approuve (ce qui n'est pas mon cas) ou pas, les CGN, ces gros routeurs NAT installés dans le réseau du FAI et gérant des centaines ou des milliers de clients, sont d'ores et déjà une réalité douloureuse dans de nombreux pays d'Asie, pour les pauvres utilisateurs de la 3G, et peut-être demain sur d'autres continents pour les accès fixes. Pour limiter les dégâts qu'ils causent, ce RFC 6888 pose un certain nombre de règles que devraient respecter ces CGN.
D'abord, qu'est-ce qu'un CGN ? Fonctionnellement, il ressemble au petit routeur NAT (RFC 2663) que vous avez chez vous. Comme lui, il fait du NAPT (Network Address and Port Translation), c'est-à-dire qu'il traduit dynamiquement des adresses IP du réseau interne vers celles utilisées à l'extérieur (et vice-versa pour les paquets dans l'autre sens). La grosse différence avec le petit routeur ou box chez vous est qu'il travaille pour de nombreux clients du FAI. Au lieu que l'adresse IP externe soit partagée uniquement entre les membres de votre cercle de famille, elle sera partagée avec des centaines d'inconnus.
Avec le CGN, il y a souvent « double NAT », une fois dans le CPE et une fois dans le CGN. Mais ce n'est pas obligatoire. Lorsqu'il y a double NAT, on parle souvent de NAT444 (deux traductions, d'IPv4 en IPv4).
Sur cette image, on voit du double NAT. Un FAI gère un
CGN.
Les adresses IP publiques du FAI, allouées par son
RIR sont ici
198.51.100.0/25. Ce sont celles qui seront vues,
par exemple, par les sites Web où se connectent les clients du FAI. Le
FAI n'a pas assez d'adresses IP publiques pour son réseau interne et
il utilise donc le 10.0.0.0/8 du RFC 1918. Prenons maintenant le client 1 : son réseau local a des adresses
dans la plage 192.168.3.0/24. Les paquets seront
donc émis avec ces adresses, NATés une première fois par la machine
CPE 1, vers l'adresse 10.0.5.22. Ils seront
ensuite NATés une seconde fois par le CGN.
Le CGN a des conséquences, par exemple dans le domaine légal (en théorie, vous pourrez voir les agents de la HADOPI débarquer chez vous parce qu'un autre utilisateur du même CGN a téléchargé illégalement, cf. RFC 6269). Et cela limite sérieusement les activités que vous pourrez avoir sur l'Internet. Par exemple, un moyen courant d'accepter les connexions entrantes, normalement interdites par le NAPT, est de configurer sa box pour rediriger tel numéro de port vers tel service sur le réseau local (par exemple pour faire fonctionner des applications pair-à-pair). Le routeur CGN étant partagé entre de nombreuses personnes qui ne se connaissent pas, cela n'est plus possible. Contrairement au routeur NAT à la maison, le CGN n'est pas géré par les abonnés, qui ne peuvent pas modifier sa configuration.
D'autre part, la simple taille du CGN en fait un engin compliqué et fragile, et sa panne affecte bien plus de clients que le redémarrage d'une box. Enfin, ayant moins de ports sources à sa disposition par client, par rapport au routeur de la maison ou du SOHO, il risque plus souvent de tomber à cours, si les clients font beaucoup de connexions sortantes.
Mais, alors, pourquoi met-on des CGN ? Juste pour embêter les clients ? En fait, les FAI n'ont pas forcément beaucoup le choix. La pénurie d'adresses IPv4, bien que niée par beaucoup de négationnistes, est réelle depuis de nombreuses années. Par exemple, cela fait longtemps qu'on ne peut plus avoir une adresse IP par machine à la maison. Mais, jusqu'à récemment, on pouvait encore avoir une adresse IP publique par foyer. Désormais, l'espace d'adressage IPv4 disponible se resserrant chaque jour, ce n'est même plus le cas. S'il n'y a pas d'adresse IPv4 publique disponible pour chaque client, le CGN est la seule solution pour pouvoir continuer à faire de l'IPv4 (passer à IPv6 ferait moins de travail mais les acteurs du marché sont frileux).
Cela, c'était la raison avouable pour mettre des CGN. Il y en a une moins avouable, c'est que le CGN, grosse machine centrale et point de passage obligatoire pour tous les abonnés, est bien en phase avec la mentalité des opérateurs telco traditionnels. C'est ainsi que, dans l'Internet mobile où les libertés sont bien plus limitées, et l'utilisateur bien plus restreint dans ce qu'il a le droit de faire, tous les opérateurs 3G ont déployé cette solution depuis longtemps, refusant de donner une adresse IPv4 publique à chaque abonné, même avant l'épuisement complet des réserves. Comme le note prudemment le RFC, « there are driving forces other than the shortage of IPv4 addresses ».
À noter qu'un RFC décrit le déploiement de CGN comme une des techniques pouvant aider à la transition vers IPv6 : RFC 6264. Le CGN est un des composants de la solution DS-Lite, décrite dans le RFC 6333 et ce composant doit donc suivre les règles données plus loin.
Maintenant qu'on a présenté les CGN, que contient ce RFC ? Il liste des conseils qui, s'ils étaient appliqués, rendraient les CGN un peu moins insupportables. Comme le note la section 1, la publication de ce RFC ne signifie pas que l'IETF approuve ou même accepte les CGN, simplement que, puisqu'ils existent, autant essayer de limiter leurs effets négatifs. Comme un CGN est un routeur NAT, les précédents documents du groupe de travail Behave, concernant tous les types de NAT, s'appliquent aussi au CGN : RFC 4787, RFC 5382 et RFC 5508 notamment.
Les section 3 à 5 représentent donc le cœur de ce RFC. Elles contiennent les recommandations spécifiques pour les CGN. Chacune est nommée REQ-n où n est un numéro d'ordre. Ainsi, REQ-1 dit que, pour chaque protocole de transport, le CGN doit suivre les recommandations spécifiques à ce protocole (RFC 4787 pour UDP, RFC 5382 pour TCP, RFC 5508 pour ICMP, et RFC 5597 pour DCCP). Notons que les autres protocoles de transport (comme SCTP) ont donc de sérieuses chances de ne pas fonctionner au travers du CGN.
Exigence suivante, REQ-2, qui dit que le comportement de l'IP address pooling doit être paired. Cela signifie quoi ? Qu'une machine donnée doit toujours obtenir la même adresse IP externe (un CGN, contrairement au petit routeur NAT de la maison, a en général plusieurs adresses IP externes à sa disposition). Cela limite les risques de casser les applications. Le RFC 4787, section 4.1, donne les détails sur ce concept de paired.
À propos du nombre d'adresses externes disponible pour le CGN : REQ-3 exige que ces adresses puissent être en nombre quelconque et dans des plages non-contigües (avec l'épuisement des adresses IPv4, il sera de plus en plus dur de trouver des plages contigües).
REQ-4 traite un problème spécifique aux CGN, que n'avaient pas les petits routeurs NAT de la maison : il faut pouvoir limiter le nombre de ports utilisables par un utilisateur donné. Dans le NAPT, il y a moins d'adresses externes que d'adresses internes. On se sert donc des ports pour désambigüiser. Un seul utilisateur gourmand pourrait lancer plein de sessions et épuiser à lui seul la plage de ports disponibles (cela peut même être volontaire, pour faire un déni de service, cf. section 8). C'est pour se protéger contre cette attaque que REQ-4 exige une limitation, configurable, par client. Le RFC recommande aussi qu'on puisse limiter le rythme de création de sessions par utilisateur. C'est nécessaire pour protéger les autres utilisateurs, mais c'est un bon exemple des inconvénients du CGN, qui casse sérieusement la transparence du réseau et le principe de bout en bout. Les routeurs NAT cassaient ces principes mais uniquement entre membres d'un même foyer ou d'un même SOHO. Avec le CGN, on dépend de gens dont on ne connait rien.
Même chose avec REQ-5, consacrée à d'autres ressources partagées dans le CGN, comme sa mémoire. Un CGN a des problèmes d'équité que n'ont pas les routeurs NAT classiques, vue son utilisation entre personnes qui n'ont rien en commun a priori.
Parfois, les cibles que vise l'utilisateur sont situées dans le réseau du FAI, et donc atteignables sans traduction d'adresse. Pour ce cas, REQ-6 demande que le CGN puisse être configuré pour ne pas traduire si la destination est dans une liste d'adresses configurées par l'administrateur réseaux.
Lorsqu'un routeur NAT accepte des paquets entrants du moment qu'il a, dans sa table des traductions, une entrée pour ce couple {adresse,port} de destination, indépendemment de l'adresse IP source d'émission, on dit qu'il fait du Endpoint-Independent Filtering (RFC 4787, section 5). REQ-7 souhaite que ce soit le comportement du CGN, car il casse moins d'applications (notamment jeux en ligne et pair-à-pair) que le Address-Dependent Filtering (où les paquets sont refusés si l'adresse source n'est pas celle dans l'entrée de la table).
REQ-8 légifère sur la réutilisation d'un port externe lorsqu'il n'est plus utilisé. Par défaut, il devrait rester réservé pendant deux minutes, le Maximum Segment Lifetime de TCP (RFC 793, section 3.3), après lequel on est sûr que le paquet ne traîne plus dans le réseau. Cela permet d'éviter une collision entre une ancienne correspondance et une nouvelle, qui utiliserait le même port externe et recevrait par erreur de vieux paquets. Des exceptions sont prévues, notamment :
REQ-9 est plus ambitieux car il exige quelque chose qui n'existe pas dans les CGN actuels : un mécanisme permettant à l'utilisateur de changer les affectations de port, et que ce mécanisme soit de préférence PCP (Port Control Protocol, RFC 6887). Aujourd'hui, sur les petits routeurs NAT de la maison ou du SOHO, ce mécanisme d'affectation manuelle des correspondances {adresse externe, port externe} -> {adresse interne, port interne} est typiquement fait par l'interface Web d'administration du routeur, ou bien par UPnP. La disparition d'un tel mécanisme dans les CGN actuels est un des plus gros problèmes que posent les CGN. Il était donc nécessaire de le rétablir, pour que toutes les applications puissent bien fonctionner. Mais PCP est encore très récent et peu déployé.
REQ-10 concerne plutôt les besoins de l'opérateur plus que ceux des simples utilisateurs : il demande que les routeurs CGN soient gérables (MIB du RFC 4008, etc).
Une autre exigence, REQ-11 concerne le traitement des erreurs. Si un routeur CGN ne peut pas créer une corrrespondance entre adresse+port externe et interne, il doit jeter le paquet et devrait renvoyer un message ICMP Destination unreachable / code 1 (Host unreachable). et déclencher une trap SNMP. Le « devrait » (et pas « doit ») est parce que ces deux types de messages peuvent légitimement avoir un débit limité.
Pourquoi Host unreachable et pas Communication administratively prohibited comme c'était le cas dans le RFC 5508, section 6 ? Parce que le code 1 (Host unreachable) est une erreur « douce » (cf. RFC 1122) et ne coupera pas les connexions TCP en cours entre les mêmes machines (RFC 5461).
En outre, le RFC interdit de supprimer des entrées existantes dans la table de correspondances, ce qui permettrait pourtant de faire de la place pour de nouvelles connexions. C'est parce que la plupart des applications gèrent beaucoup mieux une impossibilté à établir une connexion qu'une perturbation ou une interruption d'une connexion en cours (RFC 5508, section 6).
Un bon routeur CGN devrait pouvoir journaliser son activité. La section 4 encadre cette tâche. La principale question qui se pose est l'identification des clients, si une adresse IP externe est repérée pour son comportement abusif (envoi de spam, écriture d'un commentaire de blog défavorable aux autorités, partage de fichiers musicaux, et autres crimes). Le site distant va noter que « 192.0.2.42 a fait quelque chose de mal » et les enquêteurs vont chercher la personne qui est derrière cette adresse. En raison du CGN, des dizaines ou des centaines de personnes peuvent avoir utilisé cette adresse. Pour que l'enquêteur ait la moindre chance de retrouver le coupable, il faut que le site distant journalise, non seulement l'adresse IP source (comme c'est typiquement le cas aujourd'hui), mais aussi le port source (cf. RFC 6302). Et il faut que le routeur CGN ait journalisé ses correspondances, protocole de transport, adresse+port internes, adresse+port externes et heure exacte. (C'est une obligation légale dans certains pays, par exemple en France avec la LCEN.)
Non seulement c'est très Big Brother comme comportement mais, en plus, cela peut rapidement produire une énorme quantité de données, ce qui ne va pas faciliter la tâche de l'opérateur. C'est pour cela que REQ-12 demande que ce ne soit pas activé par défaut, à la fois pour préserver la vie privée des utilisateurs et pour éviter de remplir les disques durs. (Notez aussi que le RFC ne conseille pas de loguer l'adresse IP de destination, ce qui serait bien pire.)
Et, au fait, comment allouer aux utilisateurs cette ressource limitée, les numéros de ports externes ? La section 5 formule trois exigences. Le problème est que les trois sont contradictoires. REQ-13 dit qu'il faudrait chercher à maximiser l'utilisation des ports (ils sont en nombre limités, 65 536 par adresse IP), REQ-14 (qui a suscité beaucoup de discussions dans le groupe de travail) qu'il faudrait minimiser le nombre d'entrées produites dans le journal, par exemple en allouant toute une plage de ports par adresse IP, et REQ-15 que, pour des raisons de sécurité, il faudrait rendre difficile pour un attaquant la prédiction des ports sélectionnés (RFC 6056). Pas de miracle, ces trois exigences ne peuvent pas être satisfaites simultanément et un routeur CGN doit donc choisir lequel est le plus important pour lui. J'emprunte à Simon Perreault une description de la situation en mai 2013 : « Le CGN de Cisco allouait les ports 100 % dynamiquement, comme un NAT traditionnel, et génèrait donc beaucoup de logs. Mais ceux d'autres vendeurs, dont Alcatel, Juniper et Huawei, [ainsi que Cisco désormais, note de Nicolas Février] allouent les ports en bloc, ce qui génère beaucoup moins de logs au prix d'une légère perte de taux d'utilisation des adresses IPv4 externes. Il y a aussi le deterministic NAT qui alloue les ports statiquement tout en conservant une plage d'allocation dynamique pour les débordements. »
Merci à André Sintzoff pour la relecture technique et la détection d'une grosse faute technique. Merci à Nicolas Février pour ses utiles commentaires, même s'il n'est pas d'accord avec moi sur les défauts du CGN.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : D. Wing (Cisco), S. Cheshire (Apple), M. Boucadair (France Telecom), R. Penno (Cisco), P. Selkirk (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pcp
Première rédaction de cet article le 1 Mai 2013
Aujourd'hui, l'utilisateur de l'Internet ne bénéficie que rarement d'une connexion neutre, d'un simple tuyau le connectant à toutes les autres machines de l'Internet. La plupart du temps, il est au contraire bloqué derrière des engins comme les routeurs NAT ou les pare-feux. Par défaut, ces engins bloquent les connexions entrantes, limitant l'utilisateur à un usage type Minitel. Dans ce cas, on a souvent besoin de dire à l'engin sur le trajet « laisse entrer des connexions vers tel port » (par exemple pour le pair à pair). Cela se fait aujourd'hui en général par une interface spécifique (par exemple une page Web d'administration du routeur NAT) ou par le protocole privé UPnP. Il y avait donc une demande pour un protocole standard, adapté aux mécanismes d'aujourd'hui comme les CGN : c'est ce nouveau protocole, PCP (Port Control Protocol).
Voici un exemple de configuration manuelle comme on fait souvent
aujourd'hui, via une interface Web, ici celle d'une
Freebox :
Avec PCP, ces interfaces vont-elles
disparaître complètement ?
Le principe est simple : un serveur PCP tourne sur l'engin bloquant (routeur NAT ou pare-feu) et autorise des clients PCP à lui parler et à demander des services comme l'ouverture d'un port entrant, ou comme une durée de vie plus longue pour les sessions en cours. Redonnant du contrôle à la machine de l'utilisateur, il rétablit un peu de neutralité dans le réseau. Avec PCP, on a un moyen propre de gérer un serveur (acceptant des connexions entrantes) derrière un routeur NAT et même derrière un CGN. Rappelez-vous qu'accepter des connexions entrantes n'est pas seulement utile si on a un serveur Web à la maison, c'est également une fonction demandée par les protocoles de voix sur IP comme SIP ou bien par le pair-à-pair.
Une fois que le client PCP a obtenu une réponse positive du serveur
PCP (« OK, j'envoie les connexions entrantes sur le
port 8080 à 172.19.1.1,
port 80, comme tu me l'as demandé »), il peut alors prévenir le reste
du monde. Cette information sur le rendez-vous n'est pas gérée par
PCP : on se sert de fonctions spécifiques au protocole (SIP
REGISTER auprès du mandataire, pour SIP, par exemple), ou bien du
DNS (éventuellement avec mise à jour dynamique
du RFC 2136 pour cela). Les enregistrements
SRV du DNS (RFC 2782) sont la solution idéale, puisqu'ils
permettent d'indiquer le numéro de port.
On notera que PCP diminue le besoin d'ALG dans les engins intermédiaires. Une nouvelle application n'aura pas besoin d'attendre que des ALG apparaissent, elle pourra contrôler les connexions dont elle a besoin elle-même, via PCP.
Même si on n'accepte pas de connexions entrantes, qu'on est un pur client, PCP peut être utile. Les routeurs NAT et les pare-feux coupent typiquement la session au bout de N minutes d'inactivité. Pour empêcher cela, les applications qui doivent rester connectées longtemps (SSH, par exemple), envoient régulièrement des paquets keepalive. Avec PCP, ce n'est plus nécessaire, l'application peut dire au serveur PCP « augmente N, s'il te plait ».
PCP est conçu, au contraire d'UPnP, pour une large gamme de besoins : du NAT traditionnel (RFC 3022), au NAPT commun aujourd'hui dans les boxes (cf. RFC 3022, section 2.2), en passant par le CGN (RFC 6888) et des choses plus exotiques comme DS-Lite (RFC 6333 et RFC 6619), NAT64 (RFC 6146), et même NAT66/NPT (RFC 6296).
PCP est prévu pour fonctionner avec les protocoles de transport qui ont la notion de port (UDP, TCP, SCTP, DCCP, etc). Pour les autres (ICMP, RSVP, ESP...), PCP ne fournit que des services partiels.
Autre limitation : PCP suppose que la machine de M. Toutlemonde n'a qu'une seule connexion à l'Internet, passant par l'équipement qui héberge le serveur PCP. Le but est de garantir que l'équipement qui répond en PCP verra bien passer tous les paquets. Ce modèle convient à la maison ou à la petite entreprise actuelle, avec son réseau local connecté via une unique box. Le dessin 1 en section 4 du RFC illustre ce modèle.
Les sections suivantes fournissent les détails du
protocole. Celui-ci manipulant souvent des adresses IP, la représentation de celles-ci (section
5) va servir
souvent : PCP utilise systématiquement un champ de taille fixe de 128
bits (même pour des adresses IPv4, qui sont
alors représentées préfixées du ::ffff:0:0/96), car c'est
plus simple.
Une description de haut niveau du protocole est en section 6. À première vue, PCP pourrait être traité comme un protocole requête/réponse (un peu comme le DNS) mais, en fait, comme il n'est pas synchrone (on peut envoyer plusieurs requêtes à la suite et lire ensuite plusieurs réponses), il vaut peut-être mieux le considérer comme un protocole suggestion/notification. Le client PCP fait des suggestions au routeur ou au pare-feu (qui sont donc libres de refuser) et le serveur PCP (le routeur ou pare-feu) envoie des notifications indiquant son état. Dans ce modèle, il y a donc deux flux de données indépendants, un du client PCP vers le serveur et un du serveur PCP vers le client. Bien sûr, l'envoi d'une notification est en général corrélé à une suggestion (elle indique indirectement l'acceptation de la suggestion) mais, je le répète, ce n'est pas synchrone. (Une des raisons de ce choix est de permettre au serveur de résister aux attaques par déni de service en ignorant les suggestions lorsque la charge est trop élevée, laissant le client ré-émettre si nécessaire.) PCP tourne sur UDP (ports 5350 et 5351) et n'a pas de notion de transaction (les messages ne portent pas d'identificateur de transaction.) La notification donne l'état actuel du routeur ou pare-feu. Si le client tient à savoir à quelle suggestion est liée telle notification, il doit examiner le contenu du message et le corréler aux suggestions qu'il a envoyées.
La section 7 indique le format standard de tous les paquets : un
numéro de version (aujourd'hui 2), un bit indiquant s'il s'agit d'une
question ou d'une réponse, un code indiquant l'opération (la plus
importante est sans doute MAP, décrite en section
11), l'adresse IP
du client PCP, la durée de vie demandée ou obtenue (pour certaines opérations) et quelques autres informations, qui dépendent de
l'opération. Parmi elles, les options, encodées en
TLV et enregistrées dans un registre IANA.
Les réponses ont un champ indiquant le code de retour d'une requête. 0 est un succès, tous les autres codes indiquent une erreur. Par exemple, 2 est la réponse à une requête non autorisée (rappelez-vous que le serveur PCP a sa propre politique et n'obéit pas aveuglément à tout ce que demande le client), 3 la réponse à une requête syntaxiquement incorrecte, etc. Ces deux erreurs sont permanentes (renvoyer le même paquet PCP ne changera rien). Mais il existe aussi des erreurs temporaires comme 8 qui indique que le serveur PCP aurait bien voulu répondre favorablement mais qu'il manque de ressources (par exemple de ports libres) pour cela. Ré-essayer automatiquement, après un délai raisonnable, peut donc être une bonne solution.
Le fonctionnement de base de PCP figure en section 8. Le client PCP
doit d'abord trouver le serveur. Il a pu le connaître par
configuration statique, ou tout simplement l'apprendre via une option
DHCP. Sinon, il tente le routeur par défaut,
qui sera en général le serveur PCP. Le client va ensuite générer un
message, où l'adresse IP du client est sa propre adresse IP (qui sera
souvent une adresse privée, du RFC 1918). La
section 16.4 explique comment connaître cette adresse grâce à
getsockname(). Le
client doit être prêt à retransmettre (section 8.1.1 pour les détails) : UDP ne
garantit pas l'acheminement.
Le serveur reçoit la requête, vérifie qu'elle arrive sur la bonne interface (le CPE typique de M. Toutlemonde, par exemple, n'acceptera pas les requêtes PCP venant de l'Internet, uniquement celles venant du réseau local), vérifie que l'adresse du client dans le paquet correspond à l'adresse IP source (autrement, c'est qu'un NAT supplémentaire se trouvait accidentellement sur le chemin) et répond. Il inclus dans la réponse un champ Epoch qui est un compteur s'incrémentant une fois par seconde. Si le client voit ce compteur diminuer, cela indiquera que le routeur a probablement redémarré, et donc perdu toutes les correspondances enregistrées, qu'il va falloir re-créer.
C'est quoi, ces « correspondances » (mappings
dans la langue de George Martin) ? Le routeur
NAT maintient une table des correspondances entre un couple {adresse
IP interne, port interne} et un couple {adresse IP externe, port
externe}. Cette table est en partie remplie automatiquement lors des
connexions sortantes mais peut aussi être partiellement gérée par
PCP. Par exemple, le fonctionnement classique du NAT d'un petit
routeur à la maison, lorsqu'un paquet venant de {192.168.10.10,
5623} sort, est de réserver un port pour cette session (mettons le
port 7891) et de mémoriser une correspondance
{203.0.113.254, 7891} <=> {192.168.10.10,
5623} (on suppose que l'adresse IPv4 externe du routeur est
203.0.113.254). Avec cette correspondance en tête,
le paquet de réponse destiné à {203.0.113.254,
7891} sera automatiquement NATé et dirigé vers {192.168.10.10,
5623}. PCP permet de manipuler de telles correspondances et, par
exemple, pour reprendre un exemple donné plus haut, de dire « envoie
les connexions entrantes sur le port 8080 à 192.168.10.1,
port 80 », ce qui se traduira par la création d'une correspondance
(mapping) {203.0.113.254, 8080} <=> {192.168.10.11,
80}. On notera que le client PCP n'a pas indiqué l'adresse externe
203.0.113.254. PCP permet de le faire mais, dans
le cas le plus courant, le client PCP ne connait pas cette adresse et
laisse le serveur la choisir.
La section 10 résume les opérations les plus importantes de PCP,
MAP (détaillée en section 11) et
PEER (détaillée en section 12). MAP permet de
créer les correspondances statiques, pour gérer un serveur,
PEER permet notamment de manipuler les correspondances dynamiques,
celles crées automatiquement par le routeur NAT. La liste de toutes
les opérations est dans un registre IANA
(cf. section 19.2, sur la politique d'affectation des codes numériques
correspondants.)
Prenons l'exemple d'un serveur du
réseau local (comme {192.168.10.11,
80} dans mon exemple), qui va appeler MAP pour
« ouvrir » le routeur ou pare-feu aux connexions entrantes. En
pseudo-code :
/* Les variables précédées de & sont des pointeurs, pour pouvoir
écrire un résultat dans la variable. */
externalport = 80;
pcp_send_map_request(myport, myaddr, &externalport, &externaladdr,
requestedlifetime, &assignedlifetime);
if (!pcp_response_received())
panic("No answer");
}
else {
/* Éventuellement mettre à jour le DNS, un serveur de rendez-vous,
pour dire au reste du monde qu'il peut y aller */
}
/* La suite est le code habituel, sans PCP */
if (received_incoming_connection_or_packet())
process_it(s);
Si l'application se moque du port externe attribué, il suffit de ne pas l'indiquer dans la requête et de regarder dans la réponse quel port a été alloué. De toute façon, le routeur ne lui allouera pas forcément le port demandé. Par exemple, pour un CGN, tout le monde voudra sans doute s'allouer le port 80, ce qui n'est pas possible. Soit le CGN le refusera à tous, soit il le donnera au premier arrivé et allouera un autre port pour les suivants. Un client PCP bien fait doit donc être préparé : il doit lire le port effectivement attribué et réagir intelligemment s'il n'a pas eu le port souhaité (ce n'est pas fait dans le programme d'exemple ci-dessus). Bien sûr, le client PCP doit aussi être prêt à ce que sa requête soit complètement rejetée, par exemple parce que la table des correspondances a une taille fixe et que ladite table est pleine.
La lecture de la réponse permet aussi au client PCP de savoir quelle est l'adresse externe allouée, ce qui peut être pratique. (Si on n'est intéressé que par cela, il suffit donc de créer une correspondance avec une très courte durée de vie et de lire la réponse.)
La réponse PCP inclut la durée de vie de la correspondance
(champ Lifetime du paquet, variable
assignedlifetime du programme plus haut). C'est
la responsabilité du client de renouveller la correspondance avant
qu'elle n'expire (cf. section 15).
Si l'application ne sait pas si elle est derrière un routeur NAT ou un
pare-feu, ce qui est fréquent, la solution recommandée est quand même
d'essayer PCP. S'il n'y a pas de réponse, cela peut vouloir dire que
la machine a une connectivité complète (sans NAT) ou malheureusement
que le routeur ne gère pas PCP. (Le code plus haut suppose que
l'absence de réponse indique qu'on n'a pas de connectivité en tant que
serveur, donc panic().)
Le routeur doit créer des correspondances ayant la sémantique Endpoint Independent Filtering, ce qui veut dire que cette correspondance sera la même quelle que soit l'adresse IP de la machine distante. Il va devoir aussi se débrouiller pour que les messages ICMP correspondant à cette correspondance soient bien acheminés à la machine.
Outre les champs génériques communs à tous les paquets PCP,
MAP a quelques champs qui lui sont propres
notamment le port interne (la variable myport
dans le pseudo-code), le port externe suggéré
(la variable externalport dans le programme en
pseudo-code) et l'adresse IP externe suggérée (rappelez-vous que le
petit routeur NAT de la maison n'a pas le choix : il n'a en général
qu'une seule adresse IPv4 externe, donc il ignorera ce
paramètre). Dans la réponse à un MAP, la valeur
de ces champs indiquera au client ce que le serveur PCP a finalement
choisi (pas forcément ce qui était demandé). Une option de la requête
permet de dire si les adresses et ports suggérés sont impératifs (on
préfère un échec plutôt qu'une correspondance avec d'autres valeurs
que celles demandées) ou
pas (cf. section 13.2).
MAP permet aussi de contrôler un
pare-feu, avec son option
FILTER (section 13.3) où on décrit les adresses
IP et ports autorisés, le reste étant bloqué. Séparer la fonction de
NAT de celle de pare-feu est essentiel : actuellement, les routeurs
NAT typiques mélangent les deux, ce qui a mené certaines personnes à
croire que le NAT avait un rôle de
protection. Outre la sécurité, FILTER peut
être utile pour des machines sur batterie :
elles éviteront ainsi de gaspiller du courant à traiter des paquets
non désirés.
PCP est également utile au cas où on n'a certes besoin que de
connexions sortantes mais où on veut influencer des paramètres comme
la durée de vie des correspondances créées automatiquement, de manière
à ne pas avoir besoin d'envoyer de temps en temps des paquets
keepalive. On utilise pour cela l'opération
PEER. Cette opération a à peu près les mêmes
champs que MAP mais les correspondances crées
peuvent avoir des sémantiques autres que Endpoint Independent
Filtering. (MAP a le code 1 et
PEER 2, dans le registre IANA.)
Un autre usage de l'opération PEER est pour
re-créer des correspondances perdues. Un des plus gros inconvénients du NAT est qu'il maintient un
état dans le routeur. Normalement, l'Internet est
un réseau de paquets, les routeurs intermédiaires font passer les
paquets mais n'ont aucune notion de session associées, il font passer
du TCP, de l'UDP ou
n'importe quel autre protocole sans faire de différence. Un des
avantages de ce principe est que le redémarrage d'un routeur ne change
rien : les connexions TCP, par exemple, continueront comme si rien ne
s'était passé, l'état des connexions étant entièrement contenu dans
les machines terminales. Le NAT change tout cela : si un routeur NAT
redémarre, toutes les correspondances sont perdues. Si les machines
tentent de continuer la communication, de nouvelles correspondances
seront créées, avec de nouveaux numéros de port, et ce changement
cassera les connexions TCP en cours. C'est notamment insupportable
pour SSH.
Comment PCP peut-il aider ? Une machine qui connait la
liste des correspondances (elle a pu l'apprendre avec l'opération
PEER) peut, lorsqu'elle détecte un redémarrage du
routeur, lui renvoyer cette liste (toujours avec
PEER mais, cette fois, en remplissant les champs
Suggested Address et Suggested Port), rétablissant ainsi la même table
des correspondances (section 14). À noter que, pour accélérer la
reconstitution de l'état du routeur, un routeur qui sait qu'il va
redémarrer peut aussi envoyer des paquets PCP avec l'opération
ANNOUNCE (section 14.1.3) pour prévenir les
clients. Ces envois se font aux adresses
multicast
224.0.0.1:5350 et
[ff02::1]:5350 (224.0.0.1 et ff02::1
voulant dire « toutes les machines du réseau »). Les machines clientes
peuvent alors savoir qu'elles vont devoir recréer leurs
correspondances (après avoir attendu un délai aléatoire, pour éviter
qu'elles ne le fassent toutes en même temps).
PEER peut enfin créer une nouvelle
correspondance mais cela n'a pas un grand intérêt, puisque tout
routeur NAT sait le faire automatiquement au premier paquet d'une
nouvelle connexion sortante. (La seule exception est le cas cité plus
haut où on restaure l'état d'un routeur NAT qui a redémarré.)
Je ne connais pas l'état actuel de mise en œuvre de PCP dans les routeurs NAT typiques. Pour le programmeur qui veut s'y mettre sérieusement, la section 16 contient un certain nombre de conseils pratiques, aussi bien pour l'écriture de serveurs que pour celle de clients PCP. Quant à la section 17, elle se penche sur les problèmes de déploiement de cette nouvelle technologie. Par exemple, il est important que le routeur rejette les paquets entrants dont l'adresse source ne correspond pas à celles du réseau interne (RFC 2827) pour éviter qu'un méchant n'usurpe une adresse IP.
Tiens, puisqu'on parle de sécurité, la section 18 lui est entièrement consacrée. PCP permet de contrôler plus finement les correspondances dans le routeur, voire de modifier les filtres d'un pare-feu. Il est donc essentiel que ces nouvelles possibilités ne se fassent pas au détriment de la sécurité. Par exemple, une machine du réseau interne autorisée à créer ou modifier des correspondances peut voler le trafic d'une autre. Ce n'est pas très grave pour un réseau local à la maison mais bien plus embêtant dans le cas d'un grand CGN.
PCP, s'il est correctement mis en œuvre, est protégé contre les
attaquants situés en dehors du chemin. Par exemple, si une machine
quelque part sur l'Internet envoie un paquet PCP prétendant venir
d'une des adresses internes (mettons
192.168.1.1), le routeur/serveur PCP rejettera ce
paquet qui arrive par l'interface externe (il ne doit accepter les
requêtes PCP que si elles sont internes). Par contre, un attaquant
interne a à peu près open bar avec PCP. Un serveur
PCP doit donc être déployé uniquement si toutes les machines internes
sont considérées comme membres de la même bande (une supposition
raisonnable pour un réseau domestique) ou si on peut séparer les
clients en plusieurs domaines, empêchant M. Michu de voler le trafic
de Mme Toutlemonde, située derrière le même CGN.
Une façon de limiter les risques est que le serveur PCP ne configure explicitement que des correspondances qu'il aurait de toute façon configuré implicitement, lorsqu'une nouvelle connexion sort. Cela veut dire qu'il y a des opérations PCP sûres (créer une correspondance sans spécifier le port et l'adresse externes) et d'autres qui peuvent être dangereuses (créer une correspondance avec un port externe spécifié).
Si on autorise PCP à configurer un pare-feu, il faut évidemment faire encore plus attention. Il n'existe pas à l'heure actuelle de mécanisme de sécurité standard pour PCP : son premier domaine d'application concerne des cas où il n'y a déjà pas de sécurité aujourd'hui. Pour d'autres domaines, il faudra trouver de nouvelles solutions de sécurité.
Quelques autres attaques possibles avec PCP :
PCP est le successeur d'un protocole très proche nommé PMP (Port Mapping Protocol, RFC 6886). L'annexe A décrit la coexistence entre les implémentations de PMP qui restent, et PCP. L'autre protocole qui avait été envisagé par le groupe de travail PCP était bien sûr UPnP, mais qui était techniquement moins proche de ce qui était souhaité (non routé, peu sécurisé, peu fiable). PMP utilisant les mêmes ports, des dissecteurs de paquets analysent parfois le PCP sous le nom de PMP.
Aujourd'hui, on trouve très peu de mises en œuvre de PCP déployées. Aucun système d'exploitation n'a de client PCP en série. Wireshark n'a pas encore de dissecteur PCP (il est en cours de développement et un autre, sous forme d'un greffon en Lua, est disponible). Attention, Wireshark a un dissecteur pour un autre PCP (Performance Co-Pilot Protocol). Une solution possible sera peut-être (suggestion de Gunther Ozerito) faire un relais UPnP <=> PCP.
Et j'ai bien envoyé des paquets PCP à ma Freebox, mais je reçois toujours une triste réponse ICMP port 5351 unreachable d'où je déduis qu'elle n'a pas encore de serveur PCP. (Et elle ne diffuse apparemment rien vers le port 5350.)
Au fait, pour les envoyer, j'ai utilisé ce (très grossier) script Scapy, qui est loin de remplir tous les champs mais permet quelques tests :
from scapy.all import *
# http://www.secdev.org/projects/scapy/doc/build_dissect.html
class PCP(Packet):
name = "Port Control Protocol"
fields_desc = [ ByteField("Version", 2),
BitField("R", 0, 1), # 0 = Request / 1 = Response
BitField('Opcode', 1, 7), # MAP is 1, PEER is 2
ShortField("Reserved", 0),
IntField("RequestedLifetime", 0),
LongField("ClientAddressUpper", 0),
LongField("ClientAddressLower", 0)
]
p = IP(dst="192.168.2.254")/UDP(sport=0,dport=5351)/PCP(RequestedLifetime=5000,
ClientAddressLower=232236033)
sr1(p)
Un bon article d'introduction sur PCP est « New Technology Demo: PCP » dans le numéro 7.2 de l'IETF Journal.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : M. Eubanks (AmericaFree.TV LLC), P. Chimento (Johns Hopkins University Applied Physics Laboratory, M. Westerlund (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 1 Mai 2013
Ne dites plus qu'en IPv6, la somme de contrôle est toujours obligatoire dans les en-têtes des paquets UDP. Depuis ce RFC 6935, ce n'est plus vrai dans tous les cas. Lors de l'encapsulation de paquets dans un tunnel UDP, on a désormais le droit de ne pas mettre de somme de contrôle dans les paquets UDP, essentiellement pour des raisons de performance.
Le principal demandeur de cette modification était le protocole LISP (RFC 6830), qui dépend énormement de tunnels UDP. Même si le calcul de la somme de contrôle Internet est rapide (RFC 1071), comme ce calcul peut se faire des millions de fois par seconde pour un routeur très actif, on peut chercher à l'économiser. D'autant plus qu'il n'est pas forcément utile puisque, dans le cas d'un tunnel, le protocole qui circule dans le tunnel est déjà protégé par une somme de contrôle. À noter que d'autres protocoles que LISP (comme ceux utilisés pour le multicast) peuvent bénéficier de cette nouvelle indulgence. Mais elle ne s'applique pas aveuglément à tout UDP (comme l'avaient proposé certains au début de la discussion), uniquement aux tunnels.
La norme actuelle sur IPv6, le RFC 2460, imposait (dans sa section 8.1) une somme de contrôle pour les paquets UDP (en IPv4, elle était facultative). En effet, IPv6 n'a pas de somme de contrôle dans la couche 3 (contrairement à son prédecesseur).
Ce RFC est un produit du groupe de travail IETF 6man, qui produit inlassablement d'innombrables RFC pour combler tous les petits problèmes qui trainent encore dans IPv6 et sont révélés par son utilisation dans le vrai monde.
Notez bien que cette dispense de somme de contrôle n'est pas générale : elle concerne les cas où il y a un tunnel et où il utilise UDP. Pourquoi UDP, alors qu'il existe des protocoles de tunnel qui s'en dispensent ? Parce que l'Internet est hélas de plus en plus ossifié, et que des middleboxes stupides et boguées sont partout sur le trajet des pauvres paquets. Les techniques de tunnel directement sur IP (comme l'excellent GRE du RFC 2784) sont souvent bloquées, alors qu'UDP passe partout. On aura donc un protocole X (LISP ou un autre) à l'intérieur du tunnel et de l'UDP à l'extérieur. Hier, cet UDP à l'extérieur était forcément protégé par une somme de contrôle. Pour un routeur qui sert de terminaison à des dizaines de milliers de tunnels (ce qui n'aurait rien d'étonnant avec LISP), calculer et vérifier ces sommes peut être très douloureux. D'autant plus que le protocole X a souvent sa propre somme de contrôle : ne serait-ce pas mieux pour tout le monde que le tunnel soit non sécurisé, ses éventuelles corruptions de paquets étant détectées par le protocole X uniquement ?
La section 4 discute plus en détail de certains aspects du problème mais il vaut mieux consulter le RFC 6936 pour tout savoir. Cet autre RFC précise notamment dans quels cas supprimer la somme de contrôle est une bonne idée et dans quels cas il vaut mieux la garder. La section 4 de notre RFC note particulièrement que les paquets de contrôle du tunnel, ceux qui servent à la signalisation, devraient rester protégés (s'ils sont corrompus, le tunnel peut cesser de fonctionner, c'est-à-dire que la corruption d'un paquet va affecter d'autres paquets). Notons que certains protocoles de tunnel comme GRE n'ont aucun mécanisme de contrôle. Lorsqu'il y en a un, il est souvent utilisé pour établir un contexte au début, avec choix des paramètres pour le tunnel : ce peut être le bon moment pour négocier le non-usage des sommes de contrôle sur les paquets de données.
Autre piège rigolo : certaines middleboxes vont tiquer en voyant les paquets UDP sans somme de contrôle (bien que, normalement, la somme de contrôle soit de bout en bout et ne regarde pas ces équipements intermédiaires). Bien que ce soit désormais légal, il va falloir attendre longtemps avant que tous ces engins soient mis à jour (section 4.3). En attendant ce jour, il est prudent que le tunnel détecte les problèmes en envoyant des paquets avec et sans somme de contrôle au début : si seuls les premiers passent, c'est qu'on a une middlebox agressive sur le trajet et qu'il faut renoncer à appliquer ce RFC 6935. Le test est d'ailleurs à répéter de temps en temps : la route peut changer et on peut donc se retrouver soudain à traverser une nouvelle middlebox.
La section 4.1 conseille également de tenter de détecter la corruption avant de décapsuler, par exemple en examinant l'adresse IP source, pour minimiser le risque d'envoyer au protocole encapsulé un paquet reçu corrompu. Mais cette détection ne marchera pas à tous les cas (sinon, on pourrait supprimer les sommes de contrôle dans tous les cas) et le protocole encapsulé doit donc être robuste et réagit proprement lorsque ces paquets corrompus sont injectés dans un flux existant (section 4.2).
La section 5 contient la nouvelle norme pour les sommes de contrôle UDP. Elle remplace le texte du RFC 2460 (qui disait que la somme de contrôle UDP était toujours obligatoire en IPv6) par un texte plus nuancé : par défaut, la somme de contrôle doit être calculée et mise dans le paquet. Mais on peut s'en dispenser dans le cas de tunnels (et uniquement celui-ci), sur le paquet extérieur. Le protocole à l'intérieur du paquet (qui n'est pas forcément de l'UDP et même pas forcément de l'IPv6) doit rester protégé par sa propre somme de contrôle. Cela ne doit s'appliquer que pour une liste explicite de ports (ceux utilisés par le tunnel) et pas pour tout le trafic UDP de la machine. Et le tout doit se faire en lisant le RFC 6936 qui précise les conditions d'application de cette nouvelle règle.
Les curieux et les chercheurs en informatique noteront que la section 6 liste des points qui mériteraient davantage d'étude. Ainsi, il n'y a pas eu d'étude systématique de la corruption de paquets sur l'Internet depuis 2000 et personne ne sait donc trop si c'est un phénomène fréquent ou pas. Cette section note aussi qu'il existe en théorie une meilleure solution pour les tunnels, UDP Lite (RFC 3828), mais que sa probabilité de passer les middleboxes est plus faible que celle d'UDP.
Plusieurs des mises en œuvre de LISP envoient déjà des paquets UDP sans somme de contrôle (ou plus exactement avec une somme à zéro).
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : G. Fairhurst (University of Aberdeen), M. Westerlund (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 1 Mai 2013
Le RFC 2460 qui normalise IPv6 indique dans sa section 8.1 que les paquets UDP sur IPv6 doivent avoir une somme de contrôle (elle était facultative en IPv4) calculée selon le RFC 1071. Dans quels cas est-elle réellement nécessaire ? Peut-on s'en passer parfois ? Ce nouveau RFC discute des conditions qui peuvent permettre de mettre zéro dans le champ Checksum, indiquant qu'on n'a pas utilisé de somme de contrôle. Pour résumer : si on veut se passer de somme de contrôle, cela doit se faire application par application, il faut être sûr qu'on supporte les paquets corrompus ou délivrés à tort, et il faut tester le chemin emprunté pour être sûr que les « nouveaux » paquets passent bien.
Ce RFC discute des solutions à un problème de performance d'UDP et des conditions dans lesquels on peut ne plus mettre de somme de contrôle. Il sert donc d'arrière-plan au RFC normatif, le RFC 6935 qui définit les nouvelles règles pour UDP sur IPv6 (somme de contrôle facultative) et fait donc un choix ferme parmi les propositions discutées ici. Notez toutefois qu'il y a pas mal de recouvrement et de redites entre les deux RFC.
UDP est très utilisé, et pour beaucoup d'applications (le RFC 5405 donne des conseils à ce sujet). Un des usages fréquents est pour construire des tunnels, afin de pouvoir passer à travers les millions de middleboxes stupides qui infestent l'Internet, et qui bloquent souvent tous les protocoles autres que UDP et TCP. Or, un routeur d'entrée ou de sortie de tunnel peut avoir à encapsuler ou décapsuler des millions de paquets par seconde et la génération ou la vérification des sommes de contrôle de chaque paquet peut avoir un effet mesurable sur ses performances (sections 1.3.2 et 1.3.3). D'autant plus qu'il n'est pas toujours possible d'utiliser le matériel spécialisé du routeur pour cela car il ne donne souvent accès qu'aux N premiers octets du paquet (avec N typiquement < 128), alors que le calcul de la somme de contrôle nécessite d'accéder à tout le paquet.
En UDP/IPv4, la solution est de couper la somme de contrôle sur le paquet externe (le protocole interne, qui n'est pas forcément UDP, reste protégé par sa propre somme de contrôle), ce qui est légal en IPv4. Le tunnel devient alors un lien virtuel non fiable, pouvant corrompre des paquets (comme c'est le cas d'un certain nombre de liens physiques). C'est par exemple la solution recommandée pour un gros consommateur de tunnels UDP, LISP. Il est donc tentant de l'utiliser également en UDP/IPv6.
Cela peut poser des problèmes avec certaines middleboxes qui vérifient la somme de contrôle UDP et n'accepteront pas d'y trouver zéro. Décréter que la somme de contrôle UDP en IPv6 devient facultative ne signifie donc pas que ces paquets optimisés pourront voyager dès demain sur tout l'Internet : un certain nombre de pare-feux les bloqueront. Cela peut sembler un problème rhédibitoire (on utilisait UDP justement pour passer facilement à travers les middleboxes puis on réforme les règles d'UDP, créant des paquets qui sembleront illégaux à beaucoup de ces middleboxes) mais il faut noter que la plupart des ces middleboxes ne font pas encore d'IPv6 et que donc les premiers déploiements ont des chances de se faire avec des middleboxes conformes à la nouvelle règle.
À part l'UDP existant, et l'UDP avec somme facultative du RFC 6935, quelles sont les autres technologies disponibles pour des tunnels (section 2 du RFC) ? Il y a UDP Lite (RFC 3828), avec une somme de contrôle qui ne couvre que le début du paquet (et est donc rapide à calculer), et qui est certes mis en œuvre dans le noyau Linux mais qui est peu reconnu par les middleboxes. Il utilise un identifiant (champ Next Header qui identifie en général le protocole de transport) différent de celui d'UDP (136 contre le 17 d'UDP) et est donc souvent bloqué par des pare-feux trop zélés. Il y a les techniques de tunnels génériques comme IP-in-IP et GRE. Elles n'ont pas de somme de contrôle du tout et sont donc rapides. Ce sont les solutions idéales pour les tunnels mais elles aussi utilisent un champ Next Header qui peut ne pas être connu de la middlebox (94 pour IP-in-IP et 47 pour GRE) et ils passent certainement moins souvent qu'UDP (d'où le choix d'UDP pour LISP). Notons aussi que la section 6 déconseille les tunnels récursifs (un tunnel dans un tunnel dans un tunnel...) qui augmentent les risques d'erreur pour le paquet le plus interne (et ajoutent une grande complexité à la fragmmentation).
La section 3 examine ensuite les choses qui peuvent aller mal avec la solution retenue par le RFC 6935. Si on ne met pas de somme de contrôle dans le paquet UDP (ou, plus exactement, qu'on met zéro, indiquant qu'on n'a pas calculé de somme et que le récepteur ne doit pas vérifier), et qu'un bit du paquet est modifié, que peut-il se passer d'horrible ? Pour IPv4, la somme de contrôle UDP ne servait qu'à protéger les numéros de port et les données, des informations comme l'adresse IP de destination étaient protégées par la somme de contrôle de la couche 3. Celle-ci a disparu en IPv6 et la somme de contrôle UDP doit donc tout faire. Si elle est erronée, on n'est même pas sûr que le paquet nous était bien destiné (l'adresse IP de destination a pu être modifiée).
Comme l'expliquent le RFC 3819 ou des études comme « When the CRC and TCP Checksum Disagree », la corruption arrive réellement dans l'Internet. Des mesures ont indiqué jusqu'à 1 paquet corrompu sur 10 000 (cela dépend fortement du chemin suivi : le taux de corruption est quasi-nul sur certains chemins). Le RFC note (section 3.2) qu'on ne sait pas exactement où la corruption survient : cela peut être dans la RAM du routeur, sur le câble, dans les récepteurs et les émetteurs optiques ou électriques, etc.
Si c'est l'adresse IP de destination qui est modifiée, le paquet peut n'arriver nulle part, ou bien arriver à une machine qui ne l'attend pas. Si aucun programme n'écoute sur le port en question, le paquet est jeté (et un message d'erreur envoyé à la source, qui sera bien surprise). Si un programme écoute, il va recevoir un paquet invalide. Mëme chose si c'est le port de destination seul qui a été corrompu. Si l'application n'a pas de mécanisme (comme des numéros de séquence) pour détecter le problème, le paquet invalide pourra être accepté. Donc, une règle importante : une application qui est prête à débrayer les sommes de contrôle UDP doit être prête à réagir proprement si elle reçoit un datagramme envoyé à tort. C'est une des raisons pour lesquelles le RFC exige que la suppression de la somme de contrôle UDP ne se fasse pas globalement, pour toute la machine ou pour toute l'interface réseau, mais uniquement sur requête explicite d'une application majeure et consentante (section 3.5)
Si c'est l'adresse IP source qui est corrompue, le paquet arrivera sans doute à la bonne destination (mais pas à coup sûr, par exemple en cas de filtrage RFC 2827). Si l'application garde en mémoire ses correspondants, le paquet de ce correspondant inconnu sera jeté. Si elle ne le fait pas, si une réponse est envoyée... elle le sera au mauvais correspondant.
Et si c'est l'information de fragmentation qui est corrompue ? Cela peut empêcher le réassemblage (menant à la perte du paquet) mais aussi, ce qui est bien pire, conduire à des réassemblages erronés (par exemple, si le champ ID est modifié, attribuant le fragment à un autre datagramme). Comme le note le RFC 5722, il faut multiplier les tests lors du réassemblage.
Nous avons vu plus haut qu'un certain nombre de boîtiers intermédiaires jetteraient probablement sans autre forme de procès ces « nouveaux » paquets UDP avec une somme de contrôle nulle (ils étaient illégaux avant la sortie du RFC 6935). Il est donc essentiel, pour une application qui veut utiliser cette nouveauté, de tester le chemin et de vérifier que rien sur le trajet ne jette les paquets sans somme de contrôle. Il faut aussi penser à répéter ce test de temps en temps : le chemin peut changer (par exemple parce que BGP l'a décidé) et passer tout à coup par des boîtiers différents. (Et il faut faire le test dans les deux sens, ne serait-ce que parce que le routage n'est pas forcément symétrique.)
Dans tous les cas, il faut se rappeler que la somme de contrôle ne fournit de protection que contre la corruption accidentelle. Ce n'est pas un mécanisme d'authentification, et elle ne protège pas du tout contre un attaquant (qui peut modifier le paquet sans changer la somme de contrôle).
Les règles d'applicabilité sont formalisées dans les sections 4 (pour les implémentations) et 5 (pour l'usage de ces implémentations). Les programmes qui mettent en œuvre UDP sur IPv6 :
Cela, c'était pour l'implémentation d'UDP et d'IPv6 (qui, dans un Unix, est dans le noyau). Maintenant, pour les applications qui l'utilisent, la section 5 dit qu'elles :
Voilà, les règles d'applicabilités sont posées. Mais le RFC compte aussi une annexe intéressante, l'annexe A, qui est consacrée aux propositions alternatives. La solution choisie par le RFC 6935 a été d'autoriser les sommes de contrôle nulles. Mais on aurait pu faire différemment. Par exemple, le problème de performance et d'accès à la totalité du paquet aurait pu être traité par les calculs incrémentaux de somme de contôle du RFC 1624 (mais ils ne marchent pas quand il y a fragmentation IP). On aurait pu, comme cité, utiliser un protocole comme UDP Lite, ou UDPTT. Il avait aussi été proposé une mesure unilatérale, qu'un receveur ignore la somme de contrôle, quoiqu'ait mis l'émetteur (c'était plus simple mais il était alors impossible de détecter la corruption, pour tous les paquets). D'autres avaient suggéré une nouvelle option dans un en-tête Destination Options, ce qui revenait, à mon avis, à réintroduire une somme de contrôle en couche 3, ce qu'IPv6 avait délibérement abandonné. De toute façon, beaucoup de middleboxes auraient jeté les paquets avec cet en-tête (qui est rare, en pratique). Ces différentes propositions sont examinées en fonction de plusieurs critères : traversabilité des middleboxes, performances, déployabilité et résistance à la corruption de paquets.
Pour la traversée des middleboxes, l'UDP actuel ou bien un UDP avec un calcul incrémental des sommes de contrôle, est ce qui marche le mieux. Aucun changement à faire. L'UDP sans somme de contrôle du RFC 6935 aura sans doute quelques soucis (actuellement, de tels paquets sont illégaux), ainsi que les paquets avec l'en-tête Destination Options (pourtant légaux). Et les tunnels génériques seront sans doute bloqués par défaut par la plupart des pare-feux, ainsi qu'UDP Lite.
C'est à peu près la même chose pour la déployabilité : l'UDP actuel existe déjà et n'a pas à être déployé. Les sommes de contrôle facultatives du RFC 6935 nécessiteront au moins un changement dans les extrêmités (ne pas calculer la somme, ne as la vérifier) mais aussi dans certaines middleboxes qui se mêlent de vérifier la somme de contrôle, alors qu'on ne leur a rien demandé.
Pour les performances, l'UDP actuel est certainement le pire, puisqu'il faut calculer la somme de contrôle sur la totalité du paquet. C'est bien cela qui a motivé tout ce travail sur la réforme des sommes de contrôle UDP. UDP Lite, qui ne vérifie qu'une partie du paquet, et l'UDP réformé du RFC 6935 ont des bien meilleures performances (c'est aussi le cas des tunnels génériques).
Bref, il n'y a pas de solution parfaite, qui résolve tous les problèmes. Si on veut avant tout passer partout, l'UDP actuel est la meilleure solution. Si on veut une solution propre architecturalement, IP-in-IP est parfait. Si on se préoccupe des performances, l'UDP avec somme de contrôle facultative du RFC 6935 est une bonne approche et reçoit un avis favorable dans ce RFC.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : J. Chu, N. Dukkipati, Y. Cheng, M. Mathis (Google)
Expérimental
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 30 Avril 2013
Sur l'Internet, il y a des choses qu'on hésite à toucher. Depuis quelques épisodes fameux de « catastrophes congestives », où tout l'Internet s'est arrêté en raison de l'encombrement des tuyaux, la mémoire collective du réseau, incarnée notamment par l'IETF, voit avec une extrême méfiance toute modification des algorithmes de TCP, qui sont la principale ligne de défense de l'Internet face à la congestion. Néanmoins, le réseau évolue, les choses changent et il y a des gens qui insistent pour essayer des changements. Cela fait un certain temps que Google réclame une modification connue sous le doux nom de IW10 (pour Initial Window 10 segments) et ce RFC est le premier à la documenter officiellement, après trois ans de discussion dans le groupe de travail. Pour l'instant, c'est encore étiqueté comme « expérimental ».
La norme reste celle du RFC 3390. Elle dit que la fenêtre initiale d'une connexion TCP, à savoir le nombre maximal d'octets qu'on peut envoyer avant le premier accusé de réception, est donnée par une formule qui, en pratique est d'environ 4 kilo-octets, soit deux à trois segments (paquets TCP), parfois quatre. Voici, vu par tcpdump sur le client, un exemple entre deux machines séparées par 100 ms de RTT, un client HTTP qui demande un gros fichier et un serveur :
21:54:15.371487 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 1:1449, ack 118, win 1810, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448 21:54:15.371509 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 1449, win 137, options [nop ,nop,TS val 2768109 ecr 1079804426], length 0 21:54:15.372574 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 1449:2897, ack 118, win 181 0, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448 21:54:15.372593 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 2897, win 182, options [nop ,nop,TS val 2768109 ecr 1079804426], length 0 21:54:15.372615 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 2897:4345, ack 118, win 181 0, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448 21:54:15.372630 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 4345, win 227, options [nop ,nop,TS val 2768109 ecr 1079804426], length 0 21:54:15.372897 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [P.], seq 4345:5793, ack 118, win 18 10, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448 21:54:15.372910 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 5793, win 273, options [nop ,nop,TS val 2768109 ecr 1079804426], length 0 21:54:15.488019 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 5793:7241, ack 118, win 181 0, options [nop,nop,TS val 1079804455 ecr 2768109], length 1448
On voit que 204.62.14.153 a envoyé quatre
segments avant de devoir s'arrêter, les accusés de réception n'ayant
pas eu le temps de l'atteindre. La pause dure 116 ms, avant que le
serveur ne reprenne son envoi.
Ce nombre de segments est trop petit (bien plus petit que les tampons d'entrée/sortie d'un équipement réseau typique) car, sur les réseaux modernes, cela veut dire qu'un pair TCP qui veut envoyer un gros fichier va très vite remplir cette fenêtre et va devoir attendre ensuite, alors qu'il ne sait absolument pas si le réseau est congestionné ou pas. D'où la proposition IW10 qui est de permettre l'envoi de dix segments. (Pourquoi dix ? Comme l'explique l'annexe A, c'est le résultat de tests avec plusieurs valeurs possibles. Dix était la valeur qui était le meilleur compromis entre les gains et les inconvénients. Notez qu'une des techniques étudiées par le groupe de travail - et finalement abandonnée - avait été un système complexe de mesure et de rétroaction, avec des tailles initiales de fenêtre variables.)
La formule proposée par ce RFC (section 2) est fenêtre_initiale (en octets) = minimum (10*MSS, maximum (2*MSS, 14600)). Cela pourra faire jusqu'à dix segments, en fonction de la MSS. Naturellement, la machine aura le droit de choisir une fenêtre plus petite, ce choix n'est en effet pas dangereux ; mais pas de fenêtre plus grande, le but étant d'éviter la congestion de réseau.
Notez bien que cette formule ne s'applique qu'au début de la connexion. Lorsque TCP reprend son algorithme de démarrage en douceur (slow start), par exemple suite à des pertes de paquets, il doit s'en tenir au RFC 2581.
Il y a aussi quelques questions pratiques à se poser. Par exemple, une connexion TCP est bi-directionnelle : ce n'est pas tout d'utiliser une fenêtre plus grande à l'émission, il faut aussi annoncer à son pair une fenêtre de réception plus grande (cf. « An Argument for Increasing TCP's Initial Congestion Window » de Dukkipati, N., Refice, T., Cheng, Y., Chu, J., Sutin, N., Agarwal, A., Herbert, T. et J. Arvind, article de 2010 qui va être souvent cité ici.)
Ce changement a des conséquences pour les applications qui utilisent TCP (section 3). Ainsi, HTTP 1.1 n'autorise que deux connexions TCP simultanées vers le même serveur (RFC 2616, section 8.1.4). Les navigateurs en ouvrent en général plus que cela, pour éviter l'attente due à la faible taille de la fenêtre TCP. (Voir « A Swifter Start for TCP », par Partridge, C., Rockwell, D., Allman, M., Krishnan, R. et J. Sterbenz, rapport technique n° 8339 de BBN en 2002.) C'est égoïste de leur part (cela s'oppose aux mécanismes de contrôle de congestion de TCP) et cela ne devrait logiquement plus être nécessaire avec le déploiement d'IW10. Le RFC conseille donc de réduire le nombre de connexions HTTP simultanées.
La section 4 du RFC donne des éléments de contexte et d'histoire. Au début (cf. le célébrissime article de Van Jacobson, « Congestion Avoidance and Control », en 1998), TCP ne pouvait envoyer qu'un seul segment avant de recevoir le premier accusé de réception. Ce n'était pas un problème pour de longues communications, comme celles de telnet. Mais l'Internet aujourd'hui voit surtout du trafic Web (cf. « Atlas Internet Observatory 2009 Annual Report » de Labovitz, C., Iekel-Johnson, S., McPherson, D., Oberheide, J. Jahanian, F. et M. Karir, présenté à NANOG 47 en 2009.), avec des connexions de courte durée. Attendre longtemps avant de pouvoir envoyer plusieurs segments est très pénalisant (la plupart de ces connexions courtes ne quitteront jamais l'état TCP « démarrage en douceur »).
Surtout, les changements dans la capacité des réseaux ont été spectaculaires. Le rapport « The State of the Internet » d'Akamai en 2010, annonce que les accès à plus de 2 Mb/s forment désormais la majorité, ce qui met la capacité moyenne à 1,7 Mb/s, alors que, pendant ce temps, la fenêtre d'envoi initiale de TCP restait aux 4 ko du RFC 2414, sans bouger pendant dix ans. Avec un RTT de 200 ms, cette fenêtre ne permettait que 200 kb/s.
Des tas de changements avaient été proposés (pour ne citer que les RFC, voir RFC 4782 et RFC 6077) mais sans être réellement déployés. Ce sont donc les applications qui se sont adaptées, comme vu plus haut avec les navigateurs qui ouvrent plusieurs connexions, et les sites Web créant des sous-domaines sans autre raison que de débrayer la limitation du nombre de connexions par serveur (cf. « A Client-Side Argument For Changing TCP Slow Start » en 2010). Le déploiement d'IW10 devrait logiquement s'accompagner d'un changement de stratégie de ces navigateurs Web.
Au fait, en parlant d'HTTP, les connexions persistentes de HTTP 1.1 ne devraient-elles pas résoudre le problème ? Le problème est que les mesures faites avec Chrome (article de Dukkipati et al. cité plus haut) montrent que 35 % des requêtes sont faites sur des nouvelles connexions, ne pouvant pas tirer profit des connexions persistentes.
Bon, mais, au fait, quels sont les avantages exacts qu'il y a à agrandir la fenêtre initiale ? La section 5 les examine en détail. D'abord, on réduit la latence. Par exemple, si on a 21 segments à envoyer, IW3 (fenêtre initiale de trois segments) va nécessiter 4 aller-retour (envoi de données + attente de l'accusé de réception) contre 2 pour IW10. Ensuite, une telle augmentation est cohérente avec l'augmentation régulière de taille des objets. Par exemple, sur le Web, les études citées par le RFC (mesures faites sur le moteur de recherche Google) montrent que seules 10 % des ressources sur le Web tiennent encore dans les 4 ko du RFC 3390. En outre, si on utilise les connexions persistentes de HTTP 1.1, on aura encore plus de données à transmettre sur une connexion HTTP. Le Web grossit, il est logique que la fenêtre initiale de TCP suive le mouvement.
Et il n'y a pas d'inconvénients à augmenter la taille de la fenêtre initiale ? Les sections 6 et 7 décrivent le côté obscur. D'abord, en section 6, les risques pour l'utilisateur. Il y a notamment le risque de remplir complètement les tampons d'entrée-sortie dès le démarrage, pour des petits routeurs. Le RFC estime toutefois que ce risque est faible avec les tampons actuels, en s'appuyant sur l'étude « Characterizing Residential Broadband Networks » de Dischinger, M., Gummadi, K., Haeberlen, A. et S. Saroiu, en 2007, qui montre que le routeur typique de M. Michu a au moins 130 ms de tampon.
Ça, c'était pour l'utilisateur. Et pour le réseau (section 7) ? Risque t-on davantage de congestion ? Probablement pas puisque IW10 ne s'applique qu'au début de la connexion. Tout le reste du mécanisme de contrôle de la congestion de TCP reste en place, inchangé, notamment sa réaction aux pertes de paquets. En revanche, il peut y avoir un problème de justice. Tant qu'une partie des machines applique IW10 et qu'une autre partie en est resté au RFC 3390, les machines IW10 vont prendre une part plus grande des ressources réseau (c'est une question générale de l'Internet : la répartition juste entre différentes connexions concurrentes dépend de leur bonne volonté). C'est donc un point à surveiller. (Un autre problème de justice est traité dans l'annexe A, entre des machines toutes IW10 mais où certaines n'ont pas dix segments à envoyer. Les mesures semblent indiquer que ces dernières machines ne sont pas défavorisées.)
Autre inconvénient possible : comme IW10 remplit plus vite les tampons d'entrée/sortie des routeurs, si ceux-ci sont trop grands (phénomène du bufferbloat), IW10 va aggraver le problème. Les protocoles sensibles à la latence comme le DNS ou certains jeux vont alors souffrir. Les mécanismes proposés comme alternative au bufferbloat (ECN, AQM, etc) sont alors encore plus nécessaires.
En synthèse (section 8), le RFC estime que le plus gros risque est pour les utilisateurs ayant des liaisons lentes avec des tampons d'entrée/sortie réduits, dans leur box. Les 10 segments initiaux peuvent, dans certains cas, faire déborder ces tampons, le réseau ne pouvant pas les envoyer assez vite. Le RFC suggère, si on détecte qu'on est sur un tel lien, de ne pas envoyer forcément les dix segments autorisés, et d'annoncer une fenêtre de réception plus petite. Voir aussi le RFC 3150, sur le problème général de ces liens lents.
La théorie, c'est bien joli mais, quand elle dit qu'il ne faut pas trop s'inquiéter, il est prudent de vérifier par des mesures effectives, pas juste des raisonnements. C'est ce que fait la section 10. L'expérience a été faite par Google dans deux de ses centres de données, l'un voyant plutôt des clients ayant la capacité réseau moyenne, l'autre ayant en moyenne des utilisateurs de connexions lentes (20 % à moins de 100 kb/s). Avec IW10, la latence a baissé de 11,7 % dans le centre moyen et 8,7 % dans le centre lent. En regardant plus finement, les auteurs ont constaté que, comme l'indiquait la théorie, les bénéfices les plus importants d'IW10 ont été pour les gens situés loin (forte latence réseau) mais ayant des connexions rapides (ce qu'on nomme le BDP élévé avec BDP = Bandwidth-Delay Product). Mais, contrairement à la théorie, même les clients à capacité réseau limitée ont vu une amélioration. (Voir l'exposé « Increasing TCP initial window » de Dukkipati, D., Cheng, Y., Chu, J. et M. Mathis, présenté à l'IETF 78 en 2010.) Aucun problème grave n'a été observé.
D'autres expériences ont été faites, listées sur le site Web du projet IW10 ou en section 11 de ce RFC. Notez toutefois que la plupart sont des simulations, pas des mesures sur le vrai Internet. Mais ce n'est pas forcément très grave, l'étude de Google, par son ampleur, a semblé largement suffisante. Bien des RFC ont été adoptés sans une aussi grande étude préalable !
L'annexe A du RFC contient une liste d'inquiétudes théoriques sur IW10 et les résultats des tests spécifiquement liés à chacune de ces inquiétudes. Ainsi, le taux de pertes de paquets n'a pas augmenté lors des tests, sauf lors de cas extrêmes où, même avec les valeurs du RFC 3390, le phénomène de pertes se produisait. De même, des mesures ont été faites en Afrique, pas seulement en Europe et en Amérique du Nord, pour s'assurer qu'IW10 n'aurait pas d'effet pénible pour les liens moins favorisés.
En conclusion, le RFC recommande (section 12) d'activer IW10 mais que les fournisseurs de mises en œuvre de TCP et/ou les administrateurs réseau surveillent le trafic, à la recherche d'indicateurs comme le taux de pertes de paquet, pour détecter une éventuelle augmentation des phénomènes négatifs.
Ce changement de la fenêtre initiale est déjà apparue dans certains
systèmes. Par exemple, pour Linux, cela a été
fait en 2011 dans le commit
git
442b9635c569fef038d5367a7acd906db4677ae1. Notez
que, sur Linux, ip route ... initcwnd N vous
permet d'ajuster cette variable, pour expérimenter.
Un peu de lecture supplémentaire ? Le premier exposé sur IW10 date de
2010. Une argumentation hostile à IW10 ? Vous pouvez lire
l'Internet-Draft draft-gettys-iw10-considered-harmful.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : W. Dec (Cisco Systems), B. Sarikaya (Huawei), G. Zorn (Network Zen), D. Miles (Google), B. Lourdelet (Juniper Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 30 Avril 2013
Le protocole RADIUS joue un rôle important dans l'accès à l'Internet : c'est le principal mécanisme utilisé pour faire communiquer la machine qui contrôle l'accès physique avec la machine qui contient la base des utilisateurs et les informations sur les autorisations, les configurations spécifiques... RADIUS avait bien sûr déjà la capacité de transporter des informations IPv6 mais ce nouveau RFC en ajoute quelques unes.
Une petite révision sur RADIUS d'abord (vous pouvez suivre sur la figure 1 du RFC). Lorsqu'un utilisateur accède à l'Internet, plusieurs machines sont utilisées. Il y a d'abord la machine terminale de l'utilisateur, ou bien un petit routeur, nommé RG (Residential Gateway). L'un des deux porte les informations d'authentification (identificateur et mot de passe). Cette machine terminale ou bien se petit routeur se connecte au réseau et parle à un AN (Access Node : dans le cas de l'ADSL, c'est le DSLAM qui sert d'AN, dans le cas d'un accès commuté, c'est le serveur de modems). L'authentification pourrait être faite par l'AN. Mais l'utilisateur ne parle pas toujours au même AN (par exemple s'il est mobile) et puis, on gagne en souplesse en découplant les fonctions d'accès et d'authentification. On a donc un serveur qui stocke les informations d'authentification et les paramètres des clients, le AAA (Authentication, Authorization and Accounting). Entre l'AN et le AAA se trouve souvent un NAS (Network Access Server), un routeur IP (dans certains cas, AN et NAS sont confondus, par exemple pour la plupart des serveurs PPP). Le NAS est client RADIUS et utilise ce protocole pour demander à l'AAA « j'autorise ce client ? » L'AAA, serveur RADIUS, répond oui ou non et ajoute une série d'attributs, qui sont les paramètres de la session, par exemple l'adresse IP à utiliser. Notez que RADIUS ne sert qu'entre le NAS et le AAA. Entre le RG et le NAS, on peut utiliser plusieurs autres protocoles, comme PPP ou, plus courant aujourd'hui, DHCP (RFC 3315).
RADIUS avait déjà des attributs pour IPv6 :
le RFC 3162 avait Framed-IPv6-Prefix
pour indiquer le préfixe IPv6 à utiliser et
Framed-Interface-Id qui, combiné avec la valeur
précédente, permettait de fabriquer une adresse IP6 pour
l'utilisateur (cette séparation puis recombinaison était plus adaptée
à PPP qu'à DHCP, qui donne des adresses entières). Et le RFC 4818 avait
Delegated-IPv6-Prefix qui permettait de
transmettre un préfixe à déléguer à un routeur par l'option de
délégation DHCP du RFC 3633.
Quels sont ces attributs qui manquaient dans les RFC 3162
et RFC 4818 ? La section 3 en fournit la liste,
et ils sont désormais notés dans le registre
IANA (cf. section 6). Le premier est
Framed-IPv6-Address qui permet d'attribuer une
adresse IPv6 complète au visiteur (a priori via DHCP). Elle peut apparaître dans les
réponses RADIUS, mais aussi dans les questions, pour exprimer un
souhait (que le serveur RADIUS peut ignorer). Framed-IPv6-Address peut être envoyé dans une
réponse RADIUS en même temps que les anciens
Framed-IPv6-Prefix and
Framed-Interface-Id (par exemple si le réseau
local, derrière le RG, utilise à la fois DHCP et l'auto-configuration sans état
- SLAAC).
Le second attribut, DNS-Server-IPv6-Address, indique
l'adresse IP d'un résolveur DNS. (Un seul
résolveur ; mais la réponse RADIUS peut contenir plusieurs attributs
DNS-Server-IPv6-Address, afin de transmettre les
adresses de plusieurs résolveurs.) Ces serveurs DNS peuvent ensuite être indiqués aux machines du réseau
local par les Router Advertisement du RFC 6106 ou bien en DHCP (RFC 3646).
Ensuite, Route-IPv6-Information permet de
spécifier une route statique. L'attribut existant,
Framed-IPv6-Route (RFC 3162), ne suffit
pas car elle est pour l'usage du NAS, il ne la transmet pas au RG. Au
contraire, le nouvel attribut
Route-IPv6-Information est prévu pour être
redistribué. Le NAS pourra transmettre cette information au RG avec les annonces
Router Advertisement du
RFC 4191 ou bien une méthode équivalente. Les autres données
nécessaires dans l'option Route Information de
l'annonce (par exemple la préférence ou la durée de vie), devront
être connues du NAS par un autre moyen (ce point a été le plus chaud
lors des discussions dans le groupe de travail).
Enfin, dernier attribut,
Delegated-IPv6-Prefix-Pool indique le nom d'un
pool d'adresses IPv6 à utiliser par le NAS. Là encore, c'est un
attribute RADIUS conçu pour être relayé avec DHCP mais qui peut
coexister avec Framed-IPv6-Pool, plutôt fait pour les Router
Advertisement.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : M. Cotton (ICANN), L. Vegoda (ICANN), R. Bonica (Juniper), B. Haberman (Johns Hopkins University Applied Physics Lab)
Première rédaction de cet article le 30 Avril 2013
Un certain nombre de préfixes d'adresses IP sont spéciaux, réservés à des tâches comme les exemples dans la documentation, ou bien prévus pour des protocoles particuliers. Ces préfixes n'étaient pas documentés à un endroit unique, ils étaient dans certains RFC, avec parfois des registres IANA. Ce RFC restructure le système, désormais la seule source faisant autorité est le registre IANA (un pour IPv4 et un pour IPv6). En outre, ces deux registres ont désormais une structure bien définie, notamment pour indiquer les propriétés d'un préfixe spécial.
Parmi les nombreux préfixes spéciaux, on peut citer le
0.0.0.0/8 du RFC 1122, qui
sert à désigner le réseau local, ou le fe80::/10
que le RFC 4291 dédie aux adresses locales au
lien. De temps en temps, un RFC rassemble tous
ces préfixes en un seul document et c'est ainsi que le RFC 5735 cataloguait tous les préfixes spéciaux
IPv4 alors que le RFC 5156 faisait la même chose pour
IPv6. Certains préfixes sont affectés à
l'IANA pour une allocation ultérieure (comme le
192.0.0.0/24 du RFC 5736). Ces prefixes-là ont un registre à l'IANA, pour
enregistrer ces allocations mais il n'existait pas de registre général
de toutes les adresses IPv4 spéciales. Même chose en IPv6 : le RFC 2928 et le RFC 4773 affectaient
2001:0000::/23 à l'IANA et créaient un registre
pour les adresses de ce préfixe mais sans prévoir de registre pour
tous les préfixes spéciaux. Résultat, lorsqu'un nouveau préfixe était
déclaré, il n'y avait plus de source à jour, avant qu'on publie un
nouvel RFC de synthèse. Notre RFC 6890 change ce système
et crée
ce registre unique de la totalité des préfixes spéciaux, pour IPv4 et pour IPv6. Notre RFC annule donc
les RFC 5735 et RFC 5156.
La section 2 du RFC liste les décisions prises et que l'IANA devra appliquer (suivant les sections 4.1 et 4.3 du RFC 2680 qui décrit les tâches de l'IANA). Le registre doit conserver, pour chaque préfixe IP, un certain nombre d'informations parmi lesquelles :
Évidemment, si les adresses IP d'un préfixe n'ont pas le droit d'être présentes en destination, les deux booléens suivants (transmissible par un routeur, et unicité mondiale) n'ont pas de sens.
Voici quelques exemples de ces préfixes spéciaux (en mélangeant IPv4 et IPv6 qui, en pratique, sont dans deux registres) :
0.0.0.0/8 : désigne ce réseau local. Décrit
dans la section 3.2.1.3 du RFC 1122. Peut
apparaître en source, pas en destination.10.0.0.0/8 : adressage privé. Décrit dans
le RFC 1918. Peut apparaitre en source et en
destination, transmissible par les routeurs, pas d'unicité
mondiale.2001:10::/28 : préfixe dit
« ORCHID » (Overlay Routable Cryptographic Hash Identifiers), utilisé pour des adressages
sécurisés avec adresse dépendant d'une clé cryptographique. Décrit dans le RFC 4843. Ne peut
apparaitre ni en source, ni en destination (il n'est pas prévu de les
mettre directement dans les champs Source et Destination des paquets IPv6). Non transmissible par les routeurs, pas d'unicité
mondiale (mais une quasi-unicité due à leur choix imprévisible dans un espace très large).100.64.0.0/10 : partage d'adresses en
CGN. Décrit dans le RFC 6598. Peut apparaitre en source et en
destination, transmissible par les routeurs, pas d'unicité
mondiale.169.254.0.0/16 : adresses locales au lien,
typiquement auto-attribuées. Décrit dans le RFC 3927. Peut apparaitre en source et en
destination, non transmissible par les routeurs (locales au lien...), pas d'unicité
mondiale.fc0::/7 :
ULA. Décrit dans le RFC 4193. Peut apparaitre en source et en
destination, transmissible par les routeurs, pas d'unicité
mondiale (il avait été prévu un registre mondial pour une partie de
l'espace des ULA mais cela ne s'était jamais concrétisé).2001:0002::/48 ou 198.18.0.0/15 : adresses réservées pour les
mesures en laboratoire. Décrit dans le RFC 2544 ou le
RFC 5180. Peut apparaitre en source et en
destination, transmissible par les routeurs, pas d'unicité
mondiale.198.51.100.0/24 (et deux autres en IPv4) ou 2001:db8::/32 : adresses réservées à la
documentation. Décrit dans le RFC 5737 ou le
RFC 3849. Ne peut
apparaitre ni en source, ni en destination. Non transmissible par les routeurs, pas d'unicité
mondiale. Notez que, en IPv6, ces adresses pourraient être
quasi-uniques si elles étaient choisies au hasard dans l'espace
immense du 2001:db8::/32. Mais, en pratique, tout
le monde prend la première, 2001:db8::1.Première rédaction de cet article le 25 Avril 2013
Lorsqu'il s'agit de performances des réseaux informatiques, le vocabulaire utilisé, que ce soit sur les forums, sur les réseaux sociaux ou même dans les livres est en général catastrophique, flou et mélangeant tout. D'où deux articles pour préciser rigoureusement ce que sont la latence et la capacité.
D'habitude, lorsque je parle d'un concept comme latence ou capacité, je mets juste un lien vers l'article de Wikipédia. Mais, ici, Wikipédia a curieusement décidé de nommer ce concept d'un terme anglais, lag, un terme que je n'ai jamais entendu en français en dehors du monde du jeu vidéo en ligne. Revenons donc au terme correct, latence.
Pourquoi pinailler sur le vocabulaire ? Parce que, comme je l'indique plus haut, le monde de la mesure de performances est particulièrement mauvais de ce point de vue, préférant des termes flous comme « vitesse ». Ainsi, l'article de Wikipédia sur la latence explique qu'une latence élevée peut être causée par une bande passante insuffisante, ce qui n'est que très approximativement vrai. Et que le vocabulaire flou ou incorrect n'est pas innocent : cela sert par exemple aux commerciaux à vendre des produits inadaptés.
Donc, la latence, c'est simplement le temps que met un message à accomplir un certain trajet. On parle aussi de délai. Elle peut concerner l'aller-simple (c'est ce qu'utilise le RFC 2679) ou l'aller-retour (RFC 2681). Elle n'a pas de lien direct avec la capacité du réseau (ce que certains nomment « bande passante »).
(Avec certains protocoles comme TCP, il y a toutefois une relation subtile entre latence et capacité, voir le RFC 1323.)
Pourquoi est-elle une métrique importante ? Car certaines utilisations du réseau dépendent beaucoup de la latence. Par exemple, des applications interactives (SSH ou XMPP) envoient relativement peu d'octets et sont donc peu sensibles à la capacité du réseau mais le sont beaucoup plus à la latence : lorsque j'envoie un message en XMPP, je voudrais qu'il arrive le plus vite possible, sous peine d'avoir une conversation hachée. D'autres cas d'usage, comme les transferts de gros fichiers, sont relativement insensibles à la latence (si les paramètres de TCP sont corrects).
Certains types de liens réseaux ont une latence particulièrement mauvaise (particulièrement élevée). Ainsi, un satellite géostationnaire ajoute forcément une latence de 238 ms (aller-retour vers le satellite, qui est à 36 000 km d'latitude, divisée par la vitesse de la lumière, qu'on ne peut pas augmenter). C'est une durée très longue et qui explique pourquoi il ne faut utiliser le satellite pour les liaisons Internet que lorsqu'on n'a absolument pas le choix (contrairement à ce que tentent de faire croire les commerciaux qui jouent sur le côté romantique d'une communication spatiale, voir par exemple cette publicité qui parle d'un accès « rapide »).
La définition que j'ai donnée parlait de « message » et, en effet, la latence peut se mesurer dans différentes couches. Le célèbre outil ping mesure une latence aller-retour pour la couche 3 :
% ping6 -c 10 f.root-servers.net ... 10 packets transmitted, 10 received, 0% packet loss, time 9002ms rtt min/avg/max/mdev = 177.097/183.951/192.332/5.940 ms
Ici, la latence moyenne (ping ne calcule hélas pas la médiane) est de 184 millisecondes. Notez que ping n'est pas un outil très précis : il dépend de la charge des deux machines (celle qui pingue et l'amer), il ne connait pas l'instant exact où le premier bit du paquet touche le réseau (cf. RFC 2679), etc. C'est un outil approximatif, mais suffisant dans la plupart des cas. Un exemple de latence mesurée au niveau 7 est fournie par l'outil check-soa pour le DNS. Dans ce cas, la latence mesurée ne dépend pas que du réseau mais aussi de l'application distante (le serveur DNS) :
% check-soa -i societegenerale.com tigdns01.socgen.com. 193.178.155.113: OK: 2013042301 (30 ms) tigdns02.socgen.com. 193.178.155.114: OK: 2013042301 (34 ms)
Dernier exemple, avec HTTP, curl a une option peu connue pour afficher au format qu'on souhaite certains résultats de la connexion :
% curl --silent --write-out "Delay: %{time_total} seconds\n" \
--output /dev/null http://www.societegenerale.com/
Delay: 0.124 seconds
La documentation de curl indique plusieurs autres variables pour étudier les différents facteurs qui, ensemble, composent la latence :
% curl --silent --write-out "Delay: %{time_total} s, TCP connection delay: %{time_connect}, Negociation delay: %{time_starttransfer}\n" \
--output /dev/null http://www.societegenerale.com/
Delay: 0.274 s, TCP connection delay: 0.095, Negociation delay: 0.178
Ici, on voit que le transfert effectif des données ne faisait même pas
la moitié de la latence : la majorité du temps était passé à faire la
connexion TCP puis à envoyer la commande
GET. Pour une page Web de plus grande taille, les
résultats seraient bien sûrs différents.
Un bon article en français expliquant clairement la latence et son importance est « Bande passante et temps de latence réseau » d'Alain Faure. Sinon, le grand classique en anglais est « It's the Latency, Stupid » de Stuart Cheshire.
Première rédaction de cet article le 25 Avril 2013
Dans les discussions ou les textes sur les performances des réseaux informatiques, on voit souvent une grosse confusion entre des termes comme « vitesse » (qui ne veut rien dire), « bande passante » (qui date de l'époque de l'analogique), « débit » et « capacité ». D'où cet article pour préciser rigoureusement ce qu'est la capacité et en quoi elle est différente des autres termes.
Commençons par « bande passante », car ça doit être le terme le plus populaire. Le paradoxe est qu'il vient du monde de l'analogique et désignait l'intervalle de fréquences utilisable, ce qui n'a qu'un très lointain rapport avec la capacité à faire passer plein d'octets en le minimum de temps. Je veux bien que la langue soit imparfaite et qu'un terme ne corresponde pas forcément à son étymologie mais, quand même, je trouve que ce serait plus clair si on n'utilisait pas du tout ces mots dans le monde du numérique.
Ensuite, quelle différence entre débit et capacité ? Le débit est
ce qui passe effectivement dans un réseau à un
moment donné. C'est ce que l'on affiche avec Cacti ou
les logiciels similaires (ici, l'une des machines qui porte ce blog,
dans les dernières 24 heures) :

La capacité est ce qui peut passer si on envoie le plus de données possible. C'est le débit maximum. La confusion entre les deux est très fréquente (par exemple quand on parle d'« Internet à haut débit »). La capacité est définie dans le RFC 5136.
On peut aussi noter que la capacité est mesurée en bits par seconde mais que, dans certains cas, le facteur qui limite le débit est le nombre de paquets par seconde et qu'il est donc parfois bon de mesurer également ce chiffre.
Pour rendre hommage à Tanenbaum, dans un exemple actualisé par André Sintzoff, notons enfin que la capacité réseau d'un train de marchandises dont les wagons sont remplis de cartes MicroSD rendrait jalouse n'importe quelle fibre optique. Mais la latence serait catastrophique...
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Farrell (Trinity College Dublin), D. Kutscher (NEC), C. Dannewitz (University of Paderborn), B. Ohlman, A. Keranen (Ericsson), P. Hallam-Baker (Comodo Group)
Chemin des normes
Première rédaction de cet article le 22 Avril 2013
Dernière mise à jour le 23 Avril 2013
La question des identificateurs sur le
Web agite des électrons depuis le début. Il
n'existe pas d'identificateurs idéaux, ayant toutes
les bonnes propriétés. Dans la grande famille des
URI (RFC 3986), il faut donc choisir selon l'importance
qu'on donne à tel ou tel critère. Par exemple, si on attache du prix à
la stabilité de l'identificateur et qu'on veut qu'il ne désigne pas
seulement un endroit où se trouve un contenu, mais qu'on veut qu'il
désigne ce contenu et pas un autre ? Alors, on peut choisir les
nouveaux URI ni: (Named
Information) qui désignent un contenu par un
condensat (hash). Un URI
ni: ne change pas si le contenu change de
serveur, mais il est modifié si le contenu lui-même change. C'est donc
une forme d'adressage par le contenu.
À quoi cela sert ? À éviter un problème de l'indirection : si je
dis « regardez l'image en
http://www.example.org/holidays/beach.png » et
que l'image de vacances à la plage est remplacée par une photo de
LOLcat, l'URI sera
toujours valable, alors que le contenu a changé. Inversement, si un
webmestre incompétent et qui n'a pas lu
« Cool URIs don't change »
réorganise le site et met le contenu en
http://www.example.org/bigcomplicatedcmswithsecurityholes.php?kind=image&tag=beach&foo=bar&id=612981,
l'URI ne marchera plus alors que le contenu est inchangé. Un autre
exemple, plus positif, est le cas où un contenu est répliqué en
plusieurs endroits, ayant des URL
différents. Il faut pouvoir désigner le contenu, indépendamment du
service qui l'héberge. C'est pour
répondre à ces deux problèmes qu'a été créé par ce
RFC le plan d'URI ni:
(désormais dans le registre IANA des plans d'URI). Le
contenu en question pourra donc être désigné par
ni:///sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc. Une
telle technique a déjà été employée mais de manière non standard (par
exemple, on voit parfois des URI du genre
http://www.example.org/hash?function=sha256&value=rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc
où un programme situé sur www.example.org
récupère la ressource selon le contenu). Désormais, le but est de
permettre du vrai adressage par le contenu sur le Web. Cela se nomme
information-centric sur les
PowerPoint des gourous. Sur ce sujet, le RFC recommande la lecture de « Design
Considerations for a Network of Information » de Ahlgren, D'Ambrosio, Dannewitz, Marchisio, Marsh, Ohlman,
Pentikousis, Rembarz, Strandberg, et Vercellone, ainsi que des articles de Van Jacobson. On peut
aussi lire des articles sur les autres mécanismes d'adressage par le
contenu comme les magnet links de plusieurs systèmes
pair-à-pair, comme Freenet.
Une fois le contenu récupéré (en HTTP ou par d'autres moyens), le lecteur peut alors recalculer le condensat et vérifier s'il a bien reçu le bon fichier (des protocoles comme BitTorrent utilisent un mécanisme analogue pour s'assurer que le fichier transmis par les pairs est bien celui qu'on voulait).
D'autres informations peuvent se retrouver dans l'URI
ni: (voir des exemples plus loin) mais la
comparaison de deux URI ni: se fait uniquement
sur le couple {fonction de hachage utilisée,
valeur du condensat}.
Le condensat est calculé par une fonction de hachage
cryptographique et, par défaut, c'est
SHA-256 (vous avez noté le
sha256 dans l'URI ni: donné
en exemple plus haut ?) Les valeurs possibles pour l'algorithme de
hachage figurent dans un nouveau
registre. Les nouvelles valeurs sont enregistrées selon une
procédure légère d'examen par un expert (RFC 5226 et section 9.4 de notre RFC).
Les condensats de SHA-256 sont de grande taille, parfois trop pour
certaines utilisations. On a donc le droit de les tronquer à leurs N
premiers bits et le nom d'algorithme indiqué doit préciser cette
troncation. Ainsi, si on garde les 32 premiers bits, on doit indiquer
sha256-32 et pas juste
sha256. Attention, c'est évidemment au détriment
de la sécurité (si la sortie de SHA-256 est si longue, c'est pour une
bonne raison, cf. RFC 3766) et ces condensats raccourcis, quoique simples à
manipuler, ne protègent plus tellement. (Notez que le
VCS git, qui identifie
les commits par un condensat
cryptographique, permet également de les raccourcir, pour faciliter
son utilisation, par exemple depuis le
shell.)
Le format exact des URI ni: figure en section
3. On note un composant dont je n'ai pas encore parlé, l'autorité. On
peut écrire
ni:///sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc
mais aussi
ni://www.example.net/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc. L'autorité
(ici, www.example.net) désigne un endroit où on
pourra peut-être récupérer la ressource. Le gros problème des
identificateurs fondés sur le contenu du fichier, en effet, est qu'ils
sont inutiles pour accéder effectivement au fichier : pas moyen de
télécharger un fichier dont on ne connait que le condensat ! Il existe
plusieurs solutions et l'une d'elles est de passer par
l'autorité. L'idée est que l'URI ni: est
automatiquement transformé en un URL HTTP sous
.well-known (cf. RFC 5785 et section 4 de notre RFC). Ainsi,
ni://www.example.net/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc
devient
http://www.example.net/.well-known/ni/sha256/rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc
qu'on peut ensuite récupérer par des moyens classiques. On combine
alors les avantages de l'adressage par le contenu (le condensat est là
pour vérifier le contenu) et du fait que les URL marchent bien pour
récupérer un contenu. On notera que le système d'identificateurs
ARK a un mécanisme analogue (un identificateur
stable et non résolvable plus un préfixe qui
permet de faire un URL résolvable et actionnable). On a ainsi le beurre
et l'argent du beurre. ni fait désormais partie
des termes enregistrés dans le registre "well-known".
Petite question : pourquoi http: et pas
https:, qui serait plus sûr ? Parce que tous les
serveurs ne gèrent pas HTTPS et aussi parce que
ce n'est pas nécessaire pour s'assurer de l'intégrité du fichier
récupéré, le condensat cryptographique suffit. Bien sûr, une mise en
œuvre de ce RFC est autorisée à essayer avec HTTPS, par exemple
pour la confidentialité.
Comme indiqué plus haut, la comparaison entre deux URI
ni: se fait uniquement sur le couple {algorithme,
condensat} donc ni://datastore.example/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc
et
ni://www.example.net/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc
sont identiques.
Au fait, SHA-256 peut être affiché en binaire ou bien sous une
forme hexadécimale. Laquelle est utilisée ? Le format binaire
suivi d'un encodage en
Base64 (RFC 4648), sous
sa forme URL encoding, celle qui utilise
_ et - au lieu de
/ et + (ce n'est pas la forme par
défaut : songez que l'outil base64
sur Unix ne permet pas de produire cette
variante).
Si on n'a pas besoin d'être lisible par des humains et
transmissible dans des textes, il existe aussi une forme binaire, plus
compacte, des URI ni:, spécifiée en section
6.
Signe de leur souplesse, les URI ni: ont
également une forme « prononçable ». S'il faut dicter un URI au
téléphone, l'encodage par défaut est très ambigu (par exemple,
minuscules et majuscules n'ont pas la même
valeur). D'où la syntaxe nih: (NI for
Humans et non pas Not Invented Here, cf. RFC 5513) de la section
7. Les URI sous leur forme nih: sont en
Base16 (RFC 4648), peuvent inclure
des tirets supplémentaires, pour la lisibilité,
et incluent une somme de contrôle (le dernier
chiffre, calculé selon l'algorithme de Luhn de
la norme ISO 7812) pour détecter les erreurs de
compréhension. Un exemple est nih:sha-256-120;5326-9057-e12f-e2b7-4ba0-7c89-2560-a2;f .
Enfin, des paramètres peuvent apparaître dans l'URI, par exemple
pour indiquer le type de la ressource
(ni:///sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc?ct=image/png). Une
liste de paramètres possibles est enregistrée.
À noter que l'abréviation ni veut
officiellement dire Named Information mais que tout
geek va évidemment penser aux chevaliers qui disent Ni...
Avant d'utiliser les URI ni:, il est prudent
de lire la section 10, consacrée aux questions de sécurité. Ainsi, il
ne faut pas oublier que le condensat cryptographique n'est
pas une signature. Il sert
à vérifier l'intégrité mais, comme n'importe qui peut générer un
condensat pour n'importe quel contenu, il ne prouve rien quant à
l'authenticité.
La fonction SHA-256 et ses camarades ne sont
pas inversibles. D'un condensat, on ne peut pas remonter au
contenu. Toutefois, celui-ci n'est pas vraiment secret. Un attaquant
peut toujours deviner plus ou moins le contenu (c'est particulièrement
facile si le contenu est très structuré, avec peu de variations
possibles) et tester les différentes possibilités. Il peut aussi
utiliser un moteur de recherche, si des pages
existent déjà avec la correspondance entre une ressource et son
condensat (pour empêcher cela, il faudrait que les condensats
ni: soient salés, ce qui
n'est pas le cas).
Et, naturellement, si vous utilisez des condensats tronqués, comme le permet de RFC, vous perdez beaucoup en sécurité.
La notion d'autorité dans les URI
ni: peut être trompeuse. Le nom de domaine qui peut apparaître dans un URI
ni: n'est pas forcément la source du contenu,
puisque n'importe qui peut copier la ressource, et la servir depuis un
programme. Il ne faut donc pas attribuer de sémantique à la soi-disant « autorité ».
Si vous voulez regarder un tel système « en vrai », les articles de
ce blog sont tous accessibles via un URI
ni:. L'identificateur est calculé toutes les
nuits et stocké dans une base de données. Un simple petit programme
WSGI permet ensuite de récupérer un fichier
en fonction de son identificateur. À noter que ce n'est pas la forme
HTML qui est utilisée mais le source en
XML (la forme en HTML change trop souvent, par
exemple si les outils qui la produisent automatiquement à partir du
source sont modifiés). Ainsi, l'URI
ni:///sha256;6OuucQ1RgugCDVinT2RGmzYYpra0fenH-zw7tilsx9k
correspond au source XML de cet
article. En indiquant explicitement l'autorité (le serveur qui
permet de faire la récupération), c'est l'URI
ni://www.bortzmeyer.org/sha256;6OuucQ1RgugCDVinT2RGmzYYpra0fenH-zw7tilsx9k. Et
la version sous forme d'URL est . Si
vous préferez un autre article,
http://www.bortzmeyer.org/.well-known/ni/sha256/6OuucQ1RgugCDVinT2RGmzYYpra0fenH-zw7tilsx9kni:///sha256;1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp92lueI
correspond au source de cet article.
Notez qu'il n'est pas possible de mettre l'URI
ni: de l'article que vous êtes en train de lire
dans cet article (inclure le condensat change l'article et il faut
donc changer le condensat, ce qui change l'article...)
Vous voulez vérifier ? Allons-y.
% wget -O /tmp/x.xml http://www.bortzmeyer.org/.well-known/ni/sha256/1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp92lueI ... % openssl dgst -sha256 -binary /tmp/x.xml | base64 1etMCVZtd7/cq38MrtnQcoZW/e7J2cslulrFp92lueI=
Et on retrouve bien l'identificateur 1etMCVZtd... (aux transformations URL encoding près).
Si vous voulez faire depuis le shell Unix les calculs nécessaires, voici quelques exemples avec OpenSSL. Pour calculer le NI de Hello World! :
% echo -n 'Hello World!' | openssl dgst -sha256 -binary | base64 f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk=
Il faut ensuite rechercher/remplacer car base64 (ou bien la commande
openssl enc -base64) ne sait pas faire de
l'URL encoding de Base64. Avec
sed :
% echo -n 'Hello World!' | openssl dgst -sha256 -binary | base64 | sed -e 's#/#_#g' -e 's#+#-#g' -e 's#=$##' f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk
(Pour la même manipulation, on peut aussi utiliser tr :
tr -cd a-zA-Z0-9+/ | tr +/ -_. Comme expliqué par
Kim-Minh Kaplan : « Note le tr -cd pour nettoyer le résultat de l’encodage en Base 64.
Si avec SHA-256 il n’est pas nécessaire, avec SHA-512, l’encodeur
d’OpenSSL introduira un retour à la ligne qu’il faudra aussi supprimer. »)
Si on reprend l'exemple plus haut, on peut combiner les deux opérations : on récupère le fichier grâce au condensat et on vérifie que le contenu est bien le contenu attendu. Utilisons ce simple script :
#!/bin/sh
BASE_URL="http://www.bortzmeyer.org/.well-known/ni/sha256/"
if [ -z "$1" ]; then
echo "Usage: $0 ni" >&2
exit 1
fi
ni=$1
hash=$(wget -q -O - ${BASE_URL}/${ni} | openssl dgst -sha256 -binary | openssl enc -base64 | \
sed -e 's#/#_#g' -e 's#+#-#g' -e 's#=$##')
if [ "$hash" != "$ni" ]; then
echo "Error: hash is $hash instead of $ni" >&2
exit 1
else
exit 0
fi
Et voyons :
% get-and-check-ni 1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp92lueI %
Si on met une valeur fausse :
% get-and-check-ni 1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp922ueI Error: hash is 47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU instead of 1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp922ueI
Si vous voulez lire de source de mon programme, il est dans les fichiers de mon blog, scripts/blog2db/blog2db.py pour le
stockage dans la base de données et wsgis/ni.py pour la récupération.
Il existe une autre implémentation, par certains des auteurs du RFC, en http://sourceforge.net/projects/netinf/.
Si vous voulez d'autres lectures, le RFC 1737. sur les URN, parlait déjà (en
1994) d'utiliser un condensat cryptographque
(avec MD5) pour désigner un contenu. En
2003, une proposition plus élaborée,
draft-thiemann-hash-urn
décrivait un système d'URN avec adressage par le contenu (des choses
comme
urn:hash::sha1:LBPI666ED2QSWVD3VSO5BG5R54TE22QL).
Mais, avec draft-thiemann-hash-urn, il y a un gros manque : pas moyen d'indiquer un (ou
plusieurs, comme dans le cas des magnets) serveur pouvant servir le
document en question. Avec draft-thiemann-hash-urn, on n'a que des
URN (ils ne sont pas « actionnables »). Enfin, si vous voulez une
critique des ni: par rapport aux
magnets, voyez la discussion sur LinuxFr.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : J. Rosenberg (jdrosen.net)
Pour information
Réalisé dans le cadre du groupe de travail IETF simple
Première rédaction de cet article le 22 Avril 2013
Le monde de la messagerie instantanée est marqué par l'absence d'une norme unique et largement reconnue (au contraire de celui du courrier électronique, où SMTP et ses copains ont remplacé tous les concurrents). La plupart des protocoles courants de messagerie instantanée sont fermés et spécifiques à une seule entreprise. Et, même chez les standards ouverts, il y a deux normes, la plus connue, autour de XMPP, et une seconde, issue de la même organisation (l'IETF), autour de SIP. Car SIP ne sert pas qu'à la téléphonie sur IP. C'est un mécanisme de signalisation très général et il peut être utilisé pour la messagerie instantanée. En fait, de nombreux RFC, depuis des années, normalisent l'utilisation de SIP dans ce cas. Tellement nombreux, ces RFC, qu'il faut faire un méta-RFC pour servir de guide. C'est le rôle de ce RFC 6914 : la liste commentée des RFC qui, tous ensemble, décrivent SIMPLE, la messagerie instantanée utilisant SIP.
SIP lui-même est décrit dans le RFC 3261. Ce nouveau RFC 6914 fait la liste des RFC qui décrivent l'utilisation de SIP pour deux services :
Accrochez-vous, la liste est longue et SIMPLE ne mérite guère son nom. À noter que le groupe de travail IETF SIMPLE a été fermé le 26 février 2013, son travail étant considéré comme achevé.
Commençons par la présence (section 2). Elle se décompose en un service de base, permettant de publier des notifications (« je suis disponible ») et de s'y abonner (« qui est réveillé ? »), et une galaxie de services auxiliaires enrichissant tel ou tel aspect du service de base. Le seul service de base compte cinq RFC :
SUBSCRIBE et NOTIFY, au cœur
du service de présence. Il est bâti sur le RFC 3856.Ensuite, comment exprime-t-on les informations publiées et lues ? Le format de base (fondé sur XML) est dans le RFC 3863. Un modèle de données plus général est dans le RFC 4479, avec, dans le RFC 4480, plein d'extensions au format du RFC 3863. Autres extensions, celles du RFC 4481, qui ajoute la gestion du temps (évenements dans le passé et le futur, alors que le RFC 3863 se limitait au présent), et celles du RFC 4482 qui permettent de diffuser des informations sur un correspondant, par exemple une image le représentant.
Enfin, le RFC 5196 permettait d'indiquer, en sus de la présence et des données ci-dessus, les capacités du logiciel SIP qu'on utilise, par exemple pour prévenir ses correspondants qu'on accepte la vidéo.
Tout service de présence soulève évidemment des questions délicates de protection de la vie privée. Je ne souhaite pas forcément que la Terre entière soit au courant de mes déplacements et activités. La section 2.3 décrit les RFC qui s'attaquent au problème de la vie privée dans SIMPLE. Le RFC 4745 définit un format (basé sur XML) pour exprimer des préférences sur la vie privée (du genre « ne jamais diffuser cette information »). Le RFC 5025 utilise ensuite ce format pour décrire les souhaits spécifiques au service de présence. Les RFC 3857 et RFC 3858 décrivent un système d'autorisation préalable où l'utilisateur peut être prévenu si quelqu'un demande s'il est présent.
Un service SIMPLE nécessite un certain nombre de données, par exemple les carnets d'adresse. Comment les enregistre t-on ? Cela se fait avec XCAP (RFC 4825), un protocole qui permet d'envoyer des données stockées en XML. Il en existe des optimisations comme le RFC 5874 qui permet de n'envoyer que les différences avec les données précédentes, pour économiser des ressources réseau. Il se sert pour cela du format XML Diff du RFC 5261. On peut être prévenu de l'apparition de différences avec les mécanismes du RFC 5875. Les formats des données sont ensuite décrites par des documents comme le RFC 4826 (format des carnets d'adresses).
Un des gros intérêts des techniques IETF de messagerie instantanée, comme SIMPLE ou XMPP est qu'elles reposent sur une fédération. Il n'y a pas un service centralisé à qui faire confiance (comme c'est le cas avec les services des silos fermés comme MSN). Chacun peut installer son serveur et les différents serveurs peuvent communiquer entre eux, le DNS leur servant à se trouver. Le RFC 5344 approfondit les mécanismes utilisés pour la fédération.
La présence peut être un service très coûteux. Imaginez que vous receviez des notifications de présence pour une centaine de personnes, et que leurs états changent toutes les minutes (par exemple suite à des connexions/déconnexions). Au-dessus d'une liaison sans-fil, cela peut faire mal au réseau. Le RFC 4460 fournit donc des mécanismes de filtrage, pour ne pas tout recevoir. Les règles sont écrites dans le format du RFC 4461. Le RFC 5262 permet de ne pas recevoir la totalité de la notification mais uniquement la partie qui a changé (là encore, avec le format XML Diff du RFC 5261).
Maintenant qu'on en a terminé avec la présence (un service bien
plus compliqué qu'il n'avait l'air au premier abord), revenons à la
messagerie instantanée proprement dite (section 3). Dans SIMPLE, il y
a deux modes de fonctionnement pour celle-ci. En mode non connecté
(page mode, analogue au
SMS), une requête SIP
MESSAGE est envoyée au
destinataire, contenant le message. En mode connecté (session
mode), une INVITE SIP est envoyée au
destinataire et, une fois la session établie, on envoie les textes de
la conversation, comme on enverrait de l'audio avec de la téléphonie
SIP.
Le RFC 3428 décrit le mode non connecté et la méthode
MESSAGE, le « texto » de SIP. Le RFC 5365 l'étend au cas où
il y a plusieurs destinataires.
Le mode connecté utilise des méthodes SIP classiques et sa description est uniquement celle des types de données envoyées, notamment RFC 4975 pour le type « message texte » et RFC 3862 pour les méta-données.
Une extension très utile aux services de messagerie instantanée est la pièce collective (chat room, ou MUC - pour Multi-User Channel en XMPP). SIMPLE réutilise pour cela les mécanismes de conférence de SIP, normalisés dans les RFC 4353 et RFC 5239. Ensemble, ils indiquent comment on rejoint une conférence, comment on la quitte, etc.
Enfin (rassurez-vous, on arrive au bout), deux fonctions sympa : l'indication de composition dans le RFC 3994 (permettant d'indiquer que le correspondant est en train de taper un texte, il faut patienter), et l'accusé de réception dans le RFC 5438.
Voilà, vous savez désormais tout ce qu'il faut lire si vous voulez faire de la messagerie instantanée avec SIP...
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : F. Gont (UTN-FRH / SI6 Networks), C. Pignataro (Cisco Systems)
Chemin des normes
Première rédaction de cet article le 18 Avril 2013
Allez, encore un peu de nettoyage dans les registres IANA. Le protocole ICMP pour IPv4 a plein de types de messages différents. Beaucoup sont dépassés mais n'avaient pas été officiellement marqués comme tel. Ce RFC range le registre et reclasse quinze types de messages. En revoyant ces types, nous plongeons dans les essais ratés de TCP/IP...
La notion de type de message ICMP est normalisée dans le RFC 792. Les plus connus des types de message ICMPv4 sont le 8 (echo request) et le 0 (echo reply) à cause de leur utilisation dans ping. Mais il existe bien d'autres types, enregistrés à l'IANA et servant à de nombreuses fonctions discrètes, mais indispensables (comme l'indication qu'un paquet n'a pas pu être délivré, type 3). Le registre des types a aussi vu l'arrivée d'un certain nombre de types expérimentaux, qui n'ont guère eu de succès, et notre RFC s'occupe de les trier. (Rappelez-vous qu'IPv6 a un autre registre ICMP, complètement différent.)
Voici donc la liste des types abandonnés :
draft-simpson-ipv6-mobility qui n'est jamais
devenu un RFC.)Tous ces types sont désormais marqués Deprecated dans le registre IANA.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Donald Eastlake (Huawei)
Chemin des normes
Première rédaction de cet article le 18 Avril 2013
Il existe tout un ensemble de normes pour assurer la sécurité de documents XML, par exemple les protéger contre la lecture non autorisée, ou bien permettre leur authentification. Ces normes dépendent d'algorithmes cryptographiques identifiés par un URI. Ce RFC met à jour la liste précédente de ces URI (qui était dans le RFC 4051) et crée un registre des identificateurs d'algorithmes.
Ces normes de sécurité de XML étaient à l'origine un travail conjoint de l'IETF et du W3C. C'était par exemple le cas des signatures XML du RFC 3275, du XML canonique des RFC 3076 ou RFC 3741. Elles sont désormais maintenues par le W3C qui a produit des versions plus récentes (par exemple pour les signatures XML, le XML canonique ou le chiffrement XML).
Dans un monde dynamique comme celui de la
cryptographie, où les progrès de la
cryptanalyse nécessitent des changements
d'algorithmes, les normes ne sont pas liées à un algorithme
particulier. Elles permettent l'agilité cryptographique (le changement
d'algorithme) et il faut donc pouvoir indiquer quel algorithme est
utilisé pour signer ou chiffrer un document donné. Pour une norme
W3C, on ne s'étonnera pas que l'indication se
fait par le biais d'un URI. Ceux-ci commencent
désormais par le préfixe
http://www.w3.org/2007/05/xmldsig-more# (les
anciens algorithmes pouvant avoir d'autres préfixes). Ces nouveaux
algorithmes (avec 2007/05 dans leur
identificateur) sont relativement rares dans ce RFC : on n'invente
quand même pas un bon algorithme de cryptographie tous les jours et la
plupart des exemples dans cet article utilisent donc le vieux
préfixe. Rappelez-vous qu'il s'agit d'URI, pas
forcément d'URL et que vous n'obtiendrez donc
pas forcément un résultat en pointant votre navigateur
Web vers http://www.w3.org/2001/04/xmlenc#sha256.
Notons que notre RFC 6931 ne prend pas position sur la qualité cryptographique des algorithmes : il fournit un moyen de les désigner sans ambiguité, c'est tout. Si on veut étudier cette qualité cryptographique, il faut lire d'autres documents (comme le RFC 6194 pour SHA-1).
Un exemple d'un ancien algorithme est MD5
pour calculer les condensats
cryptographiques. Son URI est
http://www.w3.org/2001/04/xmldsig-more#md5. Sa
sécurité est aujourd'hui sérieusement battue en brèche (cf. RFC 6151). Autre exemple d'un algorithme qui était déjà dans le
RFC 4051, SHA-384, identifié par http://www.w3.org/2001/04/xmldsig-more#sha384.
Un exemple d'un nouvel algorithme pour la condensation
cryptographique ? Le NIST ayant récemment
annoncé que le vainqueur du concours « SHA-3 »
était Keccak, des URI utilisant le nouveau
préfixe ont été créés pour lui, par exemple
http://www.w3.org/2007/05/xmldsig-more#sha3-512
(regardez bien : sha-3 et plus
sha, et la nouvelle date dans le préfixe).
Il existe aussi des identificateurs pour les
MAC combinés avec une condensation, par exemple
http://www.w3.org/2001/04/xmldsig-more#hmac-sha512
(RFC 6234).
Et pour les signatures avec un système à clé
publique ? L'identificateur indique l'algorithme de
cryptographie asymétrique et celui de condensation, par exemple
http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
(voir aussi le RFC 3447). SHA-256
n'est pas tout récent et, si vous cherchez un algorithme enregistré
par notre nouveau RFC, pourquoi pas Whirlpool
avec http://www.w3.org/2007/05/xmldsig-more#rsa-whirlpool. Si on trouve
RSA ennuyeux, il existe aussi des
identificateurs pour un algorithme à courbes
elliptiques (RFC 6090 mais notez ses errata), ECDSA, par exemple
http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512.
Enfin, il y a les algorithmes de chiffrement symétrique. Par exemple, Camellia (RFC 3713) sera identifié par
http://www.w3.org/2001/04/xmldsig-more#camellia256-cbc. Le
plus récent SEED (RFC 4269) sera http://www.w3.org/2007/05/xmldsig-more#seed128-cbc.
Voici pour la cryptographie. Mais les normes de sécurité XML
prévoient aussi une étape de canonicalisation avant chiffrement ou
signature, et là aussi, il y a plusieurs algorithmes, identifiés par
des URI comme http://www.w3.org/2000/09/xmldsig#minimal ou http://www.w3.org/2006/12/xmlc14n11#WithComments.
Quelle est la politique d'allocation dans le nouveau registre ? La
section 5 décrit celle du W3C (le préfixe
http://www.w3.org/2007/05/xmldsig-more# est figé,
a priori, on n'y mettra pas de nouveaux algorithmes) et celle de
l'IETF : comme il est facile d'obtenir un URI (n'importe qui peut en
créer un), la seule question est celle de leur enregistrement. Il se
fera après un examen par un expert (voir le RFC 5226 pour les politiques d'allocation IETF) après
publication d'un texte décrivant le nouvel algorithme.
Quels changements depuis la version précédente de ce RFC, le RFC 4051 ? L'annexe A les liste. Les principaux, à mon avis, sont :
Articles des différentes années : 2013 2012 2011 2010 2009 2008 2007 Précédentes années
Syndication : Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu