summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2016-10-21 00:26:14 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2016-10-22 22:18:17 +0100
commitfb05276aaee4c27b6f20fb1f32290ee40a929064 (patch)
treef108448c1499972f896bf9acd891908799481d09 /src
parentcfda83c6d64b5af00ef5f7a20bcc0dd58e489ef4 (diff)
TCP Fast Open
Diffstat (limited to 'src')
-rw-r--r--src/src/daemon.c18
-rw-r--r--src/src/functions.h2
-rw-r--r--src/src/globals.c3
-rw-r--r--src/src/globals.h3
-rw-r--r--src/src/ip.c34
-rw-r--r--src/src/routers/iplookup.c14
-rw-r--r--src/src/smtp_in.c2
-rw-r--r--src/src/smtp_out.c17
-rw-r--r--src/src/transports/appendfile.c9
-rw-r--r--src/src/transports/smtp.c4
-rw-r--r--src/src/transports/smtp.h1
-rw-r--r--src/src/verify.c14
12 files changed, 77 insertions, 44 deletions
diff --git a/src/src/daemon.c b/src/src/daemon.c
index a22ac8d68..2efaeba95 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -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 "
diff --git a/src/src/functions.h b/src/src/functions.h
index dad00c971..05386d105 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -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);
diff --git a/src/src/globals.c b/src/src/globals.c
index b5ac6ceaf..dcdd6f880 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -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;
diff --git a/src/src/globals.h b/src/src/globals.h
index 6e89dde1b..3e91c427d 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -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 */
diff --git a/src/src/ip.c b/src/src/ip.c
index 04b86060f..b744f5d4c 100644
--- a/src/src/ip.c
+++ b/src/src/ip.c
@@ -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);
diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c
index 310e4d66d..e6a35a7f3 100644
--- a/src/src/routers/iplookup.c
+++ b/src/src/routers/iplookup.c
@@ -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;
}
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 9282352ac..bc6583da1 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -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;
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index 5ab15cb5f..0c655e260 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -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 */
diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c
index c9d150525..884452208 100644
--- a/src/src/transports/appendfile.c
+++ b/src/src/transports/appendfile.c
@@ -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);
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 278349b4a..6c6a10266 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -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 */
/*************************************************
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index d3666ae78..c8df38ab4 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -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
diff --git a/src/src/verify.c b/src/src/verify.c
index f8f1809cb..aa7988cef 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -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;
}