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