* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.c,v 1.119 2011/12/05 23:46:35 tbox Exp $ */
+/* $Id: journal.c,v 1.120 2011/12/22 07:32:41 each Exp $ */
#include <config.h>
if (result != ISC_R_SUCCESS) goto failure; \
} while (0)
+#define JOURNAL_SERIALSET 0x01U
+
static isc_result_t index_to_disk(dns_journal_t *);
static inline isc_uint32_t
unsigned char index_size[4];
/*% Source serial number. */
unsigned char sourceserial[4];
+ unsigned char flags;
} h;
/* Pad the header to a fixed size. */
unsigned char pad[JOURNAL_HEADER_SIZE];
journal_pos_t end;
isc_uint32_t index_size;
isc_uint32_t sourceserial;
+ isc_boolean_t serialset;
} journal_header_t;
/*%
*/
static journal_header_t
-initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0 };
+initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0, 0 };
#define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset)
journal_pos_decode(&raw->h.end, &cooked->end);
cooked->index_size = decode_uint32(raw->h.index_size);
cooked->sourceserial = decode_uint32(raw->h.sourceserial);
+ cooked->serialset = ISC_TF(raw->h.flags & JOURNAL_SERIALSET);
}
static void
journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
+ unsigned char flags = 0;
+
INSIST(sizeof(cooked->format) == sizeof(raw->h.format));
memset(raw->pad, 0, sizeof(raw->pad));
memcpy(raw->h.format, cooked->format, sizeof(raw->h.format));
journal_pos_encode(&raw->h.end, &cooked->end);
encode_uint32(cooked->index_size, raw->h.index_size);
encode_uint32(cooked->sourceserial, raw->h.sourceserial);
+ if (cooked->serialset)
+ flags |= JOURNAL_SERIALSET;
+ raw->h.flags = flags;
}
/*
static isc_result_t
journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
- isc_boolean_t create, dns_journal_t **journalp) {
+ isc_boolean_t create, dns_journal_t **journalp)
+{
FILE *fp = NULL;
isc_result_t result;
journal_rawheader_t rawheader;
isc_result_t
dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
- dns_journal_t **journalp) {
+ dns_journal_t **journalp)
+{
isc_result_t result;
int namelen;
char backup[1024];
/*
* Update the journal header.
*/
- if (JOURNAL_EMPTY(&j->header)) {
+ if (JOURNAL_EMPTY(&j->header))
j->header.begin = j->x.pos[0];
- j->header.sourceserial = j->header.begin.serial;
- }
j->header.end = j->x.pos[1];
journal_header_encode(&j->header, &rawheader);
CHECK(journal_seek(j, 0));
REQUIRE(filename != NULL);
j = NULL;
- result = dns_journal_open(mctx, filename, ISC_FALSE, &j);
+ result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
if (result == ISC_R_NOTFOUND) {
isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
"no journal file, but that's OK");
REQUIRE(filename != NULL);
j = NULL;
- result = dns_journal_open(mctx, filename, ISC_FALSE, &j);
+ result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
if (result == ISC_R_NOTFOUND) {
isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file");
return (DNS_R_NOJOURNAL);
return (result);
}
- fprintf(file, "Source serial = %u\n", j->header.sourceserial);
+ if (j->header.serialset)
+ fprintf(file, "Source serial = %u\n", j->header.sourceserial);
dns_diff_init(j->mctx, &diff);
/*
j->state == JOURNAL_STATE_TRANSACTION);
j->header.sourceserial = sourceserial;
+ j->header.serialset = ISC_TRUE;
if (j->state == JOURNAL_STATE_WRITE)
j->state = JOURNAL_STATE_INLINE;
}
-isc_uint32_t
-dns_journal_get_sourceserial(dns_journal_t *j) {
- return (j->header.sourceserial);
+isc_boolean_t
+dns_journal_get_sourceserial(dns_journal_t *j, isc_uint32_t *sourceserial) {
+ REQUIRE(sourceserial != NULL);
+
+ if (!j->header.serialset)
+ return (ISC_FALSE);
+ *sourceserial = j->header.sourceserial;
+ return (ISC_TRUE);
}
/**************************************************************************/
dns_journal_t *journal = NULL;
if (filename != NULL) {
- result = dns_journal_open(diff->mctx, filename, ISC_TRUE,
- &journal);
+ result = dns_journal_open(diff->mctx, filename,
+ DNS_JOURNAL_CREATE, &journal);
if (result != ISC_R_SUCCESS)
return (result);
}
new->header.end.serial = j->header.end.serial;
new->header.end.offset = indexend + copy_length;
new->header.sourceserial = j->header.sourceserial;
+ new->header.serialset = j->header.serialset;
/*
* Update the journal header.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.657 2011/12/20 00:26:52 marka Exp $ */
+/* $Id: zone.c,v 1.658 2011/12/22 07:32:41 each Exp $ */
/*! \file */
dns_zone_t *raw;
dns_zone_t *secure;
- isc_boolean_t rawserialset;
- isc_uint32_t rawserial;
+ isc_boolean_t sourceserialset;
+ isc_uint32_t sourceserial;
};
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
static void zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length);
static void zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length);
static isc_result_t zone_send_secureserial(dns_zone_t *zone,
+ isc_boolean_t locked,
isc_uint32_t serial);
#if 0
static void zone_rekey(dns_zone_t *zone);
static isc_boolean_t delsig_ok(dns_rdata_rrsig_t *rrsig_ptr,
dst_key_t **keys, unsigned int nkeys);
-static isc_result_t zone_send_securedb(dns_zone_t *zone, dns_db_t *db);
+static isc_result_t zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked,
+ dns_db_t *db);
#define ENTER zone_debuglog(zone, me, 1, "enter")
ISC_LIST_INIT(zone->forwards);
zone->raw = NULL;
zone->secure = NULL;
- zone->rawserial = 0;
- zone->rawserialset = ISC_FALSE;
+ zone->sourceserial = 0;
+ zone->sourceserialset = ISC_FALSE;
zone->magic = ZONE_MAGIC;
isc_mem_detach(&mctx);
}
+/*
+ * Returns ISC_TRUE iff this the signed side of an inline-signing zone
+ */
+static inline isc_boolean_t
+inline_secure(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ if (zone->raw != NULL)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+/*
+ * Returns ISC_TRUE iff this the unsigned side of an inline-signing zone
+ */
+static inline isc_boolean_t
+inline_raw(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ if (zone->secure != NULL)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
/*
* Single shot.
*/
zone_rdclass_tostr(zone, namebuf, sizeof namebuf);
zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf);
- if (zone->raw != NULL)
+ if (inline_secure(zone))
dns_zone_setclass(zone->raw, rdclass);
UNLOCK_ZONE(zone);
}
zone_viewname_tostr(zone, namebuf, sizeof namebuf);
zone->strviewname = isc_mem_strdup(zone->mctx, namebuf);
- if (zone->raw != NULL)
+ if (inline_secure(zone))
dns_zone_setview(zone->raw, view);
UNLOCK_ZONE(zone);
zone_name_tostr(zone, namebuf, sizeof namebuf);
zone->strname = isc_mem_strdup(zone->mctx, namebuf);
- if (result == ISC_R_SUCCESS && zone->raw != NULL)
+ if (result == ISC_R_SUCCESS && inline_secure(zone))
result = dns_zone_setorigin(zone->raw, origin);
UNLOCK_ZONE(zone);
return (result);
LOCK_ZONE(zone);
TIME_NOW(&now);
- if (zone->raw != NULL) {
+ if (inline_secure(zone)) {
result = zone_load(zone->raw, flags);
if (result != ISC_R_SUCCESS)
goto cleanup;
dns_zone_loadandthaw(dns_zone_t *zone) {
isc_result_t result;
- result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
+ if (inline_raw(zone))
+ result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW);
+ else
+ result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
+
switch (result) {
case DNS_R_CONTINUE:
/* Deferred thaw. */
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
dns_db_currentversion(zone->db, &version);
dns_master_initrawheader(&rawdata);
- if (zone->raw != NULL)
+ if (inline_secure(zone))
get_raw_serial(zone->raw, &rawdata);
result = dns_master_dumpinc3(zone->mctx, zone->db, version,
&dns_master_style_default,
dump_done(zone, result);
}
+/*
+ * Save the raw serial number for inline-signing zones.
+ * (XXX: Other information from the header will be used
+ * for other purposes in the future, but for now this is
+ * all we're interested in.)
+ */
static void
zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) {
- if (zone == NULL)
+ if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0)
return;
- /*
- * Save the raw serial number for inline-signing zones.
- * (XXX: Other information from the header will be used
- * for other purposes in the future, but for now this is
- * all we're interested in.)
- */
- if (zone->raw != NULL ||
- ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0))
+ zone->sourceserial = header->sourceserial;
+ zone->sourceserialset = ISC_TRUE;
+}
+
+void
+dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) {
+ if (zone == NULL)
return;
LOCK_ZONE(zone);
- zone->rawserial = header->sourceserial;
- zone->rawserialset = ISC_TRUE;
+ zone_setrawdata(zone, header);
UNLOCK_ZONE(zone);
}
const char *journalfile;
isc_result_t result = ISC_R_SUCCESS;
dns_journal_t *journal = NULL;
+ unsigned int mode = DNS_JOURNAL_CREATE|DNS_JOURNAL_WRITE;
ENTER;
journalfile = dns_zone_getjournal(zone);
if (journalfile != NULL) {
- result = dns_journal_open(zone->mctx, journalfile,
- DNS_JOURNAL_CREATE, &journal);
+ result = dns_journal_open(zone->mctx, journalfile, mode,
+ &journal);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"%s:dns_journal_open -> %s\n",
caller, dns_result_totext(result));
return (result);
}
+
if (sourceserial != NULL)
dns_journal_set_sourceserial(journal, *sourceserial);
result = dns_journal_write_transaction(journal, diff);
- dns_journal_destroy(&journal);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"%s:dns_journal_write_transaction -> %s\n",
caller, dns_result_totext(result));
- return (result);
}
+ dns_journal_destroy(&journal);
}
+
return (result);
}
}
static void
-maybe_send_securedb(dns_zone_t *zone) {
+maybe_send_secure(dns_zone_t *zone) {
+ isc_result_t result;
+
+ /*
+ * We've finished loading, or else failed to load, an inline-signing
+ * 'secure' zone. We now need information about the status of the
+ * 'raw' zone. If we failed to load, then we need it to send a
+ * copy of its database; if we succeeded, we need it to send its
+ * serial number so that we can sync with it. If it has not yet
+ * loaded, we set a flag so that it will send the necessary
+ * information when it has finished loading.
+ */
LOCK_ZONE(zone->raw);
- if (zone->raw->db != NULL)
- zone_send_securedb(zone->raw, zone->raw->db);
- else
+ if (zone->raw->db != NULL) {
+ if (zone->db != NULL) {
+ isc_uint32_t serial;
+ result = zone_get_from_db(zone->raw, zone->raw->db,
+ NULL, NULL, &serial, NULL,
+ NULL, NULL, NULL, NULL);
+ if (result == ISC_R_SUCCESS)
+ zone_send_secureserial(zone->raw, ISC_TRUE,
+ serial);
+ } else
+ zone_send_securedb(zone->raw, ISC_TRUE, zone->raw->db);
+
+ } else
DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE);
+
UNLOCK_ZONE(zone->raw);
}
return (answer);
}
+/*
+ * The zone is presumed to be locked.
+ */
static isc_result_t
zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
isc_result_t result)
zone->masterfile,
dns_result_totext(result));
} else if (zone->type == dns_zone_master &&
- zone->raw != NULL && result == ISC_R_FILENOTFOUND) {
+ inline_secure(zone) && result == ISC_R_FILENOTFOUND)
+ {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"no master file, requesting db");
- maybe_send_securedb(zone);
+ maybe_send_secure(zone);
} else {
int level = ISC_LOG_ERROR;
if (zone->type == dns_zone_key &&
dns_journal_t *journal = NULL;
result = dns_journal_open(zone->mctx, zone->journal,
- ISC_FALSE, &journal);
+ DNS_JOURNAL_READ, &journal);
if (result == ISC_R_SUCCESS) {
jserial = dns_journal_last_serial(journal);
dns_journal_destroy(&journal);
&zone->expiretime) >= 0)
zone->refreshtime = now;
}
+
break;
case dns_zone_key:
DNS_ZONE_SETFLAG(zone,
DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SENDSECURE) &&
- zone->secure != NULL)
- zone_send_securedb(zone, db);
+ inline_raw(zone))
+ {
+ if (zone->secure->db == NULL)
+ zone_send_securedb(zone, ISC_FALSE, db);
+ else
+ zone_send_secureserial(zone, ISC_FALSE, serial);
+ }
}
+ /*
+ * Finished loading inline-signing zone; need to get status
+ * from the raw side now.
+ */
+ if (zone->type == dns_zone_master && inline_secure(zone))
+ maybe_send_secure(zone);
+
+
result = ISC_R_SUCCESS;
if (needdump) {
LOCK_ZONE(zone);
if (zone->type == dns_zone_master) {
- if (zone->secure != NULL) {
+ if (inline_raw(zone)) {
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL) {
result = zone_get_from_db(zone, zone->db, NULL,
result = DNS_R_NOTLOADED;
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
if (result == ISC_R_SUCCESS)
- zone_send_secureserial(zone, serial);
+ zone_send_secureserial(zone, ISC_FALSE, serial);
}
set_resigntime(zone); /* XXXMPA make separate call back */
}
* If there is a secure version of this zone
* use its serial if it is less than ours.
*/
- if (tresult == ISC_R_SUCCESS &&
- zone->secure != NULL && zone->secure->db != NULL) {
+ if (tresult == ISC_R_SUCCESS && inline_raw(zone) &&
+ zone->secure->db != NULL)
+ {
isc_uint32_t sserial;
isc_result_t mresult;
dns_masterrawheader_t rawdata;
dns_db_currentversion(db, &version);
dns_master_initrawheader(&rawdata);
- if (zone->raw != NULL)
+ if (inline_secure(zone))
get_raw_serial(zone->raw, &rawdata);
result = dns_master_dump3(zone->mctx, db, version,
&dns_master_style_default,
dns_master_initrawheader(&rawdata);
if (rawversion == 0)
rawdata.flags |= DNS_MASTERRAW_COMPAT;
- if (zone->raw != NULL && rawversion > 0)
+ else if (inline_secure(zone))
get_raw_serial(zone->raw, &rawdata);
+ else if (zone->sourceserialset) {
+ rawdata.flags = DNS_MASTERRAW_SOURCESERIALSET;
+ rawdata.sourceserial = zone->sourceserial;
+ }
result = dns_master_dumptostream3(zone->mctx, db, version, style,
format, &rawdata, fd);
dns_db_closeversion(db, &version, ISC_FALSE);
*/
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN);
free_needed = exit_check(zone);
- if (zone->raw != NULL) {
+ if (inline_secure(zone)) {
raw = zone->raw;
zone->raw = NULL;
}
- if (zone->secure != NULL) {
+ if (inline_raw(zone)) {
secure = zone->secure;
zone->secure = NULL;
}
* Notify messages are processed by the raw zone.
*/
LOCK_ZONE(zone);
- if (zone->raw != NULL) {
+ if (inline_secure(zone)) {
result = dns_zone_notifyreceive(zone->raw, from, msg);
UNLOCK_ZONE(zone);
return (result);
isc_buffer_putstr(&buffer, "/");
isc_buffer_putstr(&buffer, zone->view->name);
}
- if (zone->raw != NULL && 9U < isc_buffer_availablelength(&buffer))
+ if (inline_secure(zone) && 9U < isc_buffer_availablelength(&buffer))
isc_buffer_putstr(&buffer, " (signed)");
- if (zone->secure != NULL && 11U < isc_buffer_availablelength(&buffer))
+ if (inline_raw(zone) && 11U < isc_buffer_availablelength(&buffer))
isc_buffer_putstr(&buffer, " (unsigned)");
buf[isc_buffer_usedlength(&buffer)] = '\0';
dns_message_destroy(&message);
}
-struct secure_serial {
+struct secure_event {
isc_event_t e;
+ dns_db_t *db;
isc_uint32_t serial;
};
dns_zone_log(zone, level, "%s", message);
}
-static void
-receive_secure_serial(isc_task_t *task, isc_event_t *event) {
- isc_result_t result;
- dns_journal_t *rjournal = NULL, *sjournal = NULL;
- isc_uint32_t start, end;
- dns_zone_t *zone;
- int n_soa = 0;
- dns_db_t *db = NULL;
- dns_dbnode_t *node = NULL;
- dns_dbversion_t *newver = NULL, *oldver = NULL;
- isc_uint32_t oldserial, newserial;
+static isc_result_t
+sync_secure_journal(dns_zone_t *zone, dns_journal_t *journal,
+ isc_uint32_t start, isc_uint32_t end,
+ dns_difftuple_t **soatuplep, dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_difftuple_t *tuple = NULL;
dns_diffop_t op = DNS_DIFFOP_ADD;
- dns_diff_t diff;
- dns_difftuple_t *tuple = NULL, *soatuple = NULL;
- dns_update_log_t log = { update_log_cb, NULL };
- isc_time_t timenow;
-
- zone = event->ev_arg;
- end = ((struct secure_serial *)event)->serial;
-
- dns_diff_init(zone->mctx, &diff);
-
- UNUSED(task);
- CHECK(dns_journal_open(zone->raw->mctx, zone->raw->journal,
- DNS_JOURNAL_WRITE, &rjournal));
- result = dns_journal_open(zone->raw->mctx, zone->journal,
- DNS_JOURNAL_READ, &sjournal);
- if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
- goto failure;
-
- start = dns_journal_get_sourceserial(rjournal);
- if (sjournal != NULL) {
- isc_uint32_t serial = dns_journal_get_sourceserial(sjournal);
- /*
- * We write the secure journal first so if that exists
- * use its value provided it is greater that from the
- * raw journal.
- */
- if (isc_serial_gt(serial, start))
- start = serial;
- dns_journal_destroy(&sjournal);
- }
-
- if (start == end)
- goto failure;
- CHECK(dns_journal_iter_init(rjournal, start, end));
+ int n_soa = 0;
- dns_db_attach(zone->db, &db);
- dns_db_currentversion(db, &oldver);
- CHECK(dns_db_newversion(db, &newver));
+ REQUIRE(soatuplep != NULL);
- for (result = dns_journal_first_rr(rjournal);
- result == ISC_R_SUCCESS;
- result = dns_journal_next_rr(rjournal)) {
- dns_name_t *name = NULL;
- isc_uint32_t ttl;
- dns_rdata_t *rdata = NULL;
- dns_journal_current_rr(rjournal, &name, &ttl, &rdata);
+ if (start == end)
+ return (DNS_R_UNCHANGED);
- if (rdata->type == dns_rdatatype_soa) {
- n_soa++;
- if (n_soa == 2) {
- /*
- * Save the lastest raw SOA record.
- */
- if (soatuple != NULL)
- dns_difftuple_free(&soatuple);
- CHECK(dns_difftuple_create(diff.mctx,
- DNS_DIFFOP_ADD,
- name, ttl, rdata,
- &soatuple));
- }
- if (n_soa == 3)
- n_soa = 1;
+ CHECK(dns_journal_iter_init(journal, start, end));
+ for (result = dns_journal_first_rr(journal);
+ result == ISC_R_SUCCESS;
+ result = dns_journal_next_rr(journal))
+ {
+ dns_name_t *name = NULL;
+ isc_uint32_t ttl;
+ dns_rdata_t *rdata = NULL;
+ dns_journal_current_rr(journal, &name, &ttl, &rdata);
+
+ if (rdata->type == dns_rdatatype_soa) {
+ n_soa++;
+ if (n_soa == 2) {
+ /*
+ * Save the latest raw SOA record.
+ */
+ if (*soatuplep != NULL)
+ dns_difftuple_free(soatuplep);
+ CHECK(dns_difftuple_create(diff->mctx,
+ DNS_DIFFOP_ADD,
+ name, ttl, rdata,
+ soatuplep));
+ }
+ if (n_soa == 3)
+ n_soa = 1;
continue;
}
- /* Sanity. */
+ /* Sanity. */
if (n_soa == 0) {
dns_zone_log(zone->raw, ISC_LOG_ERROR,
"corrupt journal file: '%s'\n",
zone->raw->journal);
- goto failure;
+ return (ISC_R_FAILURE);
}
if (zone->privatetype != 0 &&
op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
- CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata,
+ CHECK(dns_difftuple_create(diff->mctx, op, name, ttl, rdata,
&tuple));
- dns_diff_appendminimal(&diff, &tuple);
+ dns_diff_appendminimal(diff, &tuple);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ failure:
+ return(result);
+}
+
+static isc_result_t
+sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb,
+ dns_dbversion_t *secver, dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_db_t *rawdb = NULL;
+ dns_dbversion_t *rawver = NULL;
+ dns_difftuple_t *tuple = NULL, *next;
+
+ REQUIRE(DNS_ZONE_VALID(seczone));
+ REQUIRE(inline_secure(seczone));
+
+ if (!seczone->sourceserialset)
+ return (DNS_R_UNCHANGED);
+
+ dns_db_attach(seczone->raw->db, &rawdb);
+ dns_db_currentversion(rawdb, &rawver);
+ result = dns_db_diffx(diff, rawdb, rawver, secdb, secver, NULL);
+ dns_db_closeversion(rawdb, &rawver, ISC_FALSE);
+ dns_db_detach(&rawdb);
+
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ for (tuple = ISC_LIST_HEAD(diff->tuples);
+ tuple != NULL;
+ tuple = next)
+ {
+ next = ISC_LIST_NEXT(tuple, link);
+ if (tuple->rdata.type == dns_rdatatype_nsec ||
+ tuple->rdata.type == dns_rdatatype_rrsig ||
+ tuple->rdata.type == dns_rdatatype_dnskey ||
+ tuple->rdata.type == dns_rdatatype_nsec3 ||
+ tuple->rdata.type == dns_rdatatype_soa ||
+ tuple->rdata.type == dns_rdatatype_nsec3param)
+ {
+ ISC_LIST_UNLINK(diff->tuples, tuple, link);
+ dns_difftuple_free(&tuple);
+ }
+ }
+
+ if (ISC_LIST_EMPTY(diff->tuples))
+ return (DNS_R_UNCHANGED);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+receive_secure_serial(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_journal_t *rjournal = NULL;
+ isc_uint32_t start, end;
+ dns_zone_t *zone;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *newver = NULL, *oldver = NULL;
+ dns_diff_t diff;
+ dns_difftuple_t *tuple = NULL, *soatuple = NULL;
+ dns_update_log_t log = { update_log_cb, NULL };
+ isc_time_t timenow;
+
+ zone = event->ev_arg;
+ end = ((struct secure_event *)event)->serial;
+ isc_event_free(&event);
+
+ REQUIRE(inline_secure(zone));
+
+ dns_diff_init(zone->mctx, &diff);
+
+ UNUSED(task);
+
+ /*
+ * We first attempt to sync the raw zone to the secure zone
+ * by using the raw zone's journal, applying all the deltas
+ * from the latest source-serial of the secure zone up to
+ * the current serial number of the raw zone.
+ *
+ * If that fails, then we'll fall back to a direct comparison
+ * between raw and secure zones.
+ */
+ result = dns_journal_open(zone->raw->mctx, zone->raw->journal,
+ DNS_JOURNAL_WRITE, &rjournal);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ else {
+ dns_journal_t *sjournal = NULL;
+
+ result = dns_journal_open(zone->raw->mctx, zone->journal,
+ DNS_JOURNAL_READ, &sjournal);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+ goto failure;
+
+ if (!dns_journal_get_sourceserial(rjournal, &start)) {
+ start = dns_journal_first_serial(rjournal);
+ dns_journal_set_sourceserial(rjournal, start);
+ }
+ if (sjournal != NULL) {
+ isc_uint32_t serial;
+ /*
+ * We read the secure journal first, if that exists
+ * use its value provided it is greater that from the
+ * raw journal.
+ */
+ if (dns_journal_get_sourceserial(sjournal, &serial)) {
+ if (isc_serial_gt(serial, start))
+ start = serial;
+ }
+ dns_journal_destroy(&sjournal);
+ }
+ }
+
+ dns_db_attach(zone->db, &db);
+ dns_db_currentversion(db, &oldver);
+ CHECK(dns_db_newversion(db, &newver));
+
+ /*
+ * Try to apply diffs from the raw zone's journal to the secure
+ * zone. If that fails, we recover by syncing up the databases
+ * directly.
+ */
+ result = sync_secure_journal(zone, rjournal, start, end,
+ &soatuple, &diff);
+ if (result == DNS_R_UNCHANGED)
+ goto failure;
+ else if (result != ISC_R_SUCCESS) {
+ CHECK(sync_secure_db(zone, db, oldver, &diff));
}
- if (result == ISC_R_NOMORE)
- result = ISC_R_SUCCESS;
- CHECK(result);
CHECK(dns_diff_apply(&diff, db, newver));
if (soatuple != NULL) {
- isc_uint32_t desired;
+ isc_uint32_t oldserial, newserial, desired;
CHECK(dns_db_createsoatuple(db, oldver, diff.mctx,
DNS_DIFFOP_DEL, &tuple));
LOCK_ZONE(zone);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
- zone->rawserial = start;
- zone->rawserialset = ISC_TRUE;
+ zone->sourceserial = end;
+ zone->sourceserialset = ISC_TRUE;
zone_needdump(zone, DNS_DUMP_DELAY);
TIME_NOW(&timenow);
dns_db_closeversion(db, &newver, ISC_TRUE);
failure:
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_serial: %s",
+ dns_result_totext(result));
if (tuple != NULL)
dns_difftuple_free(&tuple);
if (soatuple != NULL)
}
if (rjournal != NULL)
dns_journal_destroy(&rjournal);
- if (sjournal != NULL)
- dns_journal_destroy(&sjournal);
dns_diff_clear(&diff);
- isc_event_free(&event);
+ dns_zone_idetach(&zone);
}
static isc_result_t
-zone_send_secureserial(dns_zone_t *zone, isc_uint32_t serial) {
+zone_send_secureserial(dns_zone_t *zone, isc_boolean_t locked,
+ isc_uint32_t serial)
+{
isc_event_t *e;
+ dns_zone_t *dummy = NULL;
e = isc_event_allocate(zone->secure->mctx, zone,
DNS_EVENT_ZONESECURESERIAL,
receive_secure_serial, zone->secure,
- sizeof(struct secure_serial));
+ sizeof(struct secure_event));
if (e == NULL)
return (ISC_R_NOMEMORY);
- ((struct secure_serial *)e)->serial = serial;
-
+ ((struct secure_event *)e)->serial = serial;
+ if (locked)
+ zone_iattach(zone->secure, &dummy);
+ else
+ dns_zone_iattach(zone->secure, &dummy);
isc_task_send(zone->secure->task, &e);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE);
return (ISC_R_SUCCESS);
}
-struct secure_db {
- isc_event_t e;
- dns_db_t *db;
-};
-
static void
receive_secure_db(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
UNUSED(task);
zone = event->ev_arg;
- rawdb = ((struct secure_db *)event)->db;
+ rawdb = ((struct secure_event *)event)->db;
+ isc_event_free(&event);
+
+ REQUIRE(inline_secure(zone));
+
dns_fixedname_init(&fname);
name = dns_fixedname_name(&fname);
dns_rdataset_init(&rdataset);
dns_db_detach(&rawdb);
if (dbiterator != NULL)
dns_dbiterator_destroy(&dbiterator);
- isc_event_free(&event);
+ dns_zone_idetach(&zone);
}
static isc_result_t
-zone_send_securedb(dns_zone_t *zone, dns_db_t *db) {
+zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, dns_db_t *db) {
isc_event_t *e;
dns_db_t *dummy = NULL;
+ dns_zone_t *secure = NULL;
e = isc_event_allocate(zone->secure->mctx, zone,
DNS_EVENT_ZONESECUREDB,
receive_secure_db, zone->secure,
- sizeof(struct secure_db));
+ sizeof(struct secure_event));
if (e == NULL)
return (ISC_R_NOMEMORY);
dns_db_attach(db, &dummy);
- ((struct secure_db *)e)->db = dummy;
+ ((struct secure_event *)e)->db = dummy;
+ if (locked)
+ zone_iattach(zone->secure, &secure);
+ else
+ dns_zone_iattach(zone->secure, &secure);
isc_task_send(zone->secure->task, &e);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE);
*/
if (zone->db != NULL && zone->journal != NULL &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
- !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER))
+ {
isc_uint32_t serial, oldserial;
dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs");
break;
}
}
- if (zone->type == dns_zone_master && zone->secure != NULL)
- zone_send_secureserial(zone, serial);
+ if (zone->type == dns_zone_master && inline_raw(zone))
+ zone_send_secureserial(zone, ISC_FALSE, serial);
} else {
if (dump && zone->masterfile != NULL) {
/*
zone->journal, strbuf);
}
}
- if (zone->secure != NULL)
- zone_send_securedb(zone, db);
+
+ if (inline_raw(zone))
+ zone_send_securedb(zone, ISC_FALSE, db);
}
dns_db_closeversion(db, &ver, ISC_FALSE);
dns_zone_log(zone, ISC_LOG_INFO,
"transferred serial %u%s",
serial, buf);
- if (zone->secure != NULL)
- zone_send_secureserial(zone, serial);
+ if (inline_raw(zone))
+ zone_send_secureserial(zone, ISC_FALSE, serial);
}
/*