Comment inspecter les résolveurs DNS que votre Mac utilise sur un VPN
scutil --dns imprime l’état du résolveur que macOS a réellement construit. Associez chaque bloc à une interface, interrogez un nom réel et prouvez quel serveur a répondu.
scutil --dns imprime la configuration du résolveur que macOS consulte réellement, et non l’unique serveur DNS saisi dans un panneau de réglages. La sortie est plus longue que la plupart des gens ne l’imaginent, car le système conserve des blocs de résolveur distincts pour le chemin par défaut, pour les interfaces à portée et pour le transfert propre à un domaine. Le bloc en tête de la sortie n’est pas forcément celui qui répond à la requête. Si un nom privé se résout au bureau et échoue à l’instant où le VPN monte, le décalage se situe dans les règles d’appariement et les routes, non dans l’adresse du serveur. Lisez d’abord l’ordre, puis prouvez la réponse par une vraie requête.
Lisez l’ordre des blocs avant les adresses
Chaque entrée s’ouvre sur resolver #N et énumère nameserver[0], parfois if_index, une ligne flags, reach et, quand le bloc n’est pas un simple défaut, un domain et une liste search domain. Le résolveur numéro 1 sans domaine est le défaut qui traite les noms publics. Tout ce qui porte Scoped dans ses drapeaux est lié à l’interface nommée par if_index, et tout ce qui est marqué Supplemental ne s’applique qu’aux domaines listés en dessous.
La sélection est un appariement de suffixe. Pour un nom comme intranet.corp.example, macOS préfère le résolveur dont l’entrée domain est le plus long suffixe correspondant, si bien qu’un bloc avec domain : corp.example l’emporte sur le défaut même s’il figure tout en bas de la sortie. order départage les domaines de même longueur. Un premier coup d’œil demande rarement plus : toute la sortie quand vous voulez lire un bloc d’un bout à l’autre, les premières lignes pour apprendre l’ordre des blocs, et une passe filtrée qui imprime les en-têtes de bloc à côté des lignes de champ. Les blocs à portée apparaissent sous leur propre titre et se lisent comme la suite de la liste au-dessus, alors gardez un en-tête sous les yeux chaque fois que vous citez la sortie.
scutil --dns
scutil --dns | sed -n '1,45p'
scutil --dns | grep -nE '^resolver #|^DNS configuration'
scutil --dns | grep -nE 'resolver #[0-9]+|if_index|domain|flags|nameserver'
Associez if_index à l’interface du tunnel
Un index n’est utile que si vous pouvez nommer l’interface qui se trouve derrière. scutil --nwi énumère les informations réseau que le système détient, y compris l’interface principale et l’atteignabilité, tandis que ifconfig -l vous donne les noms, où utun0 jusqu’à utun9 sont les candidats tunnel qu’un client crée habituellement. Apple utilise scutil --dns comme son propre exemple d’inspection dans le guide de déploiement, et documente comment Network Extension peut acheminer des domaines choisis vers des résolveurs choisis, ce qui est le mécanisme que ces blocs à portée dévoilent.
La vérification qui tranche la question est de savoir si le résolveur se trouve sur le chemin que le tunnel a installé :
scutil --nwi
ifconfig utun4
route -n get 10.20.0.53
netstat -rn | grep -m5 utun
Si route -n get renvoie une passerelle et une interface qui ne correspondent pas à l’entrée du résolveur, l’adresse peut être parfaitement correcte et pourtant injoignable. Un tunnel divisé qui ne transporte que les sous-réseaux d’entreprise abandonne les requêtes visant un serveur DNS hors de ceux-ci, et la panne se manifeste par un délai d’attente, ce qui explique pourquoi la sortie de configuration continue de paraître propre.
Interrogez le résolveur système, puis le serveur
Trois outils répondent à trois questions différentes, et les confondre produit la plupart des conclusions erronées dans ce domaine. dscacheutil -q host -a name passe par le même résolveur système que les applications ordinaires, donc les blocs à portée et supplémentaires s’appliquent. dig sans argument de serveur lit /etc/resolv.conf, qui n’est pas la source de vérité pour la résolution à portée sur macOS, et il saute entièrement les règles par domaine. dig @address atteint exactement un serveur et ne dit rien sur la sélection.
dscacheutil -q host -a name intranet.corp.example
dig intranet.corp.example
dig @10.20.0.53 intranet.corp.example
nslookup intranet.corp.example
Quand la première commande répond et que la seconde renvoie NXDOMAIN, vous avez trouvé la séparation que vous cherchiez et rien n’est cassé. Quand la première expire alors que dig @10.20.0.53 répond, le résolveur fonctionne mais n’est pas joignable sur le chemin choisi par le tunnel, donc l’étape suivante est route -n get et non une modification des réglages DNS. Gardez les noms privés hors de tout ce que vous collez dans un ticket ou une note partagée.
Ce que la sortie ne peut pas vous montrer
Plusieurs couches se placent au-dessus ou à côté de la liste des résolveurs, et chacune peut envoyer une requête là où la sortie ne mentionne jamais rien. Un navigateur avec DNS sécurisé activé peut résoudre par son propre canal chiffré, si bien qu’une page qui se charge pendant que dscacheutil expire n’est pas une contradiction. Un proxy DNS installé par un logiciel de sécurité tourne comme fournisseur Network Extension et transfère lui-même les requêtes, et scutil --dns montre ce qui a été configuré, non l’adresse amont que le proxy a finalement utilisée. Les domaines de recherche ajoutent une troisième subtilité : à un nom non qualifié s’ajoute chaque suffixe listé dans l’ordre, si bien que le bloc qui a répondu peut être un que vous n’avez jamais soupçonné.
Les réponses périmées sont la chose la moins coûteuse à écarter et la plus souvent oubliée :
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
scutil --dns | head -20
Si la sortie change après le vidage, l’état était en cache et la sortie précédente décrivait un tunnel qui n’existait plus. Si elle ne change pas, la configuration est ce qu’elle est, et la question se déplace vers les routes et vers la stratégie d’application.
Un court mémo pour avant et après
Capturez une référence de base seulement là où la politique l’autorise, et gardez les fichiers hors de tout dossier synchronisé. La séquence ci-dessous est celle que j’exécute sur des machines clientes : capturez la référence, connectez, capturez de nouveau, puis comparez et cherchez.
scutil --dns > ~/dns-before.txt
# connect the VPN, then:
scutil --dns > ~/dns-after.txt
diff -u ~/dns-before.txt ~/dns-after.txt
dscacheutil -q host -a name intranet.corp.example
Lisez la différence par bloc plutôt que par ligne. Un nouveau résolveur à portée portant l’index de l’interface du tunnel et une entrée domain pour le suffixe privé est la forme attendue. Un nouveau résolveur par défaut pointant vers une adresse publique est une constatation qui mérite d’être remontée à qui possède le profil client. Répétez ensuite la recherche dans l’application qui a réellement échoué, pas seulement dans l’interpréteur de commandes, et notez l’interface issue de route -n get à côté du résultat.
Pour annuler un changement, déconnectez-vous et répétez la capture de référence. Si le bloc à portée a disparu, le client a nettoyé derrière lui. Si le bloc est encore listé contre une interface qui n’existe plus, l’état est périmé, et un vidage plus une reconnexion est le correctif le plus doux avant que quiconque touche au profil.
Quatre vérifications, dans cet ordre : un bloc de résolveur correspond-il au plus long suffixe du nom ; ce bloc est-il lié à l’interface que le tunnel a installée ; la route vers son serveur de noms passe-t-elle par le tunnel ; et le résolveur système, et non dig, renvoie-t-il la réponse. La première vérification qui échoue vous dit s’il faut changer la politique DNS, les routes du tunnel ou l’application. Si les quatre passent et que le nom échoue encore, le problème se situe au-dessus du DNS, et la prochaine chose à inspecter est tout ce qui répond au port 53 devant lui.