From: Ondřej Surý Date: Thu, 18 Jun 2026 09:39:05 +0000 (+0200) Subject: Split the slabheader and slabheader_proof structures in rdataset X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f9ff2de9844c0c5a42d31dd87b444e31b094de0d;p=thirdparty%2Fbind9.git Split the slabheader and slabheader_proof structures in rdataset 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. --- diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 0d2681b610..6691216ecd 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -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 diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 85ceb537e0..8250405ed1 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -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; diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index d0d45a3325..06fe3487dc 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -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 *