recursion true;\n\
request-expire true;\n\
request-ixfr true;\n\
+ request-ixfr-max-diffs 0;\n\
require-server-cookie no;\n\
root-key-sentinel yes;\n\
servfail-ttl 1;\n\
CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
}
+ obj = NULL;
+ (void)cfg_map_get(cpeer, "request-ixfr-max-diffs", &obj);
+ if (obj != NULL) {
+ CHECK(dns_peer_setrequestixfrmaxdiffs(peer,
+ cfg_obj_asuint32(obj)));
+ }
+
obj = NULL;
(void)cfg_map_get(cpeer, "request-nsid", &obj);
if (obj != NULL) {
INSIST(result == ISC_R_SUCCESS);
dns_zone_setrequestixfr(zone, cfg_obj_asboolean(obj));
+ obj = NULL;
+ result = named_config_get(maps, "request-ixfr-max-diffs", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_zone_setrequestixfrmaxdiffs(zone, cfg_obj_asuint32(obj));
+
obj = NULL;
checknames(ztype, maps, &obj);
INSIST(obj != NULL);
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * request-ixfr clause is not allowed in zone of type primary.
+ */
+
+zone dummy {
+ type primary;
+ request-ixfr-max-diffs 100;
+ file "xxxx";
+};
query-source 0.0.0.0;
request-expire no;
request-ixfr no;
+ request-ixfr-max-diffs 0;
request-nsid no;
require-cookie no;
send-cookie no;
query-source-v6 ::;
request-expire no;
request-ixfr no;
+ request-ixfr-max-diffs 0;
request-nsid no;
require-cookie no;
send-cookie no;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
+ request-ixfr-max-diffs <integer>;
transfer-source ( <ipv4_address> | * );
transfer-source-v6 ( <ipv6_address> | * );
try-tcp-refresh <boolean>;
recursive-clients <integer>;
request-expire <boolean>;
request-ixfr <boolean>;
+ request-ixfr-max-diffs <integer>;
request-nsid <boolean>;
require-server-cookie <boolean>;
resolver-query-timeout <integer>;
query-source-v6 [ address ] ( <ipv6_address> | * );
request-expire <boolean>;
request-ixfr <boolean>;
+ request-ixfr-max-diffs <integer>;
request-nsid <boolean>;
require-cookie <boolean>;
send-cookie <boolean>;
recursion <boolean>;
request-expire <boolean>;
request-ixfr <boolean>;
+ request-ixfr-max-diffs <integer>;
request-nsid <boolean>;
require-server-cookie <boolean>;
resolver-query-timeout <integer>;
query-source-v6 [ address ] ( <ipv6_address> | * );
request-expire <boolean>;
request-ixfr <boolean>;
+ request-ixfr-max-diffs <integer>;
request-nsid <boolean>;
require-cookie <boolean>;
send-cookie <boolean>;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
+ request-ixfr-max-diffs <integer>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
isc_result_t
dns_peer_getrequestixfr(dns_peer_t *peer, bool *retval);
+isc_result_t
+dns_peer_setrequestixfrmaxdiffs(dns_peer_t *peer, uint32_t newval);
+
+isc_result_t
+dns_peer_getrequestixfrmaxdiffs(dns_peer_t *peer, uint32_t *retval);
+
isc_result_t
dns_peer_setprovideixfr(dns_peer_t *peer, bool newval);
isc_result_t
dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
- const isc_sockaddr_t *primaryaddr,
+ uint32_t ixfr_maxdiffs, const isc_sockaddr_t *primaryaddr,
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
dns_transport_type_t soa_transport_type,
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
* \li 'zone' to be valid.
*/
+bool
+dns_zone_getrequestixfrmaxdiffs(dns_zone_t *zone);
+/*%
+ * Returns the value of the request-ixfr-max-diffs option in the zone.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
+void
+dns_zone_setrequestixfrmaxdiffs(dns_zone_t *zone, uint32_t maxmsgs);
+/*%
+ * Sets the request-ixfr-max-diffs option for the zone. 0 means unlimited. The
+ * default value is determined by the setting of this option in the view.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
uint32_t
dns_zone_getixfrratio(dns_zone_t *zone);
/*%
/*! \file */
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <isc/mem.h>
bool bogus;
dns_transfer_format_t transfer_format;
uint32_t transfers;
+ uint32_t request_ixfr_maxdiffs;
bool support_ixfr;
bool provide_ixfr;
bool request_ixfr;
/*%
* Bit positions in the dns_peer_t structure flags field
*/
-#define BOGUS_BIT 0
-#define SERVER_TRANSFER_FORMAT_BIT 1
-#define TRANSFERS_BIT 2
-#define PROVIDE_IXFR_BIT 3
-#define REQUEST_IXFR_BIT 4
-#define SUPPORT_EDNS_BIT 5
-#define SERVER_UDPSIZE_BIT 6
-#define SERVER_MAXUDP_BIT 7
-#define REQUEST_NSID_BIT 8
-#define SEND_COOKIE_BIT 9
-#define REQUEST_EXPIRE_BIT 10
-#define EDNS_VERSION_BIT 11
-#define FORCE_TCP_BIT 12
-#define SERVER_PADDING_BIT 13
-#define REQUEST_TCP_KEEPALIVE_BIT 14
-#define REQUIRE_COOKIE_BIT 15
+enum {
+ BOGUS_BIT = 0,
+ SERVER_TRANSFER_FORMAT_BIT,
+ TRANSFERS_BIT,
+ PROVIDE_IXFR_BIT,
+ REQUEST_IXFR_BIT,
+ REQUEST_IXFRMAXDIFFS_BIT,
+ SUPPORT_EDNS_BIT,
+ SERVER_UDPSIZE_BIT,
+ SERVER_MAXUDP_BIT,
+ REQUEST_NSID_BIT,
+ SEND_COOKIE_BIT,
+ REQUEST_EXPIRE_BIT,
+ EDNS_VERSION_BIT,
+ FORCE_TCP_BIT,
+ SERVER_PADDING_BIT,
+ REQUEST_TCP_KEEPALIVE_BIT,
+ REQUIRE_COOKIE_BIT,
+ DNS_PEER_FLAGS_COUNT
+};
+
+STATIC_ASSERT(DNS_PEER_FLAGS_COUNT <= CHAR_BIT * sizeof(uint32_t),
+ "dns_peer_t structure flags fields are too many for uint32_t");
static void
peerlist_delete(dns_peerlist_t **list);
ACCESS_OPTION(provideixfr, PROVIDE_IXFR_BIT, bool, provide_ixfr)
ACCESS_OPTION(requestexpire, REQUEST_EXPIRE_BIT, bool, request_expire)
ACCESS_OPTION(requestixfr, REQUEST_IXFR_BIT, bool, request_ixfr)
+ACCESS_OPTION(requestixfrmaxdiffs, REQUEST_IXFRMAXDIFFS_BIT, uint32_t,
+ request_ixfr_maxdiffs)
ACCESS_OPTION(requestnsid, REQUEST_NSID_BIT, bool, request_nsid)
ACCESS_OPTION(requirecookie, REQUIRE_COOKIE_BIT, bool, require_cookie)
ACCESS_OPTION(sendcookie, SEND_COOKIE_BIT, bool, send_cookie)
dns_rdatacallbacks_t axfr;
struct {
+ uint32_t diffs;
+ uint32_t maxdiffs;
uint32_t request_serial;
uint32_t current_serial;
dns_journal_t *journal;
static void
xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
dns_name_t *zonename, dns_rdataclass_t rdclass,
- dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr,
+ dns_rdatatype_t reqtype, uint32_t ixfr_maxdiffs,
+ const isc_sockaddr_t *primaryaddr,
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
dns_transport_type_t soa_transport_type,
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata, &tuple);
dns_diff_append(&xfr->diff, &tuple);
+ xfr->ixfr.diffs++;
failure:
return (result);
}
isc_result_t
dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
- const isc_sockaddr_t *primaryaddr,
+ uint32_t ixfr_maxdiffs, const isc_sockaddr_t *primaryaddr,
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
dns_transport_type_t soa_transport_type,
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
}
xfrin_create(mctx, zone, db, loop, zonename, dns_zone_getclass(zone),
- xfrtype, primaryaddr, sourceaddr, tsigkey,
+ xfrtype, ixfr_maxdiffs, primaryaddr, sourceaddr, tsigkey,
soa_transport_type, transport, tlsctx_cache, &xfr);
if (db != NULL) {
dns_diff_clear(&xfr->diff);
+ xfr->ixfr.diffs = 0;
+
if (xfr->ixfr.journal != NULL) {
dns_journal_destroy(&xfr->ixfr.journal);
}
static void
xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
dns_name_t *zonename, dns_rdataclass_t rdclass,
- dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr,
+ dns_rdatatype_t reqtype, uint32_t ixfr_maxdiffs,
+ const isc_sockaddr_t *primaryaddr,
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
dns_transport_type_t soa_transport_type,
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
.shutdown_result = ISC_R_UNSET,
.rdclass = rdclass,
.reqtype = reqtype,
+ .ixfr.maxdiffs = ixfr_maxdiffs,
.maxrecords = dns_zone_getmaxrecords(zone),
.primaryaddr = *primaryaddr,
.sourceaddr = *sourceaddr,
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdataset_current(rds, &rdata);
CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
+
+ /*
+ * Did we hit the maximum ixfr diffs limit?
+ */
+ if (xfr->reqtype == dns_rdatatype_ixfr &&
+ xfr->ixfr.maxdiffs != 0 &&
+ xfr->ixfr.diffs >= xfr->ixfr.maxdiffs)
+ {
+ xfrin_log(xfr, ISC_LOG_DEBUG(3),
+ "too many diffs, "
+ "retrying with AXFR");
+ goto try_axfr;
+ }
}
}
}
* whether ixfr is requested
*/
bool requestixfr;
+ uint32_t requestixfr_maxdiffs;
uint32_t ixfr_ratio;
/*%
char primary[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
dns_rdatatype_t xfrtype;
+ uint32_t ixfr_maxdiffs = 0;
isc_netaddr_t primaryip;
isc_sockaddr_t primaryaddr;
isc_sockaddr_t sourceaddr;
UNLOCK_ZONE(zone);
} else {
bool use_ixfr = true;
+
if (peer != NULL) {
result = dns_peer_getrequestixfr(peer, &use_ixfr);
}
if (peer == NULL || result != ISC_R_SUCCESS) {
use_ixfr = zone->requestixfr;
}
+ if (peer != NULL) {
+ result = dns_peer_getrequestixfrmaxdiffs(
+ peer, &ixfr_maxdiffs);
+ }
+ if (peer == NULL || result != ISC_R_SUCCESS) {
+ ixfr_maxdiffs = zone->requestixfr_maxdiffs;
+ }
if (!use_ixfr) {
dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN,
ISC_LOG_DEBUG(1),
zmgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache);
- result = dns_xfrin_create(zone, xfrtype, &primaryaddr, &sourceaddr,
- zone->tsigkey, soa_transport_type,
- zone->transport, zmgr_tlsctx_cache,
- zone->mctx, zone_xfrdone, &zone->xfr);
+ result = dns_xfrin_create(
+ zone, xfrtype, ixfr_maxdiffs, &primaryaddr, &sourceaddr,
+ zone->tsigkey, soa_transport_type, zone->transport,
+ zmgr_tlsctx_cache, zone->mctx, zone_xfrdone, &zone->xfr);
isc_tlsctx_cache_detach(&zmgr_tlsctx_cache);
return (zone->requestixfr);
}
+void
+dns_zone_setrequestixfrmaxdiffs(dns_zone_t *zone, uint32_t maxdiffs) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->requestixfr_maxdiffs = maxdiffs;
+}
+
+bool
+dns_zone_getrequestixfrmaxdiffs(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (zone->requestixfr_maxdiffs);
+}
+
void
dns_zone_setixfrratio(dns_zone_t *zone, uint32_t ratio) {
REQUIRE(DNS_ZONE_VALID(zone));
{ "tcp-only", dns_peer_setforcetcp },
};
+static struct {
+ const char *name;
+ isc_result_t (*set)(dns_peer_t *peer, uint32_t newval);
+} uint32s[] = {
+ { "request-ixfr-max-diffs", dns_peer_setrequestixfrmaxdiffs },
+};
+
static isc_result_t
check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
isc_symtab_t *symtab, isc_mem_t *mctx) {
}
}
}
+ for (i = 0; i < ARRAY_SIZE(uint32s); i++) {
+ const cfg_obj_t *opt = NULL;
+ cfg_map_get(v1, uint32s[i].name, &opt);
+ if (opt != NULL) {
+ tresult = (uint32s[i].set)(
+ peer, cfg_obj_asuint32(opt));
+ if (tresult != ISC_R_SUCCESS) {
+ cfg_obj_log(opt, ISC_LOG_ERROR,
+ "setting server option "
+ "'%s' failed: %s",
+ uint32s[i].name,
+ isc_result_totext(tresult));
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
dns_peer_detach(&peer);
}
return (result);
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
{ "request-ixfr", &cfg_type_boolean,
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
+ { "request-ixfr-max-diffs", &cfg_type_uint32,
+ CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
{ "serial-update-method", &cfg_type_updatemethod, CFG_ZONE_PRIMARY },
{ "sig-signing-nodes", &cfg_type_uint32,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
{ "query-source-v6", &cfg_type_querysource6, 0 },
{ "request-expire", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
+ { "request-ixfr-max-diffs", &cfg_type_uint32, 0 },
{ "request-nsid", &cfg_type_boolean, 0 },
{ "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT },
{ "require-cookie", &cfg_type_boolean, 0 },