64 lines
1.9 KiB
Lua
64 lines
1.9 KiB
Lua
-- SPDX-License-Identifier: GPL-3.0-or-later
|
|
-- Module implementing RFC 8145 section 5
|
|
-- Signaling Trust Anchor Knowledge in DNS using Key Tag Query
|
|
local kres = require('kres')
|
|
local ffi = require('ffi')
|
|
|
|
local M = {}
|
|
M.layer = {}
|
|
|
|
-- transform trust anchor keyset structure for one domain name (in wire format)
|
|
-- to signalling query name like _ta-keytag1-keytag2.example.com.
|
|
-- Returns:
|
|
-- string constructed from valid keytags
|
|
-- nil if no valid keytag is present in keyset
|
|
local function prepare_query_name(keyset, name)
|
|
if not keyset then return nil end
|
|
local keytags = {}
|
|
for _, key in ipairs(keyset) do
|
|
if key.state == "Valid" then
|
|
table.insert(keytags, key.key_tag)
|
|
end
|
|
end
|
|
if next(keytags) == nil then return nil end
|
|
|
|
table.sort(keytags)
|
|
local query = "_ta"
|
|
for _, tag in pairs(keytags) do
|
|
query = string.format("%s-%04x", query, tag)
|
|
end
|
|
if name == "\0" then
|
|
return query .. "."
|
|
else
|
|
return query .. "." .. kres.dname2str(name)
|
|
end
|
|
end
|
|
|
|
-- construct keytag query for valid keys and send it as asynchronous query
|
|
-- (does nothing if no valid keys are present at given domain name)
|
|
local function send_ta_query(domain)
|
|
local keyset = trust_anchors.keysets[domain]
|
|
local qname = prepare_query_name(keyset, domain)
|
|
if qname ~= nil then
|
|
log_info(ffi.C.LOG_GRP_TASIGNALING, "signalling query triggered: %s", qname)
|
|
-- asynchronous query
|
|
-- we do not care about result or from where it was obtained
|
|
event.after(0, function ()
|
|
resolve(qname, kres.type.NULL, kres.class.IN, "NONAUTH")
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- act on DNSKEY queries which were not answered from cache
|
|
function M.layer.consume(state, req, pkt)
|
|
-- First check for standard "cached packets": PKT_SIZE_NOWIRE, for efficiency.
|
|
if pkt.size ~= -1 and pkt:qtype() == kres.type.DNSKEY then
|
|
local qry = req:current()
|
|
if not qry.flags.CACHED then
|
|
send_ta_query(qry:name())
|
|
end
|
|
end
|
|
return state -- do not interfere with normal query processing
|
|
end
|
|
|
|
return M
|