DNS en production avec BIND 9 et Unbound
Quitter

Leçon 1 sur 12 · Résolution et outils

La résolution vue de l'intérieur : renvois, glue, cache positif et négatif

45 min Debian 12 Versions BIND 9.18, BIND 9.20, Unbound 1.17+

Objectif

Savoir lire ce que fait un résolveur entre la question du poste et la réponse finale, pour reconnaître au premier coup d'œil un renvoi, une réponse faisant autorité, une réponse sortie du cache ou une réponse négative. C'est la base de tout dépannage DNS sérieux.

L'essentiel

  • Le poste pose une question récursive à son résolveur ; le résolveur pose des questions non récursives aux serveurs faisant autorité et suit les renvois (referrals).
  • Un renvoi = pas de réponse, pas de drapeau aa, des NS dans la section AUTHORITY et souvent leurs adresses (glue) dans ADDITIONAL.
  • La glue est obligatoire quand le serveur de noms porte un nom à l'intérieur de la zone qu'il sert (ns1.fes.masterlinux.lab pour fes.masterlinux.lab).
  • Le cache garde aussi les réponses négatives (NXDOMAIN, NODATA) pendant le TTL du SOA renvoyé, plafonné par le dernier champ du SOA.
  • Une réponse UDP trop grosse est tronquée (drapeau tc) et le client recommence en TCP : le port 53/TCP doit être ouvert.

1. Deux métiers, deux types de questions

Le cours « Réseaux et VPN » a présenté le résolveur et le serveur faisant autorité. Regardons maintenant les paquets qu'ils échangent.

Question Envoyée par Bit rd (recursion desired) Ce qu'on attend
récursive le poste, vers son résolveur 1 la réponse finale (ou une erreur)
itérative le résolveur, vers les serveurs faisant autorité 0 une réponse ou un renvoi

Avec dig, on reproduit la question d'un résolveur en coupant la récursion :

dig @10.20.0.53 www.fes.masterlinux.lab +norec    # comme le ferait un résolveur
dig @10.20.0.10 www.fes.masterlinux.lab           # comme le ferait un poste (rd=1)

Un serveur faisant autorité bien configuré refuse la récursion : il répond avec status: REFUSED (ou sans drapeau ra) quand on lui demande un nom qui n'est pas dans ses zones. Un serveur qui accepte la récursion pour tout Internet est un résolveur ouvert, donc un amplificateur d'attaques.

2. Le renvoi et la glue

L'agence MasterLinux de Fès a sa propre sous-zone, fes.masterlinux.lab, gérée par ses serveurs ns1.fes et ns2.fes. Le serveur de la zone mère (ml-dns-01, 10.20.0.53) ne connaît pas www.fes.masterlinux.lab, mais il sait à qui demander :

;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 3
;; AUTHORITY SECTION:
fes.masterlinux.lab.     86400 IN NS ns1.fes.masterlinux.lab.
fes.masterlinux.lab.     86400 IN NS ns2.fes.masterlinux.lab.
;; ADDITIONAL SECTION:
ns1.fes.masterlinux.lab. 86400 IN A  10.30.0.53
ns2.fes.masterlinux.lab. 86400 IN A  10.30.0.54

Trois indices disent « renvoi » : ANSWER: 0, pas de drapeau aa, des NS d'une zone plus précise que celle du serveur.

Sans les deux lignes de ADDITIONAL, le résolveur serait coincé : pour joindre ns1.fes.masterlinux.lab, il faudrait demander… à ns1.fes.masterlinux.lab. Ces adresses, écrites dans la zone mère, s'appellent la glue. Elles ne sont nécessaires que si le nom du serveur est sous la zone déléguée ; avec un serveur ns.hebergeur.ma, le résolveur résout ce nom séparément.

Dans la zone mère, la délégation s'écrit ainsi :

; db.masterlinux.lab (zone mère)
fes        IN NS  ns1.fes.masterlinux.lab.
fes        IN NS  ns2.fes.masterlinux.lab.
ns1.fes    IN A   10.30.0.53      ; glue
ns2.fes    IN A   10.30.0.54      ; glue

La zone fille doit publier les mêmes NS dans son propre fichier. Quand les deux listes divergent, certains résolveurs suivent la mère, d'autres la fille : on obtient des pannes intermittentes difficiles à reproduire. On vérifie avec :

