Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

È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.


IETF 116 hackathon: unilateral probing of TLS on DNS servers

First publication of this article on 27 March 2023


On 25 and 26 March, it was the IETF 116 hackathon in Yokohama. I worked on TLS probing of authoritative DNS servers.

The goal of the IETF hackathons is to test ideas that may become RFC later. "Running code" is an important part of IETF principles. It is both useful and pleasing to sit down together at big tables and to hack all weekend, testing many ideas and seeing what works and what does not.

A bit of context on this "TLS probing". The DNS is a critical infrastructure of the Internet. It is used for most activities on the Internet. Requests and responses were traditionally sent in the clear, and this is bad for privacy since they can be quite revealing ("this user queried www.aa.org", see RFC 7626). To improve DNS privacy, the IETF developed two sets of solutions: minimizing data (RFC 9156), to protect against the server you query, and encrypting data, to protect against third parties sniffing on the cable. For the second set, encryption, several techniques have been developed, I will focus here on DoT (DNS over TLS, RFC 7858) and DoQ (DNS over QUIC, RFC 9250) but mostly on DoT. These various techniques are standardized for the client-to-resolver link, the most critical for the privacy (see RFC 7626 for details). They are now deployed, although not universally. But this leaves the resolver-to-authoritative link in the clear. The current idea is therefore to use encryption for this link, what we call ADoT (authoritative DNS over TLS). Technically, it is the same DNS over TLS than for the client-to-resolver link. But in practice, there are some issues. A client talks to only one (or may be two) resolvers, which he or she knows. But a resolver talks to thousands of authoritative name servers. Some will have enabled ADoT, some not. How to know?

There were some attempts in the DPRIVE working group to define a signaling mechanism, through which the operators of authoritative name servers could say they support ADoT. But these efforts all fail. A general problem of signalisation of services on the Internet is that the signal can be wrong, and often is (advertising a service which actually des not work). So, the approach on the draft we worked on, draft-ietf-dprive-unilateral-probing, was different: probing the authoritative name server to see if it really does ADoT.

The work was done by Yorgos Thessalonikefs (from NLnet Labs) and myself. Yorgos worked on adding probing support to Unbound and I tested existing ADoT deployment, as well as adding DoT support to the Drink authoritative name server.

First, let's see DoT in action, here with a local installation of Drink and the kdig client (part of Knot):

    
% kdig +tls @localhost -p 8353 foobar.test
;; TLS session (TLS1.3)-(ECDHE-X25519)-(ECDSA-SECP256R1-SHA256)-(AES-256-GCM)
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 16994
;; Flags: qr aa rd; QUERY: 1; ANSWER: 0; AUTHORITY: 1; ADDITIONAL: 1

;; EDNS PSEUDOSECTION:
;; Version: 0; flags: ; UDP size: 1440 B; ext-rcode: NOERROR
;; Option (65023): 067265706F7274076578616D706C6503636F6D00
;; PADDING: 348 B

;; QUESTION SECTION:
;; foobar.test.        		IN	A

;; AUTHORITY SECTION:
foobar.test.        	10	IN	SOA	ns1.test. root.invalid. 2023032512 1800 300 604800 86400
;; Received 468 B
;; Time 2023-03-25 21:43:26 JST
;; From 127.0.0.1@8353(TCP) in 44.7 ms

  

OK, it worked, a TLS connection was established (the TLS cryptographic algorithms used are displayed at the beginning of the response), and we got a DNS reply. Also, the answer was padded (RFC 7830) to 468 bytes (RFC 8467) in order to avoid traffic analysis.

ADoT can also be tested with the check-soa tool. Here, all the authoritative name servers of the domain have ADoT:

% check-soa -dot aaa-cool.fr
ns01.one.com.
	195.206.121.10: OK: 2023032101
	2001:67c:28cc::10: OK: 2023032101
ns02.one.com.
	185.10.11.10: OK: 2023032101
	2001:67c:28cc:1::10: OK: 2023032101
  

And here only one has:

% check-soa -dot bortzmeyer.fr
ns2.bortzmeyer.org.
	2400:8902::f03c:91ff:fe69:60d3: ERROR: dial tcp [2400:8902::f03c:91ff:fe69:60d3]:853: connect: connection refused
	172.104.125.43: ERROR: dial tcp 172.104.125.43:853: connect: connection refused
ns4.bortzmeyer.org.
	2001:4b98:dc0:41:216:3eff:fe27:3d3f: ERROR: dial tcp [2001:4b98:dc0:41:216:3eff:fe27:3d3f]:853: i/o timeout
	92.243.4.211: ERROR: dial tcp 92.243.4.211:853: i/o timeout
puck.nether.net.
	2001:418:3f4::5: OK: 2023032600
	204.42.254.5: OK: 2023032600
  

ADoT can also be tested with the RIPE Atlas probes, here with the Blaeu tool against a root name server, B.root-servers.net:

% blaeu-resolve --requested 100 --nameserver 199.9.14.201 --type SOA --tls --nsid .
Nameserver 199.9.14.201
[TIMEOUT] : 2 occurrences 
[NSID: b4-ams; a.root-servers.net. nstld.verisign-grs.com. 2023032501 1800 900 604800 86400] : 54 occurrences 
[NSID: b4-lax; a.root-servers.net. nstld.verisign-grs.com. 2023032501 1800 900 604800 86400] : 12 occurrences 
[NSID: b4-iad; a.root-servers.net. nstld.verisign-grs.com. 2023032501 1800 900 604800 86400] : 15 occurrences 
[NSID: b4-mia; a.root-servers.net. nstld.verisign-grs.com. 2023032501 1800 900 604800 86400] : 3 occurrences 
[a.root-servers.net. nstld.verisign-grs.com. 2023032501 1800 900 604800 86400] : 1 occurrences 
[NSID: b4-sin; a.root-servers.net. nstld.verisign-grs.com. 2023032501 1800 900 604800 86400] : 1 occurrences 
Test #51316045 done at 2023-03-26T02:05:11Z
  

This is quite good, only two probes fail to connect over DoT, may be because they were on a network which blocks port 853 outgoing.

OK, so, some authoritative name servers have ADoT and some have not. Now, what should the resolver do? Since there is no signaling, should it try port 853? How to do it without waiting forever if the server does not reply at all? The idea behind the draft draft-ietf-dprive-unilateral-probing is indeed to always try ADoT and use it if it works but in an "intelligent" way. Instead of waiting for ADoT to succeed or fail, the resolver should do it on the "happy eyeballs" way (RFC 8305), trying both DoT and traditional DNS a the same time. Note that it is an unilateral choice: the resolver does all of the work and requires nothing from the authoritative server.

One resolver today does probing, although not in the way of the draft: PowerDNS Recursor. Let's try it (their DoT support is dscribed online). We get the git, we follow the good compilation instructions, we autoreconf, then ./configure, then make. We then can run it with the option --max-busy-dot-probes=100 (by default, it does not do probing). Note that probing in PowerDNS is lazy: it is not always tried, only of there is a "sufficient" traffic with the authoritative name server. You can see probing going on with tcpdump on port 853 and PowerDNS can report the results:

% rec_control dump-dot-probe-map /tmp/foo && fgrep Good /tmp/foo 
dump-dot-probe-map: dumped 13962 records
45.54.76.1	qtmlabs.xyz.	14	Good	2023-03-29T04:27:32
157.53.224.1	qtmlabs.xyz.	39	Good	2023-03-29T04:28:37
77.55.125.10	abstractionleak.com.	1	Good	2023-03-29T04:25:39
77.55.126.10	abc-sport.fr.	3	Good	2023-03-29T04:25:39
185.10.11.11	one.com.	4	Good	2023-03-29T04:28:02
195.206.121.11	one.com.	4	Good	2023-03-29T04:28:03
51.77.156.11	BILLAUD.EU.ORG.	1	Good	2023-03-29T00:09:32
129.134.30.12	facebook.com.	5	Good	2023-03-29T04:29:26
129.134.31.12	facebook.com.	6	Good	2023-03-29T04:27:39
185.89.218.12	facebook.com.	14	Good	2023-03-29T04:27:39
185.89.219.12	facebook.com.	5	Good	2023-03-29T04:27:39
139.99.155.59	EU.ORG.	1	Good	2023-03-29T04:27:32
185.49.140.60	nlnetlabs.nl.	3	Good	2023-03-29T04:26:37
172.105.50.79	geekyboo.net.	1	Good	2023-03-29T04:22:37
23.234.235.93	obo.sh.	1	Good	2023-03-29T03:34:12
212.102.32.200	cdn77.org.	1	Good	2023-03-29T03:47:44
199.9.14.201	.	17	Good	2023-03-29T04:30:39
136.243.57.208	distos.org.	1	Good	2023-03-29T03:44:00
  

We see here that all these nameservers have a working ADoT. In order to probe many domains, I have fed the resolver with data from the .fr zone, Cloudflare Domain Rankings and a list of fediverse instances. A partial list of domains which currently have working ADoT for at least one name server is:

.               # Yes, the root
facebook.com
nlnetlabs.nl
powerdns.com
eu.org
billaud.eu.org
dyn.sources.org  # Drink name server
bortzmeyer.fr
nether.net
one.com # and the zones is hosts such as aaa-cool.fr
desec.io # and the zones it hosts such as qtmlabs.xyz
nazwa.pl # and the zones it hosts such as abc-sport.fr
psyopwar.com # and the zones it hosts such as obo.sh
cdn77.org
distos.org
  

As you can see, even the root has a working ADoT server (see the announcement), despite a prudent statement of the root operators some time ago.

What about the work on Unbound? Unfortunately, it was more complicated than it seemed, since "happy eyeballs" probing (sending the request twice) runs against some assumptions in Unbound code. But the work by Yorgos made possible to better understand the issues, which is an important point for the hackathon.

The work of this weekend raised several questions, to be carried to the working group:

  • If the ADoT server replies but the reply indicates an error, such as SERVFAIL or REFUSED, should the resolver retry without DoT? PowerDNS Recursor does it, but it seems it would make more sense to accept the reply, and just to remind system administrators that port 853 and 53 should deliver consistent answers.
  • What should be the criteria to select an authoritative name server to query? Should we prefer a fast insecure server or a slow encrypted one? The draft does not mention it, because it is local policy. (PowerDNS Recursor has apparently no way to change its default policy, which is to use the fastest one, DoT or not.)
  • Should we do lazy probing, like PowerDNS Recursor does, or use the more eager "happy eyeballs" algorithm?

For the issue of consistency between port 53 and 853, this can go at odds with current practices. For instance, the only authoritative name server of dyn.bortzmeyer.fr hosts two different services, Drink for the autoritative service on port 53 and an open resolver, dnsdist, on port 853. So, the answers are different. Should we ban this practice?

% check-soa -dot dyn.bortzmeyer.fr
ns1-dyn.bortzmeyer.fr.
	2001:41d0:302:2200::180: ERROR: REFUSED
	193.70.85.11: ERROR: REFUSED

% check-soa -tcp dyn.bortzmeyer.fr
ns1-dyn.bortzmeyer.fr.
	2001:41d0:302:2200::180: OK: 2023032702
	193.70.85.11: OK: 2023032702
  

(The REFUSED is because check-soa does not send the RD - recursion desired - bit.)

All the presentations done at the end of the hackathon are online, including our presentation.


L'article seul

Fiche de lecture : Catalogue des vaisseaux imaginaires

Auteur(s) du livre : Stéphane Mahieu
Éditeur : Éditions du Sandre
9-782358-211505
Publié en 2022
Première rédaction de cet article le 21 mars 2023


Un livre qui donne envie de voyager et de lire : l'auteur a dressé un catalogue de bateaux qui apparaissent dans des œuvres de fiction. Chaque entrée résume le bateau, sa carrière, son rôle dans le roman, et est l'occasion de passer d'œuvres archi-connues à des textes bien moins célèbres.

On y trouve le Titan, du roman « Le naufrage du Titan » (avec des notes mettant en avant, non pas les ressemblances avec le Titanic, comme souvent, mais les différences), le Fantôme du « Loup des mers » (un roman politique bien plus qu'un livre d'aventures maritimes), et bien sûr le Nautilus. Mais l'auteur présente aussi des vaisseaux issus de romans plus obscurs (en tout cas en France), comme l'Étoile polaire (dans le roman d'Obroutchev), le Leviatán, issu de l'imagination de Coloane ou le Rose-de-Mahé, créé par Masson.

À noter que la bande dessinée n'est pas représentée (ni le cinéma, d'ailleurs). L'entrée pour la Licorne ne décrit pas le vaisseau du chevalier de Hadoque mais elle parle d'un recueil d'histoires anciennes (le livre est sur le projet Gutenberg).

Bref, plein d'idées de lectures vont vous venir en parcourant ce livre… Mettez votre ciré, vérifiez les provisions de bord (et les armes !) et embarquez.


L'article seul

Fiche de lecture : Plutôt nourrir

Auteur(s) du livre : Clément Osé, Noémie Calais
Éditeur : Tana
979-10-301-0424-0
Publié en 2022
Première rédaction de cet article le 20 mars 2023


Le débat sur la consommation de viande est souvent binaire, entre d'un côté les partisans de l'agriculture industrielle et de l'autre des animalolâtres qui refusent toute utilisation des animaux. Ce livre raconte le point de vue d'une éleveuse de porcs, qui essaie de faire de l'élevage de viande en échappant aux logiques industrielles.

