Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Ève

Les RFC (Request For Comments) sont les documents de référence de l'Internet. Produits par l'IETF pour la plupart, ils spécifient des normes, documentent des expériences, exposent des projets...

Leur gratuité et leur libre distribution ont joué un grand rôle dans le succès de l'Internet, notamment par rapport aux protocoles OSI de l'ISO organisation très fermée et dont les normes coûtent cher.

Je ne tente pas ici de traduire les RFC en français (un projet pour cela existe mais je n'y participe pas, considérant que c'est une mauvaise idée), mais simplement, grâce à une courte introduction en français, de donner envie de lire ces excellents documents. (Au passage, si vous les voulez présentés en italien...)

Le public visé n'est pas le gourou mais l'honnête ingénieur ou l'étudiant.


RFC 8360: Resource Public Key Infrastructure (RPKI) Validation Reconsidered

Date de publication du RFC : Avril 2018
Auteur(s) du RFC : G. Huston (APNIC), G. Michaelson (APNIC), C. Martinez (LACNIC), T. Bruijnzeels (RIPE NCC), A. Newton (ARIN), D. Shaw (AFRINIC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF sidr
Première rédaction de cet article le 6 avril 2018


La RPKI est un ensemble de formats et de règles pour certifier qui est le titulaire d'une ressource Internet, une ressource étant un préfixe d'adresses IP, un numéro de système autonome, etc. La RPKI est utilisée dans les mécanismes de sécurisation de BGP, par exemple pour vérifier qu'un AS est bien autorisé à être à l'origine d'un préfixe donné. Les règles initiales de la RPKI pour valider un certificat était trop strictes et ce RFC les assouplit légèrement (normalement, en gardant le même niveau de sécurité).

La RPKI est normalisée dans le RFC 6480. Elle prévoit notamment un système de certificats par lequel une autorité affirme qu'une autorité de niveau inférieur a bien reçu une délégation pour un groupe de ressources Internet. (On appelle ces ressources les INR, pour Internet Number Resource.) La validation des certificats est décrite dans le RFC 6487. L'ancienne règle était que le certificat de l'autorité inférieure ne devait lister que des ressources qui étaient dans le certificat de l'autorité qui signait (RFC 6487, section 7.2, notamment la condition 6 de la seconde énumération). En pratique, cette règle s'est avérée trop rigide, et la nouvelle, décrite dans notre RFC 8360 est que le certificat de l'autorité inférieure n'est accepté que pour des ressources qui étaient dans le certificat de l'autorité qui signait. S'il y a d'autres ressources, le certificat n'est plus invalide, simplement, ces ressources sont ignorées. Dit autrement, l'ensemble des ressources dont la « possession » est certifiée, est l'intersection des ressources du certificat de l'autorité parente et de celui de l'autorité fille. Cette intersection se nomme VRS, pour Verified Resource Set.

Voici d'abord une chaîne de certificats qui était valide avec l'ancienne règle, et qui l'est toujours :

Certificate 1 (trust anchor):
Issuer TA,
Subject TA,
Resources 192.0.2.0/24, 198.51.100.0/24,
      2001:db8::/32, AS64496-AS64500

Certificate 2:
Issuer TA,
Subject CA1,
Resources 192.0.2.0/24, 198.51.100.0/24, 2001:db8::/32

Certificate 3:
Issuer CA1,
Subject CA2,
Resources 192.0.2.0/24, 198.51.100.0/24, 2001:db8::/32

ROA 1:
Embedded Certificate 4 (EE certificate):
Issuer CA2,
Subject R1,
Resources 192.0.2.0/24
    

La chaîne part d'un certificat (TA, pour Trust Anchor, le point de départ de la validation). Elle aboutit à un ROA (Route Origin Authorization, cf. RFC 6482). Chaque certificat est valide puisque chacun certifie un jeu de ressources qui est un sous-ensemble du jeu de ressources de l'autorité du dessus. Idem pour le ROA.

Et voici par contre une chaîne de certificats qui était invalide selon les anciennes règles, et est désormais valide avec les règles de notre RFC 8360 :

Certificate 1 (trust anchor):
Issuer TA,
Subject TA,
Resources 192.0.2.0/24, 198.51.100.0/24,
     2001:db8::/32, AS64496-AS64500

Certificate 2:
Issuer TA,
Subject CA1,
Resources 192.0.2.0/24, 2001:db8::/32

Certificate 3 (invalid before, now valid):
Issuer CA1,
Subject CA2,
Resources 192.0.2.0/24, 198.51.100.0/24, 2001:db8::/32

ROA 1 (invalid before, now valid):
Embedded Certificate 4 (EE certificate, invalid before, now valid):
Issuer CA2,
Subject R1,
Resources 192.0.2.0/24

La chaîne était invalide car le troisième certificat ajoutait 198.51.100.0/24, qui n'était pas couvert par le certificat supérieur. Désormais, elle est valide mais vous noterez que seuls les préfixes 192.0.2.0/24 et 2001:db8::/32 sont couverts, comme précédemment (198.51.100.0/24 est ignoré). Avec les règles de notre nouveau RFC, le ROA final est désormais valide (il n'utilise pas 198.51.100.0/24). Notez que les nouvelles règles, comme les anciennes, n'autoriseront jamais l'acceptation d'un ROA pour des ressources dont l'émetteur du certificat n'est pas titulaire (c'est bien le but de la RPKI). Ce point est important car l'idée derrière ce nouveau RFC de rendre plus tolérante la validation n'est pas passée toute seule à l'IETF.

Un cas comme celui des deux chaînes ci-dessus est probablement rare. Mais il pourrait avoir des conséquences sérieuses si une ressource, par exemple un préfixe IP, était supprimée d'un préfixe situé très haut dans la hiérarchie : plein de certificats seraient alors invalidés avec les règles d'avant.

La section 4 de notre RFC détaille la procédure de validation. Les anciens certificats sont toujours validés avec l'ancienne politique, celle du RFC 6487. Pour avoir la nouvelle politique, il faut de nouveaux certificats, identifiés par un OID différent. La section 1.2 du RFC 6484 définissait id-cp-ipAddr-asNumber / 1.3.6.1.5.5.7.14.2 comme OID pour l'ancienne politique. La nouvelle politique est id-cp-ipAddr-asNumber-v2 / 1.3.6.1.5.5.7.14.3 et c'est elle qui doit être indiquée dans un certificat pour que lui soient appliquées les nouvelles règles. (Ces OID sont dans un registre IANA.) Comme les logiciels existants rejetteront les certificats avec ces nouveaux OID, il faut adapter les logiciels avant que les AC ne se mettent à utiliser les nouveaux OID (cf. section 6 du RFC). Les changements du RFC n'étant pas dans le protocole mais uniquement dans les règles de validation, le déploiement devrait être relativement facile.

Le cœur des nouvelles règles est dans la section 4.2.4.4 de notre RFC, qui remplace la section 7.2 du RFC 6487. Un nouveau concept est introduit, le VRS (Verified Resource Set). C'est l'intersection des ressources d'un certificat et de son certificat supérieur. Dans le deuxième exemple plus haut, le VRS du troisième certificat est {192.0.2.0/24, 2001:db8::/32}, intersection de {192.0.2.0/24, 2001:db8::/32} et {192.0.2.0/24, 198.51.100.0/24, 2001:db8::/32}. Si le VRS est vide, le certificat est invalide (mais on ne le rejette pas, cela peut être un cas temporaire puisque la RPKI n'est pas cohérente en permanence).

Un ROA est valide si les ressources qu'il contient sont un sous-ensemble du VRS du certificat qui l'a signé (si, rappelons-le, ce certificat déclare la nouvelle politique). La règle exacte est un peu plus compliquée, je vous laisse lire le RFC pour les détails. Notez qu'il y a également des règles pour les AS, pas seulement pour les préfixes IP.

La section 5 du RFC contient davantage d'exemples, illustrant les nouvelles règles.


Téléchargez le RFC 8360


L'article seul

RFC 8358: Update to Digital Signatures on Internet-Draft Documents

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : R. Housley (Vigil Security)
Pour information
Première rédaction de cet article le 13 mars 2018
Dernière mise à jour le 5 avril 2018


Les Internet-Drafts sont signés suivant les règles du RFC 5485, afin qu'une lectrice ou un lecteur puissent vérifier qu'un Internet-Draft n'a pas été modifié en cours de route. Ce nouveau RFC modifie légèrement le RFC 5485 sur un seul point : la signature d'Internet-Drafts qui sont écrits en Unicode.

En effet, depuis le RFC 7997, les RFC ne sont plus forcément en ASCII, ils peuvent intégrer des caractères Unicode. Le premier RFC publié avec ces caractères a été le RFC 8187, en septembre 2017. Bientôt, cela sera également possible pour les Internet-Drafts. Cela affecte forcément les règles de signature, d'où cette légère mise à jour.

Le RFC 5485 normalisait l'utilisation de CMS (RFC 5652) pour le format des signatures. Vous pouvez télécharger ces signatures sur n'importe lequel des sites miroirs. CMS utilise ASN.1, avec l'obligation d'utiliser l'encodage DER, le seul encodage d'ASN.1 qui ne soit pas ambigu (une seule façon de représenter un texte).

Les Internet-Drafts sont actuellement tous en texte brut, limité à ASCII. Mais cela ne va pas durer (RFC 7990). Les signatures des Internet-Drafts sont détachées de l'Internet-Draft (section 2 de notre RFC), dans un fichier portant le même nom auquel on ajoute l'extension .p7s (RFC 5751). Par exemple avec wget, pour récupérer un Internet-Draft et sa signature :

% wget  https://www.ietf.org/id/draft-bortzmeyer-dname-root-05.txt
% wget  https://www.ietf.org/id/draft-bortzmeyer-dname-root-05.txt.p7s

