Ah, the joys of waking up to find the Mac's done an overnight upgrade… and erm, suddenly things stop working. Thankfully, me and Claude managed to work out what the fuck is going on… I'm sharing here, as well as having raised in on https://feedbackassistant.apple.com/feedback/22280434 (that seems to need a login?).
Product: macOS 26.3.1 (Darwin 25.3.0, Build 25D771280a)
Component: Networking → DNS / mDNSResponder
Regression from: macOS 25.x 26.3.0 (working immediately prior to overnight update)
The /etc/resolver/ per-domain DNS resolver mechanism — an Apple-documented, long-standing macOS feature — is silently broken in macOS 26 for any TLD that is not present in the IANA root zone. mDNSResponder intercepts queries for custom/private TLDs and handles them as mDNS (multicast DNS), never consulting the unicast nameserver specified in the resolver file. This breaks an entire class of local development and private network DNS workflows that previously worked correctly on macOS 25 and earlier.
macOS supports per-domain DNS resolver configuration via files placed in /etc/resolver/. A file named /etc/resolver/internal containing nameserver 127.0.0.1 instructs the DNS stack to send all *.internal queries to the local nameserver at 127.0.0.1. This mechanism is documented in man 5 resolver and has worked reliably since at least macOS 10.6. It is widely used by developers running local DNS servers (dnsmasq, bind, unbound) to resolve private domain suffixes.
This machine runs dnsmasq (via Homebrew) as a local DNS resolver, configured to answer queries for *.internal domains (static entries for a local web application) and forward everything else upstream. The /etc/resolver/internal file routes these queries to dnsmasq. This setup worked correctly on macOS 25.x.
-
Install dnsmasq and configure it to answer a custom domain:
# /opt/homebrew/etc/dnsmasq.d/test.conf address=/probe.example-private/127.0.0.1 -
Start dnsmasq:
brew services start dnsmasq -
Verify dnsmasq answers directly:
dig @127.0.0.1 probe.example-private A +short # Returns: 127.0.0.1 ✓ -
Create a resolver file:
sudo sh -c 'echo "nameserver 127.0.0.1" > /etc/resolver/example-private' -
Flush DNS cache and restart mDNSResponder:
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder -
Verify
scutil --dnsshows the resolver is registered:scutil --dns | grep -A4 "example-private" # Shows: domain: example-private, nameserver: 127.0.0.1 ✓ -
Attempt to resolve via the system resolver:
ping -c1 probe.example-private # ping: cannot resolve probe.example-private: Unknown host ✗ python3 -c "import socket; print(socket.getaddrinfo('probe.example-private', 80))" # socket.gaierror: [Errno 8] nodename nor servname provided, or not known ✗
ping, curl, and any application using getaddrinfo() should resolve probe.example-private to 127.0.0.1, as specified by the dnsmasq address= directive, reached via the /etc/resolver/example-private unicast nameserver entry. This is exactly what happened on macOS 25.x.
All resolution via getaddrinfo() (i.e. every real application — browsers, curl, ping) fails with "Unknown host". No DNS traffic reaches dnsmasq. Instead, mDNSResponder intercepts the query and immediately returns a cached "No Such Record" mDNS response with an anomalously large TTL (~108002 seconds).
Evidence from dns-sd -G v4 probe.example-private:
Timestamp A/R Flags IF Hostname Address TTL
11:42:03.617 Add 40000002 0 probe.example-private. 0.0.0.0 108002 No Such Record
Evidence from tcpdump -i lo0 -n port 53 captured during a getaddrinfo() call:
0 packets captured
No packets reach dnsmasq on 127.0.0.1:53 at all. mDNSResponder handles the query entirely internally via mDNS and never consults the unicast nameserver.
Tested TLDs that fail:
| TLD | Status | Notes |
|---|---|---|
.internal |
Broken | IETF draft special-use TLD; worked on macOS 25 |
.test |
Broken | RFC 6761 §6.2 — explicitly reserved for local testing |
.home.arpa |
Broken | RFC 8375 — IANA reserved for residential private networks |
.lan |
Broken | Widely used convention (not IANA reserved, but irrelevant) |
Arbitrary (e.g. .emflocal) |
Broken | Any TLD not in the IANA root zone |
.test is particularly egregious: RFC 6761 Section 6.2 explicitly reserves .test for exactly this use case — local/private DNS testing — and specifies that resolvers SHOULD resolve it via normal DNS mechanisms. macOS 26 silently overrides this by treating it as mDNS-only.
google.com, bbc.co.uk and other standard IANA-registered TLDs continue to work correctly via the default unicast resolver. Only custom/unregistered/special-use TLDs are affected.
The only reliable workaround is to add entries manually to /etc/hosts, which bypasses mDNSResponder entirely. This is impractical for dynamic use cases (e.g. Docker container DNS, where host entries change frequently) and requires sudo for every change.
This breaks the standard local development DNS workflow that has been documented and recommended by the macOS developer community for over a decade:
- Any developer using dnsmasq +
/etc/resolver/for*.test,*.local,*.internal, or other private TLDs - Docker Desktop's (and similar tools') container name resolution via custom TLDs
- Any tool that generates
/etc/resolver/entries as part of its macOS integration (e.g. Vagrant, Tailscale, various VPN clients) - Kubernetes local development tools (minikube, kind, k3d) that use
*.cluster.localor similar
The failure is silent: scutil --dns correctly shows the resolver configuration is registered, leading users to believe the setup is correct while resolution silently fails. There is no log output, no error, and no indication that mDNS interception is occurring.
- macOS version: 26.3.1 (ProductVersionExtra: (a))
- Build: 25D771280a
- Hardware: Apple Silicon (arm64)
- Regression: Working on macOS 25.x immediately before overnight system update
- dnsmasq version: Homebrew, listening on 127.0.0.1:53
- Verified via:
dig @127.0.0.1(works),host(works — uses own resolver),ping/curl/python3 socket.getaddrinfo(all fail)
man 5 resolver(macOS) — documents the/etc/resolver/mechanism- RFC 6761 — Special-Use Domain Names (reserves
.test,.localhost,.invalid,.example) - RFC 8375 — Special-Use Domain
home.arpa - IETF draft-ietf-dnsop-interneti-mdn —
.internalspecial-use proposal