dovecot-2.2: imap/pop3/lmtp proxy: Implemented detection of prox...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 25 06:55:06 EET 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/ba06ea38c722
changeset: 14162:ba06ea38c722
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Feb 25 06:54:52 2012 +0200
description:
imap/pop3/lmtp proxy: Implemented detection of proxy loops with TTL.
If proxying tries to continue after 5 forward connections, it fails. The
limit of 5 is hard coded currently.

diffstat:

 src/imap-login/client.c          |   2 ++
 src/imap-login/imap-proxy.c      |   8 ++++++--
 src/lib-lda/lmtp-client.c        |   4 ++++
 src/lib-lda/lmtp-client.h        |   2 ++
 src/lmtp/client.c                |   1 +
 src/lmtp/client.h                |   1 +
 src/lmtp/commands.c              |  19 +++++++++++++++++--
 src/lmtp/lmtp-proxy.c            |   2 ++
 src/lmtp/lmtp-proxy.h            |   3 +++
 src/login-common/client-common.c |   1 +
 src/login-common/client-common.h |   1 +
 src/login-common/login-proxy.c   |   6 ++++++
 src/login-common/login-proxy.h   |   7 +++++++
 src/pop3-login/client.c          |   3 +++
 src/pop3-login/pop3-proxy.c      |   6 ++++--
 15 files changed, 60 insertions(+), 6 deletions(-)

diffs (283 lines):

diff -r f534ed81bce4 -r ba06ea38c722 src/imap-login/client.c
--- a/src/imap-login/client.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/imap-login/client.c	Sat Feb 25 06:54:52 2012 +0200
@@ -121,6 +121,8 @@
 			(void)net_addr2ip(value, &client->common.local_ip);
 		else if (strcasecmp(key, "x-connected-port") == 0)
 			client->common.local_port = atoi(value);
+		else if (strcasecmp(key, "x-proxy-ttl") == 0)
+			client->common.proxy_ttl = atoi(value);
 		args += 2;
 	}
 }
diff -r f534ed81bce4 -r ba06ea38c722 src/imap-login/imap-proxy.c
--- a/src/imap-login/imap-proxy.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/imap-login/imap-proxy.c	Sat Feb 25 06:54:52 2012 +0200
@@ -29,15 +29,19 @@
 
 static void proxy_write_id(struct imap_client *client, string_t *str)
 {
+	i_assert(client->common.proxy_ttl > 0);
+
 	str_printfa(str, "I ID ("
 		    "\"x-originating-ip\" \"%s\" "
 		    "\"x-originating-port\" \"%u\" "
 		    "\"x-connected-ip\" \"%s\" "
-		    "\"x-connected-port\" \"%u\")\r\n",
+		    "\"x-connected-port\" \"%u\" "
+		    "\"x-proxy-ttl\" \"%u\")\r\n",
 		    net_ip2addr(&client->common.ip),
 		    client->common.remote_port,
 		    net_ip2addr(&client->common.local_ip),
-		    client->common.local_port);
+		    client->common.local_port,
+		    client->common.proxy_ttl - 1);
 }
 
 static void proxy_free_password(struct client *client)
diff -r f534ed81bce4 -r ba06ea38c722 src/lib-lda/lmtp-client.c
--- a/src/lib-lda/lmtp-client.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lib-lda/lmtp-client.c	Sat Feb 25 06:54:52 2012 +0200
@@ -96,6 +96,7 @@
 		p_strdup(pool, set->dns_client_socket_path);
 	client->set.source_ip = set->source_ip;
 	client->set.source_port = set->source_port;
+	client->set.proxy_ttl_plus_1 = set->proxy_ttl_plus_1;
 	client->finish_callback = finish_callback;
 	client->finish_context = context;
 	client->fd = -1;
@@ -428,6 +429,9 @@
 	if (client->set.source_port != 0 &&
 	    str_array_icase_find(client->xclient_args, "PORT"))
 		str_printfa(str, " PORT=%u", client->set.source_port);
+	if (client->set.proxy_ttl_plus_1 != 0 &&
+	    str_array_icase_find(client->xclient_args, "TTL"))
+		str_printfa(str, " TTL=%u", client->set.proxy_ttl_plus_1-1);
 
 	if (str_len(str) == empty_len)
 		return FALSE;
diff -r f534ed81bce4 -r ba06ea38c722 src/lib-lda/lmtp-client.h
--- a/src/lib-lda/lmtp-client.h	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lib-lda/lmtp-client.h	Sat Feb 25 06:54:52 2012 +0200
@@ -21,6 +21,8 @@
 	   send the these as ADDR/PORT */
 	struct ip_addr source_ip;
 	unsigned int source_port;
