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)
void cleanup_memory() {
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);
all_entries = NULL;
}
@ -225,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 %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));
@ -236,7 +236,7 @@ void mem_expand_dynamically() {
}
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
}
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) {
@ -540,7 +540,7 @@ void load_regular_file(char* filename) {
printf("ERROR: Kann Datei '%s' nicht öffnen!\n", filename);
return;
}
printf("Lade Datei: %s\n", filename);
printf("INFO: Lade Datei: %s\n", filename);
char line[MAX_LINE_LENGTH_BUF];
int loaded_from_this_file = 0;
while (fgets(line, sizeof(line), file) != NULL) {
@ -558,8 +558,8 @@ void load_log_file(char* path) {
total_entries = 0;
if (is_directory(path)) {
printf("Verzeichnis erkannt: %s\n", path);
printf("Suche nach .log Dateien...\n");
printf("DEBUG: Verzeichnis erkannt: %s\n", path);
printf("DEBUG: Suche nach .log Dateien...\n");
DIR* dir = opendir(path);
if (dir == NULL) {
@ -585,17 +585,17 @@ void load_log_file(char* path) {
files_found++;
} else if (strstr(filename, ".gz") != NULL) {
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);
if (files_found == 0) {
printf("Keine .log Dateien im Verzeichnis gefunden.\n");
printf("Tipp: Für .gz Dateien verwenden Sie 'gunzip *.gz' zum Dekomprimieren\n");
printf("WARNING: Keine .log Dateien im Verzeichnis gefunden.\n");
printf(" Tipp: Für .gz Dateien verwenden Sie 'gunzip *.gz' zum Dekomprimieren\n");
} else {
printf("Insgesamt %d .log Dateien verarbeitet.\n", files_found);
printf("INFO: Insgesamt %d .log Dateien verarbeitet.\n", files_found);
}
} else {
@ -603,17 +603,17 @@ void load_log_file(char* path) {
if (strstr(path, ".gz") != NULL) {
printf("FEHLER: .gz Dateien werden in dieser Version nicht unterstützt!\n");
printf("Lösung: Dekomprimieren Sie die Datei zuerst:\n");
printf(" gunzip %s\n", path);
printf(" Dann: %s %.*s\n", "PROGRAMM", (int)(strlen(path)-3), path);
printf(" Lösung: Dekomprimieren Sie die Datei zuerst:\n");
printf(" gunzip %s\n", path);
printf(" Dann: %s %.*s\n", "PROGRAMM", (int)(strlen(path)-3), path);
return;
} else {
load_regular_file(path);
}
}
printf("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("INFO: Erfolgreich %d Einträge insgesamt geladen.\n", total_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)
@ -981,19 +981,23 @@ void format_iso8601_time(struct simple_time time, char* buffer, int buffer_size)
}
//Export in Timesketch-kompatiblem Format
void export_filtered_entries() {
printf("Dateiname für Timesketch-Export eingeben (ohne .csv): ");
void export_filtered_entries(char *filepath) {
//90 chars + delimiter
char filename[91];
if (scanf("%90s", filename) != 1) {
printf("FEHLER: Ungültiger Dateiname!\n");
clear_input_buffer();
return;
if (filepath == NULL) {
printf("Dateiname für Timesketch-Export eingeben (ohne .csv): ");
if (scanf("%90s", filename) != 1) {
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
strcat(filename, ".csv");
printf("\nINFO: Schreibe Datei %s...\n", filename);
FILE* file = fopen(filename, "w");
if (file == NULL) {
printf("ERROR: Kann Datei '%s' nicht erstellen!\n", filename);
@ -1028,7 +1032,7 @@ void export_filtered_entries() {
}
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 {
@ -2150,7 +2154,7 @@ void menu_show_entries() {
supress_preview = 1;
show_filtered_entries(0);
} else if (choice == 2) {
export_filtered_entries();
export_filtered_entries(0);
} else if (choice == 3) {
show_top_x_ips();
} else if (choice == 4) {
@ -2165,66 +2169,118 @@ void menu_show_entries() {
}
}
int main(int argc, char* argv[]) {
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) {
}
void print_help(char* binary) {
printf("\nNGINX EXAMINATOR\n");
allocate_initial_memory();
load_log_file(argv[1]);
if (total_entries == 0) {
printf("Keine gültigen Log-Einträge gefunden. Überprüfen Sie den Pfad und die Dateiformate.\n");
cleanup_memory();
printf("Verwendung:\n");
printf(" %s <LOGDATEI|VERZEICHNIS> -i Interaktiver Modus (Filter/Analyse/Export)\n", binary);
printf(" %s <LOGDATEI|VERZEICHNIS> -e <DATEINAME(optional)> Export generieren\n", binary);
printf(" %s -h Diese Hilfe anzeigen\n", binary);
printf("\nArgumente:\n");
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;
}
int choice = 0;
int stats_show = 0;
while (choice != 4 && choice != -4) {
show_status();
if (stats_show == 1) {
show_stats();
int stats_show = 0;
printf("\nNGINX EXAMINATOR\n");
allocate_initial_memory();
if (strcmp(argv[2], "-i") == 0) {
load_log_file(argv[1]);
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();
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;
int choice = 0;
int stats_show = 0;
while (choice != 4 && choice != -4) {
show_status();
if (stats_show == 1) {
show_stats();
stats_show = 0;
}
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");
}
}
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 if (strcmp(argv[2], "-e") == 0){
load_log_file(argv[1]);
if (argc == 4) {
export_filtered_entries(argv[3]);
} 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();
return 0;
}