Les partisans de l'agriculture industrielle reprochent souvent à leux opposants animalistes de ne rien connaitre à l'agriculture et au monde paysan. Ce n'est pas faux, mais, justement, ce livre est écrit, à deux mains, par des personnes qui vivent à la campagne, et qui travaillent la terre. Noémie Calais, l'éleveuse, a quitté son travail de consultante internationale pour s'occuper de porcs dans le Gers. Le travail quotidien est difficile (être paysanne n'a rien de romantique), et plein de questions se bousculent : a-t-on le droit d'élever des animaux pour finalement les tuer, comment faire une agriculture bio (ou à peu près) sans faire venir des kiwis, certes bios, mais transportés par avion depuis l'autre bout du monde, comment essayer de faire les choses proprement dans un environnement légal et économique où tout pousse à la concentration et à l'agriculture industrielle, avec toutes ses horreurs (pour les humains, comme pour les animaux). Les auteurs n'esquivent aucune question. Oui, il est légitime de manger les animaux, non, cela ne veut pas dire qu'il faut faire n'importe quoi.

Le livre va du quotidien d'une paysanne aux questions plus directement politiques, comme la réglementation délirante qui, sous couvert de protéger les consommateurs, crée tellement de normes et de certifications abstraites et déconnectées du terrain que seuls les gros, donc en pratique l'agriculture industrielle, ont des chances d'arriver à les respecter. Les arguments sanitaires, par exemple, peuvent être un prétexte pour démolir les circuits locaux. (Le cas n'est pas dans ce livre mais, par exemple, les règles de respect de la chaine du froid pour les fromages, qui sont les mêmes pour le fromage industriel sous plastique qui vient de l'autre bout du pays, et pour les dix ou vingt fromages de chèvre produits à deux kilomètres du marché sont un exemple typique.)

À lire avant d'aller au supermarché faire ses achats !


L'article seul

IPv6 chez OVH, c'est bizarre

Première rédaction de cet article le 17 mars 2023


Si vous avez déjà créé/géré une machine virtuelle chez OVH, vous avez sans doute noté la bizarrerie de la configuration IPv6. En fait, la configuration automatiquement installée lorsque vous créez votre machine est incorrecte. Voici pourquoi, et comment la réparer.

Créons d'abord un serveur (j'ai utilisé l'API OpenStack mais le problème existait déjà avant).


%    ip -6 addr show
...
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2001:41d0:801:1000::233c/56 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe10:748f/64 scope link 
       valid_lft forever preferred_lft forever

  

La machine a une adresse IPv6, 2001:41d0:801:1000::233c, dans un préfixe de longueur 56. Chic, je me dis, je vais pouvoir parler directement (sans passer par le routeur) avec les autres machines dans ce même préfixe. La table de routage va d'ailleurs en ce sens :

%    ip -6 route show
...
2001:41d0:801:1000::/56 dev ens3 proto kernel metric 256 pref medium
default via 2001:41d0:801:1000::1 dev ens3 metric 1 pref medium
  

Elle nous dit que tout le /56 est joignable sans intermédiaire (pas de via). Essayons depuis la 2001:41d0:801:1000::23b2 :

%  ping -c 3 2001:41d0:801:1000::233c
PING 2001:41d0:801:1000::233c(2011:41d0:801:1000::233c) 56 data bytes
From 2001:41d0:801:1000::23b2 icmp_seq=1 Destination unreachable: Address unreachable
...
--- 2001:41d0:801:1000::233c ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2030ms
  

Aïe, c'est raté, alors que les deux machines sont bien dans le même préfixe de longueur 56. Pourquoi ? Parce que les machines ne sont pas réellement sur un réseau local dont le préfixe ferait 56 bits. Elles doivent en fait toujours passer par le routeur, comme si elles étaient sur une liaison point-à-point avec ce routeur. (Pour la même raison, un tcpdump ne montrera pas de trafic, à part avec le routeur, par exemple du trafic NTP.)

Pour que cela marche, il faut renoncer à parler directement avec les machines proches, et corriger la configuration. Ce sont des Debian, on va éditer le fichier /etc/network/interfaces.d/50-cloud-init et remplacer la longueur incorrecte (56) par la bonne (128). Et on n'oublie pas de rajouter une route vers le routeur avant de définir la route par défaut. On redémarre et ça marche :

% ping -c 3 2001:41d0:801:1000::233c
PING 2001:41d0:801:1000::233c(2001:41d0:801:1000::233c) 56 data bytes
64 bytes from 2001:41d0:801:1000::233c: icmp_seq=1 ttl=57 time=0.810 ms
64 bytes from 2001:41d0:801:1000::233c: icmp_seq=2 ttl=57 time=0.746 ms
64 bytes from 2001:41d0:801:1000::233c: icmp_seq=3 ttl=57 time=0.764 ms

--- 2001:41d0:801:1000::233c ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2037ms
rtt min/avg/max/mdev = 0.746/0.773/0.810/0.026 ms

Et la table de routage nous montre que tout va passer par le routeur :

% ip -6 route show
...
2001:41d0:801:1000::1 dev ens3 metric 1 onlink pref medium
2001:41d0:801:1000::233c dev ens3 proto kernel metric 256 pref medium
default via 2001:41d0:801:1000::1 dev ens3 metric 1 pref medium

Il est dommage qu'on ne puisse pas parler directement aux autres machines du même préfixe. Peut-être est-ce pour des raisons de sécurité, ces machines pouvant appartenir à des organisations différentes ? C'est en effet la même chose en IPv4 mais, cette fois, avec une configuration par défaut qui est correcte (un préfixe de longueur 32).

Si vous créez beaucoup de machines virtuelles et qu'on vous n'avez pas envie de tout corriger à la main, et que, comme moi, vous utilisez Ansible, voici un playbook qui fait les choses plus ou moins proprement :


---
- hosts: coursipv6
  become: yes
  become_method: sudo
  tasks:
    - name: Broken IPv6 config at OVH
      lineinfile: 
        path: /etc/network/interfaces.d/50-cloud-init
        regexp: 'address {{ ipv6_address }}/56$' 
        line: 'address {{ ipv6_address }}/128'
        backrefs: yes

    - name: Broken IPv6 routing at OVH
      lineinfile: 
        path: /etc/network/interfaces.d/50-cloud-init
        regexp: 'route add -A inet6 default gw {{ ipv6_gateway }} || true$'
        line: '\tpost-up ip -6 route add {{ ipv6_gateway }} dev ens3 && route add -A inet6 default gw {{ ipv6_gateway }} || true'
        backrefs: yes


L'article seul

Fiche de lecture : Datamania - le grand pillage de nos données personnelles

Auteur(s) du livre : Audric Gueidan, Halfbob
Éditeur : Dunod
978-2-10-083732-1
Publié en 2023
Première rédaction de cet article le 15 mars 2023


La plupart des lecteurices de ce blog savent que, sur l'Internet, on laisse des traces partout et que nos données personnelles sont peu protégées. (Le discours policier « l'Internet, c'est l'anonymat » est de la pure propagande.) Mais bien que ce fait soit largement connu et documenté, même au-delà des lecteurices de ce blog, on ne constate pas de changement de comportement des utilisateurices. Ceux et celles-ci continuent à distribuer trop largement leurs données personnelles. Il y a de nombreuses raisons à cet état de fait et je ne vais pas toutes les discuter. Mais une des raisons, pensent les auteurs de ce livre, est le manque d'information ; les utilisateurices ont bien entendu dire qu'il y avait des problèmes avec les données personnelles mais ielles ne mesurent pas complètement l'ampleur de ces problèmes, ni les formes qu'ils prennent. Comment leur expliquer ? Les auteurs tentent une BD, « Datamania ».

Alors, une BD, c'est du texte et du dessin. Personnellement, je ne suis pas très enthousiaste pour ce style de dessin (vous pouvez voir certains de ces dessins dans l'article de GeekJunior) mais comme les goûts artistiques varient, je n'argumenterai pas sur ce point. Le texte est léger et amusant, et couvre bien les sujets. Aucune erreur technique, les auteurs font preuve de beaucoup de rigueur. L'idée est d'expliquer à des gens qui n'ont pas envie de lire tous les rapports de la CNIL. Est-ce réussi ? Bon, il est clair que je ne suis pas le cœur de cible, le livre vise des gens pas très informés. Mais, justement, je trouve que le livre n'explique pas assez et qu'il abuse des private jokes. Certaines de ces allusions sont expliquées dans l'annexe « Avez-vous remarqué ? » mais j'avoue que je me suis demandé si un·e lecteurice ordinaire ne va pas rester perplexe. (Les lecteurices qui connaissent le sujet peuvent s'amuser, sans lire cette annexe, à repérer toutes les allusions à des personnes ou organisations connues.)

Le sujet, il est vrai, est très riche et très complexe. Le livre parle de surveillance, de logiciel libre, de cookies, de chiffrement et de beaucoup d'autres choses, et ne peut évidemment pas tout traiter en détail. (Un gros plus pour avoir cité Exodus Privacy.) Je conseillerai de l'utiliser comme introduction, ou comme support à des ateliers mais je ne suis pas sûr qu'il puisse être utilisé en autonomie par des utilisateurices ordinaires. (Bon, après, c'est vrai que je suis exigeant ; qu'en pensent d'autres personnes ? Voyez l'article de GeekJunior ou celui de Médias-Cité.)

Note : j'ai reçu un exemplaire gratuit du livre de la part des auteurs.


L'article seul

The Drink DNS server at FOSDEM

First publication of this article on 13 February 2023


The great technical conference FOSDEM resumed physical activity after two years of purely online events. I had the pleasure to make a small talk at the DNS devroom about the Drink dynamic authoritative DNS server.

The slides are available on the official site. The recorded video is available at the same place, as well as links to the source code, etc.


L'article seul

Mon exposé sur la neutralité du code à Touraine Tech

Première rédaction de cet article le 23 janvier 2023


Le 20 janvier de cette année, à la conférence informatique Touraine Tech, j'ai fait un exposé sur la neutralité du code. Lorsque le ou la développeureuse dit « je ne fais pas de politique, ce programme pourra être utilisé pour différents buts », est-ce possible ?

Il y avait à cet évènement de nombreuses autres conférences intéressantes(sans compter les fouées aux rillettes) :

  • L'introduction de Ploum, très drôle et très vivante,
  • la conférence d'Amélie Abdallah « Féminisation dans la tech : la communication, ou l'échec de tout un secteur » sur le sexisme dans l'informatique et comment le combattre (supports ici),
  • celle de Jimmy Kasprzak, « Développer et enseigner, une bonne idée ? » sur l'importance et la difficulté de l'enseignement,
  • la conférence dessinée (très bons dessins) de Victor Lambret sur les méthodes de développement logiciel, où comment des études scientifiques montrent que les conseils de bon sens des consultants, même appuyés sur un sigle à la mode (comme TDD) ne produisent pas de meilleur code,
  • celle de Cécile Freyd-Foucault et Iris Naudin le jeudi soir, sur des thèmes classiques (accessibilité et fracture numérique) mais très bien traités (à faire suivre par les gens qui ignorent encore le problème) ; les références utilisées pour leur exposé sont en ligne, j'ai beaucoup aimé l'article d'Anne-Sophie Tranchet sur les formulaires odieux,
  • l'amusant « Développer publiquement un site en milieu hostile : retour d'expérience », d'Alexis Lozano, où il détaille les étapes sucessives d'un petit projet Web avec contenu fourni par les utilisateurices, et les problèmes successifs dûs aux abrutis, exposé très bien fait, très intéressant et concret,
  • comme aujourd'hui on fait de l'IA partout, la conférence « Si on aidait le capitaine Némo à classifier les monstres marins ? » de Eléa Petton et Stéphane Philippart, est recommandée, un tutoriel nous guidant pas à pas dans la construction d'une application de reconnaissance de sons, très pédagogique. Plusieurs démonstrations concrètes avec Python et Jupyter (et les bibliothèques librosa, pandas, sklearn, tensorflow, etc).
  • et enfin la conférence très détaillée de Fabien Trégan et Olivier Poncet sur la représentation des nombres dans les ordinateurs (même si vous savez déjà que (1/3)*3 ne fait pas 1, vous y apprendrez des choses), avec des supports écrits à la main sur un fond évoquant un cahier d'écolier.

Les vidéos de ces différentes conférences sont en ligne (la mienne aussi).

Un exposé d'Olivier Mertens portait sur le générateur d'images DALL-E (fait par la même société que ChatGPT). J'ai donc demandé à DALL-E « Une conférence à TouraineTech dans le style de François Boucher [puisqu'il y avait une exposition de ce dernier au Musée des Beaux-Arts] » et le résultat est… pas terrible : touraine-tech-2023-dall-e.jpg.

Et merci mille fois aux organisateurices (une telle conférence crée beaucoup de travail), et à Florian Roulet pour m'avoir invité à y prendre la parole.

Ploum et moi dédicaçant nos livres : touraine-tech-2023-dedicaces.jpg


L'article seul

ChatGPT remplacera t-il les programmeuses et programmeurs ?

Première rédaction de cet article le 3 janvier 2023


Si Ada Lovelace était la première programmeuse, les programmeuses et programmeurs actuel·les sont-ielles les dernièr·es ? Un programme « intelligent » comme ChatGPT va-t-il les condamner à la reconversion ou au chômage ? Je continue ici mon exploration de ChatGPT.

