xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdataslab.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: rdataslab.c,v 1.10 2025/01/26 16:25:24 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <ctype.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 
22 #include <isc/ascii.h>
23 #include <isc/mem.h>
24 #include <isc/region.h>
25 #include <isc/result.h>
26 #include <isc/string.h>
27 #include <isc/util.h>
28 
29 #include <dns/db.h>
30 #include <dns/rdata.h>
31 #include <dns/rdataset.h>
32 #include <dns/rdataslab.h>
33 #include <dns/stats.h>
34 
35 #define CASESET(header)                                \
36 	((atomic_load_acquire(&(header)->attributes) & \
37 	  DNS_SLABHEADERATTR_CASESET) != 0)
38 #define CASEFULLYLOWER(header)                         \
39 	((atomic_load_acquire(&(header)->attributes) & \
40 	  DNS_SLABHEADERATTR_CASEFULLYLOWER) != 0)
41 #define NONEXISTENT(header)                            \
42 	((atomic_load_acquire(&(header)->attributes) & \
43 	  DNS_SLABHEADERATTR_NONEXISTENT) != 0)
44 
45 /*
46  * The rdataslab structure allows iteration to occur in both load order
47  * and DNSSEC order.  The structure is as follows:
48  *
49  *	header		(reservelen bytes)
50  *	record count	(2 bytes)
51  *	offset table	(4 x record count bytes in load order)
52  *	data records
53  *		data length	(2 bytes)
54  *		order		(2 bytes)
55  *		meta data	(1 byte for RRSIG's)
56  *		data		(data length bytes)
57  *
58  * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
59  * rdataslab is as follows:
60  *
61  *	header		(reservelen bytes)
62  *	record count	(2 bytes)
63  *	data records
64  *		data length	(2 bytes)
65  *		meta data	(1 byte for RRSIG's)
66  *		data		(data length bytes)
67  *
68  * Offsets are from the end of the header.
69  *
70  * Load order traversal is performed by walking the offset table to find
71  * the start of the record (DNS_RDATASET_FIXED = 1).
72  *
73  * DNSSEC order traversal is performed by walking the data records.
74  *
75  * The order is stored with record to allow for efficient reconstruction
76  * of the offset table following a merge or subtraction.
77  *
78  * The iterator methods in rbtdb support both load order and DNSSEC order
79  * iteration.
80  *
81  * WARNING:
82  *	rbtdb.c directly interacts with the slab's raw structures.  If the
83  *	structure changes then rbtdb.c also needs to be updated to reflect
84  *	the changes.  See the areas tagged with "RDATASLAB".
85  */
86 
87 struct xrdata {
88 	dns_rdata_t rdata;
89 #if DNS_RDATASET_FIXED
90 	unsigned int order;
91 #endif /* if DNS_RDATASET_FIXED */
92 };
93 
94 #define peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); })
95 #define get_uint16(buffer)                            \
96 	({                                            \
97 		uint16_t __ret = peek_uint16(buffer); \
98 		buffer += sizeof(uint16_t);           \
99 		__ret;                                \
100 	})
101 
102 static void
103 rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
104 static isc_result_t
105 rdataset_first(dns_rdataset_t *rdataset);
106 static isc_result_t
107 rdataset_next(dns_rdataset_t *rdataset);
108 static void
109 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
110 static void
111 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG);
112 static unsigned int
113 rdataset_count(dns_rdataset_t *rdataset);
114 static isc_result_t
115 rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
116 		    dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
117 static isc_result_t
118 rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
119 		    dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
120 static void
121 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
122 static void
123 rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG);
124 static void
125 rdataset_clearprefetch(dns_rdataset_t *rdataset);
126 static void
127 rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name);
128 static void
129 rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
130 
131 /*% Note: the "const void *" are just to make qsort happy.  */
132 static int
133 compare_rdata(const void *p1, const void *p2) {
134 	const struct xrdata *x1 = p1;
135 	const struct xrdata *x2 = p2;
136 	return dns_rdata_compare(&x1->rdata, &x2->rdata);
137 }
138 
139 #if DNS_RDATASET_FIXED
140 static void
141 fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
142 	       unsigned int length) {
143 	unsigned int i, j;
144 	unsigned char *raw = NULL;
145 
146 	for (i = 0, j = 0; i < length; i++) {
147 		if (offsettable[i] == 0) {
148 			continue;
149 		}
150 
151 		/*
152 		 * Fill in offset table.
153 		 */
154 		raw = &offsetbase[j * 4 + 2];
155 		*raw++ = (offsettable[i] & 0xff000000) >> 24;
156 		*raw++ = (offsettable[i] & 0xff0000) >> 16;
157 		*raw++ = (offsettable[i] & 0xff00) >> 8;
158 		*raw = offsettable[i] & 0xff;
159 
160 		/*
161 		 * Fill in table index.
162 		 */
163 		raw = offsetbase + offsettable[i] + 2;
164 		*raw++ = (j & 0xff00) >> 8;
165 		*raw = j++ & 0xff;
166 	}
167 }
168 #endif /* if DNS_RDATASET_FIXED */
169 
170 isc_result_t
171 dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
172 			   isc_region_t *region, unsigned int reservelen,
173 			   uint32_t maxrrperset) {
174 	/*
175 	 * Use &removed as a sentinel pointer for duplicate
176 	 * rdata as rdata.data == NULL is valid.
177 	 */
178 	static unsigned char removed;
179 	struct xrdata *x = NULL;
180 	unsigned char *rawbuf = NULL;
181 	unsigned int buflen;
182 	isc_result_t result;
183 	unsigned int nitems;
184 	unsigned int nalloc;
185 	unsigned int length;
186 	unsigned int i;
187 #if DNS_RDATASET_FIXED
188 	unsigned char *offsetbase = NULL;
189 	unsigned int *offsettable = NULL;
190 #endif /* if DNS_RDATASET_FIXED */
191 
192 	buflen = reservelen + 2;
193 
194 	nitems = dns_rdataset_count(rdataset);
195 
196 	/*
197 	 * If there are no rdata then we can just need to allocate a header
198 	 * with zero a record count.
199 	 */
200 	if (nitems == 0) {
201 		if (rdataset->type != 0) {
202 			return ISC_R_FAILURE;
203 		}
204 		rawbuf = isc_mem_get(mctx, buflen);
205 		region->base = rawbuf;
206 		region->length = buflen;
207 		rawbuf += reservelen;
208 		*rawbuf++ = 0;
209 		*rawbuf = 0;
210 		return ISC_R_SUCCESS;
211 	}
212 
213 	if (maxrrperset > 0 && nitems > maxrrperset) {
214 		return DNS_R_TOOMANYRECORDS;
215 	}
216 
217 	if (nitems > 0xffff) {
218 		return ISC_R_NOSPACE;
219 	}
220 
221 	/*
222 	 * Remember the original number of items.
223 	 */
224 	nalloc = nitems;
225 	x = isc_mem_cget(mctx, nalloc, sizeof(struct xrdata));
226 
227 	/*
228 	 * Save all of the rdata members into an array.
229 	 */
230 	result = dns_rdataset_first(rdataset);
231 	if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
232 		goto free_rdatas;
233 	}
234 	for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
235 		INSIST(result == ISC_R_SUCCESS);
236 		dns_rdata_init(&x[i].rdata);
237 		dns_rdataset_current(rdataset, &x[i].rdata);
238 		INSIST(x[i].rdata.data != &removed);
239 #if DNS_RDATASET_FIXED
240 		x[i].order = i;
241 #endif /* if DNS_RDATASET_FIXED */
242 		result = dns_rdataset_next(rdataset);
243 	}
244 	if (i != nalloc || result != ISC_R_NOMORE) {
245 		/*
246 		 * Somehow we iterated over fewer rdatas than
247 		 * dns_rdataset_count() said there were or there
248 		 * were more items than dns_rdataset_count said
249 		 * there were.
250 		 */
251 		result = ISC_R_FAILURE;
252 		goto free_rdatas;
253 	}
254 
255 	/*
256 	 * Put into DNSSEC order.
257 	 */
258 	if (nalloc > 1U) {
259 		qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);
260 	}
261 
262 	/*
263 	 * Remove duplicates and compute the total storage required.
264 	 *
265 	 * If an rdata is not a duplicate, accumulate the storage size
266 	 * required for the rdata.  We do not store the class, type, etc,
267 	 * just the rdata, so our overhead is 2 bytes for the number of
268 	 * records, and 8 for each rdata, (length(2), offset(4) and order(2))
269 	 * and then the rdata itself.
270 	 */
271 	for (i = 1; i < nalloc; i++) {
272 		if (compare_rdata(&x[i - 1].rdata, &x[i].rdata) == 0) {
273 			x[i - 1].rdata.data = &removed;
274 #if DNS_RDATASET_FIXED
275 			/*
276 			 * Preserve the least order so A, B, A -> A, B
277 			 * after duplicate removal.
278 			 */
279 			if (x[i - 1].order < x[i].order) {
280 				x[i].order = x[i - 1].order;
281 			}
282 #endif /* if DNS_RDATASET_FIXED */
283 			nitems--;
284 		} else {
285 #if DNS_RDATASET_FIXED
286 			buflen += (8 + x[i - 1].rdata.length);
287 #else  /* if DNS_RDATASET_FIXED */
288 			buflen += (2 + x[i - 1].rdata.length);
289 #endif /* if DNS_RDATASET_FIXED */
290 			/*
291 			 * Provide space to store the per RR meta data.
292 			 */
293 			if (rdataset->type == dns_rdatatype_rrsig) {
294 				buflen++;
295 			}
296 		}
297 	}
298 
299 	/*
300 	 * Don't forget the last item!
301 	 */
302 #if DNS_RDATASET_FIXED
303 	buflen += (8 + x[i - 1].rdata.length);
304 #else  /* if DNS_RDATASET_FIXED */
305 	buflen += (2 + x[i - 1].rdata.length);
306 #endif /* if DNS_RDATASET_FIXED */
307 	/*
308 	 * Provide space to store the per RR meta data.
309 	 */
310 	if (rdataset->type == dns_rdatatype_rrsig) {
311 		buflen++;
312 	}
313 
314 	/*
315 	 * Ensure that singleton types are actually singletons.
316 	 */
317 	if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
318 		/*
319 		 * We have a singleton type, but there's more than one
320 		 * RR in the rdataset.
321 		 */
322 		result = DNS_R_SINGLETON;
323 		goto free_rdatas;
324 	}
325 
326 	/*
327 	 * Allocate the memory, set up a buffer, start copying in
328 	 * data.
329 	 */
330 	rawbuf = isc_mem_cget(mctx, 1, buflen);
331 
332 #if DNS_RDATASET_FIXED
333 	/* Allocate temporary offset table. */
334 	offsettable = isc_mem_cget(mctx, nalloc, sizeof(unsigned int));
335 #endif /* if DNS_RDATASET_FIXED */
336 
337 	region->base = rawbuf;
338 	region->length = buflen;
339 
340 	rawbuf += reservelen;
341 
342 #if DNS_RDATASET_FIXED
343 	offsetbase = rawbuf;
344 #endif /* if DNS_RDATASET_FIXED */
345 
346 	*rawbuf++ = (nitems & 0xff00) >> 8;
347 	*rawbuf++ = (nitems & 0x00ff);
348 
349 #if DNS_RDATASET_FIXED
350 	/* Skip load order table.  Filled in later. */
351 	rawbuf += nitems * 4;
352 #endif /* if DNS_RDATASET_FIXED */
353 
354 	for (i = 0; i < nalloc; i++) {
355 		if (x[i].rdata.data == &removed) {
356 			continue;
357 		}
358 #if DNS_RDATASET_FIXED
359 		offsettable[x[i].order] = rawbuf - offsetbase;
360 #endif /* if DNS_RDATASET_FIXED */
361 		length = x[i].rdata.length;
362 		if (rdataset->type == dns_rdatatype_rrsig) {
363 			length++;
364 		}
365 		INSIST(length <= 0xffff);
366 		*rawbuf++ = (length & 0xff00) >> 8;
367 		*rawbuf++ = (length & 0x00ff);
368 #if DNS_RDATASET_FIXED
369 		rawbuf += 2; /* filled in later */
370 #endif			     /* if DNS_RDATASET_FIXED */
371 		/*
372 		 * Store the per RR meta data.
373 		 */
374 		if (rdataset->type == dns_rdatatype_rrsig) {
375 			*rawbuf++ = (x[i].rdata.flags & DNS_RDATA_OFFLINE)
376 					    ? DNS_RDATASLAB_OFFLINE
377 					    : 0;
378 		}
379 		if (x[i].rdata.length != 0) {
380 			memmove(rawbuf, x[i].rdata.data, x[i].rdata.length);
381 		}
382 		rawbuf += x[i].rdata.length;
383 	}
384 
385 #if DNS_RDATASET_FIXED
386 	fillin_offsets(offsetbase, offsettable, nalloc);
387 	isc_mem_cput(mctx, offsettable, nalloc, sizeof(unsigned int));
388 #endif /* if DNS_RDATASET_FIXED */
389 
390 	result = ISC_R_SUCCESS;
391 
392 free_rdatas:
393 	isc_mem_cput(mctx, x, nalloc, sizeof(struct xrdata));
394 	return result;
395 }
396 
397 unsigned int
398 dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) {
399 	REQUIRE(slab != NULL);
400 
401 	unsigned char *current = slab + reservelen;
402 	uint16_t count = get_uint16(current);
403 
404 #if DNS_RDATASET_FIXED
405 	current += (4 * count);
406 #endif /* if DNS_RDATASET_FIXED */
407 
408 	while (count-- > 0) {
409 		uint16_t length = get_uint16(current);
410 		current += length;
411 #if DNS_RDATASET_FIXED
412 		current += 2;
413 #endif /* if DNS_RDATASET_FIXED */
414 	}
415 
416 	return (unsigned int)(current - slab);
417 }
418 
419 unsigned int
420 dns_rdataslab_rdatasize(unsigned char *slab, unsigned int reservelen) {
421 	REQUIRE(slab != NULL);
422 
423 	uint16_t rdatalen = 0;
424 	unsigned char *current = slab + reservelen;
425 	uint16_t count = get_uint16(current);
426 
427 #if DNS_RDATASET_FIXED
428 	current += (4 * count);
429 #endif /* if DNS_RDATASET_FIXED */
430 
431 	while (count-- > 0) {
432 		uint16_t length = get_uint16(current);
433 		rdatalen += length;
434 		current += length;
435 #if DNS_RDATASET_FIXED
436 		current += 2;
437 #endif /* if DNS_RDATASET_FIXED */
438 	}
439 
440 	return rdatalen;
441 }
442 
443 unsigned int
444 dns_rdataslab_count(unsigned char *slab, unsigned int reservelen) {
445 	REQUIRE(slab != NULL);
446 
447 	unsigned char *current = slab + reservelen;
448 	uint16_t count = get_uint16(current);
449 
450 	return count;
451 }
452 
453 /*
454  * Make the dns_rdata_t 'rdata' refer to the slab item
455  * beginning at '*current', which is part of a slab of type
456  * 'type' and class 'rdclass', and advance '*current' to
457  * point to the next item in the slab.
458  */
459 static void
460 rdata_from_slab(unsigned char **current, dns_rdataclass_t rdclass,
461 		dns_rdatatype_t type, dns_rdata_t *rdata) {
462 	unsigned char *tcurrent = *current;
463 	isc_region_t region;
464 	bool offline = false;
465 	uint16_t length = get_uint16(tcurrent);
466 
467 	if (type == dns_rdatatype_rrsig) {
468 		if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) {
469 			offline = true;
470 		}
471 		length--;
472 		tcurrent++;
473 	}
474 	region.length = length;
475 #if DNS_RDATASET_FIXED
476 	tcurrent += 2;
477 #endif /* if DNS_RDATASET_FIXED */
478 	region.base = tcurrent;
479 	tcurrent += region.length;
480 	dns_rdata_fromregion(rdata, rdclass, type, &region);
481 	if (offline) {
482 		rdata->flags |= DNS_RDATA_OFFLINE;
483 	}
484 	*current = tcurrent;
485 }
486 
487 /*
488  * Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
489  * contains an rdata identical to 'rdata'.  This does case insensitive
490  * comparisons per DNSSEC.
491  */
492 static bool
493 rdata_in_slab(unsigned char *slab, unsigned int reservelen,
494 	      dns_rdataclass_t rdclass, dns_rdatatype_t type,
495 	      dns_rdata_t *rdata) {
496 	unsigned char *current = slab + reservelen;
497 
498 	uint16_t count = get_uint16(current);
499 
500 #if DNS_RDATASET_FIXED
501 	current += (4 * count);
502 #endif /* if DNS_RDATASET_FIXED */
503 
504 	for (size_t i = 0; i < count; i++) {
505 		dns_rdata_t trdata = DNS_RDATA_INIT;
506 		rdata_from_slab(&current, rdclass, type, &trdata);
507 
508 		int n = dns_rdata_compare(&trdata, rdata);
509 		if (n == 0) {
510 			return true;
511 		}
512 		if (n > 0) { /* In DNSSEC order. */
513 			break;
514 		}
515 		dns_rdata_reset(&trdata);
516 	}
517 	return false;
518 }
519 
520 isc_result_t
521 dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
522 		    unsigned int reservelen, isc_mem_t *mctx,
523 		    dns_rdataclass_t rdclass, dns_rdatatype_t type,
524 		    unsigned int flags, uint32_t maxrrperset,
525 		    unsigned char **tslabp) {
526 	unsigned char *ocurrent = NULL, *ostart = NULL, *ncurrent = NULL;
527 	unsigned char *tstart = NULL, *tcurrent = NULL, *data = NULL;
528 	unsigned int ocount, ncount, count, olength, tlength, tcount, length;
529 	dns_rdata_t ordata = DNS_RDATA_INIT;
530 	dns_rdata_t nrdata = DNS_RDATA_INIT;
531 	bool added_something = false;
532 	unsigned int oadded = 0;
533 	unsigned int nadded = 0;
534 	unsigned int nncount = 0;
535 #if DNS_RDATASET_FIXED
536 	unsigned int oncount;
537 	unsigned int norder = 0;
538 	unsigned int oorder = 0;
539 	unsigned char *offsetbase = NULL;
540 	unsigned int *offsettable = NULL;
541 #endif /* if DNS_RDATASET_FIXED */
542 
543 	/*
544 	 * XXX  Need parameter to allow "delete rdatasets in nslab" merge,
545 	 * or perhaps another merge routine for this purpose.
546 	 */
547 
548 	REQUIRE(tslabp != NULL && *tslabp == NULL);
549 	REQUIRE(oslab != NULL && nslab != NULL);
550 
551 	ocurrent = oslab + reservelen;
552 	ocount = get_uint16(ocurrent);
553 #if DNS_RDATASET_FIXED
554 	ocurrent += (4 * ocount);
555 #endif /* if DNS_RDATASET_FIXED */
556 	ostart = ocurrent;
557 	ncurrent = nslab + reservelen;
558 	ncount = get_uint16(ncurrent);
559 #if DNS_RDATASET_FIXED
560 	ncurrent += (4 * ncount);
561 #endif /* if DNS_RDATASET_FIXED */
562 	INSIST(ocount > 0 && ncount > 0);
563 
564 	if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
565 		return DNS_R_TOOMANYRECORDS;
566 	}
567 
568 #if DNS_RDATASET_FIXED
569 	oncount = ncount;
570 #endif /* if DNS_RDATASET_FIXED */
571 
572 	/*
573 	 * Yes, this is inefficient!
574 	 */
575 
576 	/*
577 	 * Figure out the length of the old slab's data.
578 	 */
579 	olength = 0;
580 	for (count = 0; count < ocount; count++) {
581 		length = get_uint16(ocurrent);
582 #if DNS_RDATASET_FIXED
583 		olength += length + 8;
584 		ocurrent += length + 2;
585 #else  /* if DNS_RDATASET_FIXED */
586 		olength += length + 2;
587 		ocurrent += length;
588 #endif /* if DNS_RDATASET_FIXED */
589 	}
590 
591 	/*
592 	 * Start figuring out the target length and count.
593 	 */
594 	tlength = reservelen + 2 + olength;
595 	tcount = ocount;
596 
597 	/*
598 	 * Add in the length of rdata in the new slab that aren't in
599 	 * the old slab.
600 	 */
601 	do {
602 		dns_rdata_init(&nrdata);
603 		rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
604 		if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata)) {
605 			/*
606 			 * This rdata isn't in the old slab.
607 			 */
608 #if DNS_RDATASET_FIXED
609 			tlength += nrdata.length + 8;
610 #else  /* if DNS_RDATASET_FIXED */
611 			tlength += nrdata.length + 2;
612 #endif /* if DNS_RDATASET_FIXED */
613 			if (type == dns_rdatatype_rrsig) {
614 				tlength++;
615 			}
616 			tcount++;
617 			nncount++;
618 			added_something = true;
619 		}
620 		ncount--;
621 	} while (ncount > 0);
622 	ncount = nncount;
623 
624 	if (((flags & DNS_RDATASLAB_EXACT) != 0) && (tcount != ncount + ocount))
625 	{
626 		return DNS_R_NOTEXACT;
627 	}
628 
629 	if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0) {
630 		return DNS_R_UNCHANGED;
631 	}
632 
633 	/*
634 	 * Ensure that singleton types are actually singletons.
635 	 */
636 	if (tcount > 1 && dns_rdatatype_issingleton(type)) {
637 		/*
638 		 * We have a singleton type, but there's more than one
639 		 * RR in the rdataset.
640 		 */
641 		return DNS_R_SINGLETON;
642 	}
643 
644 	if (tcount > 0xffff) {
645 		return ISC_R_NOSPACE;
646 	}
647 
648 	/*
649 	 * Copy the reserved area from the new slab.
650 	 */
651 	tstart = isc_mem_get(mctx, tlength);
652 	memmove(tstart, nslab, reservelen);
653 	tcurrent = tstart + reservelen;
654 #if DNS_RDATASET_FIXED
655 	offsetbase = tcurrent;
656 #endif /* if DNS_RDATASET_FIXED */
657 
658 	/*
659 	 * Write the new count.
660 	 */
661 	*tcurrent++ = (tcount & 0xff00) >> 8;
662 	*tcurrent++ = (tcount & 0x00ff);
663 
664 #if DNS_RDATASET_FIXED
665 	/*
666 	 * Skip offset table.
667 	 */
668 	tcurrent += (tcount * 4);
669 
670 	offsettable = isc_mem_cget(mctx, (ocount + oncount),
671 				   sizeof(unsigned int));
672 #endif /* if DNS_RDATASET_FIXED */
673 
674 	/*
675 	 * Merge the two slabs.
676 	 */
677 	ocurrent = ostart;
678 	INSIST(ocount != 0);
679 #if DNS_RDATASET_FIXED
680 	oorder = peek_uint16(&ocurrent[2]);
681 	INSIST(oorder < ocount);
682 #endif /* if DNS_RDATASET_FIXED */
683 	rdata_from_slab(&ocurrent, rdclass, type, &ordata);
684 
685 	ncurrent = nslab + reservelen + 2;
686 #if DNS_RDATASET_FIXED
687 	ncurrent += (4 * oncount);
688 #endif /* if DNS_RDATASET_FIXED */
689 
690 	if (ncount > 0) {
691 		do {
692 			dns_rdata_reset(&nrdata);
693 #if DNS_RDATASET_FIXED
694 			norder = peek_uint16(&ncurrent[2]);
695 
696 			INSIST(norder < oncount);
697 #endif /* if DNS_RDATASET_FIXED */
698 			rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
699 		} while (rdata_in_slab(oslab, reservelen, rdclass, type,
700 				       &nrdata));
701 	}
702 
703 	while (oadded < ocount || nadded < ncount) {
704 		bool fromold;
705 		if (oadded == ocount) {
706 			fromold = false;
707 		} else if (nadded == ncount) {
708 			fromold = true;
709 		} else {
710 			fromold = (dns_rdata_compare(&ordata, &nrdata) < 0);
711 		}
712 		if (fromold) {
713 #if DNS_RDATASET_FIXED
714 			offsettable[oorder] = tcurrent - offsetbase;
715 #endif /* if DNS_RDATASET_FIXED */
716 			length = ordata.length;
717 			data = ordata.data;
718 			if (type == dns_rdatatype_rrsig) {
719 				length++;
720 				data--;
721 			}
722 			*tcurrent++ = (length & 0xff00) >> 8;
723 			*tcurrent++ = (length & 0x00ff);
724 #if DNS_RDATASET_FIXED
725 			tcurrent += 2; /* fill in later */
726 #endif				       /* if DNS_RDATASET_FIXED */
727 			memmove(tcurrent, data, length);
728 			tcurrent += length;
729 			oadded++;
730 			if (oadded < ocount) {
731 				dns_rdata_reset(&ordata);
732 #if DNS_RDATASET_FIXED
733 				oorder = peek_uint16(&ocurrent[2]);
734 				INSIST(oorder < ocount);
735 #endif /* if DNS_RDATASET_FIXED */
736 				rdata_from_slab(&ocurrent, rdclass, type,
737 						&ordata);
738 			}
739 		} else {
740 #if DNS_RDATASET_FIXED
741 			offsettable[ocount + norder] = tcurrent - offsetbase;
742 #endif /* if DNS_RDATASET_FIXED */
743 			length = nrdata.length;
744 			data = nrdata.data;
745 			if (type == dns_rdatatype_rrsig) {
746 				length++;
747 				data--;
748 			}
749 			*tcurrent++ = (length & 0xff00) >> 8;
750 			*tcurrent++ = (length & 0x00ff);
751 #if DNS_RDATASET_FIXED
752 			tcurrent += 2; /* fill in later */
753 #endif				       /* if DNS_RDATASET_FIXED */
754 			memmove(tcurrent, data, length);
755 			tcurrent += length;
756 			nadded++;
757 			if (nadded < ncount) {
758 				do {
759 					dns_rdata_reset(&nrdata);
760 #if DNS_RDATASET_FIXED
761 					norder = peek_uint16(&ncurrent[2]);
762 					INSIST(norder < oncount);
763 #endif /* if DNS_RDATASET_FIXED */
764 					rdata_from_slab(&ncurrent, rdclass,
765 							type, &nrdata);
766 				} while (rdata_in_slab(oslab, reservelen,
767 						       rdclass, type, &nrdata));
768 			}
769 		}
770 	}
771 
772 #if DNS_RDATASET_FIXED
773 	fillin_offsets(offsetbase, offsettable, ocount + oncount);
774 
775 	isc_mem_cput(mctx, offsettable, (ocount + oncount),
776 		     sizeof(unsigned int));
777 #endif /* if DNS_RDATASET_FIXED */
778 
779 	INSIST(tcurrent == tstart + tlength);
780 
781 	*tslabp = tstart;
782 
783 	return ISC_R_SUCCESS;
784 }
785 
786 isc_result_t
787 dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
788 		       unsigned int reservelen, isc_mem_t *mctx,
789 		       dns_rdataclass_t rdclass, dns_rdatatype_t type,
790 		       unsigned int flags, unsigned char **tslabp) {
791 	unsigned char *mcurrent = NULL, *sstart = NULL, *scurrent = NULL;
792 	unsigned char *tstart = NULL, *tcurrent = NULL;
793 	unsigned int mcount, scount, rcount, count, tlength, tcount, i;
794 	dns_rdata_t srdata = DNS_RDATA_INIT;
795 	dns_rdata_t mrdata = DNS_RDATA_INIT;
796 #if DNS_RDATASET_FIXED
797 	unsigned char *offsetbase = NULL;
798 	unsigned int *offsettable = NULL;
799 	unsigned int order;
800 #endif /* if DNS_RDATASET_FIXED */
801 
802 	REQUIRE(tslabp != NULL && *tslabp == NULL);
803 	REQUIRE(mslab != NULL && sslab != NULL);
804 
805 	mcurrent = mslab + reservelen;
806 	mcount = get_uint16(mcurrent);
807 	scurrent = sslab + reservelen;
808 	scount = get_uint16(scurrent);
809 	INSIST(mcount > 0 && scount > 0);
810 
811 	/*
812 	 * Yes, this is inefficient!
813 	 */
814 
815 	/*
816 	 * Start figuring out the target length and count.
817 	 */
818 	tlength = reservelen + 2;
819 	tcount = 0;
820 	rcount = 0;
821 
822 #if DNS_RDATASET_FIXED
823 	mcurrent += 4 * mcount;
824 	scurrent += 4 * scount;
825 #endif /* if DNS_RDATASET_FIXED */
826 	sstart = scurrent;
827 
828 	/*
829 	 * Add in the length of rdata in the mslab that aren't in
830 	 * the sslab.
831 	 */
832 	for (i = 0; i < mcount; i++) {
833 		unsigned char *mrdatabegin = mcurrent;
834 		rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
835 		scurrent = sstart;
836 		for (count = 0; count < scount; count++) {
837 			dns_rdata_reset(&srdata);
838 			rdata_from_slab(&scurrent, rdclass, type, &srdata);
839 			if (dns_rdata_compare(&mrdata, &srdata) == 0) {
840 				break;
841 			}
842 		}
843 		if (count == scount) {
844 			/*
845 			 * This rdata isn't in the sslab, and thus isn't
846 			 * being subtracted.
847 			 */
848 			tlength += (unsigned int)(mcurrent - mrdatabegin);
849 			tcount++;
850 		} else {
851 			rcount++;
852 		}
853 		dns_rdata_reset(&mrdata);
854 	}
855 
856 #if DNS_RDATASET_FIXED
857 	tlength += (4 * tcount);
858 #endif /* if DNS_RDATASET_FIXED */
859 
860 	/*
861 	 * Check that all the records originally existed.  The numeric
862 	 * check only works as rdataslabs do not contain duplicates.
863 	 */
864 	if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount)) {
865 		return DNS_R_NOTEXACT;
866 	}
867 
868 	/*
869 	 * Don't continue if the new rdataslab would be empty.
870 	 */
871 	if (tcount == 0) {
872 		return DNS_R_NXRRSET;
873 	}
874 
875 	/*
876 	 * If nothing is going to change, we can stop.
877 	 */
878 	if (rcount == 0) {
879 		return DNS_R_UNCHANGED;
880 	}
881 
882 	/*
883 	 * Copy the reserved area from the mslab.
884 	 */
885 	tstart = isc_mem_get(mctx, tlength);
886 	memmove(tstart, mslab, reservelen);
887 	tcurrent = tstart + reservelen;
888 #if DNS_RDATASET_FIXED
889 	offsetbase = tcurrent;
890 
891 	offsettable = isc_mem_cget(mctx, mcount, sizeof(unsigned int));
892 #endif /* if DNS_RDATASET_FIXED */
893 
894 	/*
895 	 * Write the new count.
896 	 */
897 	*tcurrent++ = (tcount & 0xff00) >> 8;
898 	*tcurrent++ = (tcount & 0x00ff);
899 
900 #if DNS_RDATASET_FIXED
901 	tcurrent += (4 * tcount);
902 #endif /* if DNS_RDATASET_FIXED */
903 
904 	/*
905 	 * Copy the parts of mslab not in sslab.
906 	 */
907 	mcurrent = mslab + reservelen;
908 	mcount = get_uint16(mcurrent);
909 #if DNS_RDATASET_FIXED
910 	mcurrent += (4 * mcount);
911 #endif /* if DNS_RDATASET_FIXED */
912 	for (i = 0; i < mcount; i++) {
913 		unsigned char *mrdatabegin = mcurrent;
914 #if DNS_RDATASET_FIXED
915 		order = peek_uint16(&mcurrent[2]);
916 		INSIST(order < mcount);
917 #endif /* if DNS_RDATASET_FIXED */
918 		rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
919 		scurrent = sstart;
920 		for (count = 0; count < scount; count++) {
921 			dns_rdata_reset(&srdata);
922 			rdata_from_slab(&scurrent, rdclass, type, &srdata);
923 			if (dns_rdata_compare(&mrdata, &srdata) == 0) {
924 				break;
925 			}
926 		}
927 		if (count == scount) {
928 			/*
929 			 * This rdata isn't in the sslab, and thus should be
930 			 * copied to the tslab.
931 			 */
932 			unsigned int length;
933 			length = (unsigned int)(mcurrent - mrdatabegin);
934 #if DNS_RDATASET_FIXED
935 			offsettable[order] = tcurrent - offsetbase;
936 #endif /* if DNS_RDATASET_FIXED */
937 			memmove(tcurrent, mrdatabegin, length);
938 			tcurrent += length;
939 		}
940 		dns_rdata_reset(&mrdata);
941 	}
942 
943 #if DNS_RDATASET_FIXED
944 	fillin_offsets(offsetbase, offsettable, mcount);
945 
946 	isc_mem_cput(mctx, offsettable, mcount, sizeof(unsigned int));
947 #endif /* if DNS_RDATASET_FIXED */
948 
949 	INSIST(tcurrent == tstart + tlength);
950 
951 	*tslabp = tstart;
952 
953 	return ISC_R_SUCCESS;
954 }
955 
956 bool
957 dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
958 		    unsigned int reservelen) {
959 	unsigned char *current1 = NULL, *current2 = NULL;
960 	unsigned int count1, count2;
961 	unsigned int length1, length2;
962 
963 	current1 = slab1 + reservelen;
964 	count1 = get_uint16(current1);
965 
966 	current2 = slab2 + reservelen;
967 	count2 = get_uint16(current2);
968 
969 	if (count1 != count2) {
970 		return false;
971 	}
972 
973 #if DNS_RDATASET_FIXED
974 	current1 += (4 * count1);
975 	current2 += (4 * count2);
976 #endif /* if DNS_RDATASET_FIXED */
977 
978 	while (count1-- > 0) {
979 		length1 = get_uint16(current1);
980 		length2 = get_uint16(current2);
981 
982 #if DNS_RDATASET_FIXED
983 		current1 += 2;
984 		current2 += 2;
985 #endif /* if DNS_RDATASET_FIXED */
986 
987 		if (length1 != length2 ||
988 		    memcmp(current1, current2, length1) != 0)
989 		{
990 			return false;
991 		}
992 
993 		current1 += length1;
994 		current2 += length1;
995 	}
996 	return true;
997 }
998 
999 bool
1000 dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
1001 		     unsigned int reservelen, dns_rdataclass_t rdclass,
1002 		     dns_rdatatype_t type) {
1003 	unsigned char *current1 = NULL, *current2 = NULL;
1004 	unsigned int count1, count2;
1005 	dns_rdata_t rdata1 = DNS_RDATA_INIT;
1006 	dns_rdata_t rdata2 = DNS_RDATA_INIT;
1007 
1008 	current1 = slab1 + reservelen;
1009 	count1 = get_uint16(current1);
1010 
1011 	current2 = slab2 + reservelen;
1012 	count2 = get_uint16(current2);
1013 
1014 	if (count1 != count2) {
1015 		return false;
1016 	}
1017 
1018 #if DNS_RDATASET_FIXED
1019 	current1 += (4 * count1);
1020 	current2 += (4 * count2);
1021 #endif /* if DNS_RDATASET_FIXED */
1022 
1023 	while (count1-- > 0) {
1024 		rdata_from_slab(&current1, rdclass, type, &rdata1);
1025 		rdata_from_slab(&current2, rdclass, type, &rdata2);
1026 		if (dns_rdata_compare(&rdata1, &rdata2) != 0) {
1027 			return false;
1028 		}
1029 		dns_rdata_reset(&rdata1);
1030 		dns_rdata_reset(&rdata2);
1031 	}
1032 	return true;
1033 }
1034 
1035 dns_slabheader_t *
1036 dns_slabheader_fromrdataset(const dns_rdataset_t *rdataset) {
1037 	dns_slabheader_t *header = (dns_slabheader_t *)rdataset->slab.raw;
1038 	return header - 1;
1039 }
1040 
1041 void *
1042 dns_slabheader_raw(dns_slabheader_t *header) {
1043 	return header + 1;
1044 }
1045 
1046 void
1047 dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) {
1048 	unsigned int i;
1049 	bool fully_lower;
1050 
1051 	/*
1052 	 * We do not need to worry about label lengths as they are all
1053 	 * less than or equal to 63.
1054 	 */
1055 	memset(header->upper, 0, sizeof(header->upper));
1056 	fully_lower = true;
1057 	for (i = 0; i < name->length; i++) {
1058 		if (isupper(name->ndata[i])) {
1059 			header->upper[i / 8] |= 1 << (i % 8);
1060 			fully_lower = false;
1061 		}
1062 	}
1063 	DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_CASESET);
1064 	if (fully_lower) {
1065 		DNS_SLABHEADER_SETATTR(header,
1066 				       DNS_SLABHEADERATTR_CASEFULLYLOWER);
1067 	}
1068 }
1069 
1070 void
1071 dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
1072 	if (CASESET(src)) {
1073 		uint_least16_t attr = DNS_SLABHEADER_GETATTR(
1074 			src, (DNS_SLABHEADERATTR_CASESET |
1075 			      DNS_SLABHEADERATTR_CASEFULLYLOWER));
1076 		DNS_SLABHEADER_SETATTR(dest, attr);
1077 		memmove(dest->upper, src->upper, sizeof(src->upper));
1078 	}
1079 }
1080 
1081 void
1082 dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node) {
1083 	ISC_LINK_INIT(h, link);
1084 	h->heap_index = 0;
1085 	h->heap = NULL;
1086 	h->db = db;
1087 	h->node = node;
1088 
1089 	atomic_init(&h->attributes, 0);
1090 	atomic_init(&h->last_refresh_fail_ts, 0);
1091 
1092 	STATIC_ASSERT((sizeof(h->attributes) == 2),
1093 		      "The .attributes field of dns_slabheader_t needs to be "
1094 		      "16-bit int type exactly.");
1095 }
1096 
1097 dns_slabheader_t *
1098 dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) {
1099 	dns_slabheader_t *h = NULL;
1100 
1101 	h = isc_mem_get(db->mctx, sizeof(*h));
1102 	*h = (dns_slabheader_t){
1103 		.link = ISC_LINK_INITIALIZER,
1104 	};
1105 	dns_slabheader_reset(h, db, node);
1106 	return h;
1107 }
1108 
1109 void
1110 dns_slabheader_destroy(dns_slabheader_t **headerp) {
1111 	unsigned int size;
1112 	dns_slabheader_t *header = *headerp;
1113 
1114 	*headerp = NULL;
1115 
1116 	isc_mem_t *mctx = header->db->mctx;
1117 
1118 	dns_db_deletedata(header->db, header->node, header);
1119 
1120 	if (NONEXISTENT(header)) {
1121 		size = sizeof(*header);
1122 	} else {
1123 		size = dns_rdataslab_size((unsigned char *)header,
1124 					  sizeof(*header));
1125 	}
1126 
1127 	isc_mem_put(mctx, header, size);
1128 }
1129 
1130 void
1131 dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proof) {
1132 	if (dns_name_dynamic(&(*proof)->name)) {
1133 		dns_name_free(&(*proof)->name, mctx);
1134 	}
1135 	if ((*proof)->neg != NULL) {
1136 		isc_mem_put(mctx, (*proof)->neg,
1137 			    dns_rdataslab_size((*proof)->neg, 0));
1138 	}
1139 	if ((*proof)->negsig != NULL) {
1140 		isc_mem_put(mctx, (*proof)->negsig,
1141 			    dns_rdataslab_size((*proof)->negsig, 0));
1142 	}
1143 	isc_mem_put(mctx, *proof, sizeof(**proof));
1144 	*proof = NULL;
1145 }
1146 
1147 dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
1148 	.disassociate = rdataset_disassociate,
1149 	.first = rdataset_first,
1150 	.next = rdataset_next,
1151 	.current = rdataset_current,
1152 	.clone = rdataset_clone,
1153 	.count = rdataset_count,
1154 	.getnoqname = rdataset_getnoqname,
1155 	.getclosest = rdataset_getclosest,
1156 	.settrust = rdataset_settrust,
1157 	.expire = rdataset_expire,
1158 	.clearprefetch = rdataset_clearprefetch,
1159 	.setownercase = rdataset_setownercase,
1160 	.getownercase = rdataset_getownercase,
1161 };
1162 
1163 /* Fixed RRSet helper macros */
1164 
1165 #define DNS_RDATASET_LENGTH 2;
1166 
1167 #if DNS_RDATASET_FIXED
1168 #define DNS_RDATASET_ORDER 2
1169 #define DNS_RDATASET_COUNT (count * 4)
1170 #else /* !DNS_RDATASET_FIXED */
1171 #define DNS_RDATASET_ORDER 0
1172 #define DNS_RDATASET_COUNT 0
1173 #endif /* DNS_RDATASET_FIXED */
1174 
1175 static void
1176 rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
1177 	dns_db_t *db = rdataset->slab.db;
1178 	dns_dbnode_t *node = rdataset->slab.node;
1179 
1180 	dns__db_detachnode(db, &node DNS__DB_FLARG_PASS);
1181 }
1182 
1183 static isc_result_t
1184 rdataset_first(dns_rdataset_t *rdataset) {
1185 	unsigned char *raw = rdataset->slab.raw;
1186 	uint16_t count = peek_uint16(raw);
1187 	if (count == 0) {
1188 		rdataset->slab.iter_pos = NULL;
1189 		rdataset->slab.iter_count = 0;
1190 		return ISC_R_NOMORE;
1191 	}
1192 
1193 	if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
1194 		raw += DNS_RDATASET_COUNT;
1195 	}
1196 
1197 	/*
1198 	 * iter_count is the number of rdata beyond the cursor
1199 	 * position, so we decrement the total count by one before
1200 	 * storing it.
1201 	 *
1202 	 * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
1203 	 * first record.  If DNS_RDATASETATTR_LOADORDER is set 'raw' points
1204 	 * to the first entry in the offset table.
1205 	 */
1206 	rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH;
1207 	rdataset->slab.iter_count = count - 1;
1208 
1209 	return ISC_R_SUCCESS;
1210 }
1211 
1212 static isc_result_t
1213 rdataset_next(dns_rdataset_t *rdataset) {
1214 	uint16_t count = rdataset->slab.iter_count;
1215 	if (count == 0) {
1216 		rdataset->slab.iter_pos = NULL;
1217 		return ISC_R_NOMORE;
1218 	}
1219 	rdataset->slab.iter_count = count - 1;
1220 
1221 	/*
1222 	 * Skip forward one record (length + 4) or one offset (4).
1223 	 */
1224 	unsigned char *raw = rdataset->slab.iter_pos;
1225 #if DNS_RDATASET_FIXED
1226 	if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
1227 #endif /* DNS_RDATASET_FIXED */
1228 	{
1229 		uint16_t length = peek_uint16(raw);
1230 		raw += length;
1231 	}
1232 	rdataset->slab.iter_pos = raw + DNS_RDATASET_ORDER +
1233 				  DNS_RDATASET_LENGTH;
1234 
1235 	return ISC_R_SUCCESS;
1236 }
1237 
1238 static void
1239 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
1240 	unsigned char *raw = NULL;
1241 	unsigned int length;
1242 	isc_region_t r;
1243 	unsigned int flags = 0;
1244 
1245 	raw = rdataset->slab.iter_pos;
1246 	REQUIRE(raw != NULL);
1247 
1248 	/*
1249 	 * Find the start of the record if not already in iter_pos
1250 	 * then skip the length and order fields.
1251 	 */
1252 #if DNS_RDATASET_FIXED
1253 	if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
1254 		unsigned int offset;
1255 		offset = ((unsigned int)raw[0] << 24) +
1256 			 ((unsigned int)raw[1] << 16) +
1257 			 ((unsigned int)raw[2] << 8) + (unsigned int)raw[3];
1258 		raw = rdataset->slab.raw + offset;
1259 	}
1260 #endif /* if DNS_RDATASET_FIXED */
1261 
1262 	length = peek_uint16(raw);
1263 
1264 	raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH;
1265 
1266 	if (rdataset->type == dns_rdatatype_rrsig) {
1267 		if (*raw & DNS_RDATASLAB_OFFLINE) {
1268 			flags |= DNS_RDATA_OFFLINE;
1269 		}
1270 		length--;
1271 		raw++;
1272 	}
1273 	r.length = length;
1274 	r.base = raw;
1275 	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
1276 	rdata->flags |= flags;
1277 }
1278 
1279 static void
1280 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
1281 	dns_db_t *db = source->slab.db;
1282 	dns_dbnode_t *node = source->slab.node;
1283 	dns_dbnode_t *cloned_node = NULL;
1284 
1285 	dns__db_attachnode(db, node, &cloned_node DNS__DB_FLARG_PASS);
1286 	INSIST(!ISC_LINK_LINKED(target, link));
1287 	*target = *source;
1288 	ISC_LINK_INIT(target, link);
1289 
1290 	target->slab.iter_pos = NULL;
1291 	target->slab.iter_count = 0;
1292 }
1293 
1294 static unsigned int
1295 rdataset_count(dns_rdataset_t *rdataset) {
1296 	unsigned char *raw = NULL;
1297 	unsigned int count;
1298 
1299 	raw = rdataset->slab.raw;
1300 	count = get_uint16(raw);
1301 
1302 	return count;
1303 }
1304 
1305 static isc_result_t
1306 rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
1307 		    dns_rdataset_t *nsec,
1308 		    dns_rdataset_t *nsecsig DNS__DB_FLARG) {
1309 	dns_db_t *db = rdataset->slab.db;
1310 	dns_dbnode_t *node = rdataset->slab.node;
1311 	const dns_slabheader_proof_t *noqname = rdataset->slab.noqname;
1312 
1313 	/*
1314 	 * Usually, rdataset->slab.raw refers the data following a
1315 	 * dns_slabheader, but in this case it points to a bare
1316 	 * rdataslab belonging to the dns_slabheader's `noqname` field.
1317 	 * The DNS_RDATASETATTR_KEEPCASE attribute is set to prevent
1318 	 * setownercase and getownercase methods from affecting the
1319 	 * case of NSEC/NSEC3 owner names.
1320 	 */
1321 	dns__db_attachnode(db, node,
1322 			   &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1323 	*nsec = (dns_rdataset_t){
1324 		.methods = &dns_rdataslab_rdatasetmethods,
1325 		.rdclass = db->rdclass,
1326 		.type = noqname->type,
1327 		.ttl = rdataset->ttl,
1328 		.trust = rdataset->trust,
1329 		.slab.db = db,
1330 		.slab.node = node,
1331 		.slab.raw = noqname->neg,
1332 		.link = nsec->link,
1333 		.count = nsec->count,
1334 		.attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE,
1335 		.magic = nsec->magic,
1336 	};
1337 
1338 	dns__db_attachnode(db, node,
1339 			   &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1340 	*nsecsig = (dns_rdataset_t){
1341 		.methods = &dns_rdataslab_rdatasetmethods,
1342 		.rdclass = db->rdclass,
1343 		.type = dns_rdatatype_rrsig,
1344 		.covers = noqname->type,
1345 		.ttl = rdataset->ttl,
1346 		.trust = rdataset->trust,
1347 		.slab.db = db,
1348 		.slab.node = node,
1349 		.slab.raw = noqname->negsig,
1350 		.link = nsecsig->link,
1351 		.count = nsecsig->count,
1352 		.attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE,
1353 		.magic = nsecsig->magic,
1354 	};
1355 
1356 	dns_name_clone(&noqname->name, name);
1357 
1358 	return ISC_R_SUCCESS;
1359 }
1360 
1361 static isc_result_t
1362 rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
1363 		    dns_rdataset_t *nsec,
1364 		    dns_rdataset_t *nsecsig DNS__DB_FLARG) {
1365 	dns_db_t *db = rdataset->slab.db;
1366 	dns_dbnode_t *node = rdataset->slab.node;
1367 	const dns_slabheader_proof_t *closest = rdataset->slab.closest;
1368 
1369 	/*
1370 	 * As mentioned above, rdataset->slab.raw usually refers the data
1371 	 * following an dns_slabheader, but in this case it points to a bare
1372 	 * rdataslab belonging to the dns_slabheader's `closest` field.
1373 	 */
1374 	dns__db_attachnode(db, node,
1375 			   &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1376 	*nsec = (dns_rdataset_t){
1377 		.methods = &dns_rdataslab_rdatasetmethods,
1378 		.rdclass = db->rdclass,
1379 		.type = closest->type,
1380 		.ttl = rdataset->ttl,
1381 		.trust = rdataset->trust,
1382 		.slab.db = db,
1383 		.slab.node = node,
1384 		.slab.raw = closest->neg,
1385 		.link = nsec->link,
1386 		.count = nsec->count,
1387 		.attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE,
1388 		.magic = nsec->magic,
1389 	};
1390 
1391 	dns__db_attachnode(db, node,
1392 			   &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1393 	*nsecsig = (dns_rdataset_t){
1394 		.methods = &dns_rdataslab_rdatasetmethods,
1395 		.rdclass = db->rdclass,
1396 		.type = dns_rdatatype_rrsig,
1397 		.covers = closest->type,
1398 		.ttl = rdataset->ttl,
1399 		.trust = rdataset->trust,
1400 		.slab.db = db,
1401 		.slab.node = node,
1402 		.slab.raw = closest->negsig,
1403 		.link = nsecsig->link,
1404 		.count = nsecsig->count,
1405 		.attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE,
1406 		.magic = nsecsig->magic,
1407 	};
1408 
1409 	dns_name_clone(&closest->name, name);
1410 
1411 	return ISC_R_SUCCESS;
1412 }
1413 
1414 static void
1415 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
1416 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
1417 
1418 	dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
1419 	header->trust = rdataset->trust = trust;
1420 	dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
1421 }
1422 
1423 static void
1424 rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) {
1425 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
1426 
1427 	dns_db_expiredata(header->db, header->node, header);
1428 }
1429 
1430 static void
1431 rdataset_clearprefetch(dns_rdataset_t *rdataset) {
1432 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
1433 
1434 	dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
1435 	DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH);
1436 	dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
1437 }
1438 
1439 static void
1440 rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
1441 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
1442 
1443 	dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
1444 	dns_slabheader_setownercase(header, name);
1445 	dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
1446 }
1447 
1448 static void
1449 rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
1450 	dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
1451 	uint8_t mask = (1 << 7);
1452 	uint8_t bits = 0;
1453 
1454 	dns_db_locknode(header->db, header->node, isc_rwlocktype_read);
1455 
1456 	if (!CASESET(header)) {
1457 		goto unlock;
1458 	}
1459 
1460 	if (CASEFULLYLOWER(header)) {
1461 		isc_ascii_lowercopy(name->ndata, name->ndata, name->length);
1462 	} else {
1463 		uint8_t *nd = name->ndata;
1464 		for (size_t i = 0; i < name->length; i++) {
1465 			if (mask == (1 << 7)) {
1466 				bits = header->upper[i / 8];
1467 				mask = 1;
1468 			} else {
1469 				mask <<= 1;
1470 			}
1471 			nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i])
1472 					      : isc_ascii_tolower(nd[i]);
1473 		}
1474 	}
1475 
1476 unlock:
1477 	dns_db_unlocknode(header->db, header->node, isc_rwlocktype_read);
1478 }
1479