]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
layer/validate: clear AD if closest encloser proof has optouted NSEC3
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Fri, 17 Mar 2017 08:20:17 +0000 (09:20 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 20 Mar 2017 11:47:18 +0000 (12:47 +0100)
lib/cache.h
lib/dnssec/nsec3.c
lib/layer/pktcache.c
lib/layer/validate.c
lib/resolve.c
lib/rplan.h
tests/deckard

index b237602c9800443e7e82eadb9bbfb194a686b5a1..b9f8f84b77fa7f0f0fdb781aa17fbf342b9e946c 100644 (file)
@@ -54,6 +54,11 @@ enum kr_cache_flag {
        KR_CACHE_FLAG_WCARD_PROOF = 1, /* Entry contains either packet with wildcard
                                        * answer either record for which wildcard
                                        * expansion proof is needed */
+       KR_CACHE_FLAG_OPTOUT      = 2, /* Entry contains secured packet containing a
+                                       * closest  encloser proof in which the NSEC3 RR
+                                       * that covers the "next closer" name
+                                       * has the Opt-Out bit set
+                                       */
 };
 
 
index f7c7a32ecb04ce8d24be30fa647867ebb8f1e5d1..c8585fa4413215a24bd384d450f906bfe05fd003 100644 (file)
@@ -360,17 +360,20 @@ static int prepend_asterisk(uint8_t *tgt, size_t maxlen, const knot_dname_t *nam
 /**
  * Closest encloser proof (RFC5155 7.2.1).
  * @note No RRSIGs are validated.
- * @param pkt                    Packet structure to be processed.
- * @param section_id             Packet section to be processed.
- * @param sname                  Name to be checked.
- * @param encloser_name          Returned matching encloser name, if found.
- * @param matching_ecloser_nsec3 Pointer to matching encloser NSEC RRSet.
- * @param covering_next_nsec3    Pointer to covering next closer NSEC3 RRSet.
- * @return                       0 or error code.
+ * @param pkt                     Packet structure to be processed.
+ * @param section_id              Packet section to be processed.
+ * @param sname                   Name to be checked.
+ * @param encloser_name           Returned matching encloser name, if found.
+ * @param matching_encloser_nsec3 Pointer to matching encloser NSEC RRSet.
+ * @param covering_next_nsec3     Pointer to covering next closer NSEC3 RRSet.
+ * @return                        0 or error code.
  */
-static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_id,
-                                  const knot_dname_t *sname, const knot_dname_t **encloser_name,
-                                  const knot_rrset_t **matching_ecloser_nsec3, const knot_rrset_t **covering_next_nsec3)
+static int closest_encloser_proof(const knot_pkt_t *pkt,
+                                 knot_section_t section_id,
+                                 const knot_dname_t *sname,
+                                 const knot_dname_t **encloser_name,
+                                 const knot_rrset_t **matching_encloser_nsec3,
+                                 const knot_rrset_t **covering_next_nsec3)
 {
        const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
        if (!sec || !sname) {
@@ -427,8 +430,8 @@ static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_
                if (encloser_name && next_closer[0]) {
                        *encloser_name = knot_wire_next_label(next_closer, NULL);
                }
-               if (matching_ecloser_nsec3) {
-                       *matching_ecloser_nsec3 = matching;
+               if (matching_encloser_nsec3) {
+                       *matching_encloser_nsec3 = matching;
                }
                if (covering_next_nsec3) {
                        *covering_next_nsec3 = covering;
@@ -444,7 +447,10 @@ static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_
  * @param pkt        Packet structure to be processed.
  * @param section_id Packet section to be processed.
  * @param encloser   Closest (provable) encloser domain name.
- * @return           0 or error code.
+ * @return           0 or error code:
+ *                   DNSSEC_OUT_OF_RANGE - NSEC3 RR (that covers a wildcard)
+ *                   has been found, but has opt-out flag set;
+ *                   otherwise - error.
  */
 static int covers_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section_t section_id,
                                             const knot_dname_t *encloser)
@@ -474,7 +480,8 @@ static int covers_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section_
                        return ret;
                }
                if (flags & FLG_NAME_COVERED) {
-                       return kr_ok();
+                       return has_optout(rrset) ?
+                              kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok();
                }
        }
 
@@ -485,11 +492,23 @@ int kr_nsec3_name_error_response_check(const knot_pkt_t *pkt, knot_section_t sec
                                        const knot_dname_t *sname)
 {
        const knot_dname_t *encloser = NULL;
-       int ret = closest_encloser_proof(pkt, section_id, sname, &encloser, NULL, NULL);
+       const knot_rrset_t *covering_next_nsec3 = NULL;
+       int ret = closest_encloser_proof(pkt, section_id, sname,
+                                        &encloser, NULL, &covering_next_nsec3);
+       if (ret != 0) {
+               return ret;
+       }
+       ret = covers_closest_encloser_wildcard(pkt, section_id, encloser);
        if (ret != 0) {
+               /* OK, but NSEC3 for wildcard at encloser has opt-out;
+                * or error */
                return ret;
        }
-       return covers_closest_encloser_wildcard(pkt, section_id, encloser);
+       /* Closest encloser proof is OK and
+        * NSEC3 for wildcard has been found and optout flag is not set.
+        * Now check if NSEC3 that covers next closer name has opt-out. */
+       return has_optout(covering_next_nsec3) ?
+              kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok();
 }
 
 /**
index 861e47cba9590405a0b47aa6b932f6ba0f963281..942f6138261ea9ff003ea6cdead923c2209afe99 100644 (file)
@@ -128,6 +128,9 @@ static int pktcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
                if (flags & KR_CACHE_FLAG_WCARD_PROOF) {
                        qry->flags |= QUERY_DNSSEC_WEXPAND;
                }
+               if (flags & KR_CACHE_FLAG_OPTOUT) {
+                       qry->flags |= QUERY_DNSSEC_OPTOUT;
+               }
                pkt->parsed = pkt->size;
                knot_wire_set_qr(pkt->wire);
                knot_wire_set_aa(pkt->wire);
@@ -229,6 +232,9 @@ static int pktcache_stash(kr_layer_t *ctx, knot_pkt_t *pkt)
        if (qry->flags & QUERY_DNSSEC_WEXPAND) {
                header.flags |= KR_CACHE_FLAG_WCARD_PROOF;
        }
+       if (qry->flags & QUERY_DNSSEC_OPTOUT) {
+               header.flags |= KR_CACHE_FLAG_OPTOUT;
+       }
 
        /* Check if we can replace (allow current or better rank, SECURE is always accepted). */
        struct kr_cache *cache = &ctx->req->ctx->cache;
index bdff94a3aff1db5a38ff82164e1c1210e37eb2e7..ae66e5486f477da51598dec8adb6aee246cfd113 100644 (file)
@@ -641,7 +641,14 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                } else {
                        ret = kr_nsec3_name_error_response_check(pkt, KNOT_AUTHORITY, qry->sname);
                }
-               if (ret != 0) {
+               if (has_nsec3 && (ret == kr_error(DNSSEC_OUT_OF_RANGE))) {
+                       /* NXDOMAIN proof is OK,
+                        * but NSEC3 that covers next closer name
+                        * (or wildcard at next closer name) has opt-out flag.
+                        * RFC5155 9.2; AD flag can not be set */
+                       qry->flags |= QUERY_DNSSEC_OPTOUT;
+                       VERBOSE_MSG(qry, "<= can't prove NXDOMAIN due to optout, going insecure\n");
+               } else if (ret != 0) {
                        VERBOSE_MSG(qry, "<= bad NXDOMAIN proof\n");
                        qry->flags |= QUERY_DNSSEC_BOGUS;
                        return KR_STATE_FAIL;
@@ -665,7 +672,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
                        if (ret != 0) {
                                if (has_nsec3 && (ret == kr_error(DNSSEC_OUT_OF_RANGE))) {
                                        VERBOSE_MSG(qry, "<= can't prove NODATA due to optout, going insecure\n");
-                                       qry->flags |= QUERY_DNSSEC_NODS;
+                                       qry->flags |= QUERY_DNSSEC_OPTOUT;
                                        /* Could not return from here,
                                         * we must continue, validate NSEC\NSEC3 and
                                         * call update_parent_keys() to mark
index 591d22f124a7eedacb8b0ccbc16eb5ab2bd06eba..c6496f763b480177241ff09aa07d44fceb95717e 100644 (file)
@@ -537,7 +537,8 @@ static int answer_finalize(struct kr_request *request, int state)
                struct kr_query *last = array_tail(rplan->resolved);
                /* Do not set AD for RRSIG query, as we can't validate it. */
                const bool secure = (last->flags & QUERY_DNSSEC_WANT) &&
-                                  !(last->flags & QUERY_DNSSEC_INSECURE);
+                                   !(last->flags & QUERY_DNSSEC_INSECURE) &&
+                                   !(last->flags & QUERY_DNSSEC_OPTOUT);
                if (!(last->flags & QUERY_STUB) /* Never set AD if forwarding. */
                    && has_ad && secure
                    && knot_pkt_qtype(answer) != KNOT_RRTYPE_RRSIG) {
index 6a70835ebe127d59d865923226aa6607ae4d4ece..4f76289634cda6861cd65042f7a73816a765e0a1 100644 (file)
@@ -54,6 +54,7 @@
        X(TRACE,           1 << 25) /**< Log answer with kr_verbose_log(), unless -DNDEBUG. */ \
        X(NO_0X20,         1 << 26) /**< Disable query case randomization . */ \
        X(DNSSEC_NODS,     1 << 27) /**< DS non-existance is proven */ \
+       X(DNSSEC_OPTOUT,   1 << 28) /**< Closest encloser proof has optout */ \
                        /* 1 << 31       Used by ../modules/dns64/dns64.lua */
 
 /** Query flags */
index b7453577c57cb837261ca6e21098b8a44a9e8b3d..b96ef5cd589ddb71eefb89e09fee1087a49edf35 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b7453577c57cb837261ca6e21098b8a44a9e8b3d
+Subproject commit b96ef5cd589ddb71eefb89e09fee1087a49edf35