diff --git a/daemon/engine.c b/daemon/engine.c index b2e2bcd81aaa0c6b8b8c498a5412d8aeebe828dc..af71bcef2e8529f08fea46233748f1449e730d3e 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -245,6 +245,7 @@ static int init_resolver(struct engine *engine) { /* Open resolution context */ engine->resolver.trust_anchors = map_make(); + engine->resolver.negative_anchors = map_make(); engine->resolver.pool = engine->pool; engine->resolver.modules = &engine->modules; /* Create OPT RR */ @@ -359,18 +360,19 @@ void engine_deinit(struct engine *engine) lru_deinit(engine->resolver.cache_rtt); lru_deinit(engine->resolver.cache_rep); - /* Unload modules. */ + /* Unload modules and engine. */ for (size_t i = 0; i < engine->modules.len; ++i) { engine_unload(engine, engine->modules.at[i]); } - array_clear(engine->modules); - array_clear(engine->storage_registry); - kr_ta_clear(&engine->resolver.trust_anchors); - if (engine->L) { lua_close(engine->L); } + /* Free data structures */ + array_clear(engine->modules); + array_clear(engine->storage_registry); + kr_ta_clear(&engine->resolver.trust_anchors); + kr_ta_clear(&engine->resolver.negative_anchors); } int engine_pcall(lua_State *L, int argc) diff --git a/daemon/lua/kres.lua b/daemon/lua/kres.lua index 649224a1fdc9b5aefb4dd754abf9628c89718454..ee2e34abd2267e85441760172a6c8f4d94946e9d 100644 --- a/daemon/lua/kres.lua +++ b/daemon/lua/kres.lua @@ -166,13 +166,21 @@ struct kr_context uint32_t options; knot_rrset_t *opt_rr; map_t trust_anchors; + map_t negative_anchors; uint8_t _stub[]; /* Do not touch */ }; -/* libknot API +/* + * libc APIs */ +void free(void *ptr); +/* + * libknot APIs + */ /* Domain names */ +knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen); +char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen); /* Resource records */ /* Packet */ const knot_dname_t *knot_pkt_qname(const knot_pkt_t *pkt); @@ -181,9 +189,9 @@ uint16_t knot_pkt_qclass(const knot_pkt_t *pkt); int knot_pkt_begin(knot_pkt_t *pkt, int section_id); int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype); -/* libkres API +/* + * libkres API */ - /* Resolution request */ struct kr_rplan *kr_resolve_plan(struct kr_request *request); /* Resolution plan */ @@ -259,6 +267,24 @@ ffi.metatype( kr_request_t, { }, }) +-- Module API +local kres_context = ffi.cast('struct kr_context *', __engine) +local kres = { + -- Constants + class = ffi.new('struct rr_class'), + type = ffi.new('struct rr_type'), + section = ffi.new('struct pkt_section'), + rcode = ffi.new('struct pkt_rcode'), + NOOP = 0, CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8, + -- Metatypes + 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 + str2dname = function(name) return ffi.string(ffi.gc(C.knot_dname_from_str(nil, name, 0), C.free)) end, + dname2str = function(dname) return ffi.string(ffi.gc(C.knot_dname_to_str(nil, dname, 0), C.free)) end, + context = function () return kres_context end, +} + -- Return DS/DNSKEY parser that adds keys to TA store local function ta_parser(store) local parser = require('zonefile').parser(function (p) @@ -268,38 +294,26 @@ local function ta_parser(store) end -- TA store management -local trust_anchors = { - current_file = "", - is_auto = false, - store = ffi.cast('struct kr_context *', __engine).trust_anchors, +kres.trust_anchors = { -- Load keys from a file config = function (path) - ta_parser(trust_anchors.store):parse_file(path) - trust_anchors.current_file = path + ta_parser(kres_context.trust_anchors):parse_file(path) + kres.trust_anchors.current_file = path + end, + -- Add DS/DNSKEY record(s) + add = function (ds) ta_parser(kres_context.trust_anchors):read(ds..'\n') end, + -- Negative TA management + set_insecure = function (list) + C.kr_ta_clear(kres_context.negative_anchors) + for i = 1, #list do + local dname = kres.str2dname(list[i]) + C.kr_ta_add(kres_context.negative_anchors, dname, kres.type.DS, 0, nil, 0) + end 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 - class = ffi.new('struct rr_class'), - type = ffi.new('struct rr_type'), - section = ffi.new('struct pkt_section'), - rcode = ffi.new('struct pkt_rcode'), - NOOP = 0, CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8, - -- Metatypes - 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 a918bf75ec89bc7fbe6cddf87afc5b173dff9219..8ae4947b954472a8e14d6243c2b86addf9fa0f1f 100644 --- a/daemon/lua/sandbox.lua +++ b/daemon/lua/sandbox.lua @@ -70,6 +70,7 @@ setmetatable(trust_anchors, { __newindex = function (t,k,v) if k == 'file' then t.config(v) elseif k == 'auto' then t.set_auto(v) + elseif k == 'negative' then t.set_insecure(v) else rawset(t, k, v) end end, }) diff --git a/lib/dnssec/ta.c b/lib/dnssec/ta.c index e39eef8045b6bb35cfc0512e666382f847cc679f..2ecb1229202a58eb8d453ab80f861400e90472d0 100644 --- a/lib/dnssec/ta.c +++ b/lib/dnssec/ta.c @@ -30,7 +30,7 @@ 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) { - if (!trust_anchors || !name || !rdata) { + if (!trust_anchors || !name) { return kr_error(EINVAL); } @@ -52,7 +52,7 @@ int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type, is_new_key = true; } /* Merge-in new key data */ - if (!ta_rr || knot_rrset_add_rdata(ta_rr, rdata, rdlen, ttl, NULL) != 0) { + if (!ta_rr || (rdlen > 0 && knot_rrset_add_rdata(ta_rr, rdata, rdlen, ttl, NULL) != 0)) { knot_rrset_free(&ta_rr, NULL); return kr_error(ENOMEM); } @@ -82,7 +82,9 @@ int kr_ta_covers(map_t *trust_anchors, const knot_dname_t *name) static int del_record(const char *k, void *v, void *ext) { knot_rrset_t *ta_rr = v; - knot_rrset_free(&ta_rr, NULL); + if (ta_rr) { + knot_rrset_free(&ta_rr, NULL); + } return 0; } diff --git a/lib/resolve.c b/lib/resolve.c index 074cbfe32d73853c6b96adde4be317026bb197de..a9eea382ab3f38a26a670b0a63af2916430e2d39 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -357,12 +357,14 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot { struct kr_rplan *rplan = &request->rplan; map_t *trust_anchors = &request->ctx->trust_anchors; + map_t *negative_anchors = &request->ctx->negative_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(trust_anchors, qry->zone_cut.name)) { + if (!kr_ta_covers(negative_anchors, qry->zone_cut.name) && + 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)); @@ -377,6 +379,11 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot } qry->flags &= ~QUERY_AWAIT_CUT; } + /* Disable DNSSEC if it enters NTA. */ + if (kr_ta_get(negative_anchors, qry->zone_cut.name)){ + DEBUG_MSG(">< negative TA, going insecure\n"); + 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_get(trust_anchors, qry->zone_cut.name)) { @@ -388,7 +395,6 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot DEBUG_MSG(">< TA: using '%s'\n", qname_str); } } - /* @todo Disable DNSSEC if it encounters NTA */ if (want_secured && !qry->zone_cut.trust_anchor) { 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); diff --git a/lib/resolve.h b/lib/resolve.h index d185fe48412a4b402f778573511036bacc9ca3a3..deaaa9e18fd09f0dcc87f9266250b500ca874e1e 100644 --- a/lib/resolve.h +++ b/lib/resolve.h @@ -86,6 +86,7 @@ struct kr_context uint32_t options; knot_rrset_t *opt_rr; map_t trust_anchors; + map_t negative_anchors; struct kr_zonecut root_hints; struct kr_cache cache; kr_nsrep_lru_t *cache_rtt; diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index 84276cb6ee8a2bf250beaf291767baea28ced431..4a8b28c390b60ae31cc1b2be76738cd8d9c35b86 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -148,9 +148,7 @@ end -- Convert list of string names to domain names function policy.to_domains(names) for i, v in ipairs(names) do - names[i] = v:gsub('([^.]*%.)', function (x) - return string.format('%s%s', string.char(x:len()-1), x:sub(1,-2)) - end) + names[i] = kres.str2dname(v) end end diff --git a/tests/pydnstest/scenario.py b/tests/pydnstest/scenario.py index 29a40d466d41dab25251a94a228674a94efd28ad..eaae8a1e8771d1f5097a07f117bac21db3ed79cf 100644 --- a/tests/pydnstest/scenario.py +++ b/tests/pydnstest/scenario.py @@ -330,6 +330,7 @@ class Step: # Wait for a response for a reasonable time answer = None if not self.data[0].is_raw_data_entry: + ctx.child_sock.settimeout(1) answer, addr = ctx.child_sock.recvfrom(4096) # Remember last answer for checking later self.raw_answer = answer