1 /* $NetBSD: rdatalist.c,v 1.7 2023/01/25 21:43:30 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <stddef.h>
19 #include <string.h>
20
21 #include <isc/util.h>
22
23 #include <dns/name.h>
24 #include <dns/nsec3.h>
25 #include <dns/rdata.h>
26 #include <dns/rdatalist.h>
27 #include <dns/rdataset.h>
28
29 #include "rdatalist_p.h"
30
31 static dns_rdatasetmethods_t methods = {
32 isc__rdatalist_disassociate,
33 isc__rdatalist_first,
34 isc__rdatalist_next,
35 isc__rdatalist_current,
36 isc__rdatalist_clone,
37 isc__rdatalist_count,
38 isc__rdatalist_addnoqname,
39 isc__rdatalist_getnoqname,
40 isc__rdatalist_addclosest,
41 isc__rdatalist_getclosest,
42 NULL, /* settrust */
43 NULL, /* expire */
44 NULL, /* clearprefetch */
45 isc__rdatalist_setownercase,
46 isc__rdatalist_getownercase,
47 NULL /* addglue */
48 };
49
50 void
dns_rdatalist_init(dns_rdatalist_t * rdatalist)51 dns_rdatalist_init(dns_rdatalist_t *rdatalist) {
52 REQUIRE(rdatalist != NULL);
53
54 /*
55 * Initialize rdatalist.
56 */
57
58 rdatalist->rdclass = 0;
59 rdatalist->type = 0;
60 rdatalist->covers = 0;
61 rdatalist->ttl = 0;
62 ISC_LIST_INIT(rdatalist->rdata);
63 ISC_LINK_INIT(rdatalist, link);
64 memset(rdatalist->upper, 0xeb, sizeof(rdatalist->upper));
65 /*
66 * Clear upper set bit.
67 */
68 rdatalist->upper[0] &= ~0x01;
69 }
70
71 isc_result_t
dns_rdatalist_tordataset(dns_rdatalist_t * rdatalist,dns_rdataset_t * rdataset)72 dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset) {
73 /*
74 * Make 'rdataset' refer to the rdata in 'rdatalist'.
75 */
76
77 REQUIRE(rdatalist != NULL);
78 REQUIRE(DNS_RDATASET_VALID(rdataset));
79 REQUIRE(!dns_rdataset_isassociated(rdataset));
80
81 /* Check if dns_rdatalist_init has was called. */
82 REQUIRE(rdatalist->upper[0] == 0xea);
83
84 rdataset->methods = &methods;
85 rdataset->rdclass = rdatalist->rdclass;
86 rdataset->type = rdatalist->type;
87 rdataset->covers = rdatalist->covers;
88 rdataset->ttl = rdatalist->ttl;
89 rdataset->trust = 0;
90 rdataset->private1 = rdatalist;
91 rdataset->private2 = NULL;
92 rdataset->private3 = NULL;
93 rdataset->privateuint4 = 0;
94 rdataset->private5 = NULL;
95
96 return (ISC_R_SUCCESS);
97 }
98
99 isc_result_t
dns_rdatalist_fromrdataset(dns_rdataset_t * rdataset,dns_rdatalist_t ** rdatalist)100 dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset,
101 dns_rdatalist_t **rdatalist) {
102 REQUIRE(rdatalist != NULL && rdataset != NULL);
103 *rdatalist = rdataset->private1;
104
105 return (ISC_R_SUCCESS);
106 }
107
108 void
isc__rdatalist_disassociate(dns_rdataset_t * rdataset)109 isc__rdatalist_disassociate(dns_rdataset_t *rdataset) {
110 UNUSED(rdataset);
111 }
112
113 isc_result_t
isc__rdatalist_first(dns_rdataset_t * rdataset)114 isc__rdatalist_first(dns_rdataset_t *rdataset) {
115 dns_rdatalist_t *rdatalist;
116
117 rdatalist = rdataset->private1;
118 rdataset->private2 = ISC_LIST_HEAD(rdatalist->rdata);
119
120 if (rdataset->private2 == NULL) {
121 return (ISC_R_NOMORE);
122 }
123
124 return (ISC_R_SUCCESS);
125 }
126
127 isc_result_t
isc__rdatalist_next(dns_rdataset_t * rdataset)128 isc__rdatalist_next(dns_rdataset_t *rdataset) {
129 dns_rdata_t *rdata;
130
131 REQUIRE(rdataset != NULL);
132
133 rdata = rdataset->private2;
134 if (rdata == NULL) {
135 return (ISC_R_NOMORE);
136 }
137
138 rdataset->private2 = ISC_LIST_NEXT(rdata, link);
139
140 if (rdataset->private2 == NULL) {
141 return (ISC_R_NOMORE);
142 }
143
144 return (ISC_R_SUCCESS);
145 }
146
147 void
isc__rdatalist_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)148 isc__rdatalist_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
149 dns_rdata_t *list_rdata;
150
151 REQUIRE(rdataset != NULL);
152
153 list_rdata = rdataset->private2;
154 INSIST(list_rdata != NULL);
155
156 dns_rdata_clone(list_rdata, rdata);
157 }
158
159 void
isc__rdatalist_clone(dns_rdataset_t * source,dns_rdataset_t * target)160 isc__rdatalist_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
161 REQUIRE(source != NULL);
162 REQUIRE(target != NULL);
163
164 *target = *source;
165
166 /*
167 * Reset iterator state.
168 */
169 target->private2 = NULL;
170 }
171
172 unsigned int
isc__rdatalist_count(dns_rdataset_t * rdataset)173 isc__rdatalist_count(dns_rdataset_t *rdataset) {
174 dns_rdatalist_t *rdatalist;
175 dns_rdata_t *rdata;
176 unsigned int count;
177
178 REQUIRE(rdataset != NULL);
179
180 rdatalist = rdataset->private1;
181
182 count = 0;
183 for (rdata = ISC_LIST_HEAD(rdatalist->rdata); rdata != NULL;
184 rdata = ISC_LIST_NEXT(rdata, link))
185 {
186 count++;
187 }
188
189 return (count);
190 }
191
192 isc_result_t
isc__rdatalist_addnoqname(dns_rdataset_t * rdataset,const dns_name_t * name)193 isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name) {
194 dns_rdataset_t *neg = NULL;
195 dns_rdataset_t *negsig = NULL;
196 dns_rdataset_t *rdset;
197 dns_ttl_t ttl;
198
199 REQUIRE(rdataset != NULL);
200
201 for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL;
202 rdset = ISC_LIST_NEXT(rdset, link))
203 {
204 if (rdset->rdclass != rdataset->rdclass) {
205 continue;
206 }
207 if (rdset->type == dns_rdatatype_nsec ||
208 rdset->type == dns_rdatatype_nsec3)
209 {
210 neg = rdset;
211 }
212 }
213 if (neg == NULL) {
214 return (ISC_R_NOTFOUND);
215 }
216
217 for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL;
218 rdset = ISC_LIST_NEXT(rdset, link))
219 {
220 if (rdset->type == dns_rdatatype_rrsig &&
221 rdset->covers == neg->type)
222 {
223 negsig = rdset;
224 }
225 }
226
227 if (negsig == NULL) {
228 return (ISC_R_NOTFOUND);
229 }
230 /*
231 * Minimise ttl.
232 */
233 ttl = rdataset->ttl;
234 if (neg->ttl < ttl) {
235 ttl = neg->ttl;
236 }
237 if (negsig->ttl < ttl) {
238 ttl = negsig->ttl;
239 }
240 rdataset->ttl = neg->ttl = negsig->ttl = ttl;
241 rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
242 rdataset->private6 = name;
243 return (ISC_R_SUCCESS);
244 }
245
246 isc_result_t
isc__rdatalist_getnoqname(dns_rdataset_t * rdataset,dns_name_t * name,dns_rdataset_t * neg,dns_rdataset_t * negsig)247 isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
248 dns_rdataset_t *neg, dns_rdataset_t *negsig) {
249 dns_rdataclass_t rdclass;
250 dns_rdataset_t *tneg = NULL;
251 dns_rdataset_t *tnegsig = NULL;
252 const dns_name_t *noqname;
253
254 REQUIRE(rdataset != NULL);
255 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0);
256
257 rdclass = rdataset->rdclass;
258 noqname = rdataset->private6;
259
260 (void)dns_name_dynamic(noqname); /* Sanity Check. */
261
262 for (rdataset = ISC_LIST_HEAD(noqname->list); rdataset != NULL;
263 rdataset = ISC_LIST_NEXT(rdataset, link))
264 {
265 if (rdataset->rdclass != rdclass) {
266 continue;
267 }
268 if (rdataset->type == dns_rdatatype_nsec ||
269 rdataset->type == dns_rdatatype_nsec3)
270 {
271 tneg = rdataset;
272 }
273 }
274 if (tneg == NULL) {
275 return (ISC_R_NOTFOUND);
276 }
277
278 for (rdataset = ISC_LIST_HEAD(noqname->list); rdataset != NULL;
279 rdataset = ISC_LIST_NEXT(rdataset, link))
280 {
281 if (rdataset->type == dns_rdatatype_rrsig &&
282 rdataset->covers == tneg->type)
283 {
284 tnegsig = rdataset;
285 }
286 }
287 if (tnegsig == NULL) {
288 return (ISC_R_NOTFOUND);
289 }
290
291 dns_name_clone(noqname, name);
292 dns_rdataset_clone(tneg, neg);
293 dns_rdataset_clone(tnegsig, negsig);
294 return (ISC_R_SUCCESS);
295 }
296
297 isc_result_t
isc__rdatalist_addclosest(dns_rdataset_t * rdataset,const dns_name_t * name)298 isc__rdatalist_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name) {
299 dns_rdataset_t *neg = NULL;
300 dns_rdataset_t *negsig = NULL;
301 dns_rdataset_t *rdset;
302 dns_ttl_t ttl;
303
304 REQUIRE(rdataset != NULL);
305
306 for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL;
307 rdset = ISC_LIST_NEXT(rdset, link))
308 {
309 if (rdset->rdclass != rdataset->rdclass) {
310 continue;
311 }
312 if (rdset->type == dns_rdatatype_nsec ||
313 rdset->type == dns_rdatatype_nsec3)
314 {
315 neg = rdset;
316 }
317 }
318 if (neg == NULL) {
319 return (ISC_R_NOTFOUND);
320 }
321
322 for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL;
323 rdset = ISC_LIST_NEXT(rdset, link))
324 {
325 if (rdset->type == dns_rdatatype_rrsig &&
326 rdset->covers == neg->type)
327 {
328 negsig = rdset;
329 }
330 }
331
332 if (negsig == NULL) {
333 return (ISC_R_NOTFOUND);
334 }
335 /*
336 * Minimise ttl.
337 */
338 ttl = rdataset->ttl;
339 if (neg->ttl < ttl) {
340 ttl = neg->ttl;
341 }
342 if (negsig->ttl < ttl) {
343 ttl = negsig->ttl;
344 }
345 rdataset->ttl = neg->ttl = negsig->ttl = ttl;
346 rdataset->attributes |= DNS_RDATASETATTR_CLOSEST;
347 rdataset->private7 = name;
348 return (ISC_R_SUCCESS);
349 }
350
351 isc_result_t
isc__rdatalist_getclosest(dns_rdataset_t * rdataset,dns_name_t * name,dns_rdataset_t * neg,dns_rdataset_t * negsig)352 isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
353 dns_rdataset_t *neg, dns_rdataset_t *negsig) {
354 dns_rdataclass_t rdclass;
355 dns_rdataset_t *tneg = NULL;
356 dns_rdataset_t *tnegsig = NULL;
357 const dns_name_t *closest;
358
359 REQUIRE(rdataset != NULL);
360 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0);
361
362 rdclass = rdataset->rdclass;
363 closest = rdataset->private7;
364
365 (void)dns_name_dynamic(closest); /* Sanity Check. */
366
367 for (rdataset = ISC_LIST_HEAD(closest->list); rdataset != NULL;
368 rdataset = ISC_LIST_NEXT(rdataset, link))
369 {
370 if (rdataset->rdclass != rdclass) {
371 continue;
372 }
373 if (rdataset->type == dns_rdatatype_nsec ||
374 rdataset->type == dns_rdatatype_nsec3)
375 {
376 tneg = rdataset;
377 }
378 }
379 if (tneg == NULL) {
380 return (ISC_R_NOTFOUND);
381 }
382
383 for (rdataset = ISC_LIST_HEAD(closest->list); rdataset != NULL;
384 rdataset = ISC_LIST_NEXT(rdataset, link))
385 {
386 if (rdataset->type == dns_rdatatype_rrsig &&
387 rdataset->covers == tneg->type)
388 {
389 tnegsig = rdataset;
390 }
391 }
392 if (tnegsig == NULL) {
393 return (ISC_R_NOTFOUND);
394 }
395
396 dns_name_clone(closest, name);
397 dns_rdataset_clone(tneg, neg);
398 dns_rdataset_clone(tnegsig, negsig);
399 return (ISC_R_SUCCESS);
400 }
401
402 void
isc__rdatalist_setownercase(dns_rdataset_t * rdataset,const dns_name_t * name)403 isc__rdatalist_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
404 dns_rdatalist_t *rdatalist;
405 unsigned int i;
406
407 /*
408 * We do not need to worry about label lengths as they are all
409 * less than or equal to 63.
410 */
411 rdatalist = rdataset->private1;
412 memset(rdatalist->upper, 0, sizeof(rdatalist->upper));
413 for (i = 1; i < name->length; i++) {
414 if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) {
415 rdatalist->upper[i / 8] |= 1 << (i % 8);
416 /*
417 * Record that upper has been set.
418 */
419 }
420 }
421 /*
422 * Record that upper has been set.
423 */
424 rdatalist->upper[0] |= 0x01;
425 }
426
427 void
isc__rdatalist_getownercase(const dns_rdataset_t * rdataset,dns_name_t * name)428 isc__rdatalist_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
429 dns_rdatalist_t *rdatalist;
430 unsigned int i;
431
432 rdatalist = rdataset->private1;
433 if ((rdatalist->upper[0] & 0x01) == 0) {
434 return;
435 }
436 for (i = 0; i < name->length; i++) {
437 /*
438 * Set the case bit if it does not match the recorded bit.
439 */
440 if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a &&
441 (rdatalist->upper[i / 8] & (1 << (i % 8))) != 0)
442 {
443 name->ndata[i] &= ~0x20; /* clear the lower case bit */
444 } else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a &&
445 (rdatalist->upper[i / 8] & (1 << (i % 8))) == 0)
446 {
447 name->ndata[i] |= 0x20; /* set the lower case bit */
448 }
449 }
450 }
451