]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] max-zone-ttl
authorEvan Hunt <each@isc.org>
Wed, 19 Feb 2014 07:26:50 +0000 (23:26 -0800)
committerEvan Hunt <each@isc.org>
Wed, 19 Feb 2014 07:26:50 +0000 (23:26 -0800)
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]

33 files changed:
CHANGES
README
bin/check/check-tool.c
bin/check/check-tool.h
bin/check/named-checkconf.c
bin/check/named-checkzone.c
bin/check/named-checkzone.docbook
bin/dnssec/dnssec-signzone.c
bin/dnssec/dnssec-signzone.docbook
bin/named/update.c
bin/named/zoneconf.c
bin/tests/system/checkconf/bad-maxttlmap.conf [new file with mode: 0644]
bin/tests/system/checkconf/clean.sh
bin/tests/system/checkconf/max-ttl.conf [new file with mode: 0644]
bin/tests/system/checkconf/maxttl-bad.conf [new file with mode: 0644]
bin/tests/system/checkconf/maxttl-bad.db [new file with mode: 0644]
bin/tests/system/checkconf/maxttl.db [new file with mode: 0644]
bin/tests/system/checkconf/tests.sh
bin/tests/system/checkzone/clean.sh
bin/tests/system/checkzone/setup.sh [new file with mode: 0644]
bin/tests/system/checkzone/tests.sh
bin/tests/system/dnssec/tests.sh
bin/tests/system/nsupdate/ns1/max-ttl.db [new file with mode: 0644]
bin/tests/system/nsupdate/ns1/named.conf
bin/tests/system/nsupdate/tests.sh [changed mode: 0644->0755]
doc/arm/Bv9ARM-book.xml
lib/bind9/check.c
lib/dns/include/dns/master.h
lib/dns/include/dns/zone.h
lib/dns/master.c
lib/dns/ttl.c
lib/dns/zone.c
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index a9084d23389d3026c968e0f42273c94efb5e8b03..7dd836779a26fcadd99fc3ff976ccf7dd9668682 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/README b/README
index 0f61794af145602fc48100e98e0d758c2b709b08..604ee31b263088da6159c2648c4fa3a924411e18 100644 (file)
--- a/README
+++ b/README
@@ -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.
index 1a805ed90e19909e263d4e7bf60c075d316b8f1b..88223d00770685585aaf03c852b08d7902093857 100644 (file)
 #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;
index 518ecef00d98b1246c23f9e0654f9d1696b45614..5ea53c483eae4cfe1c52657cd97806fbe1d01ff3 100644 (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
 
index fd3795a57fd2c9b005b99de5c274eb3d384ee0fd..97c919fe0a45db280bcca99ab774234862206ec1 100644 (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));
index a13cfa7d5c02cf8728ad7f16260761fd34c71177..b973f799341c936e5836d83a1634983d1302647a 100644 (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);
index 98d3fc3ff97c445a1449c743e7a3e35b8ab4e6d7..61baf5f03f7c3d9a062f0e81dbe532d39fd9e1bf 100644 (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>
       <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>
index 7b2f414e2a0bedc681dccd5e400834a6aa4dc775..e7609b177c523b39380a64ac81b1c78911a49d21 100644 (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(del, &tuple);
+                       } else if (set_maxttl && rdataset->ttl > maxttl) {
+                               vbprintf(2, "reducing ttl of %s/%s "
+                                           "from %d to %d\n",
+                                           namestr, typestr,
+                                           rdataset->ttl, maxttl);
                                result = dns_difftuple_create(mctx,
                                                      DNS_DIFFOP_DELRESIGN,
                                                      name, rdataset->ttl,
                                                      &rdata2, &tuple);
                                check_result(result, "dns_difftuple_create");
-                               dns_diff_append(diff, &tuple);
+                               dns_diff_append(del, &tuple);
+                               tuple = NULL;
+                               result = dns_difftuple_create(mctx,
+                                                     DNS_DIFFOP_ADDRESIGN,
+                                                     name, maxttl,
+                                                     &rdata2, &tuple);
+                               check_result(result, "dns_difftuple_create");
+                               dns_diff_append(add, &tuple);
                        }
                }
                dns_rdataset_disassociate(&tmprdataset);
