diff --git a/daemon/engine.c b/daemon/engine.c index 47de46590fc19b80deef3a2b16e7801f175c453d..b2e2bcd81aaa0c6b8b8c498a5412d8aeebe828dc 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -27,6 +27,7 @@ #include "lib/nsrep.h" #include "lib/cache.h" #include "lib/defines.h" +#include "lib/dnssec/ta.h" /** @internal Compatibility wrapper for Lua < 5.2 */ #if LUA_VERSION_NUM < 502 @@ -243,6 +244,7 @@ void *namedb_lmdb_mkopts(const char *conf, size_t maxsize) static int init_resolver(struct engine *engine) { /* Open resolution context */ + engine->resolver.trust_anchors = map_make(); engine->resolver.pool = engine->pool; engine->resolver.modules = &engine->modules; /* Create OPT RR */ @@ -363,6 +365,7 @@ void engine_deinit(struct engine *engine) } array_clear(engine->modules); array_clear(engine->storage_registry); + kr_ta_clear(&engine->resolver.trust_anchors); if (engine->L) { lua_close(engine->L); @@ -402,6 +405,12 @@ int engine_cmd(struct engine *engine, const char *str) static int engine_loadconf(struct engine *engine) { + /* Use module path for including Lua scripts */ + static const char l_paths[] = "package.path = package.path..';" PREFIX MODULEDIR "/?.lua'"; + int ret = l_dobytecode(engine->L, l_paths, sizeof(l_paths) - 1, ""); + if (ret != 0) { + lua_pop(engine->L, 1); + } /* Init environment */ static const char sandbox_bytecode[] = { #include "daemon/lua/sandbox.inc" @@ -411,12 +420,6 @@ static int engine_loadconf(struct engine *engine) lua_pop(engine->L, 1); return kr_error(ENOEXEC); } - /* Use module path for including Lua scripts */ - int ret = engine_cmd(engine, "package.path = package.path..';" PREFIX MODULEDIR "/?.lua'"); - if (ret > 0) { - lua_pop(engine->L, 1); - } - /* Load config file */ if(access("config", F_OK ) != -1 ) { ret = l_dosandboxfile(engine->L, "config"); diff --git a/daemon/lua/kres.lua b/daemon/lua/kres.lua index e548ad239802b014576e135e78b5646b7a4d9dc6..649224a1fdc9b5aefb4dd754abf9628c89718454 100644 --- a/daemon/lua/kres.lua +++ b/daemon/lua/kres.lua @@ -125,6 +125,16 @@ typedef struct { uint8_t _stub[]; /* Do not touch */ } knot_pkt_t; +/* generics */ +typedef void *(*map_alloc_f)(void *, size_t); +typedef void (*map_free_f)(void *baton, void *ptr); +typedef struct { + void *root; + map_alloc_f malloc; + map_free_f free; + void *baton; +} map_t; + /* libkres */ struct kr_query { node_t _node; @@ -141,16 +151,23 @@ struct kr_rplan { uint8_t _stub[]; /* Do not touch */ }; struct kr_request { - struct kr_context *_ctx; + struct kr_context *ctx; knot_pkt_t *answer; - struct { - const knot_rrset_t *key; - const struct sockaddr *addr; - } qsource; + struct { + const knot_rrset_t *key; + const struct sockaddr *addr; + } qsource; uint32_t options; int state; uint8_t _stub[]; /* Do not touch */ }; +struct kr_context +{ + uint32_t options; + knot_rrset_t *opt_rr; + map_t trust_anchors; + uint8_t _stub[]; /* Do not touch */ +}; /* libknot API */ @@ -172,6 +189,12 @@ struct kr_rplan *kr_resolve_plan(struct kr_request *request); /* Resolution plan */ struct kr_query *kr_rplan_current(struct kr_rplan *rplan); /* Query */ +/* Trust anchors */ +knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name); +int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type, + uint32_t ttl, const uint8_t *rdata, uint16_t rdlen); +int kr_ta_del(map_t *trust_anchors, const knot_dname_t *name); +void kr_ta_clear(map_t *trust_anchors); /* Utils */ unsigned kr_rand_uint(unsigned max); int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl, @@ -236,6 +259,33 @@ ffi.metatype( kr_request_t, { }, }) +-- Return DS/DNSKEY parser that adds keys to TA store +local function ta_parser(store) + local parser = require('zonefile').parser(function (p) + C.kr_ta_add(store, p.r_owner, p.r_type, p.r_ttl, p.r_data, p.r_data_length) + end) + return parser +end + +-- TA store management +local trust_anchors = { + current_file = "", + is_auto = false, + store = ffi.cast('struct kr_context *', __engine).trust_anchors, + -- Load keys from a file + config = function (path) + ta_parser(trust_anchors.store):parse_file(path) + trust_anchors.current_file = path + end, + -- Add DS/DNSKEY record + add = function (ds) ta_parser(trust_anchors.store):read(ds..'\n') end, + clear = function() C.kr_ta_clear(trust_anchors.store) end, + -- Set/disable RFC5011 TA management + set_auto = function (enable) + error("not supported") + end, +} + -- Module API local kres = { -- Constants @@ -248,6 +298,8 @@ local kres = { pkt_t = function (udata) return ffi.cast('knot_pkt_t *', udata) end, request_t = function (udata) return ffi.cast('struct kr_request *', udata) end, -- Global API functions + context = function () return ffi.cast('struct kr_context *', __engine) end, + trust_anchors = trust_anchors, } return kres \ No newline at end of file diff --git a/daemon/lua/sandbox.lua b/daemon/lua/sandbox.lua index 53559156ea1007b30c511a4cec6c239551a02266..a918bf75ec89bc7fbe6cddf87afc5b173dff9219 100644 --- a/daemon/lua/sandbox.lua +++ b/daemon/lua/sandbox.lua @@ -64,6 +64,16 @@ setmetatable(cache, { end }) +-- Syntactic sugar for TA store +trust_anchors = require('kres').trust_anchors +setmetatable(trust_anchors, { + __newindex = function (t,k,v) + if k == 'file' then t.config(v) + elseif k == 'auto' then t.set_auto(v) + else rawset(t, k, v) end + end, +}) + -- Register module in Lua environment function modules_register(module) -- Syntactic sugar for get() and set() properties @@ -85,7 +95,7 @@ end -- Make sandboxed environment local function make_sandbox(defined) - local __protected = { modules = true, cache = true, net = true } + local __protected = { modules = true, cache = true, net = true, trust_anchors = true } return setmetatable({}, { __index = defined, __newindex = function (t, k, v) diff --git a/lib/dnssec/ta.c b/lib/dnssec/ta.c index f9fd2bd9630d26900cf64ecc09b0aaefda66e5d6..e39eef8045b6bb35cfc0512e666382f847cc679f 100644 --- a/lib/dnssec/ta.c +++ b/lib/dnssec/ta.c @@ -14,641 +14,60 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <arpa/inet.h> -#include <assert.h> -#include <ctype.h> -#include <pthread.h> - -#include <contrib/ucw/mempool.h> #include <libknot/descriptor.h> -#include <libknot/dname.h> -#include <libknot/internal/base64.h> #include <libknot/rdataset.h> #include <libknot/rrset.h> -#include <libknot/rrtype/rdname.h> #include <libknot/packet/wire.h> #include "lib/defines.h" #include "lib/dnssec/ta.h" -static int dname_parse(knot_dname_t **dname, const char *dname_str, mm_ctx_t *pool) -{ - if (!dname) { - return kr_error(EINVAL); - } - - knot_dname_t *owner = mm_alloc(pool, KNOT_DNAME_MAXLEN); - if (owner == NULL) { - return kr_error(ENOMEM); - } - knot_dname_t *aux = knot_dname_from_str(owner, dname_str, KNOT_DNAME_MAXLEN); - if (aux == NULL) { - mm_free(pool, owner); - return kr_error(ENOMEM); - } - - assert(!*dname); - *dname = owner; - return 0; -} - -static int uint_parse(const char *str, unsigned *u) -{ - char *err_pos; - long num = strtol(str, &err_pos, 10); - if ((*err_pos != '\0') || (num < 0)) { - return kr_error(EINVAL); - } - *u = (unsigned) num; - return 0; -} - -static int strcicmp(char const *a, char const *b) -{ - if (!a && !b) { - return 0; - } - if (!a) { - return -1; - } - if (!b) { - return 1; - } - for ( ; ; ++a, ++b) { - int d = tolower(*a) - tolower(*b); - if ((d != 0) || (*a == '\0')) { - return d; - } - } -} - -static int algorithm_parse(const char *str, unsigned *u) -{ - int ret = uint_parse(str, u); - if (ret == 0) { - return 0; - } - - const lookup_table_t *item = knot_dnssec_alg_names; - while (item->id) { - if (strcicmp(str, item->name) == 0) { - break; - } - ++item; - } - - if (!item->id) { - return kr_error(ENOENT); - } - - *u = (unsigned) item->id; - return 0; -} - -static int hex2value(const char hex) -{ - if ((hex >= '0') && (hex <= '9')) { - return hex - '0'; - } else if ((hex >= 'a') && (hex <= 'f')) { - return hex - 'a' + 10; - } else if ((hex >= 'A') && (hex <= 'F')) { - return hex - 'A' + 10; - } else { - return -1; - } -} - -static int hex2byte(const char hex[2], uint8_t *u) -{ - int d0, d1; - d0 = hex2value(hex[0]); - d1 = hex2value(hex[1]); - - if ((d0 == -1) || (d1 == -1)) { - return kr_error(EINVAL); - } - - *u = ((d0 & 0x0f) << 4) | (d1 & 0x0f); - return 0; -} - -static int ta_ds_parse(uint8_t *rd, size_t *rd_written, size_t rd_maxsize, const char *seps, char **saveptr) -{ - if (!rd || !rd_written || !seps || !saveptr) { - return kr_error(EINVAL); - } - - int ret = 0; - const char *token; - unsigned aux; - - /* Key tag. */ - token = strtok_r(NULL, seps, saveptr); - if (!token) { - return kr_error(EINVAL); - } - ret = uint_parse(token, &aux); - if (ret != 0) { - return ret; - } - uint16_t key_tag = aux; - - /* Algorithm. */ - token = strtok_r(NULL, seps, saveptr); - if (!token) { - return kr_error(EINVAL); - } - ret = algorithm_parse(token, &aux); - if (ret != 0) { - return ret; - } - uint8_t algorithm = aux; - - /* Digest type. */ - token = strtok_r(NULL, seps, saveptr); - if (!token) { - return kr_error(EINVAL); - } - ret = uint_parse(token, &aux); - if (ret != 0) { - return ret; - } - uint8_t digest_type = aux; - - size_t rd_pos = 0; - if (rd_maxsize >= 4) { - * (uint16_t *) (rd + rd_pos) = htons(key_tag); rd_pos += 2; - *(rd + rd_pos++) = algorithm; - *(rd + rd_pos++) = digest_type; - } else { - return kr_error(EINVAL); - } - - char hexbuf[2]; - int i = 0; - while ((token = strtok_r(NULL, seps, saveptr)) != NULL) { - for (int j = 0; j < strlen(token); ++j) { - hexbuf[i++] = token[j]; - if (i == 2) { - uint8_t byte; - ret = hex2byte(hexbuf, &byte); - if (ret != 0) { - return ret; - } - i = 0; - - if (rd_pos < rd_maxsize) { - *(rd + rd_pos++) = byte; - } else { - return kr_error(ENOMEM); - } - } - } - } - - if (i != 0) { - return kr_error(EINVAL); - } - - *rd_written = rd_pos; - return 0; -} - -static int base2bytes(const uint8_t base[4], uint8_t bytes[3], unsigned *valid) +knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name) { - int32_t decoded = base64_decode(base, 4, bytes, 3); - if (decoded < 0) { - return kr_error(EINVAL); - } - *valid = decoded; - return 0; + return map_get(trust_anchors, (const char *)name); } -static int ta_dnskey_parse(uint8_t *rd, size_t *rd_written, size_t rd_maxsize, const char *seps, char **saveptr) +int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type, + uint32_t ttl, const uint8_t *rdata, uint16_t rdlen) { - fprintf(stderr, "%s()\n", __func__); - - if (!rd || !rd_written || !seps || !saveptr) { - return kr_error(EINVAL); - } - - int ret = 0; - const char *token; - unsigned aux; - - /* Flags. */ - token = strtok_r(NULL, seps, saveptr); - if (!token) { - return kr_error(EINVAL); - } - ret = uint_parse(token, &aux); - if (ret != 0) { - return ret; - } - uint16_t flags = aux; - - /* Protocol. */ - token = strtok_r(NULL, seps, saveptr); - if (!token) { - return kr_error(EINVAL); - } - ret = uint_parse(token, &aux); - if (ret != 0) { - return ret; - } - uint8_t protocol = aux; - if (protocol != 3) { - return kr_error(EINVAL); - } - - /* Algorithm. */ - token = strtok_r(NULL, seps, saveptr); - if (!token) { - return kr_error(EINVAL); - } - ret = algorithm_parse(token, &aux); - if (ret != 0) { - return ret; - } - uint8_t algorithm = aux; - - size_t rd_pos = 0; - if (rd_maxsize >= 4) { - * (uint16_t *) (rd + rd_pos) = htons(flags); rd_pos += 2; - *(rd + rd_pos++) = protocol; - *(rd + rd_pos++) = algorithm; - } else { + if (!trust_anchors || !name || !rdata) { return kr_error(EINVAL); } - uint8_t basebuf[4]; - uint8_t databuf[3]; - int i = 0; - while ((token = strtok_r(NULL, seps, saveptr)) != NULL) { - for (int j = 0; j < strlen(token); ++j) { - basebuf[i++] = token[j]; - if (i == 4) { - unsigned written; - ret = base2bytes(basebuf, databuf, &written); - if (ret != 0) { - return ret; - } - i = 0; - - if ((rd_pos + written) < rd_maxsize) { - memcpy(rd + rd_pos, databuf, written); - rd_pos += written; - } else { - return kr_error(ENOMEM); - } - } - } - } - - if (i != 0) { - return kr_error(EINVAL); - } - - *rd_written = rd_pos; - return 0; -} - -int kr_ta_parse(knot_rrset_t **rr, const char *ds_str, mm_ctx_t *pool) -{ -#define SEPARATORS " \t\n\r" -#define RDATA_MAXSIZE 640 - int ret = 0; - - if (!rr || !ds_str || !pool) { - ret = kr_error(EINVAL); - goto fail; - } - - char *ds_cpy = NULL; - knot_dname_t *owner = NULL; - knot_rdata_t *rdata = NULL; - knot_rrset_t *ds_set = NULL; - - size_t ds_len = strlen(ds_str) + 1; - ds_cpy = mm_alloc(pool, ds_len); - if (!ds_cpy) { - ret = kr_error(ENOMEM); - goto fail; - } - memcpy(ds_cpy, ds_str, ds_len); - char *saveptr = NULL, *token; - - /* Owner name. */ - token = strtok_r(ds_cpy, SEPARATORS, &saveptr); - if (!token) { - ret = kr_error(EINVAL); - goto fail; - } - ret = dname_parse(&owner, token, pool); - if (ret != 0) { - goto fail; - } - - /* TTL may be missing. */ - uint32_t ttl = 0; - token = strtok_r(NULL, SEPARATORS, &saveptr); - if (isdigit(token[0])) { - unsigned aux; - ret = uint_parse(token, &aux); - if (ret != 0) { - goto fail; - } - ttl = aux; - /* Read class token. */ - token = strtok_r(NULL, SEPARATORS, &saveptr); - } - - /* Class. */ - uint16_t class; - /* Token already read. */ - if (!token) { - ret = kr_error(EINVAL); - goto fail; - } - ret = knot_rrclass_from_string(token, &class); - if (ret != 0) { - ret = kr_error(EINVAL); - goto fail; - } - - /* Type. */ - uint16_t type; - token = strtok_r(NULL, SEPARATORS, &saveptr); - if (!token) { - ret = kr_error(EINVAL); - goto fail; - } - ret = knot_rrtype_from_string(token, &type); - if ((ret != 0) || - ((type != KNOT_RRTYPE_DS) && (type != KNOT_RRTYPE_DNSKEY))) { - ret = kr_error(EINVAL); - goto fail; - } - - /* Construct RDATA. */ - rdata = mm_alloc(pool, RDATA_MAXSIZE); - if (!rdata) { - ret = kr_error(ENOMEM); - goto fail; - } - size_t rd_written = 0; - + /* Convert DNSKEY records to DS */ switch (type) { - case KNOT_RRTYPE_DS: - ret = ta_ds_parse(rdata, &rd_written, RDATA_MAXSIZE, SEPARATORS, &saveptr); - break; + case KNOT_RRTYPE_DS: break; /* OK */ case KNOT_RRTYPE_DNSKEY: - ret = ta_dnskey_parse(rdata, &rd_written, RDATA_MAXSIZE, SEPARATORS, &saveptr); - break; - default: - assert(0); - ret = kr_error(EINVAL); +#warning TODO: convert DNSKEY -> DS here + return kr_error(ENOSYS); break; + default: return kr_error(EINVAL); } - if (ret != 0) { - goto fail; - } - - ds_set = knot_rrset_new(owner, type, class, pool); - if (!ds_set) { - ret = kr_error(ENOMEM); - goto fail; - } - - ret = knot_rrset_add_rdata(ds_set, rdata, rd_written, ttl, pool); - if (ret != 0) { - goto fail; - } - - *rr = ds_set; - ds_set = NULL; - -fail: - knot_rrset_free(&ds_set, pool); - mm_free(pool, rdata); - knot_dname_free(&owner, pool); - mm_free(pool, ds_cpy); - return ret; -#undef RDATA_MAXSIZE -#undef SEPARATORS -} - -#define MAX_ANCHORS 16 -struct trust_anchors_nolock { - mm_ctx_t pool; - knot_rrset_t *anchors[MAX_ANCHORS]; - int used; -}; - -struct trust_anchors { - struct trust_anchors_nolock locked; - pthread_rwlock_t rwlock; -}; - -struct trust_anchors global_trust_anchors = { - .locked.pool = {0, }, - .locked.anchors = {0, }, - .locked.used = 0, -}; - -static int ta_init(struct trust_anchors_nolock *tan) -{ - assert(tan); - - memset(tan, 0, sizeof(*tan)); - tan->pool.ctx = mp_new(4 * CPU_PAGE_SIZE); - tan->pool.alloc = (mm_alloc_t) mp_alloc; - tan->used = 0; - - return kr_ok(); -} - -static void ta_deinit(struct trust_anchors_nolock *tan) -{ - assert(tan); - - if (tan->pool.ctx) { - mp_delete(tan->pool.ctx); - tan->pool.ctx = NULL; - } -} - -int kr_ta_init(struct trust_anchors *tas) -{ - if (!tas) { - return kr_error(EINVAL); - } - - int ret = ta_init(&tas->locked); - if (ret != 0) { - return ret; - } - - ret = pthread_rwlock_init(&tas->rwlock, NULL); - if (ret != 0) { - ta_deinit(&tas->locked); - return kr_error(ret); - } - return kr_ok(); -} - -void kr_ta_deinit(struct trust_anchors *tas) -{ - if (!tas) { - return; - } - - while (pthread_rwlock_destroy(&tas->rwlock) == EBUSY); - - ta_deinit(&tas->locked); -} - -static int ta_reset(struct trust_anchors_nolock *tan, const char *ta_str) -{ - assert(tan); - - ta_deinit(tan); - int ret = ta_init(tan); - if (ret != 0) { - return ret; - } - - if (!ta_str || (ta_str[0] == '\0')) { - return kr_ok(); - } - - knot_rrset_t *ta = NULL; - ret = kr_ta_parse(&ta, ta_str, &tan->pool); - if (ret != 0) { - return ret; - } - - assert(ta); - tan->anchors[tan->used++] = ta; - - return kr_ok(); -} - -int kr_ta_reset(struct trust_anchors *tas, const char *ta_str) -{ - if (!tas) { - return kr_error(ENOENT); - } - - int ret = pthread_rwlock_wrlock(&tas->rwlock); - if (ret != 0) { - return kr_error(ret); - } - - ret = ta_reset(&tas->locked, ta_str); - - pthread_rwlock_unlock(&tas->rwlock); - return ret; -} - -static knot_rrset_t *ta_find(struct trust_anchors_nolock *tan, const knot_dname_t *name) -{ - assert(tan && name); - - knot_rrset_t *found = NULL; - - int i; - for (i = 0; i < tan->used; ++i) { - if (knot_dname_is_equal(tan->anchors[i]->owner, name)) { - found = tan->anchors[i]; - break; - } + /* Create new RRSet or use existing */ + bool is_new_key = false; + knot_rrset_t *ta_rr = kr_ta_get(trust_anchors, name); + if (!ta_rr) { + ta_rr = knot_rrset_new(name, type, KNOT_CLASS_IN, NULL); + is_new_key = true; } - - return found; -} - -static int ta_add(struct trust_anchors_nolock *tan, const char *ta_str) -{ - assert(tan && ta_str); - - if (tan->used >= MAX_ANCHORS) { + /* Merge-in new key data */ + if (!ta_rr || knot_rrset_add_rdata(ta_rr, rdata, rdlen, ttl, NULL) != 0) { + knot_rrset_free(&ta_rr, NULL); return kr_error(ENOMEM); } - - knot_rrset_t *ta = NULL; - int ret = kr_ta_parse(&ta, ta_str, &tan->pool); - if (ret != 0) { - return ret; - } - assert(ta); - - knot_rrset_t *found = ta_find(tan, ta->owner); - if (!found) { - tan->anchors[tan->used++] = ta; - return kr_ok(); + /* Reinsert */ + if (is_new_key) { + map_set(trust_anchors, (const char *)name, ta_rr); } - if (found->type != ta->type) { - knot_rrset_free(&ta, &tan->pool); - return kr_error(EINVAL); - } - - ret = knot_rdataset_merge(&found->rrs, &ta->rrs, &tan->pool); - knot_rrset_free(&ta, &tan->pool); - if (ret != 0) { - return ret; - } - - return kr_ok(); -} - -int kr_ta_add(struct trust_anchors *tas, const char *ta_str) -{ - if (!tas || !ta_str) { - return kr_error(EINVAL); - } - - int ret = pthread_rwlock_wrlock(&tas->rwlock); - if (ret != 0) { - return kr_error(ret); - } - - ret = ta_add(&tas->locked, ta_str); - - pthread_rwlock_unlock(&tas->rwlock); - return ret; -} - -static int ta_get(knot_rrset_t **ta, struct trust_anchors_nolock *tan, const knot_dname_t *name, mm_ctx_t *pool) -{ - assert(ta && tan && name); - - knot_rrset_t *copy = ta_find(tan, name); - if (!copy) { - kr_error(ENOENT); - } - - copy = knot_rrset_copy(copy, pool); - if (!copy) { - kr_error(ENOMEM); - } - - *ta = copy; - - return kr_ok(); + return kr_ok(); } -int kr_ta_contains(struct trust_anchors *tas, const knot_dname_t *name) -{ - return ta_find(&tas->locked, name) != NULL; -} - -int kr_ta_covers(struct trust_anchors *tas, const knot_dname_t *name) +int kr_ta_covers(map_t *trust_anchors, const knot_dname_t *name) { while(name) { - if (kr_ta_contains(tas, name)) { + if (kr_ta_get(trust_anchors, name)) { return true; } if (name[0] == '\0') { @@ -656,63 +75,29 @@ int kr_ta_covers(struct trust_anchors *tas, const knot_dname_t *name) } name = knot_wire_next_label(name, NULL); } - return false; -} - -int kr_ta_get(knot_rrset_t **ta, struct trust_anchors *tas, const knot_dname_t *name, mm_ctx_t *pool) -{ - if (!ta || !tas || !name) { - return kr_error(EINVAL); - } - - int ret = pthread_rwlock_rdlock(&tas->rwlock); - if (ret != 0) { - return kr_error(ret); - } - - ret = ta_get(ta, &tas->locked, name, pool); - - pthread_rwlock_unlock(&tas->rwlock); - return ret; -} - -int kr_ta_rdlock(struct trust_anchors *tas) -{ - if (!tas) { - return kr_error(EINVAL); - } - - return pthread_rwlock_rdlock(&tas->rwlock); + return false; } -int kr_ta_unlock(struct trust_anchors *tas) +/* Delete record data */ +static int del_record(const char *k, void *v, void *ext) { - if (!tas) { - return kr_error(EINVAL); - } - - return pthread_rwlock_unlock(&tas->rwlock); + knot_rrset_t *ta_rr = v; + knot_rrset_free(&ta_rr, NULL); + return 0; } -int kr_ta_rrs_count_nolock(struct trust_anchors *tas) +int kr_ta_del(map_t *trust_anchors, const knot_dname_t *name) { - if (!tas) { - return kr_error(EINVAL); + knot_rrset_t *ta_rr = kr_ta_get(trust_anchors, name); + if (ta_rr) { + del_record(NULL, ta_rr, NULL); + map_del(trust_anchors, (const char *)name); } - - return tas->locked.used; + return kr_ok(); } -int kr_ta_rrs_at_nolock(const knot_rrset_t **ta, struct trust_anchors *tas, size_t pos) +void kr_ta_clear(map_t *trust_anchors) { - if (!tas || !ta) { - return kr_error(EINVAL); - } - - if (pos >= tas->locked.used) { - return kr_error(EINVAL); - } - - *ta = tas->locked.anchors[pos]; - return kr_ok(); + map_walk(trust_anchors, del_record, NULL); + map_clear(trust_anchors); } diff --git a/lib/dnssec/ta.h b/lib/dnssec/ta.h index 3900044373bc2a11c80ba6a216f86d1e9d07a135..6c712a0db162205b985d01c66d837ea8e77f8a4d 100644 --- a/lib/dnssec/ta.h +++ b/lib/dnssec/ta.h @@ -16,46 +16,49 @@ #pragma once -#include <libknot/internal/mempattern.h> +#include "lib/generic/map.h" #include <libknot/rrset.h> -//#define ROOT_TA ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5" -#define ROOT_NAME ((const uint8_t *) "") -#define ROOT_TA ". IN DS 19036 RSASHA256 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5" -//#define ROOT_TA ". IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq QxA+Uk1ihz0=" - /** - * Parses the supplied trust anchor string and creates a new RRSet. - * - * @param rr created resource record - * @param ds_str DS in presentation format - * @param pool - * @return 0 or an error code + * Find TA RRSet by name. + * @param trust_anchors trust store + * @param name name of the TA + * @return non-empty RRSet or NULL */ -int kr_ta_parse(knot_rrset_t **rr, const char *ds_str, mm_ctx_t *pool); - -/** Trust anchor container structure. */ -struct trust_anchors; - -/** Global trust anchor container. */ -extern struct trust_anchors global_trust_anchors; - -int kr_ta_init(struct trust_anchors *tas); - -void kr_ta_deinit(struct trust_anchors *tas); - -int kr_ta_reset(struct trust_anchors *tas, const char *ta_str); - -int kr_ta_add(struct trust_anchors *tas, const char *ta_str); - -int kr_ta_contains(struct trust_anchors *tas, const knot_dname_t *name); +knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name); -int kr_ta_covers(struct trust_anchors *tas, const knot_dname_t *name); +/** + * Add TA to trust store. DS or DNSKEY types are supported. + * @param trust_anchors trust store + * @param name name of the TA + * @param type RR type of the TA (DS or DNSKEY) + * @param ttl + * @param rdata + * @param rdlen + * @return 0 or an error + */ +int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type, + uint32_t ttl, const uint8_t *rdata, uint16_t rdlen); -int kr_ta_get(knot_rrset_t **ta, struct trust_anchors *tas, const knot_dname_t *name, mm_ctx_t *pool); +/** + * Return true if the name is below/at any TA in the store. + * This can be useful to check if it's possible to validate a name beforehand. + * @param trust_anchors trust store + * @param name name of the TA + * @return boolean + */ +int kr_ta_covers(map_t *trust_anchors, const knot_dname_t *name); -int kr_ta_rdlock(struct trust_anchors *tas); -int kr_ta_unlock(struct trust_anchors *tas); +/** + * Remove TA from trust store. + * @param trust_anchors trust store + * @param name name of the TA + * @return 0 or an error + */ +int kr_ta_del(map_t *trust_anchors, const knot_dname_t *name); -int kr_ta_rrs_count_nolock(struct trust_anchors *tas); -int kr_ta_rrs_at_nolock(const knot_rrset_t **ta, struct trust_anchors *tas, size_t pos); +/** + * Clear trust store. + * @param trust_anchors trust store + */ +void kr_ta_clear(map_t *trust_anchors); diff --git a/lib/layer/validate.c b/lib/layer/validate.c index e09a67289aafc3bd0e11068fa77c258993bf57a7..31c8da944b9655f74f3555b4ba26797c451648eb 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -20,44 +20,22 @@ #include <stdio.h> #include <string.h> -#include <ccan/json/json.h> #include <libknot/packet/wire.h> -#include <libknot/rrset-dump.h> #include <libknot/rrtype/rdname.h> #include <libknot/rrtype/rrsig.h> #include "lib/dnssec/nsec.h" #include "lib/dnssec/nsec3.h" #include "lib/dnssec/packet/pkt.h" -#include "lib/dnssec/ta.h" #include "lib/dnssec.h" #include "lib/layer.h" #include "lib/resolve.h" #include "lib/rplan.h" #include "lib/defines.h" -#include "lib/nsrep.h" #include "lib/module.h" #define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "vldr", fmt) -static knot_dump_style_t KNOT_DUMP_STYLE_TA = { - .wrap = false, - .show_class = true, - .show_ttl = false, - .verbose = false, - .empty_ttl = false, - .human_ttl = false, - .human_tmstamp = true, - .ascii_to_idn = NULL -}; - -/* Set resolution context and parameters. */ -static int begin(knot_layer_t *ctx, void *module_param) -{ - ctx->data = module_param; - return KNOT_STATE_PRODUCE; -} - struct rrset_ids { const knot_dname_t *owner; uint16_t type; @@ -505,99 +483,10 @@ static int validate(knot_layer_t *ctx, knot_pkt_t *pkt) DEBUG_MSG(qry, "<= answer valid, OK\n"); return ctx->state; } - -static int rrset_txt_dump_line(const knot_rrset_t *rrset, size_t pos, - char *dst, const size_t maxlen, const knot_dump_style_t *style) -{ - assert(rrset && dst && maxlen && style); - - int written = 0; - uint32_t ttl = knot_rdata_ttl(knot_rdataset_at(&rrset->rrs, 0)); - int ret = knot_rrset_txt_dump_header(rrset, ttl, dst + written, maxlen - written, style); - if (ret <= 0) { - return ret; - } - written += ret; - ret = knot_rrset_txt_dump_data(rrset, pos, dst + written, maxlen - written, style); - if (ret <= 0) { - return ret; - } - written += ret; - - return written; -} - -static char *validate_trust_anchors(void *env, struct kr_module *module, const char *args) -{ -#define MAX_BUF_LEN 1024 - JsonNode *root = json_mkarray(); - - kr_ta_rdlock(&global_trust_anchors); - - const knot_rrset_t *ta; - int count = kr_ta_rrs_count_nolock(&global_trust_anchors); - for (int i = 0; i < count; ++i) { - ta = NULL; - kr_ta_rrs_at_nolock(&ta, &global_trust_anchors, i); - assert(ta); - char buf[MAX_BUF_LEN]; - for (uint16_t j = 0; j < ta->rrs.rr_count; ++j) { - buf[0] = '\0'; - rrset_txt_dump_line(ta, j, buf, MAX_BUF_LEN, &KNOT_DUMP_STYLE_TA); - json_append_element(root, json_mkstring(buf)); - } - } - - kr_ta_unlock(&global_trust_anchors); - - char *result = json_encode(root); - json_delete(root); - return result; -#undef MAX_BUF_LEN -} - -static char *validate_trust_anchor_add(void *env, struct kr_module *module, const char *args) -{ - int ret = 0; - if (!args || (args[0] == '\0')) { - ret = kr_error(EINVAL); - } else { - ret = kr_ta_add(&global_trust_anchors, args); - } - - char *result = NULL; - asprintf(&result, "{ \"result\": %s }", ret == 0 ? "true" : "false"); - return result; -} - -static int load(struct trust_anchors *tas, const char *path) -{ -#define MAX_LINE_LEN 512 - auto_fclose FILE *fp = fopen(path, "r"); - if (fp == NULL) { - DEBUG_MSG(NULL, "reading '%s' failed: %s\n", path, strerror(errno)); - return kr_error(errno); - } else { - DEBUG_MSG(NULL, "reading '%s'\n", path); - } - - char line[MAX_LINE_LEN]; - while (fgets(line, sizeof(line), fp) != NULL) { - int ret = kr_ta_add(tas, line); - if (ret != 0) { - return ret; - } - } - - return kr_ok(); -#undef MAX_LINE_LEN -} - /** Module implementation. */ const knot_layer_api_t *validate_layer(struct kr_module *module) { static const knot_layer_api_t _layer = { - .begin = &begin, .consume = &validate, }; /* Store module reference */ @@ -606,42 +495,7 @@ const knot_layer_api_t *validate_layer(struct kr_module *module) int validate_init(struct kr_module *module) { - int ret = kr_ta_init(&global_trust_anchors); - if (ret != 0) { - return ret; - } -// /* Add root trust anchor. */ -// ret = kr_ta_add(&global_trust_anchors, ROOT_TA); - if (ret != 0) { - return ret; - } - return kr_ok(); -} - -int validate_config(struct kr_module *module, const char *conf) -{ - int ret = kr_ta_reset(&global_trust_anchors, NULL); - if (ret != 0) { - return ret; - } - return load(&global_trust_anchors, conf); -} - -int validate_deinit(struct kr_module *module) -{ - kr_ta_deinit(&global_trust_anchors); return kr_ok(); } -const struct kr_prop validate_prop_list[] = { - { &validate_trust_anchors, "trust_anchors", "Retrieve trust anchors.", }, - { &validate_trust_anchor_add, "trust_anchor_add", "Adds a trust anchor.", }, - { NULL, NULL, NULL } -}; - -struct kr_prop *validate_props(void) -{ - return (struct kr_prop *) validate_prop_list; -} - KR_MODULE_EXPORT(validate) diff --git a/lib/module.c b/lib/module.c index 53cfbe15c892e26e9f912369016c314f6ad3c8a0..071394940611722b5cb47b4441e181ed2a8e0097 100644 --- a/lib/module.c +++ b/lib/module.c @@ -25,16 +25,12 @@ /* List of embedded modules */ const knot_layer_api_t *iterate_layer(struct kr_module *module); -int validate_init(struct kr_module *module); -int validate_deinit(struct kr_module *module); -int validate_config(struct kr_module *module, const char *conf); const knot_layer_api_t *validate_layer(struct kr_module *module); -extern struct kr_prop validate_prop_list[]; 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[] = { { "iterate", NULL, NULL, NULL, iterate_layer, NULL, NULL, NULL }, - { "validate", validate_init, validate_deinit, validate_config, validate_layer, validate_prop_list, NULL, NULL }, + { "validate", NULL, NULL, NULL, validate_layer, NULL, NULL, NULL }, { "rrcache", NULL, NULL, NULL, rrcache_layer, NULL, NULL, NULL }, { "pktcache", NULL, NULL, NULL, pktcache_layer, NULL, NULL, NULL }, }; diff --git a/lib/resolve.c b/lib/resolve.c index 6e6280e9fd3bbaaf3b80891e1b8d4900b8c6d646..074cbfe32d73853c6b96adde4be317026bb197de 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -248,7 +248,9 @@ static int resolve_query(struct kr_request *request, const knot_pkt_t *packet) /* Deferred zone cut lookup for this query. */ qry->flags |= QUERY_AWAIT_CUT; - if (knot_pkt_has_dnssec(packet)) { + /* Want DNSSEC if it's posible to secure this name (e.g. is covered by any TA) */ + map_t *trust_anchors = &request->ctx->trust_anchors; + if (knot_pkt_has_dnssec(packet) && kr_ta_covers(trust_anchors, qname)) { qry->flags |= QUERY_DNSSEC_WANT; } @@ -354,12 +356,13 @@ static int zone_cut_subreq(struct kr_rplan *rplan, struct kr_query *parent, static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot_pkt_t *packet) { struct kr_rplan *rplan = &request->rplan; + map_t *trust_anchors = &request->ctx->trust_anchors; /* The query wasn't resolved from cache, * now it's the time to look up closest zone cut from cache. */ if (qry->flags & QUERY_AWAIT_CUT) { /* Want DNSSEC if it's posible to secure this name (e.g. is covered by any TA) */ - if (kr_ta_covers(&global_trust_anchors, qry->zone_cut.name)) { + if (kr_ta_covers(trust_anchors, qry->zone_cut.name)) { qry->flags |= QUERY_DNSSEC_WANT; } int ret = ns_fetch_cut(qry, request, (qry->flags & QUERY_DNSSEC_WANT)); @@ -376,7 +379,7 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot } /* Enable DNSSEC if enters a new island of trust. */ bool want_secured = (qry->flags & QUERY_DNSSEC_WANT); - if (!want_secured && kr_ta_contains(&global_trust_anchors, qry->zone_cut.name)) { + if (!want_secured && kr_ta_get(trust_anchors, qry->zone_cut.name)) { qry->flags |= QUERY_DNSSEC_WANT; want_secured = true; WITH_DEBUG { @@ -387,8 +390,8 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot } /* @todo Disable DNSSEC if it encounters NTA */ if (want_secured && !qry->zone_cut.trust_anchor) { - kr_ta_get(&qry->zone_cut.trust_anchor, &global_trust_anchors, - qry->zone_cut.name, qry->zone_cut.pool); + knot_rrset_t *ta_rr = kr_ta_get(trust_anchors, qry->zone_cut.name); + qry->zone_cut.trust_anchor = knot_rrset_copy(ta_rr, qry->zone_cut.pool); } /* Try to fetch missing DS. */ if (want_secured && (qry->flags & QUERY_AWAIT_DS)) { diff --git a/lib/resolve.h b/lib/resolve.h index c373819b7d9fa25c2e8ab7c2227bf3405487a3f9..d185fe48412a4b402f778573511036bacc9ca3a3 100644 --- a/lib/resolve.h +++ b/lib/resolve.h @@ -20,6 +20,7 @@ #include <libknot/processing/layer.h> #include <libknot/packet/pkt.h> +#include "lib/generic/map.h" #include "lib/generic/array.h" #include "lib/nsrep.h" #include "lib/rplan.h" @@ -81,15 +82,16 @@ typedef array_t(struct kr_module *) module_array_t; * be shared between threads. */ struct kr_context -{ - mm_ctx_t *pool; +{ + uint32_t options; + knot_rrset_t *opt_rr; + map_t trust_anchors; struct kr_zonecut root_hints; struct kr_cache cache; kr_nsrep_lru_t *cache_rtt; kr_nsrep_lru_t *cache_rep; module_array_t *modules; - knot_rrset_t *opt_rr; - uint32_t options; + mm_ctx_t *pool; }; /** diff --git a/tests/kresd.j2 b/tests/kresd.j2 index 72b89cea37fe284d18a42fb498d52f8462ce46e3..2f787b5cf5da8a90ee5170d3391c6434430530f0 100644 --- a/tests/kresd.j2 +++ b/tests/kresd.j2 @@ -1,10 +1,10 @@ -net.listen('{{SELF_ADDR}}',53) -cache.size = 1*MB +net = { '{{SELF_ADDR}}' } modules = {'stats', 'policy', 'hints'} +cache.size = 1*MB hints.root({['k.root-servers.net'] = '{{ROOT_ADDR}}'}) option('NO_MINIMIZE', {{NO_MINIMIZE}}) option('ALLOW_LOCAL', true) -validate.trust_anchor_add('{{TRUST_ANCHOR}}') +trust_anchors.add('{{TRUST_ANCHOR}}') verbose(true) -- Self-checks on globals