]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: randomize RR order in answers each time we get something from the cache 18565/head
authorLennart Poettering <lennart@poettering.net>
Thu, 5 Nov 2020 13:10:40 +0000 (14:10 +0100)
committerLennart Poettering <lennart@poettering.net>
Sun, 14 Feb 2021 14:43:04 +0000 (15:43 +0100)
This allows some minimal, crappy load balancing.

Fixes: #16297
src/resolve/resolved-dns-transaction.c

index c5233a1e1956bd481a837f2f6abb6b2f664b15d7..43359f3307209675951233cbd681fef9b3b1e016 100644 (file)
@@ -1410,6 +1410,30 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
         }
 }
 
+static void dns_transaction_randomize_answer(DnsTransaction *t) {
+        int r;
+
+        assert(t);
+
+        /* Randomizes the order of the answer array. This is done for all cached responses, so that we return
+         * a different order each time. We do this only for DNS traffic, in order to do some minimal, crappy
+         * load balancing. We don't do this for LLMNR or mDNS, since the order (preferring link-local
+         * addresses, and such like) might have meaning there, and load balancing is pointless. */
+
+        if (t->scope->protocol != DNS_PROTOCOL_DNS)
+                return;
+
+        /* No point in randomizing, if there's just one RR */
+        if (dns_answer_size(t->answer) <= 1)
+                return;
+
+        r = dns_answer_reserve_or_clone(&t->answer, 0);
+        if (r < 0) /* If this fails, just don't randomize, this is non-essential stuff after all */
+                return (void) log_debug_errno(r, "Failed to clone answer record, not randomizing RR order of answer: %m");
+
+        dns_answer_randomize(t->answer);
+}
+
 static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
         int r;
 
@@ -1530,6 +1554,8 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
                 if (r < 0)
                         return r;
                 if (r > 0) {
+                        dns_transaction_randomize_answer(t);
+
                         if (t->bypass && t->scope->protocol == DNS_PROTOCOL_DNS && !t->received)
                                 /* When bypass mode is on, do not use cached data unless it came with a full
                                  * packet. */