Commit e2e7c46a authored by Marek Vavruša's avatar Marek Vavruša

lib: saner TA store, in Lua module ‘trust_anchors’

preparations for TA rotation and management
in config:
trust_anchors.file = ‘root.key’
trust_anchors.auto = true // NOTIMPL
trust_anchors.add(‘. IN DS …’) // Manual addition
parent 3de7504d
......@@ -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");
......
......@@ -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
......@@ -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)
......
This diff is collapsed.
......@@ -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);
......@@ -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)
......@@ -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 },
};
......
......@@ -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)) {
......
......@@ -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;
};
/**
......
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
......
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