]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
update handling of PMTU and EMSGSIZE
authorAlan T. DeKok <aland@freeradius.org>
Wed, 16 Apr 2025 15:27:29 +0000 (11:27 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 16 Apr 2025 15:41:27 +0000 (11:41 -0400)
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.

src/lib/bio/fd_errno.h
src/lib/bio/fd_open.c
src/lib/bio/fd_write.h

index 0b52a2cd924f2a812bc86a01f7dd03cd8e0735f7..41da53da73e43d7681d2a638cfe51caabf317275 100644 (file)
@@ -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.
index 92d2738fe61a91f3a7432fe28e99bddbf2b905fa..bc28792a88c5a57cbb4fa535c3990c25a101bd5c 100644 (file)
@@ -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.
         */
index 56e3b2499eecc5913f029f0da0b5056fa88317eb..448b8ab5bd7bc8aa6c858ec9faf404560cf83029 100644 (file)
@@ -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"