From: Alan T. DeKok Date: Wed, 16 Apr 2025 15:27:29 +0000 (-0400) Subject: update handling of PMTU and EMSGSIZE X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=460e7ba0309d2fccc488a0f3996d769ab3dda2d9;p=thirdparty%2Ffreeradius-server.git update handling of PMTU and EMSGSIZE We disable PMTU discovery for the client code too, and not just for the server code. Add notes explaining what else needs to be done in order to fully support PTMUD update the write code to handle EMSGSIZE. This should arguably be done only for connected UDP sockets. --- diff --git a/src/lib/bio/fd_errno.h b/src/lib/bio/fd_errno.h index 0b52a2cd924..41da53da73e 100644 --- a/src/lib/bio/fd_errno.h +++ b/src/lib/bio/fd_errno.h @@ -46,6 +46,16 @@ case EPIPE: fr_bio_eof(&my->bio); return 0; +#ifdef FR_FD_BIO_EMSGSIZE + /* + * PMTU has been exceeded. Return a generic IO error. + * + * @todo - do this only for connected UDP sockets. + */ + case EMSGSIZE: + return fr_bio_error(IO); +#endif + default: /* * Some other error, it's fatal. diff --git a/src/lib/bio/fd_open.c b/src/lib/bio/fd_open.c index 92d2738fe61..bc28792a88c 100644 --- a/src/lib/bio/fd_open.c +++ b/src/lib/bio/fd_open.c @@ -167,6 +167,57 @@ static int fr_bio_fd_common_udp(int fd, fr_socket_t const *sock, fr_bio_fd_confi } #endif + /* + * IPv4 fragments packets. IPv6 does not. + * + * Many systems set the "don't fragment" bit by default for IPv4. This setting means that "too + * large" packets are silently discarded in the network. + * + * Many local networks support UDP fragmentation, so we just send packets and hope for the best. + * In order to support local networks, we disable the "don't fragment" bit. + * + * The wider Internet does not support UDP fragmentation. This means that fragmented packets are + * silently discarded. + * + * @todo - the correct way to handle this is to have a configuration flag which controls whether + * or not the "DF" bit is cleared. The documentation can make it clear that this only works on + * local networks, AND only on connected datagrams. The default should be to clear the DF bit. + * + * We then need to update the UDP reading code to handle EMSGSIZE as a non-fatal error. Since + * IPv6 will _always_ do PMTU discovery, we definitely need to handle this situation there. So + * we might as well handle it for IPv4, too. + */ + if (sock->af == AF_INET) { +#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) + /* + * Disable PMTU discovery. On Linux, this also makes sure that the "don't + * fragment" flag is zero. + */ + { + int flag = IP_PMTUDISC_DONT; + + if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)) < 0) { + fr_strerror_printf("Failed setting IP_MTU_DISCOVER: %s", fr_syserror(errno)); + return -1; + } + } +#endif + +#if defined(IP_DONTFRAG) + /* + * Ensure that the "don't fragment" flag is zero. + */ + { + int off = 0; + + if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &off, sizeof(off)) < 0) { + fr_strerror_printf("Failed setting IP_DONTFRAG: %s", fr_syserror(errno)); + return -1; + } + } +#endif + } + return fr_bio_fd_common_datagram(fd, sock, cfg); } @@ -190,33 +241,6 @@ static int fr_bio_fd_server_tcp(int fd, UNUSED fr_socket_t const *sock) */ static int fr_bio_fd_server_ipv4(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg) { - int flag; - -#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) - /* - * Disable PMTU discovery. On Linux, this also makes sure that the "don't - * fragment" flag is zero. - */ - flag = IP_PMTUDISC_DONT; - - if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)) < 0) { - fr_strerror_printf("Failed setting IP_MTU_DISCOVER: %s", fr_syserror(errno)); - return -1; - } -#endif - -#if defined(IP_DONTFRAG) - /* - * Ensure that the "don't fragment" flag is zero. - */ - flag = 0; - - if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &flag, sizeof(flag)) < 0) { - fr_strerror_printf("Failed setting IP_DONTFRAG: %s", fr_syserror(errno)); - return -1; - } -#endif - /* * And set up any UDP / TCP specific information. */ diff --git a/src/lib/bio/fd_write.h b/src/lib/bio/fd_write.h index 56e3b2499ee..448b8ab5bd7 100644 --- a/src/lib/bio/fd_write.h +++ b/src/lib/bio/fd_write.h @@ -51,4 +51,5 @@ if (rcode == 0) return rcode; #undef flag_blocked #define flag_blocked write_blocked +#define FR_FD_BIO_EMSGSIZE (1) #include "fd_errno.h"