Note: Patch has some conflicts against current master.
Note2: I get "make check" failures:
2022-05-06 16:29:23 Assertion failed at init.c:2991 
(c->c2.tls_multi->opt.frame.buf.payload_size <= c->c2.frame.buf.payload_size)
2022-05-06 16:29:23 Exiting due to fatal error

> Arne Schwabe <a...@rfc2549.org> hat am 22.04.2022 16:29 geschrieben:
> 
>  
> This ensure that control packets are actually are actually smaller than

redundant "are actually"

> tls-mtu. Since 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 records, so the receiving side will only be able

"record"

> to get/read the control message content when a TLS records is

"record"

> complete. To achieve this goal, this commit does:
> 
> - Splitting 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 implementation as
>   receivers will have room for 8.
> - calculate the overhead for control channel message to allow
>   staying below that threshold.
> - remove maxlen from key_state_read_ciphertext and related functions
>   as we now always allow control channel messages to be up to
>   TLS_CHANNEL_BUF_SIZE in size and longer limit this by the mtu of
>   control packets as the implemented splitting will take care of
>   larger payloads from the SSL library
> ---
>  src/openvpn/reliable.c    |  64 +++++++++++----
>  src/openvpn/reliable.h    |  32 +++++++-
>  src/openvpn/ssl.c         | 162 ++++++++++++++++++++++++++++++++------
>  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, 229 insertions(+), 71 deletions(-)
> 
> diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c
> index 372444350..28f99d187 100644
> --- a/src/openvpn/reliable.c
> +++ b/src/openvpn/reliable.c
> @@ -41,30 +41,30 @@
>  
>  #include "memdbg.h"
>  
> -/*
> - * verify that test - base < extent while allowing for base or test 
> wraparound
> - */
> -static inline bool
> -reliable_pid_in_range1(const packet_id_type test,
> -                       const packet_id_type base,
> -                       const unsigned int extent)
> +/* calculates test - base while allowing for base or test wraparound. test is
> + * assume to be higher than base */

"assumed"

> +static inline packet_id_type
> +subtract_pid(const packet_id_type test, const packet_id_type base)
>  {
>      if (test >= base)
>      {
> -        if (test - base < extent)
> -        {
> -            return true;
> -        }
> +        return test - base;
>      }
>      else
>      {
> -        if ((test+0x80000000u) - (base+0x80000000u) < extent)
> -        {
> -            return true;
> -        }
> +        return (test+0x80000000u) - (base+0x80000000u);

As discussed on IRC, I think this is bogus. test - base is the same as 
(test+0x80000000u) - (base+0x80000000u),
so I don't see what the if accomplishes.

>      }
> +}
>  
> -    return false;
> +/*
> + * verify that test - base < extent while allowing for base or test 
> wraparound
> + */
> +static inline bool
> +reliable_pid_in_range1(const packet_id_type test,
> +                       const packet_id_type base,
> +                       const unsigned int extent)
> +{
> +    return subtract_pid(test, base) < extent;
>  }
>  
>  /*
> @@ -496,6 +496,38 @@ reliable_get_buf(struct reliable *rel)
>      return NULL;
>  }
>  
> +/* Counts the number of free buffers in output that can be potientially used
> + * for sending */
> +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);

Okay... Why does this work? packet_id always increases by 1 exactly?

> +    }
> +    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 8152e788c..c80949525 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 bool

bool? you probably meant 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 potientially 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 01717559c..3b81f9707 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -323,10 +323,12 @@ 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 configure and we still want to be able to receive the

"configured"

> +     * packets. frame->mtu_mtu is set as suggestion for the maximum packet
>       * size */
> -    frame->buf.payload_size = 1250 + overhead;
> +    frame->buf.payload_size = TLS_CHANNEL_BUF_SIZE + overhead;
>  
>      frame->buf.headroom = overhead;
>      frame->buf.tailroom = overhead;
> @@ -334,6 +336,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 pessmistic and might give higher

"pessimistic"

> + * overhead that we actually have */

"than"

> +static int
> +calc_control_channel_frame_overhead(const struct tls_session *session)
> +{
> +    const struct key_state *ks = &session->key[KS_PRIMARY];
> +    int overhead = 0;
> +
> +    /* TCP length field and opcode */
> +    overhead+= 3;
> +
> +    /* 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();
> +        overhead += packet_id_size(true);

tls_crypt_buf_overhead already contains packet_id_size(true)

> +    }
> +    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(AF_INET6, PROTO_UDP);
> +
> +    return overhead;
> +}
> +
>  void
>  init_ssl_lib(void)
>  {
> @@ -2613,10 +2657,13 @@ control_packet_needs_wkc(const struct key_state *ks)
[...]

Rest of patch not yet reviewed.

Regards,
--
Frank Lichtenheld


_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to