- 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
--------------------
_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;
_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;
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();
}
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;
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. */
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.
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