Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Ève

Ce blog n'a d'autre prétention que de me permettre de mettre à la disposition de tous des petits textes que j'écris. On y parle surtout d'informatique mais d'autres sujets apparaissent parfois.


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

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : Z. Hu, L. Zhu, J. Heidemann (USC/Information Sciences Institute), A. Mankin, D. Wessels (Verisign Labs), P. Hoffman (ICANN)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 18 mai 2016


Traditionnellement, les requêtes DNS voyageaient sur le réseau en clair, visibles par tous. Ce n'est évidemment plus acceptable, notamment depuis les révélations de Snowden, et ce RFC normalise donc un mécanisme qui permet de chiffrer les requêtes DNS pour en assurer la confidentialité vis-à-vis d'un éventuel surveillant.

Le chiffrement est le deuxième pilier de la protection des données, après la minimisation des données (qui, pour le DNS, est spécifiée dans le RFC 7816). Ce chiffrement est motivé notamment par le développement de la surveillance de masse (RFC 7258), par le souci de protéger la vie privée (RFC 6973) et par la prise de conscience des risques spécifiques au DNS (RFC 7626).

Il y avait plusieurs choix possibles pour le groupe de travail DPRIVE qui a produit ce RFC. Il pouvait utiliser une technique extérieure à l'IETF comme DNSCrypt. Il pouvait s'appuyer sur un protocole existant comme IPsec ou TLS. Et il pouvait développer un nouveau protocole (plusieurs propositions avaient été faites en ce sens). Finalement, le choix s'est porté sur un protocole facile à déployer, bien connu, et éprouvé, TLS. Pour résumer techniquement ce RFC (section 1) : on met les requêtes DNS sur un canal TLS lui-même évidemment transporté sur TCP. (Le groupe DPRIVE travaille également sur une future solution utilisant DTLS et donc UDP.) Outre la confidentialité, TLS permet de protéger les données contre une modification en cours de route.

Notons au passage que DNSSEC ne résout pas ces problèmes : son but est d'authentifier les réponses, pas de protéger contre l'espionnage.

