Compare commits
3 Commits
979e2c18c3
...
cd5c0a7e8c
| Author | SHA1 | Date | |
|---|---|---|---|
| cd5c0a7e8c | |||
| 50ee27fef1 | |||
| 734e26d45c |
+10
-3
@@ -158,7 +158,14 @@ build_databases_section() {
|
||||
return
|
||||
fi
|
||||
|
||||
local all_dbs=$(mysql -Ns -e "SHOW DATABASES" 2>/dev/null | grep -v "^information_schema$\|^mysql$\|^performance_schema$\|^sys$" || true)
|
||||
# Build MySQL command with credentials if needed
|
||||
local mysql_cmd="mysql"
|
||||
if [ "$SYS_CONTROL_PANEL" = "plesk" ] && [ -f /etc/psa/.psa.shadow ]; then
|
||||
local plesk_mysql_pass=$(cat /etc/psa/.psa.shadow)
|
||||
mysql_cmd="mysql -uadmin -p${plesk_mysql_pass}"
|
||||
fi
|
||||
|
||||
local all_dbs=$($mysql_cmd -Ns -e "SHOW DATABASES" 2>/dev/null | grep -v "^information_schema$\|^mysql$\|^performance_schema$\|^sys$" || true)
|
||||
local total_dbs=$(echo "$all_dbs" | wc -l)
|
||||
local current=0
|
||||
|
||||
@@ -169,12 +176,12 @@ build_databases_section() {
|
||||
local owner=$(get_database_owner "$db")
|
||||
local domain=$(get_database_domain "$db")
|
||||
|
||||
local size_mb=$(mysql -Ns -e "SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2)
|
||||
local size_mb=$($mysql_cmd -Ns -e "SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2)
|
||||
FROM information_schema.TABLES
|
||||
WHERE table_schema='$db'" 2>/dev/null)
|
||||
[ -z "$size_mb" ] && size_mb=0
|
||||
|
||||
local table_count=$(mysql -Ns "$db" -e "SHOW TABLES" 2>/dev/null | wc -l)
|
||||
local table_count=$($mysql_cmd -Ns "$db" -e "SHOW TABLES" 2>/dev/null | wc -l)
|
||||
|
||||
echo "DB|$db|$owner|$domain|$size_mb|$table_count" >> "$SYSREF_DB"
|
||||
done
|
||||
|
||||
@@ -885,6 +885,21 @@ block_ip_temporary() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Quick block IP (wrapper for background auto-blocking)
|
||||
# Used by ET detection and auto-mitigation engine
|
||||
quick_block_ip() {
|
||||
local ip="$1"
|
||||
local reason="${2:-Auto-block: Critical threat}"
|
||||
|
||||
# Validate IP
|
||||
if ! is_valid_ip "$ip"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Block for 1 hour using IPset or CSF
|
||||
block_ip_temporary "$ip" 1 "$reason" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Block IP permanently with CSF
|
||||
block_ip_permanent() {
|
||||
local ip="$1"
|
||||
@@ -2209,24 +2224,114 @@ monitor_network_attacks() {
|
||||
if command -v ss &>/dev/null; then
|
||||
# Count SYN_RECV connections per IP (sign of SYN flood)
|
||||
while read -r ip count; do
|
||||
if [ "$count" -gt 20 ]; then # More than 20 SYN_RECV connections
|
||||
# Skip local/private IPs first
|
||||
if [[ "$ip" =~ ^127\. ]] || \
|
||||
[[ "$ip" =~ ^10\. ]] || \
|
||||
[[ "$ip" =~ ^192\.168\. ]] || \
|
||||
[[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Track connection count for this IP
|
||||
CONNECTION_COUNT[$ip]=$count
|
||||
|
||||
if [ "$count" -gt 20 ]; then # More than 20 SYN_RECV connections = DDoS
|
||||
# Only process once per detection window
|
||||
if [ -z "${ALERT_SENT[$ip]}" ]; then
|
||||
ALERT_SENT[$ip]=1
|
||||
|
||||
# Skip local/private IPs
|
||||
if [[ "$ip" =~ ^127\. ]] || \
|
||||
[[ "$ip" =~ ^10\. ]] || \
|
||||
[[ "$ip" =~ ^192\.168\. ]] || \
|
||||
[[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then
|
||||
continue
|
||||
# Update IP reputation via file (subshell can't access IP_DATA array)
|
||||
local ip_file="$TEMP_DIR/ip_${ip//\./_}"
|
||||
local current_data="0|0|human||0|0"
|
||||
if [ -f "$ip_file" ]; then
|
||||
current_data=$(cat "$ip_file")
|
||||
fi
|
||||
IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data"
|
||||
|
||||
# Increment hits
|
||||
hits=$((hits + 1))
|
||||
|
||||
# Record attack intelligence
|
||||
record_attack_timestamp "$ip"
|
||||
record_attack_vector "$ip" "NETWORK"
|
||||
track_subnet_attack "$ip"
|
||||
|
||||
# Add SYN_FLOOD to attacks if not already present
|
||||
if [[ ! "$attacks" =~ SYN_FLOOD ]]; then
|
||||
[ -z "$attacks" ] && attacks="SYN_FLOOD" || attacks="${attacks},SYN_FLOOD"
|
||||
fi
|
||||
|
||||
# Log high connection count
|
||||
# Progressive scoring based on connection count
|
||||
# 20-50 conns: +15 pts, 50-100: +25 pts, 100+: +40 pts
|
||||
local conn_bonus=0
|
||||
if [ "$count" -ge 100 ]; then
|
||||
conn_bonus=40
|
||||
elif [ "$count" -ge 50 ]; then
|
||||
conn_bonus=25
|
||||
else
|
||||
conn_bonus=15
|
||||
fi
|
||||
|
||||
# First hit or add to existing score
|
||||
if [ "${hits:-0}" -eq 1 ]; then
|
||||
score=$conn_bonus
|
||||
else
|
||||
score=$((score + conn_bonus))
|
||||
fi
|
||||
|
||||
# Apply advanced intelligence bonuses
|
||||
local block_reasons=""
|
||||
local velocity_data=$(calculate_attack_velocity "$ip")
|
||||
IFS='|' read -r vel_count vel_bonus vel_reason <<< "$velocity_data"
|
||||
[ "$vel_bonus" -gt 0 ] && score=$((score + vel_bonus)) && block_reasons="${vel_reason}"
|
||||
|
||||
local div_data=$(calculate_diversity_bonus "$ip")
|
||||
IFS='|' read -r div_count div_bonus div_reason <<< "$div_data"
|
||||
if [ "$div_bonus" -gt 0 ]; then
|
||||
score=$((score + div_bonus))
|
||||
[ -n "$block_reasons" ] && block_reasons="${block_reasons}+" || block_reasons=""
|
||||
block_reasons="${block_reasons}${div_reason}"
|
||||
fi
|
||||
|
||||
local subnet_bonus=$(calculate_subnet_bonus "$ip")
|
||||
if [ "$subnet_bonus" -gt 0 ]; then
|
||||
score=$((score + subnet_bonus))
|
||||
local context_reason="SUBNET_ATTACK"
|
||||
[ -n "$block_reasons" ] && block_reasons="${block_reasons}+" || block_reasons=""
|
||||
block_reasons="${block_reasons}${context_reason}"
|
||||
fi
|
||||
|
||||
# Detect timing patterns
|
||||
local timing_result=$(detect_timing_pattern "$ip")
|
||||
IFS='|' read -r timing_type timing_bonus timing_reason <<< "$timing_result"
|
||||
if [ "$timing_bonus" -gt 0 ]; then
|
||||
score=$((score + timing_bonus))
|
||||
[ -n "$block_reasons" ] && block_reasons="${block_reasons}+" || block_reasons=""
|
||||
block_reasons="${block_reasons}${timing_reason}"
|
||||
fi
|
||||
|
||||
# Cap at 100
|
||||
[ "$score" -gt 100 ] && score=100
|
||||
|
||||
# Write to file for main process
|
||||
echo "$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" > "$ip_file"
|
||||
|
||||
# Store block reasons for auto-mitigation
|
||||
if [ -n "$block_reasons" ]; then
|
||||
echo "$block_reasons" > "$TEMP_DIR/block_reason_${ip//\./_}"
|
||||
fi
|
||||
|
||||
# Log to reputation DB
|
||||
flag_ip_attack "$ip" "SYN_FLOOD" 0 "SYN flood: $count connections" >/dev/null 2>&1 &
|
||||
|
||||
# Log event with reputation score
|
||||
local time_str=$(date +"%H:%M:%S")
|
||||
echo -e "${HIGH_COLOR}[${time_str}] $ip | 💥HIGH_CONN_COUNT | $count SYN_RECV connections (possible DDoS)${NC}" >> "$TEMP_DIR/recent_events"
|
||||
local level=$(get_threat_level "$score")
|
||||
local color=$(get_threat_color "$level")
|
||||
echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 💥SYN_FLOOD | $count SYN_RECV connections${NC}" >> "$TEMP_DIR/recent_events"
|
||||
fi
|
||||
else
|
||||
# Reset alert if connections drop
|
||||
# Reset alert if connections drop below threshold
|
||||
unset ALERT_SENT[$ip]
|
||||
fi
|
||||
done < <(ss -tn state syn-recv 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort | uniq -c | awk '$1 > 5 {print $2, $1}')
|
||||
@@ -2669,11 +2774,36 @@ auto_mitigation_engine() {
|
||||
|
||||
IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$data"
|
||||
|
||||
# Auto-block at score >= 80 (CRITICAL)
|
||||
if [ "$score" -ge 80 ]; then
|
||||
# Skip if already blocked in this session
|
||||
[ -n "${BLOCKED_THIS_SESSION[$ip]}" ] && continue
|
||||
# Validate score is numeric
|
||||
[ -z "$score" ] && score=0
|
||||
[[ ! "$score" =~ ^[0-9]+$ ]] && score=0
|
||||
|
||||
# Skip if already blocked in this session
|
||||
[ -n "${BLOCKED_THIS_SESSION[$ip]}" ] && continue
|
||||
|
||||
# INSTANT block at score 100 (MAXIMUM threat via IPset)
|
||||
if [ "${score:-0}" -ge 100 ]; then
|
||||
# Mark as blocked
|
||||
BLOCKED_THIS_SESSION[$ip]=1
|
||||
|
||||
# Instant IPset block
|
||||
local time_str=$(date +"%H:%M:%S")
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] INSTANT_BLOCK | $ip | Score:100 | ${attacks}${NC}" >> "$TEMP_DIR/recent_events"
|
||||
|
||||
# Get detailed block reason
|
||||
local block_reason="INSTANT AUTO-BLOCK: Score=100 Attacks=${attacks}"
|
||||
if [ -f "$TEMP_DIR/block_reason_${ip//\./_}" ]; then
|
||||
local intel_reason=$(cat "$TEMP_DIR/block_reason_${ip//\./_}")
|
||||
block_reason="${block_reason} Intel:${intel_reason}"
|
||||
fi
|
||||
|
||||
# Instant block via quick_block_ip (uses IPset for speed)
|
||||
quick_block_ip "$ip" "$block_reason" &
|
||||
continue
|
||||
fi
|
||||
|
||||
# Auto-block at score >= 80 (CRITICAL)
|
||||
if [ "${score:-0}" -ge 80 ]; then
|
||||
# Mark as blocked to prevent duplicate attempts
|
||||
BLOCKED_THIS_SESSION[$ip]=1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user