]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib: WIP, forwarding mode, some improvements in SERVFAIL & NXDOMAIN processing
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Fri, 26 May 2017 11:51:55 +0000 (13:51 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 1 Jun 2017 14:27:16 +0000 (16:27 +0200)
lib/layer/iterate.c
lib/layer/validate.c
lib/resolve.c
lib/rplan.h

index 4ba353981031cdb66b5265a9e09da54661c69902..9ce8ae05e5222c17c3383c716c1deba99e8dac53 100644 (file)
@@ -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) {
index 1fa0450961effa0838470ce5f45062ff489d991a..69aa253469aa40009a6019ef9373a6f57a516984 100644 (file)
@@ -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");
index c5b47b5ec7f65d7e3e0c56e1527b53a1e1a3a06b..d89bac38877dbbee9548da34eb8e912386549a69 100644 (file)
@@ -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;
 }
 
index 94382fd398e0f5b45b39e25a1027bb4f1c40c43e..8dcf8328777f36cb40d3ee8c76233a4fbe9cabd0 100644 (file)
@@ -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. */