Des articles approfondis sur les technologies qui façonnent l'avenir.

La configuration DNS casse encore en production

Le DNS semble simple jusqu'à la panne : mises à jour d'OS, resolv.conf, mDNS et TLD .internal causent des incidents imprévus en production.

Lettres envoyées par erreur dans les mauvais tubes pneumatiques dans une salle de tri

La dernière version de macOS d'Apple a cassé les réglages DNS personnalisés de milliers de développeurs. Plus précisément, elle a commencé à intercepter les requêtes pour le TLD .internal — que beaucoup d'entreprises utilisent pour leurs ressources réseau privées — et à les router vers mDNS (multicast DNS) au lieu du résolveur DNS configuré. Des services qui fonctionnaient sans problème depuis des années sont soudain devenus injoignables. La solution n'était pas évidente. Les messages d'erreur n'aidaient pas. Et comme souvent avec les problèmes DNS, les symptômes ressemblaient à tout sauf au DNS.

Cette histoire parle de la configuration DNS, un sujet que tout développeur rencontre, que peu comprennent vraiment et que tout le monde sous-estime jusqu'au moment où il casse quelque chose en production à 2 h du matin.

L'incident du TLD .internal

De nombreuses organisations utilisent .internal comme TLD privé pour leurs services internes : api.internal, db.staging.internal, grafana.internal. Ça semblait un choix sûr : ce n'est pas un TLD public, il signale clairement « c'est interne », et il est utilisé ainsi depuis des décennies.

Puis le nouveau système d'Apple a décidé que .internal devait être géré par mDNS, le même protocole qui résout monimprimante.local sur votre réseau domestique. Quand votre Mac tente de résoudre api.internal, au lieu d'interroger votre serveur DNS configuré, il diffuse une requête mDNS sur le réseau local. Votre serveur DNS ne voit jamais la requête. La réponse est soit rien (timeout), soit une mauvaise adresse (si une machine du réseau local répond à ce nom).

Les symptômes : curl api.internal reste bloqué 5 secondes puis échoue. Les connexions SSH vers les hôtes internes expirent. Les utilisateurs du VPN ne peuvent pas atteindre les ressources internes. Les conteneurs Docker n'arrivent pas à résoudre les noms de services. Et comme l'échec se manifeste par un simple timeout de connexion, la plupart des développeurs se mettent à déboguer leur VPN, leur pare-feu, leur application : tout sauf le DNS.

Comment fonctionne réellement la résolution DNS sur les systèmes modernes

L'idée reçue « le DNS c'est simple » (votre ordinateur demande une IP à un serveur DNS, le serveur répond) n'est plus vraie depuis des années. Les systèmes modernes disposent d'un pipeline de résolution en plusieurs étapes, et chacune peut intercepter, modifier ou rediriger les requêtes.