ChatGPT a beaucoup été utilisé pour la programmation. Voici une session où je lui demande des programmes (ce sera la seule image, dans le reste de l'article, je copierai le texte).

Exemple d'utilisation :chatgpt-http-elixir.png

Le programme est écrit en Elixir car mes questions précédentes portaient sur ce langage et ChatGPT mémorise les conversations (et il s'en sert, est-on averti, pour s'améliorer donc ne lui donnez pas d'informations confidentielles). L'utilisation d'Elixir montre que ChatGPT connait beaucoup de choses, y compris des langages assez rarement utilisés. C'est logique : pour le quantitatif (la mémorisation et la restitution d'énormes quantités d'informations), les ordinateurs sont certainement meilleurs que les humains. D'autre part, celles et ceux qui ont lu mon précédent article noteront que j'ai maintenant un compte ChatGPT, ayant trouvé un numéro de téléphone sacrifiable.

Beaucoup de gens ont été impressionnés par les qualités de ChatGPT et, voyant la facilité avec laquelle il génère des programmes (et les explique !), se sont dit que les programmeuses et les programmeurs allaient disparaitre. Un tel discours fait rêver bien des patrons, qui apprécieraient de remplacer des développeurs et développeuses payés chers par une IA docile et obéissante. Ce discours est donc très ancien dans l'informatique, Cobol avait déjà été promu avec cet argument. Et c'était également le cas de Fortran (« FORTRAN should virtually eliminate coding and debugging »). Même si ces affirmations semblent techniquement ridicules aujourd'hui, à l'époque, le progrès par rapport au langage d'assemblage était tel que cela ne semblait pas absurde. Puis on a entendu à nouveau ce raisonnement du temps des L4G puis récemment du nocode. Le fait que les espérances des patrons aient été déçues à chaque fois ne les empêche pas de garder espoir.

Voyons donc ce que sait faire ChatGPT. D'abord, on l'a dit, il connait beaucoup de choses. Je demande « Je dois trier une liste de chaînes de caractères [un exercice banal de débutant]. Comment faire ? » et ChatGPT répond « Pour trier une liste de chaînes de caractères en Elixir, vous pouvez utiliser la fonction Enum.sort/1. Cette fonction prend en entrée une liste et renvoie une liste triée de ses éléments. Voici un exemple de code qui trie une liste de chaînes de caractères en ordre croissant : »

strings = ["c", "b", "a", "d"]
sorted_strings = Enum.sort(strings)
IO.inspect(sorted_strings) # ["a", "b", "c", "d"]

Il connait la bibliothèque standard d'Elixir (où il y a bien un Enum.sort) et aussi des idiosyncrasies d'Elixir comme le fait de nommer une fonction en terminant par son arité. Et il ajoute spontanément « Si vous voulez trier la liste en ordre décroissant, vous pouvez utiliser la fonction Enum.sort/2 et lui fournir une fonction de comparaison qui renvoie :gt si le premier argument est plus grand que le second, :lt si le premier argument est plus petit que le second, et :eq s'ils sont égaux. Voici un exemple de code qui trie une liste de chaînes de caractères en ordre décroissant : »

strings = ["c", "b", "a", "d"]
sorted_strings = Enum.sort(strings, fn x, y -> if x > y do :gt else if x < y do :lt else :eq end end)
IO.inspect(sorted_strings) # ["d", "c", "b", "a"]

(Les :gt et :lt sont appelés atomes et sont une des particularités d'Elixir. Je vous ai dit qu'il « connaissait » bien le langage.)

Mais ce second code pose déjà des problèmes. D'abord, il ne compile même pas (il manque un end). Mais, surtout, ChatGPT n'a pas bien lu la documentation : la fonction passée en argument à sort est censée renvoyer un booléen, pas ces atomes. On voit là une première chose à garder en mémoire : on ne peut pas en général utiliser les programmes produits par ChatGPT tels quels, il faut les vérifier, et cette vérification doit être faite par une personne compétente en programmation. Et il n'est pas évident que l'entièreté du processus soit plus rapide et plus sûr que si cette personne compétente avait tout fait elle-même. (L'erreur de syntaxe est la moins grave, car elle est détectée à la compilation. Le pire serait une erreur qui ne planterait pas mais donnerait un résultat faux.)

Ceci dit, ChatGPT apprend et il est interactif. Voyons cela sur un autre exemple : « Comment décomposer un entier de grande taille en ses facteurs premiers ? ». ChatGPT répond « Pour décomposer un entier en ses facteurs premiers en Elixir, vous pouvez utiliser une approche récursive. Voici comment vous pouvez implémenter cette approche : »

defmodule PrimeFactors do
  def factors(n, divisor \\ 2) when divisor > n do
    [n]
  end
  def factors(n, divisor \\ 2) do
    if rem(n, divisor) == 0 do
      [divisor | factors(n / divisor, divisor)]
    else
      factors(n, divisor + 1)
    end
  end
end    

Cette fois, il n'y a pas d'erreur de syntaxe, mais cela ne compile quand même pas, en raison d'une erreur sémantique. Et il y a deux autres bogues (trouver l'une d'elles nécessite de connaitre Elixir). Mais comme ChatGPT est interactif, je lui explique : « Attention, on ne peut pas avoir deux définitions avec des valeurs par défaut. Il faut réécrire ton code. » Il me répond que j'ai raison (d'autres personnes ont vu ChatGPT nier des problèmes) et « Vous avez raison, il n'est pas possible d'avoir deux définitions avec des valeurs par défaut pour le même nom de fonction en Elixir. Pour résoudre ce problème, vous pouvez utiliser une seule définition de fonction avec une valeur par défaut pour le diviseur, et ajouter une condition pour gérer le cas où le diviseur est supérieur à n. Voici comment vous pouvez réécrire le code : »

    
defmodule PrimeFactors do
  def factors(n, divisor \\ 2) when divisor > n do
    [n]
  end
  def factors(n, divisor \\ 2) do
    if divisor > n do
      [n]
    else
      if rem(n, divisor) == 0 do
        [divisor | factors(n / divisor, divisor)]
      else
        factors(n, divisor + 1)
      end
    end
  end
end

  

Et il ajoute spontanément « Je vous recommande également de changer le nom de la fonction factors/2 en factors/1 et de changer la condition de la clause de cas factors/1 pour qu'elle vérifie si n est inférieur ou égal à 1. Voici comment le code final devrait ressembler [sic] : »


defmodule PrimeFactors do
  def factors(n, divisor \\ 2) when n <= 1 do
    []
  end
  def factors(n, divisor \\ 2) do
    if rem(n, divisor) == 0 do
      [divisor | factors(n / divisor, divisor)]
    else
      factors(n, divisor + 1)
    end
  end
end

  

C'est amusant, le code réécrit a toujours la même bogue sur la définition de fonctions avec des valeurs par défaut. Par contre, ChatGPT a « réfléchi » et a corrigé une des autres bogues (qui faisait que le nombre 1 était listé comme facteur premier). Bon, tant pis, je corrige manuellement et je lui signale la troisième bogue (celle qui nécessite de connaitre Elixir) : « Et attention, le / fait une division de réels, il faudrait utiliser div. ». Il le reconnait : « Vous avez raison, la fonction / en Elixir effectue une division de réels et non une division entière. Pour effectuer une division entière, vous pouvez utiliser la fonction div/2. Voici comment vous pouvez utiliser la fonction div/2 dans la fonction factors/1 : »


defmodule PrimeFactors do
  def factors(n, divisor \\ 2) when n <= 1 do
    []
  end
  def factors(n, divisor \\ 2) do
    if rem(n, divisor) == 0 do
      [divisor | factors(div(n, divisor), divisor)]
    else
      factors(n, divisor + 1)
    end
  end
end

  

À noter que ChatGPT avait montré qu'il connaissait l'éco-système Elixir, en expliquant comment tester avec l'interpréteur iex :

iex> PrimeFactors.factors(12)
[2, 2, 3]
iex> PrimeFactors.factors(2310)
[2, 3, 5, 7, 11]
iex> PrimeFactors.factors(7829)
[7829]
  

Prenons un autre exemple qui illustre la question du cahier des charges. En programmation dans le monde réel, c'est souvent la principale difficulté ; le·a programmeur·se passe souvent davantage de temps à comprendre un cahier des charges incomplet, contradictoire et irréaliste qu'à programmer. Commençons simplement : « Écris un programme en Python qui donne la liste des nombres allant jusqu'à N. ». ChatGPT répond :

# Demande à l'utilisateur de saisir un entier N
n = int(input("Entrez un entier N : "))

# Initialise une liste vide
l = []

# Pour chaque entier i allant de 1 à N
for i in range(1, n+1):
  # Ajoute i à la liste
  l.append(i)

# Affiche la liste
print(l)

Et explique « Ce programme demande à l'utilisateur de saisir un entier N, initialise une liste vide, puis utilise une boucle for pour ajouter chaque entier allant de 1 à N à la liste. Enfin, il affiche la liste. ». Modifions le cahier des charges (ce qui est courant) : «  Il faut que cela marche avec des entiers relatifs. » ChatGPT ne se démonte pas pour si peu « Pas de problème, voici une version modifiée du programme qui prend en compte les entiers relatifs : »

  
# Demande à l'utilisateur de saisir un entier N
n = int(input("Entrez un entier N : "))

# Initialise une liste vide
l = []

# Si N est positif
if n > 0:
  # Pour chaque entier i allant de 1 à N
  for i in range(1, n+1):
    # Ajoute i à la liste
    l.append(i)

# Si N est négatif
elif n < 0:
  # Pour chaque entier i allant de N à -1 (inclus)
  for i in range(n, 0):
    # Ajoute i à la liste
    l.append(i)

# Si N est égal à 0
else:
  # Ajoute 0 à la liste
  l.append(0)

# Affiche la liste
print(l)

Et explique « Cette version vérifie si N est positif, négatif ou égal à 0 et utilise une boucle for appropriée pour ajouter les entiers à la liste. Si N est égal à 0, 0 est simplement ajouté à la liste. » On voit que ChatGPT est parfaitement capable de faire des exercices de programmation pour grands débutants, par exemple au lycée. Mais comme je suis méchant, je lui demande ensuite un programme qui marche avec les nombres réels, ce qui est impossible. Il me fait alors une variante qui énumère, mais avec un pas (qu'il a choisi arbitrairement) de 0,1. Dois-je le considérer comme très bête ou comme très intelligent d'avoir interprété de manière créative un cahier des charges absurde ? En tout cas, cet exemple montre à quoi ressemble souvent le travail de programmation : il faut de nombreuses itérations avant d'avoir une idée claire de ce qui est demandé et un programme comme ChatGPT n'est pas forcément le mieux placé pour cela. (Mes lecteurices qui connaissent la programmation auront déjà fait remarquer in petto que si on ne peut pas énumérer les réels - qui sont en nombre infini dans tout intervalle, quelle que soit sa taille, on pourrait par contre énumérer les nombres en virgule flottante représentables sur la machine. Mais ChatGPT n'y a pas pensé.)

Mais, bref, on est encore loin d'un système qui pourrait permettre de se passer complètement des développeurs et développeuses. Il peut aider, c'est certain, faisant gagner du temps lorsqu'on a oublié comment faire une requête HTTP dans tel ou tel langage de programmation, il peut servir d'« auto-complétion améliorée » mais cela ne permet pas de lui confier tout le travail. Alors, certes, il s'agit d'Elixir, mais est-ce que cela marcherait mieux avec des langages de programmation plus répandus ? J'en doute. Mémoriser une grande quantité d'informations et pouvoir en ressortir à volonté est justement le point fort des ordinateurs. Contrairement à un humain, apprendre un langage de plus ne nécessite guère d'effort. Les différents messages lus sur les réseaux sociaux semblent indiquer que des langages bien plus communs qu'Elixir ont le même problème (pareil pour la simple algèbre).

Parmi les autres faiblesses de ChatGPT qui font obstacle à une utilisation en totale autonomie, notons aussi :

  • ChatGPT n'est pas réflexif, il ne s'analyse pas lui-même et n'est pas capable de donner un degré de certitude sur ses « solutions ». Il affirme souvent des choses fausses avec le même niveau de confiance que les choses les plus indiscutables. Et il invente souvent des choses qui n'existent pas (articles scientifiques, options de logiciel, etc).
  • Certains promoteurs de ChatGPT disent ne pas s'inquiéter de la mauvaise qualité (parfois) du code en considérant que, du moment que « ça marche », c'est suffisant. Mais cet argument ne vaut pas pour la sécurité. Si un programmme a une faille de sécurité, il va marcher, mais être néanmoins dangereux.

En conclusion, oui, ChatGPT et les logiciels similaires vont changer la programmation (comme Cobol et Fortran l'avaient fait) mais croire qu'ils vont permettre de se passer de programmeur-ses est illusoire. Les développeur·euses qui produisent du code de basse qualité à la chaîne ont du souci à se faire pour leur avenir professionnel mais cela ne concerne pas celles et ceux qui font du code créatif, difficile, novateur, ou simplement bien adapté à leur problème. ChatGPT est très fort pour des tests simplistes, comme ceux souvent faits à l'embauche mais pour de vrais programmes ? C'est un point souvent oublié par les personnes qui ne connaissent pas la programmation : écrire un petit script qui fait une tâche simple n'est pas la même chose que de programmer Apache, Louvois, ou un logiciel de calcul scientifique comme Blast.

Quelques réflexions et éléments sur ce sujet :


L'article seul

Un modeste avis sur ChatGPT

Première rédaction de cet article le 14 décembre 2022


Tout le monde aujourd'hui utilise ChatGPT et envoie sur les réseaux sociaux les résultats les plus amusants ou les plus spectaculaires. La plupart des retours sont admiratifs devant les performances de ce système d'« Intelligence Artificielle » (IA) pour répondre à des questions et générer des textes. Mais il faut nuancer un peu.

Tout d'abord, un sérieux avertissement : je n'ai pas essayé ChatGPT moi-même, en raison de leur demande excessive de données personnelles (il faut indiquer une adresse de courrier et un numéro de téléphone, et les deux sont vérifiées par envoi d'un code à retourner ensuite ; on ne peut donc pas tricher). J'ai seulement lu les résultats de ChatGPT tels que publiés par ses utilisateurs. Si vous pensez que cela rend cet article sans valeur, arrêtez votre lecture tout de suite et allez faire autre chose, par exemple regarder les belles aquarelles d'Aemarielle.

Maintenant, revenons à ChatGPT. On lui pose des questions et il répond. Le résultat est souvent étonnant, par exemple lorsqu'on lui demande des textes « écrits dans le style de [telle personne] » ou lorsqu'on l'interroge sur des questions techniques complexes. Cela illustre de manière publique les progrès importants des techniques connues sous le nom commercial d'IA (Intelligence Artificielle), ainsi que la quantité vraiment colossale de données que ChatGPT a lues et assimilées. Il est par exemple à noter que ChatGPT écrit des textes bien meilleurs que ce que font beaucoup d'humains, y compris dans un environnement professionnel (« écris un communiqué de presse se félicitant de l'augmentation de X % du chiffre d'affaires de la société Machin » donnera un résultat indistinguable du « vrai »). Notamment, il ne fait aucune faute d'orthographe ou de grammaire.

Est-ce que cela signifie qu'on peut réellement parler d'intelligence et que les humains sont désormais inutiles ? Pas si vite. D'abord, l'intelligence, ce n'est pas de savoir exécuter une tâche, c'est de savoir quelle tâche exécuter. De ce point de vue, ChatGPT est loin de l'intelligence. Plusieurs personnes ont pu constater qu'on pouvait lui demander des textes contradictoires (« explique pourquoi il est important d'augmenter les impôts » puis « explique pourquoi il faut baisser les impôts », et ChatGPT s'exécutera).

Ensuite, ce que révèle ChatGPT, ce ne sont pas tellement les progrès de l'IA que le creux et l'absence de contenu de beaucoup de textes produits par des humains. ChatGPT sait faire des devoirs d'étudiants de première année, écrire des communiqués de presse, du reporting et produire les discours des ministres. Grâce à ce système, on voit bien que ces textes n'ont pas tellement de fond et ne nécessitent pas beaucoup d'intelligence, uniquement la lecture et le traitement d'une grande quantité d'informations, tâche où les humains sont certainement inférieurs aux ordinateurs. ChatGPT ne remplacera donc pas les humains mais lui ou ses successeurs pourront prendre en charge des tâches qui étaient considérées à tort comme nécessitant de l'intelligence. Comme le note Stéphane Mouton, ChatGPT est toujours « correct mais superficiel ».

Cela va certainement « disrupter » certains secteurs, comme celui des rédacteurs sous-payés qui écrivent vite et mal. Pour prendre un autre exemple, j'ai vu des étudiants de master produire des notes qui ne valaient pas ce que fait ChatGPT. L'enseignement devra donc s'adapter. Mais cela poussera à réfléchir à ce que nous voulons que les humains fassent. Écrire des synthèses fades et sans originalité ou bien travailler de manière plus créative ?

Mais, diront certains, ChatGPT et l'IA en général vont continuer à progresser. Les limites actuelles seront forcément dépassées. Eh bien non, ou plus exactement, c'est plus compliqué que cela. La marche du progrès technique peut faire croire que le progrès est forcément linéaire, chaque année marquant une amélioration technique. Des observations comme la loi de Moore vont en ce sens. Mais ce n'est pas une règle générale du progrès. Il y a également des techniques qui stagnent, ou qui ne progressent que par bonds imprévisibles. L'IA en est un bon exemple : depuis ses débuts (qui sont à peu près ceux de l'informatique), elle alterne des bonds spectaculaires avec de longues périodes de repos, le bond spectaculaire ayant été suivi d'une constatation qu'on n'arrivait pas à l'améliorer. Peut-être que ChatGPT va progresser, ou peut-être qu'il ne dépassera pas son stade actuel avant longtemps, mais on ne peut pas affirmer qu'il fera forcément mieux dans le futur.

Et sinon, non, petits coquins, cet article n'a pas été écrit par ChatGPT, Bruce Schneier a fait la blague avant moi (et je suis d'accord avec la plupart des commentaires à son article ; l'article est sans erreur mais enfonce des portes ouvertes et ne fait preuve d'aucune réflexion).


L'article seul

RFC 8521: Registration Data Access Protocol (RDAP) Object Tagging

Date de publication du RFC : Novembre 2018
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs), A. Newton (ARIN)
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 23 novembre 2022


Contrairement à son lointain prédécesseur whois, le protocole d'accès aux informations des registres RDAP a un mécanisme standard de découverte du serveur faisant autorité. Ce mécanisme est prévu pour des données organisées de manière arborescente comme les noms de domaine ou les adresses IP. Pour des objets qui n'ont pas cette organisation, comment faire ? Ce RFC fournit une solution pour des objets quelconques, s'ils obéissent à une convention de nommage simple. C'est le cas des handles, ces identificateurs d'entités (titulaires de noms de domaine, contacts pour un préfixe IP, etc) ; s'ils sont de la forme QUELQUECHOSE-REGISTRE, on pourra trouver le serveur responsable.

Le mécanisme habituel de découverte du serveur est normalisé dans le RFC 9224. En gros, l'IANA garde un registre des serveurs, indexé par un nom de domaine ou par un préfixe IP. Ce registre est au format JSON. Un client RDAP est juste censé télécharger ce fichier, trouver le serveur faisant autorité, puis le contacter. Pour pouvoir faire la même chose avec des objets non structurés, il faut leur imposer une convention de nommage. Si on interroge avec RDAP (ou whois) l'adresse IP 88.198.21.14, on voit que son contact technique est HOAC1-RIPE. Cette convention de nommage est « d'abord un identifiant unique au sein du registre, puis un tiret, puis le nom du registre, ici le RIPE-NCC ». L'IANA a juste à garder un registre de ces registres qui nous dira, par exemple, que RIPE a comme serveur RDAP https://rdap.db.ripe.net/. On peut ensuite l'interroger en RDAP :

%  curl https://rdap.db.ripe.net/entity/HOAC1-RIPE
   "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "Hetzner Online GmbH - Contact Role" ], [ "kind", { }, "text", "group" ], [ "adr", {
    "label" : "Hetzner Online GmbH\nIndustriestrasse 25\nD-91710 Gunzenhausen\nGermany"
  }, "text", [ "", "", "", "", "", "", "" ] ], [ "tel", {
    "type" : "voice"
  }, "text", "+49 9831 505-0" ], [ "tel", {
...
  

Petit piège, la partie du début peut elle-même comporter des tirets donc lorsqu'on coupe en deux un handle, il faut le faire sur le dernier tiret (section 2 du RFC). Pourquoi le tiret, d'ailleurs ? Parce qu'il est couramment utilisé comme séparateur, et parce que son utilisation dans un URL ne pose pas de problème particulier (RDAP utilise HTTPS et donc des URL).

Le registre des serveurs RDAP est géré à l'IANA comporte un tableau JSON des services, chaque entrée étant composée de trois tableaux, la liste des adresses de courrier du responsable, la liste des suffixes (en général, un seul par registre) et la liste des serveurs RDAP. Par exemple, pour l'ARIN, on aura :

[
      [
        "andy@arin.net"
      ],
      [
        "ARIN"
      ],
      [
        "https://rdap.arin.net/registry/",
        "http://rdap.arin.net/registry/"
      ]
]  
  

Les entrées dans le registre sont ajoutées selon la politique « Premier Arrivé, Premier Servi » du RFC 8126.

Comme ce RFC décrit une extension à RDAP, le serveur RDAP doit ajouter à sa réponse, dans l'objet rdapConformance, rdap_objectTag_level_0. (Apparemment, personne ne le fait.)

Vous voulez du code ? La bibliothèque ianardap.py, qui est disponible en ligne, peut récupérer la base et l'analyser. Cela permet ensuite de faire des requêtes pour des objets :

% ./dump-object.py F11598-FRNIC  | jq .
...
       [
          "",
          "",
          "Association Framasoft c/o Locaux Motiv",
          "Lyon",
          "",
          "69007",
          "FR"
        ]
...
  

Le programme dump-object.py étant simplement :

#!/usr/bin/env python3

import ianardap

import requests

import sys

rdap = ianardap.IanaRDAPDatabase(category="objects")
for object in sys.argv[1:]:
    url = rdap.find(object)
    if url is None:
        print("No RDAP server for %s" % object, file=sys.stderr)
        continue
    response = requests.get("%sentity/%s" % (url[0], object))
    print(response.text)
  

Téléchargez le RFC 8521


L'article seul

Capitole du Libre 2022

Première rédaction de cet article le 21 novembre 2022
Dernière mise à jour le 21 février 2023


Les 19 et 20 novembre 2022, c'était Capitole du Libre à Toulouse, un rassemblement libriste important, qui reprenait après l'interruption Covid-19. Il y avait beaucoup de rencontres, d'ateliers et de conférences intéressantes. (En tout, 118 orateurs, 97 conférences, 16 ateliers et 39 stands au village associatif.)

J'ai fait deux exposés. Le premier, un peu plus politique, portait sur une question de programmation. Maintenant que tout est chiffré, comment déboguer les applications réseau alors qu'on ne peut plus utiliser Wireshark comme avant ? Il existe plusieurs solutions, de la lutte pour limiter le chiffrement, comme le font encore certains réactionnaires, à la coopération de l'application, qui est l'avenir. Voici la version en PDF, et le source en LaTeX/Beamer.

Le second exposé tirait les leçons du développement de Drink, un serveur DNS faisant autorité voué aux réponses dynamiquement générées. Voici la version en PDF, et le source en LaTeX/Beamer. Le code de Drink est disponible en ligne.

J'ai aussi participé à une table ronde sur le thème de la « souveraineté numérique », avec Gaël Duval, Philippe Latombe, et Amandine Le Pape, table ronde animée par Étienne Gonnu.

J'ai également participé à une séance dédicace de mon livre « Cyberstructure », qui avait été annoncé pour la première fois publiquement au Capitole du Libre il y a quatre ans. La séance était organisée par la librairie « Les petits ruisseaux ». J'étais à côté de David Revoy, l'auteur de Pepper et Carrot, qui faisait de superbes dessins.

Le programme de Capitole du Libre était très riche. J'ai beaucoup aimé « Introduction à Rust embarqué » de Sylvain Wallez, avec des belles démonstrations (l'inévitable diode clignotante) de ce langage en direct, sur un ATtiny85 (0,5 ko de RAM, 8 ko de flash) et un plus gros microcontrôleur ESP32. Également très technique, la descente en profondeur dans les entrailles des composants Ethernet « Plongée au coeur d'Ethernet, et son support dans Linux », de Maxime Chevallier.

Des enregistrements vidéo ont été faits et sont disponibles en ligne (dont les miens, le serveur DNS Drink et le déboguage d'applications chiffrées).


L'article seul

Survey of the DNS servers in the fediverse

First publication of this article on 18 November 2022


The fediverse is supposed to be decentralized. But the fact that the network has a decentralized architecture does not mean that it is perfectly decentralized in practice. We survey here the DNS authoritative servers for the domains used by the fediverse instances. Unfortunately, yes, they are too concentrated.

Mostly because of the incredibly childish behaviour of Elon Musk, the current wave of migration from Twitter to the fediverse is much larger than the previous ones. As a result, there is a renewed interest in the fediverse, a system which is far from recent. The fediverse is made of various instances, each one being independently administered, both from a technical point of view, and from a political one. Nothing new or extraordinary, this is how the Internet was architectured, and how its services worked, before a few centralized US-based giants distorted the vision of many people, making them believe that centralization is normal. Each fediverse instance has a domain name and this domain name is hosted on a set of authoritative name servers, which will reply to the DNS requests of the clients, the DNS resolvers. As an example, the instance I use, mastodon.gougere.fr is in the domain gougere.fr, whose set of authoritative name servers is currently composed of three servers. Unix users can for instance display them with dig :

% dig +short NS gougere.fr  
nsb.bookmyname.com.
nsa.bookmyname.com.
nsc.bookmyname.com.
  

Note you can also perform DNS queries on the fediverse itself, as explained here (see the current result).

A domain "works", for the users, only if the authoritative name servers reply, and reply properly. This makes them critical infrastructure for an instance. If your DNS authoritative servers fail, or lie, the instance is unusable, even if the Pleroma, Mastodon or other server still works fine. So, what are the DNS servers used for this critical role in the current fediverse?

To get data, I started from a list of current instances. I got one from instances.social. Note that, on a decentralized network like the fediverse, you cannot get an official and complete list of all instances. All lists are imperfect. But I have to start from somewhere (other possibilities: http://demo.fedilist.com/instance or the public list of peers of a big instance such as https://mastodon.social/api/v1/instance/peers). So, I created an authentication token on instances.social, and retrieved a list with curl:


% curl -s -H "Authorization: Bearer MY-TOKEN" https://instances.social/api/1.0/instances/list\?count=10000\&include_down=false > list.json 

I included only live instances (include_down=false) but, still, some instance names already were missing from the DNS.

The resulting list was in the JSON format and processed by two Python scripts (see the code later). The first one queried the DNS (with the excellent dnspython library) to get information such as the list of authoritative name servers and their IP addresses. The second script processed the JSON data of the first to output meaningful statistics. Of course, like with any quantitative survey, the hard problem is often which questions to ask, rather than the answers.

Let's start with the actual numbers:

%./nameservers-fediverse-analyze.py
There are 1596 instances
  

Remember that the list is incomplete (no one knows how many instances really live). Some of these instances are grouped into the same registered domain (the domain you bought from a registry, may be through a registrar). I choosed to group the instance names in the DNS zones (a set of contiguous names hosted on the same set of name servers). For instance, medievalist.masto.host and piano.masto.host are in the same zone, masto.host, they have the same servers. There are a bit less zones than instance names:

There are 1596 instances in 1540 zones. The largest zone, masto.host., encompasses 10 instances
  

Except masto.host, there are few fediverse hosters with such subdomains, so no sign of concentration/centralisation here. There is no giant fediverse hoster.

Now, the name servers themselves:

There are 2062 nameservers. The largest one, dns2.registrar-servers.com., hosts 85 instances.
  

Some name servers are more common, such as this dns2.registrar-servers.com, used by a big DNS hoster. But it is still only for a small minority of instances.

But wait, name servers come in groups, called sets. The instance administrator, except if he or she is a DNS fan, typically does not cherry-pick his or her name servers, they use a set indicated by the DNS hoster. Let's study sets instead:

There are 951 nameserver sets. The largest one, dns1.registrar-servers.com.;dns2.registrar-servers.com., hosts 85 instances. The top 10 % hosts 677 instances.
  

There are less sets than instances (a sign of a small centralisation) but not by a large margin. The biggest set is not so big but we note that the top tenth of the sets hosts more than a third of the instances. There are not so many DNS providers.

But there is a catch. Some DNS hosters use a lot of names so you may think there are many various sets but they actually depend on one company, a bad thing for decentralisation. The typical example is Cloudflare, with a lot of cool names depending on the domain they host (eleanor.ns.cloudflare.com, sue.ns.cloudflare.com, etc). So, we have to group the name servers by company. One of the simplest ways is to find the registered domain of the name servers' names. To do so, we use the Public Suffix List, which is not authoritative and not perfect but sufficient for us. It will put all the Cloudflare names into one bucket, the registered domain cloudflare.com:

There are 667 nameserver's domains. The largest one, cloudflare.com, hosts 366 instances. The top 10 % hosts 1324 instances

This time, we have a clear sign of centralisation. A lot of seemingly independent instances have a shared provider, Cloudflare. If Cloudflare breaks, or does evil things, it will affect many instances. And the top 10 % of hosters serves the overwhelming majority of fediverse instances. For your information, the biggest ones are:

  • cloudflare.com: 366
  • registrar-servers.com: 91
  • gandi.net: 90
  • domaincontrol.com: 55
  • googledomains.com: 49
  • digitalocean.com: 48
  • linode.com: 39
  • inwx.de: 23
  • inwx.eu: 23

(It can be noticed that, unlike the fediverse itself, which uses a lot of "new TLDs" such as .social, the name servers are faithful to the old TLDs.) Playing with names, as seen in the Cloudflare case, complicated things. We have also the case of AWS which does not appear on the above list but they should; they use a lot of registered domains (awsdns-46.co.uk, awsdns-20.com, etc) so they appear as many different hosters. Also, about Cloudflare, remember that this survey is only about the DNS: I did not try to see where the server instance is hosted. I repeat: just DNS, no HTTP was used or considered here. (One also could note that some authoritative name servers are installed at one big machine hoster, which gives Cloudflare an even more prominent place.)

So, as you can see, but this is hardly a surprise, the fediverse is not perfect and there are signs of centralisation, at least as far as DNS is concerned.

The two programs used for this article are:

  • nameservers-fediverse-gather.py: it gathers information from the DNS and produces a JSON file storing, for each instance, its DNS zone, the name servers and their IP addresses (which were not used for this article). To find the DNS zone, it just climbs the DNS tree until it founds name server records.
  • nameservers-fediverse-analyze.py: it reads the JSON file produced by the first program and displays statistics.

Among the weaknesses of this analysis, you'll note that our instances are considered equal. But there are very small and very big instances. It could be useful to tweak results depending on the size of the instance. instances.social gives us this information but it has to be handled with care, it is just a declaration from the instance (and many accounts may be inactive, anyway).


L'article seul

Peut-on censurer tout en respectant la vie privée ?

Première rédaction de cet article le 10 novembre 2022


C'était le thème d'une réunion pendant l'IETF 115 à Londres. Pour censurer sur l'Internet, le censeur doit regarder ce à quoi l'utilisateur voulait accéder, ce qui pose des problèmes de vie privée évidents. Peut-on censurer sans violer la vie privée ?

Le problème était posé sous la forme d'une question technique mais, évidemment, c'est plus compliqué que cela. Avant de détailler tous les aspects, voyons comment fonctionne un mécanisme de censure simple : l'utilisateur veut visiter https://truc-interdit.example/, les équipements intermédiaires sur le réseau voient cette demande, la comparent à une liste de choses interdites et bloquent éventuellement la visite. On peut réaliser cela de plusieurs façons, par exemple par un résolveur DNS menteur ou par un relais HTTP qui regarde les URL. Peu importe : dans tous les cas, des équipements intermédiaires apprendront qu'on voulait accéder à telle ou telle ressource. C'est ennuyeux pour les droits humains et ça rentre en conflit avec des techniques comme DoT ou HTTPS, qui sont justement là pour empêcher ce genre d'interceptions.

Mes lectrices et lecteurs informaticien·nes peuvent faire une pause ici et se demander comment techniquement réaliser une telle interception sans apprendre l'identité de la ressource à laquelle on voulait accéder. C'est un exercice intellectuellement stimulant. Mais, je le dis tout de suite, le problème n'est pas purement technique. En attendant d'élargir la question, je vous laisse quelques minutes pour réfléchir à une solution technique.

C'est bon, les quelques minutes sont écoulées ? Une solution possible serait, pour le cas du Web, que votre navigateur condense l'URL et envoie cet URL condensé à un service de filtrage qui répond Oui ou Non. Cela préserverait la vie privée, tout en permettant le filtrage. (Oui, il y a quelques détails techniques à prendre en compte, il faut saler pour éviter la constitution de dictionnaires, et il faut canonicaliser pour éviter qu'un malin ne fasse varier les URL pour éviter la détection, etc. Mais ne laissez pas ces détails techniques vous absorber trop longtemps.)

Le vrai problème de cette technique ? Elle nécessite la coopération de l'utilisateur (plus exactement de ses logiciels). C'était le point soigneusement dissimulé par le groupe qui avait organisé cette réunion, l'Internet Watch Foundation. (Au passage, cette réunion était un side meeting, réunion qui utilise les salles de l'IETF mais qui n'est pas forcément approuvée par l'IETF.) Le titre officiel de la réunion était « Is Privacy preserving Web Filtering Possible? » alors qu'en fait le désir n'était pas de filtrer mais de censurer (le filtrage se fait avec le consentement de l'utilisateur, la censure contre son gré). Le présentateur avait introduit la réunion en disant que le but était d'éviter qu'un internaute innocent ne soit exposé contre son gré à des images pédo-pornographiques. Si c'était vraiment le cas, le problème serait simple : un logiciel de filtrage sur la machine de l'utilisateur, comme on fait avec les bloqueurs de publicité. Le cas de la pédo-pornographie est un peu plus complexe car, contrairement aux bloqueurs de publicité, on ne souhaite pas distribuer les listes d'URL bloqués (des pédophiles pourraient les utiliser pour aprendre de nouvelles ressources). Mais ce n'est pas un gros problème, la solution du service qu'on interroge en lui envoyant un condensat de l'URL suffit.

Non, le vrai problème, c'est le consentement de l'utilisaeur. Si vraiment, on veut rendre un service à l'utilisateur, le problème est relativement simple. Si on veut censurer sans l'accord de l'utilisateur, cela devient effectivement plus compliqué. L'argument comme quoi on voulait protéger l'utilisateur contre une exposition accidentelle ne tient donc pas.

L'Internet Watch Foundation a présenté le problème comme purement technique, sachant très bien que les participant·es à l'IETF sont passionné·es de technique et vont sauter sur l'occasion, cherchant des solutions complexes et intéressantes (par exemple du côté du chiffrement homomorphique, la solution miracle souvent citée). Mais on est là dans un cas où la question n'est pas technique, mais politique. Il n'y a aucun moyen magique de censurer sans le consentement de l'utilisateur et en respectant sa vie privée. Le but de l'IWF était probablement justement de montrer qu'il n'y avait pas de solution technique (« on a été de bonne volonté on a soumis, la question à l'IETF ») et qu'il fallait donc censurer sans se soucier de vie privée.

Notons aussi qu'une infrastructure de censure, une fois en place, sert à beaucoup de choses. La pédo-pornographie, par l'horreur qu'elle suscite, sert souvent à couper court aux débats et à mettre en place des systèmes de censure, qui seront ensuite utilisés pour bien d'autres choses.


L'article seul

IETF 115 Hackathon, DNS error reporting

First publication of this article on 8 November 2022


At the IETF 115 hackathon in London, I worked on DNS error reporting.

Remember that IETF develops the standards for the Internet, roughly from layer 3 to some parts of layer 7. One of the most important technologies at IETF is of course the DNS. The role of the IETF hackathons, that take place the weekend just before the IETF meeting, is to try to implement new ideas (not yet standardized) to see if it works (IETF prides itself on relying on "running code"). This time, we were four persons working on DNS error reporting. This technique is currently specified in an Internet Draft draft-ietf-dnsop-dns-error-reporting. The problem it tries to solve is the one of informing the managers of a zone that there is some technical problem detected by a DNS resolver. Today, if you don't test your zone thoroughly with tools like DNSviz or Zonemaster, you'll know that there is a problem only when users will complain on Twitter. It would be better to be told by your clients, the resolvers, before that.

The way it works is a follows:

  • The authoritative server for the zone returns in its replies an EDNS option indicating a report receiving domain.
  • The resolver, when it detects a problem, such as a wrong DNSSEC key, sees this indication and creates a DNS query encoding the problem and appending the report receiving domain.
  • The servers for the report receiving domain receives the query, processes it and stores it.
  • The zone administrator reads about the problem and acts accordingly.

You can see there are three actors and therefore three programs to modify (the last ones, the servers for the report receiving domain, could be unmodified authoritative name servers). I worked on the authoritative side, using the experimental name server Drink. Willem Toorop worked on the Unbound resolver and Shane Kerr on another (proprietary) authoritative server. Roy Arends helped, replied and modified the draft with our feedback.

The draft is quite simple and straightforward. Drink was modified to emit a new EDNS option:


report_to = Binary.from_list(encode(config()["reporting-agent"]))
length = byte_size(report_to)
Binary.append(<<Drink.EdnsCodes.reporting::unsigned-integer-size(16),
	length::unsigned-integer-size(16)>>, report_to)

  

And then to process the reports (the query type for the reports is TXT):

"report" ->
   if config()["services"]["report"] do
              case qtype do
                :txt ->
                  result = Drink.Reports.post(Enum.join(qname, "."))
                  %{:rcode => Drink.RCodes.noerror,
                    :data => [result],
                    :ttl => @report_ttl}
                :any -> @any_hinfo
                _ -> %{:rcode => Drink.RCodes.noerror}
              end
  

Reports are stored in a separate agent. Note that we check they are properly formed, with the label _er at the beginning and at the end:

  def post(value) do
    labels = String.split(value, ".")
    if List.last(labels) == "report" do
      labels = List.delete_at(labels, length(labels)-1) # Remove report
      if List.first(labels) == "_er" and List.last(labels) == "_er" do
        labels = List.delete_at(List.delete_at(labels, length(labels)-1), 0) # Remove _er
        error_code = List.last(labels) 
        qtype = List.first(labels) 
        qname = Enum.join(List.delete_at(List.delete_at(labels, length(labels)-1), 0), ".")
        Agent.update(__MODULE__,
          fn state ->
            [{error_code, qtype, qname} | state]
          end)
        "Thanks for the report of error #{error_code} on #{qname}"
      else
        # Else do nothing, probably QNAME minimization (or may be broken report)
        "Invalid report"
      end
    end
  end
  

From the outside, this looks like this:


% dig _er.1.foobar.example.9._er.report.dyn.courbu.re TXT
...
;; ANSWER SECTION:
_er.1.foobar.example.9._er.report.dyn.courbu.re. 24 IN TXT "Thanks for the report of error 9 on foobar.example"

;; AUTHORITY SECTION:
dyn.courbu.re.		15	IN	NS	dhcp-80f2.meeting.ietf.org.
...

  

Since Drink is fully dynamic, it allows us to send a response depending on the analysis of the report (but the draft says you can return anything, you can use a static TXT record). If the report is invalid:

% dig _er.1.foobar.example.9.missing-end.report.dyn.courbu.re TXT
...
;; ANSWER SECTION:
_er.1.foobar.example.9.missing-end.report.dyn.courbu.re. 30 IN TXT "Invalid report"
    

One can then retrieve the report, by asking the name server:

%   echo report | socat - UNIX-CONNECT:/home/stephane/.drink.sock
REPORT state:
foobar.example, 9
funny.example, 9;2
    

Lessons from the hackathon? Drink is well suited for rapid exprimentation (it was one of its goals), the draft is clear and simple and interoperability is fine. By querying the modified Unbound resolver, we see report queries arriving and being accepted. Here, a DNSSEC error:


% dig @2a04:b900:0:100::28 www.bogus.bortzmeyer.fr
...
;; OPT PSEUDOSECTION:
...
; EDE: 9 (DNSKEY Missing): (validation failure <www.bogus.bortzmeyer.fr. A IN>: key for validation bogus.bortzmeyer.fr. is marked as invalid because of a previous validation failure <www.bogus.bortzmeyer.fr. A IN>: No DNSKEY record from 2001:41d0:302:2200::180 for key bogus.bortzmeyer.fr. while building chain of trust)
...

     

(Errors are the errors specified in RFC 8914.) And Drink saw:

nov. 08 18:17:14 smoking Drink[365437]: [info]  185.49.141.28 queried for _er.1.www.bogus.bortzmeyer.fr.9._er.report.dyn.courbu.re/txt
     
% echo report | socat - UNIX-CONNECT:/home/stephane/.drink.sock
REPORT state:
foobar.example, 9
funny.example, 9;2
www.bogus.bortzmeyer.fr, 9
     

So, it is a success. You can see all the reports made at the end of the hackathon (ours is "IETF115-DNS-Hackathon-Results.pdf "). Outside of that, there is a Wireshark implementation of the EDNS option: wireshark-dns-error-reporting.jpeg

Because it is a work in progress, note that there were changes before, during and after the hackathon. The query type for the reports changed from NULL to TXT (the code for NULL was tested and works), the EDNS option is now returned only when the resolver asks for it (this is not yet done in Drink), the format of the query report changed, etc. The goal is to test, not to make stable code.

The code, written in Elixir, is available online. It is not yet merged in the master, you have to use the git branch error-reporting.


L'article seul

An IPC server (with Unix sockets) in Elixir

First publication of this article on 7 November 2022


While adding IPC support to an Internet server written in Elixir, I did not find a lot of documentation or examples about Unix sockets with Elixir. So, here it is.

Unix sockets (also mentioned as "domain" or "local") are a way to communicate between processes (hence IPC = Inter-Process Communication) on the same machine. As such, they are less general than TCP/IP sockets but they are more secure (you cannot connect from the outside, and you can retrieve the process identifier, user identity, etc of the client) and you can finely control access through normal file permissions since the socket appears as a file.

To have the server written in Elixir listen on such a socket, we first clean (we use the standard module File):

    
sockname = System.get_env("HOME") <> "/.test-ipc.sock"
File.rm(sockname) # We don't test the results, since we are not interested
   # if the file existed or not.

  

Then we can open the socket, using the Erlang socket library, indicating the type :local :


{:ok, s} = :socket.open(:local, :stream, %{})
:ok = :socket.bind(s, %{family: :local, path: sockname})
# You can add File.chmod here to set permissions
:ok = :socket.listen(s)

Note that we use pattern matching to be sure the operations succeeded (we would have better error messages with a code testing the different cases).

Now, we can accept connections (the rest of the code is not specific to Unix local sockets):

{:ok, client} = :socket.accept(socket)
  

And read from the clients, and write to them (here, we just echo the message), like we would do with more common TCP/IP sockets:

    
{:ok, result} = :socket.recv(socket, 0)
msg = String.trim(result)
Logger.info("Received \"#{msg}\"")

:ok = :socket.send(socket, msg <> "\r\n")

  

A complete echo server using these techniques is ipc-serve.exs. Just run it:

% elixir server.exs
Listening on /home/stephane/.test-ipc.sock
  

Clients can be netcat:

% netcat -U ~/.test-ipc.sock  

allo
allo


Tu es là?
Tu es là?
  

Or socat:

% echo foobar | socat - UNIX-CONNECT:/home/stephane/.test-ipc.sock
foobar
  

Or of course a client you write yourself.


L'article seul

RFC 9299: An Architectural Introduction to the Locator/ID Separation Protocol (LISP)

Date de publication du RFC : Octobre 2022
Auteur(s) du RFC : A. Cabellos (UPC-BarcelonaTech), D. Saucez (INRIA)
Pour information
Réalisé dans le cadre du groupe de travail IETF lisp
Première rédaction de cet article le 3 novembre 2022


Le protocole réseau LISP (Locator/ID Separation Protocol, rien à voir avec le langage de programmation du même nom) est normalisé dans le RFC 6830 et plusieurs autres qui l'ont suivi. Ce RFC 6830 est un peu long à lire et ce nouveau RFC propose donc une vision de plus haut niveau, se focalisant sur l'architecture de LISP. Cela peut donc être un bon point de départ vers les RFC LISP.

L'idée de base de LISP est de séparer l'identificateur du localisateur, comme recommandé par le RFC 4984. Un identificateur désigne une machine, un localisateur sa position dans l'Internet. Aujourd'hui, les adresses IP servent pour les deux, ne satisfaisant parfaitement aucun des deux buts : les identificateurs devraient être stables (une machine qui change de réseau ne devrait pas en changer), les localisateurs devraient être efficaces et donc être liés à la topologie, et agrégeables.

LISP a donc deux classes : les identificateurs, ou EID (End-host IDentifier) et les localisateurs, ou RLOC (Routing LOCators). Les deux ont la syntaxe des adresses IP (mais pas leur sémantique). Un système de correspondance permet de passer de l'un à l'autre (par exemple, je connais l'EID de mon correspondant, je cherche le RLOC pour lui envoyer un paquet). LISP est plutôt prévu pour être mis en œuvre dans les routeurs, séparant un cœur de l'Internet qui n'utilise que les RLOC, d'une périphérie qui utiliserait les EID (avec, entre les deux, les routeurs LISP qui feraient la liaison).

En résumé (accrochez-vous, c'est un peu compliqué) :

  • LISP peut être vu comme un réseau virtuel (overlay) au-dessus de l'Internet existant (underlay),
  • Les RLOC n'ont de sens que dans le réseau sous-jacent, l'underlay,
  • Les EID n'ont de sens que dans le réseau virtuel overlay,
  • Entre les deux, le système de correspondance,
  • Dans le réseau sous-jacent, les RLOC servent de localisateur et d'identificateur,
  • Dans un site à la périphérie, les EID servent d'identificateur et de localisateur pour les autres machines du site.

C'est ce côté « solution dans les routeurs » et donc le fait que les machines terminales ne savent même pas qu'elles font du LISP, qui distingue LISP des autres solutions fondées sur la séparation de l'identificateur et du localisateur, comme ILNP (RFC 6740).

Au passage, pourquoi avoir développé LISP ? Quel était le problème à résoudre ? Outre la beauté conceptuelle de la chose (il n'est pas esthétique de mêler les fonctions d'identificateur et de localisateur), le principal problème à traiter était celui du passage à l'échelle du système de routage de l'Internet, décrit dans le RFC 4984. En gros, le nombre de routes distinctes augmente trop vite et menace la stabilité des routeurs de la DFZ. Le but était donc, par une nouvelle architecture, de rendre inutile certains choix qui augmentent la taille de la table de routage (comme la désagrégation des préfixes IP, afin de faire de l'ingénierie de trafic). Le RFC 7215 décrit comment LISP aide dans ce cas.

La section 7 du RFC décrit les différents scénarios d'usage de LISP :

  • Ingénierie de trafic : aujourd'hui, dans l'Internet classique BGP, quand on veut orienter le trafic entrant, le faire passer par un chemin donné, on utilise souvent la désagrégation des préfixes. Comme indiqué plus haut, cela aggrave la pression sur la table de routage globale. L'indirection que permet LISP dispense de cette solution : on peut publier dans le système de correspondance les RLOC qu'on veut.
  • Transition vers IPv6 : les EID et les RLOC ont la forme syntaxique d'une adresse IP, v4 ou v6, et il n'y a pas d'obligation qu'EID et RLOC aient la même version. On peut avoir des EID IPv6 et des RLOC IPv4, et cela fournit un mécanisme de tunnel permettant de connecter deux sites LISP IPv6 au-dessus de réseaux qui seraient purement IPv4. L'avantage par rapport aux techniques de transition actuelles est l'intégration dans une solution plus générale et plus « propre ».
  • LISP permet également de faire des VPN, ou de gérer la mobilité de réseaux entiers (un réseau qui se déplace, et donc change de RLOC, c'est juste la correspondance dans le sous-système de contrôle qu'il faut changer, et tout les partenaires routeront vers les nouveaux RLOC).

La section 3 du RFC décrit en détail l'architecture de LISP (après, vous serez mûr·e·s pour lire les RFC LISP eux-mêmes, en commençant par le RFC 6830). Elle repose sur quatre principes :

  • La séparation entre l'identificateur (le EID) et le localisateur (le RLOC),
  • Deux sous-systèmes différents, le contrôle et les données, utilisant des protocoles différents, et pouvant évoluer séparement (enfin, dans une certaine mesure),
  • Une architecture overlay : LISP est déployé sur un réseau virtuel au-dessus de l'Internet existant, ce qui évite les approches « table rase », qui ont une probabilité de déploiement à peu près nulle,
  • Un protocole déployable de manière incrémentale, pas besoin d'attendre que tout le monde s'y mette, il y a des avantages à déployer LISP même pour les premiers à l'adopter (ce problème de déploiement est une des plaies de l'Internet actuel, comme on le voit avec IPv6).

La séparation entre identificateur et localisateur n'est pas faite au niveau de la machine individuelle, comme avec ILNP, mais à la frontière entre la périphérie de l'Internet (the edge) et son cœur (the core, en gros, la DFZ et quelques routeurs en plus). La périphérie travaille avec des EID (elle ne sait même pas que LISP est utilisé), le cœur avec des RLOC. Contrairement à ILNP, il n'y a donc pas une stricte séparation entre identificateurs et localisateurs : ils ont la même syntaxe (qui est celle d'une adresse IP, v4 ou v6) et, à part les routeurs d'entrée et de sortie des tunnels LISP, personne ne sait s'il utilise un EID ou un RLOC : les machines terminales manipulent des EID, les routeurs du cœur des RLOC, tout en croyant que ce sont des adresses IP ordinaires. Seuls les routeurs à la frontière entre les deux mondes connaissent LISP (et auront donc besoin d'un logiciel adapté).

Un Internet LISP est donc une série de « sites LISP » (des réseaux de périphérie accessibles par LISP) connectés par des tunnels entre eux, au-dessus du cœur actuel. Le routeur d'entrée du tunnel se nomme ITR (pour Ingress Tunnel Router) et celui de sortie ETR (pour Egress Tunnel Router). Le terme de xTR (pour « ITR ou bien ETR ») est parfois utilisé pour désigner un routeur LISP, qu'il soit d'entrée ou de sortie lisp-arch

Le sous-système des données (data plane) se charge d'encapsuler et de décapsuler les paquets, puis de les transmettre au bon endroit. (Sa principale qualité est donc la rapidité : il ne faut pas faire attendre les paquets.) Les ITR encapsulent un paquet IP qui vient d'un site LISP (dans un paquet UDP à destination du port 4341), puis l'envoient vers l'ETR. À l'autre bout du tunnel, les ETR décapsulent le paquet. Dans le tunnel, les paquets ont donc un en-tête intérieur (un en-tête IP normal, contenant les EID source et destination), qui a été placé par la machine d'origine, et un en-tête extérieur (contenant le RLOC source, celui de l'ITR, et le RLOC de destination, celui de l'ETR puis, après l'en-tête UDP, l'en-tête spécifique de LISP). Rappelez-vous que les routeurs du cœur ne connaissent pas LISP, ils font suivre ce qui leur semble un paquet IP ordinaire. Les routeurs LISP utilisent des tables de correspondance entre EID et RLOC pour savoir à quel ETR envoyer un paquet.

Ces tables ont été apprises du sous-système de contrôle (control plane, qui contient la fonction de correspondance - mapping), le routeur ayant un cache des correspondances les plus récentes. Cette fonction de correspondance, un des points les plus délicats de LISP (comme de tout système de séparation de l'identificateur et du localisateur) est décrite dans le RFC 6833. Son rôle peut être comparé à celui du DNS et de BGP dans l'Internet classique.

Une correspondance est une relation entre un préfixe d'identificateurs (rappelez-vous que les EID sont, syntaxiquement, des adresses IP ; on peut donc utiliser des préfixes CIDR) et un ensemble de localisateurs, les RLOC des différents routeurs possibles pour joindre le préfixe convoité.

Le RFC 6833 normalise une interface avec ce système de correspondance. Il y a deux sortes d'entités, le Map Server, qui connait les correspondances pour certains préfixes (car les ETR lui ont raconté les préfixes qu'ils servent), et le Map Resolver, qui fait les requêtes (il est typiquement dans l'ITR, ou proche). Quatre messages sont possibles (les messages de contrôle LISP sont encpasulés en UDP, et vers le port 4342) :

  • Map-Register : un ETR informe son Map Server des préfixes EID qu'il sait joindre,
  • Map-Notify : la réponse de l'ETR au message précédent,
  • Map-Request : un ITR (ou bien un outil de débogage comme lig, cf. RFC 6835) cherche les RLOC correspondant à un EID,
  • Map-Reply : un Map Server ou un ETR lui répond.

Un point important de LISP est qu'il peut y avoir plusieurs mécanismes de correspondance EID->RLOC, du moment qu'ils suivent les messages standard du RFC 6833. On pourra donc, dans le cadre de l'expérience LISP, changer de mécanisme pour voir, pour tester des compromis différents. Notre RFC rappele l'existence du système ALT (RFC 6836, fondé, comme BGP sur un graphe. Mais aussi celle d'un mécanisme utilisant une base « plate » (NERD, RFC 6837), un mécanisme arborescent nommé DDT (RFC 8111), des DHT, etc. On pourrait même, dans des déploiements privés et locaux, avoir une base centralisée avec un seul serveur.

ALT, normalisé dans le RFC 6836, est le système de correspondance « historique » de LISP, et il est souvent présenté comme le seul dans les vieux documents. Il repose sur BGP, protocole bien maitrisé par les administrateurs de routeurs, ceux qui auront à déployer LISP. L'idée de base est de connecter les serveurs ALT par BGP sur un réseau virtuel au-dessus de l'Internet.

DDT, dans le RFC 8111, lui, ressemble beaucoup plus au DNS, par sa structuration arborescente des données, et sa racine.

Évidemment, tout l'Internet ne va pas migrer vers LISP instantanément. C'est pour cela que notre RFC mentionne les problèmes de communication avec le reste du monde. Les EID ne sont typiquement pas annoncés dans la table de routage globale de l'Internet. Alors, comment un site pourra-t-il communiquer avec un site LISP ? Le mécanisme décrit dans le RFC 6832 utilise deux nouvelles sortes de routeurs : les PITR (Proxy Ingress Tunnel Router) et les PETR (Proxy Egress Tunnel Router). Le PITR annonce les EID en BGP vers l'Internet, en les agrégeant le plus possible (l'un des buts de LISP étant justement d'éviter de charger la table de routage globale). Il recevra donc les paquets envoyés par les sites Internet classiques et les fera suivre par les procédures LISP normales. A priori, c'est tout : le site LISP peut toujours envoyer des paquets vers l'Internet classiques en ayant mis un EID en adresse IP source. Mais cela peut échouer pour diverse raisons (uRPF, par exemple) donc on ajoute le PETR : il recevra le paquet du site LISP et le transmettra.

Voici pour les principes de LISP. Mais, si vous travaillez au quotidien comme administrateur d'un réseau, vous avez sans doute à ce stade plein de questions concrètes et opérationnelles. C'est le moment de lire la section 4 de ce RFC. Par exemple, la gestion des caches : un routeur LISP ne peut pas faire appel au système de correspondance pour chaque paquet qu'il a à transmettre. Le sous-système des données tuerait complètement le sous-système de contrôle, si un routeur s'avisait de procéder ainsi. Il faut donc un cache, qui va stocker les réponses aux questions récentes. Qui dit cache dit problèmes de cohérence des données, puisque l'information a pu changer entre la requête, et l'utilisation d'une réponse mise en cache. Pour gérer cette cohérence, LISP dispose de divers mécanismes, notamment un TTL (Time To Live) : l'ETR le définit, indiquant combien de temps les données peuvent être utilisées (c'est typiquement 24 h, aujourd'hui).

Autre problème pratique cruciale, la joignabilité des RLOC. C'est bien joli de savoir que telle machine a tel RLOC mais est-ce vrai ? Peut-on réellement lui parler ou bien tous les paquets vont-ils finir dans un trou noir ? Un premier mécanisme pour transporter l'information de joignabilité est les LSB (Locator Status Bits). Transportés dans les paquets LISP, ces bits indiquent si un RLOC donné est joignable par l'ETR qui a envoyé le paquet. Évidemment, eux aussi peuvent être faux, donc, s'il existe une communication bi-directionnelle, il est préférable d'utiliser le mécanisme des numniques. Quand un ITR écrit à un ETR, il met un numnique dans le paquet, que l'ETR renverra dans son prochain paquet. Cette fois, plus de doute, l'ETR est bien joignable. Si l'ITR est impatient et veut une réponse tout de suite, il peut tester activement la joignabilité, en envoyant des Map-Request.

LISP est souvent présenté avec un modèle simplifié où chaque site est servi par un seul ETR, qui connait les EID du site et les annonce au Map Server. Mais, dans la réalité, les sites sérieux ont plusieurs ETR, pour des raisons de résilience et de répartition de charge. Cela soulève le problème de leur synchronisation : ces ETR doivent avoir des configurations compatibles, pour annoncer les mêmes RLOC pour leurs EID. Pour l'instant, il n'existe pas de protocole pour cela, on compte sur une synchronisation manuelle par l'administrateur réseaux.

Enfin, comme LISP repose sur des tunnels, il fait face à la malédiction habituelle des tunnels, les problèmes de MTU. Du moment qu'on encapsule, on diminue la MTU (les octets de l'en-tête prennent de la place) et on peut donc avoir du mal à parler avec les sites qui ont une MTU plus grande, compte-tenu de la prévalence d'erreurs grossières de configuration, comme le filtrage d'ICMP. La section 4.4 de notre RFC décrit le traitement normal de la MTU dans LISP et ajoute que des mécanismes comme celui du RFC 4821 seront peut-être nécessaires.

Dans l'Internet d'aujourd'hui, une préoccupation essentielle est bien sûr la sécurité : d'innombrables menaces pèsent sur les réseaux (section 8 du RFC). Quelles sont les problèmes spécifiques de LISP en ce domaine ? Par exemple, certains systèmes de correspondance, comme DDT, sont de type pull : on n'a pas l'information à l'avance, on va la chercher quand on en a besoin. Cela veut dire qu'un paquet de données (sous-système des données) peut indirectement déclencher un événement dans le sous-système de contrôle (par la recherche d'une correspondance EID->RLOC afin de savoir où envoyer le paquet). Cela peut affecter la sécurité.

D'autant plus que le sous-système de contrôle sera typiquement mis en œuvre dans le processeur généraliste des routeurs, beaucoup moins rapide que les circuits électroniques spécialisés qui servent à la transmission des données. Un attaquant qui enverrait des tas de paquets vers des EID différents pourrait, à un coût très faible pour lui, déclencher plein de demandes à DDT, ralentissant ainsi sérieusement les routeurs LISP. Une mise en œuvre naïve de LISP où toute requête pour un EID absent du cache déclencherait systématiquement une MAP-Request serait très vulnérable. Une limitation du trafic est donc nécessaire.

En parlant du système de correspondance, il représente évidemment un talon d'Achille de LISP. Si son intégrité est compromise, si des fausses informations s'y retrouvent, les routeurs seront trahis et enverront les paquets au mauvais endroit. Et si le système de correspondance est lent ou en panne, par exemple suite à une attaque par déni de service, le routage ne se fera plus du tout (à part pour les EID encore dans les caches des routeurs). On peut donc comparer ce système de correspondance au DNS dans l'Internet classique, par son côté crucial pour la sécurité.

Il faut donc des « bons » Map Server, qui suivent bien le RFC 6833 (notamment sa section 6) et, peut-être dans le futur, des Map Servers qui gèrent l'extension de sécurité LISP-Sec (si son RFC est publié un jour).

Dernier point de sécurité, le fait que LISP puisse faire du routage asymétrique (le chemin d'Alice à Bob n'est pas le même que celui de Bob à Alice). Rien d'extraordinaire à cela, c'est pareil pour lee routage Internet classique, mais il faut toujours se rappeler que cela a des conséquences de sécurité : par exemple, un pare-feu ne verra, dans certains cas, qu'une partie du trafic.

On trouvera plus de détails sur les attaques qui peuvent frapper LISP dans le RFC 7835.

Pour ceux qui sont curieux d'histoire des technologies, l'annexe A du RFC contient un résumé de LISP. Tout avait commencé à Amsterdam en octobre 2006, à l'atelier qui avait donné naissance au RFC 4984. Un groupe de participants s'était alors formé, avait échangé, et le premier Internet-Draft sur LISP avait été publié en janvier 2007. En même temps, et dans l'esprit traditionnel de l'Internet (running code), la programmation avait commencé et les premiers routeurs ont commencé à gérer des paquets LISP en juin 2007.

Le groupe de travail IETF officiel a été ensuite créé, en mars 2009. Les premiers RFC sont enfin sortis en 2013.

LISP n'a pas toujours été comme aujourd'hui ; le protocole initial était plutôt une famille de protocoles, désignés par des numéros, chacun avec des variantes sur le concept de base. Cela permettait de satisfaire tous les goûts mais cela compliquait beaucoup le protocole. On avait LISP 1, où les EID étaient routables dans l'Internet normal (ce qui n'est plus le cas), LISP 1.5 où ce routage se faisait dans un réseau séparé, LISP 2 où les EID n'étaient plus routables, et où la correspondance EID->RLOC se faisait avec le DNS, et enfin LISP 3 où le système de correspondance était nouveau (il était prévu d'utiliser une DHT...). Le LISP final est proche de LISP 3.


Téléchargez le RFC 9299


L'article seul

Il y a des cas où la chaine de blocs n'est pas utile

Première rédaction de cet article le 21 octobre 2022


La chaine de blocs, malgré quelques soubresauts et critiques, reste aujourd'hui un puissant argument marketing. On voit par exemple une université se vanter d'attester ses diplômes sur cette chaine, et son service de la communication pense apparemment que cela va jouer en sa faveur. Il est vrai que la chaine de blocs résout élégamment des problèmes auparavant considérés comme difficiles, voire impossibles, par exemple le triangle de Zooko. Mais, comme tous les outils, la chaine de blocs ne résout pas tous les problèmes. Voyons un cas où elle n'apporte rien, qui est justement le cas d'usage de l'université citée plus haut.

La chaine de blocs n'est pas simplement une liste chainée de données. Si c'était le cas, elle n'aurait rien d'intéressant, cette structure de données étant une des plus anciennes qui soit. De même, le fait que les transactions contenues dans le bloc soient signées est assez banal, les signatures numériques sont un concept ancien et répandu bien avant l'invention de la chaine de blocs. L'intérêt de la chaine de blocs est ailleurs : dans le fait qu'elle est pair-à-pair, que n'importe qui puisse y écrire, et qu'un consensus émerge entre des entités qui ne se font pas mutuellement confiance. C'est ainsi que fonctionne son utilisation la plus emblématique, les cryptomonnaies. Les gens qui acquièrent et dépensent les jetons de la cryptomonnaie utilisée ne se font pas confiance et ne se connaissent même pas. Il faut pourtant arriver à un consensus sur le fait qu'Alice ait trois jetons et, qu'après en avoir donné un à Bob, elle n'en a plus que deux (alors qu'Alice préfererait qu'on croit qu'elle en a toujours trois). C'est cela que permet la chaine de blocs et, dans ce cas d'usage, elle est irremplaçable. (Le tout est bien expliqué dans l'article de Satoshi Nakamoto qui décrit le Bitcoin, et qui a intoduit le concept de chaine de blocs. Ironiquement, le terme de blockchain n'apparait pas dans cet article.)

Le but affiché des cryptomonnaies est justement de réaliser une monnaie qui ne dépende pas d'une autorité extérieure, par exemple une banque centrale. Mais si on a une telle autorité et qu'on lui fait confiance, la chaine de blocs devient inutile. Elle fonctionne toujours mais n'est pas l'utilisation la plus intelligente des ressources informatiques.

Or, c'est justement le cas de l'université citée plus haut. Pour valider des diplômes, on ne veut pas du pair-à-pair, bien au contraire. Il y a une autorité, l'université, et c'est elle, et elle seule, qui peut dire si j'ai une maitrise de physique ou pas (mon diplôme universitaire le plus élevé). Si on met les diplômes sur une chaine de blocs, on ne souhaite certainement pas que tout le monde puisse y écrire. Le cas est donc très différent de celui des cryptomonnaies, ou d'autres utilisations de la chaine de blocs comme la réservation de noms. Notons en outre qu'aucun détail n'est donné sur la chaine utilisée par l'université : laquelle est-ce, qui la contrôle, son logiciel est-il publié, etc. En l'absence de tous ces éléments, la chaine de blocs n'apporte aucune confiance supplémentaire. L'université aurait tout aussi bien publier les diplômes sur son site Web… (Avec quelques techniques de sécurité comme HTTPS.) Et si on veut un système commun à toutes les universités, il existe déjà.

Les défenseurs de ces utilisations inutiles de la chaine de blocs citent parfois l'argument de la signature, qui permet d'authentifier le diplôme, y compris si l'information circule et n'est pas récupérée sur le site d'origine. C'est vrai, les signatures numériques sont une très bonne idée, mais elles sont bien antérieures aux chaines de blocs et peuvent être utilisées dans ce cas (par exemple en publiant des documents signés sur le site Web). Là encore, la chaine de blocs n'apporte rien. Notez que le responsable du projet est parfaitement conscient de cette inutilité puisque, dans les commentaires à un article de NextInpact, il dit ouvertement « j'assume que le mot blockchain a un peu été un prétexte ».

Une faiblesse courante avec les chaines de blocs est que peu de gens vérifient directement sur la chaine, pourtant la seule source fiable. Ils passent en général par un système centralisé. L'entreprise privée qui a été payée par l'université le dit d'ailleurs dans les commentaires à l'article de Next Inpact déjà cité : « Techniquement, tout est fait dans BCdiploma pour que la lecture des attestations soit la plus simple possible en masquant la complexité de la blockchain. Par exemple, les certificats sont ici lus depuis le site de l’université, augmentant ainsi la confiance. » (un exemple de ce que ça donnerait). Ça annule une bonne partie de l'intérêt du projet.

Pour les mêmes raisons, tous les projets de « chaines de blocs privées » ou de « chaines à permission » sont des non-sens, en raison de leur inutilité. (À l'exception peut-être de chaines pas publiques mais pas complètement privées, entre un petit nombre d'acteurs qui ne se font qu'une confiance limitée.) Évidemment, cette inutilité n'empêche pas les projets (par exemple au niveau européen), car il y a beaucoup de consultants et d'ESN à nourrir.

Mais attention, dit la lectrice attentive de cet article : l'université peut publier des diplômes signés sur son site Web, d'accord, mais elle peut aussi arrêter de les publier. Si on fait confiance à l'université pour certifier les diplômes, mais qu'on craint qu'elle n'essaie de réécrire le passé en prétendant qu'un diplôme n'a jamais existé, la publication sur le site Web n'aide pas. Bonne remarque, et il faut donc aller plus loin que la simple publication de documents signés sur un site Web. Mais on n'a pas besoin de chaine de blocs, il suffit d'utiliser des journaux publics à ajout seul (append-only logs).

Le principe de ces journaux est de publier l'information sous une forme qui rend toute altération ultérieure détectable. Il existe plusieurs solutions pour cela, mais la plus simple conceptuellement (mais pas la plus rapide) est de numéroter chaque document publié. La suppression d'un document peut ainsi être détectée. Si on a le document 67 et qu'on ne trouve pas le 66, le problème est visible. (Ce système de numérotation des documents pour assurer l'intégrité est un très vieux système, antérieur à l'informatique, avec les journaux papier utilisés par exemple dans les commissariats. Comme le dit Wikipédia, « Il est strictement interdit de modifier ou même de raturer une inscription en main courante sous peine de la rendre caduque, c'est pourquoi les pages d'une main courante papier sont toujours numérotées. ») En dehors du monde papier, un tel système est simple à faire : l'autorité numérote les documents, les signe et les publie. Les données étant publiques, n'importe qui peut facilement vérifier leur intégrité. Un tel système est par exempe décrit dans l'article « How to time-stamp a digital document » (à télécharger ici). Un des systèmes les plus anciens à être effectivement déployé est Stamper (cf. son historique), qui publiait ses signatures (faites avec PGP)… sur Usenet.

Depuis, bien d'autres systèmes de journaux à ajout seul sont apparus et sont utilisés. L'un des plus connus est le Certificate Transparency (normalisé dans le RFC 9162). Pas du tout besoin d'une chaine de blocs pour cette tâche cruciale, puisqu'il n'y a qu'un petit nombre d'émetteurs faisant autorité (les AC).

Au passage, j'ai dit qu'un tel système permettait de détecter les modifications. Or il y a des modifications légitimes, par exemple le retrait d'un diplôme obtenu à tort. Il faut donc prévoir la possibiité qu'un document annule un précédent (mais on ne supprime pas le précédent, on le remplace). La vérification publique est contradictoire avec la possibilité d'oubli, ce qui peut être une bonne ou une mauvaise chose.


L'article seul

Des leçons à tirer du problème du .coin

Première rédaction de cet article le 20 octobre 2022


Le 18 octobre 2022, la société Unstoppable Domains a annoncé qu'elle arrêtait de vendre des noms sous .coin. Il y a des leçons intéressantes à en tirer.

Ces noms ont la syntaxe de noms de domaine mais ne « fonctionnent » pas, au sens où un nom de domaine habituel fonctionne, via une résolution par le DNS. Ils sont enregistrés, oui, dans une chaine de blocs, mais ne fonctionnent pas avec vos logiciels classiques. En pratique, ils sont très peu utilisés, ceux qui les achètent sont plutôt dans une démarche d'investissement, espérant qu'ils prendront de la valeur plus tard, plutôt que dans une démarche de présence en ligne, comme lorsqu'on achète un nom de domaine plus classique pour recevoir du courrier électronique ou afficher un site Web.

Plusieurs services analogues existent, certains commerciaux (on peut vendre des noms, des identificateurs), d'autres pas. C'est aussi un monde où on rencontre de tout, du marketing boursouflé (Web3 !), à certains vendeurs qui induisent en erreur leurs clients, par exemple en leur faisant croire que ces noms auront le même usage qu'un nom classique, utilisable via le DNS. Et il y a aussi de purs escrocs. L'intérêt, en théorie, d'enregistrer des noms dans une chaine de blocs, plutôt que via un registre traditionnel, est que la chaine fonctionne automatiquement, sans intervention humaine une fois lancée, et qu'on peut donc rester titulaire de son nom de domaine, sans risque de le voir saisi ou censuré (d'où le nom de la société Unstoppable Domains). L'idée est très ancienne (elle avait commencé avec Namecoin en 2010) mais a pris de l'ampleur ces dernières années, avec l'apparition d'intermédiaires comme Unstoppable Domains, ENS, Emercoin, etc. La vogue récente des NFT a mené certains à renommer leurs produits « NFT » mais il n'y a pas de changement de fond.

Un point important de toute cette offre est qu'il n'y a pas de coordination. Tout le monde (et son chat) peut créer une chaine de blocs ou, si on est moins ambitieux, un service de création de noms sur une chaine de blocs existante (la façon de réaliser un tel service avait été détaillée lors de la JCSA 2016). L'Internet est « sans permission » ce qui veut dire, et heureusement, qu'une innovation peut être créée et déployée sur l'Internet, sans l'autorisation de personne. Cela a permis Bitcoin (qui a créé le concept de chaine de blocs), BitTorrent mais aussi le Web (si Tim Berners-Lee avait dû patienter jusqu'à l'autorisation d'un comité, on attendrait toujours le Web). La contrepartie de cette liberté est qu'il y a aussi de mauvaises idées et des concurrences dommageables. Comme chacun (et son hamster) peut lancer un service de création et de vente de noms sur une chaine de blocs, si ces noms ont une syntaxe compatible, il y a des risques de collision. Une collision, c'est quand deux noms identiques sont enregistrés via des services différents. C'est inévitable si deux services vendent des noms avec le même suffixe.

Et c'est justement ce qui s'est produit ici : Unstoppable Domains vendait du .coin mais Emercoin le faisait également. Les collisions étaient donc inévitables. Finalement, Unstoppable Domains a décidé d'arrêter, notant qu'Emercoin était présent avant (mais qu'ils ne le savaient pas). Notons l'ironie du nom Unstoppable Domains puisque cette entreprise peut supprimer un nom à sa guise…

Ces problèmes de collision sont inévitables dès que plusieurs organisations créent des noms sans aucune coordination. C'est une des raisons pour lesquelles les racines DNS alternatives n'ont jamais décollé. Leurs promoteurs évacuent souvent le problème des collisions avec de vagues promesses « on s'arrangera ». Ici, un des deux acteurs impliqués dans la collision a décidé d'arrêter mais il n'y a aucune garantie que cela se passera toujours bien. C'est pour cela que le RFC 2826 insiste sur l'importance d'une coordination formelle. Dit autrement, il ne faut qu'un seul registre pour .coin (ou .nimporte-quoi).

J'ai dit plus haut qu'Unstoppable Domains avait supprimé les noms en .coin. En fait, c'est plus compliqué que cela. Les noms sont toujours dans la chaine de blocs (dont l'un des buts est justement d'empêcher l'effacement du passé) et Unstoppable Domains peut donc expliquer qu'en fait, ils n'ont pas supprimé les noms. Mais, comme indiqué précédemment, presque aucune application ne va regarder directement dans la chaine de blocs. Elles passent quasiment toutes par des passerelles diverses, utilisant des protocoles normalisés comme HTTP ou DNS. Ce qu'Unstoppable Domains a coupé, comme ils l'indiquent, ce sont ces passerelles. C'est en effet une malhonnêteté intellectuelle fréquente chez certains services se présentant comme pair-à-pair : le support (ici, la chaine de blocs) est bien pair-à-pair, mais en pratique presque tout le monde y accède via une passerelle qui, elle, est centralisée. Lorsque cette passerelle est fermée, vous perdez tout. (Le problème est loin d'être spécifique à Unstoppable Domains ; regardez comme les ressources IPFS, service censément pair-à-pair sont toujours annoncées sous forme d'un URL passant par une passerelle centralisée. C'est en partie dû au fait que le logiciel est très complexe à compiler et installer.)

Cette dépendance de nombreux services pair-à-pair vis-à-vis de passerelles centralisées, donc vulnérables à la censure ou à des décisions business, est un des gros problèmes, à l'heure actuelle, de beaucoup de solutions pair-à-pair.

Quelques bonnes lectures pour finir :


L'article seul

Valider du XML : exemple EPP

Première rédaction de cet article le 20 octobre 2022
Dernière mise à jour le 21 octobre 2022


Cet article n'aura probablement pas beaucoup de lecteurs car peu de gens utilisent le protocole EPP. Ce dernier sert uniquement à la communication entre registres et bureaux d'enregistrement. Il utilise le format XML, et est décrit via un langage de schéma, ce qui permet sa validation par un programme. Comme ce n'est pas tout à fait évident, je montre ici comment on peut faire cette validation.

EPP est normalisé dans le RFC 5730. Mais attention, cela ne normalise que le cœur du protocole. EPP est un protocole d'avitaillement d'objets et il peut manipuler différents types d'objets, par exemple des noms de domaine. Il faut donc ajouter un RFC par type d'objet (pour les noms de domaine, c'est le RFC 5731) et à chaque fois un nouvel espace de noms. Et EPP a diverses extensions, avec à chaque fois un espace de noms. Tout cela est formellement décrit en XML Schema. Avantage : on peut valider un document EPP automatiquement et s'assurer qu'il est conforme à ce qu'on attend, avant de le traiter.

On va utiliser ici xmllint, qu'on trouve dans tous les bons systèmes d'exploitation. xmllint exige qu'on lui passe un fichier unique pour le schéma, donc je vous ai fait un joli fichier XML Schema qui inclut toutes les extensions auxquelles j'ai pensé, epp-wrapper.xsd. Ensuite, on doit récupérer à l'IANA tous les fichiers .xsd concernant les différents schémas qu'on utilise. Cela peut se faire avec le script Python extract-xsd.py et cette boucle shell :

for schema in $(./extract-xsd.py epp-wrapper.xsd); do
    wget https://www.iana.org/assignments/xml-registry/schema/${schema}
done
  

On peut ensuite valider un document EPP. Prenons celui-ci comme exemple :


<?xml version="1.0" encoding="utf-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <create>
      <domain:create
       xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>example.com</domain:name>
        <domain:authInfo>
          <domain:pw>2fooBAR</domain:pw>
        </domain:authInfo>
      </domain:create>
    </create>
    <clTRID>ABC-12345</clTRID>
  </command>
</epp>

  

Cela donne :

% xmllint --noout --schema epp-wrapper.xsd test.xml
test.xml validates
  

Parfait. Un programme qui va traiter les données peut, s'il a validé, être tranquille. Il sait par exemple qu'il aura une et une seule commande dans l'élément <epp>.

Notez que c'est en écrivant cet article qu'une faille a été trouvée dans le RFC 9167.

Si maintenant on prend un document EPP invalide (ajout d'un <foobar>) :

% xmllint --noout --schema epp-wrapper.xsd test-invalid.xml
test-invalid.xml:12: element foobar: Schemas validity error : Element '{urn:ietf:params:xml:ns:epp-1.0}foobar': This element is not expected.
test-invalid.xml fails to validate
  

Parfait encore, le document invalide est rejeté.

Si on utilise une extension à EPP comme celle pour DNSSEC du RFC 5910 :


<?xml version="1.0" encoding="utf-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <update>
      <domain:update
       xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>example.com</domain:name>
      </domain:update>
    </update>
    <extension>
      <secDNS:create xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
        <secDNS:dsData>
          <secDNS:keyTag>12345</secDNS:keyTag>
          <secDNS:alg>3</secDNS:alg>
          <secDNS:digestType>1</secDNS:digestType>
          <secDNS:digest>49FD46E6C4B45C55D4AC</secDNS:digest>
          <!-- <secDNS:keyData>, la clé elle-même, est *facultatif* -->
        </secDNS:dsData>
      </secDNS:create>
    </extension>
    <clTRID>ABC-12345</clTRID>
  </command>
</epp>

  

La validation sera possible grâce à tous les schémas chargés :

% xmllint --noout --schema epp-wrapper.xsd test-dnssec.xml
test-dnssec.xml validates
  

L'article seul

Version 15 d'Unicode

Première rédaction de cet article le 15 septembre 2022


Le mardi 13 septembre est sortie la version 15 d'Unicode. Une description officielle des principaux changements est disponible mais voici ceux qui m'ont intéressé particulièrement. (Il n'y a pas de changement radical.)

Pour explorer plus facilement la grande base Unicode, j'utilise un programme qui la convertit en SQL et permet ensuite de faire des analyses variées. Faisons quelques requêtes SQL :

ucd=> SELECT count(*) AS Total FROM Characters;
 total  
--------
 149251

Combien de caractères sont arrivés avec la version 15 ?

ucd=> SELECT version,count(version) FROM Characters GROUP BY version ORDER BY version::float;
...
 12.0    |   554
 12.1    |     1
 13.0    |  5930
 14.0    |   838
 15.0    |  4489

4489 nouveaux caractères, c'est pas mal (la version 14 était plus calme). Quels sont ces nouveaux caractères ?

ucd=> SELECT To_U(codepoint) AS Code_point, name FROM Characters WHERE version='15.0' ORDER BY Codepoint;
 code_point |                                    name                                    
-----------+----------------------------------------------------------------------------
...
U+1D2C0    | KAKTOVIK NUMERAL ZERO
...
U+1E4D4    | NAG MUNDARI LETTER ONG
...
U+1F776    | LUNAR ECLIPSE
...
U+1F77C    | MAKEMAKE
U+1F77D    | GONGGONG
...
U+1FACF    | DONKEY

Cette version amène en effet des écritures nouvelles comme le Nag Mundari, ou les chiffres de Kaktovik.

Si vous avez les bonnes polices de caractères, vous allez pouvoir voir quelques exemples (sinon, le lien mène vers Uniview). Voici par exemple la lettre ETT du Nag Mundari 𞓩 et le chiffre de Kaktovik 2 𝋂 Il y a également de nouveaux symboles, notamment liés à l'astronomie, comme l'occultation 🝵 ou la petite planète Orcus 🝿. En plus anecdotique, on a le sans-fil 🛜, les maracas 🪇 ou l'élan 🫎. Ce dernier a d'ailleurs eu droit au point de code, U+1FACE, une utilisation amusante de l'hexadécimal.

Tiens, d'ailleurs, combien de caractères Unicode sont des symboles (il n'y a pas que les emojis parmi eux, mais Unicode n'a pas de catégorie « emoji ») :

 ucd=> SELECT count(*) FROM Characters  WHERE category IN ('Sm', 'Sc', 'Sk', 'So');
 count 
-------
  7770

Ou, en plus détaillé, et avec les noms longs des catégories :

ucd=> SELECT description,count(category) FROM Characters,Categories WHERE Categories.name = Characters.category AND category IN ('Sm', 'Sc', 'Sk', 'So') GROUP BY category, description;
   description   | count 
-----------------+-------
 Modifier_Symbol |   125
 Other_Symbol    |  6634
 Math_Symbol     |   948
 Currency_Symbol |    63

L'article seul

Articles des différentes années : 2023  2022  2021  2020  2019  2018  2017  Précédentes années

Syndication : Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu.

Un article de ce blog au hasard.