Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use TCP_NODELAY on TLS sockets to speed up the TLS handshake. #1214

Merged
merged 1 commit into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletions services/listen_dnsport.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,10 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
{
int s = -1;
char* err;
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined(SO_BINDANY)
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) \
|| defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) \
|| defined(IP_BINDANY) || defined(IP_FREEBIND) \
|| defined(SO_BINDANY) || defined(TCP_NODELAY)
int on = 1;
#endif
#ifdef HAVE_SYSTEMD
Expand Down Expand Up @@ -1237,26 +1240,6 @@ set_recvpktinfo(int s, int family)
return 1;
}

/** see if interface is ssl, its port number == the ssl port number */
static int
if_is_ssl(const char* ifname, const char* port, int ssl_port,
struct config_strlist* tls_additional_port)
{
struct config_strlist* s;
char* p = strchr(ifname, '@');
if(!p && atoi(port) == ssl_port)
return 1;
if(p && atoi(p+1) == ssl_port)
return 1;
for(s = tls_additional_port; s; s = s->next) {
if(p && atoi(p+1) == atoi(s->str))
return 1;
if(!p && atoi(port) == atoi(s->str))
return 1;
}
return 0;
}

/**
* Helper for ports_open. Creates one interface (or NULL for default).
* @param ifname: The interface ip address.
Expand Down Expand Up @@ -1300,10 +1283,16 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
int quic_port, int http_notls_downstream, int sock_queue_timeout)
{
int s, noip6=0;
int is_ssl = if_is_ssl(ifname, port, ssl_port, tls_additional_port);
int is_https = if_is_https(ifname, port, https_port);
int is_dnscrypt = if_is_dnscrypt(ifname, port, dnscrypt_port);
int is_pp2 = if_is_pp2(ifname, port, proxy_protocol_port);
int nodelay = is_https && http2_nodelay;
/* Always set TCP_NODELAY on TLS connection as it speeds up the TLS
* handshake. DoH had already such option so we respect it.
* Otherwise the server waits before sending more handshake data for
* the client ACK (Nagle's algorithm), which is delayed because the
* client waits for more data before ACKing (delayed ACK). */
int nodelay = is_https?http2_nodelay:is_ssl;
struct unbound_socket* ub_sock;
int is_doq = if_is_quic(ifname, port, quic_port);
const char* add = NULL;
Expand Down
27 changes: 22 additions & 5 deletions services/outside_network.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,14 @@ pick_outgoing_tcp(struct pending_tcp* pend, struct waiting_tcp* w, int s)
/** get TCP file descriptor for address, returns -1 on failure,
* tcp_mss is 0 or maxseg size to set for TCP packets. */
int
outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp)
outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen,
int tcp_mss, int dscp, int nodelay)
{
int s;
int af;
char* err;
#if defined(SO_REUSEADDR) || defined(IP_BIND_ADDRESS_NO_PORT)
#if defined(SO_REUSEADDR) || defined(IP_BIND_ADDRESS_NO_PORT) \
|| defined(TCP_NODELAY)
int on = 1;
#endif
#ifdef INET6
Expand Down Expand Up @@ -320,6 +322,18 @@ outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss,
" setsockopt(.. IP_BIND_ADDRESS_NO_PORT ..) failed");
}
#endif /* IP_BIND_ADDRESS_NO_PORT */
if(nodelay) {
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
if(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void*)&on,
(socklen_t)sizeof(on)) < 0) {
verbose(VERB_ALGO, "outgoing tcp:"
" setsockopt(.. TCP_NODELAY ..) failed");
}
#else
verbose(VERB_ALGO, "outgoing tcp:"
" setsockopt(.. TCP_NODELAY ..) unsupported");
#endif /* defined(IPPROTO_TCP) && defined(TCP_NODELAY) */
}
return s;
}

Expand Down Expand Up @@ -649,7 +663,8 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
}

/* open socket */
s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss, w->outnet->ip_dscp);
s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss,
w->outnet->ip_dscp, w->ssl_upstream);

if(s == -1)
return 0;
Expand Down Expand Up @@ -3718,7 +3733,8 @@ outnet_comm_point_for_tcp(struct outside_network* outnet,
sldns_buffer* query, int timeout, int ssl, char* host)
{
struct comm_point* cp;
int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss, outnet->ip_dscp);
int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss,
outnet->ip_dscp, ssl);
if(fd == -1) {
return 0;
}
Expand Down Expand Up @@ -3793,7 +3809,8 @@ outnet_comm_point_for_http(struct outside_network* outnet,
{
/* cp calls cb with err=NETEVENT_DONE when transfer is done */
struct comm_point* cp;
int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss, outnet->ip_dscp);
int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss,
outnet->ip_dscp, ssl);
if(fd == -1) {
return 0;
}
Expand Down
6 changes: 4 additions & 2 deletions services/outside_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -743,9 +743,11 @@ void reuse_write_wait_remove(struct reuse_tcp* reuse, struct waiting_tcp* w);
void reuse_write_wait_push_back(struct reuse_tcp* reuse, struct waiting_tcp* w);

/** get TCP file descriptor for address, returns -1 on failure,
* tcp_mss is 0 or maxseg size to set for TCP packets. */
* tcp_mss is 0 or maxseg size to set for TCP packets,
* nodelay (TCP_NODELAY) should be set for TLS connections to speed up the TLS
* handshake.*/
int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen,
int tcp_mss, int dscp);
int tcp_mss, int dscp, int nodelay);

/**
* Create udp commpoint suitable for sending packets to the destination.
Expand Down
3 changes: 2 additions & 1 deletion testcode/fake_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1938,7 +1938,8 @@ int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
}

int outnet_get_tcp_fd(struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(tcp_mss), int ATTR_UNUSED(dscp))
socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(tcp_mss),
int ATTR_UNUSED(dscp), int ATTR_UNUSED(nodelay))
{
log_assert(0);
return -1;
Expand Down
20 changes: 20 additions & 0 deletions util/config_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -2796,6 +2796,26 @@ int cfg_has_https(struct config_file* cfg)
return 0;
}

/** see if interface is ssl, its port number == the ssl port number */
int
if_is_ssl(const char* ifname, const char* port, int ssl_port,
struct config_strlist* tls_additional_port)
{
struct config_strlist* s;
char* p = strchr(ifname, '@');
if(!p && atoi(port) == ssl_port)
return 1;
if(p && atoi(p+1) == ssl_port)
return 1;
for(s = tls_additional_port; s; s = s->next) {
if(p && atoi(p+1) == atoi(s->str))
return 1;
if(!p && atoi(port) == atoi(s->str))
return 1;
}
return 0;
}

/** see if interface is PROXYv2, its port number == the proxy port number */
int
if_is_pp2(const char* ifname, const char* port,
Expand Down
4 changes: 4 additions & 0 deletions util/config_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,10 @@ int if_is_https(const char* ifname, const char* port, int https_port);
*/
int cfg_has_https(struct config_file* cfg);

/** see if interface is ssl, its port number == the ssl port number */
int if_is_ssl(const char* ifname, const char* port, int ssl_port,
struct config_strlist* tls_additional_port);

/** see if interface is PROXYv2, its port number == the proxy port number */
int if_is_pp2(const char* ifname, const char* port,
struct config_strlist* proxy_protocol_port);
Expand Down
Loading