diff --git a/src/main.c b/src/main.c index febd32a..6bcea29 100644 --- a/src/main.c +++ b/src/main.c @@ -58,6 +58,11 @@ struct status_filter { filter_mode_t mode; }; +struct method_filter { + char pattern[10]; + filter_mode_t mode; +}; + // für IP-Adressen struct ip_filter { char ip_address[50]; @@ -81,6 +86,9 @@ struct user_agent_filter { struct filter_system { struct status_filter status_filters[MAX_FILTERS]; int status_count; + + struct method_filter method_filters[MAX_FILTERS]; + int method_count; struct ip_filter ip_filters[MAX_FILTERS]; int ip_count; @@ -269,10 +277,13 @@ Daher ist das Parsing am einfachsten, wenn ein Pointer-basierter Algorithmus die Fehleranfällig, wenn das Logformat nicht dem Standard entspricht - das gilt aber auch für andere Parser. */ // Standard-nginx-accesslog: -// Standard-nginx-accesslog: +/* + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$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 - printf("Parsing line: %s\n", line); char* current_pos = line; // leere Zeichen am Anfang überspringen current_pos = skip_spaces(current_pos); @@ -371,16 +382,16 @@ int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer au // 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);" "-" // ^ - // First, try to read what should be the HTTP method + // lesen der HTTP-Methode in temporäre Variable char temp_method[50]; copy_until_space(temp_method, current_pos, sizeof(temp_method)); - // Check if it looks like a valid HTTP method (starts with letters, reasonable length) + // Längenprüfung des Methodenstrings int is_valid_method = 1; if (strlen(temp_method) == 0 || strlen(temp_method) > 10) { is_valid_method = 0; } else { - // Check if method contains only letters (no binary data) + // prüfen, ob die Methode nur ASCII-Zeichen enthält for (int i = 0; temp_method[i] != '\0'; i++) { if (!((temp_method[i] >= 'A' && temp_method[i] <= 'Z') || (temp_method[i] >= 'a' && temp_method[i] <= 'z'))) { @@ -391,7 +402,7 @@ int parse_simple_log_line(char* line, int entry_index) { // Nimmt den Pointer au } if (is_valid_method) { - // Normal parsing: HTTP-Methode bis zum nächsten Leerzeichen einlesen und speichern + // Normal parsen: HTTP-Methode bis zum nächsten Leerzeichen einlesen und speichern strcpy(all_entries[entry_index].request_method, temp_method); while (*current_pos != ' ' && *current_pos != '\0') current_pos++; current_pos = skip_spaces(current_pos); @@ -663,6 +674,47 @@ int user_agent_matches(char* user_agent) { return 1; // Keine Einschlussfilter, keine zutreffenden Ausschlussfilter, positiver Rückgabewert =1 } +// Filterfunktion für Zugriffsmethode. Nimmt den Datensatz entgegen und prüft gegen die gesetzten Filter, gibt dann 0 oder 1 zurück +int method_matches(char* request_method) { + if (filters.method_count == 0) return 1; + // Ausschluss-Filter geht vor + for (int i = 0; i < filters.method_count; i++) { + if (filters.method_filters[i].mode == FILTER_EXCLUDE) { + int pattern_found = search_in_string(request_method, filters.method_filters[i].pattern); + if (pattern_found) { + return 0; // früheres Verlassen der Schleife, sobald Ausschlussfilter zutrifft + } + } + } + // Prüfung im entsprechenden Modus + int include_count = 0; + int include_matches = 0; + + for (int i = 0; i < filters.method_count; i++) { + if (filters.method_filters[i].mode == FILTER_INCLUDE) { + include_count++; + int pattern_found = search_in_string(request_method, filters.method_filters[i].pattern); + if (pattern_found) { + include_matches++; + if (filters.combination_mode == 1) { // OR-Modus + return 1; // Früheres Verlassen der Schleife bei erstem zutreffendem Einschlussfilter im OR-Modus + } + } + } + } + + // Diese Prüfung wird ausgeführt, wenn Einschlussfilter vorhanden sind + if (include_count > 0) { + if (filters.combination_mode == 0) { // AND-Modus + return include_matches == include_count; // Alle Einschlussfilter müssen zutreffen, die Treffer müssen Anzahl der Filter entsprechen + } else { // OR-Modus + return 0; + } + } + + return 1; // Keine Einschlussfilter, keine zutreffenden Ausschlussfilter, positiver Rückgabewert =1 +} + int status_code_matches(int status_code) { if (filters.status_count == 0) return 1; // Ausschluss-Filter prüfen: immer übergeordnet gültig @@ -786,16 +838,17 @@ int time_matches(struct simple_time entry_time) { // Prüfen aller Filter im AND-Modus oder OR-Modus (combination_mode) pro Log-Eintrag int passes_filter(int entry_index) { int status_match = status_code_matches(all_entries[entry_index].status_code); + int method_match = method_matches(all_entries[entry_index].request_method); int ip_match = ip_address_matches(all_entries[entry_index].ip_address); int time_match = time_matches(all_entries[entry_index].time); int user_agent_match = user_agent_matches(all_entries[entry_index].user_agent); if (filters.combination_mode == 0) { - return status_match && ip_match && time_match && user_agent_match; + return status_match && ip_match && time_match && user_agent_match && method_match; } else { - int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count; + int total_filters = filters.status_count + filters.method_count + filters.ip_count + filters.time_count + filters.user_agent_count; if (total_filters == 0) return 1; - return status_match || ip_match || time_match || user_agent_match; + return status_match || method_match || ip_match || time_match || user_agent_match; } } @@ -821,7 +874,7 @@ void show_status() { } printf("\n🔍 Aktive Filter-Logik:\n"); - int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count; + int total_filters = filters.status_count + filters.method_count + filters.ip_count + filters.time_count + filters.user_agent_count; if (total_filters == 0) { printf(" Keine Filter gesetzt → alle Einträge werden angezeigt\n"); @@ -869,6 +922,44 @@ void show_status() { } 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: "); @@ -951,7 +1042,7 @@ void show_status() { } // Zeigt aktuellen Modus - int active_types = (filters.status_count > 0) + (filters.ip_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); if (active_types > 1) { printf("\n %s-Verknüpfung - Ausschlussfilter vorrangig\n", @@ -1238,14 +1329,15 @@ void show_statistics() { void menu_set_filters() { int choice = 0; - while (choice != 4) { + while (choice != 6) { 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. Zurück zum Filter-Menü\n"); + printf("5. HTTP-Methode Filter hinzufügen (Freitext)\n"); + printf("6. Zurück zum Filter-Menü\n"); printf("Auswahl: "); choice = read_safe_integer(); @@ -1445,9 +1537,37 @@ void menu_set_filters() { } } else if (choice == 5) { + if (filters.method_count >= MAX_FILTERS) { + printf("FEHLER: Maximale Anzahl Method-Filter erreicht (%d)!\n", MAX_FILTERS); + continue; + } + + printf("HTTP-Methode eingeben (z.B. 'GET', 'POST', 'PUT'): "); + 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(); + } + + } else if (choice == 6) { return; } else if (choice != -1) { - printf("Ungültige Auswahl! Bitte wählen Sie 1-5.\n"); + printf("Ungültige Auswahl! Bitte wählen Sie 1-6.\n"); } } } @@ -1469,6 +1589,11 @@ void menu_delete_filters() { 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); } + + 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); + } for (int i = 0; i < filters.ip_count; i++) { char* mode_str = (filters.ip_filters[i].mode == FILTER_EXCLUDE) ? "(ausschließen)" : "(einschließen)"; @@ -1524,6 +1649,18 @@ void menu_delete_filters() { } current_index++; } + + for (int i = 0; i < filters.method_count; i++) { + if (current_index == choice) { + for (int j = i; j < filters.method_count - 1; j++) { + filters.method_filters[j] = filters.method_filters[j + 1]; + } + filters.method_count--; + printf("✅ Method-Filter gelöscht.\n"); + return; + } + current_index++; + } for (int i = 0; i < filters.ip_count; i++) { if (current_index == choice) { @@ -1588,6 +1725,7 @@ void menu_filter_mode() { 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;