From 654641c87abb090798709d0cdd82494e1a6021b4 Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Wed, 3 Sep 2025 23:30:55 +0200 Subject: [PATCH] progress --- src/main.c | 749 +++++++++++++++++++---------------------------------- 1 file changed, 261 insertions(+), 488 deletions(-) diff --git a/src/main.c b/src/main.c index b1c5494..a3663ea 100644 --- a/src/main.c +++ b/src/main.c @@ -624,7 +624,7 @@ void load_log_file(char* path) { } // Funktion zum suchen eines Suchbegriffs innerhalb eines Strings (lowercase) -int search_in_string(const char* raw_string, const char* search_string) { +int search_in_string(char* raw_string, char* search_string) { char raw_string_lower[512]; // Puffer zum Speichern des zu durchsuchenden Strings char search_string_lower[256]; // Puffer zum Speichern des Suchbegriffs @@ -1199,6 +1199,78 @@ void show_filtered_entries(int num_shown) { } } +void print_filter_args() { + int total_filters = filters.status_count + filters.method_count + filters.ip_count + filters.time_count + filters.user_agent_count + filters.url_count; + + if (total_filters == 0) { + return; + } + + printf("-f "); + + if (filters.status_count > 0) { + printf("--status="); + for (int i = 0; i < filters.status_count; i++) { + if (i > 0) printf(","); + if (filters.status_filters[i].mode == FILTER_EXCLUDE) printf("!"); + printf("%d", filters.status_filters[i].code); + } + printf(" "); + } + + if (filters.method_count > 0) { + printf("--method="); + for (int i = 0; i < filters.method_count; i++) { + if (i > 0) printf(","); + if (filters.method_filters[i].mode == FILTER_EXCLUDE) printf("!"); + printf("%s", filters.method_filters[i].pattern); + } + printf(" "); + } + + if (filters.ip_count > 0) { + printf("--ip="); + for (int i = 0; i < filters.ip_count; i++) { + if (i > 0) printf(","); + if (filters.ip_filters[i].mode == FILTER_EXCLUDE) printf("!"); + printf("%s", filters.ip_filters[i].ip_address); + } + printf(" "); + } + + if (filters.user_agent_count > 0) { + printf("--useragent="); + for (int i = 0; i < filters.user_agent_count; i++) { + if (i > 0) printf(","); + if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) printf("!"); + printf("%s", filters.user_agent_filters[i].pattern); + } + printf(" "); + } + + if (filters.url_count > 0) { + printf("--url="); + for (int i = 0; i < filters.url_count; i++) { + if (i > 0) printf(","); + if (filters.url_filters[i].mode == FILTER_EXCLUDE) printf("!"); + printf("%s", filters.url_filters[i].pattern); + } + printf(" "); + } + + if (filters.combination_mode == 1) { + printf("--mode=or "); + }else { + printf("--mode=and "); + } + + printf("\n"); + + // TODO + if (filters.time_count > 0) { + printf("HINWEIS: %d Zeitraum-Filter sind aktiv, aber nur im interaktiven Modus verfügbar.\n", filters.time_count); + } +} void show_status() { printf("\nPREVIEW:\n"); @@ -1218,209 +1290,14 @@ void show_status() { if (total_filters == 0) { printf(" -> keine Filter gesetzt\n"); } else { - printf(" Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); + printf("\n "); + print_filter_args(); + printf("\n \n"); printf(" Ausschlussfilter (!) haben Vorrang, dann Einschlussfilter\n"); - printf("\n Gesetzt:\n"); - if (filters.status_count > 0) { - printf(" -> Status: "); - - int excludes = 0, includes = 0; - for (int i = 0; i < filters.status_count; i++) { - if (filters.status_filters[i].mode == FILTER_EXCLUDE) excludes++; - else includes++; - } - - if (excludes > 0) { - printf("!("); - int first = 1; - for (int i = 0; i < filters.status_count; i++) { - if (filters.status_filters[i].mode == FILTER_EXCLUDE) { - if (!first) printf(" OR "); - printf("%d", filters.status_filters[i].code); - first = 0; - } - } - printf(")"); - if (includes > 0) printf(" AND "); - } - - if (includes > 0) { - if (includes > 1) printf("("); - int first = 1; - for (int i = 0; i < filters.status_count; i++) { - if (filters.status_filters[i].mode == FILTER_INCLUDE) { - if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); - printf("%d", filters.status_filters[i].code); - first = 0; - } - } - if (includes > 1) printf(")"); - } - printf("\n"); - } - - if (filters.method_count > 0) { - printf(" -> Request-Method: "); - - int excludes = 0, includes = 0; - for (int i = 0; i < filters.method_count; i++) { - if (filters.method_filters[i].mode == FILTER_EXCLUDE) excludes++; - else includes++; - } - - if (excludes > 0) { - printf("!("); - int first = 1; - for (int i = 0; i < filters.method_count; i++) { - if (filters.method_filters[i].mode == FILTER_EXCLUDE) { - if (!first) printf(" OR "); - printf("%s", filters.method_filters[i].pattern); - first = 0; - } - } - printf(")"); - if (includes > 0) printf(" AND "); - } - - if (includes > 0) { - if (includes > 1) printf("("); - int first = 1; - for (int i = 0; i < filters.method_count; i++) { - if (filters.method_filters[i].mode == FILTER_INCLUDE) { - if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); - printf("%s", filters.method_filters[i].pattern); - first = 0; - } - } - if (includes > 1) printf(")"); - } - printf("\n"); - } - - if (filters.ip_count > 0) { - printf(" -> IP-Adresse: "); - - int excludes = 0, includes = 0; - for (int i = 0; i < filters.ip_count; i++) { - if (filters.ip_filters[i].mode == FILTER_EXCLUDE) excludes++; - else includes++; - } - - if (excludes > 0) { - printf("!("); - int first = 1; - for (int i = 0; i < filters.ip_count; i++) { - if (filters.ip_filters[i].mode == FILTER_EXCLUDE) { - if (!first) printf(" OR "); - printf("%s", filters.ip_filters[i].ip_address); - first = 0; - } - } - printf(")"); - if (includes > 0) printf(" AND "); - } - - if (includes > 0) { - if (includes > 1) printf("("); - int first = 1; - for (int i = 0; i < filters.ip_count; i++) { - if (filters.ip_filters[i].mode == FILTER_INCLUDE) { - if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); - printf("%s", filters.ip_filters[i].ip_address); - first = 0; - } - } - if (includes > 1) printf(")"); - } - printf("\n"); - } - - if (filters.user_agent_count > 0) { - printf(" -> UserAgent: "); - - int excludes = 0, includes = 0; - for (int i = 0; i < filters.user_agent_count; i++) { - if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) excludes++; - else includes++; - } - - if (excludes > 0) { - printf("!("); - int first = 1; - for (int i = 0; i < filters.user_agent_count; i++) { - if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) { - if (!first) printf(" OR "); - printf("\"%s\"", filters.user_agent_filters[i].pattern); - first = 0; - } - } - printf(")"); - if (includes > 0) printf(" AND "); - } - - if (includes > 0) { - if (includes > 1) printf("("); - int first = 1; - for (int i = 0; i < filters.user_agent_count; i++) { - if (filters.user_agent_filters[i].mode == FILTER_INCLUDE) { - if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); - printf("\"%s\"", filters.user_agent_filters[i].pattern); - first = 0; - } - } - if (includes > 1) printf(")"); - } - printf("\n"); - } - - if (filters.url_count > 0) { - printf(" -> Payload/Pfad: "); - - int excludes = 0, includes = 0; - for (int i = 0; i < filters.url_count; i++) { - if (filters.url_filters[i].mode == FILTER_EXCLUDE) excludes++; - else includes++; - } - - if (excludes > 0) { - printf("!("); - int first = 1; - for (int i = 0; i < filters.url_count; i++) { - if (filters.url_filters[i].mode == FILTER_EXCLUDE) { - if (!first) printf(" OR "); - printf("\"%s\"", filters.url_filters[i].pattern); - first = 0; - } - } - printf(")"); - if (includes > 0) printf(" AND "); - } - - if (includes > 0) { - if (includes > 1) printf("("); - int first = 1; - for (int i = 0; i < filters.url_count; i++) { - if (filters.url_filters[i].mode == FILTER_INCLUDE) { - if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); - printf("\"%s\"", filters.url_filters[i].pattern); - first = 0; - } - } - if (includes > 1) printf(")"); - } - printf("\n"); - } - - if (filters.time_count > 0) { - printf(" -> Zeitraum: %d Filter gesetzt\n", filters.time_count); - } - - int active_types = (filters.status_count > 0) + (filters.method_count > 0 ) + (filters.ip_count > 0) + - (filters.user_agent_count > 0) + (filters.time_count > 0) + (filters.url_count > 0); + int active_types = (filters.status_count > 0) + (filters.method_count > 0 ) + (filters.ip_count > 0) + (filters.user_agent_count > 0) + (filters.time_count > 0) + (filters.url_count > 0); if (active_types > 1) { - printf("\n%s-Verknüpfung (nur Einschlussfilter)\n", - filters.combination_mode == 0 ? "UND" : "ODER"); + printf(" %s-Verknüpfung (nur Einschlussfilter, Ausschlussfilter sind stets ODER-verknüpft)\n", filters.combination_mode == 0 ? "UND" : "ODER"); } } @@ -1480,7 +1357,7 @@ int handle_menu_shortcuts(int choice) { } // überall wo integer aus String-Input gelesen werden müssen. basiert auf strtol, was gegen Buffer Overflow sicher sein soll -int safe_read_integer(const char* prompt, int min_val, int max_val) { +int safe_read_integer(char* prompt, int min_val, int max_val) { char input[50]; int value; char *endptr; @@ -1516,7 +1393,7 @@ int safe_read_integer(const char* prompt, int min_val, int max_val) { } } -int safe_read_string(const char* prompt, char* buffer, int buffer_size) { +int safe_read_string(char* prompt, char* buffer, int buffer_size) { while (1) { printf("%s", prompt); if (scanf("%s", buffer) != 1) { @@ -1539,9 +1416,11 @@ int safe_read_string(const char* prompt, char* buffer, int buffer_size) { } } +// Menü mit standardisierter Navigation int read_menu_input() { char input[10]; - if (scanf("%9s", input) != 1) { + // scanf braucht eine Begrenzung, %s würde alle Zeichen in stdin lesen - buffer overflow + if (scanf("%5s", input) != 1) { clear_input_buffer(); return -1; } @@ -1552,113 +1431,20 @@ int read_menu_input() { if (strcmp(input, "q") == 0 || strcmp(input, "Q") == 0) return -4; char *endptr; + //string to long long number = strtol(input, &endptr, 10); + // Prüfen, ob Eingabe erfolgreich zu Zahl umgewandelt werden konnte - endptr speichert das Zeichen, das nicht mehr gepasst hat - muss also Nullterminator sein if (*endptr != '\0' || number < 0 || number > 999) { return -1; } return (int)number; } -void show_stats() { - int filtered_count = count_filtered_entries(); - int count_200 = 0, count_300 = 0, count_400 = 0, count_500 = 0; - int count_get = 0, count_post = 0, count_atypical = 0, count_other = 0; - long total_bytes = 0; - int unique_ips = 0; - - char ip_list[1000][50]; - int ip_count = 0; - - struct simple_time earliest_time = {31, 12, 9999, 23, 59, 59}; - struct simple_time latest_time = {1, 1, 1970, 0, 0, 0}; - - for (int i = 0; i < total_entries; i++) { - if (passes_filter(i)) { - if (all_entries[i].status_code >= 200 && all_entries[i].status_code < 300) count_200++; - else if (all_entries[i].status_code >= 300 && all_entries[i].status_code < 400) count_300++; - else if (all_entries[i].status_code >= 400 && all_entries[i].status_code < 500) count_400++; - else if (all_entries[i].status_code >= 500) count_500++; - - if (strcmp(all_entries[i].request_method, "GET") == 0) count_get++; - else if (strcmp(all_entries[i].request_method, "POST") == 0) count_post++; - else if (strcmp(all_entries[i].request_method, "ATYPICAL") == 0) count_atypical++; - else count_other++; - - total_bytes += all_entries[i].bytes_sent; - - int ip_exists = 0; - for (int j = 0; j < ip_count; j++) { - if (strcmp(ip_list[j], all_entries[i].ip_address) == 0) { - ip_exists = 1; - break; - } - } - if (!ip_exists && ip_count < 1000) { - strcpy(ip_list[ip_count], all_entries[i].ip_address); - ip_count++; - } - - if (compare_times(all_entries[i].time, earliest_time) < 0) { - earliest_time = all_entries[i].time; - } - if (compare_times(all_entries[i].time, latest_time) > 0) { - latest_time = all_entries[i].time; - } - } - } - - unique_ips = ip_count; - - printf("\nDATENANALYSE\n"); - printf(" Gesamte Einträge: %d\n Gefilterte Einträge: %d (%.1f%%)\n Eindeutige IPs: %d\n", - total_entries, filtered_count, - total_entries > 0 ? (filtered_count * 100.0 / total_entries) : 0.0, unique_ips); - - if (filtered_count > 0) { - printf(" Ø Anfragen pro IP: %.1f\n", (double)filtered_count / unique_ips); - - printf(" Zeitspanne: %02d.%02d.%d %02d:%02d:%02d - %02d.%02d.%d %02d:%02d:%02d\n", - earliest_time.day, earliest_time.month, earliest_time.year, - earliest_time.hour, earliest_time.minute, earliest_time.second, - latest_time.day, latest_time.month, latest_time.year, - latest_time.hour, latest_time.minute, latest_time.second); - - int total_minutes = (latest_time.year - earliest_time.year) * 525600 + - (latest_time.month - earliest_time.month) * 43800 + - (latest_time.day - earliest_time.day) * 1440 + - (latest_time.hour - earliest_time.hour) * 60 + - (latest_time.minute - earliest_time.minute); - - if (total_minutes > 0) { - printf(" Ø Anfragen/Minute: %.2f", (double)filtered_count / total_minutes); - if (total_minutes >= 60) { - printf("\n Ø Anfragen/Stunde: %.2f", (double)filtered_count * 60 / total_minutes); - } - printf("\n"); - } - - printf(" Status-Codes:\n 2xx:%d (%.1f%%)\n 3xx:%d (%.1f%%)\n 4xx:%d (%.1f%%)\n 5xx:%d (%.1f%%)\n", - count_200, count_200 * 100.0 / filtered_count, - count_300, count_300 * 100.0 / filtered_count, - count_400, count_400 * 100.0 / filtered_count, - count_500, count_500 * 100.0 / filtered_count); - - printf(" HTTP-Methoden:\n GET:%d (%.1f%%)\n POST:%d (%.1f%%)\n Andere:%d (%.1f%%)\n", - count_get, count_get * 100.0 / filtered_count, - count_post, count_post * 100.0 / filtered_count, - count_other, count_other * 100.0 / filtered_count); - - printf(" Datenumfang:\n %ld Bytes total\n Ø %.1f Bytes/Anfrage\n Fehlerrate: %.1f%%\n", - total_bytes, (double)total_bytes / filtered_count, - ((count_400 + count_500) * 100.0) / filtered_count); - } -} - void show_main_menu() { printf("\nHAUPTMENÜ\n"); printf("1. Filter verwalten\n"); printf("2. Daten anzeigen und exportieren\n"); - printf("3. Statistiken anzeigen\n"); + printf("3. Export (CSV, Timesketch-kompatibel)\n"); printf("4. Programm beenden\n"); printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); printf("Auswahl: "); @@ -1666,6 +1452,7 @@ void show_main_menu() { int menu_set_filters() { int choice = 0; + // Standardnavigation aus read_menu_input while (choice != -2 && choice != -3) { show_status(); @@ -1735,7 +1522,7 @@ int menu_set_filters() { struct time_filter new_time_filter = {0}; printf("STARTZEIT:\n"); - int start_year = safe_read_integer("Jahr (z.B. 2023): ", 1970, 2100); + int start_year = safe_read_integer("Jahr (z.B. 2025): ", 1970, 2100); if (start_year < 0) continue; int start_month = safe_read_integer("Monat (1-12): ", 1, 12); @@ -2089,6 +1876,7 @@ void menu_reset_filters() { void menu_filter_management() { int choice = 0; + // Standardnavigation aus read_menu_input while (choice != -2 && choice != -3) { show_status(); @@ -2128,6 +1916,7 @@ void menu_filter_management() { void menu_show_entries() { int choice = 0; int supress_preview = 0; + // Standardnavigation aus read_menu_input() while (choice != -2 && choice != -3) { if (supress_preview == 0) { show_status(); @@ -2180,10 +1969,112 @@ void menu_show_entries() { } } +// Funktionen zum setzen der Filter (existierende Datenstrukturen) +void add_status_filter(char* value, filter_mode_t mode) { + if (filters.status_count >= MAX_FILTERS) { + printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); + return; + } + // Kovertierung des Statuscodes zu long mit Error handling + char* endptr; + int status_code = strtol(value, &endptr, 10); + if (*endptr != '\n' ){ + printf("ERROR: Ungültiger Wert im Statuscode-Filter: %s", value); + } + if (status_code < 100 || status_code > 599) { + printf("WARNING: Invalid status code: %s (must be 100-599)\n", value); + return; + } + + // setzen des Filters + filters.status_filters[filters.status_count].code = status_code; + filters.status_filters[filters.status_count].mode = mode; + filters.status_count++; + + printf("DEBUG: Filter hinzugefügt: %s%d\n", mode == FILTER_EXCLUDE ? "!" : "", status_code); +} + +void add_ip_filter(char* value, filter_mode_t mode) { + if (filters.ip_count >= MAX_FILTERS) { + printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); + return; + } + + // einfache Plausibilitätsprüfung hinsichtlich der Länge + if (strlen(value) >= sizeof(filters.ip_filters[0].ip_address)) { + printf("WARNING: IP-Adresse zu lang: %s\n", value); + return; + } + + // setzen des Filters + strcpy(filters.ip_filters[filters.ip_count].ip_address, value); + filters.ip_filters[filters.ip_count].mode = mode; + filters.ip_count++; + + printf("DEBUG: IP-Adressfilter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); +} + +// gleiche Mechanik wie bei IP-Adresse +void add_method_filter(char* value, filter_mode_t mode) { + if (filters.method_count >= MAX_FILTERS) { + printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); + return; + } + + if (strlen(value) >= sizeof(filters.method_filters[0].pattern)) { + printf("WARNING: Methoden-Filterwert zu lang: %s\n", value); + return; + } + + strcpy(filters.method_filters[filters.method_count].pattern, value); + filters.method_filters[filters.method_count].mode = mode; + filters.method_count++; + + printf("DEBUG: Methoden-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); +} + +// gleiche Mechanik wie bei IP-Adresse +void add_useragent_filter(char* value, filter_mode_t mode) { + if (filters.user_agent_count >= MAX_FILTERS) { + printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); + return; + } + + if (strlen(value) >= sizeof(filters.user_agent_filters[0].pattern)) { + printf("WARNING: User agent Filterwert zu lang: %s\n", value); + return; + } + + strcpy(filters.user_agent_filters[filters.user_agent_count].pattern, value); + filters.user_agent_filters[filters.user_agent_count].mode = mode; + filters.user_agent_count++; + + printf("DEBUG: User Agent Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); +} + +// gleiche Mechanik wie bei IP-Adresse +void add_url_filter(char* value, filter_mode_t mode) { + if (filters.url_count >= MAX_FILTERS) { + printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); + return; + } + + if (strlen(value) >= sizeof(filters.url_filters[0].pattern)) { + printf("WARNING: URL/Payload Filterwert zu lang: %s\n", value); + return; + } + + strcpy(filters.url_filters[filters.url_count].pattern, value); + filters.url_filters[filters.url_count].mode = mode; + filters.url_count++; + + printf("DEBUG: URL/Payload-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); +} + // Funktion zum Parsen der Filter-Werte, die mit --= übergeben werden. // values_str sind die Werte hinter dem =, filter_type die Werte vor dem = // filter_type wird von parse_filter_argument() übergeben -void parse_filter_values(const char* values_str, const char* filter_type) { +void parse_filter_values(char* values_str, char* filter_type) { char values_local[1024]; // Werte in lokale Variable einlesen, Nullterminator setzen strncpy(values_local, values_str, sizeof(values_local) - 1); @@ -2222,192 +2113,56 @@ void parse_filter_values(const char* values_str, const char* filter_type) { } } -// Funktionen zum setzen der Filter (existierende Datenstrukturen) -void add_status_filter(const char* value, filter_mode_t mode) { - if (filters.status_count >= MAX_FILTERS) { - printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); - return; - } - // Kovertierung des Statuscodes zu long mit Error handling - int status_code = strtol(value, &endptr, 10); - if (endptr != '\n' ){ - printf("ERROR: Ungültiger Wert im Statuscode-Filter: %s", value); - } - if (status_code < 100 || status_code > 599) { - printf("WARNING: Invalid status code: %s (must be 100-599)\n", value); - return; - } - - // setzen des Filters - filters.status_filters[filters.status_count].code = status_code; - filters.status_filters[filters.status_count].mode = mode; - filters.status_count++; - - printf("DEBUG: Filter hinzugefügt: %s%d\n", mode == FILTER_EXCLUDE ? "!" : "", status_code); -} - -void add_ip_filter(const char* value, filter_mode_t mode) { - if (filters.ip_count >= MAX_FILTERS) { - printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); - return; - } - - // einfache Plausibilitätsprüfung hinsichtlich der Länge - if (strlen(value) >= sizeof(filters.ip_filters[0].ip_address)) { - printf("WARNING: IP-Adresse zu lang: %s\n", value); - return; - } - - // setzen des Filters - strcpy(filters.ip_filters[filters.ip_count].ip_address, value); - filters.ip_filters[filters.ip_count].mode = mode; - filters.ip_count++; - - printf("DEBUG: IP-Adressfilter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); -} - -// gleiche Mechanik wie bei IP-Adresse -void add_method_filter(const char* value, filter_mode_t mode) { - if (filters.method_count >= MAX_FILTERS) { - printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); - return; - } - - if (strlen(value) >= sizeof(filters.method_filters[0].pattern)) { - printf("WARNING: Methoden-Filterwert zu lang: %s\n", value); - return; - } - - strcpy(filters.method_filters[filters.method_count].pattern, value); - filters.method_filters[filters.method_count].mode = mode; - filters.method_count++; - - printf("DEBUG: Methoden-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); -} - -// gleiche Mechanik wie bei IP-Adresse -void add_useragent_filter(const char* value, filter_mode_t mode) { - if (filters.user_agent_count >= MAX_FILTERS) { - printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); - return; - } - - if (strlen(value) >= sizeof(filters.user_agent_filters[0].pattern)) { - printf("WARNING: User agent Filterwert zu lang: %s\n", value); - return; - } - - strcpy(filters.user_agent_filters[filters.user_agent_count].pattern, value); - filters.user_agent_filters[filters.user_agent_count].mode = mode; - filters.user_agent_count++; - - printf("DEBUG: User Agent Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); -} - -// gleiche Mechanik wie bei IP-Adresse -void add_url_filter(const char* value, filter_mode_t mode) { - if (filters.url_count >= MAX_FILTERS) { - printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value); - return; - } - - if (strlen(value) >= sizeof(filters.url_filters[0].pattern)) { - printf("WARNING: URL/Payload Filterwert zu lang: %s\n", value); - return; - } - - strcpy(filters.url_filters[filters.url_count].pattern, value); - filters.url_filters[filters.url_count].mode = mode; - filters.url_count++; - - printf("DEBUG: URL/Payload-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value); -} - // Filter-Argument Parser -int parse_filter_argument(const char* arg) { +int parse_filter_argument(char* arg) { if (!starts_with(arg, "--")) { return 0; } - // = finden - const char* equals_pos = strchr(arg, '='); + // = finden, strchr gibt den Pointer auf das = zurück + char* equals_pos = strchr(arg, '='); if (equals_pos == NULL) { - printf("WARNING: Invalid filter format (missing =): %s\n", arg); + printf("WARNING: Ungültiges Filter-Format, kein '=' gefunden: %s\n", arg); return 0; } - // filter-Typ parsen - int type_len = equals_pos - arg - 2; // Position anpassen, + //int filterstr_start = arg -2; + // filter-Typ parsen: 1. Länge des Strings errechnen (Position des '=' abzüglich Startposition des Strings, abzüglich 2 (für die '--' am Anfang)) + int filterstr_length = equals_pos - arg -2; + // 2. char filter_type[50]; - strncpy(filter_type, arg + 2, type_len); - filter_type[type_len] = '\0'; + strncpy(filter_type, arg +2, filterstr_length); + filter_type[filterstr_length] = '\0'; + + // Filter-Werte (nach den =) + char* values = equals_pos + 1; - // Extract values (after =) - const char* values = equals_pos + 1; - - // Parse based on filter type - if (strcmp(filter_type, "status") == 0) { - parse_filter_values(values, add_status_filter); - } else if (strcmp(filter_type, "ip") == 0) { - parse_filter_values(values, add_ip_filter); - } else if (strcmp(filter_type, "method") == 0) { - parse_filter_values(values, add_method_filter); - } else if (strcmp(filter_type, "useragent") == 0) { - parse_filter_values(values, add_useragent_filter); - } else if (strcmp(filter_type, "url") == 0) { - parse_filter_values(values, add_url_filter); - } else if (strcmp(filter_type, "mode") == 0) { - if (strcmp(values, "and") == 0 || strcmp(values, "AND") == 0) { + if (strstr(filter_type, "status") != NULL) { + parse_filter_values(values, "status"); + } else if (strstr(filter_type, "ip") != NULL) { + parse_filter_values(values, "ip"); + } else if (strstr(filter_type, "method") != NULL) { + parse_filter_values(values, "method"); + } else if (strstr(filter_type, "useragent") != NULL) { + parse_filter_values(values, "useragent"); + } else if (strstr(filter_type, "url") != NULL) { + parse_filter_values(values, "url"); + } else if (strstr(filter_type, "mode") != NULL) { + if (strstr(values, "and") != NULL || strstr(values, "AND") != NULL) { filters.combination_mode = 0; - printf("Set filter combination mode: AND\n"); - } else if (strcmp(values, "or") == 0 || strcmp(values, "OR") == 0) { + printf("DEBUG: AND-Modus gesetzt\n"); + } else if (strstr(values, "or") != NULL || strstr(values, "OR") != NULL) { filters.combination_mode = 1; - printf("Set filter combination mode: OR\n"); + printf("DEBUG: OR-Modus gesetzt\n"); } else { - printf("WARNING: Invalid mode value: %s (use 'and' or 'or')\n", values); + printf("WARNING: ungültiger Modus-Wert: %s ('and' oder 'oder' möglich)\n", values); } } else { - printf("WARNING: Unknown filter type: %s\n", filter_type); + printf("WARNING: Unbekannter Filtertyp: %s\n", filter_type); return 0; } - return 1; // Successfully parsed -} - -// Add this to your main() function after allocate_initial_memory() -void parse_command_line_filters(int argc, char* argv[]) { - int has_filter_flag = 0; - - // First, check if -f flag is present - for (int i = 2; i < argc; i++) { - if (strcmp(argv[i], "-f") == 0) { - has_filter_flag = 1; - break; - } - } - - if (!has_filter_flag) { - return; // No filter flag, skip filter parsing - } - - printf("Parsing command line filters...\n"); - - // Parse all filter arguments - for (int i = 2; i < argc; i++) { - if (starts_with(argv[i], "--")) { - parse_filter_argument(argv[i]); - } - } - - // Show summary of parsed filters - int total_filters = filters.status_count + filters.method_count + filters.ip_count + - filters.time_count + filters.user_agent_count + filters.url_count; - - if (total_filters > 0) { - printf("Successfully parsed %d filters from command line.\n", total_filters); - } else { - printf("No valid filters found in command line arguments.\n"); - } + return 1; } void print_help(char* binary) { @@ -2415,7 +2170,8 @@ void print_help(char* binary) { printf("Verwendung:\n"); printf(" %s -i Interaktiver Modus (Filter/Analyse/Export)\n", binary); printf(" %s -e Export generieren\n", binary); - printf(" %s -h Diese Hilfe anzeigen\n", binary); + printf(" %s -f [FILTER...] Mit Kommandozeilen-Filtern\n", binary); + printf(" %s -h Diese Hilfe anzeigen\n", binary); printf("\nArgumente:\n"); printf(" Pfad zu einer einzelnen *.log Datei ODER zu einem Ordner,\n"); @@ -2425,8 +2181,29 @@ void print_help(char* binary) { printf(" -i Startet interaktiven Modus mit Filtern (Status, Methode, IP, Zeitraum,\n"); printf(" User-Agent, URL-Teilstring), Vorschau, Statistiken und CSV-Export (Timesketch).\n"); printf(" -e Generiert Timesketch-kompatible CSV-Datei, nimmt optional Dateinamen entgegen.\n"); + printf(" -f Aktiviert Kommandozeilen-Filter. Muss von Filter-Argumenten gefolgt werden.\n"); printf(" -h Zeigt diese Hilfe an.\n"); + printf("\nKOMMNDOZEILEN-FILTER (nur mit -f Flag):\n"); + printf(" --status=CODE[,CODE...] HTTP-Status-Codes (z.B. 200,404,500)\n"); + printf(" --ip=ADRESSE[,ADRESSE...] IP-Adressen (exakte Übereinstimmung)\n"); + printf(" --method=METHODE[,METHODE...] HTTP-Methoden (z.B. GET,POST,ATYPICAL)\n"); + printf(" --useragent=TEXT[,TEXT...] User-Agent Teilstrings (z.B. bot,crawler)\n"); + printf(" --url=PFAD[,PFAD...] URL-Pfad Teilstrings (z.B. .git,.php,wp-)\n"); + printf(" --mode=MODE Filtermodus: 'and' oder 'or' (Standard: and)\n"); + + printf("\nFILTER-SYNTAX:\n"); + printf(" Einschluss: Wert (nur Einträge MIT diesem Wert)\n"); + printf(" Ausschluss: !Wert (alle Einträge OHNE diesen Wert)\n"); + printf(" Mehrere: Wert1,Wert2 (kommagetrennt, keine Leerzeichen)\n"); + printf(" Gemischt: Wert1,!Wert2 (Wert1 einschließen, Wert2 ausschließen)\n"); + + printf("\nFILTER-LOGIK:\n"); + printf(" - Ausschluss-Filter (!) haben IMMER Vorrang vor Einschluss-Filtern\n"); + printf(" - AND-Modus: ALLE Einschluss-Filter pro Kategorie müssen zutreffen\n"); + printf(" - OR-Modus: MINDESTENS EIN Einschluss-Filter pro Kategorie muss zutreffen\n"); + printf(" - Ausschluss-Filter arbeiten kategorie-intern immer im OR-Modus\n"); + printf("\nUnterstützte Eingaben:\n"); printf(" - Normale NGINX-Access-Logs: *.log\n"); printf(" - Rotierte Logs: *.log.1, *.log.2, ... (rein textbasiert)\n"); @@ -2443,12 +2220,6 @@ void print_help(char* binary) { printf("\nBeispielzeile (eine Zeile pro Request):\n"); printf(" 0.0.0.0 - - [31/Aug/2025:00:11:42 +0000] \"GET /.git/config HTTP/1.1\" 400 255 \"-\" \"Mozilla/5.0\" \"-\"\n"); - printf("\nBeispiele:\n"); - printf(" - Einzeldatei analysieren:\n"); - printf(" %s /var/log/nginx/access.log -i\n", binary); - printf(" - Verzeichnis mit mehreren .log / .log.N Dateien:\n"); - printf(" %s /var/log/nginx/ -i\n", binary); - printf("\nCSV-Export (Timesketch-kompatibel):\n"); printf(" Spalten: datetime, timestamp_desc, ip_address, method, url_path, status_code,\n"); printf(" bytes_sent, user_agent, source_file, parsing_timestamp\n"); @@ -2457,9 +2228,9 @@ void print_help(char* binary) { printf(" - Parser erwartet das obige Standardformat. Abweichungen können zum Abbruch führen.\n"); printf(" - Zeitzone aus dem Log wird gelesen, aber intern als einfache Felder verarbeitet.\n"); printf(" - ATYPICAL-Methode: für fehlerhafte/binäre Requests innerhalb der \"request\"-Spalte.\n"); + printf(" - Zeitraum-Filter sind nur im interaktiven Modus verfügbar (nicht über -f).\n"); } - int main(int argc, char* argv[]) { if (argc < 3) { print_help(argv[0]); @@ -2472,7 +2243,6 @@ int main(int argc, char* argv[]) { int flag_interactive = 0; int flag_export = 0; - int flag_filters = 0; int flag_help = 0; char export_filename[90]; @@ -2491,8 +2261,15 @@ int main(int argc, char* argv[]) { flag_has_filename = 1; i++; // Schleife weiter iterieren } - } else if (strcmp(argv[i], "--filters")==0) { - flag_filters = 1; + } else if (strcmp(argv[i], "-f")==0) { + // parsen der nachfolgenden Argumente --ip= usw. + for (int j = i + 1; j < argc; j++) { + if (starts_with(argv[j], "--")) { + parse_filter_argument(argv[j]); + }else{ + break; + } + } } else if (strcmp(argv[i], "-h")==0) { flag_help = 1; @@ -2506,18 +2283,14 @@ int main(int argc, char* argv[]) { load_log_file(argv[1]); if (total_entries == 0) { - printf("Keine gültigen Log-Einträge gefunden. Überprüfen Sie den Pfad und die Dateiformate.\n"); + printf("ERROR: Keine gültigen Log-Einträge gefunden. Überprüfen Sie den Pfad und die Dateiformate.\n"); cleanup_memory(); return 1; } int choice = 0; - int stats_show = 0; + // Standardnavigation aus read_menu_input while (choice != 4 && choice != -4) { show_status(); - if (stats_show == 1) { - show_stats(); - stats_show = 0; - } show_main_menu(); choice = read_menu_input(); @@ -2533,7 +2306,7 @@ int main(int argc, char* argv[]) { } else if (choice == 2) { menu_show_entries(); } else if (choice == 3) { - stats_show = 1; + export_filtered_entries(0); } else if (choice == 4) { printf("Programmende\n"); break; @@ -2553,7 +2326,7 @@ int main(int argc, char* argv[]) { } else if (flag_help == 1){ print_help(argv[0]); return 1; - } + } cleanup_memory(); return 0; } \ No newline at end of file