]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Use TCP_NODELAY on TLS sockets to speed up the TLS handshake. 1214/head
authorYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Fri, 10 Jan 2025 11:11:59 +0000 (12:11 +0100)
committerYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Fri, 10 Jan 2025 11:11:59 +0000 (12:11 +0100)
services/listen_dnsport.c
services/outside_network.c
services/outside_network.h
testcode/fake_event.c
util/config_file.c
util/config_file.h

index bdd14b04a660c36f428404b0a56fce103b176fd8..8a5cf2a180d45b7dde5e3908b1f8785471d94d89 100644 (file)
@@ -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
@@ -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.
@@ -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;
index b9475a368c791c483b49eb56e9e09f609c712e99..0d7ec890573b7ffbd94c240620ca0625c49bba7c 100644 (file)
@@ -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
@@ -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;
 }
 
@@ -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;
@@ -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;
        }
@@ -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;
        }
index 467c81f60ca2de00657160d39e979ad4ca2a93ea..0a77e3388ddc97242d554357b38442f1d17736c7 100644 (file)
@@ -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.
index be61ed5c6e99923f1af8a95414711a96f870ab44..840a687d9d87b4ff469e64a5686be265e6b47711 100644 (file)
@@ -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;
index 58567dccc9030d20dbabfdf989e46a400d6a7c3a..dbe1b70814cae40f802a8d8065def1a75499f062 100644 (file)
@@ -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,
index 2969f8433963313c8ed811e3df1029acbe065789..07e539f0657142b88d03091f3bb46b6d3c5c6f7b 100644 (file)
@@ -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);