+
+Logging protocol unusual states
+---------------------------------------------------------------
+An extra log_selector, "protocol_detail" has been added in the default build.
+The name may change in future, hence the Experimenal status.
+
+Currrently the only effect is to enable logging, under OpenSSL,
+of a TCP RST received directly after a QUIT (in server mode).
+
+Outlook is consistently doing this; not waiting for the SMTP response
+to its QUIT, not properly closing the TLS session and not properly closing
+the TCP connection. Previously this resulted is an error from SSL_write
+being logged.
+
--------------------------------------------------------------
End of file
--------------------------------------------------------------
{
if (!*user_msgptr && *log_msgptr)
*user_msgptr = string_sprintf("Rejected after %s: %s",
- smtp_names[smtp_connection_had[smtp_ch_index-1]], *log_msgptr);
+ smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]],
+ *log_msgptr);
if (rc == DEFER) f.acl_temp_details = TRUE;
}
}
/* Drop cutthrough conns, and drop heldopen verify conns if
the previous was not DATA */
{
- uschar prev = smtp_connection_had[smtp_ch_index-2];
+ uschar prev =
+ smtp_connection_had[SMTP_HBUFF_PREV(SMTP_HBUFF_PREV(smtp_ch_index))];
BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT);
cancel_cutthrough_connection(dropverify, US"quit or conndrop");
#endif
.smtp_in_pipelining_advertised = FALSE,
.smtp_in_pipelining_used = FALSE,
+ .smtp_in_quit = FALSE,
.spool_file_wireformat = FALSE,
.submission_mode = FALSE,
.suppress_local_fixups = FALSE,
BIT_TABLE(L, outgoing_port),
BIT_TABLE(L, pid),
BIT_TABLE(L, pipelining),
+ BIT_TABLE(L, protocol_detail),
#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
BIT_TABLE(L, proxy),
#endif
int smtp_max_synprot_errors= 3;
int smtp_max_unknown_commands = 3;
uschar *smtp_notquit_reason = NULL;
+unsigned smtp_peer_options = 0;
+unsigned smtp_peer_options_wrap= 0;
uschar *smtp_ratelimit_hosts = NULL;
uschar *smtp_ratelimit_mail = NULL;
uschar *smtp_ratelimit_rcpt = NULL;
double smtp_rlr_factor = 0.0;
int smtp_rlr_limit = 0;
int smtp_rlr_threshold = INT_MAX;
-unsigned smtp_peer_options = 0;
-unsigned smtp_peer_options_wrap= 0;
#ifdef SUPPORT_I18N
uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */
#endif
#endif
BOOL smtp_in_pipelining_advertised :1; /* server advertised PIPELINING */
BOOL smtp_in_pipelining_used :1; /* server noted client using PIPELINING */
+ BOOL smtp_in_quit :1; /* server noted QUIT command */
BOOL spool_file_wireformat :1; /* current -D file has CRLF rather than NL */
BOOL submission_mode :1; /* Can be forced from ACL */
BOOL suppress_local_fixups :1; /* Can be forced from ACL */
/* The size of the circular buffer that remembers recent SMTP commands */
#define SMTP_HBUFF_SIZE 20
+#define SMTP_HBUFF_PREV(n) ((n) ? (n)-1 : SMTP_HBUFF_SIZE-1)
/* The initial size of a big buffer for use in various places. It gets put
into big_buffer_size and in some circumstances increased. It should be at least
Li_outgoing_port,
Li_pid,
Li_pipelining,
+ Li_protocol_detail,
Li_proxy,
Li_queue_time,
Li_queue_time_overall,
return;
case QUIT_CMD:
+ f.smtp_in_quit = TRUE;
smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
mac_smtp_fflush();
return;
break;
- case EOF_CMD:
case QUIT_CMD:
+ f.smtp_in_quit = TRUE;
+ case EOF_CMD:
done = 2;
break;
smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp)
{
HAD(SCH_QUIT);
+f.smtp_in_quit = TRUE;
incomplete_transaction_log(US"QUIT");
-if (acl_smtp_quit)
- {
- int rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp);
- if (rc == ERROR)
+if ( acl_smtp_quit
+ && acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp)
+ == ERROR)
log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
*log_msgp);
- }
#ifdef TCP_CORK
(void) setsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_CORK, US &on, sizeof(on));
}
if (f.smtp_in_pipelining_advertised && last_was_rcpt)
smtp_printf("503 Valid RCPT command must precede %s\r\n", FALSE,
- smtp_names[smtp_connection_had[smtp_ch_index-1]]);
+ smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]]);
else
done = synprot_error(L_smtp_protocol_error, 503, NULL,
- smtp_connection_had[smtp_ch_index-1] == SCH_DATA
+ smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)] == SCH_DATA
? US"valid RCPT command must precede DATA"
: US"valid RCPT command must precede BDAT");
some sense is perhaps "right". */
case QUIT_CMD:
+ f.smtp_in_quit = TRUE;
user_msg = NULL;
if ( acl_smtp_quit
&& ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg,
a store reset there, so use POOL_PERM. */
/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
-if ((more || corked))
+if (more || corked)
{
if (!len) buff = US &error; /* dummy just so that string_catn is ok */
return -1;
case SSL_ERROR_SYSCALL:
- log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
- sender_fullhost ? sender_fullhost : US"<unknown>",
- strerror(errno));
+ if (ct_ctx || errno != ECONNRESET || !f.smtp_in_quit)
+ log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
+ sender_fullhost ? sender_fullhost : US"<unknown>",
+ strerror(errno));
+ else if (LOGGING(protocol_detail))
+ log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before"
+ " SMTP response and TLS close\n", sender_host_address);
+ else
+ DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT,"
+ " client reset TCP before TLS close\n", sender_host_address);
return -1;
default: