diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index 683c68a968e7d48268e24655afdd613b35ec08bc..b413eb07a6a4914755bdf74af29b972a12cb54c7 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -506,6 +506,21 @@ function policy.slice_randomize_psl(seed) end end +-- Prepare for making an answer from scratch. (Return the packet for convenience.) +local function answer_clear(req) + -- If we're in postrules, previous resolving might have chosen some RRs + -- for inclusion in the answer, so we need to avoid those. + -- *_selected arrays are in mempool, so explicit deallocation is not necessary. + req.answ_selected.len = 0 + req.auth_selected.len = 0 + req.add_selected.len = 0 + + -- Let's be defensive and clear the answer, too. + local pkt = req.answer + pkt:clear_payload() + return pkt +end + function policy.DENY_MSG(msg) if msg and (type(msg) ~= 'string' or #msg >= 255) then error('DENY_MSG: optional msg must be string shorter than 256 characters') @@ -513,7 +528,7 @@ function policy.DENY_MSG(msg) return function (_, req) -- Write authority information - local answer = req.answer + local answer = answer_clear(req) ffi.C.kr_pkt_make_auth_header(answer) answer:rcode(kres.rcode.NXDOMAIN) answer:begin(kres.section.AUTHORITY) @@ -600,26 +615,28 @@ policy.DEBUG_CACHE_MISS = policy.DEBUG_IF( policy.DENY = policy.DENY_MSG() -- compatibility with < 2.0 -function policy.DROP(_, _) +function policy.DROP(_, req) + answer_clear(req) return kres.FAIL end function policy.REFUSE(_, req) - local answer = req.answer + local answer = answer_clear(req) answer:rcode(kres.rcode.REFUSED) answer:ad(false) return kres.DONE end function policy.TC(state, req) - local answer = req.answer - if answer.max_size ~= 65535 then - answer:tc(1) -- ^ Only UDP queries - answer:ad(false) - return kres.DONE - else + -- Skip non-UDP queries + if req.answer.max_size == 65535 then return state end + + local answer = answer_clear(req) + answer:tc(1) + answer:ad(false) + return kres.DONE end function policy.QTRACE(_, req)