max-transfer-time-out 120;\n\
min-refresh-time 300;\n\
min-retry-time 500;\n\
+ min-transfer-rate-in 10240 5;\n\
multi-master no;\n\
notify yes;\n\
notify-delay 5;\n\
}
dns_zone_setoption(mayberaw, DNS_ZONEOPT_MULTIMASTER, multi);
+ obj = NULL;
+ result = named_config_get(maps, "min-transfer-rate-in", &obj);
+ INSIST(result == ISC_R_SUCCESS && obj != NULL);
+ uint32_t traffic_bytes =
+ cfg_obj_asuint32(cfg_tuple_get(obj, "traffic_bytes"));
+ uint32_t time_minutes =
+ cfg_obj_asuint32(cfg_tuple_get(obj, "time_minutes"));
+ if (traffic_bytes == 0) {
+ cfg_obj_log(obj, ISC_LOG_ERROR,
+ "zone '%s': 'min-transfer-rate-in' bytes"
+ "value can not be '0'",
+ zname);
+ CHECK(ISC_R_FAILURE);
+ }
+ /* Max. 28 days (in minutes). */
+ const unsigned int time_minutes_max = 28 * 24 * 60;
+ if (time_minutes < 1 || time_minutes > time_minutes_max) {
+ cfg_obj_log(obj, ISC_LOG_ERROR,
+ "zone '%s': 'min-transfer-rate-in' minutes"
+ "value is out of range (1..%u)",
+ zname, time_minutes_max);
+ CHECK(ISC_R_FAILURE);
+ }
+ dns_zone_setminxfrratein(mayberaw, traffic_bytes,
+ transferinsecs ? time_minutes
+ : time_minutes * 60);
+
obj = NULL;
result = named_config_get(maps, "max-transfer-time-in", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
+ min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
min-ncache-ttl <duration>;
min-refresh-time <integer>;
min-retry-time <integer>;
+ min-transfer-rate-in <integer> <integer>;
minimal-any <boolean>;
minimal-responses ( no-auth | no-auth-recursive | <boolean> );
multi-master <boolean>;
min-ncache-ttl <duration>;
min-refresh-time <integer>;
min-retry-time <integer>;
+ min-transfer-rate-in <integer> <integer>;
minimal-any <boolean>;
minimal-responses ( no-auth | no-auth-recursive | <boolean> );
multi-master <boolean>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
+ min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
max-types-per-name <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
+ min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
transfer-source ( <ipv4_address> | * );
*\li DNS_R_SUCCESS
*/
+void
+dns_zone_setminxfrratein(dns_zone_t *zone, uint32_t bytes, uint32_t seconds);
+/*%<
+ * Set the minumum traffic rate (in bytes per seconds) that a zone transfer in
+ * (AXFR/IXFR) of this zone will use before being aborted.
+ *
+ * Requires:
+ * \li 'zone' to be valid initialised zone.
+ */
+
+uint32_t
+dns_zone_getminxfrratebytesin(dns_zone_t *zone);
+/*%<
+ * Returns the 'bytes' portion of the minimum traffic rate for the transfer in
+ * for this zone.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ */
+
+uint32_t
+dns_zone_getminxfrratesecondsin(dns_zone_t *zone);
+/*%<
+ * Returns the 'seconds' portion of the minimum traffic rate for the transfer in
+ * for this zone.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ */
+
void
dns_zone_setmaxxfrin(dns_zone_t *zone, uint32_t maxxfrin);
/*%<
unsigned int maxrecords; /*%< The maximum number of
* records set for the zone */
+ uint64_t nbytes_saved; /*%< For enforcing the minimum transfer rate */
dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */
isc_buffer_t *lasttsig; /*%< The last TSIG */
isc_loop_t *loop;
+ isc_timer_t *min_rate_timer;
isc_timer_t *max_time_timer;
isc_timer_t *max_idle_timer;
static void
xfrin_idledout(void *);
static void
+xfrin_minratecheck(void *);
+static void
xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg);
static isc_result_t
render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf);
xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum idle time exceeded");
}
+static void
+xfrin_minratecheck(void *arg) {
+ dns_xfrin_t *xfr = arg;
+
+ REQUIRE(VALID_XFRIN(xfr));
+
+ const uint64_t nbytes = atomic_load_relaxed(&xfr->nbytes);
+ const uint64_t min = dns_zone_getminxfrratebytesin(xfr->zone);
+
+ if (nbytes - xfr->nbytes_saved < min) {
+ isc_timer_stop(xfr->min_rate_timer);
+ xfrin_fail(xfr, ISC_R_TIMEDOUT,
+ "minimum transfer rate reached");
+ } else {
+ xfr->nbytes_saved = nbytes;
+ }
+}
+
isc_time_t
dns_xfrin_getstarttime(dns_xfrin_t *xfr) {
REQUIRE(VALID_XFRIN(xfr));
isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0);
isc_timer_start(xfr->max_idle_timer, isc_timertype_once, &interval);
+ /* Set the minimum transfer rate checking timer */
+ if (xfr->min_rate_timer == NULL) {
+ isc_timer_create(dns_zone_getloop(xfr->zone),
+ xfrin_minratecheck, xfr, &xfr->min_rate_timer);
+ }
+ isc_interval_set(&interval, dns_zone_getminxfrratesecondsin(xfr->zone),
+ 0);
+ isc_timer_start(xfr->min_rate_timer, isc_timertype_ticker, &interval);
+
/*
* The connect has to be the last thing that is called before returning,
* as it can end synchronously and destroy the xfr object.
atomic_store_relaxed(&xfr->nbytes, 0);
atomic_store_relaxed(&xfr->start, isc_time_now());
+ xfr->nbytes_saved = 0;
+
msg->id = xfr->id;
if (xfr->tsigctx != NULL) {
dst_context_destroy(&xfr->tsigctx);
isc_timer_stop(xfr->max_idle_timer);
isc_timer_destroy(&xfr->max_idle_timer);
}
+ if (xfr->min_rate_timer != NULL) {
+ isc_timer_stop(xfr->min_rate_timer);
+ isc_timer_destroy(&xfr->min_rate_timer);
+ }
if (xfr->shutdown_result == ISC_R_UNSET) {
xfr->shutdown_result = result;
case XFRST_AXFR_END:
case XFRST_IXFR_END:
/* We are at the end, cancel the timers and IO */
+ isc_timer_stop(xfr->min_rate_timer);
isc_timer_stop(xfr->max_idle_timer);
isc_timer_stop(xfr->max_time_timer);
xfrin_cancelio(xfr);
INSIST(xfr->max_time_timer == NULL);
INSIST(xfr->max_idle_timer == NULL);
+ INSIST(xfr->min_rate_timer == NULL);
isc_loop_detach(&xfr->loop);
dns_request_t *request;
dns_loadctx_t *loadctx;
dns_dumpctx_t *dumpctx;
+ uint32_t minxfrratebytesin;
+ uint32_t minxfrratesecondsin;
uint32_t maxxfrin;
uint32_t maxxfrout;
uint32_t idlein;
return count;
}
+void
+dns_zone_setminxfrratein(dns_zone_t *zone, uint32_t bytes, uint32_t seconds) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->minxfrratebytesin = bytes;
+ zone->minxfrratesecondsin = seconds;
+}
+
+uint32_t
+dns_zone_getminxfrratebytesin(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return zone->minxfrratebytesin;
+}
+
+uint32_t
+dns_zone_getminxfrratesecondsin(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return zone->minxfrratesecondsin;
+}
+
void
dns_zone_setmaxxfrin(dns_zone_t *zone, uint32_t maxxfrin) {
REQUIRE(DNS_ZONE_VALID(zone));
{ NULL, NULL, 0 }
};
+/*
+ * For min-transfer-rate-in.
+ */
+static cfg_tuplefielddef_t min_transfer_rate_fields[] = {
+ { "traffic_bytes", &cfg_type_uint32, 0 },
+ { "time_minutes", &cfg_type_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_min_transfer_rate_in = {
+ "min-transfer-rate-in", cfg_parse_tuple, cfg_print_tuple,
+ cfg_doc_tuple, &cfg_rep_tuple, min_transfer_rate_fields
+};
+
/*%
* Clauses that can be found in a 'zone' statement,
* with defaults in the 'view' or 'options' statement.
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
{ "max-retry-time", &cfg_type_uint32,
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
+ { "min-transfer-rate-in", &cfg_type_min_transfer_rate_in,
+ CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
{ "max-transfer-idle-in", &cfg_type_uint32,
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
{ "max-transfer-idle-out", &cfg_type_uint32,