]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
There may already be a packet in the buffer. Helps with #5286
authorAlan T. DeKok <aland@freeradius.org>
Tue, 30 Jan 2024 11:49:09 +0000 (06:49 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 30 Jan 2024 11:49:09 +0000 (06:49 -0500)
src/listen/radius/proto_radius_tcp.c
src/listen/tacacs/proto_tacacs_tcp.c

index 5d24641df4241866414e551240c8a6db9bfe33de..48635a5dfff6b173e2526e97282453beba8aa8c4 100644 (file)
@@ -108,6 +108,24 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
        size_t                          packet_len, in_buffer;
        decode_fail_t                   reason;
 
+       /*
+        *      We may hvae read multiple packets in the previous read.  In which case the buffer may already
+        *      have packets remaining.  In that case, we can return packets directly from the buffer, and
+        *      skip the read().
+        */
+       if (*leftover >= RADIUS_HEADER_LENGTH) {
+               packet_len = fr_nbo_to_uint16(buffer + 2);
+
+               if (packet_len <= *leftover) {
+                       data_size = 0;
+                       goto have_packet;
+               }
+
+               /*
+                *      Else we don't have a full packet, try to read more data from the network.
+                */
+       }
+
        /*
         *      Read data into the buffer.
         */
@@ -119,7 +137,7 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
 #endif
                case EAGAIN:
                        /*
-                        *      We didn't read any data leave the buffers alone.
+                        *      We didn't read any data; leave the buffers alone.
                         *
                         *      i.e. if we had a partial packet in the buffer and we didn't read any data,
                         *      then the partial packet is still left in the buffer.
@@ -130,7 +148,7 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
                        break;
                }
 
-               PDEBUG2("proto_radius_tcp got read error %zd", data_size);
+               PDEBUG2("proto_radius_tcp got read error (%zd) - %s", data_size, fr_syserror(errno));
                return data_size;
        }
 
@@ -148,6 +166,7 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
                return -1;
        }
 
+have_packet:
        /*
         *      We MUST always start with a known RADIUS packet.
         */
@@ -162,7 +181,7 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
        /*
         *      Not enough for one packet.  Tell the caller that we need to read more.
         */
-       if (in_buffer < 20) {
+       if (in_buffer < RADIUS_HEADER_LENGTH) {
                *leftover = in_buffer;
                return 0;
        }
index 19d58c3892d8015b06cf5938dfe98e37b206103a..71a327a5273fa36137b06f0616f06dd181499866 100644 (file)
@@ -130,6 +130,25 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
        ssize_t                         data_size, packet_len;
        size_t                          in_buffer;
 
+       /*
+        *      We may hvae read multiple packets in the previous read.  In which case the buffer may already
+        *      have packets remaining.  In that case, we can return packets directly from the buffer, and
+        *      skip the read().
+        */
+       if (*leftover >= FR_HEADER_LENGTH) {
+               packet_len = fr_tacacs_length(buffer, *leftover);
+               if (packet_len < 0) goto invalid;
+
+               if (packet_len <= *leftover) {
+                       data_size = 0;
+                       goto have_packet;
+               }
+
+               /*
+                *      Else we don't have a full packet, try to read more data from the network.
+                */
+       }
+
        /*
         *      Read data into the buffer.
         */
@@ -170,6 +189,7 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
                return -1;
        }
 
+have_packet:
        /*
         *      Represents all the data we've read since we last
         *      decoded a complete packet.
@@ -183,6 +203,7 @@ static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *re
         */
        packet_len = fr_tacacs_length(buffer, in_buffer);
        if (packet_len < 0) {
+       invalid:
                PERROR("Invalid TACACS packet");
                return -1;      /* Malformed, close the socket */
        }