On 28/06/13 22:30, Wietse Venema wrote: > Wietse Venema: >> John Fawcett: >>> I use fail2ban in order to block some types of apparently malicious >>> connections to postfix when the clients keep retrying. For example the >> As you agree logging every failed command would not be safe by >> default. >> >> On the other hand, logging the command name (even without) parameters >> for every [45]XX response could be tricky. Adding IF statements all >> over the code is undesirable, so this would require a structural >> change to the command reader and responder. >> >> What about a one-line change, such that the SMTP server logs the >> existing per-session error counter when the connection is closed? >> >> This counter is reset upon successful completion of a (MAIL, RCPT, >> DATA, end-of-data) sequence. This should be sufficient to expose >> clients that hammer your server with unimplemented AUTH commands. > Example: > > Jun 28 16:27:25 spike postfix/smtpd[65532]: disconnect from > camomile.cloud9.net[2604:8d00:0:1::3] error_count 0 > > As per the patch below for any Postfix version ever released. > > Wietse > > *** ./src/smtpd/smtpd.c- Sun Jun 23 11:10:02 2013 > --- ./src/smtpd/smtpd.c Fri Jun 28 16:26:41 2013 > *************** > *** 4989,4995 **** > * After the client has gone away, clean up whatever we have set up at > * connection time. > */ > ! msg_info("disconnect from %s", state.namaddr); > smtpd_state_reset(&state); > debug_peer_restore(); > } > --- 4989,4996 ---- > * After the client has gone away, clean up whatever we have set up at > * connection time. > */ > ! msg_info("disconnect from %s error_count %d", > ! state.namaddr, state.error_count); > smtpd_state_reset(&state); > debug_peer_restore(); > } I would like to propose the following addition. As well as logging error_count as per the original patch, it also logs the number of messages accepted during the smtp session. The aim of that would be to identify clients that repeatedly connect and never attempt delivery.
diff -ur postfix-2.11-20130623/src/smtpd/smtpd.c postfix-2.11-20130623-patch/src/smtpd/smtpd.c --- postfix-2.11-20130623/src/smtpd/smtpd.c 2013-06-23 17:10:02.000000000 +0200 +++ postfix-2.11-20130623-patch/src/smtpd/smtpd.c 2013-07-01 01:36:19.000000000 +0200 @@ -3239,9 +3239,11 @@ state->junk_cmds = 0; if (proxy) smtpd_chat_reply(state, "%s", STR(proxy->buffer)); - else + else { smtpd_chat_reply(state, "250 2.0.0 Ok: queued as %s", state->queue_id); + state->msg_count++; + } } else if (why && IS_SMTP_REJECT(STR(why))) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "%s", STR(why)); @@ -4989,7 +4991,8 @@ * After the client has gone away, clean up whatever we have set up at * connection time. */ - msg_info("disconnect from %s", state.namaddr); + msg_info("disconnect from %s error_count %d msg_count %d", + state.namaddr, state.error_count,state.msg_count); smtpd_state_reset(&state); debug_peer_restore(); } diff -ur postfix-2.11-20130623/src/smtpd/smtpd.h postfix-2.11-20130623-patch/src/smtpd/smtpd.h --- postfix-2.11-20130623/src/smtpd/smtpd.h 2012-07-30 17:53:16.000000000 +0200 +++ postfix-2.11-20130623-patch/src/smtpd/smtpd.h 2013-07-01 01:35:40.000000000 +0200 @@ -87,6 +87,7 @@ int conn_count; /* connections from this client */ int conn_rate; /* connection rate for this client */ int error_count; /* reset after DOT */ + int msg_count; /* message count */ int error_mask; /* client errors */ int notify_mask; /* what to report to postmaster */ char *helo_name; /* client HELO/EHLO argument */ diff -ur postfix-2.11-20130623/src/smtpd/smtpd_state.c postfix-2.11-20130623-patch/src/smtpd/smtpd_state.c --- postfix-2.11-20130623/src/smtpd/smtpd_state.c 2012-01-15 00:13:42.000000000 +0100 +++ postfix-2.11-20130623-patch/src/smtpd/smtpd_state.c 2013-07-01 01:35:59.000000000 +0200 @@ -86,6 +86,7 @@ state->addr_buf = vstring_alloc(100); state->conn_count = state->conn_rate = 0; state->error_count = 0; + state->msg_count = 0; state->error_mask = 0; state->notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, var_notify_classes);