diff --git a/modules/security/bot-analyzer.sh b/modules/security/bot-analyzer.sh index 163b1fb..d031297 100755 --- a/modules/security/bot-analyzer.sh +++ b/modules/security/bot-analyzer.sh @@ -359,7 +359,12 @@ parse_logs() { # Format: IP - - [timestamp] "METHOD URL PROTOCOL" STATUS SIZE "REFERRER" "USER-AGENT" awk -v domain="$domain" -v hours_filter="$HOURS_BACK" -v days_filter="$DAYS_BACK" ' BEGIN { - # Calculate cutoff timestamp in epoch seconds for proper comparison + # Month name to number lookup + month["Jan"]=1; month["Feb"]=2; month["Mar"]=3; month["Apr"]=4 + month["May"]=5; month["Jun"]=6; month["Jul"]=7; month["Aug"]=8 + month["Sep"]=9; month["Oct"]=10; month["Nov"]=11; month["Dec"]=12 + + # Calculate cutoff timestamp in epoch seconds if (hours_filter != "") { cmd = "date -d \"" hours_filter " hours ago\" +%s 2>/dev/null || date -v-" hours_filter "H +%s 2>/dev/null" cmd | getline cutoff_epoch @@ -387,24 +392,28 @@ parse_logs() { # Filter by timestamp if time filter is set if ((hours_filter != "" || days_filter != "") && timestamp != "unknown" && cutoff_epoch != "") { # Extract just the date/time part (before timezone) + # Format: 31/Dec/2025:10:30:15 -0500 split(timestamp, ts_parts, " ") log_ts = ts_parts[1] - # Convert Apache timestamp format for date parsing - # From: 31/Dec/2025:10:30:15 - # To: 31 Dec 2025 10:30:15 - log_ts_formatted = log_ts - sub(/:/, " ", log_ts_formatted) # Replace first : with space - gsub(/\//, " ", log_ts_formatted) # Replace all / with space + # Parse: dd/mmm/yyyy:HH:MM:SS + split(log_ts, dt, /[\/:]/) + day = dt[1] + mon = month[dt[2]] + year = dt[3] + hour = dt[4] + min = dt[5] + sec = dt[6] - # Convert to epoch seconds (GNU date for Linux, BSD date for macOS) - cmd = "date -d \"" log_ts_formatted "\" +%s 2>/dev/null || date -j -f \"%d %b %Y %H:%M:%S\" \"" log_ts_formatted "\" +%s 2>/dev/null" - cmd | getline log_epoch - close(cmd) + # Convert to epoch using awk mktime (YYYY MM DD HH MM SS) + # mktime is much faster than spawning date command + if (mon != "") { + log_epoch = mktime(year " " mon " " day " " hour " " min " " sec) - # Numerical comparison of epoch seconds - if (log_epoch != "" && log_epoch < cutoff_epoch) { - next # Skip this entry, too old + # Numerical comparison of epoch seconds + if (log_epoch < cutoff_epoch) { + next # Skip this entry, too old + } } }