]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add "exceed_mtu" configuration flag for UDP sockets.
authorAlan T. DeKok <aland@freeradius.org>
Wed, 16 Apr 2025 15:58:19 +0000 (11:58 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 16 Apr 2025 16:11:45 +0000 (12:11 -0400)
which defaults to "yes".

When set to "yes", clears the "don't fragment" bit in the IP
packet header.

When set to "no", it uses the OS definition for the DF bit.
Note that we do NOT set the DF bit.  OSX supports IP_DONTFRAG
only for raw sockets.  Linux always sets the DF flag for UDP
sockets.

No matter what this flag is set to, there are some situations
where UDP packets will silently disappear in the network.
When DF is set, "too large" packets might get an ICMP error
to the OS, which the server will currently ignore.
When DF is clear, "too large" packets might be silently discarded
by some other network element.

We can later add code to do actual PMTU discovery

src/lib/bio/fd.h
src/lib/bio/fd_config.c
src/lib/bio/fd_open.c

index d5baa7e35951713b822529633031a2c05aebc94f..81ed87de9294cedb2ba30cc8197323a5a2b7eef8 100644 (file)
@@ -111,6 +111,7 @@ typedef struct {
 
        bool            async;          //!< is it async
        bool            tcp_delay;      //!< We do tcp_nodelay by default.
+       bool            exceed_mtu;     //!< Whether we allow packets which exceed the local MTU
 
        /*
         *      Extra fields for conf_parser_t
index 2385740290d9179add001dbdda7f5158fa34de7e..97b2dc1011490b8f42839aa914d8aacf0b61074d 100644 (file)
@@ -118,6 +118,10 @@ static const conf_parser_t client_udp_sub_config[] = {
 
        { FR_CONF_OFFSET("interface", fr_bio_fd_config_t, interface) },
 
+#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
+       { FR_CONF_OFFSET("exceed_mtu", fr_bio_fd_config_t, exceed_mtu), .dflt = "yes" },
+#endif
+
        { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
        { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
 
@@ -141,6 +145,10 @@ static const conf_parser_t client_udp_unconnected_sub_config[] = {
        { FR_CONF_OFFSET("src_port_start", fr_bio_fd_config_t, src_port_start) },
        { FR_CONF_OFFSET("src_port_end", fr_bio_fd_config_t, src_port_end) },
 
+#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
+       { FR_CONF_OFFSET("exceed_mtu", fr_bio_fd_config_t, exceed_mtu), .dflt = "yes" },
+#endif
+
        { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
        { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
 
@@ -289,6 +297,10 @@ static const conf_parser_t server_udp_sub_config[] = {
        { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, recv_buff) },
        { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, 0, fr_bio_fd_config_t, send_buff) },
 
+#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
+       { FR_CONF_OFFSET("exceed_mtu", fr_bio_fd_config_t, exceed_mtu), .dflt = "yes" },
+#endif
+
        CONF_PARSER_TERMINATOR
 };
 
index bc28792a88c5a57cbb4fa535c3990c25a101bd5c..9f291e9139146e697c6cb055bb5feb5a53f5f765 100644 (file)
@@ -179,15 +179,14 @@ static int fr_bio_fd_common_udp(int fd, fr_socket_t const *sock, fr_bio_fd_confi
         *      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.
+        *      @todo - add more code to properly handle EMSGSIZE for PMTUD.  We can then also do
+        *      getsockopt(fd,IP_MTU,&integer) to get the current path MTU.  It can only be used after the
+        *      socket has been connected.  It should also be called after an EMSGSIZE error is returned.
         *
-        *      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.
+        *      getsockopt(fd,IP_MTU,&integer) can also be used for unconnected sockets, if we also set
+        *      IP_RECVERR.  In which case the errors are put into an error queue.  This is only for Linux.
         */
-       if (sock->af == AF_INET) {
+       if ((sock->af == AF_INET) && cfg->exceed_mtu) {
 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
                /*
                 *      Disable PMTU discovery.  On Linux, this also makes sure that the "don't