2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 13:08:06 +00:00

refactor dns_rdataslab_merge() and _subtract()

these two functions have been refactored for clarity
and readability, with a more logical flow, added comments,
and less code duplication.
This commit is contained in:
Evan Hunt 2025-02-07 14:31:33 -08:00
parent 6908d1f9be
commit f1ab7f199b

View File

@ -77,6 +77,11 @@
buffer += sizeof(uint16_t); \
__ret; \
})
#define put_uint16(buffer, val) \
({ \
*buffer++ = (val & 0xff00) >> 8; \
*buffer++ = (val & 0x00ff); \
})
static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
@ -256,8 +261,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
rawbuf += reservelen;
*rawbuf++ = (nitems & 0xff00) >> 8;
*rawbuf++ = (nitems & 0x00ff);
put_uint16(rawbuf, nitems);
for (i = 0; i < nalloc; i++) {
if (rdata[i].data == &removed) {
@ -268,8 +272,8 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
length++;
}
INSIST(length <= 0xffff);
*rawbuf++ = (length & 0xff00) >> 8;
*rawbuf++ = (length & 0x00ff);
put_uint16(rawbuf, length);
/*
* Store the per RR meta data.
*/
@ -331,8 +335,8 @@ dns_rdataslab_count(dns_slabheader_t *header) {
* point to the next item in the slab.
*/
static void
rdata_from_slab(unsigned char **current, dns_rdataclass_t rdclass,
dns_rdatatype_t type, dns_rdata_t *rdata) {
rdata_from_slabitem(unsigned char **current, dns_rdataclass_t rdclass,
dns_rdatatype_t type, dns_rdata_t *rdata) {
unsigned char *tcurrent = *current;
isc_region_t region;
bool offline = false;
@ -355,32 +359,49 @@ rdata_from_slab(unsigned char **current, dns_rdataclass_t rdclass,
*current = tcurrent;
}
static void
rdata_to_slabitem(unsigned char **current, dns_rdatatype_t type,
dns_rdata_t *rdata) {
unsigned int length = rdata->length;
unsigned char *data = rdata->data;
unsigned char *p = *current;
if (type == dns_rdatatype_rrsig) {
length++;
data--;
}
put_uint16(p, length);
memmove(p, data, length);
p += length;
*current = p;
}
/*
* Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
* contains an rdata identical to 'rdata'. This does case insensitive
* comparisons per DNSSEC.
*/
static bool
rdata_in_slab(unsigned char *slab, unsigned int reservelen,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
dns_rdata_t *rdata) {
unsigned char *current = slab + reservelen;
rdata_in_slab(unsigned char *slab, dns_rdataclass_t rdclass,
dns_rdatatype_t type, dns_rdata_t *rdata) {
unsigned char *current = slab;
uint16_t count = get_uint16(current);
for (size_t i = 0; i < count; i++) {
dns_rdata_t trdata = DNS_RDATA_INIT;
rdata_from_slab(&current, rdclass, type, &trdata);
rdata_from_slabitem(&current, rdclass, type, &trdata);
int n = dns_rdata_compare(&trdata, rdata);
if (n == 0) {
return true;
}
if (n > 0) { /* In DNSSEC order. */
break;
return false;
}
dns_rdata_reset(&trdata);
}
return false;
}
@ -389,31 +410,25 @@ dns_rdataslab_merge(dns_slabheader_t *oheader, dns_slabheader_t *nheader,
isc_mem_t *mctx, dns_rdataclass_t rdclass,
dns_rdatatype_t type, unsigned int flags,
uint32_t maxrrperset, dns_slabheader_t **theaderp) {
unsigned char *oslab = (unsigned char *)oheader;
unsigned char *nslab = (unsigned char *)nheader;
unsigned char *ocurrent = NULL, *ostart = NULL, *ncurrent = NULL;
unsigned char *tstart = NULL, *tcurrent = NULL, *data = NULL;
unsigned int ocount, ncount, count, olength, tlength, tcount, length;
unsigned char *ocurrent = NULL, *oslab = NULL;
unsigned char *ncurrent = NULL, *nslab = NULL;
unsigned char *tstart = NULL, *tcurrent = NULL;
unsigned int oadded = 0, nadded = 0, tcount = 0;
unsigned int ocount, ncount, tlength;
dns_rdata_t ordata = DNS_RDATA_INIT;
dns_rdata_t nrdata = DNS_RDATA_INIT;
bool added_something = false;
unsigned int oadded = 0;
unsigned int nadded = 0;
unsigned int nncount = 0;
/*
* XXX Need parameter to allow "delete rdatasets in nslab" merge,
* or perhaps another merge routine for this purpose.
*/
REQUIRE(theaderp != NULL && *theaderp == NULL);
REQUIRE(oslab != NULL && nslab != NULL);
REQUIRE(oheader != NULL && nheader != NULL);
ocurrent = oslab + sizeof(dns_slabheader_t);
ocurrent = (unsigned char *)oheader + sizeof(dns_slabheader_t);
oslab = ocurrent; /* raw slab (after header but including count) */
ocount = get_uint16(ocurrent);
ostart = ocurrent;
ncurrent = nslab + sizeof(dns_slabheader_t);
ncurrent = (unsigned char *)nheader + sizeof(dns_slabheader_t);
nslab = ncurrent; /* raw slab (after header but including count) */
ncount = get_uint16(ncurrent);
INSIST(ocount > 0 && ncount > 0);
if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
@ -424,53 +439,62 @@ dns_rdataslab_merge(dns_slabheader_t *oheader, dns_slabheader_t *nheader,
* Yes, this is inefficient!
*/
/*
* Figure out the length of the old slab's data.
*/
olength = 0;
for (count = 0; count < ocount; count++) {
length = get_uint16(ocurrent);
olength += length + 2;
ocurrent += length;
}
/*
* Start figuring out the target length and count.
*/
tlength = sizeof(dns_slabheader_t) + 2 + olength;
tcount = ocount;
tlength = sizeof(dns_slabheader_t) + 2;
/*
* Add in the length of rdata in the new slab that aren't in
* Figure out the length of the old slab's data.
*/
for (size_t i = 0; i < ocount; i++) {
unsigned int length = get_uint16(ocurrent);
tlength += length + 2;
ocurrent += length;
}
ocurrent = oslab + 2; /* reposition at the first slab item */
/*
* Add in the length of rdatas in the new slab that aren't in
* the old slab.
*/
do {
for (size_t i = 0; i < ncount; i++) {
dns_rdata_init(&nrdata);
rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
if (!rdata_in_slab(oslab, sizeof(dns_slabheader_t), rdclass,
type, &nrdata))
{
rdata_from_slabitem(&ncurrent, rdclass, type, &nrdata);
if (!rdata_in_slab(oslab, rdclass, type, &nrdata)) {
/*
* This rdata isn't in the old slab.
* This one isn't in the old slab, so we keep it.
*/
tlength += nrdata.length + 2;
if (type == dns_rdatatype_rrsig) {
tlength++;
}
tcount++;
nncount++;
added_something = true;
}
ncount--;
} while (ncount > 0);
ncount = nncount;
}
if (((flags & DNS_RDATASLAB_EXACT) != 0) && (tcount != ncount + ocount))
{
/*
* If the EXACT flag is set, there can't be any rdata in
* the new slab that was also in the old. We can tell because
* tcount is the same as ncount.
*/
if (((flags & DNS_RDATASLAB_EXACT) != 0) && (tcount < ncount)) {
return DNS_R_NOTEXACT;
}
if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0) {
/*
* Now we reduce ncount to the number of items to be copied from
* the new slab.
*/
ncount = tcount;
tcount += ocount;
ncurrent = nslab + 2; /* reposition at the first slab item */
/*
* If nothing's being copied in from the new slab and the FORCE
* flag isn't set, we're done.
*/
if (ncount == 0 && (flags & DNS_RDATASLAB_FORCE) == 0) {
return DNS_R_UNCHANGED;
}
@ -493,34 +517,36 @@ dns_rdataslab_merge(dns_slabheader_t *oheader, dns_slabheader_t *nheader,
* Copy the reserved area from the new slab.
*/
tstart = isc_mem_get(mctx, tlength);
memmove(tstart, nslab, sizeof(dns_slabheader_t));
memmove(tstart, nheader, sizeof(dns_slabheader_t));
tcurrent = tstart + sizeof(dns_slabheader_t);
/*
* Write the new count.
*/
*tcurrent++ = (tcount & 0xff00) >> 8;
*tcurrent++ = (tcount & 0x00ff);
put_uint16(tcurrent, tcount);
/*
* Merge the two slabs.
*/
ocurrent = ostart;
INSIST(ocount != 0);
rdata_from_slab(&ocurrent, rdclass, type, &ordata);
ncurrent = nslab + sizeof(dns_slabheader_t) + 2;
/* Get the first rdata from the old slab */
rdata_from_slabitem(&ocurrent, rdclass, type, &ordata);
if (ncount > 0) {
/*
* Look for the first rdata in the new slab
* that isn't also in the old slab.
*/
do {
dns_rdata_reset(&nrdata);
rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
} while (rdata_in_slab(oslab, sizeof(dns_slabheader_t), rdclass,
type, &nrdata));
rdata_from_slabitem(&ncurrent, rdclass, type, &nrdata);
} while (rdata_in_slab(oslab, rdclass, type, &nrdata));
}
while (oadded < ocount || nadded < ncount) {
bool fromold;
if (oadded == ocount) {
fromold = false;
} else if (nadded == ncount) {
@ -528,43 +554,28 @@ dns_rdataslab_merge(dns_slabheader_t *oheader, dns_slabheader_t *nheader,
} else {
fromold = (dns_rdata_compare(&ordata, &nrdata) < 0);
}
if (fromold) {
length = ordata.length;
data = ordata.data;
if (type == dns_rdatatype_rrsig) {
length++;
data--;
}
*tcurrent++ = (length & 0xff00) >> 8;
*tcurrent++ = (length & 0x00ff);
memmove(tcurrent, data, length);
tcurrent += length;
oadded++;
if (oadded < ocount) {
rdata_to_slabitem(&tcurrent, type, &ordata);
if (++oadded < ocount) {
/* Skip to the next rdata in the old slab */
dns_rdata_reset(&ordata);
rdata_from_slab(&ocurrent, rdclass, type,
&ordata);
rdata_from_slabitem(&ocurrent, rdclass, type,
&ordata);
}
} else {
length = nrdata.length;
data = nrdata.data;
if (type == dns_rdatatype_rrsig) {
length++;
data--;
}
*tcurrent++ = (length & 0xff00) >> 8;
*tcurrent++ = (length & 0x00ff);
memmove(tcurrent, data, length);
tcurrent += length;
nadded++;
if (nadded < ncount) {
rdata_to_slabitem(&tcurrent, type, &nrdata);
if (++nadded < ncount) {
/*
* Skip to the next rdata in the new slab
* that isn't in the old one.
*/
do {
dns_rdata_reset(&nrdata);
rdata_from_slab(&ncurrent, rdclass,
type, &nrdata);
} while (rdata_in_slab(oslab,
sizeof(dns_slabheader_t),
rdclass, type, &nrdata));
rdata_from_slabitem(&ncurrent, rdclass,
type, &nrdata);
} while (rdata_in_slab(oslab, rdclass, type,
&nrdata));
}
}
}
@ -581,21 +592,23 @@ dns_rdataslab_subtract(dns_slabheader_t *mheader, dns_slabheader_t *sheader,
isc_mem_t *mctx, dns_rdataclass_t rdclass,
dns_rdatatype_t type, unsigned int flags,
dns_slabheader_t **theaderp) {
unsigned char *mslab = (unsigned char *)mheader;
unsigned char *sslab = (unsigned char *)sheader;
unsigned char *mcurrent = NULL, *sstart = NULL, *scurrent = NULL;
unsigned char *mstart = NULL, *mcurrent = NULL;
unsigned char *sstart = NULL, *scurrent = NULL;
unsigned char *tstart = NULL, *tcurrent = NULL;
unsigned int mcount, scount, rcount, count, tlength, tcount, i;
dns_rdata_t srdata = DNS_RDATA_INIT;
dns_rdata_t mrdata = DNS_RDATA_INIT;
unsigned int mcount, scount, count, tlength;
unsigned int tcount = 0, rcount = 0;
REQUIRE(theaderp != NULL && *theaderp == NULL);
REQUIRE(mslab != NULL && sslab != NULL);
REQUIRE(mheader != NULL && sheader != NULL);
mcurrent = mslab + sizeof(dns_slabheader_t);
mcurrent = (unsigned char *)mheader + sizeof(dns_slabheader_t);
mcount = get_uint16(mcurrent);
scurrent = sslab + sizeof(dns_slabheader_t);
mstart = mcurrent; /* start of the first slab item (after the count) */
scurrent = (unsigned char *)sheader + sizeof(dns_slabheader_t);
scount = get_uint16(scurrent);
sstart = scurrent;
INSIST(mcount > 0 && scount > 0);
/*
@ -606,38 +619,36 @@ dns_rdataslab_subtract(dns_slabheader_t *mheader, dns_slabheader_t *sheader,
* Start figuring out the target length and count.
*/
tlength = sizeof(dns_slabheader_t) + 2;
tcount = 0;
rcount = 0;
sstart = scurrent;
/*
* Add in the length of rdata in the mslab that aren't in
* the sslab.
* Add in the length of rdata in the mheader slab that aren't in
* the sheader slab.
*/
for (i = 0; i < mcount; i++) {
for (size_t i = 0; i < mcount; i++) {
dns_rdata_t mrdata = DNS_RDATA_INIT;
unsigned char *mrdatabegin = mcurrent;
rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
scurrent = sstart;
rdata_from_slabitem(&mcurrent, rdclass, type, &mrdata);
for (count = 0; count < scount; count++) {
dns_rdata_reset(&srdata);
rdata_from_slab(&scurrent, rdclass, type, &srdata);
dns_rdata_t srdata = DNS_RDATA_INIT;
rdata_from_slabitem(&scurrent, rdclass, type, &srdata);
if (dns_rdata_compare(&mrdata, &srdata) == 0) {
break;
}
}
scurrent = sstart;
if (count == scount) {
/*
* This rdata isn't in the sslab, and thus isn't
* being subtracted.
* This rdata isn't in the sheader slab, and thus
* isn't being subtracted.
*/
tlength += (unsigned int)(mcurrent - mrdatabegin);
tcount++;
} else {
rcount++;
}
dns_rdata_reset(&mrdata);
}
mcurrent = mstart;
/*
* Check that all the records originally existed. The numeric
@ -662,45 +673,44 @@ dns_rdataslab_subtract(dns_slabheader_t *mheader, dns_slabheader_t *sheader,
}
/*
* Copy the reserved area from the mslab.
* Copy the reserved area from the mheader slab.
*/
tstart = isc_mem_get(mctx, tlength);
memmove(tstart, mslab, sizeof(dns_slabheader_t));
memmove(tstart, mheader, sizeof(dns_slabheader_t));
tcurrent = tstart + sizeof(dns_slabheader_t);
/*
* Write the new count.
*/
*tcurrent++ = (tcount & 0xff00) >> 8;
*tcurrent++ = (tcount & 0x00ff);
put_uint16(tcurrent, tcount);
/*
* Copy the parts of mslab not in sslab.
* Copy the parts of the mheader slab not in sheader.
*/
mcurrent = mslab + sizeof(dns_slabheader_t);
mcount = get_uint16(mcurrent);
for (i = 0; i < mcount; i++) {
for (size_t i = 0; i < mcount; i++) {
dns_rdata_t mrdata = DNS_RDATA_INIT;
unsigned char *mrdatabegin = mcurrent;
rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
scurrent = sstart;
rdata_from_slabitem(&mcurrent, rdclass, type, &mrdata);
for (count = 0; count < scount; count++) {
dns_rdata_reset(&srdata);
rdata_from_slab(&scurrent, rdclass, type, &srdata);
dns_rdata_t srdata = DNS_RDATA_INIT;
rdata_from_slabitem(&scurrent, rdclass, type, &srdata);
if (dns_rdata_compare(&mrdata, &srdata) == 0) {
break;
}
}
scurrent = sstart;
if (count == scount) {
/*
* This rdata isn't in the sslab, and thus should be
* copied to the tslab.
* We didn't find this item in the sheader slab, so
* it isn't being removed: copy it to the target
* slab.
*/
unsigned int length;
length = (unsigned int)(mcurrent - mrdatabegin);
unsigned int length =
(unsigned int)(mcurrent - mrdatabegin);
memmove(tcurrent, mrdatabegin, length);
tcurrent += length;
}
dns_rdata_reset(&mrdata);
}
INSIST(tcurrent == tstart + tlength);
@ -765,8 +775,8 @@ dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2,
dns_rdata_t rdata1 = DNS_RDATA_INIT;
dns_rdata_t rdata2 = DNS_RDATA_INIT;
rdata_from_slab(&current1, rdclass, type, &rdata1);
rdata_from_slab(&current2, rdclass, type, &rdata2);
rdata_from_slabitem(&current1, rdclass, type, &rdata1);
rdata_from_slabitem(&current2, rdclass, type, &rdata2);
if (dns_rdata_compare(&rdata1, &rdata2) != 0) {
return false;
}