4082. [bug] Incrementally sign large inline zone deltas.

[RT #37927]

(cherry picked from commit 1b05d22789)
This commit is contained in:
Mark Andrews 2015-03-05 09:59:29 +11:00
parent 8d47120f7d
commit 263413c7a7
10 changed files with 858 additions and 570 deletions

View file

@ -1,3 +1,6 @@
4082. [bug] Incrementally sign large inline zone deltas.
[RT #37927]
4081. [cleanup] Use dns_rdatalist_init consistently. [RT #38759]
4077. [test] Add static-stub regression test for DS NXDOMAIN

View file

@ -2191,6 +2191,7 @@ update_completed(isc_task_t *task, isc_event_t *event) {
dns_request_destroy(&request);
dns_message_renderreset(updatemsg);
dns_message_settsigkey(updatemsg, NULL);
/* XXX MPA fix zonename is freed already */
send_update(zname, &master_servers[master_inuse]);
isc_event_free(&event);
return;
@ -2493,6 +2494,9 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
dns_name_init(&master, NULL);
dns_name_clone(&soa.origin, &master);
/*
* XXXMPA
*/
if (userzone != NULL)
zname = userzone;
else

View file

@ -88,3 +88,4 @@ rm -f ns3/test-?.bk.signed.jnl
rm -f import.key Kimport*
rm -f checkgost checkdsa checkecdsa
rm -f ns3/a-file
rm -f dig.out.*

View file

@ -44,6 +44,7 @@ zone "bits" {
auto-dnssec maintain;
allow-update-forwarding { any; };
file "bits.bk";
sig-signing-signatures 1; // force incremental processing
};
server 10.53.0.4 { request-ixfr no; };

View file

@ -66,6 +66,15 @@
<listitem>
<para>None</para>
</listitem>
<listitem>
<para>
Large inline-signing changes should be less disruptive.
Signature generation is now done incrementally; the number
of signatures to be generated in each quantum is controlled
by "sig-signing-signatures <replaceable>number</replaceable>;".
[RT #37927]
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="relnotes_bugs">

View file

@ -127,6 +127,7 @@ typedef struct dns_tsec dns_tsec_t;
typedef struct dns_tsig_keyring dns_tsig_keyring_t;
typedef struct dns_tsigkey dns_tsigkey_t;
typedef isc_uint32_t dns_ttl_t;
typedef struct dns_update_state dns_update_state_t;
typedef struct dns_validator dns_validator_t;
typedef struct dns_view dns_view_t;
typedef ISC_LIST(dns_view_t) dns_viewlist_t;

View file

@ -59,6 +59,12 @@ dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
dns_dbversion_t *oldver, dns_dbversion_t *newver,
dns_diff_t *diff, isc_uint32_t sigvalidityinterval);
isc_result_t
dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
dns_dbversion_t *oldver, dns_dbversion_t *newver,
dns_diff_t *diff, isc_uint32_t sigvalidityinterval,
dns_update_state_t **state);
ISC_LANG_ENDDECLS
#endif /* DNS_UPDATE_H */

View file

@ -1903,6 +1903,12 @@ dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures);
* Set the number of signatures that will be generated per quantum.
*/
isc_uint32_t
dns_zone_getsignatures(dns_zone_t *zone);
/*%<
* Get the number of signatures that will be generated per quantum.
*/
isc_result_t
dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
isc_uint16_t keyid, isc_boolean_t deleteit);

File diff suppressed because it is too large Load diff

View file

@ -379,6 +379,23 @@ struct dns_zone {
isc_boolean_t sourceserialset;
isc_uint32_t sourceserial;
/*%
* maximum zone ttl
*/
dns_ttl_t maxttl;
/*
* Inline zone signing state.
*/
dns_diff_t rss_diff;
isc_eventlist_t rss_events;
dns_dbversion_t *rss_newver;
dns_dbversion_t *rss_oldver;
dns_db_t *rss_db;
dns_zone_t *rss_raw;
isc_event_t *rss_event;
dns_update_state_t *rss_state;
};
typedef struct {
@ -967,6 +984,13 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->secure = NULL;
zone->sourceserial = 0;
zone->sourceserialset = ISC_FALSE;
ISC_LIST_INIT(zone->rss_events);
zone->rss_db = NULL;
zone->rss_raw = NULL;
zone->rss_newver = NULL;
zone->rss_oldver = NULL;
zone->rss_event = NULL;
zone->rss_state = NULL;
zone->magic = ZONE_MAGIC;
@ -9015,7 +9039,8 @@ zone_maintenance(dns_zone_t *zone) {
break;
case dns_zone_master:
if (!isc_time_isepoch(&zone->refreshkeytime) &&
isc_time_compare(&now, &zone->refreshkeytime) >= 0)
isc_time_compare(&now, &zone->refreshkeytime) >= 0 &&
zone->rss_event == NULL)
zone_rekey(zone);
default:
break;
@ -9028,6 +9053,8 @@ zone_maintenance(dns_zone_t *zone) {
/*
* Do we need to sign/resign some RRsets?
*/
if (zone->rss_event != NULL)
break;
if (!isc_time_isepoch(&zone->signingtime) &&
isc_time_compare(&now, &zone->signingtime) >= 0)
zone_sign(zone);
@ -12935,61 +12962,74 @@ sync_secure_db(dns_zone_t *seczone, dns_zone_t *raw, dns_db_t *secdb,
static void
receive_secure_serial(isc_task_t *task, isc_event_t *event) {
static char me[] = "receive_secure_serial";
isc_result_t result;
isc_result_t result = ISC_R_SUCCESS;
dns_journal_t *rjournal = NULL;
dns_journal_t *sjournal = NULL;
isc_uint32_t start, end;
dns_zone_t *zone, *raw = NULL;
dns_db_t *db = NULL;
dns_dbversion_t *newver = NULL, *oldver = NULL;
dns_diff_t diff;
dns_zone_t *zone;
dns_difftuple_t *tuple = NULL, *soatuple = NULL;
dns_update_log_t log = { update_log_cb, NULL };
isc_time_t timenow;
UNUSED(task);
zone = event->ev_arg;
end = ((struct secure_event *)event)->serial;
isc_event_free(&event);
ENTER;
LOCK_ZONE(zone);
dns_diff_init(zone->mctx, &diff);
UNUSED(task);
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL)
dns_db_attach(zone->db, &db);
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->raw != NULL)
dns_zone_attach(zone->raw, &raw);
UNLOCK_ZONE(zone);
/*
* zone->db may be NULL if the load from disk failed.
* If we are already processing a receive secure serial event
* for the zone, just queue the new one and exit.
*/
if (db == NULL || raw == NULL) {
result = ISC_R_FAILURE;
goto failure;
if (zone->rss_event != NULL && zone->rss_event != event) {
ISC_LIST_APPEND(zone->rss_events, event, ev_link);
UNLOCK_ZONE(zone);
return;
}
/*
* 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(raw->mctx, raw->journal,
DNS_JOURNAL_WRITE, &rjournal);
if (result != ISC_R_SUCCESS)
goto failure;
else {
dns_journal_t *sjournal = NULL;
nextevent:
if (zone->rss_event != NULL) {
INSIST(zone->rss_event == event);
UNLOCK_ZONE(zone);
} else {
zone->rss_event = event;
dns_diff_init(zone->mctx, &zone->rss_diff);
/*
* zone->db may be NULL, if the load from disk failed.
*/
result = ISC_R_SUCCESS;
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL)
dns_db_attach(zone->db, &zone->rss_db);
else
result = ISC_R_FAILURE;
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
if (result == ISC_R_SUCCESS && zone->raw != NULL)
dns_zone_attach(zone->raw, &zone->rss_raw);
else
result = ISC_R_FAILURE;
UNLOCK_ZONE(zone);
CHECK(result);
/*
* 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.
*/
CHECK(dns_journal_open(zone->rss_raw->mctx,
zone->rss_raw->journal,
DNS_JOURNAL_WRITE, &rjournal));
result = dns_journal_open(zone->mctx, zone->journal,
DNS_JOURNAL_READ, &sjournal);
@ -13003,9 +13043,9 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
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.
* 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))
@ -13013,50 +13053,78 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
}
dns_journal_destroy(&sjournal);
}
dns_db_currentversion(zone->rss_db, &zone->rss_oldver);
CHECK(dns_db_newversion(zone->rss_db, &zone->rss_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, zone->rss_raw, rjournal,
start, end, &soatuple,
&zone->rss_diff);
if (result == DNS_R_UNCHANGED)
goto failure;
else if (result != ISC_R_SUCCESS)
CHECK(sync_secure_db(zone, zone->rss_raw, zone->rss_db,
zone->rss_oldver, &soatuple,
&zone->rss_diff));
CHECK(dns_diff_apply(&zone->rss_diff, zone->rss_db,
zone->rss_newver));
if (soatuple != NULL) {
isc_uint32_t oldserial, newserial, desired;
CHECK(dns_db_createsoatuple(zone->rss_db,
zone->rss_oldver,
zone->rss_diff.mctx,
DNS_DIFFOP_DEL, &tuple));
oldserial = dns_soa_getserial(&tuple->rdata);
newserial = desired =
dns_soa_getserial(&soatuple->rdata);
if (!isc_serial_gt(newserial, oldserial)) {
newserial = oldserial + 1;
if (newserial == 0)
newserial++;
dns_soa_setserial(newserial, &soatuple->rdata);
}
CHECK(do_one_tuple(&tuple, zone->rss_db,
zone->rss_newver, &zone->rss_diff));
CHECK(do_one_tuple(&soatuple, zone->rss_db,
zone->rss_newver, &zone->rss_diff));
dns_zone_log(zone, ISC_LOG_INFO,
"serial %u (unsigned %u)",
newserial, desired);
} else
CHECK(update_soa_serial(zone->rss_db, zone->rss_newver,
&zone->rss_diff, zone->mctx,
zone->updatemethod));
}
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, raw, rjournal, start, end,
&soatuple, &diff);
if (result == DNS_R_UNCHANGED)
result = dns_update_signaturesinc(&log, zone, zone->rss_db,
zone->rss_oldver, zone->rss_newver,
&zone->rss_diff,
zone->sigvalidityinterval,
&zone->rss_state);
if (result == DNS_R_CONTINUE) {
if (rjournal != NULL)
dns_journal_destroy(&rjournal);
isc_task_send(task, &event);
fprintf(stderr, "looping on dns_update_signaturesinc\n");
return;
}
if (result != ISC_R_SUCCESS)
goto failure;
else if (result != ISC_R_SUCCESS)
CHECK(sync_secure_db(zone, raw, db, oldver, &soatuple, &diff));
CHECK(dns_diff_apply(&diff, db, newver));
if (soatuple != NULL) {
isc_uint32_t oldserial, newserial, desired;
CHECK(dns_db_createsoatuple(db, oldver, diff.mctx,
DNS_DIFFOP_DEL, &tuple));
oldserial = dns_soa_getserial(&tuple->rdata);
newserial = desired = dns_soa_getserial(&soatuple->rdata);
if (!isc_serial_gt(newserial, oldserial)) {
newserial = oldserial + 1;
if (newserial == 0)
newserial++;
dns_soa_setserial(newserial, &soatuple->rdata);
}
CHECK(do_one_tuple(&tuple, db, newver, &diff));
CHECK(do_one_tuple(&soatuple, db, newver, &diff));
dns_zone_log(zone, ISC_LOG_INFO, "serial %u (unsigned %u)",
newserial, desired);
} else
CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
zone->updatemethod));
CHECK(dns_update_signatures(&log, zone, db, oldver, newver,
&diff, zone->sigvalidityinterval));
CHECK(zone_journal(zone, &diff, &end, "receive_secure_serial"));
if (rjournal == NULL)
CHECK(dns_journal_open(zone->rss_raw->mctx,
zone->rss_raw->journal,
DNS_JOURNAL_WRITE, &rjournal));
CHECK(zone_journal(zone, &zone->rss_diff, &end,
"receive_secure_serial"));
dns_journal_set_sourceserial(rjournal, end);
dns_journal_commit(rjournal);
@ -13072,12 +13140,15 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
zone_settimer(zone, &timenow);
UNLOCK_ZONE(zone);
dns_db_closeversion(db, &oldver, ISC_FALSE);
dns_db_closeversion(db, &newver, ISC_TRUE);
dns_db_closeversion(zone->rss_db, &zone->rss_oldver, ISC_FALSE);
dns_db_closeversion(zone->rss_db, &zone->rss_newver, ISC_TRUE);
failure:
if (raw != NULL)
dns_zone_detach(&raw);
isc_event_free(&zone->rss_event);
event = ISC_LIST_HEAD(zone->rss_events);
if (zone->rss_raw != NULL)
dns_zone_detach(&zone->rss_raw);
if (result != ISC_R_SUCCESS)
dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_serial: %s",
dns_result_totext(result));
@ -13085,20 +13156,28 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
dns_difftuple_free(&tuple);
if (soatuple != NULL)
dns_difftuple_free(&soatuple);
if (db != NULL) {
if (oldver != NULL)
dns_db_closeversion(db, &oldver, ISC_FALSE);
if (newver != NULL)
dns_db_closeversion(db, &newver, ISC_FALSE);
dns_db_detach(&db);
if (zone->rss_db != NULL) {
if (zone->rss_oldver != NULL)
dns_db_closeversion(zone->rss_db, &zone->rss_oldver,
ISC_FALSE);
if (zone->rss_newver != NULL)
dns_db_closeversion(zone->rss_db, &zone->rss_newver,
ISC_FALSE);
dns_db_detach(&zone->rss_db);
}
INSIST(zone->rss_oldver == NULL);
INSIST(zone->rss_newver == NULL);
if (rjournal != NULL)
dns_journal_destroy(&rjournal);
dns_diff_clear(&diff);
dns_zone_idetach(&zone);
dns_diff_clear(&zone->rss_diff);
INSIST(oldver == NULL);
INSIST(newver == NULL);
if (event != NULL) {
LOCK_ZONE(zone);
INSIST(zone->irefs > 1);
zone->irefs--;
goto nextevent;
}
dns_zone_idetach(&zone);
}
static isc_result_t
@ -16029,6 +16108,12 @@ dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures) {
zone->signatures = signatures;
}
isc_uint32_t
dns_zone_getsignatures(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
return (zone->signatures);
}
void
dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type) {
REQUIRE(DNS_ZONE_VALID(zone));