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 8198: Aggressive Use of DNSSEC-Validated Cache

Date de publication du RFC : Juillet 2017
Auteur(s) du RFC : K. Fujiwara (JPRS), A. Kato (Keio/WIDE), W. Kumari (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 26 juillet 2017


Lorqu'un client DNS interroge un résolveur, celui-ci peut répondre très vite si l'information demandée est dans sa mémoire (son « cache ») mais cela peut être beaucoup plus lent s'il faut aller demander aux serveurs faisant autorité. Il est donc essentiel, pour les performances du DNS, d'utiliser le cache le plus possible. Traditionnellement, le résolveur n'utilisait le cache que si la question posée par le client avait une réponse exacte dans le cache. Mais l'arrivée de DNSSEC autorise un usage plus énergique et plus efficace du cache : ce nouveau RFC permet aux résolveurs de synthétiser des réponses à partir des informations DNSSEC.

Comment peut-il faire ? Eh bien prenons par exemple les enregistrements NSEC. Ils indiquent une plage où il n'y a pas de noms enregistrés. Ainsi, si une zone example.com contient :

albatross IN AAAA 2001:db8:1028::a:1
elephant  IN AAAA 2001:db8:1028::a:2
zebra     IN AAAA 2001:db8:1028::a:3
    

Sa signature DNSSEC va ajouter des enregistrements NSEC, notamment :

albatross.example.com. IN NSEC elephant.example.com. AAAA    

qui veut dire qu'il n'y a pas de nom entre albatross et elephant. Si le client interroge le résolveur à propos de cat.example.com, le résolveur ira voir les serveurs faisant autorité, il aura une réponse négative (NXDOMAIN, ce nom n'existe pas) et l'enregistrement NSEC. Les deux informations seront renvoyées au client, et pourront être mémorisées dans le cache. Maintenant, si le client demande dog.example.com, les résolveurs traditionnels retourneront demander aux serveurs faisant autorité. Alors que les résolveurs modernes, conformes à ce nouveau RFC 8198, pourront déduire du NSEC que dog.example.com n'existe pas non plus, et immédiatement générer un NXDOMAIN pour le client. Cela fera gagner du temps et des efforts à tout le monde. (Les règles exactes sont dans la section 5.1 de notre RFC.)

La règle (désormais dépassée) comme quoi le résolveur ne peut répondre immédiatement que s'il a l'information correspondant à la question exacte est spécifiée dans le RFC 2308, pour le cache négatif (mémoriser les réponses NXDOMAIN). Désormais, elle n'est plus obligatoire si (et seulement si, voir section 9) le résolveur valide avec DNSSEC, et si la zone est signée (aucun changement si elle ne l'est pas). Outre le cas simple de NSEC avec des réponses négatives, présenté plus haut, il y a deux cas plus complexes, les enregistrements NSEC3, et les jokers. Si la zone est signée avec NSEC3 au lieu de NSEC, les enregistrements NSEC3 indiqueront des condensats et pas des noms et le résolveur devra donc condenser le nom demandé, pour voir s'il tombe dans un NSEC3 connu, et si on peut synthétiser le NXDOMAIN. Les règles exactes sur les NSEC3 sont dans le RFC 5155 (attention, c'est compliqué), sections 8.4 à 8.7, et dans notre RFC, section 5.2. Évidemment, si la zone est signée avec l'option « opt-out » (c'est le cas de la plupart des TLD), le résolveur ne peut pas être sûr qu'il n'y a pas un nom non signé dans une plage indiquée par un enregistrement NSEC, et ne peut donc pas synthétiser. Tout aussi évidemment, toute solution qui empêchera réellement l'énumération des noms dans une zone signée (comme le projet NSEC5) sera incompatible avec cette solution.

Si la zone inclut des jokers (RFC 1034, section 4.3.3), par exemple example.org :

    
avocado   IN A 192.0.2.1
*         IN A 192.0.2.2
zucchini IN A 192.0.2.3

Alors, le résolveur pourra également synthétiser des réponses positives. S'il a déjà récupéré et mémorisé le joker, et que le client lui demande l'adresse IPv4 de leek.example.org, le résolveur pourra tout de suite répondre 192.0.2.2. (J'ai simplifié : le résolveur doit aussi vérifier que le nom leek.example.org n'existe pas, ou en tout cas n'a pas d'enregistrement A. Le joker ne masque en effet pas les noms existants. Détails en section 5.3 du RFC.)

Pour cette utilisation plus énergique de la mémoire d'un résolveur validant, il a fallu amender légèrement le RFC 4035, dont la section 4.5 ne permettait pas cette synthèse de réponses (la nouvelle rédaction est en section 7). Notez un inconvénient potentiel de cette synthèse : un nom ajouté ne sera pas visible tout de suite. Mais c'est de toute façon une propriété générale du DNS et de ses caches souvent appelée, par erreur, « durée de propagation ».

La durée exacte pendant laquelle le résolveur « énergique » pourra garder les informations qui lui servent à la synthèse des réponses est donnée par le TTL des NSEC.

Quel intérêt à cette synthèse énergique de réponses ? Comme indiqué plus haut, cela permet de diminuer le temps de réponse (section 6). Du fait de la diminution de nombre de questions à transmettre, cela se traduira également par une diminution de la charge, et du résolveur, et du serveur faisant autorité. Sur la racine du DNS, comme 65 % des requêtes entrainent un NXDOMAIN (voir par exemple les statistiques de A-root), le gain devrait être important. Un autre avantage sera pour la lutte contre les attaques dites « random QNAMEs » lorsque l'attaquant envoie plein de requêtes pour des noms aléatoires (générant donc des NXDOMAIN). Si l'attaquant passe par un résolveur, celui-ci pourra écluser la grande majorité des requêtes sans déranger le serveur faisant autorité.

Mais la synthèse énergique entraine aussi un gain en matière de vie privée (cf. RFC 7626) : les serveurs faisant autorité verront encore moins de questions.

Cette technique de « cache négatif énergique » avait été proposée pour la première fois dans la section 6 du RFC 5074. Elle s'inscrit dans une série de propositions visant à augmenter l'efficacité des caches DNS, comme le « NXDOMAIN cut » du RFC 8020. La synthèse énergique de réponses prolonge le RFC 8020, en allant plus loin (mais elle nécessite DNSSEC).

Il semble que Google Public DNS mette déjà en œuvre une partie (les réponses négatives) de ce RFC, mais je n'ai pas encore vérifié personnellement.


Téléchargez le RFC 8198


L'article seul

Conférence climagic sur la ligne de commande et ses beautés

Première rédaction de cet article le 20 juillet 2017


Le 19 juillet 2017, à Prague, Mark Krenz, le fondateur et animateur du fameux compte Twitter climagic (Command-Line interface magic), profitait de ses vacances en Europe pour faire un exposé sur la ligne de commande, ses beautés, et le projet climagic. Ça m'a fait rater la séance plénière de l'IETF 99 mais ça valait la peine. (Pour ce·ux·lles qui n'étaient pas à Prague, les pauvres, l'exposé est visible chez Google.)

L'exposé se tenait à la ČVUT (excellents locaux, vue magnifique sur la ville depuis le 14e étage). La grande salle était presque pleine. Comme on s'en doute, il n'y avait que trois ou quatre femmes.

La thèse centrale de Mark Krenz est que la ligne de commande n'est pas une survivance du passé, qu'on garde par habitude, ou par nostalgie. C'est toujours un outil puissant et efficace pour les professionnels (comme un de ses enfants lui avait dit une fois, lorsque le réseau était en panne, « open the black window and type text, to fix the network »). Le concept n'est en outre pas spécifique à Unix, Mark Krenz a cité l'ARexx d'Amiga. Une des preuves de cette pertinence de la ligne de commande est que désormais même Windows a une ligne de commandes de qualité raisonnable, Powershell. L'orateur a ensuite illustré ce point de vue de nombreux exemples.

