Le DNS, parent pauvre d'Internet ?


Étude de cas

La récente attaque DDoS dirigée vers Dyn qui a rendu de nombreux services populaires inaccessibles (Twitter, Spotify, GitHub...) pour beaucoup d'utilisateurs nord-américains et européens a encore une fois mis le DNS sur le devant de la scène. Ce dernier est devenu assez rapidement un service central de l'Internet pour l'internaute moyen (ie. qui ne passe pas sa journée à faire du BGP) tant les noms de domaine sont omniprésents. Or comme nous allons le voir, la gestion de ce dernier et en particulier des serveurs autorités laisse quelque peu à désirer. Pour ce faire, étudions ce qu'il en est sur les domaines les plus populaires.

Une des rares listes des domaines populaires sur le Web est le Top 1 million d'Alexa (filiale d'Amazon). Cette dernière est mise à jour quotidiennement et l'étude qui suit est basée sur celle datée du 28 octobre 2016. La fiabilité de la liste est bien évidemment sujette à caution, mais c'est une ressource qui en vaut une autre dans ce domaine et elle est accessible gratuitement.

De cette liste donc ont été extrait les 10000 premiers domaines et pour chacun, j'ai cherché à déterminer les éléments suivants :

Pour ce faire, j'ai écrit un petit script Bash utilisant dig pour faire les dizaines de milliers de requêtes nécessaires, le tout tournant sur 2 machines utilisant Unbound dans sa version 1.5.10 (dernière disponible à l'heure de la rédaction de ce billet). Ce script n'est pas parfait (la récupération des TTL est parfois faillible par exemple), mais il a fait le travail pour le gros de la liste. Une deuxième passe a été faite sur une centaines de domaines pour lesquels aucunes données n'avait pu être récupérées, après amélioration de la partie du script sur la récupération des NS, et pour retester certains NS capricieux (les serveurs de noms chinois sont par exemple assez particuliers, certains étant accessible depuis une machine mais pas sur une autre pourtant relativement proche en termes de réseaux). Quelques chiffres en pagaille pour commencer :

Place au détail des résultats.

DNSSEC

La signature des données d'un domaine via DNSSEC permet d'authentifier cryptographiquement les réponses fournies par le DNS. On pourrait penser que ce mécanisme soit particulièrement adopté chez les gros domaines, d'autant plus qu'il autorise la mise en oeuvre de DANE/TLSA, permettant de contourner les lacunes du système des autorités de certification et leurs certificats.

Peine perdue : seuls 211 domaines signés avec DNSSEC. Pis, dans le Top 100 il faut attendre la 50ème position pour trouver un domaine signé (paypal.com. en l'occurence). Aucun des GAFAM n'a jugé bon de signer ses zones. C'est relativement incompréhensible dans la mesure où ces derniers sont assez friands des nouveaux TLD (.google, .apple, .amazon...), que DNSSEC est obligatoire pour ces derniers et qu'ils ont très certainement les compétences en interne pour le déployer. Bien évidemment DNSSEC n'est pas la panacée (ça ne protège pas d'un résolveur menteur type Main Rouge par exemple) mais en revanche les solutions que ce mécanisme apporte, notamment via DANE, surpassent toutes les rustines, type HPKP ou les enregistrements CAA, qui sont collées les unes après les autres au système des AC (À croire que nos amis GAFAM, en général si prompt à dénoncer les rentes de certaines corporations, font tout en protéger certaines).

Troll de ce test : on découvre que le 7506ème de mon top, jeanmarcmorandini.com., est signé (domaine enregistré chez OVH - qui propose la signature du domaine - et gestion du DNS laissée chez ces derniers), là où le premier, google.com., ne l'est pas.

