From 06bc10f3291b695d2c3c254b44efb16795009bf2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=ADt=C4=9Bzslav=20K=C5=99=C3=AD=C5=BE?= Date: Mon, 4 Dec 2017 12:34:33 +0100 Subject: [PATCH] module: detect discontinuous jumps in the system time Check differences between real and monotonic time. It clears cache when this diffrence changes since last cache clear. --- daemon/bindings.c | 18 ++++++++ daemon/lua/kres-gen.lua | 1 + daemon/lua/kres-gen.sh | 1 + daemon/lua/sandbox.lua | 1 + doc/modules.rst | 1 + lib/cache.c | 7 +++- lib/cache.h | 2 + modules/detect_time_jump/README.rst | 14 +++++++ modules/detect_time_jump/detect_time_jump.lua | 41 +++++++++++++++++++ modules/detect_time_jump/detect_time_jump.mk | 2 + modules/modules.mk | 3 +- 11 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 modules/detect_time_jump/README.rst create mode 100644 modules/detect_time_jump/detect_time_jump.lua create mode 100644 modules/detect_time_jump/detect_time_jump.mk diff --git a/daemon/bindings.c b/daemon/bindings.c index 742510b16..140ec7df3 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -547,6 +547,23 @@ static int cache_count(lua_State *L) return 0; } +/** Return time of last cache clear */ +static int cache_last_clear(lua_State *L) +{ + struct engine *engine = engine_luaget(L); + struct kr_cache *cache = &engine->resolver.cache; + lua_newtable(L); + lua_pushnumber(L, cache->last_clear_monotime); + lua_setfield(L, -2, "monotime"); + lua_newtable(L); + lua_pushnumber(L, cache->last_clear_walltime.tv_sec); + lua_setfield(L, -2, "sec"); + lua_pushnumber(L, cache->last_clear_walltime.tv_usec); + lua_setfield(L, -2, "usec"); + lua_setfield(L, -2, "walltime"); + return 1; +} + /** Return cache statistics. */ static int cache_stats(lua_State *L) { @@ -911,6 +928,7 @@ int lib_cache(lua_State *L) { "backends", cache_backends }, { "count", cache_count }, { "stats", cache_stats }, + { "last_clear", cache_last_clear }, { "open", cache_open }, { "close", cache_close }, { "prune", cache_prune }, diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index 20277e10d..b76e5eb17 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -251,6 +251,7 @@ void kr_qflags_set(struct kr_qflags *, struct kr_qflags); void kr_qflags_clear(struct kr_qflags *, struct kr_qflags); int kr_zonecut_add(struct kr_zonecut *, const knot_dname_t *, const knot_rdata_t *); void kr_zonecut_set(struct kr_zonecut *, const knot_dname_t *); +uint64_t kr_now(); knot_rrset_t *kr_ta_get(map_t *, const knot_dname_t *); int kr_ta_add(map_t *, const knot_dname_t *, uint16_t, uint32_t, const uint8_t *, uint16_t); int kr_ta_del(map_t *, const knot_dname_t *); diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index f6625c52b..df066a2f6 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -137,6 +137,7 @@ EOF kr_qflags_clear kr_zonecut_add kr_zonecut_set + kr_now # Trust anchors kr_ta_get kr_ta_add diff --git a/daemon/lua/sandbox.lua b/daemon/lua/sandbox.lua index f90473ffb..402db091f 100644 --- a/daemon/lua/sandbox.lua +++ b/daemon/lua/sandbox.lua @@ -206,6 +206,7 @@ end modules.load('ta_signal_query') modules.load('priming') modules.load('detect_time_skew') +modules.load('detect_time_jump') -- Interactive command evaluation function eval_cmd(line, raw) diff --git a/doc/modules.rst b/doc/modules.rst index f8e69edc1..c68c9584a 100644 --- a/doc/modules.rst +++ b/doc/modules.rst @@ -28,3 +28,4 @@ Knot DNS Resolver modules .. include:: ../modules/ta_signal_query/README.rst .. include:: ../modules/priming/README.rst .. include:: ../modules/detect_time_skew/README.rst +.. include:: ../modules/detect_time_jump/README.rst diff --git a/lib/cache.c b/lib/cache.c index 6a9cb43ca..2e80fa653 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -51,10 +52,10 @@ static inline int cache_purge(struct kr_cache *cache) } /** @internal Set time when clearing cache. */ -static void reset_time(struct kr_cache *cache) +static void reset_timestamps(struct kr_cache *cache) { cache->last_clear_monotime = kr_now(); - gettimeofday(&cache->last_clear_timestamp, NULL); + gettimeofday(&cache->last_clear_walltime, NULL); } /** @internal Open cache db transaction and check internal data version. */ @@ -104,6 +105,7 @@ int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct k cache->ttl_min = 0; cache->ttl_max = KR_CACHE_DEFAULT_MAXTTL; /* Check cache ABI version */ + reset_timestamps(cache); (void) assert_right_version(cache); return 0; } @@ -282,6 +284,7 @@ int kr_cache_clear(struct kr_cache *cache) } int ret = cache_purge(cache); if (ret == 0) { + reset_timestamps(cache); ret = assert_right_version(cache); } return ret; diff --git a/lib/cache.h b/lib/cache.h index 8552575af..b6fd92ea0 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -77,6 +77,8 @@ struct kr_cache } stats; uint32_t ttl_min, ttl_max; /**< Maximum TTL of inserted entries */ + struct timeval last_clear_walltime; /**< Time of last cache clear */ + uint64_t last_clear_monotime; /**< Last cache clear in monotonic time */ }; /** diff --git a/modules/detect_time_jump/README.rst b/modules/detect_time_jump/README.rst new file mode 100644 index 000000000..7057867c8 --- /dev/null +++ b/modules/detect_time_jump/README.rst @@ -0,0 +1,14 @@ +.. _mod-detect_time_jump: + +Detect discontinuous jumps in the system time +--------------------------------------------- + +This module detect discontinuous jumps in the system time when resolver +is running. It clears cache when some time jumps occurs. + +Time jumps is ussualy created by NTP time change or by admin intervention. +These change can affect cache records as they store timestamp and TTL in real +time. + +If you want to preserve cache during time travel you should disable +this module by modules.unload('detect_time_jump'). diff --git a/modules/detect_time_jump/detect_time_jump.lua b/modules/detect_time_jump/detect_time_jump.lua new file mode 100644 index 000000000..c43b8b5d7 --- /dev/null +++ b/modules/detect_time_jump/detect_time_jump.lua @@ -0,0 +1,41 @@ +-- Module interface +local ffi = require('ffi') + +local mod = {} +mod.threshold = 10 * min +local event_id = nil + +-- Get time of last cache clear. Compute difference between realtime +-- adn monotonic time. Compute difference of actual realtime and monotonic +-- time. In ideal case these differences should be almost same. +-- If they differ more than mod.threshold value then clear cache. +local function check_time() + local clear_time = cache.last_clear() + local cache_timeshift = clear_time.walltime.sec * 1000 - clear_time.monotime + local actual_timeshift = os.time() * 1000 - tonumber(ffi.C.kr_now()) + local time_diff = math.abs(cache_timeshift - actual_timeshift) + log("check_time, %d", time_diff) + if time_diff > mod.threshold then + log("Detected time change, clearing cache\n" .. + "But what does that mean? It means your future hasn't been written yet." + ) + cache.clear() + end +end + +function mod.init() + if event_id then + error("Module is already loaded.") + else + event_id = event.recurrent(1 * min , 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_jump/detect_time_jump.mk b/modules/detect_time_jump/detect_time_jump.mk new file mode 100644 index 000000000..04df60726 --- /dev/null +++ b/modules/detect_time_jump/detect_time_jump.mk @@ -0,0 +1,2 @@ +detect_time_jump_SOURCES := detect_time_jump.lua +$(call make_lua_module,detect_time_jump) diff --git a/modules/modules.mk b/modules/modules.mk index 3df953c0a..78f24c836 100644 --- a/modules/modules.mk +++ b/modules/modules.mk @@ -35,7 +35,8 @@ modules_TARGETS += etcd \ version \ ta_signal_query \ priming \ - detect_time_skew + detect_time_skew \ + detect_time_jump endif # Make C module -- 2.47.2