1 1.1 christos /* $NetBSD: ncache.c,v 1.1 2024/02/18 20:57:32 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.1 christos * SPDX-License-Identifier: MPL-2.0 7 1.1 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.1 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.1 christos #include <inttypes.h> 19 1.1 christos #include <stdbool.h> 20 1.1 christos 21 1.1 christos #include <isc/buffer.h> 22 1.1 christos #include <isc/util.h> 23 1.1 christos 24 1.1 christos #include <dns/db.h> 25 1.1 christos #include <dns/message.h> 26 1.1 christos #include <dns/ncache.h> 27 1.1 christos #include <dns/rdata.h> 28 1.1 christos #include <dns/rdatalist.h> 29 1.1 christos #include <dns/rdataset.h> 30 1.1 christos #include <dns/rdatastruct.h> 31 1.1 christos 32 1.1 christos #define DNS_NCACHE_RDATA 100U 33 1.1 christos 34 1.1 christos /* 35 1.1 christos * The format of an ncache rdata is a sequence of zero or more records of 36 1.1 christos * the following format: 37 1.1 christos * 38 1.1 christos * owner name 39 1.1 christos * type 40 1.1 christos * trust 41 1.1 christos * rdata count 42 1.1 christos * rdata length These two occur 'rdata count' 43 1.1 christos * rdata times. 44 1.1 christos * 45 1.1 christos */ 46 1.1 christos 47 1.1 christos static isc_result_t 48 1.1 christos addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 49 1.1 christos dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 50 1.1 christos dns_ttl_t maxttl, bool optout, bool secure, 51 1.1 christos dns_rdataset_t *addedrdataset); 52 1.1 christos 53 1.1 christos static isc_result_t 54 1.1 christos copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) { 55 1.1 christos isc_result_t result; 56 1.1 christos unsigned int count; 57 1.1 christos isc_region_t ar, r; 58 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 59 1.1 christos 60 1.1 christos /* 61 1.1 christos * Copy the rdataset count to the buffer. 62 1.1 christos */ 63 1.1 christos isc_buffer_availableregion(buffer, &ar); 64 1.1 christos if (ar.length < 2) { 65 1.1 christos return (ISC_R_NOSPACE); 66 1.1 christos } 67 1.1 christos count = dns_rdataset_count(rdataset); 68 1.1 christos INSIST(count <= 65535); 69 1.1 christos isc_buffer_putuint16(buffer, (uint16_t)count); 70 1.1 christos 71 1.1 christos result = dns_rdataset_first(rdataset); 72 1.1 christos while (result == ISC_R_SUCCESS) { 73 1.1 christos dns_rdataset_current(rdataset, &rdata); 74 1.1 christos dns_rdata_toregion(&rdata, &r); 75 1.1 christos INSIST(r.length <= 65535); 76 1.1 christos isc_buffer_availableregion(buffer, &ar); 77 1.1 christos if (ar.length < 2) { 78 1.1 christos return (ISC_R_NOSPACE); 79 1.1 christos } 80 1.1 christos /* 81 1.1 christos * Copy the rdata length to the buffer. 82 1.1 christos */ 83 1.1 christos isc_buffer_putuint16(buffer, (uint16_t)r.length); 84 1.1 christos /* 85 1.1 christos * Copy the rdata to the buffer. 86 1.1 christos */ 87 1.1 christos result = isc_buffer_copyregion(buffer, &r); 88 1.1 christos if (result != ISC_R_SUCCESS) { 89 1.1 christos return (result); 90 1.1 christos } 91 1.1 christos dns_rdata_reset(&rdata); 92 1.1 christos result = dns_rdataset_next(rdataset); 93 1.1 christos } 94 1.1 christos if (result != ISC_R_NOMORE) { 95 1.1 christos return (result); 96 1.1 christos } 97 1.1 christos 98 1.1 christos return (ISC_R_SUCCESS); 99 1.1 christos } 100 1.1 christos 101 1.1 christos isc_result_t 102 1.1 christos dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 103 1.1 christos dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 104 1.1 christos dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) { 105 1.1 christos return (addoptout(message, cache, node, covers, now, minttl, maxttl, 106 1.1 christos false, false, addedrdataset)); 107 1.1 christos } 108 1.1 christos 109 1.1 christos isc_result_t 110 1.1 christos dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, 111 1.1 christos dns_dbnode_t *node, dns_rdatatype_t covers, 112 1.1 christos isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl, 113 1.1 christos bool optout, dns_rdataset_t *addedrdataset) { 114 1.1 christos return (addoptout(message, cache, node, covers, now, minttl, maxttl, 115 1.1 christos optout, true, addedrdataset)); 116 1.1 christos } 117 1.1 christos 118 1.1 christos static isc_result_t 119 1.1 christos addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 120 1.1 christos dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 121 1.1 christos dns_ttl_t maxttl, bool optout, bool secure, 122 1.1 christos dns_rdataset_t *addedrdataset) { 123 1.1 christos isc_result_t result; 124 1.1 christos isc_buffer_t buffer; 125 1.1 christos isc_region_t r; 126 1.1 christos dns_rdataset_t *rdataset; 127 1.1 christos dns_rdatatype_t type; 128 1.1 christos dns_name_t *name; 129 1.1 christos dns_ttl_t ttl; 130 1.1 christos dns_trust_t trust; 131 1.1 christos dns_rdata_t rdata[DNS_NCACHE_RDATA]; 132 1.1 christos dns_rdataset_t ncrdataset; 133 1.1 christos dns_rdatalist_t ncrdatalist; 134 1.1 christos unsigned char data[65536]; 135 1.1 christos unsigned int next = 0; 136 1.1 christos 137 1.1 christos /* 138 1.1 christos * Convert the authority data from 'message' into a negative cache 139 1.1 christos * rdataset, and store it in 'cache' at 'node'. 140 1.1 christos */ 141 1.1 christos 142 1.1 christos REQUIRE(message != NULL); 143 1.1 christos 144 1.1 christos /* 145 1.1 christos * We assume that all data in the authority section has been 146 1.1 christos * validated by the caller. 147 1.1 christos */ 148 1.1 christos 149 1.1 christos /* 150 1.1 christos * Initialize the list. 151 1.1 christos */ 152 1.1 christos dns_rdatalist_init(&ncrdatalist); 153 1.1 christos ncrdatalist.rdclass = dns_db_class(cache); 154 1.1 christos ncrdatalist.covers = covers; 155 1.1 christos ncrdatalist.ttl = maxttl; 156 1.1 christos 157 1.1 christos /* 158 1.1 christos * Build an ncache rdatas into buffer. 159 1.1 christos */ 160 1.1 christos ttl = maxttl; 161 1.1 christos trust = 0xffff; 162 1.1 christos isc_buffer_init(&buffer, data, sizeof(data)); 163 1.1 christos if (message->counts[DNS_SECTION_AUTHORITY]) { 164 1.1 christos result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 165 1.1 christos } else { 166 1.1 christos result = ISC_R_NOMORE; 167 1.1 christos } 168 1.1 christos while (result == ISC_R_SUCCESS) { 169 1.1 christos name = NULL; 170 1.1 christos dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); 171 1.1 christos if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) { 172 1.1 christos for (rdataset = ISC_LIST_HEAD(name->list); 173 1.1 christos rdataset != NULL; 174 1.1 christos rdataset = ISC_LIST_NEXT(rdataset, link)) 175 1.1 christos { 176 1.1 christos if ((rdataset->attributes & 177 1.1 christos DNS_RDATASETATTR_NCACHE) == 0) 178 1.1 christos { 179 1.1 christos continue; 180 1.1 christos } 181 1.1 christos type = rdataset->type; 182 1.1 christos if (type == dns_rdatatype_rrsig) { 183 1.1 christos type = rdataset->covers; 184 1.1 christos } 185 1.1 christos if (type == dns_rdatatype_soa || 186 1.1 christos type == dns_rdatatype_nsec || 187 1.1 christos type == dns_rdatatype_nsec3) 188 1.1 christos { 189 1.1 christos if (ttl > rdataset->ttl) { 190 1.1 christos ttl = rdataset->ttl; 191 1.1 christos } 192 1.1 christos if (ttl < minttl) { 193 1.1 christos ttl = minttl; 194 1.1 christos } 195 1.1 christos if (trust > rdataset->trust) { 196 1.1 christos trust = rdataset->trust; 197 1.1 christos } 198 1.1 christos /* 199 1.1 christos * Copy the owner name to the buffer. 200 1.1 christos */ 201 1.1 christos dns_name_toregion(name, &r); 202 1.1 christos result = isc_buffer_copyregion(&buffer, 203 1.1 christos &r); 204 1.1 christos if (result != ISC_R_SUCCESS) { 205 1.1 christos return (result); 206 1.1 christos } 207 1.1 christos /* 208 1.1 christos * Copy the type to the buffer. 209 1.1 christos */ 210 1.1 christos isc_buffer_availableregion(&buffer, &r); 211 1.1 christos if (r.length < 3) { 212 1.1 christos return (ISC_R_NOSPACE); 213 1.1 christos } 214 1.1 christos isc_buffer_putuint16(&buffer, 215 1.1 christos rdataset->type); 216 1.1 christos isc_buffer_putuint8( 217 1.1 christos &buffer, 218 1.1 christos (unsigned char)rdataset->trust); 219 1.1 christos /* 220 1.1 christos * Copy the rdataset into the buffer. 221 1.1 christos */ 222 1.1 christos result = copy_rdataset(rdataset, 223 1.1 christos &buffer); 224 1.1 christos if (result != ISC_R_SUCCESS) { 225 1.1 christos return (result); 226 1.1 christos } 227 1.1 christos 228 1.1 christos if (next >= DNS_NCACHE_RDATA) { 229 1.1 christos return (ISC_R_NOSPACE); 230 1.1 christos } 231 1.1 christos dns_rdata_init(&rdata[next]); 232 1.1 christos isc_buffer_remainingregion(&buffer, &r); 233 1.1 christos rdata[next].data = r.base; 234 1.1 christos rdata[next].length = r.length; 235 1.1 christos rdata[next].rdclass = 236 1.1 christos ncrdatalist.rdclass; 237 1.1 christos rdata[next].type = 0; 238 1.1 christos rdata[next].flags = 0; 239 1.1 christos ISC_LIST_APPEND(ncrdatalist.rdata, 240 1.1 christos &rdata[next], link); 241 1.1 christos isc_buffer_forward(&buffer, r.length); 242 1.1 christos next++; 243 1.1 christos } 244 1.1 christos } 245 1.1 christos } 246 1.1 christos result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); 247 1.1 christos } 248 1.1 christos if (result != ISC_R_NOMORE) { 249 1.1 christos return (result); 250 1.1 christos } 251 1.1 christos 252 1.1 christos if (trust == 0xffff) { 253 1.1 christos if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 && 254 1.1 christos message->counts[DNS_SECTION_ANSWER] == 0) 255 1.1 christos { 256 1.1 christos /* 257 1.1 christos * The response has aa set and we haven't followed 258 1.1 christos * any CNAME or DNAME chains. 259 1.1 christos */ 260 1.1 christos trust = dns_trust_authauthority; 261 1.1 christos } else { 262 1.1 christos trust = dns_trust_additional; 263 1.1 christos } 264 1.1 christos ttl = 0; 265 1.1 christos } 266 1.1 christos 267 1.1 christos INSIST(trust != 0xffff); 268 1.1 christos 269 1.1 christos ncrdatalist.ttl = ttl; 270 1.1 christos 271 1.1 christos dns_rdataset_init(&ncrdataset); 272 1.1 christos RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) == 273 1.1 christos ISC_R_SUCCESS); 274 1.1 christos if (!secure && trust > dns_trust_answer) { 275 1.1 christos trust = dns_trust_answer; 276 1.1 christos } 277 1.1 christos ncrdataset.trust = trust; 278 1.1 christos ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE; 279 1.1 christos if (message->rcode == dns_rcode_nxdomain) { 280 1.1 christos ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN; 281 1.1 christos } 282 1.1 christos if (optout) { 283 1.1 christos ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT; 284 1.1 christos } 285 1.1 christos 286 1.1 christos return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0, 287 1.1 christos addedrdataset)); 288 1.1 christos } 289 1.1 christos 290 1.1 christos isc_result_t 291 1.1 christos dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, 292 1.1 christos isc_buffer_t *target, unsigned int options, 293 1.1 christos unsigned int *countp) { 294 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 295 1.1 christos isc_result_t result; 296 1.1 christos isc_region_t remaining, tavailable; 297 1.1 christos isc_buffer_t source, savedbuffer, rdlen; 298 1.1 christos dns_name_t name; 299 1.1 christos dns_rdatatype_t type; 300 1.1 christos unsigned int i, rcount, count; 301 1.1 christos 302 1.1 christos /* 303 1.1 christos * Convert the negative caching rdataset 'rdataset' to wire format, 304 1.1 christos * compressing names as specified in 'cctx', and storing the result in 305 1.1 christos * 'target'. 306 1.1 christos */ 307 1.1 christos 308 1.1 christos REQUIRE(rdataset != NULL); 309 1.1 christos REQUIRE(rdataset->type == 0); 310 1.1 christos REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 311 1.1 christos 312 1.1 christos savedbuffer = *target; 313 1.1 christos count = 0; 314 1.1 christos 315 1.1 christos result = dns_rdataset_first(rdataset); 316 1.1 christos while (result == ISC_R_SUCCESS) { 317 1.1 christos dns_rdataset_current(rdataset, &rdata); 318 1.1 christos isc_buffer_init(&source, rdata.data, rdata.length); 319 1.1 christos isc_buffer_add(&source, rdata.length); 320 1.1 christos dns_name_init(&name, NULL); 321 1.1 christos isc_buffer_remainingregion(&source, &remaining); 322 1.1 christos dns_name_fromregion(&name, &remaining); 323 1.1 christos INSIST(remaining.length >= name.length); 324 1.1 christos isc_buffer_forward(&source, name.length); 325 1.1 christos remaining.length -= name.length; 326 1.1 christos 327 1.1 christos INSIST(remaining.length >= 5); 328 1.1 christos type = isc_buffer_getuint16(&source); 329 1.1 christos isc_buffer_forward(&source, 1); 330 1.1 christos rcount = isc_buffer_getuint16(&source); 331 1.1 christos 332 1.1 christos for (i = 0; i < rcount; i++) { 333 1.1 christos /* 334 1.1 christos * Get the length of this rdata and set up an 335 1.1 christos * rdata structure for it. 336 1.1 christos */ 337 1.1 christos isc_buffer_remainingregion(&source, &remaining); 338 1.1 christos INSIST(remaining.length >= 2); 339 1.1 christos dns_rdata_reset(&rdata); 340 1.1 christos rdata.length = isc_buffer_getuint16(&source); 341 1.1 christos isc_buffer_remainingregion(&source, &remaining); 342 1.1 christos rdata.data = remaining.base; 343 1.1 christos rdata.type = type; 344 1.1 christos rdata.rdclass = rdataset->rdclass; 345 1.1 christos INSIST(remaining.length >= rdata.length); 346 1.1 christos isc_buffer_forward(&source, rdata.length); 347 1.1 christos 348 1.1 christos if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 && 349 1.1 christos dns_rdatatype_isdnssec(type)) 350 1.1 christos { 351 1.1 christos continue; 352 1.1 christos } 353 1.1 christos 354 1.1 christos /* 355 1.1 christos * Write the name. 356 1.1 christos */ 357 1.1 christos dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 358 1.1 christos result = dns_name_towire(&name, cctx, target); 359 1.1 christos if (result != ISC_R_SUCCESS) { 360 1.1 christos goto rollback; 361 1.1 christos } 362 1.1 christos 363 1.1 christos /* 364 1.1 christos * See if we have space for type, class, ttl, and 365 1.1 christos * rdata length. Write the type, class, and ttl. 366 1.1 christos */ 367 1.1 christos isc_buffer_availableregion(target, &tavailable); 368 1.1 christos if (tavailable.length < 10) { 369 1.1 christos result = ISC_R_NOSPACE; 370 1.1 christos goto rollback; 371 1.1 christos } 372 1.1 christos isc_buffer_putuint16(target, type); 373 1.1 christos isc_buffer_putuint16(target, rdataset->rdclass); 374 1.1 christos isc_buffer_putuint32(target, rdataset->ttl); 375 1.1 christos 376 1.1 christos /* 377 1.1 christos * Save space for rdata length. 378 1.1 christos */ 379 1.1 christos rdlen = *target; 380 1.1 christos isc_buffer_add(target, 2); 381 1.1 christos 382 1.1 christos /* 383 1.1 christos * Write the rdata. 384 1.1 christos */ 385 1.1 christos result = dns_rdata_towire(&rdata, cctx, target); 386 1.1 christos if (result != ISC_R_SUCCESS) { 387 1.1 christos goto rollback; 388 1.1 christos } 389 1.1 christos 390 1.1 christos /* 391 1.1 christos * Set the rdata length field to the compressed 392 1.1 christos * length. 393 1.1 christos */ 394 1.1 christos INSIST((target->used >= rdlen.used + 2) && 395 1.1 christos (target->used - rdlen.used - 2 < 65536)); 396 1.1 christos isc_buffer_putuint16( 397 1.1 christos &rdlen, 398 1.1 christos (uint16_t)(target->used - rdlen.used - 2)); 399 1.1 christos 400 1.1 christos count++; 401 1.1 christos } 402 1.1 christos INSIST(isc_buffer_remaininglength(&source) == 0); 403 1.1 christos result = dns_rdataset_next(rdataset); 404 1.1 christos dns_rdata_reset(&rdata); 405 1.1 christos } 406 1.1 christos if (result != ISC_R_NOMORE) { 407 1.1 christos goto rollback; 408 1.1 christos } 409 1.1 christos 410 1.1 christos *countp = count; 411 1.1 christos 412 1.1 christos return (ISC_R_SUCCESS); 413 1.1 christos 414 1.1 christos rollback: 415 1.1 christos INSIST(savedbuffer.used < 65536); 416 1.1 christos dns_compress_rollback(cctx, (uint16_t)savedbuffer.used); 417 1.1 christos *countp = 0; 418 1.1 christos *target = savedbuffer; 419 1.1 christos 420 1.1 christos return (result); 421 1.1 christos } 422 1.1 christos 423 1.1 christos static void 424 1.1 christos rdataset_disassociate(dns_rdataset_t *rdataset) { 425 1.1 christos UNUSED(rdataset); 426 1.1 christos } 427 1.1 christos 428 1.1 christos static isc_result_t 429 1.1 christos rdataset_first(dns_rdataset_t *rdataset) { 430 1.1 christos unsigned char *raw = rdataset->private3; 431 1.1 christos unsigned int count; 432 1.1 christos 433 1.1 christos count = raw[0] * 256 + raw[1]; 434 1.1 christos if (count == 0) { 435 1.1 christos rdataset->private5 = NULL; 436 1.1 christos return (ISC_R_NOMORE); 437 1.1 christos } 438 1.1 christos raw += 2; 439 1.1 christos /* 440 1.1 christos * The privateuint4 field is the number of rdata beyond the cursor 441 1.1 christos * position, so we decrement the total count by one before storing 442 1.1 christos * it. 443 1.1 christos */ 444 1.1 christos count--; 445 1.1 christos rdataset->privateuint4 = count; 446 1.1 christos rdataset->private5 = raw; 447 1.1 christos 448 1.1 christos return (ISC_R_SUCCESS); 449 1.1 christos } 450 1.1 christos 451 1.1 christos static isc_result_t 452 1.1 christos rdataset_next(dns_rdataset_t *rdataset) { 453 1.1 christos unsigned int count; 454 1.1 christos unsigned int length; 455 1.1 christos unsigned char *raw; 456 1.1 christos 457 1.1 christos count = rdataset->privateuint4; 458 1.1 christos if (count == 0) { 459 1.1 christos return (ISC_R_NOMORE); 460 1.1 christos } 461 1.1 christos count--; 462 1.1 christos rdataset->privateuint4 = count; 463 1.1 christos raw = rdataset->private5; 464 1.1 christos length = raw[0] * 256 + raw[1]; 465 1.1 christos raw += length + 2; 466 1.1 christos rdataset->private5 = raw; 467 1.1 christos 468 1.1 christos return (ISC_R_SUCCESS); 469 1.1 christos } 470 1.1 christos 471 1.1 christos static void 472 1.1 christos rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 473 1.1 christos unsigned char *raw = rdataset->private5; 474 1.1 christos isc_region_t r; 475 1.1 christos 476 1.1 christos REQUIRE(raw != NULL); 477 1.1 christos 478 1.1 christos r.length = raw[0] * 256 + raw[1]; 479 1.1 christos raw += 2; 480 1.1 christos r.base = raw; 481 1.1 christos dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 482 1.1 christos } 483 1.1 christos 484 1.1 christos static void 485 1.1 christos rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 486 1.1 christos *target = *source; 487 1.1 christos 488 1.1 christos /* 489 1.1 christos * Reset iterator state. 490 1.1 christos */ 491 1.1 christos target->privateuint4 = 0; 492 1.1 christos target->private5 = NULL; 493 1.1 christos } 494 1.1 christos 495 1.1 christos static unsigned int 496 1.1 christos rdataset_count(dns_rdataset_t *rdataset) { 497 1.1 christos unsigned char *raw = rdataset->private3; 498 1.1 christos unsigned int count; 499 1.1 christos 500 1.1 christos count = raw[0] * 256 + raw[1]; 501 1.1 christos 502 1.1 christos return (count); 503 1.1 christos } 504 1.1 christos 505 1.1 christos static void 506 1.1 christos rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 507 1.1 christos unsigned char *raw = rdataset->private3; 508 1.1 christos 509 1.1 christos raw[-1] = (unsigned char)trust; 510 1.1 christos rdataset->trust = trust; 511 1.1 christos } 512 1.1 christos 513 1.1 christos static dns_rdatasetmethods_t rdataset_methods = { 514 1.1 christos rdataset_disassociate, 515 1.1 christos rdataset_first, 516 1.1 christos rdataset_next, 517 1.1 christos rdataset_current, 518 1.1 christos rdataset_clone, 519 1.1 christos rdataset_count, 520 1.1 christos NULL, /* addnoqname */ 521 1.1 christos NULL, /* getnoqname */ 522 1.1 christos NULL, /* addclosest */ 523 1.1 christos NULL, /* getclosest */ 524 1.1 christos rdataset_settrust, /* settrust */ 525 1.1 christos NULL, /* expire */ 526 1.1 christos NULL, /* clearprefetch */ 527 1.1 christos NULL, /* setownercase */ 528 1.1 christos NULL, /* getownercase */ 529 1.1 christos NULL /* addglue */ 530 1.1 christos }; 531 1.1 christos 532 1.1 christos isc_result_t 533 1.1 christos dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, 534 1.1 christos dns_rdatatype_t type, dns_rdataset_t *rdataset) { 535 1.1 christos isc_result_t result; 536 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 537 1.1 christos isc_region_t remaining; 538 1.1 christos isc_buffer_t source; 539 1.1 christos dns_name_t tname; 540 1.1 christos dns_rdatatype_t ttype; 541 1.1 christos dns_trust_t trust = dns_trust_none; 542 1.1 christos dns_rdataset_t rclone; 543 1.1 christos 544 1.1 christos REQUIRE(ncacherdataset != NULL); 545 1.1 christos REQUIRE(ncacherdataset->type == 0); 546 1.1 christos REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 547 1.1 christos REQUIRE(name != NULL); 548 1.1 christos REQUIRE(!dns_rdataset_isassociated(rdataset)); 549 1.1 christos REQUIRE(type != dns_rdatatype_rrsig); 550 1.1 christos 551 1.1 christos dns_rdataset_init(&rclone); 552 1.1 christos dns_rdataset_clone(ncacherdataset, &rclone); 553 1.1 christos result = dns_rdataset_first(&rclone); 554 1.1 christos while (result == ISC_R_SUCCESS) { 555 1.1 christos dns_rdataset_current(&rclone, &rdata); 556 1.1 christos isc_buffer_init(&source, rdata.data, rdata.length); 557 1.1 christos isc_buffer_add(&source, rdata.length); 558 1.1 christos dns_name_init(&tname, NULL); 559 1.1 christos isc_buffer_remainingregion(&source, &remaining); 560 1.1 christos dns_name_fromregion(&tname, &remaining); 561 1.1 christos INSIST(remaining.length >= tname.length); 562 1.1 christos isc_buffer_forward(&source, tname.length); 563 1.1 christos remaining.length -= tname.length; 564 1.1 christos 565 1.1 christos INSIST(remaining.length >= 3); 566 1.1 christos ttype = isc_buffer_getuint16(&source); 567 1.1 christos 568 1.1 christos if (ttype == type && dns_name_equal(&tname, name)) { 569 1.1 christos trust = isc_buffer_getuint8(&source); 570 1.1 christos INSIST(trust <= dns_trust_ultimate); 571 1.1 christos isc_buffer_remainingregion(&source, &remaining); 572 1.1 christos break; 573 1.1 christos } 574 1.1 christos result = dns_rdataset_next(&rclone); 575 1.1 christos dns_rdata_reset(&rdata); 576 1.1 christos } 577 1.1 christos dns_rdataset_disassociate(&rclone); 578 1.1 christos if (result == ISC_R_NOMORE) { 579 1.1 christos return (ISC_R_NOTFOUND); 580 1.1 christos } 581 1.1 christos if (result != ISC_R_SUCCESS) { 582 1.1 christos return (result); 583 1.1 christos } 584 1.1 christos 585 1.1 christos INSIST(remaining.length != 0); 586 1.1 christos 587 1.1 christos rdataset->methods = &rdataset_methods; 588 1.1 christos rdataset->rdclass = ncacherdataset->rdclass; 589 1.1 christos rdataset->type = type; 590 1.1 christos rdataset->covers = 0; 591 1.1 christos rdataset->ttl = ncacherdataset->ttl; 592 1.1 christos rdataset->trust = trust; 593 1.1 christos rdataset->private1 = NULL; 594 1.1 christos rdataset->private2 = NULL; 595 1.1 christos 596 1.1 christos rdataset->private3 = remaining.base; 597 1.1 christos 598 1.1 christos /* 599 1.1 christos * Reset iterator state. 600 1.1 christos */ 601 1.1 christos rdataset->privateuint4 = 0; 602 1.1 christos rdataset->private5 = NULL; 603 1.1 christos rdataset->private6 = NULL; 604 1.1 christos return (ISC_R_SUCCESS); 605 1.1 christos } 606 1.1 christos 607 1.1 christos isc_result_t 608 1.1 christos dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, 609 1.1 christos dns_rdatatype_t covers, dns_rdataset_t *rdataset) { 610 1.1 christos dns_name_t tname; 611 1.1 christos dns_rdata_rrsig_t rrsig; 612 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 613 1.1 christos dns_rdataset_t rclone; 614 1.1 christos dns_rdatatype_t type; 615 1.1 christos dns_trust_t trust = dns_trust_none; 616 1.1 christos isc_buffer_t source; 617 1.1 christos isc_region_t remaining, sigregion; 618 1.1 christos isc_result_t result; 619 1.1 christos unsigned char *raw; 620 1.1 christos unsigned int count; 621 1.1 christos 622 1.1 christos REQUIRE(ncacherdataset != NULL); 623 1.1 christos REQUIRE(ncacherdataset->type == 0); 624 1.1 christos REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 625 1.1 christos REQUIRE(name != NULL); 626 1.1 christos REQUIRE(!dns_rdataset_isassociated(rdataset)); 627 1.1 christos 628 1.1 christos dns_rdataset_init(&rclone); 629 1.1 christos dns_rdataset_clone(ncacherdataset, &rclone); 630 1.1 christos result = dns_rdataset_first(&rclone); 631 1.1 christos while (result == ISC_R_SUCCESS) { 632 1.1 christos dns_rdataset_current(&rclone, &rdata); 633 1.1 christos isc_buffer_init(&source, rdata.data, rdata.length); 634 1.1 christos isc_buffer_add(&source, rdata.length); 635 1.1 christos dns_name_init(&tname, NULL); 636 1.1 christos isc_buffer_remainingregion(&source, &remaining); 637 1.1 christos dns_name_fromregion(&tname, &remaining); 638 1.1 christos INSIST(remaining.length >= tname.length); 639 1.1 christos isc_buffer_forward(&source, tname.length); 640 1.1 christos isc_region_consume(&remaining, tname.length); 641 1.1 christos 642 1.1 christos INSIST(remaining.length >= 2); 643 1.1 christos type = isc_buffer_getuint16(&source); 644 1.1 christos isc_region_consume(&remaining, 2); 645 1.1 christos 646 1.1 christos if (type != dns_rdatatype_rrsig || 647 1.1 christos !dns_name_equal(&tname, name)) 648 1.1 christos { 649 1.1 christos result = dns_rdataset_next(&rclone); 650 1.1 christos dns_rdata_reset(&rdata); 651 1.1 christos continue; 652 1.1 christos } 653 1.1 christos 654 1.1 christos INSIST(remaining.length >= 1); 655 1.1 christos trust = isc_buffer_getuint8(&source); 656 1.1 christos INSIST(trust <= dns_trust_ultimate); 657 1.1 christos isc_region_consume(&remaining, 1); 658 1.1 christos 659 1.1 christos raw = remaining.base; 660 1.1 christos count = raw[0] * 256 + raw[1]; 661 1.1 christos INSIST(count > 0); 662 1.1 christos raw += 2; 663 1.1 christos sigregion.length = raw[0] * 256 + raw[1]; 664 1.1 christos raw += 2; 665 1.1 christos sigregion.base = raw; 666 1.1 christos dns_rdata_reset(&rdata); 667 1.1 christos dns_rdata_fromregion(&rdata, rdataset->rdclass, 668 1.1 christos dns_rdatatype_rrsig, &sigregion); 669 1.1 christos (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); 670 1.1 christos if (rrsig.covered == covers) { 671 1.1 christos isc_buffer_remainingregion(&source, &remaining); 672 1.1 christos break; 673 1.1 christos } 674 1.1 christos 675 1.1 christos result = dns_rdataset_next(&rclone); 676 1.1 christos dns_rdata_reset(&rdata); 677 1.1 christos } 678 1.1 christos dns_rdataset_disassociate(&rclone); 679 1.1 christos if (result == ISC_R_NOMORE) { 680 1.1 christos return (ISC_R_NOTFOUND); 681 1.1 christos } 682 1.1 christos if (result != ISC_R_SUCCESS) { 683 1.1 christos return (result); 684 1.1 christos } 685 1.1 christos 686 1.1 christos INSIST(remaining.length != 0); 687 1.1 christos 688 1.1 christos rdataset->methods = &rdataset_methods; 689 1.1 christos rdataset->rdclass = ncacherdataset->rdclass; 690 1.1 christos rdataset->type = dns_rdatatype_rrsig; 691 1.1 christos rdataset->covers = covers; 692 1.1 christos rdataset->ttl = ncacherdataset->ttl; 693 1.1 christos rdataset->trust = trust; 694 1.1 christos rdataset->private1 = NULL; 695 1.1 christos rdataset->private2 = NULL; 696 1.1 christos 697 1.1 christos rdataset->private3 = remaining.base; 698 1.1 christos 699 1.1 christos /* 700 1.1 christos * Reset iterator state. 701 1.1 christos */ 702 1.1 christos rdataset->privateuint4 = 0; 703 1.1 christos rdataset->private5 = NULL; 704 1.1 christos rdataset->private6 = NULL; 705 1.1 christos return (ISC_R_SUCCESS); 706 1.1 christos } 707 1.1 christos 708 1.1 christos void 709 1.1 christos dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, 710 1.1 christos dns_rdataset_t *rdataset) { 711 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 712 1.1 christos dns_trust_t trust; 713 1.1 christos isc_region_t remaining, sigregion; 714 1.1 christos isc_buffer_t source; 715 1.1 christos dns_name_t tname; 716 1.1 christos dns_rdatatype_t type; 717 1.1 christos unsigned int count; 718 1.1 christos dns_rdata_rrsig_t rrsig; 719 1.1 christos unsigned char *raw; 720 1.1 christos 721 1.1 christos REQUIRE(ncacherdataset != NULL); 722 1.1 christos REQUIRE(ncacherdataset->type == 0); 723 1.1 christos REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 724 1.1 christos REQUIRE(found != NULL); 725 1.1 christos REQUIRE(!dns_rdataset_isassociated(rdataset)); 726 1.1 christos 727 1.1 christos dns_rdataset_current(ncacherdataset, &rdata); 728 1.1 christos isc_buffer_init(&source, rdata.data, rdata.length); 729 1.1 christos isc_buffer_add(&source, rdata.length); 730 1.1 christos 731 1.1 christos dns_name_init(&tname, NULL); 732 1.1 christos isc_buffer_remainingregion(&source, &remaining); 733 1.1 christos dns_name_fromregion(found, &remaining); 734 1.1 christos INSIST(remaining.length >= found->length); 735 1.1 christos isc_buffer_forward(&source, found->length); 736 1.1 christos remaining.length -= found->length; 737 1.1 christos 738 1.1 christos INSIST(remaining.length >= 5); 739 1.1 christos type = isc_buffer_getuint16(&source); 740 1.1 christos trust = isc_buffer_getuint8(&source); 741 1.1 christos INSIST(trust <= dns_trust_ultimate); 742 1.1 christos isc_buffer_remainingregion(&source, &remaining); 743 1.1 christos 744 1.1 christos rdataset->methods = &rdataset_methods; 745 1.1 christos rdataset->rdclass = ncacherdataset->rdclass; 746 1.1 christos rdataset->type = type; 747 1.1 christos if (type == dns_rdatatype_rrsig) { 748 1.1 christos /* 749 1.1 christos * Extract covers from RRSIG. 750 1.1 christos */ 751 1.1 christos raw = remaining.base; 752 1.1 christos count = raw[0] * 256 + raw[1]; 753 1.1 christos INSIST(count > 0); 754 1.1 christos raw += 2; 755 1.1 christos sigregion.length = raw[0] * 256 + raw[1]; 756 1.1 christos raw += 2; 757 1.1 christos sigregion.base = raw; 758 1.1 christos dns_rdata_reset(&rdata); 759 1.1 christos dns_rdata_fromregion(&rdata, rdataset->rdclass, rdataset->type, 760 1.1 christos &sigregion); 761 1.1 christos (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); 762 1.1 christos rdataset->covers = rrsig.covered; 763 1.1 christos } else { 764 1.1 christos rdataset->covers = 0; 765 1.1 christos } 766 1.1 christos rdataset->ttl = ncacherdataset->ttl; 767 1.1 christos rdataset->trust = trust; 768 1.1 christos rdataset->private1 = NULL; 769 1.1 christos rdataset->private2 = NULL; 770 1.1 christos 771 1.1 christos rdataset->private3 = remaining.base; 772 1.1 christos 773 1.1 christos /* 774 1.1 christos * Reset iterator state. 775 1.1 christos */ 776 1.1 christos rdataset->privateuint4 = 0; 777 1.1 christos rdataset->private5 = NULL; 778 1.1 christos rdataset->private6 = NULL; 779 1.1 christos } 780