From 0e9be0d902b44894ed747cabb82ea2120f2e4b45 Mon Sep 17 00:00:00 2001 From: Mosder Date: Fri, 10 Jul 2026 22:50:12 +0200 Subject: feat: added functionallity for TCP stream reassembly --- analyzer/utils/tcp.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 analyzer/utils/tcp.h (limited to 'analyzer/utils/tcp.h') diff --git a/analyzer/utils/tcp.h b/analyzer/utils/tcp.h new file mode 100644 index 0000000..37ab4bc --- /dev/null +++ b/analyzer/utils/tcp.h @@ -0,0 +1,68 @@ +// utils/tcp.h +// functions for handling TCP streams/segments + +#include + +#include "structures/heap.h" + +typedef unsigned char byte_t; + +// struct to persistently store TCP segments +// payload field is malloced and needs to be freed +#ifndef TCP_SEGMENT_DEFINED +#define TCP_SEGMENT_DEFINED +typedef struct { + byte_t *payload; + size_t len; + uint32_t seq; +} TCPSegment; +#endif + +// get TCP segment from captured packet +// params: +// - packet - captured packet +// - packet_data - metadata about packet +// returns: +// TCPSegment from packet, payload is NULL and len is -1 if the received packet was incorrect +extern TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthdr *packet_data); + +// struct that stores all the information about stream +#ifndef TCP_STREAM_DEFINED +#define TCP_STREAM_DEFINED +typedef struct { + byte_t *data; // bytes in the stream + size_t len; // length of the stream + size_t capacity; // capacity of the data buffer + uint32_t seq; // TCP sequence number of the first byte in the stream + Heap *pending; // min heap of segments yet to be added to stream (sorted by TCP sequence number) +} TCPStream; +#endif + +#define INIT_STREAM_CAPACITY 256 + +// initialize new stream +// returns: +// newly created TCPStream structure with initial values +extern TCPStream new_stream(); + +// cleanup memory allocations within stream +// params: +// stream - stream to destroy +extern void destroy_stream(TCPStream stream); + +// remove parsed data from the stream +// params: +// - stream - pointer to the stream to remove a part of +// - parsed_len - count of n first bytes of the stream that were parsed +extern void remove_parsed_data(TCPStream *stream, size_t parsed_len); + +// max difference between expected TCP seq and received TCP seq to still accept it into pending +#define MAX_SEQ_OFFSET 100000 + +// add TCP segment to stream, pending or completely discard it +// params: +// - stream - pointer to the current stream +// - segment - segment to handle +// returns: +// 1 if the segment was added to the stream, 0 if it was discarded or saved to pending +extern int handle_segment(TCPStream *stream, TCPSegment segment); -- cgit v1.2.3 From c7277e7654c0d8d0e7a4665373c0762c6e8a038d Mon Sep 17 00:00:00 2001 From: Mosder Date: Tue, 14 Jul 2026 13:40:17 +0200 Subject: fix: fixed not handling of different connections and bug regarding TCP SYN packet --- analyzer/analyzer.c | 4 ++-- analyzer/utils/tcp.c | 23 ++++++++++++++++------- analyzer/utils/tcp.h | 10 ++++++---- 3 files changed, 24 insertions(+), 13 deletions(-) (limited to 'analyzer/utils/tcp.h') diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c index 03ecd2a..7def1e6 100644 --- a/analyzer/analyzer.c +++ b/analyzer/analyzer.c @@ -15,8 +15,8 @@ void analyzer_loop(TCPStream *stream, pcap_t *pcap_handle, void (*parsed_data_ha // get new segment TCPSegment segment = get_segment_from_packet(packet, packet_data); - // handle the new segment - if (handle_segment(stream, segment)) { + // handle the new segment if it's correct one and has data in it (ignore SYN) + if (segment.len > 0 && handle_segment(stream, segment)) { // if it was added to the stream - parse it size_t parsed_len; size_t n_parsed_data; diff --git a/analyzer/utils/tcp.c b/analyzer/utils/tcp.c index ab5303e..b925ecf 100644 --- a/analyzer/utils/tcp.c +++ b/analyzer/utils/tcp.c @@ -12,8 +12,9 @@ TCPSegment new_segment() { TCPSegment segment; segment.payload = NULL; - segment.len = -1; + segment.len = 0; segment.seq = 0; + segment.port = 0; return segment; } @@ -53,8 +54,9 @@ TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthd const struct tcphdr *tcp_header = (const struct tcphdr *)(packet + eth_header_len + ip_header_len); int tcp_header_len = tcp_header->th_off * 4; - // get TCP sequence number + // get TCP sequence number and destination port segment.seq = ntohl(tcp_header->seq); + segment.port = ntohs(tcp_header->th_dport); // get payload int total_header_len = eth_header_len + ip_header_len + tcp_header_len; @@ -66,11 +68,12 @@ TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthd TCPStream new_stream() { TCPStream stream; - stream.data = NULL; // NULL to differentiate between first and other segments + stream.data = malloc(INIT_STREAM_CAPACITY); stream.len = 0; stream.capacity = INIT_STREAM_CAPACITY; stream.seq = 0; - stream.pending = heap_new(sizeof(TCPSegment), segments_compare, segment_cleanup); + stream.port = 0; + stream.pending = NULL; return stream; } @@ -142,10 +145,16 @@ void add_pending_segments(TCPStream *stream) { } int handle_segment(TCPStream *stream, TCPSegment segment) { - // add the segment if it's the first one - if (stream->data == NULL) { - stream->data = malloc(stream->capacity); + // add the segment if port is different (new connection) + if (stream->port != segment.port) { + // create new heap for new pending segments + heap_free(stream->pending); + stream->pending = heap_new(sizeof(TCPSegment), segments_compare, segment_cleanup); + + stream->len = 0; stream->seq = segment.seq; + stream->port = segment.port; + add_segment(stream, segment, 0); free(segment.payload); return 1; diff --git a/analyzer/utils/tcp.h b/analyzer/utils/tcp.h index 37ab4bc..9c6a949 100644 --- a/analyzer/utils/tcp.h +++ b/analyzer/utils/tcp.h @@ -12,9 +12,10 @@ typedef unsigned char byte_t; #ifndef TCP_SEGMENT_DEFINED #define TCP_SEGMENT_DEFINED typedef struct { - byte_t *payload; - size_t len; - uint32_t seq; + byte_t *payload; // payload in the segment + size_t len; // length of the payload + uint32_t seq; // TCP sequence number of the segment + uint16_t port; // destination (client) port of connection the segment was received from } TCPSegment; #endif @@ -23,7 +24,7 @@ typedef struct { // - packet - captured packet // - packet_data - metadata about packet // returns: -// TCPSegment from packet, payload is NULL and len is -1 if the received packet was incorrect +// TCPSegment from packet, payload is NULL if the received packet was incorrect extern TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthdr *packet_data); // struct that stores all the information about stream @@ -34,6 +35,7 @@ typedef struct { size_t len; // length of the stream size_t capacity; // capacity of the data buffer uint32_t seq; // TCP sequence number of the first byte in the stream + uint16_t port; // destination (client) port of current analyzed connection Heap *pending; // min heap of segments yet to be added to stream (sorted by TCP sequence number) } TCPStream; #endif -- cgit v1.2.3 From c182f2f4f850589c23b2241e11dab143e1003ff2 Mon Sep 17 00:00:00 2001 From: Mosder Date: Mon, 20 Jul 2026 15:48:51 +0200 Subject: refactor: changed #ifndef guards, so that there is one per file --- analyzer/parser/fight_results.h | 17 +++++------------ analyzer/parser/parser_defs.h | 15 ++++----------- analyzer/structures/heap.h | 8 +++++--- analyzer/utils/tcp.h | 11 +++++------ 4 files changed, 19 insertions(+), 32 deletions(-) (limited to 'analyzer/utils/tcp.h') diff --git a/analyzer/parser/fight_results.h b/analyzer/parser/fight_results.h index ca45348..3aadf09 100644 --- a/analyzer/parser/fight_results.h +++ b/analyzer/parser/fight_results.h @@ -4,6 +4,9 @@ #include "parser/parser_defs.h" #include "utils/tcp.h" +#ifndef FIGHT_RESULTS_H +#define FIGHT_RESULTS_H + // Payload structure: // FIGHT_RESULTS_START EntityResults (SEPARATOR_ENTITY EntityResults)* FIGHT_RESULTS_END // @@ -92,8 +95,6 @@ &entity_results.saturation \ } -#ifndef ENTITY_RESULTS_DEFINED -#define ENTITY_RESULTS_DEFINED typedef struct { int team; // friend or enemy char *name; @@ -131,7 +132,6 @@ typedef struct { char *field34; char *saturation; } EntityResults; -#endif // items/gear/drifs fields parsing info #define INIT_ITEMS_CAPACITY 8 @@ -143,8 +143,6 @@ typedef struct { #define TEAM_ENEMY 2 // fight results data for friendly -#ifndef FRIENDLY_RESULTS_DEFINED -#define FRIENDLY_RESULTS_DEFINED typedef struct { char *name; int exp; @@ -157,29 +155,24 @@ typedef struct { char *saturation_type; int saturation; } FriendlyResults; -#endif // fight results data for enemy -#ifndef ENEMY_RESULTS_DEFINED -#define ENEMY_RESULTS_DEFINED typedef struct { char *name; int level; } EnemyResults; -#endif #define MAX_ENTITIES_PER_SIDE 8 // entire fight resutls -#ifndef FIGHT_RESULTS_DEFINED -#define FIGHT_RESULTS_DEFINED typedef struct { size_t num_friendly; FriendlyResults friendly_results[MAX_ENTITIES_PER_SIDE]; size_t num_enemy; EnemyResults enemy_results[MAX_ENTITIES_PER_SIDE]; } FightResults; -#endif extern find_function_t find_fight_results; extern parse_function_t parse_fight_results; + +#endif diff --git a/analyzer/parser/parser_defs.h b/analyzer/parser/parser_defs.h index 6af6059..aa39a4c 100644 --- a/analyzer/parser/parser_defs.h +++ b/analyzer/parser/parser_defs.h @@ -3,18 +3,13 @@ #include "utils/tcp.h" -#ifndef TYPE_ENUM_DEFINED -#define TYPE_ENUM_DEFINED +#ifndef PARSER_DEFS_H +#define PARSER_DEFS_H + typedef enum { INT, FLOAT, DOUBLE, STRING } TypeEnum; -#endif -#ifndef RESULTS_ENUM_DEFINED -#define RESULTS_ENUM_DEFINED typedef enum { TYPE_FIGHT_RESULTS } ResultsEnum; -#endif -#ifndef PARSED_DATA_DEFINED -#define PARSED_DATA_DEFINED // "generic" type for parsed data typedef struct { ResultsEnum data_type; // type of data represented by an enum @@ -22,7 +17,6 @@ typedef struct { void (*data_cleanup)(void *data); // function to cleanup internal allocations inside data // if no internal allocations - this should be NULL } ParsedData; -#endif // find the first results data of specific type in stream // params: @@ -42,10 +36,9 @@ typedef byte_t *find_function_t(TCPStream *stream, int offset, int *length); typedef ParsedData parse_function_t(byte_t *data, size_t length); // struct for holding the find and parse function for every result type -#ifndef FIND_PARSE_FUNCTIONS_DEFINED -#define FIND_PARSE_FUNCTIONS_DEFINED typedef struct { find_function_t *find_fn; parse_function_t *parse_fn; } FindParseFunctions; + #endif diff --git a/analyzer/structures/heap.h b/analyzer/structures/heap.h index 8a23164..1ae72c0 100644 --- a/analyzer/structures/heap.h +++ b/analyzer/structures/heap.h @@ -3,11 +3,12 @@ #include +#ifndef HEAP_H +#define HEAP_H + #define INIT_HEAP_DEPTH 7 #define INIT_HEAP_CAPACITY (1 << INIT_HEAP_DEPTH) - 1 -#ifndef HEAP_DEFINED -#define HEAP_DEFINED typedef struct { void **data; size_t n_elements; @@ -16,7 +17,6 @@ typedef struct { int (*compare)(void *element1, void *element2); void (*element_cleanup)(void *element); } Heap; -#endif // create a new heap // params: @@ -56,3 +56,5 @@ extern void heap_top_remove(Heap *heap); // free the heap // - heap - heap to free extern void heap_free(Heap *heap); + +#endif diff --git a/analyzer/utils/tcp.h b/analyzer/utils/tcp.h index 9c6a949..13cbb15 100644 --- a/analyzer/utils/tcp.h +++ b/analyzer/utils/tcp.h @@ -5,19 +5,19 @@ #include "structures/heap.h" +#ifndef TCP_H +#define TCP_H + typedef unsigned char byte_t; // struct to persistently store TCP segments // payload field is malloced and needs to be freed -#ifndef TCP_SEGMENT_DEFINED -#define TCP_SEGMENT_DEFINED typedef struct { byte_t *payload; // payload in the segment size_t len; // length of the payload uint32_t seq; // TCP sequence number of the segment uint16_t port; // destination (client) port of connection the segment was received from } TCPSegment; -#endif // get TCP segment from captured packet // params: @@ -28,8 +28,6 @@ typedef struct { extern TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthdr *packet_data); // struct that stores all the information about stream -#ifndef TCP_STREAM_DEFINED -#define TCP_STREAM_DEFINED typedef struct { byte_t *data; // bytes in the stream size_t len; // length of the stream @@ -38,7 +36,6 @@ typedef struct { uint16_t port; // destination (client) port of current analyzed connection Heap *pending; // min heap of segments yet to be added to stream (sorted by TCP sequence number) } TCPStream; -#endif #define INIT_STREAM_CAPACITY 256 @@ -68,3 +65,5 @@ extern void remove_parsed_data(TCPStream *stream, size_t parsed_len); // returns: // 1 if the segment was added to the stream, 0 if it was discarded or saved to pending extern int handle_segment(TCPStream *stream, TCPSegment segment); + +#endif -- cgit v1.2.3