From fa2cb06c753cdc947e914ddcaf135383d93f3897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 5 Apr 2023 22:35:00 +0200 Subject: [PATCH] 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 d2377f8e044a4b1e534ec55b237bac4781936533) --- doc/arm/reference.rst | 6 +++ lib/dns/include/dns/xfrin.h | 1 + lib/dns/include/dns/zone.h | 6 +++ lib/dns/xfrin.c | 81 ++++++++++++++++++++++++++++++++++++- lib/dns/zone.c | 7 ++++ 5 files changed, 99 insertions(+), 2 deletions(-) diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 36ea3a5892..b76294c59d 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -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. diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index 70b601bb57..dd47c8cad2 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -27,6 +27,7 @@ ***/ #include +#include #include #include diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 447e8aa1b2..10ed86c4e3 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -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); /*%< diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 16081863d8..b481368129 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -22,6 +22,8 @@ #include #include #include /* Required for HP/UX (and others?) */ +#include +#include #include #include @@ -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)); } diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 5f0c099dff..16f7708464 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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.