@@ -2078,17 +2110,18 @@ rrset_remove_duplicates(dns_name_t *name, dns_rdataset_t *rdataset,
 }
 
 static void
-remove_duplicates(void) {
+cleanup_zone(void) {
        isc_result_t result;
        dns_dbiterator_t *dbiter = NULL;
        dns_rdatasetiter_t *rdsiter = NULL;
-       dns_diff_t diff;
+       dns_diff_t add, del;
        dns_dbnode_t *node = NULL;
        dns_rdataset_t rdataset;
        dns_fixedname_t fname;
        dns_name_t *name;
 
-       dns_diff_init(mctx, &diff);
+       dns_diff_init(mctx, &add);
+       dns_diff_init(mctx, &del);
        dns_fixedname_init(&fname);
        name = dns_fixedname_name(&fname);
        dns_rdataset_init(&rdataset);
@@ -2108,7 +2141,7 @@ remove_duplicates(void) {
                     result == ISC_R_SUCCESS;
                     result = dns_rdatasetiter_next(rdsiter)) {
                        dns_rdatasetiter_current(rdsiter, &rdataset);
-                       rrset_remove_duplicates(name, &rdataset, &diff);
+                       rrset_cleanup(name, &rdataset, &add, &del);
                        dns_rdataset_disassociate(&rdataset);
                }
                if (result != ISC_R_NOMORE)
@@ -2119,11 +2152,14 @@ remove_duplicates(void) {
        if (result != ISC_R_NOMORE)
                fatal("zone iteration failed.");
 
-       if (!ISC_LIST_EMPTY(diff.tuples)) {
-               result = dns_diff_applysilently(&diff, gdb, gversion);
-               check_result(result, "dns_diff_applysilently");
-       }
-       dns_diff_clear(&diff);
+       result = dns_diff_applysilently(&del, gdb, gversion);
+       check_result(result, "dns_diff_applysilently");
+
+       result = dns_diff_applysilently(&add, gdb, gversion);
+       check_result(result, "dns_diff_applysilently");
+
+       dns_diff_clear(&del);
+       dns_diff_clear(&add);
        dns_dbiterator_destroy(&dbiter);
 }
 
@@ -2448,11 +2484,11 @@ loadzonekeys(isc_boolean_t preserve_keys, isc_boolean_t load_public) {
                goto cleanup;
 
        if (set_keyttl && keyttl != rdataset.ttl) {
-               fprintf(stderr, "User-specified TTL (%d) conflicts "
+               fprintf(stderr, "User-specified TTL %d conflicts "
                                "with existing DNSKEY RRset TTL.\n",
                                keyttl);
                fprintf(stderr, "Imported keys will use the RRSet "
-                               "TTL (%d) instead.\n",
+                               "TTL %d instead.\n",
                                rdataset.ttl);
        }
        keyttl = rdataset.ttl;
@@ -3065,9 +3101,9 @@ main(int argc, char *argv[]) {
        isc_boolean_t set_iter = ISC_FALSE;
        isc_boolean_t nonsecify = ISC_FALSE;
 
-       /* Unused letters: Bb G J 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);
index 33c906b025de7b9f6b8d5ec655edd7c839828f54..67d977cdaccf8ba68ed6c3f058edfd7af3d91912 100644 (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>
         </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>
index b522f59991d29e45de5b9ff0ec3d1facb3ba39ed..217603f9ca3bb66db308ebe30ada6d3257d469fc 100644 (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];
index a98f0eb66350b41ab2a726dfa540d1ee7fe7f8a3..38493997ca87f126b73242b1f5ce351d9eb9de24 100644 (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);
diff --git a/bin/tests/system/checkconf/bad-maxttlmap.conf b/bin/tests/system/checkconf/bad-maxttlmap.conf
new file mode 100644 (file)
index 0000000..3020287
--- /dev/null
@@ -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;
+};
index dde871319176cacc09f7a49583c1d779a8be6966..26cffe1a39c300e7dc7c733f93cef3e005530303 100644 (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
diff --git a/bin/tests/system/checkconf/max-ttl.conf b/bin/tests/system/checkconf/max-ttl.conf
new file mode 100644 (file)
index 0000000..694ad2b
--- /dev/null
@@ -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;
+};
+
diff --git a/bin/tests/system/checkconf/maxttl-bad.conf b/bin/tests/system/checkconf/maxttl-bad.conf
new file mode 100644 (file)
index 0000000..6b3b289
--- /dev/null
@@ -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";
+};
+
+
diff --git a/bin/tests/system/checkconf/maxttl-bad.db b/bin/tests/system/checkconf/maxttl-bad.db
new file mode 100644 (file)
index 0000000..430f7dc
--- /dev/null
@@ -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
diff --git a/bin/tests/system/checkconf/maxttl.db b/bin/tests/system/checkconf/maxttl.db
new file mode 100644 (file)
index 0000000..a8daaa1
--- /dev/null
@@ -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
index 3d07b2a43509cb3b74694795ca050c3e301c6588..634c28cc0bfa7ce146b04063b4e8a9d2858e15ce 100644 (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"
index 7292efebe490138c26b019bd8451e249f47dcadf..b248998f4aea2e1d12301c508447e86733b75530 100644 (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
diff --git a/bin/tests/system/checkzone/setup.sh b/bin/tests/system/checkzone/setup.sh
new file mode 100644 (file)
index 0000000..3ddbd8d
--- /dev/null
@@ -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
index a727b411c8573018ececc73a5ad6149fd5d413b6..b731767073bbf38bafb89e1ef3da6109c6343a48 100644 (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
index b68dcb40b18b6a2e49424c2f88cfd18de12017a3..200ad245eddf5c44565018988ec3d233fbf71c31 100644 (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
diff --git a/bin/tests/system/nsupdate/ns1/max-ttl.db b/bin/tests/system/nsupdate/ns1/max-ttl.db
new file mode 100644 (file)
index 0000000..2f96cde
--- /dev/null
@@ -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.
index a2bcded8a5b5629e5a812ea9f41ea37d88e03d99..41a7b0016e1c257f38b35d0b79e64548b0429e32 100644 (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";
old mode 100644 (file)
new mode 100755 (executable)
index b5d7ccc..6a7b7b0
@@ -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)"
index b99e75a725c0a4aee2562f1a699588c93d8922df..d6767711ceb34f9746d4f5856de67f4a390b29f8 100644 (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>
index 7e75c0100893e6925b09d6f528967a2c605a961e..93b584ba6e380a49b879987dfb2475840237b96e 100644 (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
         */
index 931e9308443ccd42dd6aadabf6bcb84705f102c1..998f1a7facb76abb9242df77f1649933489f65b9 100644 (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,
index 5d28c2ac4cfe5e7db93145bbf079ca1cc2252024..3b7468463c1ec364f137dfb4c48830829bd44335 100644 (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.
  */
index 93b8236bdc514f2ac661d820e32540d5ee00bef3..9ad5d41d55cebe9d8895081820f355972b384a02 100644 (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;
index c794859064a062ecf9aa226a591b6bc2aa0464f9..d8ed3574492d35247cd70b94a49fd3234f9c1ee9 100644 (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);
 }
index 8c41d8ea81b1a051b718e37dfd7b5d2dfd1316de..3b3a81ba43babfe8db7545586730638aa85be9d2 100644 (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)
 {
index 65b26e5b81fb9f20d11800279cf01e092fa9d6dc..fec718ac3b79942b4b3047646384f15c90dcdaa4 100644 (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
+};