From 95763527e73c0d06d3887e4a2da22f627f13bfaa Mon Sep 17 00:00:00 2001 From: Mosder Date: Tue, 28 Jul 2026 11:14:01 +0200 Subject: feat: added support for streams from both server and client (uhm, actually, there's only one stream, since TCP streams are bidirectional, blah, blah, blah...) --- analyzer/analyzer.c | 22 ++++++++++++++++------ analyzer/parser/find_parse_functions.h | 2 +- analyzer/parser/parser.c | 4 ++++ analyzer/parser/parser_defs.h | 1 + analyzer/utils/tcp.c | 11 ++++++++--- analyzer/utils/tcp.h | 28 +++++++++++++++++----------- 6 files changed, 47 insertions(+), 21 deletions(-) diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c index aa4a645..088e6d4 100644 --- a/analyzer/analyzer.c +++ b/analyzer/analyzer.c @@ -7,9 +7,13 @@ #include "render.h" #include "utils/tcp.h" -// loop through packets received from pcap_handle and analyze the TCP stream +// loop through packets received from pcap_handle and analyze the TCP streams void analyzer_loop( - TCPStream *stream, pcap_t *pcap_handle, void *state, void (*parsed_data_handler)(void *state, ParsedData *parsed_data, size_t n_parsed_data) + TCPStream *server_stream, + TCPStream *client_stream, + pcap_t *pcap_handle, + void *state, + void (*parsed_data_handler)(void *state, ParsedData *parsed_data, size_t n_parsed_data) ) { // read packets from handle struct pcap_pkthdr *packet_data; @@ -19,7 +23,11 @@ void analyzer_loop( TCPSegment segment = get_segment_from_packet(packet, packet_data); // 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 (segment.len <= 0) + continue; + + TCPStream *stream = segment.src == SERVER ? server_stream : client_stream; + if (handle_segment(stream, segment)) { // if it was added to the stream - parse it size_t parsed_len; size_t n_parsed_data; @@ -64,9 +72,11 @@ void analyze_file(char *path) { } // analyze the file - TCPStream stream = new_stream(); + TCPStream server_stream = new_stream(SERVER); + TCPStream client_stream = new_stream(CLIENT); int state = 0; - analyzer_loop(&stream, handle, &state, file_parsed_data_handler); - destroy_stream(stream); + analyzer_loop(&server_stream, &client_stream, handle, &state, file_parsed_data_handler); + destroy_stream(server_stream); + destroy_stream(client_stream); pcap_close(handle); } diff --git a/analyzer/parser/find_parse_functions.h b/analyzer/parser/find_parse_functions.h index e2c2acb..ffe6ef0 100644 --- a/analyzer/parser/find_parse_functions.h +++ b/analyzer/parser/find_parse_functions.h @@ -3,4 +3,4 @@ #include "parser/fight_results/fight_results.h" -FindParseFunctions all_find_parse_functions[] = {{find_fight_results, parse_fight_results}}; +FindParseFunctions all_find_parse_functions[] = {{find_fight_results, parse_fight_results, SERVER}}; diff --git a/analyzer/parser/parser.c b/analyzer/parser/parser.c index d00cd97..07980e5 100644 --- a/analyzer/parser/parser.c +++ b/analyzer/parser/parser.c @@ -9,6 +9,10 @@ byte_t *find_earliest_data(TCPStream *stream, int stream_offset, int *earliest_length, parse_function_t **earliest_parse_fun) { byte_t *earliest_data = NULL; for (size_t i = 0; i < ARR_LEN(all_find_parse_functions); i++) { + // ignore if not correct stream + if (stream->src != all_find_parse_functions[i].stream_src) + continue; + int length; byte_t *data = all_find_parse_functions[i].find_fn(stream, stream_offset, &length); // if it's the first found or earlier than earliest - save it diff --git a/analyzer/parser/parser_defs.h b/analyzer/parser/parser_defs.h index 75b0366..c64e138 100644 --- a/analyzer/parser/parser_defs.h +++ b/analyzer/parser/parser_defs.h @@ -37,6 +37,7 @@ typedef ParsedData parse_function_t(byte_t *data, size_t length); typedef struct { find_function_t *find_fn; parse_function_t *parse_fn; + ConnectionSource stream_src; // which stream to look for the data } FindParseFunctions; #endif diff --git a/analyzer/utils/tcp.c b/analyzer/utils/tcp.c index 6309e64..7a79c67 100644 --- a/analyzer/utils/tcp.c +++ b/analyzer/utils/tcp.c @@ -6,6 +6,7 @@ #include #include +#include "headers/server.h" #include "utils/memory.h" #include "utils/tcp_seq_math.h" @@ -50,6 +51,9 @@ TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthd const struct ip *ip_header = (const struct ip *)(packet + eth_header_len); int ip_header_len = ip_header->ip_hl * 4; + // get source + segment.src = ip_header->ip_src.s_addr == inet_addr(SERVER_IP) ? SERVER : CLIENT; + // check if it's TCP if (ip_header->ip_p != IPPROTO_TCP) return segment; @@ -58,9 +62,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 and destination port + // get TCP sequence number and client port segment.seq = ntohl(tcp_header->seq); - segment.port = ntohs(tcp_header->th_dport); + segment.port = ntohs(segment.src == SERVER ? tcp_header->th_dport : tcp_header->th_sport); // get payload int total_header_len = eth_header_len + ip_header_len + tcp_header_len; @@ -70,7 +74,7 @@ TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthd return segment; } -TCPStream new_stream() { +TCPStream new_stream(ConnectionSource src) { // clang-format off TCPStream stream = { .data = safe_malloc(INIT_STREAM_CAPACITY), @@ -78,6 +82,7 @@ TCPStream new_stream() { .capacity = INIT_STREAM_CAPACITY, .seq = 0, .port = 0, + .src = src, .pending = NULL }; // clang-format on diff --git a/analyzer/utils/tcp.h b/analyzer/utils/tcp.h index 13cbb15..382c585 100644 --- a/analyzer/utils/tcp.h +++ b/analyzer/utils/tcp.h @@ -10,13 +10,16 @@ typedef unsigned char byte_t; +typedef enum { SERVER, CLIENT } ConnectionSource; + // struct to persistently store TCP segments // payload field is malloced and needs to be freed 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 + 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; // client port of connection the segment was received from + ConnectionSource src; // segment's source } TCPSegment; // get TCP segment from captured packet @@ -29,20 +32,23 @@ extern TCPSegment get_segment_from_packet(const byte_t *packet, const struct pca // struct that stores all the information about stream 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 - 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) + 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 + uint16_t port; // client port of currently analyzed connection + ConnectionSource src; // stream's source + Heap *pending; // min heap of segments yet to be added to stream (sorted by TCP sequence number) } TCPStream; #define INIT_STREAM_CAPACITY 256 // initialize new stream +// params: +// - src - source of the stream // returns: // newly created TCPStream structure with initial values -extern TCPStream new_stream(); +extern TCPStream new_stream(ConnectionSource src); // cleanup memory allocations within stream // params: -- cgit v1.2.3