ret = loot_rr(cache, pkt, qry->sname, qry->sclass, rrtype, qry,
&rank, &flags, 0, lowest_rank);
}
- /* Record is flagged as INSECURE => doesn't have RRSIG. */
- if (ret == 0 && (rank & KR_RANK_INSECURE)) {
+ if (ret) {
+ return ret;
+ }
+
+ if (kr_rank_test(rank, KR_RANK_INSECURE)) {
qry->flags |= QUERY_DNSSEC_INSECURE;
qry->flags &= ~QUERY_DNSSEC_WANT;
- /* Record may have RRSIG, try to find it. */
- } else if (ret == 0 && dobit) {
+ }
+
+ /* Record may have RRSIGs, try to find them. */
+ const bool dobit = (qry->flags & QUERY_DNSSEC_WANT);
+ if (cdbit || (dobit && kr_rank_test(rank, KR_RANK_SECURE))) {
+ kr_rank_set(&lowest_rank, KR_RANK_INITIAL); /* no security for RRSIGs */
ret = loot_rr(cache, pkt, qry->sname, qry->sclass, rrtype, qry,
&rank, &flags, true, lowest_rank);
+ if (ret) {
+ VERBOSE_MSG(qry, "=> RRSIG(s) expected but not found, skipping");
+ /* In some cases, e.g. due to bugs, this may fail.
+ * A possible good example is that a cache backend
+ * (such as redis) chose to evict RRSIG but not RRset.
+ * Let's return cache failure, but the packet has been
+ * updated already by the RRs! Let's try to clear it.
+ * The following command might theoretically fail again
+ * while parsing question, but let's just log that
+ * condition in non-debug mode (it might be non-fatal). */
+ if (kr_pkt_clear_payload(pkt)) {
+ kr_log_error("[ rc ] => ERROR: work-around failed\n");
+ assert(false);
+ }
+ }
}
return ret;
}