]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/selection: improve the NO6 behavior
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 3 Sep 2021 16:41:11 +0000 (18:41 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 7 Oct 2021 11:48:22 +0000 (13:48 +0200)
With broken IPv6 and no knowledge of IP addresses, we were quite often
chosing to resolve a NS's AAAA and then using it... which wasn't good.
Let's give preference to A here as well.

NEWS
lib/selection.c

diff --git a/NEWS b/NEWS
index 24813d2b4281ff6f81e5e60d621824844313c2d5..d1a080ea52860a8ec652245084a05c722d09fa57 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Improvements
 - dns64 module: also map the reverse (PTR) subtree (#478, !1201)
 - dns64 module: allow disabling based on client address (#368, !1201)
 - dns64 module: allow configuring AAAA subnets not allowed in answer (!1201)
+- nameserver selection algorithm: improve IPv6 avoidance if broken (!1207)
 
 Bugfixes
 --------
index ea6d6b07393dbac02a32405013860ef7c3c09a03..fa5581f1d309b8054407106432534fe832fc6739 100644 (file)
@@ -377,6 +377,37 @@ static void shuffle_choices(struct choice choices[], int choices_len)
        }
 }
 
+/* Adjust choice from `unresolved` in case of NO6 (broken IPv6). */
+static struct kr_transport unresolved_adjust(struct to_resolve unresolved[],
+                                            int unresolved_len, int index)
+{
+       if (unresolved[index].type != KR_TRANSPORT_RESOLVE_AAAA || !no6_is_bad())
+               goto finish;
+       /* AAAA is detected as bad; let's choose randomly from others, if there are any. */
+       int aaaa_count = 0;
+       for (int i = 0; i < unresolved_len; ++i)
+               aaaa_count += (unresolved[i].type == KR_TRANSPORT_RESOLVE_AAAA);
+       if (aaaa_count == unresolved_len)
+               goto finish;
+       /* Chosen index within non-AAAA items. */
+       int i_no6 = kr_rand_bytes(1) % (unresolved_len - aaaa_count);
+       for (int i = 0; i < unresolved_len; ++i) {
+               if (unresolved[i].type == KR_TRANSPORT_RESOLVE_AAAA) {
+                       //continue
+               } else if (i_no6 == 0) {
+                       index = i;
+                       break;
+               } else {
+                       --i_no6;
+               }
+       }
+finish:
+       return (struct kr_transport){
+               .protocol = unresolved[index].type,
+               .ns_name = unresolved[index].name
+       };
+}
+
 /* Performs the actual selection (currently variation on epsilon-greedy). */
 struct kr_transport *select_transport(struct choice choices[], int choices_len,
                                      struct to_resolve unresolved[],
@@ -409,10 +440,7 @@ struct kr_transport *select_transport(struct choice choices[], int choices_len,
                int index = kr_rand_bytes(1) % (choices_len + unresolved_len);
                if (index < unresolved_len) {
                        // We will resolve a new NS name
-                       *transport = (struct kr_transport){
-                               .protocol = unresolved[index].type,
-                               .ns_name = unresolved[index].name
-                       };
+                       *transport = unresolved_adjust(unresolved, unresolved_len, index);
                        return transport;
                } else {
                        chosen = &choices[index - unresolved_len];
@@ -428,10 +456,7 @@ struct kr_transport *select_transport(struct choice choices[], int choices_len,
        /* Don't try the same server again when there are other choices to be explored */
        if (chosen->address_state->error_count && unresolved_len) {
                int index = kr_rand_bytes(1) % unresolved_len;
-               *transport = (struct kr_transport){
-                       .ns_name = unresolved[index].name,
-                       .protocol = unresolved[index].type,
-               };
+               *transport = unresolved_adjust(unresolved, unresolved_len, index);
                return transport;
        }