Mercurial > dnsbl
comparison src/dnsbl.cpp @ 278:368572c57013
add limits on unique ip addresses per hour per authenticated user
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 17 Dec 2013 15:35:23 -0800 |
parents | a99b6c1f5f67 |
children | 2b77295fb9a7 |
comparison
equal
deleted
inserted
replaced
277:7163e9b04bdb | 278:368572c57013 |
---|---|
112 int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests | 112 int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests |
113 const char *dccifd_port = NULL; // unix domain socket to talk to the dcc interface daemon | 113 const char *dccifd_port = NULL; // unix domain socket to talk to the dcc interface daemon |
114 time_t last_error_time = 0; | 114 time_t last_error_time = 0; |
115 int resolver_sock_count = 0; // protected with fd_pool_mutex | 115 int resolver_sock_count = 0; // protected with fd_pool_mutex |
116 int resolver_pool_size = 0; // protected with fd_pool_mutex | 116 int resolver_pool_size = 0; // protected with fd_pool_mutex |
117 rcpt_rates rcpt_hourly_counts; // protected with rate_mutex | 117 rates rcpt_hourly_counts; // protected with rate_mutex |
118 rcpt_rates rcpt_daily_counts; // protected with rate_mutex | 118 rates rcpt_daily_counts; // protected with rate_mutex |
119 auth_addresses auth_hourly_addresses; // protected with rate_mutex | |
120 auth_addresses auth_daily_addresses; // protected with rate_mutex | |
119 | 121 |
120 | 122 |
121 struct ns_map { | 123 struct ns_map { |
122 // all the strings are owned by the keys/values in the ns_host string map | 124 // all the strings are owned by the keys/values in the ns_host string map |
123 string_map ns_host; // nameserver name -> host name that uses this name server | 125 string_map ns_host; // nameserver name -> host name that uses this name server |
165 // helper to manipulate recipient counts | 167 // helper to manipulate recipient counts |
166 // | 168 // |
167 void incr_rcpt_count(const char *user, int &hourly, int &daily); | 169 void incr_rcpt_count(const char *user, int &hourly, int &daily); |
168 void incr_rcpt_count(const char *user, int &hourly, int &daily) { | 170 void incr_rcpt_count(const char *user, int &hourly, int &daily) { |
169 pthread_mutex_lock(&rate_mutex); | 171 pthread_mutex_lock(&rate_mutex); |
170 rcpt_rates::iterator i = rcpt_hourly_counts.find(user); | 172 rates::iterator i = rcpt_hourly_counts.find(user); |
171 hourly = 1; | 173 hourly = 1; |
172 if (i == rcpt_hourly_counts.end()) { | 174 if (i == rcpt_hourly_counts.end()) { |
173 user = strdup(user); | 175 user = strdup(user); |
174 rcpt_hourly_counts[user] = hourly; | 176 rcpt_hourly_counts[user] = hourly; |
175 } | 177 } |
176 else { | 178 else { |
177 hourly = ++((*i).second); | 179 hourly = ++((*i).second); |
178 } | 180 } |
179 | 181 |
180 rcpt_rates::iterator j = rcpt_daily_counts.find(user); | 182 rates::iterator j = rcpt_daily_counts.find(user); |
181 daily = 1; | 183 daily = 1; |
182 if (j == rcpt_daily_counts.end()) { | 184 if (j == rcpt_daily_counts.end()) { |
183 user = strdup(user); | 185 user = strdup(user); |
184 rcpt_daily_counts[user] = daily; | 186 rcpt_daily_counts[user] = daily; |
185 } | 187 } |
186 else { | 188 else { |
187 daily = ++((*j).second); | 189 daily = ++((*j).second); |
190 } | |
191 pthread_mutex_unlock(&rate_mutex); | |
192 } | |
193 | |
194 | |
195 void add_auth_address(const char *user, int &hourly, int &daily, int32_t ip); | |
196 void add_auth_address(const char *user, int &hourly, int &daily, int32_t ip) { | |
197 pthread_mutex_lock(&rate_mutex); | |
198 auth_addresses::iterator ii = auth_hourly_addresses.find(user); | |
199 if (ii == auth_hourly_addresses.end()) { | |
200 auth_hourly_addresses[user] = new int32_t_set; | |
201 auth_hourly_addresses[user]->insert(ip); | |
202 hourly = 1; | |
203 } | |
204 else { | |
205 int32_t_set::iterator i = ((*ii).second)->find(ip); | |
206 if (i == ((*ii).second)->end()) ((*ii).second)->insert(ip); | |
207 hourly = ((*ii).second)->size(); | |
208 } | |
209 | |
210 auth_addresses::iterator jj = auth_daily_addresses.find(user); | |
211 if (jj == auth_daily_addresses.end()) { | |
212 auth_daily_addresses[user] = new int32_t_set; | |
213 auth_daily_addresses[user]->insert(ip); | |
214 daily = 1; | |
215 } | |
216 else { | |
217 int32_t_set::iterator i = ((*jj).second)->find(ip); | |
218 if (i == ((*jj).second)->end()) ((*jj).second)->insert(ip); | |
219 daily = ((*jj).second)->size(); | |
188 } | 220 } |
189 pthread_mutex_unlock(&rate_mutex); | 221 pthread_mutex_unlock(&rate_mutex); |
190 } | 222 } |
191 | 223 |
192 //////////////////////////////////////////////// | 224 //////////////////////////////////////////////// |
1133 } | 1165 } |
1134 | 1166 |
1135 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) | 1167 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) |
1136 { | 1168 { |
1137 mlfiPriv &priv = *MLFIPRIV; | 1169 mlfiPriv &priv = *MLFIPRIV; |
1170 CONFIG &dc = *priv.pc; | |
1138 priv.mailaddr = to_lower_string(from[0]); | 1171 priv.mailaddr = to_lower_string(from[0]); |
1139 priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); | 1172 priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); |
1140 priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); | 1173 priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); |
1141 priv.client_name = smfi_getsymval(ctx, (char*)"_"); | 1174 priv.client_name = smfi_getsymval(ctx, (char*)"_"); |
1142 if (!priv.helo) priv.helo = strdup("unknown"); | 1175 if (!priv.helo) priv.helo = strdup("unknown"); |
1143 if (priv.authenticated) priv.authenticated = strdup(priv.authenticated); | 1176 if (priv.authenticated) priv.authenticated = strdup(priv.authenticated); |
1177 { | |
1178 const char *uid = (priv.authenticated) ? priv.authenticated : priv.mailaddr; | |
1179 if (priv.authenticated || dc.default_context->is_unauthenticated_limited(priv.mailaddr)) { | |
1180 int hourly, daily; | |
1181 add_auth_address(uid, hourly, daily, priv.ip); | |
1182 int h_limit = dc.default_context->find_address_limit(uid); | |
1183 int d_limit = dc.default_context->get_daily_address_multiple() * h_limit; | |
1184 if (debug_syslog > 1) { | |
1185 char msg[maxlen]; | |
1186 snprintf(msg, sizeof(msg), "connect for %s (%d %d addresses, %d %d limits)", uid, hourly, daily, h_limit, d_limit); | |
1187 my_syslog(&priv, msg); | |
1188 } | |
1189 if ((hourly > h_limit) || (daily > d_limit)){ | |
1190 //smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"unique connection address limit exceeded"); | |
1191 //return SMFIS_REJECT; | |
1192 } | |
1193 } | |
1194 } | |
1144 if (priv.client_name) { | 1195 if (priv.client_name) { |
1145 priv.client_name = strdup(priv.client_name); | 1196 priv.client_name = strdup(priv.client_name); |
1146 const char *p = strstr(priv.client_name, " ["); | 1197 const char *p = strstr(priv.client_name, " ["); |
1147 if (p) { | 1198 if (p) { |
1148 uint pp = p - priv.client_name; | 1199 uint pp = p - priv.client_name; |
1171 return SMFIS_CONTINUE; | 1222 return SMFIS_CONTINUE; |
1172 } | 1223 } |
1173 | 1224 |
1174 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt) | 1225 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt) |
1175 { | 1226 { |
1176 DNSBLP rejectlist = NULL; // list that caused the reject | 1227 DNSBLP rejectlist = NULL; // list that caused the reject |
1177 mlfiPriv &priv = *MLFIPRIV; | 1228 mlfiPriv &priv = *MLFIPRIV; |
1178 CONFIG &dc = *priv.pc; | 1229 CONFIG &dc = *priv.pc; |
1179 const char *rcptaddr = rcpt[0]; | 1230 const char *rcptaddr = rcpt[0]; |
1180 const char *loto = to_lower_string(rcptaddr); | 1231 const char *loto = to_lower_string(rcptaddr); |
1181 bool self = (strcmp(loto, priv.mailaddr) == 0); | 1232 bool self = (strcmp(loto, priv.mailaddr) == 0); |
1182 | 1233 |
1183 // some version of sendmail allowed rcpt to:<> and passed it thru to the milters | 1234 // some version of sendmail allowed rcpt to:<> and passed it thru to the milters |
1184 if (strcmp(loto, "<>") == 0) { | 1235 if (strcmp(loto, "<>") == 0) { |
1185 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"bogus recipient"); | 1236 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"bogus recipient"); |
1209 return SMFIS_REJECT; | 1260 return SMFIS_REJECT; |
1210 } | 1261 } |
1211 if (priv.authenticated) { | 1262 if (priv.authenticated) { |
1212 int hourly, daily; | 1263 int hourly, daily; |
1213 incr_rcpt_count(priv.authenticated, hourly, daily); | 1264 incr_rcpt_count(priv.authenticated, hourly, daily); |
1214 int h_limit = dc.default_context->find_rate(priv.authenticated); | 1265 int h_limit = dc.default_context->find_rate_limit(priv.authenticated); |
1215 int d_limit = dc.default_context->get_daily_multiple() * h_limit; | 1266 int d_limit = dc.default_context->get_daily_rate_multiple() * h_limit; |
1216 if (debug_syslog > 1) { | 1267 if (debug_syslog > 1) { |
1217 char msg[maxlen]; | 1268 char msg[maxlen]; |
1218 snprintf(msg, sizeof(msg), "authenticated id %s (%d %d recipients, %d %d limits)", priv.authenticated, hourly, daily, h_limit, d_limit); | 1269 snprintf(msg, sizeof(msg), "authenticated id %s (%d %d recipients, %d %d limits)", priv.authenticated, hourly, daily, h_limit, d_limit); |
1219 my_syslog(&priv, msg); | 1270 my_syslog(&priv, msg); |
1220 } | 1271 } |
1293 } | 1344 } |
1294 } | 1345 } |
1295 if (!priv.authenticated && dc.default_context->is_unauthenticated_limited(priv.mailaddr)) { | 1346 if (!priv.authenticated && dc.default_context->is_unauthenticated_limited(priv.mailaddr)) { |
1296 int hourly, daily; | 1347 int hourly, daily; |
1297 incr_rcpt_count(priv.mailaddr, hourly, daily); | 1348 incr_rcpt_count(priv.mailaddr, hourly, daily); |
1298 int h_limit = dc.default_context->find_rate(priv.mailaddr); | 1349 int h_limit = dc.default_context->find_rate_limit(priv.mailaddr); |
1299 int d_limit = dc.default_context->get_daily_multiple() * h_limit; | 1350 int d_limit = dc.default_context->get_daily_rate_multiple() * h_limit; |
1300 if (debug_syslog > 1) { | 1351 if (debug_syslog > 1) { |
1301 char msg[maxlen]; | 1352 char msg[maxlen]; |
1302 snprintf(msg, sizeof(msg), "unauthenticated address %s (%d %d recipients, %d %d limits)", priv.mailaddr, hourly, daily, h_limit, d_limit); | 1353 snprintf(msg, sizeof(msg), "unauthenticated address %s (%d %d recipients, %d %d limits)", priv.mailaddr, hourly, daily, h_limit, d_limit); |
1303 my_syslog(&priv, msg); | 1354 my_syslog(&priv, msg); |
1304 } | 1355 } |
1598 loop2++; | 1649 loop2++; |
1599 if (loop1 == 20) { | 1650 if (loop1 == 20) { |
1600 // three minutes thru each loop, 20 loops per hour | 1651 // three minutes thru each loop, 20 loops per hour |
1601 // clear the recipient hourly counts | 1652 // clear the recipient hourly counts |
1602 pthread_mutex_lock(&rate_mutex); | 1653 pthread_mutex_lock(&rate_mutex); |
1603 for (rcpt_rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { | 1654 for (rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { |
1604 (*i).second = 0; | 1655 (*i).second = 0; |
1656 } | |
1657 for (auth_addresses::iterator j=auth_hourly_addresses.begin(); j!=auth_hourly_addresses.end(); j++) { | |
1658 delete (*j).second; | |
1605 } | 1659 } |
1606 pthread_mutex_unlock(&rate_mutex); | 1660 pthread_mutex_unlock(&rate_mutex); |
1607 loop1 = 0; | 1661 loop1 = 0; |
1608 } | 1662 } |
1609 if (loop2 == 480) { | 1663 if (loop2 == 480) { |
1610 // three minutes thru each loop, 480 loops per day | 1664 // three minutes thru each loop, 480 loops per day |
1611 // clear the recipient daily counts | 1665 // clear the recipient daily counts |
1612 pthread_mutex_lock(&rate_mutex); | 1666 pthread_mutex_lock(&rate_mutex); |
1613 for (rcpt_rates::iterator i=rcpt_daily_counts.begin(); i!=rcpt_daily_counts.end(); i++) { | 1667 for (rates::iterator i=rcpt_daily_counts.begin(); i!=rcpt_daily_counts.end(); i++) { |
1614 (*i).second = 0; | 1668 (*i).second = 0; |
1669 } | |
1670 for (auth_addresses::iterator j=auth_daily_addresses.begin(); j!=auth_daily_addresses.end(); j++) { | |
1671 delete (*j).second; | |
1615 } | 1672 } |
1616 pthread_mutex_unlock(&rate_mutex); | 1673 pthread_mutex_unlock(&rate_mutex); |
1617 loop2 = 0; | 1674 loop2 = 0; |
1618 } | 1675 } |
1619 CONFIG &dc = *config; | 1676 CONFIG &dc = *config; |