"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.6/difffile.c" (6 Apr 2021, 62339 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 "difffile.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  * difffile.c - DIFF file handling source code. Read and write diff files.
    3  *
    4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
    5  *
    6  * See LICENSE for the license.
    7  *
    8  */
    9 
   10 #include "config.h"
   11 #include <assert.h>
   12 #include <string.h>
   13 #include <unistd.h>
   14 #include <stdlib.h>
   15 #include <errno.h>
   16 #include "difffile.h"
   17 #include "xfrd-disk.h"
   18 #include "util.h"
   19 #include "packet.h"
   20 #include "rdata.h"
   21 #include "udb.h"
   22 #include "udbzone.h"
   23 #include "nsec3.h"
   24 #include "nsd.h"
   25 #include "rrl.h"
   26 
   27 static int
   28 write_64(FILE *out, uint64_t val)
   29 {
   30     return write_data(out, &val, sizeof(val));
   31 }
   32 
   33 static int
   34 write_32(FILE *out, uint32_t val)
   35 {
   36     val = htonl(val);
   37     return write_data(out, &val, sizeof(val));
   38 }
   39 
   40 static int
   41 write_8(FILE *out, uint8_t val)
   42 {
   43     return write_data(out, &val, sizeof(val));
   44 }
   45 
   46 static int
   47 write_str(FILE *out, const char* str)
   48 {
   49     uint32_t len = strlen(str);
   50     if(!write_32(out, len))
   51         return 0;
   52     return write_data(out, str, len);
   53 }
   54 
   55 void
   56 diff_write_packet(const char* zone, const char* pat, uint32_t old_serial,
   57     uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len,
   58     struct nsd* nsd, uint64_t filenumber)
   59 {
   60     FILE* df = xfrd_open_xfrfile(nsd, filenumber, seq_nr?"a":"w");
   61     if(!df) {
   62         log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
   63             zone, (long long)filenumber, strerror(errno));
   64         return;
   65     }
   66 
   67     /* if first part, first write the header */
   68     if(seq_nr == 0) {
   69         struct timeval tv;
   70         if (gettimeofday(&tv, NULL) != 0) {
   71             log_msg(LOG_ERR, "could not get timestamp for %s: %s",
   72                 zone, strerror(errno));
   73         }
   74         if(!write_32(df, DIFF_PART_XFRF) ||
   75             !write_8(df, 0) /* notcommitted(yet) */ ||
   76             !write_32(df, 0) /* numberofparts when done */ ||
   77             !write_64(df, (uint64_t) tv.tv_sec) ||
   78             !write_32(df, (uint32_t) tv.tv_usec) ||
   79             !write_32(df, old_serial) ||
   80             !write_32(df, new_serial) ||
   81             !write_64(df, (uint64_t) tv.tv_sec) ||
   82             !write_32(df, (uint32_t) tv.tv_usec) ||
   83             !write_str(df, zone) ||
   84             !write_str(df, pat)) {
   85             log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
   86                 zone, (long long)filenumber, strerror(errno));
   87             fclose(df);
   88             return;
   89         }
   90     }
   91 
   92     if(!write_32(df, DIFF_PART_XXFR) ||
   93         !write_32(df, len) ||
   94         !write_data(df, data, len) ||
   95         !write_32(df, len))
   96     {
   97         log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
   98             zone, (long long)filenumber, strerror(errno));
   99     }
  100     fclose(df);
  101 }
  102 
  103 void
  104 diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial,
  105     uint32_t num_parts, uint8_t commit, const char* log_str,
  106     struct nsd* nsd, uint64_t filenumber)
  107 {
  108     struct timeval tv;
  109     FILE* df;
  110 
  111     if (gettimeofday(&tv, NULL) != 0) {
  112         log_msg(LOG_ERR, "could not set timestamp for %s: %s",
  113             zone, strerror(errno));
  114     }
  115 
  116     /* overwrite the first part of the file with 'committed = 1', 
  117      * as well as the end_time and number of parts.
  118      * also write old_serial and new_serial, so that a bad file mixup
  119      * will result in unusable serial numbers. */
  120 
  121     df = xfrd_open_xfrfile(nsd, filenumber, "r+");
  122     if(!df) {
  123         log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
  124             zone, (long long)filenumber, strerror(errno));
  125         return;
  126     }
  127     if(!write_32(df, DIFF_PART_XFRF) ||
  128         !write_8(df, commit) /* committed */ ||
  129         !write_32(df, num_parts) ||
  130         !write_64(df, (uint64_t) tv.tv_sec) ||
  131         !write_32(df, (uint32_t) tv.tv_usec) ||
  132         !write_32(df, old_serial) ||
  133         !write_32(df, new_serial))
  134     {
  135         log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
  136             zone, (long long)filenumber, strerror(errno));
  137         fclose(df);
  138         return;
  139     }
  140 
  141     /* append the log_str to the end of the file */
  142     if(fseek(df, 0, SEEK_END) == -1) {
  143         log_msg(LOG_ERR, "could not fseek transfer %s file %lld: %s",
  144             zone, (long long)filenumber, strerror(errno));
  145         fclose(df);
  146         return;
  147     }
  148     if(!write_str(df, log_str)) {
  149         log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
  150             zone, (long long)filenumber, strerror(errno));
  151         fclose(df);
  152         return;
  153 
  154     }
  155     fflush(df);
  156     fclose(df);
  157 }
  158 
  159 int
  160 diff_read_64(FILE *in, uint64_t* result)
  161 {
  162     if (fread(result, sizeof(*result), 1, in) == 1) {
  163         return 1;
  164     } else {
  165         return 0;
  166     }
  167 }
  168 
  169 int
  170 diff_read_32(FILE *in, uint32_t* result)
  171 {
  172     if (fread(result, sizeof(*result), 1, in) == 1) {
  173         *result = ntohl(*result);
  174         return 1;
  175     } else {
  176         return 0;
  177     }
  178 }
  179 
  180 int
  181 diff_read_8(FILE *in, uint8_t* result)
  182 {
  183         if (fread(result, sizeof(*result), 1, in) == 1) {
  184                 return 1;
  185         } else {
  186                 return 0;
  187         }
  188 }
  189 
  190 int
  191 diff_read_str(FILE* in, char* buf, size_t len)
  192 {
  193     uint32_t disklen;
  194     if(!diff_read_32(in, &disklen))
  195         return 0;
  196     if(disklen >= len)
  197         return 0;
  198     if(fread(buf, disklen, 1, in) != 1)
  199         return 0;
  200     buf[disklen] = 0;
  201     return 1;
  202 }
  203 
  204 static void
  205 add_rdata_to_recyclebin(namedb_type* db, rr_type* rr)
  206 {
  207     /* add rdatas to recycle bin. */
  208     size_t i;
  209     for(i=0; i<rr->rdata_count; i++)
  210     {
  211         if(!rdata_atom_is_domain(rr->type, i))
  212             region_recycle(db->region, rr->rdatas[i].data,
  213                 rdata_atom_size(rr->rdatas[i])
  214                 + sizeof(uint16_t));
  215     }
  216     region_recycle(db->region, rr->rdatas,
  217         sizeof(rdata_atom_type)*rr->rdata_count);
  218 }
  219 
  220 /* this routine determines if below a domain there exist names with
  221  * data (is_existing) or no names below the domain have data.
  222  */
  223 static int
  224 has_data_below(domain_type* top)
  225 {
  226     domain_type* d = top;
  227     assert(d != NULL);
  228     /* in the canonical ordering subdomains are after this name */
  229     d = domain_next(d);
  230     while(d != NULL && domain_is_subdomain(d, top)) {
  231         if(d->is_existing)
  232             return 1;
  233         d = domain_next(d);
  234     }
  235     return 0;
  236 }
  237 
  238 /** check if domain with 0 rrsets has become empty (nonexist) */
  239 static domain_type*
  240 rrset_zero_nonexist_check(domain_type* domain, domain_type* ce)
  241 {
  242     /* is the node now an empty node (completely deleted) */
  243     if(domain->rrsets == 0) {
  244         /* if there is no data below it, it becomes non existing.
  245            also empty nonterminals above it become nonexisting */
  246         /* check for data below this node. */
  247         if(!has_data_below(domain)) {
  248             /* nonexist this domain and all parent empty nonterminals */
  249             domain_type* p = domain;
  250             while(p != NULL && p->rrsets == 0) {
  251                 if(p == ce || has_data_below(p))
  252                     return p;
  253                 p->is_existing = 0;
  254                 /* fixup wildcard child of parent */
  255                 if(p->parent &&
  256                     p->parent->wildcard_child_closest_match == p)
  257                     p->parent->wildcard_child_closest_match = domain_previous_existing_child(p);
  258                 p = p->parent;
  259             }
  260         }
  261     }
  262     return NULL;
  263 }
  264 
  265 /** remove rrset.  Adjusts zone params.  Does not remove domain */
  266 static void
  267 rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
  268 {
  269     int i;
  270     /* find previous */
  271     rrset_type** pp = &domain->rrsets;
  272     while(*pp && *pp != rrset) {
  273         pp = &( (*pp)->next );
  274     }
  275     if(!*pp) {
  276         /* rrset does not exist for domain */
  277         return;
  278     }
  279     *pp = rrset->next;
  280 
  281     DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s",
  282         domain_to_string(domain),
  283         rrtype_to_string(rrset_rrtype(rrset))));
  284 
  285     /* is this a SOA rrset ? */
  286     if(rrset->zone->soa_rrset == rrset) {
  287         rrset->zone->soa_rrset = 0;
  288     }
  289     if(rrset->zone->ns_rrset == rrset) {
  290         rrset->zone->ns_rrset = 0;
  291     }
  292     if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) {
  293         for (i = 0; i < rrset->rr_count; ++i) {
  294             if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY) {
  295                 rrset->zone->is_secure = 0;
  296                 break;
  297             }
  298         }
  299     }
  300     /* recycle the memory space of the rrset */
  301     for (i = 0; i < rrset->rr_count; ++i)
  302         add_rdata_to_recyclebin(db, &rrset->rrs[i]);
  303     region_recycle(db->region, rrset->rrs,
  304         sizeof(rr_type) * rrset->rr_count);
  305     rrset->rr_count = 0;
  306     region_recycle(db->region, rrset, sizeof(rrset_type));
  307 }
  308 
  309 static int
  310 rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type,
  311     int* rdnum, char** reason)
  312 {
  313     int k, start, end;
  314     start = 0;
  315     end = num;
  316     /**
  317      * SOA RDATA comparisons in XFR are more lenient,
  318      * only serial rdata is checked.
  319      **/
  320     if (type == TYPE_SOA) {
  321         start = 2;
  322         end = 3;
  323     }
  324     for(k = start; k < end; k++)
  325     {
  326         if(rdata_atom_is_domain(type, k)) {
  327             if(dname_compare(domain_dname(a[k].domain),
  328                 domain_dname(b[k].domain))!=0) {
  329                 *rdnum = k;
  330                 *reason = "dname data";
  331                 return 0;
  332             }
  333         } else if(rdata_atom_is_literal_domain(type, k)) {
  334             /* literal dname, but compare case insensitive */
  335             if(a[k].data[0] != b[k].data[0]) {
  336                 *rdnum = k;
  337                 *reason = "literal dname len";
  338                 return 0; /* uncompressed len must be equal*/
  339             }
  340             if(!dname_equal_nocase((uint8_t*)(a[k].data+1),
  341                 (uint8_t*)(b[k].data+1), a[k].data[0])) {
  342                 *rdnum = k;
  343                 *reason = "literal dname data";
  344                 return 0;
  345             }
  346         } else {
  347             /* check length */
  348             if(a[k].data[0] != b[k].data[0]) {
  349                 *rdnum = k;
  350                 *reason = "rdata len";
  351                 return 0;
  352             }
  353             /* check data */
  354             if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) {
  355                 *rdnum = k;
  356                 *reason = "rdata data";
  357                 return 0;
  358             }
  359         }
  360     }
  361     return 1;
  362 }
  363 
  364 static void
  365 debug_find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
  366     rdata_atom_type *rdatas, ssize_t rdata_num)
  367 {
  368     int i, rd;
  369     char* reason = "";
  370 
  371     for(i=0; i < rrset->rr_count; ++i) {
  372         if (rrset->rrs[i].type != type) {
  373             log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match "
  374                 "RR num %d type %s",
  375                 dname_to_string(domain_dname(rrset->rrs[i].owner),0),
  376                 rrtype_to_string(type), i,
  377                 rrtype_to_string(rrset->rrs[i].type));
  378         }
  379         if (rrset->rrs[i].klass != klass) {
  380             log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d "
  381                 "does not match RR num %d class %d",
  382                 dname_to_string(domain_dname(rrset->rrs[i].owner),0),
  383                 rrtype_to_string(type),
  384                 klass, i,
  385                 rrset->rrs[i].klass);
  386         }
  387         if (rrset->rrs[i].rdata_count != rdata_num) {
  388             log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u "
  389                 "does not match RR num %d rdlen %d",
  390                 dname_to_string(domain_dname(rrset->rrs[i].owner),0),
  391                 rrtype_to_string(type),
  392                 (unsigned) rdata_num, i,
  393                 (unsigned) rrset->rrs[i].rdata_count);
  394         }
  395         if (!rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
  396             &rd, &reason)) {
  397             log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element "
  398                 "%d differs from RR num %d rdata (%s)",
  399                 dname_to_string(domain_dname(rrset->rrs[i].owner),0),
  400                 rrtype_to_string(type),
  401                 rd, i, reason);
  402         }
  403     }
  404 }
  405 
  406 static int
  407 find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
  408     rdata_atom_type *rdatas, ssize_t rdata_num, int add)
  409 {
  410     int i, rd;
  411     char* reason;
  412 
  413     for(i=0; i < rrset->rr_count; ++i) {
  414         if(rrset->rrs[i].type == type &&
  415            rrset->rrs[i].klass == klass &&
  416            rrset->rrs[i].rdata_count == rdata_num &&
  417            rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
  418             &rd, &reason))
  419         {
  420             return i;
  421         }
  422     }
  423         /* this is odd. Log why rr cannot be found. */
  424     if (!add) {
  425         debug_find_rr_num(rrset, type, klass, rdatas, rdata_num);
  426     }
  427     return -1;
  428 }
  429 
  430 #ifdef NSEC3
  431 /* see if nsec3 deletion triggers need action */
  432 static void
  433 nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone,
  434     udb_ptr* udbz)
  435 {
  436     /* the RR has not actually been deleted yet, so we can inspect it */
  437     if(!zone->nsec3_param)
  438         return;
  439     /* see if the domain was an NSEC3-domain in the chain, but no longer */
  440     if(rr->type == TYPE_NSEC3 && rr->owner->nsec3 &&
  441         rr->owner->nsec3->nsec3_node.key &&
  442         nsec3_rr_uses_params(rr, zone) &&
  443         nsec3_in_chain_count(rr->owner, zone) <= 1) {
  444         domain_type* prev = nsec3_chain_find_prev(zone, rr->owner);
  445         /* remove from prehash because no longer an NSEC3 domain */
  446         if(domain_is_prehash(db->domains, rr->owner))
  447             prehash_del(db->domains, rr->owner);
  448         /* fixup the last in the zone */
  449         if(rr->owner == zone->nsec3_last)
  450             zone->nsec3_last = prev;
  451         /* unlink from the nsec3tree */
  452         zone_del_domain_in_hash_tree(zone->nsec3tree,
  453             &rr->owner->nsec3->nsec3_node);
  454         /* add previous NSEC3 to the prehash list */
  455         if(prev && prev != rr->owner)
  456             prehash_add(db->domains, prev);
  457         else    nsec3_clear_precompile(db, zone);
  458         /* this domain becomes ordinary data domain: done later */
  459     }
  460     /* see if the rr was NSEC3PARAM that we were using */
  461     else if(rr->type == TYPE_NSEC3PARAM && rr == zone->nsec3_param) {
  462         /* clear trees, wipe hashes, wipe precompile */
  463         nsec3_clear_precompile(db, zone);
  464         /* pick up new nsec3param (from udb, or avoid deleted rr) */
  465         nsec3_find_zone_param(db, zone, udbz, rr, 0);
  466         /* if no more NSEC3, done */
  467         if(!zone->nsec3_param)
  468             return;
  469         nsec3_precompile_newparam(db, zone);
  470     }
  471 }
  472 
  473 /* see if nsec3 prehash can be removed with new rrset content */
  474 static void
  475 nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  476 {
  477     /* deletion of rrset already done, we can check if conditions apply */
  478     /* see if the domain is no longer precompiled */
  479     /* it has a hash_node, but no longer fulfills conditions */
  480     if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 &&
  481         domain->nsec3->hash_wc &&
  482         domain->nsec3->hash_wc->hash.node.key &&
  483         !nsec3_condition_hash(domain, zone)) {
  484         /* remove precompile */
  485         domain->nsec3->nsec3_cover = NULL;
  486         domain->nsec3->nsec3_wcard_child_cover = NULL;
  487         domain->nsec3->nsec3_is_exact = 0;
  488         /* remove it from the hash tree */
  489         zone_del_domain_in_hash_tree(zone->hashtree,
  490             &domain->nsec3->hash_wc->hash.node);
  491         zone_del_domain_in_hash_tree(zone->wchashtree,
  492             &domain->nsec3->hash_wc->wc.node);
  493     }
  494     if(domain != zone->apex && domain->nsec3 &&
  495         domain->nsec3->ds_parent_hash &&
  496         domain->nsec3->ds_parent_hash->node.key &&
  497         (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) &&
  498         !nsec3_condition_dshash(domain, zone)) {
  499         /* remove precompile */
  500         domain->nsec3->nsec3_ds_parent_cover = NULL;
  501         domain->nsec3->nsec3_ds_parent_is_exact = 0;
  502         /* remove it from the hash tree */
  503         zone_del_domain_in_hash_tree(zone->dshashtree,
  504             &domain->nsec3->ds_parent_hash->node);
  505     }
  506 }
  507 
  508 /* see if domain needs to get precompiled info */
  509 static void
  510 nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain,
  511     zone_type* zone)
  512 {
  513     if(!zone->nsec3_param)
  514         return;
  515     if((!domain->nsec3 || !domain->nsec3->hash_wc
  516                        || !domain->nsec3->hash_wc->hash.node.key)
  517         && nsec3_condition_hash(domain, zone)) {
  518         region_type* tmpregion = region_create(xalloc, free);
  519         nsec3_precompile_domain(db, domain, zone, tmpregion);
  520         region_destroy(tmpregion);
  521     }
  522     if((!domain->nsec3 || !domain->nsec3->ds_parent_hash
  523                        || !domain->nsec3->ds_parent_hash->node.key)
  524         && nsec3_condition_dshash(domain, zone)) {
  525         nsec3_precompile_domain_ds(db, domain, zone);
  526     }
  527 }
  528 
  529 /* see if nsec3 rrset-deletion triggers need action */
  530 static void
  531 nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain,
  532     zone_type* zone, uint16_t type)
  533 {
  534     if(!zone->nsec3_param)
  535         return;
  536     nsec3_rrsets_changed_remove_prehash(domain, zone);
  537     /* for type nsec3, or a delegation, the domain may have become a
  538      * 'normal' domain with its remaining data now */
  539     if(type == TYPE_NSEC3 || type == TYPE_NS || type == TYPE_DS)
  540         nsec3_rrsets_changed_add_prehash(db, domain, zone);
  541     /* for type DNAME or a delegation, obscured data may be revealed */
  542     if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
  543         /* walk over subdomains and check them each */
  544         domain_type *d;
  545         for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
  546             d=domain_next(d)) {
  547             nsec3_rrsets_changed_add_prehash(db, d, zone);
  548         }
  549     }
  550 }
  551 
  552 /* see if nsec3 addition triggers need action */
  553 static void
  554 nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone,
  555     udb_ptr* udbz)
  556 {
  557     /* the RR has been added in full, also to UDB (and thus NSEC3PARAM 
  558      * in the udb has been adjusted) */
  559     if(zone->nsec3_param && rr->type == TYPE_NSEC3 &&
  560         (!rr->owner->nsec3 || !rr->owner->nsec3->nsec3_node.key)
  561         && nsec3_rr_uses_params(rr, zone)) {
  562         /* added NSEC3 into the chain */
  563         nsec3_precompile_nsec3rr(db, rr->owner, zone);
  564         /* the domain has become an NSEC3-domain, if it was precompiled
  565          * previously, remove that, neatly done in routine above */
  566         nsec3_rrsets_changed_remove_prehash(rr->owner, zone);
  567         /* set this NSEC3 to prehash */
  568         prehash_add(db->domains, rr->owner);
  569     } else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) {
  570         /* see if this means NSEC3 chain can be used */
  571         nsec3_find_zone_param(db, zone, udbz, NULL, 0);
  572         if(!zone->nsec3_param)
  573             return;
  574         nsec3_zone_trees_create(db->region, zone);
  575         nsec3_precompile_newparam(db, zone);
  576     }
  577 }
  578 
  579 /* see if nsec3 rrset-addition triggers need action */
  580 static void
  581 nsec3_add_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone,
  582     uint16_t type)
  583 {
  584     /* the rrset has been added so we can inspect it */
  585     if(!zone->nsec3_param)
  586         return;
  587     /* because the rrset is added we can check conditions easily.
  588      * check if domain needs to become precompiled now */
  589     nsec3_rrsets_changed_add_prehash(db, domain, zone);
  590     /* if a delegation, it changes from normal name to unhashed referral */
  591     if(type == TYPE_NS || type == TYPE_DS) {
  592         nsec3_rrsets_changed_remove_prehash(domain, zone);
  593     }
  594     /* if delegation or DNAME added, then some RRs may get obscured */
  595     if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
  596         /* walk over subdomains and check them each */
  597         domain_type *d;
  598         for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
  599             d=domain_next(d)) {
  600             nsec3_rrsets_changed_remove_prehash(d, zone);
  601         }
  602     }
  603 }
  604 #endif /* NSEC3 */
  605 
  606 /* fixup usage lower for domain names in the rdata */
  607 static void
  608 rr_lower_usage(namedb_type* db, rr_type* rr)
  609 {
  610     unsigned i;
  611     for(i=0; i<rr->rdata_count; i++) {
  612         if(rdata_atom_is_domain(rr->type, i)) {
  613             assert(rdata_atom_domain(rr->rdatas[i])->usage > 0);
  614             rdata_atom_domain(rr->rdatas[i])->usage --;
  615             if(rdata_atom_domain(rr->rdatas[i])->usage == 0)
  616                 domain_table_deldomain(db,
  617                     rdata_atom_domain(rr->rdatas[i]));
  618         }
  619     }
  620 }
  621 
  622 static void
  623 rrset_lower_usage(namedb_type* db, rrset_type* rrset)
  624 {
  625     unsigned i;
  626     for(i=0; i<rrset->rr_count; i++)
  627         rr_lower_usage(db, &rrset->rrs[i]);
  628 }
  629 
  630 int
  631 delete_RR(namedb_type* db, const dname_type* dname,
  632     uint16_t type, uint16_t klass,
  633     buffer_type* packet, size_t rdatalen, zone_type *zone,
  634     region_type* temp_region, udb_ptr* udbz, int* softfail)
  635 {
  636     domain_type *domain;
  637     rrset_type *rrset;
  638     domain = domain_table_find(db->domains, dname);
  639     if(!domain) {
  640         log_msg(LOG_WARNING, "diff: domain %s does not exist",
  641             dname_to_string(dname,0));
  642         buffer_skip(packet, rdatalen);
  643         *softfail = 1;
  644         return 1; /* not fatal error */
  645     }
  646     rrset = domain_find_rrset(domain, zone, type);
  647     if(!rrset) {
  648         log_msg(LOG_WARNING, "diff: rrset %s does not exist",
  649             dname_to_string(dname,0));
  650         buffer_skip(packet, rdatalen);
  651         *softfail = 1;
  652         return 1; /* not fatal error */
  653     } else {
  654         /* find the RR in the rrset */
  655         domain_table_type *temptable;
  656         rdata_atom_type *rdatas;
  657         ssize_t rdata_num;
  658         int rrnum;
  659         temptable = domain_table_create(temp_region);
  660         /* This will ensure that the dnames in rdata are
  661          * normalized, conform RFC 4035, section 6.2
  662          */
  663         rdata_num = rdata_wireformat_to_rdata_atoms(
  664             temp_region, temptable, type, rdatalen, packet, &rdatas);
  665         if(rdata_num == -1) {
  666             log_msg(LOG_ERR, "diff: bad rdata for %s",
  667                 dname_to_string(dname,0));
  668             return 0;
  669         }
  670         rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0);
  671         if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex
  672             && rrset->rr_count != 0)
  673             rrnum = 0; /* replace existing SOA if no match */
  674         if(rrnum == -1) {
  675             log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist",
  676                 dname_to_string(dname,0), rrtype_to_string(type));
  677             *softfail = 1;
  678             return 1; /* not fatal error */
  679         }
  680         /* delete the normalized RR from the udb */
  681         if(db->udb)
  682             udb_del_rr(db->udb, udbz, &rrset->rrs[rrnum]);
  683 #ifdef NSEC3
  684         /* process triggers for RR deletions */
  685         nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone, udbz);
  686 #endif
  687         /* lower usage (possibly deleting other domains, and thus
  688          * invalidating the current RR's domain pointers) */
  689         rr_lower_usage(db, &rrset->rrs[rrnum]);
  690         if(rrset->rr_count == 1) {
  691             /* delete entire rrset */
  692             rrset_delete(db, domain, rrset);
  693             /* check if domain is now nonexisting (or parents) */
  694             rrset_zero_nonexist_check(domain, NULL);
  695 #ifdef NSEC3
  696             /* cleanup nsec3 */
  697             nsec3_delete_rrset_trigger(db, domain, zone, type);
  698 #endif
  699             /* see if the domain can be deleted (and inspect parents) */
  700             domain_table_deldomain(db, domain);
  701         } else {
  702             /* swap out the bad RR and decrease the count */
  703             rr_type* rrs_orig = rrset->rrs;
  704             add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]);
  705             if(rrnum < rrset->rr_count-1)
  706                 rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1];
  707             memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type));
  708             /* realloc the rrs array one smaller */
  709             rrset->rrs = region_alloc_array_init(db->region, rrs_orig,
  710                 (rrset->rr_count-1), sizeof(rr_type));
  711             if(!rrset->rrs) {
  712                 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
  713                 exit(1);
  714             }
  715             region_recycle(db->region, rrs_orig,
  716                 sizeof(rr_type) * rrset->rr_count);
  717 #ifdef NSEC3
  718             if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
  719                 /* fixup nsec3_param pointer to same RR */
  720                 assert(zone->nsec3_param >= rrs_orig &&
  721                     zone->nsec3_param <=
  722                     rrs_orig+rrset->rr_count);
  723                 /* last moved to rrnum, others at same index*/
  724                 if(zone->nsec3_param == &rrs_orig[
  725                     rrset->rr_count-1])
  726                     zone->nsec3_param = &rrset->rrs[rrnum];
  727                 else
  728                     zone->nsec3_param =
  729                         (void*)zone->nsec3_param
  730                         -(void*)rrs_orig +
  731                         (void*)rrset->rrs;
  732             }
  733 #endif /* NSEC3 */
  734             rrset->rr_count --;
  735 #ifdef NSEC3
  736             /* for type nsec3, the domain may have become a
  737              * 'normal' domain with its remaining data now */
  738             if(type == TYPE_NSEC3)
  739                 nsec3_rrsets_changed_add_prehash(db, domain,
  740                     zone);
  741 #endif /* NSEC3 */
  742         }
  743     }
  744     return 1;
  745 }
  746 
  747 int
  748 add_RR(namedb_type* db, const dname_type* dname,
  749     uint16_t type, uint16_t klass, uint32_t ttl,
  750     buffer_type* packet, size_t rdatalen, zone_type *zone, udb_ptr* udbz,
  751     int* softfail)
  752 {
  753     domain_type* domain;
  754     rrset_type* rrset;
  755     rdata_atom_type *rdatas;
  756     rr_type *rrs_old;
  757     ssize_t rdata_num;
  758     int rrnum;
  759 #ifdef NSEC3
  760     int rrset_added = 0;
  761 #endif
  762     domain = domain_table_find(db->domains, dname);
  763     if(!domain) {
  764         /* create the domain */
  765         domain = domain_table_insert(db->domains, dname);
  766     }
  767     rrset = domain_find_rrset(domain, zone, type);
  768     if(!rrset) {
  769         /* create the rrset */
  770         rrset = region_alloc(db->region, sizeof(rrset_type));
  771         if(!rrset) {
  772             log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
  773             exit(1);
  774         }
  775         rrset->zone = zone;
  776         rrset->rrs = 0;
  777         rrset->rr_count = 0;
  778         domain_add_rrset(domain, rrset);
  779 #ifdef NSEC3
  780         rrset_added = 1;
  781 #endif
  782     }
  783 
  784     /* dnames in rdata are normalized, conform RFC 4035,
  785      * Section 6.2
  786      */
  787     rdata_num = rdata_wireformat_to_rdata_atoms(
  788         db->region, db->domains, type, rdatalen, packet, &rdatas);
  789     if(rdata_num == -1) {
  790         log_msg(LOG_ERR, "diff: bad rdata for %s",
  791             dname_to_string(dname,0));
  792         return 0;
  793     }
  794     rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 1);
  795     if(rrnum != -1) {
  796         DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists",
  797             dname_to_string(dname,0), rrtype_to_string(type)));
  798         /* ignore already existing RR: lenient accepting of messages */
  799         *softfail = 1;
  800         return 1;
  801     }
  802     if(rrset->rr_count == 65535) {
  803         log_msg(LOG_ERR, "diff: too many RRs at %s",
  804             dname_to_string(dname,0));
  805         return 0;
  806     }
  807 
  808     /* re-alloc the rrs and add the new */
  809     rrs_old = rrset->rrs;
  810     rrset->rrs = region_alloc_array(db->region,
  811         (rrset->rr_count+1), sizeof(rr_type));
  812     if(!rrset->rrs) {
  813         log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
  814         exit(1);
  815     }
  816     if(rrs_old)
  817         memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type));
  818     region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count);
  819     rrset->rr_count ++;
  820 
  821     rrset->rrs[rrset->rr_count - 1].owner = domain;
  822     rrset->rrs[rrset->rr_count - 1].rdatas = rdatas;
  823     rrset->rrs[rrset->rr_count - 1].ttl = ttl;
  824     rrset->rrs[rrset->rr_count - 1].type = type;
  825     rrset->rrs[rrset->rr_count - 1].klass = klass;
  826     rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num;
  827 
  828     /* see if it is a SOA */
  829     if(domain == zone->apex) {
  830         apex_rrset_checks(db, rrset, domain);
  831 #ifdef NSEC3
  832         if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
  833             /* the pointer just changed, fix it up to point
  834              * to the same record */
  835             assert(zone->nsec3_param >= rrs_old &&
  836                 zone->nsec3_param < rrs_old+rrset->rr_count);
  837             /* in this order to make sure no overflow/underflow*/
  838             zone->nsec3_param = (void*)zone->nsec3_param - 
  839                 (void*)rrs_old + (void*)rrset->rrs;
  840         }
  841 #endif /* NSEC3 */
  842     }
  843 
  844     /* write the just-normalized RR to the udb */
  845     if(db->udb) {
  846         if(!udb_write_rr(db->udb, udbz, &rrset->rrs[rrset->rr_count - 1])) {
  847             log_msg(LOG_ERR, "could not add RR to nsd.db, disk-space?");
  848             return 0;
  849         }
  850     }
  851 #ifdef NSEC3
  852     if(rrset_added) {
  853         domain_type* p = domain->parent;
  854         nsec3_add_rrset_trigger(db, domain, zone, type);
  855         /* go up and process (possibly created) empty nonterminals, 
  856          * until we hit the apex or root */
  857         while(p && p->rrsets == NULL && !p->is_apex) {
  858             nsec3_rrsets_changed_add_prehash(db, p, zone);
  859             p = p->parent;
  860         }
  861     }
  862     nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone, udbz);
  863 #endif /* NSEC3 */
  864     return 1;
  865 }
  866 
  867 static zone_type*
  868 find_or_create_zone(namedb_type* db, const dname_type* zone_name,
  869     struct nsd_options* opt, const char* zstr, const char* patname)
  870 {
  871     zone_type* zone;
  872     struct zone_options* zopt;
  873     zone = namedb_find_zone(db, zone_name);
  874     if(zone) {
  875         return zone;
  876     }
  877     zopt = zone_options_find(opt, zone_name);
  878     if(!zopt) {
  879         /* if _implicit_ then insert as _part_of_config */
  880         if(strncmp(patname, PATTERN_IMPLICIT_MARKER,
  881             strlen(PATTERN_IMPLICIT_MARKER)) == 0) {
  882             zopt = zone_options_create(opt->region);
  883             if(!zopt) return 0;
  884             zopt->part_of_config = 1;
  885             zopt->name = region_strdup(opt->region, zstr);
  886             zopt->pattern = pattern_options_find(opt, patname);
  887             if(!zopt->name || !zopt->pattern) return 0;
  888             if(!nsd_options_insert_zone(opt, zopt)) {
  889                 log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
  890                     "pattern %s", zstr, patname);
  891             }
  892         } else {
  893             /* create zone : presumably already added to zonelist
  894              * by xfrd, who wrote the AXFR or IXFR to disk, so we only
  895              * need to add it to our config.
  896              * This process does not need linesize and offset zonelist */
  897             zopt = zone_list_zone_insert(opt, zstr, patname, 0, 0);
  898             if(!zopt)
  899                 return 0;
  900         }
  901     }
  902     zone = namedb_zone_create(db, zone_name, zopt);
  903     return zone;
  904 }
  905 
  906 void
  907 delete_zone_rrs(namedb_type* db, zone_type* zone)
  908 {
  909     rrset_type *rrset;
  910     domain_type *domain = zone->apex, *next;
  911     int nonexist_check = 0;
  912     /* go through entire tree below the zone apex (incl subzones) */
  913     while(domain && domain_is_subdomain(domain, zone->apex))
  914     {
  915         DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s",
  916             domain_to_string(domain)));
  917         /* delete all rrsets of the zone */
  918         while((rrset = domain_find_any_rrset(domain, zone))) {
  919             /* lower usage can delete other domains */
  920             rrset_lower_usage(db, rrset);
  921             /* rrset del does not delete our domain(yet) */
  922             rrset_delete(db, domain, rrset);
  923             /* no rrset_zero_nonexist_check, do that later */
  924             if(domain->rrsets == 0)
  925                 nonexist_check = 1;
  926         }
  927         /* the delete upcoming could delete parents, but nothing next
  928          * or after the domain so store next ptr */
  929         next = domain_next(domain);
  930         /* see if the domain can be deleted (and inspect parents) */
  931         domain_table_deldomain(db, domain);
  932         domain = next;
  933     }
  934 
  935     /* check if data deletions have created nonexisting domain entries,
  936      * but after deleting domains so the checks are faster */
  937     if(nonexist_check) {
  938         domain_type* ce = NULL; /* for speeding up has_data_below */
  939         DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check"));
  940         domain = zone->apex;
  941         while(domain && domain_is_subdomain(domain, zone->apex))
  942         {
  943             /* the interesting domains should be existing==1
  944              * and rrsets==0, speeding up out processing of
  945              * sub-zones, since we only spuriously check empty
  946              * nonterminals */
  947             if(domain->is_existing)
  948                 ce = rrset_zero_nonexist_check(domain, ce);
  949             domain = domain_next(domain);
  950         }
  951     }
  952 
  953     DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes",
  954         (unsigned long) region_get_recycle_size(db->region)));
  955 #ifndef NDEBUG
  956     if(nsd_debug_level >= 2)
  957         region_log_stats(db->region);
  958 #endif
  959 
  960     assert(zone->soa_rrset == 0);
  961     /* keep zone->soa_nx_rrset alloced: it is reused */
  962     assert(zone->ns_rrset == 0);
  963     assert(zone->is_secure == 0);
  964 }
  965 
  966 /* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */
  967 static int
  968 apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
  969     struct nsd_options* opt, uint32_t seq_nr, uint32_t seq_total,
  970     int* is_axfr, int* delete_mode, int* rr_count,
  971     udb_ptr* udbz, struct zone** zone_res, const char* patname, int* bytes,
  972     int* softfail)
  973 {
  974     uint32_t msglen, checklen, pkttype;
  975     int qcount, ancount, counter;
  976     buffer_type* packet;
  977     region_type* region;
  978     int i;
  979     uint16_t rrlen;
  980     const dname_type *dname_zone, *dname;
  981     zone_type* zone_db;
  982 
  983     /* note that errors could not really happen due to format of the
  984      * packet since xfrd has checked all dnames and RRs before commit,
  985      * this is why the errors are fatal (exit process), it must be
  986      * something internal or a bad disk or something. */
  987 
  988     /* read ixfr packet RRs and apply to in memory db */
  989     if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_XXFR) {
  990         log_msg(LOG_ERR, "could not read type or wrong type");
  991         return 0;
  992     }
  993 
  994     if(!diff_read_32(in, &msglen)) {
  995         log_msg(LOG_ERR, "could not read len");
  996         return 0;
  997     }
  998 
  999     if(msglen < QHEADERSZ) {
 1000         log_msg(LOG_ERR, "msg too short");
 1001         return 0;
 1002     }
 1003 
 1004     region = region_create(xalloc, free);
 1005     if(!region) {
 1006         log_msg(LOG_ERR, "out of memory");
 1007         return 0;
 1008     }
 1009     packet = buffer_create(region, QIOBUFSZ);
 1010     if(msglen > QIOBUFSZ) {
 1011         log_msg(LOG_ERR, "msg too long");
 1012         region_destroy(region);
 1013         return 0;
 1014     }
 1015     buffer_clear(packet);
 1016     if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
 1017         log_msg(LOG_ERR, "short fread: %s", strerror(errno));
 1018         region_destroy(region);
 1019         return 0;
 1020     }
 1021     buffer_set_limit(packet, msglen);
 1022 
 1023     /* see if check on data fails: checks that we are not reading
 1024      * random garbage */
 1025     if(!diff_read_32(in, &checklen) || checklen != msglen) {
 1026         log_msg(LOG_ERR, "transfer part has incorrect checkvalue");
 1027         return 0;
 1028     }
 1029     *bytes += msglen;
 1030 
 1031     dname_zone = dname_parse(region, zone);
 1032     zone_db = find_or_create_zone(db, dname_zone, opt, zone, patname);
 1033     if(!zone_db) {
 1034         log_msg(LOG_ERR, "could not create zone %s %s", zone, patname);
 1035         region_destroy(region);
 1036         return 0;
 1037     }
 1038     *zone_res = zone_db;
 1039 
 1040     /* only answer section is really used, question, additional and
 1041        authority section RRs are skipped */
 1042     qcount = QDCOUNT(packet);
 1043     ancount = ANCOUNT(packet);
 1044     buffer_skip(packet, QHEADERSZ);
 1045     /* qcount should be 0 or 1 really, ancount limited by 64k packet */
 1046     if(qcount > 64 || ancount > 65530) {
 1047         log_msg(LOG_ERR, "RR count impossibly high");
 1048         region_destroy(region);
 1049         return 0;
 1050     }
 1051 
 1052     /* skip queries */
 1053     for(i=0; i<qcount; ++i)
 1054         if(!packet_skip_rr(packet, 1)) {
 1055             log_msg(LOG_ERR, "bad RR in question section");
 1056             region_destroy(region);
 1057             return 0;
 1058         }
 1059 
 1060     DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: started packet for zone %s",
 1061             dname_to_string(dname_zone, 0)));
 1062     /* first RR: check if SOA and correct zone & serialno */
 1063     if(*rr_count == 0) {
 1064         DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parse first RR",
 1065             dname_to_string(dname_zone, 0)));
 1066         dname = dname_make_from_packet(region, packet, 1, 1);
 1067         if(!dname) {
 1068             log_msg(LOG_ERR, "could not parse dname");
 1069             region_destroy(region);
 1070             return 0;
 1071         }
 1072         if(dname_compare(dname_zone, dname) != 0) {
 1073             log_msg(LOG_ERR, "SOA dname %s not equal to zone",
 1074                 dname_to_string(dname,0));
 1075             log_msg(LOG_ERR, "zone dname is %s",
 1076                 dname_to_string(dname_zone,0));
 1077             region_destroy(region);
 1078             return 0;
 1079         }
 1080         if(!buffer_available(packet, 10)) {
 1081             log_msg(LOG_ERR, "bad SOA RR");
 1082             region_destroy(region);
 1083             return 0;
 1084         }
 1085         if(buffer_read_u16(packet) != TYPE_SOA ||
 1086             buffer_read_u16(packet) != CLASS_IN) {
 1087             log_msg(LOG_ERR, "first RR not SOA IN");
 1088             region_destroy(region);
 1089             return 0;
 1090         }
 1091         buffer_skip(packet, sizeof(uint32_t)); /* ttl */
 1092         if(!buffer_available(packet, buffer_read_u16(packet)) ||
 1093             !packet_skip_dname(packet) /* skip prim_ns */ ||
 1094             !packet_skip_dname(packet) /* skip email */) {
 1095             log_msg(LOG_ERR, "bad SOA RR");
 1096             region_destroy(region);
 1097             return 0;
 1098         }
 1099         if(buffer_read_u32(packet) != serialno) {
 1100             buffer_skip(packet, -4);
 1101             log_msg(LOG_ERR, "SOA serial %u different from commit %u",
 1102                 (unsigned)buffer_read_u32(packet), (unsigned)serialno);
 1103             region_destroy(region);
 1104             return 0;
 1105         }
 1106         buffer_skip(packet, sizeof(uint32_t)*4);
 1107         counter = 1;
 1108         *rr_count = 1;
 1109         *is_axfr = 0;
 1110         *delete_mode = 0;
 1111         DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d",
 1112             dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
 1113     }
 1114     else  counter = 0;
 1115 
 1116     for(; counter < ancount; ++counter,++(*rr_count))
 1117     {
 1118         uint16_t type, klass;
 1119         uint32_t ttl;
 1120 
 1121         if(!(dname=dname_make_from_packet(region, packet, 1,1))) {
 1122             log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count);
 1123             region_destroy(region);
 1124             return 0;
 1125         }
 1126         if(!buffer_available(packet, 10)) {
 1127             log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count);
 1128             region_destroy(region);
 1129             return 0;
 1130         }
 1131         type = buffer_read_u16(packet);
 1132         klass = buffer_read_u16(packet);
 1133         ttl = buffer_read_u32(packet);
 1134         rrlen = buffer_read_u16(packet);
 1135         if(!buffer_available(packet, rrlen)) {
 1136             log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d",
 1137                 *rr_count, rrlen, (int)buffer_remaining(packet));
 1138             region_destroy(region);
 1139             return 0;
 1140         }
 1141         DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d",
 1142             dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
 1143 
 1144         if(*rr_count == 1 && type != TYPE_SOA) {
 1145             /* second RR: if not SOA: this is an AXFR; delete all zone contents */
 1146 #ifdef NSEC3
 1147             nsec3_clear_precompile(db, zone_db);
 1148             zone_db->nsec3_param = NULL;
 1149 #endif
 1150             delete_zone_rrs(db, zone_db);
 1151             if(db->udb)
 1152                 udb_zone_clear(db->udb, udbz);
 1153             /* add everything else (incl end SOA) */
 1154             *delete_mode = 0;
 1155             *is_axfr = 1;
 1156             DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d",
 1157                 dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
 1158         }
 1159         if(*rr_count == 1 && type == TYPE_SOA) {
 1160             /* if the serial no of the SOA equals the serialno, then AXFR */
 1161             size_t bufpos = buffer_position(packet);
 1162             uint32_t thisserial;
 1163             if(!packet_skip_dname(packet) ||
 1164                 !packet_skip_dname(packet) ||
 1165                 buffer_remaining(packet) < sizeof(uint32_t)*5)
 1166             {
 1167                 log_msg(LOG_ERR, "bad xfr SOA RR formerr.");
 1168                 region_destroy(region);
 1169                 return 0;
 1170             }
 1171             thisserial = buffer_read_u32(packet);
 1172             if(thisserial == serialno) {
 1173                 /* AXFR */
 1174 #ifdef NSEC3
 1175                 nsec3_clear_precompile(db, zone_db);
 1176                 zone_db->nsec3_param = NULL;
 1177 #endif
 1178                 delete_zone_rrs(db, zone_db);
 1179                 if(db->udb)
 1180                     udb_zone_clear(db->udb, udbz);
 1181                 *delete_mode = 0;
 1182                 *is_axfr = 1;
 1183             }
 1184             /* must have stuff in memory for a successful IXFR,
 1185              * the serial number of the SOA has been checked
 1186              * previously (by check_for_bad_serial) if it exists */
 1187             if(!*is_axfr && !domain_find_rrset(zone_db->apex,
 1188                 zone_db, TYPE_SOA)) {
 1189                 log_msg(LOG_ERR, "%s SOA serial %u is not "
 1190                     "in memory, skip IXFR", zone, serialno);
 1191                 region_destroy(region);
 1192                 /* break out and stop the IXFR, ignore it */
 1193                 return 2;
 1194             }
 1195             buffer_set_position(packet, bufpos);
 1196         }
 1197         if(type == TYPE_SOA && !*is_axfr) {
 1198             /* switch from delete-part to add-part and back again,
 1199                just before soa - so it gets deleted and added too */
 1200             /* this means we switch to delete mode for the final SOA */
 1201             *delete_mode = !*delete_mode;
 1202             DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d",
 1203                 dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
 1204         }
 1205         if(type == TYPE_TSIG || type == TYPE_OPT) {
 1206             /* ignore pseudo RRs */
 1207             buffer_skip(packet, rrlen);
 1208             continue;
 1209         }
 1210 
 1211         DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s",
 1212             *delete_mode?"del":"add",
 1213             dname_to_string(dname,0), rrtype_to_string(type)));
 1214         if(*delete_mode) {
 1215             /* delete this rr */
 1216             if(!*is_axfr && type == TYPE_SOA && counter==ancount-1
 1217                 && seq_nr == seq_total-1) {
 1218                 continue; /* do not delete final SOA RR for IXFR */
 1219             }
 1220             if(!delete_RR(db, dname, type, klass, packet,
 1221                 rrlen, zone_db, region, udbz, softfail)) {
 1222                 region_destroy(region);
 1223                 return 0;
 1224             }
 1225         }
 1226         else
 1227         {
 1228             /* add this rr */
 1229             if(!add_RR(db, dname, type, klass, ttl, packet,
 1230                 rrlen, zone_db, udbz, softfail)) {
 1231                 region_destroy(region);
 1232                 return 0;
 1233             }
 1234         }
 1235     }
 1236     region_destroy(region);
 1237     return 1;
 1238 }
 1239 
 1240 static int
 1241 check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial)
 1242 {
 1243     /* see if serial OK with in-memory serial */
 1244     domain_type* domain;
 1245     region_type* region = region_create(xalloc, free);
 1246     const dname_type* zone_name = dname_parse(region, zone_str);
 1247     zone_type* zone = 0;
 1248     domain = domain_table_find(db->domains, zone_name);
 1249     if(domain)
 1250         zone = domain_find_zone(db, domain);
 1251     if(zone && zone->apex == domain && zone->soa_rrset && old_serial)
 1252     {
 1253         uint32_t memserial;
 1254         memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]),
 1255             sizeof(uint32_t));
 1256         if(old_serial != ntohl(memserial)) {
 1257             region_destroy(region);
 1258             return 1;
 1259         }
 1260     }
 1261     region_destroy(region);
 1262     return 0;
 1263 }
 1264 
 1265 static int
 1266 apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in,
 1267     struct nsd_options* opt, udb_base* taskudb, udb_ptr* last_task,
 1268     uint32_t xfrfilenr)
 1269 {
 1270     char zone_buf[3072];
 1271     char log_buf[5120];
 1272     char patname_buf[2048];
 1273 
 1274     uint32_t old_serial, new_serial, num_parts, type;
 1275     uint64_t time_end_0, time_start_0;
 1276     uint32_t time_end_1, time_start_1;
 1277     uint8_t committed;
 1278     uint32_t i;
 1279     int num_bytes = 0;
 1280     assert(zonedb);
 1281 
 1282     /* read zone name and serial */
 1283     if(!diff_read_32(in, &type)) {
 1284         log_msg(LOG_ERR, "diff file too short");
 1285         return 0;
 1286     }
 1287     if(type != DIFF_PART_XFRF) {
 1288         log_msg(LOG_ERR, "xfr file has wrong format");
 1289         return 0;
 1290 
 1291     }
 1292     /* committed and num_parts are first because they need to be
 1293      * updated once the rest is written.  The log buf is not certain
 1294      * until its done, so at end of file.  The patname is in case a
 1295      * new zone is created, we know what the options-pattern is */
 1296     if(!diff_read_8(in, &committed) ||
 1297         !diff_read_32(in, &num_parts) ||
 1298         !diff_read_64(in, &time_end_0) ||
 1299         !diff_read_32(in, &time_end_1) ||
 1300         !diff_read_32(in, &old_serial) ||
 1301         !diff_read_32(in, &new_serial) ||
 1302         !diff_read_64(in, &time_start_0) ||
 1303         !diff_read_32(in, &time_start_1) ||
 1304         !diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
 1305         !diff_read_str(in, patname_buf, sizeof(patname_buf))) {
 1306         log_msg(LOG_ERR, "diff file bad commit part");
 1307         return 0;
 1308     }
 1309 
 1310     /* has been read in completely */
 1311     if(strcmp(zone_buf, domain_to_string(zonedb->apex)) != 0) {
 1312         log_msg(LOG_ERR, "file %s does not match task %s",
 1313             zone_buf, domain_to_string(zonedb->apex));
 1314         return 0;
 1315     }
 1316     if(!committed) {
 1317         log_msg(LOG_ERR, "diff file %s was not committed", zone_buf);
 1318         return 0;
 1319     }
 1320     if(num_parts == 0) {
 1321         log_msg(LOG_ERR, "diff file %s was not completed", zone_buf);
 1322         return 0;
 1323     }
 1324     if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) {
 1325         DEBUG(DEBUG_XFRD,1, (LOG_ERR,
 1326             "skipping diff file commit with bad serial"));
 1327         return 1;
 1328     }
 1329 
 1330     if(committed)
 1331     {
 1332         int is_axfr=0, delete_mode=0, rr_count=0, softfail=0;
 1333         const dname_type* apex = domain_dname_const(zonedb->apex);
 1334         udb_ptr z;
 1335 
 1336         DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf));
 1337         memset(&z, 0, sizeof(z)); /* if udb==NULL, have &z defined */
 1338         if(nsd->db->udb) {
 1339             if(udb_base_get_userflags(nsd->db->udb) != 0) {
 1340                 log_msg(LOG_ERR, "database corrupted, cannot update");
 1341                 xfrd_unlink_xfrfile(nsd, xfrfilenr);
 1342                 exit(1);
 1343             }
 1344             /* all parts were checked by xfrd before commit */
 1345             if(!udb_zone_search(nsd->db->udb, &z, dname_name(apex),
 1346                 apex->name_size)) {
 1347                 /* create it */
 1348                 if(!udb_zone_create(nsd->db->udb, &z, dname_name(apex),
 1349                     apex->name_size)) {
 1350                     /* out of disk space perhaps */
 1351                     log_msg(LOG_ERR, "could not udb_create_zone "
 1352                         "%s, disk space full?", zone_buf);
 1353                     return 0;
 1354                 }
 1355             }
 1356             /* set the udb dirty until we are finished applying changes */
 1357             udb_base_set_userflags(nsd->db->udb, 1);
 1358         }
 1359         /* read and apply all of the parts */
 1360         for(i=0; i<num_parts; i++) {
 1361             int ret;
 1362             DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i));
 1363             ret = apply_ixfr(nsd->db, in, zone_buf, new_serial, opt,
 1364                 i, num_parts, &is_axfr, &delete_mode,
 1365                 &rr_count, (nsd->db->udb?&z:NULL), &zonedb,
 1366                 patname_buf, &num_bytes, &softfail);
 1367             assert(zonedb);
 1368             if(ret == 0) {
 1369                 log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf);
 1370                 xfrd_unlink_xfrfile(nsd, xfrfilenr);
 1371                 /* the udb is still dirty, it is bad */
 1372                 exit(1);
 1373             } else if(ret == 2) {
 1374                 break;
 1375             }
 1376         }
 1377         if(nsd->db->udb)
 1378             udb_base_set_userflags(nsd->db->udb, 0);
 1379         /* read the final log_str: but do not fail on it */
 1380         if(!diff_read_str(in, log_buf, sizeof(log_buf))) {
 1381             log_msg(LOG_ERR, "could not read log for transfer %s",
 1382                 zone_buf);
 1383             snprintf(log_buf, sizeof(log_buf), "error reading log");
 1384         }
 1385 #ifdef NSEC3
 1386         if(zonedb) prehash_zone(nsd->db, zonedb);
 1387 #endif /* NSEC3 */
 1388         zonedb->is_changed = 1;
 1389         if(nsd->db->udb) {
 1390             assert(z.base);
 1391             ZONE(&z)->is_changed = 1;
 1392             ZONE(&z)->mtime = time_end_0;
 1393             ZONE(&z)->mtime_nsec = time_end_1*1000;
 1394             udb_zone_set_log_str(nsd->db->udb, &z, log_buf);
 1395             udb_zone_set_file_str(nsd->db->udb, &z, NULL);
 1396             udb_ptr_unlink(&z, nsd->db->udb);
 1397         } else {
 1398             zonedb->mtime.tv_sec = time_end_0;
 1399             zonedb->mtime.tv_nsec = time_end_1*1000;
 1400             if(zonedb->logstr)
 1401                 region_recycle(nsd->db->region, zonedb->logstr,
 1402                     strlen(zonedb->logstr)+1);
 1403             zonedb->logstr = region_strdup(nsd->db->region, log_buf);
 1404             if(zonedb->filename)
 1405                 region_recycle(nsd->db->region, zonedb->filename,
 1406                     strlen(zonedb->filename)+1);
 1407             zonedb->filename = NULL;
 1408         }
 1409         if(softfail && taskudb && !is_axfr) {
 1410             log_msg(LOG_ERR, "Failed to apply IXFR cleanly "
 1411                 "(deletes nonexistent RRs, adds existing RRs). "
 1412                 "Zone %s contents is different from master, "
 1413                 "starting AXFR. Transfer %s", zone_buf, log_buf);
 1414             /* add/del failures in IXFR, get an AXFR */
 1415             task_new_soainfo(taskudb, last_task, zonedb, 1);
 1416         } else {
 1417             if(taskudb)
 1418                 task_new_soainfo(taskudb, last_task, zonedb, 0);
 1419         }
 1420 
 1421         if(1 <= verbosity) {
 1422             double elapsed = (double)(time_end_0 - time_start_0)+
 1423                 (double)((double)time_end_1
 1424                 -(double)time_start_1) / 1000000.0;
 1425             VERBOSITY(1, (LOG_INFO, "zone %s %s of %d bytes in %g seconds",
 1426                 zone_buf, log_buf, num_bytes, elapsed));
 1427         }
 1428     }
 1429     else {
 1430         DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", log_buf));
 1431     }
 1432     return 1;
 1433 }
 1434 
 1435 struct udb_base* task_file_create(const char* file)
 1436 {
 1437         return udb_base_create_new(file, &namedb_walkfunc, NULL);
 1438 }
 1439 
 1440 static int
 1441 task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e,
 1442     size_t sz, const dname_type* zname)
 1443 {
 1444     if(!udb_ptr_alloc_space(e, udb, udb_chunk_type_task, sz)) {
 1445         return 0;
 1446     }
 1447     if(udb_ptr_is_null(last)) {
 1448         udb_base_set_userdata(udb, e->data);
 1449     } else {
 1450         udb_rptr_set_ptr(&TASKLIST(last)->next, udb, e);
 1451     }
 1452     udb_ptr_set_ptr(last, udb, e);
 1453 
 1454     /* fill in tasklist item */
 1455     udb_rel_ptr_init(&TASKLIST(e)->next);
 1456     TASKLIST(e)->size = sz;
 1457     TASKLIST(e)->oldserial = 0;
 1458     TASKLIST(e)->newserial = 0;
 1459     TASKLIST(e)->yesno = 0;
 1460 
 1461     if(zname) {
 1462         memmove(TASKLIST(e)->zname, zname, dname_total_size(zname));
 1463     }
 1464     return 1;
 1465 }
 1466 
 1467 void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z,
 1468     int gone)
 1469 {
 1470     /* calculate size */
 1471     udb_ptr e;
 1472     size_t sz;
 1473     const dname_type* apex, *ns, *em;
 1474     if(!z || !z->apex || !domain_dname(z->apex))
 1475         return; /* safety check */
 1476 
 1477     DEBUG(DEBUG_IPC,1, (LOG_INFO, "nsd: add soa info for zone %s",
 1478         domain_to_string(z->apex)));
 1479     apex = domain_dname(z->apex);
 1480     sz = sizeof(struct task_list_d) + dname_total_size(apex);
 1481     if(z->soa_rrset && !gone) {
 1482         ns = domain_dname(rdata_atom_domain(
 1483             z->soa_rrset->rrs[0].rdatas[0]));
 1484         em = domain_dname(rdata_atom_domain(
 1485             z->soa_rrset->rrs[0].rdatas[1]));
 1486         sz += sizeof(uint32_t)*6 + sizeof(uint8_t)*2
 1487             + ns->name_size + em->name_size;
 1488     } else {
 1489         ns = 0;
 1490         em = 0;
 1491     }
 1492 
 1493     /* create new task_list item */
 1494     if(!task_create_new_elem(udb, last, &e, sz, apex)) {
 1495         log_msg(LOG_ERR, "tasklist: out of space, cannot add SOAINFO");
 1496         return;
 1497     }
 1498     TASKLIST(&e)->task_type = task_soa_info;
 1499 
 1500     if(z->soa_rrset && !gone) {
 1501         uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl);
 1502         uint8_t* p = (uint8_t*)TASKLIST(&e)->zname;
 1503         p += dname_total_size(apex);
 1504         memmove(p, &ttl, sizeof(uint32_t));
 1505         p += sizeof(uint32_t);
 1506         memmove(p, &ns->name_size, sizeof(uint8_t));
 1507         p += sizeof(uint8_t);
 1508         memmove(p, dname_name(ns), ns->name_size);
 1509         p += ns->name_size;
 1510         memmove(p, &em->name_size, sizeof(uint8_t));
 1511         p += sizeof(uint8_t);
 1512         memmove(p, dname_name(em), em->name_size);
 1513         p += em->name_size;
 1514         memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[2]),
 1515             sizeof(uint32_t));
 1516         p += sizeof(uint32_t);
 1517         memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[3]),
 1518             sizeof(uint32_t));
 1519         p += sizeof(uint32_t);
 1520         memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[4]),
 1521             sizeof(uint32_t));
 1522         p += sizeof(uint32_t);
 1523         memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[5]),
 1524             sizeof(uint32_t));
 1525         p += sizeof(uint32_t);
 1526         memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[6]),
 1527             sizeof(uint32_t));
 1528     }
 1529     udb_ptr_unlink(&e, udb);
 1530 }
 1531 
 1532 void task_process_sync(struct udb_base* taskudb)
 1533 {
 1534     /* need to sync before other process uses the mmap? */
 1535     DEBUG(DEBUG_IPC,1, (LOG_INFO, "task procsync %s size %d",
 1536         taskudb->fname, (int)taskudb->base_size));
 1537     (void)taskudb;
 1538 }
 1539 
 1540 void task_remap(struct udb_base* taskudb)
 1541 {
 1542     DEBUG(DEBUG_IPC,1, (LOG_INFO, "task remap %s size %d",
 1543         taskudb->fname, (int)taskudb->glob_data->fsize));
 1544     udb_base_remap_process(taskudb);
 1545 }
 1546 
 1547 void task_clear(struct udb_base* taskudb)
 1548 {
 1549     udb_ptr t, n;
 1550     udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb));
 1551     udb_base_set_userdata(taskudb, 0);
 1552     udb_ptr_init(&n, taskudb);
 1553     while(!udb_ptr_is_null(&t)) {
 1554         udb_ptr_set_rptr(&n, taskudb, &TASKLIST(&t)->next);
 1555         udb_rptr_zero(&TASKLIST(&t)->next, taskudb);
 1556         udb_ptr_free_space(&t, taskudb, TASKLIST(&t)->size);
 1557         udb_ptr_set_ptr(&t, taskudb, &n);
 1558     }
 1559     udb_ptr_unlink(&t, taskudb);
 1560     udb_ptr_unlink(&n, taskudb);
 1561 }
 1562 
 1563 void task_new_expire(struct udb_base* udb, udb_ptr* last,
 1564     const struct dname* z, int expired)
 1565 {
 1566     udb_ptr e;
 1567     if(!z) return;
 1568     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add expire info for zone %s",
 1569         dname_to_string(z,NULL)));
 1570     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
 1571         dname_total_size(z), z)) {
 1572         log_msg(LOG_ERR, "tasklist: out of space, cannot add expire");
 1573         return;
 1574     }
 1575     TASKLIST(&e)->task_type = task_expire;
 1576     TASKLIST(&e)->yesno = expired;
 1577     udb_ptr_unlink(&e, udb);
 1578 }
 1579 
 1580 void task_new_check_zonefiles(udb_base* udb, udb_ptr* last,
 1581     const dname_type* zone)
 1582 {
 1583     udb_ptr e;
 1584     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles"));
 1585     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
 1586         (zone?dname_total_size(zone):0), zone)) {
 1587         log_msg(LOG_ERR, "tasklist: out of space, cannot add check_zones");
 1588         return;
 1589     }
 1590     TASKLIST(&e)->task_type = task_check_zonefiles;
 1591     TASKLIST(&e)->yesno = (zone!=NULL);
 1592     udb_ptr_unlink(&e, udb);
 1593 }
 1594 
 1595 void task_new_write_zonefiles(udb_base* udb, udb_ptr* last,
 1596     const dname_type* zone)
 1597 {
 1598     udb_ptr e;
 1599     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task writezonefiles"));
 1600     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
 1601         (zone?dname_total_size(zone):0), zone)) {
 1602         log_msg(LOG_ERR, "tasklist: out of space, cannot add writezones");
 1603         return;
 1604     }
 1605     TASKLIST(&e)->task_type = task_write_zonefiles;
 1606     TASKLIST(&e)->yesno = (zone!=NULL);
 1607     udb_ptr_unlink(&e, udb);
 1608 }
 1609 
 1610 void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v)
 1611 {
 1612     udb_ptr e;
 1613     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task set_verbosity"));
 1614     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
 1615         NULL)) {
 1616         log_msg(LOG_ERR, "tasklist: out of space, cannot add set_v");
 1617         return;
 1618     }
 1619     TASKLIST(&e)->task_type = task_set_verbosity;
 1620     TASKLIST(&e)->yesno = v;
 1621     udb_ptr_unlink(&e, udb);
 1622 }
 1623 
 1624 #ifdef BIND8_STATS
 1625 void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat,
 1626     size_t child_count)
 1627 {
 1628     void* p;
 1629     udb_ptr e;
 1630     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task stat_info"));
 1631     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
 1632         sizeof(*stat) + sizeof(stc_type)*child_count, NULL)) {
 1633         log_msg(LOG_ERR, "tasklist: out of space, cannot add stati");
 1634         return NULL;
 1635     }
 1636     TASKLIST(&e)->task_type = task_stat_info;
 1637     p = TASKLIST(&e)->zname;
 1638     memcpy(p, stat, sizeof(*stat));
 1639     udb_ptr_unlink(&e, udb);
 1640     return (char*)p + sizeof(*stat);
 1641 }
 1642 #endif /* BIND8_STATS */
 1643 
 1644 void
 1645 task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone,
 1646     const char* pattern, unsigned zonestatid)
 1647 {
 1648     size_t zlen = strlen(zone);
 1649     size_t plen = strlen(pattern);
 1650     void *p;
 1651     udb_ptr e;
 1652     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addzone %s %s", zone, pattern));
 1653     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
 1654         zlen + 1 + plen + 1, NULL)) {
 1655         log_msg(LOG_ERR, "tasklist: out of space, cannot add addz");
 1656         return;
 1657     }
 1658     TASKLIST(&e)->task_type = task_add_zone;
 1659     TASKLIST(&e)->yesno = zonestatid;
 1660     p = TASKLIST(&e)->zname;
 1661     memcpy(p, zone, zlen+1);
 1662     memmove((char*)p+zlen+1, pattern, plen+1);
 1663     udb_ptr_unlink(&e, udb);
 1664 }
 1665 
 1666 void
 1667 task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname)
 1668 {
 1669     udb_ptr e;
 1670     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delzone %s", dname_to_string(dname, 0)));
 1671     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
 1672         +dname_total_size(dname), dname)) {
 1673         log_msg(LOG_ERR, "tasklist: out of space, cannot add delz");
 1674         return;
 1675     }
 1676     TASKLIST(&e)->task_type = task_del_zone;
 1677     udb_ptr_unlink(&e, udb);
 1678 }
 1679 
 1680 void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key)
 1681 {
 1682     char* p;
 1683     udb_ptr e;
 1684     assert(key->name && key->algorithm && key->secret);
 1685     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addkey"));
 1686     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
 1687         +strlen(key->name)+1+strlen(key->algorithm)+1+
 1688         strlen(key->secret)+1, NULL)) {
 1689         log_msg(LOG_ERR, "tasklist: out of space, cannot add addk");
 1690         return;
 1691     }
 1692     TASKLIST(&e)->task_type = task_add_key;
 1693     p = (char*)TASKLIST(&e)->zname;
 1694     memmove(p, key->name, strlen(key->name)+1);
 1695     p+=strlen(key->name)+1;
 1696     memmove(p, key->algorithm, strlen(key->algorithm)+1);
 1697     p+=strlen(key->algorithm)+1;
 1698     memmove(p, key->secret, strlen(key->secret)+1);
 1699     udb_ptr_unlink(&e, udb);
 1700 }
 1701 
 1702 void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name)
 1703 {
 1704     char* p;
 1705     udb_ptr e;
 1706     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delkey"));
 1707     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
 1708         +strlen(name)+1, NULL)) {
 1709         log_msg(LOG_ERR, "tasklist: out of space, cannot add delk");
 1710         return;
 1711     }
 1712     TASKLIST(&e)->task_type = task_del_key;
 1713     p = (char*)TASKLIST(&e)->zname;
 1714     memmove(p, name, strlen(name)+1);
 1715     udb_ptr_unlink(&e, udb);
 1716 }
 1717 
 1718 void task_new_add_pattern(udb_base* udb, udb_ptr* last,
 1719     struct pattern_options* p)
 1720 {
 1721     region_type* temp;
 1722     buffer_type* buffer;
 1723     udb_ptr e;
 1724     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addpattern %s", p->pname));
 1725     temp = region_create(xalloc, free);
 1726     buffer = buffer_create(temp, 4096);
 1727     pattern_options_marshal(buffer, p);
 1728     buffer_flip(buffer);
 1729     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
 1730         + buffer_limit(buffer), NULL)) {
 1731         log_msg(LOG_ERR, "tasklist: out of space, cannot add addp");
 1732         region_destroy(temp);
 1733         return;
 1734     }
 1735     TASKLIST(&e)->task_type = task_add_pattern;
 1736     TASKLIST(&e)->yesno = buffer_limit(buffer);
 1737     memmove(TASKLIST(&e)->zname, buffer_begin(buffer),
 1738         buffer_limit(buffer));
 1739     udb_ptr_unlink(&e, udb);
 1740     region_destroy(temp);
 1741 }
 1742 
 1743 void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name)
 1744 {
 1745     char* p;
 1746     udb_ptr e;
 1747     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delpattern %s", name));
 1748     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
 1749         +strlen(name)+1, NULL)) {
 1750         log_msg(LOG_ERR, "tasklist: out of space, cannot add delp");
 1751         return;
 1752     }
 1753     TASKLIST(&e)->task_type = task_del_pattern;
 1754     p = (char*)TASKLIST(&e)->zname;
 1755     memmove(p, name, strlen(name)+1);
 1756     udb_ptr_unlink(&e, udb);
 1757 }
 1758 
 1759 void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt)
 1760 {
 1761     udb_ptr e;
 1762     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task opt_change"));
 1763     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
 1764         NULL)) {
 1765         log_msg(LOG_ERR, "tasklist: out of space, cannot add o_c");
 1766         return;
 1767     }
 1768     TASKLIST(&e)->task_type = task_opt_change;
 1769 #ifdef RATELIMIT
 1770     TASKLIST(&e)->oldserial = opt->rrl_ratelimit;
 1771     TASKLIST(&e)->newserial = opt->rrl_whitelist_ratelimit;
 1772     TASKLIST(&e)->yesno = (uint64_t) opt->rrl_slip;
 1773 #else
 1774     (void)opt;
 1775 #endif
 1776     udb_ptr_unlink(&e, udb);
 1777 }
 1778 
 1779 void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz)
 1780 {
 1781     udb_ptr e;
 1782     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task zonestat_inc"));
 1783     if(sz == 0)
 1784         return; /* no need to decrease to 0 */
 1785     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
 1786         NULL)) {
 1787         log_msg(LOG_ERR, "tasklist: out of space, cannot add z_i");
 1788         return;
 1789     }
 1790     TASKLIST(&e)->task_type = task_zonestat_inc;
 1791     TASKLIST(&e)->oldserial = (uint32_t)sz;
 1792     udb_ptr_unlink(&e, udb);
 1793 }
 1794 
 1795 int
 1796 task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname,
 1797     uint32_t old_serial, uint32_t new_serial, uint64_t filenumber)
 1798 {
 1799     udb_ptr e;
 1800     DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task apply_xfr"));
 1801     if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
 1802         +dname_total_size(dname), dname)) {
 1803         log_msg(LOG_ERR, "tasklist: out of space, cannot add applyxfr");
 1804         return 0;
 1805     }
 1806     TASKLIST(&e)->oldserial = old_serial;
 1807     TASKLIST(&e)->newserial = new_serial;
 1808     TASKLIST(&e)->yesno = filenumber;
 1809     TASKLIST(&e)->task_type = task_apply_xfr;
 1810     udb_ptr_unlink(&e, udb);
 1811     return 1;
 1812 }
 1813 
 1814 void
 1815 task_process_expire(namedb_type* db, struct task_list_d* task)
 1816 {
 1817     uint8_t ok;
 1818     zone_type* z = namedb_find_zone(db, task->zname);
 1819     assert(task->task_type == task_expire);
 1820     if(!z) {
 1821         DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "zone %s %s but not in zonetree",
 1822             dname_to_string(task->zname, NULL),
 1823             task->yesno?"expired":"unexpired"));
 1824         return;
 1825     }
 1826     DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: expire task zone %s %s",
 1827         dname_to_string(task->zname,0),
 1828         task->yesno?"expired":"unexpired"));
 1829     /* find zone, set expire flag */
 1830     ok = !task->yesno;
 1831     /* only update zone->is_ok if needed to minimize copy-on-write
 1832      * of memory pages shared after fork() */
 1833     if(ok && !z->is_ok)
 1834         z->is_ok = 1;
 1835     else if(!ok && z->is_ok)
 1836         z->is_ok = 0;
 1837 }
 1838 
 1839 static void
 1840 task_process_set_verbosity(struct task_list_d* task)
 1841 {
 1842     DEBUG(DEBUG_IPC,1, (LOG_INFO, "verbosity task %d", (int)task->yesno));
 1843     verbosity = task->yesno;
 1844 }
 1845 
 1846 static void
 1847 task_process_checkzones(struct nsd* nsd, udb_base* udb, udb_ptr* last_task,
 1848     struct task_list_d* task)
 1849 {
 1850     /* on SIGHUP check if zone-text-files changed and if so,
 1851      * reread.  When from xfrd-reload, no need to fstat the files */
 1852     if(task->yesno) {
 1853         struct zone_options* zo = zone_options_find(nsd->options,
 1854             task->zname);
 1855         if(zo)
 1856             namedb_check_zonefile(nsd, udb, last_task, zo);
 1857     } else {
 1858         /* check all zones */
 1859         namedb_check_zonefiles(nsd, nsd->options, udb, last_task);
 1860     }
 1861 }
 1862 
 1863 static void
 1864 task_process_writezones(struct nsd* nsd, struct task_list_d* task)
 1865 {
 1866     if(task->yesno) {
 1867         struct zone_options* zo = zone_options_find(nsd->options,
 1868             task->zname);
 1869         if(zo)
 1870             namedb_write_zonefile(nsd, zo);
 1871     } else {
 1872         namedb_write_zonefiles(nsd, nsd->options);
 1873     }
 1874 }
 1875 
 1876 static void
 1877 task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task,
 1878     struct task_list_d* task)
 1879 {
 1880     zone_type* z;
 1881     const dname_type* zdname;
 1882     const char* zname = (const char*)task->zname;
 1883     const char* pname = zname + strlen(zname)+1;
 1884     DEBUG(DEBUG_IPC,1, (LOG_INFO, "addzone task %s %s", zname, pname));
 1885     zdname = dname_parse(nsd->db->region, zname);
 1886     if(!zdname) {
 1887         log_msg(LOG_ERR, "can not parse zone name %s", zname);
 1888         return;
 1889     }
 1890     /* create zone */
 1891     z = find_or_create_zone(nsd->db, zdname, nsd->options, zname, pname);
 1892     if(!z) {
 1893         region_recycle(nsd->db->region, (void*)zdname,
 1894             dname_total_size(zdname));
 1895         log_msg(LOG_ERR, "can not add zone %s %s", zname, pname);
 1896         return;
 1897     }
 1898     z->zonestatid = (unsigned)task->yesno;
 1899     /* if zone is empty, attempt to read the zonefile from disk (if any) */
 1900     if(!z->soa_rrset && z->opts->pattern->zonefile) {
 1901         namedb_read_zonefile(nsd, z, udb, last_task);
 1902     }
 1903 }
 1904 
 1905 static void
 1906 task_process_del_zone(struct nsd* nsd, struct task_list_d* task)
 1907 {
 1908     zone_type* zone;
 1909     struct zone_options* zopt;
 1910     DEBUG(DEBUG_IPC,1, (LOG_INFO, "delzone task %s", dname_to_string(
 1911         task->zname, NULL)));
 1912     zone = namedb_find_zone(nsd->db, task->zname);
 1913     if(!zone)
 1914         return;
 1915 
 1916 #ifdef NSEC3
 1917     nsec3_clear_precompile(nsd->db, zone);
 1918     zone->nsec3_param = NULL;
 1919 #endif
 1920     delete_zone_rrs(nsd->db, zone);
 1921     if(nsd->db->udb) {
 1922         udb_ptr udbz;
 1923         if(udb_zone_search(nsd->db->udb, &udbz, dname_name(task->zname),
 1924             task->zname->name_size)) {
 1925             udb_zone_delete(nsd->db->udb, &udbz);
 1926             udb_ptr_unlink(&udbz, nsd->db->udb);
 1927         }
 1928     }
 1929 
 1930     /* remove from zonetree, apex, soa */
 1931     zopt = zone->opts;
 1932     namedb_zone_delete(nsd->db, zone);
 1933     /* remove from options (zone_list already edited by xfrd) */
 1934     zone_options_delete(nsd->options, zopt);
 1935 }
 1936 
 1937 static void
 1938 task_process_add_key(struct nsd* nsd, struct task_list_d* task)
 1939 {
 1940     struct key_options key;
 1941     key.name = (char*)task->zname;
 1942     DEBUG(DEBUG_IPC,1, (LOG_INFO, "addkey task %s", key.name));
 1943     key.algorithm = key.name + strlen(key.name)+1;
 1944     key.secret = key.algorithm + strlen(key.algorithm)+1;
 1945     key_options_add_modify(nsd->options, &key);
 1946     memset(key.secret, 0xdd, strlen(key.secret)); /* wipe secret */
 1947 }
 1948 
 1949 static void
 1950 task_process_del_key(struct nsd* nsd, struct task_list_d* task)
 1951 {
 1952     char* name = (char*)task->zname;
 1953     DEBUG(DEBUG_IPC,1, (LOG_INFO, "delkey task %s", name));
 1954     /* this is reload and nothing is using the TSIG key right now */
 1955     key_options_remove(nsd->options, name);
 1956 }
 1957 
 1958 static void
 1959 task_process_add_pattern(struct nsd* nsd, struct task_list_d* task)
 1960 {
 1961     region_type* temp = region_create(xalloc, free);
 1962     buffer_type buffer;
 1963     struct pattern_options *pat;
 1964     buffer_create_from(&buffer, task->zname, task->yesno);
 1965     pat = pattern_options_unmarshal(temp, &buffer);
 1966     DEBUG(DEBUG_IPC,1, (LOG_INFO, "addpattern task %s", pat->pname));
 1967     pattern_options_add_modify(nsd->options, pat);
 1968     region_destroy(temp);
 1969 }
 1970 
 1971 static void
 1972 task_process_del_pattern(struct nsd* nsd, struct task_list_d* task)
 1973 {
 1974     char* name = (char*)task->zname;
 1975     DEBUG(DEBUG_IPC,1, (LOG_INFO, "delpattern task %s", name));
 1976     pattern_options_remove(nsd->options, name);
 1977 }
 1978 
 1979 static void
 1980 task_process_opt_change(struct nsd* nsd, struct task_list_d* task)
 1981 {
 1982     DEBUG(DEBUG_IPC,1, (LOG_INFO, "optchange task"));
 1983 #ifdef RATELIMIT
 1984     nsd->options->rrl_ratelimit = task->oldserial;
 1985     nsd->options->rrl_whitelist_ratelimit = task->newserial;
 1986     nsd->options->rrl_slip = task->yesno;
 1987     rrl_set_limit(nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit,
 1988         nsd->options->rrl_slip);
 1989 #else
 1990     (void)nsd; (void)task;
 1991 #endif
 1992 }
 1993 
 1994 #ifdef USE_ZONE_STATS
 1995 static void
 1996 task_process_zonestat_inc(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
 1997     struct task_list_d* task)
 1998 {
 1999     DEBUG(DEBUG_IPC,1, (LOG_INFO, "zonestat_inc task %u", (unsigned)task->oldserial));
 2000     nsd->zonestatdesired = (unsigned)task->oldserial;
 2001     /* send echo to xfrd to increment on its end */
 2002     task_new_zonestat_inc(udb, last_task, nsd->zonestatdesired);
 2003 }
 2004 #endif
 2005 
 2006 static void
 2007 task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
 2008     udb_ptr* task)
 2009 {
 2010     /* we have to use an udb_ptr task here, because the apply_xfr procedure
 2011      * appends soa_info which may remap and change the pointer. */
 2012     zone_type* zone;
 2013     FILE* df;
 2014     DEBUG(DEBUG_IPC,1, (LOG_INFO, "applyxfr task %s", dname_to_string(
 2015         TASKLIST(task)->zname, NULL)));
 2016     zone = namedb_find_zone(nsd->db, TASKLIST(task)->zname);
 2017     if(!zone) {
 2018         /* assume the zone has been deleted and a zone transfer was
 2019          * still waiting to be processed */
 2020         xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno);
 2021         return;
 2022     }
 2023     /* apply the XFR */
 2024     /* oldserial, newserial, yesno is filenumber */
 2025     df = xfrd_open_xfrfile(nsd, TASKLIST(task)->yesno, "r");
 2026     if(!df) {
 2027         /* could not open file to update */
 2028         /* there is no reply to xfrd failed-update,
 2029          * because xfrd has a scan for apply-failures. */
 2030         xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno);
 2031         return;
 2032     }
 2033     /* read and apply zone transfer */
 2034     if(!apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb,
 2035         last_task, TASKLIST(task)->yesno)) {
 2036         /* there is no reply to xfrd failed-update,
 2037          * because xfrd has a scan for apply-failures. */
 2038     }
 2039 
 2040     fclose(df);
 2041     xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno);
 2042 }
 2043 
 2044 
 2045 void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
 2046         udb_ptr* task)
 2047 {
 2048     switch(TASKLIST(task)->task_type) {
 2049     case task_expire:
 2050         task_process_expire(nsd->db, TASKLIST(task));
 2051         break;
 2052     case task_check_zonefiles:
 2053         task_process_checkzones(nsd, udb, last_task, TASKLIST(task));
 2054         break;
 2055     case task_write_zonefiles:
 2056         task_process_writezones(nsd, TASKLIST(task));
 2057         break;
 2058     case task_set_verbosity:
 2059         task_process_set_verbosity(TASKLIST(task));
 2060         break;
 2061     case task_add_zone:
 2062         task_process_add_zone(nsd, udb, last_task, TASKLIST(task));
 2063         break;
 2064     case task_del_zone:
 2065         task_process_del_zone(nsd, TASKLIST(task));
 2066         break;
 2067     case task_add_key:
 2068         task_process_add_key(nsd, TASKLIST(task));
 2069         break;
 2070     case task_del_key:
 2071         task_process_del_key(nsd, TASKLIST(task));
 2072         break;
 2073     case task_add_pattern:
 2074         task_process_add_pattern(nsd, TASKLIST(task));
 2075         break;
 2076     case task_del_pattern:
 2077         task_process_del_pattern(nsd, TASKLIST(task));
 2078         break;
 2079     case task_opt_change:
 2080         task_process_opt_change(nsd, TASKLIST(task));
 2081         break;
 2082 #ifdef USE_ZONE_STATS
 2083     case task_zonestat_inc:
 2084         task_process_zonestat_inc(nsd, udb, last_task, TASKLIST(task));
 2085         break;
 2086 #endif
 2087     case task_apply_xfr:
 2088         task_process_apply_xfr(nsd, udb, last_task, task);
 2089         break;
 2090     default:
 2091         log_msg(LOG_WARNING, "unhandled task in reload type %d",
 2092             (int)TASKLIST(task)->task_type);
 2093         break;
 2094     }
 2095     udb_ptr_free_space(task, udb, TASKLIST(task)->size);
 2096 }