Prévoyant que l'unixien moyen était pinailleur, il a prévenu tout de suite que c'était ses exemples, qu'il y avait plusieurs façons de faire, et que ce n'était pas la peine de lui dire que tel exemple aurait pu être fait avec telle autre méthode. Il a aussi précisé que la référence pour ses tweets était Linux avec bash (même s'il teste parfois sur une VM FreeBSD) et qu'il ne fallait pas l'embêter avec des « mais c'est pas portable ». Effectivement, il utilise des exemples comme la commande interne help (specifique à bash) ou comme l'excellente et indispensable option -i de sed (spécifique à GNU sed).

Mark Krenz (qui travaille au CACR et est l'auteur des excellents num-utils) a d'abord résumé le projet climagic. Démarré en 2009, il consiste en un compte Twitter (il y a aussi des vidéos) où environ la moitié des tweets sont des commandes Unix. Elles sont en général sous le format commande # description (le croisillon indiquant un commentaire). Par exemple :

killall -USR1 dd # Force each dd command in the process table to output its current status (blocks written, etc). The USR1 signal does this.
    

(lisez les documentations de killall et dd si nécessaire.) Les autres tweets sont diverses réflexions, ou des blagues, par exemple sur Chuck Norris (« Chuck Norris once ran cd .. in / and it worked »).

Ah, et pourquoi le magic dans « climagic ». Précisement parce que cela n'a rien de magique, tout peut être appris. « Witchcraft to the ignorant, simple science for the learned one » (Leigh Brackett).

La force du shell Unix est évidemment sa capacité à combiner des commandes pour faire davantage que ce que ferait chaque commande individuelle. Donc, lister des commandes et des options, c'est bien, mais il faut surtout se rappeler qu'on peut les combiner. Un exemple montré par l'auteur est une commande qui énonce à voix haute les réseaux Wi-Fi rencontrés : wlist wlp2s0 scan | awk -F: '/ESSID/ {print $2}' | sort|uniq | espeak.

Je ne vais pas citer tous les trucs Unix qu'a montré l'orateur, uniquement ceux que je ne connaissais pas. Vous pourrez ainsi juger de la profondeur de mon ignorance d'Unix :

  • Je n'utilise pas les opérateurs rigolos après les noms de variables du shell. Si ALPHABET vaut les lettres de l'alphabet (par exemple en faisant ALPHABET=$(echo {a..z} | tr -d ' '), alors echo ${ALPHABET:0:3} affichera les trois premières, et echo ${ALPHABET^^} affichera leurs versions majuscules (bash seulement).
  • Je ne connaissais pas certaines variables spéciales comme SHLVL (pour voir si on est dans un sous-shell), ou COLUMNS (qui était inutile sur un VT100 mais bien pratique sur un xterm).
  • J'ai découvert qu'après more et less, il y avait désormais une commande most (pas mal pour les fichiers binaires).
  • column est cool pour formater joliment des commandes qui ne le font pas elle-même (comme mount).
  • Il y a d'autres commandes que je ne connaissais pas mais qui ne m'ont pas convaincu comme comm, ou pee (analogue à tee mais envoie les données à un processus, pas à un fichier, il se trouve dans les moreutils).
  • Certaines commandes classiques donnent des résultats inattendus dans certains cas. Par exemple cal 9 1752. Si vous vous demandez ce que sont devenus ces treize jours, ils ont disparu suite à l'application de la réforme grégorienne à l'empire britannique (les pays catholiques l'ont fait longtemps avant, ce dont on peut déduire qu'Unix n'est pas catholique). Comme tous les pays n'ont pas adopté cette réforme au même moment, logiquement, le résultat devrait dépendre de la valeur de la variable d'environnement LC_CTIME mais ce n'est hélas pas le cas.
  • Je ne savais pas non plus que la barre oblique après un joker ne renvoyait que les répertoires. Parfait pour un du -sh */ (au fait, GNU sort peut trier ces tailles « human-readables », avec -h : du -sh */ | sort -rh | head -5 permet de voir les cinq plus gros répertoires, avec un joli affichage des tailles.)
  • Parmi les autres options pratiques, -P dit à xargs d'effectuer les commandes en parallèle (comme le -j de make). Cela a permis à l'orateur de montrer un fping refait avec un ping ordinaire, l'expansion des séquences, et xargs.

Lors de la discussion qui a suivi, j'ai soulevé la question d'Unicode dans le shell Unix. Certaines commandes gèrent bien Unicode, par exemple awk :

%  echo -n café | awk '{print length($1)}'
4
    

Il a bien indiqué la longueur en caractères, pas en octets (« café » fait cinq octets en UTF-8). wc, lui, permet d'avoir caractères ou octets au choix :

% echo -n café | wc -m
4
% echo -n café | wc -c
5      
    

Cela montre que, même si le shell a la réputation d'être un vieux truc, il a su s'adapter à la modernité. Mais ce n'est pas le cas de toutes les commandes Unix. Au moins sur mon Ubuntu (il parait que ça marche sur d'autres Unix), cut semble insensible à l'internationalisation (il affiche les octets bêtement, malgré ce que prétend sa documentation) :

% echo caféthé | cut -c 3
f
% echo caféthé | cut -c 4
�
% echo caféthé | cut -c 5
�
% echo caféthé | cut -c 6     
    

De même, l'expansion par le shell ne semble pas marcher avec les caractères non-ASCII :

% echo {a..c}
a b c
% echo {à..ç}
{à..ç}
    

(Et, oui, la variable d'environnement LC_CTYPE était bien définie, sinon, grep ou wc n'auraient pas marché.)

M. climagic a évidemment parlé de plein d'autres choses, mais je les connaissais. Et vous ?

  • Il a bien sûr cité man et ses options. Notez que man -k delete ne trouve pas la commande rm
  • Il a longuement parlé de nombreux trucs du shell comme les astuces de la commande cd (cd - vous ramène au dernier répertoire), le job control (Control-Z, fg et bg), l'expansion des intervalles (echo {a..z}, echo IMG_{3200..3300}.jpg, qui permet de faire un rsync -a -v IMG_{3200..3300}.jpg server:dir…, les fonctions (le plus bel exemple était une redéfinition de cd, pour accepter l'argument ... pour dire « remonte de deux niveaux » : function cd(){ [[ "$1" == "..." ]] && builtin cd ../.. || builtin cd $@}, la redirection des seules erreurs (command 2> file), etc.
  • Mark Krenz a évidemment consacré du temps à awk et sed (tiens, lui non plus n'a pas l'air de gérer Unicode).
  • Et enfin il a parlé de deux programmes géniaux qui méritent d'être plus connus, ngrep (comme grep mais pour le réseau), et socat (netcat en mieux).

Autre discussion à la fin de la réunion, je lui ai demandé pourquoi ne pas avoir également climagic sur le réseau social décentralisé Mastodon. Il n'est pas contre (surtout si on peut le faire depuis la ligne de commande, bien sûr, mais c'est possible avec madonctl), c'est surtout un problème de manque de temps. (À noter que climagic a existé sur identi.ca mais que cela ne lui a pas laissé de bons souvenirs.)

La vue depuis l'université : prague-from-tu.jpg

Le panneau sur la salle de réunion : climagic-room.jpg


L'article seul

RFC 8197: A SIP Response Code for Unwanted Calls

Date de publication du RFC : Juillet 2017
Auteur(s) du RFC : H. Schulzrinne (FCC)
Chemin des normes
Première rédaction de cet article le 18 juillet 2017


Voici un RFC qui n'est pas trop long à lire ou à comprendre : il ajoute un code de réponse au protocole SIP (utilisé surtout pour la téléphonie sur IP), le code 607 qui dit explicitement « je n'ai pas envie de répondre à cet appel ».

Sur certaines lignes téléphoniques, la majorité des appels entrants sont du spam (cf. RFC 5039), du genre salons de beauté ou remplacements de fenêtres, voire appels automatiques en faveur d'un candidat politicien. Toute méthode de lutte contre ce spam nécessite d'avoir un retour des utilisateurs, qui déclarent « je ne veux pas de cet appel ». Simplement raccrocher ne suffit pas, il faut permettre à l'utilisateur de déclarer explicitement la spamicité d'un appel. (Les codes de rejet existants comme 603 - RFC 3261, section 21.6.2 - ne sont pas assez spécifiques. 603 indique typiquement un rejet temporaire, du genre je suis à table, ne me dérangez pas maintenant.)

C'est désormais possible avec ce nouveau code de retour 607, enregistré à l'IANA. Le logiciel de l'utilisateur enverra ce code (il aura typiquement un bouton « rejet de ce spam » comme c'est le cas pour les logiciels de courrier), et il pourra être utilisé pour diverses techniques anti-spam (par exemple par un fournisseur SIP pour déterminer que tel numéro ne fait que du spam et peut donc être bloqué). La FCC (pour laquelle travaille l'auteur du RFC) avait beaucoup plaidé pour un tel mécanisme.

Notez que l'interprétation du code sera toujours délicate, car il peut y avoir usurpation de l'identité de l'appelant (section 6 de notre RFC, et aussi RFC 4474) ou tout simplement réaffectation d'une identité à un nouvel utilisateur, innocent de ce qu'avait fait le précédent. Au passage, dans SIP, l'identité de l'appelant peut être un URI SIP ou bien un numéro de téléphone, cf. RFC 3966.

Le code aurait dû être 666 (le nombre de la Bête) mais le code 607 a été finalement choisi pour éviter des querelles religieuses. (Le RFC 7999 n'a pas eu les mêmes pudeurs.)

L'action (ou l'inaction) suivant une réponse 607 dépendra de la politique de chaque acteur. (La discussion animée à l'IETF avait surtout porté sur ce point.) Comme toujours dans la lutte contre le spam, il faudra faire des compromis entre trop de faux positifs (on refuse des messages légitimes) et trop de faux négatifs (on accepte du spam). D'autant plus que l'utilisateur peut être malveillant (rejeter comme spam des appels légitimes dans l'espoir de faire mettre l'appelant sur une liste noire) ou simplement incompétent (il clique un peu au hasard). Les signalements sont donc à prendre avec des pincettes (section 6 du RFC).


Téléchargez le RFC 8197


L'article seul

Developing a dnstap to C-DNS converter at the IETF hackathon

First publication of this article on 17 July 2017


The weekend of 15-16 july 2017, I participated to the IETF 99 hackathon in Prague. The project was to develop a dnstap to C-DNS converter. This is a small documentation of the result and of the lessons learned.

First, a bit of background. Most DNS operators these days gather a lot of data from the DNS traffic and then analyze it. Events like DITL can fill many hard disks with pcap files. pcap not being very efficient (both in producing it, in storing it, and in analyzing it), a work is under way at the IETF to create a better format: C-DNS (for "capture DNS"). C-DNS is currently specified in an Internet-Draft, draft-ietf-dnsop-dns-capture-format. It is only a draft, not yet a RFC. One of the goals of IETF hackathons is precisely to test drafts, to see if they are reasonable, implementable, etc, before they are approved.

Note that C-DNS is based on CBOR (RFC 7049). There is already an implementation of C-DNS, available under a free software licence. Here, the idea was to write a second implementation, to test interoperability. The target was a C-DNS producer. Where to find the data to put in the file? I choosed dnstap since it is currently the best way to get data from a DNS server. dnstap relies on protocol buffers so it may be difficult to handle but there is already a good dnstap client, written in Go.

So, the decisions were:

  • Get DNS data via dnstap from a Unbound resolver (the only resolver with dnstap support at this time),
  • Use the dnstap client as a starting point (which means the hackathon project was to use Go),
  • Test the C-DNS produced with the inspector from the first implementation.

First, compiling the first C-DNS implementation, which is in C++ (I used a not-up-to-date Ubuntu machine): it requires several Boost libraries, and I'm too lazy to check exactly which, so I installed everything aptitude install libboost1.58-all-dev liblzma-dev lzma-dev lzma. The C++ capture library libtins does not appear to be in a Ubuntu "xenial" package (but there is a Debian one and it is in some Ubuntu versions). The "trusty" package is too old, we install the "yakkety" one manually:

./configure
make

Then, we can produce C-DNS files from pcaps:

./compactor/compactor -o short.cdns -c /dev/null short.pcap

And read C-DNS files:

./compactor/inspector short.cdns

So, now, we can test the produced files.

Next, compiling Unbound with dnstap support (it is not done by default, probably because it add a lot of dependencies, coming from protocol buffers):

aptitude install libprotobuf-c-dev  protobuf-c-compiler libfstrm-dev fstrm-bin
./configure --enable-dnstap
make

We configure Unbound with:

dnstap:
    dnstap-enable: yes
    dnstap-socket-path: "/var/run/unbound/dnstap.sock" # "the dnstap socket won't appear in the filesystem until the dnstap listener is started."
    dnstap-send-identity: yes
    dnstap-send-version: yes
    dnstap-log-resolver-response-messages: yes
    dnstap-log-client-query-messages: yes
    dnstap-log-resolver-query-messages: yes
    dnstap-log-client-response-messages: yes

And we start it:

./unbound/unbound -d -c dnstap.conf

Then, when processing DNS queries and responses, Unbound sends a report to the dnstap socket. We just need a dnstap client to display it.

We forked the dnstap client, created a c-dns branch, and started our copy. To compile it:

aptitude install golang-dns-dev golang-goprotobuf-dev
go get github.com/farsightsec/golang-framestream
go install github.com/bortzmeyer/golang-dnstap
go build dnstap/main.go

Then we can run it:

./main -y -u /var/run/unbound/dnstap.sock

And we can see the YAML output when Unbound receives or sends DNS messages. To store this output, I was not able to put the data in a file, so I just redirected the standard output.

Most of the hackathon work took place in the new file CdnsFormat.go. First, producing CBOR. I had a look at the various Go implementations of CBOR. Most seem old and unmaintained and CBOR seemed to me simple enough that it was faster to reimplement from scratch. This is the code at the beginning of CdnsFormat.go, the cborInteger() and similar functions. I also developed a small Go program to read CBOR files and display them as a tree, a tool which was very useful to debug my C-DNS producer. The grammar of C-DNS is specified in the CDDL language (currently specified in another Internet-Draft). A validating tool exists, taking CDDL and CBOR and telling if the CBOR file is correct, but this tool's error messages are awful. It is just good to say if the file is OK or not, afterwards, you have to examine the file manually.

Then, actually producing the C-DNS file. The C-DNS format is not simple: it is intended for performance, and harsh compression, not for ease of implementation. The basic idea is to capture in tables most of what is repeated, actual DNS messages being made mostly of references to these tables. For instance, a DNS query for www.sinodun.com won't include the string www.sinodun.com. This FQDN will be stored once, in the name-rdata table, and a numeric index to an entry of this table will be used in the message. For instance:

// Server address 
s.Write(cborInteger(0))
s.Write(cborInteger(2))  

Here, we don't write the server IP address directly, we write an index to the table where the IP address is (2 is the second value of the table, C-DNS indexes start at 1, read later about the value zero). Note that the inspector crashed when meeting indexes going outside of an array, something that Jim Hague fixed during the hackathon.

Speaking of IP addresses, "client" and "server" in the C-DNS specification don't mean "source" and "destination". For a DNS query, "client" is the source and "server" the destination but, for a DNS response, it is the opposite (dnstap works the same way, easing the conversion).

Among the things that are not clear in the current version of the draft (version -03) is the fact that CBOR maps are described with keys that are strings, while in the CDNS format, they are actually integers. So when you read in the draft:

FilePreamble = {
      major-format-version => uint, 
      minor-format-version => uint, 
      ...

Read on: FilePreamble is indeed a CBOR map but the actual keys are further away:

major-format-version = 0
minor-format-version = 1

So for a version number of 0.5 (the current one), you must write in Go the map as:

//    Major version
s.Write(cborInteger(0))
s.Write(cborInteger(0))
//    Minor version
s.Write(cborInteger(1))
s.Write(cborInteger(5)) 

Another choice to make: CBOR allow arrays and maps of indefinite of finite length. C-DNS does not specify which one to use, it is up to you, programmer, to choose. Of course, it is often the case that you don't know the length in advance, so sometimes you have no choice. An example of a finite length array:

s.Write(cborArray(3))
// Then write the three items  

And an example of an indefinite length array:

s.Write(cborArrayIndef())
// Write the items
s.Write(cborBreak())

Note that you need to checkpoint from time to time (for instance by rotating the C-DNS file and creating a new one) otherwise a crash will leave you with a corrupted file (no break at the end). The fact that C-DNS (well, CBOR, actually), requires this break code at the end forced us to modify the API of dnstap modules, to have a new function finish (of type TextFinishFunc, this function is a no-op for the other formats).

Note there is a semantic mismatch between C-DNS and dnstap: C-DNS assumes all the data is mandatory while in dnstap, almost everything is optional. That means that we have to create dummy data in some places for instance:

s.Write(cborArray(2))
if m.QueryTimeSec != nil {
        s.Write(cborInteger(int(*m.QueryTimeSec)))
} else {
        s.Write(cborInteger(0))
}

Here, if we don't have the time of the DNS message, we write the dummy value 0 (because earliest-time is not optional in the C-DNS format). One possible evolution of the C-DNS draft could be to have profiles of C-DNS, for instance a "Full" profile where everything is mandatory and a "Partial" one where missing values are allowed.

The C-DNS specification is currently ambiguous about empty arrays. Most arrays are declared, in the grammar, as allowing to be empty. It raises some issues with the current tools (the inspector crashed when meeting these empty arrays, something that Jim Hague fixed during the hackathon). But it is also unclear in its semantics. For instance, the draft says that a value zero for an index mean "not found" but it does not appear to be supported by the current tools, forcing us to invent dummy data.

dnstap formats a part of the DNS messages but not everything. To get the rest, you need to parse the binary blob sent by dnstap. We use the excellent Go DNS package):

import (
  ...
  "github.com/miekg/dns"
...  
msg = new(dns.Msg)
err := msg.Unpack(m.QueryMessage)

This allows us to get information like the QNAME (name used in the question):

qname := make([]byte, 256)
...
n, err = dns.PackDomainName(msg.Question[0].Name, qname, 0, nil, false)
...
s.Write(cborByteString(qname[0:n]))

(Unpack leaves us with a domain name in the presentation - text - format, but C-DNS requires the label - binary - format, which we do with PackDomainName.) Domain names are defined as CBOR byte string and not strings 1) because you cannot be sure of their encoding (strings have to be UTF-8) 2) and for consistency reasons because the same tables can store other things than domain names.

OK, now, we have everything, compile again and run (there is a Unbound running in another window):

go build dnstap/main.go
./main -c -u /var/run/unbound/dnstap.sock > test.cdns
../compactor/inspector   test.cdns  

And the inspector produced a pcap file, as well as a report. Let's try the pcap:

% tcpdump -n -r test.cdns.pcap
reading from file test.cdns.pcap, link-type EN10MB (Ethernet)
13:02:02.000000 IP6 ::1.51834 > ::.0: UDP, length 25
13:02:02.000000 IP 0.0.0.0.0 > 193.0.14.129.53: 666 SOA? 142.com. (25)
13:02:02.000000 IP 193.0.14.129.53 > 0.0.0.0.0: 666- [0q] 0/0/0 (12)
13:02:02.000000 IP6 ::.0 > 2001:503:83eb::30.53: 666 AAAA? ns2.bodis.com. (31)
13:02:02.000000 IP 0.0.0.0.0 > 192.41.162.30.53: 666 AAAA? ns1.bodis.com. (31)
13:02:02.000000 IP6 2001:503:83eb::30.53 > ::.0: 666- [0q] 0/0/0 (12)

You immediately note the missing data. Most of the times, it was the lack of this data in dnstap (the IP addresses, for instance), sometimes it was my own lazyness (the microseconds in the time).

Sometimes, there are things that are available in dnstap but C-DNS offers no way to store them. This is the case with the bailiwick (the zone from which the DNS responses came) or with the fact thata the resolver cache experienced a hit or a miss.

This was the end of the IETF 99 hackathon. The code is available. An example C-DNS file produced by my converter is attached here. Other things would of course be possible:

  • The biggest limit of the current dnstap-to-C-DNS tool is that it uses one C-DNS block per DNS message. This is simpler for the lazy programmer, but it defeats the most important requirments of C-DNS: compression. Compression is done py putting in tables information which is common to several DNS messages. This is the obvious next step.
  • Test with an authoritative name server like Knot (which has dnstap support).

Thanks to Jim Hague for working with me throughout the hackathon (and fixing many things, and answering many questions) and to Sara Dickinson.


L'article seul

RFC 8200: Internet Protocol, Version 6 (IPv6) Specification

Date de publication du RFC : Juillet 2017
Auteur(s) du RFC : S. Deering (Retired), R. Hinden (Check Point Software)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 16 juillet 2017


Ce RFC est la nouvelle norme du protocole IPv6. IP est le protocole de base de l'Internet, la version 6 y est minoritaire mais est bien plus répandue qu'elle ne l'était lors de la sortie de la précédente norme, qui était le RFC 2460, norme que notre nouveau RFC remplace (et cela fait passer IPv6 au statut de norme Internet, la précédente étant officiellement une proposition de norme).

Pas de changements cruciaux, la norme est nouvelle, mais le protocole reste largement le même. Ce RFC 8200 continue à présenter IPv6 comme « a new version of the Internet Protocol (IP) ». Comme la première norme IPv6 est sortie en 1995, l'adjectif « new » n'est vraiment pas sérieux. Comme, malheureusement, la plupart des formations réseau ne parlent que d'IPv4 et traitent IPv6 de manière bâclée à la fin, le RFC présente IPv6 en parlant de ses différences par rapport à IPv4 (section 1 du RFC) :

  • La principale est évidemment l'espace d'adressage bien plus grand. Alors qu'IPv4, avec ses adresses sur 32 bits, ne peut même pas donner une adresse IP à chaque habitant de la planète (ce qui serait déjà insuffisant), IPv6, avec ses 128 bits d'adresse, permet de distribuer une quantité d'adresses que le cerveau humain a du mal à se représenter. Cette abondance est la principale raison pour laquelle il est crucial de migrer vers IPv6. Les autres raisons sont plus discutables.
  • IPv6 a sérieusement changé le format des options. En IPv4, les options IP étaient un champ de longueur variable dans l'en-tête, pas exactement ce qui est le plus facile à analyser pour un routeur. Le RFC dit qu'IPv6 a simplifié le format mais c'est contestable : une complexité a succédé à une autre. Désormais, le premier en-tête est de taille fixe, mais il peut y avoir un nombre quelconque d'en-têtes chaînés. Le RFC utilise malheureusement des termes publicitaires assez déconnectés de la réalité, en parlant de format plus efficace et plus souple.
  • IPv6 a un mécanisme standard pour étiqueter les paquets appartenant à un même flot de données. Mais le RFC oublie de dire qu'il semble inutilisé en pratique.
  • Et le RFC termine cette énumération par le plus gros pipeautage, prétendre qu'IPv6 aurait de meilleurs capacités d'authentification et de confidentialité. (C'est faux, elles sont les mêmes qu'en IPv4, et peu déployées, en pratique.)

Notez que ce RFC 8200 ne spécifie que le format des paquets IPv6. D'autres points très importants sont normalisés dans d'autres RFC, les adresses dans le RFC 4291, et ICMP dans le RFC 4443.

La section 3 présente le format des paquets IPv6 :

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version| Traffic Class |           Flow Label                  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Payload Length        |  Next Header  |   Hop Limit   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                                                               +
   |                                                               |
   +                         Source Address                        +
   |                                                               |
   +                                                               +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                                                               +
   |                                                               |
   +                      Destination Address                      +
   |                                                               |
   +                                                               +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    

(D'ailleurs, si quelqu'un sait pourquoi l'adresse IP source est avant la destination ? Il me semblerait plus logique que ce soit l'inverse, puisque tous les routeurs sur le trajet doivent examiner l'adresse destination, alors qu'on n'a pas toujours besoin de l'adresse source.) Le numéro de version vaut évidemment 6, le « traffic class » est présenté en section 7, le « flow label » en section 6.

Le champ « Next header » remplace le « Protocol » d'IPv4. Il peut indiquer le protocole de transport utilisé (la liste figure dans un registre IANA et est la même pour IPv4 et IPv6) mais aussi les en-têtes d'extension, une nouveauté d'IPv6, présentée en section 4 de notre RFC.

Le champ « Hop limit » remplace le « Time to Live » d'IPv4. En fait, les deux ont exactement la même sémantique, qui est celle d'un nombre maximal de routeurs utilisés sur le trajet (le but est d'éviter les boucles infinies dans le réseau). Autrefois, dans IPv4, il était prévu que ce champ soit réellement une durée, mais aucune mise en œuvre d'IPv4 ne l'avait jamais utilisé comme ceci. Le renommage dans IPv6 fait donc correspondre la terminologie avec une réalité ancienne (cf. aussi la section 8.2). Notez que c'est ce champ qui est utilisé par traceroute.

Voici une simple connexion HTTP en IPv6, vue avec tcpdump et tshark. Le client a demandé /robots.txt et a obtenu une réponse négative (404). Si vous voulez, le pcap complet est ipv6-http-connection.pcap. Voici d'abord avec tcpdump avec ses options par défaut :

15:46:21.768536 IP6 2001:4b98:dc2:43:216:3eff:fea9:41a.37703 > 2605:4500:2:245b::42.80: Flags [S], seq 3053097848, win 28800, options [mss 1440,sackOK,TS val 1963872568 ecr 0,nop,wscale 7], length 0
    

On voit les deux adresses IPv6, tcpdump n'affiche rien d'autre de l'en-tête de couche 3, tout le reste est du TCP, le protocole de transport utilisé par HTTP. Avec l'option -v de tcpdump :

15:46:21.768536 IP6 (hlim 64, next-header TCP (6) payload length: 40) 2001:4b98:dc2:43:216:3eff:fea9:41a.37703 > 2605:4500:2:245b::42.80: Flags [S] [...]
    

Cette fois, on voit le « Hop limit » (64), l'en-tête suivant (TCP, pas d'en-tête d'extension) et la longueur (40 octets). Pour avoir davantage, il faut passer à tshark (décodage complet en ipv6-http-connection.txt) :

Internet Protocol Version 6, Src: 2001:4b98:dc2:43:216:3eff:fea9:41a, Dst: 2605:4500:2:245b::42
    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)
    .... .... .... 0000 0000 0000 0000 0000 = Flow label: 0x00000
    Payload length: 40
    Next header: TCP (6)
    Hop limit: 64
    Source: 2001:4b98:dc2:43:216:3eff:fea9:41a
    [Source SA MAC: Xensourc_a9:04:1a (00:16:3e:a9:04:1a)]
    Destination: 2605:4500:2:245b::42
    [Source GeoIP: France]
        [Source GeoIP Country: France]
    [Destination GeoIP: United States]
        [Destination GeoIP Country: United States]
    

On a cette fois tout l'en-tête IPv6 : notons le « Flow Label » (j'avais bien dit que peu de gens s'en servaient, il est nul dans ce cas).

La section 4 de notre RFC est dédiée à une nouveauté d'IPv6, les en-têtes d'extension. Au lieu d'un champ « Options » de taille variable (donc difficile à analyser) comme en IPv4, IPv6 met les options IP dans des en-têtes supplémentaires, chaînés avec l'en-tête principal. Par exemple, si un paquet UDP a un en-tête « Destination Options », le champ « Next header » de l'en-tête principal vaudra 60 (pour « Destination Options »), il sera suivi de l'en-tête d'extension « Destination Options » qui aura, lui, un « Next header » de 17 pour indiquer que ce qui suit est de l'UDP. (Je rappelle que les valeurs possibles pour « Next Header » sont dans un registre IANA.) Il peut y avoir zéro, un ou davantage d'en-têtes d'extension chaînés entre eux.

Notez qu'analyser cette chaîne d'en-têtes est compliqué car les en-têtes n'ont pas tous le même format (le RFC 6564 a créé un format unique, mais cela ne concerne que les futurs en-têtes.) Il est donc exagéré de dire que la suppression du champ « Options » de taille variable a simplifié les choses.

Les différents en-têtes ne sont pas tous traités pareillement par les routeurs. Il existe notamment un en-tête, « Hop-by-hop Options » qui doit être examiné par tous les routeurs du trajet (cette obligation, jamais respectée, a de toute façon été relâchée par rapport au RFC 2460). C'est pour cela qu'il doit être placé au début des en-têtes, juste après l'en-tête principal. Les autres en-têtes d'extension doivent être ignorés par les routeurs.

Comme il est compliqué de rajouter un nouveau modèle d'en-tête (il faudrait modifier toutes les machines IPv6), une solution légère existe pour les options simples : utiliser les en-têtes d'options, « Hop-by-hop Options » et « Destination Options ». Tous les deux sont composés d'une série d'options encodées en TLV. En outre, le type de l'option indique, dans ses deux premiers bits, le traitement à appliquer au paquet si le système ne connait pas cette option. Si les deux premiers bits sont à zéro, on ignore l'option et on continue. Autrement, on jette le paquet (les trois valeurs restantes, 01, 10 et 11, indiquent si on envoie un message d'erreur ICMP et lequel). Ainsi, l'option pour la destination de numéro 0x07 (utilisée par le protocole de sécurité du RFC 5570) est facultative : elle a les deux premiers bits à zéro et sera donc ignorée silencieusement par les destinataires qui ne la connaissent pas (cf. registre IANA.)

« Destination Options », comme son nom l'indique, n'est examinée que par la machine de destination. Si vous voulez envoyer des paquets avec cet en-tête, regardez mon article.

Outre les en-têtes « Hop-by-hop Options » et « Destination Options », il existe des en-têtes :

  • « Routing Header », qui permet de spécifier le routage depuis la source (un peu comme les options de « source routing » en IPv4). Il y a plusieurs types, et les valeurs possibles sont dans un registre IANA, géré suivant les principes du RFC 5871. (Le type 0 a été retiré depuis le RFC 5095.)
  • « Fragment Header », qui permet de fragmenter les paquets de taille supérieure à la MTU.
  • Les autres en-têtes sont ceux utilisés par IPsec, décrits dans les RFC 4302 et RFC 4303.

La fragmentation est différente de celle d'IPv4. En IPv6, seule la machine émettrice peut fragmenter, pas les routeurs intermédiaires. Si le paquet est plus grand que la MTU, on le découpe en fragments, chaque fragment portant un « Fragment Header ». Cet en-tête porte une identification (un nombre sur 32 bits qui doit être unique parmi les paquets qui sont encore dans le réseau), un décalage (offset) qui indique à combien d'octets depuis le début du paquet original se situe ce fragment (il vaut donc zéro pour le premier fragment) et un bit qui indique si ce fragment est le dernier. À la destination, le paquet est réassemblé à partir des fragments. (Il est désormais interdit que ces fragments se recouvrent, cf. RFC 5722.) Voici un exemple de fragmentation. La sonde Atlas n° 6271 a interrogé un serveur DNS de la racine Yeti avec le type de question ANY qui signifie « envoie-moi tout ce que tu peux / veux ». La réponse, plus grande que la MTU (plus de quatre kilo-octets !), a été fragmentée en trois paquets (le pcap complet est en ipv6-dns-frag.pcap) :

16:14:27.112945 IP6 2001:67c:217c:4::2.60115 > 2001:4b98:dc2:45:216:3eff:fe4b:8c5b.53: 19997+ [1au] ANY? . (28)
16:14:27.113171 IP6 2001:4b98:dc2:45:216:3eff:fe4b:8c5b > 2001:67c:217c:4::2: frag (0|1232) 53 > 60115: 19997*- 35/0/1 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, NSEC, RRSIG[|domain]
16:14:27.113187 IP6 2001:4b98:dc2:45:216:3eff:fe4b:8c5b > 2001:67c:217c:4::2: frag (1232|1232)
16:14:27.113189 IP6 2001:4b98:dc2:45:216:3eff:fe4b:8c5b > 2001:67c:217c:4::2: frag (2464|637)
    

On note que tcpdump n'a interprété qu'un seul fragment comme étant du DNS, la premier, puisque c'était le seul qui portait l'en-tête UDP, avec le numéro de port 53 identifiant du DNS. Dans le résultat de tcpdump, après le mot-clé frag, on voit le décalage du fragment par rapport au début du paquet original (respectivement 0, 1232 et 2464 pour les trois fragments), et la taille du fragment (respectivement 1232, 1232 et 637 octets). Vu par tshark (l'analyse complète est en ipv6-dns-frag.txt), le premier fragment contient :

    
    Type: IPv6 (0x86dd)
Internet Protocol Version 6, Src: 2001:4b98:dc2:45:216:3eff:fe4b:8c5b, Dst: 2001:67c:217c:4::2
    Payload length: 1240
    Next header: Fragment Header for IPv6 (44)
    Fragment Header for IPv6
        Next header: UDP (17)
        Reserved octet: 0x00
        0000 0000 0000 0... = Offset: 0 (0 bytes)
        .... .... .... .00. = Reserved bits: 0
        .... .... .... ...1 = More Fragments: Yes
        Identification: 0xcbf66a8a
Data (1232 bytes)

On note le « Next Header » qui indique qu'un en-tête d'extension, l'en-tête « Fragmentation », suit l'en-tête principal. Le bit M (« More Fragments ») est à 1 (ce n'est que le premier fragment, d'autres suivent), le décalage (« offset ») est bien sûr de zéro. L'identificateur du paquet est de 0xcbf66a8a. Le dernier fragment, lui, contient :

Internet Protocol Version 6, Src: 2001:4b98:dc2:45:216:3eff:fe4b:8c5b, Dst: 2001:67c:217c:4::2
    Payload length: 645
    Next header: Fragment Header for IPv6 (44)
    Fragment Header for IPv6
        Next header: UDP (17)
        Reserved octet: 0x00
        0000 1001 1010 0... = Offset: 308 (2464 bytes)
        .... .... .... .00. = Reserved bits: 0
        .... .... .... ...0 = More Fragments: No
        Identification: 0xcbf66a8a

Cette fois, le « Next Header » indique que c'est de l'UDP qui suit, le décalage est de 2464, et le bit M est à zéro (plus d'autres fragments). L'identificateur est le même, c'est celui du paquet original, et c'est grâce à lui que la machine de destination saura réassembler les fragments. Notez qu'à la fin de l'analyse par tshark figure un réassemblage complet du paquet, ce qui permet une analyse DNS complète.

Et si je ne suis pas satisfait des en-têtes d'extension existants et que je veux créer le mien ? C'est en général une mauvaise idée. La plupart des cas concrets devraient être résolus avec un des en-têtes déjà normalisés. Notamment, l'en-tête « Destination Options » est là pour la majorité des situations. C'est lui qu'il faut regarder en premier (ce qu'ont fait les RFC 6744, RFC 6788 ou RFC 7837, la liste complète figurant dans un registre IANA). Notre RFC 8200 exige donc que, si vous tenez à créer un nouvel en-tête, vous expliquiez bien pourquoi c'est indispensable, et pourquoi aucun des en-têtes existants ne convient.

Il est également déconseillé de créer de nouvelles options « hop-by-hop » (la liste actuelle est à l'IANA), car ces options doivent être traitées par tous les routeurs du trajet. Il y a un risque sérieux qu'ils laissent tomber les paquets ayant cet en-tête « Hop-by-hop Options », ou bien qu'ils le traitent plus lentement (logiciel du routeur et pas circuits matériels spécialisés). Là aussi, il faudra donc une justification sérieuse.

La section 5 de notre RFC se penche sur un problème délicat, la taille des paquets. IPv6 exige une MTU d'au moins 1 280 octets, mais les paquets sont souvent plus grands (par exemple 1 500 octets si on part d'un Ethernet). Beaucoup de liens ont, en pratique, une MTU de 1 500 octets mais IPv6 étant souvent porté par des tunnels (en raison de l'immobilisme de beaucoup de FAI, qui ne déploient toujours pas IPv6), un certain nombre de liens offrent moins de 1 500 octets. Normalement, l'émetteur d'un paquet IPv6 doit faire de la découverte de la MTU du chemin (RFC 8201) afin de pouvoir fragmenter, si nécessaire. Une mise en œuvre « paresseuse » d'IPv6 pourrait se dispenser de découverte de la MTU du chemin, et se limiter à 1 280 octets par paquet.

Le problème est que la découverte de la MTU du chemin dépend du bon fonctionnement d'ICMP. L'émetteur d'un paquet doit pouvoir recevoir les paquets ICMP « Packet too big » (RFC 4443, section 3.2). Or, un certain nombre de pare-feux, stupidement configurés par des amateurs, bloquent tout ICMP « pour des raisons de sécurité » (c'est d'ailleurs une bonne question pour les entretiens d'embauche d'un administrateur de réseaux : « filtrer ICMP en entrée ou pas ? » S'il répond Oui, on est sûr qu'il est incompétent.) Ne recevant pas les « Packet too big », l'émetteur risque de croire à tort que ses paquets sont passés. En outre, si l'émetteur décide de fragmenter (en général, quand la MTU du chemin est inférieure à la sienne, avec TCP, on réduit la MSS, avec UDP, on fragmente), il faut que les fragments passent à travers le réseau. Et, là encore, un certain nombre de pare-feux bêtement configurés bloquent les fragments. Donc, en pratique, découverte du chemin + fragmentation est un processus fragile, en raison de ce véritable sabotage par des middleboxes.

C'est certainement le plus gros problème pratique lors du déploiement d'IPv6. On peut même penser à prendre des mesures radicales et coûteuses, comme d'abaisser la MTU à 1 280 octets pour être tranquille. Moins violent, il est fréquent de voir des MTU à 1 480 octets. Voici par exemple la configuration de mon routeur Turris Omnia pour passer par l'IPv6 de Free (un tunnel) :

config interface 'lan'
	option ip6assign '64'
	option ip6addr '2001:db8:42::1:fe/64'
	option ip6prefix '2001:db8:42::/64'
	option ip6gw '2001:db8:42::1'
	option mtu '1480'
    

Et le « flow label », dont j'avais parlé plus haut ? Il est décrit dans la (très courte) section 6, qui renvoie surtout au RFC 6437. En pratique, ce champ semble peu utilisé comme on l'a vu dans l'exemple décodé par tshark.

Même chose pour le « traffic class », en section 7 : pour son utilisation pour la différenciation de trafic, voir les RFC 2474 et RFC 3168.

Maintenant qu'IPv6, protocole de couche 3, a été bien défini, le RFC monte vers la couche 4, en consacrant sa section 8 aux problèmes des couches supérieures. Cela concerne notamment la somme de contrôle. Si vous avez fait attention au schéma de l'en-tête IPv6 de la section 3, vous avez noté qu'il n'y avait pas de champ « Header Checksum », contrairement à ce qui existait en IPv4. En IPv6, pas de somme de contrôle en couche 3, c'était une tâche supplémentaire pour les routeurs (pour citer le RFC 791, « Since some header fields change (e.g., time to live), this is recomputed and verified at each point that the internet header is processed. »), tâche dont ils sont désormais dispensés.

Par contre, la somme de contrôle existe pour les en-têtes de couche 4 et elle devient même obligatoire pour UDP (elle était facultative en IPv4, quoique très fortement recommandée). (Voir le RFC 1071, au sujet de cette somme de contrôle.)

Un gros changement de ce RFC par rapport à son prédécesseur, le RFC 2460, concerne la sécurité. La section sur la sécurité est passée d'une annexe de deux lignes (qui se contentait de passer le bébé à IPsec) à une analyse plus détaillée (section 10 du RFC). La question est délicate car la sécurité d'IPv6 a souvent fait l'objet de FUD, visant à justifier l'immobilisme de pas mal d'acteurs. Il est évidemment plus valorisant de dire « nous ne migrons pas vers IPv6 pour des raisons de sécurité » que de reconnaitre « nous sommes trop flemmards et paralysés par la peur du changement ». (Cf. mon exposé sur la sécurité d'IPv6 à l'ESGI.) S'il fallait synthétiser (la deuxième partie de cette synthèse ne figure pas dans le RFC), je dirais :

  • La sécurité d'IPv6 est quasiment la même qu'en IPv4 (ce qui est logique, il ne s'agit après tout que de deux versions du même protocole). Les grandes questions de sécurité d'IPv4 (usurpation d'adresse source, relative facilité à faire des attaques par déni de service, pas d'authentification ou de confidentialité par défaut) sont exactement les mêmes en IPv6. (C'est une blague courante à l'IETF de dire que si IPv4, l'un des plus grands succès de l'ingéniérie du vingtième siècle, était présenté à l'IESG aujourd'hui, il serait rejeté pour sa trop faible sécurité.)
  • Par contre, en pratique, les solutions techniques d'attaque et de défense, ainsi que les compétences des attaquants et des défenseurs, sont bien plus faibles en IPv6. Pas mal de logiciels « de sécurité » ne gèrent pas IPv6, bien des logiciels de piratage ne fonctionnent qu'en IPv4, les administrateurs système sont déroutés face à une attaque IPv6, et les pirates ne pensent pas à l'utiliser. (Faites l'expérience : configurez un pot de miel SSH en IPv4 et IPv6. Vous aurez plusieurs connexions par jour en IPv4 et jamais une seule en IPv6.) L'un dans l'autre, je pense que ces deux aspects s'équilibrent.

Bon, assez de stratégie, passons maintenant aux problèmes concrets que décrit cette section 10. Elle rappelle des risques de sécurité qui sont exactement les mêmes qu'en IPv4 mais qu'il est bon de garder en tête, ce sont des problèmes fondamentaux d'IP :

  • Communication en clair par défaut, donc espionnage trop facile pour les États, les entreprises privées, les pirates individuels. (Cf. Snowden.)
  • Possibilité de rejouer des paquets déjà passés, ce qui permet certaines attaques. Dans certains cas, on peut modifier le paquet avant de le rejouer, et ça passera.
  • Possibilité de générer des faux paquets et de les injecter dans le réseau.
  • Attaque de l'homme du milieu : une entité se fait passer pour l'émetteur auprès du vrai destinataire, et pour le destinataire auprès du vrai émetteur.
  • Attaque par déni de service, une des plaies les plus pénibles de l'Internet.

En cohérence avec le RFC 2460 (mais pas avec la réalité du terrain), notre RFC recommande IPsec (RFC 4301) comme solution à la plupart de ces problèmes. Hélas, depuis le temps qu'il existe, ce protocole n'a jamais connu de déploiement significatif sur l'Internet public (il est par contre utilisé dans des réseaux privés, par exemple le VPN qui vous permet de vous connecter avec votre entreprise de l'extérieur utilise probablement une variante plus ou moins standard d'IPsec). Une des raisons de ce faible déploiement est la grande complexité d'IPsec, et la complexité pire encore de ses mises en œuvre. En pratique, même si le RFC ne le reconnait que du bout des lèvres, ce sont les protocoles applicatifs comme SSH ou TLS, qui sécurisent l'Internet.

Pour les attaques par déni de service, par contre, aucune solution n'est proposée : le problème ne peut pas forcément se traiter au niveau du protocole réseau.

La différence la plus spectaculaire entre IPv4 et IPv6 est évidemment la taille des adresses. Elle rend le balayage bien plus complexe (mais pas impossible), ce qui améliore la sécurité (l'Internet IPv4 peut être exploré incroyablement vite, par exemple avec masscan, et, si on est trop flemmard pour balayer soi-même, on peut utiliser des balayages déjà faits, par exemple par Shodan ou https://scans.io/). Le RFC 7707 fait une très bonne synthèse de l'état de l'art en matière de balayage IPv6. Par exemple, Shodan, cité plus haut, doit utiliser des techniques assez douteuses pour récolter des adresses IPv6 à examiner.

Et qu'en est-il de la vie privée ? L'argument, largement FUDé, a été beaucoup utilisé contre IPv6. Le RFC note qu'IPv6 a entre autre pour but de rendre inutile l'usage du NAT, dont certaines personnes prétendent qu'il protège un peu les utilisateurs. L'argument est largement faux : le NAT (qui est une réponse à la pénurie d'adresses IPv4, pas une technique de sécurité) ne protège pas contre tout fingerprinting, loin de là. Et, si on veut empêcher les adresses IP des machines du réseau local d'être visibles à l'extérieur, on peut toujours faire du NAT en IPv6, si on veut, ou bien utiliser des méthodes des couches supérieures (comme un relais).

Autre question de vie privée avec IPv6, les adresses IP fondées sur l'adresse MAC. Cette ancienne technique, trop indiscrète, a été abandonnée avec les RFC 4941 et RFC 7721, le premier étant très déployé. Il est curieux de constater que cet argument soit encore utilisé, alors qu'il a perdu l'essentiel de sa (faible) pertinence.

Mais il y avait bien des problèmes de sécurité concrets avec le précédent RFC 2460, et qui sont réparés par ce nouveau RFC :

  • Les « fragments atomiques » ne doivent désormais plus être générés (RFC 8021) et, si on en reçoit, doivent être « réassemblés » par une procédure spéciale (RFC 6946).
  • Les fragments qui se recouvrent partiellement sont désormais interdits (cf. RFC 5722, le réassemblage des fragments en un paquet est déjà assez compliqué et sujet à erreur comme cela).
  • Si le paquet est fragmenté, les en-têtes d'extension doivent désormais tous être dans le premier fragment (RFC 7112).
  • L'en-tête de routage (Routing Header) de type 0, dit « RH0 », est abandonné, il posait trop de problèmes de sécurité (cf. RFC 5095 et RFC 5871).

L'annexe B de notre RFC résume les changements depuis le RFC 2460. Pas de choses révolutionnaires, les changements les plus importantes portaient sur la sécurité, comme listé un peu plus haut (section 10 du RFC). On notera comme changements :

  • [Section 1] Clarification que IPv6 est gros-boutien, comme IPv4 (cf. l'annexe B du RFC 791).
  • [Section 3] Clarification de l'utilisation du « hop limit », décrémenté de 1 à chaque routeur.
  • [Section 4] Clarification du fait qu'un équipement intermédiaire ne doit pas tripoter les en-têtes d'extension (à part évidemment « Hop-by-hop Options »), ni les modifier, ni en ajouter ou retirer, ni même les lire.
  • [Section 4] Le traitement de l'en-tête « Hop-by-hop Options par les routeurs sur le trajet n'est plus obligatoire. Si un routeur est pressé, il peut s'en passer (le RFC suit ainsi la pratique).
  • [Section 4.4] Suppression de l'en-tête de routage de type 0.
  • [Section 4.5] Pas mal de changements sur la fragmentation (un processus toujours fragile !), notamment l'abandon des fragments atomiques.
  • [Section 4.8] Intégration du format unique des éventuels futurs en-têtes d'extension, format initialement présenté dans le RFC 6564.
  • [Section 6] Reconnaissance du fait que « Flow Label » n'était pas réellement bien défini, et délégation de cette définition au RFC 6437.
  • [Section 8.1] Autorisation, dans certains cas bien délimités, d'omission de la somme de contrôle UDP (RFC 6935).
  • Il y a eu également correction de diverses erreurs comme les 2541 (omission sur la définition du « Flow Label ») et 4279 (paquet entrant avec un « Hop Limit » déjà à zéro).

Le projet de mise à jour de la norme IPv6 avait été lancé en 2015 (voici les supports du premier exposé).

D'habitude, je termine mes articles sur les RFC par des informations sur l'état de mise en œuvre du RFC. Mais, ici, il y en a tellement que je vous renvoie plutôt à cette liste. Notez que des tests d'interopérabilité ont été faits sur les modifications introduites par ce nouveau RFC et que les résultats publiés n'indiquent pas de problème.

Parmi les publications récentes sur le déploiement d'IPv6, signalons :


Téléchargez le RFC 8200


L'article seul

RFC 8201: Path MTU Discovery for IP version 6

Date de publication du RFC : Juillet 2017
Auteur(s) du RFC : J. McCann (Digital Equipment Corporation), S. Deering (Retired), J. Mogul (Digital Equipment Corporation), R. Hinden (Check Point Software)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 16 juillet 2017


Ce RFC est l'adaptation à IPv6 du protocole décrit dans le RFC 1191, protocole qui permet de découvrir la MTU du chemin entre deux machines reliées par Internet. Il remplace le RFC 1981.

Avec IPv4, déterminer la MTU maximale du chemin est très utile pour optimiser les performances. Mais elle devient presque indispensable en IPv6, où les routeurs n'ont pas le droit de fragmenter les paquets trop gros (toute fragmentation doit être faite dans la machine de départ). PMTU fait donc quasi-obligatoirement partie d'IPv6. Une alternative est de n'envoyer que des paquets suffisamment petits pour passer partout. C'est moins efficace (on ne tirera pas profit des MTU plus importantes), mais ça peut être intéressant pour des mises en œuvre légères d'IPv6, par exemple pour des objets connectés. (La section 4 du RFC précise en effet que mettre en œuvre cette découverte de la MTU du chemin n'est pas obligatoire.)

L'algorithme (section 3 de notre RFC) est le même qu'en v4, envoyer des paquets, et voir si on reçoit des paquets ICMP Packet too big (RFC 4443, section 3.2) qui contiennent en général la MTU maximale du lien suivant. (Pas de bit DF - Don't fragment - en IPv6 puisque la fragmentation n'est possible qu'à la source. L'annexe A détaille les différences avec l'algorithme IPv4 décrit dans le RFC 1191.)

Voici par exemple un de ces paquets ICMP, vu par tcpdump (déclenché par une commande ping -s 1500 …) :

18:18:44.813927 IP6 2a02:8400:0:3::a > 2605:4500:2:245b::bad:dcaf: ICMP6, packet too big, mtu 1450, length 1240

Il ne faut pas s'arrêter au premier paquet Packet too big reçu, car il peut y avoir des liens réseau avec une MTU encore plus basse plus loin. En outre, la MTU du chemin change avec le temps et il faut donc rester vigilant, on peut recevoir des Packet too big si le trafic passe désormais par un lien de MTU plus faible que la précédente MTU du chemin. Plus délicat, il faut aussi de temps en temps réessayer avec des paquets plus gros, pour voir si la MTU du chemin n'aurait pas augmenté. Comme cela va faire perdre des paquets, s'il n'y a pas eu d'augmentation, il ne faut pas le faire trop souvent. (Dix minutes, dit la section 5.)

La section 4 du RFC précise les exigences qu'il normalise. (Je donne quelques exemples de leur mise en œuvre dans le noyau Linux, dans net/ipv6/route.c.) Par exemple, le nœud IPv6 doit vérifier le contenu des paquets ICMP Packet Too Big qu'il reçoit (le Message Body, cf. RFC 4443, où le routeur émetteur est censé placer des données du paquet original), pour éviter de croire des faux messages ICMP envoyés par un attaquant (rien n'authentifie un paquet ICMP, à part son contenu).

Nouveauté de ce RFC, par rapport à son prédecesseur, un nœud IPv6 doit ignorer les messages Packet Too Big indiquant une MTU inférieur aux 1 280 octets minimum d'IPv6 (le RFC 8021 explique pourquoi). C'est le but de l'instruction mtu = max_t(u32, mtu, IPV6_MIN_MTU); dans le code du noyau Linux, qui ne garde pas la MTU indiquée si elle est inférieur au minimum.

Et la machine IPv6 ne doit jamais augmenter la MTU du chemin suite à la réception d'un Packet Too Big indiquant une MTU supérieure à l'actuelle. Un tel message ne peut être qu'une erreur ou une attaque. Voir les commentaires au début de la fonction rt6_mtu_change_route dans le code Linux.

Comme avec IPv4, l'algorithme PMTU marche mal en pratique car beaucoup de sites filtrent stupidement tous les paquets ICMP et la machine qui tente de faire de la Path MTU discovery n'aura jamais de réponse. IPv6, comme IPv4, devra donc plutôt utiliser la technique du RFC 4821.

La section 5 du RFC rassemble diverses questions de mise en œuvre de cette découverte de la MTU du chemin. D'abord, il y a l'interaction entre IP (couche 3) et les protocoles au dessus, comme TCP mais aussi des protocoles utilisant UDP, comme le DNS. Ces protocoles de transport ont une MMS_S (maximum send transport-message size, voir le RFC 1122) qui est à l'origine la MTU moins la taille des en-têtes. Les protocoles de transport peuvent diminuer cette MMS_S pour ne pas avoir à faire de fragmentation.

Pour le DNS, par exemple, on peut diminuer l'usage de la découverte de la MTU du chemin en diminuant la taille EDNS. Par exemple, avec le serveur nsd, on mettrait :

ipv6-edns-size: 1460

Et, avec 1 460 octets possibles, on serait alors raisonnablement sûr de ne pas avoir de fragmentation donc, même si la découverte de la MTU du chemin marche mal, tout ira bien.

Une fois la découverte de la MTU du chemin faite, où faut-il garder l'information, afin d'éviter de recommencer cette découverte à chaque fois ? Idéalement, cette information est valable pour un chemin donné : si le chemin change (ou, a fortiori, si la destination change), il faudra découvrir à nouveau. Mais la machine finale ne connait pas en général tout le chemin suivi (on ne fait pas un traceroute à chaque connexion). Le RFC suggère donc (section 5.2) de stocker une MTU du chemin par couple {destination, interface}. Si on n'a qu'une seule interface réseau, ce qui est le cas de la plupart des machines terminales, on stocke la MTU du chemin par destination et on maintient donc un état pour chaque destination (même quand on ne lui parle qu'en UDP, qui n'a normalement pas d'état). Les deux exemples suivants concernent une destination où la MTU du chemin est de 1 450 octets. Pour afficher cette information sur Linux pour une adresse de destination :

% ip -6  route get 2a02:8428:46c:5801::4
2a02:8428:46c:5801::4 from :: via 2001:67c:1348:7::1 dev eth0 src 2001:67c:1348:7::86:133 metric 0 
    cache  expires 366sec mtu 1450 pref medium

S'il n'y a pas de PMTU indiquée, c'est que le cache a expiré, réessayez (en UDP, car TCP se fie à la MSS). Notez que, tant qu'on n'a pas reçu un seul Packet Too Big, il n'y a pas de MTU affichée. Donc, pour la plupart des destinations (celles joignables avec comme PMTU la MTU d'Ethernet), vous ne verrez rien. Sur FreeBSD, cet affichage peut se faire avec :

% sysctl -o net.inet.tcp.hostcache.list | fgrep 2a02:8428:46c:5801::4
2a02:8428:46c:5801::4  1450        0     23ms     34ms         0  4388        0 0   23    4 3600

Pour d'autres systèmes, je vous recommande cet article.

Notez qu'il existe des cas compliqués (ECMP) où cette approche de stockage de la PMTU par destination peut être insuffisante. Ce n'est donc qu'une suggestion, chaque implémentation d'IPv6 peut choisir sa façon de mémoriser les MTU des chemins.

Si on veut simplifier la mise en œuvre, et la consommation mémoire, on peut ne mémoriser qu'une seule MTU du chemin, la MTU minimale de tous les chemins testés. Ce n'est pas optimal, mais ça marchera.

Si on stocke la MTU du chemin, comme l'Internet peut changer, il faut se préparer à ce que l'information stockée devienne obsolète. Si elle est trop grande, on recevra des Packet too big (il ne faut donc pas s'attendre à n'en recevoir que pendant la découverte initiale). Si elle est trop petite, on va envoyer des paquets plus petits que ce qu'on pourrait se permettre. Le RFC suggère donc (section 5.3) de ne garder l'information sur la MTU du chemin que pendant une dizaine de minutes.

Le RFC demande enfin (section 5.5) que les mises en œuvre d'IPv6 permettent à l'ingénieur système de configurer la découverte de la MTU du chemin : la débrayer sur certaines interfaces, fixer à la main la MTU d'un chemin, etc.

Il ne faut pas oublier les problèmes de sécurité (section 6 du RFC) : les Packet Too Big ne sont pas authentifiés et un attaquant peut donc en générer pour transmettre une fausse information. Si la MTU indiquée est plus grande que la réalité, les paquets seront jetés. Si elle est plus petite, on aura des sous-performances.

Autre problème de sécurité, le risque que certains administrateurs réseau incompétents ne filtrent tous les messages ICMP, donc également les Packet Too Big (c'est stupide, mais cela arrive). Dans ce cas, la découverte de la MTU du chemin ne fonctionnera pas (cf. RFC 4890 sur les recommandations concernant le filtrage ICMP). L'émetteur devra alors se rabattre sur des techniques comme celle du RFC 4821.

L'annexe B de notre RFC résume les changements faits depuis le RFC 1981. Rien de radical, les principaux portent sur la sécurité (ce sont aussi ceux qui ont engendré le plus de discussions à l'IETF) :

  • Bien expliquer les problèmes créés par le blocage des messages ICMP,
  • Formulations plus strictes sur la validation des messages ICMP,
  • Et surtout, suppression des « fragments atomiques » (RFC 8021).

Le texte a également subi une actualisation générale, les références (pré-)historiques à BSD 4.2 ou bien à TP4 ont été supprimées.

Enfin, pour faire joli, un exemple de traceroute avec recherche de la MTU du chemin activée (option --mtu). Notez la réception d'un Packet Too Big à l'étape 12, annonçant une MTU de 1 450 octets :

% sudo traceroute -6 --mtu --udp --port=53 eu.org
traceroute to eu.org (2a02:8428:46c:5801::4), 30 hops max, 65000 byte packets
 ...
 3  vl387-te2-6-paris1-rtr-021.noc.renater.fr (2001:660:300c:1002:0:131:0:2200)  2.605 ms  2.654 ms  2.507 ms
 4  2001:660:7903:6000:1::4 (2001:660:7903:6000:1::4)  5.002 ms  4.484 ms  5.494 ms
 5  neuf-telecom.sfinx.tm.fr (2001:7f8:4e:2::178)  4.193 ms  3.682 ms  3.763 ms
 6  neuf-telecom.sfinx.tm.fr (2001:7f8:4e:2::178)  14.264 ms  11.927 ms  11.509 ms
 7  2a02-8400-0000-0003-0000-0000-0000-1006.rev.sfr.net (2a02:8400:0:3::1006)  12.760 ms  10.446 ms  11.902 ms
 8  2a02-8400-0000-0003-0000-0000-0000-1c2e.rev.sfr.net (2a02:8400:0:3::1c2e)  10.524 ms  11.477 ms  11.896 ms
 9  2a02-8400-0000-0003-0000-0000-0000-1c2e.rev.sfr.net (2a02:8400:0:3::1c2e)  13.061 ms  11.589 ms  11.915 ms
10  2a02-8400-0000-0003-0000-0000-0000-117e.rev.sfr.net (2a02:8400:0:3::117e)  10.446 ms  10.420 ms  10.361 ms
11  2a02-8400-0000-0003-0000-0000-0000-000a.rev.sfr.net (2a02:8400:0:3::a)  10.460 ms  10.453 ms  10.517 ms
12  2a02-8428-046c-5801-0000-0000-0000-00ff.rev.sfr.net (2a02:8428:46c:5801::ff)  12.495 ms F=1450  12.102 ms  11.203 ms
13  2a02-8428-046c-5801-0000-0000-0000-0004.rev.sfr.net (2a02:8428:46c:5801::4)  12.397 ms  12.217 ms  12.507 ms

La question de la fragmentation en IPv6 a suscité d'innombrables articles. Vous pouvez commencer par celui de Geoff Huston.

Merci à Pierre Beyssac pour avoir fourni le serveur de test configuré comme il fallait, et à Laurent Frigault pour la solution sur FreeBSD.


Téléchargez le RFC 8201


L'article seul

RFC 8212: Default External BGP (EBGP) Route Propagation Behavior without Policies

Date de publication du RFC : Juillet 2017
Auteur(s) du RFC : J. Mauch (Akamai), J. Snijders (NTT), G. Hankins (Nokia)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 10 juillet 2017


Ce RFC est très court, mais concerne un problème fréquent sur l'Internet : les fuites de routes BGP. Traditionnellement, un routeur BGP acceptait par défaut toutes les routes, et annonçait par défaut à ses voisins toutes les routes qu'il connaissait. Il fallait une configuration explicite pour ne pas le faire. En cas d'erreur, ce comportement menait à des fuites (RFC 7908). Notre RFC normalise désormais le comportement inverse : un routeur BGP ne doit, par défaut, rien accepter et rien annoncer. Il faut qu'il soit configuré explicitement si on veut le faire.

Avec l'ancien comportement, la configuration de certains routeurs BGP, les plus imprudents, indiquait les pairs avec qui on échangeait de l'information, plus un certain nombre de routes qu'on n'envoyait pas. Si une erreur faisait qu'on recevait tout à coup des routes imprévues, on les acceptait, et on les renvoyait telles quelles, propageant la fuite (RFC 7908). Des cas fameux de fuites ne manquent pas (voir par exemple celle d'un opérateur malaisien). L'idée derrière ce comportement était d'assurer la connectivité du graphe de l'Internet. Aujourd'hui, on est plutôt plus sensibles aux risques de sécurité qu'à ceux de partitionnement du graphe, et les bonnes pratiques demandent depuis longtemps qu'on indique explicitement ce qu'on accepte et ce qu'on envoie. Voyez par exemple les recommandations de l'ANSSI.

En pratique, ce très court RFC ajoute juste deux paragraphes à la norme BGP, le RFC 4271. Dans sa section 9.1, les paragraphe en question disent désormais qu'il ne doit pas y avoir du tout d'exportation ou d'importation de routes, par défaut. Notez donc que cela ne change pas le protocole BGP, juste le comportement local.

Du moment qu'on change le comportement par défaut, il va y avoir un problème de transition (et ce point a soulevé des discussions à l'IETF). Si le logiciel du routeur s'adaptait au nouveau RFC, certains opérateurs seraient bien surpris que leurs routes ne soient tout coup plus annoncées. L'annexe A du RFC recommande une stratégie en deux temps :

  • D'abord introduire une nouvelle option « BGP non sécurisé » qui serait à Vrai par défaut (mais que les opérateurs pourraient changer), ce qui garderait le comportement actuel mais avec un avertissement émis quelque part « attention, vous exportez des routes sans décision explicite »,
  • Ensuite, dans la version suivante du logiciel, faire que cette option soit à Faux par défaut.

Les routeurs Cisco utilisant IOS-XR ont déjà ce comportement.

Et pour finir sur une note d'humour, à une réunion IETF (IETF 97), le projet qui a finalement mené à ce RFC était illustré… de photos de préservatifs. Pratiquez donc le BGP safe, l'Internet vous remerciera.


Téléchargez le RFC 8212


L'article seul

Les #MercrediFiction de Mastodon, techniques pour les traduire dans d'autres formats

Première rédaction de cet article le 9 juillet 2017


Une des pratiques les plus intéressantes de Mastodon est celle du #MercrediFiction. Le mercredi, des gens écrivent une fiction, a priori en moins de 500 caractères. Plusieurs personnes avaient demandé si on pouvait publier ces pouètes sous d'autres formats (la demande initiale était pour créer un « ebook »). J'ai donc fait un petit programme qui publie les pouètes #MercrediFiction en EPUB et HTML. Cet article, destiné à des programmeurs, explique les choix techniques et quelques problèmes rencontrés. Si vous n'êtes pas programmeur, n'hésitez pas à lire #MercrediFiction quand même !

Même moi, je m'y suis mis à en écrire. Et pour les récupérer ? Premier choix, j'ai décidé d'écrire le code en Python. J'ai utilisé la version 3 de Python (qui n'est pas compatible avec la précédente), la version 2 n'évoluant plus.

Comment récupérer les pouètes ayant le bon mot-croisillon ? La solution évidente est d'utiliser l'API de Mastodon, qui est bien documentée. Mais je la trouve trop compliquée pour mon goût, surtout question authentification (même si ce projet particulier n'a pas besoin d'authentification). J'ai donc décidé de déléguer cette tâche à l'excellent outil en ligne de commande madonctl. Récupérer les pouètes ayant le mot-croisillon #MercrediFiction et les exporter au format JSON se fait simplement avec :

    
% madonctl --output json timeline :MercrediFiction

Je ne sais pas exactement jusqu'où madonctl, ou plutôt l'API de Mastodon qu'il utilise, remonte dans le temps. Je fais donc plusieurs récupérations par jour, et je supprime ensuite les doublons.

Quelle instance utiliser pour récupérer les pouètes ? Dans une fédération, rien ne garantit que deux instances (deux nœuds Mastodon) ont le même contenu. L'algorithme exact qui détermine dans quel cas une instance a reçu un pouète n'est pas, à ma connaissance, documenté (sauf dans le code source, feront remarquer les libristes). Il semble que ce soit à peu près « on récupère les pouètes des gens qui sont sur mon instance, ainsi que ceux repouètés par quelqu'un de mon instance, ainsi que ceux émis par quelqu'un suivi par quelqu'un de mon instance ». Dans ce cas, il est clairement évident qu'il vaut mieux récupérer les pouètes sur une grosse instance, avec plein d'utilisateurs et plein de connexions avec d'autres instances. J'ai choisi Mamot, qui a ces caractéristiques, et est en plus géré par des gens bien.

Une fois le compte mercredifiction@mamot.fr créé, l'appel à madonctl me donne donc les pouètes en JSON. Qu'en faire à la fin de la journée ? (Au passage, le code est évidemment distribué sous une licence libre, et il est visible en https://github.com/bortzmeyer/MercrediFiction.)

Les deux formats que je crée actuellement, EPUB et HTML, utilisent tous les deux XHTML. Il faut donc traduire le JSON en XHTML, ce qui est trivial. J'utilise la bibliothèque officielle de Python pour analyser le JSON et, pour produire le XHTML, le module Yattag, dont le gros intérêt est que le gabarit est lui-même en Python : on n'utilise donc qu'un seul langage. Voici un exemple du code Python+Yattag utilisé pour produire le XHTML :

with tag('head'):
    with tag('link', rel = "stylesheet", type = "text/css", href = "mercredifiction.css"):
        pass
    with tag('title'):
        text("Mercredi Fiction %s" % datestr)
with tag('body'):
    with tag('h1'):
        text("Mercredi Fiction du %s" % formatdate(datestr, short=True))
    

Et le contenu du pouète lui-même ? L'API le distribue en HTML. Mais il y a deux pièges : c'est du HTML et pas du XHTML, et surtout rien ne garantit que l'instance n'enverra que du HTML sûr. Il y a un risque d'injection si on copie ce HTML aveuglément dans le document EPUB ou dans une page Web. Si demain l'instance envoie du JavaScript, on sera bien embêté.

Donc, première chose, traduire le HTML en XHTML. C'est simple, avec le module ElementTree (etree) de lxml :

    
from lxml import etree, html
...
tree = html.fromstring(content)
result = etree.tostring(tree, pretty_print=False, method="xml")
doc.asis(result.decode('UTF-8'))

(La fonction asis vient de Yattag et indique de mettre le contenu tel quel dans le document HTML, sans, par exemple, convertir les > en >.)

Et pour la sécurité ? On utilise un autre module de lxml, Cleaner :

    
from lxml.html.clean import Cleaner
...
cleaner = Cleaner(scripts=True, javascript=True, embedded=True, meta=True, page_structure=True,
                                      links=False, remove_unknown_tags=True,
                                      style=False)

Le code ci-dessus supprime de l'HTML le JavaScript, et plusieurs autres éléments HTML dangereux.

Voilà, on a désormais du XHTML propre et, espérons-le, sûr. Pour produire les pages Web, ça suffit. Mais, pour l'EPUB, c'est un peu plus compliqué. À ma connaissance, le format EPUB ne bénéficie pas d'une norme publique. J'ai donc dû me rabattre sur d'excellentes documentations comme le Epub Format Construction Guide qui explique bien la structure d'un fichier EPUB. Un fichier EPUB est un zip contenant entre autre des fichiers HTML. Le lecteur EPUB typique est bien plus strict que le navigateur Web typique, et il faut donc faire attention à l'HTML qu'on génère. Il faut aussi placer diverses métadonnées, en Dublin Core. En l'absence d'une norme disponible, certaines choses doivent être devinées (par exemple, mettre le fichier CSS dans l'EPUB et le manifeste ne suffit pas, il faut aussi le déclarer dans l'HTML, ou bien le fait que les compteurs du nombre de pages dans la table des matières semblent optionnels). Pour les programmeurs Python, il y a aussi cet exemple en Python.

Si vous écrivez un programme qui produit de l'EPUB, n'oubliez pas de valider l'EPUB produit. Cela peut se faire en ligne de commande avec le programme epubcheck :

% epubcheck mercredifiction-dernier.epub   
Validating using EPUB version 2.0.1 rules.
No errors or warnings detected.
epubcheck completed

Ou cela peut être vérifié en ligne, ce service utilisant le même programme.

Enfin, question EPUB, n'oubliez pas de servir les fichiers EPUB avec le bon type MIME, application/epub+zip, pour que le lecteur d'ebooks soit lancé automatiquement. Sur Apache, ça peut se faire avec la directive AddType application/epub+zip .epub.

Quelques petits détails amusants ou énervants, pour terminer. D'abord, l'API de Mastodon, pour des raisons qui m'échappent complètement (j'ai entendu des explications, mais toutes mauvaises), lorsque le pouète contient des emojis (comme 🌸 ou 🌤), renvoie non pas le caractère Unicode correspondant, mais du texte entre deux-points, par exemple :cherry_blossom: (ces textes viennent du système commercial Emoji One). Il n'y a absolument aucune raison d'utiliser ces séquences de texte. La bogue a été signalée mais pour l'instant sans résultat. J'avais envisagé de faire la conversion moi-même pour #MercrediFiction mais c'est trop complexe, vu la taille de la base des emojis, à moins d'installer le code très compliqué fourni par Emoji One.

Autre limite de la version actuelle de mon service, le fait que les images ne sont pas incluses. Rare sont les pouètes #MercrediFiction qui comportent des images, mais ce serait tout de même sympathique de les gérer proprement. L'EPUB et le HTML devraient sans doute être gérés différemment : dans le premier cas, le lecteur s'attend à un ebook autonome, fonctionnant sans connexion Internet, et il faut donc récupérer les images en local, et les mettre dans le fichier EPUB. Dans le second, il vaut sans doute mieux mettre un lien vers l'image originale (avec toutefois le risque que, si l'hébergement original disparait, on perde l'image).

Notez que récupérer les images présente quelques risques juridiques. En théorie, c'est pareil avec les textes (le droit d'auteur s'applique aux deux, et je dois avouer que je récolte les pouètes sans penser à ce problème) mais, en pratique, le risque de réclamation est plus élevé pour les images (demandez à n'importe quel hébergeur). Pour l'instant, je n'ai pas encore reçu de message d'un juriste me demandant de supprimer tel ou tel pouète.

Ah et, sinon, il existe un autre service de distribution, dont les sources (également en Python) sont disponibles.


L'article seul

RFC 8195: Use of BGP Large Communities

Date de publication du RFC : Juin 2017
Auteur(s) du RFC : J. Snijders, J. Heasley (NTT), M. Schmidt (i3D.net)
Pour information
Réalisé dans le cadre du groupe de travail IETF grow
Première rédaction de cet article le 1 juillet 2017


Le RFC 8092 a normalisé la notion de « grande communauté » BGP, des données attachées aux annonces de routes, plus grandes que les précédentes « communautés » et permettant donc de stocker davantage d'informations. Ce nouveau RFC explique à quoi peuvent servir ces grandes communautés et donne des exemples d'utilisation. Un document concret, qui ravira les opérateurs réseaux.

Le RFC original sur les communautés BGP était le RFC 1997, et il était accompagné d'un RFC 1998 présentant des cas concrets d'utilisation. C'est la même démarche qui est faite ici, de faire suivre le document de normalisation, le RFC 8092, d'un document décrivant des utilisations dans le monde réel (avec des expériences pratiques décrites à NANOG ou NLnog).

Un petit rappel des grandes communautés, d'abord (section 2 du RFC). Chaque communauté se compose de trois champs de quatre octets chacun. Le premier champ se nomme GA, pour Global Administrator, et sa valeur est le numéro de l'AS qui a ajouté cette communauté (rappelez-vous que les numéros d'AS font désormais quatre octets), ce qui assure l'unicité mondiale des communautés. Les deux autres champs portent les noms peu imaginatifs de Local Data Part 1 et Local Data Part 2. La plupart du temps, on se sert du premier pour identifier une fonction, et du second pour identifier les paramètres d'une fonction. Notez qu'il n'existe pas de standard pour ces deux champs locaux : comme leur nom l'indique, chaque AS les affecte comme il veut. Une même valeur peut donc avoir des significations différentes selon l'AS.

Le RFC contient plusieurs exemples, qui utilisent à chaque fois la même topologie : un transitaire, l'AS 65551, avec un client, l'AS 64497, qui est lui-même transitaire pour les AS 64498 et 64499, qui par ailleurs ont une relation de peering (en épais sur l'image) example-bgp-large-comm.png :

Notre RFC classe les communautés en deux catégories : celles d'information et celles d'action. Les premières servent à distribuer des informations qui ne modifieront pas le comportement des routeurs, mais pourront être utiles pour le déboguage, ou les statistiques. Un exemple est l'ajout d'une communauté pour indiquer dans quel pays on a appris telle route. Elles sont typiquement ajoutées par l'AS qui a défini ces informations, et il mettra donc son numéro d'AS dans le champ GA. Les secondes, les communautés d'action, servent à indiquer une action souhaitée. Elles sont définies par l'AS qui aura à agir, et mises dans le message BGP par un de ses pairs. Un exemple est une communauté pour indiquer à son pair quelle préférence on souhaite qu'il attribue à telle route.

La section 3 donne des exemples de communautés d'information. Le premier est celui où l'AS 66497 marque les routes qu'il a reçues avec une communauté qui indique le pays où la route a été apprise (le code pays utilisé est celui de ISO 3166-1). La fonction a reçu le numéro 1. Donc, la présence dans l'annonce BGP de la communauté 64497:1:528 indique une route apprise aux Pays-Bas, la communauté 64497:1:392 indique le Japon, etc. Le même opérateur peut aussi prévoir une fonction 2 pour indiquer la région (concept plus vaste que le pays), en utilisant les codes M.49 : 64497:2:2 dit que la route a été apprise en Afrique, 64497:2:150 en Europe et ainsi de suite. Rappelez-vous bien que la signification d'une fonction (et donc des paramètres qui suivent) dépend de l'AS (ou, plus rigoureusement, du champ GA). Il n'y a pas de standardisation des fonctions. Si vous voyez une communauté 65551:2:2, cela ne signifie pas forcément que la route vient d'Afrique : l'AS 65551 peut utiliser la fonction 2 pour tout à fait autre chose.

À part l'origine géographique d'une route, il est souvent utile de savoir si la route a été apprise d'un pair ou d'un transitaire. Le RFC donne l'exemple d'une fonction 3 où le paramètre 1 indique une route interne, 2 une route apprise d'un client, 3 d'un pair et 4 d'un transitaire. Ainsi, la communauté 64497:3:2 nous dit que la route vient d'un client de l'AS 64497.

Une même annonce de route peut avoir plusieurs communautés. Une route étiquetée 64497:1:528, 64497:2:150 et 64497:3:3 vient donc d'un pair aux Pays-Bas.

Et les communautés d'action (section 4 du RFC) ? Un premier exemple est celui où on indique à son camarade BGP de ne pas exporter inconditionnellement une route qu'on lui annonce (ce qui est le comportement par défaut de BGP). Mettons que c'est la fonction 4. (Vous noterez qu'il n'existe pas d'espace de numérotation de fonctions distinct pour les communautés d'information et d'action. On sait que la fonction 4 est d'action uniquement si on connait la politique de l'AS en question.) Mettons encore que l'AS 64497 a défini le paramètre comme étant un numéro d'AS à qui il ne faut pas exporter la route. Ainsi, envoyer à l'AS 64497 une route étiquetée 64497:4:64498 signifierait « n'exporte pas cette route à l'AS 64498 ». De la même façon, on peut imaginer une fonction 5 qui utilise pour cette non-exportation sélective le code pays. 64997:5:392 voudrait dire « n'exporte pas cette route au Japon ». (Rappelez-vous que BGP est du routage politique : son but principal est de permettre de faire respecter les règles du business des opérateurs.)

Je me permets d'enfoncer le clou : dans les communautés d'action, l'AS qui ajoute une communauté ne met pas son numéro d'AS dans le champ GA, mais celui de l'AS qui doit agir.

Un autre exemple de communauté d'action serait un allongement sélectif du chemin d'AS. On allonge le chemin d'AS en répétant le même numéro d'AS lorsqu'on veut décourager l'utilisation d'une certaine route. (En effet, un des facteurs essentiels d'une décision BGP est la longueur du chemin d'AS : BGP préfère le plus court.) Ainsi, l'exemple donné utilise la fonction 6 avec comme paramètre l'AS voisin où appliquer cet allongement (prepending). 64497:6:64498 signifie « ajoute ton AS quand tu exportes vers 64498 ».

Quand on gère un routeur BGP multihomé, influencer le trafic sortant est assez simple. On peut par exemple mettre une préférence plus élevée à la sortie vers tel transitaire. Influencer le trafic entrant (par exemple si on veut que le trafic vienne surtout par tel transitaire) est plus délicat : on ne peut pas configurer directement la politique des autres AS. Certains partenaires BGP peuvent permettre de définir la préférence locale (RFC 4271, section 5.1.5), via une communauté. Ici, le RFC donne l'exemple d'une fonction 8 qui indique « mets la préférence d'une route client [a priori une préférence élevée] », 10 une route de peering, 11 de transit et 12 une route de secours, à n'utiliser qu'en dernier recours (peut-être parce qu'elle passe par un fournisseur cher, ou bien de mauvaise qualité). Le paramètre (le troisième champ de la communauté) n'est pas utilisé. Alors, la communauté 64997:12:0 signifiera « AS 64997, mets à cette route la préférence des routes de secours [a priori très basse] ».

Le RFC suggère aussi, si le paramètre est utilisé, de le prendre comme indiquant la région où cette préférence spécifique est appliquée. Par exemple 64997:10:5 demandera à l'AS 64997 de mettre la préférence des routes de peering (10) à tous les routeurs en Amérique du Sud (code 5 de la norme M.49).

Attention, changer la préférence locale est une arme puissante, et sa mauvaise utilisation peut mener à des coincements (RFC 4264).

Dernier exemple donné par notre RFC, les souhaits exprimés à un serveur de routes (RFC 7947). Ces serveurs parlent en BGP mais ne sont pas des routeurs, leur seul rôle est de redistribuer l'information aux routeurs. Par défaut, tout est redistribué à tout le monde (RFC 7948), ce qui n'est pas toujours ce qu'on souhaite. Si on veut une politique plus sélective, certains serveurs de route documentent des communautés que les clients du serveur peuvent utiliser pour influencer la redistribution des routes. Notre RFC donne comme exemple une fonction 13 pour dire « n'annonce pas » (alors que cela aurait été le comportement normal) et une fonction 14 pour « annonce quand même » (si le comportement normal aurait été de ne pas relayer la route). Ainsi, 64997:13:0 est « n'annonce pas cette route par défaut » et 64997:14:64999 est « annonce cette route à l'AS 64999 ».

Vous voudriez des exemples réels ? Netnod avait annoncé que ces grandes communautés étaient utilisables sur leur AS 52005 :

  • 52005:0:0 Do not announce to any peer
  • 52005:0:ASx Do not announce to ASx
  • 52005:1:ASx Announce to ASx if 52005:0:0 is set
  • 52005:101:ASx Prepend peer AS 1 time to ASx
  • 52005:102:ASx Prepend peer AS 2 times to ASx
  • 52005:103:ASx Prepend peer AS 2 times to ASx

On trouve également ces communautés au IX-Denver, documentées ici (sous « Route Server B and C Communities ») ou au SIX (dans leur documentation). Il y a enfin cet exemple à ECIX. (Merci à Job Snijders et Pier Carlo Chiodi‏ pour les exemples.)

Voilà, à vous maintenant de développer votre propre politique de communautés d'information, et de lire la documentation de vos voisins BGP pour voir quelles communautés ils utilisent (communautés d'action).


Téléchargez le RFC 8195


L'article seul

RFC 8190: Updates to Special-Purpose IP Address Registries

Date de publication du RFC : Juin 2017
Auteur(s) du RFC : R. Bonica (Juniper Networks), M. Cotton (ICANN), B. Haberman (Johns Hopkins University), L. Vegoda (ICANN)
Première rédaction de cet article le 28 juin 2017


Le RFC 6890 avait créé un registre unique des préfixes d'adresses IP « spéciaux ». Ce nouveau RFC met à jour le RFC 6890, précisant et corrigeant quelques points.

Un préfixe « spécial » est juste un préfixe IP dédié à un usage inhabituel, et qui peut nécessiter un traitement particulier. Ainsi, les préfixes 203.0.113.0/24 et 2001:db8::/32 sont dédiés à la documentation, aux cours et exemples et, bien que n'étant pas traités différemment des autres préfixes par les routeurs, ne doivent normalement pas apparaitre dans un vrai réseau. Le RFC 6890 spécifie les deux registres de préfixes spéciaux, un pour IPv4 et un pour IPv6. Mais il y avait une ambiguité dans ce RFC, dans l'usage du terme « global ». Il n'est pas évident à traduire en français. Dans le langage courant, global/globalement, a surtout le sens de « le plus souvent/généralement », alors que, dans le contexte de l'Internet, ce serait plutôt dans le sens « valable pour tout point du globe ». Même en anglais, le terme est polysémique : il peut signifier que l'adresse IP est unique au niveau mondial ou bien il peut signifier que l'adresse est potentiellement joignable mondialement, et qu'un routeur peut donc faire suivre le paquet en dehors de son propre domaine. (La joignabilité effective, elle, dépend évidemment de l'état de BGP.) Le RFC 4291, dans sa section 2.5.4, n'est pas plus clair.

Reprenons l'exemple des préfixes de documentation. Dans les trois préfixes IPv4 de documentation (comme 203.0.113.0/24), les adresses ne sont pas uniques (chacun les alloue comme il veut et, vu le faible nombre d'adresses total, il y aura certainement des collisions) et, de toute façon, n'ont pas de signification en dehors d'un domaine : cela n'a pas de sens de transmettre des paquets ayant de telles adresses à ses partenaires. Pour le préfixe de documentation IPv6, 2001:db8::/32, c'est un peu plus compliqué car les adresses peuvent être quasi-uniques mondialement (si on prend la précaution de les tirer au sort dans le préfixe) mais, de toute façon, n'ont pas vocation à être joignables de partout et on ne transmet donc pas ces paquets à ses voisins.

Bref, notre nouveau RFC choisit d'être plus précis, renommant l'ancien booléen « global » du RFC 6890 en « globally reachable ».

La nouvelle définition (section 2) est donc bien « le paquet ayant cette adresse comme destination peut être transmis par un routeur à un routeur d'un autre domaine (d'un autre opérateur, en pratique) ». La colonne Global du registre est donc remplacée par Globally reachable. Notez qu'il n'y a pas de colonne « Unicité » (une autre définition possible de global).

Cela a nécessité quelques changements supplémentaires dans le registre (toujours section 2), colonne Globally reachable :

  • Le préfixe Teredo 2001::/32 passe de False (les adresses Teredo ne sont pas uniques) à N/A (Not Applicable) car la question de la joignabilité mondiale n'a pas vraiment de sens pour Teredo,
  • Les ULA du RFC 4193 restent à False mais avec une précision en note.

Téléchargez le RFC 8190


L'article seul

Fiche de lecture : La face cachée d'Internet

Auteur(s) du livre : Rayna Stamboliyska
Éditeur : Larousse
978-2-03-593641-7
Publié en 2017
Première rédaction de cet article le 28 juin 2017


Vous allez peut-être vous dire, en prenant connaissance du sous-titre (« hackers, darkweb, Tor, Anonymous, WikiLeaks, bitcoins… ») et surtout en voyant la couverture un peu tape-à-l'œil, que c'est juste le Nième livre sur les gros méchants cyberaffreux des bas-fonds du réseau, ceux qui font sauter une centrale nucléaire en tapotant sur un smartphone, ceux que le gentil ministre va heureusement bientôt civiliser. Des livres de ce genre, sensationnalistes, bourrés d'erreurs qui amusent les geeks et égarent les lecteurs innocents, il y en a plein. Mais celui-ci est différent :

  • Il est écrit par une auteure qui connait son (ou plutôt ses) sujets,
  • Il ne contient pas d'erreurs (ou alors je ne les ai pas trouvées),
  • Il essaie de tout expliquer sans simplifier et sans prendre le lecteur pour un ahuri.

Le cahier des charges était donc difficile. Les éditions Larousse font des livres à destination du grand public (le célèbre M. Michu). Souvent, « mais c'est pour le grand public » sert d'excuse pour bâcler le travail. Or, cela devrait être le contraire : comme M. Michu n'a pas les connaissances nécessaires pour corriger de lui-même les erreurs, il faut être plus rigoureux et plus précis quand on écrit pour le grand public. L'auteure n'a pas écrit pour toi, lecteur typique de mon blog ou, plutôt, pas que pour toi.

On trouve très peu de livres ayant un cahier des charges analogue. Soit on fait du purement technique, pour informaticiens, soit on fait du Paris Match. C'est ce que j'apprécie le plus dans le travail de Rayna Stamboliyska, l'effort pour être claire et pédagogue, sans être approximative et baratineuse.

Est-ce réussi ? Je vais laisser l·a·e lect·rice·eur en juger. Personnellement, je trouve que le livre est riche, plein d'informations, et que M. Michu va devoir faire un effort pour suivre ces nombreux personnages et ces rebondissements multiples (notamment dans le chapitre sur WikiLeaks). D'autant plus qu'on trouve dans ce livre des choses qu'on s'attend plus à voir dans un ouvrage universitaire (ma préférée est le double espace de numérotation des références, un en romain pour des notes de bas de page, un autre en italique pour la bibliographie à la fin) Mais, justement, je ne pense pas que M. Michu soit un imbécile et demander un travail au lecteur ne me choque pas.

Ah, et puisque j'ai parlé de la bibliographie : recopier à la main des URL est évidemment pénible et provoque souvent des erreurs. Donc, pour accéder aux nombreux textes cités, et pour d'autres raisons, je recommande que vous visitiez le site Web officiel attaché au livre. Quelques autres références :

Avertissement : je suis l'auteur de la préface, et j'ai reçu un exemplaire gratuit. Je ne suis donc pas neutre.

Un dernier mot, pour les programmeurs : il y a deux fautes dans le code en C sur la couverture. Cherchez.


L'article seul

Les drôles de pratiques BGP d'un opérateur bulgare et d'une université colombienne

Première rédaction de cet article le 26 juin 2017


Aujourd'hui, nous allons un peu regarder un drôle de problème BGP, et en n'utilisant que des sources ouvertes. L'infrastructure de l'Internet est en effet largement ouverte aux investigations.

Alors, d'abord, le premier fait : l'opérateur bulgare Wireless Network Solutions annonçait en BGP un grand nombre de routes assez éloignées de ce qu'on attendrait de lui. L'annonce a cessé le 7 juin mais on peut toujours voir les anciennes annonces dans ce fichier issu de RIPE stat ou directement sur RIPE Stat : announces-as34991.png

Parmi les préfixes annoncés, on trouvait en effet des valeurs comme 168.176.219.0/24. Or, l'AS 34991 est situé en Bulgarie (ici, les données complètes, obtenues via whois). Alors que le préfixe 168.176.219.0/24 fait partie du 168.176.0.0/16 alloué à l'Université nationale de Colombie (ici, les données complètes via whois). Pourquoi donc un opérateur situé dans une petite ville de Bulgarie aurait-il comme client une université à Bogota ? Les liens économiques, historiques, linguistiques ou religieux, entre la Bulgarie et la Colombie semblent faibles. Creusons.

L'Université nationale de Colombie dispose d'un préfixe IPv4 de longueur 16 (cf. les données citées plus haut) mais ne l'annonce pas en BGP. On ne le voit pas sur RIPE stat, ou sur le looking glass de Hurricane Electric. Des sous-préfixes sont annoncés mais pas le /16 complet. Voyons sur RouteViews en telnet :

% telnet route-views.routeviews.org
Trying 2001:468:d01:33::80df:3367...
Connected to route-views.routeviews.org.
...
User Access Verification

Username: rviews

route-views>show ip route 168.176.219.0   
% Subnet not in table

route-views>show ip route 168.176.0.0  
Routing entry for 168.176.0.0/16, 46 known subnets
  Variably subnetted with 7 masks
B        168.176.0.0/18 [20/0] via 66.110.0.86, 2d02h
B        168.176.64.0/19 [20/0] via 66.110.0.86, 2d02h
B        168.176.72.0/22 [20/0] via 66.110.0.86, 2d02h
B        168.176.76.0/24 [20/0] via 66.110.0.86, 2d02h
...
    

Donc, l'université colombienne n'annonce qu'une petite partie de son /16. À une époque où tout le monde souffre de la pénurie d'adresses IPv4, c'est un peu curieux. L'annonce du sous-préfixe 168.176.219.0/24 par l'AS 34991 n'est donc pas un détournement BGP classique comme l'étaient ceux par Telekom Malaysia en 2015 ou bien lors du shunt de 2013. « Aucun préfixe BGP n'a été détourné pour le tournage de ce film. » Néanmoins, il ne semble pas non plus que cette annonce, qui n'a duré que dix jours, ait été légitime, à moins que le campus de Medellín n'ait eu envie pendant dix jours d'être connecté à l'Internet via la Bulgarie ? Une autre hypothèse, qui ne peut être formulée que par des gens pratiquant la méchanceté gratuite, serait que l'université a loué des /24 à des spammeurs bulgares…

Certains ont émis l'hypothèse que l'AS bulgare avait été pris par des méchants, à l'occasion d'une attaque flamant. Une attaque flamant est l'enregistrement d'un domaine qui n'existait pas, pour récupérer le courrier, y compris les demandes d'autorisation, d'un objet dont les contacts utilisaient des domaines disparus, ou mal enregistrés. Un exemple d'attaque flamant pour des TLD est par exemple documentée ici. La (je crois) première description publique date de 2007.

Les contacts techniques et administratifs de l'AS sont en @wirelessnetbg.info. Ils ont été modifiés juste avant les annonces bizarres, et le domaine créé peu de temps avant ces annonces (cf. les données récupérées par whois, le champ Creation Date). Mais rien ne prouve (en tout cas avec des données ouvertes) qu'il y a eu une attaque flamant contre l'AS, bien qu'elle soit possible. Notez enfin que l'entreprise derrière l'AS ne semble pas exister dans le registre des entreprises en Bulgarie.

Merci à Ronald F. Guilmette pour avoir détecté le cas et l'avoir publié, et à Rayna Stamboliyska pour des investigations.


L'article seul

RFC 8126: Guidelines for Writing an IANA Considerations Section in RFCs

Date de publication du RFC : Juin 2017
Auteur(s) du RFC : M. Cotton (ICANN), B. Leiba (Huawei Technologies), T. Narten (IBM Corporation)
Première rédaction de cet article le 21 juin 2017


Un aspect peu connu du travail de normalisation est la nécessité de tenir des registres de certains paramètres, lorsque la liste de ces derniers n'est pas fixée dans un RFC. Par exemple, les algorithmes publiés dans le DNS pour IPsec ne sont pas définis de manière limitative dans le RFC 4025 mais sont enregistrés dans un registre public. Même chose pour les types de média du RFC 6838, qui ont leur propre registre. Pour les RFC, ces registres sont tenus par l'IANA. Celle-ci ne décide pas quels registres elle doit tenir ni à quelle condition un nouveau paramètre peut y rentrer, elle applique les décisions contenues dans la section IANA Considerations d'un RFC. C'est cette section qui est décrite ici. Ce RFC remplace l'ancien RFC 5226.

Prenons l'exemple du RFC 3315 (DHCP). Sa section 24 contient le texte « This document defines several new name spaces associated with DHCPv6 and DHCPv6 options: Message types, Status codes, DUID and Option codes. IANA has established a registry of values for each of these name spaces, which are described in the remainder of this section. These name spaces will be managed by the IANA and all will be managed separately from the name spaces defined for DHCPv4. ». En application de ce texte, l'IANA a créé le registre DHCPv6 and DHCPv6 options qu'on peut consulter en ligne à https://www.iana.org/assignments/dhcpv6-parameters. Et comment ajoute-t-on des entrées dans ce registre ? En suivant les règles données dans ce même RFC : «  New DHCP option codes are tentatively assigned after the specification for the associated option, published as an Internet Draft, has received expert review by a designated expert [11]. The final assignment of DHCP option codes is through Standards Action, as defined in RFC 2434.  ».

L'intérêt d'avoir une section obligatoire IANA Considerations est de concentrer en un seul endroit les informations nécessaires à l'IANA pour faire son travail. Pour aider les auteurs de RFC à écrire correctement cette section IANA Considerations, notre RFC 8126, qui succède au RFC 5226, pose quelques règles.

La section 1 du RFC décrit le problème général de la gestion d'un espace de nommage (namespace). Tous ces espaces n'ont pas les mêmes caractéristiques. Certains sont très petits (le champ protocole, qui n'a que huit bits soit 256 valeurs possibles, cf. RFC 5237) et doivent donc être gérés avec prudence, certains sont hiérarchiques comme le DNS ou comme les OID et peuvent donc être délégués, certains sont immenses, et peuvent être gérés avec moins de précautions (mais nécessitent quand même des règles, comme expliqué dans la section 1).

Cette même section 1 résume les points essentiels que doit connaitre l'auteur d'un RFC, notamment d'avoir une section dédiée IANA Considerations, et de n'y mettre que ce qui est strictement nécessaire à l'IANA (pas de digressions, pas de détails techniques).

La section 2 est consacrée à la création d'un nouveau registre. Il y a bien des décisions à prendre à ce stade. Par exemple, notre RFC recommande de voir si on ne peut pas faire un registre arborescent, où l'action de l'IANA se limiterait à la racine de ce registre, diminuant ainsi sa charge de travail. (C'est le cas des URN du RFC 8141.)

Si un RFC doit demander une telle création, il doit préciser quelle politique d'enregistrement devra suivre l'IANA. C'est une des parties les plus intéressantes du RFC, notamment sa section 4 qui explique les politiques possibles :

  • Premier Arrivé, Premier Servi (« First Come First Served »), où toute requête est acceptable et est faite dans l'ordre d'arrivée. Les entrées dans le préfixe OID iso.org.dod.internet.private.enterprise sont un bon exemple (https://www.iana.org/assignments/enterprise-numbers mais attention, le registre est lourd à charger). C'est aussi le cas des plans d'URI provisoires (RFC 7595) ou des états de traitement du courrier (RFC 6729). C'est sans doute la plus « libérale » des politiques d'enregistrement. (Il n'y a pas de mécanisme explicite contre les vilains qui enregistreraient plein de valeurs inutiles, avait noté l'examen de sécurité.)
  • Examen par un expert (« Expert review »), comme détaillé plus bas (section 5 du RFC). C'est ainsi que sont gérés les plans des URI permanents du RFC 7595, ou bien les types de méthode d'EAP (RFC 3748, sections 6 et 7.2, notez que Expert review était appelé Designated expert à cette époque).
  • Spécification nécessaire (« Specification required ») où un texte écrit et stable décrivant le paramètre souhaité est nécessaire (ce texte n'est pas forcément un RFC, il y a d'ailleurs une politique « RFC required »). Il faut en outre un examen par un expert, comme dans la politique ci-dessus, l'expert vérifiant que la spécification est claire. Les profils de ROHC (RFC 5795) sont enregistrées sous cette condition. Les utilisations de certificat de DANE (RFC 6698, section 7.2) sont « RFC nécessaire ».
  • Examen par l'IETF (« IETF Review »), l'une des plus « lourdes », puisqu'il faut un RFC « officiel », qui soit passé par l'IESG ou par un groupe de travail IETF (tous les RFC ne sont pas dans ce cas, certains sont des contributions individuelles). C'est la politique des extensions TLS du RFC 6066 (cf. RFC 5246, section 12, qui utilisait encore l'ancien terme de « IETF Consensus »).
  • Action de normalisation (« Standards Action »), encore plus difficile, le RFC doit être sur le chemin des normes et donc avoir été approuvé par l'IESG. C'est le cas par exemple des types de message BGP (RFC 4271, section 4.1), en raison de la faible taille de l'espace en question (un seul octet, donc un nombre de valeurs limité) et sans doute aussi en raison de l'extrême criticité de BGP. C'est aussi la politique pour les options DHCP données en exemple plus haut.
  • Utilisation privée (« Private use ») est une politique possible, qui est en fait l'absence de registre, et donc l'absence de politique de registre : chacun utilise les valeurs qu'il veut. Par exemple, dans le protocole TLS (RFC 5246, section 12), les valeurs 224 à 255 des identifiants numériques du type de certificat sont à usage privé ; chacun s'en sert comme il veut, sans coordination.
  • Utilisation à des fins expérimentales (« Experimental use »), est en pratique la même chose que l'utilisation privée. La seule différence est le but (tester temporairement une idée, cf. RFC 3692). C'est le cas des valeurs des en-têtes IP du RFC 4727.
  • Et il existe encore l'approbation par l'IESG (« IESG approval ») qui est la politique de dernier recours, à utiliser en cas de cafouillage du processus.
  • Et le cas un peu particulier de l'allocation hiérarchique (« Hierarchical allocation ») où l'IANA ne gère que le registre de plus haut niveau, selon une des politiques ci-dessus, déléguant les niveaux inférieurs à d'autres registres. C'est le cas par exemple des adresses IP ou bien sûr des noms de domaine.

Le choix d'une politique n'est pas évident : elle ne doit pas être trop stricte (ce qui ferait souffrir les auteurs de protocoles, confrontés à une bureaucratie pénible) mais pas non plus trop laxiste (ce qui risquerait de remplir les registres de valeurs inutiles, les rendant difficilement utilisables). En tout cas, c'est une des décisions importantes qu'il faut prendre lors de l'écriture d'une spécification.

Notre RFC conseille (sans l'imposer) d'utiliser une de ces politiques (« well-known policies »). Elles ont été testés en pratique et fonctionnent, concevoir une nouvelle politique fait courir le risque qu'elle soit incohérente ou insuffisamment spécifiée, et, de toute façon, déroutera les lecteurs et l'IANA, qui devront apprendre une nouvelle règle.

Parmi les autres points que doit spécifier le RFC qui crée un nouveau registre, le format de celui-ci (section 2.2 ; la plupart des registres sont maintenus en XML, mais même dans ce cas, des détails de syntaxe, comme les valeurs acceptables, peuvent devoir être précisés). Notez que le format n'est pas forcément automatiquement vérifié par l'IANA. Notre RFC recommande également de bien préciser si le registre accepte des caractères non-ASCII (cf. RFC 7564, section 10).

Autre choix à faire dans un registre, le pouvoir de changer les règles (change control). Pour des normes IETF (RFC sur le chemin des normes), c'est en général l'IETF qui a ce pouvoir, mais des registres IANA peuvent être créés pour des protocoles qui ne sont pas gérés par l'IETF et, dans ce cas, le pouvoir peut appartenir à une autre organisation. C'est ainsi que les types de données XML (RFC 7303), comme le application/calendar+xml (RFC 6321) sont contrôlés par le W3C.

La section 3 couvre l'enregistrement de nouveaux paramètres dans un registre existant. C'est elle qui précise, entre autres, que l'IANA ne laisse normalement pas le choix de la valeur du paramètre au demandeur (mais, en pratique, l'IANA est sympa et a accepté beaucoup de demandes humoristiques comme le port TCP n° 1984 pour le logiciel Big Brother...)

La section 6 donne des noms aux différents états d'enregistrement d'une valeur. Le registre note l'état de chaque valeur, parmi ces choix :

  • Réservé à une utilisation privée,
  • Réservé à une utilisation expérimentale,
  • Non affecté (et donc libre),
  • Réservé (non alloué mais non libre, par exemple parce que la norme a préféré le garder pour de futures extensions),
  • Affecté,
  • Utilisation connue, mais non officiellement affecté, ce qui se produit parfois quand un malotru s'approprie des valeurs sans passer par les procédures normales, comme dans le cas du RFC 8093.

Par exemple, si on prend les types de messages BGP, on voit dans le registre que 0 est réservé, les valeurs à partir de 6 sont libres, les autres sont affectées (1 = OPEN, etc).

La section 5 décrit le rôle des experts sur lesquels doit parfois s'appuyer l'IANA. Certains registres nécessitent en effet un choix technique avec l'enregistrement d'un nouveau paramètre et l'IANA n'a pas forcément les compétences nécessaires pour cette évaluation. Elle délègue alors cette tâche à un expert (designated expert, leur nom est noté à côté de celui du registre). Par exemple, pour le registre des langues, défini par le RFC 5646, l'expert actuel est Michael Everson. Ce registre utilise également une autre possibilité décrite dans cette section, une liste de discussion qui sert à un examen collectif des requêtes (pour le registre des langues, cette liste est ietf-languages@iana.org). La section 5.1 discute des autres choix qui auraient pu être faits (par exemple un examen par le groupe de travail qui a créé le RFC, ce qui n'est pas possible, les groupes de travail IETF ayant une durée de vie limitée). Elle explique ensuite les devoirs de l'expert (comme la nécessité de répondre relativement rapidement, section 5.3, chose qui est loin d'être toujours faite).

Enfin, diverses questions sont traitées dans la section 9, comme la récupération de valeurs qui avaient été affectées mais qui ne le sont plus (le RFC 3942 l'avait fait mais c'est évidemment impossible dès que les paramètres en question ont une... valeur, ce qui est le cas entre autres des adresses IP).

Bien que la plupart des allocations effectuées par l'IANA ne sont guère polémiques (à l'exception des noms de domaine et des adresses IP, qui sont des sujets très chauds), notre RFC 8126 prévoit une procédure d'appel, décrite en section 10. Cela n'a pas suffit à régler quelques cas pénibles comme l'enregistrement de CARP.

Ce RFC 8126 remplace le RFC 5226. Les principaux changements sont détaillés dans la section 14.1 :

  • Moins de texte normatif style RFC 2119, puisqu'il ne s'agit pas de la description d'un protocole,
  • Meilleure description des registres hiérarchiques,
  • Ajout d'une partie sur le pouvoir de changer les règles (change control),
  • Ajout de la possibilité de fermer un registre,
  • Ajout de la section 8 sur le cas de RFC qui remplacent un RFC existant,
  • Etc.

Notez que notre RFC est également complété en ligne par des informations plus récentes.

Les relations entre l'IETF et l'IANA sont fixées par le MOU contenu dans le RFC 2860. À noter que tout n'est pas couvert dans ce RFC, notamment des limites aux demandes de l'IETF. Que se passerait-il par exemple si l'IETF demandait à l'IANA, qui ne facture pas ses prestations, de créer un registre de milliards d'entrées, très dynamique et donc très coûteux à maintenir ? Pour l'instant, l'IANA ne peut pas, en théorie, le refuser et la question s'est parfois posée à l'IETF de savoir si tel ou tel registre n'était pas trop demander.

Puisque l'IANA est un acteur important de l'Internet, rappelons aussi que, bien que la fonction de l'IANA soit actuellement assurée par l'ICANN, la tâche de gestion des protocoles et des registres n'a rien à voir avec les activités, essentiellement politiciennes, de l'ICANN. La « fonction IANA » (création et gestion de ces registres) est formellement nommée IFO (IANA Functions Operator) ou IPPSO (IANA Protocol Parameter Services Operator) mais tout le monde dit simplement « IANA ».


Téléchargez le RFC 8126


L'article seul

Sur une panne DNS, et sur les leçons à en tirer (BNP Paribas)

Première rédaction de cet article le 20 juin 2017
Dernière mise à jour le 22 juin 2017


Ce matin du 20 juin, plein de messages sur les réseaux sociaux pour se plaindre d'une impossibilité d'accéder aux services en ligne de BNP Paribas. Le CM a bien du mal à répondre à tout le monde. À l'origine de cette panne, un problème DNS. Que s'est-il passé et pourquoi ?

Les noms de domaine utilisés par BNP Paribas sont tous dans le TLD .bnpparibas. On peut facilement vérifier que ce TLD va bien (un seul serveur ne répond pas) :

% check-soa -i bnpparibas
a0.nic.bnpparibas.
	2a01:8840:3e::9: OK: 1000002072 (241 ms)
	65.22.64.9: OK: 1000002072 (91 ms)
a2.nic.bnpparibas.
	65.22.67.9: OK: 1000002072 (3 ms)
	2a01:8840:41::9: OK: 1000002072 (3 ms)
b0.nic.bnpparibas.
	2a01:8840:3f::9: OK: 1000002072 (19 ms)
	65.22.65.9: OK: 1000002072 (27 ms)
c0.nic.bnpparibas.
	2a01:8840:40::9: OK: 1000002072 (21 ms)
	65.22.66.9: ERROR: read udp 10.10.86.133:33849->65.22.66.9:53: i/o timeout
    

Mais c'est en dessous qu'il y a des problèmes. En raison de règles ICANN absurdes, les noms publiés sont tous des sous-domaines de .bnpparibas, délégués à deux serveurs de noms :


% dig @a2.nic.bnpparibas. NS mabanqueprivee.bnpparibas
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51136
...
;; AUTHORITY SECTION:
mabanqueprivee.bnpparibas. 86400 IN NS sns5.bnpparibas.net.
mabanqueprivee.bnpparibas. 86400 IN NS sns6.bnpparibas.net.
...
;; SERVER: 2a01:8840:41::9#53(2a01:8840:41::9)
;; WHEN: Tue Jun 20 09:55:22 CEST 2017

    

Et, de ces deux serveurs de noms, l'un n'existe pas, l'autre est en panne (ou bien victime d'une attaque par déni de service) :

% check-soa -i -ns sns5.bnpparibas.net\ sns6.bnpparibas.net mabanqueprivee.bnpparibas
sns5.bnpparibas.net.
	159.50.249.65: ERROR: read udp 10.10.86.133:57342->159.50.249.65:53: i/o timeout
sns6.bnpparibas.net.
	Cannot get the IPv4 address: NXDOMAIN
    

On peut aussi tester avec dig, si vous préférez :


% dig @sns5.bnpparibas.net. NS mabanquepro.bnpparibas

; <<>> DiG 9.10.3-P4-Debian <<>> @sns5.bnpparibas.net. NS mabanquepro.bnpparibas
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

% dig @sns6.bnpparibas.net. NS mabanquepro.bnpparibas
dig: couldn't get address for 'sns6.bnpparibas.net.': not found

    

C'est assez étonnant. Un des deux serveurs n'existe même pas dans le DNS. D'après DNSDB, il n'a même jamais existé ! Tous les noms de BNP Paribas (mabanqueprivee.bnpparibas, mabanquepro.bnpparibas, etc) dépendaient donc d'un seul serveur, qui a défailli ce matin.

Résultat, les utilisateurs ne pouvaient pas résoudre le nom en adresse et donc pas accéder au site Web ou à l'API. On le voit avec les sondes RIPE Atlas :

% atlas-resolve -r 100 mabanqueprivee.bnpparibas.
[ERROR: SERVFAIL] : 48 occurrences 
[TIMEOUT(S)] : 50 occurrences 
Test #8925333 done at 2017-06-20T07:55:45Z
    

La reprise a été partielle (plusieurs serveurs anycastés ? Attaque par déni de service qui se calme ?), un peu plus tard, on voit que certaines sondes réussissaient :

    
% atlas-resolve -r 100 mabanquepro.bnpparibas.
[159.50.188.21] : 3 occurrences 
[ERROR: SERVFAIL] : 51 occurrences 
[TIMEOUT(S)] : 40 occurrences 
Test #8925337 done at 2017-06-20T07:58:24Z

Pour le serveur inexistant, l'explication m'a été donnée par un anonyme (que je remercie beaucoup) : le vrai nom est sns6.bnpparibas.FR (et pas .NET). Ce serveur existe bien, répond, et fait en effet autorité pour les zones de la banque. Lors de la délégation de la plupart des sous-domaines, c'est simplement un mauvais nom qui a été indiqué !

Tout ceci n'est pas très conforme aux bonnes pratiques (telles qu'elles sont régulièrement rappelées, par exemple, dans le rapport annuel sur la résilience de l'Internet français) :

  • Deux serveurs DNS faisant autorité, ce n'est en général pas assez (surtout si un des deux n'existe en fait pas),
  • Les serveurs doivent être supervisés. Icinga ou Zabbix auraient prévenu depuis longtemps qu'un des deux serveurs ne marchait pas.
  • Les configurations DNS doivent être testées, par exemple avec Zonemaster.
  • Le TTL renvoyé par le serveur, lorsqu'il marche, est de seulement 30 secondes. C'est très insuffisant. En cas de panne imprévue, il faut facilement plusieurs heures pour réparer (l'essentiel du temps étant consacré à paniquer en criant).

Notez que, deux jours après la panne, rien n'a été réparé :

  • Les zones n'ont toujours qu'un seul serveur (celui inexistant ne comptant évidemment pas),
  • En prime, l'unique serveur répond incorrectement (il accepte les requêtes DNS de type A mais pas celles de types NS ou SOA).

Ces erreurs sont clairement visible sur les programmes de test DNS comme Zonemaster ou bien DNSviz.


L'article seul

Sur la communication quantique (et les exagérations)

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


Dans un article publié dans Science, un groupe de chercheurs annonce avoir réussi à transporter des photons intriqués sur plus de mille kilomètres. Mais ce n'est pas cette avancée scientifique intéressante que je veux commenter, mais les grossières exagérations avec lesquelles elle a été annoncée, notamment la promesse ridicule que la communication quantique allait donner un Internet plus sûr, voire un « Internet inviolable » (comme dit dans l'article sensationaliste de l'Express).

L'article en question promet en effet, outre l'Internet inviolable, de la téléportation, des « ordinateurs dotés d'une puissance de calcul sans commune mesure avec les plus puissantes machines actuelles » et même « un Internet basé à l'avenir sur les principes de la physique quantique ». Revenons au monde réel. L'article originel est bien plus modeste. (Au passage, il n'est pas disponible en ligne, car où irait-on si tout le monde pouvait accéder facilement aux résultats scientifiques ? Heureusement, on le trouve sur Sci-Hub, qu'on ne remerciera jamais assez.) Les auteurs ont réussi à transmettre des photons intriqués sur une distance plus grande que ce qui avait été fait avant. Beau résultat (l'opération est très complexe, et est bien décrite dans leur article) mais en quoi est-ce que ça nous donne un Internet inviolable ? L'idée est que la communication quantique est à l'abri de l'écoute par un tiers, car toute lecture, même purement passive, casserait l'intrication et serait facilement détectée. Sa sécurité est donc physique et non plus algorithmique. La NSA serait donc réduite au chômage ? C'est en tout cas ce que promet l'Express…

