mDNSresponder cache policy for REFUSED answers
Hello!
A few weeks ago, I began researching a problem related to Outline VPN and Cloudflare DNS over TLS on Apple devices.
You can find details here https://community.cloudflare.com/t/1-1-1-1-1-0-0-1-dns-over-tls-limitations/643561
and here https://github.com/Jigsaw-Code/outline-apps/issues/1980
This issue affects iOS and MacOS devices and is related to the DNS mechanism. Sometimes, Cloudflare servers respond with REFUSED code to DNS queries. It seems like mDNSResponder is caching this answer because I don’t see any packets in the traffic dump when I repeat the queries.
Here is a sample of mDNSResponder logs when I received a REFUSED answer:
2024-04-18 19:42:43.901120+0700 0x24b132 Default 0x0 389 0 mDNSResponder: [com.apple.mdns:resolver] [Q64229] Received acceptable 468-byte response from BBhjVjYR over TLS via utun7/32 -- id: 0xAB9A (43930), flags: 0x8185 (R/Query, RD, RA, Refused), counts: 1/0/0/1, BBgKPenV IN A?, . OPT 1232 0 {Padding, [422 B]}
2024-04-18 19:42:43.901319+0700 0x24b132 Info 0x0 389 0 mDNSResponder: [com.apple.mdns:resolver] Penalizing server BBhjVjYR for 60 seconds
2024-04-18 19:42:43.901394+0700 0x24b132 Info 0x0 389 0 mDNSResponder: [com.apple.mdns:resolver] [Q64229] Querier concluded -- reason: response
2024-04-18 19:42:43.901532+0700 0x24b132 Default 0x0 389 0 mDNSResponder: [com.apple.mDNSResponder:Default] [Q64229] Handling concluded querier: BBgKPenV A IN
2024-04-18 19:42:43.901792+0700 0x24b132 Default 0x0 389 0 mDNSResponder: [com.apple.mDNSResponder:Default] [R101936->Q64229] DNSServiceQueryRecord(<mask.hash: 'CqqpDNZbd5XmCw8ZIscR7Q=='>(11e4ef85), A) RESULT ADD interface 0: (mortal, DNSSEC Indeterminate)<mask.hash: '3QVv2uzZDFYViunWAFfkYA=='>
2024-04-18 19:42:43.933506+0700 0x24b132 Info 0x0 389 0 mDNSResponder: [com.apple.mdns:resolver] Unpenalizing responsive server BBhjVjYR
2024-04-18 19:42:43.933578+0700 0x24b132 Info 0x0 389 0 mDNSResponder: [com.apple.mdns:resolver] [Q41448] Querier concluded -- reason: response
Here's an attempt to resolve the domain again:
➜ ~ dns-sd -Q riotgames.com
DATE: ---Thu 18 Apr 2024---
19:43:06.431 ...STARTING...
Timestamp A/R Flags IF Name Type Class Rdata
19:43:06.433 Add 40000002 0 riotgames.com. Addr IN 0.0.0.0 No Such Record
As a result, all apps using the system resolver are unable to connect to this domain for some time.
Questions:
a) Is there a way to decrypt mDNSResponder logs? Currently, I can’t see the queries and responses, only some hashes.
b) What does "Penalizing server ... for 60 seconds" mean? Why doesn’t mDNSResponder try to use other resolvers during this period? Is it related to the DoT mechanism?
c) I’m not sure if caching REFUSED answers is normal behavior; I couldn’t find any RFC about it. Is there any documentation about how mDNSResponder works, or a way to avoid caching these answers?
d) I tried to set up a MitM (Man-in-the-Middle) proxy to catch the DNS responses and found that MacOS is unable to switch to DoT for my proxy, even though I have all certificates in the trusted chain and the kdig utility works normally. So, does mDNSResponder perform SSL pinning or something similar to ensure that certificates match the resolver addresses for DoT?
Thank you for your responses. If you need any detailed information, I can provide dumps and logs.
MacBook Pro 16″, macOS 13.3