From 8643bbab848e16d1e351fd0af56339dfa63e50f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 2 Feb 2022 11:20:17 +0100 Subject: [PATCH] Reimplement the max-transfer-time-out and max-transfer-idle-out While refactoring the libns to use the new network manager, the max-transfer-*-out options were not implemented and they were turned non-operational. Reimplement the max-transfer-idle-out functionality using the write timer and max-transfer-time-out using the new isc_nm_timer API. --- lib/ns/xfrout.c | 107 +++++++++++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/lib/ns/xfrout.c b/lib/ns/xfrout.c index 8e901d5bf1..e32493f8bf 100644 --- a/lib/ns/xfrout.c +++ b/lib/ns/xfrout.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -668,6 +669,12 @@ typedef struct { const char *mnemonic; /* Style of transfer */ uint32_t end_serial; /* Serial number after XFR is done */ struct xfr_stats stats; /*%< Transfer statistics */ + + /* Timeouts */ + uint64_t maxtime; /*%< Maximum XFR timeout (in ms) */ + isc_nm_timer_t *maxtime_timer; + + uint64_t idletime; /*%< XFR idle timeout (in ms) */ } xfrout_ctx_t; static void @@ -695,6 +702,9 @@ xfrout_maybe_destroy(xfrout_ctx_t *xfr); static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp); +static void +xfrout_client_timeout(void *arg, isc_result_t result); + static void xfrout_log1(ns_client_t *client, dns_name_t *zonename, dns_rdataclass_t rdclass, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); @@ -1143,6 +1153,14 @@ have_stream: } } + /* Start the timers */ + if (xfr->maxtime > 0) { + xfrout_log(xfr, ISC_LOG_ERROR, + "starting maxtime timer %" PRIu64 " ms", + xfr->maxtime); + isc_nm_timer_start(xfr->maxtime_timer, xfr->maxtime); + } + /* * Hand the context over to sendstream(). Set xfr to NULL; * sendstream() is responsible for either passing the @@ -1202,64 +1220,52 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, bool verified_tsig, unsigned int maxtime, unsigned int idletime, bool many_answers, xfrout_ctx_t **xfrp) { - xfrout_ctx_t *xfr; - unsigned int len; - void *mem; + xfrout_ctx_t *xfr = NULL; + unsigned int len = NS_CLIENT_TCP_BUFFER_SIZE; + void *mem = NULL; REQUIRE(xfrp != NULL && *xfrp == NULL); - UNUSED(maxtime); - UNUSED(idletime); - xfr = isc_mem_get(mctx, sizeof(*xfr)); - xfr->mctx = NULL; + *xfr = (xfrout_ctx_t){ + .client = client, + .id = id, + .qname = qname, + .qtype = qtype, + .qclass = qclass, + .maxtime = maxtime * 1000, /* in milliseconds */ + .idletime = idletime * 1000, /* In milliseconds */ + .tsigkey = tsigkey, + .lasttsig = lasttsig, + .verified_tsig = verified_tsig, + .many_answers = many_answers, + }; + isc_mem_attach(mctx, &xfr->mctx); - xfr->client = client; - xfr->id = id; - xfr->qname = qname; - xfr->qtype = qtype; - xfr->qclass = qclass; - xfr->zone = NULL; - xfr->db = NULL; - xfr->ver = NULL; + if (zone != NULL) { /* zone will be NULL if it's DLZ */ dns_zone_attach(zone, &xfr->zone); } dns_db_attach(db, &xfr->db); dns_db_attachversion(db, ver, &xfr->ver); - xfr->question_added = false; - xfr->end_of_stream = false; - xfr->tsigkey = tsigkey; - xfr->lasttsig = lasttsig; - xfr->verified_tsig = verified_tsig; - xfr->many_answers = many_answers; - xfr->sends = 0; - xfr->shuttingdown = false; - xfr->poll = false; - xfr->mnemonic = NULL; - xfr->buf.base = NULL; - xfr->buf.length = 0; - xfr->txmem = NULL; - xfr->txmemlen = 0; - xfr->stream = NULL; - xfr->quota = NULL; - xfr->stats.nmsg = 0; - xfr->stats.nrecs = 0; - xfr->stats.nbytes = 0; isc_time_now(&xfr->stats.start); + isc_nm_timer_create(xfr->client->handle, xfrout_client_timeout, xfr, + &xfr->maxtime_timer); + /* * Allocate a temporary buffer for the uncompressed response - * message data. The size should be no more than 65535 bytes - * so that the compressed data will fit in a TCP message, - * and no less than 65535 bytes so that an almost maximum-sized - * RR will fit. Note that although 65535-byte RRs are allowed - * in principle, they cannot be zone-transferred (at least not - * if uncompressible), because the message and RR headers would - * push the size of the TCP message over the 65536 byte limit. + * message data. The buffer size must be 65535 bytes + * (NS_CLIENT_TCP_BUFFER_SIZE): small enough that compressed + * data will fit in a single TCP message, and big enough to + * hold a maximum-sized RR. + * + * Note that although 65535-byte RRs are allowed in principle, they + * cannot be zone-transferred (at least not if uncompressible), + * because the message and RR headers would push the size of the + * TCP message over the 65536 byte limit. */ - len = 65535; mem = isc_mem_get(mctx, len); isc_buffer_init(&xfr->buf, mem, len); @@ -1267,7 +1273,6 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, * Allocate another temporary buffer for the compressed * response message. */ - len = NS_CLIENT_TCP_BUFFER_SIZE; mem = isc_mem_get(mctx, len); isc_buffer_init(&xfr->txbuf, (char *)mem, len); xfr->txmem = mem; @@ -1557,6 +1562,10 @@ sendstream(xfrout_ctx_t *xfr) { isc_nmhandle_attach(xfr->client->handle, &xfr->client->sendhandle); + if (xfr->idletime > 0) { + isc_nmhandle_setwritetimeout(xfr->client->sendhandle, + xfr->idletime); + } isc_nm_send(xfr->client->sendhandle, &used, xfrout_senddone, xfr); xfr->sends++; @@ -1622,6 +1631,9 @@ xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { INSIST(xfr->sends == 0); + isc_nm_timer_stop(xfr->maxtime_timer); + isc_nm_timer_detach(&xfr->maxtime_timer); + if (xfr->stream != NULL) { xfr->stream->methods->destroy(&xfr->stream); } @@ -1726,6 +1738,15 @@ xfrout_maybe_destroy(xfrout_ctx_t *xfr) { xfrout_ctx_destroy(&xfr); } +static void +xfrout_client_timeout(void *arg, isc_result_t result) { + xfrout_ctx_t *xfr = (xfrout_ctx_t *)arg; + + xfr->shuttingdown = true; + xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", "aborted", + isc_result_totext(result)); +} + /* * Log outgoing zone transfer messages in a format like * : transfer of :