]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Reimplement the max-transfer-time-out and max-transfer-idle-out
authorOndřej Surý <ondrej@isc.org>
Wed, 2 Feb 2022 10:20:17 +0000 (11:20 +0100)
committerOndřej Surý <ondrej@isc.org>
Thu, 17 Feb 2022 21:59:24 +0000 (22:59 +0100)
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.

(cherry picked from commit 8643bbab848e16d1e351fd0af56339dfa63e50f6)

lib/ns/xfrout.c

index e817c40458e5a0bb0e3edb87233daf74dd19dead..7b2863264cb453bf8e33541032567c6db6d138af 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <isc/formatcheck.h>
 #include <isc/mem.h>
+#include <isc/netmgr.h>
 #include <isc/print.h>
 #include <isc/stats.h>
 #include <isc/util.h>
@@ -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);
@@ -1160,6 +1170,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
@@ -1219,64 +1237,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);
 
@@ -1284,7 +1290,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;
@@ -1574,6 +1579,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++;
@@ -1639,6 +1648,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);
        }
@@ -1743,6 +1755,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
  * <client>: transfer of <zone>: <message>