]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
mitigate NXNSAttack protocol vulnerability for wildcards in victim zone
authorVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 5 May 2020 09:32:02 +0000 (11:32 +0200)
committerPetr Špaček <petr.spacek@nic.cz>
Mon, 18 May 2020 19:51:19 +0000 (21:51 +0200)
Attacker might generate fake NS records pointing to victim's DNS zone.
If the zone contains wildcard the attacker might force us into packet
exchange with a (lame) DNS server on that IP address.

We now limit number of consecuctive failures and kill whole request if
limit is exceeded.

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

index 75a38486bbd81fdfdb4d742463cf88f7ca1c6458..4977ef1b1bbd93ac5fcfd87af4e50bd606f3c44a 100644 (file)
@@ -192,6 +192,7 @@ struct kr_request {
        knot_mm_t pool;
        unsigned int uid;
        unsigned int count_no_nsaddr;
+       unsigned int count_fail_row;
 };
 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 8cb60aa5d4b5b1d9ff3ca2e813b2af309c7d53d3..be2d3a94904174b1a2ed20d3cf64456a6daa5d81 100644 (file)
@@ -53,6 +53,7 @@ static inline int KR_COLD kr_error(int x) {
 #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
+#define KR_CONSUME_FAIL_ROW_LIMIT 3 /* Maximum number of KR_STATE_FAIL in a row. */
 
 /*
  * Defines.
index 3d2a93cb20583248b90663da3f984cd5287b7060..780e9d5676d999d37de343b787065120e2b1423e 100644 (file)
@@ -869,7 +869,8 @@ static int process_stub(knot_pkt_t *pkt, struct kr_request *req)
 }
 
 
-/** Error handling, RFC1034 5.3.3, 4d. */
+/** Error handling, RFC1034 5.3.3, 4d.
+ * NOTE: returing this does not prevent further queries (by itself). */
 static int resolve_error(knot_pkt_t *pkt, struct kr_request *req)
 {
        return KR_STATE_FAIL;
index b5348e820995a07bd3116dc17b219ee55f735644..3d7aacd6ee7622feb05e084016be1d0f12dca20a 100644 (file)
@@ -939,6 +939,23 @@ int kr_resolve_consume(struct kr_request *request, const struct sockaddr *src, k
                qry->flags.RESOLVED = false;
        }
 
+       /* For multiple errors in a row; invalidate_ns() is not enough. */
+       if (!qry->flags.CACHED) {
+               if (request->state & KR_STATE_FAIL) {
+                       if (++request->count_fail_row > KR_CONSUME_FAIL_ROW_LIMIT) {
+                               if (VERBOSE_STATUS || kr_log_rtrace_enabled(request)) {
+                                       kr_log_req(request, 0, 2, "resl",
+                                               "=> too many failures in a row, "
+                                               "bail out (mitigation for NXNSAttack "
+                                               "CVE-2020-12667)");
+                               }
+                               return KR_STATE_FAIL;
+                       }
+               } else {
+                       request->count_fail_row = 0;
+               }
+       }
+
        /* Pop query if resolved. */
        if (request->state == KR_STATE_YIELD) {
                return KR_STATE_PRODUCE; /* Requery */
index 4a4c3887ac8acb00291e9c378aed67085d742f27..3a55fefee3e7ada41acc09c962ccc28df932b0fd 100644 (file)
@@ -228,6 +228,7 @@ struct kr_request {
        knot_mm_t pool;
        unsigned int uid; /** for logging purposes only */
        unsigned int count_no_nsaddr;
+       unsigned int count_fail_row;
 };
 
 /** Initializer for an array of *_selected. */