(Ne le faites pas avec un Internet-Draft trop récent, les signatures n'apparaissent qu'au bout de quelques jours, la clé privée n'est pas en ligne.)

La signature est au format CMS (RFC 5652). Son adaptation aux RFC et Internet-Drafts est normalisée dans le RFC 5485. Le champ SignedData.SignerInfo.EncapsulatedContentInfo.eContentType du CMS identifie le type d'Internet-Draft signé. Les valeurs possibles figurent dans un registre IANA. Il y avait déjà des valeurs comme id-ct-asciiTextWithCRLF qui identifiait l'Internet-Draft classique en texte brut en ASCII, notre RFC ajoute (section 5) id-ct-utf8TextWithCRLF (texte brut en UTF-8), id-ct-htmlWithCRLF (HTML) et id-ct-epub (EPUB). Chacun de ces types a un OID, par exemple le texte brut en UTF-8 sera 1.2.840.113549.1.9.16.1.37.

Maintenant, passons à un morceau délicat, la canonicalisation des Internet-Drafts. Signer nécessite de canonicaliser, autrement, deux textes identiques aux yeux de la lectrice pourraient avoir des signatures différentes. Pour le texte brut en ASCII, le principal problème est celui des fins de ligne, qui peuvent être représentées différemment selon le système d'exploitation. Nous utilisons donc la canonicalisation traditionnelle des fichiers texte sur l'Internet, celle de FTP : le saut de ligne est représenté par deux caractères, CR et LF. Cette forme est souvent connue sous le nom de NVT (Network Virtual Terminal) mais, bien que très ancienne, n'avait été formellement décrite qu'en 2008, dans l'annexe B du RFC 5198, qui traitait pourtant un autre sujet.

Pour les Internet-Drafts au format XML, notre RFC renvoie simplement au W3C et à sa norme XML, section 2.11 de la cinquième édition, qui dit qu'il faut translating both the two-character sequence #xD #xA and any #xD that is not followed by #xA to a single #xA character. La canonicalisation XML (telle que faite par xmllint --c14n) n'est pas prévue.

Les autres formats ne subissent aucune opération particulière de canonicalisation. Un fichier EPUB, par exemple, est considéré comme une simple suite d'octets. On notera que le texte brut en Unicode ne subit pas de normalisation Unicode. C'est sans doute à cause du fait que le RFC 7997, dans sa section 4, considère que c'est hors-sujet. (Ce qui m'a toujours semblé une drôle d'idée, d'autant plus qu'il existe une norme Internet sur la canonicalisation du texte brut en Unicode, RFC 5198, qui impose la normalisation NFC.)

À l'heure actuelle, les Internet-Drafts sont signés, les outils doivent encore être adaptés aux nouvelles règles de ce RFC, mais elles sont simples et ça ne devrait pas être trop dur. Pour vérifier les signatures, la procédure (qui est documentée) consiste d'abord à installer le logiciel de canonicalisation :

% wget  https://www.ietf.org/id-info/canon.c    
% make canon
    

Puis à télécharger les certificats racine :

% wget  https://www.ietf.org/id-info/verifybundle.pem
    

Vous pouvez examiner ce groupe de certificats avec :

% openssl crl2pkcs7 -nocrl -certfile verifybundle.pem  | openssl pkcs7 -print_certs -text
    

Téléchargez ensuite des Internet-Drafts par exemple en https://www.ietf.org/id/ :

% wget      https://www.ietf.org/id/draft-ietf-isis-sr-yang-03.txt 
% wget         https://www.ietf.org/id/draft-ietf-isis-sr-yang-03.txt.p7s

On doit ensuite canonicaliser l'Internet-Draft :

% ./canon draft-ietf-isis-sr-yang-03.txt draft-ietf-isis-sr-yang-03.txt.canon

On peut alors vérifier les signatures :

% openssl cms -binary -verify -CAfile verifybundle.pem -content draft-ietf-isis-sr-yang-03.txt.canon -inform DER -in draft-ietf-isis-sr-yang-03.txt.p7s -out /dev/null
Verification successful

Si vous avez à la place :

Verification failure
139818719196416:error:2E09A09E:CMS routines:CMS_SignerInfo_verify_content:verification failure:../crypto/cms/cms_sd.c:819:
139818719196416:error:2E09D06D:CMS routines:CMS_verify:content verify error:../crypto/cms/cms_smime.c:393:
 

c'est sans doute que vous avez oublié l'option -binary.

Si vous trouvez la procédure compliquée, il y a un script qui automatise tout ça idsigcheck :

% ./idsigcheck --setup      
% ./idsigcheck draft-ietf-isis-sr-yang-03.txt
    

Si ça vous fait bad interpreter: /bin/bash^M, il faut recoder les sauts de ligne :

% dos2unix idsigcheck 
dos2unix: converting file idsigcheck to Unix format...
    

Ce script appelle OpenSSL mais pas avec les bonnes options à l'heure actuelle, vous risquez donc d'avoir la même erreur que ci-dessus.


Téléchargez le RFC 8358


L'article seul

RFC 8354: Use Cases for IPv6 Source Packet Routing in Networking (SPRING)

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : J. Brzozowski, J. Leddy (Comcast), C. Filsfils, R. Maglione, M. Townsley (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF spring
Première rédaction de cet article le 29 mars 2018


Le sigle SPRING signifie « Source Packet Routing In NetworkinG ». C'est quoi, le routage par la source (source routing) ? Normalement, la transmission de paquets IP se fait uniquement en fonction de l'adresse de destination, chaque routeur sur le trajet prenant sa décision indépendemment des autres, et sans que l'émetteur original du paquet n'ait son mot à dire. L'idée du routage par la source est de permettre à cet émetteur d'indiquer par où il souhaite que son paquet passe. L'idée est ancienne, et resurgit de temps en temps sur l'Internet. Ce nouveau RFC décrit les cas où une solution de routage par la source serait utile.

L'idée date des débuts de l'Internet. Par exemple, la norme IPv4, le RFC 791, spécifie, dans sa section 3.1, deux mécanismes de routage par la source, « Loose Source Routing » et « Strict Source Routing ». Mais ces mécanismes sont peu déployés et vous n'avez guère de chance, si vous mettez ces options dans un paquet IP, de voir un effet. En effet, le routage par la source est dangereux, il permet des attaques variées, et il complique beaucoup le travail des routeurs. Le but du projet SPRING, dont c'est le deuxième RFC, est de faire mieux. Le cahier des charges du projet est dans le RFC 7855.

L'architecture technique de SPRING est dans un document pas encore publié, draft-ietf-spring-segment-routing. Ce segment routing est déjà mis en œuvre dans le noyau Linux depuis la version 4.14 (cf. le site du projet). Notre nouveau RFC 8354 ne contient, lui, que les scénarios d'usage. (Certains étaient déjà dans la section 3 du RFC 7855.) Seul IPv6 est pris en compte.

D'abord, le cas du SOHO connecté à plusieurs fournisseurs d'accès. Comme chacun de ces fournisseurs n'acceptera que des paquets dont l'adresse IP source est dans un préfixe qu'il a alloué au client, il est essentiel de pouvoir router en fonction de la source, afin d'envoyer les paquets ayant une adresse source du FAI A vers le FAI A et seulement celui-ci. Voici par exemple comment faire sur Linux, quand on veut envoyer les paquets ayant l'adresse IP source 2001:db8:dc2:45:216:3eff:fe4b:8c5b vers un routeur différent de l'habituel (le RFC 3178 peut être une bonne lecture, quoique daté, notamment sa section 5) :

#!/bin/sh

DEVICE=eth1
SERVICE=2001:db8:dc2:45:216:3eff:fe4b:8c5b
TABLE=CustomTable
ROUTER=2001:db8:dc2:45:1

echo 200 ${TABLE} >> /etc/iproute2/rt_tables
ip -6 rule add from ${SERVICE} table ${TABLE}
ip -6 route add default via ${ROUTER} dev ${DEVICE} table ${TABLE}
ip -6 route flush cache
    

Notez que la décision correcte peut être prise par la machine terminale, comme dans l'exemple ci-dessus, ou bien par un routeur situé plus loin sur le trajet (dans le projet SPRING, la source n'est pas forcément la machine terminale initiale).

Outre le fait que le FAI B rejetterait probablement les paquets ayant une adresse source qui n'est pas à lui (RFC 3704), il peut y avoir d'autres raisons pour envoyer les paquets sur une interface de sortie particulière :

  • Elle est plus rapide,
  • Elle est moins chère (pensez à un réseau connecté en filaire mais également à un réseau mobile avec forfait « illimité » ce qui, en langage telco, veut dire ayant des limites),
  • Dans le cas du télétravailleur, il peut être souhaitable de faire passer les paquets de la machine personnelle par un FAI payé par le télétravailleur et ceux de la machine de bureau par un FAI payé par l'employeur.

Autre cas où un routage par la source peut être utile, le FAI peut s'en servir pour servir certains utilisateurs ou certains usages dans des conditions différentes, par exemple avec des prix à la tête du client. Cela viole sans doute la neutralité du réseau mais c'est peut-être un scénario qui en tentera certains (sections 2.2 et 2.5 du RFC). Cela concerne le réseau d'accès (de M. Michu au FAI) et aussi le cœur de réseau ; « l'opérateur peut vouloir configurer un chemin spécial pour les applications sensibles à la latence ».

De plus haute technologie est le scénario présenté dans la section 2.3. Ici, il s'agit d'un centre de données entièrement IPv6. Cela simplifie considérablement la gestion du réseau, et cela permet d'avoir autant d'adresses qu'on veut, sans se soucier de la pénurie d'adresses IPv4. Certains opérateurs travaillent déjà à de telles configurations. Dans ce cas, le routage par la source serait un outil puissant pour, par exemple, isoler différents types de trafic et les acheminer sur des chemins spécifiques.

Si le routage par la source, une très vieille idée, n'a jamais vraiment pris, c'est en grande partie pour des raisons de sécurité. La section 4 rappelle les risques associés, qui avaient mené à l'abandon de la solution « Type 0 Routing Header » (cf. RFC 5095).


Téléchargez le RFC 8354


L'article seul

RFC 8352: Energy-Efficient Features of Internet of Things Protocols

Date de publication du RFC : Avril 2018
Auteur(s) du RFC : C. Gomez (UPC), M. Kovatsch (ETH Zurich), H. Tian (China Academy of Telecommunication Research), Z. Cao (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF lwig
Première rédaction de cet article le 7 avril 2018


Les objets contraints, engins connectés ayant peu de capacités (un capteur de température dans la nature, par exemple), ont en général une réserve d'énergie électrique très limitée, fournie par des piles ou batteries à la capacité réduite. L'usage des protocoles de communication traditionnels, souvent très bavards, épuiserait rapidement ces réserves. Ce RFC étudie les mécanismes utilisables pour limiter la consommation électrique, et faire ainsi durer ces objets plus longtemps.

La plupart des protocoles de couche 2 utilisés pour ces « objets contraints » disposent de fonctions pour diminuer la consommation électrique. Notre RFC décrit ces fonctions, et explique comment les protocoles de couches supérieures, comme IP peuvent en tirer profit. Si vous ne connaissez pas le monde des objets contraints, et les problèmes posés par leur connexion à l'Internet, je recommande fortement la lecture des RFC 6574, RFC 7228, et RFC 7102. Le but des techniques présentées dans ce RFC est bien de faire durer plus longtemps la batterie, ce n'est pas un but écologique. Si l'objet est alimenté en permanence (une télévision connectée, ou bien un grille-pain connecté), ce n'est pas considéré comme problème.

Des tas de travaux ont déjà eu lieu sur ce problème de la diminution de la consommation électrique de ces objets. Il y a eu moins d'efforts sur celle des protocoles réseau, et ce sont ces efforts que résume ce RFC. Les protocoles traditionnels étaient conçus pour des machines alimentées en permanence et pour qui la consommation électrique n'était pas un problème. Diffuser très fréquemment une information, même inutile, n'était pas perçu comme du gaspillage, contrairement à ce qui se passe avec l'Internet des Objets. (Voir le RFC 7772 pour une solution à un tel problème.)

L'IETF a déjà développé un certain nombre de protocoles qui sont spécifiques à cet « Internet des Objets ». Ce sont par exemple 6LoWPAN (RFC 6282, RFC 6775 et RFC 4944), ou bien le protocole de routage RPL (RFC 6550) ou encore l'alternative à HTTP CoAP (RFC 7252). En gros, l'application fait tourner du CoAP sur IPv6 qui est lui-même au-dessus de 6LoWPAN, couche d'adaptation d'IP à des protocoles comme IEEE 802.15.4. Mais l'angle « économiser l'énergie » n'était pas toujours clairement mis en avant, ce que corrige notre nouveau RFC.

Qu'est ce qui coûte cher à un engin connecté (cher en terme d'énergie, la ressource rare) ? En général, faire travailler le CPU est bien moins coûteux que de faire travailler la radio, ce qui justifie une compression énergique. Et, question réseau, la réception n'est pas forcément moins coûteuse que la transmission. L'étude Powertrace est une bonne source de mesures dans ce domaine mais on peut également lire « Measuring Power Consumption of CC2530 With Z-Stack ». Le RFC contient aussi (section 2) des chiffres typiques, mesurés sur Contiki et publiés dans « The ContikiMAC Radio Duty Cycling Protocol » :

  • Écouter pendant une seconde : 63 000 μJ,
  • Réception d'un paquet : 178 μJ pour un paquet diffusé et 222 μJ autrement,
  • Transmission d'un paquet : de 120 à 1 790 μJ selon les cas.

Une technique courante quand on veut réduire la consommation électrique lors de la transmission est de réduire la puissance d'émission. Mais cela réduit la portée, donc peut nécessiter d'introduire du routage, ce qui augmenterait la consommation.

On a vu que la simple écoute pouvait consommer beaucoup d'énergie. Il faut donc trouver des techniques pour qu'on puisse couper l'écoute (éteindre complètement la radio), tout en gardant la possibilité de parler à l'objet si nécessaire. Sans ce duty-cycling (couper la partie radio de l'objet, cf. RFC 7228, section 4.3), la batterie ne durerait que quelques jours, voire quelques heures, alors que certains objets doivent pouvoir fonctionner sans entretien pendant des années. Comment couper la réception tout en étant capable de recevoir des communications ? Il existe trois grandes techniques de RDC (Radio Duty-Cycling, section 3 de notre RFC) :

  • Échantillonage : on n'est pas en réception la plupart du temps mais on écoute le canal à intervalles réguliers. Les objets qui veulent me parler doivent donc émettre un signal pendant une durée plus longue que la période d'échantillonage.
  • Transmissions aux moments prévus. On annonce les moments où on est prêt à recevoir. Cela veut dire que les objets qui veulent parler avec moi doivent le faire au bon moment.
  • Écouter quand on transmet. Dans ce cas, ceux qui ont envie de me parler doivent attendre que j'émette d'abord.

Dans les trois cas, la latence va évidemment en souffrir. On doit faire un compromis entre réduire la consommation électrique et augmenter la latence. On va également diminuer la capacité du canal puisqu'il ne pourra pas être utilisé en permanence. Ce n'est pas forcément trop grave, un capteur a peu à transmettre, en général.

Il existe plein de méthodes pour gagner quelques μJ, comme le regroupement de plusieurs paquets en un seul (il y a un coût fixe par paquet, indépendamment de leur taille). Normalement, le RDC est quelque part dans la couche 2 et les protocoles IETF, situés plus haut, ne devraient pas avoir à s'en soucier. Mais une réduction sérieuse de la consommation électrique nécessite que tout le monde participe, et que les couches hautes fassent un effort, et connaissent ce que font les couches basses, pour s'adapter.

La section 3.6 de notre RFC détaille quelques services que fournissent les protocoles de couche 2 de la famille IEEE 802.11. Une station (un objet ou un ordinateur) peut indiquer au point d'accès (AP, pour access point) qu'il va s'endormir. L'AP peut alors mémoriser les trames qui lui étaient destinées, pour les envoyer plus tard. IEEE 802.11v va plus loin en incluant des mécanismes comme le proxy ARP (répondre aux requêtes ARP à la place de l'objet endormi).

Bluetooth a un ensemble de services pour la faible consommation, nommés Bluetooth LE (pour Low Energy). 6LoWPAN peut d'ailleurs en tirer profit (cf. RFC 7668).

IEEE 802.15.4 a aussi des solutions. Il permet par exemple d'avoir deux types de réseaux, avec ou sans annonces périodiques (beacons). Dans un réseau avec annonces, des machines nommés les coordinateurs envoient régulièrement des annonces qui indiquent quand on peut émettre et quand on ne peut pas, ces dernières périodes étant le bon moment pour s'endormir afin de diminuer la consommation : on est sûr de ne rien rater. Les durées de ces périodes sont configurables par l'administrateur réseaux. Dans les réseaux sans annonces, les différentes machines connectées n'ont pas d'informations et transmettent quand elles veulent, en suivant CSMA/CA.

Enfin, DECT a aussi un mode à basse consommation, DECT ULE. Elle est également utilisable avec 6LoWPAN (RFC 8105). DECT est très asymétrique, il y a le FP (Fixed Part, la base), et le PP (Portable Part, l'objet). DECT ULE permet au FP de prévenir quand il parlera (et le PP peut dormir jusque là). À noter que si la « sieste » est trop longue (plus de dix secondes), le PP devra refaire une séquence de synchronisation avec le FP, qui peut être coûteuse en énergie. Il faut donc bien calculer son coup : si on s'endort souvent pour des périodes d'un peu plus de dix secondes, le bilan global sera sans doute négatif.

La section 4 de notre RFC couvre justement ce que devrait faire IP, en supposant qu'on utilisera 6LoWPAN. Il y a trois services importants de 6LoWPAN pour la consommation électrique :

  • 6LoWPAN a un mécanisme de fragmentation et de réassemblage. IPv6 impose que les liens aient une MTU d'au moins 1 280 octets. Si ce n'est pas le cas, il faut un mécanisme de fragmentation sous IP. Mais la fragmentation n'est pas gratuite et il vaut mieux que les applications s'abstiennent de faire des paquets trop gros (un cas que traite CoAP, dans le RFC 7959).
  • 6LoWPAN sait que le processeur consomme moins d'énergie que la partie radio de l'objet connecté, et qu'il est donc rentable de faire des calculs qui diminuent la quantité de données à envoyer, notamment la compression. Par exemple, 6LoWPAN permet de diminuer sérieusement la taille de l'en-tête de paquet IPv6 (normalement 40 octets), en comptant sur le fait que les paquets successifs d'un même flot se ressemblent.
  • 6LoWPAN a un mécanisme de découverte du voisin optimisé pour les réseaux contraints, nommé 6LoWPAN-ND.

Il y a aussi des optimisations qui ne changent pas le protocole. Par exemple, Contiki ne suit pas, dans sa mise en œuvre, une stricte séparation des couches, afin de pouvoir optimiser l'activité réseau.

De même, les protocoles de routage doivent tenir compte des contraintes de consommation électrique (section 5 du RFC). Le protocole « officiel » de l'IETF pour le routage dans les réseaux contraints est RPL (RFC 6550). L'étude Powertrace déjà citée étudie également la consommation de RPL et montre qu'il est en effet assez efficace, si le réseau est stable (s'il ne l'est pas, on consommera évidemment du courant à envoyer et recevoir les mises à jours des routes). On peut adapter les paramètres de RPL, via l'algorithme Trickle (RFC 6206, rien à voir avec le protocole de transfert de fichiers de BitNet), pour le rendre encore plus économe, mais au prix d'une convergence plus lente lorsque le réseau change.

À noter que le RFC ne parle que de RPL, et pas des autres protocoles de routage utilisables par les objets, comme Babel (RFC 6126).

Et les applications ? La section 6 du RFC leur donne du boulot, à elles aussi. Bien sûr, il est recommandé d'utiliser CoAP (RFC 7252) plutôt que HTTP, entre autre en raison de son en-tête plus court, et de taille fixe. D'autre part, CoAP a un mode de pure observation, où le client indique son intérêt pour certaines ressources, que le serveur lui enverra automatiquement par la suite, lorsqu'elles changeront, économisant ainsi une requête. Comme HTTP, CoAP peut utiliser des relais qui mémorisent la ressource demandée, ce qui permet de récupérer des ressources sans réveiller le serveur, si l'information était dans le cache. D'autres protocoles étaient à l'étude, reprenant les principes de CoAP, pour mieux gérer les serveurs endormis. (Mais la plupart de ces projets semblent… endormis à l'heure actuelle.)

Enfin, la section 7 de notre RFC résume les points importants :

  • Il ne faut pas hésiter à violer le modèle en couches, en accédant à des informations des couches basses, elles peuvent sérieusement aider à faire des économies.
  • Il faut comprimer.
  • Il faut se méfier de la diffusion, qui consomme davantage.
  • Et il faut s'endormir souvent, pour économiser l'énergie (la méthode Gaston Lagaffe, même si le RFC ne cite pas ce pionnier).

Téléchargez le RFC 8352


L'article seul

RFC 8336: The ORIGIN HTTP/2 Frame

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : M. Nottingham, E. Nygren (Akamai)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 22 mars 2018


Le concept d'origine est crucial pour la sécurité de HTTP. L'idée est d'empêcher du contenu actif (code JavaScript, par exemple) d'interagir avec des serveurs autres que ceux de l'origine, de l'endroit où on a chargé ce contenu actif. Dans la version 1 de HTTP, cela ne posait pas (trop) de problèmes. Mais la version 2 de HTTP permet d'avoir, dans une même connexion HTTP vers un serveur donné, accès à des ressources d'origines différentes (par exemple parce qu'hébergées sur des Virtual Hosts différents). Ce nouveau RFC ajoute donc au protocole HTTP/2 un nouveau type de trame, ORIGIN, qui permet de spécifier les origines utilisées dans une connexion.

L'origine est un concept ancien, mais sa description formelle n'est venue au'avec le RFC 6454, dont la lecture est fortement recommandée, avant de lire ce nouveau RFC 8336. Son application à HTTP/2, normalisé dans le RFC 7540, a posé quelques problèmes (sections 9.1.1 et 9.1.2 du RFC 7540). En effet, avec HTTP/2, des origines différentes peuvent coexister sur la même connexion HTTP. Si le serveur ne peut pas produire une réponse, par exemple parce qu'il sépare le traitement des requêtes entre des machines différentes, il va envoyer un code de retour 421, indiquant à un client HTTP de re-tenter, avec une connexion différente. Pour lui faire gagner du temps, notre nouveau RFC 8336 va indiquer préalablement les origines acceptables sur cette connexion. Le client n'aura donc pas à essayer, il saura d'avance si ça marchera ou pas. Cette méthode évite également au client HTTP de se faire des nœuds au cerveau pour déterminer si une requête pour une origine différente a des chances de réussir ou pas, processus compliqué, et qui ne marche pas toujours.

Ce n'est pas clair ? Voici un exemple concret. Le client, un navigateur Web, vient de démarrer et on lui demande de se connecter à https://www.toto.example/. Il établit une connexion TCP, puis lance TLS, et enfin fait du HTTP/2. Dans la phase d'établissement de la connexion TLS, il a récupéré un certificat qui liste des noms possibles (subjectAltName), www.toto.example mais aussi foobar.example. Et, justement, quelques secondes plus tard, l'utilisateur demande à visiter https://foobar.example/ToU/TLDR/. Un point central de HTTP/2 est la réutilisation des connexions, pour diminuer la latence, due entre autres à l'établissement de connexion, qui peut être long avec TCP et, surtout TLS. Notre navigateur va donc se dire « chic, je garde la même connexion puisque c'est la même adresse IP et que ce serveur m'a dit qu'il gérait aussi foobar.example, c'était dans son certificat » (et la section 9.1.1 du RFC 7540 le lui permet explicitement). Mais patatras, l'adresse IP est en fait celle d'un répartiteur de charge qui envoie les requêtes pour www.toto.example et foobar.example à des machines différentes. La machine qui gère foobar.example va alors renvoyer 421 Misdirected Request au navigateur qui sera fort marri, et aura perdu du temps pour rien. Alors qu'avec la trame ORIGIN de notre RFC 8336, le serveur de www.toto.example aurait dès le début envoyé une trame ORIGIN disant « sur cette connexion, c'est www.toto.example et rien d'autre ». Le navigateur aurait alors été prévenu.

La section 2 du RFC décrit en détail ce nouveau type de trame (RFC 7540, section 4, pour le concept de trame). Le type de la trame est 12 (cf. le registre des types), et elle contient une liste d'origines, chacune sous forme d'un doublet longueur-valeur. Une origine est identifiée par un nom de domaine (RFC 6454, sections 3 et 8). Il n'y a pas de limite de taille à la liste, programmeurs, faites attention aux débordements de tableau. Un nom de la liste ne peut pas inclure de jokers (donc, pas d'origine *.example.com, donc attention si vous avez des certificats utilisant des jokers). Ce type de trames doit être envoyée sur le ruisseau HTTP/2 de numéro 0 (celui de contrôle).

Comme toutes les trames d'un type inconnu du récepteur, elles sont ignorées par le destinataire. Donc, en pratique, le serveur peut envoyer ces trames sans inquiétude, le client HTTP trop vieux pour les connaitre les ignorera. Ces trames ORIGIN n'ont de sens qu'en cas de liaison directe, les relais doivent les ignorer, et ne pas les transmettre.

Au démarrage, le client HTTP/2 a un jeu d'origines qui est déterminé par les anciennes règles (section 9.1.1 du RFC 7540). S'il reçoit une trame ORIGIN, celle-ci remplace complètement ce jeu, sauf pour la première origine vue (le serveur auquel on s'est connecté, identifié par son adresse IP et, si on utilise HTTPS, par le nom indiqué dans l'extension TLS SNI, cf. RFC 6066) qui, elle, reste toujours en place. Ensuite, les éventuelles réponses 421 (Misdirected request) supprimeront des entrées du jeu d'origines.

Notez bien que la trame ORIGIN ne fait qu'indiquer qu'on peut utiliser cette connexion HTTP/2 pour cette origine. Elle n'authentifie pas le serveur. Pour cela, il faut toujours compter sur le certificat (cf. section 4 du RFC).

En parlant de sécurité, notez que le RFC 7540, section 9.1.1 obligeait le client HTTP/2 à vérifier le DNS et le nom dans le certificat, avant d'ajouter une origine. Notre nouveau RFC est plus laxiste, on ne vérifie que le certificat quand on reçoit une nouvelle origine dans une trame ORIGIN envoyée sur HTTPS (cela avait suscité des réactions diverses lors de la discussion à l'IETF). Cela veut dire qu'un méchant qui a pu avoir un certificat valable pour un nom, via une des nombreuses AC du magasin, n'a plus besoin de faire une attaque de l'Homme du Milieu (avec, par exemple, un détournement DNS). Il lui suffit, lorsqu'un autre nom qu'il contrôle est visité, d'envoyer une trame ORIGIN et de présenter le certificat. Pour éviter cela, le RFC conseille au client de vérifier le certificat plus soigneusement, par exemple avec les journaux publics du RFC 6962, ou bien avec une réponse OCSP (RFC 6960 montrant que le certificat n'a pas été révoqué, en espérant qu'un certificat « pirate » sera détecté et révoqué…)

Les développeurs regarderont avec intérêt l'annexe B, qui donne des conseils pratiques. Par exemple, si un serveur a une très longue liste d'origines possibles, il n'est pas forcément bon de l'envoyer dès le début de la connexion, au moment où la latence est critique. Il vaut mieux envoyer une liste réduite, et attendre un moment où la connexion est tranquille pour envoyer la liste complète. (La liste des origines, dans une trame ORIGIN, ne s'ajoute pas aux origines précédentes, elle les remplace. Pour retirer une origine, on envoie une nouvelle liste, sans cette origine, ou bien on compte sur les 421. Ce point avait suscité beaucoup de discussions au sein du groupe de travail.)

Pour l'instant, la gestion de ce nouveau type de trames ne semble se trouver que dans Firefox, et n'est dans aucun serveur, mais des programmeurs ont annoncé qu'ils allaient s'y mettre.


Téléchargez le RFC 8336


L'article seul

RFC 8335: PROBE: A Utility For Probing Interfaces

Date de publication du RFC : Février 2018
Auteur(s) du RFC : R. Bonica (Juniper), R. Thomas (Juniper), J. Linkova (Google), C. Lenart (Verizon), M. Boucadair (Orange)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF intarea
Première rédaction de cet article le 23 février 2018


Pour tester qu'une machine est bien joignable, vous utilisez ping ou, plus rigoureusement, vous envoyez un message ICMP de type echo, auquel la machine visée va répondre avec un message ICMP echo reply. Ce test convient souvent mais il a plusieurs limites. L'une des limites de ce test est qu'il ne teste qu'une seule interface réseau de la machine, celle par laquelle vous lui parlez (deux interfaces, dans certains cas de routage asymétrique). Si la machine visée est un gros routeur avec plein d'interfaces réseau, le test ne vous dira pas si toutes fonctionnent. D'où cette extension aux messages ICMP permettant de spécifier l'interface qu'on veut vérifier.

A priori, ce RFC ne s'intéresse qu'aux routeurs, les serveurs n'ayant souvent qu'une seule interface réseau. La nouvelle technique, nommée PROBE, n'a pas de vocation générale, contrairement à ping, et concernera surtout les administrateurs réseau. D'autant plus que, comme elle est assez indiscrète, elle ne sera a priori pas ouverte au public. Notez qu'elle permet non seulement de tester une autre interface du routeur, mais également une interface d'une machine directement connectée au routeur. Les scénarios d'usage proposés sont exposés dans la section 5, une liste non limitative de cas où ping ne suffit pas :

  • Interface réseau non numérotée (pas d'adresse, ce qui est relativement courant sur les routeurs),
  • Interface réseau numérotée de manière purement locale (par exemple adresse IPv6 link-local),
  • Absence de route vers l'interface testée (si on veut tester l'interface d'un routeur qui fait face à un point d'échange, et que le préfixe du point d'échange n'est pas annoncé par le protocole de routage, ce qui est fréquent).

En théorie, SNMP pourrait servir au moins partiellement à ces tests mais, en pratique, c'est compliqué.

ping, la technique classique, est très sommairement décrit dans le RFC 2151, section 3.2, mais sans indiquer comment il fonctionne. La méthodologie est simple : la machine de test envoie un message ICMP Echo (type 8 en IPv4 et 128 en IPv6) à la machine visée (l'amer). L'amer répond avec un Echo Reply (type 0 en IPv4 et 129 en IPv6). La réception de cet Echo Reply indique que la liaison marche bien dans les deux sens. La non-réception indique d'un problème s'est produit, mais on n'en sait pas plus (notamment, on ne sait pas si le problème était à l'aller ou bien au retour). Ici, on voit le test effectué par une sonde Atlas sur l'amer 2605:4500:2:245b::42 (l'un des serveurs hébergeant ce blog), vu par tshark :

13.013422 2a02:1811:c13:1902:1ad6:c7ff:fe2a:6ac → 2605:4500:2:245b::42 ICMPv6 126 Echo (ping) request id=0x0545, seq=1, hop limit=56
13.013500 2605:4500:2:245b::42 → 2a02:1811:c13:1902:1ad6:c7ff:fe2a:6ac ICMPv6 126 Echo (ping) reply id=0x0545, seq=1, hop limit=64 (request in 11)
    

ICMP est normalisé dans les RFC 792 pour IPv4 et RFC 4443 pour IPv6. L'exemple ci-dessus montre un test classique, avec une requête et une réponse.

Notre RFC parle d'« interface testée » (probed interface) et d'« interface testante » (probing interface). Dans l'exemple ci-dessus, l'interface Ethernet de l'Atlas était la testante et celle du serveur était la testée. Le succès du test montre que les deux interfaces sont actives et peuvent se parler.

Au contraire de ping, PROBE va envoyer le message, non pas à l'interface testée mais à une interface « relais » (proxy). Celle-ci répondra si l'interface testée fonctionne bien (état oper-status, cf. RFC 7223). Si l'interface testée n'est pas sur le nœud qui sert de relais, ce dernier détermine l'état de cette interface en regardant la table ARP (RFC 826) ou NDP (RFC 4861). Aucun test actif n'est effectué, l'interface est considérée comme active si on lui a parlé récemment (et donc si l'adresse IP est dans un cache). PROBE utilise, comme ping, ICMP. Il se sert des messages ICMP structurés du RFC 4884. Une des parties du message structuré sert à identifier l'interface testée.

L'extension à ICMP Extended Echo est décrite en section 2 du RFC. Le type de la requête est 42 pour IPv4 et 160 pour IPv6 (enregistré à l'IANA, pour IPv4 et IPv6). Parmi les champs qu'elle comprend (les deux premiers existent aussi pour l'ICMP Echo traditionnel) :

  • Un identificateur qui peut servir à faire correspondre une réponse à une requête (ICMP, comme IP, n'a pas de connexion ou de session, chaque paquet est indépendant), 0x0545 dans l'exemple vu plus haut avec tshark,
  • Un numéro de séquence, qui peut indiquer les paquets successifs d'un même test, 1 dans l'exemple vu plus haut avec tshark
  • Un bit nommé L (local) qui indique si l'interface testée est sur le nœud visé par le test ou non,
  • Une structure qui indique l'interface testée.

Cette structure suit la forme décrite dans la section 7 du RFC 4884. Elle contient un objet d'identification de l'interface. L'interface qu'on teste peut être désignée par son adresse IP (si elle n'est pas locale - bit L à zéro, c'est la seule méthode acceptée), son nom ou son index. Notez que l'adresse IP identifiant l'adresse testée n'est pas forcément de la même famille que celle du message ICMP. On peut envoyer en IPv4 un message ICMP demandant à la machine distante de tester une interface IPv6.

Plus précisément, l'objet d'identification de l'interface est composé, comme tous les objets du RFC 4884, d'un en-tête et d'une charge utile. L'en-tête contient les champs :

  • Un numéro de classe, 3, stocké à l'IANA,
  • Un numéro indiquant comment l'interface testée est désignée (1 = par nom, cf. RFC 7223, 2 = par index, le même qu'en SNMP, voir aussi le RFC 7223, section 3, le concept de if-index, et enfin 3 = par adresse),
  • La longueur des données.

L'adresse est représentée elle-même par une structure à trois champs, la famille (4 pour IPv4 et 6 pour IPv6), la longueur et la valeur de l'adresse. Notez que le RFC 5837 a un mécanisme de description de l'interface, portant le numéro de classe 2, et utilisé dans un contexte proche.

La réponse à ces requêtes a le type 43 en IPv4 et 161 en IPv6 (section 3 du RFC). Elle comprend :

  • Un code (il valait toujours 0 pour la requête) qui indique le résultat du test : 0 est un succès, 1 signale que la requête était malformée, 2 que l'interface à tester n'existe pas, 3 qu'il n'y a pas de telle entrée dans la table des interfaces, et 4 que plusieurs interfaces correspondent à la demande (liste complète dans un registre IANA),
  • Un identificateur, copié depuis la requête,
  • Un numéro de séquence, copié depuis la requête,
  • Un état qui donne des détails en cas de code 0 (autrement, pas besoin de détails) : si l'interface testée n'est pas locale, l'état vaut 2 si l'entrée dans le cache ARP ou NDP est active, 1 si elle est incomplète (ce qui indique typiquement que l'interface testée n'a pas répondu), 3 si elle n'est plus à jour, etc,
  • Un bit A (active) qui est mis à un si l'interface testée est locale et fonctionne,
  • Un bit nommé 4 (pour IPv4) qui indique si IPv4 tourne sur l'interface testée,
  • Un bit nommé 6 (pour IPv6) qui indique si IPv6 tourne sur l'interface testée.

La section 4 du RFC détaille le traitement que doit faire la machine qui reçoit l'ICMP Extended Echo. D'abord, elle doit jeter le paquet (sans répondre) si ICMP Extended Echo n'est pas explicitement activé (rappelez-vous que ce service est assez indiscret, cf. section 8 du RFC) ou bien si l'adresse IP de la machine testante n'est pas autorisée (même remarque). Si les tests sont passés et que la requête est acceptée, la machine réceptrice fabrique une réponse : le code est mis à 1 si la requête est anormale (pas de partie structurée par exemple), 2 si l'interface testée n'existe pas, 3 si elle n'est pas locale et n'apparait pas dans les tables (caches) ARP ou NDP. Si on trouve l'interface, on la teste et on remplit les bits A, 4, 6 et l'état, en fonction de ce qu'on trouve sur l'interface testée.

Reste la question de la sécurité (section 8 du RFC). Comme beaucoup de mécanismes, PROBE peut être utilisé pour le bien (l'administrateur réseaux qui détermine l'état d'une interface d'un routeur dont il s'occupe), mais aussi pour le mal (chercher à récolter des informations sur un réseau avant une attaque, par exemple, d'autant plus que les noms d'interfaces dans les routeurs peuvent être assez parlants, révélant le type de réseau, le modèle de routeur…) Le RFC exige donc que le mécanisme ICMP Extended Echo ne soit pas activé par défaut, et soit configurable (liste blanche d'adresses IP autorisées, permission - ou non - de tester des interfaces non locales, protection des différents réseaux les uns contre les autres, si on y accueille des clients différents…) Et, bien sûr, il faut pouvoir limiter le nombre de messages.

Ne comptez pas utilise PROBE tout de suite. Il n'existe apparemment pas de mise en œuvre de ce mécanisme publiée. Juniper en a réalisé une mais elle n'apparait encore dans aucune version de JunOS.


Téléchargez le RFC 8335


L'article seul

RFC 8334: Launch Phase Mapping for the Extensible Provisioning Protocol (EPP)

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : J. Gould (VeriSign), W. Tan (Cloud Registry), G. Brown (CentralNic)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 5 mars 2018


Les registres de noms de domaine ont parfois des périodes d'enregistrement spéciales, par exemple lors de la phase de lancement d'un nouveau domaine d'enregistrement, ou bien lorsque les règles d'enregistrement changent. Pendant ces périodes, les conditions d'enregistrement ne sont pas les mêmes que pendant les périodes « standards ». Les registres qui utilisent le protocole EPP pour l'enregistrement peuvent alors utiliser les extensions EPP de ce nouveau RFC pour gérer ces périodes spéciales.

Un exemple de période spéciale est l'ouverture d'un tout nouveau TLD à l'enregistrement. Un autre exemple est une libéralisation de l'enregistrement, passant par exemple de vérifications a priori strictes à un modèle plus ouvert. Dans les deux cas, on peut voir des conflits se faire jour, par exemple entre le titulaire le plus rapide à enregistrer un nom, et un détenteur de propriété intellectuelle qui voudrait reprendre le nom. Les périodes spéciales sont donc définies par des privilèges particuliers pour certains utilisateurs, permettant par exemple aux titulaires d'une marque déposée d'avoir un avantage pour le nom de domaine correspondant à cette marque. La période spéciale est qualifiée de « phase de lancement » (launch phase). Les extensions à EPP décrites dans ce nouveau RFC permettent de mettre en œuvre ces privilèges.

La classe (mapping) décrivant les domaines en EPP figure dans le RFC 5731. Elle est prévue pour le fonctionnement standard du registre, sans intégrer les périodes spéciales. Par exemple, en fonctionnement standard, une fois que quelqu'un a enregistré un nom, c'est fini, personne d'autre ne peut le faire. Mais dans les phases de lancement, il arrive qu'on accepte plusieurs candidatures pour un même nom, qui sera ensuite attribué en fonction de divers critères (y compris parfois une mise aux enchères). Ou bien il peut y avoir des vérifications supplémentaires pendant une phase de lancement. Par exemple, certaines phases peuvent être réservées aux titulaires de propriété intellectuelle, et cela est vérifié via un organisme de validation, comme la TMCH (RFC 7848).

D'où ce RFC qui étend la classe domain du RFC 5731. La section 2 du RFC décrit les nouveaux attributs et éléments des domaines, la section 3 la façon de les utiliser dans les commandes EPP et la section 4 donne le schéma XML. Voyons d'abord les nouveaux éléments et attributs.

D'abord, comme il peut y avoir plusieurs candidatures pour un même nom, il faut un moyen de les distinguer. C'est le but de l'identificateur de candidature (application identifier). Lorsque le serveur EPP reçoit une commande <domain:create> pour un nom, il attribue un identificateur de candidature, qu'il renvoie au client, dans un élément <launch:applicationID>, tout en indiquant que le domaine est en état pendingCreate (RFC 5731, section 2.3) puisque le domaine n'a pas encore été créé. Au passage, launch dans <launch:applicationID> est une abréviation pour l'espace de noms XML urn:ietf:params:xml:ns:launch-1.0. Un processeur XML correct ne doit évidemment pas tenir compte de l'abréviation (qui peut être ce qu'on veut) mais uniquement de l'espace de noms associé. Cet espace est désormais enregistré à l'IANA (cf. RFC 3688).

