;;
esac
+AC_ARG_ENABLE(tfo-client, AC_HELP_STRING([--enable-tfo-client], [Enable TCP Fast Open for client mode]))
+case "$enable_tfo_client" in
+ yes)
+ case `uname` in
+ Linux) AC_CHECK_DECL([MSG_FASTOPEN], [AC_MSG_WARN([Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO])],
+ [AC_MSG_ERROR([TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client])],
+ [AC_INCLUDES_DEFAULT
+#include <netinet/tcp.h>
+])
+ AC_DEFINE_UNQUOTED([USE_MSG_FASTOPEN], [1], [Define this to enable client TCP Fast Open.])
+ ;;
+ Darwin) AC_CHECK_DECL([CONNECT_RESUME_ON_READ_WRITE], [AC_MSG_WARN([Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO])],
+ [AC_MSG_ERROR([TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client])],
+ [AC_INCLUDES_DEFAULT
+#include <sys/socket.h>
+])
+ AC_DEFINE_UNQUOTED([USE_OSX_MSG_FASTOPEN], [1], [Define this to enable client TCP Fast Open.])
+ ;;
+ esac
+ ;;
+ no|*)
+ ;;
+esac
+
+AC_ARG_ENABLE(tfo-server, AC_HELP_STRING([--enable-tfo-server], [Enable TCP Fast Open for server mode]))
+case "$enable_tfo_server" in
+ yes)
+ AC_CHECK_DECL([TCP_FASTOPEN], [AC_MSG_WARN([Check the platform specific TFO kernel parameters are correctly configured to support server mode TFO])], [AC_MSG_ERROR([TCP Fast Open is not available for server mode: please rerun without --enable-tfo-server])], [AC_INCLUDES_DEFAULT
+#include <netinet/tcp.h>
+ ])
+ AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable server TCP Fast Open.])
+ ;;
+ no|*)
+ ;;
+esac
+
# check for libevent
AC_ARG_WITH(libevent, AC_HELP_STRING([--with-libevent=pathname],
[use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr or you can specify an explicit path). Slower, but allows use of large outgoing port ranges.]),
+14 July 2016: Wouter
+ - TCP Fast open patch from Sara Dickinson.
+
7 July 2016: Wouter
- access-control-tag-data implemented. verbose(4) prints tag debug.
# include <sys/types.h>
#endif
#include <sys/time.h>
+#ifdef USE_TCP_FASTOPEN
+#include <netinet/tcp.h>
+#endif
#include "services/listen_dnsport.h"
#include "services/outside_network.h"
#include "util/netevent.h"
#endif
return -1;
}
+#ifdef USE_TCP_FASTOPEN
+ /* qlen specifies how many outstanding TFO requests to allow. Limit is a defense
+ against IP spoofing attacks as suggested in RFC7413 */
+#ifdef __APPLE__
+ /* OS X implementation only supports qlen of 1 via this call. Actual
+ value is configured by the net.inet.tcp.fastopen_backlog kernel parm. */
+ int qlen = 1;
+#else
+ /* 5 is recommended on linux */
+ int qlen = 5;
+#endif
+ if ((setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &qlen,
+ sizeof(qlen))) == -1 ) {
+ log_err("Setting TCP Fast Open as server failed: %s", strerror(errno));
+ }
+#endif
return s;
}
return 0;
fd_set_nonblock(s);
+#ifdef USE_OSX_MSG_FASTOPEN
+ /* API for fast open is different here. We use a connectx() function and
+ then writes can happen as normal even using SSL.*/
+ /* connectx requires that the len be set in the sockaddr struct*/
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)&w->addr;
+ addr_in->sin_len = w->addrlen;
+ sa_endpoints_t endpoints;
+ endpoints.sae_srcif = 0;
+ endpoints.sae_srcaddr = NULL;
+ endpoints.sae_srcaddrlen = 0;
+ endpoints.sae_dstaddr = (struct sockaddr *)&w->addr;
+ endpoints.sae_dstaddrlen = w->addrlen;
+ if (connectx(s, &endpoints, SAE_ASSOCID_ANY,
+ CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE,
+ NULL, 0, NULL, NULL) == -1) {
+#else /* USE_OSX_MSG_FASTOPEN*/
+#ifdef USE_MSG_FASTOPEN
+ /* Only do TFO for TCP in which case no connect() is required here.
+ Don't combine client TFO with SSL, since OpenSSL can't
+ currently support doing a handshake on fd that already isn't connected*/
+ if (w->outnet->sslctx && w->ssl_upstream) {
+ if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
+#else /* USE_MSG_FASTOPEN*/
if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
+#endif /* USE_MSG_FASTOPEN*/
+#endif /* USE_OSX_MSG_FASTOPEN*/
#ifndef USE_WINSOCK
#ifdef EINPROGRESS
if(errno != EINPROGRESS) {
return 0;
}
}
+#ifdef USE_MSG_FASTOPEN
+ }
+#endif /* USE_MSG_FASTOPEN */
if(w->outnet->sslctx && w->ssl_upstream) {
pend->c->ssl = outgoing_ssl_fd(w->outnet->sslctx, s);
if(!pend->c->ssl) {
if(c->ssl)
return ssl_handle_it(c);
+#ifdef USE_MSG_FASTOPEN
+ /* Only try this on first use of a connection that uses tfo,
+ otherwise fall through to normal write */
+ /* Also, TFO not available on WINDOWS at the moment */
+ if(c->tcp_do_fastopen == 1) {
+ c->tcp_do_fastopen = 0;
+ /* We need to have all the bytes to send in one buffer to try a single
+ sendto() for the message to go in the syn packet, so we must
+ create that buffer here, even though it means a malloc.
+ NOTE: When there is a general solution for composing a TCP message
+ (inc length) in one buffer this code should use that mechanism.*/
+ struct sldns_buffer* sendto_buf = NULL;
+ uint16_t len = sldns_buffer_limit(c->buffer);
+ sendto_buf = sldns_buffer_new(len + sizeof(uint16_t));
+ if (!sendto_buf)
+ return 0;
+ sldns_buffer_write_u16_at(sendto_buf, 0, len);
+ sldns_buffer_write_at(sendto_buf, sizeof(uint16_t),
+ sldns_buffer_begin(c->buffer),
+ sldns_buffer_limit(c->buffer));
+ r = sendto(fd, sldns_buffer_begin(sendto_buf),
+ sldns_buffer_limit(sendto_buf),
+ MSG_FASTOPEN, (struct sockaddr*)&(c->repinfo.addr),
+ c->repinfo.addrlen);
+ sldns_buffer_free(sendto_buf);
+ /* this form of sendto() does both a connect() and send() so need to
+ look for various flavours of error*/
+ if (r == -1) {
+#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
+ /* Handshake is underway, maybe because no TFO cookie available.
+ Come back to write the messsage*/
+ if(errno == EINPROGRESS || errno == EWOULDBLOCK)
+ return 1;
+#endif
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+ /* Not handling EISCONN here as shouldn't ever hit that case.*/
+ if(errno != 0 && verbosity < 2)
+ return 0; /* silence lots of chatter in the logs */
+ else if(errno != 0)
+ log_err_addr("tcp sendto", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+ return 0;
+ } else {
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count < sizeof(uint16_t))
+ return 1;
+ sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
+ sizeof(uint16_t));
+ if(sldns_buffer_remaining(c->buffer) == 0) {
+ tcp_callback_writer(c);
+ return 1;
+ }
+ }
+ }
+#endif /* USE_MSG_FASTOPEN */
+
if(c->tcp_byte_count < sizeof(uint16_t)) {
uint16_t len = htons(sldns_buffer_limit(c->buffer));
#ifdef HAVE_WRITEV
c->do_not_close = 0;
c->tcp_do_toggle_rw = 0;
c->tcp_check_nb_connect = 0;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 0;
+#endif
c->inuse = 0;
c->callback = callback;
c->cb_arg = callback_arg;
c->inuse = 0;
c->tcp_do_toggle_rw = 0;
c->tcp_check_nb_connect = 0;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 0;
+#endif
c->callback = callback;
c->cb_arg = callback_arg;
evbits = UB_EV_READ | UB_EV_PERSIST;
c->do_not_close = 0;
c->tcp_do_toggle_rw = 1;
c->tcp_check_nb_connect = 0;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 0;
+#endif
c->repinfo.c = c;
c->callback = callback;
c->cb_arg = callback_arg;
c->do_not_close = 0;
c->tcp_do_toggle_rw = 0;
c->tcp_check_nb_connect = 0;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 0;
+#endif
c->callback = NULL;
c->cb_arg = NULL;
evbits = UB_EV_READ | UB_EV_PERSIST;
c->do_not_close = 0;
c->tcp_do_toggle_rw = 1;
c->tcp_check_nb_connect = 1;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 1;
+#endif
c->repinfo.c = c;
c->callback = callback;
c->cb_arg = callback_arg;
c->do_not_close = 1;
c->tcp_do_toggle_rw = 0;
c->tcp_check_nb_connect = 0;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 0;
+#endif
c->callback = callback;
c->cb_arg = callback_arg;
/* ub_event stuff */
c->do_not_close = 1;
c->tcp_do_toggle_rw = 0;
c->tcp_check_nb_connect = 0;
+#ifdef USE_MSG_FASTOPEN
+ c->tcp_do_fastopen = 0;
+#endif
c->callback = callback;
c->cb_arg = callback_arg;
/* ub_event stuff */
/** if set, checks for pending error from nonblocking connect() call.*/
int tcp_check_nb_connect;
+#ifdef USE_MSG_FASTOPEN
+ /** used to track if the sendto() call should be done when using TFO. */
+ int tcp_do_fastopen;
+#endif
+
/** number of queries outstanding on this socket, used by
* outside network for udp ports */
int inuse;