.. include:: ../modules/workarounds/README.rst
.. include:: ../modules/dnstap/README.rst
.. include:: ../modules/ta_signal_query/README.rst
+.. include:: ../modules/ta_sentinel/README.rst
.. include:: ../modules/priming/README.rst
.. include:: ../modules/detect_time_skew/README.rst
.. include:: ../modules/detect_time_jump/README.rst
--- /dev/null
+.. _mod-ta_sentinel:
+
+Sentinel for Detecting Trusted Keys
+-----------------------------------
+
+The module implementing Sentinel for Detecting Trusted Keys in DNSSEC
+according to `draft-ietf-dnsop-kskroll-sentinel-00`_.
+
+This feature allows users of validating resolver to detect which root keys
+are configured in their chain of trust. The data from such
+signaling are necessary to monitor the progress of the DNSSEC root key rollover.
+
+This module is enabled by default and we urge users not to disable it.
+If it is absolutely necessary you may add ``modules.unload('ta_sentinel')``
+to your configuration to disable it.
+
+.. _`draft-ietf-dnsop-kskroll-sentinel-00`: https://tools.ietf.org/html/draft-ietf-dnsop-kskroll-sentinel-00
--- /dev/null
+local M = {}
+M.layer = {}
+
+function M.layer.finish(state, req, pkt)
+ local kreq = kres.request_t(req)
+
+ if bit.band(state, kres.DONE) == 0 then
+ return state end -- not resolved yet, exit
+
+ local qry = kreq:resolved()
+ if qry.parent ~= nil then
+ return state end -- an internal query, exit
+
+ local kpkt = kres.pkt_t(pkt)
+ if not kpkt:ad() then
+ return state end -- insecure answer, exit
+
+ if not (kpkt:qtype() == kres.type.A) and not (kpkt:qtype() == kres.type.AAAA) then
+ return state end
+
+ if not (kpkt:qclass() == kres.class.IN) then
+ return state end
+
+ local qname = kres.dname2str(qry:name())
+ local sentype, hexkeytag = qname:match('^_([iI][sS])%-[tT][aA]%-(%x+).')
+ if not sentype then
+ sentype, hexkeytag = qname:match('^_([nN][oO][tT])%-[tT][aA]%-(%x+).')
+ end
+ if not sentype or not hexkeytag then
+ return state end -- regex did not match, exit
+ -- end of hot path
+
+ local qkeytag = tonumber(hexkeytag, 16)
+ if not qkeytag then
+ return state end -- not a valid hex string, exit
+
+ if (qkeytag < 0) or (qkeytag > 0xffff) then
+ return state end -- invalid keytag?!, exit
+ sentype = sentype:lower()
+ if verbose() then
+ log('[ta_sentinel] key tag: ' .. qkeytag .. ', sentinel: ' .. sentype)
+ end
+ assert (sentype == 'is' or sentype == 'not')
+
+ local found = false
+ for keyidx = 1, #trust_anchors.keysets['\0'] do
+ local key = trust_anchors.keysets['\0'][keyidx]
+ if qkeytag == key.key_tag then
+ found = (key.state == "Valid")
+ if verbose() then
+ log('[ta_sentinel] found keytag ' .. qkeytag .. ', key state ' .. key.state)
+ end
+ end
+ end
+
+ if (found and sentype == 'is')
+ or (not found and sentype == 'not') then
+ kpkt:clear_payload()
+ kpkt:rcode(2)
+ kpkt:ad(false)
+ end
+ return state -- do not break resolution process
+end
+
+return M