From 3e990ff05e8b09996a74c299b6f3d2e03992c88a Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Tue, 2 Sep 2025 13:03:35 +0200 Subject: [PATCH] progress --- bin/main | Bin 16424 -> 48480 bytes src/main.c | 735 +++++++++++++++++++++++++++-------------------------- 2 files changed, 372 insertions(+), 363 deletions(-) diff --git a/bin/main b/bin/main index 2d1beebce799bc12def4a7168bf495399444b0c1..43dc4e106ae3671033d1868dda9425adab7bee13 100755 GIT binary patch literal 48480 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 literal 16424 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 l(sK!pU0JIC`TBnNeLm;hF6+|$>}>Xr>KmDxd #include // library für Interaktion mit Ordnerstrukturen #include // library für is_directory: Unterscheidung zwischen Dateien und Ordnern +#include // um aktuelle Zeit zu generieren #define MAX_LINE_LENGTH_BUF 2048 #define INITIAL_ENTRIES 1000 // globale Variable zur initialen Speicherallokation in allocate_initial_memory(). Wird falls nötig um GROWTH_FACTOR erweitert -#define GROWTH_FACTOR 2 // wird in mem_expand_dynamically() genutzt, um den Speicher zu vergrößern +#define GROWTH_FACTOR 1.1 // wird in mem_expand_dynamically() genutzt, um den Speicher zu vergrößern #define MAX_FILTERS 100 #define MAX_REQUEST_LENGTH 1024 // das hohe Limit ist erforderlich, da teilweise ausufernde JSON-Requests in nginx auflaufen können. #define TOP_X 20 // definiert die Anzahl der Einträge, die in den Top-Listen angezeigt werden sollen @@ -51,6 +52,8 @@ struct log_entry { struct simple_time time; char referrer[128]; char user_agent[256]; + char source_file[256]; + char parsing_timestamp[32]; }; // Struktur für einen Status-Filtereintrag mit Inhalt & Modus @@ -222,7 +225,7 @@ void mem_expand_dynamically() { int old_max = max_entries; max_entries = max_entries * GROWTH_FACTOR; - printf("Dynamische Speichererweiterung von %d auf %d Einträge um Faktor %d\n", old_max, max_entries, GROWTH_FACTOR); + printf("Dynamische Speichererweiterung von %d auf %d Einträge um Faktor %f\n", old_max, max_entries, GROWTH_FACTOR); struct log_entry *new_ptr = realloc(all_entries, max_entries * sizeof(struct log_entry)); @@ -250,6 +253,20 @@ void allocate_initial_memory() { printf("Speicher erfolgreich alloziert für %d Log-Einträge (%lu Bytes)\n", max_entries, (unsigned long)(max_entries * sizeof(struct log_entry))); } +void get_current_timestamp(char* buffer, int buffer_size) { + time_t raw_time; + struct tm *time_info; + + time(&raw_time); + time_info = localtime(&raw_time); + + if (time_info != NULL) { + strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", time_info); + } else { + snprintf(buffer, buffer_size, "UNKNOWN"); + } +} + // Hilfsfunktion zum Prüfen, ob es sich beim Pfad um ein Directory handelt - für rekursives Parsen int is_directory(char* path) { struct stat path_stat; @@ -293,7 +310,7 @@ Fehleranfällig, wenn das Logformat nicht dem Standard entspricht - das gilt abe '"$http_user_agent" "$http_x_forwarded_for"'; */ // 107.170.27.248 - - [31/Aug/2025:00:11:42 +0000] "GET /.git/config HTTP/1.1" 400 255 "-" "Mozilla/5.0; Keydrop.io/1.0(onlyscans.com/about);" "-" -int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer auf die Zeile und einen Index entgegen - dieser ist anfangs 0 (globale Variable) und wird pro Eintrag inkrementiert +int parse_simple_log_line(char* line, int entry_index, char* source_file) { // Nimmt den Pointer auf die Zeile und einen Index entgegen - dieser ist anfangs 0 (globale Variable) und wird pro Eintrag inkrementiert char* current_pos = line; // leere Zeichen am Anfang überspringen current_pos = skip_spaces(current_pos); @@ -386,7 +403,6 @@ int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer au current_pos = skip_spaces(current_pos); // Weiter mit dem String innerhalb "", aus dem die HTTP-Methode und der URL-Pfad zu entnehmen ist - // Enhanced parsing to handle malformed binary requests gracefully if (*current_pos == '"') { current_pos++; // 107.170.27.248 - - [31/Aug/2025:00:11:42 +0000] "GET /.git/config HTTP/1.1" 400 255 "-" "Mozilla/5.0; Keydrop.io/1.0(onlyscans.com/about);" "-" @@ -433,8 +449,8 @@ int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer au } } else { // in NGINX treten gelegentlich fehlerhafte Requests auf, die binäre Daten übersenden, sodass normales parsen nicht möglich ist. - // der entsprechende Eintrag wird daher mit dem String "MALFORMED" repräsentiert - strcpy(all_entries[entry_index].request_method, "MALFORMED"); + // der entsprechende Eintrag wird daher mit dem String "ATYPICAL" repräsentiert + strcpy(all_entries[entry_index].request_method, "ATYPICAL"); // Read entire quoted content into url_path for forensic analysis int i = 0; @@ -452,8 +468,6 @@ int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer au } if (*current_pos == '"') current_pos++; - - printf("INFO: Fehlerhaften Logeintrag entdeckt, speichere mit MALFORMED-Eintrag.\n"); } // 107.170.27.248 - - [31/Aug/2025:00:11:42 +0000] "GET /.git/config HTTP/1.1" 400 255 "-" "Mozilla/5.0; Keydrop.io/1.0(onlyscans.com/about);" "-" // ^ @@ -512,30 +526,29 @@ int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer au printf("ERROR: Unerwartetes Log-Format. Lediglich mit standard-nginx-accesslog kompatibel.\nDer Fehler ist beim Prüfen des User-Agent aufgetreten. Dieser steht innerhalb eines Strings:\n\"Mozilla/5.0; Keydrop.io/1.0(onlyscans.com/about);\"\n\n"); cleanup_and_exit(); } - return 1; + get_current_timestamp(all_entries[entry_index].parsing_timestamp, sizeof(all_entries[entry_index].parsing_timestamp)); + // Dateinamen in das Feld schreiben - strncpy um Buffer overflow zu verhindern + strncpy(all_entries[entry_index].source_file, source_file, sizeof(all_entries[entry_index].source_file) - 1); + // strncpy setzt keinen Nullterminator, dieser muss am Ende eingefügt werden + all_entries[entry_index].source_file[sizeof(all_entries[entry_index].source_file) - 1] = '\0'; } -// TODO void load_regular_file(char* filename) { FILE* file = fopen(filename, "r"); if (file == NULL) { printf("ERROR: Kann Datei '%s' nicht öffnen!\n", filename); return; } - printf("Lade Datei: %s\n", filename); char line[MAX_LINE_LENGTH_BUF]; int loaded_from_this_file = 0; - while (fgets(line, sizeof(line), file) != NULL) { mem_expand_dynamically(); - - if (parse_simple_log_line(line, total_entries)) { + if (parse_simple_log_line(line, total_entries, filename)) { total_entries++; loaded_from_this_file++; } } - fclose(file); printf(" -> %d Einträge aus dieser Datei geladen.\n", loaded_from_this_file); } @@ -960,276 +973,24 @@ int count_filtered_entries() { return count; } -void show_status() { - printf("\n========== SYSTEM STATUS ==========\n"); - - if (total_entries > 0) { - printf("✅ Log-Daten: %d Einträge geladen\n", total_entries); - printf(" Speicherverbrauch: %lu Bytes (%d Einträge Kapazität)\n", (unsigned long)(max_entries * sizeof(struct log_entry)), max_entries); - } else { - printf("❌ Keine Log-Daten geladen\n"); - } - - printf("\n🔍 Aktive Filter-Logik:\n"); - 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(" Keine Filter gesetzt → alle Einträge werden angezeigt\n"); - } else { - printf(" Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); - printf(" Regel: Ausschlussfilter (!) haben Vorrang, dann Einschlussfilter\n"); - printf("\n Filter-Ausdruck:\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++; - } - - // Ausschlussfilter (immer im ODER-Modus) - 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 "); - } - - // Einschlussfilter (folgen dem gesetzten Modus) - 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(" 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: "); - - 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(" URL: "); - - 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(" Time: %d Filter(s) gesetzt\n", filters.time_count); - } - - // Zeigt aktuellen Modus - 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 - Ausschlussfilter vorrangig\n", - filters.combination_mode == 0 ? "UND" : "ODER"); - } - } - - if (total_entries > 0) { - int filtered_count = count_filtered_entries(); - printf("\n📊 Ergebnis: %d von %d Einträgen entsprechen den Filtern\n", filtered_count, total_entries); - } - - printf("===================================\n"); -} - -long long time_to_unix_microseconds(struct simple_time time) { - int days_since_1970 = (time.year - 1970) * 365 + (time.year - 1970) / 4; - - int days_in_months[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - if (time.month >= 1 && time.month <= 12) { - days_since_1970 += days_in_months[time.month - 1]; - } - - if (time.month > 2 && ((time.year % 4 == 0 && time.year % 100 != 0) || time.year % 400 == 0)) { - days_since_1970 += 1; - } - - days_since_1970 += time.day - 1; - - long long seconds = (long long)days_since_1970 * 24 * 60 * 60; - seconds += time.hour * 60 * 60; - seconds += time.minute * 60; - seconds += time.second; - - return seconds * 1000000LL; -} - +// notwendig, um konformes Timestamp-Format aus simple_time struct zu generieren. Unterstützt derzeit nur UTC void format_iso8601_time(struct simple_time time, char* buffer, int buffer_size) { snprintf(buffer, buffer_size, "%04d-%02d-%02dT%02d:%02d:%02d+00:00", time.year, time.month, time.day, time.hour, time.minute, time.second); } +//Export in Timesketch-kompatiblem Format void export_filtered_entries() { - printf("Dateiname für Timesketch Export eingeben (ohne .csv): "); - char filename[95]; - if (scanf("%94s", filename) != 1) { + printf("Dateiname für Timesketch-Export eingeben (ohne .csv): "); + //90 chars + delimiter + char filename[91]; + if (scanf("%90s", filename) != 1) { printf("FEHLER: Ungültiger Dateiname!\n"); clear_input_buffer(); return; } clear_input_buffer(); - + // Dateiendung strcat(filename, ".csv"); FILE* file = fopen(filename, "w"); @@ -1238,7 +999,8 @@ void export_filtered_entries() { return; } - fprintf(file, "message,datetime,timestamp_desc,timestamp,ip_address,method,url_path,status_code,bytes_sent,user_agent\n"); + // CSV-Kopfzeile für Timesketch-Kompatibilität + fprintf(file, "datetime,timestamp_desc,ip_address,method,url_path,status_code,bytes_sent,user_agent,source_file,parsing_timestamp\n"); int exported_count = 0; char iso_datetime[32]; @@ -1248,27 +1010,17 @@ void export_filtered_entries() { if (passes_filter(i)) { format_iso8601_time(all_entries[i].time, iso_datetime, sizeof(iso_datetime)); - long long unix_timestamp = time_to_unix_microseconds(all_entries[i].time); - snprintf(message_text, sizeof(message_text), - "%s %s %s - Status: %d, Bytes: %d", - all_entries[i].ip_address, - all_entries[i].request_method, - all_entries[i].url_path, - all_entries[i].status_code, - all_entries[i].bytes_sent, - all_entries[i].user_agent); - - fprintf(file, "\"%s\",\"%s\",\"HTTP Access Log\",%lld,\"%s\",\"%s\",\"%s\",%d,%d\n", - message_text, - iso_datetime, - unix_timestamp, - all_entries[i].ip_address, - all_entries[i].request_method, - all_entries[i].url_path, - all_entries[i].status_code, - all_entries[i].bytes_sent, - all_entries[i].user_agent); + fprintf(file, "\"%s\",\"HTTP Access Log\",\"%s\",\"%s\",\"%s\",%d,%d,\"%s\",\"%s\",\"%s\"\n", + iso_datetime, + all_entries[i].ip_address, + all_entries[i].request_method, + all_entries[i].url_path, + all_entries[i].status_code, + all_entries[i].bytes_sent, + all_entries[i].user_agent, + all_entries[i].source_file, + all_entries[i].parsing_timestamp); exported_count++; } @@ -1397,30 +1149,52 @@ void show_top_user_agents() { } } -void show_filtered_entries() { +void show_filtered_entries(int num_shown) { int shown_count = 0; - printf("\n=== GEFILTERTE LOG-EINTRÄGE ===\n"); + printf("\nLOGDATEN:\n"); printf("IP-Adresse | Methode | URL | Status | Bytes | User Agent | Zeit\n"); printf("-----------------|---------|------------------------|--------|-------|--------------------------------------|------------------\n"); - for (int i = 0; i < total_entries; i++) { - if (passes_filter(i)) { - printf("%-16s | %-7s | %-22s | %-6d | %-5d | %-36s | %02d.%02d.%d %02d:%02d:%02d\n", - all_entries[i].ip_address, - all_entries[i].request_method, - all_entries[i].url_path, - all_entries[i].status_code, - all_entries[i].bytes_sent, - all_entries[i].user_agent, - all_entries[i].time.day, - all_entries[i].time.month, - all_entries[i].time.year, - all_entries[i].time.hour, - all_entries[i].time.minute, - all_entries[i].time.second); - - shown_count++; + if (num_shown != 0) { + for (int i = 0; i < num_shown; i++) { + if (passes_filter(i)) { + printf("%-16s | %-7s | %-22s | %-6d | %-5d | %-36s | %02d.%02d.%d %02d:%02d:%02d\n", + all_entries[i].ip_address, + all_entries[i].request_method, + all_entries[i].url_path, + all_entries[i].status_code, + all_entries[i].bytes_sent, + all_entries[i].user_agent, + all_entries[i].time.day, + all_entries[i].time.month, + all_entries[i].time.year, + all_entries[i].time.hour, + all_entries[i].time.minute, + all_entries[i].time.second); + + shown_count++; + } + } + } else { + for (int i = 0; i < total_entries; i++) { + if (passes_filter(i)) { + printf("%-16s | %-7s | %-22s | %-6d | %-5d | %-36s | %02d.%02d.%d %02d:%02d:%02d\n", + all_entries[i].ip_address, + all_entries[i].request_method, + all_entries[i].url_path, + all_entries[i].status_code, + all_entries[i].bytes_sent, + all_entries[i].user_agent, + all_entries[i].time.day, + all_entries[i].time.month, + all_entries[i].time.year, + all_entries[i].time.hour, + all_entries[i].time.minute, + all_entries[i].time.second); + + shown_count++; + } } } @@ -1431,6 +1205,241 @@ void show_filtered_entries() { } } +// Statusanzeige +void show_status() { + printf("PREVIEW:\n"); + show_filtered_entries(10); + printf("\nSTATUS\n"); + + if (total_entries > 0) { + printf(" %d Logzeilen in Datenstruktur\n", total_entries); + printf(" Speicherbelegung: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry))); + } else { + printf(" ERROR: Keine Einträge in Datenstruktur!\n"); + } + + printf("\n Aktive Filter:\n"); + 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(" -> keine Filter gesetzt\n"); + } else { + printf(" Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); + 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++; + } + + // Ausschlussfilter (immer im ODER-Modus) + 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 "); + } + + // Einschlussfilter (folgen dem gesetzten Modus) + 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); + } + + // Zeigt aktuellen Modus + 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"); + } + } + + if (total_entries > 0) { + int filtered_count = count_filtered_entries(); + printf("\n ERGEBNIS: \n %d von %d Einträgen entsprechen den Filtern\n", filtered_count, total_entries); + } + +} + void show_statistics() { int count_200 = 0; int count_404 = 0; @@ -1438,7 +1447,7 @@ void show_statistics() { int total_bytes = 0; int filtered_count = 0; - printf("\n=== STATISTIKEN ===\n"); + printf("\nSTATISTIKEN\n"); for (int i = 0; i < total_entries; i++) { if (passes_filter(i)) { @@ -1451,66 +1460,66 @@ void show_statistics() { } } - printf("Gefilterte Einträge: %d von %d\n", filtered_count, total_entries); - printf("Erfolgreiche Anfragen (200): %d\n", count_200); - printf("Nicht gefunden (404): %d\n", count_404); - printf("Server-Fehler (5xx): %d\n", count_500); - printf("Gesamte übertragene Bytes: %d\n", total_bytes); + printf(" Gefilterte Einträge: %d von %d\n", filtered_count, total_entries); + printf(" Erfolgreiche Anfragen (200): %d\n", count_200); + printf(" Nicht gefunden (404): %d\n", count_404); + printf(" Server-Fehler (5xx): %d\n", count_500); + printf(" Gesamte übertragene Bytes: %d\n", total_bytes); if (filtered_count > 0) { - printf("Durchschnittliche Bytes pro Anfrage: %d\n", total_bytes / filtered_count); + printf(" Durchschnittliche Bytes pro Anfrage: %d\n", total_bytes / filtered_count); } } void print_filter_examples() { printf("\nFILTER-DOKUMENTATION\n"); - printf("\n🔴 EXKLUSIONS-FILTER (immer OR-Logik, unabhängig vom Modus):\n"); + printf("\nEXKLUSIONS-FILTER (immer OR-Logik, unabhängig vom Modus):\n"); printf("Beispiel: !('uptime' OR 'scanner')\n"); - printf("→ Schließt ALLE Einträge aus, die 'uptime' ODER 'scanner' enthalten\n\n"); + printf("> Schließt ALLE Einträge aus, die 'uptime' ODER 'scanner' enthalten\n\n"); - printf("🟢 INKLUSIONS-FILTER im AND-Modus:\n"); + printf("INKLUSIONS-FILTER im AND-Modus:\n"); printf("Beispiel: ('bot' AND 'crawl')\n"); - printf("→ Zeigt nur Einträge mit BEIDEN Begriffen\n\n"); + printf("> Zeigt nur Einträge mit BEIDEN Begriffen\n\n"); - printf("🟡 INKLUSIONS-FILTER im OR-Modus:\n"); + printf("INKLUSIONS-FILTER im OR-Modus:\n"); printf("Beispiel: ('bot' OR 'crawl')\n"); - printf("→ Zeigt Einträge mit 'bot' ODER 'crawl'\n\n"); + printf("> Zeigt Einträge mit 'bot' ODER 'crawl'\n\n"); - printf("⚡ KOMBINATION: Exklusion + Inklusion:\n"); + printf("KOMBINATION: Exklusion + Inklusion:\n"); printf("AND-Modus: !('uptime') AND ('bot' AND 'crawl')\n"); printf("OR-Modus: !('uptime') AND ('bot' OR 'crawl')\n\n"); - printf("🎯 PRAKTISCHE ANWENDUNGSFÄLLE:\n"); + printf("PRAKTISCHE ANWENDUNGSFÄLLE:\n"); printf("Malware-Erkennung:\n"); printf(" '.git' OR '.env' OR '/admin'\n"); - printf(" → Verdächtige Pfad-Zugriffe\n\n"); + printf(" > Verdächtige Pfad-Zugriffe\n\n"); printf("Bot-Traffic bereinigen:\n"); printf(" !('bot') AND Status=200 AND Method='GET'\n"); - printf(" → Nur menschliche, erfolgreiche GET-Anfragen\n\n"); + printf(" > Nur menschliche, erfolgreiche GET-Anfragen\n\n"); printf("Zeitraum-Analyse:\n"); printf(" Time='08:00-18:00' AND Status=500\n"); - printf(" → Server-Fehler nur während Geschäftszeiten\n\n"); + printf(" > Server-Fehler nur während Geschäftszeiten\n\n"); printf("DDoS-Verdacht:\n"); printf(" Status=429 OR Status=503 OR Status=500\n"); - printf(" → Alle Überlastungs- und Fehler-Codes\n"); + printf(" > Alle Überlastungs- und Fehler-Codes\n"); } void menu_set_filters() { int choice = 0; while (choice != 7) { show_status(); - printf("\n=== FILTER SETZEN ===\n"); - printf("1. Status-Code Filter hinzufügen (exakte Suche)\n"); - printf("2. IP-Adresse Filter hinzufügen (exakte Suche)\n"); - printf("3. Zeitraum Filter hinzufügen (interaktiv)\n"); - printf("4. User-Agent-Filter setzen (Freitext)\n"); - printf("5. HTTP-Methode Filter hinzufügen (Freitext)\n"); - printf("6. URL-Pfad Filter hinzufügen (Freitext)\n"); - printf("7. Zurück zum Filter-Menü\n"); + printf("\nFILTER SETZEN\n"); + printf("1. Status-Code (exakte Suche)\n"); + printf("2. IP-Adresse (exakte Suche)\n"); + printf("3. Zeitraum (interaktiv)\n"); + printf("4. User-Agent (Freitext)\n"); + printf("5. HTTP-Methode (Freitext)\n"); + printf("6. URL-Pfad (Freitext)\n"); + printf("7. Zurück\n"); printf("Auswahl: "); choice = read_safe_integer(); @@ -1536,7 +1545,7 @@ void menu_set_filters() { filters.status_filters[filters.status_count].code = status; filters.status_filters[filters.status_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE; filters.status_count++; - printf("✅ Status-Code Filter hinzugefügt. Total: %d\n", filters.status_count); + printf(">Status-Code Filter hinzugefügt. Total: %d\n", filters.status_count); } else { printf("FEHLER: Ungültiger Filter-Typ!\n"); } @@ -1561,7 +1570,7 @@ void menu_set_filters() { strcpy(filters.ip_filters[filters.ip_count].ip_address, ip); filters.ip_filters[filters.ip_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE; filters.ip_count++; - printf("✅ IP-Filter hinzugefügt. Total: %d\n", filters.ip_count); + printf(">IP-Filter hinzugefügt. Total: %d\n", filters.ip_count); } else { printf("FEHLER: Ungültiger Filter-Typ!\n"); } @@ -1679,7 +1688,7 @@ void menu_set_filters() { filters.time_filters[filters.time_count] = new_time_filter; filters.time_count++; - printf("✅ Zeitraum-Filter hinzugefügt. Total: %d\n", filters.time_count); + printf(">Zeitraum-Filter hinzugefügt. Total: %d\n", filters.time_count); } else if (choice == 4) { if (filters.user_agent_count >= MAX_FILTERS) { @@ -1700,7 +1709,7 @@ void menu_set_filters() { strcpy(filters.user_agent_filters[filters.user_agent_count].pattern, pattern); filters.user_agent_filters[filters.user_agent_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE; filters.user_agent_count++; - printf("✅ User-Agent Filter hinzugefügt. Total: %d\n", filters.user_agent_count); + printf(">User-Agent Filter hinzugefügt. Total: %d\n", filters.user_agent_count); } else { printf("FEHLER: Ungültiger Filter-Typ!\n"); } @@ -1715,7 +1724,7 @@ void menu_set_filters() { continue; } - printf("HTTP-Methode eingeben (z.B. 'GET', 'POST', 'PUT', ... Sonderwert 'MALFORMED'): "); + printf("HTTP-Methode eingeben (z.B. 'GET', 'POST', 'PUT', ... Sonderwert 'ATYPICAL'): "); char pattern[10]; if (scanf("%9s", pattern) == 1) { printf("Filter-Typ wählen:\n"); @@ -1728,7 +1737,7 @@ void menu_set_filters() { strcpy(filters.method_filters[filters.method_count].pattern, pattern); filters.method_filters[filters.method_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE; filters.method_count++; - printf("✅ Method-Filter hinzugefügt. Total: %d\n", filters.method_count); + printf(">Method-Filter hinzugefügt. Total: %d\n", filters.method_count); } else { printf("FEHLER: Ungültiger Filter-Typ!\n"); } @@ -1756,7 +1765,7 @@ void menu_set_filters() { strcpy(filters.url_filters[filters.url_count].pattern, pattern); filters.url_filters[filters.url_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE; filters.url_count++; - printf("✅ URL-Filter hinzugefügt. Total: %d\n", filters.url_count); + printf(">URL-Filter hinzugefügt. Total: %d\n", filters.url_count); } else { printf("FEHLER: Ungültiger Filter-Typ!\n"); } @@ -1781,7 +1790,7 @@ void menu_delete_filters() { return; } - printf("\n=== FILTER LÖSCHEN ===\n"); + printf("\nFILTER LÖSCHEN\n"); printf("Aktuell gesetzte Filter:\n"); int filter_index = 1; @@ -1830,7 +1839,7 @@ void menu_delete_filters() { mode_str); } - printf("Welchen Filter möchten Sie löschen (1-%d) oder 0 für Abbrechen: ", total_filters); + printf("Auswahl: (1-%d) oder 0 für Abbrechen: ", total_filters); int choice = read_safe_integer(); if (choice == 0) { @@ -1850,7 +1859,7 @@ void menu_delete_filters() { filters.status_filters[j] = filters.status_filters[j + 1]; } filters.status_count--; - printf("✅ Status-Code Filter gelöscht.\n"); + printf(">Status-Code Filter gelöscht.\n"); return; } current_index++; @@ -1862,7 +1871,7 @@ void menu_delete_filters() { filters.method_filters[j] = filters.method_filters[j + 1]; } filters.method_count--; - printf("✅ Method-Filter gelöscht.\n"); + printf(">Method-Filter gelöscht.\n"); return; } current_index++; @@ -1874,7 +1883,7 @@ void menu_delete_filters() { filters.ip_filters[j] = filters.ip_filters[j + 1]; } filters.ip_count--; - printf("✅ IP-Filter gelöscht.\n"); + printf(">IP-Filter gelöscht.\n"); return; } current_index++; @@ -1886,7 +1895,7 @@ void menu_delete_filters() { filters.user_agent_filters[j] = filters.user_agent_filters[j + 1]; } filters.user_agent_count--; - printf("✅ User-Agent Filter gelöscht.\n"); + printf(">User-Agent Filter gelöscht.\n"); return; } current_index++; @@ -1898,7 +1907,7 @@ void menu_delete_filters() { filters.url_filters[j] = filters.url_filters[j + 1]; } filters.url_count--; - printf("✅ URL-Filter gelöscht.\n"); + printf(">URL-Filter gelöscht.\n"); return; } current_index++; @@ -1910,7 +1919,7 @@ void menu_delete_filters() { filters.time_filters[j] = filters.time_filters[j + 1]; } filters.time_count--; - printf("✅ Zeitraum-Filter gelöscht.\n"); + printf(">Zeitraum-Filter gelöscht.\n"); return; } current_index++; @@ -1918,7 +1927,7 @@ void menu_delete_filters() { } void menu_filter_mode() { - printf("=== FILTER-MODUS ===\n"); + printf("FILTER-MODUS\n"); printf("Aktueller Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); printf("\nACHTUNG:\n"); printf("Der Modus wirkt sich nur auf inklusive Filter aus.\n"); @@ -1932,10 +1941,10 @@ void menu_filter_mode() { if (choice == 1) { filters.combination_mode = 0; - printf("✅ Filter-Modus auf AND gesetzt.\n"); + printf(">Filter-Modus auf AND gesetzt.\n"); } else if (choice == 2) { filters.combination_mode = 1; - printf("✅ Filter-Modus auf OR gesetzt.\n"); + printf(">Filter-Modus auf OR gesetzt.\n"); } else if (choice == 3) { print_filter_examples(); } else if (choice != -1) { @@ -1952,7 +1961,7 @@ void menu_reset_filters() { filters.url_count = 0; filters.combination_mode = 0; - printf("✅ Alle Filter zurückgesetzt.\n"); + printf(">Alle Filter zurückgesetzt.\n"); } void menu_filter_management() { @@ -2014,7 +2023,7 @@ void menu_show_entries() { continue; } } - show_filtered_entries(); + show_filtered_entries(0); } else if (choice == 2) { export_filtered_entries(); } else if (choice == 3) { @@ -2051,7 +2060,7 @@ int main(int argc, char* argv[]) { return 1; } - printf("=== NGINX LOG PARSER - VEREINFACHTE VERSION ===\n"); + printf("NGINX EXAMINATOR\n"); allocate_initial_memory(); load_log_file(argv[1]); @@ -2080,7 +2089,7 @@ int main(int argc, char* argv[]) { } else if (choice == 3) { show_statistics(); } else if (choice == 4) { - printf("Auf Wiedersehen!\n"); + printf("Programmende\n"); } else { printf("Ungültige Auswahl! Bitte wählen Sie 1-4.\n"); }