dig @10.20.0.53 fes.masterlinux.lab NS +norec   # ce que dit la mère (renvoi)
dig @10.30.0.53 fes.masterlinux.lab NS +norec   # ce que dit la fille (aa)

3. Le chemin complet, avec minimisation

Sur Internet, la chaîne commence aux serveurs racine. Les résolveurs récents (BIND 9.18+, Unbound) pratiquent la minimisation des questions (QNAME minimisation) : à la racine, ils demandent seulement NS ma. et non le nom complet www.boutique.exemple.ma. ; chaque serveur ne voit que ce dont il a besoin.

résolveur ──NS ma.?────────────► racine        ── renvoi vers les serveurs de .ma
résolveur ──NS exemple.ma.?────► serveurs .ma  ── renvoi vers ns1.exemple.ma
résolveur ──A www.exemple.ma.?─► ns1.exemple.ma ── réponse, drapeau aa

Conséquence pratique : un serveur faisant autorité mal codé qui répond mal aux questions sur des noms intermédiaires (ou à un type qu'il ne connaît pas) casse la résolution seulement chez les résolveurs modernes. Dans BIND, l'option qname-minimization relaxed; (valeur par défaut) se rabat sur l'ancien comportement en cas de souci.

4. Le cache positif : le TTL qui descend

Le résolveur garde chaque réponse le temps du TTL. Quand il la ressert, il indique le TTL restant :

;; flags: qr rd ra; ANSWER: 1
www.fes.masterlinux.lab. 2712 IN A 10.30.1.80
  • Pas de aa : la réponse vient d'un cache.
  • La zone publie un TTL de 3600 ; il en reste 2712 : la réponse est en cache depuis 888 secondes.
  • Relancez la commande : le chiffre baisse. S'il revient à 3600, le résolveur vient d'aller la rechercher.

Deux réglages côté résolveur faussent ce calcul : max-cache-ttl (BIND) ou cache-max-ttl (Unbound) plafonnent les TTL trop longs, et cache-min-ttl (Unbound) les relève. Relever les TTL fait gagner un peu de trafic, mais une migration ne se propage plus à la vitesse que l'équipe attend : à éviter.

5. Le cache négatif : NXDOMAIN et NODATA

Il existe deux réponses négatives, à ne pas confondre :

Cas status ANSWER Signification
NXDOMAIN NXDOMAIN 0 le nom n'existe pas, pour aucun type
NODATA NOERROR 0 le nom existe, mais pas ce type (ex. pas d'AAAA)

Dans les deux cas, le serveur joint le SOA de la zone dans AUTHORITY. Le résolveur garde la réponse négative le temps du TTL de ce SOA, qui ne dépasse jamais le dernier champ du SOA (le « minimum », qui a changé de sens au fil des années pour devenir la durée du cache négatif) :

masterlinux.lab. 300 IN SOA ns1.masterlinux.lab. hostmaster.masterlinux.lab. 2026102001 3600 900 1209600 300
                 ^^^                                                                                  ^^^
          TTL du cache négatif                                                    plafond du cache négatif

Cas réel : l'équipe crée paiement.masterlinux.lab à 10 h 00. Un développeur l'avait testé à 9 h 58 et reçu NXDOMAIN. Avec un dernier champ de SOA à 86400, son résolveur répond « n'existe pas » jusqu'au lendemain. Gardez ce champ entre 300 et 3600 secondes, et videz le cache en urgence (rndc flushname paiement.masterlinux.lab sur BIND, unbound-control flush paiement.masterlinux.lab sur Unbound).

6. SERVFAIL : le résolveur abandonne

SERVFAIL venant d'un résolveur veut dire « je n'ai pas pu obtenir de réponse fiable » : tous les serveurs faisant autorité sont injoignables, la délégation est cassée, ou la validation DNSSEC a échoué. Le résolveur met aussi ce résultat en cache quelques secondes (servfail-ttl dans BIND, 1 s par défaut) pour ne pas s'acharner.

Pour savoir lequel, interrogez directement les serveurs faisant autorité avec +norec, puis relancez avec +cd (checking disabled) : si +cd fonctionne, c'est DNSSEC (leçon 3.2).

7. EDNS, taille des réponses et TCP

Le DNS « historique » limitait les réponses UDP à 512 octets. EDNS(0) permet d'annoncer une taille plus grande. Depuis le DNS Flag Day de 2020, la valeur recommandée est 1232 octets : au-delà, les paquets risquent d'être fragmentés, et les fragments sont souvent perdus ou filtrés.

dig @10.20.0.53 masterlinux.lab DNSKEY +dnssec +bufsize=1232
# ;; flags: qr aa tc ...      <- tc : tronquée, dig recommence en TCP tout seul
dig @10.20.0.53 masterlinux.lab DNSKEY +dnssec +tcp     # forcer TCP

Un pare-feu qui ne laisse passer que 53/UDP casse les grosses réponses (DNSSEC, longues listes TXT) et les transferts de zone : ouvrez toujours 53/UDP et 53/TCP.

8. Le résolveur local du poste (stub)

Côté poste, la bibliothèque C lit /etc/resolv.conf :

nameserver 10.20.0.10              # jusqu'à 3 serveurs, essayés dans l'ordre
nameserver 10.20.0.11
search fes.masterlinux.lab masterlinux.lab   # suffixes ajoutés aux noms courts
options timeout:2 attempts:2 rotate
  • timeout:2 : 2 secondes d'attente par serveur (5 par défaut, interminable quand le premier est en panne).
  • attempts:2 : nombre de tours complets de la liste.
  • rotate : répartit les questions entre les serveurs au lieu de toujours commencer par le premier.
  • ndots:n : un nom qui contient moins de n points est d'abord essayé avec les suffixes de search. Kubernetes met ndots:5 : un appel à api.exemple.ma génère alors plusieurs questions inutiles avant la bonne. Écrire le nom avec un point final (api.exemple.ma.) l'évite.

Sur Ubuntu et les systèmes avec systemd-resolved, /etc/resolv.conf pointe vers 127.0.0.53 : les vrais serveurs se lisent avec resolvectl status. Sur Rocky, NetworkManager réécrit ce fichier à partir de la connexion (nmcli con mod … ipv4.dns).

Selon la version

Point BIND 9.16 (Rocky 9, paquet bind) BIND 9.18 (Debian 12, Ubuntu 24.04, paquet bind9.18 sur Rocky 9) BIND 9.20 (Debian 13)
Minimisation des questions relaxed par défaut relaxed par défaut relaxed par défaut
Taille EDNS annoncée par défaut 1232 1232 1232
Réponses périmées (serve-stale) possibles, désactivées possibles, désactivées possibles, désactivées

Pièges fréquents

  • Lire un TTL de résolveur comme celui de la zone : c'est un TTL restant. Interrogez le serveur faisant autorité (+norec) pour lire la vraie valeur.
  • Confondre NXDOMAIN et NODATA : « pas d'AAAA » n'est pas « le nom n'existe pas ». Un enregistrement A qui marche avec un AAAA absent est normal.
  • Dernier champ du SOA trop grand : un nom créé « trop tard » reste introuvable des heures.
  • 53/TCP fermé : tout marche… sauf DNSSEC, les grosses réponses et les transferts.

Lab

Vous recevez des captures dig faites sur le réseau MasterLinux. Vous allez reconnaître un renvoi et sa glue, calculer depuis quand une réponse est en cache, classer des réponses négatives et écrire le resolv.conf des serveurs de l'agence de Fès.

Quiz

  1. À quels trois indices reconnaît-on un renvoi dans la sortie de dig ?
  2. Quand la glue est-elle indispensable ?
  3. Quelle différence entre NXDOMAIN et NODATA ?
  4. Combien de temps une réponse négative reste-t-elle en cache ?
  5. Pourquoi faut-il ouvrir 53/TCP sur un pare-feu ?
Réponses
  1. Aucune réponse (ANSWER: 0), pas de drapeau aa, des enregistrements NS d'une zone plus précise dans AUTHORITY.
  2. Quand le nom du serveur de noms est à l'intérieur de la zone déléguée (ns1.fes.masterlinux.lab pour fes.masterlinux.lab).
  3. NXDOMAIN : le nom n'existe pas du tout. NODATA : le nom existe mais n'a pas d'enregistrement du type demandé (status: NOERROR, réponse vide).
  4. Le TTL du SOA joint à la réponse, qui ne dépasse jamais le dernier champ du SOA.
  5. Les réponses tronquées (drapeau tc), DNSSEC et les transferts de zone passent par TCP.

Exercices pratiques

À réaliser sur Debian 12

Faites ce lab sur votre machine

Le terminal, c’est le vôtre : une VM Linux (VirtualBox, VMware, Hyper-V, WSL…) ou Docker/Podman. L’outil ml prépare l’exercice et corrige votre travail ; la leçon se valide toute seule ici.

Créez un compte gratuit pour obtenir votre commande personnelle et faire valider vos labs automatiquement.

Créer mon compte

Tâches à réaliser

  1. Analysez /root/captures/renvoi.txt (une réponse du serveur de la zone mère). Dans /root/analyse/reponses.txt, écrivez deux lignes : zone_deleguee=… (le nom de la sous-zone déléguée) et glue_ns1=… (l'adresse fournie pour ns1 de cette sous-zone).
    Afficher un indicePas de drapeau aa, pas de réponse, mais des NS dans AUTHORITY : c'est un renvoi. Les adresses de ADDITIONAL sont la glue.
    Voir la solution
    mkdir -p /root/analyse && printf '%s\n' 'zone_deleguee=fes.masterlinux.lab' 'glue_ns1=10.30.0.53' >> /root/analyse/reponses.txt

    Vérification : f=/root/analyse/reponses.txt; grep -qx 'zone_deleguee=fes.masterlinux.lab' $f && grep -qx 'glue_ns1=10.30.0.53' $f

  2. Dans /root/captures/cache.txt, le résolveur répond depuis son cache. Ajoutez à /root/analyse/reponses.txt la ligne ecoule=… : le nombre de secondes écoulées depuis que la réponse est entrée dans le cache.
    Afficher un indiceLe TTL affiché par un résolveur est le TTL restant. TTL d'origine moins TTL restant.
    Voir la solution
    mkdir -p /root/analyse && echo ecoule=888 >> /root/analyse/reponses.txt

    Vérification : grep -qx 'ecoule=888' /root/analyse/reponses.txt

  3. Classez les trois captures a.txt, b.txt et c.txt. Ajoutez à /root/analyse/reponses.txt : autoritaire=… (la lettre de la réponse donnée par le serveur qui détient la zone), nodata=… (la lettre de la réponse « le nom existe mais pas ce type ») et negatif=… (la durée, en secondes, pendant laquelle un résolveur peut garder en cache la réponse de a.txt).
    Afficher un indiceCherchez le drapeau aa ; NOERROR avec ANSWER: 0 = NODATA ; le cache négatif dure le TTL du SOA renvoyé dans AUTHORITY.
    Voir la solution
    mkdir -p /root/analyse && printf '%s\n' 'autoritaire=a' 'nodata=c' 'negatif=300' >> /root/analyse/reponses.txt

    Vérification : f=/root/analyse/reponses.txt; grep -qx 'autoritaire=a' $f && grep -qx 'nodata=c' $f && grep -qx 'negatif=300' $f

  4. Préparez le fichier /root/analyse/resolv.conf des serveurs de l'agence de Fès : deux résolveurs (nameserver 10.20.0.10 puis nameserver 10.20.0.11), la recherche « search fes.masterlinux.lab masterlinux.lab » et la ligne « options timeout:2 attempts:2 rotate ».
    Afficher un indiceQuatre lignes, dans cet ordre : nameserver, nameserver, search, options.
    Voir la solution
    mkdir -p /root/analyse && printf '%s\n' 'nameserver 10.20.0.10' 'nameserver 10.20.0.11' 'search fes.masterlinux.lab masterlinux.lab' 'options timeout:2 attempts:2 rotate' > /root/analyse/resolv.conf

    Vérification : f=/root/analyse/resolv.conf; [ "$(grep '^nameserver' $f | tr -s ' ' | paste -sd, -)" = "nameserver 10.20.0.10,nameserver 10.20.0.11" ] && grep -Eqx 'search +fes\.masterlinux\.lab +masterlinux\.lab' $f && grep -Eq '^options .*timeout:2' $f && grep -Eq '^options .*attempts:2' $f && grep -Eq '^options .*rotate' $f