Open gmilos opened 1 month ago
The kDNSServiceFlagsReturnIntermediates flag doesn’t return a CNAME instead of the requested record type, it returns a CNAME as well as the requested record type. These intermediate answers are just progress reports of what is happening.
Similarly, a “No Such Record” result is not the final answer. It means “No Such Record right now, but if you wait a bit longer, there might be one later.” On a device like an iPhone this change in results can happen because the user turns off airplane mode, or switches to a different Wi-Fi network, or brings up VPN, or other similar changes. It can also happen if an administrator updates the authoritative DNS and new answers become available.
You can see this using a command like this on a Mac:
dns-sd -intermediates -Gv4v6 www.apple.com
Run the command with no network connection, and you’ll see “No Such Record”, meaning No Such Record right now. Leave the command running and connect to a Wi-Fi network, and you will see the set of available answers change.
The results generated using kDNSServiceFlagsReturnIntermediates should not change the fundamental operation of your code. The intention is that they can be useful hints to update some kind of progress UI, but they don’t change how your program works.
@StuartCheshire thanks for the additional context, that's v. useful. In particular thanks for (a) clarifying that CNAME
-s are delivered in addition to the requested record type, (b) highlighting how the different network conditions affect the DNSSD operations. I don't think this is handled in the swift wrapper in any thought out way.
However, what I was pointing at is that kDNSServiceFlagsReturnIntermediates
affects what callbacks the handler gets. Assuming still that we're querying a non-existent A record, we see the following sequences:
kDNSServiceFlagsReturnIntermediates
:DNSServiceQueryRecord
, configuring the query & the callbackDNSServiceProcessResult
errorCode = -65568
, i.e. kDNSServiceErr_Timeout
kDNSServiceFlagsReturnIntermediates
:
DNSServiceQueryRecord
DNSServiceProcessResult
errorCode = -65554
, i.e. kDNSServiceErr_NoSuchRecord
DNSServiceProcessResult
was made (which the library doesn't do today)errorCode = -65568
, i.e. kDNSServiceErr_Timeout
The kDNSServiceFlagsReturnIntermediates
flag is therefore significant beyond returning CNAMEs
. It also delivers kDNSServiceErr_NoSuchRecord
proactively. This is a useful signal for the callback to consider. @StuartCheshire is there a more canonical way to get that, other than as a side-effect of kDNSServiceFlagsReturnIntermediates
?
Let me also mention slightly related fact that today's implementation is blocking (particularly bad for supposedly async
library). This makes it impossible to cancel DNSServiceProcessResult
. Because of the 30s, uncancellable timeout, it makes the library unusable for querying non-existent records. Cancelability is already being discussed here: https://github.com/apple/swift-async-dns-resolver/issues/32 and here: https://github.com/apple/swift-async-dns-resolver/pull/34. It needs to be fixed in addition to deciding how to handle queries for non-existent records.
On macOS, an attempt to resolve name for which the particular record type doesn't exist, results in long (~30s) delay.
For example:
An investigation showed that adding the additional
kDNSServiceFlagsReturnIntermediates
, to theDNSServiceQueryRecord
invocation fixes the delay problem. However, now the code has to handle the possibility thatCNAME
gets returned instead of the requested record type, thus requiring it to inspect therrclass
andrrtype
returned to the innermost handler here. IfCNAME
is returned, the desired query should be repeated on thatCNAME
, otherwise an error should be generated.PRs welcome if someone beats me to the implementation.
Tested with https://github.com/apple/swift-async-dns-resolver/releases/tag/0.4.0