+	/* send TTL as this -1, so the default 0 means "don't send it" */
+	unsigned int proxy_ttl_plus_1;
 };
 
 /* reply contains the reply coming from remote server, or NULL
diff -r f534ed81bce4 -r ba06ea38c722 src/lmtp/client.c
--- a/src/lmtp/client.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lmtp/client.c	Sat Feb 25 06:54:52 2012 +0200
@@ -227,6 +227,7 @@
 	client_generate_session_id(client);
 	client->my_domain = client->set->hostname;
 	client->lhlo = i_strdup("missing");
+	client->proxy_ttl = LMTP_PROXY_DEFAULT_TTL;
 
 	DLLIST_PREPEND(&clients, client);
 	clients_count++;
diff -r f534ed81bce4 -r ba06ea38c722 src/lmtp/client.h
--- a/src/lmtp/client.h	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lmtp/client.h	Sat Feb 25 06:54:52 2012 +0200
@@ -62,6 +62,7 @@
 	struct client_state state;
 	struct istream *dot_input;
 	struct lmtp_proxy *proxy;
+	unsigned int proxy_ttl;
 
 	unsigned int disconnected:1;
 };
diff -r f534ed81bce4 -r ba06ea38c722 src/lmtp/commands.c
--- a/src/lmtp/commands.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lmtp/commands.c	Sat Feb 25 06:54:52 2012 +0200
@@ -69,7 +69,7 @@
 	client_state_reset(client);
 	client_send_line(client, "250-%s", client->my_domain);
 	if (client_is_trusted(client))
-		client_send_line(client, "250-XCLIENT ADDR PORT");
+		client_send_line(client, "250-XCLIENT ADDR PORT TTL");
 	client_send_line(client, "250-8BITMIME");
 	client_send_line(client, "250-ENHANCEDSTATUSCODES");
 	client_send_line(client, "250 PIPELINING");
@@ -296,6 +296,15 @@
 		return TRUE;
 	}
 
+	if (client->proxy_ttl == 0) {
+		i_error("Proxying to <%s> appears to be looping (TTL=0)",
+			username);
+		client_send_line(client, "554 5.4.6 <%s> "
+				 "Proxying appears to be looping (TTL=0)",
+				 username);
+		pool_unref(&pool);
+		return TRUE;
+	}
 	if (array_count(&client->state.rcpt_to) != 0) {
 		client_send_line(client, "451 4.3.0 <%s> "
 			"Can't handle mixed proxy/non-proxy destinations",
@@ -311,6 +320,7 @@
 		proxy_set.dns_client_socket_path = dns_client_socket_path;
 		proxy_set.source_ip = client->remote_ip;
 		proxy_set.source_port = client->remote_port;
+		proxy_set.proxy_ttl = client->proxy_ttl-1;
 
 		client->proxy = lmtp_proxy_init(&proxy_set, client->output);
 		if (client->state.mail_body_8bitmime)
@@ -915,7 +925,7 @@
 {
 	const char *const *tmp;
 	struct ip_addr remote_ip;
-	unsigned int remote_port = 0;
+	unsigned int remote_port = 0, ttl = -1U;
 	bool args_ok = TRUE;
 
 	if (!client_is_trusted(client)) {
@@ -931,6 +941,9 @@
 			if (str_to_uint(*tmp + 5, &remote_port) < 0 ||
 			    remote_port == 0 || remote_port > 65535)
 				args_ok = FALSE;
+		} else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
+			if (str_to_uint(*tmp + 4, &ttl) < 0)
+				args_ok = FALSE;
 		}
 	}
 	if (!args_ok) {
@@ -944,6 +957,8 @@
 		client->remote_ip = remote_ip;
 	if (remote_port != 0)
 		client->remote_port = remote_port;
+	if (ttl != -1U)
+		client->proxy_ttl = ttl;
 	client_send_line(client, "220 %s %s", client->my_domain,
 			 client->lmtp_set->login_greeting);
 	return 0;
diff -r f534ed81bce4 -r ba06ea38c722 src/lmtp/lmtp-proxy.c
--- a/src/lmtp/lmtp-proxy.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lmtp/lmtp-proxy.c	Sat Feb 25 06:54:52 2012 +0200
@@ -72,6 +72,7 @@
 		p_strdup(pool, set->dns_client_socket_path);
 	proxy->set.source_ip = set->source_ip;
 	proxy->set.source_port = set->source_port;
+	proxy->set.proxy_ttl = set->proxy_ttl;
 	i_array_init(&proxy->rcpt_to, 32);
 	i_array_init(&proxy->connections, 32);
 	return proxy;
@@ -134,6 +135,7 @@
 	client_set.dns_client_socket_path = proxy->set.dns_client_socket_path;
 	client_set.source_ip = proxy->set.source_ip;
 	client_set.source_port = proxy->set.source_port;
+	client_set.proxy_ttl_plus_1 = proxy->set.proxy_ttl+1;
 
 	conn = p_new(proxy->pool, struct lmtp_proxy_connection, 1);
 	conn->proxy = proxy;
diff -r f534ed81bce4 -r ba06ea38c722 src/lmtp/lmtp-proxy.h
--- a/src/lmtp/lmtp-proxy.h	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/lmtp/lmtp-proxy.h	Sat Feb 25 06:54:52 2012 +0200
@@ -4,6 +4,8 @@
 #include "network.h"
 #include "lmtp-client.h"
 
+#define LMTP_PROXY_DEFAULT_TTL 5
+
 struct lmtp_proxy_settings {
 	const char *my_hostname;
 	const char *dns_client_socket_path;
@@ -11,6 +13,7 @@
 	/* the original client's IP/port that connected to the proxy */
 	struct ip_addr source_ip;
 	unsigned int source_port;