Il y a deux liens à protéger dans une requête DNS, celui entre la machine de l'utilisateur et le résolveur, et celui entre le résolveur et les serveurs faisant autorité. La charte du groupe DPRIVE précisait qu'il fallait d'abord s'attaquer au premier problème, plus facile (une machine ne parle qu'à peu de résolveurs, et elle a une relation avec eux, alors qu'un résolveur parle à beaucoup de serveurs faisant autorité, qu'il ne connait pas.)

La section 3 décrit la gestion des connexions TLS. TLS tourne sur TCP (un de ses copains, DTLS, tourne sur UDP), et il faut donc utiliser ce protocole (notez que l'évolution récente du DNS fait de plus en plus de place à TCP, cf. RFC 7766). DNS-sur-TLS tourne sur un port fixe, le port 853 (les premières versions de ce protocole utilisaient un protocole de négociation de TLS, comme pour SMTP mais, trop compliqué et trop dangereux, il a été abandonné). Le serveur DNS-sur-TLS écoute donc sur le port 853, le client se connecte à ce port, et démarre tout de suite une session TLS (RFC 5246). Ensuite, il y fait circuler le DNS, encodé comme sur TCP (le message DNS précédé de deux octets indiquant sa taille, cf. RFC 1035, section 4.2.2). Comme pour tout usage de DNS sur TCP (RFC 7766), le client et le serveur ne doivent évidemment pas couper la connexion après une seule requête. S'ils le faisaient, les performances seraient catastrophiques, vu le temps qu'il faut pour établir la connexion TCP et la session TLS. Au contraire, la session doit être réutilisée (section 3.4) pour les requêtes ultérieures (et le RFC demande aussi qu'un serveur traite les requêtes en parallèle, pas séquentiellement dans leur ordre d'arrivée, section 3.3.) Un autre moyen de gagner du temps lors de l'établissement d'une nouvelle connexion TCP, moyen recommandé par notre RFC, est d'utiliser TCP Fast Open (RFC 7413).

Notez bien la règle : jamais de contenu chiffré sur le port 53, jamais de contenu en clair sur le port 853. Si le serveur ne répond pas aux requêtes sur le port 853, cela peut être parce qu'une affreuse middlebox bloque tout le trafic vers le port 853, ou tout simplement parce que ce résolveur ne gère pas encore DNS sur TLS. Le client doit alors décider, selon sa politique de sécurité, s'il se rabat sur du trafic DNS en clair ou bien s'il renonce à communiquer. Le RFC recommande que le client se souvienne des serveurs qui répondent sur le port 853, pour détecter un filtrage récemment apparu.

À noter aussi que je n'ai pas parlé encore d'authentification du serveur. Comment être sûr qu'on parle bien au serveur à qui on veut parler et pas au terrible Homme du Milieu ? Pour l'instant, gardez la question de côté, on y reviendra.

Dit comme cela, c'est peut-être un peu compliqué, mais l'un des gros avantages du choix de TLS est qu'il existe déjà des bibliothèques toutes faites pour ce protocole. Ajouter TLS à un client ou un serveur existant est donc relativement simple. (Plus simple que la gestion du RFC 7766, qui est un pré-requis pour DNS-sur-TLS.)

Revenons à l'authentification. A priori, elle est indispensable. Si on n'authentifie pas, on risque d'envoyer ses requêtes DNS à un serveur qui n'est pas le bon, et, dans ce cas, le chiffrement n'aura servi à rien. Pour se faire passer pour le bon serveur DNS, les attaquants actifs ont bien des moyens à leur disposition, comme d'injecter des fausses routes, comme en Turquie. Un chiffrement sans authentification ne protégerait que contre des attaquants strictement passifs.

Oui, mais l'authentification, c'est difficile. Il y a plein de pièges, de problèmes possibles, et d'argent à dépenser (par exemple pour acheter un certificat). Imposer dès le début une authentification stricte dans tous les cas aurait tué le projet dans l'œuf. Le choix a donc été de prévoir un certain nombre de profils d'authentification, que le client choisit, en fonction du degré de sécurité souhaité. (Le serveur, lui, n'authentifie pas le client, en tout cas aucun mécanisme n'est prévu pour cela.) Notre RFC propose deux profils d'authentification (section 4), et d'autres seront décrits dans un futur RFC. Ne vous impatientez donc pas si votre profil favori est absent de ce RFC.

Le premier profil est celui « opportuniste » (opportunistic privacy). Le client DNS qui utilise ce profil va tenter de chiffrer, il peut même essayer d'authentifier mais, si cela échoue, il continue quand même à envoyer des requêtes DNS, se disant qu'il est au moins protégé contre les attaques passives.

Le second profil est celui de l'« épinglage de clé » (out-of-band key-pinned »). La clé publique (SPKI pour Subject Public Key Info) du serveur DNS est connue du client (par un mécanisme non spécifié dans ce RFC), et il ne se connecte à un serveur DNS-sur-TLS que s'il utilise une des clés correspondant à son adresse. C'est un mécanisme analogue à l'épinglage HTTP du RFC 7469. Une syntaxe possible, pour un /etc/resolv.conf sur Unix serait, par exemple (l'annexe A propose une autre syntaxe) :

domain example.net
nameserver 2001:db8:90e:241a::1  NjAwZGI5YTVhMzBiY2EzOWY1OTY5YzM0ZGYzMTllYTVkNmYxNjAwYjJmNzZhOGFhYTNhMDEyMzU4MTIwNjNkMwo= 
  

Où le dernier champ est le condensat de la clé publique.

Ce mécanisme est sûr, empêchant toute attaque de l'Homme du Milieu. Il est peut-être même trop sûr, par exemple pour les réseaux qui utilisent ces horribles portails captifs qui font des attaques de l'Homme du Milieu pour vous rediriger vers le portail. Il peut donc être préférable de ne pas activer ce profil avant de s'être authentifié auprès du portail. (dnssec-trigger utilise un mécanisme analogue.)

J'ai déjà parlé des performances au moment de l'établissement de la connexion, et des problèmes de latence qui peuvent survenir en raison de l'utilisation de TCP et de TLS. La section 5 revient sur ces histoires (il est également recommandé de lire le rapport « T-DNS: Connection-Oriented DNS to Improve Privacy and Security »). Évidemment, une connexion TCP plus une requête DNS, c'est plus coûteux qu'une requête DNS tout court. La requête et la réponse DNS nécessitent deux voyages entre client et serveur, l'etablissement de la connexion TCP en nécessite trois à lui seul, et TLS deux de plus. On pourrait en déduire que DNS-sur-TLS-sur-TCP aura une latence plus élevée de 250 %. On peut réduire ce coût avec des trucs TCP qui réduisent le temps d'établissement de la connexion, comme le TCP Fast Open du RFC 7413 et avec des trucs TLS comme la reprise de session du RFC 5077. Mais, de toute façon, ce calcul n'est vrai que si on établit une connexion TCP par requête DNS, ce qui n'est pas conseillé, la bonne méthode étant au contraire, dans l'esprit du RFC 7766, de réutiliser les connexions.

D'autre part, TCP nécessite de stocker un état dans le serveur. Pour éviter que beaucoup de clients n'écroulent celui-ci, il faut donc ajuster les délais d'inactivité, pour couper les connexions TCP inutilisées.

La section 7 de notre RFC intéressera les ingénieurs qui se demandent pourquoi les choses sont comme elles sont et pourquoi un autre choix n'a pas été fait. Elle est consacrée à l'évolution de la solution de chiffrement du DNS, au sein du groupe de travail DPRIVE. Comme indiqué plus haut, le premier projet prévoyait de tout faire passer sur le port 53, avec un passage en TLS à la demande du client, lorsqu'il envoyait une requête DNS « bidon » avec un nouveau bit EDNS, TO (TLS OK), mis à un, et avec le QNAME (Query NAME) STARTTLS (reprenant un mot-clé utilisé par SMTP, dans le RFC 3207).

Cette méthode avait des avantages : elle permettait par exemple à un serveur d'accepter TLS quand il n'était pas trop chargé, et de le refuser autrement. Et, réutilisant le port existant, elle ne nécessitait pas de changer les ACL sur les pare-feux. Mais elle avait aussi des inconvénients : les affreuses middleboxes ont une longue habitude d'interférence avec EDNS et il n'était pas du tout sûr qu'elles laissent passer le bit TO. Et puis, même si le RFC ne le mentionne pas, il y avait un risque qu'une middlebox trop zélée ne fasse du DPI sur le port 53, s'aperçoive que ce qui passe n'est pas du DNS, et coupe la communication. Mais le principal problème de cette approche était qu'elle rendait les attaques par repli triviales. Un attaquant actif n'avait qu'à supprimer le bit TO et le client n'avait alors plus aucun moyen de savoir si l'absence de TLS était due à un serveur trop ancien, à une middlebox boguée... ou bien à une attaque par repli.

Une proposition alternative amusante avait été de mêler le trafic chiffré et non chiffré sur le port 53 sans signalisation : la structure de l'en-tête TLS est telle qu'une machine interprétant le TLS comme étant du DNS en clair aurait vu une réponse DNS (bit QR à 1) et il n'y aurait donc pas eu de confusion avec le trafic DNS en clair. Astucieux mais évidemment très fragile.

La section 8 de notre RFC synthétise les questions de sécurité. D'abord, TLS n'est évidemment pas une formule magique. Il y a eu plein d'attaques contre TLS (par exemple pour forcer un repli vers des algorithmes de chiffrement faibles), ou contre ses mises en œuvre (on pense évidemment tout de suite à OpenSSL). Pour éviter cela, outre le respect des bonnes pratiques TLS (RFC 7525), le client prudent tâchera de se souvenir quels serveurs acceptaient DNS-sur-TLS. Si un serveur qui l'acceptait ne répond tout à coup plus sur le port 853, c'est peut-être qu'un attaquant tente de forcer un repli sur le port 53, en clair. Le client prudent peut ainsi détecter une attaque possible. Si c'est un nouveau serveur, que le client ne connait pas, la marche à suivre dépend de la politique du client (sécurisé ou laxiste).

Quant aux attaques non-TLS (comme le blocage du port 853 mentionné ci-dessus), c'est également au client, en fonction de son profil de sécurité, de décider ce qu'il va faire (renoncer à communiquer, essayer un mécanisme de résolution alternatif, s'en foutre et tout passer en clair, etc).

Revenons à TLS pour noter que ce protocole ne fait pas d'effort pour dissimuler la taille des paquets. Un attaquant passif peut donc, en observant cette taille, et d'autres informations comme le temps écoulé entre deux paquets, en déduire certaines informations, malgré le chiffrement. L'option de remplissage du RFC 7830 permet de remplir les paquets avec des données bidons, afin de rendre cette analyse plus difficile.

Pour un bilan d'étape du projet « DNS et vie privée » à l'IETF, vous pouvez regarder mon exposé State of the "DNS privacy" project: running code à l'OARC.

Question mises en œuvre de ce RFC, où en est-on ? Aujourd'hui, le résolveur Unbound a le code nécessaire depuis longtemps (depuis la version 1.4.14). On peut génerer les clés nécessaires avec OpenSSL ainsi :

openssl req -x509 -newkey rsa:4096 \
      -keyout privatekeyfile.key -out publiccertfile.pem \
      -days 1000 -nodes    
  

et configurer le serveur ainsi :

server:
  interface: 2001:db8:1::dead:beef@853
  ssl-service-key: "/etc/unbound/privatekeyfile.key"
  ssl-service-pem: "/etc/unbound/publiccertfile.pem"
  ssl-port: 853
  

Unbound va alors activer DNS sur TLS au démarrage et annoncer fièrement « setup TCP for SSL [sic] service ». Les clients pourront alors l'interroger en DNS sur TLS.

Bon, mais quel client utiliser ? Dans la bibliothèque getdns, le logiciel d'exemple getdns_query sait faire du DNS sur TLS :

% ./getdns_query @2001:db8:1::dead:beef -s -a -A -l L www.bortzmeyer.org
...
Response code was: GOOD. Status was: At least one response was returned
  

(C'est l'option -l L qui lui indique de faire du TLS.)

Si on capture le trafic entre getdns_query et Unbound, on peut afficher le résultat avec tshark :

% tshark -n -d tcp.port==853,ssl -r /tmp/dnstls.pcap    
 4   0.002996  2001:db8:1::63a:671 -> 2001:db8:1::dead:beef  SSL Client Hello
 6   0.594206  2001:db8:1::dead:beef -> 2001:db8:1::63a:671  TLSv1.2 Server Hello, Certificate, Server Key Exchange, Server Hello Done
 8   0.734094  2001:db8:1::63a:671 -> 2001:db8:1::dead:beef  TLSv1.2 Client Key Exchange
16   0.751614  2001:db8:1::dead:beef -> 2001:db8:1::63a:671  TLSv1.2 Application Data
17   0.759223  2001:db8:1::63a:671 -> 2001:db8:1::dead:beef  TLSv1.2 Application Data
  

On voit un trafic TLS classique, chiffré. Notez que tshark, par défaut, ne sait pas que c'est du TLS sur le port 853 (cela sera fait lors de la prochaine version majeure). On lui indique donc explicitement (-d tcp.port==853,ssl).

Et si j'ai la flemme d'installer un Unbound configuré pour TLS, est-ce que je peux quand même tester un client DNS-sur-TLS ? Oui, si les serveurs de test publics listés en https://portal.sinodun.com/wiki/display/TDNS/DNS-over-TLS+test+servers veulent bien répondre.

Si vous préférez développer en Go, l'excellente bibliothèque GoDNS gère DNS sur TLS (depuis janvier 2016) et vous permet de faire vos propres programmes. Par exemple, ce code Go :

c := new(dns.Client)
c.Net = "tcp-tls"
if *insecure {
        c.TLSConfig = new(tls.Config)
        c.TLSConfig.InsecureSkipVerify = true
}
in, rtt, err := c.Exchange(m, net.JoinHostPort(myResolver, "853"))

va ouvrir une connexion avec le serveur myResolver, sur le port 853, et utiliser TLS. Par défaut, la bibliothèque TLS de Go vérifie le certificat, et que le nom (ou l'adresse IP) dans le certificat correspond bien (ce qui est la bonne approche). Mais cela peut être embêtant si on n'a pas acheté de certificat. D'où l'option (dangereuse !) pour débrayer la vérification (les trois lignes qui commencent par if *insecure). Voici un exemple d'utilisation (au fait, le programme est en dns-tls.go, -k active l'option dangereuse) :

%  ./dns-tls  my-resolver internautique.fr  
Error in query: x509: certificate signed by unknown authority

%  ./dns-tls -k my-resolver internautique.fr 
(time 43051 µs) 2 keys. TC=false    

Téléchargez le RFC 7858


L'article seul

RFC 7786: TCP modifications for Congestion Exposure

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


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

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

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

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

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

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

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

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

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

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

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


Téléchargez le RFC 7786


L'article seul

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

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Krishnan (Ericsson), M. Kuehlewind (ETH Zurich), B. Briscoe (Simula Research Laboratory), C. Ralli (Telefonica)
Expérimental
Réalisé dans le cadre du groupe de travail IETF conex
Première rédaction de cet article le 15 mai 2016


Le mécanisme ConEx, normalisé dans le RFC 7713, permet d'informer les routeurs situés en aval qu'un flot de données se heurte à la congestion. Il y a plusieurs façons d'indiquer cette congestion, et ce RFC le fait par une option dans l'en-tête Destination Options d'IPv6.

En effet, le mécanisme décrit dans le RFC 7713 est abstrait : il spécifie des concepts, pas comment ils sont représentés sur le câble. Notre RFC 7837, au contraire, est concret : il indique comment mettre l'information ConEx dans des champs du paquet que les équipements réseau, notamment les routeurs, pourront lire. ConEx est actuellement un projet expérimental (et même très expérimental) et il n'est pas sûr qu'il soit déployé avec enthousiasme. En attendant, puisque c'est expérimental, le but est de récolter de l'information et, pour cela, il faut du code qui tourne, avec des paquets concrets (section 1 de notre RFC). Mettre l'information ConEx dans le champ Options d'IPv4 est délicat : ce champ est de taille limitée, et pose souvent des problèmes dans le réseau. L'idée est donc d'utiliser le protocole du futur, IPv6, et ses en-têtes d'extension (RFC 2460, section 4).

La section 3 détaille les choix techniques effectués et leurs raisons. Les sections 3.3 et 4 du RFC 7713 expliquent les contraintes d'encodage concret de ConEx dans les paquets. Ici, les exigences considérées ont été :

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

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

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

L'en-tête d'extension Hop-by-hop aurait été l'option logique puisqu'elle est examinée par chaque routeur, ce qui est bien ce qu'on veut pour ConEx. Elle aurait été conforme aux principes d'IPv6. Mais, dans les routeurs actuels, le traitement de cette option se fait de manière extrêmement lente (elle n'emprunte pas le chemin rapide dans le routeur, mis en œuvre en ASIC ou FPGA), ce qui viole la troisième exigence. Le choix de l'en-tête Destination, qui est normalement de bout en bout et que les intermédiaires ne sont pas censés regarder, est donc surprenant, mais justifié. Il viole un peu la première exigence (si le paquet est encapsulé, le routeur aura du mal à voir cet en-tête). Et, surtout, analyser la chaîne des en-têtes d'extension IPv6 est anormalement compliqué. Mais il n'y avait guère d'autre choix réaliste. En pratique, certains routeurs auront donc besoin d'un changement de leurs règles de traitement des en-têtes d'extension s'ils veulent voir les marques ConEx.

(Sur la survivabilité des en-têtes d'extension IPv6 dans l'Internet, voir l'étude de Mehdi Kouhen en février 2016.)

La section 4 présente le format concret. La nouvelle option Destination se nomme CDO, pour ConEx Destination Option. Elle est mise dans un en-tête d'extension Destination Options (RFC 2460, section 4.6). Comme les autres options Destination, elle est encodée en TLV. Le type de l'option est 0x1E (30, valeur réservée aux expérimentations, non définitive), sa longueur est 1 (un seul octet, et encore, tous les bits ne sont pas utilisés) et sa valeur est composée de quatre bits (RFC 7713, notamment la section 2.1) : X (« je sais faire du ConEx »), L (« des paquets ont été perdus »), E (« de la congestion a été signalée par ECN ») et C (« pas (encore) de congestion, j'accumule des crédits »). Le dernier bit, C, est à utiliser avant qu'on détecte la congestion (RFC 7713, notamment la section 5.5).

Au passage, si vous écrivez des programmes en C qui veulent ajouter des options dans l'en-tête Destination, vous pouvez consulter mon article.

On a dit plus haut que la principale raison pour utiliser l'en-tête Destination et pas le Hop-by-Hop (qui aurait été plus logique), est le souci que les paquets restent sur le fast path des routeurs (le traitement fait par le matériel, par opposition au slow path, confié au processeur généraliste, bien plus lent). Mais le problème est que l'en-tête Destination, n'étant pas prévu pour être lu par les équipements réseau sur le chemin, peut se trouver n'importe où dans la chaîne des en-têtes (alors que l'en-tête Hop-by-hop est forcément au début, cf. RFC 2460, section 4.1). Et l'option CDO pourrait, en théorie, se trouver n'importe où dans l'en-tête Destination. Notre RFC est donc obligé de recommander (section 5) que l'option CDO soit la première dans l'en-tête Destination.

Reste à voir s'il sera effectivement possible de déployer cette option. L'ossification de l'Internet rend tout déploiement de ce type difficile (les en-têtes d'extension sont rares dans les paquets IPv6 actuels).


Téléchargez le RFC 7837


L'article seul

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

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


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

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

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

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

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

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

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

Téléchargez le RFC 7793


L'article seul

RFC 7830: The EDNS(0) Padding Option

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : A. Mayrhofer (nic.at GmbH)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 11 mai 2016


Ce nouveau RFC fait partie de la série de ceux qui tentent d'améliorer la situation du DNS pour tout ce qui concerne la protection de la vie privée. Parmi les efforts dans ce domaine, il y a une possibilité de chiffrement des communications DNS, dans le RFC 7858 (DNS-sur-TLS). Elle utilise le protocole TLS. Ce dernier ne fait rien pour dissimuler la longueur des requêtes et réponses DNS. Or, de telles métadonnées peuvent suffire à identifier les requêtes faites. Il est donc important de compléter le chiffrement avec un mécanisme de remplissage (padding). C'est ce que permet la nouvelle option EDNS normalisée dans ce RFC.

Trouver la requête effectuée uniquement à partir de la taille de la réponse est d'autant plus facile que les données DNS ne sont pas confidentielles. Un espion qui soupçonne que M. Michu fait des requêtes pour tel nom de domaine peut faire la même requête, noter la taille de la réponse chiffrée, et voir s'il trouve la même taille dans les réponses reçues par M. Michu. Voilà pourquoi il faut ajouter aux requêtes et aux réponses un nombre imprévisible d'octets, pour rendre plus difficile cette analyse des métadonnées.

Ce RFC est court car le mécanisme est très simple (section 3 du RFC). Ce mécanisme utilise une nouvelle option EDNS (EDNS est normalisé dans le RFC 6891.) Cette option porte le numéro 12 et sa partie « données » porte le remplissage. (Comme toute option EDNS, elle est encodée en TLV : un champ indique le type de l'option, ici, 12, un champ indique la longueur de l'option, et le dernier contient les données.)

Que mettre comme remplissage ? Cette question a été la plus discutée lors de la création de ce RFC (qui a été plutôt calme et consensuelle, pour le reste.) Le RFC précise que l'émetteur d'un message DNS devrait remplir avec des octets nuls (0x00). Si l'émetteur craint que certains traitements (par exemple de la compression, voyez cependant la section 6 qui demande de ne pas l'utiliser) appliqués avant le chiffrement ne suppriment l'essentiel du remplissage, il est autorisé à mettre une autre valeur. De toute façon, le récepteur doit accepter n'importe quelle valeur, pour permettre les évolutions futures. En pratique, il doit donc ignorer le contenu des données de cette option.

Pourquoi n'avoir pas simplement dit que l'émetteur pouvait mettre ce qu'il voulait, dans ce cas ? Parce qu'il semblait possible, dans ce cas, que des programmeurs naïfs utilisent de la variable non initialisée, et laissent ainsi fuiter le contenu de leur mémoire (comme dans la faille Heartbleed.) Et pourquoi n'avoir pas spécifié un remplissage avec des données aléatoires ? Parce que ce n'est pas normalement nécessaire : pour un observateur, le contenu chiffré doit apparaitre aléatoire, quel que soit le texte en clair (si TLS ne fournissait pas cette propriété, des tas d'attaques seraient possibles, par exemple à base de texte en clair connu.)

Voilà, l'essentiel du RFC tient dans cette courte section 3. Mais quelques détails suivent. Par exemple, quelle quantité d'octets mettre dans la nouvelle option ? Le RFC ne fournit pas de guide à ce sujet, il rappelle juste qu'il ne faut pas aboutir à des messages plus gros que ce que le client spécifiait dans son champ Payload size EDNS (souvent 4 096 octets mais cela dépend du client.) Le serveur DNS ne doit évidemment pas utiliser cette option si la requête ne contenait pas d'EDNS. Si elle contenait de l'EDNS sans cette option, le serveur est libre de remplir ou pas. Si la requête contenait de l'EDNS avec l'option Padding, alors, le serveur doit effectuer du remplissage.

Quelques trucs à ne pas oublier en section 6 : le remplissage augmente la taille des paquets (évidemment). Cela mènera donc à un accroissement du trafic. Dans l'Internet d'aujourd'hui, où tous les États qui en ont les moyens procèdent à une surveillance massive de leurs citoyens (RFC 7258), c'est un petit prix à payer, pour l'avantage de compliquer le travail des surveillants.

Autre piège, l'option de remplissage ne doit être utilisée que si le trafic DNS est chiffré. Autrement, non seulement elle ne servirait à rien, mais elle augmenterait le risque d'attaques avec amplification.

À noter que, comme plein d'autres champs des messages DNS (comme par exemple le QNAME, le Query Name), cette option peut servir de canal caché. Peut-être verra-t-on un jour une mise en œuvre d'IP-sur-DNS utilisant cette option ?

Notez que cette technique est indépendante du protocole de chiffrement sous-jacent, puisqu'elle est faite au niveau applicatif. DNScrypt pourrait l'utiliser (sauf qu'il a son propre système de remplissage.)

Et les mises en œuvre de cette technique ? A-t-on du code qui tourne ? getdns a le remplissage depuis sa version 0.5.1 (cf. le Changelog.) GoDNS y travaille. Wireshark peut analyser cette option. La page officielle sur cette option de remplissage liste d'autres mises en œuvre.

Daniel Kahn Gillmor, qui avait programmé cette extension dans getdns, en a profité pour faire quelques statistiques :

Ethernet Frame sizes for packet containing DNS query

                Transport    |   query to   |     query to
                   used      |  example.com |  www.example.com
   --------------------------+--------------+-------------------
               cleartext UDP |   82 octets  |   86 octets
               cleartext TCP |  108 octets  |  112 octets
                TLS over TCP |  137 octets  |  141 octets
(padded to 512) TLS over TCP |  609 octets  |  609 octets
  

On voit que le remplissage brouille la différence de taille entre les deux requêtes. Mais restons prudents : le remplissage est une bonne technique pour rendre plus difficile l'analyse des métadonnées mais il n'est pas parfait. Lisez par exemple l'excellent « Peek-a-Boo, I Still See You : Why Efficient Traffic Analysis Countermeasures Fail ».


Téléchargez le RFC 7830


L'article seul

A small DNS trick to see Sci-Hub despite censorship attempts

First publication of this article on 8 May 2016


The service Sci-Hub is a great help for the scientists, allowing them to access to a lot of scientific papers that were before locked behind paywalls. The publishing companies keep trying to censor Sci-Hub and block access to this service, for instance by taking down domain names like it happened a few days ago with sci-hub.io. If you control your DNS resolver, you can easily restore access.

Sci-Hub's domain sci-hub.io was recently taken down. There are several ways to still use Sci-Hub, such as "domain hopping" (using another TLD such as sci-hub.bz) or using Tor (the address is scihub22266oqcxt.onion). But there is one which does not seem to have been publically documented yet.

For the rest of the article, we will rely on a local DNS resolver. ("local" does not imply it is on your own machine: it may be on the local network. The important point is that you can change its configuration.) A local resolver is a great tool against DNS censorship. By default, it does not see Sci-Hub domains (NXDOMAIN means "No Such Domain"). Let's test with dig:


% dig A sci-hub.io

; <<>> DiG 9.10.4 <<>> A sci-hub.io
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 45356
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
...
;; QUESTION SECTION:
;sci-hub.io.		IN A
...
;; Query time: 1408 msec
;; SERVER: ::1#53(::1)
...

    

OK, it failed, the domain being taken down. Let's configure our local resolver to work around the problem. Sci-Hub has a public name server that answers to the Sci-Hub domains. First, we'll be using the excellent program Unbound. We just add in unbound.conf:

forward-zone:
     name:   "sci-hub.io"
     forward-addr: 31.184.194.81
     # You can also add
     # Cloudflare's name servers kay.ns.cloudflare.com
     # and eric.ns.cloudflare.com, which reply for this domain.

and we restart Unbound and it works:


% dig A sci-hub.io                

; <<>> DiG 9.10.4 <<>> A sci-hub.io
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34214
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;sci-hub.io.		IN A

;; ANSWER SECTION:
sci-hub.io.		604800 IN A 31.184.194.81

;; AUTHORITY SECTION:
sci-hub.io.		604800 IN NS sci-hub.io.

;; Query time: 42 msec
;; SERVER: ::1#53(::1)
;; WHEN: Sun May 08 14:08:02 UTC 2016
;; MSG SIZE  rcvd: 69

  

(DNS experts may discuss the use of forward-zone instead of stub-zone. The Sci-Hub servers accept recursive requests so both work. In my opinion, forward may be a bit more future-proof if the authoritative name server changes its IP address but a recursor stays in place at the old address.)

Doing the same with BIND is possible. Just put in its configuration file (somewhere/named.conf):

   zone "sci-hub.io" {
                 type forward;
                 forwarders {31.184.194.81;};
   };
    

The trick is to use the fact that 31.184.194.81 also allows DNS zone transfers. You can therefore configure your BIND as a slave for sci-hub.io. Once BIND is authoritative for this domain, it won't check with DNSSEC:

    zone "sci-hub.io" {
	         type slave;
                 masters {31.184.194.81;};
};

Note: the option dnssec-must-be-secure addresses a different issue and is not useful here.

I do not use dnsmasq but Canari Bleu does and says you have to add server=/sci-hub.io/31.184.194.81 in dnsmasq.conf.

Of course, this hack is far from perfect. It doesn't scale (imagine if there were dozens of censored domains to make accessible this way). It's brittle (the IP addresses can change without warning). But this sort of imperfect workarounds will become more and more common with the increase of politically or business-motivated censorship.


L'article seul

Google Chrome et son utilisation du DNS

Première rédaction de cet article le 8 mai 2016
Dernière mise à jour le 10 mai 2016


Une tribune sensationnaliste dans le Monde le 6 mai prétendait que « Google [avait] changé l'Internet » et portait une accusation précise : le navigateur Google Chrome utiliserait une racine DNS spécifique à Google. Passons sur le fond politique de l'article, est-ce qu'au moins les faits allégués sont exacts ?

Un petit mot au passage sur ce concept de « racine » (les explications dans la tribune publiée dans le Monde sont... floues). Un logiciel qui veut utiliser un nom de domaine (par exemple un navigateur Web qui veut aller voir https://www.laquadrature.net/fr) va devoir interroger le DNS, un système technique qui permet, à partir d'un nom de domaine, d'obtenir des informations techniques indispensables (comme l'adresse IP du serveur). Les noms de domaine sont organisés sous forme d'arbre, avec la racine représentée en haut (contrairement aux botanistes, les informaticiens mettent la racine des arbres en haut). L'interrogation du DNS est faite par un logiciel nommé résolveur, qui est en général indiqué automatiquement à la machine (c'est la plupart du temps une machine du FAI, mais on peut utiliser son propre résolveur). Le résolveur commence par la racine, d'où il est aiguillé vers les TLD puis de fil en aiguille vers tous les autres noms de domaine. On voit donc que qui contrôle la racine contrôle le DNS.

L'article publié dans le Monde dit « le navigateur Chrome de Google remplace sans avertissement l’annuaire de l’ICANN par le sien ». Au milieu de toutes les vagues affirmations de ce texte, voici un fait précis, qu'on peut contrôler. Cela prend cinq minutes à n'importe quel technicien. Avec un outil d'usage courant, tcpdump, on peut voir le trafic DNS de la machine. Lançons Chrome, tentons de visiter http://nic.la/ et observons ce trafic. (Les lignes suivantes sont triviales à interpréter pour le technicien ordinaire dont je parlais.)

11:38:24.549321 IP6 2001:691:1348:7::bad:209.27121 > 2001:67c:217c:6::2.53: 58483% [1au] A? nic.la. (35)
11:38:24.551217 IP6 2001:67c:217c:6::2.53 > 2001:691:1348:7::bad:209.27121: 58483- 0/8/9 (685)

Que voit-on ? La machine d'adresse IP 2001:691:1348:7::bad:209 a fait une requête DNS au serveur 2001:67c:217c:6::2, qui est bien un serveur de la racine (leurs adresses IP sont publiques et connues).

Amusant détail, je n'utilise personnellement pas la « racine ICANN » mais une racine « alternative », Yeti. Donc, même si on a fait un choix différent de la majorité, Chrome respecte ce choix (en fait, Chrome ne parle pas directement à la racine : comme tout bon logiciel, il parle au résolveur configuré par l'utilisateur, et ce résolveur a été configuré pour utiliser telle ou telle racine). Le complot s'effondre donc : le principal reproche fait à Google dans cet article ne repose sur rien. Alors que la vérification des faits prend quelques minutes à n'importe quel technicien, les auteurs de la tribune n'ont pas vérifié, ni demandé à un technicien de le faire.

Est-ce un accident isolé dans une tribune par ailleurs raisonnable ? Non, il y a beaucoup d'autres erreurs techniques. Par exemple, les auteurs affirment « [la racine de Google est] plus rapide puisque souvent délivré d'étapes de contrôle et de surveillance ». Enregistrer les requêtes (comme le fait la NSA) ne ralentit rien, cette affirmation est donc dénuée de sens.

Autre exemple du manque de rigueur de cette tribune, la mention du .google comme étant « la racine de Google » alors qu'il s'agit d'un banal TLD... Est-ce une distinction importante ou bien est-ce que je pinaille excessivement ? Oui, c'est important car cette erreur permet de juger le sérieux d'un texte. Imaginez un article portant sur la production laitière. L'article confond à un moment vaches et chèvres. Sans importance, puisqu'après tout ce sont bien deux mammifères produisant du lait ? Mais si un article sur ce sujet comportait une telle erreur, lui accorderait-on la moindre crédibilité ? C'est pareil ici : confondre TLD et racine, dans un article sur le DNS, est un signe d'extrême légèreté.

On notera aussi que des affirmations tout aussi fausses (« Cependant Google (et Chrome) utilise leur propre racine (copie de la racine ICANN) dont une est l’adresse IP 8.8.8.8 » se trouvent depuis longtemps sur le serveur Web de la société commerciale Open-Root, pour laquelle travaillent deux des auteurs. (8.8.8.8, alias Google Public DNS, est un résolveur DNS, qui n'a donc rien à voir avec une racine. Vaches et chèvres, encore.)

Ces erreurs techniques sont d'autant plus curieuses que, si on souhaite dire du mal de Google et mettre en garde contre le pouvoir dont jouit cette société, les exemples ne manquent pas. Google a un poids important, par sa part de marché, peut influencer ce que font les internautes, et ce poids important est certainement une question politique à traiter, comme toutes les fois où une boîte privée a trop de pouvoir. Alors, pourquoi rajouter des accusations fantaisistes ? Est-ce parce qu'il y a un risque que Chrome, un jour, fasse ce qui lui est reproché dans cette tribune ? Tout est possible mais ce ne serait pas très malin de la part de Google. En effet, l'utilisation d'une autre racine se voit (comme montré avec tcpdump plus haut). Ce ne serait pas très discret de la part de Google (la tribune parle de « substitution invisible », ce qui n'a pas de sens, vu cette visibilité du trafic réseau). D'autre part, pas mal d'entreprises utilisent en interne des TLD non-existants comme .corp, qui ne sont connus que de leurs résolveurs. Si Chrome n'utilisait pas ces résolveurs, ces TLD ne fonctionneraient pas.

Autre chose frappante, ce texte a largement circulé sur les réseaux sociaux, étant repris sans nuances, sans aucune vérification. On l'a par exemple vu cité sur le site de l'émission Arrêt sur Images. Apparemment, le fait d'être publié dans le Monde a un poids qui suffit à débrayer toute critique. (Alors qu'il s'agissait d'une tribune et pas d'un article, ce qui indique que le Monde n'a pas exercé de contrôle trop serré sur le contenu.)

Depuis, il y a eu une réponse à ce texte. Elle a été annoncée sur Twitter en utilisant le raccourcisseur d'URL de Google (goo.gl). Le site d'Open-Root utilise d'ailleurs le spyware Google Analytics. Cela indique leur niveau de cohérence (mais c'est courant chez les souverainistes : de grands discours anti-GAFA à la tribune, mais l'utilisation de tous leurs outils en pratique.) Sans compter la paranoïa « nous sommes attaqués de toute part », de la part de gens qui passent dans le Monde ou à la télé quand ils veulent, et qui sont invités à tous les colloques ministériels...

Bon, je critique cette réponse sur la forme, mais sur le fond ? Sur le fond, il n'y a rien à dire, parce qu'il n'y a pas d'éléments nouveaux : la réponse cite comme preuve que Google a son propre DNS... l'existence de Google Public DNS. Confondre un résolveur DNS public avec une racine, c'est comme l'expert en élevage cité plus haut qui confondrait vache et chèvre... C'est tellement désespérant que c'est au delà de toute discussion.

Pour les reste, pas de détails, pas de tcpdump montrant Chrome faire des requêtes à la soi-disant racine Google, rien.


L'article seul

RFC 7819: Privacy considerations for DHCP

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : S. Jiang (Huawei Technologies), S. Krishnan (Ericsson), T. Mrugalski (ISC)
Pour information
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 3 mai 2016


Le protocole DHCP est bien connu : la grande majorité des machines « client » qui se connectent à l'Internet l'utilisent pour récupérer des éléments de configuration indispensables, comme l'adresse IP à utiliser. Mais peu de gens sont conscients que DHCP peut être dangereux pour la vie privée : le client DHCP n'est en effet pas passif, il envoie au serveur des informations qui peuvent permettre de suivre à la trace une machine mobile.

DHCP pour IPv4 est normalisé dans le RFC 2131. (Un futur RFC traitera le cas de DHCP pour IPv6, qui pose des problèmes similaires.) Son principe de fonctionnement est simple : le client DHCP (la machine de M. Michu) envoie à la cantonade une requête pour demander des informations de configuration réseau, le serveur DHCP se reconnait, il répond avec ces informations. Voici une transaction DHCP, vue par tcpdump :

   21:32:13.284690 IP (tos 0x0, ttl 64, id 960, offset 0, flags [none], proto UDP (17), length 377)
    0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from b8:27:eb:84:35:e3, length 349, xid 0x4feaaa6f, Flags [none] (0x0000)
	  Client-Ethernet-Address b8:27:eb:84:35:e3
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Request
	    Client-ID Option 61, length 19: hardware-type 255, eb:84:35:e3:00:01:00:01:c7:92:bc:8a:b8:27:eb:ba:90:94
	    Requested-IP Option 50, length 4: 192.168.2.9
	    MSZ Option 57, length 2: 1500
	    Vendor-Class Option 60, length 46: "dhcpcd-6.9.0:Linux-4.4.8-2-ARCH:armv6l:BCM2708"
	    Hostname Option 12, length 5: "amour"
	    T145 Option 145, length 1: 1
	    Parameter-Request Option 55, length 14: 
	      Subnet-Mask, Classless-Static-Route, Static-Route, Default-Gateway
	      Domain-Name-Server, Hostname, Domain-Name, BR
	      NTP, Lease-Time, Server-ID, RN
	      RB, Option 119
	    END Option 255, length 0
21:32:13.299825 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 576)
    192.168.2.254.67 > 192.168.2.9.68: [udp sum ok] BOOTP/DHCP, Reply, length 548, xid 0x4feaaa6f, Flags [none] (0x0000)
	  Your-IP 192.168.2.9
	  Client-Ethernet-Address b8:27:eb:84:35:e3
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: ACK
	    Server-ID Option 54, length 4: 192.168.2.254
	    Lease-Time Option 51, length 4: 43200
	    Subnet-Mask Option 1, length 4: 255.255.255.0
	    Default-Gateway Option 3, length 4: 192.168.2.254
	    Domain-Name-Server Option 6, length 8: 192.168.2.254,149.20.64.21
	    BR Option 28, length 4: 192.168.2.255
	    END Option 255, length 0
	    PAD Option 0, length 0, occurs 264   
    

Malheureusement, dans la requête du client se trouvent plein de détails sur la machine demanderesse (section 1 du RFC). Compte-tenu de la sensibilité aux problèmes de vie privée (RFC 6973) et de l'ampleur de la surveillance de masse exercée par les États (RFC 7258), il était nécessaire de limiter cette fuite d'informations. Ce premier RFC va décrire le problème, et proposer quelques pratiques qui le limitent. Dans une prochaine étape, il y aura peut-être des modifications au protocole DHCP mais ce n'est pas encore fait.

Pour cette analyse de sécurité, la section 2 de notre RFC introduit la notion d'identificateur stable. Un identificateur stable (stable identifier) est une information envoyée par le client DHCP qui change peu ou pas dans le temps (et qui peut donc permettre de tracer une machine mobile). La stabilité peut dépendre de la mise en œuvre logicielle utilisée. Ainsi, une adresse MAC est typiquement un identificateur stable mais, si macchanger est utilisé, ce n'est plus le cas. Un identificateur stable n'est pas forcément mondialement unique.

Le gros de ce RFC est la section 3, qui liste les identificateurs envoyés par le client DHCP. Le plus évident, car il est prévu pour cela, est l'option DHCP Client Identifier (RFC 2131, section 2, et RFC 2132, section 9.14). Il est en général stable (le RFC 1533, prédécesseur du RFC 2132, recommandait même d'utiliser une adresse MAC, mais on voit parfois un nom de domaine, ou bien un DUID - décrit dans le RFC 4361). Même si on utilise un logiciel comme macchanger pour changer d'adresse MAC, pas mal de mises en œuvre de DHCP utiliseront la valeur initiale et la stockeront... pour toujours. Cette option très dangereuse peut donc annuler tout ou partie de l'effet d'autres techniques de sécurité comme celle du RFC 4941.

Moins spectaculaire, plusieurs champs de la requête transportent des identificateurs fondés sur une adresse. C'est le cas de yiadrr, qui indique l'adresse IP actuelle du client ou chaddr qui indique l'adresse MAC. Plusieurs options font de même comme la Requested IP Address (qui permet d'indiquer l'adresse IP qu'on souhaiterait recevoir).

Autre option qui envoie un identificateur stable, et souvent unique, l'option Client FQDN (RFC 4702) qui transmet au serveur le FQDN.

Après les adresses et les noms de domaine, un autre danger se présente avec les options qui permettent au client d'indiquer le logiciel qu'il utilise. C'est le cas de l'option Vendor class (RFC 2132, section 9.13, une sorte d'équivalent du User-Agent: de HTTP, dans l'exemple plus haut, elle indique une machine ARM sous Linux), du Vendor-Identifying du RFC 3925, et de toutes les options Vendor-specific information (RFC 2132, section 8.4), qui peuvent indiquer le numéro de version du logiciel utilisé, sa configuration spécifique, etc. Certes, elles ne sont pas uniques (elles ne désignent pas une machine particulière) mais elles font quand même fuiter de l'information sur le client et, combinées avec d'autres informations, elles peuvent mener à une identification unique. Une option analogue est Client System Architecture Type (RFC 4578) qui indique le type exact d'architecture pour les clients DHCP qui vont démarrer sur le réseau (par exemple avec PXE), en téléchargeant une version particulière du système d'exploitation. Si l'architecture utilisée est un peu rare, cette option donne des informations précieuses à un observateur.

En lisant cette liste, le paranoïaque peut se dire que la NSA a envoyé des gens à l'IETF pour faire normaliser le plus grand nombre possible d'extensions indiscrètes, de façon à être sûr d'identifier tous les clients DHCP observés. Il y a même une option pour indiquer l'adresse (civile, dans le monde physique, pas sur le réseau), Civic Location, dans le RFC 4776. Il est vrai que, contrairement à la plupart des options listées ici, elle est fournie par le serveur et pas par le client, et ne permet donc pas de suivre un client à la trace. Mais elle peut permettre à un observateur de savoir où, dans le monde physique, se situe le client.

Outre tous ces champs et ces options par lesquels une information souvent excessive est transmise, DHCP dispose de certains mécanismes qui peuvent être utilisés pour compromettre la vie privée (section 4 du RFC). Par exemple, l'option Client FQDN du RFC 4702, citée plus haut, sert souvent à faire des mises à jour dynamiques du DNS (RFC 2136), et, dans ce cas, l'adresse IP du client DHCP (qui peut indiquer sa localisation) et son nom, identificateur stable, sont publiés dans le DNS, que tout le monde peut consulter. On peut connaitre les déplacements d'une machine simplement en consultant ce DNS public, sans avoir besoin d'espionner des milliers de réseaux. L'observateur peut être très discret et, en toute légalité, vous suivre.

Autre mécanisme dangereux, la stratégie d'allocation du serveur DHCP. Lorsqu'un client DHCP réclame une adresse IP, le serveur peut la choisir de plusieurs façons, et certaines ont des conséquences pour la vie privée :

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

La taille très restreinte de l'espace d'adressage IPv4 complique le problème, en limitant les possibilités du serveur d'utiliser certaines stratégies d'allocation, comme l'allocation fondée sur un identificateur (le serveur DHCP n'a pas forcément assez d'adresses IP pour tous ses clients potentiels.)

Bon, OK, le client DHCP envoie des tas d'identificateurs stables. Mais en quoi est-ce dangereux ? Qu'est-ce qu'un observateur indiscret peut en faire (section 5 du RFC) ? Déjà, il peut découvrir le type de machine qu'est le client (directement, via des options comme Vendor Class, ou indirectement, via l'adresse MAC (dont le préfixe, l'OUI, dépend en général du matériel utilisé). L'espion peut aussi trouver le système d'exploitation utilisé.

Il peut aussi apprendre les réseaux que le client avait visité précédemment. Le client met en effet dans l'option Requested IP Address la précédente adresse IP qu'il avait obtenue. Si c'est une adresse publique (pas issue du RFC 1918), cela renseigne sur le précédent réseau utilisé.

L'observateur peut facilement trouver un identificateur stable à partir d'une requête DHCP (en combinant les options comme Client FQDN). Cela lui permet, s'il a accès au trafic de plusieurs serveurs DHCP, de suivre les déplacements d'une machine (c'est ce qui se produit dans les cas de surveillance massive, cf. RFC 7258.)

Dans certains cas, l'observateur n'a même pas besoin d'être présent sur le réseau du serveur DHCP : si on fait des mises à jour dynamiques du DNS, il lui suffit de faire des requêtes DNS pour suivre les changements d'adresse IP (et donc de réseau) du client.

Bref, un client DHCP en dit en général trop à son serveur, et cela permet aux machines mobiles d'être facilement pistées. Notre RFC ne fournit pas de solutions immédiates, mais elles feront l'objet d'un futur travail.


Téléchargez le RFC 7819


L'article seul

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

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : D. Saucez (INRIA), L. Iannone (Telecom ParisTech), O. Bonaventure (Université catholique de Louvain)
Pour information
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 30 avril 2016


Le protocole LISP (à ne pas confondre avec le langage de programmation) est un protocole à séparation de l'identificateur et du localisateur. Ces protocoles présentent des défis de sécurité particuliers et ce RFC est donc consacré à une étude détaillée des menaces et risques associés à LISP.

LISP est normalisé dans le RFC 6830. Il peut être utilisé dans un réseau interne ou bien sur l'Internet public et ce RFC étudie sa sécurité dans ce dernier cas, évidemment plus difficile.

Le RFC est en trois parties : la section 2 détaille le modèle de menaces (qui est l'attaquant), la section 3 expose les techniques que peut utiliser l'attaquant, la section 5 décrit les solutions possibles. Il s'agit bien de regarder les attaques génériques contre LISP, pas celles contre une mise en œuvre particulière de LISP, qui peut évidemment avoir ses bogues spécifiques.

Commençons donc par le modèle de menace (section 2). On suppose un attaquant situé quelque part sur l'Internet, éventuellement en plusieurs points de celui-ci. Il peut être sur le chemin des paquets (on path) ou pas (off path). Le premier est évidemment le plus dangereux. S'il est attaquant actif, il peut modifier des paquets et même faire des attaques de l'Homme du Milieu. Si l'attaquant est en dehors du chemin, cela va être plus difficile pour lui. Il ne peut pas modifier les paquets échangés, il peut par contre envoyer des paquets mais, pour que ceux-ci soient acceptés, il faudra qu'ils correspondent à ce qu'attendent les parties légitimes, ce qui fait que l'attaquant devra souvent deviner des informations et compter sur la chance.

Autre façon de classer les attaquants, il y a ceux qui sont internes à un site LISP et ceux qui sont externes. Les attaquants de l'intérieur sont plus dangereux car la machine qu'ils contrôlent (suite à une trahison ou un piratage) est a priori jugée de confiance.

Il faut aussi distinguer les attaquants permanents (live) des attaquants ponctuels (time-shifted). L'attaquant permanent est celui qui reste actif pendant toute la durée de l'attaque. Dès qu'il est neutralisé, l'attaque stoppe. L'attaquant ponctuel peut lancer une attaque, puis se retirer et les effets de l'attaque vont continuer. Ce genre d'attaques est évidemment bien plus dangereux.

L'attaquant peut viser le système de contrôle (control plane) de LISP ou bien son système de transmission des données (data plane). Un exemple typique est le mécanisme de correspondance (mapping) qui permet aux routeurs LISP de trouver le localisateur (le RLOC) en échange de l'identificateur (l'EID). Ce mécanisme de correspondance fait partie du système de contrôle. Si un attaquant veut détourner les paquets, il n'est pas obligé de trouver une faille dans le routage lui-même : s'il arrive à modifier les correspondances, il obtiendra le même résultat. (Comme le ferait une attaque DNS dans l'Internet classique.)

Plusieurs types d'attaques peuvent être faites contre un protocole réseau comme LISP. Il y a les attaques par rejeu, où un attaquant capture des paquets légitimes pour les rejouer intacts plus tard. Ces attaques marchent souvent, même quand les paquets sont protégés par de la cryptographie (l'attaquant n'a pas besoin de modifier les paquets, ni même de les comprendre). Il y a les manipulations de paquets (l'attaquant prend un paquet légitime et le réinjecte). Il y a la suppression complète des paquets.

Plus complexe et plus vicieux, il y a l'usurpation (spoofing). L'attaquant injecte des paquets prétendant venir d'une autre machine. C'est quelque chose qu'on voit souvent sur l'Internet. LISP est une technologie de tunnel et l'usurpation peut donc porter sur deux endroits : l'adresse externe, celle que voient les routeurs IP ordinaires (c'est le RLOC), et l'adresse interne, celle du paquet encapsulé (c'est l'EID). Identifier un usurpateur est bien plus compliqué lorsque des tunnels sont en jeu !

L'attaquant n'est pas forcément un usurpateur. Il peut très bien dire la vérité sur son adresse (rogue attack) par exemple parce qu'il se moque d'être identifié, ou bien parce qu'il est un zombie.

Autre type d'attaque, évidemment, les attaques par déni de service, où l'attaquant ne cherche pas à prendre le contrôle du système, mais à le paralyser (ou à le ralentir).

Parfois, la cible immédiate de l'attaque n'est pas la principale victime : dans les attaques par réflexion, un attaquant utilise un tiers pour renvoyer ses paquets vers la vraie victime. C'est surtout utilisé en combinaison avec l'amplification : lorsque la réponse est plus grosse que la question, un attaquant peut amplifier son trafic. En outre, pour LISP, le système de transmission est certainement bien plus rapide que celui de contrôle et il y a donc en théorie une possibilité d'attaquer le second avec le premier.

Et, bien sûr, il y a les attaques d'espionnage passif, où des grandes oreilles écoutent votre trafic pour vous surveiller, sans eux-mêmes envoyer de paquets. Grâce à Edward Snowden, l'ampleur de ce type d'attaques par les États est désormais bien connu (RFC 7258).

Bon, assez de théorie, comment fait-on avec LISP quand on est un méchant et qu'on veut effectuer une des attaques en question ? Rentrons désormais dans les détails techniques (qui nécessitent de connaitre un peu LISP : relisez les RFC 6830, RFC 7215, RFC 6832, RFC 6833 et RFC 6834). D'abord, le « glanage » (gleaning), la collecte passive d'informations sur les correspondances identificateur->localisateur (RFC 6830, section 6). Il peut être utilisé pour empoisonner le cache des correspondances d'un routeur : le méchant envoie un paquet LISP fabriqué, les routeurs innocents l'observent et enregistrent la correspondance entre l'EID et le RLOC dans leur cache et paf, le méchant a pu détourner le trafic futur. C'est un exemple d'attaque ponctuelle : l'attaquant envoie juste un paquet puis plus rien, mais l'effet persiste pendant toute la durée de vie de l'information dans le cache (quelques secondes, si on suit fidèlement les conseils du RFC 6830, section 6.2).

Autre exemple d'empoisonnement d'un routeur LISP avec de fausses informations, le champ LSB (Locator Status Bits), qui indique l'état (joignable ou pas) des machines situées sur le site de départ du paquet (RFC 6830, section 6.3). En envoyant un paquet usurpé avec un faux LSB, on peut tromper des routeurs innocents. On peut par exemple mettre tous les bits à zéro (qui signifie que le préfixe est injoignable par ce routeur), menant à une attaque par déni de service ou bien les mettre tous à zéro sauf un, menant à une surcharge de cet unique routeur. C'est également une attaque ponctuelle : ses effets se feront sentir même si l'attaquant est neutralisé.

Un point important de LISP est le test de la « joignabilité » (reachability, RFC 6830, section 6.3). LISP vérifie que la machine qui prétend être joignable, et par tel routeur, l'est effectivement. Un des outils pour cela est un numnique envoyé à l'autre machine et qu'elle doit renvoyer. Un attaquant qui arriverait à tricher avec la joignabilité pourrait pousser un routeur LISP d'entrée du tunnel (un ITR) à changer de routeur de sortie (l'ETR) au profit d'un routeur qui ne marche pas. Cela réaliserait une attaque par déni de service. Même s'il n'arrive pas à faire changer de routeur, il pourrait perturber le routage en envoyant des tas de numniques différents. (Rassurez-vous, cette attaque est plus dure à réussir qu'il ne semble, voyez la section 5.)

LISP permet que plusieurs espaces d'adressage coexistent, différenciés par leur instance ID indiquée dans l'en-tête (RFC 6830, section 5.5). Elle n'est pas authentifiée et un attaquant peut donc envoyer des paquets à une autre instance ID que la sienne.

LISP permet de l'interconnexion avec des réseaux non-LISP (RFC 6832). Ces mécanismes ont des attaques très similaires à celles qu'on peut faire contre LISP lui-même. Par exemple, un paquet avec une adresse source usurpée peut être transmis sur l'Internet par la passerelle LISP.

Mais les pires attaques se situeront sans doute sur le système de correspondance (mapping). Le point central de tous les systèmes à séparation de l'identificateur et du localisateur est de découpler deux fonctions qui, dans IP, sont confondues. Cela suit un grand principe de l'informatique : « tout problème peut être résolu en ajoutant un degré d'indirection ». Sauf que cette séparation se paie en sécurité : il faut bien, à un moment, faire correspondre identificateur et localisateur et, là, cette nouvelle fonction, la correspondance, offre de nouvelles possibilités d'attaque.

Ainsi, les messages Map-Request (RFC 6830, section 6) peuvent être utilisés de plusieurs façons. Envoyés en masse, à un système de contrôle qui est bien moins rapide que le système de transmission, ils peuvent saturer les routeurs. Comme la réponse (Map-Reply) est plus grosse que la question, ils peuvent servir à des attaques par amplification.

Et si un attaquant réussit à fabriquer de fausses réponses (Map-Reply) et à les faire accepter ? Il devra pour cela mettre le numnique correct dans ses paquets. Comme il fait 64 bits, si on a suivi les bons principes du RFC 4086 pour le générer, un attaquant qui n'est pas sur le chemin (et doit donc deviner le numnique) n'a que peu de chances de réussir. Mais attention, le numnique n'est pas une signature : il indique juste que le paquet est bien une réponse à une question posée. Si l'attaquant peut modifier les paquets, il peut empoisonner le cache de correspondance du routeur. Variante de cette attaque, si le méchant est un routeur légitime (rogue attack), il peut répondre, mais avec de fausses réponses. Il ne peut pas annoncer des préfixes quelconques mais il peut annoncer des préfixes plus généraux que ceux qu'il gère réellement (par exemple annoncer qu'il gère 192.0.2.0/24 alors qu'il ne contrôle que 192.0.2.0/26), ce qui lui permet de détourner le trafic.

Enfin, il y a les Map-Register, ces messages envoyés par les routeurs aux serveurs de correspondance pour les informer des préfixes gérés (RFC 6833, section 4.2). Ils sont authentifiés donc, normalement, un attaquant quelconque ne peut pas les usurper. Mais il reste des attaques résiduelles comme l'annonce de préfixes plus généraux que les siens.

Au passage, un problème de sécurité qu'on oublie parfois est celui de la vie privée (section 4). Les correspondances LISP sont publiques (comme les tables BGP dans l'Internet classique) et il ne faut donc pas oublier qu'on ne peut pas participer à LISP discrètement.

Et pour finir, les solutions (section 5). Comment faire pour éviter ces menaces ? Le RFC donne des conseils très généraux (« déployer soigneusement », « appliquer les règles habituelles de sécurité ») mais aussi des indications plus précises et spécifiques à LISP. Clairement, le plan de contrôle est la partie la plus sensible. Il est donc important d'utiliser les techniques d'authentification décrites dans le RFC 6833 (voir notamment sa section 6). Des extensions de sécurisation de LISP sont en cours de développement.

D'autre part, les conseils de sécurité du RFC 6830 doivent être suivis. Par exemple, quand ce RFC écrit qu'il faut limiter le rythme des Map-Request, cela doit être appliqué.

L'information obtenue par examen des paquets (comme le glanage cité plus haut) n'est évidemment pas de confiance : à n'utiliser que pour le flot de données qui contenait cette information, ou alors à vérifier avant. (Voir aussi « How to mitigate the effect of scans on mapping systems ».)


Téléchargez le RFC 7835


L'article seul

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

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : R. Penno (Cisco), S. Perreault (Jive Communications), M. Boucadair (Orange), S. Sivakumar (Cisco), K. Naito (NTT)
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 29 avril 2016


Le mécanisme de traduction d'adresses IPv4 connu sous le nom de NAT (et qui devrait plutôt être appelé NAPT pour Network Address and Port Translation, car il ne se contente pas de traduire les adresses IP) cause beaucoup de problèmes, car il casse le modèle normal de fonctionnement d'IP, modèle de bout en bout. Pour limiter les problèmes dus à ce mécanisme, plusieurs RFC posent certaines exigences que doivent respecter (en théorie) les routeurs NAT. Ce nouveau document met à jour certaines de ses exigences. Il met donc légèrement à jour les règles des RFC 4787, RFC 5382 et RFC 5508.

Ce RFC de maintenance ne s'applique qu'au « NAT44 » traditionnel, où une adresse IP publique n'est partagée que par les membres d'un même foyer, ou bien les employés d'une même entreprise. Pour le CGN, les exigences sont dans le RFC 6888.

D'abord, le suivi de connexions TCP (section 2 du RFC). Notre RFC formalise rigoureusement la machine à états que doit suivre un routeur NAT (elle est proche de celle du RFC 6146). Le RFC 5382 spécifiait bien des délais pour certains états mais sans décrire précisement la machine complète. Par exemple, l'exigence 5 du RFC 5382 donne un délai pour le temps minimum d'attente avant de considérer une connexion partiellement ouverte, ou fermée, comme abandonnée, mais il n'était pas clair si ces deux cas devaient avoir le même délai. Notre RFC tranche donc : le cas des connexions partiellement ouvertes et celui des connexions fermées sont différents et les délais devraient pouvoir être configurés différemment.

Et les paquets TCP RST (ReSeT), on en fait quoi ? Notre RFC précise clairement (suivant ce que faisait déjà le RFC 6146) qu'un paquet RST doit être considéré comme détruisant la connexion TCP et donc comme mettant fin à la correspondance dans le routeur NAT (après un délai, pour tenir compte du fait que le paquet RST a pu être reçu par le routeur NAT mais pas par la machine terminale). Attention, il faut d'abord vérifier que ce paquet RST correspond bien à une connexion existante, sinon, on permet des attaques par déni de service faciles (RFC 5961).

Les RFC 4787 et RFC 5382 précisaient qu'on pouvait utiliser le même couple {adresse IP externe, port externe} pour des connexions allant vers des machines extérieures différentes. Mais ils ne traitaient que du cas où il n'y avait qu'une machine interne qui allait vers ces machines extérieures. Désormais, on précise (section 3 de notre RFC) que cette utilisation est également valables si plusieurs machines internes se connectent. Sans cette règle, il faudrait beaucoup plus de ports externes disponibles, ce qui poserait un problème avec les environnements où le facteur de partage d'adresses est important (cf. RFC 6269).

Est-ce qu'un routeur NAT doit/peut utiliser les mêmes correspondances pour UDP et TCP (section 5 de notre RFC) ? Ce n'est pas précisé dans les RFC 4787 (exigence 1) et RFC 5382 (exigence 1). On fait une connexion TCP sortante, est-ce qu'un paquet UDP sortant va réutiliser la même correspondance ? La règle est désormais explicite : non, il ne faut pas ; par défaut, les correspondances doivent être spécifiques à un protocole (donc, différentes pour UDP et TCP).

Autre piège du NAT, le fait qui peut parfois changer une distribution aléatoire des ports en une distribution prévisible. Cela pose un problème pour certaines méthodes de sécurité qui dépendent du caractères imprévisible (par exemple le RFC 5452). Notre RFC reprend (section 9) une recommandation de la section 4 du RFC 6056 : un routeur NAT ne doit pas choisir les ports de sortie de manière prévisible ou régulière.

Comme d'habitude, la fragmentation est une source d'ennuis (section 10). Notre RFC rappelle donc qu'il faut suivre les règles de la section 5.3.1 du RFC 6864, notamment sur le caractère unique et imprévisible de l'identificateur de fragment.

Le routeur NAT voit parfois passer des paquets en « épingle à cheveux » (hairpinning). Cela désigne les paquets (section 12) qui, venus du réseau interne, y retournent, après être passés par le routeur. Si le réseau interne est 172.17.42.0/24, et qu'un serveur HTTP est sur la machine 172.17.41.1 et accessible de l'extérieur en 192.0.2.71, alors, une machine interne qui tente d'aller en http://192.0.2.71/ va envoyer des paquets qui iront au routeur NAT, prendront un virage en épingle à cheveux et reviendront dans le réseau interne, vers 172.17.41.1. Historiquement, pas mal de routeurs NAT étaient incapables de gérer ce cas. La situation est désormais meilleure mais il reste des cas limites. Ainsi, l'exigence 7 du RFC 5508 devait rappeler que le virage en épingle à cheveux était possible même en ICMP. Notre RFC insiste sur le respect de cette règle.

Enfin, la sécurité (section 13). Notre RFC estime que ses exigences renforcées vont améliorer la sécurité. Par exemple, des règles strictes (sections 7 et 11) sur la suppression des correspondances dans la table du routeur NAT évitent qu'un attaquant puisse garder ouvertes des correspondances qui devraient être fermées (et la mémoire récupérée). Les règles sur les ports sources imprévisibles de la section 9 rendront (entre autres) plus difficile le suivi des machines situées derrière un routeur NAT.

Notez enfin qu'il y a des gens qui prétendent avoir un brevet sur certaines de ces recommandations...


Téléchargez le RFC 7857


L'article seul

Le mystère DNS Free rebondit

Première rédaction de cet article le 24 avril 2016


J'ai déjà parlé ici de la bogue DNS de Free affectant certains domaines signés avec DNSSEC. Six mois après, elle n'a pas été réparée et le problème se montre en fait encore plus complexe qu'à première vue.

Le problème a été signalé sur la liste FRnog et analysé par Rémy Duchet. En gros, certains usagers de Free n'arrivent pas à aller en http://test-yann.myshopify.com/. Si on regarde avec dig, on voit bien un problème DNS (ici, j'interroge explicitement un des résolveurs DNS officiels de Free, puisque j'ai un résolveur local) :


% dig @212.27.40.240 test-yann.myshopify.com 

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> @212.27.40.240 test-yann.myshopify.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 393
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;test-yann.myshopify.com. IN A

;; Query time: 27 msec
;; SERVER: 212.27.40.240#53(212.27.40.240)
;; WHEN: Sun Apr 24 17:00:03 CEST 2016
;; MSG SIZE  rcvd: 52

    

Ah, en effet, nous avons un problème (SERVFAIL = Server Failure). Avec d'autres résolveurs de Free, pas de problème. Et ça varie dans le temps (en d'autres termes, des fois, ça marche, des fois, ça marche pas). On peut également tester avec les sondes RIPE Atlas, dans l'AS de Free, 12322 :

% atlas-resolve -r 500 --as 12322 -t A test-yann.myshopify.com
[ERROR: SERVFAIL] : 61 occurrences 
[23.227.38.68 23.227.38.69 23.227.38.70 23.227.38.71] : 133 occurrences 
[TIMEOUT(S)] : 1 occurrences 
Test #3682131 done at 2016-04-24T14:57:13Z

Cela montre bien que certains résolveurs de Free ont le problème SERVFAIL mais pas tous.

Si on essaie avec l'option +cd (Checking Disabled, couper la validation DNSSEC), tout marche :


% dig +cd @212.27.40.240 test-yann.myshopify.com 

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> +cd @212.27.40.240 test-yann.myshopify.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18276
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 22, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;test-yann.myshopify.com. IN A

;; ANSWER SECTION:
test-yann.myshopify.com. 1800 IN CNAME shops.shopify.com.
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )
test-yann.myshopify.com. 1800 IN CNAME shops.shopify.com.
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )
test-yann.myshopify.com. 1800 IN CNAME shops.shopify.com.
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )
test-yann.myshopify.com. 1800 IN CNAME shops.shopify.com.
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )
test-yann.myshopify.com. 1800 IN CNAME shops.shopify.com.
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )
test-yann.myshopify.com. 1800 IN CNAME shops.shopify.com.
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 1800 IN RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )
shops.shopify.com.	1800 IN	A 23.227.38.71
shops.shopify.com.	1800 IN	A 23.227.38.69
shops.shopify.com.	1800 IN	A 23.227.38.70
shops.shopify.com.	1800 IN	A 23.227.38.68

;; AUTHORITY SECTION:
shopify.com.		6458 IN	NS ns4.p19.dynect.net.
shopify.com.		6458 IN	NS ns3.p19.dynect.net.
shopify.com.		6458 IN	NS ns1.p19.dynect.net.
shopify.com.		6458 IN	NS ns2.p19.dynect.net.

;; Query time: 41 msec
;; SERVER: 212.27.40.240#53(212.27.40.240)
;; WHEN: Sun Apr 24 17:44:13 CEST 2016
;; MSG SIZE  rcvd: 2376

    

On a la réponse mais on voit bien qu'il y a un problème : ces enregistrements DNS CNAME (Canonical Name) répétés ne sont pas normaux. Il ne sont pas dans les serveurs faisant autorité pour le domaine :


%  dig @ns1.p19.dynect.net test-yann.myshopify.com  

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> @ns1.p19.dynect.net test-yann.myshopify.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7499
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 3, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;test-yann.myshopify.com. IN A

;; ANSWER SECTION:
test-yann.myshopify.com. 600 IN	CNAME shops.shopify.com.
test-yann.myshopify.com. 600 IN	RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 12663 myshopify.com.
				K3oRwkmXUkzNYbFO1jNLGLrSkhaRRBnKeGvld9YdcZo+
				nUOpJzGUECTzrzOTBGpbGXdJB5M3nJ6pebAGpr46m5Rk
				HfG3+FOdgCRS+CG5lpu0+KC8w80718ywOFO8LROdIjwm
				h4swblM+0Aft4o1lj5ChnCBefWgn2Cs4qSqMT0g= )
test-yann.myshopify.com. 600 IN	RRSIG CNAME 5 2 600 (
				20160519013040 20160419013040 39852 myshopify.com.
				lBsyv5zrQ4twd4LNzLrdQpHWyxL9SQGM2wfhVR/GfnWE
				TXNV3wyW5bIwRDySbmdRg9RLiz9h1sBFByIeITYEJeKv
				7daLBZSwoI7551mz0jJX5fMgEuW7FEFOP25pYb6p5o1r
				1VFvc47+X8qTLaV5j0Uz+PXJjFBvF7GB4i3gFb0= )

;; AUTHORITY SECTION:
test-winkel.myshopify.com. 60 IN NSEC test1012345.myshopify.com. CNAME RRSIG NSEC
test-winkel.myshopify.com. 60 IN RRSIG NSEC 5 3 60 (
				20160519013040 20160419013040 12663 myshopify.com.
				BHS+QE4Pdu0qFdTW2XHN4Z6mbiqu3eb89UhwO3f5/C7W
				vpQmlNEmuYNlUlAHgUWbXvCwmDr+9k0bVZuiZh0UuSCp
				pveXWvYzr6nJjCRy5CZoUJy6C60Dyt1LfW2kCNTXUdjX
				Vp8HwMlKN0np6jxe2o/ryU/BphzdYA1OEmqp9/0= )
test-winkel.myshopify.com. 60 IN RRSIG NSEC 5 3 60 (
				20160519013040 20160419013040 39852 myshopify.com.
				I8LqnvjOSLhivVteqv6gqeeytZ9YZU9heYIj/hNfYUz+
				vOQ2PQBCk7N0ujbI9vWpFkj+3YSNnsxBshxjVZfWQoLp
				Cpde8Ir+zP8WK95/04VQBpU1HjI7QBAARkPCD0YCnTBY
				U/hTVe6gcB43c9CFAUaJ5qynRmnTZFIsvtcGBz8= )

;; Query time: 22 msec
;; SERVER: 2001:500:90:1::19#53(2001:500:90:1::19)
;; WHEN: Sun Apr 24 17:45:54 CEST 2016
;; MSG SIZE  rcvd: 831

Donc, ce sont les résolveurs de Free qui les ont inventé. La bogue est clairement de la responsabilité de Free.

Dans mon article précédent, j'avais émis l'hypothèse que le problème était lié à l'utilisation de NSEC3 (RFC 5155) et des jokers. Ici, la zone est signée avec NSEC, pas NSEC3 (ce qui est curieux, d'ailleurs, puisque cela permet de connaitre la liste des clients de shopify.com), donc NSEC3 ne semble pas responsable. On retrouve par contre les jokers, dont l'interaction avec DNSSEC est régulièrement une source d'ennuis. D'une façon ou d'une autre, une combinaison de caractéristiques de la zone myshopify.com déclenche la bogue, multiplie les CNAME (la réponse du résolveur de Free a une taille supérieure à la MTU d'Ethernet...), l'enregistrement NSEC obligatoire est supprimé, et paf.

En résumé, je ne sais pas quel logiciel résolveur utilise Free (aucun des logiciels que je connais, comme Unbound ou BIND, ne montre ce comportement) mais il est bogué et devrait impérativement être réparé, si on veut que DNSSEC soit plus largement utilisé.

Et du côté de l'utilisateur ordinaire, que peut-on faire ? Le client final peut utiliser son propre résolveur (ce qui est une bonne idée, de toute façon), le webmestre qui veut publier des choses accessibles aux utilisateurs de Free ne peut pas grand'chose, à part peut-être configurer sa zone DNS de manière plus conservatrice (les jokers sont presque toujours une mauvaise idée).


L'article seul

RFC 7787: Distributed Node Consensus Protocol

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Téléchargez le RFC 7787


L'article seul

RFC 7788: Home Networking Control Protocol

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Téléchargez le RFC 7788


L'article seul

RFC 7806: On Queuing, Marking, and Dropping

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : F. Baker, R. Pan (Cisco)
Pour information
Réalisé dans le cadre du groupe de travail IETF aqm
Première rédaction de cet article le 21 avril 2016


Au cœur de l'Internet se trouvent les routeurs, et la façon dont ils traitent les paquets IP est cruciale pour le bon fonctionnement du réseau. C'est particulièrement important lorsque le trafic augmente et que les files d'attente dans les routeurs se remplissent. Que faire, alors ? Ce nouveau RFC discute des stratégies des routeurs confrontés à des files d'attente bien remplies.

Pas de « bonne » ou de « mauvaise » méthode dans ce RFC mais une discussion des possibilités. Il y a longtemps que le sujet est discuté, souvent avec des termes dangereux, car trop chargés, comme « juste » (qu'est-ce qui est juste ? Quels paquets jeter lorsque la file d'attente est pleine ? Les plus anciens ? Les plus gros ? Ceux venant de certains réseaux ?) Ainsi, le RFC 970 parle de gestion juste de la file d'attente... Le problème (à part la question de philosophie « qu'est-ce que la justice ? ») est que toute politique de gestion de la file d'attente peut entrainer des adaptations non souhaitées de la part des machines connectées au réseau (si on jette en priorité les paquets les plus gros, on encourage les machines à envoyer des paquets plus petits, comme dans le Silly Window Syndrome).

Sur la question de principe de l'équité ou de la justice, il faut toujours lire l'article de référence, « Flow Fairness: Dismantling a Religion ».

Historiquement, des modèles de trafic peu réalistes avaient été utilisés. Par exemple, certains modèles partent du débit moyen d'un flot tout au long de son existence et raisonnent là-dessus. Mais le trafic Internet est tout, sauf moyen. Il est plutôt en quanta, avec des sursauts brusques. Par exemple, une caméra va envoyer trente images par seconde et cela se traduira par beaucoup de données lorsqu'une nouvelle image est disponible, puis un silence d'un trentième de seconde avant l'image suivante.

Au passage, j'ai parlé de flot sans l'expliquer. Le terme est courant dans les discussions réseau mais souvent assez flou. Cela peut désigner une session du protocole de transport (identifiée par le fameux tuple à cinq éléments du RFC 2990), tous les paquets entre deux machines données, tous les paquets vers une machine donnée...

Autre question pratique dès qu'on discute d'équité entre les flots, comment est-ce qu'on la mesure, pour déterminer si elle est respectée ou pas ? Le RFC 7141, entre autres, se penche sur cette question.

Le gros du RFC est formé par la section 3, qui discute des outils habituels de gestion des paquets par les routeurs : mettre en file d'attente (queuing), marquer les paquets (marking) et les jeter (dropping). Tous ces outils sont indispensables (tant que la mémoire des routeurs sera finie, et donc les files d'attente n'auront pas une taille illimitée, il faudra parfois jeter des paquets) et sont interprétés par le reste du réseau comme des signaux indiquant l'approche ou le début de la congestion.

Ce RFC discute de divers concepts, il ne spécifie pas un algorithme. Pour un exemple d'algorithme récent de gestion des files d'attente des routeurs, voir FQ-Codel, même s'il ne suit pas forcément les avis du RFC.


Téléchargez le RFC 7806


L'article seul

RFC 7838: HTTP Alternative Services

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : M. Nottingham (Akamai), P. McManus (Mozilla), J. Reschke (greenbytes)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 15 avril 2016


Une nouveauté dans le monde HTTP : ce RFC décrit un mécanisme permettant d'indiquer des endroits alternatifs où trouver le contenu demandé. Ce n'est pas une classique redirection : l'URI reste le même, on découple simplement l'identificateur (l'URI) et le localisateur (l'endroit où chercher et le protocole à utiliser).

Ce concept est assez nouveau dans le monde HTTP (section 1 du RFC). En effet, le RFC 7230 tend à mélanger l'identificateur d'une ressource (http://www.example.com/foo/bar) et les moyens d'y accéder (la même ressource peut aussi être en https://www.example.com/foo/bar voire sur un miroir à un URL très différent). Le but du mécanisme de ce nouveau RFC 7838 est de séparer plus clairement identificateur et localisateur.

Quelques exemples pratiques sont donnés dans cette section 1 :

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

Actuellement, ce genre de choses est fait par des redirections HTTP explicites (codes 301, 302, 307 ou 308, voir le RFC 7231, section 6.4). L'URL vers lequel on est redirigé est montré par le navigateur (ce qui n'est clairement pas une bonne idée dans le cas de redirections temporaires comme 307). Autre façon de faire, un relais, qui se connecte au serveur effectif, sans le dire du tout au client HTTP. Les « services alternatifs » de ce RFC 7838 sont situés entre les deux façons : annoncés au client HTTP mais pas mémorisés et pas montrés à l'utilisateur (l'URI ne change pas). Le contexte de sécurité n'est pas modifié (si l'URI commençait par le plan https://, le service alternatif devra donc présenter un certificat valide), le champ Host: de la requête HTTP contiendra toujours le nom original (notez qu'il existe désormais un champ Alt-Used: pour indiquer le nom alternatif, cf. section 5). Normalement, l'utilisateur ne verra donc pas qu'on utilise un service alternatif (ceci dit, comme son logiciel client, lui, est au courant, des options de déboguage pourront permettre de l'afficher, contrairement à ce qui se passe avec un relais).

