CRITICAL FIX: Resolve subshell data loss preventing auto-blocking

Problem:
- Scores showing 100 in display but IPs NOT being auto-blocked
- HTTP/SSH/network monitoring run in subshells (pipe/background processes)
- IP_DATA array updates in subshells invisible to parent process
- Auto-mitigation engine reading stale ip_data file with score=0
- Result: SUSPICIOUS_UA and other attacks never triggering blocks

Root Cause:
```bash
tail -F logs | while read line; do
    IP_DATA[$ip]=100  # Updates in SUBSHELL - parent never sees it!
done
```

Solution:
1. Added write_ip_data_to_file() with flock-based locking
2. Every IP_DATA update now writes directly to ip_data file
3. Auto-mitigation engine can now see real-time scores
4. Fixed in 8 locations:
   - update_ip_intelligence (main scoring)
   - HTTP log monitoring (ET attacks)
   - AbuseIPDB reputation boost (3 levels)
   - cPHulk monitoring
   - SYN flood detection
   - Port scan detection

Testing:
- SUSPICIOUS_UA reaching score 100 will now auto-block
- All attack types properly trigger mitigation
- File locking prevents race conditions
- Background writes prevent blocking main loop

This fixes the #1 reported issue where attacks showed critical
scores but were never blocked.
This commit is contained in:
cschantz
2026-01-06 17:27:04 -05:00
parent 72047b4098
commit 4a9f40ce53
@@ -305,6 +305,32 @@ get_ip_intelligence() {
fi
}
# Write IP data directly to file (for cross-process communication)
write_ip_data_to_file() {
local ip="$1"
local data="$2"
# Use flock for thread-safe writes (with timeout to prevent deadlocks)
(
flock -w 2 200 || return 1
# Read existing data
local temp_file="$TEMP_DIR/ip_data.tmp"
cp "$TEMP_DIR/ip_data" "$temp_file" 2>/dev/null || touch "$temp_file"
# Remove old entry for this IP (if exists)
grep -v "^${ip}=" "$temp_file" > "${temp_file}.new" 2>/dev/null || true
# Add new entry
echo "${ip}=${data}" >> "${temp_file}.new"
# Atomic replacement
mv "${temp_file}.new" "$TEMP_DIR/ip_data"
rm -f "$temp_file"
) 200>"$TEMP_DIR/ip_data.lock"
}
# Update IP intelligence
update_ip_intelligence() {
local ip="$1"
@@ -343,6 +369,8 @@ update_ip_intelligence() {
local new_score=$((old_score + 30))
[ "${new_score:-0}" -gt 100 ] && new_score=100
IP_DATA[$ip]="$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep"
# Write to file for cross-process communication
write_ip_data_to_file "$ip" "$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep" 2>/dev/null
elif [ "${abuse_conf:-0}" -ge 50 ]; then
# Medium confidence - add 15 points
local current_data="${IP_DATA[$ip]}"
@@ -350,6 +378,8 @@ update_ip_intelligence() {
local new_score=$((old_score + 15))
[ "${new_score:-0}" -gt 100 ] && new_score=100
IP_DATA[$ip]="$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep"
# Write to file for cross-process communication
write_ip_data_to_file "$ip" "$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep" 2>/dev/null
fi
# High-risk country adds 5 points
@@ -359,6 +389,8 @@ update_ip_intelligence() {
local new_score=$((old_score + 5))
[ "${new_score:-0}" -gt 100 ] && new_score=100
IP_DATA[$ip]="$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep"
# Write to file for cross-process communication
write_ip_data_to_file "$ip" "$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep" 2>/dev/null
fi
) &
fi
@@ -453,6 +485,10 @@ update_ip_intelligence() {
# Update cached data
IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score"
# CRITICAL FIX: Write to file immediately for cross-process communication
# This ensures auto-mitigation engine sees scores from HTTP/SSH monitoring subprocesses
write_ip_data_to_file "$ip" "$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" 2>/dev/null &
# Update IP reputation DB in background (if score > 0)
if [ "${score:-0}" -gt 0 ]; then
(update_ip_reputation "$ip" 1 "$score" 0 "Live monitor: $new_attacks" >/dev/null 2>&1) &
@@ -1898,6 +1934,9 @@ monitor_apache_logs() {
# Update IP data with ET-based score
IP_DATA[$ip]="$new_score|$curr_hits|$curr_bot|$curr_attacks|$curr_ban|$curr_rep"
# CRITICAL FIX: Write to file for cross-process communication
write_ip_data_to_file "$ip" "$new_score|$curr_hits|$curr_bot|$curr_attacks|$curr_ban|$curr_rep" 2>/dev/null &
# Check rate anomaly
if type record_request &>/dev/null && type detect_rate_anomaly &>/dev/null; then
record_request "$ip"
@@ -2229,6 +2268,9 @@ monitor_cphulk_blocks() {
# Update IP_DATA
IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score"
# CRITICAL FIX: Write to file for cross-process communication
write_ip_data_to_file "$ip" "$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" 2>/dev/null &
# Log event
local time_str=$(date +"%H:%M:%S")
local level=$(get_threat_level "$score")
@@ -2297,6 +2339,9 @@ monitor_network_attacks() {
# Update IP_DATA
IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score"
# CRITICAL FIX: Write to file for cross-process communication
write_ip_data_to_file "$ip" "$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" 2>/dev/null &
# Log to reputation DB
flag_ip_attack "$ip" "DDOS" 0 "SYN flood detected" >/dev/null 2>&1 &
@@ -2347,6 +2392,9 @@ monitor_network_attacks() {
# Update IP_DATA
IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score"
# CRITICAL FIX: Write to file for cross-process communication
write_ip_data_to_file "$ip" "$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" 2>/dev/null &
# Log event
local time_str=$(date +"%H:%M:%S")
local level=$(get_threat_level "$score")