From 87d5c8ab7c7538c70e7aac23fefcb2e5f6d3964a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 28 Jul 2021 15:55:46 +0200 Subject: [PATCH] Disable the Path MTU Discover on UDP Sockets Instead of disabling the fragmentation on the UDP sockets, we now disable the Path MTU Discovery by setting IP(V6)_MTU_DISCOVER socket option to IP_PMTUDISC_OMIT on Linux and disabling IP(V6)_DONTFRAG socket option on FreeBSD. This option sets DF=0 in the IP header and also ignores the Path MTU Discovery. As additional mitigation on Linux, we recommend setting net.ipv4.ip_no_pmtu_disc to Mode 3: Mode 3 is a hardend pmtu discover mode. The kernel will only accept fragmentation-needed errors if the underlying protocol can verify them besides a plain socket lookup. Current protocols for which pmtu events will be honored are TCP, SCTP and DCCP as they verify e.g. the sequence number or the association. This mode should not be enabled globally but is only intended to secure e.g. name servers in namespaces where TCP path mtu must still work but path MTU information of other protocols should be discarded. If enabled globally this mode could break other protocols. --- lib/isc/netmgr/netmgr-int.h | 5 +++-- lib/isc/netmgr/netmgr.c | 16 ++++++++-------- lib/isc/netmgr/udp.c | 4 ++-- lib/isc/socket.c | 18 +++++++++--------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 23cfe8cbf1..2c7f3d8281 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -1779,9 +1779,10 @@ isc__nm_socket_incoming_cpu(uv_os_sock_t fd); */ isc_result_t -isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family); +isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family); /*%< - * Set the SO_IP_DONTFRAG (or equivalent) socket option of the fd if available + * Disable the Path MTU Discovery, either by disabling IP(V6)_DONTFRAG socket + * option, or setting the IP(V6)_MTU_DISCOVER socket option to IP_PMTUDISC_OMIT */ isc_result_t diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 42a9d681c7..975e8cc427 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -3044,20 +3044,20 @@ isc__nm_socket_incoming_cpu(uv_os_sock_t fd) { } isc_result_t -isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family) { +isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family) { /* - * Set the Don't Fragment flag on IP packets + * Disable the Path MTU Discovery on IP packets */ if (sa_family == AF_INET6) { #if defined(IPV6_DONTFRAG) - if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) { + if (setsockopt_off(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) { return (ISC_R_FAILURE); } else { return (ISC_R_SUCCESS); } -#elif defined(IPV6_MTU_DISCOVER) +#elif defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT) if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, - &(int){ IP_PMTUDISC_DO }, sizeof(int)) == -1) + &(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1) { return (ISC_R_FAILURE); } else { @@ -3068,14 +3068,14 @@ isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family) { #endif } else if (sa_family == AF_INET) { #if defined(IP_DONTFRAG) - if (setsockopt_on(fd, IPPROTO_IP, IP_DONTFRAG) == -1) { + if (setsockopt_off(fd, IPPROTO_IP, IP_DONTFRAG) == -1) { return (ISC_R_FAILURE); } else { return (ISC_R_SUCCESS); } -#elif defined(IP_MTU_DISCOVER) +#elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT) if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, - &(int){ IP_PMTUDISC_DO }, sizeof(int)) == -1) + &(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1) { return (ISC_R_FAILURE); } else { diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index d9dbefca3d..fbf9345592 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -65,7 +65,7 @@ isc__nm_udp_lb_socket(sa_family_t sa_family) { RUNTIME_CHECK(result == ISC_R_SUCCESS); (void)isc__nm_socket_incoming_cpu(sock); - (void)isc__nm_socket_dontfrag(sock, sa_family); + (void)isc__nm_socket_disable_pmtud(sock, sa_family); result = isc__nm_socket_reuse(sock); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -760,7 +760,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, (void)isc__nm_socket_incoming_cpu(sock->fd); - (void)isc__nm_socket_dontfrag(sock->fd, sa_family); + (void)isc__nm_socket_disable_pmtud(sock->fd, sa_family); event = isc__nm_get_netievent_udpconnect(mgr, sock, req); diff --git a/lib/isc/socket.c b/lib/isc/socket.c index 5bf8a1ffb7..fd67c8299f 100644 --- a/lib/isc/socket.c +++ b/lib/isc/socket.c @@ -2098,27 +2098,27 @@ set_tcp_maxseg(isc_socket_t *sock, int size) { } static void -set_ip_dontfrag(isc_socket_t *sock) { +set_ip_disable_pmtud(isc_socket_t *sock) { /* - * Set the Don't Fragment flag on IP packets + * Disable Path MTU Discover on IP packets */ if (sock->pf == AF_INET6) { #if defined(IPV6_DONTFRAG) (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_DONTFRAG, - &(int){ 1 }, sizeof(int)); + &(int){ 0 }, sizeof(int)); #endif -#if defined(IPV6_MTU_DISCOVER) +#if defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT) (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, - &(int){ IP_PMTUDISC_DO }, sizeof(int)); + &(int){ IP_PMTUDISC_OMIT }, sizeof(int)); #endif } else if (sock->pf == AF_INET) { #if defined(IP_DONTFRAG) - (void)setsockopt(sock->fd, IPPROTO_IP, IP_DONTFRAG, &(int){ 1 }, + (void)setsockopt(sock->fd, IPPROTO_IP, IP_DONTFRAG, &(int){ 0 }, sizeof(int)); #endif -#if defined(IP_MTU_DISCOVER) +#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT) (void)setsockopt(sock->fd, IPPROTO_IP, IP_MTU_DISCOVER, - &(int){ IP_PMTUDISC_DO }, sizeof(int)); + &(int){ IP_PMTUDISC_OMIT }, sizeof(int)); #endif } } @@ -2409,7 +2409,7 @@ again: #endif /* ifdef IP_RECVTOS */ #endif /* defined(USE_CMSG) || defined(SET_RCVBUF) || defined(SET_SNDBUF) */ - set_ip_dontfrag(sock); + set_ip_disable_pmtud(sock); setup_done: inc_stats(manager->stats, sock->statsindex[STATID_OPEN]);