+	unsigned int proxy_ttl;
 };
 
 struct lmtp_proxy_rcpt_settings {
diff -r f534ed81bce4 -r ba06ea38c722 src/login-common/client-common.c
--- a/src/login-common/client-common.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/login-common/client-common.c	Sat Feb 25 06:54:52 2012 +0200
@@ -96,6 +96,7 @@
 	client->trusted = client_is_trusted(client);
 	client->secured = ssl || client->trusted ||
 		net_ip_compare(remote_ip, local_ip);
+	client->proxy_ttl = LOGIN_PROXY_TTL;
 
 	if (last_client == NULL)
 		last_client = client;
diff -r f534ed81bce4 -r ba06ea38c722 src/login-common/client-common.h
--- a/src/login-common/client-common.h	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/login-common/client-common.h	Sat Feb 25 06:54:52 2012 +0200
@@ -117,6 +117,7 @@
 	struct login_proxy *login_proxy;
 	char *proxy_user, *proxy_master_user, *proxy_password;
 	unsigned int proxy_state;
+	unsigned int proxy_ttl;
 
 	char *auth_mech_name;
 	struct auth_client_request *auth_request;
diff -r f534ed81bce4 -r ba06ea38c722 src/login-common/login-proxy.c
--- a/src/login-common/login-proxy.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/login-common/login-proxy.c	Sat Feb 25 06:54:52 2012 +0200
@@ -277,6 +277,12 @@
 		return -1;
 	}
 
+	if (client->proxy_ttl == 0) {
+		i_error("proxy(%s): TTL reached zero - "
+			"proxies appear to be looping?", client->virtual_user);
+		return -1;
+	}
+
 	proxy = i_new(struct login_proxy, 1);
 	proxy->client = client;
 	proxy->client_fd = -1;
diff -r f534ed81bce4 -r ba06ea38c722 src/login-common/login-proxy.h
--- a/src/login-common/login-proxy.h	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/login-common/login-proxy.h	Sat Feb 25 06:54:52 2012 +0200
@@ -1,6 +1,13 @@
 #ifndef LOGIN_PROXY_H
 #define LOGIN_PROXY_H
 
+/* Max. number of embedded proxying connections until proxying fails.
+   This is intended to avoid an accidental configuration where two proxies
+   keep connecting to each others, both thinking the other one is supposed to
+   handle the user. This only works if both proxies support the Dovecot
+   TTL extension feature. */
+#define LOGIN_PROXY_TTL 5
+
 struct client;
 struct login_proxy;
 
diff -r f534ed81bce4 -r ba06ea38c722 src/pop3-login/client.c
--- a/src/pop3-login/client.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/pop3-login/client.c	Sat Feb 25 06:54:52 2012 +0200
@@ -56,6 +56,9 @@
 				args_ok = FALSE;
 			else
 				client->common.remote_port = remote_port;
+		} else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
+			if (str_to_uint(*tmp + 4, &client->common.proxy_ttl) < 0)
+				args_ok = FALSE;
 		}
 	}
 	if (!args_ok) {
diff -r f534ed81bce4 -r ba06ea38c722 src/pop3-login/pop3-proxy.c
--- a/src/pop3-login/pop3-proxy.c	Sat Feb 25 06:41:59 2012 +0200
+++ b/src/pop3-login/pop3-proxy.c	Sat Feb 25 06:54:52 2012 +0200
@@ -37,12 +37,14 @@
 {
 	string_t *str;
 
+	i_assert(client->common.proxy_ttl > 0);
 	if (client->proxy_xclient) {
 		/* remote supports XCLIENT, send it */
 		(void)o_stream_send_str(output, t_strdup_printf(
-			"XCLIENT ADDR=%s PORT=%u\r\n",
+			"XCLIENT ADDR=%s PORT=%u TTL=%u\r\n",
 			net_ip2addr(&client->common.ip),
-			client->common.remote_port));
+			client->common.remote_port,
+			client->common.proxy_ttl - 1));
 		client->common.proxy_state = POP3_PROXY_XCLIENT;
 	} else {
 		client->common.proxy_state = POP3_PROXY_LOGIN1;


More information about the dovecot-cvs mailing list