]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Split the slabheader and slabheader_proof structures in rdataset
authorOndřej Surý <ondrej@sury.org>
Thu, 18 Jun 2026 09:39:05 +0000 (11:39 +0200)
committerOndřej Surý <ondrej@sury.org>
Mon, 22 Jun 2026 11:44:50 +0000 (13:44 +0200)
Follow the method split with a data split: give the proof
pseudo-rdataset its own member in the dns_rdataset union, carrying its
own node, instead of overloading the slab member.  The proof methods
now read proof.raw/proof.node independently of the real
slab.raw/slab.noqname/slab.closest, so the two share no state and the
proof path is fully self-contained.

lib/dns/include/dns/rdataset.h
lib/dns/qpcache.c
lib/dns/rdataslab.c

index 0d2681b61034b602f0da6706d24655dcef308cf9..6691216ecdf5425bf2e9b905b03d0c9ad56f3a71 100644 (file)
@@ -192,13 +192,27 @@ struct dns_rdataset {
                 * comments in rdataslab.c for details.)
                 */
                struct {
-                       dns_dbnode_t           *node;
                        unsigned char          *raw;
                        unsigned char          *iter_pos;
                        unsigned int            iter_count;
                        dns_slabheader_proof_t *noqname, *closest;
                } slab;
 
