Hoe je de DNS-resolvers inspecteert die je Mac op een VPN gebruikt
scutil --dns drukt de resolverstatus af die macOS echt heeft opgebouwd. Koppel elk blok aan een interface, vraag een echte naam op en bewijs welke server antwoordde.
scutil --dns drukt de resolverconfiguratie af die macOS echt raadpleegt, niet de ene DNS-server die je in een instellingenpaneel hebt getypt. De uitvoer is langer dan de meeste mensen verwachten, omdat het systeem aparte resolverblokken bijhoudt voor het standaardpad, voor interfaces met een bereik en voor domeinspecifieke doorsturing. Het blok bovenaan de uitvoer is niet noodzakelijk het blok dat de query beantwoordt. Als een privénaam op kantoor wordt opgelost en faalt op het moment dat de VPN opkomt, zit de mismatch in de matchingsregels en de routes, niet in het serveradres. Lees eerst de volgorde en bewijs daarna het antwoord met een echte opzoeking.
Lees de blokvolgorde vóór de adressen
Elke vermelding opent met resolver #N en somt nameserver[0] op, soms if_index, een flags-regel, reach en, wanneer het blok geen gewone standaard is, een domain en een search domain-lijst. Resolver nummer 1 zonder domein is de standaard die openbare namen afhandelt. Alles wat Scoped in zijn flags draagt, is gebonden aan de interface die if_index noemt, en alles wat met Supplemental is gemarkeerd, geldt alleen voor de domeinen die eronder staan.
De selectie is suffixmatching. Voor een naam als intranet.corp.example verkiest macOS de resolver waarvan de domain-vermelding het langst overeenkomende suffix is, dus een blok met domain : corp.example wint van de standaard, zelfs als het diep in de uitvoer staat. order beslecht gelijke gevallen tussen domeinen van dezelfde lengte. Een eerste blik vraagt zelden meer: de volledige uitvoer wanneer je één blok van begin tot eind wilt lezen, de eerste regels om de blokvolgorde te leren, en een gefilterde doorgang die de blokkoppen naast de veldregels afdrukt. Blokken met een bereik verschijnen onder hun eigen kop en lezen als een voortzetting van de lijst erboven, dus houd een kop in het zicht wanneer je de uitvoer citeert.
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'
Koppel if_index aan de tunnelinterface
Een index is alleen nuttig als je de interface erachter kunt benoemen. scutil --nwi somt de netwerkinformatie op die het systeem bijhoudt, inclusief de primaire interface en bereikbaarheid, terwijl ifconfig -l je de namen geeft, waarbij utun0 tot utun9 de tunnelkandidaten zijn die een client gewoonlijk aanmaakt. Apple gebruikt scutil --dns als zijn eigen inspectievoorbeeld in de implementatiehandleiding, en documenteert hoe Network Extension geselecteerde domeinen naar geselecteerde resolvers kan routeren, wat precies het mechanisme is dat die blokken met een bereik blootleggen.
De controle die de vraag beslecht, is of de resolver op het pad zit dat de tunnel heeft geïnstalleerd:
scutil --nwi
ifconfig utun4
route -n get 10.20.0.53
netstat -rn | grep -m5 utun
Als route -n get een gateway en interface teruggeeft die niet bij de resolververmelding passen, kan het adres volkomen correct en toch onbereikbaar zijn. Een gesplitste tunnel die alleen de bedrijfssubnetten draagt, laat query's naar een DNS-server daarbuiten vallen, en de fout openbaart zich als een time-out, waardoor de configuratie-uitvoer er nog steeds schoon uitziet.
Vraag de systeemresolver, dan de server
Drie hulpmiddelen beantwoorden drie verschillende vragen, en ze door elkaar halen levert de meeste verkeerde conclusies in dit gebied op. dscacheutil -q host -a name loopt via dezelfde systeemresolver die gewone toepassingen gebruiken, dus blokken met een bereik en aanvullende blokken gelden. dig zonder serverargument leest /etc/resolv.conf, wat niet de bron van waarheid is voor oplossing met bereik op macOS, en het slaat de regels per domein volledig over. dig @address bereikt precies één server en zegt niets over de selectie.
dscacheutil -q host -a name intranet.corp.example
dig intranet.corp.example
dig @10.20.0.53 intranet.corp.example
nslookup intranet.corp.example
Wanneer de eerste opdracht antwoordt en de tweede NXDOMAIN teruggeeft, heb je de splitsing gevonden die je zocht en is er niets kapot. Wanneer de eerste een time-out krijgt terwijl dig @10.20.0.53 antwoordt, werkt de resolver wel, maar is hij niet bereikbaar op het pad dat de tunnel koos, dus de volgende stap is route -n get en niet een wijziging van de DNS-instellingen. Houd privénamen buiten alles wat je in een ticket of een gedeelde notitie plakt.
Wat de uitvoer je niet kan laten zien
Verschillende lagen zitten boven of naast de resolverslijst, en elk kan een query ergens heen sturen wat de uitvoer nooit vermeldt. Een browser met beveiligde DNS ingeschakeld kan via zijn eigen versleutelde kanaal oplossen, dus een pagina die laadt terwijl dscacheutil een time-out krijgt, is geen tegenspraak. Een DNS-proxy die door beveiligingssoftware is geïnstalleerd, draait als Network Extension-provider en stuurt de query's zelf door, en scutil --dns toont wat er is geconfigureerd, niet het upstreamadres dat de proxy uiteindelijk gebruikte. Zoekdomeinen voegen een derde rimpel toe: aan een niet-gekwalificeerde naam wordt elk vermeld suffix in volgorde toegevoegd, dus het blok dat antwoordde kan er een zijn die je nooit hebt vermoed.
Verouderde antwoorden zijn het goedkoopst uit te sluiten en het vaakst overgeslagen:
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
scutil --dns | head -20
Als de uitvoer na het leegmaken verandert, was de status gecachet en beschreef de eerdere uitvoer een tunnel die niet meer bestond. Verandert hij niet, dan is de configuratie zoals hij is, en verhuist de vraag naar routes en naar applicatiebeleid.
Een korte runbook voor voor en na
Leg alleen een basislijn vast waar het beleid het toestaat, en houd de bestanden buiten elke gesynchroniseerde map. De volgorde hieronder is wat ik op clients draai: leg de basislijn vast, maak verbinding, leg opnieuw vast en vergelijk daarna en zoek op.
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
Lees het verschil per blok in plaats van per regel. Een nieuwe resolver met een bereik die de tunnelinterface-index en een domain-vermelding voor het privésuffix draagt, is de verwachte vorm. Een nieuwe standaardresolver die naar een openbaar adres wijst, is een bevinding die het waard is om aan te kaarten bij wie het clientprofiel bezit. Herhaal daarna de opzoeking in de toepassing die echt faalde, niet alleen in de shell, en noteer de interface uit route -n get naast het resultaat.
Om een wijziging ongedaan te maken, verbreek je de verbinding en herhaal je de basislijnopname. Als het blok met een bereik weg is, heeft de client achter zich opgeruimd. Als het blok nog steeds staat vermeld tegen een interface die niet meer bestaat, is de status verouderd, en een leegmaakactie plus opnieuw verbinden is de zachtste correctie voordat iemand het profiel aanraakt.
Vier controles in deze volgorde: past een resolverblok op het langste suffix van de naam; is dat blok gebonden aan de interface die de tunnel installeerde; gebruikt de route naar zijn naamserver de tunnel; en geeft de systeemresolver, niet dig, het antwoord terug. De eerste controle die faalt, vertelt je of je het DNS-beleid, de tunnelroutes of de toepassing moet wijzigen. Als alle vier slagen en de naam faalt nog steeds, zit het probleem boven DNS, en het volgende dat je moet inspecteren is alles wat ervoor op poort 53 antwoordt.