+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
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.
#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>
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.
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;
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)
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;
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,
extern isc_boolean_t docheckns;
extern isc_boolean_t dochecksrv;
extern unsigned int zone_options;
+extern unsigned int zone_options2;
ISC_LANG_ENDDECLS
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;
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));
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;
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':
}
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|
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);
<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>
<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>
</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>
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) { \
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);
}
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);
}
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);
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);
}
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);
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)
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);
}
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;
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.
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;
exit(1);
}
} else
- fatal("unknown file format: %s\n", outputformatstr);
+ fatal("unknown file format: %s", outputformatstr);
}
if (serialformatstr != NULL) {
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);
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;
break;
}
- remove_duplicates();
+ /* Remove duplicates and cap TTLs at maxttl */
+ cleanup_zone();
if (!nonsecify) {
if (IS_NSEC3)
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);
<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>
</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>
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;
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);
*/
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))
"a non-terminal wildcard", namestr);
}
+ if ((options2 & DNS_ZONEOPT2_CHECKTTL) != 0) {
+ maxttl = dns_zone_getmaxttl(zone);
+ if (ttl > maxttl) {
+ ttl = maxttl;
+ update_log(client, zone,
+ LOGLEVEL_PROTOCOL,
+ "reducing TTL to the "
+ "configured max-zone-ttl %d",
+ maxttl);
+ }
+ }
+
if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {
char namestr[DNS_NAME_FORMATSIZE];
char typestr[DNS_RDATATYPE_FORMATSIZE];
} else
dns_zone_settype(zone, ztype);
-
obj = NULL;
result = cfg_map_get(zoptions, "database", &obj);
if (result == ISC_R_SUCCESS)
INSIST(0);
}
+ obj = NULL;
+ result = ns_config_get(maps, "max-zone-ttl", &obj);
+ if (result == ISC_R_SUCCESS && masterformat == dns_masterformat_map) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "zone '%s': 'max-zone-ttl' is not compatible "
+ "with 'masterfile-format map'", zname);
+ return (ISC_R_FAILURE);
+ } else if (result == ISC_R_SUCCESS) {
+ dns_ttl_t maxttl = cfg_obj_asuint32(obj);
+ dns_zone_setmaxttl(zone, maxttl);
+ if (raw != NULL)
+ dns_zone_setmaxttl(raw, maxttl);
+ }
+
if (raw != NULL && filename != NULL) {
#define SIGNED ".signed"
size_t signedlen = strlen(filename) + sizeof(SIGNED);
--- /dev/null
+/*
+ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+zone example {
+ type master;
+ masterfile-format map;
+ file "example.db";
+ max-zone-ttl 3600;
+};
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: clean.sh,v 1.2 2011/05/07 05:55:17 each Exp $
-
-rm -f good.conf.in good.conf.out badzero.conf
+rm -f good.conf.in good.conf.out badzero.conf *.out
rm -rf test.keydir
--- /dev/null
+/*
+ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+options {
+ directory ".";
+ max-zone-ttl 600;
+};
+
+zone "maxttl1.example" {
+ type master;
+ file "maxttl-bad.db";
+};
+
+zone "maxttl2.example" {
+ type master;
+ file "maxttl-bad.db";
+ max-zone-ttl 300;
+};
+
+zone "maxttl3.example" {
+ type master;
+ file "maxttl-bad.db";
+ max-zone-ttl 120;
+};
+
--- /dev/null
+/*
+ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+options {
+ directory ".";
+ max-zone-ttl 8000w;
+};
+
+zone "maxttl.example" {
+ type master;
+ file "maxttl-bad.db";
+};
+
+
--- /dev/null
+; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+ MX 10 mail
+
+a 600 A 10.0.0.1
+mail 900 A 10.0.0.2
--- /dev/null
+; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 600 ; 10 minutes
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns2
+ns2 A 10.53.0.2
+ MX 10 mail
+
+a A 10.0.0.1
+mail A 10.0.0.2
[ $n -eq 0 ] || ret=1
rm -rf test.keydir
if [ $ret != 0 ]; then echo "I:failed"; fi
+
+echo "I: checking that named-checkconf -z catches conflicting ttl with max-ttl"
+ret=0
+$CHECKCONF -z max-ttl.conf > check.out 2>&1
+grep 'TTL 900 exceeds configured max-zone-ttl 600' check.out > /dev/null 2>&1 || ret=1
+grep 'TTL 900 exceeds configured max-zone-ttl 600' check.out > /dev/null 2>&1 || ret=1
+grep 'TTL 900 exceeds configured max-zone-ttl 600' check.out > /dev/null 2>&1 || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
+status=`expr $status + $ret`
+
+echo "I: checking that named-checkconf -z catches invalid max-ttl"
+ret=0
+$CHECKCONF -z max-ttl-bad.conf > /dev/null 2>&1 && ret=1
+if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
echo "I:exit status: $status"
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: clean.sh,v 1.2 2011/03/02 04:20:33 marka Exp $
-
-rm -f test.*
+rm -f test.* good1.db.map good1.db.raw named-compilezone
--- /dev/null
+# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+rm -f named-compilezone
+ln -s $CHECKZONE named-compilezone
+
+./named-compilezone -D -F raw -o good1.db.raw example \
+ zones/good1.db > /dev/null 2>&1
+./named-compilezone -D -F map -o good1.db.map example \
+ zones/good1.db > /dev/null 2>&1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+echo "I:checking with max ttl (text) ($n)"
+ret=0
+$CHECKZONE -l 300 example zones/good1.db > test.out1.$n 2>&1 && ret=1
+$CHECKZONE -l 600 example zones/good1.db > test.out2.$n 2>&1 || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking with max ttl (raw) ($n)"
+ret=0
+$CHECKZONE -f raw -l 300 example good1.db.raw > test.out1.$n 2>&1 && ret=1
+$CHECKZONE -f raw -l 600 example good1.db.raw > test.out2.$n 2>&1 || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking with max ttl (map) ($n)"
+ret=0
+$CHECKZONE -f map -l 300 example good1.db.map > test.out1.$n 2>&1 && ret=1
+$CHECKZONE -f map -l 600 example good1.db.map > test.out2.$n 2>&1 || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:exit status: $status"
exit $status
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+echo "I:checking TTLs are capped by dnssec-signzone -M ($n)"
+ret=0
+(
+cd signer
+$SIGNER -O full -f signer.out.8 -S -M 30 -o example example.db > /dev/null 2>&1
+) || ret=1
+awk '/^;/ { next; } $2 > 30 { exit 1; }' signer/signer.out.8 || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
echo "I:checking validated data are not cached longer than originalttl ($n)"
ret=0
$DIG $DIGOPTS +ttl +noauth a.ttlpatch.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
--- /dev/null
+; Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000-2002 Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: max-ttl.db,v 1.10 2009/01/21 23:47:27 tbox Exp $
+
+$ORIGIN .
+$TTL 300 ; 5 minutes
+max-ttl.nil IN SOA ns1.max-ttl.nil. hostmaster.max-ttl.nil. (
+ 1 ; serial
+ 2000 ; refresh (2000 seconds)
+ 2000 ; retry (2000 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+max-ttl.nil. NS ns1.max-ttl.nil.
+ns1.max-ttl.nil. A 10.53.0.1
+max-ttl.nil. NS ns2.max-ttl.nil.
+ns2.max-ttl.nil. A 10.53.0.2
+
+$ORIGIN max-ttl.nil.
+* MX 10 mail
+a TXT "foo foo foo"
+ PTR foo.net.
allow-transfer { any; };
};
+zone "max-ttl.nil" {
+ type master;
+ file "max-ttl.db";
+ max-zone-ttl 300;
+ check-integrity no;
+ allow-update { any; };
+ allow-transfer { any; };
+};
+
zone "other.nil" {
type master;
file "other.db";
status=1
fi
+n=`expr $n + 1`
+ret=0
+echo "I:check that ttl is capped by max-ttl ($n)"
+$NSUPDATE <<END > /dev/null || ret=1
+server 10.53.0.1 5300
+update add cap.max-ttl.nil. 600 A 10.10.10.3
+update add nocap.max-ttl.nil. 150 A 10.10.10.3
+send
+END
+sleep 2
+$DIG @10.53.0.1 -p 5300 cap.max-ttl.nil | grep "^cap.max-ttl.nil. 300" > /dev/null 2>&1 || ret=1
+$DIG @10.53.0.1 -p 5300 nocap.max-ttl.nil | grep "^nocap.max-ttl.nil. 150" > /dev/null 2>&1 || ret=1
+if [ $ret -ne 0 ]; then
+ echo "I:failed"
+ status=1
+fi
+
n=`expr $n + 1`
ret=0
echo "I:add a record which is truncated when logged. ($n)"
<optional> lame-ttl <replaceable>number</replaceable>; </optional>
<optional> max-ncache-ttl <replaceable>number</replaceable>; </optional>
<optional> max-cache-ttl <replaceable>number</replaceable>; </optional>
+ <optional> max-zone-ttl <replaceable>number</replaceable> ; </optional>
<optional> sig-validity-interval <replaceable>number</replaceable> <optional><replaceable>number</replaceable></optional> ; </optional>
<optional> sig-signing-nodes <replaceable>number</replaceable> ; </optional>
<optional> sig-signing-signatures <replaceable>number</replaceable> ; </optional>
</varlistentry>
<varlistentry>
+ <term><command>max-zone-ttl</command></term>
+ <listitem>
+ <para>
+ Specifies a maximum permissible TTL value.
+ When loading a zone file using a
+ <option>masterfile-format</option> of
+ <constant>text</constant> or <constant>raw</constant>,
+ any record encountered with a TTL higher than
+ <option>max-zone-ttl</option> will cause the zone to
+ be rejected.
+ </para>
+ <para>
+ This is useful in DNSSEC-signed zones because when
+ rolling to a new DNSKEY, the old key needs to remain
+ available until RRSIG records have expired from
+ caches. The<option>max-zone-ttl</option> option guarantees
+ that the largest TTL in the zone will be no higher
+ the set value.
+ </para>
+ <para>
+ (NOTE: Because <constant>map</constant>-format files
+ load directly into memory, this option cannot be
+ used with them.)
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><command>zone-statistics</command></term>
<listitem>
<para>
<optional> inline-signing <replaceable>yes_or_no</replaceable>; </optional>
<optional> zero-no-soa-ttl <replaceable>yes_or_no</replaceable> ; </optional>
<optional> serial-update-method <constant>increment</constant>|<constant>unixtime</constant>; </optional>
+ <optional> max-zone-ttl <replaceable>number</replaceable> ; </optional>
};
zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replaceable></optional> {
file <replaceable>string</replaceable> ;
<optional> masterfile-format (<constant>text</constant>|<constant>raw</constant>|<constant>map</constant>) ; </optional>
<optional> allow-query { <replaceable>address_match_list</replaceable> }; </optional>
+ <optional> max-zone-ttl <replaceable>number</replaceable> ; </optional>
};
zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replaceable></optional> {
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>max-zone-ttl</command></term>
+ <listitem>
+ <para>
+ See the description of <command>max-zone-ttl</command>
+ in <xref linkend="options"/>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><command>dnssec-secure-to-insecure</command></term>
<listitem>
isc_boolean_t root = ISC_FALSE;
const cfg_listelt_t *element;
isc_boolean_t dlz;
+ dns_masterformat_t masterformat;
static optionstable options[] = {
{ "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
{ "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
+ { "max-zone-ttl", MASTERZONE | REDIRECTZONE },
{ "dnssec-secure-to-insecure", MASTERZONE },
{ "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
{ "sig-signing-nodes", MASTERZONE | SLAVEZONE },
if (root) {
if (voptions != NULL)
(void)cfg_map_get(voptions, "forwarders", &obj);
- if (obj == NULL) {
- const cfg_obj_t *options = NULL;
- (void)cfg_map_get(config, "options", &options);
- if (options != NULL)
- (void)cfg_map_get(options, "forwarders", &obj);
- }
+ if (obj == NULL && goptions != NULL)
+ (void)cfg_map_get(goptions, "forwarders", &obj);
}
if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
result = ISC_R_FAILURE;
}
}
+
+ /*
+ * Check that max-zone-ttl isn't used with masterfile-format map
+ */
+ masterformat = dns_masterformat_text;
+ obj = NULL;
+ (void)cfg_map_get(zoptions, "masterfile-format", &obj);
+ if (obj != NULL) {
+ const char *masterformatstr = cfg_obj_asstring(obj);
+ if (strcasecmp(masterformatstr, "text") == 0)
+ 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);
+ }
+
+ if (masterformat == dns_masterformat_map) {
+ obj = NULL;
+ (void)cfg_map_get(zoptions, "max-zone-ttl", &obj);
+ if (obj == NULL && voptions != NULL)
+ (void)cfg_map_get(voptions, "max-zone-ttl", &obj);
+ if (obj == NULL && goptions !=NULL)
+ (void)cfg_map_get(goptions, "max-zone-ttl", &obj);
+ if (obj != NULL) {
+ cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
+ "zone '%s': 'max-zone-ttl' is not "
+ "compatible with 'masterfile-format map'",
+ znamestr);
+ result = ISC_R_FAILURE;
+ }
+ }
+
/*
* Warn if key-directory doesn't exist
*/
#define DNS_MASTER_RESIGN 0x00002000
#define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */
#define DNS_MASTER_NOTTL 0x00008000 /*%< Don't require ttl. */
+#define DNS_MASTER_CHECKTTL 0x00010000 /*%< Check max-zone-ttl */
ISC_LANG_BEGINDECLS
void *include_arg, isc_mem_t *mctx,
dns_masterformat_t format);
+isc_result_t
+dns_master_loadfile5(const char *master_file,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ isc_uint32_t resign,
+ dns_rdatacallbacks_t *callbacks,
+ dns_masterincludecb_t include_cb,
+ void *include_arg, isc_mem_t *mctx,
+ dns_masterformat_t format,
+ dns_ttl_t maxttl);
+
isc_result_t
dns_master_loadstream(FILE *stream,
dns_name_t *top,
dns_masterincludecb_t include_cb, void *include_arg,
isc_mem_t *mctx, dns_masterformat_t format);
+isc_result_t
+dns_master_loadfileinc5(const char *master_file,
+ dns_name_t *top,
+ dns_name_t *origin,
+ dns_rdataclass_t zclass,
+ unsigned int options,
+ isc_uint32_t resign,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task,
+ dns_loaddonefunc_t done, void *done_arg,
+ dns_loadctx_t **ctxp,
+ dns_masterincludecb_t include_cb, void *include_arg,
+ isc_mem_t *mctx, dns_masterformat_t format,
+ isc_uint32_t maxttl);
+
isc_result_t
dns_master_loadstreaminc(FILE *stream,
dns_name_t *top,
#define DNS_ZONEOPT_CHECKDUPRRFAIL 0x40000000U /*%< fatal check-dup-records failures */
#define DNS_ZONEOPT_CHECKSPF 0x80000000U /*%< check SPF records */
+/*
+ * The following zone options are shifted left into the
+ * higher-order 32 bits of the options.
+ */
+#define DNS_ZONEOPT2_CHECKTTL 0x00000001 /*%< check max-zone-ttl */
+
#ifndef NOMINUM_PUBLIC
/*
* Nominum specific options build down.
*\li Pointer to null-terminated file name, or NULL.
*/
+void
+dns_zone_setmaxttl(dns_zone_t *zone, isc_uint32_t maxttl);
+/*%<
+ * Sets the max ttl of the zone.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *
+ * Returns:
+ *\li void
+ */
+
+dns_ttl_t
+dns_zone_getmaxttl(dns_zone_t *zone);
+/*%<
+ * Gets the max ttl of the zone.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *
+ * Returns:
+ *\li isc_uint32_t maxttl.
+ */
+
isc_result_t
dns_zone_load(dns_zone_t *zone);
*/
void
-dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value);
+dns_zone_setoption(dns_zone_t *zone, unsigned int option,
+ isc_boolean_t value);
+void
+dns_zone_setoption2(dns_zone_t *zone, unsigned int option,
+ isc_boolean_t value);
/*%<
- * Set given options on ('value' == ISC_TRUE) or off ('value' ==
- * #ISC_FALSE).
+ * Set the given options on ('value' == ISC_TRUE) or off
+ * ('value' == #ISC_FALSE).
+ *
+ * dns_zone_setoption2() has been introduced because the number
+ * of options needed now exceeds the 32 bits in the zone->options
+ * field; it should be used set options with names beginning
+ * with DNS_ZONEOPT2_.
*
* Require:
*\li 'zone' to be a valid zone.
unsigned int
dns_zone_getoptions(dns_zone_t *zone);
+unsigned int
+dns_zone_getoptions2(dns_zone_t *zone);
/*%<
* Returns the current zone options.
*
+ * Callers should be aware there is now more than one set of zone
+ * options. dns_zone_getoptions2() has been introduced because the
+ * number of options needed now exceeds the 32 bits in the
+ * zone->options field. It returns the options whose names begin
+ * with DNS_ZONEOPT2_.
+ *
* Require:
*\li 'zone' to be a valid zone.
*/
const char *filename);
isc_result_t (*load)(dns_loadctx_t *lctx);
+ /* Members used by all formats */
+ isc_uint32_t maxttl;
+
/* Members specific to the text format: */
isc_lex_t *lex;
isc_boolean_t keep_lex;
if (result != ISC_R_SUCCESS)
goto cleanup_ctx;
+ lctx->maxttl = 0;
+
lctx->format = format;
switch (format) {
default:
GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
explicit_ttl = ISC_FALSE;
- if (dns_ttl_fromtext(&token.value.as_textregion, &lctx->ttl)
- == ISC_R_SUCCESS) {
+ result = dns_ttl_fromtext(&token.value.as_textregion,
+ &lctx->ttl);
+ if (result == ISC_R_SUCCESS) {
limit_ttl(callbacks, source, line, &lctx->ttl);
explicit_ttl = ISC_TRUE;
lctx->ttl_known = ISC_TRUE;
lctx->ttl = this->ttl;
}
+ if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
+ lctx->ttl > lctx->maxttl)
+ {
+ (callbacks->error)(callbacks,
+ "dns_master_load: %s:%lu: "
+ "TTL %d exceeds configured max-zone-ttl %d",
+ source, line, lctx->ttl, lctx->maxttl);
+ result = ISC_R_RANGE;
+ goto log_and_cleanup;
+ }
+
ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
if (ictx->glue != NULL)
ictx->glue_line = line;
if (result != ISC_R_SUCCESS)
goto cleanup;
+ if ((lctx->options & DNS_MASTER_CHECKTTL) != 0 &&
+ rdatalist.ttl > lctx->maxttl)
+ {
+ (callbacks->error)(callbacks,
+ "dns_master_load: "
+ "TTL %d exceeds configured "
+ "max-zone-ttl %d",
+ rdatalist.ttl, lctx->maxttl);
+ result = ISC_R_RANGE;
+ goto cleanup;
+ }
+
/* Rdata contents. */
if (rdcount > rdata_size) {
dns_rdata_t *new_rdata = NULL;
dns_rdataclass_t zclass, unsigned int options,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
- return (dns_master_loadfile4(master_file, top, origin, zclass, options,
- 0, callbacks, NULL, NULL, mctx,
- dns_masterformat_text));
+ return (dns_master_loadfile5(master_file, top, origin, zclass,
+ options, 0, callbacks, NULL, NULL,
+ mctx, dns_masterformat_text, 0));
}
isc_result_t
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
dns_masterformat_t format)
{
- return (dns_master_loadfile4(master_file, top, origin, zclass, options,
- 0, callbacks, NULL, NULL, mctx, format));
+ return (dns_master_loadfile5(master_file, top, origin, zclass,
+ options, 0, callbacks, NULL, NULL,
+ mctx, format, 0));
}
isc_result_t
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
dns_masterformat_t format)
{
- return (dns_master_loadfile4(master_file, top, origin, zclass, options,
- resign, callbacks, NULL, NULL, mctx,
- format));
+ return (dns_master_loadfile5(master_file, top, origin, zclass,
+ options, resign, callbacks, NULL, NULL,
+ mctx, format, 0));
}
isc_result_t
dns_rdatacallbacks_t *callbacks,
dns_masterincludecb_t include_cb, void *include_arg,
isc_mem_t *mctx, dns_masterformat_t format)
+{
+ return (dns_master_loadfile5(master_file, top, origin, zclass,
+ options, resign, callbacks,
+ include_cb, include_arg,
+ mctx, format, 0));
+}
+
+isc_result_t
+dns_master_loadfile5(const char *master_file, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options, isc_uint32_t resign,
+ dns_rdatacallbacks_t *callbacks,
+ dns_masterincludecb_t include_cb, void *include_arg,
+ isc_mem_t *mctx, dns_masterformat_t format,
+ dns_ttl_t maxttl)
{
dns_loadctx_t *lctx = NULL;
isc_result_t result;
if (result != ISC_R_SUCCESS)
return (result);
+ lctx->maxttl = maxttl;
+
result = (lctx->openfile)(lctx, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;
void *done_arg, dns_loadctx_t **lctxp,
dns_masterincludecb_t include_cb, void *include_arg,
isc_mem_t *mctx, dns_masterformat_t format)
+{
+ options &= ~DNS_MASTER_CHECKTTL;
+ return (dns_master_loadfileinc5(master_file, top, origin, zclass,
+ options, resign, callbacks, task,
+ done, done_arg, lctxp, include_cb,
+ include_arg, mctx, format, 0));
+}
+
+isc_result_t
+dns_master_loadfileinc5(const char *master_file, dns_name_t *top,
+ dns_name_t *origin, dns_rdataclass_t zclass,
+ unsigned int options, isc_uint32_t resign,
+ dns_rdatacallbacks_t *callbacks,
+ isc_task_t *task, dns_loaddonefunc_t done,
+ void *done_arg, dns_loadctx_t **lctxp,
+ dns_masterincludecb_t include_cb, void *include_arg,
+ isc_mem_t *mctx, dns_masterformat_t format,
+ isc_uint32_t maxttl)
{
dns_loadctx_t *lctx = NULL;
isc_result_t result;
if (result != ISC_R_SUCCESS)
return (result);
+ lctx->maxttl = maxttl;
+
result = (lctx->openfile)(lctx, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;
isc_result_t result;
result = bind_ttl(source, ttl);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS && result != ISC_R_RANGE)
result = DNS_R_BADTTL;
return (result);
}
static isc_result_t
bind_ttl(isc_textregion_t *source, isc_uint32_t *ttl) {
- isc_uint32_t tmp = 0;
+ isc_uint64_t tmp = 0ULL;
isc_uint32_t n;
char *s;
char buf[64];
switch (*s) {
case 'w':
case 'W':
- tmp += n * 7 * 24 * 3600;
+ tmp += (isc_uint64_t) n * 7 * 24 * 3600;
s++;
break;
case 'd':
case 'D':
- tmp += n * 24 * 3600;
+ tmp += (isc_uint64_t) n * 24 * 3600;
s++;
break;
case 'h':
case 'H':
- tmp += n * 3600;
+ tmp += (isc_uint64_t) n * 3600;
s++;
break;
case 'm':
case 'M':
- tmp += n * 60;
+ tmp += (isc_uint64_t) n * 60;
s++;
break;
case 's':
case 'S':
- tmp += n;
+ tmp += (isc_uint64_t) n;
s++;
break;
case '\0':
/* Plain number? */
- if (tmp != 0)
+ if (tmp != 0ULL)
return (DNS_R_SYNTAX);
tmp = n;
break;
return (DNS_R_SYNTAX);
}
} while (*s != '\0');
- *ttl = tmp;
+
+ if (tmp > 0xffffffffULL)
+ return (ISC_R_RANGE);
+
+ *ttl = (isc_uint32_t)(tmp & 0xffffffffUL);
return (ISC_R_SUCCESS);
}
dns_zonetype_t type;
unsigned int flags;
unsigned int options;
+ unsigned int options2;
unsigned int db_argc;
char **db_argv;
isc_time_t expiretime;
isc_boolean_t sourceserialset;
isc_uint32_t sourceserial;
+
+ /*%
+ * maximum zone ttl
+ */
+ dns_ttl_t maxttl;
+
};
typedef struct {
#define DNS_ZONEFLG_SENDSECURE 0x40000000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
+#define DNS_ZONE_OPTION2(z,o) (((z)->options2 & (o)) != 0)
#define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0)
/* Flags for zone_load() */
zone->mastersok = NULL;
zone->masterscnt = 0;
zone->curmaster = 0;
+ zone->maxttl = 0;
zone->notify = NULL;
zone->notifykeynames = NULL;
zone->notifydscp = NULL;
return (zone->masterfile);
}
+dns_ttl_t
+dns_zone_getmaxttl(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->maxttl);
+}
+
+void
+dns_zone_setmaxttl(dns_zone_t *zone, dns_ttl_t maxttl) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (maxttl != 0)
+ zone->options2 |= DNS_ZONEOPT2_CHECKTTL;
+ else
+ zone->options2 &= ~DNS_ZONEOPT2_CHECKTTL;
+ zone->maxttl = maxttl;
+ UNLOCK_ZONE(zone);
+
+ return;
+}
+
static isc_result_t
default_journal(dns_zone_t *zone) {
isc_result_t result;
options |= DNS_MASTER_CHECKMXFAIL;
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
options |= DNS_MASTER_CHECKWILDCARD;
+ if (DNS_ZONE_OPTION2(zone, DNS_ZONEOPT2_CHECKTTL))
+ options |= DNS_MASTER_CHECKTTL;
return (options);
}
options = get_master_options(load->zone);
- result = dns_master_loadfileinc4(load->zone->masterfile,
+ result = dns_master_loadfileinc5(load->zone->masterfile,
dns_db_origin(load->db),
dns_db_origin(load->db),
load->zone->rdclass, options, 0,
&load->zone->lctx,
zone_registerinclude,
load->zone, load->zone->mctx,
- load->zone->masterformat);
+ load->zone->masterformat,
+ load->zone->maxttl);
if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE &&
result != DNS_R_SEENINCLUDE)
goto fail;
zone_idetach(&callbacks.zone);
return (result);
}
- result = dns_master_loadfile4(zone->masterfile,
+ result = dns_master_loadfile5(zone->masterfile,
&zone->origin, &zone->origin,
zone->rdclass, options, 0,
&callbacks,
zone_registerinclude,
zone, zone->mctx,
- zone->masterformat);
+ zone->masterformat,
+ zone->maxttl);
tresult = dns_db_endload(db, &callbacks);
if (result == ISC_R_SUCCESS)
result = tresult;
}
void
-dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value)
+dns_zone_setoption(dns_zone_t *zone, unsigned int option,
+ isc_boolean_t value)
{
REQUIRE(DNS_ZONE_VALID(zone));
UNLOCK_ZONE(zone);
}
+void
+dns_zone_setoption2(dns_zone_t *zone, unsigned int option,
+ isc_boolean_t value)
+{
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (value)
+ zone->options2 |= option;
+ else
+ zone->options2 &= ~option;
+ UNLOCK_ZONE(zone);
+}
+
unsigned int
dns_zone_getoptions(dns_zone_t *zone) {
-
REQUIRE(DNS_ZONE_VALID(zone));
return (zone->options);
}
+unsigned int
+dns_zone_getoptions2(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->options2);
+}
+
void
dns_zone_setkeyopt(dns_zone_t *zone, unsigned int keyopt, isc_boolean_t value)
{
#include <isc/string.h>
#include <isc/util.h>
+#include <dns/ttl.h>
+#include <dns/result.h>
+
#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <isccfg/log.h>
static cfg_type_t cfg_type_logseverity;
static cfg_type_t cfg_type_lwres;
static cfg_type_t cfg_type_masterselement;
+static cfg_type_t cfg_type_maxttl;
static cfg_type_t cfg_type_nameportiplist;
static cfg_type_t cfg_type_negated;
static cfg_type_t cfg_type_notifytype;
{ "max-transfer-idle-out", &cfg_type_uint32, 0 },
{ "max-transfer-time-in", &cfg_type_uint32, 0 },
{ "max-transfer-time-out", &cfg_type_uint32, 0 },
+ { "max-zone-ttl", &cfg_type_maxttl, 0 },
{ "min-refresh-time", &cfg_type_uint32, 0 },
{ "min-retry-time", &cfg_type_uint32, 0 },
{ "multi-master", &cfg_type_boolean, 0 },
"masters_element", parse_masterselement, NULL,
doc_masterselement, NULL, NULL
};
+
+static isc_result_t
+parse_maxttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ isc_result_t result;
+ cfg_obj_t *obj = NULL;
+ isc_uint32_t ttl;
+
+ UNUSED(type);
+
+ CHECK(cfg_gettoken(pctx, 0));
+ if (pctx->token.type != isc_tokentype_string) {
+ result = ISC_R_UNEXPECTEDTOKEN;
+ goto cleanup;
+ }
+
+ result = dns_ttl_fromtext(&pctx->token.value.as_textregion, &ttl);
+ if (result == ISC_R_RANGE ) {
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "TTL out of range ");
+ return (result);
+ } else if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
+ obj->value.uint32 = ttl;
+ *ret = obj;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
+ return (result);
+}
+
+/*%
+ * A size value (number + optional unit).
+ */
+static cfg_type_t cfg_type_maxttlval = {
+ "maxttlval", parse_maxttlval, cfg_print_uint64, cfg_doc_terminal,
+ &cfg_rep_uint64, NULL };
+
+static isc_result_t
+parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
+ return (parse_enum_or_other(pctx, type, &cfg_type_maxttlval, ret));
+}
+
+/*%
+ * A size or "unlimited", but not "default".
+ */
+static const char *maxttl_enums[] = { "unlimited", NULL };
+static cfg_type_t cfg_type_maxttl = {
+ "maxttl_no_default", parse_maxttl, cfg_print_ustring, cfg_doc_terminal,
+ &cfg_rep_string, maxttl_enums
+};