Mercurial > dovecot > core-2.2
changeset 10298:ea209b33ef96 HEAD
anvil: Added support for penalty tracking.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 10 Nov 2009 15:06:43 -0500 |
parents | e6840e39ebc7 |
children | 9702da6d3b6a |
files | src/anvil/Makefile.am src/anvil/anvil-connection.c src/anvil/anvil-settings.c src/anvil/common.h src/anvil/main.c src/anvil/penalty.c src/anvil/penalty.h |
diffstat | 7 files changed, 179 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/anvil/Makefile.am Mon Nov 09 22:04:33 2009 -0500 +++ b/src/anvil/Makefile.am Tue Nov 10 15:06:43 2009 -0500 @@ -17,9 +17,11 @@ main.c \ anvil-connection.c \ anvil-settings.c \ - connect-limit.c + connect-limit.c \ + penalty.c noinst_HEADERS = \ anvil-connection.h \ common.h \ - connect-limit.h + connect-limit.h \ + penalty.h
--- a/src/anvil/anvil-connection.c Mon Nov 09 22:04:33 2009 -0500 +++ b/src/anvil/anvil-connection.c Tue Nov 10 15:06:43 2009 -0500 @@ -7,6 +7,7 @@ #include "master-service.h" #include "master-interface.h" #include "connect-limit.h" +#include "penalty.h" #include "anvil-connection.h" #include <stdlib.h> @@ -46,7 +47,8 @@ const char *const *args, const char **error_r) { const char *cmd = args[0]; - unsigned int count; + unsigned int value; + time_t stamp; pid_t pid; args++; @@ -57,7 +59,6 @@ } pid = strtol(args[0], NULL, 10); connect_limit_connect(connect_limit, pid, args[1]); - return 0; } else if (strcmp(cmd, "DISCONNECT") == 0) { if (args[0] == NULL || args[1] == NULL) { *error_r = "DISCONNECT: Not enough parameters"; @@ -65,10 +66,8 @@ } pid = strtol(args[0], NULL, 10); connect_limit_disconnect(connect_limit, pid, args[1]); - return 0; } else if (strcmp(cmd, "CONNECT-DUMP") == 0) { connect_limit_dump(connect_limit, conn->output); - return 0; } else if (strcmp(cmd, "KILL") == 0) { if (args[0] == NULL) { *error_r = "KILL: Not enough parameters"; @@ -80,7 +79,6 @@ } pid = strtol(args[0], NULL, 10); connect_limit_disconnect_pid(connect_limit, pid); - return 0; } else if (strcmp(cmd, "LOOKUP") == 0) { if (args[0] == NULL) { *error_r = "LOOKUP: Not enough parameters"; @@ -90,14 +88,35 @@ *error_r = "LOOKUP on a FIFO, can't send reply"; return -1; } - count = connect_limit_lookup(connect_limit, args[0]); + value = connect_limit_lookup(connect_limit, args[0]); + (void)o_stream_send_str(conn->output, + t_strdup_printf("%u\n", value)); + } else if (strcmp(cmd, "PENALTY-GET") == 0) { + if (args[0] == NULL) { + *error_r = "PENALTY-GET: Not enough parameters"; + return -1; + } + value = penalty_get(penalty, args[0], &stamp); (void)o_stream_send_str(conn->output, - t_strdup_printf("%u\n", count)); - return 0; + t_strdup_printf("%u %s\n", value, dec2str(stamp))); + } else if (strcmp(cmd, "PENALTY-SET") == 0) { + if (args[0] == NULL || args[1] == NULL) { + *error_r = "PENALTY-SET: Not enough parameters"; + return -1; + } + penalty_set(penalty, args[0], strtoul(args[1], NULL, 10)); + } else if (strcmp(cmd, "PENALTY-SET-EXPIRE-SECS") == 0) { + if (args[0] == NULL) { + *error_r = "PENALTY-SET-EXPIRE-SECS: " + "Not enough parameters"; + return -1; + } + penalty_set_expire_secs(penalty, atoi(args[0])); } else { *error_r = t_strconcat("Unknown command: ", cmd, NULL); return -1; } + return 0; } static void anvil_connection_input(void *context)
--- a/src/anvil/anvil-settings.c Mon Nov 09 22:04:33 2009 -0500 +++ b/src/anvil/anvil-settings.c Tue Nov 10 15:06:43 2009 -0500 @@ -9,10 +9,12 @@ /* <settings checks> */ static struct file_listener_settings anvil_unix_listeners_array[] = { - { "anvil", 0600, "", "" } + { "anvil", 0600, "", "" }, + { "anvil-auth-penalty", 0600, "", "" } }; static struct file_listener_settings *anvil_unix_listeners[] = { - &anvil_unix_listeners_array[0] + &anvil_unix_listeners_array[0], + &anvil_unix_listeners_array[1] }; static buffer_t anvil_unix_listeners_buf = { anvil_unix_listeners, sizeof(anvil_unix_listeners), { 0, }
--- a/src/anvil/common.h Mon Nov 09 22:04:33 2009 -0500 +++ b/src/anvil/common.h Tue Nov 10 15:06:43 2009 -0500 @@ -4,5 +4,6 @@ #include "lib.h" extern struct connect_limit *connect_limit; +extern struct penalty *penalty; #endif
--- a/src/anvil/main.c Mon Nov 09 22:04:33 2009 -0500 +++ b/src/anvil/main.c Tue Nov 10 15:06:43 2009 -0500 @@ -6,9 +6,11 @@ #include "master-service.h" #include "master-interface.h" #include "connect-limit.h" +#include "penalty.h" #include "anvil-connection.h" struct connect_limit *connect_limit; +struct penalty *penalty; static void client_connected(const struct master_service_connection *conn) { @@ -27,9 +29,11 @@ master_service_init_log(master_service, "anvil: "); master_service_init_finish(master_service); connect_limit = connect_limit_init(); + penalty = penalty_init(); master_service_run(master_service, client_connected); + penalty_deinit(&penalty); connect_limit_deinit(&connect_limit); anvil_connections_destroy_all(); master_service_deinit(&master_service);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/anvil/penalty.c Tue Nov 10 15:06:43 2009 -0500 @@ -0,0 +1,125 @@ +/* Copyright (C) 2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "hash.h" +#include "llist.h" +#include "penalty.h" + +#include <time.h> + +#define PENALTY_DEFAULT_EXPIRE_SECS (60*60) + +struct penalty_rec { + /* ordered by last_update */ + struct penalty_rec *prev, *next; + + char *ident; + unsigned int penalty; + time_t last_update; +}; + +struct penalty { + /* ident => penalty_rec */ + struct hash_table *hash; + struct penalty_rec *oldest, *newest; + + unsigned int expire_secs; + struct timeout *to; +}; + +struct penalty *penalty_init(void) +{ + struct penalty *penalty; + + penalty = i_new(struct penalty, 1); + penalty->hash = + hash_table_create(default_pool, default_pool, 0, + str_hash, (hash_cmp_callback_t *)strcmp); + penalty->expire_secs = PENALTY_DEFAULT_EXPIRE_SECS; + return penalty; +} + +static void penalty_rec_free(struct penalty *penalty, struct penalty_rec *rec) +{ + DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec); + i_free(rec->ident); + i_free(rec); +} + +void penalty_deinit(struct penalty **_penalty) +{ + struct penalty *penalty = *_penalty; + + *_penalty = NULL; + + while (penalty->oldest != NULL) + penalty_rec_free(penalty, penalty->oldest); + hash_table_destroy(&penalty->hash); + + if (penalty->to != NULL) + timeout_remove(&penalty->to); + i_free(penalty); +} + +void penalty_set_expire_secs(struct penalty *penalty, unsigned int expire_secs) +{ + penalty->expire_secs = expire_secs; +} + +unsigned int penalty_get(struct penalty *penalty, const char *ident, + time_t *last_update_r) +{ + struct penalty_rec *rec; + + rec = hash_table_lookup(penalty->hash, ident); + if (rec == NULL) { + *last_update_r = 0; + return 0; + } else { + *last_update_r = rec->last_update; + return rec->penalty; + } +} + +static void penalty_timeout(struct penalty *penalty) +{ + time_t expire_time; + + expire_time = ioloop_time - penalty->expire_secs; + while (penalty->oldest != NULL && + penalty->oldest->last_update <= expire_time) { + hash_table_remove(penalty->hash, penalty->oldest->ident); + penalty_rec_free(penalty, penalty->oldest); + } + + timeout_remove(&penalty->to); + if (penalty->oldest != NULL) { + unsigned int diff = penalty->oldest->last_update - expire_time; + penalty->to = timeout_add(diff * 1000, + penalty_timeout, penalty); + } +} + +void penalty_set(struct penalty *penalty, const char *ident, + unsigned int value) +{ + struct penalty_rec *rec; + + rec = hash_table_lookup(penalty->hash, ident); + if (rec == NULL) { + rec = i_new(struct penalty_rec, 1); + rec->ident = i_strdup(ident); + hash_table_insert(penalty->hash, rec->ident, rec); + } else { + DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec); + } + rec->penalty = value; + rec->last_update = time(NULL); + DLLIST2_APPEND(&penalty->oldest, &penalty->newest, rec); + + if (penalty->to == NULL) { + penalty->to = timeout_add(penalty->expire_secs * 1000, + penalty_timeout, penalty); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/anvil/penalty.h Tue Nov 10 15:06:43 2009 -0500 @@ -0,0 +1,14 @@ +#ifndef PENALTY_H +#define PENALTY_H + +struct penalty *penalty_init(void); +void penalty_deinit(struct penalty **penalty); + +void penalty_set_expire_secs(struct penalty *penalty, unsigned int expire_secs); + +unsigned int penalty_get(struct penalty *penalty, const char *ident, + time_t *last_update_r); +void penalty_set(struct penalty *penalty, const char *ident, + unsigned int value); + +#endif