TCP Fast Open
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 20 Oct 2016 23:26:14 +0000 (00:26 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 22 Oct 2016 21:18:17 +0000 (22:18 +0100)
29 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
src/src/daemon.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/ip.c
src/src/routers/iplookup.c
src/src/smtp_in.c
src/src/smtp_out.c
src/src/transports/appendfile.c
src/src/transports/smtp.c
src/src/transports/smtp.h
src/src/verify.c
test/confs/2052 [new file with mode: 0644]
test/confs/2152 [new file with mode: 0644]
test/log/2052 [new file with mode: 0644]
test/log/2152 [new file with mode: 0644]
test/scripts/2000-GnuTLS/2052 [new file with mode: 0644]
test/scripts/2100-OpenSSL/2152 [new file with mode: 0644]
test/stderr/0388
test/stderr/0398
test/stderr/0432
test/stderr/5403
test/stderr/5410
test/stderr/5420
test/stderr/5840
test/stdout/0572

index 45d84571869afdeda6b21ff033d6d85639d5e9e4..478b5e1a4f2d7b06c73abcc826f7d40b88803847 100644 (file)
@@ -23986,11 +23986,30 @@ unauthenticated. See also &%hosts_require_auth%&, and chapter
 .cindex CHUNKING "enabling, in client"
 .cindex BDAT "SMTP command"
 .cindex "RFC 3030" "CHUNKING"
-This option provides a list of server to which, provided they announce
+This option provides a list of servers to which, provided they announce
 CHUNKING support, Exim will attempt to use BDAT commands rather than DATA.
 BDAT will not be used in conjuction with a transport filter.
 .wen
 
+.new
+.option hosts_try_fastopen smtp "host list!!" unset
+.option "fast open, TCP" "enabling, in client"
+.option "TCP Fast Open" "enabling, in client"
+.option "RFC 7413" "TCP Fast Open"
+This option provides a list of servers to which, provided
+the facility is supported by this system, Exim will attempt to
+perform a TCP Fast Open.
+No data is sent on the SYN segment but, if the remote server also
+supports the facility, it can send its SMTP banner immediately after
+the SYN,ACK segment.  This can save up to one round-trip time.
+
+The facility is only active for previously-contacted servers,
+as the initiator must present a cookie in the SYN segment.
+
+On (at least some) current Linux distributions the facility must be enabled
+in the kernel by the sysadmin before the support is usable.
+.wen
+
 .option hosts_try_prdr smtp "host list&!!" *
 .cindex "PRDR" "enabling, optional in client"
 This option provides a list of servers to which, provided they announce
index cca958f79a3b205ce7cd8349ed13d2fb15bcc1b5..83ee4c3afe86b075721d3e5ecf0c556d1f90900e 100644 (file)
@@ -54,6 +54,15 @@ Version 4.88
 14. If built with EXPERIMENTAL_QUEUEFILE, a queuefile transport, for writing
     out copies of the message spool files for use by 3rd-party scanners.
 
+15. A new option on the smtp transport, hosts_try_fastopen.  If the system
+    supports it (on Linux it must be enabled in the kernel by the sysadmin)
+    try to use RFC 7413 "TCP Fast Open".  No data is sent on the SYN segment
+    but it permits a peer that also supports the facility to send its SMTP
+    banner immediately after the SYN,ACK segment rather then waiting for
+    another ACK - so saving up to one roundtrip time.  Because it requires
+    previous communication with the peer (we save a cookie from it) this
+    will only become active on frequently-contected destinations.
+
 
 Version 4.87
 ------------
index 53c07436ad88c0cc259879a98e30f526846b1993..dc16b6dee0f99b5b62e754c07bda1c156440177e 100644 (file)
@@ -300,6 +300,7 @@ hosts_require_ocsp                   host list       unset         smtp
 hosts_require_tls                    host list       unset         smtp              3.20
 hosts_treat_as_local                 domain list     unset         main              1.95
 hosts_try_auth                       host list       unset         smtp              4.00
+hosts_try_fastopen                   host list       unset         smtp              4.88
 hosts_try_prdr                       host list       unset         smtp              4.82 if experimental_prdr
 ibase_servers                        string          unset         main              4.23
 ignore_bounce_errors_after           time            0s            main              4.00
index a22ac8d68cfe970d3c3c53e1356d8bcec5d024de..2efaeba95aab273ef6f5f49e17cbdddb4ed8bc59 100644 (file)
@@ -932,8 +932,6 @@ DEBUG(D_any|D_v) debug_selector |= D_pid;
 
 if (inetd_wait_mode)
   {
-  int on = 1;
-
   listen_socket_count = 1;
   listen_sockets = store_get(sizeof(int));
   (void) close(3);
@@ -1364,7 +1362,6 @@ the listening sockets if required. */
 if (daemon_listen && !inetd_wait_mode)
   {
   int sk;
-  int on = 1;
   ip_address_item *ipa;
 
   /* For each IP address, create a socket, bind it to the appropriate port, and
@@ -1466,13 +1463,18 @@ if (daemon_listen && !inetd_wait_mode)
       }
 
     DEBUG(D_any)
-      {
       if (wildcard)
         debug_printf("listening on all interfaces (IPv%c) port %d\n",
-          (af == AF_INET6)? '6' : '4', ipa->port);
+          af == AF_INET6 ? '6' : '4', ipa->port);
       else
         debug_printf("listening on %s port %d\n", ipa->address, ipa->port);
-      }
+
+#ifdef TCP_FASTOPEN
+    if (setsockopt(listen_sockets[sk], SOL_TCP, TCP_FASTOPEN, &smtp_connect_backlog,
+                   sizeof(smtp_connect_backlog)))
+      log_write(0, LOG_MAIN|LOG_PANIC, "failed to set socket FASTOPEN: %s",
+       strerror(errno));
+#endif
 
     /* Start listening on the bound socket, establishing the maximum backlog of
     connections that is allowed. On success, continue to the next address. */
@@ -1487,8 +1489,8 @@ if (daemon_listen && !inetd_wait_mode)
 
     if (!check_special_case(errno, addresses, ipa, TRUE))
       log_write(0, LOG_PANIC_DIE, "listen() failed on interface %s: %s",
-        wildcard? ((af == AF_INET6)? US"(any IPv6)" : US"(any IPv4)") :
-        ipa->address,
+        wildcard
+       ? af == AF_INET6 ? US"(any IPv6)" : US"(any IPv4)" : ipa->address,
         strerror(errno));
 
     DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 "
index dad00c971f0d4e9fa1834fcce0802c05f2798569..05386d105e54280f4a53562957929978e69fa8e4 100644 (file)
@@ -226,7 +226,7 @@ extern uschar *imap_utf7_encode(uschar *, const uschar *,
 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_connect(int, int, const uschar *, int, int, BOOL);
 extern int     ip_connectedsocket(int, const uschar *, int, int,
                  int, host_item *, uschar **);
 extern int     ip_get_address_family(int);
index b5ac6ceaf0f525083a97e6ff31801cf29fa48a01..dcdd6f88070f4acf3f2ba7314e1bd898e4cb9e4f 100644 (file)
@@ -990,6 +990,9 @@ BOOL    no_mbox_unspool        = FALSE;
 #endif
 BOOL    no_multiline_responses = FALSE;
 
+const int on                   = 1;    /* for setsockopt */
+const int off                  = 0;
+
 uid_t   original_euid;
 gid_t   originator_gid;
 uschar *originator_login       = NULL;
index 6e89dde1b4face6d7d2c71aa9a1303c3113fd965..3e91c427df33d9b552539e8eadbf0a9c1b10bd52 100644 (file)
@@ -611,6 +611,9 @@ extern BOOL    no_mbox_unspool;        /* don't unlink files in /scan directory
 #endif
 extern BOOL    no_multiline_responses; /* For broken clients */
 
+extern const int on;                   /* For setsockopt */
+extern const int off;
+
 extern optionlist optionlist_auths[];      /* These option lists are made */
 extern int     optionlist_auths_size;      /* global so that readconf can */
 extern optionlist optionlist_routers[];    /* see them for printing out   */
index 04b86060fa42cd23e31ed36b0641fb71e509cad3..b744f5d4c101b88e4c7fe1500d8fc3019d089c8d 100644 (file)
@@ -175,12 +175,14 @@ Arguments:
   address     the remote address, in text form
   port        the remote port
   timeout     a timeout (zero for indefinite timeout)
+  fastopen    TRUE iff TCP_FASTOPEN can be used
 
 Returns:      0 on success; -1 on failure, with errno set
 */
 
 int
-ip_connect(int sock, int af, const uschar *address, int port, int timeout)
+ip_connect(int sock, int af, const uschar *address, int port, int timeout,
+  BOOL fastopen)
 {
 struct sockaddr_in s_in4;
 struct sockaddr *s_ptr;
@@ -221,7 +223,31 @@ timer, thereby allowing the inbuilt OS timeout to operate. */
 callout_address = string_sprintf("[%s]:%d", address, port);
 sigalrm_seen = FALSE;
 if (timeout > 0) alarm(timeout);
-rc = connect(sock, s_ptr, s_len);
+
+#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.  Is there any usage where the former might be?
+We might extend the ip_connect() args for data if so.  For now,
+connect in FASTOPEN mode but with zero data.
+*/
+
+if (fastopen)
+  {
+  if (  (rc = sendto(sock, NULL, 0, MSG_FASTOPEN, s_ptr, s_len)) < 0
+     && errno == EOPNOTSUPP
+     )
+    {
+    log_write(0, LOG_MAIN|LOG_PANIC,
+             "Tried TCP Fast Open but apparently not enabled by sysctl");
+    rc = connect(sock, s_ptr, s_len);
+    }
+  }
+else
+#endif
+  rc = connect(sock, s_ptr, s_len);
+
 save_errno = errno;
 alarm(0);
 
@@ -319,7 +345,7 @@ else
 
 /* Try to connect to the server - test each IP till one works */
 
-for (h = &shost; h != NULL; h = h->next)
+for (h = &shost; h; h = h->next)
   {
   fd = Ustrchr(h->address, ':') != 0
     ? fd6 < 0 ? (fd6 = ip_socket(type, af = AF_INET6)) : fd6
@@ -332,7 +358,7 @@ for (h = &shost; h != NULL; h = h->next)
     }
 
   for(port = portlo; port <= porthi; port++)
-    if (ip_connect(fd, af, h->address, port, timeout) == 0)
+    if (ip_connect(fd, af, h->address, port, timeout, type == SOCK_STREAM) == 0)
       {
       if (fd != fd6) close(fd6);
       if (fd != fd4) close(fd4);
index 310e4d66d48f8585462c40bbb17668e0667478bd..e6a35a7f3b4174fd4e71f5fd1d7f5821b993887e 100644 (file)
@@ -191,7 +191,7 @@ being a host list. */
 
 listptr = ob->hosts;
 while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
-       sizeof(host_buffer))) != NULL)
+       sizeof(host_buffer))))
   {
   host_item *h;
 
@@ -214,19 +214,20 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
 
   /* Loop for possible multiple IP addresses for the given name. */
 
-  for (h = host; h != NULL; h = h->next)
+  for (h = host; h; h = h->next)
     {
     int host_af, query_socket;
 
     /* Skip any hosts for which we have no address */
 
-    if (h->address == NULL) continue;
+    if (!h->address) continue;
 
     /* Create a socket, for UDP or TCP, as configured. IPv6 addresses are
     detected by checking for a colon in the address. */
 
     host_af = (Ustrchr(h->address, ':') != NULL)? AF_INET6 : AF_INET;
-    query_socket = ip_socket((ob->protocol == ip_udp)? SOCK_DGRAM:SOCK_STREAM,
+
+    query_socket = ip_socket(ob->protocol == ip_udp ? SOCK_DGRAM:SOCK_STREAM,
       host_af);
     if (query_socket < 0)
       {
@@ -240,7 +241,8 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
     here only for TCP calls; for a UDP socket, "connect" always works (the
     router will timeout later on the read call). */
 
-    if (ip_connect(query_socket, host_af, h->address,ob->port, ob->timeout) < 0)
+    if (ip_connect(query_socket, host_af, h->address,ob->port, ob->timeout,
+                       ob->protocol != ip_udp) < 0)
       {
       close(query_socket);
       DEBUG(D_route)
@@ -282,7 +284,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
   /* If h == NULL we have tried all the IP addresses and failed on all of them,
   so we must continue to try more host names. Otherwise we have succeeded. */
 
-  if (h != NULL) break;
+  if (h) break;
   }
 
 
index 9282352aca2793622929a78c1bca82149b1c9ddd..bc6583da12d79b0fd436fd9ecbf615acc4c02225 100644 (file)
@@ -143,8 +143,6 @@ static BOOL pipelining_advertised;
 static BOOL rcpt_smtp_response_same;
 static BOOL rcpt_in_progress;
 static int  nonmail_command_count;
-static int  off = 0;
-static int  on = 1;
 static BOOL smtp_exit_function_called = 0;
 #ifdef SUPPORT_I18N
 static BOOL smtputf8_advertised;
index 5ab15cb5f3de4200082526187ae15ef645843e9a..0c655e2606f3fceac5ea8127f4e9e4372523e146 100644 (file)
@@ -41,10 +41,9 @@ const uschar * expint;
 uschar *iface;
 int sep = 0;
 
-if (istring == NULL) return TRUE;
+if (!istring) return TRUE;
 
-expint = expand_string(istring);
-if (expint == NULL)
+if (!(expint = expand_string(istring)))
   {
   if (expand_string_forcedfail) return TRUE;
   addr->transport_return = PANIC;
@@ -57,7 +56,7 @@ while (isspace(*expint)) expint++;
 if (*expint == 0) return TRUE;
 
 while ((iface = string_nextinlist(&expint, &sep, big_buffer,
-          big_buffer_size)) != NULL)
+          big_buffer_size)))
   {
   if (string_is_ip_address(iface, NULL) == 0)
     {
@@ -72,7 +71,7 @@ while ((iface = string_nextinlist(&expint, &sep, big_buffer,
     break;
   }
 
-if (iface != NULL) *interface = string_copy(iface);
+if (iface) *interface = string_copy(iface);
 return TRUE;
 }
 
@@ -152,8 +151,8 @@ int dscp_value;
 int dscp_level;
 int dscp_option;
 int sock;
-int on = 1;
 int save_errno = 0;
+BOOL fastopen = FALSE;
 
 #ifndef DISABLE_EVENT
 deliver_host_address = host->address;
@@ -186,6 +185,10 @@ if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
     (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
   }
 
+#ifdef TCP_FASTOPEN
+if (verify_check_given_host (&ob->hosts_try_fastopen, host) == OK) fastopen = TRUE;
+#endif
+
 /* Bind to a specific interface if requested. Caller must ensure the interface
 is the same type (IPv4 or IPv6) as the outgoing address. */
 
@@ -200,7 +203,7 @@ if (interface && ip_bind(sock, host_af, interface, 0) < 0)
 /* Connect to the remote host, and add keepalive to the socket before returning
 it, if requested. */
 
-else if (ip_connect(sock, host_af, host->address, port, timeout) < 0)
+else if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
   save_errno = errno;
 
 /* Either bind() or connect() failed */
index c9d15052588fbf8b99047f8e3835297f161f4e9c..884452208554310abd4511a4940f6cc7cf07dcf1 100644 (file)
@@ -619,19 +619,18 @@ if (host_find_byname(&host, NULL, 0, NULL, FALSE) == HOST_FIND_FAILED)
 host.address = US"127.0.0.1";
 
 
-for (h = &host; h != NULL; h = h->next)
+for (h = &host; h; h = h->next)
   {
   int sock, rc;
-  int host_af = (Ustrchr(h->address, ':') != NULL)? AF_INET6 : AF_INET;
+  int host_af = Ustrchr(h->address, ':') != NULL ? AF_INET6 : AF_INET;
 
   DEBUG(D_transport) debug_printf("calling comsat on %s\n", h->address);
 
-  sock = ip_socket(SOCK_DGRAM, host_af);
-  if (sock < 0) continue;
+  if ((sock = ip_socket(SOCK_DGRAM, host_af)) < 0) continue;
 
   /* Connect never fails for a UDP socket, so don't set a timeout. */
 
-  (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0);
+  (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0, FALSE);
   rc = send(sock, buffer, Ustrlen(buffer) + 1, 0);
   (void)close(sock);
 
index 278349b4a419460f3a5c01af2c7ffb98b8f88ab0..6c6a102661f705ec37512e73f521b6af3acbcb35 100644 (file)
@@ -124,6 +124,8 @@ optionlist smtp_transport_options[] = {
   { "hosts_try_dane",       opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_try_dane) },
 #endif
+  { "hosts_try_fastopen",   opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, hosts_try_fastopen) },
 #ifndef DISABLE_PRDR
   { "hosts_try_prdr",       opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_try_prdr) },
@@ -209,6 +211,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* hosts_try_dane */
   NULL,                /* hosts_require_dane */
 #endif
+  NULL,                /* hosts_try_fastopen */
 #ifndef DISABLE_PRDR
   US"*",               /* hosts_try_prdr */
 #endif
@@ -286,7 +289,6 @@ static uschar *smtp_command;   /* Points to last cmd for error messages */
 static uschar *mail_command;   /* Points to MAIL cmd for error messages */
 static BOOL    update_waiting; /* TRUE to update the "wait" database */
 static BOOL    pipelining_active; /* current transaction is in pipe mode */
-static int     off = 0;       /* for use by setsockopt */
 
 
 /*************************************************
index d3666ae78850cc7df1d8db85dc6ae7a70be0b621..c8df38ab4bb31892c01bad6e65cf1ddd33106496 100644 (file)
@@ -26,6 +26,7 @@ typedef struct {
   uschar *hosts_try_dane;
   uschar *hosts_require_dane;
 #endif
+  uschar *hosts_try_fastopen;
 #ifndef DISABLE_PRDR
   uschar *hosts_try_prdr;
 #endif
index f8f1809cb601ce29092ecb2f8dc849003a5c6289..aa7988cef4be4a8234b7339914fe20b3183500df 100644 (file)
@@ -41,7 +41,6 @@ static tree_node *dnsbl_cache = NULL;
 
 static uschar cutthrough_response(char, uschar **);
 
-static int     off = 0;       /* for use by setsockopt */
 
 
 /*************************************************
@@ -2909,9 +2908,8 @@ DEBUG(D_ident) debug_printf("doing ident callback\n");
 to the incoming interface address. If the sender host address is an IPv6
 address, the incoming interface address will also be IPv6. */
 
-host_af = (Ustrchr(sender_host_address, ':') == NULL)? AF_INET : AF_INET6;
-sock = ip_socket(SOCK_STREAM, host_af);
-if (sock < 0) return;
+host_af = Ustrchr(sender_host_address, ':') == NULL ? AF_INET : AF_INET6;
+if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return;
 
 if (ip_bind(sock, host_af, interface_address, 0) < 0)
   {
@@ -2920,19 +2918,15 @@ if (ip_bind(sock, host_af, interface_address, 0) < 0)
   goto END_OFF;
   }
 
-if (ip_connect(sock, host_af, sender_host_address, port, rfc1413_query_timeout)
-     < 0)
+if (ip_connect(sock, host_af, sender_host_address, port,
+               rfc1413_query_timeout, TRUE) < 0)
   {
   if (errno == ETIMEDOUT && LOGGING(ident_timeout))
-    {
     log_write(0, LOG_MAIN, "ident connection to %s timed out",
       sender_host_address);
-    }
   else
-    {
     DEBUG(D_ident) debug_printf("ident connection to %s failed: %s\n",
       sender_host_address, strerror(errno));
-    }
   goto END_OFF;
   }
 
diff --git a/test/confs/2052 b/test/confs/2052
new file mode 100644 (file)
index 0000000..fd1f4d1
--- /dev/null
@@ -0,0 +1,67 @@
+# Exim test configuration 2052
+# as per 2000 but with TCP Fast Open
+
+SERVER=
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector =  +tls_peerdn
+
+queue_only
+queue_run_in_order
+
+tls_advertise_hosts = *
+# needed to force generation
+tls_dhparam = historic
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+tls_verify_hosts = *
+tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+  driver = accept
+  condition = ${if eq {SERVER}{server}{no}{yes}}
+  retry_use_local_part
+  transport = send_to_server
+
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server:
+  driver = smtp
+  allow_localhost
+  hosts = 127.0.0.1
+  port = PORT_D
+  hosts_try_fastopen = *
+  tls_certificate = DIR/aux-fixed/cert2
+  tls_privatekey = DIR/aux-fixed/cert2
+  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_try_verify_hosts =
+
+
+# ----- Retry -----
+
+
+begin retry
+
+* * F,5d,10s
+
+
+# End
diff --git a/test/confs/2152 b/test/confs/2152
new file mode 100644 (file)
index 0000000..a8b6c15
--- /dev/null
@@ -0,0 +1,68 @@
+# Exim test configuration 2152
+# as per 2100 but with TCP Fast Open
+
+SERVER=
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+.ifdef _HAVE_TLS
+# that was purely to trigger the lazy-create of builtin macros
+.endif
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector =  +tls_peerdn
+
+queue_only
+queue_run_in_order
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+tls_verify_hosts = *
+tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+  driver = accept
+  condition = ${if eq {SERVER}{server}{no}{yes}}
+  retry_use_local_part
+  transport = send_to_server
+
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server:
+  driver = smtp
+  allow_localhost
+  hosts = 127.0.0.1
+  port = PORT_D
+  hosts_try_fastopen = *
+  tls_certificate = DIR/aux-fixed/cert2
+  tls_privatekey = DIR/aux-fixed/cert2
+  tls_verify_certificates = DIR/aux-fixed/cert2
+  tls_try_verify_hosts = :
+
+
+# ----- Retry -----
+
+
+begin retry
+
+* * F,5d,10s
+
+
+# End
diff --git a/test/log/2052 b/test/log/2052
new file mode 100644 (file)
index 0000000..68c88a3
--- /dev/null
@@ -0,0 +1,13 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1] TLS error on connection (certificate verification failed): certificate invalid
+1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session failure: delivering unencrypted to 127.0.0.1 [127.0.0.1] (not in hosts_require_tls)
+1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (recv): A TLS fatal alert has been received.: Certificate is bad
+1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (send): The specified session has been invalidated for some reason.
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
diff --git a/test/log/2152 b/test/log/2152
new file mode 100644 (file)
index 0000000..1ed6351
--- /dev/null
@@ -0,0 +1,9 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=yes DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
diff --git a/test/scripts/2000-GnuTLS/2052 b/test/scripts/2000-GnuTLS/2052
new file mode 100644 (file)
index 0000000..fa76b48
--- /dev/null
@@ -0,0 +1,22 @@
+# TLS client: TLS setup fails - retry in clear (with fastopen)
+#
+# If all works you'll not see any difference.  To enable in the
+# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
+# A packet capture on the loopback interface will show the TFU
+# option on the SYN, but the fast-output SMTP banner will not
+# be seen unless you also deliberately emulate a long path:
+# 'sudo tc qdisc add dev lo root netem delay 100ms'
+#
+# If the client-side is disabled in the kernel, Exim logs
+# will become noisy.
+#
+gnutls
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim CALLER@test.ex
+Testing
+****
+exim -qf
+****
+killdaemon
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2152 b/test/scripts/2100-OpenSSL/2152
new file mode 100644 (file)
index 0000000..329e420
--- /dev/null
@@ -0,0 +1,21 @@
+# TLS client: TLS setup fails - retry in clear (with fastopen)
+#
+# If all works you'll not see any difference.  To enable in the
+# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
+# A packet capture on the loopback interface will show the TFU
+# option on the SYN, but the fast-output SMTP banner will not
+# be seen unless you also deliberately emulate a long path:
+# 'sudo tc qdisc add dev lo root netem delay 100ms'
+#
+# If the client-side is disabled in the kernel, Exim logs
+# will become noisy.
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim CALLER@test.ex
+Testing
+****
+exim -qf
+****
+killdaemon
+no_msglog_check
index 92b3f23e1e392e0d7b7c944f51310a1941f0f2fd..f8866380edc525b9d1849ccf1223dd4fd116f3ce 100644 (file)
@@ -81,7 +81,8 @@ returned from EXIM_DBOPEN
 no retry data available
 127.0.0.1 in serialize_hosts? no (option unset)
 set_process_info: pppp delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (x@y)
-Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
   SMTP<< 220 Server ready
 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
   SMTP>> EHLO myhost.test.ex
@@ -112,7 +113,8 @@ returned from EXIM_DBOPEN
 no retry data available
 V4NET.0.0.0 in serialize_hosts? no (option unset)
 set_process_info: pppp delivering 10HmaX-0005vi-00 to V4NET.0.0.0 [V4NET.0.0.0] (x@y)
-Connecting to V4NET.0.0.0 [V4NET.0.0.0]:1224 ... failed: Network Error
+Connecting to V4NET.0.0.0 [V4NET.0.0.0]:1224 ... V4NET.0.0.0 in hosts_try_fastopen? no (option unset)
+failed: Network Error
 LOG: MAIN
   H=V4NET.0.0.0 [V4NET.0.0.0] Network Error
 set_process_info: pppp delivering 10HmaX-0005vi-00: just tried V4NET.0.0.0 [V4NET.0.0.0] for x@y: result DEFER
index 3e3994b99aec07a13936a9a73a1b71a3c53a58b1..1dcb998f70407d286f15976e530540a090bd0958 100644 (file)
@@ -129,7 +129,8 @@ dbfn_read: key=qq@remote
 callout cache: no address record found for qq@remote
 closed hints database and lockfile
 interface=NULL port=1224
-Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
   SMTP<< 220 Server ready
 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
   SMTP>> EHLO mail.test.ex
index 2fe0ca86800a3fd1d8c3938fa273f22cb208e32e..76111d5d7fb225f2fe8380fc2fe39e67ca228c5e 100644 (file)
@@ -90,7 +90,8 @@ dbfn_read: key=x@y
 callout cache: no address record found for x@y
 closed hints database and lockfile
 interface=NULL port=1224
-Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
   SMTP<< 220 server ready
 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
   SMTP>> EHLO myhost.test.ex
@@ -255,7 +256,8 @@ MUNGED: ::1 will be omitted in what follows
 >>> callout cache: no domain record found for b
 >>> callout cache: no address record found for a@b
 >>> interface=NULL port=1224
->>> Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+>>> Connecting to 127.0.0.1 [127.0.0.1]:1224 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+>>> connected
 >>>   SMTP<< 220 server ready
 >>> 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
 >>>   SMTP>> EHLO myhost.test.ex
@@ -300,7 +302,8 @@ MUNGED: ::1 will be omitted in what follows
 >>> callout cache: no domain record found for q
 >>> callout cache: no address record found for p1@q
 >>> interface=NULL port=1224
->>> Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+>>> Connecting to 127.0.0.1 [127.0.0.1]:1224 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+>>> connected
 >>>   SMTP<< 220 server ready
 >>> 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
 >>>   SMTP>> EHLO myhost.test.ex
index dfb5a97e4ebfbce7776e1b6b3611a8e5c5ee39cf..0ae10f727adad28156f876e53734a0f380bc2e5c 100644 (file)
@@ -69,7 +69,8 @@ MUNGED: ::1 will be omitted in what follows
 >>> Attempting full verification using callout
 >>> callout cache: disabled by no_cache
 >>> interface=ip4.ip4.ip4.ip4 port=1224
->>> Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected
+>>> Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+>>> connected
 >>>   SMTP<< 220 server ready
 >>> 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
 >>>   SMTP>> EHLO myhost.test.ex
index 7916518b706642a9045d3890c20c7d69617c89b2..e7323f58139de2fa000d49981a34e40a09251244 100644 (file)
@@ -49,7 +49,8 @@ considering: $local_part
   expanding: $local_part
      result: userx
 domain.com in "*"? yes (matched "*")
-Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
 considering: $primary_hostname
   expanding: $primary_hostname
      result: myhost.test.ex
@@ -313,7 +314,8 @@ considering: $local_part
   expanding: $local_part
      result: usery
 domain.com in "*"? yes (matched "*")
-Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
 considering: $primary_hostname
   expanding: $primary_hostname
      result: myhost.test.ex
@@ -544,7 +546,8 @@ considering: $local_part
   expanding: $local_part
      result: usery
 domain.com in "*"? yes (matched "*")
-Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
 considering: $primary_hostname
   expanding: $primary_hostname
      result: myhost.test.ex
index a124515756bd94adf49eb2d67273adf30b554311..684629e68501f81fc985117d9724dc16cd48911f 100644 (file)
@@ -49,7 +49,8 @@ considering: $local_part
   expanding: $local_part
      result: userx
 domain.com in "*"? yes (matched "*")
-Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
 considering: $primary_hostname
   expanding: $primary_hostname
      result: myhost.test.ex
@@ -312,7 +313,8 @@ considering: $local_part
   expanding: $local_part
      result: usery
 domain.com in "*"? yes (matched "*")
-Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
 considering: $primary_hostname
   expanding: $primary_hostname
      result: myhost.test.ex
@@ -543,7 +545,8 @@ considering: $local_part
   expanding: $local_part
      result: usery
 domain.com in "*"? yes (matched "*")
-Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... connected
+Connecting to 127.0.0.1 [127.0.0.1]:1225 from ip4.ip4.ip4.ip4 ... 127.0.0.1 in hosts_try_fastopen? no (option unset)
+connected
 considering: $primary_hostname
   expanding: $primary_hostname
      result: myhost.test.ex
index b4b035a295c4bbdd8f222df3faa0c69c443aecc8..29ca2804a3fa8cdfac23ee8ca04ab77012cf2ad9 100644 (file)
@@ -18,7 +18,8 @@
 >>> callout cache: no domain record found for dane256ee.test.ex
 >>> callout cache: no address record found for CALLER@dane256ee.test.ex
 >>> interface=NULL port=1225
->>> Connecting to dane256ee.test.ex [ip4.ip4.ip4.ip4]:1225 ... connected
+>>> Connecting to dane256ee.test.ex [ip4.ip4.ip4.ip4]:1225 ... ip4.ip4.ip4.ip4 in hosts_try_fastopen? no (option unset)
+>>> connected
 MUNGED: ::1 will be omitted in what follows
 >>> get[host|ipnode]byname[2] looked up these IP addresses:
 >>>   name=thishost.test.ex address=127.0.0.1
index 12cd05b78b734b92e11a1c1940ea65cb3d3b188e..d50a643b42e1ac9ab15ecab4d972a62e243f4ee3 100644 (file)
@@ -58,6 +58,7 @@ no_hosts_randomize
 hosts_require_auth = 
 hosts_try_auth = 
 hosts_try_chunking = *
+hosts_try_fastopen = 
 hosts_try_prdr = *
 interface = ip4.ip4.ip4.ip4
 keepalive