--- src/global/mail_params.h.orig Thu Jul 27 09:48:44 2006 +++ src/global/mail_params.h Sun Aug 27 01:50:27 2006 @@ -1924,6 +1924,12 @@ #define REJECT_UNAUTH_PIPE "reject_unauth_pipelining" +#define CONN_COUNT_LIMIT "client_connection_count_limit" +#define CONN_RATE_LIMIT "client_connection_rate_limit" +#define MAIL_RATE_LIMIT "client_message_rate_limit" +#define RCPT_RATE_LIMIT "client_recipient_rate_limit" +#define NTLS_RATE_LIMIT "client_new_tls_session_rate_limit" + #define VAR_SMTPD_NULL_KEY "smtpd_null_access_lookup_key" #define DEF_SMTPD_NULL_KEY "<>" extern char *var_smtpd_null_key; --- src/smtpd/smtpd.c.orig Tue Aug 22 22:53:52 2006 +++ src/smtpd/smtpd.c Sun Aug 27 01:57:12 2006 @@ -1917,10 +1917,10 @@ if (SMTPD_STAND_ALONE(state) == 0 && !xclient_allowed && anvil_clnt - && var_smtpd_cmail_limit > 0 && !namadr_list_match(hogger_list, state->name, state->addr) && anvil_clnt_mail(anvil_clnt, state->service, state->addr, &rate) == ANVIL_STAT_OK + && var_smtpd_cmail_limit > 0 && rate > var_smtpd_cmail_limit) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "450 4.7.1 Error: too much mail from %s", @@ -2204,10 +2204,10 @@ if (SMTPD_STAND_ALONE(state) == 0 && !xclient_allowed && anvil_clnt - && var_smtpd_crcpt_limit > 0 && !namadr_list_match(hogger_list, state->name, state->addr) && anvil_clnt_rcpt(anvil_clnt, state->service, state->addr, &rate) == ANVIL_STAT_OK + && var_smtpd_crcpt_limit > 0 && rate > var_smtpd_crcpt_limit) { state->error_mask |= MAIL_ERROR_POLICY; msg_warn("Recipient address rate limit exceeded: %d from %s for service %s", @@ -3555,8 +3555,7 @@ * of client address information in connect and disconnect events. For * now we exclude xclient authorized hosts from event count/rate control. */ - if (var_smtpd_cntls_limit > 0 - && state->tls_context + if (state->tls_context && state->tls_context->session_reused == 0 && SMTPD_STAND_ALONE(state) == 0 && !xclient_allowed @@ -3564,6 +3563,7 @@ && !namadr_list_match(hogger_list, state->name, state->addr) && anvil_clnt_newtls(anvil_clnt, state->service, state->addr, &rate) == ANVIL_STAT_OK + && var_smtpd_cntls_limit > 0 && rate > var_smtpd_cntls_limit) { state->error_mask |= MAIL_ERROR_POLICY; msg_warn("New TLS session rate limit exceeded: %d from %s for service %s", @@ -3644,13 +3644,13 @@ * of client address information in connect and disconnect events. For * now we exclude xclient authorized hosts from event count/rate control. */ - if (var_smtpd_cntls_limit > 0 - && SMTPD_STAND_ALONE(state) == 0 + if (SMTPD_STAND_ALONE(state) == 0 && !xclient_allowed && anvil_clnt && !namadr_list_match(hogger_list, state->name, state->addr) && anvil_clnt_newtls_stat(anvil_clnt, state->service, state->addr, &rate) == ANVIL_STAT_OK + && var_smtpd_cntls_limit > 0 && rate > var_smtpd_cntls_limit) { state->error_mask |= MAIL_ERROR_POLICY; msg_warn("Refusing STARTTLS request from %s for service %s", @@ -3819,12 +3819,12 @@ state->namaddr, state->service); break; } - if (var_smtpd_cntls_limit > 0 - && !xclient_allowed + if (!xclient_allowed && anvil_clnt && !namadr_list_match(hogger_list, state->name, state->addr) && anvil_clnt_newtls_stat(anvil_clnt, state->service, state->addr, &tls_rate) == ANVIL_STAT_OK + && var_smtpd_cntls_limit > 0 && tls_rate > var_smtpd_cntls_limit) { state->error_mask |= MAIL_ERROR_POLICY; msg_warn("Refusing TLS service request from %s for service %s", @@ -4375,9 +4375,11 @@ /* * Connection rate management. */ + /* if (var_smtpd_crate_limit || var_smtpd_cconn_limit || var_smtpd_cmail_limit || var_smtpd_crcpt_limit || var_smtpd_cntls_limit) + */ anvil_clnt = anvil_clnt_create(); } --- src/smtpd/smtpd_check.c.orig Sat Jul 8 05:32:43 2006 +++ src/smtpd/smtpd_check.c Sun Aug 27 02:10:31 2006 @@ -237,6 +237,7 @@ #include #include #include +#include /* Application-specific. */ @@ -347,6 +348,11 @@ static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *); /* + * rate control. + */ +extern ANVIL_CLNT *anvil_clnt; + + /* * YASLM. */ #define STR vstring_str @@ -3428,6 +3434,8 @@ ARGV *list; int found; int saved_recursion = state->recursion++; + int rate_mail, rate_rcpt, rate_newtls; + int anvil_stat = ANVIL_STAT_FAIL; if (msg_verbose) msg_info(">>> START %s RESTRICTIONS <<<", reply_class); @@ -3470,6 +3478,15 @@ } /* + * rate control. + */ + if(anvil_clnt) + anvil_stat = anvil_clnt_lookup(anvil_clnt, + state->service, state->addr, + &state->conn_count, &state->conn_rate, + &rate_mail, &rate_rcpt, &rate_newtls); + + /* * Generic restrictions. */ if (strcasecmp(name, PERMIT_ALL) == 0) { @@ -3796,6 +3813,99 @@ status = reject_unverified_address(state, state->recipient, state->recipient, SMTPD_NAME_RECIPIENT, var_unv_rcpt_code); + } + + /* + * rate control. + */ + else if (strcasecmp(name, CONN_COUNT_LIMIT) == 0) { + if (cpp[1] == 0 || alldig(cpp[1]) == 0) { + msg_warn("restriction %s must be followed by number", CONN_COUNT_LIMIT); + longjmp(smtpd_check_buf, + smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + 451, "4.3.5", + "Server configuration error")); + } else { + cpp += 1; + if(anvil_stat == ANVIL_STAT_OK + && state->conn_count > atoi(*cpp)) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + 421, "4.7.0", + "Connection concurrency limit exceeded"); + } + } + } + else if (strcasecmp(name, CONN_RATE_LIMIT) == 0) { + if (cpp[1] == 0 || alldig(cpp[1]) == 0) { + msg_warn("restriction %s must be followed by number", CONN_RATE_LIMIT); + longjmp(smtpd_check_buf, + smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + 451, "4.3.5", + "Server configuration error")); + } else { + cpp += 1; + if(anvil_stat == ANVIL_STAT_OK + && state->conn_rate > atoi(*cpp)) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + 421, "4.7.0", + "Connection rate limit exceeded"); + } + } + } + else if (strcasecmp(name, MAIL_RATE_LIMIT) == 0) { + if (cpp[1] == 0 || alldig(cpp[1]) == 0) { + msg_warn("restriction %s must be followed by number", MAIL_RATE_LIMIT); + longjmp(smtpd_check_buf, + smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + 451, "4.3.5", + "Server configuration error")); + } else { + cpp += 1; + if(anvil_stat == ANVIL_STAT_OK + && rate_mail > atoi(*cpp)) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + 450, "4.7.1", + "Message delivery request rate limit exceeded"); + } + } + } + else if (strcasecmp(name, RCPT_RATE_LIMIT) == 0) { + if (cpp[1] == 0 || alldig(cpp[1]) == 0) { + msg_warn("restriction %s must be followed by number", RCPT_RATE_LIMIT); + longjmp(smtpd_check_buf, + smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + 451, "4.3.5", + "Server configuration error")); + } else { + cpp += 1; + if(anvil_stat == ANVIL_STAT_OK + && rate_rcpt > atoi(*cpp)) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + 450, "4.7.1", + "Recipient address rate limit exceeded"); + } + } + } + else if (strcasecmp(name, NTLS_RATE_LIMIT) == 0) { + if (cpp[1] == 0 || alldig(cpp[1]) == 0) { + msg_warn("restriction %s must be followed by number", NTLS_RATE_LIMIT); + longjmp(smtpd_check_buf, + smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + 451, "4.3.5", + "Server configuration error")); + } +#ifdef USE_TLS + else { + cpp += 1; + if(state->tls_context + && anvil_stat == ANVIL_STAT_OK + && rate_newtls > atoi(*cpp)) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + 450, "4.7.1", + "New TLS session rate limit exceeded"); + } + } +#endif } /*