src/main.c aktualisiert
This commit is contained in:
parent
cd57025123
commit
2df49d7860
222
src/main.c
222
src/main.c
@ -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;
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user