]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
validate: work around some SERVFAILs (iterating mode)
authorVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 8 Jun 2017 15:03:22 +0000 (17:03 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 9 Jun 2017 09:00:24 +0000 (11:00 +0200)
- This affects the iterating mode only (except for a verbose message).
- The problem was introduced when implementing forwarding in 651c5aad.
- Example that was affected: *.org.ru.

When the same server is authoritative for multiple consecutive zones,
with a higher one being signed and a lower one being unsigned, we may
get an unsigned answer even in case we *think* we're currently in a
signed zone.

In particular, DS (sub-)queries are important because of being used to
prove the insecurity of zones - in that case the iterator can correctly
determine the (unexpected) zone name from which the answer came, due to
seeing the SOA record, but that is too late for zone_cut_check() to try
getting a trust chain to it, so we need to YIELD for it to do it.

lib/layer/validate.c

index 308777f12492de3417e028e037464786abee1286..ad618321d54d4ff868e8df857adc9f2b993859c0 100644 (file)
@@ -703,20 +703,23 @@ static int check_signer(kr_layer_t *ctx, knot_pkt_t *pkt)
                                qry->flags |= QUERY_AWAIT_CUT;
                        }
                        qry->zone_cut.name = knot_dname_copy(signer, &req->pool);
-               } /* else zone cut matches, but DS/DNSKEY doesn't => refetch. */
-               if (qry->stype != KNOT_RRTYPE_DS) {
-                       /* zone cut matches, but DS/DNSKEY doesn't => refetch. */
-                       VERBOSE_MSG(qry, ">< cut changed, needs revalidation\n");
-                       if (qry->flags & QUERY_FORWARD) {
-                               struct kr_rplan *rplan = &req->rplan;
-                               struct kr_query *next = kr_rplan_push(rplan, qry, signer, qry->sclass, KNOT_RRTYPE_DS);
-                               if (!next) {
-                                       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;
+               }
+
+               /* zone cut matches, but DS/DNSKEY doesn't => refetch. */
+               VERBOSE_MSG(qry, ">< cut changed, needs revalidation\n");
+               if ((qry->flags & QUERY_FORWARD) && qry->stype != KNOT_RRTYPE_DS) {
+                       struct kr_rplan *rplan = &req->rplan;
+                       struct kr_query *next = kr_rplan_push(rplan, qry, signer,
+                                                       qry->sclass, KNOT_RRTYPE_DS);
+                       if (!next) {
+                               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;
+                       return KR_STATE_YIELD;
+               }
+               if (!(qry->flags & QUERY_FORWARD)) {
                        return KR_STATE_YIELD;
                }
        }