lalahop
Categorie: DNS & DNSSEC

On a deux instances d'OpenDNSSEC, instance A et instance B, sur deux machines différentes. L'instance A signe déjà 4 zones. L'instance B, une seule. On souhaite factoriser et garder une seule instance OpenDNSSEC, c'est-à-dire basculer la zone de l'instance B vers l'instance A. Le serveur DNS qui fait autorité sur la zone ne change pas, lui, seule l'instance OpenDNSSEC derrière change.

Évidemment, durant cette transition, il ne faut pas casser (même temporairement) la chaîne de confiance ni faire un roulement des clés (le roulement planifié ayant eu lieu récemment, cette solution serait possible mais sans intérêt) sinon c'est trop facile et ce n'est pas fun.

Table des matières

Export des paires de clés (KSK et ZSK) depuis l'instance source (B)

La première étape est d'exporter les clés privées associées à la zone depuis le HSM (softhsm) de l'instance B. La documentation se trouve ici : Key Management - SoftHSM Documentation v1.3 mais elle est un peu rustique et incomplète donc on va faire ça ensemble. 🙂

softhsm --export guiguishow.info-ksk.pem --slot 0 --pin <user_pin> --id <CKA_ID>
The key pair has been written to guiguishow.info-ksk.pem

Pour le paramètre « --pin », il faut indiquer le « USER PIN » de votre SoftHSM. On le trouve dans /etc/opendnssec/conf.xml, au cas où 😉 .

Pour le paramètre « --id », il faut indiquer le CKA_ID de la clé à exporter. Pour rappel, on l'obtient avec la commande :

ods-ksmutil key list --verbose

Pour la ZSK, c'est la même commande, seuls l'ID et le fichier de destination changent.

On transfert les clés de manière sécurisée entre les machines (scp, par exemple).

Ajout de la zone à l'instance de destination (A)

Dans la section « Enforcer » du fichier /etc/opendnssec/conf.xml, on décommente « <ManualKeyGeneration/> ». Le but étant qu'OpenDNSSEC ne génère pas automatiquement les deux paires de clés lors de l'ajout de la zone car c'est un peu la galère pour supprimer des clés (SoftHSM + OpenDNSSEC).

On fait prendre en compte cette modification :

service opendnssec-enforcer force-reload

On ajoute la zone comme d'habitude : politique (si besoin est) dans /etc/opendnssec/kasp.conf et la définition de la zone dans /etc/opendnssec/zonelist.xml. On reprend tout de l'autre instance. On n'oublie pas de mettre le fichier de zone non signé à l'emplacement que l'on a indiqué dans « <Input></Input> ».

On fait prendre en compte l'ajout de la zone :

ods-ksmutil update kasp [uniquement si vous avez modifié kasp.conf]
ods-ksmutil update zonelist

Import des paires de clés (KSK et ZSK) sur l'instance de destination (A)

On commence par la KSK :

softhsm --import guiguishow.info-ksk.pem --slot 0 --label "<CKA_ID>" --id "<CKA_ID>" --pin <user_pin>

On reprend le même CKA_ID, c'est-à-dire celui que la clé avait sur l'autre instance. Le pin est toujours l'user pin mais de la nouvelle instance, of course. 😉

Pour la ZSK, c'est la même commande, seuls l'ID, le label et le fichier source changent.

Association des clés (KSK et ZSK) à la zone sur l'instance de destination (A)

La documentation se trouve ici : ods-ksmutil - OpenDNSSEC Documentation. Pour des exemples pratiques (pour comprendre la syntaxe des valeurs à passer aux différents paramètres, par exemple) : OpenDNSSEC training (page 22).

Import de la KSK :

ods-ksmutil key import --cka_id "<CKA_ID>" --repository <nom_repository> --zone <nom_zone> --bits 2048 --algorithm 8 --keystate ACTIVE --keytype KSK --time <datetime_passage_à_l'état_ACTIVE>

On reprend toujours le même CKA_ID. La valeur du paramètre « --repository » est le nom donné à votre HSM dans /etc/opendnnsec/conf.xml (« SoftHSM » par défaut). Les paramètres de la clé (taille, algorithme cryptographique) sont indiqués dans kasp.conf.

La date et l'heure du passage de cette clé à l'état « active » peut être trouvé dans la base de données SQLite de l'ancienne instance (B). Non, je n'ai pas trouvé une manière plus conviviale de faire cela.

# sqlite3 /var/lib/opendnssec/db/kasp.db
sqlite> select HSMkey_id,active from dnsseckeys inner join keypairs on keypairs.id = dnsseckeys.keypair_id;

Comme indiqué dans le PDF d'exemples, le format de la valeur de ce paramètre est : AAAAMMDDHHMMSS.

Pour la ZSK, il faut suivre la même procédure, seuls « CKA_ID », la taille de la clé et la datetime de création changent et « --keytype KSK » devient « --keytype ZSK ».

Évidemment, il est possible de faire la transition d'une instance d'OpenDNSSEC à une autre alors que les clés sont dans un autre état que « active ». Il faut alors adapter le paramètre « --keystate ». Je ne recommande pas cela à cause des timings, toussa.

Maintenant, il faut nettoyer les états associés à la zone. Sans cela, l'auditeur (ods-auditor) retournera une erreur « Key (xxx) has gone straight to active use without a prepublished phase » dans les logs qui bloquera le processus de signature (c'est le principe d'un auditeur en même temps : vérifier que tout est cohérent avant de signer 😛 ) et ça serait dommage de désactiver l'auditeur pour si peu.

ods-signer clear <nom_zone>
rm /var/lib/opendnssec/tmp/tracker/<nom_zone>* /var/lib/opendnssec/tmp/<nom_zone>.* /var/lib/opendnssec/signconf/<nom_zone> /var/lib/opendnssec/signed/<nom_zone>

On peut désormais réactiver la génération automatique des paires de clés pour les zones en re-commentant « <ManualKeyGeneration/> » dans la section « Enforcer » du fichier /etc/opendnssec/conf.xml.

On fait prendre en compte les changements :

ods-control stop && ods-control start

Maintenant, la commande « ods-ksmutil key list --verbose » doit vous montrer une KSK et une ZSK pour votre zone avec une datetime de transition identique à l'ancienne instance (B) et votre zone doit être signée.

Divers

Si vous avez mis de mauvaises clés dans le SoftHSM ou de mauvais paramètres dans OpenDNSSEC, il est possible de les effacer afin de pouvoir recommencer (sinon les ID identiques empêchent cela) :

# Effacer une clé dans le SoftHSM
ods-hsmutil remove <CKA_ID> 
   OU
pkcs11-tool --module /usr/lib/softhsm/libsofthsm.so -b -d <CKA_ID> -y privkey --login --pin=<USER_PIN> --slot 0
 