Autre nouveauté, comme un serveur peut utiliser plusieurs organismes de validation d'une marque déposée, il existe désormais un attribut validatorID qui indique l'organisme. Par défaut, c'est la TMCH (identificateur tmch). On pourra utiliser cet attribut lorsqu'on indiquera un identificateur de marque, par exemple lorsqu'on se sert de l'élément <mark:mark> du RFC 7848.

Les périodes spéciales ont souvent plusieurs phases, et notre RFC en définit plusieurs (dans une ouverture réelle, toutes ne sont pas forcément utilisées), qui seront utilisées dans l'élément <launch:phase> :

  • Lever de soleil (sunrise), phase où les titulaires de marques (le RFC ne mentionne pas d'autres cas, comme le nom de l'entreprise ou d'une ville) peuvent seuls soumettre des candidatures, la marque étant validée par exemple via la TMCH,
  • Prétentions (claims), où on peut enregistrer si on n'a pas de marque, mais on reçoit alors une notice disant qu'une marque similaire existe (elle est décrite plus en détail dans l'Internet-Draft draft-ietf-regext-tmch-func-spec), et on peut alors renoncer ou continuer (si on est d'humeur à affronter les avocats de la propriété intellectuelle), en annonçant, si on continue « oui, j'ai vu, j'y vais quand même »,
  • Ruée (landrush), phase immédiatement après l'ouverture, quand tout le monde et son chien peuvent se précipiter pour enregistrer,
  • État ouvert (open), une fois qu'on a atteint le régime de croisière.

La section 2 définit aussi les états d'une candidature. Notamment :

  • pendingValidation (validation en attente),
  • validated (c'est bon, mais voyez plus loin),
  • invalid (raté, vous n'avez pas de droits sur ce nom),
  • pendingAllocation (une fois qu'on est validé, tout n'est pas fini, il peut y avoir plusieurs candidatures, avec un mécanisme de sélection, par exemple fondé sur une enchère),
  • allocated (c'est vraiment bon),
  • rejected (c'est fichu…)

Les changements d'état ne sont pas forcément synchrones. Parfois, il faut attendre une validation manuelle, par exemple. Dans cas, il faut notifier le client EPP, ce qui se fait avec le mécanisme des messages asynchrones (poll message) du RFC 5730, section 2.9.2.3.

Comme toutes les extensions EPP, elle n'est utilisée par le client que si le serveur l'indique à l'ouverture de la session, en listant les espaces de noms XML des extensions qu'il accepte, par exemple :


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
   <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
      <greeting><svID>EPP beautiful server for .example</svID>
                <svDate>2018-02-20T15:37:20.0Z</svDate>
                <svcMenu><version>1.0</version><lang>en</lang>
                <objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
                <objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
                <svcExtension>
                <extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
                <extURI>urn:ietf:params:xml:ns:secDNS-1.1</extURI>
                <extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
                </svcExtension>
                </svcMenu>
        </greeting>
   </epp>

    

Maintenant qu'on a défini les données, la section 3 du RFC explique comment les utiliser. (Dans tous les exemples ci-dessous, C: identifie ce qui est envoyé par le client EPP et S: ce que le serveur répond.) Par exemple, la commande EPP <check> (RFC 5730, section 2.9.2.1) sert à vérifier si on peut enregistrer un objet (ici, un nom de domaine). Elle prend ici des éléments supplémentaires, par exemple pour tester si un nom correspond à une marque. Ici, on demande si une marque existe (notez l'extension <launch:check>) :


C:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
C:  <command>
C:   <check>
C:    <domain:check
C:     xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
C:      <domain:name>domain1.example</domain:name>
C:    </domain:check>
C:   </check>
C:   <extension>
C:    <launch:check
C:     xmlns:launch="urn:ietf:params:xml:ns:launch-1.0"
C:     type="trademark"/>
C:   </extension>
C:  </command>
C:</epp>

    

Et on a la réponse (oui, la marque existe dans la TMCH) :


S:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
S:  <response>
S:    <result code="1000">
S:     <msg>Command completed successfully</msg>
S:    </result>
S:    <extension>
S:     <launch:chkData
S:      xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
S:      <launch:cd>
S:        <launch:name exists="1">domain1.example</launch:name>
S:        <launch:claimKey validatorID="tmch">
S:        2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001
S:        </launch:claimKey>
S:      </launch:cd>
S:     </launch:chkData>
S:    </extension>
S:  </response>
S:</epp>

    

Avec la commande EPP <info>, qui sert à récupérer des informations sur un nom, on voit ici qu'un nom est en attente (pendingCreate), et on a l'affichage de la phase actuelle du lancement, dans l'élément <launch:phase> :


C:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
C:  <command>
C:   <info>
C:    <domain:info
C:     xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
C:      <domain:name>domain.example</domain:name>
C:    </domain:info>
C:   </info>
C:   <extension>
C:    <launch:info
C:     xmlns:launch="urn:ietf:params:xml:ns:launch-1.0"
C:       includeMark="true">
C:      <launch:phase>sunrise</launch:phase>
C:    </launch:info>
C:   </extension>
C:  </command>
C:</epp>
    

Et le résultat, avec entre autre l'identificateur de candidature :


S:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
S:  <response>
S:    <result code="1000">
S:      <msg>Command completed successfully</msg>
S:    </result>
S:    <resData>
S:      <domain:infData
S:       xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
S:        <domain:name>domain.example</domain:name>
S:        <domain:status s="pendingCreate"/>
S:        <domain:registrant>jd1234</domain:registrant>
S:        <domain:contact type="admin">sh8013</domain:contact>
S:        <domain:crDate>2012-04-03T22:00:00.0Z</domain:crDate>
   ...
S:      </domain:infData>
S:    </resData>
S:    <extension>
S:      <launch:infData
S:       xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
S:        <launch:phase>sunrise</launch:phase>
S:          <launch:applicationID>abc123</launch:applicationID>
S:          <launch:status s="pendingValidation"/>
S:          <mark:mark
S:            xmlns:mark="urn:ietf:params:xml:ns:mark-1.0">
S:             ...
S:         </mark:mark>
S:      </launch:infData>
S:    </extension>
S:  </response>
S:</epp>

    

C'est bien joli d'avoir des informations mais, maintenant, on voudrait créer des noms de domaine. La commande EPP <create> (RFC 5730, section 2.9.3.1) sert à cela. Selon la phase de lancement, il faut lui passer des extensions différentes. Pendant le lever de soleil (sunrise), il faut indiquer la marque déposée sur laquelle on s'appuie, dans <launch:codeMark> (il y a d'autres moyens de l'indiquer, cf. section 2.6) :


C:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
C:  <command>
C:    <create>
C:      <domain:create
C:       xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
C:        <domain:name>domain.example</domain:name>
C:        <domain:registrant>jd1234</domain:registrant>
   ...
C:      </domain:create>
C:    </create>
C:    <extension>
C:      <launch:create
C:       xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
C:        <launch:phase>sunrise</launch:phase>
C:        <launch:codeMark>
C:          <launch:code validatorID="sample1">
C:            49FD46E6C4B45C55D4AC</launch:code>
C:        </launch:codeMark>
C:      </launch:create>
C:    </extension>
C:  </command>
C:</epp>

    

On reçoit une réponse qui dit que le domaine n'est pas encore créé, mais on a un identificateur de candidature (un numéro de ticket, quoi) en <launch:applicationID>. Notez le code de retour 1001 (j'ai compris mais je ne vais pas le faire tout de suite) et non pas 1000, comme ce serait le cas en régime de croisière :


S:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
S:  <response>
S:    <result code="1001">
S:      <msg>Command completed successfully; action pending</msg>
S:    </result>
S:    <resData>
S:      <domain:creData
S:         xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
S:       <domain:name>domain.example</domain:name>
S:       <domain:crDate>2010-08-10T15:38:26.623854Z</domain:crDate>
S:      </domain:creData>
S:    </resData>
S:    <extension>
S:      <launch:creData
S:        xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
S:        <launch:phase>sunrise</launch:phase>
S:        <launch:applicationID>2393-9323-E08C-03B1
S:        </launch:applicationID>
S:      </launch:creData>
S:    </extension>
S:  </response>
S:</epp>

    

De même, des extensions permettent de créer un domaine pendant la phase où il faut indiquer qu'on a vu les prétentions qu'avait un titulaire de marque sur ce nom. Le RFC décrit aussi l'extension à utiliser dans la phase de ruée (landrush), mais j'avoue n'avoir pas compris son usage (puisque, pendant la ruée, les règles habituelles s'appliquent).

On peut également retirer une candidature, avec la commande EPP <delete> qui, en mode standard, sert à supprimer un domaine. Il faut alors indiquer l'identifiant de la candidature qu'on retire :


C:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
C:  <command>
C:   <delete>
C:    <domain:delete
C:     xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
C:      <domain:name>domain.example</domain:name>
C:    </domain:delete>
C:   </delete>
C:   <extension>
C:    <launch:delete
C:     xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
C:      <launch:phase>sunrise</launch:phase>
C:      <launch:applicationID>abc123</launch:applicationID>
C:    </launch:delete>
C:   </extension>
C:  </command>
C:</epp>

    

Et les messages non sollicités (poll), envoyés de manière asynchrone par le serveur ? Voici un exemple, où le serveur indique que la candidature a été jugée valide (le mécanisme par lequel on passe d'un état à un autre dépend de la politique du serveur) :


S:<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
S:  <response>
S:    <result code="1301">
S:      <msg>Command completed successfully; ack to dequeue</msg>
S:    </result>
S:    <msgQ count="5" id="12345">
S:      <qDate>2013-04-04T22:01:00.0Z</qDate>
S:      <msg>Application pendingAllocation.</msg>
S:    </msgQ>
S:    <resData>
S:      <domain:infData
S:       xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
S:        <domain:name>domain.example</domain:name>
S:        ...
S:      </domain:infData>
S:    </resData>
S:    <extension>
S:      <launch:infData
S:       xmlns:launch="urn:ietf:params:xml:ns:launch-1.0">
S:        <launch:phase>sunrise</launch:phase>
S:        <launch:applicationID>abc123</launch:applicationID>
S:        <launch:status s="pendingAllocation"/>
S:      </launch:infData>
S:    </extension>
S:  </response>
S:</epp>

    

Voilà, vous savez l'essentiel, si vous voulez tous les détails, il faudra lire la section 3 complète, ainsi que la section 4, qui contient le schéma XML des extensions pour les phases de lancement. Comme toutes les extensions à EPP, celle de ce RFC est désormais dans le registre des extensions EPP, décrit dans le RFC 7451.

Notez que ce RFC ne fournit pas de moyen pour indiquer au client EPP quelle est la politique d'enregistrement pendant la période spéciale. Cela doit être fait par un mécanisme externe (page Web du registre, par exemple).

Quelles sont les mises en œuvre de ce RFC ? L'extension pour les phases de lancement est ancienne (première description en 2011) et de nombreux registres offrent désormais cette possibilité. C'est d'autant plus vrai que l'ICANN impose aux registres de ses nouveaux TLD de gérer les phases de lancement avec cette extension. Ainsi :

  • Le kit de développement de clients EPP de Verisign a cette extension, sous une licence libre.
  • Logiquement, le système d'enregistrement de Verisign, utilisé notamment pour .com et .net (mais également pour bien d'autres TLD) gère cette extension (code non libre et non public, cette fois).
  • Le serveur REngin (non libre), utilisé pour .za a aussi cette extension.
  • Le serveur de CentralNIC, pareil.
  • Le client EPP distribué par Neustar est sous licence libre et sait gérer les phases de lancement.
  • Le serveur (non libre) de SIDN (qui gère le domaine national .nl) fait partie de ceux qui ont mis en œuvre ce RFC.
  • Et côté client, il y a le logiciel libre Net::DRI (extension ajoutée dans une scission nommée tdw, pas dans le logiciel originel de Patrick Mevzek), cf. LaunchPhase.pm.

Téléchargez le RFC 8334


L'article seul

RFC 8332: Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : D. Bider (Bitvise)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF curdle
Première rédaction de cet article le 21 mars 2018


Les RFC normalisant le protocole SSH mentionnaient la possibilité pour le serveur d'avoir une clé publique RSA, mais uniquement avec l'algorithme de condensation SHA-1. Celui-ci a subi plusieurs attaques et n'est plus du tout conseillé aujourd'hui. Ce nouveau RFC est la description officielle de l'utilisation de RSA avec SHA-2 dans SSH.

Le RFC officiel du protocole SSH, le RFC 4253, définit l'algorithme ssh-rsa comme utilisant the SHA-1 hash pour la signature et la vérification. Ce n'est plus cohérent avec ce qu'on sait aujourd'hui des faiblesses de SHA-1. Par exemple, le NIST (dont les règles s'imposent aux organismes gouvernementaux états-uniens), interdit SHA-1 (voir aussi la section 5.1 du RFC).

(Petit point au passage, dans SSH, le format de la clé ne désigne que la clé elle-même, alors que l'algorithme désigne un format de clé et des procédures de signature et de vérification, qui impliquent un algorithme de condensation. Ainsi, ssh-keygen -t rsa va générer une clé RSA, indépendamment de l'algorithme qui sera utilisé lors d'une session SSH. Le registre IANA indique désormais séparement le format et l'algorithme.)

Notre nouveau RFC définit donc deux nouveaux algorithmes :

  • rsa-sha2-256, qui utilise SHA-256 pour la condensation, et dont la mise en œuvre est recommandée pour tout programme ayant SSH,
  • et rsa-sha2-512, qui utilise SHA-512 et dont la mise en œuvre est facultative.

Les deux algorithmes sont maintenant dans le registre IANA. Le format, lui, ne change pas, et est toujours qualifié de ssh-rsa (RFC 4253, section 3.) Il n'est donc pas nécessaire de changer ses clés RSA. (Si vous utilisez RSA : SSH permet d'autres algorithmes de cryptographie asymétrique, voir également la section 5.1 du RFC.)

Les deux « nouveaux » (ils sont déjà présents dans plusieurs programmes SSH) algorithmes peuvent être utilisés aussi bien pour l'authentification du client que pour celle du serveur. Ici, par exemple, un serveur OpenSSH version 7.6p1 annonce les algorithme qu'il connait (section 3.1 de notre RFC), affichés par un client OpenSSH utilisant l'option -v :


debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521>

    

On y voit la présence des deux nouveaux algorithmes. ssh-rsa est celui du RFC 4253, avec SHA-1 (non explicitement indiqué).

En parlant d'OpenSSH, la version 7.2 avait une bogue (corrigée en 7.2p2), qui faisait que la signature était étiquetée ssh-rsa quand elle aurait dû l'être avec rsa-sha2-256 ou rsa-sha2-512. Pour compenser cette bogue, le RFC autorise les programmes à accepter ces signatures quand même.

Autre petit piège pratique (et qui a suscité les discussions les plus vives dans le groupe de travail), certains serveurs SSH « punissent » les clients qui essaient de s'authentifier avec des algorithmes que le serveur ne sait pas gèrer, pour diminuer l'efficacité d'éventuelles attaques par repli. Pour éviter d'être pénalisé (serveur qui raccroche brutalement, voire qui vous met en liste noire), le RFC recommande que les serveurs déploient le protocole qui permet de négocier des extensions, protocole normalisé dans le RFC 8308. (L'extension intéressante est server-sig-algs.) Le client prudent peut éviter d'essayer les nouveaux algorithmes utilisant SHA-2, si le serveur n'annonce pas cette extension. L'ancien algorithme, utilisant SHA-1, devrait normalement être abandonné au fur et à mesure que tout le monde migre.

Les nouveaux algorithmes de ce RFC sont présents dans :

Vous pouvez aussi regarder le tableau de comparaison des versions de SSH. Voici encore un ssh -v vers un serveur dont la clé de machine est RSA et qui utilise l'algorithme RSA-avec-SHA512 :

...
debug1: kex: host key algorithm: rsa-sha2-512
...
debug1: Server host key: ssh-rsa SHA256:yiol3GPr1dgVo/SNXPvtFqftLw4UF+nL+ECa1yXAtG0
...
   

Par comparaison avec les SSH récents, voici un ssh -v OpenSSH vers un serveur un peu vieux :

    

debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521>

On voit que les nouveaux algorithmes manquent (pour RSA ; SHA-2 est utilisable pour ECDSA). Et pour sa clé de machine :

...
debug1: kex: host key algorithm: ssh-rsa
...
debug1: Server host key: ssh-rsa SHA256:a6cLkwFRGuEorbmN0oRjvKrXELhIVXdgHRCcbQOM2w8
  

Le serveur utilise le vieil algorithme, ssh-rsa, ce qui veut dire SHA-1 (le SHA256 qui apparait a été généré par le client).


Téléchargez le RFC 8332


L'article seul

RFC 8326: Graceful BGP Session Shutdown

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : P. Francois, B. Decraene (Orange), C. Pelsser (Strasbourg University), K. Patel (Arrcus), C. Filsfils (Cisco Systems)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 7 mars 2018


Voici une nouvelle communauté BGP, GRACEFUL_SHUTDOWN, qui va permettre d'annoncer une route à son pair BGP, tout en l'avertissant que le lien par lequel elle passe va être bientôt coupé pour une maintenance prévue. Le pair pourra alors automatiquement limiter l'usage de cette route et chercher tout de suite des alternatives. Cela évitera les pertes de paquets qui se produisent quand on arrête un lien ou un routeur.

Le protocole BGP (RFC 4271) qui assure le routage entre les AS qui composent l'Internet permet aux routeurs d'échanger des informations entre eux « pour aller vers 2001:db8:bc9::/48, passe donc par moi ». Avec ces informations, chaque routeur calcule les routes à suivre pour chaque destination. Une fois que c'est fait, tout le monde se repose ? Non, parce qu'il y a tout le temps des changements. Certains peuvent être imprévus et accidentels (la fameuse pelleteuse), d'autres sont planifiés à l'avance : ce sont les opérations de maintenance « le 7 février à 2300 UTC, nous allons remplacer une line card du routeur, coupant toutes les sessions BGP de cette carte ». Voici par exemple un message reçu sur la liste de diffusion des opérateurs connectés au France-IX :

      
Date: Wed, 31 Jan 2018 15:57:34 +0000
From: Quelqu'un <quelquun@opérateur>
To: "paris@members.franceix.net" <paris@members.franceix.net>
Subject: [FranceIX members] [Paris] [OPÉRATEUR/ASXXXXX] - France-IX port  maintenance

Dear peers,

Tomorrow morning CEST, we will be conducting a maintenance that will
impact one of our connection to France-IX (IPs: x.y.z.t/2001:x:y:z::t).

All sessions will be shut down before and brought back up once the maintenance will be over.

Please note that our MAC address will change as the link will be migrated to a new router.

Cheers

    

Lorsqu'une telle opération est effectuée, le résultat est le même que pour une coupure imprévue : les sessions BGP sont coupées, les routeurs retirent les routes apprises via ces sessions, et vont chercher d'autres routes dans les annonces qu'ils ont reçues. Ils propagent ensuite ces changements à leurs voisins, jusqu'à ce que tout l'Internet soit au courant. Le problème est que cela prend du temps (quelques secondes au moins, des dizaines de secondes, parfois, à moins que les routeurs n'utilisent le RFC 7911 mais ce n'est pas toujours le cas). Et pendant ce temps, les paquets continuent à arriver à des routeurs qui ne savent plus les traiter (section 3 du RFC). Ces paquets seront jetés, et devront être réémis (pour le cas de TCP). Ce n'est pas satisfaisant. Bien sûr, quand la coupure est imprévue, il n'y a pas le choix. Mais quand elle est planifiée, on devrait pouvoir faire mieux, avertir les routeurs qu'ils devraient cesser d'utiliser cette route. C'est justement ce que permet la nouvelle communauté GRACEFUL_SHUTDOWN. (Les communautés BGP sont décrites dans le RFC 1997.) Elle s'utilise avant la coupure, indiquant aux pairs qu'ils devraient commencer le recalcul des routes, mais qu'ils peuvent continuer à utiliser les anciennes routes pendant ce temps. (Notez qu'un cahier des charges avait été établi pour ce problème, le RFC 6198. Et que ce projet d'une communauté pour les arrêts planifiés est ancien, au moins dix ans.)

Ce RFC décrit donc deux choses, la nouvelle communauté normalisée, GRACEFUL_SHUTDOWN (section 5), et la procédure à utiliser pour s'en servir proprement (section 4). L'idée est que les routes qui vont bientôt être coupées pour maintenance restent utilisées, mais avec une préférence locale très faible (la valeur 0 est recommandée, la plus petite valeur possible). La notion de préférence locale est décrite dans le RFC 4271, section 5.1.5. Comme son nom l'indique, elle est locale à un AS, et représente sa préférence (décidée unilatéralement) pour une route plutôt que pour une autre. Lors du choix d'une route par BGP, c'est le premier critère consulté.

Pour mettre en œuvre cette idée, chaque routeur au bord des AS (ASBR, pour Autonomous System Border Router) doit avoir une règle qui, lorsqu'une annonce de route arrive avec la communauté GRACEFUL_SHUTDOWN, applique une préférence locale de 0. Notez que cela peut se faire avec les routeurs actuels, aucun code nouveau n'est nécessaire, ce RFC ne décrit qu'une procédure. Une fois que cette règle est en place, tout le reste sera automatique, chez les pairs de l'AS qui coupe un lien ou un routeur.

Et l'AS qui procéde à une opération de maintenance, que doit-il faire ? Dans l'ordre :

  • Sur la·es session·s BGP qui va·ont être coupée·s, appliquer la communauté GRACEFUL_SHUTDOWN aux routes qu'on annonce (outbound policy),
  • Sur la·es session·s BGP qui va·ont être coupée·s, appliquer la communauté GRACEFUL_SHUTDOWN aux routes qu'on reçoit (inbound policy), et mettre leur préférence locale à zéro,
  • Attendre patiemment que tout le monde ait convergé (propagation des annonces),
  • Procéder à l'opération de maintenance, qui va couper BGP (et c'est plus joli si on utilise le RFC 8203).

J'ai dit plus haut qu'il n'était pas nécessaire de modifier le logiciel des routeurs BGP mais évidemment tout est plus simple s'ils connaissent la communauté GRACEFUL_SHUTDOWN et simplifient ainsi la tâche de l'administrateur réseaux. Cette communauté est « bien connue » (elle n'est pas spécifique à un AS), décrite dans la section 5 du RFC, enregistrée à l'IANA et sa valeur est 0xFFFF0000 (qui peut aussi s'écrire 65535:0, dans la notation habituelle des communautés).

La section 6 du RFC fait le tour de la sécurité de ce système. Comme il permet d'influencer le routage chez les pairs (on annonce une route avec la communauté GRACEFUL_SHUTDOWN et paf, le pair met une très faible préférence à ces routes), il ouvre la porte à de l'ingénierie du trafic pas toujours bienveillante. Il est donc prudent de regarder ce qu'annoncent ses pairs, et d'engueuler ou de dépairer ceux et celles qui abusent de ce mécanisme.

Pour les amateurs de solutions alternatives, l'annexe A explique les autres techniques qui auraient pu être utilisées lors de la réception des routes marquées avec GRACEFUL_SHUTDOWN. Au lieu d'influencer la préférence locale, on aurait par exemple pu utiliser le MED (multi-exit discriminator, RFC 4271, section 5.1.4) mais il n'est considéré par les pairs qu'après d'autres critères, et il ne garantit donc pas que le lien bientôt coupé ne sera plus utilisé.

L'annexe B donne des exemples de configuration pour différents types de routeurs. (Configurations pour l'AS qui reçoit la notification d'un arrêt proche, pas pour ceux qui émettent.) Ainsi, pour IOS XR :

   !    65535:0 = 0xFFFF0000 
   community-set comm-graceful-shutdown
     65535:0
   end-set

   route-policy AS64497-ebgp-inbound
     ! Règles appliquées aux annonces reçues du pair, l'AS 64497. Bien
     ! sûr, en vrai, il y aurait plein d'autres règles, par exemple de filtrage.
     if community matches-any comm-graceful-shutdown then
       set local-preference 0
     endif
     ! On a appliqué la règle du RFC : mettre la plus faible
     ! préférence locale possible  
   end-policy

   ! La configuration de la session BGP avec le pair
   router bgp 64496
    neighbor 2001:db8:1:2::1
     remote-as 64497
     address-family ipv6 unicast
      send-community-ebgp
      route-policy AS64497-ebgp-inbound in
    

Pour BIRD, cela sera :

   # (65535, 0) = 0xFFFF0000 
   function honor_graceful_shutdown() {
       if (65535, 0) ~ bgp_community then {
           bgp_local_pref = 0;
       }
   }
   filter AS64497_ebgp_inbound
   {
           # Règles appliquées aux annonces reçues du pair, l'AS 64497. Bien
           # sûr, en vrai, il y aurait plein d'autres règles, par
	   # exemple de filtrage.
           honor_graceful_shutdown();
   }
   protocol bgp peer_64497_1 {
       neighbor 2001:db8:1:2::1 as 64497;
       local as 64496;
       import keep filtered;
       import filter AS64497_ebgp_inbound;
   }
    

Et sur OpenBGPD (on voit qu'il connait GRACEFUL_SHUTDOWN, il n'y a pas besoin de donner sa valeur) :

   AS 64496
   router-id 192.0.2.1
   neighbor 2001:db8:1:2::1 {
           remote-as 64497
   }
   # Règles appliquées aux annonces reçues du pair, l'AS 64497. Bien
   # sûr, en vrai, il y aurait plein d'autres règles, par exemple de filtrage.
   match from any community GRACEFUL_SHUTDOWN set { localpref 0 }      
    

Enfin, l'annexe C du RFC décrit quelques détails supplémentaires, par exemple pour IBGP (BGP interne à un AS).

Notez que ce nouveau RFC est prévu pour le cas où la transmission des paquets (forwarding plane) est affectée. Si c'est uniquement la session BGP (control plane) qui est touchée, la solution du RFC 4724, Graceful Restart, est plus appropriée.


Téléchargez le RFC 8326


L'article seul

RFC 8324: DNS Privacy, Authorization, Special Uses, Encoding, Characters, Matching, and Root Structure: Time for Another Look?

Date de publication du RFC : Février 2018
Auteur(s) du RFC : J. Klensin
Pour information
Première rédaction de cet article le 28 février 2018


Le DNS est une infrastructure essentielle de l'Internet. S'il est en panne, rien ne marche (sauf si vous faites partie de la minorité qui fait uniquement des ping -n et des traceroute -n). S'il est lent, tout rame. Comme le DNS, heureusement, marche très bien, et s'est montré efficace, fiable et rapide, il souffre aujourd'hui de la malédiction des techniques à succès : on essaie de charger la barque, de lui faire faire plein de choses pour lesquelles il n'était pas prévu. D'un côté, c'est un signe de succès. De l'autre, c'est parfois fragilisant. Dans ce RFC individuel (qui exprime juste le point de vue d'un individu, et n'est pas du tout une norme IETF), John Klensin, qui ne participe plus activement au développement du DNS depuis des années, revient sur certaines de ces choses qu'on essaie de faire faire au DNS et se demande si ce n'est pas trop, et à partir de quel point il faudrait arrêter de « perfectionner » le DNS et plutôt passer à « autre chose » (« quand le seul outil qu'on a est un marteau, tous les problèmes ressemblent à des clous… »). Une bonne lecture pour celleszetceux qui ne veulent pas seulement faire marcher le DNS mais aussi se demander « pourquoi c'est comme ça ? » et « est-ce que ça pourrait être différent ? »

Améliorer le système petit à petit ou bien le remplacer complètement ? C'est une question que se posent régulièrement les ingénieurs, à propos d'un logiciel, d'un langage de programmation, d'un protocole réseau. À l'extrême, il y a l'ultra-conservateur qui ne voit que des inconvénients aux solutions radicales, à l'autre il y a l'ultra-optimiste qui en a marre des rustines et qui voudrait jeter le vieux système, pour le remplacer par un système forcément meilleur, car plus récent. Entre les deux, beaucoup d'informaticiens hésitent. L'ultra-conservateur oublie que les rustines successives ont transformé l'ancien système en un monstre ingérable et difficile à maintenir, l'ultra-optimiste croit naïvement qu'un système nouveau, rationnellement conçu (par lui…) sera à coup sûr plus efficace et moins bogué. Mais les deux camps, et tout celleszetceux qui sont entre les deux peuvent tirer profit de ce RFC, pour approfondir leur réflexion.

Klensin note d'abord que le DNS est vieux. La première réflexion à ce sujet était le RFC 799 en 1981, et le premier RFC décrivant le DNS est le RFC 882, en novembre 1983. (Paul Mockapetris a raconté le développement du DNS dans « Development of the Domain Name System », j'ai fait un résumé des articles d'histoire du DNS.) Le DNS remplaçait l'ancien système fondé sur un fichier centralisé de noms de machines (RFC 810, RFC 952, et peut-être aussi RFC 953). Tout n'est pas écrit : le DNS n'a pas aujourd'hui une spécification unique et à jour, aux RFC de base (RFC 1034 et RFC 1035, il faut ajouter des dizaines de RFC qui complètent ou modifient ces deux-ci, ainsi que pas mal de culture orale. (Un exemple de cette difficulté était que, pendant le développement du RFC 7816, son auteur s'est aperçu que personne ne se souvenait pourquoi les résolveurs envoyaient le FQDN complet dans les requêtes.) Plusieurs techniques ont même été supprimées comme les requêtes inverses (RFC 3425) ou comme les types d'enregistrement WKS, MD, MF et MG.

D'autres auraient dû être supprimées, car inutilisables en pratique, comme les classes (que prétendait utiliser le projet Net4D), et qui ont fait l'objet de l'Internet-Draft « The DNS Is Not Classy: DNS Classes Considered Useless », malheureusement jamais adopté dans une IETF parfois paralysée par la règle du consensus.

D'autres évolutions ont eu lieu : le DNS original ne proposait aucun mécanisme d'options, tous les clients et tous les serveurs avaient exactement les mêmes capacités. Cela a changé avec l'introduction d'EDNS, dans le RFC 2671 en 1999.

Beaucoup d'articles ont été écrits sur les systèmes de nommage. (Le RFC recommande l'article de V. Cerf, « Desirable Properties of Internet Identifiers », ou bien le livre « Signposts in Cyberspace: The Domain Name System and Internet Navigation ». Je me permets de rajouter mes articles, « Inventer un meilleur système de nommage : pas si facile », « Un DNS en pair-à-pair ? » et « Mon premier nom Namecoin enregistré ».)

Pourquoi est-ce que les gens ne sont pas contents du DNS actuel et veulent le changer (section 4 du RFC, la plus longue du RFC) ? Il y a des tas de raisons. Certaines, dit l'auteur, peuvent mener à des évolutions raisonnables du DNS actuel. Certaines nécessiteraient un protocole complètement nouveau, incompatible avec le DNS. D'autres enfin seraient irréalistes, quel que soit le système utilisé. La section 4 les passe en revue (rappelez-vous que ce RFC est une initiative individuelle, pas une opinion consensuelle à l'IETF).

Premier problème, les requêtes « multi-types ». À l'heure actuelle, une requête DNS est essentiellement composée d'un nom (QNAME, Query Name) et d'un type (QTYPE, Query Type, par exemple AAAA pour une adresse IP, TLSA pour une clé publique, etc). Or, on aurait parfois besoin de plusieurs types. L'exemple classique est celui d'une machine double-pile (IPv6 et le vieil IPv4), qui ne sait pas quelle version d'IP est acceptée en face et qui demande donc l'adresse IPv6 et l'adresse IPv4 du pair. Il n'y a actuellement pas de solution pour ce problème, il faut faire deux requêtes DNS. (Et, non, ANY ne résout pas ce problème, notamment en raison de l'interaction avec les caches : que doit faire un cache qui ne connait qu'une seule des deux adresses ?)

Deuxième problème, la sensibilité à la casse. La norme originale prévoyait des requêtes insensibles à la casse (RFC 1034, section 3.1), ce qui semble logique aux utilisateurs de l'alphabet latin. Mais c'est plutôt une source d'ennuis pour les autres écritures (et c'est une des raisons pour lesquelles accepter l'Unicode dans les noms de domaine nécessite des méthodes particulières). Avec ASCII, l'insensibilité à la casse est facile (juste un bit à changer pour passer de majuscule en minuscule et réciproquement) mais ce n'est pas le cas pour le reste d'Unicode. En outre, il n'est pas toujours évident de connaitre la correspondance majuscule-minuscule (cf. les débats entre germanophones sur la majuscule de ß). Actuellement, les noms de domaine en ASCII sont insensibles à la casse et ceux dans le reste du jeu de caractères Unicode sont forcément en minuscules (cf. RFC 5890), libre à l'application de mettre ses propres règles d'insensibilité à la casse si elle veut, lorsque l'utilisateur utilise un nom en majuscules comme RÉUSSIR-EN.FR. On referait le DNS en partant de zéro, peut-être adopterait-on UTF-8 comme encodage obligatoire, avec normalisation NFC dans les serveurs de noms, mais c'est trop tard pour le faire.

En parlant d'IDN, d'ailleurs, ce sujet a été à l'origine de nombreuses discussions, incluant pas mal de malentendus (pour lesquels, à mon humble avis, l'auteur de RFC a une sérieuse responsabilité). Unicode a une particularité que n'a pas ASCII : le même caractère peut être représenté de plusieurs façons. L'exemple classique est le É qui peut être représenté par un point de code, U+00C9 (LATIN CAPITAL LETTER E WITH ACUTE), ou par deux, U+0045 (LATIN CAPITAL LETTER E) et U+0301 (COMBINING ACUTE ACCENT). Je parle bien de la représentation en points de code, pas de celle en bits sur le réseau, qui est une autre affaire ; notez que la plupart des gens qui s'expriment à propos d'Unicode sur les forums ne connaissent pas Unicode. La normalisation Unicode vise justement à n'avoir qu'une forme (celle à un point de code si on utilise NFC) mais elle ne traite pas tous les cas gênants. Par exemple, dans certains cas, la fonction de changement de casse dépend de la langue (que le DNS ne connait évidemment pas). Le cas le plus célèbre est celui du i sans point U+0131, qui a une règle spécifique en turc. Il ne sert à rien de râler contre les langues humaines (elles sont comme ça, point), ou contre Unicode (dont la complexité ne fait que refléter celles des langues humaines et de leurs écritures). Le point important est qu'on n'arrivera pas à faire en sorte que le DNS se comporte comme M. Toutlemonde s'y attend, sauf si on se limite à un M. Toutlemonde étatsunien (et encore).

Les IDN ont souvent été accusés, y compris dans ce RFC, de permettre, ou en tout cas de faciliter, le hameçonnage par la confusion possible entre deux caractères visuellement proches. En fait, le problème n'est pas spécifique aux IDN (regardez google.com et goog1e.com) et les études montrent que les utilisateurs ne vérifient pas les noms, de toute façon. Bref, il s'agit de simple propagande de la part de ceux qui n'ont jamais vraiment accepté Unicode.

Les IDN nous amènent à un problème proche, celui des synonymes. Les noms de domaine color.example et colour.example sont différents alors que, pour tout anglophone, color et colour sont « équivalents ». J'ai mis le mot « équivalent » entre guillemets car sa définition même est floue. Est-ce que « Saint-Martin » est équivalent à « St-Martin » ? Et est-ce que « Dupont » est équivalent à « Dupond » ? Sans même aller chercher des exemples comme l'équivalence entre sinogrammes simplifiés et sinogrammes traditionnels, on voit que l'équivalence est un concept difficile à cerner. Souvent, M. Michu s'agace « je tape st-quentin.fr, pourquoi est-ce que ça n'est pas la même chose que saint-quentin-en-yvelines.fr ? » Fondamentalement, la réponse est que le DNS ne gère pas les requêtes approximatives, et qu'il n'est pas évident que tout le monde soit d'accord sur l'équivalence de deux noms. Les humains se débrouillent avec des requêtes floues car ils ont un contexte. Si on est dans les Yvelines, je sais que « St-Quentin » est celui-ci alors que, si on est dans l'Aisne, mon interlocuteur parle probablement de celui-là. Mais le DNS n'a pas ce contexte.

Plusieurs RFC ont été écrit à ce sujet, RFC 3743, RFC 4290, RFC 6927 ou RFC 7940, sans résultats convaincants. Le DNS a bien sûr des mécanismes permettant de dire que deux noms sont équivalents, comme les alias (enregistrements CNAME) ou comme les DNAME du RFC 6672. Mais :

  • Aucun d'entre eux n'a exactement la sémantique que les utilisateurs voudraient (d'où des propositions régulières d'un nouveau mécanisme comme les BNAME),
  • Et ils supposent que quelqu'un ait configuré les correspondances, ce qui suscitera des conflits, et ne satisfera jamais tout le monde.

Même écrire un cahier des charges des « variantes » n'a jamais été possible. (C'est également un sujet sur lequel j'avais écrit un article.)

Passons maintenant aux questions de protection de la vie privée. L'auteur du RFC note que la question suscite davantage de préoccupations aujourd'hui mais ne rappelle pas que ces préoccupations ne sont pas irrationnnelles, elles viennent en grande partie de la révélation de programmes de surveillance massive comme MoreCowBell. Et il « oublie » d'ailleurs de citer le RFC 7626, qui décrit en détail le problème de la vie privée lors de l'utilisation du DNS.

J'ai parlé plus haut du problème des classes dans le DNS, ce paramètre supplémentaire des enregistrements DNS (un enregistrement est identifié par trois choses, le nom, la classe et le type). L'idée au début (RFC 1034, section 3.6) était de gérer depuis le DNS plusieurs protocoles très différents (IP, bien sûr, mais aussi CHAOS et d'autres futurs), à l'époque où le débat faisait rage entre partisans d'un réseau à protocole unique (le futur Internet) et ceux et celles qui préféraient un catenet, fondé sur l'interconnexion de réseaux techniquement différents. Mais, aujourd'hui, la seule classe qui sert réellement est IN (Internet) et, en pratique, il y a peu de chances que les autres soient jamais utilisées. Il a parfois été suggéré d'utiliser les classes pour partitionner l'espace de noms (une classe IN pour l'ICANN et créer une classe UN afin de la donner à l'UIT pour qu'elle puisse jouer à la gouvernance ?) mais le fait que les classes aient été très mal normalisées laisse peu d'espoir. (Est-ce que IN example, CH example et UN example sont la même zone ? Ont-ils les mêmes serveurs de noms ? Cela n'a jamais été précisé.)

Une particularité du DNS qui déroute souvent les nouveaux administrateurs système est le fait que les données ne soient que faiblement synchronisées : à un moment donné, il est parfaitement normal que plusieurs valeurs coexistent dans l'Internet. Cela est dû à plusieurs choix, notamment :

  • Celui d'avoir plusieurs serveurs faisant autorité pour une zone, et sans mécanisme assurant leur synchronisation forte. Lorsque le serveur maître (ou primaire) est mis à jour, il sert immédiatement les nouvelles données, sans attendre que les esclaves (ou secondaires) se mettent à jour.
  • Et le choix d'utiliser intensivement les caches, la mémoire des résolveurs. Si un serveur faisant autorité sert un enregistrement avec un TTL de 7 200 secondes (deux heures) et que, cinq minutes après qu'un résolveur ait récupéré cet enregistrement, le serveur faisant autorité modifie l'enregistrement, les clients du résolveur verront encore l'ancienne valeur pendant 7 200 - 300 = 6 900 secondes.

Cela a donné naissance à la légende de la propagation du DNS et aux chiffres fantaisistes qui accompagnent cette légende comme « il faut 24 h pour que le DNS se propage ».

Ces choix ont assuré le succès du DNS, en lui permettant de passer à l'échelle, vers un Internet bien plus grand que prévu à l'origine. Un modèle à synchronisation forte aurait été plus compliqué, plus fragile et moins performant.

Mais tout choix en ingéniérie a des bonnes conséquences et des mauvaises : la synchronisation faible empêche d'utiliser le DNS pour des données changeant souvent. Des perfectionnements ont eu lieu (comme la notification non sollicitée du RFC 1996, qui permet aux serveurs secondaires d'être au courant rapidement d'un changement, mais qui ne marche que dans le cas où on connait tous les secondaires) mais n'ont pas fondamentalement changé le tableau. Bien sûr, les serveurs faisant autorité qui désireraient une réjuvénation plus rapide peuvent toujours abaisser le TTL mais, en dessous d'une certaine valeur (typiquement 30 à 60 minutes), les TTL trop bas sont parfois ignorés.

Un autre point où les demandes de beaucoup d'utilisateurs rentrent en friction avec les concepts du DNS est celui des noms privés, des noms qui n'existeraient qu'à l'intérieur d'une organisation particulière, et qui ne nécessiteraient pas d'enregistrement auprès d'un tiers. La bonne méthode pour avoir des noms privés est d'utiliser un sous-domaine d'un domaine qu'on a enregistré (aujourd'hui, tout le monde peut avoir son domaine assez facilement, voir gratuitement), et de le déléguer à des serveurs de noms qui ne sont accessibles qu'en interne. Si on est l'association Example et qu'on est titulaire de example.org, on crée priv.example.org et on y met ensuite les noms « privés » (je mets privé entre guillemets car, en pratique, comme le montrent les statistiques des serveurs de noms publics, de tels noms fuitent souvent à l'extérieur, par exemple quand un ordinateur portable passe du réseau interne à celui d'un FAI public).

Il faut noter que beaucoup d'organisations, au lieu d'utiliser la bonne méthode citée ci-dessus, repèrent un TLD actuellement inutilisé (.home, .lan, .private…) et s'en servent. C'est une très mauvaise idée, car, un jour, ces TLD seront peut-être délégués, avec les risques de confusion que cela entrainera (cf. le cas de .box et celui de .dev).

Les administrateurs système demandent souvent « mais quel est le TLD réservé pour les usages internes » et sont surpris d'apprendre qu'il n'en existe pas. C'est en partie pour de bonnes raisons (imaginez deux entreprises utilisant ce TLD et fusionnant… Ou simplement s'interconnectant via un VPN… Un problème qu'on voit souvent avec le RFC 1918.) Mais c'est aussi en partie parce que les tentatives d'en créer un se sont toujours enlisées dans les sables de la bureaucratie (personne n'a envie de passer dix ans de sa vie professionnelle à faire du lobbying auprès de l'ICANN pour réserver un tel TLD). La dernière tentative était celle de .internal mais elle n'a pas marché.

Il y a bien un registre des noms de domaines (pas uniquement des TLD) « à usage spécial », créé par le RFC 6761. Il a malheureusement été gelé par l'IESG et fait l'objet de contestations (RFC 8244). Aucun des noms qu'il contient ne convient vraiment au besoin de ceux qui voudraient des noms de domaine internes (à part .test qui devrait logiquement être utilisé pour les bancs de test, de développement, etc). Le RFC note qu'un des principaux problèmes d'un tel registre est qu'il est impossible de garder à jour tous les résolveurs de la planète quand ce registre est modifié. On ne peut donc pas garantir qu'un nouveau TLD réservé sera bien traité de manière spéciale par tous les résolveurs.

Une caractéristique du DNS qui a suscité beaucoup de débats, pas toujours bien informés et pas toujours honnêtes, est l'existence de la racine du DNS, et des serveurs qui la servent. Lors de la mise au point du DNS, la question s'était déjà posée, certains faisant remarquer que cette racine allait focaliser les problèmes, aussi bien techniques que politiques. L'expérience a montré qu'en fait la racine marchait bien, mais cela n'a pas évité les polémiques. Le RFC note que le sujet est très chaud : qui doit gérer un serveur racine ? Où faut-il les placer physiquement ? Si l'anycast a largement résolu la seconde question (RFC 7094), la première reste ouverte. Le RFC n'en parle pas mais, si la liste des onze (ou douze, ça dépend comment on compte) organisations qui gèrent un serveur racine n'a pas évolué depuis vingt ans, ce n'est pas pour des raisons techniques, ni parce qu'aucune organisation n'est capable de faire mieux que les gérants actuels, mais tout simplement parce qu'il n'existe aucun processus pour supprimer ou ajouter un serveur racine. Comme pour les membres permanents du Conseil de Sécurité de l'ONU, on en reste au statu quo, aussi inacceptable soit-il, simplement parce qu'on ne sait pas faire autrement.

Le problème de la gestion de la racine n'est pas uniquement celui de la gestion des serveurs racine. Le contenu de la zone racine est tout aussi discuté. Si les serveurs racine sont les imprimeurs du DNS, le gérant de la zone racine en est l'éditeur. Par exemple, combien faut-il de TLD ? Si quelqu'un veut créer .pizza, faut-il le permettre ? Et .xxx ? Et .vin, que le gouvernement français avait vigoureusement combattu ? Ou encore .home, déjà largement utilisé informellement dans beaucoup de réseaux locaux, mais pour lequel il y avait trois candidatures à l'ICANN (rejetées peu de temps avant la publication du RFC). Ces questions, qui se prêtent bien aux jeux politiciens, occupent actuellement un bon bout des réunions ICANN.

La base technique à ces discussions est qu'il n'y a qu'une seule racine (RFC 2826). Son contrôle va donc forcément susciter des conflits. Un autre système de nommage que le DNS, si on le concevait de nos jours, pourrait éviter le problème en évitant ces points de contrôle. Les techniques à base de chaînes de blocs comme Namecoin sont évidemment des candidates possibles. Outre les problèmes pratiques (avec Namecoin, quand on perd sa clé privée, on perd son domaine), la question de fond est « quelle gouvernance souhaite-t-on ? »

La question de la sémantique dans les noms de domaines est également délicate. L'auteur affirme que les noms de domaines sont (ou en tout cas devraient être) de purs identificateurs techniques, sans sémantique. Cela permet de justifier les limites des noms (RFC 1034, section 3.5) : s'ils sont de purs identificateurs techniques, il n'est pas nécessaire de permettre les IDN, par exemple. On peut se contenter des lettres ASCII, des chiffres et du tiret, la règle dite LDH, qui vient du RFC 952. Cette règle « Letters-Digits-Hyphen » a été une première fois remise en cause vers 1986 lorsque 3Com a voulu son nom de domaine 3com.com (à l'époque, un nom devait commencer par une lettre, ce qui a été changé par la norme actuelle, RFC 1123). Mais cela laisse d'autres marques sans nom de domaine adapté, par exemple C&A ne peut pas avoir c&a.fr. Sans parler des cas de ceux et celles qui n'utilisent pas l'alphabet latin.