+               /*
+                * A slab rdataset provides access to an rdataslab. In
+                * a QP database, 'raw' will generally point to the
+                * memory immediately following a slabheader. (There
+                * is an exception in the case of rdatasets returned by
+                * the `getnoqname` and `getclosest` methods; see
+                * comments in rdataslab.c for details.)
+                */
+               struct {
+                       unsigned char *raw;
+                       unsigned char *iter_pos;
+                       unsigned int   iter_count;
+                       dns_dbnode_t  *node;
+               } proof;
+
                /*
                 * A vec rdataset provides access to an rdatavec. In
                 * a QP database, 'header' points to the vecheader
index 85ceb537e0e442e08238e7a512aa80c0eb219085..8250405ed1f438b2e914f6bd983c0c28c0540aaf 100644 (file)
@@ -1050,7 +1050,6 @@ bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header,
                rdataset->ttl = 0;
        }
 
-       rdataset->slab.node = NULL;
        rdataset->slab.raw = header->raw;
        rdataset->slab.iter_pos = NULL;
        rdataset->slab.iter_count = 0;
index d0d45a332513cce3513123eb7b8d06d19cea3325..06fe3487dcdfe7bf66abefbb1e582d507263380c 100644 (file)
@@ -97,17 +97,27 @@ dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
 
 static void
 slabheader_proof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
+static isc_result_t
+slabheader_proof_first(dns_rdataset_t *rdataset);
+static isc_result_t
+slabheader_proof_next(dns_rdataset_t *rdataset);
+static void
+slabheader_proof_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
 static void
 slabheader_proof_clone(const dns_rdataset_t *source,
                       dns_rdataset_t *target DNS__DB_FLARG);
+static unsigned int
+slabheader_proof_count(dns_rdataset_t *rdataset);
+static dns_slabheader_t *
+slabheader_proof_getheader(const dns_rdataset_t *rdataset);
 
 dns_rdatasetmethods_t dns_rdataslab_proof_rdatasetmethods = {
        .disassociate = slabheader_proof_disassociate,
-       .first = rdataset_first,
-       .next = rdataset_next,
-       .current = rdataset_current,
+       .first = slabheader_proof_first,
+       .next = slabheader_proof_next,
+       .current = slabheader_proof_current,
        .clone = slabheader_proof_clone,
-       .count = rdataset_count,
+       .count = slabheader_proof_count,
        .getnoqname = NULL,
        .getclosest = NULL,
        .settrust = NULL,
@@ -689,8 +699,8 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
                .type = noqname->type,
                .ttl = rdataset->ttl,
                .trust = rdataset->trust,
-               .slab.node = node,
-               .slab.raw = noqname->neg,
+               .proof.node = node,
+               .proof.raw = noqname->neg,
                .link = nsec->link,
                .attributes = nsec->attributes,
                .magic = nsec->magic,
@@ -705,8 +715,8 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
                .covers = noqname->type,
                .ttl = rdataset->ttl,
                .trust = rdataset->trust,
-               .slab.node = node,
-               .slab.raw = noqname->negsig,
+               .proof.node = node,
+               .proof.raw = noqname->negsig,
                .link = nsecsig->link,
                .attributes = nsecsig->attributes,
                .magic = nsecsig->magic,
@@ -743,8 +753,8 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
                .type = closest->type,
                .ttl = rdataset->ttl,
                .trust = rdataset->trust,
-               .slab.node = node,
-               .slab.raw = closest->neg,
+               .proof.node = node,
+               .proof.raw = closest->neg,
                .link = nsec->link,
                .attributes = nsec->attributes,
                .magic = nsec->magic,
@@ -759,8 +769,8 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
                .covers = closest->type,
                .ttl = rdataset->ttl,
                .trust = rdataset->trust,
-               .slab.node = node,
-               .slab.raw = closest->negsig,
+               .proof.node = node,
+               .proof.raw = closest->negsig,
                .link = nsecsig->link,
                .attributes = nsecsig->attributes,
                .magic = nsecsig->magic,
@@ -832,26 +842,112 @@ rdataset_getheader(const dns_rdataset_t *rdataset) {
 
 static void
 slabheader_proof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
-       dns_dbnode_t *node = rdataset->slab.node;
+       dns_dbnode_t *node = rdataset->proof.node;
 
        dns__db_detachnode(&node DNS__DB_FLARG_PASS);
 }
 
+static isc_result_t
+slabheader_proof_first(dns_rdataset_t *rdataset) {
+       unsigned char *raw = rdataset->proof.raw;
+       uint16_t count = slabheader_proof_count(rdataset);
+
+       if (count == 0) {
+               rdataset->proof.iter_pos = NULL;
+               rdataset->proof.iter_count = 0;
+               return ISC_R_NOMORE;
+       }
+
+       /*
+        * iter_count is the number of rdata beyond the cursor
+        * position, so we decrement the total count by one before
+        * storing it.
+        *
+        * 'raw' points to the first record.
+        */
+       rdataset->proof.iter_pos = raw;
+       rdataset->proof.iter_count = count - 1;
+
+       return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+slabheader_proof_next(dns_rdataset_t *rdataset) {
+       uint16_t count = rdataset->proof.iter_count;
+       if (count == 0) {
+               rdataset->proof.iter_pos = NULL;
+               return ISC_R_NOMORE;
+       }
+       rdataset->proof.iter_count = count - 1;
+
+       /*
+        * Skip forward one record (length + 4) or one offset (4).
+        */
+       unsigned char *raw = rdataset->proof.iter_pos;
+       uint16_t length = peek_uint16(raw);
+       raw += length;
+       rdataset->proof.iter_pos = raw + sizeof(uint16_t);
+
+       return ISC_R_SUCCESS;
+}
+
+static void
+slabheader_proof_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+       unsigned char *raw = NULL;
+       unsigned int length;
+       isc_region_t r;
+       unsigned int flags = 0;
+
+       raw = rdataset->proof.iter_pos;
+       REQUIRE(raw != NULL);
+
+       /*
+        * Find the start of the record if not already in iter_pos
+        * then skip the length and order fields.
+        */
+       length = get_uint16(raw);
+
+       if (rdataset->type == dns_rdatatype_rrsig) {
+               if (*raw & DNS_RDATASLAB_OFFLINE) {
+                       flags |= DNS_RDATA_OFFLINE;
+               }
+               length--;
+               raw++;
+       }
+       r.length = length;
+       r.base = raw;
+       dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+       rdata->flags |= flags;
+}
+
 static void
 slabheader_proof_clone(const dns_rdataset_t *source,
                       dns_rdataset_t *target DNS__DB_FLARG) {
        INSIST(!ISC_LINK_LINKED(target, link));
-       INSIST(target->slab.node == NULL);
+       INSIST(target->proof.node == NULL);
 
        *target = *source;
 
        ISC_LINK_INIT(target, link);
-       target->slab.node = NULL;
-       dns__db_attachnode(source->slab.node,
-                          &target->slab.node DNS__DB_FLARG_PASS);
+       target->proof.node = NULL;
+       dns__db_attachnode(source->proof.node,
+                          &target->proof.node DNS__DB_FLARG_PASS);
 
-       target->slab.iter_pos = NULL;
-       target->slab.iter_count = 0;
+       target->proof.iter_pos = NULL;
+       target->proof.iter_count = 0;
+}
+
+static unsigned int
+slabheader_proof_count(dns_rdataset_t *rdataset) {
+       dns_slabheader_t *header = slabheader_proof_getheader(rdataset);
+
+       return header->nitems;
+}
+
+static dns_slabheader_t *
+slabheader_proof_getheader(const dns_rdataset_t *rdataset) {
+       uint8_t *rawbuf = rdataset->proof.raw;
+       return (dns_slabheader_t *)(rawbuf - offsetof(dns_slabheader_t, raw));
 }
 
 dns_slabtop_t *