1 /* 2 * nsec3.c -- nsec3 handling. 3 * 4 * Copyright (c) 2001-2006, 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 14 #include "nsec3.h" 15 #include "iterated_hash.h" 16 #include "namedb.h" 17 #include "nsd.h" 18 #include "answer.h" 19 #include "options.h" 20 21 #define NSEC3_RDATA_BITMAP 5 22 23 /* compare nsec3 hashes in nsec3 tree */ 24 static int 25 cmp_hash_tree(const void* x, const void* y) 26 { 27 const domain_type* a = (const domain_type*)x; 28 const domain_type* b = (const domain_type*)y; 29 if(!a->nsec3) return (b->nsec3?-1:0); 30 if(!b->nsec3) return 1; 31 if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0); 32 if(!b->nsec3->hash_wc) return 1; 33 return memcmp(a->nsec3->hash_wc->hash.hash, 34 b->nsec3->hash_wc->hash.hash, NSEC3_HASH_LEN); 35 } 36 37 /* compare nsec3 hashes in nsec3 wc tree */ 38 static int 39 cmp_wchash_tree(const void* x, const void* y) 40 { 41 const domain_type* a = (const domain_type*)x; 42 const domain_type* b = (const domain_type*)y; 43 if(!a->nsec3) return (b->nsec3?-1:0); 44 if(!b->nsec3) return 1; 45 if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0); 46 if(!b->nsec3->hash_wc) return 1; 47 return memcmp(a->nsec3->hash_wc->wc.hash, 48 b->nsec3->hash_wc->wc.hash, NSEC3_HASH_LEN); 49 } 50 51 /* compare nsec3 hashes in nsec3 ds tree */ 52 static int 53 cmp_dshash_tree(const void* x, const void* y) 54 { 55 const domain_type* a = (const domain_type*)x; 56 const domain_type* b = (const domain_type*)y; 57 if(!a->nsec3) return (b->nsec3?-1:0); 58 if(!b->nsec3) return 1; 59 if(!a->nsec3->ds_parent_hash) return (b->nsec3->ds_parent_hash?-1:0); 60 if(!b->nsec3->ds_parent_hash) return 1; 61 return memcmp(a->nsec3->ds_parent_hash->hash, 62 b->nsec3->ds_parent_hash->hash, NSEC3_HASH_LEN); 63 } 64 65 /* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are 66 * stored in the domain name of the node */ 67 static int 68 cmp_nsec3_tree(const void* x, const void* y) 69 { 70 const domain_type* a = (const domain_type*)x; 71 const domain_type* b = (const domain_type*)y; 72 /* labelcount + 32long label */ 73 assert(dname_name(domain_dname_const(a))[0] == 32); 74 assert(dname_name(domain_dname_const(b))[0] == 32); 75 return memcmp(dname_name(domain_dname_const(a)), dname_name(domain_dname_const(b)), 33); 76 } 77 78 void nsec3_zone_trees_create(struct region* region, zone_type* zone) 79 { 80 if(!zone->nsec3tree) 81 zone->nsec3tree = rbtree_create(region, cmp_nsec3_tree); 82 if(!zone->hashtree) 83 zone->hashtree = rbtree_create(region, cmp_hash_tree); 84 if(!zone->wchashtree) 85 zone->wchashtree = rbtree_create(region, cmp_wchash_tree); 86 if(!zone->dshashtree) 87 zone->dshashtree = rbtree_create(region, cmp_dshash_tree); 88 } 89 90 static void 91 detect_nsec3_params(rr_type* nsec3_apex, 92 const unsigned char** salt, int* salt_len, int* iter) 93 { 94 assert(salt && salt_len && iter); 95 assert(nsec3_apex); 96 if(nsec3_apex->rdlength < 5) 97 return; 98 if(nsec3_apex->rdlength < 5 + (uint16_t)(nsec3_apex->rdata[4])) 99 return; 100 *salt_len = nsec3_apex->rdata[4]; 101 *salt = (unsigned char*)(nsec3_apex->rdata + 5); 102 *iter = read_uint16(nsec3_apex->rdata + 2); 103 } 104 105 const dname_type * 106 nsec3_b32_create(region_type* region, zone_type* zone, unsigned char* hash) 107 { 108 const dname_type* dname; 109 char b32[SHA_DIGEST_LENGTH*2+1]; 110 b32_ntop(hash, SHA_DIGEST_LENGTH, b32, sizeof(b32)); 111 dname=dname_parse(region, b32); 112 dname=dname_concatenate(region, dname, domain_dname(zone->apex)); 113 return dname; 114 } 115 116 void 117 nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store) 118 { 119 const unsigned char* nsec3_salt = NULL; 120 int nsec3_saltlength = 0; 121 int nsec3_iterations = 0; 122 123 detect_nsec3_params(zone->nsec3_param, &nsec3_salt, 124 &nsec3_saltlength, &nsec3_iterations); 125 assert(nsec3_iterations >= 0 && nsec3_iterations <= 65536); 126 iterated_hash((unsigned char*)store, nsec3_salt, nsec3_saltlength, 127 dname_name(dname), dname->name_size, nsec3_iterations); 128 } 129 130 #define STORE_HASH(x,y) memmove(domain->nsec3->x,y,NSEC3_HASH_LEN); domain->nsec3->have_##x =1; 131 132 /** find hash or create it and store it */ 133 static void 134 nsec3_lookup_hash_and_wc(region_type* region, zone_type* zone, 135 const dname_type* dname, domain_type* domain, region_type* tmpregion) 136 { 137 const dname_type* wcard; 138 if(domain->nsec3->hash_wc) { 139 return; 140 } 141 /* lookup failed; disk failure or so */ 142 domain->nsec3->hash_wc = (nsec3_hash_wc_node_type *) 143 region_alloc(region, sizeof(nsec3_hash_wc_node_type)); 144 domain->nsec3->hash_wc->hash.node.key = NULL; 145 domain->nsec3->hash_wc->wc.node.key = NULL; 146 nsec3_hash_and_store(zone, dname, domain->nsec3->hash_wc->hash.hash); 147 wcard = dname_parse(tmpregion, "*"); 148 wcard = dname_concatenate(tmpregion, wcard, dname); 149 nsec3_hash_and_store(zone, wcard, domain->nsec3->hash_wc->wc.hash); 150 } 151 152 static void 153 nsec3_lookup_hash_ds(region_type* region, zone_type* zone, 154 const dname_type* dname, domain_type* domain) 155 { 156 if(domain->nsec3->ds_parent_hash) { 157 return; 158 } 159 /* lookup failed; disk failure or so */ 160 domain->nsec3->ds_parent_hash = (nsec3_hash_node_type *) 161 region_alloc(region, sizeof(nsec3_hash_node_type)); 162 domain->nsec3->ds_parent_hash->node.key = NULL; 163 nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash); 164 } 165 166 static int 167 nsec3_has_soa(rr_type* rr) 168 { 169 size_t offset; 170 /* byte + byte + short + string + string + bitmap */ 171 if(rr->rdlength < 6) 172 return 0; 173 offset = 4; 174 if(rr->rdlength < offset+1 || 175 rr->rdlength < offset+1+rr->rdata[offset]) 176 return 0; 177 offset += 1 + rr->rdata[offset]; 178 if(rr->rdlength < offset+1 || 179 rr->rdlength < offset+1+rr->rdata[offset]) 180 return 0; 181 offset += 1 + rr->rdata[offset]; 182 if (rr->rdlength >= offset + 3 && /* has types in bitmap */ 183 rr->rdata[offset] == 0 && /* first window = 0, */ 184 /* [1]: bitmap length must be >= 1 */ 185 /* [2]: bit[6] = SOA, thus mask first bitmap octet with 0x02 */ 186 (rr->rdata[offset+2] & 0x02)) 187 return 1; 188 return 0; 189 } 190 191 static rr_type* 192 check_apex_soa(namedb_type* namedb, zone_type *zone, int nolog) 193 { 194 uint8_t h[NSEC3_HASH_LEN]; 195 domain_type* domain; 196 const dname_type* hashed_apex, *dname = domain_dname(zone->apex); 197 unsigned j; 198 rrset_type* nsec3_rrset; 199 region_type* tmpregion; 200 201 nsec3_hash_and_store(zone, dname, h); 202 tmpregion = region_create(xalloc, free); 203 hashed_apex = nsec3_b32_create(tmpregion, zone, h); 204 domain = domain_table_find(namedb->domains, hashed_apex); 205 if(!domain) { 206 if(!nolog) { 207 log_msg(LOG_ERR, "%s NSEC3PARAM entry has no hash(apex).", 208 domain_to_string(zone->apex)); 209 log_msg(LOG_ERR, "hash(apex)= %s", 210 dname_to_string(hashed_apex, NULL)); 211 } 212 region_destroy(tmpregion); 213 return NULL; 214 } 215 nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); 216 if(!nsec3_rrset) { 217 if(!nolog) { 218 log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) has no NSEC3 RRset.", 219 domain_to_string(zone->apex)); 220 log_msg(LOG_ERR, "hash(apex)= %s", 221 dname_to_string(hashed_apex, NULL)); 222 } 223 region_destroy(tmpregion); 224 return NULL; 225 } 226 for(j=0; j<nsec3_rrset->rr_count; j++) { 227 if(nsec3_has_soa(nsec3_rrset->rrs[j])) { 228 region_destroy(tmpregion); 229 return nsec3_rrset->rrs[j]; 230 } 231 } 232 if(!nolog) { 233 log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) NSEC3 has no SOA flag.", 234 domain_to_string(zone->apex)); 235 log_msg(LOG_ERR, "hash(apex)= %s", 236 dname_to_string(hashed_apex, NULL)); 237 } 238 region_destroy(tmpregion); 239 return NULL; 240 } 241 242 static void 243 nsec3param_to_str(struct rr* rr, char* str, size_t buflen) 244 { 245 size_t len; 246 if(rr->rdlength < 5 || rr->rdlength < 5 + (uint16_t)rr->rdata[4]) { 247 str[0]=0; 248 return; 249 } 250 len = snprintf(str, buflen, "%u %u %u ", 251 (unsigned)rr->rdata[0], (unsigned)rr->rdata[1], 252 (unsigned)read_uint16(rr->rdata+2)); 253 if(rr->rdata[4] == 0) { 254 if(buflen > len + 2) 255 str[len++] = '-'; 256 } else { 257 len += hex_ntop(rr->rdata+5, rr->rdata[4], str+len, buflen-len-1); 258 } 259 if(buflen > len + 1) { 260 str[len] = 0; 261 } else { 262 assert(buflen > 0); 263 str[buflen-1] = 0; 264 } 265 } 266 267 static struct rr* 268 db_find_nsec3param(struct namedb* db, struct zone* z, struct rr* avoid_rr, 269 int checkchain) 270 { 271 unsigned i; 272 rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM); 273 if(!rrset) /* no NSEC3PARAM in mem */ 274 return NULL; 275 /* find first nsec3param we can support (SHA1, no flags) */ 276 for(i=0; i<rrset->rr_count; i++) { 277 /* do not use the RR that is going to be deleted (in IXFR) */ 278 if(rrset->rrs[i] == avoid_rr) continue; 279 if(rrset->rrs[i]->rdlength < 5) continue; /* require salt field */ 280 if(rrset->rrs[i]->rdata[0] == NSEC3_SHA1_HASH && 281 rrset->rrs[i]->rdata[1] == 0) { 282 if(checkchain) { 283 z->nsec3_param = rrset->rrs[i]; 284 if(!check_apex_soa(db, z, 1)) { 285 char str[MAX_RDLENGTH*2+16]; 286 nsec3param_to_str(z->nsec3_param, 287 str, sizeof(str)); 288 VERBOSITY(1, (LOG_WARNING, "zone %s NSEC3PARAM %s has broken chain, ignoring", domain_to_string(z->apex), str)); 289 continue; /* don't use broken chain */ 290 } 291 } 292 if(2 <= verbosity) { 293 char str[MAX_RDLENGTH*2+16]; 294 nsec3param_to_str(rrset->rrs[i], str, 295 sizeof(str)); 296 VERBOSITY(2, (LOG_INFO, "rehash of zone %s with parameters %s", 297 domain_to_string(z->apex), str)); 298 } 299 return rrset->rrs[i]; 300 } 301 } 302 return NULL; 303 } 304 305 void 306 nsec3_find_zone_param(struct namedb* db, struct zone* zone, 307 struct rr* avoid_rr, int checkchain) 308 { 309 /* avoid using the rr that is going to be deleted, avoid_rr */ 310 zone->nsec3_param = db_find_nsec3param(db, zone, avoid_rr, checkchain); 311 } 312 313 /* check params ok for one RR */ 314 static int 315 nsec3_rdata_params_ok(const rr_type *prr, const rr_type* rr) 316 { 317 if(prr->rdlength > rr->rdlength) 318 return 0; /* The salt has to fit */ 319 if(prr->rdlength < 5) 320 return 0; /* Malformed */ 321 return prr->rdata[0] == rr->rdata[0] && 322 (memcmp(prr->rdata+2, rr->rdata+2, prr->rdlength-2) == 0); 323 } 324 325 int 326 nsec3_rr_uses_params(rr_type* rr, zone_type* zone) 327 { 328 if(!rr || rr->rdlength < 6) 329 return 0; 330 return nsec3_rdata_params_ok(zone->nsec3_param, rr); 331 } 332 333 int 334 nsec3_in_chain_count(domain_type* domain, zone_type* zone) 335 { 336 rrset_type* rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); 337 unsigned i; 338 int count = 0; 339 if(!rrset || !zone->nsec3_param) 340 return 0; /* no NSEC3s, none in the chain */ 341 for(i=0; i<rrset->rr_count; i++) { 342 if(nsec3_rr_uses_params(rrset->rrs[i], zone)) 343 count++; 344 } 345 return count; 346 } 347 348 struct domain* 349 nsec3_chain_find_prev(struct zone* zone, struct domain* domain) 350 { 351 if(domain->nsec3 && domain->nsec3->nsec3_node.key) { 352 /* see if there is a prev */ 353 rbnode_type* r = rbtree_previous(&domain->nsec3->nsec3_node); 354 if(r != RBTREE_NULL) { 355 /* found a previous, which is not the root-node in 356 * the prehash tree (and thus points to the tree) */ 357 return (domain_type*)r->key; 358 } 359 } 360 if(zone->nsec3_last && zone->nsec3_last != domain) 361 return zone->nsec3_last; 362 return NULL; 363 } 364 365 366 /** clear hash tree. Called from nsec3_clear_precompile() only. */ 367 static void 368 hash_tree_clear(rbtree_type* tree) 369 { 370 if(!tree) return; 371 372 /* Previously (before commit 4ca61188b3f7a0e077476875810d18a5d439871f 373 * and/or svn commit 4776) prehashes and corresponding rbtree nodes 374 * were part of struct nsec3_domain_data. Clearing the hash_tree would 375 * then mean setting the key value of the nodes to NULL to indicate 376 * absence of the prehash. 377 * But since prehash structs are separatly allocated, this is no longer 378 * necessary as currently the prehash structs are simply recycled and 379 * NULLed. 380 * 381 * rbnode_type* n; 382 * for(n=rbtree_first(tree); n!=RBTREE_NULL; n=rbtree_next(n)) { 383 * n->key = NULL; 384 * } 385 */ 386 tree->count = 0; 387 tree->root = RBTREE_NULL; 388 } 389 390 void 391 nsec3_clear_precompile(struct namedb* db, zone_type* zone) 392 { 393 domain_type* walk; 394 /* clear prehash items (there must not be items for other zones) */ 395 prehash_clear(db->domains); 396 /* clear trees */ 397 hash_tree_clear(zone->nsec3tree); 398 hash_tree_clear(zone->hashtree); 399 hash_tree_clear(zone->wchashtree); 400 hash_tree_clear(zone->dshashtree); 401 /* wipe hashes */ 402 403 /* wipe precompile */ 404 walk = zone->apex; 405 while(walk && domain_is_subdomain(walk, zone->apex)) { 406 if(walk->nsec3) { 407 if(nsec3_condition_hash(walk, zone)) { 408 walk->nsec3->nsec3_node.key = NULL; 409 walk->nsec3->nsec3_cover = NULL; 410 walk->nsec3->nsec3_wcard_child_cover = NULL; 411 walk->nsec3->nsec3_is_exact = 0; 412 if (walk->nsec3->hash_wc) { 413 region_recycle(db->domains->region, 414 walk->nsec3->hash_wc, 415 sizeof(nsec3_hash_wc_node_type)); 416 walk->nsec3->hash_wc = NULL; 417 } 418 } 419 if(nsec3_condition_dshash(walk, zone)) { 420 walk->nsec3->nsec3_ds_parent_cover = NULL; 421 walk->nsec3->nsec3_ds_parent_is_exact = 0; 422 if (walk->nsec3->ds_parent_hash) { 423 region_recycle(db->domains->region, 424 walk->nsec3->ds_parent_hash, 425 sizeof(nsec3_hash_node_type)); 426 walk->nsec3->ds_parent_hash = NULL; 427 } 428 } 429 } 430 walk = domain_next(walk); 431 } 432 zone->nsec3_last = NULL; 433 } 434 435 /* see if domain name is part of (existing names in) the nsec3 zone */ 436 int 437 nsec3_domain_part_of_zone(domain_type* d, zone_type* z) 438 { 439 while(d) { 440 if(d->is_apex) 441 return (z->apex == d); /* zonecut, if right zone*/ 442 d = d->parent; 443 } 444 return 0; 445 } 446 447 /* condition when a domain is precompiled */ 448 int 449 nsec3_condition_hash(domain_type* d, zone_type* z) 450 { 451 return d->is_existing && !domain_has_only_NSEC3(d, z) && 452 nsec3_domain_part_of_zone(d, z) && !domain_is_glue(d, z); 453 } 454 455 /* condition when a domain is ds precompiled */ 456 int 457 nsec3_condition_dshash(domain_type* d, zone_type* z) 458 { 459 return d->is_existing && !domain_has_only_NSEC3(d, z) && 460 (domain_find_rrset(d, z, TYPE_DS) || 461 domain_find_rrset(d, z, TYPE_NS)) && d != z->apex 462 && nsec3_domain_part_of_zone(d->parent, z); 463 } 464 465 zone_type* 466 nsec3_tree_zone(namedb_type* db, domain_type* d) 467 { 468 /* see nsec3_domain_part_of_zone; domains part of zone that has 469 * apex above them */ 470 /* this does not use the rrset->zone pointer because there may be 471 * no rrsets left at apex (no SOA), e.g. during IXFR */ 472 while(d) { 473 if(d->is_apex) { 474 /* we can try a SOA if its present (faster than tree)*/ 475 /* DNSKEY and NSEC3PARAM are also good indicators */ 476 rrset_type *rrset; 477 for (rrset = d->rrsets; rrset; rrset = rrset->next) 478 if (rrset_rrtype(rrset) == TYPE_SOA || 479 rrset_rrtype(rrset) == TYPE_DNSKEY || 480 rrset_rrtype(rrset) == TYPE_NSEC3PARAM) 481 return rrset->zone; 482 return namedb_find_zone(db, domain_dname(d)); 483 } 484 d = d->parent; 485 } 486 return NULL; 487 } 488 489 zone_type* 490 nsec3_tree_dszone(namedb_type* db, domain_type* d) 491 { 492 /* the DStree does not contain nodes with d==z->apex */ 493 if(d->is_apex) 494 d = d->parent; 495 while (d) { 496 if (d->is_apex) { 497 zone_type *zone = NULL; 498 for (rrset_type *rrset = d->rrsets; rrset; rrset = rrset->next) 499 if (rrset_rrtype(rrset) == TYPE_SOA || 500 rrset_rrtype(rrset) == TYPE_DNSKEY || 501 rrset_rrtype(rrset) == TYPE_NSEC3PARAM) 502 zone = rrset->zone; 503 if (!zone) 504 zone = namedb_find_zone(db, domain_dname(d)); 505 if (zone && zone->dshashtree) 506 return zone; 507 } 508 d = d->parent; 509 } 510 return NULL; 511 } 512 513 int 514 nsec3_find_cover(zone_type* zone, uint8_t* hash, size_t hashlen, 515 domain_type** result) 516 { 517 rbnode_type* r = NULL; 518 int exact; 519 domain_type d; 520 uint8_t n[48]; 521 522 /* nsec3tree is sorted by b32 encoded domain name of the NSEC3 */ 523 b32_ntop(hash, hashlen, (char*)(n+5), sizeof(n)-5); 524 #ifdef USE_RADIX_TREE 525 d.dname = (dname_type*)n; 526 #else 527 d.node.key = n; 528 #endif 529 n[0] = 34; /* name_size */ 530 n[1] = 2; /* label_count */ 531 n[2] = 0; /* label_offset[0] */ 532 n[3] = 0; /* label_offset[1] */ 533 n[4] = 32; /* label-size[0] */ 534 535 assert(result); 536 assert(zone->nsec3_param && zone->nsec3tree); 537 538 exact = rbtree_find_less_equal(zone->nsec3tree, &d, &r); 539 if(r) { 540 *result = (domain_type*)r->key; 541 } else { 542 *result = zone->nsec3_last; 543 } 544 return exact; 545 } 546 547 void 548 nsec3_precompile_domain(struct namedb* db, struct domain* domain, 549 struct zone* zone, region_type* tmpregion) 550 { 551 domain_type* result = 0; 552 int exact; 553 allocate_domain_nsec3(db->domains, domain); 554 555 /* hash it */ 556 nsec3_lookup_hash_and_wc(db->region, 557 zone, domain_dname(domain), domain, tmpregion); 558 559 /* add into tree */ 560 zone_add_domain_in_hash_tree(db->region, &zone->hashtree, 561 cmp_hash_tree, domain, &domain->nsec3->hash_wc->hash.node); 562 zone_add_domain_in_hash_tree(db->region, &zone->wchashtree, 563 cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node); 564 565 /* lookup in tree cover ptr (or exact) */ 566 exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->hash.hash, 567 sizeof(domain->nsec3->hash_wc->hash.hash), &result); 568 domain->nsec3->nsec3_cover = result; 569 if(exact) 570 domain->nsec3->nsec3_is_exact = 1; 571 else domain->nsec3->nsec3_is_exact = 0; 572 573 /* find cover for *.domain for wildcard denial */ 574 (void)nsec3_find_cover(zone, domain->nsec3->hash_wc->wc.hash, 575 sizeof(domain->nsec3->hash_wc->wc.hash), &result); 576 domain->nsec3->nsec3_wcard_child_cover = result; 577 } 578 579 void 580 nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain, 581 struct zone* zone) 582 { 583 domain_type* result = 0; 584 int exact; 585 allocate_domain_nsec3(db->domains, domain); 586 587 /* hash it : it could have different hash parameters then the 588 other hash for this domain name */ 589 nsec3_lookup_hash_ds(db->region, zone, domain_dname(domain), domain); 590 /* lookup in tree cover ptr (or exact) */ 591 exact = nsec3_find_cover(zone, domain->nsec3->ds_parent_hash->hash, 592 sizeof(domain->nsec3->ds_parent_hash->hash), &result); 593 domain->nsec3->nsec3_ds_parent_is_exact = exact != 0; 594 domain->nsec3->nsec3_ds_parent_cover = result; 595 /* add into tree */ 596 zone_add_domain_in_hash_tree(db->region, &zone->dshashtree, 597 cmp_dshash_tree, domain, &domain->nsec3->ds_parent_hash->node); 598 } 599 600 static void 601 parse_nsec3_name(const dname_type* dname, uint8_t* hash, size_t buflen) 602 { 603 /* first label must be the match, */ 604 size_t lablen = (buflen-1) * 8 / 5; 605 const uint8_t* wire = dname_name(dname); 606 assert(lablen == 32 && buflen == NSEC3_HASH_LEN+1); 607 /* labels of length 32 for SHA1, and must have space+1 for convert */ 608 if(wire[0] != lablen) { 609 /* not NSEC3 */ 610 memset(hash, 0, buflen); 611 return; 612 } 613 (void)b32_pton((char*)wire+1, hash, buflen); 614 } 615 616 void 617 nsec3_precompile_nsec3rr(namedb_type* db, struct domain* domain, 618 struct zone* zone) 619 { 620 allocate_domain_nsec3(db->domains, domain); 621 /* add into nsec3tree */ 622 zone_add_domain_in_hash_tree(db->region, &zone->nsec3tree, 623 cmp_nsec3_tree, domain, &domain->nsec3->nsec3_node); 624 /* fixup the last in the zone */ 625 if(rbtree_last(zone->nsec3tree)->key == domain) { 626 zone->nsec3_last = domain; 627 } 628 } 629 630 void 631 nsec3_precompile_newparam(namedb_type* db, zone_type* zone) 632 { 633 region_type* tmpregion = region_create(xalloc, free); 634 domain_type* walk; 635 time_t s = time(NULL); 636 unsigned long n = 0, c = 0; 637 638 /* add nsec3s of chain to nsec3tree */ 639 for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); 640 walk = domain_next(walk)) { 641 n++; 642 if(nsec3_in_chain_count(walk, zone) != 0) { 643 nsec3_precompile_nsec3rr(db, walk, zone); 644 } 645 } 646 /* hash and precompile zone */ 647 for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); 648 walk = domain_next(walk)) { 649 if(nsec3_condition_hash(walk, zone)) { 650 nsec3_precompile_domain(db, walk, zone, tmpregion); 651 region_free_all(tmpregion); 652 } 653 if(nsec3_condition_dshash(walk, zone)) 654 nsec3_precompile_domain_ds(db, walk, zone); 655 if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > s + ZONEC_PCT_TIME) { 656 s = time(NULL); 657 VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%", 658 zone->opts->name, 659 (n==0)?0:(int)(c*((unsigned long)100)/n))); 660 } 661 } 662 region_destroy(tmpregion); 663 } 664 665 void 666 prehash_zone_complete(struct namedb* db, struct zone* zone) 667 { 668 /* robust clear it */ 669 nsec3_clear_precompile(db, zone); 670 /* find zone settings */ 671 672 assert(db && zone); 673 nsec3_find_zone_param(db, zone, NULL, 1); 674 if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) { 675 zone->nsec3_param = NULL; 676 zone->nsec3_last = NULL; 677 return; 678 } 679 nsec3_zone_trees_create(db->region, zone); 680 nsec3_precompile_newparam(db, zone); 681 } 682 683 static void 684 init_lookup_key_hash_tree(domain_type* d, uint8_t* hash) 685 { memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN); } 686 687 static void 688 init_lookup_key_wc_tree(domain_type* d, uint8_t* hash) 689 { memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); } 690 691 static void 692 init_lookup_key_ds_tree(domain_type* d, uint8_t* hash) 693 { memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN); } 694 695 /* find first in the tree and true if the first to process it */ 696 static int 697 process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p, 698 void (*init)(domain_type*, uint8_t*)) 699 { 700 domain_type d; 701 struct nsec3_domain_data n; 702 nsec3_hash_wc_node_type hash_wc; 703 nsec3_hash_node_type ds_parent_hash; 704 705 if(!tree) { 706 *p = RBTREE_NULL; 707 return 0; 708 } 709 hash_wc.hash.node.key = NULL; 710 hash_wc.wc.node.key = NULL; 711 n.hash_wc = &hash_wc; 712 ds_parent_hash.node.key = NULL; 713 n.ds_parent_hash = &ds_parent_hash; 714 d.nsec3 = &n; 715 init(&d, hash); 716 if(rbtree_find_less_equal(tree, &d, p)) { 717 /* found an exact match */ 718 return 1; 719 } 720 if(!*p) /* before first, go from first */ 721 *p = rbtree_first(tree); 722 /* the inexact, smaller, match we found, does not itself need to 723 * be edited */ 724 else 725 *p = rbtree_next(*p); /* if this becomes NULL, nothing to do */ 726 return 0; 727 } 728 729 /* set end pointer if possible */ 730 static void 731 process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p, 732 void (*init)(domain_type*, uint8_t*)) 733 { 734 domain_type d; 735 struct nsec3_domain_data n; 736 nsec3_hash_wc_node_type hash_wc; 737 nsec3_hash_node_type ds_parent_hash; 738 739 if(!tree) { 740 *p = RBTREE_NULL; 741 return; 742 } 743 hash_wc.hash.node.key = NULL; 744 hash_wc.wc.node.key = NULL; 745 n.hash_wc = &hash_wc; 746 ds_parent_hash.node.key = NULL; 747 n.ds_parent_hash = &ds_parent_hash; 748 d.nsec3 = &n; 749 init(&d, hash); 750 if(rbtree_find_less_equal(tree, &d, p)) { 751 /* an exact match, fine, because this one does not get 752 * processed */ 753 return; 754 } 755 /* inexact element, but if NULL, until first element in tree */ 756 if(!*p) { 757 *p = rbtree_first(tree); 758 return; 759 } 760 /* inexact match, use next element, if possible, the smaller 761 * element is part of the range */ 762 *p = rbtree_next(*p); 763 /* if next returns null, we go until the end of the tree */ 764 } 765 766 /* prehash domains in hash range start to end */ 767 static void 768 process_range(zone_type* zone, domain_type* start, 769 domain_type* end, domain_type* nsec3) 770 { 771 /* start NULL means from first in tree */ 772 /* end NULL means to last in tree */ 773 rbnode_type *p = RBTREE_NULL, *pwc = RBTREE_NULL, *pds = RBTREE_NULL; 774 rbnode_type *p_end = RBTREE_NULL, *pwc_end = RBTREE_NULL, *pds_end = RBTREE_NULL; 775 /* because the nodes are on the prehashlist, the domain->nsec3 is 776 * already allocated, and we need not allocate it here */ 777 /* set start */ 778 if(start) { 779 uint8_t hash[NSEC3_HASH_LEN+1]; 780 parse_nsec3_name(domain_dname(start), hash, sizeof(hash)); 781 /* if exact match on first, set is_exact */ 782 if(process_first(zone->hashtree, hash, &p, init_lookup_key_hash_tree)) { 783 ((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3; 784 ((domain_type*)(p->key))->nsec3->nsec3_is_exact = 1; 785 p = rbtree_next(p); 786 } 787 (void)process_first(zone->wchashtree, hash, &pwc, init_lookup_key_wc_tree); 788 if(process_first(zone->dshashtree, hash, &pds, init_lookup_key_ds_tree)){ 789 ((domain_type*)(pds->key))->nsec3-> 790 nsec3_ds_parent_cover = nsec3; 791 ((domain_type*)(pds->key))->nsec3-> 792 nsec3_ds_parent_is_exact = 1; 793 pds = rbtree_next(pds); 794 } 795 } else { 796 if(zone->hashtree) 797 p = rbtree_first(zone->hashtree); 798 if(zone->wchashtree) 799 pwc = rbtree_first(zone->wchashtree); 800 if(zone->dshashtree) 801 pds = rbtree_first(zone->dshashtree); 802 } 803 /* set end */ 804 if(end) { 805 uint8_t hash[NSEC3_HASH_LEN+1]; 806 parse_nsec3_name(domain_dname(end), hash, sizeof(hash)); 807 process_end(zone->hashtree, hash, &p_end, init_lookup_key_hash_tree); 808 process_end(zone->wchashtree, hash, &pwc_end, init_lookup_key_wc_tree); 809 process_end(zone->dshashtree, hash, &pds_end, init_lookup_key_ds_tree); 810 } 811 812 /* precompile */ 813 while(p != RBTREE_NULL && p != p_end) { 814 ((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3; 815 ((domain_type*)(p->key))->nsec3->nsec3_is_exact = 0; 816 p = rbtree_next(p); 817 } 818 while(pwc != RBTREE_NULL && pwc != pwc_end) { 819 ((domain_type*)(pwc->key))->nsec3-> 820 nsec3_wcard_child_cover = nsec3; 821 pwc = rbtree_next(pwc); 822 } 823 while(pds != RBTREE_NULL && pds != pds_end) { 824 ((domain_type*)(pds->key))->nsec3-> 825 nsec3_ds_parent_cover = nsec3; 826 ((domain_type*)(pds->key))->nsec3-> 827 nsec3_ds_parent_is_exact = 0; 828 pds = rbtree_next(pds); 829 } 830 } 831 832 /* prehash a domain from the prehash list */ 833 static void 834 process_prehash_domain(domain_type* domain, zone_type* zone) 835 { 836 /* in the hashtree, wchashtree, dshashtree walk through to next NSEC3 837 * and set precompile pointers to point to this domain (or is_exact), 838 * the first domain can be is_exact. If it is the last NSEC3, also 839 * process the initial part (before the first) */ 840 rbnode_type* nx; 841 842 /* this domain is part of the prehash list and therefore the 843 * domain->nsec3 is allocated and need not be allocated here */ 844 assert(domain->nsec3 && domain->nsec3->nsec3_node.key); 845 nx = rbtree_next(&domain->nsec3->nsec3_node); 846 if(nx != RBTREE_NULL) { 847 /* process until next nsec3 */ 848 domain_type* end = (domain_type*)nx->key; 849 process_range(zone, domain, end, domain); 850 } else { 851 /* first is root, but then comes the first nsec3 */ 852 domain_type* first = (domain_type*)(rbtree_first( 853 zone->nsec3tree)->key); 854 /* last in zone */ 855 process_range(zone, domain, NULL, domain); 856 /* also process before first in zone */ 857 process_range(zone, NULL, first, domain); 858 } 859 } 860 861 void prehash_zone(struct namedb* db, struct zone* zone) 862 { 863 domain_type* d; 864 if(!zone->nsec3_param) { 865 prehash_clear(db->domains); 866 return; 867 } 868 if(!check_apex_soa(db, zone, 1)) { 869 /* the zone fails apex soa check, prehash complete may 870 * detect other valid chains */ 871 prehash_clear(db->domains); 872 prehash_zone_complete(db, zone); 873 return; 874 } 875 /* process prehash list */ 876 for(d = db->domains->prehash_list; d; d = d->nsec3->prehash_next) { 877 process_prehash_domain(d, zone); 878 } 879 /* clear prehash list */ 880 prehash_clear(db->domains); 881 882 if(!check_apex_soa(db, zone, 0)) { 883 zone->nsec3_param = NULL; 884 zone->nsec3_last = NULL; 885 } 886 } 887 888 /* add the NSEC3 rrset to the query answer at the given domain */ 889 static void 890 nsec3_add_rrset(struct query* query, struct answer* answer, 891 rr_section_type section, struct domain* domain) 892 { 893 if(domain) { 894 rrset_type* rrset = domain_find_rrset(domain, query->zone, TYPE_NSEC3); 895 if(rrset) 896 answer_add_rrset(answer, section, domain, rrset); 897 } 898 } 899 900 /* this routine does hashing at query-time. slow. */ 901 static void 902 nsec3_add_nonexist_proof(struct query* query, struct answer* answer, 903 struct domain* encloser, const dname_type* qname) 904 { 905 uint8_t hash[NSEC3_HASH_LEN]; 906 const dname_type* to_prove; 907 domain_type* cover=0; 908 assert(encloser); 909 /* if query=a.b.c.d encloser=c.d. then proof needed for b.c.d. */ 910 /* if query=a.b.c.d encloser=*.c.d. then proof needed for b.c.d. */ 911 to_prove = dname_partial_copy(query->region, qname, 912 dname_label_match_count(qname, domain_dname(encloser))+1); 913 /* generate proof that one label below closest encloser does not exist */ 914 nsec3_hash_and_store(query->zone, to_prove, hash); 915 if(nsec3_find_cover(query->zone, hash, sizeof(hash), &cover)) 916 { 917 /* exact match, hash collision */ 918 domain_type* walk; 919 char hashbuf[512]; 920 char reversebuf[512]; 921 (void)b32_ntop(hash, sizeof(hash), hashbuf, sizeof(hashbuf)); 922 snprintf(reversebuf, sizeof(reversebuf), "(no name in the zone hashes to this nsec3 record)"); 923 walk = query->zone->apex; 924 while(walk) { 925 if(walk->nsec3 && walk->nsec3->nsec3_cover == cover) { 926 snprintf(reversebuf, sizeof(reversebuf), 927 "%s %s", domain_to_string(walk), 928 walk->nsec3->nsec3_is_exact?"exact":"no_exact_hash_match"); 929 if(walk->nsec3->nsec3_is_exact) 930 break; 931 } 932 if(walk->nsec3 && walk->nsec3->nsec3_ds_parent_cover == cover) { 933 snprintf(reversebuf, sizeof(reversebuf), 934 "%s %s", domain_to_string(walk), 935 walk->nsec3->nsec3_ds_parent_is_exact?"exact":"no_exact_hash_match"); 936 if(walk->nsec3->nsec3_ds_parent_is_exact) 937 break; 938 } 939 walk = domain_next(walk); 940 } 941 942 943 /* the hashed name of the query corresponds to an existing name. */ 944 VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s hash=%s reverse=%s", 945 dname_to_string(to_prove, NULL), hashbuf, reversebuf)); 946 RCODE_SET(query->packet, RCODE_SERVFAIL); 947 /* RFC 8914 - Extended DNS Errors 948 * 4.21. Extended DNS Error Code 0 - Other */ 949 ASSIGN_EDE_CODE_AND_STRING_LITERAL(query->edns.ede, 950 EDE_OTHER, "NSEC3 hash collision"); 951 return; 952 } 953 else 954 { 955 /* cover proves the qname does not exist */ 956 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, cover); 957 } 958 } 959 960 static void 961 nsec3_add_closest_encloser_proof( 962 struct query* query, struct answer* answer, 963 struct domain* closest_encloser, const dname_type* qname) 964 { 965 if(!closest_encloser) 966 return; 967 /* prove that below closest encloser nothing exists */ 968 nsec3_add_nonexist_proof(query, answer, closest_encloser, qname); 969 /* proof that closest encloser exists */ 970 if(closest_encloser->nsec3 && closest_encloser->nsec3->nsec3_is_exact) 971 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 972 closest_encloser->nsec3->nsec3_cover); 973 } 974 975 void 976 nsec3_answer_wildcard(struct query *query, struct answer *answer, 977 struct domain *wildcard, const dname_type* qname) 978 { 979 if(!wildcard) 980 return; 981 if(!query->zone->nsec3_param) 982 return; 983 nsec3_add_nonexist_proof(query, answer, wildcard, qname); 984 } 985 986 static void 987 nsec3_add_ds_proof(struct query *query, struct answer *answer, 988 struct domain *domain, int delegpt) 989 { 990 /* assert we are above the zone cut */ 991 assert(domain != query->zone->apex); 992 if(domain->nsec3 && domain->nsec3->nsec3_ds_parent_is_exact) { 993 /* use NSEC3 record from above the zone cut. */ 994 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 995 domain->nsec3->nsec3_ds_parent_cover); 996 } else if (!delegpt && domain->nsec3 && domain->nsec3->nsec3_is_exact 997 && nsec3_domain_part_of_zone(domain->nsec3->nsec3_cover, 998 query->zone)) { 999 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1000 domain->nsec3->nsec3_cover); 1001 } else { 1002 /* prove closest provable encloser */ 1003 domain_type* par = domain->parent; 1004 domain_type* prev_par = 0; 1005 1006 while(par && (!par->nsec3 || !par->nsec3->nsec3_is_exact)) 1007 { 1008 prev_par = par; 1009 par = par->parent; 1010 } 1011 assert(par); /* parent zone apex must be provable, thus this ends */ 1012 if(!par->nsec3) return; 1013 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1014 par->nsec3->nsec3_cover); 1015 /* we took several steps to go to the provable parent, so 1016 the one below it has no exact nsec3, disprove it. 1017 disprove is easy, it has a prehashed cover ptr. */ 1018 if(prev_par && prev_par->nsec3) { 1019 assert(prev_par != domain && 1020 !prev_par->nsec3->nsec3_is_exact); 1021 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1022 prev_par->nsec3->nsec3_cover); 1023 } else { 1024 /* the exact case was handled earlier, so this is 1025 * with a closest-encloser proof, if in the part 1026 * before the else the closest encloser proof is done, 1027 * then we do not need to add a DS here because 1028 * the optout proof is already complete. If not, 1029 * we add the nsec3 here to complete the closest 1030 * encloser proof with a next closer */ 1031 /* add optout range from parent zone */ 1032 /* note: no check of optout bit, resolver checks it */ 1033 if(domain->nsec3) { 1034 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1035 domain->nsec3->nsec3_ds_parent_cover); 1036 } 1037 } 1038 } 1039 } 1040 1041 void 1042 nsec3_answer_nodata(struct query* query, struct answer* answer, 1043 struct domain* original) 1044 { 1045 if(!query->zone->nsec3_param) 1046 return; 1047 /* nodata when asking for secure delegation */ 1048 if(query->qtype == TYPE_DS) 1049 { 1050 if(original == query->zone->apex) { 1051 /* DS at zone apex, but server not authoritative for parent zone */ 1052 /* so answer at the child zone level */ 1053 if(original->nsec3 && original->nsec3->nsec3_is_exact) 1054 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1055 original->nsec3->nsec3_cover); 1056 return; 1057 } 1058 /* query->zone must be the parent zone */ 1059 nsec3_add_ds_proof(query, answer, original, 0); 1060 /* if the DS is from a wildcard match */ 1061 if (original==original->wildcard_child_closest_match 1062 && label_is_wildcard(dname_name(domain_dname(original)))) { 1063 /* denial for wildcard is already there */ 1064 /* add parent proof to have a closest encloser proof for wildcard parent */ 1065 /* in other words: nsec3 matching closest encloser */ 1066 if(original->parent && original->parent->nsec3 && 1067 original->parent->nsec3->nsec3_is_exact) 1068 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1069 original->parent->nsec3->nsec3_cover); 1070 } 1071 } 1072 /* the nodata is result from a wildcard match */ 1073 else if (original==original->wildcard_child_closest_match 1074 && label_is_wildcard(dname_name(domain_dname(original)))) { 1075 /* denial for wildcard is already there */ 1076 1077 /* add parent proof to have a closest encloser proof for wildcard parent */ 1078 /* in other words: nsec3 matching closest encloser */ 1079 if(original->parent && original->parent->nsec3 && 1080 original->parent->nsec3->nsec3_is_exact) 1081 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1082 original->parent->nsec3->nsec3_cover); 1083 /* proof for wildcard itself */ 1084 /* in other words: nsec3 matching source of synthesis */ 1085 if(original->nsec3) 1086 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1087 original->nsec3->nsec3_cover); 1088 } 1089 else { /* add nsec3 to prove rrset does not exist */ 1090 if(original->nsec3) { 1091 if(!original->nsec3->nsec3_is_exact) { 1092 /* go up to an existing parent */ 1093 while(original->parent && original->parent->nsec3 && !original->parent->nsec3->nsec3_is_exact) 1094 original = original->parent; 1095 } 1096 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1097 original->nsec3->nsec3_cover); 1098 if(!original->nsec3->nsec3_is_exact) { 1099 if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact) 1100 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1101 original->parent->nsec3->nsec3_cover); 1102 1103 } 1104 } 1105 } 1106 } 1107 1108 void 1109 nsec3_answer_delegation(struct query *query, struct answer *answer) 1110 { 1111 if(!query->zone->nsec3_param) 1112 return; 1113 nsec3_add_ds_proof(query, answer, query->delegation_domain, 1); 1114 } 1115 1116 int 1117 domain_has_only_NSEC3(struct domain* domain, struct zone* zone) 1118 { 1119 /* check for only NSEC3/RRSIG */ 1120 rrset_type* rrset = domain->rrsets; 1121 int nsec3_seen = 0; 1122 while(rrset) 1123 { 1124 if(!zone || rrset->zone == zone) 1125 { 1126 if(rrset->rrs[0]->type == TYPE_NSEC3) 1127 nsec3_seen = 1; 1128 else if(rrset->rrs[0]->type != TYPE_RRSIG) 1129 return 0; 1130 } 1131 rrset = rrset->next; 1132 } 1133 return nsec3_seen; 1134 } 1135 1136 void 1137 nsec3_answer_authoritative(struct domain** match, struct query *query, 1138 struct answer *answer, struct domain* closest_encloser, 1139 const dname_type* qname) 1140 { 1141 if(!query->zone->nsec3_param) 1142 return; 1143 assert(match); 1144 /* there is a match, this has 1 RRset, which is NSEC3, but qtype is not. */ 1145 /* !is_existing: no RR types exist at the QNAME, nor at any descendant of QNAME */ 1146 if(*match && !(*match)->is_existing && 1147 #if 0 1148 query->qtype != TYPE_NSEC3 && 1149 #endif 1150 domain_has_only_NSEC3(*match, query->zone)) 1151 { 1152 /* act as if the NSEC3 domain did not exist, name error */ 1153 *match = 0; 1154 /* all nsec3s are directly below the apex, that is closest encloser */ 1155 if(query->zone->apex->nsec3 && 1156 query->zone->apex->nsec3->nsec3_is_exact) 1157 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1158 query->zone->apex->nsec3->nsec3_cover); 1159 /* disprove the nsec3 record. */ 1160 if(closest_encloser->nsec3) 1161 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_cover); 1162 /* disprove a wildcard */ 1163 if(query->zone->apex->nsec3) 1164 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1165 query->zone->apex->nsec3->nsec3_wcard_child_cover); 1166 if (domain_wildcard_child(query->zone->apex)) { 1167 /* wildcard exists below the domain */ 1168 /* wildcard and nsec3 domain clash. server failure. */ 1169 RCODE_SET(query->packet, RCODE_SERVFAIL); 1170 /* RFC 8914 - Extended DNS Errors 1171 * 4.21. Extended DNS Error Code 0 - Other */ 1172 ASSIGN_EDE_CODE_AND_STRING_LITERAL(query->edns.ede, 1173 EDE_OTHER, "Wildcard and NSEC3 domain clash"); 1174 } 1175 return; 1176 } 1177 else if(*match && (*match)->is_existing && 1178 #if 0 1179 query->qtype != TYPE_NSEC3 && 1180 #endif 1181 (domain_has_only_NSEC3(*match, query->zone) || 1182 !domain_find_any_rrset(*match, query->zone))) 1183 { 1184 /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */ 1185 nsec3_answer_nodata(query, answer, *match); 1186 return; 1187 } 1188 if(!*match) { 1189 /* name error, domain does not exist */ 1190 nsec3_add_closest_encloser_proof(query, answer, closest_encloser, 1191 qname); 1192 if(closest_encloser->nsec3) 1193 nsec3_add_rrset(query, answer, AUTHORITY_SECTION, 1194 closest_encloser->nsec3->nsec3_wcard_child_cover); 1195 } 1196 } 1197 1198 #endif /* NSEC3 */ 1199