From: Vladimír Čunát Date: Tue, 5 May 2020 09:32:02 +0000 (+0200) Subject: mitigate NXNSAttack protocol vulnerability for wildcards in victim zone X-Git-Tag: v5.1.1~1^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ba7b89db780fe3884b4e90090318e25ee5afb118;p=thirdparty%2Fknot-resolver.git mitigate NXNSAttack protocol vulnerability for wildcards in victim zone 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. --- diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index 75a38486b..4977ef1b1 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -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 { diff --git a/lib/defines.h b/lib/defines.h index 8cb60aa5d..be2d3a949 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -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. diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 3d2a93cb2..780e9d567 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -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; diff --git a/lib/resolve.c b/lib/resolve.c index b5348e820..3d7aacd6e 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -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 */ diff --git a/lib/resolve.h b/lib/resolve.h index 4a4c3887a..3a55fefee 100644 --- a/lib/resolve.h +++ b/lib/resolve.h @@ -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. */