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"
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
/* 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
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
#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 */
/* 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;
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;
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 */
{
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)
{
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;
/* 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 */
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) */
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:
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
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@test.ex 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@myhost.test.ex 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@test.ex 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
# 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$/;
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@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be sent
+
+direct, not via proxy
+.
+quit
+****
#
# Ends
354 Enter message, ending with "." on a line by itself\r
250 OK id=10HmaY-000000005vi-0000\r
221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-LIMITS MAILMAX=1000 RCPTMAX=50000\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaZ-000000005vi-0000\r
+221 myhost.test.ex closing connection\r
******** SERVER ********
Listening on port 1225 ...
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@myhost.test.ex>
+250
+RCPT TO:<userx@test.ex>
+250
+DATA
+354 hit me
+Received: from CALLER (helo=test.ex)
+ by myhost.test.ex with local-esmtp (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmaZ-000000005vi-0000
+ for userx@test.ex;
+ 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@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+
+direct, not via proxy
+.
+250 accepted OK
+QUIT
+250 bye
+End of script