From: Marek VavruĊĦa Date: Thu, 9 Jul 2015 20:19:15 +0000 (+0200) Subject: lib: made tests pass again, cleanup X-Git-Tag: v1.0.0-beta1~53^2~168 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a70cdfbc4de85973c2ffdfea278cbdef0570d829;p=thirdparty%2Fknot-resolver.git lib: made tests pass again, cleanup --- diff --git a/lib/layer/rrsigcache.c b/lib/layer/rrsigcache.c deleted file mode 100644 index 915d4a2ec..000000000 --- a/lib/layer/rrsigcache.c +++ /dev/null @@ -1,393 +0,0 @@ -/* Copyright (C) 2014 CZ.NIC, z.s.p.o. - - 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 . - */ - -#include -#include -#include -#include -#include -#include - -#include "lib/layer/iterate.h" -#include "lib/cache.h" -#include "lib/module.h" - -#define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(rplan), "rrsc", fmt) -#define DEBUG_MSG_NOPLAN(fmt...) QRDEBUG(NULL, "rrsc", fmt) -//#define DEBUG_MSG(fmt...) -//#define DEBUG_MSG_NOPLAN(fmt...) - -static int begin(knot_layer_t *ctx, void *module_param) -{ - ctx->data = module_param; - return ctx->state; -} - -/** @internal Baton for stash_commit */ -struct stash_baton -{ - struct kr_cache_txn *txn; - unsigned timestamp; -}; - -static int commit_rrsig(const char *key, void *val, void *data) -{ - knot_rrset_t *rrsig = val; - struct stash_baton *baton = data; - if (knot_rrset_ttl(rrsig) < 1) { - return kr_ok(); /* Ignore cache busters. */ - } - /* Check if already cached */ - /** @todo This should check if less trusted data is in the cache, - for that the cache would need to trace data trust level. - */ - unsigned drift = baton->timestamp; - knot_rrset_t query_rrsig; - - knot_rrset_init(&query_rrsig, rrsig->owner, rrsig->type, rrsig->rclass); - if (kr_cache_peek_rrsig(baton->txn, &query_rrsig, &drift) == 0) { - return kr_ok(); - } - return kr_cache_insert_rrsig(baton->txn, rrsig, rrsig->type, baton->timestamp); -} - -static int stash_commit(map_t *stash, unsigned timestamp, struct kr_cache_txn *txn) -{ - struct stash_baton baton = { - .txn = txn, - .timestamp = timestamp - }; - return map_walk(stash, &commit_rrsig, &baton); - return kr_ok(); -} - -static int validate_rrsig(const knot_rrset_t *rrsig, size_t pos, const knot_rrset_t *rr, - struct kr_cache_txn *txn, struct kr_request *req) -{ - struct kr_rplan *rplan = &req->rplan; - struct kr_query *qry = kr_rplan_current(rplan); - uint32_t timestamp = qry->timestamp.tv_sec; - - const knot_dname_t *signer = knot_rrsig_signer_name(&rrsig->rrs, pos); - - knot_rrset_t dnskey_rr; - knot_rrset_init(&dnskey_rr, (knot_dname_t *)signer, KNOT_RRTYPE_DNSKEY, rr->rclass); - int ret = kr_cache_peek_rr(txn, &dnskey_rr, ×tamp); - if (ret != 0) { - return KNOT_DNSSEC_ENOKEY; - } - - return kr_ok(); -} - -static int merge_in_rrsigs(knot_rrset_t *cache_rr, const knot_rrset_t *rrsigset, const knot_rrset_t *rr, - struct kr_cache_txn *txn, struct kr_request *req) -{ - struct kr_rplan *rplan = &req->rplan; - struct kr_query *query = kr_rplan_current(&req->rplan); - int ret = KNOT_EOK; - - /* Find rrset corresponding to RRSIG. */ - for (unsigned i = 0; i < rrsigset->rrs.rr_count; ++i) { - if ((knot_rrsig_type_covered(&rrsigset->rrs, i) == rr->type) && - knot_dname_is_equal(cache_rr->owner, rrsigset->owner)) { - ret = validate_rrsig(rrsigset, i, rr, txn, req); - switch (ret) { - case KNOT_DNSSEC_ENOKEY: -#ifndef NDEBUG - { - char name_str[KNOT_DNAME_MAXLEN], type_str[16]; - knot_dname_to_str(name_str, knot_rrsig_signer_name(&rrsigset->rrs, i), sizeof(name_str)); - knot_rrtype_to_string(rr->type, type_str, sizeof(type_str)); - DEBUG_MSG_NOPLAN("%s() Missing DNSKEY for '%s %s'.\n", __func__, type_str, name_str); - } -#endif - DEBUG_MSG("<= missing DNSKEY\n"); - const knot_dname_t *signer = knot_rrsig_signer_name(&rrsigset->rrs, i); - struct kr_query *next = kr_rplan_push(rplan, query->parent, - signer, query->sclass, KNOT_RRTYPE_DNSKEY); - if (!next) { - return KNOT_STATE_FAIL; - } - rem_node(&query->node); /* *MUST* keep current query at tail */ - insert_node(&query->node, &next->node); - next->flags |= QUERY_AWAIT_CUT; - return ret; - break; - case 0: - break; - default: - return ret; - break; - } - - const knot_rdata_t *rdata = knot_rdataset_at(&rrsigset->rrs, i); - ret = knot_rdataset_add(&cache_rr->rrs, rdata, rplan->pool); - if (KNOT_EOK != ret) { - return ret; - } - } - } - - return ret; -} - -static int scan_for_rrsigs(knot_rrset_t *cache_rrsig, const knot_pktsection_t *section, - const knot_rrset_t *rr, struct kr_request *req) -{ - struct kr_rplan *rplan = &req->rplan; - struct kr_cache *cache = &req->ctx->cache; - - struct kr_cache_txn txn; - int ret = kr_cache_txn_begin(cache, &txn, 0); - if (0 != ret) { - return ret; - } - - knot_rrset_init(cache_rrsig, rr->owner, rr->type, rr->rclass); - for (uint16_t i = 0; i < section->count; ++i) { - const knot_rrset_t *rrset = knot_pkt_rr(section, i); - if (KNOT_RRTYPE_RRSIG != rrset->type) { - continue; - } - /* Currently only merge. Signature check is missing. */ - int ret = merge_in_rrsigs(cache_rrsig, rrset, rr, &txn, req); - if (KNOT_EOK != ret) { - knot_rrset_clear(cache_rrsig, rplan->pool); - kr_cache_txn_abort(&txn); - return ret; - } - } - - kr_cache_txn_abort(&txn); - return kr_ok(); -} - -static int stash_add_rrsig(map_t *stash, const knot_pktsection_t *section, - const knot_rrset_t *rr, struct kr_request *req) -{ - if (rr->type == KNOT_RRTYPE_RRSIG) { - return kr_ok(); - } - - struct kr_rplan *rplan = &req->rplan; - - /* Stash key = {[1-255] owner, [1-5] type covered, [1] \x00 } */ - char key[8 + KNOT_DNAME_MAXLEN]; - int ret = knot_dname_to_wire((uint8_t *)key, rr->owner, KNOT_DNAME_MAXLEN); - if (ret <= 0) { - return ret; - } - knot_dname_to_lower((uint8_t *)key); - ret = snprintf(key + ret - 1, sizeof(key) - KNOT_DNAME_MAXLEN, "%hu", rr->type); - if (ret <= 0 || ret >= KNOT_DNAME_MAXLEN) { - return kr_error(EILSEQ); - } - - /* Check if already exists */ - knot_rrset_t *stashed = map_get(stash, key); - if (stashed) { - return kr_ok(); - } - - /* Construct RRSIG RRSet containing related data. */ - knot_rrset_t cache_rrsig; - ret = scan_for_rrsigs(&cache_rrsig, section, rr, req); - if (ret != 0) { - return ret; - } - - if (cache_rrsig.rrs.rr_count) { - stashed = knot_rrset_copy(&cache_rrsig, rplan->pool); - if (!stashed) { - return kr_error(ENOMEM); - } - } - knot_rrset_clear(&cache_rrsig, rplan->pool); - if (stashed) { - return map_set(stash, key, stashed); - } - return kr_ok(); -} - -static void stash_glue(map_t *stash, knot_pkt_t *pkt, const knot_dname_t *ns_name, mm_ctx_t *pool) -{ - const knot_pktsection_t *additional = knot_pkt_section(pkt, KNOT_ADDITIONAL); - for (unsigned i = 0; i < additional->count; ++i) { - const knot_rrset_t *rr = knot_pkt_rr(additional, i); - if ((rr->type != KNOT_RRTYPE_A && rr->type != KNOT_RRTYPE_AAAA) || - !knot_dname_is_equal(rr->owner, ns_name)) { - continue; - } -// stash_add_rrsig(stash, additional, rr, pool); - } -} - -static int stash_authority(map_t *stash, knot_pkt_t *pkt, struct kr_request *req) -{ - struct kr_rplan *rplan = &req->rplan; - struct kr_query *qry = kr_rplan_current(rplan); - const knot_pktsection_t *authority = knot_pkt_section(pkt, KNOT_AUTHORITY); - for (unsigned i = 0; i < authority->count; ++i) { - const knot_rrset_t *rr = knot_pkt_rr(authority, i); - /* Cache in-bailiwick data only */ - if (!knot_dname_in(qry->zone_cut.name, rr->owner)) { - continue; - } - /* Look up glue records for NS */ - if (rr->type == KNOT_RRTYPE_NS) { - stash_glue(stash, pkt, knot_ns_name(&rr->rrs, 0), rplan->pool); - } - /* Ignore RRSIGs directly. */ - if (rr->type == KNOT_RRTYPE_RRSIG) { - continue; - } - /* Stash record */ - int ret = stash_add_rrsig(stash, authority, rr, req); - if (ret == KNOT_DNSSEC_ENOKEY) { - return ret; - } - } - return kr_ok(); -} - -static int stash_answer(map_t *stash, knot_pkt_t *pkt, struct kr_request *req) -{ - struct kr_rplan *rplan = &req->rplan; - struct kr_query *qry = kr_rplan_current(rplan); - const knot_dname_t *cname = qry->sname; - const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); - for (unsigned i = 0; i < answer->count; ++i) { - /* Stash direct answers (equal to current QNAME/CNAME) */ - const knot_rrset_t *rr = knot_pkt_rr(answer, i); - if (!knot_dname_is_equal(rr->owner, cname)) { - continue; - } - /* Ignore RRSIGs directly. */ - if (rr->type == KNOT_RRTYPE_RRSIG) { - continue; - } - int ret = stash_add_rrsig(stash, answer, rr, req); - if (ret == KNOT_DNSSEC_ENOKEY) { - return ret; - } - /* Follow CNAME chain */ - if (rr->type == KNOT_RRTYPE_CNAME) { - cname = knot_cname_name(&rr->rrs); - } else { - cname = qry->sname; - } - } - return kr_ok(); -} - -static int scan_rrsigs(map_t *stash, knot_pkt_t *pkt, struct kr_request *req) -{ - int ret = stash_authority(stash, pkt, req); - if (ret == 0 && knot_wire_get_aa(pkt->wire)) { - ret = stash_answer(stash, pkt, req); - } - return ret; -} - -static int stash(knot_layer_t *ctx, knot_pkt_t *pkt) -{ - /* Do nothing when no DNSSEC required. */ - bool dobit = knot_pkt_has_dnssec(pkt); - if (!dobit) { - return ctx->state; - } - - struct kr_request *req = ctx->data; - struct kr_rplan *rplan = &req->rplan; - -#ifndef NDEBUG - { - struct kr_query *qry = NULL; - WALK_LIST(qry, rplan->resolved) { - char qname_str[KNOT_DNAME_MAXLEN], qtype_str[16]; - knot_dname_to_str(qname_str, qry->sname, sizeof(qname_str)); - knot_rrtype_to_string(qry->stype, qtype_str, sizeof(qtype_str)); - - DEBUG_MSG("%s() resolved '%s %s' at %u\n", __func__, qtype_str, qname_str, qry->timestamp.tv_sec); - } - } -#endif - - struct kr_query *qry = kr_rplan_current(rplan); - if (!qry || ctx->state & KNOT_STATE_FAIL) { - return ctx->state; - } - - /* Cache only positive answers. */ - if (qry->flags & QUERY_CACHED || knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) { - return ctx->state; - } - /* Stash RRSIG data from the AUTHORITY and ANSWER. */ - map_t stash_rrsig = map_make(); - stash_rrsig.malloc = (map_alloc_f) mm_alloc; - stash_rrsig.free = (map_free_f) mm_free; - stash_rrsig.baton = rplan->pool; - int ret = scan_rrsigs(&stash_rrsig, pkt, req); - /* Cache stashed records */ - if (ret == 0) { - /* Open write transaction */ - struct kr_cache *cache = &req->ctx->cache; - struct kr_cache_txn txn; - if (kr_cache_txn_begin(cache, &txn, 0) == 0) { - ret = stash_commit(&stash_rrsig, qry->timestamp.tv_sec, &txn); - if (ret == 0) { - kr_cache_txn_commit(&txn); - } else { - kr_cache_txn_abort(&txn); - } - } - /* Clear if full */ - if (ret == KNOT_ESPACE) { - /* - * Commit empty transaction to make freed pages reclaimable - * (This increases the txnid) - */ - if (kr_cache_txn_begin(cache, &txn, 0) == 0) { - kr_cache_txn_commit(&txn); - } - /* Now drop the database */ - if (kr_cache_txn_begin(cache, &txn, 0) == 0) { - ret = kr_cache_clear(&txn); - if (ret == 0) { - kr_cache_txn_commit(&txn); - } else { - kr_cache_txn_abort(&txn); - } - } - } - } - - return ctx->state; -} - -/** Module implementation. */ -const knot_layer_api_t *rrsigcache_layer(struct kr_module *module) -{ - static const knot_layer_api_t _layer = { - .begin = &begin, - .consume = &stash - }; - - return &_layer; -} - -KR_MODULE_EXPORT(rrsigcache) diff --git a/lib/layer/validate.c b/lib/layer/validate.c index 58bcfdc3b..87c61c402 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -27,12 +27,11 @@ #include "lib/nsrep.h" #include "lib/module.h" -#define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(&req->rplan), "validate", fmt) +#define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(&req->rplan), "vldr", fmt) /* Set resolution context and parameters. */ static int begin(knot_layer_t *ctx, void *module_param) { -#warning TODO: set root trust anchor ctx->data = module_param; return KNOT_STATE_PRODUCE; } @@ -95,10 +94,17 @@ static int secure_query(knot_layer_t *ctx, knot_pkt_t *pkt) static int validate(knot_layer_t *ctx, knot_pkt_t *pkt) { + struct kr_request *req = ctx->data; + struct kr_query *query = kr_rplan_current(&req->rplan); + if (ctx->state & KNOT_STATE_FAIL) { + return ctx->state; + } #warning TODO: check if we have DNSKEY in qry->zone_cut and validate RRSIGS/proof, return FAIL if failed #warning TODO: we must also validate incoming DNSKEY records against the current zone cut TA #warning FLOW: first answer that comes here must have the DNSKEY that we can validate using TA - + DEBUG_MSG("checking query, dnskey: %d, secured: %d\n", + knot_pkt_qtype(pkt) == KNOT_RRTYPE_DNSKEY, + knot_pkt_has_dnssec(pkt)); return ctx->state; } @@ -108,7 +114,6 @@ const knot_layer_api_t *validate_layer(struct kr_module *module) static const knot_layer_api_t _layer = { .begin = &begin, .consume = &validate, - .produce = &secure_query }; return &_layer; } diff --git a/lib/resolve.c b/lib/resolve.c index 2910428cb..6a4409cbd 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -424,27 +424,6 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t DEBUG_MSG("query '%s %s'\n", type_str, name_str); #endif - /* 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) { - int ret = ns_fetch_cut(qry, request, true); - if (ret != 0) { - return KNOT_STATE_FAIL; - } - - if (!qry->zone_cut.key) { - /* Try to fetch missing DNSKEY. */ - /* TODO -- Fetch all missing DNSKEYS and DS records. */ - /* TODO -- Fetch DS at parent side of a zone cut. Fetch NS at the child side of the zone cut. */ - /* TODO -- Handle holes (sequences with missing delegation). */ - struct kr_query *next = kr_rplan_push(rplan, qry, qry->zone_cut.name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY); - if (!next) { - return kr_error(ENOMEM); - } - } - } - /* Resolve current query and produce dependent or finish */ int state = knot_overlay_produce(&request->overlay, packet); if (state != KNOT_STATE_FAIL && knot_wire_get_qr(packet->wire)) { @@ -469,15 +448,28 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t */ if (qry->flags & QUERY_AWAIT_CUT) { qry->flags &= ~QUERY_AWAIT_CUT; + bool want_secured = knot_pkt_has_dnssec(request->answer); + int ret = ns_fetch_cut(qry, request, want_secured); + if (ret != 0) { + return KNOT_STATE_FAIL; + } + /* Try to fetch missing DNSKEY. */ + if (want_secured && !qry->zone_cut.key && qry->stype != KNOT_RRTYPE_DNSKEY) { + /* TODO -- Fetch all missing DNSKEYS and DS records. */ + /* TODO -- Fetch DS at parent side of a zone cut. Fetch NS at the child side of the zone cut. */ + /* TODO -- Handle holes (sequences with missing delegation). */ + struct kr_query *next = kr_rplan_push(rplan, qry, qry->zone_cut.name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY); + if (!next) { + return kr_error(ENOMEM); + } + return KNOT_STATE_PRODUCE; + } /* Update minimized QNAME if zone cut changed */ if (qry->zone_cut.name[0] != '\0' && !(qry->flags & QUERY_NO_MINIMIZE)) { if (kr_make_query(qry, packet) != 0) { return KNOT_STATE_FAIL; } } - } else if (qry->flags & QUERY_AWAIT_TRUST) { -#warning TODO: request DNSKEY in the same way as in the ns_fetch_cut() -#warning FLOW: this will put current query on hold and resolve DNSKEY first, so we can validate } ns_election: diff --git a/lib/rplan.h b/lib/rplan.h index d64f0b58f..546b35577 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -34,7 +34,6 @@ X(AWAIT_IPV4 , 1 << 4) /**< Query is waiting for A address. */ \ X(AWAIT_IPV6 , 1 << 5) /**< Query is waiting for AAAA address. */ \ X(AWAIT_CUT , 1 << 6) /**< Query is waiting for zone cut lookup */ \ - X(AWAIT_TRUST, 1 << 7) /**< Query is waiting for trust anchor and key */ \ X(SAFEMODE , 1 << 8) /**< Don't use fancy stuff (EDNS...) */ \ X(CACHED , 1 << 9) /**< Query response is cached. */ diff --git a/tests/test_zonecut.c b/tests/test_zonecut.c index 772de3e99..939ccc83a 100644 --- a/tests/test_zonecut.c +++ b/tests/test_zonecut.c @@ -32,7 +32,7 @@ static void test_zonecut_params(void **state) assert_null((void *)kr_zonecut_find(NULL, NULL)); assert_null((void *)kr_zonecut_find(&cut, NULL)); assert_int_not_equal(kr_zonecut_set_sbelt(NULL, NULL), 0); - assert_int_not_equal(kr_zonecut_find_cached(NULL, NULL, NULL, NULL, 0), 0); + assert_int_not_equal(kr_zonecut_find_cached(NULL, NULL, NULL, NULL, 0, 0), 0); } #define TEST_IP(cut, ip, expect) { \