diff --git a/CHANGES b/CHANGES
index 4b68841dfc..1ce4b71ffb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+3911. [func] Implement EDNS EXPIRE option client side. [RT #35925]
+
3910. [bug] Fix races to free event during shutdown. [RT#36720]
3909. [bug] When computing the number of elements required for a
diff --git a/bin/named/config.c b/bin/named/config.c
index c841e31e09..f7647e76f7 100644
--- a/bin/named/config.c
+++ b/bin/named/config.c
@@ -143,6 +143,7 @@ options {\n\
recursion true;\n\
provide-ixfr true;\n\
request-ixfr true;\n\
+ request-expire true;\n\
fetch-glue no;\n\
rfc2308-type1 no;\n\
additional-from-auth true;\n\
diff --git a/bin/named/server.c b/bin/named/server.c
index 24989cfb52..ecb64b91d5 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -1177,6 +1177,11 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
if (obj != NULL)
CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
+ obj = NULL;
+ (void)cfg_map_get(cpeer, "request-expire", &obj);
+ if (obj != NULL)
+ CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
+
obj = NULL;
(void)cfg_map_get(cpeer, "request-ixfr", &obj);
if (obj != NULL)
diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c
index b3143fa2c1..18db36822f 100644
--- a/bin/named/zoneconf.c
+++ b/bin/named/zoneconf.c
@@ -1256,6 +1256,11 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
ixfrdiff);
+ obj = NULL;
+ result = ns_config_get(maps, "request-expire", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_zone_setrequestexpire(zone, cfg_obj_asboolean(obj));
+
obj = NULL;
result = ns_config_get(maps, "request-ixfr", &obj);
INSIST(result == ISC_R_SUCCESS);
diff --git a/bin/tests/system/xfer/clean.sh b/bin/tests/system/xfer/clean.sh
index 48aa159137..3c9c1f7662 100644
--- a/bin/tests/system/xfer/clean.sh
+++ b/bin/tests/system/xfer/clean.sh
@@ -26,6 +26,7 @@ rm -f dig.out.ns5 dig.out.ns6 dig.out.ns7
rm -f dig.out.soa.ns3
rm -f axfr.out
rm -f ns1/slave.db ns2/slave.db
+rm -f ns1/edns-expire.db
rm -f ns2/example.db ns2/tsigzone.db ns2/example.db.jnl
rm -f ns3/example.bk ns3/tsigzone.bk ns3/example.bk.jnl
rm -f ns3/master.bk ns3/master.bk.jnl
diff --git a/bin/tests/system/xfer/ns1/named.conf b/bin/tests/system/xfer/ns1/named.conf
index 07dad85d9b..7d20f12d6e 100644
--- a/bin/tests/system/xfer/ns1/named.conf
+++ b/bin/tests/system/xfer/ns1/named.conf
@@ -44,3 +44,8 @@ zone "slave" {
type master;
file "slave.db";
};
+
+zone "edns-expire" {
+ type master;
+ file "edns-expire.db";
+};
diff --git a/bin/tests/system/xfer/ns6/named.conf b/bin/tests/system/xfer/ns6/named.conf
index c9421b1f65..6cccbe4bcd 100644
--- a/bin/tests/system/xfer/ns6/named.conf
+++ b/bin/tests/system/xfer/ns6/named.conf
@@ -19,7 +19,7 @@
include "../../common/rndc.key";
controls {
- inet 10.53.0.6 port 9953 allow { any; } keys { rndc_key; };
+ inet 10.53.0.6 port 9953 allow { any; } keys { rndc_key; };
};
options {
@@ -52,3 +52,9 @@ zone "slave" {
masters { 10.53.0.1; };
file "slave.bk";
};
+
+zone "edns-expire" {
+ type slave;
+ masters { 10.53.0.1; };
+ file "edns-expire.bk";
+};
diff --git a/bin/tests/system/xfer/ns7/named.conf b/bin/tests/system/xfer/ns7/named.conf
index dcacb08e64..e8f1645b1e 100644
--- a/bin/tests/system/xfer/ns7/named.conf
+++ b/bin/tests/system/xfer/ns7/named.conf
@@ -51,3 +51,9 @@ zone "slave" {
masters { 10.53.0.1; };
file "slave.bk";
};
+
+zone "edns-expire" {
+ type slave;
+ masters { 10.53.0.6; };
+ file "edns-expire.bk";
+};
diff --git a/bin/tests/system/xfer/setup.sh b/bin/tests/system/xfer/setup.sh
index 56ca9018ec..7df04dd4e4 100644
--- a/bin/tests/system/xfer/setup.sh
+++ b/bin/tests/system/xfer/setup.sh
@@ -21,6 +21,7 @@ SYSTEMTESTTOP=..
$SHELL clean.sh
$SHELL ../genzone.sh 1 6 7 >ns1/slave.db
+$SHELL ../genzone.sh 1 6 7 >ns1/edns-expire.db
$SHELL ../genzone.sh 2 3 >ns2/example.db
$SHELL ../genzone.sh 2 3 >ns2/tsigzone.db
$SHELL ../genzone.sh 6 3 >ns6/master.db
diff --git a/bin/tests/system/xfer/tests.sh b/bin/tests/system/xfer/tests.sh
index 2afaa0f20a..232c351462 100644
--- a/bin/tests/system/xfer/tests.sh
+++ b/bin/tests/system/xfer/tests.sh
@@ -331,5 +331,17 @@ $DIGCMD nil. TXT | grep 'incorrect key AXFR' >/dev/null && {
status=1
}
+echo "I:check that we ask for and get a EDNS EXPIRE response"
+# force a refresh query
+$RNDC -s 10.53.0.7 -p 9953 -c ../common/rndc.conf refresh edns-expire 2>&1 | sed 's/^/I:ns7 /'
+sleep 10
+
+# there may be multiple log entries so get the last one.
+expire=`awk '/edns-expire\/IN: got EDNS EXPIRE of/ { x=$9 } END { print x }' ns7/named.run`
+test ${expire:-0} -gt 0 -a ${expire:-0} -lt 1814400 || {
+ echo "I:failed (expire=${expire:-0})"
+ status=1
+}
+
echo "I:exit status: $status"
exit $status
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
index bf99f22cc5..d2acb8e318 100644
--- a/doc/arm/Bv9ARM-book.xml
+++ b/doc/arm/Bv9ARM-book.xml
@@ -4934,6 +4934,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
use-ixfr yes_or_no ;
provide-ixfr yes_or_no;
request-ixfr yes_or_no;
+ request-expire yes_or_no;
treat-cr-as-space yes_or_no ;
min-refresh-time number ;
max-refresh-time number ;
@@ -6476,6 +6477,17 @@ options {
+
+ request-expire
+
+
+ See the description of
+ request-expire in
+ .
+
+
+
+
treat-cr-as-space
@@ -10390,6 +10402,7 @@ rate-limit {
bogus yes_or_no ;
provide-ixfr yes_or_no ;
request-ixfr yes_or_no ;
+ request-expire yes_or_no ;
request-nsid yes_or_no ;
request-sit yes_or_no ;
edns yes_or_no ;
@@ -10494,6 +10507,12 @@ rate-limit {
is buggy and crashes or corrupts data when IXFR is used.
+
+ The request-expire clause determines
+ whether the local server, acting as a slave, will request
+ the EDNS EXPIRE value.
+
+
The edns clause determines whether
the local server will attempt to use EDNS when communicating
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
index 0e81401232..a8d5e00aa6 100644
--- a/lib/bind9/check.c
+++ b/lib/bind9/check.c
@@ -1513,6 +1513,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
{ "notify-source", MASTERZONE | SLAVEZONE },
{ "notify-source-v6", MASTERZONE | SLAVEZONE },
{ "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
+ { "request-expire", SLAVEZONE | REDIRECTZONE },
{ "request-ixfr", SLAVEZONE | REDIRECTZONE },
{ "server-addresses", STATICSTUBZONE },
{ "server-names", STATICSTUBZONE },
@@ -1534,8 +1535,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
static optionstable dialups[] = {
{ "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
{ "notify-passive", SLAVEZONE | STREDIRECTZONE },
- { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
+ { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
};
znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h
index 4374db4570..52ea86ef43 100644
--- a/lib/dns/include/dns/peer.h
+++ b/lib/dns/include/dns/peer.h
@@ -75,6 +75,7 @@ struct dns_peer {
isc_boolean_t support_edns;
isc_boolean_t request_nsid;
isc_boolean_t request_sit;
+ isc_boolean_t request_expire;
dns_name_t *key;
isc_sockaddr_t *transfer_source;
isc_dscp_t transfer_dscp;
@@ -166,6 +167,12 @@ dns_peer_setrequestsit(dns_peer_t *peer, isc_boolean_t newval);
isc_result_t
dns_peer_getrequestsit(dns_peer_t *peer, isc_boolean_t *retval);
+isc_result_t
+dns_peer_setrequestexpire(dns_peer_t *peer, isc_boolean_t newval);
+
+isc_result_t
+dns_peer_getrequestexpire(dns_peer_t *peer, isc_boolean_t *retval);
+
isc_result_t
dns_peer_setsupportedns(dns_peer_t *peer, isc_boolean_t newval);
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index 5a103636ea..3c5e2fd78b 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -2184,6 +2184,26 @@ dns_zone_setrefreshkeyinterval(dns_zone_t *zone, isc_uint32_t interval);
* \li 'zone' to be valid.
*/
+isc_boolean_t
+dns_zone_getrequestexpire(dns_zone_t *zone);
+/*%
+ * Returns the true/false value of the request-expire option in the zone.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
+void
+dns_zone_setrequestexpire(dns_zone_t *zone, isc_boolean_t flag);
+/*%
+ * Sets the request-expire option for the zone. Either true or false. The
+ * default value is determined by the setting of this option in the view.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
+
isc_boolean_t
dns_zone_getrequestixfr(dns_zone_t *zone);
/*%
diff --git a/lib/dns/peer.c b/lib/dns/peer.c
index 40520d7614..4f55f0cdbd 100644
--- a/lib/dns/peer.c
+++ b/lib/dns/peer.c
@@ -47,6 +47,7 @@
#define NOTIFY_DSCP_BIT 10
#define TRANSFER_DSCP_BIT 11
#define QUERY_DSCP_BIT 12
+#define REQUEST_EXPIRE_BIT 13
static void
peerlist_delete(dns_peerlist_t **list);
@@ -477,6 +478,32 @@ dns_peer_getrequestsit(dns_peer_t *peer, isc_boolean_t *retval) {
return (ISC_R_NOTFOUND);
}
+isc_result_t
+dns_peer_setrequestexpire(dns_peer_t *peer, isc_boolean_t newval) {
+ isc_boolean_t existed;
+
+ REQUIRE(DNS_PEER_VALID(peer));
+
+ existed = DNS_BIT_CHECK(REQUEST_EXPIRE_BIT, &peer->bitflags);
+
+ peer->request_expire = newval;
+ DNS_BIT_SET(REQUEST_EXPIRE_BIT, &peer->bitflags);
+
+ return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_peer_getrequestexpire(dns_peer_t *peer, isc_boolean_t *retval) {
+ REQUIRE(DNS_PEER_VALID(peer));
+ REQUIRE(retval != NULL);
+
+ if (DNS_BIT_CHECK(REQUEST_EXPIRE_BIT, &peer->bitflags)) {
+ *retval = peer->request_expire;
+ return (ISC_R_SUCCESS);
+ } else
+ return (ISC_R_NOTFOUND);
+}
+
isc_result_t
dns_peer_settransfers(dns_peer_t *peer, isc_uint32_t newval) {
isc_boolean_t existed;
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 43f8b89a15..b1c0f544e8 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -392,6 +392,11 @@ struct dns_zone {
*/
isc_boolean_t requestixfr;
+ /*%
+ * whether EDNS EXPIRE is requested
+ */
+ isc_boolean_t requestexpire;
+
/*%
* Outstanding forwarded UPDATE requests.
*/
@@ -999,6 +1004,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->secure = NULL;
zone->sourceserial = 0;
zone->sourceserialset = ISC_FALSE;
+ zone->requestixfr = ISC_TRUE;
+ zone->requestexpire = ISC_TRUE;
zone->magic = ZONE_MAGIC;
@@ -10934,6 +10941,90 @@ stub_callback(isc_task_t *task, isc_event_t *event) {
return;
}
+/*
+ * Get the EDNS EXPIRE option from the response and if it exists trim
+ * expire to be not more than it.
+ */
+static void
+get_edns_expire(dns_zone_t * zone, dns_message_t *message,
+ isc_uint32_t *expirep)
+{
+ isc_result_t result;
+ isc_uint32_t expire;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_buffer_t optbuf;
+ isc_uint16_t optcode;
+ isc_uint16_t optlen;
+
+ REQUIRE(expirep != NULL);
+ REQUIRE(message != NULL);
+
+ if (message->opt == NULL)
+ return;
+
+ result = dns_rdataset_first(message->opt);
+ if (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(message->opt, &rdata);
+ isc_buffer_init(&optbuf, rdata.data, rdata.length);
+ isc_buffer_add(&optbuf, rdata.length);
+ while (isc_buffer_remaininglength(&optbuf) >= 4) {
+ optcode = isc_buffer_getuint16(&optbuf);
+ optlen = isc_buffer_getuint16(&optbuf);
+ /*
+ * A EDNS EXPIRE response has a length of 4.
+ */
+ if (optcode != DNS_OPT_EXPIRE || optlen != 4) {
+ isc_buffer_forward(&optbuf, optlen);
+ continue;
+ }
+ expire = isc_buffer_getuint32(&optbuf);
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "got EDNS EXPIRE of %u\n", expire);
+ /*
+ * Trim *expirep?
+ */
+ if (expire < *expirep)
+ *expirep = expire;
+ break;
+ }
+ }
+}
+
+/*
+ * Set the file modification time zone->expire seconds before expiretime.
+ */
+static void
+setmodtime(dns_zone_t *zone, isc_time_t *expiretime) {
+ isc_result_t result;
+ isc_time_t when;
+ isc_interval_t i;
+
+ isc_interval_set(&i, zone->expire, 0);
+ result = isc_time_subtract(expiretime, &i, &when);
+ if (result != ISC_R_SUCCESS)
+ return;
+
+ result = ISC_R_FAILURE;
+ if (zone->journal != NULL)
+ result = isc_file_settime(zone->journal, &when);
+ if (result == ISC_R_SUCCESS &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP))
+ result = isc_file_settime(zone->masterfile, &when);
+ else if (result != ISC_R_SUCCESS)
+ result = isc_file_settime(zone->masterfile, &when);
+
+ /*
+ * Someone removed the file from underneath us!
+ */
+ if (result == ISC_R_FILENOTFOUND) {
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ } else if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR, "refresh: could not set "
+ "file modification time of '%s': %s",
+ zone->masterfile, dns_result_totext(result));
+}
+
/*
* An SOA query has finished (successfully or not).
*/
@@ -11054,6 +11145,15 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
goto same_master;
}
+ if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) &&
+ msg->rcode == dns_rcode_badvers) {
+ dns_zone_log(zone, ISC_LOG_DEBUG(1),
+ "refresh: rcode (%.*s) retrying without "
+ "EDNS EXPIRE OPTION master %s (source %s)",
+ (int)rb.used, rcode, master, source);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS);
+ goto same_master;
+ }
dns_zone_log(zone, ISC_LOG_INFO,
"refresh: unexpected rcode (%.*s) from "
"master %s (source %s)", (int)rb.used, rcode,
@@ -11219,30 +11319,26 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
if (msg != NULL)
dns_message_destroy(&msg);
} else if (isc_serial_eq(soa.serial, oldserial)) {
- if (zone->masterfile != NULL) {
- result = ISC_R_FAILURE;
- if (zone->journal != NULL)
- result = isc_file_settime(zone->journal, &now);
- if (result == ISC_R_SUCCESS &&
- !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
- !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
- result = isc_file_settime(zone->masterfile,
- &now);
- } else if (result != ISC_R_SUCCESS)
- result = isc_file_settime(zone->masterfile,
- &now);
- /* Someone removed the file from underneath us! */
- if (result == ISC_R_FILENOTFOUND) {
- zone_needdump(zone, DNS_DUMP_DELAY);
- } else if (result != ISC_R_SUCCESS)
- dns_zone_log(zone, ISC_LOG_ERROR,
- "refresh: could not set file "
- "modification time of '%s': %s",
- zone->masterfile,
- dns_result_totext(result));
+ isc_time_t expiretime;
+ isc_uint32_t expire;
+
+ /*
+ * Compute the new expire time based on this response.
+ */
+ expire = zone->expire;
+ get_edns_expire(zone, msg, &expire);
+ DNS_ZONE_TIME_ADD(&now, expire, &expiretime);
+
+ /*
+ * Has the expire time improved?
+ */
+ if (isc_time_compare(&expiretime, &zone->expiretime) > 0) {
+ zone->expiretime = expiretime;
+ if (zone->masterfile != NULL)
+ setmodtime(zone, &expiretime);
}
+
DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
- DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime);
zone->mastersok[zone->curmaster] = ISC_TRUE;
goto next_master;
} else {
@@ -11416,7 +11512,9 @@ create_query(dns_zone_t *zone, dns_rdatatype_t rdtype,
}
static isc_result_t
-add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid) {
+add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid,
+ isc_boolean_t reqexpire)
+{
isc_result_t result;
dns_rdataset_t *rdataset = NULL;
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
@@ -11430,6 +11528,13 @@ add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid) {
ednsopts[count].value = NULL;
count++;
}
+ if (reqexpire) {
+ INSIST(count < DNS_EDNSOPTIONS);
+ ednsopts[count].code = DNS_OPT_EXPIRE;
+ ednsopts[count].length = 0;
+ ednsopts[count].value = NULL;
+ count++;
+ }
result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0,
ednsopts, count);
if (result != ISC_R_SUCCESS)
@@ -11450,7 +11555,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
isc_uint32_t options;
isc_boolean_t cancel = ISC_TRUE;
int timeout;
- isc_boolean_t have_xfrsource, have_xfrdscp, reqnsid;
+ isc_boolean_t have_xfrsource, have_xfrdscp, reqnsid, reqexpire;
isc_uint16_t udpsize = SEND_BUFFER_SIZE;
isc_dscp_t dscp = -1;
@@ -11513,6 +11618,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
have_xfrsource = have_xfrdscp = ISC_FALSE;
reqnsid = zone->view->requestnsid;
+ reqexpire = zone->requestexpire;
if (zone->view->peers != NULL) {
dns_peer_t *peer = NULL;
isc_boolean_t edns;
@@ -11534,6 +11640,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
dns_resolver_getudpsize(zone->view->resolver);
(void)dns_peer_getudpsize(peer, &udpsize);
(void)dns_peer_getrequestnsid(peer, &reqnsid);
+ (void)dns_peer_getrequestexpire(peer, &reqexpire);
}
}
@@ -11575,7 +11682,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
DNS_REQUESTOPT_TCP : 0;
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
- result = add_opt(message, udpsize, reqnsid);
+ result = add_opt(message, udpsize, reqnsid, reqexpire);
if (result != ISC_R_SUCCESS)
zone_debuglog(zone, me, 1,
"unable to add opt record: %s",
@@ -11790,7 +11897,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
}
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
- result = add_opt(message, udpsize, reqnsid);
+ result = add_opt(message, udpsize, reqnsid, ISC_FALSE);
if (result != ISC_R_SUCCESS)
zone_debuglog(zone, me, 1,
"unable to add opt record: %s",
@@ -17308,6 +17415,18 @@ dns_zone_getrequestixfr(dns_zone_t *zone) {
return (zone->requestixfr);
}
+void
+dns_zone_setrequestexpire(dns_zone_t *zone, isc_boolean_t flag) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->requestexpire = flag;
+}
+
+isc_boolean_t
+dns_zone_getrequestexpire(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (zone->requestexpire);
+}
+
void
dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method) {
REQUIRE(DNS_ZONE_VALID(zone));
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index d2f8dc3e9e..02323781ec 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -1675,6 +1675,7 @@ zone_clauses[] = {
{ "notify-to-soa", &cfg_type_boolean, 0 },
{ "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
{ "serial-update-method", &cfg_type_updatemethod, 0 },
+ { "request-expire", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
{ "sig-signing-nodes", &cfg_type_uint32, 0 },
{ "sig-signing-signatures", &cfg_type_uint32, 0 },
@@ -1851,6 +1852,7 @@ server_clauses[] = {
{ "provide-ixfr", &cfg_type_boolean, 0 },
{ "query-source", &cfg_type_querysource4, 0 },
{ "query-source-v6", &cfg_type_querysource6, 0 },
+ { "request-expire", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
{ "request-nsid", &cfg_type_boolean, 0 },
#ifdef ISC_PLATFORM_USESIT