]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
mitigate NXNSAttack protocol vulnerability for unresolvable NS names
authorVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 24 Mar 2020 08:07:54 +0000 (09:07 +0100)
committerPetr Špaček <petr.spacek@nic.cz>
Mon, 18 May 2020 19:51:15 +0000 (21:51 +0200)
CWE-406: Insufficient Control of Network Message Volume (Network Amplification)

We now limit number of failed NS name resolution attempts for each
request. This does not prevent attacker from spoofing delegations
but it puts upper bound on amplification factor.

daemon/lua/kres-gen.lua
lib/defines.h
lib/resolve.c
lib/resolve.h

index 5fa9f2b22bb427b239de1816f84de6771d7a33a0..75a38486bbd81fdfdb4d742463cf88f7ca1c6458 100644 (file)
@@ -191,6 +191,7 @@ struct kr_request {
        int vars_ref;
        knot_mm_t pool;
        unsigned int uid;
+       unsigned int count_no_nsaddr;
 };
 enum kr_rank {KR_RANK_INITIAL, KR_RANK_OMIT, KR_RANK_TRY, KR_RANK_INDET = 4, KR_RANK_BOGUS, KR_RANK_MISMATCH, KR_RANK_MISSING, KR_RANK_INSECURE, KR_RANK_AUTH = 16, KR_RANK_SECURE = 32};
 struct kr_cdb_stats {
index b4ed5b58a4a1a730cf127913aae66adf2491228b..8cb60aa5d4b5b1d9ff3ca2e813b2af309c7d53d3 100644 (file)
@@ -52,6 +52,7 @@ static inline int KR_COLD kr_error(int x) {
 #define KR_CNAME_CHAIN_LIMIT 13 /* Built-in maximum CNAME chain length */
 #define KR_TIMEOUT_LIMIT 4   /* Maximum number of retries after timeout. */
 #define KR_QUERY_NSRETRY_LIMIT 4 /* Maximum number of retries per query. */
+#define KR_COUNT_NO_NSADDR_LIMIT 5
 
 /*
  * Defines.
index fd67a3a63e911b054b6cb06cbd8cd8f10671d738..b5348e820995a07bd3116dc17b219ee55f735644 100644 (file)
@@ -299,10 +299,10 @@ static int ns_fetch_cut(struct kr_query *qry, const knot_dname_t *requested_name
        return KR_STATE_PRODUCE;
 }
 
-static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
+static int ns_resolve_addr(struct kr_query *qry, struct kr_request *req)
 {
-       struct kr_rplan *rplan = &param->rplan;
-       struct kr_context *ctx = param->ctx;
+       struct kr_rplan *rplan = &req->rplan;
+       struct kr_context *ctx = req->ctx;
 
 
        /* Start NS queries from root, to avoid certain cases
@@ -333,7 +333,9 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
                        return kr_error(EAGAIN);
                }
                /* No IPv4 nor IPv6, flag server as unusable. */
-               VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out\n");
+               ++req->count_no_nsaddr;
+               VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out (counter: %u)\n",
+                               req->count_no_nsaddr);
                qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
                kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
                invalidate_ns(rplan, qry);
@@ -1396,6 +1398,11 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
 
 ns_election:
 
+       if (unlikely(request->count_no_nsaddr >= KR_COUNT_NO_NSADDR_LIMIT)) {
+               VERBOSE_MSG(qry, "=> too many unresolvable NSs, bail out "
+                               "(mitigation for NXNSAttack CVE-2020-12667)\n");
+               return KR_STATE_FAIL;
+       }
        /* If the query has already selected a NS and is waiting for IPv4/IPv6 record,
         * elect best address only, otherwise elect a completely new NS.
         */
index 1b339ff3730ac3ee95a3cc34e3dfc60324193302..4a4c3887ac8acb00291e9c378aed67085d742f27 100644 (file)
@@ -227,6 +227,7 @@ struct kr_request {
        int vars_ref; /**< Reference to per-request variable table. LUA_NOREF if not set. */
        knot_mm_t pool;
        unsigned int uid; /** for logging purposes only */
+       unsigned int count_no_nsaddr;
 };
 
 /** Initializer for an array of *_selected. */