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 {
#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.
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 = ¶m->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
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);
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.
*/
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. */