]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Set minimum MTU (1280) on IPv6 sockets
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)
The IPV6_USE_MIN_MTU socket option directs the IP layer to limit the
IPv6 packet size to the minimum required supported MTU from the base
IPv6 specification, i.e. 1280 bytes.  Many implementations of TCP
running over IPv6 neglect to check the IPV6_USE_MIN_MTU value when
performing MSS negotiation and when constructing a TCP segment despite
MSS being defined to be the MTU less the IP and TCP header sizes (60
bytes for IPv6).  This leads to oversized IPv6 packets being sent
resulting in unintended Path Maximum Transport Unit Discovery (PMTUD)
being performed and to fragmented IPv6 packets being sent.

Add and use a function to set socket option to limit the MTU on IPv6
sockets to the minimum MTU (1280) both for UDP and TCP.

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
lib/isc/netmgr/udp.c

index a6c8b0a8a63f93b3afde97659213e8760ed94660..03897e77bf884267c07078d5050201d242206fb8 100644 (file)
@@ -1863,6 +1863,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_min_mtu(uv_os_sock_t fd, sa_family_t sa_family);
+/*%<
+ * Use minimum MTU on IPv6 sockets
+ */
+
 void
 isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle);
 /*%>
index eafce4ec1c0528fa49555662677201d127c2cc61..8f5589cd6ea21865bd9d1db7296c2b4a6b9eb0cf 100644 (file)
@@ -3263,6 +3263,27 @@ isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) {
 #endif
 }
 
+isc_result_t
+isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family) {
+       if (sa_family != AF_INET6) {
+               return (ISC_R_SUCCESS);
+       }
+#ifdef IPV6_USE_MIN_MTU
+       if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU) == -1) {
+               return (ISC_R_FAILURE);
+       }
+#elif defined(IPV6_MTU)
+       if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &(int){ 1280 },
+                      sizeof(int)) == -1) {
+               return (ISC_R_FAILURE);
+       }
+#else
+       UNUSED(fd);
+#endif
+
+       return (ISC_R_SUCCESS);
+}
+
 void
 isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle) {
        int32_t recv_buffer_size = 0;
index b033e71cc8da132c1575647ed5fb247c56049eb3..4e187d31e208444e122bdafc1eb4e59e6bec1c32 100644 (file)
@@ -342,6 +342,8 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
                return;
        }
 
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+
        ievent = isc__nm_get_netievent_tcpconnect(mgr, sock, req);
 
        if (isc__nm_in_netthread()) {
@@ -525,7 +527,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->parent != NULL);
        REQUIRE(sock->tid == isc_nm_tid());
 
-       /* TODO: set min mss */
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
 
        r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
        UV_RUNTIME_CHECK(uv_tcp_init, r);
index fcce42df970d9e7a25cc7666daa4305815f204b2..1b84b50da7a704f0f084d59835bd727a7285f592 100644 (file)
@@ -297,6 +297,8 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
                return;
        }
 
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+
        /* 2 minute timeout */
        result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -489,7 +491,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->parent != NULL);
        REQUIRE(sock->tid == isc_nm_tid());
 
-       /* TODO: set min mss */
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
 
        r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
        UV_RUNTIME_CHECK(uv_tcp_init, r);
index af5362f7e693785f04922d08fa41f0cfe265886d..369eac14974621d56d9f9a5ecf0247ecb9ae21ec 100644 (file)
@@ -351,6 +351,8 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
                goto failure;
        }
 
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+
        /* 2 minute timeout */
        result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -560,7 +562,7 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->parent != NULL);
        REQUIRE(sock->tid == isc_nm_tid());
 
-       /* TODO: set min mss */
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
 
        r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
        UV_RUNTIME_CHECK(uv_tcp_init, r);
index e8ef4100f1c0cdac42c369c816d8f85c4b0f92ab..624932bc9852572d8a571a7d4ed23b491dc0979b 100644 (file)
@@ -439,6 +439,8 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->parent != NULL);
        REQUIRE(sock->tid == isc_nm_tid());
 
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+
 #if HAVE_DECL_UV_UDP_RECVMMSG
        uv_init_flags |= UV_UDP_RECVMMSG;
 #endif
@@ -1031,6 +1033,8 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
 
        (void)isc__nm_socket_disable_pmtud(sock->fd, sa_family);
 
+       (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
+
        event = isc__nm_get_netievent_udpconnect(mgr, sock, req);
 
        if (isc__nm_in_netthread()) {