[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]
This commit is contained in:
Evan Hunt 2014-02-18 23:26:50 -08:00
parent 880c48d818
commit 35f6a21f5f
33 changed files with 939 additions and 75 deletions

View file

@ -1,3 +1,10 @@
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

4
README
View file

@ -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.

View file

@ -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;

View file

@ -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

View file

@ -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));

View file

@ -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);

View file

@ -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>

View file

@ -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(diff, &tuple);
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(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);

View file

@ -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>

View file

@ -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) {
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];

View file

@ -880,7 +880,6 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
} else
dns_zone_settype(zone, ztype);
obj = NULL;
result = cfg_map_get(zoptions, "database", &obj);
if (result == ISC_R_SUCCESS)
@ -962,6 +961,21 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
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);

View file

@ -0,0 +1,22 @@
/*
* 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;
};

View file

@ -14,7 +14,5 @@
# 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

View file

@ -0,0 +1,38 @@
/*
* 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;
};

View file

@ -0,0 +1,27 @@
/*
* 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";
};

View file

@ -0,0 +1,28 @@
; 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

View file

@ -0,0 +1,28 @@
; 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

View file

@ -163,6 +163,20 @@ n=`$CHECKCONF warn-keydir.conf 2>&1 | grep "key-directory" | wc -l`
[ $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"

View file

@ -12,6 +12,4 @@
# 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

View file

@ -0,0 +1,24 @@
# 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

View file

@ -68,4 +68,29 @@ n=`expr $n + 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

View file

@ -1526,6 +1526,16 @@ awk '/IN *SOA/ {if (NF != 7) exit(1)}' signer/signer.out.4 || ret=1
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

View file

@ -0,0 +1,35 @@
; 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.

View file

@ -58,6 +58,15 @@ zone "example.nil" {
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";

17
bin/tests/system/nsupdate/tests.sh Normal file → Executable file
View file

@ -552,6 +552,23 @@ if [ $ret -ne 0 ]; then
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)"

View file

@ -4879,6 +4879,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<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>
@ -5693,6 +5694,34 @@ options {
</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>
@ -10966,6 +10995,7 @@ view "external" {
<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> {
@ -11097,6 +11127,7 @@ zone <replaceable>"."</replaceable> <optional><replaceable>class</replaceable></
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> {
@ -12224,6 +12255,16 @@ example.com. NS ns2.example.net.
</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>

View file

@ -1431,6 +1431,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
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 |
@ -1460,6 +1461,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
{ "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 },
@ -1858,12 +1860,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
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;
@ -1940,6 +1938,41 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
}
/*
* 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
*/

View file

@ -58,6 +58,7 @@
#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
@ -159,6 +160,19 @@ dns_master_loadfile4(const char *master_file,
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,
@ -236,6 +250,21 @@ dns_master_loadfileinc4(const char *master_file,
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,

View file

@ -89,6 +89,12 @@ typedef enum {
#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.
@ -289,6 +295,30 @@ dns_zone_getfile(dns_zone_t *zone);
*\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);
@ -630,10 +660,19 @@ dns_zone_unload(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.
@ -641,9 +680,17 @@ dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value);
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.
*/

View file

@ -114,6 +114,9 @@ struct dns_loadctx {
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;
@ -556,6 +559,8 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
if (result != ISC_R_SUCCESS)
goto cleanup_ctx;
lctx->maxttl = 0;
lctx->format = format;
switch (format) {
default:
@ -1605,8 +1610,9 @@ load_text(dns_loadctx_t *lctx) {
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;
@ -1953,6 +1959,17 @@ load_text(dns_loadctx_t *lctx) {
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;
@ -2381,6 +2398,18 @@ load_raw(dns_loadctx_t *lctx) {
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;
@ -2510,9 +2539,9 @@ dns_master_loadfile(const char *master_file, dns_name_t *top,
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
@ -2522,8 +2551,9 @@ dns_master_loadfile2(const char *master_file, dns_name_t *top,
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
@ -2533,9 +2563,9 @@ dns_master_loadfile3(const char *master_file, dns_name_t *top,
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
@ -2545,6 +2575,21 @@ dns_master_loadfile4(const char *master_file, dns_name_t *top,
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;
@ -2555,6 +2600,8 @@ dns_master_loadfile4(const char *master_file, dns_name_t *top,
if (result != ISC_R_SUCCESS)
return (result);
lctx->maxttl = maxttl;
result = (lctx->openfile)(lctx, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;
@ -2618,6 +2665,24 @@ dns_master_loadfileinc4(const char *master_file, dns_name_t *top,
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;
@ -2631,6 +2696,8 @@ dns_master_loadfileinc4(const char *master_file, dns_name_t *top,
if (result != ISC_R_SUCCESS)
return (result);
lctx->maxttl = maxttl;
result = (lctx->openfile)(lctx, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;

View file

@ -142,14 +142,14 @@ dns_ttl_fromtext(isc_textregion_t *source, isc_uint32_t *ttl) {
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];
@ -179,32 +179,32 @@ bind_ttl(isc_textregion_t *source, isc_uint32_t *ttl) {
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;
@ -212,6 +212,10 @@ bind_ttl(isc_textregion_t *source, isc_uint32_t *ttl) {
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);
}

View file

@ -227,6 +227,7 @@ struct dns_zone {
dns_zonetype_t type;
unsigned int flags;
unsigned int options;
unsigned int options2;
unsigned int db_argc;
char **db_argv;
isc_time_t expiretime;
@ -395,6 +396,12 @@ struct dns_zone {
isc_boolean_t sourceserialset;
isc_uint32_t sourceserial;
/*%
* maximum zone ttl
*/
dns_ttl_t maxttl;
};
typedef struct {
@ -460,6 +467,7 @@ 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() */
@ -909,6 +917,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->mastersok = NULL;
zone->masterscnt = 0;
zone->curmaster = 0;
zone->maxttl = 0;
zone->notify = NULL;
zone->notifykeynames = NULL;
zone->notifydscp = NULL;
@ -1516,6 +1525,28 @@ dns_zone_getfile(dns_zone_t *zone) {
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;
@ -2047,6 +2078,8 @@ get_master_options(dns_zone_t *zone) {
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);
}
@ -2103,7 +2136,7 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
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,
@ -2112,7 +2145,8 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
&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;
@ -2268,13 +2302,14 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
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;
@ -4986,7 +5021,8 @@ dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value) {
}
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));
@ -4998,14 +5034,34 @@ dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value)
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)
{

View file

@ -29,6 +29,9 @@
#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>
@ -111,6 +114,7 @@ static cfg_type_t cfg_type_logging;
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;
@ -1641,6 +1645,7 @@ zone_clauses[] = {
{ "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 },
@ -3155,3 +3160,55 @@ static cfg_type_t cfg_type_masterselement = {
"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
};