Gitweb:
https://git.exim.org/exim.git/commitdiff/7b505d28898cadb14eebded54b255d22541caaa6
Commit: 7b505d28898cadb14eebded54b255d22541caaa6
Parent: cf4659b914328be054abb5706fd7f2649db9a8ac
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Tue Oct 8 13:56:25 2024 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Tue Oct 8 13:56:25 2024 +0100
SOCKS: support option expansion result for no-proxy. Bug 3118
---
doc/doc-docbook/spec.xfpt | 7 +++--
doc/doc-txt/NewStuff | 3 +++
src/src/smtp_out.c | 48 +++++++++++----------------------
src/src/transports/smtp.h | 3 +--
src/src/transports/smtp_socks.c | 59 ++++++++++++++++++++++++++---------------
test/confs/4020 | 4 +++
test/log/4020 | 4 +++
test/runtest | 3 +++
test/scripts/4020-socks/4020 | 30 +++++++++++++++++++++
test/stdout/4020 | 41 ++++++++++++++++++++++++++++
10 files changed, 145 insertions(+), 57 deletions(-)
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index dc41146b3..76bdd1396 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -43122,13 +43122,16 @@ Local/Makefile.
Use of a proxy is enabled by setting the &%socks_proxy%& option
on an smtp transport.
-The option value is expanded and should then be a list
+.new
+If unset (or empty after expansion) then proxying is not done.
+.wen
+Otherwise, expansion should result in a list
(colon-separated by default) of proxy specifiers.
Each proxy specifier is a list
(space-separated by default) where the initial element
is an IP address and any subsequent elements are options.
-Options are a string <name>=<value>.
+Each option is a string of form <name>=<value>.
The list of options is in the following table:
.itable none 0 0 2 10* left 90* left
.irow &'auth'& "authentication method"
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 0a83c294a..86c5dad83 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -21,6 +21,9 @@ Version 4.98
and all the transport drivers except smtp, can now be built as loadable
modules
+ 6. A transport "socks_proxy" may expand to an empty string, specifying no
+ proxying.
+
Version 4.98
------------
1. The dkim_status ACL condition may now be used in data ACLs
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index 2ea29a7e4..4d31ff39e 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -319,12 +319,8 @@ return sock;
/* Arguments:
- host host item containing name and address and port
- host_af AF_INET or AF_INET6
- port TCP port number
- interface outgoing interface address or NULL
- tb transport
- timeout timeout value or 0
+ sc details for making connection: host, af, interface, transport
+ timeout timeout value or 0
early_data if non-NULL, idempotent data to be sent -
preferably in the TCP SYN segment
Special case: non-NULL but with NULL blob.data - caller is
@@ -484,48 +480,36 @@ Returns: connected socket number, or -1 with errno set
int
smtp_connect(smtp_connect_args * sc, const blob * early_data)
{
-int port = sc->host->port;
smtp_transport_options_block * ob = sc->ob;
-callout_address = string_sprintf("[%s]:%d", sc->host->address, port);
+callout_address = string_sprintf("[%s]:%d", sc->host->address, sc->host->port);
HDEBUG(D_transport|D_acl|D_v)
{
- uschar * s = US" ";
- if (sc->interface) s = string_sprintf(" from %s ", sc->interface);
+ gstring * g = sc->interface
+ ? string_fmt_append(NULL, " from %s", sc->interface)
+ : string_get(10);
#ifdef SUPPORT_SOCKS
- if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s);
+ if (ob->socks_proxy) g = string_catn(g, US"via proxy", 9);
#endif
- debug_printf_indent("Connecting to %s %s%s...\n", sc->host->name, callout_address, s);
+ debug_printf_indent("Connecting to %s %s%Y ...\n",
+ sc->host->name, callout_address, g);
}
/* Create and connect the socket */
#ifdef SUPPORT_SOCKS
+GET_OPTION("socks_proxy");
if (ob->socks_proxy)
{
- int sock = socks_sock_connect(sc->host, sc->host_af, port, sc->interface,
- sc->tblock, ob->connect_timeout);
-
- if (sock >= 0)
+ if (!(ob->socks_proxy = expand_string(ob->socks_proxy)))
{
- if (early_data && early_data->data && early_data->len)
- if (send(sock, early_data->data, early_data->len, 0) < 0)
- {
- int save_errno = errno;
- HDEBUG(D_transport|D_acl|D_v)
- {
- debug_printf_indent("failed: %s", CUstrerror(save_errno));
- if (save_errno == ETIMEDOUT)
- debug_printf(" (timeout=%s)", readconf_printtime(ob->connect_timeout));
- debug_printf("\n");
- }
- (void)close(sock);
- sock = -1;
- errno = save_errno;
- }
+ log_write(0, LOG_MAIN|LOG_PANIC, "Bad expansion for socks_proxy in %s",
+ sc->tblock->drinst.name);
+ return -1;
}
- return sock;
+ if (*ob->socks_proxy)
+ return socks_sock_connect(sc, early_data);
}
#endif
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index 9fc95444b..fe4b1c17a 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -247,8 +247,7 @@ extern void smtp_transport_closedown(transport_instance *);
#ifdef SUPPORT_SOCKS
-extern int socks_sock_connect(host_item *, int, int, uschar *,
- transport_instance *, int);
+extern int socks_sock_connect(smtp_connect_args *, const blob *);
#endif
/* End of transports/smtp.h */
diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c
index a626a00d3..8d4beb39a 100644
--- a/src/src/transports/smtp_socks.c
+++ b/src/src/transports/smtp_socks.c
@@ -196,23 +196,21 @@ return -1;
/* Make a connection via a socks proxy
Arguments:
- host smtp target host
- host_af address family
- port remote tcp port number
- interface local interface
- tb transport
- timeout connection timeout (zero for indefinite)
+ sc details for making connection: host, af, interface, transport
+ early_data data to send down the smtp channel (once proxied)
Return value:
0 on success; -1 on failure, with errno set
*/
int
-socks_sock_connect(host_item * host, int host_af, int port, uschar * interface,
- transport_instance * tb, int timeout)
+socks_sock_connect(smtp_connect_args * sc, const blob * early_data)
{
+transport_instance * tb = sc->tblock;
smtp_transport_options_block * ob = tb->drinst.options_block;
-const uschar * proxy_list, * proxy_spec;
+int timeout = ob->connect_timeout;
+const uschar * proxy_list = ob->socks_proxy, /* already expanded */
+ * proxy_spec;
int sep = 0;
int fd;
time_t tmo;
@@ -222,7 +220,7 @@ socks_opts proxies[32]; /* max #proxies handled */
unsigned nproxies;
socks_opts * sob = NULL;
unsigned size;
-blob early_data;
+blob proxy_early_data;
if (!timeout) timeout = 24*60*60; /* use 1 day for "indefinite" */
tmo = time(NULL) + timeout;
@@ -265,8 +263,8 @@ for sending on connection */
state = US"method select";
buf[0] = 5; buf[1] = 1; buf[2] = sob->auth_type;
-early_data.data = buf;
-early_data.len = 3;
+proxy_early_data.data = buf;
+proxy_early_data.len = 3;
/* Try proxies until a connection succeeds */
@@ -274,7 +272,7 @@ for(;;)
{
int idx;
host_item proxy;
- smtp_connect_args sc = {.sock = -1};
+ smtp_connect_args proxy_sc = {.sock = -1};
if ((idx = socks_get_proxy(proxies, nproxies)) < 0)
{
@@ -288,14 +286,14 @@ for(;;)
proxy.address = proxy.name = sob->proxy_host;
proxy.port = sob->port;
- sc.tblock = tb;
- sc.ob = ob;
- sc.host = &proxy;
- sc.host_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
- sc.interface = interface;
+ proxy_sc.tblock = tb;
+ proxy_sc.ob = ob;
+ proxy_sc.host = &proxy;
+ proxy_sc.host_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
+ proxy_sc.interface = sc->interface;
/*XXX we trust that the method-select command is idempotent */
- if ((fd = smtp_sock_connect(&sc, sob->timeout, &early_data)) >= 0)
+ if ((fd = smtp_sock_connect(&proxy_sc, sob->timeout, &proxy_early_data)) >= 0)
{
proxy_local_address = string_copy(proxy.address);
proxy_local_port = sob->port;
@@ -308,7 +306,8 @@ for(;;)
/* Do the socks protocol stuff */
-HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SOCKS>> 05 01 %02x\n", sob->auth_type);
+HDEBUG(D_transport|D_acl|D_v)
+ debug_printf_indent(" SOCKS>> 05 01 %02x\n", sob->auth_type);
/* expect method response */
@@ -328,8 +327,10 @@ if ( buf[0] != 5
goto proxy_err;
{
+ int host_af = sc->host_af;
+ host_item * host = sc->host;
union sockaddr_46 sin;
- (void) ip_addr(&sin, host_af, host->address, port);
+ (void) ip_addr(&sin, host_af, host->address, host->port);
/* send connect (ipver, ipaddr, port) */
@@ -388,6 +389,22 @@ proxy_session = TRUE;
HDEBUG(D_transport|D_acl|D_v)
debug_printf_indent(" proxy farside: [%s]:%d\n", proxy_external_address, proxy_external_port);
+if (early_data && early_data->data && early_data->len)
+ if (send(fd, early_data->data, early_data->len, 0) < 0)
+ {
+ int save_errno = errno;
+ HDEBUG(D_transport|D_acl|D_v)
+ {
+ debug_printf_indent("failed: %s", CUstrerror(save_errno));
+ if (save_errno == ETIMEDOUT)
+ debug_printf(" (timeout=%s)", readconf_printtime(ob->connect_timeout));
+ debug_printf("\n");
+ }
+ (void)close(fd);
+ fd= -1;
+ errno = save_errno;
+ }
+
return fd;
snd_err:
diff --git a/test/confs/4020 b/test/confs/4020
index 6702dcd68..763acc15a 100644
--- a/test/confs/4020
+++ b/test/confs/4020
@@ -43,7 +43,11 @@ my_smtp:
driver = smtp
interface = HOSTIPV4
port = PORT_S
+.ifdef FALLBACK
+ socks_proxy = ${if eq {1}{1} {}}
+.else
hide socks_proxy = HOSTIPV4 port=PORT_D OPT
+.endif
hosts_try_fastopen = ${if eq {$local_part}{user_tfo} {*}}
debug_print = transport_name <$transport_name>
.ifdef _HAVE_EVENT
diff --git a/test/log/4020 b/test/log/4020
index d56b922f2..d547e9611 100644
--- a/test/log/4020
+++ b/test/log/4020
@@ -6,3 +6,7 @@
1999-03-02 09:44:33 10HmaY-000000005vi-0000 pla ip4.ip4.ip4.ip4 plp 1225 pea 127.0.0.1 pep 48879
1999-03-02 09:44:33 10HmaY-000000005vi-0000 => userx@??? R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:PORT_S PRX=[ip4.ip4.ip4.ip4]:PORT_D C="250 accepted OK"
1999-03-02 09:44:33 10HmaY-000000005vi-0000 Completed
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 <= CALLER@??? U=CALLER P=local-esmtp S=sss
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 pla plp 0 pea pep 0
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 => userx@??? R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:PORT_S C="250 accepted OK"
+1999-03-02 09:44:33 10HmaZ-000000005vi-0000 Completed
diff --git a/test/runtest b/test/runtest
index bb9b1ceee..a178659f9 100755
--- a/test/runtest
+++ b/test/runtest
@@ -1560,6 +1560,9 @@ RESET_AFTER_EXTRA_LINE_READ:
# Not all platforms build with DKIM enabled
next if /^DKIM >> Body data for hash, canonicalized/;
+ # Not all platforms build with SOCKS enabled
+ next if /^try option socks_proxy$/;
+
# Not all platforms build with SPF enabled
next if /(^$time_pid?spf_conn_init|spf_compile\.c)/;
next if /try option spf_smtp_comment_template$/;
diff --git a/test/scripts/4020-socks/4020 b/test/scripts/4020-socks/4020
index 4a0ac0893..2ba57ba52 100644
--- a/test/scripts/4020-socks/4020
+++ b/test/scripts/4020-socks/4020
@@ -80,5 +80,35 @@ via name/pwd-auth proxy
quit
****
#
+# sock_proxy option set but expands to empty string
+server PORT_S
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 hit me
+.
+250 accepted OK
+QUIT
+250 bye
+****
+#
+exim -odi -bs -DFALLBACK=yes
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@???>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be sent
+
+direct, not via proxy
+.
+quit
+****
#
# Ends
diff --git a/test/stdout/4020 b/test/stdout/4020
index 47dc6e92b..b5bbaf34d 100644
--- a/test/stdout/4020
+++ b/test/stdout/4020
@@ -22,6 +22,18 @@
354 Enter message, ending with "." on a line by itself
250 OK id=10HmaY-000000005vi-0000
221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-LIMITS MAILMAX=1000 RCPTMAX=50000
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaZ-000000005vi-0000
+221 myhost.test.ex closing connection
******** SERVER ********
Listening on port 1225 ...
@@ -68,3 +80,32 @@ R
QUIT
250 bye
End of script
+Listening on port 1224 ...
+Connection request from [ip4.ip4.ip4.ip4]
+220 Connected OK
+EHLO myhost.test.ex
+250-server id
+250
+MAIL FROM:<CALLER@???>
+250
+RCPT TO:<userx@???>
+250
+DATA
+354 hit me
+Received: from CALLER (helo=test.ex)
+ by myhost.test.ex with local-esmtp (Exim x.yz)
+ (envelope-from <CALLER@???>)
+ id 10HmaZ-000000005vi-0000
+ for userx@???;
+ Tue, 2 Mar 1999 09:44:33 +0000
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+Subject: message should be sent
+Message-Id: <E10HmaZ-000000005vi-0000@???>
+From: CALLER_NAME <CALLER@???>
+
+direct, not via proxy
+.
+250 accepted OK
+QUIT
+250 bye
+End of script
--
## subscription configuration (requires account):
##
https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at
http://www.exim.org/
## Please use the Wiki with this list -
http://wiki.exim.org/