* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* A number of functions for driving outgoing SMTP calls. */
if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0)
{
- /* This is a somewhat dubious detection method; totally undocumented so likely
- to fail in future kernels. There seems to be no documented way. */
-
- if (tinfo.tcpi_unacked > 1)
+ switch (tcp_out_fastopen)
{
- DEBUG(D_transport|D_v) debug_printf("TCP_FASTOPEN mode connection\n");
- tcp_out_fastopen = TRUE;
+ /* This is a somewhat dubious detection method; totally undocumented so likely
+ to fail in future kernels. There seems to be no documented way. What we really
+ want to know is if the server sent smtp-banner data before our ACK of his SYN,ACK
+ hit him. What this (possibly?) detects is whether we sent a TFO cookie with our
+ SYN, as distinct from a TFO request. This gets a false-positive when the server
+ key is rotated; we send the old one (which this test sees) but the server returns
+ the new one and does not send its SMTP banner before we ACK his SYN,ACK.
+ To force that rotation case:
+ '# echo -n "00000000-00000000-00000000-0000000" >/proc/sys/net/ipv4/tcp_fastopen_key'
+ The kernel seems to be counting unack'd packets. */
+
+ case 1:
+ if (tinfo.tcpi_unacked > 1)
+ {
+ DEBUG(D_transport|D_v)
+ debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.tcpi_unacked);
+ tcp_out_fastopen = 2;
+ }
+ break;
+
+#ifdef notdef /* This seems to always fire, meaning that we cannot tell
+ whether the server accepted data we sent. For now assume
+ that it did. */
+
+ /* If there was data-on-SYN but we had to retrasnmit it, declare no TFO */
+
+ case 2:
+ if (!(tinfo.tcpi_options & TCPI_OPT_SYN_DATA))
+ {
+ DEBUG(D_transport|D_v) debug_printf("TFO: had to retransmit\n");
+ tcp_out_fastopen = 0;
+ }
+ break;
+#endif
}
+
}
# endif
}
int dscp_option;
int sock;
int save_errno = 0;
+const blob * fastopen_blob = NULL;
+
#ifndef DISABLE_EVENT
deliver_host_address = host->address;
else
{
- const blob * fastopen = NULL;
-
#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;
}
}
if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
#ifdef TCP_FASTOPEN
- tfo_out_check(sock);
+ if (fastopen_blob) tfo_out_check(sock);
#endif
return sock;
}