Implement maximum global and idle time for incoming XFR

After the dns_xfrin was changed to use network manager, the maximum
global (max-transfer-time-in) and idle (max-transfer-idle-in) times for
incoming transfers were turned inoperational because of missing
implementation.

Restore this functionality by implementing the timers for the incoming
transfers.

(cherry picked from commit d2377f8e04)
This commit is contained in:
Ondřej Surý 2023-04-05 22:35:00 +02:00
parent cf6a8987b3
commit fa2cb06c75
No known key found for this signature in database
GPG key ID: 2820F37E873DEA41
5 changed files with 99 additions and 2 deletions

View file

@ -3450,6 +3450,12 @@ options apply to zone transfers.
terminated. The default is 60 minutes (1 hour). The maximum value
is 28 days (40320 minutes).
.. note:: The inbound zone transfers are also affected by
``tcp-idle-timeout``, the ``max-transfer-idle-in`` will close the
inbound zone transfer if there was no complete AXFR or no complete
IXFR chunk. The ``tcp-idle-timeout`` will close the connection if
there's no progress on the TCP level.
.. namedconf:statement:: max-transfer-time-out
:tags: transfer
:short: Specifies the number of minutes after which outbound zone transfers are terminated.

View file

@ -27,6 +27,7 @@
***/
#include <isc/lang.h>
#include <isc/refcount.h>
#include <isc/tls.h>
#include <dns/transport.h>

View file

