+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.)
" +[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"
}
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");
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>
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;
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;
}
#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);
}
done_as_is,
besteffort,
dnssec,
+ expire,
#ifdef ISC_PLATFORM_USESIT
sit,
#endif
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) {
}
#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.
*/
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
int count = 0;
unsigned int flags;
+ unsigned char expire[4];
REQUIRE(client->opt == NULL); /* XXXRTH free old. */
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);
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;
}
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);
}
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;
#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;
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,
#
rm -f dig.out.ns2
+rm -f dig.out.expire
rm -f */named.memstats
rm -f ns2/named_dump.db
--- /dev/null
+; Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 3600
+@ IN SOA hostmaster.ns ns (
+ 2011072900
+ 600
+ 600
+ 1200
+ 3600
+ )
+ NS ns
+ns IN A 10.53.0.1
type master;
file "flushtest.db";
};
+
+zone "expire-test" {
+ type master;
+ file "expire-test.db";
+};
type forward;
forwarders { 10.53.0.1; };
};
+
+zone "expire-test" {
+ type slave;
+ masters { 10.53.0.1; };
+};
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
#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)
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);