From: Grigorii Demidov Date: Fri, 26 May 2017 11:51:55 +0000 (+0200) Subject: lib: WIP, forwarding mode, some improvements in SERVFAIL & NXDOMAIN processing X-Git-Tag: 1.3.0-rc1~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bf594fdc1e694192d9f77146a4e2550c567f1c55;p=thirdparty%2Fknot-resolver.git lib: WIP, forwarding mode, some improvements in SERVFAIL & NXDOMAIN processing --- diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 4ba353981..9ce8ae05e 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -654,6 +654,7 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req) } if (query->flags & QUERY_FORWARD) { next->flags |= (QUERY_FORWARD | QUERY_AWAIT_CUT); + next->forward_flags |= QUERY_CNAME; state = kr_nsrep_copy_set(&next->ns, &query->ns); if (state != kr_ok()) { return KR_STATE_FAIL; @@ -661,6 +662,7 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req) } else { next->flags |= QUERY_AWAIT_CUT; } + next->cname_parent = query; /* Want DNSSEC if and only if it's posible to secure * this name (i.e. iff it is covered by a TA) */ if (kr_ta_covers_qry(req->ctx, cname, query->stype)) { @@ -919,7 +921,10 @@ static int resolve(kr_layer_t *ctx, knot_pkt_t *pkt) break; /* OK */ case KNOT_RCODE_REFUSED: case KNOT_RCODE_SERVFAIL: { - if (query->flags & QUERY_STUB) { break; } /* Pass through in stub mode */ + if (query->flags & (QUERY_STUB | QUERY_FORWARD)) { + /* Pass through in stub mode */ + break; + } VERBOSE_MSG("<= rcode: %s\n", rcode ? rcode->name : "??"); query->fails += 1; if (query->fails >= KR_QUERY_NSRETRY_LIMIT) { diff --git a/lib/layer/validate.c b/lib/layer/validate.c index 1fa045096..69aa25346 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -305,7 +305,7 @@ static int update_parent_keys(struct kr_query *qry, uint16_t answer_type) VERBOSE_MSG(qry, "<= parent: updating DS\n"); if (qry->flags & (QUERY_DNSSEC_INSECURE)) { /* DS non-existence proven. */ mark_insecure_parents(qry); - } if ((qry->flags & (QUERY_DNSSEC_NODS | QUERY_FORWARD)) == QUERY_DNSSEC_NODS) { + } else if ((qry->flags & (QUERY_DNSSEC_NODS | QUERY_FORWARD)) == QUERY_DNSSEC_NODS) { mark_insecure_parents(qry); } else { /* DS existence proven. */ parent->zone_cut.trust_anchor = knot_rrset_copy(qry->zone_cut.trust_anchor, parent->zone_cut.pool); @@ -557,7 +557,7 @@ static int unsigned_forward(kr_layer_t *ctx, knot_pkt_t *pkt) struct kr_request *req = ctx->req; struct kr_query *qry = req->current_query; const uint16_t qtype = knot_pkt_qtype(pkt); - + const uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire); bool nods = false; for (int i = 0; i < req->rplan.resolved.len; ++i) { struct kr_query *q = req->rplan.resolved.at[i]; @@ -568,17 +568,36 @@ static int unsigned_forward(kr_layer_t *ctx, knot_pkt_t *pkt) } } - if (nods) { + if (nods && qtype == KNOT_RRTYPE_NS && !(qry->flags & QUERY_CNAME)) { qry->flags &= ~QUERY_DNSSEC_WANT; qry->flags |= QUERY_DNSSEC_INSECURE; - if (qry->parent) { - qry->parent->flags &= ~QUERY_DNSSEC_WANT; - qry->parent->flags |= QUERY_DNSSEC_INSECURE; + if (qry->forward_flags & QUERY_CNAME) { + assert(qry->cname_parent); + qry->cname_parent->flags &= ~QUERY_DNSSEC_WANT; + qry->cname_parent->flags |= QUERY_DNSSEC_INSECURE; + } else if (pkt_rcode == KNOT_RCODE_NOERROR && qry->parent != NULL) { + const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_ANSWER); + const knot_rrset_t *rr = knot_pkt_rr(sec, 0); + if (rr->type == KNOT_RRTYPE_NS) { + qry->parent->zone_cut.name = knot_dname_copy(rr->owner, &req->pool); + qry->parent->flags &= ~QUERY_DNSSEC_WANT; + qry->parent->flags |= QUERY_DNSSEC_INSECURE; + } + } + while (qry->parent) { + qry = qry->parent; + qry->flags &= ~QUERY_DNSSEC_WANT; + qry->flags |= QUERY_DNSSEC_INSECURE; + if (qry->forward_flags & QUERY_CNAME) { + assert(qry->cname_parent); + qry->cname_parent->flags &= ~QUERY_DNSSEC_WANT; + qry->cname_parent->flags |= QUERY_DNSSEC_INSECURE; + } } return KR_STATE_DONE; } - if (qtype != KNOT_RRTYPE_DS) { + if (!nods && qtype != KNOT_RRTYPE_DS) { struct kr_rplan *rplan = &req->rplan; struct kr_query *next = kr_rplan_push(rplan, qry, qry->sname, qry->sclass, KNOT_RRTYPE_DS); int state = kr_nsrep_copy_set(&next->ns, &qry->ns); @@ -639,8 +658,16 @@ static int check_signer(kr_layer_t *ctx, knot_pkt_t *pkt) qry->parent->flags &= ~QUERY_DNSSEC_WANT; qry->parent->flags |= QUERY_DNSSEC_INSECURE; } - } else { - qry->zone_cut.name = knot_dname_copy(signer, &req->pool); + } else if (qry->stype != KNOT_RRTYPE_DS) { + struct kr_rplan *rplan = &req->rplan; + struct kr_query *next = kr_rplan_push(rplan, qry, qry->sname, qry->sclass, KNOT_RRTYPE_DS); + int state = kr_nsrep_copy_set(&next->ns, &qry->ns); + if (state != kr_ok()) { + return KR_STATE_FAIL; + } + kr_zonecut_set(&next->zone_cut, qry->zone_cut.name); + kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut); + next->flags |= QUERY_DNSSEC_WANT; } } } else if (!knot_dname_is_equal(signer, qry->zone_cut.name)) { @@ -731,6 +758,21 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) rank_records(ctx, KR_RANK_OMIT); return ctx->state; } + uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire); + if ((qry->flags & QUERY_FORWARD) && + pkt_rcode != KNOT_RCODE_NOERROR && + pkt_rcode != KNOT_RCODE_NXDOMAIN) { + do { + qry->flags |= QUERY_DNSSEC_BOGUS; + if (qry->cname_parent) { + qry->cname_parent->flags |= QUERY_DNSSEC_BOGUS; + } + qry = qry->parent; + } while (qry); + ctx->state = KR_STATE_DONE; + return ctx->state; + } + if (!(qry->flags & QUERY_DNSSEC_WANT)) { const uint32_t test_flags = (QUERY_CACHED | QUERY_DNSSEC_INSECURE); const bool is_insec = ((qry->flags & test_flags) == test_flags); @@ -774,7 +816,6 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) } /* Check if this is a DNSKEY answer, check trust chain and store. */ - uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire); uint16_t qtype = knot_pkt_qtype(pkt); bool has_nsec3 = pkt_has_type(pkt, KNOT_RRTYPE_NSEC3); const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER); @@ -922,25 +963,15 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) qtype = KNOT_RRTYPE_DS; } /* Update parent query zone cut */ - if (qry->parent && pkt_rcode != KNOT_RCODE_NXDOMAIN) { + if (qry->parent) { if (update_parent_keys(qry, qtype) != 0) { return KR_STATE_FAIL; } } - - if (qry->flags & QUERY_FORWARD) { - if (qry->parent && - qtype == KNOT_RRTYPE_NS && - !no_data && - pkt_rcode == KNOT_RCODE_NOERROR) { - const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_ANSWER); - const knot_rrset_t *rr = knot_pkt_rr(sec, 0); - if (rr->type == KNOT_RRTYPE_NS) { - qry->parent->zone_cut.name = knot_dname_copy(rr->owner, &req->pool); - qry->parent->flags &= ~QUERY_DNSSEC_WANT; - qry->parent->flags |= QUERY_DNSSEC_INSECURE; - } + if (qry->flags & QUERY_FORWARD && qry->parent) { + if (pkt_rcode == KNOT_RCODE_NXDOMAIN) { + qry->parent->forward_flags |= QUERY_NO_MINIMIZE; } } VERBOSE_MSG(qry, "<= answer valid, OK\n"); diff --git a/lib/resolve.c b/lib/resolve.c index c5b47b5ec..d89bac388 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -928,6 +928,12 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query map_t *trust_anchors = &request->ctx->trust_anchors; map_t *negative_anchors = &request->ctx->negative_anchors; + if (qry->parent != NULL && + !(qry->forward_flags & QUERY_CNAME) && + knot_dname_in(qry->parent->zone_cut.name, qry->zone_cut.name)) { + return KR_STATE_PRODUCE; + } + assert(qry->flags & QUERY_FORWARD); if (!trust_anchors) { @@ -940,15 +946,41 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query return KR_STATE_PRODUCE; } + if (qry->forward_flags & QUERY_NO_MINIMIZE) { + qry->flags &= ~QUERY_AWAIT_CUT; + return KR_STATE_PRODUCE; + } + const knot_dname_t *wanted_name = qry->sname; const knot_dname_t *start_name = qry->sname; if ((qry->flags & QUERY_AWAIT_CUT) && !resume) { + qry->flags &= ~QUERY_AWAIT_CUT; const knot_dname_t *longest_ta = kr_ta_get_longest_name(trust_anchors, qry->sname); if (longest_ta) { start_name = longest_ta; qry->zone_cut.name = knot_dname_copy(start_name, qry->zone_cut.pool); + qry->flags |= QUERY_DNSSEC_WANT; + } else { + qry->flags &= ~QUERY_DNSSEC_WANT; + return KR_STATE_PRODUCE; } - qry->flags &= ~QUERY_AWAIT_CUT; + } + + bool has_ta = (qry->zone_cut.trust_anchor != NULL); + knot_dname_t *ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL); + bool refetch_ta = (!has_ta || !knot_dname_is_equal(qry->zone_cut.name, ta_name)); + bool is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY); + bool refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner)); + if (refetch_key && !is_dnskey_subreq) { + struct kr_query *next = zone_cut_subreq(rplan, qry, ta_name, KNOT_RRTYPE_DNSKEY); + if (!next) { + return KR_STATE_FAIL; + } + int state = kr_nsrep_copy_set(&next->ns, &qry->ns); + if (state != kr_ok()) { + return KR_STATE_FAIL; + } + return KR_STATE_DONE; } bool nods = false; @@ -963,17 +995,13 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query ns_req = false; minimized = false; - if (resume) { - wanted_name = qry->zone_cut.name; - } else if (qry->parent == NULL) { - int cut_labels = knot_dname_labels(qry->zone_cut.name, NULL); - int wanted_name_labels = knot_dname_labels(wanted_name, NULL); - while (wanted_name[0] && wanted_name_labels > cut_labels + name_offset) { - wanted_name = knot_wire_next_label(wanted_name, NULL); - wanted_name_labels -= 1; - } - minimized = (wanted_name != qry->sname); + int cut_labels = knot_dname_labels(qry->zone_cut.name, NULL); + int wanted_name_labels = knot_dname_labels(wanted_name, NULL); + while (wanted_name[0] && wanted_name_labels > cut_labels + name_offset) { + wanted_name = knot_wire_next_label(wanted_name, NULL); + wanted_name_labels -= 1; } + minimized = (wanted_name != qry->sname); for (int i = 0; i < request->rplan.resolved.len; ++i) { struct kr_query *q = request->rplan.resolved.at[i]; @@ -992,9 +1020,7 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query } } - if (qry->parent == NULL && - ds_req && !ns_req && (minimized || resume) && - !knot_dname_is_equal(qry->zone_cut.name, wanted_name)) { + if (ds_req && !ns_req && (minimized || resume)) { struct kr_query *next = kr_rplan_push(rplan, qry, wanted_name, qry->sclass, KNOT_RRTYPE_NS); if (!next) { @@ -1021,7 +1047,7 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query nods = ds_req; } name_offset += 1; - } while (ds_req && ns_req && !resume); + } while (ds_req && ns_req /* && !resume */ && minimized); /* Disable DNSSEC if it enters NTA. */ if (kr_ta_get(negative_anchors, wanted_name)){ @@ -1055,9 +1081,9 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query } } - const bool has_ta = (qry->zone_cut.trust_anchor != NULL); - const knot_dname_t *ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL); - const bool refetch_ta = (!has_ta || !knot_dname_is_equal(wanted_name, ta_name)); + has_ta = (qry->zone_cut.trust_anchor != NULL); + ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL); + refetch_ta = (!has_ta || !knot_dname_is_equal(wanted_name, ta_name)); if (!nods && want_secured && refetch_ta) { struct kr_query *next = kr_rplan_push(rplan, qry, wanted_name, qry->sclass, KNOT_RRTYPE_DS); if (!next) { @@ -1075,8 +1101,8 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query /* Try to fetch missing DNSKEY. * Do not fetch if this is a DNSKEY subrequest to avoid circular dependency. */ - const bool is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY); - const bool refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner)); + is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY); + refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner)); if (want_secured && refetch_key && !is_dnskey_subreq) { struct kr_query *next = zone_cut_subreq(rplan, qry, ta_name, KNOT_RRTYPE_DNSKEY); if (!next) { @@ -1088,6 +1114,7 @@ static int forward_trust_chain_check(struct kr_request *request, struct kr_query } return KR_STATE_DONE; } + return KR_STATE_PRODUCE; } diff --git a/lib/rplan.h b/lib/rplan.h index 94382fd39..8dcf83287 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -89,6 +89,8 @@ struct kr_query { struct kr_nsrep ns; struct kr_layer_pickle *deferred; uint32_t uid; /**< Query iteration number, unique within the kr_rplan. */ + uint32_t forward_flags; + struct kr_query *cname_parent; }; /** @cond internal Array of queries. */