summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2018-10-30 22:09:15 +0000
committerJeremy Harris <jgh146exb@wizmail.org>2018-10-30 22:36:55 +0000
commitb536a578fbabdc9d39da53d54a8d7700ba537431 (patch)
treeb3eef31b81c965a39b1c72b697b9244cb90a2466 /src
parent7df6163adc1837c48842471307ecb18aaded4530 (diff)
MacOS: TCP Fast Open
Diffstat (limited to 'src')
-rw-r--r--src/OS/os.h-Darwin8
-rw-r--r--src/src/daemon.c16
-rw-r--r--src/src/expand.c1
-rw-r--r--src/src/ip.c53
-rw-r--r--src/src/malware.c1
-rw-r--r--src/src/smtp_out.c3
-rw-r--r--src/src/transports/smtp_socks.c1
-rw-r--r--src/src/verify.c1
8 files changed, 67 insertions, 17 deletions
diff --git a/src/OS/os.h-Darwin b/src/OS/os.h-Darwin
index 67aeac913..4667689c9 100644
--- a/src/OS/os.h-Darwin
+++ b/src/OS/os.h-Darwin
@@ -51,10 +51,8 @@ in "man 2 getgroups". */
#define _DARWIN_UNLIMITED_GETGROUPS
#define EXIM_GROUPLIST_SIZE 64
-/* TCP_FASTOPEN support. For the moment, claim there is none
-(the probe fails; unsure why).
-Sometime in the future need to investigate connectex(). */
-
-#define EXIM_TFO_PROBE
+/* TCP Fast Open: Darwin uses a connectex() call
+rather than a modified sendto() */
+#define EXIM_TFO_CONNECTX
/* End */
diff --git a/src/src/daemon.c b/src/src/daemon.c
index ee9ddcc4f..1a15d46c0 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -1458,7 +1458,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
else
debug_printf("listening on %s port %d\n", ipa->address, ipa->port);
-#ifdef TCP_FASTOPEN
+#if defined(TCP_FASTOPEN) && !defined(__APPLE__)
if ( f.tcp_fastopen_ok
&& setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN,
&smtp_connect_backlog, sizeof(smtp_connect_backlog)))
@@ -1471,7 +1471,19 @@ if (f.daemon_listen && !f.inetd_wait_mode)
/* Start listening on the bound socket, establishing the maximum backlog of
connections that is allowed. On success, continue to the next address. */
- if (listen(listen_sockets[sk], smtp_connect_backlog) >= 0) continue;
+ if (listen(listen_sockets[sk], smtp_connect_backlog) >= 0)
+ {
+#if defined(TCP_FASTOPEN) && defined(__APPLE__)
+ if ( f.tcp_fastopen_ok
+ && setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN,
+ &on, sizeof(on)))
+ {
+ DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno));
+ f.tcp_fastopen_ok = FALSE;
+ }
+#endif
+ continue;
+ }
/* Listening has failed. In an IPv6 environment, as for bind(), if listen()
fails with the error EADDRINUSE and we are doing IPv4 wildcard listening
diff --git a/src/src/expand.c b/src/src/expand.c
index 5054e151b..49e09ecd8 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -5021,6 +5021,7 @@ while (*s != 0)
port = ntohs(service_info->s_port);
}
+ /*XXX we trust that the request is idempotent. Hmm. */
fd = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
timeout, &host, &expand_string_message,
do_tls ? NULL : &reqstr);
diff --git a/src/src/ip.c b/src/src/ip.c
index fa688be64..d601b46b3 100644
--- a/src/src/ip.c
+++ b/src/src/ip.c
@@ -196,7 +196,7 @@ Arguments:
port the remote port
timeout a timeout (zero for indefinite timeout)
fastopen_blob non-null iff TCP_FASTOPEN can be used; may indicate early-data to
- be sent in SYN segment
+ be sent in SYN segment. Any such data must be idempotent.
Returns: 0 on success; -1 on failure, with errno set
*/
@@ -245,19 +245,19 @@ callout_address = string_sprintf("[%s]:%d", address, port);
sigalrm_seen = FALSE;
if (timeout > 0) ALARM(timeout);
-#if defined(TCP_FASTOPEN) && defined(MSG_FASTOPEN)
+#ifdef TCP_FASTOPEN
/* TCP Fast Open, if the system has a cookie from a previous call to
this peer, can send data in the SYN packet. The peer can send data
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.
-
-This is a Linux implementation. It might be useable on FreeBSD; I have
-not checked. I think MacOS has a "connectx" call for this purpose,
-rather than using "sendto" ? */
+possibly use the data-on-syn, so support that too. */
if (fastopen_blob && f.tcp_fastopen_ok)
{
+# ifdef MSG_FASTOPEN
+ /* This is a Linux implementation. It might be useable on FreeBSD; I have
+ not checked. */
+
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 */
@@ -292,9 +292,44 @@ if (fastopen_blob && f.tcp_fastopen_ok)
debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
goto legacy_connect;
}
+# endif
+# ifdef EXIM_TFO_CONNECTX
+ /* MacOS */
+ sa_endpoints_t ends = {
+ .sae_srcif = 0, .sae_srcaddr = NULL, .sae_srcaddrlen = 0,
+ .sae_dstaddr = s_ptr, .sae_dstaddrlen = s_len };
+ struct iovec iov = {
+ .iov_base = fastopen_blob->data, .iov_len = fastopen_blob->len };
+ size_t len;
+
+ if ((rc = connectx(sock, &ends, SAE_ASSOCID_ANY,
+ CONNECT_DATA_IDEMPOTENT, &iov, 1, &len, NULL)) == 0)
+ {
+ DEBUG(D_transport|D_v)
+ debug_printf("TFO mode connection attempt to %s, %lu data\n",
+ address, (unsigned long)fastopen_blob->len);
+ tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_USED : TFO_ATTEMPTED;
+
+ if (len != fastopen_blob->len)
+ DEBUG(D_transport|D_v)
+ debug_printf(" only queued %lu data!\n", (unsigned long)len);
+ }
+ else if (errno == EINPROGRESS)
+ {
+ DEBUG(D_transport|D_v) debug_printf("TFO mode sendto, %s data: EINPROGRESS\n",
+ fastopen_blob->len > 0 ? "with" : "no");
+ if (!fastopen_blob->data)
+ {
+ tcp_out_fastopen = TFO_ATTEMPTED; /* we tried; unknown if useful yet */
+ rc = 0;
+ }
+ else /* assume that no data was queued; block in send */
+ rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
+ }
+# endif
}
else
-#endif
+#endif /*TCP_FASTOPEN*/
{
legacy_connect:
DEBUG(D_transport|D_v) if (fastopen_blob)
@@ -350,7 +385,7 @@ Arguments:
connhost if not NULL, host_item to be filled in with connection details
errstr pointer for allocated string on error
fastopen_blob with SOCK_STREAM, if non-null, request TCP Fast Open.
- Additionally, optional early-data to send
+ Additionally, optional idempotent early-data to send
Return:
socket fd, or -1 on failure (having allocated an error string)
diff --git a/src/src/malware.c b/src/src/malware.c
index 069a54483..541ff3b3c 100644
--- a/src/src/malware.c
+++ b/src/src/malware.c
@@ -1573,6 +1573,7 @@ badseek: err = errno;
* on both connections (as one host could resolve to multiple ips) */
for (;;)
{
+ /*XXX we trust that the cmd_str is ideempotent */
if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
&connhost, &errstr, &cmd_str)) >= 0)
{
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index ef2c9fdeb..c5eafbc57 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -194,7 +194,8 @@ if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0)
/* Arguments as for smtp_connect(), plus
- early_data if non-NULL, data to be sent - preferably in the TCP SYN segment
+ early_data if non-NULL, idenmpotent data to be sent -
+ preferably in the TCP SYN segment
Returns: connected socket number, or -1 with errno set
*/
diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c
index c7415c357..7d3a46230 100644
--- a/src/src/transports/smtp_socks.c
+++ b/src/src/transports/smtp_socks.c
@@ -297,6 +297,7 @@ for(;;)
proxy.address = proxy.name = sob->proxy_host;
proxy_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
+ /*XXX we trust that the method-select command is idempotent */
if ((fd = smtp_sock_connect(&proxy, proxy_af, sob->port,
interface, tb, sob->timeout, &early_data)) >= 0)
{
diff --git a/src/src/verify.c b/src/src/verify.c
index 9aff78a9a..d14cb685e 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -2745,6 +2745,7 @@ qlen = snprintf(CS buffer, sizeof(buffer), "%d , %d\r\n",
early_data.data = buffer;
early_data.len = qlen;
+/*XXX we trust that the query is idempotent */
if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port,
rfc1413_query_timeout, &early_data) < 0)
{