]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Fix broken fragment/mssfix with NCP
authorLev Stipakov <lev@openvpn.net>
Mon, 21 Jan 2019 20:04:54 +0000 (22:04 +0200)
committerGert Doering <gert@greenie.muc.de>
Mon, 22 Jul 2019 18:25:53 +0000 (20:25 +0200)
NCP negotiation replaces worst cast crypto overhead
with actual one in data channel frame. That frame
params are used by mssfix.

Fragment frame still contains worst case overhead.
Because of that TCP packets are fragmented, since
MSS value exceeds max fragment size.

Fix by replacing worst case crypto overhead with
actual one for fragment frame, as it is done for data
channel frame.

Trac #1140

Signed-off-by: Lev Stipakov <lstipakov@gmail.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Steffan Karger <steffan.karger@fox-it.com>
Message-Id: <1548101094-4449-1-git-send-email-lstipakov@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg18135.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/forward.c
src/openvpn/init.c
src/openvpn/openvpn.h
src/openvpn/push.c
src/openvpn/ssl.c
src/openvpn/ssl.h

index 35df089a6d9ff37f2be2e3461b6f93f1d4b35e35..c2dcb538bef8afa0b8b6def8e1ff23205e32a531 100644 (file)
@@ -1093,6 +1093,9 @@ process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, boo
                 if (is_hard_reset(opcode, c->options.key_method))
                 {
                     c->c2.frame = c->c2.frame_initial;
+#ifdef ENABLE_FRAGMENT
+                    c->c2.frame_fragment = c->c2.frame_fragment_initial;
+#endif
                 }
 
                 interval_action(&c->c2.tmp_int);
index 5ccf4d9d0b8eaf625c6936f1d19f5f8c6c51a5f8..b5a034dcef569f87213053d6d9ed99f16f32ed6d 100644 (file)
@@ -2333,9 +2333,18 @@ do_deferred_options(struct context *c, const unsigned int found)
         {
             tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername);
         }
+        struct frame *frame_fragment = NULL;
+#ifdef ENABLE_FRAGMENT
+        if (c->options.ce.fragment)
+        {
+            frame_fragment = &c->c2.frame_fragment;
+        }
+#endif
+
         /* Do not regenerate keys if server sends an extra push reply */
         if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized
-            && !tls_session_update_crypto_params(session, &c->options, &c->c2.frame))
+            && !tls_session_update_crypto_params(session, &c->options, &c->c2.frame,
+                                                 frame_fragment))
         {
             msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options");
             return false;
@@ -3118,6 +3127,7 @@ do_init_frame(struct context *c)
      */
     c->c2.frame_fragment = c->c2.frame;
     frame_subtract_extra(&c->c2.frame_fragment, &c->c2.frame_fragment_omit);
+    c->c2.frame_fragment_initial = c->c2.frame_fragment;
 #endif
 
 #if defined(ENABLE_FRAGMENT) && defined(ENABLE_OCC)
index fca33f25c6954f14cda6b720a522858611f87771..29d21f0a46809b06633a7ffe0f570a715a1cbf28 100644 (file)
@@ -265,6 +265,7 @@ struct context_2
     /* Object to handle advanced MTU negotiation and datagram fragmentation */
     struct fragment_master *fragment;
     struct frame frame_fragment;
+    struct frame frame_fragment_initial;
     struct frame frame_fragment_omit;
 #endif
 
index 8befc6f595f853ad7ea88b8c033ad5967eb29ba3..248c2e46c294da67921a4ff4dc2b128eb00d0d12 100644 (file)
@@ -287,11 +287,18 @@ incoming_push_message(struct context *c, const struct buffer *buffer)
     {
         if (c->options.mode == MODE_SERVER)
         {
+            struct frame *frame_fragment = NULL;
+#ifdef ENABLE_FRAGMENT
+            if (c->options.ce.fragment)
+            {
+                frame_fragment = &c->c2.frame_fragment;
+            }
+#endif
             struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
             /* Do not regenerate keys if client send a second push request */
             if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized
                 && !tls_session_update_crypto_params(session, &c->options,
-                                                     &c->c2.frame))
+                                                     &c->c2.frame, frame_fragment))
             {
                 msg(D_TLS_ERRORS, "TLS Error: initializing data channel failed");
                 goto error;
index 640808f949b0b3db6326be964ee90c4b75ddd1e0..abc3c53bc01bdca7276c3557ca678da0ff2e7871 100644 (file)
@@ -1990,7 +1990,8 @@ cleanup:
 
 bool
 tls_session_update_crypto_params(struct tls_session *session,
-                                 struct options *options, struct frame *frame)
+                                 struct options *options, struct frame *frame,
+                                 struct frame *frame_fragment)
 {
     if (!session->opt->server
         && 0 != strcmp(options->ciphername, session->opt->config_ciphername)
@@ -2034,6 +2035,22 @@ tls_session_update_crypto_params(struct tls_session *session,
     frame_init_mssfix(frame, options);
     frame_print(frame, D_MTU_INFO, "Data Channel MTU parms");
 
+    /*
+     * mssfix uses data channel framing, which at this point contains
+     * actual overhead. Fragmentation logic uses frame_fragment, which
+     * still contains worst case overhead. Replace it with actual overhead
+     * to prevent unneeded fragmentation.
+     */
+
+    if (frame_fragment)
+    {
+        frame_remove_from_extra_frame(frame_fragment, crypto_max_overhead());
+        crypto_adjust_frame_parameters(frame_fragment, &session->opt->key_type,
+                                      options->replay, packet_id_long_form);
+        frame_set_mtu_dynamic(frame_fragment, options->ce.fragment, SET_MTU_UPPER_BOUND);
+        frame_print(frame_fragment, D_MTU_INFO, "Fragmentation MTU parms");
+    }
+
     return tls_session_generate_data_channel_keys(session);
 }
 
index 660e9eb46fb9bc4ddb86e2378fc7b960ed024f9c..e98c54c732c63114b06711b9446b72d65a46fdde 100644 (file)
@@ -476,15 +476,18 @@ void tls_update_remote_addr(struct tls_multi *multi,
  * Update TLS session crypto parameters (cipher and auth) and derive data
  * channel keys based on the supplied options.
  *
- * @param session       The TLS session to update.
- * @param options       The options to use when updating session.
- * @param frame         The frame options for this session (frame overhead is
- *                      adjusted based on the selected cipher/auth).
+ * @param session         The TLS session to update.
+ * @param options         The options to use when updating session.
+ * @param frame           The frame options for this session (frame overhead is
+ *                        adjusted based on the selected cipher/auth).
+ * @param frame_fragment  The fragment frame options.
  *
  * @return true if updating succeeded, false otherwise.
  */
 bool tls_session_update_crypto_params(struct tls_session *session,
-                                      struct options *options, struct frame *frame);
+                                      struct options *options,
+                                      struct frame *frame,
+                                      struct frame *frame_fragment);
 
 /**
  * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher.