From 20a79130ba0425c448e3568efa22d0624d812c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=C4=9Bzslav=20K=C5=99=C3=AD=C5=BE?= <vitezslav.kriz@nic.cz> Date: Wed, 6 Dec 2017 14:00:16 +0100 Subject: [PATCH] time_skew: Detect time skew during kresd start. This module is enabled by default, but disabled in Deckard tests. --- daemon/bindings.c | 4 + daemon/lua/kres-gen.lua | 3 + daemon/lua/kres-gen.sh | 2 + daemon/lua/sandbox.lua | 1 + doc/modules.rst | 1 + lib/rplan.h | 1 + modules/detect_time_skew/README.rst | 21 +++++ modules/detect_time_skew/detect_time_skew.lua | 77 +++++++++++++++++++ modules/detect_time_skew/detect_time_skew.mk | 2 + modules/modules.mk | 3 +- tests/deckard | 2 +- 11 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 modules/detect_time_skew/README.rst create mode 100644 modules/detect_time_skew/detect_time_skew.lua create mode 100644 modules/detect_time_skew/detect_time_skew.mk diff --git a/daemon/bindings.c b/daemon/bindings.c index bde8d7a31..742510b16 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -1226,6 +1226,10 @@ static int wrk_resolve(lua_State *L) 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); diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index 8410f21bf..4dc309d5b 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -77,6 +77,7 @@ struct kr_qflags { _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; @@ -217,6 +218,8 @@ void knot_rrset_init_empty(knot_rrset_t *); 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 *); diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index 865cd1ce6..f6625c52b 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -96,6 +96,8 @@ printf "\tchar _stub[];\n};\n" 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 diff --git a/daemon/lua/sandbox.lua b/daemon/lua/sandbox.lua index 08be51017..f90473ffb 100644 --- a/daemon/lua/sandbox.lua +++ b/daemon/lua/sandbox.lua @@ -205,6 +205,7 @@ end -- Load embedded modules modules.load('ta_signal_query') modules.load('priming') +modules.load('detect_time_skew') -- Interactive command evaluation function eval_cmd(line, raw) diff --git a/doc/modules.rst b/doc/modules.rst index 709fee8ed..f8e69edc1 100644 --- a/doc/modules.rst +++ b/doc/modules.rst @@ -27,3 +27,4 @@ Knot DNS Resolver modules .. include:: ../modules/dnstap/README.rst .. include:: ../modules/ta_signal_query/README.rst .. include:: ../modules/priming/README.rst +.. include:: ../modules/detect_time_skew/README.rst diff --git a/lib/rplan.h b/lib/rplan.h index 9a0998474..f87d7f253 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -44,6 +44,7 @@ struct kr_qflags { * 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. */ diff --git a/modules/detect_time_skew/README.rst b/modules/detect_time_skew/README.rst new file mode 100644 index 000000000..87e45fe6f --- /dev/null +++ b/modules/detect_time_skew/README.rst @@ -0,0 +1,21 @@ +.. _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. diff --git a/modules/detect_time_skew/detect_time_skew.lua b/modules/detect_time_skew/detect_time_skew.lua new file mode 100644 index 000000000..ec84e595b --- /dev/null +++ b/modules/detect_time_skew/detect_time_skew.lua @@ -0,0 +1,77 @@ +-- 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 diff --git a/modules/detect_time_skew/detect_time_skew.mk b/modules/detect_time_skew/detect_time_skew.mk new file mode 100644 index 000000000..bc29deb32 --- /dev/null +++ b/modules/detect_time_skew/detect_time_skew.mk @@ -0,0 +1,2 @@ +detect_time_skew_SOURCES := detect_time_skew.lua +$(call make_lua_module,detect_time_skew) diff --git a/modules/modules.mk b/modules/modules.mk index 23d597d11..3df953c0a 100644 --- a/modules/modules.mk +++ b/modules/modules.mk @@ -34,7 +34,8 @@ modules_TARGETS += etcd \ workarounds \ version \ ta_signal_query \ - priming + priming \ + detect_time_skew endif # Make C module diff --git a/tests/deckard b/tests/deckard index fcfade5d1..a5cd67c98 160000 --- a/tests/deckard +++ b/tests/deckard @@ -1 +1 @@ -Subproject commit fcfade5d1805b7c1151523991e4d5ea68db03f03 +Subproject commit a5cd67c98836690e00ab76b7bd220023f7993ee9 -- GitLab