From: Heiko Schlittermann (HS12-RIPE) Date: Sun, 4 Oct 2020 10:33:18 +0000 (+0200) Subject: Merge branch 'hs/fix-proxy-bh' (Closes 2656) X-Git-Url: https://git.exim.org/users/heiko/exim.git/commitdiff_plain/e248dbece62f036f9845de1d15876b946eead0d0?hp=0dfff3282dcfbee8f1568797c2acd4983674c0d9 Merge branch 'hs/fix-proxy-bh' (Closes 2656) --- diff --git a/src/src/macros.h b/src/src/macros.h index 82e50b5fe..c3f1c5d43 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -201,7 +201,6 @@ host isn't speaking the protocol, and so is disallowed. Can be moved to runtime configuration if per site settings become needed. */ #ifdef SUPPORT_PROXY #define PROXY_NEGOTIATION_TIMEOUT_SEC 3 -#define PROXY_NEGOTIATION_TIMEOUT_USEC 0 #endif /* Fixed option values for all PCRE functions */ diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index c0b6b2ac1..69eae3cb4 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1033,25 +1033,6 @@ had_command_sigterm = sig; #ifdef SUPPORT_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) - (void) setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS tvtmp, vslen); -} - /************************************************* * Check if host is required proxy host * *************************************************/ @@ -1128,7 +1109,7 @@ if (cr != NULL) while (capacity > 0) { - do { ret = recv(fd, to, 1, 0); } while (ret == -1 && errno == EINTR); + do { ret = read(fd, to, 1); } while (ret == -1 && errno == EINTR && !had_command_timeout); if (ret == -1) return -1; have++; @@ -1237,15 +1218,8 @@ struct timeval tvtmp; socklen_t vslen = sizeof(struct timeval); BOOL yield = FALSE; -/* Save current socket timeout values */ -get_ok = getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &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; -if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &tv, sizeof(tv)) < 0) - goto bad; +os_non_restarting_signal(SIGALRM, command_timeout_handler); +ALARM(PROXY_NEGOTIATION_TIMEOUT_SEC); do { @@ -1253,9 +1227,9 @@ do don't do a PEEK into the data, actually slurp up enough to be "safe". Can't take it all because TLS-on-connect clients follow immediately with TLS handshake. */ - ret = recv(fd, &hdr, PROXY_INITIAL_READ, 0); + ret = read(fd, &hdr, PROXY_INITIAL_READ); } - while (ret == -1 && errno == EINTR); + while (ret == -1 && errno == EINTR && !had_command_timeout); if (ret == -1) goto proxyfail; @@ -1269,8 +1243,8 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) /* First get the length fields. */ do { - retmore = recv(fd, (uschar*)&hdr + ret, PROXY_V2_HEADER_SIZE - PROXY_INITIAL_READ, 0); - } while (retmore == -1 && errno == EINTR); + retmore = read(fd, (uschar*)&hdr + ret, PROXY_V2_HEADER_SIZE - PROXY_INITIAL_READ); + } while (retmore == -1 && errno == EINTR && !had_command_timeout); if (retmore == -1) goto proxyfail; ret += retmore; @@ -1306,8 +1280,8 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) { do { - retmore = recv(fd, (uschar*)&hdr + ret, size-ret, 0); - } while (retmore == -1 && errno == EINTR); + retmore = read(fd, (uschar*)&hdr + ret, size-ret); + } while (retmore == -1 && errno == EINTR && !had_command_timeout); if (retmore == -1) goto proxyfail; ret += retmore; @@ -1535,7 +1509,8 @@ done: should cause a synchronization failure */ proxyfail: - restore_socket_timeout(fd, get_ok, &tvtmp, vslen); + DEBUG(D_receive) if (had_command_timeout) + debug_printf("Timeout while reading proxy header\n"); bad: if (yield) @@ -1551,6 +1526,7 @@ bad: debug_printf("Failure to extract proxied host, only QUIT allowed\n"); } +ALARM(0); return; } #endif @@ -2412,7 +2388,7 @@ TCP_SYN_RCV (as of 12.1) so no idea about data-use. */ if (getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_FASTOPEN, &is_fastopen, &len) == 0) { - if (is_fastopen) + if (is_fastopen) { DEBUG(D_receive) debug_printf("TFO mode connection (TCP_FASTOPEN getsockopt)\n"); @@ -5769,7 +5745,7 @@ while (done <= 0) /* If not serializing, do the exec right away. Otherwise, fork down into another process. */ - if ( !smtp_etrn_serialize + if ( !smtp_etrn_serialize || (pid = exim_fork(US"etrn-serialised-command")) == 0) { DEBUG(D_exec) debug_print_argv(argv); diff --git a/test/confs/4031 b/test/confs/4031 new file mode 120000 index 000000000..b6e26c8b8 --- /dev/null +++ b/test/confs/4031 @@ -0,0 +1 @@ +4030 \ No newline at end of file diff --git a/test/scripts/4030-proxy-protocol/4031 b/test/scripts/4030-proxy-protocol/4031 new file mode 100644 index 000000000..ecf3e827b --- /dev/null +++ b/test/scripts/4030-proxy-protocol/4031 @@ -0,0 +1,40 @@ +# proxy-protocol proxy on inbound -bh +# +### non-prox plain receive +exim -bh 127.0.0.2 +HELO clientname +MAIL FROM: +RCPT TO: +DATA +Subject: test non-prox + +body non-prox +. +QUIT +**** +### protocol v1 receive +exim -bh HOSTIPV4 +>>> PROXY TCP4 127.0.0.2 127.42.42.42 64000 25\r\n +HELO clientname +MAIL FROM: +RCPT TO: +DATA +Subject: test v1 + +body v1 +. +QUIT +**** +### protocol v2 receive +exim -bh HOSTIPV4 +>>> \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x21\x11\x00\x0c\x7f\x00\x00\x02\x7f\x2a\x2a\x2a\xc2\x95\x04\x01 +HELO clientname +MAIL FROM: +RCPT TO: +DATA +Subject: test v2 + +body v2 +. +QUIT +**** diff --git a/test/stderr/4031 b/test/stderr/4031 new file mode 100644 index 000000000..c5336cb25 --- /dev/null +++ b/test/stderr/4031 @@ -0,0 +1,102 @@ +### non-prox plain receive +>>> host in hosts_connection_nolog? no (option unset) +>>> host in host_lookup? no (option unset) +>>> host in host_reject_connection? no (option unset) +>>> host in sender_unqualified_hosts? no (option unset) +>>> host in recipient_unqualified_hosts? no (option unset) +>>> host in helo_verify_hosts? no (option unset) +>>> host in helo_try_verify_hosts? no (option unset) +>>> host in helo_accept_junk_hosts? no (option unset) +>>> clientname in helo_lookup_domains? no (end of list) +>>> using ACL "r_acl" +>>> processing "accept" (TESTSUITE/test-config 20) +>>> check logwrite = proxy session: $proxy_session +>>> = proxy session: no +LOG: proxy session: no +>>> check logwrite = local [$received_ip_address]:$received_port +>>> = local []:-1 +LOG: local []:-1 +>>> check logwrite = proxy internal [$proxy_local_address]:$proxy_local_port +>>> = proxy internal []:0 +LOG: proxy internal []:0 +>>> check logwrite = proxy external [$proxy_external_address]:$proxy_external_port +>>> = proxy external []:0 +LOG: proxy external []:0 +>>> check logwrite = remote [$sender_host_address]:$sender_host_port +>>> = remote [127.0.0.2]:1111 +LOG: remote [127.0.0.2]:1111 +>>> accept: condition test succeeded in ACL "r_acl" +>>> end of ACL "r_acl": ACCEPT +>>> host in ignore_fromline_hosts? no (option unset) +LOG: 10HmaX-0005vi-00 <= a@test.ex H=(clientname) [127.0.0.2] P=smtp S=sss +### protocol v1 receive +>>> host in hosts_connection_nolog? no (option unset) +>>> host in host_lookup? no (option unset) +>>> host in host_reject_connection? no (option unset) +>>> host in sender_unqualified_hosts? no (option unset) +>>> host in recipient_unqualified_hosts? no (option unset) +>>> host in helo_verify_hosts? no (option unset) +>>> host in helo_try_verify_hosts? no (option unset) +>>> host in helo_accept_junk_hosts? no (option unset) +>>> looking up host name for 127.0.0.2 +LOG: no host name found for IP address 127.0.0.2 +>>> clientname in helo_lookup_domains? no (end of list) +>>> using ACL "r_acl" +>>> processing "accept" (TESTSUITE/test-config 20) +>>> check logwrite = proxy session: $proxy_session +>>> = proxy session: yes +LOG: proxy session: yes +>>> check logwrite = local [$received_ip_address]:$received_port +>>> = local []:-1 +LOG: local []:-1 +>>> check logwrite = proxy internal [$proxy_local_address]:$proxy_local_port +>>> = proxy internal [ip4.ip4.ip4.ip4]:1111 +LOG: proxy internal [ip4.ip4.ip4.ip4]:1111 +>>> check logwrite = proxy external [$proxy_external_address]:$proxy_external_port +>>> = proxy external [127.42.42.42]:1112 +LOG: proxy external [127.42.42.42]:1112 +>>> check logwrite = remote [$sender_host_address]:$sender_host_port +>>> = remote [127.0.0.2]:1113 +LOG: remote [127.0.0.2]:1113 +>>> accept: condition test succeeded in ACL "r_acl" +>>> end of ACL "r_acl": ACCEPT +>>> host in ignore_fromline_hosts? no (option unset) +LOG: 10HmaY-0005vi-00 <= a@test.ex H=(clientname) [127.0.0.2]:1113 P=smtp PRX=ip4.ip4.ip4.ip4 S=sss +### protocol v2 receive +>>> host in hosts_connection_nolog? no (option unset) +>>> host in host_lookup? no (option unset) +>>> host in host_reject_connection? no (option unset) +>>> host in sender_unqualified_hosts? no (option unset) +>>> host in recipient_unqualified_hosts? no (option unset) +>>> host in helo_verify_hosts? no (option unset) +>>> host in helo_try_verify_hosts? no (option unset) +>>> host in helo_accept_junk_hosts? no (option unset) +>>> looking up host name for 127.0.0.2 +LOG: no host name found for IP address 127.0.0.2 +>>> clientname in helo_lookup_domains? no (end of list) +>>> using ACL "r_acl" +>>> processing "accept" (TESTSUITE/test-config 20) +>>> check logwrite = proxy session: $proxy_session +>>> = proxy session: yes +LOG: proxy session: yes +>>> check logwrite = local [$received_ip_address]:$received_port +>>> = local []:-1 +LOG: local []:-1 +>>> check logwrite = proxy internal [$proxy_local_address]:$proxy_local_port +>>> = proxy internal [ip4.ip4.ip4.ip4]:1111 +LOG: proxy internal [ip4.ip4.ip4.ip4]:1111 +>>> check logwrite = proxy external [$proxy_external_address]:$proxy_external_port +>>> = proxy external [127.42.42.42]:1114 +LOG: proxy external [127.42.42.42]:1114 +>>> check logwrite = remote [$sender_host_address]:$sender_host_port +>>> = remote [127.0.0.2]:1115 +LOG: remote [127.0.0.2]:1115 +>>> accept: condition test succeeded in ACL "r_acl" +>>> end of ACL "r_acl": ACCEPT +>>> host in ignore_fromline_hosts? no (option unset) +LOG: 10HmaZ-0005vi-00 <= a@test.ex H=(clientname) [127.0.0.2]:1115 P=smtp PRX=ip4.ip4.ip4.ip4 S=sss + +******** SERVER ******** +### non-prox plain receive +### protocol v1 receive +### protocol v2 receive diff --git a/test/stdout/4031 b/test/stdout/4031 new file mode 100644 index 000000000..a0cddc62d --- /dev/null +++ b/test/stdout/4031 @@ -0,0 +1,53 @@ +### non-prox plain receive + +**** SMTP testing session as if from host 127.0.0.2 +**** but without any ident (RFC 1413) callback. +**** This is not for real! + +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250 myhost.test.ex Hello clientname [127.0.0.2] +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmaX-0005vi-00 + +**** SMTP testing: that is not a real message id! + +221 myhost.test.ex closing connection +### protocol v1 receive + +**** SMTP testing session as if from host ip4.ip4.ip4.ip4 +**** but without any ident (RFC 1413) callback. +**** This is not for real! + +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250 myhost.test.ex Hello clientname [127.0.0.2] +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmaY-0005vi-00 + +**** SMTP testing: that is not a real message id! + +221 myhost.test.ex closing connection +### protocol v2 receive + +**** SMTP testing session as if from host ip4.ip4.ip4.ip4 +**** but without any ident (RFC 1413) callback. +**** This is not for real! + +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250 myhost.test.ex Hello clientname [127.0.0.2] +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmaZ-0005vi-00 + +**** SMTP testing: that is not a real message id! + +221 myhost.test.ex closing connection + +******** SERVER ******** +### non-prox plain receive +### protocol v1 receive +### protocol v2 receive