# Effacer une clé dans OpenDNSSEC
# sqlite3 /var/lib/opendnssec/db/kasp.db
sqlite> select id from keypairs where HSMKey_id="<CKA_ID"; [notez l'ID]
sqlite> delete from keypairs where id=<ID_noté_ci_dessus>;
sqlite> delete from dnsseckeys where keypair_id=<ID_noté_ci_dessus>;

Note : l'outil pkcs11-tool se trouve dans le package opensc sous Debian. Il permet également de lister les clés présentes dans un slot (la sortie de cette commande est complémentaire à celle de la commande « ods-hsmutil list ») :

pkcs11-tool --module /usr/lib/softhsm/libsofthsm.so --list-objects --slot 0 --login --pin=<USER_PIN>

Supprimer une zone (n'affecte pas les clés dans la base de données SQLite d'OpenDNSSEC) :

ods-ksmutil zone delete -z <nom_zone>

Chez ARN, FAI associatif alsacien, on a mis en place un serveur DNS récursif-cache ouvert il y a un peu moins d'un an. Il y a quelques précautions à prendre et je n'ai pas trouvé un « how-to » qui ferait le tour de l'essentiel de la problématique.

Attention : ce billet n'est pas à prendre comme parole d'évangile. Il s'agit juste d'un retour d'expérience et de quelques notes d'un n00b qui s'est penché sur le sujet.

Table des matières

Définitions sous-jacentes

Je n'expliquerai pas le principe des attaques par amplification+réflexion, que ça soit en utilisant le protocole DNS ou non, mais je vous donne quelques ressources intéressantes concernant ce sujet :

Je ne détaillerai pas non plus les directives de configuration pour ouvrir votre récursif-cache.

Pourquoi mettre à disposition un serveur DNS récursif-cache ouvert ?

C'est en effet l'aspect le plus important : si l'on ne le comprend pas, on arrive à la conclusion qu'un récursif-cache qui répond uniquement aux blocs d'IPs qui ont été attribués à l'association suffit amplement. Mon avis sur cette question (liste non ordonnée) :

  • Parce qu'on peut le faire. 🙂
  • Parce que c'est enrichissant techniquement (montée en compétences) de chercher comment proposer un récursif-cache ouvert de manière sûre (en nuisant le moins possible à autrui).
  • Quelles garanties offrent les FAI et les gros (Google Public DNS, OpenDNS) en terme de neutralité des réponses ? Pour les FAI, on a des antécédents pour juger sur pièces : pub si réponse inexistante il y a quelques années, copwatch-idf, ARJEL, TPB en Belgique, ... La censure via le DNS est à la mode. OpenDNS mentait (oui, c'était désactivable, avec un compte mais galère si IP dynamique) et ils peuvent recommencer. Nuançons toutefois : les FAI associatifs ne sont pas des associations de malfaiteurs et sont soumises au même droit que les autres FAI. Ce qui implique de se conformer à une décision judiciaire ... quand on est parmi les parties citées à comparaître ... ce qui n'est pas le cas actuellement (oui, oui, je sais, le principe d'égalité devant la loi). Attention : je ne dis pas que les FAI associatifs sont une échappatoire mais simplement que les adhérents seront forcément consultés/informés de toute mesure prise qui serait contraire à l'éthique de l'association, ce qui est déjà une avancée majeure comparée à rester dans l'ignorance avec un fournisseur de récursif DNS sans éthique.
  • Le serveur DNS récursif-cache utilisé, tout comme le FAI, est un point assez central dès que l'on parle de vie privée : le FAI voit tout puisqu'il est l'intermédiaire obligatoire entre votre réseau et le reste des Internets, le récursif-cache voit toutes les requêtes DNS et comme la quasi-totalité des communications sur Internet commencent par une requête DNS ... Pour plus d'informations, je vous invite à lire DNS privacy considerations. Donc, c'est important que des structures qui s'engagent à être correctes au niveau de la neutralité proposent des solutions (argument de Julien Vaubourg). Utiliser un récursif-cache alternatif à celui de son FAI sans éthique n'empêche pas ce dernier de tout voir et de pouvoir altérer, mais c'est un début.
  • Dès qu'il y a un intermédiaire, qu'il soit associatif ou non, on peut avoir un doute légitime le concernant. En réaction, on se monte tous un récursif-cache validant à la maison sans forward vers un récursif commun ? Quid alors de la charge induite sur les serveurs DNS qui font autorité (on ne bénéficie plus de mutualisation du cache) ? Est-ce à eux de supporter le coût ? On notera au passage la disparité que cela produira entre les gros hébergeurs DNS/les TLD, qui pourront absorber le trafic supplémentaire (si l'on suit le raisonnement à terme), et les autres, ce qui conduira à une concentration des acteurs. Nuançons : oui, les serveurs de noms qui font autorité pour guiguishow.info. sont beaucoup, beaucoup moins sollicités que ceux qui font autorité sur info. et je n'ai aucun doute que la racine et les TLD tiendront le choc. Je pense que chaque réseau (at home, petite grappe de serveurs, ...) devrait avoir son récursif-cache validant, local et de confiance qui forward simplement les requêtes à des récursifs-cache mutualisés de confiance (pour la partie éthique / neutralité des réponses). On obtient un effet de strates (comme avec NTP) qui permet de ne pas surcharger les serveurs qui font autorité tout en gagnant une validation DNSSEC locale donc sûre ainsi qu'en performance.
  • Un récursif-cache neutre et validant, ça ne court par les rues. C'est pour cette raison que je pense qu'il est du devoir des FAI associatifs de proposer ce type de service. FDN, FAI associatif, propose un récursif neutre mais il ne fait pas de validation DNSSEC (on pourrait nuancer l'intérêt de ce point avec le problème du dernier kilomètre : la validation doit se faire au plus près du demandeur, de l'utilisateur final pour offrir toutes ses garanties), DNS-OARC propose un récursif-cache validant mais on n'a aucune garantie sur la neutralité des réponses données.
  • Parce qu'il ne doit pas y avoir que les gros (Google, OpenDNS) qui puissent le faire sans crainte sous prétexte qu'ils ont le blé/l'image/les ressources/les couilles/les ovaires/autre. Liberté d'entreprendre, tout simplement. Je veux pouvoir monter un récursif DNS parce que c'est faisable. Point. Je veux avoir la possibilité de le faire moi-même ou dans le cadre de mon association FAI favorite.
  • Il peut aussi y avoir un besoin d'itinérance. Je ne suis pas toujours connecté depuis ma ligne ADSL/mon VPN ARN. Répondre à ce besoin par une recommandation d'utiliser un VPN, ça me semble possible en entreprise mais décalé en dehors de ce cadre-là. Ça peut aussi constituer une première approche de nos idées, de notre cause par un futur adhérent. Un récursif-cache ouvert sert aussi pour des "démos" (au sens large) : commençons par arrêter de taper dig @8.8.8.8 / echo "nameserver 8.8.8.8" > /etc/resolv.conf quand on fait des tests/du debug devant/chez des non inités à notre cause et on aura alors plus de crédibilité pour les convaincre puisqu'il s'agit là d'un simple effet de prescription "si cet ami dont je pense qu'il a un bon niveau technique utilise Google Public DNS, alors ce service sera très bien pour moi".
  • Dès que l'on parle de mettre en place un serveur DNS récursif-cache ouvert, les yeux des interlocuteurs s'écarquillent. Mais quid des clusters NTP ouverts volontairement et surveillés ? Quid des serveurs de jeux vidéos (récupérer le statut sur Call of Duty (et d'autres) = UDP = sensible à une attaque par réflexion) ? Si l'on doit tout fermer et se la jouer individualisme, on ne va pas s'en sortir, à mon humble avis. On notera aussi qu'une attaque par réflexion+amplification peut être conduite avec un serveur DNS qui fait autorité, particulièrement si ce serveur sert des zones signées avec DNSSEC. Doit-on fermer les serveurs qui font autorité ? Quid des serveurs SNMP ouverts sans raison chez ces mêmes interlocuteurs ? Je passe sur les NTP ouverts par défaut chez Juniper, c'est cadeau.
  • Évidemment, il ne s'agit pas non plus de faire n'importe quoi puisqu'un récusif-cache ouvert est complice involontaire de l'attaquant en cela que c'est lui qui rend une attaque par réflexion+amplification intéressante (dissimulation relative de l'attaquant, amplification). Il y a tout une chaîne d'acteurs à protéger au-delà du réseau dans lequel se trouve le récursif-cache ouvert : les upstreams qui n'ont pas à assumer le choix, plusieurs victimes qui n'ont rien demandé, ... Si le réseau se fait blackholer par un opérateur, il sera également impossible pour les utilisateurs de ce réseau d'accéder aux services hébergés par cet opérateur ou derrière cet opérateur (downstreams). La mise en place de contre-mesures lors de la prise de décision de fournir un récursif-cache ouvert est donc une obligation morale envers autrui, à mon sens.
  • En conclusion pour ceux qui n'ont pas tout lu : ne pas confondre récursif ouvert par erreur/abandonné et récursif ouvert sciemment et surveillé. FDN n'a pas succombé à son récursif ouvert car il est surveillé et rate-limité (uniquement les requêtes portant sur le QTYPE ANY, à ma connaissance).

Typologie des attaques

Ce que j'ai observé, sur l'infra d'ARN, en presque un an :

  • Quel est le type de serveur DNS qui est le plus utilisé dans des attaques par réflexion+amplification, serveur qui fait autorité ou récursif ? Je n'ai vu aucune attaque sur notre serveur qui fait autorité (les requêtes pour vérifier s'il est un récursif ouvert ne comptent pas, of course). J'explique cela par le fait que nos zones sont trop peu intéressantes (elles ne sont pas signées, la requête la plus intéressante, de type ANY, a une taille de 71 octets au niveau 2 et génère une réponse de 337 octets) et inconnues comparées à zones intéressantes "bien connues" comme *.gov, isc.org, ... (à partir d'un scan réseau, il est possible de savoir qu'un récursif ouvert est adressé par telle IP mais pas de savoir quelles zones sert un serveur DNS qui fait autorité adressé par telle IP).
  • Requêtes de type ANY ou non ? Les deux et la proportion semble équivalente/se lisser sur une longue période : tantôt une écrasante majorité de requêtes de type ANY, tantôt une majorité de requêtes qui utilisent edns (pour pousser la limite de la réponse sur UDP au-delà des 512 octets) et qui portent sur de gros RRset A/AAAA (et une fois TXT), et aussi les deux en parallèle.
  • Régularité et intensité ? L'intensité est variable. Sans parler de fond permanent, il y a quand même quelques tests (es-tu un récursif ouvert ?) et plus si affinité (hop, je te fais passer quelques requêtes et je m'arrête) en quasi-permanence. Impossible de parler d'attaque à ce stade-là. À côté de cela, il y a les pics temporaires : 3/4 IPv4 sources différentes qui émettent en continu des requêtes qui génèrent des réponses supérieures à 4 ko, ce qui nous donne des pics de l'ordre de 100-140 kbps très régulièrement (de l'ordre d'au moins une fois par 24 heures). La durée de ces pics est extrêmement variable : plusieurs dizaines de minutes à quelques heures. On constate aussi un effet de rafales puis silence puis rafale que je ne m'explique pas dans le cadre d'une attaque... Le plus gros pic enregistré était de l'ordre de 350 kbps sur plusieurs jours. C'était dans les derniers mois de 2013, quand les attaques par réflexion+amplification étaient extrêmement à la mode. ÉDIT du 05/09/2014 à 16h45 : Nouveau pic à 700 kbps, ANY webpanel.sk, environ 4 ko au compteur, plusieurs dizaines d'IP sources réparties dans environ 20 /24, depuis plus d'une semaine (28 août - encore en cours aujourd'hui). Fin de l'édit. Au niveau de la régularité, je n'ai observé aucun schéma sur le long terme (pas plus la nuit que le jour (heure de Paris), les périodes de congés que les jours ouvrés, ...). Il peut se passer plusieurs jours sans attaque puis une déferlante de pics.
  • Domaines connus ou inconnus ? Après coup, je me suis rendu compte que cette métrique n'est pas pertinente car subjective (connu de qui ? Quelle portée géographique ? Connu selon quelle intensité ?). Je pensais pouvoir établir une typologie des domaines utilisés afin de faire de la limitation de trafic plus contraignante pour les domaines clairement conçus dans l'objectif de servir dans une attaque. Mais ça ne veut rien dire : cela peut-être un sous-domaine proposé par un hébergeur low-cost donc le site web donne une apparence légitime, cela peut conduire à un site web en langue étrangère voire à pas de site web du tout, ... Bref, impossible d'en déduire quoi que ce soit et de faire une classification (à partir d'un seul point de collecte, j'entends, si un même domaine est vu par plusieurs points de collecte, on peut avoir un doute légitime).
  • IPv4 ou IPv6 ? Les attaquants ne sont pas IPv6-ready, très clairement.

Cette typologie vaut ce qu'elle vaut puisque je l'ai réalisée sans méthodologie ni rigueur scientifique.

Comment procéder ?

Selon moi, il y a quelques étapes à suivre avant de pouvoir ouvrir un récursif DNS au monde entier l'esprit serein.

Adresse mail de contact valide

La première étape est de faire en sorte que l'on puisse vous contacter en cas de problème. Cela se fait à travers la base de données de votre RIR. Pour le RIPE, il suffit d'utiliser ce formulaire. En indiquant les adresses IPv4 et IPv6 que vous allez assigner à votre récursif ouvert, vous devez obtenir une adresse mail de contact. Évidemment, vous testerez cette adresse mail en vérifiant qu'elle est fonctionnelle et qu'elle pointe bien vers des personnes qui seront en capacité d'agir en cas de signalement. Si le formulaire vous retourne rien, vous avez quelques objets à créer dans la base de données de votre RIR.

Supervision et métrologie

La deuxième étape est de superviser la machine (physique, virtuelle, LXC, ...) qui sera votre récursif ouvert, pas tellement pour savoir si le serveur (logiciel) fonctionne, n'est pas planté, ... mais plutôt pour grapher le débit et le nombre de paquets sortants. Oui, c'est bien le trafic sortant qui est intéressant : quelle volumétrie de trafic ce serveur envoie-t-il à l'extérieur ?

L'objectif est triple :

  • Être averti d'une grosse attaque. L'outil de supervision doit lever une alerte, soit quand un seuil plutôt large est atteint sur une période très courte, de l'ordre de la minute (un pic important quoi), soit quand un seuil plutôt faible est atteint sur une période d'échantillonnage plus longue, de l'ordre des 5 minutes. Ma préférence va pour le deuxième type de seuil/échantillonnage car il indique qu'une volumétrie de trafic inhabituelle s'écoule depuis quand même une certaine période, ça serait bien d'aller y jeter un œil. Pour vous donner un ordre d'idée, chez ARN nous faisons un échantillonnage par 5 minutes et une alerte dès 250 kbps (1/4 de mbps).
  • Garder un historique grâce à la métrologie. À la fois pour avoir des éléments de réponse pour répondre aux mails d'abus alors que pourtant vous n'avez reçu aucune alerte (le cas s'est produit chez ARN, la victime a simplement envoyé un mail à tous les responsables des serveurs DNS récursifs qui l'attaquaient sans se préoccuper du débit effectif émis par chacun des récursifs) et pour avoir une trace visuelle, toujours plus expressive que des chiffres.
  • ÉDIT du 04/09/2014 à 19h00 : Calculer et grapher automatiquement le 95e centile. Très utile pour apprécier la facturation de vos transitaires. Vous pouvez alors raisonner en terme de coût : combien l'attaque en cours va-t-elle coûter et décider alors de fermer votre récursif-cache temporairement ou définitivement. Fin de l'édit

Cela peut se faire simplement avec votre outil de supervision/métrologie favori, Zabbix dans le cas d'ARN.

Ça peut aller jusqu'à utiliser Netflow/IPFIX ou des outils plus centrés sur le DNS comme DSC (chiffres, graphes, par QTYPE, remonter les QNAME populaires, ...).

On peut aussi créer des règles iptables "de comptabilité" : règles en « -j ACCEPT » qui permettent de comptabiliser (iptables -L -n -v pour voir les compteurs) les paquets entrants et sortants du port udp/53 de votre récursif.

Chez ARN, on s'est arrêté à Zabbix + compteurs iptables pour la prod'.

Préparer une configuration fermée

Dans la configuration de votre serveur DNS, prévoyez, en commentaire, le morceau de configuration qui ferme le récursif à votre réseau. L'idée est qu'en cas d'une sévère attaque, alors que vous serez totalement paniqués, vous puissiez facilement fermer votre récursif en attendant que ça se passe.

Cela a encore plus d'intérêt quand vous avez un moyen facile et permanent d'accéder à une console sur vos machines même si vos liens réseaux vers l'extérieur (transit, peering) sont saturés : accès physique ou accès distant (via IPMI en OOB, par exemple). Chez ARN, nous avons un accès IPMI à nos machines, pour information.

Choisir des méthodes pour juguler les attaques

RRL

Response Rate Limiting consiste à limiter le nombre de réponses par seconde que fournit un serveur DNS qui fait autorité à un préfixe IP(v4/v6) donné. C'est implémenté dans tous les logiciels serveur DNS qui font autorité : BIND >= 9.9.4 (pas activé à la compilation par défaut, 9.10 pour que ça soit le cas), nsd >= 3.2.15, knot, ...

Les avantages :

  • On est à un niveau très fin : quel couple QTYPE+QNAME dépasse le seuil défini ? Seuls les préfixes IP desquels émanent des requêtes portant sur ce couple seront rate-limitées. RRL s'adapte à l'attaque en cours, sans aucun travail humain puisque l'identification des paramètres de l'attaque (QNAME, QTYPE, sources) est automatique.
  • Une fois le seuil atteint, le serveur répondra quand même des réponses tronquées (un SLIP) invitant un vrai client DNS à retenter en TCP. Une réponse tronquée étant d'une taille inférieure, on annule l'effet d'amplification. Un client légitime dans un préfixe rate-limité aura quand même une réponse et ne sera pas totalement pénalisé.

Les inconvénients :

  • Les versions des logiciels serveur DNS qui implémentent RRL ne sont pas encore dans les dépôts stable de Debian. Pour BIND, la version 9.9.5 présente dans wheezy-backports a été compilé avec la fonctionnalité RRL. Rappel : la team Debian-security ne s'occupe pas des backports. 😉
  • On promène les paquets (requêtes) dans notre réseau pour finalement que le serveur refuse d'y répondre. Nuançons : ce n'est pas couteux puisque c'est en interne de notre réseau et que c'est les réponses qui ont un impact.
  • RRL est-il adapté pour les récursifs-cache ? Un récursif-cache n'a pas à interroger un serveur qui fait autorité des dizaines de fois par seconde pour un même QTYPE+QNAME grâce à son cache, ce qui justifie l'emploi de RRL sur les serveurs faisant autorité. Le client d'un récursif-cache en revanche n'a pas de cache donc il peut légitimement interroger le récursif-cache des dizaines de fois par seconde pour un même couple QTYPE+QNAME. Mon avis, basé sur les autres formes de limitation de trafic est qu'il suffit d'adapter le seuil. Mais peut-être que je me trompe sur ce point.

Chez ARN, cette solution n'a pas été retenue du fait qu'elle n'est pas implémentée dans les versions de logiciels serveur DNS disponibles dans les dépôts stable de Debian.

Limitation de trafic global en utilisant Netfilter

Puisque le routeur d'entrée d'ARN est une machine GNU/Linux (oui, un routeur ce n'est pas forcément un Cisco très cher 😉 ), on peut utiliser Netfilter pour limiter le trafic à destination de notre récursif-cache sur le port udp/53.

Pour la mise en pratique (pour le choix du module hashlimit, voir : Limiter le trafic d'un serveur DNS (notamment d'un récursif ouvert)) :

#IPv4
iptables -A FORWARD -o eth1.140 ! -s 89.234.141.0/24 -d 89.234.141.66/32 -p udp -m udp --dport 53 -j DNS-RATE-LIMIT
iptables -A DNS-RATE-LIMIT -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name RL-DNS-GLOBL-v4 --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ALL DNS QUERIES 10/s burst 20" -j DROP
 
#IPv6
ip6tables -A FORWARD -o eth1.140 ! -s 2a00:5881:8100::/40 -d 2a00:5881:8100:1000::3/128 -p udp -m udp --dport 53 -j DNS-RATE-LIMIT
ip6tables -A DNS-RATE-LIMIT -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name RL-DNS-GLOBL-v6 --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT ALL DNS QUERIES 10/s burst 20" -j DROP

La création d'une chaîne nommée « DNS-RATE-LIMIT » vous semblera légitime dans la section suivante.

Ici, on autorise 10 requêtes DNS par seconde par /24 et par /56 avec un burst à 20 requêtes par seconde. Le burst signifie que le client a le droit à 20 requêtes dès la première seconde puis 10 requêtes par seconde pour les secondes suivantes. S'il n'atteint pas le seuil (10 requêtes par seconde donc), il récupère la possibilité d'atteindre 20 requêtes par seconde au bout de 2 secondes (combien de secondes faut-il pour atteindre 20 quand on en autorise 10 requêtes par seconde ?). Le contenu des hashtables sont consultables depuis /proc/net/ip*t_hashlimit/.

En fonction de l'organisation de votre infra, il est inutile de limiter le trafic émis par l'infra elle-même et les abonnés (VPS/VPN/ADSL) si vous avez déployé des contre-mesures pour lutter contre l'usurpation d'IP (BCP 38 + drop des paquets qui ont une de vos IPs en source en entrée de votre réseau). De plus, un FAI associatif a vocation à rester à taille humaine : on se connaît, on se fait confiance (et des hébergeurs low-cost bien connus sont plus pratiques et moins chers pour mener à bien une attaque). De plus, le récursif étant en local, les requêtes peuvent s'enchaîner plus vite donc le seuil peut-être atteint plus facilement. Exemples chez ARN : OpenVPN et son mécanisme d'iroute empêchent l'usurpation d'IP sur la partie VPN. Un VPS ne peut pas usurper une IP (qu'elle soit interne ou externe) car on a déployé BCP 38, Ingress Access Lists pour être précis, avec iptables, sur chaque interface réseau virtuelle.

On se rend compte que cette méthode impose un dilemme moral puisque plus on est permissif pour les usages légitimes, plus on est permissif envers les attaquants. J'ai choisi les seuils (10 r/s burst à 20) en fonction des exemples illustrant RRL ainsi qu'en fonction des exemples donnés par Stéphane Bortzmeyer (voir les ressources pointées au sommet de ce billet) puis j'ai ajusté. D'après mes tests, on ne peut pas descendre en dessous de ces valeurs sous peine de nuire à des usages légitimes : une installation Debian classique nous fait un pic à 12 r/s pendant l'installation (si la résolution échoue, l'utilisateur obtient une erreur et ne peut continuer), résolution des reverses dans un logiciel torrent, page web bien chargée sans utilisation d'Adblock/NoScript/autre, ...

Exemple récent de ce que permettent ces seuils dans la théorie : la requête ANY nrc.gov génère une réponse de 4,278 ko soit 34,224 kb. On considère 4 IP source différentes (cf typologie) dans 4 préfixes /24 différents en simultané : 136,896 kb. Chaque IP a le droit à 10 r/s en vitesse de croisière : 1368,96 kbps soit 1,33 Mbps. On est au niveau applicatif, il faut donc ajouter les entêtes IP+UDP (ce qui rendra le facteur d'amplification moins impressionnant mais on n'est pas la pour ça). Est-il moralement acceptable de laisser filer potentiellement plus de 1,33 Mbps de trafic pourri ? D'autant plus que les attaquants n'envoient pas un nombre constant de paquets mais agissent plutôt en mode grosse rafale, moins de paquets, grosse rafale, etc. Donc les 20 r/s du burst se débloquent assez régulièrement, ce qui permet donc à la grosse rafale de passer.

Le seul avantage que je vois à cette solution est, qu'une fois le seuil dépassé, les paquets en surplus provenant de préfixes limités sont supprimés en entrée du réseau.

Les inconvénients :

  • La limitation porte sur un préfixe (/24 en IPv4, /56 en IPv6). Il est évident que l'on joue sur la dispersion des utilisateurs de notre récursif dans des préfixes différents : si plusieurs utilisateurs viennent du même préfixe avec des usages "gourmands" sur une même période de temps, alors des usages légitimes seront bloqués avec les seuils présentés ci-dessus, c'est une certitude. Et un seuil plus permissif, même uniquement un burst plus élevé, permettra aux attaquants de générer encore plus de trafic pourri. Tout est histoire de compromis en sécurité informatique.
  • J'ai remarqué que les limitations présentées ci-dessus sont globalement inefficaces. Les règles iptables ne sont pas souvent déclenchées (un peu moins d'une centaine par semaine) car le nombre de paquets par seconde ne dépasse pas le seuil défini et car le burst se régénère vite (les deux sont liés). Notamment parce que des attaquants subtils utilisent plutôt un plus grand nombre de récursifs-cache couplé à un petit de requêtes par seconde destinées à chaque récursif-cache que l'inverse. J'en arrive à la conclusion que ces limitations protègent de gros chocs mais sont trop perméables aux attaques au quotidien.

Chez ARN, cette solution a été retenue mais elle ne suffit pas : on identifie assez clairement le besoin de limiter plus fermement certains QTYPE et QNAME.

Limitation de trafic portant sur le QTYPE ANY avec Netfilter

Une partie des attaques utilisent le QTYPE ANY. Ce type d'enregistrement est valide (au sens des normes donc on doit le laisser passer) mais sert très rarement dans la pratique sauf debug et logiciels plutôt mal conçus et désuets. On peut envisager de limiter plus fortement le trafic des requêtes DNS portant sur ce type.

La difficulté vient du fait que, dans le format d'un paquet DNS, le QTYPE arrive après le QNAME. On est donc dépendant de la taille du QNAME pour trouver le QTYPE dans le paquet. Il est donc impossible de limiter toutes les requêtes de type ANY en utilisant un langage tel que u32. On peut toutefois utiliser le module « string » de Netfilter qui fait une recherche linéaire.

Pour la mise en pratique (en complément de la section précédente, d'où la chaîne « DNS-RATE-LIMIT » 😉 ) :

#IPv4
iptables -I DNS-RATE-LIMIT -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 28 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v4 --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP
 
# IPv6
ip6tables -I DNS-RATE-LIMIT -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 48 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v6 --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP

Ici, on autorise 1 requête de type ANY par seconde par /24 et par /56 avec un burst à 2 requêtes par secondes.

Explications :

  • Concernant le motif recherché, « 00 00 ff 00 01 » : 00 : fin du QNAME, c'est-à-dire « . », la racine ; 00 ff : QTYPE, codé sur 2 octets (16 bits), 00 ff = 255 = ANY ; 00 01 : CLASS, codé sur 2 octets (16 bits), 1 = IN. Pour les numéros correspondant à chaque QTYPE/CLASS/autre, voir : Domain Name System (DNS) Parameters - IANA 😉 . On peut utiliser un motif plus court mais il faut alors faire attention aux faux positifs.
  • Concernant le début de la recherche dans un paquet, « --from 28/48 » : étant donné que ce module est plus gourmand que u32 (par exemple) car recherche linéaire et que le motif peut conduire à des faux positifs, je trouve que c'est une bonne idée de commencer la recherche au niveau applicatif, sans se soucier des couches inférieures. On prend la taille standard, sans s'occuper des options IP (v4 comme v6). Exemple : 20 octets IPv4 + 8 octets UDP. Le module string compte à partir de 0 (cf man) donc --from 28 : commence l'analyse au 29e octet donc au début de DNS. Le module string commence sa recherche au début de la couche IP, il ne faut donc pas comptabiliser la couche 2 (exemple : ne pas ajouter 14 octets pour Ethernet) ! Sur plusieurs sites web, j'ai vu l'usage de « --to » pour se prémunir contre d'immenses paquets qui rendraient la recherche très fastidieuse. C'est une mauvaise idée à mon avis : on ne peut pas prévoir l'emplacement du QTYPE ! Et si un paquet inclut des options IPv4 ou des entêtes IPv6 d'extension ? Et si le QNAME est très long ? Le QTYPE sera au-delà de la zone de recherche et le paquet échappera donc à notre filtre.
  • Attention à choisir des noms de hashtable différents en fonction de l'usage (rate-limit global ou rate-limit ANY). Utiliser une même table dans plusieurs règles fait que c'est la limite la plus basse qui sera appliquée MÊME si la règle correspondante n'est pas déclenchée ! Exemple : soit le jeu de règles de filtrage suivant (sans cumul avec les filtres présentés ci-dessus) :
    -A DNS-RATE-LIMIT -m u32 --u32 "0x0>>0x16&0x3c@0x14&0xffffff00=0xff00" -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ANY ." -j DROP
    -A DNS-RATE-LIMIT -m u32 --u32 "0x0>>0x16&0x3c@0x14&0xffdfdfdf=0x3495343&&0x0>>0x16&0x3c@0x18&0xffdfdfdf=0x34f5247&&0x0>>0x16&0x3c@0x1c&0xffffff00=0xff00" -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ANY isc.org" -j DROP
    -A DNS-RATE-LIMIT -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name RL-DNS --hashlimit-srcmask 24 -m comment --comment "RATE-LIMIT ALL 10/s-20/s" -j DROP

    Les compteurs (iptables -L -n -v) des deux premières règles n'étaient pas incrémentés car les règles n'étaient pas déclenchées car les requêtes étaient de type A. Bizarrement, la dernière règle se déclenchait alors qu'une capture réseau montrait qu'on avait 4-8 requêtes/seconde mais jamais plus en entrée. En sortie de Netfilter, on voyait 1 à 2 requêtes par seconde. Vider les règles iptables et les remettre n'avait aucun effet. Après debug, le simple fait d'introduire l'une des deux premières règles faisait dysfonctionner la dernière règle. Utiliser les mêmes règles mais avec des noms de tables différents a résolu ce problème que je n'explique pas.

L'avantage est que ces limitations, complémentaire aux limitations "globales" sont efficaces : déclenchées beaucoup plus souvent (un peu plus de 8 millions de paquets en une semaine) sans pour autant empêcher les usages légitimes.

Les inconvénients :

  • Quid des faux positifs que peut provoquer le motif recherché ? Le risque est très limité puisque ces recherches s'appliquent uniquement sur la charge utile DNS des paquets à destination du port udp/53 de notre récursif. FDN n'a pas rencontré de problèmes, à ma connaissance.
  • Une recherche linéaire permet-elle d'encaisser de grosses attaques ou le netfilter sur notre routeur d'entrée va devenir un goulot d'étranglement ? Je n'ai pas réussi à mettre en avant quoi que ce soit avec mes tests dans un lab' local (100 mbps). Peut-être que je m'y suis mal pris.
  • Ces limitations apportent une solution à une partie du problème seulement : quid des attaques qui portent sur un gros RRset de type autre que ANY ?

Chez ARN, cette solution a été retenue, en complément d'une limitation globale du nombre de requêtes par seconde et apporte de bons résultats.

Limitation de trafic portant sur des QNAME précis avec Netfilter

On peut être tenté de limiter plus fortement le trafic des requêtes portant sur des QNAME clairement identifiés comme servant dans des attaques par réflexion+amplification. La première question est de savoir comment on identifie les QNAME en question. Stats avec DSC ? Un dump réseau (quid alors de la vie privée des vrais utilisateurs (oui, avec un petit nombre d'abonnés, on peut se souvenir, de tête, à quel abonné on a donné quelle IP et donc voir des choses qui ne nous regardent pas)) ? Se baser sur des sites web comme DNS Amplification Attacks Observer ou Honeypot DNS and amplification attacks ?

Pour la mise en pratique, on utilise les modules u32 et hashlimit de Netfilter.

L'avantage est que cette méthode est très efficace, surtout quand vous ajoutez préventivement les QNAME que vous trouvez sur les sites web sus-cités.

Les inconvénients :

  • Quelle confiance accorder aux sites web qui répertorient les attaques ? Nuançons : on peut très bien construire nos propres stats avec DSC.
  • Comment entretenir le jeu de règles ? D'un côté, trop de règles ralentissent Netfilter, de l'autre des règles cessent d'être utiles voire ne le sont jamais (toutes les attaques recensées sur les sites web sus-cités n'arrivent pas jusqu'à notre récursif). Comment purger les règles automatiquement ? Quelle fréquence ? Quels critères ? Quid des QNAME qui cessent d'être utilisés temporairement et reviennent en force des mois plus tard (exemple : fkfkfkfa.com) ? Bref, l'entretien est loin d'être simple.
  • Le suivi des nouvelles attaques, la création/l'application des règles u32 et l'entretien du jeu de règles ont un coût humain qui ne semble pas compatible avec l'associatif : le temps humain est précieux, aucune motivation pour faire ce boulot, ...

Chez ARN, j'ai longuement testé (et apprécié) cette méthode avant de me rendre compte que ce n'était pas compatible avec le rythme associatif et de laisser tomber.

Limiter la taille des réponses que notre récursif-cache fera sur UDP

Avec l'extension edns0, un client DNS a la possibilité d'indiquer à un serveur DNS qu'il veut recevoir une réponse plus large plus que les 512 octets par défaut sur UDP. Le serveur peut ainsi s'adapter. Le serveur possède également une directive de configuration pour indiquer quelle est la taille maximale d'une réponse qu'il acceptera d'envoyer sur UDP, quelle que soit la valeur indiquée par le client dans sa requête. Pour BIND et Unbound (à partir de la version 1.4.21), il s'agit de « max-udp-size [1024-4096] » avec une valeur par défaut et max impératif fixés à 4096 octets. ÉDIT du 04/09/2014 à 18h45 : Unbound n'impose pas de minimum, contrairement à BIND. Fin de l'édit

Pourquoi ne pas utiliser ces directives de configuration pour limiter les attaques qui utilisent de gros RRset d'un type autre que ANY et edns ? Ainsi le facteur d'amplification est réduit et notre récursif-cache intéressera beaucoup moins les attaquants.

ÉDIT du 05/09/2014 à 17h30 : Si le client de notre récursif-cache est un stub-resolver (« un résolveur qui ne sait pas suivre les renvois et qui dépend donc d'un ou de plusieurs résolveurs complets pour faire son travail [...] C'est ce résolveur minimum qu'appelent les applications lorsqu'elles font un getaddrinfo() ou getnameinfo(). Sur Unix, le résolveur minimum fait en général partie de la libc et trouve l'adresse du ou des résolveurs complets dans /etc/resolv.conf » ), alors il ne fait pas de validation DNSSEC donc il ne positionne pas le bit DO et donc notre récursif ne lui enverra pas les signatures cryptographiques (qui sont quand même ce qui fait exploser la taille des réponses loin devant les IDN et IPv6). En conséquence, les réponses seront petites. S'il s'agit d'un récursif-cache qui forward les requêtes à notre récursif (et à d'autres, ce qui permet de switcher sans dommage pour l'utilisateur final si notre limite est trop basse et impose un passage à TCP pour une requête donnée), alors une limite de la taille des réponses plus petite que celle par défaut impactera possiblement uniquement la première résolution (d'un même nom) d'un client de ce récursif-cache. Les résolutions suivantes de ce nom seront immédiates puisque mises en cache.

De plus, avant d'être obligé de tronquer sa réponse, un récursif-cache peut "produire" une section additionnelle minimaliste ce qui a pour effet de réduire la taille de la réponse, de l'amener en dessous de la limite et donc de fournir une réponse non tronquée au client (la section « ANSWER » de la réponse est intacte).

Face à ces optimisations, la taille maximale des réponses par défaut semble démesurée.

Un usage plus important de TC + passage en TCP ne sera pas toujours pénalisant : la norme autorise l'utilisation de connexions TCP persistantes. Les récursifs-cache implémentent cela. Malheureusement, aucun stub-resolver ne supporte cela à l'heure actuelle.

La question qui reste en suspens pour ma part est : comment mesure-t-on si notre limite est trop basse et gêne les utilisateurs de notre récursif ? Mesurer la proportion de trafic TCP versus UDP ? Et si le client (stub-resolver ou récursif qui forward) n'a pas réessayé suite à l'envoi d'une réponse tronquée mais a contacté le prochain récursif-cache dans sa configuration ? Un récursif-cache qui envoi uniquement des réponses tronquées (ce qui est loin d'être le cas avec une limite à 1460 octets à l'heure actuelle) est un récursif-cache plutôt inutile, à mon avis. Fin de l'édit.

À titre personnel, je ne vois aucun avantage à cette méthode. ÉDIT du 05/09/2014 à 17h10 : Après avoir examiné à nouveau cette piste, je vois plusieurs avantages :

  • Ça permet de couper net dans le tas. Illustration avec l'attaque "populaire" (du point de vue du récursif d'ARN) du moment : ANY webpanel.sk, environ 4 ko au compteur, plusieurs dizaines d'IP source réparties dans environ 20 * /24 différents. En laissant la limite par défaut (4096 octets) : 700 kbps en sortie de notre récursif au 95e centile sur une période de 7 jours. En passant la limite à 1460 octets : 180 kbps au 95e centile sur les 39h écoulées depuis la reconfiguration. Évidement, cela vient en sus de l'utilisation de Netfilter pour limiter le nombre de requêtes par seconde portant sur le QTYPE ANY.
  • Cette technique est la seule (pour l'instant, RRL permet aussi cela) à pouvoir contrer les attaques de type edns0 + gros RRset de manière automatisée puisque nous avons vus ci-dessous que les autres méthodes sont soit inefficaces (rate-limiting global) soit manuelles (rate-limiting sur des QNAME précis).

Fin de l'édit.

Les inconvénients :

  • On pénalise tout le monde (alors que la limitation de trafic ne s'applique qu'à certains préfixes), tout le temps (alors que la limitation de trafic s'applique temporairement et uniquement en cas d'abus), pour tous les usages (ici même une réponse légitime signée avec DNSSEC pourra être tronquée). Certes, un client DNS légitime réessayera en TCP mais on ralentit fortement les usages.
  • Quelle est la taille idéale à autoriser ? Celle qui ne pénalise pas les usages ? Comment l'identifie-t-on sans être intrusif ni dépendre de notre typologie d'utilisateur ? +/- la MTU pour éviter l'overhead causé par la fragmentation en cas d'attaque ? Quelle est la taille d'une réponse DNSSEC standard ? Qu'est-ce qu'une réponse signée avec DNSSEC standard ? Cette limite peut évoluer avec le temps/la population d'utilisateurs, il faut donc prévoir de l'adapter.

Chez ARN, cette idée n'a pas dépassé le stade du test dans un lab'. ÉDIT du 05/09/2014 à 17h05 : Une limitation de la taille des réponses sur UDP à 1460 octets est en test depuis le 04/09/2014. Fin de l'édit. ÉDIT du 04/11/2014 à 11h00 : Avec un recul de deux mois : ça juste marche. Les usages légitimes ne semblent pas être pénalisés et les attaques de forte amplitude ont cessé (on est à quelques kbps au 95e centile sur un mois). Peut-être les attaquants mesurent le gain d'amplification obtenu et observent que notre récursif-cache est un mauvais élève de ce point de vue. Il convient de rester prudent pendant encore quelques mois : les attaques par réflexion+amplification vont et viennent en terme de popularité donc il ne faut pas crier victoire trop vite. Fin de l'édit.

ÉDIT du 04/09/2014 à 22h00 : On peut aller encore plus loin et ouvrir un récursif-cache sur l'extérieur uniquement en TCP. Malheureusement, c'est encore du domaine du futur et ce, pour plusieurs raisons :

  • Les stub-resolvers (la glibc, utilisée, entre autres, par Debian, en tous cas), n'utilisent pas spontanément TCP mais tentent d'abord de faire leur requête sur UDP puis, en cas d'obtention d'une réponse tronquée seulement, retentent sur TCP. Il n'y a aucune directive de configuration à indiquer dans resolv.conf/host.conf pour forcer ce cas d'usage. Étant donné qu'un récursif-cache a vocation à avoir une majorité de stub-resolvers comme clients, la solution d'un récursif-cache répondant uniquement sur TCP n'est pas envisageable à l'heure actuelle. ÉDIT du 22/02/2015 à 13h55 : Depuis sa version 2.14, la glibc dispose de l'option « use_vc » (à utiliser dans resolv.conf, « options use_vc »). Cette option est disponible depuis Debian Jessie. OpenBSD a l'équivalent « tcp ». Les autres implémentations (FreeBSD, NetBSD, DragonFlyBSD, bionic (Android, Firefox OS), libresolv (Mac OS X), uclibc) ne disposent pas encore d'une telle option, ce qui en limite l'impact/l'intérêt. Source : Recursive DNS over TLS over TCP 443. Fin de l'édit.
  • Les utilisateurs de notre récursif-cache peuvent être dans des réseaux nazis dans lequels les administrateurs croient encore que DNS c'est uniquement udp/53 et bloquent donc le port tcp/53 (volontairement avec un pare-feu ou involontairement en utilisant des middleboxes mal-conçues). Ces réseaux ne sont pas rares ! Même sans évoquer notre cas d'usage, ces configurations poseront problèmes de toute façon et disparaîtront à terme.
  • TCP est plus lent (en cas d'absence de support des connexions TCP persistantes) et plus coûteux en ressources côté récursif-cache. Lire : Le DNS va t-il utiliser de plus en plus souvent TCP ?.

Fin de l'édit

Tester vos contre-mesures

Je n'ai pas été cherché bien loin les outils que j'ai utilisés.

Dans le lab' :

Sur la prod' :

  • Une bête boucle shell :
    for i in {1..<à adapter en fonction du seuil de la règle iptables à tester>}; do dig @<serveur v4 et v6> +short +retry=0 +time=1 ANY example.net.; [date;] done

    « time » avec une valeur d'une seconde permet de voir clairement le déclenchement d'une règle iptables. Cette simple boucle permet de vérifier que la limitation s'applique sans pour autant bourriner. Je trouve le résultat particulièrement lisible : burst puis vitesse de croisière. ÉDIT du 04/09/2014 à 21h15 : Je n'utilise pas « repeat » pour illustrer cet article car je suis un faible qui utilise bash, donc je n'ai pas cette commande pourtant built-in dans d'autres shells. Fin de l'édit

  • Une fois la vérification de l'efficacité de vos règles iptables effectuée, il vous faudra des beta testeurs pour tester en conditions réelles/normales que la limitation ne provoque pas de faux positifs.

Problèmes rencontrés

  • J'ai constaté un manque flagrant de documentation sur « comment monter un serveur DNS récursif-cache ouvert mais surveillé ». Même ceux qui le font, comme DNS-OARC ne sont pas bavards à ce sujet. Effet de dissuasion pour éviter les mauvaises manipulations et les nuisibles ? Idem, j'aimerais bien avoir des feedbacks sérieux sur quelle volumétrie de trafic "pourri" il est moralement acceptable de laisser filer sur les Internets.
  • Mettre en place un serveur DNS récursif-cache demande de la patience. Simplement car il faut du temps pour tâter le terrain, trouver les bonnes méthodes pour tenter de juguler les attaques, ajuster les paramètres du rate-limiting, obtenir des feedbacks, ... C'est un travail de longue haleine.
  • L'obtention de feedbacks est elle-même compliquée. D'abord car il est parfois difficile d'établir un lien de causalité entre un problème constaté et les mesures de limitation du trafic prises (un « could not resolve ... » est parlant mais ce n'est pas toujours ce type de message que l'on rencontre). Ensuite car les gens ne signalent pas forcément qu'ils rencontrent un problème avec le récursif (« c'est peut-être un problème temporaire ? problème de réseau ? »). En sont-ils simplement conscients ? Plusieurs entrées dans le fichier /etc/resolv.conf ou l'utilisation d'un serveur DNS forwarder en local suffisent à masquer le problème (basculement sur d'autres serveurs récursifs, cache, ...). Bref, prêtez attention à la configuration des machines de vos testeurs.

Merci à Stéphane Bortzmeyer pour sa relecture attentive, mais cela ne veut pas dire qu'il est d'accord avec tout (notamment sur mon absence d'intérêt pour une réduction de la taille max des réponses sur UDP).

DNSSEC : OpenDNSSEC, roulement de KSK et DLV

En temps normal, le roulement d'une KSK se passe bien et en douceur avec OpenDNSSEC. Ici, on va s'attarder sur le cas spécial (et inutile) où un roulement de KSK approche et que l'on souhaite quitter un modèle arborescence pour les données + arborescence séparée pour les délégations signées (DLV) pour le modèle normal et classique de DNSSEC : une seule arborescence unifiée.

Si vous débutez avec DNSSEC, je vous recommande les lectures suivantes :

Rappel : DLV permet de séparer l'arborescence qui contient les données (enregistrements NS/A/AAAA/MX/SRV/DNSKEY/RRSIG/...) de celle qui contient les délégations signées. Cela permet de créer une chaîne de confiance avec des ilôts sécurisés (zone signée dont la zone parente n'est pas signée/n'accepte pas l'ajout de délégations signées, ...) tant que l'intégralité de l'arborescence pour arriver à ces ilôts n'est pas signée et/ou n'accepte pas l'ajout de délégations signées. DLV est très peu utilisé. Il existe plusieurs dépôts DLV, le plus important étant celui de l'ISC (dlv.isc.org). Un (ou plusieurs) dépôt doit être configuré sur un récursif-cache sinon DLV n'est pas utilisé par ledit récursif-cache. Quand DLV est configuré, le récursif-cache cherche d'abord une délégation signée valide via l'arborescence classique (racine, TLD, ...). Si le résultat est négatif, il utilise les dépôts DLV configurés pour tenter de trouver une délégation signée.

Historique : au moment où j'ai voulu signer mes zones (dont guiguishow.info.), info. n'acceptait pas encore la soumission de délégations signées (enregistrements de type DS qui pointent sur la KSK de la zone) ou, en tout cas, mon bureau d'enregistrement ne me permettait pas d'effecter une demande d'ajout. Juste pour découvrir et m'amuser, j'ai alors décidé d'utiliser le registre DLV de l'ISC.

Or, depuis quelques mois, je peux enfin soumettre un enregistrement DS via l'interface de mon bureau d'enregistrement. Donc, en tout logique, je souhaite arrêter d'utiliser DLV. La première idée qui vient à l'esprit est de profiter du roulement de la KSK qui approche pour effectuer cette transition.

Pour les plus perspicaces : oui, j'ai signé mes zones (sauf une) en janvier 2013 donc le roulement de la KSK aurait du avoir lieu en janvier 2014. Sauf que le passage de Squeeze à Wheezy ne s'est pas fait en douceur : OpenDNSSEC a supprimé les clés utilisées du HSM logiciel, me forçant à un roulement de clés d'urgence.

Réfléchissons à cette idée (profiter du roulement de KSK approchant pour ne plus utiliser DLV) en regardant le schéma des états que peuvent avoir les clés dans OpenDNSSEC ainsi qu'en révisant le schéma de pré-publication qui est utilisé.

Voilà ce qui se passerait si j'abandonnais DLV durant le roulement de la KSK (j'ai pris en compte uniquement les états visibles dans les outils OpenDNSSEC ce qui exclut les états « Générated » et « Dead ») :
État « Publish » :

  • Récursifs-cache utilisant le dépôt DLV de l'ISC : aucun impact car le seul changement est que le RRset DNSKEY comporte un RR supplémentaire (la partie publique de la nouvelle clé).
  • Récursifs-cache qui n'utilisent pas DLV : aucun impact pour la même raison.

État « Ready » :

  • Récursifs-cache utilisant le dépôt DLV de l'ISC : aucun impact. OpenDNSSEC considère simplement que la nouvelle clé est présente dans suffisamment de récursifs-cache et peut donc être utilisée.
  • Récursifs-cache qui n'utilisent pas DLV : aucun impact pour la même raison.

Je demande l'ajout d'un RR DS dans la zone info. À partir du moment où il est publié :

  • Récursifs-cache utilisant le dépôt DLV de l'ISC :
    • Récursifs-cache qui ont encore des données en cache : aucun impact. L'ancienne clé est toujours présente dans la zone et elle signe toujours ladite zone et les anciennes signatures ainsi que la délégation signée sont en cache.
    • Récursifs-cache qui n'ont plus rien en cache : ils feront une nouvelle résolution sans utiliser DLV et trouveront le DS pointant sur la nouvelle clé ... qui ne signe rien alors qu'il y a des signatures dans la zone : échec. Théoriquement, ils continueront à utiliser DLV et remettront donc les données en cache.
  • Récursifs-cache qui n'utilisent pas DLV : le DS pointe sur la nouvelle clé ... qui ne signe rien alors qu'il y a des signatures dans la zone : échec. A priori aucun impact pour les récursifs-cache qui ont encore des données en cache.

État « Active » (j'indique à DNSSEC que le DS est publié) :

  • Récursifs-cache utilisant le dépôt DLV de l'ISC :
    • Récursifs-cache qui n'ont plus rien en cache : ils referont une résolution sans utiliser DLV et trouveront le DS qui pointe sur la nouvelle clé qui signe la ZSK qui signe la zone : tout va bien.
    • Récursifs-cache qui ont obtenus des données entre la publication du DS et le passage à l'état « active » : ils ont toujours le bon DS et les anciennes signatures en cache : échec. Ils peuvent utiliser DLV tant qu'un élément de la chaîne de confiance n'est pas brisée dans leur cache (l'enregistrement DLV pointe désormais sur l'ancienne KSK qui ne signe plus rien).
  • Récursifs-cache qui n'utilisent pas DLV :
    • Récursifs-cache qui ont obtenus des données entre la publication du DS et le passage à l'état « active » : ils ont toujours le bon DS qui pointent sur la nouvelle KSK qui ne signe rien (ancienne signature du RRset DNSKEY) : échec.
    • Récursifs-cache qui n'ont plus rien en cache : le DS pointe sur la nouvelle clé qui signe la ZSK qui signe la zone : tout va bien.

Bien sûr, la période de temps entre le moment où la délégation signée est publiée dans la zone parente et le moment où on indique cette publication à OpenDNSSEC est plus ou moins grande en fonction de ma réactivité/disponibilité. Ce qui implique que le trouble que je décris durera plus ou moins longtemps.

Pour que l'analyse soit complète, il faudrait tenir compte du fait que le cache d'un récursif n'est pas tout vide ou tout plein pour un même domaine : toutes les données (délégation dans la zone parente, signatures, ...) n'expirent pas en même temps (TTL différents). Ça augmente les combinaisons possibles.

Néanmoins, la documentation d'OpenDNSSEC (ainsi que le man ods-ksmutil) nous conseille de ne pas changer les paramètres d'une politique de signature notamment les délais de "propagation" (terme pas vraiment correct car il induit en erreur sur la réalité du processus) pendant qu'un roulement de clés est en cours. Ce qui est logique. Je ne souhaite pas changer les délais de propagation mais je vais changer les TTL (DS/SOA de la zone parente) car ils sont utilisés par OpenDNSSEC pour affiner ses calculs.

En conséquence, soit je fais ce changement de politique pour ma zone avant le roulement ou après. Avant, ça ne convient pas si je laisse une délégation dans le registre DLV car la politique ne sera donc plus adaptée à la zone parente. Après, ça me semble un peu tard notamment car les calculs pour le roulement seront légèrement "faussés".

Une méthode beaucoup plus simple est d'ajouter une délégation signée dans la zone parente (info) qui pointe sur la KSK actuelle, avant le roulement. Les récursifs-cache qui utilisent DLV et ont des données en cache continueront à valider puis, à expiration des TTL, n'utiliseront plus DLV mais pourrons toujours valider les signatures. Les récursifs-caches qui n'utilisent pas DLV et qui ont des données en cache, continueront à ne pas valider, puis, à expiration des TTL, valideront les signatures. De plus, le roulement de la KSK tombera dans le cas général qui est très bien pris en charge par OpenDNSSEC.

Les étapes sont donc de se débarrasser de DLV puis de modifier la politique de signature utilisée par OpenDNSSEC pour la zone. J'ai fait ça le week-end du 10 mai pour un roulement de clé planifié pour le 19-20 mai 2014.

Pour la première étape, il suffit de demander la publication d'un enregistrement DS dans info. La prise en compte au plus tard par les récursifs sera : maintenant + temps de publication (moins de 15 minutes dans mon cas) + 3600 secondes (1h). Cela correspond au cache négatif dans info. (ça concerne tous les récursifs-cache, qu'ils utilisent DLV ou non) et au TTL des enregistrements DLV dans le dépôt DLV de l'ISC (ça concerne les récursifs-cache qui utilisent ce dépôt).

Après quelques temps (au bout d'une heure ça devrait être plié mais j'ai attendu 2 jours, sans raison), on pourra supprimer notre délégation du dépôt de l'ISC.

Pour la deuxième étape, il faut d'abord ajouter une politique dans le fichier de configuration « kasp.xml » d'OpenDNSSEC. J'ai simplement copié/collé la politique qui s'applique à toutes mes zones qui ont une délégation signée dans le dépôt DLV de l'ISC et j'ai changé les paramètres relatifs à la zone parente.

On synchronise le contenu de ce fichier avec la base de données d'OpenDNSSEC :

ods-ksmutil update kasp
zonelist filename set to /etc/opendnssec/zonelist.xml.
kasp filename set to /etc/opendnssec/kasp.xml.
Policy guiguishow found
Info: converting P1Y to seconds; M interpreted as 31 days, Y interpreted as 365 days

On modifie ensuite le fichier zonelist.xml pour changer la politique associée à la zone par la nouvelle politique.

On synchronise le contenu de ce fichier avec la base de données d'OpenDNSSEC :

ods-ksmutil update zonelist
zonelist filename set to /etc/opendnssec/zonelist.xml.
kasp filename set to /etc/opendnssec/kasp.xml.
Zone guiguishow.info found
Policy set to guiguishow.

On vérifie que le changement a bien été pris en compte.
Avant :

ods-ksmutil zone list
zonelist filename set to /etc/opendnssec/zonelist.xml.
Found Zone: guiguishow.info; on policy dlv

Après :

ods-ksmutil zone list
zonelist filename set to /etc/opendnssec/zonelist.xml.
Found Zone: guiguishow.info; on policy guiguishow

On utilise aussi la commande « ods-ksmutil key list » pour vérifier qu'on n'a pas fait d'erreur et que nos clés sont toujours là (même si la doc indique que la commande « update » ne touche pas aux clés).

Au moment venu du roulement de la KSK, on est tranquille, on laisse OpenDNSSEC faire le taff, on demande la publication d'un nouveau DS dans la zone parente quand il nous le demande (état « ready ») et c'est tout.

DNS : glue records, net/com/org et error 2003

Aujourd'hui, je vais vous parler des glue records et notamment des cas où il faut les utiliser alors que ça ne correspond pas à la définition première que l'on se fait d'un glue record.

Je trouve que c'est assez peu documenté et très peu connu. J'ai découvert ça très récemment, alors que je configurais les serveurs de noms qui font autorité sur arn-fai.net (appartenant à ARN, FAI associatif alsacien). Je n'avais jamais eu un nom de domaine sous un TLD concerné par cette exception ni utilisé un autre secondaire pour faire autorité sur mes zones que celui proposé par mon bureau d'enregistrement, ceci explique peut-être cela.

Pour aborder sereinement ce billet, il faut avoir une petite idée du processus de résolution d'un nom par le DNS ainsi de ce qu'est un glue record (en fin de section) quand on cause de noms de domaine et de comment ça se mange.

Vous avez un nom de domaine sous les TLD net, com ou org. Vous voulez qu'un deuxième serveur fasse autorité sur votre zone. Le nom de ce serveur est aussi sous com, net ou org. Alors, vous devez déclarer un (ou plusieurs) glue record pour ce deuxième serveur via le bureau d'enregistrement via lequel le deuxième nom de domaine a été obtenu.

Si vous ne le faites pas, le registre (Verisign pour com/net, Afilias pour la gestion technique de org) vous retournera l'erreur « error : 2003 required parameter missing » lors de la déclaration des nouveaux serveurs faisant autorité sur l'interface web de votre bureau d'enregistrement.

Quelques exemples concrets :

  • On veut que la machine désignée par le nom alsace.tetaneutral.net. soit le deuxième serveur qui fait autorité sur arn-fai.net. Il faut donc que Tetaneutral.net ajoute des glue records (A/AAAA) pour alsace.tetaneutral.net. via son bureau d'enregistrement (Gandi).
  • On veut que les machines désignées par les noms (ns0|ns1).fdn.org soient les serveurs qui font autorité sur ffdn.org. Il faudra donc que FDN ajoute des glue records pour les noms (ns0|ns1).fdn.org.
  • Un enregistrement associant une IPv4 au nom ns6.gandi.net. (type A) est déclaré dans la zone net. C'est un glue record et il permet aux clients de Gandi qui achètent un nom de domaine dans net/com/org de déclarer la machine pointée comme étant un serveur faisant autorité sur leur domaine.

On peut trouver une autre illustration concrète ici : Soit disant glue records - Gandi.net Groups.

Vous allez me dire : « cet usage des glue records est un usage dérivé de la définition puisqu'un glue record sert normalement à casser une référence circulaire comme « A ns0.arn-fai.net ? » -> « je sais pas, demande à ns0.arn-fai.net qui fait autorité sur arn-fai.net ». Oui, on peut voir ça comme un usage dérivé dans le sens où on ne s'en sert pas pour casser une référence circulaire mais ça reste le même principe de fonctionnement fondamental : faire remonter une information dans la zone parente. Une information qui sera, de ce fait, hors zone.

Le seul intérêt que je vois à cette manipulation, c'est que cela permet de réduire la charge sur les serveurs qui font autorité sur net/com/org. Cela évite un échange supplémentaire. J'imagine que cela procurait un bénéfice vu les caractéristiques (latence surtout) des réseaux de l'époque bien que je ne comprends pas pourquoi certains TLD créés à l'époque (exemple : fr) ont fait un choix technique différent ...

Pour illustrer le gain d'un glue record dans le cas qui nous intéresse, imaginons un dialogue approximatif entre un récursif-cache et les serveurs qui font autorité sur net/com (ça serait pareil pour org).

D'abord, sans glue record (évidemment, on suppose qu'on a vidé le cache du récursif-cache pour les noms concernés ...) :

  • A xxx.arn-fai.net. ?
  • je ne sais pas, va voir ns0.arn-fai.net. qui a telle IP et alsace.tetaneutral.net.. Ils font autorité sur arn-fai.net.
  • ...
  • (ici, ns0.arn-fai.net ne répond pas/pas assez vite ou le récursif-cache veut mettre en cache alsace.tetaneutral.net pour plus tard au cas où, donc le récursif-cache veut interroger alsace.tetaneutral.net) : « A alsace.tetaneutral.net. ? »
  • « je ne sais pas, va voir ns0.tetaneutral.net. qui a telle IP et qui aura la réponse car il fait autorité sur tetaneutral.net. »
  • ...

Maintenant, avec un glue record (évidemment, on suppose qu'on a vidé le cache du récursif-cache pour les noms concernés ...) :

  • A xxx.arn-fai.net. ?
  • je ne sais pas, va voir ns0.arn-fai.net. qui a telle IP et alsace.tetaneutral.net. qui a telle autre IP. Ils auront la réponse car ils font autorité sur arn-fai.net.
  • ...

Notons que cela concerne uniquement les noms de domaine qui se trouvent sous un TLD dont le registre est (ou fut) Verisign. Donc net, com et org. Le registre de org est, aujourd'hui, Public Interest Registry (avec une sous-traitance à Afilias pour la partie technique) mais fut un temps, Verisign était bien le registre de org. Pour les autres TLD, il n'est pas nécessaire d'ajouter un glue record. Par exemple, je peux très bien dire :

  • un des serveurs qui fait autorité sur mazone.fr, c'est ns0.monautrezone.fr.
  • un des serveurs qui fait autorité sur mazone.info, c'est bidule.monautrezone.info.
  • ...

De quand date ce principe de fonctionnement ? De l'époque (année 2000) où Verisign a acheté Network Solutions ? De l'époque "purement" Network Solutions (1991-2000) ? De quelques années auparavant ? Je n'en ai aucune idée mais ça m'intéresse. 😉

Vous allez me dire « non mais pourquoi s'embêter avec ton histoire de glue records ... regardes, pour alsace.tetaneutral.net par exemple, il suffit de créer un enregistrement « arn-fai.net. NS vmttnn.arn-fai.net. », d'ajouter les bons enregistrements de types A/AAAA pour le nom vmttnn.arn-fai.net ainsi que d'ajouter les glue records pour ce nom et on peut très bien déclarer vmttn.arn-fai.net comme étant un serveur qui fait autorité sur arn-fai.net. ». Oui, ça marche aussi et c'est parfaitement valide.

Mais si Tetaneutral.net décide de renuméroter tout ou partie de son réseau, ARN doit être informé et modifier les valeurs des enregistrements vmttnn.arn-fai.net de types A/AAAA ainsi que les valeurs des glue records. Avec les glue records du côté de Tetaneutral.net (alsace.tetaneutral.net.), ARN n'a rien à faire. Si, à cet instant, vous avez pensé à déclarer vmttnn.arn-fai.net. comme un alias (CNAME) vers alsace.tetaneutral.net., vous avez perdu : on ne doit pas mettre un alias en valeur d'un enregistrement de type MX ou NS. C'est indiqué dans la section 10.3 du RFC 2181.

Comment voir un glue record ? C'est une information additionnelle, qui sera envoyée, par un serveur qui fait autorité, uniquement en complément d'une réponse contenant une délégation. Dans ce cas, le serveur qui fait autorité ajoutera le ou les enregistrements "glue" dans la section « additional » de sa réponse.

Exemple : l'enregistrement alsace.tetaneutral.net. de type A sera envoyé, par les serveurs qui font autorité sur net, uniquement en complément d'une réponse contenant un enregistrement NS avec la valeur alsace.tetaneutral.net. Dans notre cas, la seule question susceptible de générer cette réponse est « NS arn-fai.net. ? ». Donc la commande suivante permet de voir les glue records dans la section additionnelle : « dig @a.gtld-servers.net. NS arn-fai.net. ».

Évidemment, si alsace.tetaneutral.net est aussi déclaré comme serveur public[1] faisant autorité sur d'autres domaines, une requête « dig @a.gtld-servers.net. NS domaine.exemple. » affichera tout aussi bien les enregistrements dits "glue".

J'espère avoir réussi à documenter quelques points obscurs en étant clair et accessible.

[1] Oui, on n'est pas obligé de déclarer tous les serveurs faisant autorité sur un domaine dans des enregistrements de type NS. Cela sert notamment pour mettre en place un master "caché" (fin de section) pour, par exemple, signer hors-ligne une zone (DNSSEC) ou pour réserver des slaves qui seront seulement interrogés par les machines internes à l'organisation (association, entreprise, ...) qui possède le nom de domaine (voir : Conférence Mail/DNS à partir de 1h25m50).

DNAME

Aujourd'hui, on va parler d'un type d'enregistrement DNS : DNAME. Je connaissais ce type d'enregistrement mais je n'avais jamais eu l'occasion de l'utiliser autrement que pour un test bidon. Comme l'occasion s'est présentée récemment, je voulais faire un petit feedback. En conséquence, je vais être assez léger. Pour creuser le sujet, il faudra aller voir sur le blog de Stéphane Bortzmeyer (j'égrène les bons liens au long de ce billet).

Qu'est ce que c'est ?

Delegation Name (DNAME) est un type d'enregistrement DNS défini dans le RFC 6672 (l'original 2672 étant obsolète) qui permet de donner un alias, un synonyme à l'intégralité d'un sous-arbre dans la hiérarchie du DNS. Avec DNAME, le nom lui-même reste inchangé et n'est pas redirigé. En comparaison, le type CNAME permet de créer un alias 1 vers 1 : un unique nom pointe sur un autre. Le sous-arbre du nom aliasé reste inchangé. En gros, mettre un DNAME sur un nom produira le même résultat que de mettre des CNAME sur chacun des sous-noms possibles.

Exemple : mycorporation.example. DNAME ultimatecorporation.example.

www.mycorporation.example. pointe sur www.ultimatecorporation.example. Si ce dernier nom existe, une requête sur www.mycorporation.example produira un résultat. NXDOMAIN dans le cas contraire.

En admettant que le nom ultimatecorporation.example. existe en type AAAA (IPv6), que donnera une demande dig AAAA mycorporation.example. ? Aucun résultat. 🙂 Le nom n'existe pas dans le type demandé. Si vous êtes tombé dans le piège, relisez bien la définition : un DNAME permet de donner un alias à un sous arbre, pas au nom lui-même. Pour résoudre ce problème :

  • n'espérez pas d'ajouter un enregistrement de type CNAME pour mycorporation.example. CNAME ne se combine avec aucun autre type (exception faite des types relatifs à DNSSEC comme RSSIG) !
  • dupliquer l'information. Dans notre cas : dupliquer le type AAAA pour les deux noms (ultimatecorporation.example. et mycorporation.example.). Ce n'est pas un alias : une éventuelle modification devra être faite pour les deux noms !
  • on pourra, peut-être, utiliser un futur nouveau type, comme BNAME ou SHADOW, tous deux proposés à l'IETF, qui permettent de combiner CNAME et DNAME : on crée un alias pour un nom et pour le sous-arbre de ce nom.

À quoi ça sert ?

Le DNAME peut-être utilisé dans les cas suivants :

  • Lorsqu'une même organisation (ou personne) enregistre son nom ou celui d'une de ses marques dans plusieurs voire tous les TLD existants. Le DNAME permet de faire pointer chaque sous-arbre vers un seul sous-arbre. Seul ce dernier devra être maintenu.
  • Lors d'une rachat ou d'une fusion d'entreprises. Pour présenter le DNAME, Stéphane Bortzmeyer utilise le renommage de Vivendi Environnement en Veolia Environnement.
  • Pour les noms de domaine en unicode (IDN). DNAME est utilisé, par exemple, dans le TLD cat.

Limites

Comme le DNAME permet uniquement de donner un alias à un sous-arbre, cela peut être gênant en fonction de l'implémentation de certains scénarios. Par exemple : sous le TLD .cat, lors de l'enregistrement d'un nom IDN, le nom ASCII est aussi réservé et un DNAME redirige le sous-arbre IDN vers le sous-arbre ASCII. Cela signifie que je ne pourrais jamais envoyer de mails à destination du domaine caballè.cat. : ce FQDN est de type DNAME donc seul le sous-arbre est aliasé ! Pas de MX, pas de SRV (XMPP par exemple), pas même de A/AAAA (si pas de MX/SRV, les serveurs de mail/jabber cherchent un A/AAAA). Le mieux serait de déléguer les deux noms (IDN/ASCII) au titulaire et libre à lui d'utiliser DNAME ou pas en complément d'une duplication des type A/AAAA/MX/SRV/SPF/ pour l'apex. C'est d'ailleurs comme cela que procède DotAsia, le registre de asia. .

Comme l'utilisation de DNAME conduit à la synthèse de CNAME, cela signifie qu'il est possible d'avoir des chaînes de CNAME qui sont, normalement, déconseillées. Exemple : si l'on a www.ultimatecorporation.example. CNAME web.ultimatecorporation.example., alors dig A www.mycorporation.example générera la réponse suivante :

mycorporation.example.                  3600	IN	DNAME	ultimatecorporation.example.
www.mycorporation.example.	        0	IN	CNAME	www.ultimatecorporation.example.
www.ultimatecorporation.example.	3600	IN	CNAME	web.ultimatecorporation.example.
web.ultimatecorporation.example.	3600	IN	A	192.0.2.1

Le DNAME est fortement méconnu car, pour les deux usages sur les trois cités plus haut, il peut être remplacé par un fichier de zone avec des noms relatifs et des liens symboliques vers ce fichier pour toutes les zones identiques. La seule limite de cette méthode est la consommation mémoire : au chargement des zones, le serveur duplique les données pour obtenir un exemplaire par zone chargée (alors que les RDATA sont identiques). Cela pose problème pour les cas d'usages où l'on a beaucoup de zones identiques comme les IDN et les variantes.

Mettre en œuvre

DNS

Rien de spécial : c'est un type d'enregistrement, rien de plus.

Si vous avez deux domaines, savoir si vous allez vous les faire déléguer et mettre un DNAME dans le fichier de zone de l'un ou si vous allez demander à l'un des domaines parent de mettre le DNAME directement dans son fichier de zone à lui est un pur choix de votre part (le premier suppose de dupliquer l'apex, le second que vous n'aurez ni mail ni XMPP ni ... sur le domaine lui-même) et en fonction de votre domaine parent (inutile de demander ça à un gTLD/ccTLD hein, je dis ça pour ceux qui obtiennent des domaines via des potes 😉 ).

Postfix

On suppose que le serveur est configuré pour traiter les mails au départ/à destination du domaine mycorporation.example. On veut aussi qu'il s'occupe du nouveau domaine équivalent ultimatecorporation.example.. Pour l'identification, j'utilise SASL.

J'utilise les directives « virtual_alias_domains » et « virtual_alias_maps » :

virtual_alias_domains = ultimatecorporation.example
virtual_alias_maps = hash:/etc/postfix/virtual_aliases

/etc/postfix/virtual_aliases contient :

@ultimatecorporation.example        @mycorporation.example

Les mails adressés à guigui@ultimatecorporation.example seront redirigés vers guigui@mycorporation.example et delivrés si cette boîte existe.

Pour pouvoir envoyer des mails avec une adresse @ultimatecorporation.example, il suffit de rajouter une entrée dans une table passée en argument de « smtpd_sender_login_maps ». Exemple ici avec ce qui deviendra une hashmap :

guigui@ultimatecorporation.example        guigui@mycorporation.example

ejabberd

Il suffit simplement d'ajouter le nouveau nom dans la directive « hosts » comme le montre l'exemple commenté dans le fichier de configuration :

{hosts, ["mycorporation.example", "ultimatecorporation.example"]}