]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
validate: add extended DNS errors
authorTomas Krizek <tomas.krizek@nic.cz>
Fri, 29 Oct 2021 14:34:33 +0000 (16:34 +0200)
committerTomas Krizek <tomas.krizek@nic.cz>
Tue, 21 Dec 2021 14:02:08 +0000 (15:02 +0100)
lib/layer/validate.c

index 92ddb5a9ddb5ded3b0fe3fb36b9573ab21641fce..db3c0c78cab4dd0350d3aebeae7a87924a7ece7f 100644 (file)
@@ -148,6 +148,7 @@ do_downgrade: // we do this deep inside calls because of having signer name avai
 static int validate_section(kr_rrset_validation_ctx_t *vctx, struct kr_query *qry,
                            knot_mm_t *pool)
 {
+       struct kr_request *req = qry->request;
        if (!vctx) {
                return kr_error(EINVAL);
        }
@@ -235,10 +236,13 @@ static int validate_section(kr_rrset_validation_ctx_t *vctx, struct kr_query *qr
                        /* no RRSIGs found */
                        kr_rank_set(&entry->rank, KR_RANK_MISSING);
                        vctx->err_cnt += 1;
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_RRSIG_MISS, NULL);  // TODO double-check EDE
                        log_bogus_rrsig(vctx, rr, "no valid RRSIGs found");
                } else {
                        kr_rank_set(&entry->rank, KR_RANK_BOGUS);
                        vctx->err_cnt += 1;
+                       req->extended_error.info_code = KNOT_EDNS_EDE_BOGUS;
+                       req->extended_error.extra_text = "bogus signatures";
                        log_bogus_rrsig(vctx, rr, "bogus signatures");
                }
        }
@@ -555,6 +559,7 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_
                        }
                } else if (ret != 0) {
                        VERBOSE_MSG(qry, "<= bogus proof of DS non-existence\n");
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
                        qry->flags.DNSSEC_BOGUS = true;
                } else if (proved_name[0] != '\0') { /* don't go to insecure for . DS */
                        qry->flags.DNSSEC_NODS = true;
@@ -699,6 +704,7 @@ static int check_validation_result(kr_layer_t *ctx, const knot_pkt_t *pkt, ranke
        if (!kr_rank_test(invalid_entry->rank, KR_RANK_SECURE) &&
            (++(invalid_entry->revalidation_cnt) > MAX_REVALIDATION_CNT)) {
                VERBOSE_MSG(qry, "<= continuous revalidation, fails\n");
+               kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "continuous revalidation, fails");
                qry->flags.DNSSEC_BOGUS = true;
                return KR_STATE_FAIL;
        }
@@ -722,6 +728,7 @@ static int check_validation_result(kr_layer_t *ctx, const knot_pkt_t *pkt, ranke
        } else if (kr_rank_test(invalid_entry->rank, KR_RANK_MISSING)) {
                ret = rrsig_not_found(ctx, pkt, rr);
        } else if (!kr_rank_test(invalid_entry->rank, KR_RANK_SECURE)) {
+               kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
                qry->flags.DNSSEC_BOGUS = true;
                ret = KR_STATE_FAIL;
        }
@@ -1059,6 +1066,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
        bool use_signatures = (knot_pkt_qtype(pkt) != KNOT_RRTYPE_RRSIG);
        if (!(qry->flags.CACHED) && !knot_pkt_has_dnssec(pkt) && !use_signatures) {
                VERBOSE_MSG(qry, "<= got insecure response\n");
+               kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
                qry->flags.DNSSEC_BOGUS = true;
                return KR_STATE_FAIL;
        }
@@ -1074,6 +1082,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                 * but iterator has not selected any records. */
                if (!check_empty_answer(ctx, pkt)) {
                        VERBOSE_MSG(qry, "<= no useful RR in authoritative answer\n");
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
                        qry->flags.DNSSEC_BOGUS = true;
                        return KR_STATE_FAIL;
                }
@@ -1095,6 +1104,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                if (ds && !kr_ds_algo_support(ds)) {
                        VERBOSE_MSG(qry, ">< all DS entries use unsupported algorithm pairs, going insecure\n");
                        /* ^ the message is a bit imprecise to avoid being too verbose */
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "unsupported digest/key");
                        qry->flags.DNSSEC_WANT = false;
                        qry->flags.DNSSEC_INSECURE = true;
                        rank_records(qry, true, KR_RANK_INSECURE, qry->zone_cut.name);
@@ -1108,6 +1118,8 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                        return KR_STATE_YIELD;
                } else if (ret != 0) {
                        VERBOSE_MSG(qry, "<= bad keys, broken trust chain\n");
+                       req->extended_error.info_code = KNOT_EDNS_EDE_BOGUS;
+                       req->extended_error.extra_text = "bad keys, broken trust chain";
                        qry->flags.DNSSEC_BOGUS = true;
                        return KR_STATE_FAIL;
                }
