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