[Openvpn-devel,v6,1/2] Refactor/optimise code sending TLS control channel messages

Message ID 20221104125655.656150-1-arne@rfc2549.org
State Accepted
Headers show
Series [Openvpn-devel,v6,1/2] Refactor/optimise code sending TLS control channel messages | expand

Commit Message

Arne Schwabe Nov. 4, 2022, 1:56 a.m. UTC
This commit originally tried to solve a problem that the SSL library
might split up a control frame into multiple TLS records when doing
multiple reads. However, this does not seem to be actually the case.

OpenVPN will consider a control message packet complete
when the TLS record is complete, we have to ensure that the SSL library
will still write one record, so the receiving side will only be able
to get/read the control message content when a TLS record is
complete.

To improve handling of large control channel messages, this
commit does:

- Split one read from TLS library into multiple control
  channel packets, splitting one TLS record into multiple
  control packets.
- increase allowed number of outstanding packets to 6 from 4 on the
  sender side. This is still okay with older implementations as
  receivers will have room for 8. This allows transmitting larger
  control message more quickly.
- take the wrapped key length into account when sending packets
  This is especially important for the tls-crypt-v2 P_CONTROL_WKC_V1
  message
- calculate the overhead for control channel message to allow
  staying below that threshold.
- remove maxlen from key_state_read_ciphertext and related functions.
  We now always give the function a correctly sized buffer.

If we end up needing to send a packet larger than max-packet-size, we
warn about it but still do it as it might still work, while refusing to
send will never work.

Patch v2: avoid assertion about to large buffer by sticking to 1250 max
          control size in this commit and leaving larger sizes for the
          --max-packet-size commit. Also fix
          various other small problems and grammar fixes.
Patch v3: grammar fixes
Patch v4: adjust tls-mtu to max-packet-size in message.
Patch v6: no longer make the assumption that multiple reads from the SSL
          library split a control frame into multiple TLS records.

Signed-off-by: Arne Schwabe <arne@rfc2549.org>
---
 src/openvpn/reliable.c    |  55 ++++++++++----
 src/openvpn/reliable.h    |  32 +++++++-
 src/openvpn/ssl.c         | 156 +++++++++++++++++++++++++++++++++-----
 src/openvpn/ssl_backend.h |   8 +-
 src/openvpn/ssl_mbedtls.c |  14 +---
 src/openvpn/ssl_openssl.c |  16 ++--
 src/openvpn/ssl_pkt.h     |   4 +-
 7 files changed, 216 insertions(+), 69 deletions(-)

Comments

Gert Doering Nov. 5, 2022, 6:53 a.m. UTC | #1
Acked-by: Gert Doering <gert@greenie.muc.de>

This is a slightly complicated ACK - this is a respin of 1/3 v4 with
the "Ensure that control channel packet are respecting maximum packet size"
patch, which has an ACK from Frank Lichtenheld.  During testing of v4
I noticed that it it brings a regression for "very small packets"
(--link-mtu 440 and below) - not that these are overly useful, but if
it worked before, why shouldn't it stop afterwards?  So I started a
discussion on IRC which ended here.

Most of this patch is identical to "1/3 v4", except for a typo fix :-),
avoiding an integer underrun ("tmp.len > 0" now), removing the 2 byte
TCP length from "overhead", using the actual AF_ instead of always
going for AF_INET, and most important, the "maxlen < TLS_CHANNEL_BUF_SIZE"
that broke "very small packets" in v4 got changed to "for really really
small packets, we might exceed the MTU", but this is in the order of
"16 bytes payload".  Better die trying than not try at all...


The "if (maxlen < 16)" bit looks a bit strange, setting maxlen to 16
(okay) and max_pkt_len to TLS_CHANNEL_BUF_SIZE - if we get there with
maxlen = 16, max_pkt_len will also be something like "16" (assuming
rel_avail == 1 and no WKC) or maybe "32", but nowhere near 1250...
OTOH it is of no real significance, as "maxlen" controls how many
bytes we'll ever request as payload - so, 16+WKC, well below 1250.