A noter quelques fails, ainsi le premier enregistrement CNAME de www.gov.uk. est signé, mais pas le suivant et logiquement pas l'enregistrement A obtenu en bout de chaîne...

		$ dig +dnssec www.gov.uk.
		
		; <<>> DiG 9.10.3-P4-Debian <<>> +dnssec www.gov.uk.
		;; global options: +cmd
		;; Got answer:
		;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 524
		;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 6, ADDITIONAL: 1
		
		;; OPT PSEUDOSECTION:
		; EDNS: version: 0, flags: do; udp: 4096
		;; QUESTION SECTION:
		;www.gov.uk.                    IN      A
		
		;; ANSWER SECTION:
		www.gov.uk.             900    IN      CNAME   www-cdn.production.govuk.service.gov.uk.
		www.gov.uk.             900    IN      RRSIG   CNAME 8 3 900 20161207140749 20161107140749 1974 gov.uk. Fncc2fUqhBsL...
		www-cdn.production.govuk.service.gov.uk. 3600 IN CNAME www-gov-uk.map.fastly.net.
		www-gov-uk.map.fastly.net. 30 IN      A       151.101.120.144
		
		;; AUTHORITY SECTION:
		OG6KBN2PAEHJR3VO85E59G0BURTSNI7O.gov.uk. 14400 IN NSEC3 1 0 10 - OGMTN4UJKQS1GAGGN8KFAH93CMPOHKQ3 NS
		OG6KBN2PAEHJR3VO85E59G0BURTSNI7O.gov.uk. 14400 IN RRSIG NSEC3 8 3 14400 20161207140749 20161107140749 1974 gov.uk. j2LBlyH31jBv...
		fastly.net.             7200    IN      NS      ns1.fastly.net.
		fastly.net.             7200    IN      NS      ns2.fastly.net.
		fastly.net.             7200    IN      NS      ns3.fastly.net.
		fastly.net.             7200    IN      NS      ns4.fastly.net.
		
		;; Query time: 422 msec
		;; SERVER: 127.0.0.1#53(127.0.0.1)
		;; WHEN: Tue Nov 09 01:46:21 CET 2016
		;; MSG SIZE  rcvd: 619

Nombre de NS

Deuxième test, le nombre de serveurs autorités annoncés pour chaque domaine. Annoncer plusieurs serveurs est la plus basique des mesures pour assurer la continuité du service ainsi que la plus bête des techniques de répartition de charges. Faire uniquement dig NS domaine.example. ne permettant pas de récupérer à coup sûr les bons enregistrement d'un domaine, la technique consiste simplement à... faire du DNS : interroger les serveurs du TLD et descendre l'arbre. La méthode employée permet par ailleurs, en cas de CNAME, de bien récupérer les NS de ce dernier (voir l'exemple de www.gov.uk. plus haut : dig NS www.gov.uk. ne donne pas du tout le résultat final).

Bonne nouvelle cette fois-ci, hormis quelques huluberlus, 99,65% des domaines utilisent au moins 2 serveurs de noms. Moins reluisant, la plupart se contente de deux.

Ceci dit, avoir plusieurs NS est une chose, s'assurer de leur bonne répartion sur le réseau en est une autre (c'est d'ailleurs ce qui a été fatal à Twitter durant l'attaque sur Dyn, problème partiellement corrigé entre le moment où les tests ont été faits et la rédaction de ce billet par ailleurs). Regardons comment chaque domaine répartis tous ces serveurs.

Presque 70% des domaines choisissent de ne pas répartir leurs NS et parmi eux, le plus grand nombre les laissent sur le même AS que le principal enregistrement A du domaine. Une bourde de l'AS dans l'annonce de ces routes BGP ou une attaque DDoS vers ce dernier auront des conséquences désastreuses pour nombre de ces domaines. Et si l'on regarde quels sont les principaux AS hébergeant tous ces serveurs :

C'est la catastrophe... Sur les 33721 enregistrements NS trouvés, 18640 (55% du total) pointent vers seulement 10 AS... Si je ne me fais pas trop de soucis pour Google qui anycaste ses serveurs, je ne pense pas que cela soit le cas des serveurs hébergés dans le nuage d'Amazon.

Fait non testé, quel chemin emprunte les paquets ? En effet, on peut répartir ces serveurs sur 15 AS différents, si c'est pour au final se retrouver avec un seul prestataire s'occupant du transit, on ne fait que déplacer le problème.

TTL

Déterminer le TTL des enregistrements A (ou CNAME, car dans ce cas ce sera la première chose à redemander) a sans doute été la tâche la plus difficile de l'exercice. Pour éviter d'avoir une donnée issue du cache de mes résolveurs, il faut directement demander à un des serveurs autorité du domaine qui donne alors la bonne valeur. Problème, la liste Alexa est très imparfaite, de nombreux domaines qui y sont présents n'ont pas forcément d'enregistrements A ou CNAME (ytimg.com. par exemple : il s'agit d'un des domaines de Youtube utilisé pour distribuer des scripts aux clients. Des domaines ayant un enregistrement A sont i.ytimg.com. et s.ytimg.com.). Dans le cas où domaine.example. fait choux blanc, on teste tout de même www.domaine.example. Et si le premier NS testé ne répond pas, on teste tous les autres. Au final le TTL du premier enregistrement A ou CNAME a pu être déterminé pour 9866 domaines.