Il y a plusieurs raisons pour lesquelles cette promesse est absurde. La plupart de ces raisons découlent d'un fait simple que le journaliste oublie complètement dans son article : la communication de point à point n'est qu'une partie du système technique complexe qui permet à Alice et Bob de s'envoyer des messages de manière sécurisée. Si on ne considère pas la totalité de ce système, on va se planter. D'abord, citons « l'argument de Schneier », écrit il y a plus de huit ans et toujours ignoré par les vendeurs de solutions quantiques : la communication quantique ne sert à rien, pas parce qu'elle ne marche pas (au contraire, les progrès sont importants) mais parce qu'elle sécurise ce qui était déjà le maillon le plus fort du système. Quant on veut surveiller les gens, la plupart du temps, on ne va pas casser la cryptographie qui les protège. On va faire plus simple : exploiter une faille du protocole de communication, ou une bogue du logiciel qui le met en œuvre, ou tout simplement récupérer l'information à une des deux extrêmités (il ne sert à rien de faire de la communication quantique avec Google si Google fournit toutes vos données à la NSA). Avant de remplacer la cryptographie classique, il faudrait déjà sécuriser tous ces points. Autrement, le surveillant et l'espion, qui sont des gens rationnels, continueront à attaquer là où la défense est faible. Déployer de la communication quantique, c'est comme utiliser un camion blindé pour transmettre de l'argent entre deux entrepôts dont les portes ne ferment pas à clé. (C'est d'autant plus important que la communication quantique n'est pas de bout en bout : elle n'arrive pas jusqu'aux PC d'Alice et Bob.)

Et ce n'est pas la seule faiblesse de la communication quantique. La plus importante, à mon avis, est qu'elle n'authentifie pas. Vos messages ne peuvent pas être interceptés mais vous ne pouvez pas être sûr de savoir à qui vous parlez. Vous avez une communication sécurisée avec… quelqu'un, c'est tout. Cela rend la communication quantique très vulnérable à l'attaque de l'Homme du Milieu. Il existe bien sûr des remèdes contre cette attaque, mais tous dépendent de la cryptographie classique, avec ses faiblesses.

En parlant de cryptographie classique, notons aussi que la communication quantique est limitée à la distribution de clés. Vous avez toujours besoin d'un algorithme classique (comme AES) pour chiffrer.

Autre limite de la communication quantique : elle protège le canal, pas les données. Une fois les données « au repos » (sur les disques durs des ordinateurs d'Alice et Bob), elles sont aussi vulnérables qu'avant. Un piratage avec fuite de données (comme Ashley Madison, Yahoo, Sony…) se ferait aussi bien avec communication quantique que sans.

Qu'y avait-il encore comme promesses dénuées de sens dans l'article de l'Express ? Ah, oui, « des ordinateurs dotés d'une puissance de calcul sans commune mesure avec les plus puissantes machines actuelles ». Ici, il semble que l'auteur ait confondu la communication quantique avec le calcul quantique, qui n'a rien à voir. Et quant à la téléportation, elle relève plus de la science-fiction : l'expérience décrite dans Science n'a rien à voir avec de la téléportation, même limitée.

Voilà, comme d'habitude, on a une avancée scientifique réelle, décrite dans un article sérieux mais que personne ne lira, sur-vendue dans un dossier de presse aguicheur, lui-même repris sans critique et sans vérification dans de nombreux médias. Vu l'information reçue par les citoyens ordinaires, il n'est pas étonnant que la sécurité informatique soit actuellement si mauvaise.


L'article seul

dnstap, un journal de l'activité d'un serveur DNS

Première rédaction de cet article le 8 juin 2017


Comment voir en temps réel l'activité d'un serveur DNS, les requêtes qu'il reçoit et les réponses qu'il envoie ? Il existe plusieurs méthodes, cet article présent rapidement la plus récente, dnstap.

Est-ce que je présente d'abord dnstap, ou d'abord les autres solutions, afin d'expliquer leurs faiblesses et de dire pourquoi dnstap a été développé ? Je choisis d'être positif et de commencer par les bonnes choses : dnstap, ce qu'il fait, et comment.

dnstap est un moyen d'obtenir un flux d'informations de la part d'un serveur DNS (qu'il s'agisse d'un résolveur ou bien d'un serveur faisant autorité). Le serveur doit être modifié pour journaliser son activité, et configuré ensuite pour émettre un flux dnstap. Typiquement, ce flux est envoyé vers une prise Unix, où un lecteur dnstap l'attendra pour stocker ce flux, ou pour le formater et l'afficher joliment. Ce flux est encodé en Protocol Buffers, eux-mêmes transportés dans des Frame Streams.

C'est pas assez concret ? OK, alors jouons un peu avec un résolveur DNS, Unbound. On le configure ainsi :

 dnstap:
    dnstap-enable: yes
    dnstap-socket-path: "/var/run/unbound/dnstap.sock" 
    dnstap-send-identity: yes
    dnstap-send-version: yes
    dnstap-log-resolver-response-messages: yes
    dnstap-log-client-query-messages: yes
    

(Les quatre dernières lignes sont optionnelles. Ici, avec les deux dernières lignes, on ne journalise qu'une partie des requêtes et des réponses.) Et on relance le serveur. Il va dire quelque chose comme :

[1496927690] unbound[32195:0] notice: attempting to connect to dnstap socket /var/run/unbound/dnstap.sock
[1496927690] unbound[32195:0] notice: dnstap identity field set to "gpd-01"
[1496927690] unbound[32195:0] notice: dnstap version field set to "unbound 1.5.10"
[1496927690] unbound[32195:0] notice: dnstap Message/RESOLVER_RESPONSE enabled
[1496927690] unbound[32195:0] notice: dnstap Message/CLIENT_QUERY enabled
    

Si on l'interroge (par exemple avec dig), le serveur DNS va envoyer les messages dnstap à la prise, ici /var/run/unbound/dnstap.sock. Pour les lire, on va utiliser le client en ligne de commande dnstap :

% dnstap -q -u /var/run/unbound/dnstap.sock     
...
15:17:09.433521 CQ ::1 UDP 41b "witches.town." IN A
...
15:18:23.050690 CQ ::1 UDP 52b "fete.lutte-ouvriere.org." IN A
15:18:23.055833 RR 2001:4b98:abcb::1 UDP 147b "fete.lutte-ouvriere.org." IN A
    

Pour la première requête, l'information était dans le cache (la mémoire) du résolveur DNS. Il n'y a donc eu qu'une seule requête, depuis dig vers le résolveur (CQ = Client Query). Dans le second cas, la réponse ne se trouvait pas dans le cache, notre résolveur a dû aller demander à un serveur faisant autorité pour le domaine (en l'occurrence le serveur 2001:4b98:abcb::1, dont on voit la réponse au résolveur).

Si le cache est froid (le résolveur vient de démarrer), on verra que le résolveur devra faire plein d'autres requêtes (« requêtes tertiaires », dit le RFC 7626), ici, on a demandé www.sinodun.com, et le résolveur devra trouver les adresses IP des serveurs de .com (les serveurs de la racine étaient déjà connus, ici, c'est le serveur I.root-servers.net qui a répondu) :

