diff --git a/src/main.c b/src/main.c index e4be34c..45642a6 100644 --- a/src/main.c +++ b/src/main.c @@ -531,6 +531,7 @@ int parse_simple_log_line(char* line, int entry_index, char* source_file) { // N 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'; + return 1; } void load_regular_file(char* filename) { @@ -1073,7 +1074,7 @@ void show_top_x_ips() { } } - printf("\n=== TOP %d IP-ADRESSEN ===\n", TOP_X); + printf("\nTOP %d IP-ADRESSEN\n", TOP_X); printf("Rang | IP-Adresse | Anzahl Anfragen\n"); printf("-----|------------------|----------------\n"); @@ -1122,7 +1123,6 @@ void show_top_user_agents() { } } - // Sort by count (descending) for (int i = 0; i < unique_agents - 1; i++) { for (int j = 0; j < unique_agents - i - 1; j++) { if (agent_stats[j].count < agent_stats[j + 1].count) { @@ -1133,7 +1133,7 @@ void show_top_user_agents() { } } - printf("\n=== TOP %d USER AGENTS ===\n", TOP_X); + printf("\nTOP %d USER AGENTS\n", TOP_X); printf("Rang | User Agent | Anzahl Anfragen\n"); printf("-----|--------------------------------------|----------------\n"); @@ -1151,63 +1151,46 @@ void show_top_user_agents() { void show_filtered_entries(int num_shown) { int shown_count = 0; - + printf("\nLOGDATEN:\n"); printf("IP-Adresse | Methode | URL | Status | Bytes | User Agent | Zeit\n"); printf("-----------------|---------|------------------------|--------|-------|--------------------------------------|------------------\n"); - - 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++; - } - } + + for (int i = 0; i < total_entries; i++) { + if (!passes_filter(i)) continue; + + 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 && shown_count >= num_shown) break; // für Preview: abbrechen wenn num_shown erreicht } - - printf("\nInsgesamt %d Einträge gefunden.\n", shown_count); - + + if (num_shown != 0) { + printf("\nInsgesamt %d Einträge in der Vorschau.\n", shown_count); + } else { + printf("\nInsgesamt %d Einträge gefunden.\n", shown_count); + } + if (shown_count == 0) { printf("Keine Einträge gefunden, die dem Filter entsprechen.\n"); } } -// Statusanzeige + void show_status() { - printf("PREVIEW:\n"); + printf("\nPREVIEW:\n"); show_filtered_entries(10); printf("\nSTATUS\n"); @@ -1237,7 +1220,6 @@ void show_status() { else includes++; } - // Ausschlussfilter (immer im ODER-Modus) if (excludes > 0) { printf("!("); int first = 1; @@ -1252,7 +1234,6 @@ void show_status() { if (includes > 0) printf(" AND "); } - // Einschlussfilter (folgen dem gesetzten Modus) if (includes > 0) { if (includes > 1) printf("("); int first = 1; @@ -1269,7 +1250,7 @@ void show_status() { } if (filters.method_count > 0) { - printf("Request-Method: "); + printf(" -> Request-Method: "); int excludes = 0, includes = 0; for (int i = 0; i < filters.method_count; i++) { @@ -1307,7 +1288,7 @@ void show_status() { } if (filters.ip_count > 0) { - printf("IP-Adresse: "); + printf(" -> IP-Adresse: "); int excludes = 0, includes = 0; for (int i = 0; i < filters.ip_count; i++) { @@ -1345,7 +1326,7 @@ void show_status() { } if (filters.user_agent_count > 0) { - printf("UserAgent: "); + printf(" -> UserAgent: "); int excludes = 0, includes = 0; for (int i = 0; i < filters.user_agent_count; i++) { @@ -1383,7 +1364,7 @@ void show_status() { } if (filters.url_count > 0) { - printf("Payload/Pfad: "); + printf(" -> Payload/Pfad: "); int excludes = 0, includes = 0; for (int i = 0; i < filters.url_count; i++) { @@ -1421,10 +1402,9 @@ void show_status() { } if (filters.time_count > 0) { - printf("Zeitraum: %d Filter gesetzt\n", filters.time_count); + 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) { @@ -1435,45 +1415,12 @@ void show_status() { 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; - int count_500 = 0; - int total_bytes = 0; - int filtered_count = 0; - - printf("\nSTATISTIKEN\n"); - - for (int i = 0; i < total_entries; i++) { - if (passes_filter(i)) { - filtered_count++; - total_bytes += all_entries[i].bytes_sent; - - if (all_entries[i].status_code == 200) count_200++; - else if (all_entries[i].status_code == 404) count_404++; - else if (all_entries[i].status_code >= 500) count_500++; - } - } - - 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("\n DATENSATZ: \n %d von %d Einträgen entsprechen den Filtern\n", filtered_count, total_entries); } } void print_filter_examples() { printf("\nFILTER-DOKUMENTATION\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"); @@ -1508,21 +1455,217 @@ void print_filter_examples() { printf(" > Alle Überlastungs- und Fehler-Codes\n"); } -void menu_set_filters() { +int handle_menu_shortcuts(int choice) { + if (choice == -2) { + return -2; + } else if (choice == -3) { + return -3; + } else if (choice == -4) { + printf("Programmende\n"); + cleanup_memory(); + exit(0); + } + return choice; +} + +int safe_read_integer(const char* prompt, int min_val, int max_val) { + char input[50]; + int value; + char *endptr; + + while (1) { + printf("%s", prompt); + if (scanf("%49s", input) != 1) { + clear_input_buffer(); + printf("FEHLER: Ungültige Eingabe. Bitte erneut versuchen.\n"); + continue; + } + clear_input_buffer(); + + if (strcmp(input, "b") == 0 || strcmp(input, "B") == 0) return -2; + if (strcmp(input, "m") == 0 || strcmp(input, "M") == 0) return -3; + if (strcmp(input, "q") == 0 || strcmp(input, "Q") == 0) return -4; + + value = strtol(input, &endptr, 10); + if (*endptr != '\0') { + printf("FEHLER: '%s' ist keine gültige Zahl. Bitte erneut versuchen.\n", input); + continue; + } + + if (value < min_val || value > max_val) { + printf("FEHLER: Wert muss zwischen %d und %d liegen. Bitte erneut versuchen.\n", min_val, max_val); + continue; + } + + return value; + } +} + +int safe_read_string(const char* prompt, char* buffer, int buffer_size) { + while (1) { + printf("%s", prompt); + if (scanf("%s", buffer) != 1) { + clear_input_buffer(); + printf("FEHLER: Ungültige Eingabe. Bitte erneut versuchen.\n"); + continue; + } + clear_input_buffer(); + + if (strlen(buffer) >= buffer_size - 1) { + printf("FEHLER: Eingabe zu lang. Bitte erneut versuchen.\n"); + continue; + } + + if (strcmp(buffer, "b") == 0 || strcmp(buffer, "B") == 0) return -2; + if (strcmp(buffer, "m") == 0 || strcmp(buffer, "M") == 0) return -3; + if (strcmp(buffer, "q") == 0 || strcmp(buffer, "Q") == 0) return -4; + + return 0; + } +} + +int read_menu_input() { + char input[10]; + if (scanf("%9s", input) != 1) { + clear_input_buffer(); + return -1; + } + clear_input_buffer(); + + if (strcmp(input, "b") == 0 || strcmp(input, "B") == 0) return -2; + if (strcmp(input, "m") == 0 || strcmp(input, "M") == 0) return -3; + if (strcmp(input, "q") == 0 || strcmp(input, "Q") == 0) return -4; + + char *endptr; + long number = strtol(input, &endptr, 10); + 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("4. Programm beenden\n"); + printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); + printf("Auswahl: "); +} + +int menu_set_filters() { int choice = 0; - while (choice != 7) { + while (choice != -2 && choice != -3) { show_status(); - printf("\nFILTER SETZEN\n"); + + printf("\nFILTER HINZUFÜGEN\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("3. Zeitraum (Start- und Endzeit)\n"); + printf("4. User-Agent (Teilstring-Suche)\n"); + printf("5. HTTP-Methode (Teilstring-Suche)\n"); + printf("6. URL-Pfad (Teilstring-Suche)\n"); + printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); printf("Auswahl: "); - choice = read_safe_integer(); + choice = read_menu_input(); + choice = handle_menu_shortcuts(choice); if (choice == 1) { if (filters.status_count >= MAX_FILTERS) { @@ -1530,26 +1673,20 @@ void menu_set_filters() { continue; } - printf("Status Code eingeben (z.B. 200, 404, 500): "); - int status = read_safe_integer(); - if (status == -1) { - printf("FEHLER: Ungültiger Status Code!\n"); - } else { - printf("Filter-Typ wählen:\n"); - printf("1. Einschließen (nur Status %d anzeigen)\n", status); - printf("2. Ausschließen (Status %d NICHT anzeigen)\n", status); - printf("Auswahl: "); - int filter_type = read_safe_integer(); - - if (filter_type == 1 || filter_type == 2) { - 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); - } else { - printf("FEHLER: Ungültiger Filter-Typ!\n"); - } - } + int status = safe_read_integer("Status Code eingeben (z.B. 200, 404, 500): ", 100, 599); + if (status < 0) continue; + + printf("\nFilter-Typ wählen:\n"); + printf("1. Einschließen (nur Status %d anzeigen)\n", status); + printf("2. Ausschließen (Status %d NICHT anzeigen)\n", status); + + int filter_type = safe_read_integer("Auswahl: ", 1, 2); + if (filter_type < 0) continue; + + 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. Gesamt: %d\n", filters.status_count); } else if (choice == 2) { if (filters.ip_count >= MAX_FILTERS) { @@ -1557,27 +1694,21 @@ void menu_set_filters() { continue; } - printf("IP-Adresse eingeben: "); char ip[50]; - if (scanf("%49s", ip) == 1) { - printf("Filter-Typ wählen:\n"); - printf("1. Einschließen (nur IP %s anzeigen)\n", ip); - printf("2. Ausschließen (IP %s NICHT anzeigen)\n", ip); - printf("Auswahl: "); - int filter_type = read_safe_integer(); - - if (filter_type == 1 || filter_type == 2) { - 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); - } else { - printf("FEHLER: Ungültiger Filter-Typ!\n"); - } - } else { - printf("FEHLER: Ungültige IP-Adresse!\n"); - clear_input_buffer(); - } + int result = safe_read_string("IP-Adresse eingeben: ", ip, sizeof(ip)); + if (result < 0) continue; + + printf("\nFilter-Typ wählen:\n"); + printf("1. Einschließen (nur IP %s anzeigen)\n", ip); + printf("2. Ausschließen (IP %s NICHT anzeigen)\n", ip); + + int filter_type = safe_read_integer("Auswahl: ", 1, 2); + if (filter_type < 0) continue; + + 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. Gesamt: %d\n", filters.ip_count); } else if (choice == 3) { if (filters.time_count >= MAX_FILTERS) { @@ -1585,89 +1716,53 @@ void menu_set_filters() { continue; } - printf("\n=== ZEITRAUM FILTER HINZUFÜGEN ===\n"); + printf("\nZEITRAUM FILTER HINZUFÜGEN\n"); struct time_filter new_time_filter = {0}; - printf("Startzeit eingeben:\n"); - printf("Jahr (z.B. 2023): "); - int start_year = read_safe_integer(); - if (start_year == -1) { printf("FEHLER: Ungültiges Jahr!\n"); continue; } + printf("STARTZEIT:\n"); + int start_year = safe_read_integer("Jahr (z.B. 2023): ", 1970, 2100); + if (start_year < 0) continue; - printf("Monat (1-12): "); - int start_month = read_safe_integer(); - if (start_month == -1 || start_month < 1 || start_month > 12) { - printf("FEHLER: Ungültiger Monat!\n"); continue; - } + int start_month = safe_read_integer("Monat (1-12): ", 1, 12); + if (start_month < 0) continue; - printf("Tag (1-31): "); - int start_day = read_safe_integer(); - if (start_day == -1 || start_day < 1 || start_day > 31) { - printf("FEHLER: Ungültiger Tag!\n"); continue; - } + int start_day = safe_read_integer("Tag (1-31): ", 1, 31); + if (start_day < 0) continue; - printf("Stunde (0-23): "); - int start_hour = read_safe_integer(); - if (start_hour == -1 || start_hour < 0 || start_hour > 23) { - printf("FEHLER: Ungültige Stunde!\n"); continue; - } + int start_hour = safe_read_integer("Stunde (0-23): ", 0, 23); + if (start_hour < 0) continue; - printf("Minute (0-59): "); - int start_minute = read_safe_integer(); - if (start_minute == -1 || start_minute < 0 || start_minute > 59) { - printf("FEHLER: Ungültige Minute!\n"); continue; - } + int start_minute = safe_read_integer("Minute (0-59): ", 0, 59); + if (start_minute < 0) continue; - printf("Sekunde (0-59): "); - int start_second = read_safe_integer(); - if (start_second == -1 || start_second < 0 || start_second > 59) { - printf("FEHLER: Ungültige Sekunde!\n"); continue; - } + int start_second = safe_read_integer("Sekunde (0-59): ", 0, 59); + if (start_second < 0) continue; - printf("\nEndzeit eingeben:\n"); - printf("Jahr (z.B. 2023): "); - int end_year = read_safe_integer(); - if (end_year == -1) { printf("FEHLER: Ungültiges Jahr!\n"); continue; } + printf("\nENDZEIT:\n"); + int end_year = safe_read_integer("Jahr (z.B. 2023): ", 1970, 2100); + if (end_year < 0) continue; - printf("Monat (1-12): "); - int end_month = read_safe_integer(); - if (end_month == -1 || end_month < 1 || end_month > 12) { - printf("FEHLER: Ungültiger Monat!\n"); continue; - } + int end_month = safe_read_integer("Monat (1-12): ", 1, 12); + if (end_month < 0) continue; - printf("Tag (1-31): "); - int end_day = read_safe_integer(); - if (end_day == -1 || end_day < 1 || end_day > 31) { - printf("FEHLER: Ungültiger Tag!\n"); continue; - } + int end_day = safe_read_integer("Tag (1-31): ", 1, 31); + if (end_day < 0) continue; - printf("Stunde (0-23): "); - int end_hour = read_safe_integer(); - if (end_hour == -1 || end_hour < 0 || end_hour > 23) { - printf("FEHLER: Ungültige Stunde!\n"); continue; - } + int end_hour = safe_read_integer("Stunde (0-23): ", 0, 23); + if (end_hour < 0) continue; - printf("Minute (0-59): "); - int end_minute = read_safe_integer(); - if (end_minute == -1 || end_minute < 0 || end_minute > 59) { - printf("FEHLER: Ungültige Minute!\n"); continue; - } + int end_minute = safe_read_integer("Minute (0-59): ", 0, 59); + if (end_minute < 0) continue; - printf("Sekunde (0-59): "); - int end_second = read_safe_integer(); - if (end_second == -1 || end_second < 0 || end_second > 59) { - printf("FEHLER: Ungültige Sekunde!\n"); continue; - } + int end_second = safe_read_integer("Sekunde (0-59): ", 0, 59); + if (end_second < 0) continue; printf("\nFilter-Typ wählen:\n"); - printf("1. Einschließen (nur Ereignisse IN diesem Zeitraum anzeigen)\n"); + printf("1. Einschließen (nur Ereignisse IN diesem Zeitraum)\n"); printf("2. Ausschließen (Ereignisse in diesem Zeitraum NICHT anzeigen)\n"); - printf("Auswahl: "); - int filter_type = read_safe_integer(); - if (filter_type != 1 && filter_type != 2) { - printf("FEHLER: Ungültiger Filter-Typ!\n"); - continue; - } + int filter_type = safe_read_integer("Auswahl: ", 1, 2); + if (filter_type < 0) continue; new_time_filter.start_time.year = start_year; new_time_filter.start_time.month = start_month; @@ -1688,7 +1783,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. Gesamt: %d\n", filters.time_count); } else if (choice == 4) { if (filters.user_agent_count >= MAX_FILTERS) { @@ -1696,27 +1791,21 @@ void menu_set_filters() { continue; } - printf("User-Agent Suchtext eingeben (z.B. 'chrome', 'bot', 'upti'): "); char pattern[256]; - if (scanf("%255s", pattern) == 1) { - printf("Filter-Typ wählen:\n"); - printf("1. Einschließen (nur User-Agents mit '%s' anzeigen)\n", pattern); - printf("2. Ausschließen (User-Agents mit '%s' NICHT anzeigen)\n", pattern); - printf("Auswahl: "); - int filter_type = read_safe_integer(); - - if (filter_type == 1 || filter_type == 2) { - 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); - } else { - printf("FEHLER: Ungültiger Filter-Typ!\n"); - } - } else { - printf("FEHLER: Ungültiger Suchtext!\n"); - clear_input_buffer(); - } + int result = safe_read_string("User-Agent Suchtext eingeben (z.B. 'chrome', 'bot', 'scanner'): ", pattern, sizeof(pattern)); + if (result < 0) continue; + + printf("\nFilter-Typ wählen:\n"); + printf("1. Einschließen (nur User-Agents mit '%s')\n", pattern); + printf("2. Ausschließen (User-Agents mit '%s' NICHT anzeigen)\n", pattern); + + int filter_type = safe_read_integer("Auswahl: ", 1, 2); + if (filter_type < 0) continue; + + 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. Gesamt: %d\n", filters.user_agent_count); } else if (choice == 5) { if (filters.method_count >= MAX_FILTERS) { @@ -1724,27 +1813,21 @@ void menu_set_filters() { continue; } - 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"); - printf("1. Einschließen (nur Methode '%s' anzeigen)\n", pattern); - printf("2. Ausschließen (Methode '%s' NICHT anzeigen)\n", pattern); - printf("Auswahl: "); - int filter_type = read_safe_integer(); - - if (filter_type == 1 || filter_type == 2) { - 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); - } else { - printf("FEHLER: Ungültiger Filter-Typ!\n"); - } - } else { - printf("FEHLER: Ungültige Methode!\n"); - clear_input_buffer(); - } + int result = safe_read_string("HTTP-Methode eingeben (z.B. 'GET', 'POST', 'PUT', Sonderwert: 'ATYPICAL'): ", pattern, sizeof(pattern)); + if (result < 0) continue; + + printf("\nFilter-Typ wählen:\n"); + printf("1. Einschließen (nur Methode '%s')\n", pattern); + printf("2. Ausschließen (Methode '%s' NICHT anzeigen)\n", pattern); + + int filter_type = safe_read_integer("Auswahl: ", 1, 2); + if (filter_type < 0) continue; + + 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. Gesamt: %d\n", filters.method_count); } else if (choice == 6) { if (filters.url_count >= MAX_FILTERS) { @@ -1752,38 +1835,36 @@ void menu_set_filters() { continue; } - printf("URL-Pfad Suchtext eingeben (z.B. '.git', '.php', '/admin'): "); char pattern[MAX_REQUEST_LENGTH]; - if (scanf("%1023s", pattern) == 1) { - printf("Filter-Typ wählen:\n"); - printf("1. Einschließen (nur URLs mit '%s' anzeigen)\n", pattern); - printf("2. Ausschließen (URLs mit '%s' NICHT anzeigen)\n", pattern); - printf("Auswahl: "); - int filter_type = read_safe_integer(); - - if (filter_type == 1 || filter_type == 2) { - 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); - } else { - printf("FEHLER: Ungültiger Filter-Typ!\n"); - } - } else { - printf("FEHLER: Ungültiger Suchtext!\n"); - clear_input_buffer(); - } + int result = safe_read_string("URL-Pfad Suchtext eingeben (z.B. '.git', '.php', '/admin', 'wp-'): ", pattern, sizeof(pattern)); + if (result < 0) continue; - } else if (choice == 7) { - return; + printf("\nFilter-Typ wählen:\n"); + printf("1. Einschließen (nur URLs mit '%s')\n", pattern); + printf("2. Ausschließen (URLs mit '%s' NICHT anzeigen)\n", pattern); + + int filter_type = safe_read_integer("Auswahl: ", 1, 2); + if (filter_type < 0) continue; + + 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. Gesamt: %d\n", filters.url_count); + + } else if (choice == -2) { + return -2; + } else if (choice == -3) { + return -3; } else if (choice != -1) { - printf("Ungültige Auswahl! Bitte wählen Sie 1-7.\n"); + printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-6 oder b/m/q.\n"); } } + return choice; } void menu_delete_filters() { - int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count + filters.method_count + filters.url_count; + int total_filters = filters.status_count + filters.ip_count + filters.time_count + + filters.user_agent_count + filters.method_count + filters.url_count; if (total_filters == 0) { printf("Keine Filter gesetzt zum Löschen.\n"); @@ -1791,38 +1872,38 @@ void menu_delete_filters() { } printf("\nFILTER LÖSCHEN\n"); - printf("Aktuell gesetzte Filter:\n"); + printf("Aktuelle Filter:\n\n"); int filter_index = 1; for (int i = 0; i < filters.status_count; i++) { - char* mode_str = (filters.status_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; - printf("%d. Status-Code: %d %s\n", filter_index++, filters.status_filters[i].code, mode_str); + char* mode_str = (filters.status_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen"; + printf("%2d. Status-Code: %d (%s)\n", filter_index++, filters.status_filters[i].code, mode_str); } for (int i = 0; i < filters.method_count; i++) { - char* mode_str = (filters.method_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; - printf("%d. HTTP-Methode: \"%s\" %s\n", filter_index++, filters.method_filters[i].pattern, mode_str); + char* mode_str = (filters.method_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen"; + printf("%2d. HTTP-Methode: \"%s\" (%s)\n", filter_index++, filters.method_filters[i].pattern, mode_str); } for (int i = 0; i < filters.ip_count; i++) { - char* mode_str = (filters.ip_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; - printf("%d. IP-Adresse: %s %s\n", filter_index++, filters.ip_filters[i].ip_address, mode_str); + char* mode_str = (filters.ip_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen"; + printf("%2d. IP-Adresse: %s (%s)\n", filter_index++, filters.ip_filters[i].ip_address, mode_str); } for (int i = 0; i < filters.user_agent_count; i++) { - char* mode_str = (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; - printf("%d. User-Agent: \"%s\" %s\n", filter_index++, filters.user_agent_filters[i].pattern, mode_str); + char* mode_str = (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen"; + printf("%2d. User-Agent: \"%s\" (%s)\n", filter_index++, filters.user_agent_filters[i].pattern, mode_str); } for (int i = 0; i < filters.url_count; i++) { - char* mode_str = (filters.url_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; - printf("%d. URL-Pfad: \"%s\" %s\n", filter_index++, filters.url_filters[i].pattern, mode_str); + char* mode_str = (filters.url_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen"; + printf("%2d. URL-Pfad: \"%s\" (%s)\n", filter_index++, filters.url_filters[i].pattern, mode_str); } for (int i = 0; i < filters.time_count; i++) { - char* mode_str = (filters.time_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; - printf("%d. Zeitraum: %02d.%02d.%d %02d:%02d:%02d - %02d.%02d.%d %02d:%02d:%02d %s\n", + char* mode_str = (filters.time_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen"; + printf("%2d. Zeitraum: %02d.%02d.%d %02d:%02d:%02d - %02d.%02d.%d %02d:%02d:%02d (%s)\n", filter_index++, filters.time_filters[i].start_time.day, filters.time_filters[i].start_time.month, @@ -1839,18 +1920,13 @@ void menu_delete_filters() { mode_str); } - printf("Auswahl: (1-%d) oder 0 für Abbrechen: ", total_filters); - int choice = read_safe_integer(); + int choice = safe_read_integer("Filter zum Löschen auswählen (1-%d) oder 0 für Abbrechen: ", 0, total_filters); + if (choice < 0) return; if (choice == 0) { return; } - if (choice < 1 || choice > total_filters) { - printf("FEHLER: Ungültige Auswahl!\n"); - return; - } - int current_index = 1; for (int i = 0; i < filters.status_count; i++) { @@ -1859,7 +1935,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++; @@ -1871,7 +1947,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++; @@ -1883,7 +1959,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++; @@ -1895,7 +1971,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++; @@ -1907,7 +1983,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++; @@ -1919,7 +1995,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++; @@ -1927,60 +2003,95 @@ void menu_delete_filters() { } void menu_filter_mode() { - 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"); - printf("Die exklusiven Filter arbeiten immer im OR-Modus und \nschließen jeden Eintrag aus, der zu einem beliebigen Exklusions-Filter passt.\nExklusions-Filter haben immer Vorrang.\n"); - printf("\nAuswahl: \n"); - printf("1. AND-Modus\n"); - printf("2. OR-Modus\n"); - printf("3. Detaillierte Beispiele\n"); + printf("\nFILTER-MODUS ÄNDERN\n"); + printf("Aktueller Modus: %s\n\n", filters.combination_mode == 0 ? "AND (alle müssen zutreffen)" : "OR (einer muss zutreffen)"); - int choice = read_safe_integer(); + printf("HINWEIS: Der Modus gilt nur für Einschluss-Filter der gleichen Kategorie.\n"); + printf("Ausschluss-Filter arbeiten immer im OR-Modus und haben Vorrang.\n\n"); + + printf("1. AND-Modus (alle Einschluss-Filter müssen zutreffen)\n"); + printf("2. OR-Modus (mindestens ein Einschluss-Filter muss zutreffen)\n"); + printf("3. Detaillierte Beispiele anzeigen\n"); + printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); + printf("Auswahl: "); + + int choice = read_menu_input(); + choice = handle_menu_shortcuts(choice); 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 == -2 || choice == -3) { + return; } else if (choice != -1) { - printf("Ungültige Auswahl!\n"); + printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-3 oder b/m/q.\n"); } } void menu_reset_filters() { - filters.status_count = 0; - filters.method_count = 0; - filters.ip_count = 0; - filters.time_count = 0; - filters.user_agent_count = 0; - filters.url_count = 0; - filters.combination_mode = 0; + printf("\nFILTER ZURÜCKSETZEN\n"); - printf(">Alle Filter zurückgesetzt.\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 zum Zurücksetzen.\n"); + return; + } + + printf("WARNUNG: Alle %d Filter werden gelöscht!\n\n", total_filters); + printf("1. Ja, alle Filter löschen\n"); + printf("2. Abbrechen\n"); + printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); + printf("Auswahl: "); + + int choice = read_menu_input(); + choice = handle_menu_shortcuts(choice); + + if (choice == 1) { + filters.status_count = 0; + filters.method_count = 0; + filters.ip_count = 0; + filters.time_count = 0; + filters.user_agent_count = 0; + filters.url_count = 0; + filters.combination_mode = 0; + + printf("Alle Filter zurückgesetzt.\n"); + } else if (choice == 2) { + printf("Zurücksetzen abgebrochen.\n"); + } else if (choice == -2 || choice == -3) { + return; + } else if (choice != -1) { + printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-2 oder b/m/q.\n"); + } } void menu_filter_management() { int choice = 0; - while (choice != 5) { + while (choice != -2 && choice != -3) { show_status(); + printf("\nFILTER VERWALTEN\n"); - printf("1. Filter setzen\n"); + printf("1. Filter hinzufügen\n"); printf("2. Filter löschen\n"); - printf("3. Filter-Modus (AND/OR)\n"); - printf("4. Filter zurücksetzen\n"); - printf("5. Zeige Filter-Dokumentation\n"); - printf("6. Zurück zum Hauptmenü\n"); + printf("3. Filter-Modus ändern (AND/OR)\n"); + printf("4. Alle Filter zurücksetzen\n"); + printf("5. Filter-Dokumentation anzeigen\n"); + printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); printf("Auswahl: "); - choice = read_safe_integer(); + choice = read_menu_input(); + choice = handle_menu_shortcuts(choice); if (choice == 1) { - menu_set_filters(); + int sub_result = menu_set_filters(); + if (sub_result == -3) return; } else if (choice == 2) { menu_delete_filters(); } else if (choice == 3) { @@ -1989,40 +2100,54 @@ void menu_filter_management() { menu_reset_filters(); } else if (choice == 5) { print_filter_examples(); - } else if (choice == 6) { + } else if (choice == -2) { + return; + } else if (choice == -3) { return; } else if (choice != -1) { - printf("Ungültige Auswahl! Bitte wählen Sie 1-6.\n"); + printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-5 oder b/m/q.\n"); } } } void menu_show_entries() { int choice = 0; - while (choice != 4) { - show_status(); - printf("\nANZEIGEN UND EXPORTIEREN\n"); + int supress_preview = 0; + while (choice != -2 && choice != -3) { + if (supress_preview == 0) { + show_status(); + supress_preview = 0; + } + + int filtered_count = count_filtered_entries(); - printf("Aktuell %d gefilterte Einträge verfügbar.\n", filtered_count); - printf("1. Vollständig anzeigen\n"); - printf("2. Zu .csv exportieren (Timesketch-kompatibel)\n"); - printf("3. Top %d IP-Adressen\n", TOP_X); - printf("4. Top %d User-Agents\n", TOP_X); - printf("5. Zurück zum Hauptmenü\n"); + printf("\nDATEN ANZEIGEN UND EXPORTIEREN\n"); + printf("Verfügbare Einträge: %d (gefiltert von %d)\n\n", filtered_count, total_entries); + + printf("1. Alle gefilterten Einträge anzeigen\n"); + printf("2. Als CSV exportieren (Timesketch-kompatibel)\n"); + printf("3. Top %d IP-Adressen anzeigen\n", TOP_X); + printf("4. Top %d User-Agents anzeigen\n", TOP_X); + printf("Navigation: [b]Zurück [m]Hauptmenü [q]Beenden\n"); printf("Auswahl: "); - choice = read_safe_integer(); + choice = read_menu_input(); + choice = handle_menu_shortcuts(choice); if (choice == 1) { if (filtered_count > 1000) { - printf("WARNUNG: Die Anzeige von %d Einträgen ist in der Kommandozeile nur schlecht darstellbar.\n", filtered_count); - printf("Möchten Sie trotzdem fortfahren? (1=Ja, 0=Nein): "); - int confirm = read_safe_integer(); + printf("\nWARNUNG: Die Anzeige von %d Einträgen in der Kommandozeile ist unübersichtlich.\n", filtered_count); + printf("Empfehlung: Verwenden Sie den CSV-Export für große Datenmengen.\n\n"); + printf("1. Trotzdem anzeigen\n"); + printf("2. Abbrechen\n"); + + int confirm = safe_read_integer("Auswahl: ", 1, 2); if (confirm != 1) { - printf("Anzeige abgebrochen. Tipp: Verwenden Sie den Export für große Datenmengen.\n"); + printf("Anzeige abgebrochen.\n"); continue; } } + supress_preview = 1; show_filtered_entries(0); } else if (choice == 2) { export_filtered_entries(); @@ -2030,23 +2155,16 @@ void menu_show_entries() { show_top_x_ips(); } else if (choice == 4) { show_top_user_agents(); - } else if (choice == 5) { + } else if (choice == -2) { + return; + } else if (choice == -3) { return; } else if (choice != -1) { - printf("Ungültige Auswahl! Bitte wählen Sie 1-4.\n"); + printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-4 oder b/m/q.\n"); } } } -void show_main_menu() { - printf("\nHauptmenü:\n"); - printf("1. Filter verwalten\n"); - printf("2. Anzeigemodi\n"); - printf("3. Statistiken anzeigen\n"); - printf("4. Beenden\n"); - printf("Auswahl: "); -} - int main(int argc, char* argv[]) { if (argc != 2) { printf("Verwendung: %s \n", argv[0]); @@ -2058,11 +2176,13 @@ int main(int argc, char* argv[]) { printf(" 1. Dekomprimieren: gunzip /var/log/nginx/*.gz\n"); printf(" 2. Dann ausführen: %s /var/log/nginx/\n", argv[0]); return 1; + } else if (argc == 3) { + } - printf("NGINX EXAMINATOR\n"); - allocate_initial_memory(); + printf("\nNGINX EXAMINATOR\n"); + allocate_initial_memory(); load_log_file(argv[1]); if (total_entries == 0) { @@ -2072,13 +2192,20 @@ int main(int argc, char* argv[]) { } int choice = 0; - while (choice != 4) { + int stats_show = 0; + while (choice != 4 && choice != -4) { show_status(); + if (stats_show == 1) { + show_stats(); + int stats_show = 0; + } show_main_menu(); - choice = read_safe_integer(); + + choice = read_menu_input(); + choice = handle_menu_shortcuts(choice); if (choice == -1) { - printf("FEHLER: Bitte geben Sie eine gültige Zahl ein!\n"); + printf("FEHLER: Bitte geben Sie eine gültige Zahl oder Navigation ein (1-4, b, m, q)!\n"); continue; } @@ -2087,11 +2214,14 @@ int main(int argc, char* argv[]) { } else if (choice == 2) { menu_show_entries(); } else if (choice == 3) { - show_statistics(); + stats_show =1; } else if (choice == 4) { printf("Programmende\n"); + break; + } else if (choice == -4) { + break; } else { - printf("Ungültige Auswahl! Bitte wählen Sie 1-4.\n"); + printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-4 oder b/m/q.\n"); } }