From: Alan T. DeKok Date: Tue, 30 Jan 2024 11:49:09 +0000 (-0500) Subject: There may already be a packet in the buffer. Helps with #5286 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3f0e61d1d1790a9c5df126a322802bb2c6e7dd2;p=thirdparty%2Ffreeradius-server.git There may already be a packet in the buffer. Helps with #5286 --- diff --git a/src/listen/radius/proto_radius_tcp.c b/src/listen/radius/proto_radius_tcp.c index 5d24641df42..48635a5dfff 100644 --- a/src/listen/radius/proto_radius_tcp.c +++ b/src/listen/radius/proto_radius_tcp.c @@ -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; } diff --git a/src/listen/tacacs/proto_tacacs_tcp.c b/src/listen/tacacs/proto_tacacs_tcp.c index 19d58c3892d..71a327a5273 100644 --- a/src/listen/tacacs/proto_tacacs_tcp.c +++ b/src/listen/tacacs/proto_tacacs_tcp.c @@ -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 */ }