From f6fff9efcbe86e1918f3e10d084d54010b8a720e Mon Sep 17 00:00:00 2001 From: Nikolay Shopik Date: Mon, 28 Sep 2026 12:53:24 +0300 Subject: [PATCH] rrset: rehash copies after changing the key (#1518) Copied rrsets that got a new owner name or flags kept the hash of the source, so the rrset cache filed all of them in one hash bin. Recompute the hash at each such site and assert it on cache update. --- dns64/dns64.c | 1 + respip/respip.c | 1 + services/cache/rrset.c | 1 + services/rpz.c | 2 ++ validator/val_neg.c | 1 + validator/val_sigcrypt.c | 1 + 6 files changed, 7 insertions(+) diff --git a/dns64/dns64.c b/dns64/dns64.c index 8f9dba82f..9c6de9d12 100644 --- a/dns64/dns64.c +++ b/dns64/dns64.c @@ -968,6 +968,7 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super) if(answer) { answer->rk.dname = super->qinfo.qname; answer->rk.dname_len = super->qinfo.qname_len; + answer->entry.hash = rrset_key_hash(&answer->rk); } } diff --git a/respip/respip.c b/respip/respip.c index fc9de4c01..3840fe1dd 100644 --- a/respip/respip.c +++ b/respip/respip.c @@ -734,6 +734,7 @@ respip_data_answer(enum respip_action action, if(!new_rep) return -1; rp->rk.flags |= PACKED_RRSET_FIXEDTTL; /* avoid adjusting TTL */ + rp->entry.hash = rrset_key_hash(&rp->rk); new_rep->rrsets[rrset_id] = rp; *redirect_rrsetp = rp; diff --git a/services/cache/rrset.c b/services/cache/rrset.c index 3600d7974..3fcf1ae6c 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -222,6 +222,7 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, the grace ttl amount. This means the ref was not changed by the call. */ } + log_assert(k->entry.hash == rrset_key_hash(&k->rk)); /* looks up item with a readlock - no editing! */ if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) { /* return id and key as they will be used in the cache diff --git a/services/rpz.c b/services/rpz.c index 35c88bfc0..f5a9b34e9 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -2097,6 +2097,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs * actual data. So that the actual network data and fake data * are kept track of separately. */ rp->rk.flags |= PACKED_RRSET_RPZ; + rp->entry.hash = rrset_key_hash(&rp->rk); new_reply_info->rrsets[0] = rp; msg->rep = new_reply_info; if(!rpz_add_soa(msg->rep, ms, az)) @@ -2262,6 +2263,7 @@ rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms, * actual data. So that the actual network data and fake data * are kept track of separately. */ rp->rk.flags |= PACKED_RRSET_RPZ; + rp->entry.hash = rrset_key_hash(&rp->rk); new_reply_info->rrsets[0] = rp; msg->rep = new_reply_info; diff --git a/validator/val_neg.c b/validator/val_neg.c index 7e8bdee8c..74ef3d3b3 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -1511,6 +1511,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo, lock_rw_unlock(&cache_wc->entry.lock); wcrr->rk.dname = qinfo->qname; wcrr->rk.dname_len = qinfo->qname_len; + wcrr->entry.hash = rrset_key_hash(&wcrr->rk); if(!dns_msg_ansadd(msg, region, wcrr, 0)) return NULL; /* No SOA needed for wildcard synthesised diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 612754cf3..3b0dce6da 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -1432,6 +1432,7 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, return 0; k->rk.dname = new_dname; k->rk.dname_len = can_owner_len; + k->entry.hash = rrset_key_hash(&k->rk); }