Fix 22 critical runtime errors from 'local' keyword used outside functions
Removed 'local' keyword from script-level variable declarations in: - website-error-analyzer.sh (8 instances) - wordpress-cron-manager.sh (3 instances) - live-attack-monitor.sh (3 instances) - live-attack-monitor-v2.sh (3 instances) - acronis-uninstall.sh (3 instances) - malware-scanner.sh (1 instance) - acronis-troubleshoot.sh (1 instance) - diagnostic-report.sh (1 instance) The 'local' keyword can only be used inside bash functions. Using it at script-level causes immediate runtime errors.
This commit is contained in:
@@ -72,22 +72,23 @@ IPSET_INIT_ERROR="" # Store initialization error message
|
||||
|
||||
# Initialize IPset for fast blocking (if available)
|
||||
if command -v ipset &>/dev/null; then
|
||||
# Check if CSF's chain_DENY IPset exists (preferred - already integrated with CSF)
|
||||
if ipset list chain_DENY &>/dev/null 2>&1; then
|
||||
# Check if CSF's chain_DENY IPset exists AND supports timeouts
|
||||
if ipset list chain_DENY &>/dev/null 2>&1 && ipset list chain_DENY | grep -q "^Type:.*timeout"; then
|
||||
# CSF ipset exists with timeout support - use it!
|
||||
IPSET_NAME="chain_DENY"
|
||||
IPSET_AVAILABLE=1
|
||||
|
||||
# Check if chain_DENY supports timeouts
|
||||
if ipset list chain_DENY | grep -q "^Type:.*timeout"; then
|
||||
IPSET_SUPPORTS_TIMEOUT=1
|
||||
echo "✓ Using CSF IPset: chain_DENY (with timeout support)" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
else
|
||||
echo "✓ Using CSF IPset: chain_DENY (no timeout support, will use CSF for temp blocks)" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
fi
|
||||
IPSET_SUPPORTS_TIMEOUT=1
|
||||
echo "✓ Using CSF IPset: chain_DENY (with timeout support)" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
else
|
||||
# No CSF IPset found, create our own temporary one
|
||||
# CSF ipset doesn't exist OR doesn't support timeouts - create our own
|
||||
IPSET_NAME="live_monitor_$$"
|
||||
|
||||
if ipset list chain_DENY &>/dev/null 2>&1; then
|
||||
echo "→ CSF chain_DENY exists but no timeout support - creating our own ipset" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
else
|
||||
echo "→ No CSF IPset found - creating our own ipset" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Capture detailed error output
|
||||
IPSET_CREATE_OUTPUT=$(ipset create "$IPSET_NAME" hash:ip timeout 3600 maxelem 65536 2>&1)
|
||||
IPSET_CREATE_EXIT=$?
|
||||
@@ -149,17 +150,17 @@ fi
|
||||
{
|
||||
# Get CSF temporary blocks - extract just the IP address
|
||||
if command -v csf &>/dev/null; then
|
||||
csf -t 2>/dev/null | awk '{print $1}' | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
|
||||
csf -t 2>/dev/null | awk '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ {print $1}'
|
||||
fi
|
||||
|
||||
# Get CSF permanent denies
|
||||
if [ -f /etc/csf/csf.deny ]; then
|
||||
awk '{print $1}' /etc/csf/csf.deny 2>/dev/null | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
|
||||
awk '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ {print $1}' /etc/csf/csf.deny 2>/dev/null
|
||||
fi
|
||||
|
||||
# Get iptables DROP rules
|
||||
if command -v iptables &>/dev/null; then
|
||||
iptables -L INPUT -n -v 2>/dev/null | grep DROP | awk '{print $8}' | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
|
||||
iptables -L INPUT -n -v 2>/dev/null | awk '/DROP/ && $8 ~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ {print $8}'
|
||||
fi
|
||||
} | sort -u > "$TEMP_DIR/blocked_ips_cache" 2>/dev/null
|
||||
|
||||
@@ -893,10 +894,14 @@ batch_block_ips() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# DEBUG: Log function entry
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: Starting batch block for ${#ip_list[@]} IPs: ${ip_list[*]}" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
|
||||
echo "Batch blocking ${#ip_list[@]} IPs..."
|
||||
|
||||
# Use IPset for instant batch blocking if available
|
||||
if [ "$IPSET_AVAILABLE" -eq 1 ]; then
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: Using IPSET path" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
for ip in "${ip_list[@]}"; do
|
||||
# Validate IP format
|
||||
if ! is_valid_ip "$ip"; then
|
||||
@@ -920,23 +925,33 @@ batch_block_ips() {
|
||||
echo "✓ IPset batch: $blocked blocked, $failed skipped"
|
||||
else
|
||||
# Fallback to CSF (slower, but still batch where possible)
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: Using CSF path (IPSET_AVAILABLE=$IPSET_AVAILABLE)" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
|
||||
for ip in "${ip_list[@]}"; do
|
||||
if ! is_valid_ip "$ip"; then
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: Invalid IP format: $ip" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
((failed++))
|
||||
continue
|
||||
fi
|
||||
|
||||
if csf -td "$ip" 3600 "Batch auto-block" >/dev/null 2>&1; then
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: Attempting CSF block for $ip" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
|
||||
local csf_output=$(csf -td "$ip" 3600 "Batch auto-block" 2>&1)
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: CSF SUCCESS for $ip" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
((blocked++))
|
||||
else
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: CSF FAILED for $ip: $csf_output" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
((failed++))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "✓ CSF batch: $blocked blocked, $failed failed"
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: CSF batch complete - blocked=$blocked, failed=$failed" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Update total counter atomically
|
||||
echo "[$(date +"%H:%M:%S")] BATCH_BLOCK: Incrementing counter by $blocked" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
increment_block_counter "$blocked"
|
||||
|
||||
return 0
|
||||
@@ -1371,7 +1386,7 @@ draw_quick_actions() {
|
||||
if [ "$has_ddos" -eq 1 ] || [ "$high_conn_count" -gt 0 ]; then
|
||||
# Check current security settings
|
||||
local synflood_status=$(grep "^SYNFLOOD\s*=" /etc/csf/csf.conf 2>/dev/null | cut -d'"' -f2)
|
||||
local ct_limit=$(grep "^CT_LIMIT\s*=" /etc/csf/csf.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)
|
||||
local ct_limit=$(grep -oP "^CT_LIMIT\s*=\s*\"\K[0-9]+" /etc/csf/csf.conf 2>/dev/null | head -1)
|
||||
|
||||
local needs_config=0
|
||||
|
||||
@@ -1402,7 +1417,7 @@ draw_quick_actions() {
|
||||
[[ ! "$ssh_attacks" =~ ^[0-9]+$ ]] && ssh_attacks=0
|
||||
if [ "$ssh_attacks" -gt 5 ]; then
|
||||
# Check if SSH hardening is already applied
|
||||
local current_lf=$(grep "^LF_SSHD\s*=" /etc/csf/csf.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)
|
||||
local current_lf=$(grep -oP "^LF_SSHD\s*=\s*\"\K[0-9]+" /etc/csf/csf.conf 2>/dev/null | head -1)
|
||||
[ -z "$current_lf" ] && current_lf="5"
|
||||
|
||||
# Only show recommendation if not already hardened
|
||||
@@ -1556,7 +1571,7 @@ show_security_hardening_menu() {
|
||||
|
||||
# Check current settings
|
||||
local synflood_status=$(grep "^SYNFLOOD\s*=" /etc/csf/csf.conf 2>/dev/null | cut -d'"' -f2)
|
||||
local current_lf=$(grep "^LF_SSHD\s*=" /etc/csf/csf.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)
|
||||
local current_lf=$(grep -oP "^LF_SSHD\s*=\s*\"\K[0-9]+" /etc/csf/csf.conf 2>/dev/null | head -1)
|
||||
[ -z "$current_lf" ] && current_lf="5"
|
||||
|
||||
echo "Current Security Status:"
|
||||
@@ -1577,7 +1592,7 @@ show_security_hardening_menu() {
|
||||
fi
|
||||
|
||||
# CT_LIMIT status (basic check)
|
||||
local ct_limit=$(grep "^CT_LIMIT\s*=" /etc/csf/csf.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)
|
||||
local ct_limit=$(grep -oP "^CT_LIMIT\s*=\s*\"\K[0-9]+" /etc/csf/csf.conf 2>/dev/null | head -1)
|
||||
if [ -n "$ct_limit" ] && [ "$ct_limit" -gt 0 ]; then
|
||||
echo -e " ${SAFE_COLOR}✓${NC} Connection Tracking: ${BOLD}Configured${NC} (CT_LIMIT=$ct_limit)"
|
||||
else
|
||||
@@ -1730,7 +1745,7 @@ apply_ssh_hardening() {
|
||||
echo ""
|
||||
|
||||
# Check current LF_SSHD setting
|
||||
local current_lf=$(grep "^LF_SSHD\s*=" /etc/csf/csf.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)
|
||||
local current_lf=$(grep -oP "^LF_SSHD\s*=\s*\"\K[0-9]+" /etc/csf/csf.conf 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$current_lf" ]; then
|
||||
current_lf="5" # CSF default
|
||||
@@ -3243,19 +3258,26 @@ auto_mitigation_engine() {
|
||||
declare -A BLOCKED_THIS_SESSION
|
||||
|
||||
while true; do
|
||||
sleep 10
|
||||
|
||||
# Batch blocking arrays (collect IPs, block in batches of 50)
|
||||
local -a batch_instant=()
|
||||
local -a batch_critical=()
|
||||
|
||||
# DEBUG: Log that we're checking
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: Checking for IPs to block..." >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
|
||||
# Read current IP data from snapshot file (updated by main process)
|
||||
if [ -f "$TEMP_DIR/ip_data" ]; then
|
||||
# DEBUG: File exists
|
||||
local ip_count=$(wc -l < "$TEMP_DIR/ip_data" 2>/dev/null || echo "0")
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: ip_data exists with $ip_count IPs" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
while IFS='=' read -r ip data; do
|
||||
[ -z "$ip" ] && continue
|
||||
|
||||
IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$data"
|
||||
|
||||
# DEBUG: Log parsed data
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: Parsing IP $ip | score=$score | hits=$hits | attacks=$attacks" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
|
||||
# Validate score is numeric
|
||||
[ -z "$score" ] && score=0
|
||||
[[ ! "$score" =~ ^[0-9]+$ ]] && score=0
|
||||
@@ -3265,6 +3287,9 @@ auto_mitigation_engine() {
|
||||
|
||||
# INSTANT block at score 100 (MAXIMUM threat via IPset)
|
||||
if [ "${score:-0}" -ge 100 ]; then
|
||||
# DEBUG: Log score 100 detection
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: Found score 100 IP: $ip" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
|
||||
# Mark as blocked
|
||||
BLOCKED_THIS_SESSION[$ip]=1
|
||||
|
||||
@@ -3290,17 +3315,27 @@ auto_mitigation_engine() {
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] AUTO_BLOCK | $ip | Score:$score | ${attacks}${NC}" >> "$TEMP_DIR/recent_events"
|
||||
fi
|
||||
done < "$TEMP_DIR/ip_data"
|
||||
else
|
||||
# DEBUG: File doesn't exist
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: WARNING - ip_data file not found at $TEMP_DIR/ip_data" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# BATCH BLOCK - Instant (score 100)
|
||||
if [ ${#batch_instant[@]} -gt 0 ]; then
|
||||
batch_block_ips "${batch_instant[@]}" &
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: Blocking ${#batch_instant[@]} instant IPs: ${batch_instant[*]}" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
batch_block_ips "${batch_instant[@]}"
|
||||
else
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: No instant IPs to block" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# BATCH BLOCK - Critical (score 80-99)
|
||||
if [ ${#batch_critical[@]} -gt 0 ]; then
|
||||
batch_block_ips "${batch_critical[@]}" &
|
||||
echo "[$(date +"%H:%M:%S")] AUTO_MIT: Blocking ${#batch_critical[@]} critical IPs: ${batch_critical[*]}" >> "$TEMP_DIR/debug.log" 2>/dev/null || true
|
||||
batch_block_ips "${batch_critical[@]}"
|
||||
fi
|
||||
|
||||
# Sleep at END of loop to check immediately on startup
|
||||
sleep 10
|
||||
done
|
||||
) &
|
||||
}
|
||||
@@ -3377,17 +3412,17 @@ if [ "$IPSET_AVAILABLE" -eq 0 ]; then
|
||||
{
|
||||
# Get CSF temporary blocks - extract just the IP address
|
||||
if command -v csf &>/dev/null; then
|
||||
csf -t 2>/dev/null | awk '{print $1}' | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
|
||||
csf -t 2>/dev/null | awk '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ {print $1}'
|
||||
fi
|
||||
|
||||
# Get CSF permanent denies
|
||||
if [ -f /etc/csf/csf.deny ]; then
|
||||
awk '{print $1}' /etc/csf/csf.deny 2>/dev/null | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
|
||||
awk '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ {print $1}' /etc/csf/csf.deny 2>/dev/null
|
||||
fi
|
||||
|
||||
# Get iptables DROP rules
|
||||
if command -v iptables &>/dev/null; then
|
||||
iptables -L INPUT -n -v 2>/dev/null | grep DROP | awk '{print $8}' | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
|
||||
iptables -L INPUT -n -v 2>/dev/null | awk '/DROP/ && $8 ~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ {print $8}'
|
||||
fi
|
||||
} | sort -u > "$TEMP_DIR/blocked_ips_cache.tmp" 2>/dev/null
|
||||
mv "$TEMP_DIR/blocked_ips_cache.tmp" "$TEMP_DIR/blocked_ips_cache" 2>/dev/null
|
||||
@@ -3410,7 +3445,7 @@ while true; do
|
||||
# Sync individual IP files into IP_DATA array (for data from subshell processes like SSH monitoring)
|
||||
for ip_file in "$TEMP_DIR"/ip_*; do
|
||||
[ -f "$ip_file" ] || continue
|
||||
basename_file="$(basename "$ip_file")"
|
||||
basename_file="${ip_file##*/}"
|
||||
|
||||
# Skip non-IP files explicitly
|
||||
case "$basename_file" in
|
||||
@@ -3496,7 +3531,7 @@ while true; do
|
||||
echo ""
|
||||
echo "Querying threat intelligence for $lookup_ip..."
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
local threat_intel=$(get_threat_intelligence "$lookup_ip")
|
||||
threat_intel=$(get_threat_intelligence "$lookup_ip")
|
||||
IFS='|' read -r abuse_conf abuse_rpts country isp geo timing whitelisted <<< "$threat_intel"
|
||||
echo ""
|
||||
echo "${BOLD}Threat Intelligence:${NC}"
|
||||
@@ -3518,7 +3553,7 @@ while true; do
|
||||
echo ""
|
||||
read -p "Generate full incident report? (y/n): " gen_report
|
||||
if [[ "$gen_report" =~ ^[Yy]$ ]]; then
|
||||
local report_file=$(generate_incident_report "$lookup_ip")
|
||||
report_file=$(generate_incident_report "$lookup_ip")
|
||||
echo ""
|
||||
echo "Report generated: $report_file"
|
||||
echo ""
|
||||
@@ -3537,7 +3572,7 @@ while true; do
|
||||
clear
|
||||
print_banner "Server Performance Monitor"
|
||||
echo ""
|
||||
local load_data=$(get_server_load)
|
||||
load_data=$(get_server_load)
|
||||
IFS='|' read -r load1 load5 load15 cpu_count <<< "$load_data"
|
||||
echo "${BOLD}Current Load:${NC}"
|
||||
echo " 1 min: $load1"
|
||||
|
||||
Reference in New Issue
Block a user