From 570566c5a9bbf628942fa816b93d12a9df6d71d7 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sat, 8 Nov 2008 16:17:48 -0500 Subject: [PATCH] Added configuration parameter "tcp_connection_limit". This specifies the maximum number of connections for a single host. When exceeded, the client is disconnected. --- doc/config.example | 4 ++++ doc/pwmd.1.in | 3 +++ src/common.h | 2 ++ src/pwmd.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/doc/config.example b/doc/config.example index c17bac05..690f765c 100644 --- a/doc/config.example +++ b/doc/config.example @@ -99,6 +99,10 @@ # Only useful if running as root. #tcp_interface=eth0 +# Sets the maximum number of connections for a single host. If 0, no limit is +# set. +#tcp_connection_limit=5 + # END GLOBAL SETTINGS # File specific settings are allowed by placing the filename in braces. Each diff --git a/doc/pwmd.1.in b/doc/pwmd.1.in index 6be66733..5228213f 100644 --- a/doc/pwmd.1.in +++ b/doc/pwmd.1.in @@ -97,6 +97,9 @@ The port to listen on when \fIenable_tcp\fP is \fItrue\fP. The default is .I "tcp_interface=" Only useful when run as root. .TP +.I "tcp_connection_limit=" +The maximum number of connections for a single hostname. +.TP .I "data_directory=" Where .B pwmd diff --git a/src/common.h b/src/common.h index c3a4fbee..9d157b8c 100644 --- a/src/common.h +++ b/src/common.h @@ -142,6 +142,8 @@ struct client_thread_s { pth_event_t msg_ev; gchar *msg_name; gboolean remote; + gchar *addr; + struct timeval init; struct tls_s *tls; struct client_s *cl; }; diff --git a/src/pwmd.c b/src/pwmd.c index 441752b5..7b33d838 100644 --- a/src/pwmd.c +++ b/src/pwmd.c @@ -427,6 +427,9 @@ static void cleanup_cb(void *arg) gnutls_deinit(cn->tls->ses); g_free(cn->tls); } + + if (cn->addr) + g_free(cn->addr); #endif g_free(cl); @@ -822,6 +825,9 @@ static void set_rcfile_defaults(GKeyFile *kf) if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE) g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE); + + if (g_key_file_has_key(kf, "global", "tcp_connection_limit", NULL) == FALSE) + g_key_file_set_integer(kf, "global", "tcp_connection_limit", 5); #endif setup_logging(kf); @@ -1422,6 +1428,33 @@ try_decrypt: return TRUE; } +static gboolean check_host_limit(const gchar *addr) +{ + gint t, i; + gint total = 1; + gint limit = get_key_file_integer("global", "tcp_connection_limit"); + + pth_mutex_acquire(&cn_mutex, FALSE, NULL); + + for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) { + struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i); + + if (!cn->remote) + continue; + + if (strcmp(addr, cn->addr) == 0) + total++; + } + + if (limit > 0 && total > limit) { + pth_mutex_release(&cn_mutex); + return FALSE; + } + + pth_mutex_release(&cn_mutex); + return TRUE; +} + static void init_new_connection(gint fd, gchar *addr) { pth_t tid; @@ -1429,6 +1462,12 @@ static void init_new_connection(gint fd, gchar *addr) struct client_thread_s *new; gchar buf[41]; + if (addr && check_host_limit(addr) == FALSE) { + log_write(N_("host %s exceeds host limit"), addr); + close(fd); + return; + } + new = g_malloc0(sizeof(struct client_thread_s)); if (!new) { @@ -1444,8 +1483,11 @@ static void init_new_connection(gint fd, gchar *addr) pth_mutex_acquire(&cn_mutex, FALSE, NULL); new->fd = fd; - if (addr) + if (addr) { new->remote = TRUE; + new->addr = g_strdup(addr); + gettimeofday(&new->init, NULL); + } attr = pth_attr_new(); pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD); -- 2.11.4.GIT