La solution est en deux parties : des concepts abstraits (section 2) puis des mécanismes concrets pour les différents protocoles, dans les sections 3 et 4. Commençons par le cadre abstrait. Un « service alternatif » existe lorsqu'un serveur d'origine (concept lui-même défini dans le RFC 6454, section 4) sait que ses ressources sont accessibles avec une combinaison {protocole, serveur, port} différente. Un tel service alternatif fait autorité (au sens du RFC 7230, section 9.1), ce n'est pas un simple miroir, ni un cache. Notez que la granularité est pour une origine complète (la combinaison {protocole, serveur, port}) : on ne peut pas faire un service alternatif qui couvrirait uniquement le chemin /foo de l'URI.

Un exemple de service alternatif ? Mettons que l'origine soit {http, www.example.com, 80} et que les mêmes ressources soient accessibles en HTTP 2 à {h2, new.example.com, 81}, alors on peut dire que ce {h2, new.example.com, 81} est un service alternatif de l'origine.

Notez que j'ai appelé « protocole » le premier membre du tuple. Ce n'est pas le plan (scheme) dans l'URI (plan que pas mal de gens appellent à tort protocole). En effet, cette valeur est plus spécifique que le plan, elle peut inclure des détails techniques supplémentaires (par exemple, lorsque le plan est http://, on peut y accéder avec les protocoles http ou h2, ce second désignant HTTP 2.) Le protocole, pour les services alternatifs, est un nom ALPN (RFC 7301 et le registre IANA ALPN).

