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