Commit 35f6a21f authored by Evan Hunt's avatar Evan Hunt

[master] max-zone-ttl

3746.	[func]		New "max-zone-ttl" option enforces maximum
			TTLs for zones. If loading a zone containing a
			higher TTL, the load fails. DDNS updates with
			higher TTLs are accepted but the TTL is truncated.
			(Note: Currently supported for master zones only;
			inline-signing slaves will be added.) [RT #38405]
parent 880c48d8
3746. [func] New "max-zone-ttl" option enforces maximum
TTLs for zones. If loading a zone containing a
higher TTL, the load fails. DDNS updates with
higher TTLs are accepted but the TTL is truncated.
(Note: Currently supported for master zones only;
inline-signing slaves will be added.) [RT #38405]
3745. [func] "configure --with-tuning=large" adjusts various
compiled-in constants and default settings to
values suited to large servers with abundant
......
......@@ -123,6 +123,10 @@ BIND 9.10.0
OpenSSL as an intermediary. This has been tested with the
Thales nShield HSM and with SoftHSMv2 from the Open DNSSEC
project.
- The new "max-zone-ttl" option enforces maximum TTLs for
zones. This can simplify the process of rolling DNSSEC keys
by guaranteeing that cached signatures will have expired
within the specified amount of time.
- New "dnssec-coverage" tool to check DNSSEC key coverage
for a zone and report if a lapse in signing coverage has
been inadvertently scheduled.
......
......@@ -40,12 +40,17 @@
#include <isc/types.h>
#include <isc/util.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
#include <dns/types.h>
#include <dns/zone.h>
......@@ -108,6 +113,7 @@ unsigned int zone_options = DNS_ZONEOPT_CHECKNS |
DNS_ZONEOPT_CHECKWILDCARD |
DNS_ZONEOPT_WARNMXCNAME |
DNS_ZONEOPT_WARNSRVCNAME;
unsigned int zone_options2 = 0;
/*
* This needs to match the list in bin/named/log.c.
......@@ -577,11 +583,93 @@ setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
return (ISC_R_SUCCESS);
}
/*% scan the zone for oversize TTLs */
static isc_result_t
check_ttls(dns_zone_t *zone, dns_ttl_t maxttl) {
isc_result_t result;
dns_db_t *db = NULL;
dns_dbversion_t *version = NULL;
dns_dbnode_t *node = NULL;
dns_dbiterator_t *dbiter = NULL;
dns_rdatasetiter_t *rdsiter = NULL;
dns_rdataset_t rdataset;
dns_fixedname_t fname;
dns_name_t *name;
dns_fixedname_init(&fname);
name = dns_fixedname_name(&fname);
dns_rdataset_init(&rdataset);
dns_zone_getdb(zone, &db);
INSIST(db != NULL);
CHECK(dns_db_newversion(db, &version));
CHECK(dns_db_createiterator(db, 0, &dbiter));
for (result = dns_dbiterator_first(dbiter);
result == ISC_R_SUCCESS;
result = dns_dbiterator_next(dbiter)) {
result = dns_dbiterator_current(dbiter, &node, name);
if (result == DNS_R_NEWORIGIN)
result = ISC_R_SUCCESS;
CHECK(result);
CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsiter));
for (result = dns_rdatasetiter_first(rdsiter);
result == ISC_R_SUCCESS;
result = dns_rdatasetiter_next(rdsiter)) {
dns_rdatasetiter_current(rdsiter, &rdataset);
if (rdataset.ttl > maxttl) {
char nbuf[DNS_NAME_FORMATSIZE];
char tbuf[255];
isc_buffer_t b;
isc_region_t r;
dns_name_format(name, nbuf, sizeof(nbuf));
isc_buffer_init(&b, tbuf, sizeof(tbuf) - 1);
CHECK(dns_rdatatype_totext(rdataset.type, &b));
isc_buffer_usedregion(&b, &r);
r.base[r.length] = 0;
dns_zone_log(zone, ISC_LOG_ERROR,
"%s/%s TTL %d exceeds "
"maximum TTL %d",
nbuf, tbuf, rdataset.ttl, maxttl);
dns_rdataset_disassociate(&rdataset);
CHECK(ISC_R_RANGE);
}
dns_rdataset_disassociate(&rdataset);
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
CHECK(result);
dns_rdatasetiter_destroy(&rdsiter);
dns_db_detachnode(db, &node);
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
cleanup:
if (node != NULL)
dns_db_detachnode(db, &node);
if (rdsiter != NULL)
dns_rdatasetiter_destroy(&rdsiter);
if (dbiter != NULL)
dns_dbiterator_destroy(&dbiter);
if (version != NULL)
dns_db_closeversion(db, &version, ISC_FALSE);
if (db != NULL)
dns_db_detach(&db);
return (result);
}
/*% load the zone */
isc_result_t
load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
dns_masterformat_t fileformat, const char *classname,
dns_zone_t **zonep)
dns_ttl_t maxttl, dns_zone_t **zonep)
{
isc_result_t result;
dns_rdataclass_t rdclass;
......@@ -618,7 +706,11 @@ load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
dns_zone_setclass(zone, rdclass);
dns_zone_setoption(zone, zone_options, ISC_TRUE);
dns_zone_setoption2(zone, zone_options2, ISC_TRUE);
dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge);
dns_zone_setmaxttl(zone, maxttl);
if (docheckmx)
dns_zone_setcheckmx(zone, checkmx);
if (docheckns)
......@@ -627,6 +719,15 @@ load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
dns_zone_setchecksrv(zone, checksrv);
CHECK(dns_zone_load(zone));
/*
* When loading map files we can't catch oversize TTLs during
* load, so we check for them here.
*/
if (fileformat == dns_masterformat_map && maxttl != 0) {
CHECK(check_ttls(zone, maxttl));
}
if (zonep != NULL) {
*zonep = zone;
zone = NULL;
......
......@@ -37,7 +37,7 @@ setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp);
isc_result_t
load_zone(isc_mem_t *mctx, const char *zonename, const char *filename,
dns_masterformat_t fileformat, const char *classname,
dns_zone_t **zonep);
dns_ttl_t maxttl, dns_zone_t **zonep);
isc_result_t
dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
......@@ -56,6 +56,7 @@ extern isc_boolean_t docheckmx;
extern isc_boolean_t docheckns;
extern isc_boolean_t dochecksrv;
extern unsigned int zone_options;
extern unsigned int zone_options2;
ISC_LANG_ENDDECLS
......
......@@ -198,6 +198,7 @@ configure_zone(const char *vclass, const char *view,
const cfg_obj_t *obj = NULL;
const cfg_obj_t *fmtobj = NULL;
dns_masterformat_t masterformat;
dns_ttl_t maxttl = 0;
zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
......@@ -373,11 +374,20 @@ configure_zone(const char *vclass, const char *view,
masterformat = dns_masterformat_text;
else if (strcasecmp(masterformatstr, "raw") == 0)
masterformat = dns_masterformat_raw;
else if (strcasecmp(masterformatstr, "map") == 0)
masterformat = dns_masterformat_map;
else
INSIST(0);
}
result = load_zone(mctx, zname, zfile, masterformat, zclass, NULL);
obj = NULL;
if (get_maps(maps, "max-zone-ttl", &obj)) {
maxttl = cfg_obj_asuint32(obj);
zone_options2 |= DNS_ZONEOPT2_CHECKTTL;
}
result = load_zone(mctx, zname, zfile, masterformat,
zclass, maxttl, NULL);
if (result != ISC_R_SUCCESS)
fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
dns_result_totext(result));
......
......@@ -115,6 +115,7 @@ main(int argc, char **argv) {
dns_masterformat_t outputformat = dns_masterformat_text;
dns_masterrawheader_t header;
isc_uint32_t rawversion = 1, serialnum = 0;
dns_ttl_t maxttl = 0;
isc_boolean_t snset = ISC_FALSE;
isc_boolean_t logdump = ISC_FALSE;
FILE *errout = stdout;
......@@ -169,7 +170,7 @@ main(int argc, char **argv) {
isc_commandline_errprint = ISC_FALSE;
while ((c = isc_commandline_parse(argc, argv,
"c:df:hi:jJ:k:L:m:n:qr:s:t:o:vw:DF:M:S:T:W:"))
"c:df:hi:jJ:k:L:l:m:n:qr:s:t:o:vw:DF:M:S:T:W:"))
!= EOF) {
switch (c) {
case 'c':
......@@ -263,6 +264,18 @@ main(int argc, char **argv) {
}
break;
case 'l':
zone_options2 |= DNS_ZONEOPT2_CHECKTTL;
endp = NULL;
maxttl = strtol(isc_commandline_argument, &endp, 0);
if (*endp != '\0') {
fprintf(stderr, "maximum TTL "
"must be numeric");
exit(1);
}
break;
case 'n':
if (ARGCMP("ignore")) {
zone_options &= ~(DNS_ZONEOPT_CHECKNS|
......@@ -523,7 +536,7 @@ main(int argc, char **argv) {
origin = argv[isc_commandline_index++];
filename = argv[isc_commandline_index++];
result = load_zone(mctx, origin, filename, inputformat, classname,
&zone);
maxttl, &zone);
if (snset) {
dns_master_initrawheader(&header);
......
......@@ -74,6 +74,7 @@
<arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-M <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-l <replaceable class="parameter">ttl</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
<arg><option>-o <replaceable class="parameter">filename</replaceable></option></arg>
<arg><option>-r <replaceable class="parameter">mode</replaceable></option></arg>
......@@ -102,6 +103,7 @@
<arg><option>-k <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-l <replaceable class="parameter">ttl</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
<arg><option>-r <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-s <replaceable class="parameter">style</replaceable></option></arg>
......@@ -301,6 +303,19 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-l <replaceable class="parameter">ttl</replaceable></term>
<listitem>
<para>
Sets a maximum permissible TTL for the input file.
Any record with a TTL higher than this value will cause
the zone to be rejected. This is similar to using the
<command>max-zone-ttl</command> option in
<filename>named.conf</filename>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-L <replaceable class="parameter">serial</replaceable></term>
<listitem>
......
......@@ -179,6 +179,8 @@ static isc_boolean_t remove_orphansigs = ISC_FALSE;
static isc_boolean_t remove_inactkeysigs = ISC_FALSE;
static isc_boolean_t output_dnssec_only = ISC_FALSE;
static isc_boolean_t output_stdout = ISC_FALSE;
isc_boolean_t set_maxttl = ISC_FALSE;
static dns_ttl_t maxttl = 0;
#define INCSTAT(counter) \
if (printstats) { \
......@@ -1232,6 +1234,10 @@ get_soa_ttls(void) {
dns_rdataset_current(&soaset, &rdata);
zone_soa_min_ttl = dns_soa_getminimum(&rdata);
soa_ttl = soaset.ttl;
if (set_maxttl) {
zone_soa_min_ttl = ISC_MIN(zone_soa_min_ttl, maxttl);
soa_ttl = ISC_MIN(soa_ttl, maxttl);
}
dns_rdataset_disassociate(&soaset);
}
......@@ -2007,7 +2013,8 @@ nsec3clean(dns_name_t *name, dns_dbnode_t *node,
rdatalist.rdclass = rdata.rdclass;
rdatalist.type = rdata.type;
rdatalist.covers = 0;
rdatalist.ttl = rdataset.ttl;
if (set_maxttl)
rdatalist.ttl = ISC_MIN(rdataset.ttl, maxttl);
ISC_LIST_INIT(rdatalist.rdata);
dns_rdata_init(&delrdata);
dns_rdata_clone(&rdata, &delrdata);
......@@ -2038,13 +2045,17 @@ nsec3clean(dns_name_t *name, dns_dbnode_t *node,
}
static void
rrset_remove_duplicates(dns_name_t *name, dns_rdataset_t *rdataset,
dns_diff_t *diff)
rrset_cleanup(dns_name_t *name, dns_rdataset_t *rdataset,
dns_diff_t *add, dns_diff_t *del)
{
dns_difftuple_t *tuple = NULL;
isc_result_t result;
unsigned int count1 = 0;
dns_rdataset_t tmprdataset;
char namestr[DNS_NAME_FORMATSIZE];
char typestr[TYPE_FORMATSIZE];
dns_name_format(name, namestr, sizeof(namestr));
type_format(rdataset->type, typestr, sizeof(typestr));
dns_rdataset_init(&tmprdataset);
for (result = dns_rdataset_first(rdataset);
......@@ -2060,17 +2071,38 @@ rrset_remove_duplicates(dns_name_t *name, dns_rdataset_t *rdataset,
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&tmprdataset)) {
dns_rdata_t rdata2 = DNS_RDATA_INIT;
dns_difftuple_t *tuple = NULL;
count2++;
if (count1 >= count2)
continue;
dns_rdataset_current(&tmprdataset, &rdata2);
if (dns_rdata_casecompare(&rdata1, &rdata2) == 0) {
if (count1 < count2 &&
dns_rdata_casecompare(&rdata1, &rdata2) == 0)
{
vbprintf(2, "removing duplicate at %s/%s\n",
namestr, typestr);
result = dns_difftuple_create(mctx,
DNS_DIFFOP_DELRESIGN,
name, rdataset->ttl,
&rdata2, &tuple);
check_result(result, "dns_difftuple_create");
dns_diff_append(del, &tuple);
} else if (set_maxttl && rdataset->ttl > maxttl) {
vbprintf(2, "reducing ttl of %s/%s "
"from %d to %d\n",
namestr, typestr,
rdataset->ttl, maxttl);
result = dns_difftuple_create(mctx,
DNS_DIFFOP_DELRESIGN,
name, rdataset->ttl,
&rdata2, &tuple);
check_result(result, "dns_difftuple_create");
dns_diff_append(diff, &tuple);
dns_diff_append(del, &tuple);
tuple = NULL;
result = dns_difftuple_create(mctx,
DNS_DIFFOP_ADDRESIGN,
name, maxttl,
&rdata2, &tuple);
check_result(result, "dns_difftuple_create");
dns_diff_append(add, &tuple);
}
}
dns_rdataset_disassociate(&tmprdataset);
......@@ -2078,17 +2110,18 @@ rrset_remove_duplicates(dns_name_t *name, dns_rdataset_t *rdataset,
}
static void
remove_duplicates(void) {
cleanup_zone(void) {
isc_result_t result;
dns_dbiterator_t *dbiter = NULL;
dns_rdatasetiter_t *rdsiter = NULL;
dns_diff_t diff;
dns_diff_t add, del;
dns_dbnode_t *node = NULL;
dns_rdataset_t rdataset;
dns_fixedname_t fname;
dns_name_t *name;
dns_diff_init(mctx, &diff);
dns_diff_init(mctx, &add);
dns_diff_init(mctx, &del);
dns_fixedname_init(&fname);
name = dns_fixedname_name(&fname);
dns_rdataset_init(&rdataset);
......@@ -2108,7 +2141,7 @@ remove_duplicates(void) {
result == ISC_R_SUCCESS;
result = dns_rdatasetiter_next(rdsiter)) {
dns_rdatasetiter_current(rdsiter, &rdataset);
rrset_remove_duplicates(name, &rdataset, &diff);
rrset_cleanup(name, &rdataset, &add, &del);
dns_rdataset_disassociate(&rdataset);
}
if (result != ISC_R_NOMORE)
......@@ -2119,11 +2152,14 @@ remove_duplicates(void) {
if (result != ISC_R_NOMORE)
fatal("zone iteration failed.");
if (!ISC_LIST_EMPTY(diff.tuples)) {
result = dns_diff_applysilently(&diff, gdb, gversion);
check_result(result, "dns_diff_applysilently");
}
dns_diff_clear(&diff);
result = dns_diff_applysilently(&del, gdb, gversion);
check_result(result, "dns_diff_applysilently");
result = dns_diff_applysilently(&add, gdb, gversion);
check_result(result, "dns_diff_applysilently");
dns_diff_clear(&del);
dns_diff_clear(&add);
dns_dbiterator_destroy(&dbiter);
}
......@@ -2448,11 +2484,11 @@ loadzonekeys(isc_boolean_t preserve_keys, isc_boolean_t load_public) {
goto cleanup;
if (set_keyttl && keyttl != rdataset.ttl) {
fprintf(stderr, "User-specified TTL (%d) conflicts "
fprintf(stderr, "User-specified TTL %d conflicts "
"with existing DNSKEY RRset TTL.\n",
keyttl);
fprintf(stderr, "Imported keys will use the RRSet "
"TTL (%d) instead.\n",
"TTL %d instead.\n",
rdataset.ttl);
}
keyttl = rdataset.ttl;
......@@ -3065,9 +3101,9 @@ main(int argc, char *argv[]) {
isc_boolean_t set_iter = ISC_FALSE;
isc_boolean_t nonsecify = ISC_FALSE;
/* Unused letters: Bb G J M q Yy (and F is reserved). */
/* Unused letters: Bb G J q Yy (and F is reserved). */
#define CMDLINE_FLAGS \
"3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:n:N:o:O:PpQRr:s:ST:tuUv:X:xzZ:"
"3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:M:n:N:o:O:PpQRr:s:ST:tuUv:X:xzZ:"
/*
* Process memory debugging argument first.
......@@ -3240,6 +3276,17 @@ main(int argc, char *argv[]) {
check_result(result, "dns_name_fromtext(dlv)");
break;
case 'M':
endp = NULL;
set_maxttl = ISC_TRUE;
maxttl = strtol(isc_commandline_argument, &endp, 0);
if (*endp != '\0') {
fprintf(stderr, "maximum TTL "
"must be numeric");
exit(1);
}
break;
case 'm':
break;
......@@ -3459,7 +3506,7 @@ main(int argc, char *argv[]) {
exit(1);
}
} else
fatal("unknown file format: %s\n", outputformatstr);
fatal("unknown file format: %s", outputformatstr);
}
if (serialformatstr != NULL) {
......@@ -3471,15 +3518,18 @@ main(int argc, char *argv[]) {
else if (strcasecmp(serialformatstr, "unixtime") == 0)
serialformat = SOA_SERIAL_UNIXTIME;
else
fatal("unknown soa serial format: %s\n",
fatal("unknown soa serial format: %s",
serialformatstr);
}
if (output_dnssec_only && outputformat != dns_masterformat_text)
fatal("option -D can only be used with \"-O text\"\n");
fatal("option -D can only be used with \"-O text\"");
if (output_dnssec_only && serialformat != SOA_SERIAL_KEEP)
fatal("option -D can only be used with \"-N keep\"\n");
fatal("option -D can only be used with \"-N keep\"");
if (output_dnssec_only && set_maxttl)
fatal("option -D cannot be used with -M");
result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL,
0, 24, 0, 0, 0, 8, mctx);
......@@ -3492,6 +3542,13 @@ main(int argc, char *argv[]) {
gclass = dns_db_class(gdb);
get_soa_ttls();
if (set_maxttl && set_keyttl && keyttl > maxttl) {
fprintf(stderr, "%s: warning: Specified key TTL %d "
"exceeds maximum zone TTL; reducing to %d\n",
program, keyttl, maxttl);
keyttl = maxttl;
}
if (!set_keyttl)
keyttl = soa_ttl;
......@@ -3596,7 +3653,8 @@ main(int argc, char *argv[]) {
break;
}
remove_duplicates();
/* Remove duplicates and cap TTLs at maxttl */
cleanup_zone();
if (!nonsecify) {
if (IS_NSEC3)
......@@ -3725,7 +3783,7 @@ main(int argc, char *argv[]) {
result = isc_file_rename(tempfile, output);
if (result != ISC_R_SUCCESS)
fatal("failed to rename temp file to %s: %s\n",
fatal("failed to rename temp file to %s: %s",
output, isc_result_totext(result));
printf("%s\n", output);
......
......@@ -74,6 +74,7 @@
<arg><option>-k <replaceable class="parameter">key</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
<arg><option>-l <replaceable class="parameter">domain</replaceable></option></arg>
<arg><option>-M <replaceable class="parameter">domain</replaceable></option></arg>
<arg><option>-i <replaceable class="parameter">interval</replaceable></option></arg>
<arg><option>-I <replaceable class="parameter">input-format</replaceable></option></arg>
<arg><option>-j <replaceable class="parameter">jitter</replaceable></option></arg>
......@@ -235,6 +236,26 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-M <replaceable class="parameter">maxttl</replaceable></term>
<listitem>
<para>
Sets the maximum TTL for the signed zone.
Any TTL higher than <replaceable>maxttl</replaceable> in the
input zone will be reduced to <replaceable>maxttl</replaceable>
in the output. This provides certainty as to the largest
possible TTL in the signed zone, which is useful to know when
rolling keys because it is the longest possible time before
signatures that have been retrieved by resolvers will expire
from resolver caches. Zones that are signed with this
option should be configured to use a matching
<option>max-zone-ttl</option> in <filename>named.conf</filename>.
(Note: This option is incompatible with <option>-D</option>,
because it modifies non-DNSSEC data in the output zone.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-s <replaceable class="parameter">start-time</replaceable></term>
<listitem>
......
......@@ -2434,7 +2434,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
update_event_t *uev = (update_event_t *) event;
dns_zone_t *zone = uev->zone;
ns_client_t *client = (ns_client_t *)event->ev_arg;
isc_result_t result;
dns_db_t *db = NULL;
dns_dbversion_t *oldver = NULL;
......@@ -2450,11 +2449,12 @@ update_action(isc_task_t *task, isc_event_t *event) {
dns_ssutable_t *ssutable = NULL;
dns_fixedname_t tmpnamefixed;
dns_name_t *tmpname = NULL;
unsigned int options;
unsigned int options, options2;
dns_difftuple_t *tuple;
dns_rdata_dnskey_t dnskey;
isc_boolean_t had_dnskey;
dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
dns_ttl_t maxttl = 0;
INSIST(event->ev_type == DNS_EVENT_UPDATE);
......@@ -2730,6 +2730,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
*/
options = dns_zone_getoptions(zone);
options2 = dns_zone_getoptions2(zone);
for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
result == ISC_R_SUCCESS;
result = dns_message_nextname(request, DNS_SECTION_UPDATE))
......@@ -2855,6 +2856,18 @@ update_action(isc_task_t *task, isc_event_t *event) {
"a non-terminal wildcard", namestr);
}
if ((options2 & DNS_ZONEOPT2_CHECKTTL) != 0) {