commit 1be69820c7a7ddfe558ecd21f88ad79d2b2a2a37 Author: Vladimír Čunát Date: Fri Nov 29 16:15:10 2019 +0100 iterate: fix limit on CNAME chain length The accounting was just broken and overly messy anyway. diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index e59294bb..2ed35cb1 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -280,6 +280,7 @@ struct kr_query { struct timeval timestamp; struct kr_zonecut zone_cut; struct kr_layer_pickle *deferred; + int8_t cname_depth; struct kr_query *cname_parent; struct kr_request *request; kr_stale_cb stale_cb; diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 069b34f0..9a78b23d 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -501,10 +501,11 @@ static int unroll_cname(knot_pkt_t *pkt, struct kr_request *req, bool referral, const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER); const knot_dname_t *cname = NULL; const knot_dname_t *pending_cname = query->sname; - unsigned cname_chain_len = 0; bool is_final = (query->parent == NULL); - uint32_t iter_count = 0; bool strict_mode = (query->flags.STRICT); + + query->cname_depth = query->cname_parent ? query->cname_parent->cname_depth : 1; + do { /* CNAME was found at previous iteration, but records may not follow the correct order. * Try to find records for pending_cname owner from section start. */ @@ -562,21 +563,22 @@ static int unroll_cname(knot_pkt_t *pkt, struct kr_request *req, bool referral, if ((query->stype == KNOT_RRTYPE_CNAME) || (rr->type != KNOT_RRTYPE_CNAME)) { continue; } - cname_chain_len += 1; pending_cname = knot_cname_name(rr->rrs.rdata); if (!pending_cname) { break; } - if (cname_chain_len > an->count || cname_chain_len > KR_CNAME_CHAIN_LIMIT) { - VERBOSE_MSG("<= too long cname chain\n"); - return KR_STATE_FAIL; - } /* Don't use pending_cname immediately. * There are can be records for "old" cname. */ } if (!pending_cname) { break; } + if (++(query->cname_depth) > KR_CNAME_CHAIN_LIMIT) { + VERBOSE_MSG("<= cname chain longer than %d\n", + (int)KR_CNAME_CHAIN_LIMIT); + return KR_STATE_FAIL; + } + if (knot_dname_is_equal(cname, pending_cname)) { VERBOSE_MSG("<= cname chain loop\n"); return KR_STATE_FAIL; @@ -605,11 +607,7 @@ static int unroll_cname(knot_pkt_t *pkt, struct kr_request *req, bool referral, cname = pending_cname; break; } - } while (++iter_count < KR_CNAME_CHAIN_LIMIT); - if (iter_count >= KR_CNAME_CHAIN_LIMIT) { - VERBOSE_MSG("<= too long cname chain\n"); - return KR_STATE_FAIL; - } + } while (true); *cname_ret = cname; return kr_ok(); } diff --git a/lib/rplan.h b/lib/rplan.h index 15ca5633..0f9377dd 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -104,6 +104,10 @@ struct kr_query { struct timeval timestamp; /**< Real time for TTL+DNSSEC checks (.tv_sec only). */ struct kr_zonecut zone_cut; struct kr_layer_pickle *deferred; + + /** Current xNAME depth, set by iterator. 0 = uninitialized, 1 = no CNAME, ... + * See also KR_CNAME_CHAIN_LIMIT. */ + int8_t cname_depth; /** Pointer to the query that originated this one because of following a CNAME (or NULL). */ struct kr_query *cname_parent; struct kr_request *request; /**< Parent resolution request. */