From: Grigorii Demidov Date: Wed, 21 Jun 2017 08:02:13 +0000 (+0200) Subject: layer/validate: forwarding mode, another CNAME fix X-Git-Tag: v1.3.1^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=993b086d19b90b23b9f67808ffc8978376cd3840;p=thirdparty%2Fknot-resolver.git layer/validate: forwarding mode, another CNAME fix Don't check proof of nonexistance in NODATA or NAME ERROR answers which contains a CNAME. --- diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 11ae80d91..b8ce5d01a 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -449,6 +449,7 @@ static int unroll_cname(knot_pkt_t *pkt, struct kr_request *req, bool referral, * Try to find records for pending_cname owner from section start. */ cname = pending_cname; pending_cname = NULL; + const int cname_labels = knot_dname_labels(cname, NULL); for (unsigned i = 0; i < an->count; ++i) { const knot_rrset_t *rr = knot_pkt_rr(an, i); @@ -461,6 +462,16 @@ static int unroll_cname(knot_pkt_t *pkt, struct kr_request *req, bool referral, continue; } + if (rr->type == KNOT_RRTYPE_RRSIG) { + int rrsig_labels = knot_rrsig_labels(&rr->rrs, 0); + if (rrsig_labels > cname_labels) { + return KR_STATE_FAIL; + } + if (rrsig_labels < cname_labels) { + query->flags |= QUERY_DNSSEC_WEXPAND; + } + } + /* Process records matching current SNAME */ int state = KR_STATE_FAIL; bool to_wire = false; @@ -509,7 +520,6 @@ static int unroll_cname(knot_pkt_t *pkt, struct kr_request *req, bool referral, } /* try to unroll cname only within current zone */ const int pending_labels = knot_dname_labels(pending_cname, NULL); - const int cname_labels = knot_dname_labels(cname, NULL); if (pending_labels != cname_labels) { cname = pending_cname; break; @@ -675,9 +685,12 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req) } else { next->flags &= ~QUERY_DNSSEC_WANT; } - state = pick_authority(pkt, req, false); - if (state != kr_ok()) { - return KR_STATE_FAIL; + if (!(query->flags & QUERY_FORWARD) || + (query->flags & QUERY_DNSSEC_WEXPAND)) { + state = pick_authority(pkt, req, false); + if (state != kr_ok()) { + return KR_STATE_FAIL; + } } } else if (!query->parent) { /* Answer for initial query */ diff --git a/lib/layer/validate.c b/lib/layer/validate.c index 68d0323a0..66e16f08c 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -590,7 +590,7 @@ static int unsigned_forward(kr_layer_t *ctx, knot_pkt_t *pkt) } } - if (nods && ns_exist && qtype == KNOT_RRTYPE_NS && !(qry->flags & QUERY_CNAME)) { + if (nods && ns_exist && qtype == KNOT_RRTYPE_NS) { qry->flags &= ~QUERY_DNSSEC_WANT; qry->flags |= QUERY_DNSSEC_INSECURE; if (qry->forward_flags & QUERY_CNAME) { @@ -859,7 +859,6 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) bool has_nsec3 = pkt_has_type(pkt, KNOT_RRTYPE_NSEC3); const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER); const bool referral = (an->count == 0 && !knot_wire_get_aa(pkt->wire)); - const bool no_data = (an->count == 0 && knot_wire_get_aa(pkt->wire)); if (!(qry->flags & QUERY_CACHED) && knot_wire_get_aa(pkt->wire)) { /* Check if answer if not empty, @@ -896,7 +895,8 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) } /* Validate non-existence proof if not positive answer. */ - if (!(qry->flags & QUERY_CACHED) && pkt_rcode == KNOT_RCODE_NXDOMAIN) { + if (!(qry->flags & QUERY_CACHED) && pkt_rcode == KNOT_RCODE_NXDOMAIN && + ((qry->flags & (QUERY_FORWARD | QUERY_CNAME)) != (QUERY_FORWARD | QUERY_CNAME))) { /* @todo If knot_pkt_qname(pkt) is used instead of qry->sname then the tests crash. */ if (!has_nsec3) { ret = kr_nsec_name_error_response_check(pkt, KNOT_AUTHORITY, qry->sname); @@ -920,8 +920,10 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) /* @todo WTH, this needs API that just tries to find a proof and the caller * doesn't have to worry about NSEC/NSEC3 * @todo rework this */ - if (!(qry->flags & QUERY_CACHED)) { - if (pkt_rcode == KNOT_RCODE_NOERROR && no_data) { + if (!(qry->flags & QUERY_CACHED) && (pkt_rcode == KNOT_RCODE_NOERROR) && + ((qry->flags & (QUERY_FORWARD | QUERY_CNAME)) != (QUERY_FORWARD | QUERY_CNAME))) { + bool no_data = (an->count == 0 && knot_wire_get_aa(pkt->wire)); + if (no_data) { /* @todo * ? quick mechanism to determine which check to preform first * ? merge the functionality together to share code/resources