This commit is contained in:
overcuriousity 2025-09-02 16:22:37 +02:00
parent 58237b1ec4
commit e9cdb49877

View File

@ -203,7 +203,7 @@ int read_safe_integer() {
// Speicher freigeben und mit 0 überschreiben (Prävention von use-after-free-Schwachstelle) // Speicher freigeben und mit 0 überschreiben (Prävention von use-after-free-Schwachstelle)
void cleanup_memory() { void cleanup_memory() {
if (all_entries != NULL) { if (all_entries != NULL) {
printf("%lu Bytes Speicher werden freigegeben\n", (unsigned long)(max_entries * sizeof(struct log_entry))); printf("\nDEBUG: %lu Bytes Speicher werden freigegeben\n", (unsigned long)(max_entries * sizeof(struct log_entry)));
free(all_entries); free(all_entries);
all_entries = NULL; all_entries = NULL;
} }
@ -225,7 +225,7 @@ void mem_expand_dynamically() {
int old_max = max_entries; int old_max = max_entries;
max_entries = max_entries * GROWTH_FACTOR; max_entries = max_entries * GROWTH_FACTOR;
printf("Dynamische Speichererweiterung von %d auf %d Einträge um Faktor %f\n", old_max, max_entries, GROWTH_FACTOR); printf("DEBUG: 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)); struct log_entry *new_ptr = realloc(all_entries, max_entries * sizeof(struct log_entry));
@ -236,7 +236,7 @@ void mem_expand_dynamically() {
} }
all_entries = new_ptr; all_entries = new_ptr;
printf("Speicher erfolgreich erweitert auf %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry))); printf("DEBUG: Speicher erfolgreich erweitert auf %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry)));
} }
} }
@ -250,7 +250,7 @@ void allocate_initial_memory() {
exit(1); // cleanup_and_exit() nicht nötig, da der Speicherbereich nicht beschrieben wurde - use-after-free unproblematisch exit(1); // cleanup_and_exit() nicht nötig, da der Speicherbereich nicht beschrieben wurde - use-after-free unproblematisch
} }
printf("Speicher erfolgreich alloziert für %d Log-Einträge (%lu Bytes)\n", max_entries, (unsigned long)(max_entries * sizeof(struct log_entry))); printf("DEBUG: 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) { void get_current_timestamp(char* buffer, int buffer_size) {
@ -540,7 +540,7 @@ void load_regular_file(char* filename) {
printf("ERROR: Kann Datei '%s' nicht öffnen!\n", filename); printf("ERROR: Kann Datei '%s' nicht öffnen!\n", filename);
return; return;
} }
printf("Lade Datei: %s\n", filename); printf("INFO: Lade Datei: %s\n", filename);
char line[MAX_LINE_LENGTH_BUF]; char line[MAX_LINE_LENGTH_BUF];
int loaded_from_this_file = 0; int loaded_from_this_file = 0;
while (fgets(line, sizeof(line), file) != NULL) { while (fgets(line, sizeof(line), file) != NULL) {
@ -558,8 +558,8 @@ void load_log_file(char* path) {
total_entries = 0; total_entries = 0;
if (is_directory(path)) { if (is_directory(path)) {
printf("Verzeichnis erkannt: %s\n", path); printf("DEBUG: Verzeichnis erkannt: %s\n", path);
printf("Suche nach .log Dateien...\n"); printf("DEBUG: Suche nach .log Dateien...\n");
DIR* dir = opendir(path); DIR* dir = opendir(path);
if (dir == NULL) { if (dir == NULL) {
@ -585,17 +585,17 @@ void load_log_file(char* path) {
files_found++; files_found++;
} else if (strstr(filename, ".gz") != NULL) { } else if (strstr(filename, ".gz") != NULL) {
printf("INFO: .gz Datei '%s' übersprungen (nicht unterstützt in dieser Version)\n", filename); printf("INFO: .gz Datei '%s' übersprungen (nicht unterstützt in dieser Version)\n", filename);
printf(" Tipp: Dekomprimieren Sie mit 'gunzip %s'\n", filename); printf(" Tipp: Dekomprimieren Sie mit 'gunzip %s'\n", filename);
} }
} }
closedir(dir); closedir(dir);
if (files_found == 0) { if (files_found == 0) {
printf("Keine .log Dateien im Verzeichnis gefunden.\n"); printf("WARNING: Keine .log Dateien im Verzeichnis gefunden.\n");
printf("Tipp: Für .gz Dateien verwenden Sie 'gunzip *.gz' zum Dekomprimieren\n"); printf(" Tipp: Für .gz Dateien verwenden Sie 'gunzip *.gz' zum Dekomprimieren\n");
} else { } else {
printf("Insgesamt %d .log Dateien verarbeitet.\n", files_found); printf("INFO: Insgesamt %d .log Dateien verarbeitet.\n", files_found);
} }
} else { } else {
@ -603,17 +603,17 @@ void load_log_file(char* path) {
if (strstr(path, ".gz") != NULL) { if (strstr(path, ".gz") != NULL) {
printf("FEHLER: .gz Dateien werden in dieser Version nicht unterstützt!\n"); printf("FEHLER: .gz Dateien werden in dieser Version nicht unterstützt!\n");
printf("Lösung: Dekomprimieren Sie die Datei zuerst:\n"); printf(" Lösung: Dekomprimieren Sie die Datei zuerst:\n");
printf(" gunzip %s\n", path); printf(" gunzip %s\n", path);
printf(" Dann: %s %.*s\n", "PROGRAMM", (int)(strlen(path)-3), path); printf(" Dann: %s %.*s\n", "PROGRAMM", (int)(strlen(path)-3), path);
return; return;
} else { } else {
load_regular_file(path); load_regular_file(path);
} }
} }
printf("Erfolgreich %d Einträge insgesamt geladen.\n", total_entries); printf("INFO: Erfolgreich %d Einträge insgesamt geladen.\n", total_entries);
printf("Aktueller Speicherverbrauch: %lu Bytes für %d Einträge\n", (unsigned long)(max_entries * sizeof(struct log_entry)), max_entries); printf("DEBUG: Aktueller Speicherverbrauch: %lu Bytes für %d Einträge\n", (unsigned long)(max_entries * sizeof(struct log_entry)), max_entries);
} }
// Funktion zum suchen eines Suchbegriffs innerhalb eines Strings (lowercase) // Funktion zum suchen eines Suchbegriffs innerhalb eines Strings (lowercase)
@ -981,19 +981,23 @@ void format_iso8601_time(struct simple_time time, char* buffer, int buffer_size)
} }
//Export in Timesketch-kompatiblem Format //Export in Timesketch-kompatiblem Format
void export_filtered_entries() { void export_filtered_entries(char *filepath) {
printf("Dateiname für Timesketch-Export eingeben (ohne .csv): ");
//90 chars + delimiter //90 chars + delimiter
char filename[91]; char filename[91];
if (scanf("%90s", filename) != 1) { if (filepath == NULL) {
printf("FEHLER: Ungültiger Dateiname!\n"); printf("Dateiname für Timesketch-Export eingeben (ohne .csv): ");
clear_input_buffer(); if (scanf("%90s", filename) != 1) {
return; printf("FEHLER: Ungültiger Dateiname!\n");
clear_input_buffer();
return;
}
} else {
strncpy(filename, filepath, sizeof(filename) - 1);
filename[sizeof(filename) - 1] = '\0';
} }
clear_input_buffer();
// Dateiendung // Dateiendung
strcat(filename, ".csv"); strcat(filename, ".csv");
printf("\nINFO: Schreibe Datei %s...\n", filename);
FILE* file = fopen(filename, "w"); FILE* file = fopen(filename, "w");
if (file == NULL) { if (file == NULL) {
printf("ERROR: Kann Datei '%s' nicht erstellen!\n", filename); printf("ERROR: Kann Datei '%s' nicht erstellen!\n", filename);
@ -1028,7 +1032,7 @@ void export_filtered_entries() {
} }
fclose(file); fclose(file);
printf("%d Logeinträge erfolgreich als Timesketch-kompatible CSV-Datei nach '%s' exportiert.\n", exported_count, filename); printf("INFO: %d Logeinträge erfolgreich als Timesketch-kompatible CSV-Datei nach '%s' exportiert.\n", exported_count, filename);
} }
struct ip_stat { struct ip_stat {
@ -2150,7 +2154,7 @@ void menu_show_entries() {
supress_preview = 1; supress_preview = 1;
show_filtered_entries(0); show_filtered_entries(0);
} else if (choice == 2) { } else if (choice == 2) {
export_filtered_entries(); export_filtered_entries(0);
} else if (choice == 3) { } else if (choice == 3) {
show_top_x_ips(); show_top_x_ips();
} else if (choice == 4) { } else if (choice == 4) {
@ -2165,66 +2169,118 @@ void menu_show_entries() {
} }
} }
int main(int argc, char* argv[]) { void print_help(char* binary) {
if (argc != 2) {
printf("Verwendung: %s <nginx-log-datei-oder-verzeichnis>\n", argv[0]);
printf("Unterstützte Formate: .log Dateien, sowie für rotierte Logs: .log.1 etc.\n");
printf("Beispiele:\n");
printf(" %s /var/log/nginx/access.log (einzelne .log Datei)\n", argv[0]);
printf(" %s /var/log/nginx/ (Verzeichnis mit .log Dateien)\n", argv[0]);
printf("\nRotierte nginx-Logs (.gz-Archive) müssen manuell dekomprimiert werden:\n");
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("\nNGINX EXAMINATOR\n"); printf("\nNGINX EXAMINATOR\n");
printf("Verwendung:\n");
allocate_initial_memory(); printf(" %s <LOGDATEI|VERZEICHNIS> -i Interaktiver Modus (Filter/Analyse/Export)\n", binary);
load_log_file(argv[1]); printf(" %s <LOGDATEI|VERZEICHNIS> -e <DATEINAME(optional)> Export generieren\n", binary);
printf(" %s -h Diese Hilfe anzeigen\n", binary);
if (total_entries == 0) {
printf("Keine gültigen Log-Einträge gefunden. Überprüfen Sie den Pfad und die Dateiformate.\n"); printf("\nArgumente:\n");
cleanup_memory(); printf(" <LOGDATEI|VERZEICHNIS> Pfad zu einer einzelnen *.log Datei ODER zu einem Ordner,\n");
printf(" der eine oder mehrere *.log / *.log.N Dateien enthält.\n");
printf("\nFlags:\n");
printf(" -i Startet interaktiven Modus mit Filtern (Status, Methode, IP, Zeitraum,\n");
printf(" User-Agent, URL-Teilstring), Vorschau, Statistiken und CSV-Export (Timesketch).\n");
printf(" -e Generiert Timesketch-kompatible CSV-Datei, nimmt optional Dateinamen entgegen.\n");
printf(" -h Zeigt diese Hilfe an.\n");
printf("\nUnterstützte Eingaben:\n");
printf(" - Normale NGINX-Access-Logs: *.log\n");
printf(" - Rotierte Logs: *.log.1, *.log.2, ... (rein textbasiert)\n");
printf(" - GZIP-Archive (*.gz) werden NICHT direkt unterstützt.\n");
printf(" Tipp: Dekomprimieren Sie vorher, z.B.:\n");
printf(" gunzip /var/log/nginx/*.gz\n");
printf(" %s /var/log/nginx/ -i\n", binary);
printf("\nErwartetes NGINX-Logformat (default `log_format main`):\n");
printf(" log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n");
printf(" '$status $body_bytes_sent \"$http_referer\" '\n");
printf(" '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n");
printf("\nBeispielzeile (eine Zeile pro Request):\n");
printf(" 0.0.0.0 - - [31/Aug/2025:00:11:42 +0000] \"GET /.git/config HTTP/1.1\" 400 255 \"-\" \"Mozilla/5.0\" \"-\"\n");
printf("\nBeispiele:\n");
printf(" - Einzeldatei analysieren:\n");
printf(" %s /var/log/nginx/access.log -i\n", binary);
printf(" - Verzeichnis mit mehreren .log / .log.N Dateien:\n");
printf(" %s /var/log/nginx/ -i\n", binary);
printf("\nCSV-Export (Timesketch-kompatibel):\n");
printf(" Spalten: datetime, timestamp_desc, ip_address, method, url_path, status_code,\n");
printf(" bytes_sent, user_agent, source_file, parsing_timestamp\n");
printf("\nHinweise & Einschränkungen:\n");
printf(" - Parser erwartet das obige Standardformat. Abweichungen können zum Abbruch führen.\n");
printf(" - Zeitzone aus dem Log wird gelesen, aber intern als einfache Felder verarbeitet.\n");
printf(" - ATYPICAL-Methode: für fehlerhafte/binäre Requests innerhalb der \"request\"-Spalte.\n");
}
int main(int argc, char* argv[]) {
if (argc <= 3) {
print_help(argv[0]);
return 1; return 1;
} }
int choice = 0; printf("\nNGINX EXAMINATOR\n");
int stats_show = 0;
while (choice != 4 && choice != -4) { allocate_initial_memory();
show_status();
if (stats_show == 1) { if (strcmp(argv[2], "-i") == 0) {
show_stats(); load_log_file(argv[1]);
int stats_show = 0;
if (total_entries == 0) {
printf("Keine gültigen Log-Einträge gefunden. Überprüfen Sie den Pfad und die Dateiformate.\n");
cleanup_memory();
return 1;
} }
show_main_menu(); int choice = 0;
int stats_show = 0;
choice = read_menu_input(); while (choice != 4 && choice != -4) {
choice = handle_menu_shortcuts(choice); show_status();
if (stats_show == 1) {
if (choice == -1) { show_stats();
printf("FEHLER: Bitte geben Sie eine gültige Zahl oder Navigation ein (1-4, b, m, q)!\n"); stats_show = 0;
continue; }
show_main_menu();
choice = read_menu_input();
choice = handle_menu_shortcuts(choice);
if (choice == -1) {
printf("FEHLER: Bitte geben Sie eine gültige Zahl oder Navigation ein (1-4, b, m, q)!\n");
continue;
}
if (choice == 1) {
menu_filter_management();
} else if (choice == 2) {
menu_show_entries();
} else if (choice == 3) {
stats_show = 1;
} else if (choice == 4) {
printf("Programmende\n");
break;
} else if (choice == -4) {
break;
} else {
printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-4 oder b/m/q.\n");
}
} }
} else if (strcmp(argv[2], "-e") == 0){
if (choice == 1) { load_log_file(argv[1]);
menu_filter_management(); if (argc == 4) {
} else if (choice == 2) { export_filtered_entries(argv[3]);
menu_show_entries();
} else if (choice == 3) {
stats_show =1;
} else if (choice == 4) {
printf("Programmende\n");
break;
} else if (choice == -4) {
break;
} else { } else {
printf("FEHLER: Ungültige Auswahl! Bitte wählen Sie 1-4 oder b/m/q.\n"); export_filtered_entries(NULL);
} }
} else if (strcmp(argv[2], "-h") == 0){
print_help(argv[0]);
return 1;
} }
cleanup_memory(); cleanup_memory();
return 0; return 0;
} }