I am a bit concerned that the inner loop in write_outgoing_tls_ciphertext()
could end up as an endless loop, if "max_pkt_len" ends up being <= 
"buf_len(session->tls_wrap.tls_crypt_v2_wkc))", so the max_int() 
ends up with "len == 0", buf_copy_n() copying nothing, and the loop
repeating "send packets with a WKC and nothing else", forever.

OTOH, this needs a very small MTU to start with, which is not possible
to trigger with this patch alone (--link-mtu below 125 is refused
with "TUN MTU value (nn) must be at least 100" error).  But I'd still
like either confirmation that I have overlooked something, or maybe
adjust the max_int() to "1, ..." so it's clear we'll always handle
1 byte per loop, whatever happens...


Another observation: getting rid of all the "if (maxlen<len)" checks
in the BIO path leads to extra alloc_buf_gc() calls to convey the
"maxlen" by means of the "tmp" buf.  Not sure if this is a good 
tradeoff... more alloc()/free() against a few less integer compares...
(but then, this is control channel, which is not the most critical
fast path).


There are a few other bits in here that need work, like a comment
talking about "frame->mtu_mtu" and "TLS_CHANNEL_BUF_SIZE" while the 
code does "1250" magic numbers - but these get fixed in 2/2.


This all said, I did my best to break master + this patch, and couldn't
find a way - so, merged.  I tested server side (without any special
MTU settings) and client side with --link-mtu $various, comparing the
UDP output I saw in tcpdump.  We're still exceeding the --link-mtu
value for some cases (--link-mtu 125 -> UDP payload 121 bytes for a
few packets, and "72" for very many of them, both not really "125"
- and I wonder where the 72 is coming from, leaving lots of space
unused.  With --link-mtu 200, the maximum I saw is 171 bytes, so 
at least this patch tends to underflow available MTU (and same thing
for 300/271, 400/371).  Will come back to this with 2/2 v6 :-)


Your patch has been applied to the master branch.

commit 4e9e25a9e547ab6e1f71003947a2d186dc231cb6
Author: Arne Schwabe
Date:   Fri Nov 4 13:56:54 2022 +0100

     Refactor/optimise code sending TLS control channel messages

     Signed-off-by: Arne Schwabe <arne@rfc2549.org>
     Acked-by: Gert Doering <gert@greenie.muc.de>
     Message-Id: <20221104125655.656150-1-arne@rfc2549.org>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg25478.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c
index 734736256..3ccb73976 100644
--- a/src/openvpn/reliable.c
+++ b/src/openvpn/reliable.c
@@ -41,6 +41,14 @@ 
 
 #include "memdbg.h"
 
+/* calculates test - base while allowing for base or test wraparound. test is
+ * assumed to be higher than base */
+static inline packet_id_type
+subtract_pid(const packet_id_type test, const packet_id_type base)
+{
+    return test - base;
+}
+
 /*
  * verify that test - base < extent while allowing for base or test wraparound
  */
@@ -49,22 +57,7 @@  reliable_pid_in_range1(const packet_id_type test,
                        const packet_id_type base,
                        const unsigned int extent)
 {
-    if (test >= base)
-    {
-        if (test - base < extent)
-        {
-            return true;
-        }
-    }
-    else
-    {
-        if ((test+0x80000000u) - (base+0x80000000u) < extent)
-        {
-            return true;
-        }
-    }
-
-    return false;
+    return subtract_pid(test, base) < extent;
 }
 
 /*
@@ -498,6 +491,36 @@  reliable_get_buf(struct reliable *rel)
     return NULL;
 }
 
+int
+reliable_get_num_output_sequenced_available(struct reliable *rel)
+{
+    struct gc_arena gc = gc_new();
+    packet_id_type min_id = 0;
+    bool min_id_defined = false;
+
+    /* find minimum active packet_id */
+    for (int i = 0; i < rel->size; ++i)
+    {
+        const struct reliable_entry *e = &rel->array[i];
+        if (e->active)
+        {
+            if (!min_id_defined || reliable_pid_min(e->packet_id, min_id))
+            {
+                min_id_defined = true;
+                min_id = e->packet_id;
+            }
+        }
+    }
+
+    int ret = rel->size;
+    if (min_id_defined)
+    {
+        ret -= subtract_pid(rel->packet_id, min_id);
+    }
+    gc_free(&gc);
+    return ret;
+}
+
 /* grab a free buffer, fail if buffer clogged by unacknowledged low packet IDs */
 struct buffer *
 reliable_get_buf_output_sequenced(struct reliable *rel)
diff --git a/src/openvpn/reliable.h b/src/openvpn/reliable.h
index b9863efe3..7fffe397d 100644
--- a/src/openvpn/reliable.h
+++ b/src/openvpn/reliable.h
@@ -46,7 +46,7 @@ 
                                  *   be stored in one \c reliable_ack
                                  *   structure. */
 
-#define RELIABLE_CAPACITY 8     /**< The maximum number of packets that
+#define RELIABLE_CAPACITY 12    /**< The maximum number of packets that
                                  *   the reliability layer for one VPN
                                  *   tunnel in one direction can store. */
 
@@ -93,7 +93,7 @@  struct reliable
     int size;
     interval_t initial_timeout;
     packet_id_type packet_id;
-    int offset;
+    int offset; /**< Offset of the bufs in the reliable_entry array */
     bool hold; /* don't xmit until reliable_schedule_now is called */
     struct reliable_entry array[RELIABLE_CAPACITY];
 };
@@ -178,6 +178,20 @@  reliable_ack_empty(struct reliable_ack *ack)
     return !ack->len;
 }
 
+/**
+ * Returns the number of packets that need to be acked.
+ *
+ * @param ack The acknowledgment structure to check.
+ *
+ * @returns the number of outstanding acks
+ */
+static inline int
+reliable_ack_outstanding(struct reliable_ack *ack)
+{
+    return ack->len;
+}
+
+
 /**
  * Write a packet ID acknowledgment record to a buffer.
  *
@@ -385,6 +399,20 @@  void reliable_mark_deleted(struct reliable *rel, struct buffer *buf);
  */
 struct buffer *reliable_get_buf_output_sequenced(struct reliable *rel);
 
+
+/**
+ * Counts the number of free buffers in output that can be potentially used
+ * for sending
+ *
+ *  @param rel The reliable structure in which to search for a free
+ *     entry.
+ *
+ *  @return the number of buffer that are available for sending without
+ *             breaking ack sequence
+ * */
+int
+reliable_get_num_output_sequenced_available(struct reliable *rel);
+
 /**
  * Mark the reliable entry associated with the given buffer as
  *     active outgoing.
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 24e8ba632..528fd9026 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -305,7 +305,7 @@  tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame
      * if --tls-auth is enabled.
      */
 
-    /* calculate the maximum overhead that control channel frames may have */
+    /* calculates the maximum overhead that control channel frames can have */
     int overhead = 0;
 
     /* Socks */
@@ -324,8 +324,10 @@  tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame
     /* Previous OpenVPN version calculated the maximum size and buffer of a
      * control frame depending on the overhead of the data channel frame
      * overhead and limited its maximum size to 1250. We always allocate the
-     * 1250 buffer size since a lot of code blindly assumes a large buffer
-     * (e.g. PUSH_BUNDLE_SIZE) and set frame->mtu_mtu as suggestion for the
+     * TLS_CHANNEL_BUF_SIZE buffer size since a lot of code blindly assumes
+     * a large buffer (e.g. PUSH_BUNDLE_SIZE) and also our peer might have
+     * a higher size configured and we still want to be able to receive the
+     * packets. frame->mtu_mtu is set as suggestion for the maximum packet
      * size */
     frame->buf.payload_size = 1250 + overhead;
 
@@ -335,6 +337,48 @@  tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame
     frame->tun_mtu = min_int(data_channel_frame->tun_mtu, 1250);
 }
 
+/**
+ * calculate the maximum overhead that control channel frames have
+ * This includes header, op code and everything apart from the
+ * payload itself. This method is a bit pessimistic and might give higher
+ * overhead than we actually have */
+static int
+calc_control_channel_frame_overhead(const struct tls_session *session)
+{
+    const struct key_state *ks = &session->key[KS_PRIMARY];
+    int overhead = 0;
+
+    /* opcode */
+    overhead += 1;
+
+    /* our own session id */
+    overhead += SID_SIZE;
+
+    /* ACK array and remote SESSION ID (part of the ACK array) */
+    overhead += ACK_SIZE(min_int(reliable_ack_outstanding(ks->rec_ack), CONTROL_SEND_ACK_MAX));
+
+    /* Message packet id */
+    overhead += sizeof(packet_id_type);
+
+    if (session->tls_wrap.mode == TLS_WRAP_CRYPT)
+    {
+        overhead += tls_crypt_buf_overhead();
+    }
+    else if (session->tls_wrap.mode == TLS_WRAP_AUTH)
+    {
+        overhead += hmac_ctx_size(session->tls_wrap.opt.key_ctx_bi.encrypt.hmac);
+        overhead += packet_id_size(true);
+    }
+
+    /* Add the typical UDP overhead for an IPv6 UDP packet. TCP+IPv6 has a
+     * larger overhead but the risk of a TCP connection getting dropped because
+     * we try to send a too large packet is basically zero */
+    overhead += datagram_overhead(session->untrusted_addr.dest.addr.sa.sa_family,
+                                  PROTO_UDP);
+
+    return overhead;
+}
+
 void
 init_ssl_lib(void)
 {
@@ -2666,7 +2710,7 @@  read_incoming_tls_plaintext(struct key_state *ks, struct buffer *buf,
 {
     ASSERT(buf_init(buf, 0));
 
-    int status = key_state_read_plaintext(&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE);
+    int status = key_state_read_plaintext(&ks->ks_ssl, buf);
 
     update_time();
     if (status == -1)
@@ -2685,6 +2729,92 @@  read_incoming_tls_plaintext(struct key_state *ks, struct buffer *buf,
     return true;
 }
 
+static bool
+write_outgoing_tls_ciphertext(struct tls_session *session, bool *state_change)
+{
+    struct key_state *ks = &session->key[KS_PRIMARY];
+
+    int rel_avail = reliable_get_num_output_sequenced_available(ks->send_reliable);
+    if (rel_avail == 0)
+    {
+        return true;
+    }
+
+    /* We need to determine how much space is actually available in the control
+     * channel frame */
+    int max_pkt_len = min_int(TLS_CHANNEL_BUF_SIZE, session->opt->frame.tun_mtu);
+
+    /* Subtract overhead */
+    max_pkt_len -= calc_control_channel_frame_overhead(session);
+
+    /* calculate total available length for outgoing tls ciphertext */
+    int maxlen = max_pkt_len * rel_avail;
+
+    /* Is first packet one that will have a WKC appended? */
+    if (control_packet_needs_wkc(ks))
+    {
+        maxlen -= buf_len(session->tls_wrap.tls_crypt_v2_wkc);
+    }
+
+    /* If we end up with a size that leaves no room for payload, ignore the
+     * constraints to still be to send a packet. This might have gone negative
+     * if we have a large wrapped client key. */
+    if (maxlen < 16)
+    {
+        msg(D_TLS_ERRORS, "Warning: --max-packet-size (%d) setting too low. "
+            "Sending minimum sized packet.",
+            session->opt->frame.tun_mtu);
+        maxlen = 16;
+        /* We set the maximum length here to ensure a packet with a wrapped
+         * key can actually carry the 16 byte of payload */
+        max_pkt_len = TLS_CHANNEL_BUF_SIZE;
+    }
+
+    /* This seems a bit wasteful to allocate every time */
+    struct gc_arena gc = gc_new();
+    struct buffer tmp = alloc_buf_gc(maxlen, &gc);
+
+    int status = key_state_read_ciphertext(&ks->ks_ssl, &tmp);
+
+    if (status == -1)
+    {
+        msg(D_TLS_ERRORS,
+            "TLS Error: Ciphertext -> reliable TCP/UDP transport read error");
+        gc_free(&gc);
+        return false;
+    }
+    if (status == 1)
+    {
+        /* Split the TLS ciphertext (TLS record) into multiple small packets
+         * that respect tls_mtu */
+        while (tmp.len > 0)
+        {
+            int len = max_pkt_len;
+            int opcode = P_CONTROL_V1;
+            if (control_packet_needs_wkc(ks))
+            {
+                opcode = P_CONTROL_WKC_V1;
+                len = max_int(0, len - buf_len(session->tls_wrap.tls_crypt_v2_wkc));
+            }
+            /* do not send more than available */
+            len = min_int(len, tmp.len);
+
+            struct buffer *buf = reliable_get_buf_output_sequenced(ks->send_reliable);
+            /* we assert here since we checked for its availability before */
+            ASSERT(buf);
+            buf_copy_n(buf, &tmp, len);
+
+            reliable_mark_active_outgoing(ks->send_reliable, buf, opcode);
+            INCR_GENERATED;
+            *state_change = true;
+        }
+        dmsg(D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable");
+    }
+
+    gc_free(&gc);
+    return true;
+}
+
 
 static bool
 tls_process_state(struct tls_multi *multi,
@@ -2839,26 +2969,10 @@  tls_process_state(struct tls_multi *multi,
         buf = reliable_get_buf_output_sequenced(ks->send_reliable);
         if (buf)
         {
-            int status = key_state_read_ciphertext(&ks->ks_ssl, buf, multi->opt.frame.tun_mtu);
-
-            if (status == -1)
+            if (!write_outgoing_tls_ciphertext(session, &state_change))
             {
-                msg(D_TLS_ERRORS,
-                    "TLS Error: Ciphertext -> reliable TCP/UDP transport read error");
                 goto error;
             }
-            if (status == 1)
-            {
-                int opcode = P_CONTROL_V1;
-                if (control_packet_needs_wkc(ks))
-                {
-                    opcode = P_CONTROL_WKC_V1;
-                }
-                reliable_mark_active_outgoing(ks->send_reliable, buf, opcode);
-                INCR_GENERATED;
-                state_change = true;
-                dmsg(D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable");
-            }
         }
     }
 
diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index 1bd336999..215425d41 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -461,7 +461,6 @@  int key_state_write_plaintext_const(struct key_state_ssl *ks_ssl,
  * @param ks_ssl       - The security parameter state for this %key
  *                       session.
  * @param buf          - A buffer in which to store the ciphertext.
- * @param maxlen       - The maximum number of bytes to extract.
  *
  * @return The return value indicates whether the data was successfully
  *     processed:
@@ -470,8 +469,8 @@  int key_state_write_plaintext_const(struct key_state_ssl *ks_ssl,
  *   later to retry.
  * - \c -1: An error occurred.
  */
-int key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf,
-                              int maxlen);
+int key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf);
+
 
 /** @} name Functions for packets to be sent to a remote OpenVPN peer */
 
@@ -517,8 +516,7 @@  int key_state_write_ciphertext(struct key_state_ssl *ks_ssl,
  *   later to retry.
  * - \c -1: An error occurred.
  */
-int key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf,
-                             int maxlen);
+int key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf);
 
 /** @} name Functions for packets received from a remote OpenVPN peer */
 
diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
index b0785bae9..ea06cf703 100644
--- a/src/openvpn/ssl_mbedtls.c
+++ b/src/openvpn/ssl_mbedtls.c
@@ -1285,8 +1285,7 @@  key_state_write_plaintext_const(struct key_state_ssl *ks, const uint8_t *data, i
 }
 
 int
-key_state_read_ciphertext(struct key_state_ssl *ks, struct buffer *buf,
-                          int maxlen)
+key_state_read_ciphertext(struct key_state_ssl *ks, struct buffer *buf)
 {
     int retval = 0;
     int len = 0;
@@ -1304,10 +1303,6 @@  key_state_read_ciphertext(struct key_state_ssl *ks, struct buffer *buf,
     }
 
     len = buf_forward_capacity(buf);
-    if (maxlen < len)
-    {
-        len = maxlen;
-    }
 
     retval = endless_buf_read(&ks->bio_ctx->out, BPTR(buf), len);
 
@@ -1388,8 +1383,7 @@  key_state_write_ciphertext(struct key_state_ssl *ks, struct buffer *buf)
 }
 
 int
-key_state_read_plaintext(struct key_state_ssl *ks, struct buffer *buf,
-                         int maxlen)
+key_state_read_plaintext(struct key_state_ssl *ks, struct buffer *buf)
 {
     int retval = 0;
     int len = 0;
@@ -1407,10 +1401,6 @@  key_state_read_plaintext(struct key_state_ssl *ks, struct buffer *buf,
     }
 
     len = buf_forward_capacity(buf);
-    if (maxlen < len)
-    {
-        len = maxlen;
-    }
 
     retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len);
 
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index 710c9c06d..cd6d84246 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -1871,7 +1871,7 @@  bio_write_post(const int status, struct buffer *buf)
  * Read from an OpenSSL BIO in non-blocking mode.
  */
 static int
-bio_read(BIO *bio, struct buffer *buf, int maxlen, const char *desc)
+bio_read(BIO *bio, struct buffer *buf, const char *desc)
 {
     int i;
     int ret = 0;
@@ -1882,10 +1882,6 @@  bio_read(BIO *bio, struct buffer *buf, int maxlen, const char *desc)
     else
     {
         int len = buf_forward_capacity(buf);
-        if (maxlen < len)
-        {
-            len = maxlen;
-        }
 
         /*
          * BIO_read brackets most of the serious RSA
@@ -2012,15 +2008,14 @@  key_state_write_plaintext_const(struct key_state_ssl *ks_ssl, const uint8_t *dat
 }
 
 int
-key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf,
-                          int maxlen)
+key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf)
 {
     int ret = 0;
     perf_push(PERF_BIO_READ_CIPHERTEXT);
 
     ASSERT(NULL != ks_ssl);
 
-    ret = bio_read(ks_ssl->ct_out, buf, maxlen, "tls_read_ciphertext");
+    ret = bio_read(ks_ssl->ct_out, buf, "tls_read_ciphertext");
 
     perf_pop();
     return ret;
@@ -2042,15 +2037,14 @@  key_state_write_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf)
 }
 
 int
-key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf,
-                         int maxlen)
+key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf)
 {
     int ret = 0;
     perf_push(PERF_BIO_READ_PLAINTEXT);
 
     ASSERT(NULL != ks_ssl);
 
-    ret = bio_read(ks_ssl->ssl_bio, buf, maxlen, "tls_read_plaintext");
+    ret = bio_read(ks_ssl->ssl_bio, buf, "tls_read_plaintext");
 
     perf_pop();
     return ret;
diff --git a/src/openvpn/ssl_pkt.h b/src/openvpn/ssl_pkt.h
index 45e0a81f5..9bb3ca958 100644
--- a/src/openvpn/ssl_pkt.h
+++ b/src/openvpn/ssl_pkt.h
@@ -67,8 +67,8 @@ 
 /*
  * Define number of buffers for send and receive in the reliability layer.
  */
-#define TLS_RELIABLE_N_SEND_BUFFERS  4 /* also window size for reliability layer */
-#define TLS_RELIABLE_N_REC_BUFFERS   8
+#define TLS_RELIABLE_N_SEND_BUFFERS  6 /* also window size for reliability layer */
+#define TLS_RELIABLE_N_REC_BUFFERS   12
 
 /*
  * Used in --mode server mode to check tls-auth signature on initial