L'argument de Klensin est que ce n'est pas grave : on demande juste aux noms de domaine d'être des identificateurs uniques et non ambigus. Qu'ils ne soient pas très « conviviaux » n'est pas un problème. Inutile de dire que ce point de vue personnel ne fait pas l'unanimité.

Bien sûr, il y a aussi un aspect technique. Si on voulait, dit l'auteur ironiquement, permettre l'utilisation de la langue naturelle dans les noms de domaine, il faudrait aussi supprimer la limite de 63 caractères par composant (255 caractères pour le nom complet). Il est certain qu'il est difficile d'avoir des identificateurs qui soient à la fois utiles pour les programmes (simples, non ambigus) et pour les humains.

Le DNS n'est pas figé, et a évolué depuis ses débuts. Notamment, beaucoup de nouveaux types (RRTYPE, pour Resource Record Type) ont été créés avec le temps (cf. RFC 6895). Ce sont, par exemple :

  • NAPTR (RFC 3403), système que je trouve fort compliqué et qui n'a pas eu de succès,
  • URI (RFC 7553) qui permet de stocker des URI dans le DNS (par exemple, dig +short URI 78100.cp.bortzmeyer.fr va vous donner un URI OpenStreetMap correspondant au code postal 78100),
  • SRV (RFC 2782), qui généralise le vieux MX en permettant une indirection depuis le nom de domaine vers un nom de serveur (hélas, HTTP est le seul protocole Internet qui, stupidement, ne l'utilise pas).

Une observation à partir de l'étude du déploiement de tous les nouveaux types d'enregistrement est que ça se passe mal : pare-feux débiles qui bloquent les types qu'ils ne connaissent pas, interfaces de gestion du contenu des zones qui ne sont jamais mises à jour (bien des hébergeurs DNS ne permettent pas d'éditer URI ou TLSA, voir simplement SRV), bibliothèques qui ne permettent pas de manipuler ces types… Cela a entrainé bien des concepteurs de protocole à utiliser le type « fourre-tout » TXT. Le RFC 5507 explique ses avantages et (nombreux) inconvénients. (Le RFC 6686 raconte comment le type générique TXT a vaincu le type spécifique SPF.)

Aujourd'hui, tout le monde et son chien a un nom de domaine. Des noms se créent en quantité industrielle, ce qui est facilité par l'automatisation des procédures, et le choix de certains registres de faire des promotions commerciales. Il n'est pas exagéré de dire que, surtout dans les nouveaux TLD ICANN, la majorité des noms sont créés à des fins malveillantes. Il est donc important de pouvoir évaluer la réputation d'un nom : si mail.enlargeyourzob.xyz veut m'envoyer du courrier, puis-je utiliser la réputation de ce domaine (ce qu'il a fait précédemment) pour décider de rejeter le message ou pas ? Et si un utilisateur clique sur http://www.bitcoinspaschers.town/, le navigateur Web doit-il l'avertir que ce domaine a mauvaise réputation ? Le RFC, souvent nostalgique, rappelle que le modèle original du DNS, formalisé dans le RFC 1591, était que chaque administrateur de zone était compétent, responsable et honnête. Aujourd'hui, chacune de ces qualités est rare et leur combinaison est encore plus rare. L'auteur du RFC regrette que les registres ne soient pas davantage comptables du contenu des zones qu'ils gèrent, ce qui est un point de vue personnel et très contestable : pour un TLD qui est un service public, ce serait une violation du principe de neutralité.

Bref, en pratique, il est clair aujourd'hui qu'on trouve de tout dans le DNS. Il serait donc souhaitable qu'on puisse trier le bon grain de l'ivraie mais cela présuppose qu'on connaisse les frontières administratives. Elles ne coïncident pas forcément avec les frontières techniques (.fr et gouv.fr sont actuellement dans la même zone alors que le premier est sous la responsabilité de l'AFNIC et le second sous celle du gouvernement français). Rien dans le DNS ne les indique (le point dans un nom de domaine indique une frontière de domaine, pas forcément une frontière de zone, encore moins une frontière de responsabilité). Beaucoup de légendes circulent à ce sujet, par exemple beaucoup de gens croient à tort que tout ce qui se trouve avant les deux derniers composants d'un nom est sous la même autorité que le nom de deuxième niveau (cf. mon article sur l'analyse d'un nom). Il n'y a pas actuellement de mécanisme standard et sérieux pour déterminer les frontières de responsabilité dans un nom de domaine. Plusieurs efforts avaient été tentés à l'IETF mais ont toujours échoué. La moins mauvaise solution, aujourd'hui, est la Public Suffix List.

Beaucoup plus technique, parmi les problèmes du DNS, est celui de la taille des paquets. Car la taille compte. Il y a très très longtemps, la taille d'une réponse DNS était limitée à 512 octets. Cette limite a été supprimée en 1999 avec le RFC 2671 (c'est d'ailleurs une excellente question pour un entretien d'embauche lorsque le candidat a mis « DNS » dans la liste de ses compétences : « quelle est la taille maximale d'une réponse DNS ? »). En théorie, les réponses peuvent désormais être plus grandes (la plupart des serveurs sont configurés pour 4 096 octets) mais on se heurte à une autre limite : la MTU de 1 500 octets tend à devenir une valeur sacrée, et les réponses plus grandes que cette taille ont du mal à passer, par exemple parce qu'un pare-feu idiot bloque les fragments IP, ou parce qu'un pare-feu tout aussi crétin bloque l'ICMP, empêchant les messages Packet Too Big de passer (cf. RFC 7872).

Bref, on ne peut plus trop compter sur la fragmentation, et les serveurs limitent parfois leur réponse en UDP (TCP n'a pas de problème) à moins de 1 500 octets pour cela.

Une section entière du RFC, la 5, est consacrée au problème de la requête inverse, c'est-à-dire comment trouver un nom de domaine en connaissant le contenu d'un enregistrement lié à ce nom. La norme historique prévoyait une requête spécifique pour cela, IQUERY (RFC 1035, sections 4.1.1 et 6.4). Mais elle n'a jamais réellement marché (essentiellement parce qu'elle suppose qu'on connaisse déjà le serveur faisant autorité… pour un nom de domaine qu'on ne connait pas encore) et a été retirée dans le RFC 3425. Pour permettre quand même des « requêtes inverses » pour le cas le plus demandé, la résolution d'une adresse IP en un nom de domaine, un truc spécifique a été développé, l'« arbre inverse » in-addr.arpa (puis plus tard ip6.arpa pour IPv6). Ce truc n'utilise pas les IQUERY mais des requêtes normales, avec le type PTR. Ainsi, l'option -x de dig permet à la fois de fabriquer le nom en in-addr.arpa ou ip6.arpa et de faire une requête de type PTR pour lui :

% dig -x 2001:678:c::1
...
;; ANSWER SECTION:
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.c.0.0.0.8.7.6.0.1.0.0.2.ip6.arpa. 172796 IN PTR	d.nic.fr.
  

Cette technique pose des problèmes dans le cas de préfixes IPv4 ne tenant pas sur une frontière d'octets (cas traité par le RFC 2317). Globalement, c'est toujours resté un truc, parfois utile, souvent surestimé, mais ne fournissant jamais un service général. Une tentative avait été faite à l'IETF pour décrire ce truc et son utilisation, mais elle n'a jamais abouti (draft-ietf-dnsop-reverse-mapping-considerations), la question étant trop sensible (même écrire « des gens trouvent que les enregistrements PTR sont utiles, d'autres personnes ne sont pas d'accord », même une phrase comme cela ne rencontrait pas de consensus).

Enfin, la section 7 du RFC est consacrée à un problème difficile : le DNS ne permet pas de recherche floue. Il faut connaitre le nom exact pour avoir les données. Beaucoup d'utilisateurs voudraient quelque chose qui ressemble davantage à un moteur de recherche. Ils n'ont pas d'idée très précise sur comment ça devrait fonctionner mais ils voudraient pouvoir taper « st quentin » et que ça arrive sur www.saint-quentin-en-yvelines.fr. Le fait qu'il existe plusieurs villes nommées Saint-Quentin ne les arrête pas ; ils voudraient que ça marche « tout seul ». Le DNS a un objectif très différent : fournir une réponse exacte à une question non ambigüe.

Peut-être aurait-on pu développer un service de recherche floue au dessus du DNS. Il y a eu quelques réflexions à ce sujet (comme le projet IRNSS ou comme le RFC 2345) mais ce n'est jamais allé très loin. En pratique, les moteurs de recherche jouent ce rôle, sans que l'utilisateur comprenne la différence. Peu d'entre eux savent qu'un nom de domaine, ce n'est pas comme un terme tapé dans un moteur de recherche. On voit aussi bien des gens taper un nom de domaine dans la boîte de saisie du terme de recherche, que des gens utiliser le moteur de recherche comme fournisseurs d'identificateurs (« pour voir notre site Web, tapez "trucmachin" dans Google »). Le dernier clou dans le cercueil de la compréhension de la différence entre identificateur et moteur de recherche a été planté quand les navigateurs ont commencé à fusionner barre d'adresses et boite de saisie de la recherche.


Téléchargez le RFC 8324


L'article seul

RFC 8318: IAB, IESG, and IAOC Selection, Confirmation, and Recall Process: IAOC Advisor for the Nominating Committee

Date de publication du RFC : Janvier 2018
Auteur(s) du RFC : S. Dawkins (Wonder Hamster)
Première rédaction de cet article le 1 février 2018


Un petit RFC bureaucratique pour traiter un manque du RFC 7437, qui ne disait pas que l'IAOC devait envoyer quelqu'un au NomCom, le comité de nomination.

En effet, le NomCom, le comité chargé d'étudier les personnes qui pourront occuper des postes dans divers organismes de l'IETF (cf. RFC 7437), ce NomCom s'occupe entre autres des postes à l'IAOC (RFC 4071), mais ne disait pas que l'IAOC pouvait envoyer un membre au NomCom, comme le faisaient les autres organes. A priori, ce n'était pas grave puisque le NomCom pouvait toujours ajouter qui il voulait comme observateur mais, en 2017, le NomCom a travaillé sur un poste à l'IAOC sans avoir de représentant de l'IAOC à ses réunions.

Ce n'est pas la fin du monde mais cela a justifié ce RFC, qui ajoute juste aux règles existantes que le NomCom devrait veiller à avoir quelqu'un de l'IAOC, ou qui connait l'IAOC.

Les discussions qui ont eu lieu autour de ce minuscule changement sont résumées dans l'annexe A. Par exemple, après un long débat, ce « représentant » de l'IAOC sera qualifié d'« advisor » et pas de « liaison » (en gros, un « liaison » a un boulot plus formel et plus sérieux.)


Téléchargez le RFC 8318


L'article seul

RFC 8315: Cancel-Locks in Netnews articles

Date de publication du RFC : Février 2018
Auteur(s) du RFC : M. Bäuerle (STZ Elektronik)
Chemin des normes
Première rédaction de cet article le 14 février 2018


Cela peut sembler étonnant, mais le service des News fonctionne toujours. Et il est régulièrement perfectionné. Ce nouveau RFC normalise une extension au format des articles qui permettra de sécuriser un petit peu l'opération d'annulation d'articles.

Une fois qu'un article est lancé sur un réseau social décentralisé, comme Usenet (RFC 5537), que faire si on le regrette ? Dans un système centralisé comme Twitter, c'est simple, on s'authentifie, on le supprime et plus personne ne le voit. Mais dans un réseau décentralisé, il faut encore propager la demande de suppression (d'annulation, sur les News). Et cela pose évidemment des questions de sécurité : il ne faut pas permettre aux méchants de fabriquer trop facilement une demande d'annulation. Notre RFC propose donc une mesure de sécurité, l'en-tête Cancel-Lock:.

Cette mesure de sécurité est simple, et ne fournit certainement pas une sécurité de niveau militaire. Pour la comprendre, il faut revenir au mécanisme d'annulation d'un article d'Usenet. Un article de contrôle est un article comme les autres, envoyé sur Usenet, mais il ne vise pas à être lu par les humains, mais à être interprété par le logiciel. Un exemple d'article de contrôle est l'article de contrôle d'annulation, défini dans le RFC 5337, section 5.3. Comme son nom l'indique, il demande la suppression d'un article, identifié par son Message ID. Au début d'Usenet, ces messages de contrôle n'avaient aucune forme d'authentification. On a donc vu apparaitre des faux messages de contrôle, par exemple à des fins de censure (supprimer un article qu'on n'aimait pas). Notre nouveau RFC propose donc qu'un logiciel proche de la source du message mette un en-tête Cancel-Lock: qui indique la clé qui aura le droit d'annuler le message.

Évidemment, ce Cancel-Lock: n'apporte pas beaucoup de sécurité, entre autre parce qu'un serveur peut toujours le retirer et mettre le sien, avant de redistribuer (c'est évidemment explicitement interdit par le RFC mais il y a des méchants). Mais cela ne change de toute façon pas grand'chose à la situation actuelle, un serveur peut toujours jeter un article, de toute façon. Si on veut quand même une solution de sécurité « sérieuse », il faut utiliser PGP, comme mentionné en passant par le RFC 5537 (mais jamais normalisé dans un RFC).

La section 2 du RFC décrit en détail le mécanisme de sécurité. La valeur de l'en-tête Cancel-Lock: est l'encodage en base64 d'une condensation d'une clé secrète (en fait, on devrait plutôt l'appeler mot de passe). Pour authentifier une annulation, le message de contrôle comportera un autre en-tête, Cancel-Key:, qui révélera la clé (qui ne devra donc être utilisée qu'une fois).

Voici un exemple. On indique explicitement l'algorithme de condensation (ici, SHA-256, la liste est dans un registre IANA). D'abord, le message original aura :

Cancel-Lock: sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc=
    

Et voici le message de contrôle, authentifié :

Cancel-Key: sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA=
    

La section 3 du RFC détaille comment on utilise ces en-têtes. Le Cancel-Lock: peut être mis par l'auteur originel de l'article, ou bien par un intermédiaire (par exemple le modérateur qui a approuvé l'article). Plusieurs Cancel-Lock: peuvent donc être présents. Notez qu'il n'y a aucun moyen de savoir si le Cancel-Lock: est « authentique ». Ce mécanisme est une solution de sécurité faible.

Pour annuler un message, on envoie un message de contrôle avec un Cancel-Key: correspondant à un des Cancel-Lock:. Les serveurs recevant ce message de contrôle condenseront la clé (le mot de passe) et vérifieront s'ils retombent bien sur le condensat contenu dans un des Cancel-Lock:.

La section 4 donne les détails sur le choix de la clé (du mot de passe). Évidemment, elle doit être difficile à deviner, donc plutôt choisie par un algorithme pseudo-aléatoire (et pas "azerty123"). Et elle doit être à usage unique puisque, une fois révélée par un Cancel-Key:, elle n'est plus secrète. L'algorithme recommandé par le RFC est d'utiliser un HMAC (RFC 2104) d'un secret et de la concaténation du Message ID du message avec le nom de l'utilisateur. Comme cela, générer un Cancel-Key: pour un message donné peut se faire avec juste le message, sans avoir besoin de mémoriser les clés. Voici un exemple, tiré de la section 5, et utilisant OpenSSL. Le secret est frobnicateZ32. Le message est le <12345@example.net> et l'utilisateur est stephane :

      
% printf "%s" "<12345@example.net>stephane" \
        | openssl dgst -sha256 -hmac "frobnicateZ32" -binary \
        | openssl enc -base64
f0rHwfZXp5iKFjTbX/I5bQXh9Dta33nWBzLi8f9oaoM=

    

Voilà, nous avons notre clé, f0rHwfZXp5iKFjTbX/I5bQXh9Dta33nWBzLi8f9oaoM=. Pour le condensat, nous nous servirons de SHA-256 :


% printf "%s" "f0rHwfZXp5iKFjTbX/I5bQXh9Dta33nWBzLi8f9oaoM=" \
        | openssl dgst -sha256 -binary \
        | openssl enc -base64
RBJ8ZsgqBnW/tYT/qu1JcXK8SA2O9g+qJLDzRY5h1cg=	
   
    

Nous pouvons alors former le Cancel-Lock: :

Cancel-Lock: sha256:RBJ8ZsgqBnW/tYT/qu1JcXK8SA2O9g+qJLDzRY5h1cg=
    

Et, si nous voulons annuler ce message, le Cancel-Key: dans le message de contrôle d'annulation aura l'air :

Control: cancel <12345@example.net>
Cancel-Key: sha256:f0rHwfZXp5iKFjTbX/I5bQXh9Dta33nWBzLi8f9oaoM=
    

Pour vérifier ce message de contrôle, le logiciel calculera le condensat de la clé et vérifiera s'il retombe bien sur RBJ8ZsgqBnW/tYT/qu1JcXK8SA2O9g+qJLDzRY5h1cg=.

Enfin, la section 7 du RFC détaille la sécurité de ce mécanisme. Cette sécurité est plutôt faible :

  • Aucune protection de l'intégrité. Un intermédiaire a pu modifier, ajouter ou supprimer le Control-Lock:. Si cela vous défrise, vous devez utiliser PGP.
  • Lors d'une annulation, la clé est visible par tous, donc elle peut être copiée et utilisée dans un message de contrôle de remplacement (au lieu de l'annulation). Mais, de toute façon, un attaquant peut aussi bien faire un nouveau message faux (Usenet ne vérifie pas grand'chose).
  • Avant ce RFC, ce mécanisme était déjà largement utilisé, depuis longtemps, et souvent en utilisant SHA-1 comme fonction de condensation. Contrairement à ce qu'on lit parfois, SHA-1 n'est pas complètement cassé : il n'y a pas encore eu de publication d'une attaque pré-image pour SHA-1 (seulement des collisions). Néanmoins, SHA-1 ne peut plus être considéré comme sûr, d'autant plus que Usenet évolue très lentement : un logiciel fait aujourd'hui va rester en production longtemps et, avec le temps, d'autres attaques contre SHA-1 apparaitront. D'où la recommandation du RFC de n'utiliser que SHA-2.

Les deux nouveaux en-têtes ont été ajoutés au registre des en-têtes.

À noter que, comme il n'y a pas de groupe de travail IETF sur les News, ce RFC a été surtout discuté… sur les News, en l'occurrence les groupes news.software.nntp et de.comm.software.newsserver. Comme ce RFC décrit une technique ancienne, il y a déjà de nombreuses mises en œuvre comme la bibliothèque canlock (paquetage Debian libcanlock2), dans le serveur INN, ou les clients News Gnus (regardez cet article sur son usage), flnews, slrn ou tin. Vous pouvez aussi lire l'article de Brad Templeton comparant Cancel-Lock: aux signatures.

Merci à Julien Élie pour sa relecture.


Téléchargez le RFC 8315


L'article seul

RFC 8314: Cleartext Considered Obsolete: Use of TLS for Email Submission and Access

Date de publication du RFC : Janvier 2018
Auteur(s) du RFC : K. Moore (Windrock), C. Newman (Oracle)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF uta
Première rédaction de cet article le 31 janvier 2018


Ce RFC s'inscrit dans le cadre des efforts de sécurisation de l'Internet contre la surveillance massive, efforts notablement accélérés depuis les révélations Snowden. Désormais, l'usage de texte en clair (non chiffré) pour le courrier électronique est officiellement abandonné : POP, IMAP et SMTP doivent être chiffrés.

Plus précisément, ce nouveau RFC du groupe de travail UTA vise l'accès au courrier (POPRFC 1939 et IMAPRFC 3501), ainsi que la soumission de messages par SMTP - RFC 6409 (entre le MUA et le premier MTA). Les messages de ces protocoles doivent désormais être systématiquement chiffrés avec TLSRFC 5246. Le but est d'assurer la confidentialité des échanges. Le cas de la transmission de messages entre MTA est couvert par des RFC précédents, RFC 3207 et RFC 7672.

Pour résumer les recommandations concrètes de ce RFC :

  • TLS 1.2 au minimum (on croise encore souvent SSL malgré le RFC 7568).
  • Migrer le plus vite possible vers le tout-chiffré si ce n'est pas déjà fait.
  • Utiliser le « TLS implicite » sur un port dédié, où on démarre TLS immédiatement (par opposition au vieux système STARTTLS, où on demandait explicitement le démarrage de la cryptographie, cf. sections 2 et 3 du RFC).

Ce RFC ne traite pas le cas du chiffrement de bout en bout, par exemple avec PGP (RFC 4880 et RFC 3156). Ce chiffrement de bout en bout est certainement la meilleure solution mais il est insuffisamment déployé aujourd'hui. En attendant qu'il se généralise, il faut bien faire ce qu'on peut pour protéger les communications. En outre, PGP ne protège pas certaines métadonnées comme les en-têtes (From:, Subject:, etc), alors qu'un chiffrement TLS du transport le fait. Bref, on a besoin des deux.

La section 3 du RFC rappelle ce qu'est le « TLS implicite », qui est désormais recommandé. Le client TLS se connecte à un serveur TLS sur un port dédié, où tout se fait en TLS, et il démarre la négociation TLS immédiatement. Le TLS implicite s'oppose au « TLS explicite » qui était l'approche initiale pour le courrier. Avec le TLS explicite (RFC 2595 et RFC 3207), le serveur devait annoncer sa capacité à faire du TLS :

% telnet smtpagt1.ext.cnamts.fr. smtp
Trying 93.174.145.55...
Connected to smtpagt1.ext.cnamts.fr.
Escape character is '^]'.
220 smtpagt1.ext.cnamts.fr ESMTP CNAMTS (ain1)
EHLO mail.example.com
250-smtpagt1.ext.cnamts.fr Hello mail.example.com [192.0.2.187], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250 STARTTLS
    

Et le client devait dire qu'il allait démarrer la session TLS avec la commande STARTTLS. L'inconvénient principal de STARTTLS est qu'il est vulnérable à l'attaque « SSL stripping » où un attaquant actif modifie la communication avant que TLS ne démarre, pour faire croire que le partenaire ne sait pas faire de TLS. (Et il y a aussi la vulnérabilité CERT #555316.) Bien sûr, les serveurs peuvent se protéger en refusant les connexions sans STARTTLS mais peu le font. L'approche STARTTLS était conçue pour gérer un monde où certains logiciels savaient faire du TLS et d'autres pas, mais, à l'heure où la recommandation est de faire du TLS systématiquement, elle n'a plus guère d'utilité. (La question est discutée plus en détail dans l'annexe A. Notez qu'un des auteurs de notre nouveau RFC, Chris Newman, était l'un des auteurs du RFC 2595, qui introduisait l'idée de STARTTLS.)

Avec le TLS implicite, cela donne :

% openssl s_client -connect mail.example.com:465   
...
subject=/CN=mail.example.com
issuer=/O=CAcert Inc./OU=http://www.CAcert.org/CN=CAcert Class 3 Root
...
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
...
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
...
220 mail.example.com ESMTP Postfix
EHLO toto
250-mail.example.com
250-AUTH DIGEST-MD5 NTLM CRAM-MD5
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 SMTPUTF8
    

Donc, concrètement, pour POP, cela veut dire établir la connexion sur le port du TLS implicite, le 995 (et non pas sur le port 110, prévu pour le texte en clair), lancer TLS et authentifier avec le RFC 7817. Puis on fait du POP classique. Pour IMAP, c'est le port 993. Dans les deux cas, cette recommandation de notre RFC ne sera pas trop dure à suivre, le TLS implicite est déjà courant pour ces deux protocoles.

Pour la soumission SMTP (RFC 6409), c'est le port 465 (utilisé auparavant pour du SMTP classique, non-soumission, cf. le registre IANA et les section 7.3 et annexe A du RFC qui justifient cette réaffectation). Le mécanisme avec STARTTLS sur le port 587 (TLS explicite) est très répandu, contrairement à ce qui se passe pour POP et IMAP. La transition sera donc plus longue, et il faudra donc maintenir les deux services, TLS implicite et explicite, pendant un certain temps.

Voici les serveurs IMAP (pour récupérer le courrier) et SMTP (pour soumettre du courrier) conformes aux recommandations de ce RFC (TLS implicite), tels qu'affichés par Thunderbird : thunderbird-servers-ports.png

Et voici la configuration du MTA Postfix pour accepter du TLS implicite sur le port 465 :

submissions inet n       -       -       -       -       smtpd
   -o syslog_name=postfix/submissions
   -o smtpd_tls_wrappermode=yes
   -o smtpd_sasl_auth_enable=yes
   -o smtpd_client_restrictions=permit_sasl_authenticated,reject
   -o smtpd_etrn_restrictions=reject
   -o smtpd_sasl_authenticated_header=yes
    

(À mettre dans le master.cf.) Cette configuration active TLS et exige une authentification du client (ce qui est normal pour soumettre du courrier.) Pensez aussi à vérifier que le port est bien défini dans /etc/services (smtps 465/tcp ssmtp submissions).

La section 4 du RFC fournit des détails sur l'utilisation de TLS, du côté des fournisseurs de service de courrier. Le point essentiel est « chiffrement partout, tout le temps » (section 4.1). L'objectif ne pourra pas forcément être atteint immédiatement par tout le monde mais il faut commencer. Par exemple, on peut interdire tout accès en texte clair à certains utilisateurs, puis généraliser à tous. Et, dans ce cas, le message envoyé doit être indépendant de si le mot de passe était valide ou pas (pour ne pas donner d'indication à un éventuel écoutant). Le RFC conseille aussi de traiter les accès avec les vieilles versions de TLS (ou, pire, avec SSL) de la même façon que les accès en clair. Une fois l'accès en clair coupé, il est recommandé de forcer un changement de mot de passe, si l'ancien avait été utilisé en clair.

Et les autres points ? Les fournisseurs de services de courrier électronique doivent annoncer les services POP, IMAP et soumission SMTP en utilisant les enregistrements SRV du RFC 6186, afin de faciliter la tâche des MUA. Un nouvel enregistrement SRV arrive avec ce RFC, d'ailleurs, le _submissions._tcp, pour la soumission SMTP sur TLS. Le RFC demande que ces enregistrements SRV (ainsi que les enregistrements MX utilisés pour le courrier entrant, donc a priori pas le sujet de ce RFC) soient signés avec DNSSEC. Et, à propos du DNS, le RFC demande également la publication d'enregistrements TLSA (RFC 6698).

La cryptographie, c'est bien, mais il est également souhaitable de signaler qu'elle a été utilisée, et dans quelles conditions, pour informer les utilisateurs de la sécurité dont ils ont pu bénéficier. Par exemple, le RFC demande que les algorithmes de cryptographie utilisées soient mis dans l'en-tête Received: du courrier (cf. aussi le RFC 3848), via une clause tls (dans registre IANA). Notez que beaucoup de serveurs SMTP le font déjà, avec une syntaxe différente :

      
Received: from mail4.protonmail.ch (mail4.protonmail.ch [185.70.40.27])
        (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
        (No client certificate requested)
        by mail.bortzmeyer.org (Postfix) with ESMTPS id 38DAF31D16
        for <stephane@bortzmeyer.org>; Sat, 20 Jan 2018 16:56:59 +0100 (CET)

      

La section 5 décrit les exigences pour l'autre côté, le client, cette fois, et non plus le serveur de la section 4. D'abord, comme les MUA sont en contact direct avec l'utilisateur humain, ils doivent lui indiquer clairement le niveau de confidentialité qui a été obtenu (par exemple par une jolie icône, différente si on a utilisé TLS ou pas). Notez que cette indication de la confidentialité est un des points du projet Caliopen. Gmail, par exemple, peut afficher ces informations et cela donne :gmail-tls.png

Comment est-ce qu'un MUA doit trouver s·on·es serveur·s, au fait ? La méthode recommandée est d'utiliser les enregistements SRV du RFC 6186. Aux _imap._tcp et _pop3._tcp du RFC précédent s'ajoute _submissions._tcp pour le SMTP de soumission d'un message, avec TLS implicite. Attention, le but étant la confidentialité, le MUA ne devrait pas utiliser les serveurs annoncés via les SRV s'ils ne satisfont pas à des exigences minimales de sécurité TLS. Le MUA raisonnable devrait vérifier que le SRV est signé avec DNSSEC, ou, sinon, que le serveur indiqué est dans le même domaine que le domaine de l'adresse de courrier. La section 5.2 donne d'autres idées de choses à vérifier (validation du certificat du serveur suivant le RFC 7817, de la version de TLS…) D'une manière générale, le MUA ne doit pas envoyer d'informations sensibles comme un mot de passe si la session n'est pas sûre. La tentation pourrait être d'afficher à l'utilisateur un dialogue du genre « Nous n'avons pas réussi à établir une connexion TLS satisfaisante car la version de TLS n'est que la 1.1 et le groupe Diffie-Hellman ne fait que 512 bits, voulez-vous continuer quand même ? » Mais le RFC s'oppose à cette approche, faisant remarquer qu'il est alors trop facile pour l'utilisateur de cliquer OK et de prendre ainsi des risques qu'il ne maitrise pas.

Autre question de sécurité délicate, l'épinglage du certificat. Il s'agit de garder un certificat qui a marché autrefois, même s'il ne marche plus, par exemple parce qu'expiré. (Ce n'est donc pas le même épinglage que celui qui est proposé pour HTTP par le RFC 7469.) Le RFC autorise cette pratique, ce qui est du bon sens : un certificat expiré, ce n'est pas la même chose qu'un certificat faux. Et ces certificats expirés sont fréquents car, hélas, bien des administrateurs système ne supervisent pas l'expiration des certificats. Voici la configuration d'Icinga pour superviser un service de soumission via SMTP :

      
apply Service "submissions" {
  import "generic-service"

  check_command = "ssmtp"
  vars.ssmtp_port = 465
  assign where (host.address || host.address6) && host.vars.submissions
  vars.ssmtp_certificate_age = "7,3"
}

    

Et, une fois ce service défini, on peut ajouter à la définition d'un serveur vars.submissions = true et il sera alors supervisé : icinga-submissions.png

Notre RFC recommande également aux auteurs de MUA de faire en sorte que les utilisateurs soient informés du niveau de sécurité de la communication entre le client et le serveur. Tâche délicate, comme souvent quand on veut communiquer avec les humains. Il ne faut pas faire de fausses promesses (« votre connection est cryptée avec des techniques military-grade, vous êtes en parfaite sécurité ») tout en donnant quand même des informations, en insistant non pas sur la technique (« votre connexion utilise ECDHE-RSA-AES256-GCM-SHA384, je vous mets un A+ ») mais sur les conséquences (« Ce serveur de courrier ne propose pas de chiffrement de la communication, des dizaines d'employés de la NSA, de votre FAI, et de la Fsociety sont en train de lire le message où vous parlez de ce que vous avez fait hier soir. »).

Voilà, vous avez l'essentiel de ce RFC. Quelques détails, maintenant. D'abord, l'interaction de ces règles avec les antivirus et antispam. Il y a plusieurs façons de connecter un serveur de messagerie à un logiciel antivirus et·ou antispam (par exemple l'interface Milter, très répandue). Parfois, c'est via SMTP, avec l'antivirus et·ou antispam qui se place sur le trajet, intercepte les messages et les analyse avant de les retransmettre. C'est en général une mauvaise idée (RFC 2979). Dès qu'il y a du TLS dans la communication, c'est encore pire. Puisque le but de TLS est de garantir l'authenticité et l'intégrité de la communication, tout « intercepteur » va forcément être très sale. (Et les logiciels qui font cela sont d'abominables daubes.)

Ah, et un avertissement lié à la vie privée (section 8 du RFC) : si on présente un certificat client, on révèle son identité à tout écoutant. Le futur TLS 1.3 aidera peut-être à limiter ce risque mais, pour l'instant, attention à l'authentification par certificat client.

Si vous aimez connaitre les raisons d'un choix technique, l'annexe A couvre en détail les avantages et inconvénients respectifs du TLS implicite sur un port séparé et du TLS explicite sur le port habituel. La section 7 du RFC 2595 donnait des arguments en faveur du TLS explicite. Certaines des critiques que ce vieux RFC exprimait contre le TLS implicite n'ont plus de sens aujourd'hui (le RFC 6186 permet que le choix soit désormais fait par le logiciel et plus par l'utilisateur, et les algorithmes export sont normalement abandonnés). D'autres critiques ont toujours été mauvaises (par exemple, celle qui dit que le choix entre TLS et pas de TLS est binaire : un MUA peut essayer les deux.) Outre la sécurité, un avantage du port séparé pour TLS est qu'il permet de déployer des frontaux - répartiteurs de charge, par exemple - TLS génériques.

Et pour terminer, d'autres exemples de configuration. D'abord avec mutt, par Keltounet :

      smtp_url=smtps://USER@SERVER:465
    

Et le courrier est bien envoyé en TLS au port de soumission à TLS implicite.

Avec Dovecot, pour indiquer les protocoles utilisés dans la session TLS, Shaft suggère, dans conf.d/10-logging.conf :

login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c %k
    

(Notez le %k à la fin, qui n'est pas dans le fichier de configuration d'exemple.)

Et pour OpenSMTPd ? n05f3ra1u propose :

pki smtp.monserveur.example key "/etc/letsencrypt/live/monserveur.example/privkey.pem"
pki smtp.monserveur.example certificate "/etc/letsencrypt/live/monserveur.example/cert.pem"
...
listen on eno1 port 465 hostname smtp.monserveur.example smtps pki smtp.monserveur.example auth mask-source
    

Téléchargez le RFC 8314


L'article seul

RFC 8312: CUBIC for Fast Long-Distance Networks

Date de publication du RFC : Février 2018
Auteur(s) du RFC : I. Rhee (NCSU), L. Xu (UNL), S. Ha (Colorado), A. Zimmermann, L. Eggert (NetApp), R. Scheffenegger
Pour information
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 8 février 2018


Longtemps après sa mise au point et son déploiement massif sur Linux, voici la description officielle de l'algorithme CUBIC, un algorithme de contrôle de la congestion dans TCP.

CUBIC doit son nom au fait que la fonction de calcul de la fenêtre d'envoi des données est une fonction cubique (elle a un terme du troisième degré) et non pas linéaire. CUBIC est l'algorithme utilisé par défaut dans Linux depuis pas mal d'années :

% sudo sysctl net.ipv4.tcp_congestion_control
net.ipv4.tcp_congestion_control = cubic
    

CUBIC est plus énergique lorsqu'il s'agit d'agrandir la fenêtre d'envoi de données, lorsque le réseau a une grande capacité mais un RTT important. Dans le cas de ces réseaux « éléphants » (terme issu de la prononciation en anglais de LFN, Long and Fat Network, voir RFC 7323, section 1.1), le RTT élevé fait que l'émetteur TCP met du temps à recevoir les accusés de réception, et donc à comprendre que tout va bien et qu'il peut envoyer d'avantage de données, pour remplir le long tuyau. CUBIC permet d'accélérer cette phase.

Notez que CUBIC ne contrôle que l'émetteur, le récepteur est inchangé. Cela facilite le déploiement : un émetteur CUBIC peut parfaitement communiquer avec un récepteur traditionnel.

Avant de lire la suite du RFC, il est recommandé de (re)lire le RFC 5681, la bible sur le contrôle de congestion TCP, et notamment sur cette notion de fenêtre d'envoi (ou fenêtre de congestion).

TCP (RFC 793) a évidemment une mission difficile. L'intérêt de l'émetteur est d'envoyer le plus de données le plus vite possible. Mais à condition qu'elles arrivent sinon, s'il y a de la congestion, les données seront perdues et il faudra recommencer (ré-émettre). Et on n'est pas tout seul sur le réseau : il faut aussi tenir compte des autres, et chercher à partager équitablement l'Internet. L'algorithme doit donc être énergique (chercher à utiliser les ressources au maximum) mais pas bourrin (il ne faut pas dépasser le maximum), tout en étant juste (on n'est pas dans la startup nation, il ne faut pas écraser les autres, mais partager avec eux).

Le problème des éléphants, des réseaux à fort BDP, est connu depuis longtemps (article de T. Kelly, « Scalable TCP: Improving Performance in HighSpeed Wide Area Networks », et RFC 3649.) Dans ces réseaux, TCP tend à être trop prudent, à ouvrir sa fenêtre (les données qu'on peut envoyer tout de suite) trop lentement. Cette prudence l'honore, mais peut mener à des réseaux qui ne sont pas utilisés à fond. L'article de Ha, S., Kim, Y., Le, L., Rhee, I., et L. Xu, « A Step toward Realistic Performance Evaluation of High-Speed TCP Variants » expose ce problème. Il touche toutes les variantes de TCP depuis le TCP Reno décrit dans le RFC 5681 : le New Reno des RFC 6582 et RFC 6675, et même des protocoles non-TCP mais ayant le même algorithme, comme UDP (TFRC, RFC 5348) ou SCTP (RFC 4960).

CUBIC a été originellement documenté dans l'article de S. Ha, Injong Rhee, et Lisong Xu, « CUBIC: A New TCP-Friendly High-Speed TCP Variant », en 2008. Sur Linux, il a remplacé BIC pour les réseaux à haut BDP.

La section 3 du RFC rappelle les principes de conception de CUBIC, notamment :

  • Utilisation de la partie concave (la fenêtre s'agrandit rapidement au début puis plus lentement ensuite) et de la partie convexe de la fonction, et pas seulement la partie convexe (on ouvre la fenêtre calmement puis on accélère), comme l'ont tenté la plupart des propositions alternatives. Si vous avez du mal avec les termes concave et convexe, la figure 2 de cet article de comparaison de CUBIC et BIC illustre bien, graphiquement, ces concepts. La courbe est d'abord concave, puis convexe.
  • Comportement identique à celui de ses prédécesseurs pour les liaisons à faible RTT (ou faible BDP). Les algorithmes TCP traditionnels n'ont en effet pas de problème dans ce secteur (cf. section 4.2, et Floyd, S., Handley, M., et J. Padhye, « A Comparison of Equation-Based and AIMD Congestion Control »). « Si ce n'est pas cassé, ne le réparez pas. » CUBIC ne se différencie donc des autres algorithmes que pour les réseaux à RTT élevé, ce que rappelle le titre de notre RFC.
  • Juste partage de la capacité entre des flots ayant des RTT différents.
  • CUBIC mène à un agrandissement plus rapide de la fenêtre d'envoi, mais également à une réduction moins rapide lorsqu'il détecte de la congestion (paramètre « beta_cubic », le facteur de réduction de la fenêtre, voir aussi le RFC 3649.)

La section 4 du RFC spécifie précisement l'algorithme, après beaucoup de discussion avec les développeurs du noyau Linux (puisque le code a été écrit avant le RFC). Cette section est à lire si vous voulez comprendre tous les détails. Notez l'importance du point d'inflexion entre la partie concave et la partie convexe de la courbe qui décrit la fonction de changement de taille de la fenêtre. Ce point d'inflexion est mis à la valeur de la fenêtre d'envoi juste avant la dernière fois où TCP avait détecté de la congestion.

Notez que Linux met en outre en œuvre l'algorithme HyStart, décrit dans « Taming the Elephants: New TCP Slow Start ». Hystart mesure le RTT entre émetteur et récepteur pour détecter (par l'augmentation du RTT) un début de congestion avant que des pertes de paquets se produisent. (Merci à Lucas Nussbaum pour l'information.)

La section 5 analyse le comportement CUBIC selon les critères de comparaison des algorithmes de contrôle de la congestion décrits dans le RFC 5033.

Pour finir, voici une intéressante comparaison des algorithmes de contrôle de congestion.


Téléchargez le RFC 8312


L'article seul

RFC 8310: Usage Profiles for DNS over TLS and DNS over DTLS

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : S. Dickinson (Sinodun), D. Gillmor (ACLU), T. Reddy (McAfee)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 22 mars 2018


Afin de mieux protéger la vie privée des utilisateurs du DNS, le RFC 7858 normalise comment faire du DNS sur TLS, le chiffrement empêchant la lecture des requêtes et réponses DNS. Mais le chiffrement sans authentification n'a qu'un intérêt limité. Notamment, il ne protège pas contre un attaquant actif, qui joue les hommes du milieu. Le RFC 7858 ne proposait qu'un seul mécanisme d'authentification, peu pratique, les clés publiques configurées statiquement dans le client DNS. Ce nouveau RFC décrit d'autres mécanismes d'authentification, classés selon deux profils, un Strict (sécurité maximum) et un Opportuniste (disponibilité maximum).

Le problème de la protection de la vie privée quand on utilise le DNS est décrit dans le RFC 7626. Les solutions, comme toujours quand il s'agit de vie privée, se répartissent en deux catégories, la minimisation des données (RFC 7816) et le chiffrement (RFC 7858 et RFC 8094). Le chiffrement protège bien contre un attaquant purement passif. Mais si celui qui veut écouter les échanges DNS est capable de lancer des attaques actives (ARP spoofing, par exemple), le chiffrement ne suffit pas, il faut le doubler d'une authentification du serveur. Par exemple, en mars 2014, en Turquie, l'attaquant (le gouvernement) a pu détourner le trafic avec Google Public DNS. Même si Google Public DNS avait permis le chiffrement, il n'aurait pas servi, lors de cette attaque active. Sans l'authentification, on risque de parler en chiffré… à l'attaquant.

Le problème de l'authentification, c'est que si elle échoue, que faut-il faire ? Renoncer à envoyer des requêtes DNS ? Cela revient à se couper d'Internet. Notre nouveau RFC, considérant qu'il n'y a pas une solution qui conviendra à tous les cas, propose deux profils :

  • Le profil strict privilégie la confidentialité. Si on ne peut pas chiffrer et authentifier, on renonce.
  • Le profil opportuniste privilégie le fonctionnement du DNS. Si on ne peut pas authentifier, tant pis, on chiffre sans authentifier, mais, au moins, on a du DNS.

Notez bien qu'un profil spécifie des propriétés, une fin et pas un moyen. Un profil est défini par ces propriétés, qu'on implémente ensuite avec des mécanismes, décrits en section 6. Le RFC 7858 spécifiait déjà, dans sa section 4.2, un mécanisme d'authentification, fondé sur la connaissance préalable, par le client DNS, de la clé publique du serveur (SPKI, pour Subject Public Key Info, une solution analogue à celle du RFC 7469 pour HTTP). Mais beaucoup de détails manquaient. Ce nouveau RFC 8310 :

  • Décrit comment le client est censé obtenir les informations nécessaires à l'authentification,
  • Quelles lettres de créance peut présenter le serveur pour s'authentifier,
  • Et comment le client peut les vérifier.

À propos de ces « informations nécessaires à l'authentification », il est temps d'introduire un acronyme important (section 2 du RFC), ADN (Authentication Domain Name), le nom du serveur qu'on veut authentifier. Par exemple, pour Quad9, ce sera dns.quad9.net. Autres termes importants :

  • Ensemble de clés (SPKI pinset), un ensemble de clés cryptographiques (ou plutôt de condensats de clés),
  • Identificateur de référence (reference identifier), l'identificateur utilisé pour les vérifications (cf. RFC 6125).
  • Lettres de créance (credentials), les informations du serveur qui lui servent à s'authentifier, certificat PKIX, enregistrement TLSA (RFC 6698) ou ensemble de clés.

Note importante, la section 3 du RFC pointe le fait que les mécanismes d'authentification présentés ici ne traitent que l'authentification d'un résolveur DNS par son client. L'éventuelle future authentification d'un serveur faisant autorité par le résolveur est hors-sujet, tout comme l'authentification du client DNS par le serveur. Sont également exclus les idées d'authentifier le nom de l'organisation qui gère le serveur ou son pays : on authentifie uniquement l'ADN, « cette machine est bien dns-resolver.yeti.eu.org », c'est tout.

La section 5 présente les deux profils normalisés. Un profil est une politique choisie par le client DNS, exprimant ses exigences, et les compromis qu'il est éventuellement prêt à accepter si nécessaire. Un profil n'est pas un mécanisme d'authentification, ceux-ci sont dans la section suivante, la section 6. La section 5 présente deux profils :

  • Le profil strict, où le client exige chiffrement avec le serveur DNS et authentification du serveur. Si cela ne peut pas être fait, le profil strict renonce à utiliser le DNS, plutôt qu'à prendre des risques d'être surveillé. Le choix de ce profil protège à la fois contre les attaques passives et contre les attaques actives.
  • Le profil opportuniste, où le client tente de chiffrer et d'authentifier, mais est prêt à continuer quand même si ça échoue (cf. RFC 7435, sur ce concept de sécurité opportuniste). Si le serveur DNS permet le chiffrement, l'utilisateur de ce profil est protégé contre une attaque passive, mais pas contre une attaque active. Si le serveur ne permet pas le chiffrement, l'utilisateur risque même de voir son trafic DNS passer en clair.

Les discussions à l'IETF (par exemple pendant la réunion de Séoul en novembre 2016) avaient été vives, notamment sur l'utilité d'avoir un profil strict, qui peut mener à ne plus avoir de résolution DNS du tout, ce qui n'encouragerait pas son usage.

Une petite nuance s'impose ici : pour les deux profils, il faudra, dans certains cas, effectuer une requête DNS au tout début pour trouver certaines informations nécessaires pour se connecter au serveur DNS (par exemple son adresse IP si on n'a que son nom). Cette « méta-requête » peut se faire en clair, et non protégée contre l'écoute, même dans le cas du profil strict. Autrement, le déploiement de ce profil serait très difficile (il faudrait avoir toutes les informations stockées en dur dans le client).

Le profil strict peut être complètement inutilisable si les requêtes DNS sont interceptées et redirigées, par exemple dans le cas d'un portail captif. Dans ce cas, la seule solution est d'avoir un mode « connexion » pendant lequel on n'essaie pas de protéger la confidentialité des requêtes DNS, le temps de passer le portail captif, avant de passer en mode « accès Internet ». C'est ce que fait DNSSEC-trigger (cf. section 6.6).

Le tableau 1 du RFC résume les possibilités de ces deux profils, face à un attaquant actif et à un passif. Dans tous les cas, le profil strict donnera une connexion DNS chiffrée et authentifiée, ou bien pas de connexion du tout. Dans le meilleur cas, le profil opportuniste donnera la même chose que le strict (connexion chiffrée et authentifiée). Si le serveur est mal configuré ou si le client n'a pas les informations nécessaires pour authentifier, ou encore si un Homme du Milieu intervient, la session ne sera que chiffrée, et, dans le pire des cas, le profil opportuniste donnera une connexion en clair. On aurait pu envisager d'autres profils (par exemple un qui impose le chiffrement, mais pas l'authentification) mais le groupe de travail à l'IETF a estimé qu'ils n'auraient pas eu un grand intérêt, pour la complexité qu'ils auraient apporté.

Un mot sur la détection des problèmes. Le profil opportuniste peut permettre la détection d'un problème, même si le client continue ensuite malgré les risques. Par exemple, si un résolveur DNS acceptait DNS-sur-TLS avant, que le client avait enregistré cette information, mais que, ce matin, les connexions vers le port 853 sont refusées, avec le profil opportuniste, le client va quand même continuer sur le port 53 (en clair, donc) mais peut noter qu'il y a un problème. Il peut même (mais ce n'est pas une obligation) prévenir l'utilisateur. Cette possibilité de détection est le « D » dans le tableau 1, et est détaillée dans la section 6.5. La détection permet d'éventuellement prévenir l'utilisateur d'une attaque potentielle, mais elle est aussi utile pour le déboguage.

Évidemment, seul le profil strict protège réellement l'utilisateur contre l'écoute et toute mise en œuvre de DNS-sur-TLS devrait donc permettre au moins ce profil. Le profil opportuniste est là par réalisme : parfois, il vaut mieux une connexion DNS écoutée que pas de DNS du tout.

Les deux profils vont nécessiter un peu de configuration (le nom ou l'adresse du résolveur) mais le profil strict en nécessite davantage (par exemple la clé du résolveur).

Maintenant qu'on a bien décrit les profils, quels sont les mécanismes d'authentification disponibles ? La section 6 les décrit rapidement, et le tableau 2 les résume, il y en a six en tout, caractérisés par l'information de configuration nécessaire côté client (ils seront détaillés en section 8) :

  • Adresse IP du résolveur + clé du résolveur (SPKI, Subject Public Key Info). C'est celui qui était présenté dans la section 4.2 du RFC 7858, et qui est illustré dans mon article sur la supervision de résolveurs DNS-sur-TLS. Ce mécanisme est pénible à gérer (il faut par exemple tenir compte des éventuels changements de clé) mais c'est celui qui minimise la fuite d'information : l'éventuel surveillant n'apprendra que l'ADN (dans le SNI de la connexion TLS). En prime, il permet d'utiliser les clés nues du RFC 7250 (cf. section 9 du RFC).
  • ADN (nom de domaine du résolveur DNS-sur-TLS) et adresse IP du résolveur. On peut alors authentifier avec le certificat PKIX, comme on le fait souvent avec TLS (cf. section 8 du RFC, RFC 5280 et RFC 6125). L'identificateur à vérifier est l'ADN, qui doit se trouver dans le certificat, comme subjectAltName.
  • ADN seul. La configuration est plus simple et plus stable mais les méta-requêtes (obtenir l'adresse IP du résolveur à partir de son ADN) ne sont pas protégées et peuvent être écoutées. Si on n'utilise pas DNSSEC, on peut même se faire détourner vers un faux serveur (la vérification du certificat le détecterait, si on pouvait faire confiance à toutes les AC situées dans le magasin).
  • DHCP. Aucune configuration (c'est bien le but de DHCP) mais deux problèmes bloquants : il n'existe actuellement pas d'option DHCP pour transmettre cette information (même pas de projet) et DHCP lui-même n'est pas sûr.
  • DANE (RFC 6698). On peut authentifier le certificat du résolveur, non pas avec le fragile système des AC X.509, mais avec DANE. L'enregistrement TLSA devra être en _853._tcp.ADN. Cela nécessite un client capable de faire de la validation DNSSEC (à l'heure actuelle, le résolveur sur la machine cliente est en général un logiciel minimal, incapable de valider). Et les requêtes DANE (demande de l'enregistrement TLSA) peuvent passer en clair.
  • DANE avec une extension TLS. Cette extension (actuellement non encore décrite dans un RFC, cf. le projet draft-ietf-tls-dnssec-chain-extension) permet au serveur DNS-sur-TLS d'envoyer les enregistrements DNS et DNSSEC dans la session TLS elle-même. Plus besoin de méta-requêtes et donc plus de fuites d'information.

Cela fait beaucoup de mécanismes d'authentification ! Comment se combinent-ils ? Lesquels essayer et que faire s'ils donnent des résultats différents ? La méthode recommandée, si on a un ADN et une clé, est de tester les deux et d'exiger que les deux fonctionnent.

On a parlé à plusieurs reprises de l'ADN (Authentication Domain Name). Mais comment on obtient son ADN ? La section 7 du RFC détaille les sources d'ADN. La première est évidemment le cas où l'ADN est configuré manuellement. On pourrait imaginer, sur Unix, un /etc/resolv.conf avec une nouvelle syntaxe :

nameserver 2001:db8:53::1 adn resolver.example.net
	

Ici, on a configuré manuellement l'adresse IP et le nom (l'ADN) du résolveur. Cela convient au cas de résolveurs publics comme Quad9. Mais on pourrait imaginer des cas où seul l'ADN serait configuré quelque part, le résolveur dans /etc/resolv.conf étant rempli par DHCP, et n'étant utilisé que pour les méta-requêtes. Par exemple un (mythique, pour l'instant) /etc/tls-resolver.conf :

adn resolver.example.net
# IP address will be found via the "DHCP" DNS resolver, and checked
# with DNSSEC and/or TLS authentication
	

Troisième possibilité, l'ADN et l'adresse IP pourraient être découverts dynamiquement. Il n'existe à l'heure actuelle aucune méthode normalisée pour cela. Si on veut utiliser le profil strict, cette future méthode normalisée devra être raisonnablement sécurisée, ce qui n'est typiquement pas le cas de DHCP. On peut toujours normaliser une nouvelle option DHCP pour indiquer l'ADN mais elle ne serait, dans l'état actuel des choses, utilisable qu'avec le profil opportuniste. Bon, si vous voulez vous lancer dans ce travail, lisez bien la section 8 du RFC 7227 et la section 23 du RFC 3315 avant.

La section 11 du RFC décrit les mesures à mettre en œuvre contre deux attaques qui pourraient affaiblir la confidentialité, même si on chiffre. La première est l'analyse des tailles des requêtes et des réponses. L'accès au DNS étant public, un espion peut facilement récolter l'information sur la taille des réponses et, puisque TLS ne fait rien pour dissimuler cette taille, déduire les questions à partir des tailles. La solution recommandée contre l'attaque est le remplissage, décrit dans le RFC 7830.

Seconde attaque possible, un résolveur peut inclure l'adresse IP de son client dans ses requêtes au serveur faisant autorité (RFC 7871). Cela ne révèle pas le contenu des requêtes et des réponses, mais c'est quand même dommage pour la vie privée. Le client DNS-sur-TLS doit donc penser à mettre l'option indiquant qu'il ne veut pas qu'on fasse cela (RFC 7871, section 7.1.2).

Enfin, l'annexe A de notre RFC rappelle les dures réalités de l'Internet d'aujourd'hui : même si votre résolveur favori permet DNS-sur-TLS (c'est le cas par exemple de Quad9), le port 853 peut être bloqué par un pare-feu fasciste. Le client DNS-sur-TLS a donc intérêt à mémoriser quels résolveurs permettent DNS-sur-TLS, et depuis quels réseaux.

Pour l'instant, les nouveaux mécanismes d'authentification, et la possibilité de configurer le profil souhaité, ne semblent pas encore présents dans les logiciels, il va falloir patienter (ou programmer soi-même).

Merci à Willem Toorop pour son aide.


Téléchargez le RFC 8310


L'article seul

RFC 8308: Extension Negotiation in the Secure Shell (SSH) Protocol

Date de publication du RFC : Mars 2018
Auteur(s) du RFC : D. Bider (Bitvise Limited)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF curdle
Première rédaction de cet article le 21 mars 2018
Dernière mise à jour le 28 mars 2018


Le protocole SSH n'avait pas de mécanisme propre pour négocier des extensions au protocole de base (comme celle du RFC 4335). En outre, une partie de la négociation, par exemple des algorithmes cryptographiques, se déroulait avant le début du chiffrement et n'était donc pas protégée. Ce nouveau RFC ajoute à SSH un mécanisme pour négocier les extensions après l'échange de clés et le début de la communication sécurisée, une fois que tout est confidentiel.

Un mécanisme de négociation pour un protocole cryptographique est toujours délicat (comme TLS s'en est aperçu à plusieurs reprises). Si on n'en a pas, le client et le serveur perdent beaucoup de temps à faire des essais/erreurs « tiens, il vient de déconnecter brusquement, c'est peut-être qu'il n'aime pas SHA-512, réessayons avec SHA-1 ». Et ces deux mécanismes (négociation explicite et essai/erreur) ouvrent une nouvelle voie d'attaque, celle des attaques par repli, où l'Homme du Milieu va essayer de forcer les deux parties à utiliser des algorithmes de qualité inférieure. (La seule protection serait de ne pas discuter, de choisir des algorithmes forts et de refuser tout repli. En sécurité, ça peut aider d'être obtus.)

Notez aussi que la méthode essais/erreurs a un danger spécifique, car bien des machines SSH mettent en œuvre des mécanismes de limitation du trafic, voire de mise en liste noire, si la machine en face fait trop d'essais, ceci afin d'empêcher des attaques par force brute. D'où l'intérêt d'un vrai mécanisme de négociation (qui peut en outre permettre de détecter certaines manipulations par l'Homme du Milieu).

Vue par tshark, voici le début d'une négociation SSH, le message SSH_MSG_KEXINIT, normalisé dans le RFC 4253, section 7.1 :

SSH Protocol
    SSH Version 2
        Packet Length: 1332
        Padding Length: 5
        Key Exchange
            Message Code: Key Exchange Init (20)
            Algorithms
                Cookie: 139228cb5cfbf6c97d6b74f6ae99453d
                kex_algorithms length: 196
                kex_algorithms string: curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,ext-info-c
                server_host_key_algorithms length: 290
                server_host_key_algorithms string [truncated]: ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-s
                encryption_algorithms_client_to_server length: 150
                encryption_algorithms_client_to_server string: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc
                encryption_algorithms_server_to_client length: 150
                encryption_algorithms_server_to_client string: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc
                mac_algorithms_client_to_server length: 213
                mac_algorithms_client_to_server string [truncated]: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-2
                mac_algorithms_server_to_client length: 213
                mac_algorithms_server_to_client string [truncated]: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-2
                compression_algorithms_client_to_server length: 26
                compression_algorithms_client_to_server string: none,zlib@openssh.com,zlib
                compression_algorithms_server_to_client length: 26
                compression_algorithms_server_to_client string: none,zlib@openssh.com,zlib
                languages_client_to_server length: 0
                languages_client_to_server string: [Empty]
                languages_server_to_client length: 0
                languages_server_to_client string: [Empty]
                KEX First Packet Follows: 0
                Reserved: 00000000
            Padding String: 0000000000
    

Le message était en clair (c'est pour cela que tshark a pu le décoder). L'autre machine envoie un message équivalent. Suite à cet échange, les deux machines sauront quels algorithmes sont disponibles.

Notre RFC 8308 (section 2.1) ajoute à ce message le nouveau mécanisme d'extension. Pour préserver la compatibilité avec les anciennes mises en œuvre de SSH, et comme il n'y a pas de place « propre » disponible dans le message, le nouveau mécanisme se place dans la liste des algorithmes cryptographiques (champ kex_algorithms, celui qui commence par curve25519-sha256@libssh.org,ecdh-sha2-nistp256…). On ajoute à cette liste ext-info-c si on est client et ext-info-s si on est serveur. (Le nom est différent dans chaque direction, pour éviter que les deux parties ne se disent « cool, cet algorithme est commun, utilisons-le ».) Vous pouvez donc savoir si votre SSH gère le nouveau mécanisme en capturant ce premier paquet SSH et en examinant la liste des algorithmes d'échange de clé. (C'était le cas ici, avec OpenSSH 7.2. Vous l'aviez repéré ?)

Une fois qu'on a proposé à son pair d'utiliser le nouveau mécanisme de ce RFC 8308, on peut s'attendre, si le pair est d'accord, à recevoir un message SSH d'un nouveau type, SSH_MSG_EXT_INFO, qui sera, lui, chiffré. Il contient la liste des extensions gérées avec ce mécanisme. Notez qu'il peut être envoyé plusieurs fois, par exemple avant et après l'authentification du client, pour le cas d'un serveur timide qui ne voulait pas révéler sa liste d'extensions avant l'authentification. Ce nouveau type de message figure désormais dans le registre des types de message, avec le numéro 7.

La section 3 définit les quatre extensions actuelles (un registre accueillera les extensions futures) :

  • L'extension server-sig-algs donne la liste des algorithmes de signature acceptés par le serveur.
  • delay-compression indique les algorithmes de compression acceptés. Il y en a deux, un du client vers le serveur et un en sens inverse. Ils étaient déjà indiqués dans le message SSH_MSG_KEXINIT, dans les champs compression_algorithms_client_to_server et compression_algorithms_server_to_client mais, cette fois, ils sont transmis dans un canal sécurisé (confidentiel et authentifié).
  • no-flow-control, dont le nom indique bien la fonction.
  • elevation sert aux systèmes d'exploitation qui ont un mécanisme d'élévation des privilèges (c'est le cas de Windows, comme documenté dans le blog de Microsoft).

Les futures extensions, après ces quatre-là, nécessiteront un examen par l'IETF, via un RFC IETF (cf. RFC 8126, politique « IETF review »). Elle seront placées dans le registre des extensions.

Quelques petits problèmes de déploiement et d'incompatibilité ont été notés avec ce nouveau mécanisme d'extensions. Par exemple OpenSSH 7.3 et 7.4 gérait l'extension server-sig-algs mais n'envoyait pas la liste complète des algorithmes acceptés. Un client qui considérait cette liste comme ferme et définitive pouvait donc renoncer à utiliser certains algorithmes qui auraient pourtant marché. Voir ce message pour une explication détaillée.

Autre gag, les valeurs des extensions peuvent contenir des octets nuls et un logiciel maladroit qui les lirait comme si c'était des chaînes de caractères en C aurait des problèmes. C'est justement ce qui est arrivé à OpenSSH, jusqu'à la version 7.5 incluse, ce qui cassait brutalement la connexion. Le RFC conseille de tester la version du pair, et de ne pas utiliser les extensions en cause si on parle à un OpenSSH ≤ 7.5.

Aujourd'hui, ce mécanisme d'extension est mis en œuvre dans OpenSSH, Bitvise SSH, AsyncSSH et SmartFTP. (Cf. ce tableau de comparaison, mais qui n'est pas forcément à jour.)

Merci à Manuel Pégourié-Gonnard pour avoir détecté une erreur dans la première version.


Téléchargez le RFC 8308


L'article seul

RFC 8307: Well-Known URIs for the WebSocket Protocol

Date de publication du RFC : Janvier 2018
Auteur(s) du RFC : C. Bormann (Universitaet Bremen TZI)
Chemin des normes
Première rédaction de cet article le 3 janvier 2018


Il existe une norme pour un préfixe de chemin dans un URI, préfixe nommée .well-known, et après lequel plusieurs noms sont normalisés, pour des ressources « bien connues », c'est-à-dire auxquelles on peut accéder sans lien qui y mène. Le RFC 5785 normalise ce .well-known. Il n'était prévu à l'origine que pour les plans http: et https:. Ce très court RFC l'étend aux plans ws: et wss:, ceux des Web sockets du RFC 6455.

Les gens de CoAP avaient déjà étendu l'usage de .well-known en permettant (RFC 7252) qu'il soit utilisé pour les plans coap: et coaps:.

Il existe un registre IANA des suffixes (les termes après .well-known). Ce registre est le même quel que soit le plan d'URI utilisé. Il ne change donc pas suite à la publication de ce RFC.


Téléchargez le RFC 8307


L'article seul

RFC 8305: Happy Eyeballs Version 2: Better Connectivity Using Concurrency

Date de publication du RFC : Décembre 2017
Auteur(s) du RFC : D. Schinazi, T. Pauly (Apple)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 21 décembre 2017


Une machine connectée à l'Internet et répondant aux requêtes venues du réseau a souvent plusieurs adresses IP pour son nom. C'est parfois une adresse IPv4 et une IPv6 mais cela peut aussi être plusieurs adresses IPv6, ou bien un mélange en proportions quelconques. Les développeurs d'application et les administrateurs système qui déploieront ces applications ensuite, ont un choix difficile si certaines de ces adresses marchent et d'autres pas (ou mal). Si les différentes adresses IP de cette machine passent par des chemins différents, certains marchant et d'autres pas, l'application arrivera-t-elle à se rabattre sur une autre adresse très vite ou bien imposera-t-elle à l'utilisateur un long délai avant de détecter enfin le problème ? Cette question est connue comme « le bonheur des globes oculaires » (les dits globes étant les yeux de l'utilisateur qui attend avec impatience la page d'accueil de PornHub) et ce RFC spécifie les exigences pour l'algorithme de connexion du client. En les suivant, les globes oculaires seront heureux. Il s'agit de la version 2 de l'algorithme, bien plus élaborée que la version 1 qui figurait dans le RFC 6555.

La section 1 rappelle les données du problème : on veut évidemment que cela marche aussi bien en IPv6 (RFC 8200) qu'en IPv4 (pas question d'accepter des performances inférieures) or, dans l'état actuel du déploiement d'IPv6, bien des sites ont une connexion IPv6 totalement ou partiellement cassée. Si un serveur a IPv4 et IPv6 et que son client n'a qu'IPv4, pas de problème. Mais si le client a IPv6, tente de l'utiliser, mais que sa connexion est plus ou moins en panne, ou simplement sous-optimale, ses globes oculaires vont souffrir d'impatience. On peut aussi noter que le problème n'est pas spécifique à IPv6 : du moment que la machine visée a plusieurs adresses, qu'elles soient IPv4 ou IPv6, le risque que certaines des adresses ne marchent pas (ou moins bien) existe, et l'algorithme des globes oculaires heureux doit être utilisé. (C'est un des gros changements avec le précédent RFC, le RFC 6555, qui n'envisageait que le cas IPv6.)

La bonne solution est donc que l'application elle-même gère le problème (ou, sinon l'application elle-même, la bibliothèque logicielle qu'elle utilise et où se trouve la fonction de connexion). Il existe plusieurs algorithmes pour cela, déjà largement déployés depuis des années. On peut donc se baser sur l'expérience pour spécifier ces algorithmes. Ce RFC normalise les caractéristiques que doivent avoir ces algorithmes. Si on suit ce RFC, le trafic (IP et DNS) va légèrement augmenter (surtout si la connectivité IPv6 marche mal ou pas du tout) mais la qualité du vécu de l'utilisateur va être maintenue, même en présence de problèmes, ce qui compense largement. Autrement, il existerait un risque élevé que certains utilisateurs coupent complètement IPv6, plutôt que de supporter ces problèmes de délai de connexion.

La cible principale de notre RFC est composée des protocoles de transport avec connexion (TCP, SCTP), les protocoles sans connexion comme UDP soulevant d'autres questions (s'ils ont une sémantique requête/réponse, comme dans ICE, les algorithmes de ce RFC peuvent être utilisés).

Donc, on a un nom de machine qu'on veut contacter, mettons www.example.com, avec plusieurs adresses associées, peut-être de familles (v4 et v6) différentes. Prenons une machine ayant une seule adresse IPv4 et une seule adresse IPv6, avec une connexion IPv6 qui marche mal. Avec l'algorithme naïf qu'utilisent encore certains logiciels voici la séquence d'évenements traditionnelle :

  • L'initiateur de la connexion utilise le DNS pour demander les enregistrements A (adresse IPv4) et AAAA (IPv6).
  • Il récupère 192.0.2.1 et 2001:db8::1.
  • Il tente IPv6 (sur Linux, l'ordre des essais est réglable dans /etc/gai.conf). L'initiateur envoie un paquet TCP SYN à 2001:db8::1.
  • Pas de réponse (connexion IPv6 incorrecte). L'initiateur réessaie, deux fois, trois fois, faisant ainsi perdre de nombreuses secondes.
  • L'initiateur renonce, il passe à IPv4 et envoie un paquet TCP SYN à 192.0.2.1.
  • Le répondeur envoie un SYN+ACK en échange, l'initiateur réplique par un ACK et la connexion TCP est établie.

Le problème de cet algorithme naïf est donc la longue attente lors des essais IPv6. On veut au contraire un algorithme qui bascule rapidement en IPv4 lorsqu'IPv6 ne marche pas, sans pour autant gaspiller les ressources réseau en essayant par exemple toutes les adresses en même temps.

L'algorithme recommandé (sections 3 à 5, cœur de ce RFC) aura donc l'allure suivante :

  • L'initiateur de la connexion utilise le DNS pour demander les enregistrements A (adresse IPv4) et AAAA (IPv6).
  • Il récupère 192.0.2.1 et 2001:db8::1. Il sait donc qu'il a plusieurs adresses, de famille différente.
  • Il tente IPv6 (l'algorithme du RFC est de toute façon facilement adaptable à des cas où IPv4 est prioritaire). L'initiateur envoie un paquet TCP SYN à 2001:db8::1, avec un très court délai de garde.
  • Pas de réponse quasi-immédiate ? L'initiateur passe à IPv4 rapidement. Il envoie un paquet TCP SYN à 192.0.2.1.
  • Le répondeur envoie un SYN+ACK en échange, l'initiateur réplique par un ACK et la connexion TCP est établie.

Si le répondeur réagit à une vitesse normale en IPv6, la connexion sera établie en IPv6. Sinon, on passera vite en IPv4, et l'utilisateur humain ne s'apercevra de rien. Naturellement, si le DNS n'avait rapporté qu'une seule adresse (v4 ou v6), on reste à l'algorithme traditionnel (« essayer, patienter, ré-essayer »).

Maintenant, les détails. D'abord, le DNS (section 3 de notre RFC). Pour récupérer les adresses appartenant aux deux familles (IPv4 et IPv6), il faut envoyer deux requêtes, de type A et AAAA. Pas de délai entre les deux, et le AAAA en premier, recommande le RFC. Notez qu'il n'existe pas de type de requête DNS pour avoir les deux enregistrements d'un coup, il faut donc deux requêtes.

Il ne faut pas attendre d'avoir la réponse aux deux avant de commencer à tenter d'établir une connexion. En effet, certains pare-feux configurés avec les pieds bloquent les requêtes AAAA, qui vont finir par timeouter. Du point de vue du programmeur, cela signifie qu'il faut faire les deux requêtes DNS dans des fils différents (ou des goroutines différentes en Go), ou bien, utiliser une API asynchrone, comme getdns. Ensuite, si on reçoit la réponse AAAA mais pas encore de A, on essaye tout de suite de se connecter, si on a la réponse A, on attend quelques millisecondes la réponse AAAA puis, si elle ne vient pas, tant pis, on essaie en IPv4. (La durée exacte de cette attente est un des paramètres réglables de l'algorithme. Il se nomme Resolution Delay et sa valeur par défaut recommandée est de 50 ms.)

À propos de DNS, notez que le RFC recommande également de privilégier IPv6 pour le transport des requêtes DNS vers les résolveurs (on parle bien du transport des paquets DNS, pas du type des données demandées). Ceci dit, ce n'est pas forcément sous le contrôle de l'application.

Une fois récupérées les adresses, on va devoir les trier selon l'ordre de préférence. La section 4 décrit comment cela se passe. Rappelons qu'il peut y avoir plusieurs adresses de chaque famille, pas uniquement une v4 et une v6, et qu'il est donc important de gérer une liste de toutes les adresses reçues (imaginons qu'on ne récupère que deux adresses v4 et aucune v6 : l'algorithme des globes oculaires heureux est quand même crucial car il est parfaitement possible qu'une des adresses v4 ne marche pas).

Pour trier, le RFC recommande de suivre les règles du RFC 6724, section 6. Si le client a un état (une mémoire des connexions précédentes, ce qui est souvent le cas chez les clients qui restent longtemps à tourner, un navigateur Web, par exemple), il peut ajouter dans les critères de tri le souvenir des succès (ou échecs) précédents, ainsi que celui des RTT passés. Bien sûr, un changement de connectivité (détecté par le DNA des RFC 4436 ou RFC 6059) doit entraîner un vidage complet de l'état (on doit oublier ce qu'on a appris, qui n'est plus pertinent).

Dernier détail sur le tri : il faut mêler les adresses des deux familles. Imaginons un client qui récupère trois adresses v6 et trois v4, client qui donne la priorité à IPv4, mais dont la connexion IPv4 est défaillante. Si sa liste d'adresses à tester comprend les trois adresses v4 en premier, il devra attendre trois essais avant que cela ne marche. Il faut donc plutôt créer une liste {une adressse v4, une adresse v6, une adresse v4…}. Le nombre d'adresses d'une famille à inclure avant de commencer l'autre famille est le paramètre First Address Family Count, et il vaut un par défaut.

Enfin, on essaie de se connecter en envoyant des paquets TCP SYN (section 5). Il est important de ne pas tester IPv4 tout de suite. Les premiers algorithmes « bonheur des globes oculaires » envoyaient les deux paquets SYN en même temps, gaspillant des ressources réseau et serveur. Ce double essai faisait que les équipements IPv4 du réseau avaient autant de travail qu'avant, alors qu'on aurait souhaité les retirer du service petit à petit. En outre, ce test simultané fait que, dans la moitié des cas, la connexion sera établie en IPv4, empêchant de tirer profit des avantages d'IPv6 (cf. RFC 6269). Donc, on doit tester en IPv6 d'abord, sauf si on se souvient des tentatives précédentes (voir plus loin la variante « avec état ») ou bien si l'administrateur système a délibérement configuré la machine pour préférer IPv4.

Après chaque essai, on attend pendant une durée paramétrable, Connection Attempt Delay, 250 ms par défaut (bornée par les paramètres Minimum Connection Attempt Delay, 100 ms par défaut, qu'on ne devrait jamais descendre en dessous de 10 ms, et Maximum Connection Attempt Delay, 2 s par défaut).

L'avantage de cet algorithme « IPv6 d'abord puis rapidement basculer en IPv4 » est qu'il est sans état : l'initiateur n'a pas à garder en mémoire les caractéristiques de tous ses correspondants. Mais son inconvénient est qu'on recommence le test à chaque connexion. Il existe donc un algorithme avec état (cf. plus haut), où l'initiateur peut garder en mémoire le fait qu'une machine (ou bien un préfixe entier) a une adresse IPv6 mais ne répond pas aux demandes de connexion de cette famille. Le RFC recommande toutefois de re-essayer IPv6 au moins toutes les dix minutes, pour voir si la situation a changé.

Une conséquence de l'algorithme recommandé est que, dans certains cas, les deux connexions TCP (v4 et v6) seront établies (si le SYN IPv6 voyage lentement et que la réponse arrive après que l'initiateur de la connexion se soit impatienté et soit passé à IPv4). Cela peut être intéressant dans certains cas rares, mais le RFC recommande plutôt d'abandonner la connexion perdante (la deuxième). Autrement, cela pourrait entraîner des problèmes avec, par exemple, les sites Web qui lient un cookie à l'adresse IP du client, et seraient surpris de voir deux connexions avec des adresses différentes.

La section 9 du RFC rassemble quelques derniers problèmes pratiques. Par exemple, notre algorithme des globes oculaires heureux ne prend en compte que l'établissement de la connexion. Si une adresse ne marche pas du tout, il choisira rapidement la bonne. Mais si une adresse a des problèmes de MTU et pas l'autre, l'établissement de la connexion, qui ne fait appel qu'aux petits paquets TCP SYN, se passera bien alors que le reste de l'échange sera bloqué. Une solution possible est d'utiliser l'algorithme du RFC 4821.

D'autre part, l'algorithme ne tient compte que de la possibilité d'établir une connexion TCP, ce qui se fait typiquement uniquement dans le noyau du système d'exploitation du serveur. L'algorithme ne garantit pas qu'une application écoute, et fonctionne.

Parmi les problèmes résiduels, notez que l'algorithme des globes oculaires heureux est astucieux, mais tend à masquer les problèmes (section 9.3). Si un site Web publie les deux adresses mais que sa connectivité IPv6 est défaillante, aucun utilisateur ne lui signalera puisque, pour eux, tout va bien. Il est donc recommandé que l'opérateur fasse des tests de son côté pour repérer les problèmes (le RFC 6555 recommandait que le logiciel permette de débrayer cet algorithme, afin de tester la connectivité avec seulement v4 ou seulement v6, ou bien que le logiciel indique quelque part ce qu'il a choisi, pour mieux identifier d'éventuels problèmes v6.)

Pour le délai entre le premier SYN IPv6 et le premier SYN IPv4, la section 5 donne des idées quantitatives en suggérant 250 ms entre deux essais. C'est conçu pour être quasiment imperceptible à un utilisateur humain devant son navigateur Web, tout en évitant de surcharger le réseau inutilement. Les algorithmes avec état ont le droit d'être plus impatients, puisqu'ils peuvent se souvenir des durées d'établissement de connexion précédents.

Notez que les différents paramètres réglables indiqués ont des valeurs par défaut, décrites en section 8, et qui ont été déterminées empiriquement.

Si vous voulez une meilleure explication de la version 2 des globes oculaires heureux, il y a cet exposé au RIPE.

Enfin, les implémentations. Notez que les vieilles mises en œuvre du RFC 6555 (et présentées à la fin de mon précédent article) sont toujours conformes à ce nouvel algorithme, elles n'en utilisent simplement pas les raffinements. Les versions récentes de macOS (Sierra) et iOS (10) mettent en œuvre notre RFC, ce qui est logique, puisqu'il a été écrit par des gens d'Apple (l'annonce est ici, portant même sur des versions antérieures). Apple en a d'ailleurs profité pour breveter cette technologie. À l'inverse, un exemple récent de logiciel incapable de gérer proprement le cas d'un pair ayant plusieurs adresses IP est Mastodon (cf. bogue #3762.)

Dans l'annexe A, vous trouverez la liste complète des importants changements depuis le RFC 6555. Le précédent RFC n'envisageait qu'un seul cas, deux adresses IP, une en v4, l'autre en v6. Notre nouveau RFC 8305 est plus riche, augmente le parallélisme, et ajoute :

  • La façon de faire les requêtes DNS (pour tenir compte des serveurs bogués qui ne répondent pas aux requêtes AAAA, cf. RFC 4074),
  • La gestion du cas où il y a plusieurs adresses IP de la même famille (v4 ou v6),
  • La bonne façon d'utiliser les souvenirs des connexions précédentes,
  • Et la méthode (dont je n'ai pas parlé ici) pour le cas des réseaux purement IPv6, mais utilisant le NAT64 du RFC 8305.

Téléchargez le RFC 8305


L'article seul

RFC 8304: Transport Features of the User Datagram Protocol (UDP) and Lightweight UDP (UDP-Lite)

Date de publication du RFC : Février 2018
Auteur(s) du RFC : G. Fairhurst, T. Jones (University of Aberdeen)
Pour information
Réalisé dans le cadre du groupe de travail IETF taps
Première rédaction de cet article le 8 février 2018


Le RFC 8303, du groupe de travail TAPS, décrit les fonctions et services rendus par les protocoles de transport aux applications. Ce RFC 8304 se focalise sur deux protocoles sans connexion, UDP et UDP-Lite. Quels services fournissent-ils ?

UDP est normalisé dans le RFC 768 et UDP-Lite dans le RFC 3828. Tous les deux permettent l'envoi et la réception de datagrammes, sans connexion préalable, sans garantie d'être prévenu en cas de perte du datagramme, sans garantie qu'ils soient distribués dans l'ordre. Une application qui utilise UDP va donc devoir connaitre les services exacts que ce protocole fournit. Aujourd'hui, de nombreuses applications utilisent UDP, l'une des plus connues étant sans doute le DNS, sans compter celles qui utilisent un autre protocole de transport mais qui l'encapsulent dans UDP pour passer les boitiers intermédiaires (cf. par exemple RFC 8261). UDP-Lite est très proche d'UDP et ajoute juste la possibilité de distribuer à l'application des paquets potentiellement endommagés. Pour utiliser UDP intelligement, les programmeurs ont tout intérêt à consulter le RFC 8085.

L'API la plus courante est l'API dite « socket », normalisée par POSIX, et dont la meilleure documentation est évidemment le livre de Stevens. Les applications peuvent envoyer des données avec send(), sendto() et sendmsg(), en recevoir avec recvfrom() et recvmsg(). Elles peuvent être dans l'obligation de configurer certaines informations de bas niveau comme la permission de fragmenter ou pas, alors que TCP gère cela tout seul. Des options existent dans l'API socket pour définir ces options.

Notre RFC 8304 suit la démarche du RFC 8303 pour la description d'un protocole de transport. Plus précisement, il suite la première passe, celle de description de ce que sait faire le protocole.

Donc, pour résumer (section 3 du RFC), UDP est décrit dans le RFC 768, et UDP-Lite dans le RFC 3828. Tous les deux fournissent un service de datagramme, non connecté, et qui préserve les frontières de message (contrairement à TCP, qui envoie un flot d'octets). Le RFC 768 donne quelques idées sur l'API d'UDP, il faut notamment que l'application puisse écouter sur un port donné, et puisse choisir le port source d'envoi.

UDP marche évidemment également sur IPv6, et une extension à l'API socket pour IPv6 est décrite dans le RFC 3493.

UDP est très basique : aucun contrôle de congestion (le RFC 8085 détaille ce point), pas de retransmission des paquets perdus, pas de notification des pertes, etc. Tout doit être fait par l'application. On voit que, dans la grande majorité des cas, il vaut mieux utiliser TCP. Certains développeurs utilisent UDP parce qu'ils ont lu quelque part que c'était « plus rapide » mais c'est presque toujours une mauvaise idée.

Notre RFC décrit ensuite les primitives UDP utilisables par les applications :

  • CONNECT est très différent de celui de TCP. C'est une opération purement locale (aucun paquet n'est envoyé sur le réseau), qui associe des ports source et destination à une prise (socket), c'est tout. Une fois cette opération faite, on pourra envoyer ou recevoir des paquets. Comme CONNECT, CLOSE n'a d'effet que local (pas de connexion, donc pas de fermeture de connexion).
  • SEND et RECEIVE, dont le nom indique bien ce qu'elles font.
  • SET_IP_OPTIONS qui permet d'indiquer des options IP, chose qui n'est en général pas nécessaire en TCP mais peut être utile en UDP.
  • SET_DF est important car il permet de contrôler la fragmentation des paquets. TCP n'en a pas besoin car la MSS est négociée au début de la connexion. Avec UDP, c'est le programmeur de l'application qui doit choisir s'il laissera le système d'exploitation et les routeurs (en IPv4 seulement, pour les routeurs) fragmenter, ce qui est risqué, car pas mal de pare-feux mal configurés bloquent les fragments, ou bien s'il refusera la fragmentation (DF = Don't Fragment) et devra donc faire attention à ne pas envoyer des paquets trop gros. (Voir aussi les RFC 1191 et RFC 8201 pour une troisième possibilité.)
  • SET_TTL (IPv4) et SET_IPV6_UNICAST_HOPS permettent de définir le TTL des paquets IP envoyés. (Le terme de TTL est objectivement incorrect, et est devenu hops en IPv6, mais c'est le plus utilisé.)
  • SET_DSCP permet de définir la qualité de service souhaitée (RFC 2474).
  • SET_ECN permet de dire qu'on va utiliser ECN (RFC 3168). Comme les précédentes, elle n'a pas de sens en TCP, où le protocole de transport gère cela seul.
  • Enfin, dernière primitive citée par le RFC, la demande de notification des erreurs. Elle sert à réclamer qu'on soit prévenu de l'arrivée des messages ICMP.

Certaines primitives ont été exclues de la liste car n'étant plus d'actualité (cf. le RFC 6633).

Avec ça, on n'a parlé que d'UDP et pas d'UDP-Lite. Rappelons qu'UDP-Lite (RFC 3828) est à 95 % de l'UDP avec un seul changement, la possibilité que la somme de contrôle ne couvre qu'une partie du paquet. Il faut donc une primtive SET_CHECKSUM_COVERAGE qui indique jusqu'à quel octet le paquet est couvert par la somme de contrôle.

Notez enfin que le RFC se concentre sur l'unicast mais, si cela vous intéresse, l'annexe A décrit le cas du multicast.


Téléchargez le RFC 8304


L'article seul

RFC 8303: On the Usage of Transport Features Provided by IETF Transport Protocols

Date de publication du RFC : Février 2018
Auteur(s) du RFC : M. Welzl (University of Oslo), M. Tuexen (Muenster Univ. of Appl. Sciences), N. Khademi (University of Oslo)
Pour information
Réalisé dans le cadre du groupe de travail IETF taps
Première rédaction de cet article le 8 février 2018


La famille de protocoles TCP/IP dispose d'un grand nombre de protocoles de transport. On connait bien sûr TCP mais il y en a d'autres comme UDP et SCTP et d'autres encore moins connus. Cette diversité peut compliquer la tâche des développeurs d'application, qui ne savent pas toujours bien lequel choisir. Et elle pose également problème pour les développements futurs à l'IETF, par exemple la réflexion en cours sur les API. On a besoin d'une description claire des services que chaque protocole fournit effectivement. C'est le but du groupe de travail TAPS dont voici le deuxième RFC : une description de haut niveau des services que fournit la couche transport. À faire lire à tous les développeurs d'applications réseau, à tous les participants à la normalisation, et aux étudiants en réseaux informatiques.

Ce RFC parle de TCP, MPTCP, SCTP, UDP et UDP-Lite, sous l'angle « quels services rendent-ils aux applications ? » (QUIC, pas encore normalisé, n'y figure pas. LEDBAT, qui n'est pas vraiment un protocole de transport, est par contre présent.) L'idée est de lister un ensemble d'opérations abstraites, qui pourront ensuite être exportées dans une API. J'en profite pour recommander la lecture du RFC 8095, premier RFC du groupe TAPS.

La section 1 de notre RFC décrit la terminologie employée. Il faut notamment distinguer trois termes :

  • La fonction (Transport Feature) qui désigne une fonction particulière que le protocole de transport va effectuer, par exemple la confidentialité, la fiabilité de la distribution des données, le découpage des données en messages, etc.
  • Le service (Transport Service) qui est un ensemble cohérent de fonctions. C'est ce que demande l'application.
  • Le protocole (Transport Protocol) qui est une réalisation concrète d'un ou plusieurs services.

Un exemple de programme qui permet d'essayer différents types de prises (sockets) est socket-types.c. Vous pouvez le compiler et le lancer en indiquant le type de service souhaité. STREAM va donner du TCP, SEQPACKET du SCTP, DATAGRAM de l'UDP :

% make socket-types
cc -Wall -Wextra     socket-types.c   -o socket-types

% ./socket-types -v -p 853 9.9.9.9 STREAM
9.9.9.9 is an IP address
"Connection" STREAM successful to 9.9.9.9

% ./socket-types -v -p 443 -h dns.bortzmeyer.org STREAM 
Address(es) of dns.bortzmeyer.org is(are): 2605:4500:2:245b::42 204.62.14.153 
"Connection" STREAM successful to 2605:4500:2:245b::42
256 response bytes read
    

À première vue, l'API sockets nous permet de sélectionner le service, indépendamment du protocole qui le fournira. Mais ce n'est pas vraiment le cas. Si on veut juste un flot de données, cela pourrait être fait avec TCP ou SCTP, mais seul TCP sera sélectionné si on demande STREAM. En fait, les noms de services dns l'appel à socket() sont toujours en correspondance univoque avec les protocoles de transport.

Autres termes importants :

  • Adresse (Transport Address) qui est un tuple regroupant adresse IP, nom de protocole et numéro de port. Le projet TAPS considère uniquement des protocoles ayant la notion de ports, et fournissant donc la fonction de démultiplexage (différencier les données destinées à telle ou telle application).
  • Primitive (Primitive), un moyen pour l'application de demander quelque chose au protocole de transport.
  • Événement (Event), généré par le protocole de transport, et transmis à l'application pour l'informer.

La section 2 décrit le problème général. Actuellement, les applications sont liées à un protocole, même quand elles ne le souhaitent pas. Si une application veut que ses octets soient distribués dans l'ordre, et sans pertes, plusieurs protocoles peuvent convenir, et il n'est pas forcément utile de se limiter à seulement TCP, par exemple. Pour avancer vers un moindre couplage entre application et protocole, ce RFC décrit les fonctions et les services, un futur RFC définira des services minimaux, un autre peut-être une API.

Le RFC essaie de s'en tenir au minimum, des options utiles mais pas indispensables (comme le fait pour l'application de demander à être prévenue de certains changements réseau, cf. RFC 6458) ne sont pas étudiées.

Le RFC procède en trois passes : la première (section 3 du RFC) analyse et explique ce que chaque protocole permet, la seconde (section 4) liste les primitives et événements possibles, la troisième (section 5) donne pour chaque fonction les protocoles qui la mettent en œuvre. Par exemple, la passe 1 note que TCP fournit à l'application un moyen de fermer une connexion en cours, la passe 2 liste une primitive CLOSE.TCP, la passe 3 note que TCP et SCTP (mais pas UDP) fournissent cette opération de fermeture (qui fait partie des fonctions de base d'un protocole orienté connexion, comme TCP). Bon, d'accord, cette méthode est un peu longue et elle rend le RFC pas amusant à lire mais cela permet de s'assurer que rien n'a été oublié.

Donc, section 3 du RFC, la passe 1. Si vous connaissez bien tous ces protocoles, vous pouvez sauter cette section. Commençons par le protocole le plus connu, TCP (RFC 793). Tout le monde sait que c'est un protocole à connexion, fournissant un transport fiable et ordonné des données. Notez que la section 3.8 de la norme TCP décrit, sinon une API, du moins l'interface (les primitives) offertes aux applications. Vous verrez que les noms ne correspondent pas du tout à celle de l'API sockets (OPEN au lieu de connect/listen, SEND au lieu de write, etc).

TCP permet donc à l'application d'ouvrir une connexion (activement - TCP se connecte à un TCP distant - ou passivement - TCP attend les connexions), d'envoyer des données, d'en recevoir, de fermer la connexion (gentiment - TCP attend encore les données de l'autre - ou méchamment - on part en claquant la porte). Il y a aussi des événements, par exemple la fermeture d'une connexion déclenchée par le pair, ou bien une expiration d'un délai de garde. TCP permet également de spécifier la qualité de service attendue (cf. RFC 2474, et la section 4.2.4.2 du RFC 1123). Comme envoyer un paquet IP par caractère tapé serait peu efficace, TCP permet, pour les sessions interactives, genre SSH, d'attendre un peu pour voir si d'autres caractères n'arrivent pas (algorithme de Nagle, section 4.2.3.4 du RFC 1123). Et il y a encore d'autres possibilités moins connues, comme le User Timeout du RFC 5482. Je vous passe des détails, n'hésitez pas à lire le RFC pour approfondir, TCP a d'autres possibilités à offrir aux applications.

Après TCP, notre RFC se penche sur MPTCP. MPTCP crée plusieurs connexions TCP vers le pair, utilisant des adresses IP différentes, et répartit le trafic sur ces différents chemins (cf. RFC 6182). Le modèle qu'il présente aux applications est très proche de celui de TCP. MPTCP est décrit dans les RFC 6824 et son API est dans le RFC 6897. Ses primitives sont logiquement celles de TCP, plus quelques extensions. Parmi les variations par rapport à TCP, la primitive d'ouverture de connexion a évidemment une option pour activer ou pas MPTCP (sinon, on fait du TCP normal). Les extensions permettent de mieux contrôler quelles adresses IP on va utiliser pour la machine locale.

SCTP est le principal concurrent de TCP sur le créneau « protocole de transfert avec fiabilité de la distribution des données ». Il est normalisé dans le RFC 4960. Du point de vue de l'application, SCTP a trois différences importantes par rapport à TCP :

  • Au lieu d'un flot continu d'octets, SCTP présent une suite de messages, avec des délimitations entre eux,
  • Il a un mode où la distribution fiable n'est pas garantie,
  • Et il permet de tirer profit du multi-homing.

Il a aussi une terminologie différente, par exemple on parle d'associations et plus de connexions.

Certaines primitives sont donc différentes : par exemple, Associate au lieu du Open TCP. D'autres sont identiques, comme Send et Receive. SCTP fournit beaucoup de primitives, bien plus que TCP.

Et UDP ? Ce protocole sans connexion, et sans fiabilité, ainsi que sa variante UDP-Lite, est analysé dans un RFC séparé, le RFC 8304.

Nous passons ensuite à LEDBAT (RFC 6817). Ce n'est pas vraiment un protocole de transport, mais plutôt un système de contrôle de la congestion bâti sur l'idée « décroissante » de « on n'utilise le réseau que si personne d'autre ne s'en sert ». LEDBAT est pour les protocoles économes, qui veulent transférer des grandes quantités de données sans gêner personne. Un flot LEDBAT cédera donc toujours la place à un flot TCP ou compatible (RFC 5681). N'étant pas un protocole de transport, LEDBAT peut, en théorie, être utilisé sur les protocoles existants comme TCP ou SCTP (mais les extensions nécessaires n'ont hélas jamais été spécifiées). Pour l'instant, les applications n'ont pas vraiment de moyen propre d'activer ou de désactiver LEDBAT.

Bien, maintenant, passons à la deuxième passe (section 4 du RFC). Après la description des protocoles lors de la première passe, cette deuxième passe liste explicitement les primitives, rapidement décrites en première passe, et les met dans différentes catégories (alors que la première passe classait par protocole). Notons que certaines primitives, ou certaines options sont exclues. Ainsi, TCP a un mécanisme pour les données urgentes (RFC 793, section 3.7). Il était utilisé pour telnet (cf. RFC 854) mais n'a jamais vraiment fonctionné de manière satisfaisante et le RFC 6093 l'a officiellement exclu pour les nouvelles applications de TCP. Ce paramètre n'apparait donc pas dans notre RFC, puisque celui-ci vise le futur.

La première catégorie de primitives concerne la gestion de connexion. On y trouve d'abord les primitives d'établissement de connexion :

  • CONNECT.TCP : établit une connexion TCP,
  • CONNECT.SCTP : idem pour SCTP,
  • CONNECT.MPTCP : établit une connexion MPTCP,
  • CONNECT.UDP : établit une « connexion » UDP sauf, que, UDP étant sans connexion, il s'agit cette fois d'une opération purement locale, sans communication avec une autre machine.

Cette catégorie comprend aussi les primitives permettant de signaler qu'on est prêt à recevoir une connexion, LISTEN.TCP, celles de maintenance de la connexion, qui sont bien plus variées, et celles permettant de mettre fin à la connexion (comme CLOSE.TCP et CLOSE.SCTP, ou comme le signal qu'un délai de garde a été dépassé, TIMEOUT.TCP).

Dans les primitives de maintenance, on trouve aussi bien les changements du délai de garde (CHANGE_TIMEOUT.TCP et SCTP), le débrayage de l'algorithme de Nagle, pour TCP et SCTP, l'ajout d'une adresse IP locale à l'ensemble des adresses utilisables (ADD_PATH.MPTCP et ADD_PATH.SCTP), la notification d'erreurs, l'activation ou la désactivation de la somme de contrôle (UDP seulement, la somme de contrôle étant obligatoire pour les autres)… La plupart sont spécifiques à SCTP, le protocole le plus riche.

La deuxième catégorie rassemble les primitives liées à la transmission de données. On y trouve donc SEND.TCP (idem pour SCTP et UDP), RECEIVE.TCP (avec ses équivalents SCTP et UDP), mais aussi les signalements d'échec comme SEND_FAILURE.UDP par exemple quand on a reçu un message ICMP d'erreur.

Venons-en maintenant à la troisième passe (section 5 du RFC). On va cette fois lister les primitives sous forme d'un concept de haut niveau, en notant les protocoles auxquels elles s'appliquent. Ainsi, pour la gestion des connexions, on aura de quoi se connecter : une primitive Connect, qui s'applique à plusieurs protocoles (TCP, SCTP et UDP, même si Connect ne se réalise pas de la même façon pour tous ces protocoles). Et de quoi écouter passivement : une primitive Listen. Pour la maintenance, on aura une primitive Change timeout, qui s'applique à TCP et SCTP, une Disable Nagle qui s'applique à TCP et SCTP, une Add path qui a un sens pour MPTCP et SCTP, une Disable checksum qui ne marche que pour UDP, etc.

Pour l'envoi de données, on ne fusionne pas les opérations d'envoi (SEND.PROTOCOL) de la passe précédente car elles ont une sémantique trop différente. Il y a Reliably transfer data pour TCP, et Reliably transfer a message pour SCTP. (Et bien sûr Unreliably transfer a message avec UDP.)

Voilà, tout ça a l'air un peu abstrait mais ça acquerra davantage de sens quand on passera aux futures descriptions d'API.

L'annexe B du RFC explique la méthodologie suivie pour l'élaboration de ce document : coller au texte des RFC, exclure les primitives optionnelles, puis les trois passes dont j'ai parlé plus tôt. C'est cette annexe, écrite avant le RFC, qui avait servi de guide aux auteurs des différentes parties (il fallait des spécialistes SCTP pour ne pas faire d'erreurs lors de la description de ce protocole complexe…)

Notez (surtout si vous avez lu le RFC 8095) que TLS n'a pas été inclus, pas parce que ce ne serait pas un vrai protocole de transport (ça se discute) mais car il aurait été plus difficile à traiter (il aurait fallu des experts en sécurité).


Téléchargez le RFC 8303


L'article seul

RFC des différentes séries : 0  1000  2000  3000  4000  5000  6000  7000  8000