Choisir une bonne valeur pour ce TTL n'est pas forcément facile : trop faible, c'est générer du trafic DNS pour rien et trop élevé c'est prendre le risque qu'en cas de problème nécessitant de changer d'adresse IP, l'ancienne information reste trop longtemps dans les caches des résolveurs.

70,75% des domaines utilisent des TTL inférieurs à une heure. Si l'on s'attarde sur les TTL les plus faibles :

TTL Nb domaines
5 51
10 60
20 224
30 181
60 1022
300 3400

La conclusion est assez claire : avec des TTL aussi faibles, une bonne partie du trafic DNS ne sert strictement à rien. Ou plutôt si, en cas d'attaque DDoS sur les serveurs autorités, cela aggrave la situation dans la mesure où la probabilité que les données dans les caches des résolveurs soient présentes avant l'attaque et gardées le temps de celle-ci est très faible : aux bots attaquants le serveur s'ajoute très rapidement la masse du trafic légitime des résolveurs.

A noter que certains résolveurs possèdent une option pour forcer un TTL minimun en cache (cache-min-ttl sous Unbound par exemple). Cela est normalement une violation du protocole et peut de surcroît poser des problèmes de validation DNSSEC (le TTL étant signé - c'est la quatrième valeur dans un enregistrement RRSIG). En contrepartie, cela permet de passer outre les valeurs ridiculement basses et l'augmentation du trafic que cela génère. Dans le cas d'Unbound, la documentation conseille de ne pas mettre plus de 3600.

EDNS et TCP

Quelques rappels : EDNS (RFC 6891 dans sa forme actuelle) permet notamment de faire sauter la limite des 512 octets d'une réponse DNS mais également d'ajouter des options. La seule à ce jour est DO (pour DNSSEC OK). EDNS est donc obligatoire pour utiliser DNSSEC.

Malgré la confusion qui a pu être apportée par certains RFC (le 1123 notamment), cette dernière avait été tranchée il y a quelques années par le RFC 5966. Le récent RFC 7766 qui le remplace est désormais catégorique : la gestion de TCP n'est pas une option pour un serveur DNS (autorité ou résolveur par ailleurs). Pour les avantages qu'offrent le DNS via TCP, voir l'analyse du RFC 7766 sur le blog de Stéphane Bortzmeyer, cela m'évitera de paraphraser :-)

Bonne nouvelle, EDNS et TCP sont massivement déployés, et sur tous les NS d'un domaine dans l'écrasante majorité des cas. Si l'on regarde de plus près la taille maximale que peuvent envoyer les serveurs (s'ils gérent EDNS uniquement) :

L'écrasante majorité suit la recommandation de 4096 octets (que l'on retrouve notamment dans la section 6.2.5 du RFC 6891). Détail amusant, 333 serveurs répondent 4000 octets soit 4 ko au lieu de 4 kio. Étant donné qu'il s'agit de la valeur que donne les serveurs de noms de Microsoft, je suppose que les autres serveurs font tourner le logiciel de MS. A noter quelques cas où la taille maximale est de 64kio. Si cette taille est parfaitement autorisée, outre le fait que je n'ose imaginer la tête d'une réponse de 64kio, c'est également s'exposer sur le chemin, à un bazardage en règle des paquets par des middleboxes indélicates.

Autre détail amusant, 40 serveurs répondent une valeur de 0. 36 d'entre eux au moins appartiennent à NS1, un prestataire fournissant notamment un service de DNS. Amusant dans la mesure où ce résultat n'est donné que si l'on interroge le serveur via TCP (ce que fait mon script : il teste si le serveur accepte les connexions TCP et en profite pour faire les tests sur EDNS au passage). Si l'on discute au serveur en UDP, il donne bien la bonne valeur :

		$ dig +tcp linkedin.com. @dns1.p09.nsone.net.
		
		; <<>> DiG 9.10.3-P4-Debian <<>> +tcp linkedin.com. @dns1.p09.nsone.net.
		;; global options: +cmd
		;; Got answer:
		;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33535
		;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
		;; WARNING: recursion requested but not available
		
		;; OPT PSEUDOSECTION:
		; EDNS: version: 0, flags:; udp: 0

et en UDP :

		$ dig +notcp linkedin.com. @dns1.p09.nsone.net.
		
		; <<>> DiG 9.10.3-P4-Debian <<>> +notcp linkedin.com. @dns1.p09.nsone.net.
		;; global options: +cmd
		;; Got answer:
		;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48684
		;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
		;; WARNING: recursion requested but not available
		
		;; OPT PSEUDOSECTION:
		; EDNS: version: 0, flags:; udp: 4096

Difficile de dire quel logiciel NS1 utilise mais il possède au moins une bogue.

Politique sur les requêtes ANY

