/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 | | .setownercase = dns__rdatalist_setownercase, |
37 | | .getownercase = dns__rdatalist_getownercase, |
38 | | }; |
39 | | |
40 | | void |
41 | 7.70M | dns_rdatalist_init(dns_rdatalist_t *rdatalist) { |
42 | 7.70M | REQUIRE(rdatalist != NULL); |
43 | | |
44 | | /* |
45 | | * Initialize rdatalist. |
46 | | */ |
47 | 7.70M | *rdatalist = (dns_rdatalist_t){ |
48 | 7.70M | .rdata = ISC_LIST_INITIALIZER, |
49 | 7.70M | .link = ISC_LINK_INITIALIZER, |
50 | 7.70M | }; |
51 | 7.70M | memset(rdatalist->upper, 0xeb, sizeof(rdatalist->upper)); |
52 | | |
53 | | /* |
54 | | * Clear upper set bit. |
55 | | */ |
56 | 7.70M | rdatalist->upper[0] &= ~0x01; |
57 | 7.70M | } |
58 | | |
59 | | void |
60 | 7.69M | dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset) { |
61 | | /* |
62 | | * Make 'rdataset' refer to the rdata in 'rdatalist'. |
63 | | */ |
64 | | |
65 | 7.69M | REQUIRE(rdatalist != NULL); |
66 | 7.69M | REQUIRE(DNS_RDATASET_VALID(rdataset)); |
67 | 7.69M | REQUIRE(!dns_rdataset_isassociated(rdataset)); |
68 | | |
69 | | /* Check if dns_rdatalist_init has was called. */ |
70 | 7.69M | REQUIRE(rdatalist->upper[0] == 0xea); |
71 | | |
72 | 7.69M | *rdataset = (dns_rdataset_t){ |
73 | 7.69M | .methods = &methods, |
74 | 7.69M | .rdclass = rdatalist->rdclass, |
75 | 7.69M | .type = rdatalist->type, |
76 | 7.69M | .covers = rdatalist->covers, |
77 | 7.69M | .ttl = rdatalist->ttl, |
78 | 7.69M | .rdlist.list = rdatalist, |
79 | | |
80 | 7.69M | .link = rdataset->link, |
81 | 7.69M | .attributes = rdataset->attributes, |
82 | 7.69M | .magic = rdataset->magic, |
83 | 7.69M | }; |
84 | 7.69M | } |
85 | | |
86 | | void |
87 | | dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset, |
88 | 294k | dns_rdatalist_t **rdatalist) { |
89 | 294k | REQUIRE(rdatalist != NULL && rdataset != NULL); |
90 | 294k | REQUIRE(rdataset->methods == &methods); |
91 | | |
92 | 294k | *rdatalist = rdataset->rdlist.list; |
93 | 294k | } |
94 | | |
95 | | void |
96 | 389k | dns_rdatalist_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { |
97 | 389k | UNUSED(rdataset); |
98 | 389k | } |
99 | | |
100 | | isc_result_t |
101 | 7.66M | dns__rdatalist_first(dns_rdataset_t *rdataset) { |
102 | 7.66M | dns_rdatalist_t *rdatalist = NULL; |
103 | | |
104 | 7.66M | rdatalist = rdataset->rdlist.list; |
105 | 7.66M | rdataset->rdlist.iter = ISC_LIST_HEAD(rdatalist->rdata); |
106 | | |
107 | 7.66M | if (rdataset->rdlist.iter == NULL) { |
108 | 175k | return ISC_R_NOMORE; |
109 | 175k | } |
110 | | |
111 | 7.48M | return ISC_R_SUCCESS; |
112 | 7.66M | } |
113 | | |
114 | | isc_result_t |
115 | 7.76M | dns__rdatalist_next(dns_rdataset_t *rdataset) { |
116 | 7.76M | dns_rdata_t *rdata; |
117 | | |
118 | 7.76M | rdata = rdataset->rdlist.iter; |
119 | 7.76M | if (rdata == NULL) { |
120 | 0 | return ISC_R_NOMORE; |
121 | 0 | } |
122 | | |
123 | 7.76M | rdataset->rdlist.iter = ISC_LIST_NEXT(rdata, link); |
124 | | |
125 | 7.76M | if (rdataset->rdlist.iter == NULL) { |
126 | 7.48M | return ISC_R_NOMORE; |
127 | 7.48M | } |
128 | | |
129 | 279k | return ISC_R_SUCCESS; |
130 | 7.76M | } |
131 | | |
132 | | void |
133 | 7.76M | dns__rdatalist_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { |
134 | 7.76M | dns_rdata_t *list_rdata; |
135 | | |
136 | 7.76M | list_rdata = rdataset->rdlist.iter; |
137 | 7.76M | INSIST(list_rdata != NULL); |
138 | | |
139 | 7.76M | dns_rdata_clone(list_rdata, rdata); |
140 | 7.76M | } |
141 | | |
142 | | void |
143 | | dns__rdatalist_clone(const dns_rdataset_t *source, |
144 | 0 | dns_rdataset_t *target DNS__DB_FLARG) { |
145 | 0 | REQUIRE(source != NULL); |
146 | 0 | REQUIRE(target != NULL); |
147 | |
|
148 | 0 | *target = *source; |
149 | |
|
150 | 0 | target->rdlist.iter = NULL; |
151 | 0 | } |
152 | | |
153 | | unsigned int |
154 | 7.36M | dns__rdatalist_count(dns_rdataset_t *rdataset) { |
155 | 7.36M | dns_rdatalist_t *rdatalist = NULL; |
156 | 7.36M | unsigned int count; |
157 | | |
158 | 7.36M | REQUIRE(rdataset != NULL); |
159 | | |
160 | 7.36M | rdatalist = rdataset->rdlist.list; |
161 | | |
162 | 7.36M | count = 0; |
163 | 7.52M | ISC_LIST_FOREACH(rdatalist->rdata, rdata, link) { |
164 | 7.52M | count++; |
165 | 7.52M | } |
166 | | |
167 | 7.36M | return count; |
168 | 7.36M | } |
169 | | |
170 | | isc_result_t |
171 | 0 | dns__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { |
172 | 0 | dns_rdataset_t *neg = NULL; |
173 | 0 | dns_rdataset_t *negsig = NULL; |
174 | 0 | dns_ttl_t ttl; |
175 | |
|
176 | 0 | REQUIRE(rdataset != NULL); |
177 | |
|
178 | 0 | ISC_LIST_FOREACH(name->list, rdset, link) { |
179 | 0 | if (rdset->rdclass != rdataset->rdclass || |
180 | 0 | !dns_rdatatype_isnsec(rdset->type)) |
181 | 0 | { |
182 | 0 | continue; |
183 | 0 | } |
184 | | |
185 | 0 | ISC_LIST_FOREACH(name->list, sigset, link) { |
186 | 0 | if (sigset->type == dns_rdatatype_rrsig && |
187 | 0 | sigset->covers == rdset->type) |
188 | 0 | { |
189 | 0 | neg = rdset; |
190 | 0 | negsig = sigset; |
191 | 0 | break; |
192 | 0 | } |
193 | 0 | } |
194 | 0 | } |
195 | |
|
196 | 0 | if (neg == NULL || negsig == NULL) { |
197 | 0 | return ISC_R_NOTFOUND; |
198 | 0 | } |
199 | | |
200 | | /* |
201 | | * Minimise ttl. |
202 | | */ |
203 | 0 | ttl = rdataset->ttl; |
204 | 0 | if (neg->ttl < ttl) { |
205 | 0 | ttl = neg->ttl; |
206 | 0 | } |
207 | 0 | if (negsig->ttl < ttl) { |
208 | 0 | ttl = negsig->ttl; |
209 | 0 | } |
210 | 0 | rdataset->ttl = neg->ttl = negsig->ttl = ttl; |
211 | 0 | rdataset->attributes.noqname = true; |
212 | 0 | rdataset->rdlist.noqname = name; |
213 | |
|
214 | 0 | return ISC_R_SUCCESS; |
215 | 0 | } |
216 | | |
217 | | isc_result_t |
218 | | dns__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, |
219 | | dns_rdataset_t *neg, |
220 | 0 | dns_rdataset_t *negsig DNS__DB_FLARG) { |
221 | 0 | dns_rdataclass_t rdclass; |
222 | 0 | dns_rdataset_t *tneg = NULL; |
223 | 0 | dns_rdataset_t *tnegsig = NULL; |
224 | 0 | dns_name_t *noqname = NULL; |
225 | |
|
226 | 0 | REQUIRE(rdataset != NULL); |
227 | 0 | REQUIRE(rdataset->attributes.noqname); |
228 | |
|
229 | 0 | rdclass = rdataset->rdclass; |
230 | 0 | noqname = rdataset->rdlist.noqname; |
231 | |
|
232 | 0 | (void)dns_name_dynamic(noqname); /* Sanity Check. */ |
233 | |
|
234 | 0 | ISC_LIST_FOREACH(noqname->list, rdset, link) { |
235 | 0 | if (rdset->rdclass != rdclass) { |
236 | 0 | continue; |
237 | 0 | } |
238 | 0 | if (dns_rdatatype_isnsec(rdset->type)) { |
239 | 0 | tneg = rdset; |
240 | 0 | } |
241 | 0 | } |
242 | 0 | if (tneg == NULL) { |
243 | 0 | return ISC_R_NOTFOUND; |
244 | 0 | } |
245 | | |
246 | 0 | ISC_LIST_FOREACH(noqname->list, rdset, link) { |
247 | 0 | if (rdset->type == dns_rdatatype_rrsig && |
248 | 0 | rdset->covers == tneg->type) |
249 | 0 | { |
250 | 0 | tnegsig = rdset; |
251 | 0 | } |
252 | 0 | } |
253 | 0 | if (tnegsig == NULL) { |
254 | 0 | return ISC_R_NOTFOUND; |
255 | 0 | } |
256 | | |
257 | 0 | dns_name_clone(noqname, name); |
258 | 0 | dns_rdataset_clone(tneg, neg); |
259 | 0 | dns_rdataset_clone(tnegsig, negsig); |
260 | 0 | return ISC_R_SUCCESS; |
261 | 0 | } |
262 | | |
263 | | void |
264 | 283k | dns__rdatalist_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { |
265 | 283k | dns_rdatalist_t *rdatalist; |
266 | 283k | unsigned int i; |
267 | | |
268 | | /* |
269 | | * We do not need to worry about label lengths as they are all |
270 | | * less than or equal to 63. |
271 | | */ |
272 | 283k | rdatalist = rdataset->rdlist.list; |
273 | 283k | memset(rdatalist->upper, 0, sizeof(rdatalist->upper)); |
274 | 2.36M | for (i = 1; i < name->length; i++) { |
275 | 2.07M | if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) { |
276 | 40.2k | rdatalist->upper[i / 8] |= 1 << (i % 8); |
277 | 40.2k | } |
278 | 2.07M | } |
279 | | /* |
280 | | * Record that upper has been set. |
281 | | */ |
282 | 283k | rdatalist->upper[0] |= 0x01; |
283 | 283k | } |
284 | | |
285 | | void |
286 | 246k | dns__rdatalist_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { |
287 | 246k | dns_rdatalist_t *rdatalist; |
288 | 246k | unsigned int i; |
289 | | |
290 | 246k | rdatalist = rdataset->rdlist.list; |
291 | 246k | if ((rdatalist->upper[0] & 0x01) == 0) { |
292 | 74.8k | return; |
293 | 74.8k | } |
294 | 1.89M | for (i = 0; i < name->length; i++) { |
295 | | /* |
296 | | * Set the case bit if it does not match the recorded bit. |
297 | | */ |
298 | 1.71M | if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a && |
299 | 50.5k | (rdatalist->upper[i / 8] & (1 << (i % 8))) != 0) |
300 | 0 | { |
301 | 0 | name->ndata[i] &= ~0x20; /* clear the lower case bit */ |
302 | 1.71M | } else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a && |
303 | 42.1k | (rdatalist->upper[i / 8] & (1 << (i % 8))) == 0) |
304 | 0 | { |
305 | 0 | name->ndata[i] |= 0x20; /* set the lower case bit */ |
306 | 0 | } |
307 | 1.71M | } |
308 | 171k | } |