Mercurial > dovecot > core-2.2
changeset 14162:ba06ea38c722
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.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 25 Feb 2012 06:54:52 +0200 |
parents | f534ed81bce4 |
children | 716769cfbb1d |
files | src/imap-login/client.c src/imap-login/imap-proxy.c src/lib-lda/lmtp-client.c src/lib-lda/lmtp-client.h src/lmtp/client.c src/lmtp/client.h src/lmtp/commands.c src/lmtp/lmtp-proxy.c src/lmtp/lmtp-proxy.h src/login-common/client-common.c src/login-common/client-common.h src/login-common/login-proxy.c src/login-common/login-proxy.h src/pop3-login/client.c src/pop3-login/pop3-proxy.c |
diffstat | 15 files changed, 60 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- 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; } }
--- 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)
--- 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;
--- 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
--- 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++;
--- 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; };
--- 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;
--- 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;
--- 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 {
--- 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;
--- 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;
--- 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;
--- 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;
--- 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) {
--- 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;