Le tuple {protocole, serveur, port} peut être accompagné d'une durée de vie, indiquant combien de temps le client HTTP peut garder en mémoire l'information sur le service alternatif.

Au passage, un mot de sécurité : le client doit évidemment être conscient que, si la communication n'est pas sécurisée (par exemple par TLS), il peut être envoyé vers un faux service alternatif (section 9). Si le service d'origine n'a pas TLS mais que le service alternatif l'a, et présente un certificat au nom du service d'origine, c'est bon. Si aucun des deux n'a TLS, le risque d'avoir été trompé est bien plus élevé. Il n'est donc pas forcément prudent d'utiliser les services alternatifs sans TLS.

Notons enfin que les services alternatifs sont optionnels. Le client n'est pas obligé de les utiliser (d'autant plus que les clients HTTP actuels ne gèrent pas ces services et n'utiliseront donc pas les alternatives, tant qu'ils n'ont pas été mis à jour). Le serveur d'origine doit donc rester prêt à assurer les requêtes.

Maintenant, les mécanismes pour signaler ces services alternatifs. En HTTP 1, en utilise l'en-tête Alt-Svc: (section 3, et désormais dans le registre IANA). La réponse contient, par exemple :

Alt-Svc: h2="new.example.org:80"      
    

Cela indique que le client devrait plutôt aller voir avec le protocole h2 (HTTP 2), sur la machine new.example.org. Si on ne change que le protocole et le port, on pourrait avoir :

