progress
This commit is contained in:
		
							parent
							
								
									c0984b242e
								
							
						
					
					
						commit
						3e990ff05e
					
				
							
								
								
									
										689
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										689
									
								
								src/main.c
									
									
									
									
									
								
							@ -17,10 +17,11 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <dirent.h> // library für Interaktion mit Ordnerstrukturen
 | 
			
		||||
#include <sys/stat.h> // library für is_directory: Unterscheidung zwischen Dateien und Ordnern
 | 
			
		||||
#include <time.h> // 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,
 | 
			
		||||
            fprintf(file, "\"%s\",\"HTTP Access Log\",\"%s\",\"%s\",\"%s\",%d,%d,\"%s\",\"%s\",\"%s\"\n",
 | 
			
		||||
                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);
 | 
			
		||||
                all_entries[i].user_agent,
 | 
			
		||||
                all_entries[i].source_file,
 | 
			
		||||
                all_entries[i].parsing_timestamp);
 | 
			
		||||
            
 | 
			
		||||
            exported_count++;
 | 
			
		||||
        }
 | 
			
		||||
@ -1397,13 +1149,34 @@ 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");
 | 
			
		||||
    
 | 
			
		||||
    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",
 | 
			
		||||
@ -1423,6 +1196,7 @@ void show_filtered_entries() {
 | 
			
		||||
                shown_count++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    printf("\nInsgesamt %d Einträge gefunden.\n", 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");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user