summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2017-10-08 16:12:06 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2017-10-08 17:30:39 +0100
commit10ac8d7f410e55043b0b182fb77f2e8fb6a7aed4 (patch)
treeb61313be7211b54cc67896ed06c71716a2800649
parent6a69d109fb79fb19663137cf606557d663169373 (diff)
TFO: on FreeBSD avoid client TFO-mode connects unless a TCP_FASTOPEN setsocketopt succeeds
This fixes the FreeSBD no-kernel-support issues (it succeded the sendto for the connect-with-data, but dod not queue the data). Having checked dynamically, do not claim support-for TFO either.
-rw-r--r--src/OS/os.h-FreeBSD1
-rw-r--r--src/src/deliver.c7
-rw-r--r--src/src/exim.c3
-rw-r--r--src/src/functions.h3
-rw-r--r--src/src/ip.c55
-rw-r--r--src/src/malware.c4
-rw-r--r--src/src/smtp_out.c10
7 files changed, 60 insertions, 23 deletions
diff --git a/src/OS/os.h-FreeBSD b/src/OS/os.h-FreeBSD
index 3a06e766e..7cb836cbe 100644
--- a/src/OS/os.h-FreeBSD
+++ b/src/OS/os.h-FreeBSD
@@ -48,6 +48,7 @@ extern ssize_t os_sendfile(int, int, off_t *, size_t);
/* TCP_FASTOPEN support. There does not seems to be a
MSG_FASTOPEN defined yet... */
+#define EXIM_TFO_PROBE
#include <netinet/tcp.h> /* for TCP_FASTOPEN */
#include <sys/socket.h> /* for MSG_FASTOPEN */
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 648c63d69..df51948d4 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -8413,6 +8413,13 @@ return final_yield;
void
deliver_init(void)
{
+#ifdef EXIM_TFO_PROBE
+tfo_probe();
+#else
+tcp_fastopen_ok = TRUE;
+#endif
+
+
if (!regex_PIPELINING) regex_PIPELINING =
regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
diff --git a/src/src/exim.c b/src/src/exim.c
index f09b26902..f0c00cdf1 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -840,7 +840,8 @@ fprintf(f, "Support for:");
fprintf(f, " SOCKS");
#endif
#ifdef TCP_FASTOPEN
- fprintf(f, " TCP_Fast_Open");
+ deliver_init();
+ if (tcp_fastopen_ok) fprintf(f, " TCP_Fast_Open");
#endif
#ifdef EXPERIMENTAL_LMDB
fprintf(f, " Experimental_LMDB");
diff --git a/src/src/functions.h b/src/src/functions.h
index 9d1f6dc6e..e9f71c984 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -474,6 +474,9 @@ extern int strcmpic(const uschar *, const uschar *);
extern int strncmpic(const uschar *, const uschar *, int);
extern uschar *strstric(uschar *, uschar *, BOOL);
+#ifdef EXIM_TFO_PROBE
+extern void tfo_probe(void);
+#endif
extern void timesince(struct timeval * diff, struct timeval * then);
extern void tls_modify_variables(tls_support *);
extern uschar *tod_stamp(int);
diff --git a/src/src/ip.c b/src/src/ip.c
index e11aef985..ee91293fa 100644
--- a/src/src/ip.c
+++ b/src/src/ip.c
@@ -161,6 +161,27 @@ return bind(sock, (struct sockaddr *)&sin, s_len);
/*************************************************
+*************************************************/
+
+#ifdef EXIM_TFO_PROBE
+void
+tfo_probe(void)
+{
+# ifdef TCP_FASTOPEN
+int sock, backlog = 5;
+
+if ( (sock = socket(SOCK_STREAM, AF_INET, 0)) < 0
+ && setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN,
+ &connect_backlog, sizeof(smtp_connect_backlog))
+ )
+ tcp_fastopen_ok = TRUE;
+close(sock);
+# endif
+}
+#endif
+
+
+/*************************************************
* Connect socket to remote host *
*************************************************/
@@ -175,7 +196,7 @@ Arguments:
address the remote address, in text form
port the remote port
timeout a timeout (zero for indefinite timeout)
- fastopen non-null iff TCP_FASTOPEN can be used; may indicate early-data to
+ fastopen_blob non-null iff TCP_FASTOPEN can be used; may indicate early-data to
be sent in SYN segment
Returns: 0 on success; -1 on failure, with errno set
@@ -183,7 +204,7 @@ Returns: 0 on success; -1 on failure, with errno set
int
ip_connect(int sock, int af, const uschar *address, int port, int timeout,
- const blob * fastopen)
+ const blob * fastopen_blob)
{
struct sockaddr_in s_in4;
struct sockaddr *s_ptr;
@@ -232,16 +253,17 @@ before it gets our ACK of its SYN,ACK - the latter is useful for
the SMTP banner. Other (than SMTP) cases of TCP connections can
possibly use the data-on-syn, so support that too. */
-if (fastopen)
+if (fastopen_blob && tcp_fastopen_ok)
{
- if ((rc = sendto(sock, fastopen->data, fastopen->len,
+ if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len,
MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
/* seen for with-data, experimental TFO option, with-cookie case */
/* seen for with-data, proper TFO opt, with-cookie case */
{
- DEBUG(D_transport|D_v) debug_printf("TFO mode connection attempt, %s data\n",
- fastopen->len > 0 ? "with" : "no");
- tcp_out_fastopen = fastopen->len > 0 ? 2 : 1;
+ DEBUG(D_transport|D_v)
+ debug_printf("non-TFO mode connection attempt to %s, %d data\n",
+ address, fastopen_blob->len);
+ tcp_out_fastopen = fastopen_blob->len > 0 ? 2 : 1;
}
else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */
/* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */
@@ -251,14 +273,14 @@ if (fastopen)
/* ? older Experimental TFO option behaviour ? */
{ /* queue unsent data */
DEBUG(D_transport|D_v) debug_printf("TFO mode sendto, %s data: EINPROGRESS\n",
- fastopen->len > 0 ? "with" : "no");
- if (!fastopen->data)
+ fastopen_blob->len > 0 ? "with" : "no");
+ if (!fastopen_blob->data)
{
tcp_out_fastopen = 1; /* we tried; unknown if useful yet */
rc = 0;
}
else
- rc = send(sock, fastopen->data, fastopen->len, 0);
+ rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
}
else if(errno == EOPNOTSUPP)
{
@@ -271,9 +293,12 @@ else
#endif
{
legacy_connect:
+ DEBUG(D_transport|D_v) if (fastopen_blob)
+ debug_printf("non-TFO mode connection attempt to %s, %d data\n",
+ address, fastopen_blob->len);
if ((rc = connect(sock, s_ptr, s_len)) >= 0)
- if ( fastopen && fastopen->data && fastopen->len
- && send(sock, fastopen->data, fastopen->len, 0) < 0)
+ if ( fastopen_blob && fastopen_blob->data && fastopen_blob->len
+ && send(sock, fastopen_blob->data, fastopen_blob->len, 0) < 0)
rc = -1;
}
@@ -320,7 +345,7 @@ Arguments:
timeout a timeout
connhost if not NULL, host_item to be filled in with connection details
errstr pointer for allocated string on error
- fastopen with SOCK_STREAM, if non-null, request TCP Fast Open.
+ fastopen_blob with SOCK_STREAM, if non-null, request TCP Fast Open.
Additionally, optional early-data to send
Return:
@@ -328,7 +353,7 @@ Return:
*/
int
ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
- int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen)
+ int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen_blob)
{
int namelen, port;
host_item shost;
@@ -389,7 +414,7 @@ for (h = &shost; h; h = h->next)
}
for(port = portlo; port <= porthi; port++)
- if (ip_connect(fd, af, h->address, port, timeout, fastopen) == 0)
+ if (ip_connect(fd, af, h->address, port, timeout, fastopen_blob) == 0)
{
if (fd != fd6) close(fd6);
if (fd != fd4) close(fd4);
diff --git a/src/src/malware.c b/src/src/malware.c
index 32f2e9e49..e39cea814 100644
--- a/src/src/malware.c
+++ b/src/src/malware.c
@@ -147,10 +147,10 @@ uses the returned in_addr to get a second connection to the same system.
*/
static inline int
m_tcpsocket(const uschar * hostname, unsigned int port,
- host_item * host, uschar ** errstr, const blob * fastopen)
+ host_item * host, uschar ** errstr, const blob * fastopen_blob)
{
return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
- host, errstr, fastopen);
+ host, errstr, fastopen_blob);
}
static int
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index 786f8b592..a507ed0e8 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -212,7 +212,7 @@ int dscp_level;
int dscp_option;
int sock;
int save_errno = 0;
-const blob * fastopen = NULL;
+const blob * fastopen_blob = NULL;
#ifndef DISABLE_EVENT
@@ -265,12 +265,12 @@ else
{
#ifdef TCP_FASTOPEN
if (verify_check_given_host(&ob->hosts_try_fastopen, host) == OK)
- fastopen = early_data ? early_data : &tcp_fastopen_nodata;
+ fastopen_blob = early_data ? early_data : &tcp_fastopen_nodata;
#endif
- if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
+ if (ip_connect(sock, host_af, host->address, port, timeout, fastopen_blob) < 0)
save_errno = errno;
- else if (early_data && !fastopen && early_data->data && early_data->len)
+ else if (early_data && !fastopen_blob && early_data->data && early_data->len)
if (send(sock, early_data->data, early_data->len, 0) < 0)
save_errno = errno;
}
@@ -309,7 +309,7 @@ else
}
if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
#ifdef TCP_FASTOPEN
- if (fastopen) tfo_out_check(sock);
+ if (fastopen_blob) tfo_out_check(sock);
#endif
return sock;
}