From 6a98ba42bd3922652cf9781b07c2f3d8a0adcaee Mon Sep 17 00:00:00 2001 From: Karel Slany <karel.slany@nic.cz> Date: Tue, 31 May 2016 14:51:41 +0200 Subject: [PATCH] Moved cookies before iterate layer. --- daemon/engine.c | 1 + {modules/cookies => lib/layer}/cookies.c | 269 +------------------ lib/lib.mk | 1 + lib/module.c | 2 + modules/cookies/cookies.mk | 5 - modules/cookies_control/cookies_control.c | 290 +++++++++++++++++++++ modules/cookies_control/cookies_control.mk | 6 + modules/modules.mk | 2 +- 8 files changed, 305 insertions(+), 271 deletions(-) rename {modules/cookies => lib/layer}/cookies.c (66%) delete mode 100644 modules/cookies/cookies.mk create mode 100644 modules/cookies_control/cookies_control.c create mode 100644 modules/cookies_control/cookies_control.mk diff --git a/daemon/engine.c b/daemon/engine.c index ad852ba60..4c346aab4 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -471,6 +471,7 @@ static int init_resolver(struct engine *engine) } /* Load basic modules */ + engine_register(engine, "cookies", NULL, NULL); engine_register(engine, "iterate", NULL, NULL); engine_register(engine, "validate", NULL, NULL); engine_register(engine, "rrcache", NULL, NULL); diff --git a/modules/cookies/cookies.c b/lib/layer/cookies.c similarity index 66% rename from modules/cookies/cookies.c rename to lib/layer/cookies.c index 3c972db42..829ac0dff 100644 --- a/modules/cookies/cookies.c +++ b/lib/layer/cookies.c @@ -25,7 +25,6 @@ #include <libknot/rrtype/opt_cookie.h> // branch dns-cookies-wip #include <stdlib.h> #include <string.h> -#include <time.h> #include "daemon/engine.h" #include "lib/cookies/cache.h" @@ -352,10 +351,9 @@ static int check_response(knot_layer_t *ctx, knot_pkt_t *pkt) uint16_t rcode = knot_pkt_get_ext_rcode(pkt); if (rcode == KNOT_RCODE_BADCOOKIE) { - /* TODO -- Fall back to TCP after a limited number of retries. */ - DEBUG_MSG(NULL, "%s'n", "falling back to TCP"); + DEBUG_MSG(NULL, "%s\n", "falling back to TCP"); qry->flags |= QUERY_TCP; - return KNOT_STATE_PRODUCE; + return KNOT_STATE_CONSUME; } print_packet_dflt(pkt); @@ -363,197 +361,7 @@ static int check_response(knot_layer_t *ctx, knot_pkt_t *pkt) return ctx->state; } -/** Find storage API with given prefix. */ -static struct storage_api *find_storage_api(const storage_registry_t *registry, - const char *prefix) -{ - assert(registry); - assert(prefix); - - for (unsigned i = 0; i < registry->len; ++i) { - struct storage_api *storage = ®istry->at[i]; - if (strcmp(storage->prefix, "lmdb://") == 0) { - return storage; - } - } - - return NULL; -} - -#define NAME_ENABLED "enabled" -#define NAME_CLIENT_SECRET "client_secret" - -static bool aply_enabled(struct cookies_control *cntrl, const JsonNode *node) -{ - if (node->tag == JSON_BOOL) { - cntrl->enabled = node->bool_; - return true; - } - - return false; -} - -static struct secret_quantity *new_sq_str(const JsonNode *node) -{ - assert(node && node->tag == JSON_STRING); - - size_t len = strlen(node->string_); - - struct secret_quantity *sq = malloc(sizeof(*sq) + len); - if (!sq) { - return NULL; - } - sq->size = len; - memcpy(sq->data, node->string_, len); - - return sq; -} - -#define holds_char(x) ((x) >= 0 && (x) <= 255) - -static struct secret_quantity *new_sq_array(const JsonNode *node) -{ - assert(node && node->tag == JSON_ARRAY); - - const JsonNode *element = NULL; - size_t cnt = 0; - json_foreach(element, node) { - if (element->tag != JSON_NUMBER || !holds_char(element->number_)) { - return NULL; - } - ++cnt; - } - if (cnt == 0) { - return NULL; - } - - struct secret_quantity *sq = malloc(sizeof(*sq) + cnt); - if (!sq) { - return NULL; - } - - sq->size = cnt; - cnt = 0; - json_foreach(element, node) { - sq->data[cnt++] = (uint8_t) element->number_; - } - - return sq; -} - -static bool apply_client_secret(struct cookies_control *cntrl, const JsonNode *node) -{ - struct secret_quantity *sq = NULL; - - switch (node->tag) { - case JSON_STRING: - sq = new_sq_str(node); - break; - case JSON_ARRAY: - sq = new_sq_array(node); - break; - default: - break; - } - - if (!sq) { - return false; - } - - if (sq->size == cntrl->current_cs->size && - memcmp(sq->data, cntrl->current_cs->data, sq->size) == 0) { - /* Ignore same values. */ - free(sq); - return true; - } - - struct secret_quantity *tmp = cntrl->recent_cs; - cntrl->recent_cs = cntrl->current_cs; - cntrl->current_cs = sq; - - if (tmp && tmp != &dflt_cs) { - free(tmp); - } - - return true; -} - -static bool apply_configuration(struct cookies_control *cntrl, const JsonNode *node) -{ - assert(cntrl && node); - - if (!node->key) { - /* All top most nodes must have names. */ - return false; - } - - if (strcmp(node->key, NAME_ENABLED) == 0) { - return aply_enabled(cntrl, node); - } else if (strcmp(node->key, NAME_CLIENT_SECRET) == 0) { - return apply_client_secret(cntrl, node); - } - - return false; -} - -static bool read_secret(JsonNode *root, struct cookies_control *cntrl) -{ - assert(root && cntrl); - - JsonNode *array = json_mkarray(); - if (!array) { - return false; - } - - for (size_t i = 0; i < cntrl->current_cs->size; ++i) { - JsonNode *element = json_mknumber(cntrl->current_cs->data[i]); - if (!element) { - goto fail; - } - json_append_element(array, element); - } - - json_append_member(root, NAME_CLIENT_SECRET, array); - - return true; - -fail: - if (array) { - json_delete(array); - } - return false; -} - -/** - * Get/set DNS cookie related stuff. - * - * Input: { name: value, ... } - * Output: current configuration - */ -static char *cookies_config(void *env, struct kr_module *module, const char *args) -{ - if (args && strlen(args) > 0) { - JsonNode *node; - JsonNode *root_node = json_decode(args); - json_foreach (node, root_node) { - apply_configuration(&kr_cookies_control, node); - } - json_delete(root_node); - } - - /* Return current configuration. */ - char *result = NULL; - JsonNode *root_node = json_mkobject(); - json_append_member(root_node, NAME_ENABLED, json_mkbool(kr_cookies_control.enabled)); - read_secret(root_node, &kr_cookies_control); - result = json_encode(root_node); - json_delete(root_node); - return result; -} - -/* - * Module implementation. - */ +/** Module implementation. */ KR_EXPORT const knot_layer_api_t *cookies_layer(struct kr_module *module) @@ -566,73 +374,4 @@ const knot_layer_api_t *cookies_layer(struct kr_module *module) return &_layer; } -KR_EXPORT -int cookies_init(struct kr_module *module) -{ - const char *storage_prefix = "lmdb://"; - struct engine *engine = module->data; - DEBUG_MSG(NULL, "initialising with engine %p\n", (void *) engine); - - memset(&kr_cookies_control, 0, sizeof(kr_cookies_control)); - - kr_cookies_control.enabled = false; - - kr_cookies_control.current_cs = &dflt_cs; - - memset(&kr_cookies_control.cache, 0, sizeof(kr_cookies_control.cache)); - - struct storage_api *lmdb_storage_api = find_storage_api(&engine->storage_registry, - storage_prefix); - DEBUG_MSG(NULL, "found storage API %p for prefix '%s'\n", - (void *) lmdb_storage_api, storage_prefix); - - struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER; - opts.path = "cookies_db"; - //opts.dbname = "cookies"; - opts.mapsize = 1024 * 1024 * 1024; - opts.maxdbs = 2; - opts.flags.env = 0x80000 | 0x100000; /* MDB_WRITEMAP|MDB_MAPASYNC */ - - errno = 0; - int ret = kr_cache_open(&kr_cookies_control.cache, - lmdb_storage_api->api(), &opts, engine->pool); - DEBUG_MSG(NULL, "cache_open retval %d: %s\n", ret, kr_strerror(ret)); - - module->data = NULL; - - return kr_ok(); -} - -KR_EXPORT -int cookies_deinit(struct kr_module *module) -{ - kr_cookies_control.enabled = false; - - if (kr_cookies_control.recent_cs && - kr_cookies_control.recent_cs != &dflt_cs) { - free(kr_cookies_control.recent_cs); - } - kr_cookies_control.recent_cs = NULL; - - if (kr_cookies_control.current_cs && - kr_cookies_control.current_cs != &dflt_cs) { - free(kr_cookies_control.current_cs); - } - kr_cookies_control.current_cs = &dflt_cs; - - kr_cache_close(&kr_cookies_control.cache); - - return kr_ok(); -} - -KR_EXPORT -struct kr_prop *cookies_props(void) -{ - static struct kr_prop prop_list[] = { - { &cookies_config, "config", "Empty value to return current configuration.", }, - { NULL, NULL, NULL } - }; - return prop_list; -} - -KR_MODULE_EXPORT(cookies); +KR_MODULE_EXPORT(cookies) diff --git a/lib/lib.mk b/lib/lib.mk index 4dafe5c8e..60dd40fe0 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -1,6 +1,7 @@ libkres_SOURCES := \ contrib/fnv/hash_64a.c \ lib/generic/map.c \ + lib/layer/cookies.c \ lib/layer/iterate.c \ lib/layer/validate.c \ lib/layer/rrcache.c \ diff --git a/lib/module.c b/lib/module.c index 7c7a1398d..99c96d5fe 100644 --- a/lib/module.c +++ b/lib/module.c @@ -24,11 +24,13 @@ #include "lib/module.h" /* List of embedded modules */ +const knot_layer_api_t *cookies_layer(struct kr_module *module); const knot_layer_api_t *iterate_layer(struct kr_module *module); const knot_layer_api_t *validate_layer(struct kr_module *module); const knot_layer_api_t *rrcache_layer(struct kr_module *module); const knot_layer_api_t *pktcache_layer(struct kr_module *module); static const struct kr_module embedded_modules[] = { + { "cookies", NULL, NULL, NULL, cookies_layer, NULL, NULL, NULL }, { "iterate", NULL, NULL, NULL, iterate_layer, NULL, NULL, NULL }, { "validate", NULL, NULL, NULL, validate_layer, NULL, NULL, NULL }, { "rrcache", NULL, NULL, NULL, rrcache_layer, NULL, NULL, NULL }, diff --git a/modules/cookies/cookies.mk b/modules/cookies/cookies.mk deleted file mode 100644 index 2960154c1..000000000 --- a/modules/cookies/cookies.mk +++ /dev/null @@ -1,5 +0,0 @@ -cookies_CFLAGS := -fvisibility=hidden -fPIC -cookies_SOURCES := modules/cookies/cookies.c -cookies_DEPEND := $(libkres) -cookies_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) -$(call make_c_module,cookies) diff --git a/modules/cookies_control/cookies_control.c b/modules/cookies_control/cookies_control.c new file mode 100644 index 000000000..643e27318 --- /dev/null +++ b/modules/cookies_control/cookies_control.c @@ -0,0 +1,290 @@ +/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <ccan/json/json.h> +#include <libknot/db/db_lmdb.h> +#include <stdlib.h> +#include <string.h> + +#include "daemon/engine.h" +#include "lib/cookies/control.h" +#include "lib/layer.h" + +#define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "cookies_control", fmt) + +/** Find storage API with given prefix. */ +static struct storage_api *find_storage_api(const storage_registry_t *registry, + const char *prefix) +{ + assert(registry); + assert(prefix); + + for (unsigned i = 0; i < registry->len; ++i) { + struct storage_api *storage = ®istry->at[i]; + if (strcmp(storage->prefix, "lmdb://") == 0) { + return storage; + } + } + + return NULL; +} + +#define NAME_ENABLED "enabled" +#define NAME_CLIENT_SECRET "client_secret" + +static bool aply_enabled(struct cookies_control *cntrl, const JsonNode *node) +{ + if (node->tag == JSON_BOOL) { + cntrl->enabled = node->bool_; + return true; + } + + return false; +} + +static struct secret_quantity *new_sq_str(const JsonNode *node) +{ + assert(node && node->tag == JSON_STRING); + + size_t len = strlen(node->string_); + + struct secret_quantity *sq = malloc(sizeof(*sq) + len); + if (!sq) { + return NULL; + } + sq->size = len; + memcpy(sq->data, node->string_, len); + + return sq; +} + +#define holds_char(x) ((x) >= 0 && (x) <= 255) + +static struct secret_quantity *new_sq_array(const JsonNode *node) +{ + assert(node && node->tag == JSON_ARRAY); + + const JsonNode *element = NULL; + size_t cnt = 0; + json_foreach(element, node) { + if (element->tag != JSON_NUMBER || !holds_char(element->number_)) { + return NULL; + } + ++cnt; + } + if (cnt == 0) { + return NULL; + } + + struct secret_quantity *sq = malloc(sizeof(*sq) + cnt); + if (!sq) { + return NULL; + } + + sq->size = cnt; + cnt = 0; + json_foreach(element, node) { + sq->data[cnt++] = (uint8_t) element->number_; + } + + return sq; +} + +static bool apply_client_secret(struct cookies_control *cntrl, const JsonNode *node) +{ + struct secret_quantity *sq = NULL; + + switch (node->tag) { + case JSON_STRING: + sq = new_sq_str(node); + break; + case JSON_ARRAY: + sq = new_sq_array(node); + break; + default: + break; + } + + if (!sq) { + return false; + } + + if (sq->size == cntrl->current_cs->size && + memcmp(sq->data, cntrl->current_cs->data, sq->size) == 0) { + /* Ignore same values. */ + free(sq); + return true; + } + + struct secret_quantity *tmp = cntrl->recent_cs; + cntrl->recent_cs = cntrl->current_cs; + cntrl->current_cs = sq; + + if (tmp && tmp != &dflt_cs) { + free(tmp); + } + + return true; +} + +static bool apply_configuration(struct cookies_control *cntrl, const JsonNode *node) +{ + assert(cntrl && node); + + if (!node->key) { + /* All top most nodes must have names. */ + return false; + } + + if (strcmp(node->key, NAME_ENABLED) == 0) { + return aply_enabled(cntrl, node); + } else if (strcmp(node->key, NAME_CLIENT_SECRET) == 0) { + return apply_client_secret(cntrl, node); + } + + return false; +} + +static bool read_secret(JsonNode *root, struct cookies_control *cntrl) +{ + assert(root && cntrl); + + JsonNode *array = json_mkarray(); + if (!array) { + return false; + } + + for (size_t i = 0; i < cntrl->current_cs->size; ++i) { + JsonNode *element = json_mknumber(cntrl->current_cs->data[i]); + if (!element) { + goto fail; + } + json_append_element(array, element); + } + + json_append_member(root, NAME_CLIENT_SECRET, array); + + return true; + +fail: + if (array) { + json_delete(array); + } + return false; +} + +/** + * Get/set DNS cookie related stuff. + * + * Input: { name: value, ... } + * Output: current configuration + */ +static char *cookies_control_config(void *env, struct kr_module *module, const char *args) +{ + if (args && strlen(args) > 0) { + JsonNode *node; + JsonNode *root_node = json_decode(args); + json_foreach (node, root_node) { + apply_configuration(&kr_cookies_control, node); + } + json_delete(root_node); + } + + /* Return current configuration. */ + char *result = NULL; + JsonNode *root_node = json_mkobject(); + json_append_member(root_node, NAME_ENABLED, json_mkbool(kr_cookies_control.enabled)); + read_secret(root_node, &kr_cookies_control); + result = json_encode(root_node); + json_delete(root_node); + return result; +} + +/* + * Module implementation. + */ + +KR_EXPORT +int cookies_control_init(struct kr_module *module) +{ + const char *storage_prefix = "lmdb://"; + struct engine *engine = module->data; + DEBUG_MSG(NULL, "initialising with engine %p\n", (void *) engine); + + memset(&kr_cookies_control, 0, sizeof(kr_cookies_control)); + + kr_cookies_control.enabled = false; + + kr_cookies_control.current_cs = &dflt_cs; + + memset(&kr_cookies_control.cache, 0, sizeof(kr_cookies_control.cache)); + + struct storage_api *lmdb_storage_api = find_storage_api(&engine->storage_registry, + storage_prefix); + DEBUG_MSG(NULL, "found storage API %p for prefix '%s'\n", + (void *) lmdb_storage_api, storage_prefix); + + struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER; + opts.path = "cookies_db"; + //opts.dbname = "cookies"; + opts.mapsize = 1024 * 1024 * 1024; + opts.maxdbs = 2; + opts.flags.env = 0x80000 | 0x100000; /* MDB_WRITEMAP|MDB_MAPASYNC */ + + errno = 0; + int ret = kr_cache_open(&kr_cookies_control.cache, + lmdb_storage_api->api(), &opts, engine->pool); + DEBUG_MSG(NULL, "cache_open retval %d: %s\n", ret, kr_strerror(ret)); + + module->data = NULL; + + return kr_ok(); +} + +KR_EXPORT +int cookies_control_deinit(struct kr_module *module) +{ + kr_cookies_control.enabled = false; + + if (kr_cookies_control.recent_cs && + kr_cookies_control.recent_cs != &dflt_cs) { + free(kr_cookies_control.recent_cs); + } + kr_cookies_control.recent_cs = NULL; + + if (kr_cookies_control.current_cs && + kr_cookies_control.current_cs != &dflt_cs) { + free(kr_cookies_control.current_cs); + } + kr_cookies_control.current_cs = &dflt_cs; + + kr_cache_close(&kr_cookies_control.cache); + + return kr_ok(); +} + +KR_EXPORT +struct kr_prop *cookies_control_props(void) +{ + static struct kr_prop prop_list[] = { + { &cookies_control_config, "config", "Empty value to return current configuration.", }, + { NULL, NULL, NULL } + }; + return prop_list; +} + +KR_MODULE_EXPORT(cookies_control); diff --git a/modules/cookies_control/cookies_control.mk b/modules/cookies_control/cookies_control.mk new file mode 100644 index 000000000..8ea34e622 --- /dev/null +++ b/modules/cookies_control/cookies_control.mk @@ -0,0 +1,6 @@ +cookies_control_CFLAGS := -fvisibility=hidden -fPIC +cookies_control_SOURCES := \ + modules/cookies_control/cookies_control.c +cookies_control_DEPEND := $(libkres) +cookies_control_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) +$(call make_c_module,cookies_control) diff --git a/modules/modules.mk b/modules/modules.mk index 331f01b1d..1bac83a1f 100644 --- a/modules/modules.mk +++ b/modules/modules.mk @@ -1,7 +1,7 @@ # List of built-in modules modules_TARGETS := hints \ stats \ - cookies + cookies_control # Memcached ifeq ($(HAS_libmemcached),yes) -- GitLab