11:47:39.556098 CQ ::1 UDP 44b "www.sinodun.com." IN A
11:47:39.560778 RR 192.36.148.17 UDP 1097b "." IN NS
11:47:39.598590 RR 192.112.36.4 UDP 867b "www.sinodun.com." IN A
11:47:39.605212 RR 2001:500:9f::42 UDP 852b "m.gtld-servers.net." IN AAAA
11:47:39.611999 RR 2001:503:a83e::2:30 UDP 789b "m.gtld-servers.net." IN AAAA
11:47:39.611999 RR 199.7.91.13 UDP 852b "l.gtld-servers.net." IN AAAA
11:47:39.611999 RR 192.35.51.30 UDP 789b "j.gtld-servers.net." IN AAAA
11:47:39.616442 RR 192.35.51.30 UDP 771b "av4.nstld.com." IN A
11:47:39.618318 RR 192.12.94.30 UDP 771b "av1.nstld.com." IN A
11:47:39.619118 RR 192.26.92.30 UDP 517b "www.sinodun.com." IN A
11:47:39.620192 RR 192.82.134.30 UDP 286b "av4.nstld.com." IN A
11:47:39.625671 RR 192.82.134.30 UDP 115b "m.gtld-servers.net." IN AAAA
11:47:39.628389 RR 192.54.112.30 UDP 789b "f.gtld-servers.net." IN AAAA
11:47:39.628974 RR 192.54.112.30 UDP 789b "d.gtld-servers.net." IN AAAA
    

