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;