diff options
Diffstat (limited to 'src/lib/ndpi_reassmble.c')
-rw-r--r-- | src/lib/ndpi_reassmble.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/lib/ndpi_reassmble.c b/src/lib/ndpi_reassmble.c new file mode 100644 index 000000000..50141dacc --- /dev/null +++ b/src/lib/ndpi_reassmble.c @@ -0,0 +1,197 @@ +/* + * ndpi_reassmble.c + * + * Copyright (C) 2022 - ntop.org + * + * This file is part of nDPI, an open source deep packet inspection + * library. + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "ndpi_config.h" +#include "ndpi_api.h" + +/* ********************************************************************************* */ + +static void update_reasm_buf_bitmap(u_int8_t *buffer_bitmap, + const u_int32_t buffer_bitmap_size, + const u_int32_t recv_pos, + const u_int32_t recv_len) +{ + if (!recv_len || !buffer_bitmap_size || recv_pos + recv_len > buffer_bitmap_size * 8) + return; + const u_int32_t start_byte = recv_pos / 8; + const u_int32_t end_byte = (recv_pos + recv_len - 1) / 8; + const u_int32_t start_bit = recv_pos % 8; + const u_int32_t end_bit = (start_bit + recv_len - 1) % 8; + if (start_byte == end_byte) + { + // fill from bit 'start_bit' until bit 'end_bit', both inclusive + buffer_bitmap[start_byte] |= (((1U << recv_len) - 1U) << start_bit); + } else { + u_int32_t i; + for (i = start_byte + 1; i <= end_byte - 1; i++) + { + buffer_bitmap[i] = 0xff; // completely received byte + } + // fill from bit 'start_bit' until bit 7, both inclusive + buffer_bitmap[start_byte] |= ~((1U << start_bit) - 1U); + // fill from bit 0 until bit 'end_bit', both inclusive + buffer_bitmap[end_byte] |= (1U << (end_bit + 1U)) - 1U; + } +} + +/* ********************************************************************************* */ + +static uint64_t ndpi_reassemble_calculate_buffer_len(uint64_t min_len) +{ + return min_len + (8 - min_len % 8); +} + +void ndpi_reassemble_set_buffer_len(struct ndpi_reasm * const reasm, + uint64_t buffer_len) +{ + u_int32_t new_len = ndpi_reassemble_calculate_buffer_len(buffer_len); + + reasm->buf_req = buffer_len; + + if (reasm->buf_len == 0) + { + reasm->buf_len = new_len; + } else if (new_len > reasm->buf_len) { + uint8_t * const reasm_buf = (uint8_t *)ndpi_realloc(reasm->buf, reasm->buf_len, new_len); + uint8_t * const reasm_buf_bitmap = (uint8_t *)ndpi_realloc(reasm->buf_bitmap, reasm->buf_len, new_len); + if (reasm_buf != NULL && reasm_buf_bitmap != NULL) { + reasm->buf = reasm_buf; + reasm->buf_bitmap = reasm_buf_bitmap; + + memset(reasm->buf_bitmap + reasm->buf_len, 0, new_len - reasm->buf_len); + reasm->buf_len = new_len; + reasm->buf_last_pos = ndpi_min(reasm->buf_last_pos, new_len); + } + } +} + +/* ********************************************************************************* */ + +int ndpi_reassemble(struct ndpi_reasm * const reasm, uint8_t const * const frag, + uint64_t frag_len, uint64_t frag_offset) +{ + uint64_t max_reasm_buffer_len; + const uint64_t last_pos = frag_offset + frag_len; + + if (reasm->buf == NULL) + { + if (reasm->buf_len == 0) + { + ndpi_reassemble_set_buffer_len(reasm, + 4096 /* default: a couple of MTU sized packets */); + } + max_reasm_buffer_len = reasm->buf_len; + reasm->buf = (uint8_t *)ndpi_malloc(max_reasm_buffer_len); + reasm->buf_bitmap = (uint8_t *)ndpi_calloc(max_reasm_buffer_len, + sizeof(uint8_t)); + if (reasm->buf == NULL || reasm->buf_bitmap == NULL) + { + return -1; + } + reasm->buf_last_pos = 0; + } else { + max_reasm_buffer_len = reasm->buf_len; + } + + const uint64_t reasm_buffer_bitmap_len = reasm->buf_len / 8; + + if (last_pos > max_reasm_buffer_len) + { + return -3; + } + + memcpy(&reasm->buf[frag_offset], frag, frag_len); + if (last_pos > reasm->buf_last_pos) + { + reasm->buf_last_pos = last_pos; + } + update_reasm_buf_bitmap(reasm->buf_bitmap, reasm_buffer_bitmap_len, frag_offset, frag_len); + + return 0; +} + +int ndpi_reassemble_payload(struct ndpi_reasm * const reasm, struct ndpi_packet_struct * packet) +{ + return ndpi_reassemble(reasm, packet->payload, packet->payload_packet_len, reasm->buf_last_pos); +} + +/* ********************************************************************************* */ + +int ndpi_reassemble_in_progress(struct ndpi_reasm * const reasm) +{ + return reasm->buf_len > 0 && ndpi_reassemble_is_complete(reasm) == 0; +} + +/* ********************************************************************************* */ + +int ndpi_reassemble_is_complete(struct ndpi_reasm * const reasm) +{ + const u_int32_t complete_bytes = reasm->buf_last_pos / 8; + const u_int32_t remaining_bits = reasm->buf_last_pos % 8; + u_int32_t i; + + if (reasm->buf_last_pos < reasm->buf_req) + { + return 0; + } + + if (reasm->buf_last_pos > reasm->buf_req) + { + return 1; + } + + for(i = 0; i < complete_bytes; i++) + { + if (reasm->buf_bitmap[i] != 0xff) + { + return 0; + } + } + + if (remaining_bits && reasm->buf_bitmap[complete_bytes] != (1U << (remaining_bits)) - 1) + { + return 0; + } + + return 1; +} + +/* ********************************************************************************* */ + +void ndpi_reassemble_swap_payload(struct ndpi_packet_struct * packet, + struct ndpi_reasm const * reasm, + u_int8_t const ** const original_payload, + u_int16_t * original_payload_packet_len) +{ + if (reasm->buf == packet->payload) + { + packet->payload = *original_payload; + packet->payload_packet_len = *original_payload_packet_len; + } else { + *original_payload = packet->payload; + *original_payload_packet_len = packet->payload_packet_len; + + packet->payload = reasm->buf; + packet->payload_packet_len = reasm->buf_req; + } +} |