From: Marek Vavrusa Date: Tue, 23 Aug 2016 05:58:08 +0000 (-0700) Subject: lib/cache: add configuration options to enforce cache.{min,max}_ttl() X-Git-Tag: v1.2.0-rc1~16^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=594de930e4753596c30a1ef7cbeb09dd6d2ea607;p=thirdparty%2Fknot-resolver.git lib/cache: add configuration options to enforce cache.{min,max}_ttl() --- diff --git a/daemon/README.rst b/daemon/README.rst index 8431a44cd..1291dd9e2 100644 --- a/daemon/README.rst +++ b/daemon/README.rst @@ -796,6 +796,43 @@ daemons or manipulated from other processes, making for example synchronised loa print('Insertions:', cache.stats().insert) +.. function:: cache.max_ttl([ttl]) + + :param number ttl: maximum cache TTL (default: 6 days) + :return: current maximum TTL + + Get or set maximum cache TTL. + + .. note:: The `ttl` value must be in range `(min_ttl, 4294967295)`. + + .. warning:: This settings applies only to currently open cache, it will not persist if the cache is closed or reopened. + + .. code-block:: lua + -- Get maximum TTL + cache.max_ttl() + 518400 + -- Set maximum TTL + cache.max_ttl(172800) + 172800 + +.. function:: cache.min_ttl([ttl]) + + :param number ttl: minimum cache TTL (default: 0) + :return: current maximum TTL + + Get or set minimum cache TTL. Any entry inserted into cache with TTL lower than minimal will be overriden to minimum TTL. Forcing TTL higher than specified violates DNS standards, use with care. + + .. note:: The `ttl` value must be in range `<0, max_ttl)`. + + .. warning:: This settings applies only to currently open cache, it will not persist if the cache is closed or reopened. + + .. code-block:: lua + -- Get minimum TTL + cache.min_ttl() + 0 + -- Set minimum TTL + cache.min_ttl(5) + 5 .. function:: cache.prune([max_count]) diff --git a/daemon/bindings.c b/daemon/bindings.c index fb54af68c..ecc85d593 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -504,6 +504,53 @@ static const struct kr_cdb_api *cache_select(struct engine *engine, const char * return NULL; } +static int cache_max_ttl(lua_State *L) +{ + struct engine *engine = engine_luaget(L); + struct kr_cache *cache = &engine->resolver.cache; + + int n = lua_gettop(L); + if (n > 0) { + if (!lua_isnumber(L, 1)) { + format_error(L, "expected 'max_ttl(number ttl)'"); + lua_error(L); + } + uint32_t min = cache->ttl_min; + int64_t ttl = lua_tonumber(L, 1); + if (ttl < 0 || ttl <= min || ttl > UINT32_MAX) { + format_error(L, "max_ttl must be larger than minimum TTL, and in range <1, UINT32_MAX>'"); + lua_error(L); + } + cache->ttl_max = ttl; + } + lua_pushinteger(L, cache->ttl_max); + return 1; +} + + +static int cache_min_ttl(lua_State *L) +{ + struct engine *engine = engine_luaget(L); + struct kr_cache *cache = &engine->resolver.cache; + + int n = lua_gettop(L); + if (n > 0) { + if (!lua_isnumber(L, 1)) { + format_error(L, "expected 'min_ttl(number ttl)'"); + lua_error(L); + } + uint32_t max = cache->ttl_max; + int64_t ttl = lua_tonumber(L, 1); + if (ttl < 0 || ttl >= max || ttl > UINT32_MAX) { + format_error(L, "min_ttl must be smaller than maximum TTL, and in range <0, UINT32_MAX>'"); + lua_error(L); + } + cache->ttl_min = ttl; + } + lua_pushinteger(L, cache->ttl_min); + return 1; +} + /** Open cache */ static int cache_open(lua_State *L) { @@ -776,6 +823,8 @@ int lib_cache(lua_State *L) { "prune", cache_prune }, { "clear", cache_clear }, { "get", cache_get }, + { "max_ttl", cache_max_ttl }, + { "min_ttl", cache_min_ttl }, { NULL, NULL } }; diff --git a/lib/cache.c b/lib/cache.c index e3f356e20..9bfde3bbb 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -19,12 +19,14 @@ #include #include #include +#include #include #include #include #include +#include "contrib/ucw/lib.h" #include "contrib/cleanup.h" #include "lib/cache.h" #include "lib/cdb_lmdb.h" @@ -92,6 +94,8 @@ int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct k return ret; } memset(&cache->stats, 0, sizeof(cache->stats)); + cache->ttl_min = 0; + cache->ttl_max = KR_CACHE_DEFAULT_MAXTTL; /* Check cache ABI version */ (void) assert_right_version(cache); return 0; @@ -209,6 +213,11 @@ int kr_cache_insert(struct kr_cache *cache, uint8_t tag, const knot_dname_t *nam return kr_error(EINVAL); } + /* Enforce cache maximum TTL limits without TTL decay. + * Minimum TTL is enforced in specific caches as it requires + * rewriting of the records to avoid negative TTL when decayed. */ + header->ttl = MIN(header->ttl, cache->ttl_max); + /* Prepare key/value for insertion. */ uint8_t keybuf[KEY_SIZE]; size_t key_len = cache_key(keybuf, tag, name, type); diff --git a/lib/cache.h b/lib/cache.h index c758a2900..528db0e2e 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -83,6 +83,8 @@ struct kr_cache uint32_t insert; /**< Number of insertions */ uint32_t delete; /**< Number of deletions */ } stats; + + uint32_t ttl_min, ttl_max; /**< Maximum TTL of inserted entries */ }; /** diff --git a/lib/defines.h b/lib/defines.h index 40c5bcd9b..e5dc1d6f4 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -70,6 +70,7 @@ static inline int __attribute__((__cold__)) kr_error(int x) { #define KR_EDNS_VERSION 0 #define KR_EDNS_PAYLOAD 4096 /* Default UDP payload (max unfragmented UDP is 1452B) */ #define KR_DEFAULT_TLS_PADDING 128 /* Default EDNS(0) Padding is 128 */ +#define KR_CACHE_DEFAULT_MAXTTL (6 * 24 * 3600) /* 6 days, like the root NS TTL */ /* * Address sanitizer hints. diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c index d47e7e216..91e58bbd4 100644 --- a/lib/layer/rrcache.c +++ b/lib/layer/rrcache.c @@ -234,7 +234,7 @@ static int stash_commit(map_t *stash, struct kr_query *qry, struct kr_cache *cac .qry = qry, .cache = cache, .timestamp = qry->timestamp.tv_sec, - .min_ttl = DEFAULT_MINTTL + .min_ttl = MAX(DEFAULT_MINTTL, cache->ttl_min), }; return map_walk(stash, &commit_rr, &baton); }