src/main.c aktualisiert

This commit is contained in:
Mario Stöckl 2025-09-07 17:49:30 +00:00
parent cd57025123
commit 2df49d7860

View File

@ -30,9 +30,10 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#define GROWTH_FACTOR 1.1 // 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_FILTERS 100
#define MAX_REQUEST_LENGTH 8192 // das hohe Limit ist erforderlich, da teilweise ausufernde JSON-Requests in nginx auflaufen können. #define MAX_REQUEST_LENGTH 8192 // das hohe Limit ist erforderlich, da teilweise ausufernde JSON-Requests in nginx auflaufen können.
#define MAX_PREVIEW 10000
// struct für die Darstellung von Timestamps. Die granulare Trennung in verschiedene int-Werte macht die spätere Verarbeitung modular anpassbar/erweiterbar und erleichtert die Verarbeitung. // struct für die Darstellung von Timestamps. Die granulare Trennung in verschiedene int-Werte macht die spätere Verarbeitung modular anpassbar/erweiterbar und erleichtert die Verarbeitung.
struct simple_time { struct simple_time_t {
int day; int day;
int month; int month;
int year; int year;
@ -42,13 +43,13 @@ struct simple_time {
}; };
// Struktur für die Darstellung eines Standard-NGINX-Logeintrags. // Struktur für die Darstellung eines Standard-NGINX-Logeintrags.
struct log_entry { struct log_entry_t {
char ip_address[50]; // ausreichende Längenbegrenzung für IP-Adressen. Könnte theoretisch auch ipv6 (ungetestet) char ip_address[50]; // ausreichende Längenbegrenzung für IP-Adressen. Könnte theoretisch auch ipv6 (ungetestet)
char request_method[10]; // GET, POST, PUT, DELETE, PROPFIND ... char request_method[10]; // GET, POST, PUT, DELETE, PROPFIND ...
char url_path[MAX_REQUEST_LENGTH]; // Pfade können lang werden, insbesodere bei base64-Strings wie oft in Malware verwendet char url_path[MAX_REQUEST_LENGTH]; // Pfade können lang werden, insbesodere bei base64-Strings wie oft in Malware verwendet
int status_code; int status_code;
int bytes_sent; int bytes_sent;
struct simple_time time; struct simple_time_t time;
char referrer[128]; char referrer[128];
char user_agent[256]; char user_agent[256];
char source_file[256]; char source_file[256];
@ -56,57 +57,57 @@ struct log_entry {
}; };
// Struktur für einen Status-Filtereintrag mit Inhalt & Modus // Struktur für einen Status-Filtereintrag mit Inhalt & Modus
struct status_filter { struct status_filter_t {
int code; int code;
int filter_exclude_flag; int filter_exclude_flag;
}; };
struct method_filter { struct method_filter_t {
char pattern[10]; char pattern[10];
int filter_exclude_flag; int filter_exclude_flag;
}; };
// für IP-Adressen // für IP-Adressen
struct ip_filter { struct ip_filter_t {
char ip_address[50]; char ip_address[50];
int filter_exclude_flag; int filter_exclude_flag;
}; };
// Filter für User-Agent // Filter für User-Agent
struct user_agent_filter { struct user_agent_filter_t {
char pattern[256]; char pattern[256];
int filter_exclude_flag; int filter_exclude_flag;
}; };
// Filter für URL-Pfad/Request // Filter für URL-Pfad/Request
struct url_filter { struct url_filter_t {
char pattern[MAX_REQUEST_LENGTH]; char pattern[MAX_REQUEST_LENGTH];
int filter_exclude_flag; int filter_exclude_flag;
}; };
// Struktur zum erhalten aller Filtereinträge, kann im Dialogbetrieb bearbeitet werden. Mit Zähler. // Struktur zum erhalten aller Filtereinträge, kann im Dialogbetrieb bearbeitet werden. Mit Zähler.
struct filter_system { struct filter_system_t {
struct status_filter status_filters[MAX_FILTERS]; struct status_filter_t status_filters[MAX_FILTERS];
int status_count; int status_count;
struct method_filter method_filters[MAX_FILTERS]; struct method_filter_t method_filters[MAX_FILTERS];
int method_count; int method_count;
struct ip_filter ip_filters[MAX_FILTERS]; struct ip_filter_t ip_filters[MAX_FILTERS];
int ip_count; int ip_count;
struct user_agent_filter user_agent_filters[MAX_FILTERS]; struct user_agent_filter_t user_agent_filters[MAX_FILTERS];
int user_agent_count; int user_agent_count;
struct url_filter url_filters[MAX_FILTERS]; struct url_filter_t url_filters[MAX_FILTERS];
int url_count; int url_count;
}; };
// Initialisierung eines Arrays für die Logeinträge und weiterer Startvariablen // Initialisierung eines Arrays für die Logeinträge und weiterer Startvariablen
struct log_entry *all_entries = NULL; struct log_entry_t *all_entries = NULL;
int max_entries = 0; int max_entries = 0;
int total_entries = 0; int total_entries = 0;
struct filter_system filters = {0}; struct filter_system_t filters = {0};
// für -v option // für -v option
int flag_verbose = 0; int flag_verbose = 0;
@ -160,7 +161,7 @@ int month_name_to_number(char* month_name) {
// 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("\nDEBUG: %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_t)));
free(all_entries); free(all_entries);
all_entries = NULL; all_entries = NULL;
} }
@ -191,47 +192,49 @@ void mem_expand_dynamically(){
if (flag_verbose) printf("DEBUG: Dynamische Speichererweiterung von %d auf %d Einträge um Faktor %f\n", old_max, max_entries, GROWTH_FACTOR); if (flag_verbose) 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_t *new_ptr = realloc(all_entries, max_entries * sizeof(struct log_entry_t));
if (new_ptr == NULL){ if (new_ptr == NULL){
printf("ERROR: Speicher konnte nicht auf %d Einträge erweitert werden, ..\n", max_entries); printf("ERROR: Speicher konnte nicht auf %d Einträge erweitert werden, ..\n", max_entries);
printf("ERROR: Benötigter Speicher: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry))); printf("ERROR: Benötigter Speicher: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry_t)));
cleanup_and_exit(); cleanup_and_exit();
} }
all_entries = new_ptr; all_entries = new_ptr;
if (flag_verbose) printf("DEBUG: Speicher erfolgreich erweitert auf %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry))); if (flag_verbose) printf("DEBUG: Speicher erfolgreich erweitert auf %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry_t)));
} }
} }
void allocate_initial_memory(){ void allocate_initial_memory(){
max_entries = INITIAL_ENTRIES; // Startwert 1000, globale Variable max_entries = INITIAL_ENTRIES; // Startwert 1000, globale Variable
all_entries = malloc(max_entries * sizeof(struct log_entry)); all_entries = malloc(max_entries * sizeof(struct log_entry_t));
if (all_entries == NULL){ if (all_entries == NULL){
printf("ERROR: Konnte %d Einträge nicht allozieren, ..\n", max_entries); printf("ERROR: Konnte %d Einträge nicht allozieren, ..\n", max_entries);
printf("ERROR: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry))); printf("ERROR: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry_t)));
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
} }
if (flag_verbose) printf("DEBUG: Speicher erfolgreich alloziert für %d Log-Einträge (%lu Bytes)\n", max_entries, (unsigned long)(max_entries * sizeof(struct log_entry))); if (flag_verbose) printf("DEBUG: Speicher erfolgreich alloziert für %d Log-Einträge (%lu Bytes)\n", max_entries, (unsigned long)(max_entries * sizeof(struct log_entry_t)));
} }
void get_current_timestamp(char* buffer, int buffer_size) { // aktuelle Timestamp erfassen
void get_current_timestamp(char* buffer){
time_t raw_time; time_t raw_time;
struct tm *time_info; struct tm *time_info;
int timestamp_buffer_size =32;
time(&raw_time); time(&raw_time);
time_info = localtime(&raw_time); time_info = localtime(&raw_time);
if (time_info != NULL){ if (time_info != NULL){
strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", time_info); strftime(buffer, timestamp_buffer_size, "%Y-%m-%d %H:%M:%S", time_info);
} else { } else {
snprintf(buffer, buffer_size, "UNKNOWN"); sprintf(buffer, "UNKNOWN");
} }
} }
// Hilfsfunktion zum Prüfen, ob es sich beim Pfad um ein Directory handelt - für rekursives Parsen // Hilfsfunktion zum Prüfen, ob es sich beim Pfad um ein Directory handelt - für rekursives Parsen
// https://stackoverflow.com/questions/4553012/checking-if-a-file-is-a-directory-or-just-a-file
int is_directory(char* path){ int is_directory(char* path){
struct stat path_stat; struct stat path_stat;
if (stat(path, &path_stat) != 0){ if (stat(path, &path_stat) != 0){
@ -438,7 +441,7 @@ int parse_simple_log_line(char* line, int entry_index, char* source_file) { // N
if (is_valid_method){ if (is_valid_method){
// Normal parsen: 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); strncpy(all_entries[entry_index].request_method, temp_method,sizeof(all_entries[entry_index].request_method));
while (*current_pos != ' ' && *current_pos != '\0'){ while (*current_pos != ' ' && *current_pos != '\0'){
current_pos++; current_pos++;
} }
@ -461,15 +464,17 @@ int parse_simple_log_line(char* line, int entry_index, char* source_file) { // N
} else { } else {
// in NGINX treten gelegentlich fehlerhafte Requests auf, die binäre Daten übersenden, sodass normales parsen nicht möglich ist. // 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 "ATYPICAL" repräsentiert // der entsprechende Eintrag wird daher mit dem String "ATYPICAL" repräsentiert
// strcpy reicht hier aus, da der Wert "ATYPICAL" hard-gecoded und somit deterministisch ist"
strcpy(all_entries[entry_index].request_method, "ATYPICAL"); strcpy(all_entries[entry_index].request_method, "ATYPICAL");
// Read entire quoted content into url_path for forensic analysis // Kompletten Inhalt zwischen "" einlesen
int i = 0; int i = 0;
while (*current_pos != '"' && *current_pos != '\0' && i < sizeof(all_entries[entry_index].url_path) - 1){ while (*current_pos != '"' && *current_pos != '\0' && i < sizeof(all_entries[entry_index].url_path) - 1){
all_entries[entry_index].url_path[i] = *current_pos; all_entries[entry_index].url_path[i] = *current_pos;
i++; i++;
current_pos++; current_pos++;
} }
// Nullterminator anfügen
all_entries[entry_index].url_path[i] = '\0'; all_entries[entry_index].url_path[i] = '\0';
// zum Ende des request-strings vorarbeiten, wenn der String zu lang war. // zum Ende des request-strings vorarbeiten, wenn der String zu lang war.
@ -507,19 +512,23 @@ int parse_simple_log_line(char* line, int entry_index, char* source_file) { // N
} }
current_pos = skip_spaces(current_pos); current_pos = skip_spaces(current_pos);
// Parsen des Referrer-Feldes innerhalb "", wird übersprungen da nicht gespeichert // Parsen des Referrer-Feldes innerhalb ""
if (*current_pos == '"'){ if (*current_pos == '"'){
current_pos++; // öffnendes Anführungszeichen überspringen current_pos++; // öffnendes Anführungszeichen überspringen
// Referrer-Inhalt bis zum schließenden Anführungszeichen überspringen // Referrer-Inhalt zwischen "" einlesen
while (*current_pos != '"' && *current_pos != '\0') { int i = 0;
while (*current_pos != '"' && *current_pos != '\0' && i < sizeof(all_entries[entry_index].referrer) - 1){
all_entries[entry_index].referrer[i] = *current_pos;
i++;
current_pos++; current_pos++;
} }
all_entries[entry_index].referrer[i] = '\0';
if (*current_pos == '"') current_pos++; // schließendes Anführungszeichen überspringen if (*current_pos == '"') current_pos++; // schließendes Anführungszeichen überspringen
} else { } else {
printf("ERROR: Unerwartetes Log-Format. Lediglich mit standard-nginx-accesslog kompatibel.\nDer Fehler ist beim Prüfen des Referrer-Feldes aufgetreten.\nLogeintrag: %s\n", line); printf("ERROR: Unerwartetes Log-Format. Lediglich mit standard-nginx-accesslog kompatibel.\nDer Fehler ist beim Prüfen des Referrer-Feldes aufgetreten.\nLogeintrag: %s\n", line);
cleanup_and_exit(); cleanup_and_exit();
} }
current_pos = skip_spaces(current_pos); current_pos = skip_spaces(current_pos);
// parsen des user agents innerhalb "" // parsen des user agents innerhalb ""
if (*current_pos == '"'){ if (*current_pos == '"'){
@ -536,7 +545,7 @@ int parse_simple_log_line(char* line, int entry_index, char* source_file) { // N
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);\"\nLogeintrag: %s\n", line); 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);\"\nLogeintrag: %s\n", line);
cleanup_and_exit(); cleanup_and_exit();
} }
get_current_timestamp(all_entries[entry_index].parsing_timestamp, sizeof(all_entries[entry_index].parsing_timestamp)); get_current_timestamp(all_entries[entry_index].parsing_timestamp);
// Dateinamen in das Feld schreiben - strncpy um Buffer overflow zu verhindern // 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(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 // strncpy setzt keinen Nullterminator, dieser muss am Ende eingefügt werden
@ -637,11 +646,11 @@ void load_log_file(char* path) {
int needs_slash = (path_len > 0 && path[path_len - 1] != '/'); int needs_slash = (path_len > 0 && path[path_len - 1] != '/');
if (is_log_file(filename)){ if (is_log_file(filename)){
(needs_slash) ? snprintf(full_path, sizeof(full_path), "%s/%s", path, filename) : snprintf(full_path, sizeof(full_path), "%s%s", path, filename); (needs_slash) ? sprintf(full_path, "%s/%s", path, filename) : sprintf(full_path, "%s%s", path, filename);
load_regular_file(full_path); load_regular_file(full_path);
files_found++; files_found++;
} else if (strstr(filename, ".gz") != NULL){ } else if (strstr(filename, ".gz") != NULL){
(needs_slash) ? snprintf(full_path, sizeof(full_path), "%s/%s", path, filename) : snprintf(full_path, sizeof(full_path), "%s%s", path, filename); (needs_slash) ? sprintf(full_path, "%s/%s", path, filename) : sprintf(full_path, "%s%s", path, filename);
load_gz_file(full_path); load_gz_file(full_path);
files_found++; files_found++;
} }
@ -665,7 +674,7 @@ void load_log_file(char* path) {
printf("INFO: Erfolgreich %d Einträge insgesamt geladen.\n", total_entries); printf("INFO: Erfolgreich %d Einträge insgesamt geladen.\n", total_entries);
if (flag_verbose) printf("DEBUG: Aktueller Speicherverbrauch: %lu Bytes für %d Einträge\n", if (flag_verbose) printf("DEBUG: Aktueller Speicherverbrauch: %lu Bytes für %d Einträge\n",
(unsigned long)(max_entries * sizeof(struct log_entry)), max_entries); (unsigned long)(max_entries * sizeof(struct log_entry_t)), max_entries);
} }
// Filterfunktion für den User-Agent. Nimmt den Datensatz entgegen und prüft gegen die gesetzten Filter, gibt dann 0 oder 1 zurück // Filterfunktion für den User-Agent. Nimmt den Datensatz entgegen und prüft gegen die gesetzten Filter, gibt dann 0 oder 1 zurück
@ -822,10 +831,34 @@ int count_filtered_entries(){
} }
// notwendig, um konformes Timestamp-Format aus simple_time struct zu generieren. Unterstützt derzeit nur UTC // 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) { void format_datetime(struct simple_time_t time, char* buffer){
snprintf(buffer, buffer_size, "%04d-%02d-%02dT%02d:%02d:%02d+00:00", time.year, time.month, time.day, time.hour, time.minute, time.second); sprintf(buffer, "%04d-%02d-%02dT%02d:%02d:%02d+00:00", time.year, time.month, time.day, time.hour, time.minute, time.second);
} }
void show_preview(){
char datetime[32];
int lines_shown = 0;
int count_filtered =0;
printf("\n");
printf("| TIMESTAMP | IP-Adresse | HTTP-METHODE | PFAD/PAYLOAD | USERAGENT | STATUSCODE | BYTES | REFERRER |\n");
printf("|---------------------|-----------------|--------------|--------------------------------|----------------------|------------|----------|----------------------|\n");
for (int i = 0; i < MAX_PREVIEW; i++){
if (passes_filter(i)){
format_datetime(all_entries[i].time, datetime);
printf("| %-19.19s | %-15.15s | %-12.12s | %-30.30s | %-20.20s | %-10d | %-8d | %-20.20s |\n", datetime, all_entries[i].ip_address, all_entries[i].request_method, all_entries[i].url_path, all_entries[i].user_agent, all_entries[i].status_code, all_entries[i].bytes_sent, all_entries[i].referrer);
lines_shown++;
}
}
for (int i = 0; i < total_entries; i++){
if (passes_filter(i)){
count_filtered++;
}
}
printf("\n%d Zeilen von insgesamt %d Einträgen(gefiltert) angezeigt.\nInsgesamt %d Einträge im Datensatz.\n", lines_shown, total_entries, count_filtered);
}
void export_filtered_entries(char *filepath){ void export_filtered_entries(char *filepath){
// 90 chars +delimiter // 90 chars +delimiter
char filename[91]; char filename[91];
@ -836,6 +869,7 @@ void export_filtered_entries(char *filepath) {
return; return;
} }
} else { } else {
// buffer overflow verhindern
strncpy(filename, filepath, sizeof(filename) - 1); strncpy(filename, filepath, sizeof(filename) - 1);
filename[sizeof(filename) - 1] = '\0'; filename[sizeof(filename) - 1] = '\0';
} }
@ -851,12 +885,12 @@ void export_filtered_entries(char *filepath) {
// CSV-Kopfzeile für Timesketch-Kompatibilität // CSV-Kopfzeile für Timesketch-Kompatibilität
fprintf(file, "datetime,message,timestamp_desc,ip_address,method,url_path,status_code,bytes_sent,user_agent,parsing_timestamp\n"); fprintf(file, "datetime,message,timestamp_desc,ip_address,method,url_path,status_code,bytes_sent,user_agent,parsing_timestamp\n");
char iso_datetime[32]; char datetime[32];
for (int i = 0; i < total_entries; i++){ for (int i = 0; i < total_entries; i++){
if (passes_filter(i)){ if (passes_filter(i)){
format_iso8601_time(all_entries[i].time, iso_datetime, sizeof(iso_datetime)); format_datetime(all_entries[i].time, datetime);
fprintf(file, "%s,%s,\"NGINX Log\",%s,%s,%s,%d,%d,%s,%s\n", iso_datetime, all_entries[i].source_file, 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].parsing_timestamp); fprintf(file, "%s,%s,\"NGINX Log\",%s,%s,%s,%d,%d,%s,%s,%s\n", datetime, all_entries[i].source_file, 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].referrer,all_entries[i].parsing_timestamp);
} }
} }
@ -902,7 +936,7 @@ void apply_ip_filter(char* value, int filter_exclude_flag) {
} }
// setzen des Filters // setzen des Filters
strcpy(filters.ip_filters[filters.ip_count].ip_address, value); strncpy(filters.ip_filters[filters.ip_count].ip_address, value,sizeof(filters.ip_filters[filters.ip_count].ip_address));
filters.ip_filters[filters.ip_count].filter_exclude_flag = filter_exclude_flag; filters.ip_filters[filters.ip_count].filter_exclude_flag = filter_exclude_flag;
filters.ip_count++; filters.ip_count++;
@ -921,7 +955,7 @@ void apply_method_filter(char* value, int filter_exclude_flag) {
return; return;
} }
strcpy(filters.method_filters[filters.method_count].pattern, value); strncpy(filters.method_filters[filters.method_count].pattern,value, sizeof(filters.method_filters[filters.method_count].pattern));
filters.method_filters[filters.method_count].filter_exclude_flag = filter_exclude_flag; filters.method_filters[filters.method_count].filter_exclude_flag = filter_exclude_flag;
filters.method_count++; filters.method_count++;
@ -940,7 +974,7 @@ void apply_useragent_filter(char* value, int filter_exclude_flag) {
return; return;
} }
strcpy(filters.user_agent_filters[filters.user_agent_count].pattern, value); strncpy(filters.user_agent_filters[filters.user_agent_count].pattern, value,sizeof(filters.user_agent_filters[filters.user_agent_count].pattern));
filters.user_agent_filters[filters.user_agent_count].filter_exclude_flag = filter_exclude_flag; filters.user_agent_filters[filters.user_agent_count].filter_exclude_flag = filter_exclude_flag;
filters.user_agent_count++; filters.user_agent_count++;
@ -959,7 +993,7 @@ void apply_url_filter(char* value, int filter_exclude_flag) {
return; return;
} }
strcpy(filters.url_filters[filters.url_count].pattern, value); strncpy(filters.url_filters[filters.url_count].pattern, value,sizeof(filters.url_filters[filters.url_count].pattern));
filters.url_filters[filters.url_count].filter_exclude_flag = filter_exclude_flag; filters.url_filters[filters.url_count].filter_exclude_flag = filter_exclude_flag;
filters.url_count++; filters.url_count++;
@ -1054,6 +1088,7 @@ void print_help(char* binary) {
printf("NGINX-Auditor (Beleg)\n"); printf("NGINX-Auditor (Beleg)\n");
printf("Nutzung: %s <LOGFILE|VERZEICHNIS> [Flags]\n\n", binary); printf("Nutzung: %s <LOGFILE|VERZEICHNIS> [Flags]\n\n", binary);
printf("Flags:\n"); printf("Flags:\n");
printf(" -i [Logfile|Verzeichnis] Optional Eingabe definieren - Datei oder Verzeichnis; Standard /var/log/nginx\n");
printf(" -e [Dateiname ohne Endung] Export zu Timestamp-kompatiblem CSV\n"); printf(" -e [Dateiname ohne Endung] Export zu Timestamp-kompatiblem CSV\n");
printf(" -f --[Filterobjekt] Filtern mit den folgenden Optionen:\n"); printf(" -f --[Filterobjekt] Filtern mit den folgenden Optionen:\n");
printf(" --status=[HTTP-Statuscode],[Weiterer],[...] HTTP Status Codes, z.B. 200, 404,301,...\n"); printf(" --status=[HTTP-Statuscode],[Weiterer],[...] HTTP Status Codes, z.B. 200, 404,301,...\n");
@ -1068,82 +1103,65 @@ void print_help(char* binary) {
} }
int main(int argc, char* argv[]){ int main(int argc, char* argv[]){
if (argc < 2) { char* input_path = "/var/log/nginx"; // Standardpfad
print_help(argv[0]); char export_filename[50];
return 1;
}
printf("\nNGINX EXAMINATOR\n");
// Dateipfad: wenn nicht angegeben, wird /var/log/nginx (Standardpfad) untersucht
char* input_path;
int arg_offset = 1; // Offset für die args
// Prüfen des ersten Zeichens des ersten Arguments - Pfad oder Flag?
if (argv[1][0] == '-') {
// Ist ein Flag - Standardpfad, Offset bleibt bei 1
input_path = "/var/log/nginx/";
arg_offset = 1;
} else {
input_path = argv[1];
arg_offset = 2; // Offset inkrementieren, Dateipfad schiebt die args nach hinten
}
int flag_export = 0; int flag_export = 0;
int flag_help = 0; int flag_filter =0;
// int flag_verbose = 0; - global definiert int flag_has_export_filename = 0;
int flag_showpreview =0;
char export_filename[90];
int flag_has_filename = 0;
allocate_initial_memory(); allocate_initial_memory();
for (int i=1; i<argc; i++){
if (argc >= 2){ if (i==0){
// hier wird das offset angewendet continue;
for (int i=arg_offset; i<argc; i++) { }
if (strcmp(argv[i], "-e")==0) { if (starts_with(argv[i], "-i")){
if (!starts_with(argv[i+1], "-")&& i+1<argc){
input_path = argv[i+1];
}
}
if (starts_with(argv[i], "-e")){
flag_export =1; flag_export =1;
if (i+1<argc && argv[i+1][0]!='-'){ if (!starts_with(argv[i+1], "-")&& i+1<argc){
strncpy(export_filename, argv[i + 1], sizeof(export_filename) - 1); strncpy(export_filename, argv[i + 1], sizeof(export_filename) - 1);
flag_has_filename = 1; flag_has_export_filename =1;
i++; // Schleife weiter iterieren
}
} else if (strcmp(argv[i], "-f")==0) {
// parsen der nachfolgenden Argumente --ip= usw.
for (int j = i + 1; j < argc; j++) {
if (starts_with(argv[j], "--")) {
parse_filter_argument(argv[j]);
}else{
break;
} }
} }
if (starts_with(argv[i], "-f")){
} else if (strcmp(argv[i], "-h")==0) { flag_filter = 1;
flag_help = 1;
} else if (strcmp(argv[i], "-v")==0) {
flag_verbose = 1;
} }
if (starts_with(argv[i], "--")){
parse_filter_argument(argv[i]);
} }
if (starts_with(argv[i], "-v")){
flag_verbose =1; // globale Variable oben definiert
} }
if (starts_with(argv[i], "-s")){
// Aktionen basierend auf gesetzten flags ausführen flag_showpreview =1;
if (flag_help == 1){ printf("Flag for show prewview set\n");
}
if (starts_with(argv[i], "-h")){
print_help(argv[0]); print_help(argv[0]);
return 1; }
} else if (flag_export == 1) { }
load_log_file(input_path); load_log_file(input_path);
if (flag_has_filename == 1) { if (flag_export ==1){
if (flag_has_export_filename){
export_filtered_entries(export_filename); export_filtered_entries(export_filename);
} else { } else {
export_filtered_entries(NULL); export_filtered_entries(NULL);
} }
} else { } else {
// Standard-Verhalten: Logs laden und Zusammenfassung anzeigen // Standard-Verhalten: Logs laden und Zusammenfassung anzeigen
load_log_file(input_path);
int filtered_count = count_filtered_entries(); int filtered_count = count_filtered_entries();
printf("Geladen: %d Einträge, %d entsprechen den Filtern. Nutzen Sie -e zum Exportieren.\n", printf("Geladen: %d Einträge, %d entsprechen den Filtern. Nutzen Sie -e zum Exportieren.\n", total_entries, filtered_count);
total_entries, filtered_count); }
if (flag_showpreview==1){
printf("should show preview here\n");
show_preview();
} }
cleanup_memory(); cleanup_memory();
printf("INFO: Ausführung beendet.\n");
return 0; return 0;
} }