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.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 analyzer/utils/tcp.c (limited to 'analyzer/utils/tcp.c') diff --git a/analyzer/utils/tcp.c b/analyzer/utils/tcp.c new file mode 100644 index 0000000..56df842 --- /dev/null +++ b/analyzer/utils/tcp.c @@ -0,0 +1,172 @@ +#include "tcp.h" + +#include +#include +#include +#include +#include + +#include "tcp_seq_math.h" + +// initalize default TCP segment +TCPSegment new_segment() { + TCPSegment segment; + segment.payload = NULL; + segment.len = -1; + segment.seq = 0; + return segment; +} + +// segments compare function to use with heap +int segments_compare(void *segment1, void *segment2) { + TCPSegment *seg1 = segment1; + TCPSegment *seg2 = segment2; + return seq_before(seg1->seq, seg2->seq); +} + +// segment cleanup function to use with heap +void segment_cleanup(void *segment) { + TCPSegment *seg = segment; + free(seg->payload); +} + +TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthdr *packet_data) { + TCPSegment segment = new_segment(); + + // get Ethernet header + const struct ether_header *eth_header = (const struct ether_header *)packet; + int eth_header_len = sizeof(struct ether_header); + + // check if it's IP + if (ntohs(eth_header->ether_type) != ETHERTYPE_IP) + return segment; + + // get IP header + const struct ip *ip_header = (const struct ip *)(packet + eth_header_len); + int ip_header_len = ip_header->ip_hl * 4; + + // check if it's TCP + if (ip_header->ip_p != IPPROTO_TCP) + return segment; + + // get TCP header + 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 + segment.seq = ntohl(tcp_header->seq); + + // get payload + int total_header_len = eth_header_len + ip_header_len + tcp_header_len; + segment.len = packet_data->caplen - total_header_len; + segment.payload = malloc(segment.len); + memcpy(segment.payload, packet + total_header_len, segment.len); + return segment; +} + +TCPStream new_stream() { + TCPStream stream; + stream.data = NULL; // NULL to differentiate between first and other segments + stream.len = 0; + stream.capacity = INIT_STREAM_CAPACITY; + stream.seq = 0; + stream.pending = heap_new(sizeof(TCPSegment), segments_compare, segment_cleanup); + return stream; +} + +void destroy_stream(TCPStream stream) { + free(stream.data); + heap_free(stream.pending); +} + +void remove_parsed_data(TCPStream *stream, size_t parsed_len) { + memmove(stream->data, stream->data + parsed_len, stream->len - parsed_len); + stream->len -= parsed_len; + stream->seq += parsed_len; +} + +// get the index of the first relevant byte in segment (its tcp sequence number is the one stream is expecting) +// return the index of the first relevant byte in payload or -1 if segment isn't directly connected to stream +int get_first_relevant_byte_index(TCPStream stream, TCPSegment segment) { + // expected tcp sequence numbers for stream and segment + uint32_t stream_expected = stream.seq + stream.len; + uint32_t segment_expected = segment.seq + segment.len; + if (seq_in_range_ie(stream_expected, segment.seq, segment_expected)) + return stream_expected - segment.seq; + return -1; +} + +// check if the segment is in acceptable range to the stream +int in_acceptable_range(TCPStream stream, TCPSegment segment) { + // expected tcp sequence number for stream and max acceptable sequence number for segment + uint32_t stream_expected = stream.seq + stream.len; + uint32_t max_acceptable_seq = stream_expected + MAX_SEQ_OFFSET; + return seq_in_range_ei(segment.seq, stream_expected, max_acceptable_seq); +} + +// expand stream capacity exponentially to fit new_len +void expand_stream_capacity(TCPStream *stream, size_t new_len) { + while (stream->capacity < new_len) + stream->capacity <<= 1; + stream->data = realloc(stream->data, stream->capacity); +} + +// add segment directly to stream +void add_segment(TCPStream *stream, TCPSegment segment, size_t data_start) { + size_t new_stream_len = stream->len + segment.len - data_start; + if (new_stream_len > stream->capacity) + expand_stream_capacity(stream, new_stream_len); + memcpy(stream->data + stream->len, segment.payload + data_start, segment.len - data_start); + stream->len = new_stream_len; +} + +// add pending segments to the stream +void add_pending_segments(TCPStream *stream) { + int top_changed = 1; + TCPSegment *top; + while (top_changed && (top = heap_top_get(stream->pending))) { + top_changed = 0; + + // add pending segment it it became directly connected + int data_start = get_first_relevant_byte_index(*stream, *top); + if (data_start != -1) { + add_segment(stream, *top, data_start); + top_changed = 1; + } + + // remove top if it was just added or no longer is in acceptable range (e.g. was contained within another one pending) + if (top_changed || !in_acceptable_range(*stream, *top)) { + heap_top_remove(stream->pending); + } + } +} + +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); + stream->seq = segment.seq; + add_segment(stream, segment, 0); + free(segment.payload); + return 1; + } + + // add segment directly to the stream if it's directly connected + int data_start = get_first_relevant_byte_index(*stream, segment); + if (data_start != -1) { + add_segment(stream, segment, data_start); + free(segment.payload); + add_pending_segments(stream); + return 1; + } + + // add to pending if segment is in acceptable range: + if (in_acceptable_range(*stream, segment)) { + heap_insert(stream->pending, &segment); + return 0; + } + + // if neither, discard entirely + free(segment.payload); + return 0; +} -- cgit v1.2.3 From 106e1f7a579a66c46cb68356f585917fe7883310 Mon Sep 17 00:00:00 2001 From: Mosder Date: Tue, 14 Jul 2026 11:08:32 +0200 Subject: refactor: generalized Makefile by adding CC and CFLAGS variables. Changed from realtive to absolute paths for includes --- Makefile | 31 ++++----- analyzer/parser/fight_results.c | 2 +- analyzer/parser/fight_results.h | 4 +- analyzer/parser/find_parse_functions.h | 2 +- analyzer/parser/parser.c | 4 +- analyzer/parser/parser.h | 6 +- analyzer/parser/parser_defs.h | 2 +- analyzer/structures/hashmap.c | 112 +++++++++++++++++++++++++++++++++ analyzer/structures/hashmap.h | 81 ++++++++++++++++++++++++ analyzer/structures/heap.c | 109 ++++++++++++++++++++++++++++++++ analyzer/structures/heap.h | 58 +++++++++++++++++ analyzer/utils/fs.c | 2 +- analyzer/utils/structures/hashmap.c | 108 ------------------------------- analyzer/utils/structures/hashmap.h | 77 ----------------------- analyzer/utils/structures/heap.c | 109 -------------------------------- analyzer/utils/structures/heap.h | 58 ----------------- analyzer/utils/tcp.c | 4 +- analyzer/utils/tcp_seq_math.c | 2 +- analyzer/utils/time.c | 2 +- 19 files changed, 392 insertions(+), 381 deletions(-) create mode 100644 analyzer/structures/hashmap.c create mode 100644 analyzer/structures/hashmap.h create mode 100644 analyzer/structures/heap.c create mode 100644 analyzer/structures/heap.h delete mode 100644 analyzer/utils/structures/hashmap.c delete mode 100644 analyzer/utils/structures/hashmap.h delete mode 100644 analyzer/utils/structures/heap.c delete mode 100644 analyzer/utils/structures/heap.h (limited to 'analyzer/utils/tcp.c') diff --git a/Makefile b/Makefile index e5a9c54..2455ece 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,34 @@ +CC=gcc +CFLAGS=-iquote ./analyzer + global: compile sudo mv branal /usr/bin local: compile mv branal ${HOME}/.local/bin -compile: utils capture analyzer parser - gcc *.o main.c -lpcap -o branal +compile: structures utils capture analyzer parser + $(CC) $(CFLAGS) -lpcap *.o main.c -o branal rm *.o -utils: structures - gcc -c analyzer/utils/fs.c - gcc -c analyzer/utils/time.c - gcc -c analyzer/utils/tcp.c - gcc -c analyzer/utils/tcp_seq_math.c - structures: - gcc -c analyzer/utils/structures/hashmap.c - gcc -c analyzer/utils/structures/heap.c + $(CC) $(CFLAGS) -c analyzer/structures/hashmap.c + $(CC) $(CFLAGS) -c analyzer/structures/heap.c + +utils: + $(CC) $(CFLAGS) -c analyzer/utils/fs.c + $(CC) $(CFLAGS) -c analyzer/utils/time.c + $(CC) $(CFLAGS) -c analyzer/utils/tcp.c + $(CC) $(CFLAGS) -c analyzer/utils/tcp_seq_math.c capture: - gcc -c analyzer/capture.c + $(CC) $(CFLAGS) -c analyzer/capture.c analyzer: - gcc -c analyzer/analyzer.c + $(CC) $(CFLAGS) -c analyzer/analyzer.c parser: - gcc -c analyzer/parser/parser.c - gcc -c analyzer/parser/fight_results.c + $(CC) $(CFLAGS) -c analyzer/parser/parser.c + $(CC) $(CFLAGS) -c analyzer/parser/fight_results.c .PHONY: analyzer diff --git a/analyzer/parser/fight_results.c b/analyzer/parser/fight_results.c index 4fbb0f8..65e72ea 100644 --- a/analyzer/parser/fight_results.c +++ b/analyzer/parser/fight_results.c @@ -1,4 +1,4 @@ -#include "fight_results.h" +#include "parser/fight_results.h" #include #include diff --git a/analyzer/parser/fight_results.h b/analyzer/parser/fight_results.h index 4e1ea60..de7f525 100644 --- a/analyzer/parser/fight_results.h +++ b/analyzer/parser/fight_results.h @@ -1,8 +1,8 @@ // parser/fight_results.h // utilities for parsing the fight results data -#include "../utils/tcp.h" -#include "parser_defs.h" +#include "parser/parser_defs.h" +#include "utils/tcp.h" // Payload structure: // FIGHT_RESULTS_START EntityResults (SEPARATOR_ENTITY EntityResults)* FIGHT_RESULTS_END diff --git a/analyzer/parser/find_parse_functions.h b/analyzer/parser/find_parse_functions.h index 4e53274..dd7579e 100644 --- a/analyzer/parser/find_parse_functions.h +++ b/analyzer/parser/find_parse_functions.h @@ -1,7 +1,7 @@ // parser/find_parse_functions.h // array of find and parse functions for every result type -#include "fight_results.h" +#include "parser/fight_results.h" #define RESULT_TYPE_COUNT 1 diff --git a/analyzer/parser/parser.c b/analyzer/parser/parser.c index 246635c..3ef48b5 100644 --- a/analyzer/parser/parser.c +++ b/analyzer/parser/parser.c @@ -1,8 +1,8 @@ -#include "parser.h" +#include "parser/parser.h" #include -#include "find_parse_functions.h" +#include "parser/find_parse_functions.h" // expand parsed data exponentially to fit el_count elements ParsedData *expand_parsed_data(ParsedData *parsed_data, size_t *capacity, size_t el_count) { diff --git a/analyzer/parser/parser.h b/analyzer/parser/parser.h index e2d5c5d..4b28aa7 100644 --- a/analyzer/parser/parser.h +++ b/analyzer/parser/parser.h @@ -1,9 +1,9 @@ // parser/parser.h // main parser file -#include "../utils/tcp.h" -#include "fight_results.h" -#include "parser_defs.h" +#include "parser/fight_results.h" +#include "parser/parser_defs.h" +#include "utils/tcp.h" #define INIT_PARSED_DATA_CAPACITY 4 diff --git a/analyzer/parser/parser_defs.h b/analyzer/parser/parser_defs.h index b76b7e6..6af6059 100644 --- a/analyzer/parser/parser_defs.h +++ b/analyzer/parser/parser_defs.h @@ -1,7 +1,7 @@ // parser/parser_defs.h // useful definitions for parser files -#include "../utils/tcp.h" +#include "utils/tcp.h" #ifndef TYPE_ENUM_DEFINED #define TYPE_ENUM_DEFINED diff --git a/analyzer/structures/hashmap.c b/analyzer/structures/hashmap.c new file mode 100644 index 0000000..ed2eb4b --- /dev/null +++ b/analyzer/structures/hashmap.c @@ -0,0 +1,112 @@ +#include "structures/hashmap.h" + +#include +#include + +HashMap *hashmap_new( + size_t key_size, + size_t value_size, + size_t (*hash)(void *key), + int (*compare)(void *key1, void *key2), + void (*key_cleanup)(void *key), + void (*value_cleanup)(void *key) +) { + HashMap *map = malloc(sizeof(HashMap)); + // initialize NULLs + memset(map->table, 0, sizeof(HashMapNode *) * HASHMAP_TABLE_SIZE); + map->key_size = key_size; + map->value_size = value_size; + map->hash = hash; + map->compare = compare; + map->key_cleanup = key_cleanup; + map->value_cleanup = value_cleanup; + return map; +} + +void hashmap_put(HashMap *map, void *key, void *value) { + size_t key_hash = map->hash(key); + HashMapNode *node = map->table[key_hash]; + + // check if it exists + while (node) { + // if it exists - update node + if (map->compare(key, node->key)) { + // ensure no hanging memory allocation + if (map->value_cleanup) { + map->value_cleanup(node); + } + memcpy(node->value, value, map->value_size); + return; + } + node = node->next; + } + + // if it doesn't exist - create new node + HashMapNode *new_node = malloc(sizeof(HashMapNode)); + new_node->key = malloc(map->key_size); + new_node->value = malloc(map->value_size); + memcpy(new_node->key, key, map->key_size); + memcpy(new_node->value, value, map->value_size); + + // put in front of the linked list + new_node->next = map->table[key_hash]; + map->table[key_hash] = new_node; +} + +void *hashmap_get(HashMap *map, void *key) { + size_t key_hash = map->hash(key); + HashMapNode *node = map->table[key_hash]; + + // check if it exists + while (node) { + // if it exists - return the value pointer + if (map->compare(key, node->key)) { + return node->value; + } + node = node->next; + } + + // if it doesn't exist - return NULL + return NULL; +} + +void free_node_without_next(HashMap *map, HashMapNode *node) { + if (map->key_cleanup) { + map->key_cleanup(node); + } + if (map->value_cleanup) { + map->value_cleanup(node); + } + free(node->key); + free(node->value); + free(node); +} + +void hashmap_delete(HashMap *map, void *key) { + size_t key_hash = map->hash(key); + HashMapNode **p_node = &map->table[key_hash]; + + // check if it exists + while (*p_node) { + // if it exists - delete it + if (map->compare(key, (*p_node)->key)) { + HashMapNode *next = (*p_node)->next; + free_node_without_next(map, *p_node); + *p_node = next; + return; + } + p_node = &(*p_node)->next; + } +} + +void hashmap_free(HashMap *map) { + for (size_t i = 0; i < HASHMAP_TABLE_SIZE; i++) { + HashMapNode *curr = map->table[i]; + while (curr) { + HashMapNode *next = curr->next; + free_node_without_next(map, curr); + curr = next; + } + } + free(map); +} diff --git a/analyzer/structures/hashmap.h b/analyzer/structures/hashmap.h new file mode 100644 index 0000000..528f24a --- /dev/null +++ b/analyzer/structures/hashmap.h @@ -0,0 +1,81 @@ +// structures/hashmap.h +// a simple implementation of hashmap using linked list + +#include + +#define HASHMAP_TABLE_SIZE 128 + +typedef struct HashMapNode { + void *key; + void *value; + struct HashMapNode *next; +} HashMapNode; + +typedef struct { + HashMapNode *table[HASHMAP_TABLE_SIZE]; + size_t key_size; + size_t value_size; + size_t (*hash)(void *key); + int (*compare)(void *key1, void *key2); + void (*key_cleanup)(void *key); + void (*value_cleanup)(void *value); +} HashMap; + +// create a new hash map +// params: +// - key_size - size of the key type +// - value_size - size of the value type +// - hash - function for hashing keys +// params: +// - key - pointer to the key to hash +// returns: +// hash of the key (size_t in [0; HASHMAP_TABLE_SIZE)) +// - compare - function for comparing keys +// params: +// - key1 - pointer to the first of the keys to compare +// - key2 - pointer to the second of the keys to compare +// returns: +// truthy if the keys are identical, falsy if they are different +// - key_cleanup - function for cleaning up any internal allocations inside node->key (not the key itself) +// if it has no heap allocations, this should be NULL +// params: +// - key - pointer to the key to cleanup +// - value_cleanup - function for cleaning up any internal allocations inside node->value (not the value itself) +// if it has no heap allocations, this should be NULL +// params: +// - value - pointer to the value to cleanup +// returns: +// pointer to the new hash map +extern HashMap *hashmap_new( + size_t key_size, + size_t value_size, + size_t (*hash)(void *key), + int (*compare)(void *key1, void *key2), + void (*key_cleanup)(void *key), + void (*value_cleanup)(void *value) +); + +// create/update an entry in a hash map +// params: +// - map - hash map to insert to +// - key - pointer to the key +// - value - pointer to the value +extern void hashmap_put(HashMap *map, void *key, void *value); + +// get the value of given key from a hash map +// params: +// - map - hash map to get from +// - key - pointer to the key of the value to get +// returns: +// pointer to the value of specified key or NULL if it doesn't exist +extern void *hashmap_get(HashMap *map, void *key); + +// delete an entry from a hash map +// params: +// - map - hash map to delete from +// - key - pointer to the key of the entry to delete +extern void hashmap_delete(HashMap *map, void *key); + +// free the hash map +// - map - hash map to free +extern void hashmap_free(HashMap *map); diff --git a/analyzer/structures/heap.c b/analyzer/structures/heap.c new file mode 100644 index 0000000..690aac1 --- /dev/null +++ b/analyzer/structures/heap.c @@ -0,0 +1,109 @@ +#include "structures/heap.h" + +#include +#include + +Heap *heap_new(size_t element_size, int (*compare)(void *element1, void *element2), void (*element_cleanup)(void *element)) { + Heap *heap = malloc(sizeof(Heap)); + heap->data = malloc(INIT_HEAP_CAPACITY * sizeof(void *)); + heap->n_elements = 0; + heap->element_size = element_size; + heap->capacity = INIT_HEAP_CAPACITY; + heap->compare = compare; + heap->element_cleanup = element_cleanup; + return heap; +} + +// return index of parent in heap +size_t parent(size_t i) { + return (i - 1) / 2; +} + +// return index of left child in heap +size_t left(size_t i) { + return 2 * i + 1; +} + +// return index of right child in heap +size_t right(size_t i) { + return 2 * i + 2; +} + +// swap two elements +void swap(void **p_el1, void **p_el2) { + void *tmp = *p_el1; + *p_el1 = *p_el2; + *p_el2 = tmp; +} + +// expand heap exponentially to fit el_count elements +void expand_heap(Heap *heap, size_t el_count) { + while (heap->capacity < el_count) + heap->capacity = (heap->capacity << 1) | 1; + heap->data = realloc(heap->data, heap->capacity * sizeof(void *)); +} + +void heap_insert(Heap *heap, void *element) { + // expand heap if capacity is too small + if (heap->n_elements >= heap->capacity) + expand_heap(heap, heap->n_elements + 1); + + // insert into the last position + size_t i = heap->n_elements; + heap->data[i] = malloc(heap->element_size); + memcpy(heap->data[i], element, heap->element_size); + heap->n_elements++; + + // heapify up + while (i > 0 && heap->compare(heap->data[i], heap->data[parent(i)])) { + swap(&heap->data[i], &heap->data[parent(i)]); + i = parent(i); + } +} + +void *heap_top_get(Heap *heap) { + return heap->n_elements <= 0 ? NULL : heap->data[0]; +} + +void free_heap_element(Heap *heap, size_t index) { + if (heap->element_cleanup) + heap->element_cleanup(heap->data[index]); + free(heap->data[index]); +} + +void heap_top_remove(Heap *heap) { + if (heap->n_elements <= 0) + return; + + free_heap_element(heap, 0); + + // move last element to root + heap->data[0] = heap->data[--heap->n_elements]; + + // heapify down + size_t i = 0; + int changed; + do { + size_t l = left(i); + size_t r = right(i); + size_t to_be_parent = i; + + if (l < heap->n_elements && heap->compare(heap->data[l], heap->data[to_be_parent])) + to_be_parent = l; + if (r < heap->n_elements && heap->compare(heap->data[r], heap->data[to_be_parent])) + to_be_parent = r; + + if ((changed = to_be_parent != i)) { + swap(&heap->data[to_be_parent], &heap->data[i]); + i = to_be_parent; + } + } while (changed); +} + +void heap_free(Heap *heap) { + for (size_t i = 0; i < heap->n_elements; i++) { + free_heap_element(heap, i); + } + free(heap->data); + free(heap); +} diff --git a/analyzer/structures/heap.h b/analyzer/structures/heap.h new file mode 100644 index 0000000..8a23164 --- /dev/null +++ b/analyzer/structures/heap.h @@ -0,0 +1,58 @@ +// structures/heap.h +// a simple implementation of heap + +#include + +#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; + size_t element_size; + size_t capacity; + int (*compare)(void *element1, void *element2); + void (*element_cleanup)(void *element); +} Heap; +#endif + +// create a new heap +// params: +// - element_size - size of the heap element +// - compare - function for comparing elements +// params: +// - element1 - pointer to the first of the elements to compare +// - element2 - pointer to the second of the elements to compare +// returns: +// truthy if element1 should be element2's parent (e.g. element1 > element2 for max heap), falsy otherwise +// - element_cleanup - function for cleaning up any internal allocations inside element (not the element itself) +// if it has no heap allocations, this should be NULL +// params: +// - element - pointer to the element to cleanup +// returns: +// pointer to the new heap +extern Heap *heap_new(size_t element_size, int (*compare)(void *element1, void *element2), void (*element_cleanup)(void *element)); + +// insert new element into the heap +// params: +// - heap - heap to insert to +// - element - pointer to the element to insert +extern void heap_insert(Heap *heap, void *element); + +// get the top element from the heap +// params: +// - heap - heap to get the top element from +// returns: +// pointer to the top element in the heap or NULL if heap is empty +extern void *heap_top_get(Heap *heap); + +// remove the top element from the heap +// params: +// - heap - heap to remove the top element from +extern void heap_top_remove(Heap *heap); + +// free the heap +// - heap - heap to free +extern void heap_free(Heap *heap); diff --git a/analyzer/utils/fs.c b/analyzer/utils/fs.c index 2dd8191..5e3eb1c 100644 --- a/analyzer/utils/fs.c +++ b/analyzer/utils/fs.c @@ -1,4 +1,4 @@ -#include "fs.h" +#include "utils/fs.h" #include #include diff --git a/analyzer/utils/structures/hashmap.c b/analyzer/utils/structures/hashmap.c deleted file mode 100644 index 5c7fdf9..0000000 --- a/analyzer/utils/structures/hashmap.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "hashmap.h" - -#include -#include - -HashMap *hashmap_new( - size_t key_size, size_t value_size, size_t (*hash)(void *key), int (*compare)(void *key1, void *key2), void (*key_cleanup)(void *key), - void (*value_cleanup)(void *key) -) { - HashMap *map = malloc(sizeof(HashMap)); - // initialize NULLs - memset(map->table, 0, sizeof(HashMapNode *) * HASHMAP_TABLE_SIZE); - map->key_size = key_size; - map->value_size = value_size; - map->hash = hash; - map->compare = compare; - map->key_cleanup = key_cleanup; - map->value_cleanup = value_cleanup; - return map; -} - -void hashmap_put(HashMap *map, void *key, void *value) { - size_t key_hash = map->hash(key); - HashMapNode *node = map->table[key_hash]; - - // check if it exists - while (node) { - // if it exists - update node - if (map->compare(key, node->key)) { - // ensure no hanging memory allocation - if (map->value_cleanup) { - map->value_cleanup(node); - } - memcpy(node->value, value, map->value_size); - return; - } - node = node->next; - } - - // if it doesn't exist - create new node - HashMapNode *new_node = malloc(sizeof(HashMapNode)); - new_node->key = malloc(map->key_size); - new_node->value = malloc(map->value_size); - memcpy(new_node->key, key, map->key_size); - memcpy(new_node->value, value, map->value_size); - - // put in front of the linked list - new_node->next = map->table[key_hash]; - map->table[key_hash] = new_node; -} - -void *hashmap_get(HashMap *map, void *key) { - size_t key_hash = map->hash(key); - HashMapNode *node = map->table[key_hash]; - - // check if it exists - while (node) { - // if it exists - return the value pointer - if (map->compare(key, node->key)) { - return node->value; - } - node = node->next; - } - - // if it doesn't exist - return NULL - return NULL; -} - -void free_node_without_next(HashMap *map, HashMapNode *node) { - if (map->key_cleanup) { - map->key_cleanup(node); - } - if (map->value_cleanup) { - map->value_cleanup(node); - } - free(node->key); - free(node->value); - free(node); -} - -void hashmap_delete(HashMap *map, void *key) { - size_t key_hash = map->hash(key); - HashMapNode **p_node = &map->table[key_hash]; - - // check if it exists - while (*p_node) { - // if it exists - delete it - if (map->compare(key, (*p_node)->key)) { - HashMapNode *next = (*p_node)->next; - free_node_without_next(map, *p_node); - *p_node = next; - return; - } - p_node = &(*p_node)->next; - } -} - -void hashmap_free(HashMap *map) { - for (size_t i = 0; i < HASHMAP_TABLE_SIZE; i++) { - HashMapNode *curr = map->table[i]; - while (curr) { - HashMapNode *next = curr->next; - free_node_without_next(map, curr); - curr = next; - } - } - free(map); -} diff --git a/analyzer/utils/structures/hashmap.h b/analyzer/utils/structures/hashmap.h deleted file mode 100644 index 4f8e24a..0000000 --- a/analyzer/utils/structures/hashmap.h +++ /dev/null @@ -1,77 +0,0 @@ -// utils/structures/hashmap.h -// a simple implementation of hashmap using linked list - -#include - -#define HASHMAP_TABLE_SIZE 128 - -typedef struct HashMapNode { - void *key; - void *value; - struct HashMapNode *next; -} HashMapNode; - -typedef struct { - HashMapNode *table[HASHMAP_TABLE_SIZE]; - size_t key_size; - size_t value_size; - size_t (*hash)(void *key); - int (*compare)(void *key1, void *key2); - void (*key_cleanup)(void *key); - void (*value_cleanup)(void *value); -} HashMap; - -// create a new hash map -// params: -// - key_size - size of the key type -// - value_size - size of the value type -// - hash - function for hashing keys -// params: -// - key - pointer to the key to hash -// returns: -// hash of the key (size_t in [0; HASHMAP_TABLE_SIZE)) -// - compare - function for comparing keys -// params: -// - key1 - pointer to the first of the keys to compare -// - key2 - pointer to the second of the keys to compare -// returns: -// truthy if the keys are identical, falsy if they are different -// - key_cleanup - function for cleaning up any internal allocations inside node->key (not the key itself) -// if it has no heap allocations, this should be NULL -// params: -// - key - pointer to the key to cleanup -// - value_cleanup - function for cleaning up any internal allocations inside node->value (not the value itself) -// if it has no heap allocations, this should be NULL -// params: -// - value - pointer to the value to cleanup -// returns: -// pointer to the new hash map -extern HashMap *hashmap_new( - size_t key_size, size_t value_size, size_t (*hash)(void *key), int (*compare)(void *key1, void *key2), void (*key_cleanup)(void *key), - void (*value_cleanup)(void *value) -); - -// create/update an entry in a hash map -// params: -// - map - hash map to insert to -// - key - pointer to the key -// - value - pointer to the value -extern void hashmap_put(HashMap *map, void *key, void *value); - -// get the value of given key from a hash map -// params: -// - map - hash map to get from -// - key - pointer to the key of the value to get -// returns: -// pointer to the value of specified key or NULL if it doesn't exist -extern void *hashmap_get(HashMap *map, void *key); - -// delete an entry from a hash map -// params: -// - map - hash map to delete from -// - key - pointer to the key of the entry to delete -extern void hashmap_delete(HashMap *map, void *key); - -// free the hash map -// - map - hash map to free -extern void hashmap_free(HashMap *map); diff --git a/analyzer/utils/structures/heap.c b/analyzer/utils/structures/heap.c deleted file mode 100644 index 5310299..0000000 --- a/analyzer/utils/structures/heap.c +++ /dev/null @@ -1,109 +0,0 @@ -#include "heap.h" - -#include -#include - -Heap *heap_new(size_t element_size, int (*compare)(void *element1, void *element2), void (*element_cleanup)(void *element)) { - Heap *heap = malloc(sizeof(Heap)); - heap->data = malloc(INIT_HEAP_CAPACITY * sizeof(void *)); - heap->n_elements = 0; - heap->element_size = element_size; - heap->capacity = INIT_HEAP_CAPACITY; - heap->compare = compare; - heap->element_cleanup = element_cleanup; - return heap; -} - -// return index of parent in heap -size_t parent(size_t i) { - return (i - 1) / 2; -} - -// return index of left child in heap -size_t left(size_t i) { - return 2 * i + 1; -} - -// return index of right child in heap -size_t right(size_t i) { - return 2 * i + 2; -} - -// swap two elements -void swap(void **p_el1, void **p_el2) { - void *tmp = *p_el1; - *p_el1 = *p_el2; - *p_el2 = tmp; -} - -// expand heap exponentially to fit el_count elements -void expand_heap(Heap *heap, size_t el_count) { - while (heap->capacity < el_count) - heap->capacity = (heap->capacity << 1) | 1; - heap->data = realloc(heap->data, heap->capacity * sizeof(void *)); -} - -void heap_insert(Heap *heap, void *element) { - // expand heap if capacity is too small - if (heap->n_elements >= heap->capacity) - expand_heap(heap, heap->n_elements + 1); - - // insert into the last position - size_t i = heap->n_elements; - heap->data[i] = malloc(heap->element_size); - memcpy(heap->data[i], element, heap->element_size); - heap->n_elements++; - - // heapify up - while (i > 0 && heap->compare(heap->data[i], heap->data[parent(i)])) { - swap(&heap->data[i], &heap->data[parent(i)]); - i = parent(i); - } -} - -void *heap_top_get(Heap *heap) { - return heap->n_elements <= 0 ? NULL : heap->data[0]; -} - -void free_heap_element(Heap *heap, size_t index) { - if (heap->element_cleanup) - heap->element_cleanup(heap->data[index]); - free(heap->data[index]); -} - -void heap_top_remove(Heap *heap) { - if (heap->n_elements <= 0) - return; - - free_heap_element(heap, 0); - - // move last element to root - heap->data[0] = heap->data[--heap->n_elements]; - - // heapify down - size_t i = 0; - int changed; - do { - size_t l = left(i); - size_t r = right(i); - size_t to_be_parent = i; - - if (l < heap->n_elements && heap->compare(heap->data[l], heap->data[to_be_parent])) - to_be_parent = l; - if (r < heap->n_elements && heap->compare(heap->data[r], heap->data[to_be_parent])) - to_be_parent = r; - - if ((changed = to_be_parent != i)) { - swap(&heap->data[to_be_parent], &heap->data[i]); - i = to_be_parent; - } - } while (changed); -} - -void heap_free(Heap *heap) { - for (size_t i = 0; i < heap->n_elements; i++) { - free_heap_element(heap, i); - } - free(heap->data); - free(heap); -} diff --git a/analyzer/utils/structures/heap.h b/analyzer/utils/structures/heap.h deleted file mode 100644 index eb3430b..0000000 --- a/analyzer/utils/structures/heap.h +++ /dev/null @@ -1,58 +0,0 @@ -// utils/structures/heap.h -// a simple implementation of heap - -#include - -#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; - size_t element_size; - size_t capacity; - int (*compare)(void *element1, void *element2); - void (*element_cleanup)(void *element); -} Heap; -#endif - -// create a new heap -// params: -// - element_size - size of the heap element -// - compare - function for comparing elements -// params: -// - element1 - pointer to the first of the elements to compare -// - element2 - pointer to the second of the elements to compare -// returns: -// truthy if element1 should be element2's parent (e.g. element1 > element2 for max heap), falsy otherwise -// - element_cleanup - function for cleaning up any internal allocations inside element (not the element itself) -// if it has no heap allocations, this should be NULL -// params: -// - element - pointer to the element to cleanup -// returns: -// pointer to the new heap -extern Heap *heap_new(size_t element_size, int (*compare)(void *element1, void *element2), void (*element_cleanup)(void *element)); - -// insert new element into the heap -// params: -// - heap - heap to insert to -// - element - pointer to the element to insert -extern void heap_insert(Heap *heap, void *element); - -// get the top element from the heap -// params: -// - heap - heap to get the top element from -// returns: -// pointer to the top element in the heap or NULL if heap is empty -extern void *heap_top_get(Heap *heap); - -// remove the top element from the heap -// params: -// - heap - heap to remove the top element from -extern void heap_top_remove(Heap *heap); - -// free the heap -// - heap - heap to free -extern void heap_free(Heap *heap); diff --git a/analyzer/utils/tcp.c b/analyzer/utils/tcp.c index 56df842..ab5303e 100644 --- a/analyzer/utils/tcp.c +++ b/analyzer/utils/tcp.c @@ -1,4 +1,4 @@ -#include "tcp.h" +#include "utils/tcp.h" #include #include @@ -6,7 +6,7 @@ #include #include -#include "tcp_seq_math.h" +#include "utils/tcp_seq_math.h" // initalize default TCP segment TCPSegment new_segment() { diff --git a/analyzer/utils/tcp_seq_math.c b/analyzer/utils/tcp_seq_math.c index 272cb5a..2cc6e3f 100644 --- a/analyzer/utils/tcp_seq_math.c +++ b/analyzer/utils/tcp_seq_math.c @@ -1,4 +1,4 @@ -#include "tcp_seq_math.h" +#include "utils/tcp_seq_math.h" int seq_after(uint32_t a, uint32_t b) { return (int32_t)(a - b) > 0; diff --git a/analyzer/utils/time.c b/analyzer/utils/time.c index 72c0bc7..d95da65 100644 --- a/analyzer/utils/time.c +++ b/analyzer/utils/time.c @@ -1,4 +1,4 @@ -#include "time.h" +#include "utils/time.h" #include #include -- 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.c') 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 8317c3b33b9b1c70e5ae4c87c7efe33d9b9ce09a Mon Sep 17 00:00:00 2001 From: Mosder Date: Thu, 23 Jul 2026 17:35:04 +0200 Subject: feat: added helper functions for dealing with memory management and refactored the codebase to use them --- Makefile | 1 + analyzer/parser/fight_results/fight_results.c | 109 +++++++++++--------------- analyzer/parser/fight_results/fight_results.h | 6 +- analyzer/parser/parser.c | 16 +--- analyzer/parser/structs.c | 4 +- analyzer/structures/hashmap.c | 12 +-- analyzer/structures/heap.c | 10 ++- analyzer/utils/memory.c | 62 +++++++++++++++ analyzer/utils/memory.h | 42 ++++++++++ analyzer/utils/tcp.c | 46 +++++------ 10 files changed, 195 insertions(+), 113 deletions(-) create mode 100644 analyzer/utils/memory.c (limited to 'analyzer/utils/tcp.c') diff --git a/Makefile b/Makefile index fa3a294..cc5cb87 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ utils: $(CC) $(CFLAGS) -c analyzer/utils/tcp.c $(CC) $(CFLAGS) -c analyzer/utils/tcp_seq_math.c $(CC) $(CFLAGS) -c analyzer/utils/roman.c + $(CC) $(CFLAGS) -c analyzer/utils/memory.c parser: $(CC) $(CFLAGS) -c analyzer/parser/parser.c diff --git a/analyzer/parser/fight_results/fight_results.c b/analyzer/parser/fight_results/fight_results.c index e7c7123..efc4b36 100644 --- a/analyzer/parser/fight_results/fight_results.c +++ b/analyzer/parser/fight_results/fight_results.c @@ -30,6 +30,8 @@ void cleanup_fight_results(void *data) { for (size_t i = 0; i < fight_results->num_enemy; i++) { free(fight_results->enemy_results[i].name); } + free(fight_results->friendly_results); + free(fight_results->enemy_results); } byte_t *find_fight_results(TCPStream *stream, int offset, int *length) { @@ -41,12 +43,6 @@ byte_t *find_fight_results(TCPStream *stream, int offset, int *length) { return start; } -Item *expand_items(Item *items, size_t *items_capacity, size_t to_fit) { - while (*items_capacity < to_fit) - *items_capacity <<= 1; - return realloc(items, *items_capacity * sizeof(Item)); -} - void get_stars(char *buffer, int incr_above_b1) { char star_types[] = {'B', 'S', 'G'}; sprintf(buffer, " (%c%d)", star_types[incr_above_b1 / 3], incr_above_b1 % 3 + 1); @@ -67,10 +63,11 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) if (gears_separator) gears_str = gears_separator + strlen(SEPARATOR_GEAR); - Item item; - + // get gear info for rank, name and stars / syng level GearInfo gear_info = {0}; fill_struct(&gear_info, gear_info_fields, ARR_LEN(gear_info_fields), gear.info, strlen(gear.info), SEPARATOR_GEAR_INFO_FIELD); + + // create the buffer of information about gear char buffer[SINGLE_ITEM_BUFFER_LEN]; char roman[5]; to_roman(roman, gear_info.rank); @@ -91,9 +88,9 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) break; } } - item.data = strdup(buffer); - cleanup_struct(&gear_info, gear_info_fields, ARR_LEN(gear_info_fields)); + // add gear with specific type + Item item = {.data = strdup(buffer)}; switch (gear.type) { case TYPE_SYNG_NORMAL: // atoi should be fine, since syng_tier starts from 1 for syngs @@ -109,26 +106,22 @@ void add_gear(FriendlyResults *results, size_t *items_capacity, char *gears_str) item.type = EPIC; break; } + results->items = array_append(results->items, sizeof(Item), &results->num_items, items_capacity, &item); - // expand if needed - if (results->num_items >= *items_capacity) - results->items = expand_items(results->items, items_capacity, results->num_items + 1); - results->items[results->num_items++] = item; + cleanup_struct(&gear_info, gear_info_fields, ARR_LEN(gear_info_fields)); // add orb to items if it exists if (strlen(gear.orb)) { - Item item; - char buffer[SINGLE_ITEM_BUFFER_LEN]; Orb orb = {0}; fill_struct(&orb, orb_fields, ARR_LEN(orb_fields), gear.orb, strlen(gear.orb), SEPARATOR_ORB_FIELD); + + char buffer[SINGLE_ITEM_BUFFER_LEN]; sprintf(buffer, "%sorb %s", get_artifact_size_from_id(orb.size), get_orb_name_from_id(orb.id)); - item.data = strdup(buffer); + + Item item = {.data = strdup(buffer), .type = ORB}; + results->items = array_append(results->items, sizeof(Item), &results->num_items, items_capacity, &item); + cleanup_struct(&orb, orb_fields, ARR_LEN(orb_fields)); - item.type = ORB; - // expand if needed - if (results->num_items >= *items_capacity) - results->items = expand_items(results->items, items_capacity, results->num_items + 1); - results->items[results->num_items++] = item; } cleanup_struct(&gear, gear_fields, ARR_LEN(gear_fields)); @@ -150,16 +143,10 @@ void add_drifs(FriendlyResults *results, size_t *items_capacity, char *drifs_str if (drifs_separator) drifs_str = drifs_separator + strlen(SEPARATOR_DRIF); - Item item; - item.data = strdup(drif.name); - item.type = DRIF; + Item item = {.data = strdup(drif.name), .type = DRIF}; + results->items = array_append(results->items, sizeof(Item), &results->num_items, items_capacity, &item); cleanup_struct(&drif, drif_fields, ARR_LEN(drif_fields)); - - // expand if needed - if (results->num_items >= *items_capacity) - results->items = expand_items(results->items, items_capacity, results->num_items + 1); - results->items[results->num_items++] = item; } while (drifs_separator); } @@ -180,37 +167,31 @@ void add_items(FriendlyResults *results, size_t *items_capacity, char *items_str if (items_separator) items_str = items_separator + strlen(SEPARATOR_ITEMS); - Item item; - item.data = strdup(buffer); - item.type = NORMAL; - - // expand if needed - if (results->num_items >= *items_capacity) - results->items = expand_items(results->items, items_capacity, results->num_items + 1); - results->items[results->num_items++] = item; + Item item = {.data = strdup(buffer), .type = NORMAL}; + results->items = array_append(results->items, sizeof(Item), &results->num_items, items_capacity, &item); } while (items_separator); } // parse EntityResults to FriendlyResults FriendlyResults parse_to_friendly(EntityResults entity_results) { - FriendlyResults results; - - results.name = strdup(entity_results.name); - results.exp = entity_results.exp; - results.gold = entity_results.gold; - results.level = entity_results.level; - results.psycho = entity_results.psycho; - results.splinters = entity_results.splinters; + FriendlyResults results = { + .name = strdup(entity_results.name), + .exp = entity_results.exp, + .gold = entity_results.gold, + .level = entity_results.level, + .psycho = entity_results.psycho, + .splinters = entity_results.splinters, + .num_items = 0, + .saturation = 0 + }; // create items array and add to it gear, drifs and items - results.num_items = 0; - results.items = malloc(INIT_ITEMS_CAPACITY * sizeof(Item)); + results.items = safe_malloc(INIT_ITEMS_CAPACITY * sizeof(Item)); size_t items_cap = INIT_ITEMS_CAPACITY; add_gear(&results, &items_cap, entity_results.gear); add_drifs(&results, &items_cap, entity_results.drifs); add_items(&results, &items_cap, entity_results.items); - results.saturation = 0; if (strlen(entity_results.saturation) > 0) { int saturation_id; sscanf(entity_results.saturation, "%d,%d", &saturation_id, &results.saturation); @@ -222,25 +203,26 @@ FriendlyResults parse_to_friendly(EntityResults entity_results) { // parse EntityResults to EnemyResults EnemyResults parse_to_enemy(EntityResults entity_results) { - EnemyResults results; - - results.name = strdup(entity_results.name); - results.level = entity_results.level; - + EnemyResults results = {.name = strdup(entity_results.name), .level = entity_results.level}; return results; } ParsedData parse_fight_results(byte_t *data, size_t length) { - ParsedData parsed_data; - parsed_data.data_type = TYPE_FIGHT_RESULTS; + ParsedData parsed_data = {.data_type = TYPE_FIGHT_RESULTS, .data_cleanup = cleanup_fight_results}; // ignore start and end indicators data += strlen(FIGHT_RESULTS_START); length -= strlen(FIGHT_RESULTS_START) + strlen(FIGHT_RESULTS_END); - FightResults *results = malloc(sizeof(FightResults)); + FightResults *results = safe_malloc(sizeof(FightResults)); + + results->friendly_results = safe_malloc(INIT_ENTITIES_PER_SIDE * sizeof(FriendlyResults)); results->num_friendly = 0; + size_t friendly_cap = INIT_ENTITIES_PER_SIDE; + + results->enemy_results = safe_malloc(INIT_ENTITIES_PER_SIDE * sizeof(EnemyResults)); results->num_enemy = 0; + size_t enemy_cap = INIT_ENTITIES_PER_SIDE; byte_t *entity_separator; do { @@ -252,12 +234,16 @@ ParsedData parse_fight_results(byte_t *data, size_t length) { // depending on team - parse it into friendly or enemy results switch (entity_results.team) { - case TEAM_FRIEND: - results->friendly_results[results->num_friendly++] = parse_to_friendly(entity_results); + case TEAM_FRIEND: { + FriendlyResults res = parse_to_friendly(entity_results); + results->friendly_results = array_append(results->friendly_results, sizeof(FriendlyResults), &results->num_friendly, &friendly_cap, &res); break; - case TEAM_ENEMY: - results->enemy_results[results->num_enemy++] = parse_to_enemy(entity_results); + } + case TEAM_ENEMY: { + EnemyResults res = parse_to_enemy(entity_results); + results->enemy_results = array_append(results->enemy_results, sizeof(EnemyResults), &results->num_enemy, &enemy_cap, &res); break; + } } cleanup_struct(&entity_results, entity_fields, ARR_LEN(entity_fields)); @@ -270,6 +256,5 @@ ParsedData parse_fight_results(byte_t *data, size_t length) { } while (entity_separator); parsed_data.data = results; - parsed_data.data_cleanup = cleanup_fight_results; return parsed_data; } diff --git a/analyzer/parser/fight_results/fight_results.h b/analyzer/parser/fight_results/fight_results.h index 04add96..ec90394 100644 --- a/analyzer/parser/fight_results/fight_results.h +++ b/analyzer/parser/fight_results/fight_results.h @@ -44,14 +44,14 @@ typedef struct { int level; } EnemyResults; -#define MAX_ENTITIES_PER_SIDE 8 +#define INIT_ENTITIES_PER_SIDE 6 // entire fight resutls typedef struct { size_t num_friendly; - FriendlyResults friendly_results[MAX_ENTITIES_PER_SIDE]; + FriendlyResults *friendly_results; size_t num_enemy; - EnemyResults enemy_results[MAX_ENTITIES_PER_SIDE]; + EnemyResults *enemy_results; } FightResults; extern find_function_t find_fight_results; diff --git a/analyzer/parser/parser.c b/analyzer/parser/parser.c index 87ab4c0..d00cd97 100644 --- a/analyzer/parser/parser.c +++ b/analyzer/parser/parser.c @@ -5,13 +5,6 @@ #include "parser/find_parse_functions.h" #include "utils/memory.h" -// expand parsed data exponentially to fit el_count elements -ParsedData *expand_parsed_data(ParsedData *parsed_data, size_t *capacity, size_t el_count) { - while (*capacity < el_count) - *capacity <<= 1; - return realloc(parsed_data, *capacity * sizeof(ParsedData)); -} - // find earliest data to parse in stream byte_t *find_earliest_data(TCPStream *stream, int stream_offset, int *earliest_length, parse_function_t **earliest_parse_fun) { byte_t *earliest_data = NULL; @@ -30,7 +23,7 @@ byte_t *find_earliest_data(TCPStream *stream, int stream_offset, int *earliest_l ParsedData *parse_stream(TCPStream *stream, size_t *parsed_len, size_t *n_parsed_data) { size_t parsed_data_capacity = INIT_PARSED_DATA_CAPACITY; - ParsedData *parsed_data = malloc(parsed_data_capacity * sizeof(ParsedData)); + ParsedData *parsed_data = safe_malloc(parsed_data_capacity * sizeof(ParsedData)); *n_parsed_data = 0; int stream_offset = 0; @@ -50,11 +43,8 @@ ParsedData *parse_stream(TCPStream *stream, size_t *parsed_len, size_t *n_parsed // if data to parse was found, parse it and update the offset if (earliest_data) { - // if no capacity in parsed data array - expand it - if (*n_parsed_data >= parsed_data_capacity) - parsed_data = expand_parsed_data(parsed_data, &parsed_data_capacity, *n_parsed_data + 1); - - parsed_data[(*n_parsed_data)++] = earliest_parse_fun(earliest_data, earliest_length); + ParsedData new_parsed = earliest_parse_fun(earliest_data, earliest_length); + parsed_data = array_append(parsed_data, sizeof(ParsedData), n_parsed_data, &parsed_data_capacity, &new_parsed); stream_offset = earliest_data - stream->data + earliest_length; } } while (earliest_data); diff --git a/analyzer/parser/structs.c b/analyzer/parser/structs.c index c59fa82..dedf0d1 100644 --- a/analyzer/parser/structs.c +++ b/analyzer/parser/structs.c @@ -4,12 +4,14 @@ #include #include +#include "utils/memory.h" + void fill_struct(void *obj, const StructField *fields, size_t n_fields, const char *data, size_t data_len, const char *sep) { for (size_t i = 0; i < n_fields; i++) { char *next_sep = memmem(data, data_len, sep, strlen(sep)); size_t len = next_sep ? next_sep - data : data_len; - char *str = malloc(len + 1); + char *str = safe_malloc(len + 1); memcpy(str, data, len); str[len] = '\0'; diff --git a/analyzer/structures/hashmap.c b/analyzer/structures/hashmap.c index 84cc289..5eb27ae 100644 --- a/analyzer/structures/hashmap.c +++ b/analyzer/structures/hashmap.c @@ -3,6 +3,8 @@ #include #include +#include "utils/memory.h" + HashMap *hashmap_new( size_t key_size, size_t value_size, @@ -11,9 +13,9 @@ HashMap *hashmap_new( void (*key_cleanup)(void *key), void (*value_cleanup)(void *key) ) { - HashMap *map = malloc(sizeof(HashMap)); + HashMap *map = safe_malloc(sizeof(HashMap)); // initialize NULLs - memset(map->table, 0, sizeof(HashMapNode *) * HASHMAP_TABLE_SIZE); + memset(map->table, 0, HASHMAP_TABLE_SIZE * sizeof(HashMapNode *)); map->key_size = key_size; map->value_size = value_size; map->hash = hash; @@ -42,9 +44,9 @@ void hashmap_put(HashMap *map, void *key, void *value) { } // if it doesn't exist - create new node - HashMapNode *new_node = malloc(sizeof(HashMapNode)); - new_node->key = malloc(map->key_size); - new_node->value = malloc(map->value_size); + HashMapNode *new_node = safe_malloc(sizeof(HashMapNode)); + new_node->key = safe_malloc(map->key_size); + new_node->value = safe_malloc(map->value_size); memcpy(new_node->key, key, map->key_size); memcpy(new_node->value, value, map->value_size); diff --git a/analyzer/structures/heap.c b/analyzer/structures/heap.c index 6102940..1267668 100644 --- a/analyzer/structures/heap.c +++ b/analyzer/structures/heap.c @@ -3,9 +3,11 @@ #include #include +#include "utils/memory.h" + Heap *heap_new(size_t element_size, int (*compare)(void *element1, void *element2), void (*element_cleanup)(void *element)) { - Heap *heap = malloc(sizeof(Heap)); - heap->data = malloc(INIT_HEAP_CAPACITY * sizeof(void *)); + Heap *heap = safe_malloc(sizeof(Heap)); + heap->data = safe_malloc(INIT_HEAP_CAPACITY * sizeof(void *)); heap->n_elements = 0; heap->element_size = element_size; heap->capacity = INIT_HEAP_CAPACITY; @@ -40,7 +42,7 @@ void swap(void **p_el1, void **p_el2) { void expand_heap(Heap *heap, size_t el_count) { while (heap->capacity < el_count) heap->capacity = (heap->capacity << 1) | 1; - heap->data = realloc(heap->data, heap->capacity * sizeof(void *)); + heap->data = safe_realloc(heap->data, heap->capacity * sizeof(void *)); } void heap_insert(Heap *heap, void *element) { @@ -50,7 +52,7 @@ void heap_insert(Heap *heap, void *element) { // insert into the last position size_t i = heap->n_elements; - heap->data[i] = malloc(heap->element_size); + heap->data[i] = safe_malloc(heap->element_size); memcpy(heap->data[i], element, heap->element_size); heap->n_elements++; diff --git a/analyzer/utils/memory.c b/analyzer/utils/memory.c new file mode 100644 index 0000000..0a43bd3 --- /dev/null +++ b/analyzer/utils/memory.c @@ -0,0 +1,62 @@ +#include "memory.h" + +#include +#include +#include +#include + +void *safe_malloc(size_t size) { + for (size_t i = 0; i < MAX_ALLOC_ATTEMPTS; i++) { + void *p = malloc(size); + if (p) + return p; + if (i < MAX_ALLOC_ATTEMPTS - 1) { + printf("Failed malloc. Retrying in 1s...\n"); + sleep(1); + } + } + + printf("ERROR: Failed malloc %d times. Exiting...", MAX_ALLOC_ATTEMPTS); + exit(EXIT_FAILURE); +} + +void *safe_realloc(void *ptr, size_t size) { + if (!ptr) + return safe_malloc(size); + + for (size_t i = 0; i < MAX_ALLOC_ATTEMPTS; i++) { + void *p = realloc(ptr, size); + if (p) + return p; + if (i < MAX_ALLOC_ATTEMPTS - 1) { + printf("Failed realloc. Retrying in 1s...\n"); + sleep(1); + } + } + + printf("ERROR: Failed realloc %d times. Exiting...", MAX_ALLOC_ATTEMPTS); + exit(EXIT_FAILURE); +} + +// expand an array +// returns pointer to the expanded array +void *array_expand(void *arr, size_t el_size, size_t *cap, size_t to_fit) { + while (*cap < to_fit) + *cap *= 2; + return safe_realloc(arr, *cap * el_size); +} + +void *array_append(void *arr, size_t el_size, size_t *len, size_t *cap, void *val) { + if (*len >= *cap) + arr = array_expand(arr, el_size, cap, *len + 1); + memcpy((char *)arr + (*len)++ * el_size, val, el_size); + return arr; +} + +void *array_concat(void *arr1, size_t el_size, size_t *len1, size_t *cap, void *arr2, size_t len2) { + if (*len1 + len2 > *cap) + arr1 = array_expand(arr1, el_size, cap, *len1 + len2); + memcpy((char *)arr1 + *len1 * el_size, arr2, len2 * el_size); + *len1 += len2; + return arr1; +} diff --git a/analyzer/utils/memory.h b/analyzer/utils/memory.h index 1de58b9..0973623 100644 --- a/analyzer/utils/memory.h +++ b/analyzer/utils/memory.h @@ -1,4 +1,46 @@ // utils/memory.h // helper functions for dealing with memory management +#include + #define ARR_LEN(arr) (sizeof(arr) / sizeof(arr[0])) + +#define MAX_ALLOC_ATTEMPTS 3 + +// tries malloc MAX_ALLOC_ATTEMPTS times, if all fail - exits the program +// params: +// - size - count of bytes to allocate +// returns: +// pointer to the allocated memory +extern void *safe_malloc(size_t size); + +// tries realloc MAX_ALLOC_ATTEMPTS times, if all fail - exits the program +// params: +// - ptr - pointer to the memory to reallocate +// - size - new size of the memory +// returns: +// pointer to the reallocated memory +extern void *safe_realloc(void *ptr, size_t size); + +// append to array, expand if necessary +// params: +// - arr - array to append to +// - el_size - size of an array element +// - len - pointer to the length of the array +// - cap - pointer to the capacity of the array +// - val - pointer to the value to append to the array +// returns: +// new pointer to the array (different if it was realloced) +extern void *array_append(void *arr, size_t el_size, size_t *len, size_t *cap, void *val); + +// concatenate 2 arrays, expand if necessary +// params: +// - arr1 - first array (destination) +// - el_size - size of an array element +// - len1 - pointer to the length of arr1 +// - cap - pointer to the capacity of arr1 +// - arr2 - second array +// - len2 - length of arr2 +// returns: +// new pointer to the array (different if it was realloced) +extern void *array_concat(void *arr1, size_t el_size, size_t *len1, size_t *cap, void *arr2, size_t len2); diff --git a/analyzer/utils/tcp.c b/analyzer/utils/tcp.c index b925ecf..6309e64 100644 --- a/analyzer/utils/tcp.c +++ b/analyzer/utils/tcp.c @@ -6,15 +6,19 @@ #include #include +#include "utils/memory.h" #include "utils/tcp_seq_math.h" // initalize default TCP segment TCPSegment new_segment() { - TCPSegment segment; - segment.payload = NULL; - segment.len = 0; - segment.seq = 0; - segment.port = 0; + // clang-format off + TCPSegment segment = { + .payload = NULL, + .len = 0, + .seq = 0, + .port = 0 + }; + // clang-format on return segment; } @@ -61,19 +65,22 @@ TCPSegment get_segment_from_packet(const byte_t *packet, const struct pcap_pkthd // get payload int total_header_len = eth_header_len + ip_header_len + tcp_header_len; segment.len = packet_data->caplen - total_header_len; - segment.payload = malloc(segment.len); + segment.payload = safe_malloc(segment.len); memcpy(segment.payload, packet + total_header_len, segment.len); return segment; } TCPStream new_stream() { - TCPStream stream; - stream.data = malloc(INIT_STREAM_CAPACITY); - stream.len = 0; - stream.capacity = INIT_STREAM_CAPACITY; - stream.seq = 0; - stream.port = 0; - stream.pending = NULL; + // clang-format off + TCPStream stream = { + .data = safe_malloc(INIT_STREAM_CAPACITY), + .len = 0, + .capacity = INIT_STREAM_CAPACITY, + .seq = 0, + .port = 0, + .pending = NULL + }; + // clang-format on return stream; } @@ -107,20 +114,9 @@ int in_acceptable_range(TCPStream stream, TCPSegment segment) { return seq_in_range_ei(segment.seq, stream_expected, max_acceptable_seq); } -// expand stream capacity exponentially to fit new_len -void expand_stream_capacity(TCPStream *stream, size_t new_len) { - while (stream->capacity < new_len) - stream->capacity <<= 1; - stream->data = realloc(stream->data, stream->capacity); -} - // add segment directly to stream void add_segment(TCPStream *stream, TCPSegment segment, size_t data_start) { - size_t new_stream_len = stream->len + segment.len - data_start; - if (new_stream_len > stream->capacity) - expand_stream_capacity(stream, new_stream_len); - memcpy(stream->data + stream->len, segment.payload + data_start, segment.len - data_start); - stream->len = new_stream_len; + stream->data = array_concat(stream->data, 1, &stream->len, &stream->capacity, segment.payload + data_start, segment.len - data_start); } // add pending segments to the stream -- cgit v1.2.3