This module is enabled by default, but disabled in Deckard tests.
if (options->DNSSEC_WANT) {
knot_edns_set_do(pkt->opt_rr);
}
+ if (options->DNSSEC_CD) {
+ knot_wire_set_cd(pkt->wire);
+ }
+
if (lua_isfunction(L, 5)) {
/* Store callback in registry */
lua_pushvalue(L, 5);
_Bool DNSSEC_WANT : 1;
_Bool DNSSEC_BOGUS : 1;
_Bool DNSSEC_INSECURE : 1;
+ _Bool DNSSEC_CD : 1;
_Bool STUB : 1;
_Bool ALWAYS_CUT : 1;
_Bool DNSSEC_WEXPAND : 1;
uint32_t knot_rrset_ttl(const knot_rrset_t *);
int knot_rrset_txt_dump(const knot_rrset_t *, char **, size_t *, const knot_dump_style_t *);
int knot_rrset_txt_dump_data(const knot_rrset_t *, const size_t, char *, const size_t, const knot_dump_style_t *);
+uint32_t knot_rrsig_sig_expiration(const knot_rdataset_t *, size_t);
+uint32_t knot_rrsig_sig_inception(const knot_rdataset_t *, size_t);
const knot_dname_t *knot_pkt_qname(const knot_pkt_t *);
uint16_t knot_pkt_qtype(const knot_pkt_t *);
uint16_t knot_pkt_qclass(const knot_pkt_t *);
knot_rrset_ttl
knot_rrset_txt_dump
knot_rrset_txt_dump_data
+ knot_rrsig_sig_expiration
+ knot_rrsig_sig_inception
# Packet
knot_pkt_qname
knot_pkt_qtype
-- Load embedded modules
modules.load('ta_signal_query')
modules.load('priming')
+modules.load('detect_time_skew')
-- Interactive command evaluation
function eval_cmd(line, raw)
.. include:: ../modules/dnstap/README.rst
.. include:: ../modules/ta_signal_query/README.rst
.. include:: ../modules/priming/README.rst
+.. include:: ../modules/detect_time_skew/README.rst
* i.e. knot_wire_set_cd(request->answer->wire). */
bool DNSSEC_BOGUS : 1; /**< Query response is DNSSEC bogus. */
bool DNSSEC_INSECURE : 1;/**< Query response is DNSSEC insecure. */
+ bool DNSSEC_CD : 1; /**< CD bit in query */
bool STUB : 1; /**< Stub resolution, accept received answer as solved. */
bool ALWAYS_CUT : 1; /**< Always recover zone cut (even if cached). */
bool DNSSEC_WEXPAND : 1; /**< Query response has wildcard expansion. */
--- /dev/null
+.. _mod-detect_time_skew:
+
+System time skew detector
+-------------------------
+
+This module compares local system time with inception and expiration time
+bounds in DNSSEC signatures for `. NS` records. If the local system time is
+outside of these bounds, it is likely a misconfiguration which will cause
+all DNSSEC validation (and resolution) to fail.
+
+In case of mismatch, a warning message will be logged to help with
+further diagnostics.
+
+.. warning:: Information printed by this module can be forged by a network attacker!
+ System administrator MUST verify values printed by this module and
+ fix local system time using a trusted source.
+
+This module is useful for debugging purposes. It runs only once during resolver
+start does not anything after that. It is enabled by default.
+You may disable the module by appending
+`modules.unload('detect_time_skew')` to your configuration.
--- /dev/null
+-- Module interface
+local ffi = require('ffi')
+local knot = ffi.load(libknot_SONAME)
+
+local mod = {}
+local event_id = nil
+
+-- Resolve callback
+-- Check time validity of RRSIGs in priming query
+-- luacheck: no unused args
+local function check_time_callback(pkt, req)
+ pkt = kres.pkt_t(pkt)
+ if pkt:rcode() ~= kres.rcode.NOERROR then
+ warn("[detect_time_skew] cannot resolve '.' NS")
+ return nil
+ end
+ local valid_rrsigs = 0
+ local section = pkt:rrsets(kres.section.ANSWER)
+ local now = os.time()
+ local time_diff = 0
+ local inception = 0
+ local expiration = 0
+ for i = 1, #section do
+ local rr = section[i]
+ if rr.type == kres.type.RRSIG then
+ for k = 0, rr.rrs.rr_count - 1 do
+ inception = knot.knot_rrsig_sig_inception(rr.rrs, k)
+ expiration = knot.knot_rrsig_sig_expiration(rr.rrs, k)
+ if now > expiration then
+ -- possitive value = in the future
+ time_diff = now - expiration
+ elseif now < inception then
+ -- negative value = in the past
+ time_diff = now - inception
+ else
+ valid_rrsigs = valid_rrsigs + 1
+ end
+ end
+ end
+ end
+ if valid_rrsigs == 0 then
+ warn("[detect_time_skew] Local system time %q seems to be at "..
+ "least %u seconds in the %s. DNSSEC signatures for '.' NS "..
+ "are not valid %s. Please check your system clock!",
+ os.date("%c", now),
+ math.abs(time_diff),
+ time_diff > 0 and "future" or "past",
+ time_diff > 0 and "yet" or "anymore")
+ elseif verbose() then
+ log("[detect_time_skew] Local system time %q is within "..
+ "RRSIG validity interval <%q,%q>.", os.date("%c", now),
+ os.date("%c", inception), os.date("%c", expiration))
+ end
+end
+
+-- Make priming query and check time validty of RRSIGs.
+local function check_time()
+ resolve(".", kres.type.NS, kres.class.IN, {"DNSSEC_WANT", "DNSSEC_CD"},
+ check_time_callback)
+end
+
+function mod.init()
+ if event_id then
+ error("Module is already loaded.")
+ else
+ event_id = event.after(0 , check_time)
+ end
+end
+
+function mod.deinit()
+ if event_id then
+ event.cancel(event_id)
+ event_id = nil
+ end
+end
+
+return mod
--- /dev/null
+detect_time_skew_SOURCES := detect_time_skew.lua
+$(call make_lua_module,detect_time_skew)
workarounds \
version \
ta_signal_query \
- priming
+ priming \
+ detect_time_skew
endif
# Make C module
-Subproject commit fcfade5d1805b7c1151523991e4d5ea68db03f03
+Subproject commit a5cd67c98836690e00ab76b7bd220023f7993ee9