Les tout premiers tests de mon script ont fait apparaître que de nombreux serveurs refusaient de répondre aux requêtes ANY ou servaient un mystérieux enregistrement HINFO là où l'on s'attend plutôt à des enregistrments A, AAAA, MX, TXT... A noter que HINFO est normalement réservé, selon le RFC 1034, à fournir des informations sur le CPU et l'OS du serveur.

		; <<>> DiG 9.10.3-P4-Debian <<>> ANY upornia.com. @kay.ns.cloudflare.com.
		
		;; global options: +cmd
		;; Got answer:
		;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15252
		;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
		;; WARNING: recursion requested but not available
		
		;; OPT PSEUDOSECTION:
		; EDNS: version: 0, flags:; udp: 512
		;; QUESTION SECTION:
		;upornia.com.                   IN      ANY
		
		;; ANSWER SECTION:
		upornia.com.            3789    IN      HINFO   "Please stop asking for ANY" "See draft-ietf-dnsop-refuse-any"

Rendez-vous fut donc prit avec le brouillon en question. Écrit (ironie de l'histoire) par des gens de CloudFlare et de Dyn, il rappelle que le type ANY est très utile pour déboguer une zone ou pour récupérer en une requête plusieurs informations sur un domaine. Ceci dit, ces requêtes peuvent être dangeureuses dans la mesure où, dans le cas d'une attaque de type DDoS, elles peuvent possèder un très bon coefficient d'amplification pour peu que la réponse soit de taille respectable (et cela peut monter assez vite avec DNSSEC). A l'heure actuelle, il n'y a pas de méthode normalisée pour l'administrateur qui souhaite réserver un traitement particulier à ces requêtes. Ce brouillon envisage une solution qui consiste à dire au client : J'ai pris en compte ta requête, voici ma réponse, libre à toi de la prendre en compte et de la conserver pour ne pas recommencer le temps du TTL (assez long de préférence). Ce comportement ne contrevient pas à la définition de la requête ANY (le brouillon rappelle que ANY ne signifie pas ALL) et la réponse apportée par nos auteurs à l'avantage d'être de petite taille, ce qui limite l'amplification évoquée plus haut.

En attendant l'adoption de ce texte en RFC et son implémentation dans les logiciels, c'est un peu la jungle. Certains serveurs utilisent cette méthode (c'est le cas de CloudFlare notamment), d'autres refusent la connexion, répondent un code REFUSED, SERVFAIL ou NOTIMP, envoie une réponse vide... De fait les données récoltées ne peuvent donner qu'une indication et ne sont pas forcément représentatives de l'ensemble des domaines étudiés.

Le refus total par 19% des NS intérrogés s'expliquent entre autre par le fait qu'environ 11,5% des NS interrogés sont chez CloudFlare.

IPv6

Dernier point étudié, en peu en marge du reste : les serveurs autorités sont-ils accessibles via IPv6 ?

Et bien ce n'est pas fameux.

Conclusion

Que retenir de tout ça ? Eh bien qu'à la prochaine attaque du type de celle qu'a connu Dyn, on a va encore bien rigoler. Cette fois-ci les gros acteurs du Net ne pourront pas dire qu'ils n'étaient pas prévenus (pas par moi, ce blog n'a pas cette prétention hein). Certains semblent avoir commencé à réagir. Comme je le disais plus haut, Twitter a ajouté 4 NS à sa zone depuis la tenue des tests (Merci à Jan-Piet Mens pour le signalement indirect par ailleurs). Après vérification, il s'agit de 2 serveurs supplémentaires chez Dyn et de 2 serveurs chez Amazon (tous les 4 maquillés sous le domaine twtrdns.net.). Que disais-je ? Ah oui, on va bien rigoler.

Comme d'habitude, n'hésitez pas à me faire parvenir vos remarques en me haranguant publiquement sur Twitter :-).

En bonus

Disclaimer

L'auteur de ces lignes a délégué la gestion des noms de serveurs à son bureau d'enregistrement de nom de domaines (OVH en l'occurence) et le serveur sur lequel vous vous trouvez est hébergé... par OVH. J'en suis parfaitement conscient. La principale raison pour laquelle je n'héberge pas moi-même mes serveurs autorité est... DNSSEC. En effet, je n'ai aucune formation sur les choses du réseau autre que mon autodidaxie et je ne me sens pas encore capable de gérer sérieusement DNSSEC seul. En attendant de me faire la main sur un autre domaine, je délègue. Autre limitation : financière (louer des machines, même peu puissante - et le DNS demande au final peu de ressources - fini par avoir un coût non négligeable).