summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/scripts/MakeLinks1
-rw-r--r--src/src/EDITME3
-rw-r--r--src/src/config.h.defaults3
-rw-r--r--src/src/exim.c3
-rw-r--r--src/src/functions.h10
-rw-r--r--src/src/ip.c64
-rw-r--r--src/src/smtp_out.c142
-rw-r--r--src/src/transports/Makefile3
-rw-r--r--src/src/transports/smtp.c14
-rw-r--r--src/src/transports/smtp.h8
-rw-r--r--src/src/transports/smtp_socks.c310
-rw-r--r--src/src/verify.c9
12 files changed, 455 insertions, 115 deletions
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index a50f75b36..f68fd6f4b 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -105,6 +105,7 @@ ln -s ../../src/transports/pipe.h pipe.h
ln -s ../../src/transports/pipe.c pipe.c
ln -s ../../src/transports/smtp.h smtp.h
ln -s ../../src/transports/smtp.c smtp.c
+ln -s ../../src/transports/smtp_socks.c smtp_socks.c
ln -s ../../src/transports/tf_maildir.c tf_maildir.c
ln -s ../../src/transports/tf_maildir.h tf_maildir.h
diff --git a/src/src/EDITME b/src/src/EDITME
index 353dde3ee..d48f268b9 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -494,6 +494,9 @@ EXIM_MONITOR=eximon.bin
# Uncomment the following line to add DANE support
# EXPERIMENTAL_DANE=yes
+# Uncomment the following line to add SOCKS support
+# EXPERIMENTAL_SOCKS=yes
+
###############################################################################
# THESE ARE THINGS YOU MIGHT WANT TO SPECIFY #
###############################################################################
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index e339bdf9e..ac4994a3e 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -170,11 +170,12 @@ it's a default value. */
#define EXPERIMENTAL_DANE
#define EXPERIMENTAL_DCC
#define EXPERIMENTAL_DMARC
+#define EXPERIMENTAL_EVENT
#define EXPERIMENTAL_PROXY
#define EXPERIMENTAL_REDIS
+#define EXPERIMENTAL_SOCKS
#define EXPERIMENTAL_SPF
#define EXPERIMENTAL_SRS
-#define EXPERIMENTAL_EVENT
/* For developers */
#define WANT_DEEPER_PRINTF_CHECKS
diff --git a/src/src/exim.c b/src/src/exim.c
index c94bdc1db..54725ef37 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -853,6 +853,9 @@ fprintf(f, "Support for:");
#ifdef EXPERIMENTAL_REDIS
fprintf(f, " Experimental_Redis");
#endif
+#ifdef EXPERIMENTAL_SOCKS
+ fprintf(f, " Experimental_SOCKS");
+#endif
fprintf(f, "\n");
fprintf(f, "Lookups (built-in):");
diff --git a/src/src/functions.h b/src/src/functions.h
index 49bb5a952..df40d6456 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -208,6 +208,7 @@ extern uschar *host_ntoa(int, const void *, uschar *, int *);
extern int host_scan_for_local_hosts(host_item *, host_item **, BOOL *);
extern void invert_address(uschar *, uschar *);
+extern int ip_addr(void *, int, const uschar *, int);
extern int ip_bind(int, int, uschar *, int);
extern int ip_connect(int, int, const uschar *, int, int);
extern int ip_connectedsocket(int, const uschar *, int, int,
@@ -358,11 +359,10 @@ extern int sieve_interpret(uschar *, int, uschar *, uschar *, uschar *,
extern void sigalrm_handler(int);
extern BOOL smtp_buffered(void);
extern void smtp_closedown(uschar *);
-extern int smtp_connect(host_item *, int, int, uschar *, int, BOOL, const uschar *
-#ifdef EXPERIMENTAL_EVENT
- , uschar *
-#endif
- );
+extern int smtp_connect(host_item *, int, int, uschar *, int,
+ transport_instance *);
+extern int smtp_sock_connect(host_item *, int, int, uschar *,
+ transport_instance * tb, int);
extern int smtp_feof(void);
extern int smtp_ferror(void);
extern uschar *smtp_get_connection_info(void);
diff --git a/src/src/ip.c b/src/src/ip.c
index f6072c2e8..83c8d167b 100644
--- a/src/src/ip.c
+++ b/src/src/ip.c
@@ -97,24 +97,11 @@ ip_addrinfo(const uschar *address, struct sockaddr_in6 *saddr)
* Bind socket to interface and port *
*************************************************/
-/* This function binds a socket to a local interface address and port. For a
-wildcard IPv6 bind, the address is ":".
-
-Arguments:
- sock the socket
- af AF_INET or AF_INET6 - the socket type
- address the IP address, in text form
- port the IP port (host order)
-
-Returns: the result of bind()
-*/
-
int
-ip_bind(int sock, int af, uschar *address, int port)
+ip_addr(void * sin_, int af, const uschar * address, int port)
{
-int s_len;
-union sockaddr_46 sin;
-memset(&sin, 0, sizeof(sin));
+union sockaddr_46 * sin = sin_;
+memset(sin, 0, sizeof(sin));
/* Setup code when using an IPv6 socket. The wildcard address is ":", to
ensure an IPv6 socket is used. */
@@ -124,15 +111,13 @@ if (af == AF_INET6)
{
if (address[0] == ':' && address[1] == 0)
{
- sin.v6.sin6_family = AF_INET6;
- sin.v6.sin6_addr = in6addr_any;
+ sin->v6.sin6_family = AF_INET6;
+ sin->v6.sin6_addr = in6addr_any;
}
else
- {
- ip_addrinfo(address, &sin.v6); /* Panic-dies on error */
- }
- sin.v6.sin6_port = htons(port);
- s_len = sizeof(sin.v6);
+ ip_addrinfo(address, &sin->v6); /* Panic-dies on error */
+ sin->v6.sin6_port = htons(port);
+ return sizeof(sin->v6);
}
else
#else /* HAVE_IPv6 */
@@ -142,17 +127,34 @@ af = af; /* Avoid compiler warning */
/* Setup code when using IPv4 socket. The wildcard address is "". */
{
- sin.v4.sin_family = AF_INET;
- sin.v4.sin_port = htons(port);
- s_len = sizeof(sin.v4);
- if (address[0] == 0)
- sin.v4.sin_addr.s_addr = (S_ADDR_TYPE)INADDR_ANY;
- else
- sin.v4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CS address);
+ sin->v4.sin_family = AF_INET;
+ sin->v4.sin_port = htons(port);
+ sin->v4.sin_addr.s_addr = address[0] == 0
+ ? (S_ADDR_TYPE)INADDR_ANY
+ : (S_ADDR_TYPE)inet_addr(CS address);
+ return sizeof(sin->v4);
}
+}
-/* Now we can call the bind() function */
+
+/* This function binds a socket to a local interface address and port. For a
+wildcard IPv6 bind, the address is ":".
+
+Arguments:
+ sock the socket
+ af AF_INET or AF_INET6 - the socket type
+ address the IP address, in text form
+ port the IP port (host order)
+
+Returns: the result of bind()
+*/
+
+int
+ip_bind(int sock, int af, uschar *address, int port)
+{
+union sockaddr_46 sin;
+int s_len = ip_addr(&sin, af, address, port);
return bind(sock, (struct sockaddr *)&sin, s_len);
}
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index 8147b61d0..724339556 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -2,13 +2,14 @@
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
/* See the file NOTICE for conditions of use and distribution. */
/* A number of functions for driving outgoing SMTP calls. */
#include "exim.h"
+#include "transports/smtp.h"
@@ -143,75 +144,26 @@ return TRUE;
-/*************************************************
-* Connect to remote host *
-*************************************************/
-
-/* Create a socket, and connect it to a remote host. IPv6 addresses are
-detected by checking for a colon in the address. AF_INET6 is defined even on
-non-IPv6 systems, to enable the code to be less messy. However, on such systems
-host->address will always be an IPv4 address.
-
-The port field in the host item is used if it is set (usually router from SRV
-records or elsewhere). In other cases, the default passed as an argument is
-used, and the host item is updated with its value.
-
-Arguments:
- host host item containing name and address (and sometimes port)
- host_af AF_INET or AF_INET6
- port default remote port to connect to, in host byte order, for those
- hosts whose port setting is PORT_NONE
- interface outgoing interface address or NULL
- timeout timeout value or 0
- keepalive TRUE to use keepalive
- dscp DSCP value to assign to socket
- event event expansion
-
-Returns: connected socket number, or -1 with errno set
-*/
-
int
-smtp_connect(host_item *host, int host_af, int port, uschar *interface,
- int timeout, BOOL keepalive, const uschar *dscp
-#ifdef EXPERIMENTAL_EVENT
- , uschar * event
-#endif
- )
+smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
+ transport_instance * tb, int timeout)
{
-int on = 1;
-int save_errno = 0;
+smtp_transport_options_block * ob =
+ (smtp_transport_options_block *)tb->options_block;
+const uschar * dscp = ob->dscp;
int dscp_value;
int dscp_level;
int dscp_option;
int sock;
-
-if (host->port != PORT_NONE)
- {
- HDEBUG(D_transport|D_acl|D_v)
- debug_printf("Transport port=%d replaced by host-specific port=%d\n", port,
- host->port);
- port = host->port;
- }
-else host->port = port; /* Set the port actually used */
-
-HDEBUG(D_transport|D_acl|D_v)
- {
- if (interface == NULL)
- debug_printf("Connecting to %s [%s]:%d ... ",host->name,host->address,port);
- else
- debug_printf("Connecting to %s [%s]:%d from %s ... ", host->name,
- host->address, port, interface);
- }
+int on = 1;
+int save_errno = 0;
#ifdef EXPERIMENTAL_EVENT
- deliver_host_address = host->address;
- deliver_host_port = port;
- if (event_raise(event, US"tcp:connect", NULL)) return -1;
- /* Logging? Debug? */
+deliver_host_address = host->address;
+deliver_host_port = port;
+if (event_raise(tb->event_action, US"tcp:connect", NULL)) return -1;
#endif
-/* Create the socket */
-
if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return -1;
/* Set TCP_NODELAY; Exim does its own buffering. */
@@ -232,15 +184,13 @@ if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
option for both; ignore failures here */
if (host_af == AF_INET6 &&
dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
- {
(void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
- }
}
/* Bind to a specific interface if requested. Caller must ensure the interface
is the same type (IPv4 or IPv6) as the outgoing address. */
-if (interface != NULL && ip_bind(sock, host_af, interface, 0) < 0)
+if (interface && ip_bind(sock, host_af, interface, 0) < 0)
{
save_errno = errno;
HDEBUG(D_transport|D_acl|D_v)
@@ -286,11 +236,73 @@ else
close(sock);
return -1;
}
- if (keepalive) ip_keepalive(sock, host->address, TRUE);
+ if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
return sock;
}
}
+/*************************************************
+* Connect to remote host *
+*************************************************/
+
+/* Create a socket, and connect it to a remote host. IPv6 addresses are
+detected by checking for a colon in the address. AF_INET6 is defined even on
+non-IPv6 systems, to enable the code to be less messy. However, on such systems
+host->address will always be an IPv4 address.
+
+The port field in the host item is used if it is set (usually router from SRV
+records or elsewhere). In other cases, the default passed as an argument is
+used, and the host item is updated with its value.
+
+Arguments:
+ host host item containing name and address (and sometimes port)
+ host_af AF_INET or AF_INET6
+ port default remote port to connect to, in host byte order, for those
+ hosts whose port setting is PORT_NONE
+ interface outgoing interface address or NULL
+ timeout timeout value or 0
+ tb transport
+
+Returns: connected socket number, or -1 with errno set
+*/
+
+int
+smtp_connect(host_item *host, int host_af, int port, uschar *interface,
+ int timeout, transport_instance * tb)
+{
+smtp_transport_options_block * ob =
+ (smtp_transport_options_block *)tb->options_block;
+
+if (host->port != PORT_NONE)
+ {
+ HDEBUG(D_transport|D_acl|D_v)
+ debug_printf("Transport port=%d replaced by host-specific port=%d\n", port,
+ host->port);
+ port = host->port;
+ }
+else host->port = port; /* Set the port actually used */
+
+HDEBUG(D_transport|D_acl|D_v)
+ {
+ uschar * s = US" ";
+ if (interface) s = string_sprintf(" from %s ", interface);
+#ifdef EXPERIMENTAL_SOCKS
+ if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s);
+#endif
+ debug_printf("Connecting to %s [%s]:%d%s... ",
+ host->name, host->address, port, s);
+ }
+
+/* Create and connect the socket */
+
+#ifdef EXPERIMENTAL_SOCKS
+if (ob->socks_proxy)
+ return socks_sock_connect(host, host_af, port, interface, tb, timeout);
+#endif
+
+return smtp_sock_connect(host, host_af, port, interface, tb, timeout);
+}
+
/*************************************************
* Flush outgoing command buffer *
@@ -581,3 +593,5 @@ return buffer[0] == okdigit;
}
/* End of smtp_out.c */
+/* vi: aw ai sw=2
+*/
diff --git a/src/src/transports/Makefile b/src/src/transports/Makefile
index 02cf0c8d7..25973d5df 100644
--- a/src/src/transports/Makefile
+++ b/src/src/transports/Makefile
@@ -2,7 +2,7 @@
# calling it transports.a. This is called from the main make file, after cd'ing
# to the transports subdirectory.
-OBJ = appendfile.o autoreply.o lmtp.o pipe.o smtp.o tf_maildir.o
+OBJ = appendfile.o autoreply.o lmtp.o pipe.o smtp.o smtp_socks.o tf_maildir.o
transports.a: $(OBJ)
@$(RM_COMMAND) -f transports.a
@@ -19,6 +19,7 @@ autoreply.o: $(HDRS) autoreply.c autoreply.h
lmtp.o: $(HDRS) lmtp.c lmtp.h
pipe.o: $(HDRS) pipe.c pipe.h
smtp.o: $(HDRS) smtp.c smtp.h
+smtp_socks.o: $(HDRS) smtp_socks.c smtp.h
tf_maildir.o: $(HDRS) tf_maildir.c tf_maildir.h appendfile.h
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 5662ffbf2..11d7fdd12 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -159,6 +159,10 @@ optionlist smtp_transport_options[] = {
(void *)offsetof(smtp_transport_options_block, serialize_hosts) },
{ "size_addition", opt_int,
(void *)offsetof(smtp_transport_options_block, size_addition) }
+#ifdef EXPERIMENTAL_SOCKS
+ ,{ "socks_proxy", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, socks_proxy) }
+#endif
#ifdef SUPPORT_TLS
,{ "tls_certificate", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, tls_certificate) },
@@ -246,6 +250,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
FALSE, /* lmtp_ignore_quota */
NULL, /* expand_retry_include_ip_address */
TRUE /* retry_include_ip_address */
+#ifdef EXPERIMENTAL_SOCKS
+#endif
+ ,NULL /* socks_proxy */
#ifdef SUPPORT_TLS
,NULL, /* tls_certificate */
NULL, /* tls_crl */
@@ -1350,12 +1357,7 @@ if (continue_hostname == NULL)
{
/* This puts port into host->port */
inblock.sock = outblock.sock =
- smtp_connect(host, host_af, port, interface, ob->connect_timeout,
- ob->keepalive, ob->dscp
-#ifdef EXPERIMENTAL_EVENT
- , tblock->event_action
-#endif
- );
+ smtp_connect(host, host_af, port, interface, ob->connect_timeout, tblock);
if (inblock.sock < 0)
{
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index 1b51c133d..84fb9f50c 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -60,6 +60,9 @@ typedef struct {
BOOL lmtp_ignore_quota;
uschar *expand_retry_include_ip_address;
BOOL retry_include_ip_address;
+#ifdef EXPERIMENTAL_SOCKS
+ uschar *socks_proxy;
+#endif
#ifdef SUPPORT_TLS
uschar *tls_certificate;
uschar *tls_crl;
@@ -109,4 +112,9 @@ extern int smtp_auth(uschar *, unsigned, address_item *, host_item *,
extern BOOL smtp_mail_auth_str(uschar *, unsigned,
address_item *, smtp_transport_options_block *);
+#ifdef EXPERMENTAL_SOCKS
+extern int socks_sock_connect(host_item, int, int, uschar *,
+ transport_instance *, int);
+#endif
+
/* End of transports/smtp.h */
diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c
new file mode 100644
index 000000000..cf9f73ba3
--- /dev/null
+++ b/src/src/transports/smtp_socks.c
@@ -0,0 +1,310 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2015 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* SOCKS version 5 proxy, client-mode */
+
+#include "../exim.h"
+#include "smtp.h"
+
+#ifdef EXPERIMENTAL_SOCKS /* entire file */
+
+#ifndef nelem
+# define nelem(arr) (sizeof(arr)/sizeof(*arr))
+#endif
+
+
+/* Defaults */
+#define SOCKS_PORT 1080
+#define SOCKS_TIMEOUT 5
+
+#define AUTH_NONE 0
+#define AUTH_NAME 2 /* user/password per RFC 1929 */
+#define AUTH_NAME_VER 1
+
+struct socks_err
+ {
+ uschar * reason;
+ int errcode;
+ } socks_errs[] =
+ {
+ {NULL, 0},
+ {US"general SOCKS server failure", EIO},
+ {US"connection not allowed by ruleset", EACCES},
+ {US"Network unreachable", ENETUNREACH},
+ {US"Host unreachable", EHOSTUNREACH},
+ {US"Connection refused", ECONNREFUSED},
+ {US"TTL expired", ECANCELED},
+ {US"Command not supported", EOPNOTSUPP},
+ {US"Address type not supported", EAFNOSUPPORT}
+ };
+
+typedef struct
+ {
+ uschar auth_type; /* RFC 1928 encoding */
+ const uschar * auth_name;
+ const uschar * auth_pwd;
+ short port;
+ unsigned timeout;
+ } socks_opts;
+
+static void
+socks_option_defaults(socks_opts * sob)
+{
+sob->auth_type = AUTH_NONE;
+sob->auth_name = US"";
+sob->auth_pwd = US"";
+sob->port = SOCKS_PORT;
+sob->timeout = SOCKS_TIMEOUT;
+}
+
+static void
+socks_option(socks_opts * sob, const uschar * opt)
+{
+const uschar * s;
+
+if (Ustrncmp(opt, "auth=", 5) == 0)
+ {
+ opt += 5;
+ if (Ustrcmp(opt, "none") == 0) sob->auth_type = AUTH_NONE;
+ else if (Ustrcmp(opt, "name") == 0) sob->auth_type = AUTH_NAME;
+ }
+else if (Ustrncmp(opt, "name=", 5) == 0)
+ sob->auth_name = opt + 5;
+else if (Ustrncmp(opt, "pass=", 5) == 0)
+ sob->auth_pwd = opt + 5;
+else if (Ustrncmp(opt, "port=", 5) == 0)
+ sob->port = atoi(opt + 5);
+else if (Ustrncmp(opt, "tmo=", 4) == 0)
+ sob->timeout = atoi(opt + 4);
+return;
+}
+
+static int
+socks_auth(int fd, int method, socks_opts * sob, time_t tmo)
+{
+uschar * s;
+int len, i, j;
+
+switch(method)
+ {
+ default:
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "Unrecognised socks auth method %d", method);
+ return FAIL;
+ case AUTH_NONE:
+ return OK;
+ case AUTH_NAME:
+ HDEBUG(D_transport|D_acl|D_v) debug_printf(" socks auth NAME '%s' '%s'\n",
+ sob->auth_name, sob->auth_pwd);
+ i = Ustrlen(sob->auth_name);
+ j = Ustrlen(sob->auth_pwd);
+ s = string_sprintf("%c%c%.255s%c%.255s", AUTH_NAME_VER,
+ i, sob->auth_name, j, sob->auth_pwd);
+ len = i + j + 3;
+ HDEBUG(D_transport|D_acl|D_v)
+ {
+ int i;
+ debug_printf(" SOCKS>>");
+ for (i = 0; i<len; i++) debug_printf(" %02x", s[i]);
+ debug_printf("\n");
+ }
+ if ( send(fd, s, len, 0) < 0
+ || !fd_ready(fd, tmo-time(NULL))
+ || read(fd, s, 2) != 2
+ )
+ return FAIL;
+ HDEBUG(D_transport|D_acl|D_v)
+ debug_printf(" SOCKS<< %02x %02x\n", s[0], s[1]);
+ if (s[0] == AUTH_NAME_VER && s[1] == 0)
+ {
+ HDEBUG(D_transport|D_acl|D_v) debug_printf(" socks auth OK\n");
+ return OK;
+ }
+
+ log_write(0, LOG_MAIN|LOG_PANIC, "socks auth failed");
+ errno = EPROTO;
+ return FAIL;
+ }
+}
+
+
+
+/* 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)
+
+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)
+
+{
+smtp_transport_options_block * ob =
+ (smtp_transport_options_block *)tb->options_block;
+const uschar * proxy_list;
+const uschar * proxy_spec;
+int sep = 0;
+int fd;
+time_t tmo;
+const uschar * state;
+uschar buf[24];
+
+if (!timeout) timeout = 24*60*60; /* use 1 day for "indefinite" */
+tmo = time(NULL) + timeout;
+
+if (!(proxy_list = expand_string(ob->socks_proxy)))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "Bad expansion for socks_proxy in %s",
+ tb->name);
+ return -1;
+ }
+
+/* Loop over proxy list, trying in order until one works */
+while ((proxy_spec = string_nextinlist(&proxy_list, &sep, NULL, 0)))
+ {
+ const uschar * proxy_host;
+ int subsep = -' ';
+ host_item proxy;
+ int proxy_af;
+ union sockaddr_46 sin;
+ unsigned size;
+ socks_opts sob;
+ const uschar * option;
+
+ if (!(proxy_host = string_nextinlist(&proxy_spec, &subsep, NULL, 0)))
+ {
+ /* paniclog config error */
+ return -1;
+ }
+
+ /*XXX consider global options eg. "hide socks_password = wibble" on the tpt */
+ socks_option_defaults(&sob);
+
+ /* extract any further per-proxy options */
+ while ((option = string_nextinlist(&proxy_spec, &subsep, NULL, 0)))
+ socks_option(&sob, option);
+
+ /* bodge up a host struct for the proxy */
+ proxy.address = proxy_host;
+ proxy_af = Ustrchr(proxy_host, ':') ? AF_INET6 : AF_INET;
+
+ if ((fd = smtp_sock_connect(&proxy, proxy_af, sob.port,
+ interface, tb, sob.timeout)) < 0)
+ continue;
+
+ /* Do the socks protocol stuff */
+ /* Send method-selection */
+ state = US"method select";
+ HDEBUG(D_transport|D_acl|D_v) debug_printf(" SOCKS>> 05 01 %02x\n", sob.auth_type);
+ buf[0] = 5; buf[1] = 1; buf[2] = sob.auth_type;
+ if (send(fd, buf, 3, 0) < 0)
+ goto snd_err;
+
+ /* expect method response */
+ if ( !fd_ready(fd, tmo-time(NULL))
+ || read(fd, buf, 2) != 2
+ )
+ goto rcv_err;
+ HDEBUG(D_transport|D_acl|D_v)
+ debug_printf(" SOCKS<< %02x %02x\n", buf[0], buf[1]);
+ if ( buf[0] != 5
+ || socks_auth(fd, buf[1], &sob, tmo) != OK
+ )
+ goto proxy_err;
+
+ (void) ip_addr(&sin, host_af, host->address, port);
+
+ /* send connect (ipver, ipaddr, port) */
+ buf[0] = 5; buf[1] = 1; buf[2] = 0; buf[3] = host_af == AF_INET6 ? 4 : 1;
+ if (host_af == AF_INET6)
+ {
+ memcpy(buf+4, &sin.v6.sin6_addr, sizeof(sin.v6.sin6_addr));
+ memcpy(buf+4+sizeof(sin.v6.sin6_addr),
+ &sin.v6.sin6_port, sizeof(sin.v6.sin6_port));
+ size = 4+sizeof(sin.v6.sin6_addr)+sizeof(sin.v6.sin6_port);
+ }
+ else
+ {
+ memcpy(buf+4, &sin.v4.sin_addr.s_addr, sizeof(sin.v4.sin_addr.s_addr));
+ memcpy(buf+4+sizeof(sin.v4.sin_addr.s_addr),
+ &sin.v4.sin_port, sizeof(sin.v4.sin_port));
+ size = 4+sizeof(sin.v4.sin_addr.s_addr)+sizeof(sin.v4.sin_port);
+ }
+
+ state = US"connect";
+ HDEBUG(D_transport|D_acl|D_v)
+ {
+ int i;
+ debug_printf(" SOCKS>>");
+ for (i = 0; i<size; i++) debug_printf(" %02x", buf[i]);
+ debug_printf("\n");
+ }
+ if (send(fd, buf, size, 0) < 0)
+ goto snd_err;
+
+ /* expect conn-reply (success, local(ipver, addr, port))
+ of same length as conn-request, or non-success fail code */
+ if ( !fd_ready(fd, tmo-time(NULL))
+ || (size = read(fd, buf, size)) < 2
+ )
+ goto rcv_err;
+ HDEBUG(D_transport|D_acl|D_v)
+ {
+ int i;
+ debug_printf(" SOCKS>>");
+ for (i = 0; i<size; i++) debug_printf(" %02x", buf[i]);
+ debug_printf("\n");
+ }
+ if ( buf[0] != 5
+ || buf[1] != 0
+ )
+ goto proxy_err;
+
+ /*XXX log proxy outbound addr/port? */
+ 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)))));
+
+ return fd;
+ }
+
+HDEBUG(D_transport|D_acl|D_v) debug_printf(" no proxies left\n");
+return -1;
+
+snd_err:
+ HDEBUG(D_transport|D_acl|D_v) debug_printf(" proxy snd_err %s: %s\n", state, strerror(errno));
+ return -1;
+
+proxy_err:
+ {
+ struct socks_err * se =
+ buf[1] > nelem(socks_errs) ? NULL : socks_errs + buf[1];
+ HDEBUG(D_transport|D_acl|D_v)
+ debug_printf(" proxy %s: %s\n", state, se ? se->reason : US"unknown error code received");
+ errno = se ? se->errcode : EPROTO;
+ }
+
+rcv_err:
+ HDEBUG(D_transport|D_acl|D_v) debug_printf(" proxy rcv_err %s: %s\n", state, strerror(errno));
+ if (!errno) errno = EPROTO;
+ else if (errno == ENOENT) errno = ECONNABORTED;
+ return -1;
+}
+
+#endif /* entire file */
+/* vi: aw ai sw=2
+*/
diff --git a/src/src/verify.c b/src/src/verify.c
index c1fb17767..d85ef3b4f 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -641,13 +641,8 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
tls_out.cipher = tls_out.peerdn = tls_out.peercert = NULL;
inblock.sock = outblock.sock =
- smtp_connect(host, host_af, port, interface, callout_connect, TRUE, NULL
-#ifdef EXPERIMENTAL_EVENT
- /*XXX event action? NULL for now. */
- , NULL
-#endif
- );
- /* reconsider DSCP here */
+ smtp_connect(host, host_af, port, interface, callout_connect,
+ addr->transport);
if (inblock.sock < 0)
{
addr->message = string_sprintf("could not connect to %s [%s]: %s",