]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
cache: try also CNAME wildcard
authorVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 25 Jan 2018 16:39:10 +0000 (17:39 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 25 Jan 2018 17:00:29 +0000 (18:00 +0100)
I somehow forgot that case.  Unfortunately the cache optimization for
CNAMEs doesn't help this case, so we just do (up to) two probes.

lib/cache.c

index e7c8149554db8cbad401f87e774b91026bff5a03..f85b48ea866024209943a3de20dc61435b03d463 100644 (file)
@@ -296,6 +296,9 @@ static knot_db_val_t closest_NS(kr_layer_t *ctx, struct key *k);
 static int answer_simple_hit(kr_layer_t *ctx, knot_pkt_t *pkt, uint16_t type,
                const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl);
 static int cache_peek_real(kr_layer_t *ctx, knot_pkt_t *pkt);
+static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
+                   const uint16_t type, const uint8_t lowest_rank,
+                   const struct kr_query *qry, struct kr_cache *cache);
 
 /** function for .produce phase */
 int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
@@ -313,6 +316,7 @@ int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
        return ret;
 }
 
+
 /**
  * \note we don't transition to KR_STATE_FAIL even in case of "unexpected errors".
  */
@@ -504,49 +508,19 @@ static int cache_peek_real(kr_layer_t *ctx, knot_pkt_t *pkt)
                        assert(!ret);
                        return ctx->state;
                }
-               knot_db_val_t key = key_exact_type(k, qry->stype);
-               /* Find the record. */
-               knot_db_val_t val = { NULL, 0 };
-               ret = cache_op(cache, read, &key, &val, 1);
-               if (!ret) {
-                       ret = entry_h_seek(&val, qry->stype);
-               }
-               if (ret) {
-                       if (ret != -abs(ENOENT)) {
-                               VERBOSE_MSG(qry, "=> wildcard: hit error %d %s\n",
-                                               ret, strerror(abs(ret)));
+               const uint16_t types[] = { qry->stype, KNOT_RRTYPE_CNAME };
+               for (int i = 0; i < (2 - (qry->stype == KNOT_RRTYPE_CNAME)); ++i) {
+                       ret = try_wild(k, &ans, clencl_name, types[i],
+                                       lowest_rank, qry, cache);
+                       if (ret == kr_ok()) {
+                               break;
+                       } else if (ret != -ABS(ENOENT) && ret != -ABS(ESTALE)) {
                                assert(false);
+                               return ctx->state;
                        }
-                       WITH_VERBOSE(qry) {
-                               auto_free char *clencl_str = kr_dname_text(clencl_name);
-                               VERBOSE_MSG(qry, "=> wildcard: not found: *.%s\n",
-                                               clencl_str);
-                       }
-                       return ctx->state;
+                       /* else continue */
                }
-               /* Check if the record is OK. */
-               const struct entry_h *eh = entry_h_consistent(val, qry->stype);
-               if (!eh) {
-                       assert(false);
-                       return ctx->state;
-                       // LATER: recovery in case of error, perhaps via removing the entry?
-               }
-               int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, qry->stype);
-                       /* ^^ here we use the *expanded* wildcard name */
-               if (new_ttl < 0 || eh->rank < lowest_rank || eh->is_packet) {
-                       /* Wildcard record with stale TTL, bad rank or packet.  */
-                       VERBOSE_MSG(qry, "=> wildcard: skipping %s, rank 0%.2o, new TTL %d\n",
-                                       eh->is_packet ? "packet" : "RR", eh->rank, new_ttl);
-                       return ctx->state;
-               }
-               /* Add the RR into the answer. */
-               const void *eh_bound = val.data + val.len;
-               ret = entry2answer(&ans, AR_ANSWER, eh, eh_bound,
-                                  qry->sname, qry->stype, new_ttl);
-               VERBOSE_MSG(qry, "=> NSEC wildcard: answer expanded, ret = %d, new TTL %d\n",
-                               ret, (int)new_ttl);
-               if (ret) return ctx->state;
-               ans.rcode = PKT_NOERROR;
+               if (ret) return ctx->state; /* neither attempt succeeded */
        }
 
 
@@ -917,6 +891,59 @@ static int found_exact_hit(kr_layer_t *ctx, knot_pkt_t *pkt, knot_db_val_t val,
        }
 }
 
+
+/** Try to satisfy via wildcard.  See the single call site. */
+static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
+                   const uint16_t type, const uint8_t lowest_rank,
+                   const struct kr_query *qry, struct kr_cache *cache)
+{
+       knot_db_val_t key = key_exact_type(k, type);
+       /* Find the record. */
+       knot_db_val_t val = { NULL, 0 };
+       int ret = cache_op(cache, read, &key, &val, 1);
+       if (!ret) {
+               ret = entry_h_seek(&val, type);
+       }
+       if (ret) {
+               if (ret != -ABS(ENOENT)) {
+                       VERBOSE_MSG(qry, "=> wildcard: hit error %d %s\n",
+                                       ret, strerror(abs(ret)));
+                       assert(false);
+               }
+               WITH_VERBOSE(qry) {
+                       auto_free char *clencl_str = kr_dname_text(clencl_name),
+                               *type_str = kr_rrtype_text(type);
+                       VERBOSE_MSG(qry, "=> wildcard: not found: *.%s %s\n",
+                                       clencl_str, type_str);
+               }
+               return ret;
+       }
+       /* Check if the record is OK. */
+       const struct entry_h *eh = entry_h_consistent(val, type);
+       if (!eh) {
+               assert(false);
+               return kr_error(ret);
+               // LATER: recovery in case of error, perhaps via removing the entry?
+       }
+       int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, type);
+               /* ^^ here we use the *expanded* wildcard name */
+       if (new_ttl < 0 || eh->rank < lowest_rank || eh->is_packet) {
+               /* Wildcard record with stale TTL, bad rank or packet.  */
+               VERBOSE_MSG(qry, "=> wildcard: skipping %s, rank 0%.2o, new TTL %d\n",
+                               eh->is_packet ? "packet" : "RR", eh->rank, new_ttl);
+               return -ABS(ESTALE);
+       }
+       /* Add the RR into the answer. */
+       const void *eh_bound = val.data + val.len;
+       ret = entry2answer(ans, AR_ANSWER, eh, eh_bound, qry->sname, type, new_ttl);
+       VERBOSE_MSG(qry, "=> NSEC wildcard: answer expanded, ret = %d, new TTL %d\n",
+                       ret, (int)new_ttl);
+       if (ret) return kr_error(ret);
+       ans->rcode = PKT_NOERROR;
+       return kr_ok();
+}
+
+
 static int peek_exact_real(struct kr_cache *cache, const knot_dname_t *name, uint16_t type,
                        struct kr_cache_p *peek)
 {