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 8153: Digital Preservation Considerations for the RFC Series

Date de publication du RFC : Avril 2017
Auteur(s) du RFC : H. Flanagan (RFC Editor)
Pour information
Première rédaction de cet article le 25 avril 2017


La préservation, sur le long terme, des documents qui ne sont jamais passés par une forme papier, est un défi important de notre époque. Nous pouvons relire aujourd'hui toute la correspondance du ministère des affaires étrangères de Louix XV, pourrons-nous, dans un siècle ou deux, relire les documents numériques du vingtième siècle ? Pourrons-nous relire les RFC ? C'est le but de ce document que d'explorer les pistes permettant de donner aux RFC une meilleure chance de conservation.

Le RFC Editor (RFC 6635) est à la fois l'éditeur et l'archiviste des RFC. Les deux fonctions sont souvent contradictoires : l'éditeur voudrait utiliser les derniers gadgets pour publier des jolis trucs (multimédia, par exemple, ou contenus exécutables), l'archiviste est prudent et conservateur et voudrait des technologies simples. L'éditeur doit produire des documents clairs et lisibles. L'archiviste doit les conserver, et pour une durée potentiellement bien plus longue que les modes technologiques, durée qui peut atteindre des siècles (on est ravis, aujourd'hui, quand on retrouve les textes de lois d'un royaume depuis longtemps oublié, au fin fond de la Mésopotamie, même quand ces lois ont depuis longtemps cessé d'être applicables).

Notez que des organisations comme l'IETF produisent plein de documents (les discussions sur les listes de diffusion, par exemple), mais que ce RFC se focalise sur la préservation des RFC.

Historiquement, les RFC étaient en texte seul. Ce format avait des tas d'avantages. Simple, et auto-documenté (la seule spécification nécessaire pour le comprendre était ASCII), il convenait bien à l'archivage. Régulièrement, des naïfs demandaient que le RFC Editor passe à un format « plus moderne », en général une mode passagère, oubliée quelques années après. Le texte seul a donc tenu très longtemps, et à juste titre.

Mais la roue de l'histoire a fini par tourner et le RFC 6949 a pris acte du fait qu'on n'allait pas rester en texte seul éternellement. Le format officiel des RFC, décrit dans le RFC 7990 est désormais fondé sur XML, avec divers enrichissements comme le jeu de caractères Unicode (RFC 7997) ou les images en SVG (RFC 7996). Cela fait peser une pression plus forte sur l'archivage : si on est certain de pouvoir relire le texte brut en ASCII dans cent ans, qu'en est-il d'images SVG ? L'ancien système d'archivage des RFC ne va donc a priori pas suffire. (Le XML lui-même est relativement auto-documenté. Si on met des documents XML sous les yeux d'un programmeur qui n'en a jamais vu, il pourra probablement rétro-ingénierer l'essentiel. Ce n'est pas forcément le cas des vocabulaires qui utilisent XML, notamment le compliqué SVG.)

Le nouveau système d'archivage suivra le cadre conceptuel d'OAIS (norme ISO 14721, disponible en ligne). Sur OAIS, on peut lire la bonne introduction d'Emmanuelle Bermes. Il faut notamment distinguer deux tâches (section 1.1 de notre RFC) :

  • Préservation des bits : archiver un fichier informatique et pouvoir le ressortir des dizaines d'années après, au bit près. Cela se fait, par exemple, en recopiant régulièrement le fichier sur de nouveaux supports physiques, et en vérifiant via une somme de contrôle ou une signature que rien n'a changé. Des classiques sauvegardes, vérifiées régulièrement, suffisent donc.
  • Préservation du contenu : il ne suffit plus de stocker et de restituer les bits, il faut aussi présenter le contenu à l'utilisateur. Avoir une copie parfaite des bits d'un fichier WordPerfect de 1990 ne sert pas à grand'chose s'il n'existe plus aucun logiciel capable de lire le Wordperfect sur les machines et systèmes d'exploitation modernes. Assurer la préservation du contenu est plus complexe, et il existe plusieurs solutions, par exemple de garder une description du format (pour qu'on puisse toujours développer un outil de lecture), et/ou garder non seulement les fichiers mais aussi les outils de lecture, et tout l'environnement qui permet de les faire fonctionner.

Ceci dit, ce problème d'archivage à long terme des fichiers numériques n'est ni nouveau, ni spécifique aux RFC. Il a été largement étudié par de nombreuses organisations. On peut citer la BNF, le projet LIFE en Grande-Bretagne, ou l'étude du cycle de vie faite à la Bibliothèque du Congrès. Des processus pour maintenir sur le long terme les fichiers, avec recopies régulières et nombreuses vérifications, existent.

Les RFC bénéficient depuis un certain temps d'un mécanisme similaire de préservation des bits : les métadonnées (indispensables pour retrouver un document) sont créées et enregistrées. Les fichiers sont recopiés d'un ordinateur à l'autre au fur et à mesure que les anciennes technologies de stockage deviennent dépassées. En outre, depuis 2010, tous les RFC sont imprimés sur du papier, pour avoir « ceinture et bretelles ». Les RFC plus anciens que 2010 subissent également parfois ce traitement, mais il existe des trous (RFC perdus, ou, tout simplement, problèmes avec le droit d'auteur, avant que cette question ne soit explicitement traitée, cf. RFC 3979).

Cette copie papier s'est avérée utile au moins une fois, quand 800 RFC ont dû être été re-saisis à la main, suite à une panne informatique (et une insuffisance des sauvegardes). Un petit détail amusant au passage : le RFC Editor à une époque acceptait des documents qui n'étaient pas des RFC, et qu'il faut aussi sauvegarder, voir l'histoire antique des RFC.

Il n'y a pas actuellement de sauvegarde de l'environnement logiciel utilisé pour lire les RFC, l'idée est que cela n'est pas nécessaire : on pourra toujours lire du texte brut en ASCII dans cent ans (la preuve est qu'on n'a pas de mal à relire le RFC 1, vieux de quarante-huit ans). Le processus de sauvegarde préserve les bits, et on considère que la préservation du contenu ne pose pas de problème, avec un format aussi simple. (Par exemple, l'impression sur le papier ne garde pas les hyperliens mais ce n'est pas un problème puiqu'il n'y en a pas dans le format texte brut.)

Mais, puisque les RFC vont bientôt quitter ce format traditionnel et migrer vers un format plus riche, il faut reconsidérer la question. La section 2 de notre RFC explore en détail les conséquences de cette migration sur chaque étape du cycle de vie. Il faut désormais se pencher sur la préservation des contenus, pas seulement des bits.

Certaines caractéristiques du cycle de vie des RFC facilitent l'archivage. Ainsi, les RFC sont immuables. Même en cas d'erreur dans un RFC, il n'y a jamais de changement (au maximum, on publie un nouveau RFC, comme cela avait été fait pour le RFC 7396). Il n'y a donc pas à sauvegarder des versions successives. D'autres caractéristiques du cycle de vie des RFC compliquent l'archivage. Ainsi, ce n'est pas le RFC Editor qui décide d'approuver ou pas un RFC (RFC 5741). Il n'a donc pas le pouvoir de refuser un document selon ses critères à lui.

Le RFC Editor maintient une base de données (qui n'est pas directement accessible de l'extérieur) des RFC, avec évidemment les métadonnées associées (état, auteurs, date, DOI, liens vers les éventuels errata puisqu'on ne corrige jamais un RFC, etc). Les pages d'information sur les RFC sont automatiquement tirées de cette base (par exemple https://www.rfc-editor.org/info/rfc8153, pour ce RFC).

Les RFC citent, dans la bibliographie à la fin, des références dont certaines sont normatives (nécessaires pour comprendre le RFC, les autres étant juste « pour en savoir plus »). Idéalement, les documents ainsi référencés devraient également être archivés (s'ils ne sont pas eux-même des RFC) mais ce n'est pas le cas. Notre RFC suggère que l'utilisation de Perma.cc serait peut-être une bonne solution. C'est un mécanisme d'archivage des données extérieures, maintenu par groupe de bibliothèques juridiques de diverses universités. Pour un exemple, voici la sauvegarde Perma.cc (https://perma.cc/E7QG-TG98) de mon article sur le hackathon de l'IETF.

Dans un processus d'archivage, une étape importante est la normalisation, qui va supprimer les détails considérés comme non pertinents. Elle va permettre la préservation du contenu, en évitant de garder des variantes qui ne font que compliquer la tâche des logiciels. Par exemple, bien que XML permette d'utiliser le jeu de caractères de son choix (en l'indiquant dans la déclaration, tout au début), une bonne normalisation va tout passer en UTF-8, simplifiant la tâche du programmeur qui devra un jour, écrire ou maintenir un logiciel de lecture du XML lorsque ce format sera à moitié oublié.

Or, au cours de l'histoire des RFC, le RFC Editor a reçu plein de formats différents, y compris des RFC uniquement sur papier. Aujourd'hui, il y a au moins le format texte brut, et parfois d'autres.

Maintenant qu'il existe un format canonique officiel (celui du RFC 7991), quelles solutions pour assurer la préservation du contenu ?

  • Best effort, préserver les bits et espérer (ou compter sur les émulateurs, ce qui se fait beaucoup dans le monde du jeu vidéo vintage),
  • Préserver un format conçu pour l'archivage (PDF/A-3 étant un candidat évident - voir le RFC 7995, d'autant plus que le XML original peut être embarqué dans le document PDF),
  • Préserver le XML et tous les outils, production, test, visualisation, etc. (Ce que les mathématiciens ou les programmeurs en langages fonctionnels appeleraient une fermeture.)

La première solution, celle qui est utilisée aujourd'hui, n'est plus réaliste depuis le passage au nouveau format. Elle doit être abandonnée. La deuxième solution sauvegarde l'information dans le document, mais pas le document lui-même (et c'est embêtant que le format archivé ne soit pas le format canonique, mais uniquement un des rendus). Et l'avenir de PDF/A-3 est incertain, on n'a pas encore essayé de le lire trente ans après, et les promesses du marketing doivent être considérées avec prudence (d'autant plus qu'il y a toujours peu d'outils PDF/A, par exemple aucun logiciel pour vérifier qu'un document PDF est bien conforme à ce profil restrictif). Pour la troisième solution, cela permettrait de refaire un rendu des RFC de temps en temps, adapté aux outils qui seront modernes à ce moment. Mais c'est aussi la solution la plus chère. Si on imagine un futur où XML, HTML et PDF sont des lointains souvenirs du passé, on imagine ce que cela serait d'avoir préservé un environnement d'exécution complet, les navigateurs, les bibliothèques dont ils dépendent, le système d'exploitation et même le matériel sur lequel il tourne !

Une solution plus légère serait de faire (par exemple tous les ans) un tour d'horizon des techniques existantes et de voir s'il est encore possible, et facile, de visualiser les RFC archivés. Si ce n'est pas le cas, on pourra alors se lancer dans la tâche de regénérer des versions lisibles.

Au passage, il existe déjà des logiciels qui peuvent faciliter certains de ces activités (le RFC cite le logiciel libre de gestion d'archives ArchiveMatica).

Après cette analyse, la section 3 de notre RFC va aux recommandations : l'idée est de sauvegarder le format canonique (XML), un fichier PDF/A-3, le futur outil xml2rfc et au moins deux lecteurs PDF (qui doivent être capables d'extraire le XML embarqué). Les tâches immédiates sont donc :

  • Produire les PDF/A-3 (à l'heure de la publication de ce RFC, l'outil n'est pas encore développé) avec le XML à l'intérieur, et l'archiver,
  • Archiver le format canonique (texte seul pour les vieux RFC, XML pour les nouveaux),
  • Archiver les versions majeures des outils, notamment xml2rfc,
  • Archiver deux lecteurs PDF,
  • Avoir des partenariats avec différentes institutions compétentes pour assurer la sauvegarde des bits (c'est déjà le cas avec la bibliothèque nationale suédoise). Un guide d'évaluation de ce ces archives est ISO 16363.

La version papier, par contre, ne sera plus archivée.

Conclusion (section 4) : les RFC sont des documents importants, qui ont un intérêt pour les générations futures, et qui valent la peine qu'on fasse des efforts pour les préserver sur le long terme.


Téléchargez le RFC 8153


L'article seul

RFC 8143: Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)

Date de publication du RFC : Avril 2017
Auteur(s) du RFC : J. Élie
Chemin des normes
Première rédaction de cet article le 25 avril 2017


Ce RFC concernant le protocole NNTP met à jour l'ancien RFC 4642 qui donnait des conseils TLS très spécifiques (activer la compression, utiliser RC4...), conseils qui n'ont pas résisté à l'évolution de la cryptographie. On arrête donc de donner des conseils TLS spécifiques, NNTP a un usage générique de TLS et doit donc se référer au RFC générique BCP 195 (actuellement RFC 7525).

NNTP, le protocole de transport des News, est normalisé dans le RFC 3977. Il peut utiliser TLS (RFC 5246) pour sécuriser la communication entre deux serveurs NNTP, ou bien entre serveur et client. Le RFC 4642, qui décrivait cet usage de TLS, faisait une erreur : il donnait des conseils de cryptographie. Or, d'une part, NNTP ne faisait pas un usage particulier de la cryptographie, et n'avait pas besoin de recommandations spécifiques et, d'autre part, la cryptographie est un domaine qui évolue. Ainsi, les fonctions de compression de données de TLS sont aujourd'hui considérées comme une mauvaise idée, dans la plupart des cas (attaque CRIME, cf. RFC 7525, section 3.3).

L'essentiel de notre nouveau RFC est dans sa section 3 : désormais, il faut suivre le RFC de bonnes pratiques TLS, BCP 195 (actuellement RFC 7525).

De même que le courrier électronique peut préciser dans un en-tête Received: que la connexion SMTP était protégée par TLS, de même NNTP permet d'ajouter dans le champ Path: (section 3.1.5 du RFC 5536) une indication que le pair a été authentifié (deux points d'exclamation de suite).

La section 2 du RFC résume les changements par rapport au RFC 4642 (la liste complète est dans l'annexe A). Comme dit plus haut, la compression TLS est désormais fortement déconseillée (à la place, on peut utiliser l'extension de compression de NNTP, normalisée dans le RFC 8054). Il est très nettement recommandé d'utiliser du TLS implicite (connexion sur un port dédié (le 563 pour les clients, non spécifié pour les autres serveurs), au lieu de la directive STARTTLS, qui est vulnérable à l'attaque décrite dans la section 2.1 du RFC 7457). Il ne faut évidemment plus utiliser RC4 (cf. RFC 7465), mais les algorithmes de chiffrement obligatoires de TLS. Il faut utiliser l'extension TLS Server Name Indication (RFC 6066, section 3). Et, pour authentifier, il faut suivre les bonnes pratiques TLS des RFC 5280 et RFC 6125.

Comme la plupart des mises en oœuvre de NNTP-sur-TLS utilisent une bibliothèque TLS générique, elles suivent déjà une bonne partie des recommandations de ce RFC. Après, tout dépend des options particulières qu'elles appellent…

Merci à Julien Élie pour une relecture attentive (j'avais réussi à mettre plusieurs erreurs dans un article aussi court.)


Téléchargez le RFC 8143


L'article seul

Icinga notifications to Mastodon

First publication of this article on 23 April 2017


I use Icinga to monitor my hosts and services. Notification of problems, with Icinga, is not hardwired in the software, it is delegated to an external program. So, if you know how to send a message from a program, you can use this for notifications. Here, I explain how I did to toot (send) my Icinga notifications to Mastodon.

Mastodon is the latest trendy social network: unlike Twitter, Facebook, Slack or Instagram, it is decentralized, and does not depend on a given corporation. There is an API to perform Mastodon functions. I'm too lazy to write my own program, so I rely on the madonctl, written in Go. Let's install it. (If you use Debian like me, do note it does not compile on Debian stable, you'll need unstable, or a backport.)

% go get github.com/McKael/madonctl
    

Then, if the directory where go get installs the binaries is in your PATH, you can use the command:

%    madonctl
madonctl is a CLI tool for the Mastodon REST API.

You can use a configuration file to store common options.
...    
    

Now, let's configure it with the name of your Mastodon instance, the user name at this instance, and your password:

    
% mkdir -p ~/.config/madonctl
% madonctl config dump -i MY_INSTANCE  -L MY_MASTODON_NAME -P MY_PASSWORD > ~/.config/madonctl/madonctl.yaml

Let's test that we can toot (post a message):

%  madonctl toot "Writing a blog article" 
- Status ID: 310679
  From: bortzmeyer
  Timestamp: 2017-04-23 18:56:59.141 +0000 UTC
  Contents: Writing a blog article
  URL: https://mastodon.gougere.fr/@bortzmeyer/310679

OK, now that the command-line tool works, let's configure Icinga. First, decide if you want your Icinga notifications to be public or not. In the first case, you'll simply send them without anything specific, like I did with the test toot above. In the second case, you'll probably use Mastodon "direct" option, as I do. Your toots will be only visible to you. Let's start with the users.conf file to configure the account that will receive the notification toots:

object User "icingaadmin" {
...
  email = "ME@MY.EMAIL.SITE"
  vars.mastodon = "MY_MASTODON_NAME"
}
    

I would have preferred to name the variable simply mastodon but Icinga does not let me create a new attribute for users (one of the annoying things with Icinga is to find out if a custom attribute is allowed or not; "it depends"; and it's not well documented.) So, I use the vars dictionary.

Now, let's create the notification command itself. Based on Icinga's email notification script, it will be a simple shell script wrapper around madonctl. /mastodon-host-notification.sh will be:

    

#!/bin/sh

export HOME=/var/lib/nagios

template=$(cat <<TEMPLATE
@$USERMASTODON Icinga $NOTIFICATIONTYPE - $HOSTDISPLAYNAME is $HOSTSTATE

Notification Type: $NOTIFICATIONTYPE

Host: $HOSTALIAS
Address: $HOSTADDRESS
State: $HOSTSTATE

Date/Time: $LONGDATETIME

Additional Info: $HOSTOUTPUT

Comment: [$NOTIFICATIONAUTHORNAME] $NOTIFICATIONCOMMENT
TEMPLATE
)

/usr/share/gocode/bin/madonctl toot --visibility direct $(/usr/bin/printf "%b" "$template") 

And mastodon-service-notification.sh will be almost identical:

  

#!/bin/sh

export HOME=/var/lib/nagios

template=$(cat <<TEMPLATE
@$USERMASTODON Icinga $NOTIFICATIONTYPE - $HOSTDISPLAYNAME $SERVICEDISPLAYNAME is $SERVICESTATE

Notification Type: $NOTIFICATIONTYPE

Service: $SERVICEDESC
Host: $HOSTALIAS
Address: $HOSTADDRESS
State: $SERVICESTATE

Date/Time: $LONGDATETIME

Additional Info: $SERVICEOUTPUT

Comment: [$NOTIFICATIONAUTHORNAME] $NOTIFICATIONCOMMENT
TEMPLATE
)

/usr/share/gocode/bin/madonctl toot --visibility direct $(/usr/bin/printf "%b" "$template")
	   

(And if you don't know the printf command, it's time to learn.)

Now, let's declare this notification command to Icinga, in commands.conf:

object NotificationCommand "mastodon-host-notification" {
  command = [ SysconfDir + "/icinga2/scripts/mastodon-host-notification.sh" ]

  env = {
    NOTIFICATIONTYPE = "$notification.type$"
    HOSTALIAS = "$host.display_name$"
    HOSTADDRESS = "$address$"
    HOSTSTATE = "$host.state$"
    LONGDATETIME = "$icinga.long_date_time$"
    HOSTOUTPUT = "$host.output$"
    NOTIFICATIONAUTHORNAME = "$notification.author$"
    NOTIFICATIONCOMMENT = "$notification.comment$"
    HOSTDISPLAYNAME = "$host.display_name$"
    USERMASTODON = "$user.vars.mastodon$"
  }
}

object NotificationCommand "mastodon-service-notification" {
  command = [ SysconfDir + "/icinga2/scripts/mastodon-service-notification.sh" ]

  env = {
    NOTIFICATIONTYPE = "$notification.type$"
    HOSTALIAS = "$host.display_name$"
    HOSTADDRESS = "$address$"
    SERVICESTATE = "$service.state$"
    LONGDATETIME = "$icinga.long_date_time$"
    SERVICEOUTPUT = "$service.output$"
    NOTIFICATIONAUTHORNAME = "$notification.author$"
    NOTIFICATIONCOMMENT = "$notification.comment$"
    SERVICEDISPLAYNAME = "$service.display_name$"
    USERMASTODON = "$user.vars.mastodon$"
  }
}

We reference the scripts we just wrote. Note two things:

  • The environment variable USERMASTODON derives from user.vars.mastodon, not just user.mastodon, because mastodon is not a built-in attribute,
  • And we do not define the environment variable HOME in the env array above, since it seems ignored. Instead, we define it in the scripts (export HOME=/var/lib/nagios). Otherwise, madonctl cannot find the configuration file and complains "no instance provided".

Now, let's configure the notifications themselves, in notifications.conf:

   
apply Notification "mastodon-icingaadmin" to Host {
  import "mastodon-host-notification"

  user_groups = host.vars.notification.mastodon.groups
  users = host.vars.notification.mastodon.users

  assign where host.vars.notification.mastodon
}

apply Notification "mastodon-icingaadmin" to Service {
  import "mastodon-service-notification"

  user_groups = host.vars.notification.mastodon.groups
  users = host.vars.notification.mastodon.users

  assign where host.vars.notification.mastodon
}
  

We can now define the required variables for each host we're interested in, or in a general template if we want to be "tooted" for all our hosts. In templates.conf:

template Host "generic-host" {
...
  vars.notification["mastodon"] = {
    groups = [ "icingaadmins" ]
  }
}
  

And that's all. Restart Icinga and wait for the next problem to be "tooted". If you're impatient, break a host or a service to see what happens or, better, use the explicit notification function of Icinga (in the panel for a Host or a Service, near the top). You can see online an example of notification.


L'article seul

RFC 8145: Signaling Trust Anchor Knowledge in DNS Security Extensions (DNSSEC)

Date de publication du RFC : Avril 2017
Auteur(s) du RFC : D. Wessels (Verisign), W. Kumari (Google), P. Hoffman (ICANN)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 19 avril 2017


L'utilisation de DNSSEC implique que le résolveur DNS ait une ou plusieurs clés de départ de la validation (trust anchors). Typiquement, le résolveur aura une clé pour la racine, les autres domaines étant validés en suivant l'arborescence du DNS (cela se configure, même si la plupart des résolveurs viennent avec une pré-configuration pour la clé ICANN de la racine). Seulement, parfois, les clés changent et le gérant d'un domaine aimerait bien savoir, avant de supprimer l'ancienne clé, si les résolveurs ont bien tous reçu la nouvelle. D'où cette nouvelle option EDNS où le résolveur signale au serveur faisant autorité la liste des clés qu'il utilise comme point de départ de la validation. (Le RFC décrit également une autre méthode, non fondée sur EDNS.)

En toute rigueur, il faut dire que le résolveur ne transmet pas les clés mais les identificateurs courts (key tags ou key IDs), qui sont un condensat de 16 bits des clés (section 3.1.6 du RFC 4034, et notez dans l'annexe B du même RFC que ce ne sont pas des condensats cryptographiques). On trouve cet identificateur de clé si on utilise l'option +multi de dig :

% dig +multi DNSKEY tf
...
;; ANSWER SECTION:
tf.			172800 IN DNSKEY 257 3 8 (
                                ...
				) ; KSK; alg = RSASHA256; key id = 12520
tf.			172574 IN DNSKEY 256 3 8 (
                                ...
				) ; ZSK; alg = RSASHA256; key id = 51793
...
tf.			172574 IN RRSIG	DNSKEY 8 1 172800 (
				20170524190422 20170325180422 12520 tf.
...
    

Il est utilisé pour la communication entre humains mais on le trouve aussi dans les enregistrements DS chez le parent :

% dig DS tf
...
;; ANSWER SECTION:
tf.			86400 IN DS 12520 8 2 (
				2EC74274DD9AA7FFEA33E695EFF98F17F7C78ABD2D76
				EDBBDE4EDD4630D68FA2 )
...

Ainsi que dans les signatures :

% dig +dnssec SOA tf
...
;; ANSWER SECTION:
tf.			172800 IN SOA nsmaster.nic.fr. hostmaster.nic.fr. (
				2222242731 ; serial
                               ...
tf.			172800 IN RRSIG	SOA 8 1 172800 (
				20170531124004 20170401114004 51793 tf.
                                ...

On voit ici que la clé de .tf dans la racine est la 12520, qui signe la clé 51793, qui elle-même signe les enregistrements.

Si vous n'êtes pas parfaitement au point sur la terminologie DNSSEC, lisez la section 3 du RFC. Et, à titre d'exemple, voici la configuration d'un résolveur Unbound pour utiliser comme clés de départ de la validation celles de Yeti :

% cat /etc/unbound/unbound.conf
...
server:
    ...
    auto-trust-anchor-file: "/var/lib/unbound/yeti.key"
    ...

% cat /var/lib/unbound/yeti.key
.	86400	IN	DNSKEY	257 3 8 AwE...8uk= ;{id = 59302 (ksk), size = 2048b} ;;state=1 [ ADDPEND ] ;;count=67 ;;lastchange=1488474089 ;;Thu Mar  2 18:01:29 2017
.	86400	IN	DNSKEY	257 3 8 AwE...y0U= ;{id = 19444 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1472139347 ;;Thu Aug 25 17:35:47 2016

On voit deux clés, d'identificateurs 59302 et 19444. Tout contenu signé avec une de ces deux clés sera accepté. (Le fait qu'il y ait deux clés alors qu'une suffirait est dû au fait qu'un changement est en cours, suivant le RFC 5011.)

Voyons maintenant la première façon de signaler ses clés dont dispose un résolveur, la méthode EDNS (section 4 de notre RFC, et voir le RFC 6891, pour les détails sur ce qu'est EDNS). On utilise une nouvelle option EDNS, edns-key-tag (code 14 dans le registre IANA). Comme toutes les options EDNS, elle comprend le code (14), la longueur, puis une suite d'identificateurs de clés. Par exemple, le résolveur Unbound montré plus haut enverrait une option {14, 4, 59302, 19444} (longueur quatre car il y a deux identificateurs, de deux octets chacun). Il est recommandé d'utiliser cette option pour toutes les requêtes de type DNSKEY (et jamais pour les autres).

Notez que le serveur qui reçoit une requête avec cette option n'a rien à faire : elle est juste là pour l'informer, la réponse n'est pas modifiée. S'il le souhaite, le serveur peut enregistrer les valeurs, permettant à son administrateur de voir, par exemple, si une nouvelle clé est largement distribuée (avant de supprimer l'ancienne).

La deuxième méthode de signalisation, celle utilisant le QNAME (Query Name, le nom indiqué dans la requête DNS) figure en section 5. La requête de signalisation utilise le type NULL (valeur numérique 10), et un nom de domaine qui commence par « _ta- », suivi de la liste des identificateurs en hexadécimal (dans cet article, ils étaient toujours montré en décimal) séparés par des traits. Le nom de la zone pour laquelle s'applique ces clés est ajouté à la fin (la plupart du temps, ce sera la racine, donc il n'y aura rien à ajouter). En reprenant l'exemple du résolveur Unbound plus haut, la requête sera _ta-4bf4-e7a6.. Comme ce nom n'existe pas, la réponse sera certainement NXDOMAIN.

Le serveur utilise cette requête comme il utilise l'option EDNS : ne rien changer à la réponse qui est faite, éventuellement enregistrer les valeurs indiquées, pour pouvoir informer l'administrateur du serveur.

Voilà, comme vous voyez, c'est tout simple. Reste quelques petites questions de sécurité (section 7) et de vie privée (section 8). Pour la sécurité, comme, par défaut, les requêtes DNS passent en clair (RFC 7626), un écoutant indiscret pourra savoir quelles clés utilise un résolveur. Outre que cela peut permettre, par exemple, de trouver un résolveur ayant gardé les vieilles clés, la liste peut révéler d'autres informations, par exemple sur le logiciel utilisé (selon la façon dont il met en œuvre le RFC 5011). C'est donc un problème de vie privée également.

Notez aussi que le client peut mentir, en mettant de fausses valeurs. Par exemple, il pourrait envoyer de faux messages, avec une adresse IP source usurpée, pour faire croire que beaucoup de clients ont encore l'ancienne clé, de façon à retarder un remplacement.

(Au passage, si vous voulez des informations sur le remplacement des clés DNSSEC de la racine, voyez la page de l'ICANN, et la première expérimentation Yeti ainsi que la deuxième.)

Notez que le mécanisme utilisé a beaucoup varié au cours du développement de ce RFC (section 1.1, sur l'histoire). Au début, il n'y avait que l'option EDNS, en copiant sur le mécanisme du RFC 6975. Mais EDNS a quelques limites :

  • Il n'est pas de bout en bout : si une requête passe par plusieurs résolveurs, les options EDNS ne sont pas forcément transmises,
  • Il y a toujours le problème des stupides et bogués boitiers intermédiaires, qui bloquent parfois les paquets ayant une option EDNS qu'ils ne connaissent pas,
  • Comme l'option n'est pas forcément envoyée à chaque requête DNS, un résolveur pourrait avoir besoin de mémoriser les valeurs envoyées par ses clients, afin de les transmettre, ce qui l'obligerait à garder davantage d'état.

L'approche concurrente, avec le QNAME, a aussi ses inconvénients :

  • Elle ne permet pas de distinguer les clés connues du client, de celles connues par le client du client (si plusieurs résolveurs sont chaînés, via le mécanisme forwarder),
  • Elle nécessite deux requêtes, une avec la demande normale, une avec le QNAME spécial : en cas de répartition de charge entre serveurs, par exemple avec l'anycast, ces deux requêtes peuvent même aboutir sur des serveurs différents,
  • Enfin la requête avec le QNAME spécial peut ne pas être transmise du tout, en cas de mise en mémoire énergique des réponses négatives par un résolveur intermédiaire.

D'où le choix (chaudement discuté) de fournir les deux méthodes.

À l'heure actuelle, je ne connais pas de mise en œuvre de ce RFC.


Téléchargez le RFC 8145


L'article seul

Premier essai (raté) de raccordement à la Fibre

Première rédaction de cet article le 18 avril 2017
Dernière mise à jour le 19 avril 2017


Comme tout le monde, je voudrais un accès au Très Haut Débit de la Mort qui Tue, grâce à la fibre optique (en fait, c'est plus la meilleure latence qui m'intéresse, mais la publicité ne rentre pas dans ces subtilités). Il y a quelques années, j'ai donc rempli le formulaire en ligne auprès de mon opérateur pour avoir accès à cette merveilleuse technologie. J'ai finalement eu un rendez-vous le 18 avril pour l'arrivée de la fibre chez moi. Mais ça ne marche pas du premier coup.

D'abord, les faits. J'habite en « zone très dense », à Paris, et je suis donc a priori du bon côté de la fracture numérique. Il y a longtemps que je regarde avec envie la fibre qui est dans le garage au sous-sol :

Mais la faire monter dans les étages, et arriver dans les appartements, c'est autre chose. Ce sont les derniers mètres les plus durs. Les deux techniciens envoyés par Free sont arrivés à l'heure, mais sans reconnaissance préalable. Comme à chaque installation de fibre (d'après tous les témoignages que j'ai vu), ils découvrent le terrain à leur arrivée. Ils ont démonté la prise téléphonique, parce qu'il parait qu'elle abritait un fourreau (un tuyau en plastique) où glisserait la fibre. Sauf que… pas de fourreau visible. Même chose dans la prise libre à côté. Et dans la prise du câble, pas la place de faire glisser la fibre (et, apparemment, pas le droit d'arracher ce câble, qui ne sert pourtant à rien).

Problème : la fibre arrive bien sur le palier, mais comment la faire rentrer dans l'appartement s'il n'y a aucun fourreau qui arrive jusqu'aux prises ? Une solution évidente est de percer le mur et de faire une fibre à l'air, collée au mur pour gagner les prises. Outre le problème esthétique, cela impose de percer un mur qui ne m'appartient pas, puisqu'il fait l'interface avec les parties communes de l'immeuble. On va demander à la gardienne, qui explique que la société qui gère l'immeuble refuse absolument qu'on fasse cela, puisqu'il y a des fourreaux (soupir…). (Sur Mastodon, on m'a suggéré de percer sans demander l'autorisation, en espérant que cela ne se voit pas trop, mais une telle malhonnêté révulse ma conscience de citoyen.)

Bref, les techniciens repartent sans avoir pu résoudre le problème. Pas de fibre pour aujourd'hui.

Pourquoi est-ce si compliqué ? L'une des raisons est la multiplicité des acteurs (ah, les merveilles de la concurrence…) Il y a la propriétaire (la mairie), la société de gestion, le locataire (moi), le FAI (Free), la société qui fait les installations… Ces acteurs ne communiquent pas, et résoudre un problème prend donc beaucoup de temps, d'autant plus qu'il n'est pas facile de trouver un interlocuteur (j'avais demandé à Free si je pouvais parler avec les techniciens avant qu'ils viennent, pour discuter de deux ou trois problèmes que j'avais identifiés, mais ce n'est apparemment pas possible).

Ensuite, les documentations qu'on peut trouver en ligne semblent toutes faites pour un cas unique (on est propriétaire), qui n'est pas le mien (« vous devez soulever le problème en assemblée générale des copropriétaires »).

Bref, on est loin des discours. La connexion généralisée à la fibre optique fait partie des « grands sujets » sur lesquels on fait de nombreux colloques, des « Plan France Très Très Vraiment Très Haut Débit 2010-2020 », d'innombrables rapports, des promesses électorales (« je lancerai un plan fibre ambitieux doté de N millions de brouzoufs, pourqu'aucun de nos compatriotes ne reste tristement relié à l'ADSL ») et des déclarations ministérielles. Mais les problèmes concrets du terrain de base semblent largement ignorés.

Je ne suis pas le seul à avoir expérimenté des problèmes bêtes et pratiques lors de la pose de la fibre, voir l'excellent récit de Guigui ou bien celui de Tom.

Prochaine étape pour moi : appeler la société gestionnaire de l'immeuble, essayer d'y trouver quelqu'un qui comprenne mes questions, et demander pourquoi il n'y a pas de fourreaux, est-ce qu'on peut en faire poser, ou bien est-ce qu'on peut percer le mur sinon ?

Mise à jour : depuis la première parution de cet article, j'ai reçu d'innombrables conseils, notamment sur les réseaux sociaux. merci à tou·te·s pour les dits conseils, que je crois pouvoir classer en deux catégories. La première, ce sont les variantes autour de « on s'en fout des autorisations, perce, personne ne s'en apercevra et, s'ils râlent, envoie-les promener ». C'est radical, mais, outre l'aspect moral (violer les règles, c'est vilain, c'est comme télécharger du Johnny Hallyday sans l'autorisation des ayant-tous-les-droits), c'est risqué : un accident pendant l'opération et on a des ennuis.

Deuxième catégorie de conseils, les conseils techniques (« tirer le câble coaxial pour tirer une aiguille, et après se servir de cette aiguille pour retirer le câble et la fibre » ou bien « fais rentrer la fibre par le fourreau dans les parties communes, pousse-le et essaie de voir par où elle sort »). Ces conseils sont certainement très pertinents mais ils me font poser une question : pour avoir le Très Haut Débit de la Fibre chez soi, faut-il donc être à la fois juriste, entrepreneur en bâtiment, diplomate, et très bricoleur ? Le citoyen ordinaire qui ne sait pas faire grand'chose n'a-t-il pas droit lui aussi à la fibre ?


L'article seul

Hackathon de l'IETF

Première rédaction de cet article le 29 mars 2017


Bon, les hackathons, c'est un sujet banal, la majorité (la totalité ?) de mes lect·eur·rice·s ont déjà participé à un hackathon mais, pour moi, c'était la première fois. Donc, en mode « Stéphane découvre les hackathons après tout le monde », voici celui de l'IETF qui s'est tenu les 25 et 26 mars à Chicago.

Le concept est à la mode, c'est sûr, mais il est aussi extrêmement galvaudé. Toute startup, tout gouvernement, toute organisation de powerpointeurs se doit aujourd'hui d'avoir son hackathon. La plupart du temps, il s'agit juste de vagues rassemblements qui commencent à 10 h, s'interrompent de 12 à 14 h, et se terminent par des pitches à 16 h. Il s'agit d'avantage de séances de remue-méninges, voire de purs évenements de communication, que de vrais hackathons.

Mais, alors, c'est quoi, un « vrai » hackathon ? C'est avant tout un rassemblement où on produit quelque chose. Pas forcément des programmes, mais c'est souvent le cas, puisque le concept vient du monde de l'informatique. Le hackathon, pour moi, c'est une occasion où on parle, certes, on échange, mais il y a un but concret, à la fin, on a quelque chose qui tourne. Et comme le vrai travail prend du temps, un hackathon ne peut pas se dérouler en seulement quelques heures.

Et celui de l'IETF, c'est un « vrai » ? La tâche principale de l'IETF n'est pas de développer des programmes, c'est d'écrire des normes. Certes, l'IETF a toujours tiré fierté de son caractère concret, de l'importance donnée au « running code », au code qui marche. Mais la production de logiciels n'était pas une activité organisée de l'IETF. C'est seulement en 2015, à la réunion de Dallas, que l'IETF a organisé un hackathon, le week-end précédent la réunion. Ce n'est donc pas une vieille tradition.

On travaille sur quoi, à un hackathon IETF ? L'idée est évidemment de travailler sur les techniques IETF, donc toute la famille TCP/IP. Mais la priorité est surtout donnée aux normes en cours de développement : une mise en œuvre précoce peut aider à détecter des problèmes dans la spécification, apprécier son réalisme, avoir une idée des performances. La plupart des développeurs présents travaillaient donc sur des idées documentées dans un Internet-Draft.

Nous étions 14 équipes, chacune travaillant sur un sujet spécifique de l'IETF. La liste des équipes est disponible sur le Wiki du hackathon. J'étais dans l'équipe DNS (évidemment, vont dire certains). Globalement, c'est très libre, chacun travaille sur ce qu'il veut, et si on veut que les autres vous suivent, il faut les convaincre. Comme pour tout bon hackathon, on avait une salle de l'hôtel, du courant électrique, du Wifi, du café à volonté et de temps en temps des repas qui apparaissaient magiquement (non, je rigole, c'est Mozilla et Ericsson qui payaient les repas).

Chacun avait évidemment son ordinateur portable mais quelques uns avaient du matériel plus spécialisé comme l'équipe multicast :

À partir de là, chaque équipe a fait ses plans (voici le projet CAPPORT, le groupe de travail IETF qui essaie de nous sauver de ces affreux portails captifs, voir par exemple le RFC 7710) :

J'ai beaucoup aimé le concept. C'est très sympa de passer un week-end à ne faire que programmer et discuter d'informatique. L'ambiance était bonne (je craignais un peu que ce soit assez viriliste, tendance piscine d'une école parisienne à la mode, mais non). En prime, j'ai pu terminer mon sujet. Tout programme informatique moderne dépend d'autres programmes et bibliothèques et, souvent, les difficultés viennent de ces autres programmes qui ne font pas ce qu'on veut. Il faut alors prévenir le développeur, attendre qu'il réagisse. Ici, j'utilisais surtout la bibliothèque de programmes getdns et le développeur, Willem Toorop, était assis juste à côté de moi, je pouvais donc lui demander des trucs (« ya pas moyen de récupérer le certificat X.509 du pair, dans la struct renvoyée par un call reporting ? ») et il le faisait tout de suite (« j'ai mis ton truc, c'est dans la branche devel/, attention, j'ai pas testé »).

Allez, une image de nourriture, pour finir, pour montrer qu'on ne mangeait pas que des pizzas :


L'article seul

RFC 8073: Coordinating Attack Response at Internet Scale (CARIS) Workshop Report

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : K. Moriarty (Dell EMC Corporation), M. Ford (Internet Society)
Pour information
Première rédaction de cet article le 29 mars 2017


Ce nouveau RFC fait le bilan de l'atelier CARIS (Coordinating Attack Response at Internet Scale) qui s'est tenu à Berlin le 18 juin 2015. Cet atelier avait pour but d'explorer les problèmes de coordination entre les victimes et témoins d'une attaque portant sur l'Internet. Ce RFC est un compte-rendu, les positions exprimées ne sont pas forcément celles de l'IAB ou de l'Internet Society (organisateurs de l'atelier). D'autant plus que les participants ont mis les pieds dans le plat, expliquant très bien pourquoi il n'y a toujours pas de coordination globale des acteurs de l'Internet face aux attaques.

L'atelier avait été organisé pour que les participants à la réunion FIRST de Berlin puissent venir. Il rassemblait cinquante acteurs (c'était un atelier fermé, sur invitation seulement) de l'Internet, représentant une grande diversité d'organisations. La liste des participants figure dans l'annexe B du RFC. Chaque participant avait rempli un article de deux pages expliquant son point de vue et/ou les problèmes qu'il·elle souhaitait aborder. Tous ces documents sont disponibles en ligne (je vous encourage à les lire). Dans le reste du RFC, n'attendez pas d'attribution de tel discours à tel participant, l'atelier était tenu sous la règle de Chatham House, pour que les discussions restent libre.

L'atelier a vu cinq sessions (cf. section 2 du RFC) autour de ce thème des attaques, et de la coordination pour y faire face :

  • Coordination entre les CSIRT, et avec ceux qui combattent directement l'attaque,
  • Répondre aux dDoS et aux botnets, avec passage à l'échelle pour les attaques de grande ampleur que nous voyons aujourd'hui,
  • Infrastructure de l'Internet, notamment les acteurs du DNS, et les RIR,
  • Problèmes de confiance et de confidentialité dans les échanges entre acteurs de l'Internet (un très gros sujet lors de l'atelier),
  • Conséquences des attaques sur l'architecture de l'Internet, et sur ses futures évolutions. (Peu de détails données dans le RFC sur cette dernière session.)

Parmi les organisations qui ont participé à la première session, on notait, entre autres :

  • L'ENISA qui, quoiqu'elle fasse de la formation et de l'échange, n'a pas directement d'activité concernant les attaques pendant qu'elles se produisent (l'ENISA n'est pas « temps réel »).
  • L'APWG, qui a un mécanisme d'échange entre acteurs (une clearing house).
  • Le Ren-ISAC (si vous ne savez pas ce qu'est un ISAC, c'est le moment d'apprendre) qui sert de point de partage d'informations dans le monde académique états-unien. Cet organisme permet une mutualisation des efforts (bien des universités n'ont pas les moyens d'avoir une équipe à temps plein pour réagir aux attaques 24 heures sur 24).
  • Le CERT brésilien, qui joue un rôle essentiel dans ce pays. Bien des pays, contrairement au Brésil, n'ont pas un CERT national mais plein de petits CERT limités à un groupe ou une entreprise.

Les principaux points mis en avant pendant cette session ont été :

  • La surveillance de masse effectuée par les États a mis en danger les mécanismes de coordination, en réduisant la confiance. On note qu'au contraire de tant de colloques bavards et convenus sur la cybersécurité, l'atelier CARIS n'a pas pratiqué la langue de bois. Au lieu de répéter en boucle que la cybersécurité était importante, qu'elle reposait sur l'échange et la coordination, les participants ont directement pointé les vrais problèmes  : les acteurs n'ont pas confiance dans l'État, et pour des très bonnes raisons, ce qui diminue l'éfficacité du travail en commun.
  • Les tentatives des certains États d'encourager le partage d'informations (par exemple via une agence nationale) n'ont pas été des succès.
  • Tout le monde veut que les autres partagent de l'information mais personne ne veut en donner. Ici encore, l'atelier pointe un problème que tout le monde connait, mais dont on ne parlait pas publiquement.
  • Outre les simples problèmes d'ego, le partage d'informations est handicapé par les craintes des organisations pour leur réputation : si on dit la vérité sur une attaque qu'on n'a pas bien paré, on va paraitre faible.
  • Les barrières de langue sont un gros problème. (Le RFC ne le dit pas, mais tout le monde pense aux immenses difficultés de communication avec les acteurs chinois. Des listes de diffusion comme celles de NANOG sont pleines de remarques amères « j'ai signalé le problème au FAI chinois et il n'a rien fait », sans que leur auteur se demande comment lui réagirait s'il recevait un rapport d'attaque écrit en mandarin. Contrairement à ce que pourrait laisser croire un certain discours globaliste, tout le monde ne parle pas anglais. Sans compter les problèmes culturels, encore plus difficiles.)
  • Les règles de protection de la vie privée (comme le réglement européen sur la protection des données personnelles) peuvent gêner l'échange d'information (on n'envoie pas un fichier contenant des adresses IP aux USA). (Derrière cette remarque, on peut lire l'agacement des États-Unis - qui eux-même n'envoient pas de données - face aux lois européennes plus protectrices, mais aussi le regret des professionnels de la lutte contre les attaques informatiques, face à des lois prévues pour traiter d'autres problèmes que les leurs.)

Deuxième session, sur les mesures de lutte contre les dDoS et les botnets, notamment sur la question du passage à l'échelle de ces efforts. Les points essentiels abordé furent :

  • Les mesures prises jusqu'à présent ont été plutôt efficaces. (C'était avant l'attaque contre Dyn, et le RFC ne mentionne pas le fait que la plupart de ces « mesures efficaces » ne sont accessibles qu'aux gros acteurs, ou à leurs clients, et que le petit hébergeur reste aussi vulnérable qu'avant.)
  • La tension entre les réactions à court terme (stopper l'attaque en cours) et les exigences du long terme (éradiquer réellement le botnet, ce qui implique de le laisser « travailler » un certain temps pour l'étudier) reste entière. Sans compter, là aussi, le manque d'échanges entre pompiers de la lutte anti-dDoS et chasseurs de botnets.
  • Il existe des groupes où règne une certaine confiance mutuelle comme le peu documenté CRAG.
  • Trier le trafic entrant, puis le filtrer, est un problème soluble. (Je note personnellement que, pour l'instant, les seules solutions sont des boîtes noires fermées. Un problème pour les gens attachés à la liberté.)
  • Il existe un groupe de travail IETF nommé DOTS qui travaille sur des mécanismes techniques facilitant l'échange de données pendant une attaque. Un effort précédant de l'IETF avait mené au RFC 6545. Les deux solutions sont conceptuellement proches mais DOTS est plus récent, devrait utiliser des techniques modernes et semble avoir davantage de soutiens de la part des acteurs.
  • Il existe une certaine dose de confiance dans le milieu mais pas complète. On ne peut pas toujours faire confiance aux informations reçues. À cette session également, le problème des services d'espionnage étatiques a été mentionné, comme une grosse menace contre la confiance.
  • La question brûlante des « arrêts automatiques » (automated takedowns) a été mentionnée. Certains cow-boys voudraient, compte-tenu de la rapidité des phénomènes en jeu, que certaines décisions puissent être automatiques, sans intervention humaine. Par exemple, un nom de domaine est utilisé pour une attaque « random QNAMEs », l'attaque est analysée automatiquement, signalée au registre et paf, le nom de domaine est supprimé. Inutile de dire que l'idée est très controversée.

Ensuite, troisième session, consacrée aux organisations de l'infrastructure DNS (par exemple les registres) et aux RIR. Les points étudiés :

  • L'utilisation du passive DNS (par exemple DNSDB) pour analyser certaines attaques.
  • Les données que détiennent les RIR, en raison de leur activité mais aussi suite à divers projets non directement liés à leur activité (comme l'observation des annonces BGP ou comme la gestion d'un serveur racine du DNS). Des participants ont regretté l'absence d'API standard pour accéder à ces données.
  • Certains des RIR ont déjà une coordination active avec des organisations qui réagissent en cas d'attaques.

Quatrième session, les problèmes de confiance. Tout le monde est d'accord pour dire que c'est cool de partager les données, et que c'est indispensable pour lutter efficacement contre les attaques. Alors, pourquoi si peu d'organisations le font ? Il n'y a clairement pas une raison unique. C'est un mélange de crainte pour la vie privée, de contraintes juridiques, de problèmes techniques, de différences culturelles et de simples malentendus. Sans compter le pur égoïsme (« partager mes données avec nos concurrents ??? ») Enfin, il faut rappeler qu'il est impossible de s'assurer du devenir de données numériques : si on passe nos données à quelqu'un, pour aider pendant une attaque, que deviendront-elles après ? (Envoyer des données aux USA, c'est la certitude qu'elles seront vendues et revendues.) Le RFC note que tous les participants à l'atelier ont estimé que ces raisons étaient mauvaises ou, plus exactement, qu'on pouvait trouver des solutions. Les points précis discutés :

  • La réputation est cruciale : il y a des gens à qui on envoie toutes les données qu'ils veulent et d'autres à qui on ne transmettra rien. (Sans la règle de Chatham House, on peut parier que personne n'aurait osé exprimer cette évidence pendant l'atelier.)
  • L'utilisation du TLP (certains participants regrettent son manque de granularité, je pense personnellement que déjà trop de gens ont du mal avec ses quatre niveaux).
  • Officielement, la confiance est entre organisations. En réalité, elle est entre individus (personne ne fait confiance à un machin corporate) et il faut donc développer des liens entre individus. En outre, la confiance est forcément limitée en taille : on ne fait confiance qu'à ceux qu'on connait et on ne peut pas connaître tout le monde. Comme le dit le RFC, «  Social interaction (beer) is a common thread amongst sharing partners to build trust relationships ».
  • Par analogie avec les marques déposées, certains se sont demandés s'il faudrait un mécanisme de labelisation de la confiance.
  • Plusieurs participants ont remarqué que le travail réel ne se faisait pas dans les structures officielles, mais dans des groupes fondés sur des relations de confiance. (Le RFC utilise le terme classique des geeks pour parler de ces groupes : cabals.) Comme le dit le RFC pudiquement, « This was not disputed. » (autrement dit, tout le monde le savait bien mais ne le disait pas).

La section 4 du RFC concerne le « et maintenant ? ». Il y a eu un consensus sur la nécessité de la formation (au sens large). Par exemple, on trouve toujours des professionnels de l'Internet qui ne connaissent pas BCP 38. Du travail pour les pédagogues (et les auteurs de blogs...)

Plus technique, la question des mécanismes techniques d'échange d'information a suscité des débats animés. Le RFC 6545 date de plus de dix ans. Il ne semble pas être universellement adopté, loin de là. Le groupe de travail DOTS fera-t-il mieux ? D'autres techniques ont été discutées comme TAXII ou XMPP-Grid. Ce dernier, fondé sur XMPP (RFC 6120) semble prometteur et est déjà largement mis en œuvre. Le groupe de travail nommé MILE a aussi un protocole nommé ROLIE (pas encore de RFC).


Téléchargez le RFC 8073


L'article seul

Developing a monitoring plugin for DNS-over-TLS at the IETF hackathon

First publication of this article on 27 March 2017


The weekend of 25-26 march 2017, I participated to the IETF 98 hackathon in Chicago. The project was to develop a monitoring plugin for the DNS-over-TLS privacy protocol, standardized in RFC 7858. This is a small documentation of the result and of the lessons learned.

A bit of background, first. "Monitoring Plugins" is project to develop and maintain an excellent suite of testing programs to be used by many monitoring software like Icinga. Using their API was an obvious choice, allowing the plugin to be used in many places. And DNS-over-TLS? It's a way to improve privacy of DNS users by encrypting the DNS traffic (see RFC 7626 for the privacy issues of the DNS). DNS-over-TLS is described in RFC 7858, published less than one year ago. DNS-over-TLS is implemented in many DNS servers (such as Unbound) and there are several public DNS-over-TLS resolvers. All of them are experimental, "best effort" services and thus some monitoring is a good idea, so we can be sure they actually work most of the time. Existing monitoring plugins like check_dig cannot run with TLS.

The IETF hackathon is intended for development of IETF-related techniques. A monitoring plugin for this DNS-over-TLS service is a good fit for a hackathon: hard enough to require some work, but small enough to be reasonably completed in one weekend.

I prepared for the hackathon by setting up a Github repository and exploring the various possibilities. I saw two alternatives:

  • Use Go because it has both a nice DNS library and a good TLS standard package. On the other hand, I'm not sure that the Monitoring Plugins project accept plugins written in Go (I did not find precise rules about that). And the command line arguments parsing package of Go may make difficult to follow exactly the rules of the API.
  • Use C with the getdns package, which can do DNS over TLS (and many other things). Because most monitoring plugins are written in C, there was a lot of code to start with.

I choosed C and getdns for two reasons, the availability of getdns developers at the hackathon (that's the good thing with hackathons, working with people who are at the same table), and the problem of retrieving the PKIX certificate. Why did I need this certificate? Because I wanted to test things that are TLS-specific, such as a nearby expiration, by far the most common problem with TLS servers.

Using Go and the godns library, it is easy to do a DNS-over-TLS request with the Exchange() function. It is easy because it hides everything from the programmer. But it is also what makes it unsuitable for my purpose, it hides the TLS details and provides no way to retrieve the certificate. A possible solution would be to use godns only to create and parse DNS messages and to call directly the Go network and TLS libraries to send messages and receive responses. Then, I would have the certificate in the conn object. Certainly doable, but more work. So, I used C and getdns.

At first glance, it was not better, getdns does not give access to the certificate of the TLS connection. But this is what makes hackathons great: the developer of the library you use is in the same room and you can ask him "Willem, could you add this cool feature?", and a few minutes after, the feature is available in a git development branch. Basically, the new stuff uses the return_call_reporting getdns extension:

getdns_dict_set_int(extensions, "return_call_reporting",
                            GETDNS_EXTENSION_TRUE);     
    

and then you have a dictionary member call_reporting in the answer:

getdns_list    *report_list;
getdns_dict    *report_dict;
getdns_dict_get_list(this_response, "call_reporting", &report_list);
getdns_list_get_dict(report_list, 0, &report_dict);
    

The dictionary in the report has now a new member, tls_peer_cert (it will appear in getdns 1.1):

getdns_bindata *cert;
getdns_dict_get_bindata(report_dict, "tls_peer_cert", &cert);

To parse this certficate (which is in DER format), I use GnuTLS:

gnutls_datum_t  raw_cert;
time_t          expiration_time;
struct tm      *f_time;
raw_cert.size = cert->size;
raw_cert.data = malloc(cert->size);
memcpy(raw_cert.data, cert->data, cert->size);
gnutls_x509_crt_import(parsed_cert, &raw_cert, GNUTLS_X509_FMT_DER);
expiration_time = gnutls_x509_crt_get_expiration_time(parsed_cert);
strftime(msgbuf, 1000, "%Y-%m-%d", f_time);
printf("Expires on %s\n", msgbuf);

Now, I can test things like an incoming expiration of the certificate.

Another touchy issue was authentication. RFC 7858 allows to authenticate the server by a pinned cryptographic key. (Another authentication methods are under development at the IETF, see draft-ietf-dprive-dtls-and-tls-profiles.) That's another problem for Go, by the way: authentication is inflexible, and done by the TLS library. For getdns, on the contrary, is easy: just provide the pinned keys and getdns does the necessary checks:

    
keys = getdns_pubkey_pin_create_from_string(this_context, raw_keys);
getdns_list    *keys_list = getdns_list_create();
getdns_list_set_dict(keys_list, 0, keys);
getdns_dict_set_list(this_resolver, "tls_pubkey_pinset", keys_list);

and the result of the authentication is reported in the "call reporting" dictionary we already saw:

getdns_bindata *auth_status;
getdns_dict_get_bindata(report_dict, "tls_auth_status", &auth_status);
printf("Authentication is %s\n", auth_status->data);

Now, let's put it all together, compile and test from the command line (the arguments are the standard ones for the monitoring plugins, the servers are public servers):

    
% ./check-dns-with-getdns -H 2620:ff:c000:0:1::64:25 -n www.ietf.org
GETDNS OK - 121 ms, expiration date 2027-08-25, auth. Failed:  Address 2400:cb00:2048:1::6814:55 Address 2400:cb00:2048:1::6814:155 Address 104.20.0.85 Address 104.20.1.85

% echo $?
0

(We ask the return code of the command but this is what the monitoring software uses to find out whether everything is fine or not.) The authentication status was "Failed" because the server uses a self-signed certificate (otherwise, we would have obtained "None"). Here, we did not require authentication, so the global result is still OK. Should we provide the pinned key, it would be better:

% ./check-dns-with-getdns -H 2620:ff:c000:0:1::64:25 -n www.afnic.fr -k pin-sha256=\"pOXrpUt9kgPgbWxBFFcBTbRH2heo2wHwXp1fd4AEVXI=\"
GETDNS OK - 1667 ms, expiration date 2027-08-25, auth. Success:  Address 2001:67c:2218:30::24 Address 192.134.5.24

% echo $?
0

If the key is wrong, it fails:

% ./check-dns-with-getdns -H 2620:ff:c000:0:1::64:25 -n www.afnic.fr -a -k pin-sha256=\"pOXrpUt9kgPgbWxBFFcBTbRI2heo2wHwXp1fd4AEVXI=\"       
GETDNS CRITICAL - 123 ms, expiration date 2027-08-25, auth. Failed:  Address 2001:67c:2218:30::24 Address 192.134.5.24

And if the key is wrong and we require authentication (-r), we get a fatal error:

 % ./check-dns-with-getdns -H 2620:ff:c000:0:1::64:25 -n www.afnic.fr -r -k pin-sha256=\"pOXrpUt9kgPgbWxBFFcBTbRI2heo2wHwXp1fd4AEVXI=\" 
GETDNS CRITICAL - Error Generic error (1) when resolving www.afnic.fr at 2620:ff:c000:0:1::64:25

% echo $?
2

And of course, if the server has no DNS-over-TLS or if the server is down, or access to port 853 blocked, we also get an error:

% ./check-dns-with-getdns -H 8.8.8.8 -n www.afnic.fr                
GETDNS CRITICAL - Error Generic error (1) when resolving www.afnic.fr at 8.8.8.8

% echo $?                                            
2

(You can also appreciate the lack of details in error messages…)

Once it is tested, we can put it in a monitoring program. I choosed Icinga. The configuration is:

object CheckCommand "dns_with_getdns" {
  command = [ PluginContribDir + "/check_dns_with_getdns" ]

  arguments = {
        "-H" = "$address$",
        "-n" = "$dns_with_getdns_lookup$",
        "-a" = "$dns_with_getdns_authenticate$",
        "-e" = "$dns_with_getdns_accept_errors$",
        "-r" = "$dns_with_getdns_require_auth$",
	"-k" = "$dns_with_getdns_keys$",
        "-C" = "$dns_with_getdns_certificate$"
        }
}  

apply Service "dns-tls" {
  import "generic-service"

  check_command = "dns_with_getdns"
  assign where (host.address || host.address6) && host.vars.dns_over_tls
  vars.dns_with_getdns_lookup = "www.ietf.org"
  vars.dns_with_getdns_certificate = "7,3"
  vars.dns_with_getdns_accept_errors = false
}
     
object Host "oarc-dns" {
  import "generic-host"

  address = "2620:ff:c000:0:1::64:25"

  vars.dns_over_tls = true

  vars.dns_with_getdns_authenticate = true
  vars.dns_with_getdns_keys = "pin-sha256=\"pOXrpUt9kgPgbWxBFFcBTbRH2heo2wHwXp1fd4AEVXI=\""
}

Then we get the goal of every hackathon project: a screenshot .

Now, I'm not sure if I'll have time to continue to work on this project. There are several TODO in the code, and an ambitious goal: turn it into a proper plugin suitable for inclusion on the official Monitoring Plugins project. Even better would be to have a generic DNS checker based on getdns, replacing the existing plugins which depend on external commands such as dig. If you want to work on it, the code is at Github.

Many thanks to Willem Toorop for a lot of help and getdns additions, to Francis Dupont for debugging a stupid C problem with GnuTLS (garbage data, unaligned access, all the pleasures of C programming), and to Sara Dickinson for help, inspiration and animation of the DNS team.


L'article seul

Le transit Internet est-il vraiment mort ?

Première rédaction de cet article le 21 mars 2017


À la réunion APRICOT / APNIC du 20 février au 2 mars, à Hô-Chi-Minh-Ville, Geoff Huston a fait un exposé remarqué, au titre provocateur, « The death of transit ». A-t-il raison de prédire la fin du transit Internet ? Et pourquoi est-ce une question importante ?

Deux petits mots de terminologie, d'abord, s'inscrivant dans l'histoire. L'Internet avait été conçu comme un réseau connectant des acteurs relativement égaux (par exemple, des universités), via une épine dorsale partagée (comme NSFnet). Avec le temps, plusieurs de ces épines dorsales sont apparues, l'accès depuis la maison, l'association ou la petite entreprise est devenu plus fréquent, et un modèle de séparation entre les FAI et les transitaires est apparu. Dans ce modèle, le client se connecte à un FAI. Mais comment est-ce que les FAI se connectent entre eux, pour que Alice puisse échanger avec Bob, bien qu'ils soient clients de FAI différents ? Il y a deux solutions, le peering et le transit. Le premier est l'échange de trafic (en général gratuitement et informellement) entre des pairs (donc plus ou moins de taille comparable), le second est l'achat de connectivité IP, depuis un FAI vers un transitaire. Ces transitaires forment donc (ou formaient) l'épine dorsale de l'Internet. Le modèle de l'Internet a été un immense succès, au grand dam des opérateurs téléphoniques traditionnels et des experts officiels qui avaient toujours proclamé que cela ne marcherait jamais.

Mais une autre évolution s'est produite. Les utilisateurs ne se connectent pas à l'Internet pour le plaisir de faire des ping et des traceroute, ils veulent communiquer, donc échanger (des textes, des images, des vidéos…) À l'origine, l'idée était que l'échange se ferait directement entre les utilisateurs, ou sinon entre des serveurs proches des utilisateurs (ceux de leur réseau local). Le trafic serait donc à peu près symétrique, dans un échange pair-à-pair. Mais les choses se ne passent pas toujours comme ça. Aujourd'hui, il est de plus en plus fréquent que les communications entre utilisateurs soient médiées (oui, ce verbe est dans le Wiktionnaire) par des grands opérateurs qui ne sont pas des opérateurs de télécommmunication, pas des transitaires, mais des « plate-formes » comme les GAFA (Google, Apple, Facebook, Amazon). La communication entre utilisateurs n'est plus pair-à-pair mais passe par un intermédiaire. (On peut parler d'un Minitel 2.0.)

Bon, mais quel rapport avec l'avenir de l'Internet ? Mes lect·eur·rice·s sont très cultivé·e·s et savent bien que le Web, ce n'est pas l'Internet, et que le fait que deux utilisateurs de Gmail passent par Gmail pour communiquer alors qu'ils sont à 100 mètres l'un de l'autre n'est pas une propriété de l'Internet. (Les ministres et la plupart des journalistes n'ont pas encore compris cela, mais ça viendra.) L'Internet continue à fonctionner comme avant et on peut toujours faire du BitTorrent, et se connecter en SSH avec un Raspberry Pi situé à l'autre bout de la planète. (Notez qu'il s'agit de l'Internet en général : dans la quasi-totalité des aéroports et des hôtels, de nombreux protocoles sont interdits. Et ces malhonnêtes osent prétendre qu'ils fournissent un « accès Internet ».)

C'est là qu'on en arrive à l'exposé de Huston. Il note d'abord que les sites Web qui ne sont pas déjà chez un GAFA sont souvent hébergés sur un CDN. Ensuite, il fait remarquer que les GAFA, comme les CDN, bâtissent de plus en plus leur propre interconnexion. À ses débuts, Google était une entreprise comme une autre, qui achetait sa connectivité Internet à un fournisseur. Aujourd'hui, Google pose ses propres fibres optiques (ou achète des lambdas) et peere avec les FAI : encore un peu et Google n'aura plus besoin de transit du tout. Si tous les GAFA et tous les CDN en font autant (et la plupart sont déjà bien engagés dans cette voie), que deviendra le transit ? Qui pourra encore gagner sa vie en en vendant ? Et si le transit disparait, l'architecture de l'Internet aura bien été modifiée, par l'action de la minitélisation du Web. (Je résume beaucoup, je vous invite à lire l'exposé de Huston vous-même, ainsi que son article sur des thèmes proches.)

Notez que Huston n'est pas le premier à pointer du doigt cette évolution. Plusieurs articles moins flamboyants l'avaient déjà fait, comme les déjà anciens « The flattening internet topology: natural evolution, unsightly barnacles or contrived collapse? » ou « Internet Inter-Domain Traffic ». Mais Huston réussit toujours mieux à capter l'attention et à résumer de manière percutante un problème complexe.

Alors, si Huston a raison, quelles seront les conséquences de la disparition du transit ? Huston note qu'une telle disparition pourrait rendre inutile le système d'adressage mondial (déjà très mal en point avec l'épuisement des adresses IPv4 et la prévalence du NAT), voire le système de nommage mondial que fournit le DNS. Le pair-à-pair, déjà diabolisé sur ordre de l'industrie du divertissement, pourrait devenir très difficile, voire impossible. Aujourd'hui, même si 95 % des utilisateurs ne se servaient que des GAFA, rien n'empêche les autres de faire ce qu'ils veulent en pair-à-pair. Demain, est-ce que ce sera toujours le cas ?

Mais est-ce que Huston a raison de prédire la mort du transit ? D'abord, je précise que je suis de ceux qui ne croient pas à la fatalité : ce sont les humains qui façonnent l'histoire et les choses peuvent changer. Décrire la réalité, c'est bien, mais il faut toujours se rappeler que c'est nous qui la faisons, cette réalité, et que nous pouvons changer. Essayons de voir si les choses ont déjà changé. Huston aime bien provoquer, pour réveiller son auditoire. Mais il faut bien distinguer l'apparence et la réalité.

Les observateurs légers croient que tout l'Internet est à leur image. Comme eux-même ne se servent que de Gmail et de Facebook, ils expliquent gravement en passant à la télé que l'Internet, c'est Google et Facebook. Mais c'est loin d'être la totalité des usages. Des tas d'autres usages sont présents, par exemple dans l'échange de données entre entreprises (y compris via d'innombrables types de VPN qui transportent leurs données… sur Internet), les SCADA, BitTorrent, la recherche scientifique et ses pétaoctets de données, les réseaux spécialisés comme LoRa, les chaînes de blocs, et ces usages ne passent pas par les GAFA.

Peut-on quantifier ces usages, pour dire par exemple, qu'ils sont « minoritaires » ou bien « un détail » ? Ce n'est pas facile car il faudrait se mettre d'accord sur une métrique. Si on prend le nombre d'octets, c'est évidemment la vidéo qui domine et, à cause du poids de YouTube, on peut arriver à la conclusion que seuls les GAFA comptent. Mais d'autres critères sont possibles, quoique plus difficiles à évaluer (le poids financier, par exemple : un message d'une entreprise à une autre pour un contrat de centaines de milliers d'euros pèse moins d'octets qu'une vidéo de chat, mais représente bien plus d'argent ; ou bien le critère de l'utilité sociale). Bref, les opérateurs de transit sont loin d'être inutiles. L'Internet n'est pas encore réduit à un Minitel (ou à une télévision, l'exemple que prend Huston qui, en bon Australien, ne connait pas ce fleuron de la technologie française.)

Merci à Antoine Fressancourt, Jérôme Nicolle, Pierre Beyssac, Raphaël Maunier, Olivier Perret, Clément Cavadore et Radu-Adrian Feurdean pour leurs remarques intéressantes. Aucune de ces conversations avec eux n'est passée par un GAFA.


L'article seul

Suite de mes aventures avec le routeur Turris Omnia

Première rédaction de cet article le 19 mars 2017


Dans un précédent article, j'ai parlé du routeur Turris Omnia et de ce qu'on peut faire avec. Ce deuxième article est un assortiment de diverses choses que j'ai faites depuis avec ce routeur.

Il est connecté à Free en ADSL. Plus exactement, l'ADSL arrive sur une Freebox Révolution, configurée en bridge, à laquelle est relié le Turris Omnia, qui est le vrai routeur. À l'origine, j'avais laissé le Freebox Player connecté au Freebox Server, ce qui faisait que la télévision classique et le téléphone marchaient comme avant. Mais comme je voulais regarder les chaînes de télévision depuis un PC, avec VLC et le protocole RTSP (RFC 7826), il fallait connecter le Freebox Player au routeur. Je me suis beaucoup inspiré de cet excellent article. Donc, ce qu'il fallait faire :

  • Connecter le câble Ethernet entre le Turris et le Freebox Player (celui-ci n'a donc plus de câble vers le Freebox Server),
  • Configurer le commutateur du Turris pour utiliser le VLAN 100, celui sur lequel Freebox Player et Server communiquent.

Attention en jouant avec la configuration du commutateur interne du Turris : une erreur et on se retrouve vite avec des tempêtes de diffusion, qui peuvent aller jusqu'à rendre le routeur inaccessible en Ethernet. J'ai aussi eu un cas amusant où la plupart des paquets étaient bien transmis, sauf ceux de diffusion, ce qui cassait des protocoles comme ARP ou DHCP. Deux conseils : vérifier que le Wi-Fi fonctionne, il peut servir de mécanisme de secours pour se connecter au Turris, si l'Ethernet devient inutilisable. Et bien relire sa configuration avant de la confirmer. Dans le pire des cas, il faudra perdre toute la configuration en remettant le routeur aux réglages d'usine (pensez à garder cette documentation avant de vous couper votre accès Internet !)

Vu du côté Unix, le Turris a plein d'interfaces réseau. eth0 rassemble la plupart des ports physiques du commutateur, eth2 étant le CPU (et le port 4 du commutateur, voir cette discussion sur le forum). Voici d'ailleurs un schéma :

Ensuite, des interfaces virtuelles regroupent plusieurs de ces interfaces (sour l'interface LuCI, vous trouver cette configuration en Network -> Interfaces, https://ROUTER/cgi-bin/luci/admin/network/network). Par exemple, br-lan regroupe typiquement eth0 et eth2. Et c'est ainsi que les deux groupes communiquent (sur LuCI, Network -> Interfaces puis Edit puis Physical settings).

Et les VLAN ? Ils se configurent/s'affichent avec LuCI en Network -> Switch, https://ROUTER/cgi-bin/luci/admin/network/vlan. Par défaut, tous les ports sont non marqués (untagged) ce qui veut dire que le commutateur ne fait pas de VLAN. Si on branche le Freebox Player sur un port où on active le marquage (tagged pour le VLAN 100, celui utilisé par les boitiers Freebox) et le Freebox Server sur un autre port marqué 100, les deux boitiers peuvent communiquer, la télévision marche mais, dans ce cas, le réseau local, toujours non marqué, ne peut plus communiquer avec ces boitiers et on n'a donc pas d'accès Internet. La configuration qui marche est donc celle-ci : Le port marqué CPU dans LuCI est celui qui est marqué WAN sur le boitier (je sais, c'est bizarre).

Vous n'aimez pas les copies d'écran, vous préférez des fichiers de configuration ? Pas de problème, cela se configure dans /etc/config/network (je n'ai montré que les paramètres pertinents) :

config interface 'lan'
	option type 'bridge'
	option ifname 'eth0 eth2'
     
config interface 'Freebox'
	option type 'bridge'
	option proto 'static'
	option ifname 'eth0.100 eth1.100'

config switch_vlan
	option device 'switch0'
	option vlan '1'
	option vid '1'
	option ports '1 2 3 4 5'

config switch_vlan
	option device 'switch0'
	option vlan '2'
	option ports '0t 5t'
	option vid '100'
    

Pour résumer cette configuration : on a deux VLANs, 1 et 100. 100 (deuxième directive config switch_vlan) couvre le port 0 (qui est marqué, et où est connecté le Freebox Player) et le port CPU/WAN/5 - connecté au Freebox Server - qui est le seul à être sur deux VLAN (1 en non marqué et 100 en marqué). Le t dans la liste des ports indique un marquage (tagging). L'autre VLAN, 1 (première directive config switch_vlan), couvre les autres ports. Pour que les interfaces physiques communiquent, on a deux ponts, br-lan (directive config interface 'lan') et br-Freebox, qui fait communiquer les deux ports du VLAN 100 (qui arrivent sur des commutateurs différents, regardez le schéma plus haut). Les ports marqués correspondent aux interfaces comportant le numéro du VLAN (comme eth0.100, les paquets du VLAN 100 arrivant sur eth0)

(Au passage, si vous utilisez LuCI pour configurer, vous devrez cliquer sur Save and apply pour appliquer votre configuration. Rappelez-vous de bien la vérifier avant. Si vous avez au contraire édité le fichier de configuration à la main, ce sera un /etc/init.d/network restart, avec les mêmes précautions.)

Avec tout ça, tout le monde communique, la télé marche (si le Freebox Player affiche au démarrage qu'il ne peut pas communiquer avec le Freebox Server, c'est que vous avez un problème), l'Internet fonctionne, etc. Mais on ne peut toujours pas regarder la télévision avec VLC (vlc http://mafreebox.freebox.fr/freeboxtv/playlist.m3u affiche live555 demux error: no data received in 10s, aborting). La raison en est que RTSP est un protocole un peu spécial (il n'est pas vraiment client/serveur) : certes, le PC se connecte à la Freebox mais le flux vidéo lui-même n'est pas envoyé dans cette connexion, mais séparement sous forme de paquets UDP. Le Turris n'a apparemment pas de mécanisme de suivi des sessions RTSP (conntracker, comme ce module) qui permettrait de transmettre automatiquement ces paquets UDP à la bonne machine. J'ai donc choisi, en suivant cette excellente documentation, de configurer le Turris pour chaque machine. Sur chaque PC du réseau local qui veut regarder des conneries à la télé, il faut fixer le port dans VLC Paramètres -> Préférences -> Input/Codecs->Demuxers -> RTP/RTSP. Là on coche la case Options avancées. On voit s'afficher un champ Client port, avec la valeur -1, ce qui signfie que VLC choisit aléatoirement le port d'entrée. On met la valeur de son choix (attention, elle doit être paire), par exemple 31336. Il faut aussi configurer le Turris pour transmettre ce port à la bonne machine. (Oui, tout serait plus pratique si mafreebox.free.fr avait une adresse IPv6). Dans LuCI, c'est dans Network -> Firewall puis Port forwards ROUTER/cgi-bin/luci/admin/network/firewall/forwards : Et si vous préférez cette configuration en mode texte, c'est dans /etc/config/firewall :

config redirect
	option target 'DNAT'
	option name 'RTSP machine1'
	option proto 'udp'
	option src 'wan'
	option src_dport '31336'
	option dest 'lan'
	option dest_ip '192.168.X.Y'
	option dest_port '31336'
	option src_ip '212.27.38.253'

Une fois qu'on a ses VLAN comme on veut, on peut s'avachir devant la télé qu'on reçoit sur son PC, ou bien on peut passer à une autre tâche. Installer un disque dur supplémentaire dans l'Omnia et créer des machines virtuelles (les deux tâches sont liées, pour des raisons expliquées plus loin).

Pourquoi un disque supplémentaire, pourquoi ne pas se contenter de la Flash présente ? Cet espace de stockage est largement suffisant (8 Go) pour faire tourner les fonctions de base du routeur, mais il ne l'est plus si on veut installer des applications, par exemple de supervision ou de statistiques, qui vont stocker des données sur le long terme, ou bien si on veut mettre son serveur de messagerie sur le Turris. Ou encore si on veut s'en servir comme NAS. Si on veut réaliser la promesse de la page Web officielle, « More than just a router. The open-source [sic] center of your home », il faudra plus de huit gigas.

D'autant plus que la Flash a un autre problème, elle s'use vite quand on écrit souvent. Voilà pourquoi, dans OpenWrt, par défaut, /var est en mémoire, et donc un équivalent de /tmp, qui ne survit pas aux redémarrages. Autrement, des services comme syslog démoliraient la Flash trop vite.

Donc, installons un disque supplémentaire. L'Omnia a un emplacement libre, au dessus de l'emplacement pour carte SIM, où on peut mettre un disque SSD via une interface mSATA. J'ai acheté un Kingston mS200 de 120 Go à 50 € TTC. Mais c'est ensuite que les ennuis commencent. L'emplacement libre dans l'Omnia n'est pas celui qui a le port combiné miniPCIexpress/mSATA, le bon emplacement est occupé par une des deux cartes Wi-Fi, il va donc falloir ouvrir le routeur, et déplacer la carte Wi-Fi. (On pourrait évidemment utiliser un disque externe, connecté en USB mais une de mes motivations pour tout mettre sur le Turris Omnia était de diminuer le nombre de boitiers et de prises de courant.)

La procédure nécessite donc tournevis et une certaine habileté manuelle. Elle est très bien expliquée dans ce film (les commentaires de la vidéo valent également d'être lus). Notez toutefois que dans mon cas, cela n'a pas suffi : les vis du dessus des cartes Wi-Fi ne se défont pas et j'ai donc dû démonter la carte Wi-Fi en l'attaquant de l'autre côté de la carte mère. (Vous trouverez aussi sur le forum Turris des discussions sur cette procédure, comme ici.) Voici le Turris Omnia ouvert avant l'opération : Et le même après, la carte Wi-Fi qui était tout à droite ayant été déplacée tout à gauche : Vous pouvez aussi télécharger une image en haute définition. Attention notamment aux fils qui vont des cartes Wi-Fi aux antennes, ils se défont facilement.

Une fois le disque branché et bien branché, la carte mère replacée et le capot fermé, on redémarre le routeur (en priant, si on est croyant). On doit voir un disque en /dev/sda (tapez dmesg | grep sda après le démarrage). On le formate comme indiqué, par exemple, dans la documentation d'OpenWrt. Chez moi, cela donne :

# fdisk -l /dev/sda

Disk /dev/sda: 111.8 GiB, 120034123776 bytes, 234441648 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0263F4A2-3C22-4043-B2ED-32B962569924

Device         Start       End   Sectors  Size Type
/dev/sda1       2048 121636863 121634816   58G Linux filesystem
/dev/sda2  121636864 234441614 112804751 53.8G Linux filesystem

# blkid 
/dev/mmcblk0p1: UUID="0eec9a72-3c0f-4222-ab9e-2147243a7c1e" UUID_SUB="6b8deab1-dff4-48fc-a522-395f67d59de8" TYPE="btrfs" PARTUUID="2cbb06e2-01"
/dev/sda1: UUID="cb35ae3d-78f8-49f9-bbbb-efbab97b4a81" TYPE="ext4" PARTUUID="ab197dd0-71d2-446c-80e6-bf8810b86ebd"
/dev/sda2: UUID="df1c2ed7-5728-4629-9d72-263bbf2b5939" TYPE="ext4" PARTUUID="3673e386-6636-40e8-bf08-b32899b6e7c3"
/dev/mmcblk0: PTUUID="2cbb06e2" PTTYPE="dos"

On peut ensuite monter le disque de la manière OpenWrt habituelle. Voici mon /etc/config/fstab :

config mount
	option enabled '1'
	option target '/srv'
	option uuid 'cb35ae3d-78f8-49f9-bbbb-efbab97b4a81'

config mount
	option enabled '1'
	option uuid 'df1c2ed7-5728-4629-9d72-263bbf2b5939'
	option target '/var'

Pour compléter, notez que ce déplacement d'une carte Wi-Fi va nécessiter de reconfigurer le service Wi-Fi (dans LuCI, Network -> Wireless), la carte passant de radio1 à radio2.

Une fois qu'on a son disque, on peut installer ses machines virtuelles ou plus exactements ses containers. Pourquoi ces machines supplémentaires alors qu'on a déjà un Unix qui tourne parfaitement sur le matériel ? Mon problème était surtout que le nombre de paquetages est très limité sur l'Omnia (cf. la liste). Il n'y a ainsi pas emacs. Les outils de développement sont absents (on peut éventuellement faire de la compilation croisée) et, de toute façon, il y a deux bonnes raisons pour ne pas installer plein de choses sur l'Unix OpenWrt de l'Omnia :

  • Seuls les paquetages officiels bénéficients d'une fonction essentielle de l'Omnia (notamment pour la sécurité), la mise à jour automatique.
  • Le routeur doit router dans tous les cas, et doit donc avoir un jeu de logiciels minimum. Tout ce qu'on rajoute peut créer des problèmes.

Donc, la méthode propre sur Omnia, si on veut des logiciels comme Icinga (pour la supervision) ou des petits utilitaires sympa comme uptimed ou comme check-soa (indispensable quand on joue souvent avec le DNS), la méthode propre, donc, est d'installer des machines virtuelles sur l'Omnia.

En fait, ce ne sont pas des machines virtuelles complètes, juste des containers, avec la technique LXC. Contrairement à des vraies machines virtuelles, ils ne fournissent pas une étanchéité complète. Tous utilisent le même noyau, qui ne s'exécute qu'une fois. (C'est d'ailleurs pour cela qu'uptimed dans un container marche bien : il enregistre l'uptime du routeur, pas celui du container.) Les containers n'ont pas non plus d'horloge propre et c'est pour cela qu'ils n'ont pas besoin de NTP, celui du routeur suffit.

Autre conséquence du modèle du container, les « machines » doivent tourner avec Linux, pas de FreeBSD sur le Turris Omnia. LXC sur cette machine est bien documenté. Voici le processus de création d'un container, avec le choix des systèmes d'exploitation :

#  lxc-create -t download -n gandalf
Setting up the GPG keyring
Downloading the image index

---
DIST	RELEASE	ARCH	VARIANT	BUILD
---
Turris_OS	stable	armv7l	default	2016-11-27
Turris_OS	stable	ppc	default	2016-11-27
Alpine	3.4	armv7l	default	2016-11-27
Debian	Jessie	armv7l	default	2016-11-27
Gentoo	stable	armv7l	default	2016-11-27
openSUSE	13.2	armv7l	default	2016-11-27
openSUSE	Tumbleweed	armv7l	default	2016-11-27
Ubuntu	Xenial	armv7l	default	2016-11-27
Ubuntu	Yakkety	armv7l	default	2016-11-27
---

Distribution: Debian
Release: Jessie
Architecture: armv7l

Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs

---
Distribution Debian version Jessie was just installed into your container.

Content of the tarballs is provided by third party, thus there is no warranty of any kind.

Pas d'Arch Linux, je le regrette, donc j'ai mis Debian.

Ensuite, on démarre le container :

# lxc-start -n gandalf

On s'y attache :

# lxc-attach -n gandlf

Et on peut configurer le mot de passe, le réseau (je n'ai pas réussi à faire marcher le client DHCP sur les containers, j'ai tout configuré en statique), SSH… (Notez qu'on peut aussi faire tout cela depuis LuCI, Services -> LXC containers.) La configuration du container gandalf se retrouve dans /srv/lxc/gandalf/config. On peut notamment configurer l'adresse MAC du container (attention, si ce n'est pas fait, le container change d'adresse MAC à chaque démarrage, ce qui est excellent pour la vie privée mais moins pour l'administration système, avec arpwatch et NDPMon qui voient une nouvelle machine à chaque fois) :

# cat /srv/lxc/gandalf/config 
...
# Network configuration
lxc.network.type = veth
lxc.network.link = br-lan
lxc.network.flags = up
lxc.network.name = eth0
lxc.network.script.up = /usr/share/lxc/hooks/tx-off
lxc.network.hwaddr = 21:ae:a4:79:73:16

Une fois qu'on a un beau container qui tourne, on peut y installer ses logiciels favoris, comme Icinga (qui, avant, tournait chez moi sur un Raspberry Pi).

Le troisième grand dossier, après les VLAN et l'ajout du disque, c'était la configuration du résolveur DNS. Le Turris utilise par défaut kresd, alias Knot resolver. Intéressant logiciel, quoique ayant encore quelques défauts de jeunesse. Knot marche bien par défaut, et fournit notamment la validation DNSSEC :


% dig A www.afnic.fr
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47317
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
...
;; ANSWER SECTION:
www.afnic.fr.		133 IN CNAME www.nic.fr.
www.nic.fr.		133 IN CNAME lb01-1.nic.fr.
lb01-1.nic.fr.		133 IN A 192.134.5.24

Le AD (Authentic Data dans les flags) indique que le nom est signé et vérifié. Avec un nom pas signé, on n'a pas ce AD :


% dig A www.ssi.gouv.fr       
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16026
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...
;; ANSWER SECTION:
www.ssi.gouv.fr.	14400 IN A 213.56.166.109
...

Et, si le nom est signé mais erroné, on récupère un SERVFAIL (Server Failure) :


% dig A tsc.gov    
...
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 28366
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
...

% dig +cd A tsc.gov 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25881
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
...
;; ANSWER SECTION:
tsc.gov.		60 IN A	153.31.112.95

(Le +cd voulant dire Checking Disabled, pour être sûr que le problème vient de DNSSEC.)

Le premier changement que j'ai fait à sa configuration était de couper la transmission (forwarding) aux résolveurs du FAI (qui sont des résolveurs menteurs) : option forward_upstream '0' dans /etc/config/resolver. (Si, à l'inverse, on veut transmettre à des serveurs aval spécifiques, voir cette discussion sur le forum.)

Mais je voulais surtout une configuration spéciale pour utiliser la racine Yeti. Cela nécessite la configuration suivante. D'abord, /etc/config/resolver :

config resolver 'common'
        ...
        option keyfile '/etc/kresd/yeti-root.keys'

config resolver 'kresd'
        ...
        option include_config '/etc/kresd/custom.conf'

Le fichier des clés de Yeti, indispensable pour la validation DNSSEC, se récupère chez Yeti (et est réécrit ensuite par Knot, qui gère le RFC 5011). Ensuite, le /etc/kresd/custom.conf contient :

hints.root({
        ['bii.dns-lab.net.'] = '240c:f:1:22::6',
        ['yeti-ns.tisf.net .'] = '2001:4f8:3:1006::1:4',
        ['yeti-ns.wide.ad.jp.'] = '2001:200:1d9::35',
        ['dahu1.yeti.eu.org.'] = '2001:4b98:dc2:45:216:3eff:fe4b:8c5b',
        ['dahu2.yeti.eu.org.'] = '2001:67c:217c:6::2',
	...
})

(Pas grave s'il manque un ou deux serveurs, le primingRFC 8109 - s'en occupe.)

Voilà, le résolveur utilise désormais la racine Yeti, comme on peut le vérifier facilement :


% dig NS .
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46120
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 26, AUTHORITY: 0, ADDITIONAL: 1
...
;; ANSWER SECTION:
.			86400 IN NS bii.dns-lab.net.
.			86400 IN NS dahu1.yeti.eu.org.
.			86400 IN NS dahu2.yeti.eu.org.
.			86400 IN NS yeti-ns.tisf.net.
.			86400 IN NS yeti-ns.wide.ad.jp.
...

Notez que kresd peut être interrogé via une console CLI :

# socat - UNIX-CONNECT:/tmp/kresd/tty/$(pidof kresd)
>

Et on a droit alors à plein d'informations amusantes (tapez help() pour la liste ou bien regardez la documentation) :

> cache.count()
61495

> cache.stats()
[hit] => 12259583
[delete] => 1
[miss] => 24413638
[insert] => 1542550

> stats.list()     
[answer.nxdomain] => 775648
[answer.100ms] => 102752
[answer.1500ms] => 27366
[answer.slow] => 72019
[answer.servfail] => 354445
[answer.250ms] => 125256
[answer.cached] => 3062179
[answer.nodata] => 206878
[query.dnssec] => 80582
[answer.1ms] => 3054309
[predict.epoch] => 27
[query.edns] => 84111
[predict.queue] => 5946
[answer.total] => 4112245
[answer.10ms] => 77419
[answer.noerror] => 2775274
[answer.50ms] => 393935
[answer.500ms] => 205149
[answer.1000ms] => 47949
[predict.learned] => 447

> cache.get("google.com")
[clients2.google.com] => {
    [CNAME] => true
}
[ghs.google.com] => {
    [CNAME] => true
}
[clients6.google.com] => {
    [CNAME] => true
}
[get.google.com] => {
    [A] => true
}
[accounts-cctld.l.google.com] => {
    [A] => true
    [AAAA] => true
}
[gmail-imap.l.google.com] => {
    [A] => true
}
[inputtools.google.com] => {
    [CNAME] => true
}
[kh.google.com] => {
    [CNAME] => true
}
...

Après ces trois « grands dossiers », voici plein de petits détails et de petits projets plus ou moins amusants.

Un des avantages d'un routeur qu'on contrôle complètement, où on est root, c'est qu'on peut tout configurer, y compris les diodes luminescentes, si indispensables à l'informatique. On peut par exemple changer la couleur des diodes selon le débit. La technique en Lua expliquée sur le forum marche très bien.

Par défaut, le Turris Omnia se gère en HTTPS avec un certificat auto-signé. Même si ce n'est que sur le réseau local, ce n'est pas satisfaisant (et ça empêche les navigateurs de mémoriser les mots de passe, le site n'étant pas considéré comme sûr). Comme je suis utilisateur de CAcert, je voulais utiliser HTTPS avec un certificat CAcert. On le crée (openssl req -new -nodes -newkey rsa:2048 -keyout server.key -out server.csr -days 1000), on le fait signer via l'interface Web du CAcert (tout est gratuit et automatique dans CAcert) et on concatène clé privée et certificat (c'est le format qu'attend le serveur HTTPS du Turris, lighthttpd, cf. cet article du forum) :

# cat server.key  server.pem  > /etc/lighttpd/tls/server.pem

Et on change la configuration HTTPS (/etc/lighttpd/conf.d/ssl-enable.conf) :

$SERVER["socket"] == ":443" {
	ssl.engine = "enable"
        ssl.pemfile = "/etc/lighttpd/tls/server.pem"
	ssl.use-sslv2 = "disable"
	ssl.use-sslv3 = "disable"
}

(Et idem avec $SERVER["socket"] == "[::]:443" pour IPv6.) En prime, j'active HSTS (RFC 6797) :

$HTTP["scheme"] == "https" {
	# Add  'HTTP Strict Transport Security' header (HSTS) to sites
	setenv.add-response-header  += ( "Strict-Transport-Security" => "max-age=31536000; includeSubDomains" )
}

Et je mets une redirection en place depuis HTTP vers HTTPS, dans /etc/lighttpd/conf.d/https-redirect.conf :

$HTTP["scheme"] == "http" {
    # capture vhost name with regex conditiona -> %0 in redirect pattern
        # must be the most inner block to the redirect rule
	    $HTTP["host"] =~ ".*" {
	            url.redirect = (".*" => "https://%0$0")
		   }
}

Tout marche bien, désormais.

Un problème fréquent des tunnels (comme celui qu'utilise Free pour faire passer l'IPv6 vers les clients ADSL) est que, la MTU ayant été diminuée, les paquets d'une taille proche de la MTU traditionnelle de 1 500 octets ne passent plus. Cela se voit lorsque ping (avec la taille par défaut) ou openssl s_client passent mais que HTTP n'arrive pas à faire passer des données. a MTU configurée sur l'Omnia est de 1 480 octets :

config interface 'wan'
	option ifname 'eth1'
	option proto 'dhcp'
	option mtu '1480'

Désormais, tout passe, mais des machines du réseau local envoient toujours des paquets trop gros (je devrais peut-être diffuser la MTU réduite sur le réseau local). Le routeur note :

2016-11-02T07:47:14+00:00 err kernel[]: [  437.388025] mvneta f1034000.ethernet eth1: bad rx status 8fa50000 (max frame length error), size=1504

Il y a aussi des problèmes que je n'ai pas réussi à résoudre comme celui d'un accès anonyme aux graphes de trafic. Notez que je n'ai guère utilisé les forums génériques OpenWrt : les problèmes discutés sont souvent très spécifiques à un modèle de routeur. Par contre, la documentation d'OpenWrt est très utile si le Turris Omnia est le premier routeur OpenWrt que vous configurez sérieusement. Vous y trouverez notamment des explications sur le système de configuration /etc/config, qui peut être déroutant, si vous venez d'un Unix classique.

Et il y a des problèmes qui sont résolus (le Turris Omnia est en plein développement, et, avec les mises à jour automatiques, on voit des solutions aux problèmes arriver seules). C'est ainsi que le « socat fou » qui avait fait perdre tant de temps et d'électricité au début de l'Omnia a été réparé sans que j'ai rien eu à faire.

Le routeur Turris permet d'afficher de jolis graphes de trafic (dans LuCI, Statistics -> Graphs). La configuration n'est pas évidente (Statistics -> Setup) : j'ai dû créer à la main les répertoites indiqués dans la configuration, puis faire :

/etc/init.d/luci_statistics enable
/etc/init.d/collectd enable

Par défaut, toutes les données sont perdues à chaque démarrage (voir plus haut la discussion sur la mémoire Flash). On peut changer les répertoires de données pour le disque stable, mais cette modification est perdue à chaque mise à jour du logiciel, hélas. Bref, ce n'est pas encore satisfaisant.


L'article seul

RFC 8106: IPv6 Router Advertisement Options for DNS Configuration

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : J. Jeong (Sungkyunkwan University), S. Park (Samsung Electronics), L. Beloeil (France Telecom R&D), S. Madanapalli (iRam Technologies)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 18 mars 2017


Il existe deux méthodes pour configurer une machine IPv6 automatiquement, DHCP (RFC 3315) et RA (Router Advertisement, RFC 4862). Toutes les deux peuvent indiquer d'autres informations que l'adresse IP, comme par exemple les adresses des résolveurs DNS. Notre RFC normalise cette possibilité pour les RA. Il remplace le RFC 6106, avec peu de changements.

Si on gère un gros réseau, avec de nombreuses machines dont certaines, portables, vont et viennent, s'assurer que toutes ces machines ont les adresses IP des serveurs de noms à utiliser n'est pas trivial (section 1 du RFC). On ne peut évidemment pas utiliser le DNS, cela serait tenter de voler en tirant sur les lacets de ses chaussures. Et configurer à la main les adresses sur chaque machine (par exemple, sur Unix, en les écrivant dans le fichier /etc/resolv.conf) est bien trop difficile à maintenir. Se passer du DNS est hors de question. Pour les machines bi-protocoles (IPv4 et IPv6), une solution possible était d'utiliser un serveur de noms en v4. Mais pour une solution purement v6 ?

La solution la plus populaire était DHCP (RFC 3315 et RFC 3646). Son principal inconvénient est qu'elle est à état : le serveur DHCP doit se souvenir des baux qu'il a attribué. Sur un gros réseau local, le nombre de requêtes à traiter, chacune nécessitant une écriture dans une base de données, peut devenir très lourd.

Une autre solution est sans état et repose sur une nouveauté d'IPv6, les RA (Router Advertisements, cette méthode est aussi appelée ND, pour Neighbor Discovery, les RA en étant un cas particulier), décrits dans le RFC 4862. Ce sont des messages envoyés à intervalles réguliers par les routeurs et qui informent les machines non-routeuses des caractéristiques essentielles du réseau, comme le préfixe utilisé (par exemple 2001:db8:beef:42::/64). Le routeur diffuse ses messages et n'a pas besoin d'écrire quoi que ce soit sur son disque, ni de faire des traitements compliqués lors d'une sollicitation, il répond toujours par le même message RA.

Ces RA peuvent diffuser diverses informations, par le biais d'un système d'options. Le principe de notre RFC est donc d'utiliser ces RA pour transporter l'information sur les serveurs de noms récursifs utilisables sur le réseau local, via des options notamment celle nommée RDNSS (le numéro 25 lui a été affecté par l'IANA).

La section 1.1 du RFC rappelle qu'il existe plusieurs choix, notre RFC 8106 n'étant qu'une possibilité parmi d'autres. Le RFC 4339 contient une discussion plus détaillée de ce problème du choix d'une méthode de configuration des serveurs de noms (notons qu'il existe d'autres méthodes comme l'anycast avec une adresse « bien connue »). La section 1.2 décrit ce qui se passe lorsque plusieurs méthodes (par exemple DHCP et RA) sont utilisées en même temps.

La méthode RA décrite dans notre RFC repose sur deux options, RDNSS, déjà citée, et DNSSL (section 4). La première permet de publier les adresses des serveurs de noms, la seconde une liste de domaine à utiliser pour compléter les noms courts (formés d'un seul composant). Les valeurs pour ces deux options doivent être configurées dans le routeur qui va lancer les RA. (Le routeur Turris Omnia le fait automatiquement. Si on veut changer les paramètres, voici comment faire. En général, pour OpenWrt, il faut lire cette documentation, l'ancien logiciel radvd n'étant plus utilisé.)

La première option, RDNSS, de numéro 25, est décrite en section 5.1. Elle indique une liste d'adresse IPv6 que le client RA mettra dans sa liste locale de serveurs de noms interrogeables.

La seconde option, DNSSL, de numéro 31, est en section 5.2 (les deux options sont enregistrées dans le registre IANA, cf. section 8). Elle publie une liste de domaines, typiquement ceux qui, sur une machine Unix, se retrouveront dans l'option search de /etc/resolv.conf.

Sur Linux, le démon rdnssd permet de recevoir ces RA et de modifier la configuration DNS. Pour FreeBSD, on peut consulter une discussion sur leur liste. Les CPE de Free, les Freebox, émettent de telles options dans leurs RA (apparemment, la dernière fois que j'ai regardé, uniquement des RDNSS). Voici ce qu'affiche Wireshark :

...
Ethernet II, Src: FreeboxS_c3:83:23 (00:07:cb:c3:83:23), 
             Dst: IPv6mcast_00:00:00:01 (33:33:00:00:00:01)
...
Internet Control Message Protocol v6
    Type: 134 (Router advertisement)
...
    ICMPv6 Option (Recursive DNS Server)
        Type: Recursive DNS Server (25)
        Length: 40
        Reserved
        Lifetime: 600
        Recursive DNS Servers: 2a01:e00::2 (2a01:e00::2)
        Recursive DNS Servers: 2a01:e00::1 (2a01:e00::1)

et les serveurs DNS annoncés répondent correctement. (Vous pouvez récupérer le paquet entier sur pcapr.net.)

Autre mise en œuvre de ces options, dans radvd (ainsi que pour les logiciels auxiliaires). Wireshark, on l'a vu, sait décoder ces options.

La section 6 de notre RFC donne des conseils aux programmeurs qui voudraient mettre en œuvre ce document. Par exemple, sur un système d'exploitation où le client RA tourne dans le noyau (pour configurer les adresses IP) et où la configuration DNS est dans l'espace utilisateur, il faut prévoir un mécanisme de communication, par exemple un démon qui interroge le noyau régulièrement pour savoir s'il doit mettre à jour la configuration DNS.

RA pose divers problèmes de sécurité, tout comme DHCP, d'ailleurs. Le problème de ces techniques est qu'elles sont conçues pour faciliter la vue de l'utilisateur et de l'administrateur réseau et que « faciliter la vie » implique en général de ne pas avoir de fonctions de sécurité difficiles à configurer. La section 7 traite de ce problème, par exemple du risque de se retrouver avec l'adresse d'un serveur DNS méchant qui vous redirigerait Dieu sait où (les RA ne sont pas authentifiés). Ce risque n'a rien de spécifique aux options DNS, toute la technique RA est vulnérable (par exemple, avec un faux Neighbor Advertisement). Donc, notre RFC n'apporte pas de risque nouveau (cf. RFC 6104). Si on considère cette faiblesse de sécurité comme insupportable, la section 7.2 recommande d'utiliser le RA guard du RFC 6105, ou bien SEND (RFC 3971, mais il est nettement moins mis en avant que dans le précédent RFC).

Ce problème d'une auto-configuration simple des machines connectées à IPv6 est évidemment particulièrement important pour les objets connectés et c'est sans doute pour cela que le RFC contient la mention « This document was supported by Institute for Information & communications Technology Promotion (IITP) grant funded by the Korea government (MSIP) [10041244, Smart TV 2.0 Software Platform] ».

Les changements faits depuis le précédent RFC, le RFC 6106, figurent dans l'annexe A. On y trouve notamment :

  • Une valeur par défaut plus élevée pour la durée de vie des informations envoyées (qui passe de deux fois MaxRtrAdvInterval à trois fois sa valeur, soit 1 800 secondes avec la valeur par défaut de cette variable), pour diminuer le nombre de cas où l'information expire parce que le réseau perdait trop de paquets,
  • L'autorisation explicite des adresses locales au lien (celles en fe80::/10), comme adresses de résolveurs DNS,
  • Suppression de la limite de trois résolveurs DNS, qui était dans l'ancien RFC.

À noter que ce RFC n'intègre pas encore les résolveurs sécurisés du RFC 7858, car il se contente de réviser un RFC existant. Il n'y a donc pas de moyen de spécifier un résolveur sécurisé, pas de port 853.

Et pour finir, voici le RA émis par défaut par le routeur Turris, décodé par Wireshark :

Internet Protocol Version 6, Src: fe80::da58:d7ff:fe00:4c9e, Dst: ff02::1
    0110 .... = Version: 6
    .... 0000 0000 .... .... .... .... .... = Traffic class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
    .... .... .... 0101 1110 1011 0100 0001 = Flow label: 0x5eb41
    Payload length: 152
    Next header: ICMPv6 (58)
    Hop limit: 255
    Source: fe80::da58:d7ff:fe00:4c9e
    [Source SA MAC: CzNicZSP_00:4c:9e (d8:58:d7:00:4c:9e)]
    Destination: ff02::1
    [Source GeoIP: Unknown]
    [Destination GeoIP: Unknown]
Internet Control Message Protocol v6
    Type: Router Advertisement (134)
    Code: 0
    Checksum: 0x35ed [correct]
    [Checksum Status: Good]
    Cur hop limit: 64
    Flags: 0x80
        1... .... = Managed address configuration: Set
        .0.. .... = Other configuration: Not set
        ..0. .... = Home Agent: Not set
        ...0 0... = Prf (Default Router Preference): Medium (0)
        .... .0.. = Proxy: Not set
        .... ..0. = Reserved: 0
    Router lifetime (s): 1800
    Reachable time (ms): 0
    Retrans timer (ms): 0
    ICMPv6 Option (Source link-layer address : d8:58:d7:00:4c:9e)
        Type: Source link-layer address (1)
        Length: 1 (8 bytes)
        Link-layer address: CzNicZSP_00:4c:9e (d8:58:d7:00:4c:9e)
    ICMPv6 Option (MTU : 1480)
        Type: MTU (5)
        Length: 1 (8 bytes)
        Reserved
        MTU: 1480
    ICMPv6 Option (Prefix information : fde8:9fa9:1aba::/64)
        Type: Prefix information (3)
        Length: 4 (32 bytes)
        Prefix Length: 64
        Flag: 0xc0
            1... .... = On-link flag(L): Set
            .1.. .... = Autonomous address-configuration flag(A): Set
            ..0. .... = Router address flag(R): Not set
            ...0 0000 = Reserved: 0
        Valid Lifetime: 7200
        Preferred Lifetime: 1800
        Reserved
        Prefix: fde8:9fa9:1aba::
    ICMPv6 Option (Prefix information : 2a01:e35:8bd9:8bb0::/64)
        Type: Prefix information (3)
        Length: 4 (32 bytes)
        Prefix Length: 64
        Flag: 0xc0
            1... .... = On-link flag(L): Set
            .1.. .... = Autonomous address-configuration flag(A): Set
            ..0. .... = Router address flag(R): Not set
            ...0 0000 = Reserved: 0
        Valid Lifetime: 7200
        Preferred Lifetime: 1800
        Reserved
        Prefix: 2a01:e35:8bd9:8bb0::
    ICMPv6 Option (Route Information : Medium fde8:9fa9:1aba::/48)
        Type: Route Information (24)
        Length: 3 (24 bytes)
        Prefix Length: 48
        Flag: 0x00
            ...0 0... = Route Preference: Medium (0)
            000. .000 = Reserved: 0
        Route Lifetime: 7200
        Prefix: fde8:9fa9:1aba::
    ICMPv6 Option (Recursive DNS Server fde8:9fa9:1aba::1)
        Type: Recursive DNS Server (25)
        Length: 3 (24 bytes)
        Reserved
        Lifetime: 1800
        Recursive DNS Servers: fde8:9fa9:1aba::1
    ICMPv6 Option (Advertisement Interval : 600000)
        Type: Advertisement Interval (7)
        Length: 1 (8 bytes)
        Reserved
        Advertisement Interval: 600000

On y voit l'option RDNSS (l'avant-dernière) mais pas de DNSSL.

Merci à Alexis La Goutte pour ses informations.


Téléchargez le RFC 8106


L'article seul

RFC 8118: The application/pdf Media Type

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : M. Hardy, L. Masinter, D. Markovic (Adobe Systems), D. Johnson (PDF Association), M. Bailey (Global Graphics)
Pour information
Première rédaction de cet article le 18 mars 2017


Le format PDF, largement utilisé sur l'Internet, n'a sans doute pas besoin d'être présenté ici. De toute façon, ce nouveau RFC ne prétend pas décrire PDF, juste le type de contenu application/pdf. Ce RFC remplace l'ancien RFC 3778, notamment pour tenir compte du fait qu'officiellement, PDF n'est plus une spécification Adobe mais une norme ISO, 32000-1:2008.

Donc, si vous envoyez des documents PDF via l'Internet, que ce soit par courrier ou par le Web, vous êtes censé les étiqueter avec le type MIME application/pdf (le type de premier niveau applicaton/ indiquant que c'est un format binaire, non utilisable en dehors des applications spécialisées). Ce type a été enregistré à l'IANA (section 8 du RFC).

PDF avait été conçu pour le monde du papier (les commerciaux d'Adobe répétaient dans les années 90 que PDF permettait d'avoir « le même rendu partout » ce qui n'a pas de sens sur écran, où tous les écrans sont différents), ce qui se retrouve dans de nombreux concepts archaïques de PDF comme le découpage en pages. Un document PDF est un « rendu final », typiquement non modifiable, avec du texte utilisant différentes polices, des images… PDF permet également de représenter des liens hypertexte, une table des matières… On peut même inclure du JavaScript pour avoir des documents interactifs. PDF permet également le chiffrement et la signature, et a un mécanisme (en fait, plusieurs) pour placer des métadonnées, XMP. Bref, PDF est un format très complexe, ce qui explique les nombreuses failles de sécurité rencontrées par les programmes qui lisent du PDF.

La norme PDF est désormais déposée à l'ISO (ISO 32000-1) mais l'archaïque ISO ne distribue toujours pas librement ces documents. Si on veut apprendre PDF, il faut donc le télécharger sur le site d'Adobe.

Pour les protocoles où il y a une notion d'identificateur de fragment (comme les URI, où cet identificateur figure après le croisillon), PDF permet d'indiquer une partie d'un document. Cela fera partie de la future norme ISO, mais c'était déjà dans l'ancien RFC 3778. Cet identificateur prend la forme d'un ou plusieurs couples clé=valeur, où la clé est, par exemple, page=N (pour aller à la page n° N), comment=ID (aller à l'endroit marqué par l'annotation ID), zoom=S (agrandir d'un facteur S), search=MOT (aller à la première occurrence de MOT)… (Je n'ai pas réussi à faire fonctionner ces identificateurs de fragments avec le lecteur PDF inclus dans Chrome. Quelqu'un connait un logiciel où ça marche ?)

PDF a également des sous-ensembles. La norme est riche, bien trop riche, et il est donc utile de la restreindre. Il y a eu plusieurs de ces sous-ensembles de PDF normalisés (voir sections 2 et 4 du RFC). Ainsi, PDF/A, sous-ensemble de PDF pour l'archivage à long terme (ISO 19005-3:2012), limite les possibilités de PDF, pour augmenter la probabilité que le document soit toujours lisible dans 50 ou 100 ans. Par exemple, JavaScript y est interdit. PDF/X (ISO 15930-8:2008), lui, vise le cas où on envoie un fichier à un imprimeur. Il restreint également les possibilités de PDF, pour accroitre les chances que l'impression donne exactement le résultat attendu. Enfin, PDF/UA (ISO 14289-1:2014) vise l'accessibilité, en insistant sur une structuration sémantique (et non pas fondée sur l'apparence visuelle) du document. Tous ces sous-ensembles s'étiquettent avec le même type application/pdf. Ils ne sont pas mutuellement exclusifs : un document PDF peut être à la fois PDF/A et PDF/UA, par exemple.

Il existe d'innombrables mises en œuvre de PDF, sur toutes les plate-formes possible. Celle que j'utilise le plus sur Unix est Evince.

Un mot sur la sécurité (section 7 du RFC). On l'a dit, PDF est un format (trop) complexe, ce qui a des conséquences pour la sécurité. Comme l'impose la section 4.6 du RFC 6838, notre RFC inclut donc une analyse des risques. (Celle du RFC 3778 était trop limitée.) Notamment, PDF présente les risques suivants :

  • Les scripts inclus, écrits en JavaScript,
  • Le chargement de fichiers extérieurs, et les liens hypertexte vers l'extérieur,
  • Les fichiers inclus, qui peuvent être absolument n'importe quoi, et qui viennent avec leurs propres dangers (sans compter le risque de leur exportation vers le système de fichiers local).

Et c'est sans compter sur les risques plus génériques, comme la complexité de l'analyseur. Il y a eu de nombreuses failles de sécurité dans les lecteurs PDF (au hasard, par exemple CVE-2011-3332 ou bien CVE-2013-3553). La revue de sécurité à l'IETF avait d'ailleurs indiqué que les premières versions du futur RFC étaient encore trop légères sur ce point, et demandait un mécanisme pour mieux étiqueter les contenus « dangereux ».

Vous avez peut-être noté (lien « Version PDF de cette page » en bas) que tous les articles de ce blog ont une version PDF, produite via LaTeX (mais elle n'est pas toujours complète, notamment pour les caractères Unicode). Une autre solution pour obtenir des PDF de mes articles est d'imprimer dans un fichier, depuis le navigateur.

La section 2 du RFC rappelle l'histoire de PDF. La première version date de 1993. PDF a été un très grand succès et est largement utilisé aujourd'hui. Si on google filetype:pdf, on trouve « Environ 2 500 000 000 résultats » (valeur évidemment très approximative, le chiffre rond indiquant que Google n'a peut-être pas tout compté) . Si PDF a été créé et reste largement contrôlé par Adobe, il en existe une version ISO, la norme 32000-1, qui date de 2008 (pas de mise à jour depuis, bien qu'une révision soit attendue en 2017). ISO 32000-1:2008 est identique à la version PDF 1.7 d'Adobe.

Normalement, les anciens lecteurs PDF doivent pouvoir lire les versions plus récentes, évidemment sans tenir compte des nouveautés (section 5 du RFC).

Quels sont les changements depuis l'ancienne version, celle du RFC 3778 ? La principale est que le change controller, l'organisation qui gère la norme et peut donc demander des modifications au registre IANA est désormais l'ISO et non plus Adobe. Les autres changements sont :

  • Une mise à jour de la partie historique,
  • Une mise à jour de la partie sur les sous-ensembles de PDF, qui étaient moins nombreux autrefois,
  • Une section sécurité bien plus détaillée.

Téléchargez le RFC 8118


L'article seul

RFC 8109: Initializing a DNS Resolver with Priming Queries

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : P. Koch (DENIC), M. Larson, P. Hoffman (ICANN)
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 16 mars 2017


Un résolveur DNS ne connait au début, rien du contenu du DNS. Rien ? Pas tout à fait, il connait une liste des serveurs de noms faisant autorité pour la racine, car c'est par eux qu'il va commencer le processus de résolution de noms. Cette liste est typiquement en dur dans le code du serveur, ou bien dans un de ses fichiers de configuration. Mais peu d'administrateurs système la maintiennent à jour. Il est donc prudent, au démarrage du résolveur, de chercher une liste vraiment à jour, et c'est le priming (initialisation ?), opération que décrit ce RFC.

Le problème de départ d'un résolveur est un problème d'œuf et de poule. Le résolveur doit interroger le DNS pour avoir des informations mais comment trouve-t-il les serveurs DNS à interroger ? La solution est de traiter la racine du DNS de manière spéciale : la liste de ses serveurs est connue du résolveur au démarrage. Elle peut être dans le code du serveur lui-même, ici un Unbound qui contient les adresses IP des serveurs de la racine (je ne montre que les trois premiers, A.root-servers.net, B.root-servers.net et C.root-servers.net) :

% strings /usr/sbin/unbound | grep -i 2001:       
2001:503:ba3e::2:30
2001:500:84::b
2001:500:2::c
...
   

Ou bien elle est dans un fichier de configuration (ici, sur un Unbound) :

server:     
  directory: "/etc/unbound"
  root-hints: "root-hints"

Ce fichier peut être téléchargé via l'IANA, il peut être spécifique au logiciel résolveur, ou bien fourni par le système d'exploitation (cas du paquetage dns-root-data chez Debian). Il contient la liste des serveurs de la racine et leurs adresses :

.                        3600000      NS    A.ROOT-SERVERS.NET.
.                        3600000      NS    B.ROOT-SERVERS.NET.
...
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
B.ROOT-SERVERS.NET.      3600000      A     192.228.79.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:84::b
...
   

Cette configuration initiale du résolveur est décrite dans la section 2.3 du RFC 1034, mais ce dernier ne décrit pas réellement le priming (quoi que dise notre nouveau RFC), priming que tous les résolveurs actuels mettent en œuvre. En effet, les configurations locales tendent à ne plus être à jour au bout d'un moment. (Sauf dans le cas où elles sont dans un paquetage du système d'exploitation, mis à jour avec ce dernier, comme dans le bon exemple Debian ci-dessus.)

Les changements des serveurs racines sont rares. Si on regarde sur le site des opérateurs des serveurs racine, on voit :

  • 2016-12-02 Announcement of IPv6 addresses
  • 2015-11-05 L-Root IPv6 Renumbering
  • 2015-08-31 H-Root to be renumbered
  • 2014-03-26 IPv6 service address for c.root-servers.net (2001:500:2::C)
  • 2012-12-14 D-Root IPv4 Address to be Renumbered
  • 2011-06-10 IPv6 service address for d.root-servers.net (2001:500:2D::D)

Bref, peu de changements. Ils sont en général annoncés sur les listes de diffusion opérationnelles (comme ici, ou encore ici). Mais les fichiers de configuration ayant une fâcheuse tendance à ne pas être mis à jour et à prendre de l'âge, les anciennes adresses des serveurs racine continuent à recevoir du trafic des années après (comme le montre cette étude de J-root). Notez que la stabilité de la liste des serveurs racine n'est pas due qu'au désir de ne pas perturber les administrateurs système : il y a aussi des raisons politiques (aucun mécanisme en place pour choisir de nouveaux serveurs, ou pour retirer les « maillons faibles »). C'est pour cela que la liste des serveurs (mais pas leurs adresses) n'a pas changé depuis 1997 !

Notons aussi que l'administrateur système d'un résolveur peut changer la liste des serveurs de noms de la racine pour une autre liste. C'est ainsi que fonctionnent les racines alternatives comme Yeti. Si on veut utiliser cette racine expérimentale et pas la racine « officielle », on édite la configuration de son résolveur :

server:
    root-hints: "yeti-hints"
   

Et le fichier, téléchargé chez Yeti, contient :

.                              3600000    IN   NS       bii.dns-lab.net                         
bii.dns-lab.net                3600000    IN   AAAA     240c:f:1:22::6                          
.                              3600000    IN   NS       yeti-ns.tisf.net                        
yeti-ns.tisf.net               3600000    IN   AAAA     2001:559:8000::6                        
.                              3600000    IN   NS       yeti-ns.wide.ad.jp                      
yeti-ns.wide.ad.jp             3600000    IN   AAAA     2001:200:1d9::35                        
.                              3600000    IN   NS       yeti-ns.as59715.net                     
...
   

Le priming, maintenant. Le principe du priming est, au démarrage, de faire une requête à un des serveurs listés dans la configuration et de garder sa réponse (certainement plus à jour que la configuration) :


% dig +bufsize=4096 +norecurse +nodnssec @k.root-servers.net NS .

; <<>> DiG 9.10.3-P4-Debian <<>> +norecurse +nodnssec @k.root-servers.net NS .
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42123
;; flags: qr aa; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27

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

;; ANSWER SECTION:
.			518400 IN NS a.root-servers.net.
.			518400 IN NS b.root-servers.net.
.			518400 IN NS c.root-servers.net.
.			518400 IN NS d.root-servers.net.
.			518400 IN NS e.root-servers.net.
.			518400 IN NS f.root-servers.net.
.			518400 IN NS g.root-servers.net.
.			518400 IN NS h.root-servers.net.
.			518400 IN NS i.root-servers.net.
.			518400 IN NS j.root-servers.net.
.			518400 IN NS k.root-servers.net.
.			518400 IN NS l.root-servers.net.
.			518400 IN NS m.root-servers.net.

;; ADDITIONAL SECTION:
a.root-servers.net.	518400 IN A 198.41.0.4
a.root-servers.net.	518400 IN AAAA 2001:503:ba3e::2:30
b.root-servers.net.	518400 IN A 192.228.79.201
b.root-servers.net.	518400 IN AAAA 2001:500:84::b
c.root-servers.net.	518400 IN A 192.33.4.12
c.root-servers.net.	518400 IN AAAA 2001:500:2::c
d.root-servers.net.	518400 IN A 199.7.91.13
d.root-servers.net.	518400 IN AAAA 2001:500:2d::d
e.root-servers.net.	518400 IN A 192.203.230.10
e.root-servers.net.	518400 IN AAAA 2001:500:a8::e
f.root-servers.net.	518400 IN A 192.5.5.241
f.root-servers.net.	518400 IN AAAA 2001:500:2f::f
g.root-servers.net.	518400 IN A 192.112.36.4
g.root-servers.net.	518400 IN AAAA 2001:500:12::d0d
h.root-servers.net.	518400 IN A 198.97.190.53
h.root-servers.net.	518400 IN AAAA 2001:500:1::53
i.root-servers.net.	518400 IN A 192.36.148.17
i.root-servers.net.	518400 IN AAAA 2001:7fe::53
j.root-servers.net.	518400 IN A 192.58.128.30
j.root-servers.net.	518400 IN AAAA 2001:503:c27::2:30
k.root-servers.net.	518400 IN A 193.0.14.129
k.root-servers.net.	518400 IN AAAA 2001:7fd::1
l.root-servers.net.	518400 IN A 199.7.83.42
l.root-servers.net.	518400 IN AAAA 2001:500:9f::42
m.root-servers.net.	518400 IN A 202.12.27.33
m.root-servers.net.	518400 IN AAAA 2001:dc3::35

;; Query time: 3 msec
;; SERVER: 2001:7fd::1#53(2001:7fd::1)
;; WHEN: Fri Mar 03 17:29:05 CET 2017
;; MSG SIZE  rcvd: 811

(Les raisons du choix des trois options données à dig sont indiquées plus loin.)

La section 3 de notre RFC décrit en détail à quoi ressemblent les requêtes de priming. Le type de données demandé (QTYPE) est NS (Name Servers, type 2) et le nom demandé (QNAME) est « . » (oui, juste la racine). D'où le dig NS . ci-dessus. Le bit RD (Recursion Desired) est typiquement mis à zéro (d'où le +norecurse dans l'exemple avec dig). La taille de la réponse dépassant les 512 octets (limite très ancienne du DNS), il faut utiliser EDNS (cause du +bufsize=4096 dans l'exemple). On peut utiliser le bit DO (DNSSEC OK) qui indique qu'on demande les signatures DNSSEC mais ce n'est pas habituel (d'où le +nodnssec dans l'exemple). En effet, si la racine est signée, permettant d'authentifier l'ensemble d'enregistrements NS, la zone root-servers.net, où se trouvent actuellement tous les serveurs de la racine, ne l'est pas, et les enregistrements A et AAAA ne peuvent donc pas être validés avec DNSSEC.

Cette requête de priming est envoyée lorsque le résolveur démarre, et aussi lorsque la réponse précédente a expiré (regardez le TTL dans l'exemple : six jours). Si le premier serveur testé ne répond pas, on essaie avec un autre. Ainsi, même si le fichier de configuration n'est pas parfaitement à jour (des vieilles adresses y trainent), le résolveur finira par avoir la liste correcte.

Et comment choisit-on le premier serveur qu'on interroge ? Notre RFC recommande un tirage au sort, pour éviter que toutes les requêtes de priming ne se concentrent sur un seul serveur (par exemple le premier de la liste). Une fois que le résolveur a démarré, il peut aussi se souvenir du serveur le plus rapide, et n'interroger que celui-ci, ce qui est fait par la plupart des résolveurs, pour les requêtes ordinaires (mais n'est pas conseillé pour le priming).

Et les réponses au priming ? Il faut bien noter que, pour le serveur racine, les requêtes priming sont des requêtes comme les autres, et ne font pas l'objet d'un traitement particulier. Normalement, la réponse doit avoir le code de retour NOERROR (c'est bien le cas dans mon exemple). Parmi les flags, il doit y avoir AA (Authoritative Answer). La section de réponse doit évidemment contenir les NS de la racine, et la section additionnelle les adresses IP. Le résolveur garde alors cette réponse dans son cache, comme il le ferait pour n'importe quelle autre réponse. Notez que là aussi, il ne faut pas de traitement particulier. Par exemple, le résolveur ne doit pas compter qu'il y aura exactement 13 serveurs, même si c'est le cas depuis longtemps (ça peut changer).

Normalement, le serveur racine envoie la totalité des adresses IP (deux par serveur, une en IPv4 et une en IPv6). S'il ne le fait pas (par exemple par manque de place parce qu'on a bêtement oublié EDNS), le résolveur va devoir envoyer des requêtes A et AAAA explicites pour obtenir les adresses IP :

     
% dig @k.root-servers.net A g.root-servers.net 

; <<>> DiG 9.10.3-P4-Debian <<>> @k.root-servers.net A g.root-servers.net
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49091
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 26
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;g.root-servers.net.	IN A

;; ANSWER SECTION:
g.root-servers.net.	3600000	IN A 192.112.36.4
...

   

Vous pouvez voir ici les requêtes et réponses de priming d'un Unbound utilisant Yeti. D'abord, décodées par tcpdump :

20:31:36.226325 IP6 2001:4b98:dc2:43:216:3eff:fea9:41a.7300 > 2a02:cdc5:9715:0:185:5:203:53.53: 50959% [1au] NS? . (28)
20:31:36.264584 IP6 2a02:cdc5:9715:0:185:5:203:53.53 > 2001:4b98:dc2:43:216:3eff:fea9:41a.7300: 50959*- 26/0/7 NS bii.dns-lab.net., NS yeti.bofh.priv.at., NS yeti.ipv6.ernet.in., NS yeti.aquaray.com., NS yeti.mind-dns.nl., NS dahu1.yeti.eu.org., NS dahu2.yeti.eu.org., NS yeti1.ipv6.ernet.in., NS ns-yeti.bondis.org., NS yeti-ns.ix.ru., NS yeti-ns.lab.nic.cl., NS yeti-ns.tisf.net., NS yeti-ns.wide.ad.jp., NS yeti-ns.conit.co., NS yeti-ns.datev.net., NS yeti-ns.switch.ch., NS yeti-ns.as59715.net., NS yeti-ns1.dns-lab.net., NS yeti-ns2.dns-lab.net., NS yeti-ns3.dns-lab.net., NS xn--r2bi1c.xn--h2bv6c0a.xn--h2brj9c., NS yeti-dns01.dnsworkshop.org., NS yeti-dns02.dnsworkshop.org., NS 3f79bb7b435b05321651daefd374cd.yeti-dns.net., NS ca978112ca1bbdcafac231b39a23dc.yeti-dns.net., RRSIG (1225)

Et ici par tshark :


1   0.000000 2001:4b98:dc2:43:216:3eff:fea9:41a → 2a02:cdc5:9715:0:185:5:203:53 DNS 90 Standard query 0xc70f NS <Root> OPT
2   0.038259 2a02:cdc5:9715:0:185:5:203:53 → 2001:4b98:dc2:43:216:3eff:fea9:41a DNS 1287 Standard query response 0xc70f NS <Root> NS bii.dns-lab.net NS yeti.bofh.priv.at NS yeti.ipv6.ernet.in NS yeti.aquaray.com NS yeti.mind-dns.nl NS dahu1.yeti.eu.org NS dahu2.yeti.eu.org NS yeti1.ipv6.ernet.in NS ns-yeti.bondis.org NS yeti-ns.ix.ru NS yeti-ns.lab.nic.cl NS yeti-ns.tisf.net NS yeti-ns.wide.ad.jp NS yeti-ns.conit.co NS yeti-ns.datev.net NS yeti-ns.switch.ch NS yeti-ns.as59715.net NS yeti-ns1.dns-lab.net NS yeti-ns2.dns-lab.net NS yeti-ns3.dns-lab.net NS xn--r2bi1c.xn--h2bv6c0a.xn--h2brj9c NS yeti-dns01.dnsworkshop.org NS yeti-dns02.dnsworkshop.org NS 3f79bb7b435b05321651daefd374cd.yeti-dns.net NS ca978112ca1bbdcafac231b39a23dc.yeti-dns.net RRSIG AAAA 240c:f:1:22::6 AAAA 2a01:4f8:161:6106:1::10 AAAA 2001:e30:1c1e:1:

Et un décodage plus détaillé de tshark dans ce fichier.

Enfin, la section 5 de notre RFC traite des problèmes de sécurité du priming. Évidemment, si un attaquant injecte une fausse réponse aux requêtes de priming, il pourra détourner toutes les requêtes ultérieures vers des machines de son choix. À part le RFC 5452, la seule protection est DNSSEC : si le résolveur valide (et a donc la clé publique de la racine), il pourra détecter que les réponses sont mensongères. Cela a l'avantage de protéger également contre d'autres attaques, ne touchant pas au priming, comme les attaques sur le routage.

Notez que DNSSEC est recommandé pour valider les réponses ultérieures mais, comme on l'a vu, n'est pas important pour valider la réponse de priming elle-même, puisque root-servers.net n'est pas signé. Si un attaquant détournait, d'une manière ou d'une autre, vers un faux serveur racine, servant de fausses données, ce ne serait qu'une attaque par déni de service, puisque le résolveur validant pourrait détecter que les réponses sont fausses.

Ce RFC a connu une très longue gestation puisque le premier brouillon date de février 2007 (vous pouvez admirer la chronologie).


Téléchargez le RFC 8109


L'article seul

RFC 8117: Current Hostname Practice Considered Harmful

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : C. Huitema (Private Octopus Inc.), D. Thaler (Microsoft), R. Winter (University of Applied Sciences Augsburg)
Pour information
Réalisé dans le cadre du groupe de travail IETF intarea
Première rédaction de cet article le 12 mars 2017


« Je suis l'iPhone de Jean-Luc ! » Traditionnellement, les ordinateurs connectés à l'Internet ont un nom, et ce nom est souvent annoncé à l'extérieur par divers protocoles. Cette pratique très répandue, dont l'origine remonte à l'époque où on n'avait que quelques gros serveurs partagés, et fixes, est dangereuse pour la vie privée, dans un monde de mobilité et de machines individuelles. Comme le note ce nouveau RFC, « c'est comme si on se promenait dans la rue avec une étiquette bien visible portant son nom ». Ce RFC dresse l'état des lieux, fait la liste des protocoles problématiques, et suggère, lorsqu'on ne peut pas changer le protocole, d'utiliser des noms aléatoires, ne révélant rien sur la machine.

Pour illustrer le problème, voici un exemple du trafic WiFi pendant une réunion, en n'écoutant qu'un seul protocole, mDNS (RFC 6762). Et d'autres protocoles sont tout aussi bavards. Notez que cette écoute n'a nécessité aucun privilège particulier sur le réseau, ni aucune compétence. N'importe quel participant à la réunion, ou n'importe quelle personne située à proximité pouvait en faire autant avec tcpdump (j'ai changé les noms des personnes) :

% sudo tcpdump -n -vvv port 5353
tcpdump: listening on wlp2s0, link-type EN10MB (Ethernet), capture size 262144 bytes
15:03:16.909436 IP6 fe80::86a:ed2c:1bcc:6540.5353 > ff02::fb.5353: 0*- [0q] 2/0/3 0.4.5.6.C.C.B.1.C.2.D.E.A.6.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.E.F.ip6.arpa. (Cache flush) [2m] PTR John-Smiths-iPhone-7.local., [...]
15:03:17.319992 IP 172.25.1.84.5353 > 224.0.0.251.5353: 0*- [0q] 2/0/3 C.4.1.6.F.8.D.E.0.3.6.3.4.1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.8.E.F.ip6.arpa. (Cache flush) [2m] PTR Jane-iPhone.local., [...]
15:03:20.699557 IP6 fe80::e2ac:cbff:fe95:da80.5353 > ff02::fb.5353: 0 [5q] [4n] [1au] PTR (QU)? _googlecast._tcp.local. ANY (QU)? info-mac-66._smb._tcp.local. [...]

On y voit que les noms des machines présentes sont annoncés à tous (ff02::fb et 224.0.0.251 sont des adresses multicast). Certains noms sont très révélateurs (nom, prénom et type de la machine), d'autres un peu moins (prénom et type), d'autres sont presques opaques (juste un type de machine, très général). Un indiscret qui regarde le trafic sur des réseaux publiquement accessibles peut ainsi se faire une bonne idée de quelles machines sont présentes, voire de qui est présent. Les deux exemples des noms info-mac-66 et John-Smiths-iPhone-7 illustrent les deux risques. Dans le premier cas, si le nom est stable, il permet de suivre à la trace une machine qui se déplacerait. Le second cas est encore pire puisqu'on a directement le nom du propriétaire.

Le fait que les ordinateurs aient des noms est une tradition très ancienne (voir la définition de host name dans le RFC 7719). Un nom court (sans point à l'intérieur) combiné avec un suffixe forme un FQDN (Fully Qualified Domain Name, cf. RFC 1983). On utilise ces noms courts et ces FQDN à plein d'endroits. IP lui-même n'utilise pas de noms du tout mais plein de protocoles de la famille TCP/IP le font, comme mDNS montré plus haut.

Un nom court doit être unique dans un contexte donné mais n'est pas forcément unique mondialement. Le FQDN, lui, est unique au niveau mondial.

Je vous recommande l'excellent travail de M. Faath, F. Weisshaar et R. Winter, « How Broadcast Data Reveals Your Identity and Social Graph » à l'atelier TRAC 2016 (supports de leur exposé), montrant toutes les fuites d'information liées à cette utilisation des noms, et ce qu'un méchant peut en faire. (C'est ce groupe qui avait écouté le trafic WiFi lors d'une réunion IETF à Prague, déclenchant une grande discussion sur les attentes en matière de vie privée quand le trafic est diffusé.)

Pourquoi nomme-t-on les ordinateurs, au fait, à part la tradition ? Sur un réseau, bien des systèmes d'exploitation, à commencer par Unix et Windows tiennent pour acquis que les ordinateurs ont un nom, et ce nom peut être utilisé dans des tas de cas. Il existe plusieurs schémas de nommage (section 2 du RFC), du plus bucolique (noms de fleurs) au plus français (noms de vins) en passant par les schémas bien geeks comme les noms des personnages du Seigneur des Anneaux. Mais, parfois, c'est le système d'exploitation lui-même qui nomme l'ordinateur, en combinant le nom de l'utilisateur et les caractéristiques de l'ordinateur, comme on le voit avec les iPhones dans l'exemple tcpdump ci-dessus. (Sur les schémas de nommage, voir le RFC 1178, et, sur un ton plus léger, le RFC 2100. Il existe une excellente page Web pleine d'idées de noms. L'ISC fait des statistiques sur les noms vus sur Internet. Entre 1995 et 2017, vous pouvez constater la décroissance des noms sympas en faveur des noms utilitaires.)

Dans les environnements corporate, on ne laisse pas l'utilisateur choisir et il y a un schéma officiel. Par exemple, sur le réseau interne de Microsoft, le nom est dérivé du nom de login de l'utilisateur et un des auteurs du RFC a donc une machine huitema-test-2.

Est-il nécessaire de donner des noms aux « objets », ces machines à laver ou brosses à dents connectés, qui sont des ordinateurs, mais ne sont en général pas perçus comme tels (ce qui a des graves conséquences en terme de sécurité) ? Comme ces engins n'offrent en général pas de services, ils ont moins besoin d'un nom facile à retenir, et, lorsque les protocoles réseaux employés forcent à utiliser un nom, c'est également un nom fabriqué à partir du nom du fabricant, du modèle de l'appareil et de son numéro de série (donc, un nom du genre BrandX-edgeplus-4511-2539). On voit même parfois la langue parlée par l'utilisateur utilisée dans ce nom, qui est donc très « parlant ».

Même un identificateur partiel peut être révélateur (section 3 du RFC). Si on ordinateur se nomme dthaler-laptop, on ne peut pas être sûr qu'il appartienne vraiment au co-auteur du RFC Dave Thaler. Il y a peut-être d'autres D. Thaler dans le monde. Mais si on observe cet ordinateur faire une connexion au réseau interne de Microsoft (pas besoin de casser le chiffrement, les métadonnées suffisent), on est alors raisonnablement sûr qu'on a identifié le propriétaire.

Beaucoup de gens croient à tort qu'un identificateur personnel doit forcément inclure le nom d'état civil de l'utilisateur. Mais ce n'est pas vrai : il suffit que l'identificateur soit stable, et puisse être relié, d'une façon ou d'une autre, au nom de l'utilisateur. Par exemple, si un ordinateur portable a le nom stable a3dafaaf70950 (nom peu parlant) et que l'observateur ait pu voir une fois cette machine faire une connexion à un compte IMAP jean_dupont, on peut donc associer cet ordinateur à Jean Dupont, et le suivre ensuite à la trace.

Ce risque est encore plus important si l'attaquant maintient une base de données des identifications réussies (ce qui est automatisable), et des machines associées. Une ou deux fuites d'information faites il y a des mois, voire des années, et toutes les apparitions ultérieures de cette machine mèneront à une identification personnelle.

Donc, n'écoutez pas les gens qui vous parleront d'« anonymat » parce que les noms de machine ne sont pas parlants (comme le a3dafaaf70950 plus haut). Si quelqu'un fait cela, cela prouve simplement qu'il ne comprend rien à la sécurité informatique. Un nom stable, pouvant être observé (et on a vu que bien des protocoles étaient très indiscrets), permet l'observation, et donc la surveillance.

Justement, quels sont les protocoles qui laissent ainsi fuiter des noms de machine, que l'observateur pourra noter et enregistrer (section 4 du RFC) ? Il y a d'abord DHCP, où le message de sollicitation initial (diffusé à tous…) contient le nom de la machine en clair. Le problème de vie privée dans DHCP est analysé plus en détail dans les RFC 7819 et RFC 7824. Les solutions pour limiter les dégâts sont dans le RFC 7844.

Le DNS est également une cause de fuite, par exemple parce qu'il permet d'obtenir le nom d'une machine à partir de son adresse IP, avec les requêtes PTR dans in-addr.arpa ou ip6.arpa, nom qui peut réveler des détails. C'est le cas avec tout protocole conçu justement pour distribuer des informations, comme celui du RFC 4620 (qui ne semble pas très déployé dans la nature).

Plus sérieux est le problème de mDNS (RFC 6762), illustré par le tcpdump montré plus haut. Les requêtes sont diffusées à tous sur le réseau local, et contiennent, directement ou indirectement, les noms des machines. Même chose avec le DNS Service Discovery du RFC 6763 et le LLMNR du RFC 4795 (beaucoup moins fréquent que mDNS).

Enfin, NetBIOS (quelqu'un l'utilise encore ?) est également une grande source d'indiscrétions.

Assez décrit le problème, comment le résoudre (section 5) ? Bien sûr, il faudra des protocoles moins bavards, qui ne clament pas le nom de la machine à tout le monde. Mais changer d'un coup des protocoles aussi répandus et aussi fermement installés que, par exemple, DHCP, ne va pas être facile. De même, demander aux utilisateurs de ne pas faire de requêtes DHCP lorsqu'ils visitent un réseau « non sûr » est difficile (déjà, comment l'utilisateur va-t-il correctement juger si le réseau est sûr ?), d'autant plus qu'ils risquent fort de ne pas avoir de connectivité du tout, dans ce cas. Certes, couper les protocoles non nécessaires est un bon principe de sécurité en général. Mais cet angle d'action semble quand même bien trop drastique. (Il faut aussi noter qu'il existe des protocoles privés, non-IETF, qui peuvent faire fuire des noms sans qu'on le sache. Le client Dropbox diffuse à la cantonade l'ID du client, et celui des shares où il se connecte. Il est facile de faire un graphe des utilisateurs en mettant ensemble ceux qui se connectent au même share.)

La suggestion de notre RFC est donc d'attaquer le problème d'une autre façon, en changeant le nom de la machine, pour lui substituer une valeur imprévisible (comme le fait le RFC 7844 pour les adresses MAC). Pour chaque nouveau réseau où est connectée la machine, on génère aléatoirement un nouveau nom, et c'est celui qu'on utilisera dans les requêtes DHCP ou mDNS. Ces protocoles fonctionneront toujours mais la surveillance des machines mobiles deviendra bien plus difficile. Bien sûr, pour empêcher toute corrélation, le changement de nom doit être coordonné avec les changements des autres identificateurs, comme l'adresse IP ou l'adresse MAC.

Windows a même un concept de « nom de machine par réseau », ce qui permet aux machines ayant deux connexions de présenter deux identités différentes (malheureusement, Unix n'a pas ce concept, le nom est forcément global).

Bien sûr, on n'a rien sans rien (section 6). Si on change les noms des machines, on rendra l'administration système plus difficile. Par exemple, l'investigation sur un incident de sécurité sera plus complexe. Mais la défense de la vie privée est à ce prix.

Pour l'instant, à ma connaissance, il n'y a pas encore de mise en œuvre de cette idée de noms imprévisibles et changeants. (Une proposition a été faite pour Tails. Notez qu'il existe d'autres possibilités comme d'avoir un nom unique partout.)


Téléchargez le RFC 8117


L'article seul

RFC 8128: IETF Appointment Procedures for the ICANN Root Zone Evolution Review Committee

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : C. Morgan (AMS)
Pour information
Première rédaction de cet article le 11 mars 2017


Un petit RFC purement bureaucratique publié hier, il décrit les procédures par lesquelles l'IETF nomme un représentant dans un des innombrables comités de l'ICANN, le RZERC (Root Zone Evolution Review Committee), qui travaille sur la gestion de la zone racine du DNS.

Ce nouveau comité RZERC est chargé des mécanismes de publication de la zone racine, une zone évidemment cruciale puisque la nature arborescente du DNS fait que, si elle a des problèmes, plus rien ne marche. Notez que le RZERC ne s'occupe que de la création et de la publication de la zone racine, pas de servir cette zone. Cette tâche incombe en effet aux serveurs racines du DNS, qui sont indépendants de l'ICANN (contrairement à ce qu'on lit souvent dans des médias mal informés). L'actuelle charte du RZERC est en ligne et elle prévoit que le comité comprend entre autres « The Chair or delegate of the Internet Engineering Task Force ».

C'est l'IAB qui désigne le représentant IETF, le premier étant Jim Reid. Les qualités nécessaires sont citées en section 2 de notre RFC. Sans surprise, il faut être techniquement très compétent, et il faut pouvoir traduire des recommandations en des termes compréhensibles par la bureaucratie ICANN (« be able to articulate those technology issues such that the ICANN Board can be provided with sound technical perspectives »). Le RFC précise également qu'il faut comprendre l'articulation de la gouvernance Internet et les rôles des différents organismes, une tâche complexe, c'est sûr !

Suivant les procédures décrites en section 3 du RFC, un appel à volontaires avait été lancé le 25 mai 2016, il y avait quatre candidats (Marc Blanchet, Warren Kumari, Kaveh Ranjbar et Jim Reid), et Jim Reid a été nommé le 11 août 2016. Depuis, si on veut savoir ce que fait ce comité, il faut regarder sa page Web officielle. Son rôle n'est pas encore bien défini et fait l'objet de la plupart des discussions. En gros, il devrait intervenir uniquement lorsqu'une proposition de changement important est faite, pas pour la gestion quotidienne.


Téléchargez le RFC 8128


L'article seul

RFC 8078: Managing DS records from the Parent via CDS/CDNSKEY

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : O. Gudmundsson (CloudFlare), P. Wouters (Red Hat)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 11 mars 2017


Un problème fréquent avec DNSSEC est de transmettre à sa zone parente les clés publiques de signature de sa zone, pour que le parent puisse signer un lien qui va vers ces clés (l'enregistrement de type DS). Le RFC 7344 apportait une solution partielle, avec ses enregistrements CDS et CDNSKEY. Il y manquait deux choses : la création du premier DS (activation initiale de DNSSEC), et le retrait de tout les DS (on arrête de faire du DNSSEC). Ce nouveau RFC 8078 comble ces deux manques (et, au passage, change l'état du RFC 7344, qui passe sur le Chemin des Normes).

Avant le RFC 7344, tout changement des clés KSK (Key Signing Key) d'une zone nécessitait une interaction avec la zone parente, par le biais d'un mécanisme non-DNS (« out-of-band », par exemple un formulaire Web). La solution du RFC 7344, elle, n'utilise que le DNS (« in-band »). Ce nouveau RFC complète le RFC 7344 pour les configurations initiales et finales. (Le problème est complexe car il peut y avoir beaucoup d'acteurs en jeu. Par exemple, le BE n'est pas forcément l'hébergeur DNS. Ces difficultés ont certainement nui au déploiement de DNSSEC.)

Lorsqu'on change d'hébergeur DNS, la solution la plus propre est de faire un remplacement des clés, depuis celle de l'ancien hébergeur jusqu'à celle du nouveau. Cette solution préserve en permanence la sécurité qu'offre DNSSEC. Mais une des procédures mentionnées par notre RFC passe au contraire par un état non sécurisé, où la zone n'est pas signée. C'est dommage mais cela est parfois nécessaire si :

  • Les logiciels utilisés ne permettent pas de faire mieux, ou l'un des deux hébergeurs ne veut pas suivre la procédure « propre »,
  • Ou bien le nouvel hébergeur ne gère pas DNSSEC du tout, ou encore le titulaire de la zone ne veut plus de DNSSEC.

Une zone non signée vaut certainement mieux qu'une signature invalide. Mais le RFC oublie de dire que cela va casser certaines applications de sécurité qui exigent DNSSEC comme DANE (RFC 6698) ou SSHFP (RFC 4255).

Avant de lire la suite de ce RFC, deux conseils :

  • Lisez bien le RFC 7344. Vraiment.
  • Rappelez-vous qu'il y a des tas d'acteurs possibles dans le DNS. Le modèle RRR (Titulaire-BE-Registre, Registrant-Registrar-Registry) n'est pas le seul. Et il n'y a pas que les TLD qui délèguent des zones ! Le RFC parle donc uniquement de « parent » (responsable parental ?) pour désigner l'entité à laquelle on s'adresse pour obtenir des changements dans la zone parente.

Les enregistrements CDS (Client-side Delegation Signer) servent à trois choses (section 2 du RFC) :

  • Installer le DS (Delegation Signer) initial dans la zone parente,
  • Remplacer (rollover) la clé publique de signature des clés (KSK, Key-Signing Key) dans la zone parente,
  • Supprimer le DS de la zone parente, débrayant ainsi la validation DNSSEC de la zone fille chez les résolveurs.

Avec le RFC 7344, seule la deuxième était possible (c'est la moins dangereuse, qui ne nécessite aucun changement dans les relations de confiance,notamment entre parente et fille). Notre RFC 8078 permet désormais les deux autres, plus délicates, car posant davantage de problèmes de sécurité.

La sémantique des enregistrements CDS (ou CDNSKEY) est donc désormais « la publication d'un ou plusieurs CDS indique un souhait de synchronisation avec la zone parente ; celle-ci est supposée avoir une politique en place pour accepter/refuser/vérifier ce ou ces CDS, pour chacune des trois utilisations notées ci-dessus ». Quand des CDS différents des DS existants apparaissent dans la zone fille, le responsable parental doit agir.

D'abord, l'installation initiale d'un DS alors qu'il n'y en avait pas avant (section 3 du RFC). La seule apparition du CDS ou du CDNSKEY ne peut pas suffire car comment le vérifier, n'ayant pas encore de chaîne DNSSEC complète ? Le responsable parental peut utiliser les techniques suivantes :

  • Utiliser un autre canal, extérieur au DNS, par exemple l'API du responsable parental,
  • Utiliser des tests de vraisemblance, du genre un message de confirmation envoyé au contact technique du domaine, ou bien regarder si la configuration du domaine est stable,
  • Attendre un certain temps, de préférence vérifier depuis plusieurs endroits dans le réseau (pour éviter les empoisonnements locaux), puis considérer le CDS comme valable s'il est resté pendant ce temps (l'idée est qu'un piratage aurait été détecté, pendant ce délai),
  • Envoyer un défi au titulaire de la zone fille, par exemple génerer une valeur aléatoire et lui demander de l'insérer sous forme d'un enregistrement TXT dans la zone (bien des applications qui veulent vérifier le responsable d'un domaine font cela, par exemple Keybase ou bien Google webmasters),
  • Accepter immédiatement s'il s'agit d'une nouvelle délégation. Ainsi, le domaine sera signé et validable dès le début.

La deuxième utilisation des CDS, remplacer une clé est, on l'a vu, déjà couverte par le RFC 7344.

Et pour la troisième utilisation, la suppression de tous les DS chez le parent ? Elle fait l'objet de la section 4 du RFC. Pour demander cette suppression, on publie un CDS (ou un CDNSKEY) avec un champ « algorithme » à zéro. Cette valeur n'est pas affectée à un vrai algorithme dans le registre officiel, elle est réservée (cf. section 6 du RFC) pour dire « efface ». (Le RFC 4398 utilisait déjà le même truc.)

Pour éviter tout accident, le RFC est plus exigeant que cela et exige cette valeur spécifique pour ces enregistrements :

DOMAINNAME IN CDS 0 0 0 0
    

ou bien :

    
DOMAINNNAME IN    CDNSKEY 0 3 0 0      
    

(Le 3 étant l'actuel numéro de version de DNSSEC, voir le RFC 4034, section 2.1.2.)

Une fois le CDS (ou CDNSKEY) « zéro » détecté, et validé par DNSSEC, le parent retire le DS. Une fois le TTL passé, le fils peut « dé-signer » la zone.

À noter que ce RFC a été retardé par la question du déplacement du RFC 7344, de son état « pour information », au Chemin des Normes. La demande était discrète, et avait été raté par certains relecteurs, qui ont protesté ensuite contre ce « cavalier ». L'« élévation » du RFC 7344 est désormais explicite.


Téléchargez le RFC 8078


L'article seul

RFC 8095: Services Provided by IETF Transport Protocols and Congestion Control Mechanisms

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : G. Fairhurst (University of Aberdeen), B. Trammell, M. Kuehlewind (ETH Zurich)
Pour information
Réalisé dans le cadre du groupe de travail IETF taps
Première rédaction de cet article le 10 mars 2017


Les protocoles de transport (couche 4 dans le modèle en couches traditionnel), comme le fameux TCP, fournissent certains services aux applications situées au-dessus d'eux. Mais quels services exactement ? Qu'attend-on de la couche de transport ? Le but de ce RFC de synthèse est de lister tous les services possibles de la couche 4, et d'analyser ensuite tous les protocoles existants pour voir lesquels de ces services sont offerts. Ce document ne normalise donc pas un nouveau protocole, il classe et organise les protocoles existants. (L'idée est de pouvoir ensuite développer une interface abstraite permettant aux applications d'indiquer quels services elles attendent de la couche transport au lieu de devoir, comme c'est le cas actuellement, choisir un protocole donné. Une telle interface abstraite permettrait au système d'exploitation de choisir le protocole le plus adapté à chaque environnement.)

C'est d'autant plus important qu'il n'y a pas que TCP mais aussi des protocoles comme SCTP, UDP, DCCP, les moins connus FLUTE ou NORM, et même HTTP, qui est devenu une couche de transport de fait. Toute évolution ultérieure de l'architecture de l'Internet, des middleboxes, des API offertes par le système d'exploitation, implique une compréhension détaillée de ce que fait exactement la couche transport.

Pour TCP, tout le monde connait (ou croit connaitre) : il fournit un service de transport de données fiable (les données qui n'arrivent pas sont retransmises automatiquement, l'application n'a pas à s'en soucier, la non-modification est - insuffisamment - contrôlée via une somme de contrôle), et ordonné (les octets arrivent dans l'ordre d'envoi même si, dans le réseau sous-jacent, un datagramme en a doublé un autre). TCP ne fournit pas par contre de service de confidentialité, ce qui facilite le travail de la NSA ou de la DGSI. Tout le monde sait également qu'UDP ne fournit aucun des deux services de fiabilité et d'ordre : si l'application en a besoin, elle doit le faire elle-même (et il est donc logique que la plupart des applications utilisent TCP).

Parfois, le service de transport offert aux applications est lui-même bâti sur un autre service de transport. C'est la raison pour laquelle ce RFC présente des protocoles qui ne sont pas « officiellement » dans la couche 4 (mais, de toute façon, le modèle en couches n'a toujours été qu'une vague indication ; en faire une classification rigide n'a aucun intérêt, et a été une des raisons de l'échec du projet l'OSI). Un exemple est TLS. Une application qui s'en sert ne voit pas directement le TCP sous-jacent, elle confie ses données à TLS qui, à son tour, fait appel à TCP. Le service de transport vu par l'application offre ainsi les fonctions de TCP (remise fiable et ordonnée des données) plus celles de TLS (confidentialité, authentification et intégrité). Il faudrait être particulièrement pédant pour s'obstiner à classer TLS dans les applications comme on le voit parfois.

Le même phénomène se produit pour UDP : comme ce protocole n'offre quasiment aucun service par lui-même, on le complète souvent avec des services comme TFRC (RFC 5348) ou LEDBAT (RFC 6817) qui créent ainsi un nouveau protocole de transport au-dessus d'UDP.

La section 1 de notre RFC liste les services possibles d'une couche de transport :

  • Envoi des messages à un destinataire (unicast) ou à plusieurs (multicast ou anycast),
  • Unidirectionnel (ce qui est toujours le cas avec le multicast) ou bidirectionnel,
  • Nécessite un établissement de la connexion avant d'envoyer des données, ou pas,
  • Fiabilité de l'envoi (par un mécanisme d'accusé de réception et de réémission) ou bien fire and forget (notez que cette fiabilité peut être partielle, ce que permet par exemple SCTP),
  • Intégrité des données (par exemple via une somme de contrôle),
  • Ordre des données (avec certains protocoles de transport comme UDP, le maintien de l'ordre des octets n'est pas garanti, un paquet pouvant en doubler un autre),
  • Structuration des données (framing), certains protocoles découpent en effet les données en messages successifs (ce que ne fait pas TCP),
  • Gestion de la congestion,
  • Confidentialité,
  • Authentification (TLS fournit ces deux derniers services).

La section 3 du RFC est le gros morceau. Elle liste tous les protocoles de transport possibles (au moins ceux normalisés par l'IETF), en donnant à chaque fois une description générale du protocole, l'interface avec les applications, et enfin les services effectivement offerts par ce protocole.

À tout seigneur, tout honneur, commençons par l'archétype des protocoles de transport, TCP. Normalisé dans le RFC 793, très largement répandu (il est difficile d'imaginer une mise en œuvre d'IP qui ne soit pas accompagnée de TCP), utilisé quotidiennement par des milliards d'utilisateurs. Le RFC originel a connu pas mal de mises à jour et, aujourd'hui, apprendre TCP nécessite de lire beaucoup de RFC (le RFC 7414 en donne la liste). Ainsi, la notion de données urgentes, qui était dans le RFC originel, a été supprimée par le RFC 6093.

TCP multiplexe les connexions en utilisant les numéros de port, comme beaucoup de protocoles de transport. Une connexion est identifiée par un tuple {adresse IP source, port source, adresse IP destination, port destination}. Le port de destination identifie souvent le service utilisé (c'est moins vrai aujourd'hui, où la prolifération de middleboxes stupides oblige à tout faire passer sur les ports 80 et 443). TCP fournit un service de données non-structurées, un flot d'octets, mais, en interne, il découpe ces octets en segments, dont la taille est négociée au début (en général, TCP essaie de faire que cette taille soit la MTU du chemin, en utilisant les RFC 1191, RFC 1981 et de plus en plus le RFC 4821). Chaque octet envoyé a un numéro, le numéro de séquence, et c'est ainsi que TCP met en œuvre la fiabilité et l'ordre. (Contrairement à ce que croient certaines personnes, c'est bien l'octet qui a un numéro, pas le segment.) Autrefois, si deux segments non contigus étaient perdus, il fallait attendre la réémission du premier pour demander celle du second, mais les accusés de réception sélectifs du RFC 2018 ont changé cela.

Quant au contrôle de congestion de TCP, il est décrit en détail dans le RFC 5681. TCP réagit à la perte de paquets (ou bien à leur marquage avec l'ECN du RFC 3168) en réduisant la quantité de données envoyées.

Les données envoyées par l'application ne sont pas forcément transmises immédiatement au réseau. TCP peut attendre un peu pour remplir davantage ses segments (RFC 896). Comme certaines applications (par exemple celles qui sont fortement interactives comme SSH) n'aiment pas les délais que cela entraine, ce mécanisme est typiquement débrayable.

Enfin, pour préserver l'intégrité des données envoyées, TCP utilise une somme de contrôle (RFC 793, section 3.1, et RFC 1071). Elle ne protège pas contre toutes les modifications possibles et il est recommandé aux applications d'ajouter leur propre contrôle d'intégrité (par exemple, si on transfère un fichier, via un condensat du fichier).

Et l'interface avec les applications, cruciale, puisque le rôle de la couche transport est justement d'offrir des services aux applications ? Celle de TCP est décrite de manière relativement abstraite dans le RFC 793 (six commandes, Open, Close, Send, Receive, etc). Des points comme les options TCP n'y sont pas spécifiés. Le RFC 1122 est un peu plus détaillé, mentionnant par exemple l'accès aux messages ICMP qui peuvent indiquer une erreur TCP. Enfin, une interface concrète est celle des prises, normalisées par POSIX (pas de RFC à ce sujet). Vous créez une prise avec l'option SOCK_STREAM et hop, vous utilisez TCP et tous ses services.

Quels services, justement ? TCP fournit :

  • Établissement d'une connexion, et démultiplexage en utilisant les numéros de port,
  • Transport unicast (l'anycast est possible, si on accepte le risque qu'un changement de routes casse subitement une connexion),
  • Communication dans les deux sens,
  • Données envoyées sous forme d'un flot d'octets, sans séparation (pas de notion de message, c'est à l'application de le faire, si elle le souhaite, par exemple en indiquant la taille du message avant le message, comme le font EPP et DNS), c'est aussi cela qui permet l'accumulation de données avant envoi (algorithme de Nagle),
  • Transport fiable, les données arriveront toutes, et dans l'ordre,
  • Détection d'erreurs (mais pas très robuste),
  • Contrôle de la congestion, via les changements de taille de la fenêtre d'envoi (la fenêtre est l'ensemble des octets qui peuvent être envoyés avant qu'on ait reçu l'accusé de réception des données en cours), voir le RFC 5681.

Par contre, TCP ne fournit pas de confidentialité, et l'authentification se limite à une protection de l'adresse IP contre les attaquants situés hors du chemin (RFC 5961).

Après TCP, regardons le deuxième protocole de transport étudié, MPTCP (Multipath TCP, RFC 6824). C'est une extension de TCP qui permet d'exploiter le multi-homing. Pour échapper aux middleboxes intrusives, MPTCP fonctionne en créant plusieurs connexions TCP ordinaires depuis/vers toutes les adresses IP utilisées, et en multiplexant les données sur ces connexions (cela peut augmenter le débit, et cela augmente la résistance aux pannes, mais cela peut aussi poser des problèmes si les différents chemins ont des caractéristiques très différentes). La signalisation se fait par des options TCP.

L'interface de base est la même que celle de TCP, mais il existe des extensions (RFC 6897) pour tirer profit des particularités de MPTCP.

Les services sont les mêmes que ceux de TCP avec, en prime le multi-homing (il peut même y avoir des adresses IPv4 et IPv6 dans la même session MPTCP), et ses avantages notamment de résilience.

Après TCP, UDP est certainement le protocole de transport le plus connu. Il est notamment très utilisé par le DNS. Le RFC 8085 explique comment les applications peuvent l'utiliser au mieux. La section 3.3 de notre RFC lui est consacrée, pour décrire son interface et ses services.

Contrairement à TCP, UDP n'a pas la notion de connexion (on envoie directement les données, sans négociation préalable), UDP découpe les données en messages (voilà pourquoi les messages DNS en UDP ne sont pas précédés d'une longueur : UDP lui-même fait le découpage), n'a pas de contrôle de congestion, et ne garantit pas le bon acheminement. UDP dispose d'un contrôle d'intégrité, mais il est facultatif (quoique très recommandé) en IPv4, où on peut se contenter du contrôle d'intégrité d'IP. IPv6 n'ayant pas ce contrôle, UDP sur IPv6 doit activer son propre contrôle, sauf dans certains cas très précis (RFC 6936).

En l'absence de contrôle de congestion, l'application doit être prudente, veiller à ne pas surcharger le réseau, et ne pas s'étonner si l'émetteur envoie plus que ce que le récepteur peut traiter. D'une façon générale, il faut penser à lire le RFC 8085, qui explique en détail tout ce qu'une application doit faire si elle tourne sur UDP.

Il est d'ailleurs recommandé de bien se poser la question de l'utilité d'UDP, dans beaucoup de cas. Un certain nombre de développeurs se disent au début d'un projet « j'ai besoin de vitesse [sans qu'ils fassent bien la différence entre latence et capacité], je vais utiliser UDP ». Puis ils découvrent qu'ils ont besoin de contrôle de flux, d'ordre des données, de bonne réception des données, ils ajoutent à chaque fois des mécanismes ad hoc, spécifiques à leur application et, au bout du compte, ils ont souvent réinventé un truc aussi lourd que TCP, mais bien plus bogué. Attention donc à ne pas réinventer la roue pour rien.

L'interface d'UDP, maintenant. Le RFC 768 donne quelques indications de base, que le RFC 8085 complète. Bien qu'UDP n'ait pas le concept de connexion, il est fréquent que les API aient une opération connect() ou analogue. Mais il ne faut pas la confondre avec l'opération du même nom sur TCP : ce connect() UDP est purement local, associant la structure de données locale à une machine distante (c'est ainsi que cela se passe avec les prises Berkeley).

Et les services d'UDP ? La liste est évidemment bien plus courte que pour TCP. Elle comprend :

  • Transport des données, unicast, multicast , anycast et broadcast (c'est le seul point où UDP en fournit davantage que TCP),
  • Démultiplexage en utilisant les numéros de port,
  • Unidirectionnel (ce qui est toujours le cas avec le multicast) ou bidirectionnel,
  • Données structurées en messages,
  • Aucune garantie, ou signalement, des pertes de message,
  • Aucune garantie sur l'ordre de délivrance des messages.

Nettement moins connu qu'UDP est UDP-Lite, normalisé dans le RFC 3828. C'est une version très légèrement modifiée d'UDP, où la seule différence est que les données corrompues (détectées par la somme de contrôle) sont quand même données à l'application réceptrice, au lieu d'être jetées comme avec UDP. Cela peut être utile pour certains applications, notamment dans les domaines audio et vidéo.

Avec UDP-Lite, le champ Longueur de l'en-tête UDP change de sémantique : il n'indique plus la longueur totale des données mais la longueur de la partie qui est effectivement couverte par la somme de contrôle. Typiquement, on ne couvre que l'en-tête applicatif. Le reste est... laissé à la bienveillance des dieux (ou des démons). Pour tout le reste, voyez la section sur UDP.

Notez qu'il n'existe pas d'API spécifique pour UDP-Lite. Si quelqu'un parmi mes lecteurs a des exemples de code bien clairs...

Bien plus original est SCTP (RFC 4960). C'est un protocole à connexion et garantie d'acheminement et d'ordre des données, comme TCP. Mais il s'en distingue par sa gestion du multi-homing. Avec SCTP, une connexion peut utiliser plusieurs adresses IP source et destination, et passer de l'une à l'autre pendant la session, assurant ainsi une bonne résistance aux pannes. Plus drôle, cet ensemble d'adresses peut mêler des adresses IPv4 et IPv6.

Notez aussi qu'une connexion SCTP (on dit une association) comporte plusieurs flux de données, afin de minimiser le problème connu sous le nom de head of line blocking (un paquet perdu empêche la délivrance de toutes les données qui suivent tant qu'il n'a pas été réémis).

SCTP avait surtout été conçu pour la signalisation dans les réseaux téléphoniques. Mais on le trouve dans d'autres cas, comme ForCES (cf. RFC 5811) ou comme la signalisation WebRTC.

Contrairement à TCP, SCTP utilise une quadruple poignée de mains pour établir la connexion, ce qui permet de ne négocier les options qu'une fois certain de l'identité du partenaire (les techniques anti-DoS de TCP sont incompatible avec l'utilisation des options, cf. RFC 4987, section 3.6). La somme de contrôle fait 32 bits (au lieu des 16 bits de TCP et UDP) et est donc normalement plus robuste.

SCTP est très extensible et plusieurs extensions ont déjà été définies comme l'ajout ou le retrait d'adresses IP pendant l'association (RFC 5061), ou bien la possibilité de n'accepter qu'une fiabilité partielle (RFC 3758). Pour la sécurité, on peut faire tourner TLS sur SCTP (RFC 3436) au prix de la perte de quelques fonctions, ou bien utiliser DTLS (RFC 6083), qui préserve quasiment toutes les fonctions de SCTP.

Victime fréquente des middleboxes stupides qui ne connaissent qu'UDP et TCP, SCTP peut tourner sur UDP (RFC 6951), au lieu de directement reposer sur IP, afin de réussir à passer ces middleboxes.

Contrairement à des protocoles de transport plus anciens, SCTP a une interface bien spécifiée. Le RFC 4960 définit l'interface abstraite, et une extension aux prises Berkeley, spécifiée dans le RFC 6458, lui donne une forme concrète. Cette API prévoit également certaines extensions, comme celle des reconfigurations dynamiques d'adresses du RFC 5061.

Les services fournis par SCTP sont très proches de ceux fournis par TCP, avec deux ajouts (la gestion du multi-homing et le multi-flux), et un changement (données structurées en messages, au lieu d'être un flot d'octets continu comme TCP).

Un autre protocole de transport peu connu, et ne fournissant pas, lui, de fiabilité de l'envoi des données, est DCCP (RFC 4340). DCCP est une sorte d'UDP amélioré, qui peut fournir des services supplémentaires à ceux d'UDP, tout en restant plus léger que TCP (la description du besoin figure dans le RFC 4336). DCCP est bien adapté aux applications multimédia ou aux jeux en ligne, où une faible latence est cruciale, mais où peut aimer avoir des services en plus. Sans DCCP, chaque application qui veut de l'« UDP amélioré » devrait tout réinventer (et ferait sans doute des erreurs).

DCCP a des connexions, comme TCP, qu'on établit avant de communiquer et qu'on ferme à la fin. Il offre une grande souplesse dans le choix des services fournis, choix qui peuvent être unilatéraux (seulement l'envoyeur, ou bien seulement le récepteur) ou négociés lors de l'ouverture de la connexion. Le paquet d'ouverture de connexion indique l'application souhaitée (RFC 5595), ce qui peut être une information utile aux équipements intermédiaires. S'il faut faire passer DCCP à travers des middleboxes ignorantes, qui n'acceptent qu'UDP et TCP, on peut, comme avec SCTP, encapsuler dans UDP (RFC 6773).

L'interface avec DCCP permet d'ouvrir, de fermer et de gérer une connexion. Il n'y a pas d'API standard. Les services fournis sont :

  • Transport des données, uniquement unicast,
  • Protocole à connexion, et démultiplexage fondé sur les numéros de port,
  • Structuration des données en messages,
  • Les messages peuvent être perdus (mais, contrairement à UDP, l'application est informée des pertes), et ils peuvent être transmis dans le désordre,
  • Contrôle de la congestion (le gros avantage par rapport à UDP), et avec certains choix (optimiser la latence ou au contraire la gigue, par exemple) laissés à l'application.

Autre exemple de protocole de transport, même s'ils ne sont en général pas décrits comme tels, TLS (RFC 5246) et son copain DTLS (RFC 6347). Si on est un fanatique du modèle en couches, on ne met pas ces protocoles de sécurité en couche 4 mais, selon l'humeur, en couche 5 ou en couche 6. Mais si on est moins fanatique, on reconnait que, du point de vue de l'application, ce sont bien des protocoles de transport : c'est à eux que l'application confie ses données, comptant sur les services qu'ils promettent.

TLS tourne sur TCP et DTLS sur UDP. Du point de vue de l'application, TLS fournit les services de base de TCP (transport fiable d'un flot d'octets) et DTLS ceux d'UDP (envoi de messages qui arriveront peut-être). Mais ils ajoutent à ces services de base leurs services de sécurité :

Le RFC rappelle qu'il est important de se souvenir que TLS ne spécifie pas un mécanisme d'authentification unique, ni même qu'il doit y avoir authentification. On peut n'authentifier que le serveur (c'est actuellement l'usage le plus courant), le client et le serveur, ou bien aucun des deux. La méthode la plus courante pour authentifier est le certificat PKIX (X.509), appelé parfois par une double erreur « certificat SSL ».

DTLS ajoute également au service de base quelques trucs qui n'existent pas dans UDP, comme une aide pour la recherche de PMTU ou un mécanisme de cookie contre certaines attaques.

Il n'y a pas d'API standard de TLS. Si on a écrit une application avec l'API d'OpenSSL, il faudra refaire les appels TLS si on passe à WolfSSL ou GnuTLS. C'est d'autant plus embêtant que les programmeurs d'application ne sont pas forcément des experts en cryptographie et qu'une API mal conçue peut les entrainer dans des erreurs qui auront des conséquences pour la sécurité (l'article « The most dangerous code in the world: validating SSL certificates in non-browser software » en donne plusieurs exemples).

Passons maintenant à RTP (RFC 3550). Ce protocole est surtout utilisé pour les applications multimédia, où on accepte certaines pertes de paquet, et où le format permet de récupérer après cette perte. Comme TLS, RTP fonctionne au-dessus du « vrai » protocole de transport, et peut exploiter ses services (comme la protection de l'intégrité d'une partie du contenu, que fournissent DCCP et UDP-Lite).

RTP comprend en fait deux protocoles, RTP lui-même pour les données et RTCP pour le contrôle. Par exemple, c'est via RTCP qu'un émetteur apprend que le récepteur ne reçoit pas vite et donc qu'il faudrait, par exemple, diminuer la qualité de la vidéo.

RTP n'a pas d'interface standardisée offerte aux programmeurs. Il faut dire que RTP est souvent mis en œuvre, non pas dans un noyau mais directement dans l'application (comme avec libortp sur Unix). Ces mises en œuvre sont donc en général optimisées pour une utilisation particulière, au lieu d'être généralistes comme c'est le cas avec les implémentations de TCP ou UDP.

Autre cas d'un protocole de transport qui fonctionne au-dessus d'un autre protocole de transport, HTTP (RFC 7230 et suivants). Il n'était normalement pas conçu pour cela mais, dans l'Internet d'aujourd'hui, où il est rare d'avoir un accès neutre, où les ports autres que 80 et 443 sont souvent bloqués, et où hôtels, aéroports et écoles prétendent fournir un « accès Internet » qui n'est en fait qu'un accès HTTP, bien des applications qui n'ont rien à voir avec le Web en viennent à utiliser HTTP comme protocole de transport. (Même si le RFC 3205 n'encourage pas vraiment cette pratique puisque HTTP peut ne pas être adapté à tout. Mais, souvent, on n'a pas le choix.)

Outre cette nécessité de contourner blocages et limitations, l'utilisation de HTTP comme transport a quelques avantages : protocole bien connu, disposant d'un grand nombre de mises en œuvre, que ce soit pour les clients ou pour les serveurs, et des mécanismes de sécurité existants (RFC 2617, RFC 2817…). L'un des grands succès de HTTP est le style REST : de nombreuses applications sont conçues selon ce style.

Les applications qui utilisent HTTP peuvent se servir des méthodes existantes (GET, PUT, etc) ou bien en créer de nouvelles (qui risquent de moins bien passer partout).

Je ne vais pas refaire ici la description de HTTP que contient le RFC (suivant le même plan que pour les autres protocoles de transport), je suppose que vous connaissez déjà HTTP. Notez quand même quelques points parfois oubliés : HTTP a un mécanisme de négociation du contenu, qui permet, par exemple, de choisir le format lorsque la ressource existe en plusieurs formats, HTTP a des connexions persistentes donc on n'est pas obligé de se taper un établissement de connexion TCP par requête, et HTTP a des mécanismes de sécurité bien établis, à commencer par HTTPS.

Il y a plein de bibliothèques qui permettent de faire de l'HTTP facilement (libcurl et neon en C, Requests en Python, etc). Chacune a une API différente. Le W3C a normalisé une API nommée XMLHttpRequest, très utilisée par les programmeurs JavaScript.

Les services que fournit HTTP quand on l'utilise comme protocole de transport sont :

  • Transport unicast, bi-directionnel, fiable (grâce à TCP en dessous), et avec contrôle de congestion (idem),
  • Négociation du format, possibilité de ne transférer qu'une partie d'une ressource,
  • Authentification et confidentialité si on utilise HTTPS.

Beaucoup moins connus que les protocoles précédents sont deux des derniers de notre liste, FLUTE et NORM.

FLUTE (File Delivery over Unidirectional Transport/ Asynchronous Layered Coding Reliable Multicast) est normalisé dans le RFC 6726. Il est conçu pour un usage très spécifique, la distribution de fichiers à des groupes multicast de grande taille, où on ne peut pas demander à chaque récepteur d'accuser réception. Il est surtout utilisé dans le monde de la téléphonie mobile (par exemple dans la spécification 3GPP TS 26.346).

FLUTE fonctionne sur UDP, et le protocole ALC du RFC 5775. Il est souvent utilisé sur des réseaux avec une capacité garantie, et où on peut donc relativiser les problèmes de congestion. Il n'y a pas d'interface de programmation spécifiée.

Les services de FLUTE sont donc :

  • Transport de fichiers (que FLUTE appelle « objets ») plutôt que d'octets,
  • Fiable (heureusement, pour des fichiers).

Et NORM (NACK-Oriented Reliable Multicast ? Normalisé dans le RFC 5740, il rend à peu près les mêmes services que FLUTE (distribution massive de fichiers). À noter qu'il en existe une mise en œuvre en logiciel libre.

Reste un cas amusant, ICMP. Bien sûr, ICMP n'est pas du tout conçu pour être un protocole de transport, c'est le protocole de signalisation d'IP (RFC 792 pour ICMP sur IPv4 et RFC 4443 pour ICMP sur IPv6). Mais, bon, comme il est situé au-dessus de la couche 3, on peut le voir comme un protocole de transport.

Donc, ICMP est sans connexion, sans fiabilité, et unidirectionnel. Évidemment pas de contrôle de congestion. Pas vraiment d'interface standard, les messages ICMP ne sont signalés qu'indirectement aux applications (dans certains cas, une application peut demander à recevoir les messages ICMP). On ne peut pas tellement s'en servir comme protocole de transport, bien que des programmes comme ptunnel s'en servent presque ainsi.

Après cette longue section 3 qui faisait le tour de tous les protocoles de transport ou assimilés, la section 4 de notre RFC revient sur la question cruciale de la congestion. Sans contrôle de congestion, si chacun émettait comme ça lui chante, l'Internet s'écroulerait vite sous la charge. C'est donc une des tâches essentielles d'un protocole de transport que de fournir ce contrôle de congestion. Pour ceux qui ne le font pas, l'application doit le faire (et c'est très difficile à faire correctement).

À noter que la plupart des protocoles de transport tendent à ce que chaque flot de données utilise autant de capacité disponible que les autres flots. Au contraire, il existe des protocoles « décroissants » comme LEDBAT (RFC 6817) qui cèdent la place aux autres et n'utilise la capacité que lorsque personne n'est en concurrence avec eux.

La section 5 de notre RFC revient sur la notion de fonctions fournies par le protocole de transport, et classe sur un autre axe que la section 3. La section 3 était organisée par protocole et, pour chaque protocole, indiquait quelles étaient ses fonctions. La section 5, au contraire, est organisée par fonction et indique, pour chaque fonction, les valeurs qu'elle peut prendre, et les protocoles qui correspondent. Première catégorie de fonctions, celle du contrôle. Ainsi, une des fonctions de base d'un protocole de transport est l'adressage, celui-ci peut être unicast (TCP, UDP, SCTP, TLS, HTTP), multicast (UDP encore, FLUTE, NORM), broadcast (UDP toujours), anycast (UDP, quoique TCP puisse l'utiliser si on accepte le risque de connexions coupées lorsque le routage change).

Autre fonction, la façon dont se fait l'association entre les deux machines, et elle peut être avec connexion (TCP, SCTP, TLS) ou sans connexion (UDP). La gestion du multi-homing peut être présente (MPTCP, SCTP) ou pas. La signalisation peut être faite avec ICMP ou bien dans le protocole d'application (RTP).

Seconde catégorie de fonctions, la délivrance de données. Première fonction dans cette catégorie, la fiabilité, qui peut être complète (TCP, SCTP, TLS), partielle (RTP, FLUTE, NORM) ou inexistante (UDP, DCCP). Deuxième fonction, la détection d'erreurs, par une somme de contrôle qui couvre toutes les données (TCP, UDP, SCTP, TLS), une partie (UDP-Lite), et qui peut même être optionnelle (UDP en IPv4). Troisième fonction de délivrance, l'ordre des données, qui peut être maintenu (TCP, SCTP, TLS, HTTP, RTP) ou pas (UDP, DCCP, DTLS). Quatrième fonction, le découpage des données : flot sans découpage (TCP, TLS) ou découpage en messages (UDP, DTLS).

Troisième catégorie de fonctions, celles liées au contrôle de la transmission et notamment de la lutte contre la congestion.

Enfin, quatrième et dernière catégorie de fonctions, celles liées à la sécurité : authentification (TLS, DTLS) et confidentialité (les mêmes) notamment.

Voilà, armé de ce RFC, si vous êtes développeurs d'un nouveau protocole applicatif sur Internet, vous pouvez choisir votre protocole de transport sans vous tromper.


Téléchargez le RFC 8095


L'article seul

RFC 8086: GRE-in-UDP Encapsulation

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : L. Yong (Huawei Technologies), E. Crabbe (Oracle), X. Xu (Huawei Technologies), T. Herbert (Facebook)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 9 mars 2017


Le protocole de tunnel GRE, normalisé dans les RFC 2784 et RFC 7676, tourne normalement directement sur IP (numéro de protocole 47, TCP étant 6 et UDP 17). Cela présente quelques inconvénients, notamment la difficulté à passer certaines middleboxes, et ce nouveau RFC propose donc une encapsulation de GRE dans UDP, et non plus directement dans IP. Un des autres avantages de cette encapsulation est que le port source UDP peut être utilisé comme une source d'entropie supplémentaire : sa vérification permet d'améliorer la (faible) sécurité de GRE. GRE sur UDP permet aussi l'utilisation de DTLS si on veut chiffrer (ce que ne fait pas GRE classiquement).

Un autre avantage est que l'encapsulation dans UDP peut améliorer les performances, dans le cas où il y a des répartiteurs de charge ECMP : ils pourront alors faire passer tous les paquets d'un même tunnel GRE par le même chemin, puisqu'ils prennent leurs décisions sur la base du tuple {protocole, adresse IP source, adresse IP destination, port source, port destination}.

Vu du réseau, un tunnel GRE sur UDP sera juste du trafic UDP normal. Attention, toutefois, le trafic UDP sur l'Internet public doit normalement obéir à certaines règles, notamment de contrôle de la congestion (ces règles figurent dans le RFC 8085). Avec TCP, c'est le protocole de transport qui s'en charge, avec UDP, c'est à l'application de le faire. Si on transporte du trafic quelconque, pas spécialement raisonnable, dans un tunnel GRE sur UDP, on viole les règles du RFC 8085. Il faut donc s'assurer que le trafic dans le tunnel a des mécanismes de contrôle de la congestion, ou bien réserver GRE sur UDP à des réseaux fermés, où on prend les risques qu'on veut. (Voir aussi la section 8 de notre RFC.)

Donc, on peut se servir de GRE sur UDP au-dessus d'IPv4 ou d'IPv6 (section 2 du RFC). La somme de contrôle UDP est très recommandée (elle est obligatoire en IPv6). On doit vérifier que le trafic transporté fera attention au contrôle de congestion. Le port source UDP doit être dans la plage des ports éphémères (de 49 152 à 65 535, voir aussi la section 3.2.1). Utiliser un port par flot encapsulé facilite la tâche des équipements comme les répartiteurs de trafic. Mais on peut aussi n'utiliser qu'un seul port pour tout ce qui passe dans le tunnel et, dans ce cas, il faut le choisir de manière imprévisible, pour des raisons de sécurité (RFC 6056). Et en IPv6, merci de penser à utiliser le flow label (RFC 6438).

Le port de destination, lui, est par défaut 4754 pour de l'UDP ordinaire et 4755 pour du DTLS.

Ce protocole GRE sur UDP a eu une histoire longue et compliquée, pris dans des efforts pour fournir des mécanismes génériques d'encapsulation dans UDP (projet GUE), efforts qui n'ont guère débouché (cf. le RFC 7510 pour un autre exemple que GRE).

Voilà, après ces grands principes, le format exact (section 3). Au-dessus de l'en-tête IP (v4 ou v6), on met un en-tête UDP (RFC 768) et un en-tête GRE (RFC 2784).

La section 5 du RFC couvre le cas de DTLS (RFC 6347), qui a l'avantage de donner à GRE les moyens de chiffrer le trafic, sans modifier GRE lui-même.

Évidemment, dans l'Internet réellement existant, le problème, ce sont les middleboxes (section 7 du RFC). C'est d'ailleurs parfois uniquement à cause d'elles qu'il faut utiliser GRE sur UDP et pas GRE tout court, car certaines se permettent de bloquer les protocoles qu'elles ne connaissent pas (typiquement, tout sauf UDP et TCP).

Même en mettant GRE dans UDP, tous les problèmes ne sont pas résolus. Le trafic GRE est unidirectionnel (il y a en fait deux tunnels différents, chacun à sens unique). Il n'y est pas censé avoir des réponses au port source du trafic. Mais certaines middleboxes vont insister pour que ce soit le cas. Une solution possible, pour ces middleboxes pénibles, est de n'utiliser qu'un seul port source.

Il existe des mises en œuvre de ce RFC pour Linux et BSD. Les tests suivants ont été faits sur des machines Linux, noyaux 4.4 et 4.8. ip tunnel ne fournit pas de choix pour « GRE sur UDP ». Il faut passer par le système FOU (Foo-over-UDP, cf. cet article de LWN), qui a l'avantage d'être plus générique :

# modprobe fou      
# lsmod|grep fou
fou                    20480  0
ip_tunnel              28672  1 fou
ip6_udp_tunnel         16384  1 fou
udp_tunnel             16384  1 fou
    

La machine qui va recevoir les paquets doit configurer FOU pour indiquer que les paquets à destination de tel port UDP sont en fait du GRE :

# ip fou add port 4754 ipproto 47

(47 = GRE) La machine émettrice, elle, doit créer une interface GRE encapsulée grâce à FOU :

#  ip link add name tun1 type gre \
          remote $REMOTE local $LOCAL ttl 225 \
          encap fou encap-sport auto encap-dport 4754
# ip link   set tun1 up

Et il faut évidemment configurer une route passant par cette interface tun1, ici pour le préfixe 172.16.0.0/24 :

# ip route add  172.16.0.0/24 dev tun1

Avec cette configuration, lorsque la machine émettrice pingue 172.16.0.1, les paquets arrivent bien sur la machine réceptrice :

    
12:10:40.138768 IP (tos 0x0, ttl 215, id 10633, offset 0, flags [DF], proto UDP (17), length 116)
    172.19.7.106.46517 > 10.17.124.42.4754: [no cksum] UDP, length 88

On peut les examiner plus en détail avec Wireshark :

User Datagram Protocol, Src Port: 1121 (1121), Dst Port: 4754 (4754)
    Source Port: 1121
    Destination Port: 4754
    Length: 96
    Checksum: 0x0000 (none)
        [Good Checksum: False]
        [Bad Checksum: False]
    [Stream index: 0]
Data (88 bytes)

0000  00 00 08 00 45 00 00 54 3e 99 40 00 40 01 ef 6f   ....E..T>.@.@..o
...

Wireshark ne connait apparemment pas le GRE sur UDP. Mais, dans les données, on reconnait bien l'en-tête GRE (les quatre premiers octets où presque tous les bits sont à zéro, le bit C étant nul, les quatre octets suivants optionnels ne sont pas inclus, le 0x800 désigne IPv4, cf. RFC 2784), et on voit un paquet IPv4 ensuite. Pour que ce paquet soit correctement traité par la machine réceptrice, il faut le transmettre à GRE. Comme ce dernier n'a pas de mécanisme permettant de mettre plusieurs tunnels sur une même machine (l'en-tête GRE n'inclut pas d'identificateurs), il faut activer l'unique interface GRE :

# ip link set gre0 up   

On voit bien alors notre ping qui arrive :

# tcpdump -vv -n -i gre0                                         
tcpdump: listening on gre0, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
14:02:06.922367 IP (tos 0x0, ttl 64, id 47453, offset 0, flags [DF], proto ICMP (1), length 84)
    10.10.86.133 > 172.16.0.1: ICMP echo request, id 13947, seq 17, length 64

Voilà, je vous laisse faire la configuration en sens inverse.

Si vous voulez en savoir plus sur la mise en œuvre de FOU, voyez cet excellent exposé d'un des auteurs, Tom Herbert, cet article du même, et enfin sa vidéo.


Téléchargez le RFC 8086


L'article seul

RFC 8085: UDP Usage Guidelines

Date de publication du RFC : Mars 2017
Auteur(s) du RFC : L. Eggert (NetApp), G. Fairhurst (University of Aberdeen), G. Shepherd (Cisco Systems)
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 9 mars 2017


La grande majorité des applications Internet tourne sur le protocole de transport TCP. Mais son concurrent UDP, normalisé dans le RFC 768, prend de l'importance avec le multimédia et les jeux en ligne pour lesquels il est souvent bien adapté. Contrairement à TCP, UDP ne fournit aucun mécanisme de contrôle de la congestion. C'est donc aux applications de fournir ce contrôle, suivant les règles expliquées par ce RFC. (Qui parle surtout de congestion mais aussi d'autres sujets importants pour ceux qui utilisent UDP, comme la taille des messages ou comme les sommes de contrôle.) Il remplace le RFC 5405.

UDP est apprécié pour certaines applications car il est simple et léger et le fait qu'il ne garantisse pas l'acheminement de la totalité des paquets n'est pas forcément un problème dans les applications multimédia : si on perd quelques secondes d'une communication téléphonique RTP, il vaut mieux passer à la suite que de perdre du temps à la retransmettre comme le ferait TCP. Mais UDP ne fournit pas non plus de contrôle de la congestion. Une application UDP enthousiaste peut envoyer des paquets au débit maximum permis, saturant tous les liens situés en aval. (Il ne faut pas juste tenir compte de la capacité du lien auquel on est connecté, mais de celle du chemin complet. L'exemple du RFC, avec un chemin à seulement 56 kb/s, que cinq paquets UDP de 1 500 octets par seconde saturent, n'est pas invraisemblable.) Protéger le réseau de la congestion est pourtant nécessaire (RFC 2914 et RFC 7567), à la fois pour assurer que le réseau continue à être utilisable et également pour assurer une certaine équité entre les différents flux de données, pour éviter qu'une seule application gourmande ne monopolise le réseau pour elle. (Ceci concerne l'Internet public. Si on est dans un environnement fermé, utilisant TCP/IP mais où la capacité réseau, et son usage, sont contrôlés, le problème est évidemment différent. Voir notamment la section 3.6.)

UDP ne faisant pas ce contrôle de congestion, il faut bien que l'application le fasse et, pour cela, qu'elle mette en œuvre les conseils de ce RFC. (Notre RFC contient également des conseils pour d'autres aspects de l'utilisation d'UDP que le contrôle de congestion : mais c'est le plus important.)

Le gros du RFC est dans la section 3 qui détaille ces conseils (la section 7 contient un excellent résumé sous forme d'un tableau des conseils à suivre). Le premier est qu'il vaut peut-être mieux ne pas utiliser UDP. Beaucoup de développeurs d'applications pensent à UDP en premier parce qu'il est simple et facile à comprendre et qu'il est « plus rapide que TCP ». Mais, rapidement, ces développeurs se rendent compte qu'ils ont besoin de telle fonction de TCP, puis de telle autre, ils les mettent en œuvre dans leur application et arrivent à une sorte de TCP en moins bien, d'avantage bogué et pas plus rapide. Notre RFC conseille donc d'abord de penser aux autres protocoles de transport comme TCP (RFC 793), DCCP (RFC 4340) ou SCTP (RFC 4960). Ces protocoles sont d'autant plus intéressants qu'ils ont souvent fait l'objet de réglages soigneux depuis de nombreuses années et qu'il est donc difficile à un nouveau programme de faire mieux. D'autant plus qu'il existe souvent des réglages spécifiques pour les adapter à un usage donné. Par exemple, on peut dire à TCP de donner la priorité à la latence (paramètre TCP_NODELAY de setsockopt) ou bien au débit.

Si on ne suit pas ces sages conseils, et qu'on tient à se servir d'UDP, que doit-on faire pour l'utiliser intelligemment ? La section 3.1 couvre le gros morceau, le contrôle de congestion. Celui-ci doit être pris en compte dès la conception de l'application. Si cette dernière fait de gros transferts de données (section 3.1.2, c'est le cas de RTP, RFC 3550), elle doit mettre en œuvre TFRC, tel que spécifié dans le RFC 5348, donc faire à peu près le même travail que TCP. Et ce mécanisme doit être activé par défaut.

Si l'application transmet peu de données (section 3.1.3), elle doit quand même faire attention et le RFC demande pas plus d'un datagramme par RTT, où le RTT est un cycle aller-retour avec la machine distante (si le calcul n'est pas possible, le RFC demande une durée de trois secondes). L'application doit également détecter les pertes de paquet pour ralentir son rythme si ces pertes - signe de congestion - sont trop fréquentes.

Si l'application est bi-directionnelle (le cas de loin le plus fréquent), le contrôle de la congestion doit se faire indépendamment dans les deux directions.

Notez que se retenir d'envoyer des paquets n'est pas le seul moyen pour une application d'éviter la congestion. Elle peut aussi (si l'API utilisée le permet) se servir d'ECN (RFC 3168) pour transmettre l'information qui permettra de réguler le trafic.

Enfin, le RFC demande (section 3.1.10) un mécanisme de « disjoncteur » (circuit breaker, cf. RFC 8084 ou bien RFC 8083 pour l'exemple spécifique de RTP). C'est un mécanisme de dernier recours pour couper la communication en cas de risque d'effondrement du réseau.

Le cas où l'application est un tunnel au-dessus d'UDP est également couvert (section 3.1.11). C'est par exemple le cas du protocole GRE quand il tourne sur UDP (RFC 8086).

En suivant toutes ces règles, l'application gère proprement la congestion. Et le reste ? La section 3.2 fournit des pistes sur la gestion de la taille des paquets. La charge utile d'un paquet UDP peut théoriquement faire 65 507 octets en IPv4 et 65 527 en IPv6. Mais c'est théorique. En pratique, la fragmentation marche mal sur l'Internet, et notre RFC conseille de rester en dessous de la MTU, et d'utiliser la découverte de la MTU du chemin spécifiée dans des RFC comme le RFC 4821. (Aujourd'hui, la principale application qui envoie des paquets UDP plus gros que la MTU, et doit donc se battre avec la fragmentation, est le DNS ; voir par exemple l'étude de Geoff Huston sur les comportements très variés des serveurs de la racine.)

La section 3.3 explique la question de la fiabilité : par défaut, UDP ne retransmet pas les paquets perdus. Si c'est nécessaire, c'est l'application qui doit le faire. Elle doit aussi gérer l'eventuelle duplication des paquets (qu'UDP n'empêche pas). Le RFC note que les retards des paquets peuvent être très importants (jusqu'à deux minutes, normalise le RFC, ce qui me semble très exagéré pour l'Internet) et que l'application doit donc gérer le cas où un paquet arrive alors qu'elle croyait la session finie depuis longtemps.

La section 3.4 précise l'utilisation des sommes de contrôle (facultatives pour UDP sur IPv4 mais qui devraient être utilisées systématiquement). Si une somme de contrôle pour tout le paquet semble excessive, et qu'on veut protéger uniquement les en-têtes de l'application, une bonne alternative est UDP-Lite (RFC 3828), décrit dans la section 3.4.2. (Il y a aussi des exceptions à la règle « somme de contrôle obligatoire en IPv6 » dans le cas de tunnels.)

Beaucoup de parcours sur l'Internet sont encombrés de « middleboxes », ces engins intermédiaires qui assurent diverses fonctions (NAT, coupe-feu, etc) et qui sont souvent de médiocre qualité logicielle, bricolages programmés par un inconnu et jamais testés. La section 3.5 spécifie les règles que devraient suivre les applications UDP pour passer au travers sans trop de heurts. Notamment, beaucoup de ces « middleboxes » doivent maintenir un état par flux qui les traverse. En TCP, il est relativement facile de détecter le début et la fin d'un flux en observant les paquets d'établissement (SYN) et de destruction (FIN) de la connexion. En UDP, ces paquets n'ont pas d'équivalent et la détection d'un flux repose en général sur des heuristiques. L'engin peut donc se tromper et mettre fin à un flux qui n'était en fait pas terminé. Si le DNS s'en tire en général (c'est un simple protocole requête-réponse, avec la lupart du temps moins d'une seconde entre l'une et l'autre), d'autres protocoles basés sur UDP pourraient avoir de mauvaises surprises. Ces protocoles doivent donc se préparer à de soudaines interruptions de la communication, si le timeout d'un engin intermédiaire a expiré alors qu'il y avait encore des paquets à envoyer. (La solution des keepalives est déconseillée par le RFC car elle consomme de la capacité du réseau et ne dispense pas de gérer les coupures, qui se produiront de toute façon.)

La section 5 fera le bonheur des programmeurs qui y trouveront des conseils pour mettre en œuvre les principes de ce RFC, via l'API des prises (sockets, RFC 3493). Elle est largement documentée mais en général plutôt pour TCP que pour UDP, d'où l'intérêt du résumé qu'offre ce RFC, qui ne dispense évidemment pas de lire le Stevens. Par exemple, en l'absence de mécanisme de TIME_WAIT (la prise reste à attendre d'éventuels paquets retardés, même après sa fermeture par l'application), une application UDP peut ouvrir une prise... et recevoir immédiatement des paquets qu'elle n'avait pas prévus, qui viennent d'une exécution précédente.

Le RFC détaille également la bonne stratégie à utiliser pour les ports. Il existe un registre des noms et numéros de ports (RFC 6335), et le RFC 7605 explique comment utiliser les ports. Notre RFC conseille notamment de vérifier les ports des paquets reçus, entre autre pour se protéger de certaines attaques, où l'attaquant, qui ne peut pas observer le trafic et doit injecter des paquets aveuglément, ne connait pas les ports utilisés (en tout cas pas les deux). L'application devrait utiliser un port imprévisible, comme le fait TCP (RFC 6056). Pour avoir suffisamment d'entropie pour les répartiteurs de charge, le RFC rappelle qu'en IPv6, on peut utiliser le champ flow label (RFC 6437 et RFC 6438).

Le protocole ICMP fournit une aide utile, que les applications UDP peuvent utiliser (section 5.2). Mais attention, certains messages ICMP peuvent refléter des erreurs temporaires (absence de route, par exemple) et ne devraient pas entraîner de mesures trop drastiques. Autre piège, il est trivial d'envoyer des faux paquets ICMP. Une application doit donc essayer de déterminer, en examinant le contenu du message ICMP, s'il est authentique. Cela nécessite de garder un état des communications en cours, ce que TCP fait automatiquement mais qui, pour UDP, doit être géré par l'application. Enfin, il faut se rappeler que pas mal de middleboxes filtrent stupidement l'ICMP et l'application doit donc être prête à se débrouiller sans ces messages.

Après tous ces conseils, la section 6 est dédiée aux questions de sécurité. Comme TCP ou SCTP, UDP ne fournit en soi aucun mécanisme d'intégrité des données ou de confidentialité. Pire, il ne fournit même pas d'authentification de l'adresse IP source (authentification fournie, avec TCP, par le fait que, pour établir la connexion, il faut recevoir les réponses de l'autre). Cela permet, par exemple, les injections de faux trafic (contre lesquelles il est recommandé d'utiliser des ports source imprévisibles, comme le fait le DNS), ou bien les attaques par amplification.

L'application doit-elle mettre en œvre la sécurité seule ? Le RFC conseille plutôt de s'appuyer sur des protocoles existants comme IPsec (RFC 4301, dont notre RFC note qu'il est très peu déployé) ou DTLS (RFC 6347). En effet, encore plus que les protocoles de gestion de la congestion, ceux en charge de la sécurité sont très complexes et il est facile de se tromper. Il vaut donc mieux s'appuyer sur un système existant plutôt que d'avoir l'hubris et de croire qu'on peut faire mieux que ces protocoles ciselés depuis des années.

Pour authentifier, il existe non seulement IPsec et DTLS mais également d'autres mécanismes dans des cas particuliers. Par exemple, si les deux machines doivent être sur le même lien (un cas assez courant), on peut utiliser GTSM (RFC 3682) pour s'en assurer.

Enfin, notre RFC se termine (section 7) par un tableau qui synthétise les recommandations, indiquant à chaque fois la section du RFC où cette recommandation est développée. Développeu·r·se d'applications utilisant UDP, si tu ne lis qu'une seule section du RFC, cela doit être celle-ci !

Quels changements depuis le RFC précédent, le RFC 5405 ? Le fond des recommandations reste le même, la principale addition est celle de nombreuses recommandations spécifiques au multicast (dont je n'ai pas parlé ici) mais aussi à l'anycast, aux disjoncteurs, et aux tunnels. Il y a également l'introduction d'une différence entre l'Internet public (où il se faut se comporter en bon citoyen) et des réseaux privés et fermés utilisant les mêmes protocoles, mais où on a droit à des pratiques qui seraient jugées anti-sociales sur l'Internet public (comme d'envoyer des paquets sans tenir compte de la congestion). Ce RFC est donc bien plus long que son prédécesseur.


Téléchargez le RFC 8085


L'article seul

RFC 8094: DNS over Datagram Transport Layer Security (DTLS)

Date de publication du RFC : Février 2017
Auteur(s) du RFC : T. Reddy (Cisco), D. Wing, P. Patil (Cisco)
Expérimental
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 2 mars 2017


Le DNS fonctionne traditionnellement surtout sur UDP, notamment pour minimiser la latence : quand on veut une réponse DNS, on la veut rapidement. Dans le cadre du projet « DNS et vie privée », le choix avait été fait de chiffrer le trafic DNS avec TLS (RFC 7858), imposant ainsi l'usage de TCP. Certains pensaient quand même qu'UDP était bien adapté au DNS et, puisqu'il existe une version de TLS adaptée à UDP, DTLS, ce serait une bonne idée de l'utiliser pour chiffrer le DNS. C'est ce que décrit ce nouveau RFC (qui ne semble pas avoir un avenir brillant, peu de gens sont intéressés).

De toute façon, il est très possible que le DNS utilise de plus en plus TCP, et le RFC 7766 allait dans ce sens, demandant davantage de la part des mises en œuvre de DNS sur TCP. Mais, bon, il est toujours bon d'essayer des alternatives, d'où ce RFC, dans l'état « Expérimental ». Outre les RFC déjà cités, il est recommandé, avant de le lire, de prendre connaissance du RFC 7626, qui décrit les problèmes de vie privée que pose le DNS, et le RFC 6347, qui normalise DTLS (bien moins connu que son copain TLS, et peu utilisé jusqu'à présent, à part pour WebRTC).

Les motivations pour explorer une alternative au DNS-sur-TLS du RFC 7858 sont :

  • TCP souffre du « head of line blocking » où la perte d'un seul paquet empêche de recevoir tous ceux qui suivent, même s'ils sont bien arrivés, tant que le paquet perdu n'est pas retransmis. DNS-sur-DTLS sera donc peut-être meilleur sur des réseaux qui perdent pas mal de paquets.
  • Dans certaines conditions, l'établissement d'une session est plus rapide avec DTLS qu'avec TLS. (Rappelez-vous toutefois que le RFC 7766 exige des sessions TCP persistentes : pas question d'établir une session par requête DNS !) Reprendre une session TLS peut ne prendre qu'un aller-retour avec DTLS, alors que TLS devra attendre l'établissement de la connexion TCP (le RFC 7413 changera peut-être les choses, mais TLS et DTLS 1.3 obligeront également à réviser ce raisonnement.)

De même qu'un serveur et un client DNS ne peuvent pas se contenter d'UDP (pour pouvoir envoyer des données de grande taille, il faudra de toute façon passer à TCP), DNS-sur-DTLS ne peut pas suffire seul, et il faudra donc que les clients et serveurs aient également DNS-sur-TLS.

La spécification de DNS-sur-DTLS est dans la section 3 de notre RFC. DNS-sur-DTLS va tourner, comme DNS-sur-TLS, sur le port 853 (sauf accord préalable entre client et serveur, s'ils sont adultes et consentants). Un client peut déterminer si le serveur gère DNS-sur-DTLS en envoyant un message DTLS ClientHello vers le port 853. En l'absence de réponse, le client réessaie, puis laisse tomber DTLS. Selon sa configuration (plus ou moins paranoïaque), le client va alors tenter le DNS habituel en clair, ou bien complètement renoncer. En tout cas, interdiction d'utiliser le port 853 pour transmettre des messages DNS en clair. L'utilisation de ce port sur UDP implique DTLS.

Si, par contre, le serveur répond et qu'une session DTLS est établie, le client DNS-sur-DTLS authentifie le serveur avec les mêmes méthodes que pour TLS, en suivant les bonnes pratiques de sécurité de TLS (RFC 7525) et les profils d'authentification de DNS-sur-TLS décrits dans un futur RFC (quasiment terminé, à l'heure où j'écris). Une fois que tout cela est fait, les requêtes et réponses DNS sont protégées et les surveillants sont bien embêtés, ce qui était le but.

DTLS tourne sur UDP et reprend sa sémantique. Notamment, il est parfaitement normal qu'une réponse arrive avant une autre, même partie plus tôt. Le client DNS-sur-DTLS ne doit donc pas s'étonner et, pour faire correspondre les requêtes et les réponses, il doit, comme avec le DNS classique sur UDP, utiliser le Query ID ainsi que la question posée (qui est répétée dans les réponses, dans la section Question).

Pour ne pas écrouler le serveur sous la charge, le client ne devrait créer qu'une seule session DTLS vers chaque serveur auquel il parle, et y faire passer tous les paquets. S'il y a peu de requêtes, et que le client se demande si le serveur est toujours là, il peut utiliser l'extension TLS du « battement de cœur » (RFC 6520), qui peut également servir à rafraichir l'état d'un routeur NAT éventuel. Le RFC recommande aux serveurs DNS-sur-DTLS un délai d'au moins une seconde en cas d'inutilisation de la session, avant de raccrocher. Le problème est délicat : si ce délai est trop long, le serveur va garder des ressources inutiles, s'il est trop court, il obligera à refaire le travail d'établissement de session trop souvent. En tout cas, le client doit être prêt à ce que le serveur ait détruit la session unilatéralement, et doit la réétablir s'il reçoit l'alerte DTLS qui lui indique que sa session n'existe plus.

Un petit mot sur les performances, maintenant, puisque rappelons-nous que le DNS doit aller vite (section 4). L'établissement d'une session DTLS peut nécessiter d'envoyer des certificats, qui sont assez gros et peuvent nécessiter plusieurs paquets. Il peut donc être utile d'utiliser les clés brutes (pas de certificat) du RFC 7250, ou bien l'extension TLS Cached Information Extension (RFC 7924).

Dans le cas d'un lien stub resolver vers résolveur, le serveur DNS parle à beaucoup de clients, chaque client ne parle qu'à très peu de serveurs. L'état décrivant les sessions DTLS doit donc plutôt être gardé chez le client (RFC 5077). Cela permettra de réétablir les sessions DTLS rapidement, sans pour autant garder d'état sur le serveur.

Le DNS est la principale application qui se tape les problèmes de PMTU (Path MTU, la MTU du chemin complet). Les réponses DNS peuvent dépasser les 1 500 octets magiques (la MTU d'Ethernet et, de facto, la PMTU de l'Internet). DTLS ajoute au moins 13 octets à chaque paquet, sans compter l'effet du chiffrement. Il est donc impératif (section 5) que clients et serveurs DNS-sur-DTLS gèrent EDNS (RFC 6891) pour ne pas être limité par l'ancien maximum DNS de 512 octets, et que les serveurs limitent les paquets DTLS à la PMTU (RFC 6347).

Contrairement au DNS classique, où chaque requête est indépendante, toute solution de cryptographie va nécessiter un état, l'ensemble des paramètres cryptographiques de la session. L'anycast, qui est répandu pour le DNS, ne pose donc pas de problème au DNS classique : si le routage change d'avis entre deux requêtes, et que la seconde requête est envoyée à un autre serveur, aucun problème. Avec DTLS, ce n'est plus le cas (section 6 du RFC) : le deuxième serveur n'a pas en mémoire la session cryptographique utilisée. Le serveur qui la reçoit va répondre avec une alerte TLS fatale (la méthode recommandée) ou, pire, ne pas répondre. Dans les deux cas, le client doit détecter le problème et réétablir une session cryptographique. (À noter que l'alerte TLS n'est pas authentifiée et ne peut donc pas être utilisée comme seule indication du problème. C'est d'ailleurs pareil pour d'éventuels messages d'erreur ICMP.) Le cas est donc proche de celui où le serveur ferme la session unilatéralement, et la solution est la même : le client doit toujours être prêt à recommencer l'ouverture de session DTLS.

Un point de sécurité, pour finir (section 9). Le RFC recommande l'utilisation de l'extension TLS « agrafage OCSP » (RFC 6066, section 8), notamment pour éviter la grosse fuite d'information que représente OCSP.

Il n'existe aucune mise en œuvre de DNS-sur-DTLS, et aucune n'est prévue. L'avenir de cette expérimentation est... incertain, à moins qu'un·e courageu·x·se développeu·r·se ne s'y mette ?


Téléchargez le RFC 8094


L'article seul

Articles des différentes années : 2017  2016  2015  2014  2013  2012  2011  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.