From: Vladimír Čunát Date: Fri, 3 Sep 2021 16:41:11 +0000 (+0200) Subject: lib/selection: improve the NO6 behavior X-Git-Tag: v5.4.2~4^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=00f6768cc96c123d4c965a1ad73e3f643bf6c101;p=thirdparty%2Fknot-resolver.git lib/selection: improve the NO6 behavior 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. --- diff --git a/NEWS b/NEWS index 24813d2b4..d1a080ea5 100644 --- 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 -------- diff --git a/lib/selection.c b/lib/selection.c index ea6d6b073..fa5581f1d 100644 --- a/lib/selection.c +++ b/lib/selection.c @@ -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; }