]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: when determining error to return, prefer "conclusive" over "inconclusive...
authorLennart Poettering <lennart@poettering.net>
Thu, 26 Jun 2025 21:04:07 +0000 (23:04 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 27 Jun 2025 13:30:40 +0000 (14:30 +0100)
When asked to look something up, and all scopes we contact fail we need
to pick a suitable error code for the failure, and given that we look up
things on multiple scopes we might have multiple errors to choose from.
So far we simply picked the error from the last scope in the list, which
hence would be pretty arbitrary.

Let's tweak this a bit, and if we have multiple errors to choose from,
let's prefer "conclusive" failures over "inconclusive" ones. The
"inconclusive" ones in this sense are the ones where we didn't even issue
a request, but couldn't even do that because we had no server, no
network or things like that. The "conclusive" ones are the errors we got
from a server, that hence a "real" in a way.

This addresses the confusion described in #37969. For LLMNR lookups we
generally refuse looking up A addresses via IPv6 and AAAA via IPv4. This
generates a DNS_TRANSACTION_NO_SERVERS error, which we would then return
for one type of lookup but not for the other, because the IPv6 scope is
generally created after the IPv4 one, and hence so far won.

Fixes: #37969
src/resolve/resolved-dns-query.c

index dee771bb4475f7f4d7c5094e8c57c56d014fa65d..305399dfe8b9a91cbb3c3f8e966a92411efa40d1 100644 (file)
@@ -1157,8 +1157,14 @@ void dns_query_ready(DnsQuery *q) {
                         break;
 
                 default:
-                        /* Any kind of failure */
-                        bad = c;
+                        /* Any kind of failure: save the most recent error, as long as we never saved one
+                         * before or our current one is "conclusive" in the sense that we definitely did a
+                         * lookup, and thus have a real answer (which might be a failure, but is still *some*
+                         * answer). */
+
+                        if (!bad || !IN_SET(state, DNS_TRANSACTION_NO_SERVERS, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NO_SOURCE))
+                                bad = c;
+                        break;
                 }
         }