[exim-cvs] SOCKS: support option expansion result for no-pro…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] SOCKS: support option expansion result for no-proxy. Bug 3118
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/