DNS resolution pipeline on a typical macOS/Linux system:
Application calls getaddrinfo("api.internal")
↓
1. /etc/hosts — checked first. Static overrides.
↓
2. NSSwitch / resolver configuration
- Linux: /etc/nsswitch.conf controls lookup order
- macOS: /etc/resolver/* for per-domain DNS servers
↓
3. System resolver (systemd-resolved, mDNSResponder)
- May intercept .local, .internal, or other special TLDs
- May apply DNSSEC validation
- May cache responses
↓
4. DNS server (from DHCP, VPN, or manual config)
- Queries sent to configured upstream resolver
- May go through a corporate DNS proxy
↓
5. Recursive resolver (8.8.8.8, 1.1.1.1, corporate)
- Walks the DNS hierarchy: root → TLD → authoritative
↓
Response flows back up the chain

À chaque étape, quelque chose peut mal tourner. Le résolveur système peut intercepter une requête avant qu'elle n'atteigne votre serveur DNS configuré. Le VPN peut écraser les réglages DNS. DHCP peut fournir des serveurs DNS qui priment sur votre configuration manuelle. Et le cache, à chaque niveau, signifie qu'une correction peut ne pas prendre effet immédiatement.

Le mensonge de /etc/resolv.conf

Sous Linux, /etc/resolv.conf a longtemps été la source unique de vérité pour la configuration DNS. Vous définissiez votre nameserver ici, et le système l'utilisait. Simple.

Les distributions Linux modernes ont considérablement compliqué les choses. Si vous utilisez systemd-resolved (ce qu'Ubuntu, Fedora et la plupart des distributions basées sur systemd font par défaut), /etc/resolv.conf est un lien symbolique vers un résolveur stub sur 127.0.0.53. Votre configuration DNS réelle se trouve dans l'état de systemd-resolved, géré via resolvectl. Modifier directement /etc/resolv.conf ne sert à rien : la modification est écrasée au prochain changement réseau, ou elle casse le résolveur stub.

# What you THINK your DNS config is:
$ cat /etc/resolv.conf
nameserver 127.0.0.53  # This is systemd-resolved's stub
# What your DNS config ACTUALLY is:
$ resolvectl status
Global:
DNS Servers: 8.8.8.8 8.8.4.4
DNS Domain: ~.
Link 2 (eth0):
DNS Servers: 10.0.0.1  # From DHCP — this takes precedence
DNS Domain: corp.internal
Link 5 (wg0):  # WireGuard VPN
DNS Servers: 10.100.0.1
DNS Domain: ~internal  # VPN claims the .internal domain
# Three different DNS servers, each handling different domains.
# /etc/resolv.conf shows none of this.

Docker ajoute une couche supplémentaire. Les conteneurs Docker ont leur propre /etc/resolv.conf, généralement copié depuis la configuration de l'hôte au démarrage du conteneur. Si le DNS de l'hôte change (connexion au VPN, changement de réseau), les conteneurs en cours conservent l'ancienne configuration jusqu'à leur redémarrage. C'est une source fréquente de bugs du type « ça marche après un redémarrage mais ça casse au bout d'un moment ».

Split DNS et conflits avec le VPN

Le split DNS, qui consiste à utiliser des serveurs DNS différents selon les domaines, est courant en entreprise. Votre VPN envoie les requêtes pour *.corp.internal au serveur DNS de l'entreprise, tandis que les requêtes publiques vont à votre résolveur habituel. Ça fonctionne très bien quand c'est bien configuré, et ça échoue de façon déroutante quand ce n'est pas le cas.

Modes de défaillance courants :

  • Le VPN définit ses serveurs DNS comme valeurs par défaut globales. Certains clients VPN configurent le serveur DNS du VPN comme résolveur par défaut pour toutes les requêtes, et pas seulement pour les requêtes internes. Toutes vos requêtes DNS, y compris la navigation personnelle, passent désormais par le DNS de l'entreprise. C'est lent (le DNS de l'entreprise se trouve dans un autre datacenter) et pose un problème de confidentialité.
  • Conflits dans l'ordre des serveurs DNS. Quand plusieurs serveurs DNS sont configurés, le système les essaie dans l'ordre. Si le premier est lent ou injoignable (VPN déconnecté mais configuration DNS toujours présente), chaque requête attend un timeout avant de tenter le second. Cela ajoute 5 secondes de délai à chaque connexion.
  • Les domaines de recherche s'ajoutent silencieusement. Un domaine de recherche corp.internal fait qu'une requête pour api essaie aussi api.corp.internal. C'est pratique (taper ssh api au lieu de ssh api.corp.internal) jusqu'au jour où ça ne l'est plus : quand un nom d'hôte court entre en collision avec le nom d'un service interne, les requêtes se résolvent vers la mauvaise IP.
  • mDNS intercepte les domaines internes. Comme le montre l'incident .internal, le résolveur système peut intercepter les requêtes pour certains TLD avant qu'elles n'atteignent un serveur DNS configuré. C'est particulièrement vicieux, car l'interception se fait en silence : pas de message d'erreur, juste un timeout ou une mauvaise réponse.

Déboguer le DNS : la boîte à outils

Quand le DNS casse, il faut des outils qui montrent exactement ce qui se passe à chaque étape du pipeline de résolution.

# 1. Check what your system actually resolves:
$ dig api.internal
# Shows: query sent to which server, response received
# The 'SERVER' line tells you which DNS server answered
# 2. Query a specific DNS server directly:
$ dig @10.100.0.1 api.internal
# Bypasses the system resolver — goes directly to the specified server
# If this works but 'dig api.internal' doesn't, the problem is
# in the system resolver, not the DNS server
# 3. Check systemd-resolved state (Linux):
$ resolvectl query api.internal
# Shows which interface/server handled the query
# 4. Check macOS DNS routing:
$ scutil --dns
# Shows per-domain DNS configuration on macOS
# Look for your .internal domain — is it being routed correctly?
# 5. Monitor DNS queries in real time:
$ sudo tcpdump -i any port 53
# See actual DNS packets. If no packets go out for your query,
# the system resolver is intercepting it locally.
# 6. Flush DNS cache (when fixing config):
$ sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder  # macOS
$ resolvectl flush-caches  # Linux with systemd-resolved

L'étape de diagnostic la plus importante : interroger directement votre serveur DNS avec dig @server hostname. Si cela fonctionne alors que la résolution normale échoue, le problème se situe entre votre application et le serveur DNS (interception par le résolveur système, cache ou routage). Si les requêtes directes échouent aussi, le problème vient du serveur DNS lui-même ou de la connectivité réseau vers celui-ci.

Choisir votre TLD privé

L'incident .internal pose la question pratique : quel TLD utiliser pour les services internes ? Il n'existe pas de réponse universellement sûre, mais certaines options valent mieux que d'autres.

  • .internal : la RFC 6762 le réserve à un usage interne, mais la gestion mDNS d'Apple le rend problématique sur macOS. Peut très bien fonctionner sous Linux.
  • .local : réservé à mDNS (RFC 6762). L'utiliser pour des services résolus par DNS entrera en conflit avec Bonjour/Avahi. À éviter.
  • .corp, .home, .mail : non réservés. L'ICANN pourrait les attribuer comme TLD publics à tout moment, ce qui casserait votre résolution interne. À éviter.
  • Sous-domaine d'un domaine que vous possédez. internal.votreentreprise.com : c'est l'option la plus sûre. Vous contrôlez le domaine parent, donc aucun risque de collision. L'inconvénient : c'est plus long à taper.
  • .test, .example, .invalid, .localhost : réservés par la RFC 6761 et garantis de ne jamais être attribués comme TLD publics. .test est l'option la plus propre pour les services internes qui ne sont pas en production.

La réponse banale mais correcte : utilisez un sous-domaine d'un domaine que vous possédez. api.internal.votreentreprise.com est sans ambiguïté, n'entre en collision avec rien et fonctionne correctement sur tous les OS et tous les résolveurs DNS. C'est plus long, mais les problèmes DNS à 2 h du matin sont bien pires que de taper quelques caractères de plus.

Leçons pour les systèmes en production

Chaque panne DNS nous apprend les mêmes leçons, et nous les réapprenons sans cesse.

  1. Surveillez la résolution DNS, pas seulement les serveurs DNS. Un serveur DNS en bonne santé ne garantit pas que la résolution fonctionne. Surveillez le chemin complet : votre application peut-elle réellement résoudre les noms d'hôte dont elle a besoin ? Une vérification synthétique qui résout les noms critiques toutes les 30 secondes détecte les problèmes plus vite qu'une supervision des serveurs.
  2. Utilisez des TTL courts pour le DNS interne. Quand vous devez modifier un enregistrement DNS interne, des TTL longs entraînent des données obsolètes en cache. Des TTL de 60 secondes pour les services internes permettent un basculement rapide avec une charge minimale sur les résolveurs.
  3. Testez les mises à jour d'OS avec votre configuration DNS. La casse liée à .internal n'a touché que les utilisateurs de macOS. Testez votre environnement de développement après chaque mise à jour majeure d'OS : les changements de résolution DNS figurent rarement dans les notes de version.
  4. Documentez votre architecture DNS. Quels serveurs DNS gèrent quels domaines ? Où se trouvent les points de découpe ? Que se passe-t-il quand le VPN se déconnecte ? Cette documentation est la première chose dont vous aurez besoin pendant une panne, et la dernière que quelqu'un prend le temps d'écrire.
  5. Prévoyez un plan de secours. Si la résolution DNS échoue pour un service interne, votre application peut-elle utiliser une IP codée en dur ? Ce n'est pas élégant, mais une IP codée en dur qui fonctionne vaut mieux qu'un nom DNS qui ne se résout pas.

Le DNS fait partie de ces services fondamentaux invisibles quand ils fonctionnent et catastrophiques quand ils ne fonctionnent plus. La casse de .internal rappelle que la configuration DNS est plus fragile qu'elle n'en a l'air : une seule mise à jour d'OS peut modifier le comportement de résolution de millions d'utilisateurs. Concevez vos systèmes en partant du principe que le DNS va casser, et vous serez moins surpris quand ça arrivera.