]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3750. [experimental] Partially implement EDNS EXPIRE option as described
authorMark Andrews <marka@isc.org>
Thu, 20 Feb 2014 03:56:20 +0000 (14:56 +1100)
committerMark Andrews <marka@isc.org>
Thu, 20 Feb 2014 03:56:20 +0000 (14:56 +1100)
                        in draft-andrews-dnsext-expire-00.  Retrivial of
                        remaining time to expiry from slave zones is supported.

                        EXPIRE uses an experimental option code (65002) and
                        is subject to change. [RT #35416]

15 files changed:
CHANGES
bin/dig/dig.c
bin/dig/dig.docbook
bin/dig/dighost.c
bin/dig/include/dig/dig.h
bin/named/client.c
bin/named/include/named/client.h
bin/named/query.c
bin/tests/system/cacheclean/clean.sh
bin/tests/system/cacheclean/ns1/expire-test.db [new file with mode: 0644]
bin/tests/system/cacheclean/ns1/named.conf
bin/tests/system/cacheclean/ns2/named.conf
bin/tests/system/cacheclean/tests.sh
lib/dns/include/dns/message.h
lib/dns/message.c

diff --git a/CHANGES b/CHANGES
index 2b63f30d2984116ebb6aa44e7e7cf683d065cdae..b4900063e9f73c438030906c2e863d096df099a8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+3750.  [experimental]  Partially implement EDNS EXPIRE option as described
+                       in draft-andrews-dnsext-expire-00.  Retrivial of
+                       remaining time to expiry from slave zones is supported.
+
+                       EXPIRE uses an experimental option code (65002) and
+                       is subject to change. [RT #35416]
+
 3749.  [func]          "dig +subnet" sends an EDNS client subnet option
                        containing the specified address/prefix when
                        querying. (Thanks to Wilmer van der Gaast.)
index dd1946fc9018c13dfe7765253eff45916b0546f4..007bcdd76788921c1449c2a34405740935512528 100644 (file)
@@ -226,6 +226,7 @@ help(void) {
 "                 +[no]identify       (ID responders in short answers)\n"
 "                 +[no]trace          (Trace delegation down from root [+dnssec])\n"
 "                 +[no]dnssec         (Request DNSSEC records)\n"
+"                 +[no]expire         (Request time to expire)\n"
 "                 +[no]nsid           (Request Name Server ID)\n"
 #ifdef ISC_PLATFORM_USESIT
 "                 +[no]sit            (Request a Source Identity Token)\n"
@@ -919,19 +920,29 @@ plus_option(char *option, isc_boolean_t is_batchfile,
                }
                break;
        case 'e':
-               FULLCHECK("edns");
-               if (!state) {
-                       lookup->edns = -1;
+               switch (cmd[1]) {
+               case 'd':
+                       FULLCHECK("edns");
+                       if (!state) {
+                               lookup->edns = -1;
+                               break;
+                       }
+                       if (value == NULL) {
+                               lookup->edns = 0;
+                               break;
+                       }
+                       result = parse_uint(&num, value, 255, "edns");
+                       if (result != ISC_R_SUCCESS)
+                               fatal("Couldn't parse edns");
+                       lookup->edns = num;
                        break;
-               }
-               if (value == NULL) {
-                       lookup->edns = 0;
+               case 'x':
+                       FULLCHECK("expire");
+                       lookup->expire = state;
                        break;
+               default:
+                       goto invalid_option;
                }
-               result = parse_uint(&num, value, 255, "edns");
-               if (result != ISC_R_SUCCESS)
-                       fatal("Couldn't parse edns");
-               lookup->edns = num;
                break;
        case 'f': /* fail */
                FULLCHECK("fail");
index 9ab93d64c3bd9dba917ef3a72121d6394a210ef1..5836e7dca7a4649f716bf4d2c78f85306d5efdcb 100644 (file)
              Send a Source Identity Token EDNS option, with optional value.
              Replaying a SIT from a previous response will allow the
              server to identify a previous client.  The default is
-             <option>+nosit</option>.
+             <option>+nosit</option>.  Currently using experimental value
+             65001 for the option code.
             </para>
           </listitem>
         </varlistentry>
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><option>+[no]expire</option></term>
+          <listitem>
+            <para>
+             Send an EDNS Expire option.  Currently using experimental
+             value 65002 for the option code.
+            </para>
+          </listitem>
+        </varlistentry>
+
       </variablelist>
 
     </para>
index e6bb08df3192c7b2c46ec13c74a377c12a68abf4..337bc2936a76a060b7ce8b8224136394a33df175 100644 (file)
@@ -767,6 +767,7 @@ make_empty_lookup(void) {
        looknew->servfail_stops = ISC_TRUE;
        looknew->besteffort = ISC_TRUE;
        looknew->dnssec = ISC_FALSE;
+       looknew->expire = ISC_FALSE;
        looknew->nsid = ISC_FALSE;
 #ifdef ISC_PLATFORM_USESIT
        looknew->sit = ISC_FALSE;
@@ -855,6 +856,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
        looknew->servfail_stops = lookold->servfail_stops;
        looknew->besteffort = lookold->besteffort;
        looknew->dnssec = lookold->dnssec;
+       looknew->expire = lookold->expire;
        looknew->nsid = lookold->nsid;
 #ifdef ISC_PLATFORM_USESIT
        looknew->sit = lookold->sit;
@@ -2428,6 +2430,14 @@ setup_lookup(dig_lookup_t *lookup) {
                }
 #endif
 
+               if (lookup->expire) {
+                       INSIST(i < DNS_EDNSOPTIONS);
+                       opts[i].code = DNS_OPT_EXPIRE;
+                       opts[i].length = 0;
+                       opts[i].value = NULL;
+                       i++;
+               }
+
                add_opt(lookup->sendmsg, lookup->udpsize,
                        lookup->edns, lookup->dnssec, opts, i);
        }
index ad4c7c2ab2171fb407d246c26a33a3de54cc8386..205e6cd2aeb0f6acdef1344192792ce985facab8 100644 (file)
@@ -130,6 +130,7 @@ struct dig_lookup {
                done_as_is,
                besteffort,
                dnssec,
+               expire,
 #ifdef ISC_PLATFORM_USESIT
                sit,
 #endif
index 52d813bca8d8700b4f75d594b6e3d60a473c2e23..6e091c9b3c5ab1824126ea499806731a96ada2ae 100644 (file)
@@ -249,6 +249,7 @@ allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl);
 static void compute_sit(ns_client_t *client, isc_uint32_t when,
                        isc_uint32_t nonce, isc_buffer_t *buf);
 #endif
+static inline isc_result_t client_addopt(ns_client_t *client);
 
 void
 ns_client_recursing(ns_client_t *client) {
@@ -1013,6 +1014,15 @@ client_send(ns_client_t *client) {
        }
 #endif
 
+       /*
+        * Create an OPT for our reply.
+        */
+       if ((client->attributes & NS_CLIENTATTR_WANTOPT) != 0) {
+               result = client_addopt(client);
+               if (result != ISC_R_SUCCESS)
+                       goto done;
+       }
+
        /*
         * XXXRTH  The following doesn't deal with TCP buffer resizing.
         */
@@ -1380,6 +1390,7 @@ client_addopt(ns_client_t *client) {
        dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
        int count = 0;
        unsigned int flags;
+       unsigned char expire[4];
 
        REQUIRE(client->opt == NULL);   /* XXXRTH free old. */
 
@@ -1432,6 +1443,18 @@ client_addopt(ns_client_t *client) {
                count++;
        }
 #endif
+       if ((client->attributes & NS_CLIENTATTR_HAVEEXPIRE) != 0) {
+               isc_buffer_t buf;
+
+               INSIST(count < DNS_EDNSOPTIONS);
+
+               isc_buffer_init(&buf, expire, sizeof(expire));
+               isc_buffer_putuint32(&buf, client->expire);
+               ednsopts[count].code = DNS_OPT_EXPIRE;
+               ednsopts[count].length = 4;
+               ednsopts[count].value = expire;
+               count++;
+       }
 
        result = dns_message_buildopt(client->message, &client->opt, 0,
                                      udpsize, flags, ednsopts, count);
@@ -1752,6 +1775,10 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
                                process_sit(client, &optbuf, optlen);
                                break;
 #endif
+                       case DNS_OPT_EXPIRE:
+                               client->attributes |= NS_CLIENTATTR_WANTEXPIRE;
+                               isc_buffer_forward(&optbuf, optlen);
+                               break;
                        default:
                                isc_buffer_forward(&optbuf, optlen);
                                break;
@@ -1760,15 +1787,8 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
        }
 
        isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_edns0in);
+       client->attributes |= NS_CLIENTATTR_WANTOPT;
 
-       /*
-        * Create an OPT for our reply.
-        */
-       result = client_addopt(client);
-       if (result != ISC_R_SUCCESS) {
-               ns_client_error(client, result);
-               goto cleanup;
-       }
  cleanup:
        return (result);
 }
index 5707d8ec5be942a1fb9dcf0ce00f4e08af9224fa..c526fe0a8eb8bc6aa1dbebd1a7707b0f9188e577 100644 (file)
@@ -162,6 +162,7 @@ struct ns_client {
        ISC_LINK(ns_client_t)   rlink;
        ISC_QLINK(ns_client_t)  ilink;
        unsigned char           cookie[8];
+       isc_uint32_t            expire;
 };
 
 typedef ISC_QUEUE(ns_client_t) client_queue_t;
@@ -170,19 +171,22 @@ typedef ISC_LIST(ns_client_t) client_list_t;
 #define NS_CLIENT_MAGIC                        ISC_MAGIC('N','S','C','c')
 #define NS_CLIENT_VALID(c)             ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC)
 
-#define NS_CLIENTATTR_TCP              0x001
-#define NS_CLIENTATTR_RA               0x002 /*%< Client gets recursive service */
-#define NS_CLIENTATTR_PKTINFO          0x004 /*%< pktinfo is valid */
-#define NS_CLIENTATTR_MULTICAST                0x008 /*%< recv'd from multicast */
-#define NS_CLIENTATTR_WANTDNSSEC       0x010 /*%< include dnssec records */
-#define NS_CLIENTATTR_WANTNSID          0x020 /*%< include nameserver ID */
+#define NS_CLIENTATTR_TCP              0x0001
+#define NS_CLIENTATTR_RA               0x0002 /*%< Client gets recursive service */
+#define NS_CLIENTATTR_PKTINFO          0x0004 /*%< pktinfo is valid */
+#define NS_CLIENTATTR_MULTICAST                0x0008 /*%< recv'd from multicast */
+#define NS_CLIENTATTR_WANTDNSSEC       0x0010 /*%< include dnssec records */
+#define NS_CLIENTATTR_WANTNSID          0x0020 /*%< include nameserver ID */
 #ifdef ALLOW_FILTER_AAAA
-#define NS_CLIENTATTR_FILTER_AAAA      0x040 /*%< suppress AAAAs */
-#define NS_CLIENTATTR_FILTER_AAAA_RC   0x080 /*%< recursing for A against AAAA */
+#define NS_CLIENTATTR_FILTER_AAAA      0x0040 /*%< suppress AAAAs */
+#define NS_CLIENTATTR_FILTER_AAAA_RC   0x0080 /*%< recursing for A against AAAA */
 #endif
-#define NS_CLIENTATTR_WANTAD           0x100 /*%< want AD in response if possible */
-#define NS_CLIENTATTR_WANTSIT          0x200 /*%< include SIT */
-#define NS_CLIENTATTR_HAVESIT          0x400 /*%< has a valid SIT */
+#define NS_CLIENTATTR_WANTAD           0x0100 /*%< want AD in response if possible */
+#define NS_CLIENTATTR_WANTSIT          0x0200 /*%< include SIT */
+#define NS_CLIENTATTR_HAVESIT          0x0400 /*%< has a valid SIT */
+#define NS_CLIENTATTR_WANTEXPIRE       0x0800 /*%< return seconds to expire */
+#define NS_CLIENTATTR_HAVEEXPIRE       0x1000 /*%< return seconds to expire */
+#define NS_CLIENTATTR_WANTOPT          0x2000 /*%< add opt to reply */
 
 extern unsigned int ns_client_requests;
 
index 7b3a825f7953536336efeffe02976132d33db2dc..08c5675cdba5ed6b0aff4e48070f4fd3ffe371be 100644 (file)
@@ -7864,6 +7864,20 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                    dns_name_equal(client->query.qname, dns_rootname))
                        client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
 
+               if (is_zone && qtype == dns_rdatatype_soa &&
+                   (client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 &&
+                   client->query.restarts == 0 &&
+                   dns_zone_gettype(zone) == dns_zone_slave) {
+                       isc_time_t expiretime;
+                       isc_uint32_t secs;
+                       dns_zone_getexpiretime(zone, &expiretime);
+                       secs = isc_time_seconds(&expiretime);
+                       if (secs >= client->now && result == ISC_R_SUCCESS) {
+                               client->attributes |= NS_CLIENTATTR_HAVEEXPIRE; 
+                               client->expire = secs - client->now;
+                       }
+               }
+
                if (dns64) {
                        qtype = type = dns_rdatatype_aaaa;
                        result = query_dns64(client, &fname, rdataset,
index 7e0b949903b2c7146b1b8d3ef0b8506317b2d5a2..5640af2b5716e7defb301e4783210600a9f037f7 100644 (file)
@@ -22,5 +22,6 @@
 #
 
 rm -f dig.out.ns2
+rm -f dig.out.expire
 rm -f */named.memstats
 rm -f ns2/named_dump.db
diff --git a/bin/tests/system/cacheclean/ns1/expire-test.db b/bin/tests/system/cacheclean/ns1/expire-test.db
new file mode 100644 (file)
index 0000000..d86da4c
--- /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.
+
+$TTL 3600
+@                      IN SOA  hostmaster.ns ns (
+                               2011072900
+                               600
+                               600
+                               1200
+                               3600
+                               )
+                       NS      ns
+ns                     IN      A       10.53.0.1
index 708de1a3ab1da52d5e4c1bce5a5792a165c9348f..616875f1db70590807290cb8dc1de0cfcfc67b8a 100644 (file)
@@ -41,3 +41,8 @@ zone "flushtest.example" {
        type master;
        file "flushtest.db";
 };
+
+zone "expire-test" {
+        type master;
+       file "expire-test.db";
+};
index b0e0704100207faa028727253eb6534369dd3044..376dd8bc1ee220ca3eb56457125382ec83ac8956 100644 (file)
@@ -50,3 +50,8 @@ zone "flushtest.example" {
        type forward;
        forwarders { 10.53.0.1; };
 };
+
+zone "expire-test" {
+       type slave;
+       masters { 10.53.0.1; };
+};
index 5436852850cf66b514ae0ae8b8d75f0463e5e93e..43ca679de184dc537d4795a349de49adb7eb4337 100644 (file)
@@ -201,5 +201,12 @@ awk '/plain success\/timeout/ {getline; getline; if ($2 == "ns.flushtest.example
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:check expire option returned from slave zone"
+ret=0
+$DIG @10.53.0.2 -p 5300 +expire soa expire-test > dig.out.expire
+grep EXPIRE: dig.out.expire > /dev/null || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:exit status: $status"
 exit $status
index a6cc1b4241d82aa6d50fda2a48be4f016025c36b..88fb31ae6831eaa5cd71d312a62e2ba30b6fe29c 100644 (file)
 #define DNS_OPT_CLIENT_SUBNET  0x0008          /*%< client subnet opt code */
 /*%< Experimental options [65001...65534] as per RFC6891 */
 #define DNS_OPT_SIT            65001           /*%< SIT opt code */
+#define DNS_OPT_EXPIRE         65002           /*%< EXPIRE opt code */
 
 /*%< The number of EDNS options we know about. */
-#define DNS_EDNSOPTIONS        3
+#define DNS_EDNSOPTIONS        4
 
 #define DNS_MESSAGE_REPLYPRESERVE      (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD)
 #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
index 2b40cc64de1c40aa748e98b8251f6df7c9a3d46e..c77c891b4022b04f519facffd7882d42b6989e5b 100644 (file)
@@ -3299,6 +3299,18 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
                                render_ecs(&optbuf, target);
                                ADD_STRING(target, "\n");
                                break;
+                       } else if (optcode == DNS_OPT_EXPIRE) {
+                               if (optlen == 4) {
+                                       char buf[sizeof("4294967296")];
+                                       isc_uint32_t secs;
+                                       secs = isc_buffer_getuint32(&optbuf);
+                                       ADD_STRING(target, "; EXPIRE: ");
+                                       snprintf(buf, sizeof(buf), "%u", secs);
+                                       ADD_STRING(target, buf);
+                                       ADD_STRING(target, "\n");
+                                       break;
+                               }
+                               ADD_STRING(target, "; EXPIRE");
                        } else {
                                ADD_STRING(target, "; OPT=");
                                sprintf(buf, "%u", optcode);