.. _mod-ta_sentinel:
-Sentinel for Detecting Trusted Keys
------------------------------------
+Sentinel for Detecting Trusted Root Keys
+----------------------------------------
-The module implementing Sentinel for Detecting Trusted Keys in DNSSEC
-according to `draft-ietf-dnsop-kskroll-sentinel-00`_.
+The module implementing A Root Key Trust Anchor Sentinel for DNSSEC
+according to `draft-ietf-dnsop-kskroll-sentinel-12`_.
This feature allows users of validating resolver to detect which root keys
are configured in their chain of trust. The data from such
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
+.. _`draft-ietf-dnsop-kskroll-sentinel-12`: https://tools.ietf.org/html/draft-ietf-dnsop-kskroll-sentinel-12
local M = {}
M.layer = {}
+local ffi = require('ffi')
function M.layer.finish(state, req, pkt)
local kreq = kres.request_t(req)
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
+ local matching = ((kpkt:qtype() == kres.type.A or kpkt:qtype() == kres.type.AAAA)
+ and kpkt:qclass() == kres.class.IN)
+ if not matching then
return state end
- if not (kpkt:qclass() == kres.class.IN) then
+ -- fast filter by the length of the first label
+ local label_len = qry:name():byte(1)
+ if label_len ~= 29 and label_len ~= 30 then
return state end
-
+ -- end of hot path
+ -- check the label name
local qname = kres.dname2str(qry:name()):lower()
- local sentype, hexkeytag = qname:match('^kskroll%-sentinel%-(is)%-ta%-(%x+)%.')
- if not sentype then
- sentype, hexkeytag = qname:match('^kskroll%-sentinel%-(not)%-ta%-(%x+)%.')
+ local sentype, keytag
+ if label_len == 29 then
+ sentype = true
+ keytag = qname:match('^root%-key%-sentinel%-is%-ta%-(%x+)%.')
+ elseif label_len == 30 then
+ sentype = false
+ keytag = qname:match('^root%-key%-sentinel%-not%-ta%-(%x+)%.')
end
- if not sentype or not hexkeytag then
- return state end -- pattern 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 kreq.rank ~= ffi.C.KR_RANK_SECURE or kreq.answer:cd() then
+ if verbose() then
+ log('[ta_sentinel] name+type OK but not AD+CD conditions')
+ end
+ return state
+ end
- if (qkeytag < 0) or (qkeytag > 0xffff) then
+ -- check keytag from the label
+ keytag = tonumber(keytag)
+ if not keytag or math.floor(keytag) ~= keytag then
+ return state end -- pattern did not match, exit
+ if keytag < 0 or keytag > 0xffff then
return state end -- invalid keytag?!, exit
+
if verbose() then
- log('[ta_sentinel] key tag: ' .. qkeytag .. ', sentinel: ' .. sentype)
+ log('[ta_sentinel] key tag: ' .. keytag .. ', sentinel: ' .. tostring(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
+ if keytag == key.key_tag then
found = (key.state == "Valid")
if verbose() then
- log('[ta_sentinel] found keytag ' .. qkeytag .. ', key state ' .. key.state)
+ log('[ta_sentinel] found keytag ' .. keytag .. ', key state ' .. key.state)
end
end
end
- if (sentype == 'is' and not found) -- expected key is not there
- or (sentype == 'not' and found) then -- unexpected key is there
+ if sentype ~= found then -- expected key is not there, or unexpected key is there
kpkt:clear_payload()
- kpkt:rcode(2)
+ kpkt:rcode(kres.rcode.SERVFAIL)
kpkt:ad(false)
end
return state -- do not break resolution process