Alt-Svc: h2=":8000"
    

Il peut y avoir plusieurs valeurs, dans l'ordre des préférences décroissantes :

Alt-Svc: h2="alt.example.com:8000", h2=":443"
    

Par défaut, le service alternatif peut être mémorisé par le client pendant 24 h. Si on veut changer cette durée, on utilise le paramètre ma (Maximum Age, en secondes) :

Alt-Svc: h2=":443"; ma=3600
     

Si le serveur veut qu'on oublie tout ce qu'on a mémorisé sur les services alternatifs, et n'a pas envie d'attendre l'expiration des caches, il envoie la valeur spéciale clear :

Alt-Svc: clear
    

À part ce paramètre ma, et un autre paramètre persist (qui indique que, contrairement au comportement par défaut, le client HTTP ne devrait pas vider cette information de son cache si sa configuration réseau change), d'autres paramètres sont possibles dans le futur. Ils devront passer par le procédure « Examen par un expert » du RFC 5226 et seront mis dans le registre IANA.

Et si on utilise HTTP 2, où on est en binaire et plus en texte, et où les en-têtes sont représentés d'une façon complètement différente ? Dans ce cas, on se sert de trames du type ALTSVC (section 4). C'est une extension au protocole original. La trame ALTSVC a le type 0xa (10, dans le registre IANA) et contient un champ Longueur (de l'origine), l'origine, et le service alternatif sous une syntaxe identique à celle de la section précédente.

On l'a vu, le service alternatif fait normalement autorité et doit donc gérer les mêmes ressources. Que se passe-t-il si un serveur maladroit redirige vers une machine qui n'est pas configurée comme service alternatif ? Idéalement, cette machine ne faisant pas autorité doit répondre 421 (RFC 7540, section 9.1.2). Le client doit alors réessayer avec un autre service alternatif, s'il existe, ou bien avec le serveur d'origine. (Aujourd'hui, je crois qu'il est plus fréquent que la machine ne faisant pas autorité renvoie les ressources de sa configuration par défaut.)

Un petit mot d'histoire : ce système des services alternatifs via d'une solution spécifique à Chrome qui se nommait Alternate-Protocol:.


Téléchargez le RFC 7838


L'article seul

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

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : R. Sparks (Oracle)
Pour information
Première rédaction de cet article le 13 avril 2016


Un des gros avantages de travailler à l'IETF est qu'il existe un ensemble d'outils de travail en groupe très perfectionnés, permettant de gérer un grand nombre de documents qui changent tout le temps. Dans la plupart des SDO, ou organisations similaires, on a juste des piles de documents Word (ou, dans les dernières années, Google Docs) inexploitables. Comme le gros du travail IETF est fait sur des listes de diffusion, un des outils les plus cruciaux est le moteur de recherche dans ces listes de diffusion. Mais aucun outil n'est parfait et ce nouveau RFC est une liste de points à améliorer dans l'outil actuel, liste fondée sur l'expérience récente.

Ce https://mailarchive.ietf.org/ permet notamment de retrouver un ou plusieurs messages, parmi les centaines de messages échangés sur les listes IETF chaque jour. Voici un exemple de recherche de « tcp encryption eliot » (Eliot = Eliot Lear, auteur entre autres des RFC 1918, RFC 4192, RFC 6557...). On y voit la liste des messages correspondants en haut à droite, à gauche les noms des listes (en général, des groupes de travail IETF) où les messages apparaissent, en bas à droite l'URL stable du message en cours (ce qui permet des références précises lorsqu'on affirme « Brian Trammel a dit que ») :

L'outil actuel avait eu comme cahier des charges le RFC 6778 et avait été déployé en janvier 2014. Notre nouveau RFC liste les améliorations souhaitées.

Par exemple, lorsqu'on choisit « Group by Thread », la liste résultante est plate, sans hiérarchie. Cela rend difficile de voir où un fil de discussion commence et où il finit :

Notre RFC demande que, dans les améliorations de l'outil, l'affichage montre la hiérarchie.

Autre problème, il n'y a pas actuellement de boutons de navigation (message suivant/précédent par date, ou suivant le fil de discussion), que cela soit dans la liste des messages affichés, ou bien lorsqu'on regarde un seul message. Le RFC demande que ces boutons soient ajoutés.

C'est en lisant ce RFC que j'ai appris qu'on pouvait changer la taille de la fenêtre où s'affiche la liste des messages. Je la croyais fixe, et c'était apparemment le cas de bien des utilisateurs. Le RFC demande donc qu'on rende cette possibilité d'agrandissement plus évidente (personnellement, je n'ai pas trouvé). En prime, la façon dont est faite la troncation aujourd'hui ne semble pas rationnelle. Ici, on voit bien que les sujets sont coupés (et la fin remplacée par des ellipses) sans vraiment de raison.

