dovecot-2.2: director: If we detect that a user is being proxied...

dovecot at dovecot.org dovecot at dovecot.org
Mon Jun 2 01:17:51 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/8aa0cd95d6a8
changeset: 17419:8aa0cd95d6a8
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Jun 02 04:16:08 2014 +0300
description:
director: If we detect that a user is being proxied to multiple backends, disconnect wrong connections.
Especially IMAP connections can otherwise stay alive for a long time and
cause problems.

diffstat:

 src/director/director-connection.c |  31 +++++++++++++++++++++++++++++++
 src/director/director.c            |  22 ++++++++++++++++++++++
 src/director/director.h            |   5 +++++
 src/login-common/login-proxy.c     |  15 +++++++++++++--
 4 files changed, 71 insertions(+), 2 deletions(-)

diffs (144 lines):

diff -r 64808a9703db -r 8aa0cd95d6a8 src/director/director-connection.c
--- a/src/director/director-connection.c	Mon Jun 02 04:00:19 2014 +0300
+++ b/src/director/director-connection.c	Mon Jun 02 04:16:08 2014 +0300
@@ -531,6 +531,11 @@
 			/* keep the host */
 			host = user->host;
 		}
+		/* especially IMAP connections can take a long time to die.
+		   make sure we kill off the connections in the wrong
+		   backends. */
+		director_kick_user_hash(dir, dir->self_host, NULL,
+					username_hash, &host->ip);
 		ret = TRUE;
 	}
 	if (user->host != host) {
@@ -958,6 +963,30 @@
 }
 
 static bool
+director_cmd_user_kick_hash(struct director_connection *conn,
+			    const char *const *args)
+{
+	struct director_host *dir_host;
+	unsigned int username_hash;
+	struct ip_addr except_ip;
+	int ret;
+
+	if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+		return ret > 0;
+
+	if (str_array_length(args) != 2 ||
+	    str_to_uint(args[0], &username_hash) < 0 ||
+	    net_addr2ip(args[1], &except_ip) < 0) {
+		director_cmd_error(conn, "Invalid parameters");
+		return FALSE;
+	}
+
+	director_kick_user_hash(conn->dir, conn->host, dir_host,
+				username_hash, &except_ip);
+	return TRUE;
+}
+
+static bool
 director_cmd_user_killed(struct director_connection *conn,
 			 const char *const *args)
 {
@@ -1337,6 +1366,8 @@
 		return director_cmd_user_move(conn, args);
 	if (strcmp(cmd, "USER-KICK") == 0)
 		return director_cmd_user_kick(conn, args);
+	if (strcmp(cmd, "USER-KICK-HASH") == 0)
+		return director_cmd_user_kick_hash(conn, args);
 	if (strcmp(cmd, "USER-KILLED") == 0)
 		return director_cmd_user_killed(conn, args);
 	if (strcmp(cmd, "USER-KILLED-EVERYWHERE") == 0)
diff -r 64808a9703db -r 8aa0cd95d6a8 src/director/director.c
--- a/src/director/director.c	Mon Jun 02 04:00:19 2014 +0300
+++ b/src/director/director.c	Mon Jun 02 04:16:08 2014 +0300
@@ -782,6 +782,28 @@
 	director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK, cmd);
 }
 
+void director_kick_user_hash(struct director *dir, struct director_host *src,
+			     struct director_host *orig_src,
+			     unsigned int username_hash,
+			     const struct ip_addr *except_ip)
+{
+	const char *cmd;
+
+	cmd = t_strdup_printf("proxy\t*\tKICK-DIRECTOR-HASH\t%u\t%s",
+			      username_hash, net_ip2addr(except_ip));
+	ipc_client_cmd(dir->ipc_proxy, cmd,
+		       director_kick_user_callback, (void *)NULL);
+
+	if (orig_src == NULL) {
+		orig_src = dir->self_host;
+		orig_src->last_seq++;
+	}
+	cmd = t_strdup_printf("USER-KICK-HASH\t%s\t%u\t%u\t%u\t%s\n",
+		net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
+		username_hash, net_ip2addr(except_ip));
+	director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK, cmd);
+}
+
 void director_user_killed(struct director *dir, unsigned int username_hash)
 {
 	struct user *user;
diff -r 64808a9703db -r 8aa0cd95d6a8 src/director/director.h
--- a/src/director/director.h	Mon Jun 02 04:00:19 2014 +0300
+++ b/src/director/director.h	Mon Jun 02 04:16:08 2014 +0300
@@ -136,6 +136,11 @@
 void director_kick_user(struct director *dir, struct director_host *src,
 			struct director_host *orig_src, const char *username)
 	ATTR_NULL(3);
+void director_kick_user_hash(struct director *dir, struct director_host *src,
+			     struct director_host *orig_src,
+			     unsigned int username_hash,
+			     const struct ip_addr *except_ip)
+	ATTR_NULL(3);
 void director_user_killed(struct director *dir, unsigned int username_hash);
 void director_user_killed_everywhere(struct director *dir,
 				     struct director_host *src,
diff -r 64808a9703db -r 8aa0cd95d6a8 src/login-common/login-proxy.c
--- a/src/login-common/login-proxy.c	Mon Jun 02 04:00:19 2014 +0300
+++ b/src/login-common/login-proxy.c	Mon Jun 02 04:16:08 2014 +0300
@@ -650,17 +650,27 @@
 login_proxy_cmd_kick_director_hash(struct ipc_cmd *cmd, const char *const *args)
 {
 	struct login_proxy *proxy, *next;
+	struct ip_addr except_ip;
 	unsigned int hash, count = 0;
 
 	if (args[0] == NULL || str_to_uint(args[0], &hash) < 0) {
 		ipc_cmd_fail(&cmd, "Invalid parameters");
 		return;
 	}
+	/* optional except_ip parameter specifies that we're not killing the
+	   connections that are proxying to the except_ip backend */
+	except_ip.family = 0;
+	if (args[1] != NULL && args[1][0] != '\0' &&
+	    net_addr2ip(args[1], &except_ip) < 0) {
+		ipc_cmd_fail(&cmd, "Invalid except_ip parameter");
+		return;
+	}
 
 	for (proxy = login_proxies; proxy != NULL; proxy = next) {
 		next = proxy->next;
 
-		if (director_username_hash(proxy->client) == hash) {
+		if (director_username_hash(proxy->client) == hash &&
+		    !net_ip_compare(&proxy->ip, &except_ip)) {
 			login_proxy_free_reason(&proxy, KILLED_BY_ADMIN_REASON);
 			count++;
 		}
@@ -668,7 +678,8 @@
 	for (proxy = login_proxies_pending; proxy != NULL; proxy = next) {
 		next = proxy->next;
 
-		if (director_username_hash(proxy->client) == hash) {
+		if (director_username_hash(proxy->client) == hash &&
+		    !net_ip_compare(&proxy->ip, &except_ip)) {
 			client_destroy(proxy->client, "Connection kicked");
 			count++;
 		}


More information about the dovecot-cvs mailing list