Et si je veux voir les réponses, pas seulement les questions ? Demandons à dnstap d'être plus bavard :

% dnstap -y -u /var/run/unbound/dnstap.sock           
type: MESSAGE
identity: "gpd-01"
version: "unbound 1.5.10"
message:
  type: CLIENT_QUERY
  query_time: !!timestamp 2017-06-08 13:24:56.664846
  socket_family: INET6
  socket_protocol: UDP
  query_address: ::1
  query_port: 52255
  query_message: |
    ;; opcode: QUERY, status: NOERROR, id: 32133
    ;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; QUESTION SECTION:
    ;www.kancha.de.	IN	 A
    
    ;; ADDITIONAL SECTION:
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version 0; flags: do; udp: 4096
---
type: MESSAGE
identity: "gpd-01"
version: "unbound 1.5.10"
message:
  type: RESOLVER_RESPONSE
  query_time: !!timestamp 2017-06-08 13:24:56.664838
  response_time: !!timestamp 2017-06-08 13:24:56.697349
  socket_family: INET
  socket_protocol: UDP
  response_address: 85.13.128.3
  response_port: 53
  query_zone: "kancha.de."
  response_message: |
    ;; opcode: QUERY, status: NOERROR, id: 6700
    ;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; QUESTION SECTION:
    ;www.kancha.de.	IN	 A
    
    ;; ANSWER SECTION:
    www.kancha.de.	7200	IN	A	85.13.153.248
    
    ;; ADDITIONAL SECTION:
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version 0; flags: do; udp: 1680
---
    

(Eh oui, c'est du YAML.) Notons quelques points importants :

  • C'est le client dnstap pas le résolveur DNS, qui formate ce résultat comme il veut. On peut donc écrire d'autres clients dnstap, qui feraient autre chose avec les données (calculer des résultats agrégés, présenter comme tcpdump, etc). C'est une propriété importante de dnstap : le serveur journalise, le client dnstap en fait ce qu'il veut.
  • dnstap permet d'ajouter des informations qui n'apparaissent à aucun moment dans la requête ou dans la réponse. C'est le cas de query_zone, qui indique le bailliage (la zone d'où vient l'information sur ce nom) ou des temps de réponse.

Bon, maintenant, quelques petits détails techniques sur ce qu'il a fallu faire pour obtenir cela. D'abord, Unbound, sur presque tous les systèmes, a été compilé sans dnstap, probablement pour ne pas ajouter une dépendance supplémentaire (vers les Protocol Buffers). Si vous essayez de configurer Unbound pour dnstap, vous aurez un « fatal error: dnstap enabled in config but not built with dnstap support ». Il faut donc le compiler soi-même, avec l'option --enable-dnstap. Cela nécessite d'installer Protocol Buffers et Frame Streams (paquetages Debian libprotobuf-c-dev et libfstrm-dev).

Quant au client dnstap, celui utilisé est écrit en Go et nécessite d'installer le paquetage golang-dnstap :

% go get github.com/dnstap/golang-dnstap
% go install github.com/dnstap/golang-dnstap/dnstap

Quelles sont les autres mises en œuvre dont on dispose ? Le serveur DNS faisant autorité Knot a dnstap (mais ce n'est pas le cas du résolveur du même nom). Le serveur BIND peut également être compilé avec dnstap (testé avec la 9.11.1). Comme client, il existe aussi un client fondé sur ldns (paquetage Debian dnstap-ldns).

Enfin, pour terminer, voyons les autres solutions qui existent pour afficher ce que fait le serveur DNS. La plus évidente est de demander au serveur de journaliser lui-même. Avec le formatage des données, cela peut imposer une charge sévère au serveur, alors qu'un serveur DNS doit rester rapide, notamment en cas d'attaque par déni de service (avec dnstap, le formatage à faire est minime, vu l'efficacité des Protocol Buffers). Comme le note la documentation d'Unbound, « note that it takes time to print these lines which makes the server (significantly) slower ». Mais il y a une autre limite : on ne peut voir que les requêtes, pas les réponses, ni les requêtes tertiaires.

Avec Unbound, cela se configure ainsi :

    
     log-queries: yes

Et, si on demande le MX de sonic.gov.so, on obtient :

Jun 08 15:53:01 unbound[2017:0] info: ::1 sonic.gov.so. MX IN
  

Avec BIND, c'est :

  
08-Jun-2017 16:22:44.548 queries: info: client @0x7f71d000c8b0 ::1#39151 (sonic.gov.so): query: sonic.gov.so IN MX +E(0)D (::1)

Une autre solution pour voir le trafic DNS, et celle que je recommandais avant, est de sniffer le trafic réseau et de l'analyser. Il vaut mieux ne pas faire cela sur le serveur, que cela peut ralentir, mais sur une autre machine, avec du port mirroring pour envoyer une copie du trafic à la machine d'observation. Cette technique a le gros avantage de n'imposer absolument aucune charge au serveur. Mais elle a quatre défauts :

  • Il faut réassembler les réponses fragmentées, phénomène relativement fréquent avec le DNS, où les données peuvent dépasser la MTU et où l'utilisation d'UDP fait que la couche transport ne découpe pas les données.
  • Il faut reconstituer le trafic TCP, qui se retrouve réparti en plusieurs paquets. Avec le RFC 7766, l'utilisation de TCP deviendra sans doute de plus en plus fréquente pour le DNS.
  • Enfin, si le trafic est chiffré (RFC 7858), le sniffer est aveugle.
  • Certaines choses (comme la bailliage) ne se voient pas du tout dans le trafic, seul le serveur les connait.

Les trois premières raisons sont relativement récentes (autrefois, on ne chiffrait pas, on n'utilisait pas TCP, et les données étaient plus petites) et justifient le retour à un système où le serveur va devoir faire une partie du travail.


L'article seul

RFC 8179: Intellectual Property Rights in IETF Technology

Date de publication du RFC : Mai 2017
Auteur(s) du RFC : Scott Bradner (Harvard University), Jorge Contreras (University of Utah)
Première rédaction de cet article le 1 juin 2017


L'appropriation intellectuelle est partout et donc logiquement aussi dans les organismes de normalisation comme l'IETF. C'est l'objet de ce RFC, qui remplace les RFC 3979 et RFC 4879 sur les questions de brevets (nommées, à tort, questions de « propriété intellectuelle », alors que les brevets ne sont pas la même chose que les copyrights, traités dans le RFC 5378).

Donc, sur quels principes repose la politique de l'IETF au sujet des brevets ? L'idée de base est de s'assurer que l'IETF disposera d'information sur les brevets pouvant s'appliquer à une norme donnée, de façon à pouvoir prendre une décision en toute connaissance de cause. Il n'y a par contre pas de mécanisme automatique de décision, par exemple « Ne jamais normaliser des technologies brevetées ». En effet, compte-tenu du fait que l'écrasante majorité des brevets logiciels est futile, enregistrée uniquement parce que les organismes de brevetage ont un intérêt financier à accepter tout et n'importe quoi, une telle politique mènerait à ne rien pouvoir normaliser.

En pratique, tout ce RFC 8179 pourrait donc se résumer à « Tout participant à l'IETF qui connait ou devrait connaitre un brevet pouvant s'appliquer à une technique en cours de discussion doit en informer l'IETF ». C'est tout. Mais il y a quelques détails pratiques.

D'abord, il faut rappeler que ce sont officiellement des individus qui participent à l'IETF, pas des sociétés. Donc l'obligation s'applique à ces individus et ils ne peuvent pas y échapper en prétendant que leur compagnie leur interdit de réveler un brevet sous-marin (brevet sur lequel on fait peu de publicité, pour le ressortir une fois que la technique brevetée a été largement adoptée). Ensuite, le RFC définit ce que signifie contribuer à l'IETF (section 1). Par exemple, écrire sur une liste de diffusion d'un groupe de travail est une contribution. Cette règle est régulièrement rappelée par le fameux Note Well.

La section 1 définit formellement bien d'autres choses. Un concept essentiel mais souvent oublié est le Reasonably and personally known. Il désigne une information que le participant connait ou devrait connaitre, vu sa position dans l'entreprise qui l'emploie. L'idée est que le participant IETF n'est pas obligé de chercher activement dans le portefeuille de brevets de son entreprise, que l'obligation ne s'applique qu'à ce qu'il connait forcément, depuis son poste. Le but de l'ajout reasonably est d'éviter qu'une entreprise ne dissimule un brevet à ses propres employés.

Les principes sont donc :

  • L'IETF ne va pas chercher à déterminer si un brevet est futile ou pas (cela peut être un très gros travail, la plupart des brevets étant rédigés en termes délibérement incompréhensibles),
  • L'IETF peut normaliser ou pas une technique brevetée, il n'y a pas de refus systématique,
  • Pour pouvoir néanmoins savoir où on va, l'IETF a besoin d'information et c'est de là que découle l'exigence de divulgation des brevets, la principale obligation concrète de ce RFC 8179.

La section 3 rentre dans le concret, même si elle commence par un bel exercice de langue de bois (« The intent is to benefit the Internet community and the public at large, while respecting the legitimate rights of others. »). C'est elle qui impose que le contributeur à l'IETF ait bien divulgué tous les brevets qu'il connaissait « raisonnablement ». Outre le brevet lui-même, il peut y avoir une licence associée (un droit d'utiliser la technologie brevetée, sous certaines conditions). Si le détenteur du brevet n'indique pas de licence, l'IETF peut poliment lui demander. La licence (RAND, FRAND, RANDZ - c'est-à-dire gratuite …) sera évidemment un des éléments sur lesquels les participants à l'IETF fonderont leur position (cf. RFC 6410).

La section 4 indique ce que l'IETF va en faire, de ces divulgations (nommées « IPR [Intellectual Property Rights] disclosures ») : indication du fait qu'il existe des brevets pouvant s'y appliquer et publication de ces divulgations en http://www.ietf.org/ipr/. Par exemple, Verisign a un brevet (brevet états-unien 8,880,686, et la promesse de licence de Verisign) qu'ils prétendent valable, et dont ils affirment qu'il couvre la technique décrite dans le RFC 7816. (Sur la page officielle du RCF, c'est le lien « Find IPR Disclosures from the IETF ».) L'IETF (ou l'IAB, ou l'ISOC ou autre) n'ajoutera aucune appréciation sur la validité du brevet, ou sur les conditions de licence. Une telle appréciation nécessiterait en effet un long et coûteux travail juridique.

La note d'information n'est plus à inclure dans chaque RFC comme c'était autrefois le cas. Elle est désormais dans le IETF Trust Legal Provisions (version de 2015 : « The IETF Trust takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in any IETF Document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. »). Comme exemple d'un brevet abusif, on peut citer la divulgation #1154, qui se réclame d'un brevet sur les courbes elliptiques qui s'appliquerait à tous les RFC parlant d'un protocole qui peut utiliser ces courbes, comme le RFC 5246.

Les divulgations ne sont pas incluses dans les RFC eux-mêmes (section 10) car elles peuvent évoluer dans le temps alors que le RFC est stable. Il faut donc aller voir ces « IPR disclosures » en ligne sur http://www.ietf.org/ipr/.

Les divulgations sont-elles spécifiées plus en détail ? Oui, en section 5. La 5.1 précise qui doit faire la divulgation (le participant, en tant que personne physique), la section 5.2 donne les délais (« aussi vite que possible »), la section 5.4.3 rappelle que la divulgation doit être précise et qu'un contributeur ne peut pas se contenter de vagues généralités (« blanket disclosure »). Le tout est aussi mis en ligne, en http://www.ietf.org/ipr-instructions.

Et si un tricheur, comme la société RIM, ne respecte pas cette obligation de divulgation ? La section 6 ne prévoit aucune dérogation : si, par exemple, une société empêche ses employés de divulguer les brevets, ces employés ne doivent pas participer à l'IETF (« tu suis les règles, ou bien tu ne joues pas »). Tout participant à l'IETF est censé connaitre cette règle (section 3.3). Le RFC 6701 liste les sanctions possibles contre les tricheurs et le RFC 6702 expose comment encourager le respect des règles.

Bien, donc, arrivé là, l'IETF a ses informations et peut prendre ses décisions. Sur la base de quelles règles ? La section 7 rappelle le vieux principe qu'une technique sans brevets est meilleure ou, sinon, à la rigueur, une technique où le titulaire des brevets a promis des licences gratuites. Mais ce n'est pas une obligation, l'IETF peut choisir une technologie brevetée, même sans promesses sur la licence, si cette technologie en vaut la peine.

La seule exception concerne les techniques de sécurité obligatoires : comme tout en dépend, elles ne doivent être normalisées que s'il n'existe pas de brevet ou bien si la licence est gratuite.

Les règles de bon sens s'appliquent également : s'il s'agit de faire une nouvelle version normalisée d'un protocole très répandu, on évitera de choisir une technologie trop encombrée de brevets, s'il s'agit d'un tout nouveau protocole expérimental, on pourra être moins regardant.

Les changements depuis les RFC précédents, les RFC 3979 et RFC 4879, sont décrits dans la section 13. Pas de révolution, les principes restent les mêmes. Parmi les changements :

  • Texte modifié pour permettre l'utilisation de ces règles en dehors de la voie IETF classique (par exemple par l'IRTF).
  • La définition d'une « contribution IETF » a été élargie pour inclure, par exemple, les interventions dans les salles XMPP de l'IETF.
  • Meilleure séparation des questions de brevets (traitées dans notre RFC) avec celles de droit d'auteur (traitées dans le RFC 5378). Le terme de « propriété intellectuelle » a plusieurs défauts, dont celui de mêler des choses très différentes (brevets, marques, droit d'auteur…)
  • Il n'y a plus de boilerplate (qui était en section 5 du RFC 3979) à inclure dans les documents, il est désormais en ligne.

Téléchargez le RFC 8179


L'article seul

RFC 8111: Locator/ID Separation Protocol Delegated Database Tree (LISP-DDT)

Date de publication du RFC : Mai 2017
Auteur(s) du RFC : V. Fuller, D. Lewis, V. Ermagan (Cisco), A. Jain (Juniper Networks), A. Smirnov (Cisco)
Expérimental
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 27 mai 2017


Le protocole LISP (dont on ne rappelera jamais assez qu'il ne faut pas le confondre avec le langage de programmation du même nom) sépare les deux rôles de l'adresse IP, identificateur et localisateur. C'est très joli de séparer, cela permet plein de choses intéressantes, comme de lutter contre la croissance illimitée de la DFZ mais cela présente un défi : comment obtenir un localisateur quand on a un identificateur ? Dit autrement, « où est cette fichue machine que j'essaie de joindre ? » Ajouter une indirection, en informatique, oblige toujours à créer un système de correspondance permettant de passer par dessus le fossé qu'on vient juste de créer. LISP a plusieurs systèmes de correspondance possibles, tous expérimentaux, et ce nouveau DDT (Delegated Database Tree) vient les rejoindre. C'est le système qui est le plus proche du DNS dans ses concepts. Comme je connais un peu le DNS, j'utiliserai souvent dans cet article des comparaisons avec le DNS.

Pour résumer DDT en un paragraphe : dans LISP (RFC 6830), l'identificateur se nomme EID (Endpoint Identifier) et le localisateur RLOC (Routing Locator). Les EID ont une structure arborescente (leur forme syntaxique est celle d'adresses IP). Cet arbre est réparti sur plusieurs serveurs, les nœuds DDT. Un nœud DDT fait autorité pour un certain nombre de préfixes d'EID. Il délègue ensuite les sous-préfixes à d'autres nœuds DDT, ou bien à des Map Servers LISP (RFC 6833) quand on arrive en bas de l'arbre. (Une des différences avec le DNS est donc que les serveurs qui délèguent sont d'une nature distincte de ceux qui stockent les feuilles de l'arbre.)

LISP a une interface standard avec les serveurs qui font la résolution d'EID en RLOC, décrite dans le RFC 6833. En gros, le client envoie un message Map-Request et obtient une réponse Map-Reply, ou bien une délégation (Map-Referral) qu'il va devoir suivre en envoyant le Map-Request suivant au RLOC indiqué dans la délégation. Derrière cette interface, LISP ne spécifie pas comment les serveurs obtiennent l'information. Plusieurs propositions ont déjà été faites (comme ALT, dans le RFC 6836, ou NERD, dans le RFC 6837…), auxquelles s'ajoute celle de notre RFC. Un bon résumé est dans cette image (mais qui ne montre qu'un seul niveau de délégation, il peut y en avoir davantage.)

DDT vise avant tout le passage à l'échelle, d'où la structuration hiérarchique de l'information. La notion de délégation (d'un préfixe général à un sous-préfixe plus spécifique) est centrale dans DDT. Un client (le routeur LISP qui a un paquet destiné à un EID donné et qui cherche à quel RLOC le transmettre, ou bien un résolveur, un serveur spécialisé agissant pour le compte de ce routeur) va donc devoir suivre cette délégation, descendant l'arbre jusqu'à l'information souhaitée.

La délégation est composée, pour un préfixe délégué, d'un ensemble de RLOC (pas d'EID pour éviter des problèmes d'œuf et de poule) désignant les nœuds qui ont une information sur le préfixe délégué. (Ce sont donc l'équivalent des enregistrements NS du DNS, mais avec une indirection en moins, comme si la partie droite d'un enregistrement NS stockait directement une adresse IP.)

J'ai écrit jusque là que la clé d'accès à l'information (rôle tenu par le nom de domaine dans le DNS) était l'EID mais c'est en fait un peu plus compliqué : la clé est le XEID (eXtended EID), qui est composé de plusieurs valeurs, dont l'EID (section 4.1 de notre RFC).

Pour indiquer au résolveur qu'il doit transmettre sa requête à une autre machine, ce RFC crée un nouveau type de message LISP, Map-Referral, type 6 (cf. le registre IANA) détaillé en section 6, envoyé en réponse à un Map-Request, quand le nœud DDT ne connait pas la réponse. (Comme indiqué plus haut, c'est l'équivalent d'une réponse DNS avec uniquement une section Autorité contenant des enregistrements NS.)

