diff --git a/CHANGES b/CHANGES index 542742d26c..7839b51d26 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +5825. [funcf] Set the minimum MTU on UDPv6 and TCPv6 sockets and + limit TCP maximum segment size (TCP_MAXSEG) to (1220) + for both TCPv4 and TCPv6 sockets. [GL #2201] + 5824. [bug] Invalid dnssec-policy definitions were being accepted where the defined keys did not cover both KSK and ZSK roles for a given algorithm. This is now checked for diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index a6c8b0a8a6..596423458b 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -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,18 @@ 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); +/*%< + * Use minimum MTU on IPv6 sockets + */ + void isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle); /*%> diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index eafce4ec1c..f23be6bca9 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -3263,6 +3263,43 @@ 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) { + 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; diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index b033e71cc8..c924c25e6c 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -342,6 +342,9 @@ 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); + (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG); + ievent = isc__nm_get_netievent_tcpconnect(mgr, sock, req); if (isc__nm_in_netthread()) { @@ -525,7 +528,8 @@ 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); + (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); diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index fcce42df97..d57e2a149d 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -297,6 +297,9 @@ 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); + (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG); + /* 2 minute timeout */ result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -489,7 +492,8 @@ 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); + (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); diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index af5362f7e6..1e93a92c5e 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -351,6 +351,9 @@ 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); + (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG); + /* 2 minute timeout */ result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -560,7 +563,8 @@ 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); + (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); diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index e8ef4100f1..624932bc98 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -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()) {