]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
nsrep: never blacklist NSs because of SERVFAIL/REFUSED
authorMarek Vavruša <mvavrusa@cloudflare.com>
Thu, 12 Apr 2018 08:35:50 +0000 (01:35 -0700)
committerMarek Vavruša <mvavrusa@cloudflare.com>
Fri, 7 Sep 2018 17:45:21 +0000 (10:45 -0700)
The SERVFAIL is a soft-failure, and REFUSED isn't something the server
is really in control of. It is easy to trick the resolver into blacklisting
a NS by creating a bad delegation and pointing it at the victim NS.

This changes the scoring function to degrade server score on these rcodes,
but cap it to a really bad score. It should be treated as timed out only
if it really times out or is unreachable.

lib/nsrep.c
lib/resolve.c

index c1a273de3fdef2cfc1678ea868cea503de14cd60..3558cf715b741f96fa9969491b56bfd4e8d6d0e4 100644 (file)
@@ -427,7 +427,7 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
        case KR_NS_UPDATE_NORESET:
                new_score = (cur->score + score) / 2; break;
        case KR_NS_RESET:  new_score = score; break;
-       case KR_NS_ADD:    new_score = MIN(KR_NS_MAX_SCORE - 1, cur->score + score); break;
+       case KR_NS_ADD:    new_score = MIN(KR_NS_LONG - 1, cur->score + score); break;
        case KR_NS_MAX:    new_score = MAX(cur->score, score); break;
        default: break;
        }
index 1280b858e9ecb184a3bb9d29729836baf789100e..e7dbca2d0e47f996599cc0fac7ec59d8fef8c4c0 100644 (file)
@@ -876,11 +876,18 @@ static void update_nslist_score(struct kr_request *request, struct kr_query *qry
                }
        /* Penalise resolution failures except validation failures. */
        } else if (!(qry->flags.DNSSEC_BOGUS)) {
-               kr_nsrep_update_rtt(&qry->ns, src, KR_NS_TIMEOUT, ctx->cache_rtt, KR_NS_UPDATE);
+               const bool is_timeout = (packet == NULL);
+               /* Select whichever is worse - penalty or RTT */
+               unsigned rtt = kr_now() - qry->timestamp_mono;
+               unsigned score = is_timeout ? KR_NS_TIMEOUT : (KR_NS_LONG - 1);
+               if (score < rtt) {
+                       score = rtt;
+               }
+               kr_nsrep_update_rtt(&qry->ns, src, score, ctx->cache_rtt, KR_NS_UPDATE);
                WITH_VERBOSE(qry) {
                        char addr_str[INET6_ADDRSTRLEN];
                        inet_ntop(src->sa_family, kr_inaddr(src), addr_str, sizeof(addr_str));
-                       VERBOSE_MSG(qry, "=> server: '%s' flagged as 'bad'\n", addr_str);
+                       VERBOSE_MSG(qry, "=> server: '%s' flagged as '%s'\n", addr_str, is_timeout ? "timeout" : "bad");
                }
        }
 }