Commit 16134801 authored by Mark Andrews's avatar Mark Andrews

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]
parent 801b958a
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.)
......
......@@ -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");
......
......@@ -931,7 +931,8 @@
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>
......@@ -946,6 +947,16 @@
</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>
......
......@@ -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);
}
......
......@@ -130,6 +130,7 @@ struct dig_lookup {
done_as_is,
besteffort,
dnssec,
expire,
#ifdef ISC_PLATFORM_USESIT
sit,
#endif
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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,
......
......@@ -22,5 +22,6 @@
#
rm -f dig.out.ns2
rm -f dig.out.expire
rm -f */named.memstats
rm -f ns2/named_dump.db
; 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
......@@ -41,3 +41,8 @@ zone "flushtest.example" {
type master;
file "flushtest.db";
};
zone "expire-test" {
type master;
file "expire-test.db";
};
......@@ -50,3 +50,8 @@ zone "flushtest.example" {
type forward;
forwarders { 10.53.0.1; };
};
zone "expire-test" {
type slave;
masters { 10.53.0.1; };
};
......@@ -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
......@@ -108,9 +108,10 @@
#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)
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment