]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
anvil: Added support for penalty tracking.
authorTimo Sirainen <tss@iki.fi>
Tue, 10 Nov 2009 20:06:43 +0000 (15:06 -0500)
committerTimo Sirainen <tss@iki.fi>
Tue, 10 Nov 2009 20:06:43 +0000 (15:06 -0500)
--HG--
branch : HEAD

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 [new file with mode: 0644]
src/anvil/penalty.h [new file with mode: 0644]

index eaf0002801f695f0a07cae2d11fb8cc63808e704..6857abe4c0fc8a699df20b2780ffe64aebc85954 100644 (file)
@@ -17,9 +17,11 @@ anvil_SOURCES = \
        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
index 07dc61b0d4d2fad229e92632e23e23d6abb316e0..432a251cedc822c01f96ee1e437e0e00204e6b1a 100644 (file)
@@ -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 @@ anvil_connection_request(struct anvil_connection *conn,
                         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 @@ anvil_connection_request(struct anvil_connection *conn,
                }
                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 @@ anvil_connection_request(struct anvil_connection *conn,
                }
                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 @@ anvil_connection_request(struct anvil_connection *conn,
                }
                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 @@ anvil_connection_request(struct anvil_connection *conn,
                        *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", count));
-               return 0;
+                                       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 %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)
index 1d7a258e27a214414d7ce659d9438364b06f3dbb..e268a907ca97f94eeb79a903369c45581bf2f45f 100644 (file)
@@ -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, }
index e6468df4e6663ac3eb00259e86e4be5ecccb8190..2620817b08fb86ca19004adc1fdff37cf6a3e9f3 100644 (file)
@@ -4,5 +4,6 @@
 #include "lib.h"
 
 extern struct connect_limit *connect_limit;
+extern struct penalty *penalty;
 
 #endif
index 31bebb1a04e478f644fafd429f01e8f7ec7eb68b..e09a678c8171b9ab31ead1f8114772c836acdaeb 100644 (file)
@@ -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 @@ int main(int argc, char *argv[])
        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);
diff --git a/src/anvil/penalty.c b/src/anvil/penalty.c
new file mode 100644 (file)
index 0000000..cd91b49
--- /dev/null
@@ -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);
+       }
+}
diff --git a/src/anvil/penalty.h b/src/anvil/penalty.h
new file mode 100644 (file)
index 0000000..7c5ac38
--- /dev/null
@@ -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