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