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