1 /* 2 * nsec3.c -- nsec3 handling. 3 * 4 * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 #include <config.h> 10 #ifdef NSEC3 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <errno.h> 14 15 #include "nsec3.h" 16 #include "iterated_hash.h" 17 #include "namedb.h" 18 #include "nsd.h" 19 #include "answer.h" 20 21 #define NSEC3_SHA1_HASH 1 /* same type code as DS hash */ 22 23 24 static void 25 detect_nsec3_params(rr_type* nsec3_apex, 26 const unsigned char** salt, int* salt_len, int* iter) 27 { 28 /* always uses first NSEC3 record with SOA bit set */ 29 assert(salt && salt_len && iter); 30 assert(nsec3_apex); 31 *salt_len = rdata_atom_data(nsec3_apex->rdatas[3])[0]; 32 *salt = (unsigned char*)(rdata_atom_data(nsec3_apex->rdatas[3])+1); 33 *iter = read_uint16(rdata_atom_data(nsec3_apex->rdatas[2])); 34 } 35 36 static const dname_type * 37 nsec3_hash_dname_param(region_type *region, zone_type *zone, 38 const dname_type *dname, rr_type* param_rr) 39 { 40 unsigned char hash[SHA_DIGEST_LENGTH]; 41 char b32[SHA_DIGEST_LENGTH*2+1]; 42 const unsigned char* nsec3_salt = NULL; 43 int nsec3_saltlength = 0; 44 int nsec3_iterations = 0; 45 46 detect_nsec3_params(param_rr, &nsec3_salt, 47 &nsec3_saltlength, &nsec3_iterations); 48 iterated_hash(hash, nsec3_salt, nsec3_saltlength, dname_name(dname), 49 dname->name_size, nsec3_iterations); 50 b32_ntop(hash, sizeof(hash), b32, sizeof(b32)); 51 dname=dname_parse(region, b32); 52 dname=dname_concatenate(region, dname, domain_dname(zone->apex)); 53 return dname; 54 } 55 56 const dname_type * 57 nsec3_hash_dname(region_type *region, zone_type *zone, 58 const dname_type *dname) 59 { 60 return nsec3_hash_dname_param(region, zone, 61 dname, zone->nsec3_soa_rr); 62 } 63 64 static int 65 nsec3_has_soa(rr_type* rr) 66 { 67 if(rdata_atom_size(rr->rdatas[5]) >= 3 && /* has types in bitmap */ 68 rdata_atom_data(rr->rdatas[5])[0] == 0 && /* first window = 0, */ 69 /* [1]: windowlen must be >= 1 */ 70 rdata_atom_data(rr->rdatas[5])[2]&0x02) /* SOA bit set */ 71 return 1; 72 return 0; 73 } 74 75 static rr_type* 76 find_zone_nsec3(namedb_type* namedb, zone_type *zone) 77 { 78 size_t i; 79 domain_type* domain; 80 region_type* tmpregion; 81 /* Check settings in NSEC3PARAM. 82 Hash algorithm must be OK. And a NSEC3 with soa bit 83 must map to the zone apex. */ 84 rrset_type* paramset = domain_find_rrset(zone->apex, zone, TYPE_NSEC3PARAM); 85 if(!paramset || !paramset->rrs || !paramset->rr_count) 86 return NULL; 87 tmpregion = region_create(xalloc, free); 88 for(i=0; i < paramset->rr_count; i++) { 89 rr_type* rr = ¶mset->rrs[i]; 90 const dname_type* hashed_apex; 91 rrset_type* nsec3_rrset; 92 size_t j; 93 const unsigned char *salt1; 94 int saltlen1, iter1; 95 96 if(rdata_atom_data(rr->rdatas[0])[0] != NSEC3_SHA1_HASH) { 97 log_msg(LOG_ERR, "%s NSEC3PARAM entry %d has unknown hash algo %d", 98 dname_to_string(domain_dname(zone->apex), NULL), (int)i, 99 rdata_atom_data(rr->rdatas[0])[0]); 100 continue; 101 } 102 if(rdata_atom_data(rr->rdatas[1])[0] != 0) { 103 /* draft-nsec3-09: NSEC3PARAM records with flags 104 field value other than zero MUST be ignored. */ 105 continue; 106 } 107 /* check hash of apex -> NSEC3 with soa bit on */ 108 hashed_apex = nsec3_hash_dname_param(tmpregion, 109 zone, domain_dname(zone->apex), ¶mset->rrs[i]); 110 domain = domain_table_find(namedb->domains, hashed_apex); 111 if(!domain) { 112 log_msg(LOG_ERR, "%s NSEC3PARAM entry %d has no hash(apex).", 113 dname_to_string(domain_dname(zone->apex), NULL), (int)i); 114 log_msg(LOG_ERR, "hash(apex)= %s", 115 dname_to_string(hashed_apex, NULL)); 116 continue; 117 } 118 nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); 119 if(!nsec3_rrset) { 120 log_msg(LOG_ERR, "%s NSEC3PARAM entry %d: hash(apex) has no NSEC3 RRset", 121 dname_to_string(domain_dname(zone->apex), NULL), (int)i); 122 continue; 123 } 124 detect_nsec3_params(rr, &salt1, &saltlen1, &iter1); 125 /* find SOA bit enabled nsec3, with the same settings */ 126 for(j=0; j < nsec3_rrset->rr_count; j++) { 127 const unsigned char *salt2; 128 int saltlen2, iter2; 129 if(!nsec3_has_soa(&nsec3_rrset->rrs[j])) 130 continue; 131 /* check params OK. Ignores the optout bit. */ 132 detect_nsec3_params(&nsec3_rrset->rrs[j], 133 &salt2, &saltlen2, &iter2); 134 if(saltlen1 == saltlen2 && iter1 == iter2 && 135 rdata_atom_data(rr->rdatas[0])[0] == /* algo */ 136 rdata_atom_data(nsec3_rrset->rrs[j].rdatas[0])[0] 137 && memcmp(salt1, salt2, saltlen1) == 0) { 138 /* found it */ 139 DEBUG(DEBUG_QUERY, 1, (LOG_INFO, 140 "detected NSEC3 for zone %s saltlen=%d iter=%d", 141 dname_to_string(domain_dname( 142 zone->apex),0), saltlen2, iter2)); 143 region_destroy(tmpregion); 144 return &nsec3_rrset->rrs[j]; 145 } 146 } 147 log_msg(LOG_ERR, "%s NSEC3PARAM entry %d: hash(apex) no NSEC3 with SOAbit", 148 dname_to_string(domain_dname(zone->apex), NULL), (int)i); 149 } 150 region_destroy(tmpregion); 151 return NULL; 152 } 153 154 /* check that the rrset has an NSEC3 that uses the same parameters as the 155 zone is using. Pass NSEC3 rrset, and zone must have nsec3_rrset set. 156 if you pass NULL then 0 is returned. */ 157 static int 158 nsec3_rrset_params_ok(rr_type* base, rrset_type* rrset) 159 { 160 rdata_atom_type* prd; 161 size_t i; 162 if(!rrset) 163 return 0; /* without rrset, no matching params either */ 164 assert(rrset && rrset->zone && (base || rrset->zone->nsec3_soa_rr)); 165 if(!base) 166 base = rrset->zone->nsec3_soa_rr; 167 prd = base->rdatas; 168 for(i=0; i < rrset->rr_count; ++i) { 169 rdata_atom_type* rd = rrset->rrs[i].rdatas; 170 assert(rrset->rrs[i].type == TYPE_NSEC3); 171 if(rdata_atom_data(rd[0])[0] == 172 rdata_atom_data(prd[0])[0] && /* hash algo */ 173 rdata_atom_data(rd[2])[0] == 174 rdata_atom_data(prd[2])[0] && /* iterations 0 */ 175 rdata_atom_data(rd[2])[1] == 176 rdata_atom_data(prd[2])[1] && /* iterations 1 */ 177 rdata_atom_data(rd[3])[0] == 178 rdata_atom_data(prd[3])[0] && /* salt length */ 179 memcmp(rdata_atom_data(rd[3])+1, 180 rdata_atom_data(prd[3])+1, rdata_atom_data(rd[3])[0]) 181 == 0 ) 182 { 183 /* this NSEC3 matches nsec3 parameters from zone */ 184 return 1; 185 } 186 } 187 return 0; 188 } 189 190 #ifdef FULL_PREHASH 191 192 int 193 nsec3_find_cover(namedb_type* db, zone_type* zone, 194 const dname_type* hashname, domain_type** result) 195 { 196 rrset_type *rrset; 197 domain_type *walk; 198 domain_type *closest_match; 199 domain_type *closest_encloser; 200 int exact; 201 202 assert(result); 203 assert(zone->nsec3_soa_rr); 204 205 exact = domain_table_search( 206 db->domains, hashname, &closest_match, &closest_encloser); 207 /* exact match of hashed domain name + it has an NSEC3? */ 208 if(exact && 209 nsec3_rrset_params_ok(NULL, 210 domain_find_rrset(closest_encloser, zone, TYPE_NSEC3))) { 211 *result = closest_encloser; 212 assert(*result != 0); 213 return 1; 214 } 215 216 /* find covering NSEC3 record, lexicographically before the closest match */ 217 /* use nsec3_lookup to jumpstart the search */ 218 walk = closest_match->nsec3_lookup; 219 rrset = 0; 220 while(walk && dname_is_subdomain(domain_dname(walk), domain_dname(zone->apex))) 221 { 222 if(nsec3_rrset_params_ok(NULL, 223 domain_find_rrset(walk, zone, TYPE_NSEC3))) { 224 /* this rrset is OK NSEC3, exit while */ 225 rrset = domain_find_rrset(walk, zone, TYPE_NSEC3); 226 break; 227 } 228 walk = domain_previous(walk); 229 } 230 if(rrset) 231 *result = walk; 232 else { 233 /* 234 * There are no NSEC3s before the closest match. 235 * so the hash name is before the first NSEC3 record in the zone. 236 * use last NSEC3, which covers the wraparound in hash space 237 * 238 * Since the zone has an NSEC3 with the SOA bit set for NSEC3 to turn on, 239 * there is also a last nsec3, so find_cover always assigns *result!=0. 240 */ 241 *result = zone->nsec3_last; 242 } 243 assert(*result != 0); 244 return 0; 245 } 246 247 #else 248 249 int 250 nsec3_find_cover(namedb_type* ATTR_UNUSED(db), zone_type* zone, 251 const dname_type* hashname, struct nsec3_domain **result) 252 { 253 rbnode_t *node; 254 int exact; 255 256 assert(result); 257 if (!zone->nsec3_domains) 258 return 0; 259 260 exact = rbtree_find_less_equal(zone->nsec3_domains, hashname, &node); 261 if (!node) { 262 exact = 0; 263 node = rbtree_last(zone->nsec3_domains); 264 } 265 266 while (node != RBTREE_NULL) { 267 struct rrset *nsec3_rrset; 268 struct nsec3_domain *nsec3_domain = 269 (struct nsec3_domain *) node; 270 nsec3_rrset = domain_find_rrset(nsec3_domain->nsec3_domain, 271 zone, TYPE_NSEC3); 272 if (!nsec3_rrset) { 273 /* 274 * RRset in zone->nsec3_domains whose type != NSEC3 275 * If we get here, something is seriously wrong! 276 */ 277 return 0; 278 } 279 if (nsec3_rrset_params_ok(NULL, nsec3_rrset) != 0) { 280 *result = nsec3_domain; 281 return exact; 282 } 283 exact = 0; /* No match, so we're looking for closest match */ 284 node = rbtree_previous(node); 285 } 286 /* 287 * If we reach this point, *result == NULL. This should 288 * never happen since the zone should have one NSEC3 record with 289 * the SOA bit set, which matches a NSEC3PARAM RR in the zone. 290 */ 291 return exact; 292 } 293 #endif 294 295 #ifdef FULL_PREHASH 296 static void 297 prehash_domain_r(namedb_type* db, zone_type* zone, 298 domain_type* domain, region_type* region) 299 { 300 int exact; 301 const dname_type *wcard, *wcard_child, *hashname; 302 domain_type* result = 0; 303 if(!zone->nsec3_soa_rr) 304 { 305 /* set to 0 (in case NSEC3 removed after an update) */ 306 domain->nsec3_is_exact = 0; 307 domain->nsec3_cover = NULL; 308 domain->nsec3_wcard_child_cover = NULL; 309 return; 310 } 311 312 hashname = nsec3_hash_dname(region, zone, domain_dname(domain)); 313 exact = nsec3_find_cover(db, zone, hashname, &result); 314 domain->nsec3_cover = result; 315 if(exact) 316 domain->nsec3_is_exact = 1; 317 else domain->nsec3_is_exact = 0; 318 319 /* find cover for *.domain for wildcard denial */ 320 wcard = dname_parse(region, "*"); 321 wcard_child = dname_concatenate(region, wcard, domain_dname(domain)); 322 hashname = nsec3_hash_dname(region, zone, wcard_child); 323 exact = nsec3_find_cover(db, zone, hashname, &result); 324 domain->nsec3_wcard_child_cover = result; 325 326 if(exact && !domain_wildcard_child(domain)) 327 { 328 /* We found an exact match for the *.domain NSEC3 hash, 329 * but the domain wildcard child (*.domain) does not exist. 330 * Thus there is a hash collision. It will cause servfail 331 * for NXdomain queries below this domain. 332 */ 333 log_msg(LOG_WARNING, "prehash: collision of wildcard " 334 "denial for %s. Sign zone with different salt " 335 "to remove collision.", 336 dname_to_string(domain_dname(domain),0)); 337 } 338 } 339 340 #else 341 342 static void 343 prehash_domain_r(namedb_type* db, zone_type* zone, 344 domain_type* domain, region_type* region) 345 { 346 int exact; 347 const dname_type *hashname; 348 struct nsec3_domain* result = NULL; 349 350 domain->nsec3_cover = NULL; 351 hashname = nsec3_hash_dname(region, zone, domain_dname(domain)); 352 exact = nsec3_find_cover(db, zone, hashname, &result); 353 if (result && exact) 354 { 355 result->covers = domain; 356 domain->nsec3_cover = result->nsec3_domain; 357 } 358 return; 359 } 360 #endif 361 362 static void 363 prehash_domain(namedb_type* db, zone_type* zone, 364 domain_type* domain, region_type* region) 365 { 366 prehash_domain_r(db, zone, domain, region); 367 } 368 369 #ifdef FULL_PREHASH 370 static void 371 prehash_ds(namedb_type* db, zone_type* zone, 372 domain_type* domain, region_type* region) 373 { 374 domain_type* result = 0; 375 const dname_type* hashname; 376 int exact; 377 378 if(!zone->nsec3_soa_rr) { 379 domain->nsec3_ds_parent_is_exact = 0; 380 domain->nsec3_ds_parent_cover = NULL; 381 return; 382 } 383 384 /* hash again, other zone could have different hash parameters */ 385 hashname = nsec3_hash_dname(region, zone, domain_dname(domain)); 386 exact = nsec3_find_cover(db, zone, hashname, &result); 387 if(exact) 388 domain->nsec3_ds_parent_is_exact = 1; 389 else domain->nsec3_ds_parent_is_exact = 0; 390 domain->nsec3_ds_parent_cover = result; 391 } 392 #endif 393 394 #ifndef FULL_PREHASH 395 struct domain * 396 find_last_nsec3_domain(struct zone *zone) 397 { 398 rbnode_t *node; 399 if (zone->nsec3_domains == NULL) { 400 return NULL; 401 } 402 node = rbtree_last(zone->nsec3_domains); 403 if (node == RBTREE_NULL) { 404 return NULL; 405 } 406 return ((struct nsec3_domain *) node)->nsec3_domain; 407 } 408 409 void 410 prehash_zone_incremental(struct namedb *db, struct zone *zone) 411 { 412 region_type *temp_region; 413 rbnode_t *node; 414 /* find zone NSEC3PARAM settings */ 415 zone->nsec3_soa_rr = find_zone_nsec3(db, zone); 416 if (zone->nsec3_soa_rr == NULL) { 417 zone->nsec3_last = NULL; 418 return; 419 } 420 if (db->nsec3_mod_domains == NULL) { 421 return; 422 } 423 zone->nsec3_last = find_last_nsec3_domain(zone); 424 temp_region = region_create(xalloc, free); 425 node = rbtree_first(db->nsec3_mod_domains); 426 while (node != RBTREE_NULL) { 427 struct nsec3_mod_domain *nsec3_mod_domain = 428 (struct nsec3_mod_domain *) node; 429 struct domain *walk = nsec3_mod_domain->domain; 430 struct domain *domain_zone_apex; 431 432 if (!walk || 433 (dname_is_subdomain(domain_dname(walk), 434 domain_dname(zone->apex)) == 0)) { 435 node = rbtree_next(node); 436 continue; 437 } 438 if (walk->nsec3_cover != NULL) { 439 node = rbtree_next(node); 440 continue; 441 } 442 /* Empty Terminal */ 443 if (!walk->is_existing) { 444 walk->nsec3_cover = NULL; 445 node = rbtree_next(node); 446 continue; 447 } 448 449 /* 450 * Don't hash NSEC3 only nodes, unless possibly 451 * part of a weird case where node is empty nonterminal 452 * requiring NSEC3 but node name also is the hashed 453 * node name of another node requiring NSEC3. 454 * NSEC3 Empty Nonterminal with NSEC3 RRset present. 455 */ 456 if (domain_has_only_NSEC3(walk, zone) != 0) { 457 struct domain *next_domain = domain_next(walk); 458 if ((next_domain == NULL) || 459 (next_domain->parent != walk)) { 460 walk->nsec3_cover = NULL; 461 node = rbtree_next(node); 462 continue; 463 } 464 } 465 466 /* 467 * Identify domain nodes that belong to the zone 468 * which are not glue records. What if you hit a 469 * record that's in two zones but which has no 470 * cut point between the zones. Not valid but 471 * someone is gonna try it sometime. 472 * This implementation doesn't link an NSEC3 473 * record to the domain. 474 */ 475 domain_zone_apex = domain_find_zone_apex(walk); 476 if ((domain_zone_apex != NULL) && 477 (domain_zone_apex == zone->apex) && 478 (domain_is_glue(walk, zone) == 0)) { 479 480 prehash_domain(db, zone, walk, temp_region); 481 region_free_all(temp_region); 482 } 483 484 node = rbtree_next(node); 485 } 486 namedb_nsec3_mod_domains_destroy(db); 487 region_destroy(temp_region); 488 } 489 490 void 491 prehash_zone(struct namedb* db, struct zone* zone) 492 { 493 domain_type *walk; 494 domain_type *last_nsec3_node; 495 region_type *temp_region; 496 assert(db && zone); 497 498 /* find zone settings */ 499 zone->nsec3_soa_rr = find_zone_nsec3(db, zone); 500 if(!zone->nsec3_soa_rr) { 501 zone->nsec3_last = NULL; 502 return; 503 } 504 temp_region = region_create(xalloc, free); 505 506 /* go through entire zone and setup nsec3_lookup speedup */ 507 walk = zone->apex; 508 last_nsec3_node = NULL; 509 /* since we walk in sorted order, we pass all NSEC3s in sorted 510 order and we can set the lookup ptrs */ 511 while(walk && dname_is_subdomain( 512 domain_dname(walk), domain_dname(zone->apex))) 513 { 514 struct domain *domain_zone_apex; 515 516 if (walk->nsec3_cover != NULL) { 517 walk = domain_next(walk); 518 continue; 519 } 520 /* Empty Terminal */ 521 if (walk->is_existing == 0) { 522 walk->nsec3_cover = NULL; 523 walk = domain_next(walk); 524 continue; 525 } 526 527 /* 528 * Don't hash NSEC3 only nodes, unless possibly 529 * part of a weird case where node is empty nonterminal 530 * requiring NSEC3 but node name also is the hashed 531 * node name of another node requiring NSEC3. 532 * NSEC3 Empty Nonterminal with NSEC3 RRset present. 533 */ 534 if (domain_has_only_NSEC3(walk, zone)) { 535 struct domain *next_domain = domain_next(walk); 536 if ((next_domain == NULL) || 537 (next_domain->parent != walk)) { 538 walk->nsec3_cover = NULL; 539 walk = domain_next(walk); 540 continue; 541 } 542 } 543 544 /* 545 * Identify domain nodes that belong to the zone 546 * which are not glue records. What if you hit a 547 * record that's in two zones but which has no 548 * cut point between the zones. Not valid but 549 * someone is gonna try it sometime. 550 * This implementation doesn't link an NSEC3 551 * record to the domain. 552 */ 553 domain_zone_apex = domain_find_zone_apex(walk); 554 if ((domain_zone_apex != NULL) && 555 (domain_zone_apex == zone->apex) && 556 (domain_is_glue(walk, zone) == 0)) 557 { 558 prehash_domain(db, zone, walk, temp_region); 559 region_free_all(temp_region); 560 } 561 walk = domain_next(walk); 562 } 563 region_destroy(temp_region); 564 } 565 566 #else 567 568 static void 569 prehash_zone(struct namedb* db, struct zone* zone) 570 { 571 domain_type *walk; 572 domain_type *last_nsec3_node; 573 region_type *temp_region; 574 assert(db && zone); 575 576 /* find zone settings */ 577 zone->nsec3_soa_rr = find_zone_nsec3(db, zone); 578 if(!zone->nsec3_soa_rr) { 579 zone->nsec3_last = NULL; 580 return; 581 } 582 temp_region = region_create(xalloc, free); 583 584 /* go through entire zone and setup nsec3_lookup speedup */ 585 walk = zone->apex; 586 last_nsec3_node = NULL; 587 /* since we walk in sorted order, we pass all NSEC3s in sorted 588 order and we can set the lookup ptrs */ 589 while(walk && dname_is_subdomain( 590 domain_dname(walk), domain_dname(zone->apex))) 591 { 592 zone_type* z = domain_find_zone(walk); 593 if(z && z==zone) 594 { 595 if(domain_find_rrset(walk, zone, TYPE_NSEC3)) 596 last_nsec3_node = walk; 597 walk->nsec3_lookup = last_nsec3_node; 598 } 599 walk = domain_next(walk); 600 } 601 zone->nsec3_last = last_nsec3_node; 602 603 /* go through entire zone */ 604 walk = zone->apex; 605 while(walk && dname_is_subdomain( 606 domain_dname(walk), domain_dname(zone->apex))) 607 { 608 zone_type* z; 609 if(!walk->is_existing && domain_has_only_NSEC3(walk, zone)) { 610 walk->nsec3_cover = NULL; 611 walk->nsec3_wcard_child_cover = NULL; 612 walk = domain_next(walk); 613 continue; 614 } 615 z = domain_find_zone(walk); 616 if(z && z==zone && !domain_is_glue(walk, zone)) 617 { 618 prehash_domain(db, zone, walk, temp_region); 619 region_free_all(temp_region); 620 } 621 /* prehash the DS (parent zone) */ 622 if(domain_find_rrset(walk, zone, TYPE_DS) || 623 (domain_find_rrset(walk, zone, TYPE_NS) && 624 walk != zone->apex)) 625 { 626 assert(walk != zone->apex /* DS must be above zone cut */); 627 prehash_ds(db, zone, walk, temp_region); 628 region_free_all(temp_region); 629 } 630 walk = domain_next(walk); 631 } 632 region_destroy(temp_region); 633 } 634 #endif 635 636 void 637 prehash(struct namedb* db, int updated_only) 638 { 639 zone_type *z; 640 time_t end, start = time(NULL); 641 int count = 0; 642 for(z = db->zones; z; z = z->next) 643 { 644 if(!updated_only || z->updated) { 645 prehash_zone(db, z); 646 if(z->nsec3_soa_rr) 647 count++; 648 } 649 } 650 end = time(NULL); 651 if(count > 0) 652 VERBOSITY(1, (LOG_INFO, "nsec3-prepare took %d " 653 "seconds for %d zones.", (int)(end-start), count)); 654 } 655 656 657 #ifndef FULL_PREHASH 658 static void 659 nsec3_hash_and_find_cover(struct region *region, 660 struct namedb *db, const struct dname *domain_dname, 661 struct zone *zone, int *exact, struct domain **result) 662 { 663 dname_type const *hash_dname; 664 struct nsec3_domain *nsec3_domain; 665 666 *result = NULL; 667 *exact = 0; 668 hash_dname = nsec3_hash_dname(region, zone, domain_dname); 669 *exact = nsec3_find_cover(db, zone, hash_dname, &nsec3_domain); 670 if (nsec3_domain != NULL) { 671 *result = nsec3_domain->nsec3_domain; 672 } 673 return; 674 } 675 676 static void 677 nsec3_hash_and_find_wild_cover(struct region *region, 678 struct namedb *db, struct domain *domain, 679 struct zone *zone, int *exact, struct domain **result) 680 { 681 struct dname const *wcard_child; 682 /* find cover for *.domain for wildcard denial */ 683 (void) dname_make_wildcard(region, domain_dname(domain), 684 &wcard_child); 685 nsec3_hash_and_find_cover(region, db, wcard_child, zone, exact, 686 result); 687 if ((*exact != 0) && 688 (domain_wildcard_child(domain) == NULL)) { 689 /* We found an exact match for the *.domain NSEC3 hash, 690 * but the domain wildcard child (*.domain) does not exist. 691 * Thus there is a hash collision. It will cause servfail 692 * for NXdomain queries below this domain. 693 */ 694 log_msg(LOG_WARNING, 695 "collision of wildcard denial for %s. " 696 "Sign zone with different salt to remove collision.", 697 dname_to_string(domain_dname(domain), NULL)); 698 } 699 } 700 #endif 701 702 703 /* add the NSEC3 rrset to the query answer at the given domain */ 704 static void 705 nsec3_add_rrset(struct query *query, struct answer *answer, 706 rr_section_type section, struct domain* domain) 707 { 708 if(domain) { 709 rrset_type* rrset = domain_find_rrset(domain, query->zone, TYPE_NSEC3); 710 if(rrset) 711 answer_add_rrset(answer, section, domain, rrset); 712 } 713 } 714 715 /* this routine does hashing at query-time. slow. */ 716 static void 717 nsec3_add_nonexist_proof(struct query *query, struct answer *answer, 718 struct domain *encloser, struct namedb* db, const dname_type* qname) 719 { 720 const dname_type *to_prove; 721 #ifdef FULL_PREHASH 722 const dname_type *hashed; 723 #else 724 int exact = 0; 725 #endif 726 domain_type *cover = NULL; 727 assert(encloser); 728 /* if query=a.b.c.d encloser=c.d. then proof needed for b.c.d. */ 729 /* if query=a.b.c.d encloser=*.c.d. then proof needed for b.c.d. */ 730 to_prove = dname_partial_copy(query->region, qname, 731 dname_label_match_count(qname, domain_dname(encloser))+1); 732 /* generate proof that one label below closest encloser does not exist */ 733 #ifdef FULL_PREHASH 734 hashed = nsec3_hash_dname(query->region, query->zone, to_prove); 735 if(nsec3_find_cover(db, query->zone, hashed, &cover)) 736 #else 737 nsec3_hash_and_find_cover(query->region, db, to_prove, query->zone, 738 &exact, &cover); 739 if (exact) 740 #endif 741 { 742 /* exact match, hash collision */ 743 /* the hashed name of the query corresponds to an existing name. */ 744 log_msg(LOG_ERR, "nsec3 hash collision for name=%s", 745 dname_to_string(to_prove, NULL)); 746 RCODE_SET(query->packet, RCODE_SERVFAIL); 747 return; 748 } 749 else if (cover) { 750 /* cover proves the qname does not exist */ 751 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, cover); 752 } 753 } 754 755 static void 756 nsec3_add_closest_encloser_proof( 757 struct query *query, struct answer *answer, 758 struct domain *closest_encloser, struct namedb* db, 759 const dname_type* qname) 760 { 761 if(!closest_encloser) 762 return; 763 /* prove that below closest encloser nothing exists */ 764 nsec3_add_nonexist_proof(query, answer, closest_encloser, db, qname); 765 /* proof that closest encloser exists */ 766 #ifdef FULL_PREHASH 767 if(closest_encloser->nsec3_is_exact) 768 #else 769 if(closest_encloser->nsec3_cover) 770 #endif 771 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 772 closest_encloser->nsec3_cover); 773 } 774 775 776 void 777 nsec3_answer_wildcard(struct query *query, struct answer *answer, 778 struct domain *wildcard, struct namedb* db, const dname_type* qname) 779 { 780 if(!wildcard) 781 return; 782 if(!query->zone->nsec3_soa_rr) 783 return; 784 nsec3_add_nonexist_proof(query, answer, wildcard, db, qname); 785 } 786 787 788 static void 789 nsec3_add_ds_proof(struct query *query, struct answer *answer, 790 struct domain *domain, int delegpt) 791 { 792 #ifndef FULL_PREHASH 793 struct domain * ds_parent_cover = NULL; 794 int exact = 0; 795 #endif 796 /* assert we are above the zone cut */ 797 assert(domain != query->zone->apex); 798 799 #ifdef FULL_PREHASH 800 if(domain->nsec3_ds_parent_is_exact) { 801 /* use NSEC3 record from above the zone cut. */ 802 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 803 domain->nsec3_ds_parent_cover); 804 } else if (!delegpt && domain->nsec3_is_exact) { 805 #else 806 nsec3_hash_and_find_cover(query->region, NULL, domain_dname(domain), 807 query->zone, &exact, &ds_parent_cover); 808 if (exact) { 809 /* use NSEC3 record from above the zone cut. */ 810 if (ds_parent_cover) { 811 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 812 ds_parent_cover); 813 } 814 } else if (!delegpt && domain->nsec3_cover) { 815 #endif 816 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 817 domain->nsec3_cover); 818 } else { 819 /* prove closest provable encloser */ 820 domain_type* par = domain->parent; 821 domain_type* prev_par = NULL; 822 assert(par); /* must be provable, thus there must be a parent */ 823 824 #ifdef FULL_PREHASH 825 while(!par->nsec3_is_exact) 826 #else 827 while(!par->nsec3_cover) 828 #endif 829 { 830 prev_par = par; 831 par = par->parent; 832 assert(par); /* parent zone apex must be provable, thus this ends */ 833 } 834 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 835 par->nsec3_cover); 836 /* we took several steps to go to the provable parent, so 837 the one below it has no exact nsec3, disprove it. 838 disprove is easy, it has a prehashed cover ptr. */ 839 if(prev_par) { 840 #ifdef FULL_PREHASH 841 assert(prev_par != domain && !prev_par->nsec3_is_exact); 842 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 843 prev_par->nsec3_cover); 844 #else 845 struct domain *prev_parent_cover = NULL; 846 nsec3_hash_and_find_cover(query->region, NULL, 847 domain_dname(prev_par), query->zone, 848 &exact, &prev_parent_cover); 849 if (prev_parent_cover) { 850 nsec3_add_rrset(query, answer, 851 AUTHORITY_SECTION, prev_parent_cover); 852 } 853 #endif 854 } 855 856 /* use NSEC3 record from above the zone cut. */ 857 /* add optout range from parent zone */ 858 /* note: no check of optout bit, resolver checks it */ 859 #ifdef FULL_PREHASH 860 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 861 domain->nsec3_ds_parent_cover); 862 #else 863 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 864 ds_parent_cover); 865 #endif 866 } 867 } 868 869 870 void 871 nsec3_answer_nodata(struct query *query, struct answer *answer, 872 struct domain *original) 873 { 874 if(!query->zone->nsec3_soa_rr) 875 return; 876 877 /* nodata when asking for secure delegation */ 878 if(query->qtype == TYPE_DS) 879 { 880 if(original == query->zone->apex) { 881 /* DS at zone apex, but server not authoritative for parent zone */ 882 /* so answer at the child zone level */ 883 #ifdef FULL_PREHASH 884 if(original->nsec3_is_exact) 885 #else 886 if(original->nsec3_cover) 887 #endif 888 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 889 original->nsec3_cover); 890 return; 891 } 892 /* query->zone must be the parent zone */ 893 nsec3_add_ds_proof(query, answer, original, 0); 894 } 895 /* the nodata is result from a wildcard match */ 896 else if (original==original->wildcard_child_closest_match 897 && label_is_wildcard(dname_name(domain_dname(original)))) { 898 #ifndef FULL_PREHASH 899 struct domain* original_cover; 900 int exact; 901 #endif 902 /* denial for wildcard is already there */ 903 904 /* add parent proof to have a closest encloser proof for wildcard parent */ 905 /* in other words: nsec3 matching closest encloser */ 906 #ifdef FULL_PREHASH 907 if(original->parent && original->parent->nsec3_is_exact) 908 #else 909 if(original->parent && original->parent->nsec3_cover) 910 #endif 911 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 912 original->parent->nsec3_cover); 913 914 /* proof for wildcard itself */ 915 /* in other words: nsec3 matching source of synthesis */ 916 #ifdef FULL_PREHASH 917 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 918 original->nsec3_cover); 919 #else 920 original_cover = original->nsec3_cover; 921 if (!original_cover) { /* not exact */ 922 nsec3_hash_and_find_cover(query->region, NULL, 923 domain_dname(original), query->zone, 924 &exact, &original_cover); 925 } 926 if (original_cover) { 927 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 928 original_cover); 929 } 930 #endif 931 932 } 933 else { /* add nsec3 to prove rrset does not exist */ 934 #ifdef FULL_PREHASH 935 if(original->nsec3_is_exact) 936 #else 937 if (original->nsec3_cover != NULL) 938 #endif 939 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 940 original->nsec3_cover); 941 } 942 } 943 944 void 945 nsec3_answer_delegation(struct query *query, struct answer *answer) 946 { 947 if(!query->zone->nsec3_soa_rr) 948 return; 949 nsec3_add_ds_proof(query, answer, query->delegation_domain, 1); 950 } 951 952 int 953 domain_has_only_NSEC3(struct domain* domain, struct zone* zone) 954 { 955 /* check for only NSEC3/RRSIG */ 956 rrset_type* rrset = domain->rrsets; 957 int nsec3_seen = 0; 958 while(rrset) 959 { 960 if(!zone || rrset->zone == zone) 961 { 962 if(rrset->rrs[0].type == TYPE_NSEC3) 963 nsec3_seen = 1; 964 else if(rrset->rrs[0].type != TYPE_RRSIG) 965 return 0; 966 } 967 rrset = rrset->next; 968 } 969 return nsec3_seen; 970 } 971 972 void 973 nsec3_answer_authoritative(struct domain** match, struct query *query, 974 struct answer *answer, struct domain* closest_encloser, 975 struct namedb* db, const dname_type* qname) 976 { 977 #ifndef FULL_PREHASH 978 struct domain *cover_domain = NULL; 979 int exact = 0; 980 #endif 981 982 if(!query->zone->nsec3_soa_rr) 983 return; 984 assert(match); 985 /* there is a match, this has 1 RRset, which is NSEC3, but qtype is not. */ 986 /* !is_existing: no RR types exist at the QNAME, nor at any descendant of QNAME */ 987 if(*match && !(*match)->is_existing && 988 #if 0 989 query->qtype != TYPE_NSEC3 && 990 #endif 991 domain_has_only_NSEC3(*match, query->zone)) 992 { 993 /* act as if the NSEC3 domain did not exist, name error */ 994 *match = 0; 995 /* all nsec3s are directly below the apex, that is closest encloser */ 996 #ifdef FULL_PREHASH 997 if(query->zone->apex->nsec3_is_exact) 998 #else 999 if(query->zone->apex->nsec3_cover) 1000 #endif 1001 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1002 query->zone->apex->nsec3_cover); 1003 1004 /* disprove the nsec3 record. */ 1005 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1006 closest_encloser->nsec3_cover); 1007 /* disprove a wildcard */ 1008 #ifdef FULL_PREHASH 1009 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1010 query->zone->apex->nsec3_wcard_child_cover); 1011 #else 1012 cover_domain = NULL; 1013 nsec3_hash_and_find_cover(query->region, db, 1014 domain_dname(closest_encloser), 1015 query->zone, &exact, &cover_domain); 1016 if (cover_domain) 1017 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1018 cover_domain); 1019 #endif 1020 if (domain_wildcard_child(query->zone->apex)) { 1021 /* wildcard exists below the domain */ 1022 /* wildcard and nsec3 domain clash. server failure. */ 1023 RCODE_SET(query->packet, RCODE_SERVFAIL); 1024 } 1025 return; 1026 } 1027 else if(*match && (*match)->is_existing && 1028 #if 0 1029 query->qtype != TYPE_NSEC3 && 1030 #endif 1031 domain_has_only_NSEC3(*match, query->zone)) 1032 { 1033 /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */ 1034 nsec3_answer_nodata(query, answer, *match); 1035 return; 1036 } 1037 if(!*match) { 1038 /* name error, domain does not exist */ 1039 nsec3_add_closest_encloser_proof(query, answer, 1040 closest_encloser, db, qname); 1041 #ifdef FULL_PREHASH 1042 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1043 closest_encloser->nsec3_wcard_child_cover); 1044 #else 1045 cover_domain = NULL; 1046 nsec3_hash_and_find_wild_cover(query->region, db, 1047 closest_encloser, query->zone, &exact, &cover_domain); 1048 if (cover_domain) 1049 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1050 cover_domain); 1051 #endif 1052 } 1053 } 1054 1055 #endif /* NSEC3 */ 1056