xref: /openbsd/usr.bin/dig/lib/dns/rdatalist.c (revision 905646f0)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: rdatalist.c,v 1.2 2020/02/18 18:11:27 florian Exp $ */
18 
19 /*! \file */
20 
21 #include <stddef.h>
22 
23 #include <isc/util.h>
24 
25 #include <dns/name.h>
26 #include <dns/rdata.h>
27 #include <dns/rdatalist.h>
28 #include <dns/rdataset.h>
29 
30 #include "rdatalist_p.h"
31 
32 static dns_rdatasetmethods_t methods = {
33 	isc__rdatalist_disassociate,
34 	isc__rdatalist_first,
35 	isc__rdatalist_next,
36 	isc__rdatalist_current,
37 	isc__rdatalist_clone,
38 	isc__rdatalist_count,
39 	isc__rdatalist_addnoqname,
40 	isc__rdatalist_getnoqname,
41 	isc__rdatalist_addclosest,
42 	isc__rdatalist_getclosest,
43 	NULL,
44 	NULL,
45 	NULL,
46 	NULL,
47 	NULL,
48 	NULL
49 };
50 
51 void
52 dns_rdatalist_init(dns_rdatalist_t *rdatalist) {
53 
54 	REQUIRE(rdatalist != NULL);
55 
56 	/*
57 	 * Initialize rdatalist.
58 	 */
59 
60 	rdatalist->rdclass = 0;
61 	rdatalist->type = 0;
62 	rdatalist->covers = 0;
63 	rdatalist->ttl = 0;
64 	ISC_LIST_INIT(rdatalist->rdata);
65 	ISC_LINK_INIT(rdatalist, link);
66 }
67 
68 isc_result_t
69 dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist,
70 			 dns_rdataset_t *rdataset)
71 {
72 	/*
73 	 * Make 'rdataset' refer to the rdata in 'rdatalist'.
74 	 */
75 
76 	REQUIRE(rdatalist != NULL);
77 	REQUIRE(! dns_rdataset_isassociated(rdataset));
78 
79 	rdataset->methods = &methods;
80 	rdataset->rdclass = rdatalist->rdclass;
81 	rdataset->type = rdatalist->type;
82 	rdataset->covers = rdatalist->covers;
83 	rdataset->ttl = rdatalist->ttl;
84 	rdataset->trust = 0;
85 	rdataset->private1 = rdatalist;
86 	rdataset->private2 = NULL;
87 	rdataset->private3 = NULL;
88 	rdataset->privateuint4 = 0;
89 	rdataset->private5 = NULL;
90 
91 	return (ISC_R_SUCCESS);
92 }
93 
94 isc_result_t
95 dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset,
96 			   dns_rdatalist_t **rdatalist)
97 {
98 	REQUIRE(rdatalist != NULL && rdataset != NULL);
99 	*rdatalist = rdataset->private1;
100 
101 	return (ISC_R_SUCCESS);
102 }
103 
104 void
105 isc__rdatalist_disassociate(dns_rdataset_t *rdataset) {
106 	UNUSED(rdataset);
107 }
108 
109 isc_result_t
110 isc__rdatalist_first(dns_rdataset_t *rdataset) {
111 	dns_rdatalist_t *rdatalist;
112 
113 	rdatalist = rdataset->private1;
114 	rdataset->private2 = ISC_LIST_HEAD(rdatalist->rdata);
115 
116 	if (rdataset->private2 == NULL)
117 		return (ISC_R_NOMORE);
118 
119 	return (ISC_R_SUCCESS);
120 }
121 
122 isc_result_t
123 isc__rdatalist_next(dns_rdataset_t *rdataset) {
124 	dns_rdata_t *rdata;
125 
126 	REQUIRE(rdataset != NULL);
127 
128 	rdata = rdataset->private2;
129 	if (rdata == NULL)
130 		return (ISC_R_NOMORE);
131 
132 	rdataset->private2 = ISC_LIST_NEXT(rdata, link);
133 
134 	if (rdataset->private2 == NULL)
135 		return (ISC_R_NOMORE);
136 
137 	return (ISC_R_SUCCESS);
138 }
139 
140 void
141 isc__rdatalist_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
142 	dns_rdata_t *list_rdata;
143 
144 	REQUIRE(rdataset != NULL);
145 
146 	list_rdata = rdataset->private2;
147 	INSIST(list_rdata != NULL);
148 
149 	dns_rdata_clone(list_rdata, rdata);
150 }
151 
152 void
153 isc__rdatalist_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
154 
155 	REQUIRE(source != NULL);
156 	REQUIRE(target != NULL);
157 
158 	*target = *source;
159 
160 	/*
161 	 * Reset iterator state.
162 	 */
163 	target->private2 = NULL;
164 }
165 
166 unsigned int
167 isc__rdatalist_count(dns_rdataset_t *rdataset) {
168 	dns_rdatalist_t *rdatalist;
169 	dns_rdata_t *rdata;
170 	unsigned int count;
171 
172 	REQUIRE(rdataset != NULL);
173 
174 	rdatalist = rdataset->private1;
175 
176 	count = 0;
177 	for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
178 	     rdata != NULL;
179 	     rdata = ISC_LIST_NEXT(rdata, link))
180 		count++;
181 
182 	return (count);
183 }
184 
185 isc_result_t
186 isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
187 	dns_rdataset_t *neg = NULL;
188 	dns_rdataset_t *negsig = NULL;
189 	dns_rdataset_t *rdset;
190 	dns_ttl_t ttl;
191 
192 	REQUIRE(rdataset != NULL);
193 
194 	for (rdset = ISC_LIST_HEAD(name->list);
195 	     rdset != NULL;
196 	     rdset = ISC_LIST_NEXT(rdset, link))
197 	{
198 		if (rdset->rdclass != rdataset->rdclass)
199 			continue;
200 		if (rdset->type == dns_rdatatype_nsec ||
201 		    rdset->type == dns_rdatatype_nsec3)
202 			neg = rdset;
203 	}
204 	if (neg == NULL)
205 		return (ISC_R_NOTFOUND);
206 
207 	for (rdset = ISC_LIST_HEAD(name->list);
208 	     rdset != NULL;
209 	     rdset = ISC_LIST_NEXT(rdset, link))
210 	{
211 		if (rdset->type == dns_rdatatype_rrsig &&
212 		    rdset->covers == neg->type)
213 			negsig = rdset;
214 	}
215 
216 	if (negsig == NULL)
217 		return (ISC_R_NOTFOUND);
218 	/*
219 	 * Minimise ttl.
220 	 */
221 	ttl = rdataset->ttl;
222 	if (neg->ttl < ttl)
223 		ttl = neg->ttl;
224 	if (negsig->ttl < ttl)
225 		ttl = negsig->ttl;
226 	rdataset->ttl = neg->ttl = negsig->ttl = ttl;
227 	rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
228 	rdataset->private6 = name;
229 	return (ISC_R_SUCCESS);
230 }
231 
232 isc_result_t
233 isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
234 			  dns_rdataset_t *neg, dns_rdataset_t *negsig)
235 {
236 	dns_rdataclass_t rdclass = rdataset->rdclass;
237 	dns_rdataset_t *tneg = NULL;
238 	dns_rdataset_t *tnegsig = NULL;
239 	dns_name_t *noqname = rdataset->private6;
240 
241 	REQUIRE(rdataset != NULL);
242 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0);
243 
244 	(void)dns_name_dynamic(noqname);	/* Sanity Check. */
245 
246 	for (rdataset = ISC_LIST_HEAD(noqname->list);
247 	     rdataset != NULL;
248 	     rdataset = ISC_LIST_NEXT(rdataset, link))
249 	{
250 		if (rdataset->rdclass != rdclass)
251 			continue;
252 		if (rdataset->type == dns_rdatatype_nsec ||
253 		    rdataset->type == dns_rdatatype_nsec3)
254 			tneg = rdataset;
255 	}
256 	if (tneg == NULL)
257 		return (ISC_R_NOTFOUND);
258 
259 	for (rdataset = ISC_LIST_HEAD(noqname->list);
260 	     rdataset != NULL;
261 	     rdataset = ISC_LIST_NEXT(rdataset, link))
262 	{
263 		if (rdataset->type == dns_rdatatype_rrsig &&
264 		    rdataset->covers == tneg->type)
265 			tnegsig = rdataset;
266 	}
267 	if (tnegsig == NULL)
268 		return (ISC_R_NOTFOUND);
269 
270 	dns_name_clone(noqname, name);
271 	dns_rdataset_clone(tneg, neg);
272 	dns_rdataset_clone(tnegsig, negsig);
273 	return (ISC_R_SUCCESS);
274 }
275 
276 isc_result_t
277 isc__rdatalist_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
278 	dns_rdataset_t *neg = NULL;
279 	dns_rdataset_t *negsig = NULL;
280 	dns_rdataset_t *rdset;
281 	dns_ttl_t ttl;
282 
283 	REQUIRE(rdataset != NULL);
284 
285 	for (rdset = ISC_LIST_HEAD(name->list);
286 	     rdset != NULL;
287 	     rdset = ISC_LIST_NEXT(rdset, link))
288 	{
289 		if (rdset->rdclass != rdataset->rdclass)
290 			continue;
291 		if (rdset->type == dns_rdatatype_nsec ||
292 		    rdset->type == dns_rdatatype_nsec3)
293 			neg = rdset;
294 	}
295 	if (neg == NULL)
296 		return (ISC_R_NOTFOUND);
297 
298 	for (rdset = ISC_LIST_HEAD(name->list);
299 	     rdset != NULL;
300 	     rdset = ISC_LIST_NEXT(rdset, link))
301 	{
302 		if (rdset->type == dns_rdatatype_rrsig &&
303 		    rdset->covers == neg->type)
304 			negsig = rdset;
305 	}
306 
307 	if (negsig == NULL)
308 		return (ISC_R_NOTFOUND);
309 	/*
310 	 * Minimise ttl.
311 	 */
312 	ttl = rdataset->ttl;
313 	if (neg->ttl < ttl)
314 		ttl = neg->ttl;
315 	if (negsig->ttl < ttl)
316 		ttl = negsig->ttl;
317 	rdataset->ttl = neg->ttl = negsig->ttl = ttl;
318 	rdataset->attributes |= DNS_RDATASETATTR_CLOSEST;
319 	rdataset->private7 = name;
320 	return (ISC_R_SUCCESS);
321 }
322 
323 isc_result_t
324 isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
325 			  dns_rdataset_t *neg, dns_rdataset_t *negsig)
326 {
327 	dns_rdataclass_t rdclass = rdataset->rdclass;
328 	dns_rdataset_t *tneg = NULL;
329 	dns_rdataset_t *tnegsig = NULL;
330 	dns_name_t *closest = rdataset->private7;
331 
332 	REQUIRE(rdataset != NULL);
333 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0);
334 
335 	(void)dns_name_dynamic(closest);	/* Sanity Check. */
336 
337 	for (rdataset = ISC_LIST_HEAD(closest->list);
338 	     rdataset != NULL;
339 	     rdataset = ISC_LIST_NEXT(rdataset, link))
340 	{
341 		if (rdataset->rdclass != rdclass)
342 			continue;
343 		if (rdataset->type == dns_rdatatype_nsec ||
344 		    rdataset->type == dns_rdatatype_nsec3)
345 			tneg = rdataset;
346 	}
347 	if (tneg == NULL)
348 		return (ISC_R_NOTFOUND);
349 
350 	for (rdataset = ISC_LIST_HEAD(closest->list);
351 	     rdataset != NULL;
352 	     rdataset = ISC_LIST_NEXT(rdataset, link))
353 	{
354 		if (rdataset->type == dns_rdatatype_rrsig &&
355 		    rdataset->covers == tneg->type)
356 			tnegsig = rdataset;
357 	}
358 	if (tnegsig == NULL)
359 		return (ISC_R_NOTFOUND);
360 
361 	dns_name_clone(closest, name);
362 	dns_rdataset_clone(tneg, neg);
363 	dns_rdataset_clone(tnegsig, negsig);
364 	return (ISC_R_SUCCESS);
365 }
366