summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd/difffile.c
diff options
context:
space:
mode:
authorJakob Schlyter <jakob@cvs.openbsd.org>2010-01-15 19:25:03 +0000
committerJakob Schlyter <jakob@cvs.openbsd.org>2010-01-15 19:25:03 +0000
commit19923c28d4d7acc78ae1d4acf0332333ca85c456 (patch)
treee4bef5687db33b36c97eff67782ab2f868c25091 /usr.sbin/nsd/difffile.c
parent76bf05a40c6dd9acce15c44b07a38135e5faa628 (diff)
NSD v3.2.4
Diffstat (limited to 'usr.sbin/nsd/difffile.c')
-rw-r--r--usr.sbin/nsd/difffile.c2092
1 files changed, 772 insertions, 1320 deletions
diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c
index 5510714f364..c11f5e7faaf 100644
--- a/usr.sbin/nsd/difffile.c
+++ b/usr.sbin/nsd/difffile.c
@@ -7,33 +7,28 @@
*
*/
-#include "config.h"
+#include <config.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "difffile.h"
-#include "xfrd-disk.h"
#include "util.h"
#include "packet.h"
#include "rdata.h"
-#include "udb.h"
-#include "udbzone.h"
-#include "nsec3.h"
-#include "nsd.h"
-#include "rrl.h"
static int
-write_64(FILE *out, uint64_t val)
+write_32(FILE *out, uint32_t val)
{
+ val = htonl(val);
return write_data(out, &val, sizeof(val));
}
static int
-write_32(FILE *out, uint32_t val)
+write_16(FILE *out, uint16_t val)
{
- val = htonl(val);
+ val = htons(val);
return write_data(out, &val, sizeof(val));
}
@@ -53,117 +48,143 @@ write_str(FILE *out, const char* str)
}
void
-diff_write_packet(const char* zone, const char* pat, uint32_t old_serial,
- uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len,
- struct nsd* nsd, uint64_t filenumber)
+diff_write_packet(const char* zone, uint32_t new_serial, uint16_t id,
+ uint32_t seq_nr, uint8_t* data, size_t len, nsd_options_t* opt)
{
- FILE* df = xfrd_open_xfrfile(nsd, filenumber, seq_nr?"a":"w");
- if(!df) {
- log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
+ const char* filename = opt->difffile;
+ struct timeval tv;
+ FILE *df;
+ uint32_t file_len = sizeof(uint32_t) + strlen(zone) +
+ sizeof(new_serial) + sizeof(id) + sizeof(seq_nr) + len;
+
+ if (gettimeofday(&tv, NULL) != 0) {
+ log_msg(LOG_ERR, "could not set timestamp for %s: %s",
+ filename, strerror(errno));
return;
}
- /* if first part, first write the header */
- if(seq_nr == 0) {
- struct timeval tv;
- if (gettimeofday(&tv, NULL) != 0) {
- log_msg(LOG_ERR, "could not get timestamp for %s: %s",
- zone, strerror(errno));
- }
- if(!write_32(df, DIFF_PART_XFRF) ||
- !write_8(df, 0) /* notcommitted(yet) */ ||
- !write_32(df, 0) /* numberofparts when done */ ||
- !write_64(df, (uint64_t) tv.tv_sec) ||
- !write_32(df, (uint32_t) tv.tv_usec) ||
- !write_32(df, old_serial) ||
- !write_32(df, new_serial) ||
- !write_64(df, (uint64_t) tv.tv_sec) ||
- !write_32(df, (uint32_t) tv.tv_usec) ||
- !write_str(df, zone) ||
- !write_str(df, pat)) {
- log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
- fclose(df);
- return;
- }
+ df = fopen(filename, "a");
+ if(!df) {
+ log_msg(LOG_ERR, "could not open file %s for append: %s",
+ filename, strerror(errno));
+ return;
}
- if(!write_32(df, DIFF_PART_XXFR) ||
- !write_32(df, len) ||
+ if(!write_32(df, DIFF_PART_IXFR) ||
+ !write_32(df, (uint32_t) tv.tv_sec) ||
+ !write_32(df, (uint32_t) tv.tv_usec) ||
+ !write_32(df, file_len) ||
+ !write_str(df, zone) ||
+ !write_32(df, new_serial) ||
+ !write_16(df, id) ||
+ !write_32(df, seq_nr) ||
!write_data(df, data, len) ||
- !write_32(df, len))
+ !write_32(df, file_len))
{
- log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
+ log_msg(LOG_ERR, "could not write to file %s: %s",
+ filename, strerror(errno));
}
+ fflush(df);
fclose(df);
}
void
-diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial,
- uint32_t num_parts, uint8_t commit, const char* log_str,
- struct nsd* nsd, uint64_t filenumber)
+diff_write_commit(const char* zone, uint32_t old_serial,
+ uint32_t new_serial, uint16_t id, uint32_t num_parts,
+ uint8_t commit, const char* log_str, nsd_options_t* opt)
{
+ const char* filename = opt->difffile;
struct timeval tv;
- FILE* df;
+ FILE *df;
+ uint32_t len;
if (gettimeofday(&tv, NULL) != 0) {
log_msg(LOG_ERR, "could not set timestamp for %s: %s",
- zone, strerror(errno));
+ filename, strerror(errno));
+ return;
}
- /* overwrite the first part of the file with 'committed = 1',
- * as well as the end_time and number of parts.
- * also write old_serial and new_serial, so that a bad file mixup
- * will result in unusable serial numbers. */
-
- df = xfrd_open_xfrfile(nsd, filenumber, "r+");
+ df = fopen(filename, "a");
if(!df) {
- log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
+ log_msg(LOG_ERR, "could not open file %s for append: %s",
+ filename, strerror(errno));
return;
}
- if(!write_32(df, DIFF_PART_XFRF) ||
- !write_8(df, commit) /* committed */ ||
- !write_32(df, num_parts) ||
- !write_64(df, (uint64_t) tv.tv_sec) ||
+
+ len = strlen(zone) + sizeof(len) + sizeof(old_serial) +
+ sizeof(new_serial) + sizeof(id) + sizeof(num_parts) +
+ sizeof(commit) + strlen(log_str) + sizeof(len);
+
+ if(!write_32(df, DIFF_PART_SURE) ||
+ !write_32(df, (uint32_t) tv.tv_sec) ||
!write_32(df, (uint32_t) tv.tv_usec) ||
+ !write_32(df, len) ||
+ !write_str(df, zone) ||
!write_32(df, old_serial) ||
- !write_32(df, new_serial))
+ !write_32(df, new_serial) ||
+ !write_16(df, id) ||
+ !write_32(df, num_parts) ||
+ !write_8(df, commit) ||
+ !write_str(df, log_str) ||
+ !write_32(df, len))
{
- log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
- fclose(df);
- return;
- }
-
- /* append the log_str to the end of the file */
- if(fseek(df, 0, SEEK_END) == -1) {
- log_msg(LOG_ERR, "could not fseek transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
- fclose(df);
- return;
- }
- if(!write_str(df, log_str)) {
- log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
- zone, (long long)filenumber, strerror(errno));
- fclose(df);
- return;
-
+ log_msg(LOG_ERR, "could not write to file %s: %s",
+ filename, strerror(errno));
}
fflush(df);
fclose(df);
}
+/*
+ * Checksum to signal no data change occured (for example, by a
+ * zonec run.
+ */
int
-diff_read_64(FILE *in, uint64_t* result)
+db_crc_different(namedb_type* db)
{
- if (fread(result, sizeof(*result), 1, in) == 1) {
- return 1;
- } else {
- return 0;
+ FILE *fd = fopen(db->filename, "r");
+ uint32_t crc_file;
+ char buf[NAMEDB_MAGIC_SIZE];
+ if(fd == NULL) {
+ log_msg(LOG_ERR, "unable to load %s: %s",
+ db->filename, strerror(errno));
+ return -1;
+ }
+
+ /* seek to position of CRC, check it and magic no */
+ if(fseeko(fd, db->crc_pos, SEEK_SET)==-1) {
+ log_msg(LOG_ERR, "unable to fseeko %s: %s. db changed?",
+ db->filename, strerror(errno));
+ fclose(fd);
+ return -1;
+ }
+
+ if(fread(&crc_file, sizeof(crc_file), 1, fd) != 1) {
+ if(!feof(fd))
+ log_msg(LOG_ERR, "could not read %s CRC: %s. "
+ "db changed?", db->filename, strerror(errno));
+ fclose(fd);
+ return -1;
+ }
+ crc_file = ntohl(crc_file);
+
+ if(fread(buf, sizeof(char), sizeof(buf), fd) != sizeof(buf)) {
+ if(!feof(fd))
+ log_msg(LOG_ERR, "could not read %s magic: %s. "
+ "db changed?", db->filename, strerror(errno));
+ fclose(fd);
+ return -1;
+ }
+ if(memcmp(buf, NAMEDB_MAGIC, NAMEDB_MAGIC_SIZE) != 0) {
+ fclose(fd);
+ return -1;
}
+
+ fclose(fd);
+
+ if(db->crc == crc_file)
+ return 0;
+ return 1;
}
int
@@ -178,6 +199,17 @@ diff_read_32(FILE *in, uint32_t* result)
}
int
+diff_read_16(FILE *in, uint16_t* result)
+{
+ if (fread(result, sizeof(*result), 1, in) == 1) {
+ *result = ntohs(*result);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int
diff_read_8(FILE *in, uint8_t* result)
{
if (fread(result, sizeof(*result), 1, in) == 1) {
@@ -227,7 +259,7 @@ has_data_below(domain_type* top)
assert(d != NULL);
/* in the canonical ordering subdomains are after this name */
d = domain_next(d);
- while(d != NULL && domain_is_subdomain(d, top)) {
+ while(d != NULL && dname_is_subdomain(domain_dname(d), domain_dname(top))) {
if(d->is_existing)
return 1;
d = domain_next(d);
@@ -235,29 +267,6 @@ has_data_below(domain_type* top)
return 0;
}
-/** check if domain with 0 rrsets has become empty (nonexist) */
-static void
-rrset_zero_nonexist_check(domain_type* domain)
-{
- /* is the node now an empty node (completely deleted) */
- if(domain->rrsets == 0) {
- /* if there is no data below it, it becomes non existing.
- also empty nonterminals above it become nonexisting */
- /* check for data below this node. */
- if(!has_data_below(domain)) {
- /* nonexist this domain and all parent empty nonterminals */
- domain_type* p = domain;
- while(p != NULL && p->rrsets == 0) {
- if(has_data_below(p))
- break;
- p->is_existing = 0;
- p = p->parent;
- }
- }
- }
-}
-
-/** remove rrset. Adjusts zone params. Does not remove domain */
static void
rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
{
@@ -274,355 +283,98 @@ rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
*pp = rrset->next;
DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s",
- domain_to_string(domain),
+ dname_to_string(domain_dname(domain),0),
rrtype_to_string(rrset_rrtype(rrset))));
/* is this a SOA rrset ? */
if(rrset->zone->soa_rrset == rrset) {
rrset->zone->soa_rrset = 0;
+ rrset->zone->updated = 1;
}
if(rrset->zone->ns_rrset == rrset) {
rrset->zone->ns_rrset = 0;
}
+#ifdef DNSSEC
if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) {
for (i = 0; i < rrset->rr_count; ++i) {
- if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY) {
+ if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_SOA) {
rrset->zone->is_secure = 0;
break;
}
}
}
+#endif
/* recycle the memory space of the rrset */
for (i = 0; i < rrset->rr_count; ++i)
add_rdata_to_recyclebin(db, &rrset->rrs[i]);
region_recycle(db->region, rrset->rrs,
sizeof(rr_type) * rrset->rr_count);
- rrset->rr_count = 0;
region_recycle(db->region, rrset, sizeof(rrset_type));
+
+ /* is the node now an empty node (completely deleted) */
+ if(domain->rrsets == 0) {
+ /* if there is no data below it, it becomes non existing.
+ also empty nonterminals above it become nonexisting */
+ /* check for data below this node. */
+ if(!has_data_below(domain)) {
+ /* nonexist this domain and all parent empty nonterminals */
+ domain_type* p = domain;
+ while(p != NULL && p->rrsets == 0) {
+ p->is_existing = 0;
+ p = p->parent;
+ }
+ }
+ }
+ rrset->rr_count = 0;
}
static int
-rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type,
- int* rdnum, char** reason)
+rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type)
{
- int k, start, end;
- start = 0;
- end = num;
- /**
- * SOA RDATA comparisons in XFR are more lenient,
- * only serial rdata is checked.
- **/
- if (type == TYPE_SOA) {
- start = 2;
- end = 3;
- }
- for(k = start; k < end; k++)
+ int k;
+ for(k = 0; k < num; k++)
{
if(rdata_atom_is_domain(type, k)) {
if(dname_compare(domain_dname(a[k].domain),
- domain_dname(b[k].domain))!=0) {
- *rdnum = k;
- *reason = "dname data";
+ domain_dname(b[k].domain))!=0)
return 0;
- }
- } else if(rdata_atom_is_literal_domain(type, k)) {
- /* literal dname, but compare case insensitive */
- if(a[k].data[0] != b[k].data[0]) {
- *rdnum = k;
- *reason = "literal dname len";
- return 0; /* uncompressed len must be equal*/
- }
- if(!dname_equal_nocase((uint8_t*)(a[k].data+1),
- (uint8_t*)(b[k].data+1), a[k].data[0])) {
- *rdnum = k;
- *reason = "literal dname data";
- return 0;
- }
} else {
/* check length */
- if(a[k].data[0] != b[k].data[0]) {
- *rdnum = k;
- *reason = "rdata len";
+ if(a[k].data[0] != b[k].data[0])
return 0;
- }
/* check data */
- if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) {
- *rdnum = k;
- *reason = "rdata data";
+ if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0)
return 0;
- }
}
}
return 1;
}
-static void
-debug_find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
- rdata_atom_type *rdatas, ssize_t rdata_num)
-{
- int i, rd;
- char* reason = "";
-
- for(i=0; i < rrset->rr_count; ++i) {
- if (rrset->rrs[i].type != type) {
- log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match "
- "RR num %d type %s",
- dname_to_string(rrset->rrs[i].owner->dname,0),
- rrtype_to_string(type), i,
- rrtype_to_string(rrset->rrs[i].type));
- }
- if (rrset->rrs[i].klass != klass) {
- log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d "
- "does not match RR num %d class %d",
- dname_to_string(rrset->rrs[i].owner->dname,0),
- rrtype_to_string(type),
- klass, i,
- rrset->rrs[i].klass);
- }
- if (rrset->rrs[i].rdata_count != rdata_num) {
- log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u "
- "does not match RR num %d rdlen %d",
- dname_to_string(rrset->rrs[i].owner->dname,0),
- rrtype_to_string(type),
- (unsigned) rdata_num, i,
- (unsigned) rrset->rrs[i].rdata_count);
- }
- if (!rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
- &rd, &reason)) {
- log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element "
- "%d differs from RR num %d rdata (%s)",
- dname_to_string(rrset->rrs[i].owner->dname,0),
- rrtype_to_string(type),
- rd, i, reason);
- }
- }
-}
-
static int
-find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
- rdata_atom_type *rdatas, ssize_t rdata_num, int add)
+find_rr_num(rrset_type* rrset,
+ uint16_t type, uint16_t klass,
+ rdata_atom_type *rdatas, ssize_t rdata_num)
{
- int i, rd;
- char* reason;
+ int i;
for(i=0; i < rrset->rr_count; ++i) {
if(rrset->rrs[i].type == type &&
rrset->rrs[i].klass == klass &&
rrset->rrs[i].rdata_count == rdata_num &&
- rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
- &rd, &reason))
+ rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type))
{
return i;
}
}
- /* this is odd. Log why rr cannot be found. */
- if (!add) {
- debug_find_rr_num(rrset, type, klass, rdatas, rdata_num);
- }
- return -1;
-}
-
-#ifdef NSEC3
-/* see if nsec3 deletion triggers need action */
-static void
-nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone,
- udb_ptr* udbz)
-{
- /* the RR has not actually been deleted yet, so we can inspect it */
- if(!zone->nsec3_param)
- return;
- /* see if the domain was an NSEC3-domain in the chain, but no longer */
- if(rr->type == TYPE_NSEC3 && rr->owner->nsec3 &&
- rr->owner->nsec3->nsec3_node.key &&
- nsec3_rr_uses_params(rr, zone) &&
- nsec3_in_chain_count(rr->owner, zone) <= 1) {
- domain_type* prev = nsec3_chain_find_prev(zone, rr->owner);
- /* remove from prehash because no longer an NSEC3 domain */
- if(domain_is_prehash(db->domains, rr->owner))
- prehash_del(db->domains, rr->owner);
- /* fixup the last in the zone */
- if(rr->owner == zone->nsec3_last)
- zone->nsec3_last = prev;
- /* unlink from the nsec3tree */
- zone_del_domain_in_hash_tree(zone->nsec3tree,
- &rr->owner->nsec3->nsec3_node);
- /* add previous NSEC3 to the prehash list */
- if(prev && prev != rr->owner)
- prehash_add(db->domains, prev);
- else nsec3_clear_precompile(db, zone);
- /* this domain becomes ordinary data domain: done later */
- }
- /* see if the rr was NSEC3PARAM that we were using */
- else if(rr->type == TYPE_NSEC3PARAM && rr == zone->nsec3_param) {
- /* clear trees, wipe hashes, wipe precompile */
- nsec3_clear_precompile(db, zone);
- /* pick up new nsec3param (from udb, or avoid deleted rr) */
- nsec3_find_zone_param(db, zone, udbz, rr);
- /* if no more NSEC3, done */
- if(!zone->nsec3_param)
- return;
- nsec3_precompile_newparam(db, zone);
- }
-}
-/* see if nsec3 prehash can be removed with new rrset content */
-static void
-nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
-{
- /* deletion of rrset already done, we can check if conditions apply */
- /* see if the domain is no longer precompiled */
- /* it has a hash_node, but no longer fulfills conditions */
- if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 &&
- domain->nsec3->hash_node.key &&
- !nsec3_condition_hash(domain, zone)) {
- /* remove precompile */
- domain->nsec3->nsec3_cover = NULL;
- domain->nsec3->nsec3_wcard_child_cover = NULL;
- domain->nsec3->nsec3_is_exact = 0;
- /* remove it from the hash tree */
- zone_del_domain_in_hash_tree(zone->hashtree,
- &domain->nsec3->hash_node);
- zone_del_domain_in_hash_tree(zone->wchashtree,
- &domain->nsec3->wchash_node);
- }
- if(domain != zone->apex && domain->nsec3 &&
- domain->nsec3->dshash_node.key &&
- (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) &&
- !nsec3_condition_dshash(domain, zone)) {
- /* remove precompile */
- domain->nsec3->nsec3_ds_parent_cover = NULL;
- domain->nsec3->nsec3_ds_parent_is_exact = 0;
- /* remove it from the hash tree */
- zone_del_domain_in_hash_tree(zone->dshashtree,
- &domain->nsec3->dshash_node);
- }
-}
-
-/* see if domain needs to get precompiled info */
-static void
-nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain,
- zone_type* zone)
-{
- if(!zone->nsec3_param)
- return;
- if((!domain->nsec3 || !domain->nsec3->hash_node.key)
- && nsec3_condition_hash(domain, zone)) {
- region_type* tmpregion = region_create(xalloc, free);
- nsec3_precompile_domain(db, domain, zone, tmpregion);
- region_destroy(tmpregion);
- }
- if((!domain->nsec3 || !domain->nsec3->dshash_node.key)
- && nsec3_condition_dshash(domain, zone)) {
- nsec3_precompile_domain_ds(db, domain, zone);
- }
-}
-
-/* see if nsec3 rrset-deletion triggers need action */
-static void
-nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain,
- zone_type* zone, uint16_t type)
-{
- if(!zone->nsec3_param)
- return;
- nsec3_rrsets_changed_remove_prehash(domain, zone);
- /* for type nsec3, or a delegation, the domain may have become a
- * 'normal' domain with its remaining data now */
- if(type == TYPE_NSEC3 || type == TYPE_NS || type == TYPE_DS)
- nsec3_rrsets_changed_add_prehash(db, domain, zone);
- /* for type DNAME or a delegation, obscured data may be revealed */
- if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
- /* walk over subdomains and check them each */
- domain_type *d;
- for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
- d=domain_next(d)) {
- nsec3_rrsets_changed_add_prehash(db, d, zone);
- }
- }
-}
-
-/* see if nsec3 addition triggers need action */
-static void
-nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone,
- udb_ptr* udbz)
-{
- /* the RR has been added in full, also to UDB (and thus NSEC3PARAM
- * in the udb has been adjusted) */
- if(zone->nsec3_param && rr->type == TYPE_NSEC3 &&
- (!rr->owner->nsec3 || !rr->owner->nsec3->nsec3_node.key)
- && nsec3_rr_uses_params(rr, zone)) {
- /* added NSEC3 into the chain */
- nsec3_precompile_nsec3rr(db, rr->owner, zone);
- /* the domain has become an NSEC3-domain, if it was precompiled
- * previously, remove that, neatly done in routine above */
- nsec3_rrsets_changed_remove_prehash(rr->owner, zone);
- /* set this NSEC3 to prehash */
- prehash_add(db->domains, rr->owner);
- } else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) {
- /* see if this means NSEC3 chain can be used */
- nsec3_find_zone_param(db, zone, udbz, NULL);
- if(!zone->nsec3_param)
- return;
- nsec3_zone_trees_create(db->region, zone);
- nsec3_precompile_newparam(db, zone);
- }
-}
-
-/* see if nsec3 rrset-addition triggers need action */
-static void
-nsec3_add_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone,
- uint16_t type)
-{
- /* the rrset has been added so we can inspect it */
- if(!zone->nsec3_param)
- return;
- /* because the rrset is added we can check conditions easily.
- * check if domain needs to become precompiled now */
- nsec3_rrsets_changed_add_prehash(db, domain, zone);
- /* if a delegation, it changes from normal name to unhashed referral */
- if(type == TYPE_NS || type == TYPE_DS) {
- nsec3_rrsets_changed_remove_prehash(domain, zone);
- }
- /* if delegation or DNAME added, then some RRs may get obscured */
- if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
- /* walk over subdomains and check them each */
- domain_type *d;
- for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
- d=domain_next(d)) {
- nsec3_rrsets_changed_remove_prehash(d, zone);
- }
- }
-}
-#endif /* NSEC3 */
-
-/* fixup usage lower for domain names in the rdata */
-static void
-rr_lower_usage(namedb_type* db, rr_type* rr)
-{
- unsigned i;
- for(i=0; i<rr->rdata_count; i++) {
- if(rdata_atom_is_domain(rr->type, i)) {
- assert(rdata_atom_domain(rr->rdatas[i])->usage > 0);
- rdata_atom_domain(rr->rdatas[i])->usage --;
- if(rdata_atom_domain(rr->rdatas[i])->usage == 0)
- domain_table_deldomain(db,
- rdata_atom_domain(rr->rdatas[i]));
- }
- }
-}
-
-static void
-rrset_lower_usage(namedb_type* db, rrset_type* rrset)
-{
- unsigned i;
- for(i=0; i<rrset->rr_count; i++)
- rr_lower_usage(db, &rrset->rrs[i]);
+ return -1;
}
-int
+static int
delete_RR(namedb_type* db, const dname_type* dname,
uint16_t type, uint16_t klass,
buffer_type* packet, size_t rdatalen, zone_type *zone,
- region_type* temp_region, udb_ptr* udbz, int* softfail)
+ region_type* temp_region)
{
domain_type *domain;
rrset_type *rrset;
@@ -631,7 +383,6 @@ delete_RR(namedb_type* db, const dname_type* dname,
log_msg(LOG_WARNING, "diff: domain %s does not exist",
dname_to_string(dname,0));
buffer_skip(packet, rdatalen);
- *softfail = 1;
return 1; /* not fatal error */
}
rrset = domain_find_rrset(domain, zone, type);
@@ -639,7 +390,6 @@ delete_RR(namedb_type* db, const dname_type* dname,
log_msg(LOG_WARNING, "diff: rrset %s does not exist",
dname_to_string(dname,0));
buffer_skip(packet, rdatalen);
- *softfail = 1;
return 1; /* not fatal error */
} else {
/* find the RR in the rrset */
@@ -658,37 +408,15 @@ delete_RR(namedb_type* db, const dname_type* dname,
dname_to_string(dname,0));
return 0;
}
- rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0);
- if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex
- && rrset->rr_count != 0)
- rrnum = 0; /* replace existing SOA if no match */
+ rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num);
if(rrnum == -1) {
- log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist",
- dname_to_string(dname,0), rrtype_to_string(type));
- *softfail = 1;
+ log_msg(LOG_WARNING, "diff: RR %s does not exist",
+ dname_to_string(dname,0));
return 1; /* not fatal error */
}
- /* delete the normalized RR from the udb */
- if(db->udb)
- udb_del_rr(db->udb, udbz, &rrset->rrs[rrnum]);
-#ifdef NSEC3
- /* process triggers for RR deletions */
- nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone, udbz);
-#endif
- /* lower usage (possibly deleting other domains, and thus
- * invalidating the current RR's domain pointers) */
- rr_lower_usage(db, &rrset->rrs[rrnum]);
if(rrset->rr_count == 1) {
/* delete entire rrset */
rrset_delete(db, domain, rrset);
- /* check if domain is now nonexisting (or parents) */
- rrset_zero_nonexist_check(domain);
-#ifdef NSEC3
- /* cleanup nsec3 */
- nsec3_delete_rrset_trigger(db, domain, zone, type);
-#endif
- /* see if the domain can be deleted (and inspect parents) */
- domain_table_deldomain(db, domain);
} else {
/* swap out the bad RR and decrease the count */
rr_type* rrs_orig = rrset->rrs;
@@ -705,41 +433,16 @@ delete_RR(namedb_type* db, const dname_type* dname,
}
region_recycle(db->region, rrs_orig,
sizeof(rr_type) * rrset->rr_count);
-#ifdef NSEC3
- if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
- /* fixup nsec3_param pointer to same RR */
- assert(zone->nsec3_param >= rrs_orig &&
- zone->nsec3_param <=
- rrs_orig+rrset->rr_count);
- /* last moved to rrnum, others at same index*/
- if(zone->nsec3_param == &rrs_orig[
- rrset->rr_count-1])
- zone->nsec3_param = &rrset->rrs[rrnum];
- else
- zone->nsec3_param =
- (void*)zone->nsec3_param
- -(void*)rrs_orig +
- (void*)rrset->rrs;
- }
-#endif /* NSEC3 */
rrset->rr_count --;
-#ifdef NSEC3
- /* for type nsec3, the domain may have become a
- * 'normal' domain with its remaining data now */
- if(type == TYPE_NSEC3)
- nsec3_rrsets_changed_add_prehash(db, domain,
- zone);
-#endif /* NSEC3 */
}
}
return 1;
}
-int
+static int
add_RR(namedb_type* db, const dname_type* dname,
uint16_t type, uint16_t klass, uint32_t ttl,
- buffer_type* packet, size_t rdatalen, zone_type *zone, udb_ptr* udbz,
- int* softfail)
+ buffer_type* packet, size_t rdatalen, zone_type *zone)
{
domain_type* domain;
rrset_type* rrset;
@@ -747,7 +450,6 @@ add_RR(namedb_type* db, const dname_type* dname,
rr_type *rrs_old;
ssize_t rdata_num;
int rrnum;
- int rrset_added = 0;
domain = domain_table_find(db->domains, dname);
if(!domain) {
/* create the domain */
@@ -765,7 +467,6 @@ add_RR(namedb_type* db, const dname_type* dname,
rrset->rrs = 0;
rrset->rr_count = 0;
domain_add_rrset(domain, rrset);
- rrset_added = 1;
}
/* dnames in rdata are normalized, conform RFC 4035,
@@ -778,12 +479,11 @@ add_RR(namedb_type* db, const dname_type* dname,
dname_to_string(dname,0));
return 0;
}
- rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 1);
+ rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num);
if(rrnum != -1) {
- DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists",
- dname_to_string(dname,0), rrtype_to_string(type)));
+ DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR %s already exists",
+ dname_to_string(dname,0)));
/* ignore already existing RR: lenient accepting of messages */
- *softfail = 1;
return 1;
}
@@ -809,150 +509,157 @@ add_RR(namedb_type* db, const dname_type* dname,
/* see if it is a SOA */
if(domain == zone->apex) {
- apex_rrset_checks(db, rrset, domain);
-#ifdef NSEC3
- if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
- /* the pointer just changed, fix it up to point
- * to the same record */
- assert(zone->nsec3_param >= rrs_old &&
- zone->nsec3_param < rrs_old+rrset->rr_count);
- /* in this order to make sure no overflow/underflow*/
- zone->nsec3_param = (void*)zone->nsec3_param -
- (void*)rrs_old + (void*)rrset->rrs;
+ if(type == TYPE_SOA) {
+ uint32_t soa_minimum;
+ zone->soa_rrset = rrset;
+ zone->updated = 1;
+ /* BUG #103 tweaked SOA ttl value */
+ if(zone->soa_nx_rrset == 0) {
+ zone->soa_nx_rrset = region_alloc(db->region,
+ sizeof(rrset_type));
+ if(!zone->soa_nx_rrset) {
+ log_msg(LOG_ERR, "out of memory, %s:%d",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ zone->soa_nx_rrset->rr_count = 1;
+ zone->soa_nx_rrset->next = 0;
+ zone->soa_nx_rrset->zone = zone;
+ zone->soa_nx_rrset->rrs = region_alloc(db->region,
+ sizeof(rr_type));
+ if(!zone->soa_nx_rrset->rrs) {
+ log_msg(LOG_ERR, "out of memory, %s:%d",
+ __FILE__, __LINE__);
+ exit(1);
+ }
+ }
+ memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type));
+ memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]),
+ rdata_atom_size(rrset->rrs->rdatas[6]));
+ if (rrset->rrs->ttl > ntohl(soa_minimum)) {
+ rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum);
+ }
}
-#endif /* NSEC3 */
- }
-
- /* write the just-normalized RR to the udb */
- if(db->udb) {
- if(!udb_write_rr(db->udb, udbz, &rrset->rrs[rrset->rr_count - 1])) {
- log_msg(LOG_ERR, "could not add RR to nsd.db, disk-space?");
- return 0;
+ if(type == TYPE_NS) {
+ zone->ns_rrset = rrset;
}
- }
-#ifdef NSEC3
- if(rrset_added) {
- domain_type* p = domain->parent;
- nsec3_add_rrset_trigger(db, domain, zone, type);
- /* go up and process (possibly created) empty nonterminals,
- * until we hit the apex or root */
- while(p && p->rrsets == NULL && !p->is_apex) {
- nsec3_rrsets_changed_add_prehash(db, p, zone);
- p = p->parent;
+#ifdef DNSSEC
+ if(type == TYPE_RRSIG) {
+ int i;
+ for (i = 0; i < rrset->rr_count; ++i) {
+ if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_SOA) {
+ zone->is_secure = 1;
+ break;
+ }
+ }
}
+#endif
}
- nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone, udbz);
-#endif /* NSEC3 */
return 1;
}
static zone_type*
-find_or_create_zone(namedb_type* db, const dname_type* zone_name,
- nsd_options_t* opt, const char* zstr, const char* patname)
+find_zone(namedb_type* db, const dname_type* zone_name, nsd_options_t* opt,
+ size_t child_count)
{
+ domain_type *domain;
zone_type* zone;
- zone_options_t* zopt;
- zone = namedb_find_zone(db, zone_name);
- if(zone) {
- return zone;
- }
- zopt = zone_options_find(opt, zone_name);
- if(!zopt) {
- /* if _implicit_ then insert as _part_of_config */
- if(strncmp(patname, PATTERN_IMPLICIT_MARKER,
- strlen(PATTERN_IMPLICIT_MARKER)) == 0) {
- zopt = zone_options_create(opt->region);
- if(!zopt) return 0;
- zopt->part_of_config = 1;
- zopt->name = region_strdup(opt->region, zstr);
- zopt->pattern = pattern_options_find(opt, patname);
- if(!zopt->name || !zopt->pattern) return 0;
- if(!nsd_options_insert_zone(opt, zopt)) {
- log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
- "pattern %s", zstr, patname);
- }
- } else {
- /* create zone : presumably already added to zonelist
- * by xfrd, who wrote the AXFR or IXFR to disk, so we only
- * need to add it to our config.
- * This process does not need linesize and offset zonelist */
- zopt = zone_list_zone_insert(opt, zstr, patname, 0, 0);
- if(!zopt)
- return 0;
+ domain = domain_table_find(db->domains, zone_name);
+ if(!domain) {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfr: creating domain %s",
+ dname_to_string(zone_name,0)));
+ /* create the zone and domain of apex (zone has config options) */
+ domain = domain_table_insert(db->domains, zone_name);
+ } else {
+ /* O(1) if SOA exists */
+ zone = domain_find_zone(domain);
+ /* if domain was empty (no rrsets, empty zone) search in zonelist */
+ /* check apex to make sure we don't find a parent zone */
+ if(!zone || zone->apex != domain)
+ zone = namedb_find_zone(db, domain);
+ if(zone) {
+ assert(zone->apex == domain);
+ return zone;
}
}
- zone = namedb_zone_create(db, zone_name, zopt);
+ /* create the zone */
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfr: creating zone_type %s",
+ dname_to_string(zone_name,0)));
+ zone = (zone_type *) region_alloc(db->region, sizeof(zone_type));
+ if(!zone) {
+ log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
+ exit(1);
+ }
+ zone->next = db->zones;
+ db->zones = zone;
+ db->zone_count++;
+ zone->apex = domain;
+ zone->soa_rrset = 0;
+ zone->soa_nx_rrset = 0;
+ zone->ns_rrset = 0;
+#ifdef NSEC3
+ zone->nsec3_soa_rr = NULL;
+ zone->nsec3_last = NULL;
+#endif
+ zone->dirty = region_alloc(db->region, sizeof(uint8_t)*child_count);
+ if(!zone->dirty) {
+ log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
+ exit(1);
+ }
+ memset(zone->dirty, 0, sizeof(uint8_t)*child_count);
+ zone->opts = zone_options_find(opt, domain_dname(zone->apex));
+ if(!zone->opts) {
+ log_msg(LOG_ERR, "xfr: zone %s not in config.",
+ dname_to_string(zone_name,0));
+ return 0;
+ }
+ zone->number = db->zone_count;
+ zone->is_secure = 0;
+ zone->updated = 1;
+ zone->is_ok = 0;
return zone;
}
-void
+static void
delete_zone_rrs(namedb_type* db, zone_type* zone)
{
rrset_type *rrset;
- domain_type *domain = zone->apex, *next;
- int nonexist_check = 0;
+ domain_type *domain = zone->apex;
/* go through entire tree below the zone apex (incl subzones) */
- while(domain && domain_is_subdomain(domain, zone->apex))
+ while(domain && dname_is_subdomain(
+ domain_dname(domain), domain_dname(zone->apex)))
{
DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s",
- domain_to_string(domain)));
+ dname_to_string(domain_dname(domain),0)));
/* delete all rrsets of the zone */
while((rrset = domain_find_any_rrset(domain, zone))) {
- /* lower usage can delete other domains */
- rrset_lower_usage(db, rrset);
- /* rrset del does not delete our domain(yet) */
rrset_delete(db, domain, rrset);
- /* no rrset_zero_nonexist_check, do that later */
- if(domain->rrsets == 0)
- nonexist_check = 1;
- }
- /* the delete upcoming could delete parents, but nothing next
- * or after the domain so store next ptr */
- next = domain_next(domain);
- /* see if the domain can be deleted (and inspect parents) */
- domain_table_deldomain(db, domain);
- domain = next;
- }
-
- /* check if data deleteions have created nonexisting domain entries,
- * but after deleting domains so the checks are faster */
- if(nonexist_check) {
- DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check"));
- domain = zone->apex;
- while(domain && domain_is_subdomain(domain, zone->apex))
- {
- /* the interesting domains should be existing==1
- * and rrsets==0, speeding up out processing of
- * sub-zones, since we only spuriously check empty
- * nonterminals */
- if(domain->is_existing)
- rrset_zero_nonexist_check(domain);
- domain = domain_next(domain);
}
+ domain = domain_next(domain);
}
DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes",
(unsigned long) region_get_recycle_size(db->region)));
#ifndef NDEBUG
- if(nsd_debug_level >= 2)
+ if(nsd_debug_level >= 1)
region_log_stats(db->region);
#endif
assert(zone->soa_rrset == 0);
- /* keep zone->soa_nx_rrset alloced: it is reused */
+ /* keep zone->soa_nx_rrset alloced */
assert(zone->ns_rrset == 0);
assert(zone->is_secure == 0);
+ assert(zone->updated == 1);
}
-/* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */
static int
-apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
- nsd_options_t* opt, uint32_t seq_nr, uint32_t seq_total,
+apply_ixfr(namedb_type* db, FILE *in, const off_t* startpos,
+ const char* zone, uint32_t serialno, nsd_options_t* opt,
+ uint16_t id, uint32_t seq_nr, uint32_t seq_total,
int* is_axfr, int* delete_mode, int* rr_count,
- udb_ptr* udbz, struct zone** zone_res, const char* patname, int* bytes,
- int* softfail)
+ size_t child_count)
{
- uint32_t msglen, checklen, pkttype;
+ uint32_t filelen, msglen, pkttype, timestamp[2];
int qcount, ancount, counter;
buffer_type* packet;
region_type* region;
@@ -960,24 +667,35 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
uint16_t rrlen;
const dname_type *dname_zone, *dname;
zone_type* zone_db;
-
- /* note that errors could not really happen due to format of the
- * packet since xfrd has checked all dnames and RRs before commit,
- * this is why the errors are fatal (exit process), it must be
- * something internal or a bad disk or something. */
-
+ char file_zone_name[3072];
+ uint32_t file_serial, file_seq_nr;
+ uint16_t file_id;
+ off_t mempos;
+
+ memmove(&mempos, startpos, sizeof(off_t));
+ if(fseeko(in, mempos, SEEK_SET) == -1) {
+ log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno));
+ return 0;
+ }
/* read ixfr packet RRs and apply to in memory db */
- if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_XXFR) {
+
+ if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_IXFR) {
log_msg(LOG_ERR, "could not read type or wrong type");
return 0;
}
+ if(!diff_read_32(in, &timestamp[0]) ||
+ !diff_read_32(in, &timestamp[1])) {
+ log_msg(LOG_ERR, "could not read timestamp");
+ return 0;
+ }
- if(!diff_read_32(in, &msglen)) {
+ if(!diff_read_32(in, &filelen)) {
log_msg(LOG_ERR, "could not read len");
return 0;
}
- if(msglen < QHEADERSZ) {
+ /* read header */
+ if(filelen < QHEADERSZ + sizeof(uint32_t)*3 + sizeof(uint16_t)) {
log_msg(LOG_ERR, "msg too short");
return 0;
}
@@ -987,7 +705,34 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
log_msg(LOG_ERR, "out of memory");
return 0;
}
+
+ if(!diff_read_str(in, file_zone_name, sizeof(file_zone_name)) ||
+ !diff_read_32(in, &file_serial) ||
+ !diff_read_16(in, &file_id) ||
+ !diff_read_32(in, &file_seq_nr))
+ {
+ log_msg(LOG_ERR, "could not part data");
+ region_destroy(region);
+ return 0;
+ }
+
+ if(strcmp(file_zone_name, zone) != 0 || serialno != file_serial ||
+ id != file_id || seq_nr != file_seq_nr) {
+ log_msg(LOG_ERR, "internal error: reading part with changed id");
+ region_destroy(region);
+ return 0;
+ }
+ msglen = filelen - sizeof(uint32_t)*3 - sizeof(uint16_t)
+ - strlen(file_zone_name);
packet = buffer_create(region, QIOBUFSZ);
+ dname_zone = dname_parse(region, zone);
+ zone_db = find_zone(db, dname_zone, opt, child_count);
+ if(!zone_db) {
+ log_msg(LOG_ERR, "no zone exists");
+ region_destroy(region);
+ return 0;
+ }
+
if(msglen > QIOBUFSZ) {
log_msg(LOG_ERR, "msg too long");
region_destroy(region);
@@ -1001,23 +746,6 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
}
buffer_set_limit(packet, msglen);
- /* see if check on data fails: checks that we are not reading
- * random garbage */
- if(!diff_read_32(in, &checklen) || checklen != msglen) {
- log_msg(LOG_ERR, "transfer part has incorrect checkvalue");
- return 0;
- }
- *bytes += msglen;
-
- dname_zone = dname_parse(region, zone);
- zone_db = find_or_create_zone(db, dname_zone, opt, zone, patname);
- if(!zone_db) {
- log_msg(LOG_ERR, "could not create zone %s %s", zone, patname);
- region_destroy(region);
- return 0;
- }
- *zone_res = zone_db;
-
/* only answer section is really used, question, additional and
authority section RRs are skipped */
qcount = QDCOUNT(packet);
@@ -1073,8 +801,8 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
}
if(buffer_read_u32(packet) != serialno) {
buffer_skip(packet, -4);
- log_msg(LOG_ERR, "SOA serial %u different from commit %u",
- (unsigned)buffer_read_u32(packet), (unsigned)serialno);
+ log_msg(LOG_ERR, "SOA serial %d different from commit %d",
+ buffer_read_u32(packet), serialno);
region_destroy(region);
return 0;
}
@@ -1083,6 +811,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
*rr_count = 1;
*is_axfr = 0;
*delete_mode = 0;
+
DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d",
dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
}
@@ -1118,16 +847,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
if(*rr_count == 1 && type != TYPE_SOA) {
/* second RR: if not SOA: this is an AXFR; delete all zone contents */
-#ifdef NSEC3
- nsec3_hash_tree_clear(zone_db);
-#endif
delete_zone_rrs(db, zone_db);
- if(db->udb)
- udb_zone_clear(db->udb, udbz);
-#ifdef NSEC3
- nsec3_clear_precompile(db, zone_db);
- zone_db->nsec3_param = NULL;
-#endif /* NSEC3 */
/* add everything else (incl end SOA) */
*delete_mode = 0;
*is_axfr = 1;
@@ -1149,30 +869,10 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
thisserial = buffer_read_u32(packet);
if(thisserial == serialno) {
/* AXFR */
-#ifdef NSEC3
- nsec3_hash_tree_clear(zone_db);
-#endif
delete_zone_rrs(db, zone_db);
- if(db->udb)
- udb_zone_clear(db->udb, udbz);
-#ifdef NSEC3
- nsec3_clear_precompile(db, zone_db);
- zone_db->nsec3_param = NULL;
-#endif /* NSEC3 */
*delete_mode = 0;
*is_axfr = 1;
}
- /* must have stuff in memory for a successful IXFR,
- * the serial number of the SOA has been checked
- * previously (by check_for_bad_serial) if it exists */
- if(!*is_axfr && !domain_find_rrset(zone_db->apex,
- zone_db, TYPE_SOA)) {
- log_msg(LOG_ERR, "%s SOA serial %u is not "
- "in memory, skip IXFR", zone, serialno);
- region_destroy(region);
- /* break out and stop the IXFR, ignore it */
- return 2;
- }
buffer_set_position(packet, bufpos);
}
if(type == TYPE_SOA && !*is_axfr) {
@@ -1199,7 +899,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
continue; /* do not delete final SOA RR for IXFR */
}
if(!delete_RR(db, dname, type, klass, packet,
- rrlen, zone_db, region, udbz, softfail)) {
+ rrlen, zone_db, region)) {
region_destroy(region);
return 0;
}
@@ -1208,7 +908,7 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno,
{
/* add this rr */
if(!add_RR(db, dname, type, klass, ttl, packet,
- rrlen, zone_db, udbz, softfail)) {
+ rrlen, zone_db)) {
region_destroy(region);
return 0;
}
@@ -1228,7 +928,7 @@ check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial)
zone_type* zone = 0;
domain = domain_table_find(db->domains, zone_name);
if(domain)
- zone = domain_find_zone(db, domain);
+ zone = domain_find_zone(domain);
if(zone && zone->apex == domain && zone->soa_rrset && old_serial)
{
uint32_t memserial;
@@ -1243,796 +943,548 @@ check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial)
return 0;
}
+/* for multiple tcp packets use a data structure that has
+ * a rbtree (zone_names) with for each zone:
+ * has a rbtree by sequence number
+ * with inside a serial_number and ID (for checking only)
+ * and contains a off_t to the IXFR packet in the file.
+ * so when you get a commit for a zone, get zone obj, find sequence,
+ * then check if you have all sequence numbers available. Apply all packets.
+ */
+struct diff_read_data {
+ /* rbtree of struct diff_zone*/
+ rbtree_t* zones;
+ /* region for allocation */
+ region_type* region;
+};
+struct diff_zone {
+ /* key is dname of zone */
+ rbnode_t node;
+ /* rbtree of struct diff_xfrpart */
+ rbtree_t* parts;
+};
+struct diff_xfrpart {
+ /* key is sequence number */
+ rbnode_t node;
+ uint32_t seq_nr;
+ uint32_t new_serial;
+ uint16_t id;
+ off_t file_pos;
+};
+
+static struct diff_read_data*
+diff_read_data_create()
+{
+ region_type* region = region_create(xalloc, free);
+ struct diff_read_data* data = (struct diff_read_data*)
+ region_alloc(region, sizeof(struct diff_read_data));
+ if(!data) {
+ log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
+ exit(1);
+ }
+ data->region = region;
+ data->zones = rbtree_create(region,
+ (int (*)(const void *, const void *)) dname_compare);
+ return data;
+}
+
+static struct diff_zone*
+diff_read_find_zone(struct diff_read_data* data, const char* name)
+{
+ const dname_type* dname = dname_parse(data->region, name);
+ struct diff_zone* zp = (struct diff_zone*)
+ rbtree_search(data->zones, dname);
+ return zp;
+}
+
+static int intcompf(const void* a, const void* b)
+{
+ if(*(uint32_t*)a < *(uint32_t*)b)
+ return -1;
+ if(*(uint32_t*)a > *(uint32_t*)b)
+ return +1;
+ return 0;
+}
+
+static struct diff_zone*
+diff_read_insert_zone(struct diff_read_data* data, const char* name)
+{
+ const dname_type* dname = dname_parse(data->region, name);
+ struct diff_zone* zp = region_alloc(data->region,
+ sizeof(struct diff_zone));
+ if(!zp) {
+ log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
+ exit(1);
+ }
+ zp->node = *RBTREE_NULL;
+ zp->node.key = dname;
+ zp->parts = rbtree_create(data->region, intcompf);
+ rbtree_insert(data->zones, (rbnode_t*)zp);
+ return zp;
+}
+
+static struct diff_xfrpart*
+diff_read_find_part(struct diff_zone* zp, uint32_t seq_nr)
+{
+ struct diff_xfrpart* xp = (struct diff_xfrpart*)
+ rbtree_search(zp->parts, &seq_nr);
+ return xp;
+}
+
+static struct diff_xfrpart*
+diff_read_insert_part(struct diff_read_data* data,
+ struct diff_zone* zp, uint32_t seq_nr)
+{
+ struct diff_xfrpart* xp = region_alloc(data->region,
+ sizeof(struct diff_xfrpart));
+ if(!xp) {
+ log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
+ exit(1);
+ }
+ xp->node = *RBTREE_NULL;
+ xp->node.key = &xp->seq_nr;
+ xp->seq_nr = seq_nr;
+ rbtree_insert(zp->parts, (rbnode_t*)xp);
+ return xp;
+}
+
+/* mark commit as rollback and close inputfile, fatal exits */
+static void
+mark_and_exit(nsd_options_t* opt, FILE* f, off_t commitpos, const char* desc)
+{
+ const char* filename = opt->difffile;
+ fclose(f);
+ if(!(f = fopen(filename, "r+"))) {
+ log_msg(LOG_ERR, "mark xfr, failed to re-open difffile %s: %s",
+ filename, strerror(errno));
+ } else if(fseeko(f, commitpos, SEEK_SET) == -1) {
+ log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno));
+ fclose(f);
+ } else {
+ uint8_t c = 0;
+ fwrite(&c, sizeof(c), 1, f);
+ fclose(f);
+ log_msg(LOG_ERR, "marked xfr as failed: %s", desc);
+ log_msg(LOG_ERR, "marked xfr so that next reload can succeed");
+ }
+ exit(1);
+}
+
static int
-apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in,
- nsd_options_t* opt, udb_base* taskudb, udb_ptr* last_task,
- uint32_t xfrfilenr)
+read_sure_part(namedb_type* db, FILE *in, nsd_options_t* opt,
+ struct diff_read_data* data, struct diff_log** log,
+ size_t child_count)
{
char zone_buf[3072];
char log_buf[5120];
- char patname_buf[2048];
-
- uint32_t old_serial, new_serial, num_parts, type;
- uint64_t time_end_0, time_start_0;
- uint32_t time_end_1, time_start_1;
+ uint32_t old_serial, new_serial, num_parts;
+ uint16_t id;
uint8_t committed;
+ struct diff_zone *zp;
uint32_t i;
- int num_bytes = 0;
+ int have_all_parts = 1;
+ struct diff_log* thislog = 0;
+ off_t commitpos;
/* read zone name and serial */
- if(!diff_read_32(in, &type)) {
- log_msg(LOG_ERR, "diff file too short");
+ if(!diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
+ !diff_read_32(in, &old_serial) ||
+ !diff_read_32(in, &new_serial) ||
+ !diff_read_16(in, &id) ||
+ !diff_read_32(in, &num_parts)) {
+ log_msg(LOG_ERR, "diff file bad commit part");
return 0;
}
- if(type != DIFF_PART_XFRF) {
- log_msg(LOG_ERR, "xfr file has wrong format");
+ commitpos = ftello(in); /* position of commit byte */
+ if(commitpos == -1) {
+ log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
return 0;
-
}
- /* committed and num_parts are first because they need to be
- * updated once the rest is written. The log buf is not certain
- * until its done, so at end of file. The patname is in case a
- * new zone is created, we know what the options-pattern is */
if(!diff_read_8(in, &committed) ||
- !diff_read_32(in, &num_parts) ||
- !diff_read_64(in, &time_end_0) ||
- !diff_read_32(in, &time_end_1) ||
- !diff_read_32(in, &old_serial) ||
- !diff_read_32(in, &new_serial) ||
- !diff_read_64(in, &time_start_0) ||
- !diff_read_32(in, &time_start_1) ||
- !diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
- !diff_read_str(in, patname_buf, sizeof(patname_buf))) {
+ !diff_read_str(in, log_buf, sizeof(log_buf)) )
+ {
log_msg(LOG_ERR, "diff file bad commit part");
return 0;
}
- /* has been read in completely */
- if(strcmp(zone_buf, dname_to_string(zonedb->apex->dname,0)) != 0) {
- log_msg(LOG_ERR, "file %s does not match task %s",
- zone_buf, dname_to_string(zonedb->apex->dname,0));
- return 0;
- }
- if(!committed) {
- log_msg(LOG_ERR, "diff file %s was not committed", zone_buf);
- return 0;
+ if(log) {
+ thislog = (struct diff_log*)region_alloc(db->region, sizeof(struct diff_log));
+ if(!thislog) {
+ log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
+ exit(1);
+ }
+ thislog->zone_name = region_strdup(db->region, zone_buf);
+ thislog->comment = region_strdup(db->region, log_buf);
+ thislog->error = 0;
+ thislog->next = *log;
+ *log = thislog;
}
- if(num_parts == 0) {
- log_msg(LOG_ERR, "diff file %s was not completed", zone_buf);
- return 0;
+
+ /* has been read in completely */
+ zp = diff_read_find_zone(data, zone_buf);
+ if(!zp) {
+ log_msg(LOG_ERR, "diff file commit without IXFR");
+ if(thislog)
+ thislog->error = "error no IXFR parts";
+ return 1;
}
- if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) {
+ if(committed && check_for_bad_serial(db, zone_buf, old_serial)) {
DEBUG(DEBUG_XFRD,1, (LOG_ERR,
"skipping diff file commit with bad serial"));
+ zp->parts->root = RBTREE_NULL;
+ zp->parts->count = 0;
+ if(thislog)
+ thislog->error = "error bad serial";
return 1;
}
+ for(i=0; i<num_parts; i++) {
+ struct diff_xfrpart *xp = diff_read_find_part(zp, i);
+ if(!xp || xp->id != id || xp->new_serial != new_serial) {
+ have_all_parts = 0;
+ }
+ }
+ if(!have_all_parts) {
+ DEBUG(DEBUG_XFRD,1, (LOG_ERR,
+ "skipping diff file commit without all parts"));
+ if(thislog)
+ thislog->error = "error missing parts";
+ }
- if(committed)
+ if(committed && have_all_parts)
{
- int is_axfr=0, delete_mode=0, rr_count=0, softfail=0;
- const dname_type* apex = zonedb->apex->dname;
- udb_ptr z;
-
- DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf));
- if(nsd->db->udb) {
- if(udb_base_get_userflags(nsd->db->udb) != 0) {
- log_msg(LOG_ERR, "database corrupted, cannot update");
- xfrd_unlink_xfrfile(nsd, xfrfilenr);
- exit(1);
- }
- /* all parts were checked by xfrd before commit */
- if(!udb_zone_search(nsd->db->udb, &z, dname_name(apex),
- apex->name_size)) {
- /* create it */
- if(!udb_zone_create(nsd->db->udb, &z, dname_name(apex),
- apex->name_size)) {
- /* out of disk space perhaps */
- log_msg(LOG_ERR, "could not udb_create_zone "
- "%s, disk space full?", log_buf);
- return 0;
- }
- }
- /* set the udb dirty until we are finished applying changes */
- udb_base_set_userflags(nsd->db->udb, 1);
+ int is_axfr=0, delete_mode=0, rr_count=0;
+ off_t resume_pos;
+
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", log_buf));
+ resume_pos = ftello(in);
+ if(resume_pos == -1) {
+ log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
+ return 0;
}
- /* read and apply all of the parts */
for(i=0; i<num_parts; i++) {
- int ret;
+ struct diff_xfrpart *xp = diff_read_find_part(zp, i);
DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i));
- ret = apply_ixfr(nsd->db, in, zone_buf, new_serial, opt,
- i, num_parts, &is_axfr, &delete_mode,
- &rr_count, (nsd->db->udb?&z:NULL), &zonedb,
- patname_buf, &num_bytes, &softfail);
- if(ret == 0) {
- log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf);
- xfrd_unlink_xfrfile(nsd, xfrfilenr);
- /* the udb is still dirty, it is bad */
- exit(1);
- } else if(ret == 2) {
- break;
+ if(!apply_ixfr(db, in, &xp->file_pos, zone_buf, new_serial, opt,
+ id, xp->seq_nr, num_parts, &is_axfr, &delete_mode,
+ &rr_count, child_count)) {
+ log_msg(LOG_ERR, "bad ixfr packet part %d in %s", (int)i,
+ opt->difffile);
+ mark_and_exit(opt, in, commitpos, log_buf);
}
}
- if(nsd->db->udb)
- udb_base_set_userflags(nsd->db->udb, 0);
- /* read the final log_str: but do not fail on it */
- if(!diff_read_str(in, log_buf, sizeof(log_buf))) {
- log_msg(LOG_ERR, "could not read log for transfer %s",
- zone_buf);
- snprintf(log_buf, sizeof(log_buf), "error reading log");
- }
-#ifdef NSEC3
- if(zonedb) prehash_zone(nsd->db, zonedb);
-#endif /* NSEC3 */
- zonedb->is_changed = 1;
- if(nsd->db->udb) {
- ZONE(&z)->is_changed = 1;
- ZONE(&z)->mtime = time_end_0;
- udb_zone_set_log_str(nsd->db->udb, &z, log_buf);
- udb_zone_set_file_str(nsd->db->udb, &z, NULL);
- udb_ptr_unlink(&z, nsd->db->udb);
- } else {
- zonedb->mtime = time_end_0;
- if(zonedb->logstr)
- region_recycle(nsd->db->region, zonedb->logstr,
- strlen(zonedb->logstr)+1);
- zonedb->logstr = region_strdup(nsd->db->region, log_buf);
- if(zonedb->filename)
- region_recycle(nsd->db->region, zonedb->filename,
- strlen(zonedb->filename)+1);
- zonedb->filename = NULL;
- }
- if(softfail && taskudb && !is_axfr) {
- log_msg(LOG_ERR, "Failed to apply IXFR cleanly "
- "(deletes nonexistent RRs, adds existing RRs). "
- "Zone %s contents is different from master, "
- "starting AXFR. Transfer %s", zone_buf, log_buf);
- /* add/del failures in IXFR, get an AXFR */
- task_new_soainfo(taskudb, last_task, zonedb, 1);
- } else {
- if(taskudb)
- task_new_soainfo(taskudb, last_task, zonedb, 0);
- }
-
- if(1 <= verbosity) {
- double elapsed = (double)(time_end_0 - time_start_0)+
- (double)((double)time_end_1
- -(double)time_start_1) / 1000000.0;
- VERBOSITY(2, (LOG_INFO, "zone %s %s of %d bytes in %g seconds",
- zone_buf, log_buf, num_bytes, elapsed));
+ if(fseeko(in, resume_pos, SEEK_SET) == -1) {
+ log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno));
+ return 0;
}
}
else {
DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", log_buf));
}
- return 1;
-}
-struct udb_base* task_file_create(const char* file)
-{
- return udb_base_create_new(file, &namedb_walkfunc, NULL);
+ /* clean out the parts for the zone after the commit/rollback */
+ zp->parts->root = RBTREE_NULL;
+ zp->parts->count = 0;
+ return 1;
}
static int
-task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e,
- size_t sz, const dname_type* zname)
-{
- if(!udb_ptr_alloc_space(e, udb, udb_chunk_type_task, sz)) {
+store_ixfr_data(FILE *in, uint32_t len, struct diff_read_data* data, off_t* startpos)
+{
+ char zone_name[3072];
+ struct diff_zone* zp;
+ struct diff_xfrpart* xp;
+ uint32_t new_serial, seq;
+ uint16_t id;
+ if(!diff_read_str(in, zone_name, sizeof(zone_name)) ||
+ !diff_read_32(in, &new_serial) ||
+ !diff_read_16(in, &id) ||
+ !diff_read_32(in, &seq)) {
+ log_msg(LOG_INFO, "could not read ixfr store info: file format error");
return 0;
}
- if(udb_ptr_is_null(last)) {
- udb_base_set_userdata(udb, e->data);
- } else {
- udb_rptr_set_ptr(&TASKLIST(last)->next, udb, e);
+ len -= sizeof(uint32_t)*3 + sizeof(uint16_t) + strlen(zone_name);
+ if(fseeko(in, len, SEEK_CUR) == -1)
+ log_msg(LOG_INFO, "fseek failed: %s", strerror(errno));
+ /* store the info */
+ zp = diff_read_find_zone(data, zone_name);
+ if(!zp)
+ zp = diff_read_insert_zone(data, zone_name);
+ xp = diff_read_find_part(zp, seq);
+ if(xp) {
+ log_msg(LOG_INFO, "discarding partial xfr part: %s %d", zone_name, seq);
+ /* overwrite with newer value (which probably relates to next commit) */
}
- udb_ptr_set_ptr(last, udb, e);
-
- /* fill in tasklist item */
- udb_rel_ptr_init(&TASKLIST(e)->next);
- TASKLIST(e)->size = sz;
- TASKLIST(e)->oldserial = 0;
- TASKLIST(e)->newserial = 0;
- TASKLIST(e)->yesno = 0;
-
- if(zname) {
- memmove(TASKLIST(e)->zname, zname, dname_total_size(zname));
+ else {
+ xp = diff_read_insert_part(data, zp, seq);
}
+ xp->new_serial = new_serial;
+ xp->id = id;
+ memmove(&xp->file_pos, startpos, sizeof(off_t));
return 1;
}
-void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z,
- int gone)
+static int
+read_process_part(namedb_type* db, FILE *in, uint32_t type,
+ nsd_options_t* opt, struct diff_read_data* data,
+ struct diff_log** log, size_t child_count, off_t* startpos)
{
- /* calculate size */
- udb_ptr e;
- size_t sz;
- const dname_type* apex, *ns, *em;
- if(!z || !z->apex || !domain_dname(z->apex))
- return; /* safety check */
-
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "nsd: add soa info for zone %s",
- domain_to_string(z->apex)));
- apex = domain_dname(z->apex);
- sz = sizeof(struct task_list_d) + dname_total_size(apex);
- if(z->soa_rrset && !gone) {
- ns = domain_dname(rdata_atom_domain(
- z->soa_rrset->rrs[0].rdatas[0]));
- em = domain_dname(rdata_atom_domain(
- z->soa_rrset->rrs[0].rdatas[1]));
- sz += sizeof(uint32_t)*6 + sizeof(uint8_t)*2
- + ns->name_size + em->name_size;
- } else {
- ns = 0;
- em = 0;
- }
+ uint32_t len, len2;
- /* create new task_list item */
- if(!task_create_new_elem(udb, last, &e, sz, apex)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add SOAINFO");
- return;
+ /* read length */
+ if(!diff_read_32(in, &len))
+ return 1;
+ /* read content */
+ if(type == DIFF_PART_IXFR) {
+ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "part IXFR len %d", len));
+ if(!store_ixfr_data(in, len, data, startpos))
+ return 0;
}
- TASKLIST(&e)->task_type = task_soa_info;
-
- if(z->soa_rrset && !gone) {
- uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl);
- uint8_t* p = (uint8_t*)TASKLIST(&e)->zname;
- p += dname_total_size(apex);
- memmove(p, &ttl, sizeof(uint32_t));
- p += sizeof(uint32_t);
- memmove(p, &ns->name_size, sizeof(uint8_t));
- p += sizeof(uint8_t);
- memmove(p, dname_name(ns), ns->name_size);
- p += ns->name_size;
- memmove(p, &em->name_size, sizeof(uint8_t));
- p += sizeof(uint8_t);
- memmove(p, dname_name(em), em->name_size);
- p += em->name_size;
- memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[2]),
- sizeof(uint32_t));
- p += sizeof(uint32_t);
- memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[3]),
- sizeof(uint32_t));
- p += sizeof(uint32_t);
- memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[4]),
- sizeof(uint32_t));
- p += sizeof(uint32_t);
- memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[5]),
- sizeof(uint32_t));
- p += sizeof(uint32_t);
- memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[6]),
- sizeof(uint32_t));
+ else if(type == DIFF_PART_SURE) {
+ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "part SURE len %d", len));
+ if(!read_sure_part(db, in, opt, data, log, child_count))
+ return 0;
+ } else {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "unknown part %x len %d", type, len));
+ return 0;
}
- udb_ptr_unlink(&e, udb);
-}
-
-void task_process_sync(struct udb_base* taskudb)
-{
- /* need to sync before other process uses the mmap? */
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "task procsync %s size %d",
- taskudb->fname, (int)taskudb->base_size));
- (void)taskudb;
-}
-
-void task_remap(struct udb_base* taskudb)
-{
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "task remap %s size %d",
- taskudb->fname, (int)taskudb->glob_data->fsize));
- udb_base_remap_process(taskudb);
+ /* read length */
+ if(!diff_read_32(in, &len2))
+ return 1; /* short read is OK */
+ /* verify length */
+ if(len != len2)
+ return 0; /* bad data is wrong */
+ return 1;
}
-void task_clear(struct udb_base* taskudb)
+/*
+ * Finds smallest offset in data structs
+ * returns 0 if no offsets in the data structs.
+ */
+static int
+find_smallest_offset(struct diff_read_data* data, off_t* offset)
{
- udb_ptr t, n;
- udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb));
- udb_base_set_userdata(taskudb, 0);
- udb_ptr_init(&n, taskudb);
- while(!udb_ptr_is_null(&t)) {
- udb_ptr_set_rptr(&n, taskudb, &TASKLIST(&t)->next);
- udb_rptr_zero(&TASKLIST(&t)->next, taskudb);
- udb_ptr_free_space(&t, taskudb, TASKLIST(&t)->size);
- udb_ptr_set_ptr(&t, taskudb, &n);
- }
- udb_ptr_unlink(&t, taskudb);
- udb_ptr_unlink(&n, taskudb);
-}
+ int found_any = 0;
+ struct diff_zone* dz;
+ struct diff_xfrpart* dx;
+ off_t mem_offset, mem_fpos;
-void task_new_expire(struct udb_base* udb, udb_ptr* last,
- const struct dname* z, int expired)
-{
- udb_ptr e;
- if(!z) return;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add expire info for zone %s",
- dname_to_string(z,NULL)));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
- dname_total_size(z), z)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add expire");
- return;
- }
- TASKLIST(&e)->task_type = task_expire;
- TASKLIST(&e)->yesno = expired;
- udb_ptr_unlink(&e, udb);
-}
+ if(!data || !data->zones)
+ return 0;
+ RBTREE_FOR(dz, struct diff_zone*, data->zones)
+ {
+ if(!dz->parts)
+ continue;
+ RBTREE_FOR(dx, struct diff_xfrpart*, dz->parts)
+ {
+ memmove(&mem_fpos, &dx->file_pos, sizeof(off_t));
-void task_new_check_zonefiles(udb_base* udb, udb_ptr* last,
- const dname_type* zone)
-{
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
- (zone?dname_total_size(zone):0), zone)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add check_zones");
- return;
- }
- TASKLIST(&e)->task_type = task_check_zonefiles;
- TASKLIST(&e)->yesno = (zone!=NULL);
- udb_ptr_unlink(&e, udb);
-}
+ if(found_any) {
+ memmove(&mem_offset, offset, sizeof(off_t));
-void task_new_write_zonefiles(udb_base* udb, udb_ptr* last,
- const dname_type* zone)
-{
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task writezonefiles"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
- (zone?dname_total_size(zone):0), zone)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add writezones");
- return;
+ if(mem_fpos < mem_offset)
+ memmove(offset, &mem_fpos, sizeof(off_t));
+ } else {
+ found_any = 1;
+ memmove(offset, &mem_fpos, sizeof(off_t));
+ }
+ }
}
- TASKLIST(&e)->task_type = task_write_zonefiles;
- TASKLIST(&e)->yesno = (zone!=NULL);
- udb_ptr_unlink(&e, udb);
-}
-void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v)
-{
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task set_verbosity"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
- NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add set_v");
- return;
- }
- TASKLIST(&e)->task_type = task_set_verbosity;
- TASKLIST(&e)->yesno = v;
- udb_ptr_unlink(&e, udb);
+ return found_any;
}
-#ifdef BIND8_STATS
-void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat,
+int
+diff_read_file(namedb_type* db, nsd_options_t* opt, struct diff_log** log,
size_t child_count)
{
- void* p;
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task stat_info"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
- sizeof(*stat) + sizeof(stc_t)*child_count, NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add stati");
- return NULL;
- }
- TASKLIST(&e)->task_type = task_stat_info;
- p = TASKLIST(&e)->zname;
- memcpy(p, stat, sizeof(*stat));
- udb_ptr_unlink(&e, udb);
- return p + sizeof(*stat);
-}
-#endif /* BIND8_STATS */
+ const char* filename = opt->difffile;
+ FILE *df;
+ uint32_t type, timestamp[2], curr_timestamp[2];
+ struct diff_read_data* data = diff_read_data_create();
+ off_t startpos;
-void
-task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone,
- const char* pattern)
-{
- size_t zlen = strlen(zone);
- size_t plen = strlen(pattern);
- void *p;
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addzone %s %s", zone, pattern));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
- zlen + 1 + plen + 1, NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add addz");
- return;
+ df = fopen(filename, "r");
+ if(!df) {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "could not open file %s for reading: %s",
+ filename, strerror(errno)));
+ region_destroy(data->region);
+ return 1;
}
- TASKLIST(&e)->task_type = task_add_zone;
- p = TASKLIST(&e)->zname;
- memcpy(p, zone, zlen+1);
- memmove(p+zlen+1, pattern, plen+1);
- udb_ptr_unlink(&e, udb);
-}
-void
-task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname)
-{
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delzone %s", dname_to_string(dname, 0)));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
- +dname_total_size(dname), dname)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add delz");
- return;
- }
- TASKLIST(&e)->task_type = task_del_zone;
- udb_ptr_unlink(&e, udb);
-}
+ /* check timestamp */
+ curr_timestamp[0] = (uint32_t) db->diff_timestamp.tv_sec;
+ curr_timestamp[1] = (uint32_t) db->diff_timestamp.tv_usec;
-void task_new_add_key(udb_base* udb, udb_ptr* last, key_options_t* key)
-{
- char* p;
- udb_ptr e;
- assert(key->name && key->algorithm && key->secret);
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addkey"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
- +strlen(key->name)+1+strlen(key->algorithm)+1+
- strlen(key->secret)+1, NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add addk");
- return;
+ if(!diff_read_32(df, &type)) {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "difffile %s is empty",
+ filename));
+ db->diff_skip = 0;
+ db->diff_pos = 0;
}
- TASKLIST(&e)->task_type = task_add_key;
- p = (char*)TASKLIST(&e)->zname;
- memmove(p, key->name, strlen(key->name)+1);
- p+=strlen(key->name)+1;
- memmove(p, key->algorithm, strlen(key->algorithm)+1);
- p+=strlen(key->algorithm)+1;
- memmove(p, key->secret, strlen(key->secret)+1);
- udb_ptr_unlink(&e, udb);
-}
-
-void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name)
-{
- char* p;
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delkey"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
- +strlen(name)+1, NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add delk");
- return;
+ else if (!diff_read_32(df, &timestamp[0]) ||
+ !diff_read_32(df, &timestamp[1])) {
+ log_msg(LOG_ERR, "difffile %s bad first part: no timestamp",
+ filename);
+ region_destroy(data->region);
+ return 0;
}
- TASKLIST(&e)->task_type = task_del_key;
- p = (char*)TASKLIST(&e)->zname;
- memmove(p, name, strlen(name)+1);
- udb_ptr_unlink(&e, udb);
-}
-
-void task_new_add_pattern(udb_base* udb, udb_ptr* last, pattern_options_t* p)
-{
- region_type* temp;
- buffer_type* buffer;
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addpattern %s", p->pname));
- temp = region_create(xalloc, free);
- buffer = buffer_create(temp, 4096);
- pattern_options_marshal(buffer, p);
- buffer_flip(buffer);
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
- + buffer_limit(buffer), NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add addp");
- region_destroy(temp);
- return;
+ else if (curr_timestamp[0] != timestamp[0] ||
+ curr_timestamp[1] != timestamp[1]) {
+ /* new timestamp, no skipping */
+ db->diff_timestamp.tv_sec = (time_t) timestamp[0];
+ db->diff_timestamp.tv_usec = (suseconds_t) timestamp[1];
+
+ if (db->diff_skip) {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "new timestamp on "
+ "difffile %s, restoring diff_skip and diff_pos "
+ "[old timestamp: %u.%u; new timestamp: %u.%u]",
+ filename, curr_timestamp[0], curr_timestamp[1],
+ timestamp[0], timestamp[1]));
+ db->diff_skip = 0;
+ db->diff_pos = 0;
+ }
}
- TASKLIST(&e)->task_type = task_add_pattern;
- TASKLIST(&e)->yesno = buffer_limit(buffer);
- memmove(TASKLIST(&e)->zname, buffer_begin(buffer),
- buffer_limit(buffer));
- udb_ptr_unlink(&e, udb);
- region_destroy(temp);
-}
-void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name)
-{
- char* p;
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delpattern %s", name));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
- +strlen(name)+1, NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add delp");
- return;
+ /* Always seek, to diff_pos or to beginning of the file. */
+ if (fseeko(df, 0, SEEK_SET)==-1) {
+ log_msg(LOG_INFO, "could not fseeko file %s: %s.", filename,
+ strerror(errno));
+ region_destroy(data->region);
+ return 0;
}
- TASKLIST(&e)->task_type = task_del_pattern;
- p = (char*)TASKLIST(&e)->zname;
- memmove(p, name, strlen(name)+1);
- udb_ptr_unlink(&e, udb);
-}
-
-void task_new_opt_change(udb_base* udb, udb_ptr* last, nsd_options_t* opt)
-{
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task opt_change"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
- NULL)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add o_c");
- return;
+ if(db->diff_skip) {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skip diff file"));
+ if(fseeko(df, db->diff_pos, SEEK_SET)==-1) {
+ log_msg(LOG_INFO, "could not fseeko file %s: %s. "
+ "Reread from start.", filename,
+ strerror(errno));
+ }
}
- TASKLIST(&e)->task_type = task_opt_change;
-#ifdef RATELIMIT
- TASKLIST(&e)->oldserial = opt->rrl_ratelimit;
- TASKLIST(&e)->newserial = opt->rrl_whitelist_ratelimit;
- TASKLIST(&e)->yesno = (uint64_t) opt->rrl_slip;
-#else
- (void)opt;
-#endif
- udb_ptr_unlink(&e, udb);
-}
-int
-task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname,
- uint32_t old_serial, uint32_t new_serial, uint64_t filenumber)
-{
- udb_ptr e;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task apply_xfr"));
- if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
- +dname_total_size(dname), dname)) {
- log_msg(LOG_ERR, "tasklist: out of space, cannot add applyxfr");
+ startpos = ftello(df);
+ if(startpos == -1) {
+ log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
+ region_destroy(data->region);
return 0;
}
- TASKLIST(&e)->oldserial = old_serial;
- TASKLIST(&e)->newserial = new_serial;
- TASKLIST(&e)->yesno = filenumber;
- TASKLIST(&e)->task_type = task_apply_xfr;
- udb_ptr_unlink(&e, udb);
- return 1;
-}
-
-void
-task_process_expire(namedb_type* db, struct task_list_d* task)
-{
- uint8_t ok;
- zone_type* z = namedb_find_zone(db, task->zname);
- assert(task->task_type == task_expire);
- if(!z) {
- DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "zone %s %s but not in zonetree",
- dname_to_string(task->zname, NULL),
- task->yesno?"expired":"unexpired"));
- return;
- }
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: expire task zone %s %s",
- dname_to_string(task->zname,0),
- task->yesno?"expired":"unexpired"));
- /* find zone, set expire flag */
- ok = !task->yesno;
- /* only update zone->is_ok if needed to minimize copy-on-write
- * of memory pages shared after fork() */
- if(ok && !z->is_ok)
- z->is_ok = 1;
- else if(!ok && z->is_ok)
- z->is_ok = 0;
-}
-static void
-task_process_set_verbosity(struct task_list_d* task)
-{
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "verbosity task %d", (int)task->yesno));
- verbosity = task->yesno;
-}
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "start of diff file read at pos %u",
+ (uint32_t) db->diff_pos));
+ while(diff_read_32(df, &type))
+ {
+ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "iter loop"));
+
+ /* read timestamp */
+ if(!diff_read_32(df, &timestamp[0]) ||
+ !diff_read_32(df, &timestamp[1])) {
+ log_msg(LOG_INFO, "could not read timestamp: %s.",
+ strerror(errno));
+ region_destroy(data->region);
+ return 0;
+ }
-static void
-task_process_checkzones(struct nsd* nsd, udb_base* udb, udb_ptr* last_task,
- struct task_list_d* task)
-{
- /* on SIGHUP check if zone-text-files changed and if so,
- * reread. When from xfrd-reload, no need to fstat the files */
- if(task->yesno) {
- zone_options_t* zo = zone_options_find(nsd->options,
- task->zname);
- if(zo)
- namedb_check_zonefile(nsd, udb, last_task, zo);
- } else {
- /* check all zones */
- namedb_check_zonefiles(nsd, nsd->options, udb, last_task);
+ if(!read_process_part(db, df, type, opt, data, log,
+ child_count, &startpos))
+ {
+ log_msg(LOG_INFO, "error processing diff file");
+ region_destroy(data->region);
+ return 0;
+ }
+ startpos = ftello(df);
+ if(startpos == -1) {
+ log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
+ region_destroy(data->region);
+ return 0;
+ }
}
-}
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "end of diff file read"));
-static void
-task_process_writezones(struct nsd* nsd, struct task_list_d* task)
-{
- if(task->yesno) {
- zone_options_t* zo = zone_options_find(nsd->options,
- task->zname);
- if(zo)
- namedb_write_zonefile(nsd, zo);
+ if(find_smallest_offset(data, &db->diff_pos)) {
+ /* can skip to the first unused element */
+ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file"));
+ db->diff_skip = 1;
} else {
- namedb_write_zonefiles(nsd, nsd->options);
+ /* all processed, can skip to here next time */
+ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file"));
+ db->diff_skip = 1;
+ db->diff_pos = ftello(df);
+ if(db->diff_pos == -1) {
+ log_msg(LOG_INFO, "could not ftello: %s.",
+ strerror(errno));
+ db->diff_skip = 0;
+ }
}
-}
-static void
-task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task,
- struct task_list_d* task)
-{
- zone_type* z;
- const dname_type* zdname;
- const char* zname = (const char*)task->zname;
- const char* pname = zname + strlen(zname)+1;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "addzone task %s %s", zname, pname));
- zdname = dname_parse(nsd->db->region, zname);
- if(!zdname) {
- log_msg(LOG_ERR, "can not parse zone name %s", zname);
- return;
- }
- /* create zone */
- z = find_or_create_zone(nsd->db, zdname, nsd->options, zname, pname);
- if(!z) {
- region_recycle(nsd->db->region, (void*)zdname,
- dname_total_size(zdname));
- log_msg(LOG_ERR, "can not add zone %s %s", zname, pname);
- return;
- }
- /* if zone is empty, attempt to read the zonefile from disk (if any) */
- if(!z->soa_rrset && z->opts->pattern->zonefile) {
- namedb_read_zonefile(nsd, z, udb, last_task);
- }
+ region_destroy(data->region);
+ fclose(df);
+ return 1;
}
-static void
-task_process_del_zone(struct nsd* nsd, struct task_list_d* task)
+static int diff_broken(FILE *df, off_t* break_pos)
{
- zone_type* zone;
- zone_options_t* zopt;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "delzone task %s", dname_to_string(
- task->zname, NULL)));
- zone = namedb_find_zone(nsd->db, task->zname);
- if(!zone)
- return;
+ uint32_t type, len, len2;
+ *break_pos = ftello(df);
-#ifdef NSEC3
- nsec3_hash_tree_clear(zone);
-#endif
- delete_zone_rrs(nsd->db, zone);
- if(nsd->db->udb) {
- udb_ptr udbz;
- if(udb_zone_search(nsd->db->udb, &udbz, dname_name(task->zname),
- task->zname->name_size)) {
- udb_zone_delete(nsd->db->udb, &udbz);
- udb_ptr_unlink(&udbz, nsd->db->udb);
+ /* try to read and validate parts of the file */
+ while(diff_read_32(df, &type)) /* cannot read type is no error, normal EOF */
+ {
+ /* check type */
+ if(type != DIFF_PART_IXFR && type != DIFF_PART_SURE)
+ return 1;
+ /* check length */
+ if(!diff_read_32(df, &len))
+ return 1; /* EOF inside the part is error */
+ if(fseeko(df, len, SEEK_CUR) == -1)
+ {
+ log_msg(LOG_INFO, "fseeko failed: %s", strerror(errno));
+ return 1;
}
+ /* fseek clears EOF flag, but try reading length value,
+ if EOF, the part is truncated */
+ if(!diff_read_32(df, &len2))
+ return 1;
+ if(len != len2)
+ return 1; /* bad part, lengths must agree */
+ /* this part is ok */
+ *break_pos = ftello(df);
}
-#ifdef NSEC3
- nsec3_clear_precompile(nsd->db, zone);
- zone->nsec3_param = NULL;
-#endif /* NSEC3 */
-
- /* remove from zonetree, apex, soa */
- zopt = zone->opts;
- namedb_zone_delete(nsd->db, zone);
- /* remove from options (zone_list already edited by xfrd) */
- zone_options_delete(nsd->options, zopt);
-}
-
-static void
-task_process_add_key(struct nsd* nsd, struct task_list_d* task)
-{
- key_options_t key;
- key.name = (char*)task->zname;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "addkey task %s", key.name));
- key.algorithm = key.name + strlen(key.name)+1;
- key.secret = key.algorithm + strlen(key.algorithm)+1;
- key_options_add_modify(nsd->options, &key);
- memset(key.secret, 0xdd, strlen(key.secret)); /* wipe secret */
-}
-
-static void
-task_process_del_key(struct nsd* nsd, struct task_list_d* task)
-{
- char* name = (char*)task->zname;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "delkey task %s", name));
- /* this is reload and nothing is using the TSIG key right now */
- key_options_remove(nsd->options, name);
-}
-
-static void
-task_process_add_pattern(struct nsd* nsd, struct task_list_d* task)
-{
- region_type* temp = region_create(xalloc, free);
- buffer_type buffer;
- pattern_options_t *pat;
- buffer_create_from(&buffer, task->zname, task->yesno);
- pat = pattern_options_unmarshal(temp, &buffer);
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "addpattern task %s", pat->pname));
- pattern_options_add_modify(nsd->options, pat);
- region_destroy(temp);
-}
-
-static void
-task_process_del_pattern(struct nsd* nsd, struct task_list_d* task)
-{
- char* name = (char*)task->zname;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "delpattern task %s", name));
- pattern_options_remove(nsd->options, name);
+ return 0;
}
-static void
-task_process_opt_change(struct nsd* nsd, struct task_list_d* task)
+void diff_snip_garbage(namedb_type* db, nsd_options_t* opt)
{
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "optchange task"));
-#ifdef RATELIMIT
- nsd->options->rrl_ratelimit = task->oldserial;
- nsd->options->rrl_whitelist_ratelimit = task->newserial;
- nsd->options->rrl_slip = task->yesno;
- rrl_set_limit(nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit,
- nsd->options->rrl_slip);
-#else
- (void)nsd; (void)task;
-#endif
-}
+ off_t break_pos;
+ const char* filename = opt->difffile;
+ FILE *df;
-static void
-task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
- udb_ptr* task)
-{
- /* we have to use an udb_ptr task here, because the apply_xfr procedure
- * appends soa_info which may remap and change the pointer. */
- zone_type* zone;
- FILE* df;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "applyxfr task %s", dname_to_string(
- TASKLIST(task)->zname, NULL)));
- zone = namedb_find_zone(nsd->db, TASKLIST(task)->zname);
- if(!zone) {
- /* assume the zone has been deleted and a zone transfer was
- * still waiting to be processed */
- xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno);
- return;
- }
- /* apply the XFR */
- /* oldserial, newserial, yesno is filenumber */
- df = xfrd_open_xfrfile(nsd, TASKLIST(task)->yesno, "r");
+ /* open file here and keep open, so it cannot change under our nose */
+ df = fopen(filename, "r+");
if(!df) {
- /* could not open file to update */
- /* there is no reply to xfrd failed-update,
- * because xfrd has a scan for apply-failures. */
- xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno);
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "could not open file %s for garbage collecting: %s",
+ filename, strerror(errno)));
return;
}
- /* read and apply zone transfer */
- if(!apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb,
- last_task, TASKLIST(task)->yesno)) {
- /* there is no reply to xfrd failed-update,
- * because xfrd has a scan for apply-failures. */
+ /* and skip into file, since nsd does not read anything before the pos */
+ if(db->diff_skip) {
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "garbage collect skip diff file"));
+ if(fseeko(df, db->diff_pos, SEEK_SET)==-1) {
+ log_msg(LOG_INFO, "could not fseeko file %s: %s.",
+ filename, strerror(errno));
+ fclose(df);
+ return;
+ }
+ }
+
+ /* detect break point */
+ if(diff_broken(df, &break_pos))
+ {
+ /* snip off at break_pos */
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "snipping off trailing partial part of %s",
+ filename));
+ if(ftruncate(fileno(df), break_pos) == -1)
+ log_msg(LOG_ERR, "ftruncate %s failed: %s",
+ filename, strerror(errno));
}
fclose(df);
- xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno);
-}
-
-
-void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
- udb_ptr* task)
-{
- switch(TASKLIST(task)->task_type) {
- case task_expire:
- task_process_expire(nsd->db, TASKLIST(task));
- break;
- case task_check_zonefiles:
- task_process_checkzones(nsd, udb, last_task, TASKLIST(task));
- break;
- case task_write_zonefiles:
- task_process_writezones(nsd, TASKLIST(task));
- break;
- case task_set_verbosity:
- task_process_set_verbosity(TASKLIST(task));
- break;
- case task_add_zone:
- task_process_add_zone(nsd, udb, last_task, TASKLIST(task));
- break;
- case task_del_zone:
- task_process_del_zone(nsd, TASKLIST(task));
- break;
- case task_add_key:
- task_process_add_key(nsd, TASKLIST(task));
- break;
- case task_del_key:
- task_process_del_key(nsd, TASKLIST(task));
- break;
- case task_add_pattern:
- task_process_add_pattern(nsd, TASKLIST(task));
- break;
- case task_del_pattern:
- task_process_del_pattern(nsd, TASKLIST(task));
- break;
- case task_opt_change:
- task_process_opt_change(nsd, TASKLIST(task));
- break;
- case task_apply_xfr:
- task_process_apply_xfr(nsd, udb, last_task, task);
- break;
- default:
- log_msg(LOG_WARNING, "unhandled task in reload type %d",
- (int)TASKLIST(task)->task_type);
- break;
- }
- udb_ptr_free_space(task, udb, TASKLIST(task)->size);
}