@@ -1124,6 +1136,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                        /* something exceptional - no DNS key, empty pointers etc
                         * normally it shouldn't happen */
                        VERBOSE_MSG(qry, "<= couldn't validate RRSIGs\n");
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "couldn't validate RRSIGs");
                        qry->flags.DNSSEC_BOGUS = true;
                        return KR_STATE_FAIL;
                }
@@ -1162,6 +1175,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                        VERBOSE_MSG(qry, "<= can't prove NXDOMAIN due to optout, going insecure\n");
                } else if (ret != 0) {
                        VERBOSE_MSG(qry, "<= bad NXDOMAIN proof\n");
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_NSEC_MISS, NULL);
                        qry->flags.DNSSEC_BOGUS = true;
                        return KR_STATE_FAIL;
                }
@@ -1193,6 +1207,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                                         * parent queries as insecure */
                                } else {
                                        VERBOSE_MSG(qry, "<= bad NODATA proof\n");
+                                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_NSEC_MISS, NULL);
                                        qry->flags.DNSSEC_BOGUS = true;
                                        return KR_STATE_FAIL;
                                }
@@ -1207,6 +1222,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
        if (ret == DNSSEC_NOT_FOUND && qry->stype != KNOT_RRTYPE_DS) {
                if (ctx->state == KR_STATE_YIELD) {
                        VERBOSE_MSG(qry, "<= can't validate referral\n");
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
                        qry->flags.DNSSEC_BOGUS = true;
                        return KR_STATE_FAIL;
                } else {
@@ -1276,6 +1292,24 @@ static int validate_wrapper(kr_layer_t *ctx, knot_pkt_t *pkt) {
        struct kr_query *qry = req->current_query;
        if (ret & KR_STATE_FAIL && qry->flags.DNSSEC_BOGUS)
                qry->server_selection.error(qry, req->upstream.transport, KR_SELECTION_DNSSEC_ERROR);
+       if (ret & KR_STATE_DONE && !qry->flags.DNSSEC_BOGUS) {
+               /* Don't report extended DNS errors related to validation
+                * when it managed to succeed (e.g. by trying different auth). */
+               switch (req->extended_error.info_code) {
+               case KNOT_EDNS_EDE_BOGUS:
+               case KNOT_EDNS_EDE_NSEC_MISS:
+                       kr_request_set_extended_error(req, KNOT_EDNS_EDE_NONE, NULL);
+                       break;
+               case KNOT_EDNS_EDE_SIG_EXPIRED:
+               case KNOT_EDNS_EDE_SIG_NOTYET:
+               case KNOT_EDNS_EDE_DNSKEY_MISS:
+               case KNOT_EDNS_EDE_RRSIG_MISS:
+               case KNOT_EDNS_EDE_DNSKEY_BIT:
+                       kr_assert(false);  /* These EDE codes aren't used. */
+                       break;
+               default: break;
+               }
+       }
        return ret;
 }