RFC 8109: Initializing a DNS Resolver with Priming Queries
Stephane Bortzmeyer <[email protected]> Thu, 16 Mar 2017 09:35:26 +0100
| Newsgroups | gmane.network.dns.french |
|---|---|
| Message-ID | <[email protected]> |
Après dix ans de discussions, l'IETF a enfin réussi à publier un RFC
décrivant ce que font tous les résolveurs DNS au démarrage...
RFC 8109 : Initializing a DNS Resolver with Priming Queries
http://www.bortzmeyer.org/8109.html
----------------------------
Auteur(s) du RFC: P. Koch
(DENIC), M. Larson, P. Hoffman
(ICANN)
----------------------------
Un résolveur DNS ne connait au début, rien du contenu du DNS. Rien ?
Pas tout à fait, il connait une liste des serveurs de noms faisant
autorité pour la racine, car c'est par eux qu'il va commencer le
processus de résolution de noms. Cette liste est typiquement en dur
dans le code du serveur, ou bien dans un de ses fichiers de
configuration. Mais peu d'administrateurs système la maintiennent à
jour. Il est donc prudent, au démarrage du résolveur, de chercher une
liste vraiment à jour, et c'est le "priming" (initialisation ?),
opération que décrit ce RFC.
Le problème de départ d'un résolveur est un problème d'œuf et de poule.
Le résolveur doit interroger le DNS pour avoir des informations mais
comment trouve-t-il les serveurs DNS à interroger ? La solution est de
traiter la racine du DNS de manière spéciale : la liste de ses serveurs
est connue du résolveur au démarrage. Elle peut être dans le code du
serveur lui-même, ici un Unbound qui contient les adresses IP des
serveurs de la racine (je ne montre que les trois premiers,
A.root-servers.net, B.root-servers.net et C.root-servers.net) :
% strings /usr/sbin/unbound | grep -i 2001:
2001:503:ba3e::2:30
2001:500:84::b
2001:500:2::c
...
Ou bien elle est dans un fichier de configuration (ici, sur un
Unbound) :
server:
directory: "/etc/unbound"
root-hints: "root-hints"
Ce fichier peut être téléchargé via
l'IANA <https://www.internic.net/domain/named.root>, il peut être spécifique au logiciel résolveur, ou bien fourni
par le système d'exploitation (cas du
paquetage dns-root-data chez
Debian). Il contient la liste des serveurs
de la racine et leurs adresses :
. 3600000 NS A.ROOT-SERVERS.NET.
. 3600000 NS B.ROOT-SERVERS.NET.
...
A.ROOT-SERVERS.NET. 3600000 A 198.41.0.4
A.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:ba3e::2:30
B.ROOT-SERVERS.NET. 3600000 A 192.228.79.201
B.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:84::b
...
Cette configuration initiale du résolveur est décrite dans la section
2.3 du RFC 1034, mais ce dernier ne décrit pas réellement le "priming"
(quoi que dise notre nouveau RFC), "priming" que tous les résolveurs
actuels mettent en œuvre. En effet, les configurations locales tendent
à ne plus être à jour au bout d'un moment. (Sauf dans le cas où elles
sont dans un paquetage du système d'exploitation, mis à jour avec ce
dernier, comme dans le bon exemple Debian ci-dessus.)
Les changements des serveurs racines sont rares. Si on regarde sur le
site des opérateurs des serveurs racine <http://root-servers.org/>, on
voit :
* 2016-12-02 Announcement of IPv6 addresses
* 2015-11-05 L-Root IPv6 Renumbering
* 2015-08-31 H-Root to be renumbered
* 2014-03-26 IPv6 service address for c.root-servers.net
(2001:500:2::C)
* 2012-12-14 D-Root IPv4 Address to be Renumbered
* 2011-06-10 IPv6 service address for d.root-servers.net
(2001:500:2D::D)
Bref, peu de changements. Ils sont en général annoncés sur les listes
de diffusion opérationnelles (comme ici
<https://lists.dns-oarc.net/pipermail/dns-operations/2007-October/002083
.html>, là
<https://lists.dns-oarc.net/pipermail/dns-operations/2015-September/0136
35.html> ou encore ici
<https://lists.dns-oarc.net/pipermail/dns-operations/2012-December/00942
9.html>). Mais les fichiers de configuration ayant une fâcheuse
tendance à ne pas être mis à jour et à prendre de l'âge, les anciennes
adresses des serveurs racine continuent à recevoir du trafic des années
après (comme le montre cette étude de J-root
<https://indico.dns-oarc.net/event/24/session/10/contribution/10/materia
l/slides/0.pdf>). Notez que la stabilité de la liste des serveurs
racine n'est pas due qu'au désir de ne pas perturber les
administrateurs système : il y a aussi des raisons politiques (aucun
mécanisme en place pour choisir de nouveaux serveurs, ou pour retirer
les « maillons faibles »). C'est pour cela que la liste des serveurs
(mais pas leurs adresses) n'a pas changé depuis 1997 !
Notons aussi que l'administrateur système d'un résolveur peut changer
la liste des serveurs de noms de la racine pour une autre liste. C'est
ainsi que fonctionnent les racines alternatives comme Yeti
<https://yeti-dns.org/>. Si on veut utiliser cette racine expérimentale
et pas la racine « officielle », on édite la configuration de son
résolveur :
server:
root-hints: "yeti-hints"
Et le fichier, téléchargé chez Yeti <https://yeti-dns.org/rootzone.html>, contient :
. 3600000 IN NS bii.dns-lab.net
bii.dns-lab.net 3600000 IN AAAA 240c:f:1:22::6
. 3600000 IN NS yeti-ns.tisf.net
yeti-ns.tisf.net 3600000 IN AAAA 2001:559:8000::6
. 3600000 IN NS yeti-ns.wide.ad.jp
yeti-ns.wide.ad.jp 3600000 IN AAAA 2001:200:1d9::35
. 3600000 IN NS yeti-ns.as59715.net
...
Le "priming", maintenant. Le principe du "priming" est, au démarrage,
de faire une requête à un des serveurs listés dans la configuration et
de garder sa réponse (certainement plus à jour que la configuration) :
% dig +bufsize=4096 +norecurse +nodnssec @k.root-servers.net NS .
; <<>> DiG 9.10.3-P4-Debian <<>> +norecurse +nodnssec @k.root-servers.net NS .
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42123
;; flags: qr aa; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;. IN NS
;; ANSWER SECTION:
. 518400 IN NS a.root-servers.net.
. 518400 IN NS b.root-servers.net.
. 518400 IN NS c.root-servers.net.
. 518400 IN NS d.root-servers.net.
. 518400 IN NS e.root-servers.net.
. 518400 IN NS f.root-servers.net.
. 518400 IN NS g.root-servers.net.
. 518400 IN NS h.root-servers.net.
. 518400 IN NS i.root-servers.net.
. 518400 IN NS j.root-servers.net.
. 518400 IN NS k.root-servers.net.
. 518400 IN NS l.root-servers.net.
. 518400 IN NS m.root-servers.net.
;; ADDITIONAL SECTION:
a.root-servers.net. 518400 IN A 198.41.0.4
a.root-servers.net. 518400 IN AAAA 2001:503:ba3e::2:30
b.root-servers.net. 518400 IN A 192.228.79.201
b.root-servers.net. 518400 IN AAAA 2001:500:84::b
c.root-servers.net. 518400 IN A 192.33.4.12
c.root-servers.net. 518400 IN AAAA 2001:500:2::c
d.root-servers.net. 518400 IN A 199.7.91.13
d.root-servers.net. 518400 IN AAAA 2001:500:2d::d
e.root-servers.net. 518400 IN A 192.203.230.10
e.root-servers.net. 518400 IN AAAA 2001:500:a8::e
f.root-servers.net. 518400 IN A 192.5.5.241
f.root-servers.net. 518400 IN AAAA 2001:500:2f::f
g.root-servers.net. 518400 IN A 192.112.36.4
g.root-servers.net. 518400 IN AAAA 2001:500:12::d0d
h.root-servers.net. 518400 IN A 198.97.190.53
h.root-servers.net. 518400 IN AAAA 2001:500:1::53
i.root-servers.net. 518400 IN A 192.36.148.17
i.root-servers.net. 518400 IN AAAA 2001:7fe::53
j.root-servers.net. 518400 IN A 192.58.128.30
j.root-servers.net. 518400 IN AAAA 2001:503:c27::2:30
k.root-servers.net. 518400 IN A 193.0.14.129
k.root-servers.net. 518400 IN AAAA 2001:7fd::1
l.root-servers.net. 518400 IN A 199.7.83.42
l.root-servers.net. 518400 IN AAAA 2001:500:9f::42
m.root-servers.net. 518400 IN A 202.12.27.33
m.root-servers.net. 518400 IN AAAA 2001:dc3::35
;; Query time: 3 msec
;; SERVER: 2001:7fd::1#53(2001:7fd::1)
;; WHEN: Fri Mar 03 17:29:05 CET 2017
;; MSG SIZE rcvd: 811
(Les raisons du choix des trois options données à dig sont indiquées
plus loin.)
La section 3 de notre RFC décrit en détail à quoi ressemblent les
requêtes de "priming". Le type de données demandé ("QTYPE") est NS
("Name Servers", type 2) et le nom demandé ("QNAME") est « . » (oui,
juste la racine). D'où le dig NS . ci-dessus. Le bit RD ("Recursion
Desired") est typiquement mis à zéro (d'où le +norecurse dans l'exemple
avec dig). La taille de la réponse dépassant les 512 octets (limite
très ancienne du DNS), il faut utiliser EDNS (cause du +bufsize=4096
dans l'exemple). On peut utiliser le bit DO ("DNSSEC OK") qui indique
qu'on demande les signatures DNSSEC mais ce n'est pas habituel (d'où le
+nodnssec dans l'exemple). En effet, si la racine est signée,
permettant d'authentifier l'ensemble d'enregistrements NS, la zone
root-servers.net, où se trouvent actuellement tous les serveurs de la
racine, ne l'est pas, et les enregistrements A et AAAA ne peuvent donc
pas être validés avec DNSSEC.
Cette requête de "priming" est envoyée lorsque le résolveur démarre, et
aussi lorsque la réponse précédente a expiré (regardez le TTL dans
l'exemple : six jours). Si le premier serveur testé ne répond pas, on
essaie avec un autre. Ainsi, même si le fichier de configuration n'est
pas parfaitement à jour (des vieilles adresses y trainent), le
résolveur finira par avoir la liste correcte.
Et comment choisit-on le premier serveur qu'on interroge ? Notre RFC
recommande un tirage au sort, pour éviter que toutes les requêtes de
"priming" ne se concentrent sur un seul serveur (par exemple le premier
de la liste). Une fois que le résolveur a démarré, il peut aussi se
souvenir du serveur le plus rapide, et n'interroger que celui-ci, ce
qui est fait par la plupart des résolveurs, pour les requêtes
ordinaires (mais n'est pas conseillé pour le "priming").
Et les réponses au "priming" ? Il faut bien noter que, pour le serveur
racine, les requêtes "priming" sont des requêtes comme les autres, et
ne font pas l'objet d'un traitement particulier. Normalement, la
réponse doit avoir le code de retour NOERROR (c'est bien le cas dans
mon exemple). Parmi les "flags", il doit y avoir AA ("Authoritative
Answer"). La section de réponse doit évidemment contenir les NS de la
racine, et la section additionnelle les adresses IP. Le résolveur garde
alors cette réponse dans son cache, comme il le ferait pour n'importe
quelle autre réponse. Notez que là aussi, il ne faut pas de traitement
particulier. Par exmeple, le résolveur ne doit pas compter qu'il y aura
exactement 13 serveurs, même si c'est le cas depuis longtemps (ça peut
changer).
Normalement, le serveur racine envoie la totalité des adresses IP (deux
par serveur, une en IPv4 et une en IPv6). S'il ne le fait pas (par
exemple par manque de place parce qu'on a bêtement oublié EDNS), le
résolveur va devoir envoyer des requêtes A et AAAA explicites pour
obtenir les adresses IP :
% dig @k.root-servers.net A g.root-servers.net
; <<>> DiG 9.10.3-P4-Debian <<>> @k.root-servers.net A g.root-servers.net
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49091
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 26
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;g.root-servers.net. IN A
;; ANSWER SECTION:
g.root-servers.net. 3600000 IN A 192.112.36.4
...
Vous pouvez voir ici les requêtes et réponses de "priming" d'un Unbound
utilisant Yeti <https://yeti-dns.org/>. D'abord, décodées par tcpdump :
20:31:36.226325 IP6 2001:4b98:dc2:43:216:3eff:fea9:41a.7300 > 2a02:cdc5:9715:0:185:5:203:53.53: 50959% [1au] NS? . (28)
20:31:36.264584 IP6 2a02:cdc5:9715:0:185:5:203:53.53 > 2001:4b98:dc2:43:216:3eff:fea9:41a.7300: 50959*- 26/0/7 NS bii.dns-lab.net., NS yeti.bofh.priv.at., NS yeti.ipv6.ernet.in., NS yeti.aquaray.com., NS yeti.mind-dns.nl., NS dahu1.yeti.eu.org., NS dahu2.yeti.eu.org., NS yeti1.ipv6.ernet.in., NS ns-yeti.bondis.org., NS yeti-ns.ix.ru., NS yeti-ns.lab.nic.cl., NS yeti-ns.tisf.net., NS yeti-ns.wide.ad.jp., NS yeti-ns.conit.co., NS yeti-ns.datev.net., NS yeti-ns.switch.ch., NS yeti-ns.as59715.net., NS yeti-ns1.dns-lab.net., NS yeti-ns2.dns-lab.net., NS yeti-ns3.dns-lab.net., NS xn--r2bi1c.xn--h2bv6c0a.xn--h2brj9c., NS yeti-dns01.dnsworkshop.org., NS yeti-dns02.dnsworkshop.org., NS 3f79bb7b435b05321651daefd374cd.yeti-dns.net., NS ca978112ca1bbdcafac231b39a23dc.yeti-dns.net., RRSIG (1225)
Et ici par tshark :
1 0.000000 2001:4b98:dc2:43:216:3eff:fea9:41a → 2a02:cdc5:9715:0:185:5:203:53 DNS 90 Standard query 0xc70f NS <Root> OPT
2 0.038259 2a02:cdc5:9715:0:185:5:203:53 → 2001:4b98:dc2:43:216:3eff:fea9:41a DNS 1287 Standard query response 0xc70f NS <Root> NS bii.dns-lab.net NS yeti.bofh.priv.at NS yeti.ipv6.ernet.in NS yeti.aquaray.com NS yeti.mind-dns.nl NS dahu1.yeti.eu.org NS dahu2.yeti.eu.org NS yeti1.ipv6.ernet.in NS ns-yeti.bondis.org NS yeti-ns.ix.ru NS yeti-ns.lab.nic.cl NS yeti-ns.tisf.net NS yeti-ns.wide.ad.jp NS yeti-ns.conit.co NS yeti-ns.datev.net NS yeti-ns.switch.ch NS yeti-ns.as59715.net NS yeti-ns1.dns-lab.net NS yeti-ns2.dns-lab.net NS yeti-ns3.dns-lab.net NS xn--r2bi1c.xn--h2bv6c0a.xn--h2brj9c NS yeti-dns01.dnsworkshop.org NS yeti-dns02.dnsworkshop.org NS 3f79bb7b435b05321651daefd374cd.yeti-dns.net NS ca978112ca1bbdcafac231b39a23dc.yeti-dns.net RRSIG AAAA 240c:f:1:22::6 AAAA 2a01:4f8:161:6106
:1::10 AAAA 2001:e30:1c1e:1:
Et un décodage plus détaillé de tshark dans ce fichier (en ligne sur http://www.bortzmeyer.org/files/dns-priming-yeti.txt).
Enfin, la section 5 de notre RFC traite des problèmes de sécurité du
"priming". Évidemment, si un attaquant injecte une fausse réponse aux
requêtes de "priming", il pourra détourner toutes les requêtes
ultérieures vers des machines de son choix. À part le RFC 5452, la
seule protection est DNSSEC : si le résolveur valide (et a donc la clé
publique de la racine), il pourra détecter que les réponses sont
mensongères. Cela a l'avantage de protéger également contre d'autres
attaques, ne touchant pas au "priming", comme les attaques sur le
routage.
Notez que DNSSEC est recommandé pour valider les réponses ultérieures
mais, comme on l'a vu, n'est pas important pour valider la réponse de
"priming" elle-même, puisque root-servers.net n'est pas signé. Si un
attaquant détournait, d'une manière ou d'une autre, vers un faux
serveur racine, servant de fausses données, ce ne serait qu'une attaque
par déni de service, puisque le résolveur validant pourrait détecter
que les réponses sont fausses.
Ce RFC a connu une très longue gestation puisque le premier brouillon
date de février 2007 (vous pouvez admirer la chronologie
<https://datatracker.ietf.org/doc/draft-ietf-dnsop-resolver-priming/>).