OK, so this thing has two parts:
1. when to trigger the fallback
2. switching to forwarding mode itself
Yes, this is all packets being dropped to their
nameserver IP
addresses, so no response at all on either UDP or TCP.
1: for the trigger I'd
suggest reusing the logic from our serve_stale
module, as that one is (also) meant as fallback in case upstream servers
don't reply, and the reason for not replying doesn't seem to matter here.
2: the current server-selection code does not count on being switched
mid-request, but I hacked around that and I suspect it will work
reasonably reliably... at least until we make some significant
server-selection code change in farther future. (note: the way I wrote
it requires knot-resolver >= 5.3.0)
Overall, this seemed OK on my quick test:
-- add to normal config, typically in /etc/knot-resolver/kresd.conf
modules.load('fallback')
and then a separate module file:
-- in /var/lib/knot-resolver/kres_modules/fallback.lua (lua load path is somewhat
customizable, too)
local M = {}
-- Default settings; action: probably works just with FORWARD/TLS_FORWARD.
M.timeout = 1 * sec
M.action = policy.FORWARD({'1.1.1.1', '1.0.0.1'})
local ffi = require('ffi')
ffi.cdef("void kr_server_selection_init(struct kr_query *qry);")
M.layer = {}
function M.layer.produce(state, req, pkt)
local qry = req:current()
if qry.flags.FORWARD then return end -- we've switched already
local now = ffi.C.kr_now()
local deadline = qry.creation_time_mono + M.timeout
if now > deadline or qry.flags.NO_NS_FOUND then
if verbose() then
log('[ ][fall] => no reachable NS, using fallback action')
end
M.action(state, req)
-- Hacky: we need to reset the server-selection state,
-- so that forwarding mode can start.
-- Fortunately context is on kr_request mempool, so we can leak it.
ffi.C.kr_server_selection_init(qry);
end
end
return M
--Vladimir