]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Set TCP maximum segment size to minimum size of 1220
authorOndřej Surý <ondrej@sury.org>
Tue, 5 Oct 2021 20:30:55 +0000 (22:30 +0200)
committerOndřej Surý <ondrej@isc.org>
Tue, 8 Mar 2022 09:27:05 +0000 (10:27 +0100)
Previously the socket code would set the TCPv6 maximum segment size to
minimum value to prevent IP fragmentation for TCP.  This was not yet
implemented for the network manager.

Implement network manager functions to set and use minimum MTU socket
option and set the TCP_MAXSEG socket option for both IPv4 and IPv6 and
use those to clamp the TCP maximum segment size for TCP, TCPDNS and
TLSDNS layers in the network manager to 1220 bytes, that is 1280 (IPv6
minimum link MTU) minus 40 (IPv6 fixed header) minus 20 (TCP fixed
header)

We already rely on a similar value for UDP to prevent IP fragmentation
and it make sense to use the same value for IPv4 and IPv6 because the
modern networks are required to support IPv6 packet sizes.  If there's
need for small TCP segment values, the MTU on the interfaces needs to be
properly configured.

lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/isc/netmgr/tcp.c
lib/isc/netmgr/tcpdns.c
lib/isc/netmgr/tlsdns.c

index 03897e77bf884267c07078d5050201d242206fb8..596423458b01ff1fe05a28d82ed249305d9201f9 100644 (file)
@@ -103,6 +103,14 @@ STATIC_ASSERT(ISC_NETMGR_TCP_RECVBUF_SIZE <= ISC_NETMGR_RECVBUF_SIZE,
  */
 #define NM_BIG_BUF ISC_NETMGR_TCP_RECVBUF_SIZE * 2
 
+/*%
+ * Maximum segment size (MSS) of TCP socket on which the server responds to
+ * queries. Value lower than common MSS on Ethernet (1220, that is 1280 (IPv6
+ * minimum link MTU) - 40 (IPv6 fixed header) - 20 (TCP fixed header)) will
+ * address path MTU problem.
+ */
+#define NM_MAXSEG (1280 - 20 - 40)
+
 #if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
 #define HAVE_SO_REUSEPORT_LB 1
 #endif
@@ -1863,6 +1871,12 @@ isc__nm_socket_tcp_nodelay(uv_os_sock_t fd);
  * Disables Nagle's algorithm on a TCP socket (sets TCP_NODELAY).
  */
 
+isc_result_t
+isc__nm_socket_tcp_maxseg(uv_os_sock_t fd, int size);
+/*%<
+ * Set the TCP maximum segment size
+ */
+
 isc_result_t
 isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family);
 /*%<
index 8f5589cd6ea21865bd9d1db7296c2b4a6b9eb0cf..f23be6bca9a17a4dd464a6fa93b13aa4ba0ea06f 100644 (file)
@@ -3263,6 +3263,22 @@ isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) {
 #endif
 }
 
+isc_result_t
+isc__nm_socket_tcp_maxseg(uv_os_sock_t fd, int size) {
+#ifdef TCP_MAXSEG
+       if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (void *)&size,
+                      sizeof(size))) {
+               return (ISC_R_FAILURE);
+       } else {
+               return (ISC_R_SUCCESS);
+       }
+#else
+       UNUSED(fd);
+       UNUSED(size);
+       return (ISC_R_SUCCESS);
+#endif
+}
+
 isc_result_t
 isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family) {
        if (sa_family != AF_INET6) {
index 4e187d31e208444e122bdafc1eb4e59e6bec1c32..c924c25e6cc5a6794179c53dd00dacfa629ed777 100644 (file)
@@ -343,6 +343,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
        }
 
        (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+       (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
 
        ievent = isc__nm_get_netievent_tcpconnect(mgr, sock, req);
 
@@ -528,6 +529,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->tid == isc_nm_tid());
 
        (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+       (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
 
        r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
        UV_RUNTIME_CHECK(uv_tcp_init, r);
index 1b84b50da7a704f0f084d59835bd727a7285f592..d57e2a149d05fb95c6afa7171c5f50ad75966d92 100644 (file)
@@ -298,6 +298,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
        }
 
        (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+       (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
 
        /* 2 minute timeout */
        result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
@@ -492,6 +493,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->tid == isc_nm_tid());
 
        (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+       (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
 
        r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
        UV_RUNTIME_CHECK(uv_tcp_init, r);
index 369eac14974621d56d9f9a5ecf0247ecb9ae21ec..1e93a92c5e0b9589ec024b6f8646fabcbb77f543 100644 (file)
@@ -352,6 +352,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
        }
 
        (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+       (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
 
        /* 2 minute timeout */
        result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
@@ -563,6 +564,7 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->tid == isc_nm_tid());
 
        (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+       (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
 
        r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
        UV_RUNTIME_CHECK(uv_tcp_init, r);