1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
From 6d6d322cedd046a058ba0c3a42b2cf54143d2ce5 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 26 Oct 2025 18:18:13 +0000
Subject: [PATCH] GnuTLS: avoid logging error on seeing TCP-drop after sending
QUIT
---
src/globals.h | 1 +
src/tls-gnu.c | 15 +++++++++++----
src/transports/smtp.c | 12 ++++++++++++
test/log/1167 | 2 --
4 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/src/globals.h b/src/globals.h
index 401fb794c..392180111 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -115,14 +115,15 @@ typedef struct {
BOOL ticket_received:1;
#endif
BOOL ext_master_secret:1; /* extended-master-secret was used */
BOOL channelbind_exporter:1; /* channelbinding is EXPORTER not UNIQUE */
BOOL on_connect:1; /* For older MTAs that don't STARTTLS */
BOOL verify_override:1; /* certificate_verified only due to tls_try_verify_hosts */
+ BOOL smtp_quit:1; /* QUIT has been sent or received */
} tls_support;
extern tls_support tls_in;
extern tls_support tls_out;
#endif /*!MACRO_PREDEF*/
#ifndef DISABLE_TLS
extern BOOL gnutls_compat_mode; /* Less security, more compatibility */
diff --git a/src/tls-gnu.c b/src/tls-gnu.c
index a265e9af7..f6be70863 100644
--- a/src/tls-gnu.c
+++ b/src/tls-gnu.c
@@ -574,24 +574,31 @@ msg = rc == GNUTLS_E_FATAL_ALERT_RECEIVED
: rc == GNUTLS_E_PREMATURE_TERMINATION && errno
? string_sprintf("%s: syscall: %s", US gnutls_strerror(rc), strerror(errno))
#endif
: US gnutls_strerror(rc);
(void) tls_error(when, msg, state->host, &errstr);
-if (state->host)
- log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection %s",
- state->host->name, state->host->address, errstr);
-else
+if (!state->host)
{
uschar * conn_info = smtp_get_connection_info();
if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5;
/* I'd like to get separated H= here, but too hard for now */
log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr);
}
+else if ( !tls_out.smtp_quit
+#ifdef GNUTLS_E_PREMATURE_TERMINATION
+ || rc != GNUTLS_E_PREMATURE_TERMINATION
+#endif
+ )
+ log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection %s",
+ state->host->name, state->host->address, errstr);
+else DEBUG(D_tls)
+ debug_printf("H=%s [%s] TLS error on connection %s\n",
+ state->host->name, state->host->address, errstr);
}
static BOOL
tls_refill(unsigned lim)
{
diff --git a/src/transports/smtp.c b/src/transports/smtp.c
index d7cd93d6e..808c1a76d 100644
--- a/src/transports/smtp.c
+++ b/src/transports/smtp.c
@@ -2376,14 +2376,15 @@ if (continue_hostname && continue_proxy_cipher)
"due to SNI mismatch (transport requirement '%s')\n",
continue_proxy_sni, sni);
smtp_debug_cmd(US"QUIT", 0);
if (write(0, "QUIT\r\n", 6) < 0)
DEBUG(D_any) debug_printf("stupid compiler\n");
close(0);
+ tls_out.active.sock = -1;
continue_hostname = continue_proxy_cipher = NULL;
f.continue_more = FALSE;
continue_sequence = 1; /* Ensure proper logging of non-cont-conn */
}
}
#endif /*!DISABLE_TLS*/
@@ -2877,14 +2878,15 @@ else
DEBUG(D_transport)
debug_printf("Closing continued connection due to port mismatch:"
" %d/%d\n", sx->conn_args.host->port, continue_host_port);
smtp_debug_cmd(US"QUIT", 0);
if (write(0, "QUIT\r\n", 6) < 0)
DEBUG(D_any) debug_printf("stupid compiler\n");
close(0);
+ tls_out.active.sock = -1;
continue_hostname = continue_proxy_cipher = NULL;
f.continue_more = FALSE;
continue_sequence = 1; /* Ensure proper logging of non-cont-conn */
return smtp_setup_conn(sx, suppress_tls);
}
}
@@ -3022,14 +3024,15 @@ if ( smtp_peer_options & OPTION_TLS
# endif
errno = ERRNO_TLSFAILURE;
message = string_sprintf("TLS session: %s", tls_errstr);
sx->send_quit = FALSE;
goto TLS_FAILED;
}
+ tls_out.smtp_quit = FALSE;
sx->send_tlsclose = TRUE;
# ifdef TCP_FASTOPEN
if (sx->smtps) tfo_out_check(sx->cctx.sock);
# endif
/* TLS session is set up. Check the inblock fill level. If there is
@@ -3479,15 +3482,18 @@ FAILED:
&sx->delivery_start);
}
SEND_QUIT:
if (sx->send_quit)
+ {
(void)smtp_write_command(sx, SCMD_FLUSH, "QUIT\r\n");
+ tls_out.smtp_quit = TRUE;
+ }
#ifndef DISABLE_TLS
if (sx->cctx.tls_ctx)
{
if (sx->send_tlsclose)
{
tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
@@ -4471,14 +4477,15 @@ else
tls_shutdown_wr(sx->cctx.tls_ctx);
sx->send_tlsclose = FALSE; /* avoid later repeat */
}
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(shutdown)>>\n");
shutdown(sx->cctx.sock, SHUT_WR); /* flush output buffer, with TCP FIN */
}
+ tls_out.smtp_quit = TRUE;
}
if (smtp_peer_options & OPTION_CHUNKING && sx->cmd_count > 1)
{
/* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */
switch(sync_responses(sx, sx->cmd_count-1, 0))
{
@@ -5165,14 +5172,18 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
been passed to another process. */
SEND_QUIT:
if (sx->send_quit)
{ /* Use _MORE to get QUIT in FIN segment */
(void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n");
#ifndef DISABLE_TLS
+ /* This flag is a custom hack to avoid logging, under GnuTLS, Google's
+ habit of just dropping the TCP conn (which violates TLS spec) */
+ tls_out.smtp_quit = TRUE;
+
if (sx->cctx.tls_ctx && sx->send_tlsclose)
{
# ifdef EXIM_TCP_CORK /* Use _CORK to get TLS Close Notify in FIN segment */
(void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
# endif
tls_shutdown_wr(sx->cctx.tls_ctx);
sx->send_tlsclose = FALSE;
@@ -5352,14 +5363,15 @@ sx.outblock.cctx = &cctx;
sx.outblock.buffersize = sizeof(outbuffer);
sx.outblock.buffer = outbuffer;
sx.outblock.ptr = outbuffer;
sx.outblock.cmd_count = 0;
sx.outblock.authenticating = FALSE;
(void)smtp_write_command(&sx, SCMD_FLUSH, "QUIT\r\n");
+tls_out.smtp_quit = TRUE;
(void)smtp_read_response(&sx, buffer, sizeof(buffer), '2', ob->command_timeout);
(void)close(cctx.sock);
}
--
2.51.0
|