From d62be280a151883866554e9ea00a5efed2fa593a Mon Sep 17 00:00:00 2001 From: Mosder Date: Wed, 17 Jun 2026 22:55:55 +0200 Subject: feat: added simple reading of packets from file and printing the payloads. TODO: utilize TCP sequence number to make sure the stream is read in order and parse the packets without reassemblying the entire stream (which might be enormous), but keeping in mind that entire fight result might be accross multiple segments --- main.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 456b590..eadb516 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include #include +#include "analyzer/analyzer.h" #include "analyzer/capture.h" #include "analyzer/utils/fs.h" @@ -22,14 +23,6 @@ void start_live_analyzer() { printf("Not implemented\n"); } -// analyzes the specified file -// params: -// - file_path - path to the .pcap file to be analyzed -void analyze_file(char *file_path) { - // TODO: implement - printf("Not implemented\n"); -} - int main(int argc, char *argv[]) { create_necessary_directories(); -- cgit v1.2.3 From 05da5ef05778d0653685a20e9e5847b221a54f59 Mon Sep 17 00:00:00 2001 From: Mosder Date: Thu, 23 Jul 2026 13:59:15 +0200 Subject: refactor: generalized command parsing and moved it into a separate file --- Makefile | 28 +++++------- analyzer/commands.c | 99 ++++++++++++++++++++++++++++++++++++++++++ analyzer/commands.h | 30 +++++++++++++ csv_table_gen.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ csv_to_headers.c | 121 ---------------------------------------------------- main.c | 56 +++++------------------- 6 files changed, 271 insertions(+), 184 deletions(-) create mode 100644 analyzer/commands.c create mode 100644 analyzer/commands.h create mode 100644 csv_table_gen.c delete mode 100644 csv_to_headers.c (limited to 'main.c') diff --git a/Makefile b/Makefile index 31c1275..fa3a294 100644 --- a/Makefile +++ b/Makefile @@ -10,16 +10,22 @@ local: compile debug: CFLAGS=-iquote ./analyzer -Og -g debug: global -compile: csv structures utils parser capture analyzer render +compile: csv_table_gen main_files structures utils parser $(CC) $(CFLAGS) -lpcap *.o main.c -o branal rm *.o -csv: - $(CC) $(CFLAGS) csv_to_headers.c -o csv_to_headers - ./csv_to_headers - rm csv_to_headers +csv_table_gen: + $(CC) $(CFLAGS) csv_table_gen.c -o csv_table_gen + ./csv_table_gen + rm csv_table_gen $(CC) $(CFLAGS) -c analyzer/csv/*.c +main_files: + $(CC) $(CFLAGS) -c analyzer/commands.c + $(CC) $(CFLAGS) -c analyzer/capture.c + $(CC) $(CFLAGS) -c analyzer/analyzer.c + $(CC) $(CFLAGS) -c analyzer/render.c + structures: $(CC) $(CFLAGS) -c analyzer/structures/hashmap.c $(CC) $(CFLAGS) -c analyzer/structures/heap.c @@ -35,15 +41,3 @@ parser: $(CC) $(CFLAGS) -c analyzer/parser/parser.c $(CC) $(CFLAGS) -c analyzer/parser/structs.c $(CC) $(CFLAGS) -c analyzer/parser/fight_results/fight_results.c - -capture: - $(CC) $(CFLAGS) -c analyzer/capture.c - -analyzer: - $(CC) $(CFLAGS) -c analyzer/analyzer.c - -render: - $(CC) $(CFLAGS) -c analyzer/render.c - -.PHONY: analyzer -.PHONY: csv diff --git a/analyzer/commands.c b/analyzer/commands.c new file mode 100644 index 0000000..cb3cdea --- /dev/null +++ b/analyzer/commands.c @@ -0,0 +1,99 @@ +#include "commands.h" + +#include +#include + +#include "analyzer.h" +#include "capture.h" +#include "utils/memory.h" + +#define PROGRAM_NAME "branal" +#define INDENT " " +#define MAX_COMMAND_LENGTH 100 + +// calculate the longest command length to align explenations +int longest_command_length() { + int longest_len = 0; + for (size_t i = 0; i < commands_count; i++) { + Command cmd = commands[i]; + int len = strlen(PROGRAM_NAME); + len += strlen(" ( | ) "); + len += strlen(cmd.short_name) + strlen(cmd.name); + len += strlen(cmd.args_str) == 0 ? 0 : strlen(cmd.args_str) + 1; + if (len > longest_len) + longest_len = len; + } + return longest_len; +} + +// help command handler +int print_help(int argc, char *argv[]) { + int len = longest_command_length(); + + printf("A bare-bones analyzer for the game Broken Ranks\n"); + printf("\nUsage:\n"); + printf(INDENT "%-*s- same as below\n", len, PROGRAM_NAME); + + for (size_t i = 0; i < commands_count; i++) { + Command cmd = commands[i]; + + char buffer[MAX_COMMAND_LENGTH]; + sprintf(buffer, PROGRAM_NAME " (%s | %s) ", cmd.short_name, cmd.name); + if (strlen(cmd.args_str)) + strcat(buffer, cmd.args_str); + + printf(INDENT "%-*s- %s\n", len, buffer, cmd.explanation[0]); + for (size_t j = 1; j < cmd.explanation_lines; j++) { + printf(INDENT "%*s%s\n", len + 2, "", cmd.explanation[j]); + } + } + + return 0; +} + +// live analyzer command handler +int live_anal(int argc, char *argv[]) { + // TODO: implement + printf("Not implemented\n"); + return 1; +} + +// capturing mode command handler +int capture(int argc, char *argv[]) { + capturing_mode(argc >= 3 ? argv[2] : NULL); + return 0; +} + +// file analysis command handler +int file_anal(int argc, char *argv[]) { + if (argc < 3) { + printf("You need to provide a file (or files) to analyze"); + return 1; + } + + for (size_t i = 2; i < argc; i++) { + printf("FILE: %s\n", argv[i]); + analyze_file(argv[i]); + printf("\n"); + } + + return 0; +} + +const Command help_command = {"help", "h", "", {"display this help"}, 1, print_help}; +const Command commands[] = { + {"live", "l", "", {"start live analysis"}, 1, live_anal}, + {"capture", "c", "[file]", {"start capturing packers to file", "If file isn't provided - captures to: $HOME/.local/share/branal/captures"}, 2, capture}, + {"file", "f", "", {"analyze the specified file(s)"}, 1, file_anal}, + help_command +}; +const size_t commands_count = ARR_LEN(commands); + +int is_command(Command command, char *str) { + return !strcmp(command.short_name, str) || !strcmp(command.name, str); +} + +void command_not_recognized() { + printf("Command not recognized\n"); + printf("Use \"%s (%s | %s)\" for help\n", PROGRAM_NAME, help_command.short_name, help_command.name); +} diff --git a/analyzer/commands.h b/analyzer/commands.h new file mode 100644 index 0000000..f53a140 --- /dev/null +++ b/analyzer/commands.h @@ -0,0 +1,30 @@ +// commands.h +// commands to use in the program + +#include + +#define MAX_EXPLANATION_LINES 3 + +typedef struct { + char *name; + char *short_name; + char *args_str; + char *explanation[MAX_EXPLANATION_LINES]; + size_t explanation_lines; + int (*handler)(int argc, char *argv[]); +} Command; + +// all commands of the program +extern const Command commands[]; +extern const size_t commands_count; + +// check if the given command is represented by the given string +// params: +// - command - potentailly represented command +// - str - potentially representing string +// returns: +// 1 if command is represneted by string, 0 if not +extern int is_command(Command command, char *str); + +// print information about help when program didn't recognize command +extern void command_not_recognized(); diff --git a/csv_table_gen.c b/csv_table_gen.c new file mode 100644 index 0000000..9be57d0 --- /dev/null +++ b/csv_table_gen.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#define EXT ".csv" +#define EXT_LEN strlen(".csv") +#define CSV_PATH "csv" +#define OUT_PATH "analyzer/" CSV_PATH + +#define BUFFER_SIZE 256 +#define MAX_ARR_SIZE 4096 + +// read values from input csv and save them to buffers +// returns max_index of the array +int read_csv(char *path, char *from, char *to, char from_to_array[][BUFFER_SIZE]) { + FILE *fp = fopen(path, "r"); + + // read field names + fscanf(fp, "%[^,],%[^\n]", from, to); + + // read values + size_t max_index = 0; + size_t val1; + char val2[BUFFER_SIZE]; + while (fscanf(fp, "%zu,%[^\n]", &val1, val2) == 2) { + strcpy(from_to_array[val1], val2); + if (val1 > max_index) + max_index = val1; + } + + fclose(fp); + + return max_index; +} + +// create output .h file +void create_h(char *path, char *from, char *to) { + FILE *fp = fopen(path, "w"); + + // write comments and function prototype + fprintf(fp, "// %s\n", strstr(path, CSV_PATH)); + fprintf(fp, "// translate %s to %s - generated from csv\n\n", from, to); + fprintf(fp, "// get %s from %s\n", to, from); + fprintf(fp, "// params:\n"); + fprintf(fp, "// - %s - %s to translate from\n", from, from); + fprintf(fp, "// returns:\n"); + fprintf(fp, "// %s corresponding to %s\n", to, from); + fprintf(fp, "extern const char *get_%s_from_%s(int %s);", to, from, from); + + fclose(fp); +} + +// create output .c file +void create_c(char *path, char *h_path, char *from, char *to, char from_to_array[][BUFFER_SIZE], size_t max_index) { + FILE *fp = fopen(path, "w"); + + char arr_name[BUFFER_SIZE], arr_len_name[BUFFER_SIZE]; + sprintf(arr_name, "%s_to_%s", from, to); + sprintf(arr_len_name, "%s_to_%s_len", from, to); + + // write include and beginning of array + fprintf(fp, "#include \"%s\"\n\n", strstr(h_path, CSV_PATH)); + fprintf(fp, "static const char *%s[] = {\n", arr_name); + + // write values + for (size_t i = 0; i <= max_index; i++) { + if (strlen(from_to_array[i]) > 0) + fprintf(fp, " \"%s\",\n", from_to_array[i]); + else + fprintf(fp, " \"%zu\",\n", i); + } + + // write the end of array and len + fprintf(fp, "};\n"); + fprintf(fp, "int %s = %zu;\n\n", arr_len_name, max_index + 1); + + // write the getter + fprintf(fp, "const char *get_%s_from_%s(int %s) {\n", to, from, from); + fprintf(fp, " return %s >= 0 && %s < %s ? %s[%s] : \"null\";\n", from, from, arr_len_name, arr_name, from); + fprintf(fp, "}"); + + fclose(fp); +} + +void create_table(char *file_name) { + // read from input file + char input_path[BUFFER_SIZE]; + sprintf(input_path, "%s/%s", CSV_PATH, file_name); + char from[BUFFER_SIZE], to[BUFFER_SIZE]; + char from_to_array[MAX_ARR_SIZE][BUFFER_SIZE] = {0}; + size_t max_index = read_csv(input_path, from, to, from_to_array); + + // create output .h file + char h_path[BUFFER_SIZE]; + sprintf(h_path, "%s/%s_to_%s.h", OUT_PATH, from, to); + create_h(h_path, from, to); + + // create output .c file + char c_path[BUFFER_SIZE]; + sprintf(c_path, "%s/%s_to_%s.c", OUT_PATH, from, to); + create_c(c_path, h_path, from, to, from_to_array, max_index); +} + +int main() { + // make directory for output files + mkdir(OUT_PATH, 0755); + + DIR *csv_dir = opendir(CSV_PATH); + struct dirent *entry; + while ((entry = readdir(csv_dir))) { + char *file_name = entry->d_name; + size_t file_name_len = strlen(file_name); + // create lookup tables for each *.csv file + if (file_name_len > EXT_LEN && !strcmp(file_name + file_name_len - EXT_LEN, EXT)) + create_table(entry->d_name); + } + closedir(csv_dir); + + return 0; +} diff --git a/csv_to_headers.c b/csv_to_headers.c deleted file mode 100644 index 51a1c58..0000000 --- a/csv_to_headers.c +++ /dev/null @@ -1,121 +0,0 @@ -#include -#include -#include -#include - -#define EXT ".csv" -#define EXT_LEN strlen(".csv") -#define CSV_PATH "csv" -#define OUT_PATH "analyzer/" CSV_PATH - -#define BUFFER_SIZE 256 -#define MAX_ARR_SIZE 4096 - -// read values from input csv and save them to buffers -// returns max_index of the array -int read_csv(char *path, char *from, char *to, char from_to_array[][BUFFER_SIZE]) { - FILE *fp = fopen(path, "r"); - - // read field names - fscanf(fp, "%[^,],%[^\n]", from, to); - - // read values - size_t max_index = 0; - size_t val1; - char val2[BUFFER_SIZE]; - while (fscanf(fp, "%zu,%[^\n]", &val1, val2) == 2) { - strcpy(from_to_array[val1], val2); - if (val1 > max_index) - max_index = val1; - } - - fclose(fp); - - return max_index; -} - -// create output .h file -void create_h(char *path, char *from, char *to) { - FILE *fp = fopen(path, "w"); - - // write comments and function prototype - fprintf(fp, "// %s\n", strstr(path, CSV_PATH)); - fprintf(fp, "// translate %s to %s - generated from csv\n\n", from, to); - fprintf(fp, "// get %s from %s\n", to, from); - fprintf(fp, "// params:\n"); - fprintf(fp, "// - %s - %s to translate from\n", from, from); - fprintf(fp, "// returns:\n"); - fprintf(fp, "// %s corresponding to %s\n", to, from); - fprintf(fp, "extern const char *get_%s_from_%s(int %s);", to, from, from); - - fclose(fp); -} - -// create output .c file -void create_c(char *path, char *h_path, char *from, char *to, char from_to_array[][BUFFER_SIZE], size_t max_index) { - FILE *fp = fopen(path, "w"); - - char arr_name[BUFFER_SIZE], arr_len_name[BUFFER_SIZE]; - sprintf(arr_name, "%s_to_%s", from, to); - sprintf(arr_len_name, "%s_to_%s_len", from, to); - - // write include and beginning of array - fprintf(fp, "#include \"%s\"\n\n", strstr(h_path, CSV_PATH)); - fprintf(fp, "static const char *%s[] = {\n", arr_name); - - // write values - for (size_t i = 0; i <= max_index; i++) { - if (strlen(from_to_array[i]) > 0) - fprintf(fp, " \"%s\",\n", from_to_array[i]); - else - fprintf(fp, " \"%zu\",\n", i); - } - - // write the end of array and len - fprintf(fp, "};\n"); - fprintf(fp, "int %s = %zu;\n\n", arr_len_name, max_index + 1); - - // write the getter - fprintf(fp, "const char *get_%s_from_%s(int %s) {\n", to, from, from); - fprintf(fp, " return %s >= 0 && %s < %s ? %s[%s] : \"null\";\n", from, from, arr_len_name, arr_name, from); - fprintf(fp, "}"); - - fclose(fp); -} - -void create_table(char *file_name) { - // read from input file - char input_path[BUFFER_SIZE]; - sprintf(input_path, "%s/%s", CSV_PATH, file_name); - char from[BUFFER_SIZE], to[BUFFER_SIZE]; - char from_to_array[MAX_ARR_SIZE][BUFFER_SIZE] = {0}; - size_t max_index = read_csv(input_path, from, to, from_to_array); - - // create output .h file - char h_path[BUFFER_SIZE]; - sprintf(h_path, "%s/%s_to_%s.h", OUT_PATH, from, to); - create_h(h_path, from, to); - - // create output .c file - char c_path[BUFFER_SIZE]; - sprintf(c_path, "%s/%s_to_%s.c", OUT_PATH, from, to); - create_c(c_path, h_path, from, to, from_to_array, max_index); -} - -int main() { - // make directory for output files - mkdir(OUT_PATH, 0755); - - DIR *csv_dir = opendir(CSV_PATH); - struct dirent *entry; - while ((entry = readdir(csv_dir))) { - char *file_name = entry->d_name; - size_t file_name_len = strlen(file_name); - // create lookup tables for each *.csv file - if (file_name_len > EXT_LEN && strcmp(file_name + file_name_len - EXT_LEN, EXT) == 0) - create_table(entry->d_name); - } - closedir(csv_dir); - - return 0; -} diff --git a/main.c b/main.c index eadb516..38dfc36 100644 --- a/main.c +++ b/main.c @@ -1,54 +1,18 @@ -#include -#include - -#include "analyzer/analyzer.h" -#include "analyzer/capture.h" -#include "analyzer/utils/fs.h" - -// prints help -void print_help() { - printf("A bare-bones analyzer for the game Broken Ranks\n"); - printf("\nUsage:\n"); - printf(" branal - start live analysis\n"); - printf(" branal (l | live) - start live analysis (same as above)\n"); - printf(" branal (c | capture) [file] - start capturing packets to [file].\n"); - printf(" If [file] not given - captures to $HOME/.local/share/branal/captures\n"); - printf(" branal (f | file) - analyze the specified \n"); - printf(" branal (h | help) - display this help\n"); -} - -// starts live analyzer mode -void start_live_analyzer() { - // TODO: implement - printf("Not implemented\n"); -} +#include "commands.h" +#include "utils/fs.h" int main(int argc, char *argv[]) { create_necessary_directories(); - // start live analysis if no arguments provided - if (argc < 2) { - start_live_analyzer(); - return 0; - } + // start first command if no arguments provided + if (argc < 2) + return commands[0].handler(argc, argv); - if (strcmp("l", argv[1]) == 0 || strcmp("live", argv[1]) == 0) { - start_live_analyzer(); - } - else if (strcmp("c", argv[1]) == 0 || strcmp("capture", argv[1]) == 0) { - capturing_mode(argc >= 3 ? argv[2] : NULL); - } - else if (strcmp("h", argv[1]) == 0 || strcmp("help", argv[1]) == 0) { - print_help(); - } - else if (argc >= 3 && (strcmp("f", argv[1]) == 0 || strcmp("file", argv[1]) == 0)) { - analyze_file(argv[2]); - } - else { - printf("Command not recognized\n"); - printf("Use \"branal (h | help)\" for help\n"); - return 1; + for (size_t i = 0; i < commands_count; i++) { + if (is_command(commands[i], argv[1])) + return commands[i].handler(argc, argv); } - return 0; + command_not_recognized(); + return 1; } -- cgit v1.2.3