Le service actuel est difficile à utiliser sur un petit écran, comme celui des phono sapiens puisque les divers éléments de l'interface sont toujours présents. Pour une interface riche, il vaudrait mieux être responsive, ce que demande le RFC (par exemple, on pourrait supprimer le menu des filtres quand l'écran est trop petit).

Par contre, sur des grands écrans, l'interface actuelle est au contraire trop économe et sous-utilise l'écran.

Enfin, notre RFC regrette que l'interface actuelle ne marche guère sans JavaScript. La prochaine version doit évidemment être capable de fonctionner sans JavaScript, quitte à accepter quelques fonctions en moins (comme les filtres appliquées dynamiquement).

Reste à développer, maintenant... Je n'ai pas encore vu d'appel d'offres.


Téléchargez le RFC 7842


L'article seul

RFC 7828: The edns-tcp-keepalive EDNS0 Option

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : P. Wouters (Red Hat), J. Abley (Dyn), S. Dickinson (Sinodun), R. Bellis (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 11 avril 2016
Dernière mise à jour le 12 avril 2016


Historiquement, le DNS utilisait surtout UDP et le transport sur TCP ne servait qu'à des cas particuliers, comme lorsqu'un client DNS ré-essayait avec TCP de récupérer des données trop grosses pour UDP. Depuis le RFC 7766, ce n'est clairement plus le cas : TCP est désormais aussi utilisable qu'UDP pour le DNS. Mais les mises en œuvre typique du DNS sur TCP ont des restrictions, par exemple des délais maximum d'attente avant de « raccrocher » qui sont trop courtes, de l'ordre de quelques secondes lorsqu'il n'y a plus de trafic sur la connexion. Ce nouveau RFC propose un mécanisme EDNS permettant au client DNS de signaler au serveur qu'il souhaite garder la connexion ouverte, si le serveur est d'accord, s'il vous plait.

Utiliser une connexion TCP par requête DNS serait en effet très inefficace, notamment question latence. Il faudrait effectuer la triple poignée de mains TCP à chaque requête. Le DNS sur TCP n'est envisageable que si les connexions restent ouvertes et que la même connexion peut servir pour plusieurs requêtes. Dans ce cas, lorsque la connexion a déjà été ouverte, la latence peut être aussi faible qu'avec UDP, voire meilleure (dans le cas de données de grande taille, par exemple avec DNSSEC, plus besoin d'essayer d'abord sur UDP). Reste une question pour le serveur DNS : faut-il laisser la connexion ouverte dès qu'il n'y a plus de requêtes à traiter ? Cette nouvelle option EDNS edns-tcp-keepalive permet au client DNS d'indiquer que, lui, il est prêt à réutiliser la connexion et qu'il souhaite qu'on la garde ouverte.

Le serveur souhaite économiser ses ressources (mémoire, notamment). Contrairement à UDP, TCP nécessite que le serveur garde un état. Imaginons que chaque connexion TCP prenne une entrée dans un grand tableau des connexions TCP en cours. Si c'était « open bar » pour les clients, qu'ils puissent ouvrir autant de connexions qu'ils veulent, et les garder éternellement ensuite, le tableau serait vite rempli, menant à un déni de service. (Et si vous pensez qu'à la place du tableau, une structure de données dynamique, grossissant automatiquement, résoudrait le problème, rappelez-vous que la mémoire du serveur est finie...) Le serveur choisit donc s'il garde les connexions ouvertes, et combien de temps.