Continuons un peu la terminologie (section 3 du RFC) :

  • Un client DDT est une machine qui interroge les nœuds DDT (avec un Map-Request, cf. RFC 6833) et suit les Map-Referral jusqu'au résultat. C'est en général un résolveur (Map Resolver, RFC 6833) mais cela peut être aussi un routeur LISP (ITR, Ingress Tunnel Router).
  • Un résolveur est serveur d'un côté, pour les routeurs qui envoient des Map-Request, et client DDT de l'autre, il envoie des requêtes DDT. Il gère un cache (une mémoire des réponses récentes). Le résolveur maintient également une liste des requêtes en cours, pas encore satisfaites.

La base des données des serveurs DDT est décrite en section 4. Elle est indexée par XEID. Un XEID est un EID (identificateur LISP) plus un AFI (Address Family Identifier, 1 pour IPv4, 2 pour IPv6, etc), un identificateur d'instance (voir RFC 6830, section 5.5, et RFC 8060, section 4.1) qui sert à avoir plusieurs espaces d'adressage, et quelques autres paramètres, pas encore utilisés. Configurer un serveur DDT, c'est lui indiquer la liste de XEID qu'il doit connaitre, avec les RLOC des serveurs qui pourront répondre. Désolé, je n'ai pas de serveur DDT sous la main mais on peut trouver un exemple, dans la documentation de Cisco, où on délègue au Map Server de RLOC 10.1.1.1 :

router lisp
    ddt authoritative 2001:db8:eeee::/48
          delegate 10.1.1.1 eid-prefix 172.16.0.0/16
          delegate 10.1.1.1 eid-prefix 2001:db8:eeee::/48
    

Un autre exemple de délégation est l'actuelle liste des données dans la racine DDT.

Le DNS n'a qu'un type de serveurs faisant autorité, qu'ils soient essentiellement serveurs de délégation (ceux des TLD, par exemple) ou qu'ils soient serveurs « finaux » contenant les enregistrements autres que NS. Au contraire, LISP+DDT a deux types de serveurs, les nœuds DDT présentés dans ce RFC, qui ne font que de la délégation, et les traditionnels Map Servers, qui stockent les correspondances entre EID et RLOC (entre identificateurs et localisateurs). Dit autrement, DDT ne sert pas à trouver la réponse à la question « quel est le RLOC pour cet EID », il sert uniquement à trouver le serveur qui pourra répondre à cette question.

Comme pour le DNS, il existe une racine, le nœud qui peut répondre (enfin, trouver une délégation) pour tout XEID. (Sur le Cisco cité plus haut, la directive ddt root permettra d'indiquer le RLOC des serveurs de la racine, voir aussi la section 7.3.1 de notre RFC.) Une racine expérimentale existe, vous trouverez ses RLOC en http://ddt-root.org/.

La section 5 de notre RFC décrit en détail la modification au message Map-Request que nécessite DDT. Ce message était normalisé par le RFC 6830 (section 6.1.2) et un seul ajout est fait : un bit qui était laissé vide sert désormais à indiquer que la requête ne vient pas directement d'un routeur LISP mais est passée par des nœuds DDT.

La section 6, elle, décrit un type de message nouveau, Map-Referral, qui contient les RLOC du nœud DDT qui pourra mieux répondre à la question. Cette réponse contient un code qui indique le résultat d'un Map-Request. Ce résultat peut être « positif » :

  • NODE-REFERRAL, renvoi à un autre nœud DDT,
  • MS-REFERRAL, renvoi à un Map Server (rappelez-vous que, contrairement au DNS, il y a une nette distinction entre nœud intermédiaire et Map Server final),
  • MS-ACK, réponse positive d'un Map Server.

Mais aussi des résultats « négatifs » :

  • MS-NOT-REGISTERED, le Map Server ne connait pas cet EID,
  • DELEGATION-HOLE, l'EID demandé tombe dans un trou (préfixe non-LISP dans un préfixe LISP),
  • NOT-AUTHORITATIVE, le nœud DDT n'a pas été configuré pour ce préfixe.

Le fonctionnement global est décrit en détail dans la section 7 du RFC. À lire si on veut savoir exactement ce que doivent faire le Map Resolver, le Map Server, et le nouveau venu, le nœud DDT. La même description figure sous forme de pseudo-code dans la section 8. Par exemple, voici ce que doit faire un nœud DDT lorsqu'il reçoit un Map-Request (demande de résolution d'un EID en RLOC) :

    if ( I am not authoritative ) {
        send map-referral NOT_AUTHORITATIVE with
         incomplete bit set and ttl 0
    } else if ( delegation exists ) {
        if ( delegated map-servers ) {
            send map-referral MS_REFERRAL with
              ttl 'Default_DdtNode_Ttl'
        } else {
            send map-referral NODE_REFERRAL with
              ttl 'Default_DdtNode_Ttl'
        }
    } else {
        if ( eid in site) {
            if ( site registered ) {
                forward map-request to etr
                if ( map-server peers configured ) {
                    send map-referral MS_ACK with
                     ttl 'Default_Registered_Ttl'
                } else {
                    send map-referral MS_ACK with
                     ttl 'Default_Registered_Ttl' and incomplete bit set
                }
            } else {
                if ( map-server peers configured ) {
                    send map-referral MS_NOT_REGISTERED with
                     ttl 'Default_Configured_Not_Registered_Ttl'
                } else {
                    send map-referral MS_NOT_REGISTERED with
                     ttl 'Default_Configured_Not_Registered_Ttl'
                     and incomplete bit set
                }
            }
        } else {
            send map-referral DELEGATION_HOLE with
             ttl 'Default_Negative_Referral_Ttl'
        }
    }      
    

Un exemple complet et détaillé figure dans la section 9, avec description de tous les messages envoyés.

Question sécurité, je vous renvoie à la section 10 du RFC. DDT dispose d'un mécanisme de signature des messages (l'équivalent de ce qu'est DNSSEC pour le DNS). La délégation inclut les clés publiques des nœuds à qui on délègue.

Il existe au moins deux mises en œuvre de DDT, une chez Cisco et l'autre chez OpenLisp. (Le RFC ne sort que maintenant mais le protocole est déployé depuis des années.)


Téléchargez le RFC 8111


L'article seul

RFC 8112: Locator/ID Separation Protocol Delegated Database Tree (LISP-DDT) Referral Internet Groper (RIG)

Date de publication du RFC : Mai 2017
Auteur(s) du RFC : D. Farinacci (lispers.net), A. Jain (Juniper Networks), I. Kouvelas, D. Lewis (cisco Systems)
Expérimental
Première rédaction de cet article le 27 mai 2017


Ce RFC concerne les utilisateurs de LISP (le protocole réseau, pas le langage de programmation). Il décrit un nouvel outil, rig, le Referral Internet Groper, qui permet d'interroger les tables de correspondance identificateur->localisateur.

Un point important de LISP (RFC 6830) est en effet cette séparation de l'EID (l'identificateur d'une machine) et du RLOC (le localisateur de cette machine, qui indique où envoyer les paquets). Tout système ayant cette séparation doit maintenir une correspondance (mapping) entre les deux : lorsque je veux écrire à telle machine dont je connais l'EID, il faut que je trouve le localisateur. LISP permet plusieurs mécanismes pour cette correspondance. L'outil rig, présenté dans ce RFC, est conçu pour le mécanisme DDT (RFC 8111), une base de données arborescente et répartie. rig est donc un client DDT de déboguage, lig (RFC 6835) étant un autre outil, plus général (il peut interroger d'autres bases que DDT).

Un client DDT comme rig (ou comme un routeur LISP lors de son fonctionnement normal) va donc envoyer des Map-Request (RFC 6830, section 6.1, et aussi RFC 6833) aux serveurs DDT.

La section 4 de notre RFC résume le fonctionnement de rig. Il envoie le Map-Request et affiche le Map-Referral de réponse. Il peut ensuite suivre cette référence jusqu'à arriver au Map Server qui gère ce préfixe. (Notez que c'est le RLOC du Map Server qu'on obtient, sinon, on aurait un intéressant problème d'œuf et de poule si on avait besoin de DDT pour utiliser DDT...)

rig a donc besoin d'au moins deux paramètres, l'EID (l'identificateur) qu'on cherche à résoudre, et le serveur DDT par lequel on va commencer la recherche. (Pour l'EID, rig accepte également un nom de domaine, qu'il va traduire en EID dans le DNS.) La syntaxe typique est donc :

rig <eid> to <ddt-node>
    

La section 5 décrit les mises en œuvres existantes, sur les routeurs Cisco. La syntaxe est un peu différente de ce que je trouve dans la doc' de Cisco mais, bon, tout ceci est expérimental et en pleine évolution. Voici un exemple tiré de la documentation officielle de Cisco (LISP DDT Configuration Commands) :

Device# lisp-rig 172.16.17.17 to 10.1.1.1

rig LISP-DDT hierarchy for EID [0] 172.16.17.17 
Send Map-Request to DDT-node 10.1.1.1 ... replied, rtt: 0.007072 secs
  EID-prefix [0] 172.16.17.16/28, ttl: 1, action: ms-not-registered, referrals:
    10.1.1.1, priority/weight: 0/0
    10.2.1.1, priority/weight: 0/0
    10.3.1.1, priority/weight: 0/0
    

Et voilà, on sait que l'EID 172.16.17.17, il faut aller demander aux serveurs 10.1.1.1, 10.2.1.1 et 10.3.1.1. Dans le RFC, on trouve un exemple où rig suit ces références :

   Router# rig 12.0.1.1 to 1.1.1.1 

   Send Map-Request to DDT-node 1.1.1.1 ... node referral, rtt: 4 ms
   EID-prefix: [0] 12.0.0.0/16, ttl: 1440
   referrals: 2.2.2.2

   Send Map-Request to DDT-node 2.2.2.2 ... node referral, rtt: 0 ms
   EID-prefix: [0] 12.0.1.0/24, ttl: 1440
   referrals: 4.4.4.4, 5.5.5.5

   Send Map-Request to DDT-node 4.4.4.4 ... map-server acknowledgement,
                                            rtt: 0 ms
   EID-prefix: [0] 12.0.1.0/28, ttl: 1440
   referrals: 4.4.4.4, 5.5.5.5
    

Si vous voulez en savoir plus sur DDT et rig, vous pouvez aussi regarder l'exposé de Cisco ou celui de Paul Vinciguerra à NANOG, ou bien la page officielle de la racine DDT (qui semble peu maintenue).


Téléchargez le RFC 8112


L'article seul

L'axe des Y doit partir de zéro !

Première rédaction de cet article le 22 mai 2017
Dernière mise à jour le 23 mai 2017


On voit souvent dans les infographies des graphiques où l'axe des Y (axe des ordonnées) ne part pas de zéro. Pourquoi faut-il appeler la malédiction de tous les démons connus et inconnus sur les auteurs de ces graphiques ?

Parce que cela sert à tromper. Mettre comme point de départ une valeur différente de zéro tend à amplifier artificiellement un phénomène. Imaginons une grandeur qui varie assez peu, disons entre (unités arbitraires) 650 et 660. Si on la représente sur un graphique qui part de 0, la variation semblera faible. Si l'axe des Y part de la valeur 650, on aura l'impression de grandes variations.

Un bon exemple est la dispositive n° 11 de cet exposé : elle donne l'impression d'une envolée de la dette, en laissant entendre qu'on partait de zéro, alors que l'augmentation n'a été que de 30 % : iif-debt.jpg

Un autre exemple est ce graphique de la croissance de l'ether, où le fait de ne pas partir de zéro donne l'impression d'une croissance encore plus spectaculaire : ether-growth.png

Même s'il y a une échelle sur l'axe des Y (certains graphiques n'en ont même pas), l'œil pressé n'y fait pas attention (on en voit, des graphiques, dans une journée…) et retient une fausse impression.

Cette tromperie est bien illustrée dans ce dessin de William Easterly : y-axis.jpg

Cette règle de partir de zéro est-elle absolue ? Non, évidemment. D'abord, évidemment, si l'échelle est logarithmique, elle ne va évidemment pas partir de zéro. Ensuite, il y a des cas où cela peut être logique, par exemple s'il existe une justification liée à la nature du phénomène mesuré. Si on fait un graphique de la température du corps humain, il est plus logique de partir de 35 ou 36° que de 0, puisque la température du corps ne va jamais se promener aussi bas. Et, bien sûr, on peut vouloir mettre en évidence des petites variations (qui seraient lissées si l'axe des Y partait de zéro) sans intention de tromper. Mais je soupçonne que de tels cas sont très minoritaires.


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.