"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.6/nsec3.c" (6 Apr 2021, 37668 Bytes) of package /linux/misc/dns/nsd-4.3.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "nsec3.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.3.5_vs_4.3.6.

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