xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/ncache.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1*4afad4b7Schristos /*	$NetBSD: ncache.c,v 1.1 2024/02/18 20:57:32 christos Exp $	*/
2*4afad4b7Schristos 
3*4afad4b7Schristos /*
4*4afad4b7Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*4afad4b7Schristos  *
6*4afad4b7Schristos  * SPDX-License-Identifier: MPL-2.0
7*4afad4b7Schristos  *
8*4afad4b7Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9*4afad4b7Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
10*4afad4b7Schristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11*4afad4b7Schristos  *
12*4afad4b7Schristos  * See the COPYRIGHT file distributed with this work for additional
13*4afad4b7Schristos  * information regarding copyright ownership.
14*4afad4b7Schristos  */
15*4afad4b7Schristos 
16*4afad4b7Schristos /*! \file */
17*4afad4b7Schristos 
18*4afad4b7Schristos #include <inttypes.h>
19*4afad4b7Schristos #include <stdbool.h>
20*4afad4b7Schristos 
21*4afad4b7Schristos #include <isc/buffer.h>
22*4afad4b7Schristos #include <isc/util.h>
23*4afad4b7Schristos 
24*4afad4b7Schristos #include <dns/db.h>
25*4afad4b7Schristos #include <dns/message.h>
26*4afad4b7Schristos #include <dns/ncache.h>
27*4afad4b7Schristos #include <dns/rdata.h>
28*4afad4b7Schristos #include <dns/rdatalist.h>
29*4afad4b7Schristos #include <dns/rdataset.h>
30*4afad4b7Schristos #include <dns/rdatastruct.h>
31*4afad4b7Schristos 
32*4afad4b7Schristos #define DNS_NCACHE_RDATA 100U
33*4afad4b7Schristos 
34*4afad4b7Schristos /*
35*4afad4b7Schristos  * The format of an ncache rdata is a sequence of zero or more records of
36*4afad4b7Schristos  * the following format:
37*4afad4b7Schristos  *
38*4afad4b7Schristos  *	owner name
39*4afad4b7Schristos  *	type
40*4afad4b7Schristos  *	trust
41*4afad4b7Schristos  *	rdata count
42*4afad4b7Schristos  *		rdata length			These two occur 'rdata count'
43*4afad4b7Schristos  *		rdata				times.
44*4afad4b7Schristos  *
45*4afad4b7Schristos  */
46*4afad4b7Schristos 
47*4afad4b7Schristos static isc_result_t
48*4afad4b7Schristos addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
49*4afad4b7Schristos 	  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
50*4afad4b7Schristos 	  dns_ttl_t maxttl, bool optout, bool secure,
51*4afad4b7Schristos 	  dns_rdataset_t *addedrdataset);
52*4afad4b7Schristos 
53*4afad4b7Schristos static isc_result_t
copy_rdataset(dns_rdataset_t * rdataset,isc_buffer_t * buffer)54*4afad4b7Schristos copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
55*4afad4b7Schristos 	isc_result_t result;
56*4afad4b7Schristos 	unsigned int count;
57*4afad4b7Schristos 	isc_region_t ar, r;
58*4afad4b7Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
59*4afad4b7Schristos 
60*4afad4b7Schristos 	/*
61*4afad4b7Schristos 	 * Copy the rdataset count to the buffer.
62*4afad4b7Schristos 	 */
63*4afad4b7Schristos 	isc_buffer_availableregion(buffer, &ar);
64*4afad4b7Schristos 	if (ar.length < 2) {
65*4afad4b7Schristos 		return (ISC_R_NOSPACE);
66*4afad4b7Schristos 	}
67*4afad4b7Schristos 	count = dns_rdataset_count(rdataset);
68*4afad4b7Schristos 	INSIST(count <= 65535);
69*4afad4b7Schristos 	isc_buffer_putuint16(buffer, (uint16_t)count);
70*4afad4b7Schristos 
71*4afad4b7Schristos 	result = dns_rdataset_first(rdataset);
72*4afad4b7Schristos 	while (result == ISC_R_SUCCESS) {
73*4afad4b7Schristos 		dns_rdataset_current(rdataset, &rdata);
74*4afad4b7Schristos 		dns_rdata_toregion(&rdata, &r);
75*4afad4b7Schristos 		INSIST(r.length <= 65535);
76*4afad4b7Schristos 		isc_buffer_availableregion(buffer, &ar);
77*4afad4b7Schristos 		if (ar.length < 2) {
78*4afad4b7Schristos 			return (ISC_R_NOSPACE);
79*4afad4b7Schristos 		}
80*4afad4b7Schristos 		/*
81*4afad4b7Schristos 		 * Copy the rdata length to the buffer.
82*4afad4b7Schristos 		 */
83*4afad4b7Schristos 		isc_buffer_putuint16(buffer, (uint16_t)r.length);
84*4afad4b7Schristos 		/*
85*4afad4b7Schristos 		 * Copy the rdata to the buffer.
86*4afad4b7Schristos 		 */
87*4afad4b7Schristos 		result = isc_buffer_copyregion(buffer, &r);
88*4afad4b7Schristos 		if (result != ISC_R_SUCCESS) {
89*4afad4b7Schristos 			return (result);
90*4afad4b7Schristos 		}
91*4afad4b7Schristos 		dns_rdata_reset(&rdata);
92*4afad4b7Schristos 		result = dns_rdataset_next(rdataset);
93*4afad4b7Schristos 	}
94*4afad4b7Schristos 	if (result != ISC_R_NOMORE) {
95*4afad4b7Schristos 		return (result);
96*4afad4b7Schristos 	}
97*4afad4b7Schristos 
98*4afad4b7Schristos 	return (ISC_R_SUCCESS);
99*4afad4b7Schristos }
100*4afad4b7Schristos 
101*4afad4b7Schristos isc_result_t
dns_ncache_add(dns_message_t * message,dns_db_t * cache,dns_dbnode_t * node,dns_rdatatype_t covers,isc_stdtime_t now,dns_ttl_t minttl,dns_ttl_t maxttl,dns_rdataset_t * addedrdataset)102*4afad4b7Schristos dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
103*4afad4b7Schristos 	       dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
104*4afad4b7Schristos 	       dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) {
105*4afad4b7Schristos 	return (addoptout(message, cache, node, covers, now, minttl, maxttl,
106*4afad4b7Schristos 			  false, false, addedrdataset));
107*4afad4b7Schristos }
108*4afad4b7Schristos 
109*4afad4b7Schristos isc_result_t
dns_ncache_addoptout(dns_message_t * message,dns_db_t * cache,dns_dbnode_t * node,dns_rdatatype_t covers,isc_stdtime_t now,dns_ttl_t minttl,dns_ttl_t maxttl,bool optout,dns_rdataset_t * addedrdataset)110*4afad4b7Schristos dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
111*4afad4b7Schristos 		     dns_dbnode_t *node, dns_rdatatype_t covers,
112*4afad4b7Schristos 		     isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
113*4afad4b7Schristos 		     bool optout, dns_rdataset_t *addedrdataset) {
114*4afad4b7Schristos 	return (addoptout(message, cache, node, covers, now, minttl, maxttl,
115*4afad4b7Schristos 			  optout, true, addedrdataset));
116*4afad4b7Schristos }
117*4afad4b7Schristos 
118*4afad4b7Schristos static isc_result_t
addoptout(dns_message_t * message,dns_db_t * cache,dns_dbnode_t * node,dns_rdatatype_t covers,isc_stdtime_t now,dns_ttl_t minttl,dns_ttl_t maxttl,bool optout,bool secure,dns_rdataset_t * addedrdataset)119*4afad4b7Schristos addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
120*4afad4b7Schristos 	  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
121*4afad4b7Schristos 	  dns_ttl_t maxttl, bool optout, bool secure,
122*4afad4b7Schristos 	  dns_rdataset_t *addedrdataset) {
123*4afad4b7Schristos 	isc_result_t result;
124*4afad4b7Schristos 	isc_buffer_t buffer;
125*4afad4b7Schristos 	isc_region_t r;
126*4afad4b7Schristos 	dns_rdataset_t *rdataset;
127*4afad4b7Schristos 	dns_rdatatype_t type;
128*4afad4b7Schristos 	dns_name_t *name;
129*4afad4b7Schristos 	dns_ttl_t ttl;
130*4afad4b7Schristos 	dns_trust_t trust;
131*4afad4b7Schristos 	dns_rdata_t rdata[DNS_NCACHE_RDATA];
132*4afad4b7Schristos 	dns_rdataset_t ncrdataset;
133*4afad4b7Schristos 	dns_rdatalist_t ncrdatalist;
134*4afad4b7Schristos 	unsigned char data[65536];
135*4afad4b7Schristos 	unsigned int next = 0;
136*4afad4b7Schristos 
137*4afad4b7Schristos 	/*
138*4afad4b7Schristos 	 * Convert the authority data from 'message' into a negative cache
139*4afad4b7Schristos 	 * rdataset, and store it in 'cache' at 'node'.
140*4afad4b7Schristos 	 */
141*4afad4b7Schristos 
142*4afad4b7Schristos 	REQUIRE(message != NULL);
143*4afad4b7Schristos 
144*4afad4b7Schristos 	/*
145*4afad4b7Schristos 	 * We assume that all data in the authority section has been
146*4afad4b7Schristos 	 * validated by the caller.
147*4afad4b7Schristos 	 */
148*4afad4b7Schristos 
149*4afad4b7Schristos 	/*
150*4afad4b7Schristos 	 * Initialize the list.
151*4afad4b7Schristos 	 */
152*4afad4b7Schristos 	dns_rdatalist_init(&ncrdatalist);
153*4afad4b7Schristos 	ncrdatalist.rdclass = dns_db_class(cache);
154*4afad4b7Schristos 	ncrdatalist.covers = covers;
155*4afad4b7Schristos 	ncrdatalist.ttl = maxttl;
156*4afad4b7Schristos 
157*4afad4b7Schristos 	/*
158*4afad4b7Schristos 	 * Build an ncache rdatas into buffer.
159*4afad4b7Schristos 	 */
160*4afad4b7Schristos 	ttl = maxttl;
161*4afad4b7Schristos 	trust = 0xffff;
162*4afad4b7Schristos 	isc_buffer_init(&buffer, data, sizeof(data));
163*4afad4b7Schristos 	if (message->counts[DNS_SECTION_AUTHORITY]) {
164*4afad4b7Schristos 		result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
165*4afad4b7Schristos 	} else {
166*4afad4b7Schristos 		result = ISC_R_NOMORE;
167*4afad4b7Schristos 	}
168*4afad4b7Schristos 	while (result == ISC_R_SUCCESS) {
169*4afad4b7Schristos 		name = NULL;
170*4afad4b7Schristos 		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
171*4afad4b7Schristos 		if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
172*4afad4b7Schristos 			for (rdataset = ISC_LIST_HEAD(name->list);
173*4afad4b7Schristos 			     rdataset != NULL;
174*4afad4b7Schristos 			     rdataset = ISC_LIST_NEXT(rdataset, link))
175*4afad4b7Schristos 			{
176*4afad4b7Schristos 				if ((rdataset->attributes &
177*4afad4b7Schristos 				     DNS_RDATASETATTR_NCACHE) == 0)
178*4afad4b7Schristos 				{
179*4afad4b7Schristos 					continue;
180*4afad4b7Schristos 				}
181*4afad4b7Schristos 				type = rdataset->type;
182*4afad4b7Schristos 				if (type == dns_rdatatype_rrsig) {
183*4afad4b7Schristos 					type = rdataset->covers;
184*4afad4b7Schristos 				}
185*4afad4b7Schristos 				if (type == dns_rdatatype_soa ||
186*4afad4b7Schristos 				    type == dns_rdatatype_nsec ||
187*4afad4b7Schristos 				    type == dns_rdatatype_nsec3)
188*4afad4b7Schristos 				{
189*4afad4b7Schristos 					if (ttl > rdataset->ttl) {
190*4afad4b7Schristos 						ttl = rdataset->ttl;
191*4afad4b7Schristos 					}
192*4afad4b7Schristos 					if (ttl < minttl) {
193*4afad4b7Schristos 						ttl = minttl;
194*4afad4b7Schristos 					}
195*4afad4b7Schristos 					if (trust > rdataset->trust) {
196*4afad4b7Schristos 						trust = rdataset->trust;
197*4afad4b7Schristos 					}
198*4afad4b7Schristos 					/*
199*4afad4b7Schristos 					 * Copy the owner name to the buffer.
200*4afad4b7Schristos 					 */
201*4afad4b7Schristos 					dns_name_toregion(name, &r);
202*4afad4b7Schristos 					result = isc_buffer_copyregion(&buffer,
203*4afad4b7Schristos 								       &r);
204*4afad4b7Schristos 					if (result != ISC_R_SUCCESS) {
205*4afad4b7Schristos 						return (result);
206*4afad4b7Schristos 					}
207*4afad4b7Schristos 					/*
208*4afad4b7Schristos 					 * Copy the type to the buffer.
209*4afad4b7Schristos 					 */
210*4afad4b7Schristos 					isc_buffer_availableregion(&buffer, &r);
211*4afad4b7Schristos 					if (r.length < 3) {
212*4afad4b7Schristos 						return (ISC_R_NOSPACE);
213*4afad4b7Schristos 					}
214*4afad4b7Schristos 					isc_buffer_putuint16(&buffer,
215*4afad4b7Schristos 							     rdataset->type);
216*4afad4b7Schristos 					isc_buffer_putuint8(
217*4afad4b7Schristos 						&buffer,
218*4afad4b7Schristos 						(unsigned char)rdataset->trust);
219*4afad4b7Schristos 					/*
220*4afad4b7Schristos 					 * Copy the rdataset into the buffer.
221*4afad4b7Schristos 					 */
222*4afad4b7Schristos 					result = copy_rdataset(rdataset,
223*4afad4b7Schristos 							       &buffer);
224*4afad4b7Schristos 					if (result != ISC_R_SUCCESS) {
225*4afad4b7Schristos 						return (result);
226*4afad4b7Schristos 					}
227*4afad4b7Schristos 
228*4afad4b7Schristos 					if (next >= DNS_NCACHE_RDATA) {
229*4afad4b7Schristos 						return (ISC_R_NOSPACE);
230*4afad4b7Schristos 					}
231*4afad4b7Schristos 					dns_rdata_init(&rdata[next]);
232*4afad4b7Schristos 					isc_buffer_remainingregion(&buffer, &r);
233*4afad4b7Schristos 					rdata[next].data = r.base;
234*4afad4b7Schristos 					rdata[next].length = r.length;
235*4afad4b7Schristos 					rdata[next].rdclass =
236*4afad4b7Schristos 						ncrdatalist.rdclass;
237*4afad4b7Schristos 					rdata[next].type = 0;
238*4afad4b7Schristos 					rdata[next].flags = 0;
239*4afad4b7Schristos 					ISC_LIST_APPEND(ncrdatalist.rdata,
240*4afad4b7Schristos 							&rdata[next], link);
241*4afad4b7Schristos 					isc_buffer_forward(&buffer, r.length);
242*4afad4b7Schristos 					next++;
243*4afad4b7Schristos 				}
244*4afad4b7Schristos 			}
245*4afad4b7Schristos 		}
246*4afad4b7Schristos 		result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
247*4afad4b7Schristos 	}
248*4afad4b7Schristos 	if (result != ISC_R_NOMORE) {
249*4afad4b7Schristos 		return (result);
250*4afad4b7Schristos 	}
251*4afad4b7Schristos 
252*4afad4b7Schristos 	if (trust == 0xffff) {
253*4afad4b7Schristos 		if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
254*4afad4b7Schristos 		    message->counts[DNS_SECTION_ANSWER] == 0)
255*4afad4b7Schristos 		{
256*4afad4b7Schristos 			/*
257*4afad4b7Schristos 			 * The response has aa set and we haven't followed
258*4afad4b7Schristos 			 * any CNAME or DNAME chains.
259*4afad4b7Schristos 			 */
260*4afad4b7Schristos 			trust = dns_trust_authauthority;
261*4afad4b7Schristos 		} else {
262*4afad4b7Schristos 			trust = dns_trust_additional;
263*4afad4b7Schristos 		}
264*4afad4b7Schristos 		ttl = 0;
265*4afad4b7Schristos 	}
266*4afad4b7Schristos 
267*4afad4b7Schristos 	INSIST(trust != 0xffff);
268*4afad4b7Schristos 
269*4afad4b7Schristos 	ncrdatalist.ttl = ttl;
270*4afad4b7Schristos 
271*4afad4b7Schristos 	dns_rdataset_init(&ncrdataset);
272*4afad4b7Schristos 	RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) ==
273*4afad4b7Schristos 		      ISC_R_SUCCESS);
274*4afad4b7Schristos 	if (!secure && trust > dns_trust_answer) {
275*4afad4b7Schristos 		trust = dns_trust_answer;
276*4afad4b7Schristos 	}
277*4afad4b7Schristos 	ncrdataset.trust = trust;
278*4afad4b7Schristos 	ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE;
279*4afad4b7Schristos 	if (message->rcode == dns_rcode_nxdomain) {
280*4afad4b7Schristos 		ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
281*4afad4b7Schristos 	}
282*4afad4b7Schristos 	if (optout) {
283*4afad4b7Schristos 		ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
284*4afad4b7Schristos 	}
285*4afad4b7Schristos 
286*4afad4b7Schristos 	return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0,
287*4afad4b7Schristos 				   addedrdataset));
288*4afad4b7Schristos }
289*4afad4b7Schristos 
290*4afad4b7Schristos isc_result_t
dns_ncache_towire(dns_rdataset_t * rdataset,dns_compress_t * cctx,isc_buffer_t * target,unsigned int options,unsigned int * countp)291*4afad4b7Schristos dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
292*4afad4b7Schristos 		  isc_buffer_t *target, unsigned int options,
293*4afad4b7Schristos 		  unsigned int *countp) {
294*4afad4b7Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
295*4afad4b7Schristos 	isc_result_t result;
296*4afad4b7Schristos 	isc_region_t remaining, tavailable;
297*4afad4b7Schristos 	isc_buffer_t source, savedbuffer, rdlen;
298*4afad4b7Schristos 	dns_name_t name;
299*4afad4b7Schristos 	dns_rdatatype_t type;
300*4afad4b7Schristos 	unsigned int i, rcount, count;
301*4afad4b7Schristos 
302*4afad4b7Schristos 	/*
303*4afad4b7Schristos 	 * Convert the negative caching rdataset 'rdataset' to wire format,
304*4afad4b7Schristos 	 * compressing names as specified in 'cctx', and storing the result in
305*4afad4b7Schristos 	 * 'target'.
306*4afad4b7Schristos 	 */
307*4afad4b7Schristos 
308*4afad4b7Schristos 	REQUIRE(rdataset != NULL);
309*4afad4b7Schristos 	REQUIRE(rdataset->type == 0);
310*4afad4b7Schristos 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
311*4afad4b7Schristos 
312*4afad4b7Schristos 	savedbuffer = *target;
313*4afad4b7Schristos 	count = 0;
314*4afad4b7Schristos 
315*4afad4b7Schristos 	result = dns_rdataset_first(rdataset);
316*4afad4b7Schristos 	while (result == ISC_R_SUCCESS) {
317*4afad4b7Schristos 		dns_rdataset_current(rdataset, &rdata);
318*4afad4b7Schristos 		isc_buffer_init(&source, rdata.data, rdata.length);
319*4afad4b7Schristos 		isc_buffer_add(&source, rdata.length);
320*4afad4b7Schristos 		dns_name_init(&name, NULL);
321*4afad4b7Schristos 		isc_buffer_remainingregion(&source, &remaining);
322*4afad4b7Schristos 		dns_name_fromregion(&name, &remaining);
323*4afad4b7Schristos 		INSIST(remaining.length >= name.length);
324*4afad4b7Schristos 		isc_buffer_forward(&source, name.length);
325*4afad4b7Schristos 		remaining.length -= name.length;
326*4afad4b7Schristos 
327*4afad4b7Schristos 		INSIST(remaining.length >= 5);
328*4afad4b7Schristos 		type = isc_buffer_getuint16(&source);
329*4afad4b7Schristos 		isc_buffer_forward(&source, 1);
330*4afad4b7Schristos 		rcount = isc_buffer_getuint16(&source);
331*4afad4b7Schristos 
332*4afad4b7Schristos 		for (i = 0; i < rcount; i++) {
333*4afad4b7Schristos 			/*
334*4afad4b7Schristos 			 * Get the length of this rdata and set up an
335*4afad4b7Schristos 			 * rdata structure for it.
336*4afad4b7Schristos 			 */
337*4afad4b7Schristos 			isc_buffer_remainingregion(&source, &remaining);
338*4afad4b7Schristos 			INSIST(remaining.length >= 2);
339*4afad4b7Schristos 			dns_rdata_reset(&rdata);
340*4afad4b7Schristos 			rdata.length = isc_buffer_getuint16(&source);
341*4afad4b7Schristos 			isc_buffer_remainingregion(&source, &remaining);
342*4afad4b7Schristos 			rdata.data = remaining.base;
343*4afad4b7Schristos 			rdata.type = type;
344*4afad4b7Schristos 			rdata.rdclass = rdataset->rdclass;
345*4afad4b7Schristos 			INSIST(remaining.length >= rdata.length);
346*4afad4b7Schristos 			isc_buffer_forward(&source, rdata.length);
347*4afad4b7Schristos 
348*4afad4b7Schristos 			if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
349*4afad4b7Schristos 			    dns_rdatatype_isdnssec(type))
350*4afad4b7Schristos 			{
351*4afad4b7Schristos 				continue;
352*4afad4b7Schristos 			}
353*4afad4b7Schristos 
354*4afad4b7Schristos 			/*
355*4afad4b7Schristos 			 * Write the name.
356*4afad4b7Schristos 			 */
357*4afad4b7Schristos 			dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
358*4afad4b7Schristos 			result = dns_name_towire(&name, cctx, target);
359*4afad4b7Schristos 			if (result != ISC_R_SUCCESS) {
360*4afad4b7Schristos 				goto rollback;
361*4afad4b7Schristos 			}
362*4afad4b7Schristos 
363*4afad4b7Schristos 			/*
364*4afad4b7Schristos 			 * See if we have space for type, class, ttl, and
365*4afad4b7Schristos 			 * rdata length.  Write the type, class, and ttl.
366*4afad4b7Schristos 			 */
367*4afad4b7Schristos 			isc_buffer_availableregion(target, &tavailable);
368*4afad4b7Schristos 			if (tavailable.length < 10) {
369*4afad4b7Schristos 				result = ISC_R_NOSPACE;
370*4afad4b7Schristos 				goto rollback;
371*4afad4b7Schristos 			}
372*4afad4b7Schristos 			isc_buffer_putuint16(target, type);
373*4afad4b7Schristos 			isc_buffer_putuint16(target, rdataset->rdclass);
374*4afad4b7Schristos 			isc_buffer_putuint32(target, rdataset->ttl);
375*4afad4b7Schristos 
376*4afad4b7Schristos 			/*
377*4afad4b7Schristos 			 * Save space for rdata length.
378*4afad4b7Schristos 			 */
379*4afad4b7Schristos 			rdlen = *target;
380*4afad4b7Schristos 			isc_buffer_add(target, 2);
381*4afad4b7Schristos 
382*4afad4b7Schristos 			/*
383*4afad4b7Schristos 			 * Write the rdata.
384*4afad4b7Schristos 			 */
385*4afad4b7Schristos 			result = dns_rdata_towire(&rdata, cctx, target);
386*4afad4b7Schristos 			if (result != ISC_R_SUCCESS) {
387*4afad4b7Schristos 				goto rollback;
388*4afad4b7Schristos 			}
389*4afad4b7Schristos 
390*4afad4b7Schristos 			/*
391*4afad4b7Schristos 			 * Set the rdata length field to the compressed
392*4afad4b7Schristos 			 * length.
393*4afad4b7Schristos 			 */
394*4afad4b7Schristos 			INSIST((target->used >= rdlen.used + 2) &&
395*4afad4b7Schristos 			       (target->used - rdlen.used - 2 < 65536));
396*4afad4b7Schristos 			isc_buffer_putuint16(
397*4afad4b7Schristos 				&rdlen,
398*4afad4b7Schristos 				(uint16_t)(target->used - rdlen.used - 2));
399*4afad4b7Schristos 
400*4afad4b7Schristos 			count++;
401*4afad4b7Schristos 		}
402*4afad4b7Schristos 		INSIST(isc_buffer_remaininglength(&source) == 0);
403*4afad4b7Schristos 		result = dns_rdataset_next(rdataset);
404*4afad4b7Schristos 		dns_rdata_reset(&rdata);
405*4afad4b7Schristos 	}
406*4afad4b7Schristos 	if (result != ISC_R_NOMORE) {
407*4afad4b7Schristos 		goto rollback;
408*4afad4b7Schristos 	}
409*4afad4b7Schristos 
410*4afad4b7Schristos 	*countp = count;
411*4afad4b7Schristos 
412*4afad4b7Schristos 	return (ISC_R_SUCCESS);
413*4afad4b7Schristos 
414*4afad4b7Schristos rollback:
415*4afad4b7Schristos 	INSIST(savedbuffer.used < 65536);
416*4afad4b7Schristos 	dns_compress_rollback(cctx, (uint16_t)savedbuffer.used);
417*4afad4b7Schristos 	*countp = 0;
418*4afad4b7Schristos 	*target = savedbuffer;
419*4afad4b7Schristos 
420*4afad4b7Schristos 	return (result);
421*4afad4b7Schristos }
422*4afad4b7Schristos 
423*4afad4b7Schristos static void
rdataset_disassociate(dns_rdataset_t * rdataset)424*4afad4b7Schristos rdataset_disassociate(dns_rdataset_t *rdataset) {
425*4afad4b7Schristos 	UNUSED(rdataset);
426*4afad4b7Schristos }
427*4afad4b7Schristos 
428*4afad4b7Schristos static isc_result_t
rdataset_first(dns_rdataset_t * rdataset)429*4afad4b7Schristos rdataset_first(dns_rdataset_t *rdataset) {
430*4afad4b7Schristos 	unsigned char *raw = rdataset->private3;
431*4afad4b7Schristos 	unsigned int count;
432*4afad4b7Schristos 
433*4afad4b7Schristos 	count = raw[0] * 256 + raw[1];
434*4afad4b7Schristos 	if (count == 0) {
435*4afad4b7Schristos 		rdataset->private5 = NULL;
436*4afad4b7Schristos 		return (ISC_R_NOMORE);
437*4afad4b7Schristos 	}
438*4afad4b7Schristos 	raw += 2;
439*4afad4b7Schristos 	/*
440*4afad4b7Schristos 	 * The privateuint4 field is the number of rdata beyond the cursor
441*4afad4b7Schristos 	 * position, so we decrement the total count by one before storing
442*4afad4b7Schristos 	 * it.
443*4afad4b7Schristos 	 */
444*4afad4b7Schristos 	count--;
445*4afad4b7Schristos 	rdataset->privateuint4 = count;
446*4afad4b7Schristos 	rdataset->private5 = raw;
447*4afad4b7Schristos 
448*4afad4b7Schristos 	return (ISC_R_SUCCESS);
449*4afad4b7Schristos }
450*4afad4b7Schristos 
451*4afad4b7Schristos static isc_result_t
rdataset_next(dns_rdataset_t * rdataset)452*4afad4b7Schristos rdataset_next(dns_rdataset_t *rdataset) {
453*4afad4b7Schristos 	unsigned int count;
454*4afad4b7Schristos 	unsigned int length;
455*4afad4b7Schristos 	unsigned char *raw;
456*4afad4b7Schristos 
457*4afad4b7Schristos 	count = rdataset->privateuint4;
458*4afad4b7Schristos 	if (count == 0) {
459*4afad4b7Schristos 		return (ISC_R_NOMORE);
460*4afad4b7Schristos 	}
461*4afad4b7Schristos 	count--;
462*4afad4b7Schristos 	rdataset->privateuint4 = count;
463*4afad4b7Schristos 	raw = rdataset->private5;
464*4afad4b7Schristos 	length = raw[0] * 256 + raw[1];
465*4afad4b7Schristos 	raw += length + 2;
466*4afad4b7Schristos 	rdataset->private5 = raw;
467*4afad4b7Schristos 
468*4afad4b7Schristos 	return (ISC_R_SUCCESS);
469*4afad4b7Schristos }
470*4afad4b7Schristos 
471*4afad4b7Schristos static void
rdataset_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)472*4afad4b7Schristos rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
473*4afad4b7Schristos 	unsigned char *raw = rdataset->private5;
474*4afad4b7Schristos 	isc_region_t r;
475*4afad4b7Schristos 
476*4afad4b7Schristos 	REQUIRE(raw != NULL);
477*4afad4b7Schristos 
478*4afad4b7Schristos 	r.length = raw[0] * 256 + raw[1];
479*4afad4b7Schristos 	raw += 2;
480*4afad4b7Schristos 	r.base = raw;
481*4afad4b7Schristos 	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
482*4afad4b7Schristos }
483*4afad4b7Schristos 
484*4afad4b7Schristos static void
rdataset_clone(dns_rdataset_t * source,dns_rdataset_t * target)485*4afad4b7Schristos rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
486*4afad4b7Schristos 	*target = *source;
487*4afad4b7Schristos 
488*4afad4b7Schristos 	/*
489*4afad4b7Schristos 	 * Reset iterator state.
490*4afad4b7Schristos 	 */
491*4afad4b7Schristos 	target->privateuint4 = 0;
492*4afad4b7Schristos 	target->private5 = NULL;
493*4afad4b7Schristos }
494*4afad4b7Schristos 
495*4afad4b7Schristos static unsigned int
rdataset_count(dns_rdataset_t * rdataset)496*4afad4b7Schristos rdataset_count(dns_rdataset_t *rdataset) {
497*4afad4b7Schristos 	unsigned char *raw = rdataset->private3;
498*4afad4b7Schristos 	unsigned int count;
499*4afad4b7Schristos 
500*4afad4b7Schristos 	count = raw[0] * 256 + raw[1];
501*4afad4b7Schristos 
502*4afad4b7Schristos 	return (count);
503*4afad4b7Schristos }
504*4afad4b7Schristos 
505*4afad4b7Schristos static void
rdataset_settrust(dns_rdataset_t * rdataset,dns_trust_t trust)506*4afad4b7Schristos rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
507*4afad4b7Schristos 	unsigned char *raw = rdataset->private3;
508*4afad4b7Schristos 
509*4afad4b7Schristos 	raw[-1] = (unsigned char)trust;
510*4afad4b7Schristos 	rdataset->trust = trust;
511*4afad4b7Schristos }
512*4afad4b7Schristos 
513*4afad4b7Schristos static dns_rdatasetmethods_t rdataset_methods = {
514*4afad4b7Schristos 	rdataset_disassociate,
515*4afad4b7Schristos 	rdataset_first,
516*4afad4b7Schristos 	rdataset_next,
517*4afad4b7Schristos 	rdataset_current,
518*4afad4b7Schristos 	rdataset_clone,
519*4afad4b7Schristos 	rdataset_count,
520*4afad4b7Schristos 	NULL,		   /* addnoqname */
521*4afad4b7Schristos 	NULL,		   /* getnoqname */
522*4afad4b7Schristos 	NULL,		   /* addclosest */
523*4afad4b7Schristos 	NULL,		   /* getclosest */
524*4afad4b7Schristos 	rdataset_settrust, /* settrust */
525*4afad4b7Schristos 	NULL,		   /* expire */
526*4afad4b7Schristos 	NULL,		   /* clearprefetch */
527*4afad4b7Schristos 	NULL,		   /* setownercase */
528*4afad4b7Schristos 	NULL,		   /* getownercase */
529*4afad4b7Schristos 	NULL		   /* addglue */
530*4afad4b7Schristos };
531*4afad4b7Schristos 
532*4afad4b7Schristos isc_result_t
dns_ncache_getrdataset(dns_rdataset_t * ncacherdataset,dns_name_t * name,dns_rdatatype_t type,dns_rdataset_t * rdataset)533*4afad4b7Schristos dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
534*4afad4b7Schristos 		       dns_rdatatype_t type, dns_rdataset_t *rdataset) {
535*4afad4b7Schristos 	isc_result_t result;
536*4afad4b7Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
537*4afad4b7Schristos 	isc_region_t remaining;
538*4afad4b7Schristos 	isc_buffer_t source;
539*4afad4b7Schristos 	dns_name_t tname;
540*4afad4b7Schristos 	dns_rdatatype_t ttype;
541*4afad4b7Schristos 	dns_trust_t trust = dns_trust_none;
542*4afad4b7Schristos 	dns_rdataset_t rclone;
543*4afad4b7Schristos 
544*4afad4b7Schristos 	REQUIRE(ncacherdataset != NULL);
545*4afad4b7Schristos 	REQUIRE(ncacherdataset->type == 0);
546*4afad4b7Schristos 	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
547*4afad4b7Schristos 	REQUIRE(name != NULL);
548*4afad4b7Schristos 	REQUIRE(!dns_rdataset_isassociated(rdataset));
549*4afad4b7Schristos 	REQUIRE(type != dns_rdatatype_rrsig);
550*4afad4b7Schristos 
551*4afad4b7Schristos 	dns_rdataset_init(&rclone);
552*4afad4b7Schristos 	dns_rdataset_clone(ncacherdataset, &rclone);
553*4afad4b7Schristos 	result = dns_rdataset_first(&rclone);
554*4afad4b7Schristos 	while (result == ISC_R_SUCCESS) {
555*4afad4b7Schristos 		dns_rdataset_current(&rclone, &rdata);
556*4afad4b7Schristos 		isc_buffer_init(&source, rdata.data, rdata.length);
557*4afad4b7Schristos 		isc_buffer_add(&source, rdata.length);
558*4afad4b7Schristos 		dns_name_init(&tname, NULL);
559*4afad4b7Schristos 		isc_buffer_remainingregion(&source, &remaining);
560*4afad4b7Schristos 		dns_name_fromregion(&tname, &remaining);
561*4afad4b7Schristos 		INSIST(remaining.length >= tname.length);
562*4afad4b7Schristos 		isc_buffer_forward(&source, tname.length);
563*4afad4b7Schristos 		remaining.length -= tname.length;
564*4afad4b7Schristos 
565*4afad4b7Schristos 		INSIST(remaining.length >= 3);
566*4afad4b7Schristos 		ttype = isc_buffer_getuint16(&source);
567*4afad4b7Schristos 
568*4afad4b7Schristos 		if (ttype == type && dns_name_equal(&tname, name)) {
569*4afad4b7Schristos 			trust = isc_buffer_getuint8(&source);
570*4afad4b7Schristos 			INSIST(trust <= dns_trust_ultimate);
571*4afad4b7Schristos 			isc_buffer_remainingregion(&source, &remaining);
572*4afad4b7Schristos 			break;
573*4afad4b7Schristos 		}
574*4afad4b7Schristos 		result = dns_rdataset_next(&rclone);
575*4afad4b7Schristos 		dns_rdata_reset(&rdata);
576*4afad4b7Schristos 	}
577*4afad4b7Schristos 	dns_rdataset_disassociate(&rclone);
578*4afad4b7Schristos 	if (result == ISC_R_NOMORE) {
579*4afad4b7Schristos 		return (ISC_R_NOTFOUND);
580*4afad4b7Schristos 	}
581*4afad4b7Schristos 	if (result != ISC_R_SUCCESS) {
582*4afad4b7Schristos 		return (result);
583*4afad4b7Schristos 	}
584*4afad4b7Schristos 
585*4afad4b7Schristos 	INSIST(remaining.length != 0);
586*4afad4b7Schristos 
587*4afad4b7Schristos 	rdataset->methods = &rdataset_methods;
588*4afad4b7Schristos 	rdataset->rdclass = ncacherdataset->rdclass;
589*4afad4b7Schristos 	rdataset->type = type;
590*4afad4b7Schristos 	rdataset->covers = 0;
591*4afad4b7Schristos 	rdataset->ttl = ncacherdataset->ttl;
592*4afad4b7Schristos 	rdataset->trust = trust;
593*4afad4b7Schristos 	rdataset->private1 = NULL;
594*4afad4b7Schristos 	rdataset->private2 = NULL;
595*4afad4b7Schristos 
596*4afad4b7Schristos 	rdataset->private3 = remaining.base;
597*4afad4b7Schristos 
598*4afad4b7Schristos 	/*
599*4afad4b7Schristos 	 * Reset iterator state.
600*4afad4b7Schristos 	 */
601*4afad4b7Schristos 	rdataset->privateuint4 = 0;
602*4afad4b7Schristos 	rdataset->private5 = NULL;
603*4afad4b7Schristos 	rdataset->private6 = NULL;
604*4afad4b7Schristos 	return (ISC_R_SUCCESS);
605*4afad4b7Schristos }
606*4afad4b7Schristos 
607*4afad4b7Schristos isc_result_t
dns_ncache_getsigrdataset(dns_rdataset_t * ncacherdataset,dns_name_t * name,dns_rdatatype_t covers,dns_rdataset_t * rdataset)608*4afad4b7Schristos dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
609*4afad4b7Schristos 			  dns_rdatatype_t covers, dns_rdataset_t *rdataset) {
610*4afad4b7Schristos 	dns_name_t tname;
611*4afad4b7Schristos 	dns_rdata_rrsig_t rrsig;
612*4afad4b7Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
613*4afad4b7Schristos 	dns_rdataset_t rclone;
614*4afad4b7Schristos 	dns_rdatatype_t type;
615*4afad4b7Schristos 	dns_trust_t trust = dns_trust_none;
616*4afad4b7Schristos 	isc_buffer_t source;
617*4afad4b7Schristos 	isc_region_t remaining, sigregion;
618*4afad4b7Schristos 	isc_result_t result;
619*4afad4b7Schristos 	unsigned char *raw;
620*4afad4b7Schristos 	unsigned int count;
621*4afad4b7Schristos 
622*4afad4b7Schristos 	REQUIRE(ncacherdataset != NULL);
623*4afad4b7Schristos 	REQUIRE(ncacherdataset->type == 0);
624*4afad4b7Schristos 	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
625*4afad4b7Schristos 	REQUIRE(name != NULL);
626*4afad4b7Schristos 	REQUIRE(!dns_rdataset_isassociated(rdataset));
627*4afad4b7Schristos 
628*4afad4b7Schristos 	dns_rdataset_init(&rclone);
629*4afad4b7Schristos 	dns_rdataset_clone(ncacherdataset, &rclone);
630*4afad4b7Schristos 	result = dns_rdataset_first(&rclone);
631*4afad4b7Schristos 	while (result == ISC_R_SUCCESS) {
632*4afad4b7Schristos 		dns_rdataset_current(&rclone, &rdata);
633*4afad4b7Schristos 		isc_buffer_init(&source, rdata.data, rdata.length);
634*4afad4b7Schristos 		isc_buffer_add(&source, rdata.length);
635*4afad4b7Schristos 		dns_name_init(&tname, NULL);
636*4afad4b7Schristos 		isc_buffer_remainingregion(&source, &remaining);
637*4afad4b7Schristos 		dns_name_fromregion(&tname, &remaining);
638*4afad4b7Schristos 		INSIST(remaining.length >= tname.length);
639*4afad4b7Schristos 		isc_buffer_forward(&source, tname.length);
640*4afad4b7Schristos 		isc_region_consume(&remaining, tname.length);
641*4afad4b7Schristos 
642*4afad4b7Schristos 		INSIST(remaining.length >= 2);
643*4afad4b7Schristos 		type = isc_buffer_getuint16(&source);
644*4afad4b7Schristos 		isc_region_consume(&remaining, 2);
645*4afad4b7Schristos 
646*4afad4b7Schristos 		if (type != dns_rdatatype_rrsig ||
647*4afad4b7Schristos 		    !dns_name_equal(&tname, name))
648*4afad4b7Schristos 		{
649*4afad4b7Schristos 			result = dns_rdataset_next(&rclone);
650*4afad4b7Schristos 			dns_rdata_reset(&rdata);
651*4afad4b7Schristos 			continue;
652*4afad4b7Schristos 		}
653*4afad4b7Schristos 
654*4afad4b7Schristos 		INSIST(remaining.length >= 1);
655*4afad4b7Schristos 		trust = isc_buffer_getuint8(&source);
656*4afad4b7Schristos 		INSIST(trust <= dns_trust_ultimate);
657*4afad4b7Schristos 		isc_region_consume(&remaining, 1);
658*4afad4b7Schristos 
659*4afad4b7Schristos 		raw = remaining.base;
660*4afad4b7Schristos 		count = raw[0] * 256 + raw[1];
661*4afad4b7Schristos 		INSIST(count > 0);
662*4afad4b7Schristos 		raw += 2;
663*4afad4b7Schristos 		sigregion.length = raw[0] * 256 + raw[1];
664*4afad4b7Schristos 		raw += 2;
665*4afad4b7Schristos 		sigregion.base = raw;
666*4afad4b7Schristos 		dns_rdata_reset(&rdata);
667*4afad4b7Schristos 		dns_rdata_fromregion(&rdata, rdataset->rdclass,
668*4afad4b7Schristos 				     dns_rdatatype_rrsig, &sigregion);
669*4afad4b7Schristos 		(void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
670*4afad4b7Schristos 		if (rrsig.covered == covers) {
671*4afad4b7Schristos 			isc_buffer_remainingregion(&source, &remaining);
672*4afad4b7Schristos 			break;
673*4afad4b7Schristos 		}
674*4afad4b7Schristos 
675*4afad4b7Schristos 		result = dns_rdataset_next(&rclone);
676*4afad4b7Schristos 		dns_rdata_reset(&rdata);
677*4afad4b7Schristos 	}
678*4afad4b7Schristos 	dns_rdataset_disassociate(&rclone);
679*4afad4b7Schristos 	if (result == ISC_R_NOMORE) {
680*4afad4b7Schristos 		return (ISC_R_NOTFOUND);
681*4afad4b7Schristos 	}
682*4afad4b7Schristos 	if (result != ISC_R_SUCCESS) {
683*4afad4b7Schristos 		return (result);
684*4afad4b7Schristos 	}
685*4afad4b7Schristos 
686*4afad4b7Schristos 	INSIST(remaining.length != 0);
687*4afad4b7Schristos 
688*4afad4b7Schristos 	rdataset->methods = &rdataset_methods;
689*4afad4b7Schristos 	rdataset->rdclass = ncacherdataset->rdclass;
690*4afad4b7Schristos 	rdataset->type = dns_rdatatype_rrsig;
691*4afad4b7Schristos 	rdataset->covers = covers;
692*4afad4b7Schristos 	rdataset->ttl = ncacherdataset->ttl;
693*4afad4b7Schristos 	rdataset->trust = trust;
694*4afad4b7Schristos 	rdataset->private1 = NULL;
695*4afad4b7Schristos 	rdataset->private2 = NULL;
696*4afad4b7Schristos 
697*4afad4b7Schristos 	rdataset->private3 = remaining.base;
698*4afad4b7Schristos 
699*4afad4b7Schristos 	/*
700*4afad4b7Schristos 	 * Reset iterator state.
701*4afad4b7Schristos 	 */
702*4afad4b7Schristos 	rdataset->privateuint4 = 0;
703*4afad4b7Schristos 	rdataset->private5 = NULL;
704*4afad4b7Schristos 	rdataset->private6 = NULL;
705*4afad4b7Schristos 	return (ISC_R_SUCCESS);
706*4afad4b7Schristos }
707*4afad4b7Schristos 
708*4afad4b7Schristos void
dns_ncache_current(dns_rdataset_t * ncacherdataset,dns_name_t * found,dns_rdataset_t * rdataset)709*4afad4b7Schristos dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
710*4afad4b7Schristos 		   dns_rdataset_t *rdataset) {
711*4afad4b7Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
712*4afad4b7Schristos 	dns_trust_t trust;
713*4afad4b7Schristos 	isc_region_t remaining, sigregion;
714*4afad4b7Schristos 	isc_buffer_t source;
715*4afad4b7Schristos 	dns_name_t tname;
716*4afad4b7Schristos 	dns_rdatatype_t type;
717*4afad4b7Schristos 	unsigned int count;
718*4afad4b7Schristos 	dns_rdata_rrsig_t rrsig;
719*4afad4b7Schristos 	unsigned char *raw;
720*4afad4b7Schristos 
721*4afad4b7Schristos 	REQUIRE(ncacherdataset != NULL);
722*4afad4b7Schristos 	REQUIRE(ncacherdataset->type == 0);
723*4afad4b7Schristos 	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
724*4afad4b7Schristos 	REQUIRE(found != NULL);
725*4afad4b7Schristos 	REQUIRE(!dns_rdataset_isassociated(rdataset));
726*4afad4b7Schristos 
727*4afad4b7Schristos 	dns_rdataset_current(ncacherdataset, &rdata);
728*4afad4b7Schristos 	isc_buffer_init(&source, rdata.data, rdata.length);
729*4afad4b7Schristos 	isc_buffer_add(&source, rdata.length);
730*4afad4b7Schristos 
731*4afad4b7Schristos 	dns_name_init(&tname, NULL);
732*4afad4b7Schristos 	isc_buffer_remainingregion(&source, &remaining);
733*4afad4b7Schristos 	dns_name_fromregion(found, &remaining);
734*4afad4b7Schristos 	INSIST(remaining.length >= found->length);
735*4afad4b7Schristos 	isc_buffer_forward(&source, found->length);
736*4afad4b7Schristos 	remaining.length -= found->length;
737*4afad4b7Schristos 
738*4afad4b7Schristos 	INSIST(remaining.length >= 5);
739*4afad4b7Schristos 	type = isc_buffer_getuint16(&source);
740*4afad4b7Schristos 	trust = isc_buffer_getuint8(&source);
741*4afad4b7Schristos 	INSIST(trust <= dns_trust_ultimate);
742*4afad4b7Schristos 	isc_buffer_remainingregion(&source, &remaining);
743*4afad4b7Schristos 
744*4afad4b7Schristos 	rdataset->methods = &rdataset_methods;
745*4afad4b7Schristos 	rdataset->rdclass = ncacherdataset->rdclass;
746*4afad4b7Schristos 	rdataset->type = type;
747*4afad4b7Schristos 	if (type == dns_rdatatype_rrsig) {
748*4afad4b7Schristos 		/*
749*4afad4b7Schristos 		 * Extract covers from RRSIG.
750*4afad4b7Schristos 		 */
751*4afad4b7Schristos 		raw = remaining.base;
752*4afad4b7Schristos 		count = raw[0] * 256 + raw[1];
753*4afad4b7Schristos 		INSIST(count > 0);
754*4afad4b7Schristos 		raw += 2;
755*4afad4b7Schristos 		sigregion.length = raw[0] * 256 + raw[1];
756*4afad4b7Schristos 		raw += 2;
757*4afad4b7Schristos 		sigregion.base = raw;
758*4afad4b7Schristos 		dns_rdata_reset(&rdata);
759*4afad4b7Schristos 		dns_rdata_fromregion(&rdata, rdataset->rdclass, rdataset->type,
760*4afad4b7Schristos 				     &sigregion);
761*4afad4b7Schristos 		(void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
762*4afad4b7Schristos 		rdataset->covers = rrsig.covered;
763*4afad4b7Schristos 	} else {
764*4afad4b7Schristos 		rdataset->covers = 0;
765*4afad4b7Schristos 	}
766*4afad4b7Schristos 	rdataset->ttl = ncacherdataset->ttl;
767*4afad4b7Schristos 	rdataset->trust = trust;
768*4afad4b7Schristos 	rdataset->private1 = NULL;
769*4afad4b7Schristos 	rdataset->private2 = NULL;
770*4afad4b7Schristos 
771*4afad4b7Schristos 	rdataset->private3 = remaining.base;
772*4afad4b7Schristos 
773*4afad4b7Schristos 	/*
774*4afad4b7Schristos 	 * Reset iterator state.
775*4afad4b7Schristos 	 */
776*4afad4b7Schristos 	rdataset->privateuint4 = 0;
777*4afad4b7Schristos 	rdataset->private5 = NULL;
778*4afad4b7Schristos 	rdataset->private6 = NULL;
779*4afad4b7Schristos }
780