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 6998: A Mechanism to Measure the Routing Metrics along a Point-to-point Route in a Low Power and Lossy Network

Date de publication du RFC : Août 2013
Auteur(s) du RFC : M. Goyal (University of Wisconsin, Milwaukee), E. Baccelli (INRIA), A. Brandt (Sigma Designs), J. Martocci (Johnson Controls)
Expérimental
Réalisé dans le cadre du groupe de travail IETF roll
Première rédaction de cet article le 27 août 2013


Le protocole RPL (Routing Protocol for Low power and Lossy Networks), normalisé dans le RFC 6550, est conçu pour des réseaux de machines très bon marché, ayant peu de capacités (mémoire et calcul), étant souvent très limitées en énergie, et étant connectées par des liens de qualité médiocre. Un tel environnement peut par exemple se rencontrer dans des réseaux de capteurs dispersés dans un environnement industriel. Une partie des machines du réseau va se dévouer pour router les paquets des autres. RPL permet de trouver et de diffuser des routes mais celle choisie ne sera pas forcément optimale. D'où ces deux extensions à RPL permettant à un routeur de 1) mesurer une métrique donnée en émettant un paquet de contrôle vers la destination, paquet qui accumulera au fur et à mesure, dans les routeurs intermédiaires, les informations à propos de la route utilisée actuellement et, 2) découvrir à la demande une route meilleure (si tant est qu'il y en a une).

C'est que ce n'est pas une vie que d'être routeur dans un LLN (Low power and Lossy Network, les réseaux difficiles dont je parlais au paragraphe précédent). Le RPL classique du RFC 6550 essaie de faciliter les choses en limitant le réseau à un graphe acyclique dirigé vers un puits de données et en calculant toutes les routes à l'avance (ce qu'on nomme un protocole proactif). Une extension à RPL, nommée P2P-RPL (P2P pour pair-à-pair) et normalisée dans le RFC 6997, permet à RPL de devenir réactif et donc de calculer des routes à la demande. Elle permet aussi de trouver des routes plus courtes, en évitant le passage par le sommet du graphe pré-établi. Le routeur utilise, pour ces calculs, les métriques du RFC 6551 (latence, capacité, qualité, et autres métriques dans le registre IANA). Mais comment connaître leur valeur effective dans un réseau ? Eh bien, en les mesurant, tout simplement.

Le protocole RPL ne transmettant pas cette information pour toutes les routes, c'est au routeur qui en a besoin de demander. Il génère un paquet de contrôle RPL d'un nouveau type, Measurement Request indiquant ce qu'il veut savoir à propos du chemin entre lui-même et la destination. Chaque routeur sur le trajet va mettre à jour ce paquet avec le coût (pour la métrique demandée) du lien effectivement emprunté. Au bout, le destinataire répondra au demandeur, avec un message de contrôle Measurement Reply, contenant toute l'information accumulée. Le demandeur pourra alors agir (changer d'avis pour certaines routes, par exemple).

En fait, les deux messages utilisent le même type de paquets, les Measurement Object de code 0x06 (section 3 et registre IANA). Un bit dans son en-tête, le bit T (pour Type) sert à distinguer si ce Measurement Object est un Measurement Request ou un Measurement Reply. Le paquet contient surtout des options Metric Container (section 6.7.4 du RFC 6550 et section 2.1 du RFC 6551) qui accumuleront au fur et à mesure les valeurs demandées.

Il est intéressant de comparer ce mécanisme à celui de traceroute qui n'accumule pas les mesures mais compte sur une réponse de chaque routeur intermédiaire vers la source ; des options avaient été proposées pour un traceroute « enregistreur » - Record Route du RFC 791 ou option IP du RFC 1393 - mais elles n'ont eu aucun succès.

Notez bien que, dans un réseau ad hoc, rien ne garantit que tous les routeurs accepteront de procéder à cet enregistrement de données. Ils ont parfaitement le droit de refuser de le faire (voir la section 5 de notre RFC), par exemple pour économiser leur batterie ou bien parce qu'ils trouvent une telle demande trop indiscrète (section 8 du RFC).

Il existe déjà plusieurs mises en œuvre de cette extension expérimentale et un test d'interopérabilité a été documenté. Sinon, un bon article consacré aux mesures de P2P-RPL est « The P2P-RPL Routing Protocol for IPv6 Sensor Networks: Testbed Experiments ».

Merci à Emmanuel Baccelli pour sa relecture attentive.


Téléchargez le RFC 6998


L'article seul

RFC 6996: Autonomous System (AS) Reservation for Private Use

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : J. Mitchell (Microsoft)
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 29 juillet 2013


Comme pour beaucoup de nombres utilisés dans les protocoles TCP/IP, les numéros de système autonome ont une plage réservée aux usages privés, ne devant pas être transmis à l'extérieur. Ce nouveau RFC élargit la plage existante, qui était jugée trop petite par des gens qui gèrent des gros centres de données (comme Microsoft ou certains acteurs de l'infonuagique).

La section 10 du RFC 1930 réservait la plage allant de 64 512 à 65 535 (soit 1 024 numéros) pour des AS privés. Augmenter la taille de cette plage était délicat tant que les numéros d'AS étaient limités à 16 bits. Mais ils sont désormais sur 32 bits (RFC 6793) et il n'y a donc plus de raison de faire des économies. Une seconde plage, utilisant des numéros sur 32 bits, est donc réservée, allant de 4 200 000 000 à 4 294 967 294 (94 967 295 numéros). Ces deux plages sont documentées dans le registre IANA. (Notez que d'autres plages sont réservées pour la documentation, par le RFC 5398. Les numéros des deux plages de notre RFC sont, eux, conçus pour être utilisés par de vrais routeurs.)

La section 4 de notre RFC met en garde les opérateurs qui utilseraient ces numéros privés : ils ne doivent pas apparaître sur l'Internet public. Lorsqu'une annonce BGP dont le chemin (attributs AS_PATH ou AS4_PATH) sort du domaine privé, ces numéros d'AS doivent être retirés. Les commandes sont neighbor x.x.x.x remove-private-as pour IOS (c'est configuré pour chaque voisin BGP) et neighbor x.x.x.x remove-private pour JunOS mais attention : les anciennes versions de ces logiciels ne connaissaient que la première plage d'AS privés et ne retireront donc pas les numéros de la seconde plage. D'autre part, certains logiciels pour les routeurs ne retirent pas les numéros d'AS privés si le chemin dans l'annonce BGP contient un mélange d'AS privés et publics. Si le routeur en question n'a pas été mis à jour pour connaître la seconde plage de numéros d'AS privés, il va les prendre pour des numéros d'AS publics et ne rien retirer...

À noter que l'idée même d'avoir des nombres pour usage privé (que ce soient les numéros d'AS ou d'autres comme les adresses IP) défrise toujours un certain nombre de gens à l'IETF et que cette minorité s'était fait entendre dans le débat sur cet élargissement.


Téléchargez le RFC 6996


L'article seul

RFC 6994: Shared Use of Experimental TCP Options

Date de publication du RFC : Août 2013
Auteur(s) du RFC : J. Touch (USC/ISI)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 24 août 2013


Le protocole TCP dispose d'un champ « Options » permettant d'indiquer des fonctions spécifiques. Ce champ commence par un identificateur d'option (sur un octet) et deux valeurs sont réservées pour des options expérimentales, non enregistrées. Deux, c'est trop peu, et, en prime, il y a parfois collision entre deux options expérimentales différentes. Notre RFC propose donc un nouveau mécanisme éliminant ces collisions, en ajoutant un deuxième identificateur, l'ExID, dans les options expérimentales.

Le champ « Options » est décrit dans le RFC 793. Il a deux formes mais la plus courante est composée d'un octet indiquant l'option, d'un octet indiquant la longueur de l'option et de données spécifiques à l'option (un TLV, donc). Les options sont enregistrées à l'IANA et sont aujourd'hui au nombre d'une trentaine. 30 sur 256 possibles, cela justifie de les allouer avec prudence (RFC 2780) et les gens qui veulent juste essayer une idée amusante, sans enregistrer leur option, n'avaient pas de solution simple avant que le RFC 4727 ne réserve les options 253 et 254 pour les expérimentations. Si vous avez une idée qui nécessite une option TCP, et que vous voulez la mettre en œuvre, prenez un de ces deux numéros et mettez-le dans vos paquets TCP, vous serez dans la légalité (le RFC 3692 dit toutefois que cela ne doit pas être activé par défaut).

Mais ces expérimentations risquent de se marcher sur les pieds entre elles. Par exemple, le RFC 6013 s'alloue l'option 253. Si vous voulez tester une option en même temps que celle du RFC 6013, il ne vous reste plus qu'un numéro, ce qui peut être insuffisant (certains systèmes nécessitent plusieurs options). À noter que cet usage d'un numéro d'option expérimental est légal (c'est fait pour) mais qu'il existe aussi des squatteurs, qui utilisent des numéros normalement réservés sans les avoir enregistrés proprement. Les options 31 et 32 avaient ainsi été squattées autoritairement, comme 76 à 78, 33, 69, 70, et 76 à 78 (ces derniers dans des produits commerciaux). Le registre IANA les note comme « known unauthorized use without proper IANA assignment ».

Plusieurs approches ont été suggérées à l'IETF pour régler ce problème. Il a été proposé d'élargir l'espace des numéros d'options (Internet-Draft draft-eddy-tcpm-addl-exp-options) et/ou de libéraliser les règles d'allocation, actuellement très strictes (il faut un RFC sur le chemin des normes pour réserver une option). Ce RFC 6994 utilise une autre approche : il crée un « sous-espace » à l'intérieur des options expérimentales, dans lequel on peut (mais ce n'est pas obligatoire) enregistrer sans trop de formalités une expérimentation et son identificateur. C'est désormais l'approche recommandée pour les nouvelles options expérimentales TCP (et obligatoire si l'option expérimentale est déployée sur l'Internet public).

Le principe (section 3) est de remplacer la structure {numéro d'option, longueur, valeur} par {numéro d'option, longueur, ExID, valeur} où le ExID est l'identificateur d'une expérimentation. La taille des ExID (16 ou 32 bits) permet d'en avoir beaucoup et donc d'avoir une politique d'enregistrement libérale sans craindre d'épuiser une ressource finie. L'IANA les enregistre donc sur une base toute simple : « premier arrivé, premier servi » (RFC 5226 pour les différentes options d'allocation possibles). Le registre de ces ExID est en ligne (il compte actuellement trois expérimentations dont le Fast Open TCP qui a été décrit dans le RFC 7413).

Bon, mais l'ExID fait 16 ou 32 bits, alors ? C'est subtil : les 16 premiers bits doivent être uniques pour identifier une expérimentation. Les 16 bits optionnels suivants servent de nombre magique, pour éviter le risque de collision avec des mises en œuvre de TCP qui ne connaissent pas ce RFC (ou bien l'ignorent) et mettent leurs données juste après l'octet de longueur. Si on veut économiser de la place, on choisit un ExID de 16 bits, si on veut minimiser le risque de collision, on prend 32 bits.

Que va donc faire une mise en œuvre de TCP qui rencontre ces options (section 3.2) ? Si l'option est 253 ou 254, elle doit lire l'ExID et ignorer l'option s'il s'agit d'une expérimentation qui lui est inconnue.

Mais les collisions, alors ? Elles peuvent toujours exister. Si une implémentation ancienne de TCP utilise l'option 253 et met au début des données qu'elle envoie la valeur 0x15df, et que le récepteur TCP, conforme à ce nouveau RFC 6994, croit qu'il s'agit de l'expérimentation 5599, qu'il connait, et se met à analyser l'option comme telle ? Il n'y a pas de solution magique. La section 4 de notre RFC recommande aux receveurs TCP d'être robustes face à de telles collisions, ou bien de mettre en œuvre un mécanisme de contrôle de la cohérence des données, pour rejeter les faux positifs.

Un problème classique (et non spécifique à TCP) avec les options expérimentales est qu'un jour, elles seront peut-être normalisées et qu'il faudra alors gérer une transition depuis l'option expérimentale vers l'option standard. La section 5 couvre ce cas mais ne recommande pas une stratégie particulière. Elle se contente de dire qu'envoyer les deux options (l'expérimentale et la standard) dans le même paquet est une mauvaise idée (l'espace des options est limité en TCP).

La section 6 discute des autres approches qui auraient pu être choisies. Par exemple, au lieu des ExID, on aurait pu marquer les options avec un identificateur de l'organisation qui dirige l'expérience, en utilisant les OUI de l'IEEE ou bien les Enterprise Numbers de l'IANA (RFC 1155). Mais les OUI sont très chers (comme souvent à l'IEEE), plus de 1 800 dollars. Les PEN (Private Enterprise Numbers) sont gratuits mais ne sont normalement pas allouables à un individu. Et, dans les deux cas, ces nombres sont plus grands que l'ExID (les PEN n'ont pas de taille définie actuellement mais ils sont déjà trop nombreux pour 16 bits) alors que l'espace est limité dans le champ Options de TCP, puisque tout octet prend la place d'un octet utile aux données.

Si on regarde les versions de développement de Linux et de FreeBSD, on ne trouve rien dans ce dernier (sys/netinet/tcp_input.c dans tcp_dooptions()), qui ne connait pas, par défaut, les options expérimentales. Pour Linux, seul Fast Open est reconnu. Le code dans net/ipv4/tcp_input.c, tcp_parse_options() dit :


case TCPOPT_EXP:
        /* Fast Open option shares code 254 using a
         * 16 bits magic number. It's valid only in
         * SYN or SYN-ACK with an even size.
         */
        if (opsize < TCPOLEN_EXP_FASTOPEN_BASE ||
            get_unaligned_be16(ptr) != TCPOPT_FASTOPEN_MAGIC ||
            foc == NULL || !th->syn || (opsize & 1))
                break;
        foc->len = opsize - TCPOLEN_EXP_FASTOPEN_BASE;
        if (foc->len >= TCP_FASTOPEN_COOKIE_MIN &&
            foc->len <= TCP_FASTOPEN_COOKIE_MAX)
                memcpy(foc->val, ptr + 2, foc->len);
        ...
}

TCPOPT_FASTOPEN_MAGIC vaut 0xF989 (l'ExID sur 16 bits dans le registre IANA).


Téléchargez le RFC 6994


L'article seul

RFC 6991: Common YANG Data Types

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : J. Schoenwaelder (Jacobs University)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF netmod
Première rédaction de cet article le 31 juillet 2013


Le langage de modélisation YANG, normalisé dans le RFC 6020, est notamment utilisé dans le protocole de gestion à distance NETCONF (RFC 6241). C'est en YANG que les utilisateurs de NETCONF décrivent les données à manipuler via NETCONF. Ce RFC, successeur du RFC 6021, normalise une bibliothèque de types de données d'usage général, dérivés des types de base de YANG.

Ces types de base sont décrits dans la section 9 du RFC 6020. On y trouve les classiques de l'informatique, boolean, entiers, string, etc. Deux modules YANG sont décrits dans ce nouveau RFC, ietf-yang-types pour des types non limités à l'Internet et ietf-inet-types pour des types spécifiques à TCP/IP.

Je ne vais pas ici reprendre la liste de tous ces nouveaux types, juste donner quelques exemples de ce qu'apporte ce RFC. En section 3, les types généraux, on trouve par exemple, counter32. C'est un compteur, c'est à dire une variable qui ne fait que grimper, jusqu'au moment d'atteindre une valeur maximale (elle repart alors de zéro). Comme son nom l'indique, il est stocké sur 32 bits. Par contre, gauge32 peut monter et descendre.

Le type yang-identifier, un nouveau venu, est une chaîne de caractères ASCII (ne commençant pas par xml). Il est défini en YANG par une expression rationnelle :

typedef yang-identifier {
       type string {
         length "1..max";
         pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
         pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
         ...

date-and-time, lui, existait déjà dans le RFC 6021. C'est une date au format du RFC 3339 qui est proche du format traditionnel des schémas XML (mais, par contre, est différent de celui utilisé dans le SMI). Au contraire de date-and-time, qui est formaté, timeticks est simplement un nombre de secondes depuis l'epoch (non spécifiée : chaque schéma qui utilisera ce type indiquera quelle est l'epoch).

Il y a aussi des types plus orientés réseau comme mac-address pour les adresses MAC :

typedef mac-address {
       type string {
         pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
       }

Et d'autres qui empruntent à des identificateurs existants comme uuid (RFC 4122).

En section 4, les types spécifiques aux protocoles TCP/IP, on a entre autres ip-version qui permet d'indiquer si on parle d'IPv4 ou d'IPv6 :

typedef ip-version {
       type enumeration {
         enum unknown {
           value "0";
           description
            "An unknown or unspecified version of the Internet
             protocol.";
         }
         enum ipv4 {
           value "1";
           description
            "The IPv4 protocol as defined in RFC 791.";
         }
         enum ipv6 {
           value "2";
           description
            "The IPv6 protocol as defined in RFC 2460.";
         }
       }
...

Il y a bien sûr les numéros de port :

typedef port-number {
       type uint16 {
         range "0..65535";
       }
...

Et de système autonome :

typedef as-number {
       type uint32;
...

Et évidemment les adresses IP :

typedef ip-address {
       type union {
         type inet:ipv4-address;
         type inet:ipv6-address;
       }
...
typedef ipv6-address {
       type string {
         pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
               + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
               + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
               + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
               + '(%[\p{N}\p{L}]+)?';
         pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
               + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
               + '(%.+)?';
       }
...

Un exercice amusant : essayez de retrouver dans quel RFC est défini l'expression rationnelle officielle pour les adresses IPv6... (Avertissement : c'est difficile.)

Enfin, ce RFC donne aussi une définition du type domain-name pour les noms de domaine :

typedef domain-name {
       type string {
         pattern
           '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
         + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
         + '|\.';
         length "1..253";
       }
...

C'est une définition très contestable car, limitée à l'ASCII, elle oblige à représenter les IDN par un A-label (café.fr doit être écrit xn--caf-dma.fr, RFC 5890). Pire, le texte d'explication qui accompagne le module est plutôt embrouillé quant à la la définition des noms de domaine par rapport à celle des noms de machines (plus restrictive).

Par rapport au RFC 6021, qui contenait la bibliothèque originale, ce RFC ajoute quelques types (yang-identifier, uuid, etc, la liste complète est dans l'annexe A).


Téléchargez le RFC 6991


L'article seul

RFC 6988: Requirements for Energy Management

Date de publication du RFC : Septembre 2013
Auteur(s) du RFC : J. Quittek, M. Chandramouli (Cisco Systems), R. Winter (NEC Europe), T. Dietz (NEC Europe), B. Claise (Cisco Systems)
Pour information
Réalisé dans le cadre du groupe de travail IETF eman
Première rédaction de cet article le 1 octobre 2013


L'augmentation considérable des coûts de l'énergie, et la montée plus que justifiée des préoccupations écologiques, fait que la question de la consommation énergétique des équipements informatiques devient de plus en plus cruciale (certaines études estiment que la consommation d'énergie de l'Internet dépasse celle d'un pays comme la Russie). Les gros centres de données du nuage, usines à consommer du mégawatt, sont particulièrement visés. Cela a amené l'IETF à se lancer dans un domaine nouveau pour elle, et à créer un groupe de travail consacré à la gestion de l'énergie, EMAN, dont voici le premier vrai RFC, le cahier des charges du problème.

Le modèle envisagé est celui d'engins qui consomment ou fournissent de l'énergie, typiquement sous forme électrique, et qu'on veut pouvoir à la fois surveiller (monitoring function) et piloter (control function). Ces engins ont parfois une adresse IP, permettant de leur parler directement, et parfois pas, et il faut alors passer par un relais, qui va être la face visible de l'engin. Ce premier RFC du groupe EMAN définit les services indispensables dans les futures normes de gestion de l'énergie, suivant le modèle décrit dans le RFC 7326 (attention, ce RFC est un cahier des charges pour les normes, les futurs RFC d'EMAN, pas forcément pour les mises en œuvres qui suivront).

La gestion d'engins connectés au réseau n'est évidemment pas un problème nouveau et il existe déjà solutions et normes. Mais la gestion de l'énergie a trois particularités :

  • L'information intéressante n'est pas forcément obtenable auprès de l'engin géré. Ainsi, une machine peut être incapable d'indiquer sa consommation électrique, alors qu'on peut l'obtenir en interrogeant le dispositif qui l'alimente en électricité (par exemple un commutateur PoE) Ce genre de demandes indirectes sera fréquent dans le cadre de la gestion de l'énergie.
  • Même chose pour le contrôle (allumer ou éteindre l'engin), qui doit parfois se faire indirectement.
  • Et rappelez-vous qu'il sera fréquent que les engins connectés ne soient pas directement accessibles en IP et qu'il faille passer par un relais, ce qui est un cas bien plus rare en gestion de réseaux traditionnelle.

Avant d'aborder le cahier des charges proprement dit, la section 2 de notre RFC expose la terminologie, car tous les participants à l'IETF, bien versés dans le vocabulaire TCP/IP, ne connaissent pas forcément celui du monde de l'énergie (l'IEEE a un « Authoritative Dictionary of IEEE Standards Terms » d'où le RFC extrait plusieurs termes, mais je ne trouve pas ce dictionnaire en ligne). Donc, révisons un peu physique et ingéniérie :

  • Énergie (Energy) : dans le cadre de l'informatique et des réseaux, c'est typiquement de l'énergie électrique, mesurée en kWh (ne surtout pas écrire kW/h comme on le voit trop souvent).
  • Puissance (Power) : le taux d'usage, de production ou de transmission de l'énergie. En kW, parfois en joules par seconde.
  • Attributs (Power attributes) : les caractéristiques du courant électrique comme la tension, la phase ou la fréquence. Voir le « International Electrotechnical Vocabulary » de l'IEC.
  • Gestion de l'énergie (Energy management) : les fonctions qui permettent de mesurer, modéliser, planifier, optimiser, etc l'énergie.
  • Système de gestion de l'énergie (Energy management system) : le matériel et le logiciel qui assurent les fonctions ci-dessus.
  • Supervision de l'énergie (Energy monitoring) : le sous-ensemble de la gestion de l'énergie qui s'occupe de mesurer passivement.
  • Contrôle de l'énergie (Energy Control) : le sous-ensemble de la gestion de l'énergie qui s'occupe d'agir activement, par exemple en éteignant des machines inutiles.

La section 3 complète cette section 2 de terminologie en exposant quelques problématiques générales, qu'il faut avoir en tête lorsqu'on veut gérer l'énergie. D'abord, la notion d'état (Power state) : un engin peut être en état normal (il fonctionne, il répond et il consomme du courant), endormi (il consomme moins de courant, il ne répond pas aux requêtes normales mais il peut revenir en état normal rapidement) ou éteint (il ne consomme plus rien mais peut prendre un certain temps à se rallumer et à redevenir opérationnel). Les engins les plus simples n'ont que deux états, allumé et éteint. Les plus perfectionnés en ont plus que trois : par exemple, ils peuvent avoir des modes de basse consommation où l'engin reste complètement opérationnel mais avec des performances réduites. Sur des engins composés de plusieurs parties relativement indépendantes, il est parfois possible de couper le courant dans une partie de ces sous-ensembles et pas seulement dans l'engin entier.

Le but ultime de la gestion de l'énergie est d'économiser du courant. Comme rien n'est parfait en ce bas monde, cela se fera souvent au prix d'un service moins bon. Il sera donc en général nécessaire de faire des compromis.

La gestion de l'énergie peut être entièrement locale (à l'intérieur de l'engin lui-même) ou bien globale au réseau. Un exemple de gestion locale est une machine qui se met en sommeil automatiquement lorsqu'elle n'a pas eu d'activité depuis N minutes. Cela peut se faire sans réseau, sans collecter l'information et sans système central. Un exemple de gestion globale est un système qui voit que la consommation électrique du réseau devient trop importante (en coût ou, tout simplement, par rapport aux capacités du fournisseur d'énergie) et qui éteint alors autoritairement certains engins. Le système de gestion ayant plus d'informations que les machines locales, il peut prendre des décisions plus appropriées, et tenir compte de politiques globales (on éteint les machines dans le bureau la nuit). Les deux méthodes ont leurs avantages et leurs inconvénients et, en général, on combine les deux.

À noter (section 3.4) que la supervision de la consommation d'énergie, à elle seule, ne diminue pas la consommation. Elle va même l'augmenter, puisque le système de supervision consomme lui-même du courant. Pour que ce système mène à une diminution de la consommation, il faut aussi qu'il soit utilisé pour chercher les économies possibles, évaluer les mesures de réduction de consommation, assurer la comptabilité de chaque entité, etc.

Pour assurer une bonne supervision, avec une granularité permettant cette comptabilité, il va falloir des identificateurs pour désigner les différentes entités (section 4). Une entité peut être une machine ou bien seulement une partie d'une machine (un disque dur, par exemple, ou bien une line card). En effet, certaines mesures d'économie d'énergie peuvent être à ce niveau de détail (éteindre une seule line card). Il existe déjà de tels identificateurs, par exemple dans les MIB des RFC 4133 et RFC 3621. Il faudra donc lier les informations de gestion de l'énergie à ces identificateurs, traitant des problèmes comme la persistence en cas de redémarrage.

Ensuite, il faut connaître, pour chaque entité supervisée et/ou contrôlée, un certain nombre d'informations (section 5). Par exemple, il est préférable de connaître l'importance d'une entité, pour éviter d'éteindre une machine importante alors qu'on voulait économiser quelques watts. Une autre propriété utile est l'ensemble des caractéristiques statiques de son alimentation électrique : utilise-t-elle du courant continu ou alternatif, quelle est la tension normale, la fréquence normale (par exemple, 230 V à 50 Hz), etc. Il faut aussi connaître la liste des interfaces utilisées pour l'énergie, et s'il s'agit de production (power outlet, par où on envoie de l'énergie) ou de consommation (power inlet, par où on reçoit de l'énergie).

Et il y a des caractéristiques dynamiques :

  • Est-ce que le courant est disponible sur la prise ? Est-il utilisé ? Si oui, quelle est la puissance consommée ou produite en ce moment ? Attention, ce dernier point peut nécessiter des équipement de mesure coûteux. Certaines machines ne vont pas être capables de mesurer précisement leur propre consommation.
  • Et la consommation ou production d'énergie (rappel : l'énergie est la puissance multipliée par le temps) ? Que vaut-elle sur un intervalle de temps donné ?
  • Pour faciliter les alarmes, le RFC suggère aussi que la machine soit capable de signaler que la puissance tombe en dessous d'une certaine valeur, ou grimpe au-dessus d'un maximum.
  • Quelles sont la tension et l'intensité actuelles ?
  • Quel est l'état de la machine supervisée, allumée, éteinte, en basse consommation, en veille ? Et quels sont les états possibles (ils ne sont pas les mêmes pour toutes les machines) ? Là encore, pour les alarmes, un mécanisme de notification non sollicitée, permettant d'être informé des changements d'état, est demandé.
  • Il y a bien d'autres choses à superviser comme l'état des batteries (en train de se charger ? de se décharger ?), leur charge (pleine ? vide ? à moitié vide ?), mesurée en mAh avec évidemment des alarmes en dessous d'un certain seuil ou comme leur température.

Après la supervision, le contrôle (section 6). Contrairement à la supervision, il est actif. Il s'agit d'agir. Agir sur quoi ?

  • Couper ou allumer le courant (le RFC avertit que certains engins peuvent ne pas aimer une coupure brutale et que cette fonction doit donc se faire dans le cadre d'un système de gestion plus général, qui ne prend pas en compte que la consommation d'énergie).
  • Faire passer l'engin d'un état (basse consommation, veille, hibernation, etc) à un autre.

Une section 9 détaillée couvre les problèmes de sécurité. On a beaucoup parlé des risques de sécurité des SCADA, souvent connectés à l'Internet sans réflechir. Ces systèmes de contrôle, souvent anciens et n'ayant pas fait l'objet d'une analyse de sécurité sérieuse, sont parfois reliés à ce réseau mondial sans précautions. Contrôler l'état des machines et leur fourniture d'électricité est clairement une fonction très sensible. La sécurité doit donc être soigneusement pesée. Tout doit être authentifié et autorisé. Et les engins qui mettent en œuvre les services décrits dans ce RFC ne devraient pas être connectés à l'Internet public sans une très bonne raison (section 9.2).

Il n'y a pas que le contrôle qui pose des problèmes de sécurité. Par exemple, la supervision soulève des problèmes de vie privée, comme cela a été plusieurs fois évoqué dans le débat sur les compteurs intelligents.

Depuis ce cahier des charges, plusieurs RFC sur le sujet ont été publiés comme les RFC 7326 et le RFC 7603.


Téléchargez le RFC 6988


L'article seul

RFC 6986: GOST R 34.11-2012: Hash Function

Date de publication du RFC : Août 2013
Auteur(s) du RFC : V. Dolmatov (Cryptocom), A. Degtyarev (Cryptocom)
Pour information
Première rédaction de cet article le 5 septembre 2013


Ce RFC documente en anglais une norme russe de l'organisme GOST. GOST R 34.11-2012 est une fonction de condensation cryptographique. Elle pourra notamment être utilisée pour DNSSEC.

Les algorithmes GOST (un abus de langage puisque GOST est normalement le nom de l'organisme de normalisation) sont une alternative russe aux algorithmes de cryptographie d'origine états-unienne comme RSA ou ECDSA (qui peuvent être remplacés par GOST R 34.10-2001) ou comme SHA-2 (qui peut être remplacé par GOST R 34.11-2012, qui fait l'objet de ce RFC). Pour être utilisés dans les protocoles IETF, il leut fallait une documentation en anglais. GOST R 34.10-2001 avait été documenté dans le RFC 5832. Notre RFC 6986 documente le petit dernier membre de la famille (son prédécesseur pour la condensation, GOST R 34.11-94, était dans le RFC 5831). Notez que les algorithmes GOST sont normalisés pour un usage dans le cadre de DNSSEC (RFC 5933).

Comme les autres algorithmes GOST, notre R 34.11-2012 est donc un algorithme officiel en Russie. Il a été approuvé par le décret n° 216 de l'agence fédérale chargée de la régulation technique, en août 2012. À terme, il vise à remplacer l'ancien R 34.11-94. C'est un algorithme de condensation cryptographique, qui peut produire des condensats de 256 ou 512 bits.

Je ne vais pas essayer de vous expliquer son principe de fonctionnement (sections 4 à 10), car c'est trop loin de mon domaine de compétence. Si vous êtes plus courageux que moi, notez qu'il y a beaucoup de maths et que, dans le formatage texte brut des RFC, ce n'est pas forcément idéal.

Questions mises en œuvre, notez qu'OpenSSL 1.0.1c n'a apparemment pas d'algorithmes de condensation GOST par défaut. openssl dgst -h pour voir la liste. Il faut apparemment éditer le openssl.cnf pour y avoir accès.


Téléchargez le RFC 6986


L'article seul

RFC 6985: IMIX Genome: Specification of variable packet sizes for additional testing

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : A. Morton (AT&T Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF bmwg
Première rédaction de cet article le 19 juillet 2013


Traditionnellement, les mesures des caractéristiques d'un réseau en labo (RFC 2544) se faisaient avec des paquets de taille constante, afin de bien contrôler les conditions de la mesure, de savoir exactement ce qui était mesuré et donc de pouvoir reproduire la mesure à volonté. C'est par exemple ce que fait la commande ping avec son option -s. Mais les réseaux réels sont bien différents : ils font passer des paquets de taille très diverses. Il est donc fréquent aujourd'hui de tester avec un mélange de paquets de différentes tailles, ce qu'on nomme un IMIX (Internet MIXture). De nos jours, les équipements de test ont souvent la possibilité d'utiliser des IMIX. Mais les tests doivent être reproductibles, il faut donc un moyen de caractériser un IMIX, d'indiquer sa composition (autrement que par un vague « on a utilisé un IMIX »). C'est le but du mini-langage présenté dans ce RFC.

En gros, les petits paquets vont tester la capacité du réseau à traiter les en-têtes et les gros vont tester sa capacité à faire circuler des bits. On a donc besoin des deux dans un test. L'IMIX genome est la description, dans un langage formel, de la répartition des tailles de paquets. (Comme un génome décrit une espèce.)

Donc, à quoi ressemble un IMIX (section 3 du RFC) ? À une série de lettres dont chacune code une taille de paquet donnée, en utilisant les tailles « standard » du RFC 2544. Ainsi, avec la table a = 64 octets, b = 128, c = 256, d = 512, e = 1 024, f = 1 280 et g = 1518, l'IMIX aaafg désigne une séquence de cinq paquets, les trois premiers faisant 64 octets, le quatrième 1 280 et le dernier ayant la taille maximale sur Ethernet. Une lettre z est utilisée pour dire « la MTU du lien », donc, ici, on aurait pu utiliser aaafz. Notez bien qu'avec cette notation, les autres tailles ne peuvent pas être représentées (il faut choisir la taille la plus proche) et qu'un test avec des milliers de paquets est décrit par un IMIX assez illisible...

Si on tient à utiliser des tailles non prévues par le RFC 2544, la section 4 prévoit un moyen de définir localement des lettres, notées en majuscule. Avec la table locale A = 98, B = 1 020, l'IMIX BBAA indiquera deux gros paquets puis deux petits.

Ce système manque clairement de souplesse : et si, pour un test long, une séquence de base est répétée ? Ou bien si les tailles sont choisies par un processus pseudo-aléatoire ? La section 5 décrit deux fonctions utiles du mini-langage de description des génomes IMIX. Pour les séquences répétées, on se sert simplement d'un encodage en RLE. Le RFC ne propose pas de syntaxe concrète pour le décrire, l'exemple est juste un tableau « 20 fois abcd puis 5 fois ggga et enfin 10 fois dcba ». Le RFC propose également un autre mécanisme (à nouveau sans syntaxe précise), en indiquant les pourcentages de chaque taille (sans spécifier la séquence) : « 23 % de 64 octets, 67 % de 128 et 10 % de 1 000 ».

Le RFC prévoit aussi le cas où les tailles sont générées par un algorithme. Dans ce cas, pas de langage particulier, il faut le décrire en langage naturel lorsqu'on publie les résultats de la mesure (« on part de paquets de 64 octets et on incrémente leur taille de 1 à chaque paquet, s'arrêtant à la MTU »). Idem si l'algorithme utilisé est un générateur pseudo-aléatoire, qui doit également être décrit (avec la graine utilisée).

Si vous voulez lire des articles sur les IMIX, voir « "Test Methodology Journal: IMIX (Internet Mix) », « Library: Test Plans » ou « The Journal of Internet Test Methodologies ». Pour une discussion sur la normalisation d'IMIX (et pas du langage qui les décrit), voir une discussion terminologique dans le groupe de travail.


Téléchargez le RFC 6985


L'article seul

RFC 6984: Interoperability Report for Forwarding and Control Element Separation (ForCES)

Date de publication du RFC : Août 2013
Auteur(s) du RFC : W. Wang (Zhejiang Gongshang University), K. Ogawa (NTT Corporation), E.H. Haleplidis (University of Patras), M. Gao (Hangzhou BAUD Networks), J. Hadi Salim (Mojatatu Networks)
Pour information
Réalisé dans le cadre du groupe de travail IETF forces
Première rédaction de cet article le 25 août 2013


Un élément essentiel de la culture IETF est l'importance donnée aux programmes qui marchent : rough consensus and running code. D'où les fréquents tests d'interopérabilité, entre diverses mises en œuvre des protocoles IETF, afin de vérifier que, non seulement le code tourne mais qu'il peut interagir avec d'autres instances. Le groupe de travail ForCES, qui normalise des protocoles de communication internes aux routeurs, a ainsi procédé à deux ateliers de tests d'interopérabilité, ce RFC documentant le second.

Le premier avait eu lieu en 2009 à l'université de Patras et avait été documenté dans le RFC 6053. Le second a eu lieu en février 2011 à l'ITL (Internet Technology Lab) à l'université de Zhejiang Gongshang. (Oui, je sais, c'est long, entre l'atelier et la publication du compte-rendu dans un RFC...)

Rappelons ce que fait ForCES : il normalise la communication entre les éléments d'un routeur (ou autre engin du réseau : la norme parle de NE pour Network Element). Le but est de permettra la construction de routeurs en kit, en assemblant des parties d'origines différentes, mais parlant toutes ForCES. Le système ForCES est riche et complexe et cet atelier d'interopérabilité testait cinq composants : le protocole de communication entre CE (Control Element) et FE (Forwarding Element), normalisé dans le RFC 5810, le protocole de transport sous-jacent (RFC 5811), le modèle des FE (RFC 5812), la bibliothèque standard (RFC 6956) et le mécanisme de haute disponibilité (dont le RFC n'a pas encore été publié). Des CE et FE d'origines diverses ont été connectés entre eux, se sont parlé, la bonne compréhension a été vérifiée et tcpdump et Wireshark ont été utilisés pour un contrôle supplémentaire.

Trois mises en œuvre de ForCES ont été testées, les mêmes qu'à l'atelier précédent (ForCES n'a pas pour l'instant suscité un intérêt massif) : celle de NTT, celle de l'université de Patras, et celle faite en commun entre l'université de Zhejiang Gongshang et la société BAUD Network. Les Grecs n'ayant pu se déplacer, ils ont participé aux tests à distance, connectés via un VPN (dans la réalité, bien sûr, les FE et les CE seront toujours proches, souvent dans le même boîtier physique). Globalement, les tests ont été des succès, à part un problème embêtant avec l'encapsulation des données dans une réponse ForCES (voir les détails plus loin). Comme toujours, ces tests ont permis de découvrir des erreurs ou des approximations dans les RFC.

Les communications utilisaient IPsec, puisque le RFC sur le transport de ForCES, RFC 5811, fait obligation à chaque mise en œuvre de ForCES d'avoir IPsec (mais pas forcément de l'activer par défaut : c'est sa disponibilité qui est obligatoire, pas son usage).

Un exemple d'un des scénarios testés (section 3.4) : deux machines terminales sur deux réseaux locaux différents étaient connectées via deux routeurs OSPF. L'un était un routeur classique, l'autre une machine ForCES dont le CE (Control Element) parlait OSPF avec le routeur classique pendant que le FE (Forwarding Element) transmettait les paquets. Ce scénario nécessitait que le CE communique au FE les règles qu'il avait apprises en OSPF et testait la mise en œuvre correcte de plusieurs fonctions du RFC 6956. Une variante de ce test remplaçait le routeur classique par une autre machine ForCES : les deux CE se parlaient en OSPF et chacun disait ensuite à son FE ce qu'il devait faire des paquets IP.

La section 4 donne les résultats complets des tests. Il y a une très grande majorité de succès mais aussi deux échecs, qui vont nécessiter du travail chez les programmeurs.

Mais le principal problème de l'atelier a été un problème lors de la communication de tableaux (et pas de simples valeurs scalaires) entre deux programmes. Le problème est que ForCES permet plusieurs encodages possibles pour les données complexes (RFC 5810, section 6 et notamment 6.4). La règle est que chaque élément ForCES peut choisir librement parmi ces encodages (pas moins de trois possibilités légales, dans l'exemple discuté dans la section 5 de notre RFC). Mais un programme considérait que la réponse venait forcément dans l'encodage de la question, et plantait si ce n'était pas le cas. Bien qu'il soit clairement en tort, notre RFC considère qu'il vaut mieux en effet générer une réponse en utilisant le même encodage que la question ou la commande. Personnellement, je pense plutôt que c'était très gentil de donner un vaste choix aux CE et FE (par exemple pour optimiser le cas de grands tableaux ayant beaucoup de vide) mais que cela mène forcément à ce genre de problèmes. Traditionnellement, les protocoles IETF préfèrent l'interopérabilité à la liberté et ForCES était peut-être allé trop loin dans les possibilités de choix.


Téléchargez le RFC 6984


L'article seul

RFC 6982: Improving Awareness of Running Code: the Implementation Status Section

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : Y. Sheffer (Porticor), A. Farrel (Juniper)
Expérimental
Première rédaction de cet article le 18 juillet 2013


L'IETF se vante souvent de ne pas croire au blabla des marketeux, mais uniquement au code qui tourne. Comme le dit fièrement sa devise, « We believe in rough consensus and running code ». Mais, en pratique, les normes produites et publiées en RFC ne contiennent pas toujours la mention d'une mise en œuvre effective de cette norme. Parfois, c'est parce qu'il n'y en a pas (contrairement à une légende tenace, ce n'est nullement une obligation pour la publication d'un RFC). Parfois, c'est parce qu'elle n'est pas mentionnée. Avant la publication d'un RFC, lorsque le document est encore un simple Internet-Draft, la mention de l'existence de programmes mettant en œuvre le protocole ou le format décrit est complètement facultative. Ce nouveau RFC propose de formaliser et d'encourager cette mention. Il a depuis été remplacé par le RFC 7942.

Cela ne concerne que les Internet-Drafts, pas les RFC. En effet, les RFC sont stables (jamais modifiés) alors que les URL pointant vers un programme ne le sont pas : un programme peut être abandonné, plus maintenu, on peut se retrouver avec des 404, etc. Donc, un RFC n'est pas le bon endroit pour stocker un catalogue de mises en œuvre d'un protocole. L'expérimentation décrite dans ce nouveau RFC 6982 ne vise que les Internet-Drafts, afin d'aider à l'évaluation d'une proposition.

Le concept de running code est décrit dans le Tao (cf. RFC 4677 et RFC 6722). Il synthétise l'approche pragmatique de l'IETF : une norme qui n'est pas mise en œuvre ne sert à rien. Malgré cela, bien des RFC n'ont jamais connu la moindre mise en œuvre. En effet, ce principe général du running code n'a jamais été traduit dans une exigence formalisée et globale pour les auteurs de RFC. Il existe par contre des règles locales. Ainsi, la Routing Area de l'IETF (les groupes de travail qui normalisent les protocoles de routage) a longtemps demandé (RFC 1264) au moins une mise en œuvre avant la publication d'un RFC sur le chemin des normes. Le RFC 4794 a supprimé cette règle, qui reste appliquée par certains groupes de la Routing Area comme IDR.

Notre tout nouveau RFC 6982 est purement expérimental : il ne propose pas de définir une nouvelle règle, juste de formaliser une section dans les Internet-Drafts, facultative, qui permettra de documenter les mises en œuvre connues. L'idée est que les Internet-Drafts ayant cette section seront examinés avec plus de bienveillance, sans toutefois qu'elle soit obligatoire.

La section 4 du RFC fait la liste de tous les avantages qu'il y a à indiquer ces mises en œuvre dans l'Internet-Draft : meilleure information pour la prise de décision (aussi bien sur la publication de l'Internet-Draft que sur le statut du futur RFC), encouragement aux tests d'interopérabilité, possibilité (lorsque le code est publié) de mieux comprendre le protocole (beaucoup de programmeurs préfèrent lire le source plutôt que le RFC), et enfin assurance que telle fonction du RFC peut effectivement être mise en œuvre. C'est en effet souvent le cas (par exemple lors de la discussion qui a mené au RFC 5155) que certaines personnes affirment que la technologie envisagée est tout simplement trop complexe pour être programmée. L'existence d'un programme qu'on peut tester permet de d'assurer que, si, la technologie est réaliste (bien d'autres SDO produisent sans hésiter des technologies impossible à programmer dans des conditions raisonnables).

Cette nouvelle section, « Implementation status » est décrite en section 2 de ce RFC. Elle sera située vers la fin (comme l'actuelle - et obligatoire, elle - « Security considerations ») et pourra comporter les points suivants :

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

Cette section peut aussi indiquer l'expérience tirée de cette mise en œuvre, ainsi que des informations sur l'interopérabilité, au cas où plusieurs mises en œuvre existent. Les présidents des groupes de travail sont explicitement chargés de vérifier que cette section ne dégénère pas en simple marketing pour le produit d'un vendeur. Notre RFC propose aussi un texte standard d'avertissement à inclure au debut de cette section « Implementation status ».

D'autres endroits que l'Internet-Draft lui-même auraient pu être utilisés pour informer sur les mises en œuvre existantes. Le RFC suggère (section 3) de passer au wiki de l'IETF lorsque la liste des programmes devient trop longue, lorsqu'il semble préférable que cette liste soit maintenue par les implémenteurs plutôt que par les auteurs de l'Internet-Draft, lorsque le groupe de travail maintient activement un wiki, ou enfin lorsque la liste en question semble utile, même après la publication en RFC (pour indiquer le niveau d'adoption par les programeurs). Dans tous ces cas, il est bon d'indiquer l'URL du Wiki en question dans l'Internet-Draft.

Le RFC se donnait 18 mois pour l'évaluation de l'expérience, ce qui est la durée typique de production d'un RFC). Cette expérimentation est alors devenue la politique officielle de l'IETF (RFC 7942). On a évalué si cette section a été utilisée (par exemple pour trouver du code qu'on va ensuite tester) et si les décisions prises ont effectivement été meilleures. Curieusement, alors que cette nouvelle section n'est nullement obligatoire, ce RFC 6982 ne propose pas parmi les critères de succès de voir tout simplement combien d'auteurs d'Internet-Drafts ont inclus une telle section. Il faut dire qu'un certain nombre le font déjà de façon informelle.

Quelques exemples d'Internet-Drafts qui incluent actuellement cette section : draft-clausen-lln-loadng, draft-wilde-xml-patch ou draft-ietf-mpls-multipath-use.


Téléchargez le RFC 6982


L'article seul

RFC 6980: Security Implications of IPv6 Fragmentation with IPv6 Neighbor Discovery

Date de publication du RFC : Août 2013
Auteur(s) du RFC : F. Gont (SI6 Networks / UTN-FRH)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 26 août 2013


Ce court RFC traite un problème de sécurité lorsqu'on combine la fragmentation avec le protocole NDP d'IPv6. Il interdit désormais cette combinaison, qui pouvait être exploitée pour des attaques sur le réseau local.

NDP est normalisé dans le RFC 4861 (que ce RFC 6980 met à jour). Ce protocole est utilisé pour bien des choses, notamment pour résoudre une adresse IPv6 en adresse MAC et pour découvrir les routeurs du réseau local, ainsi que les préfixes des adresses IP de ce réseau (pour l'auto-configuration). Ses faiblesses de sécurité (très proches de celles d'ARP en IPv4) sont bien connues (RFC 3756). Notamment, n'importe quelle machine peut émettre des paquets NDP et répondre aux questions adressées à une autre machine. Ou bien l'attaquant peut se faire passer pour le routeur et émettre des « RAcailles », ces faux paquets RA (Router Advertisment).

Il existe plusieurs moyens de gérer ces dangers. On peut mettre des ACL statiques dans les commutateurs, n'autorisant les RA que sur le port où se trouve le routeur. Ou bien on peut utiliser la solution un peu plus sophistiquée du RA guard (RFC 6105). On peut aussi surveiller le trafic, avec un IPS ou bien un logiciel comme NDPmon ou ramond, et lever une alarme lorsque quelque chose d'anormal se produit. Mais toutes ces techniques ont un défaut commun : elles reposent sur une analyse du paquet pour détecter si c'était du NDP et il est trop facile de les tromper en fragmentant le paquet. S'il est en deux parties, avec les informations permettant de reconnaître et d'analyser le NDP dans le deuxième paquet, aucun des systèmes existants ne voit ce qui se passe, alors que la machine terminale réassemblera le paquet et se fera donc avoir. À l'heure actuelle, la totalité des mises en œuvre de RA guard est ainsi vulnérable (cf. RFC 7113). Bien sûr, des outils comme les IPS pourraient réassembler les paquets eux-aussi, pour voir le paquet original, mais c'est plus difficile pour les commutateurs Ethernet. Et cela leur fait courir un risque (si l'attaquant génère des quantités de fragments afin d'épuiser la mémoire des réassembleurs, pour faire une attaque par déni de service).

C'est d'autant plus balot que les vrais paquets NDP sont rarement assez grands pour avoir réellement besoin de la fragmentation (section 2). Même si un routeur a besoin d'annoncer de nombreux préfixes dans ses RA, il peut le faire en plusieurs datagrammes IP, il n'est pas nécessaire de tout mettre dans un seul grand datagramme fragmenté. Bref, la fragmentation est quasi-inutile pour NDP alors qu'elle est dangereuse. (Une exception partielle est décrite en section 3, pour SEND, dans le RFC 3971, dans le cas où il y a des gros certificats à transmettre. Je ne la mentionne pas davantage puisque SEND n'est quasiment jamais utilisé. Il résoud radicalement presque tous les problèmes de sécurité de NDP mais le manque de mises en œuvre de ce protocole, et la difficulté qu'il y a à distribuer les clés cryptographiques nécessaires font qu'en pratique, SEND n'est pas une approche envisageable. Voir la conférence de l'auteur à DEEPSEC.)

La section 4 résume les raisons d'abandonner la fragmentation pour NDP :

  • Il existe déjà des mises en œuvre d'IPv6 qui ignorent les paquets NDP fragmentés,
  • Dans la vraie vie, comme expliqué en sections 2 et 3, les paquets NDP réels ne sont pas assez grands pour être fragmentés.

Donc, la section 5 du RFC expose la nouvelle règle, qui met à jour le RFC 4861 : une machine qui émet des paquets NDP ne doit pas fragmenter ces paquets. (Une exception partielle est faite pour les messages Certification Path Advertisement utilisés par SEND. Mais, pour tous les messages habituels, la règle est l'interdiction de la fragmentation.) À la réception, les paquets NDP fragmentés doivent être ignorés.

Si vous voulez créer vous-même de tels paquets NDP fragmentés (qui seront ignorés par les systèmes modernes, vous pouvez utiliser la boîte à outils SI6 présenté dans mon article sur le hacking IPv6, avec l'option -y. Par exemple :

# ./ra6 -y 8  -i eth1 -d 2001:db8:8bd9:8bb0:ba27:ebff:feba:9094          

va générer deux fragments, huit octets n'étant pas assez pour mettre le RA. tcpdump les voit ainsi :

08:34:29.122863 IP6 fe80::8609:88f4:14:a635 > 2001:db8:8bd9:8bb0:ba27:ebff:feba:9094: frag (0|8) ICMP6, router advertisement, length 8
08:34:29.122883 IP6 fe80::8609:88f4:14:a635 > 2001:db8:8bd9:8bb0:ba27:ebff:feba:9094: frag (8|8)

Notez que tcpdump ne s'est pas laissé avoir : il a bien identifié le premier fragment comme appartenant à un RA.


Téléchargez le RFC 6980


L'article seul

RFC 6979: Deterministic Usage of DSA and ECDSA Digital Signature Algorithms

Date de publication du RFC : Août 2013
Auteur(s) du RFC : T. Pornin
Pour information
Première rédaction de cet article le 24 août 2013


Les algorithmes de signature DSA et ECDSA ont une particularité qui est souvent oubliée : chaque signature doit utiliser un nombre imprévisible. On peut, par exemple, générer ce nombre par un processus aléatoire. Mais tous les systèmes qui voudraient utiliser DSA ou ECDSA n'ont pas forcément un tel générateur aléatoire. Ce RFC propose une autre méthode : fabriquer ce nombre par dérivation déterministe d'un certain nombre de paramètres, produisant le même effet, sans pour autant nécessiter de source d'aléa.

Ces deux algorithmes sont très utilisés dans le monde. (À noter qu'ECDSA repose sur les courbes elliptiques, décrites dans le RFC 6090.) Mais cette nécessité de générer un nombre unique et imprévisible par signature n'a pas d'équivalent avec des algorithmes comme RSA. Le pourquoi de cette nécessité est bien expliqué dans un article de Nate Lawson. Si vous l'oubliez, vous serez piraté, comme Sony l'a été. Mais que ce nombre soit aléatoire n'est pas strictement nécessaire. En fait, l'aléatoire a deux défauts :

  • Il rend les tests difficiles puisque deux exécutions successives du même programme ne donneront pas le même résultat. Ces tests ne peuvent pas facilement vérifier si le nombre est bien imprévisible.
  • Et, surtout, toutes les machines n'ont pas forcément un générateur aléatoire de bonne qualité (cf. RFC 4086), notamment les engins spécialisés comme les cartes à puce. Cela peut mener à préférer RSA, pourtant plus consommateur de ressources.

L'algorithme permettant de générer un nombre unique et imprévisible, mais sans générateur aléatoire, est décrit dans les sections 2 et 3 de notre RFC (il est fondé sur l'idée de derandomization, décrite dans « How Risky is the Random-Oracle Model? »). Je ne vais pas résumer cet algorithme ici (la cryptographie, c'est trop fort pour moi) mais ses propriétés importantes sont :

  • Les signatures sont des signatures DSA ou ECDSA traditionnelles. Les vérificateurs de signature n'ont pas besoin de connaître ce nouvel algorithme et n'ont donc pas besoin d'être modifiés.
  • Les clés, elles, doivent, comme avant, être générées aléatoirement (comme avec RSA).

L'annexe A contient un exemple détaillé de calcul du nombre unique pour une signature.

Si vous envisagez de programmer cet algorithme de génération déterministe de signature, faites bien attention à la section 4, qui résume les problèmes de sécurité. Par exemple, comme rappelé plus haut, la procédure de ce RFC ne s'applique pas aux clés qui doivent, comme avant, être générées aléatoirement. Pour des engins sans générateur aléatoire, comme les carte à puce de bas et de milieu de gamme, cela peut par exemple être fait à l'usine, pendant la fabrication de l'engin.

D'autre part, comme la génération de la signature est déterministe, le même messsage aura donc toujours la même signature (tant qu'on garde la même clé privée, bien sûr). Cela n'est pas un problème dans certaines applications (RSA, tel que décrit dans le RFC 3447, fait pareil). Ainsi, TLS (RFC 5246), SSH (RFC 4251) ou CMS (RFC 5652) peuvent utiliser cet algorithme déterministe sans risque pour leur sécurité.

À noter que, de manière surprenante pour un RFC, la section 5 est consacrée aux risque de brevets sur cet algorithme (apparemment assez faibles). C'est surprenant car, comme la situation change tout le temps (nouveaux brevets, brevets reconnus comme futiles, etc), cette information est normalement distribuée en ligne et pas mise dans un RFC stable (c'est expliqué dans le RFC 8179). Les brevets actuellement connus pour ce RFC sont sur le site Web de l'IETF.

L'annexe B contient une mise en œuvre, en Java, de cet algorithme (copiée ici dans le fichier DeterministicDSA.java). On peut l'utiliser, par exemple, ainsi :


import java.math.BigInteger;
import org.ietf.DeterministicDSA;

public class TestDeterministicDSA {
    
    // http://stackoverflow.com/questions/5470219/java-get-md5-string-from-message-digest
    private static String binary2string(byte []bin) {
	StringBuilder binString = new StringBuilder();
	for (int i = 0; i < bin.length; i++) {
	    String hex = Integer.toHexString(bin[i]);
	    if (hex.length() == 1)
		{
		    binString.append('0');
		    binString.append(hex.charAt(hex.length() - 1));
		}
	    else
		binString.append(hex.substring(hex.length() - 2));
	}
	return binString.toString();
    }

    public static void main (String args[]) {
	int i;
        DeterministicDSA dsa = new DeterministicDSA("SHA-256");
	String signature;
        // We use the private key for the appendix A.2.1 of the RFC
	BigInteger p = new BigInteger("86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED8873ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", 16);
	BigInteger q = new BigInteger("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16);
	BigInteger g = new BigInteger("07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA417BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", 16);
	BigInteger x = new BigInteger("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16);
	dsa.setPrivateKey(p, q, g, x);
	for (i=0; i<args.length; i++) {
	    dsa.update(args[i].getBytes());
	    signature = binary2string(dsa.sign());
	    System.out.println(args[i] + " -> " + signature);
	    dsa.reset();
	}
    }
   
}

Et on retrouve les valeurs indiquées dans le RFC (ce qui est logique pour un processus déterministe...) :

 
% java TestDeterministicDSA sample test
sample -> 302d02150081f2f5850be5bc123c43f71a3033e9384611c54502144cdd914b65eb6c66a8aaad27299bee6b035f5e89
test -> 302c021422518c127299b0f6fdc9872b282b9e70d079081202146837ec18f150d55de95b5e29be7af5d01e4fe160

Téléchargez le RFC 6979


L'article seul

RFC 6978: A TCP Authentication Option NAT Extension

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : J. Touch (USC/ISI)
Expérimental
Première rédaction de cet article le 20 juillet 2013


Le protocole d'authentification des paquets TCP AO (Authentication Option), normalisé dans le RFC 5925, a une limite : il ne fonctionne pas du tout lorsque la session est établie à travers au moins un routeur NAT. Ce nouveau RFC propose une extension qui lui permet d'authentifier quand même les paquets dans ce cas, au prix d'une légère baisse de la sécurité.

En effet, l'authentification AO range et génère ses clés en tenant compte d'un ensemble de paramètres de la session (RFC 5925, sections 3.1 et 3.2), parmi lesquels se trouvent les adresses IP de source et de destination, ainsi que les ports de source et de destination. Un routeur NAT modifie en général l'adresse IP source et les routeurs existants (qui font souvent du NAPT et pas du NAT à proprement parler, cf. RFC 2663) modifie également le port source. AO ne retrouve donc plus ses clés (RFC 5925, section 9.2). Ce n'était pas un gros problème pour le premier client d'AO, le protocole BGP : on met rarement des routeurs BGP derrière du NAT. Mais cette limite est gênante pour généraliser AO à d'autres utilisations, sans compter les futures améliorations de TCP, par exemple le multipath du RFC 6824, où la même connexion TCP utilise plusieurs adresses IP.

Donc, la nouvelle option se nomme TCP-AO-NAT et consiste (section 4 de notre RFC) à ajouter au MKT (Master Key Tuple, cf. RFC 5925, section 3.1) deux booléens, localNAT et remoteNAT indiquant si un routeur NAT est présent en local ou en distant. Si localNAT est vrai, AO va mettre à zéro l'adresse IP source et le port source avant de calculer les clés. Si c'est remoteNAT qui est vrai, ce sera l'adresse et le port de destination qu'on ignorera.

Le MKT n'est pas transmis à la machine distante (et n'apparait donc pas dans l'option TCP AO), il est typiquement configuré à la main des deux côtés. La valeur à donner à localNAT et remoteNAT est déterminée manuellement, mais elle peut aussi être découverte par les méthodes habituelles de détection de NAT. Le client situé immédiatement derrière un routeur NAT (par exemple la machine de M. Michu à la maison) va mettre localNAT à 1. Le serveur en face va mettre remoteNAT à 1. Si les deux partenaires sont derrière un NAT (et utilisent une technique comme celle du RFC 5389), les deux booléens peuvent être à 1.

Notez bien qu'AO ne protège que TCP et ne tient pas compte du contenu des paquets. Si un ALG sur le trajet modifie les adresses contenues, mettons, dans une connexion FTP, TCP-AO-NAT n'y pourra rien.

Attention, rappele la section 6 : TCP-AO-NAT revient à ignorer certaines valeurs qui identifient la connexion et donc à diminuer l'entropie. Si localNAT est vrai, on passe d'une source de hasard pour la KDF qui est composée de deux adresses IP, deux ports et deux ISN (l'Initial Sequence Number de TCP) à une seule adresse, un seul port et les deux ISN. Si les deux booléens localNAT et remoteNAT sont vrais, il ne reste plus que les deux ISN comme source d'entropie. Bref, l'extension normalisée dans ce RFC diminue la sécurité. Toutefois, comme les ports ne sont pas toujours très aléatoires (malgré le RFC 6056) et les adresses encore moins, l'essentiel de l'entropie venait des deux ISN, de toute façon.


Téléchargez le RFC 6978


L'article seul

RFC 6975: Signaling Cryptographic Algorithm Understanding in DNSSEC

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : S. Crocker (Shinkuro Inc.), S. Rose (NIST)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsext
Première rédaction de cet article le 4 juillet 2013


Le système d'authentification du DNS DNSSEC repose sur la signature cryptographique des enregistrements DNS. Cette signature peut se faire par des algorithmes différents. Comment savoir si tel algorithme, récemment spécifié, est désormais d'un usage fréquent ou pas chez les résolveurs validants ? Ce nouveau RFC propose que le résolveur indique, dans sa requête DNS, la liste des algorithmes qu'il comprend. Cela permettra, dans le futur, de mesurer objectivement l'état du déploiement de tel ou tel algorithme.

L'algorithme utilisé dans une signature DNSSEC apparait dans l'enregistrement RRSIG sous forme d'un octet dont la signification est stockée dans un registre IANA. Ainsi, dans cette signature de .fr :

% dig +dnssec SOA fr.
...
;; ANSWER SECTION:
fr.			172800	IN	SOA	nsmaster.nic.fr. hostmaster.nic.fr. 2222283656 3600 1800 3600000 5400
fr.			172800	IN	RRSIG	SOA 8 1 172800 20130814151003 20130615141003 62646 fr. FSSGO0iZ6OBoSUE12Q/NYOU2f3AMNbOf/b4FoC48F8f5gDfSNpJStZF7 zGsN51+zFE3FCucNDw4cQMY8YqBeu6BN5IG4StqAjEp+3FqLYSzyUu4s tZY8GnLa9ZzJCTf6dGT0CE2JbEzc705hc6X6I7DDxqwrzzpj23F/Rg9 PEk=
...

La signature est faite avec l'algorithme 8, RSA + SHA-256. Dans le cas de ecdsa.isc.org :

% dig +dnssec SOA ecdsa.isc.org
...
;; ANSWER SECTION:
ecdsa.isc.org.		3600	IN	SOA	ns-int.isc.org. hostmaster.isc.org. 2013052903 7200 3600 604800 3600
ecdsa.isc.org.		3600	IN	RRSIG	SOA 14 3 3600 20130712033157 20130612023157 30631 ecdsa.isc.org. o+Q1WDDeiCM3z2b793Ni/FtMT223gJ/1Lr+RWOgPJLVxB+AlLKyKvLOs vWRBqUjwYeKE4Dx/ZUSIx8eVzOUt5g6HvBuGaYX/camsYn9ocuTp6J+w J2Fn69Qi6/WbhAa4
...

Elle est fait avec 14, ECDSA avec SHA-384. On trouve également des numéros identifiant un algorithme, celui de condensation cryptographique, dans les enregistrements DS et un autre dans NSEC3 (les valeurs possibles étant dans un autre registre IANA).

Actuellement, les serveurs faisant autorité pour une zone ne savent pas quels algorithmes sont compris par les résolveurs qui les interrogent. Le serveur qui fait autorité envoie toutes les signatures qu'il connait et le résolveur se débrouille. Reprenons le cas de .fr, signé avec RSA. Pourrait-on passer à ECDSA, normalisé dans le RFC 6605, et qui a l'avantage de fournir des clés et des signatures plus courtes ? Le problème est qu'ECDSA dans DNSSEC est très récent et qu'on pense que peu de résolveurs sont capables de valider avec ECDSA. Mais quel pourcentage exactement ? Et, avec le temps, ce pourcentage augmentera. Comment saura-t-on qu'on est arrivé au point où la grande majorité des résolveurs parlent ECDSA ? Si ce nouveau RFC 6975 est déployé, il fournira un moyen de répondre à ces questions.

Le principe est d'utiliser trois nouvelles options EDNS pour signaler les algorithmes connus. Le résolveur mettra ces options dans la requête et le serveur faisant autorité pourra les examiner pour connaître les capacités de ses clients (notez bien que c'est uniquement à des fins d'information : le serveur ne doit pas modifier sa réponse en fonction de ces options). EDNS est normalisé dans le RFC 6891 et l'enregistrement OPT qu'il ajoute contient zéro, une ou plusieurs options (la liste des options possibles est dans un registre IANA). Les trois options ajoutées sont (section 2 de notre RFC) :

  • DAU (code 5) : DNSSEC Algorithm Understood indique quels algorithmes de signature sont acceptés,
  • DHU (code 6) : DS Hash Understood indique quels algorithmes de condensation sont acceptés par le résolveur pour les enregistrements DS,
  • N3U (code 7) : NSEC3 Hash Understood donne la même information pour la condensation dans les enregistrements NSEC3.

L'encodage d'une option EDNS se fait en trois champs, le code sur deux octets (5, 6 ou 7 ici), la longueur des données sur deux octets et les données. Ici, les données consistent en une liste d'algorithmes, un octet pour chacun, dans un ordre quelconque (l'ordre n'exprime pas une préférence). Par exemple, un résolveur validant qui accepte RSA-SHA1, RSA-SHA256 et ECDSA-SHA384 encodera un DAU avec les octets {5, 0, 3, 5, 8, 14}. En pratique, le RFC estime que les trois options toutes ensemble devraient prendre de 22 à 32 octets (en comptant 6 à 10 algorithmes de signature, plus quelques uns pour la condensation).

Bon, et une fois le format défini, on s'en sert comment ? Pour les clients (les résolveurs), c'est en sections 3 et 4 du RFC. Si le client valide, il ajoute une, deux ou trois des nouvelles options dans sa requête. Sinon, il ne doit pas les utiliser.

Si le résolveur valide et qu'il reçoit une requête ayant déjà une de ces options, il doit ajouter ses propres algorithmes. La liste finale sera donc l'union des deux. Un simple relais (forwarder) qui ne valide pas mais qui reçoit une requête ayant une de ces options, doit passer l'option telle quelle car ce qui compte, ce sont les capacités du résolveur qui fera la validation DNSSEC.

Et le serveur faisant autorité ? C'est en section 5. Le point important est qu'il ne doit rien faire. Il suit le même algorithme que d'habitude et, par exemple, il envoie les mêmes signatures quels que soient les algorithmes compris par l'émetteur. Les trois nouvelles options sont là pour information uniquement. D'autres part, les trois options DAU, DHU et N3U sont uniquement dans les requêtes. Le serveur faisant autorité n'en met pas dans les réponses.

Revenons aux administrateurs d'une zone qui voudraient mesurer le déploiement d'un nouvel algorithme cryptographique. Que faire si les clients n'envoient pas cette option ? La section 6 conseille de les considérer comme du vieux logiciel, n'ayant pas les nouvelles options, ni les nouveaux algorithmes. C'est un peu court, à mon avis, car on peut aussi imaginer qu'il y aura des résolveurs récents qui n'enverront pas cette option, peut-être par souci de discrétion (ce point est également couvert dans la section 7, consacrée aux risques de sécurité).

Il ne semble pas exister beaucoup de mises en œuvre de ce RFC. Par exemple, Wireshark, au moment de la publication du RFC, ne savait pas décoder ces options et affichait juste :


    Additional records
        <Root>: type OPT
            Name: <Root>
            Type: OPT (EDNS0 option)
            UDP payload size: 1200
            Higher bits in extended RCODE: 0x0
            EDNS0 version: 0
            Z: 0x0
            Data length: 8
            Data

Depuis r50840, Wireshark a le code nécessaire et on n'a plus qu'à patienter que cela arrive dans une version officielle.

L'examen des requêtes envoyées à un gros serveur de noms ne montre actuellement pratiquement pas d'utilisation de cette option.

Trois ans après la publication du RFC, une discussion lors d'une réunion OARC semblait indiquer qu'il n'avait connu aucun déploiement et devait être considéré comme un échec.


Téléchargez le RFC 6975


L'article seul

RFC 6973: Privacy Considerations for Internet Protocols

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : A. Cooper (CDT), H. Tschofenig (Nokia Siemens Networks), B. Aboba (Microsoft Corporation), J. Peterson (NeuStar), J. Morris, M. Hansen (ULD Kiel), R. Smith (Janet)
Pour information
Première rédaction de cet article le 25 juillet 2013


La question de la vie privée est désormais une question de première importance sur l'Internet. La sortie de ce RFC en plein scandale PRISM est une coïncidence mais elle tombe bien. Pendant longtemps, la vie privée avait pourtant été plutôt négligée par les ingénieurs et cette négligence se retrouvait dans les normes techniques, par exemple les RFC, qui ne contenaient pas grand'chose sur la question. Désormais, l'importance du problème est reconnue à l'IETF et ce nouveau RFC vise à expliquer à tous les auteurs de RFC ce qu'il faut connaître de la vie privée et de sa protection, lorsqu'on conçoit un protocole réseau.

Ce n'est donc pas un texte général sur la vie privée (il en existe déjà beaucoup) même s'il explique les principes de base (le membre typique de l'IETF peut être très ignorant à ce sujet). Son objectif est de faire en sorte que les protocoles de la famille TCP/IP prennent en compte les problèmes de vie privée dès leur conception. Cela a été un long chemin. Peu de RFC traitaient explicitement cet aspect (une exception intéressante est le RFC 4941). Mais, petit à petit, entre autre grâce au travail d'Alissa Cooper, une des auteures de ce document, l'IETF est passé de « bof, c'est de la politique, ça ne nous concerne pas, et d'ailleurs la technique est neutre » à un atelier sur la protection de la vie privée (le compte-rendu figure dans le RFC 6462) puis à ce RFC 6973 qui dit en substance que tout nouveau protocole de la famille TCP/IP devrait avoir, lors de sa conception, une réflexion sur les risques qu'il pose pour la vie privée et les moyens de les limiter. S'il reste encore à l'IETF quelques partisans du « on s'en fiche, que toutes les données soient accessibles et que tout le monde soit à poil », ils se font nettement moins entendre désormais. Sans aller jusqu'à imposer une section Privacy considerations dans chaque RFC (sur le modèle de l'obligatoire section Security considerations, cf. RFC 3552), ce RFC l'encourage et aide à sa rédaction.

Le problème n'est pas trivial : la vie privée est quelque chose de complexe. Et tout le monde n'a pas la même opinion sur l'importance de son respect. Sans compter que le cadre légal est très différent d'un pays à l'autre, alors que les RFC sont censés avoir une portée mondiale. Si certains RFC ne semblent pas poser de problème de vie privée (notre RFC cite le RFC 6716...) d'autres sont ou seront entièrement consacrés à ce sujet (RFC 3325) et d'autres nécessiteront un paragraphe ou une section dédiée.

La section 2 détaille les responsabilités des concepteurs de protocoles Internet. Ces protocoles sont souvent utilisés dans une grande variété de cas, parfois non prévus lors de leur conception originelle. Bref, on ne peut pas demander au rédacteur du RFC sur un nouveau protocole de prévoir tous les usages et il y a donc des limites à l'analyse qu'il peut faire sur les conséquences de « son » protocole sur la vie privée. D'autre part, une grande partie, peut-être la majorité des problèmes de vie privée, prennent naissance dans un comportement de l'utilisateur, mal ou peu guidé par des mauvaises interfaces utilisateur. La conception de ces interfaces est typiquement hors-sujet pour l'IETF, qui ne se préoccupe que de protocoles.

Un bon exemple est fourni par HTTP (RFC 7230). Quand on voit la variété des usages de HTTP aujourd'hui, de l'accès à des pages Web statiques à l'échange de données médicales, on se dit qu'une analyse des risques qu'il pose pour la vie privée, faite à l'époque de son développement, aurait été bien limitée.

Le RFC commence vraiment avec la section 3, sur la terminologie. Section bien nécessaire pour ce sujet, où le vocabulaire utilisé est souvent trop flou. Un RFC précédent sur la terminologie de la sécurité avait été le RFC 4949 mais il parlait peu de vie privée. Donc, quelques termes nouveaux (d'autres sont dans le RFC) :

  • Assistant (enabler) : une entité qui n'est pas dans le chemin direct de communication mais qui facilite la communication (et peut donc apprendre des choses). Par exemple, un serveur DNS faisant autorité va être un assistant pour une requête HTTP.
  • Intermédiaire (intermediary) : une entité située, elle, sur le chemin de communication, par exemple un relais SIP.
  • Observateur (observer) : une entité qui est techniquement en mesure d'observer le trafic, du fait de sa position dans le réseau. L'observateur est une entité légitime du réseau, dont l'existence est connue et au moins tacitement autorisée. Par exemple, un serveur de courrier électronique qui relaie les messages est un observateur pour les courriers. L'observateur est, par exemple, un intermédiaire ou un assistant (définitions précédentes) mais il faut se rappeler que les deux extrémités de la communication sont aussi des observateurs..
  • Attaquant (attacker) : toute entité qui va essayer de violer la vie privée, de manière non autorisée.
  • Écoutant (eavesdropper) : un cas particulier d'attaquant, purement passif (il ne fait qu'écouter). Contrairement à l'observateur, il n'est pas autorisé.
  • Corrélation (correlation) : combiner plusieurs informations pour en tirer une information plus complète.
  • Empreinte numérique (fingerprint) : un ensemble de caractéristiques d'une machine ou d'un programme qui permettent de l'identifier. Par exemple, le champ User-Agent:, la liste de polices et quelques autres informations permettent de prendre l'empreinte du navigateur (cf. le Panopticlick).
  • Point intéressant (ou IOI pour Item Of Interest) : toute information que l'attaquant peut avoir envie de connaître. Ainsi, le contenu de la communication est un point intéressant mais aussi, souvent, le seul fait qu'une communication ait lieu entre Alice et Bob est un point intéressant, même si on ne sait pas ce qu'ils se sont dit.
  • Donnée personnelle (personal data) : donnée qui permet d'identifier un individu physique. Ce concept est à la base de beaucoup de lois dans l'Union européenne comme la loi Informatique & Libertés en France. Contrairement à ce que croient beaucoup de gens, une donnée personnelle ne contient pas forcément le nom de l'individu. Par exemple, dans beaucoup de cas, une adresse IP est une donnée personnelle.
  • Analyse de trafic (traffic analysis) : déduire de l'information uniquement à partir de métadonnées sur les communications (qui appelle qui, quand, etc) sans avoir accès au contenu des communications. Par exemple, la simple augmentation du trafic radio d'une armée ennemie peut permettre de prévoir une action de sa part, même si le contenu des communications est chiffré et donc incompréhensible.
  • Anonyme (anonymous) : alors là, c'est un des termes les plus utilisés et les moins bien compris quand on parle de vie privée. On est anonyme si on ne peut pas être distingué des autres membres de l'ensemble d'anonymat (anonymity set). L'anonymat n'est jamais absolu, car on diffuse toujours des informations, l'important est que l'ensemble d'anonymat autour de ces informations soit suffisamment large.
  • Identité (identity) : un ensemble d'attributs qui identifient un individu. On a en général plusieurs identités, selon le contexte. (Voir l'excellent livre d'Olivier Iteanu.)
  • Aujourd'hui, les informations d'identité sur l'Internet sont souvent stockés chez des fournisseurs d'identité spécialisés (si vous vous connectez à un service sur le Web avec votre compte Facebook, alors Facebook est votre fournisseur d'identité). Elles sont ensuite utilisées par des relying parties (le site Web où on se connecte), qui ont donc sous-traité la gestion de l'identité à un tiers.
  • Nom officiel (official name) : celui qui apparait sur les papiers d'identité étatiques. Il n'est en général pas unique. Notez que l'identité, définie plus haut, n'inclut pas forcément le nom officiel (mon identité sur un canal IRC donné peut être mon pseudo canari95). Notez aussi que l'anonymat n'est pas uniquement le fait de garder son nom officiel secret. Cela peut être aussi de vouloir empêcher le rapprochement de deux de ses identités.
  • Nom personnel (personal name) : nom par lequel on désigne un individu. Cela peut être le nom officiel mais pas toujours. Du point de vue technique, un logiciel ne sait pas en général s'il manipule des noms personnels ou des noms officiels.
  • Pseudonyme (pseudonym) : un nom qu'on va utiliser pour ne pas divulguer un nom personnel.

Par exemple, avec IP, le routeur est un intermédiaire, et peut être un observateur (s'il est équipé pour cela, disons que si le routeur est une machine Unix, il devient un observateur dès qu'il lance tcpdump). Quelqu'un qui s'est branché sur le câble sans autorisation est un écoutant.

À noter que l'analyse de sécurité du RFC 3552 supposait que les deux extrémités de la communication étaient sûres et que seuls les intermédiaires représentaient un danger. En matière de vie privée, ce n'est évidemment pas le cas (section 4 de notre RFC). Comme l'a montré l'affaire PRISM, ou comme le montrent les pratiques des gros silos commerciaux du Web 2.0 comme Facebook, le danger est souvent chez l'une des parties en train de communiquer, pas chez un tiers...

Et quelles sont exactement les menaces qui pèsent sur la vie privée ? La section 5 les détaille, suivant en partie le livre de Solove et la recommandation du Conseil de l'Europe. D'abord, leurs conséquences. Les atteintes à la vie privée peuvent provoquer de la gêne mais aussi une perte de dignité, ou des pertes financières. Dans des cas extrêmes (violence conjugale, par exemple), ces atteintes peuvent mettre la vie des victimes en danger. D'autre part, même s'il n'y a pas eu accès à des informations privées, le seul fait d'être sous surveillance peut mettre très mal à l'aise, voir créer un sentiment d'angoisse. Il peut aussi entraîner un changement de comportement (on hésitera à commettre un acte légal, de peur des conséquences s'il était révélé) pouvant aller jusqu'à l'auto-censure. La vie privée est donc une affaire sérieuse, pas un simple détail.

Première attaque contre la vie privée envisagée, la surveillance des communications. Le RFC rappelle qu'elle n'est pas limitée au cas où l'attaquant a accès au contenu des communications. La seule analyse de trafic peut déjà en révéler beaucoup. Le chiffrement n'est pas une protection parfaite : le type de trafic reste visible, via des indicateurs comme la taille des paquets ou leur fréquence. Pour déjouer sérieusement la surveillance, il faudrait des protocoles avec des tailles de paquets variables, n'ayant pas de chaîne de bits prévisibles à un endroit fixe dans le paquet, etc. Pour sérieusement gêner l'analyse de trafic, il faut des systèmes comme Tor. Parmi les entitées présentées plus haut, aussi bien les écoutants que les observateurs peuvent avoir une activité de surveillance.

Une fois les messages arrivés à bon port, tout n'est pas terminé. Les données stockées à destination peuvent faire l'objet d'une compromission, si le serveur qui les stocke n'est pas suffisamment protégé et peut être piraté. Sans compter le cas, traité plus loin, où le serveur de destination est lui-même un attaquant. Ceci dit, ces problèmes ne sont pas du ressort de l'IETF qui s'occupe normalement uniquement des réseaux.

Les risques ci-dessus sont une combinaison de risques pour la vie privée avec les risques plus généraux de sécurité. Mais il y a aussi des risques très spécifiques à la question de la vie privée. Par exemple, la corrélation, qui permet d'acquérir des informations normalement privées en reliant des données qui, séparément, semblaient inoffensives. Par exemple, si des identificateurs stables sont utilisés, les protocoles réseaux facilitent la corrélation. Une adresse IP stable sur le long terme présente un certain nombre d'avantages techniques mais est aussi un danger pour la vie privée (cf. RFC 4941). Autre exemple, le protocole TLS permet de reprendre une session cryptographique existante, pour gagner du temps et éviter de recommencer la négociation de tous les paramètres (cela peut se faire côté serveur, RFC 5246 ou côté client, RFC 5077). Mais comme cette reprise de session se fait avant la négociation de ces paramètres de cryptographie, elle a lieu en clair. Un écoutant peut donc voir que le second client TLS qu'il écoute est en fait le même que le premier, s'il utilise cette fonction.

Autre attaque contre la vie privée, celle passant par l'identification. Savoir que la machine 192.0.2.67 accède au site Web du gouvernement, c'est une chose. Pouvoir accéder à des informations sur la personne qui utilise cette machine, c'est bien mieux, pour l'attaquant. Cela peut se faire facilement avec les protocoles qui identifient une personne (une adresse SIP ou XMPP par exemple) mais aussi de manière indirecte même si le protocole permet l'anonymat. Prenons par exemple un site Web qui n'identifie pas ses utilisateurs. Aucun risque qu'un attaquant qui l'observe retrouve qui a accédé à la page /page-sensible.html, non ? Sauf que, si le même attaquant peut écouter le trafic d'un autre site Web qui authentifie ses utilisateurs, il peut faire une corrélation (via, par exemple, le champ User-Agent:) et ainsi identifier l'utilisateur.

Dans beaucoup de cas, l'utilisateur sait qu'on récolte des données personnelles sur lui. Si je me crée un compte sur amazon.com, il est clair qu'Amazon va savoir des choses sur moi, par exemple mon adresse postale pour me livrer les produits achetés. Il peut aussi y avoir des usages secondaires, des cas où le détenteur des données s'en sert pour autre chose que ce qu'il a annoncé. L'usage secondaire est techniquement indétectable et, comme cela se passe en dehors de la communication standardisée par l'IETF, notre RFC estime que ce problème, si grave qu'il soit en pratique, n'est pas de la responsabilité de l'IETF.

Encore plus sérieux, la révélation de données à des tiers. Comme il est trivial de copier des données numériques, il est techniquement impossible de savoir si les données personnelles qu'on a accepté de confier à l'entreprise X ne vont pas être copiées chez son partenaire Y. Là encore, c'est en dehors de la sphère IETF mais c'est quand même une des menaces les plus sérieuses. Le système PRISM est un exemple d'une telle copie, où les données qu'on avait accepté de confier à Google ou Facebook sont accessibles à la NSA. (Cet exemple n'est pas mentionné dans ce RFC qui, pour ne vexer personne et surtout pas les grosses entreprises états-uniennes qui contribuent beaucoup à l'IETF, passe rapidement sur ce risque, pourtant l'un des plus fréquents.)

Certains protocoles IETF permettent à l'utilisateur d'indiquer ses préférences en matière de protection de la vie privée, et notamment d'interdire la révélation de ces données à un tiers. C'est le cas par exemple du système décrit dans le RFC 6280. Évidemment, il n'existe aucun moyen technique de savoir si ces préférences sont respectées...

Notez aussi que la révélation peut être accidentelle : certains administrateurs systèmes sont assez négligents avec les données personnelles (ou bien ne se rendent pas compte qu'elles sont personnelles) et les laissent parfois accessibles par accident.

Dernière menace envisagée, l'exclusion. C'est le fait d'interdire à l'utilisateur de savoir ce qu'on sait sur lui. (La loi Informatique & Libertés appelle cela le droit d'accès aux données.) C'est une attaque tentante pour les gens qui veulent utiliser vos données personnelles. Cela limite le contrôle que l'individu peut faire.

Maintenant, assez déprimé sur les menaces, place aux solutions. La section 6 envisage les différentes méthodes connues pour limiter les dégâts. Améliorer la protection de la vie privée dans les protocoles réseau n'est pas facile car une protection sérieuse dépend de très nombreux facteurs, qui ne relèvent pas de la seule responsabilité des protocoles (ni même des logiciels). Je pense personnellement (et le RFC a tort de ne pas le rappeler) que le problème requiert avant tout des solutions politiques et juridiques. Mais ce RFC 6973 est un RFC, pas une loi, et se focalise donc surtout sur les aspects techniques : lorsqu'on est membre de l'IETF, que peut-on faire de concret aujourd'hui ?

Première chose évidemment, récolter moins de données (data minimization ou No data, no privacy problem). Les protocoles devraient être conçues de façon à ne transmettre que les données strictement nécessaires à l'accomplissemnt de la tâche. Les choix vont être délicats car les informations envoyées, même pas strictement nécessaires, peuvent avoir une utilité (le User-Agent: en HTTP, énorme risque pour la vie privée, mais si rigolo pour faire des statistiques). Le RFC se focalise donc surtout sur un point, l'identifiabilité. Il faut tout faire pour éviter qu'on identifie un utilisateur. Cela peut passer par l'absence d'identificateurs dans le protocole (ce que permet HTTP mais pas SMTP) ou par l'utilisation d'identificateurs de durée de vie limitée, choisis aléatoirement et changés régulièrement (les adresses IP temporaires du RFC 4941).

La meilleure protection de la vie privée est quand l'utilisateur peut rester anonyme. Cela implique qu'il existe un ensemble d'anonymat assez vaste pour qu'on soit réellement protégé. Un User-Agent: HTTP à lui seul vous place dans un ensemble d'anonymat qui peut être très réduit (j'ai vu une fois dans mes journaux un User-Agent: qui proclamait que le navigateur tournait sur OpenBSD, ce qui diminue considérablement le nombre de « suspects »). Par exemple, pour SIP, le RFC 3325 permet de choisir une adresse anonyme (notez que, comme souvent en matière d'anonymat, l'information sur votre identité peut venir d'ailleurs comme le champ Via:).

Proche de la notion d'anonymat, celle de pseudonymat. Dans ce cas, on a une identité stable et réutilisable, elle n'est simplement pas liée aux identités qu'on veut protéger (comme son nom officiel, par exemple). Dans l'exemple SIP ci-dessus, l'adresse utilisée est toujours anonymous@anonymous.invalid et est la même pour tout le monde. C'est de l'anonymat. Si par contre je me crée un compte aucbbf51n chez un fournisseur SIP example.net qui ne garde pas trace de mes informations personnelles, mon adresse aucbbf51n@example.net est un pseudonyme. Un pseudonyme a l'avantage, par rapport à l'anonymat, de permettre de construire une réputation.

Beaucoup d'identificateurs sur l'Internet vont être des pseudonymes puisque les protocoles Internet n'obligent pas (et heureusement, comparez avec ce que réclame l'UIT qui voudrait obliger à utiliser des « vraies » identités) à se servir d'un nom officiel. Ainsi, mon adresse de courrier pour ce blog est stephane+blog@bortzmeyer.org mais vous ne savez pas si c'est mon nom officiel ou un pseudonyme. Parfois, tout de même, des protocoles ou formats Internet transportent des identités qui peuvent être des noms officiels. Un exemple typique est le format vCard du RFC 6350.

Les pseudonymes ne sont pas parfaits, deux pseudonymes utilisés dans des contextes différents peuvent parfois être reliés par exemple via une information que vous communiquez. Si vous publiez sur l'informatique avec une adresse professionnelle monsieursérieux@example.com et que vous tenez un blog sur la sexualité des hamsters avec l'adresse lol-hamster218@example.net, ne faites pas les mêmes fautes d'orthographe, n'utilisez pas les mêmes tournures de phrase dans les deux contextes ou bien vous serez démasqué. Un exemple de pseudonymes impossibles à lier est fourni par Romain Gary et Émile Ajar : étant donné la différence des styles, personne n'avait jamais suspecté que c'était le même écrivain.

Un problème supplémentaire survient fréquemment de nos jours : beaucoup de services sur l'Internet ne font plus la gestion de l'identité eux-mêmes mais la délèguent à un fournisseur d'identité, utilisant des techniques comme OpenID ou des protocoles privés. Selon le protocole utilisé, les risques pour la vie privée peuvent être plus ou moins grands. Par exemple, si le service voulant authentifier (RP pour relying party, celui qui compte sur le fournisseur d'identité) communique directement avec le fournisseur d'identité (au lieu que tout passe via le client final), le fournisseur d'identité peut apprendre à quels services se connectent ses clients. Autre exemple, le fournisseur d'identité ne devrait pas envoyer au RP la totalité des informations dont il dispose sur un client.

Et, pour clore cette section 6 sur les solutions techniques améliorant la protection de la vie privée, le RFC note que le protocole doit fournir des mécanismes permettant à l'utilisateur de contrôler ses propres données (savoir ce que les autres savent sur lui, et pouvoir exprimer des préférences).

Plus pratique, la section 7 transforme ces bons conseils techniques en une liste de choses à vérifier lorsqu'on conçoit un nouveau protocole réseau. Une fois qu'on a développé un modèle du nouveau protocole (RFC 4101), lire cette liste et se poser les questions qu'elle contient devrait aider à limiter les risques pour la vie privée.

D'abord, minimiser la quantité de données distribuées. La meilleure protection des données est quand il n'y a pas de données. Quels sont les identificateurs utilisés par le protocole ? Est-ce qu'ils permettent la corrélation entre des sessions différentes (c'est souvent le cas s'ils sont stables sur le long terme) ? Ne pourrait-on pas limiter leur utilisation ? Leur mettre une durée de vie limitée ? Permettre aux utilisateurs d'en changer facilement ? Ensuite les données qui ne sont pas officiellement des identificateurs ? Qu'est ce qui est échangé entre les parties qui communiquent ? N'est-ce pas trop de données ? Ces données ne permettraient-elles pas de retrouver les identificateurs (pensez au Panopticlick) ? À qui sont envoyés ces identificateurs et ces données (rappelez-vous qu'il y a typiquement plus que deux parties impliquées dans une communication) ? Par exemple, lors d'une connexion HTTP à http://www.example.com/, la requête DNS est envoyéee à des assistants (cf. le vocabulaire au début), les serveurs de la racine et ceux de .com. La racine apprend donc qu'on se connecte à www.example.com. Et le risque d'empreinte numérique ? Par exemple, si le protocole permet N opérations au début d'une connexion, sans spécifier leur ordre, un observateur peut apprendre quel logiciel vous utilisez en regardant l'ordre choisi. Et enfin est-ce que le protocole permet, voire impose, la conservation de données ou d'identificateurs sur le long terme, en dehors des sessions de communication ?

Ça, c'était pour minimiser les données. Pour le contrôle par l'utilisateur, les questions à se poser sont : quels sont les mécanismes dans le protocole pour contrôler quelles données on diffuse et à qui ? Là encore, il ne faut pas penser qu'au destinataire mais aussi à tous les intermédiaires possibles. Un exemple, HTTP n'impose pas des en-têtes indiscrets comme User-Agent: et Referrer: et cela permet à certains navigateurs ou relais de les supprimer.

Les attaques contre la vie privée ne seront pas menées que par les participants légitimes à une communication. On aura aussi des tiers qui essaieront d'accéder à une information qu'ils ne sont pas censés avoir. Le protocole doit donc prendre en compte la possibilité de surveillance. Qu'est-ce qui est prévu contre l'écoute ? En général, c'est l'utilisation du chiffrement et le RFC contient donc une phrase « utilisez TLS si vous ne voulez pas être écouté ». Mais cela n'empêche pas l'analyse de trafic. Le protocole a-t-il des mécanismes qui facilitent ou au contraire compliquent cette analyse ? Par exemple, avec SSH, on voit facilement si on a affaire à un transfert de fichiers ou à une session interactive, par la quantité de données qui passe et leur cadencement. Lors d'un transfert de fichiers, on a beaucoup d'octets dans un sens et peu dans l'autre, les accusés de réception. Lors d'une connexion à un shell, on a peu d'octets de l'utilisateur vers le shell et une quantité moyenne (les réponses) en sens inverse. Le chiffrement ne dissimule pas cela. SSH a un mécanisme de remplissage de la communication avec des données bidon, pour brouiller les pistes mais je n'ai pas l'impression qu'OpenSSH l'utilise.

Toujours en sécurité classique, comment se comporte le protocole en cas de compromission des données stockées ? Ou contre une attaque active ?

Souvent, les préférences de protection de la vie privée sont réglables. Mais la plupart des utilisateurs ne modifieront jamais le réglage. Le RFC demande donc qu'on prête attention aux réglages par défaut. En l'absence d'intervention explicite, est-on protégé ou, au contraire, faut-il activer cette protection délibérement ? Par exemple, pour le cas des adresses IP temporaires, le RFC 4941 demandait qu'elles ne soient pas utilisées par défaut alors que le RFC 6724 a demandé le contraire. Écrit quatre ans après, à un moment où les préoccupations de protection de la vie privée sont devenues plus importantes, ce RFC 6724 avait des priorités différentes.

D'ailleurs, la fin de cette section 7 rappelle que, comme Schneier aime le répéter, la sécurité est toujours un compromis. Elle prend du temps, ralentit le réseau, complique les choses (pour les programeurs et pour les utilisateurs), bref a un coût. La protection de la vie privée n'échappe pas à cette nécessité de chercher un compromis.

Pour clore ce RFC, la section 8 fournit un exemple complet d'analyse de sécurité d'un service donné. Les auteurs ont choisi la difficulté, car cette analyse porte sur un service particulièrement indiscret et intrusif, le service de présence (faire connaître à l'extérieur si on est disponible ou pas, par exemple pour être contacté par messagerie instantanée). Ce service permet d'illustrer toute la palette des questions soulevées par la protection de la vie privée. Présentée dans le RFC 2778, la présence (« je suis dispo », « je déjeune », « je suis en réunion ») est un service très dynamique, nécessitant de nombreuses mises à jour. Ses implications pour la vie privée sont évidentes et, dès le début, l'IETF avait prévu un contrôle des utilisateurs sur cette information (RFC 3859). Les protocoles qui utilisent un système de présence comme SIMPLE (RFC 6914) ou XMPP (RFC 3922) s'appuient sur ce contrôle.

Voici la gestion de la présence par l'utilisateur dans le client de messagerie instantanée Pidgin : pidgin-presence.png

Dans l'architecture standard, il y a un tiers, un assistant, le serveur de présence, qui reçoit les informations des clients et les transmet aux lecteurs autorisés. Ce tiers est nécessaire pour les cas où la/les machine(s) du client soient toutes éteintes ou injoignables. Il sert également à agréger de l'information envoyée par les différentes machines de l'utilisateur (son ordinateur peut être éteint mais l'utilisateur être toujours joignable via son smartphone). Mais il complique évidemment beaucoup la sécurité puisqu'il va être au courant de beaucoup de choses. Bien sûr, le serveur ne distribue l'information qu'aux lecteurs autorisés. Mais il n'y a pas de protection technique : il faut faire une confiance totale au serveur, confiance en son honnêteté et ses bonnes pratiques de sécurité. On pirate un serveur de présence et on peut suivre les gens à la trace. Le serveur oublie de rendre TLS obligatoire et les écoutants peuvent tout apprendre (et le client du serveur de présence n'a aucun moyen de vérifier si TLS est activé ou pas). Encore pire, c'est le serveur de présence qui authentifie les lecteurs, pas le client final. L'anonymat n'est ici pas une solution puisque le but d'un service de présence est justement d'obtenir des informations sur des personnes identifiées (« quelqu'un est allé déjeuner » n'est pas une information intéressante).

Pour compléter le tableau, d'autres informations que la présence sont souvent transmises, par exemple les capacités du logiciel utilisé (accepte t-il les appels vidéo, par exemple). Elles peuvent permettre d'identifier l'appareil utilisé. En outre, les extensions ultérieures au service de présence ont permis de publier également la localisation physique. Un groupe de travail a été créé pour travailler sur la protection de la vie privée dans le cas où on distribue cette information, le groupe GEOPRIV, dont le premier RFC fut le RFC 4079 (mais il y en a d'autres).

Avec tellement d'information, l'analyse de sécurité du service de présence doit évidemment commencer par se demander si le jeu en vaut la chandelle. Déjà, on pourrait utiliser une autre architecture, plus pair à pair, où les utilisateurs se préviennent directement de leur présence. Il existe un format standard pour transporter cette information, PIDF (Presence Information Data Format), qu'on peut chiffrer pour empêcher toute écoute. Mais cette solution ne semble pas réaliste aux auteurs du RFC : elle ne fonctionne pas si la machine de publication est éteinte ou injoignable, chaque machine qui publie doit connaître les clés publiques de tous les abonnés, et enfin elle suscite un trafic important (la présence est très dynamique, avec des changements fréquents). Une variante est l'architecture où le serveur de présence ne sert que de redirecteur : il ne connait pas l'information, mais sait rediriger vers la machine actuelle de chaque personne qui publie de l'information de présence. Le serveur peut ainsi prévenir qu'une personne est injoignable et rediriger vers cette personne dans le cas contraire. Mais cette architecture, comme la précédente, a ses propres problèmes de vie privée, puisqu'elle permet à chaque participant d'apprendre les adresses IP des autres (normalement connues du seul serveur de présence). En outre, ces deux solutions, davantage pair à pair, souffrent du difficile problème de la connexion d'une machine à une autre, lorsqu'une des deux, ou les deux, sont derrière un pare-feu ou un routeur NAT. Avec le serveur de présence, il suffit aux clients d'une connexion sortante, ce qui est bien plus souvent possible.

Bref, cette intermédiaire dangereux qu'est le serveur de présence va être difficile à éliminer. D'où l'approche actuelle, qui repose plutôt sur des préférences quant à la divulgation de l'information, préférences (RFC 4745, RFC 5025 et RFC 6772) qui sont envoyées au serveur de présence, et à qui il faut faire confiance pour les respecter. Le RFC note bien que le succès est très limité : peu de logiciels exploitent cette information. Au moins, on peut documenter leurs limites, ce qui est fait ici.

On a donc là un bel exemple d'un compromis entre la protection de la vie privée (qui justifierait qu'on ne publie jamais rien sur sa présence) et le désir de faciliter la vie des utilisateurs en indiquant à l'avance si un appel a des chances d'aboutir ou pas.

Mon commentaire à une version préliminaire de ce RFC est disponible en ligne (notez la note de cloture du ticket). Globalement, mon regret est que ce document (même après les changements) est très axé sur les risques dus aux tierces parties et parle peu des risques du méchant silo qui stocke les données personnelles, ou sur les risques étatiques type PRISM.

Si vous voulez approfondir ces questions, ce RFC cite trois sources : le « FAIR INFORMATION PRACTICES: A Basic History » de Gellman, les directives de l'OCDE et le « Privacy Indexes: A Survey of Westin’s Studies ».


Téléchargez le RFC 6973


L'article seul

RFC 6972: Problem Statement and Requirements of Peer-to-Peer Streaming Protocol (PPSP)

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : Y. Zhang, N. Zong (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF ppsp
Première rédaction de cet article le 20 juillet 2013


Il existe actuellement des tas de logiciels qui font du streaming (audio ou vidéo) en pair à pair mais toujours en utilisant des protocoles privés et fermés. Cela a des tas de conséquences négatives, notamment sur le plan du choix : l'utilisateur est enfermé dans l'offre d'une compagnie particulière. Il est donc urgent de développer un protocole libre et ouvert de streaming pair à pair et c'est la tâche du groupe de travail PPSP de l'IETF. Son premier RFC, ce RFC 6972, est le cahier des charges du protocole (comme toujours à l'IETF, le travail a commencé bien avant la publication du cahier des charges et des mises en œuvre du protocole PPSP - normalisé dans le RFC 7574 - existent déjà).

Le streaming est un usage essentiel de l'Internet (le RFC cite une étude de Cisco à ce sujet). Dans sa version classique, avec un gros serveur ou une batterie de gros serveurs qui distribuent à des millions de clients, le streaming ne passe pas à l'échelle. Si on en était resté à ce mode de distribution, seule une poignée de très grosses entreprises pourraient héberger du contenu vidéo. Heureusement, il existe une meilleure solution, la distribution en pair à pair où chaque client se transforme en distributeur pour une partie du contenu. Le streaming pair à pair permet à n'importe qui de distribuer de la vidéo sur l'Internet, avec seulement des serveurs ordinaires.

Mais, car il y a un mais, ce streaming pair à pair, aujourd'hui, se fait essentiellement avec des protocoles privés d'une entreprise capitaliste particulière. La section 3 décrit les problèmes que cela pose. D'abord, sur le plan technique, cela interdit de développer des mécanismes de cache communs, le cache devant connaître le protocole utilisé (imaginez les caches Web si tout le monde ne parlait pas HTTP). Même chose pour les CDN qui ne peuvent pas être exploités facilement pour aider ce streaming puisqu'ils ne peuvent pas connaître tous les protocoles utilisés.

Enfin, les protocoles existants ne sont pas forcément bien adaptés aux mobiles qui sont pourtant une bonne partie des clients. Il y a eu des recherches à ce sujet (cf. J. Peltotalo et autres, « A real-time Peer-to-Peer streaming system for mobile networking environment » en 2009) mais qui ne se retrouvent pas forcément dans les protocoles existants. PPSP va donc devoir gérer :

  • Le fait que le mobile, contrairement au poste fixe typique, n'est pas allumé et connecté en permanence,
  • Le fait que le mobile ait une batterie de capacité limitée (les protocoles actuels n'indiquent pas si le pair est presque à sec...),
  • La capacité limitée du réseau avec le mobile : certains protocoles sont très bavards, s'envoyant plein d'informations même quand rien n'a changé,
  • L'espace limité sur le mobile, qui rend l'installation de N applications différentes pour la même tâche (le streaming) problématique.

À noter que la section 3 ignore les problèmes plus politiques comme l'excès de pouvoir que ces protocoles fermés donnent à l'entreprise qui les contrôle, et peut ainsi limiter la liberté des clients.

La section 4 décrit à un haut niveau les missions du protocole de streaming pair-à-pair. Pour modéliser ce protocole, elle reprend largement la terminologie de BitTorrent (la section 2 décrit tout le vocabulaire à connaître mais le RFC ne cite jamais BitTorrent), avec notamment la notion de tracker, le mécanisme (pas forcément une machine, cela peut être une DHT) qui garde trace de tous les pairs servant un contenu donné (ce qu'on nomme l'essaim). Il y a en fait deux protocoles, un entre le pair et le tracker et un entre pairs. Lorsqu'il rejoint un essaim, le pair doit pouvoir trouver les autres pairs (avec le premier protocole) et les contacter (avec le second). Il doit pouvoir connaître les caractéristiques des pairs, pour les choisir astucieusement. Le protocole doit bien sûr être efficace (le streaming vidéo fait passer d'énormes quantités de données) et doit être robuste (par exemple en cas de panne du tracker).

Le protocole pair<->tracker va nécessiter un identifiant unique pour les pairs (peer ID). Il va falloir aussi classer les pairs, par exemple selon le fait qu'ils ont une adresse IP publique ou pas, qu'ils sont en IPv4 ou en IPv6, qu'ils ont des ressources importantes ou pas, etc. Ce sera plutôt un protocole requête/réponse (le pair se connecte, transmet ses infos, et reçoit une liste de pairs).

Le protocole pair<->pair devra se colleter avec les problèmes de l'identification du contenu et de son intégrité (un problème important en pair-à-pair). Le contenu envisagé pour ce problème étant souvent de grande taille, il faudra le découper en morceaux (chunks) et il faudra donc un mécanisme d'identification des morceaux et de leur disponibilité. Ce sera plutôt un protocole de bavardage (échange continu d'information).

Avant d'aborder le cahier des charges précis, le RFC pose une dernière question, quels sont les usages envisagés pour ce nouveau protocole de streaming (section 5) ? Il y a la distribution de vidéo en temps réel, par exemple lors d'un événement (cela ressemble fortement à l'usage décrit dans les RFC 6707 et RFC 6770). Il y a aussi la VoD. D'autres usages sont moins évidents à première vue comme la possibilité d'avoir des caches pour le streaming. Même si on est dans une relation client/serveur, un protocole pair-à-pair de streaming permet d'envisager des systèmes de caches automatiques entre le client et le serveur, qui intercepteraient les requêtes et les mémoriseraient pour les futurs utilisateurs. Un exemple proche est l'extension P2Pyoutube du navigateur Opera.

Enfin, le cahier des charges proprement dit. Je ne vais pas reprendre ici toutes les exigences, classées en catégories (REQ : la base, OAM : gestion du protocole, TP : protocole pair<->tracker, PP : protocole pair<->pair) et numérotées. Certaines sont de l'ordre de l'évidence (PPSP.REQ.1 : chaque pair doit avoir un identificateur unique, PPSP.REQ.2 dit la même chose pour l'essaim et PPSP.REQ.4 pour le morceau). D'autres sont toujours bonnes à rappeler (PPSP.OAM.REQ-2 : il doit y avoir des paramètres de configuration, ayant des valeurs par défaut, PPSP.OAM.REQ-7 : on doit pouvoir les changer). Beaucoup sont communes à tout système de distribution de contenu en pair-à-pair et se retrouvent déjà dans BitTorrent. D'autres sont plus spécifiques au streaming. Ainsi PPSP.OAM.REQ-4 parle des mécanismes pour atteindre une qualité suffisante pour le flux audio ou vidéo. Cela implique un délai raisonnable. Le RFC dit par exemple qu'une minute de délai pour la retransmission d'un évenement sportif est inacceptable (imaginez le supporter du PSG ayant encore son verre de bière à la main alors que dans les maisons environnantes, tous les autres hurlent déjà « Buuuuuuuuuuuuuuut ! »).

Souci classique à l'IETF, le protocole doit être gérable. Des exigences comme PPSP.OAM.REQ-5 demandent qu'on puisse accéder à l'information nécessaire pour déboguer et/ou optimiser le protocole et PPSP.OAM.REQ-6 ajoute qu'il faut pouvoir tester un pair, sa connectivité, son bon fonctionnement, etc.

De même, les exigences sur le protocole tracker<->pair sont assez standards et évidentes (PPSP.TP.REQ-1 : le pair doit pouvoir obtenir du tracker une liste de pairs potentiels...). Notez quand même une exigence que l'authentification du pair soit possible, pour les essaims fermés (PPSP.TP.REQ-4). Même chose pour le protocole pair<->pair. Notez toutefois PPSP.PP.REQ-3 (obtenir directement du pair, sans passer par le tracker, d'autres pairs, de préférence vérifiés, ajoute PPSP.PP.REQ-5) et PPSP.PP.REQ-8, la possibilité d'obtenir plein d'informations sur les pairs.

Voilà, le cahier des charges est fini. Une faiblesse traditionnelle des systèmes pair-à-pair, la sécurité, fait l'objet d'une section à part, la 7. Elle analyse les risques dus à des pairs ou des trackers malveillants :

  • Attaque par déni de service en envoyant plein de requêtes,
  • Envoi de fausses informations, par exemple de disponibilité d'un morceau,
  • Violation de la vie privée, en transmettant les informations à un tiers,
  • Et d'autres encore.

Cela entraîne l'ajout de quelques exigences supplémentaires, étiquetées SEC pour SECurity. PPSP.SEC.REQ-1 reprend l'exigence déjà mentionnée de pouvoir faire des essaims fermés, avec pairs authentifiés. PPSP.SEC.REQ-2 rappelle qu'il est indispensable d'avoir un mécanisme de contrôle de l'intégrité du contenu, pour empêcher un pair malveillant d'injecter des morceaux incorrects, et PPSP.SEC.REQ-3 appelle au réalisme en demandant que tout mécanisme de sécurité passe bien à l'échelle, on peut avoir des essaims immenses.

Les auteurs annoncent qu'il y a déjà trois mises en œuvre du protocole mais il ne semble pas y avoir beaucoup de documentation à ce sujet. Le protocole correspondant à ce cahier des charges a été normalisé dans le RFC 7574.


Téléchargez le RFC 6972


L'article seul

RFC 6971: Depth-First Forwarding in Unreliable Networks (DFF)

Date de publication du RFC : Juin 2013
Auteur(s) du RFC : U. Herberg (Fujitsu), A. Cardenas (University of Texas at Dallas), T. Iwao (Fujitsu), M. Dow (Freescale), S. Cespedes (U. Icesi)
Expérimental
Première rédaction de cet article le 29 juin 2013


Traditionnellement, l'acheminement à bon port d'un paquet IP nécessitait deux processus distincts : le routage (routing) à proprement parler, où les routeurs calculent des tables de routage indiquant, pour divers préfixes IP, la prochaine étape (next hop) à atteindre, et la transmission (forwarding) où les routeurs choisissent le prochain routeur, et l'interface de sortie, pour un paquet donné. Le premier processus, le routage, est fait à l'avance, indépendemment d'un paquet précis, et nécessite des protocoles complexes comme OSPF. Le second processus, la transmission, nécessite de faire tourner l'algorithme de plus long préfixe, et se fait par contre en temps réel, pour chaque paquet entrant. Pourquoi cette séparation en deux ? Car ces deux processus ont des caractéristiques très différentes. Le premier, nécessitant des protocoles et des algorithmes élaborés, est mieux réalisé sur un processeur classique. Le second est typiquement le domaine d'ASIC spécialisés. Les routeurs haut de gamme utilisent d'ailleurs les deux types de matériel, selon la tâche. Mais cette séparation a aussi des inconvénients. Ainsi, la détection qu'un lien ne marche plus est typiquement du ressort des algorithmes de routage, qui ajusteront alors leurs routes. Pourtant, certains réseaux physiques permettent la détection, lors de la transmission d'un paquet, d'une panne et d'une impossibilité d'envoi. Pourquoi ne pas utiliser cette information pour que les paquets suivants aillent essayer une autre étape suivante ? C'est ce que propose ce RFC.

Notez que, comme souvent en matière de réseaux informatiques, le vocabulaire est flou et incohérent. Ainsi, le terme de routage est souvent utilisé pour désigner les deux processus qui concourent à l'acheminement, le routage à proprement parler et la transmission. Par exemple, j'ai parlé de table de routage alors que le sigle FIB (Forwarding Information Base) aurait été plus correct. Et le terme routeur désigne une boîte qui fait de la transmission et parfois (sur le moyen et haut de gamme) le routage. On lit ainsi des phrases fausses comme « Quagga permet de transformer un PC Unix en routeur » alors que le noyau Unix a toujours été capable de faire de la transmission de paquets (Quagga met en œuvre les protocoles de routage, qui ne sont pas nécessaires à un routeur).

Mais passons. Il faut bien faire avec le vocabulaire que nous avons. Revenons à la proposition expérimentale de notre RFC 6971. Elle ne cherche pas à couvrir tous les cas de transmission de paquets. Ce RFC s'applique aux paquets IPv6, lors de leur transmission sur des liens peu fiables, avec une topologie sans cesse changeante, un trafic assez faible, et où le protocole de couche 2 permet de savoir si un paquet a été transmis avec succès ou pas. C'est typiquement le monde des MANET et des LowPAN, des réseaux de petites machines connectées en radio. L'idée centrale de ce protocole DFF est d'avoir, dans le processus de transmission, certaines techniques utilisées d'habitude uniquement dans le routage, pour chercher un chemin alternatif. DFF va transmettre un paquet au premier routeur, s'il ne reçoit pas de nouvelles, il va essayer le second et ainsi de suite. Par contre, si la transmission vers la première étape se fait avec succès, DFF va laisser le paquet continuer, passer au routeur suivant, etc. Il fonctionne donc en profondeur d'abord (on essaie d'aller le plus loin possible, avant de tester d'autres « frères »). Les essais successifs se font séquentiellement (et non pas en parallèle comme dans les protocoles d'inondation) pour éviter qu'un destinataire ne reçoive plusieurs copies du même message. Cela peut donc prendre pas mal de temps s'il y a beaucoup de routeurs potentiels. À noter que le tout fonctionne de manière répartie, sans composant central.

N'est-ce pas un peu bizarre que de refaire une partie du travail du processus de routage dans celui de transmission ? Mais c'est lié à la façon dont fonctionnent les protocoles de routage. Travaillant à l'avance, ils ne peuvent pas s'adapter assez vite à tous les changements de topologie, qu'on ne découvrira qu'en envoyant réellement des paquets. Les protocoles de routage fonctionnent typiquement en envoyant de temps en temps des messages d'information. L'information peut donc être dépassée au moment de la transmission. Pour avoir une information plus à jour (section 1.1), il faudrait augmenter le rythme des messages d'information et cela se ferait au détriment de la consommation d'énergie des machines (rappelez-vous que DFF est prévu pour des réseaux de petites machines, souvent sans autre source d'énergie que leur batterie). Se placer sur le dos du processus de transmission (qui doit avoir lieu de toute façon) permettra donc, si ce protocole DFF tient ses promesses (ce RFC est expérimental), d'augmenter le pourcentage de paquets effectivement transmis, sans augmenter les coûts.

DFF va donc récolter de l'information sur le fonctionnement effectif du réseau, information qui peut être utile au processus de routage. DFF peut donc la réinjecter dans ce dernier, pour l'aider à calculer de meilleures routes, mais ce point n'est pas détaillé dans ce RFC.

La section 3 du RFC revient sur l'applicabilité limitée de ce protocole DFF. On l'a dit, il ne s'agit pas de remplacer tous les mécanismes de routage existants par ce mécanisme utilisant le succès de la transmission comme indication. D'abord, tous les réseaux n'offrent pas de possibilité de détecter cet échec. 802.15.4 ou 802.11 le permettent mais pas Ethernet, par exemple. D'autre part, DFF n'est utile que si la topologie change souvent. Dans un réseau filaire stable et fiable, les mécanismes de routage actuels marchent très bien et n'ont pas besoin de DFF. Et DFF nécessite un réseau ayant une topologie dense, avec plusieurs liens possibles entre deux points. S'il n'existe qu'un seul lien, DFF ne servira à rien puisque, en cas de perte d'un paquet, il n'y aura pas d'alternative. Enfin, DFF, contrairement à la transmission IP traditionnelle, nécessite un état dans le routeur. Il faut se souvenir de chaque paquet envoyé, le temps qu'on soit sûr de son bon acheminement. DFF ne peut donc être utilisé qu'en cas de faible trafic.

DFF peut fonctionner aussi bien dans les réseaux route-over (réseaux routés par les méthodes IP classiques) que dans les réseaux mesh-under (réseaux utilisant un mécanisme de « routage » dans la couche 2, cette terminologie est empruntée au RFC 6775).

La section 4 résume le fonctionnement du protocole : pour chaque paquet qu'il a reçu et qu'il doit transmettre, le routeur construit une liste des prochaines étapes possibles. Il tente d'envoyer le paquet en essayant successivement ces étapes. Si toutes échouent, le routeur renvoie le paquet à l'expéditeur, qui va alors essayer l'étape suivante dans sa liste à lui (rappelez-vous qu'on est en profondeur d'abord). On voit donc que, pour chaque paquet pas encore transmis avec succès, le routeur doit garder cette information en mémoire : routeur précédent (qui a envoyé le paquet), numéro et prochaines étapes possibles en indiquant lesquelles ont déjà été essayées. C'est quoi, ce numéro ? C'est un identifiant unique par routeur et permettant de distinguer un paquet des autres (section 12). La liste des paquets en cours de transmission, avec les métadonnées, est nommée le Processed Set (section 6.2).

DFF doit connaître la liste des prochaines étapes possibles. Il a pu utiliser un protocole de découverte des voisins (comme le NHDP du RFC 6130), ou bien il a pu trouver cette information dans la RIB (Routing Information Base), la base de données construite par le processus de routage (voir la section 5 pour les détails).

Les informations dont a besoin DFF peuvent être représentées de deux manières différentes dans le paquet. En route-over, on utilise un en-tête d'extension IPv6 standard, le hop-by-hop options (et pas un destination options, malgré les recommandations du RFC 6564 car cet en-tête doit être examiné par tous les routeurs sur le trajet). Le type de l'option DFF est 0xEE. Comme il commence par deux bits à Un, le paquet sera rejeté par les routeurs non-DFF (RFC 2460, section 4.2). La section 13.1 de notre RFC fournit les détails sur cette adaptation à IPv6. En mesh-under, on se sert des en-têtes 6LoWPAN, avec les adresses du RFC 4944 (section 13.2 pour les précisions). Outre le numéro, il faut mettre dans chaque paquet deux booléens : RET indique un paquet renvoyé à l'expéditeur car non distribuable, et DUP indique une retransmission, au moins un essai ayant apparemment échoué. Comme le paquet a pu être distribué quand même (même si le routeur émetteur n'a pas été notifié), DUP sert à indiquer la possibilité de duplication d'un paquet, avec laquelle les couches hautes vont devoir se débrouiller.

Rien ne garantit que le réseau soit un arbre pur. Des boucles sont parfaitement possibles et DFF doit les détecter. Ces booléens RET et DUP permettent notamment de distinguer un paquet délibérement renvoyé à l'émetteur d'un paquet qui boucle dans le réseau. Si le routeur reçoit un paquet qu'il a déjà transmis (il le sait d'après le numéro), avec DUP et RET tous les deux à Zéro, c'est que le paquet est en train de boucler. Si RET est à Un, c'est un retour délibéré car le routeur suivant n'a pas pu transmettre le paquet.

Le format exact des paquets figure en section 7. Le traitement des paquets par les routeurs est détaillé en sections 10 et 11 du RFC. Des examples de fonctionnement de DFF dans diverses topologies, et pour divers cas de figure, se trouvent dans l'annexe A.

Notez que, comme la plupart des protocoles conçus pour ce type de réseau (sans administrateur réseaux, et où il y a beaucoup de machines, qu'il n'est pas question de configurer une par une), DFF ne présente guère de sécurité. Par exemple, en envoyant beaucoup de paquets à une adresse inexistante, on force les routeurs à retenir ces paquets en mémoire le temps de détecter la non-délivrabilité, réalisant ainsi facilement une attaque par déni de service (section 16.3.1).

Maintenant, il reste à tester DFF en vrai, et à récolter de l'information sur les points détaillés en section 1.2 : quelles sont les bonnes valeurs pour le délai d'attente P_HOLD_TIME (trop long, et on consomme de la mémoire sur les routeurs, qui doivent se souvenir du paquet, trop court, on risque d'oublier un paquet et de le croire nouveau lorsqu'il revient après un échec, cf. section 8) ? Et les valeurs idéales pour le nombre de sauts maximum MAX_HOP_LIMIT ? Et l'interaction idéale entre DFF et les protocoles de routage ? Tous ces points vont devoir être étudiés en pratique.

L'annexe B du RFC rassemble un certain nombre d'informations sur le déploiement effectif de DFF et ses mises en œuvre (au moins deux à l'heure actuelle, une sur 802.11 et une sur 802.15.4). Par exemple, les compteurs électriques de la smart grid au Japon utilisent apparemment DFF mais les détails n'ont pas été publiés. Un autre distributeur d'électricité qui utilise DFF est la Kit Carson Electric Cooperative au Nouveau-Mexique, qui en a http://www.kitcarson.com/index.php?option=com_content&view=article&id=45&Itemid=1fait état publiquement. Une mise en œuvre en logiciel libre de DFF en Java a été annoncée par Fujitsu mais apparemment pas encore publiée (en tout cas, je ne l'ai pas trouvée).

Merci à Laurent Toutain pour sa relecture et ses remarques pertinentes sur l'algorithme DFF.


Téléchargez le RFC 6971


L'article seul

RFC 6970: Universal Plug and Play (UPnP) Internet Gateway Device (IGD)-Port Control Protocol (PCP) Interworking Function

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : M. Boucadair (France Telecom), R. Penno, D. Wing (Cisco)
Chemin des normes
Première rédaction de cet article le 24 juillet 2013


Le RFC 6887 normalise le protocole PCP (Port Control Protocol) qui permet de contrôler un routeur NAT ou un pare-feu depuis une machine cliente, par exemple pour ouvrir un port en entrée lorsqu'on utilise un logiciel de transfert de fichiers pair-à-pair ou bien un logiciel de téléphonie sur IP. PCP fonctionne également dans le cas des CGN. Mais cela ne sert à rien d'avoir des routeurs PCP si la quasi-totalité des applications sur les postes clients n'utilise toujours que le vieux protocole UPnP, certes très limité mais qui est largement déployé. Ce nouveau RFC décrit donc une solution de transition : une passerelle entre UPnP et PCP, permettant de satisfaire les clients UPnP et les serveurs PCP.

Cette passerelle sera typiquement installée dans le routeur CPE (la box). Ainsi, lorsque, par exemple, l'application qui parle UPnP fera un AddPortMapping, la passerelle le traduira en une requête MAP PCP (avec l'option PREFER_FAILURE puisque cette requête, contrairement à AddAnyPortMapping, réclame un numéro de port spécifique et échoue s'il n'est pas disponible ; cf. section 5.6). Si vous aimez les sigles, vous serez ravis car le nom complet de la passerelle est UPnP IGD-PCP IWF pour UPnP Internet Gateway Device PCP Interworking Function.

La section 4 donne les correspondances complètes entre les méthodes UPnP et les méthodes PCP, ainsi qu'entre leurs codes d'erreur. Ainsi, toute passerelle UPnP<->PCP sait qu'elle doit traduire une erreur 8 de PCP (NO_RESOURCES) en une erreur 501 ActionFailed chez UPnP v1 et 728 NoPortMapsAvailable chez UPnP v2 (qui a des codes d'erreur bien plus détaillés). De la même façon, une erreur 2 de PCP (NOT_AUTHORIZED) devient 718 ConflictInMappingEntry en UPnP v1 et 606 Action not authorized en UPnP v2.

La passerelle UPnP<->PCP n'est pas un simple relais, transférant des requêtes dans un sens et les réponses dans l'autre. Elle doit garder un état, la mémoire de toutes les correspondances demandées (section 5.3). Cela permet, par exemple de faire face au fait que UPnP permet de créer une correspondance {adresse interne, port interne, adresse externe, port externe} de durée illimitée, ce que ne sait pas faire PCP (RFC 6887, section 7.1). Dans ce cas, la passerelle enregistre la correspondance et la renouvelle dans le serveur PCP à chaque fois qu'elle approche de l'expiration (section 5.9). D'autre part, des requêtes UPnP d'information comme GetListOfPortMappings ne sont pas relayés au serveur PCP mais traitées en examinant l'état local (section 5.7).

Autre point important de ce RFC : la passerelle peut être sur un routeur NAT ou pas (par exemple, dans certains cas de CGN, le routeur CPE ne fait pas de NAT). Si elle doit faire du NAT, la réception d'une requête UPnP va se traduire par une mise à jour de la table NAT locale et l'émission d'une requête au serveur PCP.

Ah, et pour trouver le serveur PCP à utiliser, comment fait la passerelle ? Comme un client PCP normal (via DHCP, par exemple).


Téléchargez le RFC 6970


L'article seul

RFC 6967: Analysis of Solution Candidates to Reveal a Host Identifier (HOST_ID) in Shared Address Deployments

Date de publication du RFC : Juin 2013
Auteur(s) du RFC : M. Boucadair (France Telecom), J. Touch (USC/ISI), P. Levis (France Telecom), R. Penno (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF intarea
Première rédaction de cet article le 19 juin 2013


Lorsque plusieurs machines sont situées derrière un routeur NAT, leurs pairs sur l'Internet ne peuvent pas facilement les distinguer. Tout le trafic vient de la même adresse IP, l'adresse publique allouée au routeur NAT, et c'est gênant pour certaines applications. Par contre, cela est positif d'un autre point de vue : cela fournit un certain niveau de masquage des machines individuelles, qui peut aider à protéger sa vie privée. Pris entre ces deux exigences contradictoires, l'IETF propose dans ce RFC une analyse des techniques permettant de révéler la machine individuelle derrière le routeur NAT, sans prendre position sur le fait de savoir si cette révélation est une bonne ou une mauvaise chose.

L'idée est que chaque machine a une identité unique (notée HOST_ID) et que les techniques étudiées ici doivent permettre de communiquer ce HOST_ID au pair avec qui on parle sur l'Internet. Autrefois, l'adresse IPv4 pouvait servir de HOST_ID mais cela ne marche plus désormais en raison de la prévalence du NAT. Le cas du petit routeur NAT à la maison n'est pas forcément le plus intéressant (toutes les machines appartiennent au même foyer) mais le problème est plus crucial avec les CGN, où des machines n'ayant aucun lien entre elles se partagent la même adresse IP, ce qui a des tas d'effets néfastes (RFC 6269) : impossible de mettre en liste noire la machine coupable, par exemple, sans risquer de gêner des utilisateurs n'ayant commis d'autre délit que de partager l'adresse IP d'un méchant. Même problème avec des techniques comme l'A+P du RFC 6346.

J'ai dit plus haut que le but était d'avoir des HOST_ID uniques. En fait, il doivent être uniques par adresse IP publique. Deux routeurs NAT qui utilisent des adresses IPv4 publiques différentes peuvent générer des HOST_ID identiques, seul le couple {adresse IPv4 publique, HOST_ID} a besoin d'être unique au niveau mondial (section 2 du RFC).

À ce stade, rappelez-vous que ce RFC présente un problème en terme très général et expose des solutions possibles. Par exemple, le HOST_ID peut figurer dans chaque paquet IP ou bien uniquement au début d'une session. Et il peut être ajouté par l'engin qui gère le partage d'adresse (le routeur NAT ou CGN) ou bien par la machine originale (qui pourra donc mentir, mais c'est pareil avec l'adresse IP source). Enfin, bien des identificateurs peuvent être utilisés comme HOST_ID (l'adresse IP à la source, les seize bits de poids le plus faible de l'adresse IP, un identifiant opaque compris uniquement par le FAI de départ, un VLAN ID, etc).

Une telle fonction de révélation des identités soulève évidemment des problèmes liés à la protection de la vie privée. Certains voient en effet dans le NAT des avantages en terme de sécurité comme, via le partage d'adresses, le fait que l'observateur extérieur ne puisse pas savoir quelle machine exactement, parmi toutes les machines situées derrière le routeur NAT, il est en train d'observer. En fournissant un HOST_ID à l'extérieur, on perdrait cette intimité. Notez qu'HOST__ID ramènerait juste au cas où on utilise une adresse IP publique sur sa machine, ni plus, ni moins. Notamment, un HOST_ID, comme une adresse IP publique, ne serait pas forcément permanent (lisez le RFC 4941 pour un exemple d'adresses publiques temporaires préservant la vie privée). Ainsi, une machine en redémarrant pourrait acquérir un nouvel HOST_ID.

Pour limiter les risques, ce RFC suggère deux règles : que les HOST_ID ne soient uniques que localement, pas globalement. Et qu'ils soient toujours temporaires. Cette question de la vie privée avait été la plus chaude lors des discussions à l'IETF sur le futur RFC, et le document a beaucoup évolué vers davantage de prise en compte du problème de la protection de la vie privée. Alissa Cooper, du CDT et auteure du RFC 6462 avait été particulièrement critique sur les premières versions de ce document, réclamant des modifications comme le fait que le HOST_ID ne soit pas forcément unique mondialement.

D'autre part, les logiciels qui visent à mettre en œuvre des mécanismes de dissimulation, afin de protéger la vie privée, comme Tor, supprimeront évidemment le HOST_ID, comme ils suppriment aujourd'hui d'autres informations bien plus révélatrices. Regardez le Panopticlick pour voir qu'on est facilement identifié de manière unique lorsqu'on navigue sur le Web, même derrière un routeur NAT.

La section 4 de notre RFC présente ensuite toutes les solutions étudiées pour transmettre l'HOST_ID. Certaines sont clairement mauvaises et ne sont mentionnées que pour documenter les raisons de leur rejet. D'autres méritent davantage d'étude.

D'abord, utiliser le champ Identification des paquets IP. Ce champ est surtout connu pour servir lors du réassemblage des datagrammes mais on peut théoriquement s'en servir pour « exfiltrer » de l'information sur une machine. Ce champ fait seize bits, ce qui est suffisant pour identifier une machine. Cela empêche évidemment de s'en servir pour le réassemblage après fragmentation (voir l'excellent RFC 6864 si vous voulez tout comprendre sur ce champ). Comme il n'est pas toujours facile pour le routeur NAT de garantir que les datagrammes ne seront jamais fragmentés, ni avant, ni après, cette solution est déconseillée par notre RFC.

On peut alors imaginer de définir une nouvelle option IP, conçue uniquement pour notre but d'identification, et dont l'usage n'entrerait pas en conflit avec des usages existants. Elle permettrait de transporter l'information qu'on veut. (Cela avait été documenté dans l'Internet-Draft draft-chen-intarea-v4-uid-header-option, abandonné depuis.) Cette solution, comme la précédente, a l'avantage d'être indépendante du protocole de transport. Elle pose quelques problèmes techniques (que faire si le paquet a une taille proche de la MTU et qu'on veut y ajouter cette option ? que faire si l'espace pour les options, qui a une taille maximale en IPv4, est plein ?) Mais elle a surtout comme défaut que les options IP sont souvent bloquées sur l'Internet (voir aussi « Measuring interactions between transport protocols and middleboxes » par Alberto Medina, Mark Allman et Sally Floyd). Le RFC la regarde donc comme non viable.

On peut alors monter d'une couche et choisir une nouvelle option TCP, qui indiquerait le HOST_ID. (Documenté dans l'Internet-Draft draft-wing-nat-reveal-option qui a été abandonné par la suite.) Cela aurait l'avantage qu'on n'aurait pas à la répéter dans chaque paquet mais uniquement dans le paquet SYN. Cela aiderait à résoudre les problèmes de MTU (le paquet SYN est petit). Et les mesures indiquent que les options TCP sont bien mieux respectées que les options IP sur l'Internet (voir l'article de Medina, Allman et Floyd cité plus haut, ainsi que l'Internet-Draft draft-abdo-hostid-tcpopt-implementation). Mais cette solution ne marcherait évidemment pas pour les autres protocoles de transport. Et il y a quelques problèmes techniques (une vision générale est dans l'article de Honda, M., Nishida, Y., Raiciu, C., Greenhalgh, A., Handley, M. et H. Tokuda, « Is it still possible to extend TCP? »). Par exemple, l'espace pour les options a une taille maximum dans TCP.

Si on n'a pas trouvé son bonheur dans la couche 3 (champ ID d'IP ou option IP), ni dans la couche 4 (option TCP), les couches supérieures seront-elles plus accueillantes ? Pourquoi ne pas transmettre l'information dans les applications ? Par exemple, pour HTTP, l'en-tête Forwarded: (RFC 7239) pourrait être l'endroit idéal pour cela. L'engin qui fait le partage d'adresses pourrait ainsi ajouter à la requête HTTP :

Forwarded: for=192.168.13.1

Il existait avant un en-tête non-standard, X-Forwarded-For:, dit aussi XFF, qui faisait quelque chose de ce genre. Comme les autres solutions au problème de la révélation du HOST_ID, elle permet la triche. C'est pour cela que Wikipédia maintient une liste des FAI à qui on peut faire confiance pour mettre de l'information XFF correcte. Wikipédia peut alors utiliser l'information dans ce champ pour attribuer les responsabilités (de vandalisme, par exemple, ou d'introduction délibérée d'informations fausses) à la bonne adresse IP. La principale limite de cette solution est qu'elle ne marche que pour certains protocoles, comme HTTP. Pour les autres, il faudrait au fur et à mesure concevoir une extension permettant de diffuser cette information. Même pour HTTP, elle nécessite de modifier les requêtes en cours de route, ce qui est impossible avec HTTPS.

Pour éviter de devoir développer une extension ou un en-tête spécifique par protocole applicatif, la solution PROXY a été proposée. Elle consiste à ajouter l'information juste avant les données de la couche Application. L'information a cette allure (au moment du partage d'adresses, 192.168.13.1:56324 voulait parler à 192.0.2.15:443) :

PROXY TCP4 192.168.13.1 192.0.2.15 56324 443\r\n

En la recevant, le serveur a juste à retirer cette ligne et à passer ce qui suit à l'application. En pratique, cette solution n'est pas réaliste car elle casse la compatibilité : un client qui a PROXY ne peut pas parler à un serveur qui ne l'a pas (l'opposé est vrai, par contre). Sans même parler des pare-feux qui n'accepteront pas ce qui leur semblera une requête invalide. Bref, elle n'est envisageable que dans des environnements fermés.

Le NAT tel que déployé aujourd'hui dans le monde IPv4 ne mérite pas réellement son nom. Il ne traduit pas une adresse pour une autre mais un couple {adresse, port} pour un autre. Il devrait plutôt être qualifié de NAPT (Network Address and Port Translation). Peut-on utiliser les ports alloués pour transporter l'information sur le HOST_ID ? L'idée est d'allouer un jeu de ports à chaque machine située derrière le routeur NAPT. Par exemple, imaginons trois machines derrière le routeur, celui-ci utilise les ports publics de 1 024 à 20 000 pour la première machine, de 20 001 à 40 000 pour la seconde et de 40 001 à 65 535 pour la troisième (voir l'Internet-Draft draft-donley-behave-deterministic-cgn). Il ne reste plus ensuite qu'à publier cette information à l'extérieur (le RFC est muet sur ce point). Le RFC 6346 propose une solution de ce genre. Malheureusement, cela contredit partiellement les exigences de sécurité des RFC 6056 et RFC 6269 qui demandent des ports sources imprévisibles.

Plus disruptive est la solution qui consiste à utiliser un protocole nouveau, au dessus d'IP, le protocole HIP. HIP a déjà cette notion de HOST_ID (l'identité d'une machine est une clé cryptographique, ce qui résout bien des problèmes de sécurité). Mais cela nécessite que le client et le serveur parlent HIP tous les deux, ce qui parait irréaliste. À la rigueur, si tous les serveurs parlaient HIP, le routeur NAT pourrait se contenter de prendre des requêtes non-HIP et de les traduire en HIP. Mais tous les serveurs ne parlent pas HIP, loin de là.

Bon, si on n'arrive pas à mettre le HOST_ID dans le canal normal de communication, peut-on le mettre à l'extérieur ? Par exemple, peut-on utiliser ICMP pour signaler l'adresse originale d'une communication en cours ? Dans cette idée, le routeur NAT, en même temps que le paquet TCP initial vers le serveur, enverrait une requête ICMP contenant l'information utile. Cela avait été documenté dans l'Internet-Draft draft-yourtchenko-nat-reveal-ping, qui a expiré depuis. Cela marcherait pour tous les protocoles ayant la notion de port (puisque c'est ce qu'on mettrait dans le paquet ICMP pour indiquer de quelle session on parle). Et un problème éventuel sur cette fonction de révélation de l'HOST_ID (par exemple de l'ICMP bloqué) ne gênerait pas la session normale (contrairement aux options IP ou TCP). Par contre, on n'est pas sûr que ce soit la même machine qui reçoive l'ICMP et qui reçoive les autres paquets (en cas d'utilisation de répartiteurs de charge). Et cette technique rend plus difficile l'examen de l'HOST_ID par des intermédiaires, genre IDS.

Toujours dans la série « communications hors bande », l'idée de ressortir le vieux protocole IDENT (RFC 1413), qui récupérerait le HOST_ID par une connexion TCP vers la source d'une session. Il faudra donc un serveur IDENT dans la machine faisant le partage d'adresses et publier cette information (dans le DNS ?) pour éviter que les serveurs ne bombardent les pauvres CPE de requêtes IDENT. Il y a aussi des craintes quant aux performances de cette solution. Et quant à sa sécurité la requête IDENT pourrait être émise par un méchant.

Voilà, on a fait le tour de toutes les solutions envisageables. La section 5 de notre RFC présente une synthèse sous forme d'un tableau dont les lignes sont les solutions présentées plus haut et les colonnes sont les critères d'évaluation (« nécessite une modification de TCP/IP dans les machines », « a un impact sur les performances », « déployable aujourd'hui (sans refaire l'Internet de zéro) », etc).


Téléchargez le RFC 6967


L'article seul

RFC 6963: A Uniform Resource Name (URN) Namespace for Examples

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : P. Saint-Andre (Cisco Systems)
Première rédaction de cet article le 24 mai 2013


Voici un nouvel espace de nommage pour les URN, urn:example, qui servira pour les exemples et la documentation.

Les URN sont normalisés dans le RFC 8141 et offrent un moyen de construire des URI stables et indépendants de toute notion de localisation. L'URN commence par urn: puis par un NID (namespace identifier). Le RFC 3406 définissait trois genres de NID, formel, informel et expérimental (nom commençant par x-, et supprimé depuis par le RFC 8141). Lorsqu'on a besoin d'URN pour une documentation ou un cours, on utilisait en général ces NID expérimentaux. Mais les identificateurs commençant par x- sont désormais mal vus dans le monde IETF (cf. RFC 6648) et ce nouveau RFC propose donc d'abandonner ces NID expérimentaux et, pour les exemples, d'utiliser le NID example. De tels noms réservés pour les exemples sont courants dans les RFC (par exemple le RFC 2606 pour les noms de domaine ou le RFC 5612 pour les numéros d'organisations).

Ainsi, on peut désormais créer comme ça, gratuitement, l'URN urn:example:foo:bar et être sûr qu'il n'entrera jamais en collision avec un « vrai » URN. (Par contre, deux URN example peuvent être accidentellement identiques puisqu'aucune autorité ne les attribue.) Ces URN ne doivent être utilisés qu'à des fins d'exemple et pas pour court-circuiter les mécanismes normaux d'allocation des URN formels et informels, décrits dans le RFC 8141.


Téléchargez le RFC 6963


L'article seul

RFC 6962: Certificate Transparency

Date de publication du RFC : Juin 2013
Auteur(s) du RFC : B. Laurie, A. Langley, E. Kasper (Google)
Expérimental
Première rédaction de cet article le 7 juin 2013


Plusieurs attaques spectaculaires, notamment celle contre DigiNotar, ont montré la fragilité de l'actuel système de gestion de certificats X.509. Comme n'importe quelle AC peut émettre un certificat pour n'importe quel nom de domaine, il ne suffit pas d'évaluer la sécurité de son AC, il faudrait idéalement évaluer toutes les AC. Ce RFC propose une approche différente : encourager/obliger les AC à publier « au grand jour » les certificats qu'elles émettent. Un titulaire d'un certificat qui craint qu'une AC n'émette un certificat à son nom sans son autorisation n'a alors qu'à surveiller ces publications. (Il peut aussi découvrir à cette occasion que sa propre AC s'est fait pirater ou bien est devenue méchante et émet des certificats qu'on ne lui a pas demandés.)

Ce n'est pas par hasard que les auteurs de ce RFC sont trois employés de Google. Dans l'affaire DigiNotar, comme dans d'autres affaires analogues, le premier vrai/faux certificat émis par celui qui a piraté une AC est souvent un certificat pour gmail.com, de façon à permettre d'espionner le trafic vers Gmail. La proposition de ce RFC (qui est encore expérimental) est d'empêcher l'émission « discrète » de vrais/faux certificats qui seraient ensuite utilisés uniquement à certains endroits (l'Iran dans le cas de DigiNotar mais cela peut aussi concerner des entreprises qui font des attaques de l'homme du milieu contre leurs propres employés).

Le principe est donc de créer un (ou plusieurs) journal des certificats émis. Le journal doit être public, pour que Google ou n'importe qui d'autre puisse l'auditer. Il doit être en mode « ajout seulement » pour éviter qu'on puisse réécrire l'histoire. Les certificats sont déjà signés mais le journal a ses propres signatures, pour prouver son intégrité. Conceptuellement, ce journal est une liste de certificats dans l'ordre de leur création. Toute AC peut y ajouter des certificats (la liste ne peut pas être ouverte en écriture à tous, de crainte qu'elle ne soit remplie rapidement de certificats bidons). En pratique, le RFC estime que la liste des AC autorisées à écrire dans le journal sera l'union des listes des AC acceptées dans les principaux navigateurs Web (voir aussi la section 4.7).

À chaque insertion, le journal renvoie à l'AC une estampille temporelle signée, permettant à l'AC de prouver qu'elle a bien enregistré le certificat. Si une AC peut présenter cette signature mais que le certificat est absent du journal, l'observateur aura la preuve que le journal ne marche pas correctement. Le format exact de cette estampille temporelle est décrit en section 3.2. Elle devra être envoyée au client par les serveurs TLS, comme preuve de la bonne foi de l'AC (cf. sections 3.3 et 5.2).

Les titulaires de certificats importants, comme Google, mais aussi des chercheurs, des agences de sécurité, etc, pourront alors suivre l'activité de ce(s) journal (journaux) public(s) (section 5.3 du RFC). Ce qu'ils feront en cas de détection d'un certificat anormal (portant sur leur nom de domaine, mais qu'ils n'ont pas demandé) n'est pas spécifié dans le RFC : cela dépend de la politique de l'organisation concernée. Ce RFC fournit un mécanisme, son usage n'est pas de son ressort. Ce journal n'empêchera donc pas l'émission de vrais/faux certificats, ni leur usage, mais il les rendra visibles plus facilement et sans doute plus vite.

Pour que cela fonctionne, il faudra que les clients TLS vérifient que le certificat présenté est bien dans le journal (autrement, le méchant n'aurait qu'à ne pas enregistrer son vrai/faux certificat, cf. section 5.4 du RFC).

En pratique, la réalisation de ce journal utilise un arbre de Merkle, une structure de données qui permet de mettre en œuvre un système où l'ajout de certificats est possible, mais pas leur retrait. La section 2 du RFC détaille l'utilisation de ces arbres et la cryptographie utilisée.

Le protocole utilisé entre les AC et le journal, comme celui utilisé entre les clients TLD et le journal, sera HTTP et le format des données sera JSON (section 4). Ainsi, pour ajouter un certificat nouvellement émis au journal géré sur sunlight-log.example.net, l'AC fera :

POST https://sunlight-log.example.net/ct/v1/add-chain

et le corps de la requête HTTP sera un tableau JSON de certificats encodés en Base64. La réponse contiendra notamment l'estampille temporelle (SCT pour Signed Certificate Timestamp). Pour récupérer des certificats, le programme de surveillance fera par exemple :

GET https://sunlight-log.example.net/ct/v1/get-entries

D'autres URL permettront de récupérer les condensats cryptographiques contenus dans l'arbre de Merkle, pour s'assurer qu'il est cohérent.

Notez que Google a produit une mise en œuvre de ce RFC, qui semble activement développée. Et il existe un pilote écrit en Go. Il y a aussi une liste de diffusion sur ce projet et un site officiel du projet par Google. Sinon, si vous voulez en savoir plus sur cette idée de vérification publique, consultez « Efficient Data Structures for Tamper-Evident Logging » de Scott A. Crosby et Dan S. Wallach. Autres lectures sur la certificate transparency, un article de promotion de Ben Laurie et un article violemment critique.

Quelles sont les chances de succès de cette idée ? Tant que peu d'AC participent, ces journaux ne serviront pas à grand'chose (le méchant attaquera uniquement les AC non participantes). L'idée est qu'à moyen terme, la pression sur les AC (directement ou bien via les navigateurs Web qui ne feraient plus confiance aux AC non participantes) pourra faire que tous les certificats devront être dans le journal et que l'examen de celui-ci suffira à détecter les « vrais/faux certificats ».

Merci à Florian Maury pour sa relecture très détaillée.


Téléchargez le RFC 6962


L'article seul

RFC 6960: X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP

Date de publication du RFC : Juin 2013
Auteur(s) du RFC : S. Santesson (3xA Security), M. Myers (TraceRoute Security), R. Ankney, A. Malpani (CA Technologies), S. Galperin (A9), C. Adams (University of Ottawa)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pkix
Première rédaction de cet article le 7 juin 2013


Le protocole OCSP permet à un client X.509 (par exemple un navigateur Web engagé dans une connexion HTTPS) de s'informer en temps réel sur l'état d'un certificat, notamment afin de savoir s'il est révoqué ou pas. Ce nouveau RFC remplace (avec de légers changements) l'ancienne norme OCSP qui était dans le RFC 2560.

Normalement, le destinataire d'un certificat X.509 (par exemple le navigateur Web cité plus haut), authentifie ce dernier en utilisant les clés publiques des AC qu'il a dans son magasin, et en vérifiant dans une liste de CRL, mise à jour périodiquement, que le certificat est toujours d'actualité, qu'il n'a pas été révoqué par l'AC émettrice (section 3.3 du RFC 5280). En complément, ou à la place de ces CRL, le destinataire peut utiliser le protocole OCSP normalisé dans ce RFC. OCSP est un protocole synchrone : le destinataire du certificat émet une requête à un serveur OCSP et attend sa réponse avant de valider le certificat. Il peut ainsi obtenir des informations plus à jour qu'avec des CRL.

La requête OCSP contient (un survol du protocole figure en section 2 de ce RFC) le numéro de série du certificat qu'on veut authentifier. La réponse dépend de si le répondeur (le serveur OCSP) a l'information sur ce certificat. Si oui, il répond positivement (good, le certificat est valable) ou négativement (revoked, le certificat ne doit pas être accepté), en indiquant l'heure (un certificat valable à un moment peut être révoqué par la suite) et sa réponse est signée (typiquement avec le certificat de l'AC). Si non, si le répondeur n'a pas l'information, il répond unknown.

Les réponses possibles sont donc good, revoked et unknown. Notez que, de manière surprenante, good ne dit pas que le certificat existe, simplement qu'il n'a pas été révoqué. (Cette question a fait l'objet de chauds débats dans le groupe de travail : que doit faire un répondeur OCSP lorsqu'il reçoit une requête pour un certificat qu'il est censé connaître mais qu'il n'a pas émis ?)

Le répondeur peut aussi être dans l'incapacité de fournir une réponse et, dans ce cas, le message d'erreur résultant n'est pas signé. Parmi les causes possibles d'erreur, une requête incorrecte, une erreur dans le répondeur (équivalent du 500 Internal server error de HTTP), un problème temporaire qui nécessite que le client réessaie plus tard, un client non autorisé, etc.

La réponse inclut souvent des temps : dernier moment où l'information retournée était correcte, moment de la prochaine mise à jour de l'information, moment de la signature de l'information (les réponses peuvent être pré-produites) ou moment où la révocation a eu lieu.

Mais comment un destinataire de certificat sait-il où trouver le serveur OCSP ? Il est typiquement indiqué dans le certificat qu'on teste, dans l'extension Authority Information Access (section 4.2.2.1 du RFC 5280). Si la méthode d'accès est id-ad-ocsp, le contenu de cette extension est un URL pointant vers le serveur OCSP. Voici un exemple dans un certificat récupéré sur l'Internet :

% openssl x509 -text -in /tmp/site.pem
...
            Authority Information Access: 
                OCSP - URI:http://rapidssl-ocsp.geotrust.com
                CA Issuers - URI:http://rapidssl-aia.geotrust.com/rapidssl.crt

Mais cette information peut aussi être codée en dur dans le client.

La plupart du temps, l'URL en question sera un URL HTTP, et OCSP tournera donc au dessus de ce protocole (parfois en HTTPS). L'annexe A décrit en détail ce mécanisme. OCSP peut utiliser GET ou POST. Dans ce dernier cas, la requête HTTP aura le type application/ocsp-request et la requête OCSP forme le corps de la requête POST, après son encodage en DER. Même chose pour la réponse, type application/ocsp-response, et du DER dans le corps HTTP.

Voilà, vous savez l'essentiel, la section 4 décrit tout le protocole, en ASN.1 (en s'appuyant sur les modules de l'annexe B). Par exemple, une requête est une TBSRequest qui contient plusieurs Request, chacune concernant un certificat :

OCSPRequest     ::=     SEQUENCE {
       tbsRequest                  TBSRequest,
       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }

   TBSRequest      ::=     SEQUENCE {
       version             [0]     EXPLICIT Version DEFAULT v1,
       requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
       requestList                 SEQUENCE OF Request,
       requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }

 ...

  Request         ::=     SEQUENCE {
       reqCert                     CertID,
       singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }

   CertID          ::=     SEQUENCE {
       hashAlgorithm       AlgorithmIdentifier,
       issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
       issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
       serialNumber        CertificateSerialNumber }

Et la réponse est un code de retour et la réponse elle-même :

OCSPResponse ::= SEQUENCE {
      responseStatus         OCSPResponseStatus,
      responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }

   OCSPResponseStatus ::= ENUMERATED {
       successful            (0),  --Response has valid confirmations
       malformedRequest      (1),  --Illegal confirmation request
       internalError         (2),  --Internal error in issuer
       tryLater              (3),  --Try again later
                                   --(4) is not used
       sigRequired           (5),  --Must sign the request
       unauthorized          (6)   --Request unauthorized
   }

   ResponseBytes ::=       SEQUENCE {
       responseType   OBJECT IDENTIFIER,
       response       OCTET STRING }

Avec response comportant à son tour des structures ASN.1 arrivant finalement à :

  SingleResponse ::= SEQUENCE {
      certID                       CertID,
      certStatus                   CertStatus,
      thisUpdate                   GeneralizedTime,
      nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
      singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }

   CertStatus ::= CHOICE {
       good        [0]     IMPLICIT NULL,
       revoked     [1]     IMPLICIT RevokedInfo,
       unknown     [2]     IMPLICIT UnknownInfo }

   RevokedInfo ::= SEQUENCE {
       revocationTime              GeneralizedTime,
       revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }

On note que la raison de la révocation est indiquée. Elle n'est pas toujours indiquée par le répondeur OCSP (cela peut être une information sensible). La présence de cette information dans les CRL a permis à l'EFF de réaliser une intéressante étude sur les raisons des révocations (la section « How often are these attacks occurring? »).

La section 5 revient sur l'analyse de sécurité d'OCSP. On notera que les problèmes de vie privée n'y sont pas mentionnés. Pourtant, la requête OCSP indique au répondeur (en général l'AC) quels sites Web ont été visités. C'est d'ailleurs ainsi qu'il a été possible de prouver l'utilisation en Iran des vrais/faux certificats de DigiNotar, en regardant les requêtes OCSP de leurs navigateurs vers l'AC.

Un autre problème de sécurité n'est pas mentionné : que doit faire le navigateur Web qui tente d'authentifier un certificat lorsque la requête OCSP n'aboutit pas (peut-être parce qu'un Homme du Milieu bloque l'accès au serveur OCSP) ? S'il refuse d'authentifier le certificat, la connexion échoue. Mais s'il accepte, OCSP ne protège plus tellement.

Les changements depuis le RFC 2560 sont mineurs, et sont résumés dans la section 1.

Merci à Erwann Abalea pour sa relecture précise.


Téléchargez le RFC 6960


L'article seul

RFC 6959: SAVI Threat Scope

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : D. McPherson (VeriSign), F.J. Baker (Cisco Systems), J.M. Halpern (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF savi
Première rédaction de cet article le 30 mai 2013


On sait que, sur l'Internet, il est possible et même facile d'usurper une adresse IP , c'est-à-dire d'émettre un paquet IP avec une adresse source allouée à quelq'un d'autre (ou pas allouée du tout). Le projet SAVI (Source Address Validation Improvement) vise à améliorer la validation de l'adresse source, de manière à rendre l'usurpation plus rare et plus difficile. Ce RFC décrit la menace à laquelle SAVI répondra et étudie les contre-mesures existantes.

L'Internet emploie un protocole de réseau sans connexion (que ce soit en IPv4 ou en IPv6). Lorsqu'une machine veut communiquer avec une autre, elle met son adresse IP comme source d'un paquet, celle de son correspondant en destination et elle envoie le paquet. Substituer l'adresse IP d'une autre machine à la sienne est donc aussi simple que d'écrire une autre chaîne de bits à la place de l'adresse authentique. Le réseau n'essaie pas d'empêcher cela. Certes, le fraudeur ne pourra pas forcément recevoir les réponses (elles arriveront à celui dont l'adresse a été usurpée) mais ce n'est pas forcément un problème dans un réseau sans connexion. Il existe des mécanismes pour empêcher cette usurpation, le plus connu étant BCP 38 (les RFC 2827 et RFC 3704) mais ils sont insuffisamment déployés, car ils n'apportent pas de bénéfices à celui qui les déploie, uniquement aux autres acteurs de l'Internet. En outre, BCP 38 ne protège pas toujours suffisamment. Par exemple, s'il est mis en œuvre dans le premier routeur, il n'empêchera pas les machines du LAN d'usurper les adresses de leurs voisines.

L'une des idées de SAVI est donc de compléter BCP 38 avec des validations locales, apportant un bénéfice local, et qui permettraient une meilleure traçabilité.

Quelques termes à apprendre pour bien suivre les documents sur SAVI :

  • Bind anchor : l'information sur laquelle on se base pour valider une adresse IP source. Par exemple, sur un commutateur, cela pourra être l'adresse MAC ou bien le port physique du commutateur.
  • Routeur NNI (Network to Network Interface) : un routeur qui fait face à un routeur d'un autre opérateur.
  • Routeur PE (Provider Edge) : un routeur qui fait face au client d'un opérateur.
  • RPF (Reverse Path Forwarding) : valider une adresse source en regardant si la réponse au paquet entrant partirait ou non par l'interface sur laquelle il est entré (détails dans le RFC 3704).

La section 3 détaille ensuite les attaques rendues possibles, ou facilitées par l'usurpation d'adresses IP source (la section 4 couvrira les contre-mesures). D'abord, les attaques en aveugle : l'assaillant, qui a usurpé l'adresse IP source, ne peut pas recevoir les réponses à ses paquets. Il peut les envoyer, ces paquets, mais c'est tout. Cela lui complique évidemment sérieusement la vie. Certaines attaques restent possibles. Il y a celles ne nécessitant qu'un seul paquet (et donc pas de réponse). Par exemple, si un paquet spécialement construit plante le logiciel du routeur qui le traite, un attaquant peut monter une attaque par déni de service en envoyant un unique packet of death. Un autre cas est celui où, en envoyant un paquet où l'adresse source et destination sont identiques, le destinataire se réponde à lui-même, puis à la réponse de la réponse, et entretienne ainsi lui-même la boucle sans fin (une bogue de cette famille avait frappé PowerDNS).

Une autre attaque en aveugle est le RST (ReSeT) TCP usurpé (section 2.3 du RFC 4953). Un seul paquet TCP accepté (l'attaquant doit deviner un numéro de séquence contenu dans la fenêtre en cours) va couper la connexion (notez que les protocoles applicatifs comme TLS et SSH ne sont d'aucune utilité contre cette attaque). Cela peut être très gênant pour les connexions censées durer longtemps (sessions BGP par exemple). Il existe des contre-mesures (voir le RFC 5961) mais empêcher l'usurpation d'adresse IP empêcherait complètement cette attaque.

Après les attaques en aveugle formées d'un seul paquet, place aux attaques volumétriques, reposant sur l'envoi d'un grand nombre de paquets. L'idée est de remplir certaines tables de taille fixe (par exemple la table des connexions entrantes) ou, encore plus simplement, de saturer le réseau de la victime. L'attaquant n'ayant pas besoin de réponse, il a tout intérêt, dans ces paquets, à usurper l'adresse IP source pour déguiser son identité. On constate que beaucoup de gens n'ont pas encore compris la facilité avec laquelle cette usurpation est possible, et croient réellement que l'adresse IP source qu'ils observent dans les paquets entrants est réellement celle de leur attaquant (pensez à cela la prochaine fois que vous lirez dans les médias quelque chose du genre « attaque par déni de service contre tel organisme, l'examen de l'attaque montrait que l'attaquant venait de Russie/Chine/Moyen-Orient »). Pire, la victime bloque parfois les paquets IP entrants en fonction de cette adresse source, réalisant ainsi une autre attaque par déni de service, contre la victime de l'usurpation d'adresse. Certaines attaques peuvent d'ailleurs être montées dans ce seul but.

Une autre raison pour l'attaquant d'usurper l'adresse IP source est la possibilité d'attaque par réflexion : comme au billard, on va viser une autre boule que celle qu'on veut vraiment toucher. L'attaquant envoie un paquet UDP au réflecteur (qui n'est pas sa vraie victime, juste un complice involontaire) en usurpant l'adresse IP source de la victime. Le réflecteur va alors répondre à ce qu'il croit être l'émetteur et qui est en fait la victime, qui sera ainsi bombardée par le ou les réflecteurs. La réflexion sert à l'attaquant à dissimuler ses traces (le paquet va suivre un tout autre chemin dans le réseau) mais elle est surtout intéressante couplée avec l'amplification. Avec certains protocoles, la réponse va être plus grande, voire beaucoup plus grande, que la requête. Avec une amplification de 20, l'attaquant pourra ainsi obtenir un bombardement de 1 Gb/s en ne dépensant lui-même que 50 Mb/s. Plusieurs protocoles permettent l'amplification, comme NTP, SNMP et surtout le DNS comme ce fut le cas lors de l'attaque de 2006 (le RFC ne les cite pas mais des attaques plus violentes ont eu lieu en 2012 et 2013).

Le RFC classe aussi dans les attaques volumétriques les actions visant à empoisonner les données d'un serveur distant. Le cas le plus courant est celui des empoisonnements DNS où le méchant va tenter de répondre avant le serveur légitime (cas, par exemple, des attaques Kaminsky). Ici, le volume élevé des requêtes n'est pas dû au désir de saturer la victime, mais à la nécessité de faire beaucoup d'essais pour en voir un accepté. (Dans le cas du DNS, il s'agit d'essayer beaucoup de Query ID et de ports source UDP.) À noter qu'il existe aussi des attaques par empoisonnement contre les caches ARP.

Cela, c'était les attaques en aveugle. Mais, parfois, un attaquant qui usurpe une adresse IP peut observer les réponses, par exemple parce qu'il est sur le même réseau local à diffusion que la victime de l'usurpation ou bien, si le réseau local ne diffuse pas à tous, parce qu'il a empoisonné les caches ARP. L'attaquant a alors bien plus de possibilités comme le détournement d'une connexion TCP à son profit, les tests de vulnérabilité d'un objectif sans se trahir, la subversion des protocoles de routage en se faisant passer pour un des routeurs participants, etc.

La section 4 décrit ensuite les contre-mesures qui peuvent être adoptées aujourd'hui et qui sont effectivement déployées, au moins partiellement. Par exemple, un commutateur peut (en violant légèrement le modèle en couches), refuser les paquets dont l'adresse IP source ne correspond pas à l'adresse MAC du paquet (que le commutateur a pu apprendre en examinant les requêtes et réponses ARP). Ou bien ceux qui viennent d'un autre port physique que d'habitude. Si les paquets de 192.168.7.64 venaient toujours du port 3 et que, tout à coup, ils viennent du port 4, le commutateur peut soupçonner une usurpation (ou tout simplement une machine qui a été déplacée : la sécurité peut se tromper).

On peut donc jeter un paquet lorsque son adresse IP source ne correspond pas aux informations qu'on possède. Notez bien que, plus on s'éloigne de la source des paquets, plus il est difficile d'être sûr que c'est bien une usurpation. Néanmoins, le RFC identifie cinq endroits où peut se faire cet examen de validité, du plus proche de la source au plus éloigné :

  • Sur le lien où est attachée la machine, comme dans l'exemple du commutateur ci-dessus. On dispose au moins de l'adresse MAC, ce qui facilite le test. Si le médium est complètement partagé (lien Wi-Fi, Ethernet classique...), cela s'arrête là. Mais, dans la cas contraire, on a aussi souvent une information physique, comme le port du commutateur. C'est donc clairement le meilleur endroit pour valider et c'est là que porteront l'essentiel des efforts du projet SAVI (voir par exemple un des premiers RFC, le RFC 6620). Le RFC traite aussi les cas spécifiques des accès Internet par câble (technologie DOCSIS) ou par ADSL. Pour ce dernier, le premier équipement du FAI dans le réseau a en général largement assez d'informations pour empêcher qu'un abonné n'usurpe l'adresse d'un autre (mais pas pour empêcher qu'une machine chez un abonné n'usurpe l'adresse d'une autre chez le même abonné ; il n'est pas évident que ce soit un problème sérieux en pratique puisque c'est le même foyer).
  • Les commutateurs suivants, auxquels la machine n'est pas directement connectée, peuvent aussi valider, mais de manière moins fiable. Si le spanning tree ou un autre protocole comme VRRP change la topologie, les paquets émis par une adresse IP donnée apparaîtront, et légitimement, sur un autre port. Les commutateurs pourraient donc avoir besoin de se transmettre leur état SAVI (liste des adresses valides et leurs ports, autrement dit les bind anchors).
  • Les routeurs peuvent ensuite être utilisés. À part le premier, ils n'ont pas l'adresse MAC à leur disposition. Le principal test qu'ils peuvent faire est de s'assurer que l'adresse IP source est dans un préfixe qui existe sur ce réseau. Par exemple, un routeur qui sait qu'il connecte 2001:db8:32:a17::/64 à l'Internet peut raisonnablement jeter un paquet venant du réseau local et prétendant avoir comme source 2001:db8:cafe::666. Notez que le routeur ne peut en général rien faire contre une machine qui usurperait une adresse du même réseau local (ici, 2001:db8:32:a17::b00c qui se ferait passer pour 2001:db8:32:a17::babe). Dans des cas moins triviaux (routeurs avec beaucoup d'interfaces et ayant de nombreux préfixes derrière eux), pour savoir quels préfixes sont acceptables, le routeur peut simplement consulter une ACL maintenue manuellement ou alors utiliser RPF (RFC 3704).
  • Un cas intéressant est le premier routeur du FAI, le routeur PE : le RFC 2827 demande explicitement que tous ces routeurs filtrent les paquets ayant une adresse IP qui n'est pas dans le préfixe alloué au client (voir aussi la section 4.2.1 de notre RFC). À noter qu'il ne peut pas aller plus loin et valider chaque adresse : cela nécessiterait que le client fasse ce filtrage (cf. les cas plus haut).
  • Enfin, au niveau des routeurs NNI, on est très loin de la source et tout filtrage devient difficile. Qui plus est, on ne sait pas si l'opérateur en place filtre dans son propre réseau ou pas. L'ancien projet SAVA (précuseur de SAVI, mais beaucoup plus ambitieux) espérait monter une infrastructure de transmission d'informations sur la validation, permettant d'indiquer aux autres opérateurs l'étendue du filtrage qu'on avait fait sur son réseau. Le projet ayant été abandonné, il ne reste que les solutions non techniques comme de tenter de faire signer des engagements de validation d'adresse IP source à ses pairs BGP, en mettant ceux qui ne signent pas dans dans un « enfer » par exemple en étiquetant leurs annonces de préfixes avec une communauté BGP ad hoc (RFC 1997) et en la transmettant aux autres pairs (idée qui me semble personnellement très peu réaliste).

En pratique, il y a des tas de détails qui compliquent la validation d'adresse IP source. Par exemple, pour un commutateur réseau, le cas simple est celui où il y a une et une seule machine derrière chaque port physique et où chaque adresse MAC ne correspond qu'à une seule adresse IP. Si ce n'est pas le cas, le problème devient plus difficile. Pensez par exemple à une machine physique, connectée par le port d'un commutateur mais portant plusieurs machines virtuelles, chacune avec sa propre adresse IP et sans doute sa propre adresse MAC. Ce cas est en fait un commutateur interne, le commutateur physique n'étant que le deuxième commutateur sur le trajet et n'ayant donc que des capacités de validtaion limitées. Idéalement, c'est le commutateur virtuel dans le système de virtualisation qui devrait faire respecter les règles SAVI, mais l'administrateur réseaux n'en a pas forcément le contrôle et ne lui fait pas forcément confiance.

Pour apprendre le lien entre une adresse MAC et une adresse IPv4, la meilleure solution pour un commutateur est d'écouter les requêtes et les réponses DHCP et de considérer qu'elles font autorité au sujet de ce lien (cf. RFC 7513). Par exemple, en voyant passer cette réponse (vue avec tcpdump) :

09:49:23.191187 00:10:db:ff:40:70 > 18:03:73:66:e5:68, ethertype IPv4 (0x0800), length 368: (tos 0x0, ttl 64, id 16537, offset 0, flags [none], proto UDP (17), length 354)
    192.0.2.20.67 > 192.0.2.54.68: BOOTP/DHCP, Reply, length 326, hops 1, xid 0x903b4b00, Flags [none]
	  Your-IP 192.0.2.54
	  Client-Ethernet-Address 18:03:73:66:e5:68
          ...

Le commutateur sait alors que l'adresse IP 192.0.2.54 a été allouée à 18:03:73:66:e5:68 et qu'un paquet IP dont l'adresse MAC source serait 18:03:73:66:e5:68 et l'adresse IP source serait autre chose que 192.0.2.54 est probablement une usurpation et doit être jeté.

Pour IPv6, outre le trafic DHCP, le commutateur doit écouter les paquets DAD (Duplicate Address Detection) du protocole d'auto-configuration (RFC 4862). Le commutateur sera alors au courant des adresses IP légitimement enregistrées, et de l'adresse MAC correspondante, et pourra se servir de cette information pour valider. Par contre, contrairement à ce qu'on pourrait penser, le protocole d'authentification 802.1x n'aide pas : il authentifie un utilisateur mais ne limite pas les adresses IP qu'il peut utiliser. Enfin, il existe des techniques cryptographiques qui pourraient être utiles pour SAVI comme le SEND du RFC 3971 mais qui sont tellement peu déployées qu'on ne peut pas réellement compter dessus.

Certaines topologies de réseau, quoique parfaitement légales, peuvent sérieusement handicaper SAVI (section 5). Par exemple, si toutes les adresses sont statiques et stables, le problème est relativement bien circonscrit. Mais dans beaucoup de réseaux, ce n'est pas le cas et des adresses sont attribuées dynamiquement. Une même adresse IP sera, dans le temps, allouée à plusieurs adresses MAC et une même adresse MAC n'aura pas forcément la même adresse IP à chaque visite de ce réseau. (Ceux qui utilisent arpwatch sur un tel réseau savent le nombre d'« alarmes » que cela génère. SAVI a exactement le même problème.) D'autre part, si certaines machines sont simples (une adresses MAC, une adresse IP), d'autres sont plus complexes pour le validateur. Un exemple typique est un routeur. Par définition, il émet sur le réseau local des paquets avec sa propre adresse MAC mais des adresses IP source qui ne sont pas la sienne. Il est donc difficile de valider ces paquets.

Autre cas rigolo, notamment en cas de virtualisation : si une machine se déplace dans le data center mais garde son adresse IP. Les commutateurs vont devoir oublier la vieille information sur le port où est connecté cette machine et apprendre la nouvelle. (On appelle cela « mettre à jour son état SAVI ».)

La mobilité entraîne aussi des problèmes. Dans IP, elle peut se réaliser de plusieurs façons. Dans l'une, dite « en jambe de chien », la machine mobile émet des paquets avec son adresse IP source stable (home address), quel que soit le réseau physique où elle est attachée. Un tel mécanisme est évidemment incompatible avec toute solution de validation. Il faut donc que tous les paquets du mobile, aussi bien en émission qu'en réception, soient relayés par la station de base située sur son réseau d'attachement habituel.

Un petit mot aussi sur IPv6 : il crée des difficultés supplémentaires en raison de l'auto-configuration, très pratique mais, par son caractère local, non contrôlé centralement, pas forcément très sûre. Et son espace d'adressage très large (une bonne chose, et la principale raison pour laquelle il est important de déployer IPv6) a comme effet de bord la facilité à utiliser beaucoup d'adresses usurpées. En IPv4, un usurpateur a en théorie 2^32 adresses à usurper et, en pratique, plutôt moins de 2^24 (uniquement celles de son réseau local). En IPv6, même si on arrive à limiter l'usurpateur à son réseau local, il aura 2^64 adresses, ce qui permet de court-circuiter certains mécanismes de sécurité.

La section 6 revient en détail sur la question de la granularité de la validation. Aujourd'hui, il est relativement facile d'empêcher les usurpations inter-sites (où un attaquant prend l'adresse IP d'une machine sur un autre site). Mais empêcher les usurpations intra-sites est plus complexe or, justement, la plupart des attaques viennent de l'intérieur.

Notez que SAVI se limite aux couches basses : il n'est pas prévu de vérifier les adresses IP qui apparaissent dans les applications (par exemple dans le champ Received: des messages formatés suivant le RFC 5322).

Enfin, la section 7 revient sur les questions de sécurité à un haut niveau. Elle rappelle que SAVI n'a pas pour but de produire des preuves, au sens judiciaire du terme (dans le meilleur cas, la validation permet de s'assurer de l'adresse IP, mais certaines machines sont multi-utilisateurs). Elle rappelle aussi que SAVI est une technique relativement légère et que, même si elle était massivement déployé, il ne faudrait pas utiliser les adresses IP source comme authentiques. La seule solution fiable pour être certain de l'identité de son correspondant est la cryptographie.

Cette section 7 revient aussi en détail sur les conséquences de SAVI pour la vie privée. Une adresse IP peut être vue, dans certains cas, comme une donnée identifiant une personne et le fait de la valider a donc des implications. Le RFC note bien que la validation SAVI ne nécessite pas d'enregistrer de l'information et que, si on réalise cet enregistrement avec des adresses IP, on peut engager sa responsabilité morale et/ou légale.

Aujourd'hui, des fonctions de type SAVI sont présentes dans pas mal de systèmes (par exemple les commutateurs haut de gamme) mais pas forcément toujours activées. Le RFC 5210 contient un compte-rendu d'expériences à ce sujet.


Téléchargez le RFC 6959


L'article seul

RFC 6956: ForCES Logical Function Block (LFB) Library

Date de publication du RFC : Juin 2013
Auteur(s) du RFC : W. Wang (Zhejiang Gongshang University), E. Haleplidis (University of Patras), K. Ogawa (NTT Corporation), C. Li (Hangzhou DPtech), J. Halpern (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF forces
Première rédaction de cet article le 29 juin 2013


Le protocole ForCES vise à permettre la création d'équipements réseaux (par exemple des routeurs) en assemblant des pièces d'origines diverses, parlant un protocole commun et pouvant donc interagir. Ce RFC marque l'achèvement de la première (et très longue) phase de ForCES, la normalisation complète de ce protocole. Notre RFC 6956 décrit la bibliothèque standard de ForCES, les parties d'un routeur qu'on trouvera partout et qui assurent les fonctions indispensables comme faire suivre un paquet IP.

ForCES peut servir à bien d'autres choses et il y aura aussi des bibliothèques pour d'autres équipements que les routeurs, et aussi des bibliothèques non-standard, développées par tel ou tel projet. Mais pour atteindre l'objectif premier de ForCES, créer un routeur par assemblage de pièces standards, cette bibliothèque « routeur » était le dernier élement manquant.

Avant de lire ce RFC 6956, il faut bien se pénétrer du cadre général (RFC 3746), du protocole (RFC 5810) et du modèle de données (RFC 5812). J'en extrais quelques termes qu'il faut connaître :

  • NE ou Network Element, l'engin complet (un routeur, un commutateur, etc).
  • CE ou Control Element, la partie du NE qui fait tourner les protocoles de contrôle et de signalisation (pour un routeur, OSPF, BGP, etc).
  • FE ou Forwarding Element, la partie de l'engin qui traite les paquets (pour un routeur, qui les fait suivre d'une interface à l'autre). CE et FE se parlent en suivant le protocole ForCES. Un NE comprend au moins un CE et un FE.
  • LFB ou Logical Function Block, c'est le concept qui fait l'objet de ce RFC. Un LFB est une fonction d'un FE, contrôlée par le CE. Un FE typique met en œuvre plusieurs fonctions (par exemple : faire suivre les paquets, filtrer les paquets, compter les paquets et chacune de ces trois fonctions est représentée par un LFB). Un CE typique va donc utiliser le protocole ForCES pour configurer les LFB (« arrête de faire suivre les paquets », « coupe l'interface Ethernet/0/2 », etc). Un LFB est une fonction logique : dans la matériel, on ne retrouve pas forcément ce concept.
  • Classe de LFB et instance de LFB sont des concepts empruntés à la programmation objet. L'idée est qu'on définit des classes de LFB et que le LFB dans un FE donné est une instance d'une de ces classes.
  • Un « port » dans ce RFC est une interface physique du routeur.

La bibliothèque composée des classes définies dans ce RFC 6956 permet de réaliser un routeur complet, mettant en œuvre toutes les fonctions obligatoires du RFC 1812, notamment :

  • Encapsuler et décapsuler les paquets pour la couche 2 (Ethernet, par exemple),
  • Envoyer et recevoir des paquets de taille allant jusqu'à la MTU du lien, fragmenter les autres (pour IPv4),
  • Traduire les adresses IP en adresses de la couche 2 (par exemple avec ARP),
  • Gérer ICMP, et notamment créer et envoyer les messages d'erreur ICMP en réponse à des problèmes, ou bien lorsque le TTL tombe à zéro,
  • Gérer les tampons d'entrée/sortie, la congestion, un juste traitement des différents paquets,
  • Trouver le routeur suivant (next hop) lorsqu'il faut transmettre un paquet,
  • Être capable de faire tourner un IGP comme OSPF, dans certains cas un EGP comme BGP, et accepter évidemment de simples routes statiques,
  • Avoir toutes les fonctions de gestion du réseau qu'on attend : statistiques, déboguage, journalisation...

Place maintenant au cœur de ce RFC, les classes qui y sont définies. Le choix du groupe de travail forces (section 3.2) a été de privilégier la souplesse en définissant plutôt trop de classes que pas assez. Chaque classe ne va donc effectuer qu'un minimum de fonctions, être logiquement séparée des autres classes et notre routeur devra donc mettre en œuvre beaucoup de classes. Cela rend donc le RFC très long et je ne vais donc pas parler de toutes les classes, seulement de quelques unes choisies comme exemples. Pour la totalité des classes, vous devez lire le RFC.

Les définitions des classes s'appuient sur un certain nombre de types définis en section 4. Le RFC 5812 avait normalisé les types de base comme uint32, char ou boolean. Notre RFC y ajoute quelques types atomiques comme IPv4Addr, IPv6Addr, IEEEMAC (une adresse MAC), PortStatusType (permettant d'indiquer si le port est activé ou non et s'il fonctionne), VlanIDType pour le numéro de VLAN, etc. Il définit également des types composés comme MACInStatsType (une entrée dans le tableau de statistiques pour les paquets entrants, analysés à la couche 2), IPv6PrefixInfoType (un préfixe IPv6), IPv4UcastLPMStatsType (une entrée dans le tableau de statistiques pour les paquets IPv4), etc. Logiquement, les tableaux qui utilisent ces types sont également définis comme IPv6PrefixTableType (un tableau de préfixes IPv6) ou VlanInputTableType (un tableau de VLAN).

Un NE manipule des paquets donc il y a évidemment des types de paquets parmi lesquels EthernetII, IPv4, IPv6, et même Arbitrary pour des paquets quelconques.

Le tout est formellement décrit en XML dans la section 4.4. Ainsi, une adresse IPv4 est :


<dataTypeDef>
         <name>IPv4Addr</name>
         <synopsis>IPv4 address</synopsis>
         <typeRef>byte[4]</typeRef>
</dataTypeDef>

et une IPv6 est :


<dataTypeDef>
         <name>IPv6Addr</name>
         <synopsis>IPv6 address</synopsis>
         <typeRef>byte[16]</typeRef>
</dataTypeDef>

Un type atomique comme la capacité du lien est définie par :


<dataTypeDef>
        <name>LANSpeedType</name>
        <synopsis>LAN speed type</synopsis>
        <atomic>
         <baseType>uint32</baseType>
         <specialValues>
           <specialValue value="0x00000001">
            <name>LAN_SPEED_10M</name>
            <synopsis>10M Ethernet</synopsis>
           </specialValue>
           <specialValue value="0x00000002">
            <name>LAN_SPEED_100M</name>
            <synopsis>100M Ethernet</synopsis>
           </specialValue>
...

Même chose pour le PortStatusType mentionné plus haut :


<dataTypeDef>
        <name>PortStatusType</name>
        <synopsis>
          Type for port status, used for both administrative and
          operative status.
        </synopsis>
        <atomic>
         <baseType>uchar</baseType>
         <specialValues>
           <specialValue value="0">
            <name>Disabled</name>
            <synopsis>Port disabled</synopsis>
           </specialValue>
           <specialValue value="1">
            <name>Up</name>
            <synopsis>Port up</synopsis>
           </specialValue>
           <specialValue value="2">
            <name>Down</name>
            <synopsis>Port down</synopsis>
           </specialValue>
         </specialValues>
        </atomic>
      </dataTypeDef>
<dataTypeDef>

Et les types structurés ? Un exemple est celui des statistiques sur les paquets sortants, qui a deux composants (les champs des objets), un pour les paquets transmis et un pour les paquets jetés :


<dataTypeDef>
         <name>MACOutStatsType</name>
         <synopsis>
           Data type defined for statistics in EtherMACOut LFB.
         </synopsis>
         <struct>
            <component componentID="1">
               <name>NumPacketsTransmitted</name>
               <synopsis>Number of packets transmitted</synopsis>
               <typeRef>uint64</typeRef>
            </component>
            <component componentID="2">
               <name>NumPacketsDropped</name>
               <synopsis>Number of packets dropped</synopsis>
               <typeRef>uint64</typeRef>
            </component>
         </struct>
</dataTypeDef>

Un autre exemple est le préfixe IPv6, qui réutilise le type atomique IPv6Addr :


<dataTypeDef>
         <name>IPv6PrefixInfoType</name>
         <synopsis>Data type for entry of IPv6 longest prefix match
          table in IPv6UcastLPM LFB. The destination IPv6 address
          of every input packet is used as a search key to look up
          the table to find out a next hop selector.</synopsis>
         <struct>
            <component componentID="1">
               <name>IPv6Address</name>
               <synopsis>The destination IPv6 address</synopsis>
               <typeRef>IPv6Addr</typeRef>
            </component>
            <component componentID="2">
               <name>Prefixlen</name>
               <synopsis>The prefix length</synopsis>
               <atomic>
                  <baseType>uchar</baseType>
                  <rangeRestriction>
                     <allowedRange min="0" max="32"/>
                  </rangeRestriction>
               </atomic>
            </component>
...

Une fois tous ces types définis (et cela prend un bon bout du RFC), on peut les utiliser pour bâtir les classes (section 5). Chaque classe va être un gabarit dont on tirera les instances. Premier exemple : notre routeur ForCES va évidemment avoir besoin de connaître Ethernet et de traiter des paquets Ethernet, en envoi et en réception. Ethernet étant très varié, commençons par un LFB (Logical Function Block) qui représente le niveau physique, EtherPHYCop. Ce LFB (cette partie logique d'un routeur) a des composants pour indiquer l'état du port (AdminStatus et OperStatus), composants qui peuvent être lus et modifiés via le protocole ForCES. Ce LFB peut aussi générer des événements comme par exemple le changement d'état d'un port (PHYPortStatusChanged).

Au niveau au dessus (couche 2), il y a le LFB EtherMACIn. C'est par exemple là que se trouve le composant LocalMACAddresses qui indique l'adresse MAC. ou bien le composant PromiscuousMode qui dit si on veut recevoir (ou pas) tous les paquets, même adressés à une autre machine.

Rappelez-vous : cette bibliothèque standard de ForCES privilégie la souplesse, et crée donc beaucoup de LFB, pour pouvoir les arranger comme souhaité. Rien que pour Ethernet, il y en a encore plusieurs comme EtherEncap qui modélise les fonctions d'encapsulation et de décapsulation des trames (ajout ou retrait des en-têtes Ethernet).

Mais on ne peut pas passer toute la journée sur les couches basses. Pour « construire » un routeur par assemblage de LFB, il nous faut maintenant des fonctions de manipulation d'IP. C'est le cas du LFB IPv6Validator qui représente les fonctions de validation d'un paquet (avant qu'on décide de le traiter, ou de le jeter s'il est invalide). On suit le RFC 2460 et on considère comme invalide (ne devant pas être transmis) les paquets ayant une taile inférieure à la taille minimale, les paquets ayant une adresse source ou destination inacceptable, etc. Il y a aussi des paquets nommés « exceptionnels » qui, sans être à proprement parler invalides, ne pourront pas être transmis normalement (par exemple ceux avec un hop limit descendu à zéro).

Et, ensuite, le travail sera fait par les LFB de transmission. Oui, ils sont plusieurs. Pour IPv6, au moins IPv6UcastLPM (trouver le LPM, Longest Prefix Match, dans la table) et IPv6NextHop (sélection du routeur suivant), sans compter des futurs LFB optionnels, par exemple pour mettre en œuvre RPF.

Les LFB sont eux aussi formalisés en XML (section 6). Par exemple, le dernier que nous avons vu, IPv6NextHop, sera :


      <LFBClassDef LFBClassID="13">
         <name>IPv6NextHop</name>
         <synopsis>
           The LFB abstracts the process of next hop information
           application to IPv6 packets. It receives an IPv6 packet
           with an associated next hop identifier (HopSelector),
           uses the identifier as a table index to look up a next hop
           table to find an appropriate output port.
         </synopsis>
         <inputPorts>
            <inputPort group="false">
               <name>PktsIn</name>
               <synopsis>
                 A port for input of unicast IPv6 packets, along with
                 a HopSelector metadata.
                </synopsis>
              ...
            </inputPort>
         </inputPorts>
         <outputPorts>
            ...
         </outputPorts>
         <components>
            <component componentID="1">
               <name>IPv6NextHopTable</name>
               <synopsis>
                 The IPv6NextHopTable component. A HopSelector is used
                 to match the table index to find out a row which
                 contains the next hop information result.
               </synopsis>
               <typeRef>IPv6NextHopTableType</typeRef>
            </component>
         </components>
      </LFBClassDef>

Si la tête commence à vous tourner sérieusement, c'est sans doute normal et prévu. Les auteurs du RFC ont pensé à vous et inclus une section 7 qui décrit comment on crée une fonction de haut niveau à partir des LFB de cette bibiothèque standard. Leur premier exemple est la transmission de paquets IPv4 et le dessin ne compte pas moins de treize LFB... (Dont, il est vrai, neuf juste pour Ethernet.) Pour ajouter ARP, cela prend sept LFB (certains sont communs par exemple EtherEncap est utilisé à la fois par la transmission de paquets IPv4 et par ARP).

Les classes des LFB sont désormais dans un registre IANA, ce qui permettra d'en ajouter plus facilement d'autres.

Voilà, arrivé à ce stade, on a de quoi « fabriquer » un routeur ou plus exactement de quoi le modéliser. En pratique, les vrais routeurs seront bien différents mais ils exporteront aux clients ForCES des fonctions représentées par ces LFB standards, fonctions qu'on pourra configurer avec Forces.


Téléchargez le RFC 6956


L'article seul

RFC 6955: Diffie-Hellman Proof-of-Possession Algorithms

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : J. Schaad (Soaring Hawk Consulting), H. Prafullchandra (Hy-Trust)
Chemin des normes
Première rédaction de cet article le 30 mai 2013


Lorsqu'on détient une clé cryptographique privée et qu'on veut le prouver à un correspondant, la méthode la plus simple et la plus standard est de signer un message avec cette clé et de l'envoyer audit correspondant, qui, en vérifiant la signature, s'assurera qu'on était bien en possession de la clé privée. Mais dans certains cas, signer n'est pas possible. Ce RFC décrit trois algorithmes qui permettent de prouver qu'on connait une clé, sans signer. Il remplace le RFC 2875.

Ce test de POP (Proof Of Possession) est un de ceux que doit faire, par exemple, une autorité de certification, avant de signer un certificat. (Le RFC 4211, annexe C, explique pourquoi c'est important.) Ainsi, une CSR (demande de signature d'un certificat) faite par OpenSSL est signée et cela peut se vérifier :

% openssl req  -verify -in server.csr -noout       
verify OK

Le format CRMF du RFC 4211 et le format PKCS#10 permettent tous les deux d'envoyer une demande de signature de certificat à une AC mais seul CRMF a un moyen d'inclure une POP pour les algorithmes ne permettant pas de signature. PKCS#10 (RFC 2986) n'a rien. Cela existe, de tels algorithmes, ne permettant pas de signature ? Oui, c'est le cas de Diffie-Hellman et de ECDH.

Les trois algorithmes de POP de notre RFC sont le Diffie-Hellman statique en section 4, le logarithme discret en section 6 et l'ECDH statique en section 6. Ne me demandez pas de vous les expliquer, cela dépasse largement mes compétences en cryptographie. Lisez le RFC pour cela. (Et révisez le RFC 6090 pour le troisième, qui utilise les courbes elliptiques.) Notre RFC 6955 fournit les algorithmes et les modules ASN.1 qui les décrivent.

La section 1.1 décrit les changements depuis le RFC 2875. Les deux algorithmes du précédent RFC ont été réécrits pour permettra leur paramétrisation par rapport à la fonction de condensation (obligatoirement SHA-1 dans l'ancien RFC, alors que plusieurs fonctions sont désormais possibles, notamment la famille SHA-2). Et un troisième algorithme a été ajouté, pour ECDH.


Téléchargez le RFC 6955


L'article seul

RFC 6952: Analysis of BGP, LDP, PCEP and MSDP Issues According to KARP Design Guide

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : M. Jethanandani (Ciena Corporation), K. Patel (Cisco Systems), L. Zheng (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF karp
Première rédaction de cet article le 25 mai 2013


Dans le cadre du travail du groupe KARP de l'IETF, consacré à la sécurisation des protocoles de routage de l'Internet, ce RFC est consacré à l'analyse de la sécurité des protocoles de routage utilisant TCP, notamment BGP.

Deux petits rappels : KARP travaille sur les protocoles eux-mêmes, ni sur le contenu des informations transmises (c'est le rôle de SIDR, qui a produit le système RPKI+ROA), ni sur les pratiques quotidiennes d'administration des routeurs. Son rôle est d'améliorer la sécurité des protocoles, et pour cela il commence par des analyses de la sécurité des protocoles existants, suivant une méthode décrite dans le RFC 6518. Il y avait déjà eu une analyse d'OSPF (RFC 6863) et ce nouveau RFC s'attaque à des protocoles très différents mais qui ont en commun d'utiliser TCP comme transport : BGP (RFC 4271) et LDP (RFC 5036), ainsi que les moins connus PCEP (Path Computation Element Communication Protocol, RFC 5440) et MSDP (RFC 3618). Ils appartiennent tous à la catégorie un-vers-un du RFC 6518 (les messages d'un routeur sont transmis à un seul autre routeur).

Donc, aujourd'hui, quels sont les risques de sécurité pour ces protocoles et les défenses existantes ? D'abord, ceux et celles spécifiques à la couche transport. Il y a les attaques par déni de service et les attaques où l'ennemi va tenter d'établir une session avec sa victime, sans en avoir normalement le droit. Parmi les contre-mesures (RFC 4732 pour un point de vue plus général), il y a des ACL par adresse IP (tous ces protocoles utilisant TCP, il n'y a normalement pas de possibilité pour un attaquant en dehors du chemin d'usurper une adresse IP, si tout le monde suit bien le RFC 4953 et le RFC 5961) et le fait d'écouter les connexions entrantes uniquement sur les interfaces où on s'attend à avoir des pairs. Pour éviter les attaques de méchants lointains, il y a la technique GTSM du RFC 5082, qui consiste à n'accepter des paquets que s'ils ont un TTL maximal (ou proche du maximum).

Cela ne suffit pas contre des assaillants situés sur le chemin (par exemple parce qu'ils sont sur le réseau local). Ceux-ci peuvent établir une connexion avec une fausse adresse IP, ou bien simplement envoyer des resets TCP pour couper les sessions existantes (notez que TLS ou SSH ne protégeraient pas contre ce dernier risque car ils fonctionnent au-dessus de TCP). Pour assurer l'authentification et l'intégrité de la connexion TCP, on a l'« authentification MD5 » du RFC 2385, normalement remplacée par l'AO du RFC 5925. AO est très supérieur, fournissant notamment l'agilité cryptographique (la possibilité de changer d'algorithme si la cryptanalyse en a trop affaibli un, ce qui est le cas de MD5). Mais AO est loin d'avoir remplacé MD5.

Et puis il y a les problèmes qui ne dépendent pas du transport utilisé, comme l'absence d'un protocole de gestion des clés (KMP pour Key Management Protocol). Actuellement, la gestion des clés dans tous ces protocoles est purement manuelle et, résultat, les clés cryptographiques des routeurs ne sont quasiment jamais changées, même lorsqu'un administrateur quitte la société.

Maintenant, place à chaque protocole individuellement. Le RFC fait une présentation de chaque protocole (section 2), puis de l'état de sécurité idéal qu'on souhaite atteindre (section 3), puis de la différence entre l'état actuel et cet idéal (section 4). Enfin, la section 5 étudie les questions de transition vers une meilleure solution de sécurité (tous ces protocoles étant pair-à-pair, il faut que les deux pairs soient d'accord pour la nouvelle technique de sécurité). Ici, je procède différemment en traitant tous les aspects de chaque protocole successivement (enfin, pas chacun, je ne couvre que BGP et LDP, ne connaissant pas vraiment PCEP et MSDP). Donc, honneur à BGP pour commencer, puisque c'est sans doute le protocole de routage le plus important pour l'Internet (section 2.3). Comme il ne fonctionne que sur TCP, sa sécurité est en bonne partie celle de ce protocole de transport. Autrement, il devra attendre le déploiement d'AO, puis d'un KMP pour que sa sécurité s'améliore.

LDP, lui, est utilisé par MPLS et le RFC général de sécurité sur MPLS, le RFC 5920 est donc une utile lecture, ainsi que la section 5 du RFC 5036. LDP (sections 2.4, 3.1 et 4.1 de notre RFC) peut, lui, fonctionner sur TCP ou sur UDP. Ce dernier sert notamment aux messages Hello d'établissement d'une session. Cet établissement n'est donc pas protégé par les mesures de sécurité de TCP. En fait, il n'existe même quasiment aucune protection pour ces messages. Et pour TCP ? LDP peut utiliser l'authentification MD5 du RFC 2385 mais on a vu que MD5 n'était pas conseillé (RFC 6151 et section 2.9 du RFC 5036) et LDP ne permet pas encore d'utiliser AO (RFC 5925).

L'état de sécurité idéal pour LDP serait clairement un état où les messages Hello seraient authentifiés. En attendant, les contre-mesures minimales sont de n'accepter des Hello que sur les interfaces réseau qui en ont réellement besoin, et d'utiliser GSTM. Cela ne supprime pas toutes les attaques, mais un travail est déjà en cours pour l'authentification des Hello (Internet-Draft draft-zheng-mpls-ldp-hello-crypto-auth).


Téléchargez le RFC 6952


L'article seul

RFC 6951: UDP Encapsulation of SCTP Packets for End-Host to End-Host Communication

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : M. Tuexen (Muenster Univ. of Appl. Sciences), R. R. Stewart (Adara Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 30 mai 2013


Normalement, un nouveau protocole de transport comme SCTP ne devrait avoir besoin de l'autorisation de personne pour être déployé entre deux machines majeures et consentantes. Le modèle de l'Internet, fondé sur le protocole IP, permet aux machines terminales, sans autorisation d'un intermédiaire, de communiquer en mettant ce qu'elles veulent dans les paquets IP. Cela, c'est la théorie. En pratique, par incompétence, sécurité ultra-rigide ou paresse, des tas d'intermédiaires se permettent de se placer sur le chemin entre deux machines et ne laissent passer qu'un petit nombre de protocoles de transport (typiquement uniquement TCP et UDP). Un nouvel arrivé (SCTP a quand même été normalisé dans le RFC 2960 en 2000 donc, « nouveau » est relatif ; la norme actuelle est le RFC 4960) a donc le plus grand mal à se faire une place au soleil. On en est donc réduit à des astuces plus ou moins propres comme celle décrite dans ce RFC : encapsuler SCTP dans de l'UDP.

La principale cible visée est donc le grand nombre de machines coincées derrière un routeur NAT. Mais cette encapsulation peut aussi servir pour mettre en œuvre SCTP sans avoir accès au noyau, entièrement dans une application, sans avoir de privilèges particulier (ce qui est souvent nécessaire pour implémenter un protocole de transport). Attention, il ne s'agit pas de faire un tunnel pour mettre en relation deux réseaux, mais de faire communiquer deux machines terminales qui voudraient faire du SCTP et qui en sont empêchées par une middlebox (cf. section 4).

Pourquoi UDP, au fait, et pas TCP ? Parce que SCTP fournit tous les services de TCP (notamment le contrôle de congestion et la fiabilité) et qu'il ferait donc double emploi avec TCP.

Notez que rien n'empêcherait de faire un routeur NAT qui permettrait SCTP, comme ils permettent aujourd'hui de faire du TCP et de l'UDP. C'est juste que de tels routeurs, s'ils existent, sont très rares.

Bon, et comment SCTP sur UDP fonctionne (section 5) ? On utilise par défaut le port de destination et de source 9899. Toutefois, celui-ci aura pu être modifié en route par un routeur NAT et le port à l'arrivée sera donc peut-être différent. D'autre part, certaines machines peuvent se trouver dans l'obigation d'écouter sur un autre port et il faut donc qu'une mise en œuvre de ce RFC soit capable d'utiliser un port différent par correspondant (cf. l'API plus loin), et de se souvenir de ces ports. On met le paquet SCTP dans un paquet UDP qui sera lui-même transporté dans IP (peut-être avec des en-têtes d'extension, dans le cas d'IPv6). La somme de contrôle UDP doit être mise (même en IPv4 où elle est normalement facultative ; et, pour IPv6, on n'a pas le droit d'utiliser l'exception du RFC 6935).

C'est simple mais il y a quelques petits pièges. D'abord, avec les messages ICMP (section 5.5) : lors de leur réception, il n'y aura pas forcément assez d'octets du message original pour trouver l'association SCTP à qui envoyer le message ICMP. Il faudra alors jeter ce dernier sans remords. La mise en œuvre de SCTP doit donc être capable de se débrouiller sans les messages ICMP, dont la réception ne peut pas être garantie.

Deuxième piège, commun à toutes les techniques d'encapsulation, la MTU (section 5.6). SCTP doit penser à diminuer la MTU de la taille de l'en-tête UDP. Et se souvenir qu'ICMP est encore moins garanti lorsqu'on utilise l'encapsulation UDP donc les procédures de découverte de la MTU du chemin (RFC 4820 et RFC 4821) doivent fonctionner même si on ne reçoit pas les messages ICMP.

Dernier piège, mais crucial, le contrôle des adresses IP source des paquets UDP. Pour les associations SCTP à une seule adresse IP, il ne faut pas indiquer l'adresse IP de la machine dans les sous-paquets (chunks) de type INIT (section 3.3.2 du RFC 4960) mais la mettre dans le paquet UDP (ce que fait UDP par défaut). Et si la machine a plusieurs adresses IP, il faut se servir des mécanismes des RFC 5061 et RFC 4895 pour les faire connaître au correspondant, et non pas mettre les adresses IP dans les sous-paquets SCTP car l'intervention d'un routeur NAT modifierait l'adresse source, rendant ces sous-paquets invalides.

Et pour les applications, quels mécanismes sont nécessaires pour faire fonctionner cette encapsulation ? La section 6 propose des changements à l'API du RFC 6458, avec l'ajout d'une option SCTP_REMOTE_UDP_ENCAPS_PORT qui prendra en paramètre une structure :

struct sctp_udpencaps {
     sctp_assoc_t sue_assoc_id;
     struct sockaddr_storage sue_address;
     uint16_t sue_port;
   };

Ce qui permettra de définir/connaître les adresses IP et les ports utilisés par l'encapsulation UDP.

Depuis sa version 9.1, FreeBSD a la capacité d'utiliser cette encapsulation pour envoyer des paquets SCTP. Un portage a été fait vers Mac OS X, disponible en http://sctp.fh-muenster.de.


Téléchargez le RFC 6951


L'article seul

RFC 6950: Architectural Considerations on Application Features in the DNS

Date de publication du RFC : Octobre 2013
Auteur(s) du RFC : J. Peterson (NeuStar), O. Kolkman (NLnet Labs), H. Tschofenig (Nokia Siemens Networks), B. Aboba (Microsoft Corporation)
Pour information
Première rédaction de cet article le 10 octobre 2013


Le DNS est un des plus grands succès de l'Internet : une base de données répartie, fiable, sur laquelle on peut compter, et qui est très souple dans ses usages, lui permettant d'être utilisée pour beaucoup de choses (seuls les journalistes écrivent encore que « le DNS sert à trouver une adresse IP à partir d'un nom de domaine » : la réalité est bien plus riche). Mais, justement, la disponibilité et l'efficacité du DNS font qu'il est utilisé par beaucoup d'applications dont les auteurs ne sont pas forcément conscients des forces et faiblesses du DNS. Ne faudrait-il pas les appeler à réfléchir deux secondes sur ces forces et ces faiblesses ?

Le DNS permet de récupérer des données (quelconques : ce ne sont pas forcément des adresses IP) à partir d'un nom de domaine. Il est même utilisé par des applications dont les identifiants ne sont pas des noms de domaine : une petite transformation pour convertir l'identifiant en nom de domaine et hop (ONS, ENUM, etc). Le premier RFC à avoir décrit l'usage du DNS pour autre chose qu'une correspondance nom->adresse est le RFC 974 en 1986. C'est dire que c'est ancien et cela explique mes critiques sévères des ignorants qui continuent à considérer le DNS comme un simple moyen de trouver des adresses. Depuis ce RFC 974, qui introduisait l'enregistrement MX, l'idée a suivi son chemin. Un mécanisme plus général, le SRV, a été introduit par le RFC 2052 (remplacé depuis par le RFC 2782). Et, pour faire des mécanismes de délégation aussi compliqués qu'on le souhaite, il y a le NAPTR créé par le RFC 2168, généralisé ensuite par le RFC 3401. Enfin, il y a des applications qui mettent simplement leurs données dans le très général et pas structuré enregistrement TXT, ce que fait par exemple DKIM (RFC 6376).

Mais ce succès, comme tous les succès, a aussi son revers : les applications demandent de plus en plus au DNS alors que son vaste déploiement est largement dû à sa focalisation sur un petit nombre de fonctions qu'il réalise très bien. La mentalité fréquente aujourd'hui de « on met tout dans le DNS » (illustrée par un gadget fameux) est parfois en conflit avec les principes du DNS. La confidentialité est un bon exemple : elle était délibérement exclue du cahier des charges du DNS (et à juste titre : lisez le RFC 3414 si vous voulez un exemple de la complexité que la confidentalité apporte à un protocole requête-réponse). Vouloir l'ajouter aujourd'hui risque fort de faire perdre au DNS ses propriétés intéressantes (il n'est pas cité par ce RFC, mais c'est l'une des raisons de l'échec de DNScurve, qui essayait de faire trop de choses). Bien des applications qui veulent utiliser le DNS ont réclamé une certaine dose de confidentialité, alors que le DNS doit une partie de son efficacité au fait que toutes les données sont publiques. Ainsi, un cache n'a pas à s'inquiéter si les données qu'il mémorise doivent être servies à tous ou pas.

Ce nouveau RFC de l'IAB vise donc à aider les concepteurs d'applications en exposant clairement ce que le DNS fait bien, ce qu'il peut faire, et ce qu'il ne sait pas faire. C'est un excellent document pour qui veut comprendre en détail le DNS et, malgré sa longueur, il mérite d'être lu attentivement. Il fournit les informations nécessaires pour que ledit concepteur puisse répondre intelligemment à la question « Dois-je mettre cette information dans le DNS ou bien ailleurs ? » Il complète le RFC 5507, qui restait plutôt sur les questions de syntaxe, alors que ce nouveau RFC 6950 adopte une vue plus générale, plus tournée vers l'architecture du système. Pour le résumer en deux mots : le DNS doit son succès à ce qu'il n'essaie pas de résoudre tous les problèmes mais un ensemble bien précis de problèmes, pour lesquels il est une bonne solution. Comme il existe d'autres protocoles que le DNS, une application ou un service qui envisage d'utiliser le DNS dit sérieusement étudier s'il est vraiment la solution la plus adaptée (parfois oui mais parfois non).

La section 2 de notre RFC présente un certain nombre d'usages du DNS par des applications. Il commence évidemment par le routage du courrier, avec les enregistrements MX. Le MX était la première utilisation du DNS pour faire autre chose que de la simple traduction de nom en adresse IP. En partie droite d'un MX, on trouve le nom du ou des serveurs qui gèrent la messagerie pour le domaine en partie gauche. Bien sûr, une convention de nommage (du genre « le serveur de messagerie de example.org se nomme mail.example.org ») aurait pu jouer un rôle similaire. Mais les MX sont plus souples (le serveur d'un domaine n'est pas obligé d'avoir un nom dans le domaine, cf. RFC 4367) et offrent des possibilités supplémentaires (plusieurs serveurs, avec des priorités différentes). Mais le MX est spécifique au courrier électronique. Les enregistrements SRV, créés par le RFC 2052 (aujourd'hui RFC 2782), ont étendu le principe à tous les protocoles qui voulaient en profiter (avec des choses en plus comme l'indication du numéro de port ou bien comme la répartition de charge). Tous les protocoles créés depuis utilisent ces enregistrements, à la triste exception de HTTP qui, stupidement (l'avis est le mien, il n'est pas dans le RFC), ne fournit pas de mécanisme pour trouver le serveur d'un domaine (obligeant à utiliser des conventions de nommage comme www.example.com ou, pire, à mettre une adresse IP sur le domaine lui-même, et empêchant d'utiliser le DNS pour la répartition de charge et la résilience, ce qu'auraient permis les SRV).

Autre service fourni aux applications par le DNS, les enregistrements NAPTR. L'idée au début était de pouvoir trouver n'importe quel identificateur, même distinct d'un nom de domaine, dans le DNS (RFC 2915). Les NAPTR permettent de spécifier des transformations complexes depuis une famille d'identificateurs, vers les noms de domaine. L'idée est ancienne. Sa première manifestation avait été le domaine in-addr dans le RFC 883 (c'était un TLD à l'époque, il est devenu in-addr.arpa dans le RFC 973). Son but était de permettre de traduire des adresses IP en noms, en convertissant d'abord l'adresse IP en un nom de domaine se terminant en in-addr. Ce genre de transformation textuelle sur un identificateur pour en faire un nom de domaine a ensuite été reprise par tpc.int (RFC 1530, un mécanisme pour router des appels téléphoniques via l'Internet, qui allait déboucher sur ENUM). Ces mécanismes ne changent pas le protocole DNS mais ils changent la manière dont on se sert du DNS, et apportent de nouveaux utilisateurs, ayant de nouvelles attentes.

Une des demandes de ces « nouvelles » applications est de stocker des données quelconques dans le DNS. On peut mettre ce qu'on veut dans un URI (et même directement des données, cf. RFC 2397). Donc, comme un NAPTR mène à un URI, il peut nous mener à n'importe quoi. Mais, avant même cette astuce, le DNS pouvait déjà stocker n'importe quoi. Il existe même un type d'enregistrement, TXT, spécialement prévu pour des données non structurées. La souplesse du TXT et son absence de contraintes ont attiré plein de gens, malgré les conseils de prudence du RFC 5507. Il y a même eu une proposition de structurer le contenu des TXT (RFC 1464).

Bon, mais qui y a-t-il de mal à ce que les gens se servent du DNS pour y mettre des informations ? En combinant les différentes techniques vues ci-dessus, on pourrait faire tenir n'importe quel protocole requête/réponse dans le DNS. Mais ce n'est pas complètement exact. La section 3 décrit les défis auxquels son succès confronte le DNS. Certes, le DNS est une base de données répartie, fiable, et rapide. Mais lorsqu'on dit « base de données », certains utilisateurs voudraient que le DNS fournisse des services classiques des bases de données, comme la confidentialité, le contrôle d'accès, l'introspection (utiliser le protocole d'accès pour découvrir le schéma) et la possibilité de requêtes structurées complexes, un peu comme ce que fournit SQL. Mais le DNS n'a pas été conçu pour cela et ce RFC argumente que, plutôt que de forcer le DNS à fournir ces services, on utiliserait mieux son temps à développer d'autres protocoles ou tout simplement à utiliser d'autres protocoles existants. Le succès du DNS et ses qualités viennent justement de ce qu'il n'essayait pas de tout faire.

Les exemples donnés par le RFC sont tous empruntés au monde ENUM (RFC 6116) mais les questions soulevées ne sont pas spécifiques à ENUM.

D'abord, les critères de recherche : dans le DNS, la clé d'accès est le triplet {nom de domaine, classe, type}, par exemple (en syntaxe dig) www.afnic.fr. IN AAAA, et la correspondance doit être exacte (pas de recherche floue). Or, certains souhaiteraient pouvoir exprimer des requêtes plus riches. Des tentatives ont été faites pour mettre des critères supplémentaires dans le nom de domaine lui-même (par exemple, pour ENUM, tg011.0.0.4.5.4.3.4.1.7.5.1.e164.arpa pour ajouter au nom normal, 0.0.4.5.4.3.4.1.7.5.1.e164.arpa, qui est dérivé du numéro de téléphone, le trunk group tg011) mais cela devient vite pénible lorsque le nombre de critères augmente.

Autre solution envisagée, EDNS (RFC 6891), en passant les critères supplémentaires comme options EDNS. Mais cela ne marche pas comme certains le prévoient car EDNS est de saut en saut et pas de bout en bout : un serveur DNS relais ne va pas transmettre les options EDNS.

Enfin, les requêtes complexes posent un problème pour les caches, si fréquents avec le DNS. Les caches actuels considèrent que la réponse ne varie qu'avec le triplet {nom de domaine, classe, type} et pourrait donc garder en cache à tort des réponses faites à des requêtes plus complexes.

Autre demande fréquente des nouveaux utilisateurs du DNS, avoir des réponses « à la tête du client », dépendant de l'émetteur de la question. Il est par exemple courant aujourd'hui de servir des réponses différentes selon l'adresse IP de la source (option view de BIND). Tant que cela ne sert qu'à présenter des versions adaptés d'un contenu (un portail Web différent selon le pays d'origine de la requête), sans problème de sécurité, ce n'est pas trop grave : une erreur n'aura pas de conséquences trop ennuyeuses. Pour des cas plus sensibles, cela peut être gênant. D'autant plus que l'adresse IP de la source n'est pas celle du vrai client, mais celle du résolveur qu'il utilise. Dans certains cas (Google Public DNS), la distance entre les deux peut être énorme. Une option EDNS a été proposée pour que le résolveur puisse indiquer au serveur faisant autorité la vraie adresse IP du client mais elle n'est pas encore adoptée (entre autres, elle pose des problèmes si le client a une adresse IP privée, genre RFC 1918).

Le DNS a d'autres limites lorsqu'on veut l'utiliser comme base de données générique, par exemple la taille des noms de domaine (limitée à 63 caractères par composant) et la taille des réponses. Quelle limite de taille ? L'ancienne limite de 512 octets n'est normalement plus qu'un souvenir (mais il existe encore des pare-feux bogués ou mal gérés qui imposent cette limite) mais il y a deux autres seuils derrière, la MTU (si la réponse est plus grosse, on risque de la fragmentation) et les 4 096 octets qui sont, en pratique, la limite de la plupart des serveurs. Si la réponse est un URI, notez que le RFC 2397 sur les URI data: indique que ceux-ci doivent être « courts » mais il ne définit pas cet adjectif. Le RFC note que, dans le contexte d'ENUM, stocker des sonneries de téléphone rigolotes sous forme de fichiers MP3 dans un URI data: n'est probablement pas raisonnable.

En outre, le DNS reposant sur UDP, qui ne garantit pas l'adresse IP source, des données de grande taille augmentent les risques d'attaque avec amplification (RFC 4732, section 3). Dans ces attaques, le méchant émet une requête DNS (de petite taille, donc) en usurpant l'adresse IP source de sa victime. Le serveur va alors répondre à celle qu'il croit être l'émetteur et la réponse est souvent bien plus grande que la question (le RFC cite l'exemple d'un certificat stocké dans le DNS, comme dans le RFC 4398). L'attaquant pourra donc obtenir ainsi un trafic plus important que ce qu'il peut lui-même générer. C'est d'ailleurs une des raisons pour lesquels les serveurs de .com, par exemple, limitent leurs réponses à 1 460 octets. Bref, malgré EDNS, on ne peut pas espérer faire passer dans le DNS des données de taille quelconque. Le DNS est prévu pour des informations courtes.

Autre limite du DNS lorsqu'on essaie de s'en servir comme d'une base de données générique, la non-correspondance des frontières administratives avec celles du DNS : les frontières des composants d'un nom de domaine ne sont pas forcément celles qu'on voudrait. Par exemple, pour la téléphonie, les anciennes numérotations étaient très hiérarchiques (et correspondaient donc bien au DNS) alors que, depuis la portabilité des numéros de téléphone, ce n'est plus le cas et il n'est donc pas évident de savoir où déléguer les noms ENUM. Ce n'est pas juste un problème esthétique : le bon fonctionnement du DNS dépend des délégations qui sont « cachées » (gardées en mémoire) dans les résolveurs, et qui épargnent à la racine la grande majorité des requêtes. Avec la portabilité des numéros téléphoniques, il faut interroger la racine ENUM pour tout numéro (puisqu'on ne peut pas savoir à l'avance quel opérateur téléphonique le gère). C'est d'autant plus ennuyeux pour la racine ENUM que les correspondances entre un numéro et un opérateur changent et qu'on souhaite souvent une portabilité rapide (de l'ordre de quinze minutes), peu compatible avec une racine simple et efficace.

Si vous pensez que ce n'est pas si grave, que .com est un espace plat avec de nombreux noms et des changements rapides, ce qui démontre que le DNS peut s'en tirer, pensez que dans les seuls États-Unis, il y a trois cents millions de numéros de téléphone attribués, trois fois la taille de .com.

Le problème n'est évidemment pas spécifique à ENUM : si on créait un mécanisme de portabilité pour les adresses IP, les domaines comme in-addr.arpa auraient les mêmes problèmes.

La section 4 est entièrement consacrée à un problème particulier qui a fait couler beaucoup d'encre, le désir d'avoir des réponses DNS « à la tête du client ». Officiellement, le DNS présent une vue unique à tous les utilisateurs (ce point est développé dans le RFC 2826) qui affirme que les noms doivent être uniques et donc donner un résultat unique. Mais il existe une forte demande pour avoir des noms qui ne fonctionnent que dans un espace privé (à l'intérieur d'une entreprise, par exemple), afin de limiter l'accès à certaines ressources. Il existe plusieurs solutions techniques pour avoir des réponses différentes en local et en public mais aucune n'est parfaitement satisfaisante. Par exemple, si on utilise des noms locaux avec un TLD bidon comme .prive ou .local, ces noms « fuiront » un jour ou l'autre, seront vus à l'extérieur, ce qui générera de la confusion (section 3.3 du RFC 5507).

Bien, après toutes ces critiques et toutes ces limites du DNS, quels conseils pratiques donner à ceux et celles qui voudraient quand même utiliser le DNS ? La section 5 est composée d'excellents conseils pour les développeurs d'applications ou de services utilisant le DNS. En gros, le DNS sera sans doute une bonne solution si le service qui veut l'utiliser a toutes ces propriétés :

  • Les données à publier peuvent être distribuées (et mémorisées dans les caches) en utilisant les mécanismes standards du DNS,
  • Les données sont accessibles par des clés qu'on peut convertir en noms de domaine sans violer leur sémantique,
  • Les clés en question (les noms de domaine) doivent être utilisées dans leur totalité (pas de recherche sur un nom partiel),
  • Les réponses ne dépendent pas du demandeur,
  • Une fois ses informations obtenues, l'application utilisera le DNS pour trouver le pair à contacter.

Si une seule de ces propriétés manque, le DNS n'est peut-être pas la bonne solution pour le problème. À l'inverse, de bons signaux d'alarme, indiquant qu'on utilise le DNS à tort, sont :

  • On a besoin de rajouter des données indiquant les frontières administratives (ce que les applications n'ont normalement pas besoin de connaître),
  • Les identificateurs utilisés ont une sémantique ou un modèle radicalement différent de celui du DNS (par exemple, ils sont dans un espace plat, alors que le DNS doit son efficacité à son modèle hiérarchique),
  • On veut distribuer des données à certaines personnes et pas à d'autres,
  • Les réponses sont de grande taille, poussant les limites du DNS trop loin.

Bon, mais si on n'utilise pas le DNS, alors quoi ? Le RFC suggère que, dans beaucoup de cas de protocole requête/réponse, HTTP convient parfaitement (par exemple, il a de l'authentification, il peut transporter des données de taille quelconque, il est largement déployé...)

Pendant l'élaboration de ce RFC, des commentaires intéressants ont été enregistrés dans le système de suivi des tâches.


Téléchargez le RFC 6950


L'article seul

RFC 6949: RFC Series Format Requirements and Future Development

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : H. Flanagan (RFC Series Editor), N. Brownlee (Independent Submissions Editor)
Pour information
Première rédaction de cet article le 15 mai 2013


Cela fait longtemps que le format des RFC est critiqué, à l'IETF ou ailleurs. Pour d'excellentes raisons (détaillées plus loin), ce format est très ancien et très rigide, sans concessions aux gadgets modernes. Il n'a pas encore été possible de le modifier, à la fois en raison des difficultés de prise de décision au sein de la communauté, et aussi parce que le problème est réellement difficile. Contrairement à ce que prétendent certains yakafokon, trouver un format idéal n'est pas trivial. Ce RFC est la première étape d'une tentative de réforme, commençant par un cahier des charges sur les changements souhaitables. Les règles rigides de formatage (longueur des pages et des lignes) disparaissent, l'Unicode fait son entrée dans les RFC, et la possibilité d'inclure des images apparait.

Une des raisons de la stagnation du projet de changement depuis des années était la réorganisation de la fonction de RFC Editor. Désormais, les nouvelles règles sur cette fonction sont écrites (RFC 6635), une nouvelle RFC Editor a pris ses fonctions, jeune et dynamique (Heather Flanagan, un des auteurs de ce RFC), et il va peut être être enfin possible de faire évoluer le format traditionnel. (Depuis cet article, le nouveau format des RFC a été adopté, cf. RFC 7990.)

Le format actuel est documenté dans le RFC 7322 mais à l'époque de notre RFC, c'était le RFC 2223 qui s'appliquait : texte brut sans enrichissement, en ASCII, pages de 58 lignes, lignes de 72 caractères au maximum, pas de notes de base de page, références croisées par numéro de section et pas de page, etc. PostScript était autorisé et quelques RFC ont été publiés ainsi. Une tentative de mise à jour de ce RFC, avec écriture d'une proposition de nouvelle version, avait eu lieu en 2004 mais avait été abandonné. J'avais déjà écrit un article détaillé expliquant le pourquoi du format traditionnel et les raisons pour lesquelles il est difficile à changer.

La section 1 de ce RFC commence par rappeler la longue histoire des RFC. Ils ont commencé il y a plus de quarante ans, et dans les débuts, certains étaient écrits à la main (!), d'autres tapés à la machine, d'autres encore produits par les outils de formatage invraisemblables qu'on trouvait sur les mainframes de l'époque. Résultat, certains sont devenus illisibles avec le temps, les outils tombant en désuétude. Ce problème de permanence est un des problèmes les plus cruciaux pour les RFC et explique pourquoi le RFC Editor n'a jamais été très chaud à l'idée d'utiliser le logiciel à la mode du moment : l'informatique en a déjà enterré beaucoup.

Au bout d'un moment, un format standard a émergé, fondé sur du texte brut et un encodage en ASCII. À partir de là, la série des RFC a vécu une longue période de calme et de stabilité et cette permanence (songez aux formats à la mode vite disparus comme WordPerfect) a beaucoup contribué à son succès. On peut relire aujourd'hui sans problème un RFC de 1980 comme le RFC 768. Ce n'est pas que le format ait été jugé parfaitement satisfaisant par tout le monde, ni qu'aucune proposition de changement n'ait été faite, bien au contraire. Mais aucun des ces propositions n'a connu de consensus : toutes résolvaient un problème précis... en en créant plusieurs autres.

Avant de regarder les propositions actuellement sur la table, il faut bien comprendre qu'il y a plusieurs endroits dans le cycle de vie d'un RFC où un format standard est nécessaire ou utile. Cette terminologie est très importante car l'incompréhension de ces étapes du cycle de vie est l'une des causes principales de la confusion des débats sur la réforme des RFC :

  • Un format de soumission, celui dans lequel le futur RFC est remis par l'auteur au RFC Editor. Aujourd'hui, c'est obligatoirement du texte brut, que l'auteur peut accompagner de XML (RFC 7749) s'il le souhaite.
  • Un format de révision, celui avec lequel travaille le RFC Editor. C'est actuellement du nroff, pour lequel il est de plus en plus dur de trouver des outils.
  • Un format de publication dans lequel le RFC va être distribué au monde. Cette fois, il n'est pas obligé d'être unique. Le même RFC peut être distribué sous plusieurs formats, automatiquement produits. Aujourd'hui, le RFC Editor publie le texte brut et du PDF, d'autres publient du HTML (sur l'excellent http://tools.ietf.org par exemple voici ce RFC), du PDF formaté différemment, etc.
  • Un format canonique qui fait référence en cas de désaccord (rappelez-vous que pas mal de RFC sont des documents normatifs). Actuellement, c'est la version en texte brut.

Évidemment, les choses ont changé depuis (le RFC 2223 date de seize ans...) Quels sont les points qui suscitent le plus de protestations ? D'abord, l'utilisation d'art ASCII et lui seul pour les graphiques. Elle a l'avantage d'encourager les auteurs à écrire des descriptions textuelles claires, plutôt que de passer du temps à faire de jolis dessins. Sans les limitations de l'art ASCII, les diagrammes seraient probablement moins concis. D'un autre côté, des choses comme les automates finis sont vite illisibles en art ASCII et les protocoles où il y a plus de trois acteurs qui interagissent sont difficiles à dessiner. Des graphiques plus élaborés que l'art ASCII permettraient également de représenter des équations mathématiques complexes.

Après les images, le sujet le plus chaud est évidemment l'encodage. ASCII a des tas d'avantages : standard, très répandu, facile à manipuler (outils de recherche, par exemple), plus pratique lorsqu'il faut renumériser un document (oui, le cas s'est déjà produit dans le passé)... Et la langue des RFC étant de toute façon l'anglais, les limites d'ASCII ne sont pas trop graves.

Mais il y a quand même des limites : lorsqu'un RFC parle d'internationalisation (comme le RFC 5890 ou le RFC 6530, ou comme de plus en plus de normes), c'est bien dommage de ne pas pouvoir donner d'exemple lisible dans ce RFC. Devoir écrire U+00c9 pour parler de É est pénible... Des exemples comme ceux de XMPP (RFC 6121, section 5.2.3) bénéficieraient de l'acceptation d'Unicode dans les RFC.

Et certains auteurs de RFC ont des noms qui ne peuvent pas s'écrire correctement en ASCII et ils regrettent de devoir les modifier.

Autres points sur lesquels des gens ont souvent râlé contre le format actuel : la pagination et l'ajustement du texte. La pagination en unités fixes fait vraiment rétro : elle avait un sens quand les RFC étaient souvent imprimés pour être lus mais à l'ère des tablettes, cela semble bien dépassé. Plus compliqué est le cas de l'ajustement du texte. La largeur de colonne fixe qui est la norme actuelle convenait aux VT100 mais pas aux écrans modernes, avec leurs tailles très variables.

Enfin, ce n'est pas tout de définir des formats, il faut aussi des outils qui rendent la production de RFC conforme à ces formats facile (pour avoir une idée des difficultés, lire le RFC 5385). Ces outils doivent-ils être développés à l'IETF ou bien doit-on utiliser des outils standard ? Les exigences de l'IETF sont-elles tellement spécifiques qu'on ne puisse pas utiliser des outils existants ? D'un autre côté, les outils spécifiques donnent plus de souplesse et de pouvoir et, aujourd'hui, il en existe déjà beaucoup (par exemple, la version 2 de xml2rfc - une réécriture complète, abandonnant TCL pour Python, pour produire des RFC suivant le schéma du RFC 7749, est bien meilleure que la précédente) donc on peut dire que le modèle « faisons tout nous-même » marche bien (il y a beaucoup d'informaticiens à l'IETF).

Enfin, s'il y a des réclamations des lecteurs et des auteurs, il y en a aussi du RFC Editor : il voudrait pouvoir abandonner nroff (65 % des RFC aujourd'hui sont soumis au format XML, qu'il faut traduire en nroff au lieu de l'utiliser directement comme format d'entrée pour les différentes publications).

Après les contraintes et les réclamations, les décisions (section 3). D'abord, ce qui ne change pas :

  • Stabilité du RFC une fois publié (jamais de correction mais des errata),
  • Format canonique stable et standard (pas question d'utiliser Word),
  • Le texte brut reste la meilleure solution dans bien des cas donc au moins un des formats de publication doit être le texte brut,
  • Le contenu, par exemple les avertissements juridiques reste comme spécifié dans le RFC 7841.

Ensuite, les nouvelles exigences effectivement retenues, notamment :

  • Documents accessibles même aux personnes en situation de handicap (notez que certaines personnes réclamaient de la couleur dans les RFC, ce qui peut être un problème pour l'accessibilité),
  • Possibilité d'utiliser l'Unicode d'une manière très encadrée, notamment l'ASCII est obligatoire pour le texte normatif (pas de passage global d'ASCII vers UTF-8, mais possibilité d'utiliser UTF-8 par exemple pour les... exemples),
  • Possibilité d'inclure des graphiques en SVG (sous une forme qui reste à déterminer) mais uniquement en noir & blanc,
  • Nécessité de garder un mécanisme permettant des polices de chasse fixe et du texte qui ne s'ajuste pas, pour l'art ASCII et pour les exemples de code source,
  • Format canonique permettant de marquer clairement le code ou assimilé (MIB, ABNF...).
  • Autant que possible, le RFC en cours de révision devrait tenir dans un petit nombre de fichiers (pas une tarball avec des tas de trucs),
  • Le nombre de formats publiés directement par le RFC Editor restera faible, pour que ledit éditeur puisse se concentrer sur le contenu et pas sur la génération de fichiers dans des formats divers.

Et il y a aussi des exigences qui ont été supprimées :

  • La limite de longueur des pages disparait (plus de pages de taille fixe),
  • Même chose pour celle de la longueur des lignes. Ces deux exigences du RFC 2223 ayant disparue, cela ouvre la voie à du texte ajustable,
  • Le contenu ne sera plus obligé d'être à 100 % en ASCII.

Voilà, le cahier des charges est posé, il reste à définir le nouveau format, développer les outils, et déployer le tout... Ce sera pour le prochain épisode. À la réunion IETF 86 a été annoncé le choix de s'appuyer sur le format XML comme format canonique, avec comme formats de publication le texte brut, HTML, PDF et EPUB (voir la FAQ sur ces décisions.) Deux Internet-Drafts sont en cours, un sur le format, draft-rfc-format-flanagan, et un sur le style, draft-flanagan-style. (Depuis, le premier draft a été publié, RFC 7990.)


Téléchargez le RFC 6949


L'article seul

RFC 6948: Some Measurements on World IPv6 Day from End-User Perspective

Date de publication du RFC : Juillet 2013
Auteur(s) du RFC : A. Keranen, J. Arkko (Ericsson)
Pour information
Première rédaction de cet article le 18 juillet 2013


Le World IPv6 Day le 8 juin 2011 avait pour but de tester le comportement d'IPv6 si de nombreux services sur l'Internet activaient ce protocole. On peut noter que rien de spectaculaire ne s'est produit (tant mieux : comme prévu, cette activation n'a rien cassé) mais les impressions ne suffisent pas, il faut aussi mesurer ce qui s'est passé. C'est une de ces mesures que raconte ce RFC ; ses auteurs ont compté le nombre de sites Web qui activaient IPv6 et le résultat que cela avait sur le temps d'établissement d'une connexion, pour un client qui avait déjà IPv4 et IPv6.

Pourquoi est-ce que, alors qu'IPv6 est normalisé depuis de nombreuses années (RFC 2460), certains gros acteurs de l'Internet hésitent toujours à l'activer ? Les raisons vont de la simple passivité à la crainte que, dans certains cas, l'activation d'IPv6 ne dégrade le vécu de l'utilisateur (RFC 6555). Le but des IPv6 days (il y en avait d'autres avant celui de 2011 et d'autres sont apparus après) est à la fois d'encourager les frileux, et de tester pendant 24 h si les craintes sont justifiées (l'IPv6 Day de 2012, considérant que les tests avaient été suffisants et n'avaient guère montré de problèmes, était au contraire prévu pour qu'IPv6 reste activé). Pendant 24 h, le 8 juin 2011, un certain nombre d'opérateurs de services Internet ont donc configuré leurs services pour répondre en IPv6, leur permettant de tester que tout allait bien, et d'avoir une idée du pourcentage de leurs utilisateurs prêts à faire de l'IPv6. Cette configuration impliquait l'activation du protocole sur les différents équipements : serveurs, bien sûr, mais aussi applications car celles-ci gèrent parfois des adresses IP, par exemple à des fins de statistiques, et également les diverses middleboxes qui sont en général le maillon faible de la connectivité Internet.

Une fois qu'IPv6 était disponible et testé sur le service (normalement, bien avant le grand jour), il n'y avait plus qu'à le faire savoir au reste du monde, ce qui se fait en publiant un enregistrement AAAA dans le DNS.

Les mesures décrites dans ce RFC étaient donc le pourcentage de domaines avec des enregistrements AAAA et le temps pris à établir une connexion avec le serveur (ainsi que le pourcentage d'échecs).

Comme l'Internet est grand, l'étude de ce RFC s'est limitée 10  000 sites Web les mieux placés dans le classement d'Alexa (section 3 du RFC). Pour chaque domaine, le logiciel a fait une requête DNS AAAA pour ledomaine, www.ledomaine, et aussi des noms spécifiques à IPv6 comme www.ipv6.ledomaine (noms peu susceptibles d'être utilisés par le visiteur moyen). Ce logiciel de mesure active était écrit en Perl avec le module Net::DNS. Ensuite, un petit programme en C tentait une connexion TCP vers l'adresse obtenue et mesurait le délai. Les mesures ont commencé une semaine avant l'IPv6 day et se sont terminées trois jours après. Le client était situé dans les locaux d'Ericsson à Helsinki.

Quels ont été les résultats ? La section 4 donne les valeurs obtenues, avec des liens vers des graphiques externes (les RFC ne permettent pas de mettre d'images). Le pourcentage d'enregistrements AAAA est ainsi passé de 2,45 % une semaine avant le grand jour et a culminé à 4,91 % pendant. Il est ensuite redescendu (contrairement à 2012, il n'était pas demandé aux sites de garder leurs AAAA), mais est resté plus élevé qu'avant le jour IPv6. Si on prend seulement les 100 sites les mieux classés par Alexa, on trouve la même courbe mais des pourcentages bien plus élevés (les gros sites sont plus sérieux pour ce qui concerne IPv6).

Ce n'est pas tout de publier des adresses IPv6. Encore faut-il que le serveur HTTP situé derrière réponde effectivement. Si on teste toutes les adresses (v4 et v6) en TCP vers les ports 80 et 443, on trouve entre 1 et 3 % d'échecs. Pour IPv6 seul, le pourcentage d'échec est bien plus élevé. Cela ne recoupe pas les résulats vus par DNSdelve (qui montrent nettement moins d'échecs de connexion) probablement parce qu'il s'agit ici d'une journée exceptionnelle, que tout le monde n'a pas bien préparé. Apparemment, certains ont publié leur AAAA avant de configurer leur serveur, leurs routeurs et leurs pare-feux (notez la baisse du pourcentage d'échecs au fur et à mesure que la journée avance).

Et si TCP marche, OK, mais marche-t-il vite ? La connexion prend t-elle plus ou moins de temps en IPv4 et en IPv6 ? Après tout, autrefois, en raison de l'utilisation de mauvaises technologies comme 6to4 (RFC 3056 et RFC 7526) ou comme des tunnels amateurs, IPv6 avait la réputation d'être lent. Qu'en est-il aujourd'hui ? En prenant la médiane et la moyenne, on voit que la différence est très faible (même pour la moyenne, pourtant plus sensible aux petites variations), et qu'IPv6 est un peu plus rapide en temps normal mais plus lent pendant le jour IPv6 (sans doute parce que l'arrivée de nombreux sites mal configurés a fait baisser les chiffres).

En conclusion, le jour IPv6 de 2011 n'a pas été inutile. Le RFC estime qu'avant celui de 2012, il a été une des journées où l'Internet avait changé le plus. Mais les utilisateurs ordinaires n'ont rien remarqué, ce qui était justement le but. Même ceux qui mesurent les temps de connexion n'auront guère vu de différences. Le principal problème est le nombre trop élevé de sites qui publient un AAAA mais avec qui la connexion IPv6 échoue.

Autres mesures équivalentes :


Téléchargez le RFC 6948


L'article seul

RFC 6946: Processing of IPv6 "atomic" fragments

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : F. Gont (Huawei)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 15 mai 2013
Dernière mise à jour le 20 juin 2013


Une particularité amusante de la gestion de la fragmentation dans IPv6 est qu'un paquet peut très bien avoir un en-tête de fragmentation sans être fragmenté du tout. Cela se nomme un « fragment atomique » (le terme est très malheureux car il n'a rien à voir avec les « datagrammes atomiques » du RFC 6864). Ils n'ont aucun intérêt pratique mais sont engendrés par certains systèmes lorsqu'ils reçoivent un message ICMP Packet too big indiquant une MTU inférieure à 1280 octets (la taille miminale pour une MTU IPv6). Le problème est que ces fragments atomiques sont ensuite traités par bien des systèmes comme des vrais fragments, permettant ainsi certaines attaques subtiles. Ce nouveau RFC demande donc que les fragments atomiques soient gérés à part, compte tenu de leurs particularités. (Depuis, le RFC 8021 a carrément rendu ces fragments atomiques obsolètes.)

Si vous voulez réviser les règles de la fragmentation dans IPv6, c'est dans le RFC 2460 (depuis remplacé par le RFC 8200, qui a changé ces règles). Contrairement à IPv4, seules les machines de départ (pas les routeurs intermédiaires) peuvent fragmenter. Si une machine de départ doit envoyer un paquet qui est trop grand pour la MTU, elle le fragmente en plusieurs morceaux, chaque morceau indiquant son décalage par rapport au début du paquet original. Même si ce n'est pas explicite dans ce RFC, le recouvrement des fragments était autorisé, ce qui complique sérieusement le réassemblage et pouvait permettre d'échapper à certains IDS. Il n'est donc pas étonnant que le RFC 5722 ait finalement interdit ces fragments recouvrants. Bon, et les fragments atomiques, ils sont fabriqués pourquoi ? La section 5 du RFC 2460 ne laissait pas le choix aux mises en œuvre d'IPv6 : normalement, elles devaient fabriquer un fragment atomique (un paquet qui a l'en-tête de fragmentation, sans pour autant être fragmenté) si la taille indiquée par le paquet ICMP est inférieure aux 1280 octets minimaux d'IPv6 (c'est pour aider certains mécanismes de traduction IPv4<->IPv6). Dans un fragment atomique, le décalage (fragment offset) sera de zéro (puisque ce fragment est le premier) et le bit M sera à Zéro (puisque ce fragment est le dernier du datagramme). Comme ces paquets ICMP Packet too big ne sont pas authentifiés, même quand c'est possible (section 5.3 du RFC 4443 et RFC 5927), un attaquant peut donc faire fabriquer des fragments atomiques assez facilement. Notez que le RFC 8200 a changé cette règle et donc interdit les fragments atomiques.

Ensuite, comme bien des systèmes traitent ces fragments atomiques en même temps que les fragments normaux, ils peuvent, par exemple, être fusionnés avec d'autres fragments prétendant venir de la même source.

Les problèmes de sécurité liés aux fragments sont bien connus : voir notamment le RFC 5722 mais aussi le RFC 6274 qui décrit ces attaques pour IPv4 (beaucoup sont communes aux deux versions). Ce problème est encore aggravé par le fait que certains systèmes génèrent des identificateurs de fragment trop prévisibles, permettant à l'attaquant de savoir où il devra frapper.

La section 4 décrit ensuite les nouvelles règles, visant à résoudre ce problème. En deux mots, en recevant un fragment atomique (que l'on reconnait à la combinaison décalage=0 et bit M =0), on doit le traiter différemment des autres fragments et il ne peut être réassemblé qu'à partir du fragment unique.

L'annexe A contient un tableau listant un certain nombre de systèmes d'exploitation actuels en indiquant s'ils génèrent des fragments atomiques, et s'ils mettent en œuvre ce RFC (les traitent différemment des autres fragments). La plupart des systèmes génèrent ces fragments atomiques lorsqu'ils reçoivent le faux paquet ICMP Too big (une exception est NetBSD). Et plusieurs d'entre eux (Linux récent, NetBSD, OpenBSD) suivent déjà la recommandation de ce RFC et ne sont donc normalement pas vulnérables aux attaques décrites ici.

Si vous voulez tester vous-même, l'outil frag6 dans la boîte à outils SI6 permet de le faire facilement. D'abord, on envoie un fragment incomplet qui est le premier du datagramme :

# frag6 -v -i em0 --frag-type first --frag-id 1234 -d $MACHINE_UNDER_TEST

Dans une autre fenêtre, et avant l'expiration du délai de garde pour le réassemblage (60 secondes par défaut), on envoie un fragment atomique de même identificateur (1234 ici) :

# frag6 -v -i em0 --frag-type atomic --frag-id 1234 -d $MACHINE_UNDER_TEST

Si les fragments atomiques sont réellement traités à part (ce que notre RFC exige), ce qui est le cas sur un FreeBSD >= 9 ou un Linux >=> 3), le fragment atomique est « réassemblé » avec lui-même et on obtient une réponse :

ICMPv6 echo Reply from $MACHINE_UNDER_TEST (RTT: 5 seconds)

Si on n'a pas cette réponse, c'est que le système en face traite incorrectement les fragments atomiques avec les autres. Dans les deux cas, système correct ou non, le premier fragment ne sera jamais réassemblé et, au bout des 60 secondes, on aura :

Response from $MACHINE_UNDER_TEST: ICMPv6 Time Exceeded error message (Reassembly timeout: 60 seconds)

Et rappelez-vous que, normalement, les mises en œuvre d'IPv6 ne doivent plus générer de fragments atomiques depuis le RFC 8021.


Téléchargez le RFC 6946


L'article seul

RFC 6944: Applicability Statement: DNS Security (DNSSEC) DNSKEY Algorithm Implementation Status

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Rose (NIST)
Réalisé dans le cadre du groupe de travail IETF dnsext
Première rédaction de cet article le 2 mai 2013


Mais quel algorithme de cryptographie choisir pour mes signatures DNSSEC, se demande l'ingénieur système ? Il y a bien un registre IANA des algorithmes normalisés mais c'est juste une liste non qualifiée, qui mêle des algorithmes de caractéristiques très différentes. Ce nouveau RFC vise à répondre à cette question en disant quels sont les algorithmes recommandés.

La première liste d'algorithmes possibles avait été faite dans le RFC 4034. D'autres algorithmes avaient été ajoutés par la suite. Certains sont devenus populaires. Par exemple, RSA avec SHA-2 est utilisé pour presque tous les TLD importants et est donc difficilement contournable pour un résolveur validant. D'autres ont été peu à peu abandonnés, parfois parce que les progrès de la cryptanalyse les menaçaient trop, parfois simplement parce qu'ils n'avaient pas un bon marketing.

Aujourd'hui, le développeur qui écrit ou modifie un logiciel résolveur validant (comme Unbound ou BIND) doit donc se taper pas mal de RFC mais aussi pas mal de sagesse collective distillée dans plusieurs listes de diffusion pour se faire une bonne idée des algorithmes que son logiciel devrait gérer et de ceux qu'il peut laisser tomber sans trop gêner ses utilisateurs.

Ce RFC 6944 détermine pour chaque algorithme s'il est indispensable (on n'a pas le droit de faire l'impasse), recommandé (ce serait vraiment bien de l'avoir, sauf raison contraire impérieuse), facultatif (si vous n'avez rien d'autre à faire de vos soirées que de programmer) ou tout simplement à éviter (pour le cas de faiblesses cryptographiques graves et avérées). La liste se trouve dans la section 2.3 : RSA avec SHA-1 est le seul indispensable. RSA avec SHA-1 plus NSEC3 (voir plus loin l'explication de ce cas particulier), RSA SHA-256 ou SHA-512 (connus collectivement comme SHA-2), ECDSA avec SHA-256 ou SHA-384 sont recommandés. Tous les autres sont facultatifs (c'est par exemple le cas de GOST dans le RFC 5933) sauf RSA avec MD5 qui est à éviter (RFC 6151).

La section 2.2 justifie ces choix : RSA+SHA-1 est l'algorithme de référence, celui qui assure l'interopérabilité (tout logiciel compatible DNSSEC doit le mettre en œuvre). Normalisé pour DNSSEC avant l'apparition de NSEC3 dans le RFC 5155, il existe en deux variantes, une sans NSEC3 (celle qui est indispensable) et une avec (qui est recommandée car la plupart des TLD utilisent NSEC3). RSA+SHA-2 est recommandé car, comme indiqué plus haut, la racine et la plupart des TLD l'utilisent. Un résolveur qui ne comprendrait pas ces algorithmes ne servirait pas à grand'chose.

Au contraire, ECDSA est très peu utilisé en pratique. Mais les courbes elliptiques suscitent beaucoup d'intérêt, et sont une alternative au cas où il y aurait un gros problème avec RSA. D'où le statut « Recommandé ».

Des nouveaux algorithmes vont certainement apparaître dans le registre (cf. RFC 6014). Ils seront automatiquement considérés comme facultatifs, jusqu'à la sortie d'un nouveau RFC qui remplacerait ce RFC 6944.

Et si vous parlez plutôt la langue de Manuel Puig, ce RFC est également commenté en espagnol.


Téléchargez le RFC 6944


L'article seul

RFC 6943: Issues in Identifier Comparison for Security Purposes

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : D. Thaler (Microsoft)
Pour information
Première rédaction de cet article le 10 mai 2013


Utiliser des identificateurs (noms de domaine, URI, noms d'utilisateur, adresses de courrier, etc) comme clés d'accès à des informations de sécurité est courant. Par exemple, on autorise machin@truc.example et lui seul à accéder à certains contenus. Cela implique une comparaison entre l'identificateur présenté et ceux stockés dans une base. En apparence, rien de plus simple que de comparer deux chaînes de caractères. En réalité, il existe plein de pièges, que documente ce RFC de l'IAB. Si tout le monde n'utilise pas exactement le même algorithme de comparaison (et certains sont mal spécifiés ou mal connus et permettent donc des variations), alors on peut avoir aussi bien des dénis de service (utilisateur légitime refusé) que des augmentations de privilèges (utilisateur illégitime accepté).

L'informaticien naïf peut croire que comparer deux identificateurs, c'est simplement faire une comparaison bit à bit de leur représentation mais non, c'est plus compliqué que cela.

Pour comprendre le problème, la section 1 du RFC commence par parler du cycle de vie d'un identificateur. Il est d'abord généré, par exemple par une autorité centrale. Il est ensuite souvent stocké en deux endroits, chez l'utilisateur qui va s'en servir et dans une base des identificateurs enregistrés. Par exemple, si c'est une autorité centrale qui a fabriqué l'identificateur, elle le met dans sa base de données (cas, par exemple, d'un registre de noms de domaine). Naturellement, il y a des tas de possibilités différentes. Par exemple, un identificateur peut être une clé publique cryptographique, générée localement et stockée de même.

L'identificateur est ensuite distribué à ceux et celles qui en auront besoin. Cela peut se faire par des moyens numériques mais aussi par des moyens traditionnels comme une carte de visite ou une communication téléphonique. Pensez à un URL que l'on utilise dans des publicités, dans l'espoir que des gens tapent ensuite cet URL dans la barre d'adresse de leur navigateur. Ce passage par des moyens de communication non numériques est une des sources de problèmes car taper correctement un identificateur lu en vitesse sur le flanc d'un autobus n'est pas trivial.

Enfin, quelqu'un va utiliser cet identificateur. Par exemple, il va essayer d'envoyer un message à barack@whitehouse.gov et espère que cela atteindra la boîte aux lettres de quelqu'un de l'équipe du Président. Ou bien un utilisateur va récupérer un identificateur et essayer de le comparer avec celui qu'il connait. C'est le cas d'un navigateur Web voulant valider un certificat X.509 (RFC 6125).

À noter qu'il existe plein d'autres complications possibles. Par exemple, une entité peut être désignée par plusieurs identificateurs (ce RFC est à la fois http://www.ietf.org/rfc/rfc6943.txt et http://www.rfc-editor.org/rfc/rfc6943.txt, un être humain peut être référencé par son numéro de passeport ou bien par son numéro de Sécu). Notre RFC ne se préoccupe pas de ce cas, se limitant à celui, déjà assez difficile, de la comparaison de deux identificateurs pour voir s'ils sont identiques.

Cela peut se faire de trois façons (section 1.1, et voir aussi le RFC 6885 qui avait introduit ces trois cas) :

  • Identificateurs absolus : ce sont les cas idéaux, ceux où une comparaison bit à bit convient. Les adresses IP sous forme binaire sont dans ce cas : si vous mettez 2001:db8:1::1317 dans une ACL, il n'y a aucune ambiguité pour déterminer si l'adresse présentée est égale ou non à celle-ci. (Attention, ce n'est vrai que pour la forme binaire des adresses IP, pas pour leur représentation textuelle.)
  • Identificateurs définis : il existe un algorithme bien défini pour comparer deux identificateurs. Un cas typique est celui d'une comparaison insensible à la casse, par exemple pour les noms de domaine. (Au fait, la section 9.2.1 du RFC 4790 contient d'utiles conseils.)
  • Identificateurs indéfinis : il n'existe pas vraiment d'algorithme pour les comparer. Les noms humains sont dans ce cas (est-ce que George Martin est la même personne que George R. R. Martin ?)

Une technique courante pour faciliter les comparaisons des identificateurs définis est la canonicalisation. On réduit d'abord l'identificateur à une forme canonique et on fait ensuite une comparaison absolue (bit à bit). Pour des noms de domaines, on peut par exemple toujours les passer en minuscules avant de comparer. Dans le cas d'identificateurs Unicode, c'est évidemment plus complexe mais il existe plusieurs algorithmes de canonicalisation Unicode. L'important est que toutes les parties impliquées utilisent le même.

On peut bien sûr comparer sans canonicaliser mais avoir une forme canonique est tellement pratique (par exemple pour l'affichage) que cela vaut toujours la peine d'en définir une. Ce faisant, on définit aussi un algorithme de comparaison.

La section 2 cite des exemples d'utilisation d'identificateurs dans des contextes de sécurité. Par exemple, trouver une clé en échange d'un nom (a principal, dit-on en sécurité), chercher dans une ACL si une entité est autorisée, compter l'activité d'une entité donnée (et il faut donc ajouter son activité dans la bonne ligne du tableau). Le point important est qu'il faut que tout le monde utilise le même algorithme. Si on stocke l'activité d'adresses de courrier électronique sans les canonicaliser, et que quelqu'un change son adresse de jean@durand.example à jean@Durand.EXAMPLE (pourtant la même adresse), il pourra apparaître comme vierge, comme n'ayant pas d'activité précédente.

Les cas réels peuvent être très compliqués. Par exemple, en HTTPS, on compare ce qu'a tapé un utilisateur dans la barre d'adresses du navigateur avec ce que contient le certificat (RFC 6125). Plusieurs protocoles différents sont en jeu (de la définition des URL à celle de X.509) et plusieurs acteurs (des utilisateurs qui tapent plus ou moins bien, sur des systèmes très variés, et tout le monde des AC), chacun de ces acteurs pouvant avoir ses propres règles.

En cas d'algorithmes différents utilisés par des parties différentes, on peut avoir aussi bien des faux positifs que des faux négatifs. Les faux positifs, c'est quand deux identificateurs sont considérés comme identiques alors qu'ils ne devraient pas. (Je me souviens d'un vieux système Unix où le nom de login était silencieusement tronqué à huit caractères, donc bortzmeyer et bortzmeye étaient considérés identiques.) Si les privilèges sont attribués en fonction de cette égalité, on a un gain en privilèges. Si, par contre, les privilèges sont refusés en fonction de cette égalité (cas d'une liste noire), on a un refus d'un service légitime. Le faux négatif, c'est le contraire : deux identificateurs considérés comme différents alors qu'ils sont équivalents (cas de jean@durand.example et jean@Durand.EXAMPLE plus haut, si on oublie que le nom de domaine est insensible à la casse). Les conséquences sont opposées : si les privilèges sont attribués en fonction de cette égalité, on a un refus de service. Si, par contre, les privilèges sont refusés en fonction de cette égalité, on a un gain de privilèges, à tort.

Évidemment, le gain de privilèges est plus grave que le refus de service et c'est pour cela qu'on trouve, par exemple, dans la section 6.1 du RFC 3986 « comparison methods are designed to minimize false negatives while strictly avoiding false positives ». (Cet exemple suppose que les privilèges sont accordés en fonction de l'égalité et que les faux positifs sont bien plus graves.)

Le RFC donne un exemple où les identificateurs sont des URI. La société Foo paie example.com pour accéder à un service nommé Stuff. Alice, employée de Foo, a un compte identifié par http://example.com/Stuff/FooCorp/alice. En comparant des URI, Foo tient compte du fragment (la partie après le #, section 3.5 du RFC 3986) ce qu'example.com ne fait pas. Et Foo permet les # dans les noms de compte. Un autre employé de Foo, le malhonnête Chuck, se fait créer un compte avec l'identificateur http://example.com/Stuff/FooCorp/alice#stuff. Foo ne voit pas le problème puisque cet identificateur n'existe pas. Chuck va donc pouvoir obtenir des autorisations d'accès de Foo. Il peut ensuite se connecter auprès d'example.com comme étant http://example.com/Stuff/FooCorp/alice, l'identificateur d'Alice. Certes, l'autorisation de Chuck n'était valable que pour http://example.com/Stuff/FooCorp/alice#stuff mais rappelez-vous qu'example.com compare les URI en ignorant les fragments... Voici un cas où les différences entre les mécanismes de comparaison d'identificateurs ont permis un accroissement illégitime de privilèges.

Après cet exemple, la section 3 fait le tour des identificateurs les plus courants et de leurs pièges spécifiques. D'abord, les noms de machines. Ce sont normalement un sous-ensemble des noms de domaines (RFC 6055) mais notre RFC utilise ce terme dans un sens plus large, pour parler de tous les fois où un identificateur ou composant d'identificateur est appelé Host. Ils sont souvent utilisés comme identificateurs, soit directement (par exemple dans le RFC 5280), soit indirectement, comme partie d'un identificateur (le RFC cite l'exemple des URI et des adresses de courrier). Le RFC note bien que ce terme de nom de machine (hostname) est ambigu. Ainsi, dans tyrion.lannister.got, le nom de machine est-il tyrion ou bien tyrion.lannister.got (section 3.1 du RFC 1034) ? Cela peut entraîner des problèmes lorsqu'on veut décider si la machine tyrion a accès aux privilèges de la machine tyrion.lannister.got...

Dans le sens large qu'il a ici « nom de machine » peut aussi être une adresse IP littérale. Cela entraîne d'autres confusions possibles. Par exemple, si le TLD .42 existe et qu'un nom 103.2.1.42 est enregistré, comment le distinguer de l'adresse IPv4 103.2.1.42 ? Normalement, la section 2.1 du RFC 1123 règle la question : on doit tester l'adresse IP d'abord et 103.2.1.42 n'est donc jamais un nom. Mais il n'est pas sûr que tous les programmes appliquent le RFC 1123... Certaines personnes pensent donc qu'il y a un risque à accepter des TLD numériques, même si le RFC 1123 est clair.

Autre source d'ambiguité : la norme POSIX 1003.1 de l'IEEE admet pour une adresse IPv4 plusieurs formes, pas seulement la forme classique en quatre composants séparés par des points. Ainsi, 10.0.258, 0xA000201 et 012.0x102 sont des représentations légales de la même adresse, 10.0.1.2. Certaines normes se tirent d'affaire en imposant la forme stricte, celle avec les quatre composants décimaux séparés par des points. C'est le cas des URI, par exemple (« an IPv4 address in dotted- decimal form »). Même chose avec inet_pton qui n'accepte que la forme stricte. Si les différentes formes sont acceptées, on peut avoir un problème d'ambiguité.

Et avec IPv6 ? Il y a également plusieurs représentations texte possibles (mais, à mon avis, moins susceptibles de poser des problèmes en pratique), par exemple 2001:db8::1 et 2001:DB8:0:0:0:0:0:1 pour la même adresse, sans compter des cas plus tordus comme les identificateurs de zone dans les URL (RFC 6874). Contrairement à IPv4, il existe une représentation canonique, normalisée dans le RFC 5952 mais elle n'est pas forcément utilisée par tous.

L'internationalisation (RFC 2277) ajoute évidemment quelques questions. Par exemple, la section 3.2.2 du RFC 3986 autorise un nom de domaine Unicode à être écrit en encodage pour-cent ou en punycode (le second étant recommandé mais pas imposé). Comment comparer caf%C3%A9.fr et xn--caf-dma.fr ? Comme souvent en matière d'internationalisation (qui n'a jamais été complètement acceptée par certains), le RFC pinaille même plus loin en imaginant le cas (purement hypothétique) d'un registre qui accepterait l'enregistrement de noms commençant par xn--, entrainant ainsi une confusion avec des IDN.

Autre façon de comparer des noms : les résoudre en adresses IP et comparer les adresses. C'est ce que fait la bibliothèque standard Java par défaut (classe URL). Cette méthode a évidemment toujours été dangereuse, mais c'est encore pire maintenant, avec les adresses IP privées, les trucs du DNS pour avoir une réponse dépendant de la source, les mobiles, etc. Elle était conçue pour lutter contre des failles de sécurité comme le changement DNS mais le jeu en vaut-il la chandelle ? Sans compter qu'il est contestable d'attendre le DNS juste pour comparer deux identificateurs.

Après les noms de machines, les ports. L'URL http://www.example.com:443/ est-il égal à http://www.example.com:https, https ayant été enregistré (RFC 6335) comme équivalent de 443 ? (Cet exemple est facile : la seconde forme est illégale dans un URL HTTP. Mais, dans d'autres cas, cela peut être ambigu.)

On a souvent vu les URI dans les deux sections précédentes, consacrées aux noms de machines et aux ports. Le principal problème de la comparaison d'URI est qu'un URI est formé de plusieurs composants, chacun suivant des règles de comparaison différentes. Second problème, il existe plusieurs mécanismes standard de comparaison d'URI (RFC 3986, section 6.2, qui décrit l'échelle des comparaisons, de la plus simple à la plus complète). Le but de cette variété est de permettre aux diverses applications des URI d'optimiser pour les performances ou pour la sécurité. L'inconvénient est que deux comparateurs d'URI peuvent donner des résultats différents sans même qu'on puisse accuser l'un d'eux d'être bogué ou non standard.

Certains composants de l'URI posent des problèmes particuliers : les plans définissent la syntaxe spécifique d'un type d'URI et il ne faut donc jamais essayer de comparer deux URI de plans différents (http et ftp par exemple, même si, dans ce cas, la syntaxe est la même). Un autre cas souvent oublié dans les URI est la partie nommée userinfo avant le @, par exemple dans ftp://alice:bob@example.com/bar. Doit-elle être considérée significative en comparant des URI ? Le RFC ne fournit pas de règles à ce sujet.

Le chemin après le nom de machine pose un autre problème, celui des caractères . et .. qui, normalement, indiquent un chemin relatif. Mais la section 5.2.4 du RFC 3986 fournit un algorithme pour les retirer, transformant http://example.com/a/b/c/./../../g en http://example.com/a/g. Un nouveau piège pour la comparaison ?

Continuons vers la fin de l'URI. Après le ? il y a une requête. Doit-elle être prise en compte dans la comparaison ? Là encore, pas de réponse simple, c'est à l'application de décider si http://www.example.org/foo/bar?ref=323 est identique à http://www.example.org/foo/bar. Un exemple où cette question se pose est celle d'un site de référencement d'URI, avec les nombreux cas où la requête ne stocke en fait qu'une variable de suivi de la circulation de l'URI (lu sur Twitter, lu sur Facebook, etc).

Reste le fragment, la dernière partie d'un URI, après le #. En général, lorsqu'on utilise un URI comme identificateur dans un contexte de sécurité, on ignore le fragment (voir l'exemple plus haut avec Chuck et Alice...) Mais ce n'est pas une règle qui marche dans tous les cas. Là encore, l'important est la cohérence : que toutes les applications qui gèrent cet URI fassent pareil.

Comme pour les noms de machine, dans l'exemple Java plus haut, on pourrait se dire qu'une façon simple de comparer deux URI est de les déréférencer et de voir s'ils pointent vers des contenus identiques. Mais tous les URI ne sont pas déréférençables, on n'a pas forcément envie d'imposer une connexion Internet en état de marche juste pour comparer deux identificateurs et, de toute façon, un tel algorithme serait très fragile (que faire si on trouve le même document XML mais avec des encodages différents ?) En outre, toute démarche active comme celle-ci est dangereuse pour la vie privée (elle informe les gérants des serveurs Web de ce que l'on est en train de faire, comme le font les Web bugs).

Après les URI, place à une catégorie d'identificateurs très souvent utilisés pour identifier une entité, les adresses de courrier (RFC 5322 pour leur syntaxe, et RFC 6532 pour le cas où elles sont internationalisées). Une adresse de courrier, comme un URI, a plusieurs parties, qui suivent des règles différentes pour la comparaison. La partie à droite du @ est un nom de domaine et ce cas a été traité plus haut. La partie gauche, dite partie locale, est un identificateur indéfini : ses règles ne sont pas connues à l'extérieur et on ne peut donc pas savoir, par exemple, si rms@gnu.org et RMS@gnu.org sont le même utilisateur, ou si stephane+ps@bortzmeyer.org est le même que stephane+ump@bortzmeyer.org. Dans le cas où des adresses de courrier sont utilisées dans un certificat, on choisit souvent une comparaison bit à bit... qui peut donner plein de faux négatifs.

Après cette liste à la Prévert de problèmes, la section 4 de notre RFC tente une synthèse. Elle identifie quatre problèmes. Le premier est la confusion. Un identificateur est utilisé sans que son type soit clair. Par exemple, si je tape telnet 1000, est-ce l'adresse IPv4 0.0.3.232 ou bien l'adresse IPv6 ::3:e8 ? Et si je tape ping 10.1.2.42, est-ce que 10.1.2.42 est un nom ou une adresse (le TLD .42 peut exister) ?

Résoudre la confusion nécessite un algorithme clair. Dans le premier exemple ci-dessus, il n'y a pas de confusion. 100 ne peut pas être une adresse IPv6 légale (la présence ou l'absence d'un : suffit à les reconnaître). Le second exemple est normalement clair : l'adresse IP a priorité donc 10.1.2.42 ne peut pas être un nom même si le TLD .42 existe. Si cette règle de précédence est respectée par les implémentations, il n'y aura pas de problèmes (identificateurs définis). Mon avis personnel est que ce RFC pinaille quand même très fort sur ce point, en s'interrogeant gravement sur des problèmes théoriquement intéressants mais extrêmement tordus et donc rares en pratique.

Deuxième problème, l'internationalisation. Un logiciel n'a aucun problème à comparer google.com et goog1e.com et à dire qu'ils sont différents. C'est plus difficile pour un humain (vous aviez repéré le L qui était en fait un 1 ?) Toutes les fois où un humain est impliqué, dans la saisie ou la reconnaissance d'un identificateur, ce genre d'erreur peut se produire. Comme le montre cet exemple, cela n'a d'ailleurs rien de spécifique aux chaînes de caractères Unicode. Mais ce problème est souvent cité comme argument contre l'internationalisation. Bref, le point important : la sécurité ne devrait pas dépendre d'une vérification visuelle faite par un humain. (Cf. l'article de Weber et le RFC 6885.)

Problème suivant, la portée. Certains identificateurs ne sont pas uniques au niveau mondial. localhost est un bon exemple. C'est également le cas des adresses du RFC 1918. On peut aussi citer l'adresse de courrier alice qui, utilisée depuis une machine d'example.com arrivera à une Alice et, depuis une machine d'un autre domaine, à une autre. Dans ce dernier cas, la bonne solution est de toujours utiliser une adresse unique (par exemple alice@example.com) même dans un contexte local : l'expérience prouve que les identificateurs fuient souvent d'un domaine local vers un autre.

Enfin, dernier problème identifié par cette section 4, la durée. Certains identificateurs ne sont pas éternels et peuvent disparaître, ou désigner une autre entité. Par exemple, bob@example.com peut désigner un Bob aujourd'hui et, s'il quitte l'entreprise et qu'un autre est embauché, un Bob complètement différent dans quelques mois. C'est la même chose pour les adresses IP et des tas d'utilisateurs ont déjà souffert de se voir attribuer une adresse IP qui avait une mauvaise réputation.

La section 5 résume les conseils les plus importants : se méfier des identifcateurs indéfinis, prévoir une comparaison absolue ou définie pour tous les identificateurs futurs, penser aux mécanismes pour valider les identificateurs (RFC 3696). Le gros risque restera toujours le cas où plus d'un protocole utilise un identificateur donné, car les différents protocoles n'auront pas forcément les mêmes règles de comparaison des identificateurs.


Téléchargez le RFC 6943


L'article seul

RFC 6940: REsource LOcation And Discovery (RELOAD) Base Protocol

Date de publication du RFC : Janvier 2014
Auteur(s) du RFC : C. Jennings (Cisco), B. Lowekamp (Skype), E. Rescorla (RTFM, Inc.), S. Baset, H. Schulzrinne (Columbia University)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF p2psip
Première rédaction de cet article le 17 janvier 2014


Le groupe de travail IETF p2psip travaille à permettre la communication (par exemple téléphonique) entre utilisateurs de SIP sans passer par un fournisseur SIP, mais en se débrouillant en pair-à-pair. Pour cela, le groupe a choisi une approche modulaire et a d'abord développé un protocole de communication pair-à-pair, qui va servir de socle aux futures utilisations. Ce protocole se nomme RELOAD (pour REsource LOcation And Discovery), et fait l'objet de ce très long RFC, le premier du groupe p2psip.

L'enjeu est d'importance : le système fermé Skype a obtenu beaucoup d'utilisateurs en s'appuyant partiellement sur des techniques pair-à-pair. Le SIP traditionnel, où deux correspondants ne communiquent que via leurs fournisseurs SIP respectifs devait être amélioré en exploitant ces capacités pair-à-pair. Échanger des paquets RTP directement est facile. Se trouver et initier la communication l'est moins. Pour le faire en pair-à-pair, il n'existait pas de protocole ouvert et normalisé. On notera d'ailleurs que RELOAD est le premier protocole pair-à-pair (au sens moderne parce que, objectivement, IP a toujours été pair-à-pair) normalisé par l'IETF.

RELOAD est suffisemment général pour pouvoir être utilisé dans le futur par d'autres systèmes que SIP. Qu'est-ce qu'il fournit comme service que les autres protocoles existants ne fournissaient pas ?

  • Une gestion de la sécurité, avec un serveur central d'inscription qui laisse entrer (ou pas) les pairs. Si vous pensez qu'un tel serveur n'est pas pair-à-pair, vous avez raison. Si vous pensez qu'on peut s'en passer, vous avez tort.
  • La possibilité d'être utilisé par des applications différentes (par exemple SIP et XMPP),
  • Des fonctions de passage à travers les NAT (un point pénible pour SIP et ses équivalents),
  • La possibilité d'utiliser plusieurs algorithmes pour la gestion de l'overlay (le réseau virtuel entre les pairs). Le pair-à-pair est en effet un domaine encore relativement récent et il serait imprudent de croire qu'on connait le bon algorithme d'overlay et qu'on peut ignorer tous les autres. RELOAD permet des réseaux structurés (comme les DHT) et des non structurés. À des fins d'interopérabilité, RELOAD impose la possibilité d'utiliser la classique DHT Chord (ainsi, deux mises en œuvre de RELOAD sont sûres d'avoir au moins un algorithme en commun) mais permet aux overlays d'en utiliser d'autres. La section 3.5 détaille cette particularité de RELOAD. Les systèmes possibles sont stockés dans un registre IANA.
  • Une distinction entre pairs et clients, qui permet de profiter de RELOAD sans y participer comme pair. Le même protocole est utilisé (section 3.2 pour les détails). L'annexe B du RFC explique plus en détail pourquoi on autorise les « simples » clients, notamment parce que certaines machines n'ont pas assez de ressources pour assurer les tâches (routage et stockage) d'un pair (machines sur batterie, par exemple).

Si vous voulez vous cultiver sur Chord, l'article original est « Chord: A Scalable Peer-to-peer Lookup Protocol for Internet Applications » (IEEE/ACM Transactions on Networking Volume 11, Issue 1, 17-32, Feb 2003, 2001) et Wikipédia en anglais a un bon article.

Une instance RELOAD est donc un overlay (un réseau virtuel utilisant un algorithme donné) où chaque nœud (pair ou simple client) a un identificateur, le Node-ID. Cet overlay forme un graphe où tout nœud n'a pas forcément directement accès à tout autre nœud, et les pairs doivent donc se préparer à router les messages (les simples clients en sont dispensés).

L'instance RELOAD offre deux services, la transmission de messages et le stockage de données (données de petite taille, a priori, celles nécessaires à la communication). Chaque donnée a un identificateur, le Resource-ID, qui utilise le même espace de nommage que les Node-ID. Il y a ensuite une relation entre les Node-ID et les Resource-ID par exemple, qu'un nœud est responsable de toutes les données dont le Resource-ID est compris entre son Node-ID et le Node-ID précédent (si vous connaissez les DHT, ce genre de concept vous est familier. Sinon, cela peut être le moment de s'arrêter pour lire des choses sur les DHT.) La relation exacte dépend de l'algorithme d'overlay utilisée. Celle donnée en exemple est valable pour Chord.

Pour accomplir ses tâches, RELOAD a plusieurs composants. De haut en bas (si cela ressemble au modèle en couches, c'est exprès, sauf que ces couches sont entassées sur l'overlay, pas sur un réseau physique) :

  • L'application, par exemple SIP (la liste des applications est dans un registre IANA).
  • Un composant de transport des messages, qui assure des fonctions comme la fiabilité de bout en bout. Ce composant permet donc d'envoyer un message de n'importe quel pair de l'overlay à n'importe quel autre.
  • Un composant de stockage des données.
  • Un greffon de gestion de la topologie. RELOAD utilise le terme de topology plugin, pour mettre en avant le fait qu'il est modifiable : on peut remplacer le greffon par défaut, qui utilise Chord, par un autre.
  • Un composant de gestion des liens entre pairs, qui s'occupera notamment du difficile problème de la traversée des NAT, grâce à ICE (RFC 5245 et section 6.5.1.3).
  • Et plusieurs composants de transport sur les liens, entre deux pairs. Un exemple est un composant utilisant TLS (RFC 5246) sur TCP. Un autre composant au même niveau pourrait être DTLS (RFC 6347) sur UDP. Contrairement au composant de transport des messages, le premier cité, qui avait une responsabilité de bout en bout, ces composants de transport sur un lien ne sont responsables que d'envoyer des octets d'un pair à un pair voisin (voisin dans l'overlay, pas du point de vue IP...)

La sécurité est traditionnellement le point faible des DHT (et du pair-à-pair en général). (Voir l'excellent exposé d'Eric Rescorla.) Le principe de base de la sécurité de RELOAD est que chaque pair aura un certificat délivré par une instance centrale (qui ne sera responsable que de l'inscription des pairs : elle ne participera ni au routage, ni à l'envoi des messages, ni au stockage,). Chaque message, et chaque objet stocké, sera signé avec ce certificat et toutes les communications de bas niveau chiffrées (par exemple avec TLS). Une machine qui veut rejoindre l'overlay doit se connecter en HTTPS au serveur central, qui lui attribuera un Node-ID (dans le champ subjectAltName du certificat RFC 5280). Le serveur central demandera probablement une authentification (par exemple nom et mot de passe). Ce serveur et les vérifications qu'il fait sont le cœur de la sécurité de RELOAD. La machine joindra ensuite le réseau virtuel (les détails sur la façon dont elle le fait dépendent de l'algorithme utilisé pour le maintien de l'overlay).

Ne vous inquiétez pas forcément de ces obligations de sécurité : elles ne sont valables que pour un overlay installé sur le grand Internet public. Si vous avez un environnement restreint et sécurisé (disons un groupe de machines formant un réseau ad hoc local), vous avez le droit de vous en dispenser et de vous contenter de certificats auto-signés par les pairs, où le Node-ID est simplement un condensat de la clé publique. Une telle façon de fonctionner laisse le réseau très vulnérable aux attaques Sybil mais peut convenir si vous savez que vous êtes « entre vous ». Autre possibilité de simplification de la sécurité : RELOAD a un mode où les pairs s'authentifient, non pas par un certificat, mais par un secret partagé (par exemple RFC 4279).

Voici donc les grands principes de RELOAD. Je ne vais pas ensuite détailler les 186 pages du RFC, juste quelques points que je trouve intéressants. Le mécanisme de routage est présenté en section 3.3. Par défaut, RELOAD utilise du récursif symétrique (section 6.2). La requête enregistre les nœuds par lesquels elle est passée (dans la Via List) et la réponse suivra le même chemin en sens inverse. Si la topologie a changé entre-temps, la réponse sera perdue et ce sera aux couches supérieures de réémettre. (Il existe une alternative à ce stockage du chemin dans le message lui-même : si les pairs intermédiaires peuvent stocker des données, ils peuvent garder la mémoire des routes suivies, au lieu d'utiliser la Via List.)

L'inscription initiale dans l'overlay est un problème intéressant, car on voudrait que cela soit simple pour l'utilisateur, par exemple qu'il n'ait pas à rentrer 50 paramètres dans son client SIP. L'idée est que le nouveau pair n'a à connaître que le nom de l'overlay (un FQDN) et peut-être des informations d'authentification. Une requête SRV dans le DNS à partir du nom du réseau (précédé de _reload-config._tcp) donne le nom du serveur de configuration, qu'on contacte en HTTPS en lui demandant la ressource .well-known/reload-config (RFC 5785 pour .well-known). Ce serveur envoie alors tous les détails de configuration de l'overlay, en XML, un exemple figure en section 11 et à la fin de cet article. (Une machine peut aussi avoir cette configuration dans un fichier local.) C'est alors que le futur pair connait le nom du serveur d'inscription et peut le contacter pour apprendre son Node-ID.

Le stockage pair-à-pair dans RELOAD (section 4.1) permet de stocker différents types (kind) d'objets. Un type peut être défini comme stockant un scalaire, un tableau ou un dictionnaire (section 7.2 pour les détails). Tous les objets stockés sont signés par le déposant, qui pourra ainsi vérifier que ses pairs ne se sont pas moqués de lui. (Voir mon article « Assurer l'authenticité des données stockée dans une DHT».) À noter qu'un pair ne peut pas stocker des objets sous des noms arbitraires. Typiquement (cela dépend de l'application), il ne peut stocker que sous son propre nom (alice@example.com pour du SIP), ce qui fait qu'il ne pourra pas noyer tous les nœuds de la DHT sous des objets à stocker.

Une des choses les plus nécessaires pour communiquer en pair-à-pair est la découverte. Trouver quelqu'un ou quelque chose dans l'immensitude de l'Internet est difficile (alors que c'est trivial en centralisé, d'où le succès de services comme Facebook). Il existe actuellement plusieurs Internet-Drafts décrivant de futurs services de découverte qui tourneront au dessus de RELOAD.

Le format des messages RELOAD est décrit en section 6.3 : format binaire, avec les premiers en-têtes, qui sont obligatoires, à une position fixe (pour une analyse plus rapide) et les suivants, qui sont optionnels, encodés en TLV (pour la souplesse et l'extensibilité). Chaque message est auto-suffisant, un peu comme un datagramme. Sa première partie, le Forwarding Header, est la seule qui ait besoin d'être examinée par les routeurs intermédiaires. Les deux autres, le Message Content et le Security Block (les signatures), ne concernent que la machine de destination.

Notre RFC utilise une syntaxe analogue à celle du C pour décrire le format des messages (un peu comme le fait le RFC 5246). Principal point à noter pour lire cette syntaxe (la section 6.3.1 fournit tous les détails) : les termes entre chevrons sont des valeurs de taille variable. Par exemple data<0..15> désigne de zéro à quinze octets de données.

Le Forwarding Header contient les Via Lists vues plus haut et les destinations (la plupart du temps, il n'y en a qu'une seule mais RELOAD permet d'indiquer une liste de destinations à parcourir successivement : pour comparer avec le datagramme IP, disons que la liste des destinations est une fusion de l'adresse IP de destination et de l'option Source route). Cela donne :

 struct {
          ...
          uint32             overlay; /* Un condensat du nom */
          ...
          uint8              ttl;
          ...
          uint32             length;
          ...
          uint16             via_list_length; /* Pour le routage
	  symétrique */
          uint16             destination_list_length;
          ...
          Destination        via_list[via_list_length];
          Destination        destination_list
                               [destination_list_length];
          ...
        } ForwardingHeader;

Pour cet en-tête, qui doit être lu très vite par les routeurs intermédiaires, RELOAD utilise l'encodage {longueur, tableau}. Les autres termes de longueur variable utiliseront un encodage moins rapide à analyser mais plus propre. Le type Destination est, en résumant, un Node ID ou Resource ID (rappelez-vous que ces ID ont la même forme - dépendante du type d'overlay - et sont tirés du même espace).

La deuxième partie du message, Message Content, est largement opaque :


struct {
     uint16                 message_code;
     opaque                 message_body<0..2^32-1>;
     MessageExtension       extensions<0..2^32-1>;
   } MessageContents;

C'est donc surtout une suite d'octets, 2^32 au maximum. Le code indique la sémantique du message (demande de stockage de données, « ping », annonce d'un nouveau pair, etc) et la liste des codes est dans un registre IANA.

La troisième et dernière partie du message, le Security Block, est une liste de certificats X.509 et une signature :


struct {
      GenericCertificate certificates<0..2^16-1>;
      Signature          signature;
   } SecurityBlock;

Tous les messages doivent être signés et les signatures vérifiées à la réception.

Les responsabilités du greffon de gestion de la topologie figurent dans la section 6.4. Elles sont décrites sous forme de messages abstraits, à incarner pour chaque algorithme d'overlay. Un exemple, le message Join lorsqu'un nouveau pair arrive :


struct {
            NodeId                joining_peer_id;
            opaque                overlay_specific_data<0..2^16-1>;
         } JoinReq;

Les protocoles de communication entre deux nœuds devront fournir des mécanimes d'authentification du Node ID, d'intégrité et de confidentialité, par exemple en s'appuyant sur TLS (section 6.6.1). Le RFC suggère d'explorer la possibilité d'utiliser HIP (RFC 7401 et section 6.6.1.1) qui a toutes les propriétés voulues. Ils doivent aussi respecter les principes du RFC 8085, i.e. ne pas noyer les destinataires sous les retransmissions.

Le stockage des données fait l'objet de la section 7. On stocke des objets qui ont cette forme :

 struct {
          uint32                  length;
          uint64                  storage_time;
          uint32                  lifetime;
          StoredDataValue         value;
          Signature               signature;
        } StoredData;

On voit qu'ils sont signés, et ont une durée de vie maximale.

On l'a dit, RELOAD utilise par défaut la DHT Chord et toutes les mises en œuvre de RELOAD doivent connaître Chord, pour assurer l'interopérabilité. Le mécanisme utilisé par RELOAD est légèrement différent du Chord original et la section 10 détaille ces différences. Les deux principales :

  • Chord ne permettait qu'un seul prédécesseur et un seul successeur par nœud, alors que plusieurs sont possibles avec Chord-RELOAD,
  • Le routage dans Chord était itératif (le nœud de départ devait contacter directement celui d'arrivée, les autres pairs ne servaient qu'à indiquer où le trouver), il est devenu récursif (les autres pairs transmettent le message, difficile de faire autrement avec les NAT). L'annexe A du RFC discute en détail les raisons de ce choix.

Les grands principes de Chord sont gardés : nœuds organisés en un anneau (le dernier nœud dans l'ordre des Node ID est donc le précédesseur du premier), utilisation de SHA-1 (tronqué aux 128 premiers bits dans Chord-RELOAD) pour trouver le Resource ID à partir des données, table de routage composée, non seulement des voisins immédiats, mais aussi de pointeurs (les fingers) vers un certain nombre de non-voisins (pour des raisons de performance, car cela évite de parcourir la moitié de l'anneau, mais aussi de résilience, pour survivre à la perte des voisins), etc

Un exemple de fichier de configuration d'un réseau virtual (overlay) figure en section 11 :


<overlay>
      <configuration instance-name="overlay.example.org" sequence="22"
          expiration="2002-10-10T07:00:00Z" ext:ext-example="stuff" >
          <!-- Le greffon de topologie par défaut : -->
          <topology-plugin>CHORD-RELOAD</topology-plugin>
          <!-- Le certificat qui va signer tout : -->
          <root-cert>
              MIIDJDCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJVUzET...
          </root-cert>
          <!-- Les serveurs à contacter pour avoir Node-ID et
	  certificat : -->
          <enrollment-server>https://example.org</enrollment-server>
          <enrollment-server>https://example.net</enrollment-server>
          <!-- Les pairs à contacter pour rejoindre l'overlay : -->
          <bootstrap-node address="192.0.0.1" port="6084" />
          <bootstrap-node address="192.0.2.2" port="6084" />
          <bootstrap-node address="2001:db8::1" port="6084" />
          <!-- Les paramètres spécifiques à la DHT : -->
          <chord:chord-update-interval>
              400</chord:chord-update-interval>
          <chord:chord-ping-interval>30</chord:chord-ping-interval>
          <chord:chord-reactive>true</chord:chord-reactive>
         <!-- Et bien d'autres choses encor... -->
    </overlay>

6084 est le port par défaut pour RELOAD (section 14.2). La grammaire pour ce fichier de configuration est normalisée (en Relax NG) en section 11.1.1.

Pour contacter les serveurs d'inscription (enrollment server), le protocole à utiliser est en section 11.3. L'IETF a choisi de ne pas réutiliser les protocoles existants (RFC 5272 et RFC 5273) car ils sont trop complexes. À la place, le futur pair fait juste une requête HTTPS POST dont le contenu comprend du PKCS#10 (contenant la demande de certificat, cf. RFC 2311). Cette requête doit aussi contenir les informations d'authentification du pair (par exemple un nom et un mot de passe). En échange, le serveur enverra un certificat dont le sujet (le nom) sera un Node ID, choisi au hasard (RFC 4086 ; c'est important car certaines attaquent contre les DHT nécessitent que l'attaquant choisisse son Node ID). En outre, le champ subjectAltName doit contenir le nom que l'utilisateur sera autorisé à présenter à l'application (pour SIP, ce sera un nom de type machin@truc.example). Certaines autorisations (par exemple d'accès aux données stockées) dépendront de ce nom.

La faiblesse traditionnelle des DHT (ou du pair-à-pair en général) est la sécurité (RFC 5765). Sans chef pour contrôler les échanges, que faire si un méchant s'insère dans le réseau pair-à-pair pour l'espionner, modifier les données, ou bien empêcher le réseau de fonctionner ? La section 13 revient en détail sur les questions de sécurité. Le fond du problème est qu'on dépend des pairs (pour envoyer des messages à d'autres pairs ou bien pour stocker des données) et qu'on n'a pas de relation bien définie avec ces pairs. Sur un réseau public comme l'Internet, les pairs peuvent être n'importe qui, y compris des méchants. Si la majorité des pairs sont dans ce cas, on est fichu, aucun algorithme astucieux ne peut marcher dans ces conditions. Il faut donc agir sur l'inscription (enrollment). C'est ce que fait RELOAD (section 13.3) en imposant le passage par un serveur d'inscription pour obtenir un certificat, puis en imposant de prouver la possession d'un tel certificat (en signant les messages avec la clé).

RELOAD permet des certificats auto-signés mais, dans ce cas, l'overlay peut être vite noyé sous les pairs malveillants (ce qu'on nomme une attaque Sybil). La seule sécurité qui reste est le Node ID (qui est dérivé du certificat et est donc cryptographiquement vérifiable). Bref, une telle sécurité ne convient que dans des environnements fermés, où on est sûr de toutes les machines présentes. Un exemple typique est un réseau ad hoc entre les machines des participants à une réunion (et encore, en Wifi, attention à l'attaquant de l'autre côté du mur...). Dans ce cas, on peut même se passer complètement des certificats en choisissant la solution du secret partagé : on le distribue à tous les participants à la réunion et ça roule (section 13.4).


Téléchargez le RFC 6940


L'article seul

RFC 6936: Applicability Statement for the use of IPv6 UDP Datagrams with Zero Checksums

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : G. Fairhurst (University of Aberdeen), M. Westerlund (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 1 mai 2013


Le RFC 2460 qui normalise IPv6 indique dans sa section 8.1 que les paquets UDP sur IPv6 doivent avoir une somme de contrôle (elle était facultative en IPv4) calculée selon le RFC 1071. Dans quels cas est-elle réellement nécessaire ? Peut-on s'en passer parfois ? Ce nouveau RFC discute des conditions qui peuvent permettre de mettre zéro dans le champ Checksum, indiquant qu'on n'a pas utilisé de somme de contrôle. Pour résumer : si on veut se passer de somme de contrôle, cela doit se faire application par application, il faut être sûr qu'on supporte les paquets corrompus ou délivrés à tort, et il faut tester le chemin emprunté pour être sûr que les « nouveaux » paquets passent bien.

Ce RFC discute des solutions à un problème de performance d'UDP et des conditions dans lesquels on peut ne plus mettre de somme de contrôle. Il sert donc d'arrière-plan au RFC normatif, le RFC 6935 qui définit les nouvelles règles pour UDP sur IPv6 (somme de contrôle facultative) et fait donc un choix ferme parmi les propositions discutées ici. Notez toutefois qu'il y a pas mal de recouvrement et de redites entre les deux RFC.

UDP est très utilisé, et pour beaucoup d'applications (le RFC 8085 donne des conseils à ce sujet). Un des usages fréquents est pour construire des tunnels, afin de pouvoir passer à travers les millions de middleboxes stupides qui infestent l'Internet, et qui bloquent souvent tous les protocoles autres que UDP et TCP. Or, un routeur d'entrée ou de sortie de tunnel peut avoir à encapsuler ou décapsuler des millions de paquets par seconde et la génération ou la vérification des sommes de contrôle de chaque paquet peut avoir un effet mesurable sur ses performances (sections 1.3.2 et 1.3.3). D'autant plus qu'il n'est pas toujours possible d'utiliser le matériel spécialisé du routeur pour cela car il ne donne souvent accès qu'aux N premiers octets du paquet (avec N typiquement < 128), alors que le calcul de la somme de contrôle nécessite d'accéder à tout le paquet.

En UDP/IPv4, la solution est de couper la somme de contrôle sur le paquet externe (le protocole interne, qui n'est pas forcément UDP, reste protégé par sa propre somme de contrôle), ce qui est légal en IPv4. Le tunnel devient alors un lien virtuel non fiable, pouvant corrompre des paquets (comme c'est le cas d'un certain nombre de liens physiques). C'est par exemple la solution recommandée pour un gros consommateur de tunnels UDP, LISP. Il est donc tentant de l'utiliser également en UDP/IPv6.

Cela peut poser des problèmes avec certaines middleboxes qui vérifient la somme de contrôle UDP et n'accepteront pas d'y trouver zéro. Décréter que la somme de contrôle UDP en IPv6 devient facultative ne signifie donc pas que ces paquets optimisés pourront voyager dès demain sur tout l'Internet : un certain nombre de pare-feux les bloqueront. Cela peut sembler un problème rédhibitoire (on utilisait UDP justement pour passer facilement à travers les middleboxes puis on réforme les règles d'UDP, créant des paquets qui sembleront illégaux à beaucoup de ces middleboxes) mais il faut noter que la plupart des ces middleboxes ne font pas encore d'IPv6 et que donc les premiers déploiements ont des chances de se faire avec des middleboxes conformes à la nouvelle règle.

À part l'UDP existant, et l'UDP avec somme facultative du RFC 6935, quelles sont les autres technologies disponibles pour des tunnels (section 2 du RFC) ? Il y a UDP Lite (RFC 3828), avec une somme de contrôle qui ne couvre que le début du paquet (et est donc rapide à calculer), et qui est certes mis en œuvre dans le noyau Linux mais qui est peu reconnu par les middleboxes. Il utilise un identifiant (champ Next Header qui identifie en général le protocole de transport) différent de celui d'UDP (136 contre le 17 d'UDP) et est donc souvent bloqué par des pare-feux trop zélés. Il y a les techniques de tunnels génériques comme IP-in-IP et GRE. Elles n'ont pas de somme de contrôle du tout et sont donc rapides. Ce sont les solutions idéales pour les tunnels mais elles aussi utilisent un champ Next Header qui peut ne pas être connu de la middlebox (94 pour IP-in-IP et 47 pour GRE) et ils passent certainement moins souvent qu'UDP (d'où le choix d'UDP pour LISP). Notons aussi que la section 6 déconseille les tunnels récursifs (un tunnel dans un tunnel dans un tunnel...) qui augmentent les risques d'erreur pour le paquet le plus interne (et ajoutent une grande complexité à la fragmentation).

La section 3 examine ensuite les choses qui peuvent aller mal avec la solution retenue par le RFC 6935. Si on ne met pas de somme de contrôle dans le paquet UDP (ou, plus exactement, qu'on met zéro, indiquant qu'on n'a pas calculé de somme et que le récepteur ne doit pas vérifier), et qu'un bit du paquet est modifié, que peut-il se passer d'horrible ? Pour IPv4, la somme de contrôle UDP ne servait qu'à protéger les numéros de port et les données, des informations comme l'adresse IP de destination étaient protégées par la somme de contrôle de la couche 3. Celle-ci a disparu en IPv6 et la somme de contrôle UDP doit donc tout faire. Si elle est erronée, on n'est même pas sûr que le paquet nous était bien destiné (l'adresse IP de destination a pu être modifiée).

Comme l'expliquent le RFC 3819 ou des études comme « When the CRC and TCP Checksum Disagree », la corruption arrive réellement dans l'Internet. Des mesures ont indiqué jusqu'à 1 paquet corrompu sur 10 000 (cela dépend fortement du chemin suivi : le taux de corruption est quasi-nul sur certains chemins). Le RFC note (section 3.2) qu'on ne sait pas exactement où la corruption survient : cela peut être dans la RAM du routeur, sur le câble, dans les récepteurs et les émetteurs optiques ou électriques, etc.

Si c'est l'adresse IP de destination qui est modifiée, le paquet peut n'arriver nulle part, ou bien arriver à une machine qui ne l'attend pas. Si aucun programme n'écoute sur le port en question, le paquet est jeté (et un message d'erreur envoyé à la source, qui sera bien surprise). Si un programme écoute, il va recevoir un paquet invalide. Même chose si c'est le port de destination seul qui a été corrompu. Si l'application n'a pas de mécanisme (comme des numéros de séquence) pour détecter le problème, le paquet invalide pourra être accepté. Donc, une règle importante : une application qui est prête à débrayer les sommes de contrôle UDP doit être prête à réagir proprement si elle reçoit un datagramme envoyé à tort. C'est une des raisons pour lesquelles le RFC exige que la suppression de la somme de contrôle UDP ne se fasse pas globalement, pour toute la machine ou pour toute l'interface réseau, mais uniquement sur requête explicite d'une application majeure et consentante (section 3.5)

Si c'est l'adresse IP source qui est corrompue, le paquet arrivera sans doute à la bonne destination (mais pas à coup sûr, par exemple en cas de filtrage RFC 2827). Si l'application garde en mémoire ses correspondants, le paquet de ce correspondant inconnu sera jeté. Si elle ne le fait pas, si une réponse est envoyée... elle le sera au mauvais correspondant.

Et si c'est l'information de fragmentation qui est corrompue ? Cela peut empêcher le réassemblage (menant à la perte du paquet) mais aussi, ce qui est bien pire, conduire à des réassemblages erronés (par exemple, si le champ ID est modifié, attribuant le fragment à un autre datagramme). Comme le note le RFC 5722, il faut multiplier les tests lors du réassemblage.

Nous avons vu plus haut qu'un certain nombre de boîtiers intermédiaires jetteraient probablement sans autre forme de procès ces « nouveaux » paquets UDP avec une somme de contrôle nulle (ils étaient illégaux avant la sortie du RFC 6935). Il est donc essentiel, pour une application qui veut utiliser cette nouveauté, de tester le chemin et de vérifier que rien sur le trajet ne jette les paquets sans somme de contrôle. Il faut aussi penser à répéter ce test de temps en temps : le chemin peut changer (par exemple parce que BGP l'a décidé) et passer tout à coup par des boîtiers différents. (Et il faut faire le test dans les deux sens, ne serait-ce que parce que le routage n'est pas forcément symétrique.)

Dans tous les cas, il faut se rappeler que la somme de contrôle ne fournit de protection que contre la corruption accidentelle. Ce n'est pas un mécanisme d'authentification, et elle ne protège pas du tout contre un attaquant (qui peut modifier le paquet sans changer la somme de contrôle).

Les règles d'applicabilité sont formalisées dans les sections 4 (pour les implémentations) et 5 (pour l'usage de ces implémentations). Les programmes qui mettent en œuvre UDP sur IPv6 :

  • Doivent, par défaut, calculer une somme de contrôle et la mettre dans les paquets,
  • Doivent permettre de débrayer cette somme de contrôle pour certains ports (ceux utilisés par l'application volontaire),
  • Même dans ce cas, il faut fournir un mécanisme pour permettre à l'application d'envoyer certains datagrammes avec une somme de contrôle (pour les paquets keep-alive, par exemple),
  • Doivent, par défaut, rejeter les datagrammes entrants ayant une somme de contrôle nulle (et le journaliser quelque part),
  • Doivent fournir un moyen de supprimer ce contrôle des paquets UDP entrants, pour certains ports,
  • Vérifier les paquets ICMP entrants qui se réfèrent à un paquet UDP ayant une somme de contrôle nulle, par exemple que les adresses dans le paquet cité dans le message ICMP soient correctes.

Cela, c'était pour l'implémentation d'UDP et d'IPv6 (qui, dans un Unix, est dans le noyau). Maintenant, pour les applications qui l'utilisent, la section 5 dit qu'elles :

  • Doivent se souvenir qu'un paquet UDP/IPv6 sans somme de contrôle n'est pas équivalent à un paquet UDP/IPv4 sans somme de contrôle : IPv4 a toujours une somme de contrôle en couche 3, que n'a pas IPv6. UDP/IPv6 sans somme de contrôle est donc plus risqué et doit n'être utilisé qu'à bon escient.
  • Doivent n'activer la suppression de la somme de contrôle que pour un petit nombre de ports, ceux qu'elles utilisent,
  • Doivent avoir un mécanisme de contrôle d'intégrité au dessus d'UDP, idéalement, ce mécanisme devrait détecter la corruption le plus tôt possible, par exemple pour éviter d'injecter des paquets corrompus dans le flot transporté par un tunnel,
  • Doivent tester le chemin (est-ce que les paquets sans somme de contrôle arrivent bien ?) et fonctionner même si le chemin change et que les paquets passent soudain par une nouvelle middlebox, ayant un comportement différent,
  • Doivent utiliser des paquets avec somme de contrôle pour les contrôles, les tests, etc, pour faire la différence entre une rupture complète du lien, et un problème ne touchant que les paquets sans somme de contrôle.

Voilà, les règles d'applicabilités sont posées. Mais le RFC compte aussi une annexe intéressante, l'annexe A, qui est consacrée aux propositions alternatives. La solution choisie par le RFC 6935 a été d'autoriser les sommes de contrôle nulles. Mais on aurait pu faire différemment. Par exemple, le problème de performance et d'accès à la totalité du paquet aurait pu être traité par les calculs incrémentaux de somme de contôle du RFC 1624 (mais ils ne marchent pas quand il y a fragmentation IP). On aurait pu, comme cité, utiliser un protocole comme UDP Lite, ou UDPTT. Il avait aussi été proposé une mesure unilatérale, qu'un receveur ignore la somme de contrôle, quoiqu'ait mis l'émetteur (c'était plus simple mais il était alors impossible de détecter la corruption, pour tous les paquets). D'autres avaient suggéré une nouvelle option dans un en-tête Destination Options, ce qui revenait, à mon avis, à réintroduire une somme de contrôle en couche 3, ce qu'IPv6 avait délibérement abandonné. De toute façon, beaucoup de middleboxes auraient jeté les paquets avec cet en-tête (qui est rare, en pratique). Ces différentes propositions sont examinées en fonction de plusieurs critères : traversabilité des middleboxes, performances, déployabilité et résistance à la corruption de paquets.

Pour la traversée des middleboxes, l'UDP actuel ou bien un UDP avec un calcul incrémental des sommes de contrôle, est ce qui marche le mieux. Aucun changement à faire. L'UDP sans somme de contrôle du RFC 6935 aura sans doute quelques soucis (actuellement, de tels paquets sont illégaux), ainsi que les paquets avec l'en-tête Destination Options (pourtant légaux). Et les tunnels génériques seront sans doute bloqués par défaut par la plupart des pare-feux, ainsi qu'UDP Lite.

C'est à peu près la même chose pour la déployabilité : l'UDP actuel existe déjà et n'a pas à être déployé. Les sommes de contrôle facultatives du RFC 6935 nécessiteront au moins un changement dans les extrémités (ne pas calculer la somme, ne pas la vérifier) mais aussi dans certaines middleboxes qui se mêlent de vérifier la somme de contrôle, alors qu'on ne leur a rien demandé.

Pour les performances, l'UDP actuel est certainement le pire, puisqu'il faut calculer la somme de contrôle sur la totalité du paquet. C'est bien cela qui a motivé tout ce travail sur la réforme des sommes de contrôle UDP. UDP Lite, qui ne vérifie qu'une partie du paquet, et l'UDP réformé du RFC 6935 ont des bien meilleures performances (c'est aussi le cas des tunnels génériques).

Bref, il n'y a pas de solution parfaite, qui résolve tous les problèmes. Si on veut avant tout passer partout, l'UDP actuel est la meilleure solution. Si on veut une solution propre architecturalement, IP-in-IP est parfait. Si on se préoccupe des performances, l'UDP avec somme de contrôle facultative du RFC 6935 est une bonne approche et reçoit un avis favorable dans ce RFC.


Téléchargez le RFC 6936


L'article seul

RFC 6935: IPv6 and UDP Checksums for Tunneled Packets

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : M. Eubanks (AmericaFree.TV LLC), P. Chimento (Johns Hopkins University Applied Physics Laboratory, M. Westerlund (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 1 mai 2013


Ne dites plus qu'en IPv6, la somme de contrôle est toujours obligatoire dans les en-têtes des paquets UDP. Depuis ce RFC 6935, ce n'est plus vrai dans tous les cas. Lors de l'encapsulation de paquets dans un tunnel UDP, on a désormais le droit de ne pas mettre de somme de contrôle dans les paquets UDP, essentiellement pour des raisons de performance.

Le principal demandeur de cette modification était le protocole LISP (RFC 6830), qui dépend énormement de tunnels UDP. Même si le calcul de la somme de contrôle Internet est rapide (RFC 1071), comme ce calcul peut se faire des millions de fois par seconde pour un routeur très actif, on peut chercher à l'économiser. D'autant plus qu'il n'est pas forcément utile puisque, dans le cas d'un tunnel, le protocole qui circule dans le tunnel est déjà protégé par une somme de contrôle. À noter que d'autres protocoles que LISP (comme ceux utilisés pour le multicast) peuvent bénéficier de cette nouvelle indulgence. Mais elle ne s'applique pas aveuglément à tout UDP (comme l'avaient proposé certains au début de la discussion), uniquement aux tunnels.

La norme actuelle sur IPv6, le RFC 2460, imposait (dans sa section 8.1) une somme de contrôle pour les paquets UDP (en IPv4, elle était facultative). En effet, IPv6 n'a pas de somme de contrôle dans la couche 3 (contrairement à son prédecesseur).

Ce RFC est un produit du groupe de travail IETF 6man, qui produit inlassablement d'innombrables RFC pour combler tous les petits problèmes qui trainent encore dans IPv6 et sont révélés par son utilisation dans le vrai monde.

Notez bien que cette dispense de somme de contrôle n'est pas générale : elle concerne les cas où il y a un tunnel et où il utilise UDP. Pourquoi UDP, alors qu'il existe des protocoles de tunnel qui s'en dispensent ? Parce que l'Internet est hélas de plus en plus ossifié, et que des middleboxes stupides et boguées sont partout sur le trajet des pauvres paquets. Les techniques de tunnel directement sur IP (comme l'excellent GRE du RFC 2784) sont souvent bloquées, alors qu'UDP passe partout. On aura donc un protocole X (LISP ou un autre) à l'intérieur du tunnel et de l'UDP à l'extérieur. Hier, cet UDP à l'extérieur était forcément protégé par une somme de contrôle. Pour un routeur qui sert de terminaison à des dizaines de milliers de tunnels (ce qui n'aurait rien d'étonnant avec LISP), calculer et vérifier ces sommes peut être très douloureux. D'autant plus que le protocole X a souvent sa propre somme de contrôle : ne serait-ce pas mieux pour tout le monde que le tunnel soit non sécurisé, ses éventuelles corruptions de paquets étant détectées par le protocole X uniquement ?

La section 4 discute plus en détail de certains aspects du problème mais il vaut mieux consulter le RFC 6936 pour tout savoir. Cet autre RFC précise notamment dans quels cas supprimer la somme de contrôle est une bonne idée et dans quels cas il vaut mieux la garder. La section 4 de notre RFC note particulièrement que les paquets de contrôle du tunnel, ceux qui servent à la signalisation, devraient rester protégés (s'ils sont corrompus, le tunnel peut cesser de fonctionner, c'est-à-dire que la corruption d'un paquet va affecter d'autres paquets). Notons que certains protocoles de tunnel comme GRE n'ont aucun mécanisme de contrôle. Lorsqu'il y en a un, il est souvent utilisé pour établir un contexte au début, avec choix des paramètres pour le tunnel : ce peut être le bon moment pour négocier le non-usage des sommes de contrôle sur les paquets de données.

Autre piège rigolo : certaines middleboxes vont tiquer en voyant les paquets UDP sans somme de contrôle (bien que, normalement, la somme de contrôle soit de bout en bout et ne regarde pas ces équipements intermédiaires). Bien que ce soit désormais légal, il va falloir attendre longtemps avant que tous ces engins soient mis à jour (section 4.3). En attendant ce jour, il est prudent que le tunnel détecte les problèmes en envoyant des paquets avec et sans somme de contrôle au début : si seuls les premiers passent, c'est qu'on a une middlebox agressive sur le trajet et qu'il faut renoncer à appliquer ce RFC 6935. Le test est d'ailleurs à répéter de temps en temps : la route peut changer et on peut donc se retrouver soudain à traverser une nouvelle middlebox.

La section 4.1 conseille également de tenter de détecter la corruption avant de décapsuler, par exemple en examinant l'adresse IP source, pour minimiser le risque d'envoyer au protocole encapsulé un paquet reçu corrompu. Mais cette détection ne marchera pas à tous les cas (sinon, on pourrait supprimer les sommes de contrôle dans tous les cas) et le protocole encapsulé doit donc être robuste et réagit proprement lorsque ces paquets corrompus sont injectés dans un flux existant (section 4.2).

La section 5 contient la nouvelle norme pour les sommes de contrôle UDP. Elle remplace le texte du RFC 2460 (qui disait que la somme de contrôle UDP était toujours obligatoire en IPv6) par un texte plus nuancé : par défaut, la somme de contrôle doit être calculée et mise dans le paquet. Mais on peut s'en dispenser dans le cas de tunnels (et uniquement celui-ci), sur le paquet extérieur. Le protocole à l'intérieur du paquet (qui n'est pas forcément de l'UDP et même pas forcément de l'IPv6) doit rester protégé par sa propre somme de contrôle. Cela ne doit s'appliquer que pour une liste explicite de ports (ceux utilisés par le tunnel) et pas pour tout le trafic UDP de la machine. Et le tout doit se faire en lisant le RFC 6936 qui précise les conditions d'application de cette nouvelle règle.

Les curieux et les chercheurs en informatique noteront que la section 6 liste des points qui mériteraient davantage d'étude. Ainsi, il n'y a pas eu d'étude systématique de la corruption de paquets sur l'Internet depuis 2000 et personne ne sait donc trop si c'est un phénomène fréquent ou pas. Cette section note aussi qu'il existe en théorie une meilleure solution pour les tunnels, UDP Lite (RFC 3828), mais que sa probabilité de passer les middleboxes est plus faible que celle d'UDP.

Plusieurs des mises en œuvre de LISP envoient déjà des paquets UDP sans somme de contrôle (ou plus exactement avec une somme à zéro).


Téléchargez le RFC 6935


L'article seul

RFC 6931: Additional XML Security Uniform Resource Identifiers (URIs)

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Donald Eastlake (Huawei)
Chemin des normes
Première rédaction de cet article le 18 avril 2013


Il existe tout un ensemble de normes pour assurer la sécurité de documents XML, par exemple les protéger contre la lecture non autorisée, ou bien permettre leur authentification. Ces normes dépendent d'algorithmes cryptographiques identifiés par un URI. Ce RFC met à jour la liste précédente de ces URI (qui était dans le RFC 4051) et crée un registre des identificateurs d'algorithmes.

Ces normes de sécurité de XML étaient à l'origine un travail conjoint de l'IETF et du W3C. C'était par exemple le cas des signatures XML du RFC 3275, du XML canonique des RFC 3076 ou RFC 3741. Elles sont désormais maintenues par le W3C qui a produit des versions plus récentes (par exemple pour les signatures XML, le XML canonique ou le chiffrement XML).

Dans un monde dynamique comme celui de la cryptographie, où les progrès de la cryptanalyse nécessitent des changements d'algorithmes, les normes ne sont pas liées à un algorithme particulier. Elles permettent l'agilité cryptographique (le changement d'algorithme) et il faut donc pouvoir indiquer quel algorithme est utilisé pour signer ou chiffrer un document donné. Pour une norme W3C, on ne s'étonnera pas que l'indication se fait par le biais d'un URI. Ceux-ci commencent désormais par le préfixe http://www.w3.org/2007/05/xmldsig-more# (les anciens algorithmes pouvant avoir d'autres préfixes). Ces nouveaux algorithmes (avec 2007/05 dans leur identificateur) sont relativement rares dans ce RFC : on n'invente quand même pas un bon algorithme de cryptographie tous les jours et la plupart des exemples dans cet article utilisent donc le vieux préfixe. Rappelez-vous qu'il s'agit d'URI, pas forcément d'URL et que vous n'obtiendrez donc pas forcément un résultat en pointant votre navigateur Web vers http://www.w3.org/2001/04/xmlenc#sha256.

Notons que notre RFC 6931 ne prend pas position sur la qualité cryptographique des algorithmes : il fournit un moyen de les désigner sans ambiguité, c'est tout. Si on veut étudier cette qualité cryptographique, il faut lire d'autres documents (comme le RFC 6194 pour SHA-1).

Un exemple d'un ancien algorithme est MD5 pour calculer les condensats cryptographiques. Son URI est http://www.w3.org/2001/04/xmldsig-more#md5. Sa sécurité est aujourd'hui sérieusement battue en brèche (cf. RFC 6151). Autre exemple d'un algorithme qui était déjà dans le RFC 4051, SHA-384, identifié par http://www.w3.org/2001/04/xmldsig-more#sha384.

Un exemple d'un nouvel algorithme pour la condensation cryptographique ? Le NIST ayant récemment annoncé que le vainqueur du concours « SHA-3 » était Keccak, des URI utilisant le nouveau préfixe ont été créés pour lui, par exemple http://www.w3.org/2007/05/xmldsig-more#sha3-512 (regardez bien : sha-3 et plus sha, et la nouvelle date dans le préfixe).

Il existe aussi des identificateurs pour les MAC combinés avec une condensation, par exemple http://www.w3.org/2001/04/xmldsig-more#hmac-sha512 (RFC 6234).

Et pour les signatures avec un système à clé publique ? L'identificateur indique l'algorithme de cryptographie asymétrique et celui de condensation, par exemple http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 (voir aussi le RFC 3447). SHA-256 n'est pas tout récent et, si vous cherchez un algorithme enregistré par notre nouveau RFC, pourquoi pas Whirlpool avec http://www.w3.org/2007/05/xmldsig-more#rsa-whirlpool. Si on trouve RSA ennuyeux, il existe aussi des identificateurs pour un algorithme à courbes elliptiques (RFC 6090 mais notez ses errata), ECDSA, par exemple http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512.

Enfin, il y a les algorithmes de chiffrement symétrique. Par exemple, Camellia (RFC 3713) sera identifié par http://www.w3.org/2001/04/xmldsig-more#camellia256-cbc. Le plus récent SEED (RFC 4269) sera http://www.w3.org/2007/05/xmldsig-more#seed128-cbc.

Voici pour la cryptographie. Mais les normes de sécurité XML prévoient aussi une étape de canonicalisation avant chiffrement ou signature, et là aussi, il y a plusieurs algorithmes, identifiés par des URI comme http://www.w3.org/2000/09/xmldsig#minimal ou http://www.w3.org/2006/12/xmlc14n11#WithComments.

Quelle est la politique d'allocation dans le nouveau registre ? La section 5 décrit celle du W3C (le préfixe http://www.w3.org/2007/05/xmldsig-more# est figé, a priori, on n'y mettra pas de nouveaux algorithmes) et celle de l'IETF : comme il est facile d'obtenir un URI (n'importe qui peut en créer un), la seule question est celle de leur enregistrement. Il se fera après un examen par un expert (voir le RFC 5226 pour les politiques d'allocation IETF) après publication d'un texte décrivant le nouvel algorithme.

Quels changements depuis la version précédente de ce RFC, le RFC 4051 ? L'annexe A les liste. Les principaux, à mon avis, sont :


Téléchargez le RFC 6931


L'article seul

RFC 6929: Remote Authentication Dial In User Service (RADIUS) Protocol Extensions

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Alan DeKok (Network RADIUS), Avi Lior
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 1 mai 2013


RADIUS, un protocole utilisé pour l'authentification (et la configuration) d'accès à l'Internet, est ancien et marche toujours. Lorsque vous accédez à l'Internet depuis chez vous, sans vous en rendre compte, vous avez probablement indirectement utilisé RADIUS. Il marche toujours très bien mais, rançon du succès, il a été tellement étendu qu'un certain nombre de champs du message RADIUS sont désormais pleins : toutes les options possibles seront allouées très bientôt. Ce nouveau RFC décrit un mécanisme d'extension de RADIUS, permettant de continuer l'enregistrement de nouvelles options, au prix de quelques bricolages.

Il y a peu de gens qui manipulent RADIUS (RFC 2865) explicitement. Ce protocole se trouve en effet caché dans le réseau du FAI, entre la machine qui contrôle l'accès (le NAS) et un serveur RADIUS qui contient les données sur les utilisateurs. RADIUS permet de ne pas avoir à copier les informations d'authentification, ou les paramètres d'un utilisateur donné, directement dans tous les NAS, mais de les centraliser dans un petit nombre de serveurs RADIUS.

La requête, et surtout la réponse RADIUS peuvent contenir un certain nombre d'attributs (RFC 2865, section 5) comme « nom de l'utilisateur », « mot de passe », « adresse IP à attribuer », etc. Le champ « Attribute » est en TLV et le type (User-Name = 1, User-Password = 2, Framed-IP-Address = 8, etc) est encodé sur un seul octet. La liste (un registre IANA) est aujourd'hui bien remplie et devrait l'être complètement en 2014 ou 2015. C'est le principal problème de RADIUS aujourd'hui (section 1 de notre RFC). Mais il y en a d'autres comme le fait que la longueur d'un attribut soit codé sur un octet seulement (donc 253 octets maximum pour la valeur d'un attribut, puisqu'il faut retirer le type et la longueur).

Notre RFC fait donc les changements suivants :

  • Définition du format Extended Type : certains types d'attributs ont désormais ce format, qui inclut un second champ Type d'un octet dans la partie Valeur de l'attribut. Le nouveau type sera donc indiqué par la combinaison du Type et du nouveau champ (donc, deux octets, et le type sera noté N.M où N et M sont les valeurs des deux octets). Ça fait un peu bricolage, mais cela permet l'interopérabilité entre les nouvelles implémentations et les anciennes. Ce format est utilisé par quatre nouveaux attributs (de 241 à 244) et permet donc environ 1000 types nouveaux. La taille maximale des attributs a donc diminué d'un octet mais le deuxième changement, ci-dessous, résoud cela.
  • Définition du format Long Extended Type qui ajoute un octet (après le type) dans le champ Valeur, pour pouvoir ajouter des nouvelles fonctions au protocole. Deux attributs (245 et 246) utiliseront ce format, soit environ 500 possibilités.
  • En utilisant ce format, définition d'un mécanisme permettant de dire que la valeur est stockée sur plusieurs attributs consécutifs. Cette « fragmentation » permettra d'utiliser des attributs de plus de 253 octets. Elle est indiquée par un bit (nommé M pour More, s'il est à Un, cela indique que d'autres attributs suivent) dans le nouvel octet réservé.
  • Les types de données disponibles dans le champ Valeur étaient au nombre de cinq (les classiques, nombre entier, adresse IP, temps, texte et suite de bits). Notre RFC 6929 en ajoute deux, TLV (qui va donc permettre de structurer les données puisqu'un TLV pourra en contenir d'autres, et récursivement) et entier de 64 bits (certaines valeurs, par exemple le nombre d'octets transmis, dans les messages de comptabilité, ne tenaient plus toujours en 32 bits).

Voilà, c'est l'essentiel du RFC. Ceux qui étendent le protocole RADIUS vont sans doute migrer vers les nouveaux types, dès aujourd'hui, ou bien lorsque les anciens seront épuisés.

Des exemples d'encodage figurent en section 9. Par exemple, un attribut utilisant un type étendu (ici, 241.1) et ayant une valeur de type texte (la chaîne "bob") se représentera f1 06 01 62 6f 62 (f1, le type, 241, 06 la longueur totale, 01 le sous-type du type étendu, 1 (à la place du premier octet de la valeur), 62 6f 62 la vraie valeur, la chaîne de caractères). Plus compliqué, un attribut 241.2 contenant un TLV dont le type est 1, la longueur 4 et la valeur 23 45, sera représenté f1 07 02 01 04 23 45.

Avec les étendus longs (Long Extended Type), un attribut 245.1 contenant le même "bob" sera f5 07 01 00 62 6f 62 (f5 est le type, la longueur est de sept octets, 01 est la suite du type, l'octet supplémentaire est à 0 (donc le bit M aussi : pas d'autres attributs à attendre) et la valeur est la chaîne "bob" (62 6f 62 en ASCII). Si un type 245.4 encode plus de 251 octets (ici, 260 octets de valeur), on aura le premier attribut qui commencera par f5 ff 04 80 (longueur totale à 256 octets, l'octet supplémentaire vaut 80, indiquant que le bit M est à Un) et un deuxième attribut qui commencera par f5 13 04 00 (octet supplémenaire à 0 donc bit M à Zéro, ce second attribut est le dernier). La longueur totale est ff + 13 soit 260 octets pour la valeur.

Si vous voulez tester vous-même ces nouveaux types et leur encodage, l'annexe A du RFC contient un programme en C qui permet exactement cela (copie locale du source). Il s'utilise ainsi :

% echo '241.1 "bob"' | ./radius-attr-generator
241.1 "bob" -> f1 06 01 62 6f 62 

% echo '243.2 42' | ./radius-attr-generator
243.2 42 -> f3 04 02 42

# Plus drôle, un TLV dans un TLV :
% echo '241.4 { 1 23 45 } { 3 { 1 ab cd } }' | ./radius-attr-generator
241.4 { 1 23 45 } { 3 { 1 ab cd } } -> f1 0d 04 01 04 23 45 03 06 01 04 ab cd 

Parmi les autres nouveautés du RFC, il y a la formalisation de la convention de nommage informel des attributs : mots séparés par des tirets (par exemple Framed-MTU), attributs spécifiques à un vendeur préfixés par le nom du vendeur (par exemple Starbucks-Latte-Size pour un vendeur nommé Starbucks).

Le changement apporté au protocole n'est pas trivial, mais soigneusement conçu pour maintenir la compatibilité. La section 5 du RFC note toutefois quelques problèmes potentiels. D'abord, certains vendeurs se sont approprié des numéros de types qui étaient marqués comme réservés (et qui sont désormais utilisés pour les types étendus). Comme le notait le RFC 6158, c'est un comportement anti-social. Maintenant que ces numéros réservés sont utilisés, ces attributs spécifiques au vendeur anti-social ne marcheront plus (bien fait).

Autre problème potentiel, il est fréquent que les messages RADIUS soient relayés par un serveur intermédiaire (RFC 2865, section 2.3), notamment en cas d'itinérance. Idéalement, le relais devrait ignorer les attributs qu'il ne comprennent pas. Si, par contre, il rejette les messages contenant ces attributs nouveaux, un client et un serveur conformes au nouveau format ne pourront pas communiquer à travers un tel relais. Notre RFC rappelle bien qu'un relais devrait être transparent et relayer même ce qu'il ne comprend pas.

Les sections 6.6 et 10.3 fournissent les règles d'enregistrement des nouveaux types. Il est recommandé d'y aller mollo : les nouveaux espaces sont plus grands mais pas infinis. Le registre IANA stocke désormais des attributs des nouveaux types.

Devoir ajuster a posteriori un protocole, qui avait été conçu d'une certaine manière, et qui esr assez rigide, est toujours une opération délicate, spécialement lorsqu'il faut maintenir la compatibilité avec l'existant. Des tas de propositions ont été faites depuis des années, pour étendre RADIUS. La section 7 du RFC documente pourquoi celle-ci a été choisie. D'abord, elle est relativement simple, avec peu de modifications du format. Son principal inconvénient est que le format des Long Extended Type est assez baroque.

Quant au mécanisme pour agrandir la taille possible des valeurs, il a d'abord été conçu pour ne pas changer les attributs dont la valeur restait petite. D'après une étude de 2010 (citée en section 7.1) portant sur tous les dictionnaires Radius connus, les entiers représentent près de la moitié des valeurs d'attributs RADIUS publics. En ajoutant les autres types de taille fixe (adresses IP, par exemple), on arrive à plus de la moitié. Il fallait donc éviter de faire payer ces types peu consommateurs en octets.

Plusieurs des mises en œuvre de Radius gèrent déjà ces extensions, par exemple FreeRADIUS. Il faut dire qu'il n'y a guère le choix, vue l'imminence de l'épuisement.


Téléchargez le RFC 6929


L'article seul

RFC 6928: Increasing TCP's Initial Window

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : J. Chu, N. Dukkipati, Y. Cheng, M. Mathis (Google)
Expérimental
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 30 avril 2013


Sur l'Internet, il y a des choses qu'on hésite à toucher. Depuis quelques épisodes fameux de « catastrophes congestives », où tout l'Internet s'est arrêté en raison de l'encombrement des tuyaux, la mémoire collective du réseau, incarnée notamment par l'IETF, voit avec une extrême méfiance toute modification des algorithmes de TCP, qui sont la principale ligne de défense de l'Internet face à la congestion. Néanmoins, le réseau évolue, les choses changent et il y a des gens qui insistent pour essayer des changements. Cela fait un certain temps que Google réclame une modification connue sous le doux nom de IW10 (pour Initial Window 10 segments) et ce RFC est le premier à la documenter officiellement, après trois ans de discussion dans le groupe de travail. Pour l'instant, c'est encore étiqueté comme « expérimental ».

La norme reste celle du RFC 3390. Elle dit que la fenêtre initiale d'une connexion TCP, à savoir le nombre maximal d'octets qu'on peut envoyer avant le premier accusé de réception, est donnée par une formule qui, en pratique est d'environ 4 kilo-octets, soit deux à trois segments (paquets TCP), parfois quatre. Voici, vu par tcpdump sur le client, un exemple entre deux machines séparées par 100 ms de RTT, un client HTTP qui demande un gros fichier et un serveur :

21:54:15.371487 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 1:1449, ack 118, win 1810, 
options [nop,nop,TS val 1079804426 ecr 2768078], length 1448
21:54:15.371509 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 1449, win 137, options [nop
,nop,TS val 2768109 ecr 1079804426], length 0
21:54:15.372574 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 1449:2897, ack 118, win 181
0, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448
21:54:15.372593 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 2897, win 182, options [nop
,nop,TS val 2768109 ecr 1079804426], length 0
21:54:15.372615 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 2897:4345, ack 118, win 181
0, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448
21:54:15.372630 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 4345, win 227, options [nop
,nop,TS val 2768109 ecr 1079804426], length 0
21:54:15.372897 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [P.], seq 4345:5793, ack 118, win 18
10, options [nop,nop,TS val 1079804426 ecr 2768078], length 1448
21:54:15.372910 IP 192.168.2.1.57886 > 204.62.14.153.80: Flags [.], ack 5793, win 273, options [nop
,nop,TS val 2768109 ecr 1079804426], length 0
21:54:15.488019 IP 204.62.14.153.80 > 192.168.2.1.57886: Flags [.], seq 5793:7241, ack 118, win 181
0, options [nop,nop,TS val 1079804455 ecr 2768109], length 1448

On voit que 204.62.14.153 a envoyé quatre segments avant de devoir s'arrêter, les accusés de réception n'ayant pas eu le temps de l'atteindre. La pause dure 116 ms, avant que le serveur ne reprenne son envoi.

Ce nombre de segments est trop petit (bien plus petit que les tampons d'entrée/sortie d'un équipement réseau typique) car, sur les réseaux modernes, cela veut dire qu'un pair TCP qui veut envoyer un gros fichier va très vite remplir cette fenêtre et va devoir attendre ensuite, alors qu'il ne sait absolument pas si le réseau est congestionné ou pas. D'où la proposition IW10 qui est de permettre l'envoi de dix segments. (Pourquoi dix ? Comme l'explique l'annexe A, c'est le résultat de tests avec plusieurs valeurs possibles. Dix était la valeur qui était le meilleur compromis entre les gains et les inconvénients. Regardez le dessin 2 dans l'article An Argument for Increasing TCP's Initial Congestion Window si vous avez besoin d'être convaincu : il montre un progrès jusqu'à 16 et une baisse ensuite. Notez qu'une des techniques étudiées par le groupe de travail - et finalement abandonnée - avait été un système complexe de mesure et de rétroaction, avec des tailles initiales de fenêtre variables.)

La formule proposée par ce RFC (section 2) est fenêtre_initiale (en octets) = minimum (10*MSS, maximum (2*MSS, 14600)). Cela pourra faire jusqu'à dix segments, en fonction de la MSS. Naturellement, la machine aura le droit de choisir une fenêtre plus petite, ce choix n'est en effet pas dangereux ; mais pas de fenêtre plus grande, le but étant d'éviter la congestion de réseau.

Notez bien que cette formule ne s'applique qu'au début de la connexion. Lorsque TCP reprend son algorithme de démarrage en douceur (slow start), par exemple suite à des pertes de paquets, il doit s'en tenir au RFC 2581.

Il y a aussi quelques questions pratiques à se poser. Par exemple, une connexion TCP est bi-directionnelle : ce n'est pas tout d'utiliser une fenêtre plus grande à l'émission, il faut aussi annoncer à son pair une fenêtre de réception plus grande (cf. « An Argument for Increasing TCP's Initial Congestion Window » de Dukkipati, N., Refice, T., Cheng, Y., Chu, J., Sutin, N., Agarwal, A., Herbert, T. et J. Arvind, article de 2010 qui va être souvent cité ici et dont je recommande fortement la lecture. À l'époque de l'article, la plupart des systèmes annonçaient cette grande fenêtre, sauf Linux.)

Ce changement a des conséquences pour les applications qui utilisent TCP (section 3). Ainsi, HTTP 1.1 n'autorisait que deux connexions TCP simultanées vers le même serveur (RFC 2616, section 8.1.4, mais le RFC 7230 a libéralisé cette consigne). Les navigateurs en ouvrent en général plus que cela, pour éviter l'attente due à la faible taille de la fenêtre TCP. (Voir « A Swifter Start for TCP », par Partridge, C., Rockwell, D., Allman, M., Krishnan, R. et J. Sterbenz, rapport technique n° 8339 de BBN en 2002.) C'est égoïste de leur part (cela s'oppose aux mécanismes de contrôle de congestion de TCP) et cela ne devrait logiquement plus être nécessaire avec le déploiement d'IW10. Le RFC conseille donc de réduire le nombre de connexions HTTP simultanées.

La section 4 du RFC donne des éléments de contexte et d'histoire. Au début (cf. le célébrissime article de Van Jacobson, « Congestion Avoidance and Control », en 1998), TCP ne pouvait envoyer qu'un seul segment avant de recevoir le premier accusé de réception. Ce n'était pas un problème pour de longues communications, comme celles de telnet. Mais l'Internet aujourd'hui voit surtout du trafic Web (cf. « Atlas Internet Observatory 2009 Annual Report » de Labovitz, C., Iekel-Johnson, S., McPherson, D., Oberheide, J. Jahanian, F. et M. Karir, présenté à NANOG 47 en 2009.), avec des connexions de courte durée. Attendre longtemps avant de pouvoir envoyer plusieurs segments est très pénalisant (la plupart de ces connexions courtes ne quitteront jamais l'état TCP « démarrage en douceur »).

Surtout, les changements dans la capacité des réseaux ont été spectaculaires. Le rapport « The State of the Internet » d'Akamai en 2010, annonce que les accès à plus de 2 Mb/s forment désormais la majorité, ce qui met la capacité moyenne à 1,7 Mb/s, alors que, pendant ce temps, la fenêtre d'envoi initiale de TCP restait aux 4 ko du RFC 2414, sans bouger pendant dix ans. Avec un RTT de 200 ms, cette fenêtre ne permettait que 200 kb/s.

Des tas de changements avaient été proposés (pour ne citer que les RFC, voir RFC 4782 et RFC 6077) mais sans être réellement déployés. Ce sont donc les applications qui se sont adaptées, comme vu plus haut avec les navigateurs qui ouvrent plusieurs connexions, et les sites Web créant des sous-domaines sans autre raison que de débrayer la limitation du nombre de connexions par serveur (cf. « A Client-Side Argument For Changing TCP Slow Start » en 2010). Le déploiement d'IW10 devrait logiquement s'accompagner d'un changement de stratégie de ces navigateurs Web.

Au fait, en parlant d'HTTP, les connexions persistentes de HTTP 1.1 ne devraient-elles pas résoudre le problème ? Le problème est que les mesures faites avec Chrome (article de Dukkipati et al. cité plus haut) montrent que 35 % des requêtes sont faites sur des nouvelles connexions, ne pouvant pas tirer profit des connexions persistentes.

Bon, mais, au fait, quels sont les avantages exacts qu'il y a à agrandir la fenêtre initiale ? La section 5 les examine en détail. D'abord, on réduit la latence. Par exemple, si on a 21 segments à envoyer, IW3 (fenêtre initiale de trois segments) va nécessiter 4 aller-retour (envoi de données + attente de l'accusé de réception) contre 2 pour IW10. Ensuite, une telle augmentation est cohérente avec l'augmentation régulière de taille des objets. Par exemple, sur le Web, les études citées par le RFC (mesures faites sur le moteur de recherche Google) montrent que seules 10 % des ressources sur le Web tiennent encore dans les 4 ko du RFC 3390. En outre, si on utilise les connexions persistentes de HTTP 1.1, on aura encore plus de données à transmettre sur une connexion HTTP. Le Web grossit, il est logique que la fenêtre initiale de TCP suive le mouvement.

Et il n'y a pas d'inconvénients à augmenter la taille de la fenêtre initiale ? Les sections 6 et 7 décrivent le côté obscur. D'abord, en section 6, les risques pour l'utilisateur. Il y a notamment le risque de remplir complètement les tampons d'entrée-sortie dès le démarrage, pour des petits routeurs. Le RFC estime toutefois que ce risque est faible avec les tampons actuels, en s'appuyant sur l'étude « Characterizing Residential Broadband Networks » de Dischinger, M., Gummadi, K., Haeberlen, A. et S. Saroiu, en 2007, qui montre que le routeur typique de M. Michu a au moins 130 ms de tampon.

Ça, c'était pour l'utilisateur. Et pour le réseau (section 7) ? Risque t-on davantage de congestion ? Probablement pas puisque IW10 ne s'applique qu'au début de la connexion. Tout le reste du mécanisme de contrôle de la congestion de TCP reste en place, inchangé, notamment sa réaction aux pertes de paquets. En revanche, il peut y avoir un problème de justice. Tant qu'une partie des machines applique IW10 et qu'une autre partie en est resté au RFC 3390, les machines IW10 vont prendre une part plus grande des ressources réseau (c'est une question générale de l'Internet : la répartition juste entre différentes connexions concurrentes dépend de leur bonne volonté). C'est donc un point à surveiller. (Un autre problème de justice est traité dans l'annexe A, entre des machines toutes IW10 mais où certaines n'ont pas dix segments à envoyer. Les mesures semblent indiquer que ces dernières machines ne sont pas défavorisées.)

Autre inconvénient possible : comme IW10 remplit plus vite les tampons d'entrée/sortie des routeurs, si ceux-ci sont trop grands (phénomène du bufferbloat), IW10 va aggraver le problème. Les protocoles sensibles à la latence comme le DNS ou certains jeux vont alors souffrir. Les mécanismes proposés comme alternative au bufferbloat (ECN, AQM, etc) sont alors encore plus nécessaires.

En synthèse (section 8), le RFC estime que le plus gros risque est pour les utilisateurs ayant des liaisons lentes avec des tampons d'entrée/sortie réduits, dans leur box. Les 10 segments initiaux peuvent, dans certains cas, faire déborder ces tampons, le réseau ne pouvant pas les envoyer assez vite. Le RFC suggère, si on détecte qu'on est sur un tel lien, de ne pas envoyer forcément les dix segments autorisés, et d'annoncer une fenêtre de réception plus petite. Voir aussi le RFC 3150, sur le problème général de ces liens lents.

La théorie, c'est bien joli mais, quand elle dit qu'il ne faut pas trop s'inquiéter, il est prudent de vérifier par des mesures effectives, pas juste des raisonnements. C'est ce que fait la section 10. L'expérience a été faite par Google dans deux de ses centres de données, l'un voyant plutôt des clients ayant la capacité réseau moyenne, l'autre ayant en moyenne des utilisateurs de connexions lentes (20 % à moins de 100 kb/s). Avec IW10, la latence a baissé de 11,7 % dans le centre moyen et 8,7 % dans le centre lent. En regardant plus finement, les auteurs ont constaté que, comme l'indiquait la théorie, les bénéfices les plus importants d'IW10 ont été pour les gens situés loin (forte latence réseau) mais ayant des connexions rapides (ce qu'on nomme le BDP élévé avec BDP = Bandwidth-Delay Product). Mais, contrairement à la théorie, même les clients à capacité réseau limitée ont vu une amélioration. (Voir l'exposé « Increasing TCP initial window » de Dukkipati, D., Cheng, Y., Chu, J. et M. Mathis, présenté à l'IETF 78 en 2010.) Aucun problème grave n'a été observé.

D'autres expériences ont été faites, listées sur le site Web du projet IW10 ou en section 11 de ce RFC. Notez toutefois que la plupart sont des simulations, pas des mesures sur le vrai Internet. Mais ce n'est pas forcément très grave, l'étude de Google, par son ampleur, a semblé largement suffisante. Bien des RFC ont été adoptés sans une aussi grande étude préalable !

L'annexe A du RFC contient une liste d'inquiétudes théoriques sur IW10 et les résultats des tests spécifiquement liés à chacune de ces inquiétudes. Ainsi, le taux de pertes de paquets n'a pas augmenté lors des tests, sauf lors de cas extrêmes où, même avec les valeurs du RFC 3390, le phénomène de pertes se produisait. De même, des mesures ont été faites en Afrique, pas seulement en Europe et en Amérique du Nord, pour s'assurer qu'IW10 n'aurait pas d'effet pénible pour les liens moins favorisés.

En conclusion, le RFC recommande (section 12) d'activer IW10 mais que les fournisseurs de mises en œuvre de TCP et/ou les administrateurs réseau surveillent le trafic, à la recherche d'indicateurs comme le taux de pertes de paquet, pour détecter une éventuelle augmentation des phénomènes négatifs.

Ce changement de la fenêtre initiale est déjà apparue dans certains systèmes. Par exemple, pour Linux, cela a été fait en 2011 dans le commit git 442b9635c569fef038d5367a7acd906db4677ae1. Notez que, sur Linux, ip route ... initcwnd N vous permet d'ajuster cette variable, pour expérimenter.

Un peu de lecture supplémentaire ? Le premier exposé sur IW10 date de 2010. Une argumentation hostile à IW10 ? Vous pouvez lire l'Internet-Draft draft-gettys-iw10-considered-harmful.


Téléchargez le RFC 6928


L'article seul

RFC 6927: Variants in Second-Level Names Registered in Top Level Domains

Date de publication du RFC : Mai 2013
Auteur(s) du RFC : J. Levine (Taughannock Networks), P. Hoffman (VPN Consortium)
Pour information
Première rédaction de cet article le 7 mai 2013


Beaucoup d'utilisateurs des noms de domaine pensent que deux noms qui, pour eux, sont « le même », devraient être traitées d'un bloc par le DNS et/ou par les systèmes d'enregistrement de noms. Tout le problème est évidemment de définir « le même » : il n'y a en général pas d'accord entre les utilisateurs sur ce point. Ainsi, des anglophones peuvent penser que meter.example et metre.example sont « le même nom » et devraient donc se comporter ainsi. D'autres pensent que pizzeria-napoli.example et pizzerianapoli.example sont « le même nom ». Et, évidemment, depuis l'arrivée des IDN, le potentiel pour des noms « identiques » a encore augmenté. Il a donc été proposé que ces variantes d'un « même » nom soient explicitement reconnues. Ce RFC ne suggère pas de mécanisme en ce genre (je pense personnellement que le problème est bien trop flou et subjectif pour cela). Il se contente de regarder les pratiques actuellement déployées par les registres en matière de « variantes ».

Des exemples de caractères qui sont une « variante » d'un autre ne manquent pas dans les écritures du monde. Ainsi, la Chine a connu sous Mao une réforme orthographique, passant des sinogrammes « traditionnels » aux « simplifiés ». La plupart des sinophones considèrent que et sont des variantes du même mot. Dans les langues utilisant l'alphabet latin avec des accents, certains considèrent que le mot avec et sans accent sont des variantes l'un de l'autre. Le RFC note qu'en français certains omettent les accents sur les majuscules (c'est incorrect, mais cela se fait parfois) et que donc INTERNÉ et INTERNE sont considérés comme « équivalents ». Ce qui est sûr, c'est qu'historiquement, les difficultés à manier les caractères non-ASCII dans beaucoup d'environnements informatiques avaient mené bien des utilisateurs à considérer les accents comme purement décoratifs, et pouvant être omis.

Est-ce que ce vague sentiment que deux groupes de caractères sont « la même chose » peut être formalisé dans une définition rigoureuse des « variantes » ? Il y a eu quelques tentatives comme à l'ICANN, ou à l'IETF dans le RFC 3743 (non standard). Mais un autre document de la même ICANN concluait qu'il n'existait pas de définition utilisable. Ensuite, sur le comportement attendu de deux noms identiques ne fait pas non plus l'objet d'un consensus. Par exemple, si on veut, non pas seulement une réponse identique dans le DNS, mais un vécu de l'utilisateur identique, par exemple sur le Web, il n'y a aucune solution purement DNS (en raison du comportement de HTTP avec le champ Host:). Si vous voulez lire davantage sur cette question, je vous renvoie à mon article « Que veut dire synchroniser deux domaines ? ».

Ce RFC n'essaie donc pas de régler ce problème (très ancien et sans doute insoluble). Il fait un tour d'horizon des pratiques des gTLD (qui sont contractuellement obligés par l'ICANN de rédiger leurs pratiques IDN et de les déposer à l'ICANN, et qui rendent accessibles le contenu de leurs zones, permettant aux chercheurs de l'étudier) et d'un certain nombre de ccTLD. Ces obligations de l'ICANN sont décrites dans « Guidelines for the Implementation of Internationalized Domain Names ». Le RFC note que ces règles ne sont guère respectées, les politiques déposées à l'ICANN étant souvent dépassées et plus à jour (URL cassés, personnes désormais parties, etc). (Mon opinion personnelle est que ces « IDN Guidelines » n'ont aucun sens et sont motivées par des frayeurs bureaucratiques plutôt que par des considérations pratiques.)

Pensez à réviser la terminologie en section 2. Un lot (bundle, on dit aussi IDL package) est un ensemble de noms qui sont tous des variantes les uns des autres (RFC 3743). Un nom est alloué (allocated) ou enregistré s'il est attribué à un titulaire. Il est actif (active) s'il apparait dans le DNS. Il est bloqué (blocked) s'il ne peut pas être alloué du tout et réservé (witheld) s'il ne peut être alloué que dans certaines conditions.

La section 4 décrit les politiques des gTLD (avec vérification dans les fichiers de zone de la réalité de ces politiques). Certains sont faciles : .aero, .coop ou .pro n'ont pas d'IDN (même chose pour .xxx). D'autres ont un grand intérêt pour les IDN. Ainsi, .asia a évidemment une politique IDN détaillée, avec gestion de lots, via les enregistrements NS (les variantes ont le même jeu de NS). .cat a un cas plus simple que .asia puisqu'il ne reconnait qu'une seule langue, le catalan. La liste des caractères autorisés est publiée et elle comprend des caractères comme le l·l (considéré comme un caractère en catalan mais représenté par trois caractères Unicode). Lorsqu'on enregistre un nom IDN, l'ASCII « équivalent » est aussi enregistré et un DNAME (RFC 6672) est mis dans le fichier de zones (il semble que cela soit le seul gTLD à procéder ainsi). Par exemple :

xn--caball-gva.cat.	43200	IN	DNAME	caballe.cat.

Le nom IDN caballé.cat pointant vers l'ASCII caballe.cat (et merci à DNSDB pour permettre l'exploration facile du DNS à la recherche d'exemples).

Contrairement à .asia et a fortiori à .cat, .com doit gérer toutes les écritures du monde. VeriSign a transmis à l'ICANN des tables pour des écritures hiéroglyphiques et pour l'araméen... Les politiques suivies sont décrites en détail dans plusieurs documents (voir la liste dans la bibliographie du RFC). Pour l'écriture chinoise, et pour elle seule, les variantes d'un nom alloué sont bloquées. (.net et .name suivent la même politique que .com.)

.org publie une liste des langues gérées (notez que c'est absurde puisque IDN gère des écritures, pas des langues, mais cette confusion est fréquente dans les cercles ICANN, où il est toujours mal admis que des gens osent utiliser d'autres écritures que celle des États-Unis). Les tables déposées à l'ICANN sont un sous-ensemble de ces tables publiées par le registre (pas de mise à jour ?) Les documentations officielles de .org font allusion à une politique de gestion des variantes mais apparemment sans dire en quoi consiste cette politique.

.tel a beaucoup d'IDN et une politique publique. Les noms avec l'écriture japonaise utilisent un système de blocage (le premier arrivé empêche l'allocation des variantes) alors que pour l'écriture chinoise, les variantes sont publiées (avec des enregistrements NS identiques).

La section 5 passe aux ccTLD. Je ne vais pas tous les citer mais ils ont souvent des politiques intéressantes. .cl publie sa politique, qui ne tient pas compte d'éventuelles variantes.

.cn a évidemment plus de travail : leur politique est publiée sous forme d'un RFC, le RFC 4713. Les variantes sont publiées, avec des enregistrements NS. Par contre, .ir n'a pas d'IDN. Comme un certain nombre de registres des pays utilisant l'écriture arabe (qui va de droite à gauche), ils considèrent que le mélange d'un nom en écriture arabe avec un TLD en écriture latine (allant de gauche à droite) n'est pas souhaitable. (Mais il y a des IDN dans le TLD équivalent en écriture arabe, ایران.)

Bien que TLD d'un pays majoritairement anglophone, .nz a une politique IDN (qui ne parle pas des variantes) pour le maori. On notera que le domaine compte des DNAME par exemple māori.dns.net.nz qui pointe vers l'équivalent ASCII :

xn--mori-qsa.dns.net.nz. 86400	IN	DNAME	maori.dns.net.nz.

Contrairement aux autres ccTLD, il semble que .ru ne publie pas sa politique directement, uniquement via la table déposée à l'ICANN.

La politique utilisée par .fr n'est pas étudiée dans ce RFC. Elle est disponible en ligne. La liste des caractères acceptés figure en section 2 (ce sont les caractères utilisés pour les langues d'Europe de l'Ouest). S'il y a eu un système de variantes pendant la période d'ouverture (section 4), il a ensuite disparu.

Voilà, si vous voulez approfondir la question et voir la politique des autres TLD, consulter ce RFC. J'espère en tout cas avoir donné une bonne idée de la variété des écritures du monde et des solutions pour les gérer dans les noms de domaine.


Téléchargez le RFC 6927


L'article seul

RFC 6924: Registration of Second-Level URN Namespaces Under "ietf"

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : B. Leiba (Huawei)
Pour information
Première rédaction de cet article le 11 avril 2013


Dans la grande famille des URN, l'IETF avait son propre espace, commençant par ietf. Mais il n'existait pas de registre des sous-espaces de ietf. C'est désormais fait.

Le RFC 2648 avait créé cet espace ietf. Il avait quelques sous-espaces comme rfc (donc, par exemple, ce RFC est urn:ietf:rfc:6924.) Le RFC 3553 avait créé un nouveau sous-espace params, et un registre pour ce sous-espace. Ainsi, on voit des URN comme urn:ietf:params:xml:ns:vcard-4.0 (RFC 6350) ou urn:ietf:params:xml:ns:netconf:base:1.0 (RFC 6241). Mais peut-on créer encore d'autres sous-espaces que params ? Et où les décrire ?

Un registre existe désormais à cette fin. Il sera rempli selon la procédure (assez lourde) « examen par l'IETF » du RFC 5226. On n'y trouve pour l'instant que les sous-espaces des RFC 2648 et RFC 3553.


Téléchargez le RFC 6924


L'article seul

RFC 6922: The application/sql Media Type

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Y. Shafranovich (BioFortis)
Pour information
Première rédaction de cet article le 11 avril 2013


Premier enregistrement d'un nouveau type de données (type MIME) fait depuis les nouvelles règles du RFC 6838, ce RFC enregistre un type très ancien mais qui n'avait jamais été normalisé, application/sql, pour le code source SQL.

Donc, les nouvelles procédures du RFC 6838 marchent, même pour un type très ancien. SQL a plus de trente ans d'usage derrière lui. La section 3 contient le formulaire d'enregistrement du nouveau type application/sql. Ce formulaire rempli met en garde contre quelques pièges de SQL comme le fait que l'encodage puisse être indiqué dans le fichier (ce qui rend inutile le paramètre charset du type MIME), ou comme les problèmes de sécurité si un client était assez naïf pour exécuter aveuglément du SQL récupéré sur le réseau (quoique j'ai rarement vu du malware en SQL...). Le formulaire d'enregistrement comprend aussi une section sur les problèmes d'interopérabilité et elle note que, bien que SQL soit une norme ISO (norme 9075.2011, pas disponible en ligne), les différences entre mises en œuvre du langage sont quand même très grandes. Verra t-on un jour des types plus spécifiques comme application/oracle+sql ou application/postgres+sql ?

J'ai modifié la configuration Apache de ce blog pour y ajouter :

AddType application/sql .sql

Et, désormais, des fichiers comme joins.sql (cité dans cet article) sont servis avec le nouveau type MIME. N'était-ce pas mieux en text/plain (par défaut affiché dans le navigateur) ? J'hésite.


Téléchargez le RFC 6922


L'article seul

RFC 6920: Naming Things with Hashes

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Farrell (Trinity College Dublin), D. Kutscher (NEC), C. Dannewitz (University of Paderborn), B. Ohlman, A. Keranen (Ericsson), P. Hallam-Baker (Comodo Group)
Chemin des normes
Première rédaction de cet article le 22 avril 2013
Dernière mise à jour le 23 avril 2013


La question des identificateurs sur le Web agite des électrons depuis le début. Il n'existe pas d'identificateurs idéaux, ayant toutes les bonnes propriétés. Dans la grande famille des URI (RFC 3986), il faut donc choisir selon l'importance qu'on donne à tel ou tel critère. Par exemple, si on attache du prix à la stabilité de l'identificateur et qu'on veut qu'il ne désigne pas seulement un endroit où se trouve un contenu, mais qu'on veut qu'il désigne ce contenu et pas un autre ? Alors, on peut choisir les nouveaux URI ni: (Named Information) qui désignent un contenu par un condensat (hash). Un URI ni: ne change pas si le contenu change de serveur, mais il est modifié si le contenu lui-même change. C'est donc une forme d'adressage par le contenu.

À quoi cela sert ? À éviter un problème de l'indirection : si je dis « regardez l'image en http://www.example.org/holidays/beach.png » et que l'image de vacances à la plage est remplacée par une photo de LOLcat, l'URI sera toujours valable, alors que le contenu a changé. Inversement, si un webmestre incompétent et qui n'a pas lu « Cool URIs don't change » réorganise le site et met le contenu en http://www.example.org/bigcomplicatedcmswithsecurityholes.php?kind=image&tag=beach&foo=bar&id=612981, l'URI ne marchera plus alors que le contenu est inchangé. Un autre exemple, plus positif, est le cas où un contenu est répliqué en plusieurs endroits, ayant des URL différents. Il faut pouvoir désigner le contenu, indépendamment du service qui l'héberge. C'est pour répondre à ces deux problèmes qu'a été créé par ce RFC le plan d'URI ni: (désormais dans le registre IANA des plans d'URI). Le contenu en question pourra donc être désigné par ni:///sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc. Une telle technique a déjà été employée mais de manière non standard (par exemple, on voit parfois des URI du genre http://www.example.org/hash?function=sha256&value=rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc où un programme situé sur www.example.org récupère la ressource selon le contenu). Désormais, le but est de permettre du vrai adressage par le contenu sur le Web. Cela se nomme information-centric sur les PowerPoint des gourous. Sur ce sujet, le RFC recommande la lecture de « Design Considerations for a Network of Information » de Ahlgren, D'Ambrosio, Dannewitz, Marchisio, Marsh, Ohlman, Pentikousis, Rembarz, Strandberg, et Vercellone, ainsi que des articles de Van Jacobson. On peut aussi lire des articles sur les autres mécanismes d'adressage par le contenu comme les magnet links de plusieurs systèmes pair-à-pair, comme Freenet.

Une fois le contenu récupéré (en HTTP ou par d'autres moyens), le lecteur peut alors recalculer le condensat et vérifier s'il a bien reçu le bon fichier (des protocoles comme BitTorrent utilisent un mécanisme analogue pour s'assurer que le fichier transmis par les pairs est bien celui qu'on voulait).

D'autres informations peuvent se retrouver dans l'URI ni: (voir des exemples plus loin) mais la comparaison de deux URI ni: se fait uniquement sur le couple {fonction de hachage utilisée, valeur du condensat}.

Le condensat est calculé par une fonction de hachage cryptographique et, par défaut, c'est SHA-256 (vous avez noté le sha256 dans l'URI ni: donné en exemple plus haut ?) Les valeurs possibles pour l'algorithme de hachage figurent dans un nouveau registre. Les nouvelles valeurs sont enregistrées selon une procédure légère d'examen par un expert (RFC 5226 et section 9.4 de notre RFC).

Les condensats de SHA-256 sont de grande taille, parfois trop pour certaines utilisations. On a donc le droit de les tronquer à leurs N premiers bits et le nom d'algorithme indiqué doit préciser cette troncation. Ainsi, si on garde les 32 premiers bits, on doit indiquer sha256-32 et pas juste sha256. Attention, c'est évidemment au détriment de la sécurité (si la sortie de SHA-256 est si longue, c'est pour une bonne raison, cf. RFC 3766) et ces condensats raccourcis, quoique simples à manipuler, ne protègent plus tellement. (Notez que le VCS git, qui identifie les commits par un condensat cryptographique, permet également de les raccourcir, pour faciliter son utilisation, par exemple depuis le shell.)

Le format exact des URI ni: figure en section 3. On note un composant dont je n'ai pas encore parlé, l'autorité. On peut écrire ni:///sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc mais aussi ni://www.example.net/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc. L'autorité (ici, www.example.net) désigne un endroit où on pourra peut-être récupérer la ressource. Le gros problème des identificateurs fondés sur le contenu du fichier, en effet, est qu'ils sont inutiles pour accéder effectivement au fichier : pas moyen de télécharger un fichier dont on ne connait que le condensat ! Il existe plusieurs solutions et l'une d'elles est de passer par l'autorité. L'idée est que l'URI ni: est automatiquement transformé en un URL HTTP sous .well-known (cf. RFC 5785 et section 4 de notre RFC). Ainsi, ni://www.example.net/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc devient http://www.example.net/.well-known/ni/sha256/rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc qu'on peut ensuite récupérer par des moyens classiques. On combine alors les avantages de l'adressage par le contenu (le condensat est là pour vérifier le contenu) et du fait que les URL marchent bien pour récupérer un contenu. On notera que le système d'identificateurs ARK a un mécanisme analogue (un identificateur stable et non résolvable plus un préfixe qui permet de faire un URL résolvable et actionnable). On a ainsi le beurre et l'argent du beurre. ni fait désormais partie des termes enregistrés dans le registre "well-known".

Petite question : pourquoi http: et pas https:, qui serait plus sûr ? Parce que tous les serveurs ne gèrent pas HTTPS et aussi parce que ce n'est pas nécessaire pour s'assurer de l'intégrité du fichier récupéré, le condensat cryptographique suffit. Bien sûr, une mise en œuvre de ce RFC est autorisée à essayer avec HTTPS, par exemple pour la confidentialité.

Comme indiqué plus haut, la comparaison entre deux URI ni: se fait uniquement sur le couple {algorithme, condensat} donc ni://datastore.example/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc et ni://www.example.net/sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc sont identiques.

Au fait, SHA-256 peut être affiché en binaire ou bien sous une forme hexadécimale. Laquelle est utilisée ? Le format binaire suivi d'un encodage en Base64 (RFC 4648), sous sa forme URL encoding, celle qui utilise _ et - au lieu de / et + (ce n'est pas la forme par défaut : songez que l'outil base64 sur Unix ne permet pas de produire cette variante).

Si on n'a pas besoin d'être lisible par des humains et transmissible dans des textes, il existe aussi une forme binaire, plus compacte, des URI ni:, spécifiée en section 6.

Signe de leur souplesse, les URI ni: ont également une forme « prononçable ». S'il faut dicter un URI au téléphone, l'encodage par défaut est très ambigu (par exemple, minuscules et majuscules n'ont pas la même valeur). D'où la syntaxe nih: (NI for Humans et non pas Not Invented Here, cf. RFC 5513) de la section 7. Les URI sous leur forme nih: sont en Base16 (RFC 4648), peuvent inclure des tirets supplémentaires, pour la lisibilité, et incluent une somme de contrôle (le dernier chiffre, calculé selon l'algorithme de Luhn de la norme ISO 7812) pour détecter les erreurs de compréhension. Un exemple est nih:sha-256-120;5326-9057-e12f-e2b7-4ba0-7c89-2560-a2;f .

Enfin, des paramètres peuvent apparaître dans l'URI, par exemple pour indiquer le type de la ressource (ni:///sha256;rJAeWFhQWIoTExwyEQ8w_L5uB0UkfmnCGfNIPy7CdDc?ct=image/png). Une liste de paramètres possibles est enregistrée.

À noter que l'abréviation ni veut officiellement dire Named Information mais que tout geek va évidemment penser aux chevaliers qui disent Ni...

Avant d'utiliser les URI ni:, il est prudent de lire la section 10, consacrée aux questions de sécurité. Ainsi, il ne faut pas oublier que le condensat cryptographique n'est pas une signature. Il sert à vérifier l'intégrité mais, comme n'importe qui peut générer un condensat pour n'importe quel contenu, il ne prouve rien quant à l'authenticité.

La fonction SHA-256 et ses camarades ne sont pas inversibles. D'un condensat, on ne peut pas remonter au contenu. Toutefois, celui-ci n'est pas vraiment secret. Un attaquant peut toujours deviner plus ou moins le contenu (c'est particulièrement facile si le contenu est très structuré, avec peu de variations possibles) et tester les différentes possibilités. Il peut aussi utiliser un moteur de recherche, si des pages existent déjà avec la correspondance entre une ressource et son condensat (pour empêcher cela, il faudrait que les condensats ni: soient salés, ce qui n'est pas le cas).

Et, naturellement, si vous utilisez des condensats tronqués, comme le permet de RFC, vous perdez beaucoup en sécurité.

La notion d'autorité dans les URI ni: peut être trompeuse. Le nom de domaine qui peut apparaître dans un URI ni: n'est pas forcément la source du contenu, puisque n'importe qui peut copier la ressource, et la servir depuis un programme. Il ne faut donc pas attribuer de sémantique à la soi-disant « autorité ».

Si vous voulez regarder un tel système « en vrai », les articles de ce blog sont tous accessibles via un URI ni:. L'identificateur est calculé toutes les nuits et stocké dans une base de données. Un simple petit programme WSGI permet ensuite de récupérer un fichier en fonction de son identificateur. À noter que ce n'est pas la forme HTML qui est utilisée mais le source en XML (la forme en HTML change trop souvent, par exemple si les outils qui la produisent automatiquement à partir du source sont modifiés). Ainsi, l'URI ni:///sha256;6OuucQ1RgugCDVinT2RGmzYYpra0fenH-zw7tilsx9k correspond au source XML de cet article. En indiquant explicitement l'autorité (le serveur qui permet de faire la récupération), c'est l'URI ni://www.bortzmeyer.org/sha256;6OuucQ1RgugCDVinT2RGmzYYpra0fenH-zw7tilsx9k. Et la version sous forme d'URL est http://www.bortzmeyer.org/.well-known/ni/sha256/6OuucQ1RgugCDVinT2RGmzYYpra0fenH-zw7tilsx9k. Si vous préferez un autre article, ni:///sha256;1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp92lueI correspond au source de cet article.

Notez qu'il n'est pas possible de mettre l'URI ni: de l'article que vous êtes en train de lire dans cet article (inclure le condensat change l'article et il faut donc changer le condensat, ce qui change l'article...)

Vous voulez vérifier ? Allons-y.

% wget -O /tmp/x.xml http://www.bortzmeyer.org/.well-known/ni/sha256/1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp92lueI
...
% openssl dgst -sha256 -binary /tmp/x.xml | base64
1etMCVZtd7/cq38MrtnQcoZW/e7J2cslulrFp92lueI=

Et on retrouve bien l'identificateur 1etMCVZtd... (aux transformations URL encoding près).

Si vous voulez faire depuis le shell Unix les calculs nécessaires, voici quelques exemples avec OpenSSL. Pour calculer le NI de Hello World! :

% echo -n 'Hello World!' | openssl dgst -sha256 -binary | base64
f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk=

Il faut ensuite rechercher/remplacer car base64 (ou bien la commande openssl enc -base64) ne sait pas faire de l'URL encoding de Base64. Avec sed :

% echo -n 'Hello World!' | openssl dgst -sha256 -binary | base64 | sed -e 's#/#_#g' -e 's#+#-#g' -e 's#=$##' 
f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk

(Pour la même manipulation, on peut aussi utiliser tr : tr -cd a-zA-Z0-9+/ | tr +/ -_. Comme expliqué par Kim-Minh Kaplan : « Note le tr -cd pour nettoyer le résultat de l’encodage en Base 64. Si avec SHA-256 il n’est pas nécessaire, avec SHA-512, l’encodeur d’OpenSSL introduira un retour à la ligne qu’il faudra aussi supprimer. ») Si on reprend l'exemple plus haut, on peut combiner les deux opérations : on récupère le fichier grâce au condensat et on vérifie que le contenu est bien le contenu attendu. Utilisons ce simple script :


#!/bin/sh

BASE_URL="http://www.bortzmeyer.org/.well-known/ni/sha256/"

if [ -z "$1" ]; then
    echo "Usage: $0 ni" >&2
    exit 1
fi

ni=$1

hash=$(wget -q -O - ${BASE_URL}/${ni} | openssl dgst -sha256 -binary | openssl enc -base64 | \
    sed -e 's#/#_#g' -e 's#+#-#g' -e 's#=$##')

if [ "$hash" != "$ni" ]; then
    echo "Error: hash is $hash instead of $ni" >&2
    exit 1
else
    exit 0
fi

Et voyons :

% get-and-check-ni 1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp92lueI
%

Si on met une valeur fausse :

% get-and-check-ni 1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp922ueI
Error: hash is 47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU instead of 1etMCVZtd7_cq38MrtnQcoZW_e7J2cslulrFp922ueI

Si vous voulez lire de source de mon programme, il est dans les fichiers de mon blog, scripts/blog2db/blog2db.py pour le stockage dans la base de données et wsgis/ni.py pour la récupération.

Il existe une autre implémentation, par certains des auteurs du RFC, en http://sourceforge.net/projects/netinf/.

Si vous voulez d'autres lectures, le RFC 1737. sur les URN, parlait déjà (en 1994) d'utiliser un condensat cryptographque (avec MD5) pour désigner un contenu. En 2003, une proposition plus élaborée, draft-thiemann-hash-urn décrivait un système d'URN avec adressage par le contenu (des choses comme urn:hash::sha1:LBPI666ED2QSWVD3VSO5BG5R54TE22QL). Mais, avec draft-thiemann-hash-urn, il y a un gros manque : pas moyen d'indiquer un (ou plusieurs, comme dans le cas des magnets) serveur pouvant servir le document en question. Avec draft-thiemann-hash-urn, on n'a que des URN (ils ne sont pas « actionnables »). Enfin, si vous voulez une critique des ni: par rapport aux magnets, voyez la discussion sur LinuxFr.


Téléchargez le RFC 6920


L'article seul

RFC 6918: Formally Deprecating Some ICMPv4 Message Types

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : F. Gont (UTN-FRH / SI6 Networks), C. Pignataro (Cisco Systems)
Chemin des normes
Première rédaction de cet article le 18 avril 2013


Allez, encore un peu de nettoyage dans les registres IANA. Le protocole ICMP pour IPv4 a plein de types de messages différents. Beaucoup sont dépassés mais n'avaient pas été officiellement marqués comme tel. Ce RFC range le registre et reclasse quinze types de messages. En revoyant ces types, nous plongeons dans les essais ratés de TCP/IP...

La notion de type de message ICMP est normalisée dans le RFC 792. Les plus connus des types de message ICMPv4 sont le 8 (echo request) et le 0 (echo reply) à cause de leur utilisation dans ping. Mais il existe bien d'autres types, enregistrés à l'IANA et servant à de nombreuses fonctions discrètes, mais indispensables (comme l'indication qu'un paquet n'a pas pu être délivré, type 3). Le registre des types a aussi vu l'arrivée d'un certain nombre de types expérimentaux, qui n'ont guère eu de succès, et notre RFC s'occupe de les trier. (Rappelez-vous qu'IPv6 a un autre registre ICMP, complètement différent.)

Voici donc la liste des types abandonnés :

  • Type 6 Alternate Host Address : un cas amusant car il n'a jamais été documenté et personne ne semble savoir à quoi il devait servir.
  • Types 15 Information Request et 16 Information Reply : décrits dans le RFC 792, ils servaient à la configuration automatique des machines mais sont devenus inutiles depuis qu'on a DHCP.
  • Types 17 Address Mask Request et 18 Address Mask Reply : normalisés dans le RFC 950, ils devaient permettre à une machine de découvrir le masque de sous-réseau (qui, avant cela, avant le VLSM - Variable-Length Subnet Masking, dépendait de la classe d'adresses). Là encore, DHCP les a rendus inutiles.
  • Type 30 Traceroute : décrit par le RFC 1393, il devait servir à découvrir le chemin parcouru par un paquet. Au contraire de la technique utilisée par l'outil traceroute, il nécessitait du logiciel spécial dans tous les routeurs et n'a jamais été sérieusement déployé. Le RFC 6814 l'avait déjà déclaré inutile.
  • Type 31 Datagram Conversion Error : le RFC 1475 l'avait spécifié pour le protocole TP/IX, bien oublié depuis.
  • Type 32 Mobile Host Redirect : un premier essai (raté) d'un protocole permettant la mobilité des machines de réseau en réseau.
  • Types 33 IPv6 Where-Are-You et 34 IPv6 I-Am-Here : un essai, jamais déployé, pour permettre aux machines IPv4 de découvrir des voisins parlant IPv6.
  • Types 35 Mobile Registration Request et 36 Mobile Registration Reply : autre essai non suivi d'effet lié à la mobilité et à IPv6. (Il était documenté dans l'Internet-Draft draft-simpson-ipv6-mobility qui n'est jamais devenu un RFC.)
  • Types 37 Domain Name Request et 38 Domain Name Reply : normalisés dans le RFC 1788, l'idée était de permettre une traduction d'adresse IP en nom n'utilisant pas le DNS. On envoyait un paquet ICMP à une machine et elle répondait avec son nom. En pratique, cela n'a jamais été utilisé.
  • Type 39 SKIP : prévu pour un protocole qui n'a jamais été terminé.

Tous ces types sont désormais marqués Deprecated dans le registre IANA.


Téléchargez le RFC 6918


L'article seul

RFC 6916: Algorithm Agility Procedure for RPKI

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : R. Gagliano (Cisco Systems), S. Kent (BBN Technologies), S. Turner (IECA)
Réalisé dans le cadre du groupe de travail IETF sidr
Première rédaction de cet article le 11 avril 2013


La grosse infrastructure de sécurisation du routage RPKI+ROA est en train de se mettre en place, les RFC sont sortis, mais l'IETF ne s'arrête pas là. Ce document décrit la façon de changer les algorithmes de cryptographie utilisés par la RPKI lorsque les progrès de la cryptanalyse l'exigeront.

Disons-le tout de suite, cela va être un énorme travail. La RPKI n'a pas de centre, les décisions dépendent d'un grand nombre d'acteurs non coordonnés, des AC qui émettent les certificats aux RP (Relying Parties, les validateurs qui vérifient les ROA - Route Origin Authorizations). Le RFC ne sème pas d'illusion et affirme qu'un éventuel changement d'algorithmes dans la RPKI prendra plusieurs années.

Il y avait en théorie plusieurs stratégies possibles, du bas vers le haut (les acteurs situés le plus bas dans la hiérarchie migrent les premiers) ou celle finalement choisie, après de longues discussions dans le groupe de travail SIDR, du haut vers le bas (les acteurs les plus haut placés commencent).

À noter qu'il s'agit bien de changer d'algorithmes. Remplacer les clés (key rollover) est prévu et normal dans le fonctionnement de la RPKI (RFC 6489). Mais les algorithmes ne sont pas éternels. Ceux normalisés actuellement dans le RFC 6485 (RSA et SHA-256) ne résisteront pas toujours à la cryptanalyse et devront laisser un jour la place à d'autres (fondés sur les courbes elliptiques ?).

Comme le processus sera long, il devra commencer par une mise à jour de ce RFC 6485, documentant les nouveaux algorithmes et par la publication d'un plan de migration, avec chronologie. Puis la procédure décrite en section 4 sera appliquée, dans l'ordre chronologique : les AC commencent à émettre des certificats avec le nouvel algorithme, puis les RP (les validateurs) commencent à pouvoir vérifier le nouvel algorithme, puis les AC arrêtent d'utiliser l'ancien algorithme (période nommée Twilight dans le RFC, mais rien à voir avec Stephenie Meyer), puis on peut déclarer l'ancien algorithme mort. Le passage à chaque étape nécessite que tous les acteurs impliqués aient migré, ce qui explique le délai de plusieurs années envisagé (aucune procédure n'est envisagée pour le cas, catastrophique, où de brusques percées de la cryptanalyse obligeraient à un remplacement d'urgence). Le RFC est plein de phrases comme « If a substantial number of RPs are unable to process product sets signed with Suite B [le nouvel algorithme], the algorithm transition timeline document MUST be reissued, pushing back the date for this and later milestones [...] », qui donnent une idée des problèmes qui vont surgir à cause de cette règle « pas de passage sans unanimité ».

Il y aura donc une (longue) période de coexistence entre les deux algorithmes. La section 6 décrit ce que devra être le comportement des validateurs pendant cette période, notamment si les deux algorithmes donnent des résultats opposés (l'un valide et l'autre pas ; l'expérience avec des techniques cryptographiques comme DNSSEC montre que ce genre de choses arrive).

Et n'oubliez pas que ce beau plan n'a jamais été testé. Rendez-vous dans sept ou quinze ans pour le premier changement d'algorithme de la RPKI...


Téléchargez le RFC 6916


L'article seul

RFC 6914: SIMPLE made Simple: An Overview of the IETF Specifications for Instant Messaging and Presence using the Session Initiation Protocol (SIP)

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : J. Rosenberg (jdrosen.net)
Pour information
Réalisé dans le cadre du groupe de travail IETF simple
Première rédaction de cet article le 22 avril 2013


Le monde de la messagerie instantanée est marqué par l'absence d'une norme unique et largement reconnue (au contraire de celui du courrier électronique, où SMTP et ses copains ont remplacé tous les concurrents). La plupart des protocoles courants de messagerie instantanée sont fermés et spécifiques à une seule entreprise. Et, même chez les standards ouverts, il y a deux normes, la plus connue, autour de XMPP, et une seconde, issue de la même organisation (l'IETF), autour de SIP. Car SIP ne sert pas qu'à la téléphonie sur IP. C'est un mécanisme de signalisation très général et il peut être utilisé pour la messagerie instantanée. En fait, de nombreux RFC, depuis des années, normalisent l'utilisation de SIP dans ce cas. Tellement nombreux, ces RFC, qu'il faut faire un méta-RFC pour servir de guide. C'est le rôle de ce RFC 6914 : la liste commentée des RFC qui, tous ensemble, décrivent SIMPLE, la messagerie instantanée utilisant SIP.

SIP lui-même est décrit dans le RFC 3261. Ce nouveau RFC 6914 fait la liste des RFC qui décrivent l'utilisation de SIP pour deux services :

  • La présence, le fait de signaler sa disponibilité pour la communication,
  • La messagerie instantanée proprement dite.

Accrochez-vous, la liste est longue et SIMPLE ne mérite guère son nom. À noter que le groupe de travail IETF SIMPLE a été fermé le 26 février 2013, son travail étant considéré comme achevé.

Commençons par la présence (section 2). Elle se décompose en un service de base, permettant de publier des notifications (« je suis disponible ») et de s'y abonner (« qui est réveillé ? »), et une galaxie de services auxiliaires enrichissant tel ou tel aspect du service de base. Le seul service de base compte cinq RFC :

  • RFC 6665, qui définit les méthodes SUBSCRIBE et NOTIFY, au cœur du service de présence. Il est bâti sur le RFC 3856.
  • RFC 4662, qui étend ce mécanisme à des listes de ressources SIP, notamment les buddy lists, liste de correspondants. Une variante figure dans le RFC 5367.
  • RFC 3903, qui normalise le mécanisme de publication des informations.

Ensuite, comment exprime-t-on les informations publiées et lues ? Le format de base (fondé sur XML) est dans le RFC 3863. Un modèle de données plus général est dans le RFC 4479, avec, dans le RFC 4480, plein d'extensions au format du RFC 3863. Autres extensions, celles du RFC 4481, qui ajoute la gestion du temps (évenements dans le passé et le futur, alors que le RFC 3863 se limitait au présent), et celles du RFC 4482 qui permettent de diffuser des informations sur un correspondant, par exemple une image le représentant.

Enfin, le RFC 5196 permettait d'indiquer, en sus de la présence et des données ci-dessus, les capacités du logiciel SIP qu'on utilise, par exemple pour prévenir ses correspondants qu'on accepte la vidéo.

Tout service de présence soulève évidemment des questions délicates de protection de la vie privée. Je ne souhaite pas forcément que la Terre entière soit au courant de mes déplacements et activités. La section 2.3 décrit les RFC qui s'attaquent au problème de la vie privée dans SIMPLE. Le RFC 4745 définit un format (basé sur XML) pour exprimer des préférences sur la vie privée (du genre « ne jamais diffuser cette information »). Le RFC 5025 utilise ensuite ce format pour décrire les souhaits spécifiques au service de présence. Les RFC 3857 et RFC 3858 décrivent un système d'autorisation préalable où l'utilisateur peut être prévenu si quelqu'un demande s'il est présent.

Un service SIMPLE nécessite un certain nombre de données, par exemple les carnets d'adresse. Comment les enregistre t-on ? Cela se fait avec XCAP (RFC 4825), un protocole qui permet d'envoyer des données stockées en XML. Il en existe des optimisations comme le RFC 5874 qui permet de n'envoyer que les différences avec les données précédentes, pour économiser des ressources réseau. Il se sert pour cela du format XML Diff du RFC 5261. On peut être prévenu de l'apparition de différences avec les mécanismes du RFC 5875. Les formats des données sont ensuite décrites par des documents comme le RFC 4826 (format des carnets d'adresses).

Un des gros intérêts des techniques IETF de messagerie instantanée, comme SIMPLE ou XMPP est qu'elles reposent sur une fédération. Il n'y a pas un service centralisé à qui faire confiance (comme c'est le cas avec les services des silos fermés comme MSN). Chacun peut installer son serveur et les différents serveurs peuvent communiquer entre eux, le DNS leur servant à se trouver. Le RFC 5344 approfondit les mécanismes utilisés pour la fédération.

La présence peut être un service très coûteux. Imaginez que vous receviez des notifications de présence pour une centaine de personnes, et que leurs états changent toutes les minutes (par exemple suite à des connexions/déconnexions). Au-dessus d'une liaison sans-fil, cela peut faire mal au réseau. Le RFC 4460 fournit donc des mécanismes de filtrage, pour ne pas tout recevoir. Les règles sont écrites dans le format du RFC 4461. Le RFC 5262 permet de ne pas recevoir la totalité de la notification mais uniquement la partie qui a changé (là encore, avec le format XML Diff du RFC 5261).

Maintenant qu'on en a terminé avec la présence (un service bien plus compliqué qu'il n'avait l'air au premier abord), revenons à la messagerie instantanée proprement dite (section 3). Dans SIMPLE, il y a deux modes de fonctionnement pour celle-ci. En mode non connecté (page mode, analogue au SMS), une requête SIP MESSAGE est envoyée au destinataire, contenant le message. En mode connecté (session mode), une INVITE SIP est envoyée au destinataire et, une fois la session établie, on envoie les textes de la conversation, comme on enverrait de l'audio avec de la téléphonie SIP.

Le RFC 3428 décrit le mode non connecté et la méthode MESSAGE, le « texto » de SIP. Le RFC 5365 l'étend au cas où il y a plusieurs destinataires.

Le mode connecté utilise des méthodes SIP classiques et sa description est uniquement celle des types de données envoyées, notamment RFC 4975 pour le type « message texte » et RFC 3862 pour les métadonnées.

Une extension très utile aux services de messagerie instantanée est la pièce collective (chat room, ou MUC - pour Multi-User Channel en XMPP). SIMPLE réutilise pour cela les mécanismes de conférence de SIP, normalisés dans les RFC 4353 et RFC 5239. Ensemble, ils indiquent comment on rejoint une conférence, comment on la quitte, etc.

Enfin (rassurez-vous, on arrive au bout), deux fonctions sympa : l'indication de composition dans le RFC 3994 (permettant d'indiquer que le correspondant est en train de taper un texte, il faut patienter), et l'accusé de réception dans le RFC 5438.

Voilà, vous savez désormais tout ce qu'il faut lire si vous voulez faire de la messagerie instantanée avec SIP...


Téléchargez le RFC 6914


L'article seul

RFC 6912: Principles for Unicode Code Point Inclusion in Labels in the DNS

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : A. Sullivan (Dyn, Inc), D. Thaler (Microsoft), J. Klensin, O. Kolkman (NLnet Labs)
Pour information
Première rédaction de cet article le 16 avril 2013


Ce RFC de l'IAB expose les principes que, selon l'IAB, devraient suivre les registres de noms de domaine lorsqu'ils décident quels caractères Unicode sont autorisés ou pas, pour l'enregistrement de noms de domaine internationalisés.

Notons tout de suite que les principes exposés dans ce RFC ne sont guère argumentés (les sections 6, 7 et 8, normalement consacrées à cette tâche, sont très pauvres). Dès l'introduction, le RFC dit qu'il ne faut pas autoriser tous les caractères mais ne dit pas pourquoi, ou quels dangers mystérieux menacent ceux qui oseraient passer outre. Mais, une fois qu'on a décidé de ne pas permettre tous les caractères Unicode (enfin, tous ceux qui sont légaux selon le RFC 5892), il reste le problème du choix. Il n'existe pas d'algorithme pour cela (le monde Unicode est bien trop complexe, reflétant la complexité des écritures du monde et nos connaissances insuffisantes) et ce RFC, plutôt que de donner un tel algorithme, pose des principes qui devraient guider ceux et celles qui feront le choix.

La section 1 donne quelques objectifs (sans que la suite du RFC n'indique le rapport entre les principes et ces objectifs) : limiter les possibilités de confusion entre deux noms (par exemple google.com et goog1e.com, regardez bien le second), éviter qu'une adresse IP soit prise pour un nom de domaine comportant des éléments numériques (un faux problème typique, cf. RFC 1123, section 2.1), et favoriser l'accessibilité (cf. WCAG). Le RFC introduit une notion importante, celle de zone publique. Une zone du DNS est un ensemble de sous-domaines contigus et gérés par la même organisation. Certaines sont privées, au sens où une seule organisation les utilisent (par exemple la zone univ-paris-diderot.fr n'est utilisée que par l'université Denis Diderot). D'autres sont publiques au sens où le registre qui la gère accepte des enregistrements de diverses organisations. La plupart des TLD sont des zones publiques (par exemple .fr, .org ou .pm), ainsi que la racine. En effet, le RFC estime qu'il faut des règles particulières pour ces zones publiques (cf. section 4).

L'IAB s'est déjà exprimée sur cette question du choix des caractères autorisés pour les IDN. Notons que personne ne s'est posé la question pour les noms de domaines en ASCII alors que, comme le montre l'exemple goog1e.com plus haut, ils posent exactement les mêmes « problèmes ». Mais l'idée même de permettre à chacun, et pas seulement aux anglophones, d'écrire les noms de domaine avec leur écriture n'est toujours pas complètement acceptée. À part quelques ultra-réactionnaires, plus personne n'ose dire ouvertement qu'il est contre mais l'anti-IDNisme s'exprime plutôt aujourd'hui par un discours de peur, parlant de dangers (jamais clairement spécifiés) et laissant entendre qu'il faudrait contrôler sévèrement les IDN. Les déclarations précédentes de l'IAB peuvent être trouvées dans « IAB Statement: "The interpretation of rules in the ICANN gTLD Applicant Guidebook" » et « Response to ICANN questions concerning 'The interpretation of rules in the ICANN gTLD Applicant Guidebook' ». Dans ces textes, l'IAB plaidait pour un extrême conservatisme dans l'autorisation de caractères, en restreignant encore les règles techniques des RFC 5890 et RFC 5892, par exemple en n'autorisant que les caractères de la catégorie Unicode « Lettres ».

Dans ce RFC, l'IAB veut aller plus loin en interdisant également des caractères de cette catégorie. Le RFC prend l'exemple de ʼ (U+02BC, une apostrophe), qui a un rendu quasiment toujours identique à ’ (U+2019) alors qu'il est dans la catégorie Lettre (U+2019 étant dans la catégorie Ponctuation, mystères des catégories Unicode). Sans compter la traditionnelle ' (U+0027). Bien que, légalement, U+02BC soit un caractère autorisé dans un IDN, le RFC suggère que ce n'est sans doute pas une bonne idée de l'autoriser.

S'il y a des caractères dans la catégorie Lettres qui ne devraient sans doute pas être autorisés (cas ci-dessus), l'inverse existe aussi : des caractères situés dans d'autres catégories sont néanmoins indispensables dans certaines langues, notamment indiennes. Cela illustre le point mentionné plus haut : il n'y a pas d'algorithme pour établir automatiquement la liste des caractères autorisés, il va falloir y aller à la main. La section 4.2.4 du RFC 5891 mentionnait ce travail comme une reponsabilité indispensable du registre, et ce RFC 6912 ajoute que ce travail doit être fait à l'avance, pas décidé lorsqu'une demande d'enregistrement de nom se présente. Une telle décision lorsqu'une demande survient offrirait trop de possibilités à l'arbitraire. Non, il faut des règles pré-établies, et publiées. (À titre d'exemple, vous pouvez regarder les règles d'enregistrement des IDN dans .fr.)

Le RFC estime que ces règles doivent être d'autant plus sévères (doivent autoriser moins de caractères) que l'on monte dans la hiérarchie des zones et que la zone racine doit donc avoir des règles particulièrement conservatrices, puisqu'elle concerne tous les utilisateurs de l'Internet.

Donc, pas d'algorithme (s'il était possible, il aurait sans doute déjà été développé) mais des principes. Quels sont-ils ? La section 3 en fournit une liste. D'abord, le principe de longévité : comme un caractère peut changer de catégorie, invalidant son usage (un exemple figure dans le RFC 6452), il est prudent de n'autoriser que des caractères qui sont stables depuis plusieurs versions d'Unicode.

Ensuite, le principe de moindre étonnement : un utilisateur normal ne devrait pas être trop surpris de la présence ou de l'absence de tel caractère. Notez que cela dépend du contexte : un utilisateur d'une écriture donnée ne sera pas surpris par les mêmes choses qu'un utilisateur d'une autre écriture.

Ces principes étaient valables pour toutes les zones. Mais les zones publiques ont des contraintes supplémentaires (section 4). Il y a le principe conservateur (dans le doute, rejeter le caractère), le principe d'inclusion (les caractères sont interdits par défaut et on inclut ensuite explicitement ceux qu'on estime « sûrs », terme que le RFC ne définit pas, et qui vient du FUD anti-Unicode), le principe de simplicité (un « honnête homme », avec des compétences modérées en DNS et en Unicode, doit pouvoir comprendre les raisons qui ont amené au choix d'acceptation ou de rejet, sans avoir eu besoin d'être présent aux quinze dernières réunions de l'IETF)...

Ce principe de simplicité dépend là encore du contexte. Si l'honnête homme cité plus haut ne connait aucune langue indienne, il ne comprendra sans doute pas les raisons qui ont mené à l'ajout de caractères non-lettres, indispensables pour certaines de ces langues. La racine servant à tous, ses règles devraient être ultra-simples et ne pas demander de compétences linguistiques particulières. Un ccTLD d'un pays donné peut se permettre des règles plus complexes pour des étrangers, mais qui sembleront simples à ceux qui connaissent les langues locales.

Pour les zones publiques, il y a aussi le principe de prédictabilité (les règles doivent donner un résultat identique, dès qu'on les applique sérieusement) et de stabilité (la liste des caractères autorisés ne devrait changer que rarement).

La racine, pour les raisons expliquées plus haut, a droit à une section spéciale (section 5). Le RFC demande qu'elle soit strictement peuplée de lettres, en s'appuyant sur une note de la section 2.1 du RFC 1123 qui dit que c'est le cas (c'était vrai lorsque le RFC 1123 a été publié, mais il n'y a aucun consensus à l'IETF sur l'interprétation de cette note : exprime t-elle une constatation ou une prescription ?) L'idée derrière cette restriction (RFC 4690) est que les noms de domaines n'ont pas vocation à permettre d'écrire tous les mots, encore moins des phrases correctes et complètes, mais uniquement celle de permettre la création de mnémoniques pratiques.

Ce RFC exprimant des opinions très contestables, la discussion avait été animée (voir par exemple les commentaires que j'avais fait sur une précédente version, violemment anti-Unicode).


Téléchargez le RFC 6912


L'article seul

RFC 6911: RADIUS attributes for IPv6 Access Networks

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : W. Dec (Cisco Systems), B. Sarikaya (Huawei), G. Zorn (Network Zen), D. Miles (Google), B. Lourdelet (Juniper Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 30 avril 2013


Le protocole RADIUS joue un rôle important dans l'accès à l'Internet : c'est le principal mécanisme utilisé pour faire communiquer la machine qui contrôle l'accès physique avec la machine qui contient la base des utilisateurs et les informations sur les autorisations, les configurations spécifiques... RADIUS avait bien sûr déjà la capacité de transporter des informations IPv6 mais ce nouveau RFC en ajoute quelques unes.

Une petite révision sur RADIUS d'abord (vous pouvez suivre sur la figure 1 du RFC). Lorsqu'un utilisateur accède à l'Internet, plusieurs machines sont utilisées. Il y a d'abord la machine terminale de l'utilisateur, ou bien un petit routeur, nommé RG (Residential Gateway). L'un des deux porte les informations d'authentification (identificateur et mot de passe). Cette machine terminale ou bien se petit routeur se connecte au réseau et parle à un AN (Access Node : dans le cas de l'ADSL, c'est le DSLAM qui sert d'AN, dans le cas d'un accès commuté, c'est le serveur de modems). L'authentification pourrait être faite par l'AN. Mais l'utilisateur ne parle pas toujours au même AN (par exemple s'il est mobile) et puis, on gagne en souplesse en découplant les fonctions d'accès et d'authentification. On a donc un serveur qui stocke les informations d'authentification et les paramètres des clients, le AAA (Authentication, Authorization and Accounting). Entre l'AN et le AAA se trouve souvent un NAS (Network Access Server), un routeur IP (dans certains cas, AN et NAS sont confondus, par exemple pour la plupart des serveurs PPP). Le NAS est client RADIUS et utilise ce protocole pour demander à l'AAA « j'autorise ce client ? » L'AAA, serveur RADIUS, répond oui ou non et ajoute une série d'attributs, qui sont les paramètres de la session, par exemple l'adresse IP à utiliser. Notez que RADIUS ne sert qu'entre le NAS et le AAA. Entre le RG et le NAS, on peut utiliser plusieurs autres protocoles, comme PPP ou, plus courant aujourd'hui, DHCP (RFC 3315).

RADIUS avait déjà des attributs pour IPv6 : le RFC 3162 avait Framed-IPv6-Prefix pour indiquer le préfixe IPv6 à utiliser et Framed-Interface-Id qui, combiné avec la valeur précédente, permettait de fabriquer une adresse IP6 pour l'utilisateur (cette séparation puis recombinaison était plus adaptée à PPP qu'à DHCP, qui donne des adresses entières). Et le RFC 4818 avait Delegated-IPv6-Prefix qui permettait de transmettre un préfixe à déléguer à un routeur par l'option de délégation DHCP du RFC 3633.

Quels sont ces attributs qui manquaient dans les RFC 3162 et RFC 4818 ? La section 3 en fournit la liste, et ils sont désormais notés dans le registre IANA (cf. section 6). Le premier est Framed-IPv6-Address qui permet d'attribuer une adresse IPv6 complète au visiteur (a priori via DHCP). Elle peut apparaître dans les réponses RADIUS, mais aussi dans les questions, pour exprimer un souhait (que le serveur RADIUS peut ignorer). Framed-IPv6-Address peut être envoyé dans une réponse RADIUS en même temps que les anciens Framed-IPv6-Prefix and Framed-Interface-Id (par exemple si le réseau local, derrière le RG, utilise à la fois DHCP et l'auto-configuration sans état - SLAAC).

Le second attribut, DNS-Server-IPv6-Address, indique l'adresse IP d'un résolveur DNS. (Un seul résolveur ; mais la réponse RADIUS peut contenir plusieurs attributs DNS-Server-IPv6-Address, afin de transmettre les adresses de plusieurs résolveurs.) Ces serveurs DNS peuvent ensuite être indiqués aux machines du réseau local par les Router Advertisement du RFC 8106 ou bien en DHCP (RFC 3646).

Ensuite, Route-IPv6-Information permet de spécifier une route statique. L'attribut existant, Framed-IPv6-Route (RFC 3162), ne suffit pas car elle est pour l'usage du NAS, il ne la transmet pas au RG. Au contraire, le nouvel attribut Route-IPv6-Information est prévu pour être redistribué. Le NAS pourra transmettre cette information au RG avec les annonces Router Advertisement du RFC 4191 ou bien une méthode équivalente. Les autres données nécessaires dans l'option Route Information de l'annonce (par exemple la préférence ou la durée de vie), devront être connues du NAS par un autre moyen (ce point a été le plus chaud lors des discussions dans le groupe de travail).

Enfin, dernier attribut, Delegated-IPv6-Prefix-Pool indique le nom d'un pool d'adresses IPv6 à utiliser par le NAS. Là encore, c'est un attribute RADIUS conçu pour être relayé avec DHCP mais qui peut coexister avec Framed-IPv6-Pool, plutôt fait pour les Router Advertisement.


Téléchargez le RFC 6911


L'article seul

RFC 6908: Deployment Considerations for Dual-Stack Lite

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : Y. Lee (Comcast), R. Maglione (Telecom Italia), C. Williams (MCSR Labs), C. Jacquenet (France Telecom), M. Boucadair (France Telecom)
Pour information
Réalisé dans le cadre du groupe de travail IETF softwire
Première rédaction de cet article le 26 mars 2013


DS-Lite est une des nombreuses techniques de transition / co-existence IPv4 / IPv6. Elle est normalisée dans le RFC 6333. Ce nouveau RFC se penche plutôt sur des problèmes opérationnels : comment déployer DS-Lite, quels pièges éviter, etc.

DS-Lite (Dual-Stack Lite) est conçu pour un FAI récent, qui vient d'arriver et n'a donc pas pu obtenir d'adresses IPv4, toutes épuisées. Ce FAI a donc dû numéroter son réseau en IPv6, et comme ses clients ont encore de l'IPv4 à la maison, et comme ils souhaitent accéder à des machines Internet qui sont encore uniquement en IPv4, le FAI en question va donc devoir 1) NATer les adresses de ses clients (RFC 3022) vers le monde extérieur 2) tunneler leurs paquets depuis leur réseau local IPv4 (RFC 2463) jusqu'au CGN, en passant par le réseau purement IPv6 du FAI. C'est là que DS-Lite intervient (RFC 6333).

Apparemment, il n'y a eu qu'un seul déploiement effectif de DS-Lite chez un vrai FAI (le RFC ne dit pas lequel) et ce RFC 6908 est largement tiré de cette expérience réelle. Il est donc une lecture intéressante pour les opérateurs qui aiment le concret.

Ce RFC est en deux parties : les questions liées à l'AFTR et celles liées au B4. Vous ne savez pas ce qu'est un AFTR ou un B4 ? Vous n'avez pas envie de lire le RFC 6333 qui explique cela ? Alors, en deux mots, l'AFTR (Address Family Transition Router) est le gros routeur NAT (le CGN) situé entre le FAI et l'Internet. Et le B4 (Basic Bridging Broadband element) est chez le client, typiquement dans sa box et représente le point d'entrée du tunnel, du « lien virtuel » (soft wire). Prononcez les sigles à voix haute : le B4 est avant le tunnel (before) et l'AFTR après (after).

Donc, bien qu'il soit « après », notre RFC commence par l'AFTR (section 2). D'abord, comme DS-Lite utilise un tunnel, il va y avoir des problèmes dus à la MTU inférieure. Le RFC recommande donc d'essayer de faire un lien entre le B4 et l'AFTR ayant une MTU d'au moins 1540 octets pour que, après avoir retiré les 40 octets de l'encapsulation dans le tunnel, on ait les 1500 octets d'Ethernet. Si ce n'est pas possible, alors le B4 et l'AFTR vont devoir gérer la fragmentation. Comme le réassemblage des paquets est une opération coûteuse en ressources (il faut garder les fragments en mémoire tant que tout n'est pas arrivé), la tâche va être particulièrement lourde pour l'AFTR (des milliers de tunnels peuvent se terminer sur un seul AFTR). Il faut les dimensionner largement ! (C'est un problème général des CGN.)

Ensuite, il faut penser à la journalisation. Le principe de DS-Lite est que tous les clients du FAI partageront la poignée d'adresses IPv4 publiques que NATeront les AFTR. Si un client fait quelque chose de mal (par exemple accéder à un site Web qui déplait au gouvernement), il faut pouvoir l'identifier. Un observateur situé à l'extérieur a vu une adresses IPv4 du FAI et des milliers de clients pouvaient être derrière. L'AFTR doit donc noter au moins l'adresse IPv6 du B4 (elle est spécifique à chaque client) et le port source utilisé après le NAT (en espérant que l'observateur extérieur ne notera pas que l'adresse IPv4 source mais aussi le port, cf. RFC 6302).

Les adresses IP partagées sont une plaie du NAT, ce n'est pas nouveau (RFC 6269). Par exemple, si une adresse IPv4 est mise sur une liste noire suite à son comportement, ce seront des centaines ou des milliers de B4 qui seront privés de connectivité IPv4. Si le destinataire ne tient pas compte du RFC 6302 et bloque sur la seule base de l'adresse IPv4, le support téléphonique du FAI qui a déployé DS-Lite va exploser. (Un travail est en cours à l'IETF pour aider à l'identification de l'utilisateur derrière un CGN. Mais il n'est pas terminé et, de toute façon ne sera pas forcément déployé. L'obstination de tant d'acteurs à rester en IPv4 va se payer cher.)

Un problème analogue se posera si le FAI veut faire de la comptabilité des octets échangés, et s'il ne met pas cette fonction dans le CPE. Le tunnel et le NAT rendront cette analyse plus compliquée (section 2.6). À noter que le RFC 6519 normalise des extensions à Radius pour les problèmes particuliers de DS-Lite.

Mais tout ceci n'est rien par rapport aux problèmes de fiabilité que posent les AFTR. L'Internet normal est très robuste car les équipements intermédiaires (les routeurs) n'ont pas d'état : s'ils redémarrent, rien n'est perdu. S'ils s'arrêtent de fonctionner, on en utilise d'autres. Le NAT met fin à tout cela : le routeur NAT a un état en mémoire, la table des correspondances {adresse interne, adresse externe} et, s'il redémarre, tout est fichu. C'est bien pire pour un CGN : s'il redémarre, ce sont des centaines ou des milliers d'utilisateurs qui perdent leurs connexions en cours. La fiabilité des AFTR est donc cruciale (cf. annexe A.3 du RFC 6333). Notre RFC propose que des AFTR de remplacement soient installés pour être prêts à prendre le relais. Ils peuvent fonctionner en « remplacement à chaud » (Hot Standby), se synchronisant en permanence avec l'AFTR primaire, prêts à le remplacer « sans couture » puisqu'ils ont le même état, ou bien en « remplacement à froid » (Cold Standby), sans synchronisation. Dans ce second cas, l'AFTR de secours fait qu'un AFTR en panne est vite remplacé, mais il n'y a pas de miracle : les clients doivent recommencer toutes leurs sessions. Vue la complexité qu'il y a à mettre en œuvre correctement la synchronisation des états, notre RFC recommande le remplacement à froid, et tant pis si c'est moins agréable pour les utilisateurs.

Et les performances ? Combien faut-il d'AFTR pour servir les utilisateurs ? La section 2.8 discute de ce point et du meilleur placement de ces équipements.

Comme avec tout CGN, DS-Lite, en centralisant les adresses IPv4, limite les possibilités de géo-localisation. Le B4 (donc la maison de l'utilisateur) et l'AFTR peuvent parfaitement être dans des villes différentes (RFC 6269, section 7). Les applications ne devraient donc pas se fier à la géo-localisation mais demander à l'utilisateur où il se trouve, par exemple avec le protocole HELD du RFC 5985 ou en suivant l'architecture du RFC 6280. Le RFC conseille, curieusement, de mettre les AFTR le plus près possible des utilisateurs, pour limiter ce problème (alors que les AFTR ont besoin d'une connectivité IPv4, et que le réseau du FAI ne la fournit pas forcément, sinon il n'aurait pas besoin de DS-Lite).

Autre problème douloureux avec les CGN (dont DS-Lite), les connexions entrantes. Contrairement au NAT traditionnel, celui fait par la box à la maison, plus question de configurer sa box via une interface Web pour rediriger certains ports. Et plus moyen de se servir d'UPnP. Les éventuelles redirections doivent être sur l'AFTR, un engin largement partagé. Donc, pas question de demander une redirection du port 80...

Pour « programmer » l'AFTR, lui demander d'ouvrir certains ports en entrée, notre RFC recommande d'installer un serveur PCP (Port Control Protocol, RFC 6887) sur les AFTR. Il n'est pas évident que cela soit une solution satisfaisante. D'une part, il existe encore très peu de clients PCP (par rapport aux clients UPnP). D'autre part, l'AFTR étant partagé entre plusieurs clients ne se connaissant pas, rien ne dit que la coexistence se passera bien et que les opérateurs accepteront d'ouvrir PCP à leurs clients.

Voilà, c'étaient les points essentiels pour les AFTR, lisez la section 2 du RFC si vous voulez la liste complète. Et les B4 ? Ils font l'objet de la section 3. D'abord, le problème du DNS. Le B4 est censé s'annoncer comme résolveur DNS et relayer les requêtes DNS au dessus d'IPv6 vers l'extérieur. Ce faisant, il est important qu'il suive les recommendations pour les relais DNS du RFC 5625 (en pratique, la grande majorité des boxes et des petits routeurs bas de gamme violent affreusement ces recommendations). C'est notamment nécessaire si on veut que DNSSEC fonctionne.

Si un client sur un réseau local IPv4 fait des requêtes DNS en IPv4 vers une adresse qui n'est pas celle du B4, ces requêtes seront tunnelisées et NATées comme n'importe quel trafic IPv4. Compte-tenu du fait que, du point de vue du NAT, chaque requête DNS est une session à elle seule, l'augmentation de la charge sur les AFTR sera sensible. Ce n'est donc pas conseillé.

Le B4 étant le début du réseau de l'opérateur, et beaucoup de choses dépendant de sa configuration et de son bon fonctionnement, il est important que l'opérateur puisse y accéder à distance, et au dessus d'IPv6, pas au dessus du lien virtuel (qui a davantage de chances d'avoir des problèmes).

À propos d'administration et de supervision du réseau, il est important que les AFTR répondent aux paquets utilisés pour ping et traceroute, afin que le B4 puisse tester que la connectivité IPv4 au dessus du tunnel marche bien. Des adresses IPv4 spéciales ont été réservées pour cela (rappelez-vous que, si vous déployez DS-Lite, c'est que vous n'avez pas assez d'adresses IPv4 publiques), 192.0.0.0/29. Les AFTR sont censés tous répondre aux paquets envoyés à 192.0.0.2.


Téléchargez le RFC 6908


L'article seul

RFC 6906: The 'profile' Link Relation Type

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : E. Wilde (EMC Corporation)
Pour information
Première rédaction de cet article le 21 mars 2013


Les liens sont à la base du Web, tout le monde le sait, mais on sait moins que les liens sont typés, marqués avec un type qui indique leur sémantique. Ainsi, le type profile, décrit dans ce RFC, indique que le lien pointe vers un profil, une spécification du format utilisé qui restreint les possibilités d'un format donné.

Ce concept de profil est très fréquent en informatique (mais pas vraiment défini de manière rigoureuse). Lorsqu'on veut réutiliser un format mais qu'on n'a besoin que d'une petite partie de ses possibilités, on définit un profil qui consiste en gros à dire « dans tel format, n'utiliser que ci et ça ». Un profil peut être un peu plus compliqué qu'une simple restriction, par exemple il peut spécifier quelques extensions obligatoires. Le point important est qu'un programme qui sait traiter le format doit savoir traiter un fichier utilisant un profil de ce format. Ainsi, un podcast est un flux de syndication (et doit donc pouvoir être traité par tout programme gérant ces flux) mais avec des éléments spécifiques, qui peuvent être compris par un lecteur de podcasts, comme Apple iTunes.

Le format lui-même est indiqué par d'autres méthodes. Par exemple, en HTTP, le format peut être indiqué par le type de media (ou type MIME), comme text/html. On peut aussi indiquer le format dans le document lui-même : en HTML, on va utiliser la déclaration DOCTYPE pour cela. Et pour indiquer le profil ? Eh bien on va se servir d'un lien. (HTML 4 avait un attribut profile dans l'élément <head> mais il n'est pas sûr que HTML 5 le garde et, de toute façon, la solution de ce RFC est plus générale.)

Ces liens suivent le cadre général normalisé dans le RFC 8288. Ce cadre comprend notamment un registre des types de liens (dans lequel se trouve désormais profile), et plusieurs syntaxes pour mettre les liens dans le document (cas du <link> de HTML) ou dans le protocole d'accès (cas de l'en-tête Link: de HTTP).

La distinction entre profils et formats est parfois subtile. Ainsi, XHTML n'est pas considéré comme un profil de XML parce que, pour les usages de XHTML, afficher du XML brut, sans les traitements spécifiques de XHTML, n'aurait guère d'intérêt. En revanche, hCard est bien un profil de XHTML, car, si un logiciel ne comprend pas hCard, le traiter et l'afficher comme du bête XHTML est utile.

Les profils sont identifiés par un URI (comme les espaces de noms de XML). Ces URI ne sont pas forcément déréférençables (on ne peut pas toujours les donner à un navigateur Web), ce sont juste des identificateurs et le logiciel doit donc les traiter comme tels, pas les présenter systématiquement comme des liens cliquables. Le RFC conseille juste (ce n'est pas une obligation) de les rendre déréférençables, et de mettre une jolie documentation du profil au bout de l'URI. Ainsi, si je crée un profil de HTML nommé http://www.example.org/profiles/myprofile, il est recommandé (juste recommandé) qu'une page Web décrivant myprofile se trouve effectivement à cette adresse.

Une curiosité : un document peut correspondre à plusieurs profils et le lien de type profile peut donc pointer vers une liste.

La section 5 du RFC donne quelques exemples concrets. D'abord, hCard, déjà cité. Il permet de mettre des vCard (RFC 6350) dans HTML. Son URI est http://microformats.org/profile/hcard, on peut donc l'indiquer par un lien comme <link rel="profile" href="http://microformats.org/profile/hcard" /> et on trouve plein d'exemples dans la documentation

Autre exemple, Dublin Core, identifié par le profil http://dublincore.org/documents/2008/08/04/dc-html/ qui permet de mettre des métadonnées Dublin Core dans une page en HTML. (Je n'en ai pas mis dans ce blog mais mes flux de syndication, en XML, continnent du Dublin Core.) Un exemple simple, les éléments Dublin Core ayant un nom commençant par DC :


<html>
<head>
<title>Expressing Dublin Core in HTML/XHTML meta and link elements</title>
<link rel="profile" href="http://dublincore.org/documents/2008/08/04/dc-html/"/>
<meta name="DC.title" lang="en" content="Expressing Dublin Core
in HTML/XHTML meta and link elements" />
<meta name="DC.creator" content="Andy Powell, UKOLN, University of Bath" />
<meta name="DCTERMS.issued" scheme="DCTERMS.W3CDTF" content="2003-11-01" />
<meta name="DCTERMS.abstract" content="This document describes how
qualified Dublin Core metadata can be encoded
in HTML/XHTML &lt;meta&gt; elements" />
<meta name="DC.format" scheme="DCTERMS.IMT" content="text/html" />
</head>

Dernier exemple, déjà cité, les podcasts. Il n'y a pas d'identificateur officiel (on pourrait utiliser l'URI http://www.apple.com/itunes/podcasts/specs.html).

Il existe désormais un registre de ces profils, créé par le RFC 7284.


Téléchargez le RFC 6906


L'article seul

RFC 6905: Requirements for Operations, Administration, and Maintenance (OAM) in Transparent Interconnection of Lots of Links (TRILL)

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : Tissa Senevirathne (CISCO), David Bond (IBM), Sam Aldrin, Yizhou Li (Huawei), Rohit Watve (CISCO)
Pour information
Réalisé dans le cadre du groupe de travail IETF trill
Première rédaction de cet article le 30 mars 2013


Le protocole TRILL est un protocole de routage pour réseaux locaux, qui veut combiner les avantages des réseaux L2 (non routés) et L3 (routés, avec des protocoles plus complexes). Ce RFC est le cahier des charges pour les futurs mécanismes d'administration et de supervision des réseaux TRILL.

TRILL est normalisé dans le RFC 6325. Il vise surtout les gros data centers et les fournisseurs d'infonuagique. Il est par exemple déployé sur le service d'hébergement de Gandi. Comme tous les protocoles, il a besoin d'OAM : Operations, Administration and Maintenance, c'est-à-dire l'ensemble des activités de l'administrateur réseaux pour maintenir le réseau en bon état de marche (cf. RFC 6291 et RFC 5860). Un réseau TRILL est composé de RBridges, engins intermédiaires entre les ponts et les routeurs et ce sont eux qu'il faut gérer. La section 4 du RFC énumère les exigences des futurs mécanismes OAM de TRILL. Parmi elles :

  • N'importe quel RBridge doit pouvoir tester la connectivité vers n'importe quel autre RBridge (ping, quoi).
  • TRILL permet d'envoyer les paquets par différents chemins selon leurs caractéristiques. Il est donc essentiel que les trames utilisées pour l'OAM puissent être forcées à suivre un chemin particulier, celui qu'on veut tester.
  • Ces fonctions de test doivent pouvoir être effectuées à la demande, ou bien en boucle.
  • N'importe quel RBridge doit pouvoir trouver le chemin emprunté par les trames allant vers un autre RBridge (traceroute, quoi).
  • TRILL est purement pour les réseaux locaux. Il faut donc que les trames OAM ne sortent jamais du réseau TRILL.
  • Le système d'OAM doit maintenir un certain nombre de compteurs (notamment des erreurs) et les rendre accessible (par exemple par SNMP).
  • Il est nécessaire de pouvoir mesurer le taux de pertes de trames (tel que défini par le RFC 7680).
  • Il est nécessaire de pouvoir mesurer le temps d'acheminement aller-retour d'une trame (RFC 2681) et il est souhaitable qu'on puisse aussi mesurer le temps d'acheminement aller-simple (plus difficile à faire, RFC 7679).
  • Le RFC mentionne aussi la possibilité d'utiliser le trafic normal pour tester les problèmes et mesurer les performances (mesures passives, et pas seulement actives).
  • Et le tout doit bien sûr être sécurisé, qu'on ne puisse pas accéder aux informations sans être autorisé, et qu'on ne puisse pas utiliser le système d'OAM pour faire des attaques par déni de service.

Il ne reste plus qu'à développer tout cela. Un expert de TRILL parmi mes lecteurs pour expliquer ce que peuvent faire les RBridges actuels, avec résultat de commandes à l'appui ?


Téléchargez le RFC 6905


L'article seul

RFC 6903: Additional Link Relation Types

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : J. Snell
Pour information
Première rédaction de cet article le 21 mars 2013


Allez, encore tout un lot de types de liens Web qui sont enregistrés. Pas de point commun entre les types créés par ce RFC, juste quelques types intéressants.

Tous suivent les principes du RFC 8288 qui normalise cette idée de type de lien et décrit le registre où ils sont désormais stockés.

Le premier, about pointe vers une ressource qui décrit celle qui contient le lien. L'exemple donné par le RFC est celui d'un article de test d'un produit, qui pointe vers une page Web décrivant le produit. Avec les en-têtes HTTP :


HTTP/1.1 200 OK
Content-Type: text/html
Link: <http://store.example.org/product/abc>; rel="about"

Le second, preview permet de pointer vers une ressource qui offre une version limitée, plus courte ou à plus basse résolution, pour ceux qui voudraient aller vite. Ici, par exemple, une vidéo a un lien vers une version courte de dix secondes :


HTTP/1.1 200 OK
Content-Text: video/mpeg
Link: <http://example.org/preview/10-second-preview.mpg>;
       rel="preview"; type="video/mpeg"

Le troisième, privacy-policy, permet de pointer vers une ressource (par exemple une page Web) décrivant la politique du gérant, relative à la vie privée. Si vous regardez le source de ce blog, vous trouverez un tel lien en HTML, allant vers ma politique :


<link rel="privacy-policy" href="/privacy-policy.html"/>

Le RFC rappelle bien que cela n'a aucune valeur juridique : le Web est plein de « politiques de vie privée » que personne ne consulte et qui n'engagent nullement le site Web qui les affiche.

À noter que, pour indiquer ces pratiques (collectes de données personnelles, enregistrement des visites, etc), il existe un autre mécanisme, P3P. Le mécanisme de lien privacy-policy peut pointer vers une ressource P3P mais ce n'est pas obligatoire.

Le quatrième type est terms-of-service, qui pointe vers les conditions d'utilisation. Comme vous le savez, personne ne les lit, et pour des bonnes raisons (ce sont de longs textes incompréhensibles). Un exemple :


<html>
    <head>
         ...
         <link href="/tos.html" rel="terms-of-service"/>
         ...
    </head>
    <body>
         ...
    </body>
</html>

Le RFC note à juste titre que celui qui les écrit peut ensuite les violer impunément. Ce lien n'a donc d'autre rôle que de signaler ces conditions d'utilisation.

Enfin, dernier type décrit ici, type, permet de dire qu'une ressource est une instance d'une classe plus générale, identifiée par un URI, ici qu'une page décrit une personne :


HTTP/1.1 200 OK
Content-Type: text/plain
Link: <http://example.org/Person/givenName>; rel="type"

Jeanne Michu

C'est probablement surtout utile pour le Web sémantique. Attention, ce type n'a rien à voir avec le Content-type qui indique le format physique (dit souvent « type MIME »).


Téléchargez le RFC 6903


L'article seul

RFC 6902: JavaScript Object Notation (JSON) Patch

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : P. Bryan (Salesforce.com), M. Nottingham (Akamai)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 3 avril 2013


Le format de données structurées JSON, normalisé dans le RFC 7159, a pris une importance de plus en plus grande et est désormais utilisé dans bien des contextes. Cela entraine l'apparition de normes auxiliaires, spécifiant comment faire telle ou telle opération sur des fichiers JSON. Ainsi, le RFC 6901 indique comment désigner une partie d'un document JSON et ce RFC 6902, sorti en même temps, indique comment exprimer les modifications (patches) à un document JSON.

Logiquement, le patch est lui-même un fichier JSON (de type application/json-patch, cf. la section 6 de notre RFC) et il indique les opérations à faire (ajouter, remplacer, supprimer) à un endroit donné du document (identifié par un pointeur JSON, ceux du RFC 6901). Voici un exemple de patch :

[
     { "op": "add", "path": "/baz", "value": "qux" }
]

Il va ajouter (opération add) un membre nommé baz et de valeur qux. Si le document originel était :

{ "foo": "bar"}

Celui résultant de l'application du patch sera :

{
     "baz": "qux",
     "foo": "bar"
   }

À noter que ces patches travaillent sur le modèle de donnéees JSON, pas directement sur le texte (autrement, on utiliserait le traditionnel format diff), et peuvent donc s'appliquer sur des données qui ont un modèle similaire, quelle que soit la syntaxe qu'ils avaient. Dans les exemples de code Python à la fin, le patch est appliqué à des variables Python issues d'une analyse d'un fichier JSON, mais qui pourraient avoir une autre origine. (Au passage, je rappelle l'existence d'un format équivalent pour XML, le XML patch du RFC 5261.)

Le patch peut être envoyé par divers moyens, mais l'un des plus courants sera sans doute la méthode PATCH de HTTP (RFC 5789). Voici un exemple d'une requête HTTP avec un patch :

PATCH /my/data HTTP/1.1
Host: example.org
Content-Length: 326
Content-Type: application/json-patch
If-Match: "abc123"

[
     { "op": "test", "path": "/a/b/c", "value": "foo" },
     { "op": "remove", "path": "/a/b/c" },
     { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
     { "op": "replace", "path": "/a/b/c", "value": 42 },
     { "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
     { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]

Un patch JSON a quelle forme (section 3) ? C'est un tableau dont chaque object qui le compose est une opération, à appliquer dans l'ordre du tableau (dans le premier exemple ci-dessus, le tableau ne comportait qu'une seule opération). L'entité à laquelle on applique le patch est donc transformée successivement et chaque opération s'applique au résultat de l'opération précédente.

Quelles sont les opérations possibles (section 4) ? Le membre op indique l'opération, path la cible et value la nouvelle valeur. op peut être :

  • add : si la cible est dans un tableau, on ajoute la valeur à ce tableau (si le pointeur pointe vers la fin du tableau, avec la valeur -, on ajoute après le dernier élément). Si la cible est un membre inexistant d'un objet, on l'ajoute. S'il existe, on le remplace (ce point a été vigoureusement critiqué au sein du groupe de travail, où plusieurs personnes regrettaient qu'on mélange les sémantiques de add et de replace ; parmi les propositions alternatives, il y avait eu de nommer cette opération set ou put plutôt qu'add).
  • remove : on retire l'élément pointé.
  • replace : on remplace la valeur pointée.
  • move : on déplace l'élément (ce qui nécessite un paramètre supplémentaire, from).
  • copy : on copie la valeur pointée vers un nouvel endroit.
  • test : teste si une valeur donnée est présente à l'endroit indiqué. Cela sert lorsqu'on veut des opérations conditonnelles. Les opérations étant appliquées dans l'ordre, et la première qui échoue stoppant tout le patch, un test peut servir à faire dépendre les opérations suivantes de l'état du document JSON.

Mais à quel endroit applique-t-on cette opération ? C'est indiqué par le membre path qui est un pointeur JSON (cf. RFC 6901). Enfin, value indique la valeur, pour les opérations qui en ont besoin (par exemple add mais évidemment pas remove).

La section 5 spécifie ce qui se passe en cas d'erreurs : le traitement s'arrête au premier problème. Pour le cas de la méthode HTTP PATCH, voir la section 2.2 du RFC 5789. PATCH étant atomique, dans ce cas, le document ne sera pas du tout modifié.

Quelles mises en œuvre existent ? Une liste est disponible en ligne, ainsi que des jeux de test. Je vais ici essayer celle en Python, python-json-patch. D'abord, il faut installer python-json-pointer et python-json-patch :

% git clone https://github.com/stefankoegl/python-json-pointer.git
% cd python-json-pointer
% python setup.py build
% sudo python setup.py install

% git clone https://github.com/stefankoegl/python-json-patch.git
% cd python-json-patch
% python setup.py build
% sudo python setup.py install

Ensuite, on écrit un programme Python qui utilise cette bibliothèque. On va le faire simple, il prend sur la ligne de commande deux arguments, un qui donne le nom du fichier JSON original et un qui donne le nom du fichier contenant le patch. Le résultat sera écrit sur la sortie standard :

#!/usr/bin/env python

import jsonpatch
import json
import sys

if len(sys.argv) != 3:
    raise Exception("Usage: patch.py original patchfile")

old = json.loads(open(sys.argv[1]).read())
patch = json.loads(open(sys.argv[2]).read())

new = jsonpatch.apply_patch(old, patch)

print json.dumps(new)

Maintenant, on peut écrire un fichier JSON de test, test.json, qui décrit ce RFC :

% cat test.json
{
  "Title": "JSON Patch",
  "Number": "NOT PUBLISHED YET",	
  "Authors": [
       "P. Bryan"
   ]
}

On va maintenant essayer avec différents fichiers patch.json contenant des patches (l'annexe A contient plein d'autres exemples). Un ajout à un tableau :

% cat patch.json 
[
     { "op": "add", "path": "/Authors/0", "value": "M. Nottingham" }
]

% python patch.py test.json patch.json
{"Title": "JSON Patch", "Number": "NOT PUBLISHED YET", "Authors": ["M. Nottingham", "P. Bryan"]}

Un changement d'une valeur :

% cat patch.json                      
[
     { "op": "replace", "path": "/Number", "value": "6902" }
]

% python patch.py test.json patch.json
{"Title": "JSON Patch", "Number": "6902", "Authors": ["P. Bryan"]}

Un ajout à un objet :

% cat patch.json
[
     { "op": "add", "path": "/Status", "value": "standard" }
]

% python patch.py test.json patch.json
{"Status": "standard", "Title": "JSON Patch", "Number": "NOT PUBLISHED YET", "Authors": ["P. Bryan"]}

Une suppression d'un champ d'un objet :

% cat patch.json
[
     { "op": "remove", "path": "/Authors" }
]

% python patch.py test.json patch.json
{"Title": "JSON Patch", "Number": "NOT PUBLISHED YET"}

Si vous aimez les controverses, un des débats les plus animés, plus d'un an avant la sortie du RFC, avait été de savoir si l'opération d'ajout devait se noter add (comme cela a finalement été choisi) ou bien simplement +. Le format diff traditionnel utilise des mnémoniques plutôt que des noms et cela peut accroître la lisibilité (cela dépend des goûts).

Merci à Fil pour sa relecture attentive qui a trouvé plusieurs problèmes techniques.


Téléchargez le RFC 6902


L'article seul

RFC 6901: JavaScript Object Notation (JSON) Pointer

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : P. Bryan (Salesforce.com), K. Zyp (SitePen), M. Nottingham (Akamai)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 3 avril 2013


Ce court RFC spécifie une syntaxe pour identifier un élément particulier dans un document JSON. Cela permettra de pointer vers l'intérieur d'un document, par exemple depuis un URI.

JSON (RFC 7159) est un format structuré de données très populaire sur le Web. Les documents JSON peuvent être de taille très variable et il serait intéressant d'avoir une syntaxe formelle pour désigner une partie bien spécifique d'un document JSON, comme XPointer le permet pour XML et le RFC 5147 pour le texte brut. Outre les URI cités plus haut, un des usages envisagés est la modification de documents JSON, via la norme JSON patch du RFC 6902, puisque la mise à jour nécessite de dire exactement où on va faire l'ajout ou la suppression de données.

La syntaxe est exposée en section 3 : un JSON pointer est une chaîne de caractères Unicode (JSON pointer travaille entièrement avec des caractères Unicode, pas avec des octets). Il contient plusieurs éléments séparés par des barres obliques. Ce caractère, ainsi que le tilde, sont donc spéciaux et, si on veut avoir leur valeur littérale, il faut un échappement, ~0 pour le ~ et ~1 pour le /. (Programmeurs, attention, en décodant, il faut d'abord remplacer tous les ~1 par des / avant de s'attaquer à la deuxième substitution, sinon ~01 sera mal décodé.)

Pour illustrer ces pointeurs, je vais utiliser pour tous les exemples les données des chemins de fer britanniques disponibles en JSON en http://api.traintimes.im/. Commençons par récupérer la liste des stations :

% wget http://api.traintimes.im/stations_all.json

On peut alors connaître les codes tiploc des gares, ici, on va utiliser WMOR pour Woodsmoor. Cherchons les trains qui passent à Woodsmoor aux alentours de midi :

% wget -O wmor.json http://api.traintimes.im/locations.json\?location=WMOR\&date=2013-02-14\&startTime=1200

Le fichier JSON (passé à jsonlint) ressemble à :

{
  ...
  "services" : [ { 
       "departure_time" : "1141",
         "destination" : { "arrival_time" : "1145",
            "crs" : "HAZ",
            "description" : "Hazel Grove",
            "tiploc" : "HAZL"
          }},
        "departure_time" : "1206",
          "destination" : { "arrival_time" : "1227",
            "crs" : "MAN",
            "description" : "Manchester Piccadilly",
            "tiploc" : "MNCRPIC"
          }} ...

Par exemple, avec ces données /services, /services/1 et /services/1/destination/description sont tous des pointeurs JSON valides.

Et comment est-ce que cela s'interprète ? La section 4 le décrit. On part de la racine du document JSON. Donc, le pointeur composé d'une chaîne vide identifie la totalité du document. Ensuite, si la racine est un objet JSON (avec des champs nommés), l'élement suivant identifie un des champs. Ainsi, /foo identifie le champ foo de l'objet situé à la racine (il doit être unique). Si par contre la racine est un tableau, l'élement suivant doit être un nombre, l'index dans le tableau (en partant de zéro donc /1 identifie le deuxième élément du tableau situé à la racine). Une seule valeur non-numérique est permise, - qui indique l'élément situé après la fin du tableau (pour le JSON patch du RFC 6902, cela sert aux ajouts à la fin du tableau, autrement, cela désigne un élément non-existant). Donc, attention, / n'identifie pas la racine du document mais un élément de nom vide situé à la racine.

Le pointeur JSON est ensuite représenté sous forme texte comme une chaîne de caractères JSON (section 5) ce qui oblige à échapper les caractères spéciaux des chaînes JSON comme la barre inverse ou comme le guillemet. Par exemple, il faudra écrire a\\b pour trouver le membre d'objet JSON nommé a\b.

Et dans un URI (section 6) ? Il faudra encoder le pointeur en UTF-8 et faire un échappement « pour cent » (RFC 3986, section 2.1) des caractères qui sont spéciaux dans un URI (comme le point d'interrogation, section 2.2 du RFC 3986). Ainsi, http://api.traintimes.im/locations.json?location=WMOR\&date=2013-02-14\&startTime=1200#/services/1/destination/arrival_time pointera vers la valeur 1227 (regardez l'identificateur de fragment après le croisillon : c'est un pointeur JSON). À noter que tous les types MIME n'accepteront pas forcément le pointeur JSON comme un moyen normal de désigner un fragment du document JSON et l'exemple ci-dessus est donc hypothétique.

Reste à traiter le cas des erreurs (section 7). Deux erreurs typiques sont un élément non numérique dans le pointeur alors que la valeur est un tableau, ou bien un nom de champ inexistant. Le RFC ne spécifie pas ce qui doit se produire dans un tel cas, cela doit être défini par l'application qui utilise les pointeurs (pour JSON patch, voir les sections 4.1 et 5 du RFC 6902).

Une liste des mises en œuvre connues des pointeurs JSON est disponible à l'IETF (en fait, ce sont les mises en œuvre de JSON Patch mais, comme les pointeurs sont un pré-requis, elle couvre aussi les mises en œuvre des pointeurs). Il existe aussi une implémentation « faite en 20 minutes » en node.js, js-6901. Testons l'implémentation Python :

% git clone https://github.com/stefankoegl/python-json-pointer.git
% cd python-json-pointer
% python setup.py build
% sudo python setup.py install

Et lançons l'interpréteur Python pour voir :


>>> import jsonpointer
>>> import json
>>> doc = json.load(open("wmor.json"))

>>> jsonpointer.resolve_pointer(doc,'/services/1/destination/description')
u'Manchester Piccadilly'

>>> jsonpointer.resolve_pointer(doc,'/services/0/destination/description')
u'Hazel Grove'

>>> jsonpointer.resolve_pointer(doc,'/services/2/destination')
{u'crs': u'BUX', u'arrival_time': u'1251', u'description': u'Buxton', u'tiploc': u'BUXTON'}

Tout marche donc bien et on récupère, soit des valeurs, soit des objets JSON. Et avec un pointeur qui ne pointe vers rien ?


>>> jsonpointer.resolve_pointer(doc,'/zzz')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/jsonpointer.py", line 105, in resolve_pointer
    return pointer.resolve(doc, default)
  File "/usr/local/lib/python2.7/dist-packages/jsonpointer.py", line 140, in resolve
    doc = self.walk(doc, part)
  File "/usr/local/lib/python2.7/dist-packages/jsonpointer.py", line 183, in walk
    raise JsonPointerException("member '%s' not found in %s" % (part, doc))
jsonpointer.JsonPointerException: member 'zzz' not found in { ...

On a, fort logiquement, une exception.


Téléchargez le RFC 6901


L'article seul

RFC 6895: Domain Name System (DNS) IANA Considerations

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Donald Eastlake (Huawei)
Réalisé dans le cadre du groupe de travail IETF dnsext
Première rédaction de cet article le 17 avril 2013


Un RFC un peu bureaucratique, pour détailler les mécanismes utilisés pour l'enregistrement dans les registres de l'IANA des paramètres liés au DNS. Il met très légèrement à jour son prédécesseur, le RFC 6195, libéralisant encore un peu plus l'enregistrement de nouveaux types de données dans le DNS.

Un certain nombre de paramètres (section 2, qui résume le format des paquets DNS), dans le DNS, sont enregistrés à l'IANA, afin de s'assurer d'une interprétation identique partout. C'est ainsi que l'IANA gère un registre des paramètres DNS où on trouve, entre autres, les types d'enregistrement (A, codé 1, pour une adresse IPv4, AAAA, codé 28, pour une adresse IPv6, LOC, codé 29, pour les positions géographiques du RFC 1876, TLSA, codé 52, pour le RFC 6698, etc). Cet espace n'étant pas de taille infinie, il faut y enregistrer de nouveaux paramètres avec prudence.

L'affectation dans cet espace forme le point le plus important de ce RFC (section 3). Il faut comprendre qu'il y a trois types de numéros utilisés dans cet espace : ceux qui identifient un type de données (comme les quatre cités plus haut), ceux qui identifient une question et le cas particulier des méta-types. Une question, dans le DNS, peut être un type de données (on met 52 dans le champ QTYPE de la requête pour dire qu'on veut des enregistrements TLSA), mais il existe aussi des questions qui ne correspondent pas à un type unique comme 255 (noté ANY ou ALL ou *) qui veut dire « envoie-moi toutes les données que tu as, quelles que soit leur type ». Enfin, les méta-types sont des données temporaires, liées à une transaction, comme les TSIG (numéro 250) du RFC 2845, qui n'existent que le temps de la session DNS.

Pour les types de données, la politique d'allocation est simple et libérale : on remplit un formulaire (qui se trouve en annexe A du RFC), on l'envoie à l'IANA (via l'adresse dns-rrtype-applications@ietf.org) et un expert l'examinera (procédure Expert Review du RFC 5226) et rendra son jugement. (Il est recommandé de l'envoyer d'abord à la liste du liste de groupe de travail dnsext pour un examen préalable.) Les formulaires approuvés sont ensuite publiquement archivés (mais je n'ai pas trouvé où).

Le RFC donne les critères que doit suivre l'expert pour sa décision :

  • D'abord, être libéral et accepter la plupart des demandes, sauf raison impérieuse. Par défaut, la réponse est oui.
  • Parmi les bonnes raisons de rejeter une demande, l'insuffisance de la documentation fournie, des erreurs DNS dans la spécification du nouveau type (par exemple des suppositions incorrectes sur le fonctionnement des jokers, un cas relativement fréquent) ou un trop grand nombre de types demandés alors que l'application pourrait s'en tirer avec un seul.
  • Il y a une autre raison technique de rejeter une demande, ou en tout cas de l'examiner de plus près : l'enregistrement facile et libéral ne concerne que les types de données où les serveurs de noms n'ont pas besoin d'appliquer un traitement spécial (question I du formulaire à remplir). Autrement dit, ils peuvent traiter le nouveau type comme un type inconnu, selon le RFC 3597. S'il y a besoin d'un traitement spécial (par exemple CNAME, DS), on revient à la procéédure, bien plus lourde, d'une norme en bonne et due forme. Notez que, pour certains types, un traitement spécial est possible mais pas obligatoire (cas de MX, où il est conseillé d'inclure les adresses IP des serveurs de courrier dans la réponse mais, si ce n'est pas fait, le service marche quand même). Dans ce cas, c'est la procédure libérale qui s'applique

Outre l'enregistrement de nouveaux types de ressources DNS, notre RFC mentionne également d'autres champs des messages DNS. Un changement ou une extension de leur sémantique continue à nécessiter une action plus lourde à l'IETF. C'est le cas des classes (comme la plus courante, IN pour Internet). C'est aussi le cas de bits comme RD (Recursion Desired), qui n'a de signification que dans une question DNS. Dans une réponse, il est indéfini et son éventuelle utilisation future nécessitera un RFC sur le chemin des normes. Même chose pour le dernier bit qui reste libre dans les options, le bit Z (section 2.1). Quant aux opcodes qui indiquent le type du message (requête / notification / mise à jour dynamique / etc), un ajout à leur liste nécessitera le même chemin (section 2.2). Ils ont leur propre registre.

Les codes de réponse (rcodes), comme NXDOMAIN (nom inexistant), FORMERR (erreur de format) ou BADTIME (signature trop ancienne ou trop récente, cf. RFC 2845) sont tirés d'un espace plus vaste (il n'y a pas que les quatre bits 12 à 15 dans l'en-tête classique, il y a aussi des extensions comme les pseudo-enregistrements OPT) et la procédure est donc un peu plus libérale (IETF Review, c'est-à-dire un RFC non individuel mais pas forcément sur le chemin des normes, cf. section 2.3). Il y a également un registre de ces codes. À noter qu'une gestion trop légère des registres avait entraîné à une époque une double affectation du rcode 16, enregistré par le RFC 2671, puis ré-enregistré par le RFC 2845...

Notez aussi que notre RFC mentionne (section 3.3) l'allocation des noms, pour rappeler qu'il existe des noms réservés (RFC 2606) et qu'il existe un RFC (bien dépassé par les évolutions politiciennes ultérieures à l'ICANN), le RFC 1591, sur l'allocation et la gestion des TLD.

Les changements depuis le RFC 6195 sont décrits dans l'annexe B. Le seul vraiment important est une simplification du processus d'enregistrement des nouveaux types de données (par exemple, l'examen de la demande d'enregistrement d'un nouveau type de données par le groupe de travail dnsext n'est plus obligatoire). Cette simplification était largement consensuelle. Le reste des changements est un ensemble varié de clarifications et de précisions.


Téléchargez le RFC 6895


L'article seul

RFC 6892: The 'describes' Link Relation Type

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : E. Wilde (EMC Corporation)
Pour information
Première rédaction de cet article le 13 mars 2013


Dans le registre des types de liens, il y avait déjà un describedby qui indiquait une ressource Web décrivant la ressource courante. Désormais, il y a aussi l'inverse, describes, qui va d'une ressource à celle qu'elle décrit.

C'est dans le RFC 8288 que sont spécifiés ces types de liens. describedby avait été spécifié par la norme W3C POWDER mais celle-ci ne spéficiait pas le type du lien inverse. Notons que describes est très général, il ne spécifie pas le format à utiliser et, notamment, on n'est pas obligé de se limiter à RDF, on a tout à fait le droit de fournir des descriptions en XML ou JSON (section 4 de notre RFC).

Par exemple, si une page Web parle du livre Net.Lang, elle peut le référencer ainsi, en utilisant comme identificateur du livre l'URL de son site officiel :


<link rel="describes" href="http://net-lang.net/"/>

ou bien, pourquoi pas, avec l'ISBN (RFC 8254) :


<link rel="describes" href="urn:isbn:978-2-915825-08-4"/>

Il peut y avoir sur le Web plusieurs ressources qui pointent, via un lien describes, vers une ressource donnée.

Attention, n'importe qui peut toujours mettre un lien describes pointant vers n'importe où : la seule existence de ce lien n'implique pas qu'il fasse autorité (section 5).


Téléchargez le RFC 6892


L'article seul

RFC 6891: Extension Mechanisms for DNS (EDNS(0))

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : J. Damas (Bond Internet Systems), M. Graff, P. Vixie (Internet Systems Consortium)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsext
Première rédaction de cet article le 17 avril 2013


L'extension EDNS au traditionnel DNS a plus de treize ans et fête cette longue durée avec une nouvelle version, essentiellement cosmétique. EDNS a servi à faire sauter un certain nombre de barrières qui limitait la croissance du DNS, notamment l'antédiluvienne limite des réponses à seulement 512 octets.

Le protocole DNS, dans sa forme originale, spécifiée dans le RFC 1034, ne permettait pas de négocier des options, d'indiquer au serveur ce que sait faire le client, en plus des capacités minimales qu'impose le protocole. La norme originale (RFC 1035, section 2.3.4) imposait une limite de 512 octets aux messages DNS envoyés sur UDP. Une telle limite est bien trop basse, depuis longtemps, par exemple pour DNSSEC (section 3 de notre RFC), et ne correspondait pas aux capacités des réseaux et des machines modernes. Le DNS avait d'autres limites comme des champs de taille fixe, ne permettant qu'un petit nombre de valeurs possibles, désormais presque toutes définies (par exemple, avant EDNS, les codes de réponse - RCODE - ne faisaient que quatre bits, donc étaient presque tous épuisés).

EDNS0 est un mécanisme d'extension du DNS et une première extension, pour indiquer une taille supérieure aux 512 octets. L'extension se fait en squattant des champs inutilisés du paquet (DNS est un format binaire rigide, il ne permet donc pas facilement d'ajouter de nouvelles possibilités) et en créant un pseudo-type d'enregistrement, le type OPT. Déclaré comme indispensable par certaines autres extensions (notamment DNSSEC), EDNS fait aujourd'hui partie du bagage nécessaire à toute mise en œuvre du DNS.

L'extension pour indiquer la taille permet au client de spécifier la quantité d'octets qu'il est capable de recevoir (section 4.3). Avec le client DNS dig, cela se fait avec l'option bufsize (désormais activée par défaut dans les versions récentes de dig). Notre RFC recommande une valeur par défaut de 4 096 octets (section 6.2.5).

Prenons par exemple le TLD .hk car c'est un des plus gros en nombre de serveurs de noms. Si je demande cette liste :


% dig NS hk.

; <<>> DiG 9.8.1-P1 <<>> NS hk.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65212
;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 0, ADDITIONAL: 14

;; QUESTION SECTION:
;hk.				IN	NS

;; ANSWER SECTION:
hk.			69658	IN	NS	X.HKIRC.NET.hk.
hk.			69658	IN	NS	T.HKIRC.NET.hk.
hk.			69658	IN	NS	S.HKIRC.NET.hk.
hk.			69658	IN	NS	A.HKIRC.NET.hk.
hk.			69658	IN	NS	B.HKIRC.NET.hk.
hk.			69658	IN	NS	W.HKIRC.NET.hk.
hk.			69658	IN	NS	Z.HKIRC.NET.hk.
hk.			69658	IN	NS	U.HKIRC.NET.hk.
hk.			69658	IN	NS	Y.HKIRC.NET.hk.
hk.			69658	IN	NS	V.HKIRC.NET.hk.

;; ADDITIONAL SECTION:
A.HKIRC.NET.hk.		69658	IN	A	203.119.2.18
B.HKIRC.NET.hk.		69658	IN	A	203.119.87.19
B.HKIRC.NET.hk.		69658	IN	AAAA	2001:dca:1000::cb77:5713
S.HKIRC.NET.hk.		69658	IN	A	128.32.136.3
S.HKIRC.NET.hk.		69658	IN	AAAA	2607:f140:ffff:fffe::3
T.HKIRC.NET.hk.		69658	IN	A	128.32.136.14
T.HKIRC.NET.hk.		69658	IN	AAAA	2607:f140:ffff:fffe::e
U.HKIRC.NET.hk.		69658	IN	A	210.201.138.58
U.HKIRC.NET.hk.		69658	IN	AAAA	2404:0:10a0::58
V.HKIRC.NET.hk.		69658	IN	A	204.61.216.46
V.HKIRC.NET.hk.		69658	IN	AAAA	2001:500:14:6046:ad::1
W.HKIRC.NET.hk.		69658	IN	A	202.12.28.140
W.HKIRC.NET.hk.		69658	IN	AAAA	2001:dc0:1:0:4777::140
X.HKIRC.NET.hk.		69658	IN	A	202.45.188.39

;; Query time: 1 msec
;; SERVER: 130.129.5.6#53(130.129.5.6)
;; WHEN: Tue Mar 12 19:30:33 2013
;; MSG SIZE  rcvd: 486

On voit que la réponse était proche des 512 octets et que, pour qu'elle tienne dans cette limite, le serveur a dû sérieusement réduire la taille de la section additionnelle (additional section). Si le serveur avait dû réduire encore plus, jusqu'à retirer des enregistrements de la section réponse (answer section), il aurait dû mettre le bit TC (troncation) à VRAI, imposant ainsi au client de reessayer en TCP.

Mais EDNS0 permet d'avoir la totalité de la section additionnelle (notez la pseudo-section lié à l'enregistrement OPT) :


% dig +bufsize=4096 NS hk.

; <<>> DiG 9.8.1-P1 <<>> +bufsize=4096 NS hk.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50455
;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 0, ADDITIONAL: 20

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

;; ANSWER SECTION:
hk.			69632	IN	NS	Z.HKIRC.NET.hk.
hk.			69632	IN	NS	S.HKIRC.NET.hk.
hk.			69632	IN	NS	A.HKIRC.NET.hk.
hk.			69632	IN	NS	X.HKIRC.NET.hk.
hk.			69632	IN	NS	T.HKIRC.NET.hk.
hk.			69632	IN	NS	V.HKIRC.NET.hk.
hk.			69632	IN	NS	W.HKIRC.NET.hk.
hk.			69632	IN	NS	Y.HKIRC.NET.hk.
hk.			69632	IN	NS	U.HKIRC.NET.hk.
hk.			69632	IN	NS	B.HKIRC.NET.hk.

;; ADDITIONAL SECTION:
A.HKIRC.NET.hk.		69632	IN	A	203.119.2.18
B.HKIRC.NET.hk.		69632	IN	A	203.119.87.19
B.HKIRC.NET.hk.		69632	IN	AAAA	2001:dca:1000::cb77:5713
S.HKIRC.NET.hk.		69632	IN	A	128.32.136.3
S.HKIRC.NET.hk.		69632	IN	AAAA	2607:f140:ffff:fffe::3
T.HKIRC.NET.hk.		69632	IN	A	128.32.136.14
T.HKIRC.NET.hk.		69632	IN	AAAA	2607:f140:ffff:fffe::e
U.HKIRC.NET.hk.		69632	IN	A	210.201.138.58
U.HKIRC.NET.hk.		69632	IN	AAAA	2404:0:10a0::58
V.HKIRC.NET.hk.		69632	IN	A	204.61.216.46
V.HKIRC.NET.hk.		69632	IN	AAAA	2001:500:14:6046:ad::1
W.HKIRC.NET.hk.		69632	IN	A	202.12.28.140
W.HKIRC.NET.hk.		69632	IN	AAAA	2001:dc0:1:0:4777::140
X.HKIRC.NET.hk.		69632	IN	A	202.45.188.39
X.HKIRC.NET.hk.		69632	IN	AAAA	2405:3001:1:58::1:39
Y.HKIRC.NET.hk.		69632	IN	A	137.189.6.21
Y.HKIRC.NET.hk.		69632	IN	AAAA	2405:3000:3:60::21
Z.HKIRC.NET.hk.		69632	IN	A	194.146.106.70
Z.HKIRC.NET.hk.		69632	IN	AAAA	2001:67c:1010:17::53

;; Query time: 1 msec
;; SERVER: 130.129.5.6#53(130.129.5.6)
;; WHEN: Tue Mar 12 19:30:59 2013
;; MSG SIZE  rcvd: 613

Et voilà, tout le monde est désormais content.

La section 6 décrit le pseudo-enregistrement OPT, dont la présence marque un paquet comme conforme à EDNS. Il est situé dans la section additionnelle du message DNS, a le type 41, le nom de domaine est forcément . (la racine), la classe est détournée de son rôle normal pour indiquer la taille des paquets que l'envoyeur pourra recevoir en retour et le champ TTL est également détourné de son usage normal pour offrir de nouvelles options et de nouveaux codes de retour (rappelez-vous qu'il n'y avait que quatre bits pour ces codes dans le DNS original). Pour l'instant, une seule nouvelle option, le bit DO (DNSSEC OK) qui indique la capacité de l'émetteur à traiter les signatures DNSSEC (il avait été normalisé dans le RFC 3225).

L'ex-champ TTL sert aussi à indiquer le numéro de version d'EDNS, zéro actuellement (d'où le nom EDNS0 qu'on utilise parfois). Programmeurs, attention, certaines API (par exemple celle de DNS Python) nécessitent d'indiquer le numéro de version pour activer EDNS et il faut donc indiquer zéro pour dire qu'on veut de l'EDNS, ce qui peut être déroutant.

Ensuite, les données peuvent contenir plusieurs options. À l'heure actuelle, l'écrasante majoritéé des paquets EDNS n'en contiennent aucune. Mais, si c'est le cas, elles sont codées en TLV, un code indiquant l'option (les valeurs possibles étant dans un registre IANA), une longueur et les données spécifiques à l'option. Un exemple d'une telle option est le NSID du RFC 5001.

On notera qu'EDNS est ce que le DNS appelle une extension hop by hop ce qui veut dire qu'elle s'applique entre deux logiciels adjacents, pas de bout en bout. Si un client DNS demande à un résolveur local, qui demande à son tour à un serveur de .re, les options EDNS mises par le client sont transmises uniquement au résolveur, qui fabriquera ensuite une requête différente (peut-être avec d'autres options), pour le serveur faisant autorité pour .re.

Encore aujourd'hui, il existe des serveurs qui ne gèrent pas EDNS. Par exemple, ceux de microsoft.com répondent FORMERR (Format Error) :


% dig +bufsize=4096 @ns2.msft.net. SOA microsoft.com.

; <<>> DiG 9.8.1-P1 <<>> +bufsize=4096 @ns2.msft.net. SOA microsoft.com.
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: FORMERR, id: 54935
...

La section 6.2.2 de notre RFC précise donc qu'un émetteur intelligent peut alors se rabattre sur du DNS classique et ne pas envoyer l'enregistrement OPT :


% dig @ns2.msft.net. SOA microsoft.com.              

; <<>> DiG 9.8.1-P1 <<>> @ns2.msft.net. SOA microsoft.com.
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22484
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;microsoft.com.			IN	SOA

;; ANSWER SECTION:
microsoft.com.		3600	IN	SOA	ns1.msft.net. msnhst.microsoft.com. 2013031202 300 600 2419200 3600
...

Au moins, les serveurs de microsoft.com répondent, même si c'est par un refus. Plus embêtant, les serveurs qui ne répondent plus du tout lorsque la requête est en EDNS, en général en raison d'une boîte noire mal programmée et mal gérée installée devant le serveur (un pare-feu par exemple : beaucoup d'administrateurs réseaux ne supportent pas que le serveur DNS marche bien et mettent donc une middlebox boguée devant, cf. section 8 de notre RFC, ainsi que le RFC 5625). Un logiciel comme BIND, lorsqu'il ne reçoit pas de réponse, réessaie sans EDNS pour voir si c'est cela la cause du problème. Cette possibilité est décrite en section 6.2.5 qui recommande d'essayer d'abord EDNS avec une taille plus petite (inférieure à la MTU, au cas où le problème soit lié à la fragmentation), puis enfin sans EDNS.

L'EDNS original, du RFC 2671, prévoyait également des nouvelles façons de stocker les composants d'un nom de domaine, en plus des deux méthodes DNS traditionnelles, comprimée ou non (sections 4.2 et 5 de notre RFC et section 4.1.4 du RFC 1035). Cette pratique a été très peu utilisée, en raison des difficultés de déploiement (cf. RFC 3363 et RFC 3364). Notre RFC 6891 abandonne donc cette possibilité et reclasse le RFC 2673 (le seul qui avait utilisé un nouveau type de composants, les « composants binaires ») dans le cimetière des RFC dépassés. C'est le principal changement de ce nouveau RFC (les autres étant plutôt des détails, cf. annexe A.) Notons aussi que ce nouveau RFC est désormais « Norme Internet » et plus simplement « Proposition de norme ».

Pour les amateurs de programmation, du code C d'analyse d'un paquet DNS contenant de l'EDNS est dans mon article « Décoder les paquets DNS capturés avec pcap ».

Quelques exemples de code pour finir. Pour analyser un enregistrement OPT d'EDNS, voir comment c'est fait dans DNSmezzo. Ensuite, pour envoyer des requêtes EDNS, en Go, avec godns :

const (
	EDNSBUFFERSIZE  uint16  = 4096
)
...
m := new(dns.Msg)
...
m.SetEdns0(EDNSBUFFERSIZE, true)

En Python, avec DNSpython (notez qu'on indique la version d'EDNS donc zéro pour activer EDNS n'est pas une erreur) :

message = dns.message.make_query(name, type, use_edns=0, payload=4096)

Et pour finir, en C, si vous assemblez le paquet à la main (il y a évidemment des façons plus simples de faire de l'EDNS), le code pourra ressembler à :

 /* OPT pseudo-RR */
 after_qname[4] = 0;     /* root domain */
 /* OPT = type 41 */
 after_qname[5] = 0;
 after_qname[6] = 41;
 /* Class stores the payload size */
 bufsize_wire = htons(bufsize);
 memmove(after_qname + 7, &bufsize_wire, sizeof(bufsize));
 /* TTL store the RCODE and flags */
 after_qname[9] = 0;
 after_qname[10] = 0;
 if (dnssec) {
     after_qname[11] = 128;      /* DO: request DNSSEC signatures */
 } else {
     after_qname[11] = 0;
 }
 after_qname[12] = 0;
 /* Resource data length (empty, here) */
 after_qname[13] = 0;
 after_qname[14] = 0;

Téléchargez le RFC 6891


L'article seul

RFC 6890: Special-Purpose IP Address Registries

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : M. Cotton (ICANN), L. Vegoda (ICANN), R. Bonica (Juniper), B. Haberman (Johns Hopkins University Applied Physics Lab)
Première rédaction de cet article le 30 avril 2013
Dernière mise à jour le 16 juin 2017


Un certain nombre de préfixes d'adresses IP sont spéciaux, réservés à des tâches comme les exemples dans la documentation, ou bien prévus pour des protocoles particuliers. Ces préfixes n'étaient pas documentés à un endroit unique, ils étaient dans certains RFC, avec parfois des registres IANA. Ce RFC restructure le système, désormais la seule source faisant autorité est le registre IANA (un pour IPv4 et un pour IPv6). En outre, ces deux registres ont désormais une structure bien définie, notamment pour indiquer les propriétés d'un préfixe spécial.

Parmi les nombreux préfixes spéciaux, on peut citer le 0.0.0.0/8 du RFC 1122, qui sert à désigner le réseau local, ou le fe80::/10 que le RFC 4291 dédie aux adresses locales au lien. De temps en temps, un RFC rassemble tous ces préfixes en un seul document et c'est ainsi que le RFC 5735 cataloguait tous les préfixes spéciaux IPv4 alors que le RFC 5156 faisait la même chose pour IPv6. Certains préfixes sont affectés à l'IANA pour une allocation ultérieure (comme le 192.0.0.0/24 du RFC 5736). Ces prefixes-là ont un registre à l'IANA, pour enregistrer ces allocations mais il n'existait pas de registre général de toutes les adresses IPv4 spéciales. Même chose en IPv6 : le RFC 2928 et le RFC 4773 affectaient 2001:0000::/23 à l'IANA et créaient un registre pour les adresses de ce préfixe mais sans prévoir de registre pour tous les préfixes spéciaux. Résultat, lorsqu'un nouveau préfixe était déclaré, il n'y avait plus de source à jour, avant qu'on publie un nouvel RFC de synthèse. Notre RFC 6890 change ce système et crée ce registre unique de la totalité des préfixes spéciaux, pour IPv4 et pour IPv6. Notre RFC annule donc les RFC 5735 et RFC 5156.

La section 2 du RFC liste les décisions prises et que l'IANA devra appliquer (suivant les sections 4.1 et 4.3 du RFC 2860 qui décrit les tâches de l'IANA). Le registre doit conserver, pour chaque préfixe IP, un certain nombre d'informations parmi lesquelles :

  • Le RFC où ce préfixe a été décrit.
  • Un booléen disant si les adresses IP dans ce préfixe peuvent apparaître en adresse source d'un datagramme IP.
  • Un booléen disant si les adresses IP dans ce préfixe peuvent apparaître en adresse destination d'un datagramme IP.
  • Un booléen (« Forwardable ») indiquant si les routeurs peuvent faire suivre les paquets ayant une telle adresse comme destination.
  • Un booléen (« Global » dans le RFC mais renommé « Globally reachable » par le RFC 8190) indiquant si les adresses de ce préfixe peuvent être transmises à un routeur situé dans un autre domaine. Notez que la définition est claire, mais le terme est ambigu (« Global » peut désigner la transmissibilité ou bien l'unicité, la première version de mon article était d'ailleurs erronée sur ce point), d'où le renommage du RFC 8190. Pour comprendre la différence avec le booléen précédent, regardez les adresses IP privées du RFC 1918 : ells peuvent être utilisées entre routeurs, mais uniquement dans le même domaine.
  • J'indique aussi dans les exemples ci-dessous si les adresses tirées de ce préfixe sont uniques au niveau mondial ou pas.

Évidemment, si les adresses IP d'un préfixe n'ont pas le droit d'être présentes en destination, les deux booléens suivants (transmissible par un routeur, et transmissible à d'autres domaines) n'ont pas de sens.

Voici quelques exemples de ces préfixes spéciaux (en mélangeant IPv4 et IPv6 qui, en pratique, sont dans deux registres) :

  • 0.0.0.0/8 : désigne ce réseau local. Décrit dans la section 3.2.1.3 du RFC 1122. Peut apparaître en source, pas en destination.
  • 10.0.0.0/8 : adressage privé. Décrit dans le RFC 1918. Peut apparaitre en source et en destination, transmissible par les routeurs, pas d'unicité mondiale.
  • 2001:10::/28 : préfixe dit « ORCHID » (Overlay Routable Cryptographic Hash Identifiers), utilisé pour des adressages sécurisés avec adresse dépendant d'une clé cryptographique. Décrit dans le RFC 4843. Ne peut apparaitre ni en source, ni en destination (il n'est pas prévu de les mettre directement dans les champs Source et Destination des paquets IPv6). Non transmissible par les routeurs, pas d'unicité mondiale (mais une quasi-unicité due à leur choix imprévisible dans un espace très large).
  • 100.64.0.0/10 : partage d'adresses en CGN. Décrit dans le RFC 6598. Peut apparaitre en source et en destination, transmissible par les routeurs, pas d'unicité mondiale.
  • 169.254.0.0/16 : adresses locales au lien, typiquement auto-attribuées. Décrit dans le RFC 3927. Peut apparaitre en source et en destination, non transmissible par les routeurs (locales au lien...), pas d'unicité mondiale.
  • fc0::/7 : ULA. Décrit dans le RFC 4193. Peut apparaitre en source et en destination, transmissible par les routeurs, pas d'unicité mondiale (il avait été prévu un registre mondial pour une partie de l'espace des ULA mais cela ne s'était jamais concrétisé).
  • 2001:0002::/48 ou 198.18.0.0/15 : adresses réservées pour les mesures en laboratoire. Décrit dans le RFC 2544 ou le RFC 5180. Peut apparaitre en source et en destination, transmissible par les routeurs, pas d'unicité mondiale.
  • 198.51.100.0/24 (et deux autres en IPv4) ou 2001:db8::/32 : adresses réservées à la documentation. Décrit dans le RFC 5737 ou le RFC 3849. Ne peut apparaitre ni en source, ni en destination. Non transmissible par les routeurs, pas d'unicité mondiale. Notez que, en IPv6, ces adresses pourraient être quasi-uniques si elles étaient choisies au hasard dans l'espace immense du 2001:db8::/32. Mais, en pratique, tout le monde prend la première, 2001:db8::1.

Téléchargez le RFC 6890


L'article seul

RFC 6888: Common requirements for Carrier Grade NATs (CGNs)

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Perreault (Viagenie), I. Yamagata, S. Miyakawa (NTT Communications), A. Nakagawa (Japan Internet Exchange (JPIX)), H. Ashida (IS Consulting G.K.)
Réalisé dans le cadre du groupe de travail IETF behave
Première rédaction de cet article le 1 mai 2013


Qu'on les approuve (ce qui n'est pas mon cas) ou pas, les CGN, ces gros routeurs NAT installés dans le réseau du FAI et gérant des centaines ou des milliers de clients, sont d'ores et déjà une réalité douloureuse dans de nombreux pays d'Asie, pour les pauvres utilisateurs de la 3G, et peut-être demain sur d'autres continents pour les accès fixes. Pour limiter les dégâts qu'ils causent, ce RFC 6888 pose un certain nombre de règles que devraient respecter ces CGN.

D'abord, qu'est-ce qu'un CGN ? Fonctionnellement, il ressemble au petit routeur NAT (RFC 2663) que vous avez chez vous. Comme lui, il fait du NAPT (Network Address and Port Translation), c'est-à-dire qu'il traduit dynamiquement des adresses IP du réseau interne vers celles utilisées à l'extérieur (et vice-versa pour les paquets dans l'autre sens). La grosse différence avec le petit routeur ou box chez vous est qu'il travaille pour de nombreux clients du FAI. Au lieu que l'adresse IP externe soit partagée uniquement entre les membres de votre cercle de famille, elle sera partagée avec des centaines d'inconnus.

Avec le CGN, il y a souvent « double NAT », une fois dans le CPE et une fois dans le CGN. Mais ce n'est pas obligatoire. Lorsqu'il y a double NAT, on parle souvent de NAT444 (deux traductions, d'IPv4 en IPv4).

Sur cette image, on voit du double NAT. Un FAI gère un CGN. cgn Les adresses IP publiques du FAI, allouées par son RIR sont ici 198.51.100.0/25. Ce sont celles qui seront vues, par exemple, par les sites Web où se connectent les clients du FAI. Le FAI n'a pas assez d'adresses IP publiques pour son réseau interne et il utilise donc le 10.0.0.0/8 du RFC 1918. Prenons maintenant le client 1 : son réseau local a des adresses dans la plage 192.168.3.0/24. Les paquets seront donc émis avec ces adresses, NATés une première fois par la machine CPE 1, vers l'adresse 10.0.5.22. Ils seront ensuite NATés une seconde fois par le CGN.

Le CGN a des conséquences, par exemple dans le domaine légal (en théorie, vous pourrez voir les agents de la HADOPI débarquer chez vous parce qu'un autre utilisateur du même CGN a téléchargé illégalement, cf. RFC 6269). Et cela limite sérieusement les activités que vous pourrez avoir sur l'Internet. Par exemple, un moyen courant d'accepter les connexions entrantes, normalement interdites par le NAPT, est de configurer sa box pour rediriger tel numéro de port vers tel service sur le réseau local (par exemple pour faire fonctionner des applications pair-à-pair). Le routeur CGN étant partagé entre de nombreuses personnes qui ne se connaissent pas, cela n'est plus possible. Contrairement au routeur NAT à la maison, le CGN n'est pas géré par les abonnés, qui ne peuvent pas modifier sa configuration.

D'autre part, la simple taille du CGN en fait un engin compliqué et fragile, et sa panne affecte bien plus de clients que le redémarrage d'une box. Enfin, ayant moins de ports sources à sa disposition par client, par rapport au routeur de la maison ou du SOHO, il risque plus souvent de tomber à cours, si les clients font beaucoup de connexions sortantes.

Mais, alors, pourquoi met-on des CGN ? Juste pour embêter les clients ? En fait, les FAI n'ont pas forcément beaucoup le choix. La pénurie d'adresses IPv4, bien que niée par beaucoup de négationnistes, est réelle depuis de nombreuses années. Par exemple, cela fait longtemps qu'on ne peut plus avoir une adresse IP par machine à la maison. Mais, jusqu'à récemment, on pouvait encore avoir une adresse IP publique par foyer. Désormais, l'espace d'adressage IPv4 disponible se resserrant chaque jour, ce n'est même plus le cas. S'il n'y a pas d'adresse IPv4 publique disponible pour chaque client, le CGN est la seule solution pour pouvoir continuer à faire de l'IPv4 (passer à IPv6 ferait moins de travail mais les acteurs du marché sont frileux).

Cela, c'était la raison avouable pour mettre des CGN. Il y en a une moins avouable, c'est que le CGN, grosse machine centrale et point de passage obligatoire pour tous les abonnés, est bien en phase avec la mentalité des opérateurs telco traditionnels. C'est ainsi que, dans l'Internet mobile où les libertés sont bien plus limitées, et l'utilisateur bien plus restreint dans ce qu'il a le droit de faire, tous les opérateurs 3G ont déployé cette solution depuis longtemps, refusant de donner une adresse IPv4 publique à chaque abonné, même avant l'épuisement complet des réserves. Comme le note prudemment le RFC, « there are driving forces other than the shortage of IPv4 addresses ».

À noter qu'un RFC décrit le déploiement de CGN comme une des techniques pouvant aider à la transition vers IPv6 : RFC 6264. Le CGN est un des composants de la solution DS-Lite, décrite dans le RFC 6333 et ce composant doit donc suivre les règles données plus loin.

Maintenant qu'on a présenté les CGN, que contient ce RFC ? Il liste des conseils qui, s'ils étaient appliqués, rendraient les CGN un peu moins insupportables. Comme le note la section 1, la publication de ce RFC ne signifie pas que l'IETF approuve ou même accepte les CGN, simplement que, puisqu'ils existent, autant essayer de limiter leurs effets négatifs. Comme un CGN est un routeur NAT, les précédents documents du groupe de travail Behave, concernant tous les types de NAT, s'appliquent aussi au CGN : RFC 4787, RFC 5382 et RFC 5508 notamment.

Les section 3 à 5 représentent donc le cœur de ce RFC. Elles contiennent les recommandations spécifiques pour les CGN. Chacune est nommée REQ-n où n est un numéro d'ordre. Ainsi, REQ-1 dit que, pour chaque protocole de transport, le CGN doit suivre les recommandations spécifiques à ce protocole (RFC 4787 pour UDP, RFC 5382 pour TCP, RFC 5508 pour ICMP, et RFC 5597 pour DCCP). Notons que les autres protocoles de transport (comme SCTP) ont donc de sérieuses chances de ne pas fonctionner au travers du CGN.

Exigence suivante, REQ-2, qui dit que le comportement de l'IP address pooling doit être paired. Cela signifie quoi ? Qu'une machine donnée doit toujours obtenir la même adresse IP externe (un CGN, contrairement au petit routeur NAT de la maison, a en général plusieurs adresses IP externes à sa disposition). Cela limite les risques de casser les applications. Le RFC 4787, section 4.1, donne les détails sur ce concept de paired.

À propos du nombre d'adresses externes disponible pour le CGN : REQ-3 exige que ces adresses puissent être en nombre quelconque et dans des plages non-contigües (avec l'épuisement des adresses IPv4, il sera de plus en plus dur de trouver des plages contigües).

REQ-4 traite un problème spécifique aux CGN, que n'avaient pas les petits routeurs NAT de la maison : il faut pouvoir limiter le nombre de ports utilisables par un utilisateur donné. Dans le NAPT, il y a moins d'adresses externes que d'adresses internes. On se sert donc des ports pour désambigüiser. Un seul utilisateur gourmand pourrait lancer plein de sessions et épuiser à lui seul la plage de ports disponibles (cela peut même être volontaire, pour faire un déni de service, cf. section 8). C'est pour se protéger contre cette attaque que REQ-4 exige une limitation, configurable, par client. Le RFC recommande aussi qu'on puisse limiter le rythme de création de sessions par utilisateur. C'est nécessaire pour protéger les autres utilisateurs, mais c'est un bon exemple des inconvénients du CGN, qui casse sérieusement la transparence du réseau et le principe de bout en bout. Les routeurs NAT cassaient ces principes mais uniquement entre membres d'un même foyer ou d'un même SOHO. Avec le CGN, on dépend de gens dont on ne connait rien.

Même chose avec REQ-5, consacrée à d'autres ressources partagées dans le CGN, comme sa mémoire. Un CGN a des problèmes d'équité que n'ont pas les routeurs NAT classiques, vue son utilisation entre personnes qui n'ont rien en commun a priori.

Parfois, les cibles que vise l'utilisateur sont situées dans le réseau du FAI, et donc atteignables sans traduction d'adresse. Pour ce cas, REQ-6 demande que le CGN puisse être configuré pour ne pas traduire si la destination est dans une liste d'adresses configurées par l'administrateur réseaux.

Lorsqu'un routeur NAT accepte des paquets entrants du moment qu'il a, dans sa table des traductions, une entrée pour ce couple {adresse,port} de destination, indépendemment de l'adresse IP source d'émission, on dit qu'il fait du Endpoint-Independent Filtering (RFC 4787, section 5). REQ-7 souhaite que ce soit le comportement du CGN, car il casse moins d'applications (notamment jeux en ligne et pair-à-pair) que le Address-Dependent Filtering (où les paquets sont refusés si l'adresse source n'est pas celle dans l'entrée de la table).

REQ-8 légifère sur la réutilisation d'un port externe lorsqu'il n'est plus utilisé. Par défaut, il devrait rester réservé pendant deux minutes, le Maximum Segment Lifetime de TCP (RFC 793, section 3.3), après lequel on est sûr que le paquet ne traîne plus dans le réseau. Cela permet d'éviter une collision entre une ancienne correspondance et une nouvelle, qui utiliserait le même port externe et recevrait par erreur de vieux paquets. Des exceptions sont prévues, notamment :

  • Si le CGN met en œuvre la machine à états de TCP, il peut savoir quand une connexion est terminée et réutiliser alors tout de suite le port,
  • Si certains ports sont statiquement affectés, ils restent utilisables en permanence.

REQ-9 est plus ambitieux car il exige quelque chose qui n'existe pas dans les CGN actuels : un mécanisme permettant à l'utilisateur de changer les affectations de port, et que ce mécanisme soit de préférence PCP (Port Control Protocol, RFC 6887). Aujourd'hui, sur les petits routeurs NAT de la maison ou du SOHO, ce mécanisme d'affectation manuelle des correspondances {adresse externe, port externe} -> {adresse interne, port interne} est typiquement fait par l'interface Web d'administration du routeur, ou bien par UPnP. La disparition d'un tel mécanisme dans les CGN actuels est un des plus gros problèmes que posent les CGN. Il était donc nécessaire de le rétablir, pour que toutes les applications puissent bien fonctionner. Mais PCP est encore très récent et peu déployé.

REQ-10 concerne plutôt les besoins de l'opérateur plus que ceux des simples utilisateurs : il demande que les routeurs CGN soient gérables (MIB du RFC 4008, etc).

Une autre exigence, REQ-11 concerne le traitement des erreurs. Si un routeur CGN ne peut pas créer une corrrespondance entre adresse+port externe et interne, il doit jeter le paquet et devrait renvoyer un message ICMP Destination unreachable / code 1 (Host unreachable). et déclencher une trap SNMP. Le « devrait » (et pas « doit ») est parce que ces deux types de messages peuvent légitimement avoir un débit limité.

Pourquoi Host unreachable et pas Communication administratively prohibited comme c'était le cas dans le RFC 5508, section 6 ? Parce que le code 1 (Host unreachable) est une erreur « douce » (cf. RFC 1122) et ne coupera pas les connexions TCP en cours entre les mêmes machines (RFC 5461).

En outre, le RFC interdit de supprimer des entrées existantes dans la table de correspondances, ce qui permettrait pourtant de faire de la place pour de nouvelles connexions. C'est parce que la plupart des applications gèrent beaucoup mieux une impossibilté à établir une connexion qu'une perturbation ou une interruption d'une connexion en cours (RFC 5508, section 6).

Un bon routeur CGN devrait pouvoir journaliser son activité. La section 4 encadre cette tâche. La principale question qui se pose est l'identification des clients, si une adresse IP externe est repérée pour son comportement abusif (envoi de spam, écriture d'un commentaire de blog défavorable aux autorités, partage de fichiers musicaux, et autres crimes). Le site distant va noter que « 192.0.2.42 a fait quelque chose de mal » et les enquêteurs vont chercher la personne qui est derrière cette adresse. En raison du CGN, des dizaines ou des centaines de personnes peuvent avoir utilisé cette adresse. Pour que l'enquêteur ait la moindre chance de retrouver le coupable, il faut que le site distant journalise, non seulement l'adresse IP source (comme c'est typiquement le cas aujourd'hui), mais aussi le port source (cf. RFC 6302). Et il faut que le routeur CGN ait journalisé ses correspondances, protocole de transport, adresse+port internes, adresse+port externes et heure exacte. (C'est une obligation légale dans certains pays, par exemple en France avec la LCEN.)

Non seulement c'est très Big Brother comme comportement mais, en plus, cela peut rapidement produire une énorme quantité de données, ce qui ne va pas faciliter la tâche de l'opérateur. C'est pour cela que REQ-12 demande que ce ne soit pas activé par défaut, à la fois pour préserver la vie privée des utilisateurs et pour éviter de remplir les disques durs. (Notez aussi que le RFC ne conseille pas de loguer l'adresse IP de destination, ce qui serait bien pire.)

Et, au fait, comment allouer aux utilisateurs cette ressource limitée, les numéros de ports externes ? La section 5 formule trois exigences. Le problème est que les trois sont contradictoires. REQ-13 dit qu'il faudrait chercher à maximiser l'utilisation des ports (ils sont en nombre limités, 65 536 par adresse IP), REQ-14 (qui a suscité beaucoup de discussions dans le groupe de travail) qu'il faudrait minimiser le nombre d'entrées produites dans le journal, par exemple en allouant toute une plage de ports par adresse IP, et REQ-15 que, pour des raisons de sécurité, il faudrait rendre difficile pour un attaquant la prédiction des ports sélectionnés (RFC 6056). Pas de miracle, ces trois exigences ne peuvent pas être satisfaites simultanément et un routeur CGN doit donc choisir lequel est le plus important pour lui. J'emprunte à Simon Perreault une description de la situation en mai 2013 : « Le CGN de Cisco allouait les ports 100 % dynamiquement, comme un NAT traditionnel, et génèrait donc beaucoup de logs. Mais ceux d'autres vendeurs, dont Alcatel, Juniper et Huawei, [ainsi que Cisco désormais, note de Nicolas Février] allouent les ports en bloc, ce qui génère beaucoup moins de logs au prix d'une légère perte de taux d'utilisation des adresses IPv4 externes. Il y a aussi le deterministic NAT qui alloue les ports statiquement tout en conservant une plage d'allocation dynamique pour les débordements. »

Merci à André Sintzoff pour la relecture technique et la détection d'une grosse faute technique. Merci à Nicolas Février pour ses utiles commentaires, même s'il n'est pas d'accord avec moi sur les défauts du CGN.


Téléchargez le RFC 6888


L'article seul

RFC 6887: Port Control Protocol (PCP)

Date de publication du RFC : Avril 2013
Auteur(s) du RFC : D. Wing (Cisco), S. Cheshire (Apple), M. Boucadair (France Telecom), R. Penno (Cisco), P. Selkirk (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pcp
Première rédaction de cet article le 1 mai 2013


Aujourd'hui, l'utilisateur de l'Internet ne bénéficie que rarement d'une connexion neutre, d'un simple tuyau le connectant à toutes les autres machines de l'Internet. La plupart du temps, il est au contraire bloqué derrière des engins comme les routeurs NAT ou les pare-feux. Par défaut, ces engins bloquent les connexions entrantes, limitant l'utilisateur à un usage type Minitel. Dans ce cas, on a souvent besoin de dire à l'engin sur le trajet « laisse entrer des connexions vers tel port » (par exemple pour le pair à pair). Cela se fait aujourd'hui en général par une interface spécifique (par exemple une page Web d'administration du routeur NAT) ou par le protocole privé UPnP. Il y avait donc une demande pour un protocole standard, adapté aux mécanismes d'aujourd'hui comme les CGN : c'est ce nouveau protocole, PCP (Port Control Protocol).

Voici un exemple de configuration manuelle comme on fait souvent aujourd'hui, via une interface Web, ici celle d'une Freebox : freebox-config-ports.jpg Avec PCP, ces interfaces vont-elles disparaître complètement ?

Le principe est simple : un serveur PCP tourne sur l'engin bloquant (routeur NAT ou pare-feu) et autorise des clients PCP à lui parler et à demander des services comme l'ouverture d'un port entrant, ou comme une durée de vie plus longue pour les sessions en cours. Redonnant du contrôle à la machine de l'utilisateur, il rétablit un peu de neutralité dans le réseau. Avec PCP, on a un moyen propre de gérer un serveur (acceptant des connexions entrantes) derrière un routeur NAT et même derrière un CGN. Rappelez-vous qu'accepter des connexions entrantes n'est pas seulement utile si on a un serveur Web à la maison, c'est également une fonction demandée par les protocoles de voix sur IP comme SIP ou bien par le pair-à-pair.

Une fois que le client PCP a obtenu une réponse positive du serveur PCP (« OK, j'envoie les connexions entrantes sur le port 8080 à 172.19.1.1, port 80, comme tu me l'as demandé »), il peut alors prévenir le reste du monde. Cette information sur le rendez-vous n'est pas gérée par PCP : on se sert de fonctions spécifiques au protocole (SIP REGISTER auprès du mandataire, pour SIP, par exemple), ou bien du DNS (éventuellement avec mise à jour dynamique du RFC 2136 pour cela). Les enregistrements SRV du DNS (RFC 2782) sont la solution idéale, puisqu'ils permettent d'indiquer le numéro de port.

On notera que PCP diminue le besoin d'ALG dans les engins intermédiaires. Une nouvelle application n'aura pas besoin d'attendre que des ALG apparaissent, elle pourra contrôler les connexions dont elle a besoin elle-même, via PCP.

Même si on n'accepte pas de connexions entrantes, qu'on est un pur client, PCP peut être utile. Les routeurs NAT et les pare-feux coupent typiquement la session au bout de N minutes d'inactivité. Pour empêcher cela, les applications qui doivent rester connectées longtemps (SSH, par exemple), envoient régulièrement des paquets keepalive. Avec PCP, ce n'est plus nécessaire, l'application peut dire au serveur PCP « augmente N, s'il te plait ».

PCP est conçu, au contraire d'UPnP, pour une large gamme de besoins : du NAT traditionnel (RFC 3022), au NAPT commun aujourd'hui dans les boxes (cf. RFC 3022, section 2.2), en passant par le CGN (RFC 6888) et des choses plus exotiques comme DS-Lite (RFC 6333 et RFC 6619), NAT64 (RFC 6146), et même NAT66/NPT (RFC 6296).

PCP est prévu pour fonctionner avec les protocoles de transport qui ont la notion de port (UDP, TCP, SCTP, DCCP, etc). Pour les autres (ICMP, RSVP, ESP...), PCP ne fournit que des services partiels.

Autre limitation : PCP suppose que la machine de M. Toutlemonde n'a qu'une seule connexion à l'Internet, passant par l'équipement qui héberge le serveur PCP. Le but est de garantir que l'équipement qui répond en PCP verra bien passer tous les paquets. Ce modèle convient à la maison ou à la petite entreprise actuelle, avec son réseau local connecté via une unique box. Le dessin 1 en section 4 du RFC illustre ce modèle.

Les sections suivantes fournissent les détails du protocole. Celui-ci manipulant souvent des adresses IP, la représentation de celles-ci (section 5) va servir souvent : PCP utilise systématiquement un champ de taille fixe de 128 bits (même pour des adresses IPv4, qui sont alors représentées préfixées du ::ffff:0:0/96), car c'est plus simple.

Une description de haut niveau du protocole est en section 6. À première vue, PCP pourrait être traité comme un protocole requête/réponse (un peu comme le DNS) mais, en fait, comme il n'est pas synchrone (on peut envoyer plusieurs requêtes à la suite et lire ensuite plusieurs réponses), il vaut peut-être mieux le considérer comme un protocole suggestion/notification. Le client PCP fait des suggestions au routeur ou au pare-feu (qui sont donc libres de refuser) et le serveur PCP (le routeur ou pare-feu) envoie des notifications indiquant son état. Dans ce modèle, il y a donc deux flux de données indépendants, un du client PCP vers le serveur et un du serveur PCP vers le client. Bien sûr, l'envoi d'une notification est en général corrélé à une suggestion (elle indique indirectement l'acceptation de la suggestion) mais, je le répète, ce n'est pas synchrone. (Une des raisons de ce choix est de permettre au serveur de résister aux attaques par déni de service en ignorant les suggestions lorsque la charge est trop élevée, laissant le client ré-émettre si nécessaire.) PCP tourne sur UDP (ports 5350 et 5351) et n'a pas de notion de transaction (les messages ne portent pas d'identificateur de transaction.) La notification donne l'état actuel du routeur ou pare-feu. Si le client tient à savoir à quelle suggestion est liée telle notification, il doit examiner le contenu du message et le corréler aux suggestions qu'il a envoyées.

La section 7 indique le format standard de tous les paquets : un numéro de version (aujourd'hui 2), un bit indiquant s'il s'agit d'une question ou d'une réponse, un code indiquant l'opération (la plus importante est sans doute MAP, décrite en section 11), l'adresse IP du client PCP, la durée de vie demandée ou obtenue (pour certaines opérations) et quelques autres informations, qui dépendent de l'opération. Parmi elles, les options, encodées en TLV et enregistrées dans un registre IANA.

Les réponses ont un champ indiquant le code de retour d'une requête. 0 est un succès, tous les autres codes indiquent une erreur. Par exemple, 2 est la réponse à une requête non autorisée (rappelez-vous que le serveur PCP a sa propre politique et n'obéit pas aveuglément à tout ce que demande le client), 3 la réponse à une requête syntaxiquement incorrecte, etc. Ces deux erreurs sont permanentes (renvoyer le même paquet PCP ne changera rien). Mais il existe aussi des erreurs temporaires comme 8 qui indique que le serveur PCP aurait bien voulu répondre favorablement mais qu'il manque de ressources (par exemple de ports libres) pour cela. Ré-essayer automatiquement, après un délai raisonnable, peut donc être une bonne solution.

Le fonctionnement de base de PCP figure en section 8. Le client PCP doit d'abord trouver le serveur. Il a pu le connaître par configuration statique, ou tout simplement l'apprendre via une option DHCP (RFC 7291). Sinon, il tente le routeur par défaut, qui sera en général le serveur PCP. Le client va ensuite générer un message, où l'adresse IP du client est sa propre adresse IP (qui sera souvent une adresse privée, du RFC 1918). La section 16.4 explique comment connaître cette adresse grâce à getsockname(). Le client doit être prêt à retransmettre (section 8.1.1 pour les détails) : UDP ne garantit pas l'acheminement.

Le serveur reçoit la requête, vérifie qu'elle arrive sur la bonne interface (le CPE typique de M. Toutlemonde, par exemple, n'acceptera pas les requêtes PCP venant de l'Internet, uniquement celles venant du réseau local), vérifie que l'adresse du client dans le paquet correspond à l'adresse IP source (autrement, c'est qu'un NAT supplémentaire se trouvait accidentellement sur le chemin) et répond. Il inclus dans la réponse un champ Epoch qui est un compteur s'incrémentant une fois par seconde. Si le client voit ce compteur diminuer, cela indiquera que le routeur a probablement redémarré, et donc perdu toutes les correspondances enregistrées, qu'il va falloir re-créer.

C'est quoi, ces « correspondances » (mappings dans la langue de George Martin) ? Le routeur NAT maintient une table des correspondances entre un couple {adresse IP interne, port interne} et un couple {adresse IP externe, port externe}. Cette table est en partie remplie automatiquement lors des connexions sortantes mais peut aussi être partiellement gérée par PCP. Par exemple, le fonctionnement classique du NAT d'un petit routeur à la maison, lorsqu'un paquet venant de {192.168.10.10, 5623} sort, est de réserver un port pour cette session (mettons le port 7891) et de mémoriser une correspondance {203.0.113.254, 7891} <=> {192.168.10.10, 5623} (on suppose que l'adresse IPv4 externe du routeur est 203.0.113.254). Avec cette correspondance en tête, le paquet de réponse destiné à {203.0.113.254, 7891} sera automatiquement NATé et dirigé vers {192.168.10.10, 5623}. PCP permet de manipuler de telles correspondances et, par exemple, pour reprendre un exemple donné plus haut, de dire « envoie les connexions entrantes sur le port 8080 à 192.168.10.1, port 80 », ce qui se traduira par la création d'une correspondance (mapping) {203.0.113.254, 8080} <=> {192.168.10.11, 80}. On notera que le client PCP n'a pas indiqué l'adresse externe 203.0.113.254. PCP permet de le faire mais, dans le cas le plus courant, le client PCP ne connait pas cette adresse et laisse le serveur la choisir.

La section 10 résume les opérations les plus importantes de PCP, MAP (détaillée en section 11) et PEER (détaillée en section 12). MAP permet de créer les correspondances statiques, pour gérer un serveur, PEER permet notamment de manipuler les correspondances dynamiques, celles crées automatiquement par le routeur NAT. La liste de toutes les opérations est dans un registre IANA (cf. section 19.2, sur la politique d'affectation des codes numériques correspondants.)

Prenons l'exemple d'un serveur du réseau local (comme {192.168.10.11, 80} dans mon exemple), qui va appeler MAP pour « ouvrir » le routeur ou pare-feu aux connexions entrantes. En pseudo-code :

/* Les variables précédées de & sont des pointeurs, pour pouvoir
écrire un résultat dans la variable. */
externalport = 80;
pcp_send_map_request(myport, myaddr, &externalport, &externaladdr,
                requestedlifetime, &assignedlifetime);

if (!pcp_response_received())
      panic("No answer"); 
}
else {
    /* Éventuellement mettre à jour le DNS, un serveur de rendez-vous,
    pour dire au reste du monde qu'il peut y aller */
}

/* La suite est le code habituel, sans PCP */
if (received_incoming_connection_or_packet())
            process_it(s);

Si l'application se moque du port externe attribué, il suffit de ne pas l'indiquer dans la requête et de regarder dans la réponse quel port a été alloué. De toute façon, le routeur ne lui allouera pas forcément le port demandé. Par exemple, pour un CGN, tout le monde voudra sans doute s'allouer le port 80, ce qui n'est pas possible. Soit le CGN le refusera à tous, soit il le donnera au premier arrivé et allouera un autre port pour les suivants. Un client PCP bien fait doit donc être préparé : il doit lire le port effectivement attribué et réagir intelligemment s'il n'a pas eu le port souhaité (ce n'est pas fait dans le programme d'exemple ci-dessus). Bien sûr, le client PCP doit aussi être prêt à ce que sa requête soit complètement rejetée, par exemple parce que la table des correspondances a une taille fixe et que ladite table est pleine.

La lecture de la réponse permet aussi au client PCP de savoir quelle est l'adresse externe allouée, ce qui peut être pratique. (Si on n'est intéressé que par cela, il suffit donc de créer une correspondance avec une très courte durée de vie et de lire la réponse.)

La réponse PCP inclut la durée de vie de la correspondance (champ Lifetime du paquet, variable assignedlifetime du programme plus haut). C'est la responsabilité du client de renouveller la correspondance avant qu'elle n'expire (cf. section 15).

Si l'application ne sait pas si elle est derrière un routeur NAT ou un pare-feu, ce qui est fréquent, la solution recommandée est quand même d'essayer PCP. S'il n'y a pas de réponse, cela peut vouloir dire que la machine a une connectivité complète (sans NAT) ou malheureusement que le routeur ne gère pas PCP. (Le code plus haut suppose que l'absence de réponse indique qu'on n'a pas de connectivité en tant que serveur, donc panic().)

Le routeur doit créer des correspondances ayant la sémantique Endpoint Independent Filtering, ce qui veut dire que cette correspondance sera la même quelle que soit l'adresse IP de la machine distante. Il va devoir aussi se débrouiller pour que les messages ICMP correspondant à cette correspondance soient bien acheminés à la machine.

Outre les champs génériques communs à tous les paquets PCP, MAP a quelques champs qui lui sont propres notamment le port interne (la variable myport dans le pseudo-code), le port externe suggéré (la variable externalport dans le programme en pseudo-code) et l'adresse IP externe suggérée (rappelez-vous que le petit routeur NAT de la maison n'a pas le choix : il n'a en général qu'une seule adresse IPv4 externe, donc il ignorera ce paramètre). Dans la réponse à un MAP, la valeur de ces champs indiquera au client ce que le serveur PCP a finalement choisi (pas forcément ce qui était demandé). Une option de la requête permet de dire si les adresses et ports suggérés sont impératifs (on préfère un échec plutôt qu'une correspondance avec d'autres valeurs que celles demandées) ou pas (cf. section 13.2).

MAP permet aussi de contrôler un pare-feu, avec son option FILTER (section 13.3) où on décrit les adresses IP et ports autorisés, le reste étant bloqué. Séparer la fonction de NAT de celle de pare-feu est essentiel : actuellement, les routeurs NAT typiques mélangent les deux, ce qui a mené certaines personnes à croire que le NAT avait un rôle de protection. Outre la sécurité, FILTER peut être utile pour des machines sur batterie : elles éviteront ainsi de gaspiller du courant à traiter des paquets non désirés.

PCP est également utile au cas où on n'a certes besoin que de connexions sortantes mais où on veut influencer des paramètres comme la durée de vie des correspondances créées automatiquement, de manière à ne pas avoir besoin d'envoyer de temps en temps des paquets keepalive. On utilise pour cela l'opération PEER. Cette opération a à peu près les mêmes champs que MAP mais les correspondances crées peuvent avoir des sémantiques autres que Endpoint Independent Filtering. (MAP a le code 1 et PEER 2, dans le registre IANA.)

Un autre usage de l'opération PEER est pour re-créer des correspondances perdues. Un des plus gros inconvénients du NAT est qu'il maintient un état dans le routeur. Normalement, l'Internet est un réseau de paquets, les routeurs intermédiaires font passer les paquets mais n'ont aucune notion de session associées, il font passer du TCP, de l'UDP ou n'importe quel autre protocole sans faire de différence. Un des avantages de ce principe est que le redémarrage d'un routeur ne change rien : les connexions TCP, par exemple, continueront comme si rien ne s'était passé, l'état des connexions étant entièrement contenu dans les machines terminales. Le NAT change tout cela : si un routeur NAT redémarre, toutes les correspondances sont perdues. Si les machines tentent de continuer la communication, de nouvelles correspondances seront créées, avec de nouveaux numéros de port, et ce changement cassera les connexions TCP en cours. C'est notamment insupportable pour SSH.

Comment PCP peut-il aider ? Une machine qui connait la liste des correspondances (elle a pu l'apprendre avec l'opération PEER) peut, lorsqu'elle détecte un redémarrage du routeur, lui renvoyer cette liste (toujours avec PEER mais, cette fois, en remplissant les champs Suggested Address et Suggested Port), rétablissant ainsi la même table des correspondances (section 14). À noter que, pour accélérer la reconstitution de l'état du routeur, un routeur qui sait qu'il va redémarrer peut aussi envoyer des paquets PCP avec l'opération ANNOUNCE (section 14.1.3) pour prévenir les clients. Ces envois se font aux adresses multicast 224.0.0.1:5350 et [ff02::1]:5350 (224.0.0.1 et ff02::1 voulant dire « toutes les machines du réseau »). Les machines clientes peuvent alors savoir qu'elles vont devoir recréer leurs correspondances (après avoir attendu un délai aléatoire, pour éviter qu'elles ne le fassent toutes en même temps).

PEER peut enfin créer une nouvelle correspondance mais cela n'a pas un grand intérêt, puisque tout routeur NAT sait le faire automatiquement au premier paquet d'une nouvelle connexion sortante. (La seule exception est le cas cité plus haut où on restaure l'état d'un routeur NAT qui a redémarré.)

Je ne connais pas l'état actuel de mise en œuvre de PCP dans les routeurs NAT typiques. Pour le programmeur qui veut s'y mettre sérieusement, la section 16 contient un certain nombre de conseils pratiques, aussi bien pour l'écriture de serveurs que pour celle de clients PCP. Quant à la section 17, elle se penche sur les problèmes de déploiement de cette nouvelle technologie. Par exemple, il est important que le routeur rejette les paquets entrants dont l'adresse source ne correspond pas à celles du réseau interne (RFC 2827) pour éviter qu'un méchant n'usurpe une adresse IP.

Tiens, puisqu'on parle de sécurité, la section 18 lui est entièrement consacrée. PCP permet de contrôler plus finement les correspondances dans le routeur, voire de modifier les filtres d'un pare-feu. Il est donc essentiel que ces nouvelles possibilités ne se fassent pas au détriment de la sécurité. Par exemple, une machine du réseau interne autorisée à créer ou modifier des correspondances peut voler le trafic d'une autre. Ce n'est pas très grave pour un réseau local à la maison mais bien plus embêtant dans le cas d'un grand CGN.

PCP, s'il est correctement mis en œuvre, est protégé contre les attaquants situés en dehors du chemin. Par exemple, si une machine quelque part sur l'Internet envoie un paquet PCP prétendant venir d'une des adresses internes (mettons 192.168.1.1), le routeur/serveur PCP rejettera ce paquet qui arrive par l'interface externe (il ne doit accepter les requêtes PCP que si elles sont internes). Par contre, un attaquant interne a à peu près open bar avec PCP. Un serveur PCP doit donc être déployé uniquement si toutes les machines internes sont considérées comme membres de la même bande (une supposition raisonnable pour un réseau domestique) ou si on peut séparer les clients en plusieurs domaines, empêchant M. Michu de voler le trafic de Mme Toutlemonde, située derrière le même CGN.

Une façon de limiter les risques est que le serveur PCP ne configure explicitement que des correspondances qu'il aurait de toute façon configuré implicitement, lorsqu'une nouvelle connexion sort. Cela veut dire qu'il y a des opérations PCP sûres (créer une correspondance sans spécifier le port et l'adresse externes) et d'autres qui peuvent être dangereuses (créer une correspondance avec un port externe spécifié).

Si on autorise PCP à configurer un pare-feu, il faut évidemment faire encore plus attention. Il n'existe pas à l'heure actuelle de mécanisme de sécurité standard pour PCP : son premier domaine d'application concerne des cas où il n'y a déjà pas de sécurité aujourd'hui. Pour d'autres domaines, il faudra trouver de nouvelles solutions de sécurité.

Quelques autres attaques possibles avec PCP :

  • Risque d'attaque par déni de service contre le serveur PCP, par exemple en créant tellement de correspondances qu'on remplit la table qui les garde en mémoire. Le RFC préconise des limites par machine (du genre, « N correspondances PCP maximum par machine »).
  • Risque, en cas de redémarrage d'un routeur NAT, qu'un attaquant rapide ne re-crée une correspondance, avant la machine qui l'avait créée, volant ainsi le trafic. L'attaquant doit agir vite (avant que la victime n'ait re-créé les correspondances) mais c'est possible.

PCP est le successeur d'un protocole très proche nommé PMP (Port Mapping Protocol, RFC 6886). L'annexe A décrit la coexistence entre les implémentations de PMP qui restent, et PCP. L'autre protocole qui avait été envisagé par le groupe de travail PCP était bien sûr UPnP, mais qui était techniquement moins proche de ce qui était souhaité (non routé, peu sécurisé, peu fiable). PMP utilisant les mêmes ports, des dissecteurs de paquets analysent parfois le PCP sous le nom de PMP.

Aujourd'hui, on trouve très peu de mises en œuvre de PCP déployées. Aucun système d'exploitation n'a de client PCP en série. Une solution possible sera peut-être (suggestion de Gunther Ozerito) de faire un relais UPnP <=> PCP comme décrit dans le RFC 6970. Sinon, Wireshark va bientôt avoir un dissecteur PCP (il vient d'être développé et sera livré avec la future version 1.10 ; un autre, sous forme d'un greffon en Lua, est disponible). Attention, Wireshark a aussi un dissecteur pour un autre PCP (Performance Co-Pilot Protocol).

Et j'ai bien envoyé des paquets PCP à ma Freebox, mais je reçois toujours une triste réponse ICMP port 5351 unreachable d'où je déduis qu'elle n'a pas encore de serveur PCP. (Et elle ne diffuse apparemment rien vers le port 5350.)

Au fait, pour les envoyer, j'ai utilisé ce (très grossier) script Scapy, qui est loin de remplir tous les champs mais permet quelques tests :

from scapy.all import *

# http://www.secdev.org/projects/scapy/doc/build_dissect.html
class PCP(Packet):
       name = "Port Control Protocol"
       fields_desc = [ ByteField("Version", 2),
                       BitField("R", 0, 1), # 0 = Request / 1 = Response
                       BitField('Opcode', 1, 7), # MAP is 1, PEER is 2
                       ShortField("Reserved", 0),
                       IntField("RequestedLifetime", 0),
                       LongField("ClientAddressUpper", 0),
                       LongField("ClientAddressLower", 0)
                       ]

p = IP(dst="192.168.2.254")/UDP(sport=0,dport=5351)/PCP(RequestedLifetime=5000,
                                                ClientAddressLower=232236033)
sr1(p)

Un bon article d'introduction sur PCP est « New Technology Demo: PCP » dans le numéro 7.2 de l'IETF Journal.


Téléchargez le RFC 6887


L'article seul

RFC 6885: Stringprep Revision and PRECIS Problem Statement

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : M. Blanchet (Viagenie), A. Sullivan (Dyn, Inc.)
Pour information
Réalisé dans le cadre du groupe de travail IETF precis
Première rédaction de cet article le 14 mars 2013


Dans bien des protocoles, il y a besoin de comparer deux chaînes de caractères, pour voir si elles sont égales. Par exemple, un protocole d'authentification va comparer un identificateur à ceux enregistrés dans sa base, pour voir s'il est présent. Si les chaînes de caractères sont uniquement en US-ASCII, il n'y a guère de problèmes, à part décider si la comparaison est sensible à la casse. Mais si elles sont en Unicode ce qui, en 2013, est la moindre des choses ? Alors, c'est plus compliqué. Dans ce cas, on décide de préparer les chaînes avant la comparaison, pour les ramener à une forme de référence (en ASCII, un exemple simple de préparation serait de tout mettre en minuscules). Beaucoup de protocoles IETF utilisaient pour cette opération le stringprep du RFC 3454, popularisé par son utilisation dans les noms de domaines internationalisés. Mais la mise à jour de ces noms de domaines, en 2010, a abandonné stringprep (cf. RFC 5890). Dans ces conditions, les autres protocoles se retrouvaient privés d'une référence bien pratique. Le groupe de travail PRECIS a été créé pour étudier la mise en place d'un cadre général de préparation des chaînes Unicode pour tous les protocoles. Ce RFC 6885 est son premier RFC et il décrit le problème, sans proposer encore de solution.

C'est que stringprep avait été un grand succès. Voici une liste incomplète des protocoles qui l'utilisent :

  • NFS version 4 (RFC 5661),
  • le protocole d'authentification EAP (RFC 3748),
  • le protocole de communication XMPP (RFC 6120, profils Nodeprep et Resourceprep, car un identificateur XMPP comme stéphane@dns-oarc.net/Théâtre est légal),
  • les noms dans les certificats X509 (RFC 4683),
  • tous les protocoles qui passent par SASL comme l'authentification SMTP (RFC 4954) ou POP (RFC 5034),
  • le registre des algorithmes de comparaison (RFC 4790), et certains de ses algorithmes (comme celui du RFC 5051),
  • iSCSI (RFC 3722) lorsqu'il s'agit de nommer l'initiateur (la machine) et la cible (le disque),
  • et bien d'autres. Une évaluation très détaillée des différents profils figure dans l'annexe B de ce RFC.

Pour gérer plus facilement ce bestiaire, on peut les regrouper en quelques catégories (voir l'étude de Marc Blanchet), d'autant plus que beaucoup utilisent le même profil SASLprep du RFC 4013. L'annexe A de notre RFC liste ces catégories.

On l'a dit, la motivation immédiate pour le travail du groupe PRECIS était la perte de la référence que constituait les IDN, qui utilisent désormais d'autres méthodes. Puisque, de toute façon, il va falloir remettre à plat cette question de la préparation des identificateurs Unicode, c'était l'occasion de faire un bilan (il a commencé à la réunion IETF 77 dans une Bof nommée « Newprep » dont le compte-rendu est en ligne). La section 4 étudie les profils de stringprep existants et leurs limites :

  • Stringprep est lié à la version 3.2 d'Unicode. Or, plusieurs versions sont sorties depuis et stringprep ne permet pas de les utiliser.
  • Ce point est d'autant plus gênant qu'une application n'a en général pas le choix de la version Unicode : elle utilise ce que le système hôte lui fournit.
  • Les chaînes de caractère à comparer (par exemple les identificateurs) sont souvent passés d'un protocole à l'autre et il serait donc souhaitable d'avoir des règles communes. Notez que, par exemple, XMPP utilise deux profils stringprep différents pour les composants du JID (l'identificateur XMPP) : la ressource, le domaine et la partie locale n'obéissent pas aux mêmes règles. Allez donc expliquer la syntaxe légale d'un JID dans ces conditions !

Bref, c'est sur la base de ce cahier des charges informel qu'a été créé le groupe PRECIS avec l'ambition de servir des protocoles très différents (mais qui ne bénéficiaient pas des compétences d'experts en internationalisation), en s'inspirant (sans forcément le copier aveuglément) de l'IDN bis du RFC 5890 et suivants.

La section 5 de ce RFC est le cahier des charges formel. D'abord, sur la question de la comparaison entre chaînes, un rappel du problème. Il y a trois catégories de chaînes, pour ce qui concerne la comparaison :

  • Les absolues, qu'on compare octet par octet,
  • Les définies, où la comparaison est plus complexe mais est bien définie, par un algorithme standard,
  • Les indéfinies où il n'existe pas de règle standard (il n'y en a heureusement pas d'exemple connu dans les protocoles IETF).

Par exemple, deux chaînes Unicode identiques pour la deuxième catégorie (même séquence de points de code) peuvent ne pas l'être pour la première (par exemple si une est en UTF-8 et l'autre en UTF-32). Mais il peut exister un algorithme pour les comparer (tout convertir en UTF-8 puis comparer les octets). Le tableau en annexe A indique, pour les protocoles existants, à quelle catégorie ils appartiennent.

Ensuite, les caractères eux-même, un problème que la taille du bestiaire Unicode (plus de 100 000 caractères) rend difficile. Commençons par la casse. IDN v1 faisait une comparaison indépendante de la casse en convertissant tout en minuscules. IDN v2 a décidé de n'accepter que les minuscules, une éventuelle conversion des majuscules étant à faire en dehors du cadre IDN (RFC 5892). Le système défini par PRECIS doit donc gérer plusieurs cas, avec ou sans sensibilité à la casse, avec ou sans préservation de la casse.

Ensuite, la canonicalisation. Comme il existe plusieurs chaînes Unicode dont le rendu peut être identique (exemple classique : U+00C8, d'une part, et U+0045 U+0300, d'autre part, vont tous les deux donner É), Unicode prévoit des algorithmes de canonicalisation qui réduisent les chaînes de caractères à une forme canonique, avant la comparaison. La plupart des profils de stringprep se servent de NFKC. Est-ce le bon choix ? Dans tous les cas ? NFC peut être une meilleure idée (au fait, dans l'exemple ci-dessus, la chaîne deviendra U+00C8 avec NFC et avec NFKC).

Autre question délicate à considérer, les caractères interdits. Par exemple, un protocole peut avoir des caractères spéciaux comme @ ou / qu'il faudra interdire dans les identificateurs. Faut-il définir les caractères interdits (et autoriser donc le reste) ou au contraire les caractères permis (et donc interdire tous les autres) ?

Cette question est partiellement liée à la question de l'homographie. Ce RFC reprend la légende (pourtant bien démontée par UTR36) comme quoi les caractères pourraient avoir un rôle dans le hameçonnage. Mais il reconnait qu'il n'y a pas de solution technique à cette question.

Autre question sur les données, d'où viennent-elles ? Sont-elles typiquement saisies par un utilisateur (et, dans ce cas, il faut probablement lui laisser un grand choix de variantes possibles) ou bien sont-elles générées par un programme ? Derrière cette question se trouve la frontière oh combien mouvante entre ce qui relève de l'interface utilisateur et ce qui relève des protocoles (voir le RFC 5895 et aussi, même s'il n'est pas cité, le RFC 2277).

Après l'entrée, la sortie de ces chaînes de caractères soulève aussi des questions. Si les caractères sortent du monde « machine » et sont imprimés, pour se retrouver sur une carte de visite ou sur les flancs d'un autobus, les problèmes de risque de confusion visuelle seront plus aigus.

Et il y a le fait que certaines chaînes de caractères servent d'entrée au processus suivant, condensation cryptographique ou concaténation, par exemple.

Dernier problème à garder en mémoire, le risque de changements incompatibles lors de la sortie d'une nouvelle version d'Unicode. Idéalement, un caractère, une fois déclaré valide pour un protocole donné, devrait le rester éternellement, assurant ainsi la stabilité des identificateurs construits avec ce caractère. Mais Unicode ne fournit pas cette garantie (au passage, c'est pour cela que stringprep était lié à une version particulière d'Unicode). Un caractère peut changer de catégorie et, si sa validité était déterminée algorithmiquement à partir de sa catégorie, il peut passer de valide à invalide. Le cas s'est déjà produit (cf. RFC 6452).

La section 6 est ensuite le relevé des décisions (unanimes) concernant le travail du groupe PRECIS :

  • Accord pour développer un remplaçant pour stringprep, ne gérant qu'Unicode (les autres jeux de caractères sont éliminés).
  • Reprendre le mécanisme d'IDNA bis pour être indépendant de la version d'Unicode, à savoir faire dériver la validité ou nom d'un caractère d'un algorithme utilisant les propriétés Unicode, algorithme qu'il suffira de refaire tourner à chaque nouvelle version d'Unicode.
  • Essayer de définir un petit nombre de profils, chacun pouvant convenir à une grande classe de protocoles.
  • Garder en tête tous les problèmes posés en section 5.

Téléchargez le RFC 6885


L'article seul

RFC 6883: IPv6 Guidance for Internet Content Providers and Application Service Providers

Date de publication du RFC : Mars 2013
Auteur(s) du RFC : B. Carpenter (Univ. of Auckland), S. Jiang (Huawei)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 8 mars 2013


Ce nouveau RFC sur IPv6 ne spécifie pas un protocole réseau mais rassemble simplement un ensemble de conseils pour les gens qui gèrent des serveurs Internet et qui veulent les rendre accessibles en IPv6. Bien sûr, en 2013, tous les serveurs devraient depuis longtemps être ainsi accessibles. Mais le déploiement d'IPv6 a pris du retard et ce RFC est une des nombreuses tentatives pour tenir la main des retardataires qui hésitent encore à traverser le gué.

Pourquoi faut-il une stratégie de déploiement IPv6 ? Pourquoi ne pas tout simplement se dire « Au diable les mines ! En avant toute ! » ? Parce que l'administrateur typique d'un serveur Internet pense à ses utilisateurs et il veut que l'introduction d'IPv6 ne rende pas les choses moins bonnes qu'en IPv4. Certaines techniques de transition et/ou de coexistence entre IPv4 et IPv6 ayant eu des effets négatifs, il est prudent de réfléchir et de ne pas se lancer aveuglément.

Comme indiqué plus haut, ce RFC ne concerne pas le pur utilisateur qui veut se connecter en IPv6, mais le gérant de serveurs, qui est un professionnel de l'hébergement, ou simplement une organisation qui gère ses propres serveurs (serveurs Web ou autres). Il n'est pas écrit pour l'expert IPv6 (qui n'apprendra rien de nouveau) mais pour l'administrateur système/réseaux de l'hébergeur de serveurs.

La stratégie recommandée par le RFC est celle dite de la « double pile » (RFC 6180), qui consiste à avoir à la fois IPv4 et IPv6 sur les serveurs. Comme on ne va pas déployer IPv6 instantanément partout, elle se subdivise en deux approches : de l'extérieur vers l'intérieur (on rend les serveurs externes accessibles en IPv6, peut-être via un relais comme décrit en section 7, puis on migre progressivement l'infrastructure interne) ou bien de l'intérieur vers l'extérieur (on passe l'infrastructure, les serveurs de base de données, les serveurs LDAP, etc, en IPv6, avant de petit à petit ouvrir IPv6 à l'extérieur). La première approche, de l'extérieur vers l'intérieur, a l'avantage qu'un bénéfice visible pour les utilisateurs est immédiat. Elle marche même si certains services internes sont coincés en IPv4 (par exemple une vieille application tournant sur un vieux système, indispensable à votre activité mais qu'on ne peut pas mettre à jour). Certaines organisations se vantent donc d'être accessibles en IPv6 alors qu'à l'intérieur, le déploiement du nouveau protocole est loin d'être achevé.

La deuxième approche, de l'intérieur vers l'extérieur, est surtout intéressante pour les organisations de petite taille (qui contrôlent tous les systèmes internes) ou récentes (qui n'ont plus d'AS/400 en production, et encore puisque même celui-ci a IPv6). Avec cette approche, l'activation d'IPv6 sur les serveurs externes sera simple, tout sera en place avant.

Le fournisseur de services doit aussi se rappeler qu'il ne contrôle pas les clients. Certains resteront en IPv4 pur pendant longtemps, d'autres seront double-pile et on verra sans doute apparaître bientôt des clients purement IPv6. Certains clients (les mobiles, par exemple) passeront même d'IPv4 à IPv6 au cours d'une seule visite sur le site Web.

Bref, le déploiement d'IPv6 nécessitera quelques études préalables, en vérifiant les capacités du logiciel déployé (cf. RFC 6434).

Maintenant, en route vers le déploiement. Première étape suggérée par le RFC, la formation (section 3). Aujourd'hui, rares sont les formations initiales qui mentionnent IPv6 (en France, la situation dans les IUT semble particulièrement mauvaise). C'est donc souvent dans l'entreprise qu'il faudra former les employés aux différences entre IPv4 et IPv6. Il faut surtout éviter le syndrome de l'expert IPv6 isolé. En 2013, tout professionnel IP doit connaître IPv6 aussi bien qu'IPv4. C'est donc la totalité du personnel informaticien qui va devoir progresser. Le RFC dit « everybody who knows about IPv4 needs to know about IPv6, from network architect to help desk responder ».

Le but est d'éviter des résultats ridicules comme ce réseau où, lors du déploiement d'IPv6, les adresses comportant les chiffres hexadécimaux entre A et F étaient soigneusement évitées, de peur de créer de la confusion chez les techniciens ! Évidemment, si on a des techniciens assez arriérés pour ne pas savoir gérer de l'hexadécimal, on a un problème... Autre anecdote embarrassante, cet employé du help desk qui parlait à un client de « one Pv6 » car il avait cru voir un 1 dans IPv6... L'un des buts de la formation est d'éviter ce genre de bavure.

L'approche du RFC est d'éviter de traiter IPv6 à part, par exemple d'avoir une procédure de remontée des problèmes différente pour IPv6, menant vers l'unique gourou IPv6. Plutôt qu'un « service IPv6 » spécialisé, le RFC recommande qu'IPv6 soit simplement traité comme IPv4.

Dernier point délicat sur la formation, le meilleur moment où la faire. Trop tôt, et elle sera oubliée lorsque le déploiement effectif commencera. Il faut donc essayer de la synchroniser avec le déploiement.

Ensuite, il faut obtenir une connectivité IPv6 (section 4). Elle peut être native (directement sur la couche 2, comme en IPv4) ou via un tunnel géré. Historiquement, bien des expérimentations IPv6 ont été faites en se connectant par un tunnel non géré et les résultats (en performances et en fiabilité) ont découragé beaucoup de gens de continuer avec IPv6. Le RFC recommande très fortement de ne pas perdre de temps avec les tunnels et de faire du natif. Toutefois, si on se connecte via un tunnel, cela doit être un tunnel géré (le RFC ne donne pas de noms mais c'est, par exemple, un service qu'Hurricane Electric offre très bien). Les solutions avec des tunnels automatiques, non gérés, comme 6to4 (que le RFC ne cite pas) sont à fuir.

Un tunnel géré a quand même des défauts : les performances seront inférieures, et la MTU réduite va mener à des problèmes pénibles à déboguer. Bref, le fournisseur de services ne devrait pas utiliser autre chose qu'une connexion native avant d'offrir un accès de production à ses services.

Notez que cela ne concerne que le fournisseur : on ne contrôle pas les clients et il faut donc se préparer à ce que certains utilisent des bricolages non fiables comme Teredo (cf. section 9).

Étape suivante (dans le RFC ; dans le déploiement, on peut paralléliser ces tâches), l'infrastructure IPv6 (section 5). D'abord, l'attribution des adresses. Comme en IPv4, on peut utiliser des adresses PI ou PA, selon ses besoins et selon la politique du RIR local. Si on utilise du PA, il faut se préparer à de futures renumérotations et, pour cela, bien relire le RFC 4192. Naturellement, si le fournisseur de service a hébergé ses services dans le cloud, il n'a pas le choix, il devra suivre la politique de l'hébergeur.

Pour gérer les adresses IPv6 locales, on peut utiliser un logiciel spécialisé, un IPAM. Pour distribuer les adresses aux machines, on peut le faire manuellement ou via un programme qui automatise partiellement la gestion du parc, comme Puppet ou Chef. Mais on peut aussi les distribuer par DHCP (RFC 3315). Le RFC suggère DHCP, car il facilitera une éventuelle renumérotation.

Plus exotique est la possibilité de ne pas avoir d'adresses statiques pour les serveurs mais de compter uniquement sur l'auto-configuration sans état d'IPv6 (SLAAC, RFC 4862), combinée avec des mises à jour dynamiques du DNS (RFC 3007). Dans ce cas, ce sont les noms des serveurs qui sont statiques, pas leurs adresses IP. Le RFC note bien que c'est une possibilité théorique mais que personne n'a encore essayé cela pour un grand réseau de production.

Pour la topologie du réseau (physique, via les câbles, ou logique, via les VLAN), le RFC recommande d'avoir la même topologie en IPv4 et IPv6. Ce n'est pas obligatoire mais cela facilitera grandement le déboguage lorsqu'il y aura un problème.

Une fois les adresses attribuées, le routage : tous les protocoles de routage ont la capacité de router IPv6, même RIP (RFC 2080). La méthode la plus courante aujourd'hui est de déployer deux routages parallèles et indépendants, un pour IPv4 et un pour IPv6. Toutefois, deux protocoles de routage, IS-IS (RFC 5308) et OSPF (RFC 5838), ont la capacité de gérer les deux versions de manière intégrée, ce qui peut simplifier la gestion du réseau. (Pour OSPF, c'est encore très peu déployé, la plupart des sites OSPF font tourner deux routages parallèles.) Comme les concepts de routage sont les mêmes en IPv6 et en IPv4, il ne devrait pas y avoir trop de problèmes pour l'équipe qui s'en occupe.

Parmi les points qui risquent d'être différents en IPv6 figurera le cas où un site a plusieurs préfixes PA (un pour chaque fournisseur de connectivité). Il faudra alors soigner le routage pour éviter de faire sortir via le fournisseur A un paquet dont l'adresse source est prise dans le préfixe du fournisseur B : si A met en œuvre les filtrages recommandés par les RFC 2827 et RFC 3704, le paquet sera jeté.

C'est seulement lorsque tout est déployé et testé, au niveau adressage et routage, qu'on pourra envisager d'annoncer les adresses IPv6 des serveurs dans le DNS. Ne faites pas l'erreur d'un gros fournisseur de raccourcisseur d'URL qui avait fait cette annonce alors que son serveur ne marchait pas en IPv6 ! Ou comme l'avait fait Yahoo qui avait mis le AAAA sans configurer Apache.Testez donc d'abord (par exemple avec un nom spécifique comme ipv6.example.com, comme expliqué en section 9). Ensuite, mettez les enregistrements AAAA dans le DNS. Dès qu'ils seront publiés, le trafic arrivera.

Un équipement souvent placé devant les serveurs est le répartiteur de charge (section 6). Comme tous les intermédiaires, ils sont une source importante de problèmes. Après un long retard, la plupart gèrent aujourd'hui IPv6, mais il est important d'insister auprès des fournisseurs de tels équipements pour qu'IPv6 ait le même niveau de performance qu'IPv4.

Le logiciel sur les serveurs, maintenant (section 8). Dans les systèmes d'exploitation, il n'y a guère de problème, tout fonctionne en IPv6 depuis longtemps. C'est le cas des noyaux mais aussi des « grands » logiciels serveurs comme Apache, NSD ou Postfix. Mais les applications spécifiques, c'est une autre histoire, certaines ne sont pas forcément prêtes. Pour les applications client, le fait d'utiliser des noms de domaines au lieu des adresses IP aide beaucoup. Pour les serveurs, il peut y avoir des surprises, par exemple au moment de journaliser la requête, lorqu'on voudra enregistrer l'adresse IP du client. Des tests soigneux seront nécessaires.

Beaucoup de fournisseurs de service géo-localisent leurs utilisateurs. Dans ce cas, les bases de géo-localisation typiques comme GeoIP n'étant pas forcément prêtes pour IPv6, il y aura des problèmes, à moins de passer à une méthode de géolocalisation plus fiable que celle fondée sur l'adresse IP, par exemple avec la technique HELD du RFC 5985.

Lorsque le client change d'adresse IP (ce qui arrive avec les mobiles), il peut même changer de version d'IP. Si les cookies distribués sont liés à une adresse IP, il faudra en tenir compte.

On l'a vu plus haut, le fournisseur de service ne contrôle pas ses clients. Il peut tout à fait arriver que ceux-ci ont choisi des techniques de transition/coexistence entre IPv4 et IPv6 et que celles-ci soient peu fiables (par exemple Teredo). Avec l'approche recommandée dans ce RFC, la double pile, il n'y aura normalement pas de requêtes venant de NAT64 (RFC 6146). Mais on peut imaginer d'autres problèmes, y compris des doubles traductions, de v6 en v4 puis encore en v6, et que le serveur ne peut pas détecter.

Reste le cas des tunnels automatiques comme le 6to4 du RFC 3068. Le RFC 6343 donne plein de bons conseils pour limiter les dégâts. Les deux points importants, du côté du serveur, sont :

  • S'assurer que la détection de la MTU du chemin fonctionne (ce qui veut dire, en pratique, ne pas bloquer bêtement tout ICMP),
  • S'assurer que le serveur gère bien la négociation de la MSS de TCP (RFC 2923).

Mais l'hébergeur a un pouvoir limité : il peut vérifier que les paquets ICMP passent bien sur son réseau mais il ne peut rien garantir quant aux autres réseaux traversés. C'est pour cela que 6to4 est désormais abandonné (RFC 7526).

Certains fournisseurs de service ont donc choisi une approche plus violente en configurant leurs serveurs DNS pour ne pas envoyer les enregistrements AAAA au résolveur si celui-ci est dans un réseau dont on sait qu'il a des problèmes, notamment de PMTUd. Encore plus pessimiste, l'approche inverse où on n'envoie les AAAA qu'aux réseaux dont on sait qu'ils ont une connectivité IPv6 native correcte (Google avait utilisé ce mécanisme au début). Cette solution, décrite dans le RFC 6589, est coûteuse en temps (il faut gérer la liste noire ou la liste blanche) et pas tenable sur le long terme.

Malheureusement, les pouvoirs du fournisseur de service s'arrêtent là. Il ne contrôle pas la chaîne complète jusqu'au client et ne peut donc pas garantir à celui-ci un vécu parfait. La voie la plus prometteuse semble être le déploiement progressif du mécanisme happy eyeballs (globes oculaires heureux) du RFC 6555.

Et si le fournisseur de service utilise des CDN (section 10) ? Cela peut marcher, avec IPv6 comme avec IPv4 si le fournisseur du CDN suit, comme celui du serveur principal, les recommandations de ce RFC. À noter que, le CDN étant géré par une organisation différente de celle qui gère le serveur original, on aura parfois, si le CDN est plus avancé, un contenu partiellement accessible en IPv6 alors que le serveur original n'a pas IPv6. Sinon, parmi les pièges spécifiques aux CDN, la synchronisation. Le contenu à servir est distribué à tous les nœuds du CDN via l'Internet et ce processus n'est pas instantané. Comme le contenu n'est pas forcément servi en IPv4 et en IPv6 par les mêmes machines, un visiteur peut avoir, pendant les périodes où la synchronisation est en cours, un contenu différent selon qu'il y accède en v4 ou en v6.

La section 12 rassemble ensuite une liste hétérogène de problèmes potentiels supplémentaires. Par exemple, comme vu plus haut dans le cas du CDN, un service moderne comprend typiquement plusieurs éléments, parfois hébergés à des endroits différents (pensez à une page Web contenant du JavaScript et du Flash stockés sur les serveurs de Google). Dans ce cas, le service peut être partiellement accessible en IPv6 sans même que son gérant ne s'en rende compte. Si le visiteur a des problèmes de connectivité IPv6, les équipes du fournisseur de service risquent de ne pas comprendre tout de suite ce qui se passe en cas d'« IPv6 involontaire ».

C'est donc l'occasion de rappeler (section 13) que le déploiement d'IPv6 n'est pas juste un coup sans lendemain, qu'on pourrait sous-traiter, en « mode projet » : au contraire, il faut assurer la maintenance et le fonctionnement opérationnel dans le futur. Cela n'a rien d'extraordinaire et ne nécessite pas de compétences surhumaines. Il existe des réseaux et des sites en double pile depuis de nombreuses années. Mais il faut le faire.

Un exemple parmi d'autres : il est important d'assurer la supervision aussi bien en IPv6 qu'en IPv4. Cela concerne bien sûr les réseaux (pinguer les adresses IPv6 comme les adresses IPv4) mais aussi les services (si un service a été accidentellement lancé sans écoute en IPv6, il faut que cela soit détecté). À noter que, avec la plupart (peut-être tous) les logiciels de supervision existants, tester des machines ou des services qui écoutent sur plusieurs adresses IP (que celles-ci soient une adresse v4 et une adresse v6 ou bien plusieurs adresses v4) est souvent un peu pénible et pas vraiment prévu. Par exemple, avec Icinga, il faut mettre explicitement deux tests, un en IPv4 et un en IPv6, le programme de test ne testant qu'une seule des adresses du service. Si on ne fait pas attention, on risque donc de se rassurer en voyant l'écran vert du logiciel de supervision, sans avoir perçu que le service ne marchait plus en IPv6 (ou en v4, selon le cas).

Et la sécurité (section 14) ? Elle est évidemment aussi importante en IPv6 qu'en IPv4 mais on manque encore d'expérience. En pratique, début 2013, très peu d'attaques sont lancées en IPv6 (elles bénéficient par contre d'une exposition médiatique démesurée, justement parce qu'elles sont rares). Cela ne durera pas éternellement et les responsables réseaux et systèmes doivent donc se préoccuper de ces risques. En gros, comme IPv6 est uniquement une nouvelle version d'IPv4, fondée sur les mêmes concepts, la quasi-totalité des risques présents en IPv4 (de l'attaque par déni de service aux tentatives de se connecter au serveur SSH) existent en IPv6.

Aujourd'hui, il est difficile de répondre simplement à une question comme « est-ce plus dangereux en IPv6 ? » Comme on l'a vu, il y a beaucoup moins d'attaques. Mais les défenses sont également moins bonnes : il est fréquent qu'une organisation soit protégé par un pare-feu en IPv4 mais que tout le trafic IPv6 passe librement. En fait, aujourd'hui, aussi bien les attaquants que les défenseurs ne prennent guère en compte IPv6. On a donc un équilibre... instable. Sur ce sujet de la sécurité d'IPv6, on peut consulter mon exposé à l'ESGI.


Téléchargez le RFC 6883


L'article seul

RFC 6879: IPv6 Enterprise Network Renumbering Scenarios, Considerations and Methods

Date de publication du RFC : Février 2013
Auteur(s) du RFC : S. Jiang, B. Liu (Huawei Technologies), B. Carpenter (University of Auckland)
Pour information
Réalisé dans le cadre du groupe de travail IETF 6renum
Première rédaction de cet article le 28 février 2013


Ce RFC ne normalise pas un protocole mais a pour ambition de servir de guide lors de la rénumérotation d'un réseau IPv6. Pourquoi renuméroter ? Et comment ? Les administrateurs réseaux ont tout intérêt à le lire, et de préférence avant la renumérotation et même avant la mise en production du réseau, pour ne pas mettre dans l'architecture de celui-ci des éléments qui gêneront les renumérotations futures.

C'est le deuxième RFC du groupe de travail 6renum qui planche sur les scénarios de renumérotation de réseaux IPv6, ainsi que sur les moyens de rendre ces renumérotations plus faciles. Ce RFC particulier se focalise sur le cas d'une organisation de taille significative : ni un SOHO, ni un opérateur réseau, un client de taille moyenne qui a IPv6 sur son réseau local, une ou plusieurs connexions à l'Internet et au moins un employé chargé d'administrer le réseau (cf. RFC 4057).

La seule façon d'être sûr de ne jamais renuméroter serait de n'utiliser que des adresses PI. Mais, comme le note le RFC 4116, cela aurait des conséquences quantitatives néfastes pour BGP. Donc, on part du principe que l'organisation aura à renuméroter un jour. Lisons les prérequis (RFC 4192 et RFC 5887) et allons-y.

Les machines reçoivent des adresses IP dynamiques (si elles ont des adresses statiques, le problème est plus compliqué, et c'est le domaine du RFC 6866). Pour cela, on utilise DHCP ou les annonces des routeurs (SLAAC).

Mais pourquoi renumérote-t-on ? Pourquoi s'embêter dans cette opération au lieu de se contenter de garder ses adresses actuelles ? La section 3 décrit plusieurs scénarios déclencheurs. Certains peuvent être externes, d'autres internes. Parmi les externes :

  • Passage à un nouveau FAI qui a d'autres adresses pour ses clients. Idéalement, il y aura une période de recouvrement pendant laquelle l'organisation sera connectée par les deux FAI. Si ce n'est pas possible, il y aura un flag day où il faudra tout basculer d'un coup.
  • Renumérotation chez le FAI, soit parce que lui-même a changé de fournisseur, soit parce qu'il a réorganisé son réseau.
  • Ajout d'un deuxième FAI, pour une organisation qui n'en avait qu'un et qui souhaite davantage de redondance. Les anciennes adresses ne changent pas mais de nouvelles s'y ajoutent.

Et les causes internes ?

  • Réorganisation de l'organisation : fusion, acquisition, ou autre événement business qui a des conséquences sur le réseau.
  • Réorganisation technique du réseau.

La section 4 décrit ensuite les méthodes existantes pour faire ces renumérotations avec le moins de douleur possible. Parmi les mécanismes qui peuvent aider, il ne faut pas oublier la délégation de préfixe IP (RFC 3633 et RFC 6603), qui permet à un routeur d'informer d'autres routeurs sur les préfixes qu'ils vont devoir gérer (annoncer avec des RA, router, etc). Ainsi, on n'aura pas à reconfigurer tous les routeurs. Autre mécanisme important, l'utilisation de noms de domaine le plus souvent possible, car ils sont plus stables que les adresses IP. Par exemple, pour IPsec, nul besoin de configurer en utilisant des adresses, des noms peuvent être utilisés (RFC 5996), simplifiant ainsi beaucoup les futures renumérotations. (Pour les réseaux sans serveur DNS, le RFC rappelle l'existence de Multicast DNS, RFC 6762.) De même, les applications devraient aussi utiliser des noms et pas des adresses. Configurer une application avec une adresse IP, c'est placer une bombe qui explosera lors de la prochaine renumérotation du réseau.

Mais les adresses IP peuvent se cacher en d'autres endroits, comme dans les ACL des pare-feux. Au minimum, ces configurations devraient être paramétrisées : on n'utilise l'adresse IP qu'une fois, pour lui donner un identificateur, puis on se sert de cet identificateur partout (des outils comme m4 ou cpp peuvent être utilisés pour cela). C'est le B A BA de l'administration réseaux, mais ce n'est pas toujours fait.

Pendant qu'on parle d'adresses IP qui traînent, il ne faut évidemment pas mettre dans ses configurations des adresses IP d'autres sites. Sinon, lorsqu'ils renuméroteront, ils ne penseront sans doute pas à vous prévenir...

Un truc plus exotique est l'utilisation d'ULA, des adresses IP locales (RFC 4193). L'idée est de tout numéroter avec les ULA et d'effectuer une traduction d'adresses ou un relayage dans les routeurs de sortie. Ainsi, la renumérotation n'impacte que ces routeurs. Les ULA sont donc une sorte de substitut aux adresses PI.

Continuons avec les techniques utilisées sur le réseau local : comment les adresses IP arrivent-elles aux machines terminales ? En IPv6, il y a deux solutions, SLAAC (RFC 4862) et DHCP (RFC 3315). Ce RFC ne tranche pas entre les deux : du point de vue de la renumérotation, ils ont à peu près les mêmes possibilités. (DHCP a une option, RECONFIGURE qui permet, si le client DHCP la gère, de faire des renumérotations imprévues.)

Et le DNS ? Un petit site ne gère pas forcément ses propres serveurs DNS. Leur reconfiguration pourra nécessiter une coordination avec l'hébergeur DNS. Ce que le RFC recommande, c'est de ne pas le faire manuellement. Le fichier de zone édité avec vi et contenant les adresses IP de toutes les machines de l'organisation, c'est un mécanisme archaïque, et, en 2013, on doit normalement mieux faire : soit les données DNS sont dérivées automatiquement d'une base de données de machines (cela n'a pas besoin d'être une usine à gaz, cela peut être un simple script Perl/Python/Ruby), soit les machines (ou les serveurs DHCP) mettent à jour le DNS automatiquement avec les mises à jour dynamiques (RFC 3007).

Une fois qu'on a fait le tour de son réseau et des techniques utilisées, il faut se préparer, et planifier soigneusement. D'abord, diminuer la durée de vie des annonces d'adresses pour que la transition soit la plus courte possible et que les vieilles adresses ne trainent pas dans les caches. Avec l'autoconfiguration sans état (SLAAC), on ne peut pas réduire la durée de vie des annonces à moins de deux heures, il faudra faire avec. D'autre part, cette diminution va évidemment augmenter le trafic et il ne faut donc pas la faire des semaines à l'avance. Une telle durée de vie est stockée dans les enregistrements DNS (qu'il faut donc ajuster), mais aussi dans les annonces indiquant le résolveur DNS à utiliser (RFC 8106 pour SLAAC et RFC 3646 pour DHCP, où il faut réduire la durée du bail, on ne peut pas réduire seulement la durée de vie de l'option DNS). À noter que les applications qui maintiennent des connexions sur de longues périodes (SSH, par exemple), n'ont pas de mécanisme propre pour gérer la renumérotation. Il faudra faire une déconnexion/reconnexion.

Bref, anticiper et planifier sont des nécessités.


Téléchargez le RFC 6879


L'article seul

RFC 6878: IANA Registry for the Session Initiation Protocol (SIP) "Priority" Header Field

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


Cet ultra-court RFC crée officiellement un registre pour stocker les valeurs possibles du champ Priority du protocole SIP.

Le RFC 3261, qui normalise le système de téléphonie sur IP SIP incluait un champ pour indiquer la priorité d'une communication (section 20.26 du RFC 3261). Quatre valeurs possibles étaient définies, non-urgent, normal, urgent et emergency, tout en précisant que d'autres pourraient l'être mais sans indiquer comment. Ce RFC 6878 comble ce manque.

Il y donc désormais :

  • Un registre à l'IANA de ces priorités, comportant les quatre valeurs indiquées,
  • Une politique d'enregistrement, suivant le RFC 5226. Cette politique est IETF Review, qui implique un RFC non-individuel (de façon à s'assurer un passage à l'IESG) mais pas forcément sur le chemin des normes.

Téléchargez le RFC 6878


L'article seul

RFC 6875: The P2P Network Experiment Council's Activities and Experiments with Application-Layer Traffic Optimization (ALTO) in Japan

Date de publication du RFC : Février 2013
Auteur(s) du RFC : S. Kamei (NTT Communications), T. Momose (Cisco), T. Inoue, T. Nishitani (NTT Communications)
Pour information
Première rédaction de cet article le 23 février 2013


Ce RFC décrit une expérience faite il y a quelques années au Japon pour tester l'efficacité des mécanismes de sélection de pairs dans un réseau pair à pair. Elle montre que cette sélection peut améliorer l'efficacité des protocoles pair à pair, une leçon utile pour le projet ALTO (Application-Layer Traffic Optimization, RFC 5693).

Le réseau pair à pair typique relie des machines, les pairs, qui peuvent être très éloignées les unes des autres. Les relations des machines entre elles ne correspondent pas forcément aux réalités de l'interconnexion. En bref, un pair risque de télécharger des données depuis un pair lointain alors qu'il en existait un plus proche. Des tas de propositions ont été faites pour un mécanisme de sélection des pairs, menant théoriquement à une plus grande efficacité. De 2007 à 2008, au Japon, le P2P Network Experiment Council a réalisé une série de mesures pour comparer théorie et pratique. Une intense répression sous les ordres de l'industrie du divertissement, avec plusieurs arrestations, a réduit l'usage du pair à pair dans ce pays depuis, sans toutefois réussir à le réduire à zéro.

Le Japon est souvent un cas à part et, à l'époque en question, le système de pair à pair le plus populaire n'était pas Bit Torrent mais Winny ou Share. Leur trafic total combiné était estimé à 40 % du trafic total. Pour l'opérateur de réseaux, le pair à pair (P2P) a donc un impact important et cela les motive pour chercher des économies, justement ce que promettent les techniques de sélection du pair. Parmi les autres solutions envisagées par les FAI : faire un effort pour placer le contenu très demandé plus près des utilisateurs (les CDN, par exemple), augmenter les prix, ou limiter autoritairement le trafic.

L'approche choisie par le P2P Network Experiment Council, organisme créé par le gouvernement japonais en 2006, était de tester les solutions de sélection du pair. Pour cela, le conseil a déployé un réseau de serveurs indicatifs (les oracles, selon la terminologie généralement utilisée chez les chercheurs de ce domaine), indépendants d'un système de P2P particulier et donnant des indications sur le meilleur pair.

La section 3 décrit plus en détail ce « conseil pour des expériences P2P ». Créé par le ministère des télécommunications, à la suite de débats sur des sujets comme la neutralité du réseau, il est documenté (en japonais) dans le rapport « Disclosure of the Report `Working Group on P2P Networks' » et placé sous l'égide d'une fondation (oui, encore un texte dans la langue de Naoki Urasawa). Outre les tests qui font l'objet de ce RFC, le conseil a une activité de promotion des bonnes pratiques en matière de P2P.

La section 4 de notre RFC décrit les expériences menées : au début, il n'y avait aucun doute sur les économies en matière de serveurs, lorsqu'on migre vers le pair à pair. Ainsi, l'entreprise Utagoe annonçait une réduction de 90 % de son trafic sortant en migrant vers leur système UGLive. Et TV Bank Corp a vu 80 à 96 % de gain avec BB Broadcast. Mais ce sont des gains pour les fournisseurs de contenu. Et pour les opérateurs réseau ? Il y a eu de études au Japon sur le trafic total (comme celle de Cho, Fukuda, Esaki et Kato). Mais étudier le comportement des applications réellement installées sur les utilisateurs demande des mesures fort intrusives, par exemple avec du DPI.

Le choix du conseil avait donc été d'installer des faux utilisateurs : des PC munis de logiciels P2P modifiés (pour demander à l'oracle) ont été placés dans les réseaux des FAI. On peut ainsi faire varier librement et facilement tous les paramètres de mesure (et, bien que le RFC ne le dise pas, cela évite tout problème lié à la vie privée). Le faux utilisateur est donc un PC avec CentOS, VMware et un Windows par dessus. Le système hôte CentOS peut ainsi observer tout le trafic sans déranger. 60 machines ont été installées chez 40 FAI.

La section 5 décrit l'oracle (hint server), le serveur qui va distribuer les indications. C'est l'équivalent du « serveur ALTO » dans le protocole ALTO (RFC 6708). Lorsqu'un pair démarre, il indique à l'oracle son adresse IP et des informations comme les caractéristiques de la liaison Internet utilisée. L'oracle, en utilisant des informations sur la topologie du réseau informations fournies par le FAI et une table de routage obtenue via BGP (l'oracle inclut un Quagga), peut alors envoyer au pair une table des meilleurs pairs possibles. Dans ce cas idéal, l'optimisation réalisée est presque parfaite. En pratique, l'oracle n'a pas forcément toute l'information nécessaire : le FAI, l'estimant confidentielle, a pu ne pas donner une information complète.

Pour prendre sa décision, l'oracle s'appuie sur :

  • La longueur du chemin d'AS entre le client et le pair potentiel (rappelez-vous que l'oracle participe à BGP),
  • La distance géograpĥique entre ces deux pairs possibles. Ne connaissant par la longitude et la latitude de chaque machine, l'oracle fait une approximation : il trouve la préfecture dans une base GeoIP, puis utilise la position physique de la capitale de la préfecture.

Voici un exemple simplifié d'une requête d'un pair à l'oracle, et de la réponse de l'oracle. Le tout est transporté sur HTTP et les données sont encodées en couples {type, valeur} :

POST /PeerSelection HTTP/1.1
Host: OracleServerName
User-Agent: ClientName
Content-Type: text/plain; charset=utf-8

v=Version number
ip=IP address of physical interface
port=1978
nat=unknown
ub=256
db=15000

Vous avez compris que ub et db sont les capacités réseau montant et descendantes, et que nat indique (si le pair le sait), si le pair est coincé ou non derrière un routeur NAT, qui rend difficile les connexions entrantes. Et voici la réponse :

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

v=Version number
ttl=ttl
client_ip=192.0.2.67
numpeers=11
...

La section 6 résume les résultats de l'expérience. Soit un pair situé à Tokyo. Sans l'oracle, de 22 à 29 % des pairs sélectionnés étaient déjà dans le même FAI, et de 19 à 23 % dans le même district (il est important de connaître ces valeurs car, si un contenu est peu populaire et ne se trouve pas du tout dans le même FAI que l'utilisateur, aucun oracle au monde ne pourra indiquer un pair proche). Avec l'oracle, la distance moyenne avec le pair a été réduite de 10 %. (Opinion personnelle : le RFC est beaucoup plus détaillé sur la configuration de l'expérience que sur les résultats obtenus, très brefs.)

Les auteurs estiment que ces résultats montrent l'intérêt d'un système de sélection du pair. Quelles conclusions pour le groupe de travail ALTO, qui standardise une technologie analogue ? Que l'information publiquement accessible via BGP est une source utile pour optimiser le trafic entre FAI. Que, pour le trafic interne au FAI, il faut une information détaillée de la topologie du réseau de ce FAI, information qui peut être difficile à obtenir. Que les demandes futures seront peut-être d'avoir une sélection plus précise, nécessitant peut-être une structure hiérarchique dans ALTO (des serveurs ALTO utilisant eux-même d'autres serveurs ALTO). Et qu'il serait bon que l'oracle soit un peu plus bavard sur les mécanismes qu'il a utilisé pour trier les pairs possibles, afin que le pair puisse combiner le jugement de l'oracle avec ses propres critères.

Sur l'évaluation des mécanismes de sélection du pair, voir aussi le RFC 6821.


Téléchargez le RFC 6875


L'article seul

RFC 6874: Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers

Date de publication du RFC : Février 2013
Auteur(s) du RFC : B. Carpenter (Univ. of Auckland), S. Cheshire (Apple), R. Hinden (Check Point)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 23 février 2013


Ce court RFC normalise la façon d'indiquer la zone dans un URI contenant une adresse IPv6 littérale.

Les zones sont définies et expliquées dans le RFC 4007. En gros, une adresse IPv6 n'est pas forcément globale, elle peut avoir une signification limitée à une seule zone, une zone étant un ensemble de sous-réseaux contigus, souvent composé d'un seul lien Ethernet. Les adresses locales au lien, par exemple, celles qui sont dans le préfixe fe80::/10, sont dans ce cas, le lien qui les relie forme une zone. Pour indiquer cette zone, la convention de mettre un %, puis l'identificateur de la zone, après l'adresse, est fréquemment utilisée. Mais elle n'était pas normalisée, dans le cas où l'adresse apparaissait dans un URI. Ce RFC répare ce manque.

Car il peut y avoir des adresses IP littérales dans un URI (section 3.2.2 du RFC 3986). Par exemple, http://[2001:db8:1::23]/ est un URI valide. (Et je viens de tester avec mon Firefox qui l'a accepté sans problèmes.) Mais, si cette adresse est locale à une zone ? D'habitude, on utilise la convention du % (décrite en section 11 du RFC 4007). Ici, sur une machine Linux récente (cela ne marchait pas autrefois, il fallait utiliser l'option -I) :

% ping6 -c3 fe80::21e:8cff:fe76:29b6%eth0
PING fe80::21e:8cff:fe76:29b6%eth0(fe80::21e:8cff:fe76:29b6) 56 data bytes
64 bytes from fe80::21e:8cff:fe76:29b6: icmp_seq=1 ttl=64 time=8.36 ms
64 bytes from fe80::21e:8cff:fe76:29b6: icmp_seq=2 ttl=64 time=4.97 ms
64 bytes from fe80::21e:8cff:fe76:29b6: icmp_seq=3 ttl=64 time=4.84 ms

--- fe80::21e:8cff:fe76:29b6%eth0 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 4.847/6.060/8.363/1.631 ms

On teste la machine fe80:1::23 reliée au réseau identifié par eth0 (dans le cas de Linux, c'est le nom d'une interface réseau mais d'autres systèmes d'exploitation peuvent utiliser une syntaxe différente, par exemple identifier les zones par un simple numéro). Cette possibilité de désigner une zone spécifique est essentielle pour les activités de déboguage (M. Toutlemonde n'a sans doute jamais besoin d'URI incluant des adresses IP). Mais si on utilise un navigateur Web pour cette activité, comment mettre la zone ? Le RFC 4007 était muet à ce sujet. Certains navigateurs (par exemple certaines versions anciennes de Firefox) acceptaient des adresses suivies d'un pour-cent (alors que ce caractère est spécial dans les URI et que ces navigateurs violaient donc le RFC 3986).

Encore mieux, comme le RFC 4007 ne précise pas quels sont les caractères autorisés dans un identificateur de zone, on pourrait voir des zones avec un nom invalide dans un URI (comme / ou #).

La syntaxe standard normalisée par notre RFC est donc :

  • Mettre l'identificateur de zone après un pour-cent encodé (donc, %25, ce qui était déjà la méthode déployée par Internet Explorer),
  • Fortement conseiller de ne pas utiliser de caractères spéciaux dans les identificateurs de zone mais, si cela arrive, les encoder avec le système « pour-cent » du RFC 3986 (section 2.1),
  • Suivre les recommandations du RFC 5952 pour représenter l'adresse IPv6.

Pour faciliter la vie de l'administrateur réseaux, notre RFC recommande que les navigateurs acceptent un URI incluant un % tout nu, s'il est suivi d'au moins deux caractères qui ne peuvent pas être des chiffres hexadécimaux. Cela permet de copier-coller une adresse comme fe80::a%en1 dans le navigateur et que cela marche. (Par contre, fe80::a%ee1 ne serait pas accepté car E peut être un chiffre hexadécimal et il y aurait une ambiguité entre %ee et î, qui est encodé ainsi en notation pour-cent.) Cette opération de copier/coller sera sans doute le principal usage de ces URI comportant une adresse IPv6 et une zone : on ne voit pas bien dans quels cas ils se retrouveraient dans une page HTML, sauf peut-être produite automatiquement par des systèmes d'administration de réseaux (l'interface Web d'un routeur, par exemple).

Donc, désormais, http://[fe80::dead:beef%25en1] ou http://[fe80::1:2%25Ethernet%230] sont des URI légaux (dans le deuxième, le nom de la zone était Ethernet/0). Essayez-les sur votre navigateur !

Comme ces identificateurs de zone n'ont de signification que pour une machine donnée, les relais HTTP, par exemple, doivent les retirer des URI.

Voilà, c'est tout, les amateurs d'alternatives peuvent lire l'annexe A, consacrée aux raisons du choix qui a été fait. Il a l'avantage de ne pas changer le format des URI et les inconvénients qu'il n'est pas très joli, et que le copier/coller d'une console vers un navigateur ne marche pas toujours. Les autres possibilités considérées (les discussions ont été chaudes et longues) étaient :

  • Ne rien normaliser, en considérant que ping ou telnet depuis une console étaient plus pratique que d'utiliser un navigateur Web. C'était le choix le plus simple.
  • Entériner l'usage des % nus dans l'URI. Cela était cohérent avec le RFC 4007 et cela permettait le copier/coller mais cela produisait des URI illégaux.
  • Trouver un autre caractère que le % pour séparer l'adresse de la zone, par exemple le -, comme dans http://[fe80::a-ee1] (au passage, pourquoi pas un tiret bas ? parce que les navigateurs soulignent souvent automatiquement les URI, rendant le trait invisible). Mais une telle réforme du RFC 4007 aurait nécessité de changer tous les outils IPv6 et toutes les documentations.
  • Se servir de la production IPvFuture de la section 3.2.2 du RFC 3986 pour écrire, par exemple http://[v6.fe80::a-en1]. Mais cela ne permettait pas le copier/coller. (Et j'ajoute qu'aucun navigateur ne gère cette possibilité IPvFuture.)

Téléchargez le RFC 6874


L'article seul

RFC 6873: Format for the Session Initiation Protocol (SIP) Common Log Format (CLF)

Date de publication du RFC : Février 2013
Auteur(s) du RFC : G. Salgueiro (Cisco), V. Gurbani (Bell Labs, Alcatel-Lucent), A. B. Roach (Tekelec)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF sipclf
Première rédaction de cet article le 15 février 2013


La question d'un format standard et commun pour la journalisation des événements SIP est exposée et discutée dans le RFC 6872. Ce RFC 6873, lui, spécifie un format standard conforme aux exigences et au modèle de données du RFC 6872. Techniquement, sa principale originalité est d'être un format texte... indexé. Il a donc les avantages des formats textes (lisible sans outil particulier, utilisable avec des outils génériques comme grep ou awk) tout en gardant de bonnes performances si on développe des outils qui lisent ces index.

Le projet d'un format standard pour les journaux de SIP s'appuie évidemment sur le grand succès du CLF des serveurs HTTP. Ce format CLF a facilité la vie de tous les administrateurs système, et a permis le développement de plein d'outils de statistiques et d'analyse. Il a toutefois quelques défauts, le principal étant de performance. Si on cherche