Connect the office VPN and suddenly every name lookup goes to the corporate resolver. Public names still resolve, so nothing looks broken until a local printer name fails or a split-horizon record returns the office address. On some Fedora setups the opposite happens: the ISP resolver keeps answering after the tunnel is up. Both are one question — which resolver owns this query — and on NetworkManager systems the answer lives in the per-connection DNS properties.

Two connections, one winning resolver

Each connection declares a DNS priority. Ordinary connections default to 50 and VPN connections default to 0, and the lower value wins. That default is why a VPN connection silently outranks the wired link for every domain it claims: zero beats fifty without anyone choosing it.

Priority orders the candidates. It does not limit what the winner is asked about. A VPN connection with no search domain claims everything, so preferring it also sends public queries into the tunnel and, in a split-tunnel design, into whatever the corporate resolver forwards to.

Priority decides order, the search list decides ownership

nmcli -f connection.id,ipv4.dns,ipv4.dns-search,ipv4.dns-priority con show "Corp VPN"
resolvectl status
readlink -f /etc/resolv.conf

The search list is the ownership statement. A bare domain such as corp.example becomes a search suffix and a routing domain. The routing-only form ~corp.example sends lookups under that suffix to this connection without appending the domain to short names. That tilde is the difference between "ask this server" and "ask this server and finish my typing for me".

Use both forms when users type short hostnames and the records are also addressed as fully qualified names. Use only the routing form when you want the split without changing how the resolver completes a bare name.

Then make the preference explicit and reactivate:

nmcli con modify "Corp VPN" ipv4.dns-priority -100
nmcli con modify "Corp VPN" ipv6.dns-priority -100
nmcli con modify "Corp VPN" ipv4.dns-search "~corp.example,corp.example"
nmcli con up "Corp VPN"

A negative priority is the documented way to say "prefer this connection", and setting both address families keeps the behaviour consistent on a host with IPv6 connectivity. Changing the property without reactivating the connection changes nothing that is currently running, which is why the sequence ends with an explicit up.

Let systemd-resolved hold the split

The default dnsmasq plugin funnels queries into one local resolver, so per-link separation stays coarse. systemd-resolved exposes the split per link, and resolvectl query names the link that answered.

systemctl enable --now systemd-resolved
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
systemctl restart systemd-resolved NetworkManager
resolvectl query build.corp.example

After that, the corporate link carries corp.example and a public resolver serves the rest. When a lookup reaches the wrong link, the command names the link that answered it, and knowing that beats knowing the address alone.

Match the DNS design to the tunnel type

Privacy designs that send everything through the tunnel should not carry a split list, because it would hand public names back to the local resolver and undo the intent. Split-tunnel designs need one: without it the corporate resolver sees every public query, and the setup breaks the moment the tunnel drops.

Then there is the kill switch that blocks untunneled DNS. Names resolve for the tunnel's zones and fail everywhere else while the connection is perfectly healthy. The workable answers are an explicit allowance for the LAN resolver or a local cache that forwards only the corporate zone, and either one is an exception with an owner rather than a defect in the tunnel.

A profile that rewrites the resolver configuration at interface start behaves in much the same way: once the local resolver is unreachable, only the names the tunnel knows will resolve. Whichever mechanism applies, write down which names are meant to work in each state, and give that list to whoever fields the reports.

Verify per link, then again after reconnect

Ask one internal and one public name, and watch where the query actually goes. A leak-check page tells you which resolver answered, not which link the system chose, so it says nothing about the ordering you just configured.

Run the two queries again after a disconnect and reconnect. Priorities are re-applied when a connection activates, and an old symlink can survive an upgrade that nobody remembers doing. What you want written down at the end is which resolver owns which suffix, plus a check that still holds tomorrow.

Allakkat attuumassuteqartut