#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
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 */
}
array_clear(engine->modules);
array_clear(engine->storage_registry);
+ kr_ta_clear(&engine->resolver.trust_anchors);
if (engine->L) {
lua_close(engine->L);
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"
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");
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;
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
*/
/* 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,
},
})
+-- 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
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
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
-- 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)
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') {
}
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);
}
#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);
#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;
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 */
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)
/* 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 },
};
/* 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;
}
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));
}
/* 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 {
}
/* @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)) {
#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"
* 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;
};
/**
-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