Verified Commit 06bc10f3 authored by Vitezslav Kriz's avatar Vitezslav Kriz Committed by Petr Špaček

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.
parent 0abbe1f4
Pipeline #27890 passed with stages
in 2 minutes and 47 seconds
......@@ -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 },
......
......@@ -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 *);
......
......@@ -137,6 +137,7 @@ EOF
kr_qflags_clear
kr_zonecut_add
kr_zonecut_set
kr_now
# Trust anchors
kr_ta_get
kr_ta_add
......
......@@ -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)
......
......@@ -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
......@@ -17,6 +17,7 @@
#include <assert.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
......@@ -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;
......
......@@ -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 */
};
/**
......
.. _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').
-- 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
detect_time_jump_SOURCES := detect_time_jump.lua
$(call make_lua_module,detect_time_jump)
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment