scutil --dns prints the resolver configuration macOS actually consults, not the one DNS server you typed into a settings panel. The output runs longer than most people expect, because the system keeps separate resolver blocks for the default path, for scoped interfaces, and for domain-specific forwarding. The block at the top of the dump is not necessarily the one that answers the query. If a private name resolves at the office and fails the moment the VPN comes up, the mismatch is in matching rules and routes, not in the server address. Read the order first, then prove the answer with a real lookup.

Read the block order before the addresses

Every entry opens with resolver #N and lists nameserver[0], sometimes if_index, a flags line, reach, and, when the block is not a plain default, a domain and a search domain list. Resolver #1 without a domain is the default that handles public names. Anything carrying Scoped in its flags is bound to the interface named by if_index, and anything marked Supplemental applies only to the domains listed under it.

Selection is suffix matching. For a name like intranet.corp.example, macOS prefers the resolver whose domain entry is the longest matching suffix, so a block with domain : corp.example wins over the default even when it sits far down the output. order breaks ties between domains of the same length. A first look rarely needs more than this: the whole dump when you want to read one block end to end, the opening lines to learn the block order, and a filtered pass that prints the block headers beside the field lines. Scoped blocks appear under their own heading and read like a continuation of the list above them, so keep a header in view whenever you quote the output.

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'

Match if_index to the tunnel interface

An index is only useful if you can name the interface behind it. scutil --nwi lists the network information the system holds, including the primary interface and reachability, while ifconfig -l gives you the names, where utun0 through utun9 are the tunnel candidates a client normally creates. Apple uses scutil --dns as its own inspection example in the deployment guide, and documents how Network Extension can route selected domains to selected resolvers, which is the mechanism those scoped blocks expose.

The check that settles the question is whether the resolver sits on the path the tunnel installed:

scutil --nwi
ifconfig utun4
route -n get 10.20.0.53
netstat -rn | grep -m5 utun

If route -n get returns a gateway and interface that do not match the resolver entry, the address can be perfectly correct and still unreachable. A split tunnel that only carries the corporate subnets drops queries aimed at a DNS server outside them, and the failure surfaces as a timeout, which is why the configuration dump keeps looking clean.

Query the system resolver, then the server

Three tools answer three different questions, and confusing them produces most of the wrong conclusions in this area. dscacheutil -q host -a name goes through the same system resolver ordinary applications use, so scoped and supplemental blocks apply. dig with no server argument reads /etc/resolv.conf, which is not the source of truth for scoped resolution on macOS, and it skips the per-domain rules entirely. dig @address reaches exactly one server and tells you nothing about selection.

dscacheutil -q host -a name intranet.corp.example
dig intranet.corp.example
dig @10.20.0.53 intranet.corp.example
nslookup intranet.corp.example

When the first command answers and the second returns NXDOMAIN, you have found the split you were looking for and nothing is broken. When the first times out while dig @10.20.0.53 replies, the resolver works but is not reachable on the path the tunnel chose, so the next step is route -n get rather than an edit to DNS settings. Keep private names out of anything you paste into a ticket or a shared note.

What the dump cannot show you

Several layers sit above or beside the resolver list, and each can send a query somewhere the dump never mentions. A browser with secure DNS enabled may resolve over its own encrypted channel, so a page that loads while dscacheutil times out is not a contradiction. A DNS proxy installed by security software runs as a Network Extension provider and forwards queries itself, and scutil --dns shows what was configured rather than the upstream address the proxy finally used. Search domains add a third wrinkle: an unqualified name gets each listed suffix appended in order, so the block that answered can be one you never suspected.

Stale answers are the cheapest thing to rule out and the most often skipped:

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
scutil --dns | head -20

If the output changes after the flush, the state was cached and the earlier dump described a tunnel that no longer existed. If it does not change, the configuration is what it is, and the question moves to routes and to application policy.

A short runbook for before and after

Capture a baseline only where policy allows it, and keep the files out of any synced folder. The sequence below is what I run on client machines: capture the baseline, connect, capture again, then diff and look up.

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

Read the diff by block rather than by line. A new scoped resolver carrying the tunnel interface index and a domain entry for the private suffix is the expected shape. A new default resolver pointing at a public address is a finding worth raising with whoever owns the client profile. Then repeat the lookup inside the application that actually failed, not only in the shell, and note the interface from route -n get beside the result.

To undo a change, disconnect and repeat the baseline capture. If the scoped block is gone, the client cleaned up after itself. If the block is still listed against an interface that no longer exists, the state is stale, and a flush plus a reconnect is the gentlest fix before anyone touches the profile.

Four checks, in this order: does a resolver block match the longest suffix of the name; is that block bound to the interface the tunnel installed; does the route to its nameserver use the tunnel; and does the system resolver, not dig, return the answer. The first check that fails tells you whether to change DNS policy, the tunnel routes, or the application. If all four pass and the name still fails, the problem sits above DNS, and the next thing to inspect is whatever answers port 53 in front of it.

Skyldar greinar