summaryrefslogtreecommitdiffstats
path: root/modules/ta_signal_query
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/ta_signal_query/.packaging/test.config4
-rw-r--r--modules/ta_signal_query/README.rst31
-rw-r--r--modules/ta_signal_query/ta_signal_query.lua64
3 files changed, 99 insertions, 0 deletions
diff --git a/modules/ta_signal_query/.packaging/test.config b/modules/ta_signal_query/.packaging/test.config
new file mode 100644
index 0000000..dfa7c2a
--- /dev/null
+++ b/modules/ta_signal_query/.packaging/test.config
@@ -0,0 +1,4 @@
+-- SPDX-License-Identifier: GPL-3.0-or-later
+modules.load('ta_signal_query')
+assert(ta_signal_query)
+quit()
diff --git a/modules/ta_signal_query/README.rst b/modules/ta_signal_query/README.rst
new file mode 100644
index 0000000..3136ecb
--- /dev/null
+++ b/modules/ta_signal_query/README.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _mod-ta_signal_query:
+
+Signaling Trust Anchor Knowledge in DNSSEC
+==========================================
+
+The module for Signaling Trust Anchor Knowledge in DNSSEC Using Key Tag Query,
+implemented according to :rfc:`8145#section-5`.
+
+This feature allows validating resolvers to signal to authoritative servers
+which keys are referenced in their chain of trust. The data from such
+signaling allow zone administrators to monitor the progress of rollovers
+in a DNSSEC-signed zone.
+
+This mechanism serve to measure the acceptance and use of new DNSSEC
+trust anchors and key signing keys (KSKs). This signaling data can be
+used by zone administrators as a gauge to measure the successful deployment
+of new keys. This is of particular interest for the DNS root zone in the event
+of key and/or algorithm rollovers that rely on :rfc:`5011` to automatically
+update a validating DNS resolver’s trust anchor.
+
+.. attention::
+ Experience from root zone KSK rollover in 2018 shows that this mechanism
+ by itself is not sufficient to reliably measure acceptance of the new key.
+ Nevertheless, some DNS researchers found it is useful in combination
+ with other data so we left it enabled for now. This default might change
+ once more information is available.
+
+This module is enabled by default. You may use ``modules.unload('ta_signal_query')``
+in your configuration.
diff --git a/modules/ta_signal_query/ta_signal_query.lua b/modules/ta_signal_query/ta_signal_query.lua
new file mode 100644
index 0000000..72c1568
--- /dev/null
+++ b/modules/ta_signal_query/ta_signal_query.lua
@@ -0,0 +1,64 @@
+-- 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