Au passage, la section 1 du RFC rappelle aussi qu'UDP a des problèmes sérieux, notamment parce qu'il permet des attaques par réflexion et parce qu'il implique, pour les grosses données, de la fragmentation, qui est en général une source d'ennuis (voir par exemple «  Fragmentation Considered Poisonous de Herzberg et Shulman). D'où cet encouragement, depuis des années, à utiliser de plus en plus TCP.

La section 3 est la partie centrale du RFC, la spécification de la nouvelle option. Elle utilise EDNS (RFC 6891). Elle permet d'indiquer le délai d'attente avant la fermeture de la connexion, délai qui commence à courir lorsque la connexion devient inactive (« idle », cf. la section 3 du RFC 7766).

L'option se nomme edns-tcp-keepalive et a reçu le code 11 (stocké dans le registre des options EDNS). Elle prend un seul argument, encodé sur deux octets, TIMEOUT qui indique la durée du délai de garde, exprimée en unités de 100 millisecondes. Cette valeur n'apparait que dans les réponses du serveur, pas dans les requêtes du client. Si TIMEOUT vaut 600, cela signifie que les connexions restent ouvertes pendant une minute après la dernière requête reçue.

Ensuite, une fois cette option définie, comment on s'en sert ? Elle ne doit évidemment pas être utilisée sur UDP, où elle n'aurait aucune signification. Le client doit utiliser cette option pour signaler qu'il souhaiterait garder cette connexion ouverte (il ne doit pas indiquer de valeur pour TIMEOUT). Le serveur utilise cette option pour indiquer le temps pendant lequel il va garder la connexion (rappelez-vous que le client peut demander ce qu'il veut, c'est le serveur qui décide). Le client est censé « raccrocher » juste avant l'expiration de ce délai. Une valeur de 0 pour TIMEOUT signifie « raccroche tout de suite » (un serveur l'envoie, par exemple, lorsqu'il est soumis à un fort stress et n'a plus de ressources disponibles.)

Au passage, si le serveur n'a plus envie de supporter cette connexion, pourquoi ne raccroche-t-il pas lui-même, au lieu de demander au client de le faire ? C'est parce que le pair TCP qui ferme la connexion le premier passe ensuite en état TIME-WAIT (RFC 793, section 3.5) et que cela l'oblige à garder un état pendant deux fois la durée de vie maximale d'un segment TCP (soit quatre minutes en tout). Il vaut donc mieux demander au client de le faire. Par contre, après avoir envoyé le TIMEOUT=0, le serveur va avoir un délicat arbitrage à faire entre attendre que le client raccroche et fermer de lui-même la connexion (et donc garder une prise en état TIME-WAIT) quand le client n’obtempère pas suffisamment vite.

La section 5 du RFC recommande d'ailleurs aux serveurs de suivre l'activité de leurs clients et de « punir », d'une façon ou d'une autre, ceux qui violeraient ces règles, par exemple en continuant à envoyer des requêtes alors qu'on leur a demandé de raccrocher.

J'insiste mais cela vaut la peine d'être dit et répété : cette option edns-tcp-keepalive ne diminue pas la liberté des clients et des serveurs DNS. En cas de problème (tableau des connexions TCP en cours presque plein, par exemple), clients et serveurs sont libres de couper les connexions TCP plus tôt, ce qu'on appelle le « TCP session management ».

Comme d'habitude avec toute nouvelle option, on peut s'attendre à des problèmes avec les stupides middleboxes. Une requête contenant cette option peut ainsi être jetée alors qu'elle ne l'aurait pas été sans l'option. Une stratégie de repli comme celle de la section 6.2.2 du RFC 6891 peut donc être utile.

Merci à Kim-Minh Kaplan pour d'utiles précisions sur TCP.


Téléchargez le RFC 7828


L'article seul

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

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : A. Zimmermann (NetApp), W. Eddy (MTI Systems), L. Eggert (NetApp)
Pour information
Réalisé dans le cadre du groupe de travail IETF tcpm
Première rédaction de cet article le 11 avril 2016


Un peu de nettoyage dans l'imposante bibliothèque des RFC sur le protocole TCP. Bien des extensions à TCP n'ont jamais connu de déploiement réel dans la nature et d'autres, qui ont été déployées, ne sont plus utilisées depuis longtemps. Un grand nombre de RFC sont donc reclassifiés « intérêt historique seulement » ou bien « pour information ». Cela concerne surtout des vieux RFC, qui étaient bien oubliés de toute façon.

Le RFC 7414 (le guide des normes sur TCP) avait déjà fait cette classification mais sans mentionner le changement de statut dans la base de l'éditeur des RFC. C'est désormais chose faite. Il y a aussi des RFC très anciens qui n'avaient jamais été classés comme le RFC 675, la première norme TCP, à l'époque où les RFC n'avaient pas de statut clair. Remplacé par le RFC 793 (avec des modifications sérieuses du format des paquets), ce RFC 675 est désormais « intérêt historique seulement ». (À noter que le précédent grand nettoyage de TCP était dans le RFC 6247.)

Dans la liste, le RFC 1078 (TCPMUX) a suscité quelques controverses car il est apparemment mis en œuvre dans certains systèmes d'exploitation (la partie serveur, pas la partie client, qui semble absente). On ne peut donc pas le caractériser comme « non déployé ». Néanmoins, les failles, notamment de sécurité, de TCPMUX font que le RFC 1078 se retrouve lui aussi classé « intérêt historique seulement ». Notre RFC donne la liste des problèmes techniques qu'il pose.

Ce sort touche aussi des RFC récents comme le RFC 6013, proposition d'une ouverture de connexion TCP plus rapide et plus légère, publiée en 2011, implémentée, mais jamais déployée, et remplacée depuis par des RFC qui ont eu plus de succès comme le RFC 7413.

D'autres RFC sont seulement classés « pour information ». C'est le cas du RFC 700 car il ne décrivait pas un protocole mais était une analyse des premiers résultats du déploiement de TCP, ou du RFC 814, un important document de réflexion sur des concepts comme les adresses, les ports et les routes, toujours d'actualité, mais qui n'avait jamais reçu de classement auparavant. Parmi les autres RFC désormais classés, le RFC 889, qui était également un compte-rendu d'expérience sur la variation de certains paramètres numériques de TCP, comme le délai maximal d'attente. Faisons enfin une place à part pour le très utile RFC 1071 qui n'est pas abandonné, bien au contraire, juste classé comme « pour information ».


Téléchargez le RFC 7805


L'article seul

RFC 7808: Time Zone Data Distribution Service

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : M. Douglass (Spherical Cow Group), C. Daboo (Apple)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tzdist
Première rédaction de cet article le 1 avril 2016


Ah, les fuseaux horaires... Quelle source infinie de complications pour le programmeur, pour l'administrateur système de machines situées partout dans le monde, ou tout simplement pour le voyageur ou l'organisateur de télé-réunions internationales... Comme tout serait plus simple si, comme dans le roman d'Asimov « Les cavernes d'acier », les hommes vivaient en permanence sous terre, utilisant un temps uniforme. Mais, en attendant ce futur béni, il faut bien gérer les fuseaux horaires (time zones). Il existe une base de données officielle de ces fuseaux, il ne reste plus qu'à la distribuer efficacement, pour que toute machine connectée à l'Internet ait la même information. C'est le but du protocole normalisé dans ce RFC.

Que contient une base de données des fuseaux horaires (section 1 du RFC) ? Typiquement une liste de ces fuseaux avec, pour chacun d'entre eux, son décalage par rapport à UTC et ses règles concernant l'heure d'été. Les fuseaux ne suivent pas strictement le méridien, ils collent en général à des frontières inter ou intra-étatiques. Les fuseaux eux-même, et leurs décalages avec UTC, sont très stables. Mais les règles concernant l'heure d'été changent, elles, souvent. Il y a aussi le problème des secondes intercalaires, qui sont ajoutées (ou, en théorie, retirées) par l'IERS de manière imprévisible (car la rotation de la Terre n'est pas prévisible). La base actuelle représente un travail d'érudition formidable.

Au passage, un point de terminologie. Le RFC parle de « time zone » là où on dit en général en français « fuseau horaire ». Le terme français n'est pas idéal car il fait penser à un fuseau allant d'un pôle à l'autre (et englobant donc des pays différents, ayant des heures d'été différentes) alors qu'une time zone est plus restreinte. Il faut donc bien se rappeler qu'on parle ici de zones limitées à un pays, et ayant des règles (décalage avec UTC, heure d'été) uniformes. Il faut donc peut-être mieux dire « zone » ou « zone horaire » en français.

Cette information est essentielle pour les protocoles et les formats qui gèrent le temps, comme iCalendar (RFC 5545), ainsi que pour les systèmes d'exploitation. Il faut donc maintenir à jour la base de données et, jusqu'à ce RFC, il n'existait pas de mécanisme standard pour cela. Par exemple, pour un système d'exploitation comme Debian, la mise à jour se fait typiquement via le mainteneur d'un paquetage « base des fuseaux horaires » (chez Debian, le paquetage se nomme tzdata), qui introduit les changements dans son paquetage, paquetage qui est ensuite installé sur chaque machine lorsque l'administrateur système décide des mises à jour. Si le système est vieux et plus maintenu, ce sera à l'administratreur système local de « patcher » ses fichiers. Parfois, des paquetages viennent avec leur propre base des fuseaux horaires, distincte de celle du système, pour compliquer un peu les choses.

Au passage, signalons que ce RFC normalise le protocole mais qu'il faut également disposer d'une source de données de référence. Il en existe une à l'IANA, décrite dans le RFC 6557.

La section 2 décrit à grands traits l'architecture du système. Tout en amont, des contributeurs envoient des données sur les fuseaux horaires, elles sont agrégées par le fournisseur de référence (root provider, par exemple l'IANA citée plus haut). Ce fournisseur l'envoie ensuite aux clients (par exemple par le protocole de ce RFC). Le schéma du RFC est un peu plus compliqué, supposant que divers intermédiaires pourraient apparaitre. Notez que le protocole décrit ici est entre fournisseur et clients. En amont (entre contributeurs et fournisseur), il n'y a pas de mécanisme spécifié.

La section 3 de notre RFC définit la terminologie. Une zone (time zone) se caractérise donc par un ensemble de règles uniformes. La zone a un nom (utilisé par exemple dans la propriété TZID du RFC 5545) mais il n'existe pas de norme pour cela. Chaque fournisseur pourrait utiliser son schéma de nommage. Ainsi, la base IANA utilise un nom de région, une barre oblique et un nom de pays ou de ville comme Europe/Paris ou Indian/Cocos. En tout cas, il faut se méfier des abréviations ambigues, n'ayant souvent qu'une signification locale, comme PST (qui peut désigner trois zones différentes).

L'information sur les zones change (autrement, on n'aurait pas besoin d'un protocole pour télécharger les mises à jour) et il est donc important d'avoir un numéro de version permettant de savoir si on a bien la dernière version. Il peut être global à la base, ou bien spécifique à chaque zone.

Maintenant, le protocole lui-même (section 4 du RFC). Il repose, comme souvent de nos jours, sur le couple « HTTP (RFC 7230) et JSON (RFC 7159) », ce dernier servant à représenter les méta-données sur les zones. Les ressources auxquelles on accède en HTTP utilisent les gabarits d'URI du RFC 6570. Et les données elle-mêmes, les informations sur une zone horaire, en quoi sont-elles codées ? Le format par défaut est celui d'iCalendar (RFC 5545). Mais on peut aussi utiliser la représentation en XML du RFC 6321 ou celle en JSON du RFC 7265. La classique négociation de contenu de HTTP (RFC 7231, section 5.3.2) sert au client à choisir son format parmi ceux que le serveur veut bien fournir.

La base peut être assez grosse et les clients vouloir la toute dernière version. La charge sur le réseau des fournisseurs risquerait alors de devenir insupportable. C'est pourquoi il est possible de faire des requêtes conditionnelles, de façon à ne récupérer des données que si elles sont nouvelles. Là encore, c'est du classique HTTP avec les Etags (RFC 7232). Un client peut alors interroger le serveur du fournisseur une fois par jour (valeur recommandée par le RFC) sans risque de saturer le réseau.

Si le client reçoit uniquement le décalage avec UTC et les règles pour l'heure d'été, calculer une heure dans le futur peut être délicat car ces règles sont complexes. Le protocole prévoit donc la possibilité pour le client de demander au serveur de faire ces calculs et de lui envoyer les résultats.

Et si ça ne marche pas, que le serveur, pour une raison ou pour une autre, ne peut pas envoyer ce qui lui est demandé ? Il doit alors utiliser les erreurs structurées du RFC 7807 pour signaler ce qui ne va pas. (Les types d'erreurs possibles figurent dans un registre IANA.)

Comment est-ce qu'un client de ce protocole trouve le serveur ? Il doit de toute façon connaître le nom de domaine de son fournisseur, supposons ici example.net. Ensuite, il y a au moins deux méthodes :

  • Utiliser les enregistrements SRV (RFC 2782), en demandant _timezone._tcp.example.net. Il obtiendra ainsi le nom du serveur et le port à utiliser. Un enregistrement supplémentaire, sous le même nom que l'enregistrement SRV, de type TXT, indique un éventuel chemin à ajouter dans l'URI.
  • Ou bien utiliser les URI .well-known du RFC 5785, en faisant une requête HTTP pour la ressource timezone.

La section 5 du RFC décrit ensuite les actions que le serveur peut effectuer à la demande. Elles sont spécifiées en utilisant les gabarits du RFC 6570. Donc, par exemple, un gabarit {/service-prefix}/capabilities indique que le client doit ajouter /capabilities au préfixe de chemin découvert comme indiqué précédemment. Prenons un exemple complet : le client sait que son fournisseur de zones horaires est example.net. Il fait deux requêtes DNS et obtient deux enregistrements :

_timezone._tcp.example.net. SRV 0 1 8081 tz.example.com.
_timezone._tcp.example.net. TXT "path=/timezones"
    

S'il cherche à déterminer les capacités du serveur, il va alors faire une requête à l'URL http://tz.example.com:8081/timezones/capabilities.

C'est quoi, ces capabilities que je viens d'utiliser dans l'exemple ? C'est la première des actions possibles sur un serveur. Comme son nom l'indique, elle renverra un objet JSON contenant un membre actions qui sera la liste des actions possibles sur ce serveur (avec, pour chacune, le gabarit d'URI à utiliser). Une liste des actions standards possibles figure dans un registre IANA.

L'action list, elle, donne la liste des zones horaires connues du serveur. Et l'action get renvoie les données pour une zone précise. Son gabarit est {/service-prefix,data-prefix}/zones{/tzid}{?start,end} (tzid étant l'identificateur de la zone, par exemple Pacific/Noumea) et un exemple d'utilisation est :

[Requête]
      
GET /timezones/zones/America%2FNew_York HTTP/1.1
Host: tz.example.com:8081
Accept:text/calendar

[Réponse]

HTTP/1.1 200 OK
Date: Wed, 4 Jun 2008 09:32:12 GMT
Content-Type: text/calendar; charset="utf-8"
Content-Length: xxxx
ETag: "123456789-000-111"

BEGIN:VCALENDAR
...
BEGIN:VTIMEZONE
TZID:America/New_York
...
END:VTIMEZONE
END:VCALENDAR      
    

Les codes d'erreur habituels de HTTP sont utilisés donc, par exemple, si on demande un tzid inconnu, on récupérera un beau 404, mais avec le corps de la réponse en JSON, suivant le RFC 7807 :

[Requête]
      
GET /timezones/zones/Atlantid%2FPlutopolis HTTP/1.1
Host: tz.example.com:8081
Accept:text/calendar

[Réponse]

HTTP/1.1 404 Not Found
Date: Wed, 4 Jun 2008 09:32:12 GMT
Content-Type: application/problem+json; charset="utf-8"
Content-Language: en
Content-Length: xxxx

{
     "type": "urn:ietf:params:tzdist:error:tzid-not-found",
     "title": "Time zone identifier was not found on this server",
     "status": 404
}

Il existe plusieurs autres actions, comme expand qui dit au serveur de faire les calculs d'heure d'été lui-même, ou find, qui permet de chercher une zone par une partie de son nom.

Notez bien qu'il n'y a pas d'URI fixe et pré-déterminé pour les actions : il faut utiliser les gabarits pour les générer.

Les détails des objets JSON qui peuvent être renvoyés en réponse à ces actions figurent en section 6 de notre RFC.

Et la sécurité ? Elle est cruciale car, si on peut changer la connaissance qu'une machine a de l'heure, plein d'attaques deviennent possibles (fausser les estampilles temporelles dans les journaux, activer ou désactiver un certificat, etc). Il faut donc prendre soin d'utiliser un fournisseur fiable, et de récupérer la base de manière sécurisée. (HTTPS, forcément, et avec vérification sérieuse de l'identité du serveur, en suivant le RFC 6125 ou bien le RFC 6698).

Il n'y a apparemment pour le moment qu'une mise en œuvre, dans le système de calendrier Bedework. Je ne connais pas encore de service disponible qui serve la base de données suivant ce protocole (c'est pour cela que je ne montre pas d'exemple réel). Notamment, l'IANA ne le fait pas (ce n'était pas demandé dans le RFC). Il existe des services qui distribue la base, mais avec un autre protocole, comme https://timezonedb.com/api.


Téléchargez le RFC 7808


L'article seul

RFC 7807: Problem Details for HTTP APIs

Date de publication du RFC : Mars 2016
Auteur(s) du RFC : M. Nottingham (Akamai), E. Wilde
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 1 avril 2016


Lorsqu'on fait une requête HTTP, on récupère un code à trois chiffres qui indique notamment si tout s'est bien passé (si le code commence par 2, c'est bon, s'il commence par 4 ou 5, c'est qu'il y a un problème). Ces codes ne sont pas toujours assez fins et bien des API de services REST (donc reposant sur HTTP) voudraient des précisions. Plutôt que de créer un nouveau code, ce RFC propose un mécanisme qui permet d'envoyer du JSON normalisé indiquant tous les détails sur le problème survenu.

Les codes de statut de HTTP sont définis dans la section 6 du RFC 7231. Parmi les plus célèbres, on note 200 (qui veut dire que tout s'est bien passé) ou 404 (qui indique que le serveur n'a pas trouvé la ressource demandée). Si le serveur veut fournir des détails, il envoie traditionnellement de l'HTML dans le corps de sa réponse. Le navigateur Web peut alors l'afficher. Mais si la requête n'était pas envoyée par un humain derrière son navigateur, si elle venait d'un client REST ? HTML ne convient alors pas et il faut passer à une information analysable par une machine. C'est ce que fait ce RFC, qui définit deux formats, un en JSON (RFC 7159) et un en XML. Le client REST va donc avoir un résumé simple (le code de statut) et tous les détails nécessaires s'il le souhaite. « Comprenant » l'erreur exacte, le client pourra même, dans certains cas, la corriger.

Le RFC utilise surtout des exemples avec l'erreur 403 Forbidden mais j'ai préféré me servir de 402 Payment required. Ce code n'a jamais été clairement documenté (il est marqué « réservé pour un usage futur » dans le RFC 7231, section 6.5.3) et c'est sans doute pour cela que notre RFC ne l'utilise pas, mais je le trouve plus rigolo. Voici par exemple une page Web payante :

% wget https://www.bortzmeyer.org/faut-vraiment-payer.html
--2016-03-26 15:54:00--  https://www.bortzmeyer.org/faut-vraiment-payer.html
Resolving www.bortzmeyer.org (www.bortzmeyer.org)... 2001:4b98:dc0:41:216:3eff:fece:1902, 2605:4500:2:245b::42, 204.62.14.153
Connecting to www.bortzmeyer.org (www.bortzmeyer.org)|2001:4b98:dc0:41:216:3eff:fece:1902|:443... connected.
HTTP request sent, awaiting response... 402 Payment Required
2016-03-26 15:54:00 ERROR 402: Payment Required.

On peut envisager plein de choses dans cette réponse analysable par une machine, comme un URI unique pour ce problème donné, qui pourrait être, par exemple, transmis au support pour faciliter la communication. Ou bien un URI d'un service REST de paiement permettant d'envoyer l'argent souhaité. Mais, naturellement, l'utilisation de cette réponse est facultative : parfois, le code de statut est suffisant et il n'y a rien à ajouter (c'est souvent le cas du 404), et parfois il vaut mieux utiliser un format spécifique à l'application utilisée (c'est d'ailleurs le cas pour toutes les API développées avant ce RFC). Ceci dit, pour les nouvelles applications, le mécanisme décrit dans ce RFC peut être très utile, pour doter toutes les applications d'un mécanisme commun de signalement des erreurs et problèmes.

Le modèle de données utilisé est celui de JSON et le type MIME est application/problem+json. Comme je l'ai dit plus haut, il y a aussi une version XML mais la référence est le JSON. La section 3 du RFC décrit ce modèle. Commençons par un exemple, une API qui demandait entre autres d'indiquer un âge et à qui on a envoyé un nombre négatif :

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Content-Language: en

{
   "type": "https://example.net/validation-error",
   "title": "Your request parameters didn't validate.",
   "invalid-params": [ {
                         "name": "age",
                         "reason": "must be a positive integer"
                       }
                     ]
}
 

Ce message d'erreur est de type https://example.net/validation-error, une explication en langue naturelle est donnée par le membre title, et la liste des paramètres invalides est donnée dans le membre (une extension à la norme) invalid-params.

Quels sont les membres possibles de l'objet JSON renvoyé ?

  • type est un URI (il est donc unique) servant d'identificateur au problème, par exemple lorsqu'on va écrire au support. Il est recommandé qu'il soit déréférençable (c'est-à-dire qu'on puisse le visiter avec un navigateur Web et obtenir des informations sur le problème en question). S'il est absent, sa valeur par défaut est le très vide about:blank (RFC 6694, section 3).
  • title est un titre conçu pour des humains, par exemple pour les messages d'erreurs présentés à l'utilisateur. Étant en langue naturelle, il est, contrairement au type, ambigu. Il peut être adapté à la langue de l'utilisateur, via l'habituelle négociation de contenu de HTTP. detail (absent dans l'exemple ci-dessus) le complète éventuellement. Le RFC précise que detail est fait pour l'utilisateur, pas pour le programmeur qui a conçu le service. Il devrait donc contenir des informations aidant l'utilisateur à corriger sa requête, pas des informations de déboguage (pas de pile d'appels Java, par exemple...) D'ailleurs, envoyer ces informations de déboguage poserait un problème de sécurité (cf. section 5).
  • instance (absent dans l'exemple) est un URI qui, contrairement à type, n'identifie pas la classe du problème mais une instance particulière. Si http://example.com/not-enough-credit indique la classe « pas assez d'argent », https://example.com/account/12345/msgs/abc va indiquer le problème d'argent d'un compte particulier.

Notez que type et instance peuvent être des URI relatifs.

Voici maintenant un exemple sur mon blog (c'est conçu comme une application REST donc les résultats sont toujours en JSON et, en effet, ce n'est pas en HTTPS, ce serait intolérable en production) :


% curl -v http://www.bortzmeyer.org/apps/payme     
...
< HTTP/1.1 402 Payment required
...
< Content-Length: 253
< Content-Type: application/problem+json
< 
{
  "type": "http://errors.bortzmeyer.org/nopay", 
  "detail": "Bitcoin address 1HtNJ6ZFUc9yu9u2qAwB4tGdGwPQasQGax, Ethereum address 0xbe1f2ac71a9703275a4d3ea01a340f378c931740, Flattr https://flattr.com/profile/bortzmeyer", 
  "title": "You must pay"
}

% curl -v http://www.bortzmeyer.org/apps/payme\?pay=30
...
< HTTP/1.1 200 OK
< Content-Length: 36
< Content-Type: application/json
< 
{
  "title": "OK, 30 credits paid"
}

    

Le code Python WSGI correspondant est :

 def payme(start_response, environ):
    form = cgi.parse_qs(environ['QUERY_STRING'])
    response_headers = []
    amount = 0
    if form.has_key("pay"):
        try:
            amount = int(form["pay"][0])
        except ValueError: # Bad syntax
            amount = 0
    if amount > 0:
        status = '200 OK'
        response_headers.append(('Content-type', 'application/json'))
        output = json.dumps({"title": "OK, %i credits paid" % amount}, indent=2)
    else:
        status = '402 Payment required'
        response_headers.append(('Content-type', 'application/problem+json'))
        output = json.dumps({"type": "http://errors.bortzmeyer.org/nopay",
                             "title": "You must pay",
                             "detail": "Bitcoin address 1HtNJ6ZFUc9yu9u2qAwB4tGdGwPQasQGax, Ethereum address 0xbe1f2ac71a9703275a4d3ea01a340f378c931740, Flattr https://flattr.com/profile/bortzmeyer"},
                             indent=2)
    response_headers.append(('Content-Length', str(len(output))))
    start_response(status, response_headers)
    return [output]     
    

Si vous n'avez pas ce que vous voulez dans les membres prévus, vous pouvez étendre l'objet JSON. Les clients doivent donc ignorer les membres inconnus. C'est le cas du invalid-params dans l'exemple, qui n'est pas un membre standard.

Bien, maintenant, vous êtes programmeur dans une start-up, vous créez un nouveau service qui a une API, un nom de domaine en .io, un business plan pipeau et vous vous demandez si vous devez utiliser ce RFC et comment. La section 4 du RFC fournit quelques conseils. D'abord, je le répète, ce n'est pas un outil de déboguage pour vous, ne serait-ce que pour des raisons de sécurité (cf. section 5). C'est un outil pour aider vos utilisateurs. Ensuite, si le problème est un problème classique et standard, il est inutile de se servir de ce RFC. Si l'utilisateur demande une ressource qui n'existe pas, le traditionnel et générique 404 (RFC 7231, section 6.5.4) convient parfaitement et je ne vois pas de raison d'ajouter des détails analysables par une machine (dans une page HTML d'erreur, c'est différent, on peut fournir des conseils aux visiteurs, mais rappelez-vous que ce RFC est pour les API, quand le client est un programme).

D'autre part, une application peut avoir de très bonnes raisons d'utiliser un format à elle pour décrire en détail les problèmes. (Sans compter les applications existantes qui ne vont évidemment pas modifier la définition de leur API juste pour coller à ce RFC.)

En revanche, une application nouvelle, qui n'a pas de format d'erreur établi, a tout intérêt à utiliser le cadre de ce RFC plutôt que de réinventer la roue. Dans ce cas, vous allez devoir définir :

  • L'URI qui servira de type (le seul type prédéfini est about:blank),
  • Le code de statut HTTP qui l'accompagne,
  • Les éventuelles extensions (comme le membre invalid-params plus haut).

Ces extensions peuvent utiliser les liens de HTTP (RFC 5988).

Le format principal décrit par ce RFC utilise JSON. Mais, comme il y a des goûts différents, il y a aussi une variante XML, décrite dans l'annexe A. Elle est spécifiée en Relax NG. Le modèle de données étant le même, cela donne à peu près :

   start = problem

   problem =
     element problem {
       (  element  type            { xsd:anyURI }?
        & element  title           { xsd:string }?
        & element  detail          { xsd:string }?
        & element  status          { xsd:positiveInteger }?
        & element  instance        { xsd:anyURI }? ),
       anyNsElement
     }
     

Et le résultat serait :


HTTP/1.1 400 Bad Request
Content-Type: application/problem+xml
Content-Language: en

<?xml version="1.0" encoding="UTF-8"?>
<problem xmlns="urn:ietf:rfc:XXXX">
   <type>https://example.net/validation-error</type>
   <title>Your request parameters didn't validate.</title>
   <invalid-params><param><name>age</name><reason>must be a positive integer</reason></param></invalid-params>
</problem>

     

On a presque fini, quelques petits mots sur la sécurité en section 5 : attention à ne pas laisser fuiter de l'information qui pourrait aider un attaquant à préparer son attaque. Il faut notamment se méfier des détails de mise en œuvre (du genre afficher la requête SQL qui a échoué...)

Les deux nouveaux types MIME, application/problem+json et application/problem+xml figurent désormais dans le registre IANA.

Les développeurs d'API n'ont pas attendu ce RFC pour renvoyer des messages d'erreurs structurés, utilisant d'autres schémas (voici, par exemple, les erreurs possibles de l'API Github). Un concurrent sérieux à ce RFC est, par exemple, http://jsonapi.org/ qui a son propre mécanisme de signalement d'erreur.


Téléchargez le RFC 7807


L'article seul

Articles des différentes années : 2016  2015  2014  2013  2012  2011  2010  Précédentes années

Syndication : en HTTP non sécurisé, Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu, en HTTPS, Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu.