Avoid bare TCP ACKs during TLS-on-connect startup.
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 21 Jan 2021 17:34:55 +0000 (17:34 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 21 Jan 2021 17:34:55 +0000 (17:34 +0000)
    We can't get the QUICKACK turned off on the accepted socket fast enough to
    stop the ACK for the ClientHello - but we get the rest, under OpenSSL.

src/src/smtp_in.c
src/src/smtp_out.c
src/src/transports/smtp.c
test/scripts/1100-Basic-TLS/1160
test/src/client.c

index 13cba2ec21bd1c9ae2187a1daa09695e15d53ddd..4cc619014baec07f38cb39a25109ce975b1cf0c6 100644 (file)
@@ -2893,7 +2893,7 @@ if (!f.sender_host_unknown)
 if (smtp_batched_input) return TRUE;
 
 /* If valid Proxy Protocol source is connecting, set up session.
 if (smtp_batched_input) return TRUE;
 
 /* If valid Proxy Protocol source is connecting, set up session.
- * Failure will not allow any SMTP function other than QUIT. */
+Failure will not allow any SMTP function other than QUIT. */
 
 #ifdef SUPPORT_PROXY
 proxy_session = FALSE;
 
 #ifdef SUPPORT_PROXY
 proxy_session = FALSE;
@@ -2902,16 +2902,21 @@ if (check_proxy_protocol_host())
   setup_proxy_protocol_host();
 #endif
 
   setup_proxy_protocol_host();
 #endif
 
+#ifdef TCP_QUICKACK /* Avoid pure-ACKs while in tls protocol pingpong phase */
+(void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK,
+         US &off, sizeof(off));
+#endif
+
   /* Start up TLS if tls_on_connect is set. This is for supporting the legacy
   smtps port for use with older style SSL MTAs. */
 
 #ifndef DISABLE_TLS
   /* Start up TLS if tls_on_connect is set. This is for supporting the legacy
   smtps port for use with older style SSL MTAs. */
 
 #ifndef DISABLE_TLS
-  if (tls_in.on_connect)
-    {
-    if (tls_server_start(&user_msg) != OK)
-      return smtp_log_tls_fail(user_msg);
-    cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
-    }
+if (tls_in.on_connect)
+  {
+  if (tls_server_start(&user_msg) != OK)
+    return smtp_log_tls_fail(user_msg);
+  cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
+  }
 #endif
 
 /* Run the connect ACL if it exists */
 #endif
 
 /* Run the connect ACL if it exists */
@@ -3912,6 +3917,12 @@ os_non_restarting_signal(SIGTERM, command_sigterm_handler);
 
 if (smtp_batched_input) return smtp_setup_batch_msg();
 
 
 if (smtp_batched_input) return smtp_setup_batch_msg();
 
+#ifdef TCP_QUICKACK
+if (smtp_in)           /* Avoid pure-ACKs while in cmd pingpong phase */
+  (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK,
+         US &off, sizeof(off));
+#endif
+
 /* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
 value. The values are 2 larger than the required yield of the function. */
 
 /* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
 value. The values are 2 larger than the required yield of the function. */
 
@@ -3969,12 +3980,6 @@ while (done <= 0)
     }
 #endif
 
     }
 #endif
 
-#ifdef TCP_QUICKACK
-  if (smtp_in)         /* Avoid pure-ACKs while in cmd pingpong phase */
-    (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK,
-           US &off, sizeof(off));
-#endif
-
   switch(smtp_read_command(
 #ifndef DISABLE_PIPE_CONNECT
          !fl.pipe_connect_acceptable,
   switch(smtp_read_command(
 #ifndef DISABLE_PIPE_CONNECT
          !fl.pipe_connect_acceptable,
index bb7a0e3b30e120b240a2caf98f3fc64bdcd86207..2d2fd21802c88d063405fc23dac8bdfc61f64257 100644 (file)
@@ -329,12 +329,12 @@ else
     HDEBUG(D_transport|D_acl|D_v)
       debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
 
     HDEBUG(D_transport|D_acl|D_v)
       debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
 
-#ifdef TCP_QUICKACK
-    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
-#endif
     if (send(sock, early_data->data, early_data->len, 0) < 0)
       save_errno = errno;
     }
     if (send(sock, early_data->data, early_data->len, 0) < 0)
       save_errno = errno;
     }
+#ifdef TCP_QUICKACK
+    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
+#endif
   }
 
 /* Either bind() or connect() failed */
   }
 
 /* Either bind() or connect() failed */
