From e6d2a9894df8c3b65920e903ab21076a0a37e20e Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 8 Dec 2015 22:21:58 +0000 Subject: [PATCH] SOCKS: Add log_selector support. Also make the proxy_* variables meaningful for events associated with proxied transports. --- doc/doc-docbook/spec.xfpt | 17 +++--- doc/doc-txt/ChangeLog | 3 +- src/src/deliver.c | 105 +++++++++++++++++++------------- src/src/expand.c | 10 +-- src/src/globals.c | 12 ++-- src/src/globals.h | 10 +-- src/src/receive.c | 2 +- src/src/smtp_in.c | 12 ++-- src/src/transports/smtp_socks.c | 14 +++-- test/confs/4020 | 4 +- test/log/4020 | 4 +- test/scripts/4020-socks/4020 | 4 +- test/stdout/4020 | 4 +- 13 files changed, 117 insertions(+), 84 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 6096e1df2..418cb1a11 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -12038,7 +12038,8 @@ qualified host name. See also &$smtp_active_hostname$&. &$proxy_target_address$& &&& &$proxy_target_port$& &&& &$proxy_session$& -These variables are only available when built with Proxy Protocol support +These variables are only available when built with Proxy Protocol +or Socks5 support For details see chapter &<>&. .wen @@ -35481,7 +35482,7 @@ selection marked by asterisks: &` queue_time_overall `& time on queue for whole message &` pid `& Exim process id .new -&` proxy `& proxy address on <= lines +&` proxy `& proxy address on <= and => lines .wen &` received_recipients `& recipients on <= lines &` received_sender `& sender on <= lines @@ -35615,7 +35616,8 @@ The latter can be disabled by turning off the &%outgoing_interface%& option. .cindex "TCP/IP" "logging proxy address" &%proxy%&: The internal (closest to the system running Exim) IP address of the proxy, tagged by PRX=, on the &"<="& line for a message accepted -on a proxied connection. +on a proxied connection +or the &"=>"& line for a message delivered on a proxied connection.. See &<>& for more information. .wen .next @@ -38087,10 +38089,6 @@ Use of a proxy is enabled by setting the &%hosts_proxy%& main configuration option to a hostlist; connections from these hosts will use Proxy Protocol. -To log the IP of the proxy in the incoming logline, add &"+proxy"& -to the &%log_selector%& option. -This will add a component tagged with &"PRX="& to the line. - The following expansion variables are usable (&"internal"& and &"external"& here refer to the interfaces of the proxy): @@ -38190,6 +38188,11 @@ The default value for selection bias is 1. Proxies from the list are tried according to their priority and weight settings until one responds. The timeout for the overall connection applies to the set of proxied attempts. + +.section Logging SECTproxyLog +To log the (local) IP of a proxy in the incoming or delivery logline, +add &"+proxy"& to the &%log_selector%& option. +This will add a component tagged with &"PRX="& to the line. .wen . //////////////////////////////////////////////////////////////////////////// diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 1fa19daad..c167f8392 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -117,7 +117,8 @@ JH/23 Move SOCKS5 support from Experimental to mainline, enabled for a build JH/26 Move PROXY support from Experimental to mainline, enabled for a build by defining SUPPORT_PROXY. Note that the proxy_required_hosts option - is renamed to hosts_proxy. + is renamed to hosts_proxy, and the proxy_{host,target}_{address,port}. + variables are renamed to proxy_{local,external}_{address,port}. Exim version 4.86 diff --git a/src/src/deliver.c b/src/src/deliver.c index 65f148c07..53712b269 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -718,11 +718,24 @@ s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name, if (LOGGING(outgoing_port)) s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d", addr->host_used->port)); + +#ifdef SUPPORT_SOCKS +if (LOGGING(proxy) && proxy_local_address) + { + s = string_append(s, sizep, ptrp, 3, US" PRX=[", proxy_local_address, US"]"); + if (LOGGING(outgoing_port)) + s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d", + proxy_local_port)); + } +#endif + return d_log_interface(s, sizep, ptrp); } + + #ifdef SUPPORT_TLS static uschar * d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr) @@ -3297,6 +3310,21 @@ while (!done) switch (subid) { +#ifdef SUPPORT_SOCKS + case '2': /* proxy information; must arrive before A0 and applies to that addr XXX oops*/ + proxy_session = TRUE; /*XXX shouod this be cleared somewhere? */ + if (*ptr == 0) + ptr++; + else + { + proxy_local_address = string_copy(ptr); + while(*ptr++); + memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port)); + ptr += sizeof(proxy_local_port); + } + break; +#endif + #ifdef EXPERIMENTAL_DSN_INFO case '1': /* must arrive before A0, and applies to that addr */ /* Two strings: smtp_greeting and helo_response */ @@ -4441,15 +4469,13 @@ for (delivery_count = 0; addr_remote; delivery_count++) #ifdef SUPPORT_TLS if (addr->cipher) { - ptr = big_buffer; - sprintf(CS ptr, "%.128s", addr->cipher); - while(*ptr++); + ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->cipher) + 1; if (!addr->peerdn) *ptr++ = 0; else { - sprintf(CS ptr, "%.512s", addr->peerdn); - while(*ptr++); + ptr += sprintf(CS ptr, "%.512s", addr->peerdn); + ptr++; } rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer); @@ -4475,9 +4501,7 @@ for (delivery_count = 0; addr_remote; delivery_count++) # ifndef DISABLE_OCSP if (addr->ocsp > OCSP_NOT_REQ) { - ptr = big_buffer; - sprintf(CS ptr, "%c", addr->ocsp + '0'); - while(*ptr++); + ptr = big_buffer + sprintf(CS big_buffer, "%c", addr->ocsp + '0') + 1; rmt_dlv_checked_write(fd, 'X', '4', big_buffer, ptr - big_buffer); } # endif @@ -4485,23 +4509,17 @@ for (delivery_count = 0; addr_remote; delivery_count++) if (client_authenticator) { - ptr = big_buffer; - sprintf(CS big_buffer, "%.64s", client_authenticator); - while(*ptr++); + ptr = big_buffer + sprintf(CS big_buffer, "%.64s", client_authenticator) + 1; rmt_dlv_checked_write(fd, 'C', '1', big_buffer, ptr - big_buffer); } if (client_authenticated_id) { - ptr = big_buffer; - sprintf(CS big_buffer, "%.64s", client_authenticated_id); - while(*ptr++); + ptr = big_buffer + sprintf(CS big_buffer, "%.64s", client_authenticated_id) + 1; rmt_dlv_checked_write(fd, 'C', '2', big_buffer, ptr - big_buffer); } if (client_authenticated_sender) { - ptr = big_buffer; - sprintf(CS big_buffer, "%.64s", client_authenticated_sender); - while(*ptr++); + ptr = big_buffer + sprintf(CS big_buffer, "%.64s", client_authenticated_sender) + 1; rmt_dlv_checked_write(fd, 'C', '3', big_buffer, ptr - big_buffer); } @@ -4532,19 +4550,34 @@ for (delivery_count = 0; addr_remote; delivery_count++) rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer); } +#ifdef SUPPORT_SOCKS + if (LOGGING(proxy) && proxy_session) + { + ptr = big_buffer; + if (proxy_local_address) + { + DEBUG(D_deliver) debug_printf("proxy_local_address '%s'\n", proxy_local_address); + ptr = big_buffer + sprintf(CS ptr, "%.128s", proxy_local_address) + 1; + DEBUG(D_deliver) debug_printf("proxy_local_port %d\n", proxy_local_port); + memcpy(ptr, &proxy_local_port, sizeof(proxy_local_port)); + ptr += sizeof(proxy_local_port); + } + else + *ptr++ = '\0'; + rmt_dlv_checked_write(fd, 'A', '2', big_buffer, ptr - big_buffer); + } +#endif + #ifdef EXPERIMENTAL_DSN_INFO /*um, are they really per-addr? Other per-conn stuff is not (auth, tls). But host_used is! */ if (addr->smtp_greeting) { - ptr = big_buffer; DEBUG(D_deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting); - sprintf(CS ptr, "%.128s", addr->smtp_greeting); - while(*ptr++); + ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->smtp_greeting) + 1; if (addr->helo_response) { DEBUG(D_deliver) debug_printf("helo_response '%s'\n", addr->helo_response); - sprintf(CS ptr, "%.128s", addr->helo_response); - while(*ptr++); + ptr += sprintf(CS ptr, "%.128s", addr->helo_response) + 1; } else *ptr++ = '\0'; @@ -4554,8 +4587,7 @@ for (delivery_count = 0; addr_remote; delivery_count++) /* The rest of the information goes in an 'A0' item. */ - sprintf(CS big_buffer, "%c%c", addr->transport_return, - addr->special_action); + sprintf(CS big_buffer, "%c%c", addr->transport_return, addr->special_action); ptr = big_buffer + 2; memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno)); ptr += sizeof(addr->basic_errno); @@ -4565,23 +4597,15 @@ for (delivery_count = 0; addr_remote; delivery_count++) ptr += sizeof(addr->flags); if (!addr->message) *ptr++ = 0; else - { - sprintf(CS ptr, "%.1024s", addr->message); - while(*ptr++); - } + ptr += sprintf(CS ptr, "%.1024s", addr->message) + 1; if (!addr->user_message) *ptr++ = 0; else - { - sprintf(CS ptr, "%.1024s", addr->user_message); - while(*ptr++); - } + ptr += sprintf(CS ptr, "%.1024s", addr->user_message) + 1; if (!addr->host_used) *ptr++ = 0; else { - sprintf(CS ptr, "%.256s", addr->host_used->name); - while(*ptr++); - sprintf(CS ptr, "%.64s", addr->host_used->address); - while(*ptr++); + ptr += sprintf(CS ptr, "%.256s", addr->host_used->name) + 1; + ptr += sprintf(CS ptr, "%.64s", addr->host_used->address) + 1; memcpy(ptr, &(addr->host_used->port), sizeof(addr->host_used->port)); ptr += sizeof(addr->host_used->port); @@ -4600,12 +4624,9 @@ for (delivery_count = 0; addr_remote; delivery_count++) if (LOGGING(incoming_interface) && sending_ip_address) #endif { - uschar * ptr = big_buffer; - sprintf(CS ptr, "%.128s", sending_ip_address); - while(*ptr++); - sprintf(CS ptr, "%d", sending_port); - while(*ptr++); - + uschar * ptr; + ptr = big_buffer + sprintf(CS big_buffer, "%.128s", sending_ip_address) + 1; + ptr += sprintf(CS ptr, "%d", sending_port) + 1; rmt_dlv_checked_write(fd, 'I', '0', big_buffer, ptr - big_buffer); } diff --git a/src/src/expand.c b/src/src/expand.c index f3baee9af..a5f14364c 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -615,12 +615,12 @@ static var_entry var_table[] = { { "prdr_requested", vtype_bool, &prdr_requested }, #endif { "primary_hostname", vtype_stringptr, &primary_hostname }, -#ifdef SUPPORT_PROXY - { "proxy_host_address", vtype_stringptr, &proxy_host_address }, - { "proxy_host_port", vtype_int, &proxy_host_port }, +#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) + { "proxy_external_address",vtype_stringptr, &proxy_external_address }, + { "proxy_external_port", vtype_int, &proxy_external_port }, + { "proxy_local_address", vtype_stringptr, &proxy_local_address }, + { "proxy_local_port", vtype_int, &proxy_local_port }, { "proxy_session", vtype_bool, &proxy_session }, - { "proxy_target_address",vtype_stringptr, &proxy_target_address }, - { "proxy_target_port", vtype_int, &proxy_target_port }, #endif { "prvscheck_address", vtype_stringptr, &prvscheck_address }, { "prvscheck_keynum", vtype_stringptr, &prvscheck_keynum }, diff --git a/src/src/globals.c b/src/src/globals.c index fbfb9b8a2..6bd33a1a5 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -875,7 +875,7 @@ bit_table log_options[] = { /* must be in alphabetical order */ BIT_TABLE(L, outgoing_interface), BIT_TABLE(L, outgoing_port), BIT_TABLE(L, pid), -#ifdef SUPPORT_PROXY +#if defined(SUPPORT_PROXY) || defined (SUPPORT_SOCKS) BIT_TABLE(L, proxy), #endif BIT_TABLE(L, queue_run), @@ -1001,14 +1001,14 @@ int process_info_len = 0; uschar *process_log_path = NULL; BOOL prod_requires_admin = TRUE; -#ifdef SUPPORT_PROXY +#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) uschar *hosts_proxy = US""; -uschar *proxy_host_address = US""; -int proxy_host_port = 0; +uschar *proxy_external_address = US""; +int proxy_external_port = 0; +uschar *proxy_local_address = US""; +int proxy_local_port = 0; BOOL proxy_session = FALSE; BOOL proxy_session_failed = FALSE; -uschar *proxy_target_address = US""; -int proxy_target_port = 0; #endif uschar *prvscheck_address = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 4263e104d..899471116 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -645,14 +645,14 @@ extern int process_info_len; extern uschar *process_log_path; /* Alternate path */ extern BOOL prod_requires_admin; /* TRUE if prodding requires admin */ -#ifdef SUPPORT_PROXY +#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) extern uschar *hosts_proxy; /* Hostlist which (require) use proxy protocol */ -extern uschar *proxy_host_address; /* IP of host being proxied */ -extern int proxy_host_port; /* Port of host being proxied */ +extern uschar *proxy_external_address; /* IP of remote interface of proxy */ +extern int proxy_external_port; /* Port on remote interface of proxy */ +extern uschar *proxy_local_address; /* IP of local interface of proxy */ +extern int proxy_local_port; /* Port on local interface of proxy */ extern BOOL proxy_session; /* TRUE if receiving mail from valid proxy */ extern BOOL proxy_session_failed; /* TRUE if required proxy negotiation failed */ -extern uschar *proxy_target_address; /* IP of proxy server inbound */ -extern int proxy_target_port; /* Port of proxy server inbound */ #endif extern uschar *prvscheck_address; /* Set during prvscheck expansion item */ diff --git a/src/src/receive.c b/src/src/receive.c index 01f461650..dc228d921 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -3777,7 +3777,7 @@ if (prdr_requested) #ifdef SUPPORT_PROXY if (proxy_session && LOGGING(proxy)) - s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_host_address); + s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_local_address); #endif sprintf(CS big_buffer, "%d", msg_size); diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index d99f02e69..a5ed2f9b7 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -761,10 +761,10 @@ if (ret >= 16 && DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype); return ERRNO_PROXYFAIL; } - proxy_host_address = sender_host_address; + proxy_local_address = sender_host_address; sender_host_address = string_copy(US tmpip); tmpport = ntohs(hdr.v2.addr.ip4.src_port); - proxy_host_port = sender_host_port; + proxy_local_port = sender_host_port; sender_host_port = tmpport; /* Save dest ip/port */ tmpaddr.sin_addr.s_addr = hdr.v2.addr.ip4.dst_addr; @@ -787,10 +787,10 @@ if (ret >= 16 && DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype); return ERRNO_PROXYFAIL; } - proxy_host_address = sender_host_address; + proxy_local_address = sender_host_address; sender_host_address = string_copy(US tmpip6); tmpport = ntohs(hdr.v2.addr.ip6.src_port); - proxy_host_port = sender_host_port; + proxy_local_port = sender_host_port; sender_host_port = tmpport; /* Save dest ip/port */ memmove(tmpaddr6.sin6_addr.s6_addr, hdr.v2.addr.ip6.dst_addr, 16); @@ -881,7 +881,7 @@ else if (ret >= 8 && debug_printf("Proxied src arg is not an %s address\n", iptype); goto proxyfail; } - proxy_host_address = sender_host_address; + proxy_local_address = sender_host_address; sender_host_address = p; p = sp + 1; if ((sp = Ustrchr(p, ' ')) == NULL) @@ -912,7 +912,7 @@ else if (ret >= 8 && debug_printf("Proxied src port '%s' not an integer\n", p); goto proxyfail; } - proxy_host_port = sender_host_port; + proxy_local_port = sender_host_port; sender_host_port = tmp_port; p = sp + 1; if ((sp = Ustrchr(p, '\0')) == NULL) diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c index 30eded545..33b25d1da 100644 --- a/src/src/transports/smtp_socks.c +++ b/src/src/transports/smtp_socks.c @@ -290,7 +290,11 @@ for(;;) if ((fd = smtp_sock_connect(&proxy, proxy_af, sob->port, interface, tb, sob->timeout)) >= 0) + { + proxy_local_address = string_copy(proxy.address); + proxy_local_port = sob->port; break; + } log_write(0, LOG_MAIN, "%s: %s", __FUNCTION__, strerror(errno)); sob->is_failed = TRUE; @@ -373,11 +377,13 @@ if ( buf[0] != 5 ) goto proxy_err; -/*XXX log proxy outbound addr/port? */ +proxy_external_address = string_copy( + host_ntoa(buf[3] == 4 ? AF_INET6 : AF_INET, buf+4, NULL, NULL)); +proxy_external_port = ntohs(*((uint16_t *)(buf + (buf[3] == 4 ? 20 : 8)))); +proxy_session = TRUE; + HDEBUG(D_transport|D_acl|D_v) - debug_printf(" proxy farside local: [%s]:%d\n", - host_ntoa(buf[3] == 4 ? AF_INET6 : AF_INET, buf+4, NULL, NULL), - ntohs(*((uint16_t *)(buf + (buf[3] == 4 ? 20 : 8))))); + debug_printf(" proxy farside: [%s]:%d\n", proxy_external_address, proxy_external_port); return fd; diff --git a/test/confs/4020 b/test/confs/4020 index 8e2f6b052..794272e6d 100644 --- a/test/confs/4020 +++ b/test/confs/4020 @@ -13,6 +13,8 @@ tls_advertise_hosts = # ----- Main settings ----- +log_selector = +proxy +outgoing_port + domainlist local_domains = test.ex : *.test.ex acl_smtp_rcpt = accept @@ -38,7 +40,7 @@ my_smtp: driver = smtp interface = HOSTIPV4 port = PORT_S - socks_proxy = 127.0.0.1 port=PORT_S OPT + socks_proxy = 127.0.0.1 port=PORT_D OPT debug_print = transport_name <$transport_name> diff --git a/test/log/4020 b/test/log/4020 index f289beffd..b5e1f7bef 100644 --- a/test/log/4020 +++ b/test/log/4020 @@ -1,6 +1,6 @@ 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1] C="250 accepted OK" +1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 C="250 accepted OK" 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -1999-03-02 09:44:33 10HmaY-0005vi-00 => userx@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1] C="250 accepted OK" +1999-03-02 09:44:33 10HmaY-0005vi-00 => userx@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 C="250 accepted OK" 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/scripts/4020-socks/4020 b/test/scripts/4020-socks/4020 index 49d97c05f..44c885b8d 100644 --- a/test/scripts/4020-socks/4020 +++ b/test/scripts/4020-socks/4020 @@ -3,7 +3,7 @@ munge loopback # # auth: null -server PORT_S +server PORT_D <<\x05\x01\x00 >>\x05\x00 <<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8 @@ -42,7 +42,7 @@ quit # # # auth: username/password -server PORT_S +server PORT_D <<\x05\x01\x02 >>\x05\x02 <<\x01\x04fred\x05fubar diff --git a/test/stdout/4020 b/test/stdout/4020 index 720c954fd..293f5136e 100644 --- a/test/stdout/4020 +++ b/test/stdout/4020 @@ -22,7 +22,7 @@ 221 myhost.test.ex closing connection ******** SERVER ******** -Listening on port 1224 ... +Listening on port 1225 ... Connection request from [ip4.ip4.ip4.ip4] <<\x05\x01\x00 >>\x05\x00 @@ -43,7 +43,7 @@ R QUIT 250 bye End of script -Listening on port 1224 ... +Listening on port 1225 ... Connection request from [ip4.ip4.ip4.ip4] <<\x05\x01\x02 >>\x05\x02 -- 2.30.2