OK, so this thing has two parts:
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