index 301d84c2e4415aabff5fbe0a370764395be64be9..ee5e49e5761991ea247df1a7a927ac861ab1a2ae 100644 (file)
@@ -2107,6 +2107,10 @@ PIPE_CONNECT_RETRY:
       sx->send_quit = FALSE;
       return DEFER;
       }
       sx->send_quit = FALSE;
       return DEFER;
       }
+#ifdef TCP_QUICKACK
+    (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, TCP_QUICKACK, US &off,
+                       sizeof(off));
+#endif
     }
   /* Expand the greeting message while waiting for the initial response. (Makes
   sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
     }
   /* Expand the greeting message while waiting for the initial response. (Makes
   sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
@@ -2152,10 +2156,6 @@ will be?  Somehow I doubt it. */
     else
 #endif
       {
     else
 #endif
       {
-#ifdef TCP_QUICKACK
-      (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, TCP_QUICKACK, US &off,
-                       sizeof(off));
-#endif
       if (!smtp_reap_banner(sx))
        goto RESPONSE_FAILED;
       }
       if (!smtp_reap_banner(sx))
        goto RESPONSE_FAILED;
       }
index ce7298e47680a993214115d7b71e085452d771c7..e57867e1cce1f69390b88cb69c3c693cc0366d0e 100644 (file)
@@ -4,8 +4,29 @@
 # For GnuTLS, additionally run the daemon under sudo.
 # Tell wireshark to use DIR/spool/sslkeys for Master Secret log, and decode TCP/1225 as TLS, TLS/1225 as SMTP
 #
 # For GnuTLS, additionally run the daemon under sudo.
 # Tell wireshark to use DIR/spool/sslkeys for Master Secret log, and decode TCP/1225 as TLS, TLS/1225 as SMTP
 #
-# sudo exim -DSERVER=server -d+tls -bd -oX PORT_D
-exim -DSERVER=server -bd -oX PORT_D
+# We get (TLS1.3 , OpenSSL):
+#    SYN               >
+#                      < SYN,ACK
+#    ACK               >
+#    Client Hello      >
+#                      < Server Hello, Change Ciph, Extensions, Cert, Cert Verify, Finished
+#    Change Ciph,Finsh >
+#                      < Banner
+#    EHLO              >
+#                      < EHLO resp
+#    MAIL,RCPT,DATA    >
+#                      < ACK,ACK,DATA-go-ahead
+#
+# GnuTLS splits both the server records and the client response pair over two TCP segments:
+#    Client Hello      >
+#                      < Server Hello, Change Ciph
+#    Change Ciph       >
+#                      < Extensins, Cert, Cert Verify, Finished
+#    Finished          >
+# (otherwise the same).  The extra segments are piplined and do not incur an extra roundtrip time.
+#
+# exim -DSERVER=server -bd -oX PORT_D
+sudo exim -DSERVER=server -d+tls -bd -oX PORT_D
 ****
 exim CALLER@test.ex
 Test message. Contains FF: ÿ
 ****
 exim CALLER@test.ex
 Test message. Contains FF: ÿ
index 9190af0689295a1bde2a926d9118828d2a44b2b3..9beaf25bb74a4ef154b35c94db1036f150b71f88 100644 (file)
@@ -1234,6 +1234,13 @@ if (rc < 0)
   exit(85);
   }
 
   exit(85);
   }
 
+#ifdef TCP_QUICKACK
+  {
+  int off = 0;
+  (void) setsockopt(srv.sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
+  }
+#endif
+
 printf("connected\n");
 
 
 printf("connected\n");