On Wed, Sep 21, 2022 at 12:49:28PM +0200, Arne Schwabe wrote: > This ensures that control packets are actually smaller than the maximum > control channel packet size. > > 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 record, so the receiving side will only be able > to get/read the control message content when a TLS record is > complete. To achieve this goal, 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. > - 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 no longer limit this by the mtu of > control packets as the implemented splitting will take care of > larger payloads from the SSL library > > Note this commit has a warning message that references max-packet-size that > is introduced in the next commit. In this commit the packet size is not yet > configurable. > > 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.
Reread the code. Did some client-side tests with small MTUs. Didn't find any issues. One remaining typo found, see below. I think it would actually have been possible to split this up in even smaller patches (e.g. removing the maxlen parameter), but probably not worth doing that now on a v4. Acked-By: Frank Lichtenheld <fr...@lichtenheld.com> > diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c > index 672cd9c84..b69258be8 100644 > --- a/src/openvpn/ssl.c > +++ b/src/openvpn/ssl.c [...] > @@ -2675,6 +2718,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); > + } > + > + /* Not enough space available to send a full control channel packet */ > + if (maxlen < TLS_CHANNEL_BUF_SIZE) > + { > + if (rel_avail == TLS_RELIABLE_N_SEND_BUFFERS) > + { > + msg(D_TLS_ERRORS, "--max-packet-size setting too low. Unable to " > + "send control channel message."); > + } > + msg(D_REL_LOW, "Reliable: Send queue full, postponing TLS send"); > + return true; > + } > + > + /* This seems a bit wasteful to allocate every time */ > + struct gc_arena gc = gc_new(); > + struct buffer tmp = alloc_buf_gc(TLS_CHANNEL_BUF_SIZE, &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) > + { > + 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 availibility before */ "availability" > + 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; > +} > + > Regards, -- Frank Lichtenheld _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel