diff options
author | lns <matzeton@googlemail.com> | 2022-05-27 22:09:58 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2022-08-24 11:47:46 +0200 |
commit | 71f91b5183f9a2735add7e1f0ec86f41f0b06845 (patch) | |
tree | d6808a59c8357973af9a164681f1f1737c7a725d | |
parent | ac24b35b1fa36f8df6d586742200a0dc2d54f59e (diff) |
Provide a generic reassembler interface.add/generic-reassembler-interface
* Shall be used for stream based protocols e.g. Kerberos, QUIC, etc.
Signed-off-by: lns <matzeton@googlemail.com>
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | src/include/ndpi_api.h.in | 15 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 25 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 16 | ||||
-rw-r--r-- | src/lib/ndpi_reassmble.c | 197 | ||||
-rw-r--r-- | src/lib/protocols/kerberos.c | 113 | ||||
-rw-r--r-- | src/lib/protocols/quic.c | 96 | ||||
-rw-r--r-- | tests/unit/unit.c | 71 |
7 files changed, 359 insertions, 174 deletions
diff --git a/src/include/ndpi_api.h.in b/src/include/ndpi_api.h.in index 9064ac627..a9c39313c 100644 --- a/src/include/ndpi_api.h.in +++ b/src/include/ndpi_api.h.in @@ -1823,6 +1823,21 @@ extern "C" { char *out, u_int out_len, u_int8_t use_json); + /* ******************************* */ + + void ndpi_reassemble_set_buffer_len(struct ndpi_reasm * const reasm, + u_int64_t buffer_len); + int ndpi_reassemble(struct ndpi_reasm * const reasm, uint8_t const * const frag, + uint64_t frag_len, uint64_t frag_offset); + int ndpi_reassemble_payload(struct ndpi_reasm * const reasm, + struct ndpi_packet_struct * packet); + 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); + int ndpi_reassemble_in_progress(struct ndpi_reasm * const reasm); + int ndpi_reassemble_is_complete(struct ndpi_reasm * const reasm); + #ifdef __cplusplus } #endif diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index efea443d6..ee4eabbc2 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -647,6 +647,14 @@ struct ndpi_lru_cache { struct ndpi_lru_cache_entry *entries; }; +struct ndpi_reasm { + u_int8_t *buf; + u_int8_t *buf_bitmap; + u_int32_t buf_last_pos; + u_int32_t buf_req; + u_int32_t buf_len; +}; + /* ************************************************** */ struct ndpi_flow_tcp_struct { @@ -808,11 +816,6 @@ struct ndpi_flow_udp_struct { u_int8_t wireguard_stage; u_int32_t wireguard_peer_index[2]; - /* NDPI_PROTOCOL_QUIC */ - u_int8_t *quic_reasm_buf; - u_int8_t *quic_reasm_buf_bitmap; - u_int32_t quic_reasm_buf_last_pos; - /* NDPI_PROTOCOL_CSGO */ u_int8_t csgo_strid[18],csgo_state,csgo_s2; u_int32_t csgo_id2; @@ -1293,6 +1296,8 @@ struct ndpi_flow_struct { struct ndpi_flow_udp_struct udp; } l4; + struct ndpi_reasm reassemble; + /* Some protocols calculate the entropy. */ float entropy; @@ -1330,16 +1335,6 @@ struct ndpi_flow_struct { char *nat_ip; /* Via HTTP X-Forwarded-For */ } http; - /* - Put outside of the union to avoid issues in case the protocol - is remapped to somethign pther than Kerberos due to a faulty - dissector - */ - struct { - char *pktbuf; - u_int16_t pktbuf_maxlen, pktbuf_currlen; - } kerberos_buf; - struct { u_int8_t num_udp_pkts, num_binding_requests; u_int16_t num_processed_pkts; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 7929b3b88..8521d5dda 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -4895,9 +4895,6 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { if(flow->http.detected_os) ndpi_free(flow->http.detected_os); - if(flow->kerberos_buf.pktbuf) - ndpi_free(flow->kerberos_buf.pktbuf); - if(flow_is_proto(flow, NDPI_PROTOCOL_QUIC) || flow_is_proto(flow, NDPI_PROTOCOL_TLS) || flow_is_proto(flow, NDPI_PROTOCOL_DTLS) || @@ -4930,12 +4927,13 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { ndpi_free(flow->l4.tcp.tls.message[1].buffer); } - if(flow->l4_proto == IPPROTO_UDP) { - if(flow->l4.udp.quic_reasm_buf){ - ndpi_free(flow->l4.udp.quic_reasm_buf); - if(flow->l4.udp.quic_reasm_buf_bitmap) - ndpi_free(flow->l4.udp.quic_reasm_buf_bitmap); - } + if (flow->reassemble.buf != NULL) + { + ndpi_free(flow->reassemble.buf); + } + if (flow->reassemble.buf_bitmap != NULL) + { + ndpi_free(flow->reassemble.buf_bitmap); } } } 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; + } +} diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c index 92ee7defe..fd35be435 100644 --- a/src/lib/protocols/kerberos.c +++ b/src/lib/protocols/kerberos.c @@ -322,30 +322,27 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, #ifdef KERBEROS_DEBUG printf("\n[Kerberos] Process packet [len: %u]\n", packet->payload_packet_len); #endif - - if(flow->kerberos_buf.pktbuf != NULL) { - u_int missing = flow->kerberos_buf.pktbuf_maxlen - flow->kerberos_buf.pktbuf_currlen; - - if(packet->payload_packet_len <= missing) { - memcpy(&flow->kerberos_buf.pktbuf[flow->kerberos_buf.pktbuf_currlen], packet->payload, packet->payload_packet_len); - flow->kerberos_buf.pktbuf_currlen += packet->payload_packet_len; - - if(flow->kerberos_buf.pktbuf_currlen == flow->kerberos_buf.pktbuf_maxlen) { - original_packet_payload = packet->payload; - original_payload_packet_len = packet->payload_packet_len; - packet->payload = (u_int8_t *)flow->kerberos_buf.pktbuf; - packet->payload_packet_len = flow->kerberos_buf.pktbuf_currlen; + + if (ndpi_reassemble_in_progress(&flow->reassemble) != 0) + { + if (ndpi_reassemble_payload(&flow->reassemble, packet) != 0) + { + return; + } + if (ndpi_reassemble_is_complete(&flow->reassemble) != 0) + { + ndpi_reassemble_swap_payload(packet, &flow->reassemble, &original_packet_payload, + &original_payload_packet_len); #ifdef KERBEROS_DEBUG - printf("[Kerberos] Packet is now full: processing\n"); + printf("[Kerberos] Packet is now full: processing\n"); #endif - } else { + } else { #ifdef KERBEROS_DEBUG - printf("[Kerberos] Missing %u bytes: skipping\n", - flow->kerberos_buf.pktbuf_maxlen - flow->kerberos_buf.pktbuf_currlen); + printf("[Kerberos] Missing %u bytes: skipping\n", + flow->reassemble.buf_len - flow->reassemble.buf_last_pos); #endif - return; - } + return; } } @@ -356,44 +353,30 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, if(packet->tcp) { kerberos_len = ntohl(get_u_int32_t(packet->payload, 0)), - expected_len = packet->payload_packet_len - 4; + expected_len = packet->payload_packet_len - 4; base_offset = 4; - } else + } else { base_offset = 0, kerberos_len = expected_len = packet->payload_packet_len; + } #ifdef KERBEROS_DEBUG printf("[Kerberos] [Kerberos len: %u][expected_len: %u]\n", kerberos_len, expected_len); #endif - if(kerberos_len < 12000) { + if (kerberos_len < 12000 && packet->tcp != NULL && + kerberos_len > expected_len) { /* - Kerberos packets might be too long for a TCP packet - so it could be split across two packets. Instead of - rebuilding the stream we use a heuristic approach - */ - if(kerberos_len > expected_len) { - if(packet->tcp) { - if(flow->kerberos_buf.pktbuf == NULL) { - flow->kerberos_buf.pktbuf = (char*)ndpi_malloc(kerberos_len+4); - - if(flow->kerberos_buf.pktbuf != NULL) { - flow->kerberos_buf.pktbuf_maxlen = kerberos_len+4; + * Kerberos packets might be too long for a TCP packet + * so it could be split across two packets. Instead of + * rebuilding the stream we use a heuristic approach + */ + ndpi_reassemble_set_buffer_len(&flow->reassemble, kerberos_len + 4); + ndpi_reassemble_payload(&flow->reassemble, packet); #ifdef KERBEROS_DEBUG - printf("[Kerberos] Allocated %u bytes\n", flow->kerberos_buf.pktbuf_maxlen); -#endif - } - } - - if(flow->kerberos_buf.pktbuf != NULL) { - if(packet->payload_packet_len <= flow->kerberos_buf.pktbuf_maxlen) { - memcpy(flow->kerberos_buf.pktbuf, packet->payload, packet->payload_packet_len); - flow->kerberos_buf.pktbuf_currlen = packet->payload_packet_len; - } - } - } - - return; - } else if(kerberos_len == expected_len) { + printf("[Kerberos] Allocated %u bytes\n", flow->reassemble.buf_len); +#endif + return; + } else if(kerberos_len == expected_len) { if(packet->payload_packet_len > 64) { u_int16_t koffset, i; @@ -611,12 +594,10 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, ndpi_snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str); /* If necessary we can decode sname */ - if(flow->kerberos_buf.pktbuf) { - ndpi_free(flow->kerberos_buf.pktbuf); - packet->payload = original_packet_payload; - packet->payload_packet_len = original_payload_packet_len; + if(ndpi_reassemble_in_progress(&flow->reassemble) != 0) { + ndpi_reassemble_swap_payload(packet, &flow->reassemble, &original_packet_payload, + &original_payload_packet_len); } - flow->kerberos_buf.pktbuf = NULL; } } } @@ -629,14 +610,13 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, flow->extra_packets_func = ndpi_search_kerberos_extra; } - if(flow->kerberos_buf.pktbuf != NULL) { - ndpi_free(flow->kerberos_buf.pktbuf); - packet->payload = original_packet_payload; - packet->payload_packet_len = original_payload_packet_len; - flow->kerberos_buf.pktbuf = NULL; - } - - return; + if (ndpi_reassemble_in_progress(&flow->reassemble) != 0) + { + ndpi_reassemble_swap_payload(packet, &flow->reassemble, &original_packet_payload, + &original_payload_packet_len); + // XXX: Free reassemble data? + } + return; } else if(msg_type == 0x0d) /* TGS-REP */ { NDPI_LOG_DBG(ndpi_struct, "[Kerberos] Processing TGS-REP\n"); @@ -659,9 +639,8 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, } return; - } - } } + } } else { #ifdef KERBEROS_DEBUG printf("[Kerberos][s/dport: %u/%u] Skipping packet: too long [kerberos_len: %u]\n", @@ -679,18 +658,10 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, static int ndpi_search_kerberos_extra(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { - struct ndpi_packet_struct *packet = &ndpi_struct->packet; - #ifdef KERBEROS_DEBUG printf("[Kerberos] Extra function\n"); #endif - /* Unfortunately, generic "extra function" code doesn't honour protocol bitmask */ - /* TODO: handle that in ndpi_main.c for all the protocols */ - if(packet->payload_packet_len == 0 || - packet->tcp_retransmission) - return 1; - /* Possibly dissect the reply */ ndpi_search_kerberos(ndpi_struct, flow); diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c index aafeb3397..f93cb5f53 100644 --- a/src/lib/protocols/quic.c +++ b/src/lib/protocols/quic.c @@ -1007,72 +1007,6 @@ static uint8_t *decrypt_initial_packet(struct ndpi_detection_module_struct *ndpi return NULL; } -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) - buffer_bitmap[start_byte] |= (((1U << recv_len) - 1U) << start_bit); // fill from bit 'start_bit' until bit 'end_bit', both inclusive - else{ - u_int32_t i; - - for (i = start_byte + 1; i <= end_byte - 1; i++) - buffer_bitmap[i] = 0xff; // completely received byte - buffer_bitmap[start_byte] |= ~((1U << start_bit) - 1U); // fill from bit 'start_bit' until bit 7, both inclusive - buffer_bitmap[end_byte] |= (1U << (end_bit + 1U)) - 1U; // fill from bit 0 until bit 'end_bit', both inclusive - } -} - -static int is_reasm_buf_complete(const u_int8_t *buffer_bitmap, - const u_int32_t buffer_len) -{ - const u_int32_t complete_bytes = buffer_len / 8; - const u_int32_t remaining_bits = buffer_len % 8; - u_int32_t i; - - for(i = 0; i < complete_bytes; i++) - if (buffer_bitmap[i] != 0xff) - return 0; - - if (remaining_bits && buffer_bitmap[complete_bytes] != (1U << (remaining_bits)) - 1) - return 0; - - return 1; -} - -static int __reassemble(struct ndpi_flow_struct *flow, const u_int8_t *frag, - uint64_t frag_len, uint64_t frag_offset, - const u_int8_t **buf, u_int64_t *buf_len) -{ - const uint64_t max_quic_reasm_buffer_len = 4096; /* Let's say a couple of full-MTU packets... Must be multiple of 8*/ - const uint64_t quic_reasm_buffer_bitmap_len = max_quic_reasm_buffer_len / 8; - const uint64_t last_pos = frag_offset + frag_len; - - if(!flow->l4.udp.quic_reasm_buf) { - flow->l4.udp.quic_reasm_buf = (uint8_t *)ndpi_malloc(max_quic_reasm_buffer_len); - flow->l4.udp.quic_reasm_buf_bitmap = (uint8_t *)ndpi_calloc(quic_reasm_buffer_bitmap_len, sizeof(uint8_t)); - if(!flow->l4.udp.quic_reasm_buf || !flow->l4.udp.quic_reasm_buf_bitmap) - return -1; /* Memory error */ - flow->l4.udp.quic_reasm_buf_last_pos = 0; - } - if(last_pos > max_quic_reasm_buffer_len) - return -3; /* Buffer too small */ - - memcpy(&flow->l4.udp.quic_reasm_buf[frag_offset], frag, frag_len); - flow->l4.udp.quic_reasm_buf_last_pos = last_pos > flow->l4.udp.quic_reasm_buf_last_pos ? last_pos : flow->l4.udp.quic_reasm_buf_last_pos; - update_reasm_buf_bitmap(flow->l4.udp.quic_reasm_buf_bitmap, quic_reasm_buffer_bitmap_len, frag_offset, frag_len); - - *buf = flow->l4.udp.quic_reasm_buf; - *buf_len = flow->l4.udp.quic_reasm_buf_last_pos; - return 0; -} static int is_ch_complete(const u_int8_t *buf, uint64_t buf_len) { uint32_t msg_len; @@ -1087,17 +1021,16 @@ static int is_ch_complete(const u_int8_t *buf, uint64_t buf_len) } static int is_ch_reassembler_pending(struct ndpi_flow_struct *flow) { - return flow->l4.udp.quic_reasm_buf != NULL && - !(is_reasm_buf_complete(flow->l4.udp.quic_reasm_buf_bitmap, flow->l4.udp.quic_reasm_buf_last_pos) - && is_ch_complete(flow->l4.udp.quic_reasm_buf, flow->l4.udp.quic_reasm_buf_last_pos)); + return flow->reassemble.buf != NULL && + !(ndpi_reassemble_is_complete(&flow->reassemble) + && is_ch_complete(flow->reassemble.buf, flow->reassemble.buf_last_pos)); } static const uint8_t *get_reassembled_crypto_data(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - const u_int8_t *frag, - uint64_t frag_offset, uint64_t frag_len, - uint64_t *crypto_data_len) + struct ndpi_flow_struct *flow, + const u_int8_t *frag, + uint64_t frag_offset, uint64_t frag_len, + uint64_t *crypto_data_len) { - const u_int8_t *crypto_data; int rc; NDPI_LOG_DBG2(ndpi_struct, "frag %d/%d\n", frag_offset, frag_len); @@ -1110,18 +1043,23 @@ static const uint8_t *get_reassembled_crypto_data(struct ndpi_detection_module_s return frag; } - rc = __reassemble(flow, frag, frag_len, frag_offset, - &crypto_data, crypto_data_len); + if (frag_offset == 0 && frag_len >= 4) + { + ndpi_reassemble_set_buffer_len(&flow->reassemble, (frag[1] << 16) + (frag[2] << 8) + frag[3] + 4); + } + rc = ndpi_reassemble(&flow->reassemble, frag, frag_len, frag_offset); if(rc == 0) { - if(is_reasm_buf_complete(flow->l4.udp.quic_reasm_buf_bitmap, *crypto_data_len) && - is_ch_complete(crypto_data, *crypto_data_len)) { + if(ndpi_reassemble_is_complete(&flow->reassemble) && + is_ch_complete(flow->reassemble.buf, flow->reassemble.buf_last_pos)) { NDPI_LOG_DBG2(ndpi_struct, "Reassembler completed!\n"); - return crypto_data; + *crypto_data_len = flow->reassemble.buf_last_pos; + return flow->reassemble.buf; } NDPI_LOG_DBG2(ndpi_struct, "CH not yet completed\n"); } else { NDPI_LOG_DBG(ndpi_struct, "Reassembler error: %d\n", rc); } + return NULL; } diff --git a/tests/unit/unit.c b/tests/unit/unit.c index 13de97a1f..152777be7 100644 --- a/tests/unit/unit.c +++ b/tests/unit/unit.c @@ -317,6 +317,76 @@ int serializeProtoUnitTest(void) /* *********************************************** */ +static int reassmbleUnitTest() +{ + u_int8_t const * org_payload = NULL; + u_int16_t org_payload_len; + char const * const packets[] = { "There", " ", "is", " ", "some", " ", "payload", " ", "on", " ", "the", " ", "wire!" }; + struct ndpi_packet_struct packet = {}; + struct ndpi_reasm reasm = {}; + size_t i, j; + + assert(ndpi_reassemble_in_progress(&reasm) == 0); + assert(ndpi_reassemble_is_complete(&reasm) != 0); + for (i = 0; i < NDPI_ARRAY_LENGTH(packets); ++i) + { + ndpi_reassemble_set_buffer_len(&reasm, reasm.buf_req + strlen(packets[i])); + assert(ndpi_reassemble_is_complete(&reasm) == 0); + assert(ndpi_reassemble_in_progress(&reasm) != 0); + + packet.payload = (u_int8_t const *)packets[i]; + packet.payload_packet_len = strlen(packets[i]); + + assert(ndpi_reassemble_payload(&reasm, &packet) == 0); + } + assert(ndpi_reassemble_in_progress(&reasm) == 0); + assert(ndpi_reassemble_is_complete(&reasm) != 0); + + ndpi_reassemble_swap_payload(&packet, &reasm, &org_payload, &org_payload_len); + + j = 0; + for (i = 0; i < NDPI_ARRAY_LENGTH(packets); ++i) + { + assert(strncmp((char *)&packet.payload[j], packets[i], strlen(packets[i])) == 0); + j += strlen(packets[i]); + } + assert(j == packet.payload_packet_len); + + ndpi_reassemble_swap_payload(&packet, &reasm, &org_payload, &org_payload_len); + + free(reasm.buf); + free(reasm.buf_bitmap); + memset(&reasm, 0, sizeof(reasm)); + + assert(ndpi_reassemble_in_progress(&reasm) == 0); + assert(ndpi_reassemble_is_complete(&reasm) != 0); + j = 0; + for (i = 0; i < NDPI_ARRAY_LENGTH(packets); ++i) + { + j += strlen(packets[i]); + } + ndpi_reassemble_set_buffer_len(&reasm, j); + assert(ndpi_reassemble_is_complete(&reasm) == 0); + for (i = NDPI_ARRAY_LENGTH(packets); i > 0; --i) + { + assert(ndpi_reassemble_is_complete(&reasm) == 0); + assert(ndpi_reassemble_in_progress(&reasm) != 0); + + j -= strlen(packets[i - 1]); + assert(ndpi_reassemble(&reasm, (u_int8_t const *)packets[i - 1], strlen(packets[i - 1]), j) == 0); + } + + free(reasm.buf); + free(reasm.buf_bitmap); + memset(&reasm, 0, sizeof(reasm)); + + printf("%30s OK\n", __FUNCTION__); + + return 0; +} + +/* *********************************************** */ + int main(int argc, char **argv) { #ifndef WIN32 int c; @@ -355,6 +425,7 @@ int main(int argc, char **argv) { /* Tests */ if (serializerUnitTest() != 0) return -1; if (serializeProtoUnitTest() != 0) return -1; + if (reassmbleUnitTest() != 0) return -1; return 0; } |