summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/zone.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/zone.c')
-rw-r--r--contrib/bind9/lib/dns/zone.c2582
1 files changed, 2262 insertions, 320 deletions
diff --git a/contrib/bind9/lib/dns/zone.c b/contrib/bind9/lib/dns/zone.c
index c212bf6..10ba807 100644
--- a/contrib/bind9/lib/dns/zone.c
+++ b/contrib/bind9/lib/dns/zone.c
@@ -23,16 +23,18 @@
#include <errno.h>
#include <isc/file.h>
+#include <isc/hex.h>
#include <isc/mutex.h>
+#include <isc/pool.h>
#include <isc/print.h>
#include <isc/random.h>
#include <isc/ratelimiter.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/serial.h>
-#include <isc/strerror.h>
#include <isc/stats.h>
#include <isc/stdtime.h>
+#include <isc/strerror.h>
#include <isc/string.h>
#include <isc/taskpool.h>
#include <isc/timer.h>
@@ -61,6 +63,7 @@
#include <dns/private.h>
#include <dns/rbt.h>
#include <dns/rcode.h>
+#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
@@ -76,8 +79,10 @@
#include <dns/stats.h>
#include <dns/time.h>
#include <dns/tsig.h>
+#include <dns/update.h>
#include <dns/xfrin.h>
#include <dns/zone.h>
+#include <dns/zt.h>
#include <dst/dst.h>
@@ -145,6 +150,7 @@ typedef ISC_LIST(dns_signing_t) dns_signinglist_t;
typedef struct dns_nsec3chain dns_nsec3chain_t;
typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t;
typedef struct dns_keyfetch dns_keyfetch_t;
+typedef struct dns_asyncload dns_asyncload_t;
#define DNS_ZONE_CHECKLOCK
#ifdef DNS_ZONE_CHECKLOCK
@@ -217,6 +223,7 @@ struct dns_zone {
isc_time_t signingtime;
isc_time_t nsec3chaintime;
isc_time_t refreshkeytime;
+ isc_uint32_t refreshkeyinterval;
isc_uint32_t refreshkeycount;
isc_uint32_t refresh;
isc_uint32_t retry;
@@ -239,9 +246,11 @@ struct dns_zone {
isc_sockaddr_t masteraddr;
dns_notifytype_t notifytype;
isc_sockaddr_t *notify;
+ dns_name_t **notifykeynames;
unsigned int notifycnt;
isc_sockaddr_t notifyfrom;
isc_task_t *task;
+ isc_task_t *loadtask;
isc_sockaddr_t notifysrc4;
isc_sockaddr_t notifysrc6;
isc_sockaddr_t xfrsource4;
@@ -297,8 +306,10 @@ struct dns_zone {
* Optional per-zone statistics counters. Counted outside of this
* module.
*/
+ dns_zonestat_level_t statlevel;
isc_boolean_t requeststats_on;
isc_stats_t *requeststats;
+ dns_stats_t *rcvquerystats;
isc_uint32_t notifydelay;
dns_isselffunc_t isself;
void *isselfarg;
@@ -340,9 +351,25 @@ struct dns_zone {
isc_boolean_t is_rpz;
/*%
+ * Serial number update method.
+ */
+ dns_updatemethod_t updatemethod;
+
+ /*%
+ * whether ixfr is requested
+ */
+ isc_boolean_t requestixfr;
+
+ /*%
* Outstanding forwarded UPDATE requests.
*/
dns_forwardlist_t forwards;
+
+ dns_zone_t *raw;
+ dns_zone_t *secure;
+
+ isc_boolean_t sourceserialset;
+ isc_uint32_t sourceserial;
};
typedef struct {
@@ -403,8 +430,9 @@ typedef struct {
#define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U
#define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */
#define DNS_ZONEFLG_THAW 0x08000000U
-/* #define DNS_ZONEFLG_XXXXX 0x10000000U XXXMPA unused. */
+#define DNS_ZONEFLG_LOADPENDING 0x10000000U /*%< Loading scheduled */
#define DNS_ZONEFLG_NODELAY 0x20000000U
+#define DNS_ZONEFLG_SENDSECURE 0x40000000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
#define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0)
@@ -437,7 +465,9 @@ struct dns_zonemgr {
isc_timermgr_t * timermgr;
isc_socketmgr_t * socketmgr;
isc_taskpool_t * zonetasks;
+ isc_taskpool_t * loadtasks;
isc_task_t * task;
+ isc_pool_t * mctxpool;
isc_ratelimiter_t * rl;
isc_rwlock_t rwlock;
isc_mutex_t iolock;
@@ -476,6 +506,7 @@ struct dns_notify {
dns_request_t *request;
dns_name_t ns;
isc_sockaddr_t dst;
+ dns_tsigkey_t *key;
ISC_LINK(dns_notify_t) link;
};
@@ -594,6 +625,15 @@ struct dns_keyfetch {
dns_fetch_t *fetch;
};
+/*%
+ * Hold state for an asynchronous load
+ */
+struct dns_asyncload {
+ dns_zone_t *zone;
+ dns_zt_zoneloaded_t loaded;
+ void *loaded_arg;
+};
+
#define HOUR 3600
#define DAY (24*HOUR)
#define MONTH (30*DAY)
@@ -632,6 +672,9 @@ static void zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length);
static void zone_name_tostr(dns_zone_t *zone, char *buf, size_t length);
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 secure_locked,
+ isc_uint32_t serial);
#if 0
/* ondestroy example */
@@ -688,6 +731,8 @@ static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
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, isc_boolean_t locked,
+ dns_db_t *db);
#define ENTER zone_debuglog(zone, me, 1, "enter")
@@ -798,6 +843,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
isc_time_settoepoch(&zone->signingtime);
isc_time_settoepoch(&zone->nsec3chaintime);
isc_time_settoepoch(&zone->refreshkeytime);
+ zone->refreshkeyinterval = 0;
zone->refreshkeycount = 0;
zone->refresh = DNS_ZONE_DEFAULTREFRESH;
zone->retry = DNS_ZONE_DEFAULTRETRY;
@@ -813,9 +859,11 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->masterscnt = 0;
zone->curmaster = 0;
zone->notify = NULL;
+ zone->notifykeynames = NULL;
zone->notifytype = dns_notifytype_yes;
zone->notifycnt = 0;
zone->task = NULL;
+ zone->loadtask = NULL;
zone->update_acl = NULL;
zone->forward_acl = NULL;
zone->notify_acl = NULL;
@@ -857,7 +905,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->statelist = NULL;
zone->stats = NULL;
zone->requeststats_on = ISC_FALSE;
+ zone->statlevel = dns_zonestat_none;
zone->requeststats = NULL;
+ zone->rcvquerystats = NULL;
zone->notifydelay = 5;
zone->isself = NULL;
zone->isselfarg = NULL;
@@ -869,6 +919,10 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->added = ISC_FALSE;
zone->is_rpz = ISC_FALSE;
ISC_LIST_INIT(zone->forwards);
+ zone->raw = NULL;
+ zone->secure = NULL;
+ zone->sourceserial = 0;
+ zone->sourceserialset = ISC_FALSE;
zone->magic = ZONE_MAGIC;
@@ -925,6 +979,8 @@ zone_free(dns_zone_t *zone) {
if (zone->task != NULL)
isc_task_detach(&zone->task);
+ if (zone->loadtask != NULL)
+ isc_task_detach(&zone->loadtask);
if (zone->zmgr != NULL)
dns_zonemgr_releasezone(zone->zmgr, zone);
@@ -959,6 +1015,8 @@ zone_free(dns_zone_t *zone) {
isc_stats_detach(&zone->stats);
if (zone->requeststats != NULL)
isc_stats_detach(&zone->requeststats);
+ if(zone->rcvquerystats != NULL )
+ dns_stats_detach(&zone->rcvquerystats);
if (zone->db != NULL)
zone_detachdb(zone);
if (zone->acache != NULL)
@@ -1005,6 +1063,30 @@ zone_free(dns_zone_t *zone) {
}
/*
+ * Returns ISC_TRUE iff this the signed side of an inline-signing zone.
+ * Caller should hold zone lock.
+ */
+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
+ * Caller should hold zone lock.
+ */
+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.
*/
void
@@ -1032,6 +1114,8 @@ dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
zone_rdclass_tostr(zone, namebuf, sizeof namebuf);
zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf);
+ if (inline_secure(zone))
+ dns_zone_setclass(zone->raw, rdclass);
UNLOCK_ZONE(zone);
}
@@ -1092,6 +1176,7 @@ dns_zone_getserial(dns_zone_t *zone) {
*/
void
dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) {
+ char namebuf[1024];
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(type != dns_zone_none);
@@ -1102,6 +1187,12 @@ dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) {
LOCK_ZONE(zone);
REQUIRE(zone->type == dns_zone_none || zone->type == type);
zone->type = type;
+
+ if (zone->strnamerd != NULL)
+ isc_mem_free(zone->mctx, zone->strnamerd);
+
+ zone_namerd_tostr(zone, namebuf, sizeof namebuf);
+ zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf);
UNLOCK_ZONE(zone);
}
@@ -1220,10 +1311,12 @@ dns_zone_setview(dns_zone_t *zone, dns_view_t *view) {
zone_viewname_tostr(zone, namebuf, sizeof namebuf);
zone->strviewname = isc_mem_strdup(zone->mctx, namebuf);
+ if (inline_secure(zone))
+ dns_zone_setview(zone->raw, view);
+
UNLOCK_ZONE(zone);
}
-
dns_view_t *
dns_zone_getview(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
@@ -1257,6 +1350,8 @@ dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) {
zone_name_tostr(zone, namebuf, sizeof namebuf);
zone->strname = isc_mem_strdup(zone->mctx, namebuf);
+ if (result == ISC_R_SUCCESS && inline_secure(zone))
+ result = dns_zone_setorigin(zone->raw, origin);
UNLOCK_ZONE(zone);
return (result);
}
@@ -1394,16 +1489,24 @@ dns_zone_getjournal(dns_zone_t *zone) {
* allow dynamic updates either by having an update policy ("ssutable")
* or an "allow-update" ACL with a value other than exactly "{ none; }".
*/
-static isc_boolean_t
-zone_isdynamic(dns_zone_t *zone) {
+isc_boolean_t
+dns_zone_isdynamic(dns_zone_t *zone, isc_boolean_t ignore_freeze) {
REQUIRE(DNS_ZONE_VALID(zone));
- return (ISC_TF(zone->type == dns_zone_slave ||
- zone->type == dns_zone_stub ||
- zone->type == dns_zone_key ||
- (!zone->update_disabled && zone->ssutable != NULL) ||
- (!zone->update_disabled && zone->update_acl != NULL &&
- !dns_acl_isnone(zone->update_acl))));
+ if (zone->type == dns_zone_slave || zone->type == dns_zone_stub ||
+ zone->type == dns_zone_key ||
+ (zone->type == dns_zone_redirect && zone->masters != NULL))
+ return (ISC_TRUE);
+
+ /* If !ignore_freeze, we need check whether updates are disabled. */
+ if (zone->type == dns_zone_master &&
+ (!zone->update_disabled || ignore_freeze) &&
+ ((zone->ssutable != NULL) ||
+ (zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl))))
+ return (ISC_TRUE);
+
+ return (ISC_FALSE);
+
}
/*
@@ -1437,11 +1540,21 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
isc_time_t now;
isc_time_t loadtime, filetime;
dns_db_t *db = NULL;
- isc_boolean_t rbt;
+ isc_boolean_t rbt, hasraw;
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
+ hasraw = inline_secure(zone);
+ if (hasraw) {
+ result = zone_load(zone->raw, flags);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK_ZONE(zone);
+ return(result);
+ }
+ LOCK_ZONE(zone->raw);
+ }
+
TIME_NOW(&now);
INSIST(zone->type != dns_zone_none);
@@ -1453,7 +1566,6 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
goto cleanup;
}
-
INSIST(zone->db_argc >= 1);
rbt = strcmp(zone->db_argv[0], "rbt") == 0 ||
@@ -1467,7 +1579,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
goto cleanup;
}
- if (zone->db != NULL && zone_isdynamic(zone)) {
+ if (zone->db != NULL && dns_zone_isdynamic(zone, ISC_FALSE)) {
/*
* This is a slave, stub, or dynamically updated
* zone being reloaded. Do nothing - the database
@@ -1531,7 +1643,8 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
goto cleanup;
}
- if ((zone->type == dns_zone_slave || zone->type == dns_zone_stub) &&
+ if ((zone->type == dns_zone_slave || zone->type == dns_zone_stub ||
+ (zone->type == dns_zone_redirect && zone->masters != NULL)) &&
rbt) {
if (zone->masterfile == NULL ||
!isc_file_exists(zone->masterfile)) {
@@ -1569,7 +1682,9 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
result = zone_startload(db, zone, loadtime);
} else {
result = DNS_R_NOMASTERFILE;
- if (zone->type == dns_zone_master) {
+ if (zone->type == dns_zone_master ||
+ (zone->type == dns_zone_redirect &&
+ zone->masters == NULL)) {
dns_zone_log(zone, ISC_LOG_ERROR,
"loading zone: "
"no master file configured");
@@ -1590,6 +1705,8 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
result = zone_postload(zone, db, loadtime, result);
cleanup:
+ if (hasraw)
+ UNLOCK_ZONE(zone->raw);
UNLOCK_ZONE(zone);
if (db != NULL)
dns_db_detach(&db);
@@ -1606,17 +1723,100 @@ dns_zone_loadnew(dns_zone_t *zone) {
return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
}
+static void
+zone_asyncload(isc_task_t *task, isc_event_t *event) {
+ dns_asyncload_t *asl = event->ev_arg;
+ dns_zone_t *zone = asl->zone;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ UNUSED(task);
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
+ result = ISC_R_CANCELED;
+ isc_event_free(&event);
+ if (result == ISC_R_CANCELED ||
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING))
+ goto cleanup;
+
+ zone_load(zone, 0);
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING);
+ UNLOCK_ZONE(zone);
+
+ /* Inform the zone table we've finished loading */
+ if (asl->loaded != NULL)
+ (asl->loaded)(asl->loaded_arg, zone, task);
+
+ cleanup:
+ isc_mem_put(zone->mctx, asl, sizeof (*asl));
+ dns_zone_idetach(&zone);
+}
+
+isc_result_t
+dns_zone_asyncload(dns_zone_t *zone, dns_zt_zoneloaded_t done, void *arg) {
+ isc_event_t *e;
+ dns_asyncload_t *asl = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (zone->zmgr == NULL)
+ return (ISC_R_FAILURE);
+
+ asl = isc_mem_get(zone->mctx, sizeof (*asl));
+ if (asl == NULL)
+ CHECK(ISC_R_NOMEMORY);
+
+ asl->zone = NULL;
+ asl->loaded = done;
+ asl->loaded_arg = arg;
+
+ e = isc_event_allocate(zone->zmgr->mctx, zone->zmgr,
+ DNS_EVENT_ZONELOAD,
+ zone_asyncload, asl,
+ sizeof(isc_event_t));
+ if (e == NULL)
+ CHECK(ISC_R_NOMEMORY);
+
+ LOCK_ZONE(zone);
+ zone_iattach(zone, &asl->zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADPENDING);
+ isc_task_send(zone->loadtask, &e);
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (asl != NULL)
+ isc_mem_put(zone->mctx, asl, sizeof (*asl));
+ return (result);
+}
+
+isc_boolean_t
+dns__zone_loadpending(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (ISC_TF(DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING)));
+}
+
isc_result_t
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. */
break;
- case ISC_R_SUCCESS:
case DNS_R_UPTODATE:
+ case ISC_R_SUCCESS:
case DNS_R_SEENINCLUDE:
zone->update_disabled = ISC_FALSE;
break;
@@ -1635,7 +1835,8 @@ get_master_options(dns_zone_t *zone) {
unsigned int options;
options = DNS_MASTER_ZONE;
- if (zone->type == dns_zone_slave)
+ if (zone->type == dns_zone_slave ||
+ (zone->type == dns_zone_redirect && zone->masters == NULL))
options |= DNS_MASTER_SLAVE;
if (zone->type == dns_zone_key)
options |= DNS_MASTER_KEY;
@@ -1653,9 +1854,9 @@ get_master_options(dns_zone_t *zone) {
options |= DNS_MASTER_CHECKMXFAIL;
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
options |= DNS_MASTER_CHECKWILDCARD;
- if (zone->type == dns_zone_master &&
+ if (inline_secure(zone) || (zone->type == dns_zone_master &&
((zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)) ||
- zone->ssutable != NULL))
+ zone->ssutable != NULL)))
options |= DNS_MASTER_RESIGN;
return (options);
}
@@ -1679,8 +1880,7 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
result = dns_master_loadfileinc3(load->zone->masterfile,
dns_db_origin(load->db),
dns_db_origin(load->db),
- load->zone->rdclass,
- options,
+ load->zone->rdclass, options,
load->zone->sigresigninginterval,
&load->callbacks, task,
zone_loaddone, load,
@@ -1696,11 +1896,29 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
}
static void
+get_raw_serial(dns_zone_t *raw, dns_masterrawheader_t *rawdata) {
+ isc_result_t result;
+ unsigned int soacount;
+
+ LOCK(&raw->lock);
+ if (raw->db != NULL) {
+ result = zone_get_from_db(raw, raw->db, NULL, &soacount,
+ &rawdata->sourceserial,
+ NULL, NULL, NULL, NULL,
+ NULL);
+ if (result == ISC_R_SUCCESS && soacount > 0U)
+ rawdata->flags |= DNS_MASTERRAW_SOURCESERIALSET;
+ }
+ UNLOCK(&raw->lock);
+}
+
+static void
zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
const char me[] = "zone_gotwritehandle";
dns_zone_t *zone = event->ev_arg;
isc_result_t result = ISC_R_SUCCESS;
dns_dbversion_t *version = NULL;
+ dns_masterrawheader_t rawdata;
REQUIRE(DNS_ZONE_VALID(zone));
INSIST(task == zone->task);
@@ -1716,11 +1934,14 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL) {
dns_db_currentversion(zone->db, &version);
- result = dns_master_dumpinc2(zone->mctx, zone->db, version,
+ dns_master_initrawheader(&rawdata);
+ if (inline_secure(zone))
+ get_raw_serial(zone->raw, &rawdata);
+ result = dns_master_dumpinc3(zone->mctx, zone->db, version,
&dns_master_style_default,
zone->masterfile, zone->task,
dump_done, zone, &zone->dctx,
- zone->masterformat);
+ zone->masterformat, &rawdata);
dns_db_closeversion(zone->db, &version, ISC_FALSE);
} else
result = ISC_R_CANCELED;
@@ -1734,6 +1955,31 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
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 ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0)
+ return;
+
+ 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_setrawdata(zone, header);
+ UNLOCK_ZONE(zone);
+}
+
static isc_result_t
zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
dns_load_t *load;
@@ -1753,7 +1999,7 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
options |= DNS_MASTER_MANYERRORS;
- if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) {
+ if (zone->zmgr != NULL && zone->db != NULL && zone->loadtask != NULL) {
load = isc_mem_get(zone->mctx, sizeof(*load));
if (load == NULL)
return (ISC_R_NOMEMORY);
@@ -1768,11 +2014,13 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
zone_iattach(zone, &load->zone);
dns_db_attach(db, &load->db);
dns_rdatacallbacks_init(&load->callbacks);
+ load->callbacks.rawdata = zone_setrawdata;
+ zone_iattach(zone, &load->callbacks.zone);
result = dns_db_beginload(db, &load->callbacks.add,
&load->callbacks.add_private);
if (result != ISC_R_SUCCESS)
goto cleanup;
- result = zonemgr_getio(zone->zmgr, ISC_TRUE, zone->task,
+ result = zonemgr_getio(zone->zmgr, ISC_TRUE, zone->loadtask,
zone_gotreadhandle, load,
&zone->readio);
if (result != ISC_R_SUCCESS) {
@@ -1789,18 +2037,24 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
dns_rdatacallbacks_t callbacks;
dns_rdatacallbacks_init(&callbacks);
+ callbacks.rawdata = zone_setrawdata;
+ zone_iattach(zone, &callbacks.zone);
result = dns_db_beginload(db, &callbacks.add,
&callbacks.add_private);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
+ zone_idetach(&callbacks.zone);
return (result);
- result = dns_master_loadfile3(zone->masterfile, &zone->origin,
- &zone->origin, zone->rdclass,
- options, zone->sigresigninginterval,
+ }
+ result = dns_master_loadfile3(zone->masterfile,
+ &zone->origin, &zone->origin,
+ zone->rdclass, options,
+ zone->sigresigninginterval,
&callbacks, zone->mctx,
zone->masterformat);
tresult = dns_db_endload(db, &callbacks.add_private);
if (result == ISC_R_SUCCESS)
result = tresult;
+ zone_idetach(&callbacks.zone);
}
return (result);
@@ -1809,6 +2063,7 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
load->magic = 0;
dns_db_detach(&load->db);
zone_idetach(&load->zone);
+ zone_idetach(&load->callbacks.zone);
isc_mem_detach(&load->mctx);
isc_mem_put(zone->mctx, load, sizeof(*load));
return (result);
@@ -2531,13 +2786,22 @@ resume_signingwithkey(dns_zone_t *zone) {
static isc_result_t
zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
dns_nsec3chain_t *nsec3chain, *current;
+ dns_dbversion_t *version = NULL;
+ isc_boolean_t nseconly = ISC_FALSE, nsec3ok = ISC_FALSE;
isc_result_t result;
isc_time_t now;
unsigned int options = 0;
char saltbuf[255*2+1];
- char flags[sizeof("REMOVE|CREATE|NONSEC|OPTOUT")];
+ char flags[sizeof("INITIAL|REMOVE|CREATE|NONSEC|OPTOUT")];
int i;
+ dns_db_currentversion(zone->db, &version);
+ result = dns_nsec_nseconly(zone->db, version, &nseconly);
+ nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
+ dns_db_closeversion(zone->db, &version, ISC_FALSE);
+ if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0)
+ return (ISC_R_SUCCESS);
+
nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain);
if (nsec3chain == NULL)
return (ISC_R_NOMEMORY);
@@ -2564,6 +2828,12 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
flags[0] = '\0';
if (nsec3param->flags & DNS_NSEC3FLAG_REMOVE)
strlcat(flags, "REMOVE", sizeof(flags));
+ if (nsec3param->flags & DNS_NSEC3FLAG_INITIAL) {
+ if (flags[0] == '\0')
+ strlcpy(flags, "INITIAL", sizeof(flags));
+ else
+ strlcat(flags, "|INITIAL", sizeof(flags));
+ }
if (nsec3param->flags & DNS_NSEC3FLAG_CREATE) {
if (flags[0] == '\0')
strlcpy(flags, "CREATE", sizeof(flags));
@@ -2592,6 +2862,7 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
"zone_addnsec3chain(%u,%s,%u,%s)",
nsec3param->hash, flags, nsec3param->iterations,
saltbuf);
+
for (current = ISC_LIST_HEAD(zone->nsec3chain);
current != NULL;
current = ISC_LIST_NEXT(current, link)) {
@@ -2644,6 +2915,7 @@ resume_addnsec3chain(dns_zone_t *zone) {
dns_rdataset_t rdataset;
isc_result_t result;
dns_rdata_nsec3param_t nsec3param;
+ isc_boolean_t nseconly = ISC_FALSE, nsec3ok = ISC_FALSE;
if (zone->privatetype == 0)
return;
@@ -2653,6 +2925,10 @@ resume_addnsec3chain(dns_zone_t *zone) {
goto cleanup;
dns_db_currentversion(zone->db, &version);
+
+ result = dns_nsec_nseconly(zone->db, version, &nseconly);
+ nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
+
dns_rdataset_init(&rdataset);
result = dns_db_findrdataset(zone->db, node, version,
zone->privatetype, dns_rdatatype_none,
@@ -2676,8 +2952,9 @@ resume_addnsec3chain(dns_zone_t *zone) {
continue;
result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
- if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 ||
- (nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
+ if (((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) ||
+ ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 && nsec3ok))
+ {
result = zone_addnsec3chain(zone, &nsec3param);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
@@ -2727,7 +3004,7 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) {
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
isc_boolean_t dynamic = (zone->type == dns_zone_master) ?
- zone_isdynamic(zone) : ISC_FALSE;
+ dns_zone_isdynamic(zone, ISC_FALSE) : ISC_FALSE;
dns_rdataset_init(&rdataset);
result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node);
@@ -3149,8 +3426,8 @@ update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
}
static isc_result_t
-increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
- dns_diff_t *diff, isc_mem_t *mctx) {
+update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
+ isc_mem_t *mctx, dns_updatemethod_t method) {
dns_difftuple_t *deltuple = NULL;
dns_difftuple_t *addtuple = NULL;
isc_uint32_t serial;
@@ -3161,12 +3438,7 @@ increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
addtuple->op = DNS_DIFFOP_ADD;
serial = dns_soa_getserial(&addtuple->rdata);
-
- /* RFC1982 */
- serial = (serial + 1) & 0xFFFFFFFF;
- if (serial == 0)
- serial = 1;
-
+ serial = dns_update_soaserial(serial, method);
dns_soa_setserial(serial, &addtuple->rdata);
CHECK(do_one_tuple(&deltuple, db, ver, diff));
CHECK(do_one_tuple(&addtuple, db, ver, diff));
@@ -3184,17 +3456,20 @@ increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
* Write all transactions in 'diff' to the zone journal file.
*/
static isc_result_t
-zone_journal(dns_zone_t *zone, dns_diff_t *diff, const char *caller) {
+zone_journal(dns_zone_t *zone, dns_diff_t *diff, isc_uint32_t *sourceserial,
+ const char *caller)
+{
const char me[] = "zone_journal";
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,
- ISC_TRUE, &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",
@@ -3202,15 +3477,18 @@ zone_journal(dns_zone_t *zone, dns_diff_t *diff, const char *caller) {
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",
caller, dns_result_totext(result));
- return (result);
}
+ dns_journal_destroy(&journal);
}
+
return (result);
}
@@ -3391,8 +3669,9 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
if (changed) {
/* Write changes to journal file. */
- CHECK(increment_soa_serial(db, ver, &diff, zone->mctx));
- CHECK(zone_journal(zone, &diff, "sync_keyzone"));
+ CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
+ zone->updatemethod));
+ CHECK(zone_journal(zone, &diff, NULL, "sync_keyzone"));
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
zone_needdump(zone, 30);
@@ -3418,6 +3697,73 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
return (result);
}
+isc_result_t
+dns_zone_synckeyzone(dns_zone_t *zone) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+
+ if (zone->type != dns_zone_key)
+ return (DNS_R_BADZONE);
+
+ CHECK(dns_zone_getdb(zone, &db));
+
+ LOCK_ZONE(zone);
+ result = sync_keyzone(zone, db);
+ UNLOCK_ZONE(zone);
+
+ failure:
+ if (db != NULL)
+ dns_db_detach(&db);
+ return (result);
+}
+
+static void
+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.
+ */
+ if (zone->raw->db != NULL) {
+ if (zone->db != NULL) {
+ isc_uint32_t serial;
+ unsigned int soacount;
+
+ result = zone_get_from_db(zone->raw, zone->raw->db,
+ NULL, &soacount, &serial, NULL,
+ NULL, NULL, NULL, NULL);
+ if (result == ISC_R_SUCCESS && soacount > 0U)
+ 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);
+}
+
+static isc_boolean_t
+zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) {
+ isc_result_t result;
+ isc_boolean_t answer = ISC_FALSE;
+ dns_diff_t diff;
+
+ dns_diff_init(mctx, &diff);
+ result = dns_db_diffx(&diff, db1, NULL, db2, NULL, NULL);
+ if (result == ISC_R_SUCCESS && ISC_LIST_EMPTY(diff.tuples))
+ answer = ISC_TRUE;
+ dns_diff_clear(&diff);
+ 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)
@@ -3441,7 +3787,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
*/
if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
if (zone->type == dns_zone_slave ||
- zone->type == dns_zone_stub) {
+ zone->type == dns_zone_stub ||
+ (zone->type == dns_zone_redirect &&
+ zone->masters == NULL)) {
if (result == ISC_R_FILENOTFOUND)
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"no master file");
@@ -3451,6 +3799,12 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
"failed: %s",
zone->masterfile,
dns_result_totext(result));
+ } else if (zone->type == dns_zone_master &&
+ inline_secure(zone) && result == ISC_R_FILENOTFOUND)
+ {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "no master file, requesting db");
+ maybe_send_secure(zone);
} else {
int level = ISC_LOG_ERROR;
if (zone->type == dns_zone_key &&
@@ -3510,6 +3864,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
"journal rollforward failed: %s",
dns_result_totext(result));
goto cleanup;
+
+
}
if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) {
dns_zone_log(zone, ISC_LOG_ERROR,
@@ -3525,7 +3881,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
needdump = ISC_TRUE;
}
- dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded; checking validity");
/*
* Obtain ns, soa and cname counts for top of zone.
*/
@@ -3539,6 +3894,46 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
}
/*
+ * Check to make sure the journal is up to date, and remove the
+ * journal file if it isn't, as we wouldn't be able to apply
+ * updates otherwise.
+ */
+ if (zone->journal != NULL && dns_zone_isdynamic(zone, ISC_TRUE) &&
+ ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) {
+ isc_uint32_t jserial;
+ dns_journal_t *journal = NULL;
+
+ result = dns_journal_open(zone->mctx, zone->journal,
+ DNS_JOURNAL_READ, &journal);
+ if (result == ISC_R_SUCCESS) {
+ jserial = dns_journal_last_serial(journal);
+ dns_journal_destroy(&journal);
+ } else {
+ jserial = serial;
+ result = ISC_R_SUCCESS;
+ }
+
+ if (jserial != serial) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "journal file is out of date: "
+ "removing journal file");
+ if (remove(zone->journal) < 0 && errno != ENOENT) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc__strerror(errno, strbuf, sizeof(strbuf));
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_ZONE,
+ ISC_LOG_WARNING,
+ "unable to remove journal "
+ "'%s': '%s'",
+ zone->journal, strbuf);
+ }
+ }
+ }
+
+ dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded; checking validity");
+
+ /*
* Master / Slave / Stub zones require both NS and SOA records at
* the top of the zone.
*/
@@ -3548,6 +3943,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
case dns_zone_master:
case dns_zone_slave:
case dns_zone_stub:
+ case dns_zone_redirect:
if (soacount != 1) {
dns_zone_log(zone, ISC_LOG_ERROR,
"has %d SOA records", soacount);
@@ -3564,7 +3960,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
result = DNS_R_BADZONE;
goto cleanup;
}
- if (zone->type != dns_zone_stub) {
+ if (zone->type != dns_zone_stub &&
+ zone->type != dns_zone_redirect) {
result = check_nsec3param(zone, db);
if (result != ISC_R_SUCCESS)
goto cleanup;
@@ -3575,7 +3972,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
result = DNS_R_BADZONE;
goto cleanup;
}
-
if (zone->type == dns_zone_master &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRR) &&
!zone_check_dup(zone, db)) {
@@ -3602,6 +3998,14 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
INSIST(zone->type == dns_zone_master);
+ if (serial == oldserial &&
+ zone_unchanged(zone->db, db, zone->mctx)) {
+ dns_zone_log(zone, ISC_LOG_INFO,
+ "ixfr-from-differences: "
+ "unchanged");
+ return(ISC_R_SUCCESS);
+ }
+
serialmin = (oldserial + 1) & 0xffffffffU;
serialmax = (oldserial + 0x7fffffffU) &
0xffffffffU;
@@ -3644,7 +4048,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
if (zone->type == dns_zone_slave ||
- zone->type == dns_zone_stub) {
+ zone->type == dns_zone_stub ||
+ (zone->type == dns_zone_redirect &&
+ zone->masters != NULL)) {
isc_time_t t;
isc_uint32_t delay;
@@ -3666,6 +4072,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
&zone->expiretime) >= 0)
zone->refreshtime = now;
}
+
break;
case dns_zone_key:
@@ -3717,8 +4124,24 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
DNS_ZONE_SETFLAG(zone,
DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SENDSECURE) &&
+ 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) {
@@ -3736,7 +4159,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
}
if (zone->type == dns_zone_master &&
- zone_isdynamic(zone) &&
+ !DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN) &&
+ dns_zone_isdynamic(zone, ISC_FALSE) &&
dns_db_issecure(db)) {
dns_name_t *name;
dns_fixedname_t fixed;
@@ -3775,12 +4199,14 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
dns_db_issecure(db) ? " (DNSSEC signed)" : "");
zone->loadtime = loadtime;
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING);
return (result);
cleanup:
if (zone->type == dns_zone_slave ||
zone->type == dns_zone_stub ||
- zone->type == dns_zone_key) {
+ zone->type == dns_zone_key ||
+ (zone->type == dns_zone_redirect && zone->masters != NULL)) {
if (zone->journal != NULL)
zone_saveunique(zone, zone->journal, "jn-XXXXXXXX");
if (zone->masterfile != NULL)
@@ -3791,8 +4217,15 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
if (zone->task != NULL)
zone_settimer(zone, &now);
result = ISC_R_SUCCESS;
- } else if (zone->type == dns_zone_master)
- dns_zone_log(zone, ISC_LOG_ERROR, "not loaded due to errors.");
+ } else if (zone->type == dns_zone_master ||
+ zone->type == dns_zone_redirect) {
+ if (!(inline_secure(zone) && result == ISC_R_FILENOTFOUND))
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "not loaded due to errors.");
+ else if (zone->type == dns_zone_master)
+ result = ISC_R_SUCCESS;
+ }
+
return (result);
}
@@ -4087,6 +4520,8 @@ dns_zone_attach(dns_zone_t *source, dns_zone_t **target) {
void
dns_zone_detach(dns_zone_t **zonep) {
dns_zone_t *zone;
+ dns_zone_t *raw = NULL;
+ dns_zone_t *secure = NULL;
unsigned int refs;
isc_boolean_t free_now = ISC_FALSE;
@@ -4124,12 +4559,21 @@ dns_zone_detach(dns_zone_t **zonep) {
*/
INSIST(zone->view == NULL);
free_now = ISC_TRUE;
+ raw = zone->raw;
+ zone->raw = NULL;
+ secure = zone->secure;
+ zone->secure = NULL;
}
UNLOCK_ZONE(zone);
}
*zonep = NULL;
- if (free_now)
+ if (free_now) {
+ if (raw != NULL)
+ dns_zone_detach(&raw);
+ if (secure != NULL)
+ dns_zone_idetach(&secure);
zone_free(zone);
+ }
}
void
@@ -4141,26 +4585,6 @@ dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) {
UNLOCK_ZONE(source);
}
-isc_result_t
-dns_zone_synckeyzone(dns_zone_t *zone) {
- isc_result_t result;
- dns_db_t *db = NULL;
-
- if (zone->type != dns_zone_key)
- return (DNS_R_BADZONE);
-
- CHECK(dns_zone_getdb(zone, &db));
-
- LOCK_ZONE(zone);
- result = sync_keyzone(zone, db);
- UNLOCK_ZONE(zone);
-
- failure:
- if (db != NULL)
- dns_db_detach(&db);
- return (result);
-}
-
static void
zone_iattach(dns_zone_t *source, dns_zone_t **target) {
@@ -4385,48 +4809,8 @@ dns_zone_getnotifysrc6(dns_zone_t *zone) {
return (&zone->notifysrc6);
}
-isc_result_t
-dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
- isc_uint32_t count)
-{
- isc_sockaddr_t *new;
-
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(count == 0 || notify != NULL);
-
- LOCK_ZONE(zone);
- if (zone->notify != NULL) {
- isc_mem_put(zone->mctx, zone->notify,
- zone->notifycnt * sizeof(*new));
- zone->notify = NULL;
- zone->notifycnt = 0;
- }
- if (count != 0) {
- new = isc_mem_get(zone->mctx, count * sizeof(*new));
- if (new == NULL) {
- UNLOCK_ZONE(zone);
- return (ISC_R_NOMEMORY);
- }
- memcpy(new, notify, count * sizeof(*new));
- zone->notify = new;
- zone->notifycnt = count;
- }
- UNLOCK_ZONE(zone);
- return (ISC_R_SUCCESS);
-}
-
-isc_result_t
-dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters,
- isc_uint32_t count)
-{
- isc_result_t result;
-
- result = dns_zone_setmasterswithkeys(zone, masters, NULL, count);
- return (result);
-}
-
static isc_boolean_t
-same_masters(const isc_sockaddr_t *old, const isc_sockaddr_t *new,
+same_addrs(const isc_sockaddr_t *old, const isc_sockaddr_t *new,
isc_uint32_t count)
{
unsigned int i;
@@ -4456,15 +4840,170 @@ same_keynames(dns_name_t **old, dns_name_t **new, isc_uint32_t count) {
return (ISC_TRUE);
}
+static void
+clear_addresskeylist(isc_sockaddr_t **addrsp, dns_name_t ***keynamesp,
+ unsigned int *countp, isc_mem_t *mctx)
+{
+ unsigned int count;
+ isc_sockaddr_t *addrs;
+ dns_name_t **keynames;
+
+ REQUIRE(countp != NULL && addrsp != NULL && keynamesp != NULL);
+
+ count = *countp;
+ *countp = 0;
+ addrs = *addrsp;
+ *addrsp = NULL;
+ keynames = *keynamesp;
+ *keynamesp = NULL;
+
+ if (addrs != NULL)
+ isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t));
+
+ if (keynames != NULL) {
+ unsigned int i;
+ for (i = 0; i < count; i++) {
+ if (keynames[i] != NULL) {
+ dns_name_free(keynames[i], mctx);
+ isc_mem_put(mctx, keynames[i],
+ sizeof(dns_name_t));
+ keynames[i] = NULL;
+ }
+ }
+ isc_mem_put(mctx, keynames, count * sizeof(dns_name_t *));
+ }
+}
+
+static isc_result_t
+set_addrkeylist(unsigned int count,
+ const isc_sockaddr_t *addrs, isc_sockaddr_t **newaddrsp,
+ dns_name_t **names, dns_name_t ***newnamesp,
+ isc_mem_t *mctx)
+{
+ isc_result_t result;
+ isc_sockaddr_t *newaddrs = NULL;
+ dns_name_t **newnames = NULL;
+ unsigned int i;
+
+ REQUIRE(newaddrsp != NULL && *newaddrsp == NULL);
+ REQUIRE(newnamesp != NULL && *newnamesp == NULL);
+
+ newaddrs = isc_mem_get(mctx, count * sizeof(*newaddrs));
+ if (newaddrs == NULL)
+ return (ISC_R_NOMEMORY);
+ memcpy(newaddrs, addrs, count * sizeof(*newaddrs));
+
+ newnames = NULL;
+ if (names != NULL) {
+ newnames = isc_mem_get(mctx, count * sizeof(*newnames));
+ if (newnames == NULL) {
+ isc_mem_put(mctx, newaddrs, count * sizeof(*newaddrs));
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < count; i++)
+ newnames[i] = NULL;
+ for (i = 0; i < count; i++) {
+ if (names[i] != NULL) {
+ newnames[i] = isc_mem_get(mctx,
+ sizeof(dns_name_t));
+ if (newnames[i] == NULL)
+ goto allocfail;
+ dns_name_init(newnames[i], NULL);
+ result = dns_name_dup(names[i], mctx,
+ newnames[i]);
+ if (result != ISC_R_SUCCESS) {
+ allocfail:
+ for (i = 0; i < count; i++)
+ if (newnames[i] != NULL)
+ dns_name_free(
+ newnames[i],
+ mctx);
+ isc_mem_put(mctx, newaddrs,
+ count * sizeof(*newaddrs));
+ isc_mem_put(mctx, newnames,
+ count * sizeof(*newnames));
+ return (ISC_R_NOMEMORY);
+ }
+ }
+ }
+ }
+
+ *newaddrsp = newaddrs;
+ *newnamesp = newnames;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
+ isc_uint32_t count)
+{
+ return (dns_zone_setalsonotifywithkeys(zone, notify, NULL, count));
+}
+
+isc_result_t
+dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify,
+ dns_name_t **keynames, isc_uint32_t count)
+{
+ isc_result_t result;
+ isc_sockaddr_t *newaddrs = NULL;
+ dns_name_t **newnames = NULL;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(count == 0 || notify != NULL);
+ if (keynames != NULL)
+ REQUIRE(count != 0);
+
+ LOCK_ZONE(zone);
+
+ if (count == zone->notifycnt &&
+ same_addrs(zone->notify, notify, count) &&
+ same_keynames(zone->notifykeynames, keynames, count))
+ goto unlock;
+
+ clear_addresskeylist(&zone->notify, &zone->notifykeynames,
+ &zone->notifycnt, zone->mctx);
+
+ if (count == 0)
+ goto unlock;
+
+ /*
+ * Set up the notify and notifykey lists
+ */
+ result = set_addrkeylist(count, notify, &newaddrs,
+ keynames, &newnames, zone->mctx);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+
+ /*
+ * Everything is ok so attach to the zone.
+ */
+ zone->notify = newaddrs;
+ zone->notifykeynames = newnames;
+ zone->notifycnt = count;
+ unlock:
+ UNLOCK_ZONE(zone);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters,
+ isc_uint32_t count)
+{
+ isc_result_t result;
+
+ result = dns_zone_setmasterswithkeys(zone, masters, NULL, count);
+ return (result);
+}
+
isc_result_t
dns_zone_setmasterswithkeys(dns_zone_t *zone,
const isc_sockaddr_t *masters,
dns_name_t **keynames,
isc_uint32_t count)
{
- isc_sockaddr_t *new;
isc_result_t result = ISC_R_SUCCESS;
- dns_name_t **newname;
+ isc_sockaddr_t *newaddrs = NULL;
+ dns_name_t **newnames = NULL;
isc_boolean_t *newok;
unsigned int i;
@@ -4482,38 +5021,24 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone,
* unlock and exit.
*/
if (count != zone->masterscnt ||
- !same_masters(zone->masters, masters, count) ||
+ !same_addrs(zone->masters, masters, count) ||
!same_keynames(zone->masterkeynames, keynames, count)) {
if (zone->request != NULL)
dns_request_cancel(zone->request);
} else
goto unlock;
- if (zone->masters != NULL) {
- isc_mem_put(zone->mctx, zone->masters,
- zone->masterscnt * sizeof(*new));
- zone->masters = NULL;
- }
- if (zone->masterkeynames != NULL) {
- for (i = 0; i < zone->masterscnt; i++) {
- if (zone->masterkeynames[i] != NULL) {
- dns_name_free(zone->masterkeynames[i],
- zone->mctx);
- isc_mem_put(zone->mctx,
- zone->masterkeynames[i],
- sizeof(dns_name_t));
- zone->masterkeynames[i] = NULL;
- }
- }
- isc_mem_put(zone->mctx, zone->masterkeynames,
- zone->masterscnt * sizeof(dns_name_t *));
- zone->masterkeynames = NULL;
- }
+
+ /*
+ * This needs to happen before clear_addresskeylist() sets
+ * zone->masterscnt to 0:
+ */
if (zone->mastersok != NULL) {
isc_mem_put(zone->mctx, zone->mastersok,
zone->masterscnt * sizeof(isc_boolean_t));
zone->mastersok = NULL;
}
- zone->masterscnt = 0;
+ clear_addresskeylist(&zone->masters, &zone->masterkeynames,
+ &zone->masterscnt, zone->mctx);
/*
* If count == 0, don't allocate any space for masters, mastersok or
* keynames so internally, those pointers are NULL if count == 0
@@ -4522,76 +5047,34 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone,
goto unlock;
/*
- * masters must contain count elements!
- */
- new = isc_mem_get(zone->mctx, count * sizeof(*new));
- if (new == NULL) {
- result = ISC_R_NOMEMORY;
- goto unlock;
- }
- memcpy(new, masters, count * sizeof(*new));
-
- /*
- * Similarly for mastersok.
+ * mastersok must contain count elements
*/
newok = isc_mem_get(zone->mctx, count * sizeof(*newok));
if (newok == NULL) {
result = ISC_R_NOMEMORY;
- isc_mem_put(zone->mctx, new, count * sizeof(*new));
+ isc_mem_put(zone->mctx, newaddrs, count * sizeof(*newaddrs));
goto unlock;
};
for (i = 0; i < count; i++)
newok[i] = ISC_FALSE;
/*
- * if keynames is non-NULL, it must contain count elements!
+ * Now set up the masters and masterkey lists
*/
- newname = NULL;
- if (keynames != NULL) {
- newname = isc_mem_get(zone->mctx, count * sizeof(*newname));
- if (newname == NULL) {
- result = ISC_R_NOMEMORY;
- isc_mem_put(zone->mctx, new, count * sizeof(*new));
- isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
- goto unlock;
- }
- for (i = 0; i < count; i++)
- newname[i] = NULL;
- for (i = 0; i < count; i++) {
- if (keynames[i] != NULL) {
- newname[i] = isc_mem_get(zone->mctx,
- sizeof(dns_name_t));
- if (newname[i] == NULL)
- goto allocfail;
- dns_name_init(newname[i], NULL);
- result = dns_name_dup(keynames[i], zone->mctx,
- newname[i]);
- if (result != ISC_R_SUCCESS) {
- allocfail:
- for (i = 0; i < count; i++)
- if (newname[i] != NULL)
- dns_name_free(
- newname[i],
- zone->mctx);
- isc_mem_put(zone->mctx, new,
- count * sizeof(*new));
- isc_mem_put(zone->mctx, newok,
- count * sizeof(*newok));
- isc_mem_put(zone->mctx, newname,
- count * sizeof(*newname));
- goto unlock;
- }
- }
- }
+ result = set_addrkeylist(count, masters, &newaddrs,
+ keynames, &newnames, zone->mctx);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
+ goto unlock;
}
/*
* Everything is ok so attach to the zone.
*/
zone->curmaster = 0;
- zone->masters = new;
zone->mastersok = newok;
- zone->masterkeynames = newname;
+ zone->masters = newaddrs;
+ zone->masterkeynames = newnames;
zone->masterscnt = count;
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS);
@@ -5072,9 +5555,12 @@ zone_resigninc(dns_zone_t *zone) {
zonediff_init(&zonediff, &_sig_diff);
/*
- * Updates are disabled. Pause for 5 minutes.
+ * Zone is frozen or automatic resigning is disabled.
+ * Pause for 5 minutes.
*/
- if (zone->update_disabled) {
+ if (zone->update_disabled ||
+ DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN))
+ {
result = ISC_R_FAILURE;
goto failure;
}
@@ -5186,18 +5672,18 @@ zone_resigninc(dns_zone_t *zone) {
*/
if (ISC_LIST_EMPTY(zonediff.diff->tuples)) {
/*
- * Commit the changes if any key has been marked as offline.
- */
+ * Commit the changes if any key has been marked as offline. */
if (zonediff.offline)
dns_db_closeversion(db, &version, ISC_TRUE);
goto failure;
}
/* Increment SOA serial if we have made changes */
- result = increment_soa_serial(db, version, zonediff.diff, zone->mctx);
+ result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
+ zone->updatemethod);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
- "zone_resigninc:increment_soa_serial -> %s",
+ "zone_resigninc:update_soa_serial -> %s",
dns_result_totext(result));
goto failure;
}
@@ -5217,7 +5703,7 @@ zone_resigninc(dns_zone_t *zone) {
}
/* Write changes to journal file. */
- CHECK(zone_journal(zone, zonediff.diff, "zone_resigninc"));
+ CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_resigninc"));
/* Everything has succeeded. Commit the changes. */
dns_db_closeversion(db, &version, ISC_TRUE);
@@ -5625,6 +6111,7 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
isc_buffer_t buffer;
unsigned char parambuf[DNS_NSEC3PARAM_BUFFERSIZE];
dns_ttl_t ttl = 0;
+ isc_boolean_t nseconly = ISC_FALSE, nsec3ok = ISC_FALSE;
dns_rdataset_init(&rdataset);
@@ -5675,6 +6162,10 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
if (active)
goto add;
+
+ result = dns_nsec_nseconly(db, ver, &nseconly);
+ nsec3ok = (result == ISC_R_SUCCESS && !nseconly);
+
/*
* Delete all private records which match that in nsec3chain.
*/
@@ -5697,7 +6188,9 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
continue;
CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
- if (nsec3param.hash != chain->nsec3param.hash ||
+ if ((!nsec3ok &&
+ (nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0) ||
+ nsec3param.hash != chain->nsec3param.hash ||
nsec3param.iterations != chain->nsec3param.iterations ||
nsec3param.salt_length != chain->nsec3param.salt_length ||
memcmp(nsec3param.salt, chain->nsec3param.salt,
@@ -6271,7 +6764,8 @@ zone_nsec3chain(dns_zone_t *zone) {
* of removing this NSEC3 chain.
*/
if (first && !updatensec &&
- (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0) {
+ (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0)
+ {
result = need_nsec_chain(db, version,
&nsec3chain->nsec3param,
&buildnsecchain);
@@ -6585,10 +7079,11 @@ zone_nsec3chain(dns_zone_t *zone) {
goto failure;
}
- result = increment_soa_serial(db, version, zonediff.diff, zone->mctx);
+ result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
+ zone->updatemethod);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
- "increment_soa_serial -> %s",
+ "update_soa_serial -> %s",
dns_result_totext(result));
goto failure;
}
@@ -6603,7 +7098,7 @@ zone_nsec3chain(dns_zone_t *zone) {
}
/* Write changes to journal file. */
- CHECK(zone_journal(zone, zonediff.diff, "zone_nsec3chain"));
+ CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_nsec3chain"));
LOCK_ZONE(zone);
zone_needdump(zone, DNS_DUMP_DELAY);
@@ -7154,10 +7649,11 @@ zone_sign(dns_zone_t *zone) {
goto failure;
}
- result = increment_soa_serial(db, version, zonediff.diff, zone->mctx);
+ result = update_soa_serial(db, version, zonediff.diff, zone->mctx,
+ zone->updatemethod);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
- "zone_sign:increment_soa_serial -> %s",
+ "zone_sign:update_soa_serial -> %s",
dns_result_totext(result));
goto failure;
}
@@ -7179,7 +7675,7 @@ zone_sign(dns_zone_t *zone) {
/*
* Write changes to journal file.
*/
- CHECK(zone_journal(zone, zonediff.diff, "zone_sign"));
+ CHECK(zone_journal(zone, zonediff.diff, NULL, "zone_sign"));
pauseall:
/*
@@ -7941,8 +8437,9 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
if (!ISC_LIST_EMPTY(diff.tuples)) {
/* Write changes to journal file. */
- CHECK(increment_soa_serial(kfetch->db, ver, &diff, mctx));
- CHECK(zone_journal(zone, &diff, "keyfetch_done"));
+ CHECK(update_soa_serial(kfetch->db, ver, &diff, mctx,
+ zone->updatemethod));
+ CHECK(zone_journal(zone, &diff, NULL, "keyfetch_done"));
commit = ISC_TRUE;
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
@@ -8115,8 +8612,9 @@ zone_refreshkeys(dns_zone_t *zone) {
}
}
if (!ISC_LIST_EMPTY(diff.tuples)) {
- CHECK(increment_soa_serial(db, ver, &diff, zone->mctx));
- CHECK(zone_journal(zone, &diff, "zone_refreshkeys"));
+ CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
+ zone->updatemethod));
+ CHECK(zone_journal(zone, &diff, NULL, "zone_refreshkeys"));
commit = ISC_TRUE;
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
zone_needdump(zone, 30);
@@ -8164,11 +8662,17 @@ zone_maintenance(dns_zone_t *zone) {
ENTER;
/*
+ * Are we pending load/reload?
+ */
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING))
+ return;
+
+ /*
* Configuring the view of this zone may have
* failed, for example because the config file
* had a syntax error. In that case, the view
- * db or resolver will be NULL, and we had better not try
- * to do maintenance on it.
+ * adb or resolver will be NULL, and we had better not try
+ * to do further maintenance on it.
*/
if (zone->view == NULL || zone->view->adb == NULL)
return;
@@ -8179,6 +8683,9 @@ zone_maintenance(dns_zone_t *zone) {
* Expire check.
*/
switch (zone->type) {
+ case dns_zone_redirect:
+ if (zone->masters == NULL)
+ break;
case dns_zone_slave:
case dns_zone_stub:
LOCK_ZONE(zone);
@@ -8197,6 +8704,9 @@ zone_maintenance(dns_zone_t *zone) {
* Up to date check.
*/
switch (zone->type) {
+ case dns_zone_redirect:
+ if (zone->masters == NULL)
+ break;
case dns_zone_slave:
case dns_zone_stub:
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH) &&
@@ -8222,6 +8732,7 @@ zone_maintenance(dns_zone_t *zone) {
case dns_zone_master:
case dns_zone_slave:
case dns_zone_key:
+ case dns_zone_redirect:
case dns_zone_stub:
LOCK_ZONE(zone);
if (zone->masterfile != NULL &&
@@ -8249,6 +8760,7 @@ zone_maintenance(dns_zone_t *zone) {
*/
switch (zone->type) {
case dns_zone_master:
+ case dns_zone_redirect:
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
isc_time_compare(&now, &zone->notifytime) >= 0)
zone_notify(zone, &now);
@@ -8278,6 +8790,7 @@ zone_maintenance(dns_zone_t *zone) {
switch (zone->type) {
case dns_zone_master:
+ case dns_zone_redirect:
case dns_zone_slave:
/*
* Do we need to sign/resign some RRsets?
@@ -8299,6 +8812,7 @@ zone_maintenance(dns_zone_t *zone) {
set_key_expiry_warning(zone, zone->key_expiry,
isc_time_seconds(&now));
break;
+
default:
break;
}
@@ -8307,10 +8821,31 @@ zone_maintenance(dns_zone_t *zone) {
void
dns_zone_markdirty(dns_zone_t *zone) {
+ isc_uint32_t serial;
+ isc_result_t result = ISC_R_SUCCESS;
LOCK_ZONE(zone);
- if (zone->type == dns_zone_master)
- set_resigntime(zone); /* XXXMPA make separate call back */
+ if (zone->type == dns_zone_master) {
+ if (inline_raw(zone)) {
+ unsigned int soacount;
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL) {
+ result = zone_get_from_db(zone, zone->db, NULL,
+ &soacount, &serial,
+ NULL, NULL, NULL,
+ NULL, NULL);
+ } else
+ result = DNS_R_NOTLOADED;
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (result == ISC_R_SUCCESS && soacount > 0U)
+ zone_send_secureserial(zone, ISC_FALSE, serial);
+ }
+
+ /* XXXMPA make separate call back */
+ if (result == ISC_R_SUCCESS)
+ set_resigntime(zone);
+ }
zone_needdump(zone, DNS_DUMP_DELAY);
UNLOCK_ZONE(zone);
}
@@ -8498,6 +9033,22 @@ dump_done(void *arg, isc_result_t result) {
tresult = dns_db_getsoaserial(db, version, &serial);
/*
+ * If there is a secure version of this zone
+ * use its serial if it is less than ours.
+ */
+ if (tresult == ISC_R_SUCCESS && inline_raw(zone) &&
+ zone->secure->db != NULL)
+ {
+ isc_uint32_t sserial;
+ isc_result_t mresult;
+
+ mresult = dns_db_getsoaserial(zone->secure->db,
+ NULL, &sserial);
+ if (mresult == ISC_R_SUCCESS &&
+ isc_serial_lt(sserial, serial))
+ serial = sserial;
+ }
+ /*
* Note: we are task locked here so we can test
* zone->xfr safely.
*/
@@ -8605,10 +9156,15 @@ zone_dump(dns_zone_t *zone, isc_boolean_t compact) {
result = DNS_R_CONTINUE;
UNLOCK_ZONE(zone);
} else {
+ dns_masterrawheader_t rawdata;
dns_db_currentversion(db, &version);
- result = dns_master_dump2(zone->mctx, db, version,
+ dns_master_initrawheader(&rawdata);
+ if (inline_secure(zone))
+ get_raw_serial(zone->raw, &rawdata);
+ result = dns_master_dump3(zone->mctx, db, version,
&dns_master_style_default,
- masterfile, masterformat);
+ masterfile, masterformat,
+ &rawdata);
dns_db_closeversion(db, &version, ISC_FALSE);
}
fail:
@@ -8647,11 +9203,12 @@ zone_dump(dns_zone_t *zone, isc_boolean_t compact) {
static isc_result_t
dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style,
- dns_masterformat_t format)
+ dns_masterformat_t format, const isc_uint32_t rawversion)
{
isc_result_t result;
dns_dbversion_t *version = NULL;
dns_db_t *db = NULL;
+ dns_masterrawheader_t rawdata;
REQUIRE(DNS_ZONE_VALID(zone));
@@ -8663,29 +9220,46 @@ dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style,
return (DNS_R_NOTLOADED);
dns_db_currentversion(db, &version);
- result = dns_master_dumptostream2(zone->mctx, db, version, style,
- format, fd);
+ dns_master_initrawheader(&rawdata);
+ if (rawversion == 0)
+ rawdata.flags |= DNS_MASTERRAW_COMPAT;
+ 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_db_detach(&db);
return (result);
}
isc_result_t
+dns_zone_dumptostream3(dns_zone_t *zone, FILE *fd, dns_masterformat_t format,
+ const dns_master_style_t *style,
+ const isc_uint32_t rawversion)
+{
+ return (dumptostream(zone, fd, style, format, rawversion));
+}
+
+isc_result_t
dns_zone_dumptostream2(dns_zone_t *zone, FILE *fd, dns_masterformat_t format,
const dns_master_style_t *style) {
- return dumptostream(zone, fd, style, format);
+ return (dumptostream(zone, fd, style, format, DNS_RAWFORMAT_VERSION));
}
isc_result_t
dns_zone_dumptostream(dns_zone_t *zone, FILE *fd) {
- return dumptostream(zone, fd, &dns_master_style_default,
- dns_masterformat_text);
+ return (dumptostream(zone, fd, &dns_master_style_default,
+ dns_masterformat_text, 0));
}
isc_result_t
dns_zone_fulldumptostream(dns_zone_t *zone, FILE *fd) {
- return dumptostream(zone, fd, &dns_master_style_full,
- dns_masterformat_text);
+ return (dumptostream(zone, fd, &dns_master_style_full,
+ dns_masterformat_text, 0));
}
void
@@ -8880,6 +9454,8 @@ notify_destroy(dns_notify_t *notify, isc_boolean_t locked) {
dns_request_destroy(&notify->request);
if (dns_name_dynamic(&notify->ns))
dns_name_free(&notify->ns, notify->mctx);
+ if (notify->key != NULL)
+ dns_tsigkey_detach(&notify->key);
mctx = notify->mctx;
isc_mem_put(notify->mctx, notify, sizeof(*notify));
isc_mem_detach(&mctx);
@@ -8901,6 +9477,7 @@ notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) {
notify->zone = NULL;
notify->find = NULL;
notify->request = NULL;
+ notify->key = NULL;
isc_sockaddr_any(&notify->dst);
dns_name_init(&notify->ns, NULL);
ISC_LINK_INIT(notify, link);
@@ -9045,15 +9622,23 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
if (result != ISC_R_SUCCESS)
goto cleanup;
- isc_netaddr_fromsockaddr(&dstip, &notify->dst);
- isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
- result = dns_view_getpeertsig(notify->zone->view, &dstip, &key);
- if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
- notify_log(notify->zone, ISC_LOG_ERROR, "NOTIFY to %s not "
- "sent. Peer TSIG key lookup failure.", addrbuf);
- goto cleanup_message;
+ if (notify->key != NULL) {
+ /* Transfer ownership of key */
+ key = notify->key;
+ notify->key = NULL;
+ } else {
+ isc_netaddr_fromsockaddr(&dstip, &notify->dst);
+ isc_sockaddr_format(&notify->dst, addrbuf, sizeof(addrbuf));
+ result = dns_view_getpeertsig(notify->zone->view, &dstip, &key);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ notify_log(notify->zone, ISC_LOG_ERROR,
+ "NOTIFY to %s not sent. "
+ "Peer TSIG key lookup failure.", addrbuf);
+ goto cleanup_message;
+ }
}
+ /* XXX: should we log the tsig key too? */
notify_log(notify->zone, ISC_LOG_DEBUG(3), "sending notify to %s",
addrbuf);
if (notify->zone->view->peers != NULL) {
@@ -9255,14 +9840,30 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
*/
LOCK_ZONE(zone);
for (i = 0; i < zone->notifycnt; i++) {
+ dns_tsigkey_t *key = NULL;
+
dst = zone->notify[i];
if (notify_isqueued(zone, NULL, &dst))
continue;
+
result = notify_create(zone->mctx, flags, &notify);
if (result != ISC_R_SUCCESS)
continue;
+
zone_iattach(zone, &notify->zone);
notify->dst = dst;
+
+ if ((zone->notifykeynames != NULL) &&
+ (zone->notifykeynames[i] != NULL)) {
+ dns_view_t *view = dns_zone_getview(zone);
+ dns_name_t *keyname = zone->notifykeynames[i];
+ result = dns_view_gettsig(view, keyname, &key);
+ if (result == ISC_R_SUCCESS) {
+ notify->key = key;
+ key = NULL;
+ }
+ }
+
ISC_LIST_APPEND(zone->notifies, notify, link);
result = notify_send_queue(notify);
if (result != ISC_R_SUCCESS)
@@ -9753,7 +10354,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
"master %s exceeded (source %s)",
master, source);
/* Try with slave with TCP. */
- if (zone->type == dns_zone_slave &&
+ if ((zone->type == dns_zone_slave ||
+ zone->type == dns_zone_redirect) &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) {
if (!dns_zonemgr_unreachable(zone->zmgr,
&zone->masteraddr,
@@ -9819,7 +10421,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
* Perhaps AXFR/IXFR is allowed even if SOA queries aren't.
*/
if (msg->rcode == dns_rcode_refused &&
- zone->type == dns_zone_slave)
+ (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_redirect))
goto tcp_transfer;
goto next_master;
}
@@ -9828,7 +10431,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
* If truncated punt to zone transfer which will query again.
*/
if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
- if (zone->type == dns_zone_slave) {
+ if (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_redirect) {
dns_zone_log(zone, ISC_LOG_INFO,
"refresh: truncated UDP answer, "
"initiating TCP zone xfer "
@@ -9955,7 +10559,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
dns_zone_log(zone, ISC_LOG_INFO,
"refresh: skipping %s as master %s "
"(source %s) is unreachable (cached)",
- zone->type == dns_zone_slave ?
+ (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_redirect) ?
"zone transfer" : "NS query",
master, source);
goto next_master;
@@ -9963,7 +10568,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
tcp_transfer:
isc_event_free(&event);
dns_request_destroy(&zone->request);
- if (zone->type == dns_zone_slave) {
+ if (zone->type == dns_zone_slave ||
+ zone->type == dns_zone_redirect) {
do_queue_xfrin = ISC_TRUE;
} else {
INSIST(zone->type == dns_zone_stub);
@@ -10643,6 +11249,7 @@ static void
zone_shutdown(isc_task_t *task, isc_event_t *event) {
dns_zone_t *zone = (dns_zone_t *) event->ev_arg;
isc_boolean_t free_needed, linked = ISC_FALSE;
+ dns_zone_t *raw = NULL, *secure = NULL;
UNUSED(task);
REQUIRE(DNS_ZONE_VALID(zone));
@@ -10725,7 +11332,19 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
*/
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN);
free_needed = exit_check(zone);
+ if (inline_secure(zone)) {
+ raw = zone->raw;
+ zone->raw = NULL;
+ }
+ if (inline_raw(zone)) {
+ secure = zone->secure;
+ zone->secure = NULL;
+ }
UNLOCK_ZONE(zone);
+ if (raw != NULL)
+ dns_zone_detach(&raw);
+ if (secure != NULL)
+ dns_zone_idetach(&secure);
if (free_needed)
zone_free(zone);
}
@@ -10759,6 +11378,11 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
isc_time_settoepoch(&next);
switch (zone->type) {
+ case dns_zone_redirect:
+ if (zone->masters != NULL)
+ goto treat_as_slave;
+ /* FALLTHROUGH */
+
case dns_zone_master:
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY))
next = zone->notifytime;
@@ -10769,6 +11393,8 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
isc_time_compare(&zone->dumptime, &next) < 0)
next = zone->dumptime;
}
+ if (zone->type == dns_zone_redirect)
+ break;
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING) &&
!isc_time_isepoch(&zone->refreshkeytime)) {
if (isc_time_isepoch(&next) ||
@@ -10798,9 +11424,10 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
break;
case dns_zone_slave:
+ treat_as_slave:
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY))
next = zone->notifytime;
- /*FALLTHROUGH*/
+ /* FALLTHROUGH */
case dns_zone_stub:
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH) &&
@@ -11078,9 +11705,17 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
isc_sockaddr_format(from, fromtext, sizeof(fromtext));
/*
- * We only handle NOTIFY (SOA) at the present.
+ * Notify messages are processed by the raw zone.
*/
LOCK_ZONE(zone);
+ if (inline_secure(zone)) {
+ result = dns_zone_notifyreceive(zone->raw, from, msg);
+ UNLOCK_ZONE(zone);
+ return (result);
+ }
+ /*
+ * We only handle NOTIFY (SOA) at the present.
+ */
if (isc_sockaddr_pf(from) == PF_INET)
inc_stats(zone, dns_zonestatscounter_notifyinv4);
else
@@ -11468,15 +12103,17 @@ zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) {
* Leave space for terminating '\0'.
*/
isc_buffer_init(&buffer, buf, length - 1);
- if (dns_name_dynamic(&zone->origin))
- result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer);
- if (result != ISC_R_SUCCESS &&
- isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>") - 1))
- isc_buffer_putstr(&buffer, "<UNKNOWN>");
+ if (zone->type != dns_zone_redirect && zone->type != dns_zone_key) {
+ if (dns_name_dynamic(&zone->origin))
+ result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer);
+ if (result != ISC_R_SUCCESS &&
+ isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>") - 1))
+ isc_buffer_putstr(&buffer, "<UNKNOWN>");
- if (isc_buffer_availablelength(&buffer) > 0)
- isc_buffer_putstr(&buffer, "/");
- (void)dns_rdataclass_totext(zone->rdclass, &buffer);
+ if (isc_buffer_availablelength(&buffer) > 0)
+ isc_buffer_putstr(&buffer, "/");
+ (void)dns_rdataclass_totext(zone->rdclass, &buffer);
+ }
if (zone->view != NULL && strcmp(zone->view->name, "_bind") != 0 &&
strcmp(zone->view->name, "_default") != 0 &&
@@ -11484,6 +12121,10 @@ zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) {
isc_buffer_putstr(&buffer, "/");
isc_buffer_putstr(&buffer, zone->view->name);
}
+ if (inline_secure(zone) && 9U < isc_buffer_availablelength(&buffer))
+ isc_buffer_putstr(&buffer, " (signed)");
+ if (inline_raw(zone) && 11U < isc_buffer_availablelength(&buffer))
+ isc_buffer_putstr(&buffer, " (unsigned)");
buf[isc_buffer_usedlength(&buffer)] = '\0';
}
@@ -11585,8 +12226,9 @@ dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category,
vsnprintf(message, sizeof(message), fmt, ap);
va_end(ap);
isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE,
- level, "%s %s: %s", (zone->type == dns_zone_key) ?
- "managed-keys-zone" : "zone", zone->strnamerd, message);
+ level, "%s%s: %s", (zone->type == dns_zone_key) ?
+ "managed-keys-zone" : (zone->type == dns_zone_redirect) ?
+ "redirect-zone" : "zone ", zone->strnamerd, message);
}
void
@@ -11601,8 +12243,9 @@ dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) {
vsnprintf(message, sizeof(message), fmt, ap);
va_end(ap);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
- level, "%s %s: %s", (zone->type == dns_zone_key) ?
- "managed-keys-zone" : "zone", zone->strnamerd, message);
+ level, "%s%s: %s", (zone->type == dns_zone_key) ?
+ "managed-keys-zone" : (zone->type == dns_zone_redirect) ?
+ "redirect-zone" : "zone ", zone->strnamerd, message);
}
static void
@@ -11612,6 +12255,7 @@ zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel,
va_list ap;
char message[4096];
int level = ISC_LOG_DEBUG(debuglevel);
+ const char *zstr;
if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
return;
@@ -11619,9 +12263,21 @@ zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel,
va_start(ap, fmt);
vsnprintf(message, sizeof(message), fmt, ap);
va_end(ap);
+
+ switch (zone->type) {
+ case dns_zone_key:
+ zstr = "managed-keys-zone";
+ break;
+ case dns_zone_redirect:
+ zstr = "redirect-zone";
+ break;
+ default:
+ zstr = "zone";
+ }
+
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
- level, "%s: %s %s: %s", me, zone->type != dns_zone_key ?
- "zone" : "managed-keys-zone", zone->strnamerd, message);
+ level, "%s: %s %s: %s", me, zstr, zone->strnamerd,
+ message);
}
static int
@@ -11799,6 +12455,572 @@ notify_done(isc_task_t *task, isc_event_t *event) {
dns_message_destroy(&message);
}
+struct secure_event {
+ isc_event_t e;
+ dns_db_t *db;
+ isc_uint32_t serial;
+};
+
+static void
+update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) {
+ UNUSED(arg);
+ dns_zone_log(zone, level, "%s", message);
+}
+
+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;
+ int n_soa = 0;
+
+ REQUIRE(soatuplep != NULL);
+
+ if (start == end)
+ return (DNS_R_UNCHANGED);
+
+ 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. */
+ if (n_soa == 0) {
+ dns_zone_log(zone->raw, ISC_LOG_ERROR,
+ "corrupt journal file: '%s'\n",
+ zone->raw->journal);
+ return (ISC_R_FAILURE);
+ }
+
+ if (zone->privatetype != 0 &&
+ rdata->type == zone->privatetype)
+ continue;
+
+ if (rdata->type == dns_rdatatype_nsec ||
+ rdata->type == dns_rdatatype_rrsig ||
+ rdata->type == dns_rdatatype_nsec3 ||
+ rdata->type == dns_rdatatype_dnskey ||
+ rdata->type == dns_rdatatype_nsec3param)
+ continue;
+
+ op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
+
+ CHECK(dns_difftuple_create(diff->mctx, op, name, ttl, rdata,
+ &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_difftuple_t **soatuple,
+ dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_db_t *rawdb = NULL;
+ dns_dbversion_t *rawver = NULL;
+ dns_difftuple_t *tuple = NULL, *next;
+ dns_difftuple_t *oldtuple = NULL, *newtuple = NULL;
+ dns_rdata_soa_t oldsoa, newsoa;
+
+ REQUIRE(DNS_ZONE_VALID(seczone));
+ REQUIRE(inline_secure(seczone));
+ REQUIRE(soatuple != NULL && *soatuple == NULL);
+
+ 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_nsec3param)
+ {
+ ISC_LIST_UNLINK(diff->tuples, tuple, link);
+ dns_difftuple_free(&tuple);
+ continue;
+ }
+ if (tuple->rdata.type == dns_rdatatype_soa) {
+ if (tuple->op == DNS_DIFFOP_DEL) {
+ INSIST(oldtuple == NULL);
+ oldtuple = tuple;
+ }
+ if (tuple->op == DNS_DIFFOP_ADD) {
+ INSIST(newtuple == NULL);
+ newtuple = tuple;
+ }
+ }
+ }
+
+ if (oldtuple != NULL && newtuple != NULL) {
+
+ result = dns_rdata_tostruct(&oldtuple->rdata, &oldsoa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ result = dns_rdata_tostruct(&newtuple->rdata, &newsoa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ /*
+ * If the SOA records are the same except for the serial
+ * remove them from the diff.
+ */
+ if (oldsoa.refresh == newsoa.refresh &&
+ oldsoa.retry == newsoa.retry &&
+ oldsoa.minimum == newsoa.minimum &&
+ oldsoa.expire == newsoa.expire &&
+ dns_name_equal(&oldsoa.origin, &newsoa.origin) &&
+ dns_name_equal(&oldsoa.contact, &newsoa.contact)) {
+ ISC_LIST_UNLINK(diff->tuples, oldtuple, link);
+ dns_difftuple_free(&oldtuple);
+ ISC_LIST_UNLINK(diff->tuples, newtuple, link);
+ dns_difftuple_free(&newtuple);
+ }
+ }
+
+ if (ISC_LIST_EMPTY(diff->tuples))
+ return (DNS_R_UNCHANGED);
+
+ /*
+ * If there are still SOA records in the diff they can now be removed
+ * saving the new SOA record.
+ */
+ if (oldtuple != NULL) {
+ ISC_LIST_UNLINK(diff->tuples, oldtuple, link);
+ dns_difftuple_free(&oldtuple);
+ }
+
+ if (newtuple != NULL) {
+ ISC_LIST_UNLINK(diff->tuples, newtuple, link);
+ *soatuple = newtuple;
+ }
+
+ 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_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);
+
+ LOCK_ZONE(zone);
+
+ dns_diff_init(zone->mctx, &diff);
+
+ UNUSED(task);
+
+ /*
+ * zone->db may be NULL if the load from disk failed.
+ */
+ if (zone->db == NULL || !inline_secure(zone)) {
+ result = ISC_R_FAILURE;
+ goto failure;
+ }
+
+ /*
+ * 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->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, &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"));
+
+ dns_journal_set_sourceserial(rjournal, end);
+ dns_journal_commit(rjournal);
+
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+
+ zone->sourceserial = end;
+ zone->sourceserialset = ISC_TRUE;
+ zone_needdump(zone, DNS_DUMP_DELAY);
+
+ TIME_NOW(&timenow);
+ zone_settimer(zone, &timenow);
+
+ dns_db_closeversion(db, &oldver, ISC_FALSE);
+ dns_db_closeversion(db, &newver, ISC_TRUE);
+
+ failure:
+ UNLOCK_ZONE(zone);
+ 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)
+ 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 (rjournal != NULL)
+ dns_journal_destroy(&rjournal);
+ dns_diff_clear(&diff);
+ dns_zone_idetach(&zone);
+}
+
+static isc_result_t
+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_event));
+ if (e == NULL)
+ return (ISC_R_NOMEMORY);
+ ((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);
+}
+
+static isc_result_t
+checkandaddsoa(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdataset_t *rdataset, isc_uint32_t oldserial)
+{
+ dns_rdata_soa_t soa;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdatalist_t temprdatalist;
+ dns_rdataset_t temprdataset;
+ isc_buffer_t b;
+ isc_result_t result;
+ unsigned char buf[DNS_SOA_BUFFERSIZE];
+
+ result = dns_rdataset_first(rdataset);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &soa, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ if (isc_serial_gt(soa.serial, oldserial))
+ return (dns_db_addrdataset(db, node, version, 0, rdataset, 0,
+ NULL));
+ /*
+ * Always bump the serial.
+ */
+ oldserial++;
+ if (oldserial == 0)
+ oldserial++;
+ soa.serial = oldserial;
+
+ /*
+ * Construct a replacement rdataset.
+ */
+ dns_rdata_reset(&rdata);
+ isc_buffer_init(&b, buf, sizeof(buf));
+ result = dns_rdata_fromstruct(&rdata, rdataset->rdclass,
+ dns_rdatatype_soa, &soa, &b);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ temprdatalist.rdclass = rdata.rdclass;
+ temprdatalist.type = rdata.type;
+ temprdatalist.covers = 0;
+ temprdatalist.ttl = rdataset->ttl;
+ ISC_LIST_INIT(temprdatalist.rdata);
+ ISC_LIST_APPEND(temprdatalist.rdata, &rdata, link);
+
+ dns_rdataset_init(&temprdataset);
+ result = dns_rdatalist_tordataset(&temprdatalist, &temprdataset);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ return (dns_db_addrdataset(db, node, version, 0, &temprdataset,
+ 0, NULL));
+}
+
+static void
+receive_secure_db(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_zone_t *zone;
+ dns_db_t *rawdb, *db = NULL;
+ dns_dbnode_t *rawnode = NULL, *node = NULL;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ dns_dbiterator_t *dbiterator = NULL;
+ dns_rdatasetiter_t *rdsit = NULL;
+ dns_rdataset_t rdataset;
+ dns_dbversion_t *version = NULL;
+ isc_time_t loadtime;
+ unsigned int oldserial = 0;
+ isc_boolean_t have_oldserial = ISC_FALSE;
+
+ UNUSED(task);
+
+ zone = event->ev_arg;
+ 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);
+
+ TIME_NOW(&loadtime);
+ if (zone->db != NULL) {
+ result = dns_db_getsoaserial(zone->db, NULL, &oldserial);
+ if (result == ISC_R_SUCCESS)
+ have_oldserial = ISC_TRUE;
+ }
+
+ result = dns_db_create(zone->mctx, zone->db_argv[0],
+ &zone->origin, dns_dbtype_zone, zone->rdclass,
+ zone->db_argc - 1, zone->db_argv + 1, &db);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_newversion(db, &version);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_createiterator(rawdb, 0, &dbiterator);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_dbiterator_first(dbiterator);
+ result == ISC_R_SUCCESS;
+ result = dns_dbiterator_next(dbiterator)) {
+ result = dns_dbiterator_current(dbiterator, &rawnode, name);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ result = dns_db_findnode(db, name, ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_allrdatasets(rawdb, rawnode, NULL, 0, &rdsit);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_rdatasetiter_first(rdsit);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsit)) {
+ dns_rdatasetiter_current(rdsit, &rdataset);
+ if (rdataset.type == dns_rdatatype_nsec ||
+ rdataset.type == dns_rdatatype_rrsig ||
+ rdataset.type == dns_rdatatype_nsec3 ||
+ rdataset.type == dns_rdatatype_dnskey ||
+ rdataset.type == dns_rdatatype_nsec3param) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+ if (rdataset.type == dns_rdatatype_soa &&
+ have_oldserial) {
+ result = checkandaddsoa(db, node, version,
+ &rdataset, oldserial);
+ } else
+ result = dns_db_addrdataset(db, node, version,
+ 0, &rdataset, 0,
+ NULL);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ dns_rdataset_disassociate(&rdataset);
+ }
+ dns_rdatasetiter_destroy(&rdsit);
+ dns_db_detachnode(rawdb, &rawnode);
+ dns_db_detachnode(db, &node);
+ }
+
+ dns_db_closeversion(db, &version, ISC_TRUE);
+ /*
+ * Lock hierarchy: zmgr, zone, raw.
+ */
+ LOCK_ZONE(zone);
+ if (inline_secure(zone))
+ LOCK_ZONE(zone->raw);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+ result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS);
+ zone_needdump(zone, 0); /* XXXMPA */
+ if (inline_secure(zone))
+ UNLOCK_ZONE(zone->raw);
+ UNLOCK_ZONE(zone);
+
+ failure:
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_db: %s",
+ dns_result_totext(result));
+
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (db != NULL) {
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ }
+ if (rawnode != NULL)
+ dns_db_detachnode(rawdb, &rawnode);
+ dns_db_detach(&rawdb);
+ if (dbiterator != NULL)
+ dns_dbiterator_destroy(&dbiterator);
+ dns_zone_idetach(&zone);
+}
+
+static isc_result_t
+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_event));
+ if (e == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_db_attach(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);
+ return (ISC_R_SUCCESS);
+}
+
isc_result_t
dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
isc_result_t result;
@@ -11860,7 +13082,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
*/
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;
unsigned int soacount;
@@ -11882,8 +13105,10 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
RUNTIME_CHECK(soacount > 0U);
- if (zone->type == dns_zone_slave &&
- !isc_serial_gt(serial, oldserial)) {
+ if ((zone->type == dns_zone_slave ||
+ (zone->type == dns_zone_redirect &&
+ zone->masters != NULL))
+ && !isc_serial_gt(serial, oldserial)) {
isc_uint32_t serialmin, serialmax;
serialmin = (oldserial + 1) & 0xffffffffU;
serialmax = (oldserial + 0x7fffffffU) & 0xffffffffU;
@@ -11919,6 +13144,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
break;
}
}
+ if (zone->type == dns_zone_master && inline_raw(zone))
+ zone_send_secureserial(zone, ISC_FALSE, serial);
} else {
if (dump && zone->masterfile != NULL) {
/*
@@ -11969,13 +13196,14 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
zone->journal, strbuf);
}
}
+
+ if (inline_raw(zone))
+ zone_send_securedb(zone, ISC_FALSE, db);
}
dns_db_closeversion(db, &ver, ISC_FALSE);
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
- DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
- "replacing zone database");
+ dns_zone_log(zone, ISC_LOG_DEBUG(3), "replacing zone database");
if (zone->db != NULL)
zone_detachdb(zone);
@@ -12120,6 +13348,8 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
dns_zone_log(zone, ISC_LOG_INFO,
"transferred serial %u%s",
serial, buf);
+ if (inline_raw(zone))
+ zone_send_secureserial(zone, ISC_FALSE, serial);
}
/*
@@ -12274,18 +13504,26 @@ zone_loaddone(void *arg, isc_result_t result) {
(result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
result = tresult;
- LOCK_ZONE(load->zone);
- (void)zone_postload(load->zone, load->db, load->loadtime, result);
- zonemgr_putio(&load->zone->readio);
- DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_LOADING);
+ /*
+ * Lock hierarchy: zmgr, zone, raw.
+ */
+ LOCK_ZONE(zone);
+ if (inline_secure(zone))
+ LOCK_ZONE(zone->raw);
+ (void)zone_postload(zone, load->db, load->loadtime, result);
+ zonemgr_putio(&zone->readio);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADING);
+ zone_idetach(&load->callbacks.zone);
/*
* Leave the zone frozen if the reload fails.
*/
if ((result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) &&
- DNS_ZONE_FLAG(load->zone, DNS_ZONEFLG_THAW))
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_THAW))
zone->update_disabled = ISC_FALSE;
- DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_THAW);
- UNLOCK_ZONE(load->zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_THAW);
+ if (inline_secure(zone))
+ UNLOCK_ZONE(zone->raw);
+ UNLOCK_ZONE(zone);
load->magic = 0;
dns_db_detach(&load->db);
@@ -12383,7 +13621,7 @@ queue_xfrin(dns_zone_t *zone) {
*/
static void
got_transfer_quota(isc_task_t *task, isc_event_t *event) {
- isc_result_t result;
+ isc_result_t result = ISC_R_SUCCESS;
dns_peer_t *peer = NULL;
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
@@ -12432,14 +13670,6 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
"no database exists yet, requesting AXFR of "
"initial version from %s", master);
xfrtype = dns_rdatatype_axfr;
- } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) {
- dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences "
- "set, requesting %sAXFR from %s", soa_before,
- master);
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR))
- xfrtype = dns_rdatatype_soa;
- else
- xfrtype = dns_rdatatype_axfr;
} else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"forced reload, requesting AXFR of "
@@ -12455,13 +13685,10 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
UNLOCK_ZONE(zone);
} else {
isc_boolean_t use_ixfr = ISC_TRUE;
- if (peer != NULL &&
- dns_peer_getrequestixfr(peer, &use_ixfr) ==
- ISC_R_SUCCESS) {
- ; /* Using peer setting */
- } else {
- use_ixfr = zone->view->requestixfr;
- }
+ if (peer != NULL)
+ result = dns_peer_getrequestixfr(peer, &use_ixfr);
+ if (peer == NULL || result != ISC_R_SUCCESS)
+ use_ixfr = zone->requestixfr;
if (use_ixfr == ISC_FALSE) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"IXFR disabled, requesting %sAXFR from %s",
@@ -12806,6 +14033,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
zmgr->timermgr = timermgr;
zmgr->socketmgr = socketmgr;
zmgr->zonetasks = NULL;
+ zmgr->loadtasks = NULL;
+ zmgr->mctxpool = NULL;
zmgr->task = NULL;
zmgr->rl = NULL;
ISC_LIST_INIT(zmgr->zones);
@@ -12874,6 +14103,33 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
}
isc_result_t
+dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) {
+ isc_result_t result;
+ isc_mem_t *mctx = NULL;
+ dns_zone_t *zone = NULL;
+ void *item;
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+ REQUIRE(zonep != NULL && *zonep == NULL);
+
+ if (zmgr->mctxpool == NULL)
+ return (ISC_R_FAILURE);
+
+ item = isc_pool_get(zmgr->mctxpool);
+ if (item == NULL)
+ return (ISC_R_FAILURE);
+
+ isc_mem_attach((isc_mem_t *) item, &mctx);
+ result = dns_zone_create(&zone, mctx);
+ isc_mem_detach(&mctx);
+
+ if (result == ISC_R_SUCCESS)
+ *zonep = zone;
+
+ return (result);
+}
+
+isc_result_t
dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
isc_result_t result;
@@ -12890,6 +14146,7 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
REQUIRE(zone->zmgr == NULL);
isc_taskpool_gettask(zmgr->zonetasks, &zone->task);
+ isc_taskpool_gettask(zmgr->loadtasks, &zone->loadtask);
/*
* Set the task name. The tag will arbitrarily point to one
@@ -12897,6 +14154,7 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
* to be managed last).
*/
isc_task_setname(zone->task, "zone", zone);
+ isc_task_setname(zone->loadtask, "loadzone", zone);
result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
NULL, NULL,
@@ -12904,7 +14162,7 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
&zone->timer);
if (result != ISC_R_SUCCESS)
- goto cleanup_task;
+ goto cleanup_tasks;
/*
* The timer "holds" a iref.
@@ -12918,7 +14176,8 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
goto unlock;
- cleanup_task:
+ cleanup_tasks:
+ isc_task_detach(&zone->loadtask);
isc_task_detach(&zone->task);
unlock:
@@ -13034,6 +14293,10 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
isc_task_destroy(&zmgr->task);
if (zmgr->zonetasks != NULL)
isc_taskpool_destroy(&zmgr->zonetasks);
+ if (zmgr->loadtasks != NULL)
+ isc_taskpool_destroy(&zmgr->loadtasks);
+ if (zmgr->mctxpool != NULL)
+ isc_pool_destroy(&zmgr->mctxpool);
RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
for (zone = ISC_LIST_HEAD(zmgr->zones);
@@ -13047,23 +14310,56 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
}
+static isc_result_t
+mctxinit(void **target, void *arg) {
+ isc_result_t result;
+ isc_mem_t *mctx = NULL;
+
+ UNUSED(arg);
+
+ REQUIRE(target != NULL && *target == NULL);
+
+ result = isc_mem_create(0, 0, &mctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_mem_setname(mctx, "zonemgr-pool", NULL);
+
+ *target = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+mctxfree(void **target) {
+ isc_mem_t *mctx = *(isc_mem_t **) target;
+ isc_mem_detach(&mctx);
+ *target = NULL;
+}
+
+#define ZONES_PER_TASK 100
+#define ZONES_PER_MCTX 1000
+
isc_result_t
dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
isc_result_t result;
- int ntasks = num_zones / 100;
+ int ntasks = num_zones / ZONES_PER_TASK;
+ int nmctx = num_zones / ZONES_PER_MCTX;
isc_taskpool_t *pool = NULL;
+ isc_pool_t *mctxpool = NULL;
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
/*
* For anything fewer than 1000 zones we use 10 tasks in
- * the task pool. More than that, and we'll scale at one
- * task per 100 zones.
+ * the task pools. More than that, and we'll scale at one
+ * task per 100 zones. Similarly, for anything smaller than
+ * 2000 zones we use 2 memory contexts, then scale at 1:1000.
*/
if (ntasks < 10)
ntasks = 10;
+ if (nmctx < 2)
+ nmctx = 2;
- /* Create or resize the zone task pool. */
+ /* Create or resize the zone task pools. */
if (zmgr->zonetasks == NULL)
result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx,
ntasks, 2, &pool);
@@ -13073,6 +14369,43 @@ dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
if (result == ISC_R_SUCCESS)
zmgr->zonetasks = pool;
+ pool = NULL;
+ if (zmgr->loadtasks == NULL)
+ result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx,
+ ntasks, 2, &pool);
+ else
+ result = isc_taskpool_expand(&zmgr->loadtasks, ntasks, &pool);
+
+ if (result == ISC_R_SUCCESS)
+ zmgr->loadtasks = pool;
+
+#ifdef BIND9
+ /*
+ * We always set all tasks in the zone-load task pool to
+ * privileged. This prevents other tasks in the system from
+ * running while the server task manager is in privileged
+ * mode.
+ *
+ * NOTE: If we start using task privileges for any other
+ * part of the system than zone tasks, then this will need to be
+ * revisted. In that case we'd want to turn on privileges for
+ * zone tasks only when we were loading, and turn them off the
+ * rest of the time. For now, however, it's okay to just
+ * set it and forget it.
+ */
+ isc_taskpool_setprivilege(zmgr->loadtasks, ISC_TRUE);
+#endif
+
+ /* Create or resize the zone memory context pool. */
+ if (zmgr->mctxpool == NULL)
+ result = isc_pool_create(zmgr->mctx, nmctx, mctxfree,
+ mctxinit, NULL, &mctxpool);
+ else
+ result = isc_pool_expand(&zmgr->mctxpool, nmctx, &mctxpool);
+
+ if (result == ISC_R_SUCCESS)
+ zmgr->mctxpool = mctxpool;
+
return (result);
}
@@ -13309,12 +14642,14 @@ zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
io = isc_mem_get(zmgr->mctx, sizeof(*io));
if (io == NULL)
return (ISC_R_NOMEMORY);
+
io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY,
action, arg, sizeof(*io->event));
if (io->event == NULL) {
isc_mem_put(zmgr->mctx, io, sizeof(*io));
return (ISC_R_NOMEMORY);
}
+
io->zmgr = zmgr;
io->high = high;
io->task = NULL;
@@ -13334,9 +14669,8 @@ zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
UNLOCK(&zmgr->iolock);
*iop = io;
- if (!queue) {
+ if (!queue)
isc_task_send(io->task, &io->event);
- }
return (ISC_R_SUCCESS);
}
@@ -13613,7 +14947,8 @@ void
dns_zone_forcereload(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
- if (zone->type == dns_zone_master)
+ if (zone->type == dns_zone_master ||
+ (zone->type == dns_zone_redirect && zone->masters == NULL))
return;
LOCK_ZONE(zone);
@@ -13661,6 +14996,7 @@ dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats) {
void
dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) {
+
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
@@ -13673,9 +15009,24 @@ dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) {
}
}
UNLOCK_ZONE(zone);
+}
- return;
+#ifdef NEWSTATS
+void
+dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (zone->requeststats_on && stats != NULL) {
+ if (zone->rcvquerystats == NULL) {
+ dns_stats_attach(stats, &zone->rcvquerystats);
+ zone->requeststats_on = ISC_TRUE;
+ }
+ }
+ UNLOCK_ZONE(zone);
}
+#endif
isc_stats_t *
dns_zone_getrequeststats(dns_zone_t *zone) {
@@ -13693,6 +15044,20 @@ dns_zone_getrequeststats(dns_zone_t *zone) {
return (NULL);
}
+#ifdef NEWSTATS
+/*
+ * Return the received query stats bucket
+ * see note from dns_zone_getrequeststats()
+ */
+dns_stats_t *
+dns_zone_getrcvquerystats(dns_zone_t *zone) {
+ if (zone->requeststats_on)
+ return (zone->rcvquerystats);
+ else
+ return (NULL);
+}
+#endif
+
void
dns_zone_dialup(dns_zone_t *zone) {
@@ -13705,7 +15070,7 @@ dns_zone_dialup(dns_zone_t *zone) {
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY))
dns_zone_notify(zone);
- if (zone->type != dns_zone_master &&
+ if (zone->type != dns_zone_master && zone->masters != NULL &&
DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH))
dns_zone_refresh(zone);
}
@@ -14321,8 +15686,12 @@ dnskey_sane(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
}
/* Check existing DB for NSEC-only DNSKEY */
- if (!nseconly)
- CHECK(dns_nsec_nseconly(db, ver, &nseconly));
+ if (!nseconly) {
+ result = dns_nsec_nseconly(db, ver, &nseconly);
+ if (result == ISC_R_NOTFOUND)
+ result = ISC_R_SUCCESS;
+ CHECK(result);
+ }
/* Check existing DB for NSEC3 */
if (!nsec3)
@@ -14360,7 +15729,7 @@ clean_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
if (result != ISC_R_NOTFOUND)
goto failure;
- result = dns_nsec3param_deletechains(db, ver, zone, diff);
+ result = dns_nsec3param_deletechains(db, ver, zone, ISC_TRUE, diff);
failure:
if (node != NULL)
@@ -14476,14 +15845,11 @@ zone_rekey(dns_zone_t *zone) {
dns_rdatatype_none, 0, &keyset, &keysigs);
if (result == ISC_R_SUCCESS) {
ttl = keyset.ttl;
- result = dns_dnssec_keylistfromrdataset(&zone->origin, dir,
- mctx, &keyset,
- &keysigs, &soasigs,
- ISC_FALSE, ISC_FALSE,
- &dnskeys);
- /* Can't get keys for some reason; try again later. */
- if (result != ISC_R_SUCCESS)
- goto trylater;
+ CHECK(dns_dnssec_keylistfromrdataset(&zone->origin, dir,
+ mctx, &keyset,
+ &keysigs, &soasigs,
+ ISC_FALSE, ISC_FALSE,
+ &dnskeys));
} else if (result != ISC_R_NOTFOUND)
goto failure;
@@ -14509,7 +15875,7 @@ zone_rekey(dns_zone_t *zone) {
dns_zone_log(zone, ISC_LOG_ERROR, "zone_rekey:"
"couldn't update zone keys: %s",
isc_result_totext(result));
- goto trylater;
+ goto failure;
}
/*
@@ -14552,15 +15918,17 @@ zone_rekey(dns_zone_t *zone) {
CHECK(add_signing_records(db, zone->privatetype,
ver, &diff,
ISC_TF(newalg || fullsign)));
- CHECK(increment_soa_serial(db, ver, &diff, mctx));
+ CHECK(update_soa_serial(db, ver, &diff, mctx,
+ zone->updatemethod));
CHECK(add_chains(zone, db, ver, &diff));
CHECK(sign_apex(zone, db, ver, &diff, &zonediff));
- CHECK(zone_journal(zone, zonediff.diff, "zone_rekey"));
+ CHECK(zone_journal(zone, zonediff.diff, NULL,
+ "zone_rekey"));
commit = ISC_TRUE;
}
}
- dns_db_closeversion(db, &ver, commit);
+ dns_db_closeversion(db, &ver, ISC_TRUE);
if (commit) {
dns_difftuple_t *tuple;
@@ -14673,6 +16041,13 @@ zone_rekey(dns_zone_t *zone) {
}
/*
+ * Activate any NSEC3 chain updates that may have
+ * been scheduled before this rekey.
+ */
+ if (fullsign || newalg)
+ resume_addnsec3chain(zone);
+
+ /*
* Schedule the next resigning event
*/
set_resigntime(zone);
@@ -14683,15 +16058,16 @@ zone_rekey(dns_zone_t *zone) {
/*
* If we're doing key maintenance, set the key refresh timer to
- * the next scheduled key event or to one hour in the future,
- * whichever is sooner.
+ * the next scheduled key event or to 'dnssec-loadkeys-interval'
+ * seconds in the future, whichever is sooner.
*/
if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) {
isc_time_t timethen;
isc_stdtime_t then;
LOCK_ZONE(zone);
- DNS_ZONE_TIME_ADD(&timenow, HOUR, &timethen);
+ DNS_ZONE_TIME_ADD(&timenow, zone->refreshkeyinterval,
+ &timethen);
zone->refreshkeytime = timethen;
UNLOCK_ZONE(zone);
@@ -14718,7 +16094,7 @@ zone_rekey(dns_zone_t *zone) {
dns_zone_log(zone, ISC_LOG_INFO, "next key event: %s", timebuf);
}
- failure:
+ done:
dns_diff_clear(&diff);
dns_diff_clear(&_sig_diff);
@@ -14740,10 +16116,14 @@ zone_rekey(dns_zone_t *zone) {
dns_db_detach(&db);
return;
- trylater:
- isc_interval_set(&ival, HOUR, 0);
+ failure:
+ /*
+ * Something went wrong; try again in ten minutes or
+ * after a key refresh interval, whichever is shorter.
+ */
+ isc_interval_set(&ival, ISC_MIN(zone->refreshkeyinterval, 600), 0);
isc_time_nowplusinterval(&zone->refreshkeytime, &ival);
- goto failure;
+ goto done;
}
void
@@ -14802,10 +16182,572 @@ dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db)
{
isc_time_t loadtime;
isc_result_t result;
+
TIME_NOW(&loadtime);
+ /*
+ * Lock hierarchy: zmgr, zone, raw.
+ */
LOCK_ZONE(zone);
+ if (inline_secure(zone))
+ LOCK_ZONE(zone->raw);
result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS);
+ if (inline_secure(zone))
+ UNLOCK_ZONE(zone->raw);
UNLOCK_ZONE(zone);
return result;
}
+
+isc_result_t
+dns_zone_setrefreshkeyinterval(dns_zone_t *zone, isc_uint32_t interval) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ if (interval == 0)
+ return (ISC_R_RANGE);
+ /* Maximum value: 24 hours (3600 minutes) */
+ if (interval > (24 * 60))
+ interval = (24 * 60);
+ /* Multiply by 60 for seconds */
+ zone->refreshkeyinterval = interval * 60;
+ return (ISC_R_SUCCESS);
+}
+
+void
+dns_zone_setrequestixfr(dns_zone_t *zone, isc_boolean_t flag) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->requestixfr = flag;
+}
+
+isc_boolean_t
+dns_zone_getrequestixfr(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (zone->requestixfr);
+}
+
+void
+dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->updatemethod = method;
+}
+
+dns_updatemethod_t
+dns_zone_getserialupdatemethod(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return(zone->updatemethod);
+}
+
+/*
+ * Lock hierarchy: zmgr, zone, raw.
+ */
+isc_result_t
+dns_zone_link(dns_zone_t *zone, dns_zone_t *raw) {
+ isc_result_t result;
+ dns_zonemgr_t *zmgr;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(zone->zmgr != NULL);
+ REQUIRE(zone->task != NULL);
+ REQUIRE(zone->loadtask != NULL);
+ REQUIRE(zone->raw == NULL);
+
+ REQUIRE(DNS_ZONE_VALID(raw));
+ REQUIRE(raw->zmgr == NULL);
+ REQUIRE(raw->task == NULL);
+ REQUIRE(raw->loadtask == NULL);
+ REQUIRE(raw->secure == NULL);
+
+ /*
+ * Lock hierarchy: zmgr, zone, raw.
+ */
+ zmgr = zone->zmgr;
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ LOCK_ZONE(zone);
+ LOCK_ZONE(raw);
+
+ result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
+ NULL, NULL, zone->task, zone_timer, raw,
+ &raw->timer);
+ if (result != ISC_R_SUCCESS)
+ goto unlock;
+
+ /*
+ * The timer "holds" a iref.
+ */
+ raw->irefs++;
+ INSIST(raw->irefs != 0);
+
+
+ /* dns_zone_attach(raw, &zone->raw); */
+ isc_refcount_increment(&raw->erefs, NULL);
+ zone->raw = raw;
+
+ /* dns_zone_iattach(zone, &raw->secure); */
+ zone_iattach(zone, &raw->secure);
+
+ isc_task_attach(zone->task, &raw->task);
+ isc_task_attach(zone->loadtask, &raw->loadtask);
+
+ ISC_LIST_APPEND(zmgr->zones, raw, link);
+ raw->zmgr = zmgr;
+ zmgr->refs++;
+
+ unlock:
+ UNLOCK_ZONE(raw);
+ UNLOCK_ZONE(zone);
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
+ return (result);
+}
+
+void
+dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(raw != NULL && *raw == NULL);
+
+ LOCK(&zone->lock);
+ if (zone->raw != NULL)
+ dns_zone_attach(zone->raw, raw);
+ UNLOCK(&zone->lock);
+}
+
+struct keydone {
+ isc_event_t event;
+ isc_boolean_t all;
+ unsigned char data[5];
+};
+
+#define PENDINGFLAGS (DNS_NSEC3FLAG_CREATE|DNS_NSEC3FLAG_INITIAL)
+
+static void
+keydone(isc_task_t *task, isc_event_t *event) {
+ const char *me = "keydone";
+ isc_boolean_t commit = ISC_FALSE;
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_dbversion_t *oldver = NULL, *newver = NULL;
+ dns_zone_t *zone;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_diff_t diff;
+ struct keydone *keydone = (struct keydone *)event;
+ dns_update_log_t log = { update_log_cb, NULL };
+ isc_boolean_t clear_pending = ISC_FALSE;
+
+ UNUSED(task);
+
+ zone = event->ev_arg;
+ INSIST(DNS_ZONE_VALID(zone));
+
+ ENTER;
+
+ dns_rdataset_init(&rdataset);
+ dns_diff_init(zone->mctx, &diff);
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL) {
+ dns_db_attach(zone->db, &db);
+ dns_db_currentversion(db, &oldver);
+ result = dns_db_newversion(db, &newver);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "keydone:dns_db_newversion -> %s",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (db == NULL)
+ goto failure;
+
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_findrdataset(db, node, newver, zone->privatetype,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ INSIST(!dns_rdataset_isassociated(&rdataset));
+ goto failure;
+ }
+ if (result != ISC_R_SUCCESS) {
+ INSIST(!dns_rdataset_isassociated(&rdataset));
+ goto failure;
+ }
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ isc_boolean_t found = ISC_FALSE;
+
+ dns_rdataset_current(&rdataset, &rdata);
+
+ if (keydone->all) {
+ if (rdata.length == 5 && rdata.data[0] != 0 &&
+ rdata.data[3] == 0 && rdata.data[4] == 1)
+ found = ISC_TRUE;
+ else if (rdata.data[0] == 0 &&
+ (rdata.data[2] & PENDINGFLAGS) != 0) {
+ found = ISC_TRUE;
+ clear_pending = ISC_TRUE;
+ }
+ } else if (rdata.length == 5 &&
+ memcmp(rdata.data, keydone->data, 5) == 0)
+ found = ISC_TRUE;
+
+ if (found)
+ CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_DEL,
+ &zone->origin, rdataset.ttl,
+ &rdata));
+ dns_rdata_reset(&rdata);
+ }
+
+ if (!ISC_LIST_EMPTY(diff.tuples)) {
+ /* Write changes to journal file. */
+ CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
+ zone->updatemethod));
+
+ result = dns_update_signatures(&log, zone, db,
+ oldver, newver, &diff,
+ zone->sigvalidityinterval);
+ if (!clear_pending)
+ CHECK(result);
+
+ CHECK(zone_journal(zone, &diff, NULL, "keydone"));
+ commit = ISC_TRUE;
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
+ zone_needdump(zone, 30);
+ UNLOCK_ZONE(zone);
+ }
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (db != NULL) {
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (oldver != NULL)
+ dns_db_closeversion(db, &oldver, ISC_FALSE);
+ if (newver != NULL)
+ dns_db_closeversion(db, &newver, commit);
+ dns_db_detach(&db);
+ }
+ dns_diff_clear(&diff);
+ isc_event_free(&event);
+ dns_zone_idetach(&zone);
+}
+
+isc_result_t
+dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_event_t *e;
+ isc_buffer_t b;
+ dns_zone_t *dummy = NULL;
+ struct keydone *kd;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+
+ e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_KEYDONE, keydone,
+ zone, sizeof(struct keydone));
+ if (e == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+
+ kd = (struct keydone *) e;
+ if (strcasecmp(keystr, "all") == 0)
+ kd->all = ISC_TRUE;
+ else {
+ isc_textregion_t r;
+ char *algstr;
+ dns_keytag_t keyid;
+ dns_secalg_t alg;
+ size_t n;
+
+ kd->all = ISC_FALSE;
+
+ n = sscanf(keystr, "%hd/", &keyid);
+ if (n == 0U)
+ CHECK(ISC_R_FAILURE);
+
+ algstr = strchr(keystr, '/');
+ if (algstr != NULL)
+ algstr++;
+ else
+ CHECK(ISC_R_FAILURE);
+
+ n = sscanf(algstr, "%hhd", &alg);
+ if (n == 0U) {
+ DE_CONST(algstr, r.base);
+ r.length = strlen(algstr);
+ CHECK(dns_secalg_fromtext(&alg, &r));
+ }
+
+ /* construct a private-type rdata */
+ isc_buffer_init(&b, kd->data, sizeof(kd->data));
+ isc_buffer_putuint8(&b, alg);
+ isc_buffer_putuint8(&b, (keyid & 0xff00) >> 8);
+ isc_buffer_putuint8(&b, (keyid & 0xff));
+ isc_buffer_putuint8(&b, 0);
+ isc_buffer_putuint8(&b, 1);
+ }
+
+ zone_iattach(zone, &dummy);
+ isc_task_send(zone->task, &e);
+
+ failure:
+ if (e != NULL)
+ isc_event_free(&e);
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+struct nsec3param {
+ isc_event_t event;
+ unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1];
+ unsigned int length;
+ isc_boolean_t nsec;
+ isc_boolean_t replace;
+};
+
+static void
+setnsec3param(isc_task_t *task, isc_event_t *event) {
+ const char *me = "setnsec3param";
+ isc_boolean_t commit = ISC_FALSE;
+ isc_result_t result;
+ dns_dbversion_t *oldver = NULL, *newver = NULL;
+ dns_zone_t *zone;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t prdataset, nrdataset;
+ dns_diff_t diff;
+ struct nsec3param *np = (struct nsec3param *)event;
+ dns_update_log_t log = { update_log_cb, NULL };
+ dns_rdata_t rdata;
+ isc_boolean_t nseconly;
+ isc_boolean_t exists = ISC_FALSE;
+
+ UNUSED(task);
+
+ zone = event->ev_arg;
+ INSIST(DNS_ZONE_VALID(zone));
+
+ ENTER;
+
+ dns_rdataset_init(&prdataset);
+ dns_rdataset_init(&nrdataset);
+ dns_diff_init(zone->mctx, &diff);
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL) {
+ dns_db_attach(zone->db, &db);
+ dns_db_currentversion(db, &oldver);
+ result = dns_db_newversion(db, &newver);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "setnsec3param:dns_db_newversion -> %s",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (db == NULL)
+ goto failure;
+
+ CHECK(dns_db_getoriginnode(db, &node));
+
+ /*
+ * Does a private-type record already exist for this chain?
+ */
+ result = dns_db_findrdataset(db, node, newver, zone->privatetype,
+ dns_rdatatype_none, 0, &prdataset, NULL);
+ if (result == ISC_R_SUCCESS) {
+ for (result = dns_rdataset_first(&prdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&prdataset)) {
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(&prdataset, &rdata);
+
+ if (np->length == rdata.length &&
+ memcmp(rdata.data, np->data, np->length) == 0) {
+ exists = ISC_TRUE;
+ break;
+ }
+ }
+ } else if (result != ISC_R_NOTFOUND) {
+ INSIST(!dns_rdataset_isassociated(&prdataset));
+ goto failure;
+ }
+
+ /*
+ * Does the chain already exist?
+ */
+ result = dns_db_findrdataset(db, node, newver,
+ dns_rdatatype_nsec3param,
+ dns_rdatatype_none, 0, &nrdataset, NULL);
+ if (result == ISC_R_SUCCESS) {
+ for (result = dns_rdataset_first(&nrdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&nrdataset)) {
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(&nrdataset, &rdata);
+
+ if (np->length == (rdata.length + 1) &&
+ memcmp(rdata.data, np->data + 1,
+ np->length - 1) == 0)
+ {
+ exists = ISC_TRUE;
+ break;
+ }
+ }
+ } else if (result != ISC_R_NOTFOUND) {
+ INSIST(!dns_rdataset_isassociated(&nrdataset));
+ goto failure;
+ }
+
+
+ /*
+ * We need to remove any existing NSEC3 chains.
+ */
+ if (!exists && np->replace && (np->length != 0 || np->nsec))
+ CHECK(dns_nsec3param_deletechains(db, newver, zone,
+ !np->nsec, &diff));
+
+ if (!exists && np->length != 0) {
+ /*
+ * We're creating an NSEC3 chain.
+ *
+ * If the zone is not currently capable of supporting
+ * an NSEC3 chain, add the INITIAL flag, so these
+ * parameters can be used later when NSEC3 becomes
+ * available.
+ */
+ dns_rdata_init(&rdata);
+
+ np->data[2] |= DNS_NSEC3FLAG_CREATE;
+ result = dns_nsec_nseconly(db, newver, &nseconly);
+ if (result == ISC_R_NOTFOUND || nseconly)
+ np->data[2] |= DNS_NSEC3FLAG_INITIAL;
+
+ rdata.length = np->length;
+ rdata.data = np->data;
+ rdata.type = zone->privatetype;
+ rdata.rdclass = zone->rdclass;
+ CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_ADD,
+ &zone->origin, 0, &rdata));
+ }
+
+ if (!ISC_LIST_EMPTY(diff.tuples)) {
+ /* Write changes to journal file. */
+ CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
+ zone->updatemethod));
+ result = dns_update_signatures(&log, zone, db,
+ oldver, newver, &diff,
+ zone->sigvalidityinterval);
+ if (result != ISC_R_NOTFOUND)
+ CHECK(result);
+ CHECK(zone_journal(zone, &diff, NULL, "setnsec3param"));
+ commit = ISC_TRUE;
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
+ zone_needdump(zone, 30);
+ UNLOCK_ZONE(zone);
+ }
+
+ failure:
+ if (dns_rdataset_isassociated(&prdataset))
+ dns_rdataset_disassociate(&prdataset);
+ if (dns_rdataset_isassociated(&nrdataset))
+ dns_rdataset_disassociate(&nrdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (oldver != NULL)
+ dns_db_closeversion(db, &oldver, ISC_FALSE);
+ if (newver != NULL)
+ dns_db_closeversion(db, &newver, commit);
+ if (db != NULL)
+ dns_db_detach(&db);
+ if (commit)
+ resume_addnsec3chain(zone);
+ dns_diff_clear(&diff);
+ isc_event_free(&event);
+ dns_zone_idetach(&zone);
+}
+
+isc_result_t
+dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags,
+ isc_uint16_t iter, isc_uint8_t saltlen,
+ unsigned char *salt, isc_boolean_t replace)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_rdata_nsec3param_t param;
+ dns_rdata_t nrdata = DNS_RDATA_INIT;
+ dns_rdata_t prdata = DNS_RDATA_INIT;
+ unsigned char nbuf[DNS_NSEC3PARAM_BUFFERSIZE];
+ struct nsec3param *np;
+ dns_zone_t *dummy = NULL;
+ isc_buffer_t b;
+ isc_event_t *e;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(salt != NULL);
+
+ LOCK_ZONE(zone);
+
+ e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETNSEC3PARAM,
+ setnsec3param, zone, sizeof(struct nsec3param));
+ if (e == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto failure;
+ }
+
+ np = (struct nsec3param *) e;
+ np->replace = replace;
+ if (hash == 0) {
+ np->length = 0;
+ np->nsec = ISC_TRUE;
+ } else {
+ param.common.rdclass = zone->rdclass;
+ param.common.rdtype = dns_rdatatype_nsec3param;
+ ISC_LINK_INIT(&param.common, link);
+ param.mctx = NULL;
+ param.hash = hash;
+ param.flags = flags;
+ param.iterations = iter;
+ param.salt_length = saltlen;
+ param.salt = salt;
+ isc_buffer_init(&b, nbuf, sizeof(nbuf));
+ CHECK(dns_rdata_fromstruct(&nrdata, zone->rdclass,
+ dns_rdatatype_nsec3param,
+ &param, &b));
+ dns_nsec3param_toprivate(&nrdata, &prdata, zone->privatetype,
+ np->data, sizeof(np->data));
+ np->length = prdata.length;
+ }
+
+ zone_iattach(zone, &dummy);
+ isc_task_send(zone->task, &e);
+
+ failure:
+ if (e != NULL)
+ isc_event_free(&e);
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+void
+dns_zone_setstatlevel(dns_zone_t *zone, dns_zonestat_level_t level) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->statlevel = level;
+}
+
+dns_zonestat_level_t
+dns_zone_getstatlevel(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->statlevel);
+}
OpenPOWER on IntegriCloud