From a3bddaa8058346a11835f0d9947f3f60bb029fef Mon Sep 17 00:00:00 2001 From: Todd Lyons Date: Mon, 30 Dec 2013 15:02:21 -0800 Subject: [PATCH] Proxy negotiation saves socket timeout values. Rename proxy expansions conforming to Exim standards. Update documentation to reflect rename. Seperate restore socket function --- doc/doc-txt/experimental-spec.txt | 16 ++++++------- src/src/expand.c | 4 ++-- src/src/globals.c | 4 ++-- src/src/globals.h | 4 ++-- src/src/receive.c | 2 +- src/src/smtp_in.c | 40 +++++++++++++++++++++++++++---- 6 files changed, 51 insertions(+), 19 deletions(-) diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 92790ae33..b80e02b4c 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -1066,28 +1066,28 @@ Proxy Protocol server at 192.168.1.2 will look like this: 3. In the ACL's the following expansion variables are available. -proxy_host The src IP of the proxy server making the connection -proxy_port The src port the proxy server is using -proxy_session Boolean, yes/no, the connected host is required to use - Proxy Protocol. +proxy_host_address The src IP of the proxy server making the connection +proxy_host_port The src port the proxy server is using +proxy_session Boolean, yes/no, the connected host is required to use + Proxy Protocol. There is no expansion for a failed proxy session, however you can detect it by checking if $proxy_session is true but $proxy_host is empty. As an example, in my connect ACL, I have: warn condition = ${if and{ {bool{$proxy_session}} \ - {eq{$proxy_host}{}} } } + {eq{$proxy_host_address}{}} } } log_message = Failed required proxy protocol negotiation \ from $sender_host_name [$sender_host_address] warn condition = ${if and{ {bool{$proxy_session}} \ - {!eq{$proxy_host}{}} } } + {!eq{$proxy_host_address}{}} } } # But don't log health probes from the proxy itself - condition = ${if eq{$proxy_host}{$sender_host_address} \ + condition = ${if eq{$proxy_host_address}{$sender_host_address} \ {false}{true}} log_message = Successfully proxied from $sender_host_name \ [$sender_host_address] through proxy protocol \ - host $proxy_host + host $proxy_host_address 4. Runtime issues to be aware of: - Since the real connections are all coming from your proxy, and the diff --git a/src/src/expand.c b/src/src/expand.c index 325b05178..de52e6000 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -559,8 +559,8 @@ static var_entry var_table[] = { { "pid", vtype_pid, NULL }, { "primary_hostname", vtype_stringptr, &primary_hostname }, #ifdef EXPERIMENTAL_PROXY - { "proxy_host", vtype_stringptr, &proxy_host }, - { "proxy_port", vtype_int, &proxy_port }, + { "proxy_host_address", vtype_stringptr, &proxy_host_address }, + { "proxy_host_port", vtype_int, &proxy_host_port }, { "proxy_session", vtype_bool, &proxy_session }, #endif { "prvscheck_address", vtype_stringptr, &prvscheck_address }, diff --git a/src/src/globals.c b/src/src/globals.c index ec6700df5..1572461ec 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -919,8 +919,8 @@ uschar *process_log_path = NULL; BOOL prod_requires_admin = TRUE; #ifdef EXPERIMENTAL_PROXY -uschar *proxy_host = US""; -int proxy_port = 0; +uschar *proxy_host_address = US""; +int proxy_host_port = 0; uschar *proxy_required_hosts = US""; BOOL proxy_session = FALSE; BOOL proxy_session_failed = FALSE; diff --git a/src/src/globals.h b/src/src/globals.h index 5661489a7..bf54fb41f 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -594,8 +594,8 @@ extern uschar *process_log_path; /* Alternate path */ extern BOOL prod_requires_admin; /* TRUE if prodding requires admin */ #ifdef EXPERIMENTAL_PROXY -extern uschar *proxy_host; /* IP of proxy server */ -extern int proxy_port; /* Port of proxy server */ +extern uschar *proxy_host_address; /* IP of proxy server */ +extern int proxy_host_port; /* Port of proxy server */ extern uschar *proxy_required_hosts; /* Hostlist which (require) use proxy protocol */ extern BOOL proxy_session; /* TRUE if receiving mail from valid proxy */ extern BOOL proxy_session_failed; /* TRUE if required proxy negotiation failed */ diff --git a/src/src/receive.c b/src/src/receive.c index 02db23f94..0295b7e54 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -3759,7 +3759,7 @@ if (prdr_requested) if (proxy_session && (log_extra_selector & LX_proxy) != 0) { - s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_host); + s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_host_address); } #endif diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 144ad28a2..95c615e37 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -554,6 +554,25 @@ exim_exit(EXIT_FAILURE); #ifdef EXPERIMENTAL_PROXY +/************************************************* +* Restore socket timeout to previous value * +*************************************************/ +/* If the previous value was successfully retrieved, restore +it before returning control to the non-proxy routines + +Arguments: fd - File descriptor for input + get_ok - Successfully retrieved previous values + tvtmp - Time struct with previous values + vslen - Length of time struct +Returns: none +*/ +static void +restore_socket_timeout(int fd, int get_ok, struct timeval tvtmp, socklen_t vslen) +{ +if (get_ok == 0) + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvtmp, vslen); +} + /************************************************* * Check if host is required proxy host * *************************************************/ @@ -650,15 +669,25 @@ uschar *tmpip; const char v2sig[13] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02"; uschar *iptype; /* To display debug info */ struct timeval tv; +int get_ok = 0; +socklen_t vslen = 0; +struct timeval tvtmp; + +vslen = sizeof(struct timeval); fd = fileno(smtp_in); +/* Save current socket timeout values */ +get_ok = getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvtmp, + &vslen); + /* Proxy Protocol host must send header within a short time (default 3 seconds) or it's considered invalid */ tv.tv_sec = PROXY_NEGOTIATION_TIMEOUT_SEC; tv.tv_usec = PROXY_NEGOTIATION_TIMEOUT_USEC; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); + do { ret = recv(fd, &hdr, sizeof(hdr), MSG_PEEK); @@ -666,7 +695,10 @@ do while (ret == -1 && errno == EINTR); if (ret == -1) + { + restore_socket_timeout(fd, get_ok, tvtmp, vslen); return (errno == EAGAIN) ? 0 : ERRNO_PROXYFAIL; + } if (ret >= 16 && memcmp(&hdr.v2, v2sig, 13) == 0) @@ -768,7 +800,7 @@ else if (ret >= 8 && debug_printf("Proxied src arg is not an %s address\n", iptype); goto proxyfail; } - proxy_host = sender_host_address; + proxy_host_address = sender_host_address; sender_host_address = p; p = sp + 1; if ((sp = Ustrchr(p, ' ')) == NULL) @@ -799,7 +831,7 @@ else if (ret >= 8 && debug_printf("Proxied src port '%s' not an integer\n", p); goto proxyfail; } - proxy_port = sender_host_port; + proxy_host_port = sender_host_port; sender_host_port = tmp_port; p = sp + 1; if ((sp = Ustrchr(p, '\0')) == NULL) @@ -826,11 +858,13 @@ else } proxyfail: +restore_socket_timeout(fd, get_ok, tvtmp, vslen); /* Don't flush any potential buffer contents. Any input should cause a synchronization failure or we just don't want to speak SMTP to them */ return FALSE; done: +restore_socket_timeout(fd, get_ok, tvtmp, vslen); flush_input(); DEBUG(D_receive) debug_printf("Valid %s sender from Proxy Protocol header\n", @@ -839,8 +873,6 @@ return proxy_session; } #endif - - /************************************************* * Read one command line * *************************************************/ -- 2.25.1