@ -1769,6 +1769,12 @@ dns_zonemgr_gettaskmgr(dns_zonemgr_t *zmgr);
* Get the tasmkgr object attached to 'zmgr'.
*/
isc_timermgr_t *
dns_zonemgr_gettimermgr(dns_zonemgr_t *zmgr);
/*%
* Get the timermgr object attached to 'zmgr'.
*/
void
dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value);
/*%<

View file

@ -22,6 +22,8 @@
#include <isc/random.h>
#include <isc/result.h>
#include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <dns/callbacks.h>
@ -185,6 +187,9 @@ struct dns_xfrin_ctx {
unsigned char *firstsoa_data;
isc_tlsctx_cache_t *tlsctx_cache;
isc_timer_t *max_time_timer;
isc_timer_t *max_idle_timer;
};
#define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
@ -247,6 +252,10 @@ xfrin_recv_done(isc_nmhandle_t *handle, isc_result_t result,
static void
xfrin_destroy(dns_xfrin_ctx_t *xfr);
static void
xfrin_timedout(struct isc_task *, struct isc_event *);
static void
xfrin_idledout(struct isc_task *, struct isc_event *);
static void
xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg);
static isc_result_t
@ -758,6 +767,28 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
static void
xfrin_cancelio(dns_xfrin_ctx_t *xfr);
static void
xfrin_timedout(struct isc_task *task, struct isc_event *event) {
UNUSED(task);
dns_xfrin_ctx_t *xfr = event->ev_arg;
REQUIRE(VALID_XFRIN(xfr));
xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum transfer time exceeded");
isc_event_free(&event);
}
static void
xfrin_idledout(struct isc_task *task, struct isc_event *event) {
UNUSED(task);
dns_xfrin_ctx_t *xfr = event->ev_arg;
REQUIRE(VALID_XFRIN(xfr));
xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum idle time exceeded");
isc_event_free(&event);
}
void
dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
REQUIRE(VALID_XFRIN(xfr));
@ -833,6 +864,11 @@ xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
if (atomic_compare_exchange_strong(&xfr->shuttingdown, &(bool){ false },
true))
{
(void)isc_timer_reset(xfr->max_time_timer,
isc_timertype_inactive, NULL, NULL, true);
(void)isc_timer_reset(xfr->max_idle_timer,
isc_timertype_inactive, NULL, NULL, true);
if (result != DNS_R_UPTODATE && result != DNS_R_TOOMANYRECORDS)
{
xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", msg,
@ -866,6 +902,9 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
dns_xfrin_ctx_t **xfrp) {
dns_xfrin_ctx_t *xfr = NULL;
dns_zonemgr_t *zmgr = dns_zone_getmgr(zone);
isc_timermgr_t *timermgr = dns_zonemgr_gettimermgr(zmgr);
isc_task_t *ztask = NULL;
xfr = isc_mem_get(mctx, sizeof(*xfr));
*xfr = (dns_xfrin_ctx_t){ .netmgr = netmgr,
@ -876,7 +915,8 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
.maxrecords = dns_zone_getmaxrecords(zone),
.primaryaddr = *primaryaddr,
.sourceaddr = *sourceaddr,
.firstsoa = DNS_RDATA_INIT };
.firstsoa = DNS_RDATA_INIT,
.magic = XFRIN_MAGIC };
isc_mem_attach(mctx, &xfr->mctx);
dns_zone_iattach(zone, &xfr->zone);
@ -923,7 +963,12 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
isc_tlsctx_cache_attach(tlsctx_cache, &xfr->tlsctx_cache);
xfr->magic = XFRIN_MAGIC;
dns_zone_gettask(zone, &ztask);
isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, ztask,
xfrin_timedout, xfr, &xfr->max_time_timer);
isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, ztask,
xfrin_idledout, xfr, &xfr->max_idle_timer);
isc_task_detach(&ztask); /* dns_zone_task() attaches to the task */
*xfrp = xfr;
}
@ -1146,6 +1191,8 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
isc_tlsctx_t *tlsctx = NULL;
isc_tlsctx_client_session_cache_t *sess_cache = NULL;
isc_interval_t interval;
isc_time_t next;
(void)isc_refcount_increment0(&xfr->connects);
dns_xfrin_attach(xfr, &connect_xfr);
@ -1154,6 +1201,20 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
transport_type = dns_transport_get_type(xfr->transport);
}
/* Set the maximum timer */
isc_interval_set(&interval, dns_zone_getmaxxfrin(xfr->zone), 0);
isc_time_nowplusinterval(&next, &interval);
result = isc_timer_reset(xfr->max_time_timer, isc_timertype_once, &next,
NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/* Set the idle timer */
isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0);
isc_time_nowplusinterval(&next, &interval);
result = isc_timer_reset(xfr->max_idle_timer, isc_timertype_once, &next,
NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/*
* XXX: timeouts are hard-coded to 30 seconds; this needs to be
* configurable.
@ -1500,6 +1561,10 @@ xfrin_recv_done(isc_nmhandle_t *handle, isc_result_t result,
result = ISC_R_SHUTTINGDOWN;
}
/* Stop the idle timer */
(void)isc_timer_reset(xfr->max_idle_timer, isc_timertype_inactive, NULL,
NULL, true);
CHECK(result);
xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes", region->length);
@ -1754,6 +1819,8 @@ xfrin_recv_done(isc_nmhandle_t *handle, isc_result_t result,
}
atomic_store(&xfr->shuttingdown, true);
(void)isc_timer_reset(xfr->max_time_timer,
isc_timertype_inactive, NULL, NULL, true);
xfr->shutdown_result = ISC_R_SUCCESS;
break;
default:
@ -1765,6 +1832,13 @@ xfrin_recv_done(isc_nmhandle_t *handle, isc_result_t result,
dns_message_detach(&msg);
isc_refcount_increment0(&xfr->recvs);
isc_nm_read(xfr->handle, xfrin_recv_done, xfr);
isc_time_t next;
isc_interval_t interval;
isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0);
isc_time_nowplusinterval(&next, &interval);
result = isc_timer_reset(xfr->max_idle_timer,
isc_timertype_once, &next, NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
return;
}
@ -1891,6 +1965,9 @@ xfrin_destroy(dns_xfrin_ctx_t *xfr) {
isc_tlsctx_cache_detach(&xfr->tlsctx_cache);
}
isc_timer_destroy(&xfr->max_idle_timer);
isc_timer_destroy(&xfr->max_time_timer);
isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
}

View file

@ -19215,6 +19215,13 @@ dns_zonemgr_gettaskmgr(dns_zonemgr_t *zmgr) {
return (zmgr->taskmgr);
}
isc_timermgr_t *
dns_zonemgr_gettimermgr(dns_zonemgr_t *zmgr) {
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
return (zmgr->timermgr);
}
/*
* Try to start a new incoming zone transfer to fill a quota
* slot that was just vacated.