Add distributed DDoS detection with dynamic thresholds

CRITICAL FIX for botnet-style attacks

USER REPORT:
"512 SYN_RECV connections but live monitor only shows 2 IPs"

ROOT CAUSE:
Threshold was hardcoded at >20 connections per IP. This works for
focused attacks (one IP, many connections) but FAILS for distributed
DDoS where 50+ IPs each send 5-15 connections.

Example from user's attack:
- 512 total SYN_RECV connections
- Spread across 40+ attacker IPs
- Top attacker: 107 packets (likely <20 active connections)
- Result: NONE detected, server getting hammered

SOLUTION - Dynamic Threshold:

1. Total SYN_RECV Detection (line 2226)
   Count total SYN_RECV across all IPs
   If > 100 total → distributed_attack mode activated

2. Adaptive Thresholds (lines 2247-2253)
   NORMAL MODE: threshold = 20 connections
   - Focused attack (1-2 IPs)
   - High bar to avoid false positives

   DISTRIBUTED MODE: threshold = 5 connections
   - Botnet attack (many IPs)
   - Catches participants in coordinated attack
   - Triggers when total > 100

DETECTION EXAMPLES:

Focused Attack (unchanged behavior):
- 1 IP with 150 SYN_RECV
- Total: 150, threshold: 20
- Result: 1 IP detected, blocked

Distributed Botnet (NEW):
- 50 IPs each with 10 SYN_RECV
- Total: 500, threshold: 5 (distributed mode)
- Result: ALL 50 IPs detected, reputation tracked
- Progressive blocking as scores accumulate

User's Attack (512 total):
- distributed_attack = 1 (512 > 100)
- threshold = 5
- All IPs with >5 connections now tracked
- Likely catches 30-40 of the attackers

This allows catching both attack patterns without flooding
the system with false positives during normal traffic.
This commit is contained in:
cschantz
2025-12-24 19:57:22 -05:00
parent aadc3be64a
commit 7719cfecd1
2 changed files with 36 additions and 2 deletions
+18 -1
View File
@@ -2222,6 +2222,15 @@ monitor_network_attacks() {
while true; do while true; do
# Use ss if available (faster), otherwise netstat # Use ss if available (faster), otherwise netstat
if command -v ss &>/dev/null; then if command -v ss &>/dev/null; then
# Get total SYN_RECV count for distributed attack detection
local total_syn=$(ss -tn state syn-recv 2>/dev/null | wc -l)
local distributed_attack=0
# Distributed DDoS detection: Many IPs with small counts
if [ "$total_syn" -gt 100 ]; then
distributed_attack=1
fi
# Count SYN_RECV connections per IP (sign of SYN flood) # Count SYN_RECV connections per IP (sign of SYN flood)
while read -r ip count; do while read -r ip count; do
# Skip local/private IPs first # Skip local/private IPs first
@@ -2235,7 +2244,15 @@ monitor_network_attacks() {
# Track connection count for this IP # Track connection count for this IP
CONNECTION_COUNT[$ip]=$count CONNECTION_COUNT[$ip]=$count
if [ "$count" -gt 20 ]; then # More than 20 SYN_RECV connections = DDoS # Dynamic threshold based on attack type:
# - Normal: >20 connections (focused attack)
# - Distributed DDoS: >5 connections (botnet)
local threshold=20
if [ "$distributed_attack" -eq 1 ]; then
threshold=5 # Lower threshold during distributed attacks
fi
if [ "$count" -gt "$threshold" ]; then
# Only process once per detection window # Only process once per detection window
if [ -z "${ALERT_SENT[$ip]}" ]; then if [ -z "${ALERT_SENT[$ip]}" ]; then
ALERT_SENT[$ip]=1 ALERT_SENT[$ip]=1
+18 -1
View File
@@ -2222,6 +2222,15 @@ monitor_network_attacks() {
while true; do while true; do
# Use ss if available (faster), otherwise netstat # Use ss if available (faster), otherwise netstat
if command -v ss &>/dev/null; then if command -v ss &>/dev/null; then
# Get total SYN_RECV count for distributed attack detection
local total_syn=$(ss -tn state syn-recv 2>/dev/null | wc -l)
local distributed_attack=0
# Distributed DDoS detection: Many IPs with small counts
if [ "$total_syn" -gt 100 ]; then
distributed_attack=1
fi
# Count SYN_RECV connections per IP (sign of SYN flood) # Count SYN_RECV connections per IP (sign of SYN flood)
while read -r ip count; do while read -r ip count; do
# Skip local/private IPs first # Skip local/private IPs first
@@ -2235,7 +2244,15 @@ monitor_network_attacks() {
# Track connection count for this IP # Track connection count for this IP
CONNECTION_COUNT[$ip]=$count CONNECTION_COUNT[$ip]=$count
if [ "$count" -gt 20 ]; then # More than 20 SYN_RECV connections = DDoS # Dynamic threshold based on attack type:
# - Normal: >20 connections (focused attack)
# - Distributed DDoS: >5 connections (botnet)
local threshold=20
if [ "$distributed_attack" -eq 1 ]; then
threshold=5 # Lower threshold during distributed attacks
fi
if [ "$count" -gt "$threshold" ]; then
# Only process once per detection window # Only process once per detection window
if [ -z "${ALERT_SENT[$ip]}" ]; then if [ -z "${ALERT_SENT[$ip]}" ]; then
ALERT_SENT[$ip]=1 ALERT_SENT[$ip]=1