From 62001974db6f114da2cde037a87ee8eb250b88da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz> Date: Thu, 22 Oct 2015 15:13:01 +0200 Subject: [PATCH] iterator+rrcache: do not follow CNAME chains (if not DNSSEC-secured) [1] shows an attack using spoofed CNAME targets to replace legitimate entries in resolver cache by speeding up once-per-TTL attack opportunity as a defense, the resolver almost always requeries CNAME targets and doesn't store them in cache. the only exception is when the CNAME target is within current authority, and the answer is DNSSEC-secured thanks to Toshinori Maeno (@beyondDNS) for pointing this out [2] [1]: https://tools.ietf.org/id/draft-weaver-dnsext-comprehensive- resolver-00.html [2]: https://moin.qmail.jp/DNS/KnotResolver/CNAMEpatch --- lib/layer/iterate.c | 4 ++-- lib/layer/rrcache.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index da59fc382..f2d7f36fc 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -363,10 +363,10 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req) if (state == KNOT_STATE_FAIL) { return state; } - /* Follow chain only within current cut. */ + /* Follow chain only within current cut (if secure). */ if (follow_chain) { follow_cname_chain(&cname, rr, query); - if (!knot_dname_in(query->zone_cut.name, cname)) { + if (!(query->flags & QUERY_DNSSEC_WANT) || !knot_dname_in(query->zone_cut.name, cname)) { follow_chain = false; } } diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c index 623f6fe24..dfd2cec41 100644 --- a/lib/layer/rrcache.c +++ b/lib/layer/rrcache.c @@ -260,8 +260,8 @@ static int stash_answer(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, mm_ continue; } kr_rrmap_add(stash, rr, KR_RANK_AUTH, pool); - /* Follow CNAME chain in current cut. */ - if (rr->type == KNOT_RRTYPE_CNAME) { + /* Follow CNAME chain in current cut (if SECURE). */ + if ((qry->flags & QUERY_DNSSEC_WANT) && rr->type == KNOT_RRTYPE_CNAME) { const knot_dname_t *next_cname = knot_cname_name(&rr->rrs); if (knot_dname_in(qry->zone_cut.name, next_cname)) { cname = next_cname; -- GitLab