Mercurial > dnsbl
comparison src/dnsbl.cpp @ 136:f4746d8a12a3
add smtp auth rate limits
author | carl |
---|---|
date | Tue, 26 Sep 2006 13:59:14 -0700 |
parents | f9917ce924a3 |
children | a6190f7798f4 |
comparison
equal
deleted
inserted
replaced
135:8e813497582e | 136:f4746d8a12a3 |
---|---|
84 | 84 |
85 pthread_mutex_t config_mutex; | 85 pthread_mutex_t config_mutex; |
86 pthread_mutex_t syslog_mutex; | 86 pthread_mutex_t syslog_mutex; |
87 pthread_mutex_t resolve_mutex; | 87 pthread_mutex_t resolve_mutex; |
88 pthread_mutex_t fd_pool_mutex; | 88 pthread_mutex_t fd_pool_mutex; |
89 pthread_mutex_t rate_mutex; | |
89 | 90 |
90 std::set<int> fd_pool; | 91 std::set<int> fd_pool; |
91 int NULL_SOCKET = -1; | 92 int NULL_SOCKET = -1; |
92 const time_t ERROR_SOCKET_TIME = 60; // number of seconds between attempts to open a socket to the dns resolver process | 93 const time_t ERROR_SOCKET_TIME = 60; // number of seconds between attempts to open a socket to the dns resolver process |
93 char *resolver_port = NULL; // unix domain socket to talk to the dns resolver process | 94 char *resolver_port = NULL; // unix domain socket to talk to the dns resolver process |
94 int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests | 95 int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests |
95 time_t last_error_time; | 96 time_t last_error_time; |
96 int resolver_sock_count = 0; // protected with fd_pool_mutex | 97 int resolver_sock_count = 0; // protected with fd_pool_mutex |
97 int resolver_pool_size = 0; // protected with fd_pool_mutex | 98 int resolver_pool_size = 0; // protected with fd_pool_mutex |
99 rcpt_rates rcpt_counts; // protected with rate_mutex | |
98 | 100 |
99 | 101 |
100 struct ns_map { | 102 struct ns_map { |
101 // all the strings are owned by the keys/values in the ns_host string map | 103 // all the strings are owned by the keys/values in the ns_host string map |
102 string_map ns_host; // nameserver name -> host name that uses this name server | 104 string_map ns_host; // nameserver name -> host name that uses this name server |
137 #else | 139 #else |
138 int answer; // without a resolver, we return a single ip4 address, 0 == no answer | 140 int answer; // without a resolver, we return a single ip4 address, 0 == no answer |
139 #endif | 141 #endif |
140 } __attribute__ ((packed)); | 142 } __attribute__ ((packed)); |
141 | 143 |
144 | |
145 //////////////////////////////////////////////// | |
146 // helper to manipulate recipient counts | |
147 // | |
148 int incr_rcpt_count(char *user); | |
149 int incr_rcpt_count(char *user) { | |
150 pthread_mutex_lock(&rate_mutex); | |
151 rcpt_rates::iterator i = rcpt_counts.find(user); | |
152 int c = (i == rcpt_counts.end()) ? 0 : (*i).second; | |
153 rcpt_counts[user] = c++; | |
154 pthread_mutex_unlock(&rate_mutex); | |
155 return c; | |
156 } | |
142 | 157 |
143 //////////////////////////////////////////////// | 158 //////////////////////////////////////////////// |
144 // helper to discard the strings held by a context_map | 159 // helper to discard the strings held by a context_map |
145 // | 160 // |
146 void discard(context_map &cm); | 161 void discard(context_map &cm); |
222 pthread_mutex_unlock(&config_mutex); | 237 pthread_mutex_unlock(&config_mutex); |
223 get_fd(); | 238 get_fd(); |
224 ip = 0; | 239 ip = 0; |
225 mailaddr = NULL; | 240 mailaddr = NULL; |
226 queueid = NULL; | 241 queueid = NULL; |
227 authenticated = false; | 242 authenticated = NULL; |
228 have_whites = false; | 243 have_whites = false; |
229 only_whites = true; | 244 only_whites = true; |
230 memory = NULL; | 245 memory = NULL; |
231 scanner = NULL; | 246 scanner = NULL; |
232 content_suffix = NULL; | 247 content_suffix = NULL; |
243 pthread_mutex_unlock(&config_mutex); | 258 pthread_mutex_unlock(&config_mutex); |
244 reset(true); | 259 reset(true); |
245 } | 260 } |
246 | 261 |
247 void mlfiPriv::reset(bool final) { | 262 void mlfiPriv::reset(bool final) { |
248 if (mailaddr) free(mailaddr); | 263 if (mailaddr) free(mailaddr); |
249 if (queueid) free(queueid); | 264 if (queueid) free(queueid); |
265 if (authenticated) free(authenticated); | |
250 discard(env_to); | 266 discard(env_to); |
251 if (memory) delete memory; | 267 if (memory) delete memory; |
252 if (scanner) delete scanner; | 268 if (scanner) delete scanner; |
253 if (!final) { | 269 if (!final) { |
254 mailaddr = NULL; | 270 mailaddr = NULL; |
255 queueid = NULL; | 271 queueid = NULL; |
256 authenticated = false; | 272 authenticated = NULL; |
257 have_whites = false; | 273 have_whites = false; |
258 only_whites = true; | 274 only_whites = true; |
259 memory = NULL; | 275 memory = NULL; |
260 scanner = NULL; | 276 scanner = NULL; |
261 content_suffix = NULL; | 277 content_suffix = NULL; |
910 | 926 |
911 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) | 927 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) |
912 { | 928 { |
913 mlfiPriv &priv = *MLFIPRIV; | 929 mlfiPriv &priv = *MLFIPRIV; |
914 priv.mailaddr = to_lower_string(from[0]); | 930 priv.mailaddr = to_lower_string(from[0]); |
915 priv.authenticated = (smfi_getsymval(ctx, "{auth_authen}") != NULL); | 931 priv.authenticated = smfi_getsymval(ctx, "{auth_authen}"); |
932 if (priv.authenticated) priv.authenticated = strdup(priv.authenticated); | |
916 return SMFIS_CONTINUE; | 933 return SMFIS_CONTINUE; |
917 } | 934 } |
918 | 935 |
919 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt) | 936 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt) |
920 { | 937 { |
934 } | 951 } |
935 free(loto); | 952 free(loto); |
936 char *fromvalue = con.find_from(priv.mailaddr); | 953 char *fromvalue = con.find_from(priv.mailaddr); |
937 status st; | 954 status st; |
938 if (priv.authenticated) { | 955 if (priv.authenticated) { |
939 st = white; | 956 int c = incr_rcpt_count(priv.authenticated); |
957 int l = dc.default_context->find_rate(priv.authenticated); | |
958 if (c > l) { | |
959 smfi_setreply(ctx, "550", "5.7.1", "recipient rate limit exceeded"); | |
960 return SMFIS_REJECT; | |
961 } | |
962 else { | |
963 if (debug_syslog > 1) { | |
964 char buf[maxlen]; | |
965 char msg[maxlen]; | |
966 snprintf(msg, sizeof(msg), "authenticated id %s (%d recipients, %d limit)", priv.authenticated, c, l); | |
967 my_syslog(&priv, msg); | |
968 } | |
969 st = white; | |
970 } | |
940 } | 971 } |
941 else if (fromvalue == token_black) { | 972 else if (fromvalue == token_black) { |
942 st = black; | 973 st = black; |
943 } | 974 } |
944 else if (fromvalue == token_white) { | 975 else if (fromvalue == token_white) { |
1125 | 1156 |
1126 //////////////////////////////////////////////// | 1157 //////////////////////////////////////////////// |
1127 // thread to watch the old config files for changes | 1158 // thread to watch the old config files for changes |
1128 // and reload when needed. we also cleanup old | 1159 // and reload when needed. we also cleanup old |
1129 // configs whose reference count has gone to zero. | 1160 // configs whose reference count has gone to zero. |
1161 // we also clear the SMTP AUTH recipient counts hourly | |
1130 // | 1162 // |
1131 void* config_loader(void *arg); | 1163 void* config_loader(void *arg); |
1132 void* config_loader(void *arg) { | 1164 void* config_loader(void *arg) { |
1165 int loop = 0; | |
1133 typedef set<CONFIG *> configp_set; | 1166 typedef set<CONFIG *> configp_set; |
1134 configp_set old_configs; | 1167 configp_set old_configs; |
1135 while (loader_run) { | 1168 while (loader_run) { |
1136 sleep(180); // look for modifications every 3 minutes | 1169 sleep(180); // look for modifications every 3 minutes |
1137 if (!loader_run) break; | 1170 if (!loader_run) break; |
1171 loop++; | |
1172 if (loop == 20) { | |
1173 // three minutes thru each loop, 20 loops per hour | |
1174 // clear the recipient counts | |
1175 pthread_mutex_lock(&rate_mutex); | |
1176 rcpt_counts.clear(); | |
1177 pthread_mutex_unlock(&rate_mutex); | |
1178 } | |
1138 CONFIG &dc = *config; | 1179 CONFIG &dc = *config; |
1139 time_t then = dc.load_time; | 1180 time_t then = dc.load_time; |
1140 struct stat st; | 1181 struct stat st; |
1141 bool reload = false; | 1182 bool reload = false; |
1142 for (string_set::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) { | 1183 for (string_set::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) { |