-Knot Resolver 1.4.1 (2017-10-xx)
+Knot Resolver 1.5.0 (2017-11-xx)
================================
Bugfixes
--------
- fix loading modules on Darwin
+Improvements
+------------
+- new module ta_signal_query supporting Signaling Trust Anchor Knowledge
+ using Keytag Query (RFC 8145 section 5)
+
Knot Resolver 1.4.0 (2017-09-22)
================================
--- /dev/null
+.. _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.
+
+.. tip:: It is recommended to always keep this module enabled.
+
+Example configuration
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: lua
+
+ -- Signal trust anchor keys configured in the validator
+ modules = { 'ta_signal_query' }
--- /dev/null
+-- Module implementing RFC 8145 section 5
+-- Signaling Trust Anchor Knowledge in DNS using Key Tag Query
+local kres = require('kres')
+
+local mod = {}
+mod.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 i, 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 i, 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
+ if verbose() then
+ log("[ta_query_signal] signalling query trigered: %s", qname)
+ end
+ -- asynchronous query
+ -- we do not care about result or from where it was obtained
+ event.after(0, function (ev)
+ resolve(qname, kres.type.NULL, kres.class.IN, "NONAUTH")
+ end)
+ end
+end
+
+-- act on DNSKEY queries which were not answered from cache
+function mod.layer.consume(state, req, pkt)
+ local req = kres.request_t(req)
+ local qry = req:current()
+ if qry.stype == kres.type.DNSKEY and not qry.flags.CACHED then
+ send_ta_query(qry:name())
+ end
+ return state -- do not interfere with normal query processing
+end
+
+return mod