From: Oto Šťáva Date: Tue, 8 Feb 2022 12:46:15 +0000 (+0100) Subject: lib/resolve, modules: NO_ANSWER for not responding to clients X-Git-Tag: v5.5.0~10^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=334ee4f48a65a68fdd1a1128f188cf23f7c8e82b;p=thirdparty%2Fknot-resolver.git lib/resolve, modules: NO_ANSWER for not responding to clients --- diff --git a/NEWS b/NEWS index d327edf41..0d90b3cdf 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ Improvements - validator: conditionally ignore SHA1 DS, as SHOULD by RFC4509 (!1251) - lib/resolve: use EDNS padding for outgoing TLS queries (!1254) - support for PROXYv2 protocol (!1238) +- lib/resolve, policy: new NO_ANSWER flag for not responding to clients (!1257) Incompatible changes -------------------- diff --git a/daemon/lua/kres-gen-30.lua b/daemon/lua/kres-gen-30.lua index fd5a14aac..ca701affd 100644 --- a/daemon/lua/kres-gen-30.lua +++ b/daemon/lua/kres-gen-30.lua @@ -104,6 +104,7 @@ struct kr_qflags { _Bool NO_IPV6 : 1; _Bool NO_IPV4 : 1; _Bool TCP : 1; + _Bool NO_ANSWER : 1; _Bool RESOLVED : 1; _Bool AWAIT_IPV4 : 1; _Bool AWAIT_IPV6 : 1; diff --git a/daemon/lua/kres-gen-31.lua b/daemon/lua/kres-gen-31.lua index d526b3347..0e4fb9a39 100644 --- a/daemon/lua/kres-gen-31.lua +++ b/daemon/lua/kres-gen-31.lua @@ -104,6 +104,7 @@ struct kr_qflags { _Bool NO_IPV6 : 1; _Bool NO_IPV4 : 1; _Bool TCP : 1; + _Bool NO_ANSWER : 1; _Bool RESOLVED : 1; _Bool AWAIT_IPV4 : 1; _Bool AWAIT_IPV6 : 1; diff --git a/daemon/worker.c b/daemon/worker.c index baa615e25..00782081e 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1437,7 +1437,11 @@ static int qr_task_finalize(struct qr_task *task, int state) return state == KR_STATE_DONE ? kr_ok() : kr_error(EIO); } - if (unlikely(ctx->req.answer == NULL)) { /* meant to be dropped */ + /* meant to be dropped */ + if (unlikely(ctx->req.answer == NULL || ctx->req.options.NO_ANSWER)) { + /* For NO_ANSWER, a well-behaved layer should set the state to FAIL */ + kr_assert(!ctx->req.options.NO_ANSWER || (ctx->req.state & KR_STATE_FAIL)); + (void) qr_task_on_send(task, NULL, kr_ok()); return kr_ok(); } diff --git a/lib/resolve.c b/lib/resolve.c index e61574969..4559bc0de 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -732,6 +732,10 @@ knot_rrset_t* kr_request_ensure_edns(struct kr_request *request) knot_pkt_t *kr_request_ensure_answer(struct kr_request *request) { + if (request->options.NO_ANSWER) { + kr_assert(request->state & KR_STATE_FAIL); + return NULL; + } if (request->answer) return request->answer; diff --git a/lib/rplan.h b/lib/rplan.h index a007e9c61..05594de8f 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -18,6 +18,9 @@ struct kr_qflags { bool NO_IPV6 : 1; /**< Disable IPv6 */ bool NO_IPV4 : 1; /**< Disable IPv4 */ bool TCP : 1; /**< Use TCP (or TLS) for this query. */ + bool NO_ANSWER : 1; /**< Do not send any answer to the client. + * Request state should be set to `KR_STATE_FAIL` + * when this flag is set. */ bool RESOLVED : 1; /**< Query is resolved. Note that kr_query gets * RESOLVED before following a CNAME chain; see .CNAME. */ bool AWAIT_IPV4 : 1; /**< Query is waiting for A address. */ diff --git a/modules/policy/README.rst b/modules/policy/README.rst index 101316256..d8f95d847 100644 --- a/modules/policy/README.rst +++ b/modules/policy/README.rst @@ -144,6 +144,17 @@ Following actions stop the policy matching on the query, i.e. other rules are no Terminate query resolution and return REFUSED to the requestor. +.. py:attribute:: NO_ANSWER + + Terminate query resolution and do not return any answer to the requestor. + + .. warning:: During normal operation, an answer should always be returned. + Deliberate query drops are indistinguishable from packet loss and may + cause problems as described in :rfc:`8906`. Only use :any:`NO_ANSWER` + on very specific occasions, e.g. as a defense mechanism during an attack, + and prefer other actions (e.g. :any:`DROP` or :any:`REFUSE`) for normal + operation. + .. py:attribute:: TC Force requestor to use TCP. It sets truncated bit (*TC*) in response to true if the request came through UDP, which will force standard-compliant clients to retry the request over TCP. diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index f17129bfb..55a8de3cf 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -823,6 +823,12 @@ function policy.DROP(_, req) return kres.FAIL end +function policy.NO_ANSWER(_, req) + req.options.NO_ANSWER = true + log_policy_action(req, 'NO_ANSWER') + return kres.FAIL +end + function policy.REFUSE(_, req) local answer = answer_clear(req) if answer == nil then return nil end